mirror of
https://github.com/FlightControl-Master/MOOSE.git
synced 2026-08-22 16:05:25 +00:00
Ops Cargo
This commit is contained in:
@@ -1444,6 +1444,22 @@ function DATABASE:GetOpsGroup(groupname)
|
|||||||
return self.FLIGHTGROUPS[groupname]
|
return self.FLIGHTGROUPS[groupname]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Find an OPSGROUP (FLIGHTGROUP, ARMYGROUP, NAVYGROUP) in the data base.
|
||||||
|
-- @param #DATABASE self
|
||||||
|
-- @param #string groupname Group name of the group. Can also be passed as GROUP object.
|
||||||
|
-- @return Ops.OpsGroup#OPSGROUP OPS group object.
|
||||||
|
function DATABASE:FindOpsGroup(groupname)
|
||||||
|
|
||||||
|
-- Get group and group name.
|
||||||
|
if type(groupname)=="string" then
|
||||||
|
else
|
||||||
|
groupname=groupname:GetName()
|
||||||
|
end
|
||||||
|
|
||||||
|
env.info("Getting OPSGROUP "..tostring(groupname))
|
||||||
|
return self.FLIGHTGROUPS[groupname]
|
||||||
|
end
|
||||||
|
|
||||||
--- Add a flight control to the data base.
|
--- Add a flight control to the data base.
|
||||||
-- @param #DATABASE self
|
-- @param #DATABASE self
|
||||||
-- @param Ops.FlightControl#FLIGHTCONTROL flightcontrol
|
-- @param Ops.FlightControl#FLIGHTCONTROL flightcontrol
|
||||||
|
|||||||
@@ -233,7 +233,7 @@ do -- SET_BASE
|
|||||||
-- @param Core.Base#BASE Object The object itself.
|
-- @param Core.Base#BASE Object The object itself.
|
||||||
-- @return Core.Base#BASE The added BASE Object.
|
-- @return Core.Base#BASE The added BASE Object.
|
||||||
function SET_BASE:Add( ObjectName, Object )
|
function SET_BASE:Add( ObjectName, Object )
|
||||||
self:F2( { ObjectName = ObjectName, Object = Object } )
|
self:I( { ObjectName = ObjectName, Object = Object } )
|
||||||
|
|
||||||
-- Ensure that the existing element is removed from the Set before a new one is inserted to the Set
|
-- Ensure that the existing element is removed from the Set before a new one is inserted to the Set
|
||||||
if self.Set[ObjectName] then
|
if self.Set[ObjectName] then
|
||||||
@@ -5948,3 +5948,603 @@ do -- SET_ZONE_GOAL
|
|||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
do -- SET_OPSGROUP
|
||||||
|
|
||||||
|
--- @type SET_OPSGROUP
|
||||||
|
-- @extends Core.Set#SET_BASE
|
||||||
|
|
||||||
|
--- Mission designers can use the @{Core.Set#SET_OPSGROUP} class to build sets of OPS groups belonging to certain:
|
||||||
|
--
|
||||||
|
-- * Coalitions
|
||||||
|
-- * Categories
|
||||||
|
-- * Countries
|
||||||
|
-- * Contain a certain string pattern
|
||||||
|
--
|
||||||
|
-- ## SET_OPSGROUP constructor
|
||||||
|
--
|
||||||
|
-- Create a new SET_OPSGROUP object with the @{#SET_OPSGROUP.New} method:
|
||||||
|
--
|
||||||
|
-- * @{#SET_OPSGROUP.New}: Creates a new SET_OPSGROUP object.
|
||||||
|
--
|
||||||
|
-- ## Add or Remove GROUP(s) from SET_OPSGROUP
|
||||||
|
--
|
||||||
|
-- GROUPS can be added and removed using the @{Core.Set#SET_OPSGROUP.AddGroupsByName} and @{Core.Set#SET_OPSGROUP.RemoveGroupsByName} respectively.
|
||||||
|
-- These methods take a single GROUP name or an array of GROUP names to be added or removed from SET_OPSGROUP.
|
||||||
|
--
|
||||||
|
-- ## SET_OPSGROUP filter criteria
|
||||||
|
--
|
||||||
|
-- You can set filter criteria to define the set of groups within the SET_OPSGROUP.
|
||||||
|
-- Filter criteria are defined by:
|
||||||
|
--
|
||||||
|
-- * @{#SET_OPSGROUP.FilterCoalitions}: Builds the SET_OPSGROUP with the groups belonging to the coalition(s).
|
||||||
|
-- * @{#SET_OPSGROUP.FilterCategories}: Builds the SET_OPSGROUP with the groups belonging to the category(ies).
|
||||||
|
-- * @{#SET_OPSGROUP.FilterCountries}: Builds the SET_OPSGROUP with the groups belonging to the country(ies).
|
||||||
|
-- * @{#SET_OPSGROUP.FilterPrefixes}: Builds the SET_OPSGROUP with the groups *containing* the given string in the group name. **Attention!** Bad naming convention, as this not really filtering *prefixes*.
|
||||||
|
-- * @{#SET_OPSGROUP.FilterActive}: Builds the SET_OPSGROUP with the groups that are only active. Groups that are inactive (late activation) won't be included in the set!
|
||||||
|
--
|
||||||
|
-- For the Category Filter, extra methods have been added:
|
||||||
|
--
|
||||||
|
-- * @{#SET_OPSGROUP.FilterCategoryAirplane}: Builds the SET_OPSGROUP from airplanes.
|
||||||
|
-- * @{#SET_OPSGROUP.FilterCategoryHelicopter}: Builds the SET_OPSGROUP from helicopters.
|
||||||
|
-- * @{#SET_OPSGROUP.FilterCategoryGround}: Builds the SET_OPSGROUP from ground vehicles or infantry.
|
||||||
|
-- * @{#SET_OPSGROUP.FilterCategoryShip}: Builds the SET_OPSGROUP from ships.
|
||||||
|
--
|
||||||
|
--
|
||||||
|
-- Once the filter criteria have been set for the SET_OPSGROUP, you can start filtering using:
|
||||||
|
--
|
||||||
|
-- * @{#SET_OPSGROUP.FilterStart}: Starts the filtering of the groups within the SET_OPSGROUP and add or remove GROUP objects **dynamically**.
|
||||||
|
-- * @{#SET_OPSGROUP.FilterOnce}: Filters of the groups **once**.
|
||||||
|
--
|
||||||
|
--
|
||||||
|
-- ## SET_OPSGROUP iterators
|
||||||
|
--
|
||||||
|
-- Once the filters have been defined and the SET_OPSGROUP has been built, you can iterate the SET_OPSGROUP with the available iterator methods.
|
||||||
|
-- The iterator methods will walk the SET_OPSGROUP set, and call for each element within the set a function that you provide.
|
||||||
|
-- The following iterator methods are currently available within the SET_OPSGROUP:
|
||||||
|
--
|
||||||
|
-- * @{#SET_OPSGROUP.ForEachGroup}: Calls a function for each alive group it finds within the SET_OPSGROUP.
|
||||||
|
--
|
||||||
|
-- ## SET_OPSGROUP trigger events on the GROUP objects.
|
||||||
|
--
|
||||||
|
-- The SET is derived from the FSM class, which provides extra capabilities to track the contents of the GROUP objects in the SET_OPSGROUP.
|
||||||
|
--
|
||||||
|
-- ### When a GROUP object crashes or is dead, the SET_OPSGROUP will trigger a **Dead** event.
|
||||||
|
--
|
||||||
|
-- You can handle the event using the OnBefore and OnAfter event handlers.
|
||||||
|
-- The event handlers need to have the paramters From, Event, To, GroupObject.
|
||||||
|
-- The GroupObject is the GROUP object that is dead and within the SET_OPSGROUP, and is passed as a parameter to the event handler.
|
||||||
|
-- See the following example:
|
||||||
|
--
|
||||||
|
-- -- Create the SetCarrier SET_OPSGROUP collection.
|
||||||
|
--
|
||||||
|
-- local SetHelicopter = SET_OPSGROUP:New():FilterPrefixes( "Helicopter" ):FilterStart()
|
||||||
|
--
|
||||||
|
-- -- Put a Dead event handler on SetCarrier, to ensure that when a carrier is destroyed, that all internal parameters are reset.
|
||||||
|
--
|
||||||
|
-- function SetHelicopter:OnAfterDead( From, Event, To, GroupObject )
|
||||||
|
-- self:F( { GroupObject = GroupObject:GetName() } )
|
||||||
|
-- end
|
||||||
|
--
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- @field #SET_OPSGROUP SET_OPSGROUP
|
||||||
|
--
|
||||||
|
SET_OPSGROUP = {
|
||||||
|
ClassName = "SET_OPSGROUP",
|
||||||
|
Filter = {
|
||||||
|
Coalitions = nil,
|
||||||
|
Categories = nil,
|
||||||
|
Countries = nil,
|
||||||
|
GroupPrefixes = nil,
|
||||||
|
},
|
||||||
|
FilterMeta = {
|
||||||
|
Coalitions = {
|
||||||
|
red = coalition.side.RED,
|
||||||
|
blue = coalition.side.BLUE,
|
||||||
|
neutral = coalition.side.NEUTRAL,
|
||||||
|
},
|
||||||
|
Categories = {
|
||||||
|
plane = Group.Category.AIRPLANE,
|
||||||
|
helicopter = Group.Category.HELICOPTER,
|
||||||
|
ground = Group.Category.GROUND,
|
||||||
|
ship = Group.Category.SHIP,
|
||||||
|
},
|
||||||
|
}, -- FilterMeta
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
--- Creates a new SET_OPSGROUP object, building a set of groups belonging to a coalitions, categories, countries, types or with defined prefix names.
|
||||||
|
-- @param #SET_OPSGROUP self
|
||||||
|
-- @return #SET_OPSGROUP
|
||||||
|
function SET_OPSGROUP:New()
|
||||||
|
|
||||||
|
-- Inherit SET_BASE.
|
||||||
|
local self = BASE:Inherit(self, SET_BASE:New(_DATABASE.GROUPS)) -- #SET_OPSGROUP
|
||||||
|
|
||||||
|
-- Include non activated
|
||||||
|
self:FilterActive( false )
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Gets the Set.
|
||||||
|
-- @param #SET_OPSGROUP self
|
||||||
|
-- @return #SET_OPSGROUP self
|
||||||
|
function SET_OPSGROUP:GetAliveSet()
|
||||||
|
|
||||||
|
local AliveSet = SET_OPSGROUP:New()
|
||||||
|
|
||||||
|
-- Clean the Set before returning with only the alive Groups.
|
||||||
|
for GroupName, GroupObject in pairs(self.Set) do
|
||||||
|
local GroupObject=GroupObject --Wrapper.Group#GROUP
|
||||||
|
|
||||||
|
if GroupObject and GroupObject:IsAlive() then
|
||||||
|
AliveSet:Add(GroupName, GroupObject)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return AliveSet.Set or {}
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Adds a @{Core.Base#BASE} object in the @{Core.Set#SET_BASE}, using a given ObjectName as the index.
|
||||||
|
-- @param #SET_BASE self
|
||||||
|
-- @param #string ObjectName The name of the object.
|
||||||
|
-- @param Core.Base#BASE Object The object itself.
|
||||||
|
-- @return Core.Base#BASE The added BASE Object.
|
||||||
|
function SET_OPSGROUP:Add(ObjectName, Object)
|
||||||
|
self:I( { ObjectName = ObjectName, Object = Object } )
|
||||||
|
|
||||||
|
-- Ensure that the existing element is removed from the Set before a new one is inserted to the Set
|
||||||
|
if self.Set[ObjectName] then
|
||||||
|
self:Remove(ObjectName, true)
|
||||||
|
end
|
||||||
|
|
||||||
|
local object=nil --Ops.OpsGroup#OPSGROUP
|
||||||
|
if Object:IsInstanceOf("GROUP") then
|
||||||
|
|
||||||
|
---
|
||||||
|
-- GROUP Object
|
||||||
|
---
|
||||||
|
|
||||||
|
-- Fist, look up in the DATABASE if an OPSGROUP already exists.
|
||||||
|
object=_DATABASE:FindOpsGroup(ObjectName)
|
||||||
|
|
||||||
|
if not object then
|
||||||
|
|
||||||
|
if Object:IsShip() then
|
||||||
|
object=NAVYGROUP:New(Object)
|
||||||
|
elseif Object:IsGround() then
|
||||||
|
object=ARMYGROUP:New(Object)
|
||||||
|
elseif Object:IsAir() then
|
||||||
|
object=FLIGHTGROUP:New(Object)
|
||||||
|
else
|
||||||
|
env.error("ERROR: Unknown category of group object!")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
elseif Object:IsInstanceOf("OPSGROUP") then
|
||||||
|
-- We already have an OPSGROUP.
|
||||||
|
object=Object
|
||||||
|
else
|
||||||
|
env.error("ERROR: Object must be a GROUP or OPSGROUP!")
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Add object to set.
|
||||||
|
self.Set[ObjectName]=object
|
||||||
|
|
||||||
|
-- Add Object name to Index.
|
||||||
|
table.insert(self.Index, ObjectName)
|
||||||
|
|
||||||
|
-- Trigger Added event.
|
||||||
|
self:Added(ObjectName, object)
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Add a GROUP or OPSGROUP object to the set.
|
||||||
|
-- **NOTE** that an OPSGROUP is automatically created from the GROUP if it does not exist already.
|
||||||
|
-- @param Core.Set#SET_OPSGROUP self
|
||||||
|
-- @param Wrapper.Group#GROUP group The GROUP which should be added to the set. Can also be given as an #OPSGROUP object.
|
||||||
|
-- @return Core.Set#SET_OPSGROUP self
|
||||||
|
function SET_OPSGROUP:AddGroup(group)
|
||||||
|
|
||||||
|
local groupname=group:GetName()
|
||||||
|
|
||||||
|
self:Add(groupname, group )
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Add GROUP(s) or OPSGROUP(s) to the set.
|
||||||
|
-- @param Core.Set#SET_OPSGROUP self
|
||||||
|
-- @param #string AddGroupNames A single name or an array of GROUP names.
|
||||||
|
-- @return Core.Set#SET_OPSGROUP self
|
||||||
|
function SET_OPSGROUP:AddGroupsByName( AddGroupNames )
|
||||||
|
|
||||||
|
local AddGroupNamesArray = ( type( AddGroupNames ) == "table" ) and AddGroupNames or { AddGroupNames }
|
||||||
|
|
||||||
|
for AddGroupID, AddGroupName in pairs( AddGroupNamesArray ) do
|
||||||
|
self:Add(AddGroupName, GROUP:FindByName(AddGroupName))
|
||||||
|
end
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Remove GROUP(s) or OPSGROUP(s) from the set.
|
||||||
|
-- @param Core.Set#SET_OPSGROUP self
|
||||||
|
-- @param Wrapper.Group#GROUP RemoveGroupNames A single name or an array of GROUP names.
|
||||||
|
-- @return Core.Set#SET_OPSGROUP self
|
||||||
|
function SET_OPSGROUP:RemoveGroupsByName( RemoveGroupNames )
|
||||||
|
|
||||||
|
local RemoveGroupNamesArray = ( type( RemoveGroupNames ) == "table" ) and RemoveGroupNames or { RemoveGroupNames }
|
||||||
|
|
||||||
|
for RemoveGroupID, RemoveGroupName in pairs( RemoveGroupNamesArray ) do
|
||||||
|
self:Remove( RemoveGroupName )
|
||||||
|
end
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Finds an OPSGROUP based on the group name.
|
||||||
|
-- @param #SET_OPSGROUP self
|
||||||
|
-- @param #string GroupName Name of the group.
|
||||||
|
-- @return Ops.OpsGroup#OPSGROUP The found OPSGROUP (FLIGHTGROUP, ARMYGROUP or NAVYGROUP) or `#nil` if the group is not in the set.
|
||||||
|
function SET_OPSGROUP:FindGroup(GroupName)
|
||||||
|
local GroupFound = self.Set[GroupName]
|
||||||
|
return GroupFound
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Finds a FLIGHTGROUP based on the group name.
|
||||||
|
-- @param #SET_OPSGROUP self
|
||||||
|
-- @param #string GroupName Name of the group.
|
||||||
|
-- @return Ops.FlightGroup#FLIGHTGROUP The found FLIGHTGROUP or `#nil` if the group is not in the set.
|
||||||
|
function SET_OPSGROUP:FindFlightGroup(GroupName)
|
||||||
|
local GroupFound = self:FindGroup(GroupName)
|
||||||
|
return GroupFound
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Finds a ARMYGROUP based on the group name.
|
||||||
|
-- @param #SET_OPSGROUP self
|
||||||
|
-- @param #string GroupName Name of the group.
|
||||||
|
-- @return Ops.ArmyGroup#ARMYGROUP The found ARMYGROUP or `#nil` if the group is not in the set.
|
||||||
|
function SET_OPSGROUP:FindArmyGroup(GroupName)
|
||||||
|
local GroupFound = self:FindGroup(GroupName)
|
||||||
|
return GroupFound
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Finds a NAVYGROUP based on the group name.
|
||||||
|
-- @param #SET_OPSGROUP self
|
||||||
|
-- @param #string GroupName Name of the group.
|
||||||
|
-- @return Ops.NavyGroup#NAVYGROUP The found NAVYGROUP or `#nil` if the group is not in the set.
|
||||||
|
function SET_OPSGROUP:FindNavyGroup(GroupName)
|
||||||
|
local GroupFound = self:FindGroup(GroupName)
|
||||||
|
return GroupFound
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Builds a set of groups of coalitions.
|
||||||
|
-- Possible current coalitions are red, blue and neutral.
|
||||||
|
-- @param #SET_OPSGROUP self
|
||||||
|
-- @param #string Coalitions Can take the following values: "red", "blue", "neutral" or combinations as a table, for example `{"red", "neutral"}`.
|
||||||
|
-- @return #SET_OPSGROUP self
|
||||||
|
function SET_OPSGROUP:FilterCoalitions(Coalitions)
|
||||||
|
|
||||||
|
-- Create an empty set.
|
||||||
|
if not self.Filter.Coalitions then
|
||||||
|
self.Filter.Coalitions={}
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Ensure we got a table.
|
||||||
|
if type(Coalitions)~="table" then
|
||||||
|
Coalitions = {Coalitions}
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Set filter.
|
||||||
|
for CoalitionID, Coalition in pairs( Coalitions ) do
|
||||||
|
self.Filter.Coalitions[Coalition] = Coalition
|
||||||
|
end
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Builds a set of groups out of categories.
|
||||||
|
--
|
||||||
|
-- Possible current categories are:
|
||||||
|
--
|
||||||
|
-- * "plane" for fixed wing groups
|
||||||
|
-- * "helicopter" for rotary wing groups
|
||||||
|
-- * "ground" for ground groups
|
||||||
|
-- * "ship" for naval groups
|
||||||
|
--
|
||||||
|
-- @param #SET_OPSGROUP self
|
||||||
|
-- @param #string Categories Can take the following values: "plane", "helicopter", "ground", "ship" or combinations as a table, for example `{"plane", "helicopter"}`.
|
||||||
|
-- @return #SET_OPSGROUP self
|
||||||
|
function SET_OPSGROUP:FilterCategories( Categories )
|
||||||
|
|
||||||
|
if not self.Filter.Categories then
|
||||||
|
self.Filter.Categories={}
|
||||||
|
end
|
||||||
|
|
||||||
|
if type(Categories)~="table" then
|
||||||
|
Categories={Categories}
|
||||||
|
end
|
||||||
|
|
||||||
|
for CategoryID, Category in pairs( Categories ) do
|
||||||
|
self.Filter.Categories[Category] = Category
|
||||||
|
end
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Builds a set of groups out of ground category.
|
||||||
|
-- @param #SET_OPSGROUP self
|
||||||
|
-- @return #SET_OPSGROUP self
|
||||||
|
function SET_OPSGROUP:FilterCategoryGround()
|
||||||
|
self:FilterCategories("ground")
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Builds a set of groups out of airplane category.
|
||||||
|
-- @param #SET_OPSGROUP self
|
||||||
|
-- @return #SET_OPSGROUP self
|
||||||
|
function SET_OPSGROUP:FilterCategoryAirplane()
|
||||||
|
self:FilterCategories("plane")
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Builds a set of groups out of aicraft category (planes and helicopters).
|
||||||
|
-- @param #SET_OPSGROUP self
|
||||||
|
-- @return #SET_OPSGROUP self
|
||||||
|
function SET_OPSGROUP:FilterCategoryAircraft()
|
||||||
|
self:FilterCategories({"plane", "helicopter"})
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Builds a set of groups out of helicopter category.
|
||||||
|
-- @param #SET_OPSGROUP self
|
||||||
|
-- @return #SET_OPSGROUP self
|
||||||
|
function SET_OPSGROUP:FilterCategoryHelicopter()
|
||||||
|
self:FilterCategories("helicopter")
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Builds a set of groups out of ship category.
|
||||||
|
-- @param #SET_OPSGROUP self
|
||||||
|
-- @return #SET_OPSGROUP self
|
||||||
|
function SET_OPSGROUP:FilterCategoryShip()
|
||||||
|
self:FilterCategories("ship")
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Builds a set of groups of defined countries.
|
||||||
|
-- @param #SET_OPSGROUP self
|
||||||
|
-- @param #string Countries Can take those country strings known within DCS world.
|
||||||
|
-- @return #SET_OPSGROUP self
|
||||||
|
function SET_OPSGROUP:FilterCountries(Countries)
|
||||||
|
|
||||||
|
-- Create empty table if necessary.
|
||||||
|
if not self.Filter.Countries then
|
||||||
|
self.Filter.Countries = {}
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Ensure input is a table.
|
||||||
|
if type(Countries)~="table" then
|
||||||
|
Countries={Countries}
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Set filter.
|
||||||
|
for CountryID, Country in pairs( Countries ) do
|
||||||
|
self.Filter.Countries[Country] = Country
|
||||||
|
end
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Builds a set of groups that contain the given string in their group name.
|
||||||
|
-- **Attention!** Bad naming convention as this **does not** filter only **prefixes** but all groups that **contain** the string.
|
||||||
|
-- @param #SET_OPSGROUP self
|
||||||
|
-- @param #string Prefixes The string pattern(s) that needs to be contained in the group name. Can also be passed as a `#table` of strings.
|
||||||
|
-- @return #SET_OPSGROUP self
|
||||||
|
function SET_OPSGROUP:FilterPrefixes(Prefixes)
|
||||||
|
|
||||||
|
-- Create emtpy table if necessary.
|
||||||
|
if not self.Filter.GroupPrefixes then
|
||||||
|
self.Filter.GroupPrefixes={}
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Ensure we have a table.
|
||||||
|
if type(Prefixes)~="table" then
|
||||||
|
Prefixes={Prefixes}
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Set group prefixes.
|
||||||
|
for PrefixID, Prefix in pairs(Prefixes) do
|
||||||
|
self.Filter.GroupPrefixes[Prefix]=Prefix
|
||||||
|
end
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Builds a set of groups that are only active.
|
||||||
|
-- Only the groups that are active will be included within the set.
|
||||||
|
-- @param #SET_OPSGROUP self
|
||||||
|
-- @param #boolean Active (optional) Include only active groups to the set.
|
||||||
|
-- Include inactive groups if you provide false.
|
||||||
|
-- @return #SET_OPSGROUP self
|
||||||
|
-- @usage
|
||||||
|
--
|
||||||
|
-- -- Include only active groups to the set.
|
||||||
|
-- GroupSet = SET_OPSGROUP:New():FilterActive():FilterStart()
|
||||||
|
--
|
||||||
|
-- -- Include only active groups to the set of the blue coalition, and filter one time.
|
||||||
|
-- GroupSet = SET_OPSGROUP:New():FilterActive():FilterCoalition( "blue" ):FilterOnce()
|
||||||
|
--
|
||||||
|
-- -- Include only active groups to the set of the blue coalition, and filter one time.
|
||||||
|
-- -- Later, reset to include back inactive groups to the set.
|
||||||
|
-- GroupSet = SET_OPSGROUP:New():FilterActive():FilterCoalition( "blue" ):FilterOnce()
|
||||||
|
-- ... logic ...
|
||||||
|
-- GroupSet = SET_OPSGROUP:New():FilterActive( false ):FilterCoalition( "blue" ):FilterOnce()
|
||||||
|
--
|
||||||
|
function SET_OPSGROUP:FilterActive( Active )
|
||||||
|
Active = Active or not ( Active == false )
|
||||||
|
self.Filter.Active = Active
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Starts the filtering.
|
||||||
|
-- @param #SET_OPSGROUP self
|
||||||
|
-- @return #SET_OPSGROUP self
|
||||||
|
function SET_OPSGROUP:FilterStart()
|
||||||
|
|
||||||
|
if _DATABASE then
|
||||||
|
self:_FilterStart()
|
||||||
|
self:HandleEvent( EVENTS.Birth, self._EventOnBirth )
|
||||||
|
self:HandleEvent( EVENTS.Dead, self._EventOnDeadOrCrash )
|
||||||
|
self:HandleEvent( EVENTS.Crash, self._EventOnDeadOrCrash )
|
||||||
|
self:HandleEvent( EVENTS.RemoveUnit, self._EventOnDeadOrCrash )
|
||||||
|
end
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Handles the OnDead or OnCrash event for alive groups set.
|
||||||
|
-- Note: The GROUP object in the SET_OPSGROUP collection will only be removed if the last unit is destroyed of the GROUP.
|
||||||
|
-- @param #SET_OPSGROUP self
|
||||||
|
-- @param Core.Event#EVENTDATA Event
|
||||||
|
function SET_OPSGROUP:_EventOnDeadOrCrash( Event )
|
||||||
|
self:F( { Event } )
|
||||||
|
|
||||||
|
if Event.IniDCSUnit then
|
||||||
|
local ObjectName, Object = self:FindInDatabase( Event )
|
||||||
|
if ObjectName then
|
||||||
|
if Event.IniDCSGroup:getSize() == 1 then -- Only remove if the last unit of the group was destroyed.
|
||||||
|
self:Remove( ObjectName )
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Handles the Database to check on an event (birth) that the Object was added in the Database.
|
||||||
|
-- This is required, because sometimes the _DATABASE birth event gets called later than the SET_BASE birth event!
|
||||||
|
-- @param #SET_OPSGROUP self
|
||||||
|
-- @param Core.Event#EVENTDATA Event
|
||||||
|
-- @return #string The name of the GROUP
|
||||||
|
-- @return #table The GROUP
|
||||||
|
function SET_OPSGROUP:AddInDatabase( Event )
|
||||||
|
|
||||||
|
if Event.IniObjectCategory==1 then
|
||||||
|
|
||||||
|
if not self.Database[Event.IniDCSGroupName] then
|
||||||
|
self.Database[Event.IniDCSGroupName] = GROUP:Register( Event.IniDCSGroupName )
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
return Event.IniDCSGroupName, self.Database[Event.IniDCSGroupName]
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Handles the Database to check on any event that Object exists in the Database.
|
||||||
|
-- This is required, because sometimes the _DATABASE event gets called later than the SET_BASE event or vise versa!
|
||||||
|
-- @param #SET_OPSGROUP self
|
||||||
|
-- @param Core.Event#EVENTDATA Event Event data table.
|
||||||
|
-- @return #string The name of the GROUP
|
||||||
|
-- @return #table The GROUP
|
||||||
|
function SET_OPSGROUP:FindInDatabase(Event)
|
||||||
|
return Event.IniDCSGroupName, self.Database[Event.IniDCSGroupName]
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Iterate the set and call an iterator function for each OPSGROUP object.
|
||||||
|
-- @param #SET_OPSGROUP self
|
||||||
|
-- @param #function IteratorFunction The function that will be called for all OPSGROUPs in the set. **NOTE** that the function must have the OPSGROUP as first parameter!
|
||||||
|
-- @param ... (Optional) arguments passed to the `IteratorFunction`.
|
||||||
|
-- @return #SET_OPSGROUP self
|
||||||
|
function SET_OPSGROUP:ForEachGroup( IteratorFunction, ... )
|
||||||
|
|
||||||
|
self:ForEach(IteratorFunction, arg, self:GetSet())
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Check include object.
|
||||||
|
-- @param #SET_OPSGROUP self
|
||||||
|
-- @param Wrapper.Group#GROUP MGroup The group that is checked for inclusion.
|
||||||
|
-- @return #SET_OPSGROUP self
|
||||||
|
function SET_OPSGROUP:IsIncludeObject(MGroup)
|
||||||
|
|
||||||
|
-- Assume it is and check later if not.
|
||||||
|
local MGroupInclude=true
|
||||||
|
|
||||||
|
-- Filter active.
|
||||||
|
if self.Filter.Active~=nil then
|
||||||
|
|
||||||
|
local MGroupActive = false
|
||||||
|
|
||||||
|
if self.Filter.Active==false or (self.Filter.Active==true and MGroup:IsActive()==true) then
|
||||||
|
MGroupActive = true
|
||||||
|
end
|
||||||
|
|
||||||
|
MGroupInclude = MGroupInclude and MGroupActive
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Filter coalitions.
|
||||||
|
if self.Filter.Coalitions then
|
||||||
|
|
||||||
|
local MGroupCoalition = false
|
||||||
|
|
||||||
|
for CoalitionID, CoalitionName in pairs( self.Filter.Coalitions ) do
|
||||||
|
if self.FilterMeta.Coalitions[CoalitionName] and self.FilterMeta.Coalitions[CoalitionName]==MGroup:GetCoalition() then
|
||||||
|
MGroupCoalition = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
MGroupInclude = MGroupInclude and MGroupCoalition
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Filter categories.
|
||||||
|
if self.Filter.Categories then
|
||||||
|
|
||||||
|
local MGroupCategory = false
|
||||||
|
|
||||||
|
for CategoryID, CategoryName in pairs( self.Filter.Categories ) do
|
||||||
|
if self.FilterMeta.Categories[CategoryName] and self.FilterMeta.Categories[CategoryName]==MGroup:GetCategory() then
|
||||||
|
MGroupCategory = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
MGroupInclude = MGroupInclude and MGroupCategory
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Filter countries.
|
||||||
|
if self.Filter.Countries then
|
||||||
|
local MGroupCountry = false
|
||||||
|
for CountryID, CountryName in pairs( self.Filter.Countries ) do
|
||||||
|
if country.id[CountryName] == MGroup:GetCountry() then
|
||||||
|
MGroupCountry = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
MGroupInclude = MGroupInclude and MGroupCountry
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Filter "prefixes".
|
||||||
|
if self.Filter.GroupPrefixes then
|
||||||
|
|
||||||
|
local MGroupPrefix = false
|
||||||
|
|
||||||
|
for GroupPrefixId, GroupPrefix in pairs( self.Filter.GroupPrefixes ) do
|
||||||
|
if string.find( MGroup:GetName(), GroupPrefix:gsub ("-", "%%-"), 1 ) then --Not sure why "-" is replaced by "%-" ?!
|
||||||
|
MGroupPrefix = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
MGroupInclude = MGroupInclude and MGroupPrefix
|
||||||
|
end
|
||||||
|
|
||||||
|
return MGroupInclude
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|||||||
@@ -1086,16 +1086,11 @@ end
|
|||||||
-- @return Ops.OpsGroup#OPSGROUP.Waypoint Waypoint table.
|
-- @return Ops.OpsGroup#OPSGROUP.Waypoint Waypoint table.
|
||||||
function ARMYGROUP:AddWaypoint(Coordinate, Speed, AfterWaypointWithID, Formation, Updateroute)
|
function ARMYGROUP:AddWaypoint(Coordinate, Speed, AfterWaypointWithID, Formation, Updateroute)
|
||||||
|
|
||||||
env.info("FF Current waypoint index="..self.currentwp)
|
|
||||||
env.info("FF Add waypoint after index="..(AfterWaypointWithID or "nil"))
|
|
||||||
|
|
||||||
local coordinate=self:_CoordinateFromObject(Coordinate)
|
local coordinate=self:_CoordinateFromObject(Coordinate)
|
||||||
|
|
||||||
-- Set waypoint index.
|
-- Set waypoint index.
|
||||||
local wpnumber=self:GetWaypointIndexAfterID(AfterWaypointWithID)
|
local wpnumber=self:GetWaypointIndexAfterID(AfterWaypointWithID)
|
||||||
|
|
||||||
env.info("FF Add waypoint index="..wpnumber)
|
|
||||||
|
|
||||||
-- Check if final waypoint is still passed.
|
-- Check if final waypoint is still passed.
|
||||||
if wpnumber>self.currentwp then
|
if wpnumber>self.currentwp then
|
||||||
self.passedfinalwp=false
|
self.passedfinalwp=false
|
||||||
|
|||||||
@@ -1682,13 +1682,11 @@ function FLIGHTGROUP:onafterAirborne(From, Event, To)
|
|||||||
if self.isAI then
|
if self.isAI then
|
||||||
if self:IsTransporting() then
|
if self:IsTransporting() then
|
||||||
if self.cargoTransport and self.cargoTransport.deployzone and self.cargoTransport.deployzone:IsInstanceOf("ZONE_AIRBASE") then
|
if self.cargoTransport and self.cargoTransport.deployzone and self.cargoTransport.deployzone:IsInstanceOf("ZONE_AIRBASE") then
|
||||||
env.info("FF transporting land at airbase ")
|
|
||||||
local airbase=self.cargoTransport.deployzone:GetAirbase()
|
local airbase=self.cargoTransport.deployzone:GetAirbase()
|
||||||
self:LandAtAirbase(airbase)
|
self:LandAtAirbase(airbase)
|
||||||
end
|
end
|
||||||
elseif self:IsPickingup() then
|
elseif self:IsPickingup() then
|
||||||
if self.cargoTransport and self.cargoTransport.pickupzone and self.cargoTransport.pickupzone:IsInstanceOf("ZONE_AIRBASE") then
|
if self.cargoTransport and self.cargoTransport.pickupzone and self.cargoTransport.pickupzone:IsInstanceOf("ZONE_AIRBASE") then
|
||||||
env.info("FF pickingup land at airbase ")
|
|
||||||
local airbase=self.cargoTransport.pickupzone:GetAirbase()
|
local airbase=self.cargoTransport.pickupzone:GetAirbase()
|
||||||
self:LandAtAirbase(airbase)
|
self:LandAtAirbase(airbase)
|
||||||
end
|
end
|
||||||
@@ -2960,6 +2958,9 @@ function FLIGHTGROUP:_InitGroup()
|
|||||||
self:I(self.lid..text)
|
self:I(self.lid..text)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
env.info("DCS Unit BOOM_AND_RECEPTACLE="..tostring(Unit.RefuelingSystem.BOOM_AND_RECEPTACLE))
|
||||||
|
env.info("DCS Unit PROBE_AND_DROGUE="..tostring(Unit.RefuelingSystem.PROBE_AND_DROGUE))
|
||||||
|
|
||||||
-- Init done.
|
-- Init done.
|
||||||
self.groupinitialized=true
|
self.groupinitialized=true
|
||||||
|
|
||||||
|
|||||||
@@ -498,7 +498,8 @@ function NAVYGROUP:onafterStatus(From, Event, To)
|
|||||||
-- Check if group started or stopped turning.
|
-- Check if group started or stopped turning.
|
||||||
self:_CheckTurning()
|
self:_CheckTurning()
|
||||||
|
|
||||||
local freepath=UTILS.NMToMeters(10)
|
local disttoWP=math.min(self:GetDistanceToWaypoint(), UTILS.NMToMeters(10))
|
||||||
|
local freepath=disttoWP
|
||||||
|
|
||||||
-- Only check if not currently turning.
|
-- Only check if not currently turning.
|
||||||
if not self:IsTurning() then
|
if not self:IsTurning() then
|
||||||
@@ -506,7 +507,7 @@ function NAVYGROUP:onafterStatus(From, Event, To)
|
|||||||
-- Check free path ahead.
|
-- Check free path ahead.
|
||||||
freepath=self:_CheckFreePath(freepath, 100)
|
freepath=self:_CheckFreePath(freepath, 100)
|
||||||
|
|
||||||
if freepath<5000 then
|
if disttoWP>1 and freepath<disttoWP then
|
||||||
|
|
||||||
if not self.collisionwarning then
|
if not self.collisionwarning then
|
||||||
-- Issue a collision warning event.
|
-- Issue a collision warning event.
|
||||||
@@ -752,6 +753,7 @@ function NAVYGROUP:onafterUpdateRoute(From, Event, To, n, Speed, Depth)
|
|||||||
wp.alt=-self.depth
|
wp.alt=-self.depth
|
||||||
else
|
else
|
||||||
-- Take default waypoint alt.
|
-- Take default waypoint alt.
|
||||||
|
wp.alt=wp.alt or 0
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Current set speed in m/s.
|
-- Current set speed in m/s.
|
||||||
@@ -1274,8 +1276,6 @@ function NAVYGROUP:_CheckFreePath(DistanceMax, dx)
|
|||||||
--coordinate=coordinate:Translate(500, heading, true)
|
--coordinate=coordinate:Translate(500, heading, true)
|
||||||
|
|
||||||
local function LoS(dist)
|
local function LoS(dist)
|
||||||
--local checkcoord=coordinate:Translate(dist, heading, true)
|
|
||||||
--return coordinate:IsLOS(checkcoord, offsetY)
|
|
||||||
local checkvec3=UTILS.VecTranslate(vec3, dist, heading)
|
local checkvec3=UTILS.VecTranslate(vec3, dist, heading)
|
||||||
local los=land.isVisible(vec3, checkvec3)
|
local los=land.isVisible(vec3, checkvec3)
|
||||||
return los
|
return los
|
||||||
@@ -1303,7 +1303,7 @@ function NAVYGROUP:_CheckFreePath(DistanceMax, dx)
|
|||||||
local los=LoS(x)
|
local los=LoS(x)
|
||||||
|
|
||||||
-- Debug message.
|
-- Debug message.
|
||||||
self:T2(self.lid..string.format("N=%d: xmin=%.1f xmax=%.1f x=%.1f d=%.3f los=%s", N, xmin, xmax, x, d, tostring(los)))
|
self:I(self.lid..string.format("N=%d: xmin=%.1f xmax=%.1f x=%.1f d=%.3f los=%s", N, xmin, xmax, x, d, tostring(los)))
|
||||||
|
|
||||||
if los and d<=eps then
|
if los and d<=eps then
|
||||||
return x
|
return x
|
||||||
@@ -1477,6 +1477,7 @@ end
|
|||||||
-- @param #NAVYGROUP self
|
-- @param #NAVYGROUP self
|
||||||
-- @return #boolean If true, a path was found.
|
-- @return #boolean If true, a path was found.
|
||||||
function NAVYGROUP:_FindPathToNextWaypoint()
|
function NAVYGROUP:_FindPathToNextWaypoint()
|
||||||
|
env.info("FF Path finding")
|
||||||
|
|
||||||
-- Pathfinding A*
|
-- Pathfinding A*
|
||||||
local astar=ASTAR:New()
|
local astar=ASTAR:New()
|
||||||
@@ -1487,6 +1488,11 @@ function NAVYGROUP:_FindPathToNextWaypoint()
|
|||||||
-- Next waypoint.
|
-- Next waypoint.
|
||||||
local wpnext=self:GetWaypointNext()
|
local wpnext=self:GetWaypointNext()
|
||||||
|
|
||||||
|
-- No next waypoint.
|
||||||
|
if wpnext==nil then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
-- Next waypoint coordinate.
|
-- Next waypoint coordinate.
|
||||||
local nextwp=wpnext.coordinate
|
local nextwp=wpnext.coordinate
|
||||||
|
|
||||||
@@ -1507,12 +1513,17 @@ function NAVYGROUP:_FindPathToNextWaypoint()
|
|||||||
-- Distance to next waypoint.
|
-- Distance to next waypoint.
|
||||||
local dist=position:Get2DDistance(nextwp)
|
local dist=position:Get2DDistance(nextwp)
|
||||||
|
|
||||||
|
-- Check distance >= 5 meters.
|
||||||
|
if dist<5 then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
local boxwidth=dist*2
|
local boxwidth=dist*2
|
||||||
local spacex=dist*0.1
|
local spacex=dist*0.1
|
||||||
local delta=dist/10
|
local delta=dist/10
|
||||||
|
|
||||||
-- Create a grid of nodes. We only want nodes of surface type water.
|
-- Create a grid of nodes. We only want nodes of surface type water.
|
||||||
astar:CreateGrid({land.SurfaceType.WATER}, boxwidth, spacex, delta, delta*2, self.Debug)
|
astar:CreateGrid({land.SurfaceType.WATER}, boxwidth, spacex, delta, delta, self.verbose>10)
|
||||||
|
|
||||||
-- Valid neighbour nodes need to have line of sight.
|
-- Valid neighbour nodes need to have line of sight.
|
||||||
astar:SetValidNeighbourLoS(self.pathCorridor)
|
astar:SetValidNeighbourLoS(self.pathCorridor)
|
||||||
@@ -1539,7 +1550,9 @@ function NAVYGROUP:_FindPathToNextWaypoint()
|
|||||||
uid=wp.uid
|
uid=wp.uid
|
||||||
|
|
||||||
-- Debug: smoke and mark path.
|
-- Debug: smoke and mark path.
|
||||||
--node.coordinate:MarkToAll(string.format("Path node #%d", i))
|
if self.verbose>=10 then
|
||||||
|
node.coordinate:MarkToAll(string.format("Path node #%d", i))
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -108,6 +108,7 @@
|
|||||||
--
|
--
|
||||||
-- @field #OPSGROUP.Element carrier Carrier the group is loaded into as cargo.
|
-- @field #OPSGROUP.Element carrier Carrier the group is loaded into as cargo.
|
||||||
-- @field #OPSGROUP carrierGroup Carrier group transporting this group as cargo.
|
-- @field #OPSGROUP carrierGroup Carrier group transporting this group as cargo.
|
||||||
|
-- @field #OPSGROUP.MyCarrier mycarrier Carrier group for this group.
|
||||||
-- @field #table cargoqueue Table containing cargo groups to be transported.
|
-- @field #table cargoqueue Table containing cargo groups to be transported.
|
||||||
-- @field #table cargoBay Table containing OPSGROUP loaded into this group.
|
-- @field #table cargoBay Table containing OPSGROUP loaded into this group.
|
||||||
-- @field Ops.OpsTransport#OPSTRANSPORT cargoTransport Current cargo transport assignment.
|
-- @field Ops.OpsTransport#OPSTRANSPORT cargoTransport Current cargo transport assignment.
|
||||||
@@ -172,6 +173,7 @@ OPSGROUP = {
|
|||||||
cargoqueue = {},
|
cargoqueue = {},
|
||||||
cargoBay = {},
|
cargoBay = {},
|
||||||
cargocounter = 1,
|
cargocounter = 1,
|
||||||
|
mycarrier = {},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -418,25 +420,18 @@ OPSGROUP.TransportStatus={
|
|||||||
}
|
}
|
||||||
|
|
||||||
--- Cargo transport data.
|
--- Cargo transport data.
|
||||||
-- @type OPSGROUP.CargoTransport
|
-- @type OPSGROUP.MyCarrier
|
||||||
-- @field #table cargos Cargos. Each element is a @{#OPSGROUP.Cargo}.
|
-- @field #OPSGROUP group The carrier group.
|
||||||
-- @field #string status Status of the transport. See @{#OPSGROUP.TransportStatus}.
|
-- @field #OPSGROUP.Element element The carrier element.
|
||||||
-- @field #number prio Priority of this transport. Should be a number between 0 (high prio) and 100 (low prio).
|
-- @field #boolean reserved If `true`, the carrier has caro space reserved for me.
|
||||||
-- @field #number importance Importance of this transport. Smaller=higher.
|
|
||||||
-- @field #number Tstart Start time in *abs.* seconds.
|
|
||||||
-- @field Core.Zone#ZONE pickupzone Zone where the cargo is picked up.
|
|
||||||
-- @field Core.Zone#ZONE deployzone Zone where the cargo is dropped off.
|
|
||||||
-- @field Core.Zone#ZONE embarkzone (Optional) Zone where the cargo is supposed to embark. Default is the pickup zone.
|
|
||||||
-- @field Core.Zone#ZONE disembarkzone (Optional) Zone where the cargo is disembarked. Default is the deploy zone.
|
|
||||||
-- @field #OPSGROUP carrierGroup The new carrier group.
|
|
||||||
|
|
||||||
--- Cargo group data.
|
--- Cargo group data.
|
||||||
-- @type OPSGROUP.CargoGroup
|
-- @type OPSGROUP.CargoGroup
|
||||||
-- @field #OPSGROUP opsgroup The cargo opsgroup.
|
-- @field #OPSGROUP opsgroup The cargo opsgroup.
|
||||||
-- @field #string status Status of the cargo group. See @{#OPSGROUP.CargoStatus}.
|
-- @field #boolean delivered If `true`, group was delivered.
|
||||||
-- @field Core.Zone#ZONE pickupzone Zone where the cargo is picked up.
|
-- @field #OPSGROUP disembarkCarrierGroup Carrier group where the cargo group is directly loaded to.
|
||||||
-- @field Core.Zone#ZONE deployzone Zone where the cargo is dropped off.
|
-- @field #OPSGROUP disembarkCarrierElement Carrier element to which the cargo group is directly loaded to.
|
||||||
-- @field #boolean delivered If true, group was delivered.
|
-- @field #string status Status of the cargo group. Not used yet.
|
||||||
|
|
||||||
--- OpsGroup version.
|
--- OpsGroup version.
|
||||||
-- @field #string version
|
-- @field #string version
|
||||||
@@ -1022,8 +1017,9 @@ function OPSGROUP:GetVec3(UnitName)
|
|||||||
local vec3=nil --DCS#Vec3
|
local vec3=nil --DCS#Vec3
|
||||||
|
|
||||||
-- First check if this group is loaded into a carrier
|
-- First check if this group is loaded into a carrier
|
||||||
if self.carrier and self.carrier.status~=OPSGROUP.ElementStatus.DEAD and self:IsLoaded() then
|
local carrier=self:_GetMyCarrierElement()
|
||||||
local unit=self.carrier.unit
|
if carrier and carrier.status~=OPSGROUP.ElementStatus.DEAD and self:IsLoaded() then
|
||||||
|
local unit=carrier.unit
|
||||||
if unit and unit:IsAlive()~=nil then
|
if unit and unit:IsAlive()~=nil then
|
||||||
vec3=unit:GetVec3()
|
vec3=unit:GetVec3()
|
||||||
return vec3
|
return vec3
|
||||||
@@ -1219,8 +1215,10 @@ end
|
|||||||
-- @return #OPSGROUP self
|
-- @return #OPSGROUP self
|
||||||
function OPSGROUP:DespawnUnit(UnitName, Delay, NoEventRemoveUnit)
|
function OPSGROUP:DespawnUnit(UnitName, Delay, NoEventRemoveUnit)
|
||||||
|
|
||||||
env.info("FF despawn element .."..tostring(UnitName))
|
-- Debug info.
|
||||||
|
self:T(self.lid.."Despawn element "..tostring(UnitName))
|
||||||
|
|
||||||
|
-- Get element.
|
||||||
local element=self:GetElementByName(UnitName)
|
local element=self:GetElementByName(UnitName)
|
||||||
|
|
||||||
if element then
|
if element then
|
||||||
@@ -1652,7 +1650,8 @@ end
|
|||||||
-- @return #boolean If true, group is boarding.
|
-- @return #boolean If true, group is boarding.
|
||||||
function OPSGROUP:IsBoarding(CarrierGroupName)
|
function OPSGROUP:IsBoarding(CarrierGroupName)
|
||||||
if CarrierGroupName then
|
if CarrierGroupName then
|
||||||
if self.carrierGroup and self.carrierGroup.groupname~=CarrierGroupName then
|
local carrierGroup=self:_GetMyCarrierGroup()
|
||||||
|
if carrierGroup and carrierGroup.groupname~=CarrierGroupName then
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -1665,7 +1664,8 @@ end
|
|||||||
-- @return #boolean If true, group is loaded.
|
-- @return #boolean If true, group is loaded.
|
||||||
function OPSGROUP:IsLoaded(CarrierGroupName)
|
function OPSGROUP:IsLoaded(CarrierGroupName)
|
||||||
if CarrierGroupName then
|
if CarrierGroupName then
|
||||||
if self.carrierGroup and self.carrierGroup.groupname~=CarrierGroupName then
|
local carrierGroup=self:_GetMyCarrierGroup()
|
||||||
|
if carrierGroup and carrierGroup.groupname~=CarrierGroupName then
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -3007,7 +3007,6 @@ end
|
|||||||
-- @param #OPSGROUP self
|
-- @param #OPSGROUP self
|
||||||
-- @return #number Number of unfinished transports in the queue.
|
-- @return #number Number of unfinished transports in the queue.
|
||||||
function OPSGROUP:CountRemainingTransports()
|
function OPSGROUP:CountRemainingTransports()
|
||||||
env.info("FF Count remaining transports="..#self.cargoqueue)
|
|
||||||
|
|
||||||
local N=0
|
local N=0
|
||||||
|
|
||||||
@@ -3015,17 +3014,15 @@ function OPSGROUP:CountRemainingTransports()
|
|||||||
for _,_transport in pairs(self.cargoqueue) do
|
for _,_transport in pairs(self.cargoqueue) do
|
||||||
local transport=_transport --Ops.OpsTransport#OPSTRANSPORT
|
local transport=_transport --Ops.OpsTransport#OPSTRANSPORT
|
||||||
|
|
||||||
self:I(self.lid..string.format("Transport status=%s [%s]", transport:GetCarrierTransportStatus(self), transport:GetState()))
|
-- Debug info.
|
||||||
|
self:T(self.lid..string.format("Transport status=%s [%s]", transport:GetCarrierTransportStatus(self), transport:GetState()))
|
||||||
|
|
||||||
-- Count not delivered (executing or scheduled) assignments.
|
-- Count not delivered (executing or scheduled) assignments.
|
||||||
if transport and transport:GetCarrierTransportStatus(self)==OPSTRANSPORT.Status.SCHEDULED and transport:GetState()~=OPSTRANSPORT.Status.DELIVERED then
|
if transport and transport:GetCarrierTransportStatus(self)==OPSTRANSPORT.Status.SCHEDULED and transport:GetState()~=OPSTRANSPORT.Status.DELIVERED then
|
||||||
|
|
||||||
N=N+1
|
N=N+1
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
env.info("FF Count remaining transports="..N)
|
|
||||||
return N
|
return N
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -4114,8 +4111,6 @@ end
|
|||||||
-- @param #string To To state.
|
-- @param #string To To state.
|
||||||
function OPSGROUP:onafterLaserLostLOS(From, Event, To)
|
function OPSGROUP:onafterLaserLostLOS(From, Event, To)
|
||||||
|
|
||||||
--env.info("FF lost LOS")
|
|
||||||
|
|
||||||
-- No of sight.
|
-- No of sight.
|
||||||
self.spot.LOS=false
|
self.spot.LOS=false
|
||||||
|
|
||||||
@@ -4124,8 +4119,6 @@ function OPSGROUP:onafterLaserLostLOS(From, Event, To)
|
|||||||
|
|
||||||
if self.spot.On then
|
if self.spot.On then
|
||||||
|
|
||||||
--env.info("FF lost LOS ==> pause laser")
|
|
||||||
|
|
||||||
-- Switch laser off.
|
-- Switch laser off.
|
||||||
self:LaserPause()
|
self:LaserPause()
|
||||||
|
|
||||||
@@ -4143,18 +4136,13 @@ function OPSGROUP:onafterLaserGotLOS(From, Event, To)
|
|||||||
-- Has line of sight.
|
-- Has line of sight.
|
||||||
self.spot.LOS=true
|
self.spot.LOS=true
|
||||||
|
|
||||||
--env.info("FF Laser Got LOS")
|
|
||||||
|
|
||||||
if self.spot.lostLOS then
|
if self.spot.lostLOS then
|
||||||
|
|
||||||
-- Did not loose LOS anymore.
|
-- Did not loose LOS anymore.
|
||||||
self.spot.lostLOS=false
|
self.spot.lostLOS=false
|
||||||
|
|
||||||
--env.info("FF had lost LOS and regained it")
|
|
||||||
|
|
||||||
-- Resume laser if currently paused.
|
-- Resume laser if currently paused.
|
||||||
if self.spot.Paused then
|
if self.spot.Paused then
|
||||||
--env.info("FF laser was paused ==> resume")
|
|
||||||
self:LaserResume()
|
self:LaserResume()
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -4206,8 +4194,6 @@ function OPSGROUP:SetLaserTarget(Target)
|
|||||||
self.spot.offsetTarget={x=0, 2, z=0}
|
self.spot.offsetTarget={x=0, 2, z=0}
|
||||||
end
|
end
|
||||||
|
|
||||||
--env.info(string.format("Target offset %.3f", y))
|
|
||||||
|
|
||||||
else
|
else
|
||||||
self:E("WARNING: LASER target is not alive!")
|
self:E("WARNING: LASER target is not alive!")
|
||||||
return
|
return
|
||||||
@@ -4310,8 +4296,6 @@ function OPSGROUP:_UpdateLaser()
|
|||||||
-- Check current LOS.
|
-- Check current LOS.
|
||||||
local los=self:HasLoS(self.spot.Coordinate, self.spot.element, self.spot.offset)
|
local los=self:HasLoS(self.spot.Coordinate, self.spot.element, self.spot.offset)
|
||||||
|
|
||||||
--env.info(string.format("FF check LOS current=%s previous=%s", tostring(los), tostring(self.spot.LOS)))
|
|
||||||
|
|
||||||
if los then
|
if los then
|
||||||
-- Got LOS
|
-- Got LOS
|
||||||
if self.spot.lostLOS then
|
if self.spot.lostLOS then
|
||||||
@@ -4425,8 +4409,13 @@ function OPSGROUP:onafterElementDead(From, Event, To, Element)
|
|||||||
local opsgroup=_DATABASE:GetOpsGroup(groupname)
|
local opsgroup=_DATABASE:GetOpsGroup(groupname)
|
||||||
if opsgroup and not (opsgroup:IsDead() or opsgroup:IsStopped()) then
|
if opsgroup and not (opsgroup:IsDead() or opsgroup:IsStopped()) then
|
||||||
for _,element in pairs(opsgroup.elements) do
|
for _,element in pairs(opsgroup.elements) do
|
||||||
env.info("FF cargo element dead "..element.name)
|
|
||||||
|
-- Debug info.
|
||||||
|
self:T2(self.lid.."Cargo element dead "..element.name)
|
||||||
|
|
||||||
|
-- Trigger dead event.
|
||||||
opsgroup:ElementDead(element)
|
opsgroup:ElementDead(element)
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -4662,9 +4651,10 @@ function OPSGROUP:_CheckCargoTransport()
|
|||||||
local state=cargo.opsgroup:GetState()
|
local state=cargo.opsgroup:GetState()
|
||||||
local status=cargo.opsgroup.cargoStatus
|
local status=cargo.opsgroup.cargoStatus
|
||||||
local name=cargo.opsgroup.groupname
|
local name=cargo.opsgroup.groupname
|
||||||
local carriergroup=cargo.opsgroup.carrierGroup and cargo.opsgroup.carrierGroup.groupname or "N/A"
|
local carriergroup, carrierelement, reserved=cargo.opsgroup:_GetMyCarrier()
|
||||||
local carrierelement=cargo.opsgroup.carrier and cargo.opsgroup.carrier.name or "N/A"
|
local carrierGroupname=carriergroup and carriergroup.groupname or "none"
|
||||||
text=text..string.format("\n (%d) %s [%s]: %s, carrier=%s(%s), delivered=%s", j, name, state, status, carriergroup, carrierelement, tostring(cargo.delivered))
|
local carrierElementname=carrierelement and carrierelement.name or "none"
|
||||||
|
text=text..string.format("\n (%d) %s [%s]: %s, carrier=%s(%s), delivered=%s", j, name, state, status, carrierGroupname, carrierElementname, tostring(cargo.delivered))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if text~="" then
|
if text~="" then
|
||||||
@@ -4689,9 +4679,10 @@ function OPSGROUP:_CheckCargoTransport()
|
|||||||
local gstatus=cargo.opsgroup:GetState()
|
local gstatus=cargo.opsgroup:GetState()
|
||||||
local cstatus=cargo.opsgroup.cargoStatus
|
local cstatus=cargo.opsgroup.cargoStatus
|
||||||
local weight=cargo.opsgroup:GetWeightTotal()
|
local weight=cargo.opsgroup:GetWeightTotal()
|
||||||
local carriername=cargo.opsgroup.carrier and cargo.opsgroup.carrier.name or "none"
|
local carriergroup, carrierelement, reserved=cargo.opsgroup:_GetMyCarrier()
|
||||||
local carriergroup=cargo.opsgroup.carrierGroup and cargo.opsgroup.carrierGroup.groupname or "none"
|
local carrierGroupname=carriergroup and carriergroup.groupname or "none"
|
||||||
text=text..string.format("\n- %s (%.1f kg) [%s]: %s, carrier=%s (%s), delivered=%s", name, weight, gstatus, cstatus, carriername, carriergroup, tostring(cargo.delivered))
|
local carrierElementname=carrierelement and carrierelement.name or "none"
|
||||||
|
text=text..string.format("\n- %s (%.1f kg) [%s]: %s, carrier=%s (%s), delivered=%s", name, weight, gstatus, cstatus, carrierElementname, carrierGroupname, tostring(cargo.delivered))
|
||||||
end
|
end
|
||||||
self:I(self.lid..text)
|
self:I(self.lid..text)
|
||||||
end
|
end
|
||||||
@@ -4761,7 +4752,10 @@ function OPSGROUP:_CheckCargoTransport()
|
|||||||
for _,_cargo in pairs(self.cargoTransport.cargos) do
|
for _,_cargo in pairs(self.cargoTransport.cargos) do
|
||||||
local cargo=_cargo --Ops.OpsGroup#OPSGROUP.CargoGroup
|
local cargo=_cargo --Ops.OpsGroup#OPSGROUP.CargoGroup
|
||||||
|
|
||||||
if (cargo.opsgroup.carrierGroup and cargo.opsgroup.carrierGroup:GetName()==self:GetName()) and not cargo.delivered then
|
local carrierGroup=cargo.opsgroup:_GetMyCarrierGroup()
|
||||||
|
|
||||||
|
-- Check that this group is
|
||||||
|
if (carrierGroup and carrierGroup:GetName()==self:GetName()) and not cargo.delivered then
|
||||||
delivered=false
|
delivered=false
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
@@ -4780,15 +4774,6 @@ function OPSGROUP:_CheckCargoTransport()
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Loop over cargo queue and check if everything was delivered.
|
|
||||||
for i=#self.cargoqueue,1,-1 do
|
|
||||||
local transport=self.cargoqueue[i] --Ops.OpsTransport#OPSTRANSPORT
|
|
||||||
local delivered=self:_CheckDelivered(transport)
|
|
||||||
if delivered then
|
|
||||||
--self:Delivered(transport)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -4826,7 +4811,13 @@ function OPSGROUP:_DelCargobay(CargoGroup, CarrierElement)
|
|||||||
|
|
||||||
-- Reduce carrier weight.
|
-- Reduce carrier weight.
|
||||||
local weight=CargoGroup:GetWeightTotal()
|
local weight=CargoGroup:GetWeightTotal()
|
||||||
self:RedWeightCargo(CargoGroup.carrier.name, weight)
|
|
||||||
|
-- Get carrier of group.
|
||||||
|
local carrier=CargoGroup:_GetMyCarrierElement()
|
||||||
|
|
||||||
|
if carrier then
|
||||||
|
self:RedWeightCargo(carrier.name, weight)
|
||||||
|
end
|
||||||
|
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
@@ -4909,36 +4900,6 @@ function OPSGROUP:_CheckDelivered(CargoTransport)
|
|||||||
return done
|
return done
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Create a cargo transport assignment.
|
|
||||||
-- @param #OPSGROUP self
|
|
||||||
-- @param Core.Set#SET_GROUP GroupSet Set of groups to be transported. Can also be a single @{Wrapper.Group#GROUP} object.
|
|
||||||
-- @param Core.Zone#ZONE Pickupzone Pickup zone. This is the zone, where the carrier is going to pickup the cargo. **Important**: only cargo is considered, if it is in this zone when the carrier starts loading!
|
|
||||||
-- @param Core.Zone#ZONE Deployzone Deploy zone. This is the zone, where the carrier is going to drop off the cargo.
|
|
||||||
-- @param #number Prio Priority of this transport assignment. Should be a number between 1 (high prio) and 100 (low prio).
|
|
||||||
-- @param #number Importance Importance of this transport assignment (lower=more important). A transport is only considered, if all more important (if any) transports are done. Default `nil`.
|
|
||||||
-- @param #string ClockStart Start time in format "HH:MM(:SS)(+D)", e.g. "13:05:30" or "08:30+1". Can also be given as a `#number`, in which case it is interpreted as relative amount in seconds from now on.
|
|
||||||
-- @param Core.Zone#ZONE Embarkzone (Optional) Zone where the cargo is going to be embarked into the transport. By default is goes to the assigned carrier unit.
|
|
||||||
-- @param Core.Zone#ZONE Disembarkzone (Optional) Zone where the cargo disembarks to (is spawned after unloaded). Default is anywhere in the deploy zone.
|
|
||||||
-- @param #OPSGROUP DisembarkCarrierGroup (Optional) The OPSGROUP where the cargo is directly loaded into.
|
|
||||||
-- @return Ops.OpsTransport#OPSTRANSPORT Cargo transport.
|
|
||||||
function OPSGROUP:AddCargoTransport(GroupSet, Pickupzone, Deployzone, Prio, Importance, ClockStart, Embarkzone, Disembarkzone, DisembarkCarrierGroup)
|
|
||||||
|
|
||||||
-- Create a new cargo transport assignment.
|
|
||||||
local cargotransport=OPSTRANSPORT:New(GroupSet, Pickupzone, Deployzone)
|
|
||||||
|
|
||||||
if cargotransport then
|
|
||||||
|
|
||||||
-- Set state to SCHEDULED.
|
|
||||||
cargotransport.status=OPSGROUP.TransportStatus.SCHEDULED
|
|
||||||
|
|
||||||
--Add to cargo queue
|
|
||||||
table.insert(self.cargoqueue, cargotransport)
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
return cargotransport
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Create a cargo transport assignment.
|
--- Create a cargo transport assignment.
|
||||||
-- @param #OPSGROUP self
|
-- @param #OPSGROUP self
|
||||||
-- @param Ops.OpsTransport#OPSTRANSPORT OpsTransport The troop transport assignment.
|
-- @param Ops.OpsTransport#OPSTRANSPORT OpsTransport The troop transport assignment.
|
||||||
@@ -4971,134 +4932,6 @@ function OPSGROUP:DelCargoTransport(CargoTransport)
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Create a cargo transport assignment.
|
|
||||||
-- @param #OPSGROUP self
|
|
||||||
-- @param Core.Set#SET_GROUP GroupSet Set of groups to be transported. Can also be a single @{Wrapper.Group#GROUP} or @{Ops.OpsGroup#OPSGROUP} object.
|
|
||||||
-- @param Core.Zone#ZONE Pickupzone Pickup zone. This is the zone, where the carrier is going to pickup the cargo. **Important**: only cargo is considered, if it is in this zone when the carrier starts loading!
|
|
||||||
-- @param Core.Zone#ZONE Deployzone Deploy zone. This is the zone, where the carrier is going to drop off the cargo.
|
|
||||||
-- @param #number Prio Priority of this transport assignment. Should be a number between 1 (high prio) and 100 (low prio).
|
|
||||||
-- @param #number Importance Importance of this transport assignment (lower=more important). A transport is only considered, if all more important (if any) transports are done. Default `nil`.
|
|
||||||
-- @param #string ClockStart Start time in format "HH:MM:SS+D", e.g. "13:05:30" or "08:30+1". Can also be passed as a `#number` in which case it is interpreted as relative amount in seconds from now on.
|
|
||||||
-- @param Core.Zone#ZONE Embarkzone (Optional) Zone where the cargo is going to be embarked into the transport. By default is goes to the assigned carrier unit.
|
|
||||||
-- @param Core.Zone#ZONE Disembarkzone (Optional) Zone where the cargo disembarks to (is spawned after unloaded). Default is anywhere in the deploy zone.
|
|
||||||
-- @param #OPSGROUP DisembarkCarrierGroup (Optional) The OPSGROUP where the cargo is directly loaded into.
|
|
||||||
-- @return Ops.OpsTransport#OPSTRANSPORT Cargo transport.
|
|
||||||
function OPSGROUP:CreateCargoTransport(GroupSet, Pickupzone, Deployzone, Prio, Importance, ClockStart, Embarkzone, Disembarkzone, DisembarkCarrierGroup)
|
|
||||||
|
|
||||||
-- Current mission time.
|
|
||||||
local Tnow=timer.getAbsTime()
|
|
||||||
|
|
||||||
-- Set start time. Default in 5 sec.
|
|
||||||
local Tstart=Tnow+5
|
|
||||||
if ClockStart and type(ClockStart)=="number" then
|
|
||||||
Tstart=Tnow+ClockStart
|
|
||||||
elseif ClockStart and type(ClockStart)=="string" then
|
|
||||||
Tstart=UTILS.ClockToSeconds(ClockStart)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Data structure.
|
|
||||||
local transport={} --Ops.OpsTransport#OPSTRANSPORT
|
|
||||||
transport.uid=self.cargocounter
|
|
||||||
transport.status=OPSGROUP.TransportStatus.PLANNING
|
|
||||||
transport.pickupzone=Pickupzone
|
|
||||||
transport.deployzone=Deployzone
|
|
||||||
transport.embarkzone=Embarkzone or Pickupzone
|
|
||||||
transport.disembarkzone=Disembarkzone or Deployzone
|
|
||||||
transport.prio=Prio or 50
|
|
||||||
transport.importance=Importance
|
|
||||||
transport.Tstart=Tstart
|
|
||||||
transport.carrierGroup=DisembarkCarrierGroup
|
|
||||||
transport.cargos={}
|
|
||||||
|
|
||||||
-- Check type of GroupSet provided.
|
|
||||||
if GroupSet:IsInstanceOf("GROUP") or GroupSet:IsInstanceOf("OPSGROUP") then
|
|
||||||
|
|
||||||
-- We got a single GROUP or OPSGROUP objectg.
|
|
||||||
local cargo=self:CreateCargoGroupData(GroupSet, Pickupzone, Deployzone)
|
|
||||||
|
|
||||||
if cargo and self:CanCargo(cargo.opsgroup) then
|
|
||||||
table.insert(transport.cargos, cargo)
|
|
||||||
end
|
|
||||||
|
|
||||||
else
|
|
||||||
|
|
||||||
-- We got a SET_GROUP object.
|
|
||||||
|
|
||||||
for _,group in pairs(GroupSet.Set) do
|
|
||||||
|
|
||||||
local cargo=self:CreateCargoGroupData(group, Pickupzone, Deployzone)
|
|
||||||
|
|
||||||
if cargo and self:CanCargo(cargo.opsgroup) then
|
|
||||||
table.insert(transport.cargos, cargo)
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Debug info.
|
|
||||||
if self.verbose>=0 then
|
|
||||||
local text=string.format("Created Cargo Transport (UID=%d) from %s(%s) --> %s(%s)",
|
|
||||||
transport.uid, transport.pickupzone:GetName(), transport.embarkzone:GetName(), transport.deployzone:GetName(), transport.disembarkzone:GetName())
|
|
||||||
local Weight=0
|
|
||||||
for _,_cargo in pairs(transport.cargos) do
|
|
||||||
local cargo=_cargo --#OPSGROUP.CargoGroup
|
|
||||||
local weight=cargo.opsgroup:GetWeightTotal()
|
|
||||||
Weight=Weight+weight
|
|
||||||
text=text..string.format("\n- %s [%s] weight=%.1f kg", cargo.opsgroup:GetName(), cargo.opsgroup:GetState(), weight)
|
|
||||||
end
|
|
||||||
text=text..string.format("\nTOTAL: Ncargo=%d, Weight=%.1f kg", #transport.cargos, Weight)
|
|
||||||
self:I(self.lid..text)
|
|
||||||
end
|
|
||||||
|
|
||||||
if #transport.cargos>0 then
|
|
||||||
self.cargocounter=self.cargocounter+1
|
|
||||||
return transport
|
|
||||||
else
|
|
||||||
self:E(self.lid.."ERROR: Cargo too heavy for this carrier group!")
|
|
||||||
return nil
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Create a cargo group data structure.
|
|
||||||
-- @param #OPSGROUP self
|
|
||||||
-- @param Wrapper.Group#GROUP group The GROUP object.
|
|
||||||
-- @param Core.Zone#ZONE Pickupzone Pickup zone.
|
|
||||||
-- @param Core.Zone#ZONE Deployzone Deploy zone.
|
|
||||||
-- @return #OPSGROUP.CargoGroup Cargo group data.
|
|
||||||
function OPSGROUP:CreateCargoGroupData(group, Pickupzone, Deployzone)
|
|
||||||
|
|
||||||
local opsgroup=nil
|
|
||||||
|
|
||||||
if group:IsInstanceOf("OPSGROUP") then
|
|
||||||
opsgroup=group
|
|
||||||
else
|
|
||||||
|
|
||||||
opsgroup=_DATABASE:GetOpsGroup(group)
|
|
||||||
|
|
||||||
if not opsgroup then
|
|
||||||
if group:IsAir() then
|
|
||||||
opsgroup=FLIGHTGROUP:New(group)
|
|
||||||
elseif group:IsShip() then
|
|
||||||
opsgroup=NAVYGROUP:New(group)
|
|
||||||
else
|
|
||||||
opsgroup=ARMYGROUP:New(group)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
--env.info("FF found opsgroup in createcargo")
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
local cargo={} --#OPSGROUP.CargoGroup
|
|
||||||
|
|
||||||
cargo.opsgroup=opsgroup
|
|
||||||
cargo.delivered=false
|
|
||||||
cargo.status="Unknown"
|
|
||||||
cargo.pickupzone=Pickupzone
|
|
||||||
cargo.deployzone=Deployzone
|
|
||||||
|
|
||||||
return cargo
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Get total weight of the group including cargo.
|
--- Get total weight of the group including cargo.
|
||||||
-- @param #OPSGROUP self
|
-- @param #OPSGROUP self
|
||||||
@@ -5124,7 +4957,7 @@ end
|
|||||||
--- Get free cargo bay weight.
|
--- Get free cargo bay weight.
|
||||||
-- @param #OPSGROUP self
|
-- @param #OPSGROUP self
|
||||||
-- @param #string UnitName Name of the unit. Default is of the whole group.
|
-- @param #string UnitName Name of the unit. Default is of the whole group.
|
||||||
-- @return #number Total weight in kg.
|
-- @return #number Free cargo bay in kg.
|
||||||
function OPSGROUP:GetFreeCargobay(UnitName)
|
function OPSGROUP:GetFreeCargobay(UnitName)
|
||||||
|
|
||||||
local Free=0
|
local Free=0
|
||||||
@@ -5133,10 +4966,17 @@ function OPSGROUP:GetFreeCargobay(UnitName)
|
|||||||
|
|
||||||
if (UnitName==nil or UnitName==element.name) and element.status~=OPSGROUP.ElementStatus.DEAD then
|
if (UnitName==nil or UnitName==element.name) and element.status~=OPSGROUP.ElementStatus.DEAD then
|
||||||
local free=element.weightMaxCargo-element.weightCargo
|
local free=element.weightMaxCargo-element.weightCargo
|
||||||
|
--[[
|
||||||
|
for _,_opsgroup in pairs(element.reservedCargos or {}) do
|
||||||
|
local opsgroup=_opsgroup --#OPSGROUP
|
||||||
|
free=free-opsgroup:GetWeightTotal()
|
||||||
|
end
|
||||||
|
]]
|
||||||
Free=Free+free
|
Free=Free+free
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
self:I(self.lid..string.format("Free cargo bay=%d kg (unit=%s)", Free, (UnitName or "whole group")))
|
||||||
return Free
|
return Free
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -5189,6 +5029,21 @@ function OPSGROUP:GetWeightCargo(UnitName)
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local gewicht=0
|
||||||
|
for groupname, carriername in pairs(self.cargoBay) do
|
||||||
|
local element=self:GetElementByName(carriername)
|
||||||
|
if (UnitName==nil or UnitName==carriername) and (element and element.status~=OPSGROUP.ElementStatus.DEAD) then
|
||||||
|
local opsgroup=_DATABASE:FindOpsGroup(groupname)
|
||||||
|
if opsgroup then
|
||||||
|
gewicht=gewicht+opsgroup:GetWeightTotal()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if gewicht~=weight then
|
||||||
|
self:I(self.lid..string.format("ERROR: FF weight!=gewicht: weight=%.1f, gewicht=%.1f", weight, gewicht))
|
||||||
|
end
|
||||||
|
|
||||||
return weight
|
return weight
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -5247,7 +5102,7 @@ function OPSGROUP:RedWeightCargo(UnitName, Weight)
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Check if the group can be carrier of a cargo group.
|
--- Check if the group can *in principle* be carrier of a cargo group. This checks the max cargo capacity of the group but *not* how much cargo is already loaded (if any).
|
||||||
-- **Note** that the cargo group *cannot* be split into units, i.e. the largest cargo bay of any element of the group must be able to load the whole cargo group in one piece.
|
-- **Note** that the cargo group *cannot* be split into units, i.e. the largest cargo bay of any element of the group must be able to load the whole cargo group in one piece.
|
||||||
-- @param #OPSGROUP self
|
-- @param #OPSGROUP self
|
||||||
-- @param #OPSGROUP CargoGroup Cargo group, which needs a carrier.
|
-- @param #OPSGROUP CargoGroup Cargo group, which needs a carrier.
|
||||||
@@ -5258,11 +5113,14 @@ function OPSGROUP:CanCargo(CargoGroup)
|
|||||||
|
|
||||||
local weight=CargoGroup:GetWeightTotal()
|
local weight=CargoGroup:GetWeightTotal()
|
||||||
|
|
||||||
for _,element in pairs(self.elements) do
|
for _,_element in pairs(self.elements) do
|
||||||
local can=element.weightMaxCargo>=weight
|
local element=_element --#OPSGROUP.Element
|
||||||
if can then
|
|
||||||
|
-- Check that element is not dead and has
|
||||||
|
if element and element.status~=OPSGROUP.ElementStatus.DEAD and element.weightMaxCargo>=weight then
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
@@ -5278,16 +5136,104 @@ function OPSGROUP:FindCarrierForCargo(CargoGroup)
|
|||||||
|
|
||||||
local weight=CargoGroup:GetWeightTotal()
|
local weight=CargoGroup:GetWeightTotal()
|
||||||
|
|
||||||
for _,element in pairs(self.elements) do
|
for _,_element in pairs(self.elements) do
|
||||||
|
local element=_element --#OPSGROUP.Element
|
||||||
|
|
||||||
local free=self:GetFreeCargobay(element.name)
|
local free=self:GetFreeCargobay(element.name)
|
||||||
|
|
||||||
if free>=weight then
|
if free>=weight then
|
||||||
return element
|
return element
|
||||||
|
else
|
||||||
|
self:T3(self.lid..string.format("%s: Weight %d>%d free cargo bay", element.name, weight, free))
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Reserve cargo space for a cargo group.
|
||||||
|
-- @param #OPSGROUP self
|
||||||
|
-- @param #OPSGROUP CargoGroup Cargo group, which needs a carrier.
|
||||||
|
-- @return #OPSGROUP.Element Carrier able to transport the cargo.
|
||||||
|
function OPSGROUP:ReserveCargoSpace(CargoGroup)
|
||||||
|
|
||||||
|
local element=self:FindCarrierForCargo(CargoGroup)
|
||||||
|
|
||||||
|
if element then
|
||||||
|
element.reservedCargo=element.reservedCargo or {}
|
||||||
|
table.insert(element.reservedCargo, CargoGroup)
|
||||||
|
end
|
||||||
|
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Set my carrier.
|
||||||
|
-- @param #OPSGROUP self
|
||||||
|
-- @param #OPSGROUP CarrierGroup Carrier group.
|
||||||
|
-- @param #OPSGROUP.Element CarrierElement Carrier element.
|
||||||
|
-- @param #boolean Reserved If `true`, reserve space for me.
|
||||||
|
function OPSGROUP:_SetMyCarrier(CarrierGroup, CarrierElement, Reserved)
|
||||||
|
|
||||||
|
self.mycarrier.group=CarrierGroup
|
||||||
|
self.mycarrier.element=CarrierElement
|
||||||
|
self.mycarrier.reserved=Reserved
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Get my carrier group.
|
||||||
|
-- @param #OPSGROUP self
|
||||||
|
-- @return #OPSGROUP Carrier group.
|
||||||
|
function OPSGROUP:_GetMyCarrierGroup()
|
||||||
|
if self.mycarrier and self.mycarrier.group then
|
||||||
|
return self.mycarrier.group
|
||||||
|
end
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Get my carrier element.
|
||||||
|
-- @param #OPSGROUP self
|
||||||
|
-- @return #OPSGROUP.Element Carrier element.
|
||||||
|
function OPSGROUP:_GetMyCarrierElement()
|
||||||
|
if self.mycarrier and self.mycarrier.element then
|
||||||
|
return self.mycarrier.element
|
||||||
|
end
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Is my carrier reserved.
|
||||||
|
-- @param #OPSGROUP self
|
||||||
|
-- @return #boolean If `true`, space for me was reserved.
|
||||||
|
function OPSGROUP:_IsMyCarrierReserved()
|
||||||
|
if self.mycarrier then
|
||||||
|
return self.mycarrier.reserved
|
||||||
|
end
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
--- Get my carrier.
|
||||||
|
-- @param #OPSGROUP self
|
||||||
|
-- @return #OPSGROUP Carrier group.
|
||||||
|
-- @return #OPSGROUP.Element Carrier element.
|
||||||
|
-- @return #boolean If `true`, space is reserved for me
|
||||||
|
function OPSGROUP:_GetMyCarrier()
|
||||||
|
return self.mycarrier.group, self.mycarrier.element, self.mycarrier.reserved
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Remove my carrier.
|
||||||
|
-- @param #OPSGROUP self
|
||||||
|
-- @return #OPSGROUP self
|
||||||
|
function OPSGROUP:_RemoveMyCarrier()
|
||||||
|
self.mycarrier.group=nil
|
||||||
|
self.mycarrier.element=nil
|
||||||
|
self.mycarrier.reserved=nil
|
||||||
|
self.mycarrier={}
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
--- On after "Pickup" event.
|
--- On after "Pickup" event.
|
||||||
-- @param #OPSGROUP self
|
-- @param #OPSGROUP self
|
||||||
-- @param #string From From state.
|
-- @param #string From From state.
|
||||||
@@ -5403,14 +5349,6 @@ function OPSGROUP:onafterPickup(From, Event, To)
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- On before "Loading" event.
|
|
||||||
-- @param #OPSGROUP self
|
|
||||||
-- @param #string From From state.
|
|
||||||
-- @param #string Event Event.
|
|
||||||
-- @param #string To To state.
|
|
||||||
function OPSGROUP:onbeforeLoading(From, Event, To)
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
--- On after "Loading" event.
|
--- On after "Loading" event.
|
||||||
-- @param #OPSGROUP self
|
-- @param #OPSGROUP self
|
||||||
@@ -5485,12 +5423,12 @@ function OPSGROUP:onafterLoading(From, Event, To)
|
|||||||
|
|
||||||
else
|
else
|
||||||
-- Debug info.
|
-- Debug info.
|
||||||
env.info("FF cannot board carrier")
|
self:T(self.lid.."Cannot board carrier!")
|
||||||
end
|
end
|
||||||
|
|
||||||
else
|
else
|
||||||
-- Debug info.
|
-- Debug info.
|
||||||
env.info("FF cargo NOT in embark zone "..self.cargoTransport.embarkzone:GetName())
|
self:T(self.lid.."Cargo NOT in embark zone "..self.cargoTransport.embarkzone:GetName())
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
@@ -5526,7 +5464,7 @@ function OPSGROUP:onafterLoad(From, Event, To, CargoGroup, Carrier)
|
|||||||
self:I(self.lid..string.format("Loading group %s", tostring(CargoGroup.groupname)))
|
self:I(self.lid..string.format("Loading group %s", tostring(CargoGroup.groupname)))
|
||||||
|
|
||||||
-- Carrier element.
|
-- Carrier element.
|
||||||
local carrier=Carrier or CargoGroup.carrier --#OPSGROUP.Element
|
local carrier=Carrier or CargoGroup:_GetMyCarrierElement() --#OPSGROUP.Element
|
||||||
|
|
||||||
-- No carrier provided.
|
-- No carrier provided.
|
||||||
if not carrier then
|
if not carrier then
|
||||||
@@ -5553,8 +5491,7 @@ function OPSGROUP:onafterLoad(From, Event, To, CargoGroup, Carrier)
|
|||||||
CargoGroup:ClearWaypoints()
|
CargoGroup:ClearWaypoints()
|
||||||
|
|
||||||
-- Set carrier (again).
|
-- Set carrier (again).
|
||||||
CargoGroup.carrier=carrier
|
CargoGroup:_SetMyCarrier(self, carrier, false)
|
||||||
CargoGroup.carrierGroup=self
|
|
||||||
|
|
||||||
-- Despawn this group.
|
-- Despawn this group.
|
||||||
if CargoGroup:IsAlive() then
|
if CargoGroup:IsAlive() then
|
||||||
@@ -5576,7 +5513,9 @@ end
|
|||||||
-- @param #string Event Event.
|
-- @param #string Event Event.
|
||||||
-- @param #string To To state.
|
-- @param #string To To state.
|
||||||
function OPSGROUP:onafterLoaded(From, Event, To)
|
function OPSGROUP:onafterLoaded(From, Event, To)
|
||||||
env.info("FF loaded")
|
|
||||||
|
-- Debug info.
|
||||||
|
self:T(self.lid.."Carrier Loaded ==> Transport")
|
||||||
|
|
||||||
-- Cancel landedAt task.
|
-- Cancel landedAt task.
|
||||||
if self:IsFlightgroup() and self:IsLandedAt() then
|
if self:IsFlightgroup() and self:IsLandedAt() then
|
||||||
@@ -5691,6 +5630,17 @@ function OPSGROUP:onafterTransport(From, Event, To)
|
|||||||
|
|
||||||
elseif self.isArmygroup then
|
elseif self.isArmygroup then
|
||||||
|
|
||||||
|
local path=self.cargoTransport:_GetPathTransport()
|
||||||
|
if path then
|
||||||
|
|
||||||
|
for _,_zone in pairs(path.zones:GetSet()) do
|
||||||
|
local zone=_zone --Core.Zone#ZONE
|
||||||
|
local coordinate=zone:GetRandomCoordinate(nil, nil, nil) --TODO: surface type land
|
||||||
|
local waypoint=ARMYGROUP.AddWaypoint(self, coordinate, nil, self:GetWaypointCurrent().uid) ; waypoint.temp=true
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
-- ARMYGROUP
|
-- ARMYGROUP
|
||||||
local waypoint=ARMYGROUP.AddWaypoint(self, Coordinate, nil, self:GetWaypointCurrent().uid) ; waypoint.detour=true
|
local waypoint=ARMYGROUP.AddWaypoint(self, Coordinate, nil, self:GetWaypointCurrent().uid) ; waypoint.detour=true
|
||||||
|
|
||||||
@@ -5699,8 +5649,24 @@ function OPSGROUP:onafterTransport(From, Event, To)
|
|||||||
|
|
||||||
elseif self.isNavygroup then
|
elseif self.isNavygroup then
|
||||||
|
|
||||||
|
local cwp=self:GetWaypointCurrent()
|
||||||
|
local uid=cwp and cwp.uid or nil
|
||||||
|
|
||||||
|
-- Get a (random) pre-defined transport path.
|
||||||
|
local path=self.cargoTransport:_GetPathTransport()
|
||||||
|
|
||||||
|
if path then
|
||||||
|
-- Loop over zones
|
||||||
|
for i,coordinate in pairs(path) do
|
||||||
|
local waypoint=NAVYGROUP.AddWaypoint(self, coordinate, nil, uid)
|
||||||
|
waypoint.temp=true
|
||||||
|
uid=waypoint.uid
|
||||||
|
coordinate:MarkToAll(string.format("Path i=%d, UID=%d", i, uid))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
-- NAVYGROUP
|
-- NAVYGROUP
|
||||||
local waypoint=NAVYGROUP.AddWaypoint(self, Coordinate, nil, self:GetWaypointCurrent().uid) ; waypoint.detour=true
|
local waypoint=NAVYGROUP.AddWaypoint(self, Coordinate, nil, uid) ; waypoint.detour=true
|
||||||
|
|
||||||
-- Give cruise command.
|
-- Give cruise command.
|
||||||
self:Cruise()
|
self:Cruise()
|
||||||
@@ -5731,12 +5697,25 @@ function OPSGROUP:onafterUnloading(From, Event, To)
|
|||||||
|
|
||||||
-- Check that cargo is loaded into this group.
|
-- Check that cargo is loaded into this group.
|
||||||
-- NOTE: Could be that the element carriing this cargo group is DEAD, which would mean that the cargo group is also DEAD.
|
-- NOTE: Could be that the element carriing this cargo group is DEAD, which would mean that the cargo group is also DEAD.
|
||||||
if cargo.opsgroup:IsLoaded(self.groupname) and not (cargo.opsgroup:IsDead() or cargo.opsgroup:IsStopped()) then
|
if cargo.opsgroup:IsLoaded(self.groupname) and not cargo.opsgroup:IsDead() then
|
||||||
|
|
||||||
env.info("FF deploy cargo "..cargo.opsgroup:GetName())
|
-- Disembark to carrier.
|
||||||
|
local needscarrier=false
|
||||||
|
local carrier=nil
|
||||||
|
local carrierGroup=nil
|
||||||
|
|
||||||
-- New carrier group.
|
|
||||||
local carrierGroup=self.cargoTransport.carrierGroup
|
if self.cargoTransport.disembarkCarriers and #self.cargoTransport.disembarkCarriers>0 then
|
||||||
|
|
||||||
|
needscarrier=true
|
||||||
|
|
||||||
|
carrier, carrierGroup=self.cargoTransport:FindTransferCarrierForCargo(cargo.opsgroup, zone)
|
||||||
|
|
||||||
|
--TODO: max unloading time if transfer carrier does not arrive in the zone.
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
if needscarrier==false or (needscarrier and carrier and carrierGroup) then
|
||||||
|
|
||||||
-- Cargo was delivered (somehow).
|
-- Cargo was delivered (somehow).
|
||||||
cargo.delivered=true
|
cargo.delivered=true
|
||||||
@@ -5744,22 +5723,15 @@ function OPSGROUP:onafterUnloading(From, Event, To)
|
|||||||
-- Increase number of delivered cargos.
|
-- Increase number of delivered cargos.
|
||||||
self.cargoTransport.Ndelivered=self.cargoTransport.Ndelivered+1
|
self.cargoTransport.Ndelivered=self.cargoTransport.Ndelivered+1
|
||||||
|
|
||||||
if carrierGroup then
|
if carrier and carrierGroup then
|
||||||
|
|
||||||
---
|
---
|
||||||
-- Delivered to another carrier group.
|
-- Delivered to another carrier group.
|
||||||
---
|
---
|
||||||
|
|
||||||
-- Get new carrier.
|
|
||||||
local carrier=carrierGroup:FindCarrierForCargo(cargo.opsgroup)
|
|
||||||
|
|
||||||
if carrier then
|
|
||||||
-- Unload from this and directly load into the other carrier.
|
-- Unload from this and directly load into the other carrier.
|
||||||
self:Unload(cargo.opsgroup)
|
self:Unload(cargo.opsgroup)
|
||||||
carrierGroup:Load(cargo.opsgroup, carrier)
|
carrierGroup:Load(cargo.opsgroup, carrier)
|
||||||
else
|
|
||||||
env.info("ERROR: No element of the group can take this cargo!")
|
|
||||||
end
|
|
||||||
|
|
||||||
elseif zone and zone:IsInstanceOf("ZONE_AIRBASE") and zone:GetAirbase():IsShip() then
|
elseif zone and zone:IsInstanceOf("ZONE_AIRBASE") and zone:GetAirbase():IsShip() then
|
||||||
|
|
||||||
@@ -5767,8 +5739,9 @@ function OPSGROUP:onafterUnloading(From, Event, To)
|
|||||||
-- Delivered to a ship via helo or VTOL
|
-- Delivered to a ship via helo or VTOL
|
||||||
---
|
---
|
||||||
|
|
||||||
--
|
-- Issue warning.
|
||||||
env.info("ERROR: Deploy/disembark zone is a ZONE_AIRBASE of a ship! Where to put the cargo? Dumping into the sea, sorry!")
|
env.info("ERROR: Deploy/disembark zone is a ZONE_AIRBASE of a ship! Where to put the cargo? Dumping into the sea, sorry!")
|
||||||
|
--TODO: Dumb into sea.
|
||||||
|
|
||||||
else
|
else
|
||||||
|
|
||||||
@@ -5813,12 +5786,19 @@ function OPSGROUP:onafterUnloading(From, Event, To)
|
|||||||
-- Trigger "Unloaded" event for current cargo transport
|
-- Trigger "Unloaded" event for current cargo transport
|
||||||
self.cargoTransport:Unloaded(cargo.opsgroup)
|
self.cargoTransport:Unloaded(cargo.opsgroup)
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
else
|
||||||
|
self:T(self.lid.."Cargo needs carrier but no carrier is avaiable (yet)!")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
else
|
||||||
|
-- Not loaded or dead
|
||||||
|
end
|
||||||
|
|
||||||
|
end -- loop over cargos
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- On before "Unload" event.
|
--- On before "Unload" event.
|
||||||
@@ -5854,6 +5834,8 @@ function OPSGROUP:onafterUnload(From, Event, To, OpsGroup, Coordinate, Activated
|
|||||||
-- Set cargo status.
|
-- Set cargo status.
|
||||||
OpsGroup.cargoStatus=OPSGROUP.CargoStatus.NOTCARGO
|
OpsGroup.cargoStatus=OPSGROUP.CargoStatus.NOTCARGO
|
||||||
|
|
||||||
|
--TODO: Unload flightgroup. Find parking spot etc.
|
||||||
|
|
||||||
if Coordinate then
|
if Coordinate then
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -5900,6 +5882,14 @@ function OPSGROUP:onafterUnload(From, Event, To, OpsGroup, Coordinate, Activated
|
|||||||
-- Respawn group.
|
-- Respawn group.
|
||||||
OpsGroup:_Respawn(0, Template)
|
OpsGroup:_Respawn(0, Template)
|
||||||
|
|
||||||
|
if self:IsNavygroup() then
|
||||||
|
self.currentwp=1
|
||||||
|
NAVYGROUP.AddWaypoint(self, Coordinate, nil, nil, nil, false)
|
||||||
|
elseif self:IsArmygroup() then
|
||||||
|
self.currentwp=1
|
||||||
|
ARMYGROUP.AddWaypoint(self, Coordinate, nil, nil, nil, false)
|
||||||
|
end
|
||||||
|
|
||||||
else
|
else
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -6033,6 +6023,14 @@ function OPSGROUP:onbeforeBoard(From, Event, To, CarrierGroup, Carrier)
|
|||||||
if self:IsDead() then
|
if self:IsDead() then
|
||||||
self:I(self.lid.."Group DEAD ==> Deny Board transition!")
|
self:I(self.lid.."Group DEAD ==> Deny Board transition!")
|
||||||
return false
|
return false
|
||||||
|
elseif CarrierGroup:IsDead() then
|
||||||
|
self:I(self.lid.."Carrier Group DEAD ==> Deny Board transition!")
|
||||||
|
self.cargoStatus=OPSGROUP.CargoStatus.NOTCARGO
|
||||||
|
return false
|
||||||
|
elseif Carrier.status==OPSGROUP.ElementStatus.DEAD then
|
||||||
|
self:I(self.lid.."Carrier Element DEAD ==> Deny Board transition!")
|
||||||
|
self.cargoStatus=OPSGROUP.CargoStatus.NOTCARGO
|
||||||
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
return true
|
return true
|
||||||
@@ -6052,21 +6050,21 @@ function OPSGROUP:onafterBoard(From, Event, To, CarrierGroup, Carrier)
|
|||||||
-- Set cargo status.
|
-- Set cargo status.
|
||||||
self.cargoStatus=OPSGROUP.CargoStatus.BOARDING
|
self.cargoStatus=OPSGROUP.CargoStatus.BOARDING
|
||||||
|
|
||||||
-- Set carrier.
|
-- Set carrier. As long as the group is not loaded, we only reserve the cargo space.
|
||||||
self.carrier=Carrier
|
self:_SetMyCarrier(CarrierGroup, Carrier, true)
|
||||||
self.carrierGroup=CarrierGroup
|
|
||||||
|
|
||||||
-- Army or navy group.
|
-- Army or Navy group.
|
||||||
local isArmyOrNavy=CarrierGroup:IsArmygroup() or CarrierGroup:IsNavygroup()
|
local CarrierIsArmyOrNavy=CarrierGroup:IsArmygroup() or CarrierGroup:IsNavygroup()
|
||||||
|
local CargoIsArmyOrNavy=self:IsArmygroup() or self:IsNavygroup()
|
||||||
|
|
||||||
-- Check that carrier is standing still.
|
-- Check that carrier is standing still.
|
||||||
if isArmyOrNavy and CarrierGroup:IsHolding() or CarrierGroup:IsParking() or CarrierGroup:IsLandedAt() then
|
if (CarrierIsArmyOrNavy and CarrierGroup:IsHolding()) or (CarrierGroup:IsParking() or CarrierGroup:IsLandedAt()) then
|
||||||
|
|
||||||
-- Board if group is mobile, not late activated and army or navy. Everything else is loaded directly.
|
-- Board if group is mobile, not late activated and army or navy. Everything else is loaded directly.
|
||||||
local board=self.speedMax>0 and self:IsAlive() and isArmyOrNavy and self.carrierGroup:IsAlive()
|
local board=self.speedMax>0 and CargoIsArmyOrNavy and self:IsAlive() and CarrierGroup:IsAlive()
|
||||||
|
|
||||||
-- Armygroup cannot board ship ==> Load directly.
|
-- Armygroup cannot board ship ==> Load directly.
|
||||||
if self:IsArmygroup() and self.carrierGroup:IsNavygroup() then
|
if self:IsArmygroup() and CarrierGroup:IsNavygroup() then
|
||||||
board=false
|
board=false
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -6093,16 +6091,20 @@ function OPSGROUP:onafterBoard(From, Event, To, CarrierGroup, Carrier)
|
|||||||
|
|
||||||
else
|
else
|
||||||
|
|
||||||
|
---
|
||||||
|
-- Direct load into carrier.
|
||||||
|
---
|
||||||
|
|
||||||
-- Debug info.
|
-- Debug info.
|
||||||
self:I(self.lid..string.format("FF board with direct load to carrier %s", self.carrierGroup:GetName()))
|
self:I(self.lid..string.format("Board with direct load to carrier %s", CarrierGroup:GetName()))
|
||||||
|
|
||||||
-- Trigger Load event.
|
-- Trigger Load event.
|
||||||
self.carrierGroup:Load(self)
|
CarrierGroup:Load(self)
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
else
|
else
|
||||||
env.info("FF Carrier not ready for boarding yet ==> repeating boarding call in 10 sec")
|
self:T(self.lid.."Carrier not ready for boarding yet ==> repeating boarding call in 10 sec")
|
||||||
self:__Board(-10, CarrierGroup, Carrier)
|
self:__Board(-10, CarrierGroup, Carrier)
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -6827,7 +6829,17 @@ function OPSGROUP._PassingWaypoint(group, opsgroup, uid)
|
|||||||
opsgroup:I(opsgroup.lid..text)
|
opsgroup:I(opsgroup.lid..text)
|
||||||
|
|
||||||
-- Trigger PassingWaypoint event.
|
-- Trigger PassingWaypoint event.
|
||||||
if waypoint.astar then
|
if waypoint.temp then
|
||||||
|
|
||||||
|
-- Remove temp waypoint.
|
||||||
|
opsgroup:RemoveWaypointByID(uid)
|
||||||
|
|
||||||
|
if opsgroup:IsNavygroup() or opsgroup:IsArmygroup() then
|
||||||
|
--TODO: not sure if this works with FLIGHTGROUPS
|
||||||
|
opsgroup:Cruise()
|
||||||
|
end
|
||||||
|
|
||||||
|
elseif waypoint.astar then
|
||||||
|
|
||||||
-- Remove Astar waypoint.
|
-- Remove Astar waypoint.
|
||||||
opsgroup:RemoveWaypointByID(uid)
|
opsgroup:RemoveWaypointByID(uid)
|
||||||
@@ -6867,8 +6879,6 @@ function OPSGROUP._PassingWaypoint(group, opsgroup, uid)
|
|||||||
|
|
||||||
if opsgroup.isFlightgroup then
|
if opsgroup.isFlightgroup then
|
||||||
|
|
||||||
env.info("FF passing waypointg in state istransporting ==> land at")
|
|
||||||
|
|
||||||
-- Land at current pos and wait for 60 min max.
|
-- Land at current pos and wait for 60 min max.
|
||||||
opsgroup:LandAt(opsgroup:GetCoordinate(), 60*60)
|
opsgroup:LandAt(opsgroup:GetCoordinate(), 60*60)
|
||||||
|
|
||||||
@@ -6880,12 +6890,15 @@ function OPSGROUP._PassingWaypoint(group, opsgroup, uid)
|
|||||||
|
|
||||||
elseif opsgroup:IsBoarding() then
|
elseif opsgroup:IsBoarding() then
|
||||||
|
|
||||||
if opsgroup.carrierGroup and opsgroup.carrierGroup:IsAlive() then
|
local carrierGroup=opsgroup:_GetMyCarrierGroup()
|
||||||
|
local carrier=opsgroup:_GetMyCarrierElement()
|
||||||
|
|
||||||
if opsgroup.carrier and opsgroup.carrier.unit and opsgroup.carrier.unit:IsAlive() then
|
if carrierGroup and carrierGroup:IsAlive() then
|
||||||
|
|
||||||
|
if carrier and carrier.unit and carrier.unit:IsAlive() then
|
||||||
|
|
||||||
-- Load group into the carrier.
|
-- Load group into the carrier.
|
||||||
opsgroup.carrierGroup:Load(opsgroup)
|
carrierGroup:Load(opsgroup)
|
||||||
|
|
||||||
else
|
else
|
||||||
opsgroup:E(opsgroup.lid.."ERROR: Group cannot board assigned carrier UNIT as it is NOT alive!")
|
opsgroup:E(opsgroup.lid.."ERROR: Group cannot board assigned carrier UNIT as it is NOT alive!")
|
||||||
@@ -7652,9 +7665,6 @@ function OPSGROUP:_UpdatePosition()
|
|||||||
-- Add up travelled distance.
|
-- Add up travelled distance.
|
||||||
self.traveldist=self.traveldist+self.travelds
|
self.traveldist=self.traveldist+self.travelds
|
||||||
|
|
||||||
-- Debug info.
|
|
||||||
--env.info(string.format("FF Traveled %.1f m", self.traveldist))
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
return self
|
return self
|
||||||
|
|||||||
@@ -26,9 +26,8 @@
|
|||||||
-- @field #string lid Log ID.
|
-- @field #string lid Log ID.
|
||||||
-- @field #number uid Unique ID of the transport.
|
-- @field #number uid Unique ID of the transport.
|
||||||
-- @field #number verbose Verbosity level.
|
-- @field #number verbose Verbosity level.
|
||||||
-- @field #table cargos Cargos. Each element is a @{#OPSGROUP.Cargo}.
|
-- @field #table cargos Cargos. Each element is a @{Ops.OpsGroup#OPSGROUP.CargoGroup}.
|
||||||
-- @field #table carriers Carriers assigned for this transport.
|
-- @field #table carriers Carriers assigned for this transport.
|
||||||
-- @field #string status Status of the transport. See @{#OPSTRANSPORT.Status}.
|
|
||||||
-- @field #number prio Priority of this transport. Should be a number between 0 (high prio) and 100 (low prio).
|
-- @field #number prio Priority of this transport. Should be a number between 0 (high prio) and 100 (low prio).
|
||||||
-- @field #number importance Importance of this transport. Smaller=higher.
|
-- @field #number importance Importance of this transport. Smaller=higher.
|
||||||
-- @field #number Tstart Start time in *abs.* seconds.
|
-- @field #number Tstart Start time in *abs.* seconds.
|
||||||
@@ -39,12 +38,13 @@
|
|||||||
-- @field Core.Zone#ZONE embarkzone (Optional) Zone where the cargo is supposed to embark. Default is the pickup zone.
|
-- @field Core.Zone#ZONE embarkzone (Optional) Zone where the cargo is supposed to embark. Default is the pickup zone.
|
||||||
-- @field Core.Zone#ZONE disembarkzone (Optional) Zone where the cargo is disembarked. Default is the deploy zone.
|
-- @field Core.Zone#ZONE disembarkzone (Optional) Zone where the cargo is disembarked. Default is the deploy zone.
|
||||||
-- @field Core.Zone#ZONE unboardzone (Optional) Zone where the cargo is going to after disembarkment.
|
-- @field Core.Zone#ZONE unboardzone (Optional) Zone where the cargo is going to after disembarkment.
|
||||||
-- @field Ops.OpsGroup#OPSGROUP carrierGroup The new carrier group.
|
|
||||||
-- @field #boolean disembarkActivation Activation setting when group is disembared from carrier.
|
-- @field #boolean disembarkActivation Activation setting when group is disembared from carrier.
|
||||||
-- @field #boolean disembarkInUtero Do not spawn the group in any any state but leave it "*in utero*". For example, to directly load it into another carrier.
|
-- @field #boolean disembarkInUtero Do not spawn the group in any any state but leave it "*in utero*". For example, to directly load it into another carrier.
|
||||||
|
-- @field #table disembarkCarriers Table of carriers to which the cargo is disembared. This is a direct transfer from the old to the new carrier.
|
||||||
-- @field #number Ncargo Total number of cargo groups.
|
-- @field #number Ncargo Total number of cargo groups.
|
||||||
-- @field #number Ncarrier Total number of assigned carriers.
|
-- @field #number Ncarrier Total number of assigned carriers.
|
||||||
-- @field #number Ndelivered Total number of cargo groups delivered.
|
-- @field #number Ndelivered Total number of cargo groups delivered.
|
||||||
|
-- @field #table pathsTransport Paths of `#OPSGROUP.Path`.
|
||||||
-- @extends Core.Fsm#FSM
|
-- @extends Core.Fsm#FSM
|
||||||
|
|
||||||
--- *Victory is the beautiful, bright-colored flower. Transport is the stem without which it could never have blossomed.* -- Winston Churchill
|
--- *Victory is the beautiful, bright-colored flower. Transport is the stem without which it could never have blossomed.* -- Winston Churchill
|
||||||
@@ -65,11 +65,12 @@ OPSTRANSPORT = {
|
|||||||
carriers = {},
|
carriers = {},
|
||||||
carrierTransportStatus = {},
|
carrierTransportStatus = {},
|
||||||
conditionStart = {},
|
conditionStart = {},
|
||||||
|
pathsTransport = {},
|
||||||
}
|
}
|
||||||
|
|
||||||
--- Cargo transport status.
|
--- Cargo transport status.
|
||||||
-- @type OPSTRANSPORT.Status
|
-- @type OPSTRANSPORT.Status
|
||||||
-- @field #string PLANNING Planning state.
|
-- @field #string PLANNED Planning state.
|
||||||
-- @field #string SCHEDULED Transport is scheduled in the cargo queue.
|
-- @field #string SCHEDULED Transport is scheduled in the cargo queue.
|
||||||
-- @field #string EXECUTING Transport is being executed.
|
-- @field #string EXECUTING Transport is being executed.
|
||||||
-- @field #string DELIVERED Transport was delivered.
|
-- @field #string DELIVERED Transport was delivered.
|
||||||
@@ -80,6 +81,12 @@ OPSTRANSPORT.Status={
|
|||||||
DELIVERED="delivered",
|
DELIVERED="delivered",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
--- Path.
|
||||||
|
-- @type OPSTRANSPORT.Path
|
||||||
|
-- @field #table coords Table of coordinates.
|
||||||
|
-- @field #number radius Radomization radius in meters. Default 0 m.
|
||||||
|
-- @field #number altitude Altitude in feet AGL. Only for aircraft.
|
||||||
|
|
||||||
--- Generic mission condition.
|
--- Generic mission condition.
|
||||||
-- @type OPSTRANSPORT.Condition
|
-- @type OPSTRANSPORT.Condition
|
||||||
-- @field #function func Callback function to check for a condition. Should return a #boolean.
|
-- @field #function func Callback function to check for a condition. Should return a #boolean.
|
||||||
@@ -122,25 +129,23 @@ function OPSTRANSPORT:New(GroupSet, Pickupzone, Deployzone)
|
|||||||
|
|
||||||
-- Defaults.
|
-- Defaults.
|
||||||
self.uid=_OPSTRANSPORTID
|
self.uid=_OPSTRANSPORTID
|
||||||
self.status=OPSTRANSPORT.Status.PLANNING
|
--self.status=OPSTRANSPORT.Status.PLANNING
|
||||||
|
|
||||||
self.pickupzone=Pickupzone
|
self.pickupzone=Pickupzone
|
||||||
self.deployzone=Deployzone
|
self.deployzone=Deployzone
|
||||||
self.embarkzone=Pickupzone
|
self.embarkzone=Pickupzone
|
||||||
self.carrierGroup=nil
|
|
||||||
self.cargos={}
|
self.cargos={}
|
||||||
self.carriers={}
|
self.carriers={}
|
||||||
self.Ncargo=0
|
self.Ncargo=0
|
||||||
self.Ncarrier=0
|
self.Ncarrier=0
|
||||||
self.Ndelivered=0
|
self.Ndelivered=0
|
||||||
|
|
||||||
|
|
||||||
self:SetPriority()
|
self:SetPriority()
|
||||||
self:SetTime()
|
self:SetTime()
|
||||||
|
|
||||||
-- Add cargo groups.
|
-- Add cargo groups (could also be added later).
|
||||||
if GroupSet then
|
if GroupSet then
|
||||||
self:AddCargoGroups(GroupSet, Pickupzone, Deployzone)
|
self:AddCargoGroups(GroupSet)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
@@ -152,8 +157,11 @@ function OPSTRANSPORT:New(GroupSet, Pickupzone, Deployzone)
|
|||||||
self:AddTransition(OPSTRANSPORT.Status.PLANNED, "Scheduled", OPSTRANSPORT.Status.SCHEDULED) -- Cargo is queued at at least one carrier.
|
self:AddTransition(OPSTRANSPORT.Status.PLANNED, "Scheduled", OPSTRANSPORT.Status.SCHEDULED) -- Cargo is queued at at least one carrier.
|
||||||
self:AddTransition(OPSTRANSPORT.Status.SCHEDULED, "Executing", OPSTRANSPORT.Status.EXECUTING) -- Cargo is being transported.
|
self:AddTransition(OPSTRANSPORT.Status.SCHEDULED, "Executing", OPSTRANSPORT.Status.EXECUTING) -- Cargo is being transported.
|
||||||
self:AddTransition(OPSTRANSPORT.Status.EXECUTING, "Delivered", OPSTRANSPORT.Status.DELIVERED) -- Cargo was delivered.
|
self:AddTransition(OPSTRANSPORT.Status.EXECUTING, "Delivered", OPSTRANSPORT.Status.DELIVERED) -- Cargo was delivered.
|
||||||
|
|
||||||
self:AddTransition("*", "Status", "*")
|
self:AddTransition("*", "Status", "*")
|
||||||
self:AddTransition("*", "Stop", "*")
|
self:AddTransition("*", "Stop", "*")
|
||||||
|
|
||||||
|
self:AddTransition("*", "Loaded", "*")
|
||||||
self:AddTransition("*", "Unloaded", "*")
|
self:AddTransition("*", "Unloaded", "*")
|
||||||
|
|
||||||
|
|
||||||
@@ -171,13 +179,13 @@ end
|
|||||||
-- @param #OPSTRANSPORT self
|
-- @param #OPSTRANSPORT self
|
||||||
-- @param Core.Set#SET_GROUP GroupSet Set of groups to be transported. Can also be passed as a single GROUP or OPSGROUP object.
|
-- @param Core.Set#SET_GROUP GroupSet Set of groups to be transported. Can also be passed as a single GROUP or OPSGROUP object.
|
||||||
-- @return #OPSTRANSPORT self
|
-- @return #OPSTRANSPORT self
|
||||||
function OPSTRANSPORT:AddCargoGroups(GroupSet, Pickupzone, Deployzone)
|
function OPSTRANSPORT:AddCargoGroups(GroupSet)
|
||||||
|
|
||||||
-- Check type of GroupSet provided.
|
-- Check type of GroupSet provided.
|
||||||
if GroupSet:IsInstanceOf("GROUP") or GroupSet:IsInstanceOf("OPSGROUP") then
|
if GroupSet:IsInstanceOf("GROUP") or GroupSet:IsInstanceOf("OPSGROUP") then
|
||||||
|
|
||||||
-- We got a single GROUP or OPSGROUP object.
|
-- We got a single GROUP or OPSGROUP object.
|
||||||
local cargo=self:_CreateCargoGroupData(GroupSet, Pickupzone, Deployzone)
|
local cargo=self:_CreateCargoGroupData(GroupSet)
|
||||||
|
|
||||||
if cargo then --and self:CanCargo(cargo.opsgroup)
|
if cargo then --and self:CanCargo(cargo.opsgroup)
|
||||||
table.insert(self.cargos, cargo)
|
table.insert(self.cargos, cargo)
|
||||||
@@ -190,7 +198,7 @@ function OPSTRANSPORT:AddCargoGroups(GroupSet, Pickupzone, Deployzone)
|
|||||||
|
|
||||||
for _,group in pairs(GroupSet.Set) do
|
for _,group in pairs(GroupSet.Set) do
|
||||||
|
|
||||||
local cargo=self:_CreateCargoGroupData(group, Pickupzone, Deployzone)
|
local cargo=self:_CreateCargoGroupData(group)
|
||||||
|
|
||||||
if cargo then
|
if cargo then
|
||||||
table.insert(self.cargos, cargo)
|
table.insert(self.cargos, cargo)
|
||||||
@@ -202,11 +210,10 @@ function OPSTRANSPORT:AddCargoGroups(GroupSet, Pickupzone, Deployzone)
|
|||||||
|
|
||||||
-- Debug info.
|
-- Debug info.
|
||||||
if self.verbose>=0 then
|
if self.verbose>=0 then
|
||||||
local text=string.format("Created Cargo Transport (UID=%d) from %s(%s) --> %s(%s)",
|
local text=string.format("Added cargo groups:")
|
||||||
self.uid, self.pickupzone:GetName(), self.embarkzone and self.embarkzone:GetName() or "none", self.deployzone:GetName(), self.disembarkzone and self.disembarkzone:GetName() or "none")
|
|
||||||
local Weight=0
|
local Weight=0
|
||||||
for _,_cargo in pairs(self.cargos) do
|
for _,_cargo in pairs(self.cargos) do
|
||||||
local cargo=_cargo --#OPSGROUP.CargoGroup
|
local cargo=_cargo --Ops.OpsGroup#OPSGROUP.CargoGroup
|
||||||
local weight=cargo.opsgroup:GetWeightTotal()
|
local weight=cargo.opsgroup:GetWeightTotal()
|
||||||
Weight=Weight+weight
|
Weight=Weight+weight
|
||||||
text=text..string.format("\n- %s [%s] weight=%.1f kg", cargo.opsgroup:GetName(), cargo.opsgroup:GetState(), weight)
|
text=text..string.format("\n- %s [%s] weight=%.1f kg", cargo.opsgroup:GetName(), cargo.opsgroup:GetState(), weight)
|
||||||
@@ -250,6 +257,40 @@ function OPSTRANSPORT:SetDisembarkActivation(Active)
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Set transfer carrier(s). These are carrier groups, where the cargo is directly loaded into when disembarked.
|
||||||
|
-- @param #OPSTRANSPORT self
|
||||||
|
-- @param Core.Set#SET_GROUP Carriers Carrier set.
|
||||||
|
-- @return #OPSTRANSPORT self
|
||||||
|
function OPSTRANSPORT:SetDisembarkCarriers(Carriers)
|
||||||
|
|
||||||
|
self:I(self.lid.."Setting transfer carriers!")
|
||||||
|
|
||||||
|
-- Create table.
|
||||||
|
self.disembarkCarriers=self.disembarkCarriers or {}
|
||||||
|
|
||||||
|
if Carriers:IsInstanceOf("GROUP") or Carriers:IsInstanceOf("OPSGROUP") then
|
||||||
|
|
||||||
|
local carrier=self:_GetOpsGroupFromObject(Carriers)
|
||||||
|
if carrier then
|
||||||
|
table.insert(self.disembarkCarriers, carrier)
|
||||||
|
end
|
||||||
|
|
||||||
|
elseif Carriers:IsInstanceOf("SET_GROUP") or Carriers:IsInstanceOf("SET_OPSGROUP") then
|
||||||
|
|
||||||
|
for _,object in pairs(Carriers:GetSet()) do
|
||||||
|
local carrier=self:_GetOpsGroupFromObject(object)
|
||||||
|
if carrier then
|
||||||
|
table.insert(self.disembarkCarriers, carrier)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
else
|
||||||
|
self:E(self.lid.."ERROR: Carriers must be a GROUP, OPSGROUP, SET_GROUP or SET_OPSGROUP object!")
|
||||||
|
end
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Set if group remains *in utero* after disembarkment from carrier. Can be used to directly load the group into another carrier. Similar to disembark in late activated state.
|
--- Set if group remains *in utero* after disembarkment from carrier. Can be used to directly load the group into another carrier. Similar to disembark in late activated state.
|
||||||
-- @param #OPSTRANSPORT self
|
-- @param #OPSTRANSPORT self
|
||||||
@@ -264,21 +305,7 @@ function OPSTRANSPORT:SetDisembarkInUtero(InUtero)
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Check if an OPS group is assigned as carrier for this transport.
|
|
||||||
-- @param #OPSTRANSPORT self
|
|
||||||
-- @param Ops.OpsGroup#OPSGROUP CarrierGroup Potential carrier OPSGROUP.
|
|
||||||
-- @return #boolean If true, group is an assigned carrier.
|
|
||||||
function OPSTRANSPORT:IsCarrier(CarrierGroup)
|
|
||||||
|
|
||||||
for _,_carrier in pairs(self.carriers) do
|
|
||||||
local carrier=_carrier --Ops.OpsGroup#OPSGROUP
|
|
||||||
if carrier.groupname==CarrierGroup.groupname then
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Add a carrier assigned for this transport.
|
--- Add a carrier assigned for this transport.
|
||||||
-- @param #OPSTRANSPORT self
|
-- @param #OPSTRANSPORT self
|
||||||
@@ -359,6 +386,8 @@ end
|
|||||||
-- @return #OPSTRANSPORT self
|
-- @return #OPSTRANSPORT self
|
||||||
function OPSTRANSPORT:AddConditionStart(ConditionFunction, ...)
|
function OPSTRANSPORT:AddConditionStart(ConditionFunction, ...)
|
||||||
|
|
||||||
|
if ConditionFunction then
|
||||||
|
|
||||||
local condition={} --#OPSTRANSPORT.Condition
|
local condition={} --#OPSTRANSPORT.Condition
|
||||||
|
|
||||||
condition.func=ConditionFunction
|
condition.func=ConditionFunction
|
||||||
@@ -369,9 +398,63 @@ function OPSTRANSPORT:AddConditionStart(ConditionFunction, ...)
|
|||||||
|
|
||||||
table.insert(self.conditionStart, condition)
|
table.insert(self.conditionStart, condition)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Add path used for transportation from the pickup to the deploy zone. If multiple paths are defined, a random one is chosen.
|
||||||
|
-- @param #OPSTRANSPORT self
|
||||||
|
-- @param Wrapper.Group#GROUP PathGroup A (late activated) GROUP defining a transport path by their waypoints.
|
||||||
|
-- @param #number Radius Randomization radius in meters. Default 0 m.
|
||||||
|
-- @param #number Altitude Altitude in feet AGL. Only for aircraft.
|
||||||
|
-- @return #OPSTRANSPORT self
|
||||||
|
function OPSTRANSPORT:AddPathTransport(PathGroup, Radius, Altitude)
|
||||||
|
|
||||||
|
local path={} --#OPSTRANSPORT.Path
|
||||||
|
path.coords={}
|
||||||
|
path.radius=Radius or 0
|
||||||
|
path.altitude=Altitude
|
||||||
|
|
||||||
|
-- Get route points.
|
||||||
|
local waypoints=PathGroup:GetTaskRoute()
|
||||||
|
|
||||||
|
for _,wp in pairs(waypoints) do
|
||||||
|
local coord=COORDINATE:New(wp.x, wp.alt, wp.y)
|
||||||
|
table.insert(path.coords, coord)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Add path.
|
||||||
|
table.insert(self.pathsTransport, path)
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Get a path for transportation.
|
||||||
|
-- @param #OPSTRANSPORT self
|
||||||
|
-- @return #table The path of COORDINATEs.
|
||||||
|
function OPSTRANSPORT:_GetPathTransport()
|
||||||
|
|
||||||
|
if self.pathsTransport and #self.pathsTransport>0 then
|
||||||
|
|
||||||
|
-- Get a random path for transport.
|
||||||
|
local path=self.pathsTransport[math.random(#self.pathsTransport)] --#OPSTRANSPORT.Path
|
||||||
|
|
||||||
|
|
||||||
|
local coordinates={}
|
||||||
|
for _,coord in ipairs(path.coords) do
|
||||||
|
|
||||||
|
-- TODO: Add randomization.
|
||||||
|
|
||||||
|
table.insert(coordinates, coord)
|
||||||
|
end
|
||||||
|
|
||||||
|
return coordinates
|
||||||
|
end
|
||||||
|
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Add a carrier assigned for this transport.
|
--- Add a carrier assigned for this transport.
|
||||||
-- @param #OPSTRANSPORT self
|
-- @param #OPSTRANSPORT self
|
||||||
@@ -394,46 +477,22 @@ function OPSTRANSPORT:GetCarrierTransportStatus(CarrierGroup)
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Create a cargo group data structure.
|
|
||||||
|
|
||||||
|
--- Check if an OPS group is assigned as carrier for this transport.
|
||||||
-- @param #OPSTRANSPORT self
|
-- @param #OPSTRANSPORT self
|
||||||
-- @param Wrapper.Group#GROUP group The GROUP object.
|
-- @param Ops.OpsGroup#OPSGROUP CarrierGroup Potential carrier OPSGROUP.
|
||||||
-- @param Core.Zone#ZONE Pickupzone Pickup zone.
|
-- @return #boolean If true, group is an assigned carrier.
|
||||||
-- @param Core.Zone#ZONE Deployzone Deploy zone.
|
function OPSTRANSPORT:IsCarrier(CarrierGroup)
|
||||||
-- @return #OPSGROUP.CargoGroup Cargo group data.
|
|
||||||
function OPSTRANSPORT:_CreateCargoGroupData(group, Pickupzone, Deployzone)
|
|
||||||
|
|
||||||
local opsgroup=nil
|
for _,_carrier in pairs(self.carriers) do
|
||||||
|
local carrier=_carrier --Ops.OpsGroup#OPSGROUP
|
||||||
if group:IsInstanceOf("OPSGROUP") then
|
if carrier.groupname==CarrierGroup.groupname then
|
||||||
opsgroup=group
|
return true
|
||||||
elseif group:IsInstanceOf("GROUP") then
|
|
||||||
|
|
||||||
opsgroup=_DATABASE:GetOpsGroup(group)
|
|
||||||
|
|
||||||
if not opsgroup then
|
|
||||||
if group:IsAir() then
|
|
||||||
opsgroup=FLIGHTGROUP:New(group)
|
|
||||||
elseif group:IsShip() then
|
|
||||||
opsgroup=NAVYGROUP:New(group)
|
|
||||||
else
|
|
||||||
opsgroup=ARMYGROUP:New(group)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
else
|
return false
|
||||||
self:E(self.lid.."ERROR: Cargo must be a GROUP or OPSGROUP object!")
|
|
||||||
return nil
|
|
||||||
end
|
|
||||||
|
|
||||||
local cargo={} --#OPSGROUP.CargoGroup
|
|
||||||
|
|
||||||
cargo.opsgroup=opsgroup
|
|
||||||
cargo.delivered=false
|
|
||||||
cargo.status="Unknown"
|
|
||||||
cargo.pickupzone=Pickupzone
|
|
||||||
cargo.deployzone=Deployzone
|
|
||||||
|
|
||||||
return cargo
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Check if transport is ready to be started.
|
--- Check if transport is ready to be started.
|
||||||
@@ -444,30 +503,48 @@ end
|
|||||||
-- @return #boolean If true, mission can be started.
|
-- @return #boolean If true, mission can be started.
|
||||||
function OPSTRANSPORT:IsReadyToGo()
|
function OPSTRANSPORT:IsReadyToGo()
|
||||||
|
|
||||||
|
-- Debug text.
|
||||||
|
local text=self.lid.."Is ReadyToGo? "
|
||||||
|
|
||||||
|
-- Current abs time.
|
||||||
local Tnow=timer.getAbsTime()
|
local Tnow=timer.getAbsTime()
|
||||||
|
|
||||||
-- Start time did not pass yet.
|
-- Start time did not pass yet.
|
||||||
if self.Tstart and Tnow<self.Tstart or false then
|
if self.Tstart and Tnow<self.Tstart or false then
|
||||||
|
text=text.."No, start time not passed!"
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Stop time already passed.
|
-- Stop time already passed.
|
||||||
if self.Tstop and Tnow>self.Tstop or false then
|
if self.Tstop and Tnow>self.Tstop or false then
|
||||||
|
text=text.."Nope, stop time already passed!"
|
||||||
|
self:T(text)
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
-- All start conditions true?
|
-- All start conditions true?
|
||||||
local startme=self:EvalConditionsAll(self.conditionStart)
|
local startme=self:EvalConditionsAll(self.conditionStart)
|
||||||
|
|
||||||
|
-- Nope, not yet.
|
||||||
if not startme then
|
if not startme then
|
||||||
|
text=text..("No way, at least one start condition is not true!")
|
||||||
|
self:I(text)
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
-- We're good to go!
|
-- We're good to go!
|
||||||
|
text=text.."Yes!"
|
||||||
|
self:T(text)
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Check if all cargo was delivered (or is dead).
|
||||||
|
-- @param #OPSTRANSPORT self
|
||||||
|
-- @return #boolean If true, all possible cargo was delivered.
|
||||||
|
function OPSTRANSPORT:IsDelivered()
|
||||||
|
return self:is(OPSTRANSPORT.Status.DELIVERED)
|
||||||
|
end
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
-- Status Update
|
-- Status Update
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
@@ -482,14 +559,16 @@ function OPSTRANSPORT:onafterStatus(From, Event, To)
|
|||||||
-- Current FSM state.
|
-- Current FSM state.
|
||||||
local fsmstate=self:GetState()
|
local fsmstate=self:GetState()
|
||||||
|
|
||||||
|
-- Info text.
|
||||||
local text=string.format("%s [%s --> %s]: Ncargo=%d/%d, Ncarrier=%d", fsmstate:upper(), self.pickupzone:GetName(), self.deployzone:GetName(), self.Ncargo, self.Ndelivered, self.Ncarrier)
|
local text=string.format("%s [%s --> %s]: Ncargo=%d/%d, Ncarrier=%d", fsmstate:upper(), self.pickupzone:GetName(), self.deployzone:GetName(), self.Ncargo, self.Ndelivered, self.Ncarrier)
|
||||||
|
|
||||||
text=text..string.format("\nCargos:")
|
text=text..string.format("\nCargos:")
|
||||||
for _,_cargo in pairs(self.cargos) do
|
for _,_cargo in pairs(self.cargos) do
|
||||||
local cargo=_cargo --Ops.OpsGroup#OPSGROUP.CargoGroup
|
local cargo=_cargo --Ops.OpsGroup#OPSGROUP.CargoGroup
|
||||||
local name=cargo.opsgroup.carrier and cargo.opsgroup.carrier.name or "none"
|
local carrier=cargo.opsgroup:_GetMyCarrierElement()
|
||||||
text=text..string.format("\n- %s: %s [%s], weight=%d kg, carrier=%s", cargo.opsgroup:GetName(), cargo.opsgroup.cargoStatus:upper(), cargo.opsgroup:GetState(), cargo.opsgroup:GetWeightTotal(), name)
|
local name=carrier and carrier.name or "none"
|
||||||
|
local cstate=carrier and carrier.status or "N/A"
|
||||||
|
text=text..string.format("\n- %s: %s [%s], weight=%d kg, carrier=%s [%s]", cargo.opsgroup:GetName(), cargo.opsgroup.cargoStatus:upper(), cargo.opsgroup:GetState(), cargo.opsgroup:GetWeightTotal(), name, cstate)
|
||||||
end
|
end
|
||||||
|
|
||||||
text=text..string.format("\nCarriers:")
|
text=text..string.format("\nCarriers:")
|
||||||
@@ -504,7 +583,10 @@ function OPSTRANSPORT:onafterStatus(From, Event, To)
|
|||||||
-- Check if all cargo was delivered (or is dead).
|
-- Check if all cargo was delivered (or is dead).
|
||||||
self:_CheckDelivered()
|
self:_CheckDelivered()
|
||||||
|
|
||||||
|
-- Update status again.
|
||||||
|
if not self:IsDelivered() then
|
||||||
self:__Status(-30)
|
self:__Status(-30)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
@@ -574,6 +656,9 @@ end
|
|||||||
-- @param #OPSTRANSPORT self
|
-- @param #OPSTRANSPORT self
|
||||||
function OPSTRANSPORT:_CheckDelivered()
|
function OPSTRANSPORT:_CheckDelivered()
|
||||||
|
|
||||||
|
-- First check that at least one cargo was added (as we allow to do that later).
|
||||||
|
if self.Ncargo>0 then
|
||||||
|
|
||||||
local done=true
|
local done=true
|
||||||
local dead=true
|
local dead=true
|
||||||
for _,_cargo in pairs(self.cargos) do
|
for _,_cargo in pairs(self.cargos) do
|
||||||
@@ -609,6 +694,8 @@ function OPSTRANSPORT:_CheckDelivered()
|
|||||||
self:Delivered()
|
self:Delivered()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Check if all given condition are true.
|
--- Check if all given condition are true.
|
||||||
@@ -634,3 +721,92 @@ function OPSTRANSPORT:EvalConditionsAll(Conditions)
|
|||||||
-- All conditions were true.
|
-- All conditions were true.
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
--- Find transfer carrier element for cargo group.
|
||||||
|
-- @param #OPSTRANSPORT self
|
||||||
|
-- @param Ops.OpsGroup#OPSGROUP CargoGroup The cargo group that needs to be loaded into a carrier unit/element of the carrier group.
|
||||||
|
-- @param Core.Zone#ZONE Zone (Optional) Zone where the carrier must be in.
|
||||||
|
-- @return Ops.OpsGroup#OPSGROUP.Element New carrier element for cargo or nil.
|
||||||
|
-- @return Ops.OpsGroup#OPSGROUP New carrier group for cargo or nil.
|
||||||
|
function OPSTRANSPORT:FindTransferCarrierForCargo(CargoGroup, Zone)
|
||||||
|
|
||||||
|
local carrier=nil --Ops.OpsGroup#OPSGROUP.Element
|
||||||
|
local carrierGroup=nil --Ops.OpsGroup#OPSGROUP
|
||||||
|
|
||||||
|
--TODO: maybe sort the carriers wrt to largest free cargo bay. Or better smallest free cargo bay that can take the cargo group weight.
|
||||||
|
|
||||||
|
for _,_carrier in pairs(self.disembarkCarriers or {}) do
|
||||||
|
local carrierGroup=_carrier --Ops.OpsGroup#OPSGROUP
|
||||||
|
|
||||||
|
-- Find an element of the group that has enough free space.
|
||||||
|
carrier=carrierGroup:FindCarrierForCargo(CargoGroup)
|
||||||
|
|
||||||
|
if carrier then
|
||||||
|
if Zone==nil or Zone:IsCoordinateInZone(carrier.unit:GetCoordinate()) then
|
||||||
|
return carrier, carrierGroup
|
||||||
|
else
|
||||||
|
self:T3(self.lid.."Got transfer carrier but carrier not in zone (yet)!")
|
||||||
|
end
|
||||||
|
else
|
||||||
|
self:T3(self.lid.."No transfer carrier available!")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return nil, nil
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Create a cargo group data structure.
|
||||||
|
-- @param #OPSTRANSPORT self
|
||||||
|
-- @param Wrapper.Group#GROUP group The GROUP or OPSGROUP object.
|
||||||
|
-- @return Ops.OpsGroup#OPSGROUP.CargoGroup Cargo group data.
|
||||||
|
function OPSTRANSPORT:_CreateCargoGroupData(group)
|
||||||
|
|
||||||
|
local opsgroup=self:_GetOpsGroupFromObject(group)
|
||||||
|
|
||||||
|
local cargo={} --Ops.OpsGroup#OPSGROUP.CargoGroup
|
||||||
|
|
||||||
|
cargo.opsgroup=opsgroup
|
||||||
|
cargo.delivered=false
|
||||||
|
cargo.status="Unknown"
|
||||||
|
cargo.disembarkCarrierElement=nil
|
||||||
|
cargo.disembarkCarrierGroup=nil
|
||||||
|
|
||||||
|
return cargo
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Get an OPSGROUIP
|
||||||
|
-- @param #OPSTRANSPORT self
|
||||||
|
-- @param Core.Base#BASE Object The object, which can be a GROUP or OPSGROUP.
|
||||||
|
-- @return Ops.OpsGroup#OPSGROUP Ops Group.
|
||||||
|
function OPSTRANSPORT:_GetOpsGroupFromObject(Object)
|
||||||
|
|
||||||
|
local opsgroup=nil
|
||||||
|
|
||||||
|
if Object:IsInstanceOf("OPSGROUP") then
|
||||||
|
-- We already have an OPSGROUP
|
||||||
|
opsgroup=Object
|
||||||
|
elseif Object:IsInstanceOf("GROUP") then
|
||||||
|
|
||||||
|
-- Look into DB and try to find an existing OPSGROUP.
|
||||||
|
opsgroup=_DATABASE:GetOpsGroup(Object)
|
||||||
|
|
||||||
|
if not opsgroup then
|
||||||
|
if Object:IsAir() then
|
||||||
|
opsgroup=FLIGHTGROUP:New(Object)
|
||||||
|
elseif Object:IsShip() then
|
||||||
|
opsgroup=NAVYGROUP:New(Object)
|
||||||
|
else
|
||||||
|
opsgroup=ARMYGROUP:New(Object)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
else
|
||||||
|
self:E(self.lid.."ERROR: Object must be a GROUP or OPSGROUP object!")
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
return opsgroup
|
||||||
|
end
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user