This commit is contained in:
Applevangelist
2025-11-13 15:54:47 +01:00
parent c9c6d5dbc2
commit 6f05249214
12 changed files with 1013 additions and 561 deletions
-30
View File
@@ -1063,36 +1063,6 @@ end
do -- Event Creation
--- Creation of a New Cargo Event.
-- @param #EVENT self
-- @param AI.AI_Cargo#AI_CARGO Cargo The Cargo created.
function EVENT:CreateEventNewCargo( Cargo )
self:F( { Cargo } )
local Event = {
id = EVENTS.NewCargo,
time = timer.getTime(),
cargo = Cargo,
}
world.onEvent( Event )
end
--- Creation of a Cargo Deletion Event.
-- @param #EVENT self
-- @param AI.AI_Cargo#AI_CARGO Cargo The Cargo created.
function EVENT:CreateEventDeleteCargo( Cargo )
self:F( { Cargo } )
local Event = {
id = EVENTS.DeleteCargo,
time = timer.getTime(),
cargo = Cargo,
}
world.onEvent( Event )
end
--- Creation of a New Zone Event.
-- @param #EVENT self
-- @param Core.Zone#ZONE_BASE Zone The Zone created.
-470
View File
@@ -1106,30 +1106,6 @@ do
-- --self:F({ GroupObject = GroupObject:GetName() })
-- end
--
-- While this is a good example, there is a catch.
-- Imagine you want to execute the code above, the the self would need to be from the object declared outside (above) the OnAfterDead method.
-- So, the self would need to contain another object. Fortunately, this can be done, but you must use then the **`.`** notation for the method.
-- See the modified example:
--
-- -- Now we have a constructor of the class AI_CARGO_DISPATCHER, that receives the SetHelicopter as a parameter.
-- -- Within that constructor, we want to set an enclosed event handler OnAfterDead for SetHelicopter.
-- -- But within the OnAfterDead method, we want to refer to the self variable of the AI_CARGO_DISPATCHER.
--
-- function AI_CARGO_DISPATCHER:New(SetCarrier, SetCargo, SetDeployZones)
--
-- local self = BASE:Inherit(self, FSM:New()) -- #AI_CARGO_DISPATCHER
--
-- -- Put a Dead event handler on SetCarrier, to ensure that when a carrier is destroyed, that all internal parameters are reset.
-- -- Note the "." notation, and the explicit declaration of SetHelicopter, which would be using the ":" notation the implicit self variable declaration.
--
-- function SetHelicopter.OnAfterDead(SetHelicopter, From, Event, To, GroupObject)
-- SetHelicopter:F({ GroupObject = GroupObject:GetName() })
-- self.PickupCargo[GroupObject] = nil -- So here I clear the PickupCargo table entry of the self object AI_CARGO_DISPATCHER.
-- self.CarrierHome[GroupObject] = nil
-- end
--
-- end
--
-- ===
-- @field #SET_GROUP SET_GROUP
SET_GROUP = {
@@ -2269,28 +2245,6 @@ do -- SET_UNIT
-- --self:F({ UnitObject = UnitObject:GetName() })
-- end
--
-- While this is a good example, there is a catch.
-- Imagine you want to execute the code above, the the self would need to be from the object declared outside (above) the OnAfterDead method.
-- So, the self would need to contain another object. Fortunately, this can be done, but you must use then the **`.`** notation for the method.
-- See the modified example:
--
-- -- Now we have a constructor of the class AI_CARGO_DISPATCHER, that receives the SetHelicopter as a parameter.
-- -- Within that constructor, we want to set an enclosed event handler OnAfterDead for SetHelicopter.
-- -- But within the OnAfterDead method, we want to refer to the self variable of the AI_CARGO_DISPATCHER.
--
-- function ACLASS:New(SetCarrier, SetCargo, SetDeployZones)
--
-- local self = BASE:Inherit(self, FSM:New()) -- #AI_CARGO_DISPATCHER
--
-- -- Put a Dead event handler on SetCarrier, to ensure that when a carrier is destroyed, that all internal parameters are reset.
-- -- Note the "." notation, and the explicit declaration of SetHelicopter, which would be using the ":" notation the implicit self variable declaration.
--
-- function SetHelicopter.OnAfterDead(SetHelicopter, From, Event, To, UnitObject)
-- SetHelicopter:F({ UnitObject = UnitObject:GetName() })
-- self.array[UnitObject] = nil -- So here I clear the array table entry of the self object ACLASS.
-- end
--
-- end
-- ===
-- @field #SET_UNIT SET_UNIT
SET_UNIT = {
@@ -5781,430 +5735,6 @@ do -- SET_AIRBASE
end
do -- SET_CARGO
---
-- @type SET_CARGO
-- @extends Core.Set#SET_BASE
--- Mission designers can use the @{Core.Set#SET_CARGO} class to build sets of cargos optionally belonging to certain:
--
-- * Coalitions
-- * Types
-- * Name or Prefix
--
-- ## SET_CARGO constructor
--
-- Create a new SET_CARGO object with the @{#SET_CARGO.New} method:
--
-- * @{#SET_CARGO.New}: Creates a new SET_CARGO object.
--
-- ## Add or Remove CARGOs from SET_CARGO
--
-- CARGOs can be added and removed using the @{Core.Set#SET_CARGO.AddCargosByName} and @{Core.Set#SET_CARGO.RemoveCargosByName} respectively.
-- These methods take a single CARGO name or an array of CARGO names to be added or removed from SET_CARGO.
--
-- ## SET_CARGO filter criteria
--
-- You can set filter criteria to automatically maintain the SET_CARGO contents.
-- Filter criteria are defined by:
--
-- * @{#SET_CARGO.FilterCoalitions}: Builds the SET_CARGO with the cargos belonging to the coalition(s).
-- * @{#SET_CARGO.FilterPrefixes}: Builds the SET_CARGO with the cargos containing the same string(s). **Attention!** LUA regular expression apply here, so special characters in names like minus, dot, hash (#) etc might lead to unexpected results.
-- Have a read through here to understand the application of regular expressions: [LUA regular expressions](https://riptutorial.com/lua/example/20315/lua-pattern-matching)
-- * @{#SET_CARGO.FilterTypes}: Builds the SET_CARGO with the cargos belonging to the cargo type(s).
-- * @{#SET_CARGO.FilterCountries}: Builds the SET_CARGO with the cargos belonging to the country(ies).
--
-- Once the filter criteria have been set for the SET_CARGO, you can start filtering using:
--
-- * @{#SET_CARGO.FilterStart}: Starts the filtering of the cargos within the SET_CARGO.
--
-- ## SET_CARGO iterators
--
-- Once the filters have been defined and the SET_CARGO has been built, you can iterate the SET_CARGO with the available iterator methods.
-- The iterator methods will walk the SET_CARGO set, and call for each cargo within the set a function that you provide.
-- The following iterator methods are currently available within the SET_CARGO:
--
-- * @{#SET_CARGO.ForEachCargo}: Calls a function for each cargo it finds within the SET_CARGO.
--
-- @field #SET_CARGO SET_CARGO
SET_CARGO = {
ClassName = "SET_CARGO",
Cargos = {},
Filter = {
Coalitions = nil,
Types = nil,
Countries = nil,
ClientPrefixes = nil,
},
FilterMeta = {
Coalitions = {
red = coalition.side.RED,
blue = coalition.side.BLUE,
neutral = coalition.side.NEUTRAL,
},
},
}
--- Creates a new SET_CARGO object, building a set of cargos belonging to a coalitions and categories.
-- @param #SET_CARGO self
-- @return #SET_CARGO
-- @usage
-- -- Define a new SET_CARGO Object. The DatabaseSet will contain a reference to all Cargos.
-- DatabaseSet = SET_CARGO:New()
function SET_CARGO:New() -- R2.1
-- Inherits from BASE
local self = BASE:Inherit(self, SET_BASE:New(_DATABASE.CARGOS)) -- #SET_CARGO
return self
end
--- Add CARGO to SET_CARGO.
-- @param Core.Set#SET_CARGO self
-- @param Cargo.Cargo#CARGO Cargo A single cargo.
-- @return Core.Set#SET_CARGO self
function SET_CARGO:AddCargo(Cargo) -- R2.4
self:Add(Cargo:GetName(), Cargo)
return self
end
--- Add CARGOs to SET_CARGO.
-- @param Core.Set#SET_CARGO self
-- @param #string AddCargoNames A single name or an array of CARGO names.
-- @return Core.Set#SET_CARGO self
function SET_CARGO:AddCargosByName(AddCargoNames) -- R2.1
local AddCargoNamesArray = (type(AddCargoNames) == "table") and AddCargoNames or { AddCargoNames }
for AddCargoID, AddCargoName in pairs(AddCargoNamesArray) do
self:Add(AddCargoName, CARGO:FindByName(AddCargoName))
end
return self
end
--- Remove CARGOs from SET_CARGO.
-- @param Core.Set#SET_CARGO self
-- @param Cargo.Cargo#CARGO RemoveCargoNames A single name or an array of CARGO names.
-- @return Core.Set#SET_CARGO self
function SET_CARGO:RemoveCargosByName(RemoveCargoNames) -- R2.1
local RemoveCargoNamesArray = (type(RemoveCargoNames) == "table") and RemoveCargoNames or { RemoveCargoNames }
for RemoveCargoID, RemoveCargoName in pairs(RemoveCargoNamesArray) do
self:Remove(RemoveCargoName.CargoName)
end
return self
end
--- Finds a Cargo based on the Cargo Name.
-- @param #SET_CARGO self
-- @param #string CargoName
-- @return Cargo.Cargo#CARGO The found Cargo.
function SET_CARGO:FindCargo(CargoName) -- R2.1
local CargoFound = self.Set[CargoName]
return CargoFound
end
--- Builds a set of cargos of coalitions.
-- Possible current coalitions are red, blue and neutral.
-- @param #SET_CARGO self
-- @param #string Coalitions Can take the following values: "red", "blue", "neutral".
-- @return #SET_CARGO self
--- Builds a set of cargos of defined cargo types.
-- Possible current types are those types known within DCS world.
-- @param #SET_CARGO self
-- @param #string Types Can take those type strings known within DCS world.
-- @return #SET_CARGO self
function SET_CARGO:FilterTypes(Types) -- R2.1
if not self.Filter.Types then
self.Filter.Types = {}
end
if type(Types) ~= "table" then
Types = { Types }
end
for TypeID, Type in pairs(Types) do
self.Filter.Types[Type] = Type
end
return self
end
--- Builds a set of cargos of defined countries.
-- Possible current countries are those known within DCS world.
-- @param #SET_CARGO self
-- @param #string Countries Can take those country strings known within DCS world.
-- @return #SET_CARGO self
function SET_CARGO:FilterCountries(Countries) -- R2.1
if not self.Filter.Countries then
self.Filter.Countries = {}
end
if type(Countries) ~= "table" then
Countries = { Countries }
end
for CountryID, Country in pairs(Countries) do
self.Filter.Countries[Country] = Country
end
return self
end
--- Builds a set of CARGOs that contain a given string in their name.
-- **Attention!** Bad naming convention as this **does not** filter only **prefixes** but all cargos that **contain** the string.
-- @param #SET_CARGO self
-- @param #string Prefixes The string pattern(s) that need to be in the cargo name. Can also be passed as a `#table` of strings.
-- @return #SET_CARGO self
function SET_CARGO:FilterPrefixes(Prefixes) -- R2.1
if not self.Filter.CargoPrefixes then
self.Filter.CargoPrefixes = {}
end
if type(Prefixes) ~= "table" then
Prefixes = { Prefixes }
end
for PrefixID, Prefix in pairs(Prefixes) do
self.Filter.CargoPrefixes[Prefix] = Prefix
end
return self
end
--- Starts the filtering.
-- @param #SET_CARGO self
-- @return #SET_CARGO self
function SET_CARGO:FilterStart() -- R2.1
if _DATABASE then
self:_FilterStart()
self:HandleEvent(EVENTS.NewCargo)
self:HandleEvent(EVENTS.DeleteCargo)
end
return self
end
--- Stops the filtering for the defined collection.
-- @param #SET_CARGO self
-- @return #SET_CARGO self
function SET_CARGO:FilterStop()
self:UnHandleEvent(EVENTS.NewCargo)
self:UnHandleEvent(EVENTS.DeleteCargo)
return self
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_CARGO self
-- @param Core.Event#EVENTDATA Event
-- @return #string The name of the CARGO
-- @return #table The CARGO
function SET_CARGO:AddInDatabase(Event) -- R2.1
--self:F3({ Event })
return Event.IniDCSUnitName, self.Database[Event.IniDCSUnitName]
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_CARGO self
-- @param Core.Event#EVENTDATA Event
-- @return #string The name of the CARGO
-- @return #table The CARGO
function SET_CARGO:FindInDatabase(Event) -- R2.1
--self:F3({ Event })
return Event.IniDCSUnitName, self.Database[Event.IniDCSUnitName]
end
--- Iterate the SET_CARGO and call an iterator function for each CARGO, providing the CARGO and optional parameters.
-- @param #SET_CARGO self
-- @param #function IteratorFunction The function that will be called when there is an alive CARGO in the SET_CARGO. The function needs to accept a CARGO parameter.
-- @return #SET_CARGO self
function SET_CARGO:ForEachCargo(IteratorFunction, ...) -- R2.1
--self:F2(arg)
self:ForEach(IteratorFunction, arg, self:GetSet())
return self
end
--- Iterate the SET_CARGO while identifying the nearest @{Cargo.Cargo#CARGO} from a @{Core.Point#COORDINATE}.
-- @param #SET_CARGO self
-- @param Core.Point#COORDINATE Coordinate A @{Core.Point#COORDINATE} object from where to evaluate the closest @{Cargo.Cargo#CARGO}.
-- @return Cargo.Cargo#CARGO The closest @{Cargo.Cargo#CARGO}.
function SET_CARGO:FindNearestCargoFromPointVec2(Coordinate) -- R2.1
--self:F2(Coordinate)
local NearestCargo = self:FindNearestObjectFromPointVec2(Coordinate)
return NearestCargo
end
---
-- @param #SET_CARGO self
function SET_CARGO:FirstCargoWithState(State)
local FirstCargo = nil
for CargoName, Cargo in pairs(self.Set) do
if Cargo:Is(State) then
FirstCargo = Cargo
break
end
end
return FirstCargo
end
---
-- @param #SET_CARGO self
function SET_CARGO:FirstCargoWithStateAndNotDeployed(State)
local FirstCargo = nil
for CargoName, Cargo in pairs(self.Set) do
if Cargo:Is(State) and not Cargo:IsDeployed() then
FirstCargo = Cargo
break
end
end
return FirstCargo
end
--- Iterate the SET_CARGO while identifying the first @{Cargo.Cargo#CARGO} that is UnLoaded.
-- @param #SET_CARGO self
-- @return Cargo.Cargo#CARGO The first @{Cargo.Cargo#CARGO}.
function SET_CARGO:FirstCargoUnLoaded()
local FirstCargo = self:FirstCargoWithState("UnLoaded")
return FirstCargo
end
--- Iterate the SET_CARGO while identifying the first @{Cargo.Cargo#CARGO} that is UnLoaded and not Deployed.
-- @param #SET_CARGO self
-- @return Cargo.Cargo#CARGO The first @{Cargo.Cargo#CARGO}.
function SET_CARGO:FirstCargoUnLoadedAndNotDeployed()
local FirstCargo = self:FirstCargoWithStateAndNotDeployed("UnLoaded")
return FirstCargo
end
--- Iterate the SET_CARGO while identifying the first @{Cargo.Cargo#CARGO} that is Loaded.
-- @param #SET_CARGO self
-- @return Cargo.Cargo#CARGO The first @{Cargo.Cargo#CARGO}.
function SET_CARGO:FirstCargoLoaded()
local FirstCargo = self:FirstCargoWithState("Loaded")
return FirstCargo
end
--- Iterate the SET_CARGO while identifying the first @{Cargo.Cargo#CARGO} that is Deployed.
-- @param #SET_CARGO self
-- @return Cargo.Cargo#CARGO The first @{Cargo.Cargo#CARGO}.
function SET_CARGO:FirstCargoDeployed()
local FirstCargo = self:FirstCargoWithState("Deployed")
return FirstCargo
end
---
-- @param #SET_CARGO self
-- @param AI.AI_Cargo#AI_CARGO MCargo
-- @return #SET_CARGO self
function SET_CARGO:IsIncludeObject(MCargo) -- R2.1
--self:F2(MCargo)
local MCargoInclude = true
if MCargo then
local MCargoName = MCargo:GetName()
if self.Filter.Coalitions then
local MCargoCoalition = false
for CoalitionID, CoalitionName in pairs(self.Filter.Coalitions) do
local CargoCoalitionID = MCargo:GetCoalition()
--self:T(3({ "Coalition:", CargoCoalitionID, self.FilterMeta.Coalitions[CoalitionName], CoalitionName })
if self.FilterMeta.Coalitions[CoalitionName] and self.FilterMeta.Coalitions[CoalitionName] == CargoCoalitionID then
MCargoCoalition = true
end
end
--self:F({ "Evaluated Coalition", MCargoCoalition })
MCargoInclude = MCargoInclude and MCargoCoalition
end
if self.Filter.Types then
local MCargoType = false
for TypeID, TypeName in pairs(self.Filter.Types) do
--self:T(3({ "Type:", MCargo:GetType(), TypeName })
if TypeName == MCargo:GetType() then
MCargoType = true
end
end
--self:F({ "Evaluated Type", MCargoType })
MCargoInclude = MCargoInclude and MCargoType
end
if self.Filter.CargoPrefixes then
local MCargoPrefix = false
for CargoPrefixId, CargoPrefix in pairs(self.Filter.CargoPrefixes) do
--self:T(3({ "Prefix:", string.find(MCargo.Name, CargoPrefix, 1), CargoPrefix })
if string.find(MCargo.Name, CargoPrefix, 1) then
MCargoPrefix = true
end
end
--self:F({ "Evaluated Prefix", MCargoPrefix })
MCargoInclude = MCargoInclude and MCargoPrefix
end
end
if self.Filter.Functions and MCargoInclude then
local MClientFunc = self:_EvalFilterFunctions(MCargo)
MCargoInclude = MCargoInclude and MClientFunc
end
--self:T(2(MCargoInclude)
return MCargoInclude
end
--- Handles the OnEventNewCargo event for the Set.
-- @param #SET_CARGO self
-- @param Core.Event#EVENTDATA EventData
function SET_CARGO:OnEventNewCargo(EventData) -- R2.1
--self:F({ "New Cargo", EventData })
if EventData.Cargo then
if EventData.Cargo and self:IsIncludeObject(EventData.Cargo) then
self:Add(EventData.Cargo.Name, EventData.Cargo)
end
end
end
--- Handles the OnDead or OnCrash event for alive units set.
-- @param #SET_CARGO self
-- @param Core.Event#EVENTDATA EventData
function SET_CARGO:OnEventDeleteCargo(EventData) -- R2.1
--self:F3({ EventData })
if EventData.Cargo then
local Cargo = _DATABASE:FindCargo(EventData.Cargo.Name)
if Cargo and Cargo.Name then
-- When cargo was deleted, it may probably be because of an S_EVENT_DEAD.
-- However, in the loading logic, an S_EVENT_DEAD is also generated after a Destroy() call.
-- And this is a problem because it will remove all entries from the SET_CARGOs.
-- To prevent this from happening, the Cargo object has a flag NoDestroy.
-- When true, the SET_CARGO won't Remove the Cargo object from the set.
-- This flag is switched off after the event handlers have been called in the EVENT class.
--self:F({ CargoNoDestroy = Cargo.NoDestroy })
if Cargo.NoDestroy then
else
self:Remove(Cargo.Name)
end
end
end
end
end
do -- SET_ZONE