Index | FAQ | Search | Memberlist | Usergroups | Profile | Log in to check your private messages | Log in | Register

liquid brushes

| Inside3d Forums Forum Index -> Programming Tutorials

View previous topic :: View next topic
Author | Message
--- | ---
frag.machine Joined: 25 Nov 2006 Posts: 728 |

Posted: Fri Jan 22, 2010 12:45 am Post subject: 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:

Code:
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:
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 ?
_________________
frag.machine - Q2K4 Project
http://fragmachine.quakedev.com/

Back to top |

Spike Joined: 05 Nov 2004 Posts: 944 Location: UK |

Posted: Fri Jan 22, 2010 1:07 am Post subject: |

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.
_________________
What's a signature?

Back to top |

mh Joined: 12 Jan 2008 Posts: 909 |

Posted: Fri Jan 22, 2010 10:26 am Post subject: |

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. _________________ DirectQ Engine - New release 1.8.666a, 9th August 2010 MHQuake Blog (General) Direct3D 8 Quake Engines

Back to top |

Spike Joined: 05 Nov 2004 Posts: 944 Location: UK |

Posted: Fri Jan 22, 2010 11:54 am Post subject: |

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.
_________________
What's a signature?

Back to top |

frag.machine Joined: 25 Nov 2006 Posts: 728 |

Posted: Fri Jan 22, 2010 1:36 pm Post subject: |

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.
_________________
frag.machine - Q2K4 Project
http://fragmachine.quakedev.com/

Back to top |

Baker Joined: 14 Mar 2006 Posts: 1538 |

Posted: Fri Jan 22, 2010 9:31 pm Post subject: |

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. _________________ Tomorrow Never Dies. I feel this Tomorrow knocking on the door ...

Back to top |

qbism Joined: 04 Nov 2004 Posts: 82 |

Posted: Sat Jan 30, 2010 1:24 am Post subject: |

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:

Code:
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:
// 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:
//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.
_________________
http://qbism.com

Back to top |

frag.machine Joined: 25 Nov 2006 Posts: 728 |

Posted: Sat Jan 30, 2010 6:33 pm Post subject: |

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.
_________________
frag.machine - Q2K4 Project
http://fragmachine.quakedev.com/

Back to top |

Display posts from previous:

| Inside3d Forums Forum Index -> Programming Tutorials | All times are GMT
Page 1 of 1

Jump to:

You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum

Powered by phpBB © 2004 phpBB Group