Okay, for all you guys/girls out there who have quake2 maps that you want to
convert to q3, or for those who are sick of all the jump pads, I've got the
solution! Thanks to Zoid for the help he gave me with the elusive "ladder"
surface tag.
I'd first like to mention that I've seen all the "simple" tutorials out there
for minor changes, and so I decided I'd write this to get something more
substantial out there. This is meant for mod authors who know what they're doing
and want ladders. I've tried to comment everything so its understandable, but
this is NOT MEANT FOR PEOPLE TRYING TO LEARN HOW TO
PROGRAM. This is for people who want ladders. =)
Let's get started, shall we?
-------------------------------------------------------------------------------------------------------------------------------------
Okay, first things first. We need to declare variables we'll be using
througout the physics functions. This first thing we'll add is a flag that we
can toggle if our client is on a ladder. We're doing this so we don't have to
call the function we'll be making each time we want to know their ladder status.
So, down to the nitty gritty. Feel free to open up bg_local.h. We're going to modify the pml_t (thats an L not
a 1) structure. This structure is used as a global in the player physics file,
and so it can be access anywhere. Add the hi-lighted line below.
= = = = = = = = = = + = = = = = = = = |
typedef
struct { vec3_t forward, right, up;
float
frametime;
int msec;
qboolean walking; qboolean
groundPlane; trace_t
groundTrace;
qboolean ladder; |
// We'll use this
flag to tell when the player is on a
ladder
|
float impactSpeed;
vec3_t previous_origin;
vec3_t previous_velocity;
int previous_waterlevel; }
pml_t;
|
Okay, feel free to close that file, we're all done with it.
-------------------------------------------------------------------------------------------------------------------------------------
Our next task is to add a couple variables for the standard physics code. Go
ahead and open up bg_pmove.c.
Near the top of the
file you should see the following. Add in the three global variables I've
hi-lighted.
= = = = = + = = = + = = = + = = = = |
float pm_stopspeed = 100;
float
pm_duckScale = 0.25; float pm_swimScale = 0.50;
float
pm_wadeScale = 0.70;
float
pm_ladderScale = 0.50; |
// Set the max movement speed to HALF of
normal
|
float pm_accelerate =
10; float
pm_airaccelerate = 1;
float
pm_ladderAccelerate = 3000; |
// The acceleration to friction ratio is
1:1
|
float pm_wateraccelerate =
4; float
pm_flyaccelerate = 8;
float
pm_ladderfriction = 3000; |
// Friction is high enough so you don't slip
down
|
float pm_friction =
6; float
pm_waterfriction = 1; float pm_flightfriction = 3;
|
Now, that wasn't too hard, was
it?
-------------------------------------------------------------------------------------------------------------------------------------
Wheee, okay. Now that we've made our little friction and acceleration and
scale variables, it's time to implement them. Make sence? Good. Scroll down to
around line 200 in bg_pmove.c. This should put you
smack dab in the center of static void PM_Friction( void ).
= = = = = = + + + + = = = = = = = = |
//
apply flying friction if ( pm->ps->powerups[PW_FLIGHT] ||
pm->ps->pm_type == PM_SPECTATOR ) {
drop +=
speed*pm_flightfriction*pml.frametime;
}
if ( pml.ladder ) // If
they're on a ladder... {
drop +=
speed*pm_ladderfriction*pml.frametime;
}
|
// Add ladder
friction!
|
// scale the velocity
newspeed = speed - drop; if (newspeed < 0) {
newspeed = 0;
} newspeed /= speed;
|
-------------------------------------------------------------------------------------------------------------------------------------
Now that we're done with that, lets go to the end of the function. At this
point we need to add our actual functions to handle checking for the ladder, and
also to handle the physics for people on ladders.
At this point, add the following.
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
|
/* =================== PM_LadderMove() by:
Calrathan [Arthur Tomlin]
Right now all I know is that this works
for VERTICAL ladders. Ladders with angles on them (urban2 for AQ2)
Haven't been tested =================== */ static void PM_LadderMove( void ) { int i; vec3_t
wishvel; float
wishspeed; vec3_t wishdir;
float scale;
float vel;
PM_Friction ();
scale =
PM_CmdScale( &pm->cmd );
// user intentions [what the user is attempting to
do] if (
!scale ) {
wishvel[0] = 0;
wishvel[1] = 0;
wishvel[2] = 0; }
else { // if
they're trying to move... lets calculate it
for (i=0 ;
i<3 ; i++)
wishvel[i] = scale *
pml.forward[i]*pm->cmd.forwardmove +
scale *
pml.right[i]*pm->cmd.rightmove;
wishvel[2] += scale * pm->cmd.upmove;
}
VectorCopy
(wishvel, wishdir); wishspeed =
VectorNormalize(wishdir);
if ( wishspeed > pm->ps->speed *
pm_ladderScale ) {
wishspeed = pm->ps->speed * pm_ladderScale;
}
PM_Accelerate (wishdir,
wishspeed, pm_ladderAccelerate);
// This SHOULD help us with sloped ladders, but it remains
untested. if ( pml.groundPlane && DotProduct(
pm->ps->velocity, pml.groundTrace.plane.normal ) < 0 )
{ vel =
VectorLength(pm->ps->velocity);
// slide along the ground
plane [the ladder section under our feet]
PM_ClipVelocity
(pm->ps->velocity, pml.groundTrace.plane.normal,
pm->ps->velocity, OVERCLIP );
VectorNormalize(pm->ps->velocity);
VectorScale(pm->ps->velocity, vel,
pm->ps->velocity); }
PM_SlideMove( qfalse ); // move without
gravity }
/* ============= CheckLadder [ ARTHUR TOMLIN
] ============= */ void
CheckLadder( void ) {
vec3_t flatforward,spot;
trace_t trace; pml.ladder =
qfalse; // check for
ladder flatforward[0] =
pml.forward[0]; flatforward[1] =
pml.forward[1]; flatforward[2] =
0; VectorNormalize (flatforward);
VectorMA (pm->ps->origin, 1, flatforward,
spot); pm->trace (&trace,
pm->ps->origin, pm->mins, pm->maxs, spot,
pm->ps->clientNum, MASK_PLAYERSOLID);
if ((trace.fraction < 1) &&
(trace.surfaceFlags & SURF_LADDER))
pml.ladder = qtrue;
}
|
-------------------------------------------------------------------------------------------------------------------------------------
OKAY! Final step. Last thing to do is go into void PmoveSingle (pmove_t
*pmove) and make sure we use the ladder if we're on it. This should be
around line 1900
= = = = = = = = = + = = = = = = = = = = = = = + + = = = = = = = =
|
// set groundentity
PM_GroundTrace();
if ( pm->ps->pm_type == PM_DEAD ) {
PM_DeadMove ();
}
PM_DropTimers();
CheckLadder(); |
// ARTHUR TOMLIN
check and see if they're on a
ladder
|
if ( pm->ps->powerups[PW_FLIGHT] )
{ // flight powerup doesn't allow jump and has different
friction
PM_FlyMove(); } else
if (pm->ps->pm_flags & PMF_GRAPPLE_PULL) {
PM_GrappleMove();
// We can wiggle a bit
PM_AirMove();
} else if (pm->ps->pm_flags
& PMF_TIME_WATERJUMP) {
PM_WaterJumpMove(); } else if ( pm->waterlevel > 1 ) {
//
swimming
PM_WaterMove();
} else if (pml.ladder)
{
PM_LadderMove();
|
} else if ( pml.walking ) {
//
walking on ground
PM_WalkMove(); } else {
// airborne
PM_AirMove();
}
|
-------------------------------------------------------------------------------------------------------------------------------------
There we go, the Ladder code is done. But, we still have a problem. Ladders
don't seem to work in your maps, even if you did a direct .BSP conversion! Oh
no!
Easy fix. Have your map designers [or for the versitile, do it yourself]
make a box around your ladders. This box should be given a texture of
"common/ladderclip". Edit your "quake3\baseq3\scripts\common.shader" file, and
insert the lines:
textures/common/ladderclip {
qer_trans 0.40 surfaceparm
nolightmap surfaceparm nomarks
surfaceparm nodraw
surfaceparm nonsolid surfaceparm
playerclip surfaceparm noimpact
surfaceparm ladder }
|
-------------------------------------------------------------------------------------------------------------------------------------
Before we finish, I'd like to remind you to rebuild BOTH the "game" and
"cgame" module. This will the client side prediction work properly with ladders
[ aka no shaking like a mofo ]. Compile your map, and there we have it. Working
ladders. =)
Addendum! Known issue: Player's legs stay in previous state, sometimes as
if they're running in midair
If you use this tutorial, please give credit to the author,