DEADSOFTWARE

slightly better water particles
[d2df-sdl.git] / src / game / g_gfx.pas
index ab895762d3cae8f6b59ed2cc18fe77fc87ed3650..bbdc4329cd2ee406e874f82158a40f61651f5c8e 100644 (file)
@@ -87,6 +87,8 @@ type
     offsetX, offsetY:   ShortInt;
     // for bubbles
     liquidTopY: Integer; // don't float higher than this
+    // for water
+    stickDX: Integer;
 
     //k8: sorry, i have to emulate virtual methods this way, 'cause i haet `Object`
 
@@ -690,71 +692,48 @@ begin
 end;
 
 
-// ////////////////////////////////////////////////////////////////////////// //
-procedure TParticle.thinkerBubble ();
-var
-  h: Integer;
-  dY: SmallInt;
-  b: Integer;
-  s: ShortInt;
-begin
-  h := gMapInfo.Height;
-
-  dY := Round(VelY);
-
-  if dY <> 0 then
-  begin
-    if dY > 0 then
-      s := 1
-    else
-      s := -1;
-
-    for b := 1 to Abs(dY) do
-    begin
-      if (Y+s >= h) or (Y+s <= 0) then begin die(); break; end;
-
-      (*
-      if not isLiquidAt(X, Y+s) {ByteBool(gCollideMap[Y+s, X] and MARK_LIQUID)} then
-      begin // Óæå íå æèäêîñòü
-        State := STATE_FREE;
-        Break;
-      end;
-      *)
-      // we traced liquid before, so don't bother checking
-      if (Y+s <= liquidTopY) then begin die(); break; end;
-
-      Y := Y+s;
-    end;
-  end;
-
-  if VelY > -4 then
-    VelY := VelY + AccelY;
-
-  Time := Time + 1;
-end;
-
-
 // ////////////////////////////////////////////////////////////////////////// //
 procedure TParticle.thinkerWater ();
 var
-  w, h: Integer;
   dX, dY: SmallInt;
+  {$IF not DEFINED(D2F_NEW_SPARK_THINKER)}
+  w, h: Integer;
   b: Integer;
   s: ShortInt;
+  {$ELSE}
+  pan: TPanel;
+  ex, ey: Integer;
+  {$ENDIF}
 begin
+  {$IF not DEFINED(D2F_NEW_SPARK_THINKER)}
   w := gMapInfo.Width;
   h := gMapInfo.Height;
+  {$ENDIF}
 
+  //TODO: trace wall end when water becomes stick
   if (State = STATE_STICK) and (Random(30) = 15) then
   begin // Ñòåêàåò/îòëèïàåò
     VelY := 0.5;
     AccelY := 0.15;
+    {$IF not DEFINED(D2F_NEW_SPARK_THINKER)}
     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;
+    {$ELSE}
+    if (stickDX = 0) then
+    begin
+      // no walls around, drop
+      State := STATE_NORMAL;
+    end
+    else
+    begin
+      if (g_Map_PanelAtPoint(X+stickDX, Y, (GridTagWall or GridTagDoor or GridTagStep)) = nil) then State := STATE_NORMAL;
+    end;
+    {$ENDIF}
     exit;
   end;
 
+  {$IF not DEFINED(D2F_NEW_SPARK_THINKER)}
   if not isBlockedAt(X, Y) {ByteBool(gCollideMap[Y, X] and MARK_BLOCKED)} then
   begin
     if isLiftUpAt(X, Y) {ByteBool(gCollideMap[Y, X] and MARK_LIFTUP)} then
@@ -779,11 +758,37 @@ begin
       AccelY := 0.15;
     end;
   end;
+  {$ELSE}
+  pan := g_Map_PanelAtPoint(X, Y, (GridTagWall or GridTagDoor or GridTagStep or GridTagAcid1 or GridTagAcid2 or GridTagWater or GridTagLift));
+  if (pan <> nil) then
+  begin
+    if ((pan.tag and (GridTagAcid1 or GridTagAcid2 or GridTagWater)) <> 0) then begin die(); exit; end;
+    if ((pan.PanelType and PANEL_LIFTUP) <> 0) then
+    begin
+      if (VelY > -4-Random(3)) then VelY -= 0.8;
+      if (Abs(VelX) > 0.1) then VelX -= VelX/10.0;
+      VelX += (Random-Random)*0.2;
+      AccelY := 0.15;
+    end;
+    if ((pan.PanelType and PANEL_LIFTLEFT) <> 0) then
+    begin
+      if (VelX > -8-Random(3)) then VelX -= 0.8;
+      AccelY := 0.15;
+    end;
+    if ((pan.PanelType and PANEL_LIFTRIGHT) <> 0) then
+    begin
+      if (VelX < 8+Random(3)) then VelX += 0.8;
+      AccelY := 0.15;
+    end;
+  end;
+  {$ENDIF}
 
   dX := Round(VelX);
   dY := Round(VelY);
 
+  {$IF not DEFINED(D2F_NEW_SPARK_THINKER)}
   if (Abs(VelX) < 0.1) and (Abs(VelY) < 0.1) then
+  begin
     if (State <> STATE_STICK) and
        (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
@@ -793,24 +798,88 @@ begin
       AccelY := 0.5;
       State := STATE_NORMAL;
     end;
-
-  if dX <> 0 then
+  end;
+  {$ELSE}
+  if (State <> STATE_STICK) and (Abs(VelX) < 0.1) and (Abs(VelY) < 0.1) then
   begin
-    if dX > 0 then
-      s := 1
-    else
-      s := -1;
+    // Âèñèò â âîçäóõå - êàïàåò
+    if (nil = g_Map_traceToNearest(X, Y-1, X, Y+1, (GridTagWall or GridTagDoor or GridTagStep or GridTagAcid1 or GridTagAcid2 or GridTagWater), @ex, @ey)) then
+    begin
+      VelY := 0.8;
+      AccelY := 0.5;
+      State := STATE_NORMAL;
+    end;
+  end;
+  {$ENDIF}
 
+  {$IF DEFINED(D2F_NEW_SPARK_THINKER)}
+  // horizontal
+  if (dX <> 0) then
+  begin
+    pan := g_Map_traceToNearest(X, Y, X+dX, Y, (GridTagWall or GridTagDoor or GridTagStep or GridTagAcid1 or GridTagAcid2 or GridTagWater), @ex, @ey);
+    X := ex;
+    // free to ride?
+    if (pan <> nil) then
+    begin
+      // nope
+      if (dY > 0) and ((pan.tag and (GridTagAcid1 or GridTagAcid2 or GridTagWater)) <> 0) then begin die(); exit; end;
+      // Ñòåíà/äâåðü?
+      if ((pan.tag and (GridTagWall or GridTagDoor or GridTagStep)) <> 0) then
+      begin
+        VelX := 0;
+        VelY := 0;
+        AccelX := 0;
+        AccelY := 0;
+        State := STATE_STICK;
+        if (dX > 0) then stickDX := 1 else stickDX := -1;
+      end;
+    end;
+    if (X < 0) or (X >= gMapInfo.Width) then begin die(); exit; end;
+  end;
+  // vertical
+  if (dY <> 0) then
+  begin
+    pan := g_Map_traceToNearest(X, Y, X, Y+dY, (GridTagWall or GridTagDoor or GridTagStep or GridTagAcid1 or GridTagAcid2 or GridTagWater), @ex, @ey);
+    Y := ey;
+    // free to ride?
+    if (pan <> nil) then
+    begin
+      // nope
+      if (dY > 0) and ((pan.tag and (GridTagAcid1 or GridTagAcid2 or GridTagWater)) <> 0) then begin die(); exit; end;
+      // Ñòåíà/äâåðü?
+      if ((pan.tag and (GridTagWall or GridTagDoor or GridTagStep)) <> 0) then
+      begin
+        VelX := 0;
+        VelY := 0;
+        AccelX := 0;
+        AccelY := 0;
+        if (dY > 0) and (State <> STATE_STICK) then
+        begin
+          State := STATE_NORMAL;
+        end
+        else
+        begin
+          State := STATE_STICK;
+               if (g_Map_PanelAtPoint(X-1, Y, (GridTagWall or GridTagDoor or GridTagStep)) <> nil) then stickDX := -1
+          else if (g_Map_PanelAtPoint(X+1, Y, (GridTagWall or GridTagDoor or GridTagStep)) <> nil) then stickDX := 1
+          else stickDX := 0;
+        end;
+      end;
+    end;
+    if (Y < 0) or (Y >= gMapInfo.Height) then begin die(); exit; end;
+  end;
+  {$ELSE}
+  // horizontal
+  if (dX <> 0) then
+  begin
+    if (dX > 0) then s := 1 else s := -1;
     for b := 1 to Abs(dX) do
     begin
-       // Ñáîêó ãðàíèöà?
+      // Ñáîêó ãðàíèöà?
       if (X+s >= w) or (X+s <= 0) then begin die(); break;end;
-
       //c := gCollideMap[Y, X+s];
-
       // Ñáîêó æèäêîñòü, à ÷àñòèöà óæå ïàäàåò?
       if isLiquidAt(X+s, Y) {ByteBool(c and MARK_LIQUID)} and (dY > 0) then begin die(); break; end;
-
       if isBlockedAt(X+s, Y) {ByteBool(c and MARK_BLOCKED)} then
       begin // Ñòåíà/äâåðü
         VelX := 0;
@@ -820,47 +889,80 @@ begin
         State := STATE_STICK;
         Break;
       end;
-
       X := X+s;
     end;
   end;
-
-  if dY <> 0 then
+  // vertical
+  if (dY <> 0) then
   begin
-    if dY > 0 then
-      s := 1
-    else
-      s := -1;
-
+    if (dY > 0) then s := 1 else s := -1;
     for b := 1 to Abs(dY) do
     begin
       // Ñíèçó/ñâåðõó ãðàíèöà
       if (Y+s >= h) or (Y+s <= 0) then begin die(); break; end;
-
       //c := gCollideMap[Y+s, X];
-
       // Ñíèçó æèäêîñòü, à ÷àñòèöà óæå ïàäàåò
       if isLiquidAt(X, Y+s) {ByteBool(c and MARK_LIQUID)} and (dY > 0) then begin die(); break; end;
-
       if isBlockedAt(X, Y+s) {ByteBool(c and MARK_BLOCKED)} then
       begin // Ñòåíà/äâåðü
         VelX := 0;
         VelY := 0;
         AccelX := 0;
         AccelY := 0;
-        if (s > 0) and (State <> STATE_STICK) then
-          State := STATE_NORMAL
-        else
-          State := STATE_STICK;
+        if (s > 0) and (State <> STATE_STICK) then State := STATE_NORMAL else State := STATE_STICK;
+        break;
+      end;
+      Y := Y+s;
+    end;
+  end;
+  {$ENDIF}
+
+  VelX += AccelX;
+  VelY += AccelY;
+
+  Time += 1;
+end;
+
+
+// ////////////////////////////////////////////////////////////////////////// //
+procedure TParticle.thinkerBubble ();
+var
+  h: Integer;
+  dY: SmallInt;
+  b: Integer;
+  s: ShortInt;
+begin
+  h := gMapInfo.Height;
+
+  dY := Round(VelY);
+
+  if dY <> 0 then
+  begin
+    if dY > 0 then
+      s := 1
+    else
+      s := -1;
+
+    for b := 1 to Abs(dY) do
+    begin
+      if (Y+s >= h) or (Y+s <= 0) then begin die(); break; end;
+
+      (*
+      if not isLiquidAt(X, Y+s) {ByteBool(gCollideMap[Y+s, X] and MARK_LIQUID)} then
+      begin // Óæå íå æèäêîñòü
+        State := STATE_FREE;
         Break;
       end;
+      *)
+      // we traced liquid before, so don't bother checking
+      if (Y+s <= liquidTopY) then begin die(); break; end;
 
       Y := Y+s;
     end;
   end;
 
-  VelX := VelX + AccelX;
-  VelY := VelY + AccelY;
+  if VelY > -4 then
+    VelY := VelY + AccelY;
 
   Time := Time + 1;
 end;
@@ -1286,7 +1388,7 @@ begin
 
       // 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;
+      if not g_Map_TraceLiquidNonPrecise(X, Y, 0, -8, liquidx, liquidTopY) then continue;
 
       VelX := 0;
       VelY := -1-Random;