DEADSOFTWARE

better hitscan tracer; no more level trace bitmap (but no more particles too, alas)
[d2df-sdl.git] / src / game / g_map.pas
index 0543abe30aa620cb0506c08d8e2c480dc06a0356..a73434b9b8c6632bd41dbe63a194dd5376885def 100644 (file)
@@ -172,6 +172,9 @@ var
 
 function panelTypeToTag (panelType: Word): Integer; // returns GridTagXXX
 
+function g_Map_traceToNearestWall (x0, y0, x1, y1: Integer; hitx: PInteger=nil; hity: PInteger=nil): Integer;
+
+
 implementation
 
 uses
@@ -281,6 +284,74 @@ begin
 end;
 
 
+// wall index in `gWalls` or -1
+function g_Map_traceToNearestWall (x0, y0, x1, y1: Integer; hitx: PInteger=nil; hity: PInteger=nil): Integer;
+var
+  maxDistSq: Single;
+
+  function sqchecker (pan: TPanel; var ray: Ray2D): Single;
+  var
+    aabb: AABB2D;
+    tmin: Single;
+  begin
+    result := -666.0; // invalid
+    if not pan.Enabled then exit;
+    aabb := AABB2D.CreateWH(pan.X, pan.Y, pan.Width, pan.Height);
+    if not aabb.valid then exit;
+    if aabb.intersects(ray, @tmin) then
+    begin
+      //if (tmin*tmin > maxDistSq) then exit;
+      if (tmin >= 0.0) then
+      begin
+        //e_WriteLog(Format('sqchecker(%d,%d,%d,%d): panel #%d (%d,%d)-(%d,%d); tmin=%f', [x0, y0, x1, y1, pan.arrIdx, pan.X, pan.Y, pan.Width, pan.Height, tmin]), MSG_NOTIFY);
+        //if (tmin < 0.0) then tmin := 0.0;
+        result := tmin;
+      end;
+    end;
+  end;
+
+var
+  qr: TDynAABBTreeMap.TSegmentQueryResult;
+  ray: Ray2D;
+  hxf, hyf: Single;
+  hx, hy: Integer;
+begin
+  result := -1;
+  if (mapTree = nil) then exit;
+  maxDistSq := (x1-x0)*(x1-x0)+(y1-y0)*(y1-y0);
+  if mapTree.segmentQuery(qr, x0, y0, x1, y1, sqchecker, (GridTagWall or GridTagDoor)) then
+  begin
+    if (qr.flesh <> nil) and (qr.time*qr.time <= maxDistSq) then
+    begin
+      result := qr.flesh.arrIdx;
+      if (hitx <> nil) or (hity <> nil) then
+      begin
+        ray := Ray2D.Create(x0, y0, x1, y1);
+        hxf := ray.origX+ray.dirX*qr.time;
+        hyf := ray.origY+ray.dirY*qr.time;
+        while true do
+        begin
+          hx := trunc(hxf);
+          hy := trunc(hyf);
+          if (hx >= qr.flesh.X) and (hy >= qr.flesh.Y) and (hx < qr.flesh.X+qr.flesh.Width) and (hy < qr.flesh.Y+qr.flesh.Height) then
+          begin
+            // go back a little
+            hxf -= ray.dirX;
+            hyf -= ray.dirY;
+          end
+          else
+          begin
+            break;
+          end;
+        end;
+        if (hitx <> nil) then hitx^ := hx;
+        if (hity <> nil) then hity^ := hy;
+      end;
+    end;
+  end;
+end;
+
+
 function g_Map_IsSpecialTexture(Texture: String): Boolean;
 begin
   Result := (Texture = TEXTURE_NAME_WATER) or
@@ -935,45 +1006,52 @@ end;
 
 procedure CreateMonster(monster: TMonsterRec_1);
 var
-  a, i: Integer;
+  a: Integer;
+  mon: TMonster;
 begin
   if g_Game_IsClient then Exit;
 
   if (gGameSettings.GameType = GT_SINGLE)
   or LongBool(gGameSettings.Options and GAME_OPTION_MONSTERS) then
   begin
-    i := g_Monsters_Create(monster.MonsterType, monster.X, monster.Y,
-                           TDirection(monster.Direction));
+    mon := g_Monsters_Create(monster.MonsterType, monster.X, monster.Y, TDirection(monster.Direction));
 
     if gTriggers <> nil then
+    begin
       for a := 0 to High(gTriggers) do
-        if gTriggers[a].TriggerType in [TRIGGER_PRESS,
-             TRIGGER_ON, TRIGGER_OFF, TRIGGER_ONOFF] then
-          if (gTriggers[a].Data.MonsterID-1) = gMonsters[i].StartID then
-            gMonsters[i].AddTrigger(a);
+      begin
+        if gTriggers[a].TriggerType in [TRIGGER_PRESS, TRIGGER_ON, TRIGGER_OFF, TRIGGER_ONOFF] then
+        begin
+          if (gTriggers[a].Data.MonsterID-1) = mon.StartID then mon.AddTrigger(a);
+        end;
+      end;
+    end;
 
-    if monster.MonsterType <> MONSTER_BARREL then
-      Inc(gTotalMonsters);
+    if monster.MonsterType <> MONSTER_BARREL then Inc(gTotalMonsters);
   end;
 end;
 
 procedure g_Map_ReAdd_DieTriggers();
-var
-  i, a: Integer;
-begin
-  if g_Game_IsClient then Exit;
 
-  for i := 0 to High(gMonsters) do
-    if gMonsters[i] <> nil then
+  function monsDieTrig (mon: TMonster): Boolean;
+  var
+    a: Integer;
+  begin
+    result := false; // don't stop
+    mon.ClearTriggers();
+    for a := 0 to High(gTriggers) do
+    begin
+      if gTriggers[a].TriggerType in [TRIGGER_PRESS, TRIGGER_ON, TRIGGER_OFF, TRIGGER_ONOFF] then
       begin
-        gMonsters[i].ClearTriggers();
-
-        for a := 0 to High(gTriggers) do
-          if gTriggers[a].TriggerType in [TRIGGER_PRESS,
-               TRIGGER_ON, TRIGGER_OFF, TRIGGER_ONOFF] then
-            if (gTriggers[a].Data.MonsterID-1) = gMonsters[i].StartID then
-              gMonsters[i].AddTrigger(a);
+        if (gTriggers[a].Data.MonsterID-1) = mon.StartID then mon.AddTrigger(a);
       end;
+    end;
+  end;
+
+begin
+  if g_Game_IsClient then Exit;
+
+  g_Mons_ForEach(monsDieTrig);
 end;
 
 function extractWadName(resourceName: string): string;
@@ -1026,7 +1104,7 @@ var
   mapX1: Integer = -$3fffffff;
   mapY1: Integer = -$3fffffff;
 
-  procedure calcBoundingBox (var panels: TPanelArray);
+  procedure calcBoundingBox (constref panels: TPanelArray);
   var
     idx: Integer;
     pan: TPanel;
@@ -1043,7 +1121,7 @@ var
     end;
   end;
 
-  procedure addPanelsToGrid (var panels: TPanelArray; tag: Integer);
+  procedure addPanelsToGrid (constref panels: TPanelArray; tag: Integer);
   var
     idx: Integer;
     pan: TPanel;
@@ -1890,7 +1968,7 @@ end;
 // old algo
 procedure g_Map_DrawPanels (PanelType: Word);
 
-  procedure DrawPanels (var panels: TPanelArray; drawDoors: Boolean=False);
+  procedure DrawPanels (constref panels: TPanelArray; drawDoors: Boolean=False);
   var
     idx: Integer;
   begin
@@ -2094,7 +2172,7 @@ function g_Map_CollideLiquid_TextureOld(X, Y: Integer; Width, Height: Word): DWO
 var
   texid: DWORD;
 
-  function checkPanels (var panels: TPanelArray): Boolean;
+  function checkPanels (constref panels: TPanelArray): Boolean;
   var
     a: Integer;
   begin