📄 g_utils.pas
字号:
Exit;
end;
continue_:
t := G_Find(t, FOFS_targetname, ent^.target);
end;
end;
end;
(*
=============
TempVector
This is just a convenience function
for making temporary vectors for function calls
=============
*)
function tv(x, y, z: Single): PSingle;
{$IFDEF COMPILER6_UP}{$WRITEABLECONST ON}{$ENDIF}
const
index: Integer = 0;
vecs: array[0..7] of vec3_t =
((0,0,0),(0,0,0),(0,0,0),(0,0,0),(0,0,0),(0,0,0),(0,0,0),(0,0,0));
{$IFDEF COMPILER6_UP}{$WRITEABLECONST OFF}{$ENDIF}
var
v: vec3_p;
begin
// use an array so that multiple tempvectors won't collide
// for a while
v := @vecs[index];
index := (index + 1) and 7;
v[0] := x;
v[1] := y;
v[2] := z;
Result:= PSingle(v);
end;
(*
=============
VectorToString
This is just a convenience function
for printing vectors
=============
*)
function vtos(const v: vec3_t): PChar;
{$IFDEF COMPILER6_UP}{$WRITEABLECONST ON}{$ENDIF}
const
index: Integer = 0;
str: array[0..7, 0..31] of Char = (
#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0,
#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0,
#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0,
#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0,
#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0,
#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0,
#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0,
#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0
);
{$IFDEF COMPILER6_UP}{$WRITEABLECONST OFF}{$ENDIF}
var
s: PChar;
begin
// use an array so that multiple vtos won't collide
s := str[index];
index := (index + 1) and 7;
Com_sprintf(s, 32, '(%d %d %d)', [{Round}Trunc(v[0]), {Round}Trunc(v[1]), {Round}Trunc(v[2])]);
Result:= s;
end;
var
VEC_UP : vec3_t = (0, -1, 0);
MOVEDIR_UP : vec3_t = (0, 0, 1);
VEC_DOWN : vec3_t = (0, -2, 0);
MOVEDIR_DOWN : vec3_t = (0, 0, -1);
procedure G_SetMovedir(var angles: vec3_t; var movedir: vec3_t);
begin
if VectorCompare(angles, VEC_UP) <> 0 then
begin
VectorCopy(MOVEDIR_UP, movedir);
end
else if VectorCompare(angles, VEC_DOWN) <> 0 then
begin
VectorCopy(MOVEDIR_DOWN, movedir);
end
else
begin
AngleVectors(angles, @movedir, nil, nil);
end;
VectorClear(angles);
end;
function vectoyaw(const vec: vec3_t): Single;
var
yaw: Single;
begin
if ((* vec[q_shared.YAW] == 0 && *) vec[q_shared.PITCH] = 0) then
begin
yaw := 0;
if (vec[q_shared.YAW] > 0) then
yaw := 90
else if (vec[q_shared.YAW] < 0) then
yaw := -90;
end else
begin
yaw := {Round}Trunc((ArcTan2(vec[q_shared.YAW], vec[q_shared.PITCH]) * 180 / M_PI));
if (yaw < 0) then
yaw := yaw + 360;
end;
Result:= yaw;
end;
procedure vectoangles(const value1: vec3_t; var angles: vec3_t);
var
forward_: Single;
yaw, pitch: Single;
begin
if (value1[1] = 0) and (value1[0] = 0) then
begin
yaw := 0;
if (value1[2] > 0) then
pitch := 90
else
pitch := 270;
end
else
begin
if (value1[0] <> 0) then
yaw := {Round}Trunc(ArcTan2(value1[1], value1[0]) * 180 / M_PI)
else if (value1[1] > 0) then
yaw := 90
else
yaw := -90;
if (yaw < 0) then
yaw := yaw + 360;
forward_ := sqrt(value1[0]*value1[0] + value1[1]*value1[1]);
pitch := {Round}Trunc(ArcTan2(value1[2], forward_) * 180 / M_PI);
if (pitch < 0) then
pitch := pitch + 360;
end;
angles[q_shared.PITCH] := -pitch;
angles[q_shared.YAW] := yaw;
angles[q_shared.ROLL] := 0;
end;
function G_CopyString(in_: PChar): PChar;
begin
Result := gi.TagMalloc(StrLen(in_)+1, TAG_LEVEL);
StrCopy(Result, in_);
end;
procedure G_InitEdict(e: edict_p);
begin
e^.inuse := True;
e^.classname := 'noclass';
e^.gravity := 1.0;
e^.s.number := (Integer(e) - Integer(g_edicts)) div SizeOf(edict_t);
end;
(*
=================
G_Spawn
Either finds a free edict, or allocates a new one.
Try to avoid reusing an entity that was recently freed, because it
can cause the client to think the entity morphed into something else
instead of being removed and recreated, which can cause interpolated
angles and bad trails.
=================
*)
function G_Spawn: edict_p;
var
i, i_hack: Integer; //Clootie: i_hack - is Delphi local cycle variable hack
e: edict_p;
begin
e := @g_edicts^[{Round}Trunc(maxclients^.value)+1] ;
i_hack := 0;
for i := {Round}Trunc(maxclients^.value)+1 to globals.num_edicts - 1 do
begin
// the first couple seconds of server time can involve a lot of
// freeing and allocating, so relax the replacement policy
if not e^.inuse and ((e^.freetime < 2) or (level.time - e^.freetime > 0.5)) then
begin
G_InitEdict(e);
Result := e;
Exit;
end;
Inc(e); // i++, e++)
i_hack := i + 1;
end;
if (i_hack = game.maxentities) then
gi.error('ED_Alloc: no free edicts', []);
Inc(globals.num_edicts);
G_InitEdict(e);
Result := e;
end;
(*
=================
G_FreeEdict
Marks the edict as free
=================
*)
procedure G_FreeEdict(ed: edict_p);
begin
gi.unlinkentity(ed); // unlink from world
if ((Integer(ed) - Integer(g_edicts)) div SizeOf(edict_t) <=
(maxclients^.value + BODY_QUEUE_SIZE)) then
begin
// gi.dprintf("tried to free special edict\n");
Exit;
end;
FillChar(ed^, SizeOf(ed^), 0);
ed^.classname := 'freed';
ed^.freetime := level.time;
ed^.inuse := false;
end;
(*
============
G_TouchTriggers
============
*)
procedure G_TouchTriggers(ent: edict_p);
var
i, num: Integer;
touch: array [0..MAX_EDICTS-1] of edict_p;
hit: edict_p;
begin
// dead things don't activate triggers!
if ((ent^.client <> nil) or (ent^.svflags and SVF_MONSTER <> 0)) and
(ent^.health <= 0) then
Exit;
num := gi.BoxEdicts(@ent^.absmin, @ent^.absmax, @touch, MAX_EDICTS, AREA_TRIGGERS);
// be careful, it is possible to have an entity in this
// list removed before we get to it (killtriggered)
for i := 0 to num - 1 do
begin
hit := touch[i];
if not hit^.inuse then
Continue;
if (@hit^.touch = nil) then
Continue;
hit^.touch(hit, ent, nil, nil);
end;
end;
(*
============
G_TouchSolids
Call after linking a new trigger in during gameplay
to force all entities it covers to immediately touch it
============
*)
procedure G_TouchSolids(ent: edict_p);
var
i, num: Integer;
touch: array [0..MAX_EDICTS-1] of edict_p;
hit: edict_p;
begin
num := gi.BoxEdicts(@ent^.absmin, @ent^.absmax, @touch, MAX_EDICTS, AREA_SOLID);
// be careful, it is possible to have an entity in this
// list removed before we get to it (killtriggered)
for i := 0 to num - 1 do
begin
hit := touch[i];
if not hit^.inuse then
Continue;
if (@hit^.touch <> nil) then
hit^.touch(hit, ent, nil, nil);
if not ent^.inuse then
Break;
end;
end;
(*
==============================================================================
Kill box
==============================================================================
*)
(*
=================
KillBox
Kills all entities that would touch the proposed new positioning
of ent. Ent should be unlinked before calling this!
=================
*)
function KillBox(ent: edict_p): qboolean;
var
tr: trace_t;
begin
while True do
begin
tr := gi.trace(@ent^.s.origin, @ent^.mins, @ent^.maxs, @ent^.s.origin, nil, MASK_PLAYERSOLID);
if (tr.ent = nil) then
Break;
// nail it
T_Damage(tr.ent, ent, ent, vec3_origin, ent^.s.origin, vec3_origin, 100000,
0, DAMAGE_NO_PROTECTION, MOD_TELEFRAG);
// if we didn't kill it, fail
if (edict_p(tr.ent)^.solid <> SOLID_NOT) then
begin
Result := False;
Exit;
end;
end;
Result := True; // all clear
end;
end.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -