DEADSOFTWARE

fixed bug in grid update; one more mode for Holmes
[d2df-sdl.git] / src / game / g_gfx.pas
index fe494a8cd539128405cc5b12c4ef78a1ac65f496..c84ba47eda80a1e2c6097a134a78d5ba0929a212 100644 (file)
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  *)
 {$INCLUDE ../shared/a_modes.inc}
-{.$DEFINE HAS_COLLIDE_BITMAP}
 unit g_gfx;
 
 interface
 
 uses
-  g_textures;
+  e_log, g_textures;
 
 const
   BLOOD_NORMAL = 0;
@@ -60,10 +59,9 @@ procedure g_GFX_Update();
 procedure g_GFX_Draw();
 
 
-{$IF DEFINED(HAS_COLLIDE_BITMAP)}
 var
-  gCollideMap: Array of Array of Byte;
-{$ENDIF}
+  gpart_dbg_enabled: Boolean = true;
+  gpart_dbg_phys_enabled: Boolean = true;
 
 
 implementation
@@ -85,6 +83,8 @@ type
     State:              Byte;
     ParticleType:       Byte;
     offsetX, offsetY:   ShortInt;
+    // for bubbles
+    liquidTopY: Integer; // don't float higher than this
   end;
 
   TOnceAnim = record
@@ -103,65 +103,70 @@ const
   STATE_STICK  = 2;
 
 var
-  Particles: Array of TParticle;
-  OnceAnims: Array of TOnceAnim;
+  Particles: array of TParticle;
+  OnceAnims: array of TOnceAnim;
   MaxParticles: Integer;
   CurrentParticle: Integer;
 
 
-function isBlockedAt (x, y: Integer; w: Integer=1; h: Integer=1): Boolean; inline;
+function isBlockedAt (x, y: Integer): Boolean; inline;
 begin
-  result := g_Map_CollidePanel(x, y, w, h, (PANEL_WALL or PANEL_CLOSEDOOR or PANEL_STEP));
+  if not gpart_dbg_phys_enabled then begin result := false; exit; end;
+  result := g_Map_HasAnyPanelAtPoint(x, y, (PANEL_WALL or PANEL_CLOSEDOOR or PANEL_STEP));
 end;
 
-
 // ???
-function isWallAt (x, y: Integer; w: Integer=1; h: Integer=1): Boolean; inline;
+function isWallAt (x, y: Integer): Boolean; inline;
 begin
-  result := g_Map_CollidePanel(x, y, w, h, (PANEL_WALL or PANEL_STEP));
+  if not gpart_dbg_phys_enabled then begin result := false; exit; end;
+  result := g_Map_HasAnyPanelAtPoint(x, y, (PANEL_WALL or PANEL_STEP));
 end;
 
-
-function isLiftUpAt (x, y: Integer; w: Integer=1; h: Integer=1): Boolean; inline;
+function isLiftUpAt (x, y: Integer): Boolean; inline;
 begin
-  result := g_Map_CollidePanel(x, y, w, h, PANEL_LIFTUP);
+  if not gpart_dbg_phys_enabled then begin result := false; exit; end;
+  result := g_Map_HasAnyPanelAtPoint(x, y, PANEL_LIFTUP);
 end;
 
-function isLiftDownAt (x, y: Integer; w: Integer=1; h: Integer=1): Boolean; inline;
+function isLiftDownAt (x, y: Integer): Boolean; inline;
 begin
-  result := g_Map_CollidePanel(x, y, w, h, PANEL_LIFTDOWN);
+  if not gpart_dbg_phys_enabled then begin result := false; exit; end;
+  result := g_Map_HasAnyPanelAtPoint(x, y, PANEL_LIFTDOWN);
 end;
 
-function isLiftLeftAt (x, y: Integer; w: Integer=1; h: Integer=1): Boolean; inline;
+function isLiftLeftAt (x, y: Integer): Boolean; inline;
 begin
-  result := g_Map_CollidePanel(x, y, w, h, PANEL_LIFTLEFT);
+  if not gpart_dbg_phys_enabled then begin result := false; exit; end;
+  result := g_Map_HasAnyPanelAtPoint(x, y, PANEL_LIFTLEFT);
 end;
 
-function isLiftRightAt (x, y: Integer; w: Integer=1; h: Integer=1): Boolean; inline;
+function isLiftRightAt (x, y: Integer): Boolean; inline;
 begin
-  result := g_Map_CollidePanel(x, y, w, h, PANEL_LIFTRIGHT);
+  if not gpart_dbg_phys_enabled then begin result := false; exit; end;
+  result := g_Map_HasAnyPanelAtPoint(x, y, PANEL_LIFTRIGHT);
 end;
 
-
-function isLiquidAt (x, y: Integer; w: Integer=1; h: Integer=1): Boolean; inline;
+function isLiquidAt (x, y: Integer): Boolean; inline;
 begin
-  result := g_Map_CollidePanel(x, y, w, h, (PANEL_WATER or PANEL_ACID1 or PANEL_ACID2));
+  if not gpart_dbg_phys_enabled then begin result := false; exit; end;
+  result := g_Map_HasAnyPanelAtPoint(x, y, (PANEL_WATER or PANEL_ACID1 or PANEL_ACID2));
 end;
 
-
-function isAnythingAt (x, y: Integer; w: Integer=1; h: Integer=1): Boolean; inline;
+function isAnythingAt (x, y: Integer): Boolean; inline;
 begin
-  result := g_Map_CollidePanel(x, y, w, h, (PANEL_WALL or PANEL_CLOSEDOOR or PANEL_OPENDOOR or PANEL_WATER or PANEL_ACID1 or PANEL_ACID2 or PANEL_STEP or PANEL_LIFTUP or PANEL_LIFTDOWN or PANEL_LIFTLEFT or PANEL_LIFTRIGHT));
+  if not gpart_dbg_phys_enabled then begin result := false; exit; end;
+  result := g_Map_HasAnyPanelAtPoint(x, y, (PANEL_WALL or PANEL_CLOSEDOOR or PANEL_OPENDOOR or PANEL_WATER or PANEL_ACID1 or PANEL_ACID2 or PANEL_STEP or PANEL_LIFTUP or PANEL_LIFTDOWN or PANEL_LIFTLEFT or PANEL_LIFTRIGHT));
 end;
 
 
 procedure g_Mark(x, y, Width, Height: Integer; t: Byte; st: Boolean);
-{$IF DEFINED(HAS_COLLIDE_BITMAP)}
+{$IF not DEFINED(HAS_COLLIDE_BITMAP)}
+begin
+end;
+{$ELSE}
 var
   yy, y2, xx, x2: Integer;
-{$ENDIF}
 begin
-{$IF DEFINED(HAS_COLLIDE_BITMAP)}
   if x < 0 then
   begin
     Width := Width + x;
@@ -206,16 +211,15 @@ begin
         for xx := x to x2 do
           gCollideMap[yy][xx] := gCollideMap[yy][xx] and t;
     end;
-{$ENDIF}
 end;
+{$ENDIF}
+
 
-procedure CreateCollideMap();
 {$IF DEFINED(HAS_COLLIDE_BITMAP)}
+procedure CreateCollideMap();
 var
   a: Integer;
-{$ENDIF}
 begin
-{$IF DEFINED(HAS_COLLIDE_BITMAP)}
   g_Game_SetLoadingText(_lc[I_LOAD_COLLIDE_MAP]+' 1/6', 0, False);
   SetLength(gCollideMap, gMapInfo.Height+1);
   for a := 0 to High(gCollideMap) do
@@ -285,20 +289,23 @@ begin
           g_Mark(X, Y, Width, Height, MARK_WALL, True);
     end;
   end;
-{$ENDIF}
 end;
+{$ENDIF}
+
 
 procedure g_GFX_Init();
 begin
-  CreateCollideMap();
+  //CreateCollideMap();
 end;
 
+
 procedure g_GFX_Free();
 var
   a: Integer;
 begin
   Particles := nil;
   SetLength(Particles, MaxParticles);
+  for a := 0 to High(Particles) do Particles[a].State := STATE_FREE;
   CurrentParticle := 0;
 
   if OnceAnims <> nil then
@@ -308,37 +315,14 @@ begin
 
     OnceAnims := nil;
   end;
-
-  {$IF DEFINED(HAS_COLLIDE_BITMAP)}
-  gCollideMap := nil;
-  {$ENDIF}
 end;
 
 
-procedure CorrectOffsets(id: Integer);
-{$IF not DEFINED(HAS_COLLIDE_BITMAP)}
+{
+procedure CorrectOffsets(id: Integer); inline;
 var
   part: PParticle;
-{$ENDIF}
 begin
-{$IF DEFINED(HAS_COLLIDE_BITMAP)}
-  with Particles[id] do
-  begin
-    if (X >= 0) and (Y > 0) and
-    (Y < Length(gCollideMap)) and (X < Length(gCollideMap[0])) and
-    (ByteBool(gCollideMap[Y-1, X] and MARK_BLOCKED)) then
-      offsetY := 1 // Ñòåíà ñâåðõó
-    else
-      offsetY := 0;
-
-    if (X > 0) and (Y >= 0) and
-    (Y < Length(gCollideMap)) and (X < Length(gCollideMap[0])) and
-    (ByteBool(gCollideMap[Y, X-1] and MARK_BLOCKED)) then
-      offsetX := 1 // Ñòåíà ñëåâà
-    else
-      offsetX := 0;
-  end;
-{$ELSE}
   part := @Particles[id];
   part.offsetX := 0;
   part.offsetY := 0;
@@ -346,8 +330,8 @@ begin
   if isBlockedAt(part.X, part.Y-1) then part.offsetY := 1;
   // check for left wall
   if isBlockedAt(part.X-1, part.Y) then part.offsetX := 1;
-{$ENDIF}
 end;
+}
 
 
 procedure g_GFX_SparkVel (fX, fY: Integer; Count: Word; VX, VY: Integer; DevX, DevY: Byte);
@@ -395,7 +379,7 @@ begin
       LiveTime := 30+Random(60);
       ParticleType := PARTICLE_SPARK;
 
-      CorrectOffsets(CurrentParticle);
+      {CorrectOffsets(CurrentParticle);}
     end;
 
     if CurrentParticle+2 > MaxParticles then
@@ -492,7 +476,7 @@ begin
       LiveTime := 120+Random(40);
       ParticleType := PARTICLE_BLOOD;
 
-      CorrectOffsets(CurrentParticle);
+      {CorrectOffsets(CurrentParticle);}
     end;
 
     if CurrentParticle >= MaxParticles-1 then
@@ -554,7 +538,7 @@ begin
       LiveTime := 30+Random(60);
       ParticleType := PARTICLE_SPARK;
 
-      CorrectOffsets(CurrentParticle);
+      {CorrectOffsets(CurrentParticle);}
     end;
 
     if CurrentParticle+2 > MaxParticles then
@@ -636,7 +620,7 @@ begin
       LiveTime := 60+Random(60);
       ParticleType := PARTICLE_WATER;
 
-      CorrectOffsets(CurrentParticle);
+      {CorrectOffsets(CurrentParticle);}
     end;
 
     if CurrentParticle+2 > MaxParticles then
@@ -721,7 +705,7 @@ begin
       LiveTime := 60+Random(60);
       ParticleType := PARTICLE_WATER;
 
-      CorrectOffsets(CurrentParticle);
+      {CorrectOffsets(CurrentParticle);}
     end;
 
     if CurrentParticle+2 > MaxParticles then
@@ -731,12 +715,13 @@ begin
   end;
 end;
 
+
 procedure g_GFX_Bubbles(fX, fY: Integer; Count: Word; DevX, DevY: Byte);
 var
   a: Integer;
   DevX1, DevX2,
   DevY1, DevY2: Byte;
-  l: Integer;
+  l, liquidx: Integer;
 begin
   l := Length(Particles);
   if l = 0 then
@@ -760,8 +745,15 @@ begin
          (Y >= gMapInfo.Height) or (Y <= 0) then
         Continue;
 
+      (*
+      // don't spawn bubbles outside of the liquid
       if not isLiquidAt(X, Y) {ByteBool(gCollideMap[Y, X] and MARK_LIQUID)} then
         Continue;
+      *)
+
+      // trace liquid, so we'll know where it ends; do it in 8px steps for speed
+      // tracer will return `false` if we started outside of the liquid
+      if not g_Map_TraceLiquid(X, Y, 0, -8, liquidx, liquidTopY) then continue;
 
       VelX := 0;
       VelY := -1-Random;
@@ -778,7 +770,7 @@ begin
       LiveTime := 65535;
       ParticleType := PARTICLE_BUBBLES;
 
-      CorrectOffsets(CurrentParticle);
+      {CorrectOffsets(CurrentParticle);}
     end;
 
     if CurrentParticle+2 > MaxParticles then
@@ -789,13 +781,16 @@ begin
 end;
 
 procedure g_GFX_SetMax(Count: Integer);
+var
+  a: Integer;
 begin
-  if Count > 50000 then
-    Count := 50000;
+  if Count > 50000 then Count := 50000;
+  if (Count < 1) then Count := 1;
 
   SetLength(Particles, Count);
+  for a := 0 to High(Particles) do Particles[a].State := STATE_FREE;
   MaxParticles := Count;
-  if CurrentParticle >= Count then
+  //if CurrentParticle >= Count then
     CurrentParticle := 0;
 end;
 
@@ -854,6 +849,7 @@ var
   s: ShortInt;
   //c: Byte;
 begin
+  if not gpart_dbg_enabled then exit;
   if Particles <> nil then
   begin
     w := gMapInfo.Width;
@@ -862,15 +858,15 @@ begin
     len := High(Particles);
 
     for a := 0 to len do
-      if Particles[a].State <> 0 then
+    begin
+      if Particles[a].State <> STATE_FREE then
+      begin
         with Particles[a] do
         begin
-          if Time = LiveTime then
-            State := STATE_FREE;
-          if (X+1 >= w) or (Y+1 >= h) or (X <= 0) or (Y <= 0) then
-            State := STATE_FREE;
-          if State = STATE_FREE then
-            Continue;
+          if Time = LiveTime then State := STATE_FREE;
+          if (X+1 >= w) or (Y+1 >= h) or (X <= 0) or (Y <= 0) then State := STATE_FREE;
+          if State = STATE_FREE then Continue;
+          //e_WriteLog(Format('particle #%d: %d', [State, ParticleType]), MSG_NOTIFY);
 
           case ParticleType of
             PARTICLE_BLOOD:
@@ -1322,8 +1318,10 @@ begin
             end;
           end; // case
 
-          CorrectOffsets(a);
-        end;
+          {CorrectOffsets(a);}
+        end; // with
+      end; // if
+    end; // for
   end; // Particles <> nil
 
   if OnceAnims <> nil then