Merge branch 'master' into develop

This commit is contained in:
Frank 2020-11-30 11:40:34 +01:00
commit edf657c65c
5 changed files with 135 additions and 119 deletions

View File

@ -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.5, RTBSpeedMax * 0.6 )
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()

View File

@ -1,24 +1,24 @@
--- **Functional** -- Make SAM sites execute evasive and defensive behaviour when being fired upon.
--
--
-- ===
--
--
-- ## Features:
--
--
-- * When SAM sites are being fired upon, the SAMs will take evasive action will reposition themselves when possible.
-- * When SAM sites are being fired upon, the SAMs will take defensive action by shutting down their radars.
--
--
-- ===
--
--
-- ## Missions:
--
--
-- [SEV - SEAD Evasion](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/SEV%20-%20SEAD%20Evasion)
--
--
-- ===
--
--
-- ### Authors: **FlightControl**
--
--
-- ===
--
--
-- @module Functional.Sead
-- @image SEAD.JPG
@ -26,25 +26,26 @@
-- @extends Core.Base#BASE
--- Make SAM sites execute evasive and defensive behaviour when being fired upon.
--
--
-- This class is very easy to use. Just setup a SEAD object by using @{#SEAD.New}() and SAMs will evade and take defensive action when being fired upon.
--
--
-- # Constructor:
--
--
-- Use the @{#SEAD.New}() constructor to create a new SEAD object.
--
--
-- SEAD_RU_SAM_Defenses = SEAD:New( { 'RU SA-6 Kub', 'RU SA-6 Defenses', 'RU MI-26 Troops', 'RU Attack Gori' } )
--
--
-- @field #SEAD
SEAD = {
ClassName = "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 = {},
SuppressedGroups = {},
EngagementRange = 75 -- default 75% engagement range Feature Request #1355
}
@ -61,7 +62,7 @@ function SEAD:New( SEADGroupPrefixes )
local self = BASE:Inherit( self, BASE:New() )
self:F( SEADGroupPrefixes )
if type( SEADGroupPrefixes ) == 'table' then
for SEADGroupPrefixID, SEADGroupPrefix in pairs( SEADGroupPrefixes ) do
self.SEADGroupPrefixes[SEADGroupPrefix] = SEADGroupPrefix
@ -69,15 +70,15 @@ function SEAD:New( SEADGroupPrefixes )
else
self.SEADGroupNames[SEADGroupPrefixes] = 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 Gives the engagement range in percent, e.g. 50
-- @param #number range Set the engagement range in percent, e.g. 50
-- @return self
function SEAD:SetEngagementRange(range)
self:F( { range } )
@ -86,6 +87,7 @@ function SEAD:SetEngagementRange(range)
range = 75
end
self.EngagementRange = range
self:T(string.format("*** SEAD - Engagement range set to %s",range))
return self
end
@ -94,18 +96,19 @@ end
-- @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 )
--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
self:T( "*** SEAD - Missile Launched = " .. SEADWeaponName)
self:T({ SEADWeapon })
--check for SEAD missiles
if SEADWeaponName == "weapons.missiles.X_58" --Kh-58U anti-radiation missiles fired
or
or
SEADWeaponName == "weapons.missiles.Kh25MP_PRGS1VP" --Kh-25MP anti-radiation missiles fired
or
SEADWeaponName == "weapons.missiles.X_25MP" --Kh-25MPU anti-radiation missiles fired
@ -122,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
end
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) ]
@ -150,44 +161,36 @@ function SEAD:OnEventShot( EventData )
self:T( _targetskill )
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
--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 range = self.EngagementRange -- Feature Request #1355
--env.info(string.format("*** SEAD - Engagement Range is %d", range))
@ -195,22 +198,16 @@ function SEAD:OnEventShot( EventData )
id.ctrl:setOption(AI.Option.Ground.id.AC_ENGAGEMENT_RANGE_RESTRICTION,range) --Feature Request #1355
SuppressedGroups[id.groupName] = nil
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

View File

@ -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

View File

@ -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
end

View File

@ -175,7 +175,7 @@
--
-- ## 5.5) Air-2-Air missile attack range:
-- * @{#CONTROLLABLE.OptionAAAttackRange}(): Defines the usage of A2A missiles against possible targets .
--
--
-- @field #CONTROLLABLE
CONTROLLABLE = {
ClassName = "CONTROLLABLE",
@ -503,7 +503,7 @@ function CONTROLLABLE:TaskCombo( DCSTasks )
tasks = DCSTasks
}
}
return DCSTaskCombo
end
@ -801,12 +801,12 @@ end
-- @return #CONTROLLABLE self
function CONTROLLABLE:CommandSetFrequency(Frequency, Modulation, Delay)
local CommandSetFrequency = {
id = 'SetFrequency',
params = {
frequency = Frequency*1000000,
modulation = Modulation or radio.modulation.AM,
}
local CommandSetFrequency = {
id = 'SetFrequency',
params = {
frequency = Frequency*1000000,
modulation = Modulation or radio.modulation.AM,
}
}
if Delay and Delay>0 then
@ -880,7 +880,7 @@ function CONTROLLABLE:TaskAttackGroup( AttackGroup, WeaponType, WeaponExpend, At
groupId = AttackGroup:GetID(),
weaponType = WeaponType or 1073741822,
expend = WeaponExpend or "Auto",
attackQtyLimit = AttackQty and true or false,
attackQtyLimit = AttackQty and true or false,
attackQty = AttackQty or 1,
directionEnabled = Direction and true or false,
direction = Direction and math.rad(Direction) or 0,
@ -920,7 +920,7 @@ function CONTROLLABLE:TaskAttackUnit(AttackUnit, GroupAttack, WeaponExpend, Atta
weaponType = WeaponType or 1073741822,
}
}
return DCSTask
end
@ -1084,7 +1084,7 @@ function CONTROLLABLE:TaskEmbarking(Coordinate, GroupSetForEmbarking, Duration,
-- Distribution
--local distribution={}
--distribution[id]=gids
local groupID=self and self:GetID()
local DCSTask = {
@ -1313,7 +1313,7 @@ function CONTROLLABLE:TaskLandAtVec2(Vec2, Duration)
duration = Duration,
},
}
return DCSTask
end
@ -1795,7 +1795,7 @@ function CONTROLLABLE:TaskFunction( FunctionString, ... )
-- DCS task.
local DCSTask = self:TaskWrappedAction(self:CommandDoScript(table.concat( DCSScript )))
return DCSTask
end
@ -1972,7 +1972,7 @@ function CONTROLLABLE:TaskRoute( Points )
id = 'Mission',
params = {
airborne = self:IsAir(),
route = {points = Points},
route = {points = Points},
},
}
@ -2898,9 +2898,9 @@ end
function CONTROLLABLE:OptionROE(ROEvalue)
local DCSControllable = self:GetDCSObject()
if DCSControllable then
local Controller = self:_GetController()
if self:IsAir() then
@ -3464,13 +3464,13 @@ end
-- @return #CONTROLLABLE self
function CONTROLLABLE:OptionProhibitAfterburner(Prohibit)
self:F2( { self.ControllableName } )
if Prohibit==nil then
Prohibit=true
end
if self:IsAir() then
self:SetOption(AI.Option.Air.id.PROHIBIT_AB, Prohibit)
self:SetOption(AI.Option.Air.id.PROHIBIT_AB, Prohibit)
end
return self
@ -3481,9 +3481,9 @@ end
-- @return #CONTROLLABLE self
function CONTROLLABLE:OptionECM_Never()
self:F2( { self.ControllableName } )
if self:IsAir() then
self:SetOption(AI.Option.Air.id.ECM_USING, 0)
self:SetOption(AI.Option.Air.id.ECM_USING, 0)
end
return self
@ -3494,9 +3494,9 @@ end
-- @return #CONTROLLABLE self
function CONTROLLABLE:OptionECM_OnlyLockByRadar()
self:F2( { self.ControllableName } )
if self:IsAir() then
self:SetOption(AI.Option.Air.id.ECM_USING, 1)
self:SetOption(AI.Option.Air.id.ECM_USING, 1)
end
return self
@ -3508,9 +3508,9 @@ end
-- @return #CONTROLLABLE self
function CONTROLLABLE:OptionECM_DetectedLockByRadar()
self:F2( { self.ControllableName } )
if self:IsAir() then
self:SetOption(AI.Option.Air.id.ECM_USING, 2)
self:SetOption(AI.Option.Air.id.ECM_USING, 2)
end
return self
@ -3521,9 +3521,9 @@ end
-- @return #CONTROLLABLE self
function CONTROLLABLE:OptionECM_AlwaysOn()
self:F2( { self.ControllableName } )
if self:IsAir() then
self:SetOption(AI.Option.Air.id.ECM_USING, 3)
self:SetOption(AI.Option.Air.id.ECM_USING, 3)
end
return self
@ -3667,18 +3667,18 @@ end
-- @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 } )
self:F2( { self.ControllableName } )
-- defaults to 3
local range = range or 3
if range < 0 or range > 4 then
range = 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 Controller then
if self:IsAir() then
self:SetOption(AI.Option.Air.val.MISSILE_ATTACK, range)
self:SetOption(AI.Option.Air.val.MISSILE_ATTACK, range)
end
end
return self