Merge pull request #12 from spencershepard/develop

Develop
This commit is contained in:
spencershepard 2022-01-19 22:41:18 -08:00 committed by GitHub
commit a30d251ebd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
44 changed files with 334 additions and 85 deletions

View File

@ -1,22 +1,34 @@
RotorOps = {} RotorOps = {}
RotorOps.version = "1.0.11" RotorOps.version = "1.2.1"
--RotorOps settings that are safe to change dynamically (ideally from the mission editor in DO SCRIPT for ease of use)
---[[ROTOROPS OPTIONS]]---
--- Protip: change these options from the mission editor rather than changing the script file itself. See documentation on github for details.
--RotorOps settings that are safe to change dynamically (ideally from the mission editor in DO SCRIPT for portability). You can change these while the script is running, at any time.
RotorOps.voice_overs = true RotorOps.voice_overs = true
RotorOps.ground_speed = 60 --max speed for ground vehicles moving between zones RotorOps.ground_speed = 60 --max speed for ground vehicles moving between zones
RotorOps.zone_status_display = true --constantly show units remaining and zone status on screen RotorOps.zone_status_display = true --constantly show units remaining and zone status on screen
RotorOps.max_units_left = 0 --allow clearing the zone when a few units are left to prevent frustration with units getting stuck in buildings etc RotorOps.max_units_left = 0 --allow clearing the zone when a few units are left to prevent frustration with units getting stuck in buildings etc
RotorOps.force_offroad = false --affects "move_to_zone" tasks only RotorOps.force_offroad = false --affects "move_to_zone" tasks only
RotorOps.apcs_spawn_infantry = false --apcs will unload troops when arriving to a new zone
--RotorOps settings that are safe to change only before calling setupConflict()
--RotorOps settings that are proabably safe to change
RotorOps.transports = {'UH-1H', 'Mi-8MT', 'Mi-24P', 'SA342M', 'SA342L', 'SA342Mistral'} --players flying these will have ctld transport access RotorOps.transports = {'UH-1H', 'Mi-8MT', 'Mi-24P', 'SA342M', 'SA342L', 'SA342Mistral'} --players flying these will have ctld transport access
RotorOps.auto_push = true --should attacking ground units move to the next zone after clearing? RotorOps.auto_push = true --should attacking ground units move to the next zone after clearing?
RotorOps.CTLD_crates = false RotorOps.CTLD_crates = false
RotorOps.CTLD_sound_effects = true --sound effects for troop pickup/dropoffs
RotorOps.exclude_ai_group_name = "noai" --include this somewhere in a group name to exclude the group from being tasked in the active zone
---[[END OF OPTIONS]]---
--RotorOps variables that are safe to read only --RotorOps variables that are safe to read only
RotorOps.game_states = {not_started = 0, alpha_active = 1, bravo_active = 2, charlie_active = 3, delta_active = 4, won = 99} --game level user flag will use these values RotorOps.game_states = {not_started = 0, alpha_active = 1, bravo_active = 2, charlie_active = 3, delta_active = 4, lost = 98, won = 99} --game level user flag will use these values
RotorOps.game_state = 0 RotorOps.game_state = 0
RotorOps.zones = {} RotorOps.zones = {}
RotorOps.active_zone = "" --name of the active zone RotorOps.active_zone = "" --name of the active zone
@ -24,22 +36,27 @@ RotorOps.active_zone_index = 0
RotorOps.game_state_flag = 1 --user flag to store the game state RotorOps.game_state_flag = 1 --user flag to store the game state
RotorOps.staging_zone = "" RotorOps.staging_zone = ""
RotorOps.ctld_pickup_zones = {} --keep track of ctld zones we've added, mainly for map markup RotorOps.ctld_pickup_zones = {} --keep track of ctld zones we've added, mainly for map markup
RotorOps.ai_red_infantry_groups = {} RotorOps.ai_defending_infantry_groups = {}
RotorOps.ai_blue_infantry_groups = {} RotorOps.ai_attacking_infantry_groups = {}
RotorOps.ai_red_vehicle_groups = {} RotorOps.ai_defending_vehicle_groups = {}
RotorOps.ai_blue_vehicle_groups = {} RotorOps.ai_attacking_vehicle_groups = {}
RotorOps.ai_tasks = {} RotorOps.ai_tasks = {}
RotorOps.defending = false
trigger.action.outText("ROTOR OPS STARTED: "..RotorOps.version, 5) trigger.action.outText("ROTOR OPS STARTED: "..RotorOps.version, 5)
env.info("ROTOR OPS STARTED: "..RotorOps.version) env.info("ROTOR OPS STARTED: "..RotorOps.version)
local staged_units --table of ground units that started in the staging zone RotorOps.staged_units = {} --table of ground units that started in the staging zone
RotorOps.eventHandler = {}
local commandDB = {} local commandDB = {}
local game_message_buffer = {} local game_message_buffer = {}
local active_zone_initial_enemy_units local active_zone_initial_defenders
local apcs = {} --table to keep track of infantry vehicles
local low_units_message_fired = false
local gameMsgs = {
RotorOps.gameMsgs = {
push = { push = {
{'ALL GROUND UNITS, PUSH TO THE ACTIVE ZONE!', 'push_next_zone.ogg'}, {'ALL GROUND UNITS, PUSH TO THE ACTIVE ZONE!', 'push_next_zone.ogg'},
{'ALL GROUND UNITS, PUSH TO ALPHA!', 'push_alpha.ogg'}, {'ALL GROUND UNITS, PUSH TO ALPHA!', 'push_alpha.ogg'},
@ -74,10 +91,89 @@ local gameMsgs = {
{'GET OUR TROOPS TO CHARLIE!', 'get_troops_charlie.ogg'}, {'GET OUR TROOPS TO CHARLIE!', 'get_troops_charlie.ogg'},
{'GET OUR TROOPS TO DELTA!', 'get_troops_delta.ogg'}, {'GET OUR TROOPS TO DELTA!', 'get_troops_delta.ogg'},
}, },
jtac = {
{'JTAC DROPPED!', 'jtac_dropped.ogg'},
},
enemy_almost_cleared = {
{'ENEMY HAS NEARLY CAPTURED THE ZONE!', 'enemy_almost_cleared.ogg'},
{'ENEMY HAS NEARLY CAPTURED THE ZONE!', 'enemy_decimating_forces.ogg'},
{'ENEMY HAS NEARLY CAPTURED THE ZONE!', 'enemy_destroying_ground.ogg'},
},
almost_cleared = {
{'WE HAVE NEARLY CLEARED THE ZONE!', 'almost_cleared.ogg'},
{'WE HAVE NEARLY CLEARED THE ZONE!', 'theyre_weak.ogg'},
{'WE HAVE NEARLY CLEARED THE ZONE!', 'tearing_them_up.ogg'},
},
enemy_pushing = {
{'ENEMY PUSHING TO THE NEXT ZONE!', 'enemy_pushing_zone.ogg'},
{'ENEMY PUSHING TO ALPHA!', 'enemy_pushing_alpha.ogg'},
{'ENEMY PUSHING TO BRAVO!', 'enemy_pushing_bravo.ogg'},
{'ENEMY PUSHING TO CHARLIE!', 'enemy_pushing_charlie.ogg'},
{'ENEMY PUSHING TO DELTA!', 'enemy_pushing_delta.ogg'},
},
start_defense = {
{'SUPPORT THE WAR ON THE GROUND! PUSH BACK AGAINST THE ENEMY!', 'push_back.ogg'},
},
failure = {
{'GROUND MISSION FAILED!', 'mission_failure.ogg'},
},
friendly_troops_dropped = {
{'FRIENDLY TROOPS DROPPED INTO ZONE!', 'friendly_troops_dropped_active.ogg'},
},
hold_ground = {
{'HOLD GROUND TO WIN!', 'hold_our_ground.ogg'},
},
enemy_cleared_zone = {
{'ENEMY TOOK THE ACTIVE ZONE!', 'enemy_destroying_us.ogg'},
{'ENEMY TOOK ALPHA!', 'enemy_destroying_us.ogg'},
{'ENEMY TOOK BRAVO!', 'enemy_destroying_us.ogg'},
{'ENEMY TOOK CHARLIE!', 'enemy_destroying_us.ogg'},
{'ENEMY TOOK DELTA!', 'enemy_destroying_us.ogg'},
},
} }
local sound_effects = {
["troop_pickup"] = {'troops_load_ao.ogg', 'troops_load_ready.ogg', 'troops_load_to_action.ogg',force_offroad = true},
["troop_dropoff"] = {'troops_unload_thanks.ogg', 'troops_unload_everybody_off.ogg', 'troops_unload_get_off.ogg', 'troops_unload_here_we_go.ogg', 'troops_unload_moving_out.ogg',},
}
function RotorOps.eventHandler:onEvent(event)
if (world.event.S_EVENT_ENGINE_STARTUP == event.id) then --play some sound files when a player starts engines
local initaitor = event.initiator:getGroup():getID()
if RotorOps.defending then
trigger.action.outSoundForGroup(initaitor , RotorOps.gameMsgs.enemy_pushing[RotorOps.active_zone_index + 1][2])
else
trigger.action.outSoundForGroup(initaitor , RotorOps.gameMsgs.push[RotorOps.active_zone_index + 1][2])
end
end
end
function RotorOps.registerCtldCallbacks(var)
ctld.addCallback(function(_args)
local action = _args.action
local unit = _args.unit
local picked_troops = _args.onboard
local dropped_troops = _args.unloaded
--trigger.action.outText("dbg: ".. mist.utils.tableShow(_args), 5)
if action == "load_troops" or action == "extract_troops" then
trigger.action.outSoundForGroup(unit:getGroup():getID() , sound_effects.troop_pickup[math.random(1, #sound_effects.troop_pickup)])
elseif action == "unload_troops_zone" or action == "dropped_troops" then
trigger.action.outSoundForGroup(unit:getGroup():getID() , sound_effects.troop_dropoff[math.random(1, #sound_effects.troop_dropoff)])
if RotorOps.isUnitInZone(unit, RotorOps.active_zone) then
local id = timer.scheduleFunction(RotorOps.gameMsgHandler, RotorOps.gameMsgs.friendly_troops_dropped, timer.getTime() + 6) --allow some extra time so we don't step on the player's troop/unload sound effects
end
if dropped_troops.jtac == true then
local id = timer.scheduleFunction(RotorOps.gameMsgHandler, RotorOps.gameMsgs.jtac, timer.getTime() + 6) --allow some extra time so we don't step on the player's troop/unload sound effects
end
end
end)
end
---UTILITY FUNCTIONS--- ---UTILITY FUNCTIONS---
local function debugMsg(text) local function debugMsg(text)
@ -98,7 +194,12 @@ end
local function tableHasKey(table,key) local function tableHasKey(table,key)
if table then
return table[key] ~= nil return table[key] ~= nil
else
env.warning("table parameter not provided")
return nil
end
end end
@ -131,7 +232,7 @@ local function getDistance(point1, point2)
return distance return distance
end end
local function isUnitInZone(unit, zone_name) function RotorOps.isUnitInZone(unit, zone_name)
local zone = trigger.misc.getZone(zone_name) local zone = trigger.misc.getZone(zone_name)
local distance = getDistance(unit:getPoint(), zone.point) local distance = getDistance(unit:getPoint(), zone.point)
if distance <= zone.radius then if distance <= zone.radius then
@ -156,17 +257,26 @@ function RotorOps.groupsFromUnits(units, table)
end end
local function gameMsg(event, _index) function RotorOps.gameMsg(event, _index)
if not event then
env.warning("event parameter is nil")
return
end
local index = 1 local index = 1
if _index ~= nill then if _index ~= nil then
index = _index + 1 index = _index + 1
end end
if tableHasKey(event, index) then if tableHasKey(event, index) then
game_message_buffer[#game_message_buffer + 1] = {event[index][1], event[index][2]} game_message_buffer[#game_message_buffer + 1] = {event[index][1], event[index][2]}
else env.info("ROTOR OPS could not find entry for "..key) else env.warning("ROTOR OPS could not find sound file entry")
end end
end end
function RotorOps.gameMsgHandler(event) --for use with scheduled functions
RotorOps.gameMsg(event)
end
local function processMsgBuffer(vars) local function processMsgBuffer(vars)
if #game_message_buffer > 0 then if #game_message_buffer > 0 then
@ -239,7 +349,7 @@ end
--Easy way to deploy troops from a vehicle with waypoint action. Spawns from the first valid unit found in a group --Easy way to deploy troops from a vehicle with waypoint action. Spawns from the first valid unit found in a group
function RotorOps.deployTroops(quantity, target_group) function RotorOps.deployTroops(quantity, target_group, announce)
local target_group_obj local target_group_obj
if type(target_group) == 'string' then if type(target_group) == 'string' then
target_group_obj = Group.getByName(target_group) target_group_obj = Group.getByName(target_group)
@ -257,17 +367,18 @@ function RotorOps.deployTroops(quantity, target_group)
-- voiceover trigger stuff -- voiceover trigger stuff
for index, zone in pairs(RotorOps.zones) for index, zone in pairs(RotorOps.zones)
do do
if isUnitInZone(valid_unit, zone.name) then if RotorOps.isUnitInZone(valid_unit, zone.name) and announce == true then
if side == "red" then if side == "red" then
gameMsg(gameMsgs.troops_dropped, index) RotorOps.gameMsg(RotorOps.gameMsgs.troops_dropped, index)
else else
gameMsg(gameMsgs.friendly_troops_dropped, index) RotorOps.gameMsg(RotorOps.gameMsgs.friendly_troops_dropped)
end end
end end
end end
end end
--see list of tasks in aiExecute. Zone is optional for many tasks --see list of tasks in aiExecute. Zone is optional for many tasks
function RotorOps.aiTask(grp, task, zone) function RotorOps.aiTask(grp, task, zone)
local group_name local group_name
@ -276,6 +387,9 @@ function RotorOps.aiTask(grp, task, zone)
else else
group_name = Group.getName(grp) group_name = Group.getName(grp)
end end
if string.find(group_name:lower(), RotorOps.exclude_ai_group_name:lower()) then --exclude groups that the user specifies with a special group name
return
end
if tableHasKey(RotorOps.ai_tasks, group_name) == true then --if we already have this group in our list to manage if tableHasKey(RotorOps.ai_tasks, group_name) == true then --if we already have this group in our list to manage
--debugMsg("timer already exists, updating task for "..group_name.." : ".. RotorOps.ai_tasks[group_name].ai_task.." to "..task) --debugMsg("timer already exists, updating task for "..group_name.." : ".. RotorOps.ai_tasks[group_name].ai_task.." to "..task)
RotorOps.ai_tasks[group_name].ai_task = task RotorOps.ai_tasks[group_name].ai_task = task
@ -455,14 +569,14 @@ function RotorOps.aiExecute(vars)
if task == "patrol" then if task == "patrol" then
local vars = {} local vars = {}
vars.grp = Group.getByName(group_name) vars.grp = Group.getByName(group_name)
vars.radius = 500 vars.radius = 300
RotorOps.patrolRadius(vars) --takes a group object, not name RotorOps.patrolRadius(vars) --takes a group object, not name
update_interval = math.random(40,70) update_interval = math.random(150,200)
elseif task == "aggressive" then elseif task == "aggressive" then
local vars = {} local vars = {}
vars.grp = Group.getByName(group_name) vars.grp = Group.getByName(group_name)
vars.radius = 5000 vars.radius = 5000
update_interval = math.random(20,40) update_interval = math.random(60,90)
RotorOps.chargeEnemy(vars) --takes a group object, not name RotorOps.chargeEnemy(vars) --takes a group object, not name
elseif task == "clear_zone" then elseif task == "clear_zone" then
local vars = {} local vars = {}
@ -501,61 +615,88 @@ end
function RotorOps.assessUnitsInZone(var) function RotorOps.assessUnitsInZone(var)
if RotorOps.game_state == RotorOps.game_states.not_started then return end if RotorOps.game_state == RotorOps.game_states.not_started then return end
--find and sort units found in the active zone
local red_ground_units = mist.getUnitsInZones(mist.makeUnitTable({'[red][vehicle]'}), {RotorOps.active_zone}) local defending_ground_units
local red_infantry = RotorOps.sortOutInfantry(red_ground_units).infantry local defending_infantry
local red_vehicles = RotorOps.sortOutInfantry(red_ground_units).not_infantry local defending_vehicles
local blue_ground_units = mist.getUnitsInZones(mist.makeUnitTable({'[blue][vehicle]'}), {RotorOps.active_zone}) local attacking_ground_units
local blue_infantry = RotorOps.sortOutInfantry(blue_ground_units).infantry local attacking_infantry
local blue_vehicles = RotorOps.sortOutInfantry(blue_ground_units).not_infantry local attacking_vehicles
--ground unit ai stuff
RotorOps.ai_red_infantry_groups = RotorOps.groupsFromUnits(red_infantry)
RotorOps.ai_blue_infantry_groups = RotorOps.groupsFromUnits(blue_infantry) --find and sort units found in the active zone
RotorOps.ai_red_vehicle_groups = RotorOps.groupsFromUnits(red_vehicles) if RotorOps.defending then
RotorOps.ai_blue_vehicle_groups = RotorOps.groupsFromUnits(blue_vehicles) defending_ground_units = mist.getUnitsInZones(mist.makeUnitTable({'[blue][vehicle]'}), {RotorOps.active_zone})
defending_infantry = RotorOps.sortOutInfantry(defending_ground_units).infantry
defending_vehicles = RotorOps.sortOutInfantry(defending_ground_units).not_infantry
attacking_ground_units = mist.getUnitsInZones(mist.makeUnitTable({'[red][vehicle]'}), {RotorOps.active_zone})
attacking_infantry = RotorOps.sortOutInfantry(attacking_ground_units).infantry
attacking_vehicles = RotorOps.sortOutInfantry(attacking_ground_units).not_infantry
else --attacking
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
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
end
for index, group in pairs(RotorOps.ai_red_infantry_groups) do
--ground unit ai stuff
RotorOps.ai_defending_infantry_groups = RotorOps.groupsFromUnits(defending_infantry)
RotorOps.ai_defending_vehicle_groups = RotorOps.groupsFromUnits(defending_vehicles)
RotorOps.ai_attacking_infantry_groups = RotorOps.groupsFromUnits(attacking_infantry)
RotorOps.ai_attacking_vehicle_groups = RotorOps.groupsFromUnits(attacking_vehicles)
for index, group in pairs(RotorOps.ai_defending_infantry_groups) do
if group then if group then
RotorOps.aiTask(group, "patrol") RotorOps.aiTask(group, "patrol")
end end
end end
for index, group in pairs(RotorOps.ai_blue_infantry_groups) do for index, group in pairs(RotorOps.ai_attacking_infantry_groups) do
if group then if group then
RotorOps.aiTask(group, "clear_zone", RotorOps.active_zone) RotorOps.aiTask(group, "clear_zone", RotorOps.active_zone)
end end
end end
for index, group in pairs(RotorOps.ai_blue_vehicle_groups) do for index, group in pairs(RotorOps.ai_attacking_vehicle_groups) do
if group then if group then
RotorOps.aiTask(group, "clear_zone", RotorOps.active_zone) RotorOps.aiTask(group, "clear_zone", RotorOps.active_zone)
end end
end end
--FIRES ONCE PER ZONE ACTIVATION
--let's compare the defending units in zone vs their initial numbers and set a game flag --let's compare the defending units in zone vs their initial numbers and set a game flag
if not active_zone_initial_enemy_units then if not active_zone_initial_defenders then
--debugMsg("taking stock of the active zone") --debugMsg("taking stock of the active zone")
active_zone_initial_enemy_units = red_ground_units active_zone_initial_defenders = defending_ground_units
low_units_message_fired = false
env.info("ROTOR OPS: zone activated: "..RotorOps.active_zone)
end end
local defenders_status_flag = RotorOps.zones[RotorOps.active_zone_index].defenders_status_flag local defenders_status_flag = RotorOps.zones[RotorOps.active_zone_index].defenders_status_flag
if #active_zone_initial_enemy_units == 0 then active_zone_initial_enemy_units = 1 end --prevent divide by zero --if #active_zone_initial_defenders == 0 then active_zone_initial_defenders = 1 end --prevent divide by zero
local defenders_remaining_percent = math.floor((#red_ground_units / #active_zone_initial_enemy_units) * 100) local defenders_remaining_percent = math.floor((#defending_ground_units / #active_zone_initial_defenders) * 100)
if #red_ground_units <= RotorOps.max_units_left then --if we should declare the zone cleared if #defending_ground_units <= RotorOps.max_units_left then --if we should declare the zone cleared
active_zone_initial_enemy_units = nil active_zone_initial_defenders = nil
defenders_remaining_percent = 0 defenders_remaining_percent = 0
trigger.action.setUserFlag(defenders_status_flag, 0) --set the zone's flag to cleared trigger.action.setUserFlag(defenders_status_flag, 0) --set the zone's flag to cleared
gameMsg(gameMsgs.cleared, RotorOps.active_zone_index) if RotorOps.defending == true then
RotorOps.gameMsg(RotorOps.gameMsgs.enemy_cleared_zone, RotorOps.active_zone_index)
else
RotorOps.gameMsg(RotorOps.gameMsgs.cleared, RotorOps.active_zone_index)
end
if RotorOps.auto_push then --push units to the next zone if RotorOps.auto_push then --push units to the next zone
RotorOps.setActiveZone(RotorOps.active_zone_index + 1) RotorOps.setActiveZone(RotorOps.active_zone_index + 1)
end end
else else
trigger.action.setUserFlag(defenders_status_flag, defenders_remaining_percent) --set the zones flag to indicate the status of remaining enemies trigger.action.setUserFlag(defenders_status_flag, defenders_remaining_percent) --set the zones flag to indicate the status of remaining defenders
end end
--are all zones clear? --are all zones clear?
@ -569,23 +710,104 @@ function RotorOps.assessUnitsInZone(var)
--is the game finished? --is the game finished?
if all_zones_clear then if all_zones_clear then
RotorOps.changeGameState(RotorOps.game_states.won) if RotorOps.defending == true then
gameMsg(gameMsgs.success) RotorOps.game_state = RotorOps.game_states.lost
trigger.action.setUserFlag(RotorOps.game_state_flag, RotorOps.game_states.lost)
RotorOps.gameMsg(RotorOps.gameMsgs.failure)
else
RotorOps.game_state = RotorOps.game_states.won
trigger.action.setUserFlag(RotorOps.game_state_flag, RotorOps.game_states.won)
RotorOps.gameMsg(RotorOps.gameMsgs.success)
end
return --we won't reset our timer to fire this function again return --we won't reset our timer to fire this function again
end end
--is the defending game finished?
local defending_game_won = true
for key, staged_unit in pairs(RotorOps.staged_units) do
if staged_unit:isExist() then --check if the enemy has staged units left
defending_game_won = false
end
end
if RotorOps.defending and defending_game_won then
RotorOps.game_state = RotorOps.game_states.won
trigger.action.setUserFlag(RotorOps.game_state_flag, RotorOps.game_states.won)
RotorOps.gameMsg(RotorOps.gameMsgs.success)
return --we won't reset our timer to fire this function again
end
--APCs unload
local function unloadAPCs()
local units_table = attacking_vehicles
for index, vehicle in pairs(units_table) do
local should_deploy = false
if vehicle:hasAttribute("Infantry carriers") and RotorOps.isUnitInZone(vehicle, RotorOps.active_zone) then --if a vehicle is an APC and in zone
local apc_name = vehicle:getName()
if tableHasKey(apcs, apc_name) == true then --if we have this apc in our table already
for key, apc_details in pairs(apcs[apc_name]) do
if hasValue(apc_details, RotorOps.active_zone) then --if our apc table has the current zone
else --our apc table does not have the current zone
apcs[apc_name].deployed_zones = {RotorOps.active_zone,}
should_deploy = true
end
end
else --we don't have the apc in our table
should_deploy = true
apcs[apc_name] = {['deployed_zones'] = {RotorOps.active_zone,}}
end
end
if should_deploy then
local function timedDeploy()
if vehicle:isExist() then
RotorOps.deployTroops(4, vehicle:getGroup(), false)
end
end
local id = timer.scheduleFunction(timedDeploy, nil, timer.getTime() + math.random(90, 180))
end
end
end
if RotorOps.apcs_spawn_infantry then
unloadAPCs() --this should really be an aitask
end
--voiceovers based on remaining defenders
if not low_units_message_fired then
if defenders_remaining_percent <= 40 then
low_units_message_fired = true
env.info("ROTOR OPS: low units remaining in zone")
if RotorOps.defending then
RotorOps.gameMsg(RotorOps.gameMsgs.enemy_almost_cleared, math.random(1, #RotorOps.gameMsgs.enemy_almost_cleared))
else
RotorOps.gameMsg(RotorOps.gameMsgs.almost_cleared, math.random(1, #RotorOps.gameMsgs.almost_cleared))
end
end
end
--zone status display --zone status display
local message = "" local message = ""
local header = "" local header = ""
local body = "" local body = ""
if defenders_remaining_percent == 0 then if RotorOps.defending == true then
header = "["..RotorOps.active_zone .. " CLEARED!] " header = "[DEFEND "..RotorOps.active_zone .. "] "
else body = "RED: " ..#attacking_infantry.. " infantry, " .. #attacking_vehicles .. " vehicles. BLUE: "..#defending_infantry.. " infantry, " .. #defending_vehicles.." vehicles. ["..defenders_remaining_percent.."%]"
header = "[BATTLE FOR "..RotorOps.active_zone .. "] " else
header = "[ATTACK "..RotorOps.active_zone .. "] "
body = "RED: " ..#defending_infantry.. " infantry, " .. #defending_vehicles .. " vehicles. BLUE: "..#attacking_infantry.. " infantry, " .. #attacking_vehicles.." vehicles. ["..defenders_remaining_percent.."%]"
end end
body = "RED: " ..#red_infantry.. " infantry, " .. #red_vehicles .. " vehicles. BLUE: "..#blue_infantry.. " infantry, " .. #blue_vehicles.." vehicles. ["..defenders_remaining_percent.."%]"
message = header .. body message = header .. body
if RotorOps.zone_status_display then if RotorOps.zone_status_display then
@ -655,12 +877,6 @@ end
function RotorOps.changeGameState(new_state)
RotorOps.game_state = new_state
trigger.action.setUserFlag(RotorOps.game_state_flag, new_state)
end
function RotorOps.setActiveZone(new_index) function RotorOps.setActiveZone(new_index)
local old_index = RotorOps.active_zone_index local old_index = RotorOps.active_zone_index
if new_index > #RotorOps.zones then if new_index > #RotorOps.zones then
@ -674,18 +890,33 @@ function RotorOps.setActiveZone(new_index)
RotorOps.active_zone = RotorOps.zones[new_index].name RotorOps.active_zone = RotorOps.zones[new_index].name
if new_index ~= old_index then --the active zone is changing if new_index ~= old_index then --the active zone is changing
if old_index > 0 then
ctld.activatePickupZone(RotorOps.zones[old_index].name)
end
ctld.deactivatePickupZone(RotorOps.zones[new_index].name)
RotorOps.changeGameState(new_index)
if new_index < old_index then gameMsg(gameMsgs.fallback, new_index) end
if new_index > old_index then gameMsg(gameMsgs.get_troops_to_zone, new_index) end
local staged_groups = RotorOps.groupsFromUnits(staged_units) if not RotorOps.defending then
if old_index > 0 then
ctld.activatePickupZone(RotorOps.zones[old_index].name) --make the captured zone a pickup zone
end
ctld.deactivatePickupZone(RotorOps.zones[new_index].name)
end
RotorOps.game_state = new_index
trigger.action.setUserFlag(RotorOps.game_state_flag, new_index)
if new_index > old_index then
if RotorOps.defending == true then
RotorOps.gameMsg(RotorOps.gameMsgs.enemy_pushing, new_index)
else
RotorOps.gameMsg(RotorOps.gameMsgs.push, new_index)
RotorOps.gameMsg(RotorOps.gameMsgs.get_troops_to_zone, new_index)
end
end
local staged_groups = RotorOps.groupsFromUnits(RotorOps.staged_units)
for index, group in pairs(staged_groups) do for index, group in pairs(staged_groups) do
RotorOps.aiTask(group,"move_to_active_zone", RotorOps.zones[RotorOps.active_zone_index].name) --send vehicles to next zone; use move_to_active_zone so units don't get stuck if the active zone moves before they arrive RotorOps.aiTask(group,"move_to_active_zone", RotorOps.zones[RotorOps.active_zone_index].name) --send vehicles to next zone; use move_to_active_zone so units don't get stuck if the active zone moves before they arrive
end end
end end
@ -697,6 +928,11 @@ end
--make some changes to the CTLD script/settings --make some changes to the CTLD script/settings
function RotorOps.setupCTLD() function RotorOps.setupCTLD()
if type(ctld.pickupZones[1][2]) == "number" then --ctld converts its string table to integer on load, so we'll see if that's happened already
trigger.action.outText("ERROR: CTLD Loaded Too Soon!!", 90)
return
end
ctld.enableCrates = RotorOps.CTLD_crates ctld.enableCrates = RotorOps.CTLD_crates
ctld.enabledFOBBuilding = false ctld.enabledFOBBuilding = false
ctld.JTAC_lock = "vehicle" ctld.JTAC_lock = "vehicle"
@ -716,15 +952,14 @@ function RotorOps.setupCTLD()
} }
ctld.loadableGroups = { ctld.loadableGroups = {
{name = "Small Standard Group (4)", inf = 2, mg = 1, at = 1 },
{name = "Standard Group (8)", inf = 4, mg = 2, at = 2 }, -- will make a loadable group with 6 infantry, 2 MGs and 2 anti-tank for both coalitions {name = "Standard Group (8)", inf = 4, mg = 2, at = 2 }, -- will make a loadable group with 6 infantry, 2 MGs and 2 anti-tank for both coalitions
{name = "Anti Air (5)", inf = 2, aa = 3 }, {name = "Anti Air (5)", inf = 2, aa = 3 },
{name = "Anti Tank (8)", inf = 2, at = 6 }, {name = "Anti Tank (8)", inf = 2, at = 6 },
{name = "Mortar Squad (6)", mortar = 6 }, {name = "Mortar Squad (6)", mortar = 6 },
{name = "Small Standard Group (4)", inf = 2, mg = 1, at = 1 }, {name = "JTAC Group (4)", inf = 3, jtac = 1 },
{name = "JTAC Group (5)", inf = 4, jtac = 1 }, {name = "Small Platoon (16)", inf = 9, mg = 3, at = 3, aa = 1 },
{name = "Single JTAC (1)", jtac = 1 }, {name = "Platoon (24)", inf = 10, mg = 5, at = 6, aa = 3 },
{name = "Small Platoon (16)", inf = 10, mg = 3, at = 3 },
{name = "Platoon (24)", inf = 12, mg = 4, at = 3, aa = 1 },
} }
end end
@ -747,7 +982,7 @@ function RotorOps.addZone(_name, _zone_defenders_flag)
end end
function RotorOps.stagingZone(_name) function RotorOps.stagingZone(_name)
RotorOps.addPickupZone(_name, "blue", -1, "yes", 0) RotorOps.addPickupZone(_name, "blue", -1, "no", 0)
RotorOps.staging_zone = _name RotorOps.staging_zone = _name
end end
@ -771,9 +1006,13 @@ function RotorOps.setupConflict(_game_state_flag)
RotorOps.setupCTLD() RotorOps.setupCTLD()
--RotorOps.setupRadioMenu() --RotorOps.setupRadioMenu()
RotorOps.game_state_flag = _game_state_flag RotorOps.game_state_flag = _game_state_flag
RotorOps.changeGameState(RotorOps.game_states.not_started) RotorOps.game_state = RotorOps.game_states.not_started
processMsgBuffer()
trigger.action.setUserFlag(RotorOps.game_state_flag, RotorOps.game_states.not_started)
trigger.action.outText("ALL TROOPS GET TO TRANSPORT AND PREPARE FOR DEPLOYMENT!" , 10, false) trigger.action.outText("ALL TROOPS GET TO TRANSPORT AND PREPARE FOR DEPLOYMENT!" , 10, false)
if RotorOps.CTLD_sound_effects == true then
local timer_id = timer.scheduleFunction(RotorOps.registerCtldCallbacks, 1, timer.getTime() + 5)
end
end end
@ -790,17 +1029,27 @@ function RotorOps.startConflict()
--local conflict_zones_menu = commandDB['conflict_zones_menu'] --local conflict_zones_menu = commandDB['conflict_zones_menu']
--missionCommands.removeItem(commandDB['start_conflict']) --missionCommands.removeItem(commandDB['start_conflict'])
--commandDB['clear_zone'] = missionCommands.addCommand( "[CHEAT] Force Clear Zone" , conflict_zones_menu , RotorOps.clearActiveZone) --commandDB['clear_zone'] = missionCommands.addCommand( "[CHEAT] Force Clear Zone" , conflict_zones_menu , RotorOps.clearActiveZone)
RotorOps.staged_units = mist.getUnitsInZones(mist.makeUnitTable({'[all][vehicle]'}), {RotorOps.staging_zone})
if RotorOps.staged_units[1]:getCoalition() == 1 then --check the coalition in the staging zone to see if we're defending
RotorOps.defending = true
RotorOps.gameMsg(RotorOps.gameMsgs.start_defense)
ctld.activatePickupZone(RotorOps.zones[#RotorOps.zones].name) --make the last zone a pickup zone for defenders
ctld.deactivatePickupZone(RotorOps.staging_zone)
else
RotorOps.gameMsg(RotorOps.gameMsgs.start)
ctld.activatePickupZone(RotorOps.staging_zone)
end
gameMsg(gameMsgs.start)
gameMsg(gameMsgs.push, 1)
processMsgBuffer()
staged_units = mist.getUnitsInZones(mist.makeUnitTable({'[all][vehicle]'}), {RotorOps.staging_zone})
RotorOps.setActiveZone(1) RotorOps.setActiveZone(1)
local id = timer.scheduleFunction(RotorOps.assessUnitsInZone, 1, timer.getTime() + 5) local id = timer.scheduleFunction(RotorOps.assessUnitsInZone, 1, timer.getTime() + 5)
world.addEventHandler(RotorOps.eventHandler)
end end

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
sound/friendly_cap.ogg Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
sound/friendly_convoy.ogg Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
sound/friendly_sead.ogg Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
sound/losing_battle.ogg Normal file

Binary file not shown.

Binary file not shown.

BIN
sound/target_destroyed.ogg Normal file

Binary file not shown.