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

📄 sv_world.pas

📁 雷神之锤2(Quake2)Delphi源码
💻 PAS
📖 第 1 页 / 共 2 页
字号:
unit sv_world;


// world.c -- world query functions

interface


uses
  SysUtils,
  Common,
  GameUnit,
  q_shared,
  Server;


type
  areanode_p = ^areanode_s;
  areanode_s = record
    axis: Integer;		// -1 = leaf node
    dist: Single;
    children: array[0..2] of areanode_p; // to areanode_t;
    trigger_edicts: link_t;
    solid_edicts: link_t;
  end;
  areanode_t = areanode_s;


function SV_HullForEntity(ent: edict_p): Integer; cdecl;
procedure SV_ClearWorld; cdecl;
procedure SV_LinkEdict(ent: edict_p); cdecl;
procedure SV_UnlinkEdict(ent: edict_p); cdecl;
function SV_AreaEdicts (mins, maxs: vec3_t; list: PParea_list;
  maxcount, areatype: Integer): Integer; cdecl;
function SV_Trace(start, mins, maxs, end_: vec3_p; passedict: edict_p; contentmask: Integer): trace_t; cdecl;
function SV_PointContents(p: vec3_t): Integer; cdecl;


const
  AREA_DEPTH = 4;
  AREA_NODES = 32;


type
{$IFNDEF COMPILER6_UP}
  TSingleArray = array [0..MaxInt div SizeOf(Single)-1] of Single;
  PSingleArray = ^TSingleArray;
{$ENDIF}


var
  sv_areanodes: array[0..AREA_NODES-1] of areanode_t;
  sv_numareanodes: Integer;

  area_mins, area_maxs: PSingleArray;
  area_list: PParea_list;
  area_count, area_maxcount: Integer;
  area_type: Integer;



implementation


uses
  CModel,
  g_local,
  sv_game,
  sv_init;

// !!!! Juha: Phew... !!!
(*
#define	STRUCT_FROM_LINK(l,t,m) ((t * )((byte * )l - (int)&(((t * )0)->m)))
#define	EDICT_FROM_AREA(l) STRUCT_FROM_LINK(l,edict_t,area)
*)

function EDICT_FROM_AREA(l: pointer): edict_p;
begin
 Result := edict_p(@edict_p(l).area);
end;



// ClearLink is used for new headnodes
procedure ClearLink(l: link_p);
begin
  l^.next := l;
  l^.prev := l^.next;
end;

procedure RemoveLink(l: link_p);
begin
  l^.next^.prev := l^.prev;
  l^.prev^.next := l^.next;
end;

procedure InsertLinkBefore(l: link_p; before: link_p);
begin
  l^.next := before;
  l^.prev := before^.prev;
  l^.prev^.next := l;
  l^.next^.prev := l;
end;


(*
===============
SV_CreateAreaNode

Builds a uniformly subdivided tree for the given world size
===============
*)
function SV_CreateAreaNode(depth: Integer; mins, maxs: vec3_t): areanode_p;
var
  anode: areanode_p;
  size, mins1, maxs1, mins2, maxs2: vec3_t;
begin
  anode := @sv_areanodes[sv_numareanodes];
  Inc(sv_numareanodes);

  ClearLink(@anode^.trigger_edicts);
  ClearLink(@anode^.solid_edicts);

  if (depth = AREA_DEPTH) then
  begin
    anode^.axis := -1;
    anode^.children[1] := Nil;
    anode^.children[0] := anode^.children[1];
    Result := anode;
    Exit;
  end;

  VectorSubtract(maxs, mins, size);
  if (size[0] > size[1]) then
    anode^.axis := 0
  else
    anode^.axis := 1;

  anode^.dist := 0.5 * (maxs[anode^.axis] + mins[anode^.axis]);
  VectorCopy(mins, mins1);
  VectorCopy(mins, mins2);
  VectorCopy(maxs, maxs1);
  VectorCopy(maxs, maxs2);

  mins2[anode^.axis] := anode^.dist;
  maxs1[anode^.axis] := mins2[anode^.axis];

  anode^.children[0] := SV_CreateAreaNode(depth + 1, mins2, maxs2);
  anode^.children[1] := SV_CreateAreaNode(depth + 1, mins1, maxs1);

  Result := anode;
end;

(*
===============
SV_ClearWorld

===============
*)
procedure SV_ClearWorld;
begin
  FillChar(sv_areanodes, SizeOf(sv_areanodes), 0);
  sv_numareanodes := 0;
  SV_CreateAreaNode(0, sv.models[1].mins, sv.models[1].maxs);
end;


(*
===============
SV_UnlinkEdict

===============
*)
procedure SV_UnlinkEdict(ent: edict_p); cdecl;
begin
  if (ent.area.prev = nil) then
    Exit;		// not linked in anywhere
  RemoveLink(@ent^.area);
  ent^.area.next := nil;
  ent^.area.prev := ent^.area.next;
end;

(*
===============
SV_LinkEdict

===============
*)
const
  MAX_TOTAL_ENT_LEAFS = 128;

type
  TMaxLeafsArray = array[0..MAX_TOTAL_ENT_LEAFS-1] of Integer;

procedure SV_LinkEdict(ent: edict_p);
var
  node: areanode_p;
  leafs: TMaxLeafsArray;
  clusters: TMaxLeafsArray;
  num_leafs: Integer;
  i, j, k: Integer;
  area: Integer;
  topnode: Integer;
  max, v: Single;
begin
  if (ent.area.prev <> nil) then
    SV_UnlinkEdict(ent);	// unlink from old position

  if (ent = ge^.edicts) then
    Exit;		// don't add the world

  if (not ent^.inuse) then
    Exit;

  // set the size
  VectorSubtract(ent^.maxs, ent^.mins, ent^.size);

  // encode the size into the entity_state for client prediction
  if (ent^.solid = SOLID_BBOX) AND ((ent^.svflags AND SVF_DEADMONSTER) = 0) then
  begin
    // assume that x/y are equal and symetric
    i := Trunc(ent^.maxs[0] / 8);
    if (i < 1) then
      i := 1;

    if (i > 31) then
      i := 31;

    // z is not symetric
    j := Trunc((-ent^.mins[2]) / 8);
    if (j < 1) then
      j := 1;

    if (j > 31) then
      j := 31;

    // and z maxs can be negative...
    k := Trunc((ent^.maxs[2] + 32) / 8);
    if (k < 1) then
      k := 1;

    if (k > 63) then
      k := 63;

    ent^.s.solid := (k shl 10) OR (j shl 5) OR i;
  end
  else if (ent^.solid = SOLID_BSP) then
  begin
    ent^.s.solid := 31;		// a solid_bbox will never create this value
  end
  else
    ent^.s.solid := 0;

  // set the abs box
  if ((ent^.solid = SOLID_BSP) AND
  ((ent^.s.angles[0] <> 0) OR (ent^.s.angles[1] <> 0) OR (ent^.s.angles[2] <> 0))) then
  begin
    // expand for rotation
    max := 0;
    for i := 0 to 2 do
    begin
      v := fabs(ent^.mins[i]);
      if (v > max) then
        max := v;
      v := fabs(ent^.maxs[i]);
      if (v > max) then
        max := v;
    end;
    for i := 0 to 2 do
    begin
      ent^.absmin[i] := ent^.s.origin[i] - max;
      ent^.absmax[i] := ent^.s.origin[i] + max;
    end;
  end
  else
  begin
    // normal
    VectorAdd(ent^.s.origin, ent^.mins, ent^.absmin);
    VectorAdd(ent^.s.origin, ent^.maxs, ent^.absmax);
  end;

  // because movement is clipped an epsilon away from an actual edge,
  // we must fully check even when bounding boxes don't quite touch
  ent^.absmin[0] := ent^.absmin[0] - 1;
  ent^.absmin[1] := ent^.absmin[1] - 1;
  ent^.absmin[2] := ent^.absmin[2] - 1;
  ent^.absmax[0] := ent^.absmax[0] + 1;
  ent^.absmax[1] := ent^.absmax[1] + 1;
  ent^.absmax[2] := ent^.absmax[2] + 1;

// link to PVS leafs
  ent^.num_clusters := 0;
  ent^.areanum := 0;
  ent^.areanum2 := 0;

  //get all leafs, including solids
  num_leafs := CM_BoxLeafnums(ent^.absmin, ent^.absmax, @leafs,
    MAX_TOTAL_ENT_LEAFS, @topnode);

  // set areas
  for i := 0 to (num_leafs - 1) do
  begin
    clusters[i] := CM_LeafCluster(leafs[i]);
    area := CM_LeafArea(leafs[i]);
    if (area <> 0) then
    begin
      // doors may legally straggle two areas,
      // but nothing should evern need more than that
      if (ent^.areanum <> 0) AND (ent^.areanum <> area) then
      begin
        if (ent^.areanum2 <> 0) AND (ent^.areanum2 <> area) AND (sv.state = ss_loading) then
          Com_DPrintf('Object touching 3 areas at %f %f %f'#10, [
            ent^.absmin[0], ent^.absmin[1], ent^.absmin[2]]);

        ent^.areanum2 := area;
      end
      else
        ent^.areanum := area;
    end;
  end;

  if (num_leafs >= MAX_TOTAL_ENT_LEAFS) then
  begin
    // assume we missed some leafs, and mark by headnode
    ent^.num_clusters := -1;
    ent^.headnode := topnode;
  end
  else
  begin
    ent^.num_clusters := 0;
    for i := 0 to (num_leafs - 1) do
    begin
      if (clusters[i] = -1) then
        Continue;		// not a visible leaf

      j := 0;
      while j < i do
      begin
        if (clusters[j] = clusters[i]) then
          Break;
        Inc(j);
      end;

      if (j = i) then
      begin
        if (ent^.num_clusters = MAX_ENT_CLUSTERS) then
        begin
          // assume we missed some leafs, and mark by headnode
          ent^.num_clusters := -1;
          ent^.headnode := topnode;
          Break;
        end;

        ent^.clusternums[ent^.num_clusters] := clusters[i];
        Inc(ent^.num_clusters);
      end;
    end;
  end;

  // if first time, make sure old_origin is valid
  if (ent^.linkcount = 0) then
  begin
    VectorCopy(ent^.s.origin, ent^.s.old_origin);
  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

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -