diff --git a/Moose Development/Moose/Functional/Sead.lua b/Moose Development/Moose/Functional/Sead.lua index ae886d712..2c5abb451 100644 --- a/Moose Development/Moose/Functional/Sead.lua +++ b/Moose Development/Moose/Functional/Sead.lua @@ -1,26 +1,26 @@ --- **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**, **applevangelist** --- +-- -- Last Update: Feb 2021 --- +-- -- === --- +-- -- @module Functional.Sead -- @image SEAD.JPG @@ -28,24 +28,24 @@ -- @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 = 30, DelayOn = { 40, 60 } } , Good = { Evade = 20, DelayOn = { 30, 50 } } , High = { Evade = 15, DelayOn = { 20, 40 } } , - Excellent = { Evade = 10, DelayOn = { 10, 30 } } - }, + Excellent = { Evade = 10, DelayOn = { 10, 30 } } + }, SEADGroupPrefixes = {}, SuppressedGroups = {}, EngagementRange = 75 -- default 75% engagement range Feature Request #1355 @@ -84,7 +84,7 @@ SEAD = { ["X_31"] = "X_31", ["Kh25"] = "Kh25", } - + --- Creates the main object which is handling defensive actions for SA sites or moving SA vehicles. -- When an anti radiation missile is fired (KH-58, KH-31P, KH-31A, KH-25MPU, HARM missiles), the SA will shut down their radars and will take evasive actions... -- Chances are big that the missile will miss. @@ -99,7 +99,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 @@ -107,7 +107,7 @@ function SEAD:New( SEADGroupPrefixes ) else self.SEADGroupPrefixes[SEADGroupPrefixes] = SEADGroupPrefixes end - + self:HandleEvent( EVENTS.Shot ) self:I("*** SEAD - Started Version 0.2.5") return self @@ -120,7 +120,7 @@ end function SEAD:UpdateSet( SEADGroupPrefixes ) self:F( SEADGroupPrefixes ) - + if type( SEADGroupPrefixes ) == 'table' then for SEADGroupPrefixID, SEADGroupPrefix in pairs( SEADGroupPrefixes ) do self.SEADGroupPrefixes[SEADGroupPrefix] = SEADGroupPrefix @@ -174,10 +174,10 @@ function SEAD:OnEventShot( EventData ) 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 @@ -205,7 +205,7 @@ function SEAD:OnEventShot( EventData ) SEADWeaponName == "weapons.missiles.AGM_84H" --AGM84 anti-radiation missiles fired --]] if self:_CheckHarms(SEADWeaponName) 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) -- Unit name @@ -222,7 +222,7 @@ function SEAD:OnEventShot( EventData ) self:T( '*** SEAD - Group Found' ) break end - end + 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" } @@ -231,42 +231,26 @@ function SEAD:OnEventShot( EventData ) self:T( _targetskill ) if self.TargetSkill[_targetskill] then if (_evade > self.TargetSkill[_targetskill].Evade) then - + 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 - + --tracker ID table to switch groups off and on again - local id = { + 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 - --env.info(string.format("*** SEAD - Engagement Range is %d", range)) + 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) id.ctrl:setOption(AI.Option.Ground.id.AC_ENGAGEMENT_RANGE_RESTRICTION,range) --Feature Request #1355 - SuppressedGroups[id.groupName] = nil + self.SuppressedGroups[id.groupName] = nil --delete group id from table when done end -- randomize switch-on time local delay = math.random(self.TargetSkill[_targetskill].DelayOn[1], self.TargetSkill[_targetskill].DelayOn[2]) diff --git a/Moose Development/Moose/Ops/Airboss.lua b/Moose Development/Moose/Ops/Airboss.lua index 7cdf8a06d..3beeed272 100644 --- a/Moose Development/Moose/Ops/Airboss.lua +++ b/Moose Development/Moose/Ops/Airboss.lua @@ -39,7 +39,7 @@ -- * [F-14A/B Tomcat](https://forums.eagle.ru/forumdisplay.php?f=395) (Player & AI) -- * [A-4E Skyhawk Community Mod](https://forums.eagle.ru/showthread.php?t=224989) (Player & AI) -- * [AV-8B N/A Harrier](https://forums.eagle.ru/forumdisplay.php?f=555) (Player & AI) [**WIP**] --- * [T-45C Goshawk (VNAO)(Player & AI)] +-- * [T-45C Goshawk](https://www.vnao-cvw-7.com/t-45-goshawk) (VNAO)(Player & AI) [**WIP**] -- * F/A-18C Hornet (AI) -- * F-14A Tomcat (AI) -- * E-2D Hawkeye (AI) @@ -573,7 +573,10 @@ -- * **L**ined **U**p **L**eft or **R**ight: LUL, LUR -- * Too **H**igh or too **LO**w: H, LO -- * Too **F**ast or too **SLO**w: F, SLO --- * **Fly through** glideslope **down** or **up**: \\ , / +-- * **O**ver**S**hoot: OS, only referenced during **X** +-- * **Fly through** glideslope **down** or **up**: \\ , /, advisory only +-- * **D**rift **L**eft or **R**ight:DL, DR, advisory only +-- * **A**ngled **A**pproach: Angled approach (wings level and LUL): AA, advisory only -- -- Each grading, x, is subdivided by -- @@ -634,7 +637,7 @@ -- -- ## Foul Deck Waveoff -- --- A foul deck waveoff is called by the LSO if an aircraft is detected within the landing area when an approaching aircraft is crossing the ship's wake during Case I/II operations, +-- A foul deck waveoff is called by the LSO if an aircraft is detected within the landing area when an approaching aircraft is at position IM-IC during Case I/II operations, -- or with an aircraft approaching the 3/4 NM during Case III operations. -- -- The approaching aircraft will be notified via LSO radio comms and is supposed to overfly the landing area to enter the Bolter pattern. **This pass is not graded**. @@ -1264,6 +1267,7 @@ AIRBOSS = { -- @field #string S3BTANKER Lockheed S-3B Viking tanker. -- @field #string E2D Grumman E-2D Hawkeye AWACS. -- @field #string C2A Grumman C-2A Greyhound from Military Aircraft Mod. +-- @field #string T45C T-45C by VNAO AIRBOSS.AircraftCarrier={ AV8B="AV8BNA", HORNET="FA-18C_hornet", @@ -1340,6 +1344,8 @@ AIRBOSS.CarrierType={ -- @field #number _min Min _OK_ value. Default -0.5 deg. -- @field #number Left (LUR) threshold. Default -1.0 deg. -- @field #number Right (LUL) threshold. Default 1.0 deg. +-- @field #number LeftMed threshold for AA/OS measuring. Default -2.0 deg. +-- @field #number RightMed threshold for AA/OS measuring. Default 2.0 deg. -- @field #number LEFT LUR threshold. Default -3.0 deg. -- @field #number RIGHT LUL threshold. Default 3.0 deg. @@ -2650,10 +2656,10 @@ end --- Set multiplayer environment wire correction. -- @param #AIRBOSS self --- @param #number Dcorr Correction distance in meters. Default 8.7 m. +-- @param #number Dcorr Correction distance in meters. Default 12 m. -- @return #AIRBOSS self function AIRBOSS:SetMPWireCorrection(Dcorr) - self.mpWireCorrection=Dcorr or 8.7 + self.mpWireCorrection=Dcorr or 12 return self end @@ -2815,16 +2821,20 @@ end -- @param #number _max -- @param #number _min -- @param #number Left +-- @param #number LeftMed -- @param #number LEFT -- @param #number Right +-- @param #number RightMed -- @param #number RIGHT -- @return #AIRBOSS self -function AIRBOSS:SetLineupErrorThresholds(_max,_min, Left, LEFT, Right, RIGHT) +function AIRBOSS:SetLineupErrorThresholds(_max,_min, Left, LeftMed, LEFT, Right, RightMed, RIGHT) self.lue._max=_max or 0.5 self.lue._min=_min or -0.5 self.lue.Left=Left or -1.0 + self.lue.LeftMed=LeftMed or -2.0 self.lue.LEFT=LEFT or -3.0 self.lue.Right=Right or 1.0 + self.lue.RightMed=RightMed or 2.0 self.lue.RIGHT=RIGHT or 3.0 return self end @@ -10096,6 +10106,27 @@ function AIRBOSS:_Groove(playerData) -- Distance in NM. local d=UTILS.MetersToNM(rho) + -- Drift on lineup. + if rho>=RAR and rho<=RIM then + if gd.LUE>0.21 and lineupError<-0.21 then + env.info" Drift Right across centre ==> DR-" + gd.Drift=" DR" + self:T(self.lid..string.format("Got Drift Right across centre step %s, d=%.3f: Max LUE=%.3f, lower LUE=%.3f", gs, d, gd.LUE, lineupError)) + elseif gd.LUE<-0.21 and lineupError>0.21 then + env.info" Drift Left ==> DL-" + gd.Drift=" DL" + self:T(self.lid..string.format("Got Drift Left across centre at step %s, d=%.3f: Min LUE=%.3f, lower LUE=%.3f", gs, d, gd.LUE, lineupError)) + elseif gd.LUE>0.12 and lineupError<-0.12 then + env.info" Little Drift Right across centre ==> (DR-)" + gd.Drift=" (DR)" + self:T(self.lid..string.format("Got Little Drift Right across centre at step %s, d=%.3f: Max LUE=%.3f, lower LUE=%.3f", gs, d, gd.LUE, lineupError)) + elseif gd.LUE<-0.12 and lineupError>0.12 then + env.info" Little Drift Left across centre ==> (DL-)" + gd.Drift=" (DL)" + self:E(self.lid..string.format("Got Little Drift Left across centre at step %s, d=%.3f: Min LUE=%.3f, lower LUE=%.3f", gs, d, gd.LUE, lineupError)) + end + end + -- Update max deviation of line up error. if math.abs(lineupError)>math.abs(gd.LUE) then self:T(self.lid..string.format("Got bigger LUE at step %s, d=%.3f: LUE %.3f>%.3f", gs, d, lineupError, gd.LUE)) @@ -12092,7 +12123,7 @@ function AIRBOSS:_LSOgrade(playerData) local nS=count(G, '%(') local nN=N-nS-nL - -- Groove time 16-18 sec for a unicorn. + -- Groove time 15-18.99 sec for a unicorn. local Tgroove=playerData.Tgroove local TgrooveUnicorn=Tgroove and (Tgroove>=15.0 and Tgroove<=18.99) or false @@ -12227,7 +12258,35 @@ function AIRBOSS:_Flightdata2Text(playerData, groovestep) -- Aircraft specific AoA values. local acaoa=self:_GetAircraftAoA(playerData) - + + --Angled Approach. + local P=nil + if step==AIRBOSS.PatternStep.GROOVE_XX and ROL<=4.0 then + if LUE>self.lue.RIGHT then + P=underline("AA") + elseif + LUE>self.lue.RightMed then + P="AA " + elseif + LUE>self.lue.Right then + P=little("AA") + end + end + + --Overshoot Start. + local O=nil + if step==AIRBOSS.PatternStep.GROOVE_XX then + if LUEacaoa.SLOW then @@ -12260,7 +12319,7 @@ function AIRBOSS:_Flightdata2Text(playerData, groovestep) A=little("LO") end - -- Line up. Good [-0.5, 0.5] + -- Line up. XX Step replaced by Overshoot start (OS). Good [-0.5, 0.5] local D=nil if LUE>self.lue.RIGHT then D=underline("LUL") @@ -12268,11 +12327,11 @@ function AIRBOSS:_Flightdata2Text(playerData, groovestep) D="LUL" elseif LUE>self.lue._max then D=little("LUL") - elseif LUE1 then seconds=seconds+tonumber(dsplit[2])*60*60*24 end - -- Split hours, minutes, seconds + -- Split hours, minutes, seconds local tsplit=UTILS.Split(dsplit[1], ":") -- Get time in seconds @@ -833,7 +841,7 @@ function UTILS.ClockToSeconds(clock) end i=i+1 end - + return seconds end @@ -845,12 +853,12 @@ function UTILS.DisplayMissionTime(duration) local mission_time=Tnow-timer.getTime0() local mission_time_minutes=mission_time/60 local mission_time_seconds=mission_time%60 - local local_time=UTILS.SecondsToClock(Tnow) + local local_time=UTILS.SecondsToClock(Tnow) local text=string.format("Time: %s - %02d:%02d", local_time, mission_time_minutes, mission_time_seconds) MESSAGE:New(text, duration):ToAll() end ---- Replace illegal characters [<>|/?*:\\] in a string. +--- Replace illegal characters [<>|/?*:\\] in a string. -- @param #string Text Input text. -- @param #string ReplaceBy Replace illegal characters by this character or string. Default underscore "_". -- @return #string The input text with illegal chars replaced. @@ -871,28 +879,28 @@ function UTILS.RandomGaussian(x0, sigma, xmin, xmax, imax) -- Standard deviation. Default 10 if not given. sigma=sigma or 10 - + -- Max attempts. imax=imax or 100 - + local r local gotit=false local i=0 while not gotit do - + -- Uniform numbers in [0,1). We need two. local x1=math.random() local x2=math.random() - + -- Transform to Gaussian exp(-(x-x0)²/(2*sigma²). r = math.sqrt(-2*sigma*sigma * math.log(x1)) * math.cos(2*math.pi * x2) + x0 - + i=i+1 if (r>=xmin and r<=xmax) or i>imax then gotit=true end end - + return r end @@ -917,9 +925,9 @@ function UTILS.Randomize(value, fac, lower, upper) else max=value+value*fac end - + local r=math.random(min, max) - + return r end @@ -961,7 +969,7 @@ end function UTILS.VecDist2D(a, b) local c={x=b.x-a.x, y=b.y-a.y} - + local d=math.sqrt(c.x*c.x+c.y*c.y) return d @@ -975,7 +983,7 @@ end function UTILS.VecDist3D(a, b) local c={x=b.x-a.x, y=b.y-a.y, z=b.z-a.z} - + local d=math.sqrt(UTILS.VecDot(c, c)) return d @@ -989,7 +997,7 @@ function UTILS.VecCross(a, b) return {x=a.y*b.z - a.z*b.y, y=a.z*b.x - a.x*b.z, z=a.x*b.y - a.y*b.x} end ---- Calculate the difference between two 3D vectors by substracting the x,y,z components from each other. +--- Calculate the difference between two 3D vectors by substracting the x,y,z components from each other. -- @param DCS#Vec3 a Vector in 3D with x, y, z components. -- @param DCS#Vec3 b Vector in 3D with x, y, z components. -- @return DCS#Vec3 Vector c=a-b with c(i)=a(i)-b(i), i=x,y,z. @@ -997,7 +1005,7 @@ function UTILS.VecSubstract(a, b) return {x=a.x-b.x, y=a.y-b.y, z=a.z-b.z} end ---- Calculate the total vector of two 3D vectors by adding the x,y,z components of each other. +--- Calculate the total vector of two 3D vectors by adding the x,y,z components of each other. -- @param DCS#Vec3 a Vector in 3D with x, y, z components. -- @param DCS#Vec3 b Vector in 3D with x, y, z components. -- @return DCS#Vec3 Vector c=a+b with c(i)=a(i)+b(i), i=x,y,z. @@ -1005,14 +1013,14 @@ function UTILS.VecAdd(a, b) return {x=a.x+b.x, y=a.y+b.y, z=a.z+b.z} end ---- Calculate the angle between two 3D vectors. +--- Calculate the angle between two 3D vectors. -- @param DCS#Vec3 a Vector in 3D with x, y, z components. -- @param DCS#Vec3 b Vector in 3D with x, y, z components. --- @return #number Angle alpha between and b in degrees. alpha=acos(a*b)/(|a||b|), (* denotes the dot product). +-- @return #number Angle alpha between and b in degrees. alpha=acos(a*b)/(|a||b|), (* denotes the dot product). function UTILS.VecAngle(a, b) local cosalpha=UTILS.VecDot(a,b)/(UTILS.VecNorm(a)*UTILS.VecNorm(b)) - + local alpha=0 if cosalpha>=0.9999999999 then --acos(1) is not defined. alpha=0 @@ -1020,8 +1028,8 @@ function UTILS.VecAngle(a, b) alpha=math.pi else alpha=math.acos(cosalpha) - end - + end + return math.deg(alpha) end @@ -1056,18 +1064,18 @@ function UTILS.HdgDiff(h1, h2) -- Angle in rad. local alpha= math.rad(tonumber(h1)) local beta = math.rad(tonumber(h2)) - + -- Runway vector. local v1={x=math.cos(alpha), y=0, z=math.sin(alpha)} local v2={x=math.cos(beta), y=0, z=math.sin(beta)} local delta=UTILS.VecAngle(v1, v2) - + return math.abs(delta) end ---- Translate 3D vector in the 2D (x,z) plane. y-component (usually altitude) unchanged. +--- Translate 3D vector in the 2D (x,z) plane. y-component (usually altitude) unchanged. -- @param DCS#Vec3 a Vector in 3D with x, y, z components. -- @param #number distance The distance to translate. -- @param #number angle Rotation angle in degrees. @@ -1083,7 +1091,7 @@ function UTILS.VecTranslate(a, distance, angle) return {x=TX, y=a.y, z=TY} end ---- Translate 2D vector in the 2D (x,z) plane. +--- Translate 2D vector in the 2D (x,z) plane. -- @param DCS#Vec2 a Vector in 2D with x, y components. -- @param #number distance The distance to translate. -- @param #number angle Rotation angle in degrees. @@ -1099,40 +1107,40 @@ function UTILS.Vec2Translate(a, distance, angle) return {x=TX, y=TY} end ---- Rotate 3D vector in the 2D (x,z) plane. y-component (usually altitude) unchanged. +--- Rotate 3D vector in the 2D (x,z) plane. y-component (usually altitude) unchanged. -- @param DCS#Vec3 a Vector in 3D with x, y, z components. -- @param #number angle Rotation angle in degrees. -- @return DCS#Vec3 Vector rotated in the (x,z) plane. function UTILS.Rotate2D(a, angle) local phi=math.rad(angle) - + local x=a.z local y=a.x - + local Z=x*math.cos(phi)-y*math.sin(phi) local X=x*math.sin(phi)+y*math.cos(phi) local Y=a.y - + local A={x=X, y=Y, z=Z} return A end ---- Rotate 2D vector in the 2D (x,z) plane. +--- Rotate 2D vector in the 2D (x,z) plane. -- @param DCS#Vec2 a Vector in 2D with x, y components. -- @param #number angle Rotation angle in degrees. -- @return DCS#Vec2 Vector rotated in the (x,y) plane. function UTILS.Vec2Rotate2D(a, angle) local phi=math.rad(angle) - + local x=a.x local y=a.y - + local X=x*math.cos(phi)-y*math.sin(phi) local Y=x*math.sin(phi)+y*math.cos(phi) - + local A={x=X, y=Y} return A @@ -1150,17 +1158,17 @@ function UTILS.TACANToFrequency(TACANChannel, TACANMode) end if TACANMode ~= "X" and TACANMode ~= "Y" then return nil -- error in arguments - end - + end + -- This code is largely based on ED's code, in DCS World\Scripts\World\Radio\BeaconTypes.lua, line 137. -- I have no idea what it does but it seems to work local A = 1151 -- 'X', channel >= 64 local B = 64 -- channel >= 64 - + if TACANChannel < 64 then B = 1 end - + if TACANMode == 'Y' then A = 1025 if TACANChannel < 64 then @@ -1171,7 +1179,7 @@ function UTILS.TACANToFrequency(TACANChannel, TACANMode) A = 962 end end - + return (A + TACANChannel - B) * 1000000 end @@ -1198,13 +1206,13 @@ end -- @param #number Time (Optional) Abs. time in seconds. Default now, i.e. the value return from timer.getAbsTime(). -- @return #number Day of the mission. Mission starts on day 0. function UTILS.GetMissionDay(Time) - + Time=Time or timer.getAbsTime() - + local clock=UTILS.SecondsToClock(Time, false) - + local x=tonumber(UTILS.Split(clock, "+")[2]) - + return x end @@ -1214,11 +1222,11 @@ end function UTILS.GetMissionDayOfYear(Time) local Date, Year, Month, Day=UTILS.GetDCSMissionDate() - + local d=UTILS.GetMissionDay(Time) - + return UTILS.GetDayOfYear(Year, Month, Day)+d - + end --- Returns the current date. @@ -1230,20 +1238,20 @@ function UTILS.GetDate() -- Mission start date local date, year, month, day=UTILS.GetDCSMissionDate() - + local time=timer.getAbsTime() - + local clock=UTILS.SecondsToClock(time, false) - + local x=tonumber(UTILS.Split(clock, "+")[2]) - + local day=day+x end --- Returns the magnetic declination of the map. -- Returned values for the current maps are: --- +-- -- * Caucasus +6 (East), year ~ 2011 -- * NTTR +12 (East), year ~ 2011 -- * Normandy -10 (West), year ~ 1944 @@ -1254,7 +1262,7 @@ function UTILS.GetMagneticDeclination(map) -- Map. map=map or UTILS.GetDCSMap() - + local declination=0 if map==DCSMAP.Caucasus then declination=6 @@ -1289,12 +1297,12 @@ function UTILS.FileExists(file) end else return nil - end + end end --- Checks the current memory usage collectgarbage("count"). Info is printed to the DCS log file. Time stamp is the current mission runtime. --- @param #boolean output If true, print to DCS log file. --- @return #number Memory usage in kByte. +-- @param #boolean output If true, print to DCS log file. +-- @return #number Memory usage in kByte. function UTILS.CheckMemory(output) local time=timer.getTime() local clock=UTILS.SecondsToClock(time) @@ -1324,7 +1332,7 @@ function UTILS.GetCoalitionName(Coalition) else return "Unknown" end - + end --- Get the modulation name from its numerical value. @@ -1343,7 +1351,7 @@ function UTILS.GetModulationName(Modulation) else return "Unknown" end - + end --- Get the callsign name from its enumerator value @@ -1356,7 +1364,7 @@ function UTILS.GetCallsignName(Callsign) return name end end - + for name, value in pairs(CALLSIGN.AWACS) do if value==Callsign then return name @@ -1368,7 +1376,7 @@ function UTILS.GetCallsignName(Callsign) return name end end - + for name, value in pairs(CALLSIGN.Tanker) do if value==Callsign then return name @@ -1412,11 +1420,11 @@ end function UTILS.GetDayOfYear(Year, Month, Day) local floor = math.floor - + local n1 = floor(275 * Month / 9) local n2 = floor((Month + 9) / 12) local n3 = (1 + floor((Year - 4 * floor(Year / 4) + 2) / 3)) - + return n1 - (n2 * n3) + Day - 30 end @@ -1429,14 +1437,14 @@ end -- @return #number Sun rise/set in seconds of the day. function UTILS.GetSunRiseAndSet(DayOfYear, Latitude, Longitude, Rising, Tlocal) - -- Defaults + -- Defaults local zenith=90.83 local latitude=Latitude local longitude=Longitude local rising=Rising local n=DayOfYear Tlocal=Tlocal or 0 - + -- Short cuts. local rad = math.rad @@ -1463,47 +1471,47 @@ function UTILS.GetSunRiseAndSet(DayOfYear, Latitude, Longitude, Rising, Tlocal) return val end end - + -- Convert the longitude to hour value and calculate an approximate time local lng_hour = longitude / 15 - + local t if rising then -- Rising time is desired t = n + ((6 - lng_hour) / 24) else -- Setting time is desired t = n + ((18 - lng_hour) / 24) end - + -- Calculate the Sun's mean anomaly local M = (0.9856 * t) - 3.289 - + -- Calculate the Sun's true longitude local L = fit_into_range(M + (1.916 * sin(M)) + (0.020 * sin(2 * M)) + 282.634, 0, 360) - + -- Calculate the Sun's right ascension local RA = fit_into_range(atan(0.91764 * tan(L)), 0, 360) - + -- Right ascension value needs to be in the same quadrant as L local Lquadrant = floor(L / 90) * 90 local RAquadrant = floor(RA / 90) * 90 RA = RA + Lquadrant - RAquadrant - + -- Right ascension value needs to be converted into hours RA = RA / 15 - + -- Calculate the Sun's declination local sinDec = 0.39782 * sin(L) local cosDec = cos(asin(sinDec)) - + -- Calculate the Sun's local hour angle local cosH = (cos(zenith) - (sinDec * sin(latitude))) / (cosDec * cos(latitude)) - + if rising and cosH > 1 then return "N/R" -- The sun never rises on this location on the specified date elseif cosH < -1 then return "N/S" -- The sun never sets on this location on the specified date end - + -- Finish calculating H and convert into hours local H if rising then @@ -1512,13 +1520,13 @@ function UTILS.GetSunRiseAndSet(DayOfYear, Latitude, Longitude, Rising, Tlocal) H = acos(cosH) end H = H / 15 - + -- Calculate local mean time of rising/setting local T = H + RA - (0.06571 * t) - 6.622 -- Adjust back to UTC local UT = fit_into_range(T - lng_hour +Tlocal, 0, 24) - + return floor(UT)*60*60+frac(UT)*60*60--+Tlocal*60*60 end @@ -1568,9 +1576,9 @@ end --@param #table table to be shuffled --@return #table function UTILS.ShuffleTable(t) - if t == nil or type(t) ~= "table" then - BASE:I("Error in ShuffleTable: Missing or wrong tyåe of Argument") - return + if t == nil or type(t) ~= "table" then + BASE:I("Error in ShuffleTable: Missing or wrong tyåe of Argument") + return end math.random() math.random() diff --git a/Moose Development/Moose/Wrapper/Controllable.lua b/Moose Development/Moose/Wrapper/Controllable.lua index 4c527e997..059240c39 100644 --- a/Moose Development/Moose/Wrapper/Controllable.lua +++ b/Moose Development/Moose/Wrapper/Controllable.lua @@ -3687,3 +3687,57 @@ function CONTROLLABLE:OptionAAAttackRange(range) 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 + +--- (GROUND) Relocate controllable to a random point within a given radius; use e.g.for evasive actions; Note that not all ground controllables can actually drive, also the alarm state of the controllable might stop it from moving. +-- @param #CONTROLLABLE self +-- @param #number speed Speed of the controllable, default 20 +-- @param #number radius Radius of the relocation zone, default 500 +-- @param #boolean onroad If true, route on road (less problems with AI way finding), default true +-- @param #boolean shortcut If true and onroad is set, take a shorter route - if available - off road, default false +function CONTROLLABLE:RelocateGroundRandomInRadius(speed, radius, onroad, shortcut) + self:F2( { self.ControllableName } ) + + local _coord = self:GetCoordinate() + local _radius = radius or 500 + local _speed = speed or 20 + local _tocoord = _coord:GetRandomCoordinateInRadius(_radius,100) + local _onroad = onroad or true + local _grptsk = {} + local _candoroad = false + local _shortcut = shortcut or false + + -- create a DCS Task an push it on the group + -- TaskGroundOnRoad(ToCoordinate,Speed,OffRoadFormation,Shortcut,FromCoordinate,WaypointFunction,WaypointFunctionArguments) + if onroad then + _grptsk, _candoroad = self:TaskGroundOnRoad(_tocoord,_speed,"Off Road",_shortcut) + self:Route(_grptsk,5) + else + self:TaskRouteToVec2(_tocoord:GetVec2(),_speed,"Off Road") + end + + return self +end diff --git a/Moose Development/Moose/Wrapper/Positionable.lua b/Moose Development/Moose/Wrapper/Positionable.lua index 338417123..22dc87e33 100644 --- a/Moose Development/Moose/Wrapper/Positionable.lua +++ b/Moose Development/Moose/Wrapper/Positionable.lua @@ -598,16 +598,16 @@ function POSITIONABLE:GetHeading() if DCSPositionable then local PositionablePosition = DCSPositionable:getPosition() - + if PositionablePosition then local PositionableHeading = math.atan2( PositionablePosition.x.z, PositionablePosition.x.x ) - + if PositionableHeading < 0 then PositionableHeading = PositionableHeading + 2 * math.pi end - + PositionableHeading = PositionableHeading * 180 / math.pi - + return PositionableHeading end end @@ -1446,6 +1446,7 @@ do -- Cargo ["Dry-cargo ship-2"] = 70000, ["Higgins_boat"] = 3700, -- Higgins Boat can load 3700 kg of general cargo or 36 men (source wikipedia). ["USS_Samuel_Chase"] = 25000, -- Let's say 25 tons for now. Wiki says 33 Higgins boats, which would be 264 tons (can't be right!) and/or 578 troops. + ["LST_Mk2"] =2100000, -- Can carry 2100 tons according to wiki source! } self.__.CargoBayWeightLimit = ( Weights[Desc.typeName] or 50000 ) @@ -1453,48 +1454,55 @@ do -- Cargo local Desc = self:GetDesc() local Weights = { - ["M1126 Stryker ICV"] = 9, - ["M-113"] = 9, ["AAV7"] = 25, - ["M2A1_halftrack"] = 9, - ["BMD-1"] = 9, + ["Bedford_MWD"] = 8, -- new by kappa + ["Blitz_36-6700A"] = 10, -- new by kappa + ["BMD-1"] = 9, -- IRL should be 4 passengers ["BMP-1"] = 8, ["BMP-2"] = 7, - ["BMP-3"] = 8, + ["BMP-3"] = 8, -- IRL should be 7+2 passengers ["Boman"] = 25, - ["BTR-80"] = 9, - ["BTR_D"] = 12, + ["BTR-80"] = 9, -- IRL should be 7 passengers + ["BTR-82A"] = 9, -- new by kappa -- IRL should be 7 passengers + ["BTR_D"] = 12, -- IRL should be 10 passengers ["Cobra"] = 8, + ["Land_Rover_101_FC"] = 11, -- new by kappa + ["Land_Rover_109_S3"] = 7, -- new by kappa ["LAV-25"] = 6, ["M-2 Bradley"] = 6, ["M1043 HMMWV Armament"] = 4, ["M1045 HMMWV TOW"] = 4, ["M1126 Stryker ICV"] = 9, ["M1134 Stryker ATGM"] = 9, + ["M2A1_halftrack"] = 9, + ["M-113"] = 9, -- IRL should be 11 passengers ["Marder"] = 6, - ["MCV-80"] = 9, + ["MCV-80"] = 9, -- IRL should be 7 passengers ["MLRS FDDM"] = 4, - ["MTLB"] = 25, - ["TPZ"] = 10, - ["Ural-4320 APA-5D"] = 10, + ["MTLB"] = 25, -- IRL should be 11 passengers ["GAZ-66"] = 8, ["GAZ-3307"] = 12, ["GAZ-3308"] = 14, - ["Tigr_233036"] = 6, + ["Grad_FDDM"] = 6, -- new by kappa ["KAMAZ Truck"] = 12, ["KrAZ6322"] = 12, ["M 818"] = 12, + ["Tigr_233036"] = 6, + ["TPZ"] = 10, + ["UAZ-469"] = 4, -- new by kappa ["Ural-375"] = 12, ["Ural-4320-31"] = 14, + ["Ural-4320 APA-5D"] = 10, ["Ural-4320T"] = 14, + ["ZBD04A"] = 7, -- new by kappa } local CargoBayWeightLimit = ( Weights[Desc.typeName] or 0 ) * 95 - + self.__.CargoBayWeightLimit = CargoBayWeightLimit end end - + self:F({CargoBayWeightLimit = self.__.CargoBayWeightLimit}) end end --- Cargo