partial implementation of non-infinite world (edge wrap/warp/bounce)
authornemo
Sun, 29 Sep 2013 16:10:32 -0400
changeset 9473 a51a69094c24
parent 9470 9ed07a96349d
child 9475 619920c6aea0
partial implementation of non-infinite world (edge wrap/warp/bounce)
hedgewars/uGearsHandlersMess.pas
hedgewars/uGearsHandlersRope.pas
hedgewars/uGearsHedgehog.pas
hedgewars/uGearsUtils.pas
hedgewars/uTypes.pas
hedgewars/uVariables.pas
hedgewars/uWorld.pas
--- a/hedgewars/uGearsHandlersMess.pas	Fri Sep 27 21:52:21 2013 -0400
+++ b/hedgewars/uGearsHandlersMess.pas	Sun Sep 29 16:10:32 2013 -0400
@@ -284,6 +284,8 @@
     collV, collH: LongInt;
     land: word;
 begin
+    WorldWrap(Gear);
+
     // clip velocity at 2 - over 1 per pixel, but really shouldn't cause many actual problems.
     if Gear^.dX.Round > 2 then
         Gear^.dX.QWordValue:= 8589934592;
@@ -302,8 +304,6 @@
     tdX := Gear^.dX;
     tdY := Gear^.dY;
 
-
-
 // might need some testing/adjustments - just to avoid projectiles to fly forever (accelerated by wind/skips)
     if (hwRound(Gear^.X) < min(LAND_WIDTH div -2, -2048))
     or (hwRound(Gear^.X) > max(LAND_WIDTH * 3 div 2, 6144)) then
@@ -889,6 +889,7 @@
     flower: PVisualGear;
 
 begin
+    WorldWrap(Gear);
     AllInactive := false;
     gX := hwRound(Gear^.X);
     gY := hwRound(Gear^.Y);
@@ -4637,6 +4638,7 @@
 ////////////////////////////////////////////////////////////////////////////////
 procedure doStepPoisonCloud(Gear: PGear);
 begin
+    WorldWrap(Gear);
     if Gear^.Timer = 0 then
         begin
         DeleteGear(Gear);
--- a/hedgewars/uGearsHandlersRope.pas	Fri Sep 27 21:52:21 2013 -0400
+++ b/hedgewars/uGearsHandlersRope.pas	Sun Sep 29 16:10:32 2013 -0400
@@ -33,6 +33,7 @@
     HHGear: PGear;
 begin
     HHGear := Gear^.Hedgehog^.Gear;
+    WorldWrap(HHGear);
     if (HHGear^.Hedgehog^.CurAmmoType = amParachute) and (HHGear^.dY > _0_39) then
         begin
         DeleteGear(Gear);
@@ -116,7 +117,7 @@
 
     HHGear := Gear^.Hedgehog^.Gear;
 
-    if ((HHGear^.State and gstHHDriven) = 0)
+    if ((HHGear^.State and gstHHDriven) = 0) or WorldWrap(HHGear)
        or (CheckGearDrowning(HHGear)) or (Gear^.PortalCounter <> 0) then
         begin
         PlaySound(sndRopeRelease);
--- a/hedgewars/uGearsHedgehog.pas	Fri Sep 27 21:52:21 2013 -0400
+++ b/hedgewars/uGearsHedgehog.pas	Sun Sep 29 16:10:32 2013 -0400
@@ -828,6 +828,7 @@
 var isFalling, isUnderwater: boolean;
     land: Word;
 begin
+WorldWrap(Gear);
 land:= 0;
 isUnderwater:= cWaterLine < hwRound(Gear^.Y) + Gear^.Radius;
 if Gear^.dX.QWordValue > 8160437862 then
--- a/hedgewars/uGearsUtils.pas	Fri Sep 27 21:52:21 2013 -0400
+++ b/hedgewars/uGearsUtils.pas	Sun Sep 29 16:10:32 2013 -0400
@@ -53,6 +53,8 @@
 function  GetAmmo(Hedgehog: PHedgehog): TAmmoType;
 function  GetUtility(Hedgehog: PHedgehog): TAmmoType;
 
+function WorldWrap(var Gear: PGear): boolean;
+
 
 
 function MakeHedgehogsStep(Gear: PGear) : boolean;
@@ -486,7 +488,10 @@
             CurAmmoGear^.Pos := 1000
         end
     else
-        CheckGearDrowning := false;
+        begin
+        if Gear^.Kind = gtHedgehog then Gear^.State:= Gear^.State and not gstSubmersible;
+        CheckGearDrowning := false
+        end
 end;
 
 
@@ -1198,5 +1203,75 @@
 GetUtility:= i
 end;
 
+(*
+Intended to check Gear X/Y against the map left/right edges and apply one of the world modes
+* Normal - infinite world, do nothing
+* Wrap (entering left edge exits at same height on right edge)
+* Bounce (striking edge is treated as a 100% elasticity bounce)
+* From the depths (same as from sky, but from sea, with submersible flag set)
+
+Trying to make the checks a little broader than on first pass to catch things that don't move normally.
+*)
+function WorldWrap(var Gear: PGear): boolean;
+var tdx: hwFloat;
+begin
+WorldWrap:= false;
+// for playing around since it isn't hooked up yet
+//WorldEdge:= weBounce;
+if WorldEdge = weNone then exit(false);
+if (hwRound(Gear^.X)-Gear^.Radius < leftX) or
+   (hwRound(Gear^.X)+Gear^.Radius > rightX) then
+    begin
+    if WorldEdge = weWrap then
+        begin
+        if (hwRound(Gear^.X)-Gear^.Radius < leftX) then
+             Gear^.X:= int2hwfloat(rightX-Gear^.Radius)
+        else Gear^.X:= int2hwfloat(leftX+Gear^.Radius)
+        end
+    else if WorldEdge = weBounce then
+        begin
+        if (hwRound(Gear^.X)-Gear^.Radius < leftX) then
+            begin
+            Gear^.dX.isNegative:= false;
+            Gear^.X:= int2hwfloat(leftX+Gear^.Radius)
+            end
+        else 
+            begin
+            Gear^.dX.isNegative:= true;
+            Gear^.X:= int2hwfloat(rightX-Gear^.Radius)
+            end
+        end
+    else if WorldEdge = weSea then
+        begin
+        if (hwRound(Gear^.Y) > cWaterLine) and (Gear^.State and gstSubmersible <> 0) then
+            Gear^.State:= Gear^.State and not gstSubmersible
+        else
+            begin
+            Gear^.State:= Gear^.State or gstSubmersible;
+            Gear^.X:= int2hwFloat(PlayWidth)*int2hwFloat(min(max(0,hwRound(Gear^.Y)),PlayHeight))/PlayHeight;
+            Gear^.Y:= int2hwFloat(cWaterLine+cVisibleWater+Gear^.Radius*2);
+            tdx:= Gear^.dX;
+            Gear^.dX:= Gear^.dY;
+            Gear^.dY:= tdx;
+            Gear^.dY.isNegative:= true
+            end
+        end;
+(*
+* Window in the sky (Gear moved high into the sky, Y is used to determine X) [unfortunately, not a safe thing to do. shame, I thought aerial bombardment would be kinda neat
+This one would be really easy to freeze game unless it was flagged unfortunately.
+
+    else 
+        begin
+        Gear^.X:= int2hwFloat(PlayWidth)*int2hwFloat(min(max(0,hwRound(Gear^.Y)),PlayHeight))/PlayHeight;
+        Gear^.Y:= -_2048-_256-_256;
+        tdx:= Gear^.dX;
+        Gear^.dX:= Gear^.dY;
+        Gear^.dY:= tdx;
+        Gear^.dY.isNegative:= false
+        end
+*)
+    WorldWrap:= true
+    end;
+end;
 
 end.
--- a/hedgewars/uTypes.pas	Fri Sep 27 21:52:21 2013 -0400
+++ b/hedgewars/uTypes.pas	Sun Sep 29 16:10:32 2013 -0400
@@ -173,6 +173,8 @@
     TRenderMode = (rmDefault, rmLeftEye, rmRightEye);
     TStereoMode = (smNone, smRedCyan, smCyanRed, smRedBlue, smBlueRed, smRedGreen, smGreenRed, smHorizontal, smVertical);
 
+    TWorldEdge = (weNone, weWrap, weBounce, weSea, weSky);
+
     THHFont = record
             Handle: PTTF_Font;
             Height: LongInt;
--- a/hedgewars/uVariables.pas	Fri Sep 27 21:52:21 2013 -0400
+++ b/hedgewars/uVariables.pas	Sun Sep 29 16:10:32 2013 -0400
@@ -82,6 +82,7 @@
     GameType        : TGameType;
     InputMask       : LongWord;
     GameFlags       : Longword;
+    WorldEdge       : TWorldEdge;
     TurnTimeLeft    : Longword;
     TagTurnTimeLeft : Longword;
     ReadyTimeLeft   : Longword;
@@ -2446,6 +2447,7 @@
 
     InputMask           := $FFFFFFFF;
     GameFlags           := 0;
+    WorldEdge           := weNone;
     TurnTimeLeft        := 0;
     TagTurnTimeLeft     := 0;
     cSuddenDTurns       := 15;
--- a/hedgewars/uWorld.pas	Fri Sep 27 21:52:21 2013 -0400
+++ b/hedgewars/uWorld.pas	Sun Sep 29 16:10:32 2013 -0400
@@ -1235,6 +1235,13 @@
     end;
 {$WARNINGS ON}
 
+if WorldEdge <> weNone then
+    begin
+(* I think for a bounded world, will fill the left and right areas with black or something. Also will probably want various border effects/animations based on border type.  Prob also, say, trigger a border animation timer on an impact. *)
+    DrawLine(leftX, -3000, leftX, cWaterLine+cVisibleWater, 3.0, $FF, $00, $FF, $FF);
+    DrawLine(rightX, -3000, rightX, cWaterLine+cVisibleWater, 3.0, $FF, $00, $FF, $FF)
+    end;
+
 // this scale is used to keep the various widgets at the same dimension at all zoom levels
 SetScale(cDefaultZoomLevel);
 
@@ -1631,7 +1638,7 @@
         DrawSprite(sprArrow, TargetCursorPoint.X, cScreenHeight - TargetCursorPoint.Y, (RealTicks shr 6) mod 8)
         end
     end;
-isFirstFrame:= false
+isFirstFrame:= false;
 end;
 
 var PrevSentPointTime: LongWord = 0;