mirror of
https://github.com/FlightControl-Master/MOOSE.git
synced 2025-10-29 16:58:06 +00:00
File diff suppressed because it is too large
Load Diff
@@ -3628,36 +3628,39 @@ function AIRBOSS:_CheckAIStatus()
|
||||
-- Unit
|
||||
local unit=element.unit
|
||||
|
||||
-- Get lineup and distance to carrier.
|
||||
local lineup=self:_Lineup(unit, true)
|
||||
if unit and unit:IsAlive() then
|
||||
|
||||
local unitcoord=unit:GetCoord()
|
||||
-- Get lineup and distance to carrier.
|
||||
local lineup=self:_Lineup(unit, true)
|
||||
|
||||
local dist=unitcoord:Get2DDistance(self:GetCoord())
|
||||
local unitcoord=unit:GetCoord()
|
||||
|
||||
-- Distance in NM.
|
||||
local distance=UTILS.MetersToNM(dist)
|
||||
local dist=unitcoord:Get2DDistance(self:GetCoord())
|
||||
|
||||
-- Altitude in ft.
|
||||
local alt=UTILS.MetersToFeet(unitcoord.y)
|
||||
-- Distance in NM.
|
||||
local distance=UTILS.MetersToNM(dist)
|
||||
|
||||
-- Check if parameters are right and flight is in the groove.
|
||||
if lineup<2 and distance<=0.75 and alt<500 and not element.ballcall then
|
||||
-- Altitude in ft.
|
||||
local alt=UTILS.MetersToFeet(unitcoord.y)
|
||||
|
||||
-- Paddles: Call the ball!
|
||||
self:RadioTransmission(self.LSORadio, self.LSOCall.CALLTHEBALL, nil, nil, nil, true)
|
||||
-- Check if parameters are right and flight is in the groove.
|
||||
if lineup<2 and distance<=0.75 and alt<500 and not element.ballcall then
|
||||
|
||||
-- Pilot: "405, Hornet Ball, 3.2"
|
||||
self:_LSOCallAircraftBall(element.onboard,self:_GetACNickname(unit:GetTypeName()), self:_GetFuelState(unit)/1000)
|
||||
-- Paddles: Call the ball!
|
||||
self:RadioTransmission(self.LSORadio, self.LSOCall.CALLTHEBALL, nil, nil, nil, true)
|
||||
|
||||
-- Paddles: Roger ball after 0.5 seconds.
|
||||
self:RadioTransmission(self.LSORadio, self.LSOCall.ROGERBALL, nil, nil, 0.5, true)
|
||||
-- Pilot: "405, Hornet Ball, 3.2"
|
||||
self:_LSOCallAircraftBall(element.onboard,self:_GetACNickname(unit:GetTypeName()), self:_GetFuelState(unit)/1000)
|
||||
|
||||
-- Flight element called the ball.
|
||||
element.ballcall=true
|
||||
-- Paddles: Roger ball after 0.5 seconds.
|
||||
self:RadioTransmission(self.LSORadio, self.LSOCall.ROGERBALL, nil, nil, 0.5, true)
|
||||
|
||||
-- This is for the whole flight. Maybe we need it.
|
||||
flight.ballcall=true
|
||||
-- Flight element called the ball.
|
||||
element.ballcall=true
|
||||
|
||||
-- This is for the whole flight. Maybe we need it.
|
||||
flight.ballcall=true
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
@@ -6263,6 +6266,11 @@ function AIRBOSS:_ScanCarrierZone()
|
||||
|
||||
-- Get flight group if possible.
|
||||
local knownflight=self:_GetFlightFromGroupInQueue(group, self.flights)
|
||||
|
||||
-- Unknown new AI flight. Create a new flight group.
|
||||
if not knownflight and not self:_IsHuman(group) then
|
||||
knownflight=self:_CreateFlightGroup(group)
|
||||
end
|
||||
|
||||
-- Get aircraft type name.
|
||||
local actype=group:GetTypeName()
|
||||
@@ -6276,10 +6284,10 @@ function AIRBOSS:_ScanCarrierZone()
|
||||
local putintomarshal=false
|
||||
|
||||
-- Get flight group.
|
||||
local flight=_DATABASE:GetFlightGroup(groupname)
|
||||
local flight=_DATABASE:GetOpsGroup(groupname)
|
||||
|
||||
if flight and flight:IsInbound() and flight.destbase:GetName()==self.carrier:GetName() then
|
||||
if flight.ishelo then
|
||||
if flight.isHelo then
|
||||
else
|
||||
putintomarshal=true
|
||||
end
|
||||
@@ -6320,10 +6328,7 @@ function AIRBOSS:_ScanCarrierZone()
|
||||
|
||||
else
|
||||
|
||||
-- Unknown new AI flight. Create a new flight group.
|
||||
if not self:_IsHuman(group) then
|
||||
self:_CreateFlightGroup(group)
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
475
Moose Development/Moose/Ops/Brigade.lua
Normal file
475
Moose Development/Moose/Ops/Brigade.lua
Normal file
@@ -0,0 +1,475 @@
|
||||
--- **Ops** - Brigade Warehouse.
|
||||
--
|
||||
-- **Main Features:**
|
||||
--
|
||||
-- * Manage platoons
|
||||
-- * Carry out ARTY and PATROLZONE missions (AUFTRAG)
|
||||
-- * Define rearming zones
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- ### Author: **funkyfranky**
|
||||
--
|
||||
-- @module Ops.Brigade
|
||||
-- @image OPS_Brigade.png
|
||||
|
||||
|
||||
--- BRIGADE class.
|
||||
-- @type BRIGADE
|
||||
-- @field #string ClassName Name of the class.
|
||||
-- @field #number verbose Verbosity of output.
|
||||
-- @field #table rearmingZones Rearming zones. Each element is of type `#BRIGADE.SupplyZone`.
|
||||
-- @field #table refuellingZones Refuelling zones. Each element is of type `#BRIGADE.SupplyZone`.
|
||||
-- @field Core.Set#SET_ZONE retreatZones Retreat zone set.
|
||||
-- @extends Ops.Legion#LEGION
|
||||
|
||||
--- Be surprised!
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- # The BRIGADE Concept
|
||||
--
|
||||
-- An BRIGADE consists of one or multiple PLATOONs. These platoons "live" in a WAREHOUSE that has a phyiscal struction (STATIC or UNIT) and can be captured or destroyed.
|
||||
--
|
||||
--
|
||||
-- @field #BRIGADE
|
||||
BRIGADE = {
|
||||
ClassName = "BRIGADE",
|
||||
verbose = 0,
|
||||
rearmingZones = {},
|
||||
refuellingZones = {},
|
||||
}
|
||||
|
||||
--- Supply Zone.
|
||||
-- @type BRIGADE.SupplyZone
|
||||
-- @field Core.Zone#ZONE zone The zone.
|
||||
-- @field Ops.Auftrag#AUFTRAG mission Mission assigned to supply ammo or fuel.
|
||||
-- @field #boolean markerOn If `true`, marker is on.
|
||||
-- @field Wrapper.Marker#MARKER marker F10 marker.
|
||||
|
||||
--- BRIGADE class version.
|
||||
-- @field #string version
|
||||
BRIGADE.version="0.1.0"
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- ToDo list
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- TODO: Spawn when hosting warehouse is a ship or oil rig or gas platform.
|
||||
-- TODO: Rearming zones.
|
||||
-- TODO: Retreat zones.
|
||||
-- DONE: Add weapon range.
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- Constructor
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
--- Create a new BRIGADE class object.
|
||||
-- @param #BRIGADE self
|
||||
-- @param #string WarehouseName Name of the warehouse STATIC or UNIT object representing the warehouse.
|
||||
-- @param #string BrigadeName Name of the brigade.
|
||||
-- @return #BRIGADE self
|
||||
function BRIGADE:New(WarehouseName, BrigadeName)
|
||||
|
||||
-- Inherit everything from LEGION class.
|
||||
local self=BASE:Inherit(self, LEGION:New(WarehouseName, BrigadeName)) -- #BRIGADE
|
||||
|
||||
-- Nil check.
|
||||
if not self then
|
||||
BASE:E(string.format("ERROR: Could not find warehouse %s!", WarehouseName))
|
||||
return nil
|
||||
end
|
||||
|
||||
-- Set some string id for output to DCS.log file.
|
||||
self.lid=string.format("BRIGADE %s | ", self.alias)
|
||||
|
||||
-- Defaults
|
||||
self:SetRetreatZones()
|
||||
|
||||
-- Add FSM transitions.
|
||||
-- From State --> Event --> To State
|
||||
self:AddTransition("*", "ArmyOnMission", "*") -- An ARMYGROUP was send on a Mission (AUFTRAG).
|
||||
|
||||
------------------------
|
||||
--- Pseudo Functions ---
|
||||
------------------------
|
||||
|
||||
--- Triggers the FSM event "Start". Starts the BRIGADE. Initializes parameters and starts event handlers.
|
||||
-- @function [parent=#BRIGADE] Start
|
||||
-- @param #BRIGADE self
|
||||
|
||||
--- Triggers the FSM event "Start" after a delay. Starts the BRIGADE. Initializes parameters and starts event handlers.
|
||||
-- @function [parent=#BRIGADE] __Start
|
||||
-- @param #BRIGADE self
|
||||
-- @param #number delay Delay in seconds.
|
||||
|
||||
|
||||
--- Triggers the FSM event "Stop". Stops the BRIGADE and all its event handlers.
|
||||
-- @param #BRIGADE self
|
||||
|
||||
--- Triggers the FSM event "Stop" after a delay. Stops the BRIGADE and all its event handlers.
|
||||
-- @function [parent=#BRIGADE] __Stop
|
||||
-- @param #BRIGADE self
|
||||
-- @param #number delay Delay in seconds.
|
||||
|
||||
|
||||
--- Triggers the FSM event "ArmyOnMission".
|
||||
-- @function [parent=#BRIGADE] ArmyOnMission
|
||||
-- @param #BRIGADE self
|
||||
-- @param Ops.ArmyGroup#ARMYGROUP ArmyGroup The ARMYGROUP on mission.
|
||||
-- @param Ops.Auftrag#AUFTRAG Mission The mission.
|
||||
|
||||
--- Triggers the FSM event "ArmyOnMission" after a delay.
|
||||
-- @function [parent=#BRIGADE] __ArmyOnMission
|
||||
-- @param #BRIGADE self
|
||||
-- @param #number delay Delay in seconds.
|
||||
-- @param Ops.ArmyGroup#ARMYGROUP ArmyGroup The ARMYGROUP on mission.
|
||||
-- @param Ops.Auftrag#AUFTRAG Mission The mission.
|
||||
|
||||
--- On after "ArmyOnMission" event.
|
||||
-- @function [parent=#BRIGADE] OnAfterArmyOnMission
|
||||
-- @param #BRIGADE self
|
||||
-- @param #string From From state.
|
||||
-- @param #string Event Event.
|
||||
-- @param #string To To state.
|
||||
-- @param Ops.ArmyGroup#ARMYGROUP ArmyGroup The ARMYGROUP on mission.
|
||||
-- @param Ops.Auftrag#AUFTRAG Mission The mission.
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- User Functions
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
--- Add a platoon to the brigade.
|
||||
-- @param #BRIGADE self
|
||||
-- @param Ops.Platoon#PLATOON Platoon The platoon object.
|
||||
-- @return #BRIGADE self
|
||||
function BRIGADE:AddPlatoon(Platoon)
|
||||
|
||||
-- Add platoon to brigade.
|
||||
table.insert(self.cohorts, Platoon)
|
||||
|
||||
-- Add assets to platoon.
|
||||
self:AddAssetToPlatoon(Platoon, Platoon.Ngroups)
|
||||
|
||||
-- Set brigade of platoon.
|
||||
Platoon:SetBrigade(self)
|
||||
|
||||
-- Start platoon.
|
||||
if Platoon:IsStopped() then
|
||||
Platoon:Start()
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
|
||||
--- Add asset group(s) to platoon.
|
||||
-- @param #BRIGADE self
|
||||
-- @param Ops.Platoon#PLATOON Platoon The platoon object.
|
||||
-- @param #number Nassets Number of asset groups to add.
|
||||
-- @return #BRIGADE self
|
||||
function BRIGADE:AddAssetToPlatoon(Platoon, Nassets)
|
||||
|
||||
if Platoon then
|
||||
|
||||
-- Get the template group of the platoon.
|
||||
local Group=GROUP:FindByName(Platoon.templatename)
|
||||
|
||||
if Group then
|
||||
|
||||
-- Debug text.
|
||||
local text=string.format("Adding asset %s to platoon %s", Group:GetName(), Platoon.name)
|
||||
self:T(self.lid..text)
|
||||
|
||||
-- Add assets to airwing warehouse.
|
||||
self:AddAsset(Group, Nassets, nil, nil, nil, nil, Platoon.skill, Platoon.livery, Platoon.name)
|
||||
|
||||
else
|
||||
self:E(self.lid.."ERROR: Group does not exist!")
|
||||
end
|
||||
|
||||
else
|
||||
self:E(self.lid.."ERROR: Platoon does not exit!")
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Define a set of retreat zones.
|
||||
-- @param #BRIGADE self
|
||||
-- @param Core.Set#SET_ZONE RetreatZoneSet Set of retreat zones.
|
||||
-- @return #BRIGADE self
|
||||
function BRIGADE:SetRetreatZones(RetreatZoneSet)
|
||||
self.retreatZones=RetreatZoneSet or SET_ZONE:New()
|
||||
return self
|
||||
end
|
||||
|
||||
--- Add a retreat zone.
|
||||
-- @param #BRIGADE self
|
||||
-- @param Core.Zone#ZONE RetreatZone Retreat zone.
|
||||
-- @return #BRIGADE self
|
||||
function BRIGADE:AddRetreatZone(RetreatZone)
|
||||
self.retreatZones:AddZone(RetreatZone)
|
||||
return self
|
||||
end
|
||||
|
||||
--- Get retreat zones.
|
||||
-- @param #BRIGADE self
|
||||
-- @return Core.Set#SET_ZONE Set of retreat zones.
|
||||
function BRIGADE:GetRetreatZones()
|
||||
return self.retreatZones
|
||||
end
|
||||
|
||||
--- Add a rearming zone.
|
||||
-- @param #BRIGADE self
|
||||
-- @param Core.Zone#ZONE RearmingZone Rearming zone.
|
||||
-- @return #BRIGADE.SupplyZone The rearming zone data.
|
||||
function BRIGADE:AddRearmingZone(RearmingZone)
|
||||
|
||||
local rearmingzone={} --#BRIGADE.SupplyZone
|
||||
|
||||
rearmingzone.zone=RearmingZone
|
||||
rearmingzone.mission=nil
|
||||
rearmingzone.marker=MARKER:New(rearmingzone.zone:GetCoordinate(), "Rearming Zone"):ToCoalition(self:GetCoalition())
|
||||
|
||||
table.insert(self.rearmingZones, rearmingzone)
|
||||
|
||||
return rearmingzone
|
||||
end
|
||||
|
||||
|
||||
--- Add a refuelling zone.
|
||||
-- @param #BRIGADE self
|
||||
-- @param Core.Zone#ZONE RefuellingZone Refuelling zone.
|
||||
-- @return #BRIGADE.SupplyZone The refuelling zone data.
|
||||
function BRIGADE:AddRefuellingZone(RefuellingZone)
|
||||
|
||||
local supplyzone={} --#BRIGADE.SupplyZone
|
||||
|
||||
supplyzone.zone=RefuellingZone
|
||||
supplyzone.mission=nil
|
||||
supplyzone.marker=MARKER:New(supplyzone.zone:GetCoordinate(), "Refuelling Zone"):ToCoalition(self:GetCoalition())
|
||||
|
||||
table.insert(self.rearmingZones, supplyzone)
|
||||
|
||||
return supplyzone
|
||||
end
|
||||
|
||||
|
||||
--- Get platoon by name.
|
||||
-- @param #BRIGADE self
|
||||
-- @param #string PlatoonName Name of the platoon.
|
||||
-- @return Ops.Platoon#PLATOON The Platoon object.
|
||||
function BRIGADE:GetPlatoon(PlatoonName)
|
||||
local platoon=self:_GetCohort(PlatoonName)
|
||||
return platoon
|
||||
end
|
||||
|
||||
--- Get platoon of an asset.
|
||||
-- @param #BRIGADE self
|
||||
-- @param Functional.Warehouse#WAREHOUSE.Assetitem Asset The platoon asset.
|
||||
-- @return Ops.Platoon#PLATOON The platoon object.
|
||||
function BRIGADE:GetPlatoonOfAsset(Asset)
|
||||
local platoon=self:GetPlatoon(Asset.squadname)
|
||||
return platoon
|
||||
end
|
||||
|
||||
--- Remove asset from platoon.
|
||||
-- @param #BRIGADE self
|
||||
-- @param Functional.Warehouse#WAREHOUSE.Assetitem Asset The platoon asset.
|
||||
function BRIGADE:RemoveAssetFromPlatoon(Asset)
|
||||
local platoon=self:GetPlatoonOfAsset(Asset)
|
||||
if platoon then
|
||||
platoon:DelAsset(Asset)
|
||||
end
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- FSM Functions
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
--- Start BRIGADE FSM.
|
||||
-- @param #BRIGADE self
|
||||
function BRIGADE:onafterStart(From, Event, To)
|
||||
|
||||
-- Start parent Warehouse.
|
||||
self:GetParent(self, BRIGADE).onafterStart(self, From, Event, To)
|
||||
|
||||
-- Info.
|
||||
self:I(self.lid..string.format("Starting BRIGADE v%s", BRIGADE.version))
|
||||
|
||||
end
|
||||
|
||||
--- Update status.
|
||||
-- @param #BRIGADE self
|
||||
function BRIGADE:onafterStatus(From, Event, To)
|
||||
|
||||
-- Status of parent Warehouse.
|
||||
self:GetParent(self).onafterStatus(self, From, Event, To)
|
||||
|
||||
-- FSM state.
|
||||
local fsmstate=self:GetState()
|
||||
|
||||
----------------
|
||||
-- Transport ---
|
||||
----------------
|
||||
|
||||
self:CheckTransportQueue()
|
||||
|
||||
--------------
|
||||
-- Mission ---
|
||||
--------------
|
||||
|
||||
-- Check if any missions should be cancelled.
|
||||
self:CheckMissionQueue()
|
||||
|
||||
---------------------
|
||||
-- Rearming Zones ---
|
||||
---------------------
|
||||
|
||||
for _,_rearmingzone in pairs(self.rearmingZones) do
|
||||
local rearmingzone=_rearmingzone --#BRIGADE.SupplyZone
|
||||
if (not rearmingzone.mission) or rearmingzone.mission:IsOver() then
|
||||
rearmingzone.mission=AUFTRAG:NewAMMOSUPPLY(rearmingzone.zone)
|
||||
self:AddMission(rearmingzone.mission)
|
||||
end
|
||||
end
|
||||
|
||||
-----------------------
|
||||
-- Refuelling Zones ---
|
||||
-----------------------
|
||||
|
||||
-- Check refuelling zones.
|
||||
for _,_supplyzone in pairs(self.refuellingZones) do
|
||||
local supplyzone=_supplyzone --#BRIGADE.SupplyZone
|
||||
-- Check if mission is nil or over.
|
||||
if (not supplyzone.mission) or supplyzone.mission:IsOver() then
|
||||
supplyzone.mission=AUFTRAG:NewFUELSUPPLY(supplyzone.zone)
|
||||
self:AddMission(supplyzone.mission)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-----------
|
||||
-- Info ---
|
||||
-----------
|
||||
|
||||
-- General info:
|
||||
if self.verbose>=1 then
|
||||
|
||||
-- Count missions not over yet.
|
||||
local Nmissions=self:CountMissionsInQueue()
|
||||
|
||||
-- Asset count.
|
||||
local Npq, Np, Nq=self:CountAssetsOnMission()
|
||||
|
||||
-- Asset string.
|
||||
local assets=string.format("%d [OnMission: Total=%d, Active=%d, Queued=%d]", self:CountAssets(), Npq, Np, Nq)
|
||||
|
||||
-- Output.
|
||||
local text=string.format("%s: Missions=%d, Platoons=%d, Assets=%s", fsmstate, Nmissions, #self.cohorts, assets)
|
||||
self:I(self.lid..text)
|
||||
end
|
||||
|
||||
------------------
|
||||
-- Mission Info --
|
||||
------------------
|
||||
if self.verbose>=2 then
|
||||
local text=string.format("Missions Total=%d:", #self.missionqueue)
|
||||
for i,_mission in pairs(self.missionqueue) do
|
||||
local mission=_mission --Ops.Auftrag#AUFTRAG
|
||||
|
||||
local prio=string.format("%d/%s", mission.prio, tostring(mission.importance)) ; if mission.urgent then prio=prio.." (!)" end
|
||||
local assets=string.format("%d/%d", mission:CountOpsGroups(), mission.Nassets or 0)
|
||||
local target=string.format("%d/%d Damage=%.1f", mission:CountMissionTargets(), mission:GetTargetInitialNumber(), mission:GetTargetDamage())
|
||||
|
||||
text=text..string.format("\n[%d] %s %s: Status=%s, Prio=%s, Assets=%s, Targets=%s", i, mission.name, mission.type, mission.status, prio, assets, target)
|
||||
end
|
||||
self:I(self.lid..text)
|
||||
end
|
||||
|
||||
--------------------
|
||||
-- Transport Info --
|
||||
--------------------
|
||||
if self.verbose>=2 then
|
||||
local text=string.format("Transports Total=%d:", #self.transportqueue)
|
||||
for i,_transport in pairs(self.transportqueue) do
|
||||
local transport=_transport --Ops.OpsTransport#OPSTRANSPORT
|
||||
|
||||
local prio=string.format("%d/%s", transport.prio, tostring(transport.importance)) ; if transport.urgent then prio=prio.." (!)" end
|
||||
local carriers=string.format("Ncargo=%d/%d, Ncarriers=%d", transport.Ncargo, transport.Ndelivered, transport.Ncarrier)
|
||||
|
||||
text=text..string.format("\n[%d] UID=%d: Status=%s, Prio=%s, Cargo: %s", i, transport.uid, transport:GetState(), prio, carriers)
|
||||
end
|
||||
self:I(self.lid..text)
|
||||
end
|
||||
|
||||
-------------------
|
||||
-- Platoon Info --
|
||||
-------------------
|
||||
if self.verbose>=3 then
|
||||
local text="Platoons:"
|
||||
for i,_platoon in pairs(self.cohorts) do
|
||||
local platoon=_platoon --Ops.Platoon#PLATOON
|
||||
|
||||
local callsign=platoon.callsignName and UTILS.GetCallsignName(platoon.callsignName) or "N/A"
|
||||
local modex=platoon.modex and platoon.modex or -1
|
||||
local skill=platoon.skill and tostring(platoon.skill) or "N/A"
|
||||
|
||||
-- Platoon text.
|
||||
text=text..string.format("\n* %s %s: %s*%d/%d, Callsign=%s, Modex=%d, Skill=%s", platoon.name, platoon:GetState(), platoon.aircrafttype, platoon:CountAssets(true), #platoon.assets, callsign, modex, skill)
|
||||
end
|
||||
self:I(self.lid..text)
|
||||
end
|
||||
|
||||
-------------------
|
||||
-- Rearming Info --
|
||||
-------------------
|
||||
if self.verbose>=4 then
|
||||
local text="Rearming Zones:"
|
||||
for i,_rearmingzone in pairs(self.rearmingZones) do
|
||||
local rearmingzone=_rearmingzone --#BRIGADE.SupplyZone
|
||||
-- Info text.
|
||||
text=text..string.format("\n* %s: Mission status=%s, suppliers=%d", rearmingzone.zone:GetName(), rearmingzone.mission:GetState(), rearmingzone.mission:CountOpsGroups())
|
||||
end
|
||||
self:I(self.lid..text)
|
||||
end
|
||||
|
||||
-------------------
|
||||
-- Refuelling Info --
|
||||
-------------------
|
||||
if self.verbose>=4 then
|
||||
local text="Refuelling Zones:"
|
||||
for i,_refuellingzone in pairs(self.refuellingZones) do
|
||||
local refuellingzone=_refuellingzone --#BRIGADE.SupplyZone
|
||||
-- Info text.
|
||||
text=text..string.format("\n* %s: Mission status=%s, suppliers=%d", refuellingzone.zone:GetName(), refuellingzone.mission:GetState(), refuellingzone.mission:CountOpsGroups())
|
||||
end
|
||||
self:I(self.lid..text)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- FSM Functions
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
--- On after "ArmyOnMission".
|
||||
-- @param #BRIGADE self
|
||||
-- @param #string From From state.
|
||||
-- @param #string Event Event.
|
||||
-- @param #string To To state.
|
||||
-- @param Ops.ArmyGroup#ARMYGROUP ArmyGroup Ops army group on mission.
|
||||
-- @param Ops.Auftrag#AUFTRAG Mission The requested mission.
|
||||
function BRIGADE:onafterArmyOnMission(From, Event, To, ArmyGroup, Mission)
|
||||
-- Debug info.
|
||||
self:T(self.lid..string.format("Group %s on %s mission %s", ArmyGroup:GetName(), Mission:GetType(), Mission:GetName()))
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
2190
Moose Development/Moose/Ops/Chief.lua
Normal file
2190
Moose Development/Moose/Ops/Chief.lua
Normal file
File diff suppressed because it is too large
Load Diff
1037
Moose Development/Moose/Ops/Cohort.lua
Normal file
1037
Moose Development/Moose/Ops/Cohort.lua
Normal file
File diff suppressed because it is too large
Load Diff
1489
Moose Development/Moose/Ops/Commander.lua
Normal file
1489
Moose Development/Moose/Ops/Commander.lua
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
2516
Moose Development/Moose/Ops/Legion.lua
Normal file
2516
Moose Development/Moose/Ops/Legion.lua
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
2205
Moose Development/Moose/Ops/OpsTransport.lua
Normal file
2205
Moose Development/Moose/Ops/OpsTransport.lua
Normal file
File diff suppressed because it is too large
Load Diff
1203
Moose Development/Moose/Ops/OpsZone.lua
Normal file
1203
Moose Development/Moose/Ops/OpsZone.lua
Normal file
File diff suppressed because it is too large
Load Diff
202
Moose Development/Moose/Ops/Platoon.lua
Normal file
202
Moose Development/Moose/Ops/Platoon.lua
Normal file
@@ -0,0 +1,202 @@
|
||||
--- **Ops** - Brigade Platoon.
|
||||
--
|
||||
-- **Main Features:**
|
||||
--
|
||||
-- * Set parameters like livery, skill valid for all platoon members.
|
||||
-- * Define modex and callsigns.
|
||||
-- * Define mission types, this platoon can perform (see Ops.Auftrag#AUFTRAG).
|
||||
-- * Pause/unpause platoon operations.
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- ### Author: **funkyfranky**
|
||||
-- @module Ops.Platoon
|
||||
-- @image OPS_Platoon.png
|
||||
|
||||
|
||||
--- PLATOON class.
|
||||
-- @type PLATOON
|
||||
-- @field #string ClassName Name of the class.
|
||||
-- @field #number verbose Verbosity level.
|
||||
-- @field Ops.OpsGroup#OPSGROUP.WeaponData weaponData Weapon data table with key=BitType.
|
||||
-- @extends Ops.Cohort#COHORT
|
||||
|
||||
--- *Some cool cohort quote* -- Known Author
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- # The PLATOON Concept
|
||||
--
|
||||
-- A PLATOON is essential part of an BRIGADE.
|
||||
--
|
||||
--
|
||||
--
|
||||
-- @field #PLATOON
|
||||
PLATOON = {
|
||||
ClassName = "PLATOON",
|
||||
verbose = 0,
|
||||
weaponData = {},
|
||||
}
|
||||
|
||||
--- PLATOON class version.
|
||||
-- @field #string version
|
||||
PLATOON.version="0.1.0"
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- TODO list
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- TODO: Add weapon data.
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- Constructor
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
--- Create a new PLATOON object and start the FSM.
|
||||
-- @param #PLATOON self
|
||||
-- @param #string TemplateGroupName Name of the template group.
|
||||
-- @param #number Ngroups Number of asset groups of this platoon. Default 3.
|
||||
-- @param #string PlatoonName Name of the platoon, e.g. "VFA-37".
|
||||
-- @return #PLATOON self
|
||||
function PLATOON:New(TemplateGroupName, Ngroups, PlatoonName)
|
||||
|
||||
-- Inherit everything from COHORT class.
|
||||
local self=BASE:Inherit(self, COHORT:New(TemplateGroupName, Ngroups, PlatoonName)) -- #PLATOON
|
||||
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- User functions
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- TODO: Platoon specific user functions.
|
||||
|
||||
--- Set brigade of this platoon.
|
||||
-- @param #PLATOON self
|
||||
-- @param Ops.Brigade#BRIGADE Brigade The brigade.
|
||||
-- @return #PLATOON self
|
||||
function PLATOON:SetBrigade(Brigade)
|
||||
self.legion=Brigade
|
||||
return self
|
||||
end
|
||||
|
||||
--- Get brigade of this platoon.
|
||||
-- @param #PLATOON self
|
||||
-- @return Ops.Brigade#BRIGADE The brigade.
|
||||
function PLATOON:GetBrigade()
|
||||
return self.legion
|
||||
end
|
||||
|
||||
--- Add a weapon range for ARTY auftrag.
|
||||
-- @param #PLATOON self
|
||||
-- @param #number RangeMin Minimum range in nautical miles. Default 0 NM.
|
||||
-- @param #number RangeMax Maximum range in nautical miles. Default 10 NM.
|
||||
-- @param #number BitType Bit mask of weapon type for which the given min/max ranges apply. Default is `ENUMS.WeaponFlag.Auto`, i.e. for all weapon types.
|
||||
-- @return #PLATOON self
|
||||
function PLATOON:AddWeaponRange(RangeMin, RangeMax, BitType)
|
||||
|
||||
RangeMin=UTILS.NMToMeters(RangeMin or 0)
|
||||
RangeMax=UTILS.NMToMeters(RangeMax or 10)
|
||||
|
||||
local weapon={} --Ops.OpsGroup#OPSGROUP.WeaponData
|
||||
|
||||
weapon.BitType=BitType or ENUMS.WeaponFlag.Auto
|
||||
weapon.RangeMax=RangeMax
|
||||
weapon.RangeMin=RangeMin
|
||||
|
||||
self.weaponData=self.weaponData or {}
|
||||
self.weaponData[tostring(weapon.BitType)]=weapon
|
||||
|
||||
-- Debug info.
|
||||
self:T(self.lid..string.format("Adding weapon data: Bit=%s, Rmin=%d m, Rmax=%d m", tostring(weapon.BitType), weapon.RangeMin, weapon.RangeMax))
|
||||
|
||||
if self.verbose>=2 then
|
||||
local text="Weapon data:"
|
||||
for _,_weapondata in pairs(self.weaponData) do
|
||||
local weapondata=_weapondata
|
||||
text=text..string.format("\n- Bit=%s, Rmin=%d m, Rmax=%d m", tostring(weapondata.BitType), weapondata.RangeMin, weapondata.RangeMax)
|
||||
end
|
||||
self:I(self.lid..text)
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- Start & Status
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
--- On after Start event. Starts the FLIGHTGROUP FSM and event handlers.
|
||||
-- @param #PLATOON self
|
||||
-- @param #string From From state.
|
||||
-- @param #string Event Event.
|
||||
-- @param #string To To state.
|
||||
function PLATOON:onafterStart(From, Event, To)
|
||||
|
||||
-- Short info.
|
||||
local text=string.format("Starting %s v%s %s", self.ClassName, self.version, self.name)
|
||||
self:I(self.lid..text)
|
||||
|
||||
-- Start the status monitoring.
|
||||
self:__Status(-1)
|
||||
end
|
||||
|
||||
--- On after "Status" event.
|
||||
-- @param #PLATOON self
|
||||
-- @param #string From From state.
|
||||
-- @param #string Event Event.
|
||||
-- @param #string To To state.
|
||||
function PLATOON:onafterStatus(From, Event, To)
|
||||
|
||||
if self.verbose>=1 then
|
||||
|
||||
-- FSM state.
|
||||
local fsmstate=self:GetState()
|
||||
|
||||
local callsign=self.callsignName and UTILS.GetCallsignName(self.callsignName) or "N/A"
|
||||
local modex=self.modex and self.modex or -1
|
||||
local skill=self.skill and tostring(self.skill) or "N/A"
|
||||
|
||||
local NassetsTot=#self.assets
|
||||
local NassetsInS=self:CountAssets(true)
|
||||
local NassetsQP=0 ; local NassetsP=0 ; local NassetsQ=0
|
||||
if self.legion then
|
||||
NassetsQP, NassetsP, NassetsQ=self.legion:CountAssetsOnMission(nil, self)
|
||||
end
|
||||
|
||||
-- Short info.
|
||||
local text=string.format("%s [Type=%s, Call=%s, Modex=%d, Skill=%s]: Assets Total=%d, Stock=%d, Mission=%d [Active=%d, Queue=%d]",
|
||||
fsmstate, self.aircrafttype, callsign, modex, skill, NassetsTot, NassetsInS, NassetsQP, NassetsP, NassetsQ)
|
||||
self:I(self.lid..text)
|
||||
|
||||
-- Weapon data info.
|
||||
if self.verbose>=3 and self.weaponData then
|
||||
local text="Weapon Data:"
|
||||
for bit,_weapondata in pairs(self.weaponData) do
|
||||
local weapondata=_weapondata --Ops.OpsGroup#OPSGROUP.WeaponData
|
||||
text=text..string.format("\n- Bit=%s: Rmin=%.1f km, Rmax=%.1f km", bit, weapondata.RangeMin/1000, weapondata.RangeMax/1000)
|
||||
end
|
||||
self:I(self.lid..text)
|
||||
end
|
||||
|
||||
-- Check if group has detected any units.
|
||||
self:_CheckAssetStatus()
|
||||
|
||||
end
|
||||
|
||||
if not self:IsStopped() then
|
||||
self:__Status(-60)
|
||||
end
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- Misc Functions
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- TODO: Misc functions.
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
@@ -36,7 +36,6 @@
|
||||
-- @field #number modexcounter Counter to incease modex number for assets.
|
||||
-- @field #string callsignName Callsign name.
|
||||
-- @field #number callsigncounter Counter to increase callsign names for new assets.
|
||||
-- @field Ops.AirWing#AIRWING airwing The AIRWING object the squadron belongs to.
|
||||
-- @field #number Ngroups Number of asset flight groups this squadron has.
|
||||
-- @field #number engageRange Mission range in meters.
|
||||
-- @field #string attribute Generalized attribute of the squadron template group.
|
||||
@@ -46,7 +45,8 @@
|
||||
-- @field #number radioFreq Radio frequency in MHz the squad uses.
|
||||
-- @field #number radioModu Radio modulation the squad uses.
|
||||
-- @field #number takeoffType Take of type.
|
||||
-- @extends Core.Fsm#FSM
|
||||
-- @field #table parkingIDs Parking IDs for this squadron.
|
||||
-- @extends Ops.Cohort#COHORT
|
||||
|
||||
--- *It is unbelievable what a squadron of twelve aircraft did to tip the balance.* -- Adolf Galland
|
||||
--
|
||||
@@ -64,37 +64,23 @@
|
||||
SQUADRON = {
|
||||
ClassName = "SQUADRON",
|
||||
verbose = 0,
|
||||
lid = nil,
|
||||
name = nil,
|
||||
templatename = nil,
|
||||
aircrafttype = nil,
|
||||
assets = {},
|
||||
missiontypes = {},
|
||||
repairtime = 0,
|
||||
maintenancetime= 0,
|
||||
livery = nil,
|
||||
skill = nil,
|
||||
modex = nil,
|
||||
modexcounter = 0,
|
||||
callsignName = nil,
|
||||
callsigncounter= 11,
|
||||
airwing = nil,
|
||||
Ngroups = nil,
|
||||
engageRange = nil,
|
||||
tankerSystem = nil,
|
||||
refuelSystem = nil,
|
||||
tacanChannel = {},
|
||||
}
|
||||
|
||||
--- SQUADRON class version.
|
||||
-- @field #string version
|
||||
SQUADRON.version="0.5.2"
|
||||
SQUADRON.version="0.8.0"
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- TODO list
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- TODO: Parking spots for squadrons?
|
||||
-- DONE: Parking spots for squadrons?
|
||||
-- DONE: Engage radius.
|
||||
-- DONE: Modex.
|
||||
-- DONE: Call signs.
|
||||
@@ -112,97 +98,20 @@ SQUADRON.version="0.5.2"
|
||||
function SQUADRON:New(TemplateGroupName, Ngroups, SquadronName)
|
||||
|
||||
-- Inherit everything from FSM class.
|
||||
local self=BASE:Inherit(self, FSM:New()) -- #SQUADRON
|
||||
local self=BASE:Inherit(self, COHORT:New(TemplateGroupName, Ngroups, SquadronName)) -- #SQUADRON
|
||||
|
||||
-- Name of the template group.
|
||||
self.templatename=TemplateGroupName
|
||||
|
||||
-- Squadron name.
|
||||
self.name=tostring(SquadronName or TemplateGroupName)
|
||||
|
||||
-- Set some string id for output to DCS.log file.
|
||||
self.lid=string.format("SQUADRON %s | ", self.name)
|
||||
|
||||
-- Template group.
|
||||
self.templategroup=GROUP:FindByName(self.templatename)
|
||||
|
||||
-- Check if template group exists.
|
||||
if not self.templategroup then
|
||||
self:E(self.lid..string.format("ERROR: Template group %s does not exist!", tostring(self.templatename)))
|
||||
return nil
|
||||
end
|
||||
|
||||
-- Defaults.
|
||||
self.Ngroups=Ngroups or 3
|
||||
self:SetMissionRange()
|
||||
self:SetSkill(AI.Skill.GOOD)
|
||||
--self:SetVerbosity(0)
|
||||
|
||||
-- Everyone can ORBIT.
|
||||
self:AddMissionCapability(AUFTRAG.Type.ORBIT)
|
||||
|
||||
-- Generalized attribute.
|
||||
self.attribute=self.templategroup:GetAttribute()
|
||||
|
||||
-- Aircraft type.
|
||||
self.aircrafttype=self.templategroup:GetTypeName()
|
||||
|
||||
|
||||
-- Refueling system.
|
||||
self.refuelSystem=select(2, self.templategroup:GetUnit(1):IsRefuelable())
|
||||
self.tankerSystem=select(2, self.templategroup:GetUnit(1):IsTanker())
|
||||
|
||||
|
||||
-- Start State.
|
||||
self:SetStartState("Stopped")
|
||||
|
||||
-- Add FSM transitions.
|
||||
-- From State --> Event --> To State
|
||||
self:AddTransition("Stopped", "Start", "OnDuty") -- Start FSM.
|
||||
self:AddTransition("*", "Status", "*") -- Status update.
|
||||
|
||||
self:AddTransition("OnDuty", "Pause", "Paused") -- Pause squadron.
|
||||
self:AddTransition("Paused", "Unpause", "OnDuty") -- Unpause squadron.
|
||||
|
||||
self:AddTransition("*", "Stop", "Stopped") -- Stop squadron.
|
||||
|
||||
|
||||
------------------------
|
||||
--- Pseudo Functions ---
|
||||
------------------------
|
||||
|
||||
--- Triggers the FSM event "Start". Starts the SQUADRON. Initializes parameters and starts event handlers.
|
||||
-- @function [parent=#SQUADRON] Start
|
||||
-- @param #SQUADRON self
|
||||
|
||||
--- Triggers the FSM event "Start" after a delay. Starts the SQUADRON. Initializes parameters and starts event handlers.
|
||||
-- @function [parent=#SQUADRON] __Start
|
||||
-- @param #SQUADRON self
|
||||
-- @param #number delay Delay in seconds.
|
||||
|
||||
--- Triggers the FSM event "Stop". Stops the SQUADRON and all its event handlers.
|
||||
-- @param #SQUADRON self
|
||||
|
||||
--- Triggers the FSM event "Stop" after a delay. Stops the SQUADRON and all its event handlers.
|
||||
-- @function [parent=#SQUADRON] __Stop
|
||||
-- @param #SQUADRON self
|
||||
-- @param #number delay Delay in seconds.
|
||||
|
||||
--- Triggers the FSM event "Status".
|
||||
-- @function [parent=#SQUADRON] Status
|
||||
-- @param #SQUADRON self
|
||||
|
||||
--- Triggers the FSM event "Status" after a delay.
|
||||
-- @function [parent=#SQUADRON] __Status
|
||||
-- @param #SQUADRON self
|
||||
-- @param #number delay Delay in seconds.
|
||||
|
||||
|
||||
-- Debug trace.
|
||||
if false then
|
||||
BASE:TraceOnOff(true)
|
||||
BASE:TraceClass(self.ClassName)
|
||||
BASE:TraceLevel(1)
|
||||
end
|
||||
-- See COHORT class
|
||||
|
||||
return self
|
||||
end
|
||||
@@ -211,68 +120,6 @@ end
|
||||
-- User functions
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
--- Set livery painted on all squadron aircraft.
|
||||
-- Note that the livery name in general is different from the name shown in the mission editor.
|
||||
--
|
||||
-- Valid names are the names of the **livery directories**. Check out the folder in your DCS installation for:
|
||||
--
|
||||
-- * Full modules: `DCS World OpenBeta\CoreMods\aircraft\<Aircraft Type>\Liveries\<Aircraft Type>\<Livery Name>`
|
||||
-- * AI units: `DCS World OpenBeta\Bazar\Liveries\<Aircraft Type>\<Livery Name>`
|
||||
--
|
||||
-- The folder name `<Livery Name>` is the string you want.
|
||||
--
|
||||
-- Or personal liveries you have installed somewhere in your saved games folder.
|
||||
--
|
||||
-- @param #SQUADRON self
|
||||
-- @param #string LiveryName Name of the livery.
|
||||
-- @return #SQUADRON self
|
||||
function SQUADRON:SetLivery(LiveryName)
|
||||
self.livery=LiveryName
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set skill level of all squadron team members.
|
||||
-- @param #SQUADRON self
|
||||
-- @param #string Skill Skill of all flights.
|
||||
-- @usage mysquadron:SetSkill(AI.Skill.EXCELLENT)
|
||||
-- @return #SQUADRON self
|
||||
function SQUADRON:SetSkill(Skill)
|
||||
self.skill=Skill
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set verbosity level.
|
||||
-- @param #SQUADRON self
|
||||
-- @param #number VerbosityLevel Level of output (higher=more). Default 0.
|
||||
-- @return #SQUADRON self
|
||||
function SQUADRON:SetVerbosity(VerbosityLevel)
|
||||
self.verbose=VerbosityLevel or 0
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set turnover and repair time. If an asset returns from a mission to the airwing, it will need some time until the asset is available for further missions.
|
||||
-- @param #SQUADRON self
|
||||
-- @param #number MaintenanceTime Time in minutes it takes until a flight is combat ready again. Default is 0 min.
|
||||
-- @param #number RepairTime Time in minutes it takes to repair a flight for each life point taken. Default is 0 min.
|
||||
-- @return #SQUADRON self
|
||||
function SQUADRON:SetTurnoverTime(MaintenanceTime, RepairTime)
|
||||
self.maintenancetime=MaintenanceTime and MaintenanceTime*60 or 0
|
||||
self.repairtime=RepairTime and RepairTime*60 or 0
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set radio frequency and modulation the squad uses.
|
||||
-- @param #SQUADRON self
|
||||
-- @param #number Frequency Radio frequency in MHz. Default 251 MHz.
|
||||
-- @param #number Modulation Radio modulation. Default 0=AM.
|
||||
-- @usage mysquadron:SetSkill(AI.Skill.EXCELLENT)
|
||||
-- @return #SQUADRON self
|
||||
function SQUADRON:SetRadio(Frequency, Modulation)
|
||||
self.radioFreq=Frequency or 251
|
||||
self.radioModu=Modulation or radio.modulation.AM
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set number of units in groups.
|
||||
-- @param #SQUADRON self
|
||||
-- @param #number nunits Number of units. Must be >=1 and <=4. Default 2.
|
||||
@@ -284,6 +131,18 @@ function SQUADRON:SetGrouping(nunits)
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set valid parking spot IDs. Assets of this squad are only allowed to be spawned at these parking spots. **Note** that the IDs are different from the ones displayed in the mission editor!
|
||||
-- @param #SQUADRON self
|
||||
-- @param #table ParkingIDs Table of parking ID numbers or a single `#number`.
|
||||
-- @return #SQUADRON self
|
||||
function SQUADRON:SetParkingIDs(ParkingIDs)
|
||||
if type(ParkingIDs)~="table" then
|
||||
ParkingIDs={ParkingIDs}
|
||||
end
|
||||
self.parkingIDs=ParkingIDs
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- Set takeoff type. All assets of this squadron will be spawned with cold (default) or hot engines.
|
||||
-- Spawning on runways is not supported.
|
||||
@@ -302,7 +161,7 @@ function SQUADRON:SetTakeoffType(TakeoffType)
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set takeoff type cold (default).
|
||||
--- Set takeoff type cold (default). All assets of this squadron will be spawned with engines off (cold).
|
||||
-- @param #SQUADRON self
|
||||
-- @return #SQUADRON self
|
||||
function SQUADRON:SetTakeoffCold()
|
||||
@@ -310,7 +169,7 @@ function SQUADRON:SetTakeoffCold()
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set takeoff type hot.
|
||||
--- Set takeoff type hot. All assets of this squadron will be spawned with engines on (hot).
|
||||
-- @param #SQUADRON self
|
||||
-- @return #SQUADRON self
|
||||
function SQUADRON:SetTakeoffHot()
|
||||
@@ -318,115 +177,6 @@ function SQUADRON:SetTakeoffHot()
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- Set mission types this squadron is able to perform.
|
||||
-- @param #SQUADRON self
|
||||
-- @param #table MissionTypes Table of mission types. Can also be passed as a #string if only one type.
|
||||
-- @param #number Performance Performance describing how good this mission can be performed. Higher is better. Default 50. Max 100.
|
||||
-- @return #SQUADRON self
|
||||
function SQUADRON:AddMissionCapability(MissionTypes, Performance)
|
||||
|
||||
-- Ensure Missiontypes is a table.
|
||||
if MissionTypes and type(MissionTypes)~="table" then
|
||||
MissionTypes={MissionTypes}
|
||||
end
|
||||
|
||||
-- Set table.
|
||||
self.missiontypes=self.missiontypes or {}
|
||||
|
||||
for _,missiontype in pairs(MissionTypes) do
|
||||
|
||||
-- Check not to add the same twice.
|
||||
if self:CheckMissionCapability(missiontype, self.missiontypes) then
|
||||
self:E(self.lid.."WARNING: Mission capability already present! No need to add it twice.")
|
||||
-- TODO: update performance.
|
||||
else
|
||||
|
||||
local capability={} --Ops.Auftrag#AUFTRAG.Capability
|
||||
capability.MissionType=missiontype
|
||||
capability.Performance=Performance or 50
|
||||
table.insert(self.missiontypes, capability)
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
-- Debug info.
|
||||
self:T2(self.missiontypes)
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Get mission types this squadron is able to perform.
|
||||
-- @param #SQUADRON self
|
||||
-- @return #table Table of mission types. Could be empty {}.
|
||||
function SQUADRON:GetMissionTypes()
|
||||
|
||||
local missiontypes={}
|
||||
|
||||
for _,Capability in pairs(self.missiontypes) do
|
||||
local capability=Capability --Ops.Auftrag#AUFTRAG.Capability
|
||||
table.insert(missiontypes, capability.MissionType)
|
||||
end
|
||||
|
||||
return missiontypes
|
||||
end
|
||||
|
||||
--- Get mission capabilities of this squadron.
|
||||
-- @param #SQUADRON self
|
||||
-- @return #table Table of mission capabilities.
|
||||
function SQUADRON:GetMissionCapabilities()
|
||||
return self.missiontypes
|
||||
end
|
||||
|
||||
--- Get mission performance for a given type of misson.
|
||||
-- @param #SQUADRON self
|
||||
-- @param #string MissionType Type of mission.
|
||||
-- @return #number Performance or -1.
|
||||
function SQUADRON:GetMissionPeformance(MissionType)
|
||||
|
||||
for _,Capability in pairs(self.missiontypes) do
|
||||
local capability=Capability --Ops.Auftrag#AUFTRAG.Capability
|
||||
if capability.MissionType==MissionType then
|
||||
return capability.Performance
|
||||
end
|
||||
end
|
||||
|
||||
return -1
|
||||
end
|
||||
|
||||
--- Set max mission range. Only missions in a circle of this radius around the squadron airbase are executed.
|
||||
-- @param #SQUADRON self
|
||||
-- @param #number Range Range in NM. Default 100 NM.
|
||||
-- @return #SQUADRON self
|
||||
function SQUADRON:SetMissionRange(Range)
|
||||
self.engageRange=UTILS.NMToMeters(Range or 100)
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set call sign.
|
||||
-- @param #SQUADRON self
|
||||
-- @param #number Callsign Callsign from CALLSIGN.Aircraft, e.g. "Chevy" for CALLSIGN.Aircraft.CHEVY.
|
||||
-- @param #number Index Callsign index, Chevy-**1**.
|
||||
-- @return #SQUADRON self
|
||||
function SQUADRON:SetCallsign(Callsign, Index)
|
||||
self.callsignName=Callsign
|
||||
self.callsignIndex=Index
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set modex.
|
||||
-- @param #SQUADRON self
|
||||
-- @param #number Modex A number like 100.
|
||||
-- @param #string Prefix A prefix string, which is put before the `Modex` number.
|
||||
-- @param #string Suffix A suffix string, which is put after the `Modex` number.
|
||||
-- @return #SQUADRON self
|
||||
function SQUADRON:SetModex(Modex, Prefix, Suffix)
|
||||
self.modex=Modex
|
||||
self.modexPrefix=Prefix
|
||||
self.modexSuffix=Suffix
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set low fuel threshold.
|
||||
-- @param #SQUADRON self
|
||||
-- @param #number LowFuel Low fuel threshold in percent. Default 25.
|
||||
@@ -454,201 +204,17 @@ end
|
||||
-- @param Ops.AirWing#AIRWING Airwing The airwing.
|
||||
-- @return #SQUADRON self
|
||||
function SQUADRON:SetAirwing(Airwing)
|
||||
self.airwing=Airwing
|
||||
self.legion=Airwing
|
||||
return self
|
||||
end
|
||||
|
||||
--- Add airwing asset to squadron.
|
||||
--- Get airwing.
|
||||
-- @param #SQUADRON self
|
||||
-- @param Ops.AirWing#AIRWING.SquadronAsset Asset The airwing asset.
|
||||
-- @return #SQUADRON self
|
||||
function SQUADRON:AddAsset(Asset)
|
||||
self:T(self.lid..string.format("Adding asset %s of type %s", Asset.spawngroupname, Asset.unittype))
|
||||
Asset.squadname=self.name
|
||||
table.insert(self.assets, Asset)
|
||||
return self
|
||||
-- @return Ops.AirWing#AIRWING The airwing.
|
||||
function SQUADRON:GetAirwing(Airwing)
|
||||
return self.legion
|
||||
end
|
||||
|
||||
--- Remove airwing asset from squadron.
|
||||
-- @param #SQUADRON self
|
||||
-- @param Ops.AirWing#AIRWING.SquadronAsset Asset The airwing asset.
|
||||
-- @return #SQUADRON self
|
||||
function SQUADRON:DelAsset(Asset)
|
||||
for i,_asset in pairs(self.assets) do
|
||||
local asset=_asset --Ops.AirWing#AIRWING.SquadronAsset
|
||||
if Asset.uid==asset.uid then
|
||||
self:T2(self.lid..string.format("Removing asset %s", asset.spawngroupname))
|
||||
table.remove(self.assets, i)
|
||||
break
|
||||
end
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
--- Remove airwing asset group from squadron.
|
||||
-- @param #SQUADRON self
|
||||
-- @param #string GroupName Name of the asset group.
|
||||
-- @return #SQUADRON self
|
||||
function SQUADRON:DelGroup(GroupName)
|
||||
for i,_asset in pairs(self.assets) do
|
||||
local asset=_asset --Ops.AirWing#AIRWING.SquadronAsset
|
||||
if GroupName==asset.spawngroupname then
|
||||
self:T2(self.lid..string.format("Removing asset %s", asset.spawngroupname))
|
||||
table.remove(self.assets, i)
|
||||
break
|
||||
end
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
--- Get name of the squadron
|
||||
-- @param #SQUADRON self
|
||||
-- @return #string Name of the squadron.
|
||||
function SQUADRON:GetName()
|
||||
return self.name
|
||||
end
|
||||
|
||||
--- Get radio frequency and modulation.
|
||||
-- @param #SQUADRON self
|
||||
-- @return #number Radio frequency in MHz.
|
||||
-- @return #number Radio Modulation (0=AM, 1=FM).
|
||||
function SQUADRON:GetRadio()
|
||||
return self.radioFreq, self.radioModu
|
||||
end
|
||||
|
||||
--- Create a callsign for the asset.
|
||||
-- @param #SQUADRON self
|
||||
-- @param Ops.AirWing#AIRWING.SquadronAsset Asset The airwing asset.
|
||||
-- @return #SQUADRON self
|
||||
function SQUADRON:GetCallsign(Asset)
|
||||
|
||||
if self.callsignName then
|
||||
|
||||
Asset.callsign={}
|
||||
|
||||
for i=1,Asset.nunits do
|
||||
|
||||
local callsign={}
|
||||
|
||||
callsign[1]=self.callsignName
|
||||
callsign[2]=math.floor(self.callsigncounter / 10)
|
||||
callsign[3]=self.callsigncounter % 10
|
||||
if callsign[3]==0 then
|
||||
callsign[3]=1
|
||||
self.callsigncounter=self.callsigncounter+2
|
||||
else
|
||||
self.callsigncounter=self.callsigncounter+1
|
||||
end
|
||||
|
||||
Asset.callsign[i]=callsign
|
||||
|
||||
self:T3({callsign=callsign})
|
||||
|
||||
--TODO: there is also a table entry .name, which is a string.
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--- Create a modex for the asset.
|
||||
-- @param #SQUADRON self
|
||||
-- @param Ops.AirWing#AIRWING.SquadronAsset Asset The airwing asset.
|
||||
-- @return #SQUADRON self
|
||||
function SQUADRON:GetModex(Asset)
|
||||
|
||||
if self.modex then
|
||||
|
||||
Asset.modex={}
|
||||
|
||||
for i=1,Asset.nunits do
|
||||
|
||||
Asset.modex[i]=string.format("%03d", self.modex+self.modexcounter)
|
||||
|
||||
self.modexcounter=self.modexcounter+1
|
||||
|
||||
self:T3({modex=Asset.modex[i]})
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
--- Add TACAN channels to the squadron. Note that channels can only range from 1 to 126.
|
||||
-- @param #SQUADRON self
|
||||
-- @param #number ChannelMin Channel.
|
||||
-- @param #number ChannelMax Channel.
|
||||
-- @return #SQUADRON self
|
||||
-- @usage mysquad:AddTacanChannel(64,69) -- adds channels 64, 65, 66, 67, 68, 69
|
||||
function SQUADRON:AddTacanChannel(ChannelMin, ChannelMax)
|
||||
|
||||
ChannelMax=ChannelMax or ChannelMin
|
||||
|
||||
if ChannelMin>126 then
|
||||
self:E(self.lid.."ERROR: TACAN Channel must be <= 126! Will not add to available channels")
|
||||
return self
|
||||
end
|
||||
if ChannelMax>126 then
|
||||
self:E(self.lid.."WARNING: TACAN Channel must be <= 126! Adjusting ChannelMax to 126")
|
||||
ChannelMax=126
|
||||
end
|
||||
|
||||
for i=ChannelMin,ChannelMax do
|
||||
self.tacanChannel[i]=true
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Get an unused TACAN channel.
|
||||
-- @param #SQUADRON self
|
||||
-- @return #number TACAN channel or *nil* if no channel is free.
|
||||
function SQUADRON:FetchTacan()
|
||||
|
||||
for channel,free in pairs(self.tacanChannel) do
|
||||
if free then
|
||||
self:T(self.lid..string.format("Checking out Tacan channel %d", channel))
|
||||
self.tacanChannel[channel]=false
|
||||
return channel
|
||||
end
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
--- "Return" a used TACAN channel.
|
||||
-- @param #SQUADRON self
|
||||
-- @param #number channel The channel that is available again.
|
||||
function SQUADRON:ReturnTacan(channel)
|
||||
self:T(self.lid..string.format("Returning Tacan channel %d", channel))
|
||||
self.tacanChannel[channel]=true
|
||||
end
|
||||
|
||||
--- Check if squadron is "OnDuty".
|
||||
-- @param #SQUADRON self
|
||||
-- @return #boolean If true, squdron is in state "OnDuty".
|
||||
function SQUADRON:IsOnDuty()
|
||||
return self:Is("OnDuty")
|
||||
end
|
||||
|
||||
--- Check if squadron is "Stopped".
|
||||
-- @param #SQUADRON self
|
||||
-- @return #boolean If true, squdron is in state "Stopped".
|
||||
function SQUADRON:IsStopped()
|
||||
return self:Is("Stopped")
|
||||
end
|
||||
|
||||
--- Check if squadron is "Paused".
|
||||
-- @param #SQUADRON self
|
||||
-- @return #boolean If true, squdron is in state "Paused".
|
||||
function SQUADRON:IsPaused()
|
||||
return self:Is("Paused")
|
||||
end
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- Start & Status
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
@@ -685,10 +251,10 @@ function SQUADRON:onafterStatus(From, Event, To)
|
||||
local skill=self.skill and tostring(self.skill) or "N/A"
|
||||
|
||||
local NassetsTot=#self.assets
|
||||
local NassetsInS=self:CountAssetsInStock()
|
||||
local NassetsInS=self:CountAssets(true)
|
||||
local NassetsQP=0 ; local NassetsP=0 ; local NassetsQ=0
|
||||
if self.airwing then
|
||||
NassetsQP, NassetsP, NassetsQ=self.airwing:CountAssetsOnMission(nil, self)
|
||||
if self.legion then
|
||||
NassetsQP, NassetsP, NassetsQ=self.legion:CountAssetsOnMission(nil, self)
|
||||
end
|
||||
|
||||
-- Short info.
|
||||
@@ -706,369 +272,10 @@ function SQUADRON:onafterStatus(From, Event, To)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--- Check asset status.
|
||||
-- @param #SQUADRON self
|
||||
function SQUADRON:_CheckAssetStatus()
|
||||
|
||||
if self.verbose>=2 and #self.assets>0 then
|
||||
|
||||
local text=""
|
||||
for j,_asset in pairs(self.assets) do
|
||||
local asset=_asset --Ops.AirWing#AIRWING.SquadronAsset
|
||||
|
||||
-- Text.
|
||||
text=text..string.format("\n[%d] %s (%s*%d): ", j, asset.spawngroupname, asset.unittype, asset.nunits)
|
||||
|
||||
if asset.spawned then
|
||||
|
||||
---
|
||||
-- Spawned
|
||||
---
|
||||
|
||||
-- Mission info.
|
||||
local mission=self.airwing and self.airwing:GetAssetCurrentMission(asset) or false
|
||||
if mission then
|
||||
local distance=asset.flightgroup and UTILS.MetersToNM(mission:GetTargetDistance(asset.flightgroup.group:GetCoordinate())) or 0
|
||||
text=text..string.format("Mission %s - %s: Status=%s, Dist=%.1f NM", mission.name, mission.type, mission.status, distance)
|
||||
else
|
||||
text=text.."Mission None"
|
||||
end
|
||||
|
||||
-- Flight status.
|
||||
text=text..", Flight: "
|
||||
if asset.flightgroup and asset.flightgroup:IsAlive() then
|
||||
local status=asset.flightgroup:GetState()
|
||||
local fuelmin=asset.flightgroup:GetFuelMin()
|
||||
local fuellow=asset.flightgroup:IsFuelLow()
|
||||
local fuelcri=asset.flightgroup:IsFuelCritical()
|
||||
|
||||
text=text..string.format("%s Fuel=%d", status, fuelmin)
|
||||
if fuelcri then
|
||||
text=text.." (Critical!)"
|
||||
elseif fuellow then
|
||||
text=text.." (Low)"
|
||||
end
|
||||
|
||||
local lifept, lifept0=asset.flightgroup:GetLifePoints()
|
||||
text=text..string.format(", Life=%d/%d", lifept, lifept0)
|
||||
|
||||
local ammo=asset.flightgroup:GetAmmoTot()
|
||||
text=text..string.format(", Ammo=%d [G=%d, R=%d, B=%d, M=%d]", ammo.Total,ammo.Guns, ammo.Rockets, ammo.Bombs, ammo.Missiles)
|
||||
else
|
||||
text=text.."N/A"
|
||||
end
|
||||
|
||||
-- Payload info.
|
||||
local payload=asset.payload and table.concat(self.airwing:GetPayloadMissionTypes(asset.payload), ", ") or "None"
|
||||
text=text..", Payload={"..payload.."}"
|
||||
|
||||
else
|
||||
|
||||
---
|
||||
-- In Stock
|
||||
---
|
||||
|
||||
text=text..string.format("In Stock")
|
||||
|
||||
if self:IsRepaired(asset) then
|
||||
text=text..", Combat Ready"
|
||||
else
|
||||
|
||||
text=text..string.format(", Repaired in %d sec", self:GetRepairTime(asset))
|
||||
|
||||
if asset.damage then
|
||||
text=text..string.format(" (Damage=%.1f)", asset.damage)
|
||||
end
|
||||
end
|
||||
|
||||
if asset.Treturned then
|
||||
local T=timer.getAbsTime()-asset.Treturned
|
||||
text=text..string.format(", Returned for %d sec", T)
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
self:I(self.lid..text)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--- On after "Stop" event.
|
||||
-- @param #SQUADRON self
|
||||
-- @param #string From From state.
|
||||
-- @param #string Event Event.
|
||||
-- @param #string To To state.
|
||||
function SQUADRON:onafterStop(From, Event, To)
|
||||
|
||||
self:I(self.lid.."STOPPING Squadron!")
|
||||
|
||||
-- Remove all assets.
|
||||
for i=#self.assets,1,-1 do
|
||||
local asset=self.assets[i]
|
||||
self:DelAsset(asset)
|
||||
end
|
||||
|
||||
self.CallScheduler:Clear()
|
||||
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- Misc Functions
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
--- Check if there is a squadron that can execute a given mission.
|
||||
-- We check the mission type, the refuelling system, engagement range
|
||||
-- @param #SQUADRON self
|
||||
-- @param Ops.Auftrag#AUFTRAG Mission The mission.
|
||||
-- @return #boolean If true, Squadron can do that type of mission.
|
||||
function SQUADRON:CanMission(Mission)
|
||||
|
||||
local cando=true
|
||||
|
||||
-- On duty?=
|
||||
if not self:IsOnDuty() then
|
||||
self:T(self.lid..string.format("Squad in not OnDuty but in state %s. Cannot do mission %s with target %s", self:GetState(), Mission.name, Mission:GetTargetName()))
|
||||
return false
|
||||
end
|
||||
|
||||
-- Check mission type. WARNING: This assumes that all assets of the squad can do the same mission types!
|
||||
if not self:CheckMissionType(Mission.type, self:GetMissionTypes()) then
|
||||
self:T(self.lid..string.format("INFO: Squad cannot do mission type %s (%s, %s)", Mission.type, Mission.name, Mission:GetTargetName()))
|
||||
return false
|
||||
end
|
||||
|
||||
-- Check that tanker mission
|
||||
if Mission.type==AUFTRAG.Type.TANKER then
|
||||
|
||||
if Mission.refuelSystem and Mission.refuelSystem==self.tankerSystem then
|
||||
-- Correct refueling system.
|
||||
else
|
||||
self:T(self.lid..string.format("INFO: Wrong refueling system requested=%s != %s=available", tostring(Mission.refuelSystem), tostring(self.tankerSystem)))
|
||||
return false
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-- Distance to target.
|
||||
local TargetDistance=Mission:GetTargetDistance(self.airwing:GetCoordinate())
|
||||
|
||||
-- Max engage range.
|
||||
local engagerange=Mission.engageRange and math.max(self.engageRange, Mission.engageRange) or self.engageRange
|
||||
|
||||
-- Set range is valid. Mission engage distance can overrule the squad engage range.
|
||||
if TargetDistance>engagerange then
|
||||
self:I(self.lid..string.format("INFO: Squad is not in range. Target dist=%d > %d NM max mission Range", UTILS.MetersToNM(TargetDistance), UTILS.MetersToNM(engagerange)))
|
||||
return false
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
--- Count assets in airwing (warehous) stock.
|
||||
-- @param #SQUADRON self
|
||||
-- @return #number Assets not spawned.
|
||||
function SQUADRON:CountAssetsInStock()
|
||||
|
||||
local N=0
|
||||
for _,_asset in pairs(self.assets) do
|
||||
local asset=_asset --Ops.AirWing#AIRWING.SquadronAsset
|
||||
if asset.spawned then
|
||||
|
||||
else
|
||||
N=N+1
|
||||
end
|
||||
end
|
||||
|
||||
return N
|
||||
end
|
||||
|
||||
--- Get assets for a mission.
|
||||
-- @param #SQUADRON self
|
||||
-- @param Ops.Auftrag#AUFTRAG Mission The mission.
|
||||
-- @param #number Nplayloads Number of payloads available.
|
||||
-- @return #table Assets that can do the required mission.
|
||||
function SQUADRON:RecruitAssets(Mission, Npayloads)
|
||||
|
||||
-- Number of payloads available.
|
||||
Npayloads=Npayloads or self.airwing:CountPayloadsInStock(Mission.type, self.aircrafttype, Mission.payloads)
|
||||
|
||||
local assets={}
|
||||
|
||||
-- Loop over assets.
|
||||
for _,_asset in pairs(self.assets) do
|
||||
local asset=_asset --Ops.AirWing#AIRWING.SquadronAsset
|
||||
|
||||
|
||||
-- Check if asset is currently on a mission (STARTED or QUEUED).
|
||||
if self.airwing:IsAssetOnMission(asset) then
|
||||
|
||||
---
|
||||
-- Asset is already on a mission.
|
||||
---
|
||||
|
||||
-- Check if this asset is currently on a GCICAP mission (STARTED or EXECUTING).
|
||||
if self.airwing:IsAssetOnMission(asset, AUFTRAG.Type.GCICAP) and Mission.type==AUFTRAG.Type.INTERCEPT then
|
||||
|
||||
-- Check if the payload of this asset is compatible with the mission.
|
||||
-- Note: we do not check the payload as an asset that is on a GCICAP mission should be able to do an INTERCEPT as well!
|
||||
self:I(self.lid.."Adding asset on GCICAP mission for an INTERCEPT mission")
|
||||
table.insert(assets, asset)
|
||||
|
||||
end
|
||||
|
||||
else
|
||||
|
||||
---
|
||||
-- Asset as NO current mission
|
||||
---
|
||||
|
||||
if asset.spawned then
|
||||
|
||||
---
|
||||
-- Asset is already SPAWNED (could be uncontrolled on the airfield or inbound after another mission)
|
||||
---
|
||||
|
||||
local flightgroup=asset.flightgroup
|
||||
|
||||
-- Firstly, check if it has the right payload.
|
||||
if self:CheckMissionCapability(Mission.type, asset.payload.capabilities) and flightgroup and flightgroup:IsAlive() then
|
||||
|
||||
-- Assume we are ready and check if any condition tells us we are not.
|
||||
local combatready=true
|
||||
|
||||
if Mission.type==AUFTRAG.Type.INTERCEPT then
|
||||
combatready=flightgroup:CanAirToAir()
|
||||
else
|
||||
local excludeguns=Mission.type==AUFTRAG.Type.BOMBING or Mission.type==AUFTRAG.Type.BOMBRUNWAY or Mission.type==AUFTRAG.Type.BOMBCARPET or Mission.type==AUFTRAG.Type.SEAD or Mission.type==AUFTRAG.Type.ANTISHIP
|
||||
combatready=flightgroup:CanAirToGround(excludeguns)
|
||||
end
|
||||
|
||||
-- No more attacks if fuel is already low. Safety first!
|
||||
if flightgroup:IsFuelLow() then
|
||||
combatready=false
|
||||
end
|
||||
|
||||
-- Check if in a state where we really do not want to fight any more.
|
||||
if flightgroup:IsHolding() or flightgroup:IsLanding() or flightgroup:IsLanded() or flightgroup:IsArrived() or flightgroup:IsDead() or flightgroup:IsStopped() then
|
||||
combatready=false
|
||||
end
|
||||
|
||||
-- This asset is "combatready".
|
||||
if combatready then
|
||||
self:I(self.lid.."Adding SPAWNED asset to ANOTHER mission as it is COMBATREADY")
|
||||
table.insert(assets, asset)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
else
|
||||
|
||||
---
|
||||
-- Asset is still in STOCK
|
||||
---
|
||||
|
||||
-- Check that asset is not already requested for another mission.
|
||||
if Npayloads>0 and self:IsRepaired(asset) and (not asset.requested) then
|
||||
|
||||
-- Add this asset to the selection.
|
||||
table.insert(assets, asset)
|
||||
|
||||
-- Reduce number of payloads so we only return the number of assets that could do the job.
|
||||
Npayloads=Npayloads-1
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end -- loop over assets
|
||||
|
||||
return assets
|
||||
end
|
||||
|
||||
|
||||
--- Get the time an asset needs to be repaired.
|
||||
-- @param #SQUADRON self
|
||||
-- @param Ops.AirWing#AIRWING.SquadronAsset Asset The asset.
|
||||
-- @return #number Time in seconds until asset is repaired.
|
||||
function SQUADRON:GetRepairTime(Asset)
|
||||
|
||||
if Asset.Treturned then
|
||||
|
||||
local t=self.maintenancetime
|
||||
t=t+Asset.damage*self.repairtime
|
||||
|
||||
-- Seconds after returned.
|
||||
local dt=timer.getAbsTime()-Asset.Treturned
|
||||
|
||||
local T=t-dt
|
||||
|
||||
return T
|
||||
else
|
||||
return 0
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--- Checks if a mission type is contained in a table of possible types.
|
||||
-- @param #SQUADRON self
|
||||
-- @param Ops.AirWing#AIRWING.SquadronAsset Asset The asset.
|
||||
-- @return #boolean If true, the requested mission type is part of the possible mission types.
|
||||
function SQUADRON:IsRepaired(Asset)
|
||||
|
||||
if Asset.Treturned then
|
||||
local Tnow=timer.getAbsTime()
|
||||
local Trepaired=Asset.Treturned+self.maintenancetime
|
||||
if Tnow>=Trepaired then
|
||||
return true
|
||||
else
|
||||
return false
|
||||
end
|
||||
|
||||
else
|
||||
return true
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
--- Checks if a mission type is contained in a table of possible types.
|
||||
-- @param #SQUADRON self
|
||||
-- @param #string MissionType The requested mission type.
|
||||
-- @param #table PossibleTypes A table with possible mission types.
|
||||
-- @return #boolean If true, the requested mission type is part of the possible mission types.
|
||||
function SQUADRON:CheckMissionType(MissionType, PossibleTypes)
|
||||
|
||||
if type(PossibleTypes)=="string" then
|
||||
PossibleTypes={PossibleTypes}
|
||||
end
|
||||
|
||||
for _,canmission in pairs(PossibleTypes) do
|
||||
if canmission==MissionType then
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
--- Check if a mission type is contained in a list of possible capabilities.
|
||||
-- @param #SQUADRON self
|
||||
-- @param #string MissionType The requested mission type.
|
||||
-- @param #table Capabilities A table with possible capabilities.
|
||||
-- @return #boolean If true, the requested mission type is part of the possible mission types.
|
||||
function SQUADRON:CheckMissionCapability(MissionType, Capabilities)
|
||||
|
||||
for _,cap in pairs(Capabilities) do
|
||||
local capability=cap --Ops.Auftrag#AUFTRAG.Capability
|
||||
if capability.MissionType==MissionType then
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
-- @type TARGET
|
||||
-- @field #string ClassName Name of the class.
|
||||
-- @field #number verbose Verbosity level.
|
||||
-- @field #number uid Unique ID of the target.
|
||||
-- @field #string lid Class id string for output to DCS log file.
|
||||
-- @field #table targets Table of target objects.
|
||||
-- @field #number targetcounter Running number to generate target object IDs.
|
||||
@@ -30,14 +31,17 @@
|
||||
-- @field #number Ndead Number of target elements/units that are dead (destroyed or despawned).
|
||||
-- @field #table elements Table of target elements/units.
|
||||
-- @field #table casualties Table of dead element names.
|
||||
-- @field #number prio Priority.
|
||||
-- @field #number importance Importance.
|
||||
-- @field Ops.Auftrag#AUFTRAG mission Mission attached to this target.
|
||||
-- @field Ops.Intelligence#INTEL.Contact contact Contact attached to this target.
|
||||
-- @field #boolean isDestroyed If true, target objects were destroyed.
|
||||
-- @extends Core.Fsm#FSM
|
||||
|
||||
--- **It is far more important to be able to hit the target than it is to haggle over who makes a weapon or who pulls a trigger** -- Dwight D. Eisenhower
|
||||
--- **It is far more important to be able to hit the target than it is to haggle over who makes a weapon or who pulls a trigger** -- Dwight D Eisenhower
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- # The TARGET Concept
|
||||
--
|
||||
-- Define a target of your mission and monitor its status. Events are triggered when the target is damaged or destroyed.
|
||||
@@ -128,13 +132,15 @@ _TARGETID=0
|
||||
|
||||
--- TARGET class version.
|
||||
-- @field #string version
|
||||
TARGET.version="0.3.1"
|
||||
TARGET.version="0.5.2"
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- TODO list
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- TODO: A lot.
|
||||
-- TODO: Had cases where target life was 0 but target was not dead. Need to figure out why!
|
||||
-- TODO: Add pseudo functions.
|
||||
-- DONE: Initial object can be nil.
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- Constructor
|
||||
@@ -151,26 +157,23 @@ function TARGET:New(TargetObject)
|
||||
|
||||
-- Increase counter.
|
||||
_TARGETID=_TARGETID+1
|
||||
|
||||
-- Set UID.
|
||||
self.uid=_TARGETID
|
||||
|
||||
if TargetObject then
|
||||
|
||||
-- Add object.
|
||||
self:AddObject(TargetObject)
|
||||
|
||||
-- Get first target.
|
||||
local Target=self.targets[1] --#TARGET.Object
|
||||
|
||||
if not Target then
|
||||
self:E("ERROR: No valid TARGET!")
|
||||
return nil
|
||||
end
|
||||
-- Add object.
|
||||
self:AddObject(TargetObject)
|
||||
|
||||
-- Target Name.
|
||||
self.name=self:GetTargetName(Target)
|
||||
end
|
||||
|
||||
-- Target category.
|
||||
self.category=self:GetTargetCategory(Target)
|
||||
-- Defaults.
|
||||
self:SetPriority()
|
||||
self:SetImportance()
|
||||
|
||||
-- Log ID.
|
||||
self.lid=string.format("TARGET #%03d [%s] | ", _TARGETID, tostring(self.category))
|
||||
self.lid=string.format("TARGET #%03d | ", _TARGETID)
|
||||
|
||||
-- Start state.
|
||||
self:SetStartState("Stopped")
|
||||
@@ -187,7 +190,7 @@ function TARGET:New(TargetObject)
|
||||
|
||||
self:AddTransition("*", "Damaged", "*") -- Target was damaged.
|
||||
self:AddTransition("*", "Destroyed", "Dead") -- Target was completely destroyed.
|
||||
self:AddTransition("*", "Dead", "Dead") -- Target was completely destroyed.
|
||||
self:AddTransition("*", "Dead", "Dead") -- Target is dead. Could be destroyed or despawned.
|
||||
|
||||
------------------------
|
||||
--- Pseudo Functions ---
|
||||
@@ -220,7 +223,6 @@ function TARGET:New(TargetObject)
|
||||
-- @param #number delay Delay in seconds.
|
||||
|
||||
|
||||
|
||||
-- Start.
|
||||
self:__Start(-1)
|
||||
|
||||
@@ -231,12 +233,24 @@ end
|
||||
-- User functions
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
--- Create target data from a given object.
|
||||
--- Create target data from a given object. Valid objects are:
|
||||
--
|
||||
-- * GROUP
|
||||
-- * UNIT
|
||||
-- * STATIC
|
||||
-- * AIRBASE
|
||||
-- * COORDINATE
|
||||
-- * ZONE
|
||||
-- * SET_GROUP
|
||||
-- * SET_UNIT
|
||||
-- * SET_STATIC
|
||||
-- * SET_OPSGROUP
|
||||
--
|
||||
-- @param #TARGET self
|
||||
-- @param Wrapper.Positionable#POSITIONABLE Object The target GROUP, UNIT, STATIC, AIRBASE or COORDINATE.
|
||||
function TARGET:AddObject(Object)
|
||||
|
||||
if Object:IsInstanceOf("SET_GROUP") or Object:IsInstanceOf("SET_UNIT") then
|
||||
if Object:IsInstanceOf("SET_GROUP") or Object:IsInstanceOf("SET_UNIT") or Object:IsInstanceOf("SET_STATIC") or Object:IsInstanceOf("SET_OPSGROUP") then
|
||||
|
||||
---
|
||||
-- Sets
|
||||
@@ -247,31 +261,81 @@ function TARGET:AddObject(Object)
|
||||
for _,object in pairs(set.Set) do
|
||||
self:AddObject(object)
|
||||
end
|
||||
|
||||
|
||||
elseif Object:IsInstanceOf("SET_ZONE") then
|
||||
|
||||
local set=Object --Core.Set#SET_ZONE
|
||||
|
||||
set:SortByName()
|
||||
|
||||
for index,ZoneName in pairs(set.Index) do
|
||||
local zone=set.Set[ZoneName] --Core.Zone#ZONE
|
||||
self:_AddObject(zone)
|
||||
end
|
||||
|
||||
else
|
||||
|
||||
---
|
||||
-- Groups, Units, Statics, Airbases, Coordinates
|
||||
---
|
||||
|
||||
self:_AddObject(Object)
|
||||
if Object:IsInstanceOf("OPSGROUP") then
|
||||
self:_AddObject(Object:GetGroup()) -- We add the MOOSE GROUP object not the OPSGROUP object.
|
||||
else
|
||||
self:_AddObject(Object)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--- Set priority of the target.
|
||||
-- @param #TARGET self
|
||||
-- @param #number Priority Priority of the target. Default 50.
|
||||
-- @return #TARGET self
|
||||
function TARGET:SetPriority(Priority)
|
||||
self.prio=Priority or 50
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set importance of the target.
|
||||
-- @param #TARGET self
|
||||
-- @param #number Importance Importance of the target. Default `nil`.
|
||||
-- @return #TARGET self
|
||||
function TARGET:SetImportance(Importance)
|
||||
self.importance=Importance
|
||||
return self
|
||||
end
|
||||
|
||||
--- Check if TARGET is alive.
|
||||
-- @param #TARGET self
|
||||
-- @return #boolean If true, target is alive.
|
||||
function TARGET:IsAlive()
|
||||
return self:Is("Alive")
|
||||
|
||||
for _,_target in pairs(self.targets) do
|
||||
local target=_target --Ops.Target#TARGET.Object
|
||||
if target.Status==TARGET.ObjectStatus.ALIVE then
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
--- Check if TARGET is destroyed.
|
||||
-- @param #TARGET self
|
||||
-- @return #boolean If true, target is destroyed.
|
||||
function TARGET:IsDestroyed()
|
||||
return self.isDestroyed
|
||||
end
|
||||
|
||||
|
||||
--- Check if TARGET is dead.
|
||||
-- @param #TARGET self
|
||||
-- @return #boolean If true, target is dead.
|
||||
function TARGET:IsDead()
|
||||
return self:Is("Dead")
|
||||
local is=self:Is("Dead")
|
||||
return is
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
@@ -322,6 +386,11 @@ function TARGET:onafterStatus(From, Event, To)
|
||||
damaged=true
|
||||
end
|
||||
|
||||
if life==0 then
|
||||
self:I(self.lid..string.format("FF life is zero but no object dead event fired ==> object dead now for traget object %s!", tostring(target.Name)))
|
||||
self:ObjectDead(target)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-- Target was damaged.
|
||||
@@ -422,6 +491,8 @@ function TARGET:onafterObjectDead(From, Event, To, Target)
|
||||
|
||||
if self.Ndestroyed==self.Ntargets0 then
|
||||
|
||||
self.isDestroyed=true
|
||||
|
||||
self:Destroyed()
|
||||
|
||||
else
|
||||
@@ -691,6 +762,13 @@ function TARGET:_AddObject(Object)
|
||||
target.Object=Object
|
||||
|
||||
table.insert(self.targets, target)
|
||||
|
||||
if self.name==nil then
|
||||
self.name=self:GetTargetName(target)
|
||||
end
|
||||
if self.category==nil then
|
||||
self.category=self:GetTargetCategory(target)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -805,10 +883,25 @@ function TARGET:GetLife()
|
||||
return N
|
||||
end
|
||||
|
||||
--- Get target 2D position vector.
|
||||
-- @param #TARGET self
|
||||
-- @param #TARGET.Object Target Target object.
|
||||
-- @return DCS#Vec2 Vector with x,y components.
|
||||
function TARGET:GetTargetVec2(Target)
|
||||
|
||||
local vec3=self:GetTargetVec3(Target)
|
||||
|
||||
if vec3 then
|
||||
return {x=vec3.x, y=vec3.z}
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
--- Get target 3D position vector.
|
||||
-- @param #TARGET self
|
||||
-- @param #TARGET.Object Target Target object.
|
||||
-- @return DCS#Vec3 Vector with x,y,z components
|
||||
-- @return DCS#Vec3 Vector with x,y,z components.
|
||||
function TARGET:GetTargetVec3(Target)
|
||||
|
||||
if Target.Type==TARGET.ObjectType.GROUP then
|
||||
@@ -955,6 +1048,12 @@ function TARGET:GetTargetName(Target)
|
||||
local coord=Target.Object --Core.Point#COORDINATE
|
||||
|
||||
return coord:ToStringMGRS()
|
||||
|
||||
elseif Target.Type==TARGET.ObjectType.ZONE then
|
||||
|
||||
local Zone=Target.Object --Core.Zone#ZONE
|
||||
|
||||
return Zone:GetName()
|
||||
|
||||
end
|
||||
|
||||
@@ -965,7 +1064,48 @@ end
|
||||
-- @param #TARGET self
|
||||
-- @return #string Name of the target usually the first object.
|
||||
function TARGET:GetName()
|
||||
return self.name
|
||||
local name=self.name or "Unknown"
|
||||
return name
|
||||
end
|
||||
|
||||
--- Get 2D vector.
|
||||
-- @param #TARGET self
|
||||
-- @return DCS#Vec2 2D vector of the target.
|
||||
function TARGET:GetVec2()
|
||||
|
||||
for _,_target in pairs(self.targets) do
|
||||
local Target=_target --#TARGET.Object
|
||||
|
||||
local coordinate=self:GetTargetVec2(Target)
|
||||
|
||||
if coordinate then
|
||||
return coordinate
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
self:E(self.lid..string.format("ERROR: Cannot get Vec2 of target %s", self.name))
|
||||
return nil
|
||||
end
|
||||
|
||||
--- Get 3D vector.
|
||||
-- @param #TARGET self
|
||||
-- @return DCS#Vec3 3D vector of the target.
|
||||
function TARGET:GetVec3()
|
||||
|
||||
for _,_target in pairs(self.targets) do
|
||||
local Target=_target --#TARGET.Object
|
||||
|
||||
local coordinate=self:GetTargetVec3(Target)
|
||||
|
||||
if coordinate then
|
||||
return coordinate
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
self:E(self.lid..string.format("ERROR: Cannot get Vec3 of target %s", self.name))
|
||||
return nil
|
||||
end
|
||||
|
||||
--- Get coordinate.
|
||||
@@ -988,6 +1128,12 @@ function TARGET:GetCoordinate()
|
||||
return nil
|
||||
end
|
||||
|
||||
--- Get category.
|
||||
-- @param #TARGET self
|
||||
-- @return #string Target category. See `TARGET.Category.X`, where `X=AIRCRAFT, GROUND`.
|
||||
function TARGET:GetCategory()
|
||||
return self.category
|
||||
end
|
||||
|
||||
--- Get target category.
|
||||
-- @param #TARGET self
|
||||
|
||||
Reference in New Issue
Block a user