collision indicator on failed girder placement (especially useful with rubberband I guess). still needs some tweaks but I am going to bed now :P
--- 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