From e5c57269bb3906df239cd4e38ac1aa0549efded5 Mon Sep 17 00:00:00 2001 From: Applevangelist <72444570+Applevangelist@users.noreply.github.com> Date: Sun, 22 Nov 2020 17:24:56 +0100 Subject: [PATCH 1/7] Update Controllable.lua Added option OptionAAAttackRange and OptionEngageRange --- .../Moose/Wrapper/Controllable.lua | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/Moose Development/Moose/Wrapper/Controllable.lua b/Moose Development/Moose/Wrapper/Controllable.lua index 7332271ab..ded28c6bd 100644 --- a/Moose Development/Moose/Wrapper/Controllable.lua +++ b/Moose Development/Moose/Wrapper/Controllable.lua @@ -173,6 +173,12 @@ -- * @{#CONTROLLABLE.OptionAllowJettisonWeaponsOnThreat} -- * @{#CONTROLLABLE.OptionKeepWeaponsOnThreat} -- +-- ## 5.5) Air-2-Air missile attack range: +-- * @{#CONTROLLABLE.OptionAAAttackRange}(): Defines the usage of A2A missiles against possible targets. +-- +-- ## 5.6) GROUND units attack range: +-- * @{#CONTROLLABLE.OptionEngageRange}(): Engage range limit in percent (a number between 0 and 100). Default 100. Defines the range at which a GROUND unit/group (e.g. a SAM site) is allowed to use its weapons automatically. +-- -- @field #CONTROLLABLE CONTROLLABLE = { ClassName = "CONTROLLABLE", @@ -3659,3 +3665,50 @@ function CONTROLLABLE:OptionRestrictBurner(RestrictBurner) end end + +--- Sets Controllable Option for A2A attack range for AIR FIGHTER units. +-- @param #CONTROLLABLE self +-- @param #number Defines the range: MAX_RANGE = 0, NEZ_RANGE = 1, HALF_WAY_RMAX_NEZ = 2, TARGET_THREAT_EST = 3, RANDOM_RANGE = 4. Defaults to 3. See: https://wiki.hoggitworld.com/view/DCS_option_missileAttack +function CONTROLLABLE:OptionAAAttackRange(range) + self:F2( { self.ControllableName } ) + -- defaults to 3 + local range = range or 3 + if range < 0 or range > 4 then + range = 3 + end + local DCSControllable = self:GetDCSObject() + if DCSControllable then + local Controller = self:_GetController() + if Controller then + if self:IsAir() then + self:SetOption(AI.Option.Air.val.MISSILE_ATTACK, range) + end + end + return self + end + return nil +end + +--- Defines the range at which a GROUND unit/group is allowed to use its weapons automatically. +-- @param #CONTROLLABLE self +-- @param #number EngageRange Engage range limit in percent (a number between 0 and 100). Default 100. +-- @return #CONTROLLABLE self +function CONTROLLABLE:OptionEngageRange(EngageRange) + self:F2( { self.ControllableName } ) + -- Set default if not specified. + EngageRange=EngageRange or 100 + if EngageRange < 0 or EngageRange > 100 then + EngageRange = 100 + end + local DCSControllable = self:GetDCSObject() + if DCSControllable then + local Controller = self:_GetController() + if Controller then + if self:IsGround() then + self:SetOption(AI.Option.Ground.id.AC_ENGAGEMENT_RANGE_RESTRICTION, EngageRange) + end + end + return self + end + return nil +end From f034e3680c24d38c5eeee449d6409eb073d8f79f Mon Sep 17 00:00:00 2001 From: Applevangelist <72444570+Applevangelist@users.noreply.github.com> Date: Sun, 22 Nov 2020 17:39:56 +0100 Subject: [PATCH 2/7] Update Controllable.lua --- Moose Development/Moose/Wrapper/Controllable.lua | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Moose Development/Moose/Wrapper/Controllable.lua b/Moose Development/Moose/Wrapper/Controllable.lua index ded28c6bd..6282d409c 100644 --- a/Moose Development/Moose/Wrapper/Controllable.lua +++ b/Moose Development/Moose/Wrapper/Controllable.lua @@ -3668,7 +3668,8 @@ end --- Sets Controllable Option for A2A attack range for AIR FIGHTER units. -- @param #CONTROLLABLE self --- @param #number Defines the range: MAX_RANGE = 0, NEZ_RANGE = 1, HALF_WAY_RMAX_NEZ = 2, TARGET_THREAT_EST = 3, RANDOM_RANGE = 4. Defaults to 3. See: https://wiki.hoggitworld.com/view/DCS_option_missileAttack +-- @param #number range Defines the range +-- @usage Range can be one of MAX_RANGE = 0, NEZ_RANGE = 1, HALF_WAY_RMAX_NEZ = 2, TARGET_THREAT_EST = 3, RANDOM_RANGE = 4. Defaults to 3. See: https://wiki.hoggitworld.com/view/DCS_option_missileAttack function CONTROLLABLE:OptionAAAttackRange(range) self:F2( { self.ControllableName } ) -- defaults to 3 From aab2f20280c47da23aed42861d4d429dc1de0008 Mon Sep 17 00:00:00 2001 From: Applevangelist <72444570+Applevangelist@users.noreply.github.com> Date: Mon, 23 Nov 2020 12:32:00 +0100 Subject: [PATCH 3/7] Update Sead.lua Feature Request #1355 Added a couple of new missiles, SD-10 and AGM84 Cleaned up the logic --- Moose Development/Moose/Functional/Sead.lua | 125 ++++++++++---------- 1 file changed, 62 insertions(+), 63 deletions(-) diff --git a/Moose Development/Moose/Functional/Sead.lua b/Moose Development/Moose/Functional/Sead.lua index 6edb99312..62f71e137 100644 --- a/Moose Development/Moose/Functional/Sead.lua +++ b/Moose Development/Moose/Functional/Sead.lua @@ -39,12 +39,14 @@ SEAD = { ClassName = "SEAD", TargetSkill = { - Average = { Evade = 50, DelayOff = { 10, 25 }, DelayOn = { 10, 30 } } , - Good = { Evade = 30, DelayOff = { 8, 20 }, DelayOn = { 20, 40 } } , - High = { Evade = 15, DelayOff = { 5, 17 }, DelayOn = { 30, 50 } } , - Excellent = { Evade = 10, DelayOff = { 3, 10 }, DelayOn = { 30, 60 } } + Average = { Evade = 30, DelayOn = { 40, 60 } } , + Good = { Evade = 20, DelayOn = { 30, 50 } } , + High = { Evade = 15, DelayOn = { 20, 40 } } , + Excellent = { Evade = 10, DelayOn = { 10, 30 } } }, - SEADGroupPrefixes = {} + SEADGroupPrefixes = {}, + SuppressedGroups = {}, + EngagementRange = 75 -- default 75% engagement range Feature Request #1355 } --- Creates the main object which is handling defensive actions for SA sites or moving SA vehicles. @@ -70,25 +72,41 @@ function SEAD:New( SEADGroupPrefixes ) end self:HandleEvent( EVENTS.Shot ) - + self:I("*** SEAD - Started Version 0.2.0") return self end +--- Sets the engagement range of the SAMs. Defaults to 75% to make it more deadly. Feature Request #1355 +-- @param #SEAD self +-- @param #number range Set the engagement range in percent, e.g. 50 +-- @return self +function SEAD:SetEngagementRange(range) + self:F( { range } ) + range = range or 75 + if range < 0 or range > 100 then + range = 75 + end + self.EngagementRange = range + self:T(string.format("*** SEAD - Engagement range set to %s",range)) + return self +end + --- Detects if an SA site was shot with an anti radiation missile. In this case, take evasive actions based on the skill level set within the ME. -- @see SEAD -- @param #SEAD -- @param Core.Event#EVENTDATA EventData function SEAD:OnEventShot( EventData ) - self:F( { EventData } ) + self:T( { EventData } ) local SEADUnit = EventData.IniDCSUnit local SEADUnitName = EventData.IniDCSUnitName - local SEADWeapon = EventData.Weapon -- Identify the weapon fired + local SEADWeapon = EventData.Weapon -- Identify the weapon fired local SEADWeaponName = EventData.WeaponName -- return weapon type - -- Start of the 2nd loop - self:T( "Missile Launched = " .. SEADWeaponName ) + + self:T( "*** SEAD - Missile Launched = " .. SEADWeaponName) + self:T({ SEADWeapon }) - --if SEADWeaponName == "KH-58" or SEADWeaponName == "KH-25MPU" or SEADWeaponName == "AGM-88" or SEADWeaponName == "KH-31A" or SEADWeaponName == "KH-31P" then -- Check if the missile is a SEAD + --check for SEAD missiles if SEADWeaponName == "weapons.missiles.X_58" --Kh-58U anti-radiation missiles fired or SEADWeaponName == "weapons.missiles.Kh25MP_PRGS1VP" --Kh-25MP anti-radiation missiles fired @@ -107,27 +125,35 @@ function SEAD:OnEventShot( EventData ) or SEADWeaponName == "weapons.missiles.AGM_122" --AGM-122 Sidearm anti-radiation missiles fired or + SEADWeaponName == "weapons.missiles.LD-10" --LD-10 anti-radiation missiles fired + or SEADWeaponName == "weapons.missiles.ALARM" --ALARM anti-radiation missiles fired + or + SEADWeaponName == "weapons.missiles.AGM_84E" --AGM84 anti-radiation missiles fired + or + SEADWeaponName == "weapons.missiles.AGM_84A" --AGM84 anti-radiation missiles fired + or + SEADWeaponName == "weapons.missiles.AGM_84H" --AGM84 anti-radiation missiles fired then local _evade = math.random (1,100) -- random number for chance of evading action local _targetMim = EventData.Weapon:getTarget() -- Identify target - local _targetMimname = Unit.getName(_targetMim) - local _targetMimgroup = Unit.getGroup(Weapon.getTarget(SEADWeapon)) - local _targetMimgroupName = _targetMimgroup:getName() - local _targetMimcont= _targetMimgroup:getController() + local _targetMimname = Unit.getName(_targetMim) -- Unit name + local _targetMimgroup = Unit.getGroup(Weapon.getTarget(SEADWeapon)) --targeted grouo + local _targetMimgroupName = _targetMimgroup:getName() -- group name local _targetskill = _DATABASE.Templates.Units[_targetMimname].Template.skill self:T( self.SEADGroupPrefixes ) self:T( _targetMimgroupName ) + -- see if we are shot at local SEADGroupFound = false for SEADGroupPrefixID, SEADGroupPrefix in pairs( self.SEADGroupPrefixes ) do if string.find( _targetMimgroupName, SEADGroupPrefix, 1, true ) then SEADGroupFound = true - self:T( 'Group Found' ) + self:T( '*** SEAD - Group Found' ) break end end - if SEADGroupFound == true then + if SEADGroupFound == true then -- yes we are being attacked if _targetskill == "Random" then -- when skill is random, choose a skill local Skills = { "Average", "Good", "High", "Excellent" } _targetskill = Skills[ math.random(1,4) ] @@ -136,63 +162,36 @@ function SEAD:OnEventShot( EventData ) if self.TargetSkill[_targetskill] then if (_evade > self.TargetSkill[_targetskill].Evade) then - self:T( string.format("Evading, target skill " ..string.format(_targetskill)) ) - - local _targetMim = Weapon.getTarget(SEADWeapon) - local _targetMimname = Unit.getName(_targetMim) + self:T( string.format("*** SEAD - Evading, target skill " ..string.format(_targetskill)) ) + local _targetMimgroup = Unit.getGroup(Weapon.getTarget(SEADWeapon)) local _targetMimcont= _targetMimgroup:getController() routines.groupRandomDistSelf(_targetMimgroup,300,'Diamond',250,20) -- move randomly - local SuppressedGroups1 = {} -- unit suppressed radar off for a random time - - local function SuppressionEnd1(id) - id.ctrl:setOption(AI.Option.Ground.id.ALARM_STATE,AI.Option.Ground.val.ALARM_STATE.GREEN) - SuppressedGroups1[id.groupName] = nil - end - - local id = { + --tracker ID table to switch groups off and on again + local id = { groupName = _targetMimgroup, ctrl = _targetMimcont } - - local delay1 = math.random(self.TargetSkill[_targetskill].DelayOff[1], self.TargetSkill[_targetskill].DelayOff[2]) - - if SuppressedGroups1[id.groupName] == nil then - - SuppressedGroups1[id.groupName] = { - SuppressionEndTime1 = timer.getTime() + delay1, - SuppressionEndN1 = SuppressionEndCounter1 --Store instance of SuppressionEnd() scheduled function - } - - Controller.setOption(_targetMimcont, AI.Option.Ground.id.ALARM_STATE,AI.Option.Ground.val.ALARM_STATE.GREEN) - timer.scheduleFunction(SuppressionEnd1, id, SuppressedGroups1[id.groupName].SuppressionEndTime1) --Schedule the SuppressionEnd() function - --trigger.action.outText( string.format("Radar Off " ..string.format(delay1)), 20) - end - - local SuppressedGroups = {} - - local function SuppressionEnd(id) + + local function SuppressionEnd(id) --switch group back on + local range = self.EngagementRange -- Feature Request #1355 + self:T(string.format("*** SEAD - Engagement Range is %d", range)) id.ctrl:setOption(AI.Option.Ground.id.ALARM_STATE,AI.Option.Ground.val.ALARM_STATE.RED) - SuppressedGroups[id.groupName] = nil + id.ctrl:setOption(AI.Option.Ground.id.AC_ENGAGEMENT_RANGE_RESTRICTION,range) --Feature Request #1355 + self.SuppressedGroups[id.groupName] = nil --delete group id from table when done end - - local id = { - groupName = _targetMimgroup, - ctrl = _targetMimcont - } - + -- randomize switch-on time local delay = math.random(self.TargetSkill[_targetskill].DelayOn[1], self.TargetSkill[_targetskill].DelayOn[2]) - - if SuppressedGroups[id.groupName] == nil then - SuppressedGroups[id.groupName] = { - SuppressionEndTime = timer.getTime() + delay, - SuppressionEndN = SuppressionEndCounter --Store instance of SuppressionEnd() scheduled function - } - - timer.scheduleFunction(SuppressionEnd, id, SuppressedGroups[id.groupName].SuppressionEndTime) --Schedule the SuppressionEnd() function - --trigger.action.outText( string.format("Radar On " ..string.format(delay)), 20) + local SuppressionEndTime = timer.getTime() + delay + --create entry + if self.SuppressedGroups[id.groupName] == nil then --no timer entry for this group yet + self.SuppressedGroups[id.groupName] = { + SuppressionEndTime = delay + } + Controller.setOption(_targetMimcont, AI.Option.Ground.id.ALARM_STATE,AI.Option.Ground.val.ALARM_STATE.GREEN) + timer.scheduleFunction(SuppressionEnd, id, SuppressionEndTime) --Schedule the SuppressionEnd() function end end end From 5842562ce15dfea6fea11e75ea43ff17afa32540 Mon Sep 17 00:00:00 2001 From: Applevangelist <72444570+Applevangelist@users.noreply.github.com> Date: Tue, 24 Nov 2020 16:23:22 +0100 Subject: [PATCH 4/7] Update AI_Air.lua Resolves AI reeping low back to base, and possible also issue #1305 --- Moose Development/Moose/AI/AI_Air.lua | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/Moose Development/Moose/AI/AI_Air.lua b/Moose Development/Moose/AI/AI_Air.lua index 213e58757..413baa5c8 100644 --- a/Moose Development/Moose/AI/AI_Air.lua +++ b/Moose Development/Moose/AI/AI_Air.lua @@ -595,19 +595,24 @@ function AI_AIR:onafterRTB( AIGroup, From, Event, To ) --- Calculate the target route point. local FromCoord = AIGroup:GetCoordinate() - local ToTargetCoord = self.HomeAirbase:GetCoordinate() - - if not self.RTBMinSpeed and not self.RTBMaxSpeed then + local ToTargetCoord = self.HomeAirbase:GetCoordinate() -- coordinate is on land height(!) + local ToTargetVec3 = ToTargetCoord:GetVec3() + ToTargetVec3.y = ToTargetCoord:GetLandHeight()+1000 -- let's set this 1000m/3000 feet above ground + local ToTargetCoord2 = COORDINATE:NewFromVec3( ToTargetVec3 ) + + if not self.RTBMinSpeed or not self.RTBMaxSpeed then local RTBSpeedMax = AIGroup:GetSpeedMax() - self:SetRTBSpeed( RTBSpeedMax * 0.25, RTBSpeedMax * 0.25 ) + self:SetRTBSpeed( RTBSpeedMax * 0.2, RTBSpeedMax * 0.5 ) end local RTBSpeed = math.random( self.RTBMinSpeed, self.RTBMaxSpeed ) - local ToAirbaseAngle = FromCoord:GetAngleDegrees( FromCoord:GetDirectionVec3( ToTargetCoord ) ) + --local ToAirbaseAngle = FromCoord:GetAngleDegrees( FromCoord:GetDirectionVec3( ToTargetCoord2 ) ) - local Distance = FromCoord:Get2DDistance( ToTargetCoord ) + local Distance = FromCoord:Get2DDistance( ToTargetCoord2 ) - local ToAirbaseCoord = FromCoord:Translate( 5000, ToAirbaseAngle ) + --local ToAirbaseCoord = FromCoord:Translate( 5000, ToAirbaseAngle ) + local ToAirbaseCoord = ToTargetCoord2 + if Distance < 5000 then self:I( "RTB and near the airbase!" ) self:Home() From ff4927dbb77d256dabf661c31c096bf33555ec3e Mon Sep 17 00:00:00 2001 From: Applevangelist <72444570+Applevangelist@users.noreply.github.com> Date: Wed, 25 Nov 2020 12:38:31 +0100 Subject: [PATCH 5/7] Update AI_Air.lua --- Moose Development/Moose/AI/AI_Air.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Moose Development/Moose/AI/AI_Air.lua b/Moose Development/Moose/AI/AI_Air.lua index 413baa5c8..6c8c9579c 100644 --- a/Moose Development/Moose/AI/AI_Air.lua +++ b/Moose Development/Moose/AI/AI_Air.lua @@ -602,7 +602,7 @@ function AI_AIR:onafterRTB( AIGroup, From, Event, To ) if not self.RTBMinSpeed or not self.RTBMaxSpeed then local RTBSpeedMax = AIGroup:GetSpeedMax() - self:SetRTBSpeed( RTBSpeedMax * 0.2, RTBSpeedMax * 0.5 ) + self:SetRTBSpeed( RTBSpeedMax * 0.5, RTBSpeedMax * 0.6 ) end local RTBSpeed = math.random( self.RTBMinSpeed, self.RTBMaxSpeed ) From c486167b01cd05a26b65b37820a827dc9f7b1501 Mon Sep 17 00:00:00 2001 From: Applevangelist <72444570+Applevangelist@users.noreply.github.com> Date: Thu, 26 Nov 2020 10:28:51 +0100 Subject: [PATCH 6/7] Update Task_A2G_Dispatcher.lua Option to suppress flashing messages --- .../Moose/Tasking/Task_A2G_Dispatcher.lua | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/Moose Development/Moose/Tasking/Task_A2G_Dispatcher.lua b/Moose Development/Moose/Tasking/Task_A2G_Dispatcher.lua index b7ae6ba17..448d7f545 100644 --- a/Moose Development/Moose/Tasking/Task_A2G_Dispatcher.lua +++ b/Moose Development/Moose/Tasking/Task_A2G_Dispatcher.lua @@ -451,6 +451,7 @@ do -- TASK_A2G_DISPATCHER self.Detection = Detection self.Mission = Mission + self.FlashNewTask = true --set to false to suppress flash messages self.Detection:FilterCategories( { Unit.Category.GROUND_UNIT } ) @@ -471,6 +472,12 @@ do -- TASK_A2G_DISPATCHER return self end + --- Set flashing player messages on or off + -- @param #TASK_A2G_DISPATCHER self + -- @param #boolean onoff Set messages on (true) or off (false) + function TASK_A2G_DISPATCHER:SetSendMessages( onoff ) + self.FlashNewTask = onoff + end --- Creates a SEAD task when there are targets for it. -- @param #TASK_A2G_DISPATCHER self @@ -616,7 +623,9 @@ do -- TASK_A2G_DISPATCHER if not DetectedItem then local TaskText = Task:GetName() for TaskGroupID, TaskGroup in pairs( self.SetGroup:GetSet() ) do - Mission:GetCommandCenter():MessageToGroup( string.format( "Obsolete A2G task %s for %s removed.", TaskText, Mission:GetShortText() ), TaskGroup ) + if self.FlashNewTask then + Mission:GetCommandCenter():MessageToGroup( string.format( "Obsolete A2G task %s for %s removed.", TaskText, Mission:GetShortText() ), TaskGroup ) + end end Task = self:RemoveTask( TaskIndex ) end @@ -686,7 +695,7 @@ do -- TASK_A2G_DISPATCHER -- Now we send to each group the changes, if any. for TaskGroupID, TaskGroup in pairs( self.SetGroup:GetSet() ) do local TargetsText = TargetsReport:Text(", ") - if ( Mission:IsGroupAssigned(TaskGroup) ) and TargetsText ~= "" then + if ( Mission:IsGroupAssigned(TaskGroup) ) and TargetsText ~= "" and self.FlashNewTask then Mission:GetCommandCenter():MessageToGroup( string.format( "Task %s has change of targets:\n %s", Task:GetName(), TargetsText ), TaskGroup ) end end @@ -805,7 +814,7 @@ do -- TASK_A2G_DISPATCHER local TaskText = TaskReport:Text(", ") for TaskGroupID, TaskGroup in pairs( self.SetGroup:GetSet() ) do - if ( not Mission:IsGroupAssigned(TaskGroup) ) and TaskText ~= "" then + if ( not Mission:IsGroupAssigned(TaskGroup) ) and TaskText ~= "" and self.FlashNewTask then Mission:GetCommandCenter():MessageToGroup( string.format( "%s has tasks %s. Subscribe to a task using the radio menu.", Mission:GetShortText(), TaskText ), TaskGroup ) end end @@ -815,4 +824,4 @@ do -- TASK_A2G_DISPATCHER return true end -end \ No newline at end of file +end From e7efd89d7a7493f3a94b6db17d2abc4d4b61684d Mon Sep 17 00:00:00 2001 From: Applevangelist <72444570+Applevangelist@users.noreply.github.com> Date: Thu, 26 Nov 2020 10:30:07 +0100 Subject: [PATCH 7/7] Update Task_A2A_Dispatcher.lua Added user function to change flash message behaviour --- Moose Development/Moose/Tasking/Task_A2A_Dispatcher.lua | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/Moose Development/Moose/Tasking/Task_A2A_Dispatcher.lua b/Moose Development/Moose/Tasking/Task_A2A_Dispatcher.lua index 573b8c4b0..76c7225a7 100644 --- a/Moose Development/Moose/Tasking/Task_A2A_Dispatcher.lua +++ b/Moose Development/Moose/Tasking/Task_A2A_Dispatcher.lua @@ -253,7 +253,12 @@ do -- TASK_A2A_DISPATCHER return self end - + --- Set flashing player messages on or off + -- @param #TASK_A2A_DISPATCHER self + -- @param #boolean onoff Set messages on (true) or off (false) + function TASK_A2A_DISPATCHER:SetSendMessages( onoff ) + self.FlashNewTask = onoff + end --- Creates an INTERCEPT task when there are targets for it. -- @param #TASK_A2A_DISPATCHER self @@ -610,7 +615,7 @@ do -- TASK_A2A_DISPATCHER local TaskText = TaskReport:Text(", ") for TaskGroupID, TaskGroup in pairs( self.SetGroup:GetSet() ) do - if ( not Mission:IsGroupAssigned(TaskGroup) ) and TaskText ~= "" and ( not not self.FlashNewTask) then + if ( not Mission:IsGroupAssigned(TaskGroup) ) and TaskText ~= "" and (self.FlashNewTask) then Mission:GetCommandCenter():MessageToGroup( string.format( "%s has tasks %s. Subscribe to a task using the radio menu.", Mission:GetShortText(), TaskText ), TaskGroup ) end end