Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- -- Fighter AI v0.99
- controllingMainframe = 0 --the mainframe with the target prioritization card
- restrictSlot = 1 --ai will only control these weapons, and will orient the craft along those
- abortBreakDistance = 300 -- distance at which we reengage
- -- control multiplier.
- -- raise in large increment until plane oscillate while shooting
- Ku = 50
- -- oscillation period - try to guess how many second an oscillation
- -- it will correct oscillation at point one
- Tu = 0.2
- minAlt = 75
- maxAlt = 300
- function killThatThing(I, weaponInfo, targetInfo, weaponIndex, turretSpinnerIndex)
- P = targetInfo.AimPointPosition
- V = targetInfo.Velocity
- WS = weaponInfo.Speed
- G = I:GetGravityForAltitude(P.y).magnitude
- T = (P - weaponInfo.GlobalPosition).magnitude / (WS*0.85) -- FIRST ESTIMATE OF FUTURE TARGET POSITION
- FP = P + V*T - I:GetVelocityVector()*T
- -- position the target will be
- AD = FP - weaponInfo.GlobalPosition
- -- direction direct to the target
- PJ = Mathf.Sqrt(AD.x*AD.x + AD.z*AD.z)
- -- horizontal distance to the target
- S2 = WS*WS
- -- speed^2
- S4 = S2*WS*WS
- -- speed^4 (need these many times)
- DELTA = S4 - G*(G*PJ*PJ + 2*AD.y * S2)
- -- is there a solution to the parable?
- if ( DELTA > 0 ) then
- --ok we can reach it and now we have a better estimate
- AG = Mathf.Atan2(S2 - Mathf.Sqrt(DELTA),G*PJ)
- --calculate angle
- --now we can calculate a better time to target using the horizontal speed
- --as obtained from the firing angle
- T = (P - weaponInfo.GlobalPosition).magnitude / (WS * Mathf.Cos(AG))
- FP = P + V*T - I:GetVelocityVector()*T
- --position target will be
- AD = FP - weaponInfo.GlobalPosition
- -- line direct to the target position
- PJ = Mathf.Sqrt(AD.x*AD.x + AD.z*AD.z)
- -- horizontal distance to the target
- DELTA = S4 - G*(G*PJ*PJ + 2*AD.y * S2)
- -- check the parable solution
- if ( DELTA > 0 ) then
- --ok we can reach it and now we have a better estimate
- PY = (S2 - Mathf.Sqrt(DELTA))/(G)
- -- no need to calculate angle or tangent, just the elev
- AD.y = PY --assign new elevation to the firing direction
- if(turretSpinnerIndex < 0) then
- I:AimWeaponInDirection(weaponIndex, AD.x, AD.y, AD.z, weaponInfo.WeaponSlot)
- I:FireWeapon(weaponIndex, weaponInfo.WeaponSlot)
- else
- I:AimWeaponInDirectionOnTurretOrSpinner(
- turretSpinnerIndex,weaponIndex, AD.x, AD.y, AD.z, weaponInfo.WeaponSlot)
- I:FireWeaponOnTurretOrSpinner(
- turretSpinnerIndex,weaponIndex,weaponInfo.WeaponSlot)
- end
- end
- end
- return AD
- end
- local function PIDFactory()
- local this = {}
- function this.pidupd(this,err)
- local P = this.P
- local I = this.I
- local D = this.D
- local Integrator = this.Integrator + I*err
- local max = this.SatMax
- local min = this.SatMin
- local last = this.Last
- this.Last = err
- local delta = err-last
- local out = P*err+D*delta+Integrator
- if out > max then -- Integrator windup prevention
- Integrator = this.Integrator
- out = max
- end
- if out < min then -- Integrator windup prevention
- Integrator = this.Integrator
- out = min
- end
- this.Integrator = Integrator
- return out
- end
- function this.pidconfig(this,p,i,d)
- this.P = p
- this.I = i
- this.D = d
- end
- function this.pidlimits(this,max,min)
- this.SatMax = max
- this.SatMin = min
- end
- function this.CreatePID(this)
- local pid = {}
- pid.Update = this.pidupd
- pid.Configure = this.pidconfig
- pid.SetLimits = this.pidlimits
- pid.P = 1 -- Just make it a simple passthrough for now
- pid.I = 0
- pid.D = 0
- pid.Integrator=0
- pid.Last=0
- pid.SatMax = 1
- pid.SatMin = -1
- return pid
- end
- return this
- end
- function idleAround(I)
- idlePosition = I:GetConstructCenterOfMass()
- com = I:GetConstructCenterOfMass()
- fcom = I:GetConstructCenterOfMass() + I:GetVelocityVector()
- if (I:GetFriendlyCount() > 0) then
- idlePosition = idlePosition / I:GetFriendlyCount()
- for friendlyIndex=0, I:GetFriendlyCount() do
- friendlyInfo = I:GetFriendlyInfo(friendlyIndex)
- idlePosition = friendlyInfo.ReferencePosition / I:GetFriendlyCount()
- end
- end
- flyDirection = I:GetConstructCenterOfMass()-I:GetVelocityVector()-idlePosition
- if (com.y < I:GetTerrainAltitudeForLocalPosition(com.x,0,com.z) + minAlt or
- fcom.y < I:GetTerrainAltitudeForLocalPosition(fcom.x,0,fcom.z) + minAlt or
- com.y < minAlt) then
- flyDirection = Vector3(0,1,0)
- I:LogToHud("EC")
- I:Component_SetBoolLogicAll(0, true)
- else
- I:Component_SetBoolLogicAll(0, false)
- end
- flyAlong(I, flyDirection, -I:GetGravityForAltitude(I:GetConstructCenterOfMass().y) )
- end
- factory = PIDFactory()
- yawPID = factory.CreatePID(factory)
- pitchPID = factory.CreatePID(factory)
- rollPID = factory.CreatePID(factory)
- yawPID.SetLimits(yawPID,1,-1)
- pitchPID.SetLimits(pitchPID,1,-1)
- rollPID.SetLimits(rollPID,1,-1)
- Kp = 0.60*Ku
- Ki = 2*Kp/Tu
- Kd = Kp*Ku/8
- yawPID.Configure(yawPID,Kp,Ki,Kd)
- rollPID.Configure(rollPID,Kp,Ki,Kd)
- pitchPID.Configure(pitchPID,Kp,Ki,Kd)
- function flyAlong(I, direction, normal)
- I:RequestThrustControl(0, 1)
- logstr = ""
- dt = 1
- --I:RequestControl(mode,type,drive)
- eYaw = Vector3.Dot(
- Vector3.ProjectOnPlane(direction, I:GetConstructUpVector() ),
- I:GetConstructRightVector()
- )
- ePitch = Vector3.Dot(
- Vector3.ProjectOnPlane(direction, I:GetConstructRightVector() ),
- I:GetConstructUpVector()
- )
- eRoll = Vector3.Dot(
- Vector3.ProjectOnPlane(normal, I:GetConstructForwardVector() ),
- I:GetConstructRightVector()
- )
- CYaw = yawPID.Update(yawPID,eYaw)
- CPitch = pitchPID.Update(pitchPID,ePitch)
- CRoll = rollPID.Update(rollPID,eRoll)
- --CYaw = 0.63661977*Mathf.Atan(CYaw*10)
- --CPitch = 0.63661977*Mathf.Atan(CPitch*10)
- --CRoll = 0.63661977*Mathf.Atan(CRoll*10)
- if ( CYaw < 0 ) then
- --turn left
- I:RequestControl(2,0,-CYaw)
- I:RequestControl(2,1,0)
- logstr = logstr .. " left " .. -CYaw
- else
- --turn right
- I:RequestControl(2,1,CYaw)
- I:RequestControl(2,0,0)
- logstr = logstr .. " right " ..CYaw
- end
- if ( CPitch < 0 ) then
- --pitch down
- I:RequestControl(2,5,-CPitch)
- I:RequestControl(2,4,0)
- logstr = logstr .. " down " .. -CPitch
- else
- --pitch up
- I:RequestControl(2,4,CPitch)
- I:RequestControl(2,5,0)
- logstr = logstr .. " up " .. CPitch
- end
- if ( CRoll < 0 ) then
- -- roll left
- logstr = logstr .. " rccw " .. -CRoll
- I:RequestControl(2,2,-CRoll)
- I:RequestControl(2,3,0)
- else
- -- roll right
- I:RequestControl(2,3,CRoll)
- I:RequestControl(2,2,0)
- logstr = logstr .. " rcw " .. CRoll
- end
- --I:LogToHud(logstr)
- end
- BREAK = 0 -- close in to target at max altitude
- SPLIT = 1 -- match target direction rolling down/up according to start alt
- ROLL = 2 -- if enemy vector are parallel, roll into tail
- TARGET = 3 -- aim to a shoot solution
- RUN = 4 -- too close and enemy not fast enough
- LOOP = 5 --enemy is faster loop on it's tail
- YOYO = 6
- EC = 7
- attackState = TARGET
- function performManeuver(I,targetInfo,attackState, situation)
- --some random defaults
- flyDirection = -I:GetGravityForAltitude(situation.com.y)
- flyNormal = -I:GetGravityForAltitude(situation.com.y)
- if (attackState == EC) then
- I:LogToHud("EC")
- flyDirection = Vector3(0,1,0)
- flyNormal = -I:GetGravityForAltitude(situation.com.y)
- I:Component_SetBoolLogicAll(0, true)
- else
- I:Component_SetBoolLogicAll(0, false)
- end
- if (attackState == TARGET) then
- I:LogToHud("TARGETING")
- flyNormal = situation.attackDirection + Vector3(0,1,0)
- if(situation.forwardiness < 0) then
- flyDirection = Vector3(0, -situation.operationAltitude+0.5, 0)
- else
- flyDirection = situation.attackDirection
- end
- end
- if (attackState == BREAK) then
- I:LogToHud("BREAK")
- if(situation.forwardiness > 0 or situation.separation < 0) then
- flyDirection = -situation.targetVelocity.normalized + Vector3(0, -situation.operationAltitude, 0)
- flyNormal = flyDirection + Vector3(0,1,0)
- else
- flyDirection = -situation.targetDirection
- flyDirection.y = 1-situation.operationAltitude
- flyNormal = Vector3(0,1,0)
- end
- end
- if (attackState == YOYO) then
- I:LogToHud("YOYO")
- flyDirection = Vector3(0,-situation.operationAltitude,0)
- flyNormal = situation.targetDirection
- end
- if (attackState == ROLL) then
- I:LogToHud("ROLL")
- flyDirection = situation.targetDirection + Vector3(0,-situation.operationAltitude,0) + I:GetConstructRightVector() * situation.rightness
- flyNormal = situation.targetDirection
- end
- if (attackState == TURNFIGHT) then
- I:LogToHud("TURNFIGHT")
- flyDirection = Vector3.Cross(situation.targetDirection.normalized, -I:GetGravityForAltitude(situation.com.y))
- flyNormal = situation.targetDirection
- end
- if (attackState == LOOP) then
- I:LogToHud("LOOP")
- flyDirection = -situation.targetVelocity + Vector3(0, -situation.operationAltitude,0)
- flyNormal = situation.targetDirection
- end
- flyAlong(I, flyDirection, flyNormal)
- end
- function attackEnemy(I, AD, targetInfo)
- situation = {}
- situation.com = I:GetConstructCenterOfMass()
- situation.futurecom = situation.com + I:GetVelocityVector()
- situation.attackDirection = AD
- situation.targetPosition = targetInfo.AimPointPosition
- situation.targetVelocity = targetInfo.Velocity
- situation.targetDirection = situation.targetPosition - I:GetConstructCenterOfMass()
- situation.forwardiness = Vector3.Dot(situation.targetDirection.normalized, I:GetConstructForwardVector())
- situation.uppiness = Vector3.Dot(situation.targetDirection.normalized, I:GetConstructUpVector())
- situation.rightness = Vector3.Dot(situation.targetDirection.normalized, I:GetConstructRightVector())
- situation.accordingness = Vector3.Dot(situation.targetVelocity.normalized, I:GetVelocityVector().normalized)
- situation.distance = situation.targetDirection.magnitude
- situation.separation = (situation.targetDirection + situation.targetVelocity).magnitude - I:GetVelocityVector().magnitude - 50
- situation.operationAltitude = 2*(situation.com.y - minAlt)/(maxAlt-minAlt) - 1 -- -1 .. 1
- situation.targetAltitude = 2*(situation.targetPosition.y - minAlt)/(maxAlt-minAlt) - 1 -- -1 .. 1
- situation.speedFactor = I:GetVelocityVector().magnitude / (situation.targetVelocity.magnitude+0.01)
- situation.decisionSeed = ((I:GetConstructForwardVector().x + I:GetConstructForwardVector().y + I:GetConstructForwardVector().z)*534534545353.0)%100
- if(attackState == BREAK) then
- if(situation.distance > abortBreakDistance ) then attackState = TARGET end
- else
- if(situation.separation > 0 and situation.distance > I:GetVelocityVector().magnitude + 50 ) then attackState = TARGET end
- end
- if (attackState == TARGET) then
- if (situation.forwardiness > 0 and situation.separation < 0) then
- if (situation.decisionSeed < 33) then
- attackState = YOYO
- end
- if (situation.decisionSeed > 32 and situation.decisionSeed < 66) then
- attackState = ROLL
- end
- if (situation.decisionSeed > 65) then
- attackState = LOOP
- end
- else
- if (situation.forwardiness < -0.9 and situation.accordingness > 0.9 and situation.speedFactor < 4 and situation.distance < abortBreakDistance) then
- if (situation.decisionSeed < 33) then
- attackState = YOYO
- end
- if (situation.decisionSeed > 32 and situation.decisionSeed < 66) then
- attackState = ROLL
- end
- if (situation.decisionSeed > 65) then
- attackState = LOOP
- end
- end
- if (situation.forwardiness > 0.9 and situation.accordingness > 0.9 and situation.separation < 0) then
- if(situation.speedFactor > 4) then
- attackState = BREAK
- else
- if (situation.decisionSeed < 33) then
- attackState = YOYO
- end
- if (situation.decisionSeed > 32 and situation.decisionSeed < 66) then
- attackState = TURNFIGHT
- end
- if (situation.decisionSeed > 65 ) then
- attackState = LOOP
- end
- end
- end
- if (situation.uppiness > 0.5 and situation.distance < I:GetVelocityVector().magnitude/2) then
- if (situation.decisionSeed < 33) then
- attackState = YOYO
- end
- if (situation.decisionSeed > 32 and situation.decisionSeed < 66) then
- attackState = TURNFIGHT
- end
- if (situation.decisionSeed > 65 ) then
- attackState = LOOP
- end
- end
- if (situation.forwardiness < 0 and situation.speedFactor > 4 and situation.distance < abortBreakDistance ) then
- attackState = BREAK
- end
- end
- end
- --emergency upcode
- if (situation.com.y < I:GetTerrainAltitudeForLocalPosition(situation.com.x,0,situation.com.z) + minAlt or
- situation.futurecom.y < I:GetTerrainAltitudeForLocalPosition(situation.futurecom.x,0,situation.futurecom.z) or
- situation.com.y < minAlt) then
- attackState = EC
- end
- performManeuver(I,targetInfo,attackState, situation)
- end
- function Update(I)
- targetInfo = I:GetTargetInfo(controllingMainframe, 0)
- AttackDirection = nil
- if(targetInfo.Valid) then
- for weaponIndex=0,I:GetWeaponCount() do
- weaponInfo = I:GetWeaponInfo(weaponIndex)
- if ((weaponInfo.WeaponType == 4 or weaponInfo.WeaponType == 0 )
- and weaponInfo.Valid and weaponInfo.PlayerCurrentlyControllingIt == false
- and weaponInfo.WeaponSlot == restrictSlot) then
- AttackDirection = killThatThing(I, weaponInfo, targetInfo, weaponIndex, -1)
- end
- end
- for turretSpinnerIndex=0,I:GetTurretSpinnerCount() do
- for weaponIndex=0,I:GetWeaponCountOnTurretOrSpinner(turretSpinnerIndex) do
- weaponInfo = I:GetWeaponInfoOnTurretOrSpinner(turretSpinnerIndex, weaponIndex)
- if ((weaponInfo.WeaponType == 4 or weaponInfo.WeaponType == 0 )
- and weaponInfo.Valid and weaponInfo.PlayerCurrentlyControllingIt == false
- and weaponInfo.WeaponSlot == restrictSlot ) then
- AttackDirection = killThatThing(I, weaponInfo, targetInfo, weaponIndex, turretSpinnerIndex)
- end
- end
- end
- if (AttackDirection == nil) then
- P = targetInfo.AimPointPosition
- V = targetInfo.Velocity
- FP = P + V
- I:LogToHud("No weapon configured!!")
- AttackDirection = FP - I:GetConstructCenterOfMass()
- end
- attackEnemy(I, AttackDirection, targetInfo)
- else
- idleAround(I)
- I:LogToHud("IDLING")
- end
- end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement