39 function CheckGearNear(Gear: PGear; Kind: TGearType; rX, rY: LongInt): PGear; |
39 function CheckGearNear(Gear: PGear; Kind: TGearType; rX, rY: LongInt): PGear; |
40 function CheckGearDrowning(var Gear: PGear): boolean; |
40 function CheckGearDrowning(var Gear: PGear): boolean; |
41 procedure CheckCollision(Gear: PGear); inline; |
41 procedure CheckCollision(Gear: PGear); inline; |
42 procedure CheckCollisionWithLand(Gear: PGear); inline; |
42 procedure CheckCollisionWithLand(Gear: PGear); inline; |
43 |
43 |
|
44 procedure AmmoShove(Ammo: PGear; Damage, Power: LongInt); |
|
45 function GearsNear(X, Y: hwFloat; Kind: TGearType; r: LongInt): PGearArrayS; |
|
46 procedure SpawnBoxOfSmth; |
|
47 procedure ShotgunShot(Gear: PGear); |
|
48 |
|
49 procedure SetAllToActive; |
|
50 procedure SetAllHHToActive; inline; |
|
51 procedure SetAllHHToActive(Ice: boolean); |
|
52 |
|
53 function GetAmmo(Hedgehog: PHedgehog): TAmmoType; |
|
54 function GetUtility(Hedgehog: PHedgehog): TAmmoType; |
|
55 |
|
56 |
|
57 |
44 function MakeHedgehogsStep(Gear: PGear) : boolean; |
58 function MakeHedgehogsStep(Gear: PGear) : boolean; |
45 |
59 |
46 var doStepHandlers: array[TGearType] of TGearStepProcedure; |
60 var doStepHandlers: array[TGearType] of TGearStepProcedure; |
47 |
61 |
48 |
62 |
49 implementation |
63 implementation |
50 uses uFloat, uSound, uCollisions, uUtils, uConsts, uVisualGears, uAIMisc, |
64 uses uSound, uCollisions, uUtils, uConsts, uVisualGears, uAIMisc, |
51 uVariables, uLandGraphics, uScript, uStats, uCaptions, uTeams, uStore, |
65 uVariables, uLandGraphics, uScript, uStats, uCaptions, uTeams, uStore, |
52 uLocale, uTextures, uRenderUtils, uRandom, SDLh, uDebug, uGears, |
66 uLocale, uTextures, uRenderUtils, uRandom, SDLh, uDebug, |
53 uGearsList, Math, uVisualGearsList; |
67 uGearsList, Math, uVisualGearsList, uGearsHandlersMess, |
|
68 uGearsHedgehog; |
54 |
69 |
55 procedure doMakeExplosion(X, Y, Radius: LongInt; AttackingHog: PHedgehog; Mask: Longword); inline; |
70 procedure doMakeExplosion(X, Y, Radius: LongInt; AttackingHog: PHedgehog; Mask: Longword); inline; |
56 begin |
71 begin |
57 doMakeExplosion(X, Y, Radius, AttackingHog, Mask, $FFFFFFFF); |
72 doMakeExplosion(X, Y, Radius, AttackingHog, Mask, $FFFFFFFF); |
58 end; |
73 end; |
764 end |
779 end |
765 end |
780 end |
766 end; |
781 end; |
767 end; |
782 end; |
768 |
783 |
|
784 |
|
785 procedure ShotgunShot(Gear: PGear); |
|
786 var t: PGear; |
|
787 dmg, r, dist: LongInt; |
|
788 dx, dy: hwFloat; |
|
789 begin |
|
790 Gear^.Radius:= cShotgunRadius; |
|
791 t:= GearsList; |
|
792 while t <> nil do |
|
793 begin |
|
794 case t^.Kind of |
|
795 gtHedgehog, |
|
796 gtMine, |
|
797 gtSMine, |
|
798 gtKnife, |
|
799 gtCase, |
|
800 gtTarget, |
|
801 gtExplosives: begin//, |
|
802 // gtStructure: begin |
|
803 //addFileLog('ShotgunShot radius: ' + inttostr(Gear^.Radius) + ', t^.Radius = ' + inttostr(t^.Radius) + ', distance = ' + inttostr(dist) + ', dmg = ' + inttostr(dmg)); |
|
804 dmg:= 0; |
|
805 r:= Gear^.Radius + t^.Radius; |
|
806 dx:= Gear^.X-t^.X; |
|
807 dx.isNegative:= false; |
|
808 dy:= Gear^.Y-t^.Y; |
|
809 dy.isNegative:= false; |
|
810 if r-hwRound(dx+dy) > 0 then |
|
811 begin |
|
812 dist:= hwRound(Distance(dx, dy)); |
|
813 dmg:= ModifyDamage(min(r - dist, 25), t); |
|
814 end; |
|
815 if dmg > 0 then |
|
816 begin |
|
817 if (not t^.Invulnerable) then |
|
818 ApplyDamage(t, Gear^.Hedgehog, dmg, dsBullet) |
|
819 else |
|
820 Gear^.State:= Gear^.State or gstWinner; |
|
821 |
|
822 DeleteCI(t); |
|
823 t^.dX:= t^.dX + Gear^.dX * dmg * _0_01 + SignAs(cHHKick, Gear^.dX); |
|
824 t^.dY:= t^.dY + Gear^.dY * dmg * _0_01; |
|
825 t^.State:= t^.State or gstMoving; |
|
826 if t^.Kind = gtKnife then t^.State:= t^.State and (not gstCollision); |
|
827 t^.Active:= true; |
|
828 FollowGear:= t |
|
829 end |
|
830 end; |
|
831 gtGrave: begin |
|
832 dmg:= 0; |
|
833 r:= Gear^.Radius + t^.Radius; |
|
834 dx:= Gear^.X-t^.X; |
|
835 dx.isNegative:= false; |
|
836 dy:= Gear^.Y-t^.Y; |
|
837 dy.isNegative:= false; |
|
838 if r-hwRound(dx+dy) > 0 then |
|
839 begin |
|
840 dist:= hwRound(Distance(dx, dy)); |
|
841 dmg:= ModifyDamage(min(r - dist, 25), t); |
|
842 end; |
|
843 if dmg > 0 then |
|
844 begin |
|
845 t^.dY:= - _0_1; |
|
846 t^.Active:= true |
|
847 end |
|
848 end; |
|
849 end; |
|
850 t:= t^.NextGear |
|
851 end; |
|
852 if (GameFlags and gfSolidLand) = 0 then |
|
853 DrawExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), cShotgunRadius) |
|
854 end; |
|
855 |
|
856 procedure AmmoShove(Ammo: PGear; Damage, Power: LongInt); |
|
857 var t: PGearArray; |
|
858 Gear: PGear; |
|
859 i, j, tmpDmg: LongInt; |
|
860 VGear: PVisualGear; |
|
861 begin |
|
862 t:= CheckGearsCollision(Ammo); |
|
863 // Just to avoid hogs on rope dodging fire. |
|
864 if (CurAmmoGear <> nil) and ((CurAmmoGear^.Kind = gtRope) or (CurAmmoGear^.Kind = gtJetpack) or (CurAmmoGear^.Kind = gtBirdy)) |
|
865 and (CurrentHedgehog^.Gear <> nil) and (CurrentHedgehog^.Gear^.CollisionIndex = -1) |
|
866 and (sqr(hwRound(Ammo^.X) - hwRound(CurrentHedgehog^.Gear^.X)) + sqr(hwRound(Ammo^.Y) - hwRound(CurrentHedgehog^.Gear^.Y)) <= sqr(cHHRadius + Ammo^.Radius)) then |
|
867 begin |
|
868 t^.ar[t^.Count]:= CurrentHedgehog^.Gear; |
|
869 inc(t^.Count) |
|
870 end; |
|
871 |
|
872 i:= t^.Count; |
|
873 |
|
874 if (Ammo^.Kind = gtFlame) and (i > 0) then |
|
875 Ammo^.Health:= 0; |
|
876 while i > 0 do |
|
877 begin |
|
878 dec(i); |
|
879 Gear:= t^.ar[i]; |
|
880 if ((Ammo^.Kind = gtFlame) or (Ammo^.Kind = gtBlowTorch)) and |
|
881 (Gear^.Kind = gtHedgehog) and (Gear^.Hedgehog^.Effects[heFrozen] > 255) then |
|
882 Gear^.Hedgehog^.Effects[heFrozen]:= max(255,Gear^.Hedgehog^.Effects[heFrozen]-10000); |
|
883 tmpDmg:= ModifyDamage(Damage, Gear); |
|
884 if (Gear^.State and gstNoDamage) = 0 then |
|
885 begin |
|
886 |
|
887 if (Ammo^.Kind = gtDEagleShot) or (Ammo^.Kind = gtSniperRifleShot) then |
|
888 begin |
|
889 VGear := AddVisualGear(hwround(Ammo^.X), hwround(Ammo^.Y), vgtBulletHit); |
|
890 if VGear <> nil then |
|
891 VGear^.Angle := DxDy2Angle(-Ammo^.dX, Ammo^.dY); |
|
892 end; |
|
893 |
|
894 if (Gear^.Kind = gtHedgehog) and (Ammo^.State and gsttmpFlag <> 0) and (Ammo^.Kind = gtShover) then |
|
895 Gear^.FlightTime:= 1; |
|
896 |
|
897 |
|
898 case Gear^.Kind of |
|
899 gtHedgehog, |
|
900 gtMine, |
|
901 gtSMine, |
|
902 gtKnife, |
|
903 gtTarget, |
|
904 gtCase, |
|
905 gtExplosives: //, |
|
906 //gtStructure: |
|
907 begin |
|
908 if (Ammo^.Kind = gtDrill) then |
|
909 begin |
|
910 Ammo^.Timer:= 0; |
|
911 exit; |
|
912 end; |
|
913 if (not Gear^.Invulnerable) then |
|
914 begin |
|
915 if (Ammo^.Kind = gtKnife) and (tmpDmg > 0) then |
|
916 for j:= 1 to max(1,min(3,tmpDmg div 5)) do |
|
917 begin |
|
918 VGear:= AddVisualGear(hwRound(Ammo^.X-((Ammo^.X-Gear^.X)/_2)), hwRound(Ammo^.Y-((Ammo^.Y-Gear^.Y)/_2)), vgtStraightShot); |
|
919 if VGear <> nil then |
|
920 with VGear^ do |
|
921 begin |
|
922 Tint:= $FFCC00FF; |
|
923 Angle:= random(360); |
|
924 dx:= 0.0005 * (random(100)); |
|
925 dy:= 0.0005 * (random(100)); |
|
926 if random(2) = 0 then |
|
927 dx := -dx; |
|
928 if random(2) = 0 then |
|
929 dy := -dy; |
|
930 FrameTicks:= 600+random(200); |
|
931 State:= ord(sprStar) |
|
932 end |
|
933 end; |
|
934 ApplyDamage(Gear, Ammo^.Hedgehog, tmpDmg, dsShove) |
|
935 end |
|
936 else |
|
937 Gear^.State:= Gear^.State or gstWinner; |
|
938 if (Gear^.Kind = gtExplosives) and (Ammo^.Kind = gtBlowtorch) then |
|
939 begin |
|
940 if (Ammo^.Hedgehog^.Gear <> nil) then |
|
941 Ammo^.Hedgehog^.Gear^.State:= Ammo^.Hedgehog^.Gear^.State and (not gstNotKickable); |
|
942 ApplyDamage(Gear, Ammo^.Hedgehog, tmpDmg * 100, dsUnknown); // crank up damage for explosives + blowtorch |
|
943 end; |
|
944 |
|
945 if (Gear^.Kind = gtHedgehog) and (Gear^.Hedgehog^.King or (Gear^.Hedgehog^.Effects[heFrozen] > 0)) then |
|
946 begin |
|
947 Gear^.dX:= Ammo^.dX * Power * _0_005; |
|
948 Gear^.dY:= Ammo^.dY * Power * _0_005 |
|
949 end |
|
950 else if ((Ammo^.Kind <> gtFlame) or (Gear^.Kind = gtHedgehog)) and (Power <> 0) then |
|
951 begin |
|
952 Gear^.dX:= Ammo^.dX * Power * _0_01; |
|
953 Gear^.dY:= Ammo^.dY * Power * _0_01 |
|
954 end; |
|
955 |
|
956 if (not isZero(Gear^.dX)) or (not isZero(Gear^.dY)) then |
|
957 begin |
|
958 Gear^.Active:= true; |
|
959 DeleteCI(Gear); |
|
960 Gear^.State:= Gear^.State or gstMoving; |
|
961 if Gear^.Kind = gtKnife then Gear^.State:= Gear^.State and (not gstCollision); |
|
962 // move the gear upwards a bit to throw it over tiny obstacles at start |
|
963 if TestCollisionXwithGear(Gear, hwSign(Gear^.dX)) then |
|
964 begin |
|
965 if not (TestCollisionXwithXYShift(Gear, _0, -3, hwSign(Gear^.dX)) |
|
966 or (TestCollisionYwithGear(Gear, -1) <> 0)) then |
|
967 Gear^.Y:= Gear^.Y - _1; |
|
968 if not (TestCollisionXwithXYShift(Gear, _0, -2, hwSign(Gear^.dX)) |
|
969 or (TestCollisionYwithGear(Gear, -1) <> 0)) then |
|
970 Gear^.Y:= Gear^.Y - _1; |
|
971 if not (TestCollisionXwithXYShift(Gear, _0, -1, hwSign(Gear^.dX)) |
|
972 or (TestCollisionYwithGear(Gear, -1) <> 0)) then |
|
973 Gear^.Y:= Gear^.Y - _1; |
|
974 end |
|
975 end; |
|
976 |
|
977 |
|
978 if (Ammo^.Kind <> gtFlame) or ((Ammo^.State and gsttmpFlag) = 0) then |
|
979 FollowGear:= Gear |
|
980 end; |
|
981 end |
|
982 end; |
|
983 end; |
|
984 if i <> 0 then |
|
985 SetAllToActive |
|
986 end; |
|
987 |
|
988 |
|
989 function CountGears(Kind: TGearType): Longword; |
|
990 var t: PGear; |
|
991 count: Longword = 0; |
|
992 begin |
|
993 |
|
994 t:= GearsList; |
|
995 while t <> nil do |
|
996 begin |
|
997 if t^.Kind = Kind then |
|
998 inc(count); |
|
999 t:= t^.NextGear |
|
1000 end; |
|
1001 CountGears:= count; |
|
1002 end; |
|
1003 |
|
1004 procedure SetAllToActive; |
|
1005 var t: PGear; |
|
1006 begin |
|
1007 AllInactive:= false; |
|
1008 t:= GearsList; |
|
1009 while t <> nil do |
|
1010 begin |
|
1011 t^.Active:= true; |
|
1012 t:= t^.NextGear |
|
1013 end |
|
1014 end; |
|
1015 |
|
1016 procedure SetAllHHToActive; inline; |
|
1017 begin |
|
1018 SetAllHHToActive(true) |
|
1019 end; |
|
1020 |
|
1021 |
|
1022 procedure SetAllHHToActive(Ice: boolean); |
|
1023 var t: PGear; |
|
1024 begin |
|
1025 AllInactive:= false; |
|
1026 t:= GearsList; |
|
1027 while t <> nil do |
|
1028 begin |
|
1029 if (t^.Kind = gtHedgehog) or (t^.Kind = gtExplosives) then |
|
1030 begin |
|
1031 if (t^.Kind = gtHedgehog) and Ice then CheckIce(t); |
|
1032 t^.Active:= true |
|
1033 end; |
|
1034 t:= t^.NextGear |
|
1035 end |
|
1036 end; |
|
1037 |
|
1038 |
|
1039 var GearsNearArray : TPGearArray; |
|
1040 function GearsNear(X, Y: hwFloat; Kind: TGearType; r: LongInt): PGearArrayS; |
|
1041 var |
|
1042 t: PGear; |
|
1043 s: Longword; |
|
1044 begin |
|
1045 r:= r*r; |
|
1046 s:= 0; |
|
1047 SetLength(GearsNearArray, s); |
|
1048 t := GearsList; |
|
1049 while t <> nil do |
|
1050 begin |
|
1051 if (t^.Kind = Kind) |
|
1052 and ((X - t^.X)*(X - t^.X) + (Y - t^.Y)*(Y-t^.Y) < int2hwFloat(r)) then |
|
1053 begin |
|
1054 inc(s); |
|
1055 SetLength(GearsNearArray, s); |
|
1056 GearsNearArray[s - 1] := t; |
|
1057 end; |
|
1058 t := t^.NextGear; |
|
1059 end; |
|
1060 |
|
1061 GearsNear.size:= s; |
|
1062 GearsNear.ar:= @GearsNearArray |
|
1063 end; |
|
1064 |
|
1065 |
|
1066 procedure SpawnBoxOfSmth; |
|
1067 var t, aTot, uTot, a, h: LongInt; |
|
1068 i: TAmmoType; |
|
1069 begin |
|
1070 if (PlacingHogs) or |
|
1071 (cCaseFactor = 0) |
|
1072 or (CountGears(gtCase) >= 5) |
|
1073 or (GetRandom(cCaseFactor) <> 0) then |
|
1074 exit; |
|
1075 |
|
1076 FollowGear:= nil; |
|
1077 aTot:= 0; |
|
1078 uTot:= 0; |
|
1079 for i:= Low(TAmmoType) to High(TAmmoType) do |
|
1080 if (Ammoz[i].Ammo.Propz and ammoprop_Utility) = 0 then |
|
1081 inc(aTot, Ammoz[i].Probability) |
|
1082 else |
|
1083 inc(uTot, Ammoz[i].Probability); |
|
1084 |
|
1085 t:=0; |
|
1086 a:=aTot; |
|
1087 h:= 1; |
|
1088 |
|
1089 if (aTot+uTot) <> 0 then |
|
1090 if ((GameFlags and gfInvulnerable) = 0) then |
|
1091 begin |
|
1092 h:= cHealthCaseProb * 100; |
|
1093 t:= GetRandom(10000); |
|
1094 a:= (10000-h)*aTot div (aTot+uTot) |
|
1095 end |
|
1096 else |
|
1097 begin |
|
1098 t:= GetRandom(aTot+uTot); |
|
1099 h:= 0 |
|
1100 end; |
|
1101 |
|
1102 |
|
1103 if t<h then |
|
1104 begin |
|
1105 FollowGear:= AddGear(0, 0, gtCase, 0, _0, _0, 0); |
|
1106 FollowGear^.Health:= cHealthCaseAmount; |
|
1107 FollowGear^.Pos:= posCaseHealth; |
|
1108 AddCaption(GetEventString(eidNewHealthPack), cWhiteColor, capgrpAmmoInfo); |
|
1109 end |
|
1110 else if (t<a+h) then |
|
1111 begin |
|
1112 t:= aTot; |
|
1113 if (t > 0) then |
|
1114 begin |
|
1115 FollowGear:= AddGear(0, 0, gtCase, 0, _0, _0, 0); |
|
1116 t:= GetRandom(t); |
|
1117 i:= Low(TAmmoType); |
|
1118 FollowGear^.Pos:= posCaseAmmo; |
|
1119 FollowGear^.AmmoType:= i; |
|
1120 AddCaption(GetEventString(eidNewAmmoPack), cWhiteColor, capgrpAmmoInfo); |
|
1121 end |
|
1122 end |
|
1123 else |
|
1124 begin |
|
1125 t:= uTot; |
|
1126 if (t > 0) then |
|
1127 begin |
|
1128 FollowGear:= AddGear(0, 0, gtCase, 0, _0, _0, 0); |
|
1129 t:= GetRandom(t); |
|
1130 i:= Low(TAmmoType); |
|
1131 FollowGear^.Pos:= posCaseUtility; |
|
1132 FollowGear^.AmmoType:= i; |
|
1133 AddCaption(GetEventString(eidNewUtilityPack), cWhiteColor, capgrpAmmoInfo); |
|
1134 end |
|
1135 end; |
|
1136 |
|
1137 // handles case of no ammo or utility crates - considered also placing booleans in uAmmos and altering probabilities |
|
1138 if (FollowGear <> nil) then |
|
1139 begin |
|
1140 FindPlace(FollowGear, true, 0, LAND_WIDTH); |
|
1141 |
|
1142 if (FollowGear <> nil) then |
|
1143 AddVoice(sndReinforce, CurrentTeam^.voicepack) |
|
1144 end |
|
1145 end; |
|
1146 |
|
1147 |
|
1148 function GetAmmo(Hedgehog: PHedgehog): TAmmoType; |
|
1149 var t, aTot: LongInt; |
|
1150 i: TAmmoType; |
|
1151 begin |
|
1152 Hedgehog:= Hedgehog; // avoid hint |
|
1153 |
|
1154 aTot:= 0; |
|
1155 for i:= Low(TAmmoType) to High(TAmmoType) do |
|
1156 if (Ammoz[i].Ammo.Propz and ammoprop_Utility) = 0 then |
|
1157 inc(aTot, Ammoz[i].Probability); |
|
1158 |
|
1159 t:= aTot; |
|
1160 i:= Low(TAmmoType); |
|
1161 if (t > 0) then |
|
1162 begin |
|
1163 t:= GetRandom(t); |
|
1164 while t >= 0 do |
|
1165 begin |
|
1166 inc(i); |
|
1167 if (Ammoz[i].Ammo.Propz and ammoprop_Utility) = 0 then |
|
1168 dec(t, Ammoz[i].Probability) |
|
1169 end |
|
1170 end; |
|
1171 GetAmmo:= i |
|
1172 end; |
|
1173 |
|
1174 function GetUtility(Hedgehog: PHedgehog): TAmmoType; |
|
1175 var t, uTot: LongInt; |
|
1176 i: TAmmoType; |
|
1177 begin |
|
1178 |
|
1179 uTot:= 0; |
|
1180 for i:= Low(TAmmoType) to High(TAmmoType) do |
|
1181 if ((Ammoz[i].Ammo.Propz and ammoprop_Utility) <> 0) |
|
1182 and ((Hedgehog^.Team^.HedgehogsNumber > 1) or (Ammoz[i].Ammo.AmmoType <> amSwitch)) then |
|
1183 inc(uTot, Ammoz[i].Probability); |
|
1184 |
|
1185 t:= uTot; |
|
1186 i:= Low(TAmmoType); |
|
1187 if (t > 0) then |
|
1188 begin |
|
1189 t:= GetRandom(t); |
|
1190 while t >= 0 do |
|
1191 begin |
|
1192 inc(i); |
|
1193 if ((Ammoz[i].Ammo.Propz and ammoprop_Utility) <> 0) and ((Hedgehog^.Team^.HedgehogsNumber > 1) |
|
1194 or (Ammoz[i].Ammo.AmmoType <> amSwitch)) then |
|
1195 dec(t, Ammoz[i].Probability) |
|
1196 end |
|
1197 end; |
|
1198 GetUtility:= i |
|
1199 end; |
|
1200 |
|
1201 |
769 end. |
1202 end. |