diff --git a/Moose Development/Moose/Ops/ArmyGroup.lua b/Moose Development/Moose/Ops/ArmyGroup.lua index 70928e07e..f758ff079 100644 --- a/Moose Development/Moose/Ops/ArmyGroup.lua +++ b/Moose Development/Moose/Ops/ArmyGroup.lua @@ -1082,10 +1082,15 @@ end -- @return Ops.OpsGroup#OPSGROUP.Waypoint Waypoint table. function ARMYGROUP:AddWaypoint(Coordinate, Speed, AfterWaypointWithID, Formation, Updateroute) + env.info("FF Current waypoint index="..self.currentwp) + env.info("FF Add waypoint after index="..(AfterWaypointWithID or "nil")) + local coordinate=self:_CoordinateFromObject(Coordinate) -- Set waypoint index. local wpnumber=self:GetWaypointIndexAfterID(AfterWaypointWithID) + + env.info("FF Add waypoint index="..wpnumber) -- Check if final waypoint is still passed. if wpnumber>self.currentwp then diff --git a/Moose Development/Moose/Ops/OpsGroup.lua b/Moose Development/Moose/Ops/OpsGroup.lua index 7dbeabb77..3f3dc427b 100644 --- a/Moose Development/Moose/Ops/OpsGroup.lua +++ b/Moose Development/Moose/Ops/OpsGroup.lua @@ -5303,15 +5303,17 @@ function OPSGROUP:onafterPickup(From, Event, To) end elseif self.isNavygroup then - local waypoint=NAVYGROUP.AddWaypoint(self, Coordinate) - waypoint.detour=true + -- Navy Group + + local waypoint=NAVYGROUP.AddWaypoint(self, Coordinate, nil, self:GetWaypointCurrent().uid) ; waypoint.detour=true self:__Cruise(-2) elseif self.isArmygroup then - local waypoint=ARMYGROUP.AddWaypoint(self, Coordinate) - waypoint.detour=true + -- Army Group + + local waypoint=ARMYGROUP.AddWaypoint(self, Coordinate, nil, self:GetWaypointCurrent().uid) ; waypoint.detour=true self:__Cruise(-2) @@ -5496,7 +5498,7 @@ function OPSGROUP:onafterLoaded(From, Event, To) end -- Order group to transport. - self:__Transport(1, self.cargoTransport.deployzone) + self:__Transport(1) end @@ -5551,8 +5553,16 @@ function OPSGROUP:onafterTransport(From, Event, To) else - -- Get a random coordinate in the deploy zone and let the carrier go there. - local Coordinate=Zone:GetRandomCoordinate() + -- Coord where the carrier goes to unload. + local Coordinate=nil --Core.Point#COORDINATE + + if self.cargoTransport.carrierGroup and self.cargoTransport.carrierGroup:IsLoading() then + -- Coordinate of the new carrier. + Coordinate=self.cargoTransport.carrierGroup:GetCoordinate() + else + -- Get a random coordinate in the deploy zone and let the carrier go there. + Coordinate=Zone:GetRandomCoordinate() + end -- Add waypoint. if self.isFlightgroup then @@ -5594,9 +5604,8 @@ function OPSGROUP:onafterTransport(From, Event, To) elseif self.isArmygroup then - -- ARMYGROUP - local waypoint=ARMYGROUP.AddWaypoint(self, Coordinate) - waypoint.detour=true + -- ARMYGROUP + local waypoint=ARMYGROUP.AddWaypoint(self, Coordinate, nil, self:GetWaypointCurrent().uid) ; waypoint.detour=true -- Give cruise command. self:Cruise() @@ -5604,8 +5613,7 @@ function OPSGROUP:onafterTransport(From, Event, To) elseif self.isNavygroup then -- NAVYGROUP - local waypoint=NAVYGROUP.AddWaypoint(self, Coordinate) - waypoint.detour=true + local waypoint=NAVYGROUP.AddWaypoint(self, Coordinate, nil, self:GetWaypointCurrent().uid) ; waypoint.detour=true -- Give cruise command. self:Cruise() @@ -5629,7 +5637,7 @@ function OPSGROUP:onafterUnloading(From, Event, To) self.carrierStatus=OPSGROUP.CarrierStatus.UNLOADING -- Deploy zone. - local zone=self.cargoTransport.disembarkzone --Core.Zone#ZONE + local zone=self.cargoTransport.disembarkzone or self.cargoTransport.deployzone --Core.Zone#ZONE for _,_cargo in pairs(self.cargoTransport.cargos) do local cargo=_cargo --#OPSGROUP.CargoGroup @@ -5663,7 +5671,7 @@ function OPSGROUP:onafterUnloading(From, Event, To) env.info("ERROR: No element of the group can take this cargo!") end - elseif zone:IsInstanceOf("ZONE_AIRBASE") and zone:GetAirbase():IsShip() then + elseif zone and zone:IsInstanceOf("ZONE_AIRBASE") and zone:GetAirbase():IsShip() then --- -- Delivered to a ship via helo or VTOL @@ -5684,20 +5692,37 @@ function OPSGROUP:onafterUnloading(From, Event, To) self:Unload(cargo.opsgroup) else + + local Coordinate=nil - -- TODO: honor disembark zone! + if self.cargoTransport.disembarkzone then + + -- Random coordinate in disembark zone. + Coordinate=self.cargoTransport.disembarkzone:GetRandomCoordinate() + + else - local zoneCarrier=ZONE_RADIUS:New("Carrier", self:GetVec2(), 100) - - -- Random coordinate/heading in the zone. - local Coordinate=zoneCarrier:GetRandomCoordinate(50) + -- TODO: Optimize with random Vec2 + + -- Create a zone around the carrier. + local zoneCarrier=ZONE_RADIUS:New("Carrier", self:GetVec2(), 100) + + -- Random coordinate/heading in the zone. + Coordinate=zoneCarrier:GetRandomCoordinate(50) + + end + + -- Random heading of the group. local Heading=math.random(0,359) - -- Unload. + -- Unload to Coordinate. self:Unload(cargo.opsgroup, Coordinate, self.cargoTransport.disembarkActivation, Heading) end - + + -- Trigger "Unloaded" event for current cargo transport + self.cargoTransport:Unloaded(cargo.opsgroup) + end end @@ -5799,7 +5824,7 @@ function OPSGROUP:onafterUnload(From, Event, To, OpsGroup, Coordinate, Activated -- Trigger "Disembarked" event. OpsGroup:Disembarked(OpsGroup.carrierGroup, OpsGroup.carrier) - + -- No carrier any more. OpsGroup.carrier=nil OpsGroup.carrierGroup=nil @@ -5882,7 +5907,8 @@ function OPSGROUP:onafterDelivered(From, Event, To, CargoTransport) -- Check group done. self:I(self.lid.."All cargo delivered ==> check group done") - self:_CheckGroupDone(0.1) + self:__Cruise(0.1) + self:_CheckGroupDone(0.2) -- No current transport any more. self.cargoTransport=nil @@ -6718,7 +6744,7 @@ function OPSGROUP._PassingWaypoint(group, opsgroup, uid) opsgroup:LandAt(opsgroup:GetCoordinate(), 60*60) else - -- Stop and loading. + -- Wait and load cargo. opsgroup:Wait() opsgroup:__Loading(-5) end @@ -6733,8 +6759,8 @@ function OPSGROUP._PassingWaypoint(group, opsgroup, uid) opsgroup:LandAt(opsgroup:GetCoordinate(), 60*60) else - -- Stop and loading. - opsgroup:Wait() + -- Stop and unload. + opsgroup:Wait() opsgroup:Unloading() end @@ -8101,15 +8127,19 @@ end -- @return Core.Point#COORDINATE The coordinate of the object. function OPSGROUP:_CoordinateFromObject(Object) - if Object:IsInstanceOf("COORDINATE") then - return Object - else - if Object:IsInstanceOf("POSITIONABLE") or Object:IsInstanceOf("ZONE_BASE") then - self:T(self.lid.."WARNING: Coordinate is not a COORDINATE but a POSITIONABLE or ZONE. Trying to get coordinate") - return Object:GetCoordinate() + if Object then + if Object:IsInstanceOf("COORDINATE") then + return Object else - self:E(self.lid.."ERROR: Coordinate is neither a COORDINATE nor any POSITIONABLE or ZONE!") + if Object:IsInstanceOf("POSITIONABLE") or Object:IsInstanceOf("ZONE_BASE") then + self:T(self.lid.."WARNING: Coordinate is not a COORDINATE but a POSITIONABLE or ZONE. Trying to get coordinate") + return Object:GetCoordinate() + else + self:E(self.lid.."ERROR: Coordinate is neither a COORDINATE nor any POSITIONABLE or ZONE!") + end end + else + self:E(self.lid.."ERROR: Object passed is nil!") end return nil diff --git a/Moose Development/Moose/Ops/OpsTransport.lua b/Moose Development/Moose/Ops/OpsTransport.lua index 56f28b878..c354ff996 100644 --- a/Moose Development/Moose/Ops/OpsTransport.lua +++ b/Moose Development/Moose/Ops/OpsTransport.lua @@ -1,4 +1,4 @@ ---- **Ops** - Troop transport assignment of OPS groups. +--- **Ops** - Troop transport assignment for OPS groups. -- -- ## Main Features: -- @@ -106,22 +106,24 @@ function OPSTRANSPORT:New(GroupSet, Pickupzone, Deployzone) _OPSTRANSPORTID=_OPSTRANSPORTID+1 -- Set some string id for output to DCS.log file. - self.lid=string.format("OPSTRANSPORT [UID=%d] %s --> %s | ", _OPSTRANSPORTID, Pickupzone:GetName(), Deployzone:GetName()) + self.lid=string.format("OPSTRANSPORT [UID=%d] | ", _OPSTRANSPORTID) -- Defaults. self.uid=_OPSTRANSPORTID - self.status=OPSTRANSPORT.Status.PLANNING + self.status=OPSTRANSPORT.Status.PLANNING + self.pickupzone=Pickupzone self.deployzone=Deployzone self.embarkzone=Pickupzone - self.disembarkzone=Deployzone - self.prio=50 - self.importance=nil - self.Tstart=timer.getAbsTime()+5 self.carrierGroup=nil self.cargos={} self.carriers={} + + self:SetPriority() + self:SetTime() + + -- Add cargo groups. if GroupSet then self:AddCargoGroups(GroupSet, Pickupzone, Deployzone) end @@ -139,6 +141,9 @@ function OPSTRANSPORT:New(GroupSet, Pickupzone, Deployzone) self:AddTransition("*", "Status", "*") self:AddTransition("*", "Stop", "*") + self:AddTransition("*", "Unloaded", "*") + + -- Call status update self:__Status(-1) @@ -183,7 +188,7 @@ function OPSTRANSPORT:AddCargoGroups(GroupSet, Pickupzone, Deployzone) -- Debug info. if self.verbose>=0 then local text=string.format("Created Cargo Transport (UID=%d) from %s(%s) --> %s(%s)", - self.uid, self.pickupzone:GetName(), self.embarkzone:GetName(), self.deployzone:GetName(), self.disembarkzone:GetName()) + self.uid, self.pickupzone:GetName(), self.embarkzone and self.embarkzone:GetName() or "none", self.deployzone:GetName(), self.disembarkzone and self.disembarkzone:GetName() or "none") local Weight=0 for _,_cargo in pairs(self.cargos) do local cargo=_cargo --#OPSGROUP.CargoGroup @@ -213,7 +218,7 @@ end -- @param Core.Zone#ZONE DisembarkZone Zone where the troops are disembarked. -- @return #OPSTRANSPORT self function OPSTRANSPORT:SetDisembarkZone(DisembarkZone) - self.disembarkzone=DisembarkZone or self.deployzone + self.disembarkzone=DisembarkZone return self end @@ -260,6 +265,56 @@ function OPSTRANSPORT:_AddCarrier(CarrierGroup) return self end +--- Set transport start and stop time. +-- @param #OPSTRANSPORT self +-- @param #string ClockStart Time the transport is started, e.g. "05:00" for 5 am. If specified as a #number, it will be relative (in seconds) to the current mission time. Default is 5 seconds after mission was added. +-- @param #string ClockStop (Optional) Time the transport is stopped, e.g. "13:00" for 1 pm. If mission could not be started at that time, it will be removed from the queue. If specified as a #number it will be relative (in seconds) to the current mission time. +-- @return #OPSTRANSPORT self +function OPSTRANSPORT:SetTime(ClockStart, ClockStop) + + -- Current mission time. + local Tnow=timer.getAbsTime() + + -- Set start time. Default in 5 sec. + local Tstart=Tnow+5 + if ClockStart and type(ClockStart)=="number" then + Tstart=Tnow+ClockStart + elseif ClockStart and type(ClockStart)=="string" then + Tstart=UTILS.ClockToSeconds(ClockStart) + end + + -- Set stop time. Default nil. + local Tstop=nil + if ClockStop and type(ClockStop)=="number" then + Tstop=Tnow+ClockStop + elseif ClockStop and type(ClockStop)=="string" then + Tstop=UTILS.ClockToSeconds(ClockStop) + end + + self.Tstart=Tstart + self.Tstop=Tstop + + if Tstop then + self.duration=self.Tstop-self.Tstart + end + + return self +end + +--- Set mission priority and (optional) urgency. Urgent missions can cancel other running missions. +-- @param #OPSTRANSPORT self +-- @param #number Prio Priority 1=high, 100=low. Default 50. +-- @param #number Importance Number 1-10. If missions with lower value are in the queue, these have to be finished first. Default is `nil`. +-- @param #boolean Urgent If *true*, another running mission might be cancelled if it has a lower priority. +-- @return #OPSTRANSPORT self +function OPSTRANSPORT:SetPriority(Prio, Importance, Urgent) + self.prio=Prio or 50 + self.urgent=Urgent + self.importance=Importance + return self +end + + --- Add a carrier assigned for this transport. -- @param #OPSTRANSPORT self -- @param Ops.OpsGroup#OPSGROUP CarrierGroup Carrier OPSGROUP. @@ -337,14 +392,18 @@ function OPSTRANSPORT:onafterStatus(From, Event, To) local fsmstate=self:GetState() - local text=string.format("State=%s", fsmstate) + local text=string.format("State=%s: %s --> %s", fsmstate, self.pickupzone:GetName(), self.deployzone:GetName()) + text=text..string.format("\nCargos:") for _,_cargo in pairs(self.cargos) do local cargo=_cargo --Ops.OpsGroup#OPSGROUP.CargoGroup + text=text..string.format("\n- %s: %s %s, carrier=%s", cargo.opsgroup:GetName(), cargo.opsgroup:GetState(), cargo.opsgroup.cargoStatus, cargo.opsgroup.carrier and cargo.opsgroup.carrier.name or "none") end + text=text..string.format("\nCarriers:") for _,_carrier in pairs(self.carriers) do - local carrier=_carrier + local carrier=_carrier --Ops.OpsGroup#OPSGROUP + text=text..string.format("\n- %s: %s %s, cargo=%d kg", carrier:GetName(), carrier:GetState(), carrier.carrierStatus, carrier:GetWeightCargo()) end self:I(self.lid..text) @@ -394,8 +453,7 @@ end function OPSTRANSPORT:onafterDelivered(From, Event, To) self:I(self.lid..string.format("New status %s", OPSTRANSPORT.Status.DELIVERED)) - -- TODO: Inform all assigned carriers that cargo was delivered. They can have this in the queue or are currently processing this transport. - + -- Inform all assigned carriers that cargo was delivered. They can have this in the queue or are currently processing this transport. for _,_carrier in pairs(self.carriers) do local carrier=_carrier --Ops.OpsGroup#OPSGROUP if self:GetCarrierTransportStatus(carrier)~=OPSTRANSPORT.Status.DELIVERED then @@ -405,6 +463,16 @@ function OPSTRANSPORT:onafterDelivered(From, Event, To) end +--- On after "Unloaded" event. +-- @param #OPSTRANSPORT self +-- @param #string From From state. +-- @param #string Event Event. +-- @param #string To To state. +-- @param Ops.OpsGroup#OPSGROUP OpsGroup OPSGROUP that was unloaded from a carrier. +function OPSTRANSPORT:onafterUnloaded(From, Event, To, OpsGroup) + self:I(self.lid..string.format("Unloaded OPSGROUP %s", OpsGroup:GetName())) +end + ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- Misc Functions -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------