fteqw/quakec/csqctest/src/common/phys.qc

335 lines
8.9 KiB
Plaintext

//note that this file uses various engine pastes and is thus subject to the terms of the GNU GPL.
//use with caution
float lastclientthink, sv_maxspeed, sv_friction, sv_accelerate, sv_stopspeed;
float sv_edgefriction, cl_rollangle, cl_divspeed;
vector phys_origin; //in/out
float phys_movetype; //in
float phys_health; //in
float phys_fixangle; //in
float phys_onground; //in/out
float phys_waterjump; //in/out
vector phys_angles; //out
vector phys_v_angles; //in
vector phys_velocity; //in/out
vector phys_movement; //in
vector phys_punchangle; //in/out
float phys_gravity; //in (should be sv_gravity * self.gravity)
#define bound(min,val,max) if (val < min) val = min; else if (val > max) val = max
#define sv_stepheight 22
var void() thinkfunc;
float(entity ent, float ftime) SV_FlyMove =
{
}
void() WalkMove =
{
float clip, oldonground, originalmove_clip, originalmove_flags, originalmove_groundentity;
vector upmove, downmove, start_origin, start_velocity, stepnormal, originalmove_origin, originalmove_velocity;
// SV_CheckVelocity(ent);
// do a regular slide move unless it looks like you ran into a step
oldonground = phys_onground;
phys_onground = false;
start_origin = phys_origin;
start_velocity = phys_velocity;
clip = SV_FlyMove (ent, sv.frametime, NULL);
SV_SetOnGround (ent);
SV_CheckVelocity(ent);
VectorCopy(phys_origin, originalmove_origin);
VectorCopy(phys_velocity, originalmove_velocity);
originalmove_clip = clip;
originalmove_flags = (int)ent->fields.server->flags;
originalmove_groundentity = phys_groundentity;
if (phys_waterjump)
return;
// if (sv_nostep.integer)
// return;
// if move didn't block on a step, return
if (clip & 2)
{
// if move was not trying to move into the step, return
if (fabs(start_velocity[0]) < 0.03125 && fabs(start_velocity[1]) < 0.03125)
return;
if (phys_movetype != MOVETYPE_FLY)
{
// return if gibbed by a trigger
if (phys_movetype != MOVETYPE_WALK)
return;
// only step up while jumping if that is enabled
// if (!(sv_jumpstep.integer && sv_gameplayfix_stepwhilejumping.integer))
if (!oldonground && phys_waterlevel == 0)
return;
}
// try moving up and forward to go up a step
// back to start pos
VectorCopy (start_origin, phys_origin);
VectorCopy (start_velocity, phys_velocity);
// move up
VectorClear (upmove);
upmove[2] = sv_stepheight;
// FIXME: don't link?
SV_PushEntity(ent, upmove);
// move forward
phys_velocity[2] = 0;
clip = SV_FlyMove (ent, sv.frametime, stepnormal);
phys_velocity[2] += start_velocity[2];
// SV_CheckVelocity(ent);
// check for stuckness, possibly due to the limited precision of floats
// in the clipping hulls
if (clip
&& fabs(originalmove_origin[1] - phys_origin[1]) < 0.03125
&& fabs(originalmove_origin[0] - phys_origin[0]) < 0.03125)
{
//Con_Printf("wall\n");
// stepping up didn't make any progress, revert to original move
VectorCopy(originalmove_origin, phys_origin);
VectorCopy(originalmove_velocity, phys_velocity);
//clip = originalmove_clip;
phys_flags = originalmove_flags;
phys_groundentity = originalmove_groundentity;
// now try to unstick if needed
//clip = SV_TryUnstick (ent, oldvel);
return;
}
//Con_Printf("step - ");
// extra friction based on view angle
if (clip & 2 && sv_wallfriction.integer)
SV_WallFriction (ent, stepnormal);
}
// skip out if stepdown is enabled, moving downward, not in water, and the move started onground and ended offground
// else if (!(sv_gameplayfix_stepdown.integer && phys_waterlevel < 2 && start_velocity[2] < (1.0 / 32.0) && oldonground && !((int)ent->fields.server->flags & FL_ONGROUND)))
// return;
/*
// move down
VectorClear (downmove);
downmove[2] = -sv_stepheight + start_velocity[2]*sv.frametime;
// FIXME: don't link?
downtrace = SV_PushEntity (ent, downmove);
if (downtrace.fraction < 1 && downtrace.plane.normal[2] > 0.7)
{
// LordHavoc: disabled this check so you can walk on monsters/players
//if (phys_solid == SOLID_BSP)
{
//Con_Printf("onground\n");
phys_onground = true;
phys_groundentity = PRVM_EDICT_TO_PROG(downtrace.ent);
}
}
else
{
//Con_Printf("slope\n");
// if the push down didn't end up on good ground, use the move without
// the step up. This happens near wall / slope combinations, and can
// cause the player to hop up higher on a slope too steep to climb
VectorCopy(originalmove_origin, ent->fields.server->origin);
VectorCopy(originalmove_velocity, ent->fields.server->velocity);
//clip = originalmove_clip;
ent->fields.server->flags = originalmove_flags;
ent->fields.server->groundentity = originalmove_groundentity;
}
SV_SetOnGround (ent);
SV_CheckVelocity(ent);
*/
};
// LordHavoc:
// Highly optimized port of SV_ClientThink from engine code to QuakeC.
// note that the engine will call this function if it finds it,
// so modify for your own mods and enjoy...
void() RunPlayerPhysics =
{
local vector wishvel, wishdir, v;
local float wishspeed, f;
if (phys_movetype == MOVETYPE_NONE)
return;
if (phys_punchangle != '0 0 0')
{
f = vlen(phys_punchangle) - 10 * frametime;
if (f > 0)
phys_punchangle = normalize(phys_punchangle) * f;
else
phys_punchangle = '0 0 0';
}
// if dead, behave differently
if (phys_health <= 0)
return;
// show 1/3 the pitch angle and all the roll angle
phys_angles_z = bound(-1, phys_velocity * v_right * cl_divspeed, 1) * cl_rollangle;
if (!phys_fixangle)
{
phys_angles_x = (phys_v_angle_x + phys_punchangle_x) * 0.333 * autocvar(r_meshpitch, -1);
phys_angles_y = phys_v_angle_y + phys_punchangle_y;
}
if (phys_waterjump)
{
phys_velocity_x = phys_movedir_x;
phys_velocity_y = phys_movedir_y;
if (time > phys_teleport_time || phys_waterlevel == 0)
{
phys_waterjump = false;
phys_teleport_time = 0;
}
return;
}
makevectors(phys_v_angle);
// swim
if (phys_waterlevel >= 2)
if (phys_movetype != MOVETYPE_NOCLIP)
{
phys_onground = false;
if (phys_movement == '0 0 0')
wishvel = '0 0 -60'; // drift towards bottom
else
wishvel = v_forward * phys_movement_x + v_right * phys_movement_y + '0 0 1' * phys_movement_z;
wishspeed = vlen (wishvel);
if (wishspeed > sv_maxspeed)
wishspeed = sv_maxspeed;
wishspeed = wishspeed * 0.7;
// water friction
if (phys_velocity != '0 0 0')
{
f = vlen(phys_velocity) * (1 - frametime * sv_friction);
if (f > 0)
phys_velocity = normalize(phys_velocity) * f;
else
phys_velocity = '0 0 0';
}
else
f = 0;
// water acceleration
if (wishspeed <= f)
return;
f = min(wishspeed - f, sv_accelerate * wishspeed * frametime);
phys_velocity = phys_velocity + normalize(wishvel) * f;
return;
}
// hack to not let you back into teleporter
if (time < phys_teleport_time && phys_movement_x < 0)
wishvel = v_right * phys_movement_y;
else
{
if (phys_onground)
makevectors (phys_v_angle_y * '0 1 0');
wishvel = v_forward * phys_movement_x + v_right * phys_movement_y;
}
if (phys_movetype != MOVETYPE_WALK)
wishvel_z = phys_movement_z;
else
wishvel_z = 0;
wishdir = normalize(wishvel);
wishspeed = vlen(wishvel);
if (wishspeed > sv_maxspeed)
wishspeed = sv_maxspeed;
if (phys_movetype == MOVETYPE_NOCLIP) // noclip
{
phys_onground = false;
phys_velocity = wishdir * wishspeed;
}
else if (phys_onground) // walking
{
// friction
if (phys_velocity_x || phys_velocity_y)
{
v = phys_velocity;
v_z = 0;
f = vlen(v);
// if the leading edge is over a dropoff, increase friction
v = phys_origin + normalize(v) * 16 + '0 0 1' * phys_mins_z;
traceline(v, v + '0 0 -34', TRUE, self);
// apply friction
if (trace_fraction == 1.0)
{
if (f < sv_stopspeed)
f = 1 - frametime * (sv_stopspeed / f) * sv_friction * sv_edgefriction;
else
f = 1 - frametime * sv_friction * sv_edgefriction;
}
else
{
if (f < sv_stopspeed)
f = 1 - frametime * (sv_stopspeed / f) * sv_friction;
else
f = 1 - frametime * sv_friction;
}
if (f < 0)
phys_velocity = '0 0 0';
else
phys_velocity = phys_velocity * f;
}
// acceleration
f = wishspeed - (phys_velocity * wishdir);
if (f > 0)
phys_velocity = phys_velocity + wishdir * min(f, sv_accelerate * frametime * wishspeed);
}
else // airborn
{
if (wishspeed < 30)
f = wishspeed - (phys_velocity * wishdir);
else
f = 30 - (phys_velocity * wishdir);
if (f > 0)
phys_velocity = phys_velocity + wishdir * (min(f, sv_accelerate) * wishspeed * frametime);
}
PlayerPreThink();
if (thinkfunc)
thinkfunc();
if (!SV_CheckWater (ent) && !phys_waterjump) )
phys_velocity_z -= phys_gravity * frametime;
// SV_CheckStuck (ent);
SV_WalkMove (ent);
PlayerPostThink();
}