Merge branch 'develop' into FF/Ops

This commit is contained in:
Frank
2022-10-18 22:33:07 +02:00
16 changed files with 1653 additions and 294 deletions

View File

@@ -422,6 +422,44 @@ function AIRWING:SetPayloadAmount(Payload, Navailable)
return self
end
--- Increase or decrease the amount of available payloads. Unlimited playloads first need to be set to a limited number with the `SetPayloadAmount` function.
-- @param #AIRWING self
-- @param #AIRWING.Payload Payload The payload table created by the `:NewPayload` function.
-- @param #number N Number of payloads to be added. Use negative number to decrease amount. Default 1.
-- @return #AIRWING self
function AIRWING:IncreasePayloadAmount(Payload, N)
N=N or 1
if Payload and Payload.navail>=0 then
-- Increase/decrease amount.
Payload.navail=Payload.navail+N
-- Ensure playload does not drop below 0.
Payload.navail=math.max(Payload.navail, 0)
end
return self
end
--- Get amount of payloads available for a given playload.
-- @param #AIRWING self
-- @param #AIRWING.Payload Payload The payload table created by the `:NewPayload` function.
-- @return #number Number of payloads available. Unlimited payloads will return -1.
function AIRWING:GetPayloadAmount(Payload)
return Payload.navail
end
--- Get capabilities of a given playload.
-- @param #AIRWING self
-- @param #AIRWING.Payload Payload The payload data table.
-- @return #table Capabilities.
function AIRWING:GetPayloadCapabilities(Payload)
return Payload.capabilities
end
--- Add a mission capability to an existing payload.
-- @param #AIRWING self
-- @param #AIRWING.Payload Payload The payload table to which the capability should be added.

View File

@@ -497,7 +497,7 @@ do
-- @field #AWACS
AWACS = {
ClassName = "AWACS", -- #string
version = "0.2.44", -- #string
version = "0.2.45", -- #string
lid = "", -- #string
coalition = coalition.side.BLUE, -- #number
coalitiontxt = "blue", -- #string
@@ -3515,7 +3515,7 @@ function AWACS:_CheckInAI(FlightGroup,Group,AuftragsNr)
text = string.format("%s. %s. %s. %s",managedgroup.CallSign,self.callsigntxt,alpha,alphacheckbulls)
self:__CheckedIn(1,managedgroup.GID)
local AW = FlightGroup:GetAirWing()
local AW = FlightGroup.legion
if AW.HasOwnStation then
self:__AssignAnchor(5,managedgroup.GID,AW.HasOwnStation,AW.StationName)
else

View File

@@ -30,7 +30,7 @@
-- @module Ops.CSAR
-- @image OPS_CSAR.jpg
-- Date: June 2022
-- Date: October 2022
-------------------------------------------------------------------------
--- **CSAR** class, extends Core.Base#BASE, Core.Fsm#FSM
@@ -270,7 +270,7 @@ CSAR.AircraftType["Bronco-OV-10A"] = 2
--- CSAR class version.
-- @field #string version
CSAR.version="1.0.11"
CSAR.version="1.0.15"
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- ToDo list
@@ -613,6 +613,19 @@ function CSAR:_DoubleEjection(_unitname)
return false
end
--- (User) Add a PLAYERTASK - FSM events will check success
-- @param #CSAR self
-- @param Ops.PlayerTask#PLAYERTASK PlayerTask
-- @return #CSAR self
function CSAR:AddPlayerTask(PlayerTask)
self:T(self.lid .. " AddPlayerTask")
if not self.PlayerTaskQueue then
self.PlayerTaskQueue = FIFO:New()
end
self.PlayerTaskQueue:Push(PlayerTask,PlayerTask.PlayerTaskNr)
return self
end
--- (Internal) Spawn a downed pilot
-- @param #CSAR self
-- @param #number country Country for template.
@@ -1197,6 +1210,38 @@ function CSAR:_RemoveNameFromDownedPilots(name,force)
return found
end
--- [User] Set callsign options for TTS output. See @{Wrapper.Group#GROUP.GetCustomCallSign}() on how to set customized callsigns.
-- @param #CSAR self
-- @param #boolean ShortCallsign If true, only call out the major flight number
-- @param #boolean Keepnumber If true, keep the **customized callsign** in the #GROUP name for players as-is, no amendments or numbers.
-- @param #table CallsignTranslations (optional) Table to translate between DCS standard callsigns and bespoke ones. Does not apply if using customized
-- callsigns from playername or group name.
-- @return #CSAR self
function CSAR:SetCallSignOptions(ShortCallsign,Keepnumber,CallsignTranslations)
if not ShortCallsign or ShortCallsign == false then
self.ShortCallsign = false
else
self.ShortCallsign = true
end
self.Keepnumber = Keepnumber or false
self.CallsignTranslations = CallsignTranslations
return self
end
--- (Internal) Check if a name is in downed pilot table and remove it.
-- @param #CSAR self
-- @param #string UnitName
-- @return #string CallSign
function CSAR:_GetCustomCallSign(UnitName)
local callsign = Unitname
local unit = UNIT:FindByName(UnitName)
if unit and unit:IsAlive() then
local group = unit:GetGroup()
callsign = group:GetCustomCallSign(self.ShortCallsign,self.Keepnumber,self.CallsignTranslations)
end
return callsign
end
--- (Internal) Check state of wounded group.
-- @param #CSAR self
-- @param #string heliname heliname
@@ -1253,9 +1298,9 @@ function CSAR:_CheckWoundedGroupStatus(heliname,woundedgroupname)
local dist = UTILS.MetersToNM(self.autosmokedistance)
disttext = string.format("%.0fnm",dist)
end
self:_DisplayMessageToSAR(_heliUnit, string.format("%s: %s. I hear you! Finally, that is music in my ears!\nI'll pop a smoke when you are %s away.\nLand or hover by the smoke.", _heliName, _pilotName, disttext), self.messageTime,false,true)
self:_DisplayMessageToSAR(_heliUnit, string.format("%s: %s. I hear you! Finally, that is music in my ears!\nI'll pop a smoke when you are %s away.\nLand or hover by the smoke.", self:_GetCustomCallSign(_heliName), _pilotName, disttext), self.messageTime,false,true)
else
self:_DisplayMessageToSAR(_heliUnit, string.format("%s: %s. I hear you! Finally, that is music in my ears!\nRequest a flare or smoke if you need.", _heliName, _pilotName), self.messageTime,false,true)
self:_DisplayMessageToSAR(_heliUnit, string.format("%s: %s. I hear you! Finally, that is music in my ears!\nRequest a flare or smoke if you need.", self:_GetCustomCallSign(_heliName), _pilotName), self.messageTime,false,true)
end
--mark as shown for THIS heli and THIS group
self.heliVisibleMessage[_lookupKeyHeli] = true
@@ -1319,7 +1364,7 @@ function CSAR:_PickupUnit(_heliUnit, _pilotName, _woundedGroup, _woundedGroupNam
_maxUnits = self.max_units
end
if _unitsInHelicopter + 1 > _maxUnits then
self:_DisplayMessageToSAR(_heliUnit, string.format("%s, %s. We\'re already crammed with %d guys! Sorry!", _pilotName, _heliName, _unitsInHelicopter, _unitsInHelicopter), self.messageTime,false,false,true)
self:_DisplayMessageToSAR(_heliUnit, string.format("%s, %s. We\'re already crammed with %d guys! Sorry!", _pilotName, self:_GetCustomCallSign(_heliName), _unitsInHelicopter, _unitsInHelicopter), self.messageTime,false,false,true)
return self
end
@@ -1337,13 +1382,29 @@ function CSAR:_PickupUnit(_heliUnit, _pilotName, _woundedGroup, _woundedGroupNam
_woundedGroup:Destroy(false)
self:_RemoveNameFromDownedPilots(_woundedGroupName,true)
self:_DisplayMessageToSAR(_heliUnit, string.format("%s: %s I\'m in! Get to the MASH ASAP! ", _heliName, _pilotName), self.messageTime,true,true)
self:_DisplayMessageToSAR(_heliUnit, string.format("%s: %s I\'m in! Get to the MASH ASAP! ", self:_GetCustomCallSign(_heliName), _pilotName), self.messageTime,true,true)
self:_UpdateUnitCargoMass(_heliName)
self:__Boarded(5,_heliName,_woundedGroupName,grouptable.desc)
return self
end
--- (Internal) Function to calculate and set Unit internal cargo mass
-- @param #CSAR self
-- @param #string _heliName Unit name
-- @return #CSAR self
function CSAR:_UpdateUnitCargoMass(_heliName)
self:T(self.lid .. " _UpdateUnitCargoMass")
local calculatedMass = self:_PilotsOnboard(_heliName)*80
local Unit = UNIT:FindByName(_heliName)
if Unit then
Unit:SetUnitInternalCargo(calculatedMass)
end
return self
end
--- (Internal) Move group to destination.
-- @param #CSAR self
-- @param Wrapper.Group#GROUP _leader
@@ -1358,7 +1419,6 @@ function CSAR:_OrderGroupToMoveToPoint(_leader, _destination)
return self
end
--- (internal) Function to check if the heli door(s) are open. Thanks to Shadowze.
-- @param #CSAR self
-- @param #string unit_name Name of unit.
@@ -1392,9 +1452,9 @@ function CSAR:_CheckCloseWoundedGroup(_distance, _heliUnit, _heliName, _woundedG
if self.heliCloseMessage[_lookupKeyHeli] == nil then
if self.autosmoke == true then
self:_DisplayMessageToSAR(_heliUnit, string.format("%s: %s. You\'re close now! Land or hover at the smoke.", _heliName, _pilotName), self.messageTime,false,true)
self:_DisplayMessageToSAR(_heliUnit, string.format("%s: %s. You\'re close now! Land or hover at the smoke.", self:_GetCustomCallSign(_heliName), _pilotName), self.messageTime,false,true)
else
self:_DisplayMessageToSAR(_heliUnit, string.format("%s: %s. You\'re close now! Land in a safe place, I will go there ", _heliName, _pilotName), self.messageTime,false,true)
self:_DisplayMessageToSAR(_heliUnit, string.format("%s: %s. You\'re close now! Land in a safe place, I will go there ", self:_GetCustomCallSign(_heliName), _pilotName), self.messageTime,false,true)
end
self.heliCloseMessage[_lookupKeyHeli] = true
end
@@ -1447,7 +1507,7 @@ function CSAR:_CheckCloseWoundedGroup(_distance, _heliUnit, _heliName, _woundedG
end
if _heliUnit:InAir() and _unitsInHelicopter + 1 <= _maxUnits then
-- TODO - make variable
-- DONE - make variable
if _distance < self.rescuehoverdistance then
--check height!
@@ -1455,7 +1515,7 @@ function CSAR:_CheckCloseWoundedGroup(_distance, _heliUnit, _heliName, _woundedG
if leaderheight < 0 then leaderheight = 0 end
local _height = _heliUnit:GetHeight() - leaderheight
-- TODO - make variable
-- DONE - make variable
if _height <= self.rescuehoverheight then
local _time = self.hoverStatus[_lookupKeyHeli]
@@ -1561,9 +1621,12 @@ function CSAR:_RescuePilots(_heliUnit)
self.inTransitGroups[_heliName] = nil
local _txt = string.format("%s: The %d pilot(s) have been taken to the\nmedical clinic. Good job!", _heliName, PilotsSaved)
local _txt = string.format("%s: The %d pilot(s) have been taken to the\nmedical clinic. Good job!", self:_GetCustomCallSign(_heliName), PilotsSaved)
self:_DisplayMessageToSAR(_heliUnit, _txt, self.messageTime)
self:_UpdateUnitCargoMass(_heliName)
-- trigger event
self:__Rescued(-1,_heliUnit,_heliName, PilotsSaved)
return self
@@ -1597,7 +1660,7 @@ function CSAR:_DisplayMessageToSAR(_unit, _text, _time, _clear, _speak, _overrid
local _clear = _clear or nil
local _time = _time or self.messageTime
if _override or not self.suppressmessages then
local m = MESSAGE:New(_text,_time,"Info",_clear):ToGroup(group)
local m = MESSAGE:New(_text,_time,"CSAR",_clear):ToGroup(group)
end
-- integrate SRS
if _speak and self.useSRS then
@@ -1746,7 +1809,7 @@ function CSAR:_SignalFlare(_unitName)
else
_distance = string.format("%.1fkm",_closest.distance)
end
local _msg = string.format("%s - Popping signal flare at your %s o\'clock. Distance %s", _unitName, _clockDir, _distance)
local _msg = string.format("%s - Popping signal flare at your %s o\'clock. Distance %s", self:_GetCustomCallSign(_unitName), _clockDir, _distance)
self:_DisplayMessageToSAR(_heli, _msg, self.messageTime, false, true, true)
local _coord = _closest.pilot:GetCoordinate()
@@ -1800,7 +1863,7 @@ function CSAR:_Reqsmoke( _unitName )
else
_distance = string.format("%.1fkm",_closest.distance/1000)
end
local _msg = string.format("%s - Popping smoke at your %s o\'clock. Distance %s", _unitName, _clockDir, _distance)
local _msg = string.format("%s - Popping smoke at your %s o\'clock. Distance %s", self:_GetCustomCallSign(_unitName), _clockDir, _distance)
self:_DisplayMessageToSAR(_heli, _msg, self.messageTime, false, true, true)
local _coord = _closest.pilot:GetCoordinate()
local color = self.smokecolor
@@ -1851,7 +1914,7 @@ function CSAR:_GetClosestMASH(_heli)
if self.allowFARPRescue then
local position = _heli:GetCoordinate()
local afb,distance = position:GetClosestAirbase2(nil,self.coalition)
local afb,distance = position:GetClosestAirbase(nil,self.coalition)
_shortestDistance = distance
end
@@ -2004,13 +2067,17 @@ function CSAR:_GetClockDirection(_heli, _group)
local DirectionVec3 = _playerPosition:GetDirectionVec3( _targetpostions )
local Angle = _playerPosition:GetAngleDegrees( DirectionVec3 )
self:T(self.lid .. " _GetClockDirection"..tostring(Angle).." "..tostring(_heading))
local clock = 12
if _heading then
local Aspect = Angle - _heading
if Aspect == 0 then Aspect = 360 end
clock = math.abs(UTILS.Round((Aspect / 30),0))
if clock == 0 then clock = 12 end
end
local hours = 0
local clock = 12
if _heading and Angle then
clock = 12
--if angle == 0 then angle = 360 end
clock = _heading-Angle
hours = (clock/30)*-1
clock = 12+hours
clock = UTILS.Round(clock,0)
if clock > 12 then clock = clock-12 end
end
return clock
end
@@ -2282,6 +2349,29 @@ end
function CSAR:onbeforeBoarded(From, Event, To, Heliname, Woundedgroupname)
self:T({From, Event, To, Heliname, Woundedgroupname})
self:_ScheduledSARFlight(Heliname,Woundedgroupname)
local Unit = UNIT:FindByName(Heliname)
if Unit and Unit:IsPlayer() and self.PlayerTaskQueue then
local playername = Unit:GetPlayerName()
local dropcoord = Unit:GetCoordinate() or COORDINATE:New(0,0,0)
local dropvec2 = dropcoord:GetVec2()
self.PlayerTaskQueue:ForEach(
function (Task)
local task = Task -- Ops.PlayerTask#PLAYERTASK
local subtype = task:GetSubType()
-- right subtype?
if Event == subtype and not task:IsDone() then
local targetzone = task.Target:GetObject() -- Core.Zone#ZONE should be a zone in this case ....
if (targetzone and targetzone.ClassName and string.match(targetzone.ClassName,"ZONE") and targetzone:IsVec2InZone(dropvec2))
or (string.find(task.CSARPilotName,Woundedgroupname)) then
if task.Clients:HasUniqueID(playername) then
-- success
task:__Success(-1)
end
end
end
end
)
end
return self
end
@@ -2311,6 +2401,23 @@ function CSAR:onbeforeRescued(From, Event, To, HeliUnit, HeliName, PilotsSaved)
self:T({From, Event, To, HeliName, HeliUnit})
self.rescues = self.rescues + 1
self.rescuedpilots = self.rescuedpilots + PilotsSaved
local Unit = HeliUnit or UNIT:FindByName(HeliName)
if Unit and Unit:IsPlayer() and self.PlayerTaskQueue then
local playername = Unit:GetPlayerName()
self.PlayerTaskQueue:ForEach(
function (Task)
local task = Task -- Ops.PlayerTask#PLAYERTASK
local subtype = task:GetSubType()
-- right subtype?
if Event == subtype and not task:IsDone() then
if task.Clients:HasUniqueID(playername) then
-- success
task:__Success(-1)
end
end
end
)
end
return self
end

View File

@@ -22,8 +22,7 @@
-- @module Ops.CTLD
-- @image OPS_CTLD.jpg
-- Date: Feb 2022
-- Last Update Sep 2022
-- Last Update October 2022
do
@@ -288,8 +287,8 @@ CTLD_ENGINEERING = {
end
do
do
------------------------------------------------------
--- **CTLD_CARGO** class, extends Core.Base#BASE
-- @type CTLD_CARGO
@@ -308,9 +307,8 @@ do
-- @field #string Subcategory Sub-category name.
-- @extends Core.Base#BASE
---
-- @field CTLD_CARGO
-- @field #CTLD_CARGO CTLD_CARGO
CTLD_CARGO = {
ClassName = "CTLD_CARGO",
ID = 0,
@@ -343,7 +341,7 @@ CTLD_CARGO = {
CRATE = "Crate", -- #string crate
REPAIR = "Repair", -- #string repair
ENGINEERS = "Engineers", -- #string engineers
STATIC = "Static", -- #string engineers
STATIC = "Static", -- #string statics
}
--- Function to create new CTLD_CARGO object.
@@ -574,6 +572,10 @@ CTLD_CARGO = {
end
do
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO CTLD
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------
--- **CTLD** class, extends Core.Base#BASE, Core.Fsm#FSM
-- @type CTLD
@@ -824,6 +826,8 @@ do
--
-- To award player with points, using the SCORING Class (SCORING: my_Scoring, CTLD: CTLD_Cargotransport)
--
-- my_scoring = SCORING:New("Combat Transport")
--
-- function CTLD_Cargotransport:OnAfterCratesDropped(From, Event, To, Group, Unit, Cargotable)
-- local points = 10
-- if Unit then
@@ -901,7 +905,7 @@ do
--
-- my_ctld.useprefix = true -- this is true by default and MUST BE ON.
--
-- ### 5.2 Integrate Hercules ground crew (F8 Menu) loadable objects (alternative method)
-- ### 5.2 Integrate Hercules ground crew (F8 Menu) loadable objects (alternative method, use either the above OR this method, NOT both!)
--
-- Integrate to your CTLD instance like so, where `my_ctld` is a previously created CTLD instance:
--
@@ -928,6 +932,8 @@ do
-- The script works on the EVENTS.Shot trigger, which is used by the mod when you **drop cargo from the Hercules while flying**. Unloading on the ground does
-- not achieve anything here. If you just want to unload on the ground, use the normal Moose CTLD (see 5.1).
--
-- DO NOT use the "splash damage" script together with this method! Your cargo will explode on the ground!
--
-- There are two ways of airdropping:
--
-- 1) Very low and very slow (>5m and <10m AGL) - here you can drop stuff which has "Skid" at the end of the cargo name (loaded via F8 Ground Crew menu)
@@ -1068,7 +1074,7 @@ CTLD.UnitTypes = {
--- CTLD class version.
-- @field #string version
CTLD.version="1.0.11"
CTLD.version="1.0.16"
--- Instantiate a new CTLD.
-- @param #CTLD self
@@ -1476,6 +1482,19 @@ function CTLD:SetTroopDropZoneRadius(Radius)
return self
end
--- (User) Add a PLAYERTASK - FSM events will check success
-- @param #CTLD self
-- @param Ops.PlayerTask#PLAYERTASK PlayerTask
-- @return #CTLD self
function CTLD:AddPlayerTask(PlayerTask)
self:T(self.lid .. " AddPlayerTask")
if not self.PlayerTaskQueue then
self.PlayerTaskQueue = FIFO:New()
end
self.PlayerTaskQueue:Push(PlayerTask,PlayerTask.PlayerTaskNr)
return self
end
--- (Internal) Event handler function
-- @param #CTLD self
-- @param Core.Event#EVENTDATA EventData
@@ -3386,7 +3405,13 @@ end
-- @return #CTLD self
function CTLD:AddCTLDZone(Name, Type, Color, Active, HasBeacon, Shiplength, Shipwidth)
self:T(self.lid .. " AddCTLDZone")
local zone = ZONE:FindByName(Name)
if not zone then
self:E(self.lid.."**** Zone does not exist: "..Name)
return self
end
local ctldzone = {} -- #CTLD.CargoZone
ctldzone.active = Active or false
ctldzone.color = Color or SMOKECOLOR.Red
@@ -3632,9 +3657,10 @@ function CTLD:IsUnitInZone(Unit,Zonetype)
local zoneret = nil
local zonewret = nil
local zonenameret = nil
local unitcoord = Unit:GetCoordinate()
local unitVec2 = unitcoord:GetVec2()
for _,_cargozone in pairs(zonetable) do
local czone = _cargozone -- #CTLD.CargoZone
local unitcoord = Unit:GetCoordinate()
local zonename = czone.name
local active = czone.active
local color = czone.color
@@ -3651,17 +3677,17 @@ function CTLD:IsUnitInZone(Unit,Zonetype)
zone = ZONE:FindByName(zonename)
self:T("Checking Zone: "..zonename)
zonecoord = zone:GetCoordinate()
zoneradius = zone:GetRadius()
zoneradius = 1500
zonewidth = zoneradius
elseif AIRBASE:FindByName(zonename) then
zone = AIRBASE:FindByName(zonename):GetZone()
self:T("Checking Zone: "..zonename)
zonecoord = zone:GetCoordinate()
zoneradius = zone:GetRadius()
zoneradius = 2500
zonewidth = zoneradius
end
local distance = self:_GetDistance(zonecoord,unitcoord)
if distance <= zoneradius and active then
if zone:IsVec2InZone(unitVec2) and active then
outcome = true
end
if maxdist > distance then
@@ -4244,7 +4270,7 @@ end
end
-------------------------------------------------------------------
-- FSM functions
-- TODO FSM functions
-------------------------------------------------------------------
--- (Internal) FSM Function onafterStart.
@@ -4417,6 +4443,27 @@ end
-- @return #CTLD self
function CTLD:onbeforeTroopsDeployed(From, Event, To, Group, Unit, Troops)
self:T({From, Event, To})
if Unit and Unit:IsPlayer() and self.PlayerTaskQueue then
local playername = Unit:GetPlayerName()
local dropcoord = Troops:GetCoordinate() or COORDINATE:New(0,0,0)
local dropvec2 = dropcoord:GetVec2()
self.PlayerTaskQueue:ForEach(
function (Task)
local task = Task -- Ops.PlayerTask#PLAYERTASK
local subtype = task:GetSubType()
-- right subtype?
if Event == subtype and not task:IsDone() then
local targetzone = task.Target:GetObject() -- Core.Zone#ZONE should be a zone in this case ....
if targetzone and targetzone.ClassName and string.match(targetzone.ClassName,"ZONE") and targetzone:IsVec2InZone(dropvec2) then
if task.Clients:HasUniqueID(playername) then
-- success
task:__Success(-1)
end
end
end
end
)
end
return self
end
@@ -4444,10 +4491,31 @@ end
-- @param Wrapper.Group#GROUP Vehicle The #GROUP object of the vehicle or FOB build.
-- @return #CTLD self
function CTLD:onbeforeCratesBuild(From, Event, To, Group, Unit, Vehicle)
self:T({From, Event, To})
self:I({From, Event, To})
if Unit and Unit:IsPlayer() and self.PlayerTaskQueue then
local playername = Unit:GetPlayerName()
local dropcoord = Vehicle:GetCoordinate() or COORDINATE:New(0,0,0)
local dropvec2 = dropcoord:GetVec2()
self.PlayerTaskQueue:ForEach(
function (Task)
local task = Task -- Ops.PlayerTask#PLAYERTASK
local subtype = task:GetSubType()
-- right subtype?
if Event == subtype and not task:IsDone() then
local targetzone = task.Target:GetObject() -- Core.Zone#ZONE should be a zone in this case ....
if targetzone and targetzone.ClassName and string.match(targetzone.ClassName,"ZONE") and targetzone:IsVec2InZone(dropvec2) then
if task.Clients:HasUniqueID(playername) then
-- success
task:__Success(-1)
end
end
end
end
)
end
return self
end
--- (Internal) FSM Function onbeforeTroopsRTB.
-- @param #CTLD self
-- @param #string From State.
@@ -4802,7 +4870,9 @@ end -- end do
do
--- **Hercules Cargo AIR Drop Events** by Anubis Yinepu
-- Moose CTLD OO refactoring by Applevangelist
--
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO CTLD_HERCULES
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- This script will only work for the Herculus mod by Anubis, and only for **Air Dropping** cargo from the Hercules.
-- Use the standard Moose CTLD if you want to unload on the ground.
-- Payloads carried by pylons 11, 12 and 13 need to be declared in the Herculus_Loadout.lua file
@@ -4932,13 +5002,21 @@ CTLD_HERCULES.Types = {
--
-- Expected template names are the ones in the rounded brackets.
--
-- HINTS
-- ### HINTS
--
-- The script works on the EVENTS.Shot trigger, which is used by the mod when you **drop cargo from the Hercules while flying**. Unloading on the ground does
-- not achieve anything here. If you just want to unload on the ground, use the normal Moose CTLD.
-- **Do not use** the **splash damage** script together with this, your cargo will just explode when reaching the ground!
--
-- ### Airdrops
--
-- There are two ways of airdropping:
-- 1) Very low and very slow (>5m and <10m AGL) - here you can drop stuff which has "Skid" at the end of the cargo name (loaded via F8 Ground Crew menu)
-- 2) Higher up and slow (>100m AGL) - here you can drop paratroopers and cargo which has "Air" at the end of the cargo name (loaded via F8 Ground Crew menu)
--
-- ### General
--
-- Use either this method to integrate the Hercules **or** the one from the "normal" CTLD. Never both!
function CTLD_HERCULES:New(Coalition, Alias, CtldObject)
-- Inherit everything from FSM class.
local self=BASE:Inherit(self, FSM:New()) -- #CTLD_HERCULES

View File

@@ -210,7 +210,7 @@ FLIGHTGROUP.Players={}
--- FLIGHTGROUP class version.
-- @field #string version
FLIGHTGROUP.version="0.8.0"
FLIGHTGROUP.version="0.8.1"
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO list
@@ -372,11 +372,34 @@ end
--- Get airwing the flight group belongs to.
-- @param #FLIGHTGROUP self
-- @return Ops.AirWing#AIRWING The AIRWING object.
function FLIGHTGROUP:GetAirWing()
-- @return Ops.AirWing#AIRWING The AIRWING object (if any).
function FLIGHTGROUP:GetAirwing()
return self.legion
end
--- Get name of airwing the flight group belongs to.
-- @param #FLIGHTGROUP self
-- @return #string Name of the airwing or "None" if the flightgroup does not belong to any airwing.
function FLIGHTGROUP:GetAirwingName()
local name=self.legion and self.legion.alias or "None"
return name
end
--- Get squadron the flight group belongs to.
-- @param #FLIGHTGROUP self
-- @return Ops.Squadron#SQUADRON The SQUADRON of this flightgroup or #nil if the flightgroup does not belong to any squadron.
function FLIGHTGROUP:GetSquadron()
return self.cohort
end
--- Get squadron name the flight group belongs to.
-- @param #FLIGHTGROUP self
-- @return #string The squadron name or "None" if the flightgroup does not belon to any squadron.
function FLIGHTGROUP:GetSquadronName()
local name=self.cohort and self.cohort:GetName() or "None"
return name
end
--- Set if aircraft is VTOL capable. Unfortunately, there is no DCS way to determine this via scripting.
-- @param #FLIGHTGROUP self
-- @return #FLIGHTGROUP self
@@ -836,6 +859,7 @@ end
function FLIGHTGROUP:GetKills()
return self.Nkills
end
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Status
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
@@ -1935,7 +1959,7 @@ function FLIGHTGROUP:onafterArrived(From, Event, To)
end
--TODO: Check that current base is airwing base.
local airwing=self:GetAirWing() --airwing:GetAirbaseName()==self.currbase:GetName()
local airwing=self:GetAirwing() --airwing:GetAirbaseName()==self.currbase:GetName()
-- Check what to do.
if airwing and not (self:IsPickingup() or self:IsTransporting()) then

View File

@@ -1854,7 +1854,7 @@ end
--- Count total number of assets of the legion.
-- @param #LEGION self
-- @param #boolean InStock If true, only assets that are in the warehouse stock/inventory are counted.
-- @param #boolean InStock If `true`, only assets that are in the warehouse stock/inventory are counted.
-- @param #table MissionTypes (Optional) Count only assest that can perform certain mission type(s). Default is all types.
-- @param #table Attributes (Optional) Count only assest that have a certain attribute(s), e.g. `WAREHOUSE.Attribute.AIR_BOMBER`.
-- @return #number Amount of asset groups in stock.

File diff suppressed because it is too large Load Diff

View File

@@ -1,11 +1,11 @@
--- **Ops** - PlayerTask (mission) for Players.
---- **Ops** - PlayerTask (mission) for Players.
--
-- ## Main Features:
--
-- * Simplifies defining and executing Player tasks
-- * FSM events when a mission is added, done, successful or failed, replanned
-- * Ready to use SRS and localization
-- * Mission locations can be smoked, flared and marked on the map
-- * Mission locations can be smoked, flared, illuminated and marked on the map
--
-- ===
--
@@ -21,7 +21,7 @@
-- ===
-- @module Ops.PlayerTask
-- @image OPS_PlayerTask.jpg
-- @date Last Update September 2022
-- @date Last Update October 2022
do
@@ -50,6 +50,13 @@ do
-- @field Ops.PlayerTask#PLAYERTASKCONTROLLER TaskController
-- @field #number timestamp
-- @field #number lastsmoketime
-- @field #number coalition
-- @field #string Freetext
-- @field #string FreetextTTS
-- @field #string TaskSubType
-- @field #table NextTaskSuccess
-- @field #table NextTaskFailure
-- @field #string FinalState
-- @extends Core.Fsm#FSM
@@ -78,11 +85,17 @@ PLAYERTASK = {
TaskController = nil,
timestamp = 0,
lastsmoketime = 0,
Freetext = nil,
FreetextTTS = nil,
TaskSubType = nil,
NextTaskSuccess = {},
NextTaskFailure = {},
FinalState = "none",
}
--- PLAYERTASK class version.
-- @field #string version
PLAYERTASK.version="0.1.3"
PLAYERTASK.version="0.1.9"
--- Generic task condition.
-- @type PLAYERTASK.Condition
@@ -95,6 +108,7 @@ PLAYERTASK.version="0.1.3"
-- @param Ops.Target#TARGET Target Target for this task
-- @param #boolean Repeat Repeat this task if true (default = false)
-- @param #number Times Repeat on failure this many times if Repeat is true (default = 1)
-- @param #string TTSType TTS friendly task type name
-- @return #PLAYERTASK self
function PLAYERTASK:New(Type, Target, Repeat, Times, TTSType)
@@ -252,6 +266,124 @@ function PLAYERTASK:_SetController(Controller)
return self
end
--- [User] Set a coalition side for this task
-- @param #PLAYERTASK self
-- @param #number Coalition Coaltion side to add, e.g. coalition.side.BLUE
-- @return #PLAYERTASK self
function PLAYERTASK:SetCoalition(Coalition)
self:T(self.lid.."SetCoalition")
self.coalition = Coalition or coalition.side.BLUE
return self
end
--- [User] Get the coalition side for this task
-- @param #PLAYERTASK self
-- @return #number Coalition Coaltion side, e.g. coalition.side.BLUE, or nil if not set
function PLAYERTASK:GetCoalition()
self:T(self.lid.."GetCoalition")
return self.coalition
end
--- [USER] Add a free text description to this task.
-- @param #PLAYERTASK self
-- @param #string Text
-- @return #PLAYERTASK self
function PLAYERTASK:AddFreetext(Text)
self:T(self.lid.."AddFreetext")
self.Freetext = Text
return self
end
--- [USER] Query if a task has free text description.
-- @param #PLAYERTASK self
-- @return #PLAYERTASK self
function PLAYERTASK:HasFreetext()
self:T(self.lid.."HasFreetext")
return self.Freetext ~= nil and true or false
end
--- [USER] Query if a task has free text TTS description.
-- @param #PLAYERTASK self
-- @return #PLAYERTASK self
function PLAYERTASK:HasFreetextTTS()
self:T(self.lid.."HasFreetextTTS")
return self.FreetextTTS ~= nil and true or false
end
--- [USER] Set a task sub type description to this task.
-- @param #PLAYERTASK self
-- @param #string Type
-- @return #PLAYERTASK self
function PLAYERTASK:SetSubType(Type)
self:T(self.lid.."AddSubType")
self.TaskSubType = Type
return self
end
--- [USER] Get task sub type description from this task.
-- @param #PLAYERTASK self
-- @return #string Type or nil
function PLAYERTASK:GetSubType()
self:T(self.lid.."GetSubType")
return self.TaskSubType
end
--- [USER] Get the free text description from this task.
-- @param #PLAYERTASK self
-- @return #string Text
function PLAYERTASK:GetFreetext()
self:T(self.lid.."GetFreetext")
return self.Freetext or self.FreetextTTS or "No Details"
end
--- [USER] Add a free text description for TTS to this task.
-- @param #PLAYERTASK self
-- @param #string TextTTS
-- @return #PLAYERTASK self
function PLAYERTASK:AddFreetextTTS(TextTTS)
self:T(self.lid.."AddFreetextTTS")
self.FreetextTTS = TextTTS
return self
end
--- [USER] Get the free text TTS description from this task.
-- @param #PLAYERTASK self
-- @return #string Text
function PLAYERTASK:GetFreetextTTS()
self:T(self.lid.."GetFreetextTTS")
return self.FreetextTTS or self.Freetext or "No Details"
end
--- [USER] Add a short free text description for the menu entry of this task.
-- @param #PLAYERTASK self
-- @param #string Text
-- @return #PLAYERTASK self
function PLAYERTASK:SetMenuName(Text)
self:T(self.lid.."SetMenuName")
self.Target.name = Text
return self
end
--- [USER] Add a task to be assigned to same clients when task was a success.
-- @param #PLAYERTASK self
-- @param Ops.PlayerTask#PLAYERTASK Task
-- @return #PLAYERTASK self
function PLAYERTASK:AddNextTaskAfterSuccess(Task)
self:T(self.lid.."AddNextTaskAfterSuccess")
table.insert(self.NextTaskSuccess,Task)
return self
end
--- [USER] Add a task to be assigned to same clients when task was a failure.
-- @param #PLAYERTASK self
-- @param Ops.PlayerTask#PLAYERTASK Task
-- @return #PLAYERTASK self
function PLAYERTASK:AddNextTaskAfterFailure(Task)
self:T(self.lid.."AddNextTaskAfterFailure")
table.insert(self.NextTaskFailure,Task)
return self
end
--- [User] Check if task is done
-- @param #PLAYERTASK self
-- @return #boolean done
@@ -398,7 +530,7 @@ function PLAYERTASK:SmokeTarget(Color)
if not self.lastsmoketime then self.lastsmoketime = 0 end
local TDiff = timer.getAbsTime() - self.lastsmoketime
if self.Target and TDiff > 299 then
local coordinate = self.Target:GetCoordinate()
local coordinate = self.Target:GetAverageCoordinate()
if coordinate then
coordinate:Smoke(color)
self.lastsmoketime = timer.getAbsTime()
@@ -415,7 +547,7 @@ function PLAYERTASK:FlareTarget(Color)
self:T(self.lid.."SmokeTarget")
local color = Color or FLARECOLOR.Red
if self.Target then
local coordinate = self.Target:GetCoordinate()
local coordinate = self.Target:GetAverageCoordinate()
if coordinate then
coordinate:Flare(color,0)
end
@@ -423,6 +555,25 @@ function PLAYERTASK:FlareTarget(Color)
return self
end
--- [User] Illuminate Target Area
-- @param #PLAYERTASK self
-- @param #number Power Power of illumination bomb in Candela. Default 1000 cd.
-- @param #number Height Height above target used to release the bomb, default 150m.
-- @return #PLAYERTASK self
function PLAYERTASK:IlluminateTarget(Power,Height)
self:T(self.lid.."IlluminateTarget")
local Power = Power or 1000
local Height = Height or 150
if self.Target then
local coordinate = self.Target:GetAverageCoordinate()
if coordinate then
local bcoord = COORDINATE:NewFromVec2( coordinate:GetVec2(), Height )
bcoord:IlluminationBomb(Power)
end
end
return self
end
-- success / failure function addion courtesy @FunkyFranky.
--- [User] Add success condition.
@@ -650,6 +801,7 @@ function PLAYERTASK:onafterCancel(From, Event, To)
self.TaskController:__TaskCancelled(-1,self)
end
self.timestamp = timer.getAbsTime()
self.FinalState = "Cancel"
self:__Done(-1)
return self
end
@@ -669,6 +821,7 @@ function PLAYERTASK:onafterSuccess(From, Event, To)
self.TargetMarker:Remove()
end
self.timestamp = timer.getAbsTime()
self.FinalState = "Success"
self:__Done(-1)
return self
end
@@ -693,9 +846,7 @@ function PLAYERTASK:onafterFailed(From, Event, To)
if self.TargetMarker then
self.TargetMarker:Remove()
end
if self.TaskController then
self.TaskController:__TaskFailed(-1,self)
end
self.FinalState = "Failed"
self:__Done(-1)
end
self.timestamp = timer.getAbsTime()
@@ -715,6 +866,8 @@ do
-- DONE Flash directions
-- DONE less rebuilds menu, Task info menu available after join
-- DONE Limit menu entries
-- DONE Integrated basic CTLD tasks
-- DONE Integrate basic CSAR tasks
-------------------------------------------------------------------------------------------------------------------
--- PLAYERTASKCONTROLLER class.
@@ -762,6 +915,9 @@ do
-- @field #table PlayerInfoMenu
-- @field #boolean noflaresmokemenu
-- @field #boolean TransmitOnlyWithPlayers
-- @field #boolean buddylasing
-- @field Ops.PlayerRecce#PLAYERRECCE PlayerRecce
-- @field #number Coalition
-- @extends Core.Fsm#FSM
---
@@ -788,7 +944,7 @@ do
--
-- ## 2 Task Types
--
-- Targets can be of types GROUP, SET\_GROUP, UNIT, SET\_UNIT, STATIC, SET\_STATIC, AIRBASE, ZONE or COORDINATE. The system will auto-create tasks for players from these targets.
-- Targets can be of types GROUP, SET\_GROUP, UNIT, SET\_UNIT, STATIC, SET\_STATIC, SET\_SCENERY, AIRBASE, ZONE or COORDINATE. The system will auto-create tasks for players from these targets.
-- Tasks are created as @{Ops.PlayerTask#PLAYERTASK} objects, which leverage @{Ops.Target#TARGET} for the management of the actual target. The system creates these task types
-- from the target objects:
--
@@ -808,6 +964,8 @@ do
-- * ZONE and COORDINATE - Targets will be scanned for GROUND or STATIC enemy units and tasks created from these
-- * Intercept - Any airborne targets, if the controller is of type "A2A"
-- * Anti-Ship - Any ship targets, if the controller is of type "A2S"
-- * CTLD - Combat transport and logistics deployment
-- * CSAR - Combat search and rescue
--
-- ## 3 Task repetition
--
@@ -937,11 +1095,14 @@ do
-- NONE = "None",
-- POINTEROVERTARGET = "%s, %s, pointer in reach for task %03d, lasing!",
-- POINTERTARGETREPORT = "\nPointer in reach: %s\nLasing: %s",
-- RECCETARGETREPORT = "\nRecce %s in reach: %s\nLasing: %s",
-- POINTERTARGETLASINGTTS = ". Pointer in reach and lasing.",
-- TARGET = "Target",
-- FLASHON = "%s - Flashing directions is now ON!",
-- FLASHOFF = "%s - Flashing directions is now OFF!",
-- FLASHMENU = "Flash Directions Switch",
-- BRIEFING = "Briefing",
-- TARGETLOCATION ="Target location",
-- },
--
-- e.g.
@@ -1065,6 +1226,9 @@ PLAYERTASKCONTROLLER = {
PlayerInfoMenu = {},
noflaresmokemenu = false,
TransmitOnlyWithPlayers = true,
buddylasing = false,
PlayerRecce = nil,
Coalition = nil,
}
---
@@ -1080,8 +1244,10 @@ PLAYERTASKCONTROLLER.Type = {
A2GS = "Air-To-Ground-Sea",
}
--- Define a new AUFTRAG Type
--- Define new AUFTRAG Types
AUFTRAG.Type.PRECISIONBOMBING = "Precision Bombing"
AUFTRAG.Type.CTLD = "Combat Transport"
AUFTRAG.Type.CSAR = "Combat Rescue"
---
-- @type SeadAttributes
@@ -1152,11 +1318,14 @@ PLAYERTASKCONTROLLER.Messages = {
NONE = "None",
POINTEROVERTARGET = "%s, %s, pointer in reach for task %03d, lasing!",
POINTERTARGETREPORT = "\nPointer in reach: %s\nLasing: %s",
RECCETARGETREPORT = "\nRecce %s in reach: %s\nLasing: %s",
POINTERTARGETLASINGTTS = ". Pointer in reach and lasing.",
TARGET = "Target",
FLASHON = "%s - Flashing directions is now ON!",
FLASHOFF = "%s - Flashing directions is now OFF!",
FLASHMENU = "Flash Directions Switch",
BRIEFING = "Briefing",
TARGETLOCATION ="Target location",
},
DE = {
TASKABORT = "Auftrag abgebrochen!",
@@ -1213,19 +1382,22 @@ PLAYERTASKCONTROLLER.Messages = {
NONE = "Keine",
POINTEROVERTARGET = "%s, %s, Marker im Zielbereich für %03d, Laser an!",
POINTERTARGETREPORT = "\nMarker im Zielbereich: %s\nLaser an: %s",
RECCETARGETREPORT = "\nSpäher % im Zielbereich: %s\nLasing: %s",
POINTERTARGETLASINGTTS = ". Marker im Zielbereich, Laser is an.",
TARGET = "Ziel",
FLASHON = "%s - Richtungsangaben einblenden ist EIN!",
FLASHOFF = "%s - Richtungsangaben einblenden ist AUS!",
FLASHMENU = "Richtungsangaben Schalter",
BRIEFING = "Briefing",
TARGETLOCATION ="Zielkoordinate",
},
}
--- PLAYERTASK class version.
-- @field #string version
PLAYERTASKCONTROLLER.version="0.1.38"
PLAYERTASKCONTROLLER.version="0.1.43"
--- Constructor
--- Create and run a new TASKCONTROLLER instance.
-- @param #PLAYERTASKCONTROLLER self
-- @param #string Name Name of this controller
-- @param #number Coalition of this controller, e.g. coalition.side.BLUE
@@ -1303,9 +1475,9 @@ function PLAYERTASKCONTROLLER:New(Name, Coalition, Type, ClientFilter)
self:AddTransition("*", "TaskRepeatOnFailed", "*")
self:AddTransition("*", "Stop", "Stopped")
self:__Start(-1)
self:__Start(2)
local starttime = math.random(5,10)
self:__Status(-starttime)
self:__Status(starttime)
-- Player leaves
self:HandleEvent(EVENTS.PlayerLeaveUnit, self._EventHandler)
@@ -1454,12 +1626,13 @@ end
-- @param #string text Original text.
-- @return #string Spoken text.
function PLAYERTASKCONTROLLER:_GetTextForSpeech(text)
self:T(self.lid.."_GetTextForSpeech")
-- Space out numbers.
text=string.gsub(text,"%d","%1 ")
-- get rid of leading or trailing spaces
text=string.gsub(text,"^%s*","")
text=string.gsub(text,"%s*$","")
text=string.gsub(text," "," ")
return text
end
@@ -1546,6 +1719,27 @@ function PLAYERTASKCONTROLLER:EnablePrecisionBombing(FlightGroup,LaserCode)
return self
end
--- [User] Allow precision laser-guided bombing on statics and "high-value" ground units (MBT etc) with player units lasing.
-- @param #PLAYERTASKCONTROLLER self
-- @param Ops.PlayerRecce#PLAYERRECCE Recce (Optional) The PLAYERRECCE object governing the lasing players.
-- @return #PLAYERTASKCONTROLLER self
function PLAYERTASKCONTROLLER:EnableBuddyLasing(Recce)
self:T(self.lid.."EnableBuddyLasing")
self.buddylasing = true
self.PlayerRecce = Recce
return self
end
--- [User] Allow precision laser-guided bombing on statics and "high-value" ground units (MBT etc) with player units lasing.
-- @param #PLAYERTASKCONTROLLER self
-- @return #PLAYERTASKCONTROLLER self
function PLAYERTASKCONTROLLER:DisableBuddyLasing()
self:T(self.lid.."DisableBuddyLasing")
self.buddylasing = false
return self
end
--- [User] Allow addition of targets with user F10 map markers.
-- @param #PLAYERTASKCONTROLLER self
-- @param #string Tag (Optional) The tagname to use to identify commands, defaults to "TASK"
@@ -1583,7 +1777,7 @@ end
-- @return #string playername
-- @return #string ttsplayername
function PLAYERTASKCONTROLLER:_GetPlayerName(Client)
self:T(self.lid.."DisablePrecisionBombing")
self:T(self.lid.."_GetPlayerName")
local playername = Client:GetPlayerName()
local ttsplayername = nil
if not self.customcallsigns[playername] then
@@ -1717,7 +1911,7 @@ function PLAYERTASKCONTROLLER:_EventHandler(EventData)
end
playername = self:_GetTextForSpeech(playername)
--local text = string.format("%s, %s, switch to %s for task assignment!",EventData.IniPlayerName,self.MenuName or self.Name,freqtext)
local text = string.format(switchtext,self.MenuName or self.Name,playername,freqtext)
local text = string.format(switchtext,playername,self.MenuName or self.Name,freqtext)
self.SRSQueue:NewTransmission(text,nil,self.SRS,timer.getAbsTime()+60,2,{EventData.IniGroup},text,30,self.BCFrequency,self.BCModulation)
end
end
@@ -1872,6 +2066,23 @@ function PLAYERTASKCONTROLLER:_CheckTaskQueue()
self:T("*****Removing player " .. _id)
self.TasksPerPlayer:PullByID(_id)
end
-- Follow-up tasks?
local nexttasks = {}
if task.FinalState == "Success" then
nexttasks = task.NextTaskSuccess
elseif task.FinalState == "Failed" then
nexttasks = task.NextTaskFailure
end
local clientlist, count = task:GetClientObjects()
if count > 0 then
for _,_client in pairs(clientlist) do
local client = _client --Wrapper.Client#CLIENT
local group = client:GetGroup()
for _,task in pairs(nexttasks) do
self:_JoinTask(group,client,task,true)
end
end
end
local TNow = timer.getAbsTime()
if TNow - task.timestamp > 10 then
local task = self.TaskQueue:PullByID(_id) -- Ops.PlayerTask#PLAYERTASK
@@ -2225,7 +2436,7 @@ function PLAYERTASKCONTROLLER:_AddTask(Target)
ttstype = self.gettext:GetEntry("BAITTS",self.locale)
end
-- see if we can do precision bombing
if (type == AUFTRAG.Type.BAI or type == AUFTRAG.Type.CAS) and self.precisionbombing then
if (type == AUFTRAG.Type.BAI or type == AUFTRAG.Type.CAS) and (self.precisionbombing or self.buddylasing) then
-- threatlevel between 3 and 6 means, it's artillery, tank, modern tank or AAA
if threat > 2 and threat < 7 then
type = AUFTRAG.Type.PRECISIONBOMBING
@@ -2317,16 +2528,53 @@ function PLAYERTASKCONTROLLER:_AddTask(Target)
return self
end
--- [User] Add a PLAYERTASK object to the list of (open) tasks
-- @param #PLAYERTASKCONTROLLER self
-- @param Ops.PlayerTask#PLAYERTASK PlayerTask
-- @return #PLAYERTASKCONTROLLER self
-- @usage
-- Example to create a PLAYERTASK of type CTLD and give Players 10 minutes to complete:
--
-- local newtask = PLAYERTASK:New(AUFTRAG.Type.CTLD,ZONE:Find("Unloading"),false,0,"Combat Transport")
-- newtask.Time0 = timer.getAbsTime() -- inject a timestamp for T0
-- newtask:AddFreetext("Transport crates to the drop zone and build a vehicle in the next 10 minutes!")
--
-- -- add a condition for failure - fail after 10 minutes
-- newtask:AddConditionFailure(
-- function()
-- local Time = timer.getAbsTime()
-- if Time - newtask.Time0 > 600 then
-- return true
-- end
-- return false
-- end
-- )
--
-- taskmanager:AddPlayerTaskToQueue(PlayerTask)
function PLAYERTASKCONTROLLER:AddPlayerTaskToQueue(PlayerTask)
self:T(self.lid.."AddPlayerTaskToQueue")
if PlayerTask and PlayerTask.ClassName and PlayerTask.ClassName == "PLAYERTASK" then
PlayerTask:_SetController(self)
PlayerTask:SetCoalition(self.Coalition)
self.TaskQueue:Push(PlayerTask)
self:__TaskAdded(-1,PlayerTask)
else
self:E(self.lid.."***** NO valid PAYERTASK object sent!")
end
return self
end
--- [Internal] Join a player to a task
-- @param #PLAYERTASKCONTROLLER self
-- @param Wrapper.Group#GROUP Group
-- @param Wrapper.Client#CLIENT Client
-- @param Ops.PlayerTask#PLAYERTASK Task
-- @param #boolean Force Assign task even if client already has one
-- @return #PLAYERTASKCONTROLLER self
function PLAYERTASKCONTROLLER:_JoinTask(Group, Client, Task)
function PLAYERTASKCONTROLLER:_JoinTask(Group, Client, Task, Force)
self:T(self.lid.."_JoinTask")
local playername, ttsplayername = self:_GetPlayerName(Client)
if self.TasksPerPlayer:HasUniqueID(playername) then
if self.TasksPerPlayer:HasUniqueID(playername) and not Force then
-- Player already has a task
if not self.NoScreenOutput then
local text = self.gettext:GetEntry("HAVEACTIVETASK",self.locale)
@@ -2350,7 +2598,7 @@ function PLAYERTASKCONTROLLER:_JoinTask(Group, Client, Task)
--local m=MESSAGE:New(text,"10","Tasking"):ToAll()
end
if self.UseSRS then
self:I(self.lid..text)
self:T(self.lid..text)
self.SRSQueue:NewTransmission(text,nil,self.SRS,nil,2)
end
self.TasksPerPlayer:Push(Task,playername)
@@ -2424,8 +2672,10 @@ function PLAYERTASKCONTROLLER:_ActiveTaskInfo(Group, Client, Task)
self:T(self.lid.."_ActiveTaskInfo")
local playername, ttsplayername = self:_GetPlayerName(Client)
local text = ""
local textTTS = ""
if self.TasksPerPlayer:HasUniqueID(playername) or Task then
-- TODO: Show multiple?
-- NODO: Show multiple?
-- Details
local task = Task or self.TasksPerPlayer:ReadByID(playername) -- Ops.PlayerTask#PLAYERTASK
local tname = self.gettext:GetEntry("TASKNAME",self.locale)
local ttsname = self.gettext:GetEntry("TASKNAMETTS",self.locale)
@@ -2438,6 +2688,7 @@ function PLAYERTASKCONTROLLER:_ActiveTaskInfo(Group, Client, Task)
else
CoordText = Coordinate:ToStringA2A(Client)
end
-- Threat Level
local ThreatLevel = task.Target:GetThreatLevelMax()
--local ThreatLevelText = "high"
local ThreatLevelText = self.gettext:GetEntry("THREATHIGH",self.locale)
@@ -2448,11 +2699,13 @@ function PLAYERTASKCONTROLLER:_ActiveTaskInfo(Group, Client, Task)
--ThreatLevelText = "low"
ThreatLevelText = self.gettext:GetEntry("THREATLOW",self.locale)
end
-- Targetno and Threat
local targets = task.Target:CountTargets() or 0
local clientlist, clientcount = task:GetClients()
local ThreatGraph = "[" .. string.rep( "", ThreatLevel ) .. string.rep( "", 10 - ThreatLevel ) .. "]: "..ThreatLevel
local ThreatLocaleText = self.gettext:GetEntry("THREATTEXT",self.locale)
text = string.format(ThreatLocaleText, taskname, ThreatGraph, targets, CoordText)
-- Prec bombing
if task.Type == AUFTRAG.Type.PRECISIONBOMBING and self.precisionbombing then
if self.LasingDrone and self.LasingDrone.playertask then
local yes = self.gettext:GetEntry("YES",self.locale)
@@ -2464,12 +2717,57 @@ function PLAYERTASKCONTROLLER:_ActiveTaskInfo(Group, Client, Task)
text = text .. prectext
end
end
-- Buddylasing
if task.Type == AUFTRAG.Type.PRECISIONBOMBING and self.buddylasing then
if self.PlayerRecce then
local yes = self.gettext:GetEntry("YES",self.locale)
local no = self.gettext:GetEntry("NO",self.locale)
-- TODO make dist dependent on PlayerRecce Object
local reachdist = 8000
local inreach = false
-- someone close enough?
local pset = self.PlayerRecce.PlayerSet:GetAliveSet()
for _,_player in pairs(pset) do
local player = _player -- Wrapper.Client#CLIENT
local pcoord = player:GetCoordinate()
if pcoord:Get2DDistance(Coordinate) <= reachdist then
inreach = true
local callsign = player:GetGroup():GetCustomCallSign(self.ShortCallsign,self.Keepnumber,self.CallsignTranslations)
local playername = player:GetPlayerName()
local islasing = no
if self.PlayerRecce.CanLase[player:GetTypeName()] and self.PlayerRecce.AutoLase[playername] then
-- TODO - maybe compare Spot target
islasing = yes
end
local inrtext = inreach == true and yes or no
local prectext = self.gettext:GetEntry("RECCETARGETREPORT",self.locale)
-- RECCETARGETREPORT = "\nSpäher % im Zielbereich: %s\nLasing: %s",
prectext = string.format(prectext,callsign,inrtext,islasing)
text = text .. prectext
end
end
end
-- Transport
elseif task.Type == AUFTRAG.Type.CTLD or task.Type == AUFTRAG.Type.CSAR then
-- THREATTEXT = "%s\nThreat: %s\nTargets left: %d\nCoord: %s",
-- THREATTEXTTTS = "%s, %s. Target information for %s. Threat level %s. Targets left %d. Target location %s.",
text = taskname
textTTS = taskname
local detail = task:GetFreetext()
local detailTTS = task:GetFreetextTTS()
local brieftxt = self.gettext:GetEntry("BRIEFING",self.locale)
local locatxt = self.gettext:GetEntry("TARGETLOCATION",self.locale)
text = text .. string.format("\n%s: %s\n%s %s",brieftxt,detail,locatxt,CoordText)
--text = text .. "\nBriefing: "..detail.."\nTarget location "..CoordText
--textTTS = textTTS .. "; Briefing: "..detailTTS.."\nTarget location "..CoordText
textTTS = textTTS .. string.format("; %s: %s; %s %s",brieftxt,detailTTS,locatxt,CoordText)
end
-- Pilots
local clienttxt = self.gettext:GetEntry("PILOTS",self.locale)
if clientcount > 0 then
for _,_name in pairs(clientlist) do
if self.customcallsigns[_name] then
-- personalized flight name in player naming
--_name = string.match(_name,"| ([%a]+)")
_name = self.customcallsigns[_name]
end
clienttxt = clienttxt .. _name .. ", "
@@ -2479,7 +2777,14 @@ function PLAYERTASKCONTROLLER:_ActiveTaskInfo(Group, Client, Task)
local keine = self.gettext:GetEntry("NONE",self.locale)
clienttxt = clienttxt .. keine
end
-- Task Report
text = text .. clienttxt
if task:HasFreetext() and not ( task.Type == AUFTRAG.Type.CTLD or task.Type == AUFTRAG.Type.CSAR) then
local brieftxt = self.gettext:GetEntry("BRIEFING",self.locale)
text = text .. string.format("\n%s: ",brieftxt)..task:GetFreetext()
end
textTTS = textTTS .. clienttxt
if self.UseSRS then
if string.find(CoordText," BR, ") then
CoordText = string.gsub(CoordText," BR, "," Bee, Arr, ")
@@ -2492,6 +2797,15 @@ function PLAYERTASKCONTROLLER:_ActiveTaskInfo(Group, Client, Task)
local lasingtext = self.gettext:GetEntry("POINTERTARGETLASINGTTS",self.locale)
ttstext = ttstext .. lasingtext
end
elseif task.Type == AUFTRAG.Type.CTLD or task.Type == AUFTRAG.Type.CSAR then
ttstext = textTTS
if string.find(ttstext," BR, ") then
CoordText = string.gsub(ttstext," BR, "," Bee, Arr, ")
end
elseif task:HasFreetext() then
-- add tts freetext
local brieftxt = self.gettext:GetEntry("BRIEFING",self.locale)
ttstext = ttstext .. string.format("; %s: ",brieftxt)..task:GetFreetextTTS()
end
self.SRSQueue:NewTransmission(ttstext,nil,self.SRS,nil,2)
end
@@ -2758,10 +3072,12 @@ function PLAYERTASKCONTROLLER:_BuildMenus(Client,enforced,fromsuccess)
local active = MENU_GROUP_DELAYED:New(group,menuactive,topmenu)
local info = MENU_GROUP_COMMAND_DELAYED:New(group,menuinfo,active,self._ActiveTaskInfo,self,group,client)
local mark = MENU_GROUP_COMMAND_DELAYED:New(group,menumark,active,self._MarkTask,self,group,client)
if self.Type ~= PLAYERTASKCONTROLLER.Type.A2A or self.noflaresmokemenu then
-- no smoking/flaring here if A2A or designer has set to false
local smoke = MENU_GROUP_COMMAND_DELAYED:New(group,menusmoke,active,self._SmokeTask,self,group,client)
local flare = MENU_GROUP_COMMAND_DELAYED:New(group,menuflare,active,self._FlareTask,self,group,client)
if self.Type ~= PLAYERTASKCONTROLLER.Type.A2A then
if self.noflaresmokemenu ~= true then
-- no smoking/flaring here if A2A or designer has set noflaresmokemenu to true
local smoke = MENU_GROUP_COMMAND_DELAYED:New(group,menusmoke,active,self._SmokeTask,self,group,client)
local flare = MENU_GROUP_COMMAND_DELAYED:New(group,menuflare,active,self._FlareTask,self,group,client)
end
end
local abort = MENU_GROUP_COMMAND_DELAYED:New(group,menuabort,active,self._AbortTask,self,group,client)
if self.activehasinfomenu and self.taskinfomenu then

View File

@@ -4,7 +4,7 @@
--
-- * Manages target, number alive, life points, damage etc.
-- * Events when targets are damaged or destroyed
-- * Various target objects: UNIT, GROUP, STATIC, AIRBASE, COORDINATE, SET_GROUP, SET_UNIT
-- * Various target objects: UNIT, GROUP, STATIC, AIRBASE, COORDINATE, SET_GROUP, SET_UNIT, SET_SCENERY
--
-- ===
--
@@ -69,6 +69,7 @@ TARGET = {
casualties = {},
threatlevel0 = 0,
conditionStart = {},
TStatus = 30,
}
@@ -146,7 +147,7 @@ _TARGETID=0
--- TARGET class version.
-- @field #string version
TARGET.version="0.5.2"
TARGET.version="0.5.4"
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO list
@@ -185,6 +186,7 @@ function TARGET:New(TargetObject)
-- Defaults.
self:SetPriority()
self:SetImportance()
self.TStatus = 30
-- Log ID.
self.lid=string.format("TARGET #%03d | ", _TARGETID)
@@ -259,12 +261,13 @@ end
-- * SET_UNIT
-- * SET_STATIC
-- * SET_OPSGROUP
-- * SET_SCENERY
--
-- @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") or Object:IsInstanceOf("SET_STATIC") or Object:IsInstanceOf("SET_OPSGROUP") then
if Object:IsInstanceOf("SET_GROUP") or Object:IsInstanceOf("SET_UNIT") or Object:IsInstanceOf("SET_STATIC") or Object:IsInstanceOf("SET_SCENERY") or Object:IsInstanceOf("SET_OPSGROUP") then
---
-- Sets
@@ -570,7 +573,7 @@ function TARGET:onafterStatus(From, Event, To)
-- Update status again in 30 sec.
if self:IsAlive() then
self:__Status(-30)
self:__Status(-self.TStatus)
end
end
@@ -828,8 +831,8 @@ function TARGET:_AddObject(Object)
if static and static:IsAlive() then
target.Life0=1
target.Life=1
target.Life0=static:GetLife0()
target.Life=static:GetLife()
target.N0=target.N0+1
table.insert(self.elements, target.Name)
@@ -1131,8 +1134,9 @@ end
--- Get target 3D position vector.
-- @param #TARGET self
-- @param #TARGET.Object Target Target object.
-- @param #boolean Average
-- @return DCS#Vec3 Vector with x,y,z components.
function TARGET:GetTargetVec3(Target)
function TARGET:GetTargetVec3(Target, Average)
if Target.Type==TARGET.ObjectType.GROUP then
@@ -1140,6 +1144,9 @@ function TARGET:GetTargetVec3(Target)
if object and object:IsAlive() then
local vec3=object:GetVec3()
if Average then
vec3=object:GetAverageVec3()
end
if vec3 then
return vec3
@@ -1218,8 +1225,9 @@ end
--- Get target coordinate.
-- @param #TARGET self
-- @param #TARGET.Object Target Target object.
-- @param #boolean Average
-- @return Core.Point#COORDINATE Coordinate of the target.
function TARGET:GetTargetCoordinate(Target)
function TARGET:GetTargetCoordinate(Target, Average)
if Target.Type==TARGET.ObjectType.COORDINATE then
@@ -1229,7 +1237,7 @@ function TARGET:GetTargetCoordinate(Target)
else
-- Get updated position vector.
local vec3=self:GetTargetVec3(Target)
local vec3=self:GetTargetVec3(Target, Average)
-- Update position. This saves us to create a new COORDINATE object each time.
if vec3 then
@@ -1362,6 +1370,26 @@ function TARGET:GetCoordinate()
return nil
end
--- Get average coordinate.
-- @param #TARGET self
-- @return Core.Point#COORDINATE Coordinate of the target.
function TARGET:GetAverageCoordinate()
for _,_target in pairs(self.targets) do
local Target=_target --#TARGET.Object
local coordinate=self:GetTargetCoordinate(Target,true)
if coordinate then
return coordinate
end
end
self:E(self.lid..string.format("ERROR: Cannot get average coordinate of target %s", tostring(self.name)))
return nil
end
--- Get category.
-- @param #TARGET self
-- @return #string Target category. See `TARGET.Category.X`, where `X=AIRCRAFT, GROUND`.