Merge remote-tracking branch 'origin/develop' into develop

This commit is contained in:
Applevangelist
2023-02-23 10:20:22 +01:00
19 changed files with 1089 additions and 927 deletions

View File

@@ -68,7 +68,7 @@ ARMYGROUP = {
--- Army Group version.
-- @field #string version
ARMYGROUP.version="0.9.0"
ARMYGROUP.version="1.0.0"
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO list

View File

@@ -158,6 +158,7 @@
-- @field Core.Point#COORDINATE missionWaypointCoord Mission waypoint coordinate.
-- @field Core.Point#COORDINATE missionEgressCoord Mission egress waypoint coordinate.
-- @field #number missionWaypointRadius Random radius in meters.
-- @field #boolean legionReturn If `true`, assets return to their legion (default). If `false`, they will stay alive.
--
-- @field #table enrouteTasks Mission enroute tasks.
--
@@ -639,7 +640,7 @@ AUFTRAG.Category={
--- AUFTRAG class version.
-- @field #string version
AUFTRAG.version="0.9.10"
AUFTRAG.version="1.1.0"
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO list
@@ -648,6 +649,7 @@ AUFTRAG.version="0.9.10"
-- TODO: Replace engageRange by missionRange. Here and in other classes. CTRL+H is your friend!
-- TODO: Mission success options damaged, destroyed.
-- TODO: F10 marker to create new missions.
-- DONE: Add option that assets do not return to their legion.
-- DONE: Add Capture zone task.
-- DONE: Add orbit mission for moving anker points.
-- DONE: Add recovery tanker mission for boat ops.
@@ -1039,7 +1041,7 @@ end
-- @param #AUFTRAG self
-- @param Core.Point#COORDINATE Coordinate Where to orbit.
-- @param #number Altitude Orbit altitude in feet above sea level. Default is y component of `Coordinate`.
-- @param #number Speed Orbit speed in knots. Default 350 KIAS.
-- @param #number Speed Orbit indicated airspeed in knots at the set altitude ASL. Default 350 KIAS.
-- @param #number Heading Heading of race-track pattern in degrees. If not specified, a circular orbit is performed.
-- @param #number Leg Length of race-track in NM. If not specified, a circular orbit is performed.
-- @return #AUFTRAG self
@@ -1058,7 +1060,8 @@ function AUFTRAG:NewORBIT(Coordinate, Altitude, Speed, Heading, Leg)
end
-- Orbit speed in m/s.
mission.orbitSpeed = UTILS.KnotsToMps(UTILS.KnotsToAltKIAS(Speed or 350, UTILS.MetersToFeet(mission.orbitAltitude)))
--mission.orbitSpeed = UTILS.KnotsToMps(UTILS.KnotsToAltKIAS(Speed or 350, UTILS.MetersToFeet(mission.orbitAltitude)))
mission.orbitSpeed = UTILS.TasToIas(UTILS.KnotsToMps(Speed or 350), mission.orbitAltitude)
-- Mission speed in km/h.
mission.missionSpeed = UTILS.KnotsToKmph(Speed or 350)
@@ -1093,7 +1096,7 @@ end
-- @param #AUFTRAG self
-- @param Core.Point#COORDINATE Coordinate Position where to orbit around.
-- @param #number Altitude Orbit altitude in feet. Default is y component of `Coordinate`.
-- @param #number Speed Orbit speed in knots. Default 350 KIAS.
-- @param #number Speed Orbit indicated airspeed in knots at the set altitude ASL. Default 350 KIAS.
-- @return #AUFTRAG self
function AUFTRAG:NewORBIT_CIRCLE(Coordinate, Altitude, Speed)
@@ -1106,7 +1109,7 @@ end
-- @param #AUFTRAG self
-- @param Core.Point#COORDINATE Coordinate Where to orbit.
-- @param #number Altitude Orbit altitude in feet. Default is y component of `Coordinate`.
-- @param #number Speed Orbit speed in knots. Default 350 KIAS.
-- @param #number Speed Orbit indicated airspeed in knots at the set altitude ASL. Default 350 KIAS.
-- @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.
-- @return #AUFTRAG self
@@ -1124,7 +1127,7 @@ end
-- @param #AUFTRAG self
-- @param Wrapper.Group#GROUP Group Group where to orbit around. Can also be a UNIT object.
-- @param #number Altitude Orbit altitude in feet. Default is 6,000 ft.
-- @param #number Speed Orbit speed in knots. Default 350 KIAS.
-- @param #number Speed Orbit indicated airspeed in knots at the set altitude ASL. Default 350 KIAS.
-- @param #number Leg Length of race-track in NM. Default nil.
-- @param #number Heading Heading of race-track pattern in degrees. Default is heading of the group.
-- @param DCS#Vec2 OffsetVec2 Offset 2D-vector {x=0, y=0} in NM with respect to the group. Default directly overhead. Can also be given in polar coordinates `{r=5, phi=45}`.
@@ -1172,7 +1175,7 @@ end
-- @param #AUFTRAG self
-- @param Core.Point#COORDINATE Coordinate Where to orbit.
-- @param #number Altitude Orbit altitude in feet. Default is y component of `Coordinate`.
-- @param #number Speed Orbit speed in knots. Default 350 kts.
-- @param #number Speed Orbit indicated airspeed in knots at the set altitude ASL. Default 350 KIAS.
-- @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.
-- @return #AUFTRAG self
@@ -1199,7 +1202,7 @@ end
-- @param #AUFTRAG self
-- @param Core.Point#COORDINATE Coordinate Where to orbit.
-- @param #number Altitude Orbit altitude in feet. Default is y component of `Coordinate`.
-- @param #number Speed Orbit speed in knots. Default 350 kts.
-- @param #number Speed Orbit indicated airspeed in knots at the set altitude ASL. Default 350 KIAS.
-- @param #number Heading Heading of race-track pattern in degrees. Default 270 (East to West).
-- @param #number Leg Length of race-track in NM. Default 10 NM.
-- @param #number RefuelSystem Refueling system (0=boom, 1=probe). This info is *only* for AIRWINGs so they launch the right tanker type.
@@ -1296,11 +1299,7 @@ end
function AUFTRAG:NewCAP(ZoneCAP, Altitude, Speed, Coordinate, Heading, Leg, TargetTypes)
-- Ensure given TargetTypes parameter is a table.
if TargetTypes then
if type(TargetTypes)~="table" then
TargetTypes={TargetTypes}
end
end
TargetTypes=UTILS.EnsureTable(TargetTypes, true)
-- Create ORBIT first.
local mission=AUFTRAG:NewORBIT(Coordinate or ZoneCAP:GetCoordinate(), Altitude or 10000, Speed or 350, Heading, Leg)
@@ -1342,11 +1341,8 @@ end
function AUFTRAG:NewCAPGROUP(Grp, Altitude, Speed, RelHeading, Leg, OffsetDist, OffsetAngle, UpdateDistance, TargetTypes, EngageRange)
-- Ensure given TargetTypes parameter is a table.
if TargetTypes then
if type(TargetTypes)~="table" then
TargetTypes={TargetTypes}
end
end
TargetTypes=UTILS.EnsureTable(TargetTypes, true)
-- Six NM astern.
local OffsetVec2={r=OffsetDist or 6, phi=OffsetAngle or 180}
@@ -1395,11 +1391,7 @@ end
function AUFTRAG:NewCAS(ZoneCAS, Altitude, Speed, Coordinate, Heading, Leg, TargetTypes)
-- Ensure given TargetTypes parameter is a table.
if TargetTypes then
if type(TargetTypes)~="table" then
TargetTypes={TargetTypes}
end
end
TargetTypes=UTILS.EnsureTable(TargetTypes, true)
-- Create ORBIT first.
local mission=AUFTRAG:NewORBIT(Coordinate or ZoneCAS:GetCoordinate(), Altitude or 10000, Speed, Heading, Leg)
@@ -2428,9 +2420,9 @@ function AUFTRAG:NewFromTarget(Target, MissionType)
elseif MissionType==AUFTRAG.Type.BOMBRUNWAY then
mission=self:NewBOMBRUNWAY(Target, Altitude)
elseif MissionType==AUFTRAG.Type.CAS then
mission=self:NewCAS(ZONE_RADIUS:New(Target:GetName(),Target:GetVec2(),1000),Altitude,Speed,Target:GetAverageCoordinate(),Heading,Leg,TargetTypes)
mission=self:NewCAS(ZONE_RADIUS:New(Target:GetName(),Target:GetVec2(),1000), Altitude, Speed, Target:GetAverageCoordinate(), Heading, Leg, TargetTypes)
elseif MissionType==AUFTRAG.Type.CASENHANCED then
mission=self:NewCASENHANCED(ZONE_RADIUS:New(Target:GetName(),Target:GetVec2(),1000),Altitude,Speed,RangeMax,NoEngageZoneSet,TargetTypes)
mission=self:NewCASENHANCED(ZONE_RADIUS:New(Target:GetName(),Target:GetVec2(),1000), Altitude, Speed, RangeMax, NoEngageZoneSet, TargetTypes)
elseif MissionType==AUFTRAG.Type.INTERCEPT then
mission=self:NewINTERCEPT(Target)
elseif MissionType==AUFTRAG.Type.SEAD then
@@ -2668,6 +2660,17 @@ function AUFTRAG:SetTeleport(Switch)
return self
end
--- **[LEGION, COMMANDER, CHIEF]** Set whether assigned assets return to their legion once the mission is over. This is only applicable to **army** and **navy** groups, *i.e.* aircraft
-- will always return.
-- @param #AUFTRAG self
-- @param #boolean Switch If `true`, assets will return. If `false`, assets will not return and stay where it finishes its last mission. If `nil`, let asset decide.
-- @return #AUFTRAG self
function AUFTRAG:SetReturnToLegion(Switch)
self.legionReturn=Switch
self:T(self.lid..string.format("Setting ReturnToLetion=%s", tostring(self.legionReturn)))
return self
end
--- Set mission push time. This is the time the mission is executed. If the push time is not passed, the group will wait at the mission execution waypoint.
-- @param #AUFTRAG self
@@ -3375,7 +3378,7 @@ function AUFTRAG:GetPriority()
return self.prio
end
--- Get casualties, i.e. number of units that died during this mission.
--- Get casualties, *i.e.* number of own units that died during this mission.
-- @param #AUFTRAG self
-- @return #number Number of dead units.
function AUFTRAG:GetCasualties()
@@ -3902,6 +3905,15 @@ function AUFTRAG:onafterStatus(From, Event, To)
local Ngroups=self:CountOpsGroups()
local Nassigned=self.Nassigned and self.Nassigned-self.Ndead or 0
-- check conditions if set
local conditionDone=false
if self.conditionFailureSet then
conditionDone = self:EvalConditionsAny(self.conditionFailure)
end
if self.conditionSuccessSet and not conditionDone then
conditionDone = self:EvalConditionsAny(self.conditionSuccess)
end
-- Check if mission is not OVER yet.
if self:IsNotOver() then
@@ -3915,6 +3927,11 @@ function AUFTRAG:onafterStatus(From, Event, To)
-- Cancel mission if stop time passed.
self:Cancel()
elseif conditionDone then
-- Cancel mission if conditions were met.
self:Cancel()
elseif self.durationExe and self.Texecuting and Tnow-self.Texecuting>self.durationExe then
@@ -4014,18 +4031,7 @@ function AUFTRAG:onafterStatus(From, Event, To)
end
self:I(self.lid..text)
end
-- check conditions if set
if self.conditionFailureSet then
local failed = self:EvalConditionsAny(self.conditionFailure)
if failed then self:__Failed(-1) end
end
if self.conditionSuccessSet then
local success = self:EvalConditionsAny(self.conditionSuccess)
if success then self:__Success(-1) end
end
-- Ready to evaluate mission outcome?
local ready2evaluate=self.Tover and Tnow-self.Tover>=self.dTevaluate or false

View File

@@ -216,7 +216,7 @@ FLIGHTGROUP.Players={}
--- FLIGHTGROUP class version.
-- @field #string version
FLIGHTGROUP.version="0.8.4"
FLIGHTGROUP.version="1.0.0"
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO list

View File

@@ -1984,9 +1984,9 @@ 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. If `false`, only assets that are NOT in stock (i.e. spawned) are counted. If `nil`, all assets 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`.
-- @param #table Attributes (Optional) Count only assest that have a certain attribute(s), e.g. `GROUP.Attribute.AIR_BOMBER`.
-- @return #number Amount of asset groups in stock.
function LEGION:CountAssets(InStock, MissionTypes, Attributes)
@@ -3147,10 +3147,18 @@ function LEGION.CalculateAssetMissionScore(asset, MissionType, TargetVec2, Inclu
-- Distance factor.
local distance=0
if TargetVec2 and OrigVec2 then
-- Distance in NM.
distance=UTILS.MetersToNM(UTILS.VecDist2D(OrigVec2, TargetVec2))
-- Round: 55 NM ==> 5.5 ==> 6, 63 NM ==> 6.3 ==> 6
distance=UTILS.Round(distance/10, 0)
if asset.category==Group.Category.AIRPLANE or asset.category==Group.Category.HELICOPTER then
-- Round: 55 NM ==> 5.5 ==> 6, 63 NM ==> 6.3 ==> 6
distance=UTILS.Round(distance/10, 0)
else
-- For ground units the distance is a more important factor
distance=UTILS.Round(distance, 0)
end
end
-- Reduce score for legions that are futher away.

View File

@@ -90,7 +90,7 @@ NAVYGROUP = {
--- NavyGroup version.
-- @field #string version
NAVYGROUP.version="0.7.9"
NAVYGROUP.version="1.0.0"
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO list
@@ -199,11 +199,6 @@ function NAVYGROUP:New(group)
-- @param #number Speed Speed in knots until next waypoint is reached.
--- Triggers the FSM event "TurnIntoWind".
-- @function [parent=#NAVYGROUP] TurnIntoWind
-- @param #NAVYGROUP self
@@ -1038,6 +1033,7 @@ end
-- @param #number Speed Speed in knots to the next waypoint.
-- @param #number Depth Depth in meters to the next waypoint.
function NAVYGROUP:onbeforeUpdateRoute(From, Event, To, n, Speed, Depth)
-- Is transition allowed? We assume yes until proven otherwise.
local allowed=true
local trepeat=nil
@@ -1057,6 +1053,9 @@ function NAVYGROUP:onbeforeUpdateRoute(From, Event, To, n, Speed, Depth)
elseif self:IsHolding() then
self:T(self.lid.."Update route denied. Group is holding position!")
return false
elseif self:IsEngaging() then
self:T(self.lid.."Update route allowed. Group is engaging!")
return true
end
-- Check for a current task.
@@ -1074,7 +1073,10 @@ function NAVYGROUP:onbeforeUpdateRoute(From, Event, To, n, Speed, Depth)
self:T2(self.lid.."Allowing update route for Task: ReconMission")
elseif task.dcstask.id==AUFTRAG.SpecialTask.RELOCATECOHORT then
-- For relocate
self:T2(self.lid.."Allowing update route for Task: Relocate Cohort")
self:T2(self.lid.."Allowing update route for Task: Relocate Cohort")
elseif task.dcstask.id==AUFTRAG.SpecialTask.REARMING then
-- For rearming
self:T2(self.lid.."Allowing update route for Task: Rearming")
else
local taskname=task and task.description or "No description"
self:T(self.lid..string.format("WARNING: Update route denied because taskcurrent=%d>0! Task description = %s", self.taskcurrent, tostring(taskname)))
@@ -1106,7 +1108,6 @@ function NAVYGROUP:onbeforeUpdateRoute(From, Event, To, n, Speed, Depth)
end
return allowed
end
--- On after "UpdateRoute" event.

View File

@@ -496,11 +496,13 @@ OPSGROUP.CargoStatus={
-- @field #OPSGROUP opsgroup The cargo opsgroup.
-- @field #boolean delivered If `true`, group was delivered.
-- @field #boolean disembarkActivation If `true`, group is activated. If `false`, group is late activated.
-- @field Core.Zone#ZONE disembarkZone Zone where this group is disembarked to.
-- @field Core.Set#SET_OPSGROUP disembarkCarriers Carriers where this group is directly disembared to.
-- @field #string status Status of the cargo group. Not used yet.
--- OpsGroup version.
-- @field #string version
OPSGROUP.version="0.9.0"
OPSGROUP.version="1.0.0"
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO list
@@ -623,6 +625,9 @@ function OPSGROUP:New(group)
-- Set Default altitude.
self:SetDefaultAltitude()
-- Group will return to its legion when done.
self:SetReturnToLegion()
-- Laser.
self.spot={}
@@ -1009,6 +1014,20 @@ function OPSGROUP:_SetLegion(Legion)
return self
end
--- **[GROUND, NAVAL]** Set whether this group should return to its legion once all mission etc are finished. Only for ground and naval groups. Aircraft will
-- @param #OPSGROUP self
-- @param #boolean Switch If `true` or `nil`, group will return. If `false`, group will not return and stay where it finishes its last mission.
-- @return #OPSGROUP self
function OPSGROUP:SetReturnToLegion(Switch)
if Switch==false then
self.legionReturn=false
else
self.legionReturn=true
end
self:T(self.lid..string.format("Setting ReturnToLetion=%s", tostring(self.legionReturn)))
return self
end
--- Set default cruise speed.
-- @param #OPSGROUP self
-- @param #number Speed Speed in knots.
@@ -1603,6 +1622,31 @@ function OPSGROUP:SetReturnOnOutOfAmmo()
return self
end
--- Set max weight that each unit of the group can handle.
-- @param #OPSGROUP self
-- @param #number Weight Max weight of cargo in kg the unit can carry.
-- @param #string UnitName Name of the Unit. If not given, weight is set for all units of the group.
-- @return #OPSGROUP self
function OPSGROUP:SetCargoBayLimit(Weight, UnitName)
for _,_element in pairs(self.elements) do
local element=_element --#OPSGROUP.Element
if UnitName==nil or UnitName==element.name then
element.weightMaxCargo=Weight
if element.unit then
element.unit:SetCargoBayWeightLimit(Weight)
end
end
end
return self
end
--- Check if an element of the group has line of sight to a coordinate.
-- @param #OPSGROUP self
-- @param Core.Point#COORDINATE Coordinate The position to which we check the LoS. Can also be a DCS#Vec3.
@@ -1639,7 +1683,7 @@ function OPSGROUP:HasLoS(Coordinate, Element, OffsetElement, OffsetCoordinate)
-- Check los for the given element.
if Element.unit and Element.unit:IsAlive() then
local vec3=Element.unit:GetVec3()
local los=checklos(Element)
local los=checklos(vec3)
return los
end
else
@@ -4360,7 +4404,7 @@ function OPSGROUP:_UpdateTask(Task, Mission)
if self:IsArmygroup() or self:IsNavygroup() then
-- Especially NAVYGROUP needs a full stop as patrol ad infinitum
self:FullStop()
self:__FullStop(0.1)
else
-- FLIGHTGROUP not implemented (intended!) for this AUFTRAG type.
end
@@ -5313,7 +5357,8 @@ function OPSGROUP:onafterMissionStart(From, Event, To, Mission)
-- IMMOBILE Group
---
env.info(self.lid.."FF Immobile GROUP")
-- Debug info.
self:T(self.lid.."Immobile GROUP!")
-- Add waypoint task. UpdateRoute is called inside.
local Clock=Mission.Tpush and UTILS.SecondsToClock(Mission.Tpush) or 5
@@ -5613,6 +5658,11 @@ function OPSGROUP:onafterMissionDone(From, Event, To, Mission)
if Mission.icls then
self:_SwitchICLS()
end
-- Return to legion?
if self.legion and Mission.legionReturn~=nil then
self:SetReturnToLegion(Mission.legionReturn)
end
-- Delay before check if group is done.
local delay=1
@@ -5940,7 +5990,7 @@ function OPSGROUP:RouteToMission(mission, delay)
formation=ENUMS.Formation.Vehicle.OffRoad
end
waypoint=ARMYGROUP.AddWaypoint(self, waypointcoord, SpeedToMission, uid, formation, false)
waypoint=ARMYGROUP.AddWaypoint(self, waypointcoord, SpeedToMission, uid, formation, false)
elseif self:IsNavygroup() then
@@ -7043,6 +7093,8 @@ function OPSGROUP:SetLaserTarget(Target)
-- Set coordinate.
self.spot.Coordinate:UpdateFromVec3(self.spot.vec3)
self.spot.Coordinate:MarkToAll("Target Laser",ReadOnly,Text)
end
end
@@ -7881,9 +7933,15 @@ function OPSGROUP:_CheckCargoTransport()
self.cargoTZC=nil
end
-- Get current mission (if any).
local mission=self:GetMissionCurrent()
-- Check if there is anything in the queue.
if not self.cargoTransport and not self:IsOnMission() then
if (not self.cargoTransport) and (mission==nil or mission.type==AUFTRAG.Type.NOTHING) then
self.cargoTransport=self:_GetNextCargoTransport()
if self.cargoTransport and mission then
self:MissionCancel(mission)
end
if self.cargoTransport and not self:IsActive() then
self:Activate()
end
@@ -7957,7 +8015,7 @@ function OPSGROUP:_CheckCargoTransport()
end
-- Boarding finished ==> Transport cargo.
if gotcargo and self.cargoTransport:_CheckRequiredCargos(self.cargoTZC) and not boarding then
if gotcargo and self.cargoTransport:_CheckRequiredCargos(self.cargoTZC, self) and not boarding then
self:T(self.lid.."Boarding finished ==> Loaded")
self:LoadingDone()
else
@@ -8969,7 +9027,7 @@ function OPSGROUP:onafterLoading(From, Event, To)
-- Check if current mission is using this ops transport.
if isOnMission then
local mission=cargo.opsgroup:GetMissionCurrent()
if mission and mission.opstransport and mission.opstransport.uid==self.cargoTransport.uid then
if mission and ((mission.opstransport and mission.opstransport.uid==self.cargoTransport.uid) or mission.type==AUFTRAG.Type.NOTHING) then
isOnMission=not isHolding
end
end
@@ -9331,6 +9389,8 @@ function OPSGROUP:onafterUnloading(From, Event, To)
-- Set carrier status to UNLOADING.
self:_NewCarrierStatus(OPSGROUP.CarrierStatus.UNLOADING)
self:T(self.lid.."Unloading..")
-- Deploy zone.
local zone=self.cargoTZC.DisembarkZone or self.cargoTZC.DeployZone --Core.Zone#ZONE
@@ -9343,9 +9403,16 @@ function OPSGROUP:onafterUnloading(From, Event, To)
if cargo.opsgroup:IsLoaded(self.groupname) and not cargo.opsgroup:IsDead() then
-- Disembark to carrier.
local needscarrier=false --#boolean
local carrier=nil --Ops.OpsGroup#OPSGROUP.Element
local carrierGroup=nil --Ops.OpsGroup#OPSGROUP
local disembarkToCarriers=cargo.disembarkCarriers~=nil or self.cargoTZC.disembarkToCarriers
-- Set specifc zone for this cargo.
if cargo.disembarkZone then
zone=cargo.disembarkZone
end
self:T(self.lid..string.format("Unloading cargo %s to zone %s", cargo.opsgroup:GetName(), zone and zone:GetName() or "No Zone Found!"))
-- Try to get the OPSGROUP if deploy zone is a ship.
if zone and zone:IsInstanceOf("ZONE_AIRBASE") and zone:GetAirbase():IsShip() then
@@ -9356,17 +9423,22 @@ function OPSGROUP:onafterUnloading(From, Event, To)
carrier=carrierGroup:GetElementByName(shipname)
end
if self.cargoTZC.DisembarkCarriers and #self.cargoTZC.DisembarkCarriers>0 then
if disembarkToCarriers then
-- Debug info.
self:T(self.lid..string.format("Trying to find disembark carriers in zone %s", zone:GetName()))
-- Disembarkcarriers.
local disembarkCarriers=cargo.disembarkCarriers or self.cargoTZC.DisembarkCarriers
needscarrier=true
carrier, carrierGroup=self.cargoTransport:FindTransferCarrierForCargo(cargo.opsgroup, zone, self.cargoTZC)
-- Try to find a carrier that can take the cargo.
carrier, carrierGroup=self.cargoTransport:FindTransferCarrierForCargo(cargo.opsgroup, zone, disembarkCarriers, self.cargoTZC.DeployAirbase)
--TODO: max unloading time if transfer carrier does not arrive in the zone.
end
if needscarrier==false or (needscarrier and carrier and carrierGroup) then
if (disembarkToCarriers and carrier and carrierGroup) or (not disembarkToCarriers) then
-- Cargo was delivered (somehow).
cargo.delivered=true
@@ -9385,7 +9457,7 @@ function OPSGROUP:onafterUnloading(From, Event, To)
elseif zone and zone:IsInstanceOf("ZONE_AIRBASE") and zone:GetAirbase():IsShip() then
---
-- Delivered to a ship via helo or VTOL
-- Delivered to a ship via helo that landed on its platform
---
-- Issue warning.
@@ -9408,7 +9480,7 @@ function OPSGROUP:onafterUnloading(From, Event, To)
else
-- Get disembark zone of this TZC.
local DisembarkZone=self.cargoTransport:GetDisembarkZone(self.cargoTZC)
local DisembarkZone=cargo.disembarkZone or self.cargoTransport:GetDisembarkZone(self.cargoTZC)
local Coordinate=nil
@@ -9431,7 +9503,7 @@ function OPSGROUP:onafterUnloading(From, Event, To)
Coordinate=zoneCarrier:GetRandomCoordinate()
else
env.info(string.format("FF ERROR carrier element nil!"))
self:E(self.lid..string.format("ERROR carrier element nil!"))
end
end
@@ -10258,7 +10330,7 @@ function OPSGROUP:_CheckGroupDone(delay)
-- Passed FINAL waypoint
---
if self.legion then
if self.legion and self.legionReturn then
self:T(self.lid..string.format("Passed final WP, adinfinitum=FALSE, LEGION set ==> RTZ"))
if self.isArmygroup then

View File

@@ -172,6 +172,7 @@ OPSTRANSPORT.Status={
-- @field #table TransportPaths Path for Transport. Each elment of the table is of type `#OPSTRANSPORT.Path`.
-- @field #table RequiredCargos Required cargos.
-- @field #table DisembarkCarriers Carriers where the cargo is directly disembarked to.
-- @field #boolean disembarkToCarriers If `true`, cargo is supposed to embark to another carrier.
-- @field #boolean disembarkActivation If true, troops are spawned in late activated state when disembarked from carrier.
-- @field #boolean disembarkInUtero If true, troops are disembarked "in utero".
-- @field #boolean assets Cargo assets.
@@ -195,7 +196,7 @@ _OPSTRANSPORTID=0
--- Army Group version.
-- @field #string version
OPSTRANSPORT.version="0.6.1"
OPSTRANSPORT.version="0.7.0"
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO list
@@ -204,6 +205,7 @@ OPSTRANSPORT.version="0.6.1"
-- TODO: Trains.
-- TODO: Stop transport.
-- TODO: Improve pickup and transport paths.
-- DONE: Disembark parameters per cargo group.
-- DONE: Special transport cohorts/legions. Similar to mission.
-- DONE: Cancel transport.
-- DONE: Allow multiple pickup/depoly zones.
@@ -515,9 +517,11 @@ end
-- @param #OPSTRANSPORT self
-- @param Core.Set#SET_GROUP GroupSet Set of groups to be transported. Can also be passed as a single GROUP or OPSGROUP object.
-- @param #OPSTRANSPORT.TransportZoneCombo TransportZoneCombo Transport zone combo.
-- @param #boolean DisembarkActivation If `true`, cargo group is activated when disembarked. If `false`, cargo groups are late activated when disembarked. Default `nil` (usually activated).
-- @param #boolean DisembarkActivation If `true`, cargo group is activated when disembarked. If `false`, cargo groups are late activated when disembarked. Default `nil` (usually activated).
-- @param Core.Zone#ZONE DisembarkZone Zone where the groups disembark to.
-- @param Core.Set#SET_OPSGROUP DisembarkCarriers Carrier groups where the cargo directly disembarks to.
-- @return #OPSTRANSPORT self
function OPSTRANSPORT:AddCargoGroups(GroupSet, TransportZoneCombo, DisembarkActivation)
function OPSTRANSPORT:AddCargoGroups(GroupSet, TransportZoneCombo, DisembarkActivation, DisembarkZone, DisembarkCarriers)
-- Use default TZC if no transport zone combo is provided.
TransportZoneCombo=TransportZoneCombo or self.tzcDefault
@@ -526,7 +530,7 @@ function OPSTRANSPORT:AddCargoGroups(GroupSet, TransportZoneCombo, DisembarkActi
if GroupSet:IsInstanceOf("GROUP") or GroupSet:IsInstanceOf("OPSGROUP") then
-- We got a single GROUP or OPSGROUP object.
local cargo=self:_CreateCargoGroupData(GroupSet, TransportZoneCombo, DisembarkActivation)
local cargo=self:_CreateCargoGroupData(GroupSet, TransportZoneCombo, DisembarkActivation, DisembarkZone, DisembarkCarriers)
if cargo then
@@ -722,7 +726,7 @@ function OPSTRANSPORT:GetDisembarkActivation(TransportZoneCombo)
return TransportZoneCombo.disembarkActivation
end
--- Set transfer carrier(s). These are carrier groups, where the cargo is directly loaded into when disembarked.
--- Set/add transfer carrier(s). These are carrier groups, where the cargo is directly loaded into when disembarked.
-- @param #OPSTRANSPORT self
-- @param Core.Set#SET_GROUP Carriers Carrier set. Can also be passed as a #GROUP, #OPSGROUP or #SET_OPSGROUP object.
-- @param #OPSTRANSPORT.TransportZoneCombo TransportZoneCombo Transport zone combo.
@@ -734,12 +738,27 @@ function OPSTRANSPORT:SetDisembarkCarriers(Carriers, TransportZoneCombo)
-- Use default TZC if no transport zone combo is provided.
TransportZoneCombo=TransportZoneCombo or self.tzcDefault
-- Set that we want to disembark to carriers.
TransportZoneCombo.disembarkToCarriers=true
self:_AddDisembarkCarriers(Carriers, TransportZoneCombo.DisembarkCarriers)
return self
end
--- Set/add transfer carrier(s). These are carrier groups, where the cargo is directly loaded into when disembarked.
-- @param #OPSTRANSPORT self
-- @param Core.Set#SET_GROUP Carriers Carrier set. Can also be passed as a #GROUP, #OPSGROUP or #SET_OPSGROUP object.
-- @param #table Table the table to add.
-- @return #OPSTRANSPORT self
function OPSTRANSPORT:_AddDisembarkCarriers(Carriers, Table)
if Carriers:IsInstanceOf("GROUP") or Carriers:IsInstanceOf("OPSGROUP") then
local carrier=self:_GetOpsGroupFromObject(Carriers)
if carrier then
table.insert(TransportZoneCombo.DisembarkCarriers, carrier)
table.insert(Table, carrier)
end
elseif Carriers:IsInstanceOf("SET_GROUP") or Carriers:IsInstanceOf("SET_OPSGROUP") then
@@ -747,7 +766,7 @@ function OPSTRANSPORT:SetDisembarkCarriers(Carriers, TransportZoneCombo)
for _,object in pairs(Carriers:GetSet()) do
local carrier=self:_GetOpsGroupFromObject(object)
if carrier then
table.insert(TransportZoneCombo.DisembarkCarriers, carrier)
table.insert(Table, carrier)
end
end
@@ -755,7 +774,7 @@ function OPSTRANSPORT:SetDisembarkCarriers(Carriers, TransportZoneCombo)
self:E(self.lid.."ERROR: Carriers must be a GROUP, OPSGROUP, SET_GROUP or SET_OPSGROUP object!")
end
return self
end
--- Get transfer carrier(s). These are carrier groups, where the cargo is directly loaded into when disembarked.
@@ -1568,13 +1587,21 @@ end
-- @return #boolean If true, all possible cargo was delivered.
function OPSTRANSPORT:IsDelivered(Nmin)
local is=self:is(OPSTRANSPORT.Status.DELIVERED)
Nmin=Nmin or 0
if Nmin>self.Ncargo then
Nmin=self.Ncargo
end
if self.Ndelivered<Nmin then
is=false
-- Nmin=Nmin or 0
-- if Nmin>self.Ncargo then
-- Nmin=self.Ncargo
-- end
--
-- if self.Ndelivered<Nmin then
-- is=false
-- end
-- Check if Ndelivered is at least Nmin (if given)
if is==false and Nmin and self.Ndelivered>=math.min(self.Ncargo, Nmin) then
is=true
end
return is
end
@@ -1928,31 +1955,72 @@ end
--- Check if all required cargos are loaded.
-- @param #OPSTRANSPORT self
-- @param #OPSTRANSPORT.TransportZoneCombo TransportZoneCombo Transport zone combo.
-- @return #boolean If true, all required cargos are loaded or there is no required cargo.
function OPSTRANSPORT:_CheckRequiredCargos(TransportZoneCombo)
-- @param Ops.OpsGroup#OPSGROUP CarrierGroup The carrier group asking.
-- @return #boolean If true, all required cargos are loaded or there is no required cargo or asking carrier is full.
function OPSTRANSPORT:_CheckRequiredCargos(TransportZoneCombo, CarrierGroup)
-- Use default TZC if no transport zone combo is provided.
TransportZoneCombo=TransportZoneCombo or self.tzcDefault
local requiredCargos=TransportZoneCombo.RequiredCargos
-- Use input or take all cargos.
local requiredCargos=TransportZoneCombo.Cargos
-- Check if required cargos was set by user.
if TransportZoneCombo.RequiredCargos and #TransportZoneCombo.RequiredCargos>0 then
requiredCargos=TransportZoneCombo.RequiredCargos
else
requiredCargos={}
for _,_cargo in pairs(TransportZoneCombo.Cargos) do
local cargo=_cargo --Ops.OpsGroup#OPSGROUP.CargoGroup
table.insert(requiredCargos, cargo.opsgroup)
end
end
if requiredCargos==nil or #requiredCargos==0 then
return true
end
-- All carrier names.
local carrierNames=self:_GetCarrierNames()
local gotit=true
-- Cargo groups not loaded yet.
local weightmin=nil
for _,_cargo in pairs(requiredCargos) do
local cargo=_cargo --Ops.OpsGroup#OPSGROUP
-- Is this cargo loaded into any carrier?
local isLoaded=cargo:IsLoaded(carrierNames)
if not cargo:IsLoaded(carrierNames) then
return false
if not isLoaded then
local weight=cargo:GetWeightTotal()
if weightmin==nil or weight<weightmin then
weightmin=weight
end
end
end
if weightmin then
-- Free space of carrier.
local freeSpace=CarrierGroup:GetFreeCargobayMax(true)
-- Debug info.
self:T(self.lid..string.format("Check required cargos for carrier=%s free=%.1f, weight=%.1f", CarrierGroup:GetName(), freeSpace, weightmin))
if weightmin<freeSpace then
-- This group can still take cargo.
return false
else
-- This group is full! Even if there is cargo left, we cannot transport it.
return true
end
end
-- No cargo left.
return true
end
@@ -1986,24 +2054,25 @@ end
-- @param #OPSTRANSPORT self
-- @param Ops.OpsGroup#OPSGROUP CargoGroup The cargo group that needs to be loaded into a carrier unit/element of the carrier group.
-- @param Core.Zone#ZONE Zone (Optional) Zone where the carrier must be in.
-- @param #OPSTRANSPORT.TransportZoneCombo TransportZoneCombo Transport zone combo.
-- @param #table DisembarkCarriers Disembark carriers.
-- @param Wrapper.Airbase#AIRBASE DeployAirbase Airbase where to deploy.
-- @return Ops.OpsGroup#OPSGROUP.Element New carrier element for cargo or nil.
-- @return Ops.OpsGroup#OPSGROUP New carrier group for cargo or nil.
function OPSTRANSPORT:FindTransferCarrierForCargo(CargoGroup, Zone, TransportZoneCombo)
function OPSTRANSPORT:FindTransferCarrierForCargo(CargoGroup, Zone, DisembarkCarriers, DeployAirbase)
-- Use default TZC if no transport zone combo is provided.
TransportZoneCombo=TransportZoneCombo or self.tzcDefault
--TransportZoneCombo=TransportZoneCombo or self.tzcDefault
local carrier=nil --Ops.OpsGroup#OPSGROUP.Element
local carrierGroup=nil --Ops.OpsGroup#OPSGROUP
--TODO: maybe sort the carriers wrt to largest free cargo bay. Or better smallest free cargo bay that can take the cargo group weight.
for _,_carrier in pairs(TransportZoneCombo.DisembarkCarriers) do
for _,_carrier in pairs(DisembarkCarriers or {}) do
local carrierGroup=_carrier --Ops.OpsGroup#OPSGROUP
-- First check if carrier is alive and loading cargo.
if carrierGroup and carrierGroup:IsAlive() and (carrierGroup:IsLoading() or TransportZoneCombo.DeployAirbase) then
if carrierGroup and carrierGroup:IsAlive() and (carrierGroup:IsLoading() or DeployAirbase) then
-- Find an element of the group that has enough free space.
carrier=carrierGroup:FindCarrierForCargo(CargoGroup)
@@ -2021,6 +2090,7 @@ function OPSTRANSPORT:FindTransferCarrierForCargo(CargoGroup, Zone, TransportZon
end
end
self:T2(self.lid.."Could NOT find any carrier that is ALIVE and LOADING (or DELOYAIRBASE))!")
return nil, nil
end
@@ -2029,8 +2099,10 @@ end
-- @param Wrapper.Group#GROUP group The GROUP or OPSGROUP object.
-- @param #OPSTRANSPORT.TransportZoneCombo TransportZoneCombo Transport zone combo.
-- @param #boolean DisembarkActivation If `true`, cargo group is activated when disembarked.
-- @param Core.Zone#ZONE DisembarkZone Disembark zone, where the cargo is spawned when delivered.
-- @param Core.Set#SET_OPSGROUP DisembarkCarriers Disembark carriers cargo is directly loaded into when delivered.
-- @return Ops.OpsGroup#OPSGROUP.CargoGroup Cargo group data.
function OPSTRANSPORT:_CreateCargoGroupData(group, TransportZoneCombo, DisembarkActivation)
function OPSTRANSPORT:_CreateCargoGroupData(group, TransportZoneCombo, DisembarkActivation, DisembarkZone, DisembarkCarriers)
-- Get ops group.
local opsgroup=self:_GetOpsGroupFromObject(group)
@@ -2051,8 +2123,12 @@ function OPSTRANSPORT:_CreateCargoGroupData(group, TransportZoneCombo, Disembark
cargo.opsgroup=opsgroup
cargo.delivered=false
cargo.status="Unknown"
cargo.disembarkActivation=DisembarkActivation
cargo.tzcUID=TransportZoneCombo
cargo.disembarkZone=DisembarkZone
if DisembarkCarriers then
cargo.disembarkCarriers={}
self:_AddDisembarkCarriers(DisembarkCarriers, cargo.disembarkCarriers)
end
return cargo
end
@@ -2077,8 +2153,10 @@ function OPSTRANSPORT:_CountCargosInZone(Zone, Delivered, Carrier, TransportZone
if mycarrier and mycarrier:IsUnloading() then
-- Get disembark carriers.
local carriers=mycarrier.cargoTransport:GetDisembarkCarriers(mycarrier.cargoTZC)
-- Check if carrier is in the list.
for _,_carrier in pairs(carriers) do
local carrier=_carrier --Ops.OpsGroup#OPSGROUP
if Carrier:GetName()==carrier:GetName() then
@@ -2086,6 +2164,20 @@ function OPSTRANSPORT:_CountCargosInZone(Zone, Delivered, Carrier, TransportZone
end
end
if mycarrier.cargoTZC and mycarrier.cargoTZC.Cargos then
for _,_cargodata in pairs(mycarrier.cargoTZC.Cargos) do
local cargodata=_cargodata --Ops.OpsGroup#OPSGROUP.CargoGroup
if cargo:GetName()==cargodata.opsgroup:GetName() then
for _,_carrier in pairs(cargodata.disembarkCarriers) do
local carrier=_carrier --Ops.OpsGroup#OPSGROUP
if Carrier:GetName()==carrier:GetName() then
return true
end
end
end
end
end
end
return false