From 8bf56b8b1a1977c2112627388e4d4fdbcf2c7585 Mon Sep 17 00:00:00 2001 From: Frank Date: Wed, 26 Jul 2023 16:36:44 +0200 Subject: [PATCH 01/16] Update Airboss.lua - Fixed AI handling (got lost in some merge with develop branch and was using FLIGHTGROUPS) --- Moose Development/Moose/Ops/Airboss.lua | 61 ++++++++++++++++++++----- 1 file changed, 49 insertions(+), 12 deletions(-) diff --git a/Moose Development/Moose/Ops/Airboss.lua b/Moose Development/Moose/Ops/Airboss.lua index 6a0a032d5..2a17e4c13 100644 --- a/Moose Development/Moose/Ops/Airboss.lua +++ b/Moose Development/Moose/Ops/Airboss.lua @@ -5822,27 +5822,64 @@ function AIRBOSS:_ScanCarrierZone() -- Get aircraft type name. local actype = group:GetTypeName() - -- Create a new flight group if knownflight then + -- Debug output. + self:T2(self.lid..string.format("Known flight group %s of type %s in CCA.", groupname, actype)) + -- Check if flight is AI and if we want to handle it at all. - if knownflight.ai and knownflight.flag == -100 and self.handleai and false then --Disabled AI handling because of incorrect OPSGROUP reference! + if knownflight.ai and self.handleai then - local putintomarshal = false + -- Defines if AI group should be handled by the airboss. + local iscarriersquad=true - -- Get flight group. - local flight = _DATABASE:GetOpsGroup( groupname ) - - if flight and flight:IsInbound() and flight.destbase:GetName() == self.carrier:GetName() then - if flight.ishelo then + -- Check if AI group is part of the group set if a set was defined. + if self.squadsetAI then + local group=self.squadsetAI:FindGroup(groupname) + if group then + iscarriersquad=true else - putintomarshal = true + iscarriersquad=false end - flight.airboss = self end - -- Send AI flight to marshal stack. - if putintomarshal then + -- Check if group was explicitly excluded. + if self.excludesetAI then + local group=self.excludesetAI:FindGroup(groupname) + if group then + iscarriersquad=false + end + + end + + + -- Get distance to carrier. + local dist=knownflight.group:GetCoordinate():Get2DDistance(self:GetCoordinate()) + + -- Close in distance. Is >0 if AC comes closer wrt to first detected distance d0. + local closein=knownflight.dist0-dist + + -- Debug info. + self:T3(self.lid..string.format("Known AI flight group %s closed in by %.1f NM", knownflight.groupname, UTILS.MetersToNM(closein))) + + -- Is this group the tanker? + local istanker=self.tanker and self.tanker.tanker:GetName()==groupname + + -- Is this group the AWACS? + local isawacs=self.awacs and self.awacs.tanker:GetName()==groupname + + -- Send tanker to marshal stack? + local tanker2marshal = istanker and self.tanker:IsReturning() and self.tanker.airbase:GetName()==self.airbase:GetName() and knownflight.flag==-100 and self.tanker.recovery==true + + -- Send AWACS to marhsal stack? + local awacs2marshal = isawacs and self.awacs:IsReturning() and self.awacs.airbase:GetName()==self.airbase:GetName() and knownflight.flag==-100 and self.awacs.recovery==true + + -- Put flight into Marshal. + local putintomarshal=closein>UTILS.NMToMeters(5) and knownflight.flag==-100 and iscarriersquad and istanker==false and isawacs==false + + -- Send AI flight to marshal stack if group closes in more than 5 and has initial flag value. + if putintomarshal or tanker2marshal or awacs2marshal then + -- Get the next free stack for current recovery case. local stack = self:_GetFreeStack( knownflight.ai ) From 80e9cb692cb758373ca551b7aa776e491e627f07 Mon Sep 17 00:00:00 2001 From: phr0gz Date: Sat, 29 Jul 2023 13:37:07 +0200 Subject: [PATCH 02/16] Add FSM OnAfter and OnBefore (#1974) Add FSM Function OnAfter and OnBefore in FlightGroup. --- Moose Development/Moose/Ops/FlightGroup.lua | 317 +++++++++++++++++++- 1 file changed, 316 insertions(+), 1 deletion(-) diff --git a/Moose Development/Moose/Ops/FlightGroup.lua b/Moose Development/Moose/Ops/FlightGroup.lua index e4554330e..46cd5f2d6 100644 --- a/Moose Development/Moose/Ops/FlightGroup.lua +++ b/Moose Development/Moose/Ops/FlightGroup.lua @@ -325,7 +325,322 @@ function FLIGHTGROUP:New(group) -- @param #FLIGHTGROUP self -- @param #number delay Delay in seconds. - -- TODO: Add pseudo functions. + --- FSM Function OnAfterElementSpawned. + -- @function [parent=#FLIGHTGROUP] OnAfterElementSpawned + -- @param #FLIGHTGROUP self + -- @param #string From From state. + -- @param #string Event Event. + -- @param #string To To state. + -- @param Ops.OpsGroup#OPSGROUP.Element Element The flight group element. + + --- FSM Function OnAfterElementParking. + -- @function [parent=#FLIGHTGROUP] OnAfterElementParking + -- @param #FLIGHTGROUP self + -- @param #string From From state. + -- @param #string Event Event. + -- @param #string To To state. + -- @param Ops.OpsGroup#OPSGROUP.Element Element The flight group element. + -- @param Wrapper.Airbase#AIRBASE.ParkingSpot Spot Parking Spot. + + --- FSM Function OnAfterElementEngineOn. + -- @function [parent=#FLIGHTGROUP] OnAfterElementEngineOn + -- @param #FLIGHTGROUP self + -- @param #string From From state. + -- @param #string Event Event. + -- @param #string To To state. + -- @param Ops.OpsGroup#OPSGROUP.Element Element The flight group element. + + --- FSM Function OnAfterElementTaxiing. + -- @function [parent=#FLIGHTGROUP] OnAfterElementTaxiing + -- @param #FLIGHTGROUP self + -- @param #string From From state. + -- @param #string Event Event. + -- @param #string To To state. + -- @param Ops.OpsGroup#OPSGROUP.Element Element The flight group element. + + --- FSM Function OnAfterElementTakeoff. + -- @function [parent=#FLIGHTGROUP] OnAfterElementTakeoff + -- @param #FLIGHTGROUP self + -- @param #string From From state. + -- @param #string Event Event. + -- @param #string To To state. + -- @param Ops.OpsGroup#OPSGROUP.Element Element The flight group element. + -- @param Wrapper.Airbase#AIRBASE airbase The airbase if applicable or nil. + + --- FSM Function OnAfterElementAirborne. + -- @function [parent=#FLIGHTGROUP] OnAfterElementAirborne + -- @param #FLIGHTGROUP self + -- @param #string From From state. + -- @param #string Event Event. + -- @param #string To To state. + -- @param Ops.OpsGroup#OPSGROUP.Element Element The flight group element. + + --- FSM Function OnAfterElementLanded. + -- @function [parent=#FLIGHTGROUP] OnAfterElementLanded + -- @param #FLIGHTGROUP self + -- @param #string From From state. + -- @param #string Event Event. + -- @param #string To To state. + -- @param Ops.OpsGroup#OPSGROUP.Element Element The flight group element. + -- @param Wrapper.Airbase#AIRBASE airbase The airbase if applicable or nil. + + --- FSM Function OnAfterElementArrived. + -- @function [parent=#FLIGHTGROUP] OnAfterElementArrived + -- @param #FLIGHTGROUP self + -- @param #string From From state. + -- @param #string Event Event. + -- @param #string To To state. + -- @param Ops.OpsGroup#OPSGROUP.Element Element The flight group element. + -- @param Wrapper.Airbase#AIRBASE airbase The airbase, where the element arrived. + -- @param Wrapper.Airbase#AIRBASE.ParkingSpot Parking The Parking spot the element has. + + --- FSM Function OnAfterElementDestroyed. + -- @function [parent=#FLIGHTGROUP] OnAfterElementDestroyed + -- @param #FLIGHTGROUP self + -- @param #string From From state. + -- @param #string Event Event. + -- @param #string To To state. + -- @param Ops.OpsGroup#OPSGROUP.Element Element The flight group element. + + --- FSM Function OnAfterElementDead. + -- @function [parent=#FLIGHTGROUP] OnAfterElementDead + -- @param #FLIGHTGROUP self + -- @param #string From From state. + -- @param #string Event Event. + -- @param #string To To state. + -- @param Ops.OpsGroup#OPSGROUP.Element Element The flight group element. + + --- FSM Function OnAfterSpawned. + -- @function [parent=#FLIGHTGROUP] OnAfterSpawned + -- @param #FLIGHTGROUP self + -- @param #string From From state. + -- @param #string Event Event. + -- @param #string To To state. + + --- FSM Function OnAfterParking. + -- @function [parent=#FLIGHTGROUP] OnAfterParking + -- @param #FLIGHTGROUP self + -- @param #string From From state. + -- @param #string Event Event. + -- @param #string To To state. + + --- FSM Function OnAfterTaxiing. + -- @function [parent=#FLIGHTGROUP] OnAfterTaxiing + -- @param #FLIGHTGROUP self + -- @param #string From From state. + -- @param #string Event Event. + -- @param #string To To state. + + --- FSM Function OnAfterTakeoff. + -- @function [parent=#FLIGHTGROUP] OnAfterTakeoff + -- @param #FLIGHTGROUP self + -- @param #string From From state. + -- @param #string Event Event. + -- @param #string To To state. + + --- FSM Function OnAfterAirborne. + -- @function [parent=#FLIGHTGROUP] OnAfterAirborne + -- @param #FLIGHTGROUP self + -- @param #string From From state. + -- @param #string Event Event. + -- @param #string To To state. + + --- FSM Function OnAfterCruise. + -- @function [parent=#FLIGHTGROUP] OnAfterCruise + -- @param #FLIGHTGROUP self + -- @param #string From From state. + -- @param #string Event Event. + -- @param #string To To state. + + --- FSM Function OnAfterLanding. + -- @function [parent=#FLIGHTGROUP] OnAfterLanding + -- @param #FLIGHTGROUP self + -- @param #string From From state. + -- @param #string Event Event. + -- @param #string To To state. + + --- FSM Function OnAfterLanded. + -- @function [parent=#FLIGHTGROUP] OnAfterLanded + -- @param #FLIGHTGROUP self + -- @param #string From From state. + -- @param #string Event Event. + -- @param #string To To state. + -- @param Wrapper.Airbase#AIRBASE airbase The airbase the flight landed. + + --- FSM Function OnAfterLandedAt. + -- @function [parent=#FLIGHTGROUP] OnAfterLandedAt + -- @param #FLIGHTGROUP self + -- @param #string From From state. + -- @param #string Event Event. + -- @param #string To To state. + + --- FSM Function OnAfterArrived. + -- @function [parent=#FLIGHTGROUP] OnAfterArrived + -- @param #FLIGHTGROUP self + -- @param #string From From state. + -- @param #string Event Event. + -- @param #string To To state. + + --- FSM Function OnAfterDead. + -- @function [parent=#FLIGHTGROUP] OnAfterDead + -- @param #FLIGHTGROUP self + -- @param #string From From state. + -- @param #string Event Event. + -- @param #string To To state. + + --- FSM Function OnAfterUpdateRoute. + -- @function [parent=#FLIGHTGROUP] OnAfterUpdateRoute + -- @param #FLIGHTGROUP self + -- @param #string From From state. + -- @param #string Event Event. + -- @param #string To To state. + -- @param #number n Next waypoint index. Default is the one coming after that one that has been passed last. + -- @param #number N Waypoint Max waypoint index to be included in the route. Default is the final waypoint. + + --- FSM Function OnAfterOutOfMissilesAA. + -- @function [parent=#FLIGHTGROUP] OnAfterOutOfMissilesAA + -- @param #FLIGHTGROUP self + -- @param #string From From state. + -- @param #string Event Event. + -- @param #string To To state. + + --- FSM Function OnAfterOutOfMissilesAG. + -- @function [parent=#FLIGHTGROUP] OnAfterOutOfMissilesAG + -- @param #FLIGHTGROUP self + -- @param #string From From state. + -- @param #string Event Event. + -- @param #string To To state. + + --- FSM Function OnAfterRTB. + -- @function [parent=#FLIGHTGROUP] OnAfterRTB + -- @param #FLIGHTGROUP self + -- @param #string From From state. + -- @param #string Event Event. + -- @param #string To To state. + -- @param Wrapper.Airbase#AIRBASE airbase The airbase to hold at. + -- @param #number SpeedTo Speed used for traveling from current position to holding point in knots. Default 75% of max speed. + -- @param #number SpeedHold Holding speed in knots. Default 250 kts. + -- @param #number SpeedLand Landing speed in knots. Default 170 kts. + + --- FSM Function OnAfterLandAtAirbase. + -- @function [parent=#FLIGHTGROUP] OnAfterLandAtAirbase + -- @param #FLIGHTGROUP self + -- @param #string From From state. + -- @param #string Event Event. + -- @param #string To To state. + -- @param Wrapper.Airbase#AIRBASE airbase The airbase to hold at. + + --- FSM Function OnAfterWait. + -- @function [parent=#FLIGHTGROUP] OnAfterWait + -- @param #FLIGHTGROUP self + -- @param #string From From state. + -- @param #string Event Event. + -- @param #string To To state. + -- @param #number Duration Duration how long the group will be waiting in seconds. Default `nil` (=forever). + -- @param #number Altitude Altitude in feet. Default 10,000 ft for airplanes and 1,000 feet for helos. + -- @param #number Speed Speed in knots. Default 250 kts for airplanes and 20 kts for helos. + + --- FSM Function OnAfterRefuel. + -- @function [parent=#FLIGHTGROUP] OnAfterRefuel + -- @param #FLIGHTGROUP self + -- @param #string From From state. + -- @param #string Event Event. + -- @param #string To To state. + -- @param Core.Point#COORDINATE Coordinate The coordinate. + + --- FSM Function OnAfterRefueled. + -- @function [parent=#FLIGHTGROUP] OnAfterRefueled + -- @param #FLIGHTGROUP self + -- @param #string From From state. + -- @param #string Event Event. + -- @param #string To To state. + + --- FSM Function OnAfterDisengage. + -- @function [parent=#FLIGHTGROUP] OnAfterDisengage + -- @param #FLIGHTGROUP self + -- @param #string From From state. + -- @param #string Event Event. + -- @param #string To To state. + -- @param Core.Set#SET_UNIT TargetUnitSet + + --- FSM Function OnAfterEngageTarget. + -- @function [parent=#FLIGHTGROUP] OnAfterEngageTarget + -- @param #FLIGHTGROUP self + -- @param #string From From state. + -- @param #string Event Event. + -- @param #string To To state. + -- @param #table Target Target object. Can be a UNIT, STATIC, GROUP, SET_UNIT or SET_GROUP object. + + --- FSM Function OnAfterLandAt. + -- @function [parent=#FLIGHTGROUP] OnAfterLandAt + -- @param #FLIGHTGROUP self + -- @param #string From From state. + -- @param #string Event Event. + -- @param #string To To state. + -- @param Core.Set#SET_UNIT TargetUnitSet + + --- FSM Function OnAfterFuelLow. + -- @function [parent=#FLIGHTGROUP] OnAfterFuelLow + -- @param #FLIGHTGROUP self + -- @param #string From From state. + -- @param #string Event Event. + -- @param #string To To state. + + --- FSM Function OnAfterFuelCritical. + -- @function [parent=#FLIGHTGROUP] OnAfterFuelCritical + -- @param #FLIGHTGROUP self + -- @param #string From From state. + -- @param #string Event Event. + -- @param #string To To state. + + --- FSM Function OnBeforeUpdateRoute. + -- @function [parent=#FLIGHTGROUP] OnBeforeUpdateRoute + -- @param #FLIGHTGROUP self + -- @param #string From From state. + -- @param #string Event Event. + -- @param #string To To state. + -- @param #number n Next waypoint index. Default is the one coming after that one that has been passed last. + -- @param #number N Waypoint Max waypoint index to be included in the route. Default is the final waypoint. + -- @return #boolean Transision allowed? + + --- FSM Function OnBeforeRTB. + -- @function [parent=#FLIGHTGROUP] OnBeforeRTB + -- @param #FLIGHTGROUP self + -- @param #string From From state. + -- @param #string Event Event. + -- @param #string To To state. + -- @param Wrapper.Airbase#AIRBASE airbase The airbase to hold at. + -- @param #number SpeedTo Speed used for travelling from current position to holding point in knots. + -- @param #number SpeedHold Holding speed in knots. + + --- FSM Function OnBeforeLandAtAirbase. + -- @function [parent=#FLIGHTGROUP] OnBeforeLandAtAirbase + -- @param #FLIGHTGROUP self + -- @param #string From From state. + -- @param #string Event Event. + -- @param #string To To state. + -- @param Wrapper.Airbase#AIRBASE airbase The airbase to hold at. + + --- FSM Function OnBeforeWait. + -- @function [parent=#FLIGHTGROUP] OnBeforeWait + -- @param #FLIGHTGROUP self + -- @param #string From From state. + -- @param #string Event Event. + -- @param #string To To state. + -- @param #number Duration Duration how long the group will be waiting in seconds. Default `nil` (=forever). + -- @param #number Altitude Altitude in feet. Default 10,000 ft for airplanes and 1,000 feet for helos. + -- @param #number Speed Speed in knots. Default 250 kts for airplanes and 20 kts for helos. + + --- FSM Function OnBeforeLandAt. + -- @function [parent=#FLIGHTGROUP] OnBeforeLandAt + -- @param #FLIGHTGROUP self + -- @param #string From From state. + -- @param #string Event Event. + -- @param #string To To state. + -- @param Core.Point#COORDINATE Coordinate The coordinate where to land. Default is current position. + -- @param #number Duration The duration in seconds to remain on ground. Default 600 sec (10 min). + + -- TODO: Add pseudo functions ? Normally done, but should be double check -- Handle events: self:HandleEvent(EVENTS.Birth, self.OnEventBirth) From cbd371b40f89b150dec9e2922eae965810b47ea6 Mon Sep 17 00:00:00 2001 From: phr0gz Date: Sat, 29 Jul 2023 15:44:13 +0200 Subject: [PATCH 03/16] Chief zone removal Tanker, AWACS (#1975) Add the ability to remove a zone for Tanker and AWACS. --- Moose Development/Moose/Ops/Chief.lua | 21 ++++++++++++ Moose Development/Moose/Ops/Commander.lua | 40 +++++++++++++++++++++++ 2 files changed, 61 insertions(+) diff --git a/Moose Development/Moose/Ops/Chief.lua b/Moose Development/Moose/Ops/Chief.lua index 0272ec659..503cbfc2b 100644 --- a/Moose Development/Moose/Ops/Chief.lua +++ b/Moose Development/Moose/Ops/Chief.lua @@ -1501,6 +1501,17 @@ function CHIEF:AddAwacsZone(Zone, Altitude, Speed, Heading, Leg) return zone end +--- Remove a AWACS zone. +-- @param #CHIEF self +-- @param Core.Zone#ZONE Zone Zone, where the flight orbits. +function CHIEF:RemoveAwacsZone(Zone) + + -- Hand over to commander. + local zone=self.commander:RemoveAwacsZone(Zone) + + return zone +end + --- Add a refuelling tanker zone. -- @param #CHIEF self -- @param Core.Zone#ZONE Zone Zone. @@ -1518,6 +1529,16 @@ function CHIEF:AddTankerZone(Zone, Altitude, Speed, Heading, Leg, RefuelSystem) return zone end +--- Remove a refuelling tanker zone. +-- @param #CHIEF self +-- @param Core.Zone#ZONE Zone Zone, where the flight orbits. +function CHIEF:RemoveTankerZone(Zone) + + -- Hand over to commander. + local zone=self.commander:RemoveTankerZone(Zone) + + return zone +end --- Set border zone set, defining your territory. -- diff --git a/Moose Development/Moose/Ops/Commander.lua b/Moose Development/Moose/Ops/Commander.lua index 0af40ed2d..b0bd1673e 100644 --- a/Moose Development/Moose/Ops/Commander.lua +++ b/Moose Development/Moose/Ops/Commander.lua @@ -735,6 +735,26 @@ function COMMANDER:AddAwacsZone(Zone, Altitude, Speed, Heading, Leg) return awacszone end +--- Remove a AWACS zone. +-- @param #COMMANDER self +-- @param Core.Zone#ZONE Zone Zone, where the flight orbits. +function COMMANDER:RemoveAwacsZone(Zone) + + local awacszone={} --Ops.AirWing#AIRWING.PatrolZone + + awacszone.zone=Zone + for i,_awacszone in pairs(self.awacsZones) do + if _awacszone.zone == awacszone.zone then + if _awacszone.mission and _awacszone.mission:IsNotOver() then + _awacszone.mission:Cancel() + end + table.remove(self.awacsZones, i) + break + end + end + return awacszone +end + --- Add a refuelling tanker zone. -- @param #COMMANDER self -- @param Core.Zone#ZONE Zone Zone. @@ -762,6 +782,26 @@ function COMMANDER:AddTankerZone(Zone, Altitude, Speed, Heading, Leg, RefuelSyst return tankerzone end +--- Remove a refuelling tanker zone. +-- @param #COMMANDER self +-- @param Core.Zone#ZONE Zone Zone, where the flight orbits. +function COMMANDER:RemoveTankerZone(Zone) + + local tankerzone={} --Ops.AirWing#AIRWING.PatrolZone + + tankerzone.zone=Zone + for i,_tankerzone in pairs(self.tankerZones) do + if _tankerzone.zone == tankerzone.zone then + if _tankerzone.mission and _tankerzone.mission:IsNotOver() then + _tankerzone.mission:Cancel() + end + table.remove(self.tankerZones, i) + break + end + end + return tankerzone +end + --- Check if this mission is already in the queue. -- @param #COMMANDER self -- @param Ops.Auftrag#AUFTRAG Mission The mission. From 4ed2b0610d90e63fcf5f80557ceeabb28a3dd2ce Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Sat, 29 Jul 2023 16:44:25 +0200 Subject: [PATCH 04/16] #AWACS * ensure tactical frequencies are handed back #PlayerTask * Add'l check for stale tasks to rebuild menu --- Moose Development/Moose/Ops/Awacs.lua | 19 +++++++++++++++ Moose Development/Moose/Ops/PlayerTask.lua | 28 ++++++++++++++++++---- 2 files changed, 42 insertions(+), 5 deletions(-) diff --git a/Moose Development/Moose/Ops/Awacs.lua b/Moose Development/Moose/Ops/Awacs.lua index 3c04848a3..d4e58c12c 100644 --- a/Moose Development/Moose/Ops/Awacs.lua +++ b/Moose Development/Moose/Ops/Awacs.lua @@ -1517,6 +1517,23 @@ function AWACS:_SubScribeTactRadio(Group,Frequency) return self end +--- [Internal] _CheckSubscribers +-- @param #AWACS self +-- @return #AWACS self +function AWACS:_CheckSubscribers() + self:T(self.lid.."_InitLocalization") + + for _name,_freq in pairs(self.TacticalSubscribers or {}) do + local grp = GROUP:FindByName(_name) + if (not grp) or (not grp:IsAlive()) then + self.TacticalFrequencies[_freq] = _freq + self.TacticalSubscribers[_name] = nil + end + end + + return self +end + --- [Internal] Init localization -- @param #AWACS self -- @return #AWACS self @@ -6180,6 +6197,8 @@ function AWACS:onafterStatus(From, Event, To) self:_CheckMerges() + self:_CheckSubscribers() + local outcome, targets = self:_TargetSelectionProcess(true) self:_CheckTaskQueue() diff --git a/Moose Development/Moose/Ops/PlayerTask.lua b/Moose Development/Moose/Ops/PlayerTask.lua index d44e9c644..b589bdd63 100644 --- a/Moose Development/Moose/Ops/PlayerTask.lua +++ b/Moose Development/Moose/Ops/PlayerTask.lua @@ -98,7 +98,7 @@ PLAYERTASK = { --- PLAYERTASK class version. -- @field #string version -PLAYERTASK.version="0.1.18" +PLAYERTASK.version="0.1.19" --- Generic task condition. -- @type PLAYERTASK.Condition @@ -2483,6 +2483,15 @@ function PLAYERTASKCONTROLLER:_CheckTaskQueue() self:T("*****Removing player " .. _id) self.TasksPerPlayer:PullByID(_id) end + local clients=task:GetClientObjects() + for _,client in pairs(clients) do + self:_RemoveMenuEntriesForTask(task,client) + --self:_SwitchMenuForClient(client,"Info") + end + for _,client in pairs(clients) do + -- self:_RemoveMenuEntriesForTask(Task,client) + self:_SwitchMenuForClient(client,"Info",5) + end -- Follow-up tasks? local nexttasks = {} if task.FinalState == "Success" then @@ -3594,28 +3603,28 @@ function PLAYERTASKCONTROLLER:_RemoveMenuEntriesForTask(Task,Client) if Task then if Task.UUIDS and self.JoinTaskMenuTemplate then --self:I("***** JoinTaskMenuTemplate") - UTILS.PrintTableToLog(Task.UUIDS) + --UTILS.PrintTableToLog(Task.UUIDS) local controller = self.JoinTaskMenuTemplate for _,_uuid in pairs(Task.UUIDS) do local Entry = controller:FindEntryByUUID(_uuid) if Entry then controller:DeleteF10Entry(Entry,Client) controller:DeleteGenericEntry(Entry) - UTILS.PrintTableToLog(controller.menutree) + --UTILS.PrintTableToLog(controller.menutree) end end end if Task.AUUIDS and self.ActiveTaskMenuTemplate then --self:I("***** ActiveTaskMenuTemplate") - UTILS.PrintTableToLog(Task.AUUIDS) + --UTILS.PrintTableToLog(Task.AUUIDS) for _,_uuid in pairs(Task.AUUIDS) do local controller = self.ActiveTaskMenuTemplate local Entry = controller:FindEntryByUUID(_uuid) if Entry then controller:DeleteF10Entry(Entry,Client) controller:DeleteGenericEntry(Entry) - UTILS.PrintTableToLog(controller.menutree) + --UTILS.PrintTableToLog(controller.menutree) end end end @@ -4210,6 +4219,15 @@ function PLAYERTASKCONTROLLER:onafterTaskFailed(From, Event, To, Task) taskname = string.format(failtxttts, self.MenuName or self.Name, Task.PlayerTaskNr, tostring(Task.TTSType)) self.SRSQueue:NewTransmission(taskname,nil,self.SRS,nil,2) end + local clients=Task:GetClientObjects() + for _,client in pairs(clients) do + self:_RemoveMenuEntriesForTask(Task,client) + --self:_SwitchMenuForClient(client,"Info") + end + for _,client in pairs(clients) do + -- self:_RemoveMenuEntriesForTask(Task,client) + self:_SwitchMenuForClient(client,"Info",5) + end return self end From f87a676e4bfb84757367655e8fd307c688fb5b32 Mon Sep 17 00:00:00 2001 From: Thomas <72444570+Applevangelist@users.noreply.github.com> Date: Sat, 29 Jul 2023 16:45:00 +0200 Subject: [PATCH 05/16] Update Scoring.lua (#1976) Add report Spaces --- Moose Development/Moose/Functional/Scoring.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Moose Development/Moose/Functional/Scoring.lua b/Moose Development/Moose/Functional/Scoring.lua index 3d0c56b9f..ec95dc8a3 100644 --- a/Moose Development/Moose/Functional/Scoring.lua +++ b/Moose Development/Moose/Functional/Scoring.lua @@ -1420,7 +1420,7 @@ function SCORING:ReportDetailedPlayerHits( PlayerName ) Penalty = Penalty + UnitData.Penalty PenaltyHit = UnitData.PenaltyHit end - local ScoreMessageHit = string.format( "%s:%d ", CategoryName, Score - Penalty ) + local ScoreMessageHit = string.format( "%s: %d ", CategoryName, Score - Penalty ) self:T( ScoreMessageHit ) ScoreMessageHits = ScoreMessageHits .. ScoreMessageHit PlayerScore = PlayerScore + Score @@ -1476,7 +1476,7 @@ function SCORING:ReportDetailedPlayerDestroys( PlayerName ) end end - local ScoreMessageDestroy = string.format( " %s:%d ", CategoryName, Score - Penalty ) + local ScoreMessageDestroy = string.format( " %s: %d ", CategoryName, Score - Penalty ) self:T( ScoreMessageDestroy ) ScoreMessageDestroys = ScoreMessageDestroys .. ScoreMessageDestroy From 65703d1092f679da072b47fa0711e4d51855a278 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Sat, 29 Jul 2023 17:19:51 +0200 Subject: [PATCH 06/16] Debugs --- Moose Development/Moose/Ops/Awacs.lua | 2 +- Moose Development/Moose/Ops/PlayerTask.lua | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Moose Development/Moose/Ops/Awacs.lua b/Moose Development/Moose/Ops/Awacs.lua index d4e58c12c..5bff6cc86 100644 --- a/Moose Development/Moose/Ops/Awacs.lua +++ b/Moose Development/Moose/Ops/Awacs.lua @@ -1613,7 +1613,7 @@ function AWACS:_NewRadioEntry(TextTTS, TextScreen,GID,IsGroup,ToScreen,IsNew,Fro local RadioEntry = {} -- #AWACS.RadioEntry RadioEntry.IsNew = IsNew RadioEntry.TextTTS = TextTTS - RadioEntry.TextScreen = TextScreen + RadioEntry.TextScreen = TextScreen or TextTTS RadioEntry.GroupID = GID RadioEntry.ToScreen = ToScreen RadioEntry.Duration = STTS.getSpeechTime(TextTTS,0.95,false) or 8 diff --git a/Moose Development/Moose/Ops/PlayerTask.lua b/Moose Development/Moose/Ops/PlayerTask.lua index b589bdd63..848732a32 100644 --- a/Moose Development/Moose/Ops/PlayerTask.lua +++ b/Moose Development/Moose/Ops/PlayerTask.lua @@ -2177,7 +2177,7 @@ end -- @return #PLAYERTASKCONTROLLER self function PLAYERTASKCONTROLLER:_EventHandler(EventData) self:T(self.lid.."_EventHandler: "..EventData.id) - self:T(self.lid.."_EventHandler: "..EventData.IniPlayerName) + --self:T(self.lid.."_EventHandler: "..EventData.IniPlayerName) if EventData.id == EVENTS.PlayerLeaveUnit or EventData.id == EVENTS.Ejection or EventData.id == EVENTS.Crash or EventData.id == EVENTS.PilotDead then if EventData.IniPlayerName then self:T(self.lid.."Event for player: "..EventData.IniPlayerName) From 09d4e155ded1d79140d4ea97263f15ea5c3589c3 Mon Sep 17 00:00:00 2001 From: Thomas <72444570+Applevangelist@users.noreply.github.com> Date: Mon, 31 Jul 2023 14:24:47 +0200 Subject: [PATCH 07/16] Update PlayerTask.lua (#1977) Prevent Events being available before the menu structure has been created --- Moose Development/Moose/Ops/PlayerTask.lua | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/Moose Development/Moose/Ops/PlayerTask.lua b/Moose Development/Moose/Ops/PlayerTask.lua index 848732a32..cdc693a33 100644 --- a/Moose Development/Moose/Ops/PlayerTask.lua +++ b/Moose Development/Moose/Ops/PlayerTask.lua @@ -1656,13 +1656,6 @@ function PLAYERTASKCONTROLLER:New(Name, Coalition, Type, ClientFilter) local starttime = math.random(5,10) self:__Status(starttime) - -- Player leaves - self:HandleEvent(EVENTS.PlayerLeaveUnit, self._EventHandler) - self:HandleEvent(EVENTS.Ejection, self._EventHandler) - self:HandleEvent(EVENTS.Crash, self._EventHandler) - self:HandleEvent(EVENTS.PilotDead, self._EventHandler) - self:HandleEvent(EVENTS.PlayerEnterAircraft, self._EventHandler) - self:I(self.lid..self.version.." Started.") return self @@ -4072,6 +4065,12 @@ function PLAYERTASKCONTROLLER:onafterStart(From, Event, To) self:T(self.lid.."onafterStart") self:_CreateJoinMenuTemplate() self:_CreateActiveTaskMenuTemplate() + -- Player Events + self:HandleEvent(EVENTS.PlayerLeaveUnit, self._EventHandler) + self:HandleEvent(EVENTS.Ejection, self._EventHandler) + self:HandleEvent(EVENTS.Crash, self._EventHandler) + self:HandleEvent(EVENTS.PilotDead, self._EventHandler) + self:HandleEvent(EVENTS.PlayerEnterAircraft, self._EventHandler) return self end From 56fcd8f37f839430acaed9aad85d37177349044a Mon Sep 17 00:00:00 2001 From: phr0gz Date: Tue, 1 Aug 2023 10:00:17 +0200 Subject: [PATCH 08/16] Add RemoveGciCapZone in Chief (#1973) This will add the ability to remove CGI CAP zone from chief. --- Moose Development/Moose/Ops/Chief.lua | 11 +++++++++++ Moose Development/Moose/Ops/Commander.lua | 20 ++++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/Moose Development/Moose/Ops/Chief.lua b/Moose Development/Moose/Ops/Chief.lua index 503cbfc2b..77477e0cc 100644 --- a/Moose Development/Moose/Ops/Chief.lua +++ b/Moose Development/Moose/Ops/Chief.lua @@ -1485,6 +1485,17 @@ function CHIEF:AddGciCapZone(Zone, Altitude, Speed, Heading, Leg) return zone end +--- Remove a GCI CAP +-- @param #CHIEF self +-- @param Core.Zone#ZONE Zone Zone, where the flight orbits. +function CHIEF:RemoveGciCapZone(Zone) + + -- Hand over to commander. + local zone=self.commander:RemoveGciCapZone(Zone) + + return zone +end + --- Add an AWACS zone. -- @param #CHIEF self -- @param Core.Zone#ZONE Zone Zone. diff --git a/Moose Development/Moose/Ops/Commander.lua b/Moose Development/Moose/Ops/Commander.lua index b0bd1673e..378df6007 100644 --- a/Moose Development/Moose/Ops/Commander.lua +++ b/Moose Development/Moose/Ops/Commander.lua @@ -710,6 +710,26 @@ function COMMANDER:AddGciCapZone(Zone, Altitude, Speed, Heading, Leg) return patrolzone end +--- Remove a GCI CAP. +-- @param #COMMANDER self +-- @param Core.Zone#ZONE Zone Zone, where the flight orbits. +function COMMANDER:RemoveGciCapZone(Zone) + + local patrolzone={} --Ops.AirWing#AIRWING.PatrolZone + + patrolzone.zone=Zone + for i,_patrolzone in pairs(self.gcicapZones) do + if _patrolzone.zone == patrolzone.zone then + if _patrolzone.mission and _patrolzone.mission:IsNotOver() then + _patrolzone.mission:Cancel() + end + table.remove(self.gcicapZones, i) + break + end + end + return patrolzone +end + --- Add an AWACS zone. -- @param #COMMANDER self -- @param Core.Zone#ZONE Zone Zone. From 1fdc50b0dae7620fcfbe43ba8a548bc697786e87 Mon Sep 17 00:00:00 2001 From: Thomas <72444570+Applevangelist@users.noreply.github.com> Date: Tue, 1 Aug 2023 10:00:42 +0200 Subject: [PATCH 09/16] Update Scenery.lua (#1980) _id might be nil in :FindByZoneName() --- Moose Development/Moose/Wrapper/Scenery.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Moose Development/Moose/Wrapper/Scenery.lua b/Moose Development/Moose/Wrapper/Scenery.lua index 6a6f70bd9..24dc45fd6 100644 --- a/Moose Development/Moose/Wrapper/Scenery.lua +++ b/Moose Development/Moose/Wrapper/Scenery.lua @@ -178,7 +178,7 @@ function SCENERY:FindByZoneName( ZoneName ) zone = ZONE:FindByName(ZoneName) end local _id = zone:GetProperty('OBJECT ID') - BASE:T("Object ID ".._id) + --BASE:T("Object ID ".._id) if not _id then -- this zone has no object ID BASE:E("**** Zone without object ID: "..ZoneName.." | Type: "..tostring(zone.ClassName)) From 677a64c3dc0ea339f70feca7c27095879cf1bf79 Mon Sep 17 00:00:00 2001 From: Thomas <72444570+Applevangelist@users.noreply.github.com> Date: Tue, 1 Aug 2023 10:38:39 +0200 Subject: [PATCH 10/16] Update Scenery.lua (#1980) (#1981) _id might be nil in :FindByZoneName() --- Moose Development/Moose/Wrapper/Scenery.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Moose Development/Moose/Wrapper/Scenery.lua b/Moose Development/Moose/Wrapper/Scenery.lua index 6a6f70bd9..24dc45fd6 100644 --- a/Moose Development/Moose/Wrapper/Scenery.lua +++ b/Moose Development/Moose/Wrapper/Scenery.lua @@ -178,7 +178,7 @@ function SCENERY:FindByZoneName( ZoneName ) zone = ZONE:FindByName(ZoneName) end local _id = zone:GetProperty('OBJECT ID') - BASE:T("Object ID ".._id) + --BASE:T("Object ID ".._id) if not _id then -- this zone has no object ID BASE:E("**** Zone without object ID: "..ZoneName.." | Type: "..tostring(zone.ClassName)) From 7c4dd8160dd353bdffa6b8cdddfca06b1fa3b785 Mon Sep 17 00:00:00 2001 From: Thomas <72444570+Applevangelist@users.noreply.github.com> Date: Tue, 1 Aug 2023 11:53:00 +0200 Subject: [PATCH 11/16] Update Set.lua (#1982) Intellisense updates --- Moose Development/Moose/Core/Set.lua | 206 ++++++++++++++------------- 1 file changed, 110 insertions(+), 96 deletions(-) diff --git a/Moose Development/Moose/Core/Set.lua b/Moose Development/Moose/Core/Set.lua index 2ba9d95ac..e3cd263c4 100644 --- a/Moose Development/Moose/Core/Set.lua +++ b/Moose Development/Moose/Core/Set.lua @@ -46,8 +46,9 @@ -- @image Core_Sets.JPG do -- SET_BASE - - --- @type SET_BASE + + --- + -- @type SET_BASE -- @field #table Filter Table of filters. -- @field #table Set Table of objects. -- @field #table Index Table of indices. @@ -578,8 +579,8 @@ do -- SET_BASE end ----- Private method that registers all alive players in the mission. - ---- @param #SET_BASE self - ---- @return #SET_BASE self + -- @param #SET_BASE self + -- @return #SET_BASE self -- function SET_BASE:_RegisterPlayers() -- -- local CoalitionsData = { AlivePlayersRed = coalition.getPlayers( coalition.side.RED ), AlivePlayersBlue = coalition.getPlayers( coalition.side.BLUE ) } @@ -796,8 +797,8 @@ do -- SET_BASE ----- Iterate the SET_BASE and call an iterator function for each **alive** unit, providing the Unit and optional parameters. - ---- @param #SET_BASE self - ---- @param #function IteratorFunction The function that will be called when there is an alive unit in the SET_BASE. The function needs to accept a UNIT parameter. + -- @param #SET_BASE self + -- @param #function IteratorFunction The function that will be called when there is an alive unit in the SET_BASE. The function needs to accept a UNIT parameter. ---- @return #SET_BASE self -- function SET_BASE:ForEachDCSUnitAlive( IteratorFunction, ... ) -- self:F3( arg ) @@ -808,8 +809,8 @@ do -- SET_BASE -- end -- ----- Iterate the SET_BASE and call an iterator function for each **alive** player, providing the Unit of the player and optional parameters. - ---- @param #SET_BASE self - ---- @param #function IteratorFunction The function that will be called when there is an alive player in the SET_BASE. The function needs to accept a UNIT parameter. + -- @param #SET_BASE self + -- @param #function IteratorFunction The function that will be called when there is an alive player in the SET_BASE. The function needs to accept a UNIT parameter. ---- @return #SET_BASE self -- function SET_BASE:ForEachPlayer( IteratorFunction, ... ) -- self:F3( arg ) @@ -821,8 +822,8 @@ do -- SET_BASE -- -- ----- Iterate the SET_BASE and call an iterator function for each client, providing the Client to the function and optional parameters. - ---- @param #SET_BASE self - ---- @param #function IteratorFunction The function that will be called when there is an alive player in the SET_BASE. The function needs to accept a CLIENT parameter. + -- @param #SET_BASE self + -- @param #function IteratorFunction The function that will be called when there is an alive player in the SET_BASE. The function needs to accept a CLIENT parameter. ---- @return #SET_BASE self -- function SET_BASE:ForEachClient( IteratorFunction, ... ) -- self:F3( arg ) @@ -901,9 +902,12 @@ do -- SET_BASE end -do -- SET_GROUP +do - --- @type SET_GROUP #SET_GROUP + -- SET_GROUP + + --- + -- @type SET_GROUP #SET_GROUP -- @field Core.Timer#TIMER ZoneTimer -- @field #number ZoneTimerInterval -- @extends Core.Set#SET_BASE @@ -1568,7 +1572,7 @@ do -- SET_GROUP self:F2( arg ) self:ForEach( IteratorFunction, arg, self:GetSet(), - --- @param Core.Zone#ZONE_BASE ZoneObject + -- @param Core.Zone#ZONE_BASE ZoneObject -- @param Wrapper.Group#GROUP GroupObject function( ZoneObject, GroupObject ) if GroupObject:IsCompletelyInZone( ZoneObject ) then @@ -1590,7 +1594,7 @@ do -- SET_GROUP self:F2( arg ) self:ForEach( IteratorFunction, arg, self:GetSet(), - --- @param Core.Zone#ZONE_BASE ZoneObject + -- @param Core.Zone#ZONE_BASE ZoneObject -- @param Wrapper.Group#GROUP GroupObject function( ZoneObject, GroupObject ) if GroupObject:IsPartlyInZone( ZoneObject ) then @@ -1612,7 +1616,7 @@ do -- SET_GROUP self:F2( arg ) self:ForEach( IteratorFunction, arg, self:GetSet(), - --- @param Core.Zone#ZONE_BASE ZoneObject + -- @param Core.Zone#ZONE_BASE ZoneObject -- @param Wrapper.Group#GROUP GroupObject function( ZoneObject, GroupObject ) if GroupObject:IsNotInZone( ZoneObject ) then @@ -1659,7 +1663,7 @@ do -- SET_GROUP self:F2( arg ) self:ForEach( IteratorFunction, arg, self:GetSet(), - --- @param Core.Zone#ZONE_BASE ZoneObject + -- @param Core.Zone#ZONE_BASE ZoneObject -- @param Wrapper.Group#GROUP GroupObject function( ZoneObject, GroupObject ) if GroupObject:IsAnyInZone( ZoneObject ) then @@ -1857,8 +1861,8 @@ do -- SET_GROUP end ----- Iterate the SET_GROUP and call an iterator function for each **alive** player, providing the Group of the player and optional parameters. - ---- @param #SET_GROUP self - ---- @param #function IteratorFunction The function that will be called when there is an alive player in the SET_GROUP. The function needs to accept a GROUP parameter. + -- @param #SET_GROUP self + -- @param #function IteratorFunction The function that will be called when there is an alive player in the SET_GROUP. The function needs to accept a GROUP parameter. ---- @return #SET_GROUP self -- function SET_GROUP:ForEachPlayer( IteratorFunction, ... ) -- self:F2( arg ) @@ -1870,8 +1874,8 @@ do -- SET_GROUP -- -- ----- Iterate the SET_GROUP and call an iterator function for each client, providing the Client to the function and optional parameters. - ---- @param #SET_GROUP self - ---- @param #function IteratorFunction The function that will be called when there is an alive player in the SET_GROUP. The function needs to accept a CLIENT parameter. + -- @param #SET_GROUP self + -- @param #function IteratorFunction The function that will be called when there is an alive player in the SET_GROUP. The function needs to accept a CLIENT parameter. ---- @return #SET_GROUP self -- function SET_GROUP:ForEachClient( IteratorFunction, ... ) -- self:F2( arg ) @@ -2011,8 +2015,9 @@ do -- SET_GROUP end do -- SET_UNIT - - --- @type SET_UNIT + + --- + -- @type SET_UNIT -- @field Core.Timer#TIMER ZoneTimer -- @field #number ZoneTimerInterval -- @extends Core.Set#SET_BASE @@ -2672,7 +2677,7 @@ do -- SET_UNIT self:F2( arg ) self:ForEach( IteratorFunction, arg, self:GetSet(), - --- @param Core.Zone#ZONE_BASE ZoneObject + -- @param Core.Zone#ZONE_BASE ZoneObject -- @param Wrapper.Unit#UNIT UnitObject function( ZoneObject, UnitObject ) if UnitObject:IsInZone( ZoneObject ) then @@ -2694,7 +2699,7 @@ do -- SET_UNIT self:F2( arg ) self:ForEach( IteratorFunction, arg, self:GetSet(), - --- @param Core.Zone#ZONE_BASE ZoneObject + -- @param Core.Zone#ZONE_BASE ZoneObject -- @param Wrapper.Unit#UNIT UnitObject function( ZoneObject, UnitObject ) if UnitObject:IsNotInZone( ZoneObject ) then @@ -3011,8 +3016,8 @@ do -- SET_UNIT ----- Iterate the SET_UNIT and call an iterator function for each **alive** player, providing the Unit of the player and optional parameters. - ---- @param #SET_UNIT self - ---- @param #function IteratorFunction The function that will be called when there is an alive player in the SET_UNIT. The function needs to accept a UNIT parameter. + -- @param #SET_UNIT self + -- @param #function IteratorFunction The function that will be called when there is an alive player in the SET_UNIT. The function needs to accept a UNIT parameter. ---- @return #SET_UNIT self -- function SET_UNIT:ForEachPlayer( IteratorFunction, ... ) -- self:F2( arg ) @@ -3024,8 +3029,8 @@ do -- SET_UNIT -- -- ----- Iterate the SET_UNIT and call an iterator function for each client, providing the Client to the function and optional parameters. - ---- @param #SET_UNIT self - ---- @param #function IteratorFunction The function that will be called when there is an alive player in the SET_UNIT. The function needs to accept a CLIENT parameter. + -- @param #SET_UNIT self + -- @param #function IteratorFunction The function that will be called when there is an alive player in the SET_UNIT. The function needs to accept a CLIENT parameter. ---- @return #SET_UNIT self -- function SET_UNIT:ForEachClient( IteratorFunction, ... ) -- self:F2( arg ) @@ -3040,7 +3045,7 @@ do -- SET_UNIT -- @param Wrapper.Unit#UNIT MUnit -- @return #SET_UNIT self function SET_UNIT:IsIncludeObject( MUnit ) - self:F2( MUnit ) + self:F2( {MUnit} ) local MUnitInclude = false @@ -3191,8 +3196,9 @@ do -- SET_UNIT end do -- SET_STATIC - - --- @type SET_STATIC + + --- + -- @type SET_STATIC -- @extends Core.Set#SET_BASE --- Mission designers can use the SET_STATIC class to build sets of Statics belonging to certain: @@ -3612,7 +3618,7 @@ do -- SET_STATIC self:F2( arg ) self:ForEach( IteratorFunction, arg, self:GetSet(), - --- @param Core.Zone#ZONE_BASE ZoneObject + -- @param Core.Zone#ZONE_BASE ZoneObject -- @param Wrapper.Static#STATIC StaticObject function( ZoneObject, StaticObject ) if StaticObject:IsInZone( ZoneObject ) then @@ -3634,7 +3640,7 @@ do -- SET_STATIC self:F2( arg ) self:ForEach( IteratorFunction, arg, self:GetSet(), - --- @param Core.Zone#ZONE_BASE ZoneObject + -- @param Core.Zone#ZONE_BASE ZoneObject -- @param Wrapper.Static#STATIC StaticObject function( ZoneObject, StaticObject ) if StaticObject:IsNotInZone( ZoneObject ) then @@ -3945,8 +3951,9 @@ do -- SET_STATIC end do -- SET_CLIENT - - --- @type SET_CLIENT + + --- + -- @type SET_CLIENT -- @field Core.Timer#TIMER ZoneTimer -- @field #number ZoneTimerInterval -- @extends Core.Set#SET_BASE @@ -4008,8 +4015,8 @@ do -- SET_CLIENT Countries = nil, ClientPrefixes = nil, Zones = nil, - Playernames = nil, - Callsigns = nil, + Playernames = nil, + Callsigns = nil, }, FilterMeta = { Coalitions = { @@ -4059,7 +4066,7 @@ do -- SET_CLIENT --- Remove CLIENT(s) from SET_CLIENT. -- @param Core.Set#SET_CLIENT self - -- @param Wrapper.Client#CLIENT RemoveClientNames A single name or an array of CLIENT names. + -- @param Wrapper.Client#CLIENT RemoveClientNames A single object or an array of CLIENT objects. -- @return self function SET_CLIENT:RemoveClientsByName( RemoveClientNames ) @@ -4369,7 +4376,7 @@ do -- SET_CLIENT self:F2( arg ) self:ForEach( IteratorFunction, arg, self:GetSet(), - --- @param Core.Zone#ZONE_BASE ZoneObject + -- @param Core.Zone#ZONE_BASE ZoneObject -- @param Wrapper.Client#CLIENT ClientObject function( ZoneObject, ClientObject ) if ClientObject:IsInZone( ZoneObject ) then @@ -4391,7 +4398,7 @@ do -- SET_CLIENT self:F2( arg ) self:ForEach( IteratorFunction, arg, self:GetSet(), - --- @param Core.Zone#ZONE_BASE ZoneObject + -- @param Core.Zone#ZONE_BASE ZoneObject -- @param Wrapper.Client#CLIENT ClientObject function( ZoneObject, ClientObject ) if ClientObject:IsNotInZone( ZoneObject ) then @@ -4526,45 +4533,45 @@ do -- SET_CLIENT MClientInclude = MClientInclude and MClientPrefix end - if self.Filter.Zones then - local MClientZone = false - for ZoneName, Zone in pairs( self.Filter.Zones ) do - self:T3( "Zone:", ZoneName ) - local unit = MClient:GetClientGroupUnit() - if unit and unit:IsInZone(Zone) then - MClientZone = true - end - end - MClientInclude = MClientInclude and MClientZone - end - - if self.Filter.Playernames then - local MClientPlayername = false - local playername = MClient:GetPlayerName() or "Unknown" - --self:I(playername) - for _,_Playername in pairs(self.Filter.Playernames) do - if playername and string.find(playername,_Playername) then - MClientPlayername = true - end - end - self:T( { "Evaluated Playername", MClientPlayername } ) - MClientInclude = MClientInclude and MClientPlayername - end - - if self.Filter.Callsigns then - local MClientCallsigns = false - local callsign = MClient:GetCallsign() - --self:I(callsign) - for _,_Callsign in pairs(self.Filter.Callsigns) do - if callsign and string.find(callsign,_Callsign) then - MClientCallsigns = true - end - end - self:T( { "Evaluated Callsign", MClientCallsigns } ) - MClientInclude = MClientInclude and MClientCallsigns - end - - end + if self.Filter.Zones then + local MClientZone = false + for ZoneName, Zone in pairs( self.Filter.Zones ) do + self:T3( "Zone:", ZoneName ) + local unit = MClient:GetClientGroupUnit() + if unit and unit:IsInZone(Zone) then + MClientZone = true + end + end + MClientInclude = MClientInclude and MClientZone + end + + if self.Filter.Playernames then + local MClientPlayername = false + local playername = MClient:GetPlayerName() or "Unknown" + --self:I(playername) + for _,_Playername in pairs(self.Filter.Playernames) do + if playername and string.find(playername,_Playername) then + MClientPlayername = true + end + end + self:T( { "Evaluated Playername", MClientPlayername } ) + MClientInclude = MClientInclude and MClientPlayername + end + + if self.Filter.Callsigns then + local MClientCallsigns = false + local callsign = MClient:GetCallsign() + --self:I(callsign) + for _,_Callsign in pairs(self.Filter.Callsigns) do + if callsign and string.find(callsign,_Callsign) then + MClientCallsigns = true + end + end + self:T( { "Evaluated Callsign", MClientCallsigns } ) + MClientInclude = MClientInclude and MClientCallsigns + end + + end self:T2( MClientInclude ) return MClientInclude end @@ -4573,7 +4580,8 @@ end do -- SET_PLAYER - --- @type SET_PLAYER + --- + -- @type SET_PLAYER -- @extends Core.Set#SET_BASE --- Mission designers can use the @{Core.Set#SET_PLAYER} class to build sets of units belonging to alive players: @@ -4868,7 +4876,7 @@ do -- SET_PLAYER self:F2( arg ) self:ForEach( IteratorFunction, arg, self:GetSet(), - --- @param Core.Zone#ZONE_BASE ZoneObject + -- @param Core.Zone#ZONE_BASE ZoneObject -- @param Wrapper.Client#CLIENT ClientObject function( ZoneObject, ClientObject ) if ClientObject:IsInZone( ZoneObject ) then @@ -4890,7 +4898,7 @@ do -- SET_PLAYER self:F2( arg ) self:ForEach( IteratorFunction, arg, self:GetSet(), - --- @param Core.Zone#ZONE_BASE ZoneObject + -- @param Core.Zone#ZONE_BASE ZoneObject -- @param Wrapper.Client#CLIENT ClientObject function( ZoneObject, ClientObject ) if ClientObject:IsNotInZone( ZoneObject ) then @@ -4998,8 +5006,9 @@ do -- SET_PLAYER end do -- SET_AIRBASE - - --- @type SET_AIRBASE + + --- + -- @type SET_AIRBASE -- @extends Core.Set#SET_BASE --- Mission designers can use the @{Core.Set#SET_AIRBASE} class to build sets of airbases optionally belonging to certain: @@ -5341,8 +5350,9 @@ do -- SET_AIRBASE end do -- SET_CARGO - - --- @type 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: @@ -5767,8 +5777,9 @@ do -- SET_CARGO end do -- SET_ZONE - - --- @type SET_ZONE + + --- + -- @type SET_ZONE -- @extends Core.Set#SET_BASE --- Mission designers can use the @{Core.Set#SET_ZONE} class to build sets of zones of various types. @@ -6135,8 +6146,9 @@ do -- SET_ZONE end do -- SET_ZONE_GOAL - - --- @type SET_ZONE_GOAL + + --- + -- @type SET_ZONE_GOAL -- @extends Core.Set#SET_BASE --- Mission designers can use the @{Core.Set#SET_ZONE_GOAL} class to build sets of zones of various types. @@ -6446,8 +6458,9 @@ do -- SET_ZONE_GOAL end do -- SET_OPSZONE - - --- @type SET_OPSZONE + + --- + -- @type SET_OPSZONE -- @extends Core.Set#SET_BASE --- Mission designers can use the @{Core.Set#SET_OPSZONE} class to build sets of zones of various types. @@ -6903,8 +6916,9 @@ end do -- SET_OPSGROUP - - --- @type 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: @@ -7617,7 +7631,7 @@ do -- SET_SCENERY --- Add SCENERY(s) to SET_SCENERY. -- @param #SET_SCENERY self - -- @param #string AddScenery A single SCENERY. + -- @param Wrapper.Scenery#SCENERY AddScenery A single SCENERY object. -- @return #SET_SCENERY self function SET_SCENERY:AddScenery( AddScenery ) self:F2( AddScenery:GetName() ) @@ -7843,7 +7857,7 @@ do -- SET_SCENERY function SET_SCENERY:GetRelativeLife() local life = self:GetLife() local life0 = self:GetLife0() - self:T3(string.format("Set Lifepoints: %d life0 | %d life",life0,life)) + self:T2(string.format("Set Lifepoints: %d life0 | %d life",life0,life)) local rlife = math.floor((life / life0) * 100) return rlife end From 2771e7f85650a55ba0025c25d58cae059cc248eb Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Tue, 1 Aug 2023 16:18:23 +0200 Subject: [PATCH 12/16] #SCENERY, SET_SCENERY * Reworked COORDINATE scan as this doesn't seem to work * Added SET_SCENERY Filters, and FilterOnce() to apply them --- Moose Development/Moose/Core/Set.lua | 107 ++++++++++++++++++-- Moose Development/Moose/Wrapper/Scenery.lua | 91 ++++++++++++----- 2 files changed, 161 insertions(+), 37 deletions(-) diff --git a/Moose Development/Moose/Core/Set.lua b/Moose Development/Moose/Core/Set.lua index e3cd263c4..973090bb7 100644 --- a/Moose Development/Moose/Core/Set.lua +++ b/Moose Development/Moose/Core/Set.lua @@ -243,7 +243,7 @@ do -- SET_BASE function SET_BASE:Add( ObjectName, Object ) -- Debug info. - self:T( { ObjectName = ObjectName, Object = Object } ) + self:T2( { 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 @@ -258,6 +258,8 @@ do -- SET_BASE -- Trigger Added event. self:Added( ObjectName, Object ) + + return self end --- Adds a @{Core.Base#BASE} object in the @{Core.Set#SET_BASE}, using the Object Name as the index. @@ -1949,7 +1951,7 @@ do if self.Filter.Zones then local MGroupZone = false for ZoneName, Zone in pairs( self.Filter.Zones ) do - --self:I( "Zone:", ZoneName ) + --self:T( "Zone:", ZoneName ) if MGroup:IsInZone(Zone) then MGroupZone = true end @@ -4466,7 +4468,7 @@ do -- SET_CLIENT if self.Filter.Active == false or (self.Filter.Active == true and MClient:IsActive() == true and MClient:IsAlive() == true) then MClientActive = true end - --self:I( { "Evaluated Active", MClientActive } ) + --self:T( { "Evaluated Active", MClientActive } ) MClientInclude = MClientInclude and MClientActive end @@ -4548,7 +4550,7 @@ do -- SET_CLIENT if self.Filter.Playernames then local MClientPlayername = false local playername = MClient:GetPlayerName() or "Unknown" - --self:I(playername) + --self:T(playername) for _,_Playername in pairs(self.Filter.Playernames) do if playername and string.find(playername,_Playername) then MClientPlayername = true @@ -4561,7 +4563,7 @@ do -- SET_CLIENT if self.Filter.Callsigns then local MClientCallsigns = false local callsign = MClient:GetCallsign() - --self:I(callsign) + --self:T(callsign) for _,_Callsign in pairs(self.Filter.Callsigns) do if callsign and string.find(callsign,_Callsign) then MClientCallsigns = true @@ -7585,6 +7587,7 @@ do -- SET_SCENERY Scenerys = {}, Filter = { SceneryPrefixes = nil, + SceneryRoles = nil, Zones = nil, }, } @@ -7607,7 +7610,7 @@ do -- SET_SCENERY if ZoneSet then for _,_zone in pairs(ZoneSet.Set) do - self:T("Zone type handed: "..tostring(_zone.ClassName)) + self:T("Zone type handed: "..tostring(_zone.ClassName)) table.insert(zonenames,_zone:GetName()) end self:AddSceneryByName(zonenames) @@ -7701,6 +7704,7 @@ do -- SET_SCENERY end for _,Zone in pairs( zones ) do local zonename = Zone:GetName() + self:T(zonename) self.Filter.Zones[zonename] = Zone end return self @@ -7719,11 +7723,30 @@ do -- SET_SCENERY Prefixes = { Prefixes } end for PrefixID, Prefix in pairs( Prefixes ) do + --self:T(Prefix) self.Filter.SceneryPrefixes[Prefix] = Prefix end return self end - + + --- Builds a set of SCENERYs that **contain** an exact match of the "ROLE" property. + -- @param #SET_SCENERY self + -- @param #string Role The string pattern(s) that needs to exactly match the scenery "ROLE" property from the ME quad-zone properties. Can also be passed as a `#table` of strings. + -- @return #SET_SCENERY self + function SET_SCENERY:FilterRoles( Role ) + if not self.Filter.SceneryRoles then + self.Filter.SceneryRoles = {} + end + if type( Role ) ~= "table" then + Role = { Role } + end + for PrefixID, Prefix in pairs( Role ) do + --self:T(Prefix) + self.Filter.SceneryRoles[Prefix] = Prefix + end + return self + end + --- Iterate the SET_SCENERY and count how many SCENERYSs are alive. -- @param #SET_SCENERY self -- @return #number The number of SCENERYSs alive. @@ -7816,10 +7839,76 @@ do -- SET_SCENERY -- @param Wrapper.Scenery#SCENERY MScenery -- @return #SET_SCENERY self function SET_SCENERY:IsIncludeObject( MScenery ) - self:F2( MScenery ) - return true + self:T( MScenery.SceneryName ) + + local MSceneryInclude = true + + if MScenery then + local MSceneryName = MScenery:GetName() + + -- Filter Prefixes + if self.Filter.Prefixes then + local MSceneryPrefix = false + for ZonePrefixId, ZonePrefix in pairs( self.Filter.Prefixes ) do + self:T( { "Prefix:", string.find( MSceneryName, ZonePrefix, 1 ), ZonePrefix } ) + if string.find( MSceneryName, ZonePrefix, 1 ) then + MSceneryPrefix = true + end + end + self:T( { "Evaluated Prefix", MSceneryPrefix } ) + MSceneryInclude = MSceneryInclude and MSceneryPrefix + end + + if self.Filter.Zones then + local MSceneryZone = false + for ZoneName, Zone in pairs( self.Filter.Zones ) do + --self:T( "Zone:", ZoneName ) + local coord = MScenery:GetCoordinate() + if coord and Zone:IsCoordinateInZone(coord) then + MSceneryZone = true + end + self:T( { "Evaluated Zone", MSceneryZone } ) + end + MSceneryInclude = MSceneryInclude and MSceneryZone + end + + -- Filter Roles + if self.Filter.SceneryRoles then + local MSceneryRole = false + local Role = MScenery:GetProperty("ROLE") or "none" + for ZoneRoleId, ZoneRole in pairs( self.Filter.SceneryRoles ) do + self:T( { "Role:", ZoneRole, Role } ) + if ZoneRole == Role then + MSceneryRole = true + end + end + self:T( { "Evaluated Role ", MSceneryRole } ) + MSceneryInclude = MSceneryInclude and MSceneryRole + end + end + + self:T2( MSceneryInclude ) + return MSceneryInclude end + --- Filters for the defined collection. + -- @param #SET_SCENERY self + -- @return #SET_SCENERY self + function SET_SCENERY:FilterOnce() + + for ObjectName, Object in pairs( self:GetSet() ) do + self:T(ObjectName) + if self:IsIncludeObject( Object ) then + self:Add( ObjectName, Object ) + else + self:Remove(ObjectName, true) + end + end + + return self --FilteredSet + end + + --- Count overall initial (Life0) lifepoints of the SET objects. -- @param #SET_SCENERY self -- @return #number LIfe0Points diff --git a/Moose Development/Moose/Wrapper/Scenery.lua b/Moose Development/Moose/Wrapper/Scenery.lua index 24dc45fd6..3c697579c 100644 --- a/Moose Development/Moose/Wrapper/Scenery.lua +++ b/Moose Development/Moose/Wrapper/Scenery.lua @@ -9,7 +9,7 @@ -- === -- -- @module Wrapper.Scenery --- @image Wrapper_Scenery.JPG +-- @image Wrapper_Scenery.JPG+ --- SCENERY Class @@ -18,6 +18,7 @@ -- @field #string SceneryName Name of the scenery object. -- @field DCS#Object SceneryObject DCS scenery object. -- @field #number Life0 Initial life points. +-- @field #table Properties -- @extends Wrapper.Positionable#POSITIONABLE @@ -43,7 +44,7 @@ function SCENERY:Register( SceneryName, SceneryObject ) local self = BASE:Inherit( self, POSITIONABLE:New( SceneryName ) ) - self.SceneryName = SceneryName + self.SceneryName = tostring(SceneryName) self.SceneryObject = SceneryObject @@ -52,9 +53,43 @@ function SCENERY:Register( SceneryName, SceneryObject ) else self.Life0 = 0 end + + self.Properties = {} + return self end +--- Returns the Value of the zone with the given PropertyName, or nil if no matching property exists. +-- @param #SCENERY self +-- @param #string PropertyName The name of a the QuadZone Property from the scenery assignment to be retrieved. +-- @return #string The Value of the QuadZone Property from the scenery assignment with the given PropertyName, or nil if absent. +function SCENERY:GetProperty(PropertyName) + return self.Properties[PropertyName] +end + +--- Returns the scenery Properties table. +-- @param #SCENERY self +-- @return #table The Key:Value table of QuadZone properties of the zone from the scenery assignment . +function SCENERY:GetAllProperties() + return self.Properties +end + +--- Set a scenery property +-- @param #SCENERY self +-- @param #string PropertyName +-- @param #string PropertyValue +-- @return #SCENERY self +function SCENERY:SetProperty(PropertyName, PropertyValue) + self.Properties[PropertyName] = PropertyValue + return self +end +--- Obtain object name. +--@param #SCENERY self +--@return #string Name +function SCENERY:GetName() + return self.SceneryName +end + --- Obtain DCS Object from the SCENERY Object. --@param #SCENERY self --@return DCS#Object DCS scenery object. @@ -115,26 +150,28 @@ end --@param Core.Point#COORDINATE Coordinate Where to find the scenery object --@param #number Radius (optional) Search radius around coordinate, defaults to 100 --@return #SCENERY Scenery Object or `nil` if it cannot be found -function SCENERY:FindByName(Name, Coordinate, Radius) - +function SCENERY:FindByName(Name, Coordinate, Radius, Role) + local radius = Radius or 100 local name = Name or "unknown" local scenery = nil - BASE:T({name, radius, Coordinate:GetVec2()}) - --- -- @param Core.Point#COORDINATE coordinate -- @param #number radius -- @param #string name - local function SceneryScan(coordinate, radius, name) - if coordinate ~= nil then - local scenerylist = coordinate:ScanScenery(radius) - local rscenery = nil - for _,_scenery in pairs(scenerylist) do + local function SceneryScan(scoordinate, sradius, sname) + if scoordinate ~= nil then + local Vec2 = scoordinate:GetVec2() + local scanzone = ZONE_RADIUS:New("Zone-"..sname,Vec2,sradius,true) + scanzone:Scan({Object.Category.SCENERY}) + local scanned = scanzone:GetScannedSceneryObjects() + local rscenery = nil -- Wrapper.Scenery#SCENERY + for _,_scenery in pairs(scanned) do local scenery = _scenery -- Wrapper.Scenery#SCENERY - if tostring(scenery.SceneryName) == tostring(name) then + if tostring(scenery.SceneryName) == tostring(sname) then rscenery = scenery + if Role then rscenery:SetProperty("ROLE",Role) end break end end @@ -144,6 +181,7 @@ function SCENERY:FindByName(Name, Coordinate, Radius) end if Coordinate then + --BASE:I("Coordinate Scenery Scan") scenery = SceneryScan(Coordinate, radius, name) end @@ -154,7 +192,7 @@ end -- to find the correct object. --@param #SCENERY self --@param #string Name The name or id of the scenery object as taken from the ME. Ex. '595785449' ---@param Core.Zone#ZONE Zone Where to find the scenery object. Can be handed as zone name. +--@param Core.Zone#ZONE_BASE Zone Where to find the scenery object. Can be handed as zone name. --@param #number Radius (optional) Search radius around coordinate, defaults to 100 --@return #SCENERY Scenery Object or `nil` if it cannot be found function SCENERY:FindByNameInZone(Name, Zone, Radius) @@ -164,7 +202,7 @@ function SCENERY:FindByNameInZone(Name, Zone, Radius) Zone = ZONE:FindByName(Zone) end local coordinate = Zone:GetCoordinate() - return self:FindByName(Name,coordinate,Radius) + return self:FindByName(Name,coordinate,Radius,Zone:GetProperty("ROLE")) end --- Find a SCENERY object from its zone name. Since SCENERY isn't registered in the Moose database (just too many objects per map), we need to do a scan first @@ -173,38 +211,34 @@ end --@param #string ZoneName The name of the scenery zone as created with a right-click on the map in the mission editor and select "assigned to...". Can be handed over as ZONE object. --@return #SCENERY First found Scenery Object or `nil` if it cannot be found function SCENERY:FindByZoneName( ZoneName ) - local zone = ZoneName -- Core.Zone#ZONE + local zone = ZoneName -- Core.Zone#ZONE_BASE if type(ZoneName) == "string" then - zone = ZONE:FindByName(ZoneName) + zone = ZONE:FindByName(ZoneName) -- Core.Zone#ZONE_POLYGON end local _id = zone:GetProperty('OBJECT ID') + --local properties = zone:GetAllProperties() or {} + --BASE:I(string.format("Object ID is: %s",_id or "none")) --BASE:T("Object ID ".._id) if not _id then -- this zone has no object ID BASE:E("**** Zone without object ID: "..ZoneName.." | Type: "..tostring(zone.ClassName)) if string.find(zone.ClassName,"POLYGON") then zone:Scan({Object.Category.SCENERY}) - local scanned = zone:GetScannedScenery() + local scanned = zone:GetScannedSceneryObjects() for _,_scenery in (scanned) do local scenery = _scenery -- Wrapper.Scenery#SCENERY if scenery:IsAlive() then + local role = zone:GetProperty("ROLE") + if role then scenery:SetProperty("ROLE",role) end return scenery end end return nil else - local coordinate = zone:GetCoordinate() - local scanned = coordinate:ScanScenery() - for _,_scenery in (scanned) do - local scenery = _scenery -- Wrapper.Scenery#SCENERY - if scenery:IsAlive() then - return scenery - end - end - return nil + return self:FindByName(_id, zone:GetCoordinate(),nil,zone:GetProperty("ROLE")) end else - return self:FindByName(_id, zone:GetCoordinate()) + return self:FindByName(_id, zone:GetCoordinate(),nil,zone:GetProperty("ROLE")) end end @@ -219,6 +253,7 @@ function SCENERY:FindAllByZoneName( ZoneName ) zone = ZONE:FindByName(ZoneName) end local _id = zone:GetProperty('OBJECT ID') + --local properties = zone:GetAllProperties() or {} if not _id then -- this zone has no object ID --BASE:E("**** Zone without object ID: "..ZoneName.." | Type: "..tostring(zone.ClassName)) @@ -230,7 +265,7 @@ function SCENERY:FindAllByZoneName( ZoneName ) return nil end else - local obj = self:FindByName(_id, zone:GetCoordinate()) + local obj = self:FindByName(_id, zone:GetCoordinate(),nil,zone:GetProperty("ROLE")) if obj then return {obj} else From 6aa468308056758ba59cedbedeb55471e22ab94c Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Tue, 1 Aug 2023 16:19:03 +0200 Subject: [PATCH 13/16] #PLAYERTASK --- Moose Development/Moose/Ops/PlayerTask.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Moose Development/Moose/Ops/PlayerTask.lua b/Moose Development/Moose/Ops/PlayerTask.lua index cdc693a33..f91893c7e 100644 --- a/Moose Development/Moose/Ops/PlayerTask.lua +++ b/Moose Development/Moose/Ops/PlayerTask.lua @@ -21,7 +21,7 @@ -- === -- @module Ops.PlayerTask -- @image OPS_PlayerTask.jpg --- @date Last Update June 2023 +-- @date Last Update July 2023 do From 9cc08cb088861fd378386de812af20aa2b0bbfce Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Tue, 1 Aug 2023 16:26:29 +0200 Subject: [PATCH 14/16] # --- Moose Development/Moose/Wrapper/Scenery.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Moose Development/Moose/Wrapper/Scenery.lua b/Moose Development/Moose/Wrapper/Scenery.lua index 3c697579c..1ef31a039 100644 --- a/Moose Development/Moose/Wrapper/Scenery.lua +++ b/Moose Development/Moose/Wrapper/Scenery.lua @@ -9,7 +9,7 @@ -- === -- -- @module Wrapper.Scenery --- @image Wrapper_Scenery.JPG+ +-- @image Wrapper_Scenery.JPG --- SCENERY Class From c5757ffd222fe703e8f58252e6293296d6f0411b Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Wed, 2 Aug 2023 18:02:34 +0200 Subject: [PATCH 15/16] #CONTROLLABLE * Added EnRouteTaskCAP() --- .../Moose/Wrapper/Controllable.lua | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/Moose Development/Moose/Wrapper/Controllable.lua b/Moose Development/Moose/Wrapper/Controllable.lua index 37067d492..79f794b48 100644 --- a/Moose Development/Moose/Wrapper/Controllable.lua +++ b/Moose Development/Moose/Wrapper/Controllable.lua @@ -1734,6 +1734,27 @@ function CONTROLLABLE:EnRouteTaskSEAD(TargetTypes, Priority) return DCSTask end +--- (AIR) Enroute CAP task. +-- @param #CONTROLLABLE self +-- @param DCS#AttributeNameArray TargetTypes Array of target categories allowed to engage. Default `{"Air"}`. +-- @param #number Priority (Optional) All en-route tasks have the priority parameter. This is a number (less value - higher priority) that determines actions related to what task will be performed first. Default 0. +-- @return DCS#Task The DCS task structure. +function CONTROLLABLE:EnRouteTaskCAP(TargetTypes, Priority) + + local DCSTask = { + id = 'EngageTargets', + key = "CAP", + --auto = true, + enabled = true, + params = { + targetTypes = TargetTypes or {"Air"}, + priority = Priority or 0 + } + } + + return DCSTask +end + --- (AIR) Engaging a controllable. The task does not assign the target controllable to the unit/controllable to attack now; -- it just allows the unit/controllable to engage the target controllable as well as other assigned targets. -- See [hoggit](https://wiki.hoggitworld.com/view/DCS_task_engageGroup). From 29ed630536ef4429f425da52f927f7c972d2a37d Mon Sep 17 00:00:00 2001 From: Frank Date: Sun, 13 Aug 2023 17:40:28 +0200 Subject: [PATCH 16/16] COORDINATE - Generalized MarkupToAllFreeForm UTILS - Added some functions from MIST --- Moose Development/Moose/Core/Point.lua | 26 +++- Moose Development/Moose/Utilities/Utils.lua | 160 +++++++++++++++++++- 2 files changed, 181 insertions(+), 5 deletions(-) diff --git a/Moose Development/Moose/Core/Point.lua b/Moose Development/Moose/Core/Point.lua index d942e49ba..99e8eb593 100644 --- a/Moose Development/Moose/Core/Point.lua +++ b/Moose Development/Moose/Core/Point.lua @@ -2389,7 +2389,6 @@ do -- COORDINATE end --- Creates a free form shape on the F10 map. The first point is the current COORDINATE. The remaining points need to be specified. - -- **NOTE**: A free form polygon must have **at least three points** in total and currently only **up to 15 points** in total are supported. -- @param #COORDINATE self -- @param #table Coordinates Table of coordinates of the remaining points of the shape. -- @param #number Coalition Coalition: All=-1, Neutral=0, Red=1, Blue=2. Default -1=All. @@ -2463,9 +2462,30 @@ do -- COORDINATE vecs[11], vecs[12], vecs[13], vecs[14], vecs[15], Color, FillColor, LineType, ReadOnly, Text or "") else - self:E("ERROR: Currently a free form polygon can only have 15 points in total!") + -- Unfortunately, unpack(vecs) does not work! So no idea how to generalize this :( - trigger.action.markupToAll(7, Coalition, MarkID, unpack(vecs), Color, FillColor, LineType, ReadOnly, Text or "") + --trigger.action.markupToAll(7, Coalition, MarkID, unpack(vecs), Color, FillColor, LineType, ReadOnly, Text or "") + + -- Write command as string and execute that. Idea by Grimes https://forum.dcs.world/topic/324201-mark-to-all-function/#comment-5273793 + local s=string.format("trigger.action.markupToAll(7, %d, %d,", Coalition, MarkID) + for _,vec in pairs(vecs) do + s=s..string.format("%s,", UTILS._OneLineSerialize(vec)) + end + s=s..string.format("%s, %s, %s, %s", UTILS._OneLineSerialize(Color), UTILS._OneLineSerialize(FillColor), tostring(LineType), tostring(ReadOnly)) + if Text and Text~="" then + s=s..string.format(", \"%s\"", Text) + end + s=s..")" + + + -- Execute string command + local success=UTILS.DoString(s) + + if not success then + self:E("ERROR: Could not draw polygon") + env.info(s) + end + end return MarkID diff --git a/Moose Development/Moose/Utilities/Utils.lua b/Moose Development/Moose/Utilities/Utils.lua index 7b0467ed1..cc5f1df8b 100644 --- a/Moose Development/Moose/Utilities/Utils.lua +++ b/Moose Development/Moose/Utilities/Utils.lua @@ -293,8 +293,9 @@ UTILS.DeepCopy = function(object) end ---- Porting in Slmod's serialize_slmod2. +--- Serialize a given table. -- @param #table tbl Input table. +-- @return #string Table as a string. UTILS.OneLineSerialize = function( tbl ) -- serialization of a table all on a single line, no comments, made to replace old get_table_string function lookup_table = {} @@ -371,7 +372,54 @@ UTILS.OneLineSerialize = function( tbl ) -- serialization of a table all on a s return objectreturn end ---porting in Slmod's "safestring" basic serialize +--- Serialize a table to a single line string. +-- @param #table tbl table to serialize. +-- @return #string string containing serialized table. +function UTILS._OneLineSerialize(tbl) + + if type(tbl) == 'table' then --function only works for tables! + + local tbl_str = {} + + tbl_str[#tbl_str + 1] = '{ ' + + for ind,val in pairs(tbl) do -- serialize its fields + if type(ind) == "number" then + tbl_str[#tbl_str + 1] = '[' + tbl_str[#tbl_str + 1] = tostring(ind) + tbl_str[#tbl_str + 1] = '] = ' + else --must be a string + tbl_str[#tbl_str + 1] = '[' + tbl_str[#tbl_str + 1] = UTILS.BasicSerialize(ind) + tbl_str[#tbl_str + 1] = '] = ' + end + + if ((type(val) == 'number') or (type(val) == 'boolean')) then + tbl_str[#tbl_str + 1] = tostring(val) + tbl_str[#tbl_str + 1] = ', ' + elseif type(val) == 'string' then + tbl_str[#tbl_str + 1] = UTILS.BasicSerialize(val) + tbl_str[#tbl_str + 1] = ', ' + elseif type(val) == 'nil' then -- won't ever happen, right? + tbl_str[#tbl_str + 1] = 'nil, ' + elseif type(val) == 'table' then + tbl_str[#tbl_str + 1] = UTILS._OneLineSerialize(val) + tbl_str[#tbl_str + 1] = ', ' --I think this is right, I just added it + else + --log:warn('Unable to serialize value type $1 at index $2', mist.utils.basicSerialize(type(val)), tostring(ind)) + end + + end + + tbl_str[#tbl_str + 1] = '}' + return table.concat(tbl_str) + else + return UTILS.BasicSerialize(tbl) + end +end + +--- Basic serialize (porting in Slmod's "safestring" basic serialize). +-- @param #string s Table to serialize. UTILS.BasicSerialize = function(s) if s == nil then return "\"\"" @@ -402,6 +450,114 @@ function UTILS.PrintTableToLog(table, indent) end end +--- Returns table in a easy readable string representation. +-- @param tbl table to show +-- @param loc +-- @param indent +-- @param tableshow_tbls +-- @return Human readable string representation of given table. +function UTILS.TableShow(tbl, loc, indent, tableshow_tbls) + tableshow_tbls = tableshow_tbls or {} --create table of tables + loc = loc or "" + indent = indent or "" + if type(tbl) == 'table' then --function only works for tables! + tableshow_tbls[tbl] = loc + + local tbl_str = {} + + tbl_str[#tbl_str + 1] = indent .. '{\n' + + for ind,val in pairs(tbl) do -- serialize its fields + if type(ind) == "number" then + tbl_str[#tbl_str + 1] = indent + tbl_str[#tbl_str + 1] = loc .. '[' + tbl_str[#tbl_str + 1] = tostring(ind) + tbl_str[#tbl_str + 1] = '] = ' + else + tbl_str[#tbl_str + 1] = indent + tbl_str[#tbl_str + 1] = loc .. '[' + tbl_str[#tbl_str + 1] = UTILS.BasicSerialize(ind) + tbl_str[#tbl_str + 1] = '] = ' + end + + if ((type(val) == 'number') or (type(val) == 'boolean')) then + tbl_str[#tbl_str + 1] = tostring(val) + tbl_str[#tbl_str + 1] = ',\n' + elseif type(val) == 'string' then + tbl_str[#tbl_str + 1] = UTILS.BasicSerialize(val) + tbl_str[#tbl_str + 1] = ',\n' + elseif type(val) == 'nil' then -- won't ever happen, right? + tbl_str[#tbl_str + 1] = 'nil,\n' + elseif type(val) == 'table' then + if tableshow_tbls[val] then + tbl_str[#tbl_str + 1] = tostring(val) .. ' already defined: ' .. tableshow_tbls[val] .. ',\n' + else + tableshow_tbls[val] = loc .. '[' .. UTILS.BasicSerialize(ind) .. ']' + tbl_str[#tbl_str + 1] = tostring(val) .. ' ' + tbl_str[#tbl_str + 1] = UTILS.TableShow(val, loc .. '[' .. UTILS.BasicSerialize(ind).. ']', indent .. ' ', tableshow_tbls) + tbl_str[#tbl_str + 1] = ',\n' + end + elseif type(val) == 'function' then + if debug and debug.getinfo then + local fcnname = tostring(val) + local info = debug.getinfo(val, "S") + if info.what == "C" then + tbl_str[#tbl_str + 1] = string.format('%q', fcnname .. ', C function') .. ',\n' + else + if (string.sub(info.source, 1, 2) == [[./]]) then + tbl_str[#tbl_str + 1] = string.format('%q', fcnname .. ', defined in (' .. info.linedefined .. '-' .. info.lastlinedefined .. ')' .. info.source) ..',\n' + else + tbl_str[#tbl_str + 1] = string.format('%q', fcnname .. ', defined in (' .. info.linedefined .. '-' .. info.lastlinedefined .. ')') ..',\n' + end + end + + else + tbl_str[#tbl_str + 1] = 'a function,\n' + end + else + tbl_str[#tbl_str + 1] = 'unable to serialize value type ' .. UTILS.BasicSerialize(type(val)) .. ' at index ' .. tostring(ind) + end + end + + tbl_str[#tbl_str + 1] = indent .. '}' + return table.concat(tbl_str) + end +end + +--- Dumps the global table _G. +-- This dumps the global table _G to a file in the DCS\Logs directory. +-- This function requires you to disable script sanitization in $DCS_ROOT\Scripts\MissionScripting.lua to access lfs and io libraries. +-- @param #string fname File name. +function UTILS.Gdump(fname) + if lfs and io then + + local fdir = lfs.writedir() .. [[Logs\]] .. fname + + local f = io.open(fdir, 'w') + + f:write(UTILS.TableShow(_G)) + + f:close() + + env.info(string.format('Wrote debug data to $1', fdir)) + else + env.error("WARNING: lfs and/or io not de-sanitized - cannot dump _G!") + end +end + +--- Executes the given string. +-- borrowed from Slmod +-- @param #string s string containing LUA code. +-- @return #boolean `true` if successfully executed, `false` otherwise. +function UTILS.DoString(s) + local f, err = loadstring(s) + if f then + return true, f() + else + return false, err + end +end + UTILS.ToDegree = function(angle) return angle*180/math.pi