View previous topic :: View next topic |
Author |
Message |
mh

Joined: 12 Jan 2008 Posts: 909
|
Posted: Fri Aug 14, 2009 12:18 am Post subject: Jumping on Exploboxes |
|
|
EDIT - put begin and end comments around the relevant code changes so that you can more easily see the bits that you need to add to your engine if you don't want to just copy/paste whole functions
This came to light after everyone started playing the Bloody Slipgates mod. There is a place where one of the red keys is hidden where there are 3 routes to it. Route 1 involves a fairly fiendish ninja jump (captured for posterity in my demo), route 2 involves a clip brush in a place where it doesn't seem obvious, and route 3 involves jumping off a small explobox. Now, most if not all engines aside from DP don't support jumping off exploboxes, so route 2 was added at the last minute in order to provide a way (I think the mod author may not have realised that route 1 was possible here).
Here I'm going to show you how to implement the ability to jump off exploboxes in Quake. Before I start though there's a big disclaimer to make.
BIG DISCLAIMER
This is a gameplay changing tutorial. It might make some areas in some maps that were previously inaccessible easier to get at, so I consider it a "cheating" change. It's all server-side though so it won't affect MP games, but just be aware that if you implement it you may spoil your enjoyment of some maps or mods.
I've only tested it on Bloody Slipgates, and only in the relevant area. I've also ensured that it doesn't interfere with other regular brush entities.
Some mods may do things with exploboxes that break as a result of this code. You have been warned.
Now, open sv_phys.c and look for the SV_Physics function. Replace it with this: Code: | void SV_Physics (void)
{
int i;
edict_t *ent;
// let the progs know that a new frame has started
pr_global_struct->self = EDICT_TO_PROG(sv.edicts);
pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
pr_global_struct->time = sv.time;
PR_ExecuteProgram (pr_global_struct->StartFrame);
//SV_CheckAllEnts ();
//
// treat each object in turn
//
ent = sv.edicts;
for (i=0 ; i<sv.num_edicts ; i++, ent = NEXT_EDICT(ent))
{
// jumping on exploboxes begin
qboolean modelhack = false;
// jumping on exploboxes end
if (ent->free)
continue;
// jumping on exploboxes begin
// don't do the world edict
if (ent->v.touch == 0 && i > 0)
{
model_t *mod = sv.models[(int) ent->v.modelindex];
if (mod)
{
if (mod->type == mod_brush && mod->name[0] != '*')
{
// we have a brushmodel that (1) doesn't have a touch function, and (2)
// is an instanced BSP model, so we switch the solid and movetype
ent->v.solid = SOLID_BSP;
ent->v.movetype = MOVETYPE_PUSH;
// flag that we're hacking the model
modelhack = true;
}
}
}
// jumping on exploboxes end
if (pr_global_struct->force_retouch)
{
SV_LinkEdict (ent, true); // force retouch even for stationary
}
if (i > 0 && i <= svs.maxclients)
SV_Physics_Client (ent, i);
else if (ent->v.movetype == MOVETYPE_PUSH)
// jumping on exploboxes begin
SV_Physics_Pusher (ent, modelhack);
// jumping on exploboxes end
else if (ent->v.movetype == MOVETYPE_NONE)
SV_Physics_None (ent);
#ifdef QUAKE2
else if (ent->v.movetype == MOVETYPE_FOLLOW)
SV_Physics_Follow (ent);
#endif
else if (ent->v.movetype == MOVETYPE_NOCLIP)
SV_Physics_Noclip (ent);
else if (ent->v.movetype == MOVETYPE_STEP)
SV_Physics_Step (ent);
else if (ent->v.movetype == MOVETYPE_TOSS
|| ent->v.movetype == MOVETYPE_BOUNCE
#ifdef QUAKE2
|| ent->v.movetype == MOVETYPE_BOUNCEMISSILE
#endif
|| ent->v.movetype == MOVETYPE_FLY
|| ent->v.movetype == MOVETYPE_FLYMISSILE)
SV_Physics_Toss (ent);
else
Sys_Error ("SV_Physics: bad movetype %i", (int)ent->v.movetype);
}
if (pr_global_struct->force_retouch)
pr_global_struct->force_retouch--;
sv.time += host_frametime;
} |
The cause of not being able to jump off an explobox is because of the movetype value that they have (MOVETYPE_NONE) so here we detect if we have an explobox and switch the movetype. We also need to switch the solid value because MOVETYPE_PUSH requires SOLID_BSP.
The code to detect if it's an explobox can work with any instanced BSP model. First it detects if the model has a touch function; if it does we assume that it''s meant to be interacted with in some way, and so we don't switch it. Then we ensure that we've got an instanced BSP model. Note also the change to the call to SV_Physics_Pusher in here. I'll talk about that one after the next block of code.
Next, we replace SV_Physics_Pusher itself with this: Code: | void SV_Physics_Pusher (edict_t *ent, qboolean modelhack)
{
float thinktime;
float oldltime;
float movetime;
oldltime = ent->v.ltime;
thinktime = ent->v.nextthink;
if (thinktime < ent->v.ltime + host_frametime)
{
movetime = thinktime - ent->v.ltime;
if (movetime < 0)
movetime = 0;
}
else
movetime = host_frametime;
if (movetime)
{
#ifdef QUAKE2
if (ent->v.avelocity[0] || ent->v.avelocity[1] || ent->v.avelocity[2])
SV_PushRotate (ent, movetime);
else
#endif
SV_PushMove (ent, movetime); // advances ent->v.ltime if not blocked
}
// jumping on exploboxes begin
if (modelhack)
{
// run regular thinking
SV_RunThink (ent);
}
else if (thinktime > oldltime && thinktime <= ent->v.ltime)
// jumping on exploboxes end
{
ent->v.nextthink = 0;
pr_global_struct->time = sv.time;
pr_global_struct->self = EDICT_TO_PROG(ent);
pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
PR_ExecuteProgram (ent->v.think);
if (ent->free)
return;
}
} |
All that we're doing here is detecting if the model was hacked above and sending it through the think function for a MOVETYPE_NONE model if so.
This code as it stands will potentially give you a "SOLID_BSP with a non-BSP model" error so the last thing to do is fix that. I'm going to do a quick and dirty fix rather than something more robust, so open world.c and replace SV_HullForEntity with this: Code: | hull_t *SV_HullForEntity (edict_t *ent, vec3_t mins, vec3_t maxs, vec3_t offset)
{
model_t *model;
vec3_t size;
vec3_t hullmins, hullmaxs;
hull_t *hull;
// decide which clipping hull to use, based on the size
if (ent->v.solid == SOLID_BSP)
{ // explicit hulls in the BSP model
if (ent->v.movetype != MOVETYPE_PUSH)
Sys_Error ("SOLID_BSP without MOVETYPE_PUSH");
model = sv.models[ (int)ent->v.modelindex ];
// jumping on exploboxes begin
if (!model || model->type != mod_brush)
goto dont_crash;
// jumping on exploboxes end
VectorSubtract (maxs, mins, size);
if (size[0] < 3)
hull = &model->hulls[0];
else if (size[0] <= 32)
hull = &model->hulls[1];
else
hull = &model->hulls[2];
// calculate an offset value to center the origin
VectorSubtract (hull->clip_mins, mins, offset);
VectorAdd (offset, ent->v.origin, offset);
}
else
{ // create a temp hull from bounding box sizes
dont_crash:
VectorSubtract (ent->v.mins, maxs, hullmins);
VectorSubtract (ent->v.maxs, mins, hullmaxs);
hull = SV_HullForBox (hullmins, hullmaxs);
VectorCopy (ent->v.origin, offset);
}
return hull;
} |
This happens because the entities model changes from a brush to a sprite when it explodes, so all we do here is jump to the non-SOLID_BSP hull code instead of throwing a Sys_Error.
Now, this code is fairly hacky and there are better ways of doing the whole thing; one possible solution would be to store the original values of solid and movetype in the edict_t struct and switch between them and the new ones as required. I did it this way so that I could present the tutorial in a manner that's easier to follow, but I wouldn't claim is the right way, or even a good way. But if you want to jump off exploboxes it'll let you do it. Any improvements are entirely up to you. _________________ DirectQ Engine - New release 1.8.666a, 9th August 2010
MHQuake Blog (General)
Direct3D 8 Quake Engines
Last edited by mh on Sat Aug 15, 2009 2:56 pm; edited 1 time in total |
|
Back to top |
|
 |
Team Xlink
Joined: 25 Jun 2009 Posts: 320
|
Posted: Fri Aug 14, 2009 1:38 am Post subject: |
|
|
Nice Tutorial!
Finally, I can take the fun route!
Thank you! _________________
Anonymous wrote: | if it works, it works. if it doesn't, HAHAHA! |
|
|
Back to top |
|
 |
Downsider

Joined: 16 Sep 2008 Posts: 478
|
Posted: Fri Aug 14, 2009 4:09 pm Post subject: |
|
|
Good job coming up with the fix, but I hate seeing tutorials that just say, "Replace this function with this function because I said so".
At the very least, you could compare the two functions to show the differences, so that way you could work out what's actually going on. Some people are working with different code bases that have changed certain aspects of the engine and can't simply replace the entire function. Others also want to understand what's going on, too, especially since a lot of these additions are very hacky and aren't understood immediately unless your knowledge of Quake is rather deep. |
|
Back to top |
|
 |
c0burn
Joined: 05 Nov 2004 Posts: 158 Location: Liverpool, England
|
Posted: Fri Aug 14, 2009 7:06 pm Post subject: |
|
|
Can this be fixed in QC the same way the URQP fixes sliding when you jump on a monster? (touch function that fiddles with FL_ONGROUND)? |
|
Back to top |
|
 |
mh

Joined: 12 Jan 2008 Posts: 909
|
Posted: Sat Aug 15, 2009 2:52 pm Post subject: |
|
|
Downsider wrote: | Good job coming up with the fix, but I hate seeing tutorials that just say, "Replace this function with this function because I said so".
At the very least, you could compare the two functions to show the differences, so that way you could work out what's actually going on. Some people are working with different code bases that have changed certain aspects of the engine and can't simply replace the entire function. Others also want to understand what's going on, too, especially since a lot of these additions are very hacky and aren't understood immediately unless your knowledge of Quake is rather deep. |
I have commented the relevant code areas as well as provided some explanation text, but I can amend the tutorial and put // begin and // end comments around the modified parts. In the specific case of this one, the physics code is something that I think not too many people modify, but I suppose you're right all the same.
c0burn wrote: | Can this be fixed in QC the same way the URQP fixes sliding when you jump on a monster? (touch function that fiddles with FL_ONGROUND)? |
Should be possible, yes. I'm not too familiar with QC but it's all fields that are exported through ent->v so they should also be accessible from QC. In fact I would be of the opinion that QC is the correct place to do it.  _________________ DirectQ Engine - New release 1.8.666a, 9th August 2010
MHQuake Blog (General)
Direct3D 8 Quake Engines |
|
Back to top |
|
 |
Lardarse

Joined: 05 Nov 2005 Posts: 243 Location: Bristol, UK
|
Posted: Sun Aug 16, 2009 8:59 pm Post subject: Re: Jumping on Exploboxes |
|
|
mh wrote: | This came to light after everyone started playing the Bloody Slipgates mod. There is a place where one of the red keys is hidden where there are 3 routes to it. Route 1 involves a fairly fiendish ninja jump (captured for posterity in my demo), route 2 involves a clip brush in a place where it doesn't seem obvious, and route 3 involves jumping off a small explobox. Now, most if not all engines aside from DP don't support jumping off exploboxes, so route 2 was added at the last minute in order to provide a way (I think the mod author may not have realised that route 1 was possible here). |
I couldn't do it. negke tried to do it in his first run demo and couldn't do it either...
There is actually a 4th method: Look at the box, jump, shoot the box.
I would like a QC solution, though... _________________ <ekiM> Son, you're writing data structures your CPU can't cache. |
|
Back to top |
|
 |
mh

Joined: 12 Jan 2008 Posts: 909
|
Posted: Sun Aug 16, 2009 10:24 pm Post subject: Re: Jumping on Exploboxes |
|
|
Lardarse wrote: | I couldn't do it. negke tried to do it in his first run demo and couldn't do it either... |
Well if I could do it, it can't be that hard.
Lardarse wrote: | I would like a QC solution, though... |
Obviously the ideal way to go; one of our resident QC hackers would have to help you with that, however. I'm still highly dubious about ever having posted this thing; it's just Wrong and Bad in so many ways (cheating, edict behaviour modification, physics hacking, etc). _________________ DirectQ Engine - New release 1.8.666a, 9th August 2010
MHQuake Blog (General)
Direct3D 8 Quake Engines |
|
Back to top |
|
 |
Downsider

Joined: 16 Sep 2008 Posts: 478
|
Posted: Thu Aug 20, 2009 9:01 pm Post subject: |
|
|
Kurok had a fix for this from version 0.3 -> 0.4, if I remember correctly. Ask MDave, although for all I know he could have changed the exploboxes into brushes or something (Is this possible?). Or maybe I'm totally off my hat and it never was fixed, or it's a different problem entirely!  |
|
Back to top |
|
 |
r00k
Joined: 13 Nov 2004 Posts: 483
|
Posted: Fri Aug 21, 2009 5:40 pm Post subject: |
|
|
c0burn wrote: | Can this be fixed in QC the same way the URQP fixes sliding when you jump on a monster? (touch function that fiddles with FL_ONGROUND)? |
Maybe if touching an explosion box, switch it's movetype to MOVETYPE_STEP, and keeping track of that entity, so if not touching it, switch it back to MOVETYPE_NONE... i'm still looking for an explosion box in normal Quake maps that i can stand on.. e3m1? I think as c0burn mentioned in player_touch setting the box ONGROUND would keep u from slip-sliding around while on it, fiddling with the movetype should allow you to jump off it... I'll have to play with this as it might breakif u blow it up while standing on it
hmm weird. I havent looked in misc.qc in AT LEAST 6 years...
here's what i found in my CAx mod...
Code: |
void() misc_explobox2 =
{
remove(self);
return;
local float oldz;
self.solid = SOLID_BBOX;
//self.movetype = MOVETYPE_NONE;
self.movetype = MOVETYPE_PUSH;
precache_model2 ("maps/b_exbox2.bsp");
setmodel (self, "maps/b_exbox2.bsp");
precache_sound ("weapons/r_exp3.wav");
self.health = 20;
self.th_die = barrel_explode;
self.takedamage = DAMAGE_AIM;
self.origin_z = self.origin_z + 2;
oldz = self.origin_z;
droptofloor(0,0);
if (oldz - self.origin_z > 250)
{
dprint ("item fell out of level at ");
dprint (vtos(self.origin));
dprint ("\n");
remove(self);
}
};
|
I dont remember switching that movetype before nor do i know the result as in CA i clear this entity out. When I get home I'll have to test this as I cant compile under this OS (i have a 16gb thumbdrive with my quake stuff that i take along with me ) |
|
Back to top |
|
 |
mh

Joined: 12 Jan 2008 Posts: 909
|
Posted: Fri Aug 21, 2009 6:22 pm Post subject: |
|
|
You'll need to switch to SOLID_BSP as well, but I do believe that is all that's required. Just hacked it into a vanilla ID QC and it worked fine.
There's a box you can test it on in e4m1 by the way, in the room with the lasers. _________________ DirectQ Engine - New release 1.8.666a, 9th August 2010
MHQuake Blog (General)
Direct3D 8 Quake Engines |
|
Back to top |
|
 |
Wazat
Joined: 15 Oct 2004 Posts: 732 Location: Middle 'o the desert, USA
|
Posted: Sat Aug 22, 2009 2:59 am Post subject: |
|
|
Assuming my memories weren't planted by conspiring hamsters (haaamsteeers!), I'm reasonably certain I had walking & jumping off of non-BSP objects working perfectly in one of my mods. Thus I was able to run around on monsters' heads and jump off.
Again, if memory serves me, it was a simple feat of tracelining down in playerprethink, testing if the impacted non-bsp object was worthy of your footsteps (most things are: monsters, explode boxes, maybe even triggers), and setting the player's FL_ONGROUND flag. Once the flag was set, the player could walk as though he was on a SOLID_BSP object.
But I still suspect conspiring hamsters planting false memories to keep me under control.
It can be fun abusing the power of QC like this to get great results. I'm still proud of the semi-solid-corpses-without-an-engine-mod hack I put in Ace of Nails. And Conquest's pause-the-world-without-pausing feature.[/shamelessbrag] _________________ When my computer inevitably explodes and kills me, my cat inherits everything I own. He may be the only one capable of continuing my work. |
|
Back to top |
|
 |
Team Xlink
Joined: 25 Jun 2009 Posts: 320
|
Posted: Sat Dec 05, 2009 9:05 pm Post subject: |
|
|
mh wrote: | [b]
Next, we replace SV_Physics_Pusher itself with this: Code: | void SV_Physics_Pusher (edict_t *ent, qboolean modelhack)
{
float thinktime;
float oldltime;
float movetime;
} |
|
A friend of mine was having trouble with that and I told him about this so I thought maybe other people were having trouble.
The part where you add the qboolean modelhack wasn't commented and he didn't notice it so maybe a comment there might help others as well.
EDIT: I am confused. How exactly is it supposed to work?
I tried taking that way but it didn't change anything at all.
I think I ama misunderstanding how to use it. _________________
Anonymous wrote: | if it works, it works. if it doesn't, HAHAHA! |
|
|
Back to top |
|
 |
|
|
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
|