22 * Important: Since gears change the course of the game, calculations that |
22 * Important: Since gears change the course of the game, calculations that |
23 * lead to different results for different clients/players/machines |
23 * lead to different results for different clients/players/machines |
24 * should NOT occur! |
24 * should NOT occur! |
25 * Use safe functions and data types! (e.g. GetRandom() and hwFloat) |
25 * Use safe functions and data types! (e.g. GetRandom() and hwFloat) |
26 *) |
26 *) |
27 |
27 |
28 {$INCLUDE "options.inc"} |
28 {$INCLUDE "options.inc"} |
29 |
29 |
30 unit uGearsHandlersMess; |
30 unit uGearsHandlersMess; |
31 interface |
31 interface |
32 uses uTypes, uFloat; |
32 uses uTypes, uFloat; |
392 begin |
392 begin |
393 xland:= TestCollisionXwithGear(Gear, -hwSign(Gear^.dX)); |
393 xland:= TestCollisionXwithGear(Gear, -hwSign(Gear^.dX)); |
394 if xland <> 0 then collH := -hwSign(Gear^.dX) |
394 if xland <> 0 then collH := -hwSign(Gear^.dX) |
395 end; |
395 end; |
396 //if Gear^.AdvBounce and (collV <>0) and (collH <> 0) and (hwSqr(tdX) + hwSqr(tdY) > _0_08) then |
396 //if Gear^.AdvBounce and (collV <>0) and (collH <> 0) and (hwSqr(tdX) + hwSqr(tdY) > _0_08) then |
397 if (collV <> 0) and (collH <> 0) and |
397 if (collV <> 0) and (collH <> 0) and |
398 (((Gear^.AdvBounce=1) and ((collV=-1) or ((tdX.QWordValue + tdY.QWordValue) > _0_2.QWordValue)))) then |
398 (((Gear^.AdvBounce=1) and ((collV=-1) or ((tdX.QWordValue + tdY.QWordValue) > _0_2.QWordValue)))) then |
399 //or ((xland or land) and lfBouncy <> 0)) then |
399 //or ((xland or land) and lfBouncy <> 0)) then |
400 begin |
400 begin |
401 if (xland or land) and lfBouncy = 0 then |
401 if (xland or land) and lfBouncy = 0 then |
402 begin |
402 begin |
434 else |
434 else |
435 Gear^.State := Gear^.State or gstMoving; |
435 Gear^.State := Gear^.State or gstMoving; |
436 |
436 |
437 if ((xland or land) and lfBouncy <> 0) and (Gear^.dX.QWordValue < _0_15.QWordValue) and (Gear^.dY.QWordValue < _0_15.QWordValue) then |
437 if ((xland or land) and lfBouncy <> 0) and (Gear^.dX.QWordValue < _0_15.QWordValue) and (Gear^.dY.QWordValue < _0_15.QWordValue) then |
438 Gear^.State := Gear^.State or gstCollision; |
438 Gear^.State := Gear^.State or gstCollision; |
439 |
439 |
440 if ((xland or land) and lfBouncy <> 0) and (Gear^.Radius >= 3) and |
440 if ((xland or land) and lfBouncy <> 0) and (Gear^.Radius >= 3) and |
441 ((Gear^.dX.QWordValue > _0_15.QWordValue) or (Gear^.dY.QWordValue > _0_15.QWordValue)) then |
441 ((Gear^.dX.QWordValue > _0_15.QWordValue) or (Gear^.dY.QWordValue > _0_15.QWordValue)) then |
442 begin |
442 begin |
443 boing:= AddVisualGear(gX, gY, vgtStraightShot, 0, false, 1); |
443 boing:= AddVisualGear(gX, gY, vgtStraightShot, 0, false, 1); |
444 if boing <> nil then |
444 if boing <> nil then |
758 draw:= true; |
758 draw:= true; |
759 xx:= hwRound(Gear^.X); |
759 xx:= hwRound(Gear^.X); |
760 yy:= hwRound(Gear^.Y); |
760 yy:= hwRound(Gear^.Y); |
761 if draw and (WorldEdge = weWrap) and ((xx < LongInt(leftX) + 3) or (xx > LongInt(rightX) - 3)) then |
761 if draw and (WorldEdge = weWrap) and ((xx < LongInt(leftX) + 3) or (xx > LongInt(rightX) - 3)) then |
762 begin |
762 begin |
763 if xx < LongInt(leftX) + 3 then |
763 if xx < LongInt(leftX) + 3 then |
764 xx:= rightX-3 |
764 xx:= rightX-3 |
765 else xx:= leftX+3; |
765 else xx:= leftX+3; |
766 Gear^.X:= int2hwFloat(xx) |
766 Gear^.X:= int2hwFloat(xx) |
767 end |
767 end |
768 end |
768 end |
1052 if Gear^.Timer = 0 then |
1052 if Gear^.Timer = 0 then |
1053 begin |
1053 begin |
1054 // no need to display remaining time anymore |
1054 // no need to display remaining time anymore |
1055 Gear^.RenderTimer:= false; |
1055 Gear^.RenderTimer:= false; |
1056 // bee can drown when timer reached 0 |
1056 // bee can drown when timer reached 0 |
1057 Gear^.State:= Gear^.State and not gstSubmersible; |
1057 Gear^.State:= Gear^.State and (not gstSubmersible); |
1058 end; |
1058 end; |
1059 end; |
1059 end; |
1060 end; |
1060 end; |
1061 |
1061 |
1062 procedure doStepBee(Gear: PGear); |
1062 procedure doStepBee(Gear: PGear); |
1233 y := hwRound(Gear^.Y); |
1233 y := hwRound(Gear^.Y); |
1234 |
1234 |
1235 if ((y and LAND_HEIGHT_MASK) = 0) and ((x and LAND_WIDTH_MASK) = 0) and (Land[y, x] <> 0) then |
1235 if ((y and LAND_HEIGHT_MASK) = 0) and ((x and LAND_WIDTH_MASK) = 0) and (Land[y, x] <> 0) then |
1236 inc(Gear^.Damage); |
1236 inc(Gear^.Damage); |
1237 // let's interrupt before a collision to give portals a chance to catch the bullet |
1237 // let's interrupt before a collision to give portals a chance to catch the bullet |
1238 if (Gear^.Damage = 1) and (Gear^.Tag = 0) and not(CheckLandValue(x, y, lfLandMask)) then |
1238 if (Gear^.Damage = 1) and (Gear^.Tag = 0) and (not CheckLandValue(x, y, lfLandMask)) then |
1239 begin |
1239 begin |
1240 Gear^.Tag := 1; |
1240 Gear^.Tag := 1; |
1241 Gear^.Damage := 0; |
1241 Gear^.Damage := 0; |
1242 Gear^.X := Gear^.X - Gear^.dX; |
1242 Gear^.X := Gear^.X - Gear^.dX; |
1243 Gear^.Y := Gear^.Y - Gear^.dY; |
1243 Gear^.Y := Gear^.Y - Gear^.dY; |
1770 PlaySound(sndMineTick); |
1770 PlaySound(sndMineTick); |
1771 dec(Gear^.Timer); |
1771 dec(Gear^.Timer); |
1772 end |
1772 end |
1773 end |
1773 end |
1774 else // gsttmpFlag = 0 |
1774 else // gsttmpFlag = 0 |
1775 if ((GameFlags and gfInfAttack = 0) and ((TurnTimeLeft = 0) or (Gear^.Hedgehog^.Gear = nil))) |
1775 if ((GameFlags and gfInfAttack = 0) and ((TurnTimeLeft = 0) or (Gear^.Hedgehog^.Gear = nil))) |
1776 or ((GameFlags and gfInfAttack <> 0) and (GameTicks > Gear^.FlightTime)) then |
1776 or ((GameFlags and gfInfAttack <> 0) and (GameTicks > Gear^.FlightTime)) then |
1777 Gear^.State := Gear^.State or gsttmpFlag; |
1777 Gear^.State := Gear^.State or gsttmpFlag; |
1778 end; |
1778 end; |
1779 |
1779 |
1780 //////////////////////////////////////////////////////////////////////////////// |
1780 //////////////////////////////////////////////////////////////////////////////// |
1804 dxdy: hwFloat; |
1804 dxdy: hwFloat; |
1805 begin |
1805 begin |
1806 if (Gear^.dY.QWordValue = 0) and (Gear^.dY.QWordValue = 0) and (TestCollisionYwithGear(Gear, 1) = 0) then |
1806 if (Gear^.dY.QWordValue = 0) and (Gear^.dY.QWordValue = 0) and (TestCollisionYwithGear(Gear, 1) = 0) then |
1807 SetLittle(Gear^.dY); |
1807 SetLittle(Gear^.dY); |
1808 Gear^.State := Gear^.State or gstAnimation; |
1808 Gear^.State := Gear^.State or gstAnimation; |
1809 if Gear^.Health < cBarrelHealth then Gear^.State:= Gear^.State and not gstFrozen; |
1809 if Gear^.Health < cBarrelHealth then Gear^.State:= Gear^.State and (not gstFrozen); |
1810 |
1810 |
1811 if ((Gear^.dX.QWordValue <> 0) |
1811 if ((Gear^.dX.QWordValue <> 0) |
1812 or (Gear^.dY.QWordValue <> 0)) then |
1812 or (Gear^.dY.QWordValue <> 0)) then |
1813 begin |
1813 begin |
1814 DeleteCI(Gear); |
1814 DeleteCI(Gear); |
1890 with CurrentHedgehog^ do |
1890 with CurrentHedgehog^ do |
1891 if Gear <> nil then |
1891 if Gear <> nil then |
1892 Gear^.Message := Gear^.Message and (not (gmLJump or gmHJump)); |
1892 Gear^.Message := Gear^.Message and (not (gmLJump or gmHJump)); |
1893 exit |
1893 exit |
1894 end; |
1894 end; |
1895 if (k = gtExplosives) and (Gear^.Health < cBarrelHealth) then Gear^.State:= Gear^.State and not gstFrozen; |
1895 if (k = gtExplosives) and (Gear^.Health < cBarrelHealth) then Gear^.State:= Gear^.State and (not gstFrozen); |
1896 |
1896 |
1897 if ((k <> gtExplosives) and (Gear^.Damage > 0)) or ((k = gtExplosives) and (Gear^.Health<=0)) then |
1897 if ((k <> gtExplosives) and (Gear^.Damage > 0)) or ((k = gtExplosives) and (Gear^.Health<=0)) then |
1898 begin |
1898 begin |
1899 x := hwRound(Gear^.X); |
1899 x := hwRound(Gear^.X); |
1900 y := hwRound(Gear^.Y); |
1900 y := hwRound(Gear^.Y); |
2469 doStepFallingGear(Gear); |
2469 doStepFallingGear(Gear); |
2470 if (Gear^.State and gstCollision) <> 0 then |
2470 if (Gear^.State and gstCollision) <> 0 then |
2471 begin |
2471 begin |
2472 doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 30, Gear^.Hedgehog, EXPLAutoSound); |
2472 doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 30, Gear^.Hedgehog, EXPLAutoSound); |
2473 DeleteGear(Gear); |
2473 DeleteGear(Gear); |
|
2474 {$IFNDEF PAS2C} |
2474 with mobileRecord do |
2475 with mobileRecord do |
2475 if (performRumble <> nil) and (not fastUntilLag) then |
2476 if (performRumble <> nil) and (not fastUntilLag) then |
2476 performRumble(kSystemSoundID_Vibrate); |
2477 performRumble(kSystemSoundID_Vibrate); |
|
2478 {$ENDIF} |
2477 exit |
2479 exit |
2478 end; |
2480 end; |
2479 if (GameTicks and $3F) = 0 then |
2481 if (GameTicks and $3F) = 0 then |
2480 AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtSmokeTrace) |
2482 AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtSmokeTrace) |
2481 end; |
2483 end; |
2500 |
2502 |
2501 LandFlags:= 0; |
2503 LandFlags:= 0; |
2502 if Gear^.AmmoType = amRubber then LandFlags:= lfBouncy |
2504 if Gear^.AmmoType = amRubber then LandFlags:= lfBouncy |
2503 else if cIce then LandFlags:= lfIce; |
2505 else if cIce then LandFlags:= lfIce; |
2504 |
2506 |
2505 if ((Distance(tx - x, ty - y) > _256) and ((WorldEdge <> weWrap) or |
2507 if ((Distance(tx - x, ty - y) > _256) and ((WorldEdge <> weWrap) or |
2506 ( |
2508 ( |
2507 (Distance(tx - int2hwFloat(rightX+(rx-leftX)), ty - y) > _256) and |
2509 (Distance(tx - int2hwFloat(rightX+(rx-leftX)), ty - y) > _256) and |
2508 (Distance(tx - int2hwFloat(leftX-(rightX-rx)), ty - y) > _256) |
2510 (Distance(tx - int2hwFloat(leftX-(rightX-rx)), ty - y) > _256) |
2509 ))) |
2511 ))) |
2510 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 |
2512 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 |
4613 AmmoShove(Gear, 0, 80); |
4615 AmmoShove(Gear, 0, 80); |
4614 Gear^.dX.isNegative := not Gear^.dX.isNegative; |
4616 Gear^.dX.isNegative := not Gear^.dX.isNegative; |
4615 Gear^.dY.isNegative := not Gear^.dY.isNegative; |
4617 Gear^.dY.isNegative := not Gear^.dY.isNegative; |
4616 |
4618 |
4617 Gear^.doStep := @doStepSineGunShotWork; |
4619 Gear^.doStep := @doStepSineGunShotWork; |
|
4620 {$IFNDEF PAS2C} |
4618 with mobileRecord do |
4621 with mobileRecord do |
4619 if (performRumble <> nil) and (not fastUntilLag) then |
4622 if (performRumble <> nil) and (not fastUntilLag) then |
4620 performRumble(kSystemSoundID_Vibrate); |
4623 performRumble(kSystemSoundID_Vibrate); |
|
4624 {$ENDIF} |
4621 end; |
4625 end; |
4622 |
4626 |
4623 //////////////////////////////////////////////////////////////////////////////// |
4627 //////////////////////////////////////////////////////////////////////////////// |
4624 procedure doStepFlamethrowerWork(Gear: PGear); |
4628 procedure doStepFlamethrowerWork(Gear: PGear); |
4625 var |
4629 var |
5378 begin |
5382 begin |
5379 StopSoundChan(Gear^.SoundChannel); |
5383 StopSoundChan(Gear^.SoundChannel); |
5380 Gear^.SoundChannel:= -1; |
5384 Gear^.SoundChannel:= -1; |
5381 if GameTicks mod 40 = 0 then dec(Gear^.Health) |
5385 if GameTicks mod 40 = 0 then dec(Gear^.Health) |
5382 end |
5386 end |
5383 else |
5387 else |
5384 begin |
5388 begin |
5385 if Gear^.SoundChannel = -1 then |
5389 if Gear^.SoundChannel = -1 then |
5386 Gear^.SoundChannel := LoopSound(sndIceBeam); |
5390 Gear^.SoundChannel := LoopSound(sndIceBeam); |
5387 if GameTicks mod 10 = 0 then dec(Gear^.Health) |
5391 if GameTicks mod 10 = 0 then dec(Gear^.Health) |
5388 end |
5392 end |
5485 landRect.x := min(max(target.x - iceRadius, 0), LAND_WIDTH - 1); |
5489 landRect.x := min(max(target.x - iceRadius, 0), LAND_WIDTH - 1); |
5486 landRect.y := min(max(target.y - iceRadius, 0), LAND_HEIGHT - 1); |
5490 landRect.y := min(max(target.y - iceRadius, 0), LAND_HEIGHT - 1); |
5487 landRect.w := min(2*iceRadius, LAND_WIDTH - landRect.x - 1); |
5491 landRect.w := min(2*iceRadius, LAND_WIDTH - landRect.x - 1); |
5488 landRect.h := min(2*iceRadius, LAND_HEIGHT - landRect.y - 1); |
5492 landRect.h := min(2*iceRadius, LAND_HEIGHT - landRect.y - 1); |
5489 UpdateLandTexture(landRect.x, landRect.w, landRect.y, landRect.h, true); |
5493 UpdateLandTexture(landRect.x, landRect.w, landRect.y, landRect.h, true); |
5490 |
5494 |
5491 // Freeze nearby mines/explosives/cases too |
5495 // Freeze nearby mines/explosives/cases too |
5492 iter := GearsList; |
5496 iter := GearsList; |
5493 while iter <> nil do |
5497 while iter <> nil do |
5494 begin |
5498 begin |
5495 if (iter^.State and gstFrozen = 0) and |
5499 if (iter^.State and gstFrozen = 0) and |
5496 ((iter^.Kind = gtExplosives) or (iter^.Kind = gtCase) or (iter^.Kind = gtMine)) and |
5500 ((iter^.Kind = gtExplosives) or (iter^.Kind = gtCase) or (iter^.Kind = gtMine)) and |
5497 (abs(iter^.X.Round-target.x)+abs(iter^.Y.Round-target.y)+2<2*iceRadius) and (Distance(iter^.X-int2hwFloat(target.x),iter^.Y-int2hwFloat(target.y))<int2hwFloat(iceRadius*2)) then |
5501 (abs(LongInt(iter^.X.Round) - target.x) + abs(LongInt(iter^.Y.Round) - target.y) + 2 < 2 * iceRadius) |
|
5502 and (Distance(iter^.X - int2hwFloat(target.x), iter^.Y - int2hwFloat(target.y)) < int2hwFloat(iceRadius * 2)) then |
5498 begin |
5503 begin |
5499 for t:= 0 to 5 do |
5504 for t:= 0 to 5 do |
5500 begin |
5505 begin |
5501 vg:= AddVisualGear(hwRound(iter^.X)+random(4)-8, hwRound(iter^.Y)+random(8), vgtDust, 1); |
5506 vg:= AddVisualGear(hwRound(iter^.X)+random(4)-8, hwRound(iter^.Y)+random(8), vgtDust, 1); |
5502 if vg <> nil then |
5507 if vg <> nil then |
5619 gi := GearsList; |
5624 gi := GearsList; |
5620 while gi <> nil do |
5625 while gi <> nil do |
5621 begin |
5626 begin |
5622 with gi^ do CheckSum:= CheckSum xor X.round xor X.frac xor dX.round xor dX.frac xor Y.round xor Y.frac xor dY.round xor dY.frac; |
5627 with gi^ do CheckSum:= CheckSum xor X.round xor X.frac xor dX.round xor dX.frac xor Y.round xor Y.frac xor dY.round xor dY.frac; |
5623 AddRandomness(CheckSum); |
5628 AddRandomness(CheckSum); |
5624 if gi^.Kind = gtGenericFaller then gi^.State:= gi^.State and not gstTmpFlag; |
5629 if gi^.Kind = gtGenericFaller then gi^.State:= gi^.State and (not gstTmpFlag); |
5625 gi := gi^.NextGear |
5630 gi := gi^.NextGear |
5626 end; |
5631 end; |
5627 AddPickup(Gear^.Hedgehog^, a, Gear^.Power, hwRound(Gear^.X), hwRound(Gear^.Y)); |
5632 AddPickup(Gear^.Hedgehog^, a, Gear^.Power, hwRound(Gear^.X), hwRound(Gear^.Y)); |
5628 DeleteGear(Gear) |
5633 DeleteGear(Gear) |
5629 end; |
5634 end; |