📄 sv_world.pas
字号:
end;
Inc(ent^.linkcount);
if (ent^.solid = SOLID_NOT) then
Exit;
// find the first node that the ent's box crosses
node := @sv_areanodes;
while (True) do
begin
if (node^.axis = -1) then
Break;
if (ent^.absmin[node^.axis] > node^.dist) then
node := node^.children[0]
else if (ent^.absmax[node^.axis] < node^.dist) then
node := node^.children[1]
else
Break; // crosses the node
end;
// link it in
if (ent^.solid = SOLID_TRIGGER) then
InsertLinkBefore(@ent^.area, @node^.trigger_edicts)
else
InsertLinkBefore(@ent^.area, @node^.solid_edicts);
end;
(*
====================
SV_AreaEdicts_r
====================
*)
procedure SV_AreaEdicts_r(node: areanode_p);
var
l, next, start: link_p;
check: edict_p;
// count: Integer;
begin
// count := 0;
// touch linked edicts
if (area_type = AREA_SOLID) then
start := @node.solid_edicts
else
start := @node.trigger_edicts;
l := start^.next;
while l <> start do
begin
next := l^.next;
check := EDICT_FROM_AREA(l);
if (check^.solid = SOLID_NOT) then
begin
l := next;
Continue; // deactivated
end;
if ((check^.absmin[0] > area_maxs^[0]) or
(check^.absmin[1] > area_maxs^[1]) or
(check^.absmin[2] > area_maxs^[2]) or
(check^.absmax[0] < area_mins^[0]) or
(check^.absmax[1] < area_mins^[1]) or
(check^.absmax[2] < area_mins^[2])) then
begin
l := next;
Continue; // not touching
end;
if (area_count = area_maxcount) then
begin
Com_Printf('SV_AreaEdicts: MAXCOUNT'#10, []);
Exit;
end;
area_list^[area_count] := check;
Inc(area_count);
l := next;
end;
if (node^.axis = -1) then
Exit; // terminal node
// recurse down both sides
if (area_maxs^[node^.axis] > node^.dist) then
SV_AreaEdicts_r(node^.children[0]);
if (area_mins^[node^.axis] < node^.dist) then
SV_AreaEdicts_r(node^.children[1]);
end;
(*
================
SV_AreaEdicts
================
*)
function SV_AreaEdicts(mins, maxs: vec3_p; list: Parea_list;
maxcount, areatype: Integer): Integer;
begin
area_mins := PSingleArray(mins);
area_maxs := PSingleArray(maxs);
area_list := list;
area_count := 0;
area_maxcount := maxcount;
area_type := areatype;
SV_AreaEdicts_r(@sv_areanodes);
Result := area_count;
end;
//===========================================================================
(*
=============
SV_PointContents
=============
*)
type
TEdictArr = array[0..MAX_EDICTS - 1] of edict_p;
PEdictArr = ^TEdictArr;
function SV_PointContents(const p: vec3_t): Integer;
var
touch: TEdictArr;
hit: edict_p;
i, num: Integer;
contents, c2: Integer;
headnode: Integer;
angles: PSingleArray;
begin
// get base contents from world
contents := CM_PointContents(p, sv.models[1].headnode);
// or in contents from all the other entities
num := SV_AreaEdicts(@p, @p, Parea_list(@touch), MAX_EDICTS, AREA_SOLID);
for i := 0 to (num - 1) do
begin
hit := touch[i];
// might intersect, so do an exact clip
headnode := SV_HullForEntity(hit);
angles := @hit^.s.angles;
if (hit^.solid <> SOLID_BSP) then
angles := @vec3_origin; // boxes don't rotate
c2 := CM_TransformedPointContents(p, headnode, hit^.s.origin, hit^.s.angles);
contents := contents or c2;
end;
Result := contents;
end;
type
moveclip_p = ^moveclip_t;
moveclip_t = record
boxmins, boxmaxs: vec3_t; // enclose the test object along entire move
mins, maxs: PSingleArray; // size of the moving object
mins2, maxs2: vec3_t; // size when clipping against mosnters
start, end_: PSingleArray;
trace: trace_t;
passedict: edict_p;
contentmask: Integer;
end;
(*
================
SV_HullForEntity
Returns a headnode that can be used for testing or clipping an
object of mins/maxs size.
Offset is filled in to contain the adjustment that must be added to the
testing object's origin to get a point to use with the returned hull.
================
*)
function SV_HullForEntity(ent: edict_p): Integer;
var
model: cmodel_p;
begin
// decide which clipping hull to use, based on the size
if (ent^.solid = SOLID_BSP) then
begin
// explicit hulls in the BSP model
model := sv.models[ent^.s.modelindex];
if (model = nil) then
Com_Error(ERR_FATAL, 'MOVETYPE_PUSH with a non bsp model', []);
Result := model^.headnode;
Exit;
end;
// create a temp hull from bounding box sizes
Result := CM_HeadnodeForBox(ent^.mins, ent^.maxs);
end;
//===========================================================================
(*
====================
SV_ClipMoveToEntities
====================
*)
procedure SV_ClipMoveToEntities(clip: moveclip_p);
var
i, num: Integer;
touchlist: TEdictArr;
touch: edict_p;
trace: trace_t;
headnode: Integer;
angles: PSingleArray;
begin
num := SV_AreaEdicts(@clip.boxmins, @clip.boxmaxs, Parea_list(@touchlist), 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
touch := touchlist[i];
if (touch^.solid = SOLID_NOT) then
Continue;
if (touch = clip^.passedict) then
Continue;
if (clip^.trace.allsolid) then
Exit;
if (clip^.passedict <> nil) then
begin
if (touch^.owner = clip^.passedict) then
Continue; // don't clip against own missiles
if (clip^.passedict^.owner = touch) then
Continue; // don't clip against owner
end;
if ((clip^.contentmask and CONTENTS_DEADMONSTER = 0) and
((touch^.svflags and SVF_DEADMONSTER) <> 0)) then
Continue;
// might intersect, so do an exact clip
headnode := SV_HullForEntity(touch);
angles := @touch^.s.angles;
if (touch^.solid <> SOLID_BSP) then
angles := @vec3_origin; // boxes don't rotate
if (touch^.svflags and SVF_MONSTER) <> 0 then
trace := CM_TransformedBoxTrace(vec3_p(clip^.start)^, vec3_p(clip^.end_)^,
clip^.mins2, clip^.maxs2, headnode, clip^.contentmask,
touch^.s.origin, vec3_p(angles)^)
else
trace := CM_TransformedBoxTrace(vec3_p(clip^.start)^, vec3_p(clip^.end_)^,
vec3_p(clip^.mins)^, vec3_p(clip^.maxs)^, headnode, clip^.contentmask,
touch^.s.origin, vec3_p(angles)^);
if ((trace.allsolid) or (trace.startsolid) or
(trace.fraction < clip^.trace.fraction)) then
begin
trace.ent := touch;
if (clip^.trace.startsolid) then
begin
clip^.trace := trace;
clip^.trace.startsolid := true;
end
else
clip^.trace := trace;
end
else if (trace.startsolid) then
clip^.trace.startsolid := true;
end;
end;
(*
==================
SV_TraceBounds
==================
*)
procedure SV_TraceBounds(var start, mins, maxs, end_, boxmins, boxmaxs: vec3_t);
var
i: Integer;
begin
{
// debug to test against everything
boxmins[2] := -9999;
boxmins[1] := boxmins[2];
boxmins[0] := boxmins[1];
boxmaxs[2] := 9999;
boxmaxs[1] := boxmaxs[2];
boxmaxs[0] := boxmaxs[1];
}
for i := 0 to 2 do
begin
if (end_[i] > start[i]) then
begin
boxmins[i] := start[i] + mins[i] - 1;
boxmaxs[i] := end_[i] + maxs[i] + 1;
end
else
begin
boxmins[i] := end_[i] + mins[i] - 1;
boxmaxs[i] := start[i] + maxs[i] + 1;
end;
end;
end;
(*
==================
SV_Trace
Moves the given mins/maxs volume through the world from start to end.
Passedict and edicts owned by passedict are explicitly not checked.
==================
*)
function SV_Trace(start, mins, maxs, end_: vec3_p; passedict: edict_p; contentmask: Integer): trace_t;
var
clip: moveclip_t;
begin
if (mins = nil) then
mins := @vec3_origin;
if (maxs = nil) then
maxs := @vec3_origin;
FillChar(clip, SizeOf(moveclip_t), 0);
// clip to world
clip.trace := CM_BoxTrace(start^, end_^, mins^, maxs^, 0, contentmask);
clip.trace.ent := ge^.edicts;
if (clip.trace.fraction = 0) then
begin
Result := clip.trace; // blocked by the world
Exit;
end;
clip.contentmask := contentmask;
clip.start := PSingleArray(start);
clip.end_ := PSingleArray(end_);
clip.mins := PSingleArray(mins);
clip.maxs := PSingleArray(maxs);
clip.passedict := passedict;
VectorCopy(mins^, clip.mins2);
VectorCopy(maxs^, clip.maxs2);
// create the bounding box of the entire move
SV_TraceBounds(start^, clip.mins2, clip.maxs2, end_^, clip.boxmins, clip.boxmaxs);
// clip to other solid entities
SV_ClipMoveToEntities(@clip);
Result := clip.trace;
end;
end.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -