📄 m_move.pas
字号:
(*
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.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*)
// m_move.c -- monster movement
{******************************************************
Name: m_move.pas
Translator: you_known
Description: a part of Quake 2 - Visual C to Delphi
Conversion
Date: 2002-02-02 22:10
E-mail: you_known@163.com
******************************************************}
unit m_move;
interface
implementation
uses
game,
g_local,
g_utils,
q_shared;
const
STEPSIZE = 18;
(*
=============
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)<>0) 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<>nil) then
begin
if not (ent^.goalentity<>nil) then
ent^.goalentity := ent^.enemy;
dz := ent^.s.origin[2] - ent^.goalentity^.s.origin[2];
if (ent^.goalentity^.client<>nil) then
begin
if dz > 40 then
neworg[2] := neworg[2] - 8;
if not ((ent^.flags and FL_SWIM<>0) 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<>0) then
begin
if not (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)=1 then
result := False;
end;
end;
// swim monsters don't exit water voluntarily
if (ent^.flags and FL_SWIM<>0) then
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<>nil) then
break;
end;
result := False;
end;
// push down from a step height above the wished position
if not (ent^.monsterinfo.aiflags and AI_NOSTEP<>0) then
stepsizes := STEPSIZE
else
stepsizes := 1;
neworg[2] := neworg[2] + stepsizes;
VectorCopy (neworg, vend);
vend[2] := Pointer(Cardinal(@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);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -