diff --git a/Moose Development/Moose/Core/Point.lua b/Moose Development/Moose/Core/Point.lua index 0454f1274..afffab5da 100644 --- a/Moose Development/Moose/Core/Point.lua +++ b/Moose Development/Moose/Core/Point.lua @@ -874,6 +874,11 @@ do -- COORDINATE -- Get the vector from A to B local vec=UTILS.VecSubstract(ToCoordinate, self) + + if f>1 then + local norm=UTILS.VecNorm(vec) + f=Fraction/norm + end -- Scale the vector. vec.x=f*vec.x @@ -883,7 +888,9 @@ do -- COORDINATE -- Move the vector to start at the end of A. vec=UTILS.VecAdd(self, vec) + -- Create a new coordiante object. local coord=COORDINATE:New(vec.x,vec.y,vec.z) + return coord end diff --git a/Moose Development/Moose/Ops/ArmyGroup.lua b/Moose Development/Moose/Ops/ArmyGroup.lua index 98d2992a2..35ba2606f 100644 --- a/Moose Development/Moose/Ops/ArmyGroup.lua +++ b/Moose Development/Moose/Ops/ArmyGroup.lua @@ -1005,32 +1005,65 @@ end -- @param #number Formation Formation of the group. function ARMYGROUP:onafterUpdateRoute(From, Event, To, n, N, Speed, Formation) - -- Debug info. - local text=string.format("Update route state=%s: n=%s, N=%s, Speed=%s, Formation=%s", self:GetState(), tostring(n), tostring(N), tostring(Speed), tostring(Formation)) - self:T(self.lid..text) - -- Update route from this waypoint number onwards. n=n or self:GetWaypointIndexNext(self.adinfinitum) -- Max index. - N=N or #self.waypoints + N=N or #self.waypoints N=math.min(N, #self.waypoints) + + -- Debug info. + local text=string.format("Update route state=%s: n=%s, N=%s, Speed=%s, Formation=%s", self:GetState(), tostring(n), tostring(N), tostring(Speed), tostring(Formation)) + self:T(self.lid..text) - -- Waypoints. + -- Waypoints including addtional wp onroad. local waypoints={} - local formationlast=nil - for i=n, #self.waypoints do + -- Next waypoint. + local wp=self.waypoints[n] --Ops.OpsGroup#OPSGROUP.Waypoint + + -- Formation at the current position. + local formation0=wp.action + if formation0==ENUMS.Formation.Vehicle.OnRoad then + if wp.roadcoord then + if wp.roaddist>10 then + formation0=ENUMS.Formation.Vehicle.OffRoad + end + else + formation0=ENUMS.Formation.Vehicle.OffRoad + end + end + + -- Current point. + local current=self:GetCoordinate():WaypointGround(UTILS.MpsToKmph(self.speedWp), formation0) --ENUMS.Formation.Vehicle.OffRoad) + table.insert(waypoints, 1, current) + + -- Loop over waypoints. + for j=n, N do + + -- Index of previous waypoint. + local i=j-1 + + -- If we go to the first waypoint j=1 ==> i=0, so we take the last waypoint passed. E.g. when adinfinitum and passed final waypoint. + if i==0 then + i=self.currentwp + end -- Next waypoint. - local wp=UTILS.DeepCopy(self.waypoints[i]) --Ops.OpsGroup#OPSGROUP.Waypoint + local wp=UTILS.DeepCopy(self.waypoints[j]) --Ops.OpsGroup#OPSGROUP.Waypoint + + -- Previous waypoint. Index is i and not i-1 because we added the current position. + local wp0=self.waypoints[i] --Ops.OpsGroup#OPSGROUP.Waypoint + + --local text=string.format("FF Update: i=%d, wp[i]=%s, wp[i-1]=%s", i, wp.action, wp0.action) + --env.info(text) -- Speed. if Speed then wp.speed=UTILS.KnotsToMps(tonumber(Speed)) else - -- Take default waypoint speed. But make sure speed>0 if patrol ad infinitum. - if wp.speed<0.1 then --self.adinfinitum and + -- Take default waypoint speed. But make sure speed>0 if patrol ad infinitum. + if wp.speed<0.1 then wp.speed=UTILS.KmphToMps(self.speedCruise) end end @@ -1041,9 +1074,23 @@ function ARMYGROUP:onafterUpdateRoute(From, Event, To, n, N, Speed, Formation) elseif Formation then wp.action=Formation end - + -- Add waypoint in between because this waypoint is "On Road" but lies "Off Road". - if wp.action==ENUMS.Formation.Vehicle.OnRoad and wp.roaddist>10 then + if wp.action==ENUMS.Formation.Vehicle.OnRoad and wp0.roaddist>=0 then + + --env.info("FF adding waypoint0 on road #"..i) + + -- Add "On Road" waypoint in between. + local wproad=wp0.roadcoord:WaypointGround(UTILS.MpsToKmph(wp.speed), ENUMS.Formation.Vehicle.OnRoad) --Ops.OpsGroup#OPSGROUP.Waypoint + + -- Insert road waypoint. + table.insert(waypoints, wproad) + end + + -- Add waypoint in between because this waypoint is "On Road" but lies "Off Road". + if wp.action==ENUMS.Formation.Vehicle.OnRoad and wp.roaddist>=0 then + + --env.info("FF adding waypoint on road #"..i) -- The real waypoint is actually off road. wp.action=ENUMS.Formation.Vehicle.OffRoad @@ -1053,13 +1100,11 @@ function ARMYGROUP:onafterUpdateRoute(From, Event, To, n, N, Speed, Formation) -- Insert road waypoint. table.insert(waypoints, wproad) - end + end + -- Add waypoint. - table.insert(waypoints, wp) - - -- Last formation. - formationlast=wp.action + table.insert(waypoints, wp) end -- First (next wp). @@ -1069,29 +1114,18 @@ function ARMYGROUP:onafterUpdateRoute(From, Event, To, n, N, Speed, Formation) self.option.Formation=wp.action -- Current set speed in m/s. - self.speedWp=wp.speed - - local formation0=wp.action==ENUMS.Formation.Vehicle.OnRoad and ENUMS.Formation.Vehicle.OnRoad or wp.action - - -- Current point. - local current=self:GetCoordinate():WaypointGround(UTILS.MpsToKmph(self.speedWp), formation0) - table.insert(waypoints, 1, current) - - -- Insert a point on road. - if wp.action==ENUMS.Formation.Vehicle.OnRoad and (wp.coordinate or wp.roadcoord) then - - current=self:GetClosestRoad():WaypointGround(UTILS.MpsToKmph(self.speedWp), ENUMS.Formation.Vehicle.OnRoad) - table.insert(waypoints, 2, current) - end + self.speedWp=wp.speed -- Debug output. if self.verbose>=10 then - --if true then for i,_wp in pairs(waypoints) do local wp=_wp --Ops.OpsGroup#OPSGROUP.Waypoint - local text=string.format("WP #%d UID=%d type=%s: Speed=%d m/s, alt=%d m, Action=%s", i, wp.uid and wp.uid or -1, wp.type, wp.speed, wp.alt, wp.action) + + local text=string.format("WP #%d UID=%d Formation=%s: Speed=%d m/s, Alt=%d m, Type=%s", i, wp.uid and wp.uid or -1, wp.action, wp.speed, wp.alt, wp.type) + local coord=COORDINATE:NewFromWaypoint(wp):MarkToAll(text) self:I(text) + end end @@ -1722,7 +1756,10 @@ end -- @param #boolean Updateroute If true or nil, call UpdateRoute. If false, no call. -- @return Ops.OpsGroup#OPSGROUP.Waypoint Waypoint table. function ARMYGROUP:AddWaypoint(Coordinate, Speed, AfterWaypointWithID, Formation, Updateroute) + + -- Debug info. self:T(self.lid..string.format("AddWaypoint Formation = %s",tostring(Formation) or "none")) + -- Create coordinate. local coordinate=self:_CoordinateFromObject(Coordinate) diff --git a/Moose Development/Moose/Ops/Auftrag.lua b/Moose Development/Moose/Ops/Auftrag.lua index 430a032b0..a1e46b10b 100644 --- a/Moose Development/Moose/Ops/Auftrag.lua +++ b/Moose Development/Moose/Ops/Auftrag.lua @@ -2112,6 +2112,10 @@ function AUFTRAG:_NewRELOCATECOHORT(Legion, Cohort) mission.DCStask=mission:GetDCSMissionTask() + if Cohort.isGround then + mission.optionFormation=ENUMS.Formation.Vehicle.OnRoad + end + mission.DCStask.params.legion=Legion mission.DCStask.params.cohort=Cohort @@ -2505,8 +2509,17 @@ function AUFTRAG:GetRequiredAssets(Legion) --if Legion and self.Nassets[Legion.alias] then -- N=self.Nassets[Legion.alias] --end + + local Nmin=self.NassetsMin + local Nmax=self.NassetsMax + + if self.type==AUFTRAG.Type.RELOCATECOHORT then + local cohort=self.DCStask.params.cohort --Ops.Cohort#COHORT + Nmin=#cohort.assets + Nmax=Nmin + end - return self.NassetsMin, self.NassetsMax + return Nmin, Nmax end --- **[LEGION, COMMANDER, CHIEF]** Define how many assets are required that escort the mission assets. diff --git a/Moose Development/Moose/Ops/Commander.lua b/Moose Development/Moose/Ops/Commander.lua index 171365087..5049e05e9 100644 --- a/Moose Development/Moose/Ops/Commander.lua +++ b/Moose Development/Moose/Ops/Commander.lua @@ -732,9 +732,12 @@ function COMMANDER:RelocateCohort(Cohort, Legion, Delay, NcarriersMin, Ncarriers else for _,legion in pairs(self.legions) do mission:AssignTransportLegion(legion) - end + end end + -- Set mission range very large. Mission designer should know... + mission:SetMissionRange(10000) + -- Add mission. self:AddMission(mission) diff --git a/Moose Development/Moose/Ops/Flotilla.lua b/Moose Development/Moose/Ops/Flotilla.lua index 179925658..55e44e9b6 100644 --- a/Moose Development/Moose/Ops/Flotilla.lua +++ b/Moose Development/Moose/Ops/Flotilla.lua @@ -65,7 +65,10 @@ function FLOTILLA:New(TemplateGroupName, Ngroups, FlotillaName) local self=BASE:Inherit(self, COHORT:New(TemplateGroupName, Ngroups, FlotillaName)) -- #FLOTILLA -- All flotillas get mission type Nothing. - self:AddMissionCapability(AUFTRAG.Type.NOTHING, 50) + self:AddMissionCapability(AUFTRAG.Type.NOTHING, 50) + + -- Is naval. + self.isNaval=true -- Get initial ammo. self.ammo=self:_CheckAmmo() diff --git a/Moose Development/Moose/Ops/Legion.lua b/Moose Development/Moose/Ops/Legion.lua index e1339535c..66888cb66 100644 --- a/Moose Development/Moose/Ops/Legion.lua +++ b/Moose Development/Moose/Ops/Legion.lua @@ -499,6 +499,9 @@ function LEGION:RelocateCohort(Cohort, Legion, Delay, NcarriersMin, NcarriersMax end end + -- Set mission range very large. Mission designer should know... + mission:SetMissionRange(10000) + -- Add mission. self:AddMission(mission) end diff --git a/Moose Development/Moose/Ops/NavyGroup.lua b/Moose Development/Moose/Ops/NavyGroup.lua index 5c1cd9781..f0d5268e0 100644 --- a/Moose Development/Moose/Ops/NavyGroup.lua +++ b/Moose Development/Moose/Ops/NavyGroup.lua @@ -541,6 +541,10 @@ function NAVYGROUP:_CreateTurnIntoWind(starttime, stoptime, speed, uturn, offset -- Set start time. local Tstart=UTILS.ClockToSeconds(starttime) + + if uturn==nil then + uturn=true + end -- Set stop time. local Tstop=Tstart+90*60 @@ -1241,8 +1245,8 @@ function NAVYGROUP:onafterTurnIntoWind(From, Event, To, IntoWind) IntoWind.Open=true - IntoWind.Coordinate=self:GetCoordinate() - + IntoWind.Coordinate=self:GetCoordinate(true) + self.intowind=IntoWind -- Wind speed in m/s. diff --git a/Moose Development/Moose/Ops/OpsGroup.lua b/Moose Development/Moose/Ops/OpsGroup.lua index e9c282d4c..ebbfdf6ef 100644 --- a/Moose Development/Moose/Ops/OpsGroup.lua +++ b/Moose Development/Moose/Ops/OpsGroup.lua @@ -2800,7 +2800,7 @@ end --- Get next waypoint index. -- @param #OPSGROUP self --- @param #boolean cyclic If true, return first waypoint if last waypoint was reached. Default is patrol ad infinitum value set. +-- @param #boolean cyclic If `true`, return first waypoint if last waypoint was reached. Default is patrol ad infinitum value set. -- @param #number i Waypoint index from which the next index is returned. Default is the last waypoint passed. -- @return #number Next waypoint index. function OPSGROUP:GetWaypointIndexNext(cyclic, i) @@ -4072,11 +4072,14 @@ function OPSGROUP:onafterTaskExecute(From, Event, To, Task) local wp=nil --#OPSGROUP.Waypoint if self.isArmygroup then self:T2(self.lid.."Routing group to spawn zone of new legion") - wp=ARMYGROUP.AddWaypoint(self, Coordinate, Speed, currUID, Formation) + wp=ARMYGROUP.AddWaypoint(self, Coordinate, UTILS.KmphToKnots(self.speedCruise), currUID, Mission.optionFormation) elseif self.isFlightgroup then self:T2(self.lid.."Routing group to intermediate point near new legion") Coordinate=self:GetCoordinate():GetIntermediateCoordinate(Coordinate, 0.8) wp=FLIGHTGROUP.AddWaypoint(self, Coordinate, UTILS.KmphToKnots(self.speedCruise), currUID, UTILS.MetersToFeet(self.altitudeCruise)) + elseif self.isNavygroup then + self:T2(self.lid.."Routing group to spawn zone of new legion") + wp=NAVYGROUP.AddWaypoint(self, Coordinate, UTILS.KmphToKnots(self.speedCruise), currUID) else end @@ -4993,9 +4996,9 @@ function OPSGROUP:onafterMissionDone(From, Event, To, Mission) -- Emission to default. if Mission.optionEmission then self:SwitchEmission() - end + end -- Formation to default. - if Mission.optionFormation then + if Mission.optionFormation and self:IsFlightgroup() then self:SwitchFormation() end -- Radio freq and modu to default. @@ -5107,6 +5110,17 @@ function OPSGROUP:RouteToMission(mission, delay) -- Ingress waypoint coordinate where the mission is executed. local waypointcoord=nil --Core.Point#COORDINATE + -- Current coordinate of the group. + local currentcoord=self:GetCoordinate() + + -- Road connection. + local roadcoord=currentcoord:GetClosestPointToRoad() + + local roaddist=nil + if roadcoord then + roaddist=currentcoord:Get2DDistance(roadcoord) + end + -- Target zone. local targetzone=nil --Core.Zone#ZONE @@ -5192,14 +5206,23 @@ function OPSGROUP:RouteToMission(mission, delay) --- -- Roughly go to the new legion. - local ToCoordinate=mission.DCStask.params.legion:GetCoordinate() + local ToCoordinate=mission.DCStask.params.legion:GetCoordinate() if self.isFlightgroup then - waypointcoord=self:GetCoordinate():GetIntermediateCoordinate(ToCoordinate, 0.2):SetAltitude(self.altitudeCruise) + -- Get mission waypoint coord in direction of the + waypointcoord=currentcoord:GetIntermediateCoordinate(ToCoordinate, 0.2):SetAltitude(self.altitudeCruise) + elseif self.isArmygroup then + -- Army group: check for road connection. + if roadcoord then + waypointcoord=roadcoord + else + waypointcoord=currentcoord:GetIntermediateCoordinate(ToCoordinate, 100) + end else - waypointcoord=self:GetCoordinate():GetIntermediateCoordinate(ToCoordinate, 0.05) + -- Navy group: Route into direction of the target. + waypointcoord=currentcoord:GetIntermediateCoordinate(ToCoordinate, 0.05) end - + elseif mission.type==AUFTRAG.Type.RECOVERYTANKER then --- -- Recoverytanker @@ -5333,12 +5356,16 @@ function OPSGROUP:RouteToMission(mission, delay) end - -- Add waypoint. + -- Add mission execution (ingress) waypoint. local waypoint=nil --#OPSGROUP.Waypoint if self:IsFlightgroup() then waypoint=FLIGHTGROUP.AddWaypoint(self, waypointcoord, SpeedToMission, uid, UTILS.MetersToFeet(mission.missionAltitude or self.altitudeCruise), false) elseif self:IsArmygroup() then - waypoint=ARMYGROUP.AddWaypoint(self, waypointcoord, SpeedToMission, uid, mission.optionFormation, false) + local formation=mission.optionFormation + if mission.type==AUFTRAG.Type.RELOCATECOHORT then + formation=ENUMS.Formation.Vehicle.OffRoad + end + waypoint=ARMYGROUP.AddWaypoint(self, waypointcoord, SpeedToMission, uid, formation, false) elseif self:IsNavygroup() then waypoint=NAVYGROUP.AddWaypoint(self, waypointcoord, SpeedToMission, uid, UTILS.MetersToFeet(mission.missionAltitude or self.altitudeCruise), false) end @@ -5357,8 +5384,6 @@ function OPSGROUP:RouteToMission(mission, delay) -- Add egress waypoint. local egresscoord=mission:GetMissionEgressCoord() if egresscoord then - --egresscoord:MarkToAll(string.format("Egress Mission %s alt=%d m", mission:GetName(), waypointcoord.y)) - -- Add waypoint. local Ewaypoint=nil --#OPSGROUP.Waypoint if self:IsFlightgroup() then Ewaypoint=FLIGHTGROUP.AddWaypoint(self, egresscoord, SpeedToMission, waypoint.uid, UTILS.MetersToFeet(mission.missionAltitude or self.altitudeCruise), false) @@ -5371,12 +5396,9 @@ function OPSGROUP:RouteToMission(mission, delay) mission:SetGroupEgressWaypointUID(self, Ewaypoint.uid) end - - -- Get current pos. - local coord=self:GetCoordinate() -- Distance to waypoint coordinate. - local d=coord:Get2DDistance(waypointcoord) + local d=currentcoord:Get2DDistance(waypointcoord) -- Debug info. self:T(self.lid..string.format("FF distance to ingress waypoint=%.1f m", d)) @@ -5764,6 +5786,8 @@ function OPSGROUP:onafterPassingWaypoint(From, Event, To, Waypoint) self:_PassedFinalWaypoint(true, "PassingWaypoint: adinfinitum but only ONE WAYPOINT left") else + --[[ Solved now! + -- Looks like the passing waypoint function is triggered over and over again if the group is near the final waypoint. -- So the only good solution is to guide the group away from that waypoint and then update the route. @@ -5772,9 +5796,19 @@ function OPSGROUP:onafterPassingWaypoint(From, Event, To, Waypoint) -- Get a waypoint local Coordinate=Waypoint.coordinate:GetIntermediateCoordinate(wp1.coordinate, 0.1) - - -- Detour to the temp waypoint. When reached, the normal route is resumed. - self:Detour(Coordinate, self.speedCruise, nil, true) + + local formation=nil + if self.isArmygroup then + formation=ENUMS.Formation.Vehicle.OffRoad + end + + self:Detour(Coordinate, self.speedCruise, formation, true) + + ]] + + + -- Send + self:__UpdateRoute(-0.01, 1, 1) end end @@ -5786,6 +5820,27 @@ function OPSGROUP:onafterPassingWaypoint(From, Event, To, Waypoint) -- Final waypoint reached. self:_PassedFinalWaypoint(true, "PassingWaypoint: wpindex=#self.waypoints (or wpindex=nil)") end + + elseif wpindex==1 then + + -- Ad infinitum and not mission waypoint? + if self.adinfinitum then + --- + -- Ad Infinitum + --- + + if #self.waypoints<=1 then + -- Only one waypoint. Ad infinitum does not really make sense. However, another waypoint could be added later... + self:_PassedFinalWaypoint(true, "PassingWaypoint: adinfinitum but only ONE WAYPOINT left") + + else + + if not Waypoint.missionUID then + -- Redo the route until the end. + self:__UpdateRoute(-0.01, 2) + end + end + end end @@ -9686,6 +9741,11 @@ function OPSGROUP:_CheckStuck() -- Debug warning. self:T(self.lid..string.format("WARNING: Group came to an unexpected standstill. Speed=%.1f<%.1f m/s expected for %d sec", speed, ExpectedSpeed, holdtime)) + + if self.legion then + self:T(self.lid..string.format("Asset is returned to its legion after being stuck!")) + self:ReturnToLegion() + end end diff --git a/Moose Development/Moose/Ops/Platoon.lua b/Moose Development/Moose/Ops/Platoon.lua index 405cb2268..c262ff4a5 100644 --- a/Moose Development/Moose/Ops/Platoon.lua +++ b/Moose Development/Moose/Ops/Platoon.lua @@ -65,6 +65,9 @@ function PLATOON:New(TemplateGroupName, Ngroups, PlatoonName) -- All platoons get mission type Nothing. self:AddMissionCapability(AUFTRAG.Type.NOTHING, 50) + + -- Is ground. + self.isGround=true -- Get ammo. self.ammo=self:_CheckAmmo() diff --git a/Moose Development/Moose/Ops/Squadron.lua b/Moose Development/Moose/Ops/Squadron.lua index 43d3c7a22..e720de2cc 100644 --- a/Moose Development/Moose/Ops/Squadron.lua +++ b/Moose Development/Moose/Ops/Squadron.lua @@ -102,6 +102,9 @@ function SQUADRON:New(TemplateGroupName, Ngroups, SquadronName) -- Everyone can ORBIT. self:AddMissionCapability(AUFTRAG.Type.ORBIT) + + -- Is air. + self.isAir=true -- Refueling system. self.refuelSystem=select(2, self.templategroup:GetUnit(1):IsRefuelable())