Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 85 additions & 5 deletions scripts/RotorOps.lua
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
RotorOps = {}
RotorOps.version = "1.4.5"
RotorOps.version = "1.5.0"
local debug = false


Expand Down Expand Up @@ -51,6 +51,7 @@ RotorOps.farp_pickups = true --allow ctld troop pickup at FARPs
RotorOps.enable_staging_pickzones = true
RotorOps.persistent_tasking = false --prevent the script from restasking in a loop --might help with odd movement patterns between zones
RotorOps.halt_convoy_without_airsupport = true --if true, attacking convoys not proceed in zone without player helicopters nearby. Does not affect defensive missions
RotorOps.zone_structures_destruction_percent = 30 --percentage of structures that must be destroyed in order to clear the zone

--RotorOps settings that are safe to change only in the script config option in the scenario config file
RotorOps.draw_conflict_zones = true
Expand Down Expand Up @@ -92,6 +93,7 @@ RotorOps.eventHandler = {}
local commandDB = {}
local game_message_buffer = {}
local active_zone_initial_defenders
local active_zone_initial_structures_health
local initial_stage_units
local apcs = {} --table to keep track of infantry vehicles
local low_units_message_fired = false
Expand Down Expand Up @@ -521,6 +523,43 @@ function RotorOps.sortOutInfantry(mixed_units)
return {infantry = _infantry, not_infantry = _not_infantry}
end

function RotorOps.sortOutStatics(mixed_statics)
local targets = {}
local not_targets = {}
--- statics that have :getCategory() == UNIT or :getCategory() == BASE are targets
debugTable(mixed_statics)
for index, static in pairs(mixed_statics) do
--ensure unit exists
env.info("Iterating through statics, index: "..index)
if static == nil then
env.info("RotorOps: "..index.." is nil")
end

success, err = pcall(function() -- it was very tricky to access the 'Big Smoke' object properties without breaking the script
if static:getDesc() == nil then
env.info("RotorOps: "..index.." has no description")
end
end)
if err then
env.info("RotorOps: err "..static:getName().." has no description")
end

if not err and static:isExist() and static.getDesc and static.getID and static.getName and static.getCategory and Object.getCategory(static) == Object.Category.STATIC then
env.info("RotorOps: "..static:getName().." is a static object")
if static:getCategory() == Object.Category.STATIC and (static:getDesc().category == StaticObject.Category.UNIT or static:getDesc().category == StaticObject.Category.BASE or static:getDesc().category == StaticObject.Category.WEAPON or static:getDesc().category == StaticObject.Category.VOID) then
targets[#targets + 1] = static
env.info("RotorOps: "..static:getName().." is a static target")
else
not_targets[#not_targets + 1] = static
env.info("RotorOps: "..static:getName().." is NOT a static target")
end

end
end
return {targets = targets, not_targets = not_targets}
end



function RotorOps.getValidUnitFromGroup(grp)
if grp == nil then return end
Expand Down Expand Up @@ -1105,10 +1144,26 @@ function RotorOps.assessUnitsInZone(var)
local defending_ground_units
local defending_infantry
local defending_vehicles
local defending_structures
local attacking_ground_units
local attacking_infantry
local attacking_vehicles

local get_total_health = function(units)
env.info("RotorOps: get_total_health() called on units: "..#units)
local total_health = 0
-- if not a table, or table is empty return 0
if type(units) ~= "table" or #units == 0 then
return 0
end
for index, unit in pairs(units) do
if unit:isExist() and unit:getLife() then
total_health = total_health + unit:getLife()
env.info("RotorOps: "..unit:getName().." health: "..unit:getLife().." total health: "..total_health)
end
end
return total_health
end

--find and sort units found in the active zone
if RotorOps.defending then
Expand All @@ -1122,6 +1177,8 @@ function RotorOps.assessUnitsInZone(var)
defending_ground_units = mist.getUnitsInZones(mist.makeUnitTable({'[red][vehicle]'}), {RotorOps.active_zone})
defending_infantry = RotorOps.sortOutInfantry(defending_ground_units).infantry
defending_vehicles = RotorOps.sortOutInfantry(defending_ground_units).not_infantry
local defending_statics = mist.getUnitsInZones(mist.makeUnitTable({'[red][static]'}), {RotorOps.active_zone})
defending_structures = RotorOps.sortOutStatics(defending_statics).targets
attacking_ground_units = mist.getUnitsInZones(mist.makeUnitTable({'[blue][vehicle]'}), {RotorOps.active_zone})
attacking_infantry = RotorOps.sortOutInfantry(attacking_ground_units).infantry
attacking_vehicles = RotorOps.sortOutInfantry(attacking_ground_units).not_infantry
Expand Down Expand Up @@ -1237,6 +1294,9 @@ function RotorOps.assessUnitsInZone(var)
RotorOps.inf_spawns_avail = math.ceil(RotorOps.inf_spawns_avail)
end

--get the health of the defending structures in the zone
active_zone_initial_structures_health = get_total_health(defending_structures) or 0
env.info("ROTOR OPS: initial defenders: "..#active_zone_initial_defenders..", initial structures: "..#defending_structures.." health: "..active_zone_initial_structures_health)
env.info("ROTOR OPS: zone activated: "..RotorOps.active_zone..", inf spawns avail:"..RotorOps.inf_spawns_avail..", spawn zones:"..#inf_spawn_zones)
end

Expand All @@ -1245,11 +1305,31 @@ function RotorOps.assessUnitsInZone(var)
--if #active_zone_initial_defenders == 0 then active_zone_initial_defenders = 1 end --prevent divide by zero
local defenders_remaining_percent = math.floor((#defending_ground_units / #active_zone_initial_defenders) * 100)

if #defending_ground_units <= RotorOps.max_units_left then --if we should declare the zone cleared
--structures/assets
local defending_structures_dead_health = math.floor(active_zone_initial_structures_health * (RotorOps.zone_structures_destruction_percent / 100))
local defending_structures_current_health = get_total_health(defending_structures) or 0
local remaining_health = defending_structures_current_health - defending_structures_dead_health

-- Ensure remaining health is not negative
if remaining_health < 0 then
remaining_health = 0
end

-- Ensure denominator is not zero before calculating percentage
local denominator = active_zone_initial_structures_health - defending_structures_dead_health
local defending_structures_remaining_health_percent = 0
if denominator > 0 then
defending_structures_remaining_health_percent = math.floor((remaining_health / denominator) * 100)
end
env.info("ROTOROPS: dead health: "..defending_structures_dead_health..", remaining health: "..remaining_health..", initial health: "..active_zone_initial_structures_health)
env.info("ROTOROPS: structures remaining percent: "..defending_structures_remaining_health_percent.." current health: "..defending_structures_current_health)

if #defending_ground_units <= RotorOps.max_units_left and defending_structures_remaining_health_percent <= 1 then --if we should declare the zone cleared
active_zone_initial_defenders = nil
active_zone_initial_structures_health = nil
defenders_remaining_percent = 0
trigger.action.setUserFlag(defenders_status_flag, 0) --set the zone's flag to cleared
trigger.action.setUserFlag(zone_defenders_flags[RotorOps.active_zone_index], 0) --set the zone's flag to cleared
trigger.action.setUserFlag(zone_defenders_flags[RotorOps.active_zone_index], 0) --set the zone's flag to cleared
if RotorOps.defending == true then
RotorOps.gameMsg(RotorOps.gameMsgs.enemy_cleared_zone, RotorOps.active_zone_index)
else
Expand Down Expand Up @@ -1409,10 +1489,10 @@ function RotorOps.assessUnitsInZone(var)
local body = ""
if RotorOps.defending == true then
header = "[DEFEND "..RotorOps.active_zone .. "] "
body = "BLUE: "..#defending_infantry.. " infantry, " .. #defending_vehicles.." vehicles. RED CONVOY: " .. #staged_units_remaining .." vehicles. ["..percent_staged_remain.."%]"
body = "BLUE: "..#defending_infantry.. " inf, " .. #defending_vehicles.." vehicles, ".. defending_structures_remaining_health_percent .."% assets. RED CONVOY: " .. #staged_units_remaining .." vehicles. ["..percent_staged_remain.."%]"
else
header = "[ATTACK "..RotorOps.active_zone .. "] "
body = "RED: " ..#defending_infantry.. " infantry, " .. #defending_vehicles .. " vehicles. BLUE CONVOY: " .. #staged_units_remaining .." vehicles. ["..percent_staged_remain.."%]"
body = "RED: " ..#defending_infantry.. " inf, " .. #defending_vehicles .. " vehicles, ".. defending_structures_remaining_health_percent .."% assets. BLUE CONVOY: " .. #staged_units_remaining .." vehicles. ["..percent_staged_remain.."%]"
end

if clear_text_index == 1 and not RotorOps.defending then
Expand Down