DEADSOFTWARE

more particle control options
[d2df-sdl.git] / src / game / g_gfx.pas
index f6558892a8263b9a338cbded80607b1cee17ed2a..4be9437ab278b002c609235a6865c85c3fadab02 100644 (file)
@@ -1,9 +1,25 @@
+(* 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
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *)
+{$INCLUDE ../shared/a_modes.inc}
 unit g_gfx;
 
 interface
 
 uses
-  g_textures;
+  e_log, g_textures;
 
 const
   BLOOD_NORMAL = 0;
@@ -42,8 +58,11 @@ procedure g_Mark(x, y, Width, Height: Integer; t: Byte; st: Boolean);
 procedure g_GFX_Update();
 procedure g_GFX_Draw();
 
+
 var
-  gCollideMap: Array of Array of Byte;
+  gpart_dbg_enabled: Boolean = true;
+  gpart_dbg_phys_enabled: Boolean = true;
+
 
 implementation
 
@@ -53,6 +72,7 @@ uses
   g_game, g_language, g_net;
 
 type
+  PParticle = ^TParticle;
   TParticle = record
     X, Y:               Integer;
     VelX, VelY:         Single;
@@ -81,12 +101,67 @@ 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): Boolean; inline;
+begin
+  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): Boolean; inline;
+begin
+  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): Boolean; inline;
+begin
+  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): Boolean; inline;
+begin
+  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): Boolean; inline;
+begin
+  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): Boolean; inline;
+begin
+  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): Boolean; inline;
+begin
+  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): Boolean; inline;
+begin
+  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 not DEFINED(HAS_COLLIDE_BITMAP)}
+begin
+end;
+{$ELSE}
 var
   yy, y2, xx, x2: Integer;
 begin
@@ -135,7 +210,10 @@ begin
           gCollideMap[yy][xx] := gCollideMap[yy][xx] and t;
     end;
 end;
+{$ENDIF}
+
 
+{$IF DEFINED(HAS_COLLIDE_BITMAP)}
 procedure CreateCollideMap();
 var
   a: Integer;
@@ -210,18 +288,22 @@ begin
     end;
   end;
 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
@@ -231,31 +313,24 @@ begin
 
     OnceAnims := nil;
   end;
-
-  gCollideMap := nil;
 end;
 
+
 procedure CorrectOffsets(id: Integer);
+var
+  part: PParticle;
 begin
-  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;
+  part := @Particles[id];
+  part.offsetX := 0;
+  part.offsetY := 0;
+  // check for upper wall
+  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;
 end;
 
-procedure g_GFX_SparkVel(fX, fY: Integer; Count: Word; VX, VY: Integer; DevX, DevY: Byte);
+
+procedure g_GFX_SparkVel (fX, fY: Integer; Count: Word; VX, VY: Integer; DevX, DevY: Byte);
 var
   a: Integer;
   DevX1, DevX2,
@@ -263,10 +338,8 @@ var
   l: Integer;
 begin
   l := Length(Particles);
-  if l = 0 then
-    Exit;
-  if Count > l then
-    Count := l;
+  if l = 0 then exit;
+  if Count > l then Count := l;
 
   DevX1 := DevX div 2;
   DevX2 := DevX + 1;
@@ -312,6 +385,7 @@ begin
   end;
 end;
 
+
 procedure g_GFX_Blood(fX, fY: Integer; Count: Word; vx, vy: Integer;
   DevX, DevY: Word; CR, CG, CB: Byte; Kind: Byte = BLOOD_NORMAL);
 var
@@ -345,10 +419,13 @@ begin
       X := fX - DevX1 + Random(DevX2);
       Y := fY - DevY1 + Random(DevY2);
 
+      {
       if (X < 0) or (X > gMapInfo.Width-1) or
          (Y < 0) or (Y > gMapInfo.Height-1) or
          ByteBool(gCollideMap[Y, X] and MARK_WALL) then
         Continue;
+      }
+      if isWallAt(X, Y) then continue;
 
       VelX := vx + (Random-Random)*3;
       VelY := vy + (Random-Random)*3;
@@ -405,6 +482,7 @@ begin
   end;
 end;
 
+
 procedure g_GFX_Spark(fX, fY: Integer; Count: Word; Angle: SmallInt; DevX, DevY: Byte);
 var
   a: Integer;
@@ -662,7 +740,7 @@ begin
          (Y >= gMapInfo.Height) or (Y <= 0) then
         Continue;
 
-      if not ByteBool(gCollideMap[Y, X] and MARK_LIQUID) then
+      if not isLiquidAt(X, Y) {ByteBool(gCollideMap[Y, X] and MARK_LIQUID)} then
         Continue;
 
       VelX := 0;
@@ -691,13 +769,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;
 
@@ -754,8 +835,9 @@ var
   dX, dY: SmallInt;
   b, len: Integer;
   s: ShortInt;
-  c: Byte;
+  //c: Byte;
 begin
+  if not gpart_dbg_enabled then exit;
   if Particles <> nil then
   begin
     w := gMapInfo.Width;
@@ -764,15 +846,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:
@@ -780,10 +862,18 @@ begin
               if gAdvBlood then
                 begin
                   if (State = STATE_STICK) then
+                    {
                     if (not ByteBool(gCollideMap[Y-1, X] and MARK_BLOCKED)) and
                        (not ByteBool(gCollideMap[Y+1, X] and MARK_BLOCKED)) and
                        (not ByteBool(gCollideMap[Y, X-1] and MARK_BLOCKED)) and
-                       (not ByteBool(gCollideMap[Y, X+1] and MARK_BLOCKED)) then
+                       (not ByteBool(gCollideMap[Y, X+1] and MARK_BLOCKED))
+                    then
+                    }
+                    if (not isBlockedAt(X, Y-1)) and
+                       (not isBlockedAt(X, Y+1)) and
+                       (not isBlockedAt(X-1, Y)) and
+                       (not isBlockedAt(X+1, Y))
+                    then
                       begin // Îòëèïëà - êàïàåò
                         VelY := 0.5;
                         AccelY := 0.15;
@@ -797,9 +887,9 @@ begin
                         Continue;
                       end;
 
-                  if not ByteBool(gCollideMap[Y, X] and MARK_BLOCKED) then
+                  if not isBlockedAt(X, Y) {ByteBool(gCollideMap[Y, X] and MARK_BLOCKED)} then
                   begin
-                    if ByteBool(gCollideMap[Y, X] and MARK_LIFTUP) then
+                    if isLiftUpAt(X, Y) {ByteBool(gCollideMap[Y, X] and MARK_LIFTUP)} then
                     begin // Ëèôò ââåðõ
                       if VelY > -4-Random(3) then
                         VelY := VelY - 0.8;
@@ -808,13 +898,13 @@ begin
                       VelX := VelX + (Random-Random)*0.2;
                       AccelY := 0.15;
                     end;
-                    if ByteBool(gCollideMap[Y, X] and MARK_LIFTLEFT) then
+                    if isLiftLeftAt(X, Y) {ByteBool(gCollideMap[Y, X] and MARK_LIFTLEFT)} then
                     begin // Ïîòîê âëåâî
                       if VelX > -8-Random(3) then
                         VelX := VelX - 0.8;
                       AccelY := 0.15;
                     end;
-                    if ByteBool(gCollideMap[Y, X] and MARK_LIFTRIGHT) then
+                    if isLiftRightAt(X, Y) {ByteBool(gCollideMap[Y, X] and MARK_LIFTRIGHT)} then
                     begin // Ïîòîê âïðàâî
                       if VelX < 8+Random(3) then
                         VelX := VelX + 0.8;
@@ -827,9 +917,9 @@ begin
 
                   if (Abs(VelX) < 0.1) and (Abs(VelY) < 0.1) then
                     if (State <> STATE_STICK) and
-                       (not ByteBool(gCollideMap[Y-1, X] and MARK_BLOCKED)) and
-                       (not ByteBool(gCollideMap[Y, X] and MARK_BLOCKED)) and
-                       (not ByteBool(gCollideMap[Y+1, X] and MARK_BLOCKED)) then
+                       (not isBlockedAt(X, Y-1) {ByteBool(gCollideMap[Y-1, X] and MARK_BLOCKED)}) and
+                       (not isBlockedAt(X, Y) {ByteBool(gCollideMap[Y, X] and MARK_BLOCKED)}) and
+                       (not isBlockedAt(X, Y+1) {ByteBool(gCollideMap[Y+1, X] and MARK_BLOCKED)}) then
                     begin // Âèñèò â âîçäóõå - êàïàåò
                       VelY := 0.8;
                       AccelY := 0.5;
@@ -853,9 +943,9 @@ begin
                         Break;
                       end;
 
-                      c := gCollideMap[Y, X+s];
+                      //c := gCollideMap[Y, X+s];
 
-                      if ByteBool(c and MARK_BLOCKED) then
+                      if isBlockedAt(X+s, Y) {ByteBool(c and MARK_BLOCKED)} then
                       begin // Ñòåíà/äâåðü
                         VelX := 0;
                         VelY := 0;
@@ -886,9 +976,9 @@ begin
                         Break;
                       end;
 
-                      c := gCollideMap[Y+s, X];
+                      //c := gCollideMap[Y+s, X];
 
-                      if ByteBool(c and MARK_BLOCKED) then
+                      if isBlockedAt(X, Y+s) {ByteBool(c and MARK_BLOCKED)} then
                       begin // Ñòåíà/äâåðü
                         VelX := 0;
                         VelY := 0;
@@ -912,7 +1002,7 @@ begin
 
                   if (X+dX >= w) or (Y+dY >= h) or
                      (X+dX <= 0) or (Y+dY <= 0) or
-                     ByteBool(gCollideMap[Y+dY, X+dX] and MARK_BLOCKED) then
+                     isBlockedAt(X+dX, Y+dY) {ByteBool(gCollideMap[Y+dY, X+dX] and MARK_BLOCKED)} then
                     begin // Ñòåíà/äâåðü/ãðàíèöà
                       State := STATE_FREE;
                       VelX := 0;
@@ -929,7 +1019,7 @@ begin
               VelY := VelY + AccelY;
 
             // Êðîâü ðàñòâîðÿåòñÿ â æèäêîñòè:
-              if ByteBool(gCollideMap[Y, X] and MARK_LIQUID) then
+              if isLiquidAt(X, Y) {ByteBool(gCollideMap[Y, X] and MARK_LIQUID)} then
               begin
                 Inc(Time);
 
@@ -943,9 +1033,9 @@ begin
               dY := Round(VelY);
 
               if (Abs(VelX) < 0.1) and (Abs(VelY) < 0.1) and
-                 (not ByteBool(gCollideMap[Y-1, X] and MARK_BLOCKED)) and
-                 (not ByteBool(gCollideMap[Y, X] and MARK_BLOCKED)) and
-                 (not ByteBool(gCollideMap[Y+1, X] and MARK_BLOCKED)) then
+                 (not isBlockedAt(X, Y-1) {ByteBool(gCollideMap[Y-1, X] and MARK_BLOCKED)}) and
+                 (not isBlockedAt(X, Y) {ByteBool(gCollideMap[Y, X] and MARK_BLOCKED)}) and
+                 (not isBlockedAt(X, Y+1) {ByteBool(gCollideMap[Y+1, X] and MARK_BLOCKED)}) then
               begin // Âèñèò â âîçäóõå
                 VelY := 0.8;
                 AccelY := 0.5;
@@ -968,16 +1058,16 @@ begin
                     Break;
                   end;
 
-                  c := gCollideMap[Y, X+s];
+                  //c := gCollideMap[Y, X+s];
 
-                  if ByteBool(c and MARK_BLOCKED) then
+                  if isBlockedAt(X+s, Y) {ByteBool(c and MARK_BLOCKED)} then
                     begin // Ñòåíà/äâåðü - ïàäàåò âåðòèêàëüíî
                       VelX := 0;
                       AccelX := 0;
                       Break;
                     end
                   else // Ïóñòî:
-                    if c = MARK_FREE then
+                    if not isAnythingAt(X+s, Y) {c = MARK_FREE} then
                       X := X + s
                     else // Îñòàëüíîå:
                       begin
@@ -1004,9 +1094,9 @@ begin
                     Break;
                   end;
 
-                  c := gCollideMap[Y+s, X];
+                  //c := gCollideMap[Y+s, X];
 
-                  if ByteBool(c and MARK_BLOCKED) then
+                  if isBlockedAt(X, Y+s) {ByteBool(c and MARK_BLOCKED)} then
                     begin // Ñòåíà/äâåðü - ïàäàåò âåðòèêàëüíî
                       if s < 0 then
                         begin
@@ -1024,7 +1114,7 @@ begin
                       Break;
                     end
                   else // Ïóñòî:
-                    if c = MARK_FREE then
+                    if not isAnythingAt(X, Y+s) {c = MARK_FREE} then
                       Y := Y + s
                     else // Îñàëüíîå:
                       begin
@@ -1052,15 +1142,15 @@ begin
               begin // Ñòåêàåò/îòëèïàåò
                 VelY := 0.5;
                 AccelY := 0.15;
-                if (not ByteBool(gCollideMap[Y, X-1] and MARK_BLOCKED)) and
-                   (not ByteBool(gCollideMap[Y, X+1] and MARK_BLOCKED)) then
+                if (not isBlockedAt(X-1, Y) {ByteBool(gCollideMap[Y, X-1] and MARK_BLOCKED)}) and
+                   (not isBlockedAt(X+1, Y) {ByteBool(gCollideMap[Y, X+1] and MARK_BLOCKED)}) then
                   State := STATE_NORMAL;
                 Continue;
               end;
 
-              if not ByteBool(gCollideMap[Y, X] and MARK_BLOCKED) then
+              if not isBlockedAt(X, Y) {ByteBool(gCollideMap[Y, X] and MARK_BLOCKED)} then
               begin
-                if ByteBool(gCollideMap[Y, X] and MARK_LIFTUP) then
+                if isLiftUpAt(X, Y) {ByteBool(gCollideMap[Y, X] and MARK_LIFTUP)} then
                 begin // Ëèôò ââåðõ
                   if VelY > -4-Random(3) then
                     VelY := VelY - 0.8;
@@ -1069,13 +1159,13 @@ begin
                   VelX := VelX + (Random-Random)*0.2;
                   AccelY := 0.15;
                 end;
-                if ByteBool(gCollideMap[Y, X] and MARK_LIFTLEFT) then
+                if isLiftLeftAt(X, Y) {ByteBool(gCollideMap[Y, X] and MARK_LIFTLEFT)} then
                 begin // Ïîòîê âëåâî
                   if VelX > -8-Random(3) then
                     VelX := VelX - 0.8;
                   AccelY := 0.15;
                 end;
-                if ByteBool(gCollideMap[Y, X] and MARK_LIFTRIGHT) then
+                if isLiftRightAt(X, Y) {ByteBool(gCollideMap[Y, X] and MARK_LIFTRIGHT)} then
                 begin // Ïîòîê âïðàâî
                   if VelX < 8+Random(3) then
                     VelX := VelX + 0.8;
@@ -1088,9 +1178,9 @@ begin
 
               if (Abs(VelX) < 0.1) and (Abs(VelY) < 0.1) then
                 if (State <> STATE_STICK) and
-                   (not ByteBool(gCollideMap[Y-1, X] and MARK_BLOCKED)) and
-                   (not ByteBool(gCollideMap[Y, X] and MARK_BLOCKED)) and
-                   (not ByteBool(gCollideMap[Y+1, X] and MARK_BLOCKED)) then
+                   (not isBlockedAt(X, Y-1) {ByteBool(gCollideMap[Y-1, X] and MARK_BLOCKED)}) and
+                   (not isBlockedAt(X, Y) {ByteBool(gCollideMap[Y, X] and MARK_BLOCKED)}) and
+                   (not isBlockedAt(X, Y+1) {ByteBool(gCollideMap[Y+1, X] and MARK_BLOCKED)}) then
                 begin // Âèñèò â âîçäóõå - êàïàåò
                   VelY := 0.8;
                   AccelY := 0.5;
@@ -1112,15 +1202,15 @@ begin
                     Break;
                   end;
 
-                  c := gCollideMap[Y, X+s];
+                  //c := gCollideMap[Y, X+s];
 
-                  if ByteBool(c and MARK_LIQUID) and (dY > 0) then
+                  if isLiquidAt(X+s, Y) {ByteBool(c and MARK_LIQUID)} and (dY > 0) then
                   begin // Ñáîêó æèäêîñòü, à ÷àñòèöà óæå ïàäàåò
                     State := STATE_FREE;
                     Break;
                   end;
 
-                  if ByteBool(c and MARK_BLOCKED) then
+                  if isBlockedAt(X+s, Y) {ByteBool(c and MARK_BLOCKED)} then
                   begin // Ñòåíà/äâåðü
                     VelX := 0;
                     VelY := 0;
@@ -1149,15 +1239,15 @@ begin
                     Break;
                   end;
 
-                  c := gCollideMap[Y+s, X];
+                  //c := gCollideMap[Y+s, X];
 
-                  if ByteBool(c and MARK_LIQUID) and (dY > 0) then
+                  if isLiquidAt(X, Y+s) {ByteBool(c and MARK_LIQUID)} and (dY > 0) then
                   begin // Ñíèçó æèäêîñòü, à ÷àñòèöà óæå ïàäàåò
                     State := STATE_FREE;
                     Break;
                   end;
 
-                  if ByteBool(c and MARK_BLOCKED) then
+                  if isBlockedAt(X, Y+s) {ByteBool(c and MARK_BLOCKED)} then
                   begin // Ñòåíà/äâåðü
                     VelX := 0;
                     VelY := 0;
@@ -1199,7 +1289,7 @@ begin
                     Break;
                   end;
 
-                  if not ByteBool(gCollideMap[Y+s, X] and MARK_LIQUID) then
+                  if not isLiquidAt(X, Y+s) {ByteBool(gCollideMap[Y+s, X] and MARK_LIQUID)} then
                   begin // Óæå íå æèäêîñòü
                     State := STATE_FREE;
                     Break;
@@ -1217,7 +1307,9 @@ begin
           end; // case
 
           CorrectOffsets(a);
-        end;
+        end; // with
+      end; // if
+    end; // for
   end; // Particles <> nil
 
   if OnceAnims <> nil then