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