RotorOps/RotaryOps.lua
2021-12-29 23:20:33 -08:00

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'
}
]]