⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sv_world.pas

📁 雷神之锤2(Quake2)Delphi源码
💻 PAS
📖 第 1 页 / 共 2 页
字号:
      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;

  (* Original variant:
  for (l=start->next  ; l != start ; l = next)
  {
          next = l->next;
          check = EDICT_FROM_AREA(l);

          if (check->solid == SOLID_NOT)
                  continue;		// deactivated
          if (check->absmin[0] > area_maxs[0]
          || check->absmin[1] > area_maxs[1]
          || check->absmin[2] > area_maxs[2]
          || check->absmax[0] < area_mins[0]
          || check->absmax[1] < area_mins[1]
          || check->absmax[2] < area_mins[2])
                  continue;		// not touching

          if (area_count == area_maxcount)
          {
                  Com_Printf ("SV_AreaEdicts: MAXCOUNT\n");
                  return;
          }

          area_list[area_count] = check;
          area_count++;
  } *)

  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_t; list: PParea_list;
  maxcount, areatype: Integer): Integer;
begin
  area_mins := @mins;
  area_maxs := @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_t ;
  PEdictArr = ^TEdictArr;

function SV_PointContents(p: vec3_t): Integer;
var
  touch: PEdictArr;
  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: PEdictArr;
  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 ( not(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
{$ifdef 0}
  // 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];
{$else}
  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;
{$endif}
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 + -