DEADSOFTWARE

`Grid.forEachAtPoint()` converted to no-callback
[d2df-sdl.git] / src / game / g_map.pas
index b1174c8595ef86a1dafd7b550994b894906e0e06..29ece6fafd845f590715a7502689b9fc1dc2630a 100644 (file)
@@ -1,4 +1,4 @@
-(* Copyright (C)  DooM 2D:Forever Developers
+(* Copyright (C)  Doom 2D: Forever Developers
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -20,9 +20,9 @@ unit g_map;
 interface
 
 uses
-  SysUtils, Classes,
+  SysUtils, Classes, mempool,
   e_graphics, g_basic, MAPDEF, g_textures,
-  g_phys, wadreader, g_panel, g_grid, md5, binheap, xprofiler, xparser, xdynrec;
+  g_phys, utils, g_panel, g_grid, md5, binheap, xprofiler, xparser, xdynrec;
 
 type
   TMapInfo = record
@@ -59,7 +59,7 @@ type
 
 function  g_Map_Load(Res: String): Boolean;
 function  g_Map_GetMapInfo(Res: String): TMapInfo;
-function  g_Map_GetMapsList(WADName: String): SArray;
+function  g_Map_GetMapsList(WADName: String): SSArray;
 function  g_Map_Exist(Res: String): Boolean;
 procedure g_Map_Free(freeTextures: Boolean=true);
 procedure g_Map_Update();
@@ -202,6 +202,14 @@ const
   GridDrawableMask = (GridTagBack or GridTagStep or GridTagWall or GridTagDoor or GridTagAcid1 or GridTagAcid2 or GridTagWater or GridTagFore);
 
 
+type
+  TBinHeapPanelDrawCmp = class
+  public
+    class function less (const a, b: TPanel): Boolean; inline;
+  end;
+
+  TBinHeapPanelDraw = specialize TBinaryHeapBase<TPanel, TBinHeapPanelDrawCmp>;
+
 var
   gWalls: TPanelArray;
   gRenderBackgrounds: TPanelArray;
@@ -224,10 +232,11 @@ var
   gdbg_map_use_accel_render: Boolean = true;
   gdbg_map_use_accel_coldet: Boolean = true;
   profMapCollision: TProfiler = nil; //WARNING: FOR DEBUGGING ONLY!
-  gDrawPanelList: TBinaryHeapObj = nil; // binary heap of all walls we have to render, populated by `g_Map_CollectDrawPanels()`
+  gDrawPanelList: TBinHeapPanelDraw = nil; // binary heap of all walls we have to render, populated by `g_Map_CollectDrawPanels()`
 
   gCurrentMap: TDynRecord = nil;
   gCurrentMapFileName: AnsiString = ''; // so we can skip texture reloading
+  gTestMap: String = '';
 
 
 function panelTypeToTag (panelType: Word): Integer; // returns GridTagXXX
@@ -247,7 +256,7 @@ uses
   GL, GLExt, g_weapons, g_game, g_sound, e_sound, CONFIG,
   g_options, g_triggers, g_player,
   Math, g_monsters, g_saveload, g_language, g_netmsg,
-  utils, sfs, xstreams, hashtable,
+  sfs, xstreams, hashtable, wadreader,
   ImagingTypes, Imaging, ImagingUtility,
   ImagingGif, ImagingNetworkGraphics;
 
@@ -506,20 +515,16 @@ begin
 end;
 
 
-function dplLess (a, b: TObject): Boolean;
-var
-  pa, pb: TPanel;
+class function TBinHeapPanelDrawCmp.less (const a, b: TPanel): Boolean; inline;
 begin
-  pa := TPanel(a);
-  pb := TPanel(b);
-  if (pa.tag < pb.tag) then begin result := true; exit; end;
-  if (pa.tag > pb.tag) then begin result := false; exit; end;
-  result := (pa.arrIdx < pb.arrIdx);
+  if (a.tag < b.tag) then begin result := true; exit; end;
+  if (a.tag > b.tag) then begin result := false; exit; end;
+  result := (a.arrIdx < b.arrIdx);
 end;
 
 procedure dplClear ();
 begin
-  if (gDrawPanelList = nil) then gDrawPanelList := TBinaryHeapObj.Create(@dplLess) else gDrawPanelList.clear();
+  if (gDrawPanelList = nil) then gDrawPanelList := TBinHeapPanelDraw.Create() else gDrawPanelList.clear();
 end;
 
 
@@ -589,6 +594,21 @@ begin
 end;
 
 
+function xxPanAtPointChecker (pan: TPanel; panelType: Word): Boolean; inline;
+begin
+  if ((pan.tag and GridTagLift) <> 0) then
+  begin
+    // stop if the lift of the right type
+    result :=
+      ((WordBool(PanelType and PANEL_LIFTUP) and (pan.LiftType = 0)) or
+       (WordBool(PanelType and PANEL_LIFTDOWN) and (pan.LiftType = 1)) or
+       (WordBool(PanelType and PANEL_LIFTLEFT) and (pan.LiftType = 2)) or
+       (WordBool(PanelType and PANEL_LIFTRIGHT) and (pan.LiftType = 3)));
+    exit;
+  end;
+  result := true; // otherwise, stop anyway, 'cause `forEachAtPoint()` is guaranteed to call this only for correct panels
+end;
+
 function g_Map_HasAnyPanelAtPoint (x, y: Integer; panelType: Word): Boolean;
 
   function checker (pan: TPanel; tag: Integer): Boolean;
@@ -617,6 +637,9 @@ function g_Map_HasAnyPanelAtPoint (x, y: Integer; panelType: Word): Boolean;
 
 var
   tagmask: Integer = 0;
+  pmark: PoolMark;
+  hitcount: Integer;
+  ppan: PPanel;
 begin
   result := false;
 
@@ -629,24 +652,41 @@ begin
   if WordBool(PanelType and PANEL_BLOCKMON) then tagmask := tagmask or GridTagBlockMon;
 
   if (tagmask = 0) then exit;// just in case
+
+  pmark := framePool.mark();
   if ((tagmask and GridTagLift) <> 0) then
   begin
     // slow
-    result := (mapGrid.forEachAtPoint(x, y, checker, tagmask) <> nil);
+    hitcount := mapGrid.forEachAtPoint(x, y, tagmask);
+    ppan := PPanel(framePool.getPtr(pmark));
+    while (hitcount > 0) do
+    begin
+      if (xxPanAtPointChecker(ppan^, PanelType)) then begin result := true; break; end;
+      Inc(ppan);
+      Dec(hitcount);
+    end;
   end
   else
   begin
     // fast
-    result := (mapGrid.forEachAtPoint(x, y, nil, tagmask) <> nil);
+    result := (mapGrid.forEachAtPoint(x, y, tagmask, false, true) <> 0); // firsthit
   end;
+  framePool.release(pmark);
 end;
 
 
 function g_Map_PanelAtPoint (x, y: Integer; tagmask: Integer=-1): TPanel;
+var
+  pmark: PoolMark;
+  hitcount: Integer;
 begin
   result := nil;
   if (tagmask = 0) then exit;
-  result := mapGrid.forEachAtPoint(x, y, nil, tagmask);
+  //result := mapGrid.forEachAtPoint(x, y, nil, tagmask);
+  pmark := framePool.mark();
+  hitcount := mapGrid.forEachAtPoint(x, y, tagmask, false, true); // firsthit
+  if (hitcount <> 0) then result := PPanel(framePool.getPtr(pmark))^;
+  framePool.release(pmark);
 end;
 
 
@@ -869,7 +909,7 @@ end;
 function CreateNullTexture(RecName: String): Integer;
 begin
   RecName := toLowerCase1251(RecName);
-  if (TextNameHash = nil) then TextNameHash := hashNewStrInt();
+  if (TextNameHash = nil) then TextNameHash := THashStrInt.Create();
   if TextNameHash.get(RecName, result) then exit; // i found her!
 
   SetLength(Textures, Length(Textures)+1);
@@ -896,7 +936,7 @@ var
   a, ResLength: Integer;
 begin
   RecName := toLowerCase1251(RecName);
-  if (TextNameHash = nil) then TextNameHash := hashNewStrInt();
+  if (TextNameHash = nil) then TextNameHash := THashStrInt.Create();
   if TextNameHash.get(RecName, result) then
   begin
     // i found her!
@@ -984,7 +1024,7 @@ begin
   else // Íåò òàêîãî ðåóñðñà â WAD'å
   begin
     //e_WriteLog(Format('SHIT! Error loading texture %s : %s', [RecName, g_ExtractFilePathName(RecName)]), MSG_WARNING);
-    if (BadTextNameHash = nil) then BadTextNameHash := hashNewStrInt();
+    if (BadTextNameHash = nil) then BadTextNameHash := THashStrInt.Create();
     if log and (not BadTextNameHash.get(RecName, a)) then
     begin
       e_WriteLog(Format('Error loading texture %s', [RecName]), TMsgType.Warning);
@@ -1014,7 +1054,7 @@ var
   f, c, frdelay, frloop: Integer;
 begin
   RecName := toLowerCase1251(RecName);
-  if (TextNameHash = nil) then TextNameHash := hashNewStrInt();
+  if (TextNameHash = nil) then TextNameHash := THashStrInt.Create();
   if TextNameHash.get(RecName, result) then
   begin
     // i found her!
@@ -1026,7 +1066,7 @@ begin
 
   //e_LogWritefln('*** Loading animated texture "%s"', [RecName]);
 
-  if (BadTextNameHash = nil) then BadTextNameHash := hashNewStrInt();
+  if (BadTextNameHash = nil) then BadTextNameHash := THashStrInt.Create();
   if BadTextNameHash.get(RecName, f) then
   begin
     //e_WriteLog(Format('no animation texture %s (don''t worry)', [RecName]), MSG_NOTIFY);
@@ -1044,7 +1084,7 @@ begin
 
     if not WAD.GetResource(g_ExtractFilePathName(RecName), TextureWAD, ResLength, log) then
     begin
-      if (BadTextNameHash = nil) then BadTextNameHash := hashNewStrInt();
+      if (BadTextNameHash = nil) then BadTextNameHash := THashStrInt.Create();
       if log and (not BadTextNameHash.get(RecName, f)) then
       begin
         e_WriteLog(Format('Error loading animation texture %s', [RecName]), TMsgType.Warning);
@@ -1138,7 +1178,7 @@ begin
         end
         else
         begin
-          if (BadTextNameHash = nil) then BadTextNameHash := hashNewStrInt();
+          if (BadTextNameHash = nil) then BadTextNameHash := THashStrInt.Create();
           if log and (not BadTextNameHash.get(RecName, f)) then
           begin
             e_WriteLog(Format('Error loading animation texture %s', [RecName]), TMsgType.Warning);
@@ -1230,7 +1270,7 @@ begin
       end
       else
       begin
-        if (BadTextNameHash = nil) then BadTextNameHash := hashNewStrInt();
+        if (BadTextNameHash = nil) then BadTextNameHash := THashStrInt.Create();
         if log  and (not BadTextNameHash.get(RecName, f)) then
         begin
           e_WriteLog(Format('Error loading animation texture "%s" images', [RecName]), TMsgType.Warning);
@@ -1609,7 +1649,7 @@ type
     actPanel: TDynRecord;
   end;
 var
-  WAD: TWADFile;
+  WAD, TestWAD: TWADFile;
   //mapReader: TDynRecord = nil;
   mapTextureList: TDynField = nil; //TTexturesRec1Array; tagInt: texture index
   panels: TDynField = nil; //TPanelsRec1Array;
@@ -1638,6 +1678,8 @@ var
 begin
   mapGrid.Free();
   mapGrid := nil;
+  TestWAD := nil;
+  Data := nil;
 
   //gCurrentMap.Free();
   //gCurrentMap := nil;
@@ -1666,13 +1708,41 @@ begin
         Exit;
       end;
 
-      //k8: why loader ignores path here?
-      mapResName := g_ExtractFileName(Res);
-      if not WAD.GetMapResource(mapResName, Data, Len) then
+      if gTestMap <> '' then
       begin
-        g_FatalError(Format(_lc[I_GAME_ERROR_MAP_RES], [mapResName]));
-        WAD.Free();
-        Exit;
+        s := g_ExtractWadName(gTestMap);
+        TestWAD := TWADFile.Create();
+        if not TestWAD.ReadFile(s) then
+        begin
+          g_SimpleError(Format(_lc[I_GAME_ERROR_MAP_WAD], [s]));
+          TestWAD.Free();
+          TestWAD := nil;
+        end;
+      end;
+
+      if TestWAD <> nil then
+      begin
+        mapResName := g_ExtractFileName(gTestMap);
+        if not TestWAD.GetMapResource(mapResName, Data, Len) then
+        begin
+          g_SimpleError(Format(_lc[I_GAME_ERROR_MAP_RES], [mapResName]));
+          Data := nil;
+        end else
+          e_WriteLog('Using test map: '+gTestMap, TMsgType.Notify);
+        TestWAD.Free();
+        TestWAD := nil;
+      end;
+
+      if Data = nil then
+      begin
+        //k8: why loader ignores path here?
+        mapResName := g_ExtractFileName(Res);
+        if not WAD.GetMapResource(mapResName, Data, Len) then
+        begin
+          g_FatalError(Format(_lc[I_GAME_ERROR_MAP_RES], [mapResName]));
+          WAD.Free();
+          Exit;
+        end;
       end;
 
       WAD.Free();
@@ -1749,7 +1819,7 @@ begin
       g_Game_SetLoadingText(_lc[I_LOAD_TEXTURES], mapTextureList.count-1, False);
 
       // find used textures
-      usedTextures := hashNewStrInt();
+      usedTextures := THashStrInt.Create();
       try
         if (panels <> nil) and (panels.count > 0) then
         begin
@@ -2290,11 +2360,11 @@ begin
   mapReader.Free();
 end;
 
-function g_Map_GetMapsList(WADName: string): SArray;
+function g_Map_GetMapsList(WADName: string): SSArray;
 var
   WAD: TWADFile;
   a: Integer;
-  ResList: SArray;
+  ResList: SSArray;
 begin
   Result := nil;
   WAD := TWADFile.Create();
@@ -2319,7 +2389,7 @@ function g_Map_Exist(Res: string): Boolean;
 var
   WAD: TWADFile;
   FileName, mnn: string;
-  ResList: SArray;
+  ResList: SSArray;
   a: Integer;
 begin
   Result := False;
@@ -2580,32 +2650,68 @@ end;
 
 // new algo
 procedure g_Map_CollectDrawPanels (x0, y0, wdt, hgt: Integer);
-
+  (*
   function checker (pan: TPanel; tag: Integer): Boolean;
   begin
     result := false; // don't stop, ever
     if ((tag and GridTagDoor) <> 0) <> pan.Door then exit;
     gDrawPanelList.insert(pan);
   end;
-
+  *)
+var
+  pmark: PoolMark;
+  phit: PPanel;
+  hitcount: Integer;
 begin
   dplClear();
   //tagmask := panelTypeToTag(PanelType);
-  mapGrid.forEachInAABB(x0, y0, wdt, hgt, checker, GridDrawableMask);
+  //mapGrid.forEachInAABB(x0, y0, wdt, hgt, checker, GridDrawableMask);
+  pmark := framePool.mark();
+  hitcount := mapGrid.forEachInAABB(x0, y0, wdt, hgt, GridDrawableMask);
+  if (hitcount = 0) then exit;
+  phit := PPanel(framePool.getPtr(pmark));
+  while (hitcount > 0) do
+  begin
+    if ((phit^.tag and GridTagDoor) <> 0) <> phit^.Door then
+    begin
+    end
+    else
+    begin
+      gDrawPanelList.insert(phit^);
+    end;
+    Inc(phit);
+    Dec(hitcount);
+  end;
+  framePool.release(pmark);
   // list will be rendered in `g_game.DrawPlayer()`
 end;
 
 
-procedure g_Map_DrawPanelShadowVolumes(lightX: Integer; lightY: Integer; radius: Integer);
-
+procedure g_Map_DrawPanelShadowVolumes (lightX: Integer; lightY: Integer; radius: Integer);
+  (*
   function checker (pan: TPanel; tag: Integer): Boolean;
   begin
     result := false; // don't stop, ever
     pan.DrawShadowVolume(lightX, lightY, radius);
   end;
-
+  *)
+var
+  pmark: PoolMark;
+  phit: PPanel;
+  hitcount: Integer;
 begin
-  mapGrid.forEachInAABB(lightX-radius, lightY-radius, radius*2, radius*2, checker, (GridTagWall or GridTagDoor));
+  //mapGrid.forEachInAABB(lightX-radius, lightY-radius, radius*2, radius*2, checker, (GridTagWall or GridTagDoor));
+  pmark := framePool.mark();
+  hitcount := mapGrid.forEachInAABB(lightX-radius, lightY-radius, radius*2, radius*2, (GridTagWall or GridTagDoor));
+  if (hitcount = 0) then exit;
+  phit := PPanel(framePool.getPtr(pmark));
+  while (hitcount > 0) do
+  begin
+    phit^.DrawShadowVolume(lightX, lightY, radius);
+    Inc(phit);
+    Dec(hitcount);
+  end;
+  framePool.release(pmark);
 end;
 
 
@@ -2771,6 +2877,7 @@ end;
 function g_Map_CollidePanel(X, Y: Integer; Width, Height: Word; PanelType: Word; b1x3: Boolean): Boolean;
 const
   SlowMask = GridTagLift or GridTagBlockMon;
+
   function checker (pan: TPanel; tag: Integer): Boolean;
   begin
     {
@@ -2805,7 +2912,12 @@ const
 
 var
   tagmask: Integer = 0;
+  pmark: PoolMark;
+  phit: PPanel;
+  hitcount: Integer;
+  pan: TPanel;
 begin
+  result := false;
   if WordBool(PanelType and (PANEL_WALL or PANEL_CLOSEDOOR or PANEL_OPENDOOR)) then tagmask := tagmask or (GridTagWall or GridTagDoor);
   if WordBool(PanelType and PANEL_WATER) then tagmask := tagmask or GridTagWater;
   if WordBool(PanelType and PANEL_ACID1) then tagmask := tagmask or GridTagAcid1;
@@ -2814,12 +2926,12 @@ begin
   if WordBool(PanelType and (PANEL_LIFTUP or PANEL_LIFTDOWN or PANEL_LIFTLEFT or PANEL_LIFTRIGHT)) then tagmask := tagmask or GridTagLift;
   if WordBool(PanelType and PANEL_BLOCKMON) then tagmask := tagmask or GridTagBlockMon;
 
-  if (tagmask = 0) then begin result := false; exit; end; // just in case
+  if (tagmask = 0) then exit; // just in case
 
   if (profMapCollision <> nil) then profMapCollision.sectionBeginAccum('*solids');
   if gdbg_map_use_accel_coldet then
   begin
-    if (Width = 1) and (Height = 1) then
+    {if (Width = 1) and (Height = 1) then
     begin
       if ((tagmask and SlowMask) <> 0) then
       begin
@@ -2832,18 +2944,50 @@ begin
         result := (mapGrid.forEachAtPoint(X, Y, nil, tagmask) <> nil);
       end;
     end
-    else
+    else}
     begin
+      pmark := framePool.mark();
       if ((tagmask and SlowMask) <> 0) then
       begin
         // slow
-        result := (mapGrid.forEachInAABB(X, Y, Width, Height, checker, tagmask) <> nil);
+        //result := (mapGrid.forEachInAABB(X, Y, Width, Height, checker, tagmask) <> nil);
+        hitcount := mapGrid.forEachInAABB(X, Y, Width, Height, tagmask);
+        //if (hitcount = 0) then exit;
+        phit := PPanel(framePool.getPtr(pmark));
+        while (hitcount > 0) do
+        begin
+          pan := phit^;
+          if ((pan.tag and GridTagLift) <> 0) then
+          begin
+            result :=
+              ((WordBool(PanelType and PANEL_LIFTUP) and (pan.LiftType = 0)) or
+               (WordBool(PanelType and PANEL_LIFTDOWN) and (pan.LiftType = 1)) or
+               (WordBool(PanelType and PANEL_LIFTLEFT) and (pan.LiftType = 2)) or
+               (WordBool(PanelType and PANEL_LIFTRIGHT) and (pan.LiftType = 3))) {and
+               g_Collide(X, Y, Width, Height, pan.X, pan.Y, pan.Width, pan.Height)};
+          end
+          else if ((pan.tag and GridTagBlockMon) <> 0) then
+          begin
+            result := ((not b1x3) or (pan.Width+pan.Height >= 64)); //and g_Collide(X, Y, Width, Height, pan.X, pan.Y, pan.Width, pan.Height);
+          end
+          else
+          begin
+            // other shit
+            result := true; // i found her!
+          end;
+          if (result) then break;
+          Inc(phit);
+          Dec(hitcount);
+        end;
       end
       else
       begin
         // fast
-        result := (mapGrid.forEachInAABB(X, Y, Width, Height, nil, tagmask) <> nil);
+        //result := (mapGrid.forEachInAABB(X, Y, Width, Height, nil, tagmask) <> nil);
+        hitcount := mapGrid.forEachInAABB(X, Y, Width, Height, tagmask, false, true); // return first hit
+        result := (hitcount > 0);
       end;
+      framePool.release(pmark);
     end;
   end
   else
@@ -2854,11 +2998,35 @@ begin
 end;
 
 
+// returns `true` if we need to stop
+function liquidChecker (pan: TPanel; var texid: DWORD; var cctype: Integer): Boolean; inline;
+begin
+  result := false;
+  //if ((tag and (GridTagWater or GridTagAcid1 or GridTagAcid2)) = 0) then exit;
+  // check priorities
+  case cctype of
+    0: if ((pan.tag and GridTagWater) = 0) then exit; // allowed: water
+    1: if ((pan.tag and (GridTagWater or GridTagAcid1)) = 0) then exit; // allowed: water, acid1
+    //2: if ((tag and (GridTagWater or GridTagAcid1 or GridTagAcid2) = 0) then exit; // allowed: water, acid1, acid2
+  end;
+  // collision?
+  //if not g_Collide(X, Y, Width, Height, pan.X, pan.Y, pan.Width, pan.Height) then exit;
+  // yeah
+  texid := pan.GetTextureID();
+  // water? water has the highest priority, so stop right here
+  if ((pan.tag and GridTagWater) <> 0) then begin cctype := 0; result := true; exit; end;
+  // acid2?
+  if ((pan.tag and GridTagAcid2) <> 0) then cctype := 2;
+  // acid1?
+  if ((pan.tag and GridTagAcid1) <> 0) then cctype := 1;
+end;
+
 function g_Map_CollideLiquid_Texture(X, Y: Integer; Width, Height: Word): DWORD;
 var
   cctype: Integer = 3; // priority: 0: water was hit, 1: acid1 was hit, 2: acid2 was hit; 3: nothing was hit
-  texid: DWORD;
+  //texid: DWORD;
 
+  (*
   // slightly different from the old code, but meh...
   function checker (pan: TPanel; tag: Integer): Boolean;
   begin
@@ -2881,12 +3049,18 @@ var
     // acid1?
     if ((tag and GridTagAcid1) <> 0) then cctype := 1;
   end;
-
+  *)
+var
+  pmark: PoolMark;
+  phit: PPanel;
+  hitcount: Integer;
+  pan: TPanel;
 begin
   if (profMapCollision <> nil) then profMapCollision.sectionBeginAccum('liquids');
   if gdbg_map_use_accel_coldet then
   begin
-    texid := LongWord(TEXTURE_NONE);
+    {texid}result := LongWord(TEXTURE_NONE);
+    {
     if (Width = 1) and (Height = 1) then
     begin
       mapGrid.forEachAtPoint(X, Y, checker, (GridTagWater or GridTagAcid1 or GridTagAcid2));
@@ -2895,7 +3069,20 @@ begin
     begin
       mapGrid.forEachInAABB(X, Y, Width, Height, checker, (GridTagWater or GridTagAcid1 or GridTagAcid2));
     end;
-    result := texid;
+    }
+    pmark := framePool.mark();
+    hitcount := mapGrid.forEachInAABB(X, Y, Width, Height, (GridTagWater or GridTagAcid1 or GridTagAcid2));
+    if (hitcount = 0) then exit;
+    phit := PPanel(framePool.getPtr(pmark));
+    while (hitcount > 0) do
+    begin
+      pan := phit^;
+      Inc(phit);
+      Dec(hitcount);
+      if (liquidChecker(pan, result, cctype)) then break;
+    end;
+    framePool.release(pmark);
+    //result := texid;
   end
   else
   begin
@@ -3281,14 +3468,16 @@ begin
   topx := x;
   topy := y;
   // started outside of the liquid?
-  if (mapGrid.forEachAtPoint(x, y, nil, MaskLiquid) = nil) then begin result := false; exit; end;
+  //if (mapGrid.forEachAtPoint(x, y, nil, MaskLiquid) = nil) then begin result := false; exit; end;
+  if (g_Map_PanelAtPoint(x, y, MaskLiquid) = nil) then begin result := false; exit; end;
   if (dx = 0) and (dy = 0) then begin result := false; exit; end; // sanity check
   result := true;
   while true do
   begin
     Inc(x, dx);
     Inc(y, dy);
-    if (mapGrid.forEachAtPoint(x, y, nil, MaskLiquid) = nil) then exit; // out of the water, just exit
+    //if (mapGrid.forEachAtPoint(x, y, nil, MaskLiquid) = nil) then exit; // out of the water, just exit
+    if (g_Map_PanelAtPoint(x, y, MaskLiquid) = nil) then exit; // out of the water, just exit
     topx := x;
     topy := y;
   end;