Advertisement
Aklidien

FtD - Lua Controlled Plane and Missiles

Nov 14th, 2015
259
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 15.37 KB | None | 0 0
  1. --[[
  2. Advanced aerial AI, version 2.8
  3. Created by Madwand 8/22/2015
  4. Use and modify this code however you like, however please credit me
  5. if you use this AI or a derivative of it in a tournament, or you publish a blueprint
  6. using it. Also let me know if you make any significant improvements,
  7. I can add them back into the code.
  8.  
  9. Documentation on the options is at http://pastebin.com/GyE59Y3a
  10. --]]
  11.  
  12. -- BASIC OPTIONS
  13. AngleBeforeTurn = 5
  14. AngleBeforeRoll = 10
  15. AttackRunDistance = 800
  16. AbortRunDistance = 300
  17. ClosingDistance = 1000
  18. ForceAttackTime = 15
  19. CruiseAltitude = 200
  20. MaxElevationAngle = 30
  21. CruiseSpeed = 5
  22. AttackRunSpeed = 5
  23. EscapeSpeed = 5
  24. RollingSpeed = 3
  25. ClosingSpeed = 5
  26. OrbitSpawn = true
  27.  
  28. -- AIRSHIP/HELICOPTER OPTIONS
  29. UseAltitudeJets = false
  30. UseSpinners = false
  31. MinHelicopterBladeSpeed = 20
  32. MaxHelicopterBladeSpeed = 30
  33.  
  34. -- TERRAIN AVOIDANCE OPTIONS
  35. TerrainAvoidanceStrategy = 1.
  36. MinAltitude = 100
  37. MaxAltitude = 400
  38. TerrainLookahead = {0,1,2,4}
  39. MaxTerrainSpeed = 5
  40.  
  41. -- WATER START OPTIONS
  42. DeployAlt = 5
  43. ReleaseAlt = 15
  44. EnableEnginesAlt = 10
  45.  
  46. -- COLLISION AVOIDANCE OPTIONS
  47. CollisionDetectionRange = 300
  48. CollisionDetectionHeight = 20
  49. CollisionAngle = 20
  50.  
  51. -- "DOGFIGHTING" OPTIONS
  52. MatchTargetAltitude = false
  53. MatchAltitudeRange = 600
  54. MatchAltitudeOffset = 50
  55.  
  56. -- ADVANCED OPTIONS
  57. MODE = 2
  58. AltitudeClamp = .2
  59. PitchDamping = 90
  60. YawDamping = 90
  61. RollDamping = 45
  62. DefaultRollAngle = 0
  63. UsePropulsionBalancing = true
  64.  
  65. --Static variables. Do not change these.
  66. DRIVELEFT = 0
  67. DRIVERIGHT = 1
  68. DRIVEMAIN = 8
  69. DRIVEUP = 4
  70. DRIVEDOWN = 5
  71. ROLLLEFT = 2
  72. ROLLRIGHT = 3
  73.  
  74. firstpass = true
  75. yawing = ""
  76. pitching = ""
  77. rolling = ""
  78. vertical = ""
  79. state = "cruise"
  80. DebugMode = false
  81. onattackrun = false
  82. WaterStarted = false
  83. NextAttackTime = 0
  84. OverTerrain = false
  85. Roll = 0
  86. Pitch = 0
  87. Yaw = 0
  88. DRoll = 0
  89. DPitch = 0
  90. DYaw = 0
  91. PitchCorrection = 0
  92. CurrentSpeed = 0
  93.  
  94. --Try to pitch (or yaw, if necessary) to a given angle of elevation
  95. function AdjustElevationToAngle(I,DesiredElevation)
  96.   local PitchSpeedCheck = math.abs(DesiredElevation-Pitch)/PitchDamping
  97.   local YawSpeedCheck = math.abs(DesiredElevation-Pitch)/YawDamping
  98.   if (Pitch > DesiredElevation+5) then
  99.     if (math.abs(Roll)>135 and PitchSpeedCheck>DPitch) then
  100.       I:RequestControl(MODE,DRIVEUP,1)
  101.       pitching = "Pup"
  102.     elseif (Roll<-45 and YawSpeedCheck>DYaw) then
  103.       I:RequestControl(MODE,DRIVERIGHT,1)
  104.       yawing = "right"
  105.     elseif (Roll>45 and YawSpeedCheck>-DYaw) then
  106.       I:RequestControl(MODE,DRIVELEFT,1)
  107.       yawing = "left"
  108.     elseif (math.abs(Roll)<45 and PitchSpeedCheck>-DPitch) then
  109.       I:RequestControl(MODE,DRIVEDOWN,1)
  110.       pitching = "Pdown"
  111.     end
  112.   elseif (Pitch < DesiredElevation-5) then
  113.     if (math.abs(Roll)>135 and PitchSpeedCheck>-DPitch) then
  114.       I:RequestControl(MODE,DRIVEDOWN,1)
  115.       pitching = "Pdown"
  116.     elseif (Roll<-45 and YawSpeedCheck>-DYaw) then
  117.       I:RequestControl(MODE,DRIVELEFT,1)
  118.       yawing = "left"
  119.     elseif (Roll>45 and YawSpeedCheck>DYaw) then
  120.       I:RequestControl(MODE,DRIVERIGHT,1)
  121.       yawing = "right"
  122.     elseif (math.abs(Roll)<45 and PitchSpeedCheck>DPitch) then
  123.       I:RequestControl(MODE,DRIVEUP,1)
  124.       pitching = "Pup"
  125.     end
  126.   end
  127. end
  128.  
  129. --Try to climb or decend to a particular altitude
  130. function AdjustAltitudeTo(I, DesiredAltitude)
  131.   local Alt = I:GetConstructCenterOfMass().y
  132.  
  133.   AdjustAltitudeJets(I,DesiredAltitude)
  134.    
  135.   local Angle = math.min(math.abs(Alt-DesiredAltitude)*AltitudeClamp,MaxElevationAngle)
  136.   if ((Alt<MinAltitude and Pitch<0) or (Alt>MaxAltitude and Pitch>0)) then
  137.     Angle = MaxElevationAngle
  138.   end -- pull up/down with full strength if we are below/above min/max altitudes
  139.  
  140.   if (Alt < DesiredAltitude) then
  141.     if (Pitch < 0) then
  142.       AdjustElevationToAngle(I,MaxElevationAngle)
  143.     else
  144.       AdjustElevationToAngle(I,Angle)
  145.     end
  146.   else
  147.     if (Pitch > 0) then
  148.       AdjustElevationToAngle(I,-MaxElevationAngle)
  149.     else
  150.       AdjustElevationToAngle(I,-Angle)
  151.     end
  152.   end
  153.  
  154.   AdjustHelicopterBlades(I,DesiredAltitude)
  155. end
  156.  
  157. function AdjustAltitudeJets(I,DesiredAltitude)
  158.   if not UseAltitudeJets then return end
  159.   local Alt = I:GetConstructCenterOfMass().y
  160.   if (Alt < DesiredAltitude) then
  161.     I:RequestThrustControl(4)
  162.     vertical = "up"
  163.   else
  164.     I:RequestThrustControl(5)
  165.     vertical = "down"
  166.   end
  167. end
  168.  
  169. function AdjustHelicopterBlades(I,DesiredAltitude)
  170.   if not UseSpinners then return end
  171.   local Alt = I:GetConstructCenterOfMass().y
  172.   if (Alt < DesiredAltitude) then
  173.     for spinner = 0, I:GetSpinnerCount() - 1 do
  174.       I:SetSpinnerContinuousSpeed(spinner, MaxHelicopterBladeSpeed)
  175.       vertical = "up"
  176.     end
  177.   else
  178.     for spinner = 0, I:GetSpinnerCount() - 1 do
  179.       I:SetSpinnerContinuousSpeed(spinner, MinHelicopterBladeSpeed)
  180.       vertical = "down"
  181.     end
  182.   end
  183. end
  184.  
  185. -- Get the current stats about angles of the vehicle
  186. function GetAngleStats(I)
  187.   Roll = I:GetConstructRoll()
  188. -- transform roll into roll we are familiar with from the game
  189.   if (Roll > 180) then Roll = Roll-360 end
  190.  
  191.   Pitch = I:GetConstructPitch()
  192. -- transform pitch into pitch we are familiar with from the game
  193.   if (Pitch > 180) then
  194.     Pitch = 360 - Pitch
  195.   elseif (Pitch>0) then
  196.     Pitch = -Pitch
  197.   end
  198.  
  199. -- Many vehicles need to keep their nose pitched upwards relative to velocity.
  200. -- This uses basic machine learning to calculate the upwards pitch correction.
  201.   VPitch = math.deg(math.asin(I:GetVelocityVectorNormalized().y)) -- observed pitch from velocity
  202.   PitchCorrection = PitchCorrection + .01*(Pitch-VPitch-PitchCorrection)
  203.   PitchCorrection = math.min(math.max(PitchCorrection,-MaxElevationAngle),MaxElevationAngle)
  204.   Pitch = Pitch - PitchCorrection
  205.  
  206.   local AngularVelocity = I:GetLocalAngularVelocity()
  207.   DRoll = AngularVelocity.z
  208.   DPitch = -AngularVelocity.x
  209.   DYaw = AngularVelocity.y
  210. end
  211.  
  212. -- Try to roll the craft and pull up on pitch controls to face a given azimuth (relative to the vehicles facing)
  213. -- Will try to set roll angle at one that will maintain a given altitude
  214. function RollTowardsAzimuth(I,Azimuth,DesiredAltitude)
  215.   local Alt = I:GetConstructCenterOfMass().y
  216. -- depending on our altitude, RollAngle will be set to 90 +/- 20 degrees to climb or descend as appropriate  
  217.   RollAngle = math.min(110,math.max(70,(90 + (Alt-DesiredAltitude)*.66)))
  218.  
  219.   if ((Azimuth<0 and (Azimuth>-150 or Roll<0)) or
  220.       (Azimuth>150 and Roll<0)) then  -- roll towards the left, otherwise towards the right
  221.     RollAngle = -RollAngle
  222.   end
  223.  
  224.   AdjustRollToAngle(I,RollAngle)
  225.  
  226.   if (Roll >= RollAngle-10 and Roll <= RollAngle+10) then -- start pitching
  227.     I:RequestControl(MODE,DRIVEUP,1)
  228.     pitching = "up"
  229.   end
  230.    
  231.   --I:LogToHud(string.format("%.2f %.2f %.2f", Azimuth, RollAngle, Roll))
  232. end
  233.  
  234. -- Roll the vehicle to a specified roll angle
  235. function AdjustRollToAngle(I,Angle)
  236.   local RollSpeedCheck = math.abs(Angle-Roll)/RollDamping
  237.   if (Roll < Angle and RollSpeedCheck>DRoll) then
  238.     I:RequestControl(MODE,ROLLLEFT,1)
  239.     rolling = "Rleft"
  240.   elseif (Roll > Angle and RollSpeedCheck>-DRoll) then
  241.     I:RequestControl(MODE,ROLLRIGHT,1)
  242.     rolling = "Rright"
  243.   end
  244. end
  245.  
  246. -- Yaw the vehicle towards a given targets aziumth (relative to the vehicle's facing)
  247. -- This function wil try to keep the nose "AngleBeforeTurn" degrees away from directly
  248. -- pointing at the given aziumuth
  249. function YawTowardsTarget(I, Azimuth, OffsetAngle)
  250.   if (Azimuth > 0) then
  251.     return YawTowardsAzimuth(I, Azimuth-OffsetAngle)
  252.   end
  253.   return YawTowardsAzimuth(I, Azimuth+OffsetAngle)
  254. end
  255.  
  256. -- Yaw the vehicle towards a given aziumth (relative to the vehicle's facing)
  257. function YawTowardsAzimuth(I,Azimuth)
  258.   if (math.abs(Roll)<45) then
  259.     local YawSpeedCheck = math.abs(Azimuth)/YawDamping
  260.     if (Azimuth > 0 and YawSpeedCheck>-DYaw) then
  261.       I:RequestControl(MODE,DRIVELEFT,1)
  262.       yawing = "left"
  263.     elseif (Azimuth < 0 and YawSpeedCheck>DYaw) then
  264.       I:RequestControl(MODE,DRIVERIGHT,1)
  265.       yawing = "right"
  266.     end
  267.     return true
  268.   end
  269.   return false
  270. end
  271.  
  272. -- No enemies, just cruise along
  273. function Cruise(I)
  274.   if OrbitSpawn then
  275.     SpawnInfo = I:GetTargetPositionInfoForPosition(0, SpawnPos.x, 0, SpawnPos.z)
  276.     NavigateToPoint(I, false, SpawnInfo)
  277.   else
  278.     state = "cruise"
  279.     AdjustRollToAngle(I, DefaultRollAngle)
  280.     SetSpeed(I, CruiseSpeed)
  281.     DesiredAltitude = AdjustAltitudeForTerrain(I, CruiseAltitude, false)
  282.     AdjustAltitudeTo(I, DesiredAltitude)
  283.     NextAttackTime = I:GetTime()+ForceAttackTime
  284.   end
  285. end
  286.  
  287. -- Given the current velocity vector and an azimuth, get the expected terrain height in that direction
  288. function GetTerrainAltitude(I, VelocityV, Angle)
  289.   local TerrainAltitude = -999
  290.   MyPos = I:GetConstructCenterOfMass()
  291.   for i,Lookahead in ipairs(TerrainLookahead) do
  292.     Position = Quaternion.Euler(0,Angle,0) * VelocityV * Lookahead
  293.     Position = MyPos + VelocityV * Lookahead
  294.     TerrainAltitude = math.max(TerrainAltitude,I:GetTerrainAltitudeForPosition(Position))
  295.   end
  296.   return TerrainAltitude
  297. end
  298.  
  299. -- Adjust a given altitude to compensate for terrain, according to "TerrainAvoidanceStrategy"
  300. -- and other terrain-avoidance-specific parameters.
  301. -- Last parameter forces the use of "TerrainAvoidanceStrategy" 2
  302. -- returns new altitude that should be used
  303. function AdjustAltitudeForTerrain(I, Altitude, StrategyOverride)
  304.   VelocityV = I:GetVelocityVector()
  305.   TerrainAltitude = GetTerrainAltitude(I, VelocityV, 0)
  306.  
  307.   OverTerrain = false
  308.   if (TerrainAltitude + MinAltitude > Altitude or TerrainAltitude>0) then -- we'll need to avoid the terrain
  309.     OverTerrain = TerrainAltitude + MinAltitude > Altitude
  310.    
  311.     if(StrategyOverride or TerrainAvoidanceStrategy == 2) then -- don't change altitude unless needed
  312.       Altitude = math.max(Altitude, TerrainAltitude + MinAltitude)
  313.     elseif(TerrainAvoidanceStrategy == 1) then -- just add Altitude to terrain height
  314.       Altitude = math.max(math.min(TerrainAltitude+Altitude, MaxAltitude), TerrainAltitude + MinAltitude)
  315.     end
  316.   end
  317.  
  318.   --I:LogToHud(string.format("TA: %.2f Here: %.2f Alt: %.2f", TerrainAltitude, I:GetTerrainAltitudeForLocalPosition(0, 0, 0), Altitude))
  319.  
  320.   return Altitude
  321. end
  322.  
  323. -- given information about the target, returns the angle to try to approach
  324. -- the target at.
  325. function CollisionAvoidance(I, Pos)
  326.   local Alt = I:GetConstructCenterOfMass().y
  327.   if (Pos.Range<CollisionDetectionRange and
  328.       math.abs(Pos.Azimuth)<CollisionAngle and
  329.       math.abs(Pos.ElevationForAltitudeComponentOnly)<CollisionDetectionHeight) then
  330.     --I:LogToHud("Collision warning.")
  331.     return math.max(CollisionAngle,AngleBeforeTurn)
  332.   end
  333.   return AngleBeforeTurn
  334. end
  335.  
  336. -- Perform a water start check. Returns true if movement is permitted.
  337. function WaterStartCheck(I)
  338.   local Alt = I:GetConstructCenterOfMass().y
  339.  
  340.   if (Alt < DeployAlt) then
  341.     I:Component_SetBoolLogicAll(0, true)
  342.     WaterStarted = true
  343.   elseif (WaterStarted and Alt > ReleaseAlt) then
  344.     I:Component_SetBoolLogicAll(0, false)
  345.     WaterStarted = false
  346.   end
  347.  
  348.   if (not WaterStarted or Alt>=EnableEnginesAlt) then
  349.     return true
  350.   end
  351.   return false
  352. end
  353.  
  354. function SetSpeed(I, CurrentSpeed)
  355.   if UsePropulsionBalancing then
  356.     I:RequestThrustControl(0,CurrentSpeed/5)
  357.   else
  358.     I:RequestControl(MODE,DRIVEMAIN,CurrentSpeed)
  359.   end
  360. end
  361.  
  362. -- given the range, azimuth off the nose, and height of a target, navigates to it
  363. function NavigateToPoint(I, Engaged, Pos)
  364.   local DesiredAltitude = CruiseAltitude
  365.   local MatchingAltitude = Engaged and MatchTargetAltitude and Pos.GroundDistance < MatchAltitudeRange
  366.   if MatchingAltitude then
  367.     DesiredAltitude = math.max(math.min(Pos.AltitudeAboveSeaLevel+MatchAltitudeOffset,MaxAltitude),MinAltitude)
  368.   end
  369.      
  370.   if (TerrainAvoidanceStrategy>0) then
  371.     DesiredAltitude = AdjustAltitudeForTerrain(I, DesiredAltitude, MatchingAltitude)
  372.   end
  373.  
  374.   CurrentSpeed = EscapeSpeed
  375.   if onattackrun then
  376.     CurrentSpeed = RollingSpeed
  377.     if (math.abs(Pos.Azimuth) > AngleBeforeRoll) then -- roll to turn
  378.       RollTowardsAzimuth(I, Pos.Azimuth, DesiredAltitude)
  379.       state = "rolling"
  380.     else -- yaw to turn
  381.       AdjustRollToAngle(I, DefaultRollAngle)
  382.       if (Pos.Range > ClosingDistance) then
  383.         if (YawTowardsAzimuth(I, Pos.Azimuth)) then
  384.           CurrentSpeed = ClosingSpeed
  385.         end
  386.         state = "closing in"
  387.       else
  388.         local YawAngle = CollisionAvoidance(I, Pos)
  389.         if (YawTowardsTarget(I, Pos.Azimuth, YawAngle)) then
  390.           CurrentSpeed = AttackRunSpeed
  391.         end
  392.         state = "yawing in"
  393.       end
  394.     end
  395.    
  396.     if (Pos.Range < AbortRunDistance) then
  397.       onattackrun = false
  398.       NextAttackTime = I:GetTime()+ForceAttackTime
  399.     end
  400.   else -- not on attack run, just go forwards until we're out of range
  401.     state = "escaping"
  402.     AdjustRollToAngle(I, DefaultRollAngle)
  403.     local YawAngle = CollisionAvoidance(I, Pos)
  404.     if (YawAngle>AngleBeforeTurn and YawAngle>Pos.Azimuth) then
  405.       YawTowardsTarget(I, Pos.Azimuth, YawAngle)
  406.     end
  407.     if (Pos.Range > AttackRunDistance or I:GetTime()>NextAttackTime) then
  408.       onattackrun = true
  409.     end
  410.   end
  411.  
  412.   if OverTerrain then
  413.     CurrentSpeed = math.min(CurrentSpeed,MaxTerrainSpeed)
  414.   end
  415.   if not Engaged then
  416.     CurrentSpeed = math.min(CurrentSpeed,CruiseSpeed)
  417.   end
  418.   SetSpeed(I, CurrentSpeed)
  419.  
  420.   AdjustAltitudeTo(I, DesiredAltitude)
  421. end
  422.  
  423. -- Calculate all movement for the vehicle
  424. function Movement(I)
  425.   if (firstpass) then
  426.     firstpass = false
  427.     MaxElevationAngle = math.max(MaxElevationAngle,1)
  428.     SpawnPos = I:GetConstructCenterOfMass()
  429.   end
  430.  
  431.   GetAngleStats(I)
  432.  
  433.   yawing = ""
  434.   pitching = ""
  435.   rolling = ""
  436.   vertical = ""
  437.    
  438.   if (I:GetNumberOfMainframes() > 0 and I:GetNumberOfTargets(0) > 0) then
  439.     local TargetPos = I:GetTargetPositionInfo(0,0)
  440.     if TargetPos.Valid then
  441.       NavigateToPoint(I, true, TargetPos)
  442.     else
  443.       Cruise(I)
  444.     end
  445.   else
  446.     Cruise(I)
  447.   end
  448.    
  449.   if DebugMode then
  450.     I:LogToHud(string.format("%s %s %s %s %d", state, yawing, pitching, rolling, CurrentSpeed))
  451.     --I:LogToHud(string.format("%.2f %.2f %.2f", Yaw, Pitch, Roll))
  452.   end
  453. end
  454.  
  455.  
  456.  
  457.  
  458.  
  459.  
  460. mainframeNumber_=0
  461. warningInfo_={}
  462.  
  463. -- Side Functions
  464. function Speed(vel)
  465.    return math.sqrt(vel.x^2 + vel.y^2 + vel.z^2)
  466. end
  467. function Distance(a,b)
  468.    return math.sqrt((a.x - b.x)^2 + (a.y - b.y)^2 + (a.z - b.z)^2)
  469. end
  470.  
  471. -- Aim Point
  472. function Predict(P_Missile,V_Missile,P_Target,V_Target)
  473.    D = Distance(P_Missile,P_Target)
  474.    S = Speed(V_Target-V_Missile)
  475.    Time =  D/S
  476.  
  477.    if(Time>0 and Time < 200) then
  478.       P_Target = P_Target + (V_Target*Time)
  479.    end
  480.    
  481.    return P_Target
  482. end
  483.  
  484.  
  485.  
  486.  
  487.  
  488. -- Main update function. Everything starts here.
  489. function Update(I)
  490.   if WaterStartCheck(I) then
  491.     Movement(I)
  492.   end
  493.  
  494.     -- Loops through the tranceivers and missiles
  495.   for transceiverNumber=0,I:GetLuaTransceiverCount() do
  496.     for missileNumber=0,I:GetLuaControlledMissileCount(transceiverNumber) do
  497.       -- Gets currently selected missile information
  498.       missileInfo=I:GetLuaControlledMissileInfo(transceiverNumber, missileNumber)
  499.       targetInfo=I:GetTargetInfo(mainframeNumber_,0)
  500.       predictPosition=Predict(missileInfo.Position,missileInfo.Velocity,targetInfo.Position,targetInfo.Velocity)
  501.       I:SetLuaControlledMissileAimPoint(transceiverNumber, missileNumber, predictPosition.x, predictPosition.y, predictPosition.z)
  502.     end
  503.   end
  504. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement