This commit is contained in:
Frank 2020-08-08 01:10:03 +02:00
parent 495a9fd3a0
commit 337e1a837f
8 changed files with 618 additions and 581 deletions

View File

@ -1609,6 +1609,7 @@ WAREHOUSE = {
-- @field #boolean iscargo If true, asset is cargo. If false asset is transport. Nil if in stock. -- @field #boolean iscargo If true, asset is cargo. If false asset is transport. Nil if in stock.
-- @field #number rid The request ID of this asset. -- @field #number rid The request ID of this asset.
-- @field #boolean arrived If true, asset arrived at its destination. -- @field #boolean arrived If true, asset arrived at its destination.
-- @field #number damage Damage of asset group in percent.
--- Item of the warehouse queue table. --- Item of the warehouse queue table.
-- @type WAREHOUSE.Queueitem -- @type WAREHOUSE.Queueitem
@ -3822,6 +3823,11 @@ function WAREHOUSE:onafterAddAsset(From, Event, To, group, ngroups, forceattribu
asset.iscargo=nil asset.iscargo=nil
asset.arrived=nil asset.arrived=nil
-- Destroy group if it is alive.
if group:IsAlive()==true then
asset.damage=group:GetDamage()
end
-- Add asset to stock. -- Add asset to stock.
table.insert(self.stock, asset) table.insert(self.stock, asset)
@ -3991,6 +3997,7 @@ function WAREHOUSE:_RegisterAsset(group, ngroups, forceattribute, forcecargobay,
asset.skill=skill asset.skill=skill
asset.assignment=assignment asset.assignment=assignment
asset.spawned=false asset.spawned=false
asset.damage=0
asset.spawngroupname=string.format("%s_AID-%d", templategroupname, asset.uid) asset.spawngroupname=string.format("%s_AID-%d", templategroupname, asset.uid)
if i==1 then if i==1 then

View File

@ -66,7 +66,7 @@
-- At this point the airwing does not have any assets (aircraft). In order to add these, one needs to first define SQUADRONS. -- At this point the airwing does not have any assets (aircraft). In order to add these, one needs to first define SQUADRONS.
-- --
-- VFA151=SQUADRON:New("F-14 Group", 8, "VFA-151 (Vigilantes)") -- VFA151=SQUADRON:New("F-14 Group", 8, "VFA-151 (Vigilantes)")
-- VFA151:AddMissionCapability({AUFTRAG.Type.PATROL, AUFTRAG.Type.INTERCEPT}) -- VFA151:AddMissionCapability({AUFTRAG.Type.GCCAP, AUFTRAG.Type.INTERCEPT})
-- --
-- airwing:AddSquadron(VFA151) -- airwing:AddSquadron(VFA151)
-- --
@ -78,8 +78,8 @@
-- defined in the Mission Editor. -- defined in the Mission Editor.
-- --
-- -- F-14 payloads for CAP and INTERCEPT. Phoenix are first, sparrows are second choice. -- -- F-14 payloads for CAP and INTERCEPT. Phoenix are first, sparrows are second choice.
-- airwing:NewPayload(GROUP:FindByName("F-14 Payload AIM-54C"), 2, {AUFTRAG.Type.INTERCEPT, AUFTRAG.Type.PATROL}, 80) -- airwing:NewPayload(GROUP:FindByName("F-14 Payload AIM-54C"), 2, {AUFTRAG.Type.INTERCEPT, AUFTRAG.Type.GCCAP}, 80)
-- airwing:NewPayload(GROUP:FindByName("F-14 Payload AIM-7M"), 20, {AUFTRAG.Type.INTERCEPT, AUFTRAG.Type.PATROL}) -- airwing:NewPayload(GROUP:FindByName("F-14 Payload AIM-7M"), 20, {AUFTRAG.Type.INTERCEPT, AUFTRAG.Type.GCCAP})
-- --
-- This will add two AIM-54C and 20 AIM-7M payloads. -- This will add two AIM-54C and 20 AIM-7M payloads.
-- --
@ -127,6 +127,7 @@ AIRWING = {
-- @field #AIRWING.Payload payload The payload of the asset. -- @field #AIRWING.Payload payload The payload of the asset.
-- @field Ops.FlightGroup#FLIGHTGROUP flightgroup The flightgroup object. -- @field Ops.FlightGroup#FLIGHTGROUP flightgroup The flightgroup object.
-- @field #string squadname Name of the squadron this asset belongs to. -- @field #string squadname Name of the squadron this asset belongs to.
-- @field #number Treturned Time stamp when asset returned to the airwing.
-- @extends Functional.Warehouse#WAREHOUSE.Assetitem -- @extends Functional.Warehouse#WAREHOUSE.Assetitem
--- Payload data. --- Payload data.
@ -284,26 +285,32 @@ function AIRWING:NewPayload(Unit, Npayloads, MissionTypes, Performance)
Performance=Performance or 50 Performance=Performance or 50
if type(Unit)=="string" then if type(Unit)=="string" then
Unit=UNIT:FindByName(Unit) local name=Unit
env.info("unit as string "..Unit)
Unit=UNIT:FindByName(name)
if not Unit then if not Unit then
Unit=GROUP:FindByName(Unit) env.info("no UNIT trying group")
Unit=GROUP:FindByName(name)
if not Unit then
env.info("no GROUP either!")
end
end end
end end
-- If a GROUP object was given, get the first unit.
if Unit:IsInstanceOf("GROUP") then
Unit=Unit:GetUnit(1)
end
-- Ensure Missiontypes is a table.
if MissionTypes and type(MissionTypes)~="table" then
MissionTypes={MissionTypes}
end
if Unit then if Unit then
local payload={} --#AIRWING.Payload -- If a GROUP object was given, get the first unit.
if Unit:IsInstanceOf("GROUP") then
Unit=Unit:GetUnit(1)
end
-- Ensure Missiontypes is a table.
if MissionTypes and type(MissionTypes)~="table" then
MissionTypes={MissionTypes}
end
-- Create payload.
local payload={} --#AIRWING.Payload
payload.unitname=Unit:GetName() payload.unitname=Unit:GetName()
payload.aircrafttype=Unit:GetTypeName() payload.aircrafttype=Unit:GetTypeName()
payload.pylons=Unit:GetTemplatePayload() payload.pylons=Unit:GetTemplatePayload()
@ -338,8 +345,10 @@ function AIRWING:NewPayload(Unit, Npayloads, MissionTypes, Performance)
table.insert(self.payloads, payload) table.insert(self.payloads, payload)
return payload return payload
end end
self:E(self.lid.."ERROR: No UNIT found to create PAYLOAD!")
return nil return nil
end end
@ -771,7 +780,7 @@ function AIRWING:onafterStatus(From, Event, To)
-- General info: -- General info:
-- TODO: assets total -- TODO: assets total
local text=string.format("Status %s: missions=%d, payloads=%d (%d), squads=%d", fsmstate, nmissions, #self.payloads, Npayloads, #self.squadrons) local text=string.format("%s: Missions=%d, Payloads=%d (%d), Squads=%d", fsmstate, nmissions, Npayloads, #self.payloads, #self.squadrons)
self:I(self.lid..text) self:I(self.lid..text)
------------------ ------------------
@ -898,7 +907,7 @@ end
-- @return #AIRWING self -- @return #AIRWING self
function AIRWING:CheckCAP() function AIRWING:CheckCAP()
local Ncap=self:CountMissionsInQueue({AUFTRAG.Type.PATROL, AUFTRAG.Type.INTERCEPT}) local Ncap=self:CountMissionsInQueue({AUFTRAG.Type.GCCAP, AUFTRAG.Type.INTERCEPT})
for i=1,self.nflightsCAP-Ncap do for i=1,self.nflightsCAP-Ncap do
@ -906,7 +915,7 @@ function AIRWING:CheckCAP()
local altitude=patrol.altitude+1000*patrol.noccupied local altitude=patrol.altitude+1000*patrol.noccupied
local missionCAP=AUFTRAG:NewPATROL(patrol.coord, altitude, patrol.speed, patrol.heading, patrol.leg) local missionCAP=AUFTRAG:NewGCCAP(patrol.coord, altitude, patrol.speed, patrol.heading, patrol.leg)
missionCAP.patroldata=patrol missionCAP.patroldata=patrol
@ -1068,7 +1077,7 @@ function AIRWING:GetTankerForFlight(flightgroup)
end end
--- Get next mission. --- Check if mission is not over and ready to cancel.
-- @param #AIRWING self -- @param #AIRWING self
function AIRWING:_CheckMissions() function AIRWING:_CheckMissions()
@ -1076,12 +1085,8 @@ function AIRWING:_CheckMissions()
for _,_mission in pairs(self.missionqueue) do for _,_mission in pairs(self.missionqueue) do
local mission=_mission --Ops.Auftrag#AUFTRAG local mission=_mission --Ops.Auftrag#AUFTRAG
if mission:IsNotOver() then if mission:IsNotOver() and mission:IsReadyToCancel() then
mission:Cancel()
if mission:IsReadyToCancel() then
mission:Cancel()
end
end end
end end
@ -1157,7 +1162,7 @@ function AIRWING:_GetNextMission()
-- Another check. -- Another check.
if #assets<mission.nassets then if #assets<mission.nassets then
self:E(self.lid..string.format("ERROR: Not enought payloads for mission assets! Can only do %d/%d", #assets, mission.nassets)) self:E(self.lid..string.format("ERROR: Not enough payloads for mission assets! Can only do %d/%d", #assets, mission.nassets))
end end
-- Optimize the asset selection. Now we include the payload performance as this could change the result. -- Optimize the asset selection. Now we include the payload performance as this could change the result.
@ -1424,7 +1429,7 @@ end
-- @param #string From From state. -- @param #string From From state.
-- @param #string Event Event. -- @param #string Event Event.
-- @param #string To To state. -- @param #string To To state.
-- @param Functional.Warehouse#WAREHOUSE.Assetitem asset The asset that has just been added. -- @param #AIRWING.SquadronAsset asset The asset that has just been added.
-- @param #string assignment The (optional) assignment for the asset. -- @param #string assignment The (optional) assignment for the asset.
function AIRWING:onafterNewAsset(From, Event, To, asset, assignment) function AIRWING:onafterNewAsset(From, Event, To, asset, assignment)
@ -1487,6 +1492,9 @@ function AIRWING:onafterNewAsset(From, Event, To, asset, assignment)
self:I(self.lid..string.format("Asset %s from squadron %s returned! asset.assignment=\"%s\", assignment=\"%s\"", asset.spawngroupname, squad.name, tostring(asset.assignment), tostring(assignment))) self:I(self.lid..string.format("Asset %s from squadron %s returned! asset.assignment=\"%s\", assignment=\"%s\"", asset.spawngroupname, squad.name, tostring(asset.assignment), tostring(assignment)))
self:ReturnPayloadFromAsset(asset) self:ReturnPayloadFromAsset(asset)
-- Set timestamp.
asset.Treturned=timer.getAbsTime()
end end
end end
@ -1545,8 +1553,8 @@ function AIRWING:onafterAssetSpawned(From, Event, To, group, asset, request)
-- Add mission to flightgroup queue. -- Add mission to flightgroup queue.
if mission then if mission then
-- RTB on low fuel if on PATROL. -- RTB on low fuel if on GCCAP.
if mission.type==AUFTRAG.Type.PATROL then if mission.type==AUFTRAG.Type.GCCAP then
flightgroup:SetFuelLowThreshold(nil, true) flightgroup:SetFuelLowThreshold(nil, true)
end end
@ -1787,6 +1795,12 @@ end
-- @return #number Count of available payloads in stock. -- @return #number Count of available payloads in stock.
function AIRWING:CountPayloadsInStock(MissionTypes, UnitTypes) function AIRWING:CountPayloadsInStock(MissionTypes, UnitTypes)
if MissionTypes then
if type(MissionTypes)=="string" then
MissionTypes={MissionTypes}
end
end
if UnitTypes then if UnitTypes then
if type(UnitTypes)=="string" then if type(UnitTypes)=="string" then
UnitTypes={UnitTypes} UnitTypes={UnitTypes}
@ -1811,17 +1825,20 @@ function AIRWING:CountPayloadsInStock(MissionTypes, UnitTypes)
for _,_payload in pairs(self.payloads) do for _,_payload in pairs(self.payloads) do
local payload=_payload --#AIRWING.Payload local payload=_payload --#AIRWING.Payload
if self:CheckMissionCapability(MissionTypes, payload.capabilities) and _checkUnitTypes(payload) then for _,MissionType in pairs(MissionTypes) do
if self:CheckMissionCapability(MissionType, payload.capabilities) and _checkUnitTypes(payload) then
if payload.unlimited then
-- Payload is unlimited. Return a BIG number.
return 999
else
n=n+payload.navail
end
if payload.unlimited then
-- Payload is unlimited. Return a BIG number.
return 999
else
n=n+payload.navail
end end
end end
end end
return n return n
@ -1911,14 +1928,6 @@ function AIRWING:GetAssetsOnMission(MissionTypes, IncludeQueued)
return assets return assets
end end
--- Check
-- @param #AIRWING self
-- @param #boolean onlyactive Count only the active ones.
-- @return #table Table of unit types.
function AIRWING:_CheckSquads(onlyactive)
end
--- Get the aircraft types of this airwing. --- Get the aircraft types of this airwing.
-- @param #AIRWING self -- @param #AIRWING self
-- @param #boolean onlyactive Count only the active ones. -- @param #boolean onlyactive Count only the active ones.
@ -2003,18 +2012,6 @@ function AIRWING:CanMission(Mission)
end end
-- Payloads are not fetched from stock any more.
--[[
-- Now clear all reserved payloads.
for _,_asset in pairs(Assets) do
local asset=_asset --#AIRWING.SquadronAsset
-- Only unspawned payloads are returned.
if not asset.spawned and not asset.requested then
self:ReturnPayloadFromAsset(asset)
end
end
]]
-- Check if required assets are present. -- Check if required assets are present.
if Mission.nassets and Mission.nassets > #Assets then if Mission.nassets and Mission.nassets > #Assets then
self:I(self.lid..string.format("INFO: Not enough assets available! Got %d but need at least %d", #Assets, Mission.nassets)) self:I(self.lid..string.format("INFO: Not enough assets available! Got %d but need at least %d", #Assets, Mission.nassets))

View File

@ -51,7 +51,7 @@
-- @field #number orbitLeg Length of orbit leg in meters. -- @field #number orbitLeg Length of orbit leg in meters.
-- @field Core.Point#COORDINATE orbitRaceTrack Race-track orbit coordinate. -- @field Core.Point#COORDINATE orbitRaceTrack Race-track orbit coordinate.
-- --
-- @field #AUFTRAG.TargetData engageTarget Target data to engage. -- @field Ops.Target#TARGET engageTarget Target data to engage.
-- --
-- @field Core.Zone#ZONE_RADIUS engageZone *Circular* engagement zone. -- @field Core.Zone#ZONE_RADIUS engageZone *Circular* engagement zone.
-- @field #table engageTargetTypes Table of target types that are engaged in the engagement zone. -- @field #table engageTargetTypes Table of target types that are engaged in the engagement zone.
@ -98,11 +98,6 @@
-- @field #number missionRepeated Number of times mission was repeated. -- @field #number missionRepeated Number of times mission was repeated.
-- @field #number missionRepeatMax Number of times mission is repeated if failed. -- @field #number missionRepeatMax Number of times mission is repeated if failed.
-- --
-- @field #number radioFreq Mission radio frequency in MHz.
-- @field #number radioModu Mission radio modulation (0=AM and 1=FM).
-- @field #number tacanChannel Mission TACAN channel.
-- @field #number tacanMorse Mission TACAN morse code.
--
-- @field Ops.OpsGroup#OPSGROUP.Radio radio Radio freq and modulation. -- @field Ops.OpsGroup#OPSGROUP.Radio radio Radio freq and modulation.
-- @field Ops.OpsGroup#OPSGROUP.Beacon tacan TACAN setting. -- @field Ops.OpsGroup#OPSGROUP.Beacon tacan TACAN setting.
-- @field Ops.OpsGroup#OPSGROUP.Beacon icls ICLS setting. -- @field Ops.OpsGroup#OPSGROUP.Beacon icls ICLS setting.
@ -188,9 +183,9 @@
-- --
-- An orbit mission can be created with the @{#AUFTRAG.NewORBIT}() function. -- An orbit mission can be created with the @{#AUFTRAG.NewORBIT}() function.
-- --
-- ## PATROL -- ## GCCAP
-- --
-- An patrol mission can be created with the @{#AUFTRAG.NewPATROL}() function. -- An patrol mission can be created with the @{#AUFTRAG.NewGCCAP}() function.
-- --
-- ## RECON -- ## RECON
-- --
@ -293,7 +288,7 @@ _AUFTRAGSNR=0
-- @field #string FERRY Ferry flight mission. -- @field #string FERRY Ferry flight mission.
-- @field #string INTERCEPT Intercept mission. -- @field #string INTERCEPT Intercept mission.
-- @field #string ORBIT Orbit mission. -- @field #string ORBIT Orbit mission.
-- @field #string PATROL Similar to CAP but no auto engage targets. -- @field #string GCCAP Similar to CAP but no auto engage targets.
-- @field #string RECON Recon mission. -- @field #string RECON Recon mission.
-- @field #string RECOVERYTANKER Recovery tanker mission. Not implemented yet. -- @field #string RECOVERYTANKER Recovery tanker mission. Not implemented yet.
-- @field #string RESCUEHELO Rescue helo. -- @field #string RESCUEHELO Rescue helo.
@ -316,7 +311,7 @@ AUFTRAG.Type={
FERRY="Ferry Flight", FERRY="Ferry Flight",
INTERCEPT="Intercept", INTERCEPT="Intercept",
ORBIT="Orbit", ORBIT="Orbit",
PATROL="Patrol", GCCAP="Patrol",
RECON="Recon", RECON="Recon",
RECOVERYTANKER="Recovery Tanker", RECOVERYTANKER="Recovery Tanker",
RESCUEHELO="Rescue Helo", RESCUEHELO="Rescue Helo",
@ -632,7 +627,7 @@ function AUFTRAG:NewORBIT_RACETRACK(Coordinate, Altitude, Speed, Heading, Leg)
return mission return mission
end end
--- Create a PATROL mission. --- Create a GCCAP mission.
-- @param #AUFTRAG self -- @param #AUFTRAG self
-- @param Core.Point#COORDINATE Coordinate Where to orbit. -- @param Core.Point#COORDINATE Coordinate Where to orbit.
-- @param #number Altitude Orbit altitude in feet. Default is y component of `Coordinate`. -- @param #number Altitude Orbit altitude in feet. Default is y component of `Coordinate`.
@ -640,13 +635,13 @@ end
-- @param #number Heading Heading of race-track pattern in degrees. Default random in [0, 360) degrees. -- @param #number Heading Heading of race-track pattern in degrees. Default random in [0, 360) degrees.
-- @param #number Leg Length of race-track in NM. Default 10 NM. -- @param #number Leg Length of race-track in NM. Default 10 NM.
-- @return #AUFTRAG self -- @return #AUFTRAG self
function AUFTRAG:NewPATROL(Coordinate, Altitude, Speed, Heading, Leg) function AUFTRAG:NewGCCAP(Coordinate, Altitude, Speed, Heading, Leg)
-- Create ORBIT first. -- Create ORBIT first.
local mission=AUFTRAG:NewORBIT_RACETRACK(Coordinate, Altitude, Speed, Heading, Leg) local mission=AUFTRAG:NewORBIT_RACETRACK(Coordinate, Altitude, Speed, Heading, Leg)
-- Mission type PATROL. -- Mission type GCCAP.
mission.type=AUFTRAG.Type.PATROL mission.type=AUFTRAG.Type.GCCAP
mission:_SetLogID() mission:_SetLogID()
@ -671,7 +666,7 @@ function AUFTRAG:NewTANKER(Coordinate, Altitude, Speed, Heading, Leg, RefuelSyst
-- Create ORBIT first. -- Create ORBIT first.
local mission=AUFTRAG:NewORBIT_RACETRACK(Coordinate, Altitude, Speed, Heading, Leg) local mission=AUFTRAG:NewORBIT_RACETRACK(Coordinate, Altitude, Speed, Heading, Leg)
-- Mission type PATROL. -- Mission type TANKER.
mission.type=AUFTRAG.Type.TANKER mission.type=AUFTRAG.Type.TANKER
mission:_SetLogID() mission:_SetLogID()
@ -701,7 +696,7 @@ function AUFTRAG:NewAWACS(Coordinate, Altitude, Speed, Heading, Leg)
-- Create ORBIT first. -- Create ORBIT first.
local mission=AUFTRAG:NewORBIT_RACETRACK(Coordinate, Altitude, Speed, Heading, Leg) local mission=AUFTRAG:NewORBIT_RACETRACK(Coordinate, Altitude, Speed, Heading, Leg)
-- Mission type PATROL. -- Mission type AWACS.
mission.type=AUFTRAG.Type.AWACS mission.type=AUFTRAG.Type.AWACS
mission:_SetLogID() mission:_SetLogID()
@ -1082,7 +1077,7 @@ function AUFTRAG:NewRESCUEHELO(Carrier)
local mission=AUFTRAG:New(AUFTRAG.Type.RESCUEHELO) local mission=AUFTRAG:New(AUFTRAG.Type.RESCUEHELO)
mission:_TargetFromObject(Carrier) self.carrier=Carrier
-- Mission options: -- Mission options:
mission.missionTask=ENUMS.MissionTask.NOTHING mission.missionTask=ENUMS.MissionTask.NOTHING
@ -1157,6 +1152,31 @@ function AUFTRAG:NewARTY(Target, Nshots, Radius)
return mission return mission
end end
--- Create a mission to attack a group. Mission type is automatically chosen from the group category.
-- @param #AUFTRAG self
-- @param Ops.Target#TARGET Target The target.
-- @return #AUFTRAG self
function AUFTRAG:NewTARGET(Target)
local mission=nil --#AUFTRAG
if Target.category==TARGET.Category.GROUND then
elseif Target.category==TARGET.Category.AIRCRAFT then
elseif Target.category==TARGET.Category.AIRBASE then
elseif Target.category==TARGET.Category.COORDINATE then
end
if mission then
mission:SetPriority(10, true)
end
end
--- Create a mission to attack a group. Mission type is automatically chosen from the group category. --- Create a mission to attack a group. Mission type is automatically chosen from the group category.
-- @param #AUFTRAG self -- @param #AUFTRAG self
@ -1882,12 +1902,6 @@ function AUFTRAG:Evaluate()
-- Assume success and check if any failed condition applies. -- Assume success and check if any failed condition applies.
local failed=false local failed=false
-- Any success condition true?
local successCondition=self:EvalConditionsAny(self.conditionSuccess)
-- Any failure condition true?
local failureCondition=self:EvalConditionsAny(self.conditionFailure)
-- Target damage in %. -- Target damage in %.
local targetdamage=self:GetTargetDamage() local targetdamage=self:GetTargetDamage()
@ -1931,6 +1945,13 @@ function AUFTRAG:Evaluate()
end end
-- Any success condition true?
local successCondition=self:EvalConditionsAny(self.conditionSuccess)
-- Any failure condition true?
local failureCondition=self:EvalConditionsAny(self.conditionFailure)
if failureCondition then if failureCondition then
failed=true failed=true
elseif successCondition then elseif successCondition then
@ -2217,8 +2238,7 @@ end
-- @param #string From From state. -- @param #string From From state.
-- @param #string Event Event. -- @param #string Event Event.
-- @param #string To To state. -- @param #string To To state.
-- @param Ops.OpsGroup#OPSGROUP FlightGroup function AUFTRAG:onafterScheduled(From, Event, To)
function AUFTRAG:onafterScheduled(From, Event, To, FlightGroup)
self.status=AUFTRAG.Status.SCHEDULED self.status=AUFTRAG.Status.SCHEDULED
self:T(self.lid..string.format("New mission status=%s", self.status)) self:T(self.lid..string.format("New mission status=%s", self.status))
end end
@ -2264,6 +2284,7 @@ end
-- @param #string To To state. -- @param #string To To state.
-- @param Ops.OpsGroup#OPSGROUP OpsGroup The ops group that is dead now. -- @param Ops.OpsGroup#OPSGROUP OpsGroup The ops group that is dead now.
function AUFTRAG:onafterElementDestroyed(From, Event, To, OpsGroup, Element) function AUFTRAG:onafterElementDestroyed(From, Event, To, OpsGroup, Element)
-- Increase number of own casualties.
self.Ncasualties=self.Ncasualties+1 self.Ncasualties=self.Ncasualties+1
end end
@ -2499,6 +2520,170 @@ function AUFTRAG:onafterStop(From, Event, To)
end end
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Target Functions
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- Create target data from a given object.
-- @param #AUFTRAG self
-- @param Wrapper.Positionable#POSITIONABLE Object The target GROUP, UNIT, STATIC.
function AUFTRAG:_TargetFromObject(Object)
if not self.engageTarget then
self.engageTarget=TARGET:New(Object)
else
-- Target was already specified elsewhere.
end
-- TODO: get rid of this.
self.Ntargets=self.engageTarget.Ntargets0
-- Debug info.
self:T(self.lid..string.format("Mission Target %s Type=%s, Ntargets=%d, Lifepoints=%d", self.engageTarget.lid, self.engageTarget.lid, self.Ntargets, self.engageTarget:GetLife()))
return self
end
--- Count alive mission targets.
-- @param #AUFTRAG self
-- @param #AUFTRAG.TargetData Target (Optional) The target object.
-- @return #number Number of alive target units.
function AUFTRAG:CountMissionTargets(Target)
if self.engageTarget then
return self.engageTarget:CountTargets()
else
return 0
end
end
--- Get target life points.
-- @param #AUFTRAG self
-- @return #number Number of initial life points when mission was planned.
function AUFTRAG:GetTargetInitialLife()
local target=self:GetTargetData()
if target then
return target.life0
else
return 0
end
end
--- Get target damage.
-- @param #AUFTRAG self
-- @return #number Damage in percent.
function AUFTRAG:GetTargetDamage()
local target=self:GetTargetData()
if target then
return target:GetDamage()
else
return 0
end
end
--- Get target life points.
-- @param #AUFTRAG self
-- @return #number Life points of target.
function AUFTRAG:GetTargetLife()
local target=self:GetTargetData()
if target then
return target:GetLife()
else
return 0
end
end
--- Get target.
-- @param #AUFTRAG self
-- @return Ops.Target#TARGET The target object. Could be many things.
function AUFTRAG:GetTargetData()
return self.engageTarget
end
--- Get mission objective object. Could be many things depending on the mission type.
-- @param #AUFTRAG self
-- @return Wrapper.Positionable#POSITIONABLE The target object. Could be many things.
function AUFTRAG:GetObjective()
return self:GetTargetData().Target
end
--- Get type of target.
-- @param #AUFTRAG self
-- @return #string The target type.
function AUFTRAG:GetTargetType()
return self:GetTargetData().Type
end
--- Get 2D vector of target.
-- @param #AUFTRAG self
-- @return DCS#VEC2 The target 2D vector or *nil*.
function AUFTRAG:GetTargetVec2()
local coord=self:GetTargetCoordinate()
if coord then
return coord:GetVec2()
end
return nil
end
--- Get coordinate of target.
-- @param #AUFTRAG self
-- @return Core.Point#COORDINATE The target coordinate or *nil*.
function AUFTRAG:GetTargetCoordinate()
if self.transportPickup then
-- Special case where we defined a
return self.transportPickup
elseif self.engageTarget then
return self.engageTarget:GetCoordinate()
else
self:E(self.lid.."ERROR: Cannot get target coordinate!")
end
return nil
end
--- Get name of the target.
-- @param #AUFTRAG self
-- @return #string Name of the target or "N/A".
function AUFTRAG:GetTargetName()
if self.engageTarget.Target then
return self.engageTarget.Name
end
return "N/A"
end
--- Get distance to target.
-- @param #AUFTRAG self
-- @param Core.Point#COORDINATE FromCoord The coordinate from which the distance is measured.
-- @return #number Distance in meters or 0.
function AUFTRAG:GetTargetDistance(FromCoord)
local TargetCoord=self:GetTargetCoordinate()
if TargetCoord and FromCoord then
return TargetCoord:Get2DDistance(FromCoord)
else
self:E(self.lid.."ERROR: TargetCoord or FromCoord does not exist in AUFTRAG:GetTargetDistance() function! Returning 0")
end
return 0
end
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Misc Functions -- Misc Functions
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
@ -2554,229 +2739,6 @@ function AUFTRAG:GetAssetByName(Name)
return nil return nil
end end
--- Count alive mission targets.
-- @param #AUFTRAG self
-- @param #AUFTRAG.TargetData Target (Optional) The target object.
-- @return #number Number of alive target units.
function AUFTRAG:CountMissionTargets(Target)
local N=0
Target=Target or self:GetTargetData()
if Target then
if Target.Type==AUFTRAG.TargetType.GROUP then
local target=Target.Target --Wrapper.Group#GROUP
local units=target:GetUnits()
for _,_unit in pairs(units or {}) do
local unit=_unit --Wrapper.Unit#UNIT
-- We check that unit is "alive" and has health >1. Somtimes units get heavily damanged but are still alive.
-- TODO: here I could introduce and count that if units have only health < 50% if mission objective is to just "damage" the units.
if unit and unit:IsAlive() and unit:GetLife()>1 then
N=N+1
end
end
elseif Target.Type==AUFTRAG.TargetType.UNIT then
local target=Target.Target --Wrapper.Unit#UNIT
if target and target:IsAlive() and target:GetLife()>1 then
N=N+1
end
elseif Target.Type==AUFTRAG.TargetType.STATIC then
local target=Target.Target --Wrapper.Static#STATIC
if target and target:IsAlive() then
N=N+1
end
elseif Target.Type==AUFTRAG.TargetType.AIRBASE then
-- TODO: any (good) way to tell whether an airbase was "destroyed" or at least damaged? Is :GetLive() working?
elseif Target.Type==AUFTRAG.TargetType.COORDINATE then
-- No target!
elseif Target.Type==AUFTRAG.TargetType.SETGROUP then
for _,_group in pairs(Target.Target.Set or {}) do
local group=_group --Wrapper.Group#GROUP
local units=group:GetUnits()
for _,_unit in pairs(units or {}) do
local unit=_unit --Wrapper.Unit#UNIT
-- We check that unit is "alive".
if unit and unit:IsAlive() and unit:GetLife()>1 then
N=N+1
end
end
end
elseif Target.Type==AUFTRAG.TargetType.SETUNIT then
for _,_unit in pairs(Target.Target.Set or {}) do
local unit=_unit --Wrapper.Unit#UNIT
-- We check that unit is "alive".
if unit and unit:IsAlive() and unit:GetLife()>1 then
N=N+1
end
end
else
self:E("ERROR unknown target type")
end
end
return N
end
--- Get target life points.
-- @param #AUFTRAG self
-- @return #number Number of initial life points when mission was planned.
function AUFTRAG:GetTargetInitialLife()
return self:GetTargetData().Lifepoints
end
--- Get target damage.
-- @param #AUFTRAG self
-- @return #number Damage in percent.
function AUFTRAG:GetTargetDamage()
local target=self:GetTargetData()
local life=self:GetTargetLife()/self:GetTargetInitialLife()
local damage=1-life
return damage*100
end
--- Get target life points.
-- @param #AUFTRAG self
-- @return #number Life points of target.
function AUFTRAG:GetTargetLife()
return self:_GetTargetLife(nil, false)
end
--- Get target life points.
-- @param #AUFTRAG self
-- @param #AUFTRAG.TargetData Target (Optional) The target object.
-- @param #boolean Healthy Get the life points of the healthy target.
-- @return #number Life points of target.
function AUFTRAG:_GetTargetLife(Target, Healthy)
local N=0
Target=Target or self:GetTargetData()
local function _GetLife(unit)
local unit=unit --Wrapper.Unit#UNIT
if Healthy then
local life=unit:GetLife()
local life0=unit:GetLife0()
return math.max(life, life0)
else
return unit:GetLife()
end
end
if Target then
if Target.Type==AUFTRAG.TargetType.GROUP then
local target=Target.Target --Wrapper.Group#GROUP
local units=target:GetUnits()
for _,_unit in pairs(units or {}) do
local unit=_unit --Wrapper.Unit#UNIT
-- We check that unit is "alive".
if unit and unit:IsAlive() then
N=N+_GetLife(unit)
end
end
elseif Target.Type==AUFTRAG.TargetType.UNIT then
local target=Target.Target --Wrapper.Unit#UNIT
if target and target:IsAlive() then
N=N+_GetLife(target)
end
elseif Target.Type==AUFTRAG.TargetType.STATIC then
local target=Target.Target --Wrapper.Static#STATIC
-- Statics are alive or not.
if target and target:IsAlive() then
N=N+1 --_GetLife(target)
else
N=N+0
end
elseif Target.Type==AUFTRAG.TargetType.AIRBASE then
-- TODO: any (good) way to tell whether an airbase was "destroyed" or at least damaged? Is :GetLive() working?
N=N+1
elseif Target.Type==AUFTRAG.TargetType.COORDINATE then
-- A coordinate does not live.
N=N+1
elseif Target.Type==AUFTRAG.TargetType.SETGROUP then
for _,_group in pairs(Target.Target.Set or {}) do
local group=_group --Wrapper.Group#GROUP
local units=group:GetUnits()
for _,_unit in pairs(units or {}) do
local unit=_unit --Wrapper.Unit#UNIT
-- We check that unit is "alive".
if unit and unit:IsAlive() then
N=N+_GetLife(unit)
end
end
end
elseif Target.Type==AUFTRAG.TargetType.SETUNIT then
for _,_unit in pairs(Target.Target.Set or {}) do
local unit=_unit --Wrapper.Unit#UNIT
-- We check that unit is "alive".
if unit and unit:IsAlive() then
N=N+_GetLife(unit)
end
end
else
self:E(self.lid.."ERROR unknown target type")
end
end
return N
end
--- Count alive flight groups assigned for this mission. --- Count alive flight groups assigned for this mission.
-- @param #AUFTRAG self -- @param #AUFTRAG self
-- @return #number Number of alive flight groups. -- @return #number Number of alive flight groups.
@ -2791,109 +2753,6 @@ function AUFTRAG:CountOpsGroups()
return N return N
end end
--- Get coordinate of target.
-- @param #AUFTRAG self
-- @return #AUFTRAG.TargetData The target object. Could be many things.
function AUFTRAG:GetTargetData()
return self.engageTarget
end
--- Get mission objective object. Could be many things depending on the mission type.
-- @param #AUFTRAG self
-- @return Wrapper.Positionable#POSITIONABLE The target object. Could be many things.
function AUFTRAG:GetObjective()
return self:GetTargetData().Target
end
--- Get type of target.
-- @param #AUFTRAG self
-- @return #string The target type.
function AUFTRAG:GetTargetType()
return self:GetTargetData().Type
end
--- Get 2D vector of target.
-- @param #AUFTRAG self
-- @return DCS#VEC2 The target 2D vector or *nil*.
function AUFTRAG:GetTargetVec2()
local coord=self:GetTargetCoordinate()
if coord then
return coord:GetVec2()
end
return nil
end
--- Get coordinate of target.
-- @param #AUFTRAG self
-- @return Core.Point#COORDINATE The target coordinate or *nil*.
function AUFTRAG:GetTargetCoordinate()
if self.transportPickup then
-- Special case where we defined a
return self.transportPickup
else
local target
if self:GetTargetType()==AUFTRAG.TargetType.COORDINATE then
-- Here the objective itself is a COORDINATE.
return self:GetObjective()
elseif self:GetTargetType()==AUFTRAG.TargetType.SETGROUP then
-- Return the first group in the set.
-- TODO: does this only return ALIVE groups?!
return self:GetObjective():GetFirst():GetCoordinate()
elseif self:GetTargetType()==AUFTRAG.TargetType.SETUNIT then
-- Return the first unit in the set.
-- TODO: does this only return ALIVE units?!
return self:GetObjective():GetFirst():GetCoordinate()
else
-- In all other cases the GetCoordinate() function should work.
return self:GetObjective():GetCoordinate()
end
end
return nil
end
--- Get name of the target.
-- @param #AUFTRAG self
-- @return #string Name of the target or "N/A".
function AUFTRAG:GetTargetName()
if self.engageTarget.Target then
return self.engageTarget.Name
end
return "N/A"
end
--- Get distance to target.
-- @param #AUFTRAG self
-- @param Core.Point#COORDINATE FromCoord The coordinate from which the distance is measured.
-- @return #number Distance in meters or 0.
function AUFTRAG:GetTargetDistance(FromCoord)
local TargetCoord=self:GetTargetCoordinate()
if TargetCoord and FromCoord then
return TargetCoord:Get2DDistance(FromCoord)
else
self:E(self.lid.."ERROR: TargetCoord or FromCoord does not exist in AUFTRAG:GetTargetDistance() function! Returning 0")
end
return 0
end
--- Get coordinate of target. First unit/group of the set is used. --- Get coordinate of target. First unit/group of the set is used.
-- @param #AUFTRAG self -- @param #AUFTRAG self
@ -3100,10 +2959,10 @@ function AUFTRAG:GetDCSMissionTask(TaskControllable)
-- Done below as also other mission types use the orbit task. -- Done below as also other mission types use the orbit task.
elseif self.type==AUFTRAG.Type.PATROL then elseif self.type==AUFTRAG.Type.GCCAP then
-------------------- --------------------
-- PATROL Mission -- -- GCCAP Mission --
-------------------- --------------------
-- Done below as also other mission types use the orbit task. -- Done below as also other mission types use the orbit task.
@ -3177,7 +3036,7 @@ function AUFTRAG:GetDCSMissionTask(TaskControllable)
-- We create a "fake" DCS task and pass the parameters to the FLIGHTGROUP. -- We create a "fake" DCS task and pass the parameters to the FLIGHTGROUP.
local param={} local param={}
param.unitname=self:GetTargetName() param.unitname=self.carrier:GetName()
param.offsetX=200 param.offsetX=200
param.offsetZ=240 param.offsetZ=240
param.altitude=70 param.altitude=70
@ -3207,7 +3066,7 @@ function AUFTRAG:GetDCSMissionTask(TaskControllable)
if self.type==AUFTRAG.Type.ORBIT or if self.type==AUFTRAG.Type.ORBIT or
self.type==AUFTRAG.Type.CAP or self.type==AUFTRAG.Type.CAP or
self.type==AUFTRAG.Type.CAS or self.type==AUFTRAG.Type.CAS or
self.type==AUFTRAG.Type.PATROL or self.type==AUFTRAG.Type.GCCAP or
self.type==AUFTRAG.Type.AWACS or self.type==AUFTRAG.Type.AWACS or
self.type==AUFTRAG.Type.TANKER then self.type==AUFTRAG.Type.TANKER then
@ -3237,39 +3096,28 @@ end
--- Get DCS task table for an attack group or unit task. --- Get DCS task table for an attack group or unit task.
-- @param #AUFTRAG self -- @param #AUFTRAG self
-- @param #AUFTRAG.TargetData target Target data. -- @param Ops.Target#TARGET Target Target data.
-- @param #table DCStasks DCS DCS tasks table to which the task is added. -- @param #table DCStasks DCS DCS tasks table to which the task is added.
-- @return DCS#Task The DCS task table. -- @return DCS#Task The DCS task table.
function AUFTRAG:_GetDCSAttackTask(target, DCStasks) function AUFTRAG:_GetDCSAttackTask(Target, DCStasks)
local DCStask=nil DCStasks=DCStasks or {}
if target.Type==AUFTRAG.TargetType.GROUP then for _,_target in pairs(Target.targets) do
local target=_target --Ops.Target#TARGET.Object
DCStask=CONTROLLABLE.TaskAttackGroup(nil, target.Target, self.engageWeaponType, self.engageWeaponExpend, self.engageQuantity, self.engageDirection, self.engageAltitude, self.engageAsGroup) if target.Type==TARGET.ObjectType.GROUP then
table.insert(DCStasks, DCStask) local DCStask=CONTROLLABLE.TaskAttackGroup(nil, target.Object, self.engageWeaponType, self.engageWeaponExpend, self.engageQuantity, self.engageDirection, self.engageAltitude, self.engageAsGroup)
elseif target.Type==AUFTRAG.TargetType.UNIT or target.Type==AUFTRAG.TargetType.STATIC then
DCStask=CONTROLLABLE.TaskAttackUnit(nil, target.Target, self.engageAsGroup, self.WeaponExpend, self.engageQuantity, self.engageDirection, self.engageAltitude, self.engageWeaponType)
table.insert(DCStasks, DCStask)
elseif target.Type==AUFTRAG.TargetType.SETGROUP then
-- Add all groups.
for _,group in pairs(target.Target.Set or {}) do
DCStask=CONTROLLABLE.TaskAttackGroup(nil, group, self.engageWeaponType, self.engageWeaponExpend, self.engageQuantity, self.engageDirection, self.engageAltitude, self.engageAsGroup)
table.insert(DCStasks, DCStask) table.insert(DCStasks, DCStask)
end
elseif target.Type==AUFTRAG.TargetType.SETUNIT then elseif target.Type==TARGET.ObjectType.UNIT or target.Type==TARGET.ObjectType.STATIC then
local DCStask=CONTROLLABLE.TaskAttackUnit(nil, target.Object, self.engageAsGroup, self.WeaponExpend, self.engageQuantity, self.engageDirection, self.engageAltitude, self.engageWeaponType)
-- Add tasks to attack all units.
for _,unit in pairs(target.Target.Set or {}) do
DCStask=CONTROLLABLE.TaskAttackUnit(nil, unit, self.engageAsGroup, self.WeaponExpend, self.engageQuantity, self.engageDirection, self.engageAltitude, self.engageWeaponType)
table.insert(DCStasks, DCStask) table.insert(DCStasks, DCStask)
end end
end end
@ -3277,96 +3125,6 @@ function AUFTRAG:_GetDCSAttackTask(target, DCStasks)
return DCStasks return DCStasks
end end
--- Create target data from a given object.
-- @param #AUFTRAG self
-- @param Wrapper.Positionable#POSITIONABLE Object The target GROUP, UNIT, STATIC.
-- @return #AUFTRAG.TargetData Target.
function AUFTRAG:_TargetFromObject(Object)
local target={} --#AUFTRAG.TargetData
-- The object.
target.Target=Object
if Object:IsInstanceOf("GROUP") then
target.Type=AUFTRAG.TargetType.GROUP
local object=Object --Wrapper.Group#GROUP
target.Name=object:GetName()
elseif Object:IsInstanceOf("UNIT") then
target.Type=AUFTRAG.TargetType.UNIT
local object=Object --Wrapper.Unit#UNIT
target.Name=object:GetName()
elseif Object:IsInstanceOf("STATIC") then
target.Type=AUFTRAG.TargetType.STATIC
target.Name=Object:GetName()
elseif Object:IsInstanceOf("COORDINATE") then
target.Type=AUFTRAG.TargetType.COORDINATE
local object=Object --Core.Point#COORDINATE
target.Name=object:ToStringLLDMS()
elseif Object:IsInstanceOf("AIRBASE") then
target.Type=AUFTRAG.TargetType.AIRBASE
local object=Object --Wrapper.Airbase#AIRBASE
target.Name=object:GetName()
elseif Object:IsInstanceOf("SET_GROUP") then
target.Type=AUFTRAG.TargetType.SETGROUP
local object=Object --Core.Set#SET_GROUP
target.Name=object:GetFirst():GetName()
elseif Object:IsInstanceOf("SET_UNIT") then
target.Type=AUFTRAG.TargetType.SETUNIT
local object=Object --Core.Set#SET_UNIT
target.Name=object:GetFirst():GetName()
else
self:E(self.lid.."ERROR: Unknown object given as target. Needs to be a GROUP, UNIT, STATIC, COORDINATE")
return nil
end
-- Number of initial targets.
local Ninitial=self:CountMissionTargets(target)
-- Initial total life point.
local Lifepoints=self:_GetTargetLife(target, true)
-- Set engage Target.
self.engageTarget=target
self.engageTarget.Ninital=Ninitial
self.engageTarget.Lifepoints=Lifepoints
-- TODO: get rid of this.
self.Ntargets=Ninitial
-- Debug info.
self:T(self.lid..string.format("Mission Target %s Type=%s, Ntargets=%d, Lifepoints=%d", target.Name, target.Type, Ninitial, Lifepoints))
return target
end
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

View File

@ -2624,6 +2624,9 @@ function FLIGHTGROUP:AddElementByName(unitname)
element.status=OPSGROUP.ElementStatus.INUTERO element.status=OPSGROUP.ElementStatus.INUTERO
element.group=unit:GetGroup() element.group=unit:GetGroup()
-- TODO: this is wrong when grouping is used!
local unittemplate=element.unit:GetTemplate()
element.modex=element.unit:GetTemplate().onboard_num element.modex=element.unit:GetTemplate().onboard_num
element.skill=element.unit:GetTemplate().skill element.skill=element.unit:GetTemplate().skill
element.pylons=element.unit:GetTemplatePylons() element.pylons=element.unit:GetTemplatePylons()
@ -2642,8 +2645,8 @@ function FLIGHTGROUP:AddElementByName(unitname)
element.ai=true element.ai=true
end end
local text=string.format("Adding element %s: status=%s, skill=%s, modex=%s, fuelmass=%.1f (%d %%), category=%d, categoryname=%s, callsign=%s, ai=%s", local text=string.format("Adding element %s: status=%s, skill=%s, modex=%s, fuelmass=%.1f (%d), category=%d, categoryname=%s, callsign=%s, ai=%s",
element.name, element.status, element.skill, element.modex, element.fuelmass, element.fuelrel, element.category, element.categoryname, element.callsign, tostring(element.ai)) element.name, element.status, element.skill, element.modex, element.fuelmass, element.fuelrel*100, element.category, element.categoryname, element.callsign, tostring(element.ai))
self:I(self.lid..text) self:I(self.lid..text)
-- Add element to table. -- Add element to table.

View File

@ -1437,7 +1437,7 @@ end
function OPSGROUP:onafterTaskExecute(From, Event, To, Task) function OPSGROUP:onafterTaskExecute(From, Event, To, Task)
-- Debug message. -- Debug message.
local text=string.format("Task %s ID=%d execute.", tostring(Task.description), Task.id) local text=string.format("Task %s ID=%d execute", tostring(Task.description), Task.id)
MESSAGE:New(text, 10, "DEBUG"):ToAllIf(self.Debug) MESSAGE:New(text, 10, "DEBUG"):ToAllIf(self.Debug)
self:I(self.lid..text) self:I(self.lid..text)

View File

@ -26,6 +26,8 @@
-- @field #number ngrouping User defined number of units in the asset group. -- @field #number ngrouping User defined number of units in the asset group.
-- @field #table assets Squadron assets. -- @field #table assets Squadron assets.
-- @field #table missiontypes Capabilities (mission types and performances) of the squadron. -- @field #table missiontypes Capabilities (mission types and performances) of the squadron.
-- @field #number maintenancetime Time in seconds needed for maintenance of a returned flight.
-- @field #number repairtime Time in seconds for each
-- @field #string livery Livery of the squadron. -- @field #string livery Livery of the squadron.
-- @field #number skill Skill of squadron members. -- @field #number skill Skill of squadron members.
-- @field #number modex Modex. -- @field #number modex Modex.
@ -67,6 +69,8 @@ SQUADRON = {
aircrafttype = nil, aircrafttype = nil,
assets = {}, assets = {},
missiontypes = {}, missiontypes = {},
repairtime = 0,
maintenancetime= 0,
livery = nil, livery = nil,
skill = nil, skill = nil,
modex = nil, modex = nil,
@ -233,6 +237,17 @@ function SQUADRON:SetSkill(Skill)
return self return self
end end
--- Set maintenance and repair time.
-- @param #SQUADRON self
-- @param #number MaintenanceTime Time in minutes it takes until a flight is combat ready again. Default is 0 min.
-- @param #number RepairTime Time in minutes it takes to repair a flight for each percent damage taken. Default is 0 min.
-- @return #SQUADRON self
function SQUADRON:SetMaintenanceTime(MaintenanceTime, RepairTime)
self.maintenancetime=MaintenanceTime and MaintenanceTime*60 or 0
self.repairtime=RepairTime and RepairTime*60 or 0
return self
end
--- Set radio frequency and modulation the squad uses. --- Set radio frequency and modulation the squad uses.
-- @param #SQUADRON self -- @param #SQUADRON self
-- @param #number Frequency Radio frequency in MHz. Default 251 MHz. -- @param #number Frequency Radio frequency in MHz. Default 251 MHz.
@ -683,12 +698,12 @@ function SQUADRON:RecruitAssets(Mission)
-- Asset is already on a mission. -- Asset is already on a mission.
--- ---
-- Check if this asset is currently on a PATROL mission (STARTED or EXECUTING). -- Check if this asset is currently on a GCCAP mission (STARTED or EXECUTING).
if self.airwing:IsAssetOnMission(asset, AUFTRAG.Type.PATROL) and Mission.type==AUFTRAG.Type.INTERCEPT then if self.airwing:IsAssetOnMission(asset, AUFTRAG.Type.GCCAP) and Mission.type==AUFTRAG.Type.INTERCEPT then
-- Check if the payload of this asset is compatible with the mission. -- Check if the payload of this asset is compatible with the mission.
-- Note: we do not check the payload as an asset that is on a PATROL mission should be able to do an INTERCEPT as well! -- Note: we do not check the payload as an asset that is on a GCCAP mission should be able to do an INTERCEPT as well!
self:I(self.lid.."Adding asset on PATROL mission for an INTERCEPT mission") self:I(self.lid.."Adding asset on GCCAP mission for an INTERCEPT mission")
table.insert(assets, asset) table.insert(assets, asset)
end end
@ -696,7 +711,7 @@ function SQUADRON:RecruitAssets(Mission)
else else
--- ---
-- Asset as no current mission -- Asset as NO current mission
--- ---
if asset.spawned then if asset.spawned then
@ -744,7 +759,7 @@ function SQUADRON:RecruitAssets(Mission)
--- ---
-- Check that asset is not already requested for another mission. -- Check that asset is not already requested for another mission.
if Npayloads>0 and not asset.requested then if Npayloads>0 and self:IsRepaired(asset) and (not asset.requested) then
-- Add this asset to the selection. -- Add this asset to the selection.
table.insert(assets, asset) table.insert(assets, asset)
@ -761,6 +776,26 @@ function SQUADRON:RecruitAssets(Mission)
return assets return assets
end end
--- Checks if a mission type is contained in a table of possible types.
-- @param #SQUADRON self
-- @param Ops.AirWing#AIRWING.SquadronAsset Asset The asset.
-- @return #boolean If true, the requested mission type is part of the possible mission types.
function SQUADRON:IsRepaired(Asset)
if Asset.Treturned then
local Tnow=timer.getAbsTime()
if Asset.Treturned+self.maintenancetime>=Tnow then
return true
else
return false
end
else
return true
end
end
--- Checks if a mission type is contained in a table of possible types. --- Checks if a mission type is contained in a table of possible types.
-- @param #SQUADRON self -- @param #SQUADRON self

View File

@ -16,11 +16,15 @@
-- @type TARGET -- @type TARGET
-- @field #string ClassName Name of the class. -- @field #string ClassName Name of the class.
-- @field #boolean Debug Debug mode. Messages to all about status. -- @field #boolean Debug Debug mode. Messages to all about status.
-- @field #number verbose Verbosity level.
-- @field #string lid Class id string for output to DCS log file. -- @field #string lid Class id string for output to DCS log file.
-- @field #table targets Table of target objects. -- @field #table targets Table of target objects.
-- @field #number targetcounter Running number to generate target object IDs. -- @field #number targetcounter Running number to generate target object IDs.
-- @field #number life Total life points on last status update. -- @field #number life Total life points on last status update.
-- @field #number life0 Total life points of completely healthy targets. -- @field #number life0 Total life points of completely healthy targets.
-- @field #number threatlevel0 Initial threat level.
-- @field #number category Target category (Ground, Air, Sea).
-- @field #number Ntargets0 Number of initial targets.
-- @extends Core.Fsm#FSM -- @extends Core.Fsm#FSM
--- **It is far more important to be able to hit the target than it is to haggle over who makes a weapon or who pulls a trigger** -- Dwight D. Eisenhower --- **It is far more important to be able to hit the target than it is to haggle over who makes a weapon or who pulls a trigger** -- Dwight D. Eisenhower
@ -38,11 +42,14 @@
TARGET = { TARGET = {
ClassName = "TARGET", ClassName = "TARGET",
Debug = nil, Debug = nil,
verbose = 0,
lid = nil, lid = nil,
targets = {}, targets = {},
targetcounter = 0, targetcounter = 0,
life = 0, life = 0,
life0 = 0, life0 = 0,
Ntargets0 = 0,
threatlevel0 = 0
} }
@ -60,7 +67,23 @@ TARGET.ObjectType={
AIRBASE="Airbase", AIRBASE="Airbase",
} }
--- Type.
--- Category.
-- @type TARGET.Category
-- @field #string AIRCRAFT
-- @field #string GROUND
-- @field #string NAVAL
-- @field #string AIRBASE
-- @field #string COORDINATE
TARGET.Category={
AIRCRAFT="Aircraft",
GROUND="Grund",
NAVAL="Naval",
AIRBASE="Airbase",
COORDINATE="Coordinate",
}
--- Object status.
-- @type TARGET.ObjectStatus -- @type TARGET.ObjectStatus
-- @field #string ALIVE Object is alive. -- @field #string ALIVE Object is alive.
-- @field #string DEAD Object is dead. -- @field #string DEAD Object is dead.
@ -106,10 +129,15 @@ function TARGET:New(TargetObject)
-- Increase counter. -- Increase counter.
_TARGETID=_TARGETID+1 _TARGETID=_TARGETID+1
self.lid=string.format("TARGET #%03d | ", _TARGETID) -- Add object.
self:AddObject(TargetObject) self:AddObject(TargetObject)
local Target=self.targets[1] --#TARGET.Object
self.category=self:GetTargetCategory(Target)
self.lid=string.format("TARGET #%03d %s | ", _TARGETID, self.category)
-- Start state. -- Start state.
self:SetStartState("Stopped") self:SetStartState("Stopped")
@ -180,17 +208,11 @@ end
-- @param Wrapper.Positionable#POSITIONABLE Object The target GROUP, UNIT, STATIC, AIRBASE or COORDINATE. -- @param Wrapper.Positionable#POSITIONABLE Object The target GROUP, UNIT, STATIC, AIRBASE or COORDINATE.
function TARGET:AddObject(Object) function TARGET:AddObject(Object)
if Object:IsInstanceOf("GROUP") then if Object:IsInstanceOf("SET_GROUP") or Object:IsInstanceOf("SET_UNIT") then
local group=Object --Wrapper.Group#GROUP ---
-- Sets
local units=group:GetUnits() ---
for _,unit in pairs(units) do
self:_AddObject(unit)
end
elseif Object:IsInstanceOf("SET_GROUP") or Object:IsInstanceOf("SET_UNIT") then
local set=Object --Core.Set#SET_GROUP local set=Object --Core.Set#SET_GROUP
@ -198,11 +220,10 @@ function TARGET:AddObject(Object)
self:AddObject(object) self:AddObject(object)
end end
else else
--- ---
-- Units, Statics, Airbases, Coordinates -- Groups, Units, Statics, Airbases, Coordinates
--- ---
self:_AddObject(Object) self:_AddObject(Object)
@ -265,7 +286,7 @@ function TARGET:onafterStatus(From, Event, To)
end end
-- Log output. -- Log output.
local text=string.format("%s: Targets=%d/%d Life=%.1f/%.1f Damage=%.1f", fsmstate, self:CountTargets(), #self.targets, self:GetLife(), self:GetLife0(), self:GetDamage()) local text=string.format("%s: Targets=%d/%d Life=%.1f/%.1f Damage=%.1f", fsmstate, self:CountTargets(), self.Ntargets0, self:GetLife(), self:GetLife0(), self:GetDamage())
if damaged then if damaged then
text=text.." Damaged!" text=text.." Damaged!"
end end
@ -277,7 +298,7 @@ function TARGET:onafterStatus(From, Event, To)
for i,_target in pairs(self.targets) do for i,_target in pairs(self.targets) do
local target=_target --#TARGET.Object local target=_target --#TARGET.Object
local damage=(1-target.Life/target.Life0)*100 local damage=(1-target.Life/target.Life0)*100
text=text..string.format("\n[%d] %s %s: Life=%.1f/%.1f, Damage=%.1f", i, target.Name, target.Status, target.Life, target.Life0, damage) text=text..string.format("\n[%d] %s %s %s: Life=%.1f/%.1f, Damage=%.1f", i, target.Type, target.Name, target.Status, target.Life, target.Life0, damage)
end end
self:I(self.lid..text) self:I(self.lid..text)
end end
@ -397,7 +418,30 @@ function TARGET:_AddObject(Object)
local target={} --#TARGET.Object local target={} --#TARGET.Object
if Object:IsInstanceOf("UNIT") then if Object:IsInstanceOf("GROUP") then
local group=Object --Wrapper.Group#GROUP
target.Type=TARGET.ObjectType.GROUP
target.Name=group:GetName()
local units=group:GetUnits()
target.Life=0 ; target.Life0=0
for _,_unit in pairs(units or {}) do
local unit=_unit --Wrapper.Unit#UNIT
local life=unit:GetLife()
target.Life=target.Life+life
target.Life0=target.Life0+math.max(unit:GetLife0(), life) -- There was an issue with ships that life is greater life0, which cannot be!
self.threatlevel0=self.threatlevel0+unit:GetThreatLevel()
self.Ntargets0=self.Ntargets0+1
end
elseif Object:IsInstanceOf("UNIT") then
local unit=Object --Wrapper.Unit#UNIT local unit=Object --Wrapper.Unit#UNIT
@ -407,6 +451,10 @@ function TARGET:_AddObject(Object)
if unit and unit:IsAlive() then if unit and unit:IsAlive() then
target.Life=unit:GetLife() target.Life=unit:GetLife()
target.Life0=math.max(unit:GetLife0(), target.Life) -- There was an issue with ships that life is greater life0! target.Life0=math.max(unit:GetLife0(), target.Life) -- There was an issue with ships that life is greater life0!
self.threatlevel0=self.threatlevel0+unit:GetThreatLevel()
self.Ntargets0=self.Ntargets0+1
end end
elseif Object:IsInstanceOf("STATIC") then elseif Object:IsInstanceOf("STATIC") then
@ -419,6 +467,8 @@ function TARGET:_AddObject(Object)
if static and static:IsAlive() then if static and static:IsAlive() then
target.Life0=1 target.Life0=1
target.Life=1 target.Life=1
self.Ntargets0=self.Ntargets0+1
end end
@ -432,6 +482,7 @@ function TARGET:_AddObject(Object)
target.Life0=1 target.Life0=1
target.Life=1 target.Life=1
self.Ntargets0=self.Ntargets0+1
elseif Object:IsInstanceOf("COORDINATE") then elseif Object:IsInstanceOf("COORDINATE") then
@ -443,6 +494,9 @@ function TARGET:_AddObject(Object)
target.Life0=1 target.Life0=1
target.Life=1 target.Life=1
-- TODO: does this make sense for a coordinate?
--self.Ntargets0=self.Ntargets0+1
else else
self:E(self.lid.."ERROR: Unknown object type!") self:E(self.lid.."ERROR: Unknown object type!")
return nil return nil
@ -488,7 +542,24 @@ end
-- @return #number Life points of target. -- @return #number Life points of target.
function TARGET:GetTargetLife(Target) function TARGET:GetTargetLife(Target)
if Target.Type==TARGET.ObjectType.UNIT then if Target.Type==TARGET.ObjectType.GROUP then
if Target.Object and Target.Object:IsAlive() then
local units=Target.Object:GetUnits()
local life=0
for _,_unit in pairs(units or {}) do
local unit=_unit --Wrapper.Unit#UNIT
life=life+unit:GetLife()
end
return life
else
return 0
end
elseif Target.Type==TARGET.ObjectType.UNIT then
if Target.Object and Target.Object:IsAlive() then if Target.Object and Target.Object:IsAlive() then
return Target.Object:GetLife() return Target.Object:GetLife()
@ -527,18 +598,6 @@ function TARGET:GetLife()
local N=0 local N=0
local function _GetLife(unit)
local unit=unit --Wrapper.Unit#UNIT
if Healthy then
local life=unit:GetLife()
local life0=unit:GetLife0()
return math.max(life, life0)
else
return unit:GetLife()
end
end
for _,_target in pairs(self.targets) do for _,_target in pairs(self.targets) do
local Target=_target --#TARGET.Object local Target=_target --#TARGET.Object
@ -549,6 +608,132 @@ function TARGET:GetLife()
return N return N
end end
--- Get target coordinate.
-- @param #TARGET self
-- @param #TARGET.Object Target Target object.
-- @return Core.Point#COORDINATE Coordinate of the target.
function TARGET:GetTargetCoordinate(Target)
if Target.Type==TARGET.ObjectType.GROUP then
if Target.Object and Target.Object:IsAlive() then
return Target.Object:GetCoordinate()
end
elseif Target.Type==TARGET.ObjectType.UNIT then
if Target.Object and Target.Object:IsAlive() then
return Target.Object:GetCoordinate()
end
elseif Target.Type==TARGET.ObjectType.STATIC then
if Target.Object and Target.Object:IsAlive() then
return Target.Object:GetCoordinate()
end
elseif Target.Type==TARGET.ObjectType.AIRBASE then
if Target.Status==TARGET.ObjectStatus.ALIVE then
return Target.Object:GetCoordinate()
end
elseif Target.Type==TARGET.ObjectType.COORDINATE then
return Target.Object
end
return nil
end
--- Get coordinate.
-- @param #TARGET self
-- @return Core.Point#COORDINATE Coordinate of the target.
function TARGET:GetCoordinate()
for _,_target in pairs(self.targets) do
local Target=_target --#TARGET.Object
local coordinate=self:GetTargetCoordinate(Target)
if coordinate then
return coordinate
end
end
return nil
end
--- Get target category
-- @param #TARGET self
-- @param #TARGET.Object Target Target object.
-- @return #TARGET.Category Target category.
function TARGET:GetTargetCategory(Target)
local category=nil
if Target.Type==TARGET.ObjectType.GROUP then
if Target.Object and Target.Object:IsAlive()~=nil then
local group=Target.Object --Wrapper.Group#GROUP
local cat=group:GetCategory()
if cat==Group.Category.AIRPLANE or cat==Group.Category.HELICOPTER then
category=TARGET.Category.AIRCRAFT
elseif cat==Group.Category.GROUND or cat==Group.Category.TRAIN then
category=TARGET.Category.GROUND
elseif cat==Group.Category.SHIP then
category=TARGET.Category.NAVAL
end
end
elseif Target.Type==TARGET.ObjectType.UNIT then
if Target.Object and Target.Object:IsAlive() then
local unit=Target.Object --Wrapper.Unit#UNIT
local group=unit:GetGroup()
local cat=group:GetCategory()
if cat==Group.Category.AIRPLANE or cat==Group.Category.HELICOPTER then
category=TARGET.Category.AIRCRAFT
elseif cat==Group.Category.GROUND or cat==Group.Category.TRAIN then
category=TARGET.Category.GROUND
elseif cat==Group.Category.SHIP then
category=TARGET.Category.NAVAL
end
end
elseif Target.Type==TARGET.ObjectType.STATIC then
return TARGET.Category.GROUND
elseif Target.Type==TARGET.ObjectType.AIRBASE then
return TARGET.Category.AIRBASE
elseif Target.Type==TARGET.ObjectType.COORDINATE then
return TARGET.Category.COORDINATE
end
return category
end
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Misc Functions -- Misc Functions
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
@ -580,7 +765,20 @@ function TARGET:CountTargets()
for _,_target in pairs(self.targets) do for _,_target in pairs(self.targets) do
local Target=_target --#TARGET.Object local Target=_target --#TARGET.Object
if Target.Type==TARGET.ObjectType.UNIT then if Target.Type==TARGET.ObjectType.GROUP then
local target=Target.Object --Wrapper.Group#GROUP
local units=target:GetUnits()
for _,_unit in pairs(units or {}) do
local unit=_unit --Wrapper.Unit#UNIT
if unit and unit:IsAlive() and unit:GetLife()>1 then
N=N+1
end
end
elseif Target.Type==TARGET.ObjectType.UNIT then
local target=Target.Object --Wrapper.Unit#UNIT local target=Target.Object --Wrapper.Unit#UNIT

View File

@ -2213,6 +2213,45 @@ function GROUP:GetDCSDesc(n)
return nil return nil
end end
--- Get health of the group.
-- @param #GROUP self
-- @return #number Health in percent.
function GROUP:GetHealth()
local lp=0
local lp0=0
local units=self:GetUnits()
for _,_unit in pairs(units or {}) do
local unit=_unit --Wrapper.Unit#UNIT
if unit and unit:IsAlive() then
local life=unit:GetLife()
local life0=unit:GetLife0()
life0=math.max(life0, life) --Issue with ships
lp=lp+life
lp0=lp0+life
end
end
if lp0>0 then
return lp/lp0*100
else
return 0
end
end
--- Get damage of the group.
-- @param #GROUP self
-- @return #number Damage in percent.
function GROUP:GetDamage()
return 100-self:GetHealth()
end
--- Get the generalized attribute of a self. --- Get the generalized attribute of a self.
-- Note that for a heterogenious self, the attribute is determined from the attribute of the first unit! -- Note that for a heterogenious self, the attribute is determined from the attribute of the first unit!