mirror of
https://github.com/FlightControl-Master/MOOSE_MISSIONS.git
synced 2026-08-22 06:44:43 +00:00
925 lines
50 KiB
Lua
925 lines
50 KiB
Lua
-----------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
-- __ __ ___ _ __ __ _____ ______ _____
|
|
-- / //_/ / | _____ _____ (_)_____ / /_ ____ _ ____ / /_ / ___//_ __// ___/
|
|
-- / ,< ______ / /| | / ___// ___// // ___// __// __ `// __ \ / __/ \__ \ / / \__ \
|
|
-- / /| |/_____// ___ | (__ )(__ )/ /(__ )/ /_ / /_/ // / / // /_ ___/ / / / ___/ /
|
|
--/_/_|_|_ _ /_/ |_|/____//____//_//____/_\__/_\__,_//_/ /_/ \__/ /____/ /_/ /____/ __ _____ _ __
|
|
-- / ___/ (_)____ ___ ____ / /___ /_ __/_____ ____ _ ____ _____ ____ ____ _____ / /_ / ___/ _____ _____ (_)____ / /_
|
|
-- \__ \ / // __ `__ \ / __ \ / // _ \ / / / ___// __ `// __ \ / ___// __ \ / __ \ / ___// __/ \__ \ / ___// ___// // __ \ / __/
|
|
-- ___/ // // / / / / // /_/ // // __/ / / / / / /_/ // / / /(__ )/ /_/ // /_/ // / / /_ ___/ // /__ / / / // /_/ // /_
|
|
--/____//_//_/ /_/ /_// .___//_/ \___/ /_/ /_/ \__,_//_/ /_//____// .___/ \____//_/ \__/ /____/ \___//_/ /_// .___/ \__/
|
|
-- /_/ /_/ /_/
|
|
-----------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
--
|
|
-------------------------------------------------------------------------------
|
|
--------------------------------- DEV NOTES ---------------------------------
|
|
-------------------------------------------------------------------------------
|
|
-- FIXES
|
|
-- TODO manage ground carriers somehow (menu refresh and cargo validation)
|
|
--
|
|
--
|
|
--
|
|
-- FUTURE FEATURES
|
|
-- TODO board troops that aren't currently alive in mission - necessary to make possible to board troops on a ship
|
|
-- TODO Spawn cargos during mission - scheduled spawn?
|
|
-- TODO Validate cargo before boarding (also)
|
|
-- TODO
|
|
--
|
|
|
|
-----------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
-- __ __ __ ___ __
|
|
-- / / / /_____ ___ _____ / |/ /____ _ ____ __ __ ____ _ / /
|
|
-- / / / // ___// _ \ / ___/ / /|_/ // __ `// __ \ / / / // __ `// /
|
|
--/ /_/ /(__ )/ __// / / / / // /_/ // / / // /_/ // /_/ // /
|
|
--\____//____/ \___//_/ /_/ /_/ \__,_//_/ /_/ \__,_/ \__,_//_/
|
|
--
|
|
-----------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
-------------------------------------------------------------------------------
|
|
----------------------------- WHAT K-ASS-STS IS? ------------------------------
|
|
-------------------------------------------------------------------------------
|
|
-- K-Assistant-Simple Transport Script aims to Assist the Mission Designers in the implementation of a Simple, Flexible and Realistic cargo management system based on MOOOSE Framework.
|
|
--
|
|
-- Simple - because it can be easily integrated into your missions, moreover it is also simple to use in game as the menus and functions available for the players are few and easy to use.
|
|
--
|
|
-- Flessible - because it tries to give way to mission designers to build their missions without limiting too much imagination by regulating every action.
|
|
-- Potentially with this script you can also load on your helicopter static objects not defined as "cargos" in DCS, for example a building or a cow...
|
|
-- It is up to the mission designer to decide what should be done and what should not be done.
|
|
--
|
|
-- Realistic - although the script leaves the mission designers free to use their imagination, at the same time it binds them to a realistic approach as,
|
|
-- thanks to the API released in 2020 by Eagle Dynamics, for each object loaded into your helicopter it will be simulated the addition of the mass relative to the cargo itself.
|
|
-- Pilots will now need to deal with cargo mass!
|
|
--
|
|
-------------------------------------------------------------------------------
|
|
------------------------------ SCRIPT SETTINGS --------------------------------
|
|
-------------------------------------------------------------------------------
|
|
-- The script can be configured to better meet the needs of the Mission Designer.
|
|
-- The configurations must be made by modifying the parameters contained in the sts_Settings table that you can find immediately after this section of instructions.
|
|
-- See sts_Settings table for more informations.
|
|
--
|
|
-------------------------------------------------------------------------------
|
|
------------------------- TAGS and LOADABLE OBJECTS ---------------------------
|
|
-------------------------------------------------------------------------------
|
|
-- TAGS : are needed to identify elemensts within the script, must be in groups, statics and zones defined in ME (Mission Editor)
|
|
-- Eg.
|
|
-- sts_Settings.CarrierTAG = "TRS" identify carriers groups that will transport cargos, all groups whose name contains "TRS" will be considered carriers.
|
|
-- sts_Settings.CargoGroupsTAG = "GRP" identify groups that can be boarded to carriers so, all groups whose name contains "GRP" will be considered CARGO_GROUPs.
|
|
-- sts_Settings.CargoCrateTAG = "CRT" identify static objects that can be loaded to carriers as CRATES, all static objects whose name contains "CRT" will be considered CARGO_CRATEs.
|
|
--
|
|
-- TAGs can identify CARGO_GROUPS, CARGO_CRATES, CARRIERS and ZONES (for more details regarding Zones please see ZONES section).
|
|
--
|
|
-- LOADABLE OBJECTS :
|
|
-- CARGO_GROUPS - By putting the TAG that identifies the loadable Groups ("GRP" by default) in the name of the group defined by Mission Editor, this will then be boardable in game.
|
|
-- You simply have to land your helicopter near the group and use the radio menus under F10 - Other to board them.
|
|
-- Group mass will be calculated and added to carrier mass.
|
|
--
|
|
-- CARGO_CRATES - By putting the TAG that identifies the loadable static as Crates ("CRT" by default) in the name of the group defined by Mission Editor, this will then be loadable in game.
|
|
-- You simply have to land your helicopter near the crate and use the radio menus under F10 - Other to load it.
|
|
--
|
|
-- BE AWARE : not all static objects have a defined mass!
|
|
-- For static objects belonging to the "Cargos" category, the mass set in the Mission Editor will be considered.
|
|
-- Static objects belonging to other categories (such as our beloved cows) do not have a mass that can be set in the Mission Editor,
|
|
-- for these objects a mass equal to the value defined in sts_Settings.DefaultStaticCargoMass (default is 666 kilograms) will always be considered.
|
|
--
|
|
-- CARGO VALIDATION if sts_Settings.ValidateCargo is true the cargo will be validated after being loaded.
|
|
-- If the loaded weight exceeds the maximum load capacity of the carrier the cargo will be unloaded immediately.
|
|
--
|
|
-------------------------------------------------------------------------------
|
|
----------------------------------- ZONES -------------------------------------
|
|
-------------------------------------------------------------------------------
|
|
-- The script involves the use of Zones (trigger zones defined in mission editor) to allow players to access some useful functions.
|
|
-- Also in this case, to identify the various types of zone, the script uses TAGs.
|
|
--
|
|
-- WAY POINT ZONES (WPZones) - WPZones are zones that can be defined by Mission Editor by inserting the TAG sts_settings.WPZoneTAG ("WPZ" by default) in the zone name.
|
|
-- When a CARGO_GROUP is unboarded inside a WPZone, after about 40 seconds it will head towards the center of the zone.
|
|
-- (Ideal for an assault)
|
|
--
|
|
-- PATROL ZONES (PTZones) - PTZones are zones that can be defined by Mission Editor by inserting the TAG sts_settings.PTZoneTAG ("PTZ" by default) in the zone name.
|
|
-- When a CARGO_GROUP is unboarded inside a PTZones, after about 40 seconds it will start patrolling endlessly and randomly the zone.
|
|
-- (Ideal for defending an area)
|
|
--
|
|
--
|
|
--
|
|
-- PATROL ZONES INSIDE WAY POINT ZONES - If a PT Zone is inside WP Zone after troops are unboarded inside they will head to the center of WP Zone.
|
|
-- Once they'll reach the center of WP Zone they will search for PT Zones, if they find one or more, they will start patrolling.
|
|
--
|
|
--
|
|
--
|
|
-- SMOKE ZONES (SMKZones) - SMKZones are zones that can be defined by Mission Editor by inserting the TAG sts_settings.SMKZoneTAG ("SMK" by default) in the zone name.
|
|
-- When a Smoke Zone is defined the center of it will be smoked endlessly after mission start.
|
|
--
|
|
-------------------------------------------------------------------------------
|
|
---------------------------- IN GAME ZONE CREATION ----------------------------
|
|
-------------------------------------------------------------------------------
|
|
-- In order to allow greater dynamism in the mission, the Zones described above can also be created directly in the game by using F10 Map Markers.
|
|
--
|
|
-- WAY POINT ZONES (WPZones) - Add a Marker in F10 Map, edit the marker text by inserting the following pattern: "#ZoneTAG ... (RadiusInMeters) ..."
|
|
-- Click outside the text field to apply, the zone will be created.
|
|
--
|
|
-- PATROL ZONES (PTZones) - Add a Marker in F10 Map, edit the marker text by inserting the following pattern: "#ZoneTAG ... (RadiusInMeters) ..."
|
|
-- Click outside the text field to apply, the zone will be created.
|
|
--
|
|
-- SMOKE ZONES (SMKZones) - Add a Marker in F10 Map, edit the marker text by inserting the following pattern: "#ZoneTAG ..."
|
|
-- Click outside the text field to apply, the zone will be created.
|
|
--
|
|
-- Some examples:
|
|
-- WPZone Mark Text : #WPZ Sochi (3000) -- will create a 3000 meter diameter WPZone at the marker position.
|
|
-- PTZone Mark Text : #PTZ Defend-1 (1740) -- will create a 1750 meter diameter PTZone at the marker position.
|
|
-- SMKZone Mark Text : #SMK LZ-1 -- will create a smoke that will last for 5 minutes at the marker position.
|
|
-----------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
-- Mission Created By Kappa
|
|
-- Using Moose by the DCS Moose Community
|
|
-- Prepared for github by Wingthor
|
|
-- Date 2020-12-15
|
|
|
|
-- ************************************************************************
|
|
-- ***************************** SETTINGS *******************************
|
|
-- ************************************************************************
|
|
|
|
sts_Settings = {
|
|
------------------------------------------------------------ GENERAL SETTINGS AND DEBUG ------------------------------------------------------------
|
|
Debug = false, -- Enable debug messages during mission
|
|
DebugTrace = false, -- Enable debug tracing on dcs.log
|
|
RefreshTime = 20, -- Set refresh time in seconds
|
|
------------------------------------------------------------------ CARGO SETTINGS ------------------------------------------------------------------
|
|
LoadRadius = 150, -- The radius till Cargo can be loaded into the carrier
|
|
NearRadius = 25, -- The radius in meters when the cargo will board the Carrier (25m have better performance for routing of booardable groups)
|
|
RespawnOnDestroyed = true, -- if true, destroyed cargos will be respawned at the initial position.
|
|
ValidateCargo = true, -- If true, will validate cargo before boarding if too heavy it will be unloaded
|
|
OverloadPercentage = 37, -- Defines the helicopter cargo overload limit (30% default setting - allow to load about 1000Kg in Huey and 2800Kg in Mi-8)
|
|
DefaultStaticCargoMass = 666, -- Defines the default cargo mass for static objects that are massless (all statics exept thoose in "Cargo" category, yes, cows also...)
|
|
----------------------------------------------------- CARRIERS AND LOADABLE SETTNGS AND TAGS -------------------------------------------------------
|
|
CargoGroupsTAG = "GRP", -- Define TAG needed to identify CARGO_GROUPs - it must be in the group name defined in ME
|
|
CargoCrateTAG = "CRT", -- Define TAG needed to identify CARGO_CRATEs - it must be in the group name defined in ME
|
|
CarrierTAG = "TRS", -- Define TAG needed to identify Carrier Groups - it must be in the group name defined in ME
|
|
------------------------------------------------------------- ZONES SETTNGS AND TAGS ----------------------------------------------------------------
|
|
WPZoneTAG = "WPZ", -- Define TAG needed to identify WP Zones - it must be in the zone name defined in ME or in F10 Mark on Map (#WPZ)
|
|
PTZoneTAG = "PTZ", -- Define TAG needed to identify PT Zones - it must be in the zone name defined in ME or in F10 Mark on Map (#PTZ)
|
|
SMKZoneTAG = "SMK", -- Define TAG needed to identify SMK Zones - it must be in the zone name defined in ME or in F10 Mark on Map (#SMK)
|
|
ZonesMarkOnMap = true, -- If true, WP zones will be marked on F10 map
|
|
}
|
|
|
|
-- disable MOOSE settings menu
|
|
_SETTINGS:SetPlayerMenuOff()
|
|
|
|
-- LOG TRACING
|
|
if sts_Settings.DebugTrace then BASE:TraceAll(true) end -- debug
|
|
|
|
-- ************************************************************************
|
|
-- ******************* DATA COLLECTION AND UTILITY *********************
|
|
-- ************************************************************************
|
|
|
|
--Carrier set - this groups will transport things
|
|
TransportSets = {
|
|
BLUE = SET_GROUP:New():FilterCoalitions("blue"):FilterActive():FilterPrefixes("TRS"):FilterStart(),
|
|
RED = SET_GROUP:New():FilterCoalitions("red"):FilterActive():FilterPrefixes("TRS"):FilterStart(),
|
|
NEUTRAL = SET_GROUP:New():FilterCoalitions("neutral"):FilterActive():FilterPrefixes("TRS"):FilterStart()
|
|
}
|
|
|
|
--SetS of zones used by the script
|
|
ZoneSets = {
|
|
TGTZONES = SET_ZONE:New():FilterPrefixes(sts_Settings.WPZoneTAG):FilterPrefixes(sts_Settings.PTZoneTAG):FilterStart(), --This zones will be the route target for cargo groups that are unloaded in this zones
|
|
SMKZONES = SET_ZONE:New():FilterPrefixes(sts_Settings.SMKZoneTAG):FilterOnce()
|
|
}
|
|
|
|
--Set of transportable groups and statics
|
|
TransportableSets = {
|
|
BLUE = {
|
|
Groups = SET_GROUP:New():FilterCoalitions("blue"):FilterActive(true):FilterCategoryGround():FilterPrefixes(sts_Settings.CargoGroupsTAG):FilterOnce() ,
|
|
Crates = SET_STATIC:New():FilterCoalitions("blue"):FilterPrefixes(sts_Settings.CargoCrateTAG):FilterOnce()
|
|
},
|
|
RED = {
|
|
Groups = SET_GROUP:New():FilterCoalitions("red"):FilterActive(true):FilterCategoryGround():FilterPrefixes(sts_Settings.CargoGroupsTAG):FilterOnce() ,
|
|
Crates = SET_STATIC:New():FilterCoalitions("red"):FilterPrefixes(sts_Settings.CargoCrateTAG):FilterOnce()
|
|
},
|
|
NEUTRAL = {
|
|
Groups = SET_GROUP:New():FilterCoalitions("neutral"):FilterActive(true):FilterCategoryGround():FilterPrefixes(sts_Settings.CargoGroupsTAG):FilterOnce() ,
|
|
Crates = SET_STATIC:New():FilterCoalitions("neutral"):FilterPrefixes(sts_Settings.CargoCrateTAG):FilterOnce()
|
|
}
|
|
}
|
|
|
|
--Table where CARGO_GROUPS created will be stored
|
|
CargoGroups = {
|
|
BLUE = {},
|
|
RED = {},
|
|
NEUTRAL = {}
|
|
}
|
|
|
|
--Table where CARGO_CRATES created will be stored
|
|
CargoCrates = {
|
|
BLUE = {},
|
|
RED = {},
|
|
NEUTRAL = {}
|
|
}
|
|
|
|
-- Table where to store menus data avalaible via F10 - Other radio items
|
|
Menu = {}
|
|
|
|
-- Table where to store mass data for carriers - carrier mass will be added/removed when cargo is loaded/unloaded
|
|
UnitMass = {}
|
|
|
|
-- Table where to store Zones created via mark points in F10 map
|
|
MarkTGTZonesMarks = {}
|
|
|
|
|
|
function spairs(t, order)
|
|
-- collect the keys
|
|
local keys = {}
|
|
for k in pairs(t) do keys[#keys+1] = k end
|
|
-- if order function given, sort by it by passing the table and keys a, b,
|
|
-- otherwise just sort the keys
|
|
if order then
|
|
table.sort(keys, function(a,b) return order(t, a, b) end)
|
|
else
|
|
table.sort(keys)
|
|
end
|
|
-- return the iterator function
|
|
local i = 0
|
|
return function()
|
|
i = i + 1
|
|
if keys[i] then
|
|
return keys[i], t[keys[i]]
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Returns a cargo and carrier's mass info message
|
|
function CarrierMassInfo(carrierGroup)
|
|
local carrierUnit = carrierGroup:GetFirstUnitAlive()
|
|
local carrierUnitName = carrierUnit:GetName()
|
|
local carrierUnitCargoBayMaxWeight = UnitMass[carrierUnitName].maxMass
|
|
local maxLoadableMass = math.ceil(((carrierUnitCargoBayMaxWeight /100) * sts_Settings.OverloadPercentage) + carrierUnitCargoBayMaxWeight)
|
|
local actualLoadableMass = math.ceil(((carrierUnitCargoBayMaxWeight /100) * sts_Settings.OverloadPercentage) + (carrierUnitCargoBayMaxWeight - UnitMass[carrierUnitName].cargoMass))
|
|
local loadedMass = UnitMass[carrierUnitName].cargoMass
|
|
carrierGroup:MessageToGroup("\n".."Mass loaded in cargo bay: "..loadedMass.." Kg".."\n".."Remaining loadable mass: "..actualLoadableMass.." Kg".."\n".."Maximum loadable mass"..maxLoadableMass.." Kg", 15, carrierGroup, "- CARRIER MASS INFO")
|
|
end
|
|
|
|
-- Returns a message for each cargo in cargo bay
|
|
function CarrierCargoInfo(carrierGroup)
|
|
local carrierUnit = carrierGroup:GetFirstUnitAlive()
|
|
local carrierUnitName = carrierUnit:GetName()
|
|
local cargoList = carrierUnit:GetCargo()
|
|
carrierGroup:MessageToGroup("\n", 16, carrierGroup, "- CARGO MANIFEST")
|
|
for k, cargo in pairs(cargoList) do
|
|
local cargoName = cargo:GetName()
|
|
carrierGroup:MessageToGroup("Cargo Mass : ".. UnitMass[carrierUnitName][cargoName].." Kg", 15, carrierGroup, cargoName)
|
|
end
|
|
end
|
|
|
|
-- ************************************************************************
|
|
-- *************************** ZONES HANDLERS ****************************
|
|
-- ************************************************************************
|
|
|
|
-- Uses MarkPoints to show WP zones in F10 Map
|
|
-- runs only if Settings.ZonesMarkOnMap is true
|
|
function MarkZonesOnMap(zoneList)
|
|
if sts_Settings.ZonesMarkOnMap then
|
|
for k, zone in pairs(zoneList) do
|
|
zone:MarkZone(20)
|
|
end
|
|
end
|
|
end
|
|
-- Smokes zones defined in ME - reapeat every 5 minutes
|
|
function SmokeZones(zoneList)
|
|
for k, zone in pairs(zoneList) do
|
|
local zonePoint = zone:GetCoordinate()
|
|
local smokeZoneScheduler = SCHEDULER:New( nil,
|
|
function()
|
|
zonePoint:SmokeBlue()
|
|
end, {}, 5, 310
|
|
)
|
|
end
|
|
end
|
|
|
|
-- Creates zones when a tagged mark is added on F10 Map
|
|
function AddZoneFromMark(markCoordinate, markText, markID)
|
|
if string.match(markText, "#"..sts_Settings.WPZoneTAG) or string.match(markText, "#"..sts_Settings.PTZoneTAG) or string.match(markText, "#"..sts_Settings.SMKZoneTAG)then
|
|
local markIDstring = tostring(markID)
|
|
local markCoordinateV2 = markCoordinate:GetVec2()
|
|
local zoneRadius = 500
|
|
if string.match(markText, "%((%d+)%)") then
|
|
zoneRadius = tonumber(string.match(markText, "%((%d+)%)")) -- set zone radius if defined in markText
|
|
end
|
|
if string.match(markText, "#"..sts_Settings.WPZoneTAG) then -- create WPZone
|
|
MarkTGTZonesMarks[markIDstring] = ZONE_RADIUS:New(sts_Settings.WPZoneTAG.."_mk_"..markIDstring , markCoordinateV2, zoneRadius)
|
|
MarkTGTZonesMarks[markIDstring]:MarkZone(20)
|
|
ZoneSets.TGTZONES:AddZone(MarkTGTZonesMarks[markIDstring])
|
|
if sts_Settings.Debug then MESSAGE:New( markText.." - WP Zone Created", 3):ToAll() end --debug
|
|
elseif string.match(markText, "#"..sts_Settings.PTZoneTAG) then -- create PTZone
|
|
MarkTGTZonesMarks[markIDstring] = ZONE_RADIUS:New(sts_Settings.PTZoneTAG.."_mk_"..markIDstring , markCoordinateV2, zoneRadius)
|
|
MarkTGTZonesMarks[markIDstring]:MarkZone(20)
|
|
ZoneSets.TGTZONES:AddZone(MarkTGTZonesMarks[markIDstring])
|
|
if sts_Settings.Debug then MESSAGE:New( markText.." - PT Zone Created", 3):ToAll() end --debug
|
|
elseif string.match(markText, "#"..sts_Settings.SMKZoneTAG) then -- create SMKZone
|
|
markCoordinate:SmokeBlue()
|
|
if sts_Settings.Debug then MESSAGE:New( markText.." - Smoke Zone Created", 3):ToAll() end --debug
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Removes zones created via mark on F10 Map
|
|
function RemoveZoneFromMark(markText, markID)
|
|
if string.match(markText, "#WPZ") or string.match(markText, "#PTZ") then
|
|
local markIDstring = tostring(markID)
|
|
if string.match(markText, "#WPZ") then
|
|
ZoneSets.TGTZONES:RemoveZonesByName(sts_Settings.WPZoneTAG.."_mk_"..markIDstring)
|
|
elseif string.match(markText, "#PTZ") then
|
|
ZoneSets.TGTZONES:RemoveZonesByName(sts_Settings.PTZoneTAG.."_mk_"..markIDstring)
|
|
end
|
|
MarkTGTZonesMarks[markID] = nil
|
|
MESSAGE:New( markText.." Zone Removed", 3):ToAll()
|
|
end
|
|
end
|
|
|
|
-- ************************************************************************
|
|
-- *************************** MASS HANDLERS ****************************
|
|
-- ************************************************************************
|
|
|
|
-- calculates cargo mass
|
|
-- params : cargo object
|
|
-- carrierUnitName (optional, needed only if cargo is loaded)
|
|
function CalculateCargoMass(cargo, carrierUnitName)
|
|
local cargoType = cargo:GetClassName()
|
|
local cargoName = cargo:GetName()
|
|
local cargoMass
|
|
|
|
if cargo:IsLoaded() and carrierUnitName then -- if cargo is loaded gets the cargo mass from carrier's mass table
|
|
cargoMass = UnitMass[carrierUnitName][cargoName]
|
|
elseif cargoType == "CARGO_GROUP" and not cargo:IsLoaded() then -- if GROUP cargo isn't loaded calculates cargo mass
|
|
local cargo_GroupObject = cargo:GetObject()
|
|
local cargoAliveUnits = cargo_GroupObject:CountAliveUnits()
|
|
local cargoInitUnitsCount = cargo:GetCount()
|
|
local cargoWeight = cargo:GetWeight()
|
|
cargoMass = (cargoWeight/cargoInitUnitsCount)*cargoAliveUnits
|
|
elseif cargoType == "CARGO_CRATE" and not cargo:IsLoaded() then -- if CRATE cargo isn't loaded calculates cargo mass
|
|
local pStatic = StaticObject.getByName( cargoName ) -- DCS API finds static object by name
|
|
local iWeight = pStatic:getCargoWeight() -- DCS API gets static mass defined in ME
|
|
if iWeight > 0 then
|
|
cargoMass = iWeight
|
|
else
|
|
cargoMass = sts_Settings.DefaultStaticCargoMass -- if Static object has no mass set, applies default value
|
|
end
|
|
end
|
|
return cargoMass
|
|
end
|
|
|
|
-- Add mass to a carrier
|
|
function AddMass(carrierGroup, cargo, cargoAliveUnits)
|
|
local cargoClass = cargo:GetClassName()
|
|
local cargoName = cargo:GetName()
|
|
local carrierUnit = carrierGroup:GetFirstUnitAlive()
|
|
local carrierUnitName = carrierUnit:GetName()
|
|
local cargoMass = 0
|
|
if cargoClass == "CARGO_GROUP" then
|
|
local cargoInitUnitsCount = cargo:GetCount()
|
|
local cargoWeight = cargo:GetWeight()
|
|
cargoMass = (cargoWeight/cargoInitUnitsCount)*cargoAliveUnits -- calculates mass based un cargo alive units
|
|
elseif cargoClass == "CARGO_CRATE" then
|
|
local pStatic = StaticObject.getByName( cargoName ) -- DCS API finds static object by name
|
|
local iWeight = pStatic:getCargoWeight() -- DCS API gets static mass defined in ME
|
|
if iWeight > 0 then
|
|
cargoMass = iWeight
|
|
else
|
|
cargoMass = sts_Settings.DefaultStaticCargoMass -- if Static object has no mass set, applies default value
|
|
end
|
|
end
|
|
UnitMass[carrierUnitName][cargoName] = cargoMass -- record mass for specific cargo
|
|
UnitMass[carrierUnitName].cargoMass = UnitMass[carrierUnitName].cargoMass + cargoMass -- record calculated total cargo mass in carrier cargo bay
|
|
trigger.action.setUnitInternalCargo( carrierUnitName , UnitMass[carrierUnitName].cargoMass) -- DCS API that defines the cargo mass
|
|
carrierGroup:MessageToGroup("\n".."Mass loaded: "..cargoMass.." Kg ".."\n".."Total Mass in cargo bay: "..UnitMass[carrierUnitName].cargoMass.." Kg", 10, carrierGroup, "- CARGO-INFO")
|
|
end
|
|
|
|
-- Remove mass from a carrier
|
|
function RemoveMass(carrierGroup, cargo)
|
|
local cargoName = cargo:GetName()
|
|
local carrierUnit = carrierGroup:GetFirstUnitAlive()
|
|
local carrierUnitName = carrierUnit:GetName()
|
|
UnitMass[carrierUnitName].cargoMass = UnitMass[carrierUnitName].cargoMass - UnitMass[carrierUnitName][cargoName]
|
|
trigger.action.setUnitInternalCargo( carrierUnitName , UnitMass[carrierUnitName].cargoMass) -- DCS API that defines the cargo mass
|
|
carrierGroup:MessageToGroup("\n".."Mass Unloaded: "..UnitMass[carrierUnitName][cargoName].." Kg ".."\n".."Total Mass in cargo bay: "..UnitMass[carrierUnitName].cargoMass.." Kg", 10, carrierGroup, "- CARGO-INFO")
|
|
end
|
|
|
|
-- ************************************************************************
|
|
-- *************************** CARGO HANDLERS ***************************
|
|
-- ************************************************************************
|
|
|
|
--Generate CARGO_GROUPS and store them in CargoGroups table
|
|
function CargoGroupGenerator(group)
|
|
local groupName = group:GetName()
|
|
if string.match(groupName, sts_Settings.CargoGroupsTAG) then
|
|
local COALITION = string.upper(group:GetCoalitionName())
|
|
if not CargoGroups[COALITION][groupName] then
|
|
CargoGroups[COALITION][groupName] = CARGO_GROUP:New(group, "GROUP", groupName, sts_Settings.LoadRadius, sts_Settings.NearRadius)
|
|
end
|
|
if sts_Settings.RespawnOnDestroyed then CargoGroups[COALITION][groupName]:RespawnOnDestroyed(true) end
|
|
end
|
|
end
|
|
|
|
-- Generate CARGO_CRATES and store them in CargoCrates table
|
|
function CargoCrateGenerator(static, COALITION)
|
|
local staticName = static:GetName()
|
|
CargoCrates[COALITION][staticName] = CARGO_CRATE:New(static, "CRATE", staticName, 50, 50)
|
|
if sts_Settings.RespawnOnDestroyed then CargoCrates[COALITION][staticName]:RespawnOnDestroyed(true) end
|
|
end
|
|
|
|
-- Routes cargo through WP and PT Zones
|
|
function CargoRouter( cargoGroup )
|
|
local wpZone = nil
|
|
local ptZones = nil
|
|
local zones = ZoneSets.TGTZONES:GetSet() --gets zones table from zone set
|
|
local cargo = cargoGroup
|
|
|
|
for k, zone in pairs(zones) do -- loop zones
|
|
if cargo:IsInZone(zone) then
|
|
local zoneName = zone:GetName()
|
|
if string.match(zoneName, sts_Settings.WPZoneTAG) then
|
|
wpZone = zone
|
|
elseif string.match(zoneName, sts_Settings.PTZoneTAG) then
|
|
if not ptZones then ptZones = {} end
|
|
ptZones[#ptZones+1] = zone
|
|
end
|
|
end
|
|
end
|
|
if cargo:IsAlive() and not cargo:IsLoaded() then
|
|
local transportableGroup = cargo:GetObject()
|
|
if wpZone then
|
|
local zonePoint = wpZone:GetCoordinate()
|
|
transportableGroup:RouteGroundTo(zonePoint, 50, "Diamond", 20, AfterCargoRouter, transportableGroup ) -- route at the zone center
|
|
elseif ptZones then
|
|
transportableGroup:PatrolZones(ptZones, 50, "Diamond", 20, 50) -- patrol a list of zones
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Routes cargo groups through PT Zones after they reach the center of a WP Zone
|
|
function AfterCargoRouter(group)
|
|
local ptZones = {}
|
|
local zones = ZoneSets.TGTZONES:GetSet()
|
|
for k, zone in pairs(zones) do
|
|
if group:IsInZone(zone) then
|
|
local zoneName = zone:GetName()
|
|
if string.match(zoneName, sts_Settings.PTZoneTAG) then
|
|
ptZones[#ptZones+1] = zone
|
|
end
|
|
end
|
|
end
|
|
if #ptZones < 1 then return end
|
|
if group:IsAlive() then
|
|
group:PatrolZones(ptZones, 50, "Diamond", 20, 50)
|
|
end
|
|
end
|
|
|
|
-- Check and validate cargo after that is been loaded on carrier
|
|
-- Needed to avoid people to overload carriers and transport too many troops that would not have enought room inside carrier
|
|
function ValidateCargoAfterLoad(carrierUnit)
|
|
if not sts_Settings.ValidateCargo then return true end
|
|
local carrierUnitName = carrierUnit:GetName()
|
|
local carrierUnitCargoBayMaxWeight = UnitMass[carrierUnitName].maxMass
|
|
local loadableMass = math.ceil(((carrierUnitCargoBayMaxWeight /100) * sts_Settings.OverloadPercentage) + carrierUnitCargoBayMaxWeight)
|
|
if UnitMass[carrierUnitName].cargoMass <= loadableMass then
|
|
return true
|
|
else
|
|
return false
|
|
end
|
|
end
|
|
|
|
-- Unboards troops and define actions to do after unboarding
|
|
--cargoGroup = table[1]
|
|
--carrierGroup = table[2]
|
|
--COALITION = table[3]
|
|
--if NOT nil will prevent cargo to be routed in zones after unboarding = table[4]
|
|
function UnBoardTroops(table)
|
|
local cargoGroup = table[1]
|
|
local cargoGroupName = cargoGroup:GetName()
|
|
--local cargo_GroupObject = cargoGroup:GetObject()
|
|
local carrierGroup = table[2]
|
|
--local carrierGroupName = carrierGroup:GetName()
|
|
local carrierUnit = carrierGroup:GetFirstUnitAlive()
|
|
local COALITION = table[3]
|
|
local carrierPoint = carrierGroup:GetCoordinate()
|
|
--local zoneList = ZoneSets.TGTZONES:GetSet()
|
|
local RouteCargo -- if false cargo will not be routed by CargoRouter() after unboarding
|
|
if table[4] == nil then
|
|
RouteCargo = true
|
|
else
|
|
RouteCargo = false
|
|
end
|
|
local MenuGeneratorDelayed = TIMER:New(MenuGenerator, carrierGroup)
|
|
|
|
if cargoGroup:IsUnboarding() then
|
|
carrierGroup:MessageToGroup("Cargo is already unboarding", 10, carrierGroup, cargoGroupName)
|
|
return
|
|
end
|
|
|
|
-- NOTE do not use that P.o.S. of :onafterUnBoard() that does not fucking work fine for me -.-
|
|
function cargoGroup:onafterUnLoad(Event, From, To, Core, ToPointVec2)
|
|
--delay for menu re-generation wait to group to be unboarded
|
|
MenuGeneratorDelayed:Start(5)
|
|
carrierGroup:MessageToGroup("Unboarded!", 10, carrierGroup, cargoGroupName)
|
|
RemoveMass(carrierGroup, cargoGroup) -- removes cargo mass from carrier
|
|
carrierUnit:RemoveCargo(cargoGroup) -- need to remove cargo manually - cargo group are added to cargo automatically when boarded but not removed when unboarded
|
|
-- Schedule group routing to Zones because need to wait until all of group is unboarded, also simulates times needed to pathfinding - timer set on 40 seconds
|
|
if RouteCargo == true then
|
|
local unloadscheduler = SCHEDULER:New( nil,
|
|
function()
|
|
CargoRouter(cargoGroup)
|
|
end, {}, 40
|
|
)
|
|
end
|
|
end
|
|
|
|
if math.floor(carrierUnit:GetVelocityKMH()) <= 10 and math.floor(carrierGroup:GetHeight(true)) <= 20 then -- prevents from unboarding from high speed or altitude
|
|
cargoGroup:UnBoard(carrierPoint:GetRandomCoordinateInRadius(30, 20))
|
|
carrierGroup:MessageToGroup("Unboarding...", 10, carrierGroup, cargoGroupName)
|
|
MenuGeneratorDelayed:Start(1)
|
|
else
|
|
carrierGroup:MessageToGroup("You must be under 20 meters and less then 10 Km/h to unboard!!", 10, carrierGroup, cargoGroupName)
|
|
end
|
|
end
|
|
|
|
-- Board troops to a carrier
|
|
--cargoGroup = table[1]
|
|
--carrierGroup = table[2]
|
|
--COALITION = table[3]
|
|
function BoardTroops(table)
|
|
local cargoGroup = table[1]
|
|
local cargoGroupName = cargoGroup:GetName()
|
|
|
|
local cargo_GroupObject = cargoGroup:GetObject()
|
|
local cargoAliveUnits = cargo_GroupObject:CountAliveUnits()
|
|
local carrierGroup = table[2]
|
|
--local carrierGroupName = carrierGroup:GetName()
|
|
local carrierUnit = carrierGroup:GetFirstUnitAlive()
|
|
--local carrierUnitName = carrierUnit:GetName()
|
|
--local carrierPoint = carrierUnit:GetCoordinate()
|
|
local COALITION = table[3]
|
|
if cargoGroup:IsBoarding() then -- prevent boarding from multiple carriers
|
|
carrierGroup:MessageToGroup("Is already boarding - cannot board", 15, carrierGroup, cargoGroupName)
|
|
MenuGenerator(carrierGroup)
|
|
return
|
|
end
|
|
local MenuGeneratorDelayed = TIMER:New(MenuGenerator, carrierGroup)
|
|
|
|
-- function cargoGroup:onafterLoad(Event, From, To) -- , CargoCarrier
|
|
function cargoGroup:OnEnterLoaded()
|
|
carrierGroup:MessageToGroup("Boarded!", 10, carrierGroup, cargoGroupName)
|
|
MenuGeneratorDelayed:Start(2)
|
|
AddMass(carrierGroup, cargoGroup, cargoAliveUnits) -- Add cargo mass to carrier
|
|
if not ValidateCargoAfterLoad(carrierUnit) then -- if cargo not validated it will be unloaded
|
|
UnBoardTroops({cargoGroup, carrierGroup, COALITION, 1})
|
|
carrierGroup:MessageToGroup(cargoGroupName.."\n".."Cargo not loadable. Too big or heavy!", 10, carrierGroup, "- CARGO-INFO")
|
|
end
|
|
end -- END ON AFTER LOAD
|
|
|
|
if math.floor(carrierUnit:GetVelocityKMH()) <= 10 and math.floor(carrierGroup:GetHeight(true)) <= 20 then -- prevents from boarding from high speed or altitude
|
|
cargoGroup:Board(carrierUnit, sts_Settings.NearRadius)
|
|
carrierGroup:MessageToGroup("Boarding...", 10, carrierGroup, cargoGroupName)
|
|
MenuGenerator(carrierGroup)
|
|
boardScheduler = SCHEDULER:New( nil, -- if cargo not boarded within 3 minutes, since it is not possible to stop the boarding process, this will abort the boarding process destroyng and respawning cargo
|
|
function()
|
|
if cargoGroup:IsLoaded() then boardScheduler:Stop() return end -- cargo now is loaded do nothing
|
|
if cargoGroup:IsBoarding() then -- if cargo is still boarding
|
|
cargoGroup:RespawnOnDestroyed(true)
|
|
cargoGroup:Destroy()
|
|
carrierGroup:MessageToGroup("Unable to board!\nBOARDING ABORTED AND CARGO GROUP RESPAWNED TO IT'S INITIAL POSITION!", 10, carrierGroup, cargoGroupName)
|
|
boardScheduler:Stop()
|
|
end
|
|
end, {}, 180
|
|
)
|
|
else
|
|
carrierGroup:MessageToGroup("You must be under 20 meters and less then 10 Km/h to board!!", 10, carrierGroup, cargoGroupName)
|
|
end
|
|
end
|
|
|
|
--Unload crates and define actions to do after unloading
|
|
--cargoCrate = table[1]
|
|
--carrierGroup = table[2]
|
|
--COALITION = table[3]
|
|
function UnLoadCrate(table)
|
|
local cargoCrate = table[1]
|
|
local cargoCrateName = cargoCrate:GetName()
|
|
local carrierGroup = table[2]
|
|
--local carrierName = carrierGroup:GetName()
|
|
local carrierUnit = carrierGroup:GetFirstUnitAlive()
|
|
local COALITION = table[3]
|
|
local carrierPoint = carrierUnit:GetCoordinate()
|
|
local MenuGeneratorDelayed = TIMER:New(MenuGenerator, carrierGroup)
|
|
function cargoCrate:onafterUnLoad(Event, From, To) -- , CargoCarrier
|
|
|
|
carrierGroup:MessageToGroup("Crate Unloaded!", 10, carrierGroup, cargoCrateName)
|
|
RemoveMass(carrierGroup, cargoCrate) -- removes mass from carrier
|
|
carrierUnit:RemoveCargo(cargoCrate) -- remove cargo manually-only cargo group are added to cargo automatically when boarded but not removed when unboarded crates need to be added and removed manually
|
|
MenuGeneratorDelayed:Start(1)
|
|
end
|
|
if math.floor(carrierUnit:GetVelocityKMH()) <= 10 and math.floor(carrierGroup:GetHeight(true)) <= 5 then -- prevents from unloading from high speed or altitude
|
|
cargoCrate:UnLoad(carrierPoint:GetRandomCoordinateInRadius(20, 15))
|
|
MenuGeneratorDelayed:Start(1)
|
|
else
|
|
carrierGroup:MessageToGroup("You must be under 5 meters and lass then 10 Km/h to unload!!", 10, carrierGroup, cargoCrateName)
|
|
end
|
|
end
|
|
|
|
--Load crates to a carrier and generate menus for unboarding
|
|
--cargoCrate = table[1]
|
|
--carrierGroup = table[2]
|
|
--COALITION = table[3]
|
|
function LoadCrate(table)
|
|
local cargoCrate = table[1]
|
|
local cargoCrateName = cargoCrate:GetName()
|
|
local carrierGroup = table[2]
|
|
--local carrierGroupName = carrierGroup:GetName()
|
|
local carrierUnit = carrierGroup:GetFirstUnitAlive()
|
|
--local carrierUnitName = carrierUnit:GetName()
|
|
--local carrierPoint = carrierUnit:GetCoordinate()
|
|
local COALITION = table[3]
|
|
local MenuGeneratorDelayed = TIMER:New(MenuGenerator, carrierGroup)
|
|
-- function cargoCrate:onafterLoad(Event, From, To, CargoCarrier) --
|
|
function cargoCrate:OnEnterLoaded() --
|
|
carrierGroup:MessageToGroup("Crate Loaded!", 10, carrierGroup, cargoCrateName)
|
|
-- MenuGeneratorDelayed:Start(1)
|
|
AddMass(carrierGroup, cargoCrate)
|
|
if not ValidateCargoAfterLoad(carrierUnit) then
|
|
UnLoadCrate({cargoCrate, carrierGroup, COALITION})
|
|
carrierGroup:MessageToGroup(cargoCrateName.."\n".."Cargo not loadable. Too big or heavy!", 10, carrierGroup, "- CARGO-INFO")
|
|
else
|
|
carrierUnit:AddCargo(cargoCrate)
|
|
end
|
|
MenuGeneratorDelayed:Start(1)
|
|
end -- END enterloaded
|
|
if math.floor(carrierUnit:GetVelocityKMH()) <= 3 and math.floor(carrierGroup:GetHeight(true)) <= 3 then -- prevents from loading from high speed or altitude
|
|
cargoCrate:Load(carrierUnit)
|
|
MenuGenerator(carrierGroup)
|
|
else
|
|
carrierGroup:MessageToGroup("You must be on ground to load crates!!!", 10, carrierGroup, cargoCrateName)
|
|
end
|
|
end
|
|
|
|
-- ************************************************************************
|
|
-- *************************** CARGO SPAWNER ****************************
|
|
-- ************************************************************************
|
|
--TODO DEVELOP
|
|
--CargoSpawn = SPAWN:New("AntiTank_x6_GRP-1"):OnSpawnGroup(
|
|
-- function( SpawnGroup )
|
|
-- if sts_Settings.Debug then MESSAGE:New( "AFTER SPAWN" , 3):ToAll() end --debug
|
|
-- local groupName = SpawnGroup:GetName()
|
|
-- local COALITION = string.upper(SpawnGroup:GetCoalitionName())
|
|
-- if not CargoGroups[COALITION][groupName] then
|
|
-- CargoGroups[COALITION][groupName] = CARGO_GROUP:New(SpawnGroup, "GROUP", groupName, sts_Settings.LoadRadius, sts_Settings.NearRadius)
|
|
-- end
|
|
-- end
|
|
--)
|
|
|
|
--function SpawnFromStatic(staticName)
|
|
--
|
|
-- local spawnStatic = STATIC:FindByName( staticName )
|
|
-- --local staticHeight = spawnStatic:GetHeight()
|
|
-- local staticVec3 = spawnStatic:GetPositionVec3()
|
|
--
|
|
---- if sts_Settings.Debug then MESSAGE:New( "height SPAWN "..staticHeight , 5):ToAll() end --debug
|
|
-- -- Spawn from the static position at the height specified in the ME of the group template!
|
|
-- cargoSpawn = SPAWN:New("AntiTank_x6_GRP-1"):SpawnFromVec3(staticVec3)
|
|
--
|
|
--end
|
|
|
|
-- ************************************************************************
|
|
-- *************************** MENU HANDLERS ****************************
|
|
-- ************************************************************************
|
|
-- Generates Radio Menus under F10 - Other
|
|
function MenuGenerator(carrierGroup)
|
|
local carrierGroupName = carrierGroup:GetName()
|
|
if not string.match(carrierGroupName , sts_Settings.CarrierTAG) then return end
|
|
local carrierCoalition = string.upper(carrierGroup:GetCoalitionName())
|
|
local carrierUnit = carrierGroup:GetFirstUnitAlive()
|
|
local carrierUnitName = carrierUnit:GetName()
|
|
local carrierUnitCoord = carrierUnit:GetCoordinate()
|
|
-- -- DEBUG
|
|
-- local unitCargo = carrierUnit:GetCargo()
|
|
-- for k, cargo in pairs(unitCargo) do
|
|
--
|
|
-- MESSAGE:New( "cargo --- ---- "..cargo:GetName() , 10):ToAll()
|
|
-- end
|
|
|
|
-------- GROUPS MENUS GEN/DEL --------
|
|
local distanceTableGroups = {} -- table that will contain cargo distance from carrier (format : {[cargoName] = distance}
|
|
local cargoTableGroups = {} -- table that will contain cargo group objects ( format: {[cargoName] = cargoObject}
|
|
for k, cargoGroup in pairs(CargoGroups[carrierCoalition]) do
|
|
local cargoGroupName = cargoGroup:GetName()
|
|
|
|
if cargoGroup:IsInLoadRadius(carrierUnitCoord) and not cargoGroup:IsBoarding() and not cargoGroup:IsLoaded() and cargoGroup:IsAlive() then --if cargo is boardable
|
|
local cargoGroupCoordinate = cargoGroup:GetCoordinate()
|
|
local cargoDistanceFromCarrier = carrierUnitCoord:DistanceFromPointVec2(cargoGroupCoordinate) -- calculates cargo distance from carrier
|
|
distanceTableGroups[cargoGroupName] = math.ceil(cargoDistanceFromCarrier) -- insert data to table
|
|
cargoTableGroups[cargoGroupName] = cargoGroup -- insert data to table
|
|
if Menu[carrierGroupName].commands.unload[cargoGroupName] then -- since the cargo is boardable (so it isn't loaded), if an unload command menu for cargo exists remove it
|
|
Menu[carrierGroupName].commands.unload[cargoGroupName]:Remove()
|
|
Menu[carrierGroupName].commands.unload[cargoGroupName] = nil
|
|
end
|
|
elseif not cargoGroup:IsInLoadRadius(carrierUnitCoord) or not cargoGroup:IsAlive() or cargoGroup:IsLoaded() or cargoGroup:IsBoarding() then -- if cargo is not boarddable removes command menu
|
|
if Menu[carrierGroupName].commands[cargoGroupName] then
|
|
Menu[carrierGroupName].commands[cargoGroupName]:Remove()
|
|
Menu[carrierGroupName].commands[cargoGroupName] = nil
|
|
end
|
|
end
|
|
end
|
|
for cargoname, distance in spairs(distanceTableGroups, function(t,a,b) return t[b] > t[a] end) do -- generates radio menus for group boarding sorted by distance from carrier
|
|
-- TODO Verify if this "if statement" is still needed
|
|
if Menu[carrierGroupName].commands[cargoname] then
|
|
Menu[carrierGroupName].commands[cargoname]:Remove()
|
|
end
|
|
Menu[carrierGroupName].commands[cargoname] = MENU_GROUP_COMMAND:New( carrierGroup, "Board "..string.gsub(cargoname, sts_Settings.CargoGroupsTAG, "").."("..CalculateCargoMass(cargoTableGroups[cargoname]).." Kg)", Menu[carrierGroupName].commands.mainTroops, BoardTroops, {cargoTableGroups[cargoname], carrierGroup, carrierCoalition} )
|
|
end
|
|
|
|
-------- CRATES MENUS GEN/DEL --------
|
|
local distanceTableCrates = {} -- table that will contain cargo distance from carrier (format : {[cargoName] = distance}
|
|
local cargoTableCrates = {} -- table that will contain cargo group objects ( format: {[cargoName] = cargoObject}
|
|
for k, cargoCrate in pairs(CargoCrates[carrierCoalition]) do
|
|
local cargoCrateName = cargoCrate:GetName()
|
|
|
|
if cargoCrate:IsInLoadRadius(carrierUnitCoord) and not cargoCrate:IsLoaded() and cargoCrate:IsAlive() then--if cargo is loadable
|
|
local cargoCrateCoordinate = cargoCrate:GetCoordinate()
|
|
local cargoDistanceFromCarrier = carrierUnitCoord:DistanceFromPointVec2(cargoCrateCoordinate) -- calculates cargo distance from carrier
|
|
distanceTableCrates[cargoCrateName] = math.ceil(cargoDistanceFromCarrier) -- insert data to table
|
|
cargoTableCrates[cargoCrateName] = cargoCrate -- insert data to table
|
|
if Menu[carrierGroupName].commands.unload[cargoCrateName] then -- since the cargo is loadable (so it isn't loaded), if an unload command menu for cargo exists remove it
|
|
Menu[carrierGroupName].commands.unload[cargoCrateName]:Remove()
|
|
Menu[carrierGroupName].commands.unload[cargoCrateName] = nil
|
|
end
|
|
elseif not cargoCrate:IsInLoadRadius(carrierUnitCoord) or not cargoCrate:IsAlive() or cargoCrate:IsLoaded() then -- if cargo is not loadable removes command menu
|
|
if Menu[carrierGroupName].commands[cargoCrateName] then
|
|
Menu[carrierGroupName].commands[cargoCrateName]:Remove()
|
|
Menu[carrierGroupName].commands[cargoCrateName] = nil
|
|
end
|
|
end
|
|
end
|
|
|
|
for cargoname, distance in spairs(distanceTableCrates, function(t,a,b) return t[b] > t[a] end) do -- generates radio menus for crates loading sorted by distance from carrier
|
|
if Menu[carrierGroupName].commands[cargoname] then
|
|
Menu[carrierGroupName].commands[cargoname]:Remove()
|
|
end
|
|
Menu[carrierGroupName].commands[cargoname] = MENU_GROUP_COMMAND:New( carrierGroup, "Load "..string.gsub(cargoname, sts_Settings.CargoCrateTAG, "").."("..CalculateCargoMass(cargoTableCrates[cargoname]).." Kg)", Menu[carrierGroupName].commands.mainCrates, LoadCrate, {cargoTableCrates[cargoname], carrierGroup, carrierCoalition} )
|
|
end
|
|
|
|
local unitCargo = carrierUnit:GetCargo() -- generates unload command menus based on loaded cargos
|
|
for k, cargo in pairs(unitCargo) do
|
|
local cargoName = cargo:GetName()
|
|
if not cargo:IsUnboarding() then
|
|
if cargo:GetType() == "GROUP" then --TODO
|
|
Menu[carrierGroupName].commands.unload[cargoName] = MENU_GROUP_COMMAND:New( carrierGroup, "Unboard "..string.gsub(cargoName, sts_Settings.CargoGroupsTAG, "").." ("..CalculateCargoMass(cargo,carrierUnitName).." Kg)", Menu[carrierGroupName].commands.unload.mainTroops, UnBoardTroops, {cargo, carrierGroup, carrierCoalition} )
|
|
else
|
|
Menu[carrierGroupName].commands.unload[cargoName] = MENU_GROUP_COMMAND:New( carrierGroup, "Unload "..string.gsub(cargoName, sts_Settings.CargoGroupsTAG, "").." ("..CalculateCargoMass(cargo,carrierUnitName).." Kg)", Menu[carrierGroupName].commands.unload.mainCrates, UnLoadCrate, {cargo, carrierGroup, carrierCoalition} )
|
|
end
|
|
elseif cargo:IsUnboarding() then
|
|
Menu[carrierGroupName].commands.unload[cargoName]:Remove()
|
|
end
|
|
end
|
|
end
|
|
|
|
-- ************************************************************************
|
|
-- ************************* REFRESH SCHEDULER **************************
|
|
-- ************************************************************************
|
|
|
|
MainScheduler = SCHEDULER:New( nil,
|
|
function()
|
|
|
|
-- SpawnFromStatic("stitic") -- test
|
|
|
|
-- for each group of each transport set check if the group is still alive:
|
|
-- if group is NOT alive remove the group from set
|
|
-- if group IS alive then call the function MenuGenerator for this group
|
|
for skey, transportSet in pairs(TransportSets) do
|
|
local transportSetTable = transportSet:GetSet()
|
|
for gkey, transportGroup in pairs(transportSetTable) do
|
|
if not transportGroup:IsAlive() then
|
|
transportSet:RemoveGroupsByName(transportGroup:GetName())
|
|
else
|
|
MenuGenerator(transportGroup)
|
|
end
|
|
end
|
|
end
|
|
end, {}, 5, sts_Settings.RefreshTime
|
|
)
|
|
|
|
-- ************************************************************************
|
|
-- **************************** SCRIPT INIT *****************************
|
|
-- ************************************************************************
|
|
|
|
--Generate CARGO_GROUPS and CARGO_CRATES for each coalition at the beginning of the mission
|
|
|
|
TransportableSets.BLUE.Groups:ForEachGroup(
|
|
function (group)
|
|
CargoGroupGenerator(group)
|
|
end
|
|
)
|
|
TransportableSets.BLUE.Crates:ForEachStatic(
|
|
function (static)
|
|
CargoCrateGenerator(static, "BLUE")
|
|
end
|
|
)
|
|
TransportableSets.RED.Groups:ForEachGroup(
|
|
function (group)
|
|
CargoGroupGenerator(group)
|
|
end
|
|
)
|
|
TransportableSets.RED.Crates:ForEachStatic(
|
|
function (static)
|
|
CargoCrateGenerator(static, "RED")
|
|
end
|
|
)
|
|
TransportableSets.NEUTRAL.Groups:ForEachGroup(
|
|
function (group)
|
|
CargoGroupGenerator(group)
|
|
end
|
|
)
|
|
TransportableSets.NEUTRAL.Crates:ForEachStatic(
|
|
function (static)
|
|
CargoCrateGenerator(static, "NEUTRAL")
|
|
end
|
|
)
|
|
|
|
MarkZonesOnMap(ZoneSets.TGTZONES:GetSet())
|
|
SmokeZones(ZoneSets.SMKZONES:GetSet())
|
|
|
|
-- init carrier removing all old data if present and creating tables for menu and mass management
|
|
function CarrierInit(carrierGroup)
|
|
if not carrierGroup then return end
|
|
local carrierGroupName = carrierGroup:GetName()
|
|
if not string.match(carrierGroupName, sts_Settings.CarrierTAG) then return end
|
|
local carrierUnit = carrierGroup:GetFirstUnitAlive()
|
|
local carrierUnitName = carrierUnit:GetName()
|
|
|
|
UnitMass[carrierUnitName] = nil --reset mass data
|
|
UnitMass[carrierUnitName] = {}
|
|
UnitMass[carrierUnitName].cargoMass = 0
|
|
carrierUnit:ClearCargo() -- reset cargo
|
|
carrierUnit:SetCargoBayWeightLimit() -- reset cargo bay limit
|
|
UnitMass[carrierUnitName].maxMass = carrierUnit:GetCargoBayFreeWeight()
|
|
|
|
if Menu[carrierGroupName] then Menu[carrierGroupName].main:Remove() end -- reset menus
|
|
Menu[carrierGroupName] = nil
|
|
Menu[carrierGroupName] = {}
|
|
Menu[carrierGroupName].main = MENU_GROUP:New( carrierGroup, "K-STS" )
|
|
Menu[carrierGroupName].commands = {}
|
|
Menu[carrierGroupName].commands.unload = {}
|
|
-- Menu[carrierGroupName].commands.mainUnload = MENU_GROUP:New( carrierGroup, "Unload Cargos", Menu[carrierGroupName].main )
|
|
Menu[carrierGroupName].commands.mainTroops = MENU_GROUP:New( carrierGroup, "Troops Transport", Menu[carrierGroupName].main )
|
|
Menu[carrierGroupName].commands.unload.mainTroops = MENU_GROUP:New( carrierGroup, "Unboard Troops", Menu[carrierGroupName].commands.mainTroops )
|
|
Menu[carrierGroupName].commands.mainCrates = MENU_GROUP:New( carrierGroup, "Crates Transport", Menu[carrierGroupName].main )
|
|
Menu[carrierGroupName].commands.unload.mainCrates = MENU_GROUP:New( carrierGroup, "Unload Crates", Menu[carrierGroupName].commands.mainCrates )
|
|
Menu[carrierGroupName].commands.mainInfo = MENU_GROUP:New( carrierGroup, "Info...", Menu[carrierGroupName].main )
|
|
Menu[carrierGroupName].commands.carrierMassInfo = MENU_GROUP_COMMAND:New( carrierGroup, "Mass Info", Menu[carrierGroupName].commands.mainInfo, CarrierMassInfo, carrierGroup)
|
|
Menu[carrierGroupName].commands.carrierCargoInfo = MENU_GROUP_COMMAND:New( carrierGroup, "Cargo Manifest", Menu[carrierGroupName].commands.mainInfo, CarrierCargoInfo, carrierGroup)
|
|
end
|
|
|
|
MESSAGE:New( "K-STS Loaded" , 5):ToAll()
|
|
|
|
-- ************************************************************************
|
|
-- *************************** EVENT HANDLERS ***************************
|
|
-- ************************************************************************
|
|
|
|
-- Event Handling Subscriptions
|
|
EventHandler = EVENTHANDLER:New()
|
|
EventHandler:HandleEvent(EVENTS.Birth)
|
|
EventHandler:HandleEvent(EVENTS.Land)
|
|
EventHandler:HandleEvent(EVENTS.Takeoff)
|
|
--EventHandler:HandleEvent(EVENTS.Dead)
|
|
EventHandler:HandleEvent(EVENTS.MarkChange)
|
|
EventHandler:HandleEvent(EVENTS.MarkRemoved)
|
|
|
|
|
|
function EventHandler:OnEventBirth(EventData)
|
|
CarrierInit(EventData.IniGroup)
|
|
MenuGenerator(EventData.IniGroup)
|
|
|
|
if sts_Settings.Debug then MESSAGE:New( "DEBUG: ".."BIRTH EVENT" , 3):ToAll() end --debug
|
|
end
|
|
|
|
function EventHandler:OnEventLand(EventData)
|
|
MenuGenerator(EventData.IniGroup)
|
|
if sts_Settings.Debug then MESSAGE:New( "DEBUG: ".."LAND EVENT" , 3):ToAll() end --debug
|
|
end
|
|
|
|
function EventHandler:OnEventTakeoff(EventData)
|
|
MenuGenerator(EventData.IniGroup)
|
|
if sts_Settings.Debug then MESSAGE:New( "DEBUG: ".."TAKE-OFF EVENT" , 3):ToAll() end --debug
|
|
end
|
|
|
|
--function EventHandler:OnEventDead(EventData)
|
|
-- if sts_Settings.Debug then MESSAGE:New( "DEBUG: ".."DEAD EVENT" , 3):ToAll() end --debug
|
|
--end
|
|
|
|
function EventHandler:OnEventMarkChange(EventData)
|
|
--EVENTDATA.MarkCoalition
|
|
--EVENTDATA.MarkCoordinate
|
|
--EVENTDATA.MarkGroupID
|
|
--EVENTDATA.MarkID
|
|
--EVENTDATA.MarkText
|
|
--EVENTDATA.MarkVec3
|
|
AddZoneFromMark(EventData.MarkCoordinate, EventData.MarkText, EventData.MarkID)
|
|
if sts_Settings.Debug then MESSAGE:New( "DEBUG: ".."MARK CHANGE EVENT" , 3):ToAll() end --debug
|
|
end
|
|
|
|
function EventHandler:OnEventMarkRemoved(EventData)
|
|
RemoveZoneFromMark(EventData.MarkText, EventData.MarkID)
|
|
if sts_Settings.Debug then MESSAGE:New( "DEBUG: ".."MARK REMOVE EVENT" , 3):ToAll() end --debug
|
|
end
|