Advertisement
Guest User

Untitled

a guest
Nov 4th, 2015
263
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 14.96 KB | None | 0 0
  1. -- Fighter AI v0.99
  2.  
  3. controllingMainframe = 0  --the mainframe with the target prioritization card
  4. restrictSlot = 1          --ai will only control these weapons, and will orient the craft along those
  5. abortBreakDistance = 300    -- distance at which we reengage
  6.  
  7.  
  8.  
  9. -- control multiplier.
  10. -- raise in large increment until plane oscillate while shooting
  11. Ku = 50
  12. -- oscillation period - try to guess how many second an oscillation
  13. -- it will correct oscillation at point one
  14. Tu = 0.2
  15.  
  16.  
  17. minAlt = 75
  18. maxAlt = 300
  19.  
  20.  
  21. function killThatThing(I, weaponInfo, targetInfo, weaponIndex, turretSpinnerIndex)
  22.  
  23.     P = targetInfo.AimPointPosition
  24.     V = targetInfo.Velocity
  25.     WS = weaponInfo.Speed
  26.     G = I:GetGravityForAltitude(P.y).magnitude
  27.  
  28.  
  29.     T = (P - weaponInfo.GlobalPosition).magnitude / (WS*0.85) -- FIRST ESTIMATE OF FUTURE TARGET POSITION
  30.  
  31.  
  32.     FP = P + V*T  - I:GetVelocityVector()*T
  33.  -- position the target will be
  34.  
  35.     AD = FP - weaponInfo.GlobalPosition
  36.   -- direction direct to the target
  37.  
  38.  
  39.  
  40.     PJ = Mathf.Sqrt(AD.x*AD.x + AD.z*AD.z)
  41.  -- horizontal distance to the target
  42.  
  43.    
  44.     S2 = WS*WS
  45.   -- speed^2
  46.     S4 = S2*WS*WS
  47.   -- speed^4 (need these many times)
  48.     DELTA = S4 - G*(G*PJ*PJ + 2*AD.y * S2)
  49.  -- is there a solution to the parable?
  50.      
  51.  
  52.     if ( DELTA > 0 ) then
  53.         --ok we can reach it and now we have a better estimate
  54.        
  55.         AG = Mathf.Atan2(S2 - Mathf.Sqrt(DELTA),G*PJ)
  56.  --calculate angle
  57.        
  58.         --now we can calculate a better time to target using the horizontal speed
  59.         --as obtained from the firing angle
  60.        
  61. T = (P - weaponInfo.GlobalPosition).magnitude / (WS * Mathf.Cos(AG))
  62.        
  63.  
  64.         FP = P + V*T - I:GetVelocityVector()*T
  65.   --position target will be
  66.  
  67.         AD = FP - weaponInfo.GlobalPosition
  68.  -- line direct to the target position
  69.  
  70.  
  71.  
  72.         PJ = Mathf.Sqrt(AD.x*AD.x + AD.z*AD.z)
  73.   -- horizontal distance to the target
  74.  
  75.    
  76.      
  77.         DELTA = S4 - G*(G*PJ*PJ + 2*AD.y * S2)
  78.  -- check the parable solution
  79.  
  80.  
  81.         if ( DELTA > 0 ) then
  82.         --ok we can reach it and now we have a better estimate
  83.         PY = (S2 - Mathf.Sqrt(DELTA))/(G)
  84.  -- no need to calculate angle or tangent, just the elev
  85.  
  86.  
  87.  
  88.         AD.y = PY --assign new elevation to the firing direction
  89.  
  90.  
  91.         if(turretSpinnerIndex < 0) then
  92.            I:AimWeaponInDirection(weaponIndex, AD.x, AD.y, AD.z, weaponInfo.WeaponSlot)
  93.            I:FireWeapon(weaponIndex, weaponInfo.WeaponSlot)
  94.         else
  95.            I:AimWeaponInDirectionOnTurretOrSpinner(
  96.                  turretSpinnerIndex,weaponIndex, AD.x, AD.y, AD.z, weaponInfo.WeaponSlot)
  97.  
  98.          
  99.            I:FireWeaponOnTurretOrSpinner(
  100.                  turretSpinnerIndex,weaponIndex,weaponInfo.WeaponSlot)
  101.  
  102.         end
  103.  
  104.       end
  105.          
  106.     end
  107.    return AD
  108. end
  109. local function PIDFactory()
  110.     local this = {}
  111.     function this.pidupd(this,err)
  112.         local P = this.P
  113.         local I = this.I
  114.         local D = this.D
  115.         local Integrator = this.Integrator + I*err
  116.         local max = this.SatMax
  117.         local min = this.SatMin
  118.         local last = this.Last
  119.         this.Last = err
  120.         local delta = err-last
  121.         local out = P*err+D*delta+Integrator
  122.         if out > max then -- Integrator windup prevention
  123.             Integrator = this.Integrator
  124.             out = max
  125.         end
  126.         if out < min then -- Integrator windup prevention
  127.             Integrator = this.Integrator
  128.             out = min
  129.         end
  130.         this.Integrator = Integrator
  131.         return out
  132.     end
  133.     function this.pidconfig(this,p,i,d)
  134.         this.P = p
  135.         this.I = i
  136.         this.D = d
  137.     end
  138.     function this.pidlimits(this,max,min)
  139.         this.SatMax = max
  140.         this.SatMin = min
  141.     end
  142.     function this.CreatePID(this)
  143.         local pid = {}
  144.         pid.Update = this.pidupd
  145.         pid.Configure = this.pidconfig
  146.         pid.SetLimits = this.pidlimits
  147.         pid.P = 1 -- Just make it a simple passthrough for now
  148.         pid.I = 0
  149.         pid.D = 0
  150.         pid.Integrator=0
  151.         pid.Last=0
  152.         pid.SatMax = 1
  153.         pid.SatMin = -1
  154.         return pid
  155.     end
  156.     return this
  157. end
  158. function idleAround(I)
  159.     idlePosition = I:GetConstructCenterOfMass()
  160.     com = I:GetConstructCenterOfMass()
  161.     fcom = I:GetConstructCenterOfMass() + I:GetVelocityVector()
  162.     if (I:GetFriendlyCount() > 0) then
  163.         idlePosition = idlePosition / I:GetFriendlyCount()
  164.         for friendlyIndex=0, I:GetFriendlyCount() do
  165.             friendlyInfo = I:GetFriendlyInfo(friendlyIndex)
  166.             idlePosition = friendlyInfo.ReferencePosition / I:GetFriendlyCount()
  167.         end
  168.     end
  169.    
  170.     flyDirection = I:GetConstructCenterOfMass()-I:GetVelocityVector()-idlePosition
  171.         if (com.y < I:GetTerrainAltitudeForLocalPosition(com.x,0,com.z) + minAlt or
  172.          fcom.y < I:GetTerrainAltitudeForLocalPosition(fcom.x,0,fcom.z) + minAlt or
  173.          com.y < minAlt) then
  174.       flyDirection = Vector3(0,1,0)
  175.         I:LogToHud("EC")
  176.     I:Component_SetBoolLogicAll(0, true)
  177.     else
  178.     I:Component_SetBoolLogicAll(0, false)
  179.     end
  180.     flyAlong(I, flyDirection, -I:GetGravityForAltitude(I:GetConstructCenterOfMass().y) )
  181. end
  182.  
  183.  
  184.  
  185. factory = PIDFactory()
  186. yawPID = factory.CreatePID(factory)
  187. pitchPID = factory.CreatePID(factory)
  188. rollPID = factory.CreatePID(factory)
  189.  
  190. yawPID.SetLimits(yawPID,1,-1)
  191. pitchPID.SetLimits(pitchPID,1,-1)
  192. rollPID.SetLimits(rollPID,1,-1)
  193.  
  194. Kp = 0.60*Ku
  195. Ki = 2*Kp/Tu
  196. Kd = Kp*Ku/8
  197.  
  198. yawPID.Configure(yawPID,Kp,Ki,Kd)
  199. rollPID.Configure(rollPID,Kp,Ki,Kd)
  200. pitchPID.Configure(pitchPID,Kp,Ki,Kd)
  201.  
  202.  
  203.  
  204.  
  205. function flyAlong(I, direction, normal)
  206.     I:RequestThrustControl(0, 1)
  207.     logstr = ""
  208.      dt = 1
  209.  
  210.     --I:RequestControl(mode,type,drive)
  211.     eYaw =  Vector3.Dot(
  212.             Vector3.ProjectOnPlane(direction, I:GetConstructUpVector() ),
  213.             I:GetConstructRightVector()
  214.             )
  215.     ePitch = Vector3.Dot(
  216.             Vector3.ProjectOnPlane(direction, I:GetConstructRightVector() ),
  217.             I:GetConstructUpVector()
  218.             )
  219.     eRoll = Vector3.Dot(
  220.             Vector3.ProjectOnPlane(normal, I:GetConstructForwardVector() ),
  221.             I:GetConstructRightVector()
  222.             )
  223.      
  224.    
  225.    
  226.     CYaw =  yawPID.Update(yawPID,eYaw)
  227.     CPitch =  pitchPID.Update(pitchPID,ePitch)
  228.     CRoll =  rollPID.Update(rollPID,eRoll)
  229.    
  230.     --CYaw = 0.63661977*Mathf.Atan(CYaw*10)
  231.     --CPitch = 0.63661977*Mathf.Atan(CPitch*10)
  232.     --CRoll = 0.63661977*Mathf.Atan(CRoll*10)
  233.    
  234.     if ( CYaw < 0 ) then
  235.             --turn left
  236.             I:RequestControl(2,0,-CYaw)
  237.             I:RequestControl(2,1,0)
  238.             logstr = logstr .. " left " .. -CYaw
  239.     else
  240.             --turn right
  241.             I:RequestControl(2,1,CYaw)
  242.             I:RequestControl(2,0,0)
  243.             logstr = logstr .. " right " ..CYaw
  244.     end
  245.     if ( CPitch < 0 ) then
  246.             --pitch down
  247.             I:RequestControl(2,5,-CPitch)
  248.             I:RequestControl(2,4,0)
  249.             logstr = logstr .. " down " .. -CPitch
  250.     else
  251.             --pitch up
  252.             I:RequestControl(2,4,CPitch)
  253.             I:RequestControl(2,5,0)
  254.             logstr = logstr .. " up " .. CPitch
  255.     end    
  256.            
  257.     if ( CRoll < 0 ) then
  258.             -- roll left
  259.             logstr = logstr .. " rccw " .. -CRoll
  260.             I:RequestControl(2,2,-CRoll)
  261.             I:RequestControl(2,3,0)
  262.     else
  263.             -- roll right  
  264.             I:RequestControl(2,3,CRoll)
  265.             I:RequestControl(2,2,0)
  266.             logstr = logstr .. " rcw " .. CRoll
  267.  
  268.     end
  269.     --I:LogToHud(logstr)
  270. end
  271.  
  272.  
  273. BREAK = 0 -- close in to target at max altitude
  274. SPLIT = 1 -- match target direction rolling down/up according to start alt
  275. ROLL = 2 -- if enemy vector are parallel, roll into tail
  276. TARGET = 3 -- aim to a shoot solution
  277. RUN = 4 -- too close and enemy not fast enough
  278. LOOP = 5 --enemy is faster loop on it's tail
  279. YOYO = 6
  280. EC = 7
  281.  
  282. attackState = TARGET
  283.  
  284. function performManeuver(I,targetInfo,attackState, situation)
  285.     --some random defaults
  286.     flyDirection = -I:GetGravityForAltitude(situation.com.y)
  287.     flyNormal = -I:GetGravityForAltitude(situation.com.y)
  288.     if (attackState == EC) then
  289.         I:LogToHud("EC")
  290.         flyDirection = Vector3(0,1,0)
  291.         flyNormal =  -I:GetGravityForAltitude(situation.com.y)
  292.         I:Component_SetBoolLogicAll(0, true)
  293.     else
  294.         I:Component_SetBoolLogicAll(0, false)
  295.     end
  296.  
  297.     if (attackState == TARGET) then
  298.         I:LogToHud("TARGETING")
  299.         flyNormal = situation.attackDirection + Vector3(0,1,0)
  300.         if(situation.forwardiness < 0) then
  301.             flyDirection = Vector3(0, -situation.operationAltitude+0.5, 0)
  302.         else
  303.             flyDirection = situation.attackDirection
  304.         end
  305.     end
  306.    
  307.     if (attackState == BREAK) then
  308.         I:LogToHud("BREAK")
  309.         if(situation.forwardiness > 0 or situation.separation < 0) then
  310.             flyDirection = -situation.targetVelocity.normalized +  Vector3(0, -situation.operationAltitude, 0)
  311.             flyNormal = flyDirection + Vector3(0,1,0)
  312.         else
  313.             flyDirection = -situation.targetDirection
  314.             flyDirection.y = 1-situation.operationAltitude
  315.             flyNormal = Vector3(0,1,0)
  316.         end
  317.     end
  318.     if (attackState == YOYO) then
  319.         I:LogToHud("YOYO")
  320.         flyDirection = Vector3(0,-situation.operationAltitude,0)
  321.         flyNormal = situation.targetDirection
  322.     end
  323.     if (attackState == ROLL) then
  324.         I:LogToHud("ROLL")
  325.         flyDirection =  situation.targetDirection + Vector3(0,-situation.operationAltitude,0) +  I:GetConstructRightVector() * situation.rightness
  326.         flyNormal = situation.targetDirection
  327.     end
  328.    
  329.     if (attackState == TURNFIGHT) then
  330.         I:LogToHud("TURNFIGHT")
  331.         flyDirection =  Vector3.Cross(situation.targetDirection.normalized, -I:GetGravityForAltitude(situation.com.y))
  332.         flyNormal = situation.targetDirection
  333.     end
  334.    
  335.     if (attackState == LOOP) then
  336.         I:LogToHud("LOOP")
  337.         flyDirection =  -situation.targetVelocity +  Vector3(0, -situation.operationAltitude,0)
  338.         flyNormal = situation.targetDirection
  339.     end
  340.    
  341.     flyAlong(I, flyDirection, flyNormal)
  342. end
  343.  
  344.  
  345.  
  346.  
  347. function attackEnemy(I, AD, targetInfo)
  348.     situation = {}
  349.  
  350.     situation.com = I:GetConstructCenterOfMass()
  351.     situation.futurecom = situation.com + I:GetVelocityVector()
  352.     situation.attackDirection = AD
  353.     situation.targetPosition = targetInfo.AimPointPosition
  354.     situation.targetVelocity = targetInfo.Velocity
  355.     situation.targetDirection = situation.targetPosition - I:GetConstructCenterOfMass()
  356.    
  357.     situation.forwardiness = Vector3.Dot(situation.targetDirection.normalized, I:GetConstructForwardVector())
  358.     situation.uppiness = Vector3.Dot(situation.targetDirection.normalized, I:GetConstructUpVector())
  359.     situation.rightness = Vector3.Dot(situation.targetDirection.normalized, I:GetConstructRightVector())
  360.     situation.accordingness = Vector3.Dot(situation.targetVelocity.normalized, I:GetVelocityVector().normalized)
  361.    
  362.     situation.distance = situation.targetDirection.magnitude
  363.     situation.separation = (situation.targetDirection + situation.targetVelocity).magnitude - I:GetVelocityVector().magnitude  - 50
  364.    
  365.    
  366.    
  367.     situation.operationAltitude = 2*(situation.com.y - minAlt)/(maxAlt-minAlt) - 1   -- -1 .. 1
  368.     situation.targetAltitude = 2*(situation.targetPosition.y - minAlt)/(maxAlt-minAlt) - 1   -- -1 .. 1
  369.    
  370.     situation.speedFactor = I:GetVelocityVector().magnitude / (situation.targetVelocity.magnitude+0.01)
  371.  
  372.     situation.decisionSeed = ((I:GetConstructForwardVector().x + I:GetConstructForwardVector().y + I:GetConstructForwardVector().z)*534534545353.0)%100    
  373.  
  374.  
  375.    
  376.    
  377.     if(attackState == BREAK) then
  378.         if(situation.distance > abortBreakDistance ) then  attackState = TARGET end
  379.     else
  380.         if(situation.separation > 0 and situation.distance > I:GetVelocityVector().magnitude  + 50 ) then  attackState = TARGET end
  381.     end
  382.     if (attackState == TARGET) then
  383.     if (situation.forwardiness > 0 and situation.separation < 0) then
  384.         if (situation.decisionSeed < 33) then
  385.             attackState = YOYO
  386.         end
  387.         if (situation.decisionSeed > 32 and situation.decisionSeed < 66) then
  388.             attackState = ROLL
  389.         end
  390.         if (situation.decisionSeed > 65) then
  391.             attackState = LOOP
  392.         end
  393.  
  394.     else
  395.    
  396.     if (situation.forwardiness < -0.9 and situation.accordingness > 0.9 and situation.speedFactor < 4 and situation.distance < abortBreakDistance) then
  397.         if (situation.decisionSeed < 33) then
  398.             attackState = YOYO
  399.         end
  400.         if (situation.decisionSeed > 32 and situation.decisionSeed < 66) then
  401.             attackState = ROLL
  402.         end
  403.         if (situation.decisionSeed > 65) then
  404.             attackState = LOOP
  405.         end
  406.     end
  407.    
  408.     if (situation.forwardiness > 0.9 and situation.accordingness > 0.9 and situation.separation < 0) then
  409.         if(situation.speedFactor > 4) then
  410.            attackState = BREAK
  411.         else
  412.             if (situation.decisionSeed < 33) then
  413.                 attackState = YOYO
  414.             end
  415.             if (situation.decisionSeed > 32 and situation.decisionSeed < 66) then
  416.                 attackState = TURNFIGHT
  417.             end
  418.             if (situation.decisionSeed > 65 ) then
  419.                 attackState = LOOP
  420.             end
  421.         end
  422.     end
  423.    
  424.     if (situation.uppiness > 0.5 and situation.distance < I:GetVelocityVector().magnitude/2) then
  425.         if (situation.decisionSeed < 33) then
  426.             attackState = YOYO
  427.         end
  428.         if (situation.decisionSeed > 32 and situation.decisionSeed < 66) then
  429.             attackState = TURNFIGHT
  430.         end
  431.         if (situation.decisionSeed > 65 ) then
  432.             attackState = LOOP
  433.         end
  434.     end
  435.    
  436.     if (situation.forwardiness < 0 and situation.speedFactor > 4 and situation.distance < abortBreakDistance ) then
  437.         attackState = BREAK
  438.     end
  439.     end
  440.     end
  441.    
  442.    
  443.     --emergency upcode
  444.     if (situation.com.y < I:GetTerrainAltitudeForLocalPosition(situation.com.x,0,situation.com.z) + minAlt or
  445.             situation.futurecom.y < I:GetTerrainAltitudeForLocalPosition(situation.futurecom.x,0,situation.futurecom.z) or
  446.             situation.com.y < minAlt) then
  447.        attackState = EC
  448.     end
  449.  
  450.     performManeuver(I,targetInfo,attackState, situation)
  451.  
  452. end
  453.  
  454.  
  455. function Update(I)
  456.    
  457.     targetInfo = I:GetTargetInfo(controllingMainframe, 0)
  458.     AttackDirection = nil
  459.    
  460.    
  461.    
  462.     if(targetInfo.Valid) then
  463.         for weaponIndex=0,I:GetWeaponCount() do
  464.           weaponInfo = I:GetWeaponInfo(weaponIndex)
  465.      
  466.           if ((weaponInfo.WeaponType == 4 or weaponInfo.WeaponType == 0 )
  467.                and weaponInfo.Valid and weaponInfo.PlayerCurrentlyControllingIt == false
  468.                and weaponInfo.WeaponSlot == restrictSlot) then
  469.                AttackDirection = killThatThing(I, weaponInfo, targetInfo, weaponIndex, -1)
  470.           end
  471.         end
  472.        
  473.         for turretSpinnerIndex=0,I:GetTurretSpinnerCount() do
  474.             for weaponIndex=0,I:GetWeaponCountOnTurretOrSpinner(turretSpinnerIndex) do
  475.               weaponInfo = I:GetWeaponInfoOnTurretOrSpinner(turretSpinnerIndex, weaponIndex)
  476.                 if ((weaponInfo.WeaponType == 4 or weaponInfo.WeaponType == 0 )
  477.                 and weaponInfo.Valid and weaponInfo.PlayerCurrentlyControllingIt == false
  478.                 and weaponInfo.WeaponSlot == restrictSlot ) then
  479.                 AttackDirection = killThatThing(I, weaponInfo, targetInfo, weaponIndex, turretSpinnerIndex)
  480.                 end
  481.             end
  482.         end
  483.         if (AttackDirection == nil) then
  484.             P = targetInfo.AimPointPosition
  485.             V = targetInfo.Velocity
  486.        
  487.             FP = P + V
  488.        
  489.          
  490.               I:LogToHud("No weapon configured!!")
  491.             AttackDirection = FP - I:GetConstructCenterOfMass()
  492.         end
  493.         attackEnemy(I, AttackDirection, targetInfo)
  494.     else
  495.    
  496.         idleAround(I)
  497.        I:LogToHud("IDLING")
  498.    
  499.     end
  500.        
  501. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement