diff --git a/Moose Development/Moose/Functional/Tiresias.lua b/Moose Development/Moose/Functional/Tiresias.lua new file mode 100644 index 000000000..ba7d8ddcb --- /dev/null +++ b/Moose Development/Moose/Functional/Tiresias.lua @@ -0,0 +1,388 @@ +--- **Functional** - TIRESIAS +-- +-- === +-- +-- ## Features: +-- +-- * Tbd +-- +-- === +-- +-- ## Missions: +-- +-- ### [TIRESIAS](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master) +-- +-- === +-- +-- ### Author : **applevangelist ** +-- +-- @module Functional.Tiresias +-- @image Functional.Tiresias.jpg +-- +-- Last Update: Dec 2023 + +------------------------------------------------------------------------- +--- **TIRESIAS** class, extends Core.Base#BASE +-- @type TIRESIAS +-- @field #string ClassName +-- @field #booelan debug +-- @field #string version +-- @field #number Interval +-- @field Core.Set#SET_CLIENT PilotSet +-- @field Core.Set#SET_GROUP GroundSet +-- @field #string CoalitionText +-- @field #number Coalition +-- @field Core.Set#SET_GROUP VehicleSet +-- @field Core.Set#SET_GROUP AAASet +-- @field Core.Set#SET_GROUP SAMSet +-- @field #number AAARange +-- @field #number HeloSwitchRange +-- @field #number PlaneSwitchRange +-- @field Core.Set#SET_GROUP FlightSet +-- @extends Core.Fsm#FSM + +--- +-- @type TIRESIAS.Data +-- @field #string type +-- @field #number range +-- @field #boolean invisible +-- @field #boolean AIOff + + +--- +-- # Documentation +-- +-- @field TIRESIAS +TIRESIAS = { + ClassName = "TIRESIAS", + debug = true, + version = "0.0.1", + Interval = 20, + PilotSet = nil, + GroundSet = nil, + CoalitionText = "blue", + Coalition = coalition.side.BLUE, + VehicleSet = nil, + AAASet = nil, + SAMSet = nil, + AAARange = 60, + HeloSwitchRange = 10, -- NM + PlaneSwitchRange = 25, -- NM +} + +--- +-- @param #TIRESIAS self +-- @return #TIRESIAS self +function TIRESIAS:New() + + -- Inherit everything from FSM class. + local self = BASE:Inherit(self, FSM:New()) -- #TIRESIAS + + self.PilotSet = SET_CLIENT:New():FilterActive(true):FilterCoalitions(self.CoalitionText):FilterStart() + + --- FSM Functions --- + + -- Start State. + self:SetStartState("Stopped") + + -- Add FSM transitions. + -- From State --> Event --> To State + self:AddTransition("Stopped", "Start", "Running") -- Start FSM. + self:AddTransition("*", "Status", "*") -- TIRESIAS status update. + self:AddTransition("*", "Stop", "Stopped") -- Stop FSM. + + self:HandleEvent(EVENTS.PlayerEnterAircraft,self._EventHandler) + + self.lid = string.format("TIRESIAS %s | ",self.version) + + self:I(self.lid.."Managing ground groups!") + + self:__Start(1) + return self +end + +------------------------------------------------------------------------------------------------------------- +-- +-- Helper Functions +-- +------------------------------------------------------------------------------------------------------------- + +--- +-- @param #TIRESIAS self +-- @param Wrapper.Group#GROUP Group +-- @return #boolean isin +function TIRESIAS._FilterAAA(Group) + local grp = Group -- Wrapper.Group#GROUP + local isaaa = grp:IsAAA() + if isaaa == true and grp:IsGround() then + return false -- remove from SET + else + return true -- keep in SET + end +end + +--- +-- @param #TIRESIAS self +-- @param Wrapper.Group#GROUP Group +-- @return #boolean isin +function TIRESIAS._FilterSAM(Group) + local grp = Group -- Wrapper.Group#GROUP + local issam = grp:IsSAM() + if issam == true and grp:IsGround() then + return false -- remove from SET + else + return true -- keep in SET + end +end + +--- +-- @param #TIRESIAS self +-- @return #TIRESIAS self +function TIRESIAS:_InitGroups() + self:I(self.lid.."_InitGroups") + -- Set all groups invisible/motionless + local EngageRange = self.AAARange + self.AAASet:ForEachGroupAlive( + function(grp) + if not grp.Tiresias then + grp:OptionEngageRange(EngageRange) + grp:SetCommandInvisible(true) + grp.Tiresias = { -- #TIRESIAS.Data + type = "AAA", + invisible = true, + range = EngageRange, + } + end + if grp.Tiresias and grp.Tiresias.invisible and grp.Tiresias.invisible == false then + grp:SetCommandInvisible(true) + end + end + ) + self.VehicleSet:ForEachGroupAlive( + function(grp) + if not grp.Tiresias then + grp:SetAIOff() + grp:SetCommandInvisible(true) + grp.Tiresias = { -- #TIRESIAS.Data + type = "Vehicle", + invisible = true, + AIOff = true, + } + end + if grp.Tiresias and grp.Tiresias.invisible and grp.Tiresias.invisible == false then + grp:SetCommandInvisible(true) + grp:SetAIOff() + end + end + ) + self.SAMSet:ForEachGroupAlive( + function(grp) + if not grp.Tiresias then + grp:SetCommandInvisible(true) + grp.Tiresias = { -- #TIRESIAS.Data + type = "SAM", + invisible = true, + } + end + if grp.Tiresias and grp.Tiresias.invisible and grp.Tiresias.invisible == false then + grp:SetCommandInvisible(true) + end + end + ) + return self +end + +--- (Internal) Event handler function +-- @param #TIRESIAS self +-- @param Core.Event#EVENTDATA EventData +-- @return #TIRESIAS self +function TIRESIAS:_EventHandler(EventData) + self:I(string.format("%s Event = %d",self.lid, EventData.id)) + local event = EventData -- Core.Event#EVENTDATA + if event.id == EVENTS.PlayerEnterAircraft or event.id == EVENTS.PlayerEnterUnit then + local _coalition = event.IniCoalition + if _coalition ~= self.Coalition then + return --ignore! + end + local unitname = event.IniUnitName or "none" + local _unit = event.IniUnit + local _group = event.IniGroup + if _group and _group:IsAlive() then + local radius = self.PlaneSwitchRange + if _group:IsHelicopter() then + radius = self.HeloSwitchRange + end + self:_SwitchOnGroups(_group,radius) + end + end + return self +end + +--- +-- @param #TIRESIAS self +-- @param Wrapper.Group#GROUP group +-- @param #number radius Radius in NM +-- @return #TIRESIAS self +function TIRESIAS:_SwitchOnGroups(group,radius) + self:I(self.lid.."_SwitchOnGroups "..group:GetName().." Radius "..radius.." NM") + local zone = ZONE_GROUP:New("Zone-"..group:GetName(),group,UTILS.NMToMeters(radius)) + local ground = SET_GROUP:New():FilterCategoryGround():FilterZones({zone}):FilterOnce() + local count = ground:CountAlive() + if self.debug then + local text = string.format("There are %d groups around this plane or helo!",count) + self:I(text) + end + if ground:CountAlive() > 0 then + ground:ForEachGroupAlive( + function(grp) + if grp.Tiresias and grp.Tiresias.type then + if grp.Tiresias.invisible == true then + grp:SetCommandInvisible(false) + grp.Tiresias.invisible = false + end + if grp.Tiresias.type == "Vehicle" and grp.Tiresias.AIOff and grp.Tiresias.AIOff == false then + grp:SetAIOn() + grp.Tiresias.AIOff = false + end + else + BASE:I("TIRESIAS - This group has not been initialized!") + end + end + ) + end + return self +end + +------------------------------------------------------------------------------------------------------------- +-- +-- FSM Functions +-- +------------------------------------------------------------------------------------------------------------- + +--- +-- @param #TIRESIAS self +-- @param #string From +-- @param #string Event +-- @param #string To +-- @return #TIRESIAS self +function TIRESIAS:onafterStart(From, Event, To) + self:I({From, Event, To}) + + local VehicleSet = SET_GROUP:New():FilterCategoryGround():FilterFunction(TIRESIAS._FilterAAA):FilterFunction(TIRESIAS._FilterSAM):FilterStart() + local AAASet = SET_GROUP:New():FilterCategoryGround():FilterFunction(function(grp) return grp:IsAAA() end):FilterStart() + local SAMSet = SET_GROUP:New():FilterCategoryGround():FilterFunction(function(grp) return grp:IsSAM() end):FilterStart() + self.FlightSet = SET_GROUP:New():FilterCategories({"plane","helicopter"}):FilterStart() + + local EngageRange = self.AAARange + + function VehicleSet:OnAfterAdded(From,Event,To,ObjectName,Object) + BASE:I("TIRESIAS: VEHCILE Object Added: "..Object:GetName()) + if Object and Object:IsAlive() then + Object:SetAIOff() + Object:SetCommandInvisible(true) + Object.Tiresias = { -- #TIRESIAS.Data + type = "Vehicle", + invisible = true, + AIOff = true, + } + end + end + + function AAASet:OnAfterAdded(From,Event,To,ObjectName,Object) + if Object and Object:IsAlive() then + BASE:I("TIRESIAS: AAA Object Added: "..Object:GetName()) + Object:OptionEngageRange(EngageRange) + Object:SetCommandInvisible(true) + Object.Tiresias = { -- #TIRESIAS.Data + type = "AAA", + invisible = true, + range = EngageRange, + } + end + end + + function SAMSet:OnAfterAdded(From,Event,To,ObjectName,Object) + if Object and Object:IsAlive() then + BASE:I("TIRESIAS: SAM Object Added: "..Object:GetName()) + Object:SetCommandInvisible(true) + Object.Tiresias = { -- #TIRESIAS.Data + type = "SAM", + invisible = true, + } + end + end + + self.VehicleSet = VehicleSet + self.AAASet = AAASet + self.SAMSet = SAMSet + + self:_InitGroups() + + self:__Status(1) + return self +end + +--- +-- @param #TIRESIAS self +-- @param #string From +-- @param #string Event +-- @param #string To +-- @return #TIRESIAS self +function TIRESIAS:onbeforeStatus(From, Event, To) + self:T({From, Event, To}) + if self:GetState() == "Stopped" then + return false + end + return self +end + +--- +-- @param #TIRESIAS self +-- @param #string From +-- @param #string Event +-- @param #string To +-- @return #TIRESIAS self +function TIRESIAS:onafterStatus(From, Event, To) + self:I({From, Event, To}) + if self.debug then + local count = self.VehicleSet:CountAlive() + local AAAcount = self.AAASet:CountAlive() + local SAMcount = self.SAMSet:CountAlive() + local text = string.format("Overall: %d | Vehicles: %d | AAA: %d | SAM: %d",count+AAAcount+SAMcount,count,AAAcount,SAMcount) + self:I(text) + end + self:_InitGroups() + if self.FlightSet:CountAlive() > 0 then + local Set = self.FlightSet:GetAliveSet() + for _,_plane in pairs(Set) do + local plane = _plane -- Wrapper.Group#GROUP + local radius = self.PlaneSwitchRange + if plane:IsHelicopter() then + radius = self.HeloSwitchRange + end + self:_SwitchOnGroups(_plane,radius) + end + end + if self:GetState() ~= "Stopped" then + self:__Status(self.Interval) + end + return self +end + +--- +-- @param #TIRESIAS self +-- @param #string From +-- @param #string Event +-- @param #string To +-- @return #TIRESIAS self +function TIRESIAS:onafterStop(From, Event, To) + self:I({From, Event, To}) + self:UnHandleEvent(EVENTS.PlayerEnterAircraft) + return self +end + +------------------------------------------------------------------------------------------------------------- +-- +-- End +-- +-------------------------------------------------------------------------------------------------------------