liquid brushes
Moderator: InsideQC Admins
8 posts
• Page 1 of 1
liquid brushes
I am working in a way to create liquid brushes, and I almost was succesfull, but I need some advising in how to fix a small detail.
I decided to take a mixed solution (QuakeC + engine), so that's why I am posting the problem here.
From the QuakeC side, I am creating a new kind of func_door (func_liquid_door), adding this to the end of doors.qc:
The setwater (entity, entity) you see above is a new builtin I created to handle (by engine side) the .watertype and .waterlevel values. Here follows the code:
I am only resorting to engine coding because .waterlevel and .watertype are entity fields marked as "do not set in prog code, maintained by C code" in defs.qc. Otherwise there's nothing there I couldn't handle directly in QuakeC.
So, after that, I created a test map with a func_liquid_door toggled by buttons to mimic a pool being flooded and drained. And it works... kinda. The physics part works pretty well, you can swim and drown into the brush, and when toggled you can walk normally. But visually, there's no warped view, no colorshift. Checking the code, I found that (at least in FitzQuake) water warping is checked in gl_rmain.c (R_SetupView). But I have no idea how I could force the engine to render the water brush correctly, since it only checks contents against the world model. I could eventually hack something to do the trick, but I prefer to make it in an more elegant way.
Any suggestions ?
I decided to take a mixed solution (QuakeC + engine), so that's why I am posting the problem here.
From the QuakeC side, I am creating a new kind of func_door (func_liquid_door), adding this to the end of doors.qc:
- Code: Select all
void() liquid_door_touch =
{
if (other.health <= 0)
{
return;
}
setwater (self, other);
};
// just a simplified copy & paste from original func_door
void() func_liquid_door =
{
SetMovedir ();
self.solid = SOLID_TRIGGER;
self.movetype = MOVETYPE_PUSH;
setorigin (self, self.origin);
setmodel (self, self.model);
self.classname = "liquid_door";
self.use = door_use;
if (!self.speed)
self.speed = 100;
if (!self.wait)
self.wait = 3;
if (!self.lip)
self.lip = 8;
if (!self.dmg)
self.dmg = 2;
if (!self.watertype)
self.watertype = 3;
self.pos1 = self.origin;
self.pos2 = self.pos1 + self.movedir*(fabs(self.movedir*self.size) - self.lip);
if (self.spawnflags & DOOR_START_OPEN)
{
setorigin (self, self.pos2);
self.pos2 = self.pos1;
self.pos1 = self.origin;
}
self.state = STATE_BOTTOM;
self.touch = liquid_door_touch;
self.think = LinkDoors;
self.nextthink = self.ltime + 0.1;
};
The setwater (entity, entity) you see above is a new builtin I created to handle (by engine side) the .watertype and .waterlevel values. Here follows the code:
- Code: Select all
qboolean CheckPointInsideEntity (vec3_t p, edict_t *e)
{
return (
(p[0] >= e->v.mins[0]) &&
(p[1] >= e->v.mins[1]) &&
(p[2] >= e->v.mins[2]) &&
(p[0] <= e->v.maxs[0]) &&
(p[1] <= e->v.maxs[1]) &&
(p[2] <= e->v.maxs[2]));
}
/**
* setwater (entity waterbrush, entity other)
**/
void PF_SetWater (void)
{
edict_t *ent1, *ent2;
vec3_t point;
ent1 = G_EDICT(OFS_PARM0);
ent2 = G_EDICT(OFS_PARM1);
point[0] = ent2->v.origin[0];
point[1] = ent2->v.origin[1];
point[2] = ent2->v.origin[2] + ent2->v.mins[2] + 1;
ent2->v.waterlevel = 0;
ent2->v.watertype = CONTENTS_EMPTY;
if (CheckPointInsideEntity (point, ent1))
{
ent2->v.watertype = ent1->v.watertype;
ent2->v.waterlevel = 1;
point[2] = ent2->v.origin[2] + (ent2->v.mins[2] + ent2->v.maxs[2]) * 0.5;
if (CheckPointInsideEntity (point, ent1))
{
ent2->v.waterlevel = 2;
point[2] = ent2->v.origin[2] + ent2->v.view_ofs[2];
if (CheckPointInsideEntity (point, ent1))
{
ent2->v.waterlevel = 3;
}
}
}
}
I am only resorting to engine coding because .waterlevel and .watertype are entity fields marked as "do not set in prog code, maintained by C code" in defs.qc. Otherwise there's nothing there I couldn't handle directly in QuakeC.
So, after that, I created a test map with a func_liquid_door toggled by buttons to mimic a pool being flooded and drained. And it works... kinda. The physics part works pretty well, you can swim and drown into the brush, and when toggled you can walk normally. But visually, there's no warped view, no colorshift. Checking the code, I found that (at least in FitzQuake) water warping is checked in gl_rmain.c (R_SetupView). But I have no idea how I could force the engine to render the water brush correctly, since it only checks contents against the world model. I could eventually hack something to do the trick, but I prefer to make it in an more elegant way.
Any suggestions ?
I know FrikaC made a cgi-bin version of the quakec interpreter once and wrote part of his website in QuakeC
(LordHavoc)
-

frag.machine - Posts: 2090
- Joined: Sat Nov 25, 2006 1:49 pm
side note: halflife sets .skin to negative values to denote non-solid brush models.
in your client, you will need to loop through the entities (cl_entities in nq, I think) and test any brush entities for their solidity.
note that any pointcontents etc will give solid for liquid entities, thanks to quirks of qbsp.
if you use the .skin field you don't have to extend your network protocol, and it could be done automagically in the engine instead of having to use builtins.
in your client, you will need to loop through the entities (cl_entities in nq, I think) and test any brush entities for their solidity.
note that any pointcontents etc will give solid for liquid entities, thanks to quirks of qbsp.
if you use the .skin field you don't have to extend your network protocol, and it could be done automagically in the engine instead of having to use builtins.
- Spike
- Posts: 2892
- Joined: Fri Nov 05, 2004 3:12 am
- Location: UK
RMQ does it via a stuffcmd of cshift to set the contents color. You can also check cl.inwater for whether or not the client in inside a water brush.
We had the power, we had the space, we had a sense of time and place
We knew the words, we knew the score, we knew what we were fighting for
We knew the words, we knew the score, we knew what we were fighting for
-

mh - Posts: 2292
- Joined: Sat Jan 12, 2008 1:38 am
cshift doesn't warp, only discolours (and that must look odd in the majorty of quakeworld clients, where cshift is honoured and water colouration is disabled as its an fps loss).
testing the value of cl.inwater will not work as the client will see any func_water models as fully solid if it did check them, which it won't.
tbh, there's no difference between setting fields in qc or in a builtin. Those comments are more informative than instructional.
In the case of water types, they're just normally set in the engine and it'll override the content types periodically, so cannot be used for persistant storage.
testing the value of cl.inwater will not work as the client will see any func_water models as fully solid if it did check them, which it won't.
tbh, there's no difference between setting fields in qc or in a builtin. Those comments are more informative than instructional.
In the case of water types, they're just normally set in the engine and it'll override the content types periodically, so cannot be used for persistant storage.
- Spike
- Posts: 2892
- Joined: Fri Nov 05, 2004 3:12 am
- Location: UK
Spike wrote:side note: halflife sets .skin to negative values to denote non-solid brush models.
in your client, you will need to loop through the entities (cl_entities in nq, I think) and test any brush entities for their solidity.
note that any pointcontents etc will give solid for liquid entities, thanks to quirks of qbsp.
if you use the .skin field you don't have to extend your network protocol, and it could be done automagically in the engine instead of having to use builtins.
I was thinking about changing the behavior of SV_CheckWater(), in sv_phys.c. The current version checks only contents against the wordmodel, verifying against any brush model the entity is touching should be enough. The idea of negative values for .skin sounds good. I'll make some tests.
I know FrikaC made a cgi-bin version of the quakec interpreter once and wrote part of his website in QuakeC
(LordHavoc)
-

frag.machine - Posts: 2090
- Joined: Sat Nov 25, 2006 1:49 pm
I want to see the Quake guy face a rising lava situation or a room filling with water
I hope you are successful, I'm looking very forward to seeing this.
I hope you are successful, I'm looking very forward to seeing this.
The night is young. How else can I annoy the world before sunsrise?
Inquisitive minds want to know ! And if they don't -- well like that ever has stopped me before ..
-

Baker - Posts: 3666
- Joined: Tue Mar 14, 2006 5:15 am
Did you look at Pox's qc extras? Moving water, even water on a train.
Unrelated to qc extras, bu this was in my modded engine timefrag, world.c:
In SV_RecursiveHullCheck:
The end of SV_ClipMoveToEntity:
Maybe usefull, or at least give some ideas.
Unrelated to qc extras, bu this was in my modded engine timefrag, world.c:
- Code: Select all
int SV_PointContents (vec3_t p) //qbism//jf 02-10-22 now checks inside entities
{
int cont;
trace_t trace;
vec3_t p2;
cont = SV_HullPointContents(&sv.worldmodel->hulls[0], 0, p);
p2[2] = p[2] + 3;
p[2] = p[2] -3;
trace = SV_Move (p, vec3_origin, vec3_origin, p2, 0, sv.edicts);
if (trace.inlava) return CONTENTS_LAVA; //qbism//jf 02-10-22 put the harshest first!
else if (trace.inslime) return CONTENTS_SLIME;
else if (trace.inwater) return CONTENTS_WATER; //qbism//jf 02-10-22 always check this LAST. inwater set for all liquids.
else return cont;
}
In SV_RecursiveHullCheck:
- Code: Select all
// check for empty
if (num < 0)
{
if (num != CONTENTS_SOLID)
{
trace->allsolid = false;
if (num == CONTENTS_EMPTY)
trace->inopen = true;
else
trace->inwater = true; //qbism// 02-10-22 set inwater for any liquid
}
else
trace->startsolid = true;
return true; // empty
}
The end of SV_ClipMoveToEntity:
- Code: Select all
//qbism//jf 02-10-22 return liquid contents of brush models.
if (ent->v.solid == SOLID_WATER)
trace.inwater = 1;
else if (ent->v.solid == SOLID_SLIME)
{
trace.inslime = 1;
trace.inwater = 1; //qbism//jf 02-10-22 always set inwater for any type of liquid.
}
else if (ent->v.solid == SOLID_LAVA)
{
trace.inlava = 1;
trace.inwater = 1; //qbism//jf 02-10-22 always set inwater for any type of liquid.
}
return trace;
}
Maybe usefull, or at least give some ideas.
-
qbism - Posts: 1236
- Joined: Thu Nov 04, 2004 5:51 am
Thanks! I'll compare it against the original code and maybe I can make it work.
EDIT: Also, I need to check Pox's stuff.
EDIT2: Duh! I should listened to you guys and checked Pox's mod first. Awesome stuff, it will be more than enough to what I want. Thanks everyone for the help.
EDIT: Also, I need to check Pox's stuff.
EDIT2: Duh! I should listened to you guys and checked Pox's mod first. Awesome stuff, it will be more than enough to what I want. Thanks everyone for the help.
I know FrikaC made a cgi-bin version of the quakec interpreter once and wrote part of his website in QuakeC
(LordHavoc)
-

frag.machine - Posts: 2090
- Joined: Sat Nov 25, 2006 1:49 pm
8 posts
• Page 1 of 1
Return to Programming Tutorials
Who is online
Users browsing this forum: No registered users and 1 guest