mirror of
https://github.com/FlightControl-Master/MOOSE.git
synced 2025-10-29 16:58:06 +00:00
Waypoints
This commit is contained in:
parent
d9b7cc18f3
commit
af023c1994
@ -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 )
|
||||
|
||||
@ -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)
|
||||
--
|
||||
|
||||
899
Moose Development/Moose/Ops/ArmyGroup.lua
Normal file
899
Moose Development/Moose/Ops/ArmyGroup.lua
Normal file
@ -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
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- # 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
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
@ -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
|
||||
|
||||
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user