📄 pmoveunit.pas
字号:
friction := pm_friction * 1.5; // extra friction
//control = speed < pm_stopspeed ? pm_stopspeed : speed;
if (speed < pm_stopspeed) then
control := pm_stopspeed
else
control := speed;
drop := drop + control * friction * pml.frametime;
// scale the velocity
newspeed := speed - drop;
if (newspeed < 0) then
newspeed := 0;
newspeed := newspeed / speed;
VectorScale(pml.velocity, newspeed, pml.velocity);
end;
// accelerate
fmove := pm.cmd.forwardmove;
smove := pm.cmd.sidemove;
VectorNormalize(pml.forward);
VectorNormalize(pml.right);
for i := 0 to 2 do
wishvel[i] := pml.forward[i] * fmove + pml.right[i] * smove;
wishvel[2] := wishvel[2] + pm.cmd.upmove;
VectorCopy(wishvel, wishdir);
wishspeed := VectorNormalize(wishdir);
//
// clamp to server defined max speed
//
if (wishspeed > pm_maxspeed) then
begin
VectorScale(wishvel, pm_maxspeed / wishspeed, wishvel);
wishspeed := pm_maxspeed;
end;
currentspeed := DotProduct(pml.velocity, wishdir);
addspeed := wishspeed - currentspeed;
if (addspeed <= 0) then
Exit;
accelspeed := pm_accelerate * pml.frametime * wishspeed;
if (accelspeed > addspeed) then
accelspeed := addspeed;
for i := 0 to 2 do
pml.velocity[i] := pml.velocity[i] + accelspeed * wishdir[i];
if (doclip) then
begin
for i := 0 to 2 do
end_[i] := pml.origin[i] + pml.frametime * pml.velocity[i];
trace := pm.trace(pml.origin, pm.mins, pm.maxs, end_);
VectorCopy(trace.endpos, pml.origin);
end
else
begin
// move
VectorMA(pml.origin, pml.frametime, pml.velocity, pml.origin);
end;
end;
{*
==============
PM_CheckDuck
Sets mins, maxs, and pm->viewheight
==============
*}
procedure PM_CheckDuck;
var
trace: trace_t;
begin
pm.mins[0] := -16;
pm.mins[1] := -16;
pm.maxs[0] := 16;
pm.maxs[1] := 16;
if (pm.s.pm_type = PM_GIB) then
begin
pm.mins[2] := 0;
pm.maxs[2] := 16;
pm.viewheight := 8;
Exit;
end;
pm.mins[2] := -24;
if (pm.s.pm_type = PM_DEAD) then
begin
pm.s.pm_flags := pm.s.pm_flags or PMF_DUCKED;
end
else if (pm.cmd.upmove < 0) and (pm.s.pm_flags and PMF_ON_GROUND <> 0) then
begin // duck
pm.s.pm_flags := pm.s.pm_flags or PMF_DUCKED;
end
else
begin // stand up if possible
if (pm.s.pm_flags and PMF_DUCKED <> 0) then
begin
// try to stand up
pm.maxs[2] := 32;
trace := pm.trace(pml.origin, pm.mins, pm.maxs, pml.origin);
if (not trace.allsolid) then
pm.s.pm_flags := pm.s.pm_flags and not PMF_DUCKED;
end;
end;
if (pm.s.pm_flags and PMF_DUCKED <> 0) then
begin
pm.maxs[2] := 4;
pm.viewheight := -2;
end
else
begin
pm.maxs[2] := 32;
pm.viewheight := 22;
end;
end;
{*
==============
PM_DeadMove
==============
*}
procedure PM_DeadMove;
var
forward_: Single;
begin
if (pm.groundentity = nil) then
Exit;
// extra friction
forward_ := VectorLength(pml.velocity);
forward_ := forward_ - 20;
if (forward_ <= 0) then
begin
VectorClear(pml.velocity);
end
else
begin
VectorNormalize(pml.velocity);
VectorScale(pml.velocity, forward_, pml.velocity);
end;
end;
function PM_GoodPosition: qboolean;
var
trace: trace_t;
origin, end_: vec3_t;
i: Integer;
begin
if (pm.s.pm_type = PM_SPECTATOR) then
begin
Result := True;
Exit;
end;
for i := 0 to 2 do
begin
end_[i] := pm.s.origin[i] * 0.125;
origin[i] := end_[i]
end;
trace := pm.trace(origin, pm.mins, pm.maxs, end_);
Result := not trace.allsolid;
end;
{*
================
PM_SnapPosition
On exit, the origin will have a value that is pre-quantized to the 0.125
precision of the network channel and in a valid position.
================
*}
procedure PM_SnapPosition;
var
sign: array[0..2] of Integer;
i, j, bits: Integer;
base: array[0..2] of Smallint;
{$IFDEF COMPILER6_UP}{$WRITEABLECONST ON}{$ENDIF}
const
// try all single bits first
jitterbits: array[0..7] of Integer = (0, 4, 1, 2, 3, 5, 6, 7);
{$IFDEF COMPILER6_UP}{$WRITEABLECONST OFF}{$ENDIF}
begin
// snap velocity to eigths
for i := 0 to 2 do
pm.s.velocity[i] := Trunc(pml.velocity[i] * 8);
for i := 0 to 2 do
begin
if (pml.origin[i] >= 0) then
sign[i] := 1
else
sign[i] := -1;
pm.s.origin[i] := Trunc(pml.origin[i] * 8);
if (pm.s.origin[i] * 0.125 = pml.origin[i]) then
sign[i] := 0;
end;
VectorCopy(pm.s.origin, base);
// try all combinations
for j := 0 to 7 do
begin
bits := jitterbits[j];
VectorCopy(base, pm.s.origin);
for i := 0 to 2 do
if (bits and (1 shl i) <> 0) then
pm.s.origin[i] := pm.s.origin[i] + sign[i];
if PM_GoodPosition then
Exit;
end;
// go back to the last position
VectorCopy(pml.previous_origin, pm.s.origin);
//Com_DPrintf ('using previous_origin', []);
end;
(*
//NO LONGER USED
/*
================
PM_InitialSnapPosition
================
*/
void PM_InitialSnapPosition (void)
{
int x, y, z;
short base[3];
VectorCopy (pm->s.origin, base);
for (z=1 ; z>=-1 ; z--)
{
pm->s.origin[2] = base[2] + z;
for (y=1 ; y>=-1 ; y--)
{
pm->s.origin[1] = base[1] + y;
for (x=1 ; x>=-1 ; x--)
{
pm->s.origin[0] = base[0] + x;
if (PM_GoodPosition ())
{
pml.origin[0] = pm->s.origin[0]*0.125;
pml.origin[1] = pm->s.origin[1]*0.125;
pml.origin[2] = pm->s.origin[2]*0.125;
VectorCopy (pm->s.origin, pml.previous_origin);
return;
}
}
}
}
Com_DPrintf ('Bad InitialSnapPosition'#10);
}
*)
{*
================
PM_InitialSnapPosition
================
*}
procedure PM_InitialSnapPosition;
var
x, y, z: Integer;
base: array[0..2] of Smallint;
{$IFDEF COMPILER6_UP}{$WRITEABLECONST ON}{$ENDIF}
const
offset: array[0..2] of Integer = (0, -1, 1);
{$IFDEF COMPILER6_UP}{$WRITEABLECONST OFF}{$ENDIF}
begin
VectorCopy(pm.s.origin, base);
for z := 0 to 2 do
begin
pm.s.origin[2] := base[2] + offset[z];
for y := 0 to 2 do
begin
pm.s.origin[1] := base[1] + offset[y];
for x := 0 to 2 do
begin
pm.s.origin[0] := base[0] + offset[x];
if PM_GoodPosition then
begin
pml.origin[0] := pm.s.origin[0] * 0.125;
pml.origin[1] := pm.s.origin[1] * 0.125;
pml.origin[2] := pm.s.origin[2] * 0.125;
VectorCopy(pm.s.origin, pml.previous_origin);
Exit;
end;
end;
end;
end;
Com_DPrintf('Bad InitialSnapPosition'#10, ['']);
end;
{*
================
PM_ClampAngles
================
*}
procedure PM_ClampAngles;
var
temp: Word;
i: Integer;
begin
if (pm.s.pm_flags and PMF_TIME_TELEPORT <> 0) then
begin
pm.viewangles[YAW] := SHORT2ANGLE(pm.cmd.angles[YAW] + pm.s.delta_angles[YAW]);
pm.viewangles[PITCH] := 0;
pm.viewangles[ROLL] := 0;
end
else
begin
// circularly clamp the angles with deltas
for i := 0 to 2 do
begin
temp := pm.cmd.angles[i] + pm.s.delta_angles[i];
pm.viewangles[i] := SHORT2ANGLE(temp);
end;
// don't let the player look up or down more than 90 degrees
if (pm.viewangles[PITCH] > 89) and (pm.viewangles[PITCH] < 180) then
pm.viewangles[PITCH] := 89
else if (pm.viewangles[PITCH] < 271) and (pm.viewangles[PITCH] >= 180) then
pm.viewangles[PITCH] := 271;
end;
AngleVectors(pm.viewangles, @pml.forward, @pml.right, @pml.up);
end;
{*
================
Pmove
Can be called by either the server or the client
================
*}
procedure Pmove(pmove: pmove_p);
var
msec: Integer;
angles: vec3_t;
begin
pm := pmove;
// clear results
pm.numtouch := 0;
VectorClear(pm.viewangles);
pm.viewheight := 0;
pm.groundentity := nil;
pm.watertype := 0;
pm.waterlevel := 0;
// clear all pmove local vars
FillChar(pml, SizeOf(pml), 0);
// convert origin and velocity to float values
pml.origin[0] := pm.s.origin[0] * 0.125;
pml.origin[1] := pm.s.origin[1] * 0.125;
pml.origin[2] := pm.s.origin[2] * 0.125;
pml.velocity[0] := pm.s.velocity[0] * 0.125;
pml.velocity[1] := pm.s.velocity[1] * 0.125;
pml.velocity[2] := pm.s.velocity[2] * 0.125;
// save old org in case we get stuck
VectorCopy(pm.s.origin, pml.previous_origin);
pml.frametime := pm.cmd.msec * 0.001;
PM_ClampAngles;
if (pm.s.pm_type = PM_SPECTATOR) then
begin
PM_FlyMove(False);
PM_SnapPosition;
Exit;
end;
if (pm.s.pm_type >= PM_DEAD) then
begin
pm.cmd.forwardmove := 0;
pm.cmd.sidemove := 0;
pm.cmd.upmove := 0;
end;
if (pm.s.pm_type = PM_FREEZE) then
Exit; // no movement at all
// set mins, maxs, and viewheight
PM_CheckDuck;
if (pm.snapinitial) then
PM_InitialSnapPosition;
// set groundentity, watertype, and waterlevel
PM_CatagorizePosition;
if (pm.s.pm_type = PM_DEAD) then
PM_DeadMove;
PM_CheckSpecialMovement;
// drop timing counter
if (pm.s.pm_time <> 0) then
begin
msec := pm.cmd.msec shr 3;
if (msec = 0) then
msec := 1;
if (msec >= pm.s.pm_time) then
begin
pm.s.pm_flags := pm.s.pm_flags and not (PMF_TIME_WATERJUMP or PMF_TIME_LAND or PMF_TIME_TELEPORT);
pm.s.pm_time := 0;
end
else
pm.s.pm_time := pm.s.pm_time - msec;
end;
if (pm.s.pm_flags and PMF_TIME_TELEPORT <> 0) then
begin // teleport pause stays exactly in place
end
else if (pm.s.pm_flags and PMF_TIME_WATERJUMP <> 0) then
begin // waterjump has no control, but falls
pml.velocity[2] := pml.velocity[2] - pm.s.gravity * pml.frametime;
if (pml.velocity[2] < 0) then
begin // cancel as soon as we are falling down again
pm.s.pm_flags := pm.s.pm_flags and not (PMF_TIME_WATERJUMP or PMF_TIME_LAND or PMF_TIME_TELEPORT);
pm.s.pm_time := 0;
end;
PM_StepSlideMove;
end
else
begin
PM_CheckJump;
PM_Friction_func;
if (pm.waterlevel >= 2) then
PM_WaterMove
else
begin
VectorCopy(pm.viewangles, angles);
if (angles[PITCH] > 180) then
angles[PITCH] := angles[PITCH] - 360;
angles[PITCH] := angles[PITCH] / 3;
AngleVectors(angles, @pml.forward, @pml.right, @pml.up);
PM_AirMove;
end;
end;
// set groundentity, watertype, and waterlevel for final spot
PM_CatagorizePosition;
PM_SnapPosition;
end;
end.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -