📄 g_utils.pas
字号:
begin
if (@t.use <> nil) then
t.use(t, ent, activator);
end;
if not ent.inuse then
begin
gi_dprintf('entity was removed while using targets'#10, []);
Exit;
end;
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(v[0]), Round(v[1]), Round(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; out 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(vec: vec3_t): Single;
var
yaw: Single;
begin
if ((* vec[YAW] == 0 && *) vec[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((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; out 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(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(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 = e - g_edicts;
e.s.number := (Integer(e) - Integer(g_edicts)) div SizeOf(edict_s); //todo: Clootie: need to check
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;
{$Warnings Off}
var
i, i_hack: Integer; //Clootie: i_hack - is Delphi local cycle variable hack
e: edict_p;
begin
e := @g_edicts[Round(maxclients.value)+1];
// for ( i=maxclients->value+1 ; i<globals.num_edicts ; i++, e++)
for i:= Round(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;
{$Warnings On}
(*
=================
G_FreeEdict
Marks the edict as free
=================
*)
procedure G_FreeEdict(ed: edict_p);
begin
gi.unlinkentity(ed); // unlink from world
//todo: Clootie: need to check
if ((Integer(ed) - Integer(g_edicts)) div SizeOf(edict_s) <=
(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(const ent: edict_t);
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 (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 + -