mirror of
https://github.com/spencershepard/RotorOps.git
synced 2025-11-10 15:45:30 +00:00
463 lines
16 KiB
Lua
463 lines
16 KiB
Lua
RotaryOps = {}
|
|
RotaryOps.transports = {'UH-1H', 'Mi-8MT', 'Mi-24P'}
|
|
trigger.action.outText("ROTARY OPS STARTED", 5)
|
|
env.info("ROTARY OPS STARTED")
|
|
|
|
|
|
local function tableHasKey(table,key)
|
|
return table[key] ~= nil
|
|
end
|
|
|
|
local function dispMsg(text)
|
|
trigger.action.outText(text, 5)
|
|
return text
|
|
end
|
|
|
|
local function tableHasKey(table,key)
|
|
return table[key] ~= nil
|
|
end
|
|
|
|
local function hasValue (tab, val)
|
|
for index, value in ipairs(tab) do
|
|
if value == val then
|
|
return true
|
|
end
|
|
end
|
|
return false
|
|
end
|
|
|
|
local function getObjectVolume(obj)
|
|
local length = (obj:getDesc().box.max.x + math.abs(obj:getDesc().box.min.x))
|
|
local height = (obj:getDesc().box.max.y + math.abs(obj:getDesc().box.min.y))
|
|
local depth = (obj:getDesc().box.max.z + math.abs(obj:getDesc().box.min.z))
|
|
return length * height * depth
|
|
end
|
|
|
|
function RotaryOps.spawnInfantryOnGrp(grp, src_grp_name, behavior) --allow to spawn on other group units
|
|
trigger.action.outText("attempting to spawn at "..grp:getUnit(1):getTypeName(), 5)
|
|
local vars = {}
|
|
vars.gpName = src_grp_name
|
|
vars.action = 'clone'
|
|
vars.point = grp:getUnit(1):getPoint()
|
|
vars.radius = 5
|
|
vars.disperse = 'disp'
|
|
vars.maxDisp = 5
|
|
local new_grp_table = mist.teleportToPoint(vars)
|
|
|
|
if new_grp_table then
|
|
local new_grp = Group.getByName(new_grp_table.name)
|
|
local PATROL = 1
|
|
local AGGRESSIVE = 2
|
|
if behavior == PATROL then
|
|
--trigger.action.outText("new group: "..mist.utils.tableShow(new_grp_table), 5)
|
|
--local id = timer.scheduleFunction(RotaryOps.seekCover, new_grp, timer.getTime() + 1)
|
|
RotaryOps.patrolRadius({grp = new_grp})
|
|
end
|
|
if behavior == AGGRESSIVE then
|
|
RotaryOps.chargeEnemy({grp = new_grp})
|
|
end
|
|
else trigger.action.outText("Infantry failed to spawn. ", 5)
|
|
end
|
|
end
|
|
|
|
function RotaryOps.chargeEnemy(vars)
|
|
--trigger.action.outText("charge enemies: "..mist.utils.tableShow(vars), 5)
|
|
local grp = vars.grp
|
|
local search_radius = vars.radius or 5000
|
|
----
|
|
local first_valid_unit
|
|
if grp:isExist() ~= true then return end
|
|
for index, unit in pairs(grp:getUnits())
|
|
do
|
|
if unit:isExist() == true then
|
|
first_valid_unit = unit
|
|
break
|
|
else --trigger.action.outText("a unit no longer exists", 15)
|
|
end
|
|
end
|
|
----
|
|
|
|
if first_valid_unit == nil then return end
|
|
local start_point = first_valid_unit:getPoint()
|
|
if not vars.spawn_point then vars.spawn_point = start_point end
|
|
|
|
local enemy_coal
|
|
if grp:getCoalition() == 1 then enemy_coal = 2 end
|
|
if grp:getCoalition() == 2 then enemy_coal = 1 end
|
|
|
|
--local sphere = trigger.misc.getZone('town')
|
|
local volS = {
|
|
id = world.VolumeType.SPHERE,
|
|
params = {
|
|
point = grp:getUnit(1):getPoint(), --check if exists, maybe itterate through grp
|
|
radius = search_radius
|
|
}
|
|
}
|
|
local enemy_unit
|
|
local path = {}
|
|
local ifFound = function(foundItem, val)
|
|
--trigger.action.outText("found item: "..foundItem:getTypeName(), 5)
|
|
if foundItem:hasAttribute("Infantry") == true and foundItem:getCoalition() == enemy_coal then
|
|
enemy_unit = foundItem
|
|
--trigger.action.outText("found enemy! "..foundItem:getTypeName(), 5)
|
|
|
|
path[1] = mist.ground.buildWP(start_point, '', 5)
|
|
path[2] = mist.ground.buildWP(enemy_unit:getPoint(), '', 5)
|
|
--path[3] = mist.ground.buildWP(vars.spawn_point, '', 5)
|
|
else
|
|
|
|
--trigger.action.outText("object found is not enemy inf in "..search_radius, 5)
|
|
end
|
|
|
|
return true
|
|
end
|
|
--default path if no units found
|
|
if false then
|
|
trigger.action.outText("group going back to origin", 5)
|
|
path[1] = mist.ground.buildWP(start_point, '', 5)
|
|
path[2] = mist.ground.buildWP(vars.spawn_point, '', 5)
|
|
|
|
end
|
|
world.searchObjects(Object.Category.UNIT, volS, ifFound)
|
|
mist.goRoute(grp, path)
|
|
local id = timer.scheduleFunction(RotaryOps.chargeEnemy, vars, timer.getTime() + math.random(50,70))
|
|
|
|
end
|
|
|
|
|
|
function RotaryOps.patrolRadius(vars)
|
|
trigger.action.outText("patrol radius: "..mist.utils.tableShow(vars), 5)
|
|
local grp = vars.grp
|
|
local search_radius = vars.radius or 100
|
|
local first_valid_unit
|
|
if grp:isExist() ~= true then return end
|
|
for index, unit in pairs(grp:getUnits())
|
|
do
|
|
if unit:isExist() == true then
|
|
first_valid_unit = unit
|
|
break
|
|
else --trigger.action.outText("a unit no longer exists", 15)
|
|
end
|
|
end
|
|
if first_valid_unit == nil then return end
|
|
local start_point = first_valid_unit:getPoint()
|
|
local object_vol_thresh = 0
|
|
local max_waypoints = 5
|
|
local foundUnits = {}
|
|
--local sphere = trigger.misc.getZone('town')
|
|
local volS = {
|
|
id = world.VolumeType.SPHERE,
|
|
params = {
|
|
point = grp:getUnit(1):getPoint(), --check if exists, maybe itterate through grp
|
|
radius = search_radius
|
|
}
|
|
}
|
|
|
|
local ifFound = function(foundItem, val)
|
|
--trigger.action.outText("found item: "..foundItem:getTypeName(), 5)
|
|
if foundItem:hasAttribute("Infantry") ~= true then --disregard infantry...we only want objects that might provide cover
|
|
if getObjectVolume(foundItem) > object_vol_thresh then
|
|
foundUnits[#foundUnits + 1] = foundItem
|
|
--trigger.action.outText("valid cover item: "..foundItem:getTypeName(), 5)
|
|
else trigger.action.outText("object not large enough: "..foundItem:getTypeName(), 5)
|
|
end
|
|
else --trigger.action.outText("object not the right type", 5)
|
|
end
|
|
return true
|
|
end
|
|
|
|
world.searchObjects(1, volS, ifFound)
|
|
world.searchObjects(3, volS, ifFound)
|
|
world.searchObjects(5, volS, ifFound)
|
|
--world.searchObjects(Object.Category.BASE, volS, ifFound)
|
|
local path = {}
|
|
path[1] = mist.ground.buildWP(start_point, '', 5)
|
|
local m = math.min(#foundUnits, max_waypoints)
|
|
for i = 1, m, 1
|
|
do
|
|
local rand_index = math.random(1,#foundUnits)
|
|
path[i + 1] = mist.ground.buildWP(foundUnits[rand_index]:getPoint(), '', 5)
|
|
--trigger.action.outText("waypoint to: "..foundUnits[rand_index]:getTypeName(), 5)
|
|
end
|
|
if #path <= 3 then
|
|
for i = #path, max_waypoints, 1
|
|
do
|
|
path[#path + 1] = mist.ground.buildWP(mist.getRandPointInCircle(start_point, search_radius), '', 5)
|
|
end
|
|
end
|
|
--trigger.action.outText("new waypoints created: "..(#path - 1), 5)
|
|
mist.goRoute(grp, path)
|
|
--local timing = mist.getPathLength(path) / 5
|
|
local id = timer.scheduleFunction(RotaryOps.patrolRadius, vars, timer.getTime() + math.random(50,70))
|
|
|
|
end
|
|
|
|
|
|
function RotaryOps.knowEnemy(vars)
|
|
--trigger.action.outText("charge enemies: "..mist.utils.tableShow(vars), 5)
|
|
local grp = vars.grp
|
|
local search_radius = vars.radius or 5000
|
|
----
|
|
local first_valid_unit
|
|
if grp:isExist() ~= true then return end
|
|
for index, unit in pairs(grp:getUnits())
|
|
do
|
|
if unit:isExist() == true then
|
|
first_valid_unit = unit
|
|
break
|
|
else --trigger.action.outText("a unit no longer exists", 15)
|
|
end
|
|
end
|
|
----
|
|
|
|
if first_valid_unit == nil then return end
|
|
local start_point = first_valid_unit:getPoint()
|
|
if not vars.spawn_point then vars.spawn_point = start_point end
|
|
|
|
local enemy_coal
|
|
if grp:getCoalition() == 1 then enemy_coal = 2 end
|
|
if grp:getCoalition() == 2 then enemy_coal = 1 end
|
|
|
|
--local sphere = trigger.misc.getZone('town')
|
|
local volS = {
|
|
id = world.VolumeType.SPHERE,
|
|
params = {
|
|
point = grp:getUnit(1):getPoint(), --check if exists, maybe itterate through grp
|
|
radius = search_radius
|
|
}
|
|
}
|
|
local enemy_unit
|
|
local path = {}
|
|
local ifFound = function(foundItem, val)
|
|
--trigger.action.outText("found item: "..foundItem:getTypeName(), 5)
|
|
if foundItem:getCoalition() == enemy_coal then
|
|
enemy_unit = foundItem
|
|
trigger.action.outText("found enemy! "..foundItem:getTypeName(), 5)
|
|
|
|
path[1] = mist.ground.buildWP(start_point, '', 5)
|
|
path[2] = mist.ground.buildWP(enemy_unit:getPoint(), '', 5)
|
|
--path[3] = mist.ground.buildWP(vars.spawn_point, '', 5)
|
|
grp:getUnit(1):getController():knowTarget(enemy_unit, true, true)
|
|
|
|
|
|
else
|
|
|
|
--trigger.action.outText("object found is not enemy inf in "..search_radius, 5)
|
|
end
|
|
|
|
return true
|
|
end
|
|
--default path if no units found
|
|
if false then
|
|
trigger.action.outText("group going back to origin", 5)
|
|
path[1] = mist.ground.buildWP(start_point, '', 5)
|
|
path[2] = mist.ground.buildWP(vars.spawn_point, '', 5)
|
|
|
|
end
|
|
world.searchObjects(Object.Category.UNIT, volS, ifFound)
|
|
--mist.goRoute(grp, path)
|
|
local id = timer.scheduleFunction(RotaryOps.knowEnemy, vars, timer.getTime() + 15)
|
|
|
|
end
|
|
|
|
|
|
------------------------------------------
|
|
|
|
|
|
|
|
RotaryOps.zones = {}
|
|
RotaryOps.active_zone = ""
|
|
RotaryOps.active_zone_index = 1
|
|
RotaryOps.active_zone_flag = 1
|
|
RotaryOps.conflict = {
|
|
aggressor = 'blue',
|
|
blue_forces_flag = 99,
|
|
red_forces_flag = 98,
|
|
aggressor_zone_is_first = true,
|
|
}
|
|
|
|
|
|
function RotaryOps.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
|
|
|
|
function RotaryOps.assessUnitsInZone(var)
|
|
--consider adding other unit types
|
|
local red_ground_units = mist.getUnitsInZones(mist.makeUnitTable({'[red][vehicle]'}), {RotaryOps.active_zone}) --consider adding other unit types
|
|
local red_infantry = RotaryOps.sortOutInfantry(red_ground_units).infantry
|
|
local red_vehicles = RotaryOps.sortOutInfantry(red_ground_units).not_infantry
|
|
local blue_ground_units = mist.getUnitsInZones(mist.makeUnitTable({'[blue][vehicle]'}), {RotaryOps.active_zone}) --consider adding other unit types
|
|
local blue_infantry = RotaryOps.sortOutInfantry(blue_ground_units).infantry
|
|
local blue_vehicles = RotaryOps.sortOutInfantry(blue_ground_units).not_infantry
|
|
|
|
trigger.action.outText("[BATTLE FOR "..RotaryOps.active_zone .. "] RED: " ..#red_infantry.. " infantry, " .. #red_vehicles .. " vehicles. BLUE: "..#blue_infantry.. " infantry, " .. #blue_vehicles.." vehicles.", 5, true)
|
|
local id = timer.scheduleFunction(RotaryOps.assessUnitsInZone, 1, timer.getTime() + 5)
|
|
end
|
|
local id = timer.scheduleFunction(RotaryOps.assessUnitsInZone, 1, timer.getTime() + 5)
|
|
|
|
|
|
function RotaryOps.drawZones(zones) --should be drawZones and itterate through all zones, getting the active zone, and incrementing id
|
|
local previous_point
|
|
for index, zone in pairs(zones)
|
|
do
|
|
local point = trigger.misc.getZone(zone.outter_zone_name).point
|
|
local radius = trigger.misc.getZone(zone.outter_zone_name).radius
|
|
local coalition = -1
|
|
local id = index --this must be UNIQUE!
|
|
local color = {1, 1, 1, 0.5}
|
|
local fill_color = {1, 1, 1, 0.1}
|
|
local text_fill_color = {0, 0, 0, 0}
|
|
local line_type = 5 --1 Solid 2 Dashed 3 Dotted 4 Dot Dash 5 Long Dash 6 Two Dash
|
|
local font_size = 20
|
|
local read_only = false
|
|
local text = zone.outter_zone_name
|
|
if zone.outter_zone_name == RotaryOps.active_zone then
|
|
color = {1, 1, 1, 0.5}
|
|
fill_color = {1, 0, 1, 0.1}
|
|
end
|
|
if previous_point ~= nill then
|
|
trigger.action.lineToAll(coalition, id + 200, point, previous_point, color, line_type)
|
|
end
|
|
previous_point = point
|
|
trigger.action.circleToAll(coalition, id, point, radius, color, fill_color, line_type)
|
|
trigger.action.textToAll(coalition, id + 100, point, color, text_fill_color, font_size, read_only, text)
|
|
end
|
|
|
|
|
|
end
|
|
|
|
--function to automatically add transport craft to ctld, rather than having to define each in the mission editor
|
|
function RotaryOps.addPilots(var)
|
|
for uName, uData in pairs(mist.DBs.humansByName) do
|
|
if hasValue(RotaryOps.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(RotaryOps.addPilots, 1, timer.getTime() + 15)
|
|
end
|
|
RotaryOps.addPilots(1)
|
|
|
|
function RotaryOps.pushZone()
|
|
RotaryOps.setActiveZone(1)
|
|
end
|
|
|
|
function RotaryOps.fallBack()
|
|
RotaryOps.setActiveZone(-1)
|
|
end
|
|
|
|
function RotaryOps.setActiveZone(value) --this should accept the zone index so that we can set active value to any zone and set up zones appropriately
|
|
local old_index = RotaryOps.active_zone_index
|
|
local new_index = RotaryOps.active_zone_index + value
|
|
if new_index > #RotaryOps.zones then
|
|
new_index = #RotaryOps.zones
|
|
end
|
|
if new_index < 1 then
|
|
new_index = 1
|
|
end
|
|
|
|
if new_index ~= old_index then --the active zone is changing
|
|
|
|
ctld.activatePickupZone(RotaryOps.zones[old_index].outter_zone_name)
|
|
ctld.deactivatePickupZone(RotaryOps.zones[new_index].outter_zone_name)
|
|
RotaryOps.active_zone_index = new_index
|
|
|
|
end
|
|
RotaryOps.active_zone = RotaryOps.zones[new_index].outter_zone_name
|
|
trigger.action.outText("active zone: "..RotaryOps.active_zone.." old zone: "..RotaryOps.zones[old_index].outter_zone_name, 5)
|
|
trigger.action.setUserFlag(RotaryOps.active_zone_flag, RotaryOps.active_zone_index)
|
|
end
|
|
|
|
function RotaryOps.setupCTLD()
|
|
ctld.enableCrates = false
|
|
ctld.enabledFOBBuilding = false
|
|
ctld.JTAC_lock = "vehicle"
|
|
ctld.location_DMS = true
|
|
ctld.numberOfTroops = 24 --max loading size
|
|
|
|
ctld.unitLoadLimits = {
|
|
-- Remove the -- below to turn on options
|
|
["SA342Mistral"] = 4,
|
|
["SA342L"] = 4,
|
|
["SA342M"] = 4,
|
|
["UH-1H"] = 10,
|
|
["Mi-8MT"] = 24,
|
|
["Mi-24P"] = 8,
|
|
}
|
|
|
|
ctld.loadableGroups = {
|
|
-- {name = "Mortar Squad Red", inf = 2, mortar = 5, side =1 }, --would make a group loadable by RED only
|
|
{name = "Standard Group (10)", inf = 6, 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 Tank (8)", inf = 2, at = 6 },
|
|
{name = "Mortar Squad (6)", mortar = 6 },
|
|
{name = "Small Standard Group (4)", inf = 2, mg = 1, at = 1 },
|
|
{name = "JTAC Group (5)", inf = 4, jtac = 1 }, -- will make a loadable group with 4 infantry and a JTAC soldier for both coalitions
|
|
{name = "Single JTAC (1)", jtac = 1 },
|
|
{name = "Platoon (24)", inf = 12, mg = 4, at = 3, aa = 1 },
|
|
|
|
}
|
|
end
|
|
RotaryOps.setupCTLD()
|
|
|
|
|
|
function RotaryOps.logSomething()
|
|
--trigger.action.outText("zones: ".. mist.utils.tableShow(RotaryOps.zones), 5)
|
|
for key, value in pairs(RotaryOps.zones) do
|
|
trigger.action.outText("zone: ".. RotaryOps.zones[key].outter_zone_name, 5)
|
|
end
|
|
end
|
|
|
|
|
|
function RotaryOps.setupRadioMenu()
|
|
local conflict_zones_menu = missionCommands.addSubMenu( "Conflict Zones")
|
|
|
|
local push_zone = missionCommands.addCommand( "Push to next zone", conflict_zones_menu , RotaryOps.pushZone)
|
|
|
|
local fall_back = missionCommands.addCommand( "Fall back to prev zone" , conflict_zones_menu , RotaryOps.fallBack)
|
|
|
|
local log_something = missionCommands.addCommand( "Log something" , conflict_zones_menu , RotaryOps.logSomething)
|
|
end
|
|
RotaryOps.setupRadioMenu()
|
|
|
|
|
|
function RotaryOps.addZone(_outter_zone_name, _vars, group_id) --todo: implement zone group ids
|
|
group_id = group_id or 1
|
|
table.insert(RotaryOps.zones, {outter_zone_name = _outter_zone_name, vars = _vars})
|
|
RotaryOps.drawZones(RotaryOps.zones)
|
|
--ctld.dropOffZones[#ctld.dropOffZones + 1] = { _outter_zone_name, "green", 0 }
|
|
ctld.pickupZones[#ctld.pickupZones + 1] = { _outter_zone_name, "blue", -1, "yes", 0 } --should be set as innactive to start, can we dynamically change sides?
|
|
--trigger.action.outText("zones: ".. mist.utils.tableShow(RotaryOps.zones), 5)
|
|
end
|
|
|
|
function RotaryOps.setupConflict(_active_zone_flag)
|
|
|
|
RotaryOps.active_zone_flag = _active_zone_flag
|
|
RotaryOps.setActiveZone(0)
|
|
end
|
|
|
|
|
|
|
|
|
|
--[[
|
|
vars = {
|
|
inner_zone = '',
|
|
infantry_spawn = 10,
|
|
infantry_respawn = 50,
|
|
infantry_spawn_zone = ''
|
|
defender_coal = 'red'
|
|
}
|
|
]]
|
|
|