diff --git a/Moose Development/Moose/Core/Astar.lua b/Moose Development/Moose/Core/Astar.lua index 20db867ba..3ee069619 100644 --- a/Moose Development/Moose/Core/Astar.lua +++ b/Moose Development/Moose/Core/Astar.lua @@ -1,4 +1,4 @@ ---- **Core** - Pathfinding. +--- **Core** - A* Pathfinding. -- -- **Main Features:** -- @@ -272,7 +272,7 @@ end -- @param #ASTAR.Node nodeA Node A. -- @param #ASTAR.Node nodeB Node B. -- @return #number Distance between nodes in meters. -function ASTAR:dist_between ( nodeA, nodeB ) +function ASTAR:DistNodes ( nodeA, nodeB ) return nodeA.coordinate:Get2DDistance(nodeB.coordinate) end @@ -281,8 +281,8 @@ end -- @param #ASTAR.Node nodeA Node A. -- @param #ASTAR.Node nodeB Node B. -- @return #number Distance between nodes in meters. -function ASTAR:heuristic_cost_estimate( nodeA, nodeB ) - return self:dist_between(nodeA, nodeB) +function ASTAR:HeuristicCost( nodeA, nodeB ) + return self:DistNodes(nodeA, nodeB) end --- Function @@ -318,7 +318,7 @@ end --- Function -- @param #ASTAR self -function ASTAR:neighbor_nodes ( theNode, nodes ) +function ASTAR:neighbor_nodes(theNode, nodes) local neighbors = {} for _, node in ipairs ( nodes ) do @@ -360,11 +360,11 @@ end --- Function -- @param #ASTAR self -function ASTAR:unwind_path ( flat_path, map, current_node ) +function ASTAR:UnwindPath( flat_path, map, current_node ) if map [ current_node ] then table.insert ( flat_path, 1, map [ current_node ] ) - return self:unwind_path ( flat_path, map, map [ current_node ] ) + return self:UnwindPath ( flat_path, map, map [ current_node ] ) else return flat_path end @@ -393,14 +393,14 @@ function ASTAR:GetPath() g_score [ start ] = 0 - f_score [ start ] = g_score [ start ] + self:heuristic_cost_estimate ( start, goal ) + f_score [ start ] = g_score [ start ] + self:HeuristicCost ( start, goal ) while #openset > 0 do local current = self:lowest_f_score ( openset, f_score ) if current == goal then - local path = self:unwind_path ( {}, came_from, goal ) + local path = self:UnwindPath ( {}, came_from, goal ) table.insert(path, goal) return path end @@ -414,13 +414,13 @@ function ASTAR:GetPath() if self:not_in ( closedset, neighbor ) then - local tentative_g_score = g_score [ current ] + self:dist_between ( current, neighbor ) + local tentative_g_score = g_score [ current ] + self:DistNodes ( current, neighbor ) if self:not_in ( openset, neighbor ) or tentative_g_score < g_score [ neighbor ] then came_from [ neighbor ] = current g_score [ neighbor ] = tentative_g_score - f_score [ neighbor ] = g_score [ neighbor ] + self:heuristic_cost_estimate ( neighbor, goal ) + f_score [ neighbor ] = g_score [ neighbor ] + self:HeuristicCost ( neighbor, goal ) if self:not_in ( openset, neighbor ) then table.insert ( openset, neighbor ) diff --git a/Moose Development/Moose/Ops/AirWing.lua b/Moose Development/Moose/Ops/AirWing.lua index 56bf7ca4b..b894e7621 100644 --- a/Moose Development/Moose/Ops/AirWing.lua +++ b/Moose Development/Moose/Ops/AirWing.lua @@ -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. -- -- VFA151=SQUADRON:New("F-14 Group", 8, "VFA-151 (Vigilantes)") --- VFA151:AddMissonCapability({AUFTRAG.Type.PATROL, AUFTRAG.Type.INTERCEPT}) +-- VFA151:AddMissionCapability({AUFTRAG.Type.PATROL, AUFTRAG.Type.INTERCEPT}) -- -- airwing:AddSquadron(VFA151) -- diff --git a/Moose Development/Moose/Ops/ArmyGroup.lua b/Moose Development/Moose/Ops/ArmyGroup.lua new file mode 100644 index 000000000..0533311fc --- /dev/null +++ b/Moose Development/Moose/Ops/ArmyGroup.lua @@ -0,0 +1,899 @@ +--- **Ops** - Enhanced Ground Group. +-- +-- **Main Features:** +-- +-- * Dynamically add and remove waypoints. +-- +-- === +-- +-- ### Author: **funkyfranky** +-- @module Ops.ArmyGroup +-- @image OPS_ArmyGroup.png + + +--- ARMYGROUP class. +-- @type ARMYGROUP +-- @field #boolean adinfinitum Resume route at first waypoint when final waypoint is reached. +-- @extends Ops.OpsGroup#OPSGROUP + +--- *Something must be left to chance; nothing is sure in a sea fight above all.* -- Horatio Nelson +-- +-- === +-- +-- ![Banner Image](..\Presentations\ARMYGROUP\NavyGroup_Main.jpg) +-- +-- # The ARMYGROUP Concept +-- +-- This class enhances naval groups. +-- +-- @field #ARMYGROUP +ARMYGROUP = { + ClassName = "ARMYGROUP", +} + +--- Navy group element. +-- @type ARMYGROUP.Element +-- @field #string name Name of the element, i.e. the unit. +-- @field #string typename Type name. + +--- NavyGroup version. +-- @field #string version +ARMYGROUP.version="0.0.1" + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +-- TODO list +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +-- TODO: A lot. + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +-- Constructor +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +--- Create a new ARMYGROUP class object. +-- @param #ARMYGROUP self +-- @param #string GroupName Name of the group. +-- @return #ARMYGROUP self +function ARMYGROUP:New(GroupName) + + -- Inherit everything from FSM class. + local self=BASE:Inherit(self, OPSGROUP:New(GroupName)) -- #ARMYGROUP + + -- Set some string id for output to DCS.log file. + self.lid=string.format("ARMYGROUP %s | ", self.groupname) + + -- Defaults + self:SetDefaultROE() + self:SetDetection() + self:SetPatrolAdInfinitum(true) + + -- Add FSM transitions. + -- From State --> Event --> To State + self:AddTransition("*", "FullStop", "Holding") -- Hold position. + + self:AddTransition("*", "Detour", "OnDetour") -- Make a detour to a coordinate and resume route afterwards. + self:AddTransition("OnDetour", "DetourReached", "Cruising") -- Group reached the detour coordinate. + + ------------------------ + --- Pseudo Functions --- + ------------------------ + + --- Triggers the FSM event "Stop". Stops the ARMYGROUP and all its event handlers. + -- @param #ARMYGROUP self + + --- Triggers the FSM event "Stop" after a delay. Stops the ARMYGROUP and all its event handlers. + -- @function [parent=#ARMYGROUP] __Stop + -- @param #ARMYGROUP self + -- @param #number delay Delay in seconds. + + -- TODO: Add pseudo functions. + + + -- Init waypoints. + self:InitWaypoints() + + -- Initialize the group. + self:_InitGroup() + + -- Debug trace. + if false then + self.Debug=true + BASE:TraceOnOff(true) + BASE:TraceClass(self.ClassName) + BASE:TraceLevel(1) + end + + -- Handle events: + self:HandleEvent(EVENTS.Birth, self.OnEventBirth) + self:HandleEvent(EVENTS.Dead, self.OnEventDead) + self:HandleEvent(EVENTS.RemoveUnit, self.OnEventRemoveUnit) + + -- Start the status monitoring. + self:__CheckZone(-1) + self:__Status(-2) + self:__QueueUpdate(-3) + + return self +end + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +-- User Functions +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +--- Group patrols ad inifintum. If the last waypoint is reached, it will go to waypoint one and repeat its route. +-- @param #ARMYGROUP self +-- @param #boolean switch If true or nil, patrol until the end of time. If false, go along the waypoints once and stop. +-- @return #ARMYGROUP self +function ARMYGROUP:SetPatrolAdInfinitum(switch) + if switch==false then + self.adinfinitum=false + else + self.adinfinitum=true + end + return self +end + +--- Group patrols ad inifintum. If the last waypoint is reached, it will go to waypoint one and repeat its route. +-- @param #ARMYGROUP self +-- @param #number Speed Speed in knots. Default 70% of max speed. +-- @return #ARMYGROUP self +function ARMYGROUP:SetSpeedCruise(Speed) + + self.speedCruise=Speed and UTILS.KnotsToKmph(Speed) or self.speedmax*0.7 + + return self +end + + +--- Add a *scheduled* task. +-- @param #ARMYGROUP self +-- @param Core.Point#COORDINATE Coordinate Coordinate of the target. +-- @param #number Radius Radius in meters. Default 100 m. +-- @param #number Nshots Number of shots to fire. Default 3. +-- @param #number WeaponType Type of weapon. Default auto. +-- @param #string Clock Time when to start the attack. +-- @param #number Prio Priority of the task. +function ARMYGROUP:AddTaskFireAtPoint(Coordinate, Radius, Nshots, WeaponType, Clock, Prio) + + local DCStask=CONTROLLABLE.TaskFireAtPoint(nil, Coordinate:GetVec2(), Radius, Nshots, WeaponType) + + self:AddTask(DCStask, Clock, nil, Prio) + +end + +--- Add a *scheduled* task. +-- @param #ARMYGROUP self +-- @param Wrapper.Group#GROUP TargetGroup Target group. +-- @param #number WeaponExpend How much weapons does are used. +-- @param #number WeaponType Type of weapon. Default auto. +-- @param #string Clock Time when to start the attack. +-- @param #number Prio Priority of the task. +function ARMYGROUP:AddTaskAttackGroup(TargetGroup, WeaponExpend, WeaponType, Clock, Prio) + + local DCStask=CONTROLLABLE.TaskAttackGroup(nil, TargetGroup, WeaponType, WeaponExpend, AttackQty, Direction, Altitude, AttackQtyLimit, GroupAttack) + + self:AddTask(DCStask, Clock, nil, Prio) + +end + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +-- Status +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +---- Update status. +-- @param #ARMYGROUP self +function ARMYGROUP:onbeforeStatus(From, Event, To) + + if self:IsDead() then + self:I(self.lid..string.format("Onbefore Status DEAD ==> false")) + return false + elseif self:IsStopped() then + self:I(self.lid..string.format("Onbefore Status STOPPED ==> false")) + return false + end + + return true +end + +--- Update status. +-- @param #ARMYGROUP self +function ARMYGROUP:onafterStatus(From, Event, To) + + -- FSM state. + local fsmstate=self:GetState() + + --- + -- Detection + --- + + -- Check if group has detected any units. + if self.detectionOn then + self:_CheckDetectedUnits() + end + + if self:IsAlive() and not self:IsDead() then + + -- Current heading and position of the carrier. + local hdg=self:GetHeading() + local pos=self:GetCoordinate() + local speed=self.group:GetVelocityKNOTS() + + + -- Get number of tasks and missions. + local nTaskTot, nTaskSched, nTaskWP=self:CountRemainingTasks() + local nMissions=self:CountRemainingMissison() + + -- Info text. + local text=string.format("State %s: Wp=%d/%d Speed=%.1f Heading=%03d Tasks=%d Missions=%d", + fsmstate, self.currentwp, #self.waypoints, speed, hdg, nTaskTot, nMissions) + self:I(self.lid..text) + + else + + -- Info text. + local text=string.format("State %s: Alive=%s", fsmstate, tostring(self:IsAlive())) + self:I(self.lid..text) + + end + + + --- + -- Tasks + --- + + -- Task queue. + if #self.taskqueue>0 and self.verbose>1 then + local text=string.format("Tasks #%d", #self.taskqueue) + for i,_task in pairs(self.taskqueue) do + local task=_task --Ops.OpsGroup#OPSGROUP.Task + local name=task.description + local taskid=task.dcstask.id or "unknown" + local status=task.status + local clock=UTILS.SecondsToClock(task.time, true) + local eta=task.time-timer.getAbsTime() + local started=task.timestamp and UTILS.SecondsToClock(task.timestamp, true) or "N/A" + local duration=-1 + if task.duration then + duration=task.duration + if task.timestamp then + -- Time the task is running. + duration=task.duration-(timer.getAbsTime()-task.timestamp) + else + -- Time the task is supposed to run. + duration=task.duration + end + end + -- Output text for element. + if task.type==OPSGROUP.TaskType.SCHEDULED then + text=text..string.format("\n[%d] %s (%s): status=%s, scheduled=%s (%d sec), started=%s, duration=%d", i, taskid, name, status, clock, eta, started, duration) + elseif task.type==OPSGROUP.TaskType.WAYPOINT then + text=text..string.format("\n[%d] %s (%s): status=%s, waypoint=%d, started=%s, duration=%d, stopflag=%d", i, taskid, name, status, task.waypoint, started, duration, task.stopflag:Get()) + end + end + self:I(self.lid..text) + end + + --- + -- Missions + --- + + -- Current mission name. + if self.verbose>0 then + local Mission=self:GetMissionByID(self.currentmission) + + -- Current status. + local text=string.format("Missions %d, Current: %s", self:CountRemainingMissison(), Mission and Mission.name or "none") + for i,_mission in pairs(self.missionqueue) do + local mission=_mission --Ops.Auftrag#AUFTRAG + local Cstart= UTILS.SecondsToClock(mission.Tstart, true) + local Cstop = mission.Tstop and UTILS.SecondsToClock(mission.Tstop, true) or "INF" + text=text..string.format("\n[%d] %s (%s) status=%s (%s), Time=%s-%s, prio=%d wp=%s targets=%d", + i, tostring(mission.name), mission.type, mission:GetGroupStatus(self), tostring(mission.status), Cstart, Cstop, mission.prio, tostring(mission:GetGroupWaypointIndex(self)), mission:CountMissionTargets()) + end + self:I(self.lid..text) + end + + self:__Status(-10) +end + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +-- FSM Events +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +--- On after "ElementSpawned" event. +-- @param #ARMYGROUP self +-- @param #string From From state. +-- @param #string Event Event. +-- @param #string To To state. +-- @param #ARMYGROUP.Element Element The group element. +function ARMYGROUP:onafterElementSpawned(From, Event, To, Element) + self:I(self.lid..string.format("Element spawned %s", Element.name)) + + -- Set element status. + self:_UpdateStatus(Element, OPSGROUP.ElementStatus.SPAWNED) + +end + +--- On after "ElementDead" event. +-- @param #ARMYGROUP self +-- @param #string From From state. +-- @param #string Event Event. +-- @param #string To To state. +-- @param #ARMYGROUP.Element Element The group element. +function ARMYGROUP:onafterElementDead(From, Event, To, Element) + self:T(self.lid..string.format("Element dead %s.", Element.name)) + + -- Set element status. + self:_UpdateStatus(Element, OPSGROUP.ElementStatus.DEAD) +end + +--- On after "Spawned" event. +-- @param #ARMYGROUP self +-- @param #string From From state. +-- @param #string Event Event. +-- @param #string To To state. +function ARMYGROUP:onafterSpawned(From, Event, To) + self:I(self.lid..string.format("Group spawned!")) + + if self.ai then + + -- Set default ROE and ROT options. + self:SetOptionROE(self.roe) + + end + + -- Get orientation. + self.Corientlast=self.group:GetUnit(1):GetOrientationX() + + self.depth=self.group:GetHeight() + + -- Update route. + self:Cruise() + +end + +--- On after "UpdateRoute" event. +-- @param #ARMYGROUP self +-- @param #string From From state. +-- @param #string Event Event. +-- @param #string To To state. +-- @param #number n Waypoint number. Default is next waypoint. +-- @param #number Speed Speed in knots. Default cruise speed. +-- @param #number Depth Depth in meters. Default 0 meters. +function ARMYGROUP:onafterUpdateRoute(From, Event, To, n, Speed, Depth) + + -- Update route from this waypoint number onwards. + n=n or self:GetWaypointIndexNext(self.adinfinitum) + + -- Debug info. + self:T(self.lid..string.format("FF Update route n=%d", n)) + + -- Update waypoint tasks, i.e. inject WP tasks into waypoint table. + self:_UpdateWaypointTasks(n) + + -- Waypoints. + local waypoints={} + + -- Depth for submarines. + local depth=Depth or 0 + + -- Get current speed in km/h. + local speed=Speed and UTILS.KnotsToKmph(Speed) or self.group:GetVelocityKMH() + + -- Current waypoint. + local current=self:GetCoordinate():WaypointNaval(speed, depth) + table.insert(waypoints, current) + + -- Add remaining waypoints to route. + for i=n, #self.waypoints do + local wp=self.waypoints[i] + + -- Set speed. + if i==n then + + if Speed then + wp.speed=UTILS.KnotsToMps(Speed) + elseif self.speedCruise then + wp.speed=UTILS.KmphToMps(self.speedCruise) + else + -- Take default waypoint speed. + end + + else + + if self.speedCruise then + wp.speed=UTILS.KmphToMps(self.speedCruise) + else + -- Take default waypoint speed. + end + + end + + -- Set depth. + wp.alt=-depth --Depth and -Depth or wp.alt + + -- Add waypoint. + table.insert(waypoints, wp) + end + + + if #waypoints>1 then + + self:I(self.lid..string.format("Updateing route: WP=%d, Speed=%.1f knots, depth=%d meters", #self.waypoints-n+1, UTILS.KmphToKnots(speed), depth)) + + -- Route group to all defined waypoints remaining. + self:Route(waypoints) + + else + + --- + -- No waypoints left + --- + + self:I(self.lid..string.format("No waypoints left")) + + if #self.waypoints>1 then + self:I(self.lid..string.format("Resuming route at first waypoint")) + self:__UpdateRoute(-1, 1, nil, self.depth) + end + + end + +end + +--- On after "Detour" event. +-- @param #ARMYGROUP self +-- @param #string From From state. +-- @param #string Event Event. +-- @param #string To To state. +-- @param Core.Point#COORDINATE Coordinate Coordinate where to go. +-- @param #number Speed Speed in knots. Default cruise speed. +-- @param #number Depth Depth in meters. Default 0 meters. +-- @param #number ResumeRoute If true, resume route after detour point was reached. +function ARMYGROUP:onafterDetour(From, Event, To, Coordinate, Speed, Depth, ResumeRoute) + + -- Waypoints. + local waypoints={} + + -- Depth for submarines. + local depth=Depth or 0 + + -- Get current speed in km/h. + local speed=Speed and UTILS.KnotsToKmph(Speed) or self.group:GetVelocityKMH() + + -- Current waypoint. + local current=self:GetCoordinate():WaypointGround(Speed,Formation,DCSTasks) + table.insert(waypoints, current) + + -- At each waypoint report passing. + local Task=self.group:TaskFunction("ARMYGROUP._DetourReached", self, ResumeRoute) + + local detour=Coordinate:WaypointNaval(speed, depth, {Task}) + table.insert(waypoints, detour) + + self:Route(waypoints) + +end + +--- On after "DetourReached" event. +-- @param #ARMYGROUP self +-- @param #string From From state. +-- @param #string Event Event. +-- @param #string To To state. +function ARMYGROUP:onafterDetourReached(From, Event, To) + self:I(self.lid.."Group reached detour coordinate.") +end + +--- Function called when a group is passing a waypoint. +--@param Wrapper.Group#GROUP group Group that passed the waypoint +--@param #ARMYGROUP navygroup Navy group object. +--@param #boolean resume Resume route. +function ARMYGROUP._DetourReached(group, navygroup, resume) + + -- Debug message. + local text=string.format("Group reached detour coordinate") + navygroup:I(navygroup.lid..text) + + if resume then + local indx=navygroup:GetWaypointIndexNext(true) + local speed=navygroup:GetSpeedToWaypoint(indx) + navygroup:UpdateRoute(indx, speed, navygroup.depth) + end + + navygroup:DetourReached() + +end + +--- On after "FullStop" event. +-- @param #ARMYGROUP self +-- @param #string From From state. +-- @param #string Event Event. +-- @param #string To To state. +function ARMYGROUP:onafterFullStop(From, Event, To) + + -- Get current position. + local pos=self:GetCoordinate() + + -- Create a new waypoint. + local wp=pos:WaypointNaval(0) + + -- Create new route consisting of only this position ==> Stop! + self:Route({wp}) + +end + +--- On after "Cruise" event. +-- @param #ARMYGROUP self +-- @param #string From From state. +-- @param #string Event Event. +-- @param #string To To state. +-- @param #number Speed Speed in knots. +function ARMYGROUP:onafterCruise(From, Event, To, Speed) + + self:UpdateRoute(nil, Speed, self.depth) + +end + + + +--- On after "Dead" event. +-- @param #ARMYGROUP self +-- @param #string From From state. +-- @param #string Event Event. +-- @param #string To To state. +function ARMYGROUP:onafterDead(From, Event, To) + self:I(self.lid..string.format("Group dead!")) + + -- Delete waypoints so they are re-initialized at the next spawn. + self.waypoints=nil + self.groupinitialized=false + + -- Cancel all mission. + for _,_mission in pairs(self.missionqueue) do + local mission=_mission --Ops.Auftrag#AUFTRAG + + self:MissionCancel(mission) + mission:GroupDead(self) + + end + + -- Stop + self:Stop() +end + +--- On after Start event. Starts the ARMYGROUP FSM and event handlers. +-- @param #ARMYGROUP self +-- @param #string From From state. +-- @param #string Event Event. +-- @param #string To To state. +function ARMYGROUP:onafterStop(From, Event, To) + + -- Check if group is still alive. + if self:IsAlive() then + -- Destroy group. No event is generated. + self.group:Destroy(false) + end + + -- Handle events: + self:UnHandleEvent(EVENTS.Birth) + self:UnHandleEvent(EVENTS.Dead) + self:UnHandleEvent(EVENTS.RemoveUnit) + + self.CallScheduler:Clear() + + self:I(self.lid.."STOPPED! Unhandled events, cleared scheduler and removed from database.") +end + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +-- Events DCS +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +--- Event function handling the birth of a unit. +-- @param #ARMYGROUP self +-- @param Core.Event#EVENTDATA EventData Event data. +function ARMYGROUP:OnEventBirth(EventData) + + -- Check that this is the right group. + if EventData and EventData.IniGroup and EventData.IniUnit and EventData.IniGroupName and EventData.IniGroupName==self.groupname then + local unit=EventData.IniUnit + local group=EventData.IniGroup + local unitname=EventData.IniUnitName + + if self.respawning then + + local function reset() + self.respawning=nil + end + + -- Reset switch in 1 sec. This should allow all birth events of n>1 groups to have passed. + -- TODO: Can I do this more rigorously? + self:ScheduleOnce(1, reset) + + else + + -- Get element. + local element=self:GetElementByName(unitname) + + -- Set element to spawned state. + self:T3(self.lid..string.format("EVENT: Element %s born ==> spawned", element.name)) + self:ElementSpawned(element) + + end + + end + +end + +--- Flightgroup event function handling the crash of a unit. +-- @param #ARMYGROUP self +-- @param Core.Event#EVENTDATA EventData Event data. +function ARMYGROUP:OnEventDead(EventData) + + -- Check that this is the right group. + if EventData and EventData.IniGroup and EventData.IniUnit and EventData.IniGroupName and EventData.IniGroupName==self.groupname then + self:T(self.lid..string.format("EVENT: Unit %s dead!", EventData.IniUnitName)) + + local unit=EventData.IniUnit + local group=EventData.IniGroup + local unitname=EventData.IniUnitName + + -- Get element. + local element=self:GetElementByName(unitname) + + if element then + self:I(self.lid..string.format("EVENT: Element %s dead ==> dead", element.name)) + self:ElementDead(element) + end + + end + +end + +--- Flightgroup event function handling the crash of a unit. +-- @param #ARMYGROUP self +-- @param Core.Event#EVENTDATA EventData Event data. +function ARMYGROUP:OnEventRemoveUnit(EventData) + + -- Check that this is the right group. + if EventData and EventData.IniGroup and EventData.IniUnit and EventData.IniGroupName and EventData.IniGroupName==self.groupname then + local unit=EventData.IniUnit + local group=EventData.IniGroup + local unitname=EventData.IniUnitName + + -- Get element. + local element=self:GetElementByName(unitname) + + if element then + self:I(self.lid..string.format("EVENT: Element %s removed ==> dead", element.name)) + self:ElementDead(element) + end + + end + +end + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +-- Routing +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +--- Add an a waypoint to the route. +-- @param #ARMYGROUP self +-- @param Core.Point#COORDINATE coordinate The coordinate of the waypoint. Use COORDINATE:SetAltitude(altitude) to define the altitude. +-- @param #number speed Speed in knots. Default is default cruise speed or 70% of max speed. +-- @param #number wpnumber Waypoint number. Default at the end. +-- @param #boolean updateroute If true or nil, call UpdateRoute. If false, no call. +-- @return #number Waypoint index. +function ARMYGROUP:AddWaypoint(coordinate, speed, wpnumber, updateroute) + + -- Waypoint number. Default is at the end. + wpnumber=wpnumber or #self.waypoints+1 + + if wpnumber>self.currentwp then + self.passedfinalwp=false + end + + -- Speed in knots. + speed=speed or self:GetSpeedCruise() + + -- Speed at waypoint. + local speedkmh=UTILS.KnotsToKmph(speed) + + -- Create a Naval waypoint. + local wp=coordinate:WaypointNaval(speedkmh) + + -- Add to table. + table.insert(self.waypoints, wpnumber, wp) + + -- Debug info. + self:T(self.lid..string.format("Adding NAVAL waypoint #%d, speed=%.1f knots. Last waypoint passed was #%s. Total waypoints #%d", wpnumber, speed, self.currentwp, #self.waypoints)) + + + -- Update route. + if updateroute==nil or updateroute==true then + self:_CheckGroupDone(1) + end + + return wpnumber +end + +--- Initialize group parameters. Also initializes waypoints if self.waypoints is nil. +-- @param #ARMYGROUP self +-- @return #ARMYGROUP self +function ARMYGROUP:_InitGroup() + + -- First check if group was already initialized. + if self.groupinitialized then + self:E(self.lid.."WARNING: Group was already initialized!") + return + end + + -- Get template of group. + self.template=self.group:GetTemplate() + + -- Define category. + self.isAircraft=false + self.isNaval=false + self.isGround=true + + -- Ships are always AI. + self.ai=true + + -- Is (template) group late activated. + self.isLateActivated=self.template.lateActivation + + -- Naval groups cannot be uncontrolled. + self.isUncontrolled=false + + -- Max speed in km/h. + self.speedmax=self.group:GetSpeedMax() + + -- Group ammo. + --self.ammo=self:GetAmmoTot() + + self.traveldist=0 + self.traveltime=timer.getAbsTime() + self.position=self:GetCoordinate() + + -- Radio parameters from template. + self.radioOn=true -- Radio is always on for ships. + self.radioFreq=tonumber(self.template.units[1].frequency)/1000000 + self.radioModu=tonumber(self.template.units[1].modulation)/1000000 + + -- If not set by the use explicitly yet, we take the template values as defaults. + if not self.radioFreqDefault then + self.radioFreqDefault=self.radioFreq + self.radioModuDefault=self.radioModu + end + + -- Set default formation. + if not self.formationDefault then + if self.ishelo then + self.formationDefault=ENUMS.Formation.RotaryWing.EchelonLeft.D300 + else + self.formationDefault=ENUMS.Formation.FixedWing.EchelonLeft.Group + end + end + + local units=self.group:GetUnits() + + for _,_unit in pairs(units) do + local unit=_unit --Wrapper.Unit#UNIT + + local element={} --#ARMYGROUP.Element + element.name=unit:GetName() + element.typename=unit:GetTypeName() + element.status=OPSGROUP.ElementStatus.INUTERO + element.unit=unit + table.insert(self.elements, element) + + self:GetAmmoUnit(unit, false) + + if unit:IsAlive() then + self:ElementSpawned(element) + end + + end + + -- Get first unit. This is used to extract other parameters. + local unit=self.group:GetUnit(1) + + if unit then + + self.descriptors=unit:GetDesc() + + self.actype=unit:GetTypeName() + + -- Debug info. + local text=string.format("Initialized Navy Group %s:\n", self.groupname) + text=text..string.format("AC type = %s\n", self.actype) + text=text..string.format("Speed max = %.1f Knots\n", UTILS.KmphToKnots(self.speedmax)) + --text=text..string.format("Speed cruise = %.1f Knots\n", UTILS.KmphToKnots(self.speedCruise)) + text=text..string.format("Elements = %d\n", #self.elements) + text=text..string.format("Waypoints = %d\n", #self.waypoints) + text=text..string.format("Radio = %.1f MHz %s %s\n", self.radioFreq, UTILS.GetModulationName(self.radioModu), tostring(self.radioOn)) + --text=text..string.format("Ammo = %d (G=%d/R=%d/B=%d/M=%d)\n", self.ammo.Total, self.ammo.Guns, self.ammo.Rockets, self.ammo.Bombs, self.ammo.Missiles) + text=text..string.format("FSM state = %s\n", self:GetState()) + text=text..string.format("Is alive = %s\n", tostring(self.group:IsAlive())) + text=text..string.format("LateActivate = %s\n", tostring(self:IsLateActivated())) + self:I(self.lid..text) + + -- Init done. + self.groupinitialized=true + + end + + return self +end + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +-- Misc Functions +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +--- Check if group is done, i.e. +-- +-- * passed the final waypoint, +-- * no current task +-- * no current mission +-- * number of remaining tasks is zero +-- * number of remaining missions is zero +-- +-- @param #ARMYGROUP self +-- @param #number delay Delay in seconds. +function ARMYGROUP:_CheckGroupDone(delay) + + if self:IsAlive() and self.ai then + + if delay and delay>0 then + -- Delayed call. + self:ScheduleOnce(delay, ARMYGROUP._CheckGroupDone, self) + else + + if self.passedfinalwp then + + if #self.waypoints>1 and self.adinfinitum then + + local speed=self:GetSpeedToWaypoint(1) + + -- Start route at first waypoint. + self:__UpdateRoute(-1, 1, speed, self.depth) + + end + + else + + self:UpdateRoute(nil, nil, self.depth) + + end + + end + + end + +end + + +--- Get default cruise speed. +-- @param #ARMYGROUP self +-- @return #number Cruise speed (>0) in knots. +function ARMYGROUP:GetSpeedCruise() + return UTILS.KmphToKnots(self.speedCruise or self.speedmax*0.7) +end + +--- Returns a non-zero speed to the next waypoint (even if the waypoint speed is zero). +-- @param #ARMYGROUP self +-- @param #number indx Waypoint index. +-- @return #number Speed to next waypoint (>0) in knots. +function ARMYGROUP:GetSpeedToWaypoint(indx) + + local speed=self:GetWaypointSpeed(indx) + + if speed<=0.1 then + speed=self:GetSpeedCruise() + end + + return speed +end + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- diff --git a/Moose Development/Moose/Ops/FlightGroup.lua b/Moose Development/Moose/Ops/FlightGroup.lua index c4f53b443..1d0f2c05c 100644 --- a/Moose Development/Moose/Ops/FlightGroup.lua +++ b/Moose Development/Moose/Ops/FlightGroup.lua @@ -2956,7 +2956,7 @@ end -- @param #number speed Speed in knots. Default 350 kts. -- @param #number wpnumber Waypoint number. Default at the end. -- @param #boolean updateroute If true or nil, call UpdateRoute. If false, no call. --- @return #number Waypoint index. +-- @return Ops.OpsGroup#OPSGROUP.Waypoint Waypoint table. function FLIGHTGROUP:AddWaypoint(coordinate, speed, wpnumber, updateroute) -- Waypoint number. Default is at the end. @@ -2973,43 +2973,24 @@ function FLIGHTGROUP:AddWaypoint(coordinate, speed, wpnumber, updateroute) local speedkmh=UTILS.KnotsToKmph(speed) -- Create air waypoint. - local wp=coordinate:WaypointAir(COORDINATE.WaypointAltType.BARO, COORDINATE.WaypointType.TurningPoint, COORDINATE.WaypointAction.TurningPoint, speedkmh, true, nil, {}, string.format("Added Waypoint #%d", wpnumber)) + local name=string.format("Added Waypoint #%d", wpnumber) + local wp=coordinate:WaypointAir(COORDINATE.WaypointAltType.BARO, COORDINATE.WaypointType.TurningPoint, COORDINATE.WaypointAction.TurningPoint, speedkmh, true, nil, {}, name) - -- Add to table. - table.insert(self.waypoints, wpnumber, wp) + -- Create waypoint data table. + local waypoint=self:_CreateWaypoint(wp) + + -- Add waypoint to table. + self:_AddWaypoint(waypoint, wpnumber) -- Debug info. self:T(self.lid..string.format("Adding AIR waypoint #%d, speed=%.1f knots. Last waypoint passed was #%s. Total waypoints #%d", wpnumber, speed, self.currentwp, #self.waypoints)) - -- Shift all waypoint tasks after the inserted waypoint. - for _,_task in pairs(self.taskqueue) do - local task=_task --Ops.OpsGroup#OPSGROUP.Task - if task.type==OPSGROUP.TaskType.WAYPOINT and task.waypoint and task.waypoint>=wpnumber then - task.waypoint=task.waypoint+1 - end - end - - -- Shift all mission waypoints after the inserted waypoint. - for _,_mission in pairs(self.missionqueue) do - local mission=_mission --Ops.Auftrag#AUFTRAG - - -- Get mission waypoint index. - local wpidx=mission:GetGroupWaypointIndex(self) - - -- Increase number if this waypoint lies in the future. - if wpidx and wpidx>=wpnumber then - mission:SetGroupWaypointIndex(self, wpidx+1) - end - - end - -- Update route. if updateroute==nil or updateroute==true then - --self:_CheckGroupDone(1) self:__UpdateRoute(-1) end - return wpnumber + return waypoint end diff --git a/Moose Development/Moose/Ops/NavyGroup.lua b/Moose Development/Moose/Ops/NavyGroup.lua index d6fe5816f..046cf4f8b 100644 --- a/Moose Development/Moose/Ops/NavyGroup.lua +++ b/Moose Development/Moose/Ops/NavyGroup.lua @@ -934,7 +934,7 @@ end -- @param #number speed Speed in knots. Default is default cruise speed or 70% of max speed. -- @param #number wpnumber Waypoint number. Default at the end. -- @param #boolean updateroute If true or nil, call UpdateRoute. If false, no call. --- @return #number Waypoint index. +-- @return Ops.OpsGroup#OPSGROUP.Waypoint Waypoint table. function NAVYGROUP:AddWaypoint(coordinate, speed, wpnumber, updateroute) -- Waypoint number. Default is at the end. @@ -952,41 +952,22 @@ function NAVYGROUP:AddWaypoint(coordinate, speed, wpnumber, updateroute) -- Create a Naval waypoint. local wp=coordinate:WaypointNaval(speedkmh) - - -- Add to table. - table.insert(self.waypoints, wpnumber, wp) + + -- Create waypoint data table. + local waypoint=self:_CreateWaypoint(wp) + + -- Add waypoint to table. + self:_AddWaypoint(waypoint, wpnumber) -- Debug info. self:T(self.lid..string.format("Adding NAVAL waypoint #%d, speed=%.1f knots. Last waypoint passed was #%s. Total waypoints #%d", wpnumber, speed, self.currentwp, #self.waypoints)) - - -- Shift all waypoint tasks after the inserted waypoint. - for _,_task in pairs(self.taskqueue) do - local task=_task --Ops.OpsGroup#OPSGROUP.Task - if task.type==OPSGROUP.TaskType.WAYPOINT and task.waypoint and task.waypoint>=wpnumber then - task.waypoint=task.waypoint+1 - end - end - -- Shift all mission waypoints after the inserted waypoint. - for _,_mission in pairs(self.missionqueue) do - local mission=_mission --Ops.Auftrag#AUFTRAG - - -- Get mission waypoint index. - local wpidx=mission:GetGroupWaypointIndex(self) - - -- Increase number if this waypoint lies in the future. - if wpidx and wpidx>=wpnumber then - mission:SetGroupWaypointIndex(self, wpidx+1) - end - - end - -- Update route. if updateroute==nil or updateroute==true then self:_CheckGroupDone(1) end - return wpnumber + return waypoint end --- Initialize group parameters. Also initializes waypoints if self.waypoints is nil. diff --git a/Moose Development/Moose/Ops/OpsGroup.lua b/Moose Development/Moose/Ops/OpsGroup.lua index 65422467a..c625458a6 100644 --- a/Moose Development/Moose/Ops/OpsGroup.lua +++ b/Moose Development/Moose/Ops/OpsGroup.lua @@ -39,6 +39,7 @@ -- @field #number speedmax Max speed in km/h. -- @field #number speedCruise Cruising speed in km/h. -- @field #boolean passedfinalwp Group has passed the final waypoint. +-- @field #number wpcounter Running number counting waypoints. -- @field #boolean respawning Group is being respawned. -- @field Core.Set#SET_ZONE checkzones Set of zones. -- @field Core.Set#SET_ZONE inzones Set of zones in which the group is currently in. @@ -117,6 +118,7 @@ OPSGROUP = { inzones = nil, groupinitialized = nil, respawning = nil, + wpcounter = 1, } --- Status of group element. @@ -201,6 +203,19 @@ OPSGROUP.TaskType={ -- @field #number MissilesCR Amount of cruise missiles. -- @field #number MissilesBM Amount of ballistic missiles. +--- Waypoint data. +-- @type OPSGROUP.Waypoint +-- @field #table wp DCS waypoint table. +-- @field Core.Point#COORDINATE coordinate Waypoint coordinate. +-- @field #number speed Speed in m/s. +-- @field #number altitude Altitude in meters. For submaries use negative sign for depth. +-- @field #number index Waypoint index. This might change as waypoints are added and removed. +-- @field #number uid Waypoint's unit id, which is a running number. +-- @field #boolean onroad If true, ground group takes a road. +-- @field #number formation The formation for this waypoint. +-- @field #boolean detour If true, this waypoint is not part of the normal route. +-- @field #string action Waypoint action (turning point, etc.). Ground groups have the formation here. + --- NavyGroup version. -- @field #string version OPSGROUP.version="0.1.0" @@ -632,6 +647,70 @@ end -- Waypoint Functions ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +--- Get the waypoint from its unique ID. +-- @param #OPSGROUP self +-- @param #number uid Waypoint unique ID. +-- @return #OPSGROUP.Waypoint Waypoint data. +function OPSGROUP:GetWaypointByID(uid) + + for _,_waypoint in pairs(self.waypoints) do + local waypoint=_waypoint --#OPSGROUP.Waypoint + if waypoint.uid==uid then + return waypoint + end + end + + return nil +end + +--- Get the waypoint from its index. +-- @param #OPSGROUP self +-- @param #number index Waypoint index. +-- @return #OPSGROUP.Waypoint Waypoint data. +function OPSGROUP:GetWaypointByIndex(index) + + for i,_waypoint in pairs(self.waypoints) do + local waypoint=_waypoint --#OPSGROUP.Waypoint + if i==index then + return waypoint + end + end + + return nil +end + +--- Get the waypoint index (its position in the current waypoints table). +-- @param #OPSGROUP self +-- @param #number uid Waypoint unique ID. +-- @return #OPSGROUP.Waypoint Waypoint data. +function OPSGROUP:GetWaypointIndex(uid) + + for i,_waypoint in pairs(self.waypoints) do + local waypoint=_waypoint --#OPSGROUP.Waypoint + if waypoint.uid==uid then + return i + end + end + + return nil +end + +--- Remove a waypoint with a ceratin UID. +-- @param #OPSGROUP self +-- @param #number uid Waypoint UID. +-- @return #OPSGROUP self +function OPSGROUP:RemoveWaypointByID(uid) + + local index=self:GetWaypointIndex(uid) + + if index then + self:RemoveWaypoint(index) + + end + + return self +end + --- Remove a waypoint. -- @param #OPSGROUP self -- @param #number wpindex Waypoint number. @@ -652,28 +731,6 @@ function OPSGROUP:RemoveWaypoint(wpindex) -- Debug info. self:I(self.lid..string.format("Removing waypoint %d. N %d-->%d", wpindex, N, n)) - -- Shift all waypoint tasks after the removed waypoint. - for _,_task in pairs(self.taskqueue) do - local task=_task --#OPSGROUP.Task - if task.type==OPSGROUP.TaskType.WAYPOINT and task.waypoint and task.waypoint>wpindex then - task.waypoint=task.waypoint-1 - end - end - - -- Shift all mission waypoints after the removerd waypoint. - for _,_mission in pairs(self.missionqueue) do - local mission=_mission --Ops.Auftrag#AUFTRAG - - -- Get mission waypoint index. - local wpidx=mission:GetGroupWaypointIndex(self) - - -- Reduce number if this waypoint lies in the future. - if wpidx and wpidx>wpindex then - mission:SetGroupWaypointIndex(self, wpidx-1) - end - end - - -- Waypoint was not reached yet. if wpindex > self.currentwp then @@ -858,35 +915,46 @@ end -- @return #OPSGROUP.Task The task structure. function OPSGROUP:AddTaskWaypoint(task, waypointindex, description, prio, duration) - -- Increase counter. - self.taskcounter=self.taskcounter+1 - - -- Task data structure. - local newtask={} --#OPSGROUP.Task - newtask.description=description - newtask.status=OPSGROUP.TaskStatus.SCHEDULED - newtask.dcstask=task - newtask.prio=prio or 50 - newtask.id=self.taskcounter - newtask.duration=duration - newtask.time=0 - newtask.waypoint=waypointindex or (self.currentwp and self.currentwp+1 or 2) - newtask.type=OPSGROUP.TaskType.WAYPOINT - newtask.stopflag=USERFLAG:New(string.format("%s StopTaskFlag %d", self.groupname, newtask.id)) - newtask.stopflag:Set(0) - - -- Add to table. - table.insert(self.taskqueue, newtask) + -- Index. + waypointindex=waypointindex or (self.currentwp and self.currentwp+1 or 2) - -- Info. - self:I(self.lid..string.format("Adding WAYPOINT task %s at WP %d", newtask.description, newtask.waypoint)) - self:T3({newtask=newtask}) + -- Get waypoint + local waypoint=self:GetWaypointByIndex(waypointindex) - -- Update route. - --self:_CheckGroupDone(1) - self:__UpdateRoute(-1) + if waypoint then - return newtask + -- Increase counter. + self.taskcounter=self.taskcounter+1 + + -- Task data structure. + local newtask={} --#OPSGROUP.Task + newtask.description=description + newtask.status=OPSGROUP.TaskStatus.SCHEDULED + newtask.dcstask=task + newtask.prio=prio or 50 + newtask.id=self.taskcounter + newtask.duration=duration + newtask.time=0 + newtask.waypoint=waypoint.uid + newtask.type=OPSGROUP.TaskType.WAYPOINT + newtask.stopflag=USERFLAG:New(string.format("%s StopTaskFlag %d", self.groupname, newtask.id)) + newtask.stopflag:Set(0) + + -- Add to table. + table.insert(self.taskqueue, newtask) + + -- Info. + self:I(self.lid..string.format("Adding WAYPOINT task %s at WP %d", newtask.description, newtask.waypoint)) + self:T3({newtask=newtask}) + + -- Update route. + --self:_CheckGroupDone(1) + self:__UpdateRoute(-1) + + return newtask + end + + return nil end --- Add an *enroute* task. @@ -1215,20 +1283,7 @@ function OPSGROUP:onafterTaskCancel(From, Event, To, Task) -- Call task done function. self:TaskDone(Task) - - - --[[ - local mission=self:GetMissionByTaskID(Task.id) - - -- Is this a waypoint task? - if Task.type==OPSGROUP.TaskType.WAYPOINT and Task.waypoint then - -- Check that this is a mission waypoint and no other tasks are defined here. - if mission and #self:GetTasksWaypoint(Task.waypoint)==0 then - self:RemoveWaypoint(Task.waypoint) - end - end - ]] end else @@ -1710,7 +1765,7 @@ function OPSGROUP:RouteToMission(mission, delay) end -- Add waypoint. - self:AddWaypoint(waypointcoord, UTILS.KmphToKnots(self.speedCruise), nextwaypoint, false) + local waypoint=self:AddWaypoint(waypointcoord, UTILS.KmphToKnots(self.speedCruise), nextwaypoint, false) -- Special for Troop transport. if mission.type==AUFTRAG.Type.TROOPTRANSPORT then @@ -1738,7 +1793,7 @@ function OPSGROUP:RouteToMission(mission, delay) mission:SetGroupWaypointTask(self, waypointtask) -- Set waypoint index. - mission:SetGroupWaypointIndex(self, nextwaypoint) + mission:SetGroupWaypointIndex(self, waypoint.uid) --- -- Mission Specific Settings @@ -1848,13 +1903,14 @@ end -- @param #string To To state. -- @param #number n Waypoint passed. -- @param #number N Total number of waypoints. -function OPSGROUP:onafterPassingWaypoint(From, Event, To, n, N) +-- @param #OPSGROUP.Waypoint Waypoint Waypoint data passed. +function OPSGROUP:onafterPassingWaypoint(From, Event, To, n, N, Waypoint) local text=string.format("Group passed waypoint %d/%d", n, N) self:T(self.lid..text) MESSAGE:New(text, 30, "DEBUG"):ToAllIf(self.Debug) -- Get all waypoint tasks. - local tasks=self:GetTasksWaypoint(n) + local tasks=self:GetTasksWaypoint(Waypoint.uid) -- Debug info. local text=string.format("WP %d/%d tasks:", n, N) @@ -2125,6 +2181,43 @@ end -- Waypoints & Routing ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +--- Initialize Mission Editor waypoints. +-- @param #OPSGROUP self +-- @param #table waypoint DCS waypoint data table. +-- @return #OPSGROUP.Waypoint Waypoint data. +function OPSGROUP:_CreateWaypoint(waypoint) + + local wp={} --#OPSGROUP.Waypoint + + wp.wp=waypoint + wp.uid=self.wpcounter + + wp.altitude=altitude + wp.speed=speed + wp.detour=detour + wp.formation=formation + wp.onroad=onroad + + wp.coordinate=coordinate + + self.wpcounter=self.wpcounter+1 + + return wp +end + +--- Initialize Mission Editor waypoints. +-- @param #OPSGROUP self +-- @param #OPSGROUP.Waypoint waypoint Waypoint data. +-- @param #number wpnumber Waypoint index/number. Default is as last waypoint. +function OPSGROUP:_AddWaypoint(waypoint, wpnumber) + + wpnumber=wpnumber or #self.waypoints+1 + + -- Add waypoint to table. + tabel.insert(self.waypoints, wpnumber, waypoint) + +end + --- Initialize Mission Editor waypoints. -- @param #OPSGROUP self -- @param #table waypoints Table of waypoints. Default is from group template. @@ -2134,8 +2227,17 @@ function OPSGROUP:InitWaypoints(waypoints) -- Template waypoints. self.waypoints0=self.group:GetTemplateRoutePoints() - -- Waypoints of group as defined in the ME. - self.waypoints=waypoints or UTILS.DeepCopy(self.waypoints0) + -- Waypoints + self.waypoints={} + + for index,wp in pairs(self.waypoints0) do + + local waypoint=self:_CreateWaypoint() + + self:_AddWaypoint(waypoint) + + + end -- Debug info. self:I(self.lid..string.format("Initializing %d waypoints", #self.waypoints)) @@ -2201,7 +2303,8 @@ function OPSGROUP:_UpdateWaypointTasks(n) local waypoints=self.waypoints local nwaypoints=#waypoints - for i,wp in pairs(waypoints) do + for i,_wp in pairs(waypoints) do + local wp=_wp --Ops.OpsGroup#OPSGROUP.Waypoint if i>=n or nwaypoints==1 then @@ -2212,11 +2315,11 @@ function OPSGROUP:_UpdateWaypointTasks(n) local taskswp={} -- At each waypoint report passing. - local TaskPassingWaypoint=self.group:TaskFunction("OPSGROUP._PassingWaypoint", self, i) + local TaskPassingWaypoint=self.group:TaskFunction("OPSGROUP._PassingWaypoint", self, i, wp.uid) table.insert(taskswp, TaskPassingWaypoint) -- Waypoint task combo. - wp.task=self.group:TaskCombo(taskswp) + wp.wp.task=self.group:TaskCombo(taskswp) end @@ -2232,19 +2335,23 @@ end --@param Wrapper.Group#GROUP group Group that passed the waypoint --@param #OPSGROUP opsgroup Ops group object. --@param #number i Waypoint number that has been reached. -function OPSGROUP._PassingWaypoint(group, opsgroup, i) +--@param #number uid Waypoint UID. +function OPSGROUP._PassingWaypoint(group, opsgroup, i, uid) local final=#opsgroup.waypoints or 1 -- Debug message. - local text=string.format("Group passing waypoint %d of %d", i, final) + local text=string.format("Group passing waypoint %d of %d, uid=%d", i, final, uid) opsgroup:I(opsgroup.lid..text) -- Set current waypoint. opsgroup.currentwp=i + + -- Get waypoint data. + local waypoint=opsgroup:GetWaypointByID(uid) -- Trigger PassingWaypoint event. - opsgroup:PassingWaypoint(i, final) + opsgroup:PassingWaypoint(i, final, waypoint) end diff --git a/Moose Development/Moose/Ops/Squadron.lua b/Moose Development/Moose/Ops/Squadron.lua index 99ac9c9b1..dd1da2d86 100644 --- a/Moose Development/Moose/Ops/Squadron.lua +++ b/Moose Development/Moose/Ops/Squadron.lua @@ -133,7 +133,7 @@ function SQUADRON:New(TemplateGroupName, Ngroups, SquadronName) self:SetEngagementRange() -- Everyone can ORBIT. - self:AddMissonCapability(AUFTRAG.Type.ORBIT) + self:AddMissionCapability(AUFTRAG.Type.ORBIT) self.attribute=self.templategroup:GetAttribute() @@ -261,7 +261,7 @@ end -- @param #table MissionTypes Table of mission types. Can also be passed as a #string if only one type. -- @param #number Performance Performance describing how good this mission can be performed. Higher is better. Default 50. Max 100. -- @return #SQUADRON self -function SQUADRON:AddMissonCapability(MissionTypes, Performance) +function SQUADRON:AddMissionCapability(MissionTypes, Performance) -- Ensure Missiontypes is a table. if MissionTypes and type(MissionTypes)~="table" then diff --git a/Moose Development/Moose/Utilities/Utils.lua b/Moose Development/Moose/Utilities/Utils.lua index ece8a111b..74a7b4c5b 100644 --- a/Moose Development/Moose/Utilities/Utils.lua +++ b/Moose Development/Moose/Utilities/Utils.lua @@ -353,7 +353,7 @@ UTILS.MpsToMiph = function( mps ) end --- Convert meters per second to knots. --- @param #number knots Speed in m/s. +-- @param #number mps Speed in m/s. -- @return #number Speed in knots. UTILS.MpsToKnots = function( mps ) return mps * 1.94384 --3600 / 1852