dofile("Base.rte/Constants.lua") require("Actors/AI/NativeCrabAI") function Create(self) self.AI = NativeCrabAI:Create(self) function APCOffset(Origin, ang, dist) if Origin then return Vector(Origin.X, Origin.Y) + Vector(dist, 0):RadRotate(ang) end return Vector(dist, 0):RadRotate(ang) end self.DestructTimer = Timer() self.ConcreteTimer = Timer() self.GunTimer = Timer() self.Ctrl = self:GetController() self.CenterPos = self.Pos + self:RotateOffset(Vector(0, -5)) self.Wheels = {} self.WhOfst = {} self.Suspension = {} self.mainGunAmmo = 0 self.throttle = 0 self.destruct = 0 self.maxMgAmmo = 50 -- MG: Magazine capacity self.mgAmmo = self.maxMgAmmo self.rof = 80 -- MG: ms between shots self.rot = 2300 -- MG: Reload time in ms self.timing = self.rof -- Find the gun local thisID = self.ID local MoObj = nil for i = 1, MovableMan:GetMOIDCount()-1 do if MovableMan:GetRootMOID(i) == thisID then -- an obj without a parent has ID == RootID MoObj = MovableMan:GetMOFromID(i) if MoObj.ClassName == "HDFirearm" then self.Barrel = ToHDFirearm(MoObj) elseif MoObj.ClassName == "Turret" then self.Turret = ToAttachable(MoObj) end end end end function Destroy(self) for i = 1, #self.Wheels do if MovableMan:ValidMO(self.Wheels[i]) then self.Wheels[i].ToDelete = true end end for i = 1, #self.Suspension do if MovableMan:ValidMO(self.Suspension[i]) then self.Suspension[i].ToDelete = true end end end function Update(self) if self.Health < 0 then self:GibThis() return end local dist = 32 -- pixels between wheels local below = 35 -- pxels between wheels and body local multi = 1000 -- force multiplyer local maxForce = 3000 local Tmp, RightPos, LeftPos if self.HFlipped then RightPos = self.Pos + self:RotateOffset(Vector(-dist+10, -5)) LeftPos = self.Pos + self:RotateOffset(Vector(dist-10, -5)) else RightPos = self.Pos + self:RotateOffset(Vector(dist-10, -5)) LeftPos = self.Pos + self:RotateOffset(Vector(-dist+10, -5)) end if self.Ctrl:IsState(Controller.MOVE_LEFT) and self.throttle < 14 then self.throttle = self.throttle + 0.2 elseif self.Ctrl:IsState(Controller.MOVE_RIGHT) and self.throttle > -14 then self.throttle = self.throttle - 0.2 else self.throttle = self.throttle * 0.98 end -- Initialize or verify suspension for i = 1, 7 do if not MovableMan:ValidMO(self.Suspension[i]) then self.Suspension[i] = CreateMOSRotating("Suspension", "EDV.rte") self.Suspension[i].Pos = self.Pos MovableMan:AddParticle(self.Suspension[i]) end end -- Update Wheels local force = 0 for i = 1, 3 do if self.HFlipped then self.WhOfst[i] = self.Pos + self:RotateOffset(Vector(dist*(i-2), below)) else self.WhOfst[i] = self.Pos + self:RotateOffset(Vector(dist*(2-i), below)) end if not MovableMan:ValidMO(self.Wheels[i]) then -- Initialize or verify wheels self.Wheels[i] = CreateMOSRotating("APCWheel", "EDV.rte") self.Wheels[i].Pos = self.WhOfst[i] self.Wheels[i].Team = self.Team MovableMan:AddParticle(self.Wheels[i]) end Tmp = self.Wheels[i].Pos - self.WhOfst[i] self.Wheels[i].AngularVel = self.throttle if Tmp.Magnitude > 20 then self.Wheels[i].Pos = self.WhOfst[i] self.Wheels[i]:ClearForces() elseif Tmp.Magnitude > 4 then force = math.min(Tmp.Magnitude * multi, maxForce) self.Wheels[i]:AddForce(APCOffset(Vector(0,0), Tmp.AbsRadAngle + 3.141592, Tmp.Magnitude * multi), Vector(0,0)) if self.Vel.Magnitude < 5 and math.abs(self.throttle) > 9.9 and math.abs(self.Wheels[1].AngularVel) > 7 then self.Wheels[i]:EraseFromTerrain() -- Dislodge wheel if necessary end else self.Wheels[i]:MoveOutOfTerrain(6) -- Sand end end -- Update suspension self.CenterPos = self.Pos + self:RotateOffset(Vector(0, -5)) self.Suspension[1].Pos = (self.Wheels[2].Pos + self.CenterPos)/2 self.Suspension[1].RotAngle = (self.Wheels[2].Pos - self.CenterPos).AbsRadAngle + 1.57 self.Suspension[2].Pos = (self.Wheels[1].Pos + RightPos)/2 self.Suspension[2].RotAngle = (self.Wheels[1].Pos - RightPos).AbsRadAngle + 1.57 self.Suspension[3].Pos = (self.Wheels[3].Pos + LeftPos)/2 self.Suspension[3].RotAngle = (self.Wheels[3].Pos - LeftPos).AbsRadAngle + 1.57 self.Suspension[4].Pos = (self.Wheels[1].Pos + self.CenterPos)/2 self.Suspension[4].RotAngle = (self.Wheels[1].Pos - self.CenterPos).AbsRadAngle + 1.57 self.Suspension[5].Pos = (self.Wheels[3].Pos + self.CenterPos)/2 self.Suspension[5].RotAngle = (self.Wheels[3].Pos - self.CenterPos).AbsRadAngle + 1.57 self.Suspension[6].Pos = (self.Wheels[2].Pos + RightPos)/2 self.Suspension[6].RotAngle = (self.Wheels[2].Pos - RightPos).AbsRadAngle + 1.57 self.Suspension[7].Pos = (self.Wheels[2].Pos + LeftPos)/2 self.Suspension[7].RotAngle = (self.Wheels[2].Pos - LeftPos).AbsRadAngle + 1.57 -- Update chassi self:MoveOutOfTerrain(6) -- Sand self.AngularVel = self.AngularVel * 0.5 self.RotAngle = (self.Wheels[1].Pos - self.Wheels[3].Pos).AbsRadAngle Tmp = APCOffset((self.Wheels[1].Pos + self.Wheels[2].Pos + self.Wheels[3].Pos)/3, self.RotAngle + 1.57, below) - self.Pos if self.Vel.Magnitude > 15 then local Vel = Vector(self.Vel.X, self.Vel.Y) Vel:SetMagnitude(15) self.Vel = Vel else self.Vel = self.Vel * 0.98 end if Tmp.Magnitude > 1 then force = math.min(Tmp.Magnitude^2 * multi * 1.8, 140000) self:AddForce(APCOffset(Vector(0,0), Tmp.AbsRadAngle, force), Vector(0,0)) end if self.DestructTimer:IsPastSimMS(600) then self.DestructTimer:Reset() for i = 1, #self.Wheels do if self.Wheels[i].Pos.Y < self.Pos.Y then self.destruct = self.destruct + 1 end end if self.destruct > 9 then -- The vehicle is on its back, self destruct self:GibThis() else self.destruct = math.max(self.destruct - 1, 0) end end if self.Turret:IsAttached() then if self.Barrel:IsAttached() then -- Limit the aim angle if self.HFlipped then if self.Barrel.RotAngle - self.RotAngle > 0.6 then self.Barrel.RotAngle = self.RotAngle + 0.6 elseif self.Barrel.RotAngle - self.RotAngle < -0.9 then self.Barrel.RotAngle = self.RotAngle - 0.9 end else if self.Barrel.RotAngle - self.RotAngle > 0.9 then self.Barrel.RotAngle = self.RotAngle + 0.9 elseif self.Barrel.RotAngle - self.RotAngle < -0.6 then self.Barrel.RotAngle = self.RotAngle - 0.6 end end local fireCoAx = false if self.Barrel.Magazine then if self.Ctrl:IsState(Controller.WEAPON_FIRE) then if self.mainGunAmmo > self.Barrel.Magazine.RoundCount then -- bullets are missing from the magazine so the gun must have been fired local Effect = CreateAEmitter("APC Cannon Shot", "EDV.rte") if Effect then if self.HFlipped then Effect.Vel = self.Vel + Vector(-50, RangeRand(-3,3)):RadRotate(self.Barrel.RotAngle) else Effect.Vel = self.Vel + Vector(50, RangeRand(-3,3)):RadRotate(self.Barrel.RotAngle) end Effect.RotAngle = self.Barrel.RotAngle Effect.Pos = self.Barrel.MuzzlePos Effect:SetWhichMOToNotHit(self, 0.5) MovableMan:AddParticle(Effect) self.Barrel:AddImpulseForce(Vector(-900, 0):RadRotate(self.Barrel.RotAngle), Vector()) end end end -- update the ammo counter so this script can't spawn bullets until the gun has been fired again self.mainGunAmmo = self.Barrel.Magazine.RoundCount end if self:IsPlayerControlled() then if self.mgAmmo > 0 and self.Ctrl:IsState(Controller.BODY_JUMP) then fireCoAx = true elseif self.Ctrl:IsState(Controller.BODY_CROUCH) and self.ConcreteTimer:IsPastSimMS(90) then self.ConcreteTimer:Reset() local Emitter = CreateAEmitter("Concrete Emitter", "EDV.rte") Emitter.Vel = self.Vel Emitter.Pos = self.Pos + self:RotateOffset(Vector(43, 9)) if self.HFlipped then Emitter.RotAngle = self.RotAngle + 3.64 else Emitter.RotAngle = self.RotAngle - 0.50 end MovableMan:AddParticle(Emitter) end elseif self.Ctrl:IsState(Controller.WEAPON_FIRE) then fireCoAx = true -- let the AI fire the co-ax end if fireCoAx and self.GunTimer:IsPastSimMS(self.timing) then self.GunTimer:Reset() local bulletType = "MG Flash" if self.mgAmmo % 4 == 0 then bulletType = "MG Flash Tracer" end local Emitter = CreateAEmitter(bulletType, "EDV.rte") if Emitter then if self.HFlipped then Emitter.RotAngle = self.Barrel.RotAngle + 3.14 else Emitter.RotAngle = self.Barrel.RotAngle end Emitter.Vel = self.Vel Emitter.Pos = self.Barrel.Pos + self.Barrel:RotateOffset(Vector(13, -10)) Emitter:SetWhichMOToNotHit(self, -1) MovableMan:AddParticle(Emitter) end self.mgAmmo = self.mgAmmo - 1 if self.mgAmmo < 1 then self.timing = self.rot self.mgAmmo = self.maxMgAmmo Emitter = CreateAEmitter("Magazine Emitter", "EDV.rte") if Emitter then Emitter.Vel = self.Vel Emitter.Pos = self.Turret.Pos + self.Turret:RotateOffset(Vector(0, -12)) if self.HFlipped then Emitter.RotAngle = self.Turret.RotAngle + 1.2 else Emitter.RotAngle = self.Turret.RotAngle + 2.1 end MovableMan:AddParticle(Emitter) end else self.timing = self.rof end end end else self.Health = self.Health - 1 -- no turret end end function UpdateAI(self) self.AI:Update(self) end --[[ ArmoredCarBehaviors = {} -- open fire on the selected target function ArmoredCarBehaviors.ShootTarget(self) if not MovableMan:IsActor(self.Target) then return true end local TargetAvgVel = self.Target.Vel local ShootTimer = Timer() local aimTime = RangeRand(600, 1000) local aimError = RangeRand(-0.2, 0.2) local AimPoint while self.Turret:IsAttached() and self.Barrel:IsAttached() do if self.FirearmIsReady then TargetAvgVel = TargetAvgVel * 0.4 + self.Target.Vel * 0.6 -- filter the target's velocity if not self.flying then self.deviceState = ACrab.AIMING end if SceneMan:ShortestDistance(self.Pos, AimPoint or self.Target.Pos, false).Magnitude < 40 then AimPoint = self.Target.Pos + self.TargetOffset * 0.9 -- move the aimpoint closer to the center of the target at close ranges else AimPoint = self.Target.Pos + self.TargetOffset end aim = HumanAI.GetHitAngle(AimPoint, TargetAvgVel/RangeRand(0.2, 4.0), self.Barrel.Pos, 50) if aim then self.Ctrl.AnalogAim = Vector(1,0):RadRotate(aim+aimError+RangeRand(-0.018, 0.018)) else break -- target out of range end if ShootTimer:IsPastSimMS(aimTime) then self.fire = true aimError = aimError * RangeRand(0.95, 0.99) else self.fire = false end else self.deviceState = ACrab.POINTING self.fire = false ShootTimer:Reset() if self.FirearmIsEmpty then self:ReloadFirearm() aimTime = RangeRand(400, 700) aimError = RangeRand(-0.14, 0.14) else break -- no firearm avaliable end end coroutine.yield() -- wait until next frame if not MovableMan:IsActor(self.Target) then break end end return true end]]