Merge branch 'FF/Ops' into FF/OpsDev

This commit is contained in:
Frank 2024-01-23 11:05:50 +01:00
commit d82df93eff
15 changed files with 171 additions and 49 deletions

View File

@ -297,8 +297,8 @@ end
--- Get COORDINATES of pathline. Note that COORDINATE objects are created when calling this function. That does involve deep copy calls and can have an impact on performance if done too often.
-- @param #PATHLINE self
-- @return #list <Core.Point#COORDINATE> List of COORDINATES points.
function PATHLINE:GetCoordinats()
-- @return <Core.Point#COORDINATE> List of COORDINATES points.
function PATHLINE:GetCoordinates()
local vecs={}
@ -324,7 +324,7 @@ function PATHLINE:GetPointFromIndex(n)
local point=nil --#PATHLINE.Point
if n>=1 and n<=N then
point=self.point[n]
point=self.points[n]
else
self:E(self.lid..string.format("ERROR: No point in pathline for N=%s", tostring(n)))
end

View File

@ -1204,7 +1204,7 @@ do
if not DontSetCargoBayLimit then
-- I set the default cargo bay weight limit each time a new group is added to the set.
-- TODO Why is this here in the first place?
for UnitID, UnitData in pairs( group:GetUnits() ) do
for UnitID, UnitData in pairs( group:GetUnits() or {} ) do
if UnitData and UnitData:IsAlive() then
UnitData:SetCargoBayWeightLimit()
end
@ -8399,7 +8399,7 @@ do -- SET_SCENERY
--- Calculate current relative lifepoints of the SET objects, i.e. Life divided by Life0 as percentage value, eg 75 meaning 75% alive.
-- **CAVEAT**: Some objects change their life value or "hitpoints" **after** the first hit. Hence we will adjust the Life0 value to 120%
-- of the last life value if life exceeds life0 ata any point.
-- Thus will will get a smooth percentage decrease, if you use this e.g. as success criteria for a bombing task.
-- Thus we will get a smooth percentage decrease, if you use this e.g. as success criteria for a bombing task.
-- @param #SET_SCENERY self
-- @return #number LifePoints
function SET_SCENERY:GetRelativeLife()

View File

@ -176,7 +176,7 @@ STRATEGO = {
debug = false,
drawzone = false,
markzone = false,
version = "0.2.3",
version = "0.2.4",
portweight = 3,
POIweight = 1,
maxrunways = 3,
@ -435,7 +435,9 @@ function STRATEGO:AnalyseBases()
if not abzone then
abzone = ZONE_RADIUS:New(abname,ab:GetVec2(),500)
end
local coa = ab:GetCoalition() + 1
local coa = ab:GetCoalition()
if coa == nil then return end -- Spawned FARPS issue - these have no tangible data
coa = coa+1
local abtype = "AIRBASE"
if ab:IsShip() then
numrwys = 1
@ -946,22 +948,22 @@ function STRATEGO:FindClosestConsolidationTarget(Startpoint,BaseWeight)
return shortest,target, weight, coa
end
--- [USER] Get the next best strategic target node with same or higher BaseWeight.
--- [USER] Get the next best strategic target node with same or higher Consolidated Weight.
-- @param #STRATEGO self
-- @param #string Startpoint Name of start point.
-- @param #number BaseWeight Base weight of the node, e.g. the number of runways of an airbase or the weight of ports or POIs.
-- @param #number Weight Consolidated Weight of the node, i.e. the calculated weight of the node based on number of runways, connections and a weight factor.
-- @return #number ShortestDist Shortest distance found.
-- @return #string Name Name of the target node.
-- @return #number Weight Consolidated weight of the target node, zero if none found.
-- @return #number Coalition Coaltion of the target.
function STRATEGO:FindClosestStrategicTarget(Startpoint,BaseWeight)
self:T(self.lid.."FindClosestStrategicTarget")
function STRATEGO:FindClosestStrategicTarget(Startpoint,Weight)
self:T(self.lid.."FindClosestStrategicTarget for "..Startpoint.." Weight "..Weight or 0)
-- find existing routes
local shortest = 1000*1000
local target = nil
local weight = 0
local coa = nil
if not BaseWeight then BaseWeight = self.maxrunways end
if not Weight then Weight = self.maxrunways end
local startpoint = string.gsub(Startpoint,"[%p%s]",".")
for _,_route in pairs(self.routexists) do
if string.find(_route,startpoint,1,true) then
@ -969,7 +971,11 @@ function STRATEGO:FindClosestStrategicTarget(Startpoint,BaseWeight)
local tname = string.gsub(_route,startpoint,"")
local tname = string.gsub(tname,";","")
local cname = self.easynames[tname]
if dist < shortest and self.airbasetable[cname].coalition ~= self.coalition and self.airbasetable[cname].baseweight >= BaseWeight then
local coa = self.airbasetable[cname].coalition
local tweight = self.airbasetable[cname].baseweight
local ttweight = self.airbasetable[cname].weight
self:T("Start -> End: "..startpoint.." -> "..cname)
if (dist < shortest) and (coa ~= self.coalition) and (tweight >= Weight) then
shortest = dist
target = cname
weight = self.airbasetable[cname].weight
@ -989,7 +995,7 @@ function STRATEGO:FindStrategicTargets()
for _,_data in pairs(self.airbasetable) do
local data = _data -- #STRATEGO.Data
if data.coalition == self.coalition then
local dist, name, points, coa = self:FindClosestStrategicTarget(data.name,self.maxrunways)
local dist, name, points, coa = self:FindClosestStrategicTarget(data.name,data.weight)
if coa == coalition.side.NEUTRAL and points ~= 0 then
local fpoints = points + self.NeutralBenefit
local tries = 1

View File

@ -3414,7 +3414,7 @@ end
-- FSM states
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- On after Start event. Starts the warehouse. Addes event handlers and schedules status updates of reqests and queue.
--- On after Start event. Starts the warehouse. Adds event handlers and schedules status updates of reqests and queue.
-- @param #WAREHOUSE self
-- @param #string From From state.
-- @param #string Event Event.
@ -3595,6 +3595,7 @@ function WAREHOUSE:onafterStatus(From, Event, To)
local Trepair=self:GetRunwayRepairtime()
self:I(self.lid..string.format("Runway destroyed! Will be repaired in %d sec", Trepair))
if Trepair==0 then
self.runwaydestroyed = nil
self:RunwayRepaired()
end
end
@ -5393,6 +5394,7 @@ function WAREHOUSE:onafterRunwayDestroyed(From, Event, To)
self.runwaydestroyed=timer.getAbsTime()
return self
end
--- On after "RunwayRepaired" event.
@ -5408,6 +5410,7 @@ function WAREHOUSE:onafterRunwayRepaired(From, Event, To)
self.runwaydestroyed=nil
return self
end

View File

@ -700,7 +700,7 @@ ATIS.Messages = {
EN =
{
HOURS = "hours",
TIME = "hours",
TIME = "Hours",
NOCLOUDINFO = "Cloud coverage information not available",
OVERCAST = "Overcast",
BROKEN = "Broken clouds",

View File

@ -56,6 +56,8 @@
-- @field #boolean despawnAfterHolding Aircraft are despawned after holding.
-- @field #boolean capOptionPatrolRaceTrack Use closer patrol race track or standard orbit auftrag.
-- @field #number capFormation If capOptionPatrolRaceTrack is true, set the formation, also.
-- @field #number capOptionVaryStartTime If set, vary mission start time for CAP missions generated random between capOptionVaryStartTime and capOptionVaryEndTime
-- @field #number capOptionVaryEndTime If set, vary mission start time for CAP missions generated random between capOptionVaryStartTime and capOptionVaryEndTime
--
-- @extends Ops.Legion#LEGION
@ -132,6 +134,8 @@ AIRWING = {
markpoints = false,
capOptionPatrolRaceTrack = false,
capFormation = nil,
capOptionVaryStartTime = nil,
capOptionVaryEndTime = nil,
}
--- Payload data.
@ -183,7 +187,7 @@ AIRWING = {
--- AIRWING class version.
-- @field #string version
AIRWING.version="0.9.4"
AIRWING.version="0.9.5"
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- ToDo list
@ -721,6 +725,17 @@ function AIRWING:SetCapCloseRaceTrack(OnOff)
return self
end
--- Set CAP mission start to vary randomly between Start end End seconds.
-- @param #AIRWING self
-- @param #number Start
-- @param #number End
-- @return #AIRWING self
function AIRWING:SetCapStartTimeVariation(Start, End)
self.capOptionVaryStartTime = Start or 5
self.capOptionVaryEndTime = End or 60
return self
end
--- Set number of TANKER flights with Boom constantly in the air.
-- @param #AIRWING self
-- @param #number Nboom Number of flights. Default 1.
@ -1165,6 +1180,14 @@ function AIRWING:CheckCAP()
end
if self.capOptionVaryStartTime then
local ClockStart = math.random(self.capOptionVaryStartTime, self.capOptionVaryEndTime)
missionCAP:SetTime(ClockStart)
end
missionCAP.patroldata=patrol
patrol.noccupied=patrol.noccupied+1

View File

@ -121,6 +121,7 @@ do
-- @field #number TacticalIncrFreq
-- @field #number TacticalModulation
-- @field #number TacticalInterval
-- @field Core.Set#SET_GROUP DetectionSet
-- @extends Core.Fsm#FSM
@ -603,6 +604,7 @@ AWACS = {
TacticalIncrFreq = 0.5,
TacticalModulation = radio.modulation.AM,
TacticalInterval = 120,
DetectionSet = nil,
}
---

View File

@ -458,6 +458,17 @@ function EASYGCICAP:SetDefaultOverhead(Overhead)
return self
end
--- Set CAP mission start to vary randomly between Start end End seconds.
-- @param #EASYGCICAP self
-- @param #number Start
-- @param #number End
-- @return #EASYGCICAP self
function EASYGCICAP:SetCapStartTimeVariation(Start, End)
self.capOptionVaryStartTime = Start or 5
self.capOptionVaryEndTime = End or 60
return self
end
--- Add an AirWing to the manager
-- @param #EASYGCICAP self
-- @param #string Airbasename
@ -511,6 +522,11 @@ function EASYGCICAP:_AddAirwing(Airbasename, Alias)
CAP_Wing:SetRespawnAfterDestroyed()
CAP_Wing:SetNumberCAP(self.capgrouping)
CAP_Wing:SetCapCloseRaceTrack(true)
if self.capOptionVaryStartTime then
CAP_Wing:SetCapStartTimeVariation(self.capOptionVaryStartTime,self.capOptionVaryEndTime)
end
if CapFormation then
CAP_Wing:SetCAPFormation(CapFormation)
end

View File

@ -2360,7 +2360,8 @@ function FLIGHTGROUP:onafterCruise(From, Event, To)
-- CLIENT
---
--self:_UpdateMenu(0.1)
-- Had this commented out (forgot why, probably because it was not necessary) but re-enabling it because of carrier launch.
self:_UpdateMenu(0.1)
end

View File

@ -578,7 +578,7 @@ function INTEL:AddAgent(AgentGroup)
end
-- Add to detection set.
self.detectionset:AddGroup(AgentGroup)
self.detectionset:AddGroup(AgentGroup,true)
return self
end

View File

@ -98,7 +98,7 @@ PLAYERTASK = {
--- PLAYERTASK class version.
-- @field #string version
PLAYERTASK.version="0.1.23"
PLAYERTASK.version="0.1.24"
--- Generic task condition.
-- @type PLAYERTASK.Condition
@ -1966,6 +1966,8 @@ end
-- Can optionally be handed as Ops.ArmyGroup#ARMYGROUP - **Note** might not find an LOS spot or get lost on the way. Cannot island-hop.
-- @param #number LaserCode The lasercode to be used. Defaults to 1688.
-- @param Core.Point#COORDINATE HoldingPoint (Optional) Point where the drone should initially circle. If not set, defaults to BullsEye of the coalition.
-- @param #number Alt (Optional) Altitude in feet. Only applies if using a FLIGHTGROUP object! Defaults to 10000.
-- @param #number Speed (Optional) Speed in knots. Only applies if using a FLIGHTGROUP object! Defaults to 120.
-- @return #PLAYERTASKCONTROLLER self
-- @usage
-- -- Set up precision bombing, FlightGroup as lasing unit
@ -1980,7 +1982,7 @@ end
-- ArmyGroup:Activate()
-- taskmanager:EnablePrecisionBombing(ArmyGroup,1688)
--
function PLAYERTASKCONTROLLER:EnablePrecisionBombing(FlightGroup,LaserCode,HoldingPoint)
function PLAYERTASKCONTROLLER:EnablePrecisionBombing(FlightGroup,LaserCode,HoldingPoint, Alt, Speed)
self:T(self.lid.."EnablePrecisionBombing")
if FlightGroup then
if FlightGroup.ClassName and (FlightGroup.ClassName == "FLIGHTGROUP" or FlightGroup.ClassName == "ARMYGROUP")then
@ -1993,11 +1995,20 @@ function PLAYERTASKCONTROLLER:EnablePrecisionBombing(FlightGroup,LaserCode,Holdi
self.LasingDrone:SetLaser(LaserCode)
self.LaserCode = LaserCode or 1688
self.LasingDroneTemplate = self.LasingDrone:_GetTemplate(true)
self.LasingDroneAlt = Alt or 10000
self.LasingDroneSpeed = Speed or 120
-- let it orbit the BullsEye if FG
if self.LasingDrone:IsFlightgroup() then
self.LasingDroneIsFlightgroup = true
local BullsCoordinate = COORDINATE:NewFromVec3( coalition.getMainRefPoint( self.Coalition ))
if HoldingPoint then BullsCoordinate = HoldingPoint end
local Orbit = AUFTRAG:NewORBIT_CIRCLE(BullsCoordinate,10000,120)
local Orbit = AUFTRAG:NewORBIT_CIRCLE(BullsCoordinate,self.LasingDroneAlt,self.LasingDroneSpeed)
self.LasingDrone:AddMission(Orbit)
elseif self.LasingDrone:IsArmygroup() then
self.LasingDroneIsArmygroup = true
local BullsCoordinate = COORDINATE:NewFromVec3( coalition.getMainRefPoint( self.Coalition ))
if HoldingPoint then BullsCoordinate = HoldingPoint end
local Orbit = AUFTRAG:NewONGUARD(BullsCoordinate)
self.LasingDrone:AddMission(Orbit)
end
else
@ -2536,10 +2547,16 @@ function PLAYERTASKCONTROLLER:_CheckPrecisionTasks()
if self.LasingDrone then
self.LasingDrone:_Respawn(1,nil,true)
else
-- TODO: Handle ArmyGroup
-- DONE: Handle ArmyGroup
if self.LasingDroneIsFlightgroup then
local FG = FLIGHTGROUP:New(self.LasingDroneTemplate)
FG:Activate()
self:EnablePrecisionBombing(FG,self.LaserCode or 1688)
else
local FG = ARMYGROUP:New(self.LasingDroneTemplate)
FG:Activate()
self:EnablePrecisionBombing(FG,self.LaserCode or 1688)
end
end
return self
end
@ -2554,13 +2571,11 @@ function PLAYERTASKCONTROLLER:_CheckPrecisionTasks()
self.LasingDrone.playertask.inreach = false
self.LasingDrone.playertask.reachmessage = false
-- move the drone to target
if self.LasingDrone:IsFlightgroup() then
if self.LasingDroneIsFlightgroup then
self.LasingDrone:CancelAllMissions()
local auftrag = AUFTRAG:NewORBIT_CIRCLE(task.Target:GetCoordinate(),10000,120)
--local currmission = self.LasingDrone:GetMissionCurrent()
local auftrag = AUFTRAG:NewORBIT_CIRCLE(task.Target:GetCoordinate(),self.LasingDroneAlt,self.LasingDroneSpeed)
self.LasingDrone:AddMission(auftrag)
--currmission:__Cancel(-2)
elseif self.LasingDrone:IsArmygroup() then
elseif self.LasingDroneIsArmygroup then
local tgtcoord = task.Target:GetCoordinate()
local tgtzone = ZONE_RADIUS:New("ArmyGroup-"..math.random(1,10000),tgtcoord:GetVec2(),3000)
local finalpos=nil -- Core.Point#COORDINATE
@ -2573,11 +2588,10 @@ function PLAYERTASKCONTROLLER:_CheckPrecisionTasks()
end
end
if finalpos then
self.LasingDrone:CancelAllMissions()
-- yeah we got one
local auftrag = AUFTRAG:NewARMOREDGUARD(finalpos,"Off road")
local currmission = self.LasingDrone:GetMissionCurrent()
self.LasingDrone:AddMission(auftrag)
if currmission then currmission:__Cancel(-2) end
else
-- could not find LOS position!
self:E("***Could not find LOS position to post ArmyGroup for lasing!")

View File

@ -1107,7 +1107,7 @@ function TARGET:GetTargetLife(Target)
elseif Target.Type==TARGET.ObjectType.SCENERY then
if Target.Object and Target.Object:IsAlive() then
if Target.Object and Target.Object:IsAlive(25) then
local life = Target.Object:GetLife()
return life
else

View File

@ -2084,7 +2084,16 @@ function AIRBASE:_InitRunways(IncludeInverse)
-- Data table.
local runway={} --#AIRBASE.Runway
local namefromheading = math.floor(heading/10)
if self.AirbaseName == AIRBASE.Syria.Beirut_Rafic_Hariri and math.abs(namefromheading-name) > 1 then
runway.name=string.format("%02d", tonumber(namefromheading))
else
runway.name=string.format("%02d", tonumber(name))
end
--runway.name=string.format("%02d", tonumber(name))
runway.magheading=tonumber(runway.name)*10
runway.heading=heading
runway.width=width or 0

View File

@ -938,20 +938,22 @@ end
-- @param #CONTROLLABLE self
-- @param #number Frequency Radio frequency in MHz.
-- @param #number Modulation Radio modulation. Default `radio.modulation.AM`.
-- @param #number Power (Optional) Power of the Radio in Watts. Defaults to 10.
-- @param #number Delay (Optional) Delay in seconds before the frequency is set. Default is immediately.
-- @return #CONTROLLABLE self
function CONTROLLABLE:CommandSetFrequency( Frequency, Modulation, Delay )
function CONTROLLABLE:CommandSetFrequency( Frequency, Modulation, Power, Delay )
local CommandSetFrequency = {
id = 'SetFrequency',
params = {
frequency = Frequency * 1000000,
modulation = Modulation or radio.modulation.AM,
power=Power or 10,
},
}
if Delay and Delay > 0 then
SCHEDULER:New( nil, self.CommandSetFrequency, { self, Frequency, Modulation }, Delay )
SCHEDULER:New( nil, self.CommandSetFrequency, { self, Frequency, Modulation, Power } )
else
self:SetCommand( CommandSetFrequency )
end
@ -959,6 +961,32 @@ function CONTROLLABLE:CommandSetFrequency( Frequency, Modulation, Delay )
return self
end
--- [AIR] Set radio frequency. See [DCS command EPLRS](https://wiki.hoggitworld.com/view/DCS_command_setFrequencyForUnit)
-- @param #CONTROLLABLE self
-- @param #number Frequency Radio frequency in MHz.
-- @param #number Modulation Radio modulation. Default `radio.modulation.AM`.
-- @param #number Power (Optional) Power of the Radio in Watts. Defaults to 10.
-- @param #UnitID UnitID (Optional, if your object is a UNIT) The UNIT ID this is for.
-- @param #number Delay (Optional) Delay in seconds before the frequency is set. Default is immediately.
-- @return #CONTROLLABLE self
function CONTROLLABLE:CommandSetFrequencyForUnit(Frequency,Modulation,Power,UnitID,Delay)
local CommandSetFrequencyForUnit={
id='SetFrequencyForUnit',
params={
frequency=Frequency*1000000,
modulation=Modulation or radio.modulation.AM,
unitId=UnitID or self:GetID(),
power=Power or 10,
},
}
if Delay and Delay>0 then
SCHEDULER:New(nil,self.CommandSetFrequencyForUnit,{self,Frequency,Modulation,Power,UnitID})
else
self:SetCommand(CommandSetFrequencyForUnit)
end
return self
end
--- Set EPLRS data link on/off.
-- @param #CONTROLLABLE self
-- @param #boolean SwitchOnOff If true (or nil) switch EPLRS on. If false switch off.

View File

@ -123,16 +123,36 @@ end
--- Check if SCENERY Object is alive.
--@param #SCENERY self
--@param #number Threshold (Optional) If given, SCENERY counts as alive above this relative life in percent (1..100).
--@return #number life
function SCENERY:IsAlive()
function SCENERY:IsAlive(Threshold)
if not Threshold then
return self:GetLife() >= 1 and true or false
else
return self:GetRelativeLife() > Threshold and true or false
end
end
--- Check if SCENERY Object is dead.
--@param #SCENERY self
--@param #number Threshold (Optional) If given, SCENERY counts as dead below this relative life in percent (1..100).
--@return #number life
function SCENERY:IsDead()
function SCENERY:IsDead(Threshold)
if not Threshold then
return self:GetLife() < 1 and true or false
else
return self:GetRelativeLife() <= Threshold and true or false
end
end
--- Get SCENERY relative life in percent, e.g. 75.
--@param #SCENERY self
--@return #number rlife
function SCENERY:GetRelativeLife()
local life = self:GetLife()
local life0 = self:GetLife0()
local rlife = math.floor((life/life0)*100)
return rlife
end
--- Get the threat level of a SCENERY object. Always 0 as scenery does not pose a threat to anyone.