mirror of
https://github.com/FlightControl-Master/MOOSE.git
synced 2025-08-15 10:47:21 +00:00
OPS
- Fixed bug in WAREHOUSE isShip - FLIGHTGROUP added damage and ammo checks that trigger FSM events - Improved engage detected targets - Improved OPSZONE
This commit is contained in:
parent
d7dae1366d
commit
972fa9f674
@ -80,7 +80,8 @@
|
||||
-- @field #string autosavepath Path where the asset file is saved on auto save.
|
||||
-- @field #string autosavefile File name of the auto asset save file. Default is auto generated from warehouse id and name.
|
||||
-- @field #boolean safeparking If true, parking spots for aircraft are considered as occupied if e.g. a client aircraft is parked there. Default false.
|
||||
-- @field #boolean isunit If true, warehouse is represented by a unit instead of a static.
|
||||
-- @field #boolean isUnit If `true`, warehouse is represented by a unit instead of a static.
|
||||
-- @field #boolean isShip If `true`, warehouse is represented by a ship unit.
|
||||
-- @field #number lowfuelthresh Low fuel threshold. Triggers the event AssetLowFuel if for any unit fuel goes below this number.
|
||||
-- @field #boolean respawnafterdestroyed If true, warehouse is respawned after it was destroyed. Assets are kept.
|
||||
-- @field #number respawndelay Delay before respawn in seconds.
|
||||
@ -1590,7 +1591,8 @@ WAREHOUSE = {
|
||||
autosavepath = nil,
|
||||
autosavefile = nil,
|
||||
saveparking = false,
|
||||
isunit = false,
|
||||
isUnit = false,
|
||||
isShip = false,
|
||||
lowfuelthresh = 0.15,
|
||||
respawnafterdestroyed=false,
|
||||
respawndelay = nil,
|
||||
@ -1655,6 +1657,7 @@ WAREHOUSE = {
|
||||
-- @field #table transportassets Table of transport carrier assets. Each element of the table is a @{#WAREHOUSE.Assetitem}.
|
||||
-- @field #number transportattribute Attribute of transport assets of type @{#WAREHOUSE.Attribute}.
|
||||
-- @field #number transportcategory Category of transport assets of type @{#WAREHOUSE.Category}.
|
||||
-- @field #boolean lateActivation Assets are spawned in late activated state.
|
||||
|
||||
--- Item of the warehouse pending queue table.
|
||||
-- @type WAREHOUSE.Pendingitem
|
||||
@ -1857,39 +1860,45 @@ WAREHOUSE.version="1.0.2"
|
||||
-- @return #WAREHOUSE self
|
||||
function WAREHOUSE:New(warehouse, alias)
|
||||
|
||||
-- Inherit everthing from FSM class.
|
||||
local self=BASE:Inherit(self, FSM:New()) -- #WAREHOUSE
|
||||
|
||||
-- Check if just a string was given and convert to static.
|
||||
if type(warehouse)=="string" then
|
||||
local warehousename=warehouse
|
||||
local warehousename=warehouse
|
||||
warehouse=UNIT:FindByName(warehousename)
|
||||
if warehouse==nil then
|
||||
warehouse=STATIC:FindByName(warehousename, true)
|
||||
self.isunit=false
|
||||
else
|
||||
self.isunit=true
|
||||
if warehouse:IsShip() then
|
||||
env.info("FF warehouse is ship!")
|
||||
self.isShip=true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Nil check.
|
||||
if warehouse==nil then
|
||||
BASE:E("ERROR: Warehouse does not exist!")
|
||||
env.error("ERROR: Warehouse does not exist!")
|
||||
return nil
|
||||
end
|
||||
|
||||
-- Check if we have a STATIC or UNIT object.
|
||||
if warehouse:IsInstanceOf("STATIC") then
|
||||
self.isUnit=false
|
||||
elseif warehouse:IsInstanceOf("UNIT") then
|
||||
self.isUnit=true
|
||||
if warehouse:IsShip() then
|
||||
self.isShip=true
|
||||
end
|
||||
else
|
||||
env.error("ERROR: Warehouse is neither STATIC nor UNIT object!")
|
||||
return nil
|
||||
end
|
||||
|
||||
-- Set alias.
|
||||
self.alias=alias or warehouse:GetName()
|
||||
|
||||
-- Print version.
|
||||
env.info(string.format("Adding warehouse v%s for structure %s with alias %s", WAREHOUSE.version, warehouse:GetName(), self.alias))
|
||||
|
||||
-- Inherit everthing from FSM class.
|
||||
local self=BASE:Inherit(self, FSM:New()) -- #WAREHOUSE
|
||||
|
||||
-- Set some string id for output to DCS.log file.
|
||||
self.lid=string.format("WAREHOUSE %s | ", self.alias)
|
||||
|
||||
-- Print version.
|
||||
self:I(self.lid..string.format("Adding warehouse v%s for structure %s [isUnit=%s, isShip=%s]", WAREHOUSE.version, warehouse:GetName(), tostring(self:IsUnit()), tostring(self:IsShip())))
|
||||
|
||||
-- Set some variables.
|
||||
self.warehouse=warehouse
|
||||
@ -3324,7 +3333,7 @@ end
|
||||
|
||||
--- Check if runway is operational.
|
||||
-- @param #WAREHOUSE self
|
||||
-- @return #boolean If true, runway is operational.
|
||||
-- @return #boolean If `true`, runway is operational.
|
||||
function WAREHOUSE:IsRunwayOperational()
|
||||
if self.airbase then
|
||||
if self.runwaydestroyed then
|
||||
@ -3360,6 +3369,27 @@ function WAREHOUSE:GetRunwayRepairtime()
|
||||
return 0
|
||||
end
|
||||
|
||||
--- Check if warehouse physical representation is a unit (not a static) object.
|
||||
-- @param #WAREHOUSE self
|
||||
-- @return #boolean If `true`, warehouse object is a unit.
|
||||
function WAREHOUSE:IsUnit()
|
||||
return self.isUnit
|
||||
end
|
||||
|
||||
--- Check if warehouse physical representation is a static (not a unit) object.
|
||||
-- @param #WAREHOUSE self
|
||||
-- @return #boolean If `true`, warehouse object is a static.
|
||||
function WAREHOUSE:IsStatic()
|
||||
return not self.isUnit
|
||||
end
|
||||
|
||||
--- Check if warehouse physical representation is a ship.
|
||||
-- @param #WAREHOUSE self
|
||||
-- @return #boolean If `true`, warehouse object is a ship.
|
||||
function WAREHOUSE:IsShip()
|
||||
return self.isShip
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- FSM states
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
@ -4399,7 +4429,7 @@ function WAREHOUSE:onbeforeRequest(From, Event, To, Request)
|
||||
|
||||
-- Delete request from queue because it will never be possible.
|
||||
-- Unless(!) at least one is a moving warehouse, which could, e.g., be an aircraft carrier.
|
||||
if not (self.isunit or Request.warehouse.isunit) then
|
||||
if not (self.isUnit or Request.warehouse.isUnit) then
|
||||
self:_DeleteQueueItem(Request, self.queue)
|
||||
end
|
||||
|
||||
@ -5828,8 +5858,6 @@ function WAREHOUSE:_SpawnAssetGroundNaval(alias, asset, request, spawnzone, late
|
||||
|
||||
-- Late activation.
|
||||
template.lateActivation=lateactivated
|
||||
|
||||
--env.info("FF lateActivation="..tostring(template.lateActivation))
|
||||
|
||||
template.route.points[1].x = coord.x
|
||||
template.route.points[1].y = coord.z
|
||||
@ -6108,18 +6136,10 @@ function WAREHOUSE:_RouteGround(group, request)
|
||||
end
|
||||
|
||||
for n,wp in ipairs(Waypoints) do
|
||||
--env.info(n)
|
||||
local tf=self:_SimpleTaskFunctionWP("warehouse:_PassingWaypoint",group, n, #Waypoints)
|
||||
group:SetTaskWaypoint(wp, tf)
|
||||
end
|
||||
|
||||
-- Task function triggering the arrived event at the last waypoint.
|
||||
--local TaskFunction = self:_SimpleTaskFunction("warehouse:_Arrived", group)
|
||||
|
||||
-- Put task function on last waypoint.
|
||||
--local Waypoint = Waypoints[#Waypoints]
|
||||
--group:SetTaskWaypoint(Waypoint, TaskFunction)
|
||||
|
||||
-- Route group to destination.
|
||||
group:Route(Waypoints, 1)
|
||||
|
||||
@ -7676,7 +7696,7 @@ function WAREHOUSE:_SimpleTaskFunction(Function, group)
|
||||
local DCSScript = {}
|
||||
|
||||
DCSScript[#DCSScript+1] = string.format('local mygroup = GROUP:FindByName(\"%s\") ', groupname) -- The group that executes the task function. Very handy with the "...".
|
||||
if self.isunit then
|
||||
if self.isUnit then
|
||||
DCSScript[#DCSScript+1] = string.format("local mywarehouse = UNIT:FindByName(\"%s\") ", warehouse) -- The unit that holds the warehouse self object.
|
||||
else
|
||||
DCSScript[#DCSScript+1] = string.format("local mywarehouse = STATIC:FindByName(\"%s\") ", warehouse) -- The static that holds the warehouse self object.
|
||||
@ -7707,7 +7727,7 @@ function WAREHOUSE:_SimpleTaskFunctionWP(Function, group, n, N)
|
||||
local DCSScript = {}
|
||||
|
||||
DCSScript[#DCSScript+1] = string.format('local mygroup = GROUP:FindByName(\"%s\") ', groupname) -- The group that executes the task function. Very handy with the "...".
|
||||
if self.isunit then
|
||||
if self.isUnit then
|
||||
DCSScript[#DCSScript+1] = string.format("local mywarehouse = UNIT:FindByName(\"%s\") ", warehouse) -- The unit that holds the warehouse self object.
|
||||
else
|
||||
DCSScript[#DCSScript+1] = string.format("local mywarehouse = STATIC:FindByName(\"%s\") ", warehouse) -- The static that holds the warehouse self object.
|
||||
|
||||
@ -147,9 +147,10 @@ AIRWING.version="0.9.0"
|
||||
-- ToDo list
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- TODO: Spawn in air or hot ==> Needs WAREHOUSE update.
|
||||
-- TODO: Spawn in air ==> Needs WAREHOUSE update.
|
||||
-- DONE: Spawn in air.
|
||||
-- TODO: Make special request to transfer squadrons to anther airwing (or warehouse).
|
||||
-- TODO: Check that airbase has enough parking spots if a request is BIG. Alternatively, split requests.
|
||||
-- TODO: Check that airbase has enough parking spots if a request is BIG.
|
||||
-- DONE: Add squadrons to warehouse.
|
||||
-- DONE: Build mission queue.
|
||||
-- DONE: Find way to start missions.
|
||||
|
||||
@ -55,10 +55,13 @@ ARMYGROUP = {
|
||||
engage = {},
|
||||
}
|
||||
|
||||
--- Target
|
||||
--- Engage Target.
|
||||
-- @type ARMYGROUP.Target
|
||||
-- @field Ops.Target#TARGET Target The target.
|
||||
-- @field Core.Point#COORDINATE Coordinate Last known coordinate of the target.
|
||||
-- @field Ops.OpsGroup#OPSGROUP.Waypoint Waypoint the waypoint created to go to the target.
|
||||
-- @field #number roe ROE backup.
|
||||
-- @field #number alarmstate Alarm state backup.
|
||||
|
||||
--- Army Group version.
|
||||
-- @field #string version
|
||||
@ -332,7 +335,11 @@ end
|
||||
function ARMYGROUP:IsCombatReady()
|
||||
local combatready=true
|
||||
|
||||
if self:IsRearming() or self:IsRetreating() or self.outofAmmo or self:IsEngaging() or self:is("Retreated") or self:IsDead() or self:IsStopped() or self:IsInUtero() then
|
||||
if self:IsRearming() or self:IsRetreating() or self:IsOutOfAmmo() or self:IsEngaging() or self:IsDead() or self:IsStopped() or self:IsInUtero() then
|
||||
combatready=false
|
||||
end
|
||||
|
||||
if self:IsPickingup() or self:IsLoading() or self:IsTransporting() or self:IsLoaded() or self:IsCargo() or self:IsCarrier() then
|
||||
combatready=false
|
||||
end
|
||||
|
||||
@ -356,26 +363,20 @@ function ARMYGROUP:Status()
|
||||
|
||||
if alive then
|
||||
|
||||
---
|
||||
-- Detection
|
||||
---
|
||||
-- Update position etc.
|
||||
self:_UpdatePosition()
|
||||
|
||||
-- Check if group has detected any units.
|
||||
if self.detectionOn then
|
||||
self:_CheckDetectedUnits()
|
||||
end
|
||||
self:_CheckDetectedUnits()
|
||||
|
||||
-- Check ammo status.
|
||||
self:_CheckAmmoStatus()
|
||||
|
||||
-- Update position etc.
|
||||
self:_UpdatePosition()
|
||||
|
||||
-- Check if group got stuck.
|
||||
self:_CheckStuck()
|
||||
|
||||
|
||||
-- Check damage of elements and group.
|
||||
self:_CheckDamage()
|
||||
|
||||
-- Check if group got stuck.
|
||||
self:_CheckStuck()
|
||||
|
||||
-- Update engagement.
|
||||
if self:IsEngaging() then
|
||||
@ -462,6 +463,21 @@ function ARMYGROUP:Status()
|
||||
end
|
||||
self:I(self.lid..text)
|
||||
end
|
||||
|
||||
---
|
||||
-- Engage Detected Targets
|
||||
---
|
||||
if self:IsCruising() and self.detectionOn and self.engagedetectedOn then
|
||||
|
||||
local targetgroup, targetdist=self:_GetDetectedTarget()
|
||||
|
||||
-- If we found a group, we engage it.
|
||||
if targetgroup then
|
||||
self:I(self.lid..string.format("Engaging target group %s at distance %d meters", targetgroup:GetName(), targetdist))
|
||||
self:EngageTarget(targetgroup)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
---
|
||||
@ -580,7 +596,7 @@ function ARMYGROUP:onafterSpawned(From, Event, To)
|
||||
|
||||
-- Update route.
|
||||
if #self.waypoints>1 then
|
||||
self:Cruise(nil, self.option.Formation)
|
||||
self:__Cruise(-0.1, nil, self.option.Formation)
|
||||
else
|
||||
self:FullStop()
|
||||
end
|
||||
@ -1003,11 +1019,13 @@ function ARMYGROUP:onafterEngageTarget(From, Event, To, Target)
|
||||
-- Target coordinate.
|
||||
self.engage.Coordinate=UTILS.DeepCopy(self.engage.Target:GetCoordinate())
|
||||
|
||||
-- TODO: Backup current ROE and alarm state and reset after disengage.
|
||||
-- Backup ROE and alarm state.
|
||||
self.engage.roe=self:GetROE()
|
||||
self.engage.alarmstate=self:GetAlarmstate()
|
||||
|
||||
-- Switch ROE and alarm state.
|
||||
self:SwitchAlarmstate(ENUMS.AlarmState.Auto)
|
||||
self:SwitchROE(ENUMS.ROE.WeaponFree)
|
||||
self:SwitchROE(ENUMS.ROE.OpenFire)
|
||||
|
||||
-- ID of current waypoint.
|
||||
local uid=self:GetWaypointCurrent().uid
|
||||
@ -1025,17 +1043,19 @@ end
|
||||
function ARMYGROUP:_UpdateEngageTarget()
|
||||
|
||||
if self.engage.Target and self.engage.Target:IsAlive() then
|
||||
|
||||
--env.info("FF Update Engage Target "..self.engage.Target:GetName())
|
||||
|
||||
local vec3=self.engage.Target:GetCoordinate():GetVec3()
|
||||
-- Get current position vector.
|
||||
local vec3=self.engage.Target:GetVec3()
|
||||
|
||||
local dist=UTILS.VecDist2D(vec3, self.engage.Coordinate:GetVec3())
|
||||
-- Distance to last known position of target.
|
||||
local dist=UTILS.VecDist3D(vec3, self.engage.Coordinate:GetVec3())
|
||||
|
||||
-- Check if target moved more than 100 meters.
|
||||
if dist>100 then
|
||||
|
||||
--env.info("FF Update Engage Target Moved "..self.engage.Target:GetName())
|
||||
|
||||
-- Update new position.
|
||||
self.engage.Coordinate:UpdateFromVec3(vec3)
|
||||
|
||||
-- ID of current waypoint.
|
||||
@ -1053,7 +1073,10 @@ function ARMYGROUP:_UpdateEngageTarget()
|
||||
end
|
||||
|
||||
else
|
||||
|
||||
-- Target not alive any more == Disengage.
|
||||
self:Disengage()
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
@ -1066,8 +1089,17 @@ end
|
||||
function ARMYGROUP:onafterDisengage(From, Event, To)
|
||||
self:T(self.lid.."Disengage Target")
|
||||
|
||||
-- TODO: Reset ROE and alarm state.
|
||||
self:_CheckGroupDone(1)
|
||||
-- Restore previous ROE and alarm state.
|
||||
self:SwitchROE(self.engage.roe)
|
||||
self:SwitchAlarmstate(self.engage.alarmstate)
|
||||
|
||||
-- Remove current waypoint
|
||||
if self.engage.Waypoint then
|
||||
self:RemoveWaypointByID(self.engage.Waypoint.uid)
|
||||
end
|
||||
|
||||
-- Check group is done
|
||||
self:_CheckGroupDone(1)
|
||||
end
|
||||
|
||||
--- On after "Rearmed" event.
|
||||
|
||||
@ -152,16 +152,21 @@
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- # The AUFTRAG Concept
|
||||
--
|
||||
-- The AUFTRAG class significantly simplifies the workflow of using DCS tasks.
|
||||
--
|
||||
-- You can think of an AUFTRAG as document, which contains the mission briefing, i.e. information about the target location, mission altitude, speed and various other parameters.
|
||||
-- This document can be handed over directly to a pilot (or multiple pilots) via the @{Ops.FlightGroup#FLIGHTGROUP} class. The pilots will then execute the mission.
|
||||
-- The AUFTRAG document can also be given to an AIRWING. The airwing will then determine the best assets (pilots and payloads) available for the job.
|
||||
-- One more up the food chain, an AUFTRAG can be passed to a WINGCOMMANDER. The wing commander will find the best AIRWING and pass the job over to it.
|
||||
--
|
||||
-- The AUFTRAG document can also be given to an AIRWING. The airwing will then determine the best assets (pilots and payloads) available for the job.
|
||||
--
|
||||
-- Similarly, an AUFTRAG can be given to ground or navel groups via the @{Ops.ArmyGroup#ARMYGROUP} or @{Ops.NavyGroup#NAVYGROUP} classes, respectively. These classes have also
|
||||
-- AIRWING analouges, which are called BRIGADE and FLEET. Brigades and fleets will likewise select the best assets they have available and pass on the AUFTRAG to them.
|
||||
--
|
||||
--
|
||||
-- One more up the food chain, an AUFTRAG can be passed to a COMMANDER. The commander will recruit the best assets of AIRWINGs, BRIGADEs and/or FLEETs and pass the job over to it.
|
||||
--
|
||||
--
|
||||
-- # Airborne Missions
|
||||
--
|
||||
@ -169,7 +174,7 @@
|
||||
--
|
||||
-- ## Anti-Ship
|
||||
--
|
||||
-- An anti-ship mission can be created with the @{#AUFTRAG.NewANTISHIP}(*Target, Altitude*) function.
|
||||
-- An anti-ship mission can be created with the @{#AUFTRAG.NewANTISHIP}() function.
|
||||
--
|
||||
-- ## AWACS
|
||||
--
|
||||
@ -225,7 +230,7 @@
|
||||
--
|
||||
-- ## RECON
|
||||
--
|
||||
-- Not implemented yet.
|
||||
-- An reconnaissance mission can be created with the @{#AUFTRAG.NewRECON}() function.
|
||||
--
|
||||
-- ## RESCUE HELO
|
||||
--
|
||||
@ -260,40 +265,43 @@
|
||||
--
|
||||
-- # Assigning Missions
|
||||
--
|
||||
-- An AUFTRAG can be assigned to groups, airwings or wingcommanders
|
||||
-- An AUFTRAG can be assigned to groups (FLIGHTGROUP, ARMYGROUP, NAVYGROUP), legions (AIRWING, BRIGADE, FLEET) or to a COMMANDER.
|
||||
--
|
||||
-- ## Group Level
|
||||
--
|
||||
-- ### Flight Group
|
||||
--
|
||||
-- Assigning an AUFTRAG to a flight groups is done via the @{Ops.FlightGroup#FLIGHTGROUP.AddMission} function. See FLIGHTGROUP docs for details.
|
||||
-- Assigning an AUFTRAG to a flight group is done via the @{Ops.FlightGroup#FLIGHTGROUP.AddMission} function. See FLIGHTGROUP docs for details.
|
||||
--
|
||||
-- ### Army Group
|
||||
--
|
||||
-- Assigning an AUFTRAG to an army group is done via the @{Ops.ArmyGroup#ARMYGROUP.AddMission} function. See ARMYGROUP docs for details.
|
||||
--
|
||||
-- ### Navy Group
|
||||
--
|
||||
-- Assigning an AUFTRAG to a navy groups is done via the @{Ops.NavyGroup#NAVYGROUP.AddMission} function. See NAVYGROUP docs for details.
|
||||
-- Assigning an AUFTRAG to a navy group is done via the @{Ops.NavyGroup#NAVYGROUP.AddMission} function. See NAVYGROUP docs for details.
|
||||
--
|
||||
-- ## Legion Level
|
||||
--
|
||||
-- Adding an AUFTRAG to an airwing is done via the @{Ops.AirWing#AIRWING.AddMission} function. See AIRWING docs for further details.
|
||||
-- Similarly, an AUFTRAG can be added to a brigade via the @{Ops.Brigade#BRIGADE.AddMission} function
|
||||
-- Similarly, an AUFTRAG can be added to a brigade via the @{Ops.Brigade#BRIGADE.AddMission} function.
|
||||
--
|
||||
-- ## Commander Level
|
||||
--
|
||||
-- Assigning an AUFTRAG to acommander is done via the @{Ops.Commander#COMMANDER.AddMission} function. See COMMADER docs for details.
|
||||
-- Assigning an AUFTRAG to acommander is done via the @{Ops.Commander#COMMANDER.AddMission} function. See COMMANDER docs for details.
|
||||
--
|
||||
-- ## Chief Level
|
||||
--
|
||||
-- Assigning an AUFTRAG to a wing commander is done via the @{Ops.Chief#CHIEF.AddMission} function. See CHIEF docs for details.
|
||||
--
|
||||
--
|
||||
--
|
||||
-- # Events
|
||||
--
|
||||
-- The AUFTRAG class creates many useful (FSM) events, which can be used in the mission designers script.
|
||||
-- The AUFTRAG class creates many useful (FSM) events, which can be used in the mission designers script.
|
||||
--
|
||||
-- TODO
|
||||
--
|
||||
--
|
||||
-- # Examples
|
||||
--
|
||||
-- TODO
|
||||
--
|
||||
--
|
||||
-- @field #AUFTRAG
|
||||
AUFTRAG = {
|
||||
@ -599,8 +607,8 @@ function AUFTRAG:New(Type)
|
||||
self:SetStartState(self.status)
|
||||
|
||||
-- PLANNED --> (QUEUED) --> (REQUESTED) --> SCHEDULED --> STARTED --> EXECUTING --> DONE
|
||||
self:AddTransition("*", "Planned", AUFTRAG.Status.PLANNED) -- Mission is in planning stage.
|
||||
self:AddTransition(AUFTRAG.Status.PLANNED, "Queued", AUFTRAG.Status.QUEUED) -- Mission is in queue of an AIRWING.
|
||||
self:AddTransition("*", "Planned", AUFTRAG.Status.PLANNED) -- Mission is in planning stage. Could be in the queue of a COMMANDER or CHIEF.
|
||||
self:AddTransition(AUFTRAG.Status.PLANNED, "Queued", AUFTRAG.Status.QUEUED) -- Mission is in queue of a LEGION.
|
||||
self:AddTransition(AUFTRAG.Status.QUEUED, "Requested", AUFTRAG.Status.REQUESTED) -- Mission assets have been requested from the warehouse.
|
||||
self:AddTransition(AUFTRAG.Status.REQUESTED, "Scheduled", AUFTRAG.Status.SCHEDULED) -- Mission added to the first ops group queue.
|
||||
|
||||
@ -624,6 +632,171 @@ function AUFTRAG:New(Type)
|
||||
self:AddTransition("*", "ElementDestroyed", "*")
|
||||
self:AddTransition("*", "GroupDead", "*")
|
||||
self:AddTransition("*", "AssetDead", "*")
|
||||
|
||||
------------------------
|
||||
--- Pseudo Functions ---
|
||||
------------------------
|
||||
|
||||
--- Triggers the FSM event "Status".
|
||||
-- @function [parent=#AUFTRAG] Status
|
||||
-- @param #AUFTRAG self
|
||||
|
||||
--- Triggers the FSM event "Status" after a delay.
|
||||
-- @function [parent=#AUFTRAG] __Status
|
||||
-- @param #AUFTRAG self
|
||||
-- @param #number delay Delay in seconds.
|
||||
|
||||
--- Triggers the FSM event "Stop".
|
||||
-- @function [parent=#AUFTRAG] Stop
|
||||
-- @param #AUFTRAG self
|
||||
|
||||
--- Triggers the FSM event "Stop" after a delay.
|
||||
-- @function [parent=#AUFTRAG] __Stop
|
||||
-- @param #AUFTRAG self
|
||||
-- @param #number delay Delay in seconds.
|
||||
|
||||
|
||||
--- Triggers the FSM event "Planned".
|
||||
-- @function [parent=#AUFTRAG] Planned
|
||||
-- @param #AUFTRAG self
|
||||
|
||||
--- Triggers the FSM event "Planned" after a delay.
|
||||
-- @function [parent=#AUFTRAG] __Planned
|
||||
-- @param #AUFTRAG self
|
||||
-- @param #number delay Delay in seconds.
|
||||
|
||||
|
||||
--- Triggers the FSM event "Queued".
|
||||
-- @function [parent=#AUFTRAG] Queued
|
||||
-- @param #AUFTRAG self
|
||||
|
||||
--- Triggers the FSM event "Queued" after a delay.
|
||||
-- @function [parent=#AUFTRAG] __Queued
|
||||
-- @param #AUFTRAG self
|
||||
-- @param #number delay Delay in seconds.
|
||||
|
||||
|
||||
--- Triggers the FSM event "Requested".
|
||||
-- @function [parent=#AUFTRAG] Requested
|
||||
-- @param #AUFTRAG self
|
||||
|
||||
--- Triggers the FSM event "Requested" after a delay.
|
||||
-- @function [parent=#AUFTRAG] __Requested
|
||||
-- @param #AUFTRAG self
|
||||
-- @param #number delay Delay in seconds.
|
||||
|
||||
|
||||
--- Triggers the FSM event "Scheduled".
|
||||
-- @function [parent=#AUFTRAG] Scheduled
|
||||
-- @param #AUFTRAG self
|
||||
|
||||
--- Triggers the FSM event "Scheduled" after a delay.
|
||||
-- @function [parent=#AUFTRAG] __Scheduled
|
||||
-- @param #AUFTRAG self
|
||||
-- @param #number delay Delay in seconds.
|
||||
|
||||
|
||||
--- Triggers the FSM event "Started".
|
||||
-- @function [parent=#AUFTRAG] Started
|
||||
-- @param #AUFTRAG self
|
||||
|
||||
--- Triggers the FSM event "Started" after a delay.
|
||||
-- @function [parent=#AUFTRAG] __Started
|
||||
-- @param #AUFTRAG self
|
||||
-- @param #number delay Delay in seconds.
|
||||
|
||||
|
||||
--- Triggers the FSM event "Executing".
|
||||
-- @function [parent=#AUFTRAG] Executing
|
||||
-- @param #AUFTRAG self
|
||||
|
||||
--- Triggers the FSM event "Executing" after a delay.
|
||||
-- @function [parent=#AUFTRAG] __Executing
|
||||
-- @param #AUFTRAG self
|
||||
-- @param #number delay Delay in seconds.
|
||||
|
||||
|
||||
--- Triggers the FSM event "Cancel".
|
||||
-- @function [parent=#AUFTRAG] Cancel
|
||||
-- @param #AUFTRAG self
|
||||
|
||||
--- Triggers the FSM event "Cancel" after a delay.
|
||||
-- @function [parent=#AUFTRAG] __Cancel
|
||||
-- @param #AUFTRAG self
|
||||
-- @param #number delay Delay in seconds.
|
||||
|
||||
--- On after "Cancel" event.
|
||||
-- @function [parent=#AUFTRAG] OnAfterCancel
|
||||
-- @param #AUFTRAG self
|
||||
-- @param #string From From state.
|
||||
-- @param #string Event Event.
|
||||
-- @param #string To To state.
|
||||
|
||||
|
||||
--- Triggers the FSM event "Done".
|
||||
-- @function [parent=#AUFTRAG] Done
|
||||
-- @param #AUFTRAG self
|
||||
|
||||
--- Triggers the FSM event "Done" after a delay.
|
||||
-- @function [parent=#AUFTRAG] __Done
|
||||
-- @param #AUFTRAG self
|
||||
-- @param #number delay Delay in seconds.
|
||||
|
||||
--- On after "Done" event.
|
||||
-- @function [parent=#AUFTRAG] OnAfterDone
|
||||
-- @param #AUFTRAG self
|
||||
-- @param #string From From state.
|
||||
-- @param #string Event Event.
|
||||
-- @param #string To To state.
|
||||
|
||||
|
||||
--- Triggers the FSM event "Success".
|
||||
-- @function [parent=#AUFTRAG] Success
|
||||
-- @param #AUFTRAG self
|
||||
|
||||
--- Triggers the FSM event "Success" after a delay.
|
||||
-- @function [parent=#AUFTRAG] __Success
|
||||
-- @param #AUFTRAG self
|
||||
-- @param #number delay Delay in seconds.
|
||||
|
||||
--- On after "Success" event.
|
||||
-- @function [parent=#AUFTRAG] OnAfterSuccess
|
||||
-- @param #AUFTRAG self
|
||||
-- @param #string From From state.
|
||||
-- @param #string Event Event.
|
||||
-- @param #string To To state.
|
||||
|
||||
--- Triggers the FSM event "Failure".
|
||||
-- @function [parent=#AUFTRAG] Failure
|
||||
-- @param #AUFTRAG self
|
||||
|
||||
--- Triggers the FSM event "Failure" after a delay.
|
||||
-- @function [parent=#AUFTRAG] __Failure
|
||||
-- @param #AUFTRAG self
|
||||
-- @param #number delay Delay in seconds.
|
||||
|
||||
--- On after "Failure" event.
|
||||
-- @function [parent=#AUFTRAG] OnAfterFailure
|
||||
-- @param #AUFTRAG self
|
||||
-- @param #string From From state.
|
||||
-- @param #string Event Event.
|
||||
-- @param #string To To state.
|
||||
|
||||
--- Triggers the FSM event "Repeat".
|
||||
-- @function [parent=#AUFTRAG] Repeat
|
||||
-- @param #AUFTRAG self
|
||||
|
||||
--- Triggers the FSM event "Repeat" after a delay.
|
||||
-- @function [parent=#AUFTRAG] __Repeat
|
||||
-- @param #AUFTRAG self
|
||||
-- @param #number delay Delay in seconds.
|
||||
|
||||
--- On after "Repeat" event.
|
||||
-- @function [parent=#AUFTRAG] OnAfterRepeat
|
||||
-- @param #AUFTRAG self
|
||||
-- @param #string From From state.
|
||||
-- @param #string Event Event.
|
||||
-- @param #string To To state.
|
||||
|
||||
-- Init status update.
|
||||
self:__Status(-1)
|
||||
@ -1921,6 +2094,44 @@ function AUFTRAG:SetEngageAltitude(Altitude)
|
||||
return self
|
||||
end
|
||||
|
||||
--- Enable to automatically engage detected targets.
|
||||
-- @param #AUFTRAG self
|
||||
-- @param #number RangeMax Max range in NM. Only detected targets within this radius from the group will be engaged. Default is 25 NM.
|
||||
-- @param #table TargetTypes Types of target attributes that will be engaged. See [DCS enum attributes](https://wiki.hoggitworld.com/view/DCS_enum_attributes). Default "All".
|
||||
-- @param Core.Set#SET_ZONE EngageZoneSet Set of zones in which targets are engaged. Default is anywhere.
|
||||
-- @param Core.Set#SET_ZONE NoEngageZoneSet Set of zones in which targets are *not* engaged. Default is nowhere.
|
||||
-- @return #AUFTRAG self
|
||||
function AUFTRAG:SetEngageDetected(RangeMax, TargetTypes, EngageZoneSet, NoEngageZoneSet)
|
||||
|
||||
-- Ensure table.
|
||||
if TargetTypes then
|
||||
if type(TargetTypes)~="table" then
|
||||
TargetTypes={TargetTypes}
|
||||
end
|
||||
else
|
||||
TargetTypes={"All"}
|
||||
end
|
||||
|
||||
-- Ensure SET_ZONE if ZONE is provided.
|
||||
if EngageZoneSet and EngageZoneSet:IsInstanceOf("ZONE_BASE") then
|
||||
local zoneset=SET_ZONE:New():AddZone(EngageZoneSet)
|
||||
EngageZoneSet=zoneset
|
||||
end
|
||||
if NoEngageZoneSet and NoEngageZoneSet:IsInstanceOf("ZONE_BASE") then
|
||||
local zoneset=SET_ZONE:New():AddZone(NoEngageZoneSet)
|
||||
NoEngageZoneSet=zoneset
|
||||
end
|
||||
|
||||
-- Set parameters.
|
||||
self.engagedetectedOn=true
|
||||
self.engagedetectedRmax=UTILS.NMToMeters(RangeMax or 25)
|
||||
self.engagedetectedTypes=TargetTypes
|
||||
self.engagedetectedEngageZones=EngageZoneSet
|
||||
self.engagedetectedNoEngageZones=NoEngageZoneSet
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set mission altitude. This is the altitude of the waypoint create where the DCS task is executed.
|
||||
-- @param #AUFTRAG self
|
||||
-- @param #string Altitude Altitude in feet.
|
||||
@ -4039,8 +4250,9 @@ end
|
||||
-- @param #AUFTRAG self
|
||||
-- @param Wrapper.Group#GROUP group Group.
|
||||
-- @param #number randomradius Random radius in meters.
|
||||
-- @param #table surfacetypes Surface types of random zone.
|
||||
-- @return Core.Point#COORDINATE Coordinate where the mission is executed.
|
||||
function AUFTRAG:GetMissionWaypointCoord(group, randomradius)
|
||||
function AUFTRAG:GetMissionWaypointCoord(group, randomradius, surfacetypes)
|
||||
|
||||
-- Check if a coord has been explicitly set.
|
||||
if self.missionWaypointCoord then
|
||||
@ -4052,12 +4264,12 @@ function AUFTRAG:GetMissionWaypointCoord(group, randomradius)
|
||||
end
|
||||
|
||||
-- Create waypoint coordinate half way between us and the target.
|
||||
local waypointcoord=group:GetCoordinate():GetIntermediateCoordinate(self:GetTargetCoordinate(), self.missionFraction)
|
||||
local waypointcoord=group:GetCoordinate():GetIntermediateCoordinate(self:GetTargetCoordinate(), self.missionFraction)
|
||||
local alt=waypointcoord.y
|
||||
|
||||
-- Add some randomization.
|
||||
if randomradius then
|
||||
waypointcoord=ZONE_RADIUS:New("Temp", waypointcoord:GetVec2(), randomradius):GetRandomCoordinate():SetAltitude(alt, false)
|
||||
waypointcoord=ZONE_RADIUS:New("Temp", waypointcoord:GetVec2(), randomradius):GetRandomCoordinate(nil, nil, surfacetypes):SetAltitude(alt, false)
|
||||
end
|
||||
|
||||
-- Set altitude of mission waypoint.
|
||||
|
||||
@ -413,6 +413,47 @@ function CHIEF:GetCommander()
|
||||
return self.commander
|
||||
end
|
||||
|
||||
|
||||
--- Add an AIRWING to the chief's commander.
|
||||
-- @param #CHIEF self
|
||||
-- @param Ops.AirWing#AIRWING Airwing The airwing to add.
|
||||
-- @return #CHIEF self
|
||||
function CHIEF:AddAirwing(Airwing)
|
||||
|
||||
-- Add airwing to the commander.
|
||||
self:AddLegion(Airwing)
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Add a BRIGADE to the chief's commander.
|
||||
-- @param #CHIEF self
|
||||
-- @param Ops.Brigade#BRIGADE Brigade The brigade to add.
|
||||
-- @return #CHIEF self
|
||||
function CHIEF:AddBrigade(Brigade)
|
||||
|
||||
-- Add brigade to the commander
|
||||
self:AddLegion(Brigade)
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Add a LEGION to the chief's commander.
|
||||
-- @param #CHIEF self
|
||||
-- @param Ops.Legion#LEGION Legion The legion to add.
|
||||
-- @return #CHIEF self
|
||||
function CHIEF:AddLegion(Legion)
|
||||
|
||||
-- Set chief of the legion.
|
||||
Legion.chief=self
|
||||
|
||||
-- Add legion to the commander.
|
||||
self.commander:AddLegion(Legion)
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- Add mission to mission queue of the COMMANDER.
|
||||
-- @param #CHIEF self
|
||||
-- @param Ops.Auftrag#AUFTRAG Mission Mission to be added.
|
||||
@ -1181,10 +1222,8 @@ function CHIEF:CheckOpsZoneQueue()
|
||||
env.info(string.format("Zone %s is owned by coalition %d", opszone.zone:GetName(), ownercoalition))
|
||||
|
||||
-- Recruit ground assets that
|
||||
local recruited, assets, legions=self:RecruitAssetsForZone(opszone, AUFTRAG.Type.PATROLZONE, 1, 3, {Group.Category.GROUND}, {GROUP.Attribute.GROUND_INFANTRY})
|
||||
|
||||
|
||||
|
||||
local recruited=self:RecruitAssetsForZone(opszone, AUFTRAG.Type.PATROLZONE, 1, 3, {Group.Category.GROUND}, {GROUP.Attribute.GROUND_INFANTRY})
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
@ -1494,8 +1533,6 @@ end
|
||||
-- @param #table Categories Group categories of the assets.
|
||||
-- @param #table Attributes Generalized group attributes.
|
||||
-- @return #boolean If `true` enough assets could be recruited.
|
||||
-- @return #table Assets that have been recruited from all legions.
|
||||
-- @return #table Legions that have recruited assets.
|
||||
function CHIEF:RecruitAssetsForZone(OpsZone, MissionType, NassetsMin, NassetsMax, Categories, Attributes)
|
||||
|
||||
-- Cohorts.
|
||||
@ -1520,7 +1557,7 @@ function CHIEF:RecruitAssetsForZone(OpsZone, MissionType, NassetsMin, NassetsMax
|
||||
-- Target position.
|
||||
local TargetVec2=OpsZone.zone:GetVec2()
|
||||
|
||||
-- Recruite assets.
|
||||
-- Recruite infantry assets.
|
||||
local recruitedInf, assetsInf, legionsInf=LEGION.RecruitCohortAssets(Cohorts, MissionType, nil, NassetsMin, NassetsMax, TargetVec2, nil, nil, nil, nil, Categories, Attributes)
|
||||
|
||||
if recruitedInf then
|
||||
@ -1536,9 +1573,9 @@ function CHIEF:RecruitAssetsForZone(OpsZone, MissionType, NassetsMin, NassetsMax
|
||||
end
|
||||
end
|
||||
|
||||
-- Recruite assets.
|
||||
-- Recruite carrier assets. This need to be ground or helicopters to deploy at a zone.
|
||||
local recruitedTrans, assetsTrans, legionsTrans=
|
||||
LEGION.RecruitCohortAssets(Cohorts, AUFTRAG.Type.OPSTRANSPORT, nil, NassetsMin, NassetsMax, TargetVec2, nil, nil, nil, weightMax, {Group.Category.HELICOPTER, Group.Category.GROUND})
|
||||
LEGION.RecruitCohortAssets(Cohorts, AUFTRAG.Type.OPSTRANSPORT, nil, 1, 1, TargetVec2, nil, nil, nil, weightMax, {Group.Category.HELICOPTER, Group.Category.GROUND})
|
||||
|
||||
local transport=nil --Ops.OpsTransport#OPSTRANSPORT
|
||||
if recruitedTrans then
|
||||
@ -1550,7 +1587,15 @@ function CHIEF:RecruitAssetsForZone(OpsZone, MissionType, NassetsMin, NassetsMax
|
||||
-- Add cargo assets to transport.
|
||||
for _,_legion in pairs(legionsInf) do
|
||||
local legion=_legion --Ops.Legion#LEGION
|
||||
local tpz=transport:AddTransportZoneCombo(legion.spawnzone, OpsZone.zone)
|
||||
|
||||
-- Pickup at spawnzone or at airbase if the legion warehouse has one.
|
||||
local pickupzone=legion.spawnzone
|
||||
if legion.airbase and legion:IsRunwayOperational() then
|
||||
pickupzone=ZONE_AIRBASE:New(legion.airbasename, 4000)
|
||||
end
|
||||
|
||||
local tpz=transport:AddTransportZoneCombo(pickupzone, OpsZone.zone)
|
||||
|
||||
for _,_asset in pairs(assetsInf) do
|
||||
local asset=_asset --Functional.Warehouse#WAREHOUSE.Assetitem
|
||||
if asset.legion.alias==legion.alias then
|
||||
@ -1579,6 +1624,7 @@ function CHIEF:RecruitAssetsForZone(OpsZone, MissionType, NassetsMin, NassetsMax
|
||||
|
||||
-- Create Patrol zone mission.
|
||||
local mission=AUFTRAG:NewPATROLZONE(OpsZone.zone)
|
||||
mission:SetEngageDetected()
|
||||
|
||||
for _,asset in pairs(assetsInf) do
|
||||
mission:AddAsset(asset)
|
||||
@ -1593,11 +1639,13 @@ function CHIEF:RecruitAssetsForZone(OpsZone, MissionType, NassetsMin, NassetsMax
|
||||
|
||||
OpsZone.missionPatrol=mission
|
||||
|
||||
return true
|
||||
else
|
||||
LEGION.UnRecruitAssets(assetsInf)
|
||||
return false
|
||||
end
|
||||
|
||||
return recruited, assets, legions
|
||||
return nil
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
@ -20,7 +20,7 @@
|
||||
-- @field #table legions Table of legions which are commanded.
|
||||
-- @field #table missionqueue Mission queue.
|
||||
-- @field #table transportqueue Transport queue.
|
||||
-- @field Ops.ChiefOfStaff#CHIEF chief Chief of staff.
|
||||
-- @field Ops.Chief#CHIEF chief Chief of staff.
|
||||
-- @extends Core.Fsm#FSM
|
||||
|
||||
--- Be surprised!
|
||||
@ -736,6 +736,7 @@ function COMMANDER:CheckMissionQueue()
|
||||
for _,_legion in pairs(legions) do
|
||||
local legion=_legion --Ops.Legion#LEGION
|
||||
|
||||
-- Set pickup zone to spawn zone or airbase if the legion has one that is operational.
|
||||
local pickupzone=legion.spawnzone
|
||||
if legion.airbase and legion:IsRunwayOperational() then
|
||||
pickupzone=ZONE_AIRBASE:New(legion.airbasename, 4000)
|
||||
|
||||
@ -501,55 +501,6 @@ function FLIGHTGROUP:SetFuelCriticalRTB(switch)
|
||||
return self
|
||||
end
|
||||
|
||||
--- Enable to automatically engage detected targets.
|
||||
-- @param #FLIGHTGROUP self
|
||||
-- @param #number RangeMax Max range in NM. Only detected targets within this radius from the group will be engaged. Default is 25 NM.
|
||||
-- @param #table TargetTypes Types of target attributes that will be engaged. See [DCS enum attributes](https://wiki.hoggitworld.com/view/DCS_enum_attributes). Default "All".
|
||||
-- @param Core.Set#SET_ZONE EngageZoneSet Set of zones in which targets are engaged. Default is anywhere.
|
||||
-- @param Core.Set#SET_ZONE NoEngageZoneSet Set of zones in which targets are *not* engaged. Default is nowhere.
|
||||
-- @return #FLIGHTGROUP self
|
||||
function FLIGHTGROUP:SetEngageDetectedOn(RangeMax, TargetTypes, EngageZoneSet, NoEngageZoneSet)
|
||||
|
||||
-- Ensure table.
|
||||
if TargetTypes then
|
||||
if type(TargetTypes)~="table" then
|
||||
TargetTypes={TargetTypes}
|
||||
end
|
||||
else
|
||||
TargetTypes={"All"}
|
||||
end
|
||||
|
||||
-- Ensure SET_ZONE if ZONE is provided.
|
||||
if EngageZoneSet and EngageZoneSet:IsInstanceOf("ZONE_BASE") then
|
||||
local zoneset=SET_ZONE:New():AddZone(EngageZoneSet)
|
||||
EngageZoneSet=zoneset
|
||||
end
|
||||
if NoEngageZoneSet and NoEngageZoneSet:IsInstanceOf("ZONE_BASE") then
|
||||
local zoneset=SET_ZONE:New():AddZone(NoEngageZoneSet)
|
||||
NoEngageZoneSet=zoneset
|
||||
end
|
||||
|
||||
-- Set parameters.
|
||||
self.engagedetectedOn=true
|
||||
self.engagedetectedRmax=UTILS.NMToMeters(RangeMax or 25)
|
||||
self.engagedetectedTypes=TargetTypes
|
||||
self.engagedetectedEngageZones=EngageZoneSet
|
||||
self.engagedetectedNoEngageZones=NoEngageZoneSet
|
||||
|
||||
-- Ensure detection is ON or it does not make any sense.
|
||||
self:SetDetection(true)
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Disable to automatically engage detected targets.
|
||||
-- @param #FLIGHTGROUP self
|
||||
-- @return #FLIGHTGROUP self
|
||||
function FLIGHTGROUP:SetEngageDetectedOff()
|
||||
self.engagedetectedOn=false
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- Enable that the group is despawned after landing. This can be useful to avoid DCS taxi issues with other AI or players or jamming taxiways.
|
||||
-- @param #FLIGHTGROUP self
|
||||
@ -841,23 +792,28 @@ function FLIGHTGROUP:Status()
|
||||
|
||||
-- FSM state.
|
||||
local fsmstate=self:GetState()
|
||||
|
||||
-- Is group alive?
|
||||
local alive=self:IsAlive()
|
||||
|
||||
-- Update position.
|
||||
self:_UpdatePosition()
|
||||
|
||||
---
|
||||
-- Detection
|
||||
---
|
||||
|
||||
-- Check if group has detected any units.
|
||||
if self.detectionOn then
|
||||
self:_CheckDetectedUnits()
|
||||
end
|
||||
|
||||
self:_CheckDetectedUnits()
|
||||
|
||||
-- Check ammo status.
|
||||
self:_CheckAmmoStatus()
|
||||
|
||||
-- Check damage.
|
||||
self:_CheckDamage()
|
||||
|
||||
---
|
||||
-- Parking
|
||||
---
|
||||
|
||||
-- TODO: _CheckParking() function
|
||||
|
||||
-- Check if flight began to taxi (if it was parking).
|
||||
if self:IsParking() then
|
||||
for _,_element in pairs(self.elements) do
|
||||
@ -930,11 +886,6 @@ function FLIGHTGROUP:Status()
|
||||
local lp0=unit:GetLife0()
|
||||
local parking=element.parking and tostring(element.parking.TerminalID) or "X"
|
||||
|
||||
-- Check if element is not dead and we missed an event.
|
||||
--if life<=0 and element.status~=OPSGROUP.ElementStatus.DEAD and element.status~=OPSGROUP.ElementStatus.INUTERO then
|
||||
-- self:ElementDead(element)
|
||||
--end
|
||||
|
||||
-- Get ammo.
|
||||
local ammo=self:GetAmmoElement(element)
|
||||
|
||||
@ -952,7 +903,9 @@ function FLIGHTGROUP:Status()
|
||||
-- Distance travelled
|
||||
---
|
||||
|
||||
if self.verbose>=4 and self:IsAlive() then
|
||||
if self.verbose>=4 and alive then
|
||||
|
||||
-- TODO: _Check distance travelled.
|
||||
|
||||
-- Travelled distance since last check.
|
||||
local ds=self.travelds
|
||||
@ -998,18 +951,14 @@ function FLIGHTGROUP:Status()
|
||||
|
||||
end
|
||||
|
||||
---
|
||||
-- Tasks & Missions
|
||||
---
|
||||
|
||||
self:_PrintTaskAndMissionStatus()
|
||||
|
||||
---
|
||||
-- Fuel State
|
||||
---
|
||||
|
||||
-- TODO: _CheckFuelState() function.
|
||||
|
||||
-- Only if group is in air.
|
||||
if self:IsAlive() and self.group:IsAirborne(true) then
|
||||
if alive and self.group:IsAirborne(true) then
|
||||
|
||||
local fuelmin=self:GetFuelMin()
|
||||
|
||||
@ -1051,77 +1000,7 @@ function FLIGHTGROUP:Status()
|
||||
---
|
||||
if self:IsAirborne() and self:IsFuelGood() and self.detectionOn and self.engagedetectedOn then
|
||||
|
||||
-- Target.
|
||||
local targetgroup=nil --Wrapper.Group#GROUP
|
||||
local targetdist=math.huge
|
||||
|
||||
-- Loop over detected groups.
|
||||
for _,_group in pairs(self.detectedgroups:GetSet()) do
|
||||
local group=_group --Wrapper.Group#GROUP
|
||||
|
||||
if group and group:IsAlive() then
|
||||
|
||||
-- Get 3D vector of target.
|
||||
local targetVec3=group:GetVec3()
|
||||
|
||||
-- Distance to target.
|
||||
local distance=UTILS.VecDist3D(self.position, targetVec3)
|
||||
|
||||
if distance<=self.engagedetectedRmax and distance<targetdist then
|
||||
|
||||
-- Check type attribute.
|
||||
local righttype=false
|
||||
for _,attribute in pairs(self.engagedetectedTypes) do
|
||||
local gotit=group:HasAttribute(attribute, false)
|
||||
self:I(self.lid..string.format("Group %s has attribute %s = %s", group:GetName(), attribute, tostring(gotit)))
|
||||
if gotit then
|
||||
righttype=true
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
-- We got the right type.
|
||||
if righttype then
|
||||
|
||||
local insideEngage=true
|
||||
local insideNoEngage=false
|
||||
|
||||
-- Check engage zones.
|
||||
if self.engagedetectedEngageZones then
|
||||
insideEngage=false
|
||||
for _,_zone in pairs(self.engagedetectedEngageZones.Set) do
|
||||
local zone=_zone --Core.Zone#ZONE
|
||||
local inzone=zone:IsVec3InZone(targetVec3)
|
||||
if inzone then
|
||||
insideEngage=true
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Check no engage zones.
|
||||
if self.engagedetectedNoEngageZones then
|
||||
for _,_zone in pairs(self.engagedetectedNoEngageZones.Set) do
|
||||
local zone=_zone --Core.Zone#ZONE
|
||||
local inzone=zone:IsVec3InZone(targetVec3)
|
||||
if inzone then
|
||||
insideNoEngage=true
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- If inside engage but not inside no engage zones.
|
||||
if insideEngage and not insideNoEngage then
|
||||
targetdist=distance
|
||||
targetgroup=group
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
local targetgroup, targetdist=self:_GetDetectedTarget()
|
||||
|
||||
-- If we found a group, we engage it.
|
||||
if targetgroup then
|
||||
@ -1137,6 +1016,12 @@ function FLIGHTGROUP:Status()
|
||||
|
||||
self:_CheckCargoTransport()
|
||||
|
||||
---
|
||||
-- Tasks & Missions
|
||||
---
|
||||
|
||||
self:_PrintTaskAndMissionStatus()
|
||||
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
@ -18,6 +18,7 @@
|
||||
-- @field #table transportqueue Transport queue.
|
||||
-- @field #table cohorts Cohorts of this legion.
|
||||
-- @field Ops.Commander#COMMANDER commander Commander of this legion.
|
||||
-- @field Ops.Chief#CHIEF chief Chief of this legion.
|
||||
-- @extends Functional.Warehouse#WAREHOUSE
|
||||
|
||||
--- Be surprised!
|
||||
@ -672,9 +673,9 @@ function LEGION:onafterMissionRequest(From, Event, To, Mission)
|
||||
local request=self:GetRequestByID(self.queueid)
|
||||
|
||||
if request then
|
||||
if self.isShip then
|
||||
--self:T(self.lid.."FF request late activated")
|
||||
--request.lateActivation=true
|
||||
if self:IsShip() then
|
||||
self:T(self.lid.."Warehouse phyiscal structure is SHIP. Requestes assets will be late activated!")
|
||||
request.lateActivation=true
|
||||
end
|
||||
end
|
||||
|
||||
@ -985,6 +986,8 @@ function LEGION:onafterAssetSpawned(From, Event, To, group, asset, request)
|
||||
|
||||
-- Check if we have a cohort or if this was some other request.
|
||||
if cohort then
|
||||
|
||||
self:I(self.lid..string.format("Cohort asset spawned %s", asset.spawngroupname))
|
||||
|
||||
-- Create a flight group.
|
||||
local flightgroup=self:_CreateFlightGroup(asset)
|
||||
@ -1064,8 +1067,10 @@ function LEGION:onafterAssetSpawned(From, Event, To, group, asset, request)
|
||||
end
|
||||
|
||||
-- Add group to the detection set of the CHIEF (INTEL).
|
||||
if self.commander and self.commander.chief then
|
||||
self.commander.chief.detectionset:AddGroup(asset.flightgroup.group)
|
||||
local chief=self.chief or (self.commander and self.commander.chief or nil) --Ops.Chief#CHIEF
|
||||
if chief then
|
||||
self:I(self.lid..string.format("Adding group %s to agents of CHIEF", group:GetName()))
|
||||
chief.detectionset:AddGroup(asset.flightgroup.group)
|
||||
end
|
||||
|
||||
elseif string.find(assignment, "Transport-") then
|
||||
|
||||
@ -465,26 +465,22 @@ function NAVYGROUP:Status(From, Event, To)
|
||||
-- Is group alive?
|
||||
local alive=self:IsAlive()
|
||||
|
||||
--
|
||||
-- Free path.
|
||||
local freepath=0
|
||||
|
||||
-- Check if group is exists and is active.
|
||||
if alive then
|
||||
|
||||
---
|
||||
-- Detection
|
||||
---
|
||||
|
||||
-- Check if group has detected any units.
|
||||
if self.detectionOn then
|
||||
self:_CheckDetectedUnits()
|
||||
end
|
||||
|
||||
|
||||
-- Update last known position, orientation, velocity.
|
||||
self:_UpdatePosition()
|
||||
|
||||
-- Check if group has detected any units.
|
||||
self:_CheckDetectedUnits()
|
||||
|
||||
-- Check if group started or stopped turning.
|
||||
self:_CheckTurning()
|
||||
|
||||
|
||||
-- Distance to next Waypoint.
|
||||
local disttoWP=math.min(self:GetDistanceToWaypoint(), UTILS.NMToMeters(10))
|
||||
freepath=disttoWP
|
||||
|
||||
@ -527,7 +523,8 @@ function NAVYGROUP:Status(From, Event, To)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
-- Group exists but can also be inactive.
|
||||
if alive~=nil then
|
||||
|
||||
if self.verbose>=1 then
|
||||
@ -702,7 +699,7 @@ function NAVYGROUP:onafterSpawned(From, Event, To)
|
||||
|
||||
-- Update route.
|
||||
if #self.waypoints>1 then
|
||||
self:Cruise()
|
||||
self:__Cruise(-0.1)
|
||||
else
|
||||
self:FullStop()
|
||||
end
|
||||
|
||||
@ -85,6 +85,12 @@
|
||||
--
|
||||
-- @field Core.Astar#ASTAR Astar path finding.
|
||||
-- @field #boolean ispathfinding If true, group is on pathfinding route.
|
||||
--
|
||||
-- @field #boolean engagedetectedOn If `true`, auto engage detected targets.
|
||||
-- @field #number engagedetectedRmax Max range in NM. Only detected targets within this radius from the group will be engaged. Default is 25 NM.
|
||||
-- @field #table engagedetectedTypes Types of target attributes that will be engaged. See [DCS enum attributes](https://wiki.hoggitworld.com/view/DCS_enum_attributes). Default "All".
|
||||
-- @field Core.Set#SET_ZONE engagedetectedEngageZones Set of zones in which targets are engaged. Default is anywhere.
|
||||
-- @field Core.Set#SET_ZONE engagedetectedNoEngageZones Set of zones in which targets are *not* engaged. Default is nowhere.
|
||||
--
|
||||
-- @field #OPSGROUP.Radio radio Current radio settings.
|
||||
-- @field #OPSGROUP.Radio radioDefault Default radio settings.
|
||||
@ -607,8 +613,6 @@ function OPSGROUP:New(group)
|
||||
self:AddTransition("*", "InUtero", "InUtero") -- Deactivated group goes back to mummy.
|
||||
self:AddTransition("*", "Stop", "Stopped") -- Stop FSM.
|
||||
|
||||
--self:AddTransition("*", "Status", "*") -- Status update.
|
||||
|
||||
self:AddTransition("*", "Destroyed", "*") -- The whole group is dead.
|
||||
self:AddTransition("*", "Damaged", "*") -- Someone in the group took damage.
|
||||
|
||||
@ -929,6 +933,7 @@ end
|
||||
-- @param #boolean Switch If `true`, detection is on. If `false` or `nil`, detection is off. Default is off.
|
||||
-- @return #OPSGROUP self
|
||||
function OPSGROUP:SetDetection(Switch)
|
||||
self:T(self.lid..string.format("Detection is %s", tostring(Switch)))
|
||||
self.detectionOn=Switch
|
||||
return self
|
||||
end
|
||||
@ -1112,6 +1117,59 @@ function OPSGROUP:GetHighestThreat()
|
||||
return threat, levelmax
|
||||
end
|
||||
|
||||
--- Enable to automatically engage detected targets.
|
||||
-- @param #OPSGROUP self
|
||||
-- @param #number RangeMax Max range in NM. Only detected targets within this radius from the group will be engaged. Default is 25 NM.
|
||||
-- @param #table TargetTypes Types of target attributes that will be engaged. See [DCS enum attributes](https://wiki.hoggitworld.com/view/DCS_enum_attributes). Default "All".
|
||||
-- @param Core.Set#SET_ZONE EngageZoneSet Set of zones in which targets are engaged. Default is anywhere.
|
||||
-- @param Core.Set#SET_ZONE NoEngageZoneSet Set of zones in which targets are *not* engaged. Default is nowhere.
|
||||
-- @return #OPSGROUP self
|
||||
function OPSGROUP:SetEngageDetectedOn(RangeMax, TargetTypes, EngageZoneSet, NoEngageZoneSet)
|
||||
|
||||
-- Ensure table.
|
||||
if TargetTypes then
|
||||
if type(TargetTypes)~="table" then
|
||||
TargetTypes={TargetTypes}
|
||||
end
|
||||
else
|
||||
TargetTypes={"All"}
|
||||
end
|
||||
|
||||
-- Ensure SET_ZONE if ZONE is provided.
|
||||
if EngageZoneSet and EngageZoneSet:IsInstanceOf("ZONE_BASE") then
|
||||
local zoneset=SET_ZONE:New():AddZone(EngageZoneSet)
|
||||
EngageZoneSet=zoneset
|
||||
end
|
||||
if NoEngageZoneSet and NoEngageZoneSet:IsInstanceOf("ZONE_BASE") then
|
||||
local zoneset=SET_ZONE:New():AddZone(NoEngageZoneSet)
|
||||
NoEngageZoneSet=zoneset
|
||||
end
|
||||
|
||||
-- Set parameters.
|
||||
self.engagedetectedOn=true
|
||||
self.engagedetectedRmax=UTILS.NMToMeters(RangeMax or 25)
|
||||
self.engagedetectedTypes=TargetTypes
|
||||
self.engagedetectedEngageZones=EngageZoneSet
|
||||
self.engagedetectedNoEngageZones=NoEngageZoneSet
|
||||
|
||||
-- Debug info.
|
||||
self:T(self.lid..string.format("Engage detected ON: Rmax=%d NM", UTILS.MetersToNM(self.engagedetectedRmax)))
|
||||
|
||||
-- Ensure detection is ON or it does not make any sense.
|
||||
self:SetDetection(true)
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Disable to automatically engage detected targets.
|
||||
-- @param #OPSGROUP self
|
||||
-- @return #OPSGROUP self
|
||||
function OPSGROUP:SetEngageDetectedOff()
|
||||
self:T(self.lid..string.format("Engage detected OFF"))
|
||||
self.engagedetectedOn=false
|
||||
return self
|
||||
end
|
||||
|
||||
--- Check if an element of the group has line of sight to a coordinate.
|
||||
-- @param #OPSGROUP self
|
||||
-- @param Core.Point#COORDINATE Coordinate The position to which we check the LoS.
|
||||
@ -2042,7 +2100,7 @@ function OPSGROUP:HasPassedFinalWaypoint()
|
||||
return self.passedfinalwp
|
||||
end
|
||||
|
||||
--- Check if the group is currently rearming.
|
||||
--- Check if the group is currently rearming or on its way to the rearming place.
|
||||
-- @param #OPSGROUP self
|
||||
-- @return #boolean If true, group is rearming.
|
||||
function OPSGROUP:IsRearming()
|
||||
@ -2050,6 +2108,42 @@ function OPSGROUP:IsRearming()
|
||||
return rearming
|
||||
end
|
||||
|
||||
--- Check if the group is completely out of ammo.
|
||||
-- @param #OPSGROUP self
|
||||
-- @return #boolean If `true`, group is out-of-ammo.
|
||||
function OPSGROUP:IsOutOfAmmo()
|
||||
return self.outofAmmo
|
||||
end
|
||||
|
||||
--- Check if the group is out of bombs.
|
||||
-- @param #OPSGROUP self
|
||||
-- @return #boolean If `true`, group is out of bombs.
|
||||
function OPSGROUP:IsOutOfBombs()
|
||||
return self.outofBombs
|
||||
end
|
||||
|
||||
--- Check if the group is out of guns.
|
||||
-- @param #OPSGROUP self
|
||||
-- @return #boolean If `true`, group is out of guns.
|
||||
function OPSGROUP:IsOutOfGuns()
|
||||
return self.outofGuns
|
||||
end
|
||||
|
||||
--- Check if the group is out of missiles.
|
||||
-- @param #OPSGROUP self
|
||||
-- @return #boolean If `true`, group is out of missiles.
|
||||
function OPSGROUP:IsOutOfMissiles()
|
||||
return self.outofMissiles
|
||||
end
|
||||
|
||||
--- Check if the group is out of torpedos.
|
||||
-- @param #OPSGROUP self
|
||||
-- @return #boolean If `true`, group is out of torpedos.
|
||||
function OPSGROUP:IsOutOfTorpedos()
|
||||
return self.outofTorpedos
|
||||
end
|
||||
|
||||
|
||||
--- Check if the group has currently switched a LASER on.
|
||||
-- @param #OPSGROUP self
|
||||
-- @return #boolean If true, LASER of the group is on.
|
||||
@ -2057,14 +2151,23 @@ function OPSGROUP:IsLasing()
|
||||
return self.spot.On
|
||||
end
|
||||
|
||||
--- Check if the group is currently retreating.
|
||||
--- Check if the group is currently retreating or retreated.
|
||||
-- @param #OPSGROUP self
|
||||
-- @return #boolean If true, group is retreating.
|
||||
-- @return #boolean If true, group is retreating or retreated.
|
||||
function OPSGROUP:IsRetreating()
|
||||
local is=self:is("Retreating")
|
||||
local is=self:is("Retreating") or self:is("Retreated")
|
||||
return is
|
||||
end
|
||||
|
||||
--- Check if the group is retreated (has reached its retreat zone).
|
||||
-- @param #OPSGROUP self
|
||||
-- @return #boolean If true, group is retreated.
|
||||
function OPSGROUP:IsRetreated()
|
||||
local is=self:is("Retreated")
|
||||
return is
|
||||
end
|
||||
|
||||
|
||||
--- Check if the group is currently returning to a zone.
|
||||
-- @param #OPSGROUP self
|
||||
-- @return #boolean If true, group is returning.
|
||||
@ -2812,15 +2915,6 @@ function OPSGROUP:SetTask(DCSTask)
|
||||
|
||||
if self:IsAlive() then
|
||||
|
||||
if self.taskcurrent>0 then
|
||||
|
||||
-- TODO: Why the hell did I do this? It breaks scheduled tasks. I comment it out for now to see where it fails.
|
||||
--local task=self:GetTaskCurrent()
|
||||
--self:RemoveTask(task)
|
||||
--self.taskcurrent=0
|
||||
|
||||
end
|
||||
|
||||
-- Inject enroute tasks.
|
||||
if self.taskenroute and #self.taskenroute>0 then
|
||||
if tostring(DCSTask.id)=="ComboTask" then
|
||||
@ -2836,7 +2930,6 @@ function OPSGROUP:SetTask(DCSTask)
|
||||
end
|
||||
|
||||
-- Set task.
|
||||
--self.group:SetTask(DCSTask)
|
||||
self.controller:setTask(DCSTask)
|
||||
|
||||
-- Debug info.
|
||||
@ -2861,7 +2954,6 @@ function OPSGROUP:PushTask(DCSTask)
|
||||
if self:IsAlive() then
|
||||
|
||||
-- Push task.
|
||||
--self.group:PushTask(DCSTask)
|
||||
self.controller:pushTask(DCSTask)
|
||||
|
||||
-- Debug info.
|
||||
@ -3315,7 +3407,6 @@ function OPSGROUP:onafterTaskExecute(From, Event, To, Task)
|
||||
|
||||
-- Insert into task queue. Not sure any more, why I added this. But probably if a task is just executed without having been put into the queue.
|
||||
if self:GetTaskCurrent()==nil then
|
||||
--env.info("FF adding current task to queue")
|
||||
table.insert(self.taskqueue, Task)
|
||||
end
|
||||
|
||||
@ -3355,8 +3446,15 @@ function OPSGROUP:onafterTaskExecute(From, Event, To, Task)
|
||||
-- Parameters.
|
||||
local zone=Task.dcstask.params.zone --Core.Zone#ZONE
|
||||
|
||||
local surfacetypes=nil
|
||||
if self:IsArmygroup() then
|
||||
surfacetypes={land.SurfaceType.LAND, land.SurfaceType.ROAD}
|
||||
elseif self:IsNavygroup() then
|
||||
surfacetypes={land.SurfaceType.WATER, land.SurfaceType.SHALLOW_WATER}
|
||||
end
|
||||
|
||||
-- Random coordinate in zone.
|
||||
local Coordinate=zone:GetRandomCoordinate()
|
||||
local Coordinate=zone:GetRandomCoordinate(nil, nil, surfacetypes)
|
||||
|
||||
--Coordinate:MarkToAll("Random Patrol Zone Coordinate")
|
||||
|
||||
@ -3968,6 +4066,11 @@ function OPSGROUP:onafterMissionExecute(From, Event, To, Mission)
|
||||
|
||||
-- Set mission status to EXECUTING.
|
||||
Mission:Executing()
|
||||
|
||||
-- Set auto engage detected targets.
|
||||
if Mission.engagedetectedOn then
|
||||
self:SetEngageDetectedOn(UTILS.MetersToNM(Mission.engagedetectedRmax), Mission.engagedetectedTypes, Mission.engagedetectedEngageZones, Mission.engagedetectedNoEngageZones)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@ -4124,6 +4227,11 @@ function OPSGROUP:onafterMissionDone(From, Event, To, Mission)
|
||||
Mission.patroldata.noccupied=Mission.patroldata.noccupied-1
|
||||
AIRWING.UpdatePatrolPointMarker(Mission.patroldata)
|
||||
end
|
||||
|
||||
-- Switch auto engage detected off. This IGNORES that engage detected had been activated for the group!
|
||||
if Mission.engagedetectedOn then
|
||||
self:SetEngageDetectedOff()
|
||||
end
|
||||
|
||||
-- ROE to default.
|
||||
if Mission.optionROE then
|
||||
@ -4201,17 +4309,20 @@ function OPSGROUP:RouteToMission(mission, delay)
|
||||
|
||||
-- Catch dead or stopped groups.
|
||||
if self:IsDead() or self:IsStopped() then
|
||||
self:T(self.lid..string.format("Route To Mission: I am DEAD or STOPPED! Ooops..."))
|
||||
return
|
||||
end
|
||||
|
||||
-- OPSTRANSPORT: Just add the ops transport to the queue.
|
||||
if mission.type==AUFTRAG.Type.OPSTRANSPORT then
|
||||
self:T(self.lid..string.format("Route To Mission: I am OPSTRANSPORT! Add transport and return..."))
|
||||
self:AddOpsTransport(mission.opstransport)
|
||||
return
|
||||
end
|
||||
|
||||
-- ALERT 5: Just set the mission to executing.
|
||||
-- ALERT5: Just set the mission to executing.
|
||||
if mission.type==AUFTRAG.Type.ALERT5 then
|
||||
self:T(self.lid..string.format("Route To Mission: I am ALERT5! Go right to MissionExecute()..."))
|
||||
self:MissionExecute(mission)
|
||||
return
|
||||
end
|
||||
@ -4219,15 +4330,28 @@ function OPSGROUP:RouteToMission(mission, delay)
|
||||
-- ID of current waypoint.
|
||||
local uid=self:GetWaypointCurrent().uid
|
||||
|
||||
-- Random radius.
|
||||
-- Ingress waypoint coordinate where the mission is executed.
|
||||
local waypointcoord=nil --Core.Point#COORDINATE
|
||||
|
||||
-- Random radius of 1000 meters.
|
||||
local randomradius=1000
|
||||
|
||||
-- Surface types.
|
||||
local surfacetypes=nil
|
||||
if self:IsArmygroup() then
|
||||
surfacetypes={land.SurfaceType.LAND, land.SurfaceType.ROAD}
|
||||
elseif self:IsNavygroup() then
|
||||
surfacetypes={land.SurfaceType.WATER, land.SurfaceType.SHALLOW_WATER}
|
||||
end
|
||||
|
||||
-- Get ingress waypoint.
|
||||
if mission.type==AUFTRAG.Type.PATROLZONE then
|
||||
randomradius=nil
|
||||
local zone=mission.engageTarget:GetObject() --Core.Zone#ZONE
|
||||
waypointcoord=zone:GetRandomCoordinate(nil , nil, surfacetypes)
|
||||
else
|
||||
waypointcoord=mission:GetMissionWaypointCoord(self.group, randomradius, surfacetypes)
|
||||
end
|
||||
|
||||
-- Get coordinate where the mission is executed.
|
||||
local waypointcoord=mission:GetMissionWaypointCoord(self.group, randomradius)
|
||||
|
||||
-- Add enroute tasks.
|
||||
for _,task in pairs(mission.enrouteTasks) do
|
||||
self:AddTaskEnroute(task)
|
||||
@ -4532,9 +4656,17 @@ function OPSGROUP:onafterPassingWaypoint(From, Event, To, Waypoint)
|
||||
-- Zone object.
|
||||
local zone=task.dcstask.params.zone --Core.Zone#ZONE
|
||||
|
||||
-- Random coordinate in zone.
|
||||
local Coordinate=zone:GetRandomCoordinate()
|
||||
-- Surface types.
|
||||
local surfacetypes=nil
|
||||
if self:IsArmygroup() then
|
||||
surfacetypes={land.SurfaceType.LAND, land.SurfaceType.ROAD}
|
||||
elseif self:IsNavygroup() then
|
||||
surfacetypes={land.SurfaceType.WATER, land.SurfaceType.SHALLOW_WATER}
|
||||
end
|
||||
|
||||
-- Random coordinate in zone.
|
||||
local Coordinate=zone:GetRandomCoordinate(nil, nil, surfacetypes)
|
||||
|
||||
-- Speed and altitude.
|
||||
local Speed=UTILS.KmphToKnots(task.dcstask.params.speed or self.speedCruise)
|
||||
local Altitude=task.dcstask.params.altitude and UTILS.MetersToFeet(task.dcstask.params.altitude) or nil
|
||||
@ -7820,7 +7952,7 @@ end
|
||||
-- @param #OPSGROUP self
|
||||
function OPSGROUP:_CheckDetectedUnits()
|
||||
|
||||
if self.group and not self:IsDead() then
|
||||
if self.detectionOn and self.group and not self:IsDead() then
|
||||
|
||||
-- Get detected DCS units.
|
||||
local detectedtargets=self.group:GetDetectedTargets()
|
||||
@ -10636,6 +10768,87 @@ function OPSGROUP:ClearWaypoints(IndexMin, IndexMax)
|
||||
--self.waypoints={}
|
||||
end
|
||||
|
||||
--- Get target group.
|
||||
-- @param #OPSGROUP self
|
||||
-- @return Wrapper.Group#GROUP Detected target group.
|
||||
-- @return #number Distance to target.
|
||||
function OPSGROUP:_GetDetectedTarget()
|
||||
|
||||
-- Target.
|
||||
local targetgroup=nil --Wrapper.Group#GROUP
|
||||
local targetdist=math.huge
|
||||
|
||||
-- Loop over detected groups.
|
||||
for _,_group in pairs(self.detectedgroups:GetSet()) do
|
||||
local group=_group --Wrapper.Group#GROUP
|
||||
|
||||
if group and group:IsAlive() then
|
||||
|
||||
-- Get 3D vector of target.
|
||||
local targetVec3=group:GetVec3()
|
||||
|
||||
-- Distance to target.
|
||||
local distance=UTILS.VecDist3D(self.position, targetVec3)
|
||||
|
||||
if distance<=self.engagedetectedRmax and distance<targetdist then
|
||||
|
||||
-- Check type attribute.
|
||||
local righttype=false
|
||||
for _,attribute in pairs(self.engagedetectedTypes) do
|
||||
local gotit=group:HasAttribute(attribute, false)
|
||||
self:I(self.lid..string.format("Group %s has attribute %s = %s", group:GetName(), attribute, tostring(gotit)))
|
||||
if gotit then
|
||||
righttype=true
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
-- We got the right type.
|
||||
if righttype then
|
||||
|
||||
local insideEngage=true
|
||||
local insideNoEngage=false
|
||||
|
||||
-- Check engage zones.
|
||||
if self.engagedetectedEngageZones then
|
||||
insideEngage=false
|
||||
for _,_zone in pairs(self.engagedetectedEngageZones.Set) do
|
||||
local zone=_zone --Core.Zone#ZONE
|
||||
local inzone=zone:IsVec3InZone(targetVec3)
|
||||
if inzone then
|
||||
insideEngage=true
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Check no engage zones.
|
||||
if self.engagedetectedNoEngageZones then
|
||||
for _,_zone in pairs(self.engagedetectedNoEngageZones.Set) do
|
||||
local zone=_zone --Core.Zone#ZONE
|
||||
local inzone=zone:IsVec3InZone(targetVec3)
|
||||
if inzone then
|
||||
insideNoEngage=true
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- If inside engage but not inside no engage zones.
|
||||
if insideEngage and not insideNoEngage then
|
||||
targetdist=distance
|
||||
targetgroup=group
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return targetgroup, targetdist
|
||||
end
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
@ -16,6 +16,7 @@
|
||||
--- OPSZONE class.
|
||||
-- @type OPSZONE
|
||||
-- @field #string ClassName Name of the class.
|
||||
-- @field #string lid DCS log ID string.
|
||||
-- @field #number verbose Verbosity of output.
|
||||
-- @field Core.Zone#ZONE zone The zone.
|
||||
-- @field Wrapper.Airbase#AIRBASE airbase The airbase that is monitored.
|
||||
@ -34,6 +35,7 @@
|
||||
-- @field #number dTCapture Time interval in seconds until a zone is captured.
|
||||
-- @field #boolean neutralCanCapture Neutral units can capture. Default `false`.
|
||||
-- @field #boolean drawZone If `true`, draw the zone on the F10 map.
|
||||
-- @field #boolean markZone If `true`, mark the zone on the F10 map.
|
||||
-- @extends Core.Fsm#FSM
|
||||
|
||||
--- Be surprised!
|
||||
@ -132,8 +134,12 @@ function OPSZONE:New(Zone, CoalitionOwner)
|
||||
self:AddTransition("*", "Stop", "Stopped") -- Stop FSM.
|
||||
|
||||
self:AddTransition("*", "Captured", "Guarded") -- Zone was captured.
|
||||
|
||||
self:AddTransition("Empty", "Guarded", "Guarded") -- Owning coalition left the zone and returned.
|
||||
|
||||
self:AddTransition("*", "Empty", "Empty") -- No red or blue units inside the zone.
|
||||
|
||||
|
||||
self:AddTransition("*", "Attacked", "Attacked") -- A guarded zone is under attack.
|
||||
self:AddTransition("*", "Defeated", "Guarded") -- The owning coalition defeated an attack.
|
||||
|
||||
@ -180,6 +186,23 @@ function OPSZONE:New(Zone, CoalitionOwner)
|
||||
-- @param #number Coalition Coalition side that captured the zone.
|
||||
|
||||
|
||||
--- Triggers the FSM event "Guarded".
|
||||
-- @function [parent=#OPSZONE] Guarded
|
||||
-- @param #OPSZONE self
|
||||
|
||||
--- Triggers the FSM event "Guarded" after a delay.
|
||||
-- @function [parent=#OPSZONE] __Guarded
|
||||
-- @param #OPSZONE self
|
||||
-- @param #number delay Delay in seconds.
|
||||
|
||||
--- On after "Guarded" event.
|
||||
-- @function [parent=#OPSZONE] OnAfterGuarded
|
||||
-- @param #OPSZONE self
|
||||
-- @param #string From From state.
|
||||
-- @param #string Event Event.
|
||||
-- @param #string To To state.
|
||||
|
||||
|
||||
--- Triggers the FSM event "Empty".
|
||||
-- @function [parent=#OPSZONE] Empty
|
||||
-- @param #OPSZONE self
|
||||
@ -403,6 +426,18 @@ function OPSZONE:onafterStart(From, Event, To)
|
||||
-- Reinit the timer.
|
||||
self.timerStatus=self.timerStatus or TIMER:New(OPSZONE.Status, self)
|
||||
|
||||
-- Perform initial scan.
|
||||
self:Scan()
|
||||
|
||||
if self.Nblu==0 and self.Nred==0 then
|
||||
elseif self.Nblu>0 and self.Nred>0 then
|
||||
|
||||
elseif self.Nblu>0 then
|
||||
|
||||
elseif self.Nred>0 then
|
||||
|
||||
end
|
||||
|
||||
-- Status update.
|
||||
self.timerStatus:Start(1, 60)
|
||||
|
||||
@ -528,12 +563,12 @@ function OPSZONE:onenterGuarded(From, Event, To)
|
||||
|
||||
local color=self:_GetZoneColor()
|
||||
|
||||
self.zone:DrawZone(nil, color, 1.0, color, 0.7)
|
||||
self.zone:DrawZone(nil, color, 1.0, color, 0.5)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--- On enter "Guarded" state.
|
||||
--- On enter "Attacked" state.
|
||||
-- @param #OPSZONE self
|
||||
-- @param #string From From state.
|
||||
-- @param #string Event Event.
|
||||
@ -549,9 +584,10 @@ function OPSZONE:onenterAttacked(From, Event, To)
|
||||
if self.drawZone then
|
||||
self.zone:UndrawZone()
|
||||
|
||||
local color={1,1,1}
|
||||
|
||||
self.zone:DrawZone(nil, color, 1.0, color, 0.9)
|
||||
local color={1,204/255,204/255}
|
||||
|
||||
self.zone:DrawZone(nil, color, 1.0, color, 0.5)
|
||||
end
|
||||
|
||||
end
|
||||
@ -580,7 +616,7 @@ end
|
||||
-- Scan Functions
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
--- Add a platoon to the brigade.
|
||||
--- Scan zone.
|
||||
-- @param #OPSZONE self
|
||||
-- @return #OPSZONE self
|
||||
function OPSZONE:Scan()
|
||||
@ -720,7 +756,20 @@ function OPSZONE:Scan()
|
||||
self.Nred=Nred
|
||||
self.Nblu=Nblu
|
||||
self.Nnut=Nnut
|
||||
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Evaluate zone.
|
||||
-- @param #OPSZONE self
|
||||
-- @return #OPSZONE self
|
||||
function OPSZONE:EvaluateZone()
|
||||
|
||||
-- Set values.
|
||||
local Nred=self.Nred
|
||||
local Nblu=self.Nblu
|
||||
local Nnut=self.Nnut
|
||||
|
||||
if self:IsRed() then
|
||||
|
||||
---
|
||||
@ -746,7 +795,7 @@ function OPSZONE:Scan()
|
||||
|
||||
else
|
||||
|
||||
-- Still red units in red zone.
|
||||
-- Red units in red zone.
|
||||
|
||||
if Nblu>0 then
|
||||
|
||||
@ -758,6 +807,9 @@ function OPSZONE:Scan()
|
||||
|
||||
if self:IsAttacked() and self:IsContested() then
|
||||
self:Defeated(coalition.side.BLUE)
|
||||
elseif self:IsEmpty() then
|
||||
-- Red units left zone and returned (or from initial Empty state).
|
||||
self:Guarded()
|
||||
end
|
||||
|
||||
end
|
||||
@ -810,6 +862,9 @@ function OPSZONE:Scan()
|
||||
if self:IsAttacked() and self:IsContested() then
|
||||
-- Blue defeated read attack.
|
||||
self:Defeated(coalition.side.RED)
|
||||
elseif self:IsEmpty() then
|
||||
-- Blue units left zone and returned (or from initial Empty state).
|
||||
self:Guarded()
|
||||
end
|
||||
|
||||
end
|
||||
@ -858,7 +913,7 @@ function OPSZONE:Scan()
|
||||
self:E(self.lid.."ERROR!")
|
||||
end
|
||||
|
||||
return self
|
||||
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
@ -923,11 +978,11 @@ function OPSZONE:_GetZoneColor()
|
||||
local color={0,0,0}
|
||||
|
||||
if self.ownerCurrent==coalition.side.NEUTRAL then
|
||||
color={0, 1, 0}
|
||||
color={1, 1, 1}
|
||||
elseif self.ownerCurrent==coalition.side.BLUE then
|
||||
color={1, 0, 0}
|
||||
elseif self.ownerCurrent==coalition.side.RED then
|
||||
color={0, 0, 1}
|
||||
elseif self.ownerCurrent==coalition.side.RED then
|
||||
color={1, 0, 0}
|
||||
else
|
||||
|
||||
end
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user