diff -r 8054d9d775fd -r 2759212a27de hedgewars/uGearsHandlersMess.pas --- a/hedgewars/uGearsHandlersMess.pas Fri Oct 11 17:43:13 2013 +0200 +++ b/hedgewars/uGearsHandlersMess.pas Sat Jan 04 23:55:54 2014 +0400 @@ -208,7 +208,7 @@ if (gi^.Kind = gtHedgehog) then begin d := r - hwRound(Distance(gi^.X - x, gi^.Y - y)); - if (d > 1) and (not gi^.Invulnerable) and (GetRandom(2) = 0) then + if (d > 1) and ((gi^.Hedgehog^.Effects[heInvulnerable] = 0)) and (GetRandom(2) = 0) then begin if (CurrentHedgehog^.Gear = gi) then PlaySoundV(sndOops, gi^.Hedgehog^.Team^.voicepack) @@ -263,13 +263,13 @@ Gear^.Y := Gear^.Y + cDrownSpeed; Gear^.X := Gear^.X + Gear^.dX * cDrownSpeed; // Create some bubbles (0.5% might be better but causes too few bubbles sometimes) - if (((not SuddenDeathDmg) and (WaterOpacity < $FF)) + if ((not SuddenDeathDmg and (WaterOpacity < $FF)) or (SuddenDeathDmg and (SDWaterOpacity < $FF))) and ((GameTicks and $1F) = 0) then if (Gear^.Kind = gtHedgehog) and (Random(4) = 0) then AddVisualGear(hwRound(Gear^.X) - Gear^.Radius, hwRound(Gear^.Y) - Gear^.Radius, vgtBubble) else if Random(12) = 0 then AddVisualGear(hwRound(Gear^.X) - Gear^.Radius, hwRound(Gear^.Y) - Gear^.Radius, vgtBubble); - if ((not SuddenDeathDmg) and (WaterOpacity > $FE)) + if (not SuddenDeathDmg and (WaterOpacity > $FE)) or (SuddenDeathDmg and (SDWaterOpacity > $FE)) or (hwRound(Gear^.Y) > Gear^.Radius + cWaterLine + cVisibleWater) then DeleteGear(Gear); @@ -280,30 +280,33 @@ var isFalling: boolean; //tmp: QWord; - tdX, tdY: hwFloat; - collV, collH: LongInt; - land: word; + tX, tdX, tdY: hwFloat; + collV, collH, gX, gY: LongInt; + land, xland: word; + boing: PVisualGear; begin - WorldWrap(Gear); + tX:= Gear^.X; + gX:= hwRound(Gear^.X); + gY:= hwRound(Gear^.Y); + if (Gear^.Kind <> gtGenericFaller) and WorldWrap(Gear) and (WorldEdge = weWrap) and (Gear^.AdvBounce <> 0) and + ((TestCollisionXwithGear(Gear, 1) <> 0) or (TestCollisionXwithGear(Gear, -1) <> 0)) then + begin + Gear^.X:= tX; + Gear^.dX.isNegative:= (gX > LongInt(leftX) + Gear^.Radius*2) + end; // clip velocity at 2 - over 1 per pixel, but really shouldn't cause many actual problems. -{$IFNDEF WEBGL} if Gear^.dX.Round > 2 then Gear^.dX.QWordValue:= 8589934592; if Gear^.dY.Round > 2 then Gear^.dY.QWordValue:= 8589934592; -{$ELSE} - if Gear^.dX.Round > 2 then - begin - Gear^.dX.Round:= 2; - Gear^.dX.Frac:= 0 + + if (Gear^.State and gstSubmersible <> 0) and (gY > cWaterLine) then + begin + Gear^.dX:= Gear^.dX * _0_999; + Gear^.dY:= Gear^.dY * _0_999 end; - if Gear^.dY.QWordValue > 2 then - begin - Gear^.dY.Round:= 2; - Gear^.dY.Frac:= 0 - end; -{$ENDIF} + Gear^.State := Gear^.State and (not gstCollision); collV := 0; collH := 0; @@ -311,27 +314,32 @@ 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 + if (gX < min(LAND_WIDTH div -2, -2048)) + or (gX > max(LAND_WIDTH * 3 div 2, 6144)) then Gear^.State := Gear^.State or gstCollision; if Gear^.dY.isNegative then begin - isFalling := true; land:= TestCollisionYwithGear(Gear, -1); + isFalling := land = 0; if land <> 0 then begin collV := -1; if land and lfIce <> 0 then - Gear^.dX := Gear^.dX * (_0_9 + Gear^.Friction * _0_1) - else - Gear^.dX := Gear^.dX * Gear^.Friction; - - Gear^.dY := - Gear^.dY * Gear^.Elasticity; - Gear^.State := Gear^.State or gstCollision + Gear^.dX := Gear^.dX * (_0_9 + Gear^.Friction * _0_1) + else Gear^.dX := Gear^.dX * Gear^.Friction; + if (Gear^.AdvBounce = 0) or (land and lfBouncy = 0) then + begin + Gear^.dY := - Gear^.dY * Gear^.Elasticity; + Gear^.State := Gear^.State or gstCollision + end + else Gear^.dY := - Gear^.dY * cElastic end - else if (Gear^.AdvBounce=1) and (TestCollisionYwithGear(Gear, 1) <> 0) then - collV := 1; + else if Gear^.AdvBounce = 1 then + begin + land:= TestCollisionYwithGear(Gear, 1); + if land <> 0 then collV := 1 + end end else begin // Gear^.dY.isNegative is false @@ -345,35 +353,64 @@ else Gear^.dX := Gear^.dX * Gear^.Friction; - Gear^.dY := - Gear^.dY * Gear^.Elasticity; - Gear^.State := Gear^.State or gstCollision + if (Gear^.AdvBounce = 0) or (land and lfBouncy = 0) then + begin + Gear^.dY := - Gear^.dY * Gear^.Elasticity; + Gear^.State := Gear^.State or gstCollision + end + else Gear^.dY := - Gear^.dY * cElastic end else begin isFalling := true; - if (Gear^.AdvBounce=1) and (TestCollisionYwithGear(Gear, -1) <> 0) then - collV := -1 + if Gear^.AdvBounce = 1 then + begin + land:= TestCollisionYwithGear(Gear, -1); + if land <> 0 then collV := -1 + end end end; - if TestCollisionXwithGear(Gear, hwSign(Gear^.dX)) then + xland:= TestCollisionXwithGear(Gear, hwSign(Gear^.dX)); + if xland <> 0 then begin collH := hwSign(Gear^.dX); - Gear^.dX := - Gear^.dX * Gear^.Elasticity; - Gear^.dY := Gear^.dY * Gear^.Elasticity; - Gear^.State := Gear^.State or gstCollision + if (Gear^.AdvBounce = 0) or (xland and lfBouncy = 0) then + begin + Gear^.dX := - Gear^.dX * Gear^.Elasticity; + Gear^.dY := Gear^.dY * Gear^.Elasticity; + Gear^.State := Gear^.State or gstCollision + end + else + begin + Gear^.dX := - Gear^.dX * cElastic; + Gear^.dY := Gear^.dY * cElastic + end end - else if (Gear^.AdvBounce=1) and TestCollisionXwithGear(Gear, -hwSign(Gear^.dX)) then - collH := -hwSign(Gear^.dX); + else if Gear^.AdvBounce = 1 then + begin + xland:= TestCollisionXwithGear(Gear, -hwSign(Gear^.dX)); + if xland <> 0 then collH := -hwSign(Gear^.dX) + end; //if Gear^.AdvBounce and (collV <>0) and (collH <> 0) and (hwSqr(tdX) + hwSqr(tdY) > _0_08) then - if (Gear^.AdvBounce=1) and (collV <>0) and (collH <> 0) and ((collV=-1) - or ((tdX.QWordValue + tdY.QWordValue) > _0_2.QWordValue)) then - begin - Gear^.dX := tdY*Gear^.Elasticity*Gear^.Friction; - Gear^.dY := tdX*Gear^.Elasticity; - //*Gear^.Friction; - Gear^.dY.isNegative := (not tdY.isNegative); + if (collV <> 0) and (collH <> 0) and + (((Gear^.AdvBounce=1) and ((collV=-1) or ((tdX.QWordValue + tdY.QWordValue) > _0_2.QWordValue)))) then + //or ((xland or land) and lfBouncy <> 0)) then + begin + if (xland or land) and lfBouncy = 0 then + begin + Gear^.dX := tdY*Gear^.Elasticity*Gear^.Friction; + Gear^.dY := tdX*Gear^.Elasticity; + Gear^.State := Gear^.State or gstCollision + end + else + begin + Gear^.dX := tdY*cElastic*Gear^.Friction; + Gear^.dY := tdX*cElastic + end; + + Gear^.dY.isNegative := not tdY.isNegative; isFalling := false; Gear^.AdvBounce := 10; end; @@ -386,7 +423,7 @@ Gear^.dY := Gear^.dY + cGravity; if (GameFlags and gfMoreWind) <> 0 then Gear^.dX := Gear^.dX + cWindSpeed / Gear^.Density - end; + end; Gear^.X := Gear^.X + Gear^.dX; Gear^.Y := Gear^.Y + Gear^.dY; @@ -397,7 +434,28 @@ else Gear^.State := Gear^.State or gstMoving; - if (Gear^.nImpactSounds > 0) and + if ((xland or land) and lfBouncy <> 0) and (Gear^.dX.QWordValue < _0_15.QWordValue) and (Gear^.dY.QWordValue < _0_15.QWordValue) then + Gear^.State := Gear^.State or gstCollision; + + if ((xland or land) and lfBouncy <> 0) and (Gear^.Radius >= 3) and + ((Gear^.dX.QWordValue > _0_15.QWordValue) or (Gear^.dY.QWordValue > _0_15.QWordValue)) then + begin + boing:= AddVisualGear(gX, gY, vgtStraightShot, 0, false, 1); + if boing <> nil then + with boing^ do + begin + Angle:= random(360); + dx:= 0; + dy:= 0; + FrameTicks:= 200; + tX:= _0; + tX.QWordValue:= Gear^.dY.QWordValue + Gear^.dX.QWordValue; + Scale:= hwFloat2Float(Gear^.Density * tX) / 1.5; + State:= ord(sprBoing) + end; + PlaySound(sndMelonImpact, true) + end + else if (Gear^.nImpactSounds > 0) and (Gear^.State and gstCollision <> 0) and (((Gear^.Kind <> gtMine) and (Gear^.Damage <> 0)) or (Gear^.State and gstMoving <> 0)) and (((Gear^.Radius < 3) and (Gear^.dY < -_0_1)) or @@ -700,6 +758,13 @@ draw:= true; xx:= hwRound(Gear^.X); yy:= hwRound(Gear^.Y); + if draw and (WorldEdge = weWrap) and ((xx < LongInt(leftX) + 3) or (xx > LongInt(rightX) - 3)) then + begin + if xx < LongInt(leftX) + 3 then + xx:= rightX-3 + else xx:= leftX+3; + Gear^.X:= int2hwFloat(xx) + end end else if GameTicks and $7 = 0 then begin @@ -864,21 +929,21 @@ AllInactive := false; if Gear^.dY.isNegative then - if TestCollisionY(Gear, -1) then + if TestCollisionY(Gear, -1) <> 0 then Gear^.dY := _0; - if (not Gear^.dY.isNegative) then - if TestCollisionY(Gear, 1) then - begin + if not Gear^.dY.isNegative then + if TestCollisionY(Gear, 1) <> 0 then + begin Gear^.dY := - Gear^.dY * Gear^.Elasticity; if Gear^.dY > - _1div1024 then - begin + begin Gear^.Active := false; exit - end + end else if Gear^.dY < - _0_03 then PlaySound(Gear^.ImpactSound) - end; + end; Gear^.Y := Gear^.Y + Gear^.dY; CheckGearDrowning(Gear); @@ -924,13 +989,24 @@ if Gear^.Timer = 0 then - Gear^.RenderTimer:= false + begin + // no "fuel"? just fall + doStepFallingGear(Gear); + // if drowning, stop bee sound + if (Gear^.State and gstDrowning) <> 0 then + StopSoundChan(Gear^.SoundChannel); + end else begin if (GameTicks and $F) = 0 then begin if (GameTicks and $30) = 0 then - AddVisualGear(gX, gY, vgtBeeTrace); + begin + if nuw then + AddVisualGear(gX, gY, vgtBubble) + else + AddVisualGear(gX, gY, vgtBeeTrace); + end; Gear^.dX := Gear^.Elasticity * (Gear^.dX + _0_000064 * (Gear^.Target.X - gX)); Gear^.dY := Gear^.Elasticity * (Gear^.dY + _0_000064 * (Gear^.Target.Y - gY)); // make sure new speed isn't higher than original one (which we stored in Friction variable) @@ -971,17 +1047,15 @@ end; if (Gear^.Timer > 0) then - dec(Gear^.Timer) - else - begin - Gear^.State:= Gear^.State and (not gstSubmersible); - if nuw then - begin - StopSoundChan(Gear^.SoundChannel); - CheckGearDrowning(Gear); - end - else - doStepFallingGear(Gear); + begin + dec(Gear^.Timer); + if Gear^.Timer = 0 then + begin + // no need to display remaining time anymore + Gear^.RenderTimer:= false; + // bee can drown when timer reached 0 + Gear^.State:= Gear^.State and not gstSubmersible; + end; end; end; @@ -1141,7 +1215,7 @@ Gear^.Y := Gear^.Y + Gear^.dY; tX:= Gear^.X; tY:= Gear^.Y; - if WorldWrap(Gear) then + if (Gear^.PortalCounter < 30) and WorldWrap(Gear) then begin cX:= Gear^.X; cY:= Gear^.Y; @@ -1161,7 +1235,7 @@ if ((y and LAND_HEIGHT_MASK) = 0) and ((x and LAND_WIDTH_MASK) = 0) and (Land[y, x] <> 0) then inc(Gear^.Damage); // let's interrupt before a collision to give portals a chance to catch the bullet - if (Gear^.Damage = 1) and (Gear^.Tag = 0) and (not(CheckLandValue(x, y, lfLandMask))) then + if (Gear^.Damage = 1) and (Gear^.Tag = 0) and not(CheckLandValue(x, y, lfLandMask)) then begin Gear^.Tag := 1; Gear^.Damage := 0; @@ -1188,7 +1262,7 @@ dec(Gear^.Health, Gear^.Damage); Gear^.Damage := 0 end; - if ((Gear^.State and gstDrowning) <> 0) and (Gear^.Damage < Gear^.Health) and (((not SuddenDeathDmg) and (WaterOpacity < $FF)) or (SuddenDeathDmg and (SDWaterOpacity < $FF))) then + if ((Gear^.State and gstDrowning) <> 0) and (Gear^.Damage < Gear^.Health) and ((not SuddenDeathDmg and (WaterOpacity < $FF)) or (SuddenDeathDmg and (SDWaterOpacity < $FF))) then begin for i:=(Gear^.Health - Gear^.Damage) * 4 downto 0 do begin @@ -1374,7 +1448,7 @@ Gear^.X := Gear^.X + Gear^.dX; Gear^.Y := Gear^.Y + _1_9; end; - SetAllHHToActive(true); + SetAllHHToActive; end; if TestCollisionYwithGear(Gear, 1) <> 0 then begin @@ -1649,12 +1723,14 @@ //////////////////////////////////////////////////////////////////////////////// procedure doStepSMine(Gear: PGear); + var land: Word; begin // TODO: do real calculation? - if TestCollisionXwithGear(Gear, 2) - or (TestCollisionYwithGear(Gear, -2) <> 0) - or TestCollisionXwithGear(Gear, -2) - or (TestCollisionYwithGear(Gear, 2) <> 0) then + land:= TestCollisionXwithGear(Gear, 2); + if land = 0 then land:= TestCollisionYwithGear(Gear,-2); + if land = 0 then land:= TestCollisionXwithGear(Gear,-2); + if land = 0 then land:= TestCollisionYwithGear(Gear, 2); + if (land <> 0) and (land and lfBouncy = 0) then begin if (not isZero(Gear^.dX)) or (not isZero(Gear^.dY)) then begin @@ -1681,24 +1757,23 @@ Gear^.State := Gear^.State or gstAttacking end else // gstAttacking <> 0 - begin + begin AllInactive := false; if Gear^.Timer = 0 then begin doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 30, Gear^.Hedgehog, EXPLAutoSound); DeleteGear(Gear); exit - end else + end + else if (Gear^.Timer and $FF) = 0 then PlaySound(sndMineTick); - - dec(Gear^.Timer); + dec(Gear^.Timer); end - end + end else // gsttmpFlag = 0 - if (TurnTimeLeft = 0) - or ((GameFlags and gfInfAttack <> 0) and (GameTicks > Gear^.FlightTime)) - or (Gear^.Hedgehog^.Gear = nil) then + if ((GameFlags and gfInfAttack = 0) and ((TurnTimeLeft = 0) or (Gear^.Hedgehog^.Gear = nil))) + or ((GameFlags and gfInfAttack <> 0) and (GameTicks > Gear^.FlightTime)) then Gear^.State := Gear^.State or gsttmpFlag; end; @@ -1731,7 +1806,7 @@ if (Gear^.dY.QWordValue = 0) and (Gear^.dY.QWordValue = 0) and (TestCollisionYwithGear(Gear, 1) = 0) then SetLittle(Gear^.dY); Gear^.State := Gear^.State or gstAnimation; - if Gear^.Health < cBarrelHealth then Gear^.State:= Gear^.State and (not gstFrozen); + if Gear^.Health < cBarrelHealth then Gear^.State:= Gear^.State and not gstFrozen; if ((Gear^.dX.QWordValue <> 0) or (Gear^.dY.QWordValue <> 0)) then @@ -1779,7 +1854,7 @@ if Gear^.dX.QWordValue = 0 then AddCI(Gear) end; *) - if (not Gear^.dY.isNegative) and (Gear^.dY < _0_001) and (TestCollisionYwithGear(Gear, 1) <> 0) then + if not Gear^.dY.isNegative and (Gear^.dY < _0_001) and (TestCollisionYwithGear(Gear, 1) <> 0) then Gear^.dY := _0; if hwAbs(Gear^.dX) < _0_001 then Gear^.dX := _0; @@ -1817,7 +1892,7 @@ Gear^.Message := Gear^.Message and (not (gmLJump or gmHJump)); exit end; - if (k = gtExplosives) and (Gear^.Health < cBarrelHealth) then Gear^.State:= Gear^.State and (not gstFrozen); + if (k = gtExplosives) and (Gear^.Health < cBarrelHealth) then Gear^.State:= Gear^.State and not gstFrozen; if ((k <> gtExplosives) and (Gear^.Damage > 0)) or ((k = gtExplosives) and (Gear^.Health<=0)) then begin @@ -1924,10 +1999,10 @@ Gear^.dY := Gear^.dY + cGravity; - if (Gear^.dY.isNegative) and (TestCollisionYwithGear(Gear, -1) <> 0) then - Gear^.dY := _0; - - Gear^.Y := Gear^.Y + Gear^.dY; + if ((not Gear^.dY.isNegative) and (TestCollisionYwithGear(Gear, 1) <> 0)) or + (Gear^.dY.isNegative and (TestCollisionYwithGear(Gear, -1) <> 0)) then + Gear^.dY := _0 + else Gear^.Y := Gear^.Y + Gear^.dY; if (not Gear^.dY.isNegative) and (Gear^.dY > _0_001) then SetAllHHToActive(false); @@ -1962,7 +2037,11 @@ procedure doStepTarget(Gear: PGear); begin if (Gear^.Timer = 0) and (Gear^.Tag = 0) then + begin PlaySound(sndWarp); + // workaround: save spawn Y for doStepCase (which is a mess atm) + Gear^.Angle:= hwRound(Gear^.Y); + end; if (Gear^.Tag = 0) and (Gear^.Timer < 1000) then inc(Gear^.Timer) @@ -2020,6 +2099,7 @@ for i:= 0 to 3 do begin + AddVisualGear(hwRound(Gear^.X) + hwSign(Gear^.dX) * (10 + 6 * i), hwRound(Gear^.Y) + 12 + Random(6), vgtDust); AmmoShove(Gear, 30, 25); Gear^.X := Gear^.X + Gear^.dX * 5 end; @@ -2041,7 +2121,7 @@ begin WorldWrap(Gear); sticky:= (Gear^.State and gsttmpFlag) <> 0; - if (not sticky) then AllInactive := false; + if not sticky then AllInactive := false; landPixel:= TestCollisionYwithGear(Gear, 1); if landPixel = 0 then @@ -2124,7 +2204,7 @@ gX := hwRound(Gear^.X); gY := hwRound(Gear^.Y); // Standard fire - if (not sticky) then + if not sticky then begin if ((GameTicks and $1) = 0) then begin @@ -2150,7 +2230,7 @@ if Gear^.Health > 0 then dec(Gear^.Health); - Gear^.Timer := 450 - Gear^.Tag * 8 + GetRandom(2) + Gear^.Timer := 450 - Gear^.Tag * 8 + LongInt(GetRandom(2)) end else begin @@ -2164,7 +2244,7 @@ end; // This one is interesting. I think I understand the purpose, but I wonder if a bit more fuzzy of kicking could be done with getrandom. - Gear^.Timer := 100 - Gear^.Tag * 3 + GetRandom(2); + Gear^.Timer := 100 - Gear^.Tag * 3 + LongInt(GetRandom(2)); if (Gear^.Damage > 3000+Gear^.Tag*1500) then Gear^.Health := 0 end @@ -2174,7 +2254,7 @@ begin gX := hwRound(Gear^.X); gY := hwRound(Gear^.Y); - if (not sticky) then + if not sticky then begin if ((GameTicks and $3) = 0) and (Random(1) = 0) then for i:= Random(2) downto 0 do @@ -2213,7 +2293,8 @@ end; HHGear^.dY := HHGear^.dY + cGravity; - if (not HHGear^.dY.isNegative) then + if Gear^.Timer > 0 then dec(Gear^.Timer); + if not (HHGear^.dY.isNegative) or (Gear^.Timer = 0) then begin HHGear^.State := HHGear^.State or gstMoving; DeleteGear(Gear); @@ -2290,7 +2371,7 @@ HHGear^.Y := HHGear^.Y + cGravity * 40; // don't drift into obstacles - if TestCollisionXwithGear(HHGear, hwSign(HHGear^.dX)) then + if TestCollisionXwithGear(HHGear, hwSign(HHGear^.dX)) <> 0 then HHGear^.X := HHGear^.X - int2hwFloat(hwSign(HHGear^.dX)); HHGear^.Y := HHGear^.Y + cGravity * 100; Gear^.X := HHGear^.X; @@ -2322,7 +2403,7 @@ AllInactive := false; Gear^.X := Gear^.X + cAirPlaneSpeed * Gear^.Tag; - if (Gear^.Health > 0) and (not (Gear^.X < Gear^.dX)) and (Gear^.X < Gear^.dX + cAirPlaneSpeed) then + if (Gear^.Health > 0)and(not (Gear^.X < Gear^.dX))and(Gear^.X < Gear^.dX + cAirPlaneSpeed) then begin dec(Gear^.Health); case Gear^.State of @@ -2390,11 +2471,9 @@ begin doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 30, Gear^.Hedgehog, EXPLAutoSound); DeleteGear(Gear); - {$IFNDEF PAS2C} with mobileRecord do if (performRumble <> nil) and (not fastUntilLag) then performRumble(kSystemSoundID_Vibrate); - {$ENDIF} exit end; if (GameTicks and $3F) = 0 then @@ -2408,6 +2487,7 @@ HHGear: PGear; x, y, tx, ty: hwFloat; rx: LongInt; + LandFlags: Word; begin AllInactive := false; @@ -2418,12 +2498,16 @@ y := HHGear^.Y; rx:= hwRound(x); + LandFlags:= 0; + if Gear^.AmmoType = amRubber then LandFlags:= lfBouncy + else if cIce then LandFlags:= lfIce; + if ((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) ))) - or (not TryPlaceOnLand(Gear^.Target.X - SpritesData[sprAmGirder].Width div 2, Gear^.Target.Y - SpritesData[sprAmGirder].Height div 2, sprAmGirder, Gear^.State, true, false)) then + 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); HHGear^.Message := HHGear^.Message and (not gmAttack); @@ -2485,9 +2569,9 @@ AllInactive := false; HHGear := Gear^.Hedgehog^.Gear; - if (not (TryPlaceOnLand(Gear^.Target.X - SpritesData[sprHHTelepMask].Width div 2, + if not TryPlaceOnLand(Gear^.Target.X - SpritesData[sprHHTelepMask].Width div 2, Gear^.Target.Y - SpritesData[sprHHTelepMask].Height div 2, - sprHHTelepMask, 0, false, false))) then + sprHHTelepMask, 0, false, false) then begin HHGear^.Message := HHGear^.Message and (not gmAttack); HHGear^.State := HHGear^.State and (not gstAttacking); @@ -2499,7 +2583,7 @@ else begin DeleteCI(HHGear); - SetAllHHToActive(true); + SetAllHHToActive; Gear^.doStep := @doStepTeleportAnim; // copy old HH position and direction to Gear (because we need them for drawing the vanishing hog) @@ -2821,7 +2905,7 @@ dmg:= dmgBase - max(hwRound(Distance(tdX, tdY)),gi^.Radius); if (dmg > 1) then dmg:= ModifyDamage(min(dmg div 2, cakeDmg), gi); if (dmg > 1) then - if (CurrentHedgehog^.Gear = gi) and (not gi^.Invulnerable) then + if (CurrentHedgehog^.Gear = gi) and ((gi^.Hedgehog^.Effects[heInvulnerable] = 0)) then gi^.State := gi^.State or gstLoser else gi^.State := gi^.State or gstWinner; @@ -3072,16 +3156,16 @@ tempColl:= Gear^.CollisionMask; Gear^.CollisionMask:= $007F; - if (TestCollisionYWithGear(Gear, hwSign(Gear^.dY)) <> 0) or TestCollisionXWithGear(Gear, hwSign(Gear^.dX)) or (GameTicks > Gear^.FlightTime) then + if (TestCollisionYWithGear(Gear, hwSign(Gear^.dY)) <> 0) or (TestCollisionXWithGear(Gear, hwSign(Gear^.dX)) <> 0) or (GameTicks > Gear^.FlightTime) then t := CheckGearsCollision(Gear) else t := nil; Gear^.CollisionMask:= tempColl; //fixes drill not exploding when touching HH bug if (Gear^.Timer = 0) or ((t <> nil) and (t^.Count <> 0)) - or ( ((Gear^.State and gsttmpFlag) = 0) and (TestCollisionYWithGear(Gear, hwSign(Gear^.dY)) = 0) and (not TestCollisionXWithGear(Gear, hwSign(Gear^.dX)))) + or ( ((Gear^.State and gsttmpFlag) = 0) and (TestCollisionYWithGear(Gear, hwSign(Gear^.dY)) = 0) and (TestCollisionXWithGear(Gear, hwSign(Gear^.dX)) = 0)) // CheckLandValue returns true if the type isn't matched - or (not (CheckLandValue(hwRound(Gear^.X), hwRound(Gear^.Y), lfIndestructible))) then + or (not CheckLandValue(hwRound(Gear^.X), hwRound(Gear^.Y), lfIndestructible)) then begin //out of time or exited ground StopSoundChan(Gear^.SoundChannel); @@ -3093,7 +3177,7 @@ exit end - else if (TestCollisionYWithGear(Gear, hwSign(Gear^.dY)) = 0) and (not (TestCollisionXWithGear(Gear, hwSign(Gear^.dX)))) then + else if (TestCollisionYWithGear(Gear, hwSign(Gear^.dY)) = 0) and (TestCollisionXWithGear(Gear, hwSign(Gear^.dX)) = 0) then begin StopSoundChan(Gear^.SoundChannel); Gear^.Tag := 1; @@ -3251,7 +3335,7 @@ dec(Gear^.Timer); fChanged := false; - if ((HHGear^.State and gstHHDriven) = 0) or (Gear^.Timer = 0) then + if (HHGear = nil) or ((HHGear^.State and gstHHDriven) = 0) or (Gear^.Timer = 0) then begin fChanged := true; if Gear^.Angle > 2048 then @@ -3296,7 +3380,7 @@ else AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtSmokeTrace); - if ((HHGear^.Message and gmAttack) <> 0) and (Gear^.Health <> 0) then + if (HHGear <> nil) and ((HHGear^.Message and gmAttack) <> 0) and (Gear^.Health <> 0) then begin HHGear^.Message := HHGear^.Message and (not gmAttack); AddGear(hwRound(Gear^.X), hwRound(Gear^.Y), gtAirBomb, 0, Gear^.dX * _0_5, Gear^.dY * @@ -3304,7 +3388,7 @@ dec(Gear^.Health) end; - if ((HHGear^.Message and gmLJump) <> 0) and ((Gear^.State and gsttmpFlag) = 0) then + if (HHGear <> nil) and ((HHGear^.Message and gmLJump) <> 0) and ((Gear^.State and gsttmpFlag) = 0) then begin Gear^.State := Gear^.State or gsttmpFlag; PauseMusic; @@ -3471,7 +3555,7 @@ Gear^.X := HHGear^.X; Gear^.Y := HHGear^.Y; - if (not isUnderWater) and hasBorder and ((HHGear^.X < _0) + if not isUnderWater and hasBorder and ((HHGear^.X < _0) or (hwRound(HHGear^.X) > LAND_WIDTH)) then HHGear^.dY.isNegative:= false; @@ -3550,7 +3634,13 @@ HHGear := Gear^.Hedgehog^.Gear; if HHGear = nil then begin - DeleteGear(Gear); + Gear^.Timer := 0; + Gear^.State := Gear^.State or gstAnimation or gstTmpFlag; + Gear^.Timer := 0; + Gear^.doStep := @doStepBirdyDisappear; + CurAmmoGear := nil; + isCursorVisible := false; + AfterAttack; exit end; @@ -3652,14 +3742,21 @@ HHGear: PGear; begin if Gear^.Timer > 0 then - dec(Gear^.Timer, 1) - else if Gear^.Hedgehog^.Gear = nil then - begin - DeleteGear(Gear); + dec(Gear^.Timer, 1); + + HHGear := Gear^.Hedgehog^.Gear; + if HHGear = nil then + begin + Gear^.Timer := 0; + Gear^.State := Gear^.State or gstAnimation or gstTmpFlag; + Gear^.Timer := 0; + Gear^.doStep := @doStepBirdyDisappear; + CurAmmoGear := nil; + isCursorVisible := false; AfterAttack; exit end; - HHGear := Gear^.Hedgehog^.Gear; + HHGear^.Message := HHGear^.Message and (not (gmUp or gmPrecise or gmLeft or gmRight)); if abs(hwRound(HHGear^.Y - Gear^.Y)) > 32 then begin @@ -3724,9 +3821,7 @@ i: LongInt; begin AllInactive := false; - {$IFNDEF PAS2C} Gear^.dX := Gear^.dX; - {$ENDIF} doStepFallingGear(Gear); // CheckGearDrowning(Gear); // already checked for in doStepFallingGear CalcRotationDirAngle(Gear); @@ -3867,18 +3962,18 @@ // won't port stuff that does not move towards the front/portal entrance if iscake then begin - if (not (((iterator^.X - Gear^.X)*ox + (iterator^.Y - Gear^.Y)*oy).isNegative)) then + if not (((iterator^.X - Gear^.X)*ox + (iterator^.Y - Gear^.Y)*oy).isNegative) then continue; end else - if (not ((Gear^.dX*ox + Gear^.dY*oy).isNegative)) then + if not ((Gear^.dX*ox + Gear^.dY*oy).isNegative) then continue; isbullet:= (iterator^.Kind in [gtShotgunShot, gtDEagleShot, gtSniperRifleShot, gtSineGunShot]); r:= int2hwFloat(iterator^.Radius); - if (not (isbullet or iscake)) then + if not (isbullet or iscake) then begin // wow! good candidate there, let's see if the distance and direction is okay! if hasdxy then @@ -3910,7 +4005,7 @@ oy := (iterator^.Y - Gear^.Y); poffs:= (Gear^.dX * ox + Gear^.dY * oy); - if (not isBullet) and poffs.isNegative then + if not isBullet and poffs.isNegative then continue; // only port bullets close to the portal @@ -3937,7 +4032,7 @@ if Gear^.Elasticity.isNegative then nx.isNegative := (not nx.isNegative) else - ny.isNegative := (not ny.isNegative); + ny.isNegative := not ny.isNegative; // calc gear offset in portal normal vector direction noffs:= (nx * ox + ny * oy); @@ -3946,7 +4041,7 @@ continue; // avoid gravity related loops of not really moving gear - if (not (iscake or isbullet)) + if not (iscake or isbullet) and (Gear^.dY.isNegative) and (conPortal^.dY.isNegative) and ((iterator^.dX.QWordValue + iterator^.dY.QWordValue) < _0_08.QWordValue) @@ -3971,7 +4066,7 @@ if conPortal^.Elasticity.isNegative then nx.isNegative := (not nx.isNegative) else - ny.isNegative := (not ny.isNegative); + ny.isNegative := not ny.isNegative; // inverse cake's normal movement direction, // as if it just walked through a hole @@ -4007,14 +4102,14 @@ iterator^.X := conPortal^.X + poffs * conPortal^.dX + noffs * nx; iterator^.Y := conPortal^.Y + poffs * conPortal^.dY + noffs * ny; - if (not hasdxy) and (not (conPortal^.dY.isNegative)) then + if not hasdxy and (not (conPortal^.dY.isNegative)) then begin iterator^.dY:= iterator^.dY + hwAbs(cGravity * (iterator^.Y - conPortal^.Y)) end; // see if the space on the exit side actually is enough - if (not (isBullet or isCake)) then + if not (isBullet or isCake) then begin // TestCollisionXwithXYShift requires a hwFloat for xShift ox.QWordValue := _1.QWordValue; @@ -4027,17 +4122,16 @@ iterator^.Radius := iterator^.Radius - 1; // check front - isCollision := TestCollisionY(iterator, sy) - or TestCollisionX(iterator, sx); - - if (not isCollision) then + isCollision := (TestCollisionY(iterator, sy) <> 0) or (TestCollisionX(iterator, sx) <> 0); + + if not isCollision then begin // check center area (with half the radius so that the // the square check won't check more pixels than we want to) iterator^.Radius := 1 + resetr div 2; rh := resetr div 4; - isCollision := TestCollisionYwithXYShift(iterator, 0, -sy * rh, sy, false) - or TestCollisionXwithXYShift(iterator, ox * rh, 0, sx, false); + isCollision := (TestCollisionYwithXYShift(iterator, 0, -sy * rh, sy, false) <> 0) + or (TestCollisionXwithXYShift(iterator, ox * rh, 0, sx, false) <> 0); end; iterator^.Radius := resetr; @@ -4082,7 +4176,7 @@ resetdy:=hwAbs(iterator^.dX*4); resetdy:= resetdy + hwPow(resetdy,3)/_6 + _3 * hwPow(resetdy,5) / _40 + _5 * hwPow(resetdy,7) / resety + resetx * hwPow(resetdy,9) / resetdx; iterator^.Angle:= hwRound(resetdy*_2048 / _PI); - if (not iterator^.dY.isNegative) then iterator^.Angle:= 2048-iterator^.Angle; + if not iterator^.dY.isNegative then iterator^.Angle:= 2048-iterator^.Angle; if iterator^.dX.isNegative then iterator^.Angle:= 4096-iterator^.Angle; end // VISUAL USE OF ANGLE ONLY @@ -4096,10 +4190,11 @@ if (CurrentHedgehog <> nil) and (CurrentHedgehog^.Gear <> nil) and (iterator = CurrentHedgehog^.Gear) and (CurAmmoGear <> nil) - and (CurAmmoGear^.Kind =gtRope) then + and (CurAmmoGear^.Kind = gtRope) + and (CurAmmoGear^.Elasticity <> _0) then CurAmmoGear^.PortalCounter:= 1; - if (not isbullet) and (iterator^.State and gstInvisible = 0) + if not isbullet and (iterator^.State and gstInvisible = 0) and (iterator^.Kind <> gtFlake) then FollowGear := iterator; @@ -4162,7 +4257,7 @@ Gear^.State := Gear^.State and (not gstMoving); if (Land[y, x] and lfBouncy <> 0) - or (not (CalcSlopeTangent(Gear, x, y, tx, ty, 255))) + or (not CalcSlopeTangent(Gear, x, y, tx, ty, 255)) or (DistanceI(tx,ty) < _12) then // reject shots at too irregular terrain begin loadNewPortalBall(Gear, true); @@ -4175,7 +4270,7 @@ Gear^.dY := -s * tx; Gear^.DirAngle := DxDy2Angle(-Gear^.dY,Gear^.dX); - if (not Gear^.dX.isNegative) then + if not Gear^.dX.isNegative then Gear^.DirAngle := 180-Gear^.DirAngle; if ((Gear^.LinkedGear = nil) @@ -4265,7 +4360,7 @@ iterator:= GearsList; while iterator <> nil do begin - if (not (iterator^.Kind in [gtPortal, gtAirAttack, gtKnife])) and ((iterator^.Hedgehog <> CurrentHedgehog) + if not (iterator^.Kind in [gtPortal, gtAirAttack, gtKnife]) and ((iterator^.Hedgehog <> CurrentHedgehog) or ((iterator^.Message and gmAllStoppable) = 0)) then begin iterator^.Active:= true; @@ -4520,11 +4615,9 @@ Gear^.dY.isNegative := not Gear^.dY.isNegative; Gear^.doStep := @doStepSineGunShotWork; - {$IFNDEF PAS2C} with mobileRecord do if (performRumble <> nil) and (not fastUntilLag) then performRumble(kSystemSoundID_Vibrate); - {$ENDIF} end; //////////////////////////////////////////////////////////////////////////////// @@ -4705,7 +4798,8 @@ Gear^.dY := Gear^.dY + cGravity / 100; if (GameTicks and $FF) = 0 then doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 20, Gear^.Hedgehog, EXPLDontDraw or EXPLNoGfx or EXPLNoDamage or EXPLDoNotTouchAny or EXPLPoisoned); - AllInactive:= false; + if Gear^.State and gstTmpFlag = 0 then + AllInactive:= false; end; //////////////////////////////////////////////////////////////////////////////// @@ -4732,7 +4826,7 @@ if (tmp^.Kind = gtHedgehog) or (tmp^.Kind = gtMine) or (tmp^.Kind = gtExplosives) then begin //tmp^.State:= tmp^.State or gstFlatened; - if not tmp^.Invulnerable then + if (tmp^.Hedgehog^.Effects[heInvulnerable] = 0) then ApplyDamage(tmp, CurrentHedgehog, tmp^.Health div 3, dsUnknown); //DrawTunnel(tmp^.X, tmp^.Y - _1, _0, _0_5, cHHRadius * 6, cHHRadius * 3); tmp2:= AddGear(hwRound(tmp^.X), hwRound(tmp^.Y), gtHammerHit, 0, _0, _0, 0); @@ -5073,7 +5167,7 @@ while t <> nil do begin if (t^.Kind = gtHedgehog) and (t^.Hedgehog^.Team^.Clan = HH^.Team^.Clan) then - t^.Invulnerable:= true; + t^.Hedgehog^.Effects[heInvulnerable]:= 1; t:= t^.NextGear; end; end; @@ -5387,7 +5481,7 @@ if (Timer = iceCollideWithGround) and ((GameTicks - Power) > groundFreezingTime) then begin - FillRoundInLand2(target.x, target.y, iceRadius, icePixel); + FillRoundInLandFT(target.x, target.y, iceRadius, icePixel); landRect.x := min(max(target.x - iceRadius, 0), LAND_WIDTH - 1); landRect.y := min(max(target.y - iceRadius, 0), LAND_HEIGHT - 1); landRect.w := min(2*iceRadius, LAND_WIDTH - landRect.x - 1); @@ -5400,7 +5494,7 @@ begin if (iter^.State and gstFrozen = 0) and ((iter^.Kind = gtExplosives) or (iter^.Kind = gtCase) or (iter^.Kind = gtMine)) and - (Distance(iter^.X-int2hwFloat(target.x),iter^.Y-int2hwFloat(target.y)) int2hwFloat(Gear^.Angle)) + (((abs(HHGear^.X.Round-Gear^.X.Round) + abs(HHGear^.Y.Round-Gear^.Y.Round) + 2) > Gear^.Angle) and + (Distance(HHGear^.X-Gear^.X,HHGear^.Y-Gear^.Y) > int2hwFloat(Gear^.Angle))) then begin hogs := GearsNear(Gear^.X, Gear^.Y, gtHedgehog, Gear^.Angle); @@ -5626,9 +5721,9 @@ begin tdX:= HHGear^.X-Gear^.X; dir:= hwSign(tdX); - if (not TestCollisionX(Gear, dir)) then + if TestCollisionX(Gear, dir) = 0 then Gear^.X:= Gear^.X + signAs(_1,tdX); - if TestCollisionXwithXYShift(Gear, signAs(_10,tdX), 0, dir) then + if TestCollisionXwithXYShift(Gear, signAs(_10,tdX), 0, dir) <> 0 then begin Gear^.dX:= SignAs(_0_15, tdX); Gear^.dY:= -_0_3; @@ -5667,9 +5762,9 @@ begin (*ox:= 0; oy:= 0; if TestCollisionYwithGear(Gear, -1) <> 0 then oy:= -1; - if TestCollisionXwithGear(Gear, 1) then ox:= 1; - if TestCollisionXwithGear(Gear, -1) then ox:= -1; - if TestCollisionYwithGear(Gear, 1) <> 0 then oy:= 1; + if TestCollisionXwithGear(Gear, 1) <> 0 then ox:= 1; + if TestCollisionXwithGear(Gear, -1) <> 0 then ox:= -1; + if TestCollisionYwithGear(Gear, 1) <> 0 then oy:= 1; if Gear^.Health > 0 then PlaySound(sndRopeAttach); @@ -5698,9 +5793,9 @@ end else if GameTicks and $3F = 0 then begin - if (TestCollisionYwithGear(Gear, -1) = 0) - and (not (TestCollisionXwithGear(Gear, 1))) - and (not (TestCollisionXwithGear(Gear, -1))) + if (TestCollisionYwithGear(Gear,-1) = 0) + and (TestCollisionXwithGear(Gear, 1) = 0) + and (TestCollisionXwithGear(Gear,-1) = 0) and (TestCollisionYwithGear(Gear, 1) = 0) then Gear^.State:= Gear^.State and (not gstCollision) or gstMoving; end end;