mirror of
https://github.com/spencershepard/RotorOps.git
synced 2025-11-10 15:45:30 +00:00
..
This commit is contained in:
parent
dc4a0a8e79
commit
f0f6c0f221
214
RotorOps.lua
214
RotorOps.lua
@ -1,30 +1,39 @@
|
|||||||
RotorOps = {}
|
RotorOps = {}
|
||||||
RotorOps.transports = {'UH-1H', 'Mi-8MT', 'Mi-24P'}
|
|
||||||
RotorOps.zone_states = {not_started = 0, active = 1, cleared = 2, started = 3}
|
RotorOps.voice_overs = true
|
||||||
RotorOps.game_states = {not_started = 0, in_progress = 1, won = 2, lost = 3}
|
RotorOps.ground_speed = 30 --max speed for ground vehicles moving between zones
|
||||||
RotorOps.game_state = 0
|
RotorOps.zone_status_display = true --constantly show units remaining and zone status on screen
|
||||||
RotorOps.ground_speed = 10
|
|
||||||
RotorOps.auto_push = true
|
|
||||||
local last_message_time
|
|
||||||
local game_message_buffer = {}
|
|
||||||
RotorOps.zone_status_display = true
|
|
||||||
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.ai_active_zone = true --allow the script to automatically create waypoints for ground units in the active zone
|
||||||
|
|
||||||
|
|
||||||
|
RotorOps.zone_states = {not_started = 0, active = 1, cleared = 2, started = 3} --zone level user flags will use these values
|
||||||
|
|
||||||
|
RotorOps.game_states = {not_started = 0, in_progress = 1, won = 2, lost = 3} --game level user flag will use these values
|
||||||
|
|
||||||
|
RotorOps.transports = {'UH-1H', 'Mi-8MT', 'Mi-24P'} --players flying these will have ctld transport access
|
||||||
|
|
||||||
|
RotorOps.game_state = 0
|
||||||
RotorOps.zones = {}
|
RotorOps.zones = {}
|
||||||
RotorOps.active_zone = ""
|
RotorOps.active_zone = "" --name of the active zone
|
||||||
RotorOps.active_zone_index = 1
|
RotorOps.active_zone_index = 1
|
||||||
RotorOps.active_zone_flag = 1
|
RotorOps.game_state_flag = 1 --user flag to store the game state
|
||||||
|
|
||||||
RotorOps.staging_zone = ""
|
RotorOps.staging_zone = ""
|
||||||
|
RotorOps.auto_push = true --leave true for now
|
||||||
|
|
||||||
RotorOps.ctld_pickup_zones = {}
|
RotorOps.ctld_pickup_zones = {} --keep track of ctld zones we've added, mainly for map markup
|
||||||
|
|
||||||
trigger.action.outText("ROTOR OPS STARTED", 5)
|
trigger.action.outText("ROTOR OPS STARTED", 5)
|
||||||
env.info("ROTOR OPS STARTED")
|
env.info("ROTOR OPS STARTED")
|
||||||
|
|
||||||
local staged_units
|
local staged_units --table of ground units that started in the staging zone
|
||||||
local commandDB = {}
|
local commandDB = {}
|
||||||
|
local game_message_buffer = {}
|
||||||
|
RotorOps.ai_red_infantry_groups = {}
|
||||||
|
RotorOps.ai_blue_infantry_groups = {}
|
||||||
|
RotorOps.ai_red_vehicle_groups = {}
|
||||||
|
RotorOps.ai_blue_vehicle_groups = {}
|
||||||
|
RotorOps.ai_timers = {} --simply use the group ID for schedulefunction id
|
||||||
|
|
||||||
local gameMsgs = {
|
local gameMsgs = {
|
||||||
push = {
|
push = {
|
||||||
@ -61,6 +70,7 @@ local gameMsgs = {
|
|||||||
|
|
||||||
local function debugMsg(text)
|
local function debugMsg(text)
|
||||||
trigger.action.outText(text, 5)
|
trigger.action.outText(text, 5)
|
||||||
|
env.info("ROTOROPS_DEBUG: "..text)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
@ -96,9 +106,11 @@ local function getObjectVolume(obj)
|
|||||||
return length * height * depth
|
return length * height * depth
|
||||||
end
|
end
|
||||||
|
|
||||||
function RotorOps.groupsFromUnits(units)
|
|
||||||
--debugTable(units)
|
function RotorOps.groupsFromUnits(units, table)
|
||||||
local groups = {}
|
local groups = {}
|
||||||
|
--debugTable(units)
|
||||||
|
|
||||||
--local groupIndex = {}
|
--local groupIndex = {}
|
||||||
for i = 1, #units do
|
for i = 1, #units do
|
||||||
if hasValue(groups, units[i]:getGroup():getName()) == false then
|
if hasValue(groups, units[i]:getGroup():getName()) == false then
|
||||||
@ -129,14 +141,32 @@ local function processMsgBuffer(vars)
|
|||||||
if #game_message_buffer > 0 then
|
if #game_message_buffer > 0 then
|
||||||
local message = table.remove(game_message_buffer, 1)
|
local message = table.remove(game_message_buffer, 1)
|
||||||
trigger.action.outText(message[1], 10, true)
|
trigger.action.outText(message[1], 10, true)
|
||||||
|
if RotorOps.voice_overs then
|
||||||
trigger.action.outSound(message[2])
|
trigger.action.outSound(message[2])
|
||||||
end
|
end
|
||||||
|
end
|
||||||
local id = timer.scheduleFunction(processMsgBuffer, 1, timer.getTime() + 5)
|
local id = timer.scheduleFunction(processMsgBuffer, 1, timer.getTime() + 5)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function RotorOps.sortOutInfantry(mixed_units)
|
||||||
|
local _infantry = {}
|
||||||
|
local _not_infantry = {}
|
||||||
|
for index, unit in pairs(mixed_units)
|
||||||
|
do
|
||||||
|
if unit:hasAttribute("Infantry") then
|
||||||
|
_infantry[#_infantry + 1] = unit
|
||||||
|
else _not_infantry[#_not_infantry + 1] = unit
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return {infantry = _infantry, not_infantry = _not_infantry}
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
--spawn/clone a group onto the location of the first unit in a group (best to only use this for groups of one unit only for now!)
|
||||||
function RotorOps.spawnInfantryOnGrp(grp, src_grp_name, behavior) --allow to spawn on other group units
|
function RotorOps.spawnInfantryOnGrp(grp, src_grp_name, behavior) --allow to spawn on other group units
|
||||||
debugMsg("attempting to spawn at "..grp:getUnit(1):getTypeName())
|
debugMsg("attempting to spawn at "..grp:getUnit(1):getTypeName())
|
||||||
local vars = {}
|
local vars = {}
|
||||||
@ -230,7 +260,7 @@ end
|
|||||||
|
|
||||||
|
|
||||||
function RotorOps.patrolRadius(vars)
|
function RotorOps.patrolRadius(vars)
|
||||||
debugMsg("patrol radius: "..mist.utils.tableShow(vars))
|
debugMsg("patrol radius: "..mist.utils.tableShow(vars.grp))
|
||||||
local grp = vars.grp
|
local grp = vars.grp
|
||||||
local search_radius = vars.radius or 100
|
local search_radius = vars.radius or 100
|
||||||
local first_valid_unit
|
local first_valid_unit
|
||||||
@ -292,32 +322,45 @@ function RotorOps.patrolRadius(vars)
|
|||||||
--trigger.action.outText("new waypoints created: "..(#path - 1), 5)
|
--trigger.action.outText("new waypoints created: "..(#path - 1), 5)
|
||||||
mist.goRoute(grp, path)
|
mist.goRoute(grp, path)
|
||||||
--local timing = mist.getPathLength(path) / 5
|
--local timing = mist.getPathLength(path) / 5
|
||||||
local id = timer.scheduleFunction(RotorOps.patrolRadius, vars, timer.getTime() + math.random(50,70))
|
--local id = timer.scheduleFunction(RotorOps.patrolRadius, vars, timer.getTime() + math.random(50,70))
|
||||||
|
|
||||||
|
|
||||||
|
local group_name = grp:getName()
|
||||||
|
if tableHasKey(RotorOps.ai_timers, group_name) == true then --if we already have this group id in our list of timers
|
||||||
|
debugMsg("timer already active, do nothing for "..group_name.." : ".. RotorOps.ai_timers[group_name])
|
||||||
|
--timer.removeFunction(RotorOps.ai_timers[group_name])
|
||||||
|
else
|
||||||
|
debugMsg("adding timer: "..group_name)
|
||||||
|
local timer_id = timer.scheduleFunction(RotorOps.patrolRadius, vars, timer.getTime() + math.random(50,70))
|
||||||
|
RotorOps.ai_timers[group_name] = timer_id
|
||||||
end
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
------------------------------------------
|
------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
local function changeGameState(new_state)
|
||||||
|
RotorOps.game_state = new_state
|
||||||
|
trigger.action.setUserFlag(RotorOps.game_state_flag, new_state)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function RotorOps.aiActiveZone(var)
|
||||||
|
if RotorOps.ai_active_zone == false then return end
|
||||||
|
--debugMsg("aiActiveZone func")
|
||||||
|
|
||||||
|
for index, group in pairs(RotorOps.ai_red_infantry_groups) do
|
||||||
function RotorOps.sortOutInfantry(mixed_units)
|
if group then
|
||||||
local _infantry = {}
|
debugMsg("grp="..group)
|
||||||
local _not_infantry = {}
|
RotorOps.patrolRadius({grp=Group.getByName(group), radius=400})
|
||||||
for index, unit in pairs(mixed_units)
|
|
||||||
do
|
|
||||||
if unit:hasAttribute("Infantry") then
|
|
||||||
_infantry[#_infantry + 1] = unit
|
|
||||||
else _not_infantry[#_not_infantry + 1] = unit
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
return {infantry = _infantry, not_infantry = _not_infantry}
|
|
||||||
|
|
||||||
|
local id = timer.scheduleFunction(RotorOps.aiActiveZone, 1, timer.getTime() + 10)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
@ -354,10 +397,17 @@ function RotorOps.assessUnitsInZone(var)
|
|||||||
|
|
||||||
if all_zones_clear then
|
if all_zones_clear then
|
||||||
RotorOps.gameWon()
|
RotorOps.gameWon()
|
||||||
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--ground unit ai stuff
|
||||||
|
RotorOps.ai_red_infantry_groups = RotorOps.groupsFromUnits(red_infantry)
|
||||||
|
RotorOps.ai_blue_infantry_groups = RotorOps.groupsFromUnits(blue_infantry)
|
||||||
|
RotorOps.ai_red_vehicle_groups = RotorOps.groupsFromUnits(red_vehicles)
|
||||||
|
RotorOps.ai_blue_vehicle_groups = RotorOps.groupsFromUnits(blue_vehicles)
|
||||||
|
|
||||||
|
|
||||||
|
--zone status display stuff
|
||||||
local message = ""
|
local message = ""
|
||||||
local header = ""
|
local header = ""
|
||||||
local body = ""
|
local body = ""
|
||||||
@ -435,18 +485,7 @@ function RotorOps.drawZones() --this could use a lot of work, we should use tri
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--function to automatically add transport craft to ctld, rather than having to define each in the mission editor
|
|
||||||
function RotorOps.addPilots(var)
|
|
||||||
for uName, uData in pairs(mist.DBs.humansByName) do
|
|
||||||
if hasValue(RotorOps.transports, uData.type) then
|
|
||||||
if hasValue(ctld.transportPilotNames, uData.unitName) ~= true then
|
|
||||||
ctld.transportPilotNames [#ctld.transportPilotNames + 1] = uData.unitName
|
|
||||||
--else trigger.action.outText("player already in pilot table", 5)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
local id = timer.scheduleFunction(RotorOps.addPilots, 1, timer.getTime() + 15)
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
function RotorOps.sendUnitsToZone(units_table, zone, _formation, _final_heading, _speed, _force_offroad)
|
function RotorOps.sendUnitsToZone(units_table, zone, _formation, _final_heading, _speed, _force_offroad)
|
||||||
@ -480,32 +519,22 @@ function RotorOps.fallBack()
|
|||||||
RotorOps.sendUnitsToZone(staged_units, RotorOps.zones[RotorOps.active_zone_index].name)
|
RotorOps.sendUnitsToZone(staged_units, RotorOps.zones[RotorOps.active_zone_index].name)
|
||||||
end
|
end
|
||||||
|
|
||||||
function RotorOps.startConflict()
|
|
||||||
if RotorOps.game_state == RotorOps.game_states.in_progress then return end
|
|
||||||
RotorOps.game_state = RotorOps.game_states.in_progress
|
|
||||||
|
|
||||||
--make some changes to the radio menu
|
|
||||||
local conflict_zones_menu = commandDB['conflict_zones_menu']
|
|
||||||
missionCommands.removeItem(commandDB['start_conflict'])
|
|
||||||
commandDB['push_zone'] = missionCommands.addCommand( "Push to next zone", conflict_zones_menu , RotorOps.pushZone)
|
|
||||||
commandDB['fall_back'] = missionCommands.addCommand( "Fall back to prev zone" , conflict_zones_menu , RotorOps.fallBack)
|
|
||||||
|
|
||||||
staged_units = mist.getUnitsInZones(mist.makeUnitTable({'[all][vehicle]'}), {RotorOps.staging_zone})
|
|
||||||
--local helicopters = mist.getUnitsInZones(mist.makeUnitTable({'[all][helicopter]'}), {RotorOps.zones[1].name})
|
|
||||||
--RotorOps.sendUnitsToZone(helicopters, RotorOps.zones[2].name, nil, nil, 90)
|
|
||||||
RotorOps.sendUnitsToZone(staged_units, RotorOps.zones[1].name)
|
|
||||||
RotorOps.setActiveZone(1)
|
|
||||||
gameMsg(gameMsgs.start)
|
|
||||||
gameMsg(gameMsgs.push, 1)
|
|
||||||
processMsgBuffer()
|
|
||||||
local id = timer.scheduleFunction(RotorOps.assessUnitsInZone, 1, timer.getTime() + 5)
|
|
||||||
end
|
|
||||||
|
|
||||||
function RotorOps.gameWon()
|
function RotorOps.gameWon()
|
||||||
RotorOps.game_state = RotorOps.game_states.won
|
changeGameState(RotorOps.game_states.won)
|
||||||
gameMsg(gameMsgs.success)
|
gameMsg(gameMsgs.success)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function RotorOps.spawnInfantryAtZone(vars)
|
||||||
|
local side = vars.side
|
||||||
|
local inf = vars.inf
|
||||||
|
local zone = vars.zone
|
||||||
|
local radius = vars.radius
|
||||||
|
ctld.spawnGroupAtTrigger(side, inf, zone, radius)
|
||||||
|
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
|
||||||
@ -531,7 +560,7 @@ function RotorOps.setActiveZone(new_index)
|
|||||||
|
|
||||||
RotorOps.active_zone = RotorOps.zones[new_index].name
|
RotorOps.active_zone = RotorOps.zones[new_index].name
|
||||||
--debugMsg("active zone: "..RotorOps.active_zone.." old zone: "..RotorOps.zones[old_index].name)
|
--debugMsg("active zone: "..RotorOps.active_zone.." old zone: "..RotorOps.zones[old_index].name)
|
||||||
trigger.action.setUserFlag(RotorOps.active_zone_flag, RotorOps.active_zone_index)
|
|
||||||
RotorOps.drawZones()
|
RotorOps.drawZones()
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -570,30 +599,15 @@ end
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
function RotorOps.debugAction()
|
|
||||||
--trigger.action.outText("zones: ".. mist.utils.tableShow(RotorOps.zones), 5)
|
|
||||||
RotorOps.clearActiveZone()
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
function RotorOps.setupRadioMenu()
|
function RotorOps.setupRadioMenu()
|
||||||
commandDB['conflict_zones_menu'] = missionCommands.addSubMenu( "ROTOR OPS")
|
commandDB['conflict_zones_menu'] = missionCommands.addSubMenu( "ROTOR OPS")
|
||||||
local conflict_zones_menu = commandDB['conflict_zones_menu']
|
local conflict_zones_menu = commandDB['conflict_zones_menu']
|
||||||
|
|
||||||
|
|
||||||
commandDB['start_conflict'] = missionCommands.addCommand( "Start conflict" , conflict_zones_menu , RotorOps.startConflict)
|
commandDB['start_conflict'] = missionCommands.addCommand( "Start conflict" , conflict_zones_menu , RotorOps.startConflict)
|
||||||
commandDB['debug_action'] = missionCommands.addCommand( "Debug action" , conflict_zones_menu , RotorOps.debugAction)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function RotorOps.spawnInfantryAtZone(vars)
|
|
||||||
local side = vars.side
|
|
||||||
local inf = vars.inf
|
|
||||||
local zone = vars.zone
|
|
||||||
local radius = vars.radius
|
|
||||||
ctld.spawnGroupAtTrigger(side, inf, zone, radius)
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
function RotorOps.addZone(_name, _zone_status_flag)
|
function RotorOps.addZone(_name, _zone_status_flag)
|
||||||
@ -611,12 +625,25 @@ function RotorOps.stagingZone(_name)
|
|||||||
RotorOps.staging_zone = _name
|
RotorOps.staging_zone = _name
|
||||||
end
|
end
|
||||||
|
|
||||||
function RotorOps.setupConflict(_active_zone_flag)
|
--function to automatically add transport craft to ctld, rather than having to define each in the mission editor
|
||||||
|
function RotorOps.addPilots(var)
|
||||||
|
for uName, uData in pairs(mist.DBs.humansByName) do
|
||||||
|
if hasValue(RotorOps.transports, uData.type) then
|
||||||
|
if hasValue(ctld.transportPilotNames, uData.unitName) ~= true then
|
||||||
|
ctld.transportPilotNames [#ctld.transportPilotNames + 1] = uData.unitName
|
||||||
|
--else trigger.action.outText("player already in pilot table", 5)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
local id = timer.scheduleFunction(RotorOps.addPilots, 1, timer.getTime() + 15)
|
||||||
|
end
|
||||||
|
|
||||||
|
function RotorOps.setupConflict(_game_state_flag)
|
||||||
RotorOps.addPilots(1)
|
RotorOps.addPilots(1)
|
||||||
RotorOps.setupCTLD()
|
RotorOps.setupCTLD()
|
||||||
RotorOps.setupRadioMenu()
|
RotorOps.setupRadioMenu()
|
||||||
RotorOps.active_zone_flag = _active_zone_flag
|
RotorOps.game_state_flag = _game_state_flag
|
||||||
RotorOps.game_state = RotorOps.game_states.not_started
|
changeGameState(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)
|
||||||
|
|
||||||
end
|
end
|
||||||
@ -628,3 +655,28 @@ function RotorOps.addPickupZone(zone_name, smoke, limit, active, side)
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function RotorOps.startConflict()
|
||||||
|
if RotorOps.game_state == RotorOps.game_states.in_progress then return end
|
||||||
|
changeGameState(RotorOps.game_states.in_progress)
|
||||||
|
|
||||||
|
--make some changes to the radio menu
|
||||||
|
local conflict_zones_menu = commandDB['conflict_zones_menu']
|
||||||
|
missionCommands.removeItem(commandDB['start_conflict'])
|
||||||
|
--commandDB['push_zone'] = missionCommands.addCommand( "Push to next zone", conflict_zones_menu , RotorOps.pushZone)
|
||||||
|
--commandDB['fall_back'] = missionCommands.addCommand( "Fall back to prev zone" , conflict_zones_menu , RotorOps.fallBack)
|
||||||
|
commandDB['clear_zone'] = missionCommands.addCommand( "Force Clear Zone" , conflict_zones_menu , RotorOps.clearActiveZone)
|
||||||
|
|
||||||
|
staged_units = mist.getUnitsInZones(mist.makeUnitTable({'[all][vehicle]'}), {RotorOps.staging_zone})
|
||||||
|
--local helicopters = mist.getUnitsInZones(mist.makeUnitTable({'[all][helicopter]'}), {RotorOps.zones[1].name})
|
||||||
|
--RotorOps.sendUnitsToZone(helicopters, RotorOps.zones[2].name, nil, nil, 90)
|
||||||
|
RotorOps.sendUnitsToZone(staged_units, RotorOps.zones[1].name)
|
||||||
|
RotorOps.setActiveZone(1)
|
||||||
|
gameMsg(gameMsgs.start)
|
||||||
|
gameMsg(gameMsgs.push, 1)
|
||||||
|
processMsgBuffer()
|
||||||
|
RotorOps.aiActiveZone()
|
||||||
|
local id = timer.scheduleFunction(RotorOps.assessUnitsInZone, 1, timer.getTime() + 5)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
BIN
sound/beacon.ogg
Normal file
BIN
sound/beacon.ogg
Normal file
Binary file not shown.
BIN
sound/beaconsilent.ogg
Normal file
BIN
sound/beaconsilent.ogg
Normal file
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user