DEADSOFTWARE

holmes: new outliner; it should work in all scales now
[d2df-sdl.git] / src / game / g_holmes.pas
index 6d52559b7e7c281d5743393e187c574be123dae2..e64c20508a3411567a8571300da18f0605b2f677 100644 (file)
@@ -19,6 +19,7 @@ unit g_holmes;
 interface
 
 uses
+  mempool, geom,
   e_log, e_input,
   g_textures, g_basic, e_graphics, g_phys, g_grid, g_player, g_monsters,
   g_window, g_map, g_triggers, g_items, g_game, g_panel, g_console, g_gfx,
@@ -103,7 +104,7 @@ var
 implementation
 
 uses
-  {rttiobj,} typinfo,
+  {rttiobj,} typinfo, e_texture,
   SysUtils, Classes, GL, SDL2,
   MAPDEF, g_main, g_options,
   utils, hashtable, xparser;
@@ -129,6 +130,7 @@ var
 // ////////////////////////////////////////////////////////////////////////// //
 {$INCLUDE g_holmes.inc}
 {$INCLUDE g_holmes_ui.inc}
+{$INCLUDE g_holmes_ol.inc} // outliner
 
 
 // ////////////////////////////////////////////////////////////////////////// //
@@ -625,7 +627,7 @@ end;
 // ////////////////////////////////////////////////////////////////////////// //
 procedure g_Holmes_VidModeChanged ();
 begin
-  e_WriteLog(Format('Holmes: videomode changed: %dx%d', [gScreenWidth, gScreenHeight]), MSG_NOTIFY);
+  e_WriteLog(Format('Holmes: videomode changed: %dx%d', [gScreenWidth, gScreenHeight]), TMsgType.Notify);
   // texture space is possibly lost here, idc
   curtexid := 0;
   font6texid := 0;
@@ -696,6 +698,7 @@ begin
 end;
 
 
+{$IFDEF HOLMES_OLD_OUTLINES}
 var
   edgeBmp: array of Byte = nil;
 
@@ -898,6 +901,155 @@ begin
   if g_ol_rlayer_fore then doWallsOld(gRenderForegrounds, PANEL_FORE, 210, 210, 210);
 end;
 
+{$ELSE}
+var
+  oliner: TOutliner = nil;
+
+procedure drawOutlines ();
+var
+  r, g, b: Integer;
+
+  procedure clearOliner ();
+  begin
+    //if (oliner <> nil) and ((oliner.height <> vph+2) or (oliner.width <> vpw+2)) then begin oliner.Free(); oliner := nil; end;
+    if (oliner = nil) then oliner := TOutliner.Create(vpw+2, vph+2) else oliner.setup(vpw+2, vph+2);
+  end;
+
+  procedure drawOutline (ol: TOutliner; sx, sy: Integer);
+    procedure xline (x0, x1, y: Integer);
+    var
+      x: Integer;
+    begin
+      if (g_dbg_scale < 1.0) then
+      begin
+        glBegin(GL_POINTS);
+          for x := x0 to x1 do glVertex2f(sx+x+0.375, sy+y+0.375);
+        glEnd();
+      end
+      else
+      begin
+        glBegin(GL_QUADS);
+          glVertex2f(sx+x0+0, sy+y+0);
+          glVertex2f(sx+x1+1, sy+y+0);
+          glVertex2f(sx+x1+1, sy+y+1);
+          glVertex2f(sx+x0+0, sy+y+1);
+        glEnd();
+      end;
+    end;
+  var
+    y: Integer;
+    sp: TOutliner.TSpanX;
+  begin
+    if (ol = nil) then exit;
+    glPointSize(1);
+    glDisable(GL_POINT_SMOOTH);
+    for y := 0 to ol.height-1 do
+    begin
+      for sp in ol.eachSpanAtY(y) do
+      begin
+        if (g_dbg_scale <= 1.0) then
+        begin
+          glBegin(GL_POINTS);
+            glVertex2f(sx+sp.x0+0.375, sy+y+0.375);
+            glVertex2f(sx+sp.x1+0.375, sy+y+0.375);
+          glEnd();
+        end
+        else
+        begin
+          glBegin(GL_QUADS);
+            glVertex2f(sx+sp.x0+0, sy+y+0);
+            glVertex2f(sx+sp.x0+1, sy+y+0);
+            glVertex2f(sx+sp.x0+1, sy+y+1);
+            glVertex2f(sx+sp.x0+0, sy+y+1);
+
+            glVertex2f(sx+sp.x1+0, sy+y+0);
+            glVertex2f(sx+sp.x1+1, sy+y+0);
+            glVertex2f(sx+sp.x1+1, sy+y+1);
+            glVertex2f(sx+sp.x1+0, sy+y+1);
+          glEnd();
+        end;
+      end;
+      for sp in ol.eachSpanEdgeAtY(y, -1) do
+      begin
+        xline(sp.x0, sp.x1, y);
+        {
+        glBegin(GL_QUADS);
+          glVertex2f(sx+sp.x0+0, sy+y+0);
+          glVertex2f(sx+sp.x1+1, sy+y+0);
+          glVertex2f(sx+sp.x1+1, sy+y+1);
+          glVertex2f(sx+sp.x0+0, sy+y+1);
+        glEnd();
+        }
+      end;
+      for sp in ol.eachSpanEdgeAtY(y, +1) do
+      begin
+        xline(sp.x0, sp.x1, y);
+        {
+        glBegin(GL_QUADS);
+          glVertex2f(sx+sp.x0+0, sy+y+0);
+          glVertex2f(sx+sp.x1+1, sy+y+0);
+          glVertex2f(sx+sp.x1+1, sy+y+1);
+          glVertex2f(sx+sp.x0+0, sy+y+1);
+        glEnd();
+        }
+      end;
+    end;
+  end;
+
+  procedure doWallsOld (parr: array of TPanel; ptype: Word; ar, ag, ab: Integer);
+  var
+    f: Integer;
+    pan: TPanel;
+  begin
+    r := ar;
+    g := ag;
+    b := ab;
+    if g_ol_nice then clearOliner();
+    for f := 0 to High(parr) do
+    begin
+      pan := parr[f];
+      if (pan = nil) or not pan.Enabled or (pan.Width < 1) or (pan.Height < 1) then continue;
+      if ((pan.PanelType and ptype) = 0) then continue;
+      if (pan.X > vpx+vpw+41) or (pan.Y > vpy+vph+41) then continue;
+      if (pan.X+pan.Width < vpx-41) then continue;
+      if (pan.Y+pan.Height < vpy-41) then continue;
+      if g_ol_nice then
+      begin
+        oliner.addRect(pan.X-(vpx+1), pan.Y-(vpy+1), pan.Width, pan.Height);
+      end;
+      if g_ol_fill_walls then
+      begin
+        fillRect(pan.X, pan.Y, pan.Width, pan.Height, r, g, b);
+      end
+      else if not g_ol_nice then
+      begin
+        drawRect(pan.X, pan.Y, pan.Width, pan.Height, r, g, b);
+      end;
+    end;
+    if g_ol_nice then
+    begin
+      glColor4f(r/255.0, g/255.0, b/255.0, 1.0);
+      drawOutline(oliner, vpx+1, vpy+1);
+    end;
+  end;
+
+begin
+  if (vpw < 2) or (vph < 2) then exit;
+  glScissor(0, gScreenHeight-gPlayerScreenSize.Y, gPlayerScreenSize.X, gPlayerScreenSize.Y);
+  glEnable(GL_SCISSOR_TEST);
+  if g_ol_rlayer_back then doWallsOld(gRenderBackgrounds, PANEL_BACK, 255, 127, 0);
+  if g_ol_rlayer_step then doWallsOld(gSteps, PANEL_STEP, 192, 192, 192);
+  if g_ol_rlayer_wall then doWallsOld(gWalls, PANEL_WALL, 255, 255, 255);
+  if g_ol_rlayer_door then doWallsOld(gWalls, PANEL_OPENDOOR or PANEL_CLOSEDOOR, 0, 255, 0);
+  if g_ol_rlayer_acid1 then doWallsOld(gAcid1, PANEL_ACID1, 255, 0, 0);
+  if g_ol_rlayer_acid2 then doWallsOld(gAcid2, PANEL_ACID2, 198, 198, 0);
+  if g_ol_rlayer_water then doWallsOld(gWater, PANEL_WATER, 0, 255, 255);
+  if g_ol_rlayer_fore then doWallsOld(gRenderForegrounds, PANEL_FORE, 210, 210, 210);
+  glScissor(0, 0, gScreenWidth, gScreenHeight);
+  glDisable(GL_SCISSOR_TEST);
+end;
+{$ENDIF}
+
 
 procedure plrDebugDraw ();
   procedure drawTileGrid ();
@@ -967,6 +1119,8 @@ procedure plrDebugDraw ();
   procedure hilightCell1 (cx, cy: Integer);
   begin
     //e_WriteLog(Format('h1: (%d,%d)', [cx, cy]), MSG_NOTIFY);
+    cx := cx and (not (monsGrid.tileSize-1));
+    cy := cy and (not (monsGrid.tileSize-1));
     fillRect(cx, cy, monsGrid.tileSize, monsGrid.tileSize, 255, 255, 0, 92);
   end;
 
@@ -1037,7 +1191,7 @@ procedure plrDebugDraw ();
       mon.getMapBox(mx, my, mw, mh);
       drawLine(mx+mw div 2, my+mh div 2, emx+emw div 2, emy+emh div 2, 255, 0, 0, 255);
       {$IF DEFINED(D2F_DEBUG)}
-      //mapGrid.dbgRayTraceTileHitCB := hilightCell1;
+      mapGrid.dbgRayTraceTileHitCB := hilightCell1;
       {$ENDIF}
       if (g_Map_traceToNearestWall(mx+mw div 2, my+mh div 2, emx+emw div 2, emy+emh div 2, @ex, @ey) <> nil) then
       //if (mapGrid.traceRay(ex, ey, mx+mw div 2, my+mh div 2, emx+emw div 2, emy+emh div 2, hilightWallTrc, (GridTagWall or GridTagDoor)) <> nil) then
@@ -1045,7 +1199,7 @@ procedure plrDebugDraw ();
         drawLine(mx+mw div 2, my+mh div 2, ex, ey, 0, 255, 0, 255);
       end;
       {$IF DEFINED(D2F_DEBUG)}
-      //mapGrid.dbgRayTraceTileHitCB := nil;
+      mapGrid.dbgRayTraceTileHitCB := nil;
       {$ENDIF}
     end;
 
@@ -1205,6 +1359,8 @@ procedure plrDebugDraw ();
 var
   mon: TMonster;
   mx, my, mw, mh: Integer;
+  //pan: TPanel;
+  //ex, ey: Integer;
 begin
   if (gPlayer1 = nil) then exit;
 
@@ -1241,6 +1397,22 @@ begin
 
   //drawGibsBoxes();
 
+
+  //pan := g_Map_traceToNearest(16, 608, 16, 8, (GridTagObstacle or GridTagLiquid), @ex, @ey);
+  (*
+  {$IF DEFINED(D2F_DEBUG)}
+  mapGrid.dbgRayTraceTileHitCB := hilightCell1;
+  {$ENDIF}
+  pan := mapGrid.traceRay(ex, ey, 16, 608, 16, 8, nil, (GridTagObstacle or GridTagLiquid));
+  if (pan <> nil) then writeln('end=(', ex, ',', ey, ')');
+  {$IF DEFINED(D2F_DEBUG)}
+  mapGrid.dbgRayTraceTileHitCB := nil;
+  {$ENDIF}
+
+  pan := g_Map_PanelAtPoint(16, 608, (GridTagObstacle or GridTagLiquid));
+  if (pan <> nil) then writeln('hit!');
+  *)
+
   glPopMatrix();
 
   glDisable(GL_SCISSOR_TEST);
@@ -1254,6 +1426,7 @@ function g_Holmes_MouseEvent (var ev: THMouseEvent): Boolean;
 var
   he: THMouseEvent;
 begin
+  if g_Game_IsNet then begin result := false; exit; end;
   holmesInitCommands();
   holmesInitBinds();
   result := true;
@@ -1283,6 +1456,7 @@ var
   end;
 
 begin
+  if g_Game_IsNet then begin result := false; exit; end;
   holmesInitCommands();
   holmesInitBinds();
   result := false;
@@ -1333,6 +1507,7 @@ end;
 // ////////////////////////////////////////////////////////////////////////// //
 procedure g_Holmes_Draw ();
 begin
+  if g_Game_IsNet then exit;
   {$IF not DEFINED(HEADLESS)}
   holmesInitCommands();
   holmesInitBinds();
@@ -1343,10 +1518,7 @@ begin
   glDisable(GL_SCISSOR_TEST);
   glDisable(GL_TEXTURE_2D);
 
-  if gGameOn then
-  begin
-    plrDebugDraw();
-  end;
+  if gGameOn then plrDebugDraw();
   {$ENDIF}
 
   laserSet := false;
@@ -1355,6 +1527,7 @@ end;
 
 procedure g_Holmes_DrawUI ();
 begin
+  if g_Game_IsNet then exit;
   {$IF not DEFINED(HEADLESS)}
   glPushMatrix();
   glScalef(g_holmes_ui_scale, g_holmes_ui_scale, 1.0);
@@ -1417,11 +1590,13 @@ end;
 
 procedure dbgToggleTraceBox (arg: Integer=-1); begin if (arg < 0) then showTraceBox := not showTraceBox else showTraceBox := (arg > 0); end;
 
+procedure dbgToggleHolmesPause (arg: Integer=-1); begin if (arg < 0) then g_Game_HolmesPause(not gPauseHolmes) else g_Game_HolmesPause(arg > 0); end;
+
 procedure cbAtcurSelectMonster ();
   function monsAtDump (mon: TMonster; tag: Integer): Boolean;
   begin
     result := true; // stop
-    e_WriteLog(Format('monster #%d (UID:%u) (proxyid:%d)', [mon.arrIdx, mon.UID, mon.proxyId]), MSG_NOTIFY);
+    e_WriteLog(Format('monster #%d (UID:%u) (proxyid:%d)', [mon.arrIdx, mon.UID, mon.proxyId]), TMsgType.Notify);
     monMarkedUID := mon.UID;
     dumpPublishedProperties(mon);
   end;
@@ -1451,12 +1626,12 @@ procedure cbAtcurDumpMonsters ();
   function monsAtDump (mon: TMonster; tag: Integer): Boolean;
   begin
     result := false; // don't stop
-    e_WriteLog(Format('monster #%d (UID:%u) (proxyid:%d)', [mon.arrIdx, mon.UID, mon.proxyId]), MSG_NOTIFY);
+    e_WriteLog(Format('monster #%d (UID:%u) (proxyid:%d)', [mon.arrIdx, mon.UID, mon.proxyId]), TMsgType.Notify);
   end;
 begin
-  e_WriteLog('===========================', MSG_NOTIFY);
+  e_WriteLog('===========================', TMsgType.Notify);
   monsGrid.forEachAtPoint(pmsCurMapX, pmsCurMapY, monsAtDump);
-  e_WriteLog('---------------------------', MSG_NOTIFY);
+  e_WriteLog('---------------------------', TMsgType.Notify);
 end;
 
 procedure cbAtcurDumpWalls ();
@@ -1473,9 +1648,9 @@ var
   trig: PTrigger;
 begin
   platMarkedGUID := -1;
-  e_WriteLog('=== TOGGLE WALL ===', MSG_NOTIFY);
+  e_WriteLog('=== TOGGLE WALL ===', TMsgType.Notify);
   mapGrid.forEachAtPoint(pmsCurMapX, pmsCurMapY, wallToggle, (GridTagWall or GridTagDoor));
-  e_WriteLog('--- toggle wall ---', MSG_NOTIFY);
+  e_WriteLog('--- toggle wall ---', TMsgType.Notify);
   if showTriggers then
   begin
     for f := 0 to High(gTriggers) do
@@ -1537,6 +1712,8 @@ begin
   cmdAdd('atcur_disable_walls', cbAtcurToggleWalls, 'disable walls', 'wall control');
 
   cmdAdd('dbg_tracebox', dbgToggleTraceBox, 'test traceBox()', 'player control');
+
+  cmdAdd('hlm_pause', dbgToggleHolmesPause, '"Holmes" pause mode', 'game control');
 end;
 
 
@@ -1575,6 +1752,8 @@ begin
 
     keybindAdd('C-1', 'mon_spawn zombie');
 
+    keybindAdd('C-S-P', 'hlm_pause');
+
     // mouse
     msbindAdd('LMB', 'atcur_select_monster');
     msbindAdd('M-LMB', 'atcur_dump_monsters');