31 * |
31 * |
32 * Note: Gears that do not have an effect on the game but are just visual |
32 * Note: Gears that do not have an effect on the game but are just visual |
33 * effects are called "Visual Gears" and defined in the respective unit! |
33 * effects are called "Visual Gears" and defined in the respective unit! |
34 *) |
34 *) |
35 interface |
35 interface |
36 uses SDLh, uConsts, uFloat, uTypes; |
36 uses uConsts, uFloat, uTypes; |
37 |
37 |
38 procedure initModule; |
38 procedure initModule; |
39 procedure freeModule; |
39 procedure freeModule; |
40 function SpawnCustomCrateAt(x, y: LongInt; crate: TCrateType; content, cnt: Longword): PGear; |
40 function SpawnCustomCrateAt(x, y: LongInt; crate: TCrateType; content, cnt: Longword): PGear; |
41 function SpawnFakeCrateAt(x, y: LongInt; crate: TCrateType; explode: boolean; poison: boolean ): PGear; |
41 function SpawnFakeCrateAt(x, y: LongInt; crate: TCrateType; explode: boolean; poison: boolean ): PGear; |
42 function GetAmmo(Hedgehog: PHedgehog): TAmmoType; |
|
43 function GetUtility(Hedgehog: PHedgehog): TAmmoType; |
|
44 procedure HideHog(HH: PHedgehog); |
|
45 procedure ProcessGears; |
42 procedure ProcessGears; |
46 procedure EndTurnCleanup; |
43 procedure EndTurnCleanup; |
47 procedure SetAllToActive; |
|
48 procedure SetAllHHToActive(Ice: boolean); |
|
49 procedure DrawGears; |
44 procedure DrawGears; |
50 procedure FreeGearsList; |
45 procedure FreeGearsList; |
51 procedure AddMiscGears; |
46 procedure AddMiscGears; |
52 procedure AssignHHCoords; |
47 procedure AssignHHCoords; |
53 function GearByUID(uid : Longword) : PGear; |
48 function GearByUID(uid : Longword) : PGear; |
54 procedure doStepDrowningGear(Gear: PGear); |
|
55 |
|
56 implementation |
49 implementation |
57 uses uStore, uSound, uTeams, uRandom, uCollisions, uIO, uLandGraphics, {$IFDEF SDL13}uTouch,{$ENDIF} |
50 uses uStore, uSound, uTeams, uRandom, uIO, uLandGraphics, {$IFDEF SDL2}uTouch,{$ENDIF} |
58 uLocale, uAI, uAmmos, uStats, uVisualGears, uScript, GLunit, uVariables, |
51 uLocale, uAmmos, uStats, uVisualGears, uScript, uVariables, |
59 uCommands, uUtils, uTextures, uRenderUtils, uGearsRender, uCaptions, uDebug, uLandTexture, |
52 uCommands, uUtils, uTextures, uRenderUtils, uGearsRender, uCaptions, uDebug, uLandTexture, |
60 uGearsHedgehog, uGearsUtils, uGearsList, uGearsHandlers, uGearsHandlersRope; |
53 uGearsHedgehog, uGearsUtils, uGearsList, uGearsHandlersRope |
|
54 , uVisualGearsList, uGearsHandlersMess, uAI; |
61 |
55 |
62 var skipFlag: boolean; |
56 var skipFlag: boolean; |
63 |
|
64 procedure AmmoShove(Ammo: PGear; Damage, Power: LongInt); forward; |
|
65 //procedure AmmoFlameWork(Ammo: PGear); forward; |
|
66 function GearsNear(X, Y: hwFloat; Kind: TGearType; r: LongInt): PGearArrayS; forward; |
|
67 procedure SpawnBoxOfSmth; forward; |
|
68 procedure ShotgunShot(Gear: PGear); forward; |
|
69 procedure doStepCase(Gear: PGear); forward; |
|
70 |
|
71 |
57 |
72 var delay: LongWord; |
58 var delay: LongWord; |
73 delay2: LongWord; |
59 delay2: LongWord; |
74 step: (stDelay, stChDmg, stSweep, stTurnReact, |
60 step: (stDelay, stChDmg, stSweep, stTurnReact, |
75 stAfterDelay, stChWin, stWater, stChWin2, stHealth, |
61 stAfterDelay, stChWin, stWater, stChWin2, stHealth, |
76 stSpawn, stNTurn); |
62 stSpawn, stNTurn); |
77 upd: Longword; |
|
78 snowLeft,snowRight: LongInt; |
|
79 NewTurnTick: LongWord; |
63 NewTurnTick: LongWord; |
80 //SDMusic: shortstring; |
64 //SDMusic: shortstring; |
81 |
|
82 // For better maintainability the step handlers of gears are stored in |
|
83 // separate files. |
|
84 // Note: step handlers of gears that are hedgehogs are in a different file |
|
85 // than the handlers for all other gears. |
|
86 {$INCLUDE "GSHandlers.inc"} |
|
87 |
65 |
88 function CheckNoDamage: boolean; // returns TRUE in case of no damaged hhs |
66 function CheckNoDamage: boolean; // returns TRUE in case of no damaged hhs |
89 var Gear: PGear; |
67 var Gear: PGear; |
90 dmg: LongInt; |
68 dmg: LongInt; |
91 begin |
69 begin |
667 snowLeft:= -(snowRight-LAND_WIDTH); |
618 snowLeft:= -(snowRight-LAND_WIDTH); |
668 |
619 |
669 if (not hasBorder) and ((Theme = 'Snow') or (Theme = 'Christmas')) then |
620 if (not hasBorder) and ((Theme = 'Snow') or (Theme = 'Christmas')) then |
670 for i:= vobCount * Longword(max(LAND_WIDTH,4096)) div 2048 downto 1 do |
621 for i:= vobCount * Longword(max(LAND_WIDTH,4096)) div 2048 downto 1 do |
671 AddGear(LongInt(GetRandom(snowRight - snowLeft)) + snowLeft, LAND_HEIGHT + LongInt(GetRandom(750)) - 1300, gtFlake, 0, _0, _0, 0); |
622 AddGear(LongInt(GetRandom(snowRight - snowLeft)) + snowLeft, LAND_HEIGHT + LongInt(GetRandom(750)) - 1300, gtFlake, 0, _0, _0, 0); |
672 end; |
|
673 |
|
674 |
|
675 procedure ShotgunShot(Gear: PGear); |
|
676 var t: PGear; |
|
677 dmg, r, dist: LongInt; |
|
678 dx, dy: hwFloat; |
|
679 begin |
|
680 Gear^.Radius:= cShotgunRadius; |
|
681 t:= GearsList; |
|
682 while t <> nil do |
|
683 begin |
|
684 case t^.Kind of |
|
685 gtHedgehog, |
|
686 gtMine, |
|
687 gtSMine, |
|
688 gtKnife, |
|
689 gtCase, |
|
690 gtTarget, |
|
691 gtExplosives: begin//, |
|
692 // gtStructure: begin |
|
693 //addFileLog('ShotgunShot radius: ' + inttostr(Gear^.Radius) + ', t^.Radius = ' + inttostr(t^.Radius) + ', distance = ' + inttostr(dist) + ', dmg = ' + inttostr(dmg)); |
|
694 dmg:= 0; |
|
695 r:= Gear^.Radius + t^.Radius; |
|
696 dx:= Gear^.X-t^.X; |
|
697 dx.isNegative:= false; |
|
698 dy:= Gear^.Y-t^.Y; |
|
699 dy.isNegative:= false; |
|
700 if r-hwRound(dx+dy) > 0 then |
|
701 begin |
|
702 dist:= hwRound(Distance(dx, dy)); |
|
703 dmg:= ModifyDamage(min(r - dist, 25), t); |
|
704 end; |
|
705 if dmg > 0 then |
|
706 begin |
|
707 if (not t^.Invulnerable) then |
|
708 ApplyDamage(t, Gear^.Hedgehog, dmg, dsBullet) |
|
709 else |
|
710 Gear^.State:= Gear^.State or gstWinner; |
|
711 |
|
712 DeleteCI(t); |
|
713 t^.dX:= t^.dX + Gear^.dX * dmg * _0_01 + SignAs(cHHKick, Gear^.dX); |
|
714 t^.dY:= t^.dY + Gear^.dY * dmg * _0_01; |
|
715 t^.State:= t^.State or gstMoving; |
|
716 if t^.Kind = gtKnife then t^.State:= (t^.State and (not gstCollision)); |
|
717 t^.Active:= true; |
|
718 FollowGear:= t |
|
719 end |
|
720 end; |
|
721 gtGrave: begin |
|
722 dmg:= 0; |
|
723 r:= Gear^.Radius + t^.Radius; |
|
724 dx:= Gear^.X-t^.X; |
|
725 dx.isNegative:= false; |
|
726 dy:= Gear^.Y-t^.Y; |
|
727 dy.isNegative:= false; |
|
728 if r-hwRound(dx+dy) > 0 then |
|
729 begin |
|
730 dist:= hwRound(Distance(dx, dy)); |
|
731 dmg:= ModifyDamage(min(r - dist, 25), t); |
|
732 end; |
|
733 if dmg > 0 then |
|
734 begin |
|
735 t^.dY:= - _0_1; |
|
736 t^.Active:= true |
|
737 end |
|
738 end; |
|
739 end; |
|
740 t:= t^.NextGear |
|
741 end; |
|
742 if (GameFlags and gfSolidLand) = 0 then |
|
743 DrawExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), cShotgunRadius) |
|
744 end; |
|
745 |
|
746 procedure AmmoShove(Ammo: PGear; Damage, Power: LongInt); |
|
747 var t: PGearArray; |
|
748 Gear: PGear; |
|
749 i, j, tmpDmg: LongInt; |
|
750 VGear: PVisualGear; |
|
751 begin |
|
752 t:= CheckGearsCollision(Ammo); |
|
753 // Just to avoid hogs on rope dodging fire. |
|
754 if (CurAmmoGear <> nil) and ((CurAmmoGear^.Kind = gtRope) or (CurAmmoGear^.Kind = gtJetpack) or (CurAmmoGear^.Kind = gtBirdy)) |
|
755 and (CurrentHedgehog^.Gear <> nil) and (CurrentHedgehog^.Gear^.CollisionIndex = -1) |
|
756 and (sqr(hwRound(Ammo^.X) - hwRound(CurrentHedgehog^.Gear^.X)) + sqr(hwRound(Ammo^.Y) - hwRound(CurrentHedgehog^.Gear^.Y)) <= sqr(cHHRadius + Ammo^.Radius)) then |
|
757 begin |
|
758 t^.ar[t^.Count]:= CurrentHedgehog^.Gear; |
|
759 inc(t^.Count) |
|
760 end; |
|
761 |
|
762 i:= t^.Count; |
|
763 |
|
764 if (Ammo^.Kind = gtFlame) and (i > 0) then |
|
765 Ammo^.Health:= 0; |
|
766 while i > 0 do |
|
767 begin |
|
768 dec(i); |
|
769 Gear:= t^.ar[i]; |
|
770 if ((Ammo^.Kind = gtFlame) or (Ammo^.Kind = gtBlowTorch)) and |
|
771 (Gear^.Kind = gtHedgehog) and (Gear^.Hedgehog^.Effects[heFrozen] > 255) then |
|
772 Gear^.Hedgehog^.Effects[heFrozen]:= max(255,Gear^.Hedgehog^.Effects[heFrozen]-10000); |
|
773 tmpDmg:= ModifyDamage(Damage, Gear); |
|
774 if (Gear^.State and gstNoDamage) = 0 then |
|
775 begin |
|
776 |
|
777 if (Ammo^.Kind = gtDEagleShot) or (Ammo^.Kind = gtSniperRifleShot) then |
|
778 begin |
|
779 VGear := AddVisualGear(hwround(Ammo^.X), hwround(Ammo^.Y), vgtBulletHit); |
|
780 if VGear <> nil then |
|
781 VGear^.Angle := DxDy2Angle(-Ammo^.dX, Ammo^.dY); |
|
782 end; |
|
783 |
|
784 if (Gear^.Kind = gtHedgehog) and (Ammo^.State and gsttmpFlag <> 0) and (Ammo^.Kind = gtShover) then |
|
785 Gear^.FlightTime:= 1; |
|
786 |
|
787 |
|
788 case Gear^.Kind of |
|
789 gtHedgehog, |
|
790 gtMine, |
|
791 gtSMine, |
|
792 gtKnife, |
|
793 gtTarget, |
|
794 gtCase, |
|
795 gtExplosives: //, |
|
796 //gtStructure: |
|
797 begin |
|
798 if (Ammo^.Kind = gtDrill) then |
|
799 begin |
|
800 Ammo^.Timer:= 0; |
|
801 exit; |
|
802 end; |
|
803 if (not Gear^.Invulnerable) then |
|
804 begin |
|
805 if (Ammo^.Kind = gtKnife) and (tmpDmg > 0) then |
|
806 for j:= 1 to max(1,min(3,tmpDmg div 5)) do |
|
807 begin |
|
808 VGear:= AddVisualGear(hwRound(Ammo^.X-((Ammo^.X-Gear^.X)/_2)), hwRound(Ammo^.Y-((Ammo^.Y-Gear^.Y)/_2)), vgtStraightShot); |
|
809 if VGear <> nil then |
|
810 with VGear^ do |
|
811 begin |
|
812 Tint:= $FFCC00FF; |
|
813 Angle:= random(360); |
|
814 dx:= 0.0005 * (random(100)); |
|
815 dy:= 0.0005 * (random(100)); |
|
816 if random(2) = 0 then |
|
817 dx := -dx; |
|
818 if random(2) = 0 then |
|
819 dy := -dy; |
|
820 FrameTicks:= 600+random(200); |
|
821 State:= ord(sprStar) |
|
822 end |
|
823 end; |
|
824 ApplyDamage(Gear, Ammo^.Hedgehog, tmpDmg, dsShove) |
|
825 end |
|
826 else |
|
827 Gear^.State:= Gear^.State or gstWinner; |
|
828 if (Gear^.Kind = gtExplosives) and (Ammo^.Kind = gtBlowtorch) then |
|
829 begin |
|
830 if (Ammo^.Hedgehog^.Gear <> nil) then |
|
831 Ammo^.Hedgehog^.Gear^.State:= (Ammo^.Hedgehog^.Gear^.State and (not gstNotKickable)); |
|
832 ApplyDamage(Gear, Ammo^.Hedgehog, tmpDmg * 100, dsUnknown); // crank up damage for explosives + blowtorch |
|
833 end; |
|
834 |
|
835 if (Gear^.Kind = gtHedgehog) and (Gear^.Hedgehog^.King or (Gear^.Hedgehog^.Effects[heFrozen] > 0)) then |
|
836 begin |
|
837 Gear^.dX:= Ammo^.dX * Power * _0_005; |
|
838 Gear^.dY:= Ammo^.dY * Power * _0_005 |
|
839 end |
|
840 else if ((Ammo^.Kind <> gtFlame) or (Gear^.Kind = gtHedgehog)) and (Power <> 0) then |
|
841 begin |
|
842 Gear^.dX:= Ammo^.dX * Power * _0_01; |
|
843 Gear^.dY:= Ammo^.dY * Power * _0_01 |
|
844 end; |
|
845 |
|
846 if (not isZero(Gear^.dX)) or (not isZero(Gear^.dY)) then |
|
847 begin |
|
848 Gear^.Active:= true; |
|
849 DeleteCI(Gear); |
|
850 Gear^.State:= Gear^.State or gstMoving; |
|
851 if Gear^.Kind = gtKnife then Gear^.State:= (Gear^.State and (not gstCollision)); |
|
852 // move the gear upwards a bit to throw it over tiny obstacles at start |
|
853 if TestCollisionXwithGear(Gear, hwSign(Gear^.dX)) then |
|
854 begin |
|
855 if (not (TestCollisionXwithXYShift(Gear, _0, -3, hwSign(Gear^.dX))) |
|
856 or (TestCollisionYwithGear(Gear, -1) <> 0)) then |
|
857 Gear^.Y:= Gear^.Y - _1; |
|
858 if (not (TestCollisionXwithXYShift(Gear, _0, -2, hwSign(Gear^.dX))) |
|
859 or (TestCollisionYwithGear(Gear, -1) <> 0)) then |
|
860 Gear^.Y:= Gear^.Y - _1; |
|
861 if (not (TestCollisionXwithXYShift(Gear, _0, -1, hwSign(Gear^.dX))) |
|
862 or (TestCollisionYwithGear(Gear, -1) <> 0)) then |
|
863 Gear^.Y:= Gear^.Y - _1; |
|
864 end |
|
865 end; |
|
866 |
|
867 |
|
868 if (Ammo^.Kind <> gtFlame) or ((Ammo^.State and gsttmpFlag) = 0) then |
|
869 FollowGear:= Gear |
|
870 end; |
|
871 end |
|
872 end; |
|
873 end; |
|
874 if i <> 0 then |
|
875 SetAllToActive |
|
876 end; |
623 end; |
877 |
624 |
878 procedure AssignHHCoords; |
625 procedure AssignHHCoords; |
879 var i, t, p, j: LongInt; |
626 var i, t, p, j: LongInt; |
880 ar: array[0..Pred(cMaxHHs)] of PHedgehog; |
627 ar: array[0..Pred(cMaxHHs)] of PHedgehog; |
1069 |
776 |
1070 if ( (x = 0) and (y = 0) ) then |
777 if ( (x = 0) and (y = 0) ) then |
1071 FindPlace(FollowGear, true, 0, LAND_WIDTH); |
778 FindPlace(FollowGear, true, 0, LAND_WIDTH); |
1072 |
779 |
1073 SpawnFakeCrateAt := FollowGear; |
780 SpawnFakeCrateAt := FollowGear; |
1074 end; |
|
1075 |
|
1076 function GetAmmo(Hedgehog: PHedgehog): TAmmoType; |
|
1077 var t, aTot: LongInt; |
|
1078 i: TAmmoType; |
|
1079 begin |
|
1080 Hedgehog:= Hedgehog; // avoid hint |
|
1081 |
|
1082 aTot:= 0; |
|
1083 for i:= Low(TAmmoType) to High(TAmmoType) do |
|
1084 if (Ammoz[i].Ammo.Propz and ammoprop_Utility) = 0 then |
|
1085 inc(aTot, Ammoz[i].Probability); |
|
1086 |
|
1087 t:= aTot; |
|
1088 i:= Low(TAmmoType); |
|
1089 if (t > 0) then |
|
1090 begin |
|
1091 t:= GetRandom(t); |
|
1092 while t >= 0 do |
|
1093 begin |
|
1094 inc(i); |
|
1095 if (Ammoz[i].Ammo.Propz and ammoprop_Utility) = 0 then |
|
1096 dec(t, Ammoz[i].Probability) |
|
1097 end |
|
1098 end; |
|
1099 GetAmmo:= i |
|
1100 end; |
|
1101 |
|
1102 function GetUtility(Hedgehog: PHedgehog): TAmmoType; |
|
1103 var t, uTot: LongInt; |
|
1104 i: TAmmoType; |
|
1105 begin |
|
1106 |
|
1107 uTot:= 0; |
|
1108 for i:= Low(TAmmoType) to High(TAmmoType) do |
|
1109 if ((Ammoz[i].Ammo.Propz and ammoprop_Utility) <> 0) |
|
1110 and ((Hedgehog^.Team^.HedgehogsNumber > 1) or (Ammoz[i].Ammo.AmmoType <> amSwitch)) then |
|
1111 inc(uTot, Ammoz[i].Probability); |
|
1112 |
|
1113 t:= uTot; |
|
1114 i:= Low(TAmmoType); |
|
1115 if (t > 0) then |
|
1116 begin |
|
1117 t:= GetRandom(t); |
|
1118 while t >= 0 do |
|
1119 begin |
|
1120 inc(i); |
|
1121 if ((Ammoz[i].Ammo.Propz and ammoprop_Utility) <> 0) and ((Hedgehog^.Team^.HedgehogsNumber > 1) |
|
1122 or (Ammoz[i].Ammo.AmmoType <> amSwitch)) then |
|
1123 dec(t, Ammoz[i].Probability) |
|
1124 end |
|
1125 end; |
|
1126 GetUtility:= i |
|
1127 end; |
|
1128 |
|
1129 |
|
1130 |
|
1131 procedure SpawnBoxOfSmth; |
|
1132 var t, aTot, uTot, a, h: LongInt; |
|
1133 i: TAmmoType; |
|
1134 begin |
|
1135 if (PlacingHogs) or |
|
1136 (cCaseFactor = 0) |
|
1137 or (CountGears(gtCase) >= 5) |
|
1138 or (GetRandom(cCaseFactor) <> 0) then |
|
1139 exit; |
|
1140 |
|
1141 FollowGear:= nil; |
|
1142 aTot:= 0; |
|
1143 uTot:= 0; |
|
1144 for i:= Low(TAmmoType) to High(TAmmoType) do |
|
1145 if (Ammoz[i].Ammo.Propz and ammoprop_Utility) = 0 then |
|
1146 inc(aTot, Ammoz[i].Probability) |
|
1147 else |
|
1148 inc(uTot, Ammoz[i].Probability); |
|
1149 |
|
1150 t:=0; |
|
1151 a:=aTot; |
|
1152 h:= 1; |
|
1153 |
|
1154 if (aTot+uTot) <> 0 then |
|
1155 if ((GameFlags and gfInvulnerable) = 0) then |
|
1156 begin |
|
1157 h:= cHealthCaseProb * 100; |
|
1158 t:= GetRandom(10000); |
|
1159 a:= (10000-h)*aTot div (aTot+uTot) |
|
1160 end |
|
1161 else |
|
1162 begin |
|
1163 t:= GetRandom(aTot+uTot); |
|
1164 h:= 0 |
|
1165 end; |
|
1166 |
|
1167 |
|
1168 if t<h then |
|
1169 begin |
|
1170 FollowGear:= AddGear(0, 0, gtCase, 0, _0, _0, 0); |
|
1171 FollowGear^.Health:= cHealthCaseAmount; |
|
1172 FollowGear^.Pos:= posCaseHealth; |
|
1173 AddCaption(GetEventString(eidNewHealthPack), cWhiteColor, capgrpAmmoInfo); |
|
1174 end |
|
1175 else if (t<a+h) then |
|
1176 begin |
|
1177 t:= aTot; |
|
1178 if (t > 0) then |
|
1179 begin |
|
1180 FollowGear:= AddGear(0, 0, gtCase, 0, _0, _0, 0); |
|
1181 t:= GetRandom(t); |
|
1182 i:= Low(TAmmoType); |
|
1183 FollowGear^.Pos:= posCaseAmmo; |
|
1184 FollowGear^.AmmoType:= i; |
|
1185 AddCaption(GetEventString(eidNewAmmoPack), cWhiteColor, capgrpAmmoInfo); |
|
1186 end |
|
1187 end |
|
1188 else |
|
1189 begin |
|
1190 t:= uTot; |
|
1191 if (t > 0) then |
|
1192 begin |
|
1193 FollowGear:= AddGear(0, 0, gtCase, 0, _0, _0, 0); |
|
1194 t:= GetRandom(t); |
|
1195 i:= Low(TAmmoType); |
|
1196 FollowGear^.Pos:= posCaseUtility; |
|
1197 FollowGear^.AmmoType:= i; |
|
1198 AddCaption(GetEventString(eidNewUtilityPack), cWhiteColor, capgrpAmmoInfo); |
|
1199 end |
|
1200 end; |
|
1201 |
|
1202 // handles case of no ammo or utility crates - considered also placing booleans in uAmmos and altering probabilities |
|
1203 if (FollowGear <> nil) then |
|
1204 begin |
|
1205 FindPlace(FollowGear, true, 0, LAND_WIDTH); |
|
1206 |
|
1207 if (FollowGear <> nil) then |
|
1208 AddVoice(sndReinforce, CurrentTeam^.voicepack) |
|
1209 end |
|
1210 end; |
781 end; |
1211 |
782 |
1212 |
783 |
1213 function GearByUID(uid : Longword) : PGear; |
784 function GearByUID(uid : Longword) : PGear; |
1214 var gear: PGear; |
785 var gear: PGear; |