📄 m_move.pas
字号:
{----------------------------------------------------------------------------}
{ }
{ File(s): m_move.pas }
{ Content: Monster movement commands }
{ }
{ Initial conversion by : you_known - you_known@163.com }
{ Initial conversion on : 03-Feb-2002 }
{ }
{ This File contains part of convertion of Quake2 source to ObjectPascal. }
{ More information about this project can be found at: }
{ http://www.sulaco.co.za/quake2/ }
{ }
{ Copyright (C) 1997-2001 Id Software, Inc. }
{ }
{ This program is free software; you can redistribute it and/or }
{ modify it under the terms of the GNU General Public License }
{ as published by the Free Software Foundation; either version 2 }
{ of the License, or (at your option) any later version. }
{ }
{ This program is distributed in the hope that it will be useful, }
{ but WITHOUT ANY WARRANTY; without even the implied warranty of }
{ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. }
{ }
{ See the GNU General Public License for more details. }
{ }
{----------------------------------------------------------------------------}
{ * Updated: }
{----------------------------------------------------------------------------}
{ * Still dependent (to compile correctly) on: }
{ }
{----------------------------------------------------------------------------}
{ * TODO: }
{ }
{----------------------------------------------------------------------------}
unit m_move;
interface
uses g_local;
type pedict_t = ^edict_t;
qboolean =boolean;
const STEPSIZE = 18;
implementation
(*
=============
M_CheckBottom
Returns false if any part of the bottom of the entity is off an edge that
is not a staircase.
=============
*)
var c_yes,c_no: Smallint;
function M_CheckBottom(ent:pedict_t):qboolean;
label realcheck;
var mins, maxs, start, stop: vec3_t;
trace: trace_t;
x,y: Smallint;
mid,bottom: Single;
begin
VectorAdd(ent^.s.origin,ent^.mins,mins);
VectorAdd(ent^.s.origin,ent^.maxs,maxs);
// if all of the points under the corners are solid world, don't bother
// with the tougher checks
// the corners must be within 16 of the midpoint
start[2] := mins[2] - 1;
for x := 0 to 1 do
for y := 0 to 1 do
begin
if x = 0 then
start[0] := mins[0] else start[0] := maxs[0];
if y = 0 then
start[1] := mins[1] else start[1] := maxs[1];
if gi.pointcontents(start) <> CONTENTS_SOLID then
goto realcheck;
end;
c_yes := c_yes + 1;
result:=True; // we got out easy
realcheck:
c_no := c_no + 1;
//
// check it for real...
//
start[2] := mins[2];
// the midpoint must be within 16 of the bottom
stop[0] := (mins[0] + maxs[0])*0.5;
start[0] := stop[0];
stop[1] := (mins[1] + maxs[1])*0.5;
start[1] := stop[1];
stop[2] := start[2] - 2*STEPSIZE;
trace := gi.trace (start, vec3_origin, vec3_origin, stop, ent, MASK_MONSTERSOLID);
if trace.fraction = 1.0 then
result := False;
bottom := trace.endpos[2];
mid := bottom;
// the corners must be within 16 of the midpoint
for x := 0 to 1 do
for y :=0 to 1 do
begin
if x = 0 then
stop[0] := mins[0] else stop[0] := maxs[0];
start[0] := stop[0];
if y = 0 then
stop[1] := mins[1] else stop[1] := maxs[1];
start[1] := stop[1];
trace := gi.trace (start, vec3_origin, vec3_origin, stop, ent, MASK_MONSTERSOLID);
if (trace.fraction <> 1.0) and (trace.endpos[2] > bottom) then
bottom := trace.endpos[2];
if (trace.fraction = 1.0) or (mid - trace.endpos[2] > STEPSIZE)
then result := False;
end;
c_yes := c_yes + 1;
result := True;
end;
(*
=============
SV_movestep
Called by monster program code.
The move will be adjusted for slopes and stairs, but if the move isn't
possible, no move is done, false is returned, and
pr_global_struct->trace_normal is set to the normal of the blocking wall
=============
*)
//FIXME since we need to test end position contents here, can we avoid doing
//it again later in catagorize position?
function SV_movestep(ent:pedict_t; move:vec3_t; relink:qboolean):qboolean;
var dz:Single;
oldorg, neworg, vend:vec3_t; //We can not use 'end' here,so I used vend.
trace:trace_t;
i:Smallint;
stepsizes:Single; //Well,case not sensitive,'stepsizes' replaced 'stepsize'.
test:vec3_t;
contents:smallint;
begin
// try the move
VectorCopy (ent^.s.origin, oldorg);
VectorAdd (ent^.s.origin, move, neworg);
// flying monsters don't step up
if (ent^.flags and (FL_SWIM or FL_FLY)) then
begin
// try one move with vertical motion, then one without
for i := 0 to 1 do
begin
VectorAdd(ent^.s.origin, move ,neworg);
if (i = 0) and (ent^.enemy) then
begin
if not ent^.goalentity then
ent^.goalentity := ent^.enemy;
dz := ent^.s.origin[2] - ent^.goalentity^.s.origin[2];
if (ent^.goalentity^.client) then
begin
if dz > 40 then
neworg[2] := neworg[2] - 8;
if not ((ent^.flags and FL_SWIM) and (ent^.waterlevel < 2)) then
if dz < 30 then
neworg[2] := neworg[2] + 8;
end
else
begin
if dz > 8 then
neworg[2] := neworg[2] + 8
else if dz > 0 then
neworg[2] := neworg[2] - dz
else if dz < -8 then
neworg[2] := neworg[2] + 8
else neworg[2] := neworg[2] + dz;
end;
end;
trace := gi.trace (ent^.s.origin, ent^.mins, ent^.maxs, neworg, ent, MASK_MONSTERSOLID);
// fly monsters don't enter water voluntarily
if (ent^.flags and FL_FLY) then
begin
if not ent^.waterlevel then
begin
test[0] := trace.endpos[0];
test[1] := trace.endpos[1];
test[2] := trace.endpos[2] + ent^.mins[2] + 1;
contents := gi.pointcontents(test);
if (contents and MASK_WATER)=1 then
result := False;
end;
end;
// swim monsters don't exit water voluntarily
if (ent^.flags and FL_SWIM)
begin
if (ent^.waterlevel < 2) then
begin
test[0] := trace.endpos[0];
test[1] := trace.endpos[1];
test[2] := trace.endpos[2] + ent^.mins[2] + 1;
contents := gi.pointcontents(test);
if not (contents and MASK_WATER)=1 then
result := False;
end;
end;
if trace.fraction = 1 then
begin
VectorCopy (trace.endpos, ent^.s.origin);
if relink then
begin
gi.linkentity (ent);
G_TouchTriggers (ent);
end;
result := True;
end;
if not ent^.enemy then
break;
end;
result := False;
end;
// push down from a step height above the wished position
if not ((ent^.monsterinfo.aiflags) and (AI_NOSTEP)) then
stepsizes := STEPSIZE
else
stepsizes := 1;
neworg[2] := neworg[2] + stepsizes;
VectorCopy (neworg, vend);
vend[2] := vend - stepsizes * 2;
trace := gi.trace (neworg, ent^.mins, ent^.maxs, vend, ent, MASK_MONSTERSOLID);
if trace.allsolid then
result := False;
if trace.startsolid then
begin
neworg[2] := neworg[2] - stepsizes;
trace := gi.trace (neworg, ent^.mins, ent^.maxs, vend, ent, MASK_MONSTERSOLID);
if (trace.allsolid or trace.startsolid) then
result := False;
end;
// don't go in to water
if ent^.waterlevel = 0 then
begin
test[0] := trace.endpos[0];
test[1] := trace.endpos[1];
test[2] := trace.endpos[2] + ent^.mins[2] + 1;
contents := gi.pointcontents(test);
if (contents and MASK_WATER)
result := False;
end;
if trace.fraction = 1 then
begin
// if monster had the ground pulled out, go ahead and fall
if (ent^.flags and FL_PARTIALGROUND) then
begin
VectorAdd (ent^.s.origin, move, ent^.s.origin);
if relink then
begin
gi.linkentity (ent);
G_TouchTriggers (ent);
end;
ent^.groundentity := nil;
result := True;
end;
result := False; // walked off an edge
end;
// check point traces down for dangling corners
VectorCopy (trace.endpos, ent^.s.origin);
if not (M_CheckBottom (ent)) then
begin
if (ent^.flags and FL_PARTIALGROUND) then
begin
// entity had floor mostly pulled out from underneath it
// and is trying to correct
if relink then
begin
gi.linkentity (ent);
G_TouchTriggers (ent);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -