collision indicator on failed girder placement (especially useful with rubberband I guess). still needs some tweaks but I am going to bed now :P
authorsheepluva
Sun, 01 Jun 2014 04:17:27 +0200
changeset 10251 a3b42e81803c
parent 10250 887610b44848
child 10252 814e137625f7
collision indicator on failed girder placement (especially useful with rubberband I guess). still needs some tweaks but I am going to bed now :P
hedgewars/uGearsHandlersMess.pas
hedgewars/uLandGraphics.pas
hedgewars/uTypes.pas
hedgewars/uVisualGears.pas
hedgewars/uVisualGearsHandlers.pas
hedgewars/uVisualGearsList.pas
hedgewars/uWorld.pas
--- a/hedgewars/uGearsHandlersMess.pas	Sat May 31 15:04:26 2014 -0400
+++ b/hedgewars/uGearsHandlersMess.pas	Sun Jun 01 04:17:27 2014 +0200
@@ -2502,6 +2502,8 @@
     x, y, tx, ty: hwFloat;
     rx: LongInt;
     LandFlags: Word;
+    warn: PVisualGear;
+    distFail: boolean;
 begin
     AllInactive := false;
 
@@ -2516,14 +2518,21 @@
     if Gear^.AmmoType = amRubber then LandFlags:= lfBouncy
     else if cIce then LandFlags:= lfIce;
 
-    if ((Distance(tx - x, ty - y) > _256) and ((WorldEdge <> weWrap) or
+    distFail:= ((Distance(tx - x, ty - y) > _256) and ((WorldEdge <> weWrap) or
             (
             (Distance(tx - int2hwFloat(rightX+(rx-leftX)), ty - y) > _256) and
             (Distance(tx - int2hwFloat(leftX-(rightX-rx)), ty - y) > _256)
-            )))
+            )));
+    if distFail
     or (not TryPlaceOnLand(Gear^.Target.X - SpritesData[Ammoz[Gear^.AmmoType].PosSprite].Width div 2, Gear^.Target.Y - SpritesData[Ammoz[Gear^.AmmoType].PosSprite].Height div 2, Ammoz[Gear^.AmmoType].PosSprite, Gear^.State, true, false, LandFlags)) then
         begin
         PlaySound(sndDenied);
+        if not distFail then
+            begin
+            warn:= AddVisualGear(Gear^.Target.X, Gear^.Target.Y, vgtNoPlaceWarn, 0);
+            if warn <> nil then
+                warn^.Tex := GetPlaceCollisionTex(Gear^.Target.X - SpritesData[Ammoz[Gear^.AmmoType].PosSprite].Width div 2, Gear^.Target.Y - SpritesData[Ammoz[Gear^.AmmoType].PosSprite].Height div 2, Ammoz[Gear^.AmmoType].PosSprite, Gear^.State);
+            end;
         HHGear^.Message := HHGear^.Message and (not gmAttack);
         HHGear^.State := HHGear^.State and (not gstAttacking);
         HHGear^.State := HHGear^.State or gstHHChooseTarget;
--- a/hedgewars/uLandGraphics.pas	Sat May 31 15:04:26 2014 -0400
+++ b/hedgewars/uLandGraphics.pas	Sun Jun 01 04:17:27 2014 +0200
@@ -49,9 +49,10 @@
 procedure DrawIceBreak(x, y, iceRadius, iceHeight: Longint);
 function TryPlaceOnLand(cpX, cpY: LongInt; Obj: TSprite; Frame: LongInt; doPlace, indestructible: boolean): boolean; inline;
 function TryPlaceOnLand(cpX, cpY: LongInt; Obj: TSprite; Frame: LongInt; doPlace, indestructible: boolean; LandFlags: Word): boolean;
+function GetPlaceCollisionTex(cpX, cpY: LongInt; Obj: TSprite; Frame: LongInt): PTexture;
 
 implementation
-uses SDLh, uLandTexture, uVariables, uUtils, uDebug;
+uses SDLh, uLandTexture, uTextures, uVariables, uUtils, uDebug;
 
 
 procedure calculatePixelsCoordinates(landX, landY: Longint; var pixelX, pixelY: Longint); inline;
@@ -694,6 +695,67 @@
 UpdateLandTexture(x, w, y, h, true)
 end;
 
+function GetPlaceCollisionTex(cpX, cpY: LongInt; Obj: TSprite; Frame: LongInt): PTexture;
+var X, Y, bpp, h, w, row, col, numFramesFirstCol: LongInt;
+    p, pt: PByteArray;
+    Image, finalSurface: PSDL_Surface;
+begin
+GetPlaceCollisionTex:= nil;
+numFramesFirstCol:= SpritesData[Obj].imageHeight div SpritesData[Obj].Height;
+
+TryDo(SpritesData[Obj].Surface <> nil, 'Assert SpritesData[Obj].Surface failed', true);
+Image:= SpritesData[Obj].Surface;
+w:= SpritesData[Obj].Width;
+h:= SpritesData[Obj].Height;
+row:= Frame mod numFramesFirstCol;
+col:= Frame div numFramesFirstCol;
+
+if SDL_MustLock(Image) then
+    SDLTry(SDL_LockSurface(Image) >= 0, true);
+
+bpp:= Image^.format^.BytesPerPixel;
+TryDo(bpp = 4, 'It should be 32 bpp sprite', true);
+
+
+
+finalSurface:= SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, 32, RMask, GMask, BMask, AMask);
+
+TryDo(finalSurface <> nil, 'GetPlaceCollisionTex: fail to create surface', true);
+
+if SDL_MustLock(finalSurface) then
+    SDLTry(SDL_LockSurface(finalSurface) >= 0, true);
+
+// draw on surface based on collisions
+p:= PByteArray(@(PByteArray(Image^.pixels)^[ Image^.pitch * row * h + col * w * 4 ]));
+pt:= PByteArray(@(PByteArray(finalSurface^.pixels)^));
+
+case bpp of
+    4: for y:= 0 to Pred(h) do
+        begin
+        for x:= 0 to Pred(w) do
+            if (((PLongword(@(p^[x * 4]))^) and AMask) <> 0)
+                and (((cpY + y) <= Longint(topY)) or ((cpY + y) >= LAND_HEIGHT) or
+                   ((cpX + x) <= Longint(leftX)) or ((cpX + x) >= Longint(rightX)) or (Land[cpY + y, cpX + x] <> 0)) then
+                    (PLongword(@(pt^[x * 4]))^):= cWhiteColor
+            else
+                (PLongword(@(pt^[x * 4]))^):= 0;
+        p:= PByteArray(@(p^[Image^.pitch]));
+        pt:= PByteArray(@(pt^[finalSurface^.pitch]));
+        end;
+    end;
+
+if SDL_MustLock(Image) then
+    SDL_UnlockSurface(Image);
+
+if SDL_MustLock(finalSurface) then
+    SDL_UnlockSurface(finalSurface);
+
+GetPlaceCollisionTex:= Surface2Tex(finalSurface, true);
+
+SDL_FreeSurface(finalSurface);
+end;
+
+
 function Despeckle(X, Y: LongInt): boolean;
 var nx, ny, i, j, c, xx, yy: LongInt;
     pixelsweep: boolean;
--- a/hedgewars/uTypes.pas	Sat May 31 15:04:26 2014 -0400
+++ b/hedgewars/uTypes.pas	Sun Jun 01 04:17:27 2014 +0200
@@ -113,7 +113,7 @@
             vgtDust, vgtSplash, vgtDroplet, vgtSmokeRing, vgtBeeTrace, vgtEgg,
             vgtFeather, vgtHealthTag, vgtSmokeTrace, vgtEvilTrace, vgtExplosion,
             vgtBigExplosion, vgtChunk, vgtNote, vgtLineTrail, vgtBulletHit, vgtCircle,
-            vgtSmoothWindBar, vgtStraightShot);
+            vgtSmoothWindBar, vgtStraightShot, vgtNoPlaceWarn);
 
     // Damage can be caused by different sources
     TDamageSource = (dsUnknown, dsFall, dsBullet, dsExplosion, dsShove, dsPoison);
--- a/hedgewars/uVisualGears.pas	Sat May 31 15:04:26 2014 -0400
+++ b/hedgewars/uVisualGears.pas	Sun Jun 01 04:17:27 2014 +0200
@@ -449,6 +449,8 @@
                                 DrawSprite(sprFlake, round(Gear^.X) + WorldDx, round(Gear^.Y) + WorldDy + SkyOffset, Gear^.Frame)
                             else
                                 DrawSpriteRotatedF(sprFlake, round(Gear^.X) + WorldDx, round(Gear^.Y) + WorldDy + SkyOffset, Gear^.Frame, 1, Gear^.Angle);
+                vgtNoPlaceWarn:
+                            DrawTexture(round(Gear^.X) + WorldDx - round(Gear^.Tex^.w * Gear^.Scale) div 2, round(Gear^.Y) + WorldDy - round(Gear^.Tex^.h * Gear^.Scale) div 2, Gear^.Tex, Gear^.Scale);
                 end;
             if (Gear^.Tint <> $FFFFFFFF) then
                 untint;
--- a/hedgewars/uVisualGearsHandlers.pas	Sat May 31 15:04:26 2014 -0400
+++ b/hedgewars/uVisualGearsHandlers.pas	Sun Jun 01 04:17:27 2014 +0200
@@ -895,6 +895,27 @@
     end
 end;
 
+////////////////////////////////////////////////////////////////////////////////
+procedure doStepNoPlaceWarn(Gear: PVisualGear; Steps: Longword);
+begin
+
+if Gear^.FrameTicks <= Steps then
+    DeleteVisualGear(Gear)
+else
+    begin
+    // age
+    dec(Gear^.FrameTicks, Steps);
+    // toggle between orange and red every few ticks
+    if (Gear^.FrameTicks div 300) mod 2 = 0 then
+        Gear^.Tint:= $FF400000
+    else
+        Gear^.Tint:= $FF000000;
+    // fade out alpha
+    Gear^.Tint:= Gear^.Tint or ((Gear^.FrameTicks * $FF) div 3000);
+    // get bigger as we fade out
+    // Gear^.Scale:= 1.1 - 0.001 * (Gear^.FrameTicks div 30);
+    end
+end;
 
 const handlers: array[TVisualGearType] of TVGearStepProcedure =
         (
@@ -930,7 +951,8 @@
             @doStepBulletHit,
             @doStepCircle,
             @doStepSmoothWindBar,
-            @doStepStraightShot
+            @doStepStraightShot,
+            @doStepNoPlaceWarn
         );
 
 procedure initModule;
--- a/hedgewars/uVisualGearsList.pas	Sat May 31 15:04:26 2014 -0400
+++ b/hedgewars/uVisualGearsList.pas	Sun Jun 01 04:17:27 2014 +0200
@@ -322,6 +322,12 @@
                 FrameTicks:= random(750) + 1250;
                 State:= ord(sprSnowDust);
                 end;
+  vgtNoPlaceWarn:
+                begin
+                FrameTicks:= 2000;
+                Tint:= $FF0000FF;
+                Scale:= 1.0;
+                end;
         end;
 
 if State <> 0 then
@@ -363,6 +369,7 @@
                   gear^.Scale:= 0.4;
                   gear^.Layer:= 4
                   end;
+    vgtNoPlaceWarn: gear^.Layer:= 6;
 
     // 0: this layer is very distant in the background when in stereo
     vgtTeamHealthSorter,
--- a/hedgewars/uWorld.pas	Sat May 31 15:04:26 2014 -0400
+++ b/hedgewars/uWorld.pas	Sun Jun 01 04:17:27 2014 +0200
@@ -1839,7 +1839,13 @@
             i:= GetCurAmmoEntry(CurrentHedgehog^)^.Pos;
             with Ammoz[CurAmmoType] do
                 if PosCount > 1 then
+                    begin
+                    if (CurAmmoType = amGirder) or (CurAmmoType = amRubber) then
+                        Tint($FF, $FF, $FF, $A0);
                     DrawSprite(PosSprite, TargetCursorPoint.X - (SpritesData[PosSprite].Width shr 1), cScreenHeight - TargetCursorPoint.Y - (SpritesData[PosSprite].Height shr 1),i);
+                    if (CurAmmoType = amGirder) or (CurAmmoType = amRubber) then
+                        Untint();
+                    end;
                 end;
         DrawSprite(sprArrow, TargetCursorPoint.X, cScreenHeight - TargetCursorPoint.Y, (RealTicks shr 6) mod 8)
         end