From 5e67861ea94a42f4ef1af0b0c9c03dce2a597b32 Mon Sep 17 00:00:00 2001 From: FlightControl Date: Mon, 8 Apr 2019 17:55:24 +0200 Subject: [PATCH 01/25] Improvements --- Moose Development/Moose/AI/AI_Escort.lua | 97 ++++++++-------- Moose Development/Moose/AI/AI_Formation.lua | 4 +- Moose Development/Moose/Core/Set.lua | 107 +++++++++++++++++- .../Moose/Functional/Detection.lua | 18 +-- 4 files changed, 167 insertions(+), 59 deletions(-) diff --git a/Moose Development/Moose/AI/AI_Escort.lua b/Moose Development/Moose/AI/AI_Escort.lua index 713129c0d..b742aad2f 100644 --- a/Moose Development/Moose/AI/AI_Escort.lua +++ b/Moose Development/Moose/AI/AI_Escort.lua @@ -198,11 +198,11 @@ function AI_ESCORT:New( EscortUnit, EscortGroupSet, EscortName, EscortBriefing ) self.EscortUnit = self.FollowUnit -- Wrapper.Unit#UNIT self.EscortGroupSet = EscortGroupSet + + self.EscortGroupSet:SetSomeIteratorLimit( 5 ) + self.EscortBriefing = EscortBriefing - - - -- if not EscortBriefing then -- EscortGroup:MessageToClient( EscortGroup:GetCategoryName() .. " '" .. EscortName .. "' (" .. EscortGroup:GetCallsign() .. ") reporting! " .. @@ -226,8 +226,6 @@ function AI_ESCORT:New( EscortUnit, EscortGroupSet, EscortName, EscortBriefing ) EscortGroupSet:ForEachGroup( --- @param Core.Group#GROUP EscortGroup function( EscortGroup ) - EscortGroup.EscortMenu = MENU_GROUP:New( self.EscortUnit:GetGroup(), EscortGroup:GetName() ) - -- Set EscortGroup known at EscortUnit. if not self.EscortUnit._EscortGroups then self.EscortUnit._EscortGroups = {} @@ -244,6 +242,14 @@ function AI_ESCORT:New( EscortUnit, EscortGroupSet, EscortName, EscortBriefing ) end ) + EscortGroupSet:ForSomeGroup( + --- @param Core.Group#GROUP EscortGroup + function( EscortGroup ) + EscortGroup.EscortMenu = MENU_GROUP:New( self.EscortUnit:GetGroup(), EscortGroup:GetName() ) + end + ) + + self.Detection = DETECTION_AREAS:New( EscortGroupSet, 5000 ) self.Detection:Start() @@ -337,7 +343,7 @@ function AI_ESCORT:MenuFormation( Formation, ... ) if not self["FlightMenuFormation"..Formation] then self["FlightMenuFormation"..Formation] = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), Formation, self.FlightMenuFormation, function ( self, Formation, ... ) - self.EscortGroupSet:ForEachGroupAlive( + self.EscortGroupSet:ForSomeGroupAlive( --- @param Core.Group#GROUP EscortGroup function( EscortGroup, self, Formation, ... ) if EscortGroup:IsAir() then @@ -350,7 +356,7 @@ function AI_ESCORT:MenuFormation( Formation, ... ) ) end --- self.EscortGroupSet:ForEachGroupAlive( +-- self.EscortGroupSet:ForSomeGroupAlive( -- --- @param Core.Group#GROUP EscortGroup -- function( EscortGroup ) -- if EscortGroup:IsAir() then @@ -382,7 +388,7 @@ function AI_ESCORT:MenuJoinUp() self.FlightMenuJoinUp = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), "Join Up", self.FlightMenuReportNavigation, AI_ESCORT._FlightJoinUp, self ) end - self.EscortGroupSet:ForEachGroupAlive( + self.EscortGroupSet:ForSomeGroupAlive( --- @param Core.Group#GROUP EscortGroup function( EscortGroup ) if EscortGroup:IsAir() then @@ -606,7 +612,7 @@ function AI_ESCORT:MenuHoldAtEscortPosition( Height, Speed, MenuTextFormat ) Speed ) - self.EscortGroupSet:ForEachGroupAlive( + self.EscortGroupSet:ForSomeGroupAlive( --- @param Core.Group#GROUP EscortGroup function( EscortGroup ) if EscortGroup:IsAir() then @@ -693,7 +699,7 @@ function AI_ESCORT:MenuHoldAtLeaderPosition( Height, Speed, MenuTextFormat ) Speed ) - self.EscortGroupSet:ForEachGroupAlive( + self.EscortGroupSet:ForSomeGroupAlive( --- @param Core.Group#GROUP EscortGroup function( EscortGroup ) if EscortGroup:IsAir() then @@ -834,7 +840,7 @@ function AI_ESCORT:MenuFlare( MenuTextFormat ) self.FlightMenuFlareYellow = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), "Release yellow flare", self.FlightMenuFlare, AI_ESCORT._FlightFlare, self, FLARECOLOR.Yellow, "Released a yellow flare!" ) end - self.EscortGroupSet:ForEachGroupAlive( + self.EscortGroupSet:ForSomeGroupAlive( --- @param Core.Group#GROUP EscortGroup function( EscortGroup ) if not EscortGroup.EscortMenuReportNavigation then @@ -891,7 +897,7 @@ function AI_ESCORT:MenuSmoke( MenuTextFormat ) self.FlightMenuSmokeBlue = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), "Release blue smoke", self.FlightMenuSmoke, AI_ESCORT._FlightSmoke, self, SMOKECOLOR.Blue, "Releasing blue smoke!" ) end - self.EscortGroupSet:ForEachGroupAlive( + self.EscortGroupSet:ForSomeGroupAlive( --- @param Core.Group#GROUP EscortGroup function( EscortGroup ) if not EscortGroup:IsAir() then @@ -950,23 +956,23 @@ function AI_ESCORT:MenuReportTargets( Seconds ) self.FlightReportTargetsScheduler = SCHEDULER:New( self, self._FlightReportTargetsScheduler, {}, 5, Seconds ) - self.EscortGroupSet:ForEachGroupAlive( + self.EscortGroupSet:ForSomeGroupAlive( --- @param Core.Group#GROUP EscortGroup function( EscortGroup ) if EscortGroup:IsAir() then + if not EscortGroup.EscortMenuReportNearbyTargets then EscortGroup.EscortMenuReportNearbyTargets = MENU_GROUP:New( self.EscortUnit:GetGroup(), "Report targets", EscortGroup.EscortMenu ) end -- Report Targets - EscortGroup.EscortMenuReportNearbyTargetsNow = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), "Report targets now!", EscortGroup.EscortMenuReportNearbyTargets, AI_ESCORT._ReportNearbyTargetsNow, self, EscortGroup ) + EscortGroup.EscortMenuReportNearbyTargetsNow = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), "Report targets now!", EscortGroup.EscortMenuReportNearbyTargets, AI_ESCORT._ReportNearbyTargetsNow, self, EscortGroup, true ) EscortGroup.EscortMenuReportNearbyTargetsOn = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), "Report targets on", EscortGroup.EscortMenuReportNearbyTargets, AI_ESCORT._SwitchReportNearbyTargets, self, EscortGroup, true ) EscortGroup.EscortMenuReportNearbyTargetsOff = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), "Report targets off", EscortGroup.EscortMenuReportNearbyTargets, AI_ESCORT._SwitchReportNearbyTargets, self, EscortGroup, false ) -- Attack Targets EscortGroup.EscortMenuAttackNearbyTargets = MENU_GROUP:New( self.EscortUnit:GetGroup(), "Attack targets", EscortGroup.EscortMenu ) - EscortGroup.ReportTargetsScheduler = SCHEDULER:New( self, self._ReportTargetsScheduler, { EscortGroup }, timer, Seconds ) timer=timer+1 end @@ -984,7 +990,7 @@ end function AI_ESCORT:MenuAssistedAttack() self:F() - self.EscortGroupSet:ForEachGroupAlive( + self.EscortGroupSet:ForSomeGroupAlive( --- @param Core.Group#GROUP EscortGroup function( EscortGroup ) if not EscortGroup:IsAir() then @@ -1005,7 +1011,7 @@ end function AI_ESCORT:MenuROE( MenuTextFormat ) self:F( MenuTextFormat ) - self.EscortGroupSet:ForEachGroupAlive( + self.EscortGroupSet:ForSomeGroupAlive( --- @param Core.Group#GROUP EscortGroup function( EscortGroup ) if not EscortGroup.EscortMenuROE then @@ -1038,7 +1044,7 @@ end function AI_ESCORT:MenuEvasion( MenuTextFormat ) self:F( MenuTextFormat ) - self.EscortGroupSet:ForEachGroupAlive( + self.EscortGroupSet:ForSomeGroupAlive( --- @param Core.Group#GROUP EscortGroup function( EscortGroup ) if EscortGroup:IsAir() then @@ -1133,7 +1139,7 @@ function AI_ESCORT:_FlightHoldPosition( OrbitGroup, OrbitHeight, OrbitSeconds ) local EscortUnit = self.EscortUnit - self.EscortGroupSet:ForEachGroupAlive( + self.EscortGroupSet:ForSomeGroupAlive( --- @param Core.Group#GROUP EscortGroup function( EscortGroup, OrbitGroup ) if EscortGroup:IsAir() then @@ -1160,7 +1166,7 @@ end function AI_ESCORT:_FlightJoinUp( EscortGroup ) - self.EscortGroupSet:ForEachGroupAlive( + self.EscortGroupSet:ForSomeGroupAlive( --- @param Core.Group#GROUP EscortGroup function( EscortGroup ) if EscortGroup:IsAir() then @@ -1187,7 +1193,7 @@ end function AI_ESCORT:_FlightFormationTrail( XStart, XSpace, YStart ) - self.EscortGroupSet:ForEachGroupAlive( + self.EscortGroupSet:ForSomeGroupAlive( --- @param Core.Group#GROUP EscortGroup function( EscortGroup ) if EscortGroup:IsAir() then @@ -1214,7 +1220,7 @@ end function AI_ESCORT:_FlightFormationStack( XStart, XSpace, YStart, YSpace ) - self.EscortGroupSet:ForEachGroupAlive( + self.EscortGroupSet:ForSomeGroupAlive( --- @param Core.Group#GROUP EscortGroup function( EscortGroup ) if EscortGroup:IsAir() then @@ -1237,7 +1243,7 @@ end function AI_ESCORT:_FlightFlare( Color, Message ) - self.EscortGroupSet:ForEachGroupAlive( + self.EscortGroupSet:ForSomeGroupAlive( --- @param Core.Group#GROUP EscortGroup function( EscortGroup ) if EscortGroup:IsAir() then @@ -1260,7 +1266,7 @@ end function AI_ESCORT:_FlightSmoke( Color, Message ) - self.EscortGroupSet:ForEachGroupAlive( + self.EscortGroupSet:ForSomeGroupAlive( --- @param Core.Group#GROUP EscortGroup function( EscortGroup ) if EscortGroup:IsAir() then @@ -1283,14 +1289,7 @@ end function AI_ESCORT:_FlightReportNearbyTargetsNow() - self.EscortGroupSet:ForEachGroupAlive( - --- @param Core.Group#GROUP EscortGroup - function( EscortGroup ) - if EscortGroup:IsAir() then - self:_ReportNearbyTargetsNow( EscortGroup ) - end - end - ) + self:_FlightReportTargetsScheduler() end @@ -1314,7 +1313,7 @@ end function AI_ESCORT:_FlightSwitchReportNearbyTargets( ReportTargets ) - self.EscortGroupSet:ForEachGroupAlive( + self.EscortGroupSet:ForSomeGroupAlive( --- @param Core.Group#GROUP EscortGroup function( EscortGroup ) if EscortGroup:IsAir() then @@ -1438,7 +1437,7 @@ end function AI_ESCORT:_FlightAttackTarget( DetectedItem ) - self.EscortGroupSet:ForEachGroupAlive( + self.EscortGroupSet:ForSomeGroupAlive( --- @param Core.Group#GROUP EscortGroup function( EscortGroup, DetectedItem ) if EscortGroup:IsAir() then @@ -1550,7 +1549,6 @@ function AI_ESCORT:_ReportTargetsScheduler( EscortGroup ) local EscortGroupName = EscortGroup:GetName() - EscortGroup.EscortMenuAttackNearbyTargets:RemoveSubMenus() if EscortGroup.EscortMenuTargetAssistance then EscortGroup.EscortMenuTargetAssistance:RemoveSubMenus() @@ -1559,10 +1557,10 @@ function AI_ESCORT:_ReportTargetsScheduler( EscortGroup ) local DetectedItems = self.Detection:GetDetectedItems() local ClientEscortTargets = self.Detection - --local EscortUnit = EscortGroupData:GetUnit( 1 ) + local TimeUpdate = timer.getTime() + for DetectedItemIndex, DetectedItem in pairs( DetectedItems ) do - self:F( { DetectedItemIndex, DetectedItem } ) local DetectedItemReportSummary = self.Detection:DetectedItemReportMenu( DetectedItem, EscortGroup, _DATABASE:GetPlayerSettings( self.EscortUnit:GetPlayerName() ) ) @@ -1576,7 +1574,7 @@ function AI_ESCORT:_ReportTargetsScheduler( EscortGroup ) self, EscortGroup, DetectedItem - ) + ):SetTag( "Escort" ):SetTime( TimeUpdate ) else if self.EscortMenuTargetAssistance then local MenuTargetAssistance = MENU_GROUP:New( self.EscortUnit:GetGroup(), EscortGroupName, EscortGroup.EscortMenuTargetAssistance ) @@ -1594,6 +1592,8 @@ function AI_ESCORT:_ReportTargetsScheduler( EscortGroup ) end + EscortGroup.EscortMenuAttackNearbyTargets:RemoveSubMenus( TimeUpdate, "Esort" ) + return true else end @@ -1617,7 +1617,8 @@ function AI_ESCORT:_FlightReportTargetsScheduler() local ClientGroup = self.EscortUnit:GetGroup() - self.FlightMenuAttackNearbyTargets:RemoveSubMenus() + local TimeUpdate = timer.getTime() + local DetectedItems = self.Detection:GetDetectedItems() @@ -1629,20 +1630,24 @@ function AI_ESCORT:_FlightReportTargetsScheduler() DetectedTargets = true -- There are detected targets, when the content of the for loop is executed. We use it to display a message. - local DetectedItemReportSummary = self.Detection:DetectedItemReportMenu( DetectedItem, ClientGroup, _DATABASE:GetPlayerSettings( self.EscortUnit:GetPlayerName() ) ) - - local DetectedMsg = DetectedItemReportSummary:Text(", ") - DetectedTargetsReport:AddIndent( DetectedMsg, "-" ) - + local DetectedItemReportMenu = self.Detection:DetectedItemReportMenu( DetectedItem, ClientGroup, _DATABASE:GetPlayerSettings( self.EscortUnit:GetPlayerName() ) ) + local ReportMenuText = DetectedItemReportMenu:Text(", ") + MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), - DetectedMsg, + ReportMenuText, self.FlightMenuAttackNearbyTargets, AI_ESCORT._FlightAttackTarget, self, DetectedItem - ) + ):SetTag( "Flight" ):SetTime( TimeUpdate ) + + local DetectedItemReportSummary = self.Detection:DetectedItemReportSummary( DetectedItem, ClientGroup, _DATABASE:GetPlayerSettings( self.EscortUnit:GetPlayerName() ) ) + local ReportSummary = DetectedItemReportSummary:Text(", ") + DetectedTargetsReport:AddIndent( ReportSummary, "-" ) end + self.FlightMenuAttackNearbyTargets:RemoveSubMenus( TimeUpdate, "Flight" ) + if DetectedTargets then EscortGroup:MessageTypeToGroup( DetectedTargetsReport:Text( "\n" ), MESSAGE.Type.Information, self.EscortUnit:GetGroup() ) -- else diff --git a/Moose Development/Moose/AI/AI_Formation.lua b/Moose Development/Moose/AI/AI_Formation.lua index 338d29738..ca82a043d 100644 --- a/Moose Development/Moose/AI/AI_Formation.lua +++ b/Moose Development/Moose/AI/AI_Formation.lua @@ -1038,7 +1038,7 @@ function AI_FORMATION:onenterFollowing( FollowGroupSet ) --R2.1 local Alpha_R = ( Alpha_T < 0 ) and Alpha_T + 2 * math.pi or Alpha_T local Position = math.cos( Alpha_R ) local GD = ( ( GDv.x )^2 + ( GDv.z )^2 ) ^ 0.5 - local Distance = GD * Position + - CS * 0.5 + local Distance = GD * Position + - CS * 0.3 -- Calculate the group direction vector local GV = { x = GV2.x - CV2.x, y = GV2.y - CV2.y, z = GV2.z - CV2.z } @@ -1056,7 +1056,7 @@ function AI_FORMATION:onenterFollowing( FollowGroupSet ) --R2.1 -- Now we calculate the intersecting vector between the circle around CV2 with radius FollowDistance and GH2. -- From the GeoGebra model: CVI = (x(CV2) + FollowDistance cos(alpha), y(GH2) + FollowDistance sin(alpha), z(CV2)) local CVI = { x = CV2.x + CS * 10 * math.sin(Ca), - y = GH2.y - ( Distance + FollowFormation.x ) / 5, -- + FollowFormation.y, + y = GH2.y - ( Distance + FollowFormation.x ) / 10, -- + FollowFormation.y, z = CV2.z + CS * 10 * math.cos(Ca), } diff --git a/Moose Development/Moose/Core/Set.lua b/Moose Development/Moose/Core/Set.lua index 4399c92f7..5a5f47adb 100644 --- a/Moose Development/Moose/Core/Set.lua +++ b/Moose Development/Moose/Core/Set.lua @@ -125,7 +125,7 @@ do -- SET_BASE self.Index = {} self.CallScheduler = SCHEDULER:New( self ) - + self:SetEventPriority( 2 ) return self @@ -341,6 +341,25 @@ do -- SET_BASE return self end + --- Define the SET iterator **"limit"**. + -- @param #SET_BASE self + -- @param #number Limit Defines how many objects are evaluated of the set as part of the Some iterators. The default is 1. + -- @return #SET_BASE self + function SET_BASE:SetSomeIteratorLimit( Limit ) + + self.SomeIteratorLimit = Limit or 1 + + return self + end + + --- Get the SET iterator **"limit"**. + -- @param #SET_BASE self + -- @return #number Defines how many objects are evaluated of the set as part of the Some iterators. + function SET_BASE:GetSomeIteratorLimit() + + return self.SomeIteratorLimit or self:Count() + end + --- Filters for the defined collection. -- @param #SET_BASE self @@ -590,6 +609,66 @@ do -- SET_BASE return self end + + --- Iterate the SET_BASE and derived classes and call an iterator function for the given SET_BASE, providing the Object for each element within the set and optional parameters. + -- @param #SET_BASE self + -- @param #function IteratorFunction The function that will be called. + -- @return #SET_BASE self + function SET_BASE:ForSome( IteratorFunction, arg, Set, Function, FunctionArguments ) + self:F3( arg ) + + Set = Set or self:GetSet() + arg = arg or {} + + local Limit = self:GetSomeIteratorLimit() + + local function CoRoutine() + local Count = 0 + for ObjectID, ObjectData in pairs( Set ) do + local Object = ObjectData + self:T3( Object ) + if Function then + if Function( unpack( FunctionArguments ), Object ) == true then + IteratorFunction( Object, unpack( arg ) ) + end + else + IteratorFunction( Object, unpack( arg ) ) + end + Count = Count + 1 + if Count >= Limit then + break + end + -- if Count % self.YieldInterval == 0 then + -- coroutine.yield( false ) + -- end + end + return true + end + + -- local co = coroutine.create( CoRoutine ) + local co = CoRoutine + + local function Schedule() + + -- local status, res = coroutine.resume( co ) + local status, res = co() + self:T3( { status, res } ) + + if status == false then + error( res ) + end + if res == false then + return true -- resume next time the loop + end + + return false + end + + --self.CallScheduler:Schedule( self, Schedule, {}, self.TimeInterval, self.TimeInterval, 0 ) + Schedule() + + return self + end ----- Iterate the SET_BASE and call an interator function for each **alive** unit, providing the Unit and optional parameters. @@ -1144,7 +1223,7 @@ do -- SET_GROUP --- Iterate the SET_GROUP and call an iterator function for each GROUP object, providing the GROUP and optional parameters. -- @param #SET_GROUP self - -- @param #function IteratorFunction The function that will be called when there is an alive GROUP in the SET_GROUP. The function needs to accept a GROUP parameter. + -- @param #function IteratorFunction The function that will be called for all GROUP in the SET_GROUP. The function needs to accept a GROUP parameter. -- @return #SET_GROUP self function SET_GROUP:ForEachGroup( IteratorFunction, ... ) self:F2( arg ) @@ -1154,6 +1233,18 @@ do -- SET_GROUP return self end + --- Iterate the SET_GROUP and call an iterator function for some GROUP objects, providing the GROUP and optional parameters. + -- @param #SET_GROUP self + -- @param #function IteratorFunction The function that will be called for some GROUP in the SET_GROUP. The function needs to accept a GROUP parameter. + -- @return #SET_GROUP self + function SET_GROUP:ForSomeGroup( IteratorFunction, ... ) + self:F2( arg ) + + self:ForSome( IteratorFunction, arg, self:GetSet() ) + + return self + end + --- Iterate the SET_GROUP and call an iterator function for each **alive** GROUP object, providing the GROUP and optional parameters. -- @param #SET_GROUP self -- @param #function IteratorFunction The function that will be called when there is an alive GROUP in the SET_GROUP. The function needs to accept a GROUP parameter. @@ -1166,6 +1257,18 @@ do -- SET_GROUP return self end + --- Iterate the SET_GROUP and call an iterator function for some **alive** GROUP objects, providing the GROUP and optional parameters. + -- @param #SET_GROUP self + -- @param #function IteratorFunction The function that will be called when there is an alive GROUP in the SET_GROUP. The function needs to accept a GROUP parameter. + -- @return #SET_GROUP self + function SET_GROUP:ForSomeGroupAlive( IteratorFunction, ... ) + self:F2( arg ) + + self:ForSome( IteratorFunction, arg, self:GetAliveSet() ) + + return self + end + --- Iterate the SET_GROUP and call an iterator function for each **alive** GROUP presence completely in a @{Zone}, providing the GROUP and optional parameters to the called function. -- @param #SET_GROUP self -- @param Core.Zone#ZONE ZoneObject The Zone to be tested for. diff --git a/Moose Development/Moose/Functional/Detection.lua b/Moose Development/Moose/Functional/Detection.lua index 06ecfe87f..fe078643a 100644 --- a/Moose Development/Moose/Functional/Detection.lua +++ b/Moose Development/Moose/Functional/Detection.lua @@ -305,7 +305,7 @@ do -- DETECTION_BASE --- DETECTION constructor. -- @param #DETECTION_BASE self - -- @param Core.Set#SET_BASE DetectionSet The @{Set} that is used to detect the units. + -- @param Core.Set#SET_GROUP DetectionSet The @{Set} of @{Group}s that is used to detect the units. -- @return #DETECTION_BASE self function DETECTION_BASE:New( DetectionSet ) @@ -541,13 +541,14 @@ do -- DETECTION_BASE end - self.DetectionCount = self.DetectionSet:Count() - for DetectionID, DetectionData in pairs( self.DetectionSet:GetSet() ) do - --self:F( { DetectionGroupData } ) - self:F( { DetectionGroup = DetectionData:GetName() } ) - self:__Detection( DetectDelay, DetectionData, DetectionTimeStamp ) -- Process each detection asynchronously. - DetectDelay = DetectDelay + 1 - end + self.DetectionCount = self.DetectionSet:GetSomeIteratorLimit() + + self.DetectionSet:ForSomeGroupAlive( + function( DetectionGroup ) + self:__Detection( DetectDelay, DetectionGroup, DetectionTimeStamp ) -- Process each detection asynchronously. + DetectDelay = DetectDelay + 1 + end + ) end --- @param #DETECTION_BASE self @@ -2502,7 +2503,6 @@ do -- DETECTION_AREAS local Report = REPORT:New() Report:Add( DetectedItemID ) Report:Add( string.format( "Threat: [%s%s]", string.rep( "■", ThreatLevelA2G ), string.rep( "□", 10-ThreatLevelA2G ) ) ) - Report:Add( DetectedItemCoordText ) return Report end From bf449492b55289c013f74ba52622729081080b2e Mon Sep 17 00:00:00 2001 From: FlightControl Date: Tue, 9 Apr 2019 17:45:29 +0200 Subject: [PATCH 02/25] Updated approach speed logic to prevent airplanes to fly beyond the hold position. --- Moose Development/Moose/AI/AI_Escort.lua | 4 ++-- Moose Development/Moose/AI/AI_Formation.lua | 25 ++++++++++++--------- 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/Moose Development/Moose/AI/AI_Escort.lua b/Moose Development/Moose/AI/AI_Escort.lua index b742aad2f..f6b0ffeb9 100644 --- a/Moose Development/Moose/AI/AI_Escort.lua +++ b/Moose Development/Moose/AI/AI_Escort.lua @@ -306,8 +306,8 @@ function AI_ESCORT:Menus() -- self:MenuScanForTargets( 100, 60 ) self:MenuJoinUp() - self:MenuFormationTrail( 0, 50, 100 ) - self:MenuFormationStack( 0, 0, 100, 100 ) + self:MenuFormationTrail( 50, 100, 50 ) + self:MenuFormationStack( 50, 100, 50, 50 ) self:MenuFormationLeftLine( 0, 0, 100, 100 ) self:MenuFormationRightLine( 0, 0, 100, 100 ) self:MenuFormationLeftWing( 0, 50, 0, 100, 100 ) diff --git a/Moose Development/Moose/AI/AI_Formation.lua b/Moose Development/Moose/AI/AI_Formation.lua index ca82a043d..edf3afe96 100644 --- a/Moose Development/Moose/AI/AI_Formation.lua +++ b/Moose Development/Moose/AI/AI_Formation.lua @@ -963,15 +963,11 @@ end --- @param #AI_FORMATION self function AI_FORMATION:onenterFollowing( FollowGroupSet ) --R2.1 - self:F( ) - self:T( { self.FollowUnit.UnitName, self.FollowUnit:IsAlive() } ) if self.FollowUnit:IsAlive() then local ClientUnit = self.FollowUnit - self:T( {ClientUnit.UnitName } ) - local CT1, CT2, CV1, CV2 CT1 = ClientUnit:GetState( self, "CT1" ) @@ -1038,7 +1034,7 @@ function AI_FORMATION:onenterFollowing( FollowGroupSet ) --R2.1 local Alpha_R = ( Alpha_T < 0 ) and Alpha_T + 2 * math.pi or Alpha_T local Position = math.cos( Alpha_R ) local GD = ( ( GDv.x )^2 + ( GDv.z )^2 ) ^ 0.5 - local Distance = GD * Position + - CS * 0.3 + local Distance = GD * Position + - CS * 0.5 -- Calculate the group direction vector local GV = { x = GV2.x - CV2.x, y = GV2.y - CV2.y, z = GV2.z - CV2.z } @@ -1056,7 +1052,7 @@ function AI_FORMATION:onenterFollowing( FollowGroupSet ) --R2.1 -- Now we calculate the intersecting vector between the circle around CV2 with radius FollowDistance and GH2. -- From the GeoGebra model: CVI = (x(CV2) + FollowDistance cos(alpha), y(GH2) + FollowDistance sin(alpha), z(CV2)) local CVI = { x = CV2.x + CS * 10 * math.sin(Ca), - y = GH2.y - ( Distance + FollowFormation.x ) / 10, -- + FollowFormation.y, + y = GH2.y + ( Distance + FollowFormation.x ) / 10, -- + FollowFormation.y, z = CV2.z + CS * 10 * math.cos(Ca), } @@ -1087,13 +1083,22 @@ function AI_FORMATION:onenterFollowing( FollowGroupSet ) --R2.1 - local Time = 60 + local Time = 120 local Speed = - ( Distance + FollowFormation.x ) / Time - local GS = Speed + CS - if Speed < 0 then - Speed = 0 + + if Distance > -4000 then + Speed = - ( Distance + FollowFormation.x ) / 90 end + + if Distance > -1500 then + Speed = - ( Distance + FollowFormation.x ) / 20 + end + + local GS = Speed + CS + + self:F( { Distance = Distance, Speed = Speed, CS = CS, GS = GS } ) + -- Now route the escort to the desired point with the desired speed. FollowGroup:RouteToVec3( GDV_Formation, GS ) -- DCS models speed in Mps (Miles per second) From 03c47cc9f9c9efdea68c79b26d26de8cd547236b Mon Sep 17 00:00:00 2001 From: FlightControl Date: Wed, 10 Apr 2019 18:49:05 +0200 Subject: [PATCH 03/25] documentation --- Moose Development/Moose/AI/AI_Escort.lua | 85 ++++++++++++++++-------- 1 file changed, 57 insertions(+), 28 deletions(-) diff --git a/Moose Development/Moose/AI/AI_Escort.lua b/Moose Development/Moose/AI/AI_Escort.lua index f6b0ffeb9..07bedf8c8 100644 --- a/Moose Development/Moose/AI/AI_Escort.lua +++ b/Moose Development/Moose/AI/AI_Escort.lua @@ -25,11 +25,49 @@ -- -- Allows you to interact with escorting AI on your flight and take the lead. -- --- Each escorting group can be commanded with a whole set of radio commands (radio menu in your flight, and then F10). +-- Each escorting group can be commanded with a complete set of radio commands (radio menu in your flight, and then F10). -- --- The radio commands will vary according the category of the group. The richest set of commands are with Helicopters and AirPlanes. +-- The radio commands will vary according the category of the group. The richest set of commands are with helicopters and airPlanes. -- Ships and Ground troops will have a more limited set, but they can provide support through the bombing of targets designated by the other escorts. --- +-- +-- Escorts detect targets using a built-in detection mechanism. The detected targets are reported at a specified time interval. +-- Once targets are reported, each escort has these targets as menu options to command the attack of these targets. +-- Targets are by default grouped per area of 5000 meters, but the kind of detection and the grouping range can be altered. +-- +-- Different formations can be selected in the Flight menu: Trail, Stack, Left Line, Right Line, Left Wing, Right Wing, Central Wing and Boxed formations are available. +-- The Flight menu also allows for a mass attack, where all of the escorts are commanded to attack a target. +-- +-- Escorts can emit flares to reports their location. They can be commanded to hold at a location, which can be their current or the leader location. +-- In this way, you can spread out the escorts over the battle field before a coordinated attack. +-- +-- But basically, the escort class provides 4 modes of operation, and depending on the mode, you are either leading the flight, or following the flight. +-- +-- ## Leading the flight +-- +-- When leading the flight, you are expected to guide the escorts towards the target areas, +-- and carefully coordinate the attack based on the threat levels reported, and the available weapons +-- carried by the escorts. Ground ships or ground troops can execute A-assisted attacks, when they have long-range ground precision weapons for attack. +-- +-- ## Following the flight +-- +-- Escorts can be commanded to execute a specific mission path. In this mode, the escorts are in the lead. +-- You as a player, are following the escorts, and are commanding them to progress the mission while +-- ensuring that the escorts survive. You are joining the escorts in the battlefield. They will detect and report targets +-- and you will ensure that the attacks are well coordinated, assigning the correct escort type for the detected target +-- type. Once the attack is finished, the escort will resume the mission it was assigned. +-- In other words, you can use the escorts for reconnaissance, and for guiding the attack. +-- Imagine you as a mi-8 pilot, assigned to pickup cargo. Two ka-50s are guiding the way, and you are +-- following. You are in control. The ka-50s detect targets, report them, and you command how the attack +-- will commence and from where. You can control where the escorts are holding position and which targets +-- are attacked first. You are in control how the ka-50s will follow their mission path. +-- +-- Escorts can act as part of a AI A2G dispatcher offensive. In this way, You was a player are in control. +-- The mission is defined by the A2G dispatcher, and you are responsible to join the flight and ensure that the +-- attack is well coordinated. +-- +-- It is with great proud that I present you this class, and I hope you will enjoy the functionality and the dynamism +-- it brings in your DCS world simulations. +-- -- # RADIO MENUs that can be created: -- -- Find a summary below of the current available commands: @@ -38,7 +76,7 @@ -- -- Escort group navigation functions: -- --- * **"Join-Up and Follow at x meters":** The escort group fill follow you at about x meters, and they will follow you. +-- * **"Join-Up":** The escort group fill follow you in the assigned formation. -- * **"Flare":** Provides menu commands to let the escort group shoot a flare in the air in a color. -- * **"Smoke":** Provides menu commands to let the escort group smoke the air in a color. Note that smoking is only available for ground and naval troops. -- @@ -46,32 +84,33 @@ -- -- Escort group navigation functions: -- --- * **"At current location":** Stops the escort group and they will hover 30 meters above the ground at the position they stopped. --- * **"At client location":** Stops the escort group and they will hover 30 meters above the ground at the position they stopped. +-- * **"At current location":** The escort group will hover above the ground at the position they were. The altitude can be specified as a parameter. +-- * **"At my location":** The escort group will hover or orbit at the position where you are. The escort will fly to your location and hold position. The altitude can be specified as a parameter. -- -- ## Report targets ...: -- --- Report targets will make the escort group to report any target that it identifies within a 8km range. Any detected target can be attacked using the 4. Attack nearby targets function. (see below). +-- Report targets will make the escort group to report any target that it identifies within detection range. Any detected target can be attacked using the "Attack Targets" menu function. (see below). -- -- * **"Report now":** Will report the current detected targets. --- * **"Report targets on":** Will make the escort group to report detected targets and will fill the "Attack nearby targets" menu list. +-- * **"Report targets on":** Will make the escorts to report the detected targets and will fill the "Attack Targets" menu list. -- * **"Report targets off":** Will stop detecting targets. -- --- ## Scan targets ...: --- --- Menu items to pop-up the escort group for target scanning. After scanning, the escort group will resume with the mission or defined task. --- --- * **"Scan targets 30 seconds":** Scan 30 seconds for targets. --- * **"Scan targets 60 seconds":** Scan 60 seconds for targets. --- -- ## Attack targets ...: -- -- This menu item will list all detected targets within a 15km range. Depending on the level of detection (known/unknown) and visuality, the targets type will also be listed. +-- This menu will be available in Flight menu or in each Escort menu. +-- +-- ## Scan targets ...: +-- +-- Menu items to pop-up the escort group for target scanning. After scanning, the escort group will resume with the mission or rejoin formation. +-- +-- * **"Scan targets 30 seconds":** Scan 30 seconds for targets. +-- * **"Scan targets 60 seconds":** Scan 60 seconds for targets. -- -- ## Request assistance from ...: -- --- This menu item will list all detected targets within a 15km range, as with the menu item **Attack Targets**. --- This menu item allows to request attack support from other escorts supporting the current client group. +-- This menu item will list all detected targets within a 15km range, similar as with the menu item **Attack Targets**. +-- This menu item allows to request attack support from other ground based escorts supporting the current escort. -- eg. the function allows a player to request support from the Ship escort to attack a target identified by the Plane escort with its Tomahawk missiles. -- eg. the function allows a player to request support from other Planes escorting to bomb the unit with illumination missiles or bombs, so that the main plane escort can attack the area. -- @@ -111,22 +150,12 @@ --- @type AI_ESCORT -- @extends AI.AI_Formation#AI_FORMATION --- @field Wrapper.Client#CLIENT EscortUnit --- @field Wrapper.Group#GROUP EscortGroup --- @field #string EscortName --- @field #AI_ESCORT.MODE EscortMode The mode the escort is in. --- @field Core.Scheduler#SCHEDULER FollowScheduler The instance of the SCHEDULER class. --- @field #number FollowDistance The current follow distance. --- @field #boolean ReportTargets If true, nearby targets are reported. --- @Field DCS#AI.Option.Air.val.ROE OptionROE Which ROE is set to the EscortGroup. --- @field DCS#AI.Option.Air.val.REACTION_ON_THREAT OptionReactionOnThreat Which REACTION_ON_THREAT is set to the EscortGroup. --- @field FunctionalMENU_GROUPDETECTION_BASE Detection --- AI_ESCORT class -- -- # AI_ESCORT construction methods. -- --- Create a new SPAWN object with the @{#AI_ESCORT.New} method: +-- Create a new AI_ESCORT object with the @{#AI_ESCORT.New} method: -- -- * @{#AI_ESCORT.New}: Creates a new AI_ESCORT object from a @{Wrapper.Group#GROUP} for a @{Wrapper.Client#CLIENT}, with an optional briefing text. -- From d985d9a41d5241322b6fafd7d46699892aadc896 Mon Sep 17 00:00:00 2001 From: FlightControl Date: Tue, 16 Apr 2019 19:49:46 +0200 Subject: [PATCH 04/25] WIP --- Moose Development/Moose/Core/Database.lua | 3 ++- Moose Development/Moose/Core/Event.lua | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Moose Development/Moose/Core/Database.lua b/Moose Development/Moose/Core/Database.lua index 5a07d5f5a..be7a7c924 100644 --- a/Moose Development/Moose/Core/Database.lua +++ b/Moose Development/Moose/Core/Database.lua @@ -890,7 +890,7 @@ end -- @param #DATABASE self -- @param Core.Event#EVENTDATA Event function DATABASE:_EventOnBirth( Event ) - self:F2( { Event } ) + self:F( { Event } ) if Event.IniDCSUnit then if Event.IniObjectCategory == 3 then @@ -907,6 +907,7 @@ function DATABASE:_EventOnBirth( Event ) local PlayerName = Event.IniUnit:GetPlayerName() if PlayerName then self:I( { "Player Joined:", PlayerName } ) + self:AddClient( Event.IniDCSUnitName ) if not self.PLAYERS[PlayerName] then self:AddPlayer( Event.IniUnitName, PlayerName ) end diff --git a/Moose Development/Moose/Core/Event.lua b/Moose Development/Moose/Core/Event.lua index 386169cb0..89cfc22cd 100644 --- a/Moose Development/Moose/Core/Event.lua +++ b/Moose Development/Moose/Core/Event.lua @@ -986,7 +986,7 @@ function EVENT:onEvent( Event ) local PriorityEnd = PriorityOrder == -1 and 1 or 5 if Event.IniObjectCategory ~= Object.Category.STATIC then - self:T( { EventMeta.Text, Event, Event.IniDCSUnitName, Event.TgtDCSUnitName, PriorityOrder } ) + self:F( { EventMeta.Text, Event, Event.IniDCSUnitName, Event.TgtDCSUnitName, PriorityOrder } ) end for EventPriority = PriorityBegin, PriorityEnd, PriorityOrder do From b21ff707ba8c579a72635bcf8e0236625f4d8a24 Mon Sep 17 00:00:00 2001 From: FlightControl Date: Tue, 23 Apr 2019 19:59:11 +0300 Subject: [PATCH 05/25] Updates escort before plane trip. --- Moose Development/Moose/AI/AI_Escort.lua | 11 ++ Moose Development/Moose/AI/AI_Formation.lua | 8 +- Moose Development/Moose/Core/Point.lua | 2 +- Moose Development/Moose/Core/Set.lua | 33 +++++ Moose Development/Moose/Core/Spawn.lua | 137 ++++++++++++-------- 5 files changed, 129 insertions(+), 62 deletions(-) diff --git a/Moose Development/Moose/AI/AI_Escort.lua b/Moose Development/Moose/AI/AI_Escort.lua index 07bedf8c8..784799ef9 100644 --- a/Moose Development/Moose/AI/AI_Escort.lua +++ b/Moose Development/Moose/AI/AI_Escort.lua @@ -286,6 +286,8 @@ function AI_ESCORT:New( EscortUnit, EscortGroupSet, EscortName, EscortBriefing ) return self end +--- @param #AI_ESCORT self +-- @param Core.Set#SET_GROUP EscortGroupSet function AI_ESCORT:onafterStart( EscortGroupSet ) self:E("Start") @@ -300,6 +302,15 @@ function AI_ESCORT:onafterStart( EscortGroupSet ) EscortGroup:OptionROEOpenFire() end ) + + local LeaderEscort = EscortGroupSet:GetFirst() -- Wrapper.Group#GROUP + + local Report = REPORT:New( "Escorts Reporting." ) + Report:Add( "Current coordinate: " .. LeaderEscort:GetCoordinate():ToString( self.EscortUnit ) ) + Report:Add( "Configuration: " .. EscortGroupSet:GetUnitTypeNames():Text( ", " ) ) + Report:Add( "Joining Up ..." ) + + LeaderEscort:MessageTypeToGroup( Report:Text(), MESSAGE.Type.Information, self.EscortUnit ) end diff --git a/Moose Development/Moose/AI/AI_Formation.lua b/Moose Development/Moose/AI/AI_Formation.lua index edf3afe96..e0981a599 100644 --- a/Moose Development/Moose/AI/AI_Formation.lua +++ b/Moose Development/Moose/AI/AI_Formation.lua @@ -740,7 +740,7 @@ end -- @return #AI_FORMATION function AI_FORMATION:onafterFormationLeftLine( FollowGroupSet, From , Event , To, XStart, YStart, ZStart, ZSpace ) --R2.1 - self:onafterFormationLine(FollowGroupSet,From,Event,To,XStart,0,YStart,0,ZStart,ZSpace) + self:onafterFormationLine(FollowGroupSet,From,Event,To,XStart,0,YStart,0,-ZStart,-ZSpace) return self end @@ -759,7 +759,7 @@ end -- @return #AI_FORMATION function AI_FORMATION:onafterFormationRightLine( FollowGroupSet, From , Event , To, XStart, YStart, ZStart, ZSpace ) --R2.1 - self:onafterFormationLine(FollowGroupSet,From,Event,To,XStart,0,YStart,0,-ZStart,-ZSpace) + self:onafterFormationLine(FollowGroupSet,From,Event,To,XStart,0,YStart,0,ZStart,ZSpace) return self end @@ -778,7 +778,7 @@ end -- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group. function AI_FORMATION:onafterFormationLeftWing( FollowGroupSet, From , Event , To, XStart, XSpace, YStart, ZStart, ZSpace ) --R2.1 - self:onafterFormationLine(FollowGroupSet,From,Event,To,XStart,XSpace,YStart,0,ZStart,ZSpace) + self:onafterFormationLine(FollowGroupSet,From,Event,To,XStart,XSpace,YStart,0,-ZStart,-ZSpace) return self end @@ -798,7 +798,7 @@ end -- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group. function AI_FORMATION:onafterFormationRightWing( FollowGroupSet, From , Event , To, XStart, XSpace, YStart, ZStart, ZSpace ) --R2.1 - self:onafterFormationLine(FollowGroupSet,From,Event,To,XStart,XSpace,YStart,0,-ZStart,-ZSpace) + self:onafterFormationLine(FollowGroupSet,From,Event,To,XStart,XSpace,YStart,0,ZStart,ZSpace) return self end diff --git a/Moose Development/Moose/Core/Point.lua b/Moose Development/Moose/Core/Point.lua index a0cebabb4..8e14da386 100644 --- a/Moose Development/Moose/Core/Point.lua +++ b/Moose Development/Moose/Core/Point.lua @@ -2050,7 +2050,7 @@ do -- COORDINATE -- * Uses default settings in COORDINATE. -- * Can be overridden if for a GROUP containing x clients, a menu was selected to override the default. -- @param #COORDINATE self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable + -- @param Wrapper.Controllable#CONTROLLABLE Controllable The controllable to retrieve the settings from, otherwise the default settings will be chosen. -- @param Core.Settings#SETTINGS Settings (optional) The settings. Can be nil, and in this case the default settings are used. If you want to specify your own settings, use the _SETTINGS object. -- @param Tasking.Task#TASK Task The task for which coordinates need to be calculated. -- @return #string The coordinate Text in the configured coordinate system. diff --git a/Moose Development/Moose/Core/Set.lua b/Moose Development/Moose/Core/Set.lua index 5a5f47adb..f0e24adf5 100644 --- a/Moose Development/Moose/Core/Set.lua +++ b/Moose Development/Moose/Core/Set.lua @@ -924,7 +924,40 @@ do -- SET_GROUP return AliveSet.Set or {} end + + --- Returns a report of of unit types. + -- @param #SET_GROUP self + -- @return Core.Report#REPORT A report of the unit types found. The key is the UnitTypeName and the value is the amount of unit types found. + function SET_GROUP:GetUnitTypeNames() + self:F2() + local MT = {} -- Message Text + local UnitTypes = {} + + local ReportUnitTypes = REPORT:New() + + for GroupID, GroupData in pairs( self:GetSet() ) do + local Units = GroupData:GetUnits() + for UnitID, UnitData in pairs( Units ) do + if UnitData:IsAlive() then + local UnitType = UnitData:GetTypeName() + + if not UnitTypes[UnitType] then + UnitTypes[UnitType] = 1 + else + UnitTypes[UnitType] = UnitTypes[UnitType] + 1 + end + end + end + end + + for UnitTypeID, UnitType in pairs( UnitTypes ) do + ReportUnitTypes:Add( UnitType .. " of " .. UnitTypeID ) + end + + return ReportUnitTypes + end + --- Add a GROUP to SET_GROUP. -- Note that for each unit in the group that is set, a default cargo bay limit is initialized. -- @param Core.Set#SET_GROUP self diff --git a/Moose Development/Moose/Core/Spawn.lua b/Moose Development/Moose/Core/Spawn.lua index d65aae7a2..6724e1b89 100644 --- a/Moose Development/Moose/Core/Spawn.lua +++ b/Moose Development/Moose/Core/Spawn.lua @@ -1156,6 +1156,18 @@ function SPAWN:ReSpawn( SpawnIndex ) return SpawnGroup end + +--- Set the spawn index to a specified index number. +-- This method can be used to "reset" the spawn counter to a specific index number. +-- This will actually enable a respawn of groups from the specific index. +-- @param #SPAWN self +-- @param #string SpawnIndex The index of the group from where the spawning will start again. The default value would be 0, which means a complete reset of the spawnindex. +-- @return #SPAWN self +function SPAWN:SetSpawnIndex( SpawnIndex ) + self.SpawnIndex = SpawnIndex or 0 +end + + --- Will spawn a group with a specified index number. -- Uses @{DATABASE} global object defined in MOOSE. -- @param #SPAWN self @@ -1465,6 +1477,11 @@ function SPAWN:SpawnAtAirbase( SpawnAirbase, Takeoff, TakeoffAltitude, TerminalT local SpawnTemplate = self.SpawnGroups[self.SpawnIndex].SpawnTemplate if SpawnTemplate then + + -- Check if the aircraft with the specified SpawnIndex is already spawned. + -- If yes, ensure that the aircraft is spawned at the same aircraft spot. + + local GroupAlive = self:GetGroupFromIndex( self.SpawnIndex ) -- Debug output self:T( { "Current point of ", self.SpawnTemplatePrefix, SpawnAirbase } ) @@ -1535,7 +1552,8 @@ function SPAWN:SpawnAtAirbase( SpawnAirbase, Takeoff, TakeoffAltitude, TerminalT local spots -- Spawn happens on ground, i.e. at an airbase, a FARP or a ship. - if spawnonground then + if spawnonground and not SpawnTemplate.parked then + -- Number of free parking spots. local nfree=0 @@ -1708,67 +1726,72 @@ function SPAWN:SpawnAtAirbase( SpawnAirbase, Takeoff, TakeoffAltitude, TerminalT end - -- Translate the position of the Group Template to the Vec3. - for UnitID = 1, nunits do - self:T2('Before Translation SpawnTemplate.units['..UnitID..'].x = '..SpawnTemplate.units[UnitID].x..', SpawnTemplate.units['..UnitID..'].y = '..SpawnTemplate.units[UnitID].y) - - -- Template of the current unit. - local UnitTemplate = SpawnTemplate.units[UnitID] - - -- Tranlate position and preserve the relative position/formation of all aircraft. - local SX = UnitTemplate.x - local SY = UnitTemplate.y - local BX = SpawnTemplate.route.points[1].x - local BY = SpawnTemplate.route.points[1].y - local TX = PointVec3.x + (SX-BX) - local TY = PointVec3.z + (SY-BY) - - if spawnonground then - - -- Ships and FARPS seem to have a build in queue. - if spawnonship or spawnonfarp or spawnonrunway then - - self:T(string.format("Group %s spawning at farp, ship or runway %s.", self.SpawnTemplatePrefix, SpawnAirbase:GetName())) + if not SpawnTemplate.parked then + -- Translate the position of the Group Template to the Vec3. - -- Spawn on ship. We take only the position of the ship. - SpawnTemplate.units[UnitID].x = PointVec3.x --TX - SpawnTemplate.units[UnitID].y = PointVec3.z --TY - SpawnTemplate.units[UnitID].alt = PointVec3.y - - else + SpawnTemplate.parked = true - self:T(string.format("Group %s spawning at airbase %s on parking spot id %d", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), parkingindex[UnitID])) - - -- Get coordinates of parking spot. - SpawnTemplate.units[UnitID].x = parkingspots[UnitID].x - SpawnTemplate.units[UnitID].y = parkingspots[UnitID].z - SpawnTemplate.units[UnitID].alt = parkingspots[UnitID].y - - --parkingspots[UnitID]:MarkToAll(string.format("Group %s spawning at airbase %s on parking spot id %d", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), parkingindex[UnitID])) - end + for UnitID = 1, nunits do + self:T2('Before Translation SpawnTemplate.units['..UnitID..'].x = '..SpawnTemplate.units[UnitID].x..', SpawnTemplate.units['..UnitID..'].y = '..SpawnTemplate.units[UnitID].y) + + -- Template of the current unit. + local UnitTemplate = SpawnTemplate.units[UnitID] + + -- Tranlate position and preserve the relative position/formation of all aircraft. + local SX = UnitTemplate.x + local SY = UnitTemplate.y + local BX = SpawnTemplate.route.points[1].x + local BY = SpawnTemplate.route.points[1].y + local TX = PointVec3.x + (SX-BX) + local TY = PointVec3.z + (SY-BY) - else - - self:T(string.format("Group %s spawning in air at %s.", self.SpawnTemplatePrefix, SpawnAirbase:GetName())) + if spawnonground then + + -- Ships and FARPS seem to have a build in queue. + if spawnonship or spawnonfarp or spawnonrunway then + + self:T(string.format("Group %s spawning at farp, ship or runway %s.", self.SpawnTemplatePrefix, SpawnAirbase:GetName())) + + -- Spawn on ship. We take only the position of the ship. + SpawnTemplate.units[UnitID].x = PointVec3.x --TX + SpawnTemplate.units[UnitID].y = PointVec3.z --TY + SpawnTemplate.units[UnitID].alt = PointVec3.y + + else + + self:T(string.format("Group %s spawning at airbase %s on parking spot id %d", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), parkingindex[UnitID])) + + -- Get coordinates of parking spot. + SpawnTemplate.units[UnitID].x = parkingspots[UnitID].x + SpawnTemplate.units[UnitID].y = parkingspots[UnitID].z + SpawnTemplate.units[UnitID].alt = parkingspots[UnitID].y + + --parkingspots[UnitID]:MarkToAll(string.format("Group %s spawning at airbase %s on parking spot id %d", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), parkingindex[UnitID])) + end + + else - -- Spawn in air as requested initially. Original template orientation is perserved, altitude is already correctly set. - SpawnTemplate.units[UnitID].x = TX - SpawnTemplate.units[UnitID].y = TY - SpawnTemplate.units[UnitID].alt = PointVec3.y + self:T(string.format("Group %s spawning in air at %s.", self.SpawnTemplatePrefix, SpawnAirbase:GetName())) + + -- Spawn in air as requested initially. Original template orientation is perserved, altitude is already correctly set. + SpawnTemplate.units[UnitID].x = TX + SpawnTemplate.units[UnitID].y = TY + SpawnTemplate.units[UnitID].alt = PointVec3.y + + end + + -- Parking spot id. + UnitTemplate.parking = nil + UnitTemplate.parking_id = nil + if parkingindex[UnitID] then + UnitTemplate.parking = parkingindex[UnitID] + end + -- Debug output. + self:T2(string.format("Group %s unit number %d: Parking = %s",self.SpawnTemplatePrefix, UnitID, tostring(UnitTemplate.parking))) + self:T2(string.format("Group %s unit number %d: Parking ID = %s",self.SpawnTemplatePrefix, UnitID, tostring(UnitTemplate.parking_id))) + self:T2('After Translation SpawnTemplate.units['..UnitID..'].x = '..SpawnTemplate.units[UnitID].x..', SpawnTemplate.units['..UnitID..'].y = '..SpawnTemplate.units[UnitID].y) end - - -- Parking spot id. - UnitTemplate.parking = nil - UnitTemplate.parking_id = nil - if parkingindex[UnitID] then - UnitTemplate.parking = parkingindex[UnitID] - end - - -- Debug output. - self:T2(string.format("Group %s unit number %d: Parking = %s",self.SpawnTemplatePrefix, UnitID, tostring(UnitTemplate.parking))) - self:T2(string.format("Group %s unit number %d: Parking ID = %s",self.SpawnTemplatePrefix, UnitID, tostring(UnitTemplate.parking_id))) - self:T2('After Translation SpawnTemplate.units['..UnitID..'].x = '..SpawnTemplate.units[UnitID].x..', SpawnTemplate.units['..UnitID..'].y = '..SpawnTemplate.units[UnitID].y) end -- Set gereral spawnpoint position. @@ -2088,7 +2111,7 @@ end function SPAWN:InitUnControlled( UnControlled ) self:F2( { self.SpawnTemplatePrefix, UnControlled } ) - self.SpawnUnControlled = UnControlled or true + self.SpawnUnControlled = ( UnControlled == true ) and true or nil for SpawnGroupID = 1, self.SpawnMaxGroups do self.SpawnGroups[SpawnGroupID].UnControlled = self.SpawnUnControlled From 315d6bf82a1ae4fafc5085acc223caefb1970848 Mon Sep 17 00:00:00 2001 From: FlightControl Date: Tue, 23 Apr 2019 20:33:21 +0300 Subject: [PATCH 06/25] ParkAtAirbase new method. --- Moose Development/Moose/Core/Spawn.lua | 364 +++++++++++++++++++++++++ 1 file changed, 364 insertions(+) diff --git a/Moose Development/Moose/Core/Spawn.lua b/Moose Development/Moose/Core/Spawn.lua index 6724e1b89..615bfcffe 100644 --- a/Moose Development/Moose/Core/Spawn.lua +++ b/Moose Development/Moose/Core/Spawn.lua @@ -1824,6 +1824,370 @@ function SPAWN:SpawnAtAirbase( SpawnAirbase, Takeoff, TakeoffAltitude, TerminalT return nil end + +--- Will park a group at an @{Wrapper.Airbase}. +-- This method is mostly advisable to be used if you want to simulate parking units at an airbase and be visible. +-- Note that each point in the route assigned to the spawning group is reset to the point of the spawn. +-- +-- All groups that are in the spawn collection and that are alive, and not in the air, are parked. +-- +-- The @{Wrapper.Airbase#AIRBASE} object must refer to a valid airbase known in the sim. +-- You can use the following enumerations to search for the pre-defined airbases on the current known maps of DCS: +-- +-- * @{Wrapper.Airbase#AIRBASE.Caucasus}: The airbases on the Caucasus map. +-- * @{Wrapper.Airbase#AIRBASE.Nevada}: The airbases on the Nevada (NTTR) map. +-- * @{Wrapper.Airbase#AIRBASE.Normandy}: The airbases on the Normandy map. +-- +-- Use the method @{Wrapper.Airbase#AIRBASE.FindByName}() to retrieve the airbase object. +-- The known AIRBASE objects are automatically imported at mission start by MOOSE. +-- Therefore, there isn't any New() constructor defined for AIRBASE objects. +-- +-- Ships and Farps are added within the mission, and are therefore not known. +-- For these AIRBASE objects, there isn't an @{Wrapper.Airbase#AIRBASE} enumeration defined. +-- You need to provide the **exact name** of the airbase as the parameter to the @{Wrapper.Airbase#AIRBASE.FindByName}() method! +-- +-- @param #SPAWN self +-- @param Wrapper.Airbase#AIRBASE SpawnAirbase The @{Wrapper.Airbase} where to spawn the group. +-- @param Wrapper.Airbase#AIRBASE.TerminalType TerminalType (optional) The terminal type the aircraft should be spawned at. See @{Wrapper.Airbase#AIRBASE.TerminalType}. +-- @param #table Parkingdata (optional) Table holding the coordinates and terminal ids for all units of the group. Spawning will be forced to happen at exactily these spots! +-- @return #nil Nothing is returned! +-- @usage +-- Spawn_Plane = SPAWN:New( "Plane" ) +-- Spawn_Plane:ParkAtAirbase( AIRBASE:FindByName( AIRBASE.Caucasus.Krymsk ) ) +-- +-- Spawn_Heli = SPAWN:New( "Heli") +-- +-- Spawn_Heli:ParkAtAirbase( AIRBASE:FindByName( "FARP Cold" ) ) +-- +-- Spawn_Heli:ParkAtAirbase( AIRBASE:FindByName( "Carrier" ) ) +-- +-- Spawn_Plane:ParkAtAirbase( AIRBASE:FindByName( AIRBASE.Caucasus.Krymsk ), AIRBASE.TerminalType.OpenBig ) +-- +function SPAWN:ParkAtAirbase( SpawnAirbase, TerminalType, Parkingdata ) -- R2.2, R2.4, R2.5 + self:F( { self.SpawnTemplatePrefix, SpawnAirbase, TerminalType } ) + + -- Get position of airbase. + local PointVec3 = SpawnAirbase:GetCoordinate() + self:T2(PointVec3) + + -- Set take off type. Default is hot. + local Takeoff = SPAWN.Takeoff.Cold + + for SpawnIndex = 1, self.SpawnMaxGroups do + + -- Get group template. + local SpawnTemplate = self.SpawnGroups[SpawnIndex].SpawnTemplate + + if SpawnTemplate then + + -- Check if the aircraft with the specified SpawnIndex is already spawned. + -- If yes, ensure that the aircraft is spawned at the same aircraft spot. + + local GroupAlive = self:GetGroupFromIndex( SpawnIndex ) + + -- Debug output + self:T( { "Current point of ", self.SpawnTemplatePrefix, SpawnAirbase } ) + + -- Template group, unit and its attributes. + local TemplateGroup = GROUP:FindByName(self.SpawnTemplatePrefix) + local TemplateUnit=TemplateGroup:GetUnit(1) + local ishelo=TemplateUnit:HasAttribute("Helicopters") + local isbomber=TemplateUnit:HasAttribute("Bombers") + local istransport=TemplateUnit:HasAttribute("Transports") + local isfighter=TemplateUnit:HasAttribute("Battleplanes") + + -- Number of units in the group. With grouping this can actually differ from the template group size! + local nunits=#SpawnTemplate.units + + -- First waypoint of the group. + local SpawnPoint = SpawnTemplate.route.points[1] + + -- These are only for ships and FARPS. + SpawnPoint.linkUnit = nil + SpawnPoint.helipadId = nil + SpawnPoint.airdromeId = nil + + -- Get airbase ID and category. + local AirbaseID = SpawnAirbase:GetID() + local AirbaseCategory = SpawnAirbase:GetDesc().category + self:F( { AirbaseCategory = AirbaseCategory } ) + + -- Set airdromeId. + if AirbaseCategory == Airbase.Category.SHIP then + SpawnPoint.linkUnit = AirbaseID + SpawnPoint.helipadId = AirbaseID + elseif AirbaseCategory == Airbase.Category.HELIPAD then + SpawnPoint.linkUnit = AirbaseID + SpawnPoint.helipadId = AirbaseID + elseif AirbaseCategory == Airbase.Category.AIRDROME then + SpawnPoint.airdromeId = AirbaseID + end + + -- Set waypoint type/action. + SpawnPoint.alt = 0 + SpawnPoint.type = GROUPTEMPLATE.Takeoff[Takeoff][1] -- type + SpawnPoint.action = GROUPTEMPLATE.Takeoff[Takeoff][2] -- action + + -- Check if we spawn on ground. + local spawnonground=not (Takeoff==SPAWN.Takeoff.Air) + self:T({spawnonground=spawnonground, TOtype=Takeoff, TOair=Takeoff==SPAWN.Takeoff.Air}) + + -- Check where we actually spawn if we spawn on ground. + local spawnonship=false + local spawnonfarp=false + local spawnonrunway=false + local spawnonairport=false + if spawnonground then + if AirbaseCategory == Airbase.Category.SHIP then + spawnonship=true + elseif AirbaseCategory == Airbase.Category.HELIPAD then + spawnonfarp=true + elseif AirbaseCategory == Airbase.Category.AIRDROME then + spawnonairport=true + end + spawnonrunway=Takeoff==SPAWN.Takeoff.Cold + end + + -- Array with parking spots coordinates. + local parkingspots={} + local parkingindex={} + local spots + + -- Spawn happens on ground, i.e. at an airbase, a FARP or a ship. + if spawnonground and not SpawnTemplate.parked then + + + -- Number of free parking spots. + local nfree=0 + + -- Set terminal type. + local termtype=TerminalType + + -- Scan options. Might make that input somehow. + local scanradius=50 + local scanunits=true + local scanstatics=true + local scanscenery=false + local verysafe=false + + -- Number of free parking spots at the airbase. + if spawnonship or spawnonfarp or spawnonrunway then + -- These places work procedural and have some kind of build in queue ==> Less effort. + self:T(string.format("Group %s is spawned on farp/ship/runway %s.", self.SpawnTemplatePrefix, SpawnAirbase:GetName())) + nfree=SpawnAirbase:GetFreeParkingSpotsNumber(termtype, true) + spots=SpawnAirbase:GetFreeParkingSpotsTable(termtype, true) + elseif Parkingdata~=nil then + -- Parking data explicitly set by user as input parameter. + nfree=#Parkingdata + spots=Parkingdata + else + if ishelo then + if termtype==nil then + -- Helo is spawned. Try exclusive helo spots first. + self:T(string.format("Helo group %s is at %s using terminal type %d.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), AIRBASE.TerminalType.HelicopterOnly)) + spots=SpawnAirbase:FindFreeParkingSpotForAircraft(TemplateGroup, AIRBASE.TerminalType.HelicopterOnly, scanradius, scanunits, scanstatics, scanscenery, verysafe, nunits) + nfree=#spots + if nfree=1 then + + -- All units get the same spot. DCS takes care of the rest. + for i=1,nunits do + table.insert(parkingspots, spots[1].Coordinate) + table.insert(parkingindex, spots[1].TerminalID) + end + -- This is actually used... + PointVec3=spots[1].Coordinate + + else + -- If there is absolutely no spot ==> air start! + _notenough=true + end + + elseif spawnonairport then + + if nfree>=nunits then + + for i=1,nunits do + table.insert(parkingspots, spots[i].Coordinate) + table.insert(parkingindex, spots[i].TerminalID) + end + + else + -- Not enough spots for the whole group ==> air start! + _notenough=true + end + end + + -- Not enough spots ==> Prepare airstart. + if _notenough then + + if not self.SpawnUnControlled then + else + self:E(string.format("WARNING: Group %s has no parking spots at %s ==> No emergency air start or uncontrolled spawning ==> No spawn!", self.SpawnTemplatePrefix, SpawnAirbase:GetName())) + return nil + end + end + + else + + end + + if not SpawnTemplate.parked then + -- Translate the position of the Group Template to the Vec3. + + SpawnTemplate.parked = true + + for UnitID = 1, nunits do + self:T2('Before Translation SpawnTemplate.units['..UnitID..'].x = '..SpawnTemplate.units[UnitID].x..', SpawnTemplate.units['..UnitID..'].y = '..SpawnTemplate.units[UnitID].y) + + -- Template of the current unit. + local UnitTemplate = SpawnTemplate.units[UnitID] + + -- Tranlate position and preserve the relative position/formation of all aircraft. + local SX = UnitTemplate.x + local SY = UnitTemplate.y + local BX = SpawnTemplate.route.points[1].x + local BY = SpawnTemplate.route.points[1].y + local TX = PointVec3.x + (SX-BX) + local TY = PointVec3.z + (SY-BY) + + if spawnonground then + + -- Ships and FARPS seem to have a build in queue. + if spawnonship or spawnonfarp or spawnonrunway then + + self:T(string.format("Group %s spawning at farp, ship or runway %s.", self.SpawnTemplatePrefix, SpawnAirbase:GetName())) + + -- Spawn on ship. We take only the position of the ship. + SpawnTemplate.units[UnitID].x = PointVec3.x --TX + SpawnTemplate.units[UnitID].y = PointVec3.z --TY + SpawnTemplate.units[UnitID].alt = PointVec3.y + + else + + self:T(string.format("Group %s spawning at airbase %s on parking spot id %d", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), parkingindex[UnitID])) + + -- Get coordinates of parking spot. + SpawnTemplate.units[UnitID].x = parkingspots[UnitID].x + SpawnTemplate.units[UnitID].y = parkingspots[UnitID].z + SpawnTemplate.units[UnitID].alt = parkingspots[UnitID].y + + --parkingspots[UnitID]:MarkToAll(string.format("Group %s spawning at airbase %s on parking spot id %d", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), parkingindex[UnitID])) + end + + else + + self:T(string.format("Group %s spawning in air at %s.", self.SpawnTemplatePrefix, SpawnAirbase:GetName())) + + -- Spawn in air as requested initially. Original template orientation is perserved, altitude is already correctly set. + SpawnTemplate.units[UnitID].x = TX + SpawnTemplate.units[UnitID].y = TY + SpawnTemplate.units[UnitID].alt = PointVec3.y + + end + + -- Parking spot id. + UnitTemplate.parking = nil + UnitTemplate.parking_id = nil + if parkingindex[UnitID] then + UnitTemplate.parking = parkingindex[UnitID] + end + + -- Debug output. + self:T2(string.format("Group %s unit number %d: Parking = %s",self.SpawnTemplatePrefix, UnitID, tostring(UnitTemplate.parking))) + self:T2(string.format("Group %s unit number %d: Parking ID = %s",self.SpawnTemplatePrefix, UnitID, tostring(UnitTemplate.parking_id))) + self:T2('After Translation SpawnTemplate.units['..UnitID..'].x = '..SpawnTemplate.units[UnitID].x..', SpawnTemplate.units['..UnitID..'].y = '..SpawnTemplate.units[UnitID].y) + end + end + + -- Set gereral spawnpoint position. + SpawnPoint.x = PointVec3.x + SpawnPoint.y = PointVec3.z + SpawnPoint.alt = PointVec3.y + + SpawnTemplate.x = PointVec3.x + SpawnTemplate.y = PointVec3.z + + -- Spawn group. + local GroupSpawned = self:SpawnWithIndex( SpawnIndex ) + + -- When spawned in the air, we need to generate a Takeoff Event. + if Takeoff == GROUP.Takeoff.Air then + for UnitID, UnitSpawned in pairs( GroupSpawned:GetUnits() ) do + SCHEDULER:New( nil, BASE.CreateEventTakeoff, { GroupSpawned, timer.getTime(), UnitSpawned:GetDCSObject() } , 5 ) + end + end + + -- Check if we accidentally spawned on the runway. Needs to be schedules, because group is not immidiately alive. + if Takeoff~=SPAWN.Takeoff.Runway and Takeoff~=SPAWN.Takeoff.Air and spawnonairport then + SCHEDULER:New(nil, AIRBASE.CheckOnRunWay, {SpawnAirbase, GroupSpawned, 75, true} , 1.0) + end + + return GroupSpawned + end + end + + return nil +end + --- Will spawn a group from a Vec3 in 3D space. -- This method is mostly advisable to be used if you want to simulate spawning units in the air, like helicopters or airplanes. -- Note that each point in the route assigned to the spawning group is reset to the point of the spawn. From b4d6f78e42587b7a4c6a8dea1b4d743693cc855a Mon Sep 17 00:00:00 2001 From: FlightControl Date: Thu, 25 Apr 2019 08:59:07 +0300 Subject: [PATCH 07/25] WIP, need to make a new class next week, AI_ESCORT_REQUEST. Need to solve the issue with the formation flying uof multiple escort classes working together. Planes may not crash into each other. --- Moose Development/Moose/AI/AI_Escort.lua | 275 +++----------------- Moose Development/Moose/AI/AI_Formation.lua | 6 +- Moose Development/Moose/Core/Spawn.lua | 36 ++- Moose Development/Moose/Modules.lua | 1 + Moose Development/Moose/Utilities/Enums.lua | 9 + 5 files changed, 78 insertions(+), 249 deletions(-) create mode 100644 Moose Development/Moose/Utilities/Enums.lua diff --git a/Moose Development/Moose/AI/AI_Escort.lua b/Moose Development/Moose/AI/AI_Escort.lua index 784799ef9..59932b443 100644 --- a/Moose Development/Moose/AI/AI_Escort.lua +++ b/Moose Development/Moose/AI/AI_Escort.lua @@ -250,7 +250,7 @@ function AI_ESCORT:New( EscortUnit, EscortGroupSet, EscortName, EscortBriefing ) self.GT1 = 0 - self.FlightMenu = MENU_GROUP:New( self.EscortUnit:GetGroup(), "Flight" ) + self.FlightMenu = MENU_GROUP:New( self.EscortUnit:GetGroup(), EscortName ) EscortGroupSet:ForEachGroup( --- @param Core.Group#GROUP EscortGroup @@ -271,17 +271,6 @@ function AI_ESCORT:New( EscortUnit, EscortGroupSet, EscortName, EscortBriefing ) end ) - EscortGroupSet:ForSomeGroup( - --- @param Core.Group#GROUP EscortGroup - function( EscortGroup ) - EscortGroup.EscortMenu = MENU_GROUP:New( self.EscortUnit:GetGroup(), EscortGroup:GetName() ) - end - ) - - - self.Detection = DETECTION_AREAS:New( EscortGroupSet, 5000 ) - - self.Detection:Start() return self end @@ -295,7 +284,7 @@ function AI_ESCORT:onafterStart( EscortGroupSet ) EscortGroupSet:ForEachGroup( --- @param Core.Group#GROUP EscortGroup function( EscortGroup ) - EscortGroup.EscortMenu = MENU_GROUP:New( self.EscortUnit:GetGroup(), EscortGroup:GetName() ) + --EscortGroup.EscortMenu = MENU_GROUP:New( self.EscortUnit:GetGroup(), EscortGroup:GetName() ) EscortGroup:WayPointInitialize( 1 ) EscortGroup:OptionROTVertical() @@ -311,6 +300,10 @@ function AI_ESCORT:onafterStart( EscortGroupSet ) Report:Add( "Joining Up ..." ) LeaderEscort:MessageTypeToGroup( Report:Text(), MESSAGE.Type.Information, self.EscortUnit ) + + self.Detection = DETECTION_AREAS:New( EscortGroupSet, 5000 ) + + self.Detection:__Start( 30 ) end @@ -364,7 +357,7 @@ function AI_ESCORT:Menus() self:MenuReportTargets( 60 ) self:MenuAssistedAttack() self:MenuROE() - self:MenuEvasion() +-- self:MenuEvasion() -- self:MenuResumeMission() @@ -396,21 +389,6 @@ function AI_ESCORT:MenuFormation( Formation, ... ) ) end --- self.EscortGroupSet:ForSomeGroupAlive( --- --- @param Core.Group#GROUP EscortGroup --- function( EscortGroup ) --- if EscortGroup:IsAir() then --- if not EscortGroup.EscortMenuReportNavigation then --- EscortGroup.EscortMenuReportNavigation = MENU_GROUP:New( self.EscortUnit:GetGroup(), "Navigation", EscortGroup.EscortMenu ) --- end --- --- if not EscortGroup["EscortMenuFormation"..Formation] then --- EscortGroup["EscortMenuFormation"..Formation] = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), Formation, EscortGroup.EscortMenuReportNavigation, AI_ESCORT["_EscortFormation"..Formation], self, EscortGroup, ... ) --- end --- end --- end --- ) - end @@ -428,22 +406,6 @@ function AI_ESCORT:MenuJoinUp() self.FlightMenuJoinUp = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), "Join Up", self.FlightMenuReportNavigation, AI_ESCORT._FlightJoinUp, self ) end - self.EscortGroupSet:ForSomeGroupAlive( - --- @param Core.Group#GROUP EscortGroup - function( EscortGroup ) - if EscortGroup:IsAir() then - if not EscortGroup.EscortMenuReportNavigation then - EscortGroup.EscortMenuReportNavigation = MENU_GROUP:New( self.EscortUnit:GetGroup(), "Navigation", EscortGroup.EscortMenu ) - end - - if not EscortGroup.EscortMenuJoinUpAndFollow then - EscortGroup.EscortMenuJoinUpAndFollow = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), "Join-Up", EscortGroup.EscortMenuReportNavigation, ESCORT._JoinUp, self, EscortGroup ) - end - - end - end - ) - return self end @@ -652,36 +614,6 @@ function AI_ESCORT:MenuHoldAtEscortPosition( Height, Speed, MenuTextFormat ) Speed ) - self.EscortGroupSet:ForSomeGroupAlive( - --- @param Core.Group#GROUP EscortGroup - function( EscortGroup ) - if EscortGroup:IsAir() then - - if not EscortGroup.EscortMenuHold then - EscortGroup.EscortMenuHold = MENU_GROUP:New( self.EscortUnit:GetGroup(), "Hold position", EscortGroup.EscortMenu ) - end - - - if not EscortGroup.EscortMenuHoldPosition then - EscortGroup.EscortMenuHoldPosition = {} - end - - EscortGroup.EscortMenuHoldPosition[#EscortGroup.EscortMenuHoldPosition+1] = MENU_GROUP_COMMAND - :New( - self.EscortUnit:GetGroup(), - MenuText, - EscortGroup.EscortMenuHold, - AI_ESCORT._HoldPosition, - self, - EscortGroup, - EscortGroup, - Height, - Speed - ) - end - end - ) - return self end @@ -739,58 +671,6 @@ function AI_ESCORT:MenuHoldAtLeaderPosition( Height, Speed, MenuTextFormat ) Speed ) - self.EscortGroupSet:ForSomeGroupAlive( - --- @param Core.Group#GROUP EscortGroup - function( EscortGroup ) - if EscortGroup:IsAir() then - - if not EscortGroup.EscortMenuHold then - EscortGroup.EscortMenuHold = MENU_GROUP:New( self.EscortUnit:GetGroup(), "Hold position", EscortGroup.EscortMenu ) - end - - if not Height then - Height = 30 - end - - if not Speed then - Speed = 0 - end - - local MenuText = "" - if not MenuTextFormat then - if Speed == 0 then - MenuText = string.format( "Rejoin and hold at %d meter", Height ) - else - MenuText = string.format( "Rejoin and hold at %d meter at %d", Height, Speed ) - end - else - if Speed == 0 then - MenuText = string.format( MenuTextFormat, Height ) - else - MenuText = string.format( MenuTextFormat, Height, Speed ) - end - end - - if not self.EscortMenuHoldAtLeaderPosition then - self.EscortMenuHoldAtLeaderPosition = {} - end - - self.EscortMenuHoldAtLeaderPosition[#self.EscortMenuHoldAtLeaderPosition+1] = MENU_GROUP_COMMAND - :New( - self.EscortUnit:GetGroup(), - MenuText, - EscortGroup.EscortMenuHold, - AI_ESCORT._HoldPosition, - self, - self.EscortUnit:GetGroup(), - EscortGroup, - Height, - Speed - ) - end - end - ) - return self end @@ -880,30 +760,6 @@ function AI_ESCORT:MenuFlare( MenuTextFormat ) self.FlightMenuFlareYellow = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), "Release yellow flare", self.FlightMenuFlare, AI_ESCORT._FlightFlare, self, FLARECOLOR.Yellow, "Released a yellow flare!" ) end - self.EscortGroupSet:ForSomeGroupAlive( - --- @param Core.Group#GROUP EscortGroup - function( EscortGroup ) - if not EscortGroup.EscortMenuReportNavigation then - EscortGroup.EscortMenuReportNavigation = MENU_GROUP:New( self.EscortUnit:GetGroup(), "Navigation", EscortGroup.EscortMenu ) - end - - local MenuText = "" - if not MenuTextFormat then - MenuText = "Flare" - else - MenuText = MenuTextFormat - end - - if not EscortGroup.EscortMenuFlare then - EscortGroup.EscortMenuFlare = MENU_GROUP:New( self.EscortUnit:GetGroup(), MenuText, EscortGroup.EscortMenuReportNavigation ) - EscortGroup.EscortMenuFlareGreen = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), "Release green flare", EscortGroup.EscortMenuFlare, AI_ESCORT._Flare, self, EscortGroup, FLARECOLOR.Green, "Released a green flare!" ) - EscortGroup.EscortMenuFlareRed = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), "Release red flare", EscortGroup.EscortMenuFlare, AI_ESCORT._Flare, self, EscortGroup, FLARECOLOR.Red, "Released a red flare!" ) - EscortGroup.EscortMenuFlareWhite = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), "Release white flare", EscortGroup.EscortMenuFlare, AI_ESCORT._Flare, self, EscortGroup, FLARECOLOR.White, "Released a white flare!" ) - EscortGroup.EscortMenuFlareYellow = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), "Release yellow flare", EscortGroup.EscortMenuFlare, AI_ESCORT._Flare, self, EscortGroup, FLARECOLOR.Yellow, "Released a yellow flare!" ) - end - end - ) - return self end @@ -937,33 +793,6 @@ function AI_ESCORT:MenuSmoke( MenuTextFormat ) self.FlightMenuSmokeBlue = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), "Release blue smoke", self.FlightMenuSmoke, AI_ESCORT._FlightSmoke, self, SMOKECOLOR.Blue, "Releasing blue smoke!" ) end - self.EscortGroupSet:ForSomeGroupAlive( - --- @param Core.Group#GROUP EscortGroup - function( EscortGroup ) - if not EscortGroup:IsAir() then - if not EscortGroup.EscortMenuReportNavigation then - EscortGroup.EscortMenuReportNavigation = MENU_GROUP:New( self.EscortUnit:GetGroup(), "Navigation", EscortGroup.EscortMenu ) - end - - local MenuText = "" - if not MenuTextFormat then - MenuText = "Smoke" - else - MenuText = MenuTextFormat - end - - if not EscortGroup.EscortMenuSmoke then - EscortGroup.EscortMenuSmoke = MENU_GROUP:New( self.EscortUnit:GetGroup(), "Smoke", EscortGroup.EscortMenuReportNavigation ) - EscortGroup.EscortMenuSmokeGreen = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), "Release green smoke", EscortGroup.EscortMenuSmoke, AI_ESCORT._Smoke, self, EscortGroup, SMOKECOLOR.Green, "Releasing green smoke!" ) - EscortGroup.EscortMenuSmokeRed = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), "Release red smoke", EscortGroup.EscortMenuSmoke, AI_ESCORT._Smoke, self, EscortGroup, SMOKECOLOR.Red, "Releasing red smoke!" ) - EscortGroup.EscortMenuSmokeWhite = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), "Release white smoke", EscortGroup.EscortMenuSmoke, AI_ESCORT._Smoke, self, EscortGroup, SMOKECOLOR.White, "Releasing white smoke!" ) - EscortGroup.EscortMenuSmokeOrange = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), "Release orange smoke", EscortGroup.EscortMenuSmoke, AI_ESCORT._Smoke, self, EscortGroup, SMOKECOLOR.Orange, "Releasing orange smoke!" ) - EscortGroup.EscortMenuSmokeBlue = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), "Release blue smoke", EscortGroup.EscortMenuSmoke, AI_ESCORT._Smoke, self, EscortGroup, SMOKECOLOR.Blue, "Releasing blue smoke!" ) - end - end - end - ) - return self end @@ -996,29 +825,6 @@ function AI_ESCORT:MenuReportTargets( Seconds ) self.FlightReportTargetsScheduler = SCHEDULER:New( self, self._FlightReportTargetsScheduler, {}, 5, Seconds ) - self.EscortGroupSet:ForSomeGroupAlive( - --- @param Core.Group#GROUP EscortGroup - function( EscortGroup ) - if EscortGroup:IsAir() then - - if not EscortGroup.EscortMenuReportNearbyTargets then - EscortGroup.EscortMenuReportNearbyTargets = MENU_GROUP:New( self.EscortUnit:GetGroup(), "Report targets", EscortGroup.EscortMenu ) - end - - -- Report Targets - EscortGroup.EscortMenuReportNearbyTargetsNow = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), "Report targets now!", EscortGroup.EscortMenuReportNearbyTargets, AI_ESCORT._ReportNearbyTargetsNow, self, EscortGroup, true ) - EscortGroup.EscortMenuReportNearbyTargetsOn = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), "Report targets on", EscortGroup.EscortMenuReportNearbyTargets, AI_ESCORT._SwitchReportNearbyTargets, self, EscortGroup, true ) - EscortGroup.EscortMenuReportNearbyTargetsOff = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), "Report targets off", EscortGroup.EscortMenuReportNearbyTargets, AI_ESCORT._SwitchReportNearbyTargets, self, EscortGroup, false ) - - -- Attack Targets - EscortGroup.EscortMenuAttackNearbyTargets = MENU_GROUP:New( self.EscortUnit:GetGroup(), "Attack targets", EscortGroup.EscortMenu ) - - EscortGroup.ReportTargetsScheduler = SCHEDULER:New( self, self._ReportTargetsScheduler, { EscortGroup }, timer, Seconds ) - timer=timer+1 - end - end - ) - return self end @@ -1051,28 +857,23 @@ end function AI_ESCORT:MenuROE( MenuTextFormat ) self:F( MenuTextFormat ) - self.EscortGroupSet:ForSomeGroupAlive( - --- @param Core.Group#GROUP EscortGroup - function( EscortGroup ) - if not EscortGroup.EscortMenuROE then - -- Rules of Engagement - EscortGroup.EscortMenuROE = MENU_GROUP:New( self.EscortUnit:GetGroup(), "ROE", EscortGroup.EscortMenu ) - if EscortGroup:OptionROEHoldFirePossible() then - EscortGroup.EscortMenuROEHoldFire = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), "Hold Fire", EscortGroup.EscortMenuROE, AI_ESCORT._ROE, self, EscortGroup, EscortGroup:OptionROEHoldFire(), "Holding weapons!" ) - end - if EscortGroup:OptionROEReturnFirePossible() then - EscortGroup.EscortMenuROEReturnFire = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), "Return Fire", EscortGroup.EscortMenuROE, AI_ESCORT._ROE, self, EscortGroup, EscortGroup:OptionROEReturnFire(), "Returning fire!" ) - end - if EscortGroup:OptionROEOpenFirePossible() then - EscortGroup.EscortMenuROEOpenFire = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), "Open Fire", EscortGroup.EscortMenuROE, AI_ESCORT._ROE, self, EscortGroup, EscortGroup:OptionROEOpenFire(), "Opening fire on designated targets!!" ) - end - if EscortGroup:OptionROEWeaponFreePossible() then - EscortGroup.EscortMenuROEWeaponFree = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), "Weapon Free", EscortGroup.EscortMenuROE, AI_ESCORT._ROE, self, EscortGroup, EscortGroup:OptionROEWeaponFree(), "Opening fire on targets of opportunity!" ) - end - end - end - ) + if not self.FlightMenuROE then + self.FlightMenuROE = MENU_GROUP:New( self.EscortUnit:GetGroup(), "ROE", self.FlightMenu ) + end + if not self.FlightMenuROEHoldFire then + self.FlightMenuROEHoldFire = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), "Hold fire", self.FlightMenuROE, AI_ESCORT._ROE, self, ENUMS.ROE.HoldFire, "Holding weapons!" ) + end + if not self.FlightMenuROEReturnFire then + self.FlightMenuROEReturnFire = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), "Return fire", self.FlightMenuROE, AI_ESCORT._ROE, self, ENUMS.ROE.ReturnFire, "Returning fire!" ) + end + if not self.FlightMenuROEOpenFire then + self.FlightMenuROEOpenFire = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), "Open fire", self.FlightMenuROE, AI_ESCORT._ROE, self, ENUMS.ROE.OpenFire, "Open fire at designated targets!" ) + end + if not self.FlightMenuROEWeaponFree then + self.FlightMenuROEWeaponFree = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), "Engage all targets", self.FlightMenuROE, AI_ESCORT._ROE, self, ENUMS.ROE.WeaponFree, "Engaging all targets!" ) + end + return self end @@ -1318,15 +1119,6 @@ function AI_ESCORT:_FlightSmoke( Color, Message ) end -function AI_ESCORT:_ReportNearbyTargetsNow( EscortGroup ) - - local EscortUnit = self.EscortUnit - - self:_ReportTargetsScheduler( EscortGroup ) - -end - - function AI_ESCORT:_FlightReportNearbyTargetsNow() self:_FlightReportTargetsScheduler() @@ -1522,12 +1314,27 @@ function AI_ESCORT:_AssistTarget( EscortGroup, DetectedItem ) end -function AI_ESCORT:_ROE( EscortGroup, EscortROEFunction, EscortROEMessage ) +function AI_ESCORT:_ROE( EscortAction, EscortROEMessage ) + + self:F({EscortAction=EscortAction,EscortROEMessage=EscortROEMessage}) local EscortUnit = self.EscortUnit - pcall( function() EscortROEFunction() end ) - EscortGroup:MessageTypeToGroup( EscortROEMessage, MESSAGE.Type.Information, EscortUnit:GetGroup() ) + self.EscortGroupSet:ForSomeGroupAlive( + --- @param Wrapper.Group#GROUP EscortGroup + function( EscortGroup ) + if EscortAction == ENUMS.ROE.HoldFire then + EscortGroup:OptionROEHoldFire() + elseif EscortAction == ENUMS.ROE.ReturnFire then + EscortGroup:OptionROEReturnFire() + elseif EscortAction == ENUMS.ROE.OpenFire then + EscortGroup:OptionROEOpenFire() + elseif EscortAction == ENUMS.ROE.WeaponFree then + EscortGroup:OptionROEWeaponFree() + end + EscortGroup:MessageTypeToGroup( EscortROEMessage, MESSAGE.Type.Information, EscortUnit:GetGroup() ) + end + ) end diff --git a/Moose Development/Moose/AI/AI_Formation.lua b/Moose Development/Moose/AI/AI_Formation.lua index e0981a599..5eae434e2 100644 --- a/Moose Development/Moose/AI/AI_Formation.lua +++ b/Moose Development/Moose/AI/AI_Formation.lua @@ -1087,11 +1087,11 @@ function AI_FORMATION:onenterFollowing( FollowGroupSet ) --R2.1 local Speed = - ( Distance + FollowFormation.x ) / Time - if Distance > -4000 then - Speed = - ( Distance + FollowFormation.x ) / 90 + if Distance > -10000 then + Speed = - ( Distance + FollowFormation.x ) / 60 end - if Distance > -1500 then + if Distance > -2500 then Speed = - ( Distance + FollowFormation.x ) / 20 end diff --git a/Moose Development/Moose/Core/Spawn.lua b/Moose Development/Moose/Core/Spawn.lua index 615bfcffe..a7bb1a76f 100644 --- a/Moose Development/Moose/Core/Spawn.lua +++ b/Moose Development/Moose/Core/Spawn.lua @@ -1173,7 +1173,7 @@ end -- @param #SPAWN self -- @param #string SpawnIndex The index of the group to be spawned. -- @return Wrapper.Group#GROUP The group that was spawned. You can use this group for further actions. -function SPAWN:SpawnWithIndex( SpawnIndex ) +function SPAWN:SpawnWithIndex( SpawnIndex, NoBirth ) self:F2( { SpawnTemplatePrefix = self.SpawnTemplatePrefix, SpawnIndex = SpawnIndex, AliveUnits = self.AliveUnits, SpawnMaxGroups = self.SpawnMaxGroups } ) if self:_GetSpawnIndex( SpawnIndex ) then @@ -1275,14 +1275,16 @@ function SPAWN:SpawnWithIndex( SpawnIndex ) SpawnTemplate.CoalitionID = self.SpawnInitCoalition or SpawnTemplate.CoalitionID - if SpawnTemplate.CategoryID == Group.Category.HELICOPTER or SpawnTemplate.CategoryID == Group.Category.AIRPLANE then - if SpawnTemplate.route.points[1].type == "TakeOffParking" then - SpawnTemplate.uncontrolled = self.SpawnUnControlled - end - end +-- if SpawnTemplate.CategoryID == Group.Category.HELICOPTER or SpawnTemplate.CategoryID == Group.Category.AIRPLANE then +-- if SpawnTemplate.route.points[1].type == "TakeOffParking" then +-- SpawnTemplate.uncontrolled = self.SpawnUnControlled +-- end +-- end end - self:HandleEvent( EVENTS.Birth, self._OnBirth ) + if not NoBirth then + self:HandleEvent( EVENTS.Birth, self._OnBirth ) + end self:HandleEvent( EVENTS.Dead, self._OnDeadOrCrash ) self:HandleEvent( EVENTS.Crash, self._OnDeadOrCrash ) self:HandleEvent( EVENTS.RemoveUnit, self._OnDeadOrCrash ) @@ -1471,17 +1473,23 @@ function SPAWN:SpawnAtAirbase( SpawnAirbase, Takeoff, TakeoffAltitude, TerminalT EmergencyAirSpawn=true end + self:F( { SpawnIndex = self.SpawnIndex } ) + if self:_GetSpawnIndex( self.SpawnIndex + 1 ) then -- Get group template. local SpawnTemplate = self.SpawnGroups[self.SpawnIndex].SpawnTemplate + self:F( { SpawnTemplate = SpawnTemplate } ) + if SpawnTemplate then -- Check if the aircraft with the specified SpawnIndex is already spawned. -- If yes, ensure that the aircraft is spawned at the same aircraft spot. local GroupAlive = self:GetGroupFromIndex( self.SpawnIndex ) + + self:F( { GroupAlive = GroupAlive } ) -- Debug output self:T( { "Current point of ", self.SpawnTemplatePrefix, SpawnAirbase } ) @@ -1802,6 +1810,8 @@ function SPAWN:SpawnAtAirbase( SpawnAirbase, Takeoff, TakeoffAltitude, TerminalT SpawnTemplate.x = PointVec3.x SpawnTemplate.y = PointVec3.z + SpawnTemplate.uncontrolled = nil + -- Spawn group. local GroupSpawned = self:SpawnWithIndex( self.SpawnIndex ) @@ -1868,13 +1878,14 @@ function SPAWN:ParkAtAirbase( SpawnAirbase, TerminalType, Parkingdata ) -- R2.2, -- Get position of airbase. local PointVec3 = SpawnAirbase:GetCoordinate() - self:T2(PointVec3) -- Set take off type. Default is hot. local Takeoff = SPAWN.Takeoff.Cold for SpawnIndex = 1, self.SpawnMaxGroups do + self:F( { SpawnIndex = SpawnIndex, SpawnMaxGroups = self.SpawnMaxGroups } ) + -- Get group template. local SpawnTemplate = self.SpawnGroups[SpawnIndex].SpawnTemplate @@ -1945,7 +1956,7 @@ function SPAWN:ParkAtAirbase( SpawnAirbase, TerminalType, Parkingdata ) -- R2.2, elseif AirbaseCategory == Airbase.Category.AIRDROME then spawnonairport=true end - spawnonrunway=Takeoff==SPAWN.Takeoff.Cold + spawnonrunway=Takeoff==SPAWN.Takeoff.Runway end -- Array with parking spots coordinates. @@ -2096,7 +2107,7 @@ function SPAWN:ParkAtAirbase( SpawnAirbase, TerminalType, Parkingdata ) -- R2.2, SpawnTemplate.parked = true for UnitID = 1, nunits do - self:T2('Before Translation SpawnTemplate.units['..UnitID..'].x = '..SpawnTemplate.units[UnitID].x..', SpawnTemplate.units['..UnitID..'].y = '..SpawnTemplate.units[UnitID].y) + self:F('Before Translation SpawnTemplate.units['..UnitID..'].x = '..SpawnTemplate.units[UnitID].x..', SpawnTemplate.units['..UnitID..'].y = '..SpawnTemplate.units[UnitID].y) -- Template of the current unit. local UnitTemplate = SpawnTemplate.units[UnitID] @@ -2166,8 +2177,10 @@ function SPAWN:ParkAtAirbase( SpawnAirbase, TerminalType, Parkingdata ) -- R2.2, SpawnTemplate.x = PointVec3.x SpawnTemplate.y = PointVec3.z + SpawnTemplate.uncontrolled = true + -- Spawn group. - local GroupSpawned = self:SpawnWithIndex( SpawnIndex ) + local GroupSpawned = self:SpawnWithIndex( SpawnIndex, true ) -- When spawned in the air, we need to generate a Takeoff Event. if Takeoff == GROUP.Takeoff.Air then @@ -2181,7 +2194,6 @@ function SPAWN:ParkAtAirbase( SpawnAirbase, TerminalType, Parkingdata ) -- R2.2, SCHEDULER:New(nil, AIRBASE.CheckOnRunWay, {SpawnAirbase, GroupSpawned, 75, true} , 1.0) end - return GroupSpawned end end diff --git a/Moose Development/Moose/Modules.lua b/Moose Development/Moose/Modules.lua index 68e0125d9..42ce0a74e 100644 --- a/Moose Development/Moose/Modules.lua +++ b/Moose Development/Moose/Modules.lua @@ -1,3 +1,4 @@ +__Moose.Include( 'Scripts/Moose/Utilities/Enums.lua' ) __Moose.Include( 'Scripts/Moose/Utilities/Routines.lua' ) __Moose.Include( 'Scripts/Moose/Utilities/Utils.lua' ) diff --git a/Moose Development/Moose/Utilities/Enums.lua b/Moose Development/Moose/Utilities/Enums.lua new file mode 100644 index 000000000..b5f1e0fde --- /dev/null +++ b/Moose Development/Moose/Utilities/Enums.lua @@ -0,0 +1,9 @@ +ENUMS = {} + +ENUMS.ROE = { + HoldFire = 1, + ReturnFire = 2, + OpenFire = 3, + WeaponFree = 4 + } + From ab423b3ba482c7d50ff8e405aa944772b883547e Mon Sep 17 00:00:00 2001 From: FlightControl Date: Thu, 25 Apr 2019 18:52:46 +0200 Subject: [PATCH 08/25] First working version of AI_ESCORT_REQUEST. --- .../Moose/AI/AI_Escort_Request.lua | 278 ++++++++++++++++++ Moose Development/Moose/Core/Spawn.lua | 2 + Moose Development/Moose/Modules.lua | 1 + 3 files changed, 281 insertions(+) create mode 100644 Moose Development/Moose/AI/AI_Escort_Request.lua diff --git a/Moose Development/Moose/AI/AI_Escort_Request.lua b/Moose Development/Moose/AI/AI_Escort_Request.lua new file mode 100644 index 000000000..e16499974 --- /dev/null +++ b/Moose Development/Moose/AI/AI_Escort_Request.lua @@ -0,0 +1,278 @@ +--- **Functional** -- Taking the lead of AI escorting your flight or of other AI, upon request using the menu. +-- +-- === +-- +-- ## Features: +-- +-- * Escort navigation commands. +-- * Escort hold at position commands. +-- * Escorts reporting detected targets. +-- * Escorts scanning targets in advance. +-- * Escorts attacking specific targets. +-- * Request assistance from other groups for attack. +-- * Manage rule of engagement of escorts. +-- * Manage the allowed evasion techniques of escorts. +-- * Make escort to execute a defined mission or path. +-- * Escort tactical situation reporting. +-- +-- === +-- +-- ## Missions: +-- +-- [ESC - Escorting](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/ESC%20-%20Escorting) +-- +-- === +-- +-- Allows you to interact with escorting AI on your flight and take the lead. +-- +-- Each escorting group can be commanded with a complete set of radio commands (radio menu in your flight, and then F10). +-- +-- The radio commands will vary according the category of the group. The richest set of commands are with helicopters and airPlanes. +-- Ships and Ground troops will have a more limited set, but they can provide support through the bombing of targets designated by the other escorts. +-- +-- Escorts detect targets using a built-in detection mechanism. The detected targets are reported at a specified time interval. +-- Once targets are reported, each escort has these targets as menu options to command the attack of these targets. +-- Targets are by default grouped per area of 5000 meters, but the kind of detection and the grouping range can be altered. +-- +-- Different formations can be selected in the Flight menu: Trail, Stack, Left Line, Right Line, Left Wing, Right Wing, Central Wing and Boxed formations are available. +-- The Flight menu also allows for a mass attack, where all of the escorts are commanded to attack a target. +-- +-- Escorts can emit flares to reports their location. They can be commanded to hold at a location, which can be their current or the leader location. +-- In this way, you can spread out the escorts over the battle field before a coordinated attack. +-- +-- But basically, the escort class provides 4 modes of operation, and depending on the mode, you are either leading the flight, or following the flight. +-- +-- ## Leading the flight +-- +-- When leading the flight, you are expected to guide the escorts towards the target areas, +-- and carefully coordinate the attack based on the threat levels reported, and the available weapons +-- carried by the escorts. Ground ships or ground troops can execute A-assisted attacks, when they have long-range ground precision weapons for attack. +-- +-- ## Following the flight +-- +-- Escorts can be commanded to execute a specific mission path. In this mode, the escorts are in the lead. +-- You as a player, are following the escorts, and are commanding them to progress the mission while +-- ensuring that the escorts survive. You are joining the escorts in the battlefield. They will detect and report targets +-- and you will ensure that the attacks are well coordinated, assigning the correct escort type for the detected target +-- type. Once the attack is finished, the escort will resume the mission it was assigned. +-- In other words, you can use the escorts for reconnaissance, and for guiding the attack. +-- Imagine you as a mi-8 pilot, assigned to pickup cargo. Two ka-50s are guiding the way, and you are +-- following. You are in control. The ka-50s detect targets, report them, and you command how the attack +-- will commence and from where. You can control where the escorts are holding position and which targets +-- are attacked first. You are in control how the ka-50s will follow their mission path. +-- +-- Escorts can act as part of a AI A2G dispatcher offensive. In this way, You was a player are in control. +-- The mission is defined by the A2G dispatcher, and you are responsible to join the flight and ensure that the +-- attack is well coordinated. +-- +-- It is with great proud that I present you this class, and I hope you will enjoy the functionality and the dynamism +-- it brings in your DCS world simulations. +-- +-- # RADIO MENUs that can be created: +-- +-- Find a summary below of the current available commands: +-- +-- ## Navigation ...: +-- +-- Escort group navigation functions: +-- +-- * **"Join-Up":** The escort group fill follow you in the assigned formation. +-- * **"Flare":** Provides menu commands to let the escort group shoot a flare in the air in a color. +-- * **"Smoke":** Provides menu commands to let the escort group smoke the air in a color. Note that smoking is only available for ground and naval troops. +-- +-- ## Hold position ...: +-- +-- Escort group navigation functions: +-- +-- * **"At current location":** The escort group will hover above the ground at the position they were. The altitude can be specified as a parameter. +-- * **"At my location":** The escort group will hover or orbit at the position where you are. The escort will fly to your location and hold position. The altitude can be specified as a parameter. +-- +-- ## Report targets ...: +-- +-- Report targets will make the escort group to report any target that it identifies within detection range. Any detected target can be attacked using the "Attack Targets" menu function. (see below). +-- +-- * **"Report now":** Will report the current detected targets. +-- * **"Report targets on":** Will make the escorts to report the detected targets and will fill the "Attack Targets" menu list. +-- * **"Report targets off":** Will stop detecting targets. +-- +-- ## Attack targets ...: +-- +-- This menu item will list all detected targets within a 15km range. Depending on the level of detection (known/unknown) and visuality, the targets type will also be listed. +-- This menu will be available in Flight menu or in each Escort menu. +-- +-- ## Scan targets ...: +-- +-- Menu items to pop-up the escort group for target scanning. After scanning, the escort group will resume with the mission or rejoin formation. +-- +-- * **"Scan targets 30 seconds":** Scan 30 seconds for targets. +-- * **"Scan targets 60 seconds":** Scan 60 seconds for targets. +-- +-- ## Request assistance from ...: +-- +-- This menu item will list all detected targets within a 15km range, similar as with the menu item **Attack Targets**. +-- This menu item allows to request attack support from other ground based escorts supporting the current escort. +-- eg. the function allows a player to request support from the Ship escort to attack a target identified by the Plane escort with its Tomahawk missiles. +-- eg. the function allows a player to request support from other Planes escorting to bomb the unit with illumination missiles or bombs, so that the main plane escort can attack the area. +-- +-- ## ROE ...: +-- +-- Sets the Rules of Engagement (ROE) of the escort group when in flight. +-- +-- * **"Hold Fire":** The escort group will hold fire. +-- * **"Return Fire":** The escort group will return fire. +-- * **"Open Fire":** The escort group will open fire on designated targets. +-- * **"Weapon Free":** The escort group will engage with any target. +-- +-- ## Evasion ...: +-- +-- Will define the evasion techniques that the escort group will perform during flight or combat. +-- +-- * **"Fight until death":** The escort group will have no reaction to threats. +-- * **"Use flares, chaff and jammers":** The escort group will use passive defense using flares and jammers. No evasive manoeuvres are executed. +-- * **"Evade enemy fire":** The rescort group will evade enemy fire before firing. +-- * **"Go below radar and evade fire":** The escort group will perform evasive vertical manoeuvres. +-- +-- ## Resume Mission ...: +-- +-- Escort groups can have their own mission. This menu item will allow the escort group to resume their Mission from a given waypoint. +-- Note that this is really fantastic, as you now have the dynamic of taking control of the escort groups, and allowing them to resume their path or mission. +-- +-- === +-- +-- ### Authors: **FlightControl** +-- +-- === +-- +-- @module AI.AI_Escort +-- @image Escorting.JPG + + + +--- @type AI_ESCORT_REQUEST +-- @extends AI.AI_Formation#AI_FORMATION + +--- AI_ESCORT_REQUEST class +-- +-- # AI_ESCORT_REQUEST construction methods. +-- +-- Create a new AI_ESCORT_REQUEST object with the @{#AI_ESCORT_REQUEST.New} method: +-- +-- * @{#AI_ESCORT_REQUEST.New}: Creates a new AI_ESCORT_REQUEST object from a @{Wrapper.Group#GROUP} for a @{Wrapper.Client#CLIENT}, with an optional briefing text. +-- +-- @usage +-- -- Declare a new EscortPlanes object as follows: +-- +-- -- First find the GROUP object and the CLIENT object. +-- local EscortUnit = CLIENT:FindByName( "Unit Name" ) -- The Unit Name is the name of the unit flagged with the skill Client in the mission editor. +-- local EscortGroup = GROUP:FindByName( "Group Name" ) -- The Group Name is the name of the group that will escort the Escort Client. +-- +-- -- Now use these 2 objects to construct the new EscortPlanes object. +-- EscortPlanes = AI_ESCORT_REQUEST:New( EscortUnit, EscortGroup, "Desert", "Welcome to the mission. You are escorted by a plane with code name 'Desert', which can be instructed through the F10 radio menu." ) +-- +-- @field #AI_ESCORT_REQUEST +AI_ESCORT_REQUEST = { + ClassName = "AI_ESCORT_REQUEST", +} + +--- AI_ESCORT_REQUEST.Mode class +-- @type AI_ESCORT_REQUEST.MODE +-- @field #number FOLLOW +-- @field #number MISSION + +--- MENUPARAM type +-- @type MENUPARAM +-- @field #AI_ESCORT_REQUEST ParamSelf +-- @field #Distance ParamDistance +-- @field #function ParamFunction +-- @field #string ParamMessage + +--- AI_ESCORT_REQUEST class constructor for an AI group +-- @param #AI_ESCORT_REQUEST self +-- @param Wrapper.Client#CLIENT EscortUnit The client escorted by the EscortGroup. +-- @param Core.Spawn#SPAWN EscortSpawn The spawn object of AI, escorting the EscortUnit. +-- @param Wrapper.Airbase#AIRBASE EscortAirbase The airbase where escorts will be spawned once requested. +-- @param #string EscortName Name of the escort. +-- @param #string EscortBriefing A text showing the AI_ESCORT_REQUEST briefing to the player. Note that if no EscortBriefing is provided, the default briefing will be shown. +-- @return #AI_ESCORT_REQUEST self +-- @usage +-- -- Declare a new EscortPlanes object as follows: +-- +-- -- First find the GROUP object and the CLIENT object. +-- local EscortUnit = CLIENT:FindByName( "Unit Name" ) -- The Unit Name is the name of the unit flagged with the skill Client in the mission editor. +-- local EscortGroup = GROUP:FindByName( "Group Name" ) -- The Group Name is the name of the group that will escort the Escort Client. +-- +-- -- Now use these 2 objects to construct the new EscortPlanes object. +-- EscortPlanes = AI_ESCORT_REQUEST:New( EscortUnit, EscortGroup, "Desert", "Welcome to the mission. You are escorted by a plane with code name 'Desert', which can be instructed through the F10 radio menu." ) +function AI_ESCORT_REQUEST:New( EscortUnit, EscortSpawn, EscortAirbase, EscortName, EscortBriefing ) + + self.EscortGroupSet = SET_GROUP:New() + self.EscortSpawn = EscortSpawn + self.EscortAirbase = EscortAirbase + + local self = BASE:Inherit( self, AI_ESCORT:New( EscortUnit, self.EscortGroupSet, EscortName, EscortBriefing ) ) -- #AI_ESCORT_REQUEST + self:F( { EscortUnit } ) + + self.LeaderGroup = self.EscortUnit:GetGroup() + + self.Detection = DETECTION_AREAS:New( self.EscortGroupSet, 5000 ) + self.Detection:__Start( 30 ) + + + return self +end + +--- @param #AI_ESCORT_REQUEST self +-- @param Core.Set#SET_GROUP EscortGroupSet +function AI_ESCORT_REQUEST:SpawnEscort() + + local EscortGroup = self.EscortSpawn:SpawnAtAirbase( self.EscortAirbase, SPAWN.Takeoff.Cold ) + self.EscortGroupSet:AddGroup( EscortGroup ) + + EscortGroup:OptionROTVertical() + EscortGroup:OptionROEHoldFire() + + self:ScheduleOnce( 5, + function() + local LeaderEscort = self.EscortGroupSet:GetFirst() -- Wrapper.Group#GROUP + + local Report = REPORT:New( "Escorts Reporting." ) + Report:Add( "Current coordinate: " .. LeaderEscort:GetCoordinate():ToString( self.EscortUnit ) ) + Report:Add( "Configuration: " .. self.EscortGroupSet:GetUnitTypeNames():Text( ", " ) ) + Report:Add( "Joining Up ..." ) + + LeaderEscort:MessageTypeToGroup( Report:Text(), MESSAGE.Type.Information, self.EscortUnit ) + end + ) + + self:__FormationTrail( 30, 50, 100, 100 ) + self:JoinFormation( EscortGroup ) +end + +--- @param #AI_ESCORT_REQUEST self +-- @param Core.Set#SET_GROUP EscortGroupSet +function AI_ESCORT_REQUEST:onafterStart( EscortGroupSet ) + + self:E("Start") + + EscortGroupSet:ForEachGroup( + --- @param Core.Group#GROUP EscortGroup + function( EscortGroup ) + --EscortGroup.EscortMenu = MENU_GROUP:New( self.EscortUnit:GetGroup(), EscortGroup:GetName() ) + EscortGroup:WayPointInitialize( 1 ) + + EscortGroup:OptionROTVertical() + EscortGroup:OptionROEOpenFire() + end + ) + + if not self.MenuRequestEscort then + self.MenuRequestEscort = MENU_GROUP_COMMAND:New( self.LeaderGroup, "Request A2G Escort", nil, + function() + env.info("call") + self:SpawnEscort() + end + ) + end + +end + diff --git a/Moose Development/Moose/Core/Spawn.lua b/Moose Development/Moose/Core/Spawn.lua index a7bb1a76f..d042f49e6 100644 --- a/Moose Development/Moose/Core/Spawn.lua +++ b/Moose Development/Moose/Core/Spawn.lua @@ -2197,6 +2197,8 @@ function SPAWN:ParkAtAirbase( SpawnAirbase, TerminalType, Parkingdata ) -- R2.2, end end + self:SetSpawnIndex() + return nil end diff --git a/Moose Development/Moose/Modules.lua b/Moose Development/Moose/Modules.lua index 42ce0a74e..43c168b77 100644 --- a/Moose Development/Moose/Modules.lua +++ b/Moose Development/Moose/Modules.lua @@ -86,6 +86,7 @@ __Moose.Include( 'Scripts/Moose/AI/AI_Cas.lua' ) __Moose.Include( 'Scripts/Moose/AI/AI_Bai.lua' ) __Moose.Include( 'Scripts/Moose/AI/AI_Formation.lua' ) __Moose.Include( 'Scripts/Moose/AI/AI_Escort.lua' ) +__Moose.Include( 'Scripts/Moose/AI/AI_Escort_Request.lua' ) __Moose.Include( 'Scripts/Moose/AI/AI_Cargo.lua' ) __Moose.Include( 'Scripts/Moose/AI/AI_Cargo_APC.lua' ) __Moose.Include( 'Scripts/Moose/AI/AI_Cargo_Helicopter.lua' ) From 3657a196457d3512f5f2c57f9bbba2051abc2f50 Mon Sep 17 00:00:00 2001 From: FlightControl Date: Fri, 26 Apr 2019 18:42:42 +0200 Subject: [PATCH 09/25] Updates of working version. --- Moose Development/Moose/AI/AI_Escort.lua | 30 ++++++++++------ .../Moose/AI/AI_Escort_Request.lua | 36 ++++++------------- .../Moose/Functional/Detection.lua | 10 +++--- 3 files changed, 37 insertions(+), 39 deletions(-) diff --git a/Moose Development/Moose/AI/AI_Escort.lua b/Moose Development/Moose/AI/AI_Escort.lua index 59932b443..0ecd87ffe 100644 --- a/Moose Development/Moose/AI/AI_Escort.lua +++ b/Moose Development/Moose/AI/AI_Escort.lua @@ -332,22 +332,29 @@ end --- Defines the default menus -- @param #AI_ESCORT self +-- @param #number XStart The start position on the X-axis in meters for the first group. +-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group. +-- @param #nubmer YStart The start position on the Y-axis in meters for the first group. +-- @param #number YSpace The space between groups on the Y-axis in meters for each sequent group. +-- @param #nubmer ZStart The start position on the Z-axis in meters for the first group. +-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group. +-- @param #number ZLevels The amount of levels on the Z-axis. -- @return #AI_ESCORT -function AI_ESCORT:Menus() +function AI_ESCORT:Menus( XStart, XSpace, YStart, YSpace, ZStart, ZSpace, ZLevels ) self:F() -- self:MenuScanForTargets( 100, 60 ) self:MenuJoinUp() - self:MenuFormationTrail( 50, 100, 50 ) - self:MenuFormationStack( 50, 100, 50, 50 ) - self:MenuFormationLeftLine( 0, 0, 100, 100 ) - self:MenuFormationRightLine( 0, 0, 100, 100 ) - self:MenuFormationLeftWing( 0, 50, 0, 100, 100 ) - self:MenuFormationRightWing( 0, 50, 0, 100, 100 ) - self:MenuFormationCenterWing( 50, 50, 0, 50, 100, 100 ) - self:MenuFormationBox( 50, 100, 0, 50, 50, 100, 10 ) - + self:MenuFormationTrail(XStart,XSpace,YStart) + self:MenuFormationStack(XStart,XSpace,YStart,YSpace) + self:MenuFormationLeftLine(XStart,YStart,ZStart,ZSpace) + self:MenuFormationRightLine(XStart,YStart,ZStart,ZSpace) + self:MenuFormationLeftWing(XStart,XSpace,YStart,ZStart,ZSpace) + self:MenuFormationRightWing(XStart,XSpace,YStart,ZStart,ZSpace) + self:MenuFormationVic(XStart,XSpace,YStart,YSpace,ZStart,ZSpace) + self:MenuFormationBox(XStart,XSpace,YStart,YSpace,ZStart,ZSpace,ZLevels) + self:MenuHoldAtEscortPosition( 1000, 500 ) self:MenuHoldAtLeaderPosition( 1000, 500 ) @@ -1474,6 +1481,9 @@ function AI_ESCORT:_FlightReportTargetsScheduler() local ClientEscortTargets = self.Detection for DetectedItemIndex, DetectedItem in pairs( DetectedItems ) do + + self:F("FlightReportTargetScheduler Targets") + DetectedTargets = true -- There are detected targets, when the content of the for loop is executed. We use it to display a message. diff --git a/Moose Development/Moose/AI/AI_Escort_Request.lua b/Moose Development/Moose/AI/AI_Escort_Request.lua index e16499974..2c6b24e00 100644 --- a/Moose Development/Moose/AI/AI_Escort_Request.lua +++ b/Moose Development/Moose/AI/AI_Escort_Request.lua @@ -195,14 +195,15 @@ AI_ESCORT_REQUEST = { -- @param #string EscortBriefing A text showing the AI_ESCORT_REQUEST briefing to the player. Note that if no EscortBriefing is provided, the default briefing will be shown. -- @return #AI_ESCORT_REQUEST self -- @usage --- -- Declare a new EscortPlanes object as follows: --- --- -- First find the GROUP object and the CLIENT object. --- local EscortUnit = CLIENT:FindByName( "Unit Name" ) -- The Unit Name is the name of the unit flagged with the skill Client in the mission editor. --- local EscortGroup = GROUP:FindByName( "Group Name" ) -- The Group Name is the name of the group that will escort the Escort Client. --- --- -- Now use these 2 objects to construct the new EscortPlanes object. --- EscortPlanes = AI_ESCORT_REQUEST:New( EscortUnit, EscortGroup, "Desert", "Welcome to the mission. You are escorted by a plane with code name 'Desert', which can be instructed through the F10 radio menu." ) +-- EscortSpawn = SPAWN:NewWithAlias( "Red A2G Escort Template", "Red A2G Escort AI" ):InitLimit( 10, 10 ) +-- EscortSpawn:ParkAtAirbase( AIRBASE:FindByName( AIRBASE.Caucasus.Sochi_Adler ), AIRBASE.TerminalType.OpenBig ) +-- +-- local EscortUnit = UNIT:FindByName( "Red A2G Pilot" ) +-- +-- Escort = AI_ESCORT_REQUEST:New( EscortUnit, EscortSpawn, AIRBASE:FindByName(AIRBASE.Caucasus.Sochi_Adler), "A2G", "Briefing" ) +-- Escort:FormationTrail( 50, 100, 100 ) +-- Escort:Menus() +-- Escort:__Start( 5 ) function AI_ESCORT_REQUEST:New( EscortUnit, EscortSpawn, EscortAirbase, EscortName, EscortBriefing ) self.EscortGroupSet = SET_GROUP:New() @@ -210,7 +211,6 @@ function AI_ESCORT_REQUEST:New( EscortUnit, EscortSpawn, EscortAirbase, EscortNa self.EscortAirbase = EscortAirbase local self = BASE:Inherit( self, AI_ESCORT:New( EscortUnit, self.EscortGroupSet, EscortName, EscortBriefing ) ) -- #AI_ESCORT_REQUEST - self:F( { EscortUnit } ) self.LeaderGroup = self.EscortUnit:GetGroup() @@ -241,34 +241,20 @@ function AI_ESCORT_REQUEST:SpawnEscort() Report:Add( "Joining Up ..." ) LeaderEscort:MessageTypeToGroup( Report:Text(), MESSAGE.Type.Information, self.EscortUnit ) + self:FormationTrail( 50, 50, 50 ) + self:JoinFormation( EscortGroup ) end ) - self:__FormationTrail( 30, 50, 100, 100 ) - self:JoinFormation( EscortGroup ) end --- @param #AI_ESCORT_REQUEST self -- @param Core.Set#SET_GROUP EscortGroupSet function AI_ESCORT_REQUEST:onafterStart( EscortGroupSet ) - self:E("Start") - - EscortGroupSet:ForEachGroup( - --- @param Core.Group#GROUP EscortGroup - function( EscortGroup ) - --EscortGroup.EscortMenu = MENU_GROUP:New( self.EscortUnit:GetGroup(), EscortGroup:GetName() ) - EscortGroup:WayPointInitialize( 1 ) - - EscortGroup:OptionROTVertical() - EscortGroup:OptionROEOpenFire() - end - ) - if not self.MenuRequestEscort then self.MenuRequestEscort = MENU_GROUP_COMMAND:New( self.LeaderGroup, "Request A2G Escort", nil, function() - env.info("call") self:SpawnEscort() end ) diff --git a/Moose Development/Moose/Functional/Detection.lua b/Moose Development/Moose/Functional/Detection.lua index fe078643a..133706fb9 100644 --- a/Moose Development/Moose/Functional/Detection.lua +++ b/Moose Development/Moose/Functional/Detection.lua @@ -541,14 +541,17 @@ do -- DETECTION_BASE end - self.DetectionCount = self.DetectionSet:GetSomeIteratorLimit() + self.DetectionCount = self.DetectionSet:Count() - self.DetectionSet:ForSomeGroupAlive( + self.DetectionSet:ForEachGroupAlive( function( DetectionGroup ) self:__Detection( DetectDelay, DetectionGroup, DetectionTimeStamp ) -- Process each detection asynchronously. DetectDelay = DetectDelay + 1 end ) + + self:__Detect( -self.RefreshTimeInterval ) + end --- @param #DETECTION_BASE self @@ -803,10 +806,9 @@ do -- DETECTION_BASE self:__DetectedItem( 0.1, DetectedItem ) end end - - self:__Detect( self.RefreshTimeInterval ) end + end From 1440f6c6268c5b1c3f512be18c5166795cf8b2be Mon Sep 17 00:00:00 2001 From: FlightControl Date: Fri, 3 May 2019 19:11:53 +0200 Subject: [PATCH 10/25] WIP, not for play. --- Moose Development/Moose/AI/AI_Escort.lua | 336 ++++++++++++++---- .../Moose/AI/AI_Escort_Request.lua | 3 +- Moose Development/Moose/Utilities/Enums.lua | 6 + 3 files changed, 281 insertions(+), 64 deletions(-) diff --git a/Moose Development/Moose/AI/AI_Escort.lua b/Moose Development/Moose/AI/AI_Escort.lua index 0ecd87ffe..3d3a9c912 100644 --- a/Moose Development/Moose/AI/AI_Escort.lua +++ b/Moose Development/Moose/AI/AI_Escort.lua @@ -270,8 +270,7 @@ function AI_ESCORT:New( EscortUnit, EscortGroupSet, EscortName, EscortBriefing ) EscortGroup.EscortMode = AI_ESCORT.MODE.FOLLOW end ) - - + return self end @@ -279,12 +278,10 @@ end -- @param Core.Set#SET_GROUP EscortGroupSet function AI_ESCORT:onafterStart( EscortGroupSet ) - self:E("Start") - EscortGroupSet:ForEachGroup( --- @param Core.Group#GROUP EscortGroup function( EscortGroup ) - --EscortGroup.EscortMenu = MENU_GROUP:New( self.EscortUnit:GetGroup(), EscortGroup:GetName() ) + EscortGroup.EscortMenu = MENU_GROUP:New( self.EscortUnit:GetGroup(), EscortGroup:GetName(), self.MainMenu ) EscortGroup:WayPointInitialize( 1 ) EscortGroup:OptionROTVertical() @@ -294,7 +291,7 @@ function AI_ESCORT:onafterStart( EscortGroupSet ) local LeaderEscort = EscortGroupSet:GetFirst() -- Wrapper.Group#GROUP - local Report = REPORT:New( "Escorts Reporting." ) + local Report = REPORT:New( "Escort reporting:" ) Report:Add( "Current coordinate: " .. LeaderEscort:GetCoordinate():ToString( self.EscortUnit ) ) Report:Add( "Configuration: " .. EscortGroupSet:GetUnitTypeNames():Text( ", " ) ) Report:Add( "Joining Up ..." ) @@ -345,15 +342,23 @@ function AI_ESCORT:Menus( XStart, XSpace, YStart, YSpace, ZStart, ZSpace, ZLevel -- self:MenuScanForTargets( 100, 60 ) + self.XStart = XStart or self.XStart + self.XSpace = XSpace or self.XSpace + self.YStart = YStart or self.YStart + self.YSpace = YSpace or self.YSpace + self.ZStart = ZStart or self.ZStart + self.ZSpace = ZSpace or self.ZSpace + self.ZLevels = ZLevels or self.ZLevels + self:MenuJoinUp() - self:MenuFormationTrail(XStart,XSpace,YStart) - self:MenuFormationStack(XStart,XSpace,YStart,YSpace) - self:MenuFormationLeftLine(XStart,YStart,ZStart,ZSpace) - self:MenuFormationRightLine(XStart,YStart,ZStart,ZSpace) - self:MenuFormationLeftWing(XStart,XSpace,YStart,ZStart,ZSpace) - self:MenuFormationRightWing(XStart,XSpace,YStart,ZStart,ZSpace) - self:MenuFormationVic(XStart,XSpace,YStart,YSpace,ZStart,ZSpace) - self:MenuFormationBox(XStart,XSpace,YStart,YSpace,ZStart,ZSpace,ZLevels) + self:MenuFormationTrail(self.XStart,self.XSpace,self.YStart) + self:MenuFormationStack(self.XStart,self.XSpace,self.YStart,self.YSpace) + self:MenuFormationLeftLine(self.XStart,self.YStart,self.ZStart,self.ZSpace) + self:MenuFormationRightLine(self.XStart,self.YStart,self.ZStart,self.ZSpace) + self:MenuFormationLeftWing(self.XStart,self.XSpace,self.YStart,self.ZStart,self.ZSpace) + self:MenuFormationRightWing(self.XStart,self.XSpace,self.YStart,self.ZStart,self.ZSpace) + self:MenuFormationVic(self.XStart,self.XSpace,self.YStart,self.YSpace,self.ZStart,self.ZSpace) + self:MenuFormationBox(self.XStart,self.XSpace,self.YStart,self.YSpace,self.ZStart,self.ZSpace,self.ZLevels) self:MenuHoldAtEscortPosition( 1000, 500 ) self:MenuHoldAtLeaderPosition( 1000, 500 ) @@ -364,7 +369,7 @@ function AI_ESCORT:Menus( XStart, XSpace, YStart, YSpace, ZStart, ZSpace, ZLevel self:MenuReportTargets( 60 ) self:MenuAssistedAttack() self:MenuROE() --- self:MenuEvasion() + self:MenuROT() -- self:MenuResumeMission() @@ -377,7 +382,7 @@ end function AI_ESCORT:MenuFormation( Formation, ... ) if not self.FlightMenuFormation then - self.FlightMenuFormation = MENU_GROUP:New( self.EscortUnit:GetGroup(), "Formation", self.FlightMenu ) + self.FlightMenuFormation = MENU_GROUP:New( self.EscortUnit:GetGroup(), "Formation", self.MainMenu ) end if not self["FlightMenuFormation"..Formation] then @@ -412,6 +417,23 @@ function AI_ESCORT:MenuJoinUp() if not self.FlightMenuJoinUp then self.FlightMenuJoinUp = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), "Join Up", self.FlightMenuReportNavigation, AI_ESCORT._FlightJoinUp, self ) end + + self.EscortGroupSet:ForSomeGroupAlive( + --- @param Core.Group#GROUP EscortGroup + function( EscortGroup ) + if EscortGroup:IsAir() then + EscortGroup.EscortMenu = MENU_GROUP:New( self.EscortUnit:GetGroup(), EscortGroup:GetName(), self.MainMenu ) + if not EscortGroup.EscortMenuReportNavigation then + EscortGroup.EscortMenuReportNavigation = MENU_GROUP:New( self.EscortUnit:GetGroup(), "Navigation", EscortGroup.EscortMenu ) + end + + if not EscortGroup.EscortMenuJoinUpAndFollow then + EscortGroup.EscortMenuJoinUpAndFollow = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), "Join-Up", EscortGroup.EscortMenuReportNavigation, ESCORT._JoinUp, self, EscortGroup ) + end + + end + end + ) return self end @@ -601,25 +623,48 @@ function AI_ESCORT:MenuHoldAtEscortPosition( Height, Speed, MenuTextFormat ) end end - if not self.FlightMenuHold then - self.FlightMenuHold = MENU_GROUP:New( self.EscortUnit:GetGroup(), "Hold position", self.FlightMenu ) + self.FlightMenuHold = self.FlightMenuHold or {} + + if not self.FlightMenuHold[MenuText] then + self.FlightMenuHold[MenuText] = MENU_GROUP:New( self.EscortUnit:GetGroup(), MenuText, self.FlightMenu ) end - if not self.FlightMenuHoldPosition then - self.FlightMenuHoldPosition = {} - end - - self.FlightMenuHoldPosition[#self.FlightMenuHoldPosition+1] = MENU_GROUP_COMMAND + self.FlightMenuHoldPosition = self.FlightMenuHoldPosition or {} + self.FlightMenuHoldPosition[MenuText] = MENU_GROUP_COMMAND :New( self.EscortUnit:GetGroup(), - MenuText, - self.FlightMenuHold, + "Flight", + self.FlightMenuHold[MenuText], AI_ESCORT._FlightHoldPosition, self, nil, Height, Speed ) + + self.EscortGroupSet:ForSomeGroupAlive( + --- @param Core.Group#GROUP EscortGroup + function( EscortGroup ) + if EscortGroup:IsAir() then + + local EscortGroupName = EscortGroup:GetName() + + EscortGroup.EscortMenuHoldPosition = EscortGroup.EscortMenuHoldPosition or {} + EscortGroup.EscortMenuHoldPosition[MenuText] = MENU_GROUP_COMMAND + :New( + self.EscortUnit:GetGroup(), + EscortGroupName, + self.FlightMenuHold[MenuText], + AI_ESCORT._HoldPosition, + self, + EscortGroup, + EscortGroup, + Height, + Speed + ) + end + end + ) return self end @@ -635,10 +680,6 @@ end function AI_ESCORT:MenuHoldAtLeaderPosition( Height, Speed, MenuTextFormat ) self:F( { Height, Speed, MenuTextFormat } ) - if not self.FlightMenuHold then - self.FlightMenuHold = MENU_GROUP:New( self.EscortUnit:GetGroup(), "Hold position", self.FlightMenu ) - end - if not Height then Height = 30 end @@ -662,15 +703,18 @@ function AI_ESCORT:MenuHoldAtLeaderPosition( Height, Speed, MenuTextFormat ) end end - if not self.FlightMenuHoldAtLeaderPosition then - self.FlightMenuHoldAtLeaderPosition = {} + self.FlightMenuHold = self.FlightMenuHold or {} + + if not self.FlightMenuHold[MenuText] then + self.FlightMenuHold[MenuText] = MENU_GROUP:New( self.EscortUnit:GetGroup(), MenuText, self.FlightMenu ) end - self.FlightMenuHoldAtLeaderPosition[#self.FlightMenuHoldAtLeaderPosition+1] = MENU_GROUP_COMMAND + self.FlightMenuHoldAtLeaderPosition = self.FlightMenuHoldAtLeaderPosition or {} + self.FlightMenuHoldAtLeaderPosition[MenuText] = MENU_GROUP_COMMAND :New( self.EscortUnit:GetGroup(), MenuText, - self.FlightMenuHold, + self.FlightMenuHold[MenuText], AI_ESCORT._FlightHoldPosition, self, self.EscortUnit:GetGroup(), @@ -678,6 +722,30 @@ function AI_ESCORT:MenuHoldAtLeaderPosition( Height, Speed, MenuTextFormat ) Speed ) + self.EscortGroupSet:ForSomeGroupAlive( + --- @param Core.Group#GROUP EscortGroup + function( EscortGroup ) + if EscortGroup:IsAir() then + + local EscortGroupName = EscortGroup:GetName() + + EscortGroup.EscortMenuHoldAtLeaderPosition = EscortGroup.EscortMenuHoldAtLeaderPosition or {} + EscortGroup.EscortMenuHoldAtLeaderPosition[MenuText] = MENU_GROUP_COMMAND + :New( + self.EscortUnit:GetGroup(), + EscortGroupName, + self.FlightMenuHold[MenuText], + AI_ESCORT._HoldPosition, + self, + self.EscortUnit:GetGroup(), + EscortGroup, + Height, + Speed + ) + end + end + ) + return self end @@ -767,6 +835,33 @@ function AI_ESCORT:MenuFlare( MenuTextFormat ) self.FlightMenuFlareYellow = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), "Release yellow flare", self.FlightMenuFlare, AI_ESCORT._FlightFlare, self, FLARECOLOR.Yellow, "Released a yellow flare!" ) end + self.EscortGroupSet:ForSomeGroupAlive( + --- @param Core.Group#GROUP EscortGroup + function( EscortGroup ) + + EscortGroup.EscortMenu = MENU_GROUP:New( self.EscortUnit:GetGroup(), EscortGroup:GetName(), self.MainMenu ) + + if not EscortGroup.EscortMenuReportNavigation then + EscortGroup.EscortMenuReportNavigation = MENU_GROUP:New( self.EscortUnit:GetGroup(), "Navigation", EscortGroup.EscortMenu ) + end + + local MenuText = "" + if not MenuTextFormat then + MenuText = "Flare" + else + MenuText = MenuTextFormat + end + + if not EscortGroup.EscortMenuFlare then + EscortGroup.EscortMenuFlare = MENU_GROUP:New( self.EscortUnit:GetGroup(), MenuText, EscortGroup.EscortMenuReportNavigation ) + EscortGroup.EscortMenuFlareGreen = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), "Release green flare", EscortGroup.EscortMenuFlare, AI_ESCORT._Flare, self, EscortGroup, FLARECOLOR.Green, "Released a green flare!" ) + EscortGroup.EscortMenuFlareRed = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), "Release red flare", EscortGroup.EscortMenuFlare, AI_ESCORT._Flare, self, EscortGroup, FLARECOLOR.Red, "Released a red flare!" ) + EscortGroup.EscortMenuFlareWhite = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), "Release white flare", EscortGroup.EscortMenuFlare, AI_ESCORT._Flare, self, EscortGroup, FLARECOLOR.White, "Released a white flare!" ) + EscortGroup.EscortMenuFlareYellow = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), "Release yellow flare", EscortGroup.EscortMenuFlare, AI_ESCORT._Flare, self, EscortGroup, FLARECOLOR.Yellow, "Released a yellow flare!" ) + end + end + ) + return self end @@ -800,6 +895,36 @@ function AI_ESCORT:MenuSmoke( MenuTextFormat ) self.FlightMenuSmokeBlue = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), "Release blue smoke", self.FlightMenuSmoke, AI_ESCORT._FlightSmoke, self, SMOKECOLOR.Blue, "Releasing blue smoke!" ) end + self.EscortGroupSet:ForSomeGroupAlive( + --- @param Core.Group#GROUP EscortGroup + function( EscortGroup ) + if not EscortGroup:IsAir() then + + EscortGroup.EscortMenu = MENU_GROUP:New( self.EscortUnit:GetGroup(), EscortGroup:GetName(), self.MainMenu ) + + if not EscortGroup.EscortMenuReportNavigation then + EscortGroup.EscortMenuReportNavigation = MENU_GROUP:New( self.EscortUnit:GetGroup(), "Navigation", EscortGroup.EscortMenu ) + end + + local MenuText = "" + if not MenuTextFormat then + MenuText = "Smoke" + else + MenuText = MenuTextFormat + end + + if not EscortGroup.EscortMenuSmoke then + EscortGroup.EscortMenuSmoke = MENU_GROUP:New( self.EscortUnit:GetGroup(), "Smoke", EscortGroup.EscortMenuReportNavigation ) + EscortGroup.EscortMenuSmokeGreen = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), "Release green smoke", EscortGroup.EscortMenuSmoke, AI_ESCORT._Smoke, self, EscortGroup, SMOKECOLOR.Green, "Releasing green smoke!" ) + EscortGroup.EscortMenuSmokeRed = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), "Release red smoke", EscortGroup.EscortMenuSmoke, AI_ESCORT._Smoke, self, EscortGroup, SMOKECOLOR.Red, "Releasing red smoke!" ) + EscortGroup.EscortMenuSmokeWhite = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), "Release white smoke", EscortGroup.EscortMenuSmoke, AI_ESCORT._Smoke, self, EscortGroup, SMOKECOLOR.White, "Releasing white smoke!" ) + EscortGroup.EscortMenuSmokeOrange = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), "Release orange smoke", EscortGroup.EscortMenuSmoke, AI_ESCORT._Smoke, self, EscortGroup, SMOKECOLOR.Orange, "Releasing orange smoke!" ) + EscortGroup.EscortMenuSmokeBlue = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), "Release blue smoke", EscortGroup.EscortMenuSmoke, AI_ESCORT._Smoke, self, EscortGroup, SMOKECOLOR.Blue, "Releasing blue smoke!" ) + end + end + end + ) + return self end @@ -819,6 +944,8 @@ function AI_ESCORT:MenuReportTargets( Seconds ) if not Seconds then Seconds = 30 end + + self.FlightMenuReportTargetsInterval = Seconds local timer = 1 @@ -832,6 +959,31 @@ function AI_ESCORT:MenuReportTargets( Seconds ) self.FlightReportTargetsScheduler = SCHEDULER:New( self, self._FlightReportTargetsScheduler, {}, 5, Seconds ) + self.EscortGroupSet:ForSomeGroupAlive( + --- @param Core.Group#GROUP EscortGroup + function( EscortGroup ) + if EscortGroup:IsAir() then + + --EscortGroup.EscortMenuAttackNearbyTargets = MENU_GROUP:New( self.EscortUnit:GetGroup(), EscortGroup:GetName() ) + + --if not EscortGroup.EscortMenuReportNearbyTargets then + -- EscortGroup.EscortMenuReportNearbyTargets = MENU_GROUP:New( self.EscortUnit:GetGroup(), "Report targets", EscortGroup.EscortMenu ) + --end + + -- Report Targets + --EscortGroup.EscortMenuReportNearbyTargetsNow = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), "Report targets now!", EscortGroup.EscortMenuReportNearbyTargets, AI_ESCORT._ReportNearbyTargetsNow, self, EscortGroup, true ) + --EscortGroup.EscortMenuReportNearbyTargetsOn = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), "Report targets on", EscortGroup.EscortMenuReportNearbyTargets, AI_ESCORT._SwitchReportNearbyTargets, self, EscortGroup, true ) + --EscortGroup.EscortMenuReportNearbyTargetsOff = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), "Report targets off", EscortGroup.EscortMenuReportNearbyTargets, AI_ESCORT._SwitchReportNearbyTargets, self, EscortGroup, false ) + + -- Attack Targets + EscortGroup.EscortMenuAttackNearbyTargets = MENU_GROUP:New( self.EscortUnit:GetGroup(), "Attack targets", EscortGroup.EscortMenu ) + + --EscortGroup.ReportTargetsScheduler = SCHEDULER:New( self, self._ReportTargetsScheduler, { EscortGroup }, timer, Seconds ) + timer=timer+1 + end + end + ) + return self end @@ -869,17 +1021,45 @@ function AI_ESCORT:MenuROE( MenuTextFormat ) end if not self.FlightMenuROEHoldFire then - self.FlightMenuROEHoldFire = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), "Hold fire", self.FlightMenuROE, AI_ESCORT._ROE, self, ENUMS.ROE.HoldFire, "Holding weapons!" ) + self.FlightMenuROEHoldFire = MENU_GROUP:New( self.EscortUnit:GetGroup(), "Hold fire", self.FlightMenuROE ) + self.FlightMenuROEHoldFireFlight = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), "Flight", self.FlightMenuROEHoldFire, AI_ESCORT._ROE, self, GROUP.OptionROEHoldFire, "Holding weapons!" ) end if not self.FlightMenuROEReturnFire then - self.FlightMenuROEReturnFire = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), "Return fire", self.FlightMenuROE, AI_ESCORT._ROE, self, ENUMS.ROE.ReturnFire, "Returning fire!" ) + self.FlightMenuROEReturnFire = MENU_GROUP:New( self.EscortUnit:GetGroup(), "Return fire", self.FlightMenuROE ) + self.FlightMenuROEReturnFireFlight = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), "Flight", self.FlightMenuROEReturnFire, AI_ESCORT._ROE, self, GROUP.OptionROEReturnFire, "Returning fire!" ) end if not self.FlightMenuROEOpenFire then - self.FlightMenuROEOpenFire = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), "Open fire", self.FlightMenuROE, AI_ESCORT._ROE, self, ENUMS.ROE.OpenFire, "Open fire at designated targets!" ) + self.FlightMenuROEOpenFire = MENU_GROUP:New( self.EscortUnit:GetGroup(), "Open fire", self.FlightMenuROE ) + self.FlightMenuROEOpenFireFlight = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), "Flight", self.FlightMenuROEOpenFire, AI_ESCORT._ROE, self, GROUP.OptionROEOpenFire, "Open fire at designated targets!" ) end if not self.FlightMenuROEWeaponFree then - self.FlightMenuROEWeaponFree = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), "Engage all targets", self.FlightMenuROE, AI_ESCORT._ROE, self, ENUMS.ROE.WeaponFree, "Engaging all targets!" ) + self.FlightMenuROEWeaponFree = MENU_GROUP:New( self.EscortUnit:GetGroup(), "Engage all targets", self.FlightMenuROE ) + self.FlightMenuROEWeaponFreeFlight = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), "Flight", self.FlightMenuROEWeaponFree, AI_ESCORT._ROE, self, GROUP.OptionROEWeaponFree, "Engaging all targets!" ) end + + self.EscortGroupSet:ForSomeGroupAlive( + --- @param Core.Group#GROUP EscortGroup + function( EscortGroup ) + if not EscortGroup.EscortMenuROE then + -- Rules of Engagement + + local EscortGroupName = EscortGroup:GetName() + + if EscortGroup:OptionROEHoldFirePossible() then + EscortGroup.EscortMenuROEHoldFire = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), EscortGroupName, self.FlightMenuROEHoldFire, AI_ESCORT._ROE, self, EscortGroup, GROUP.OptionROEHoldFire, "Holding weapons!" ) + end + if EscortGroup:OptionROEReturnFirePossible() then + EscortGroup.EscortMenuROEReturnFire = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), EscortGroupName, self.FlightMenuROEReturnFire, AI_ESCORT._ROE, self, EscortGroup, GROUP.OptionROEReturnFire, "Returning fire!" ) + end + if EscortGroup:OptionROEOpenFirePossible() then + EscortGroup.EscortMenuROEOpenFire = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), EscortGroupName, self.FlightMenuROEOpenFire, AI_ESCORT._ROE, self, EscortGroup, GROUP.OptionROEOpenFire, "Opening fire on designated targets!!" ) + end + if EscortGroup:OptionROEWeaponFreePossible() then + EscortGroup.EscortMenuROEWeaponFree = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), EscortGroupName, self.FlightMenuROEWeaponFree, AI_ESCORT._ROE, self, EscortGroup, GROUP.OptionROEWeaponFree, "Opening fire on targets of opportunity!" ) + end + end + end + ) return self end @@ -889,27 +1069,50 @@ end -- All rules of engagement will appear under the menu **Evasion**. -- @param #AI_ESCORT self -- @return #AI_ESCORT -function AI_ESCORT:MenuEvasion( MenuTextFormat ) +function AI_ESCORT:MenuROT( MenuTextFormat ) self:F( MenuTextFormat ) + if not self.FlightMenuROT then + self.FlightMenuROT = MENU_GROUP:New( self.EscortUnit:GetGroup(), "ROT", self.FlightMenu ) + end + + if not self.FlightMenuROTNoReaction then + self.FlightMenuROTNoReaction = MENU_GROUP:New( self.EscortUnit:GetGroup(), "Fight until death", self.FlightMenuROT ) + self.FlightMenuROTNoReactionFlight = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), "Flight", self.FlightMenuROTNoReaction, AI_ESCORT._ROT, self, GROUP.OptionROTNoReaction, "Fighting until death!" ) + end + if not self.FlightMenuROTPassiveDefense then + self.FlightMenuROTPassiveDefense = MENU_GROUP:New( self.EscortUnit:GetGroup(), "Use flares, chaff and jammers", self.FlightMenuROT ) + self.FlightMenuROTPassiveDefenseFlight = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), "Flight", self.FlightMenuROTPassiveDefense, AI_ESCORT._ROT, self, GROUP.OptionROTPassiveDefense, "Defending using jammers, chaff and flares!" ) + end + if not self.FlightMenuROTEvadeFire then + self.FlightMenuROTEvadeFire = MENU_GROUP:New( self.EscortUnit:GetGroup(), "Open fire", self.FlightMenuROT ) + self.FlightMenuROTEvadeFireFlight = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), "Evade enemy fire", self.FlightMenuROTEvadeFire, AI_ESCORT._ROT, self, GROUP.OptionROTEvadeFire, "Evading on enemy fire!" ) + end + if not self.FlightMenuROTVertical then + self.FlightMenuROTVertical = MENU_GROUP:New( self.EscortUnit:GetGroup(), "Avoid radar and evade fire", self.FlightMenuROT ) + self.FlightMenuROTVerticalFlight = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), "Flight", self.FlightMenuROTVertical, AI_ESCORT._ROT, self, GROUP.OptionROTVertical, "Evading on enemy fire with vertical manoeuvres!" ) + end + self.EscortGroupSet:ForSomeGroupAlive( --- @param Core.Group#GROUP EscortGroup function( EscortGroup ) if EscortGroup:IsAir() then + + local EscortGroupName = EscortGroup:GetName() + if not EscortGroup.EscortMenuEvasion then -- Reaction to Threats - EscortGroup.EscortMenuEvasion = MENU_GROUP:New( self.EscortUnit:GetGroup(), "Evasion", EscortGroup.EscortMenu ) if EscortGroup:OptionROTNoReactionPossible() then - EscortGroup.EscortMenuEvasionNoReaction = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), "Fight until death", EscortGroup.EscortMenuEvasion, AI_ESCORT._ROT, self, EscortGroup, EscortGroup:OptionROTNoReaction(), "Fighting until death!" ) + EscortGroup.EscortMenuEvasionNoReaction = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), EscortGroupName, self.FlightMenuROTNoReaction, AI_ESCORT._ROT, self, EscortGroup, GROUP.OptionROTNoReaction, "Fighting until death!" ) end if EscortGroup:OptionROTPassiveDefensePossible() then - EscortGroup.EscortMenuEvasionPassiveDefense = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), "Use flares, chaff and jammers", EscortGroup.EscortMenuEvasion, AI_ESCORT._ROT, self, EscortGroup, EscortGroup:OptionROTPassiveDefense(), "Defending using jammers, chaff and flares!" ) + EscortGroup.EscortMenuEvasionPassiveDefense = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), EscortGroupName, self.FlightMenuROTPassiveDefense, AI_ESCORT._ROT, self, EscortGroup, GROUP.OptionROTPassiveDefense, "Defending using jammers, chaff and flares!" ) end if EscortGroup:OptionROTEvadeFirePossible() then - EscortGroup.EscortMenuEvasionEvadeFire = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), "Evade enemy fire", EscortGroup.EscortMenuEvasion, AI_ESCORT._ROT, self, EscortGroup, EscortGroup:OptionROTEvadeFire(), "Evading on enemy fire!" ) + EscortGroup.EscortMenuEvasionEvadeFire = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), EscortGroupName, self.FlightMenuROTEvadeFire, AI_ESCORT._ROT, self, EscortGroup, GROUP.OptionROTEvadeFire, "Evading on enemy fire!" ) end if EscortGroup:OptionROTVerticalPossible() then - EscortGroup.EscortMenuOptionEvasionVertical = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), "Go below radar and evade fire", EscortGroup.EscortMenuEvasion, AI_ESCORT._ROT, self, EscortGroup, EscortGroup:OptionROTVertical(), "Evading on enemy fire with vertical manoeuvres!" ) + EscortGroup.EscortMenuOptionEvasionVertical = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), EscortGroupName, self.FlightMenuROTVertical, AI_ESCORT._ROT, self, EscortGroup, GROUP.OptionROTVertical, "Evading on enemy fire with vertical manoeuvres!" ) end end end @@ -1126,6 +1329,15 @@ function AI_ESCORT:_FlightSmoke( Color, Message ) end +function AI_ESCORT:_ReportNearbyTargetsNow( EscortGroup ) + + local EscortUnit = self.EscortUnit + + self:_ReportTargetsScheduler( EscortGroup ) + +end + + function AI_ESCORT:_FlightReportNearbyTargetsNow() self:_FlightReportTargetsScheduler() @@ -1320,40 +1532,38 @@ function AI_ESCORT:_AssistTarget( EscortGroup, DetectedItem ) end +function AI_ESCORT:_ROE( EscortGroup, EscortROEFunction, EscortROEMessage ) + pcall( function() EscortROEFunction() end ) + EscortGroup:MessageTypeToGroup( EscortROEMessage, MESSAGE.Type.Information, self.EscortUnit:GetGroup() ) +end -function AI_ESCORT:_ROE( EscortAction, EscortROEMessage ) - - self:F({EscortAction=EscortAction,EscortROEMessage=EscortROEMessage}) - - local EscortUnit = self.EscortUnit - +function AI_ESCORT:_FlightROE( EscortROEFunction, EscortROEMessage ) self.EscortGroupSet:ForSomeGroupAlive( --- @param Wrapper.Group#GROUP EscortGroup function( EscortGroup ) - if EscortAction == ENUMS.ROE.HoldFire then - EscortGroup:OptionROEHoldFire() - elseif EscortAction == ENUMS.ROE.ReturnFire then - EscortGroup:OptionROEReturnFire() - elseif EscortAction == ENUMS.ROE.OpenFire then - EscortGroup:OptionROEOpenFire() - elseif EscortAction == ENUMS.ROE.WeaponFree then - EscortGroup:OptionROEWeaponFree() - end - EscortGroup:MessageTypeToGroup( EscortROEMessage, MESSAGE.Type.Information, EscortUnit:GetGroup() ) + self:_ROE( EscortGroup, EscortROEFunction, EscortROEMessage ) end ) end function AI_ESCORT:_ROT( EscortGroup, EscortROTFunction, EscortROTMessage ) - - local EscortUnit = self.EscortUnit - pcall( function() EscortROTFunction() end ) - EscortGroup:MessageTypeToGroup( EscortROTMessage, MESSAGE.Type.Information, EscortUnit:GetGroup() ) + EscortGroup:MessageTypeToGroup( EscortROTMessage, MESSAGE.Type.Information, self.EscortUnit:GetGroup() ) end +function AI_ESCORT:_FlightROT( EscortROTFunction, EscortROTMessage ) + self.EscortGroupSet:ForSomeGroupAlive( + --- @param Wrapper.Group#GROUP EscortGroup + function( EscortGroup ) + self:_ROT( EscortGroup, EscortROTFunction, EscortROTMessage ) + end + ) +end + + + function AI_ESCORT:_ResumeMission( WayPoint ) local EscortGroup = self.EscortGroup diff --git a/Moose Development/Moose/AI/AI_Escort_Request.lua b/Moose Development/Moose/AI/AI_Escort_Request.lua index 2c6b24e00..372f09d22 100644 --- a/Moose Development/Moose/AI/AI_Escort_Request.lua +++ b/Moose Development/Moose/AI/AI_Escort_Request.lua @@ -243,6 +243,7 @@ function AI_ESCORT_REQUEST:SpawnEscort() LeaderEscort:MessageTypeToGroup( Report:Text(), MESSAGE.Type.Information, self.EscortUnit ) self:FormationTrail( 50, 50, 50 ) self:JoinFormation( EscortGroup ) + self:Menus() end ) @@ -253,7 +254,7 @@ end function AI_ESCORT_REQUEST:onafterStart( EscortGroupSet ) if not self.MenuRequestEscort then - self.MenuRequestEscort = MENU_GROUP_COMMAND:New( self.LeaderGroup, "Request A2G Escort", nil, + self.MenuRequestEscort = MENU_GROUP_COMMAND:New( self.LeaderGroup, "Request A2G Escort", self.FlightMenu, function() self:SpawnEscort() end diff --git a/Moose Development/Moose/Utilities/Enums.lua b/Moose Development/Moose/Utilities/Enums.lua index b5f1e0fde..a5bd06237 100644 --- a/Moose Development/Moose/Utilities/Enums.lua +++ b/Moose Development/Moose/Utilities/Enums.lua @@ -7,3 +7,9 @@ ENUMS.ROE = { WeaponFree = 4 } +ENUMS.ROT = { + NoReaction = 1, + PassiveDefense = 2, + EvadeFire = 3, + Vertical = 4 +} \ No newline at end of file From 93951dd4b485675df4c014faded1eaf8cef15ce8 Mon Sep 17 00:00:00 2001 From: FlightControl Date: Sat, 4 May 2019 07:10:09 +0200 Subject: [PATCH 11/25] WIP, not for playing. --- Moose Development/Moose/AI/AI_Escort.lua | 73 ++++++++++++------------ 1 file changed, 37 insertions(+), 36 deletions(-) diff --git a/Moose Development/Moose/AI/AI_Escort.lua b/Moose Development/Moose/AI/AI_Escort.lua index 3d3a9c912..d09aedaec 100644 --- a/Moose Development/Moose/AI/AI_Escort.lua +++ b/Moose Development/Moose/AI/AI_Escort.lua @@ -828,23 +828,26 @@ function AI_ESCORT:MenuFlare( MenuTextFormat ) end if not self.FlightMenuFlare then + self.FlightMenuFlare = MENU_GROUP:New( self.EscortUnit:GetGroup(), MenuText, self.FlightMenuReportNavigation ) - self.FlightMenuFlareGreen = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), "Release green flare", self.FlightMenuFlare, AI_ESCORT._FlightFlare, self, FLARECOLOR.Green, "Released a green flare!" ) - self.FlightMenuFlareRed = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), "Release red flare", self.FlightMenuFlare, AI_ESCORT._FlightFlare, self, FLARECOLOR.Red, "Released a red flare!" ) - self.FlightMenuFlareWhite = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), "Release white flare", self.FlightMenuFlare, AI_ESCORT._FlightFlare, self, FLARECOLOR.White, "Released a white flare!" ) - self.FlightMenuFlareYellow = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), "Release yellow flare", self.FlightMenuFlare, AI_ESCORT._FlightFlare, self, FLARECOLOR.Yellow, "Released a yellow flare!" ) + + self.FlightMenuFlareGreen = MENU_GROUP:New( self.EscortUnit:GetGroup(), "Release green flare", self.FlightMenuFlare ) + self.FlightMenuFlareRed = MENU_GROUP:New( self.EscortUnit:GetGroup(), "Release red flare", self.FlightMenuFlare ) + self.FlightMenuFlareWhite = MENU_GROUP:New( self.EscortUnit:GetGroup(), "Release white flare", self.FlightMenuFlare ) + self.FlightMenuFlareYellow = MENU_GROUP:New( self.EscortUnit:GetGroup(), "Release yellow flare", self.FlightMenuFlare ) + + self.FlightMenuFlareGreenFlight = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), "Flight", self.FlightMenuFlareGreen, AI_ESCORT._FlightFlare, self, FLARECOLOR.Green, "Released a green flare!" ) + self.FlightMenuFlareRedFlight = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), "Flight", self.FlightMenuFlareRed, AI_ESCORT._FlightFlare, self, FLARECOLOR.Red, "Released a red flare!" ) + self.FlightMenuFlareWhiteFlight = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), "Flight", self.FlightMenuFlareWhite, AI_ESCORT._FlightFlare, self, FLARECOLOR.White, "Released a white flare!" ) + self.FlightMenuFlareYellowFlight = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), "Flight", self.FlightMenuFlareYellow, AI_ESCORT._FlightFlare, self, FLARECOLOR.Yellow, "Released a yellow flare!" ) end self.EscortGroupSet:ForSomeGroupAlive( --- @param Core.Group#GROUP EscortGroup function( EscortGroup ) - EscortGroup.EscortMenu = MENU_GROUP:New( self.EscortUnit:GetGroup(), EscortGroup:GetName(), self.MainMenu ) - - if not EscortGroup.EscortMenuReportNavigation then - EscortGroup.EscortMenuReportNavigation = MENU_GROUP:New( self.EscortUnit:GetGroup(), "Navigation", EscortGroup.EscortMenu ) - end - + local EscortGroupName = EscortGroup:GetCallsign() + local MenuText = "" if not MenuTextFormat then MenuText = "Flare" @@ -852,13 +855,10 @@ function AI_ESCORT:MenuFlare( MenuTextFormat ) MenuText = MenuTextFormat end - if not EscortGroup.EscortMenuFlare then - EscortGroup.EscortMenuFlare = MENU_GROUP:New( self.EscortUnit:GetGroup(), MenuText, EscortGroup.EscortMenuReportNavigation ) - EscortGroup.EscortMenuFlareGreen = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), "Release green flare", EscortGroup.EscortMenuFlare, AI_ESCORT._Flare, self, EscortGroup, FLARECOLOR.Green, "Released a green flare!" ) - EscortGroup.EscortMenuFlareRed = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), "Release red flare", EscortGroup.EscortMenuFlare, AI_ESCORT._Flare, self, EscortGroup, FLARECOLOR.Red, "Released a red flare!" ) - EscortGroup.EscortMenuFlareWhite = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), "Release white flare", EscortGroup.EscortMenuFlare, AI_ESCORT._Flare, self, EscortGroup, FLARECOLOR.White, "Released a white flare!" ) - EscortGroup.EscortMenuFlareYellow = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), "Release yellow flare", EscortGroup.EscortMenuFlare, AI_ESCORT._Flare, self, EscortGroup, FLARECOLOR.Yellow, "Released a yellow flare!" ) - end + EscortGroup.EscortMenuFlareGreen = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), EscortGroupName, self.FlightMenuFlareGreen, AI_ESCORT._Flare, self, EscortGroup, FLARECOLOR.Green, "Released a green flare!" ) + EscortGroup.EscortMenuFlareRed = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), EscortGroupName, self.FlightMenuFlareRed, AI_ESCORT._Flare, self, EscortGroup, FLARECOLOR.Red, "Released a red flare!" ) + EscortGroup.EscortMenuFlareWhite = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), EscortGroupName, self.FlightMenuFlareWhite, AI_ESCORT._Flare, self, EscortGroup, FLARECOLOR.White, "Released a white flare!" ) + EscortGroup.EscortMenuFlareYellow = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), EscortGroupName, self.FlightMenuFlareYellow, AI_ESCORT._Flare, self, EscortGroup, FLARECOLOR.Yellow, "Released a yellow flare!" ) end ) @@ -887,12 +887,20 @@ function AI_ESCORT:MenuSmoke( MenuTextFormat ) end if not self.FlightMenuSmoke then - self.FlightMenuSmoke = MENU_GROUP:New( self.EscortUnit:GetGroup(), "Smoke", self.FlightMenuReportNavigation ) - self.FlightMenuSmokeGreen = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), "Release green smoke", self.FlightMenuSmoke, AI_ESCORT._FlightSmoke, self, SMOKECOLOR.Green, "Releasing green smoke!" ) - self.FlightMenuSmokeRed = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), "Release red smoke", self.FlightMenuSmoke, AI_ESCORT._FlightSmoke, self, SMOKECOLOR.Red, "Releasing red smoke!" ) - self.FlightMenuSmokeWhite = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), "Release white smoke", self.FlightMenuSmoke, AI_ESCORT._FlightSmoke, self, SMOKECOLOR.White, "Releasing white smoke!" ) - self.FlightMenuSmokeOrange = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), "Release orange smoke", self.FlightMenuSmoke, AI_ESCORT._FlightSmoke, self, SMOKECOLOR.Orange, "Releasing orange smoke!" ) - self.FlightMenuSmokeBlue = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), "Release blue smoke", self.FlightMenuSmoke, AI_ESCORT._FlightSmoke, self, SMOKECOLOR.Blue, "Releasing blue smoke!" ) + + self.FlightMenuSmoke = MENU_GROUP:New( self.EscortUnit:GetGroup(), MenuText, self.FlightMenuReportNavigation ) + + self.FlightMenuSmokeGreen = MENU_GROUP:New( self.EscortUnit:GetGroup(), "Release green smoke", self.FlightMenuSmoke ) + self.FlightMenuSmokeRed = MENU_GROUP:New( self.EscortUnit:GetGroup(), "Release red smoke", self.FlightMenuSmoke ) + self.FlightMenuSmokeWhite = MENU_GROUP:New( self.EscortUnit:GetGroup(), "Release white smoke", self.FlightMenuSmoke ) + self.FlightMenuSmokeOrange = MENU_GROUP:New( self.EscortUnit:GetGroup(), "Release orange smoke", self.FlightMenuSmoke ) + self.FlightMenuSmokeBlue = MENU_GROUP:New( self.EscortUnit:GetGroup(), "Release blue smoke", self.FlightMenuSmoke ) + + self.FlightMenuSmokeGreenFlight = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), "Flight", self.FlightMenuSmokeGreen, AI_ESCORT._FlightSmoke, self, SMOKECOLOR.Green, "Releasing green smoke!" ) + self.FlightMenuSmokeRedFlight = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), "Flight", self.FlightMenuSmokeRed, AI_ESCORT._FlightSmoke, self, SMOKECOLOR.Red, "Releasing red smoke!" ) + self.FlightMenuSmokeWhiteFlight = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), "Flight", self.FlightMenuSmokeWhite, AI_ESCORT._FlightSmoke, self, SMOKECOLOR.White, "Releasing white smoke!" ) + self.FlightMenuSmokeOrangeFlight = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), "Flight", self.FlightMenuSmokeOrange, AI_ESCORT._FlightSmoke, self, SMOKECOLOR.Orange, "Releasing orange smoke!" ) + self.FlightMenuSmokeBlueFlight = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), "Flight", self.FlightMenuSmokeBlue, AI_ESCORT._FlightSmoke, self, SMOKECOLOR.Blue, "Releasing blue smoke!" ) end self.EscortGroupSet:ForSomeGroupAlive( @@ -900,11 +908,7 @@ function AI_ESCORT:MenuSmoke( MenuTextFormat ) function( EscortGroup ) if not EscortGroup:IsAir() then - EscortGroup.EscortMenu = MENU_GROUP:New( self.EscortUnit:GetGroup(), EscortGroup:GetName(), self.MainMenu ) - - if not EscortGroup.EscortMenuReportNavigation then - EscortGroup.EscortMenuReportNavigation = MENU_GROUP:New( self.EscortUnit:GetGroup(), "Navigation", EscortGroup.EscortMenu ) - end + local EscortGroupName = EscortGroup:GetCallsign() local MenuText = "" if not MenuTextFormat then @@ -913,14 +917,11 @@ function AI_ESCORT:MenuSmoke( MenuTextFormat ) MenuText = MenuTextFormat end - if not EscortGroup.EscortMenuSmoke then - EscortGroup.EscortMenuSmoke = MENU_GROUP:New( self.EscortUnit:GetGroup(), "Smoke", EscortGroup.EscortMenuReportNavigation ) - EscortGroup.EscortMenuSmokeGreen = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), "Release green smoke", EscortGroup.EscortMenuSmoke, AI_ESCORT._Smoke, self, EscortGroup, SMOKECOLOR.Green, "Releasing green smoke!" ) - EscortGroup.EscortMenuSmokeRed = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), "Release red smoke", EscortGroup.EscortMenuSmoke, AI_ESCORT._Smoke, self, EscortGroup, SMOKECOLOR.Red, "Releasing red smoke!" ) - EscortGroup.EscortMenuSmokeWhite = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), "Release white smoke", EscortGroup.EscortMenuSmoke, AI_ESCORT._Smoke, self, EscortGroup, SMOKECOLOR.White, "Releasing white smoke!" ) - EscortGroup.EscortMenuSmokeOrange = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), "Release orange smoke", EscortGroup.EscortMenuSmoke, AI_ESCORT._Smoke, self, EscortGroup, SMOKECOLOR.Orange, "Releasing orange smoke!" ) - EscortGroup.EscortMenuSmokeBlue = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), "Release blue smoke", EscortGroup.EscortMenuSmoke, AI_ESCORT._Smoke, self, EscortGroup, SMOKECOLOR.Blue, "Releasing blue smoke!" ) - end + EscortGroup.EscortMenuSmokeGreen = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), EscortGroupName, self.FlightMenuSmokeGreen, AI_ESCORT._Smoke, self, EscortGroup, SMOKECOLOR.Green, "Releasing green smoke!" ) + EscortGroup.EscortMenuSmokeRed = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), EscortGroupName, self.FlightMenuSmokeRed, AI_ESCORT._Smoke, self, EscortGroup, SMOKECOLOR.Red, "Releasing red smoke!" ) + EscortGroup.EscortMenuSmokeWhite = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), EscortGroupName, self.FlightMenuSmokeWhite, AI_ESCORT._Smoke, self, EscortGroup, SMOKECOLOR.White, "Releasing white smoke!" ) + EscortGroup.EscortMenuSmokeOrange = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), EscortGroupName, self.FlightMenuSmokeOrange, AI_ESCORT._Smoke, self, EscortGroup, SMOKECOLOR.Orange, "Releasing orange smoke!" ) + EscortGroup.EscortMenuSmokeBlue = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), EscortGroupName, self.FlightMenuSmokeBlue, AI_ESCORT._Smoke, self, EscortGroup, SMOKECOLOR.Blue, "Releasing blue smoke!" ) end end ) From e09a02ec148c8faa45a3a2cab51baed7e6cb73e1 Mon Sep 17 00:00:00 2001 From: FlightControl Date: Mon, 13 May 2019 11:22:49 +0200 Subject: [PATCH 12/25] Escort menus reworked. It took a while (sorry), was involved in many projects in RL. --- Moose Development/Moose/AI/AI_Escort.lua | 325 +++++++++-------------- 1 file changed, 131 insertions(+), 194 deletions(-) diff --git a/Moose Development/Moose/AI/AI_Escort.lua b/Moose Development/Moose/AI/AI_Escort.lua index d09aedaec..2a78343c6 100644 --- a/Moose Development/Moose/AI/AI_Escort.lua +++ b/Moose Development/Moose/AI/AI_Escort.lua @@ -226,6 +226,10 @@ function AI_ESCORT:New( EscortUnit, EscortGroupSet, EscortName, EscortBriefing ) self:F( { EscortUnit, EscortGroupSet } ) self.EscortUnit = self.FollowUnit -- Wrapper.Unit#UNIT + + self.PlayerUnit = self.FollowUnit -- Wrapper.Unit#UNIT + self.PlayerGroup = self.FollowUnit:GetGroup() -- Wrapper.Group#GROUP + self.EscortGroupSet = EscortGroupSet self.EscortGroupSet:SetSomeIteratorLimit( 5 ) @@ -250,7 +254,8 @@ function AI_ESCORT:New( EscortUnit, EscortGroupSet, EscortName, EscortBriefing ) self.GT1 = 0 - self.FlightMenu = MENU_GROUP:New( self.EscortUnit:GetGroup(), EscortName ) + self.MainMenu = MENU_GROUP:New( self.PlayerGroup, EscortName ) + self.FlightMenu = MENU_GROUP:New( self.PlayerGroup, "Flight", self.MainMenu ) EscortGroupSet:ForEachGroup( --- @param Core.Group#GROUP EscortGroup @@ -281,7 +286,7 @@ function AI_ESCORT:onafterStart( EscortGroupSet ) EscortGroupSet:ForEachGroup( --- @param Core.Group#GROUP EscortGroup function( EscortGroup ) - EscortGroup.EscortMenu = MENU_GROUP:New( self.EscortUnit:GetGroup(), EscortGroup:GetName(), self.MainMenu ) + EscortGroup.EscortMenu = MENU_GROUP:New( self.PlayerGroup, EscortGroup:GetName(), self.MainMenu ) EscortGroup:WayPointInitialize( 1 ) EscortGroup:OptionROTVertical() @@ -382,11 +387,11 @@ end function AI_ESCORT:MenuFormation( Formation, ... ) if not self.FlightMenuFormation then - self.FlightMenuFormation = MENU_GROUP:New( self.EscortUnit:GetGroup(), "Formation", self.MainMenu ) + self.FlightMenuFormation = MENU_GROUP:New( self.PlayerGroup, "Formation", self.MainMenu ) end if not self["FlightMenuFormation"..Formation] then - self["FlightMenuFormation"..Formation] = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), Formation, self.FlightMenuFormation, + self["FlightMenuFormation"..Formation] = MENU_GROUP_COMMAND:New( self.PlayerGroup, Formation, self.FlightMenuFormation, function ( self, Formation, ... ) self.EscortGroupSet:ForSomeGroupAlive( --- @param Core.Group#GROUP EscortGroup @@ -410,27 +415,19 @@ end -- @return #AI_ESCORT function AI_ESCORT:MenuJoinUp() - if not self.FlightMenuReportNavigation then - self.FlightMenuReportNavigation = MENU_GROUP:New( self.EscortUnit:GetGroup(), "Navigation", self.FlightMenu ) - end - - if not self.FlightMenuJoinUp then - self.FlightMenuJoinUp = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), "Join Up", self.FlightMenuReportNavigation, AI_ESCORT._FlightJoinUp, self ) - end + local FlightMenuReportNavigation = MENU_GROUP:New( self.PlayerGroup, "Navigation", self.FlightMenu ) + local FlightMenuJoinUp = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Join Up", FlightMenuReportNavigation, AI_ESCORT._FlightJoinUp, self ) self.EscortGroupSet:ForSomeGroupAlive( --- @param Core.Group#GROUP EscortGroup function( EscortGroup ) if EscortGroup:IsAir() then - EscortGroup.EscortMenu = MENU_GROUP:New( self.EscortUnit:GetGroup(), EscortGroup:GetName(), self.MainMenu ) - if not EscortGroup.EscortMenuReportNavigation then - EscortGroup.EscortMenuReportNavigation = MENU_GROUP:New( self.EscortUnit:GetGroup(), "Navigation", EscortGroup.EscortMenu ) - end - - if not EscortGroup.EscortMenuJoinUpAndFollow then - EscortGroup.EscortMenuJoinUpAndFollow = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), "Join-Up", EscortGroup.EscortMenuReportNavigation, ESCORT._JoinUp, self, EscortGroup ) - end - + + local EscortGroupName = EscortGroup:GetName() + local EscortMenu = MENU_GROUP:New( self.PlayerGroup, EscortGroupName, self.MainMenu ) + local EscortMenuReportNavigation = MENU_GROUP:New( self.PlayerGroup, "Navigation", EscortMenu ) + local EscortMenuJoinUp = MENU_GROUP:New( self.PlayerGroup, "Join Up", EscortMenuReportNavigation ) + end end ) @@ -623,18 +620,11 @@ function AI_ESCORT:MenuHoldAtEscortPosition( Height, Speed, MenuTextFormat ) end end - self.FlightMenuHold = self.FlightMenuHold or {} - - if not self.FlightMenuHold[MenuText] then - self.FlightMenuHold[MenuText] = MENU_GROUP:New( self.EscortUnit:GetGroup(), MenuText, self.FlightMenu ) - end - - self.FlightMenuHoldPosition = self.FlightMenuHoldPosition or {} - self.FlightMenuHoldPosition[MenuText] = MENU_GROUP_COMMAND + local FlightMenuHoldPosition = MENU_GROUP_COMMAND :New( - self.EscortUnit:GetGroup(), - "Flight", - self.FlightMenuHold[MenuText], + self.PlayerGroup, + MenuText, + self.FlightMenu, AI_ESCORT._FlightHoldPosition, self, nil, @@ -648,13 +638,15 @@ function AI_ESCORT:MenuHoldAtEscortPosition( Height, Speed, MenuTextFormat ) if EscortGroup:IsAir() then local EscortGroupName = EscortGroup:GetName() + local EscortMenu = MENU_GROUP:New( self.PlayerGroup, EscortGroupName, self.MainMenu ) + local EscortMenuReportNavigation = MENU_GROUP:New( self.PlayerGroup, "Navigation", EscortMenu ) + local EscortMenuHold = MENU_GROUP:New( self.PlayerGroup, MenuText, EscortMenuReportNavigation ) - EscortGroup.EscortMenuHoldPosition = EscortGroup.EscortMenuHoldPosition or {} - EscortGroup.EscortMenuHoldPosition[MenuText] = MENU_GROUP_COMMAND + local EscortMenuHoldPosition = MENU_GROUP_COMMAND :New( - self.EscortUnit:GetGroup(), + self.PlayerGroup, EscortGroupName, - self.FlightMenuHold[MenuText], + EscortMenuHold, AI_ESCORT._HoldPosition, self, EscortGroup, @@ -703,21 +695,14 @@ function AI_ESCORT:MenuHoldAtLeaderPosition( Height, Speed, MenuTextFormat ) end end - self.FlightMenuHold = self.FlightMenuHold or {} - - if not self.FlightMenuHold[MenuText] then - self.FlightMenuHold[MenuText] = MENU_GROUP:New( self.EscortUnit:GetGroup(), MenuText, self.FlightMenu ) - end - - self.FlightMenuHoldAtLeaderPosition = self.FlightMenuHoldAtLeaderPosition or {} - self.FlightMenuHoldAtLeaderPosition[MenuText] = MENU_GROUP_COMMAND + local FlightMenuHoldAtLeaderPosition = MENU_GROUP_COMMAND :New( - self.EscortUnit:GetGroup(), + self.PlayerGroup, MenuText, - self.FlightMenuHold[MenuText], + self.FlightMenu, AI_ESCORT._FlightHoldPosition, self, - self.EscortUnit:GetGroup(), + self.PlayerGroup, Height, Speed ) @@ -728,16 +713,18 @@ function AI_ESCORT:MenuHoldAtLeaderPosition( Height, Speed, MenuTextFormat ) if EscortGroup:IsAir() then local EscortGroupName = EscortGroup:GetName() + local EscortMenu = MENU_GROUP:New( self.PlayerGroup, EscortGroupName, self.MainMenu ) + local EscortMenuReportNavigation = MENU_GROUP:New( self.PlayerGroup, "Navigation", EscortMenu ) + local EscortMenuHold = MENU_GROUP:New( self.PlayerGroup, MenuText, EscortMenuReportNavigation ) - EscortGroup.EscortMenuHoldAtLeaderPosition = EscortGroup.EscortMenuHoldAtLeaderPosition or {} - EscortGroup.EscortMenuHoldAtLeaderPosition[MenuText] = MENU_GROUP_COMMAND + local EscortMenuHoldAtLeaderPosition = MENU_GROUP_COMMAND :New( - self.EscortUnit:GetGroup(), + self.PlayerGroup, EscortGroupName, - self.FlightMenuHold[MenuText], + EscortMenuHold, AI_ESCORT._HoldPosition, self, - self.EscortUnit:GetGroup(), + self.PlayerGroup, EscortGroup, Height, Speed @@ -761,7 +748,7 @@ function AI_ESCORT:MenuScanForTargets( Height, Seconds, MenuTextFormat ) if self.EscortGroup:IsAir() then if not self.EscortMenuScan then - self.EscortMenuScan = MENU_GROUP:New( self.EscortUnit:GetGroup(), "Scan for targets", self.EscortMenu ) + self.EscortMenuScan = MENU_GROUP:New( self.PlayerGroup, "Scan for targets", self.EscortMenu ) end if not Height then @@ -793,7 +780,7 @@ function AI_ESCORT:MenuScanForTargets( Height, Seconds, MenuTextFormat ) self.EscortMenuScanForTargets[#self.EscortMenuScanForTargets+1] = MENU_GROUP_COMMAND :New( - self.EscortUnit:GetGroup(), + self.PlayerGroup, MenuText, self.EscortMenuScan, AI_ESCORT._ScanTargets, @@ -816,10 +803,6 @@ end function AI_ESCORT:MenuFlare( MenuTextFormat ) self:F() - if not self.FlightMenuReportNavigation then - self.FlightMenuReportNavigation = MENU_GROUP:New( self.EscortUnit:GetGroup(), "Navigation", self.FlightMenu ) - end - local MenuText = "" if not MenuTextFormat then MenuText = "Flare" @@ -827,38 +810,27 @@ function AI_ESCORT:MenuFlare( MenuTextFormat ) MenuText = MenuTextFormat end - if not self.FlightMenuFlare then + local FlightMenuReportNavigation = MENU_GROUP:New( self.PlayerGroup, "Navigation", self.FlightMenu ) + local FlightMenuFlare = MENU_GROUP:New( self.PlayerGroup, MenuText, FlightMenuReportNavigation ) - self.FlightMenuFlare = MENU_GROUP:New( self.EscortUnit:GetGroup(), MenuText, self.FlightMenuReportNavigation ) - - self.FlightMenuFlareGreen = MENU_GROUP:New( self.EscortUnit:GetGroup(), "Release green flare", self.FlightMenuFlare ) - self.FlightMenuFlareRed = MENU_GROUP:New( self.EscortUnit:GetGroup(), "Release red flare", self.FlightMenuFlare ) - self.FlightMenuFlareWhite = MENU_GROUP:New( self.EscortUnit:GetGroup(), "Release white flare", self.FlightMenuFlare ) - self.FlightMenuFlareYellow = MENU_GROUP:New( self.EscortUnit:GetGroup(), "Release yellow flare", self.FlightMenuFlare ) - - self.FlightMenuFlareGreenFlight = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), "Flight", self.FlightMenuFlareGreen, AI_ESCORT._FlightFlare, self, FLARECOLOR.Green, "Released a green flare!" ) - self.FlightMenuFlareRedFlight = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), "Flight", self.FlightMenuFlareRed, AI_ESCORT._FlightFlare, self, FLARECOLOR.Red, "Released a red flare!" ) - self.FlightMenuFlareWhiteFlight = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), "Flight", self.FlightMenuFlareWhite, AI_ESCORT._FlightFlare, self, FLARECOLOR.White, "Released a white flare!" ) - self.FlightMenuFlareYellowFlight = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), "Flight", self.FlightMenuFlareYellow, AI_ESCORT._FlightFlare, self, FLARECOLOR.Yellow, "Released a yellow flare!" ) - end + local FlightMenuFlareGreenFlight = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Release green flare", FlightMenuFlare, AI_ESCORT._FlightFlare, self, FLARECOLOR.Green, "Released a green flare!" ) + local FlightMenuFlareRedFlight = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Release red flare", FlightMenuFlare, AI_ESCORT._FlightFlare, self, FLARECOLOR.Red, "Released a red flare!" ) + local FlightMenuFlareWhiteFlight = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Release white flare", FlightMenuFlare, AI_ESCORT._FlightFlare, self, FLARECOLOR.White, "Released a white flare!" ) + local FlightMenuFlareYellowFlight = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Release yellow flare", FlightMenuFlare, AI_ESCORT._FlightFlare, self, FLARECOLOR.Yellow, "Released a yellow flare!" ) self.EscortGroupSet:ForSomeGroupAlive( --- @param Core.Group#GROUP EscortGroup function( EscortGroup ) - local EscortGroupName = EscortGroup:GetCallsign() - - local MenuText = "" - if not MenuTextFormat then - MenuText = "Flare" - else - MenuText = MenuTextFormat - end - - EscortGroup.EscortMenuFlareGreen = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), EscortGroupName, self.FlightMenuFlareGreen, AI_ESCORT._Flare, self, EscortGroup, FLARECOLOR.Green, "Released a green flare!" ) - EscortGroup.EscortMenuFlareRed = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), EscortGroupName, self.FlightMenuFlareRed, AI_ESCORT._Flare, self, EscortGroup, FLARECOLOR.Red, "Released a red flare!" ) - EscortGroup.EscortMenuFlareWhite = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), EscortGroupName, self.FlightMenuFlareWhite, AI_ESCORT._Flare, self, EscortGroup, FLARECOLOR.White, "Released a white flare!" ) - EscortGroup.EscortMenuFlareYellow = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), EscortGroupName, self.FlightMenuFlareYellow, AI_ESCORT._Flare, self, EscortGroup, FLARECOLOR.Yellow, "Released a yellow flare!" ) + local EscortGroupName = EscortGroup:GetName() + local EscortMenu = MENU_GROUP:New( self.PlayerGroup, EscortGroupName, self.MainMenu ) + local EscortMenuReportNavigation = MENU_GROUP:New( self.PlayerGroup, "Navigation", EscortMenu ) + local EscortMenuFlare = MENU_GROUP:New( self.PlayerGroup, MenuText, EscortMenuReportNavigation ) + + local EscortMenuFlareGreen = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Release green flare", EscortMenuFlare, AI_ESCORT._Flare, self, EscortGroup, FLARECOLOR.Green, "Released a green flare!" ) + local EscortMenuFlareRed = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Release red flare", EscortMenuFlare, AI_ESCORT._Flare, self, EscortGroup, FLARECOLOR.Red, "Released a red flare!" ) + local EscortMenuFlareWhite = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Release white flare", EscortMenuFlare, AI_ESCORT._Flare, self, EscortGroup, FLARECOLOR.White, "Released a white flare!" ) + local EscortMenuFlareYellow = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Release yellow flare", EscortMenuFlare, AI_ESCORT._Flare, self, EscortGroup, FLARECOLOR.Yellow, "Released a yellow flare!" ) end ) @@ -875,10 +847,6 @@ end function AI_ESCORT:MenuSmoke( MenuTextFormat ) self:F() - if not self.FlightMenuReportNavigation then - self.FlightMenuReportNavigation = MENU_GROUP:New( self.EscortUnit:GetGroup(), "Navigation", self.FlightMenu ) - end - local MenuText = "" if not MenuTextFormat then MenuText = "Smoke" @@ -886,42 +854,31 @@ function AI_ESCORT:MenuSmoke( MenuTextFormat ) MenuText = MenuTextFormat end - if not self.FlightMenuSmoke then + local FlightMenuReportNavigation = MENU_GROUP:New( self.PlayerGroup, "Navigation", self.FlightMenu ) + local FlightMenuSmoke = MENU_GROUP:New( self.PlayerGroup, MenuText, FlightMenuReportNavigation ) - self.FlightMenuSmoke = MENU_GROUP:New( self.EscortUnit:GetGroup(), MenuText, self.FlightMenuReportNavigation ) + local FlightMenuSmokeGreenFlight = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Release green smoke", FlightMenuSmoke, AI_ESCORT._FlightSmoke, self, SMOKECOLOR.Green, "Releasing green smoke!" ) + local FlightMenuSmokeRedFlight = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Release red smoke", FlightMenuSmoke, AI_ESCORT._FlightSmoke, self, SMOKECOLOR.Red, "Releasing red smoke!" ) + local FlightMenuSmokeWhiteFlight = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Release white smoke", FlightMenuSmoke, AI_ESCORT._FlightSmoke, self, SMOKECOLOR.White, "Releasing white smoke!" ) + local FlightMenuSmokeOrangeFlight = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Release orange smoke", FlightMenuSmoke, AI_ESCORT._FlightSmoke, self, SMOKECOLOR.Orange, "Releasing orange smoke!" ) + local FlightMenuSmokeBlueFlight = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Release blue smoke", FlightMenuSmoke, AI_ESCORT._FlightSmoke, self, SMOKECOLOR.Blue, "Releasing blue smoke!" ) - self.FlightMenuSmokeGreen = MENU_GROUP:New( self.EscortUnit:GetGroup(), "Release green smoke", self.FlightMenuSmoke ) - self.FlightMenuSmokeRed = MENU_GROUP:New( self.EscortUnit:GetGroup(), "Release red smoke", self.FlightMenuSmoke ) - self.FlightMenuSmokeWhite = MENU_GROUP:New( self.EscortUnit:GetGroup(), "Release white smoke", self.FlightMenuSmoke ) - self.FlightMenuSmokeOrange = MENU_GROUP:New( self.EscortUnit:GetGroup(), "Release orange smoke", self.FlightMenuSmoke ) - self.FlightMenuSmokeBlue = MENU_GROUP:New( self.EscortUnit:GetGroup(), "Release blue smoke", self.FlightMenuSmoke ) - - self.FlightMenuSmokeGreenFlight = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), "Flight", self.FlightMenuSmokeGreen, AI_ESCORT._FlightSmoke, self, SMOKECOLOR.Green, "Releasing green smoke!" ) - self.FlightMenuSmokeRedFlight = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), "Flight", self.FlightMenuSmokeRed, AI_ESCORT._FlightSmoke, self, SMOKECOLOR.Red, "Releasing red smoke!" ) - self.FlightMenuSmokeWhiteFlight = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), "Flight", self.FlightMenuSmokeWhite, AI_ESCORT._FlightSmoke, self, SMOKECOLOR.White, "Releasing white smoke!" ) - self.FlightMenuSmokeOrangeFlight = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), "Flight", self.FlightMenuSmokeOrange, AI_ESCORT._FlightSmoke, self, SMOKECOLOR.Orange, "Releasing orange smoke!" ) - self.FlightMenuSmokeBlueFlight = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), "Flight", self.FlightMenuSmokeBlue, AI_ESCORT._FlightSmoke, self, SMOKECOLOR.Blue, "Releasing blue smoke!" ) - end self.EscortGroupSet:ForSomeGroupAlive( --- @param Core.Group#GROUP EscortGroup function( EscortGroup ) if not EscortGroup:IsAir() then - local EscortGroupName = EscortGroup:GetCallsign() - - local MenuText = "" - if not MenuTextFormat then - MenuText = "Smoke" - else - MenuText = MenuTextFormat - end - - EscortGroup.EscortMenuSmokeGreen = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), EscortGroupName, self.FlightMenuSmokeGreen, AI_ESCORT._Smoke, self, EscortGroup, SMOKECOLOR.Green, "Releasing green smoke!" ) - EscortGroup.EscortMenuSmokeRed = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), EscortGroupName, self.FlightMenuSmokeRed, AI_ESCORT._Smoke, self, EscortGroup, SMOKECOLOR.Red, "Releasing red smoke!" ) - EscortGroup.EscortMenuSmokeWhite = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), EscortGroupName, self.FlightMenuSmokeWhite, AI_ESCORT._Smoke, self, EscortGroup, SMOKECOLOR.White, "Releasing white smoke!" ) - EscortGroup.EscortMenuSmokeOrange = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), EscortGroupName, self.FlightMenuSmokeOrange, AI_ESCORT._Smoke, self, EscortGroup, SMOKECOLOR.Orange, "Releasing orange smoke!" ) - EscortGroup.EscortMenuSmokeBlue = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), EscortGroupName, self.FlightMenuSmokeBlue, AI_ESCORT._Smoke, self, EscortGroup, SMOKECOLOR.Blue, "Releasing blue smoke!" ) + local EscortGroupName = EscortGroup:GetName() + local EscortMenu = MENU_GROUP:New( self.PlayerGroup, EscortGroupName, self.MainMenu ) + local EscortMenuReportNavigation = MENU_GROUP:New( self.PlayerGroup, "Navigation", EscortMenu ) + local EscortMenuSmoke = MENU_GROUP:New( self.PlayerGroup, MenuText, EscortMenuReportNavigation ) + + local EscortMenuSmokeGreen = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Release green smoke", EscortMenuSmoke, AI_ESCORT._Smoke, self, EscortGroup, SMOKECOLOR.Green, "Releasing green smoke!" ) + local EscortMenuSmokeRed = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Release red smoke", EscortMenuSmoke, AI_ESCORT._Smoke, self, EscortGroup, SMOKECOLOR.Red, "Releasing red smoke!" ) + local EscortMenuSmokeWhite = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Release white smoke", EscortMenuSmoke, AI_ESCORT._Smoke, self, EscortGroup, SMOKECOLOR.White, "Releasing white smoke!" ) + local EscortMenuSmokeOrange = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Release orange smoke", EscortMenuSmoke, AI_ESCORT._Smoke, self, EscortGroup, SMOKECOLOR.Orange, "Releasing orange smoke!" ) + local EscortMenuSmokeBlue = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Release blue smoke", EscortMenuSmoke, AI_ESCORT._Smoke, self, EscortGroup, SMOKECOLOR.Blue, "Releasing blue smoke!" ) end end ) @@ -938,10 +895,6 @@ end function AI_ESCORT:MenuReportTargets( Seconds ) self:F( { Seconds } ) - if not self.FlightMenuReportNearbyTargets then - self.FlightMenuReportNearbyTargets = MENU_GROUP:New( self.EscortUnit:GetGroup(), "Report targets", self.FlightMenu ) - end - if not Seconds then Seconds = 30 end @@ -950,13 +903,15 @@ function AI_ESCORT:MenuReportTargets( Seconds ) local timer = 1 + local FlightMenuReportTargets = MENU_GROUP:New( self.PlayerGroup, "Report targets", self.FlightMenu ) + -- Report Targets - self.FlightMenuReportNearbyTargetsNow = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), "Report targets now!", self.FlightMenuReportNearbyTargets, AI_ESCORT._FlightReportNearbyTargetsNow, self ) - self.FlightMenuReportNearbyTargetsOn = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), "Report targets on", self.FlightMenuReportNearbyTargets, AI_ESCORT._FlightSwitchReportNearbyTargets, self, true ) - self.FlightMenuReportNearbyTargetsOff = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), "Report targets off", self.FlightMenuReportNearbyTargets, AI_ESCORT._FlightSwitchReportNearbyTargets, self, false ) + local FlightMenuReportTargetsNow = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Report targets now!", FlightMenuReportTargets, AI_ESCORT._FlightReportNearbyTargetsNow, self ) + local FlightMenuReportTargetsOn = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Report targets on", FlightMenuReportTargets, AI_ESCORT._FlightSwitchReportNearbyTargets, self, true ) + local FlightMenuReportTargetsOff = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Report targets off", FlightMenuReportTargets, AI_ESCORT._FlightSwitchReportNearbyTargets, self, false ) -- Attack Targets - self.FlightMenuAttackNearbyTargets = MENU_GROUP:New( self.EscortUnit:GetGroup(), "Attack targets", self.FlightMenu ) + local FlightMenuAttackNearbyTargets = MENU_GROUP:New( self.PlayerGroup, "Attack targets", self.FlightMenu ) self.FlightReportTargetsScheduler = SCHEDULER:New( self, self._FlightReportTargetsScheduler, {}, 5, Seconds ) @@ -965,19 +920,18 @@ function AI_ESCORT:MenuReportTargets( Seconds ) function( EscortGroup ) if EscortGroup:IsAir() then - --EscortGroup.EscortMenuAttackNearbyTargets = MENU_GROUP:New( self.EscortUnit:GetGroup(), EscortGroup:GetName() ) + local EscortGroupName = EscortGroup:GetName() + local EscortMenu = MENU_GROUP:New( self.PlayerGroup, EscortGroupName, self.MainMenu ) + local EscortMenuReportTargets = MENU_GROUP:New( self.PlayerGroup, "Report targets", EscortMenu ) - --if not EscortGroup.EscortMenuReportNearbyTargets then - -- EscortGroup.EscortMenuReportNearbyTargets = MENU_GROUP:New( self.EscortUnit:GetGroup(), "Report targets", EscortGroup.EscortMenu ) - --end -- Report Targets - --EscortGroup.EscortMenuReportNearbyTargetsNow = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), "Report targets now!", EscortGroup.EscortMenuReportNearbyTargets, AI_ESCORT._ReportNearbyTargetsNow, self, EscortGroup, true ) - --EscortGroup.EscortMenuReportNearbyTargetsOn = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), "Report targets on", EscortGroup.EscortMenuReportNearbyTargets, AI_ESCORT._SwitchReportNearbyTargets, self, EscortGroup, true ) - --EscortGroup.EscortMenuReportNearbyTargetsOff = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), "Report targets off", EscortGroup.EscortMenuReportNearbyTargets, AI_ESCORT._SwitchReportNearbyTargets, self, EscortGroup, false ) + --EscortGroup.EscortMenuReportNearbyTargetsNow = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Report targets now!", EscortGroup.EscortMenuReportNearbyTargets, AI_ESCORT._ReportNearbyTargetsNow, self, EscortGroup, true ) + --EscortGroup.EscortMenuReportNearbyTargetsOn = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Report targets on", EscortGroup.EscortMenuReportNearbyTargets, AI_ESCORT._SwitchReportNearbyTargets, self, EscortGroup, true ) + --EscortGroup.EscortMenuReportNearbyTargetsOff = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Report targets off", EscortGroup.EscortMenuReportNearbyTargets, AI_ESCORT._SwitchReportNearbyTargets, self, EscortGroup, false ) -- Attack Targets - EscortGroup.EscortMenuAttackNearbyTargets = MENU_GROUP:New( self.EscortUnit:GetGroup(), "Attack targets", EscortGroup.EscortMenu ) + local EscortMenuAttackTargets = MENU_GROUP:New( self.PlayerGroup, "Attack targets", EscortMenu ) --EscortGroup.ReportTargetsScheduler = SCHEDULER:New( self, self._ReportTargetsScheduler, { EscortGroup }, timer, Seconds ) timer=timer+1 @@ -1002,7 +956,7 @@ function AI_ESCORT:MenuAssistedAttack() if not EscortGroup:IsAir() then -- Request assistance from other escorts. -- This is very useful to let f.e. an escorting ship attack a target detected by an escorting plane... - self.EscortMenuTargetAssistance = MENU_GROUP:New( self.EscortUnit:GetGroup(), "Request assistance from", EscortGroup.EscortMenu ) + self.EscortMenuTargetAssistance = MENU_GROUP:New( self.PlayerGroup, "Request assistance from", EscortGroup.EscortMenu ) end end ) @@ -1017,26 +971,12 @@ end function AI_ESCORT:MenuROE( MenuTextFormat ) self:F( MenuTextFormat ) - if not self.FlightMenuROE then - self.FlightMenuROE = MENU_GROUP:New( self.EscortUnit:GetGroup(), "ROE", self.FlightMenu ) - end + local FlightMenuROE = MENU_GROUP:New( self.PlayerGroup, "Rule Of Engagement", self.FlightMenu ) - if not self.FlightMenuROEHoldFire then - self.FlightMenuROEHoldFire = MENU_GROUP:New( self.EscortUnit:GetGroup(), "Hold fire", self.FlightMenuROE ) - self.FlightMenuROEHoldFireFlight = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), "Flight", self.FlightMenuROEHoldFire, AI_ESCORT._ROE, self, GROUP.OptionROEHoldFire, "Holding weapons!" ) - end - if not self.FlightMenuROEReturnFire then - self.FlightMenuROEReturnFire = MENU_GROUP:New( self.EscortUnit:GetGroup(), "Return fire", self.FlightMenuROE ) - self.FlightMenuROEReturnFireFlight = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), "Flight", self.FlightMenuROEReturnFire, AI_ESCORT._ROE, self, GROUP.OptionROEReturnFire, "Returning fire!" ) - end - if not self.FlightMenuROEOpenFire then - self.FlightMenuROEOpenFire = MENU_GROUP:New( self.EscortUnit:GetGroup(), "Open fire", self.FlightMenuROE ) - self.FlightMenuROEOpenFireFlight = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), "Flight", self.FlightMenuROEOpenFire, AI_ESCORT._ROE, self, GROUP.OptionROEOpenFire, "Open fire at designated targets!" ) - end - if not self.FlightMenuROEWeaponFree then - self.FlightMenuROEWeaponFree = MENU_GROUP:New( self.EscortUnit:GetGroup(), "Engage all targets", self.FlightMenuROE ) - self.FlightMenuROEWeaponFreeFlight = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), "Flight", self.FlightMenuROEWeaponFree, AI_ESCORT._ROE, self, GROUP.OptionROEWeaponFree, "Engaging all targets!" ) - end + local FlightMenuROEHoldFire = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Hold fire", FlightMenuROE, AI_ESCORT._ROE, self, GROUP.OptionROEHoldFire, "Holding weapons!" ) + local FlightMenuROEReturnFire = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Return fire", FlightMenuROE, AI_ESCORT._ROE, self, GROUP.OptionROEReturnFire, "Returning fire!" ) + local FlightMenuROEOpenFire = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Open Fire", FlightMenuROE, AI_ESCORT._ROE, self, GROUP.OptionROEOpenFire, "Open fire at designated targets!" ) + local FlightMenuROEWeaponFree = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Engage all targets", FlightMenuROE, AI_ESCORT._ROE, self, GROUP.OptionROEWeaponFree, "Engaging all targets!" ) self.EscortGroupSet:ForSomeGroupAlive( --- @param Core.Group#GROUP EscortGroup @@ -1045,18 +985,20 @@ function AI_ESCORT:MenuROE( MenuTextFormat ) -- Rules of Engagement local EscortGroupName = EscortGroup:GetName() + local EscortMenu = MENU_GROUP:New( self.PlayerGroup, EscortGroupName, self.MainMenu ) + local EscortMenuROE = MENU_GROUP:New( self.PlayerGroup, "Rule Of Engagement", EscortMenu ) if EscortGroup:OptionROEHoldFirePossible() then - EscortGroup.EscortMenuROEHoldFire = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), EscortGroupName, self.FlightMenuROEHoldFire, AI_ESCORT._ROE, self, EscortGroup, GROUP.OptionROEHoldFire, "Holding weapons!" ) + local EscortMenuROEHoldFire = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Hold fire", EscortMenuROE, AI_ESCORT._ROE, self, EscortGroup, GROUP.OptionROEHoldFire, "Holding weapons!" ) end if EscortGroup:OptionROEReturnFirePossible() then - EscortGroup.EscortMenuROEReturnFire = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), EscortGroupName, self.FlightMenuROEReturnFire, AI_ESCORT._ROE, self, EscortGroup, GROUP.OptionROEReturnFire, "Returning fire!" ) + local EscortMenuROEReturnFire = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Return fire", EscortMenuROE, AI_ESCORT._ROE, self, EscortGroup, GROUP.OptionROEReturnFire, "Returning fire!" ) end if EscortGroup:OptionROEOpenFirePossible() then - EscortGroup.EscortMenuROEOpenFire = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), EscortGroupName, self.FlightMenuROEOpenFire, AI_ESCORT._ROE, self, EscortGroup, GROUP.OptionROEOpenFire, "Opening fire on designated targets!!" ) + EscortGroup.EscortMenuROEOpenFire = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Open Fire", EscortMenuROE, AI_ESCORT._ROE, self, EscortGroup, GROUP.OptionROEOpenFire, "Opening fire on designated targets!!" ) end if EscortGroup:OptionROEWeaponFreePossible() then - EscortGroup.EscortMenuROEWeaponFree = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), EscortGroupName, self.FlightMenuROEWeaponFree, AI_ESCORT._ROE, self, EscortGroup, GROUP.OptionROEWeaponFree, "Opening fire on targets of opportunity!" ) + EscortGroup.EscortMenuROEWeaponFree = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Engage all targets", EscortMenuROE, AI_ESCORT._ROE, self, EscortGroup, GROUP.OptionROEWeaponFree, "Opening fire on targets of opportunity!" ) end end end @@ -1073,26 +1015,12 @@ end function AI_ESCORT:MenuROT( MenuTextFormat ) self:F( MenuTextFormat ) - if not self.FlightMenuROT then - self.FlightMenuROT = MENU_GROUP:New( self.EscortUnit:GetGroup(), "ROT", self.FlightMenu ) - end + local FlightMenuROT = MENU_GROUP:New( self.PlayerGroup, "Reaction On Threat", self.FlightMenu ) - if not self.FlightMenuROTNoReaction then - self.FlightMenuROTNoReaction = MENU_GROUP:New( self.EscortUnit:GetGroup(), "Fight until death", self.FlightMenuROT ) - self.FlightMenuROTNoReactionFlight = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), "Flight", self.FlightMenuROTNoReaction, AI_ESCORT._ROT, self, GROUP.OptionROTNoReaction, "Fighting until death!" ) - end - if not self.FlightMenuROTPassiveDefense then - self.FlightMenuROTPassiveDefense = MENU_GROUP:New( self.EscortUnit:GetGroup(), "Use flares, chaff and jammers", self.FlightMenuROT ) - self.FlightMenuROTPassiveDefenseFlight = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), "Flight", self.FlightMenuROTPassiveDefense, AI_ESCORT._ROT, self, GROUP.OptionROTPassiveDefense, "Defending using jammers, chaff and flares!" ) - end - if not self.FlightMenuROTEvadeFire then - self.FlightMenuROTEvadeFire = MENU_GROUP:New( self.EscortUnit:GetGroup(), "Open fire", self.FlightMenuROT ) - self.FlightMenuROTEvadeFireFlight = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), "Evade enemy fire", self.FlightMenuROTEvadeFire, AI_ESCORT._ROT, self, GROUP.OptionROTEvadeFire, "Evading on enemy fire!" ) - end - if not self.FlightMenuROTVertical then - self.FlightMenuROTVertical = MENU_GROUP:New( self.EscortUnit:GetGroup(), "Avoid radar and evade fire", self.FlightMenuROT ) - self.FlightMenuROTVerticalFlight = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), "Flight", self.FlightMenuROTVertical, AI_ESCORT._ROT, self, GROUP.OptionROTVertical, "Evading on enemy fire with vertical manoeuvres!" ) - end + local FlightMenuROTNoReaction = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Fight until death", FlightMenuROT, AI_ESCORT._ROT, self, GROUP.OptionROTNoReaction, "Fighting until death!" ) + local FlightMenuROTPassiveDefense = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Use flares, chaff and jammers", FlightMenuROT, AI_ESCORT._ROT, self, GROUP.OptionROTPassiveDefense, "Defending using jammers, chaff and flares!" ) + local FlightMenuROTEvadeFire = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Open fire", FlightMenuROT, AI_ESCORT._ROT, self, GROUP.OptionROTEvadeFire, "Evading on enemy fire!" ) + local FlightMenuROTVertical = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Avoid radar and evade fire", FlightMenuROT, AI_ESCORT._ROT, self, GROUP.OptionROTVertical, "Evading on enemy fire with vertical manoeuvres!" ) self.EscortGroupSet:ForSomeGroupAlive( --- @param Core.Group#GROUP EscortGroup @@ -1100,20 +1028,22 @@ function AI_ESCORT:MenuROT( MenuTextFormat ) if EscortGroup:IsAir() then local EscortGroupName = EscortGroup:GetName() + local EscortMenu = MENU_GROUP:New( self.PlayerGroup, EscortGroupName, self.MainMenu ) + local EscortMenuROT = MENU_GROUP:New( self.PlayerGroup, "Reaction On Threat", EscortMenu ) if not EscortGroup.EscortMenuEvasion then -- Reaction to Threats if EscortGroup:OptionROTNoReactionPossible() then - EscortGroup.EscortMenuEvasionNoReaction = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), EscortGroupName, self.FlightMenuROTNoReaction, AI_ESCORT._ROT, self, EscortGroup, GROUP.OptionROTNoReaction, "Fighting until death!" ) + local EscortMenuEvasionNoReaction = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Fight until death", EscortMenuROT, AI_ESCORT._ROT, self, EscortGroup, GROUP.OptionROTNoReaction, "Fighting until death!" ) end if EscortGroup:OptionROTPassiveDefensePossible() then - EscortGroup.EscortMenuEvasionPassiveDefense = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), EscortGroupName, self.FlightMenuROTPassiveDefense, AI_ESCORT._ROT, self, EscortGroup, GROUP.OptionROTPassiveDefense, "Defending using jammers, chaff and flares!" ) + local EscortMenuEvasionPassiveDefense = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Use flares, chaff and jammers", EscortMenuROT, AI_ESCORT._ROT, self, EscortGroup, GROUP.OptionROTPassiveDefense, "Defending using jammers, chaff and flares!" ) end if EscortGroup:OptionROTEvadeFirePossible() then - EscortGroup.EscortMenuEvasionEvadeFire = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), EscortGroupName, self.FlightMenuROTEvadeFire, AI_ESCORT._ROT, self, EscortGroup, GROUP.OptionROTEvadeFire, "Evading on enemy fire!" ) + local EscortMenuEvasionEvadeFire = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Open fire", EscortMenuROT, AI_ESCORT._ROT, self, EscortGroup, GROUP.OptionROTEvadeFire, "Evading on enemy fire!" ) end if EscortGroup:OptionROTVerticalPossible() then - EscortGroup.EscortMenuOptionEvasionVertical = MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), EscortGroupName, self.FlightMenuROTVertical, AI_ESCORT._ROT, self, EscortGroup, GROUP.OptionROTVertical, "Evading on enemy fire with vertical manoeuvres!" ) + local EscortMenuOptionEvasionVertical = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Avoid radar and evade fire", EscortMenuROT, AI_ESCORT._ROT, self, EscortGroup, GROUP.OptionROTVertical, "Evading on enemy fire with vertical manoeuvres!" ) end end end @@ -1132,7 +1062,7 @@ function AI_ESCORT:MenuResumeMission() if not self.EscortMenuResumeMission then -- Mission Resume Menu Root - self.EscortMenuResumeMission = MENU_GROUP:New( self.EscortUnit:GetGroup(), "Resume mission from", self.EscortMenu ) + self.EscortMenuResumeMission = MENU_GROUP:New( self.PlayerGroup, "Resume mission from", self.EscortMenu ) end return self @@ -1410,7 +1340,7 @@ end -- @param Wrapper.Group#GROUP EscortGroup function AI_ESCORT.___Resume( EscortGroup, self ) - local PlayerGroup = self.EscortUnit:GetGroup() + local PlayerGroup = self.PlayerGroup if EscortGroup.EscortMode == AI_ESCORT.MODE.FOLLOW then self:JoinFormation( EscortGroup ) @@ -1535,7 +1465,7 @@ end function AI_ESCORT:_ROE( EscortGroup, EscortROEFunction, EscortROEMessage ) pcall( function() EscortROEFunction() end ) - EscortGroup:MessageTypeToGroup( EscortROEMessage, MESSAGE.Type.Information, self.EscortUnit:GetGroup() ) + EscortGroup:MessageTypeToGroup( EscortROEMessage, MESSAGE.Type.Information, self.PlayerGroup ) end function AI_ESCORT:_FlightROE( EscortROEFunction, EscortROEMessage ) @@ -1550,7 +1480,7 @@ end function AI_ESCORT:_ROT( EscortGroup, EscortROTFunction, EscortROTMessage ) pcall( function() EscortROTFunction() end ) - EscortGroup:MessageTypeToGroup( EscortROTMessage, MESSAGE.Type.Information, self.EscortUnit:GetGroup() ) + EscortGroup:MessageTypeToGroup( EscortROTMessage, MESSAGE.Type.Information, self.PlayerGroup ) end @@ -1625,6 +1555,10 @@ function AI_ESCORT:_ReportTargetsScheduler( EscortGroup ) local TimeUpdate = timer.getTime() + local EscortGroupName = EscortGroup:GetName() + local EscortMenu = MENU_GROUP:New( self.PlayerGroup, EscortGroupName, self.MainMenu ) + local EscortMenuAttackTargets = MENU_GROUP:New( self.PlayerGroup, "Attack targets", EscortMenu ) + for DetectedItemIndex, DetectedItem in pairs( DetectedItems ) do local DetectedItemReportSummary = self.Detection:DetectedItemReportMenu( DetectedItem, EscortGroup, _DATABASE:GetPlayerSettings( self.EscortUnit:GetPlayerName() ) ) @@ -1632,9 +1566,10 @@ function AI_ESCORT:_ReportTargetsScheduler( EscortGroup ) local DetectedMenu = DetectedItemReportSummary:Text("\n") if EscortGroup:IsAir() then - MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), + + MENU_GROUP_COMMAND:New( self.PlayerGroup, DetectedMenu, - EscortGroup.EscortMenuAttackNearbyTargets, + EscortMenuAttackTargets, AI_ESCORT._AttackTarget, self, EscortGroup, @@ -1642,8 +1577,8 @@ function AI_ESCORT:_ReportTargetsScheduler( EscortGroup ) ):SetTag( "Escort" ):SetTime( TimeUpdate ) else if self.EscortMenuTargetAssistance then - local MenuTargetAssistance = MENU_GROUP:New( self.EscortUnit:GetGroup(), EscortGroupName, EscortGroup.EscortMenuTargetAssistance ) - MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), + local MenuTargetAssistance = MENU_GROUP:New( self.PlayerGroup, EscortGroupName, EscortGroup.EscortMenuTargetAssistance ) + MENU_GROUP_COMMAND:New( self.PlayerGroup, DetectedMenu, MenuTargetAssistance, AI_ESCORT._AssistTarget, @@ -1657,7 +1592,7 @@ function AI_ESCORT:_ReportTargetsScheduler( EscortGroup ) end - EscortGroup.EscortMenuAttackNearbyTargets:RemoveSubMenus( TimeUpdate, "Esort" ) + EscortMenuAttackTargets:RemoveSubMenus( TimeUpdate, "Esort" ) return true else @@ -1678,9 +1613,9 @@ function AI_ESCORT:_FlightReportTargetsScheduler() local DetectedTargetsReport = REPORT:New( "Reporting detected targets:\n" ) -- A new report to display the detected targets as a message to the player. - if self.EscortUnit:IsAlive() and EscortGroup:IsAlive() then + if EscortGroup and ( self.EscortUnit:IsAlive() and EscortGroup:IsAlive() ) then - local ClientGroup = self.EscortUnit:GetGroup() + local ClientGroup = self.PlayerGroup local TimeUpdate = timer.getTime() @@ -1691,6 +1626,8 @@ function AI_ESCORT:_FlightReportTargetsScheduler() local ClientEscortTargets = self.Detection + local FlightMenuAttackTargets = MENU_GROUP:New( self.PlayerGroup, "Attack targets", self.FlightMenu ) + for DetectedItemIndex, DetectedItem in pairs( DetectedItems ) do self:F("FlightReportTargetScheduler Targets") @@ -1701,9 +1638,9 @@ function AI_ESCORT:_FlightReportTargetsScheduler() local DetectedItemReportMenu = self.Detection:DetectedItemReportMenu( DetectedItem, ClientGroup, _DATABASE:GetPlayerSettings( self.EscortUnit:GetPlayerName() ) ) local ReportMenuText = DetectedItemReportMenu:Text(", ") - MENU_GROUP_COMMAND:New( self.EscortUnit:GetGroup(), + MENU_GROUP_COMMAND:New( self.PlayerGroup, ReportMenuText, - self.FlightMenuAttackNearbyTargets, + FlightMenuAttackTargets, AI_ESCORT._FlightAttackTarget, self, DetectedItem @@ -1714,12 +1651,12 @@ function AI_ESCORT:_FlightReportTargetsScheduler() DetectedTargetsReport:AddIndent( ReportSummary, "-" ) end - self.FlightMenuAttackNearbyTargets:RemoveSubMenus( TimeUpdate, "Flight" ) + FlightMenuAttackTargets:RemoveSubMenus( TimeUpdate, "Flight" ) if DetectedTargets then - EscortGroup:MessageTypeToGroup( DetectedTargetsReport:Text( "\n" ), MESSAGE.Type.Information, self.EscortUnit:GetGroup() ) + EscortGroup:MessageTypeToGroup( DetectedTargetsReport:Text( "\n" ), MESSAGE.Type.Information, self.PlayerGroup ) -- else --- EscortGroup:MessageTypeToGroup( "No targets detected.", MESSAGE.Type.Information, self.EscortUnit:GetGroup() ) +-- EscortGroup:MessageTypeToGroup( "No targets detected.", MESSAGE.Type.Information, self.PlayerGroup ) end return true From 78a5e89928285b2465e273e449cb728bb5d67731 Mon Sep 17 00:00:00 2001 From: FlightControl Date: Fri, 17 May 2019 21:12:02 +0200 Subject: [PATCH 13/25] Synth --- Moose Development/Moose/AI/AI_Escort.lua | 72 ++++++++++++------------ 1 file changed, 37 insertions(+), 35 deletions(-) diff --git a/Moose Development/Moose/AI/AI_Escort.lua b/Moose Development/Moose/AI/AI_Escort.lua index 2a78343c6..8d94b39ae 100644 --- a/Moose Development/Moose/AI/AI_Escort.lua +++ b/Moose Development/Moose/AI/AI_Escort.lua @@ -409,33 +409,6 @@ function AI_ESCORT:MenuFormation( Formation, ... ) end ---- Defines --- Defines a menu slot to let the escort to join formation. --- This menu will appear under **Formation**. --- @param #AI_ESCORT self --- @return #AI_ESCORT -function AI_ESCORT:MenuJoinUp() - - local FlightMenuReportNavigation = MENU_GROUP:New( self.PlayerGroup, "Navigation", self.FlightMenu ) - local FlightMenuJoinUp = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Join Up", FlightMenuReportNavigation, AI_ESCORT._FlightJoinUp, self ) - - self.EscortGroupSet:ForSomeGroupAlive( - --- @param Core.Group#GROUP EscortGroup - function( EscortGroup ) - if EscortGroup:IsAir() then - - local EscortGroupName = EscortGroup:GetName() - local EscortMenu = MENU_GROUP:New( self.PlayerGroup, EscortGroupName, self.MainMenu ) - local EscortMenuReportNavigation = MENU_GROUP:New( self.PlayerGroup, "Navigation", EscortMenu ) - local EscortMenuJoinUp = MENU_GROUP:New( self.PlayerGroup, "Join Up", EscortMenuReportNavigation ) - - end - end - ) - - return self -end - - --- Defines a menu slot to let the escort to join in a trail formation. -- This menu will appear under **Formation**. -- @param #AI_ESCORT self @@ -587,6 +560,33 @@ function AI_ESCORT:MenuFormationBox( XStart, XSpace, YStart, YSpace, ZStart, ZSp end +--- Defines --- Defines a menu slot to let the escort to join formation. +-- This menu will appear under **Formation**. +-- @param #AI_ESCORT self +-- @return #AI_ESCORT +function AI_ESCORT:MenuJoinUp() + + local FlightMenuReportNavigation = MENU_GROUP:New( self.PlayerGroup, "Navigation", self.FlightMenu ) + local FlightMenuJoinUp = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Join Up", FlightMenuReportNavigation, AI_ESCORT._FlightJoinUp, self ) + + self.EscortGroupSet:ForSomeGroupAlive( + --- @param Core.Group#GROUP EscortGroup + function( EscortGroup ) + if EscortGroup:IsAir() then + + local EscortGroupName = EscortGroup:GetName() + local EscortMenu = MENU_GROUP:New( self.PlayerGroup, EscortGroupName, self.MainMenu ) + local EscortMenuReportNavigation = MENU_GROUP:New( self.PlayerGroup, "Navigation", EscortMenu ) + local EscortMenuJoinUp = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Join Up", EscortMenuReportNavigation, AI_ESCORT._JoinUp, self ) + + end + end + ) + + return self +end + + --- Defines a menu slot to let the escort hold at their current position and stay low with a specified height during a specified time in seconds. -- This menu will appear under **Hold position**. -- @param #AI_ESCORT self @@ -620,11 +620,13 @@ function AI_ESCORT:MenuHoldAtEscortPosition( Height, Speed, MenuTextFormat ) end end + local FlightMenuReportNavigation = MENU_GROUP:New( self.PlayerGroup, "Navigation", self.FlightMenu ) + local FlightMenuHoldPosition = MENU_GROUP_COMMAND :New( self.PlayerGroup, MenuText, - self.FlightMenu, + FlightMenuReportNavigation, AI_ESCORT._FlightHoldPosition, self, nil, @@ -640,13 +642,12 @@ function AI_ESCORT:MenuHoldAtEscortPosition( Height, Speed, MenuTextFormat ) local EscortGroupName = EscortGroup:GetName() local EscortMenu = MENU_GROUP:New( self.PlayerGroup, EscortGroupName, self.MainMenu ) local EscortMenuReportNavigation = MENU_GROUP:New( self.PlayerGroup, "Navigation", EscortMenu ) - local EscortMenuHold = MENU_GROUP:New( self.PlayerGroup, MenuText, EscortMenuReportNavigation ) local EscortMenuHoldPosition = MENU_GROUP_COMMAND :New( self.PlayerGroup, - EscortGroupName, - EscortMenuHold, + MenuText, + EscortMenuReportNavigation, AI_ESCORT._HoldPosition, self, EscortGroup, @@ -695,11 +696,13 @@ function AI_ESCORT:MenuHoldAtLeaderPosition( Height, Speed, MenuTextFormat ) end end + local FlightMenuReportNavigation = MENU_GROUP:New( self.PlayerGroup, "Navigation", self.FlightMenu ) + local FlightMenuHoldAtLeaderPosition = MENU_GROUP_COMMAND :New( self.PlayerGroup, MenuText, - self.FlightMenu, + FlightMenuReportNavigation, AI_ESCORT._FlightHoldPosition, self, self.PlayerGroup, @@ -715,13 +718,12 @@ function AI_ESCORT:MenuHoldAtLeaderPosition( Height, Speed, MenuTextFormat ) local EscortGroupName = EscortGroup:GetName() local EscortMenu = MENU_GROUP:New( self.PlayerGroup, EscortGroupName, self.MainMenu ) local EscortMenuReportNavigation = MENU_GROUP:New( self.PlayerGroup, "Navigation", EscortMenu ) - local EscortMenuHold = MENU_GROUP:New( self.PlayerGroup, MenuText, EscortMenuReportNavigation ) local EscortMenuHoldAtLeaderPosition = MENU_GROUP_COMMAND :New( self.PlayerGroup, - EscortGroupName, - EscortMenuHold, + MenuText, + EscortMenuReportNavigation, AI_ESCORT._HoldPosition, self, self.PlayerGroup, From 6be56b1b8683382db823c22ec36b2f20643ca3cb Mon Sep 17 00:00:00 2001 From: FlightControl Date: Thu, 23 May 2019 16:33:47 +0300 Subject: [PATCH 14/25] Progress --- Moose Development/Moose/AI/AI_Escort.lua | 80 ++++++++----------- .../Moose/AI/AI_Escort_Request.lua | 17 ++-- Moose Development/Moose/AI/AI_Formation.lua | 74 +++++++++++++---- 3 files changed, 98 insertions(+), 73 deletions(-) diff --git a/Moose Development/Moose/AI/AI_Escort.lua b/Moose Development/Moose/AI/AI_Escort.lua index 8d94b39ae..6a7517dd9 100644 --- a/Moose Development/Moose/AI/AI_Escort.lua +++ b/Moose Development/Moose/AI/AI_Escort.lua @@ -176,10 +176,6 @@ AI_ESCORT = { EscortUnit = nil, EscortGroup = nil, EscortMode = 1, - MODE = { - FOLLOW = 1, - MISSION = 2, - }, Targets = {}, -- The identified targets FollowScheduler = nil, ReportTargets = true, @@ -192,11 +188,6 @@ AI_ESCORT = { --- @field Functional.Detection#DETECTION_AREAS AI_ESCORT.Detection = nil ---- AI_ESCORT.Mode class --- @type AI_ESCORT.MODE --- @field #number FOLLOW --- @field #number MISSION - --- MENUPARAM type -- @type MENUPARAM -- @field #AI_ESCORT ParamSelf @@ -225,8 +216,6 @@ function AI_ESCORT:New( EscortUnit, EscortGroupSet, EscortName, EscortBriefing ) local self = BASE:Inherit( self, AI_FORMATION:New( EscortUnit, EscortGroupSet, EscortName, EscortBriefing ) ) -- #AI_ESCORT self:F( { EscortUnit, EscortGroupSet } ) - self.EscortUnit = self.FollowUnit -- Wrapper.Unit#UNIT - self.PlayerUnit = self.FollowUnit -- Wrapper.Unit#UNIT self.PlayerGroup = self.FollowUnit:GetGroup() -- Wrapper.Group#GROUP @@ -261,18 +250,16 @@ function AI_ESCORT:New( EscortUnit, EscortGroupSet, EscortName, EscortBriefing ) --- @param Core.Group#GROUP EscortGroup function( EscortGroup ) -- Set EscortGroup known at EscortUnit. - if not self.EscortUnit._EscortGroups then - self.EscortUnit._EscortGroups = {} + if not self.PlayerUnit._EscortGroups then + self.PlayerUnit._EscortGroups = {} end - if not self.EscortUnit._EscortGroups[EscortGroup:GetName()] then - self.EscortUnit._EscortGroups[EscortGroup:GetName()] = {} - self.EscortUnit._EscortGroups[EscortGroup:GetName()].EscortGroup = EscortGroup - self.EscortUnit._EscortGroups[EscortGroup:GetName()].EscortName = self.EscortName - self.EscortUnit._EscortGroups[EscortGroup:GetName()].Detection = self.Detection + if not self.PlayerUnit._EscortGroups[EscortGroup:GetName()] then + self.PlayerUnit._EscortGroups[EscortGroup:GetName()] = {} + self.PlayerUnit._EscortGroups[EscortGroup:GetName()].EscortGroup = EscortGroup + self.PlayerUnit._EscortGroups[EscortGroup:GetName()].EscortName = self.EscortName + self.PlayerUnit._EscortGroups[EscortGroup:GetName()].Detection = self.Detection end - - EscortGroup.EscortMode = AI_ESCORT.MODE.FOLLOW end ) @@ -297,11 +284,9 @@ function AI_ESCORT:onafterStart( EscortGroupSet ) local LeaderEscort = EscortGroupSet:GetFirst() -- Wrapper.Group#GROUP local Report = REPORT:New( "Escort reporting:" ) - Report:Add( "Current coordinate: " .. LeaderEscort:GetCoordinate():ToString( self.EscortUnit ) ) - Report:Add( "Configuration: " .. EscortGroupSet:GetUnitTypeNames():Text( ", " ) ) - Report:Add( "Joining Up ..." ) + Report:Add( "Joining Up " .. EscortGroupSet:GetUnitTypeNames():Text( ", " ) .. " from " .. LeaderEscort:GetCoordinate():ToString( self.PlayerUnit ) ) - LeaderEscort:MessageTypeToGroup( Report:Text(), MESSAGE.Type.Information, self.EscortUnit ) + LeaderEscort:MessageTypeToGroup( Report:Text(), MESSAGE.Type.Information, self.PlayerUnit ) self.Detection = DETECTION_AREAS:New( EscortGroupSet, 5000 ) @@ -317,7 +302,7 @@ function AI_ESCORT:SetDetection( Detection ) self.Detection = Detection self.EscortGroup.Detection = self.Detection - self.EscortUnit._EscortGroups[self.EscortGroup:GetName()].Detection = self.EscortGroup.Detection + self.PlayerUnit._EscortGroups[self.EscortGroup:GetName()].Detection = self.EscortGroup.Detection Detection:__Start( 1 ) @@ -935,7 +920,7 @@ function AI_ESCORT:MenuReportTargets( Seconds ) -- Attack Targets local EscortMenuAttackTargets = MENU_GROUP:New( self.PlayerGroup, "Attack targets", EscortMenu ) - --EscortGroup.ReportTargetsScheduler = SCHEDULER:New( self, self._ReportTargetsScheduler, { EscortGroup }, timer, Seconds ) + EscortGroup.ReportTargetsScheduler = SCHEDULER:New( self, self._ReportTargetsScheduler, { EscortGroup }, timer, Seconds ) timer=timer+1 end end @@ -1078,7 +1063,7 @@ end -- @param #number OrbitSeconds function AI_ESCORT:_HoldPosition( OrbitGroup, EscortGroup, OrbitHeight, OrbitSeconds ) - local EscortUnit = self.EscortUnit + local EscortUnit = self.PlayerUnit local OrbitUnit = OrbitGroup:GetUnit(1) -- Wrapper.Unit#UNIT @@ -1121,7 +1106,7 @@ end -- @param #number OrbitSeconds function AI_ESCORT:_FlightHoldPosition( OrbitGroup, OrbitHeight, OrbitSeconds ) - local EscortUnit = self.EscortUnit + local EscortUnit = self.PlayerUnit self.EscortGroupSet:ForSomeGroupAlive( --- @param Core.Group#GROUP EscortGroup @@ -1141,10 +1126,11 @@ end function AI_ESCORT:_JoinUp( EscortGroup ) - local EscortUnit = self.EscortUnit + local EscortUnit = self.PlayerUnit self:JoinFormation( EscortGroup ) - EscortGroup.EscortMode = AI_ESCORT.MODE.FOLLOW + + EscortGroup:SetState( self, "Mode", self.__Enum.Mode.Follow ) end @@ -1218,7 +1204,7 @@ end function AI_ESCORT:_Flare( EscortGroup, Color, Message ) - local EscortUnit = self.EscortUnit + local EscortUnit = self.PlayerUnit EscortGroup:GetUnit(1):Flare( Color ) EscortGroup:MessageTypeToGroup( Message, MESSAGE.Type.Information, EscortUnit:GetGroup() ) @@ -1242,7 +1228,7 @@ end function AI_ESCORT:_Smoke( EscortGroup, Color, Message ) - local EscortUnit = self.EscortUnit + local EscortUnit = self.PlayerUnit EscortGroup:GetUnit(1):Smoke( Color ) EscortGroup:MessageTypeToGroup( Message, MESSAGE.Type.Information, EscortUnit:GetGroup() ) @@ -1264,7 +1250,7 @@ end function AI_ESCORT:_ReportNearbyTargetsNow( EscortGroup ) - local EscortUnit = self.EscortUnit + local EscortUnit = self.PlayerUnit self:_ReportTargetsScheduler( EscortGroup ) @@ -1280,7 +1266,7 @@ end function AI_ESCORT:_SwitchReportNearbyTargets( EscortGroup, ReportTargets ) - local EscortUnit = self.EscortUnit + local EscortUnit = self.PlayerUnit self.ReportTargets = ReportTargets @@ -1312,7 +1298,7 @@ end function AI_ESCORT:_ScanTargets( ScanDuration ) local EscortGroup = self.EscortGroup -- Wrapper.Group#GROUP - local EscortUnit = self.EscortUnit + local EscortUnit = self.PlayerUnit self.FollowScheduler:Stop( self.FollowSchedule ) @@ -1344,10 +1330,8 @@ function AI_ESCORT.___Resume( EscortGroup, self ) local PlayerGroup = self.PlayerGroup - if EscortGroup.EscortMode == AI_ESCORT.MODE.FOLLOW then - self:JoinFormation( EscortGroup ) - EscortGroup:MessageTypeToClient( "Destroyed all targets. Rejoining.", MESSAGE.Type.Information, PlayerGroup ) - end + self:JoinFormation( EscortGroup ) + EscortGroup:MessageTypeToClient( "Destroyed all targets. Rejoining.", MESSAGE.Type.Information, PlayerGroup ) end @@ -1359,7 +1343,7 @@ function AI_ESCORT:_AttackTarget( EscortGroup, DetectedItem ) self:F( EscortGroup ) - local EscortUnit = self.EscortUnit + local EscortUnit = self.PlayerUnit self:ReleaseFormation( EscortGroup ) @@ -1383,7 +1367,7 @@ function AI_ESCORT:_AttackTarget( EscortGroup, DetectedItem ) ) Tasks[#Tasks+1] = EscortGroup:TaskCombo( AttackUnitTasks ) - Tasks[#Tasks+1] = EscortGroup:TaskFunction( "AI_ESCORT.___Resume", self, EscortGroup ) + Tasks[#Tasks+1] = EscortGroup:TaskFunction( "AI_ESCORT.___Resume", EscortGroup, self ) EscortGroup:SetTask( EscortGroup:TaskCombo( @@ -1439,7 +1423,7 @@ end -- @param Functional.Detection#DETECTION_BASE.DetectedItem DetectedItem function AI_ESCORT:_AssistTarget( EscortGroup, DetectedItem ) - local EscortUnit = self.EscortUnit + local EscortUnit = self.PlayerUnit local DetectedSet = self.Detection:GetDetectedItemSet( DetectedItem ) @@ -1500,7 +1484,7 @@ end function AI_ESCORT:_ResumeMission( WayPoint ) local EscortGroup = self.EscortGroup - local EscortUnit = self.EscortUnit + local EscortUnit = self.PlayerUnit self.FollowScheduler:Stop( self.FollowSchedule ) @@ -1540,7 +1524,7 @@ end function AI_ESCORT:_ReportTargetsScheduler( EscortGroup ) self:F( EscortGroup:GetName() ) - if EscortGroup:IsAlive() and self.EscortUnit:IsAlive() then + if EscortGroup:IsAlive() and self.PlayerUnit:IsAlive() then if true then @@ -1563,7 +1547,7 @@ function AI_ESCORT:_ReportTargetsScheduler( EscortGroup ) for DetectedItemIndex, DetectedItem in pairs( DetectedItems ) do - local DetectedItemReportSummary = self.Detection:DetectedItemReportMenu( DetectedItem, EscortGroup, _DATABASE:GetPlayerSettings( self.EscortUnit:GetPlayerName() ) ) + local DetectedItemReportSummary = self.Detection:DetectedItemReportMenu( DetectedItem, EscortGroup, _DATABASE:GetPlayerSettings( self.PlayerUnit:GetPlayerName() ) ) local DetectedMenu = DetectedItemReportSummary:Text("\n") @@ -1615,7 +1599,7 @@ function AI_ESCORT:_FlightReportTargetsScheduler() local DetectedTargetsReport = REPORT:New( "Reporting detected targets:\n" ) -- A new report to display the detected targets as a message to the player. - if EscortGroup and ( self.EscortUnit:IsAlive() and EscortGroup:IsAlive() ) then + if EscortGroup and ( self.PlayerUnit:IsAlive() and EscortGroup:IsAlive() ) then local ClientGroup = self.PlayerGroup @@ -1637,7 +1621,7 @@ function AI_ESCORT:_FlightReportTargetsScheduler() DetectedTargets = true -- There are detected targets, when the content of the for loop is executed. We use it to display a message. - local DetectedItemReportMenu = self.Detection:DetectedItemReportMenu( DetectedItem, ClientGroup, _DATABASE:GetPlayerSettings( self.EscortUnit:GetPlayerName() ) ) + local DetectedItemReportMenu = self.Detection:DetectedItemReportMenu( DetectedItem, ClientGroup, _DATABASE:GetPlayerSettings( self.PlayerUnit:GetPlayerName() ) ) local ReportMenuText = DetectedItemReportMenu:Text(", ") MENU_GROUP_COMMAND:New( self.PlayerGroup, @@ -1648,7 +1632,7 @@ function AI_ESCORT:_FlightReportTargetsScheduler() DetectedItem ):SetTag( "Flight" ):SetTime( TimeUpdate ) - local DetectedItemReportSummary = self.Detection:DetectedItemReportSummary( DetectedItem, ClientGroup, _DATABASE:GetPlayerSettings( self.EscortUnit:GetPlayerName() ) ) + local DetectedItemReportSummary = self.Detection:DetectedItemReportSummary( DetectedItem, ClientGroup, _DATABASE:GetPlayerSettings( self.PlayerUnit:GetPlayerName() ) ) local ReportSummary = DetectedItemReportSummary:Text(", ") DetectedTargetsReport:AddIndent( ReportSummary, "-" ) end diff --git a/Moose Development/Moose/AI/AI_Escort_Request.lua b/Moose Development/Moose/AI/AI_Escort_Request.lua index 372f09d22..8d17d2657 100644 --- a/Moose Development/Moose/AI/AI_Escort_Request.lua +++ b/Moose Development/Moose/AI/AI_Escort_Request.lua @@ -212,7 +212,7 @@ function AI_ESCORT_REQUEST:New( EscortUnit, EscortSpawn, EscortAirbase, EscortNa local self = BASE:Inherit( self, AI_ESCORT:New( EscortUnit, self.EscortGroupSet, EscortName, EscortBriefing ) ) -- #AI_ESCORT_REQUEST - self.LeaderGroup = self.EscortUnit:GetGroup() + self.LeaderGroup = self.PlayerUnit:GetGroup() self.Detection = DETECTION_AREAS:New( self.EscortGroupSet, 5000 ) self.Detection:__Start( 30 ) @@ -235,15 +235,14 @@ function AI_ESCORT_REQUEST:SpawnEscort() function() local LeaderEscort = self.EscortGroupSet:GetFirst() -- Wrapper.Group#GROUP - local Report = REPORT:New( "Escorts Reporting." ) - Report:Add( "Current coordinate: " .. LeaderEscort:GetCoordinate():ToString( self.EscortUnit ) ) - Report:Add( "Configuration: " .. self.EscortGroupSet:GetUnitTypeNames():Text( ", " ) ) - Report:Add( "Joining Up ..." ) - - LeaderEscort:MessageTypeToGroup( Report:Text(), MESSAGE.Type.Information, self.EscortUnit ) + local Report = REPORT:New() + + Report:Add( "Joining Up " .. self.EscortGroupSet:GetUnitTypeNames():Text( ", " ) .. " from " .. LeaderEscort:GetCoordinate():ToString( self.EscortUnit ) ) + + LeaderEscort:MessageTypeToGroup( Report:Text(), MESSAGE.Type.Information, self.PlayerUnit ) self:FormationTrail( 50, 50, 50 ) self:JoinFormation( EscortGroup ) - self:Menus() + self:Menus( self.XStart, self.XSpace, self.YStart, self.YSpace, self.ZStart, self.ZSpace, self.ZLevels ) end ) @@ -254,7 +253,7 @@ end function AI_ESCORT_REQUEST:onafterStart( EscortGroupSet ) if not self.MenuRequestEscort then - self.MenuRequestEscort = MENU_GROUP_COMMAND:New( self.LeaderGroup, "Request A2G Escort", self.FlightMenu, + self.MenuRequestEscort = MENU_GROUP_COMMAND:New( self.LeaderGroup, "Request A2G Escort", self.MainMenu, function() self:SpawnEscort() end diff --git a/Moose Development/Moose/AI/AI_Formation.lua b/Moose Development/Moose/AI/AI_Formation.lua index 5eae434e2..5eb5d0e90 100644 --- a/Moose Development/Moose/AI/AI_Formation.lua +++ b/Moose Development/Moose/AI/AI_Formation.lua @@ -110,10 +110,43 @@ AI_FORMATION = { dtFollow = 0.5, } ---- AI_FORMATION.Mode class --- @type AI_FORMATION.MODE --- @field #number FOLLOW --- @field #number MISSION +AI_FORMATION.__Enum = {} + +--- @type AI_FORMATION.__Enum.Formation +-- @field #number None +-- @field #number Line +-- @field #number Trail +-- @field #number Stack +-- @field #number LeftLine +-- @field #number RightLine +-- @field #number LeftWing +-- @field #number RightWing +-- @field #number Vic +-- @field #number Box +AI_FORMATION.__Enum.Formation = { + None = 0, + Mission = 1, + Line = 2, + Trail = 3, + Stack = 4, + LeftLine = 5, + RightLine = 6, + LeftWing = 7, + RightWing = 8, + Vic = 9, + Box = 10, +} + +--- @type AI_FORMATION.__Enum.Mode +-- @field #number Mission +-- @field #number Formation +AI_FORMATION.__Enum.Mode = { + Mission = 0, + Formation = 1, +} + + + --- MENUPARAM type -- @type MENUPARAM @@ -139,7 +172,7 @@ function AI_FORMATION:New( FollowUnit, FollowGroupSet, FollowName, FollowBriefin self.FollowGroupSet:ForEachGroup( function( FollowGroup ) self:E("Following") - FollowGroup.Following = true + FollowGroup:SetState( self, "Mode", self.__Enum.Mode.Formation ) end ) @@ -663,8 +696,8 @@ end -- @param #nubmer ZStart The start position on the Z-axis in meters for the first group. -- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group. -- @return #AI_FORMATION -function AI_FORMATION:onafterFormationLine( FollowGroupSet, From , Event , To, XStart, XSpace, YStart, YSpace, ZStart, ZSpace ) --R2.1 - self:F( { FollowGroupSet, From , Event ,To, XStart, XSpace, YStart, YSpace, ZStart, ZSpace } ) +function AI_FORMATION:onafterFormationLine( FollowGroupSet, From , Event , To, XStart, XSpace, YStart, YSpace, ZStart, ZSpace, Formation ) --R2.1 + self:F( { FollowGroupSet, From , Event ,To, XStart, XSpace, YStart, YSpace, ZStart, ZSpace, Formation } ) FollowGroupSet:Flush( self ) @@ -682,6 +715,9 @@ function AI_FORMATION:onafterFormationLine( FollowGroupSet, From , Event , To, X local Vec3 = PointVec3:GetVec3() FollowGroup:SetState( self, "FormationVec3", Vec3 ) i = i + 1 + + FollowGroup:SetState( FollowGroup, "Formation", Formation ) + FollowGroup:SetState( FollowGroup, "Mode", self.__Enum.Mode.Formation ) end return self @@ -700,7 +736,7 @@ end -- @return #AI_FORMATION function AI_FORMATION:onafterFormationTrail( FollowGroupSet, From , Event , To, XStart, XSpace, YStart ) --R2.1 - self:onafterFormationLine(FollowGroupSet,From,Event,To,XStart,XSpace,YStart,0,0,0) + self:onafterFormationLine(FollowGroupSet,From,Event,To,XStart,XSpace,YStart,0,0,0, self.__Enum.Formation.Trail ) return self end @@ -719,7 +755,7 @@ end -- @return #AI_FORMATION function AI_FORMATION:onafterFormationStack( FollowGroupSet, From , Event , To, XStart, XSpace, YStart, YSpace ) --R2.1 - self:onafterFormationLine(FollowGroupSet,From,Event,To,XStart,XSpace,YStart,YSpace,0,0) + self:onafterFormationLine(FollowGroupSet,From,Event,To,XStart,XSpace,YStart,YSpace,0,0, self.__Enum.Formation.Stack ) return self end @@ -740,7 +776,7 @@ end -- @return #AI_FORMATION function AI_FORMATION:onafterFormationLeftLine( FollowGroupSet, From , Event , To, XStart, YStart, ZStart, ZSpace ) --R2.1 - self:onafterFormationLine(FollowGroupSet,From,Event,To,XStart,0,YStart,0,-ZStart,-ZSpace) + self:onafterFormationLine(FollowGroupSet,From,Event,To,XStart,0,YStart,0,-ZStart,-ZSpace, self.__Enum.Formation.LeftLine ) return self end @@ -759,7 +795,7 @@ end -- @return #AI_FORMATION function AI_FORMATION:onafterFormationRightLine( FollowGroupSet, From , Event , To, XStart, YStart, ZStart, ZSpace ) --R2.1 - self:onafterFormationLine(FollowGroupSet,From,Event,To,XStart,0,YStart,0,ZStart,ZSpace) + self:onafterFormationLine(FollowGroupSet,From,Event,To,XStart,0,YStart,0,ZStart,ZSpace,self.__Enum.Formation.RightLine) return self end @@ -778,7 +814,7 @@ end -- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group. function AI_FORMATION:onafterFormationLeftWing( FollowGroupSet, From , Event , To, XStart, XSpace, YStart, ZStart, ZSpace ) --R2.1 - self:onafterFormationLine(FollowGroupSet,From,Event,To,XStart,XSpace,YStart,0,-ZStart,-ZSpace) + self:onafterFormationLine(FollowGroupSet,From,Event,To,XStart,XSpace,YStart,0,-ZStart,-ZSpace,self.__Enum.Formation.LeftWing) return self end @@ -798,7 +834,7 @@ end -- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group. function AI_FORMATION:onafterFormationRightWing( FollowGroupSet, From , Event , To, XStart, XSpace, YStart, ZStart, ZSpace ) --R2.1 - self:onafterFormationLine(FollowGroupSet,From,Event,To,XStart,XSpace,YStart,0,ZStart,ZSpace) + self:onafterFormationLine(FollowGroupSet,From,Event,To,XStart,XSpace,YStart,0,ZStart,ZSpace,self.__Enum.Formation.RightWing) return self end @@ -836,6 +872,8 @@ function AI_FORMATION:onafterFormationCenterWing( FollowGroupSet, From , Event , local Vec3 = PointVec3:GetVec3() FollowGroup:SetState( self, "FormationVec3", Vec3 ) i = i + 1 + FollowGroup:SetState( FollowGroup, "Formation", self.__Enum.Formation.Vic ) + FollowGroup:SetState( FollowGroup, "Mode", self.__Enum.Mode.Formation ) end return self @@ -895,6 +933,8 @@ function AI_FORMATION:onafterFormationBox( FollowGroupSet, From , Event , To, XS local Vec3 = PointVec3:GetVec3() FollowGroup:SetState( self, "FormationVec3", Vec3 ) i = i + 1 + FollowGroup:SetState( FollowGroup, "Formation", self.__Enum.Formation.Box ) + FollowGroup:SetState( FollowGroup, "Mode", self.__Enum.Mode.Formation ) end return self @@ -919,7 +959,7 @@ end -- @return #AI_FORMATION function AI_FORMATION:ReleaseFormation( FollowGroup ) - FollowGroup.Following = false + FollowGroup:SetState( FollowGroup, "Mode", self.__Enum.Mode.Mission ) return self end @@ -931,7 +971,9 @@ end -- @return #AI_FORMATION function AI_FORMATION:JoinFormation( FollowGroup ) - FollowGroup.Following = true + -- If a formation type was defined for the AI_FORMATION object, then we can joinup. + + FollowGroup:SetState( FollowGroup, "Mode", self.__Enum.Mode.Formation ) return self end @@ -989,7 +1031,7 @@ function AI_FORMATION:onenterFollowing( FollowGroupSet ) --R2.1 -- @param Wrapper.Unit#UNIT ClientUnit function( FollowGroup, Formation, ClientUnit, CT1, CV1, CT2, CV2 ) - if FollowGroup.Following == true then + if FollowGroup:GetState( FollowGroup, "Mode" ) == self.__Enum.Mode.Formation then FollowGroup:OptionROTEvadeFire() FollowGroup:OptionROEReturnFire() From d3ecbac40abf802fd6d3ce65465151204889f85a Mon Sep 17 00:00:00 2001 From: FlightControl Date: Mon, 27 May 2019 17:10:19 +0200 Subject: [PATCH 15/25] Updates for mission mode. --- Moose Development/Moose/AI/AI_Escort.lua | 78 ++++++++++++------- .../Moose/AI/AI_Escort_Request.lua | 20 +++-- 2 files changed, 65 insertions(+), 33 deletions(-) diff --git a/Moose Development/Moose/AI/AI_Escort.lua b/Moose Development/Moose/AI/AI_Escort.lua index 6a7517dd9..0cf5b5800 100644 --- a/Moose Development/Moose/AI/AI_Escort.lua +++ b/Moose Development/Moose/AI/AI_Escort.lua @@ -274,7 +274,7 @@ function AI_ESCORT:onafterStart( EscortGroupSet ) --- @param Core.Group#GROUP EscortGroup function( EscortGroup ) EscortGroup.EscortMenu = MENU_GROUP:New( self.PlayerGroup, EscortGroup:GetName(), self.MainMenu ) - EscortGroup:WayPointInitialize( 1 ) + EscortGroup:WayPointInitialize() EscortGroup:OptionROTVertical() EscortGroup:OptionROEOpenFire() @@ -361,7 +361,7 @@ function AI_ESCORT:Menus( XStart, XSpace, YStart, YSpace, ZStart, ZSpace, ZLevel self:MenuROE() self:MenuROT() --- self:MenuResumeMission() + self:MenuResumeMission() return self @@ -1047,10 +1047,16 @@ end function AI_ESCORT:MenuResumeMission() self:F() - if not self.EscortMenuResumeMission then - -- Mission Resume Menu Root - self.EscortMenuResumeMission = MENU_GROUP:New( self.PlayerGroup, "Resume mission from", self.EscortMenu ) - end + self.EscortGroupSet:ForSomeGroupAlive( + --- @param Core.Group#GROUP EscortGroup + function( EscortGroup ) + if EscortGroup:IsAir() then + local EscortGroupName = EscortGroup:GetName() + local EscortMenu = MENU_GROUP:New( self.PlayerGroup, EscortGroupName, self.MainMenu ) + EscortGroup.EscortMenuResumeMission = MENU_GROUP:New( self.PlayerGroup, "Resume from", EscortMenu ) + end + end + ) return self end @@ -1324,10 +1330,12 @@ function AI_ESCORT:_ScanTargets( ScanDuration ) end ---- @param #AI_ESCORT self --- @param Wrapper.Group#GROUP EscortGroup +--- @param Wrapper.Group#GROUP EscortGroup +-- @param #AI_ESCORT self function AI_ESCORT.___Resume( EscortGroup, self ) + self:F( { self=self } ) + local PlayerGroup = self.PlayerGroup self:JoinFormation( EscortGroup ) @@ -1336,6 +1344,26 @@ function AI_ESCORT.___Resume( EscortGroup, self ) end +--- @param #AI_ESCORT self +-- @param Wrapper.Group#GROUP EscortGroup +-- @param #number WayPoint +function AI_ESCORT._ResumeMission( EscortGroup, WayPoint ) + + --self.FollowScheduler:Stop( self.FollowSchedule ) + + local WayPoints = EscortGroup:GetTaskRoute() + self:T( WayPoint, WayPoints ) + + for WayPointIgnore = 1, WayPoint do + table.remove( WayPoints, 1 ) + end + + EscortGroup:SetTask( EscortGroup:TaskRoute( WayPoints ), 1 ) + + EscortGroup:MessageTypeToClient( "Resuming mission from waypoint ", MESSAGE.Type.Information, self.PlayerGroup ) +end + + --- @param #AI_ESCORT self -- @param Wrapper.Group#GROUP EscortGroup The escort group that will attack the detected item. -- @param Functional.Detection#DETECTION_BASE.DetectedItem DetectedItem @@ -1481,26 +1509,6 @@ end -function AI_ESCORT:_ResumeMission( WayPoint ) - - local EscortGroup = self.EscortGroup - local EscortUnit = self.PlayerUnit - - self.FollowScheduler:Stop( self.FollowSchedule ) - - local WayPoints = EscortGroup:GetTaskRoute() - self:T( WayPoint, WayPoints ) - - for WayPointIgnore = 1, WayPoint do - table.remove( WayPoints, 1 ) - end - - SCHEDULER:New( EscortGroup, EscortGroup.SetTask, { EscortGroup:TaskRoute( WayPoints ) }, 1 ) - - EscortGroup:MessageToClient( "Resuming mission from waypoint " .. WayPoint .. ".", 10, EscortUnit ) -end - - --- Registers the waypoints -- @param #AI_ESCORT self -- @return #table @@ -1580,6 +1588,20 @@ function AI_ESCORT:_ReportTargetsScheduler( EscortGroup ) EscortMenuAttackTargets:RemoveSubMenus( TimeUpdate, "Esort" ) + if EscortGroup.EscortMenuResumeMission then + EscortGroup.EscortMenuResumeMission:RemoveSubMenus() + + local TaskPoints = EscortGroup:GetTaskRoute() + + for WayPointID, WayPoint in pairs( TaskPoints ) do + local EscortVec3 = EscortGroup:GetVec3() + local Distance = ( ( WayPoint.x - EscortVec3.x )^2 + + ( WayPoint.y - EscortVec3.z )^2 + ) ^ 0.5 / 1000 + MENU_GROUP_COMMAND:New( self.PlayerGroup, "Waypoint " .. WayPointID .. " at " .. string.format( "%.2f", Distance ).. "km", EscortGroup.EscortMenuResumeMission, AI_ESCORT._ResumeMission, self, EscortGroup, WayPointID ) + end + end + return true else end diff --git a/Moose Development/Moose/AI/AI_Escort_Request.lua b/Moose Development/Moose/AI/AI_Escort_Request.lua index 8d17d2657..e7d2b6d78 100644 --- a/Moose Development/Moose/AI/AI_Escort_Request.lua +++ b/Moose Development/Moose/AI/AI_Escort_Request.lua @@ -149,7 +149,7 @@ --- @type AI_ESCORT_REQUEST --- @extends AI.AI_Formation#AI_FORMATION +-- @extends AI.AI_Escort#AI_ESCORT --- AI_ESCORT_REQUEST class -- @@ -216,7 +216,8 @@ function AI_ESCORT_REQUEST:New( EscortUnit, EscortSpawn, EscortAirbase, EscortNa self.Detection = DETECTION_AREAS:New( self.EscortGroupSet, 5000 ) self.Detection:__Start( 30 ) - + + self.SpawnMode = self.__Enum.Mode.Mission return self end @@ -240,8 +241,10 @@ function AI_ESCORT_REQUEST:SpawnEscort() Report:Add( "Joining Up " .. self.EscortGroupSet:GetUnitTypeNames():Text( ", " ) .. " from " .. LeaderEscort:GetCoordinate():ToString( self.EscortUnit ) ) LeaderEscort:MessageTypeToGroup( Report:Text(), MESSAGE.Type.Information, self.PlayerUnit ) - self:FormationTrail( 50, 50, 50 ) - self:JoinFormation( EscortGroup ) + if self.SpawnMode == self.__Enum.Mode.Formation then + self:FormationTrail( 50, 50, 50 ) + self:JoinFormation( EscortGroup ) + end self:Menus( self.XStart, self.XSpace, self.YStart, self.YSpace, self.ZStart, self.ZSpace, self.ZLevels ) end ) @@ -253,7 +256,7 @@ end function AI_ESCORT_REQUEST:onafterStart( EscortGroupSet ) if not self.MenuRequestEscort then - self.MenuRequestEscort = MENU_GROUP_COMMAND:New( self.LeaderGroup, "Request A2G Escort", self.MainMenu, + self.MenuRequestEscort = MENU_GROUP_COMMAND:New( self.LeaderGroup, "Request new escort ", self.MainMenu, function() self:SpawnEscort() end @@ -262,3 +265,10 @@ function AI_ESCORT_REQUEST:onafterStart( EscortGroupSet ) end +--- Set the spawn mode to be mission execution. +-- @param #AI_ESCORT_REQUEST self +function AI_ESCORT_REQUEST:SetEscortSpawnMission() + + self.SpawnMode = self.__Enum.Mode.Mission + +end From c5236d337e77c05370bd59dbfe50a85cc5ee23ca Mon Sep 17 00:00:00 2001 From: FlightControl Date: Tue, 28 May 2019 20:44:51 +0300 Subject: [PATCH 16/25] Updates --- Moose Development/Moose/AI/AI_Escort.lua | 142 ++-- .../Moose/AI/AI_Escort_Request.lua | 25 +- Moose Development/Moose/AI/AI_Formation.lua | 5 +- Moose Development/Moose/Core/Spawn.lua | 651 +++++++++--------- Moose Development/Moose/Wrapper/Airbase.lua | 7 +- 5 files changed, 451 insertions(+), 379 deletions(-) diff --git a/Moose Development/Moose/AI/AI_Escort.lua b/Moose Development/Moose/AI/AI_Escort.lua index 0cf5b5800..b8e169a5e 100644 --- a/Moose Development/Moose/AI/AI_Escort.lua +++ b/Moose Development/Moose/AI/AI_Escort.lua @@ -225,6 +225,7 @@ function AI_ESCORT:New( EscortUnit, EscortGroupSet, EscortName, EscortBriefing ) self.EscortBriefing = EscortBriefing + self.Menu = {} -- if not EscortBriefing then -- EscortGroup:MessageToClient( EscortGroup:GetCategoryName() .. " '" .. EscortName .. "' (" .. EscortGroup:GetCallsign() .. ") reporting! " .. @@ -545,26 +546,36 @@ function AI_ESCORT:MenuFormationBox( XStart, XSpace, YStart, YSpace, ZStart, ZSp end +--- Sets a menu slot to join formation for an escort. +-- @param #AI_ESCORT self +-- @return #AI_ESCORT +function AI_ESCORT:EscortMenuJoinUp( EscortGroup ) + + if self.Menu.JoinUp == true then + if EscortGroup:IsAir() then + local EscortGroupName = EscortGroup:GetName() + local EscortMenu = MENU_GROUP:New( self.PlayerGroup, EscortGroupName, self.MainMenu ) + local EscortMenuReportNavigation = MENU_GROUP:New( self.PlayerGroup, "Navigation", EscortMenu ) + local EscortMenuJoinUp = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Join Up", EscortMenuReportNavigation, AI_ESCORT._JoinUp, self, EscortGroup ) + end + end +end + + --- Defines --- Defines a menu slot to let the escort to join formation. --- This menu will appear under **Formation**. -- @param #AI_ESCORT self -- @return #AI_ESCORT function AI_ESCORT:MenuJoinUp() + self.Menu.JoinUp = true + local FlightMenuReportNavigation = MENU_GROUP:New( self.PlayerGroup, "Navigation", self.FlightMenu ) local FlightMenuJoinUp = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Join Up", FlightMenuReportNavigation, AI_ESCORT._FlightJoinUp, self ) self.EscortGroupSet:ForSomeGroupAlive( --- @param Core.Group#GROUP EscortGroup function( EscortGroup ) - if EscortGroup:IsAir() then - - local EscortGroupName = EscortGroup:GetName() - local EscortMenu = MENU_GROUP:New( self.PlayerGroup, EscortGroupName, self.MainMenu ) - local EscortMenuReportNavigation = MENU_GROUP:New( self.PlayerGroup, "Navigation", EscortMenu ) - local EscortMenuJoinUp = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Join Up", EscortMenuReportNavigation, AI_ESCORT._JoinUp, self ) - - end + self:EscortSetMenuJoinUp( EscortGroup ) end ) @@ -572,6 +583,32 @@ function AI_ESCORT:MenuJoinUp() end +function AI_ESCORT:EscortMenuHoldAtEscortPosition( EscortGroup ) + + for _, HoldAtEscortPosition in pairs( self.Menu.HoldAtEscortPosition ) do + if EscortGroup:IsAir() then + local EscortGroupName = EscortGroup:GetName() + local EscortMenu = MENU_GROUP:New( self.PlayerGroup, EscortGroupName, self.MainMenu ) + local EscortMenuReportNavigation = MENU_GROUP:New( self.PlayerGroup, "Navigation", EscortMenu ) + local EscortMenuHoldPosition = MENU_GROUP_COMMAND + :New( + self.PlayerGroup, + HoldAtEscortPosition.MenuText, + EscortMenuReportNavigation, + AI_ESCORT._HoldPosition, + self, + EscortGroup, + EscortGroup, + HoldAtEscortPosition.Height, + HoldAtEscortPosition.Speed + ) + end + end + + return self +end + + --- Defines a menu slot to let the escort hold at their current position and stay low with a specified height during a specified time in seconds. -- This menu will appear under **Hold position**. -- @param #AI_ESCORT self @@ -619,28 +656,16 @@ function AI_ESCORT:MenuHoldAtEscortPosition( Height, Speed, MenuTextFormat ) Speed ) + self.Menu.HoldAtEscortPosition = self.Menu.HoldAtEscortPosition or {} + self.Menu.HoldAtEscortPosition[#self.Menu.HoldAtEscortPosition+1] = {} + self.Menu.HoldAtEscortPosition[#self.Menu.HoldAtEscortPosition].Height = Height + self.Menu.HoldAtEscortPosition[#self.Menu.HoldAtEscortPosition].Speed = Speed + self.Menu.HoldAtEscortPosition[#self.Menu.HoldAtEscortPosition].MenuText = MenuText + self.EscortGroupSet:ForSomeGroupAlive( --- @param Core.Group#GROUP EscortGroup function( EscortGroup ) - if EscortGroup:IsAir() then - - local EscortGroupName = EscortGroup:GetName() - local EscortMenu = MENU_GROUP:New( self.PlayerGroup, EscortGroupName, self.MainMenu ) - local EscortMenuReportNavigation = MENU_GROUP:New( self.PlayerGroup, "Navigation", EscortMenu ) - - local EscortMenuHoldPosition = MENU_GROUP_COMMAND - :New( - self.PlayerGroup, - MenuText, - EscortMenuReportNavigation, - AI_ESCORT._HoldPosition, - self, - EscortGroup, - EscortGroup, - Height, - Speed - ) - end + self:EscortMenuHoldAtEscortPosition( EscortGroup ) end ) @@ -648,6 +673,33 @@ function AI_ESCORT:MenuHoldAtEscortPosition( Height, Speed, MenuTextFormat ) end +function AI_ESCORT:EscortMenuHoldAtLeaderPosition( EscortGroup ) + + for _, HoldAtLeaderPosition in pairs( self.Menu.HoldAtLeaderPosition ) do + if EscortGroup:IsAir() then + + local EscortGroupName = EscortGroup:GetName() + local EscortMenu = MENU_GROUP:New( self.PlayerGroup, EscortGroupName, self.MainMenu ) + local EscortMenuReportNavigation = MENU_GROUP:New( self.PlayerGroup, "Navigation", EscortMenu ) + + local EscortMenuHoldAtLeaderPosition = MENU_GROUP_COMMAND + :New( + self.PlayerGroup, + HoldAtLeaderPosition.MenuText, + EscortMenuReportNavigation, + AI_ESCORT._HoldPosition, + self, + self.PlayerGroup, + EscortGroup, + HoldAtLeaderPosition.Height, + HoldAtLeaderPosition.Speed + ) + end + end + + return self +end + --- Defines a menu slot to let the escort hold at the client position and stay low with a specified height during a specified time in seconds. -- This menu will appear under **Navigation**. -- @param #AI_ESCORT self @@ -695,28 +747,16 @@ function AI_ESCORT:MenuHoldAtLeaderPosition( Height, Speed, MenuTextFormat ) Speed ) + self.Menu.HoldAtLeaderPosition = self.Menu.HoldAtLeaderPosition or {} + self.Menu.HoldAtLeaderPosition[#self.Menu.HoldAtLeaderPosition+1] = {} + self.Menu.HoldAtLeaderPosition[#self.Menu.HoldAtLeaderPosition].Height = Height + self.Menu.HoldAtLeaderPosition[#self.Menu.HoldAtLeaderPosition].Speed = Speed + self.Menu.HoldAtLeaderPosition[#self.Menu.HoldAtLeaderPosition].MenuText = MenuText + self.EscortGroupSet:ForSomeGroupAlive( --- @param Core.Group#GROUP EscortGroup function( EscortGroup ) - if EscortGroup:IsAir() then - - local EscortGroupName = EscortGroup:GetName() - local EscortMenu = MENU_GROUP:New( self.PlayerGroup, EscortGroupName, self.MainMenu ) - local EscortMenuReportNavigation = MENU_GROUP:New( self.PlayerGroup, "Navigation", EscortMenu ) - - local EscortMenuHoldAtLeaderPosition = MENU_GROUP_COMMAND - :New( - self.PlayerGroup, - MenuText, - EscortMenuReportNavigation, - AI_ESCORT._HoldPosition, - self, - self.PlayerGroup, - EscortGroup, - Height, - Speed - ) - end + self:EscortMenuHoldAtLeaderPosition( EscortGroup ) end ) @@ -1140,7 +1180,7 @@ function AI_ESCORT:_JoinUp( EscortGroup ) end -function AI_ESCORT:_FlightJoinUp( EscortGroup ) +function AI_ESCORT:_FlightJoinUp() self.EscortGroupSet:ForSomeGroupAlive( --- @param Core.Group#GROUP EscortGroup @@ -1339,7 +1379,7 @@ function AI_ESCORT.___Resume( EscortGroup, self ) local PlayerGroup = self.PlayerGroup self:JoinFormation( EscortGroup ) - EscortGroup:MessageTypeToClient( "Destroyed all targets. Rejoining.", MESSAGE.Type.Information, PlayerGroup ) + EscortGroup:MessageTypeToGroup( "Destroyed all targets. Rejoining.", MESSAGE.Type.Information, PlayerGroup ) end @@ -1347,7 +1387,7 @@ end --- @param #AI_ESCORT self -- @param Wrapper.Group#GROUP EscortGroup -- @param #number WayPoint -function AI_ESCORT._ResumeMission( EscortGroup, WayPoint ) +function AI_ESCORT:_ResumeMission( EscortGroup, WayPoint ) --self.FollowScheduler:Stop( self.FollowSchedule ) @@ -1360,7 +1400,7 @@ function AI_ESCORT._ResumeMission( EscortGroup, WayPoint ) EscortGroup:SetTask( EscortGroup:TaskRoute( WayPoints ), 1 ) - EscortGroup:MessageTypeToClient( "Resuming mission from waypoint ", MESSAGE.Type.Information, self.PlayerGroup ) + EscortGroup:MessageTypeToGroup( "Resuming mission from waypoint ", MESSAGE.Type.Information, self.PlayerGroup ) end diff --git a/Moose Development/Moose/AI/AI_Escort_Request.lua b/Moose Development/Moose/AI/AI_Escort_Request.lua index e7d2b6d78..4b95b4b90 100644 --- a/Moose Development/Moose/AI/AI_Escort_Request.lua +++ b/Moose Development/Moose/AI/AI_Escort_Request.lua @@ -193,7 +193,7 @@ AI_ESCORT_REQUEST = { -- @param Wrapper.Airbase#AIRBASE EscortAirbase The airbase where escorts will be spawned once requested. -- @param #string EscortName Name of the escort. -- @param #string EscortBriefing A text showing the AI_ESCORT_REQUEST briefing to the player. Note that if no EscortBriefing is provided, the default briefing will be shown. --- @return #AI_ESCORT_REQUEST self +-- @return #AI_ESCORT_REQUEST -- @usage -- EscortSpawn = SPAWN:NewWithAlias( "Red A2G Escort Template", "Red A2G Escort AI" ):InitLimit( 10, 10 ) -- EscortSpawn:ParkAtAirbase( AIRBASE:FindByName( AIRBASE.Caucasus.Sochi_Adler ), AIRBASE.TerminalType.OpenBig ) @@ -223,10 +223,9 @@ function AI_ESCORT_REQUEST:New( EscortUnit, EscortSpawn, EscortAirbase, EscortNa end --- @param #AI_ESCORT_REQUEST self --- @param Core.Set#SET_GROUP EscortGroupSet function AI_ESCORT_REQUEST:SpawnEscort() - local EscortGroup = self.EscortSpawn:SpawnAtAirbase( self.EscortAirbase, SPAWN.Takeoff.Cold ) + local EscortGroup = self.EscortSpawn:SpawnAtAirbase( self.EscortAirbase, SPAWN.Takeoff.Hot ) self.EscortGroupSet:AddGroup( EscortGroup ) EscortGroup:OptionROTVertical() @@ -241,11 +240,27 @@ function AI_ESCORT_REQUEST:SpawnEscort() Report:Add( "Joining Up " .. self.EscortGroupSet:GetUnitTypeNames():Text( ", " ) .. " from " .. LeaderEscort:GetCoordinate():ToString( self.EscortUnit ) ) LeaderEscort:MessageTypeToGroup( Report:Text(), MESSAGE.Type.Information, self.PlayerUnit ) + self:FormationTrail( 50, 50, 50 ) if self.SpawnMode == self.__Enum.Mode.Formation then - self:FormationTrail( 50, 50, 50 ) self:JoinFormation( EscortGroup ) end - self:Menus( self.XStart, self.XSpace, self.YStart, self.YSpace, self.ZStart, self.ZSpace, self.ZLevels ) + + --self:Menus( self.XStart, self.XSpace, self.YStart, self.YSpace, self.ZStart, self.ZSpace, self.ZLevels ) + + self:EscortMenuJoinUp( EscortGroup ) + + self:EscortMenuHoldAtEscortPosition( EscortGroup ) + self:EscortMenuHoldAtLeaderPosition( EscortGroup ) + + self:MenuFlare() + self:MenuSmoke() + + self:MenuReportTargets( 60 ) + self:MenuAssistedAttack() + self:MenuROE() + self:MenuROT() + + self:MenuResumeMission() end ) diff --git a/Moose Development/Moose/AI/AI_Formation.lua b/Moose Development/Moose/AI/AI_Formation.lua index 5eb5d0e90..f4ad1902f 100644 --- a/Moose Development/Moose/AI/AI_Formation.lua +++ b/Moose Development/Moose/AI/AI_Formation.lua @@ -717,7 +717,6 @@ function AI_FORMATION:onafterFormationLine( FollowGroupSet, From , Event , To, X i = i + 1 FollowGroup:SetState( FollowGroup, "Formation", Formation ) - FollowGroup:SetState( FollowGroup, "Mode", self.__Enum.Mode.Formation ) end return self @@ -873,7 +872,6 @@ function AI_FORMATION:onafterFormationCenterWing( FollowGroupSet, From , Event , FollowGroup:SetState( self, "FormationVec3", Vec3 ) i = i + 1 FollowGroup:SetState( FollowGroup, "Formation", self.__Enum.Formation.Vic ) - FollowGroup:SetState( FollowGroup, "Mode", self.__Enum.Mode.Formation ) end return self @@ -934,7 +932,6 @@ function AI_FORMATION:onafterFormationBox( FollowGroupSet, From , Event , To, XS FollowGroup:SetState( self, "FormationVec3", Vec3 ) i = i + 1 FollowGroup:SetState( FollowGroup, "Formation", self.__Enum.Formation.Box ) - FollowGroup:SetState( FollowGroup, "Mode", self.__Enum.Mode.Formation ) end return self @@ -1026,7 +1023,7 @@ function AI_FORMATION:onenterFollowing( FollowGroupSet ) --R2.1 ClientUnit:SetState( self, "CV1", CV2 ) end - FollowGroupSet:ForEachGroup( + FollowGroupSet:ForEachGroupAlive( --- @param Wrapper.Group#GROUP FollowGroup -- @param Wrapper.Unit#UNIT ClientUnit function( FollowGroup, Formation, ClientUnit, CT1, CV1, CT2, CV2 ) diff --git a/Moose Development/Moose/Core/Spawn.lua b/Moose Development/Moose/Core/Spawn.lua index d042f49e6..3495907ad 100644 --- a/Moose Development/Moose/Core/Spawn.lua +++ b/Moose Development/Moose/Core/Spawn.lua @@ -1835,6 +1835,336 @@ function SPAWN:SpawnAtAirbase( SpawnAirbase, Takeoff, TakeoffAltitude, TerminalT end +--- Will park a group at an @{Wrapper.Airbase}. +-- +-- @param #SPAWN self +-- @param Wrapper.Airbase#AIRBASE SpawnAirbase The @{Wrapper.Airbase} where to spawn the group. +-- @param Wrapper.Airbase#AIRBASE.TerminalType TerminalType (optional) The terminal type the aircraft should be spawned at. See @{Wrapper.Airbase#AIRBASE.TerminalType}. +-- @param #table Parkingdata (optional) Table holding the coordinates and terminal ids for all units of the group. Spawning will be forced to happen at exactily these spots! +-- @return #nil Nothing is returned! +function SPAWN:ParkAircraft( SpawnAirbase, TerminalType, Parkingdata, SpawnIndex ) + + self:F( { SpawnIndex = SpawnIndex, SpawnMaxGroups = self.SpawnMaxGroups } ) + + -- Get position of airbase. + local PointVec3 = SpawnAirbase:GetCoordinate() + self:T2(PointVec3) + + -- Set take off type. Default is hot. + local Takeoff = SPAWN.Takeoff.Cold + + -- Get group template. + local SpawnTemplate = self.SpawnGroups[SpawnIndex].SpawnTemplate + + if SpawnTemplate then + + -- Check if the aircraft with the specified SpawnIndex is already spawned. + -- If yes, ensure that the aircraft is spawned at the same aircraft spot. + + local GroupAlive = self:GetGroupFromIndex( SpawnIndex ) + + -- Debug output + self:T( { "Current point of ", self.SpawnTemplatePrefix, SpawnAirbase } ) + + -- Template group, unit and its attributes. + local TemplateGroup = GROUP:FindByName(self.SpawnTemplatePrefix) + local TemplateUnit=TemplateGroup:GetUnit(1) + local ishelo=TemplateUnit:HasAttribute("Helicopters") + local isbomber=TemplateUnit:HasAttribute("Bombers") + local istransport=TemplateUnit:HasAttribute("Transports") + local isfighter=TemplateUnit:HasAttribute("Battleplanes") + + -- Number of units in the group. With grouping this can actually differ from the template group size! + local nunits=#SpawnTemplate.units + + -- First waypoint of the group. + local SpawnPoint = SpawnTemplate.route.points[1] + + -- These are only for ships and FARPS. + SpawnPoint.linkUnit = nil + SpawnPoint.helipadId = nil + SpawnPoint.airdromeId = nil + + -- Get airbase ID and category. + local AirbaseID = SpawnAirbase:GetID() + local AirbaseCategory = SpawnAirbase:GetDesc().category + self:F( { AirbaseCategory = AirbaseCategory } ) + + -- Set airdromeId. + if AirbaseCategory == Airbase.Category.SHIP then + SpawnPoint.linkUnit = AirbaseID + SpawnPoint.helipadId = AirbaseID + elseif AirbaseCategory == Airbase.Category.HELIPAD then + SpawnPoint.linkUnit = AirbaseID + SpawnPoint.helipadId = AirbaseID + elseif AirbaseCategory == Airbase.Category.AIRDROME then + SpawnPoint.airdromeId = AirbaseID + end + + -- Set waypoint type/action. + SpawnPoint.alt = 0 + SpawnPoint.type = GROUPTEMPLATE.Takeoff[Takeoff][1] -- type + SpawnPoint.action = GROUPTEMPLATE.Takeoff[Takeoff][2] -- action + + -- Check if we spawn on ground. + local spawnonground=not (Takeoff==SPAWN.Takeoff.Air) + self:T({spawnonground=spawnonground, TOtype=Takeoff, TOair=Takeoff==SPAWN.Takeoff.Air}) + + -- Check where we actually spawn if we spawn on ground. + local spawnonship=false + local spawnonfarp=false + local spawnonrunway=false + local spawnonairport=false + if spawnonground then + if AirbaseCategory == Airbase.Category.SHIP then + spawnonship=true + elseif AirbaseCategory == Airbase.Category.HELIPAD then + spawnonfarp=true + elseif AirbaseCategory == Airbase.Category.AIRDROME then + spawnonairport=true + end + spawnonrunway=Takeoff==SPAWN.Takeoff.Runway + end + + -- Array with parking spots coordinates. + local parkingspots={} + local parkingindex={} + local spots + + -- Spawn happens on ground, i.e. at an airbase, a FARP or a ship. + if spawnonground and not SpawnTemplate.parked then + + + -- Number of free parking spots. + local nfree=0 + + -- Set terminal type. + local termtype=TerminalType + + -- Scan options. Might make that input somehow. + local scanradius=50 + local scanunits=true + local scanstatics=true + local scanscenery=false + local verysafe=false + + -- Number of free parking spots at the airbase. + if spawnonship or spawnonfarp or spawnonrunway then + -- These places work procedural and have some kind of build in queue ==> Less effort. + self:T(string.format("Group %s is spawned on farp/ship/runway %s.", self.SpawnTemplatePrefix, SpawnAirbase:GetName())) + nfree=SpawnAirbase:GetFreeParkingSpotsNumber(termtype, true) + spots=SpawnAirbase:GetFreeParkingSpotsTable(termtype, true) + elseif Parkingdata~=nil then + -- Parking data explicitly set by user as input parameter. + nfree=#Parkingdata + spots=Parkingdata + else + if ishelo then + if termtype==nil then + -- Helo is spawned. Try exclusive helo spots first. + self:T(string.format("Helo group %s is at %s using terminal type %d.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), AIRBASE.TerminalType.HelicopterOnly)) + spots=SpawnAirbase:FindFreeParkingSpotForAircraft(TemplateGroup, AIRBASE.TerminalType.HelicopterOnly, scanradius, scanunits, scanstatics, scanscenery, verysafe, nunits) + nfree=#spots + if nfree=1 then + + -- All units get the same spot. DCS takes care of the rest. + for i=1,nunits do + table.insert(parkingspots, spots[1].Coordinate) + table.insert(parkingindex, spots[1].TerminalID) + end + -- This is actually used... + PointVec3=spots[1].Coordinate + + else + -- If there is absolutely no spot ==> air start! + _notenough=true + end + + elseif spawnonairport then + + if nfree>=nunits then + + for i=1,nunits do + table.insert(parkingspots, spots[i].Coordinate) + table.insert(parkingindex, spots[i].TerminalID) + end + + else + -- Not enough spots for the whole group ==> air start! + _notenough=true + end + end + + -- Not enough spots ==> Prepare airstart. + if _notenough then + + if not self.SpawnUnControlled then + else + self:E(string.format("WARNING: Group %s has no parking spots at %s ==> No emergency air start or uncontrolled spawning ==> No spawn!", self.SpawnTemplatePrefix, SpawnAirbase:GetName())) + return nil + end + end + + else + + end + + if not SpawnTemplate.parked then + -- Translate the position of the Group Template to the Vec3. + + SpawnTemplate.parked = true + + for UnitID = 1, nunits do + self:F('Before Translation SpawnTemplate.units['..UnitID..'].x = '..SpawnTemplate.units[UnitID].x..', SpawnTemplate.units['..UnitID..'].y = '..SpawnTemplate.units[UnitID].y) + + -- Template of the current unit. + local UnitTemplate = SpawnTemplate.units[UnitID] + + -- Tranlate position and preserve the relative position/formation of all aircraft. + local SX = UnitTemplate.x + local SY = UnitTemplate.y + local BX = SpawnTemplate.route.points[1].x + local BY = SpawnTemplate.route.points[1].y + local TX = PointVec3.x + (SX-BX) + local TY = PointVec3.z + (SY-BY) + + if spawnonground then + + -- Ships and FARPS seem to have a build in queue. + if spawnonship or spawnonfarp or spawnonrunway then + + self:T(string.format("Group %s spawning at farp, ship or runway %s.", self.SpawnTemplatePrefix, SpawnAirbase:GetName())) + + -- Spawn on ship. We take only the position of the ship. + SpawnTemplate.units[UnitID].x = PointVec3.x --TX + SpawnTemplate.units[UnitID].y = PointVec3.z --TY + SpawnTemplate.units[UnitID].alt = PointVec3.y + + else + + self:T(string.format("Group %s spawning at airbase %s on parking spot id %d", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), parkingindex[UnitID])) + + -- Get coordinates of parking spot. + SpawnTemplate.units[UnitID].x = parkingspots[UnitID].x + SpawnTemplate.units[UnitID].y = parkingspots[UnitID].z + SpawnTemplate.units[UnitID].alt = parkingspots[UnitID].y + + --parkingspots[UnitID]:MarkToAll(string.format("Group %s spawning at airbase %s on parking spot id %d", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), parkingindex[UnitID])) + end + + else + + self:T(string.format("Group %s spawning in air at %s.", self.SpawnTemplatePrefix, SpawnAirbase:GetName())) + + -- Spawn in air as requested initially. Original template orientation is perserved, altitude is already correctly set. + SpawnTemplate.units[UnitID].x = TX + SpawnTemplate.units[UnitID].y = TY + SpawnTemplate.units[UnitID].alt = PointVec3.y + + end + + -- Parking spot id. + UnitTemplate.parking = nil + UnitTemplate.parking_id = nil + if parkingindex[UnitID] then + UnitTemplate.parking = parkingindex[UnitID] + end + + -- Debug output. + self:T2(string.format("Group %s unit number %d: Parking = %s",self.SpawnTemplatePrefix, UnitID, tostring(UnitTemplate.parking))) + self:T2(string.format("Group %s unit number %d: Parking ID = %s",self.SpawnTemplatePrefix, UnitID, tostring(UnitTemplate.parking_id))) + self:T2('After Translation SpawnTemplate.units['..UnitID..'].x = '..SpawnTemplate.units[UnitID].x..', SpawnTemplate.units['..UnitID..'].y = '..SpawnTemplate.units[UnitID].y) + end + end + + -- Set gereral spawnpoint position. + SpawnPoint.x = PointVec3.x + SpawnPoint.y = PointVec3.z + SpawnPoint.alt = PointVec3.y + + SpawnTemplate.x = PointVec3.x + SpawnTemplate.y = PointVec3.z + + SpawnTemplate.uncontrolled = true + + -- Spawn group. + local GroupSpawned = self:SpawnWithIndex( SpawnIndex, true ) + + -- When spawned in the air, we need to generate a Takeoff Event. + if Takeoff == GROUP.Takeoff.Air then + for UnitID, UnitSpawned in pairs( GroupSpawned:GetUnits() ) do + SCHEDULER:New( nil, BASE.CreateEventTakeoff, { GroupSpawned, timer.getTime(), UnitSpawned:GetDCSObject() } , 5 ) + end + end + + -- Check if we accidentally spawned on the runway. Needs to be schedules, because group is not immidiately alive. + if Takeoff~=SPAWN.Takeoff.Runway and Takeoff~=SPAWN.Takeoff.Air and spawnonairport then + SCHEDULER:New(nil, AIRBASE.CheckOnRunWay, {SpawnAirbase, GroupSpawned, 75, true} , 1.0) + end + + end + +end + --- Will park a group at an @{Wrapper.Airbase}. -- This method is mostly advisable to be used if you want to simulate parking units at an airbase and be visible. -- Note that each point in the route assigned to the spawning group is reset to the point of the spawn. @@ -1876,325 +2206,10 @@ end function SPAWN:ParkAtAirbase( SpawnAirbase, TerminalType, Parkingdata ) -- R2.2, R2.4, R2.5 self:F( { self.SpawnTemplatePrefix, SpawnAirbase, TerminalType } ) - -- Get position of airbase. - local PointVec3 = SpawnAirbase:GetCoordinate() + self:ParkAircraft( SpawnAirbase, TerminalType, Parkingdata, 1 ) - -- Set take off type. Default is hot. - local Takeoff = SPAWN.Takeoff.Cold - - for SpawnIndex = 1, self.SpawnMaxGroups do - - self:F( { SpawnIndex = SpawnIndex, SpawnMaxGroups = self.SpawnMaxGroups } ) - - -- Get group template. - local SpawnTemplate = self.SpawnGroups[SpawnIndex].SpawnTemplate - - if SpawnTemplate then - - -- Check if the aircraft with the specified SpawnIndex is already spawned. - -- If yes, ensure that the aircraft is spawned at the same aircraft spot. - - local GroupAlive = self:GetGroupFromIndex( SpawnIndex ) - - -- Debug output - self:T( { "Current point of ", self.SpawnTemplatePrefix, SpawnAirbase } ) - - -- Template group, unit and its attributes. - local TemplateGroup = GROUP:FindByName(self.SpawnTemplatePrefix) - local TemplateUnit=TemplateGroup:GetUnit(1) - local ishelo=TemplateUnit:HasAttribute("Helicopters") - local isbomber=TemplateUnit:HasAttribute("Bombers") - local istransport=TemplateUnit:HasAttribute("Transports") - local isfighter=TemplateUnit:HasAttribute("Battleplanes") - - -- Number of units in the group. With grouping this can actually differ from the template group size! - local nunits=#SpawnTemplate.units - - -- First waypoint of the group. - local SpawnPoint = SpawnTemplate.route.points[1] - - -- These are only for ships and FARPS. - SpawnPoint.linkUnit = nil - SpawnPoint.helipadId = nil - SpawnPoint.airdromeId = nil - - -- Get airbase ID and category. - local AirbaseID = SpawnAirbase:GetID() - local AirbaseCategory = SpawnAirbase:GetDesc().category - self:F( { AirbaseCategory = AirbaseCategory } ) - - -- Set airdromeId. - if AirbaseCategory == Airbase.Category.SHIP then - SpawnPoint.linkUnit = AirbaseID - SpawnPoint.helipadId = AirbaseID - elseif AirbaseCategory == Airbase.Category.HELIPAD then - SpawnPoint.linkUnit = AirbaseID - SpawnPoint.helipadId = AirbaseID - elseif AirbaseCategory == Airbase.Category.AIRDROME then - SpawnPoint.airdromeId = AirbaseID - end - - -- Set waypoint type/action. - SpawnPoint.alt = 0 - SpawnPoint.type = GROUPTEMPLATE.Takeoff[Takeoff][1] -- type - SpawnPoint.action = GROUPTEMPLATE.Takeoff[Takeoff][2] -- action - - -- Check if we spawn on ground. - local spawnonground=not (Takeoff==SPAWN.Takeoff.Air) - self:T({spawnonground=spawnonground, TOtype=Takeoff, TOair=Takeoff==SPAWN.Takeoff.Air}) - - -- Check where we actually spawn if we spawn on ground. - local spawnonship=false - local spawnonfarp=false - local spawnonrunway=false - local spawnonairport=false - if spawnonground then - if AirbaseCategory == Airbase.Category.SHIP then - spawnonship=true - elseif AirbaseCategory == Airbase.Category.HELIPAD then - spawnonfarp=true - elseif AirbaseCategory == Airbase.Category.AIRDROME then - spawnonairport=true - end - spawnonrunway=Takeoff==SPAWN.Takeoff.Runway - end - - -- Array with parking spots coordinates. - local parkingspots={} - local parkingindex={} - local spots - - -- Spawn happens on ground, i.e. at an airbase, a FARP or a ship. - if spawnonground and not SpawnTemplate.parked then - - - -- Number of free parking spots. - local nfree=0 - - -- Set terminal type. - local termtype=TerminalType - - -- Scan options. Might make that input somehow. - local scanradius=50 - local scanunits=true - local scanstatics=true - local scanscenery=false - local verysafe=false - - -- Number of free parking spots at the airbase. - if spawnonship or spawnonfarp or spawnonrunway then - -- These places work procedural and have some kind of build in queue ==> Less effort. - self:T(string.format("Group %s is spawned on farp/ship/runway %s.", self.SpawnTemplatePrefix, SpawnAirbase:GetName())) - nfree=SpawnAirbase:GetFreeParkingSpotsNumber(termtype, true) - spots=SpawnAirbase:GetFreeParkingSpotsTable(termtype, true) - elseif Parkingdata~=nil then - -- Parking data explicitly set by user as input parameter. - nfree=#Parkingdata - spots=Parkingdata - else - if ishelo then - if termtype==nil then - -- Helo is spawned. Try exclusive helo spots first. - self:T(string.format("Helo group %s is at %s using terminal type %d.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), AIRBASE.TerminalType.HelicopterOnly)) - spots=SpawnAirbase:FindFreeParkingSpotForAircraft(TemplateGroup, AIRBASE.TerminalType.HelicopterOnly, scanradius, scanunits, scanstatics, scanscenery, verysafe, nunits) - nfree=#spots - if nfree=1 then - - -- All units get the same spot. DCS takes care of the rest. - for i=1,nunits do - table.insert(parkingspots, spots[1].Coordinate) - table.insert(parkingindex, spots[1].TerminalID) - end - -- This is actually used... - PointVec3=spots[1].Coordinate - - else - -- If there is absolutely no spot ==> air start! - _notenough=true - end - - elseif spawnonairport then - - if nfree>=nunits then - - for i=1,nunits do - table.insert(parkingspots, spots[i].Coordinate) - table.insert(parkingindex, spots[i].TerminalID) - end - - else - -- Not enough spots for the whole group ==> air start! - _notenough=true - end - end - - -- Not enough spots ==> Prepare airstart. - if _notenough then - - if not self.SpawnUnControlled then - else - self:E(string.format("WARNING: Group %s has no parking spots at %s ==> No emergency air start or uncontrolled spawning ==> No spawn!", self.SpawnTemplatePrefix, SpawnAirbase:GetName())) - return nil - end - end - - else - - end - - if not SpawnTemplate.parked then - -- Translate the position of the Group Template to the Vec3. - - SpawnTemplate.parked = true - - for UnitID = 1, nunits do - self:F('Before Translation SpawnTemplate.units['..UnitID..'].x = '..SpawnTemplate.units[UnitID].x..', SpawnTemplate.units['..UnitID..'].y = '..SpawnTemplate.units[UnitID].y) - - -- Template of the current unit. - local UnitTemplate = SpawnTemplate.units[UnitID] - - -- Tranlate position and preserve the relative position/formation of all aircraft. - local SX = UnitTemplate.x - local SY = UnitTemplate.y - local BX = SpawnTemplate.route.points[1].x - local BY = SpawnTemplate.route.points[1].y - local TX = PointVec3.x + (SX-BX) - local TY = PointVec3.z + (SY-BY) - - if spawnonground then - - -- Ships and FARPS seem to have a build in queue. - if spawnonship or spawnonfarp or spawnonrunway then - - self:T(string.format("Group %s spawning at farp, ship or runway %s.", self.SpawnTemplatePrefix, SpawnAirbase:GetName())) - - -- Spawn on ship. We take only the position of the ship. - SpawnTemplate.units[UnitID].x = PointVec3.x --TX - SpawnTemplate.units[UnitID].y = PointVec3.z --TY - SpawnTemplate.units[UnitID].alt = PointVec3.y - - else - - self:T(string.format("Group %s spawning at airbase %s on parking spot id %d", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), parkingindex[UnitID])) - - -- Get coordinates of parking spot. - SpawnTemplate.units[UnitID].x = parkingspots[UnitID].x - SpawnTemplate.units[UnitID].y = parkingspots[UnitID].z - SpawnTemplate.units[UnitID].alt = parkingspots[UnitID].y - - --parkingspots[UnitID]:MarkToAll(string.format("Group %s spawning at airbase %s on parking spot id %d", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), parkingindex[UnitID])) - end - - else - - self:T(string.format("Group %s spawning in air at %s.", self.SpawnTemplatePrefix, SpawnAirbase:GetName())) - - -- Spawn in air as requested initially. Original template orientation is perserved, altitude is already correctly set. - SpawnTemplate.units[UnitID].x = TX - SpawnTemplate.units[UnitID].y = TY - SpawnTemplate.units[UnitID].alt = PointVec3.y - - end - - -- Parking spot id. - UnitTemplate.parking = nil - UnitTemplate.parking_id = nil - if parkingindex[UnitID] then - UnitTemplate.parking = parkingindex[UnitID] - end - - -- Debug output. - self:T2(string.format("Group %s unit number %d: Parking = %s",self.SpawnTemplatePrefix, UnitID, tostring(UnitTemplate.parking))) - self:T2(string.format("Group %s unit number %d: Parking ID = %s",self.SpawnTemplatePrefix, UnitID, tostring(UnitTemplate.parking_id))) - self:T2('After Translation SpawnTemplate.units['..UnitID..'].x = '..SpawnTemplate.units[UnitID].x..', SpawnTemplate.units['..UnitID..'].y = '..SpawnTemplate.units[UnitID].y) - end - end - - -- Set gereral spawnpoint position. - SpawnPoint.x = PointVec3.x - SpawnPoint.y = PointVec3.z - SpawnPoint.alt = PointVec3.y - - SpawnTemplate.x = PointVec3.x - SpawnTemplate.y = PointVec3.z - - SpawnTemplate.uncontrolled = true - - -- Spawn group. - local GroupSpawned = self:SpawnWithIndex( SpawnIndex, true ) - - -- When spawned in the air, we need to generate a Takeoff Event. - if Takeoff == GROUP.Takeoff.Air then - for UnitID, UnitSpawned in pairs( GroupSpawned:GetUnits() ) do - SCHEDULER:New( nil, BASE.CreateEventTakeoff, { GroupSpawned, timer.getTime(), UnitSpawned:GetDCSObject() } , 5 ) - end - end - - -- Check if we accidentally spawned on the runway. Needs to be schedules, because group is not immidiately alive. - if Takeoff~=SPAWN.Takeoff.Runway and Takeoff~=SPAWN.Takeoff.Air and spawnonairport then - SCHEDULER:New(nil, AIRBASE.CheckOnRunWay, {SpawnAirbase, GroupSpawned, 75, true} , 1.0) - end - - end + for SpawnIndex = 2, self.SpawnMaxGroups do + self:ScheduleOnce( SpawnIndex * 0.1, SPAWN.ParkAircraft, self, SpawnAirbase, TerminalType, Parkingdata, SpawnIndex ) end self:SetSpawnIndex() diff --git a/Moose Development/Moose/Wrapper/Airbase.lua b/Moose Development/Moose/Wrapper/Airbase.lua index 953ba2457..1960b67a0 100644 --- a/Moose Development/Moose/Wrapper/Airbase.lua +++ b/Moose Development/Moose/Wrapper/Airbase.lua @@ -549,12 +549,15 @@ function AIRBASE:GetParkingSpotsTable(termtype) local spots={} for _,_spot in pairs(parkingdata) do if AIRBASE._CheckTerminalType(_spot.Term_Type, termtype) then + self:I({_spot=_spot}) local _free=_isfree(_spot) local _coord=COORDINATE:NewFromVec3(_spot.vTerminalPos) table.insert(spots, {Coordinate=_coord, TerminalID=_spot.Term_Index, TerminalType=_spot.Term_Type, TOAC=_spot.TO_AC, Free=_free, TerminalID0=_spot.Term_Index_0, DistToRwy=_spot.fDistToRW}) end end + self:I({ spots = spots } ) + return spots end @@ -704,6 +707,8 @@ function AIRBASE:FindFreeParkingSpotForAircraft(group, terminaltype, scanradius, local _spot=parkingspot.Coordinate -- Core.Point#COORDINATE local _termid=parkingspot.TerminalID + self:I({_termid=_termid}) + if AIRBASE._CheckTerminalType(parkingspot.TerminalType, terminaltype) then -- Very safe uses the DCS getParking() info to check if a spot is free. Unfortunately, the function returns free=false until the aircraft has actually taken-off. @@ -783,7 +788,7 @@ function AIRBASE:FindFreeParkingSpotForAircraft(group, terminaltype, scanradius, --_spot:MarkToAll(string.format("Parking spot %d free=%s", parkingspot.TerminalID, tostring(not occupied))) if occupied then - self:T(string.format("%s: Parking spot id %d occupied.", airport, _termid)) + self:I(string.format("%s: Parking spot id %d occupied.", airport, _termid)) else self:I(string.format("%s: Parking spot id %d free.", airport, _termid)) if nvalid<_nspots then From 7b5b57c08734153b4ededc04feec1ab3d90c14be Mon Sep 17 00:00:00 2001 From: FlightControl Date: Fri, 31 May 2019 16:35:35 +0200 Subject: [PATCH 17/25] updates --- Moose Development/Moose/AI/AI_Escort.lua | 39 ++++++++----------- .../Moose/AI/AI_Escort_Request.lua | 26 ++++++++++--- 2 files changed, 38 insertions(+), 27 deletions(-) diff --git a/Moose Development/Moose/AI/AI_Escort.lua b/Moose Development/Moose/AI/AI_Escort.lua index b8e169a5e..734b84a8f 100644 --- a/Moose Development/Moose/AI/AI_Escort.lua +++ b/Moose Development/Moose/AI/AI_Escort.lua @@ -293,6 +293,9 @@ function AI_ESCORT:onafterStart( EscortGroupSet ) self.Detection:__Start( 30 ) + self:HandleEvent( EVENTS.Dead, OnEventDeadOrCrash ) + self:HandleEvent( EVENTS.Crash, OnEventDeadOrCrash ) + end --- Set a Detection method for the EscortUnit to be reported upon. @@ -554,8 +557,7 @@ function AI_ESCORT:EscortMenuJoinUp( EscortGroup ) if self.Menu.JoinUp == true then if EscortGroup:IsAir() then local EscortGroupName = EscortGroup:GetName() - local EscortMenu = MENU_GROUP:New( self.PlayerGroup, EscortGroupName, self.MainMenu ) - local EscortMenuReportNavigation = MENU_GROUP:New( self.PlayerGroup, "Navigation", EscortMenu ) + local EscortMenuReportNavigation = MENU_GROUP:New( self.PlayerGroup, "Navigation", EscortGroup.EscortMenu ) local EscortMenuJoinUp = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Join Up", EscortMenuReportNavigation, AI_ESCORT._JoinUp, self, EscortGroup ) end end @@ -588,8 +590,7 @@ function AI_ESCORT:EscortMenuHoldAtEscortPosition( EscortGroup ) for _, HoldAtEscortPosition in pairs( self.Menu.HoldAtEscortPosition ) do if EscortGroup:IsAir() then local EscortGroupName = EscortGroup:GetName() - local EscortMenu = MENU_GROUP:New( self.PlayerGroup, EscortGroupName, self.MainMenu ) - local EscortMenuReportNavigation = MENU_GROUP:New( self.PlayerGroup, "Navigation", EscortMenu ) + local EscortMenuReportNavigation = MENU_GROUP:New( self.PlayerGroup, "Navigation", EscortGroup.EscortMenu ) local EscortMenuHoldPosition = MENU_GROUP_COMMAND :New( self.PlayerGroup, @@ -679,8 +680,7 @@ function AI_ESCORT:EscortMenuHoldAtLeaderPosition( EscortGroup ) if EscortGroup:IsAir() then local EscortGroupName = EscortGroup:GetName() - local EscortMenu = MENU_GROUP:New( self.PlayerGroup, EscortGroupName, self.MainMenu ) - local EscortMenuReportNavigation = MENU_GROUP:New( self.PlayerGroup, "Navigation", EscortMenu ) + local EscortMenuReportNavigation = MENU_GROUP:New( self.PlayerGroup, "Navigation", EscortGroup.EscortMenu ) local EscortMenuHoldAtLeaderPosition = MENU_GROUP_COMMAND :New( @@ -850,8 +850,7 @@ function AI_ESCORT:MenuFlare( MenuTextFormat ) function( EscortGroup ) local EscortGroupName = EscortGroup:GetName() - local EscortMenu = MENU_GROUP:New( self.PlayerGroup, EscortGroupName, self.MainMenu ) - local EscortMenuReportNavigation = MENU_GROUP:New( self.PlayerGroup, "Navigation", EscortMenu ) + local EscortMenuReportNavigation = MENU_GROUP:New( self.PlayerGroup, "Navigation", EscortGroup.EscortMenu ) local EscortMenuFlare = MENU_GROUP:New( self.PlayerGroup, MenuText, EscortMenuReportNavigation ) local EscortMenuFlareGreen = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Release green flare", EscortMenuFlare, AI_ESCORT._Flare, self, EscortGroup, FLARECOLOR.Green, "Released a green flare!" ) @@ -897,8 +896,7 @@ function AI_ESCORT:MenuSmoke( MenuTextFormat ) if not EscortGroup:IsAir() then local EscortGroupName = EscortGroup:GetName() - local EscortMenu = MENU_GROUP:New( self.PlayerGroup, EscortGroupName, self.MainMenu ) - local EscortMenuReportNavigation = MENU_GROUP:New( self.PlayerGroup, "Navigation", EscortMenu ) + local EscortMenuReportNavigation = MENU_GROUP:New( self.PlayerGroup, "Navigation", EscortGroup.EscortMenu ) local EscortMenuSmoke = MENU_GROUP:New( self.PlayerGroup, MenuText, EscortMenuReportNavigation ) local EscortMenuSmokeGreen = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Release green smoke", EscortMenuSmoke, AI_ESCORT._Smoke, self, EscortGroup, SMOKECOLOR.Green, "Releasing green smoke!" ) @@ -948,8 +946,7 @@ function AI_ESCORT:MenuReportTargets( Seconds ) if EscortGroup:IsAir() then local EscortGroupName = EscortGroup:GetName() - local EscortMenu = MENU_GROUP:New( self.PlayerGroup, EscortGroupName, self.MainMenu ) - local EscortMenuReportTargets = MENU_GROUP:New( self.PlayerGroup, "Report targets", EscortMenu ) + local EscortMenuReportTargets = MENU_GROUP:New( self.PlayerGroup, "Report targets", EscortGroup.EscortMenu ) -- Report Targets @@ -958,7 +955,7 @@ function AI_ESCORT:MenuReportTargets( Seconds ) --EscortGroup.EscortMenuReportNearbyTargetsOff = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Report targets off", EscortGroup.EscortMenuReportNearbyTargets, AI_ESCORT._SwitchReportNearbyTargets, self, EscortGroup, false ) -- Attack Targets - local EscortMenuAttackTargets = MENU_GROUP:New( self.PlayerGroup, "Attack targets", EscortMenu ) + local EscortMenuAttackTargets = MENU_GROUP:New( self.PlayerGroup, "Attack targets", EscortGroup.EscortMenu ) EscortGroup.ReportTargetsScheduler = SCHEDULER:New( self, self._ReportTargetsScheduler, { EscortGroup }, timer, Seconds ) timer=timer+1 @@ -1012,8 +1009,7 @@ function AI_ESCORT:MenuROE( MenuTextFormat ) -- Rules of Engagement local EscortGroupName = EscortGroup:GetName() - local EscortMenu = MENU_GROUP:New( self.PlayerGroup, EscortGroupName, self.MainMenu ) - local EscortMenuROE = MENU_GROUP:New( self.PlayerGroup, "Rule Of Engagement", EscortMenu ) + local EscortMenuROE = MENU_GROUP:New( self.PlayerGroup, "Rule Of Engagement", EscortGroup.EscortMenu ) if EscortGroup:OptionROEHoldFirePossible() then local EscortMenuROEHoldFire = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Hold fire", EscortMenuROE, AI_ESCORT._ROE, self, EscortGroup, GROUP.OptionROEHoldFire, "Holding weapons!" ) @@ -1055,8 +1051,7 @@ function AI_ESCORT:MenuROT( MenuTextFormat ) if EscortGroup:IsAir() then local EscortGroupName = EscortGroup:GetName() - local EscortMenu = MENU_GROUP:New( self.PlayerGroup, EscortGroupName, self.MainMenu ) - local EscortMenuROT = MENU_GROUP:New( self.PlayerGroup, "Reaction On Threat", EscortMenu ) + local EscortMenuROT = MENU_GROUP:New( self.PlayerGroup, "Reaction On Threat", EscortGroup.EscortMenu ) if not EscortGroup.EscortMenuEvasion then -- Reaction to Threats @@ -1092,8 +1087,7 @@ function AI_ESCORT:MenuResumeMission() function( EscortGroup ) if EscortGroup:IsAir() then local EscortGroupName = EscortGroup:GetName() - local EscortMenu = MENU_GROUP:New( self.PlayerGroup, EscortGroupName, self.MainMenu ) - EscortGroup.EscortMenuResumeMission = MENU_GROUP:New( self.PlayerGroup, "Resume from", EscortMenu ) + EscortGroup.EscortMenuResumeMission = MENU_GROUP:New( self.PlayerGroup, "Resume from", EscortGroup.EscortMenu ) end end ) @@ -1435,7 +1429,7 @@ function AI_ESCORT:_AttackTarget( EscortGroup, DetectedItem ) ) Tasks[#Tasks+1] = EscortGroup:TaskCombo( AttackUnitTasks ) - Tasks[#Tasks+1] = EscortGroup:TaskFunction( "AI_ESCORT.___Resume", EscortGroup, self ) + Tasks[#Tasks+1] = EscortGroup:TaskFunction( "AI_ESCORT.___Resume", self ) EscortGroup:SetTask( EscortGroup:TaskCombo( @@ -1590,8 +1584,7 @@ function AI_ESCORT:_ReportTargetsScheduler( EscortGroup ) local TimeUpdate = timer.getTime() local EscortGroupName = EscortGroup:GetName() - local EscortMenu = MENU_GROUP:New( self.PlayerGroup, EscortGroupName, self.MainMenu ) - local EscortMenuAttackTargets = MENU_GROUP:New( self.PlayerGroup, "Attack targets", EscortMenu ) + local EscortMenuAttackTargets = MENU_GROUP:New( self.PlayerGroup, "Attack targets", EscortGroup.EscortMenu ) for DetectedItemIndex, DetectedItem in pairs( DetectedItems ) do @@ -1712,3 +1705,5 @@ function AI_ESCORT:_FlightReportTargetsScheduler() return false end + + diff --git a/Moose Development/Moose/AI/AI_Escort_Request.lua b/Moose Development/Moose/AI/AI_Escort_Request.lua index 4b95b4b90..6bbbe8576 100644 --- a/Moose Development/Moose/AI/AI_Escort_Request.lua +++ b/Moose Development/Moose/AI/AI_Escort_Request.lua @@ -231,22 +231,24 @@ function AI_ESCORT_REQUEST:SpawnEscort() EscortGroup:OptionROTVertical() EscortGroup:OptionROEHoldFire() - self:ScheduleOnce( 5, - function() + self:ScheduleOnce( 0.1, + function( EscortGroup ) local LeaderEscort = self.EscortGroupSet:GetFirst() -- Wrapper.Group#GROUP local Report = REPORT:New() Report:Add( "Joining Up " .. self.EscortGroupSet:GetUnitTypeNames():Text( ", " ) .. " from " .. LeaderEscort:GetCoordinate():ToString( self.EscortUnit ) ) - LeaderEscort:MessageTypeToGroup( Report:Text(), MESSAGE.Type.Information, self.PlayerUnit ) + self:FormationTrail( 50, 50, 50 ) if self.SpawnMode == self.__Enum.Mode.Formation then self:JoinFormation( EscortGroup ) end --self:Menus( self.XStart, self.XSpace, self.YStart, self.YSpace, self.ZStart, self.ZSpace, self.ZLevels ) - + + EscortGroup.EscortMenu = MENU_GROUP:New( self.PlayerGroup, EscortGroup:GetName(), self.MainMenu ) + self:EscortMenuJoinUp( EscortGroup ) self:EscortMenuHoldAtEscortPosition( EscortGroup ) @@ -261,7 +263,18 @@ function AI_ESCORT_REQUEST:SpawnEscort() self:MenuROT() self:MenuResumeMission() - end + + --- @param #AI_ESCORT self + -- @param Core.Event#EVENTDATA EventData + function EscortGroup:OnEventDeadOrCrash( EventData ) + self:F( { "EventDead", EventData } ) + self.EscortMenu:Remove() + end + + EscortGroup:HandleEvent( EVENTS.Dead, EscortGroup.OnEventDeadOrCrash ) + EscortGroup:HandleEvent( EVENTS.Crash, EscortGroup.OnEventDeadOrCrash ) + + end, EscortGroup ) end @@ -277,6 +290,9 @@ function AI_ESCORT_REQUEST:onafterStart( EscortGroupSet ) end ) end + + self:HandleEvent( EVENTS.Dead, self.OnEventDeadOrCrash ) + self:HandleEvent( EVENTS.Crash, self.OnEventDeadOrCrash ) end From 7bae22248a4502666fc4cfbff998e1155625597d Mon Sep 17 00:00:00 2001 From: FlightControl Date: Sat, 1 Jun 2019 08:06:18 +0200 Subject: [PATCH 18/25] Optimizations ROE and ROT and flight modes. --- Moose Development/Moose/AI/AI_Escort.lua | 112 +++++++++++++----- .../Moose/AI/AI_Escort_Request.lua | 2 +- Moose Development/Moose/AI/AI_Formation.lua | 35 ++++-- 3 files changed, 111 insertions(+), 38 deletions(-) diff --git a/Moose Development/Moose/AI/AI_Escort.lua b/Moose Development/Moose/AI/AI_Escort.lua index 734b84a8f..ea5dccfe8 100644 --- a/Moose Development/Moose/AI/AI_Escort.lua +++ b/Moose Development/Moose/AI/AI_Escort.lua @@ -250,6 +250,8 @@ function AI_ESCORT:New( EscortUnit, EscortGroupSet, EscortName, EscortBriefing ) EscortGroupSet:ForEachGroup( --- @param Core.Group#GROUP EscortGroup function( EscortGroup ) + EscortGroup.EscortMenu = MENU_GROUP:New( self.PlayerGroup, EscortGroup:GetName(), self.MainMenu ) + -- Set EscortGroup known at EscortUnit. if not self.PlayerUnit._EscortGroups then self.PlayerUnit._EscortGroups = {} @@ -577,7 +579,7 @@ function AI_ESCORT:MenuJoinUp() self.EscortGroupSet:ForSomeGroupAlive( --- @param Core.Group#GROUP EscortGroup function( EscortGroup ) - self:EscortSetMenuJoinUp( EscortGroup ) + self:EscortMenuJoinUp( EscortGroup ) end ) @@ -997,10 +999,10 @@ function AI_ESCORT:MenuROE( MenuTextFormat ) local FlightMenuROE = MENU_GROUP:New( self.PlayerGroup, "Rule Of Engagement", self.FlightMenu ) - local FlightMenuROEHoldFire = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Hold fire", FlightMenuROE, AI_ESCORT._ROE, self, GROUP.OptionROEHoldFire, "Holding weapons!" ) - local FlightMenuROEReturnFire = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Return fire", FlightMenuROE, AI_ESCORT._ROE, self, GROUP.OptionROEReturnFire, "Returning fire!" ) - local FlightMenuROEOpenFire = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Open Fire", FlightMenuROE, AI_ESCORT._ROE, self, GROUP.OptionROEOpenFire, "Open fire at designated targets!" ) - local FlightMenuROEWeaponFree = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Engage all targets", FlightMenuROE, AI_ESCORT._ROE, self, GROUP.OptionROEWeaponFree, "Engaging all targets!" ) + local FlightMenuROEHoldFire = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Hold fire", FlightMenuROE, AI_ESCORT._FlightROEHoldFire, self, "Holding weapons!" ) + local FlightMenuROEReturnFire = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Return fire", FlightMenuROE, AI_ESCORT._FlightROEReturnFire, self, "Returning fire!" ) + local FlightMenuROEOpenFire = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Open Fire", FlightMenuROE, AI_ESCORT._FlightROEOpenFire, self, "Open fire at designated targets!" ) + local FlightMenuROEWeaponFree = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Engage all targets", FlightMenuROE, AI_ESCORT._FlightROEWeaponFree, self, "Engaging all targets!" ) self.EscortGroupSet:ForSomeGroupAlive( --- @param Core.Group#GROUP EscortGroup @@ -1012,16 +1014,16 @@ function AI_ESCORT:MenuROE( MenuTextFormat ) local EscortMenuROE = MENU_GROUP:New( self.PlayerGroup, "Rule Of Engagement", EscortGroup.EscortMenu ) if EscortGroup:OptionROEHoldFirePossible() then - local EscortMenuROEHoldFire = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Hold fire", EscortMenuROE, AI_ESCORT._ROE, self, EscortGroup, GROUP.OptionROEHoldFire, "Holding weapons!" ) + local EscortMenuROEHoldFire = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Hold fire", EscortMenuROE, AI_ESCORT._ROE, self, EscortGroup, EscortGroup.OptionROEHoldFire, "Holding weapons!" ) end if EscortGroup:OptionROEReturnFirePossible() then - local EscortMenuROEReturnFire = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Return fire", EscortMenuROE, AI_ESCORT._ROE, self, EscortGroup, GROUP.OptionROEReturnFire, "Returning fire!" ) + local EscortMenuROEReturnFire = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Return fire", EscortMenuROE, AI_ESCORT._ROE, self, EscortGroup, EscortGroup.OptionROEReturnFire, "Returning fire!" ) end if EscortGroup:OptionROEOpenFirePossible() then - EscortGroup.EscortMenuROEOpenFire = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Open Fire", EscortMenuROE, AI_ESCORT._ROE, self, EscortGroup, GROUP.OptionROEOpenFire, "Opening fire on designated targets!!" ) + EscortGroup.EscortMenuROEOpenFire = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Open Fire", EscortMenuROE, AI_ESCORT._ROE, self, EscortGroup, EscortGroup.OptionROEOpenFire, "Opening fire on designated targets!!" ) end if EscortGroup:OptionROEWeaponFreePossible() then - EscortGroup.EscortMenuROEWeaponFree = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Engage all targets", EscortMenuROE, AI_ESCORT._ROE, self, EscortGroup, GROUP.OptionROEWeaponFree, "Opening fire on targets of opportunity!" ) + EscortGroup.EscortMenuROEWeaponFree = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Engage all targets", EscortMenuROE, AI_ESCORT._ROE, self, EscortGroup, EscortGroup.OptionROEWeaponFree, "Opening fire on targets of opportunity!" ) end end end @@ -1040,10 +1042,10 @@ function AI_ESCORT:MenuROT( MenuTextFormat ) local FlightMenuROT = MENU_GROUP:New( self.PlayerGroup, "Reaction On Threat", self.FlightMenu ) - local FlightMenuROTNoReaction = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Fight until death", FlightMenuROT, AI_ESCORT._ROT, self, GROUP.OptionROTNoReaction, "Fighting until death!" ) - local FlightMenuROTPassiveDefense = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Use flares, chaff and jammers", FlightMenuROT, AI_ESCORT._ROT, self, GROUP.OptionROTPassiveDefense, "Defending using jammers, chaff and flares!" ) - local FlightMenuROTEvadeFire = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Open fire", FlightMenuROT, AI_ESCORT._ROT, self, GROUP.OptionROTEvadeFire, "Evading on enemy fire!" ) - local FlightMenuROTVertical = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Avoid radar and evade fire", FlightMenuROT, AI_ESCORT._ROT, self, GROUP.OptionROTVertical, "Evading on enemy fire with vertical manoeuvres!" ) + local FlightMenuROTNoReaction = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Fight until death", FlightMenuROT, AI_ESCORT._FlightROTNoReaction, self, "Fighting until death!" ) + local FlightMenuROTPassiveDefense = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Use flares, chaff and jammers", FlightMenuROT, AI_ESCORT._FlightROTPassiveDefense, self, "Defending using jammers, chaff and flares!" ) + local FlightMenuROTEvadeFire = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Open fire", FlightMenuROT, AI_ESCORT._FlightROTEvadeFire, self, "Evading on enemy fire!" ) + local FlightMenuROTVertical = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Avoid radar and evade fire", FlightMenuROT, AI_ESCORT._FlightROTVertical, self, "Evading on enemy fire with vertical manoeuvres!" ) self.EscortGroupSet:ForSomeGroupAlive( --- @param Core.Group#GROUP EscortGroup @@ -1056,16 +1058,16 @@ function AI_ESCORT:MenuROT( MenuTextFormat ) if not EscortGroup.EscortMenuEvasion then -- Reaction to Threats if EscortGroup:OptionROTNoReactionPossible() then - local EscortMenuEvasionNoReaction = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Fight until death", EscortMenuROT, AI_ESCORT._ROT, self, EscortGroup, GROUP.OptionROTNoReaction, "Fighting until death!" ) + local EscortMenuEvasionNoReaction = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Fight until death", EscortMenuROT, AI_ESCORT._ROT, self, EscortGroup, EscortGroup.OptionROTNoReaction, "Fighting until death!" ) end if EscortGroup:OptionROTPassiveDefensePossible() then - local EscortMenuEvasionPassiveDefense = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Use flares, chaff and jammers", EscortMenuROT, AI_ESCORT._ROT, self, EscortGroup, GROUP.OptionROTPassiveDefense, "Defending using jammers, chaff and flares!" ) + local EscortMenuEvasionPassiveDefense = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Use flares, chaff and jammers", EscortMenuROT, AI_ESCORT._ROT, self, EscortGroup, EscortGroup.OptionROTPassiveDefense, "Defending using jammers, chaff and flares!" ) end if EscortGroup:OptionROTEvadeFirePossible() then - local EscortMenuEvasionEvadeFire = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Open fire", EscortMenuROT, AI_ESCORT._ROT, self, EscortGroup, GROUP.OptionROTEvadeFire, "Evading on enemy fire!" ) + local EscortMenuEvasionEvadeFire = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Open fire", EscortMenuROT, AI_ESCORT._ROT, self, EscortGroup, EscortGroup.OptionROTEvadeFire, "Evading on enemy fire!" ) end if EscortGroup:OptionROTVerticalPossible() then - local EscortMenuOptionEvasionVertical = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Avoid radar and evade fire", EscortMenuROT, AI_ESCORT._ROT, self, EscortGroup, GROUP.OptionROTVertical, "Evading on enemy fire with vertical manoeuvres!" ) + local EscortMenuOptionEvasionVertical = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Avoid radar and evade fire", EscortMenuROT, AI_ESCORT._ROT, self, EscortGroup, EscortGroup.OptionROTVertical, "Evading on enemy fire with vertical manoeuvres!" ) end end end @@ -1107,7 +1109,7 @@ function AI_ESCORT:_HoldPosition( OrbitGroup, EscortGroup, OrbitHeight, OrbitSec local OrbitUnit = OrbitGroup:GetUnit(1) -- Wrapper.Unit#UNIT - self:ReleaseFormation( EscortGroup ) + self:ModeMission( EscortGroup ) local PointFrom = {} local GroupVec3 = EscortGroup:GetUnit(1):GetVec3() @@ -1168,7 +1170,7 @@ function AI_ESCORT:_JoinUp( EscortGroup ) local EscortUnit = self.PlayerUnit - self:JoinFormation( EscortGroup ) + self:ModeFormation( EscortGroup ) EscortGroup:SetState( self, "Mode", self.__Enum.Mode.Follow ) end @@ -1372,7 +1374,6 @@ function AI_ESCORT.___Resume( EscortGroup, self ) local PlayerGroup = self.PlayerGroup - self:JoinFormation( EscortGroup ) EscortGroup:MessageTypeToGroup( "Destroyed all targets. Rejoining.", MESSAGE.Type.Information, PlayerGroup ) end @@ -1407,7 +1408,7 @@ function AI_ESCORT:_AttackTarget( EscortGroup, DetectedItem ) local EscortUnit = self.PlayerUnit - self:ReleaseFormation( EscortGroup ) + self:ModeMission( EscortGroup ) if EscortGroup:IsAir() then EscortGroup:OptionROEOpenFire() @@ -1512,36 +1513,89 @@ function AI_ESCORT:_AssistTarget( EscortGroup, DetectedItem ) end function AI_ESCORT:_ROE( EscortGroup, EscortROEFunction, EscortROEMessage ) - pcall( function() EscortROEFunction() end ) + pcall( function() EscortROEFunction( EscortGroup ) end ) EscortGroup:MessageTypeToGroup( EscortROEMessage, MESSAGE.Type.Information, self.PlayerGroup ) end -function AI_ESCORT:_FlightROE( EscortROEFunction, EscortROEMessage ) - self.EscortGroupSet:ForSomeGroupAlive( + +function AI_ESCORT:_FlightROEHoldFire( EscortROEMessage ) + self.EscortGroupSet:ForEachGroupAlive( --- @param Wrapper.Group#GROUP EscortGroup function( EscortGroup ) - self:_ROE( EscortGroup, EscortROEFunction, EscortROEMessage ) + self:_ROE( EscortGroup, EscortGroup.OptionROEHoldFire, EscortROEMessage ) + end + ) +end + +function AI_ESCORT:_FlightROEOpenFire( EscortROEMessage ) + self.EscortGroupSet:ForEachGroupAlive( + --- @param Wrapper.Group#GROUP EscortGroup + function( EscortGroup ) + self:_ROE( EscortGroup, EscortGroup.OptionROEOpenFire, EscortROEMessage ) + end + ) +end + +function AI_ESCORT:_FlightROEReturnFire( EscortROEMessage ) + self.EscortGroupSet:ForEachGroupAlive( + --- @param Wrapper.Group#GROUP EscortGroup + function( EscortGroup ) + self:_ROE( EscortGroup, EscortGroup.OptionROEReturnFire, EscortROEMessage ) + end + ) +end + +function AI_ESCORT:_FlightROEWeaponFree( EscortROEMessage ) + self.EscortGroupSet:ForEachGroupAlive( + --- @param Wrapper.Group#GROUP EscortGroup + function( EscortGroup ) + self:_ROE( EscortGroup, EscortGroup.OptionROEWeaponFree, EscortROEMessage ) end ) end function AI_ESCORT:_ROT( EscortGroup, EscortROTFunction, EscortROTMessage ) - pcall( function() EscortROTFunction() end ) + pcall( function() EscortROTFunction( EscortGroup ) end ) EscortGroup:MessageTypeToGroup( EscortROTMessage, MESSAGE.Type.Information, self.PlayerGroup ) end -function AI_ESCORT:_FlightROT( EscortROTFunction, EscortROTMessage ) - self.EscortGroupSet:ForSomeGroupAlive( +function AI_ESCORT:_FlightROTNoReaction( EscortROTMessage ) + self.EscortGroupSet:ForEachGroupAlive( --- @param Wrapper.Group#GROUP EscortGroup function( EscortGroup ) - self:_ROT( EscortGroup, EscortROTFunction, EscortROTMessage ) + self:_ROT( EscortGroup, EscortGroup.OptionROTNoReaction, EscortROTMessage ) end ) end +function AI_ESCORT:_FlightROTPassiveDefense( EscortROTMessage ) + self.EscortGroupSet:ForEachGroupAlive( + --- @param Wrapper.Group#GROUP EscortGroup + function( EscortGroup ) + self:_ROT( EscortGroup, EscortGroup.OptionROTPassiveDefense, EscortROTMessage ) + end + ) +end +function AI_ESCORT:_FlightROTEvadeFire( EscortROTMessage ) + self.EscortGroupSet:ForEachGroupAlive( + --- @param Wrapper.Group#GROUP EscortGroup + function( EscortGroup ) + self:_ROT( EscortGroup, EscortGroup.OptionROTEvadeFire, EscortROTMessage ) + end + ) +end + +function AI_ESCORT:_FlightROTVertical( EscortROTMessage ) + self.EscortGroupSet:ForEachGroupAlive( + --- @param Wrapper.Group#GROUP EscortGroup + function( EscortGroup ) + self:_ROT( EscortGroup, EscortGroup.OptionROTVertical, EscortROTMessage ) + end + ) +end --- Registers the waypoints -- @param #AI_ESCORT self diff --git a/Moose Development/Moose/AI/AI_Escort_Request.lua b/Moose Development/Moose/AI/AI_Escort_Request.lua index 6bbbe8576..faf0e817c 100644 --- a/Moose Development/Moose/AI/AI_Escort_Request.lua +++ b/Moose Development/Moose/AI/AI_Escort_Request.lua @@ -242,7 +242,7 @@ function AI_ESCORT_REQUEST:SpawnEscort() self:FormationTrail( 50, 50, 50 ) if self.SpawnMode == self.__Enum.Mode.Formation then - self:JoinFormation( EscortGroup ) + self:ModeFormation( EscortGroup ) end --self:Menus( self.XStart, self.XSpace, self.YStart, self.YSpace, self.ZStart, self.ZSpace, self.ZLevels ) diff --git a/Moose Development/Moose/AI/AI_Formation.lua b/Moose Development/Moose/AI/AI_Formation.lua index f4ad1902f..31930c045 100644 --- a/Moose Development/Moose/AI/AI_Formation.lua +++ b/Moose Development/Moose/AI/AI_Formation.lua @@ -950,33 +950,52 @@ function AI_FORMATION:SetFlightRandomization( FlightRandomization ) --R2.1 end ---- This releases the air unit in your flight from the formation flight. + +--- This sets your escorts to fly a mission. -- @param #AI_FORMATION self -- @param Wrapper.Group#GROUP FollowGroup FollowGroup. -- @return #AI_FORMATION -function AI_FORMATION:ReleaseFormation( FollowGroup ) +function AI_FORMATION:ModeMission( FollowGroup ) - FollowGroup:SetState( FollowGroup, "Mode", self.__Enum.Mode.Mission ) + if FollowGroup then + FollowGroup:SetState( FollowGroup, "Mode", self.__Enum.Mode.Mission ) + else + self.EscortGroupSet:ForSomeGroupAlive( + --- @param Core.Group#GROUP EscortGroup + function( FollowGroup ) + FollowGroup:SetState( FollowGroup, "Mode", self.__Enum.Mode.Mission ) + end + ) + end + return self end ---- This joins up the air unit in your formation flight. +--- This sets your escorts to fly in a formation. -- @param #AI_FORMATION self -- @param Wrapper.Group#GROUP FollowGroup FollowGroup. -- @return #AI_FORMATION -function AI_FORMATION:JoinFormation( FollowGroup ) +function AI_FORMATION:ModeFormation( FollowGroup ) - -- If a formation type was defined for the AI_FORMATION object, then we can joinup. - - FollowGroup:SetState( FollowGroup, "Mode", self.__Enum.Mode.Formation ) + if FollowGroup then + FollowGroup:SetState( FollowGroup, "Mode", self.__Enum.Mode.Formation ) + else + self.EscortGroupSet:ForSomeGroupAlive( + --- @param Core.Group#GROUP EscortGroup + function( FollowGroup ) + FollowGroup:SetState( FollowGroup, "Mode", self.__Enum.Mode.Formation ) + end + ) + end return self end + --- Stop function. Formation will not be updated any more. -- @param #AI_FORMATION self -- @param Core.Set#SET_GROUP FollowGroupSet The following set of groups. From 0a027caa4747b0aa0ff56ba38495c14249e4f2a6 Mon Sep 17 00:00:00 2001 From: FlightControl Date: Sat, 15 Jun 2019 12:47:24 +0200 Subject: [PATCH 19/25] Test --- Moose Development/Moose/AI/AI_Escort.lua | 79 ++++++++++++++++++++---- 1 file changed, 68 insertions(+), 11 deletions(-) diff --git a/Moose Development/Moose/AI/AI_Escort.lua b/Moose Development/Moose/AI/AI_Escort.lua index ea5dccfe8..49542b3ae 100644 --- a/Moose Development/Moose/AI/AI_Escort.lua +++ b/Moose Development/Moose/AI/AI_Escort.lua @@ -151,6 +151,10 @@ --- @type AI_ESCORT -- @extends AI.AI_Formation#AI_FORMATION + +-- TODO: Add the menus when the class Start method is activated. +-- TODO: Remove the menus when the class Stop method is called. + --- AI_ESCORT class -- -- # AI_ESCORT construction methods. @@ -323,7 +327,7 @@ function AI_ESCORT:TestSmokeDirectionVector( SmokeDirection ) end ---- Defines the default menus +--- Defines the default menus for helicopters. -- @param #AI_ESCORT self -- @param #number XStart The start position on the X-axis in meters for the first group. -- @param #number XSpace The space between groups on the X-axis in meters for each sequent group. @@ -333,7 +337,60 @@ end -- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group. -- @param #number ZLevels The amount of levels on the Z-axis. -- @return #AI_ESCORT -function AI_ESCORT:Menus( XStart, XSpace, YStart, YSpace, ZStart, ZSpace, ZLevels ) +function AI_ESCORT:MenusHelicopter( XStart, XSpace, YStart, YSpace, ZStart, ZSpace, ZLevels ) + self:F() + +-- self:MenuScanForTargets( 100, 60 ) + + self.XStart = XStart or self.XStart + self.XSpace = XSpace or self.XSpace + self.YStart = YStart or self.YStart + self.YSpace = YSpace or self.YSpace + self.ZStart = ZStart or self.ZStart + self.ZSpace = ZSpace or self.ZSpace + self.ZLevels = ZLevels or self.ZLevels + + self:MenuJoinUp() + self:MenuFormationTrail(self.XStart,self.XSpace,self.YStart) + self:MenuFormationStack(self.XStart,self.XSpace,self.YStart,self.YSpace) + self:MenuFormationLeftLine(self.XStart,self.YStart,self.ZStart,self.ZSpace) + self:MenuFormationRightLine(self.XStart,self.YStart,self.ZStart,self.ZSpace) + self:MenuFormationLeftWing(self.XStart,self.XSpace,self.YStart,self.ZStart,self.ZSpace) + self:MenuFormationRightWing(self.XStart,self.XSpace,self.YStart,self.ZStart,self.ZSpace) + self:MenuFormationVic(self.XStart,self.XSpace,self.YStart,self.YSpace,self.ZStart,self.ZSpace) + self:MenuFormationBox(self.XStart,self.XSpace,self.YStart,self.YSpace,self.ZStart,self.ZSpace,self.ZLevels) + + self:MenuHoldAtEscortPosition( 30 ) + self:MenuHoldAtEscortPosition( 100 ) + self:MenuHoldAtEscortPosition( 500 ) + self:MenuHoldAtLeaderPosition( 30, 500 ) + + self:MenuFlare() + self:MenuSmoke() + + self:MenuReportTargets( 60 ) + self:MenuAssistedAttack() + self:MenuROE() + self:MenuROT() + + self:MenuResumeMission() + + + return self +end + + +--- Defines the default menus for airplanes. +-- @param #AI_ESCORT self +-- @param #number XStart The start position on the X-axis in meters for the first group. +-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group. +-- @param #nubmer YStart The start position on the Y-axis in meters for the first group. +-- @param #number YSpace The space between groups on the Y-axis in meters for each sequent group. +-- @param #nubmer ZStart The start position on the Z-axis in meters for the first group. +-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group. +-- @param #number ZLevels The amount of levels on the Z-axis. +-- @return #AI_ESCORT +function AI_ESCORT:MenusAirplanes( XStart, XSpace, YStart, YSpace, ZStart, ZSpace, ZLevels ) self:F() -- self:MenuScanForTargets( 100, 60 ) @@ -940,7 +997,7 @@ function AI_ESCORT:MenuReportTargets( Seconds ) -- Attack Targets local FlightMenuAttackNearbyTargets = MENU_GROUP:New( self.PlayerGroup, "Attack targets", self.FlightMenu ) - self.FlightReportTargetsScheduler = SCHEDULER:New( self, self._FlightReportTargetsScheduler, {}, 5, Seconds ) + self.FlightReportTargetsScheduler = SCHEDULER:New( self, self._FlightReportTargetsScheduler, {}, Seconds, Seconds ) self.EscortGroupSet:ForSomeGroupAlive( --- @param Core.Group#GROUP EscortGroup @@ -1150,7 +1207,7 @@ function AI_ESCORT:_FlightHoldPosition( OrbitGroup, OrbitHeight, OrbitSeconds ) local EscortUnit = self.PlayerUnit - self.EscortGroupSet:ForSomeGroupAlive( + self.EscortGroupSet:ForEachGroupAlive( --- @param Core.Group#GROUP EscortGroup function( EscortGroup, OrbitGroup ) if EscortGroup:IsAir() then @@ -1178,7 +1235,7 @@ end function AI_ESCORT:_FlightJoinUp() - self.EscortGroupSet:ForSomeGroupAlive( + self.EscortGroupSet:ForEachGroupAlive( --- @param Core.Group#GROUP EscortGroup function( EscortGroup ) if EscortGroup:IsAir() then @@ -1205,7 +1262,7 @@ end function AI_ESCORT:_FlightFormationTrail( XStart, XSpace, YStart ) - self.EscortGroupSet:ForSomeGroupAlive( + self.EscortGroupSet:ForEachGroupAlive( --- @param Core.Group#GROUP EscortGroup function( EscortGroup ) if EscortGroup:IsAir() then @@ -1232,7 +1289,7 @@ end function AI_ESCORT:_FlightFormationStack( XStart, XSpace, YStart, YSpace ) - self.EscortGroupSet:ForSomeGroupAlive( + self.EscortGroupSet:ForEachGroupAlive( --- @param Core.Group#GROUP EscortGroup function( EscortGroup ) if EscortGroup:IsAir() then @@ -1255,7 +1312,7 @@ end function AI_ESCORT:_FlightFlare( Color, Message ) - self.EscortGroupSet:ForSomeGroupAlive( + self.EscortGroupSet:ForEachGroupAlive( --- @param Core.Group#GROUP EscortGroup function( EscortGroup ) if EscortGroup:IsAir() then @@ -1278,7 +1335,7 @@ end function AI_ESCORT:_FlightSmoke( Color, Message ) - self.EscortGroupSet:ForSomeGroupAlive( + self.EscortGroupSet:ForEachGroupAlive( --- @param Core.Group#GROUP EscortGroup function( EscortGroup ) if EscortGroup:IsAir() then @@ -1325,7 +1382,7 @@ end function AI_ESCORT:_FlightSwitchReportNearbyTargets( ReportTargets ) - self.EscortGroupSet:ForSomeGroupAlive( + self.EscortGroupSet:ForEachGroupAlive( --- @param Core.Group#GROUP EscortGroup function( EscortGroup ) if EscortGroup:IsAir() then @@ -1468,7 +1525,7 @@ end function AI_ESCORT:_FlightAttackTarget( DetectedItem ) - self.EscortGroupSet:ForSomeGroupAlive( + self.EscortGroupSet:ForEachGroupAlive( --- @param Core.Group#GROUP EscortGroup function( EscortGroup, DetectedItem ) if EscortGroup:IsAir() then From d34cff16755d642877b45d7829263a8c47d87db1 Mon Sep 17 00:00:00 2001 From: FlightControl Date: Mon, 17 Jun 2019 09:00:45 +0200 Subject: [PATCH 20/25] Temporary --- Moose Development/Moose/AI/AI_Escort.lua | 520 ++++++++++++++--------- 1 file changed, 319 insertions(+), 201 deletions(-) diff --git a/Moose Development/Moose/AI/AI_Escort.lua b/Moose Development/Moose/AI/AI_Escort.lua index 49542b3ae..b81ebbb02 100644 --- a/Moose Development/Moose/AI/AI_Escort.lua +++ b/Moose Development/Moose/AI/AI_Escort.lua @@ -301,6 +301,43 @@ function AI_ESCORT:onafterStart( EscortGroupSet ) self:HandleEvent( EVENTS.Dead, OnEventDeadOrCrash ) self:HandleEvent( EVENTS.Crash, OnEventDeadOrCrash ) + + self:SetFlightMenuFormation( "Trail" ) + self:SetFlightMenuFormation( "Stack" ) + self:SetFlightMenuFormation( "LeftLine" ) + self:SetFlightMenuFormation( "RightLine" ) + self:SetFlightMenuFormation( "LeftWing" ) + self:SetFlightMenuFormation( "RightWing" ) + self:SetFlightMenuFormation( "Vic" ) + self:SetFlightMenuFormation( "Box" ) + + self:SetFlightMenuHoldAtEscortPosition() + self:SetFlightMenuHoldAtLeaderPosition() + + self:SetFlightMenuFlare() + self:SetFlightMenuSmoke() + + self:SetFlightMenuROE() + self:SetFlightMenuROT() + + self:SetFlightMenuTargets() + + self.EscortGroupSet:ForSomeGroupAlive( + --- @param Core.Group#GROUP EscortGroup + function( EscortGroup ) + self:SetEscortMenuHoldAtEscortPosition( EscortGroup ) + self:SetEscortMenuHoldAtLeaderPosition( EscortGroup ) + + self:SetEscortMenuFlare( EscortGroup ) + self:SetEscortMenuSmoke( EscortGroup ) + + self:SetEscortMenuROE( EscortGroup ) + self:SetEscortMenuROT( EscortGroup ) + + self:SetEscortMenuTargets( EscortGroup ) + end + ) + end @@ -431,28 +468,40 @@ function AI_ESCORT:MenusAirplanes( XStart, XSpace, YStart, YSpace, ZStart, ZSpac end +function AI_ESCORT:SetFlightMenuFormation( Formation ) -function AI_ESCORT:MenuFormation( Formation, ... ) + local FormationID = "Formation" .. Formation + + local MenuFormation = self.Menu[FormationID] - if not self.FlightMenuFormation then - self.FlightMenuFormation = MENU_GROUP:New( self.PlayerGroup, "Formation", self.MainMenu ) - end - - if not self["FlightMenuFormation"..Formation] then - self["FlightMenuFormation"..Formation] = MENU_GROUP_COMMAND:New( self.PlayerGroup, Formation, self.FlightMenuFormation, + if MenuFormation then + local Arguments = MenuFormation.Arguments + local FlightMenuFormation = MENU_GROUP:New( self.PlayerGroup, "Formation", self.MainMenu ) + local MenuFlightFormationID = MENU_GROUP_COMMAND:New( self.PlayerGroup, Formation, FlightMenuFormation, function ( self, Formation, ... ) self.EscortGroupSet:ForSomeGroupAlive( --- @param Core.Group#GROUP EscortGroup function( EscortGroup, self, Formation, ... ) if EscortGroup:IsAir() then - self:E({Formation=Formation}) - self["Formation"..Formation]( self, ... ) + self:E({FormationID=FormationID}) + self[FormationID]( self, ... ) end end, self, Formation, ... ) - end, self, Formation, ... + end, self, Formation, Arguments ) end + + return self +end + + +function AI_ESCORT:MenuFormation( Formation, ... ) + + local FormationID = "Formation"..Formation + self.Menu[FormationID] = self.Menu[FormationID] or {} + self.Menu[FormationID][#self.Menu[FormationID]+1] = {} + self.Menu[FormationID][#self.Menu[FormationID]+1].Arguments = ... end @@ -644,7 +693,28 @@ function AI_ESCORT:MenuJoinUp() end -function AI_ESCORT:EscortMenuHoldAtEscortPosition( EscortGroup ) +function AI_ESCORT:SetFlightMenuHoldAtEscortPosition() + + for _, MenuHoldAtEscortPosition in pairs( self.Menu.HoldAtEscortPosition ) do + local FlightMenuReportNavigation = MENU_GROUP:New( self.PlayerGroup, "Navigation", self.FlightMenu ) + + local FlightMenuHoldPosition = MENU_GROUP_COMMAND + :New( + self.PlayerGroup, + MenuHoldAtEscortPosition.MenuText, + FlightMenuReportNavigation, + AI_ESCORT._FlightHoldPosition, + self, + nil, + MenuHoldAtEscortPosition.Height, + MenuHoldAtEscortPosition.Speed + ) + + end + return self +end + +function AI_ESCORT:SetEscortMenuHoldAtEscortPosition( EscortGroup ) for _, HoldAtEscortPosition in pairs( self.Menu.HoldAtEscortPosition ) do if EscortGroup:IsAir() then @@ -702,38 +772,38 @@ function AI_ESCORT:MenuHoldAtEscortPosition( Height, Speed, MenuTextFormat ) end end - local FlightMenuReportNavigation = MENU_GROUP:New( self.PlayerGroup, "Navigation", self.FlightMenu ) - - local FlightMenuHoldPosition = MENU_GROUP_COMMAND - :New( - self.PlayerGroup, - MenuText, - FlightMenuReportNavigation, - AI_ESCORT._FlightHoldPosition, - self, - nil, - Height, - Speed - ) - self.Menu.HoldAtEscortPosition = self.Menu.HoldAtEscortPosition or {} self.Menu.HoldAtEscortPosition[#self.Menu.HoldAtEscortPosition+1] = {} self.Menu.HoldAtEscortPosition[#self.Menu.HoldAtEscortPosition].Height = Height self.Menu.HoldAtEscortPosition[#self.Menu.HoldAtEscortPosition].Speed = Speed self.Menu.HoldAtEscortPosition[#self.Menu.HoldAtEscortPosition].MenuText = MenuText - self.EscortGroupSet:ForSomeGroupAlive( - --- @param Core.Group#GROUP EscortGroup - function( EscortGroup ) - self:EscortMenuHoldAtEscortPosition( EscortGroup ) - end - ) - return self end -function AI_ESCORT:EscortMenuHoldAtLeaderPosition( EscortGroup ) +function AI_ESCORT:SetFlightMenuHoldAtLeaderPosition() + + for _, MenuHoldAtLeaderPosition in pairs( self.Menu.HoldAtLeaderPosition ) do + local FlightMenuReportNavigation = MENU_GROUP:New( self.PlayerGroup, "Navigation", self.FlightMenu ) + + local FlightMenuHoldAtLeaderPosition = MENU_GROUP_COMMAND + :New( + self.PlayerGroup, + MenuHoldAtLeaderPosition.MenuText, + FlightMenuReportNavigation, + AI_ESCORT._FlightHoldPosition, + self, + self.PlayerGroup, + MenuHoldAtLeaderPosition.Height, + MenuHoldAtLeaderPosition.Speed + ) + end + + return self +end + +function AI_ESCORT:SetEscortMenuHoldAtLeaderPosition( EscortGroup ) for _, HoldAtLeaderPosition in pairs( self.Menu.HoldAtLeaderPosition ) do if EscortGroup:IsAir() then @@ -792,33 +862,12 @@ function AI_ESCORT:MenuHoldAtLeaderPosition( Height, Speed, MenuTextFormat ) end end - local FlightMenuReportNavigation = MENU_GROUP:New( self.PlayerGroup, "Navigation", self.FlightMenu ) - - local FlightMenuHoldAtLeaderPosition = MENU_GROUP_COMMAND - :New( - self.PlayerGroup, - MenuText, - FlightMenuReportNavigation, - AI_ESCORT._FlightHoldPosition, - self, - self.PlayerGroup, - Height, - Speed - ) - self.Menu.HoldAtLeaderPosition = self.Menu.HoldAtLeaderPosition or {} self.Menu.HoldAtLeaderPosition[#self.Menu.HoldAtLeaderPosition+1] = {} self.Menu.HoldAtLeaderPosition[#self.Menu.HoldAtLeaderPosition].Height = Height self.Menu.HoldAtLeaderPosition[#self.Menu.HoldAtLeaderPosition].Speed = Speed self.Menu.HoldAtLeaderPosition[#self.Menu.HoldAtLeaderPosition].MenuText = MenuText - self.EscortGroupSet:ForSomeGroupAlive( - --- @param Core.Group#GROUP EscortGroup - function( EscortGroup ) - self:EscortMenuHoldAtLeaderPosition( EscortGroup ) - end - ) - return self end @@ -879,6 +928,41 @@ function AI_ESCORT:MenuScanForTargets( Height, Seconds, MenuTextFormat ) end +function AI_ESCORT:SetFlightMenuFlare() + + for _, MenuFlare in pairs( self.Menu.Flare) do + local FlightMenuReportNavigation = MENU_GROUP:New( self.PlayerGroup, "Navigation", self.FlightMenu ) + local FlightMenuFlare = MENU_GROUP:New( self.PlayerGroup, MenuText, FlightMenuReportNavigation ) + + local FlightMenuFlareGreenFlight = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Release green flare", FlightMenuFlare, AI_ESCORT._FlightFlare, self, FLARECOLOR.Green, "Released a green flare!" ) + local FlightMenuFlareRedFlight = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Release red flare", FlightMenuFlare, AI_ESCORT._FlightFlare, self, FLARECOLOR.Red, "Released a red flare!" ) + local FlightMenuFlareWhiteFlight = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Release white flare", FlightMenuFlare, AI_ESCORT._FlightFlare, self, FLARECOLOR.White, "Released a white flare!" ) + local FlightMenuFlareYellowFlight = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Release yellow flare", FlightMenuFlare, AI_ESCORT._FlightFlare, self, FLARECOLOR.Yellow, "Released a yellow flare!" ) + end + + return self +end + +function AI_ESCORT:SetEscortMenuFlare( EscortGroup ) + + for _, MenuFlare in pairs( self.Menu.Flare) do + if EscortGroup:IsAir() then + + local EscortGroupName = EscortGroup:GetName() + local EscortMenuReportNavigation = MENU_GROUP:New( self.PlayerGroup, "Navigation", EscortGroup.EscortMenu ) + local EscortMenuFlare = MENU_GROUP:New( self.PlayerGroup, MenuFlare.MenuText, EscortMenuReportNavigation ) + + local EscortMenuFlareGreen = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Release green flare", EscortMenuFlare, AI_ESCORT._Flare, self, EscortGroup, FLARECOLOR.Green, "Released a green flare!" ) + local EscortMenuFlareRed = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Release red flare", EscortMenuFlare, AI_ESCORT._Flare, self, EscortGroup, FLARECOLOR.Red, "Released a red flare!" ) + local EscortMenuFlareWhite = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Release white flare", EscortMenuFlare, AI_ESCORT._Flare, self, EscortGroup, FLARECOLOR.White, "Released a white flare!" ) + local EscortMenuFlareYellow = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Release yellow flare", EscortMenuFlare, AI_ESCORT._Flare, self, EscortGroup, FLARECOLOR.Yellow, "Released a yellow flare!" ) + end + end + + return self +end + + --- Defines a menu slot to let the escort disperse a flare in a certain color. -- This menu will appear under **Navigation**. @@ -896,32 +980,52 @@ function AI_ESCORT:MenuFlare( MenuTextFormat ) MenuText = MenuTextFormat end - local FlightMenuReportNavigation = MENU_GROUP:New( self.PlayerGroup, "Navigation", self.FlightMenu ) - local FlightMenuFlare = MENU_GROUP:New( self.PlayerGroup, MenuText, FlightMenuReportNavigation ) - - local FlightMenuFlareGreenFlight = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Release green flare", FlightMenuFlare, AI_ESCORT._FlightFlare, self, FLARECOLOR.Green, "Released a green flare!" ) - local FlightMenuFlareRedFlight = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Release red flare", FlightMenuFlare, AI_ESCORT._FlightFlare, self, FLARECOLOR.Red, "Released a red flare!" ) - local FlightMenuFlareWhiteFlight = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Release white flare", FlightMenuFlare, AI_ESCORT._FlightFlare, self, FLARECOLOR.White, "Released a white flare!" ) - local FlightMenuFlareYellowFlight = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Release yellow flare", FlightMenuFlare, AI_ESCORT._FlightFlare, self, FLARECOLOR.Yellow, "Released a yellow flare!" ) - - self.EscortGroupSet:ForSomeGroupAlive( - --- @param Core.Group#GROUP EscortGroup - function( EscortGroup ) - - local EscortGroupName = EscortGroup:GetName() - local EscortMenuReportNavigation = MENU_GROUP:New( self.PlayerGroup, "Navigation", EscortGroup.EscortMenu ) - local EscortMenuFlare = MENU_GROUP:New( self.PlayerGroup, MenuText, EscortMenuReportNavigation ) - - local EscortMenuFlareGreen = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Release green flare", EscortMenuFlare, AI_ESCORT._Flare, self, EscortGroup, FLARECOLOR.Green, "Released a green flare!" ) - local EscortMenuFlareRed = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Release red flare", EscortMenuFlare, AI_ESCORT._Flare, self, EscortGroup, FLARECOLOR.Red, "Released a red flare!" ) - local EscortMenuFlareWhite = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Release white flare", EscortMenuFlare, AI_ESCORT._Flare, self, EscortGroup, FLARECOLOR.White, "Released a white flare!" ) - local EscortMenuFlareYellow = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Release yellow flare", EscortMenuFlare, AI_ESCORT._Flare, self, EscortGroup, FLARECOLOR.Yellow, "Released a yellow flare!" ) - end - ) + self.Menu.Flare = self.Menu.Flare or {} + self.Menu.Flare[#self.Menu.Flare+1] = {} + self.Menu.Flare[#self.Menu.Flare].MenuText = MenuText return self end + +function AI_ESCORT:SetFlightMenuSmoke() + + for _, MenuSmoke in pairs( self.Menu.Smoke) do + local FlightMenuReportNavigation = MENU_GROUP:New( self.PlayerGroup, "Navigation", self.FlightMenu ) + local FlightMenuSmoke = MENU_GROUP:New( self.PlayerGroup, MenuText, FlightMenuReportNavigation ) + + local FlightMenuSmokeGreenFlight = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Release green smoke", FlightMenuSmoke, AI_ESCORT._FlightSmoke, self, SMOKECOLOR.Green, "Releasing green smoke!" ) + local FlightMenuSmokeRedFlight = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Release red smoke", FlightMenuSmoke, AI_ESCORT._FlightSmoke, self, SMOKECOLOR.Red, "Releasing red smoke!" ) + local FlightMenuSmokeWhiteFlight = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Release white smoke", FlightMenuSmoke, AI_ESCORT._FlightSmoke, self, SMOKECOLOR.White, "Releasing white smoke!" ) + local FlightMenuSmokeOrangeFlight = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Release orange smoke", FlightMenuSmoke, AI_ESCORT._FlightSmoke, self, SMOKECOLOR.Orange, "Releasing orange smoke!" ) + local FlightMenuSmokeBlueFlight = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Release blue smoke", FlightMenuSmoke, AI_ESCORT._FlightSmoke, self, SMOKECOLOR.Blue, "Releasing blue smoke!" ) + end + + return self +end + + +function AI_ESCORT:SetEscortMenuSmoke( EscortGroup ) + + for _, MenuSmoke in pairs( self.Menu.Smoke) do + if EscortGroup:IsAir() then + + local EscortGroupName = EscortGroup:GetName() + local EscortMenuReportNavigation = MENU_GROUP:New( self.PlayerGroup, "Navigation", EscortGroup.EscortMenu ) + local EscortMenuSmoke = MENU_GROUP:New( self.PlayerGroup, MenuSmoke.MenuText, EscortMenuReportNavigation ) + + local EscortMenuSmokeGreen = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Release green smoke", EscortMenuSmoke, AI_ESCORT._Smoke, self, EscortGroup, SMOKECOLOR.Green, "Releasing green smoke!" ) + local EscortMenuSmokeRed = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Release red smoke", EscortMenuSmoke, AI_ESCORT._Smoke, self, EscortGroup, SMOKECOLOR.Red, "Releasing red smoke!" ) + local EscortMenuSmokeWhite = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Release white smoke", EscortMenuSmoke, AI_ESCORT._Smoke, self, EscortGroup, SMOKECOLOR.White, "Releasing white smoke!" ) + local EscortMenuSmokeOrange = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Release orange smoke", EscortMenuSmoke, AI_ESCORT._Smoke, self, EscortGroup, SMOKECOLOR.Orange, "Releasing orange smoke!" ) + local EscortMenuSmokeBlue = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Release blue smoke", EscortMenuSmoke, AI_ESCORT._Smoke, self, EscortGroup, SMOKECOLOR.Blue, "Releasing blue smoke!" ) + end + end + + return self +end + + --- Defines a menu slot to let the escort disperse a smoke in a certain color. -- This menu will appear under **Navigation**. -- Note that smoke menu options will only be displayed for ships and ground units. Not for air units. @@ -939,89 +1043,75 @@ function AI_ESCORT:MenuSmoke( MenuTextFormat ) MenuText = MenuTextFormat end - local FlightMenuReportNavigation = MENU_GROUP:New( self.PlayerGroup, "Navigation", self.FlightMenu ) - local FlightMenuSmoke = MENU_GROUP:New( self.PlayerGroup, MenuText, FlightMenuReportNavigation ) - - local FlightMenuSmokeGreenFlight = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Release green smoke", FlightMenuSmoke, AI_ESCORT._FlightSmoke, self, SMOKECOLOR.Green, "Releasing green smoke!" ) - local FlightMenuSmokeRedFlight = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Release red smoke", FlightMenuSmoke, AI_ESCORT._FlightSmoke, self, SMOKECOLOR.Red, "Releasing red smoke!" ) - local FlightMenuSmokeWhiteFlight = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Release white smoke", FlightMenuSmoke, AI_ESCORT._FlightSmoke, self, SMOKECOLOR.White, "Releasing white smoke!" ) - local FlightMenuSmokeOrangeFlight = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Release orange smoke", FlightMenuSmoke, AI_ESCORT._FlightSmoke, self, SMOKECOLOR.Orange, "Releasing orange smoke!" ) - local FlightMenuSmokeBlueFlight = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Release blue smoke", FlightMenuSmoke, AI_ESCORT._FlightSmoke, self, SMOKECOLOR.Blue, "Releasing blue smoke!" ) - - - self.EscortGroupSet:ForSomeGroupAlive( - --- @param Core.Group#GROUP EscortGroup - function( EscortGroup ) - if not EscortGroup:IsAir() then - - local EscortGroupName = EscortGroup:GetName() - local EscortMenuReportNavigation = MENU_GROUP:New( self.PlayerGroup, "Navigation", EscortGroup.EscortMenu ) - local EscortMenuSmoke = MENU_GROUP:New( self.PlayerGroup, MenuText, EscortMenuReportNavigation ) - - local EscortMenuSmokeGreen = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Release green smoke", EscortMenuSmoke, AI_ESCORT._Smoke, self, EscortGroup, SMOKECOLOR.Green, "Releasing green smoke!" ) - local EscortMenuSmokeRed = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Release red smoke", EscortMenuSmoke, AI_ESCORT._Smoke, self, EscortGroup, SMOKECOLOR.Red, "Releasing red smoke!" ) - local EscortMenuSmokeWhite = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Release white smoke", EscortMenuSmoke, AI_ESCORT._Smoke, self, EscortGroup, SMOKECOLOR.White, "Releasing white smoke!" ) - local EscortMenuSmokeOrange = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Release orange smoke", EscortMenuSmoke, AI_ESCORT._Smoke, self, EscortGroup, SMOKECOLOR.Orange, "Releasing orange smoke!" ) - local EscortMenuSmokeBlue = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Release blue smoke", EscortMenuSmoke, AI_ESCORT._Smoke, self, EscortGroup, SMOKECOLOR.Blue, "Releasing blue smoke!" ) - end - end - ) + self.Menu.Smoke = self.Menu.Smoke or {} + self.Menu.Smoke[#self.Menu.Smoke+1] = {} + self.Menu.Smoke[#self.Menu.Smoke].MenuText = MenuText return self end + +function AI_ESCORT:SetFlightMenuTargets() + + for _, MenuTargets in pairs( self.Menu.Targets) do + local FlightMenuReportTargets = MENU_GROUP:New( self.PlayerGroup, "Report targets", self.FlightMenu ) + + -- Report Targets + local FlightMenuReportTargetsNow = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Report targets now!", FlightMenuReportTargets, AI_ESCORT._FlightReportNearbyTargetsNow, self ) + local FlightMenuReportTargetsOn = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Report targets on", FlightMenuReportTargets, AI_ESCORT._FlightSwitchReportNearbyTargets, self, true ) + local FlightMenuReportTargetsOff = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Report targets off", FlightMenuReportTargets, AI_ESCORT._FlightSwitchReportNearbyTargets, self, false ) + + -- Attack Targets + local FlightMenuAttackNearbyTargets = MENU_GROUP:New( self.PlayerGroup, "Attack targets", self.FlightMenu ) + + MenuTargets.FlightReportTargetsScheduler = SCHEDULER:New( self, self._FlightReportTargetsScheduler, {}, MenuTargets.Interval, MenuTargets.Interval ) + end + + return self +end + + +function AI_ESCORT:SetEscortMenuTargets( EscortGroup ) + + for _, MenuTargets in pairs( self.Menu.Targets) do + if EscortGroup:IsAir() then + local EscortGroupName = EscortGroup:GetName() + local EscortMenuReportTargets = MENU_GROUP:New( self.PlayerGroup, "Report targets", EscortGroup.EscortMenu ) + + -- Report Targets + --EscortGroup.EscortMenuReportNearbyTargetsNow = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Report targets now!", EscortGroup.EscortMenuReportNearbyTargets, AI_ESCORT._ReportNearbyTargetsNow, self, EscortGroup, true ) + --EscortGroup.EscortMenuReportNearbyTargetsOn = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Report targets on", EscortGroup.EscortMenuReportNearbyTargets, AI_ESCORT._SwitchReportNearbyTargets, self, EscortGroup, true ) + --EscortGroup.EscortMenuReportNearbyTargetsOff = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Report targets off", EscortGroup.EscortMenuReportNearbyTargets, AI_ESCORT._SwitchReportNearbyTargets, self, EscortGroup, false ) + + -- Attack Targets + local EscortMenuAttackTargets = MENU_GROUP:New( self.PlayerGroup, "Attack targets", EscortGroup.EscortMenu ) + + EscortGroup.ReportTargetsScheduler = SCHEDULER:New( self, self._ReportTargetsScheduler, { EscortGroup }, timer, MenuTargets.Interval ) + end + end + + return self +end + + + --- Defines a menu slot to let the escort report their current detected targets with a specified time interval in seconds. -- This menu will appear under **Report targets**. -- Note that if a report targets menu is not specified, no targets will be detected by the escort, and the attack and assisted attack menus will not be displayed. -- @param #AI_ESCORT self -- @param DCS#Time Seconds Optional parameter that lets the escort report their current detected targets after specified time interval in seconds. The default time is 30 seconds. -- @return #AI_ESCORT -function AI_ESCORT:MenuReportTargets( Seconds ) +function AI_ESCORT:MenuTargets( Seconds ) self:F( { Seconds } ) if not Seconds then Seconds = 30 end - self.FlightMenuReportTargetsInterval = Seconds + self.Menu.Targets = self.Menu.Targets or {} + self.Menu.Targets[#self.Menu.Targets+1] = {} + self.Menu.Targets[#self.Menu.Targets].Interval = Seconds - local timer = 1 - - local FlightMenuReportTargets = MENU_GROUP:New( self.PlayerGroup, "Report targets", self.FlightMenu ) - - -- Report Targets - local FlightMenuReportTargetsNow = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Report targets now!", FlightMenuReportTargets, AI_ESCORT._FlightReportNearbyTargetsNow, self ) - local FlightMenuReportTargetsOn = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Report targets on", FlightMenuReportTargets, AI_ESCORT._FlightSwitchReportNearbyTargets, self, true ) - local FlightMenuReportTargetsOff = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Report targets off", FlightMenuReportTargets, AI_ESCORT._FlightSwitchReportNearbyTargets, self, false ) - - -- Attack Targets - local FlightMenuAttackNearbyTargets = MENU_GROUP:New( self.PlayerGroup, "Attack targets", self.FlightMenu ) - - self.FlightReportTargetsScheduler = SCHEDULER:New( self, self._FlightReportTargetsScheduler, {}, Seconds, Seconds ) - - self.EscortGroupSet:ForSomeGroupAlive( - --- @param Core.Group#GROUP EscortGroup - function( EscortGroup ) - if EscortGroup:IsAir() then - - local EscortGroupName = EscortGroup:GetName() - local EscortMenuReportTargets = MENU_GROUP:New( self.PlayerGroup, "Report targets", EscortGroup.EscortMenu ) - - - -- Report Targets - --EscortGroup.EscortMenuReportNearbyTargetsNow = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Report targets now!", EscortGroup.EscortMenuReportNearbyTargets, AI_ESCORT._ReportNearbyTargetsNow, self, EscortGroup, true ) - --EscortGroup.EscortMenuReportNearbyTargetsOn = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Report targets on", EscortGroup.EscortMenuReportNearbyTargets, AI_ESCORT._SwitchReportNearbyTargets, self, EscortGroup, true ) - --EscortGroup.EscortMenuReportNearbyTargetsOff = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Report targets off", EscortGroup.EscortMenuReportNearbyTargets, AI_ESCORT._SwitchReportNearbyTargets, self, EscortGroup, false ) - - -- Attack Targets - local EscortMenuAttackTargets = MENU_GROUP:New( self.PlayerGroup, "Attack targets", EscortGroup.EscortMenu ) - - EscortGroup.ReportTargetsScheduler = SCHEDULER:New( self, self._ReportTargetsScheduler, { EscortGroup }, timer, Seconds ) - timer=timer+1 - end - end - ) - return self end @@ -1047,49 +1137,108 @@ function AI_ESCORT:MenuAssistedAttack() return self end +function AI_ESCORT:SetFlightMenuROE() + + for _, MenuROE in pairs( self.Menu.ROE) do + local FlightMenuROE = MENU_GROUP:New( self.PlayerGroup, "Rule Of Engagement", self.FlightMenu ) + + local FlightMenuROEHoldFire = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Hold fire", FlightMenuROE, AI_ESCORT._FlightROEHoldFire, self, "Holding weapons!" ) + local FlightMenuROEReturnFire = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Return fire", FlightMenuROE, AI_ESCORT._FlightROEReturnFire, self, "Returning fire!" ) + local FlightMenuROEOpenFire = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Open Fire", FlightMenuROE, AI_ESCORT._FlightROEOpenFire, self, "Open fire at designated targets!" ) + local FlightMenuROEWeaponFree = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Engage all targets", FlightMenuROE, AI_ESCORT._FlightROEWeaponFree, self, "Engaging all targets!" ) + end + + return self +end + + +function AI_ESCORT:SetEscortMenuROE( EscortGroup ) + + for _, MenuROE in pairs( self.Menu.ROE) do + if EscortGroup:IsAir() then + + local EscortGroupName = EscortGroup:GetName() + local EscortMenuROE = MENU_GROUP:New( self.PlayerGroup, "Rule Of Engagement", EscortGroup.EscortMenu ) + + if EscortGroup:OptionROEHoldFirePossible() then + local EscortMenuROEHoldFire = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Hold fire", EscortMenuROE, AI_ESCORT._ROE, self, EscortGroup, EscortGroup.OptionROEHoldFire, "Holding weapons!" ) + end + if EscortGroup:OptionROEReturnFirePossible() then + local EscortMenuROEReturnFire = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Return fire", EscortMenuROE, AI_ESCORT._ROE, self, EscortGroup, EscortGroup.OptionROEReturnFire, "Returning fire!" ) + end + if EscortGroup:OptionROEOpenFirePossible() then + EscortGroup.EscortMenuROEOpenFire = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Open Fire", EscortMenuROE, AI_ESCORT._ROE, self, EscortGroup, EscortGroup.OptionROEOpenFire, "Opening fire on designated targets!!" ) + end + if EscortGroup:OptionROEWeaponFreePossible() then + EscortGroup.EscortMenuROEWeaponFree = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Engage all targets", EscortMenuROE, AI_ESCORT._ROE, self, EscortGroup, EscortGroup.OptionROEWeaponFree, "Opening fire on targets of opportunity!" ) + end + end + end + + return self +end + + --- Defines a menu to let the escort set its rules of engagement. -- All rules of engagement will appear under the menu **ROE**. -- @param #AI_ESCORT self -- @return #AI_ESCORT -function AI_ESCORT:MenuROE( MenuTextFormat ) - self:F( MenuTextFormat ) +function AI_ESCORT:MenuROE() + self:F() - local FlightMenuROE = MENU_GROUP:New( self.PlayerGroup, "Rule Of Engagement", self.FlightMenu ) + self.Menu.ROE = self.Menu.ROE or {} + self.Menu.ROE[#self.Menu.ROE+1] = {} - local FlightMenuROEHoldFire = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Hold fire", FlightMenuROE, AI_ESCORT._FlightROEHoldFire, self, "Holding weapons!" ) - local FlightMenuROEReturnFire = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Return fire", FlightMenuROE, AI_ESCORT._FlightROEReturnFire, self, "Returning fire!" ) - local FlightMenuROEOpenFire = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Open Fire", FlightMenuROE, AI_ESCORT._FlightROEOpenFire, self, "Open fire at designated targets!" ) - local FlightMenuROEWeaponFree = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Engage all targets", FlightMenuROE, AI_ESCORT._FlightROEWeaponFree, self, "Engaging all targets!" ) + return self +end - self.EscortGroupSet:ForSomeGroupAlive( - --- @param Core.Group#GROUP EscortGroup - function( EscortGroup ) - if not EscortGroup.EscortMenuROE then - -- Rules of Engagement - - local EscortGroupName = EscortGroup:GetName() - local EscortMenuROE = MENU_GROUP:New( self.PlayerGroup, "Rule Of Engagement", EscortGroup.EscortMenu ) - - if EscortGroup:OptionROEHoldFirePossible() then - local EscortMenuROEHoldFire = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Hold fire", EscortMenuROE, AI_ESCORT._ROE, self, EscortGroup, EscortGroup.OptionROEHoldFire, "Holding weapons!" ) + +function AI_ESCORT:SetFlightMenuROT() + + for _, MenuROT in pairs( self.Menu.ROT) do + local FlightMenuROT = MENU_GROUP:New( self.PlayerGroup, "Reaction On Threat", self.FlightMenu ) + + local FlightMenuROTNoReaction = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Fight until death", FlightMenuROT, AI_ESCORT._FlightROTNoReaction, self, "Fighting until death!" ) + local FlightMenuROTPassiveDefense = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Use flares, chaff and jammers", FlightMenuROT, AI_ESCORT._FlightROTPassiveDefense, self, "Defending using jammers, chaff and flares!" ) + local FlightMenuROTEvadeFire = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Open fire", FlightMenuROT, AI_ESCORT._FlightROTEvadeFire, self, "Evading on enemy fire!" ) + local FlightMenuROTVertical = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Avoid radar and evade fire", FlightMenuROT, AI_ESCORT._FlightROTVertical, self, "Evading on enemy fire with vertical manoeuvres!" ) + end + + return self +end + + +function AI_ESCORT:SetEscortMenuROT( EscortGroup ) + + for _, MenuROT in pairs( self.Menu.ROT) do + if EscortGroup:IsAir() then + + local EscortGroupName = EscortGroup:GetName() + local EscortMenuROT = MENU_GROUP:New( self.PlayerGroup, "Reaction On Threat", EscortGroup.EscortMenu ) + + if not EscortGroup.EscortMenuEvasion then + -- Reaction to Threats + if EscortGroup:OptionROTNoReactionPossible() then + local EscortMenuEvasionNoReaction = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Fight until death", EscortMenuROT, AI_ESCORT._ROT, self, EscortGroup, EscortGroup.OptionROTNoReaction, "Fighting until death!" ) end - if EscortGroup:OptionROEReturnFirePossible() then - local EscortMenuROEReturnFire = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Return fire", EscortMenuROE, AI_ESCORT._ROE, self, EscortGroup, EscortGroup.OptionROEReturnFire, "Returning fire!" ) + if EscortGroup:OptionROTPassiveDefensePossible() then + local EscortMenuEvasionPassiveDefense = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Use flares, chaff and jammers", EscortMenuROT, AI_ESCORT._ROT, self, EscortGroup, EscortGroup.OptionROTPassiveDefense, "Defending using jammers, chaff and flares!" ) end - if EscortGroup:OptionROEOpenFirePossible() then - EscortGroup.EscortMenuROEOpenFire = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Open Fire", EscortMenuROE, AI_ESCORT._ROE, self, EscortGroup, EscortGroup.OptionROEOpenFire, "Opening fire on designated targets!!" ) + if EscortGroup:OptionROTEvadeFirePossible() then + local EscortMenuEvasionEvadeFire = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Open fire", EscortMenuROT, AI_ESCORT._ROT, self, EscortGroup, EscortGroup.OptionROTEvadeFire, "Evading on enemy fire!" ) end - if EscortGroup:OptionROEWeaponFreePossible() then - EscortGroup.EscortMenuROEWeaponFree = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Engage all targets", EscortMenuROE, AI_ESCORT._ROE, self, EscortGroup, EscortGroup.OptionROEWeaponFree, "Opening fire on targets of opportunity!" ) + if EscortGroup:OptionROTVerticalPossible() then + local EscortMenuOptionEvasionVertical = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Avoid radar and evade fire", EscortMenuROT, AI_ESCORT._ROT, self, EscortGroup, EscortGroup.OptionROTVertical, "Evading on enemy fire with vertical manoeuvres!" ) end end end - ) - + end + return self end + --- Defines a menu to let the escort set its evasion when under threat. -- All rules of engagement will appear under the menu **Evasion**. -- @param #AI_ESCORT self @@ -1097,39 +1246,8 @@ end function AI_ESCORT:MenuROT( MenuTextFormat ) self:F( MenuTextFormat ) - local FlightMenuROT = MENU_GROUP:New( self.PlayerGroup, "Reaction On Threat", self.FlightMenu ) - - local FlightMenuROTNoReaction = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Fight until death", FlightMenuROT, AI_ESCORT._FlightROTNoReaction, self, "Fighting until death!" ) - local FlightMenuROTPassiveDefense = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Use flares, chaff and jammers", FlightMenuROT, AI_ESCORT._FlightROTPassiveDefense, self, "Defending using jammers, chaff and flares!" ) - local FlightMenuROTEvadeFire = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Open fire", FlightMenuROT, AI_ESCORT._FlightROTEvadeFire, self, "Evading on enemy fire!" ) - local FlightMenuROTVertical = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Avoid radar and evade fire", FlightMenuROT, AI_ESCORT._FlightROTVertical, self, "Evading on enemy fire with vertical manoeuvres!" ) - - self.EscortGroupSet:ForSomeGroupAlive( - --- @param Core.Group#GROUP EscortGroup - function( EscortGroup ) - if EscortGroup:IsAir() then - - local EscortGroupName = EscortGroup:GetName() - local EscortMenuROT = MENU_GROUP:New( self.PlayerGroup, "Reaction On Threat", EscortGroup.EscortMenu ) - - if not EscortGroup.EscortMenuEvasion then - -- Reaction to Threats - if EscortGroup:OptionROTNoReactionPossible() then - local EscortMenuEvasionNoReaction = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Fight until death", EscortMenuROT, AI_ESCORT._ROT, self, EscortGroup, EscortGroup.OptionROTNoReaction, "Fighting until death!" ) - end - if EscortGroup:OptionROTPassiveDefensePossible() then - local EscortMenuEvasionPassiveDefense = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Use flares, chaff and jammers", EscortMenuROT, AI_ESCORT._ROT, self, EscortGroup, EscortGroup.OptionROTPassiveDefense, "Defending using jammers, chaff and flares!" ) - end - if EscortGroup:OptionROTEvadeFirePossible() then - local EscortMenuEvasionEvadeFire = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Open fire", EscortMenuROT, AI_ESCORT._ROT, self, EscortGroup, EscortGroup.OptionROTEvadeFire, "Evading on enemy fire!" ) - end - if EscortGroup:OptionROTVerticalPossible() then - local EscortMenuOptionEvasionVertical = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Avoid radar and evade fire", EscortMenuROT, AI_ESCORT._ROT, self, EscortGroup, EscortGroup.OptionROTVertical, "Evading on enemy fire with vertical manoeuvres!" ) - end - end - end - end - ) + self.Menu.ROT = self.Menu.ROT or {} + self.Menu.ROT[#self.Menu.ROT+1] = {} return self end From 6a1bf507003a6692a42bbcde3dd505019d935f65 Mon Sep 17 00:00:00 2001 From: FlightControl Date: Mon, 17 Jun 2019 10:19:15 +0300 Subject: [PATCH 21/25] Updated --- Moose Development/Moose/AI/AI_Escort.lua | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Moose Development/Moose/AI/AI_Escort.lua b/Moose Development/Moose/AI/AI_Escort.lua index b81ebbb02..408ab2be8 100644 --- a/Moose Development/Moose/AI/AI_Escort.lua +++ b/Moose Development/Moose/AI/AI_Escort.lua @@ -405,7 +405,7 @@ function AI_ESCORT:MenusHelicopter( XStart, XSpace, YStart, YSpace, ZStart, ZSpa self:MenuFlare() self:MenuSmoke() - self:MenuReportTargets( 60 ) + self:MenuTargets( 60 ) self:MenuAssistedAttack() self:MenuROE() self:MenuROT() @@ -456,7 +456,7 @@ function AI_ESCORT:MenusAirplanes( XStart, XSpace, YStart, YSpace, ZStart, ZSpac self:MenuFlare() self:MenuSmoke() - self:MenuReportTargets( 60 ) + self:MenuTargets( 60 ) self:MenuAssistedAttack() self:MenuROE() self:MenuROT() @@ -501,7 +501,7 @@ function AI_ESCORT:MenuFormation( Formation, ... ) local FormationID = "Formation"..Formation self.Menu[FormationID] = self.Menu[FormationID] or {} self.Menu[FormationID][#self.Menu[FormationID]+1] = {} - self.Menu[FormationID][#self.Menu[FormationID]+1].Arguments = ... + self.Menu[FormationID][#self.Menu[FormationID]].Arguments = ... end @@ -932,7 +932,7 @@ function AI_ESCORT:SetFlightMenuFlare() for _, MenuFlare in pairs( self.Menu.Flare) do local FlightMenuReportNavigation = MENU_GROUP:New( self.PlayerGroup, "Navigation", self.FlightMenu ) - local FlightMenuFlare = MENU_GROUP:New( self.PlayerGroup, MenuText, FlightMenuReportNavigation ) + local FlightMenuFlare = MENU_GROUP:New( self.PlayerGroup, MenuFlare.MenuText, FlightMenuReportNavigation ) local FlightMenuFlareGreenFlight = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Release green flare", FlightMenuFlare, AI_ESCORT._FlightFlare, self, FLARECOLOR.Green, "Released a green flare!" ) local FlightMenuFlareRedFlight = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Release red flare", FlightMenuFlare, AI_ESCORT._FlightFlare, self, FLARECOLOR.Red, "Released a red flare!" ) @@ -992,7 +992,7 @@ function AI_ESCORT:SetFlightMenuSmoke() for _, MenuSmoke in pairs( self.Menu.Smoke) do local FlightMenuReportNavigation = MENU_GROUP:New( self.PlayerGroup, "Navigation", self.FlightMenu ) - local FlightMenuSmoke = MENU_GROUP:New( self.PlayerGroup, MenuText, FlightMenuReportNavigation ) + local FlightMenuSmoke = MENU_GROUP:New( self.PlayerGroup, MenuSmoke.MenuText, FlightMenuReportNavigation ) local FlightMenuSmokeGreenFlight = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Release green smoke", FlightMenuSmoke, AI_ESCORT._FlightSmoke, self, SMOKECOLOR.Green, "Releasing green smoke!" ) local FlightMenuSmokeRedFlight = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Release red smoke", FlightMenuSmoke, AI_ESCORT._FlightSmoke, self, SMOKECOLOR.Red, "Releasing red smoke!" ) @@ -1086,7 +1086,7 @@ function AI_ESCORT:SetEscortMenuTargets( EscortGroup ) -- Attack Targets local EscortMenuAttackTargets = MENU_GROUP:New( self.PlayerGroup, "Attack targets", EscortGroup.EscortMenu ) - EscortGroup.ReportTargetsScheduler = SCHEDULER:New( self, self._ReportTargetsScheduler, { EscortGroup }, timer, MenuTargets.Interval ) + EscortGroup.ReportTargetsScheduler = SCHEDULER:New( self, self._ReportTargetsScheduler, { EscortGroup }, 1, MenuTargets.Interval ) end end @@ -1117,7 +1117,7 @@ end --- Defines a menu slot to let the escort attack its detected targets using assisted attack from another escort joined also with the client. -- This menu will appear under **Request assistance from**. --- Note that this method needs to be preceded with the method MenuReportTargets. +-- Note that this method needs to be preceded with the method MenuTargets. -- @param #AI_ESCORT self -- @return #AI_ESCORT function AI_ESCORT:MenuAssistedAttack() From 9c523cad5224405007b3f95b083b88d513c96aa2 Mon Sep 17 00:00:00 2001 From: FlightControl Date: Mon, 17 Jun 2019 20:25:50 +0300 Subject: [PATCH 22/25] Updates --- Moose Development/Moose/AI/AI_Escort.lua | 151 +++++++++++--------- Moose Development/Moose/AI/AI_Formation.lua | 32 +++++ 2 files changed, 112 insertions(+), 71 deletions(-) diff --git a/Moose Development/Moose/AI/AI_Escort.lua b/Moose Development/Moose/AI/AI_Escort.lua index 408ab2be8..3dc05027a 100644 --- a/Moose Development/Moose/AI/AI_Escort.lua +++ b/Moose Development/Moose/AI/AI_Escort.lua @@ -223,9 +223,11 @@ function AI_ESCORT:New( EscortUnit, EscortGroupSet, EscortName, EscortBriefing ) self.PlayerUnit = self.FollowUnit -- Wrapper.Unit#UNIT self.PlayerGroup = self.FollowUnit:GetGroup() -- Wrapper.Group#GROUP + self.EscortName = EscortName + self.EscortGroupSet = EscortGroupSet - self.EscortGroupSet:SetSomeIteratorLimit( 5 ) + self.EscortGroupSet:SetSomeIteratorLimit( 8 ) self.EscortBriefing = EscortBriefing @@ -248,14 +250,9 @@ function AI_ESCORT:New( EscortUnit, EscortGroupSet, EscortName, EscortBriefing ) self.GT1 = 0 - self.MainMenu = MENU_GROUP:New( self.PlayerGroup, EscortName ) - self.FlightMenu = MENU_GROUP:New( self.PlayerGroup, "Flight", self.MainMenu ) - EscortGroupSet:ForEachGroup( --- @param Core.Group#GROUP EscortGroup function( EscortGroup ) - EscortGroup.EscortMenu = MENU_GROUP:New( self.PlayerGroup, EscortGroup:GetName(), self.MainMenu ) - -- Set EscortGroup known at EscortUnit. if not self.PlayerUnit._EscortGroups then self.PlayerUnit._EscortGroups = {} @@ -280,7 +277,6 @@ function AI_ESCORT:onafterStart( EscortGroupSet ) EscortGroupSet:ForEachGroup( --- @param Core.Group#GROUP EscortGroup function( EscortGroup ) - EscortGroup.EscortMenu = MENU_GROUP:New( self.PlayerGroup, EscortGroup:GetName(), self.MainMenu ) EscortGroup:WayPointInitialize() EscortGroup:OptionROTVertical() @@ -302,6 +298,10 @@ function AI_ESCORT:onafterStart( EscortGroupSet ) self:HandleEvent( EVENTS.Dead, OnEventDeadOrCrash ) self:HandleEvent( EVENTS.Crash, OnEventDeadOrCrash ) + self.MainMenu = MENU_GROUP:New( self.PlayerGroup, self.EscortName ) + self.FlightMenu = MENU_GROUP:New( self.PlayerGroup, "Flight", self.MainMenu ) + + self:SetFlightMenuJoinUp() self:SetFlightMenuFormation( "Trail" ) self:SetFlightMenuFormation( "Stack" ) self:SetFlightMenuFormation( "LeftLine" ) @@ -325,6 +325,12 @@ function AI_ESCORT:onafterStart( EscortGroupSet ) self.EscortGroupSet:ForSomeGroupAlive( --- @param Core.Group#GROUP EscortGroup function( EscortGroup ) + + EscortGroup.EscortMenu = MENU_GROUP:New( self.PlayerGroup, EscortGroup:GetCallsign(), self.MainMenu ) + + self:SetEscortMenuJoinUp( EscortGroup ) + self:SetEscortMenuResumeMission( EscortGroup ) + self:SetEscortMenuHoldAtEscortPosition( EscortGroup ) self:SetEscortMenuHoldAtLeaderPosition( EscortGroup ) @@ -335,10 +341,10 @@ function AI_ESCORT:onafterStart( EscortGroupSet ) self:SetEscortMenuROT( EscortGroup ) self:SetEscortMenuTargets( EscortGroup ) + end ) - end --- Set a Detection method for the EscortUnit to be reported upon. @@ -379,13 +385,13 @@ function AI_ESCORT:MenusHelicopter( XStart, XSpace, YStart, YSpace, ZStart, ZSpa -- self:MenuScanForTargets( 100, 60 ) - self.XStart = XStart or self.XStart - self.XSpace = XSpace or self.XSpace - self.YStart = YStart or self.YStart - self.YSpace = YSpace or self.YSpace - self.ZStart = ZStart or self.ZStart - self.ZSpace = ZSpace or self.ZSpace - self.ZLevels = ZLevels or self.ZLevels + self.XStart = XStart or 50 + self.XSpace = XSpace or 50 + self.YStart = YStart or 50 + self.YSpace = YSpace or 50 + self.ZStart = ZStart or 50 + self.ZSpace = ZSpace or 50 + self.ZLevels = ZLevels or 10 self:MenuJoinUp() self:MenuFormationTrail(self.XStart,self.XSpace,self.YStart) @@ -410,9 +416,6 @@ function AI_ESCORT:MenusHelicopter( XStart, XSpace, YStart, YSpace, ZStart, ZSpa self:MenuROE() self:MenuROT() - self:MenuResumeMission() - - return self end @@ -432,13 +435,13 @@ function AI_ESCORT:MenusAirplanes( XStart, XSpace, YStart, YSpace, ZStart, ZSpac -- self:MenuScanForTargets( 100, 60 ) - self.XStart = XStart or self.XStart - self.XSpace = XSpace or self.XSpace - self.YStart = YStart or self.YStart - self.YSpace = YSpace or self.YSpace - self.ZStart = ZStart or self.ZStart - self.ZSpace = ZSpace or self.ZSpace - self.ZLevels = ZLevels or self.ZLevels + self.XStart = XStart or 50 + self.XSpace = XSpace or 50 + self.YStart = YStart or 50 + self.YSpace = YSpace or 50 + self.ZStart = ZStart or 50 + self.ZSpace = ZSpace or 50 + self.ZLevels = ZLevels or 10 self:MenuJoinUp() self:MenuFormationTrail(self.XStart,self.XSpace,self.YStart) @@ -461,9 +464,6 @@ function AI_ESCORT:MenusAirplanes( XStart, XSpace, YStart, YSpace, ZStart, ZSpac self:MenuROE() self:MenuROT() - self:MenuResumeMission() - - return self end @@ -476,17 +476,18 @@ function AI_ESCORT:SetFlightMenuFormation( Formation ) if MenuFormation then local Arguments = MenuFormation.Arguments + self:I({Arguments=unpack(Arguments)}) local FlightMenuFormation = MENU_GROUP:New( self.PlayerGroup, "Formation", self.MainMenu ) local MenuFlightFormationID = MENU_GROUP_COMMAND:New( self.PlayerGroup, Formation, FlightMenuFormation, function ( self, Formation, ... ) self.EscortGroupSet:ForSomeGroupAlive( --- @param Core.Group#GROUP EscortGroup - function( EscortGroup, self, Formation, ... ) + function( EscortGroup, self, Formation, Arguments ) if EscortGroup:IsAir() then self:E({FormationID=FormationID}) - self[FormationID]( self, ... ) + self[FormationID]( self, unpack(Arguments) ) end - end, self, Formation, ... + end, self, Formation, Arguments ) end, self, Formation, Arguments ) @@ -500,8 +501,7 @@ function AI_ESCORT:MenuFormation( Formation, ... ) local FormationID = "Formation"..Formation self.Menu[FormationID] = self.Menu[FormationID] or {} - self.Menu[FormationID][#self.Menu[FormationID]+1] = {} - self.Menu[FormationID][#self.Menu[FormationID]].Arguments = ... + self.Menu[FormationID].Arguments = arg end @@ -656,11 +656,20 @@ function AI_ESCORT:MenuFormationBox( XStart, XSpace, YStart, YSpace, ZStart, ZSp return self end +function AI_ESCORT:SetFlightMenuJoinUp() + + if self.Menu.JoinUp == true then + local FlightMenuReportNavigation = MENU_GROUP:New( self.PlayerGroup, "Navigation", self.FlightMenu ) + local FlightMenuJoinUp = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Join Up", FlightMenuReportNavigation, AI_ESCORT._FlightJoinUp, self ) + end + +end + --- Sets a menu slot to join formation for an escort. -- @param #AI_ESCORT self -- @return #AI_ESCORT -function AI_ESCORT:EscortMenuJoinUp( EscortGroup ) +function AI_ESCORT:SetEscortMenuJoinUp( EscortGroup ) if self.Menu.JoinUp == true then if EscortGroup:IsAir() then @@ -679,16 +688,6 @@ function AI_ESCORT:MenuJoinUp() self.Menu.JoinUp = true - local FlightMenuReportNavigation = MENU_GROUP:New( self.PlayerGroup, "Navigation", self.FlightMenu ) - local FlightMenuJoinUp = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Join Up", FlightMenuReportNavigation, AI_ESCORT._FlightJoinUp, self ) - - self.EscortGroupSet:ForSomeGroupAlive( - --- @param Core.Group#GROUP EscortGroup - function( EscortGroup ) - self:EscortMenuJoinUp( EscortGroup ) - end - ) - return self end @@ -1079,14 +1078,14 @@ function AI_ESCORT:SetEscortMenuTargets( EscortGroup ) local EscortMenuReportTargets = MENU_GROUP:New( self.PlayerGroup, "Report targets", EscortGroup.EscortMenu ) -- Report Targets - --EscortGroup.EscortMenuReportNearbyTargetsNow = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Report targets now!", EscortGroup.EscortMenuReportNearbyTargets, AI_ESCORT._ReportNearbyTargetsNow, self, EscortGroup, true ) + EscortGroup.EscortMenuReportNearbyTargetsNow = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Report targets now!", EscortMenuReportTargets, AI_ESCORT._ReportNearbyTargetsNow, self, EscortGroup, true ) --EscortGroup.EscortMenuReportNearbyTargetsOn = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Report targets on", EscortGroup.EscortMenuReportNearbyTargets, AI_ESCORT._SwitchReportNearbyTargets, self, EscortGroup, true ) --EscortGroup.EscortMenuReportNearbyTargetsOff = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Report targets off", EscortGroup.EscortMenuReportNearbyTargets, AI_ESCORT._SwitchReportNearbyTargets, self, EscortGroup, false ) -- Attack Targets local EscortMenuAttackTargets = MENU_GROUP:New( self.PlayerGroup, "Attack targets", EscortGroup.EscortMenu ) - EscortGroup.ReportTargetsScheduler = SCHEDULER:New( self, self._ReportTargetsScheduler, { EscortGroup }, 1, MenuTargets.Interval ) + --EscortGroup.ReportTargetsScheduler = SCHEDULER:New( self, self._ReportTargetsScheduler, { EscortGroup }, 1, MenuTargets.Interval ) end end @@ -1256,18 +1255,13 @@ end -- All rules of engagement will appear under the menu **Resume mission from**. -- @param #AI_ESCORT self -- @return #AI_ESCORT -function AI_ESCORT:MenuResumeMission() +function AI_ESCORT:SetEscortMenuResumeMission( EscortGroup ) self:F() - self.EscortGroupSet:ForSomeGroupAlive( - --- @param Core.Group#GROUP EscortGroup - function( EscortGroup ) - if EscortGroup:IsAir() then - local EscortGroupName = EscortGroup:GetName() - EscortGroup.EscortMenuResumeMission = MENU_GROUP:New( self.PlayerGroup, "Resume from", EscortGroup.EscortMenu ) - end - end - ) + if EscortGroup:IsAir() then + local EscortGroupName = EscortGroup:GetName() + EscortGroup.EscortMenuResumeMission = MENU_GROUP:New( self.PlayerGroup, "Resume from", EscortGroup.EscortMenu ) + end return self end @@ -1346,8 +1340,6 @@ function AI_ESCORT:_JoinUp( EscortGroup ) local EscortUnit = self.PlayerUnit self:ModeFormation( EscortGroup ) - - EscortGroup:SetState( self, "Mode", self.__Enum.Mode.Follow ) end @@ -1549,7 +1541,16 @@ function AI_ESCORT.___Resume( EscortGroup, self ) local PlayerGroup = self.PlayerGroup - EscortGroup:MessageTypeToGroup( "Destroyed all targets. Rejoining.", MESSAGE.Type.Information, PlayerGroup ) + EscortGroup:OptionROEHoldFire() + EscortGroup:OptionROTVertical() + + EscortGroup:SetState( EscortGroup, "Mode", EscortGroup:GetState( EscortGroup, "PreviousMode" ) ) + + if EscortGroup:GetState( EscortGroup, "Mode" ) == self.__Enum.Mode.Mission then + EscortGroup:MessageTypeToGroup( "Destroyed all targets. Resuming route.", MESSAGE.Type.Information, PlayerGroup ) + else + EscortGroup:MessageTypeToGroup( "Destroyed all targets. Rejoining formation.", MESSAGE.Type.Information, PlayerGroup ) + end end @@ -1583,7 +1584,7 @@ function AI_ESCORT:_AttackTarget( EscortGroup, DetectedItem ) local EscortUnit = self.PlayerUnit - self:ModeMission( EscortGroup ) + self:ModeAttack( EscortGroup ) if EscortGroup:IsAir() then EscortGroup:OptionROEOpenFire() @@ -1607,7 +1608,7 @@ function AI_ESCORT:_AttackTarget( EscortGroup, DetectedItem ) Tasks[#Tasks+1] = EscortGroup:TaskCombo( AttackUnitTasks ) Tasks[#Tasks+1] = EscortGroup:TaskFunction( "AI_ESCORT.___Resume", self ) - EscortGroup:SetTask( + EscortGroup:PushTask( EscortGroup:TaskCombo( Tasks ), 1 @@ -1628,7 +1629,7 @@ function AI_ESCORT:_AttackTarget( EscortGroup, DetectedItem ) end, Tasks ) - EscortGroup:SetTask( + EscortGroup:PushTask( EscortGroup:TaskCombo( Tasks ), 1 @@ -1797,9 +1798,10 @@ function AI_ESCORT:_ReportTargetsScheduler( EscortGroup ) if EscortGroup:IsAlive() and self.PlayerUnit:IsAlive() then - if true then - local EscortGroupName = EscortGroup:GetName() + local EscortGroupName = EscortGroup:GetCallsign() + + local DetectedTargetsReport = REPORT:New( "Reporting target locations from my position:\n" ) -- A new report to display the detected targets as a message to the player. if EscortGroup.EscortMenuTargetAssistance then @@ -1812,14 +1814,17 @@ function AI_ESCORT:_ReportTargetsScheduler( EscortGroup ) local TimeUpdate = timer.getTime() - local EscortGroupName = EscortGroup:GetName() local EscortMenuAttackTargets = MENU_GROUP:New( self.PlayerGroup, "Attack targets", EscortGroup.EscortMenu ) - + + local DetectedTargets = false for DetectedItemIndex, DetectedItem in pairs( DetectedItems ) do + DetectedTargets = true - local DetectedItemReportSummary = self.Detection:DetectedItemReportMenu( DetectedItem, EscortGroup, _DATABASE:GetPlayerSettings( self.PlayerUnit:GetPlayerName() ) ) + local DetectedMenu = self.Detection:DetectedItemReportMenu( DetectedItem, EscortGroup, _DATABASE:GetPlayerSettings( self.PlayerUnit:GetPlayerName() ) ):Text("\n") - local DetectedMenu = DetectedItemReportSummary:Text("\n") + local DetectedItemReportSummary = self.Detection:DetectedItemReportSummary( DetectedItem, EscortGroup, _DATABASE:GetPlayerSettings( self.PlayerUnit:GetPlayerName() ) ) + local ReportSummary = DetectedItemReportSummary:Text(", ") + DetectedTargetsReport:AddIndent( ReportSummary, "-" ) if EscortGroup:IsAir() then @@ -1850,6 +1855,12 @@ function AI_ESCORT:_ReportTargetsScheduler( EscortGroup ) EscortMenuAttackTargets:RemoveSubMenus( TimeUpdate, "Esort" ) + if DetectedTargets then + EscortGroup:MessageTypeToGroup( DetectedTargetsReport:Text( "\n" ), MESSAGE.Type.Information, self.PlayerGroup ) + else + EscortGroup:MessageTypeToGroup( "No targets detected.", MESSAGE.Type.Information, self.PlayerGroup ) + end + if EscortGroup.EscortMenuResumeMission then EscortGroup.EscortMenuResumeMission:RemoveSubMenus() @@ -1865,8 +1876,6 @@ function AI_ESCORT:_ReportTargetsScheduler( EscortGroup ) end return true - else - end end return false @@ -1881,7 +1890,7 @@ function AI_ESCORT:_FlightReportTargetsScheduler() local EscortGroup = self.EscortGroupSet:GetFirst() -- Wrapper.Group#GROUP - local DetectedTargetsReport = REPORT:New( "Reporting detected targets:\n" ) -- A new report to display the detected targets as a message to the player. + local DetectedTargetsReport = REPORT:New( "Reporting target locations from your position:\n" ) -- A new report to display the detected targets as a message to the player. if EscortGroup and ( self.PlayerUnit:IsAlive() and EscortGroup:IsAlive() ) then diff --git a/Moose Development/Moose/AI/AI_Formation.lua b/Moose Development/Moose/AI/AI_Formation.lua index 31930c045..dbed463b1 100644 --- a/Moose Development/Moose/AI/AI_Formation.lua +++ b/Moose Development/Moose/AI/AI_Formation.lua @@ -143,6 +143,8 @@ AI_FORMATION.__Enum.Formation = { AI_FORMATION.__Enum.Mode = { Mission = 0, Formation = 1, + Attack = 2, + Reconnaissance = 3, } @@ -958,11 +960,13 @@ end function AI_FORMATION:ModeMission( FollowGroup ) if FollowGroup then + FollowGroup:SetState( FollowGroup, "PreviousMode", FollowGroup:GetState( FollowGroup, "Mode" ) ) FollowGroup:SetState( FollowGroup, "Mode", self.__Enum.Mode.Mission ) else self.EscortGroupSet:ForSomeGroupAlive( --- @param Core.Group#GROUP EscortGroup function( FollowGroup ) + FollowGroup:SetState( FollowGroup, "PreviousMode", FollowGroup:GetState( FollowGroup, "Mode" ) ) FollowGroup:SetState( FollowGroup, "Mode", self.__Enum.Mode.Mission ) end ) @@ -973,6 +977,30 @@ function AI_FORMATION:ModeMission( FollowGroup ) end +--- This sets your escorts to execute an attack. +-- @param #AI_FORMATION self +-- @param Wrapper.Group#GROUP FollowGroup FollowGroup. +-- @return #AI_FORMATION +function AI_FORMATION:ModeAttack( FollowGroup ) + + if FollowGroup then + FollowGroup:SetState( FollowGroup, "PreviousMode", FollowGroup:GetState( FollowGroup, "Mode" ) ) + FollowGroup:SetState( FollowGroup, "Mode", self.__Enum.Mode.Attack ) + else + self.EscortGroupSet:ForSomeGroupAlive( + --- @param Core.Group#GROUP EscortGroup + function( FollowGroup ) + FollowGroup:SetState( FollowGroup, "PreviousMode", FollowGroup:GetState( FollowGroup, "Mode" ) ) + FollowGroup:SetState( FollowGroup, "Mode", self.__Enum.Mode.Attack ) + end + ) + end + + + return self +end + + --- This sets your escorts to fly in a formation. -- @param #AI_FORMATION self -- @param Wrapper.Group#GROUP FollowGroup FollowGroup. @@ -980,11 +1008,13 @@ end function AI_FORMATION:ModeFormation( FollowGroup ) if FollowGroup then + FollowGroup:SetState( FollowGroup, "PreviousMode", FollowGroup:GetState( FollowGroup, "Mode" ) ) FollowGroup:SetState( FollowGroup, "Mode", self.__Enum.Mode.Formation ) else self.EscortGroupSet:ForSomeGroupAlive( --- @param Core.Group#GROUP EscortGroup function( FollowGroup ) + FollowGroup:SetState( FollowGroup, "PreviousMode", FollowGroup:GetState( FollowGroup, "Mode" ) ) FollowGroup:SetState( FollowGroup, "Mode", self.__Enum.Mode.Formation ) end ) @@ -1047,6 +1077,8 @@ function AI_FORMATION:onenterFollowing( FollowGroupSet ) --R2.1 -- @param Wrapper.Unit#UNIT ClientUnit function( FollowGroup, Formation, ClientUnit, CT1, CV1, CT2, CV2 ) + self:I({Mode=FollowGroup:GetState( FollowGroup, "Mode" )}) + if FollowGroup:GetState( FollowGroup, "Mode" ) == self.__Enum.Mode.Formation then FollowGroup:OptionROTEvadeFire() From 1e0e67c13d60dbeb7de3b4ba8de6658bc2776f27 Mon Sep 17 00:00:00 2001 From: FlightControl Date: Tue, 18 Jun 2019 07:06:00 +0300 Subject: [PATCH 23/25] Updates --- Moose Development/Moose/AI/AI_Escort.lua | 157 +++++++++++------- .../Moose/AI/AI_Escort_Request.lua | 32 ++-- Moose Development/Moose/Core/Spawn.lua | 13 ++ 3 files changed, 121 insertions(+), 81 deletions(-) diff --git a/Moose Development/Moose/AI/AI_Escort.lua b/Moose Development/Moose/AI/AI_Escort.lua index 3dc05027a..c10d6cbee 100644 --- a/Moose Development/Moose/AI/AI_Escort.lua +++ b/Moose Development/Moose/AI/AI_Escort.lua @@ -270,36 +270,8 @@ function AI_ESCORT:New( EscortUnit, EscortGroupSet, EscortName, EscortBriefing ) return self end ---- @param #AI_ESCORT self --- @param Core.Set#SET_GROUP EscortGroupSet -function AI_ESCORT:onafterStart( EscortGroupSet ) - EscortGroupSet:ForEachGroup( - --- @param Core.Group#GROUP EscortGroup - function( EscortGroup ) - EscortGroup:WayPointInitialize() - - EscortGroup:OptionROTVertical() - EscortGroup:OptionROEOpenFire() - end - ) - - local LeaderEscort = EscortGroupSet:GetFirst() -- Wrapper.Group#GROUP - - local Report = REPORT:New( "Escort reporting:" ) - Report:Add( "Joining Up " .. EscortGroupSet:GetUnitTypeNames():Text( ", " ) .. " from " .. LeaderEscort:GetCoordinate():ToString( self.PlayerUnit ) ) - - LeaderEscort:MessageTypeToGroup( Report:Text(), MESSAGE.Type.Information, self.PlayerUnit ) - - self.Detection = DETECTION_AREAS:New( EscortGroupSet, 5000 ) - - self.Detection:__Start( 30 ) - - self:HandleEvent( EVENTS.Dead, OnEventDeadOrCrash ) - self:HandleEvent( EVENTS.Crash, OnEventDeadOrCrash ) - - self.MainMenu = MENU_GROUP:New( self.PlayerGroup, self.EscortName ) - self.FlightMenu = MENU_GROUP:New( self.PlayerGroup, "Flight", self.MainMenu ) +function AI_ESCORT:_InitFlightMenus() self:SetFlightMenuJoinUp() self:SetFlightMenuFormation( "Trail" ) @@ -322,25 +294,77 @@ function AI_ESCORT:onafterStart( EscortGroupSet ) self:SetFlightMenuTargets() +end + +function AI_ESCORT:_InitEscortMenus( EscortGroup ) + + EscortGroup.EscortMenu = MENU_GROUP:New( self.PlayerGroup, EscortGroup:GetCallsign(), self.MainMenu ) + + self:SetEscortMenuJoinUp( EscortGroup ) + self:SetEscortMenuResumeMission( EscortGroup ) + + self:SetEscortMenuHoldAtEscortPosition( EscortGroup ) + self:SetEscortMenuHoldAtLeaderPosition( EscortGroup ) + + self:SetEscortMenuFlare( EscortGroup ) + self:SetEscortMenuSmoke( EscortGroup ) + + self:SetEscortMenuROE( EscortGroup ) + self:SetEscortMenuROT( EscortGroup ) + + self:SetEscortMenuTargets( EscortGroup ) + +end + +function AI_ESCORT:_InitEscortRoute( EscortGroup ) + + EscortGroup.MissionRoute = EscortGroup:GetTaskRoute() + +end + + +--- @param #AI_ESCORT self +-- @param Core.Set#SET_GROUP EscortGroupSet +function AI_ESCORT:onafterStart( EscortGroupSet ) + + self:F() + + EscortGroupSet:ForEachGroup( + --- @param Core.Group#GROUP EscortGroup + function( EscortGroup ) + EscortGroup:WayPointInitialize() + + EscortGroup:OptionROTVertical() + EscortGroup:OptionROEOpenFire() + end + ) + + -- TODO:Revise this... + local LeaderEscort = EscortGroupSet:GetFirst() -- Wrapper.Group#GROUP + if LeaderEscort then + local Report = REPORT:New( "Escort reporting:" ) + Report:Add( "Joining Up " .. EscortGroupSet:GetUnitTypeNames():Text( ", " ) .. " from " .. LeaderEscort:GetCoordinate():ToString( self.PlayerUnit ) ) + LeaderEscort:MessageTypeToGroup( Report:Text(), MESSAGE.Type.Information, self.PlayerUnit ) + end + + self.Detection = DETECTION_AREAS:New( EscortGroupSet, 5000 ) + + self.Detection:__Start( 30 ) + + self:HandleEvent( EVENTS.Dead, OnEventDeadOrCrash ) + self:HandleEvent( EVENTS.Crash, OnEventDeadOrCrash ) + + self.MainMenu = MENU_GROUP:New( self.PlayerGroup, self.EscortName ) + self.FlightMenu = MENU_GROUP:New( self.PlayerGroup, "Flight", self.MainMenu ) + + self:_InitFlightMenus() + self.EscortGroupSet:ForSomeGroupAlive( --- @param Core.Group#GROUP EscortGroup function( EscortGroup ) - EscortGroup.EscortMenu = MENU_GROUP:New( self.PlayerGroup, EscortGroup:GetCallsign(), self.MainMenu ) - - self:SetEscortMenuJoinUp( EscortGroup ) - self:SetEscortMenuResumeMission( EscortGroup ) - - self:SetEscortMenuHoldAtEscortPosition( EscortGroup ) - self:SetEscortMenuHoldAtLeaderPosition( EscortGroup ) - - self:SetEscortMenuFlare( EscortGroup ) - self:SetEscortMenuSmoke( EscortGroup ) - - self:SetEscortMenuROE( EscortGroup ) - self:SetEscortMenuROT( EscortGroup ) - - self:SetEscortMenuTargets( EscortGroup ) + self:_InitEscortMenus( EscortGroup ) + self:_InitEscortRoute( EscortGroup ) end ) @@ -1086,6 +1110,7 @@ function AI_ESCORT:SetEscortMenuTargets( EscortGroup ) local EscortMenuAttackTargets = MENU_GROUP:New( self.PlayerGroup, "Attack targets", EscortGroup.EscortMenu ) --EscortGroup.ReportTargetsScheduler = SCHEDULER:New( self, self._ReportTargetsScheduler, { EscortGroup }, 1, MenuTargets.Interval ) + EscortGroup.ResumeScheduler = SCHEDULER:New( self, self._ResumeScheduler, { EscortGroup }, 1, 60 ) end end @@ -1561,8 +1586,10 @@ end function AI_ESCORT:_ResumeMission( EscortGroup, WayPoint ) --self.FollowScheduler:Stop( self.FollowSchedule ) + + self:ModeMission( EscortGroup ) - local WayPoints = EscortGroup:GetTaskRoute() + local WayPoints = EscortGroup.MissionRoute self:T( WayPoint, WayPoints ) for WayPointIgnore = 1, WayPoint do @@ -1788,6 +1815,32 @@ function AI_ESCORT:RegisterRoute() return TaskPoints end +--- Resume Scheduler. +-- @param #AI_ESCORT self +-- @param Wrapper.Group#GROUP EscortGroup +function AI_ESCORT:_ResumeScheduler( EscortGroup ) + self:F( EscortGroup:GetName() ) + + if EscortGroup:IsAlive() and self.PlayerUnit:IsAlive() then + + + local EscortGroupName = EscortGroup:GetCallsign() + + if EscortGroup.EscortMenuResumeMission then + EscortGroup.EscortMenuResumeMission:RemoveSubMenus() + + local TaskPoints = EscortGroup.MissionRoute + + for WayPointID, WayPoint in pairs( TaskPoints ) do + local EscortVec3 = EscortGroup:GetVec3() + local Distance = ( ( WayPoint.x - EscortVec3.x )^2 + + ( WayPoint.y - EscortVec3.z )^2 + ) ^ 0.5 / 1000 + MENU_GROUP_COMMAND:New( self.PlayerGroup, "Waypoint " .. WayPointID .. " at " .. string.format( "%.2f", Distance ).. "km", EscortGroup.EscortMenuResumeMission, AI_ESCORT._ResumeMission, self, EscortGroup, WayPointID ) + end + end + end +end --- Report Targets Scheduler. @@ -1861,20 +1914,6 @@ function AI_ESCORT:_ReportTargetsScheduler( EscortGroup ) EscortGroup:MessageTypeToGroup( "No targets detected.", MESSAGE.Type.Information, self.PlayerGroup ) end - if EscortGroup.EscortMenuResumeMission then - EscortGroup.EscortMenuResumeMission:RemoveSubMenus() - - local TaskPoints = EscortGroup:GetTaskRoute() - - for WayPointID, WayPoint in pairs( TaskPoints ) do - local EscortVec3 = EscortGroup:GetVec3() - local Distance = ( ( WayPoint.x - EscortVec3.x )^2 + - ( WayPoint.y - EscortVec3.z )^2 - ) ^ 0.5 / 1000 - MENU_GROUP_COMMAND:New( self.PlayerGroup, "Waypoint " .. WayPointID .. " at " .. string.format( "%.2f", Distance ).. "km", EscortGroup.EscortMenuResumeMission, AI_ESCORT._ResumeMission, self, EscortGroup, WayPointID ) - end - end - return true end diff --git a/Moose Development/Moose/AI/AI_Escort_Request.lua b/Moose Development/Moose/AI/AI_Escort_Request.lua index faf0e817c..7a2fecb55 100644 --- a/Moose Development/Moose/AI/AI_Escort_Request.lua +++ b/Moose Development/Moose/AI/AI_Escort_Request.lua @@ -226,43 +226,27 @@ end function AI_ESCORT_REQUEST:SpawnEscort() local EscortGroup = self.EscortSpawn:SpawnAtAirbase( self.EscortAirbase, SPAWN.Takeoff.Hot ) - self.EscortGroupSet:AddGroup( EscortGroup ) EscortGroup:OptionROTVertical() EscortGroup:OptionROEHoldFire() self:ScheduleOnce( 0.1, function( EscortGroup ) + + self.EscortGroupSet:AddGroup( EscortGroup ) + local LeaderEscort = self.EscortGroupSet:GetFirst() -- Wrapper.Group#GROUP - local Report = REPORT:New() - Report:Add( "Joining Up " .. self.EscortGroupSet:GetUnitTypeNames():Text( ", " ) .. " from " .. LeaderEscort:GetCoordinate():ToString( self.EscortUnit ) ) LeaderEscort:MessageTypeToGroup( Report:Text(), MESSAGE.Type.Information, self.PlayerUnit ) - self:FormationTrail( 50, 50, 50 ) if self.SpawnMode == self.__Enum.Mode.Formation then self:ModeFormation( EscortGroup ) end - --self:Menus( self.XStart, self.XSpace, self.YStart, self.YSpace, self.ZStart, self.ZSpace, self.ZLevels ) - - EscortGroup.EscortMenu = MENU_GROUP:New( self.PlayerGroup, EscortGroup:GetName(), self.MainMenu ) - - self:EscortMenuJoinUp( EscortGroup ) - - self:EscortMenuHoldAtEscortPosition( EscortGroup ) - self:EscortMenuHoldAtLeaderPosition( EscortGroup ) - - self:MenuFlare() - self:MenuSmoke() - - self:MenuReportTargets( 60 ) - self:MenuAssistedAttack() - self:MenuROE() - self:MenuROT() - - self:MenuResumeMission() + self:_InitFlightMenus() + self:_InitEscortMenus( EscortGroup ) + self:_InitEscortRoute( EscortGroup ) --- @param #AI_ESCORT self -- @param Core.Event#EVENTDATA EventData @@ -283,6 +267,8 @@ end -- @param Core.Set#SET_GROUP EscortGroupSet function AI_ESCORT_REQUEST:onafterStart( EscortGroupSet ) + self:F() + if not self.MenuRequestEscort then self.MenuRequestEscort = MENU_GROUP_COMMAND:New( self.LeaderGroup, "Request new escort ", self.MainMenu, function() @@ -291,6 +277,8 @@ function AI_ESCORT_REQUEST:onafterStart( EscortGroupSet ) ) end + self:GetParent( self ).onafterStart( self, EscortGroupSet ) + self:HandleEvent( EVENTS.Dead, self.OnEventDeadOrCrash ) self:HandleEvent( EVENTS.Crash, self.OnEventDeadOrCrash ) diff --git a/Moose Development/Moose/Core/Spawn.lua b/Moose Development/Moose/Core/Spawn.lua index 3495907ad..e0f7055c0 100644 --- a/Moose Development/Moose/Core/Spawn.lua +++ b/Moose Development/Moose/Core/Spawn.lua @@ -2839,6 +2839,19 @@ function SPAWN:_Prepare( SpawnTemplatePrefix, SpawnIndex ) --R2.2 SpawnTemplate.units[UnitID].unitId = nil end end + + -- Callsign + for UnitID = 1, #SpawnTemplate.units do + local Callsign = SpawnTemplate.units[UnitID].callsign + if Callsign[1] ~= nil then -- blue callsign + Callsign[2] = ( ( SpawnIndex - 1 ) % 10 ) + 1 + local CallsignName = SpawnTemplate.units[UnitID].callsign["name"] -- #string + local CallsignLen = CallsignName:len() + SpawnTemplate.units[UnitID].callsign["name"] = CallsignName:sub(1,CallsignLen) .. SpawnTemplate.units[UnitID].callsign[2] .. SpawnTemplate.units[UnitID].callsign[3] + else + SpawnTemplate.units[UnitID].callsign = Callsign + SpawnIndex + end + end self:T3( { "Template:", SpawnTemplate } ) return SpawnTemplate From 1d4dad01804c68a55c067dbcd4b5b3cd1969697d Mon Sep 17 00:00:00 2001 From: FlightControl Date: Tue, 18 Jun 2019 20:03:24 +0300 Subject: [PATCH 24/25] Updates --- Moose Development/Moose/AI/AI_Escort.lua | 31 +++++++++++---------- Moose Development/Moose/AI/AI_Formation.lua | 3 +- 2 files changed, 19 insertions(+), 15 deletions(-) diff --git a/Moose Development/Moose/AI/AI_Escort.lua b/Moose Development/Moose/AI/AI_Escort.lua index c10d6cbee..6a817ffbf 100644 --- a/Moose Development/Moose/AI/AI_Escort.lua +++ b/Moose Development/Moose/AI/AI_Escort.lua @@ -1099,17 +1099,17 @@ function AI_ESCORT:SetEscortMenuTargets( EscortGroup ) for _, MenuTargets in pairs( self.Menu.Targets) do if EscortGroup:IsAir() then local EscortGroupName = EscortGroup:GetName() - local EscortMenuReportTargets = MENU_GROUP:New( self.PlayerGroup, "Report targets", EscortGroup.EscortMenu ) + --local EscortMenuReportTargets = MENU_GROUP:New( self.PlayerGroup, "Report targets", EscortGroup.EscortMenu ) -- Report Targets - EscortGroup.EscortMenuReportNearbyTargetsNow = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Report targets now!", EscortMenuReportTargets, AI_ESCORT._ReportNearbyTargetsNow, self, EscortGroup, true ) + EscortGroup.EscortMenuReportNearbyTargetsNow = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Report targets", EscortGroup.EscortMenu, AI_ESCORT._ReportNearbyTargetsNow, self, EscortGroup, true ) --EscortGroup.EscortMenuReportNearbyTargetsOn = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Report targets on", EscortGroup.EscortMenuReportNearbyTargets, AI_ESCORT._SwitchReportNearbyTargets, self, EscortGroup, true ) --EscortGroup.EscortMenuReportNearbyTargetsOff = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Report targets off", EscortGroup.EscortMenuReportNearbyTargets, AI_ESCORT._SwitchReportNearbyTargets, self, EscortGroup, false ) -- Attack Targets - local EscortMenuAttackTargets = MENU_GROUP:New( self.PlayerGroup, "Attack targets", EscortGroup.EscortMenu ) + --local EscortMenuAttackTargets = MENU_GROUP:New( self.PlayerGroup, "Attack targets", EscortGroup.EscortMenu ) - --EscortGroup.ReportTargetsScheduler = SCHEDULER:New( self, self._ReportTargetsScheduler, { EscortGroup }, 1, MenuTargets.Interval ) + EscortGroup.ReportTargetsScheduler = SCHEDULER:New( self, self._ReportTargetsScheduler, { EscortGroup }, 1, MenuTargets.Interval ) EscortGroup.ResumeScheduler = SCHEDULER:New( self, self._ResumeScheduler, { EscortGroup }, 1, 60 ) end end @@ -1365,6 +1365,8 @@ function AI_ESCORT:_JoinUp( EscortGroup ) local EscortUnit = self.PlayerUnit self:ModeFormation( EscortGroup ) + + EscortGroup:MessageTypeToGroup( "Joining up!", MESSAGE.Type.Information, EscortUnit:GetGroup() ) end @@ -1615,7 +1617,7 @@ function AI_ESCORT:_AttackTarget( EscortGroup, DetectedItem ) if EscortGroup:IsAir() then EscortGroup:OptionROEOpenFire() - EscortGroup:OptionROTPassiveDefense() + EscortGroup:OptionROTVertical() EscortGroup:SetState( EscortGroup, "Escort", self ) local DetectedSet = self.Detection:GetDetectedItemSet( DetectedItem ) @@ -1664,8 +1666,7 @@ function AI_ESCORT:_AttackTarget( EscortGroup, DetectedItem ) end - EscortGroup:MessageTypeToGroup( "Engaging!", MESSAGE.Type.Information, EscortUnit ) - + EscortGroup:MessageTypeToGroup( "Engaging Target!", MESSAGE.Type.Information, self.PlayerGroup ) end @@ -1846,7 +1847,7 @@ end --- Report Targets Scheduler. -- @param #AI_ESCORT self -- @param Wrapper.Group#GROUP EscortGroup -function AI_ESCORT:_ReportTargetsScheduler( EscortGroup ) +function AI_ESCORT:_ReportTargetsScheduler( EscortGroup, Report ) self:F( EscortGroup:GetName() ) if EscortGroup:IsAlive() and self.PlayerUnit:IsAlive() then @@ -1854,7 +1855,7 @@ function AI_ESCORT:_ReportTargetsScheduler( EscortGroup ) local EscortGroupName = EscortGroup:GetCallsign() - local DetectedTargetsReport = REPORT:New( "Reporting target locations from my position:\n" ) -- A new report to display the detected targets as a message to the player. + local DetectedTargetsReport = REPORT:New( "Reporting targets:\n" ) -- A new report to display the detected targets as a message to the player. if EscortGroup.EscortMenuTargetAssistance then @@ -1908,10 +1909,12 @@ function AI_ESCORT:_ReportTargetsScheduler( EscortGroup ) EscortMenuAttackTargets:RemoveSubMenus( TimeUpdate, "Esort" ) - if DetectedTargets then - EscortGroup:MessageTypeToGroup( DetectedTargetsReport:Text( "\n" ), MESSAGE.Type.Information, self.PlayerGroup ) - else - EscortGroup:MessageTypeToGroup( "No targets detected.", MESSAGE.Type.Information, self.PlayerGroup ) + if Report then + if DetectedTargets then + EscortGroup:MessageTypeToGroup( DetectedTargetsReport:Text( "\n" ), MESSAGE.Type.Information, self.PlayerGroup ) + else + EscortGroup:MessageTypeToGroup( "No targets detected.", MESSAGE.Type.Information, self.PlayerGroup ) + end end return true @@ -1929,7 +1932,7 @@ function AI_ESCORT:_FlightReportTargetsScheduler() local EscortGroup = self.EscortGroupSet:GetFirst() -- Wrapper.Group#GROUP - local DetectedTargetsReport = REPORT:New( "Reporting target locations from your position:\n" ) -- A new report to display the detected targets as a message to the player. + local DetectedTargetsReport = REPORT:New( "Reporting your targets:\n" ) -- A new report to display the detected targets as a message to the player. if EscortGroup and ( self.PlayerUnit:IsAlive() and EscortGroup:IsAlive() ) then diff --git a/Moose Development/Moose/AI/AI_Formation.lua b/Moose Development/Moose/AI/AI_Formation.lua index dbed463b1..7d0be781a 100644 --- a/Moose Development/Moose/AI/AI_Formation.lua +++ b/Moose Development/Moose/AI/AI_Formation.lua @@ -1142,7 +1142,8 @@ function AI_FORMATION:onenterFollowing( FollowGroupSet ) --R2.1 -- Now we calculate the intersecting vector between the circle around CV2 with radius FollowDistance and GH2. -- From the GeoGebra model: CVI = (x(CV2) + FollowDistance cos(alpha), y(GH2) + FollowDistance sin(alpha), z(CV2)) local CVI = { x = CV2.x + CS * 10 * math.sin(Ca), - y = GH2.y + ( Distance + FollowFormation.x ) / 10, -- + FollowFormation.y, + --y = GH2.y + ( Distance + FollowFormation.x ) / 10, -- + FollowFormation.y, + y = GH2.y, z = CV2.z + CS * 10 * math.cos(Ca), } From b4324cb05753c33bafe78b172bead155ee79c959 Mon Sep 17 00:00:00 2001 From: FlightControl Date: Tue, 18 Jun 2019 20:18:43 +0300 Subject: [PATCH 25/25] Optimized inclination for formation flying. --- Moose Development/Moose/AI/AI_Formation.lua | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Moose Development/Moose/AI/AI_Formation.lua b/Moose Development/Moose/AI/AI_Formation.lua index 7d0be781a..cf1971f8f 100644 --- a/Moose Development/Moose/AI/AI_Formation.lua +++ b/Moose Development/Moose/AI/AI_Formation.lua @@ -1141,8 +1141,12 @@ function AI_FORMATION:onenterFollowing( FollowGroupSet ) --R2.1 -- Now we calculate the intersecting vector between the circle around CV2 with radius FollowDistance and GH2. -- From the GeoGebra model: CVI = (x(CV2) + FollowDistance cos(alpha), y(GH2) + FollowDistance sin(alpha), z(CV2)) + local Inclination = ( Distance + FollowFormation.x ) / 10 + if Inclination < -30 then + Inclination = - 30 + end local CVI = { x = CV2.x + CS * 10 * math.sin(Ca), - --y = GH2.y + ( Distance + FollowFormation.x ) / 10, -- + FollowFormation.y, + y = GH2.y + Inclination, -- + FollowFormation.y, y = GH2.y, z = CV2.z + CS * 10 * math.cos(Ca), }