@jtff/miztemplate-lib 3.7.2 → 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.
- package/lua/lib/HoundElint.lua +3469 -1621
- package/lua/lib/Moose_.lua +310 -263
- package/lua/lib/{Splash_Damage_3.0.lua → Splash_Damage_main.lua} +485 -50
- package/package.json +4 -4
- package/scripts/inject-scripts.js +2 -2
|
@@ -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"] =
|
|
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"] =
|
|
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
|
-
--
|
|
142
|
+
--Cluster bomb settings
|
|
131
143
|
["cluster_enabled"] = false,
|
|
132
|
-
["cluster_base_length"] = 150, --
|
|
133
|
-
["cluster_base_width"] = 200, --
|
|
134
|
-
["cluster_max_length"] = 300, --
|
|
135
|
-
["cluster_max_width"] = 400, --
|
|
136
|
-
["cluster_min_length"] = 100, --
|
|
137
|
-
["cluster_min_width"] = 150, --
|
|
138
|
-
["cluster_bomblet_reductionmodifier"] = true, --
|
|
139
|
-
["cluster_bomblet_damage_modifier"] = 1, --
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
-
--
|
|
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
|
-
--
|
|
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
|
-
--
|
|
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
|
-
--
|
|
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
|
-
--
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
--
|
|
1383
|
-
--
|
|
1384
|
-
--
|
|
1385
|
-
--
|
|
1386
|
-
--
|
|
1387
|
-
--
|
|
1388
|
-
--
|
|
1389
|
-
--
|
|
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:
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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.
|
|
1707
|
-
env.info("SPLASH DAMAGE
|
|
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
|