# HG changeset patch # User sheepluva # Date 1401589047 -7200 # Node ID a3b42e81803c8c41644f66da26a74fd63e3800eb # Parent 887610b4484835eb5e48b02e6f49b07b3d5e1b04 collision indicator on failed girder placement (especially useful with rubberband I guess). still needs some tweaks but I am going to bed now :P diff -r 887610b44848 -r a3b42e81803c hedgewars/uGearsHandlersMess.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; diff -r 887610b44848 -r a3b42e81803c hedgewars/uLandGraphics.pas --- 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; diff -r 887610b44848 -r a3b42e81803c hedgewars/uTypes.pas --- 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); diff -r 887610b44848 -r a3b42e81803c hedgewars/uVisualGears.pas --- 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; diff -r 887610b44848 -r a3b42e81803c hedgewars/uVisualGearsHandlers.pas --- 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; diff -r 887610b44848 -r a3b42e81803c hedgewars/uVisualGearsList.pas --- 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, diff -r 887610b44848 -r a3b42e81803c hedgewars/uWorld.pas --- 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