mirror of
https://github.com/lifestorm/wnsrc.git
synced 2025-12-17 13:53:45 +03:00
Upload
This commit is contained in:
611
lua/entities/aw2_dropship.lua
Normal file
611
lua/entities/aw2_dropship.lua
Normal file
@@ -0,0 +1,611 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
AddCSLuaFile()
|
||||
|
||||
ENT.Type = "anim"
|
||||
ENT.Base = "base_gmodentity"
|
||||
|
||||
ENT.PrintName = "Combine Dropship"
|
||||
ENT.Category = "Airwatch 2"
|
||||
|
||||
ENT.Spawnable = true
|
||||
ENT.AdminOnly = true
|
||||
|
||||
ENT.AutomaticFrameAdvance = true
|
||||
|
||||
ENT.useGunner = false
|
||||
|
||||
ENT.firstPersonOffset = Vector(110, 50, 40)
|
||||
ENT.thirdPersonOffset = Vector(-800, 0, 100)
|
||||
|
||||
ENT.baseAttach = 1
|
||||
ENT.barrelAttach = 2
|
||||
|
||||
ENT.pitchIndex = 0
|
||||
ENT.yawIndex = 1
|
||||
|
||||
ENT.accuracy = 0.02
|
||||
ENT.damage = 15
|
||||
ENT.delay = 0.1
|
||||
|
||||
util.PrecacheSound("NPC_CombineDropship.NearRotorLoop")
|
||||
util.PrecacheSound("NPC_CombineDropship.OnGroundRotorLoop")
|
||||
util.PrecacheSound("NPC_CombineDropship.DescendingWarningLoop")
|
||||
util.PrecacheSound("NPC_CombineDropship.FireLoop")
|
||||
|
||||
function ENT:SpawnFunction(ply, tr, className)
|
||||
if not tr.Hit then
|
||||
return
|
||||
end
|
||||
|
||||
local spawnPos = tr.HitPos + tr.HitNormal * 120
|
||||
|
||||
local ent = ents.Create(className)
|
||||
ent:Spawn()
|
||||
ent:Activate()
|
||||
|
||||
ent:SetPos(spawnPos)
|
||||
|
||||
ent.Owner = ply
|
||||
|
||||
return ent
|
||||
end
|
||||
|
||||
function ENT:SetupDataTables()
|
||||
self:NetworkVar("Entity", 0, "GunOperator")
|
||||
self:NetworkVar("Entity", 1, "Pod")
|
||||
|
||||
self:NetworkVar("Int", 0, "SpeedMult")
|
||||
end
|
||||
|
||||
function ENT:Think()
|
||||
local phys = self:GetPhysicsObject()
|
||||
|
||||
if phys:IsValid() then
|
||||
phys:Wake()
|
||||
end
|
||||
|
||||
if SERVER then
|
||||
self:aimGun()
|
||||
self:weaponThink()
|
||||
|
||||
local ply = self.driver
|
||||
|
||||
if ply and ply:IsValid() or GetConVar("aw2_alwayson"):GetBool() then
|
||||
if not self.isActive then
|
||||
self:enableEffects()
|
||||
self.isActive = true
|
||||
end
|
||||
else
|
||||
if self.isActive then
|
||||
self:disableEffects()
|
||||
self.isActive = false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
self:NextThink(CurTime())
|
||||
return true
|
||||
end
|
||||
|
||||
function ENT:hasLOS()
|
||||
local ply = self:GetGunOperator()
|
||||
|
||||
if ply and ply:IsValid() then
|
||||
local hitpos = self:getHitpos(ply)
|
||||
|
||||
local barrel = self:GetPod():GetAttachment(self.barrelAttach)
|
||||
|
||||
local dot = barrel.Ang:Forward():Dot((hitpos - barrel.Pos):GetNormalized())
|
||||
|
||||
if dot >= 0.95 then
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
function ENT:getViewData(ply)
|
||||
if not ply:IsValid() then
|
||||
return
|
||||
end
|
||||
|
||||
local eyeAng = ply:EyeAngles()
|
||||
|
||||
-- Hours wasted on trying to find what the issue was: 4.5
|
||||
-- Hours wasted on trying to fix the issue before finding out the fix was the issue: Too many
|
||||
if SERVER then
|
||||
eyeAng = self:WorldToLocalAngles(eyeAng) -- Note to self: NEVER subtract angles when you can WorldToLocal/LocalToWorld
|
||||
end
|
||||
|
||||
local thirdperson = ply:GetVehicle():GetThirdPersonMode()
|
||||
|
||||
local pos, ang
|
||||
|
||||
if thirdperson then
|
||||
local trace = util.TraceLine({
|
||||
start = self:GetPos(),
|
||||
endpos = self:GetPos() + eyeAng:Up() * self.thirdPersonOffset.z + eyeAng:Forward() * self.thirdPersonOffset.x,
|
||||
filter = {self, self:GetPod()},
|
||||
mask = MASK_SOLID_BRUSHONLY
|
||||
})
|
||||
|
||||
pos = trace.HitPos + trace.HitNormal * 5
|
||||
ang = eyeAng
|
||||
else
|
||||
local entAng = self:GetAngles()
|
||||
|
||||
entAng.p = 0
|
||||
entAng.r = 0
|
||||
|
||||
local offset = self.firstPersonOffset
|
||||
|
||||
pos = self:LocalToWorld(offset)
|
||||
ang = eyeAng
|
||||
end
|
||||
|
||||
return pos, ang
|
||||
end
|
||||
|
||||
function ENT:getHitpos(ply)
|
||||
local pos, ang = self:getViewData(ply)
|
||||
|
||||
return util.QuickTrace(pos, ang:Forward() * 10000, {self, self:GetPod()}).HitPos
|
||||
end
|
||||
|
||||
function ENT:CanPhysgun(ply)
|
||||
if ply and ply:IsValid() then
|
||||
return ply:IsAdmin()
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
if SERVER then
|
||||
function ENT:Initialize()
|
||||
self:SetModel("models/Combine_dropship.mdl")
|
||||
self:ResetSequence("cargo_hover")
|
||||
|
||||
self:PhysicsInit(SOLID_VPHYSICS)
|
||||
self:SetMoveType(MOVETYPE_VPHYSICS)
|
||||
self:SetSolid(SOLID_VPHYSICS)
|
||||
|
||||
self:SetUseType(SIMPLE_USE)
|
||||
|
||||
local phys = self:GetPhysicsObject()
|
||||
|
||||
if phys:IsValid() then
|
||||
phys:SetMass(500000)
|
||||
end
|
||||
|
||||
local pod = ents.Create("prop_dynamic")
|
||||
pod:SetModel("models/combine_dropship_container.mdl")
|
||||
pod:SetPos(self:GetPos())
|
||||
pod:SetAngles(self:GetAngles())
|
||||
pod:SetParent(self)
|
||||
pod:Spawn()
|
||||
pod:Activate()
|
||||
|
||||
self:DeleteOnRemove(pod)
|
||||
|
||||
self:SetPod(pod)
|
||||
|
||||
self.seatDriver = ents.Create("prop_vehicle_prisoner_pod")
|
||||
self.seatDriver:SetModel("models/props_lab/cactus.mdl")
|
||||
self.seatDriver:SetPos(self:GetPos())
|
||||
self.seatDriver:SetAngles(self:GetAngles())
|
||||
self.seatDriver:SetSolid(SOLID_NONE)
|
||||
self.seatDriver:SetKeyValue("limitview", 0, 0)
|
||||
self.seatDriver:SetNoDraw(true)
|
||||
self.seatDriver:Spawn()
|
||||
self.seatDriver:SetParent(self)
|
||||
self.seatDriver:SetNotSolid(true)
|
||||
|
||||
self:DeleteOnRemove(self.seatDriver)
|
||||
|
||||
self.seatDriver.aw2Ent = self
|
||||
|
||||
if self.useGunner then
|
||||
self.seatGunner = ents.Create("prop_vehicle_prisoner_pod")
|
||||
self.seatGunner:SetModel("models/props_lab/cactus.mdl")
|
||||
self.seatGunner:SetPos(self:GetPos())
|
||||
self.seatGunner:SetAngles(self:GetAngles())
|
||||
self.seatGunner:SetSolid(SOLID_NONE)
|
||||
self.seatGunner:SetKeyValue("limitview", 0, 0)
|
||||
self.seatGunner:SetNoDraw(true)
|
||||
self.seatGunner:Spawn()
|
||||
self.seatGunner:SetParent(self)
|
||||
self.seatGunner:SetNotSolid(true)
|
||||
|
||||
self:DeleteOnRemove(self.seatGunner)
|
||||
|
||||
self.seatGunner.aw2Ent = self
|
||||
end
|
||||
|
||||
self:StartMotionController()
|
||||
|
||||
self:SetPlaybackRate(0)
|
||||
|
||||
self:SetBodygroup(1, 1)
|
||||
|
||||
self.driver, self.gunner = nil
|
||||
|
||||
self.storedPos = Vector(0, 0, 0)
|
||||
self.storedVel = Vector(0, 0, 0)
|
||||
|
||||
self.storedPitch = 0
|
||||
self.storedYaw = 0
|
||||
|
||||
self.isActive = false
|
||||
self.isFiring = false
|
||||
|
||||
self.nextShot = 0
|
||||
|
||||
self.passengers = {}
|
||||
|
||||
self:SetSpeedMult(GetConVar("aw2_dropship_speedmult"):GetInt())
|
||||
end
|
||||
|
||||
function ENT:Use(ply)
|
||||
local sequence = self:GetPod():GetSequenceName(self:GetPod():GetSequence())
|
||||
|
||||
if not self.driver then
|
||||
ply:EnterVehicle(self.seatDriver)
|
||||
ply:SetNoDraw(true)
|
||||
|
||||
self.driver = ply
|
||||
|
||||
if not self.useGunner then
|
||||
self:SetGunOperator(ply)
|
||||
end
|
||||
|
||||
ply.aw2Ent = self
|
||||
|
||||
net.Start("aw2Enter")
|
||||
net.WriteEntity(self)
|
||||
net.Send(ply)
|
||||
elseif self.useGunner and not self.gunner then
|
||||
ply:EnterVehicle(self.seatGunner)
|
||||
ply:SetNoDraw(true)
|
||||
|
||||
self.gunner = ply
|
||||
self:SetGunOperator(ply)
|
||||
|
||||
ply.aw2Ent = self
|
||||
|
||||
net.Start("aw2Enter")
|
||||
net.WriteEntity(self)
|
||||
net.Send(ply)
|
||||
elseif sequence == "open_idle" then
|
||||
local seat = ents.Create("prop_vehicle_prisoner_pod")
|
||||
seat:SetModel("models/props_lab/cactus.mdl")
|
||||
seat:SetPos(self:GetPos())
|
||||
seat:SetAngles(self:GetAngles())
|
||||
seat:SetSolid(SOLID_NONE)
|
||||
seat:SetKeyValue("limitview", 0, 0)
|
||||
seat:SetNoDraw(true)
|
||||
seat:Spawn()
|
||||
seat:SetParent(self)
|
||||
seat:SetNotSolid(true)
|
||||
|
||||
self:DeleteOnRemove(seat)
|
||||
|
||||
seat.aw2Ent = self
|
||||
|
||||
table.insert(self.passengers, seat)
|
||||
|
||||
ply:EnterVehicle(seat)
|
||||
ply:SetNoDraw(true)
|
||||
|
||||
ply.aw2Ent = self
|
||||
|
||||
net.Start("aw2Enter")
|
||||
net.WriteEntity(self)
|
||||
net.Send(ply)
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:OnRemove()
|
||||
self:StopSound("NPC_CombineDropship.NearRotorLoop")
|
||||
self:StopSound("NPC_CombineDropship.OnGroundRotorLoop")
|
||||
self:StopSound("NPC_CombineDropship.DescendingWarningLoop")
|
||||
self:StopSound("NPC_CombineDropship.FireLoop")
|
||||
end
|
||||
|
||||
function ENT:enableEffects()
|
||||
self.wash = ents.Create("env_rotorwash_emitter")
|
||||
self.wash:SetPos(self:GetPos())
|
||||
self.wash:SetAngles(self:GetAngles())
|
||||
self.wash:SetParent(self)
|
||||
self.wash:Spawn()
|
||||
|
||||
self:EmitSound("NPC_CombineDropship.OnGroundRotorLoop")
|
||||
self:EmitSound("NPC_CombineDropship.NearRotorLoop")
|
||||
|
||||
self:ResetSequence("cargo_idle")
|
||||
self:SetPlaybackRate(1)
|
||||
|
||||
self:SetBodygroup(1, 0)
|
||||
end
|
||||
|
||||
function ENT:disableEffects()
|
||||
if self.wash and self.wash:IsValid() then
|
||||
self.wash:Remove()
|
||||
end
|
||||
|
||||
self:GetPod():ResetSequence("idle")
|
||||
self:StopSound("NPC_CombineDropship.DescendingWarningLoop")
|
||||
|
||||
self:StopSound("NPC_CombineDropship.OnGroundRotorLoop")
|
||||
self:StopSound("NPC_CombineDropship.NearRotorLoop")
|
||||
|
||||
self:ResetSequence("cargo_hover")
|
||||
self:SetPlaybackRate(0)
|
||||
|
||||
self:SetBodygroup(1, 1)
|
||||
end
|
||||
|
||||
function ENT:weaponThink()
|
||||
local ply = self:GetGunOperator()
|
||||
|
||||
if not ply or not ply:IsValid() then
|
||||
return
|
||||
end
|
||||
|
||||
local fire = ply:KeyDown(IN_ATTACK) and not ply:KeyDown(IN_RELOAD) and self:hasLOS()
|
||||
|
||||
if fire then
|
||||
if self.nextShot <= CurTime() then
|
||||
self.nextShot = CurTime() + self.delay
|
||||
|
||||
local bullet = {}
|
||||
bullet.Num = 1
|
||||
bullet.Src = self:GetPod():GetAttachment(self.barrelAttach).Pos
|
||||
bullet.Dir = (self:getHitpos(ply) - self:GetPod():GetAttachment(self.barrelAttach).Pos):GetNormalized():Angle():Forward()
|
||||
bullet.Spread = Vector(self.accuracy, self.accuracy, 0)
|
||||
bullet.Tracer = 1
|
||||
bullet.TracerName = "HelicopterTracer"
|
||||
bullet.Force = 20
|
||||
bullet.Damage = self.damage
|
||||
bullet.Attacker = ply
|
||||
bullet.Callback = function(attacker, trace, dmginfo)
|
||||
if not trace.HitPos or not trace.HitNormal then
|
||||
return
|
||||
end
|
||||
|
||||
dmginfo:SetDamageType(DMG_AIRBOAT)
|
||||
|
||||
local e = EffectData()
|
||||
e:SetOrigin(trace.HitPos)
|
||||
e:SetNormal(trace.HitNormal)
|
||||
util.Effect("AR2Impact", e)
|
||||
end
|
||||
|
||||
self:GetPod():FireBullets(bullet)
|
||||
|
||||
local effectData = EffectData()
|
||||
effectData:SetOrigin(self:GetPod():GetAttachment(self.barrelAttach).Pos)
|
||||
effectData:SetAngles(self:GetPod():GetAttachment(self.barrelAttach).Ang)
|
||||
effectData:SetEntity(self:GetPod())
|
||||
|
||||
util.Effect("ChopperMuzzleFlash", effectData)
|
||||
|
||||
if not self.isFiring then
|
||||
self:EmitSound("NPC_CombineDropship.FireLoop")
|
||||
|
||||
self.isFiring = true
|
||||
end
|
||||
end
|
||||
elseif self.isFiring then
|
||||
self:StopSound("NPC_CombineDropship.FireLoop")
|
||||
|
||||
self.isFiring = false
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:keyPress(ply, key)
|
||||
if ply == self.driver and key == IN_RELOAD then
|
||||
local pod = self:GetPod()
|
||||
|
||||
local sequence = pod:GetSequenceName(pod:GetSequence())
|
||||
|
||||
if sequence == "idle" then
|
||||
pod:ResetSequence("open_idle")
|
||||
self:EmitSound("NPC_CombineDropship.DescendingWarningLoop")
|
||||
else
|
||||
pod:ResetSequence("idle")
|
||||
self:StopSound("NPC_CombineDropship.DescendingWarningLoop")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:aimGun()
|
||||
local ply = self:GetGunOperator()
|
||||
local pod = self:GetPod()
|
||||
|
||||
local pitch = 0
|
||||
local yaw = 0
|
||||
|
||||
if ply and ply:IsValid() then
|
||||
-- Thanks wiremod
|
||||
local rad2deg = 180 / math.pi
|
||||
|
||||
local pos, _ = WorldToLocal(self:getHitpos(ply), self:GetAngles(), pod:GetAttachment(self.baseAttach).Pos, self:GetAngles())
|
||||
local len = pos:Length()
|
||||
|
||||
if len < 0.0000001000000 then
|
||||
pitch = 0
|
||||
else
|
||||
pitch = rad2deg * math.asin(pos.z / len)
|
||||
end
|
||||
|
||||
yaw = rad2deg * math.atan2(pos.y, pos.x)
|
||||
end
|
||||
|
||||
local pitchMin, pitchMax = pod:GetPoseParameterRange(self.pitchIndex)
|
||||
local yawMin, yawMax = pod:GetPoseParameterRange(self.yawIndex)
|
||||
|
||||
pitch = math.Clamp(pitch, pitchMin, pitchMax)
|
||||
yaw = math.Clamp(yaw, yawMin, yawMax)
|
||||
|
||||
pod:SetPoseParameter("weapon_pitch", pitch)
|
||||
pod:SetPoseParameter("weapon_yaw", yaw)
|
||||
end
|
||||
|
||||
function ENT:ejectPlayer(ply, vehicle)
|
||||
ply:SetNoDraw(false)
|
||||
|
||||
ply.aw2Ent = nil
|
||||
|
||||
net.Start("aw2Eject")
|
||||
net.Send(ply)
|
||||
|
||||
if self.driver == ply then
|
||||
self.driver = nil
|
||||
|
||||
if not self.useGunner then
|
||||
self:SetGunOperator(nil)
|
||||
end
|
||||
elseif self.gunner == ply then
|
||||
self.gunner = nil
|
||||
|
||||
self:SetGunOperator(nil)
|
||||
else
|
||||
for k, v in pairs(self.passengers) do
|
||||
if v == vehicle then
|
||||
table.remove(self.passengers, k)
|
||||
vehicle:Remove()
|
||||
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local ang = Angle(0, self:GetAngles().y, 0)
|
||||
|
||||
ply:SetEyeAngles(ang)
|
||||
ply:SetPos(self:LocalToWorld(Vector(170, 0, -50)))
|
||||
ply:SetVelocity(self:GetVelocity())
|
||||
end
|
||||
|
||||
function ENT:PhysicsSimulate(phys, delta)
|
||||
local vel = phys:GetVelocity()
|
||||
|
||||
local localVel = WorldToLocal(phys:GetVelocity(), Angle(), Vector(), phys:GetAngles())
|
||||
|
||||
if self.isActive then
|
||||
local accel = self:GetPoseParameter("cargo_body_accel")
|
||||
accel = math.Approach(accel, math.Remap(localVel.x, 0, 1600, -0.7, 1), 0.04)
|
||||
|
||||
self:SetPoseParameter("cargo_body_accel", accel)
|
||||
|
||||
local sway = math.Remap(localVel.y, -800, 800, -1, 1)
|
||||
|
||||
self:SetPoseParameter("cargo_body_sway", -sway)
|
||||
else
|
||||
self:SetPoseParameter("cargo_body_accel", 0)
|
||||
self:SetPoseParameter("cargo_body_sway", 0)
|
||||
end
|
||||
|
||||
local desiredPitch = -(self.storedVel:Dot(self:GetForward()) - vel:Dot(self:GetForward())) * 3
|
||||
local desiredRoll = -(self.storedVel:Dot(self:GetRight()) - vel:Dot(self:GetRight())) * 3
|
||||
|
||||
local pLerp = 1 - math.sin(delta * math.pi * 0.5)
|
||||
|
||||
desiredPitch = Lerp(pLerp * delta + delta, self.storedPitch, desiredPitch)
|
||||
|
||||
self.storedPitch = desiredPitch
|
||||
self.storedVel = vel
|
||||
|
||||
local desiredPos = self:GetPos()
|
||||
local desiredYaw = self:GetAngles().y
|
||||
|
||||
local ply = self.driver
|
||||
|
||||
if ply and ply:IsValid() then
|
||||
local addPos = Vector(0, 0, 0)
|
||||
|
||||
if ply:KeyDown(IN_FORWARD) then
|
||||
addPos.x = 0.7
|
||||
elseif ply:KeyDown(IN_BACK) then
|
||||
addPos.x = -0.2
|
||||
end
|
||||
|
||||
if ply:KeyDown(IN_MOVELEFT) then
|
||||
addPos.y = 0.2
|
||||
elseif ply:KeyDown(IN_MOVERIGHT) then
|
||||
addPos.y = -0.2
|
||||
end
|
||||
|
||||
if ply:KeyDown(IN_JUMP) then
|
||||
addPos.z = 0.3
|
||||
elseif ply:KeyDown(IN_SPEED) then
|
||||
addPos.z = -0.3
|
||||
end
|
||||
|
||||
local ang = self:GetAngles()
|
||||
ang.r = 0
|
||||
ang.p = 0
|
||||
|
||||
if ply:KeyDown(IN_WALK) then
|
||||
desiredYaw = self.storedYaw
|
||||
else
|
||||
desiredYaw = self:WorldToLocalAngles(ply:EyeAngles()).y
|
||||
end
|
||||
|
||||
if ply:KeyDown(IN_WALK) then
|
||||
addPos:Rotate(Angle(0, self.storedYaw, 0))
|
||||
else
|
||||
addPos:Rotate(Angle(0, desiredYaw, 0))
|
||||
self.storedYaw = desiredYaw
|
||||
end
|
||||
|
||||
local mult = self:GetSpeedMult()
|
||||
|
||||
addPos:Mul(mult)
|
||||
|
||||
local dist = math.Clamp(self.storedPos:Distance(addPos), 0, mult)
|
||||
local time = math.Remap(dist, 0, mult, 0, 1)
|
||||
|
||||
local lerp = 1 - math.sin(time * math.pi * 0.5)
|
||||
|
||||
addPos = LerpVector(lerp * delta + (delta * 0.4), self.storedPos, addPos)
|
||||
|
||||
self.storedPos = addPos
|
||||
|
||||
desiredPos = desiredPos + addPos
|
||||
end
|
||||
|
||||
local randPos = Vector(math.sin(math.cos(CurTime())) * 10, math.sin(math.sin(CurTime())) * 10, 0)
|
||||
randPos:Rotate(self:GetAngles())
|
||||
|
||||
desiredPos = desiredPos + randPos
|
||||
|
||||
local move = {}
|
||||
move.secondstoarrive = 0.5
|
||||
move.pos = desiredPos
|
||||
move.angle = Angle(desiredPitch, desiredYaw, desiredRoll)
|
||||
move.maxangular = 12000
|
||||
move.maxangulardamp = 10000
|
||||
move.maxspeed = 12000
|
||||
move.maxspeeddamp = 10000
|
||||
move.dampfactor = 0.8
|
||||
move.teleportdistance = 0
|
||||
move.deltatime = delta
|
||||
|
||||
if ply and ply:IsValid() or GetConVar("aw2_alwayson"):GetBool() then
|
||||
phys:ComputeShadowControl(move)
|
||||
else
|
||||
self.storedPos = Vector(0, 0, 0)
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user