@jtff/miztemplate-lib 3.7.1 → 3.7.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,17 @@
1
1
  --[[
2
-
2
+ 04 April 2025 (Stevey666) - 3.1
3
+ - Set default cluster munitions option to false, set this to true in the options if you want it
4
+ - Added missing radio commands for Cascade Scaling
5
+ - Adjust default cascading to 2 (from 1)
6
+ - Adjusted Ural-4320 to be a tanker and ammo carrier for cargo cookoff
7
+ - Prevent weapons not in the list from being tracked
8
+ - Moved some logging behind the debug mode flag
9
+ - Ordnance Protection, added a max height ordnance protection will snap explosion to ground
10
+ - Ordnance Protection, fixed enable/disable option
11
+ - Added Giant Explosion feature
12
+ - Adjusted some hydra70 values on recom. from ETBSmorgan
13
+
14
+
3
15
  09 March 2025 (Stevey666) - 3.0
4
16
  - Added ordinance protection gives a few options - stop the additional larger_explosion that tends to blow up your own bombs if theyre dropped at the same place if its within x m
5
17
  - Additional ordnance protection option that will cause a snap to ground larger_explosion if its within x meters of a recent larger explosion and within x seconds (can set in options)
@@ -79,8 +91,7 @@ splash_damage_options = {
79
91
  ["game_messages"] = false, --enable some messages on screen
80
92
  ["debug"] = false, --enable debugging messages
81
93
  ["weapon_missing_message"] = false, --false disables messages alerting you to weapons missing from the explTable
82
-
83
- ["track_pre_explosion_debug"] = false, --Toggle to enable/disable pre-explosion tracking debugging
94
+ ["track_pre_explosion_debug"] = false, --Toggle to enable/disable pre-explosion tracking debugging
84
95
 
85
96
  ["enable_radio_menu"] = true, --enables the in-game radio menu for modifying settings
86
97
 
@@ -104,7 +115,7 @@ splash_damage_options = {
104
115
  ["use_dynamic_blast_radius"] = true, --if true, blast radius is calculated from explosion power; if false, blast_search_radius (90) is used
105
116
  ["dynamic_blast_radius_modifier"] = 2, --multiplier for the blast radius
106
117
 
107
- ["cascade_scaling"] = 1, --multiplier for secondary (cascade) blast damage, 1 damage fades out too soon, 3 damage seems a good balance
118
+ ["cascade_scaling"] = 2, --multiplier for secondary (cascade) blast damage, 1 damage fades out too soon, 2 or 3 damage seems a good balance
108
119
  ["cascade_explode_threshold"] = 60, --only trigger cascade explosion if the unit's current health is <= this percent of its maximum, setting can help blow nearby jeeps but not tanks
109
120
  ["always_cascade_explode"] = false, --switch if you want everything to explode like with the original script
110
121
 
@@ -123,20 +134,30 @@ splash_damage_options = {
123
134
  ["ordnance_protection_radius"] = 10, --Distance in meters to protect nearby bombs
124
135
  ["detect_ordnance_destruction"] = true, --Toggle detection of ordnance destroyed by large explosions
125
136
  ["snap_to_ground_if_destroyed_by_large_explosion"] = true, --If the ordnance protection fails or is disabled we can snap larger_explosions to the ground (if enabled - power as set in weapon list) - so an explosion still does hit the ground
137
+ ["max_snapped_height"] = 80, --max height it will snap to ground from
126
138
  ["recent_large_explosion_snap"] = true, --enable looking for a recent large_explosion generated by the script
127
- ["recent_large_explosion_range"] = 200, --range its looking for in meters for a recent large_explosion generated by the script
139
+ ["recent_large_explosion_range"] = 100, --range its looking for in meters for a recent large_explosion generated by the script
128
140
  ["recent_large_explosion_time"] = 4, --in seconds how long ago there was a recent large_explosion generated by the script
129
141
 
130
- -- Cluster bomb settings
142
+ --Cluster bomb settings
131
143
  ["cluster_enabled"] = false,
132
- ["cluster_base_length"] = 150, -- Base forward spread (meters)
133
- ["cluster_base_width"] = 200, -- Base lateral spread (meters)
134
- ["cluster_max_length"] = 300, -- Max forward spread (meters)
135
- ["cluster_max_width"] = 400, -- Max lateral spread (meters)
136
- ["cluster_min_length"] = 100, -- Min forward spread
137
- ["cluster_min_width"] = 150, -- Min lateral spread
138
- ["cluster_bomblet_reductionmodifier"] = true, -- Use equation to reduce number of bomblets (to make it look better)
139
- ["cluster_bomblet_damage_modifier"] = 1, -- Adjustable global modifier for bomblet explosive power
144
+ ["cluster_base_length"] = 150, --Base forward spread (meters)
145
+ ["cluster_base_width"] = 200, --Base lateral spread (meters)
146
+ ["cluster_max_length"] = 300, --Max forward spread (meters)
147
+ ["cluster_max_width"] = 400, --Max lateral spread (meters)
148
+ ["cluster_min_length"] = 100, --Min forward spread
149
+ ["cluster_min_width"] = 150, --Min lateral spread
150
+ ["cluster_bomblet_reductionmodifier"] = true, --Use equation to reduce number of bomblets (to make it look better)
151
+ ["cluster_bomblet_damage_modifier"] = 1, --Adjustable global modifier for bomblet explosive power
152
+
153
+ --Giant Explosion Options - Remember, any target you want to blow up needs to be named "GiantExplosionTarget(X)" (X) being any value/name etc
154
+ ["giant_explosion_enabled"] = true, --Toggle to enable/disable Giant Explosion
155
+ ["giant_explosion_power"] = 6000, --Power in kg of TNT (default 8 tons)
156
+ ["giant_explosion_scale"] = 1, --Size scale factor (default 1)
157
+ ["giant_explosion_duration"] = 3.0, --Total duration in seconds (default 3s)
158
+ ["giant_explosion_count"] = 250, --Number of explosions (default 300)
159
+ ["giant_explosion_target_static"] = true, --Toggle to true for static targets (store position once), false for dynamic (update every second)
160
+ ["giant_explosion_poll_rate"] = 1, --Polling rate in seconds for flag checks (default 1s)
140
161
  }
141
162
 
142
163
  local script_enable = 1
@@ -198,7 +219,7 @@ flamesize:
198
219
  --3) Refueler ATZ-10
199
220
  ["ATZ-10"] = {
200
221
  cargoExplosion = true,
201
- cargoExplosionMult = 1.8,
222
+ cargoExplosionMult = 2,
202
223
  cargoExplosionPower = 200,
203
224
  cargoCookOff = false,
204
225
  cookOffCount = 0,
@@ -258,7 +279,7 @@ flamesize:
258
279
  flameSize = 1,
259
280
  flameDuration = 30,
260
281
  },
261
-
282
+ --#Technically this is both ammo and fuel looking at the model
262
283
  ["Ural-4320"] = {
263
284
  cargoExplosion = true,
264
285
  cargoExplosionMult = 1,
@@ -269,7 +290,7 @@ flamesize:
269
290
  cookOffDuration = 20,
270
291
  cookOffRandomTiming = true,
271
292
  cookOffPowerRandom = 50,
272
- isTanker = false,
293
+ isTanker = true,
273
294
  flameSize = 1,
274
295
  flameDuration = 30,
275
296
  },
@@ -499,7 +520,7 @@ explTable = {
499
520
  ["HYDRA_70_MK5"] = { explosive = 8, shaped_charge = false },
500
521
  ["HYDRA_70_M151"] = { explosive = 5, shaped_charge = false },
501
522
  ["HYDRA_70_M151_M433"] = { explosive = 5, shaped_charge = false },
502
- ["HYDRA_70_M229"] = { explosive = 5, shaped_charge = false },
523
+ ["HYDRA_70_M229"] = { explosive = 10, shaped_charge = false },
503
524
  ["FFAR Mk1 HE"] = { explosive = 5, shaped_charge = false },
504
525
  ["FFAR Mk5 HEAT"] = { explosive = 8, shaped_charge = false },
505
526
  ["HVAR"] = { explosive = 5, shaped_charge = false },
@@ -551,7 +572,7 @@ explTable = {
551
572
  ["AGR_20"] = { explosive = 8, shaped_charge = false },
552
573
  ["AGR_20A"] = { explosive = 8, shaped_charge = false },
553
574
  ["AGR_20_M282"] = { explosive = 8, shaped_charge = false },
554
- ["Hydra_70_M282_MPP"] = { explosive = 8, shaped_charge = false },
575
+ ["Hydra_70_M282_MPP"] = { explosive = 5, shaped_charge = true },
555
576
  ["BRM-1_90MM"] = { explosive = 8, shaped_charge = false },
556
577
  }
557
578
 
@@ -646,12 +667,346 @@ local function calculate_dispersion(velocity, burst_altitude)
646
667
  return math.max(splash_damage_options.cluster_min_length, math.min(splash_damage_options.cluster_max_length, length_jitter)),
647
668
  math.max(splash_damage_options.cluster_min_width, math.min(splash_damage_options.cluster_max_width, width_jitter))
648
669
  end
649
- ----[[ ##### End of HELPER/UTILITY FUNCTIONS ##### ]]----
650
670
 
671
+
672
+
673
+
674
+
675
+
676
+
677
+
678
+
679
+ ----[[ ##### End of HELPER/UTILITY FUNCTIONS ##### ]]----
680
+ giantExplosionTargets = {}
651
681
  cargoEffectsQueue = {}
652
682
  WpnHandler = {}
683
+ tracked_target_position = nil --Store the last known position of TargetUnit for giant explosion
653
684
  tracked_weapons = {}
654
685
  local processedUnitsGlobal = {}
686
+
687
+ function scanGiantExplosionTargets()
688
+ giantExplosionTargets = {}
689
+ local function findTargets(obj)
690
+ if obj:isExist() then
691
+ local name = obj:getName()
692
+ if string.find(name, "GiantExplosionTarget") then
693
+ local flagName = string.gsub(name, "Target", "")
694
+ table.insert(giantExplosionTargets, {
695
+ name = name,
696
+ flag = flagName,
697
+ obj = obj,
698
+ pos = obj:getPoint(),
699
+ static = splash_damage_options.giant_explosion_target_static
700
+ })
701
+ end
702
+ end
703
+ return true
704
+ end
705
+ world.searchObjects({Object.Category.UNIT, Object.Category.STATIC}, {id = world.VolumeType.ALL}, findTargets)
706
+ if not splash_damage_options.giant_explosion_target_static then
707
+ timer.scheduleFunction(updateGiantExplosionPositions, {}, timer.getTime() + 1.0)
708
+ end
709
+ end
710
+
711
+ function updateTargetPosition()
712
+ for name, target in pairs(giantExplosionTargets) do
713
+ if target.obj:isExist() then
714
+ target.pos = target.obj:getPosition().p
715
+ end
716
+ end
717
+ return timer.getTime() + 1.0
718
+ end
719
+
720
+
721
+ --Giant Explosion Function
722
+ function triggerGiantExplosion(params)
723
+ if not splash_damage_options.giant_explosion_enabled then
724
+ debugMsg("Giant Explosion is disabled in options.")
725
+ return
726
+ end
727
+
728
+ local initialPos = params.pos or {x = 0, y = 0, z = 0}
729
+ local explosionPower = params.power or splash_damage_options.giant_explosion_power
730
+ local sizeScale = params.scale or splash_damage_options.giant_explosion_scale
731
+ local totalDuration = params.duration or splash_damage_options.giant_explosion_duration
732
+ local explosionCount = params.count or splash_damage_options.giant_explosion_count
733
+
734
+ if not initialPos.x or not initialPos.y or not initialPos.z then
735
+ gameMsg("Error: Invalid position for giant explosion!")
736
+ debugMsg("No valid initial position set for giant explosion!")
737
+ return
738
+ end
739
+
740
+ debugMsg("Triggering giant fireball at X: " .. initialPos.x .. ", Y: " .. initialPos.y .. ", Z: " .. initialPos.z)
741
+
742
+ local function scheduleExplosion(pos, delay)
743
+ if not pos or not pos.x or not pos.y or not pos.z then
744
+ debugMsg("Error: Invalid position for explosion - pos: " .. tostring(pos))
745
+ return
746
+ end
747
+ timer.scheduleFunction(function(p)
748
+ if p and p.x and p.y and p.z then
749
+ trigger.action.explosion(p, explosionPower)
750
+ end
751
+ end, pos, timer.getTime() + delay)
752
+ end
753
+
754
+ -- Pre-explosion scan for cargo units
755
+ local scanRadius = 1500 * sizeScale -- 1500m base radius, scaled by sizeScale
756
+ local preExplosionTargets = {}
757
+ if splash_damage_options.enable_cargo_effects then
758
+ local volS = {
759
+ id = world.VolumeType.SPHERE,
760
+ params = { point = initialPos, radius = scanRadius }
761
+ }
762
+ local ifFound = function(foundObject)
763
+ if foundObject:isExist() then
764
+ local category = foundObject:getCategory()
765
+ if (category == Object.Category.UNIT and foundObject:getDesc().category == Unit.Category.GROUND_UNIT) or
766
+ category == Object.Category.STATIC then
767
+ table.insert(preExplosionTargets, {
768
+ name = foundObject:getTypeName(),
769
+ health = foundObject:getLife() or 0,
770
+ position = foundObject:getPoint(),
771
+ maxHealth = (category == Object.Category.UNIT and foundObject:getDesc().life) or foundObject:getLife() or 0,
772
+ unit = foundObject
773
+ })
774
+ end
775
+ end
776
+ return true
777
+ end
778
+ world.searchObjects({Object.Category.UNIT, Object.Category.STATIC}, volS, ifFound)
779
+ debugMsg("Pre-explosion scan for Giant Explosion: " .. #preExplosionTargets .. " targets found within " .. scanRadius .. "m")
780
+ end
781
+ -- Trigger the explosion
782
+ local maxRadius = 200 * sizeScale
783
+ local maxHeight = 500 * sizeScale
784
+ local adjustedExplosionCount = math.floor(explosionCount * (sizeScale ^ 2.5))
785
+ local stepTime = totalDuration / adjustedExplosionCount
786
+ local variance = 0.25 --Fixed at 25%
787
+
788
+ for i = 1, adjustedExplosionCount do
789
+ local progress = i / adjustedExplosionCount
790
+ local currentRadius = maxRadius * progress
791
+ local r = currentRadius * (0.9 + math.random() * 0.1)
792
+ local theta = math.random() * 2 * math.pi
793
+ local phi = math.acos(math.random())
794
+
795
+ local offsetX = r * math.sin(phi) * math.cos(theta)
796
+ local offsetZ = r * math.sin(phi) * math.sin(theta)
797
+ local offsetY = r * math.cos(phi)
798
+
799
+ offsetX = offsetX * (1 + (math.random() - 0.5) * variance)
800
+ offsetZ = offsetZ * (1 + (math.random() - 0.5) * variance)
801
+ offsetY = offsetY * (1 + (math.random() - 0.5) * variance * 0.5)
802
+
803
+ local blastPos = {
804
+ x = initialPos.x + offsetX,
805
+ y = land.getHeight({x = initialPos.x, y = initialPos.z}) + offsetY,
806
+ z = initialPos.z + offsetZ
807
+ }
808
+ if blastPos.y < land.getHeight({x = blastPos.x, y = blastPos.z}) then
809
+ blastPos.y = land.getHeight({x = blastPos.x, y = blastPos.z})
810
+ end
811
+
812
+ local delay = (i - 1) * stepTime + (math.random() - 0.5) * stepTime * variance
813
+ scheduleExplosion(blastPos, delay)
814
+ end
815
+
816
+ gameMsg("Expanding giant fireball over " .. totalDuration .. "s (scale " .. sizeScale .. ")!")
817
+
818
+ -- Post-explosion scan and cargo cook-off queuing
819
+ if splash_damage_options.enable_cargo_effects then
820
+ timer.scheduleFunction(function(args)
821
+ local centerPos = args[1]
822
+ local radius = args[2]
823
+ local preTargets = args[3]
824
+
825
+ local postExplosionTargets = {}
826
+ local volS = {
827
+ id = world.VolumeType.SPHERE,
828
+ params = { point = centerPos, radius = radius }
829
+ }
830
+ local ifFound = function(foundObject)
831
+ if foundObject:isExist() then
832
+ local category = foundObject:getCategory()
833
+ if (category == Object.Category.UNIT and foundObject:getDesc().category == Unit.Category.GROUND_UNIT) or
834
+ category == Object.Category.STATIC then
835
+ table.insert(postExplosionTargets, {
836
+ name = foundObject:getTypeName(),
837
+ health = foundObject:getLife() or 0,
838
+ position = foundObject:getPoint(),
839
+ maxHealth = (category == Object.Category.UNIT and foundObject:getDesc().life) or foundObject:getLife() or 0
840
+ })
841
+ end
842
+ end
843
+ return true
844
+ end
845
+ world.searchObjects({Object.Category.UNIT, Object.Category.STATIC}, volS, ifFound)
846
+ debugMsg("Post-explosion scan for Giant Explosion: " .. #postExplosionTargets .. " targets found within " .. radius .. "m")
847
+
848
+ -- Compare pre- and post-explosion targets
849
+ for _, preTarget in ipairs(preTargets) do
850
+ local found = false
851
+ local postHealth = 0
852
+ for _, postTarget in ipairs(postExplosionTargets) do
853
+ if preTarget.name == postTarget.name and getDistance(preTarget.position, postTarget.position) < 1 then
854
+ found = true
855
+ postHealth = postTarget.health
856
+ break
857
+ end
858
+ end
859
+
860
+ local cargoData = cargoUnits[preTarget.name]
861
+ if cargoData and (not found or postHealth <= 0) then
862
+ local distance = getDistance(initialPos, preTarget.position)
863
+ if distance <= radius then
864
+ local cargoPower = cargoData.cargoExplosionPower or explosionPower
865
+ table.insert(cargoEffectsQueue, {
866
+ name = preTarget.name,
867
+ distance = distance,
868
+ coords = preTarget.position,
869
+ power = cargoPower,
870
+ explosion = cargoData.cargoExplosion,
871
+ cookOff = cargoData.cargoCookOff,
872
+ cookOffCount = cargoData.cookOffCount,
873
+ cookOffPower = cargoData.cookOffPower,
874
+ cookOffDuration = cargoData.cookOffDuration,
875
+ cookOffRandomTiming = cargoData.cookOffRandomTiming,
876
+ cookOffPowerRandom = cargoData.cookOffPowerRandom,
877
+ isTanker = cargoData.isTanker,
878
+ flameSize = cargoData.flameSize,
879
+ flameDuration = cargoData.flameDuration
880
+ })
881
+ debugMsg("Queued cargo effect for " .. preTarget.name .. " destroyed by Giant Explosion at " .. string.format("%.1f", distance) .. "m")
882
+ end
883
+ end
884
+ end
885
+
886
+ -- Process queued cargo effects with prioritized flames
887
+ if #cargoEffectsQueue > 0 then
888
+ local flameIndex = 0 -- Separate index for flames
889
+ local otherIndex = 0 -- Index for explosions, cook-offs, debris
890
+ local processedCargoUnits = {}
891
+ local flamePositions = {}
892
+ for _, effect in ipairs(cargoEffectsQueue) do
893
+ local unitKey = effect.name .. "_" .. effect.coords.x .. "_" .. effect.coords.z
894
+ if not processedUnitsGlobal[unitKey] and not processedCargoUnits[unitKey] then
895
+ -- Handle tanker flames first with minimal delay
896
+ if effect.isTanker and effect.explosion then
897
+ debugMsg("Triggering cargo explosion for tanker " .. effect.name .. " at " .. string.format("%.1f", effect.distance) .. "m with power " .. effect.power .. " scheduled at " .. flameIndex .. "s")
898
+ timer.scheduleFunction(function(params)
899
+ debugMsg("Executing cargo explosion at X: " .. string.format("%.0f", params[1].x) .. ", Y: " .. string.format("%.0f", params[1].y) .. ", Z: " .. string.format("%.0f", params[1].z) .. " with power " .. params[2])
900
+ trigger.action.explosion(params[1], params[2])
901
+ end, {effect.coords, effect.power}, timer.getTime() + flameIndex + 0.1)
902
+
903
+ local flameSize = effect.flameSize or 3
904
+ local flameDuration = effect.flameDuration
905
+ local flameDensity = 1.0
906
+ local effectId = effectSmokeId
907
+ effectSmokeId = effectSmokeId + 1
908
+ local isDuplicate = false
909
+ for _, pos in pairs(flamePositions) do
910
+ if getDistance3D(effect.coords, pos) < 3 then
911
+ isDuplicate = true
912
+ debugMsg("Skipping duplicate flame for " .. effect.name .. " near X: " .. string.format("%.0f", pos.x) .. ", Y: " .. string.format("%.0f", pos.y) .. ", Z: " .. string.format("%.0f", pos.z))
913
+ break
914
+ end
915
+ end
916
+ if not isDuplicate then
917
+ debugMsg("Adding flame effect for tanker " .. effect.name .. " at " .. string.format("%.1f", effect.distance) .. "m (Size: " .. flameSize .. ", Duration: " .. flameDuration .. "s, ID: " .. effectId .. ") scheduled at " .. flameIndex .. "s")
918
+ timer.scheduleFunction(function(params)
919
+ local terrainHeight = land.getHeight({x = params[1].x, y = params[1].z})
920
+ local adjustedCoords = {x = params[1].x, y = terrainHeight + 2, z = params[1].z}
921
+ debugMsg("Spawning flame effect at X: " .. string.format("%.0f", adjustedCoords.x) .. ", Y: " .. string.format("%.0f", adjustedCoords.y) .. ", Z: " .. string.format("%.0f", adjustedCoords.z))
922
+ trigger.action.explosion(adjustedCoords, 10) -- Small trigger explosion
923
+ trigger.action.effectSmokeBig(adjustedCoords, params[2], params[3], params[4])
924
+ end, {effect.coords, flameSize, flameDensity, effectId}, timer.getTime() + flameIndex + 0.2)
925
+ timer.scheduleFunction(function(id)
926
+ debugMsg("Stopping flame effect for " .. effect.name .. " (ID: " .. id .. ")")
927
+ trigger.action.effectSmokeStop(id)
928
+ end, effectId, timer.getTime() + flameIndex + flameDuration + 0.2)
929
+ table.insert(flamePositions, effect.coords)
930
+ end
931
+ flameIndex = flameIndex + 0.5 -- Fast spacing for flames (0.5s)
932
+ end
933
+ -- Handle non-tanker explosions, cook-offs, and debris
934
+ if not effect.isTanker or (effect.explosion and not effect.isTanker) then
935
+ if effect.explosion then
936
+ debugMsg("Triggering cargo explosion for " .. effect.name .. " at " .. string.format("%.1f", effect.distance) .. "m with power " .. effect.power .. " scheduled at " .. otherIndex .. "s")
937
+ timer.scheduleFunction(function(params)
938
+ debugMsg("Executing cargo explosion at X: " .. string.format("%.0f", params[1].x) .. ", Y: " .. string.format("%.0f", params[1].y) .. ", Z: " .. string.format("%.0f", params[1].z) .. " with power " .. params[2])
939
+ trigger.action.explosion(params[1], params[2])
940
+ end, {effect.coords, effect.power}, timer.getTime() + otherIndex + 0.1)
941
+ end
942
+ if effect.cookOff and effect.cookOffCount > 0 then
943
+ debugMsg("Scheduling " .. effect.cookOffCount .. " cook-off explosions for " .. effect.name .. " at " .. string.format("%.1f", effect.distance) .. "m over " .. effect.cookOffDuration .. "s starting at " .. otherIndex .. "s")
944
+ for i = 1, effect.cookOffCount do
945
+ local delay = effect.cookOffRandomTiming and math.random() * effect.cookOffDuration or (i - 1) * (effect.cookOffDuration / effect.cookOffCount)
946
+ local basePower = effect.cookOffPower
947
+ local powerVariation = effect.cookOffPowerRandom / 100
948
+ local cookOffPower = effect.cookOffPowerRandom == 0 and basePower or basePower * (1 + powerVariation * (math.random() * 2 - 1))
949
+ debugMsg("Cook-off #" .. i .. " for " .. effect.name .. " at " .. string.format("%.1f", effect.distance) .. "m scheduled at " .. string.format("%.3f", delay) .. "s with power " .. string.format("%.2f", cookOffPower))
950
+ timer.scheduleFunction(function(params)
951
+ debugMsg("Executing cook-off at X: " .. string.format("%.0f", params[1].x) .. ", Y: " .. string.format("%.0f", params[1].y) .. ", Z: " .. string.format("%.0f", params[1].z) .. " with power " .. params[2])
952
+ trigger.action.explosion(params[1], params[2])
953
+ end, {effect.coords, cookOffPower}, timer.getTime() + otherIndex + delay)
954
+ end
955
+ if splash_damage_options.debris_effects then
956
+ local debrisCount = math.random(splash_damage_options.debris_count_min, splash_damage_options.debris_count_max)
957
+ for j = 1, debrisCount do
958
+ local theta = math.random() * 2 * math.pi
959
+ local phi = math.acos(math.random() * 2 - 1)
960
+ local minDist = splash_damage_options.debris_max_distance * 0.1
961
+ local maxDist = splash_damage_options.debris_max_distance
962
+ local r = math.random() * (maxDist - minDist) + minDist
963
+ local debrisX = effect.coords.x + r * math.sin(phi) * math.cos(theta)
964
+ local debrisZ = effect.coords.z + r * math.sin(phi) * math.sin(theta)
965
+ local terrainY = land.getHeight({x = debrisX, y = debrisZ})
966
+ local debrisY = terrainY + math.random() * maxDist
967
+ local debrisPos = {x = debrisX, y = debrisY, z = debrisZ}
968
+ local debrisPower = splash_damage_options.debris_power
969
+ local debrisDelay = (j - 1) * (effect.cookOffDuration / debrisCount)
970
+ timer.scheduleFunction(function(debrisArgs)
971
+ debugMsg("Debris explosion at X: " .. string.format("%.0f", debrisArgs[1].x) .. ", Y: " .. string.format("%.0f", debrisArgs[1].y) .. ", Z: " .. string.format("%.0f", debrisArgs[1].z) .. " with power " .. debrisArgs[2])
972
+ trigger.action.explosion(debrisArgs[1], debrisArgs[2])
973
+ end, {debrisPos, debrisPower}, timer.getTime() + otherIndex + debrisDelay)
974
+ end
975
+ end
976
+ end
977
+ otherIndex = otherIndex + 1 -- Slower spacing for non-flame effects (1s)
978
+ end
979
+ processedCargoUnits[unitKey] = true
980
+ processedUnitsGlobal[unitKey] = true
981
+ end
982
+ end
983
+ cargoEffectsQueue = {} -- Clear the queue after processing
984
+ end
985
+ end, {initialPos, scanRadius, preExplosionTargets}, timer.getTime() + totalDuration + 1.0)
986
+ end
987
+ end
988
+
989
+ --Flag Checker for mission editor
990
+ function checkGiantExplosionFlag()
991
+ for name, target in pairs(giantExplosionTargets) do
992
+ local flagName = name:gsub("GiantExplosionTarget", "GiantExplosionTarget")
993
+ local flagValue = trigger.misc.getUserFlag(flagName)
994
+ --commenting out as it spams every second
995
+ debugMsg("Checking flag " .. flagName .. ": " .. flagValue)
996
+ if flagValue == 1 then
997
+ debugMsg("Triggering explosion for " .. name .. " at X:" .. target.pos.x .. " Y:" .. target.pos.y .. " Z:" .. target.pos.z)
998
+ triggerGiantExplosion({
999
+ pos = target.pos,
1000
+ power = splash_damage_options.giant_explosion_power,
1001
+ scale = splash_damage_options.giant_explosion_scale,
1002
+ duration = splash_damage_options.giant_explosion_duration,
1003
+ count = splash_damage_options.giant_explosion_count
1004
+ })
1005
+ trigger.action.setUserFlag(flagName, 2)
1006
+ end
1007
+ end
1008
+ return timer.getTime() + splash_damage_options.giant_explosion_poll_rate
1009
+ end
655
1010
 
656
1011
  function getWeaponExplosive(name)
657
1012
  local weaponData = explTable[name]
@@ -678,7 +1033,7 @@ function track_wpns_cluster_scan(args)
678
1033
  }
679
1034
  local bombletsFound = {}
680
1035
  local allWeaponsFound = {}
681
- -- General scan for all weapons
1036
+ --General scan for all weapons
682
1037
  world.searchObjects(Object.Category.WEAPON, scanVol, function(wpn)
683
1038
  if wpn:isExist() then
684
1039
  local wpnId = wpn.id_
@@ -700,7 +1055,7 @@ function track_wpns_cluster_scan(args)
700
1055
  end
701
1056
  return true
702
1057
  end)
703
- -- Log results
1058
+ --Log results
704
1059
  debugMsg("Scanned for submunition '" .. subName .. "' bomblets from '" .. parentName .. "': " .. #bombletsFound .. " found (Attempt " .. attempt .. ")")
705
1060
  if #allWeaponsFound > 0 then
706
1061
  local msg = "General scan for '" .. parentName .. "': " .. #allWeaponsFound .. " bomblets released, expected " .. subCount .. " '" .. subName .. "'"
@@ -722,7 +1077,7 @@ function track_wpns_cluster_scan(args)
722
1077
  elseif #bombletsFound == 0 and #allWeaponsFound == 0 then
723
1078
  debugMsg("No bomblets of any type detected for '" .. parentName .. "' (Attempt " .. attempt .. ")")
724
1079
  end
725
- -- Retry if no expected submunitions found
1080
+ --Retry if no expected submunitions found
726
1081
  if #bombletsFound == 0 and attempt < maxAttempts then
727
1082
  debugMsg("No expected submunition '" .. subName .. "' found on attempt " .. attempt .. ", retrying in 0.5s")
728
1083
  timer.scheduleFunction(track_wpns_cluster_scan, {parentPos, parentDir, parentName, subName, subCount, subPower, parentVel, attempt + 1}, timer.getTime() + 0.5)
@@ -797,7 +1152,7 @@ world.searchObjects({Object.Category.UNIT, Object.Category.STATIC}, tickVol, fun
797
1152
  --Tight scan while weapon exists
798
1153
  --local tightRadius = 50
799
1154
  --if splash_damage_options.use_dynamic_blast_radius then
800
- -- tightRadius = math.pow(explosionPower, 1/3) * 5 * splash_damage_options.dynamic_blast_radius_modifier
1155
+ --tightRadius = math.pow(explosionPower, 1/3) * 5 * splash_damage_options.dynamic_blast_radius_modifier
801
1156
  --end
802
1157
  local tightRadius = blastRadius --Use already calculated blastRadius
803
1158
  local volS = {
@@ -921,7 +1276,7 @@ world.searchObjects({Object.Category.UNIT, Object.Category.STATIC}, tickVol, fun
921
1276
 
922
1277
  --Store pre-explosion state of all tracked weapons for detection
923
1278
  local preExplosionWeapons = {}
924
- if splash_damage_options.detect_ordnance_destruction and splash_damage_options.larger_explosions then
1279
+ if splash_damage_options.ordnance_protection and splash_damage_options.detect_ordnance_destruction and splash_damage_options.larger_explosions then
925
1280
  for id, data in pairs(tracked_weapons) do
926
1281
  if data.wpn:isExist() then
927
1282
  preExplosionWeapons[id] = {
@@ -948,7 +1303,7 @@ world.searchObjects({Object.Category.UNIT, Object.Category.STATIC}, tickVol, fun
948
1303
  if submunitionCount > 60 then submunitionCount = 60 end --Cap at 60
949
1304
  end
950
1305
  end
951
- -- Extended scan with general bomblet detection
1306
+ --Extended scan with general bomblet detection
952
1307
  timer.scheduleFunction(track_wpns_cluster_scan, {explosionPoint, wpnData.dir, wpnData.name, submunitionName, submunitionCount, submunitionPower, wpnData.speed}, timer.getTime() + 0.3)
953
1308
  else
954
1309
  --Standard explosion handling
@@ -961,7 +1316,7 @@ world.searchObjects({Object.Category.UNIT, Object.Category.STATIC}, tickVol, fun
961
1316
  blastWave(explosionPoint, splash_damage_options.blast_search_radius, wpnData.ordnance, explosionPower, isShapedCharge)
962
1317
  end
963
1318
  --detect_ordnance_destruction comes before recent_large_explosion_snap in original
964
- if splash_damage_options.detect_ordnance_destruction and splash_damage_options.larger_explosions then
1319
+ if splash_damage_options.ordnance_protection and splash_damage_options.detect_ordnance_destruction and splash_damage_options.larger_explosions then
965
1320
  timer.scheduleFunction(function(args)
966
1321
  local explosionPoint = args[1]
967
1322
  local blastRadius = args[2]
@@ -997,19 +1352,20 @@ world.searchObjects({Object.Category.UNIT, Object.Category.STATIC}, tickVol, fun
997
1352
  end, {explosionPoint, blastRadius, wpnData.name, preExplosionWeapons}, timer.getTime() + 0.2)
998
1353
  end
999
1354
  --recent_large_explosion_snap comes after main explosion and detect_ordnance_destruction
1000
- if splash_damage_options.larger_explosions and splash_damage_options.recent_large_explosion_snap then
1355
+ if splash_damage_options.ordnance_protection and splash_damage_options.larger_explosions and splash_damage_options.recent_large_explosion_snap and splash_damage_options.snap_to_ground_if_destroyed_by_large_explosion then
1001
1356
  local currentTime = timer.getTime()
1002
1357
  for id, data in pairs(tracked_weapons) do
1003
1358
  if id ~= wpn_id_ and not data.wpn:isExist() then
1004
1359
  local terrainHeight = land.getHeight({x = data.pos.x, y = data.pos.z})
1005
- local isMidAir = data.pos.y > terrainHeight + 5
1360
+ local weaponHeight = data.pos.y - terrainHeight --Calculate height above ground
1361
+ local isMidAir = weaponHeight > 5 --Still checks if above ground
1006
1362
  local snapTriggered = false
1007
1363
  for _, explosion in ipairs(recentExplosions) do
1008
1364
  local timeDiff = currentTime - explosion.time
1009
1365
  local distance = getDistance3D(data.pos, explosion.pos)
1010
1366
  debugMsg("Checking " .. data.name .. " at X: " .. data.pos.x .. ", Y: " .. data.pos.y .. ", Z: " .. data.pos.z .. " against explosion at X: " .. explosion.pos.x .. ", Y: " .. explosion.pos.y .. ", Z: " .. explosion.pos.z .. " - Distance: " .. distance .. "m, TimeDiff: " .. timeDiff .. "s")
1011
1367
  if timeDiff <= splash_damage_options.recent_large_explosion_time and distance <= splash_damage_options.recent_large_explosion_range then
1012
- if isMidAir then
1368
+ if isMidAir and weaponHeight <= splash_damage_options.max_snapped_height then --New height check
1013
1369
  local groundPos = { x = data.pos.x, y = terrainHeight, z = data.pos.z }
1014
1370
  local destroyedWeaponPower, isShapedCharge = getWeaponExplosive(data.name)
1015
1371
  destroyedWeaponPower = destroyedWeaponPower * splash_damage_options.overall_scaling
@@ -1019,11 +1375,13 @@ world.searchObjects({Object.Category.UNIT, Object.Category.STATIC}, tickVol, fun
1019
1375
  if splash_damage_options.apply_shaped_charge_effects and isShapedCharge then
1020
1376
  destroyedWeaponPower = destroyedWeaponPower * splash_damage_options.shaped_charge_multiplier
1021
1377
  end
1022
- debugMsg("Weapon " .. data.name .. " detected recent large explosion within " .. splash_damage_options.recent_large_explosion_range .. "m and " .. splash_damage_options.recent_large_explosion_time .. "s, snapping to ground at X: " .. string.format("%.0f", groundPos.x) .. ", Y: " .. string.format("%.0f", groundPos.y) .. ", Z: " .. string.format("%.0f", groundPos.z) .. " with power " .. destroyedWeaponPower)
1378
+ debugMsg("Weapon " .. data.name .. " detected recent large explosion within " .. splash_damage_options.recent_large_explosion_range .. "m and " .. splash_damage_options.recent_large_explosion_time .. "s, snapping to ground at X: " .. string.format("%.0f", groundPos.x) .. ", Y: " .. string.format("%.0f", groundPos.y) .. ", Z: " .. string.format("%.0f", groundPos.z) .. " with power " .. destroyedWeaponPower .. " (Height: " .. string.format("%.0f", weaponHeight) .. "m)")
1023
1379
  trigger.action.explosion(groundPos, destroyedWeaponPower)
1024
1380
  snapTriggered = true
1025
1381
  table.insert(weaponsToRemove, id)
1026
1382
  break
1383
+ elseif isMidAir then
1384
+ debugMsg("Weapon " .. data.name .. " destroyed above max_snapped_height (" .. splash_damage_options.max_snapped_height .. "m) at " .. string.format("%.0f", weaponHeight) .. "m, skipping snap")
1027
1385
  else
1028
1386
  debugMsg("Weapon " .. data.name .. " impacted ground within recent_large_explosion_range (" .. splash_damage_options.recent_large_explosion_range .. "m) and time (" .. splash_damage_options.recent_large_explosion_time .. "s), no snap needed")
1029
1387
  snapTriggered = true
@@ -1066,7 +1424,9 @@ world.searchObjects({Object.Category.UNIT, Object.Category.STATIC}, tickVol, fun
1066
1424
  local chosenTargets = args[6]
1067
1425
  local weaponName = args[7]
1068
1426
  local wpnData = args[8]
1427
+ if splash_damage_options.debug then
1069
1428
  debugMsg("Starting impact handling for " .. weaponName .. " at " .. timer.getTime() .. "s")
1429
+ end
1070
1430
  local status, err = pcall(function()
1071
1431
  --Log pre-explosion targets
1072
1432
  if splash_damage_options.track_pre_explosion then
@@ -1093,7 +1453,9 @@ world.searchObjects({Object.Category.UNIT, Object.Category.STATIC}, tickVol, fun
1093
1453
  local preExplosionTargets = innerArgs[3] or {}
1094
1454
  local weaponName = innerArgs[4]
1095
1455
  local weaponPower = innerArgs[5]
1456
+ if splash_damage_options.debug == true then
1096
1457
  debugMsg("Starting post-explosion analysis for " .. weaponName .. " at " .. timer.getTime() .. "s")
1458
+ end
1097
1459
 
1098
1460
  --Scan all units in wider radius
1099
1461
  local postExplosionTargets = {}
@@ -1366,32 +1728,37 @@ function onWpnEvent(event)
1366
1728
  if event.weapon then
1367
1729
  local ordnance = event.weapon
1368
1730
  local typeName = trim(ordnance:getTypeName())
1731
+ if splash_damage_options.debug then
1369
1732
  env.info("Weapon fired: [" .. typeName .. "]")
1370
1733
  debugMsg("Weapon fired: [" .. typeName .. "]")
1371
-
1734
+ end
1372
1735
  if string.find(typeName, "weapons.shells") then
1736
+ if splash_damage_options.debug then
1373
1737
  debugMsg("Event shot, but not tracking: " .. typeName)
1374
1738
  env.info("SplashDamage: event shot, but not tracking: " .. typeName .. " (" .. event.initiator:getTypeName() .. ")")
1739
+ end
1375
1740
  return
1376
1741
  end
1377
1742
 
1743
+ --Check if weapon is in explTable before tracking
1378
1744
  if not explTable[typeName] then
1379
1745
  env.info("SplashDamage: " .. typeName .. " missing from script (" .. event.initiator:getTypeName() .. ")")
1380
1746
  if splash_damage_options.weapon_missing_message == true then
1381
1747
  trigger.action.outText("SplashDamage: " .. typeName .. " missing from script (" .. (event.initiator and event.initiator:isExist() and event.initiator:getTypeName() or "no initiator") .. ")", 3)
1382
- -- if mist and mist.utils and mist.utils.tableShow then --Only if MiST is present
1383
- -- local success, desc = pcall(mist.utils.tableShow, ordnance:getDesc())
1384
- -- if success then
1385
- -- debugMsg("desc for [" .. typeName .. "]: " .. desc)
1386
- -- else
1387
- -- debugMsg("Could not retrieve description for [" .. typeName .. "]. Object may no longer exist.")
1388
- -- end
1389
- -- end
1748
+ -- if mist and mist.utils and mist.utils.tableShow then --Only if MiST is present
1749
+ -- local success, desc = pcall(mist.utils.tableShow, ordnance:getDesc())
1750
+ -- if success then
1751
+ -- debugMsg("desc for [" .. typeName .. "]: " .. desc)
1752
+ -- else
1753
+ -- debugMsg("Could not retrieve description for [" .. typeName .. "]. Object may no longer exist.")
1754
+ -- end
1755
+ -- end
1390
1756
  env.info("Current keys in explTable:")
1391
1757
  for k, v in pairs(explTable) do
1392
1758
  env.info("Key: [" .. k .. "]")
1393
1759
  end
1394
1760
  end
1761
+ return --Skip tracking this weapon since its not in the table
1395
1762
  end
1396
1763
 
1397
1764
  if (ordnance:getDesc().category ~= 0) and event.initiator then
@@ -1634,7 +2001,7 @@ function addSplashDamageMenu()
1634
2001
  addValueAdjustmentCommands(infantryCantFireMenu, "infantry_cant_fire_health")
1635
2002
  local rocketMultiplierMenu = missionCommands.addSubMenu("Rocket Multiplier", debugGeneralMenu)
1636
2003
  addValueAdjustmentCommands(rocketMultiplierMenu, "rocket_multiplier")
1637
- --Page 2: Explosion
2004
+ --Page 2/3: Explosions
1638
2005
  local explosionCargoMenu = missionCommands.addSubMenu("Explosion Settings", splash_damage_menu)
1639
2006
  local staticDamageMenu = missionCommands.addSubMenu("Static Damage Boost", explosionCargoMenu)
1640
2007
  addValueAdjustmentCommands(staticDamageMenu, "static_damage_boost")
@@ -1642,8 +2009,7 @@ function addSplashDamageMenu()
1642
2009
  missionCommands.addCommand("Toggle Larger Explosions", explosionCargoMenu, toggleSplashDamageSetting, "larger_explosions")
1643
2010
  local blastRadiusMenu = missionCommands.addSubMenu("Blast Search Radius", explosionCargoMenu)
1644
2011
  addValueAdjustmentCommands(blastRadiusMenu, "blast_search_radius")
1645
- local cascadeThresholdMenu = missionCommands.addSubMenu("Cascade Damage Threshold", explosionCargoMenu)
1646
- addValueAdjustmentCommands(cascadeThresholdMenu, "cascade_damage_threshold")
2012
+
1647
2013
  local overallScalingMenu = missionCommands.addSubMenu("Overall Scaling", explosionCargoMenu)
1648
2014
  addValueAdjustmentCommands(overallScalingMenu, "overall_scaling")
1649
2015
  missionCommands.addCommand("Toggle Shaped Charge Effects", explosionCargoMenu, toggleSplashDamageSetting, "apply_shaped_charge_effects")
@@ -1652,13 +2018,16 @@ function addSplashDamageMenu()
1652
2018
  missionCommands.addCommand("Toggle Dynamic Blast Radius", explosionCargoMenu, toggleSplashDamageSetting, "use_dynamic_blast_radius")
1653
2019
  local dynamicBlastMenu = missionCommands.addSubMenu("Dynamic Blast Radius Modifier", explosionCargoMenu)
1654
2020
  addValueAdjustmentCommands(dynamicBlastMenu, "dynamic_blast_radius_modifier")
2021
+
2022
+ local explosionCargoMenu = missionCommands.addSubMenu("Cascade Settings", splash_damage_menu)
1655
2023
  local cascadeScalingMenu = missionCommands.addSubMenu("Cascade Scaling", explosionCargoMenu)
1656
2024
  addValueAdjustmentCommands(cascadeScalingMenu, "cascade_scaling")
1657
2025
  local cascadeExplodeThresholdMenu = missionCommands.addSubMenu("Cascade Explode Threshold", explosionCargoMenu)
1658
2026
  addValueAdjustmentCommands(cascadeExplodeThresholdMenu, "cascade_explode_threshold")
2027
+ local cascadeThresholdMenu = missionCommands.addSubMenu("Cascade Damage Threshold", explosionCargoMenu)
2028
+ addValueAdjustmentCommands(cascadeThresholdMenu, "cascade_damage_threshold")
1659
2029
 
1660
-
1661
- --Page 3: Cargo and Ordnance Protection
2030
+ --Page 4: Cargo and Ordnance Protection
1662
2031
  local explosionCargoMenu = missionCommands.addSubMenu("Cargo and Ordnance", splash_damage_menu)
1663
2032
  missionCommands.addCommand("Toggle Always Cascade Explode", explosionCargoMenu, toggleSplashDamageSetting, "always_cascade_explode")
1664
2033
  missionCommands.addCommand("Toggle Tracking & Cargo Effects", explosionCargoMenu, toggleSplashDamageSetting, "track_pre_explosion")
@@ -1668,8 +2037,13 @@ function addSplashDamageMenu()
1668
2037
  local ordnanceRadiusMenu = missionCommands.addSubMenu("Ordnance Protection Radius", explosionCargoMenu)
1669
2038
  addValueAdjustmentCommands(ordnanceRadiusMenu, "ordnance_protection_radius")
1670
2039
  missionCommands.addCommand("Toggle Snap To Ground If Destroyed By LE", explosionCargoMenu, toggleSplashDamageSetting, "snap_to_ground_if_destroyed_by_large_explosion")
1671
-
1672
- --Page 4: Debris Settings
2040
+ local ordnanceRadiusMenu = missionCommands.addSubMenu("Ordnance Protection Radius", explosionCargoMenu)
2041
+ local cargoThresholdMenu = missionCommands.addSubMenu("Max Snap Height", explosionCargoMenu)
2042
+ addValueAdjustmentCommands(cargoThresholdMenu, "max_snapped_height")
2043
+ missionCommands.addCommand("Toggle Recent Expl Track Snap", explosionCargoMenu, toggleSplashDamageSetting, "recent_large_explosion_snap")
2044
+
2045
+
2046
+ --Page 5: Debris Settings
1673
2047
  local debrisMenu = missionCommands.addSubMenu("Debris Settings", splash_damage_menu)
1674
2048
  missionCommands.addCommand("Toggle Debris Effects", debrisMenu, toggleSplashDamageSetting, "debris_effects")
1675
2049
  local debrisCountMinMenu = missionCommands.addSubMenu("Min Debris Count", debrisMenu)
@@ -1681,7 +2055,7 @@ function addSplashDamageMenu()
1681
2055
  local debrisPowerMenu = missionCommands.addSubMenu("Debris Power", debrisMenu)
1682
2056
  addValueAdjustmentCommands(debrisPowerMenu, "debris_power")
1683
2057
 
1684
- --Page 5: Cluster Settings
2058
+ --Page 6: Cluster Settings
1685
2059
  local clusterMenu = missionCommands.addSubMenu("Cluster Settings", splash_damage_menu)
1686
2060
  missionCommands.addCommand("Toggle Cluster Enabled", clusterMenu, toggleSplashDamageSetting, "cluster_enabled")
1687
2061
  local clusterBaseLengthMenu = missionCommands.addSubMenu("Cluster Base Length", clusterMenu)
@@ -1699,18 +2073,79 @@ function addSplashDamageMenu()
1699
2073
  missionCommands.addCommand("Toggle Bomblet Reduction Modifier", clusterMenu, toggleSplashDamageSetting, "cluster_bomblet_reductionmodifier")
1700
2074
  local clusterBombletDamageMenu = missionCommands.addSubMenu("Bomblet Damage Modifier", clusterMenu)
1701
2075
  addValueAdjustmentCommands(clusterBombletDamageMenu, "cluster_bomblet_damage_modifier")
2076
+
2077
+ --Page 7: Giant Explosion Settings
2078
+ local giantExplosionMenu = missionCommands.addSubMenu("Giant Explosion Settings", splash_damage_menu)
2079
+ missionCommands.addCommand("Toggle Giant Explosion", giantExplosionMenu, toggleSplashDamageSetting, "giant_explosion_enabled")
2080
+ missionCommands.addCommand("Toggle Static Target", giantExplosionMenu, toggleSplashDamageSetting, "giant_explosion_target_static")
2081
+ for name, target in pairs(giantExplosionTargets) do
2082
+ local displayName = name:gsub("GiantExplosionTarget", "GiantExplosionTarget")
2083
+ missionCommands.addCommand("Detonate " .. displayName, giantExplosionMenu, function()
2084
+ trigger.action.setUserFlag(displayName, 1)
2085
+ end)
2086
+ end
2087
+ missionCommands.addCommand("Detonate All Giant Targets", giantExplosionMenu, function()
2088
+ for name, target in pairs(giantExplosionTargets) do
2089
+ local flagName = name:gsub("GiantExplosionTarget", "GiantExplosionTarget")
2090
+ trigger.action.setUserFlag(flagName, 1)
2091
+ end
2092
+ end)
2093
+ local powerMenu = missionCommands.addSubMenu("Explosion Power", giantExplosionMenu)
2094
+ addValueAdjustmentCommands(powerMenu, "giant_explosion_power")
2095
+ local scaleMenu = missionCommands.addSubMenu("Size Scale", giantExplosionMenu)
2096
+ missionCommands.addCommand("+0.1", scaleMenu, updateSplashDamageSetting, "giant_explosion_scale", 0.1)
2097
+ missionCommands.addCommand("+0.5", scaleMenu, updateSplashDamageSetting, "giant_explosion_scale", 0.5)
2098
+ missionCommands.addCommand("-0.1", scaleMenu, updateSplashDamageSetting, "giant_explosion_scale", -0.1)
2099
+ missionCommands.addCommand("-0.5", scaleMenu, updateSplashDamageSetting, "giant_explosion_scale", -0.5)
2100
+ local durationMenu = missionCommands.addSubMenu("Duration", giantExplosionMenu)
2101
+ missionCommands.addCommand("+0.25s", durationMenu, updateSplashDamageSetting, "giant_explosion_duration", 0.25)
2102
+ missionCommands.addCommand("-0.25s", durationMenu, updateSplashDamageSetting, "giant_explosion_duration", -0.25)
2103
+ local countMenu = missionCommands.addSubMenu("Explosion Count", giantExplosionMenu)
2104
+ addValueAdjustmentCommands(countMenu, "giant_explosion_count")
1702
2105
 
1703
2106
  end
1704
2107
 
1705
2108
  if (script_enable == 1) then
1706
- gameMsg("SPLASH DAMAGE 3.0 SCRIPT RUNNING")
1707
- env.info("SPLASH DAMAGE 2. SCRIPT RUNNING")
2109
+ gameMsg("SPLASH DAMAGE 3.1 SCRIPT RUNNING")
2110
+ env.info("SPLASH DAMAGE 3.1 SCRIPT RUNNING")
1708
2111
 
1709
2112
  timer.scheduleFunction(function()
1710
2113
  protectedCall(track_wpns)
1711
2114
  return timer.getTime() + refreshRate
1712
2115
  end, {}, timer.getTime() + refreshRate)
1713
2116
 
2117
+ if splash_damage_options.giant_explosion_enabled then
2118
+ giantExplosionTargets = {} -- Ensure it’s fresh
2119
+ local targetCount = 0
2120
+ for coa = 0, 2 do
2121
+ local groups = coalition.getGroups(coa)
2122
+ if groups then
2123
+ for _, group in pairs(groups) do
2124
+ local units = group:getUnits()
2125
+ if units then
2126
+ for _, unit in pairs(units) do
2127
+ local name = unit:getName()
2128
+ if name:find("GiantExplosionTarget") then
2129
+ local pos = unit:getPosition().p
2130
+ giantExplosionTargets[name] = {obj = unit, pos = pos}
2131
+ if splash_damage_options.giant_explosion_target_static then
2132
+ giantExplosionTargets[name].pos = pos
2133
+ end
2134
+ debugMsg("Found GiantExplosionTarget: " .. name .. " at X:" .. pos.x .. " Y:" .. pos.y .. " Z:" .. pos.z)
2135
+ targetCount = targetCount + 1
2136
+ end
2137
+ end
2138
+ end
2139
+ end
2140
+ end
2141
+ end
2142
+ debugMsg("Total GiantExplosionTargets found: " .. targetCount)
2143
+ timer.scheduleFunction(checkGiantExplosionFlag, {}, timer.getTime() + splash_damage_options.giant_explosion_poll_rate)
2144
+ if not splash_damage_options.giant_explosion_target_static then
2145
+ timer.scheduleFunction(updateTargetPosition, {}, timer.getTime() + 1.0)
2146
+ end
2147
+ end
2148
+
1714
2149
  world.addEventHandler(WpnHandler)
1715
2150
  addSplashDamageMenu()
1716
2151
  end