mirror of
https://github.com/lifestorm/wnsrc.git
synced 2025-12-17 05:43:46 +03:00
792 lines
31 KiB
Lua
792 lines
31 KiB
Lua
--[[
|
|
| 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("shared.lua")
|
|
include("shared.lua")
|
|
/*--------------------------------------------------
|
|
*** Copyright (c) 2012-2021 by DrVrej, All rights reserved. ***
|
|
No parts of this code or any of its contents may be reproduced, copied, modified or adapted,
|
|
without the prior written consent of the author, unless otherwise indicated for stand-alone materials.
|
|
--------------------------------------------------*/
|
|
ENT.Model = {"models/combine_dropship.mdl"}
|
|
ENT.StartHealth = 700
|
|
ENT.TurningSpeed = 10
|
|
ENT.SightAngle = 100
|
|
ENT.VJ_NPC_Class = {"CLASS_COMBINE"}
|
|
ENT.VJ_IsHugeMonster = true
|
|
ENT.Aerial_AnimTbl_Calm = {"cargo_idle"}
|
|
ENT.Aerial_AnimTbl_Alerted = {"cargo_idle"}
|
|
|
|
ENT.CallForHelpDistance = 10000
|
|
ENT.InvestigateSoundDistance = 18
|
|
|
|
ENT.HasMeleeAttack = false
|
|
|
|
ENT.HasRangeAttack = true
|
|
ENT.DisableDefaultRangeAttackCode = true
|
|
ENT.DisableRangeAttackAnimation = true
|
|
ENT.RangeAttackAngleRadius = 100
|
|
ENT.RangeDistance = 4000
|
|
ENT.RangeToMeleeDistance = 0
|
|
ENT.TimeUntilRangeAttackProjectileRelease = 0
|
|
ENT.NextRangeAttackTime = 6
|
|
|
|
ENT.Passive_RunOnTouch = false
|
|
ENT.Passive_RunOnDamage = false
|
|
ENT.Passive_AlliesRunOnDamage = false
|
|
|
|
ENT.MovementType = VJ_MOVETYPE_AERIAL
|
|
ENT.AA_GroundLimit = 500
|
|
ENT.Aerial_FlyingSpeed_Calm = 450
|
|
ENT.Aerial_FlyingSpeed_Alerted = 600
|
|
|
|
ENT.ConstantlyFaceEnemy = true
|
|
ENT.ConstantlyFaceEnemy_IfAttacking = true
|
|
ENT.ConstantlyFaceEnemyDistance = 10000
|
|
|
|
--ENT.SoundTbl_Breath = {"NPC_CombineDropship.NearRotorLoop"}
|
|
ENT.BreathSoundLevel = 90
|
|
|
|
ENT.DeathCorpseBodyGroup = VJ_Set(1, 1)
|
|
|
|
ENT.NextDustTime = 0
|
|
ENT.FlexForwardOutput = 0
|
|
ENT.NextSoldierTime = 18
|
|
ENT.SoldiersSpawned = 0
|
|
ENT.CurrentSoldierIdx = 1
|
|
|
|
local dropTables = {
|
|
{
|
|
{class="npc_vj_overwatch_soldier_z",weapon="weapon_vj_smg1"},
|
|
{class="npc_vj_overwatch_soldier_z",weapon="weapon_vj_smg1"},
|
|
{class="npc_vj_overwatch_soldier_z",weapon="weapon_vj_smg1"},
|
|
{class="npc_vj_overwatch_soldier_z",weapon="weapon_vj_ar2"},
|
|
{class="npc_vj_overwatch_shotgunner_z",weapon="weapon_vj_spas12_mk2_z"},
|
|
{class="npc_vj_overwatch_elite_z",weapon="weapon_vj_ar2"},
|
|
{class="npc_vj_overwatch_sniper_z",weapon="weapon_vj_combine_sniper_rifle_z"},
|
|
},
|
|
|
|
{
|
|
{class="npc_vj_overwatch_soldier_z",weapon="weapon_vj_smg1"},
|
|
{class="npc_vj_overwatch_soldier_z",weapon="weapon_vj_smg1"},
|
|
{class="npc_vj_overwatch_soldier_z",weapon="weapon_vj_smg1"},
|
|
{class="npc_vj_overwatch_soldier_z",weapon="weapon_vj_ar2"},
|
|
{class="npc_vj_overwatch_shotgunner_z",weapon="weapon_vj_spas12_mk2_z"},
|
|
{class="npc_vj_hunter2_z",weapon=""},
|
|
{class="npc_vj_hunter2_z",weapon=""},
|
|
},
|
|
|
|
{
|
|
{class="npc_vj_novaprospekt_soldier_z",weapon="weapon_vj_smg1"},
|
|
{class="npc_vj_novaprospekt_soldier_z",weapon="weapon_vj_smg1"},
|
|
{class="npc_vj_novaprospekt_soldier_z",weapon="weapon_vj_smg1"},
|
|
{class="npc_vj_novaprospekt_soldier_z",weapon="weapon_vj_smg1"},
|
|
{class="npc_vj_novaprospekt_soldier_z",weapon="weapon_vj_ar2"},
|
|
{class="npc_vj_novaprospekt_soldier_z",weapon="weapon_vj_ar2"},
|
|
{class="npc_vj_novaprospekt_shotgunner_z",weapon="weapon_vj_spas12_mk2_z"},
|
|
},
|
|
|
|
{
|
|
{class="npc_vj_civil_protection_z",weapon="weapon_vj_stunstick_z"},
|
|
{class="npc_vj_civil_protection_z",weapon="weapon_vj_9mmpistol"},
|
|
{class="npc_vj_civil_protection_z",weapon="weapon_vj_9mmpistol"},
|
|
{class="npc_vj_civil_protection_z",weapon="weapon_vj_9mmpistol"},
|
|
{class="npc_vj_civil_protection_z",weapon="weapon_vj_smg1"},
|
|
{class="npc_vj_civil_protection_elite_z",weapon="weapon_vj_mp5k_z"},
|
|
{class="npc_vj_civil_protection_elite_z",weapon="weapon_vj_mp5k_z"},
|
|
},
|
|
|
|
{
|
|
{class="npc_vj_rollermine_z",weapon=""},
|
|
{class="npc_vj_rollermine_z",weapon=""},
|
|
{class="npc_vj_rollermine_z",weapon=""},
|
|
{class="npc_vj_rollermine_z",weapon=""},
|
|
{class="npc_vj_rollermine_z",weapon=""},
|
|
{class="npc_vj_rollermine_z",weapon=""},
|
|
{class="npc_vj_rollermine_z",weapon=""},
|
|
},
|
|
|
|
{
|
|
{class="npc_vj_rollermine_explosive_z",weapon=""},
|
|
{class="npc_vj_rollermine_explosive_z",weapon=""},
|
|
{class="npc_vj_rollermine_explosive_z",weapon=""},
|
|
{class="npc_vj_rollermine_explosive_z",weapon=""},
|
|
{class="npc_vj_rollermine_explosive_z",weapon=""},
|
|
{class="npc_vj_rollermine_explosive_z",weapon=""},
|
|
{class="npc_vj_rollermine_explosive_z",weapon=""},
|
|
},
|
|
|
|
{
|
|
{class="npc_vj_vortigaunt_synth_z",weapon=""},
|
|
{class="npc_vj_vortigaunt_synth_z",weapon=""},
|
|
{class="npc_vj_vortigaunt_synth_z",weapon=""},
|
|
{class="npc_vj_vortigaunt_synth_z",weapon=""},
|
|
{class="npc_vj_vortigaunt_synth_z",weapon=""},
|
|
},
|
|
|
|
{
|
|
{class="npc_vj_hunter2_z",weapon=""},
|
|
{class="npc_vj_hunter2_z",weapon=""},
|
|
{class="npc_vj_hunter2_z",weapon=""},
|
|
},
|
|
|
|
{
|
|
{class="npc_vj_combine_apc_z",weapon=""},
|
|
},
|
|
|
|
{
|
|
{class="npc_vj_overwatch_assassin_z",weapon="weapon_vj_assassin_pistols_z"},
|
|
{class="npc_vj_overwatch_assassin_z",weapon="weapon_vj_assassin_pistols_z"},
|
|
{class="npc_vj_overwatch_assassin_z",weapon="weapon_vj_assassin_pistols_z"},
|
|
{class="npc_vj_assassin_synth_z",weapon=""},
|
|
{class="npc_vj_assassin_synth_z",weapon=""},
|
|
},
|
|
|
|
{
|
|
{class="npc_vj_strider_synth_z",weapon=""},
|
|
},
|
|
}
|
|
|
|
function ENT:Controller_IntMsg(ply, controlEnt)
|
|
|
|
ply:ChatPrint("NOTE: Controlling is not really supported for this SNPC!!")
|
|
|
|
end
|
|
|
|
function ENT:CustomOnInitialize()
|
|
|
|
local dropidx = math.Clamp(GetConVar("vj_zippycombines_dropship_snpcs"):GetInt(), 0,11)
|
|
if dropidx == 0 then
|
|
dropidx = math.random(1, 11)
|
|
end
|
|
self.DropTable = dropTables[dropidx]
|
|
|
|
-- self.SoldierAmount = 7
|
|
-- if dropidx == 7 then -- Vorts
|
|
-- self.SoldierAmount = 5
|
|
-- elseif dropidx == 8 then -- Hunters
|
|
-- self.SoldierAmount = 3
|
|
-- end
|
|
|
|
timer.Simple(0,function() self:SetPos( self:GetPos() + Vector(0,0,200) ) end)
|
|
|
|
self.AnimTbl_IdleStand = {self:GetSequenceActivity(self:LookupSequence("cargo_idle"))}
|
|
--self:EmitSound( "NPC_CombineDropship.RotorLoop", 100, 100)
|
|
|
|
if dropidx == 9 then
|
|
self.APC = ents.Create("prop_dynamic")
|
|
self.APC:SetModel("models/combine_apc.mdl")
|
|
self.APC:SetParent(self)
|
|
self.APC:SetPos(self:GetPos() - self:GetUp()*15)
|
|
self.APC:SetAngles(self:GetAngles()+Angle(0,-90,0))
|
|
|
|
self.DeployDist = 750
|
|
|
|
self:SetCollisionBounds( Vector (160,160,150) , Vector (-160,-160,50) )
|
|
elseif dropidx == 11 then
|
|
self.Strider = ents.Create("prop_dynamic")
|
|
self.Strider:SetModel("models/combine_strider.mdl")
|
|
self.Strider:SetParent(self)
|
|
self.Strider:SetPos(self:GetPos() - self:GetUp()*100)
|
|
self.Strider:SetAngles(self:GetAngles())
|
|
self.Strider:ResetSequence("carried")
|
|
|
|
self.DeployDist = 1500
|
|
|
|
self:SetCollisionBounds( Vector (160,160,150) , Vector (-160,-160,50) )
|
|
else
|
|
self.Container = ents.Create("prop_dynamic")
|
|
self.Container:SetModel("models/combine_dropship_container.mdl")
|
|
self.Container:SetParent(self)
|
|
self.Container:SetPos(self:GetPos())
|
|
self.Container:SetAngles(self:GetAngles())
|
|
|
|
self.ContainerPhys = ents.Create("prop_dynamic")
|
|
self.ContainerPhys:SetModel("models/props_wasteland/cargo_container01b.mdl")
|
|
self.ContainerPhys:SetParent(self.Container)
|
|
self.ContainerPhys:SetPos(self.Container:GetPos() + self.Container:GetForward() * -50 + self.Container:GetUp() * 15)
|
|
self.ContainerPhys:SetAngles(self.Container:GetAngles() + Angle(0,90,0))
|
|
self.ContainerPhys:SetNoDraw(true)
|
|
self.ContainerPhys:DrawShadow(false)
|
|
|
|
self.DeployDist = 1750
|
|
|
|
self:SetCollisionBounds( Vector (75,100,200) , Vector (-150,-100,-40) )
|
|
end
|
|
|
|
self.AngleNoiseOffset = math.Rand(0, 2*math.pi)
|
|
self.pitchAdd_NoiseSpeedOffset = math.Rand(0.9, 1.1)
|
|
self.rollAdd_NoiseSpeedOffset = math.Rand(0.9, 1.1)
|
|
|
|
self.MoveNoiseOffset = math.Rand(0,2*math.pi)
|
|
self.MoveX_NoiseSpeedOffset = math.Rand(0.9, 1.1)
|
|
self.MoveY_NoiseSpeedOffset = math.Rand(0.9, 1.1)
|
|
self.MoveZ_NoiseSpeedOffset = math.Rand(0.9, 1.1)
|
|
|
|
self.CurrentAimPoseParamAng = Angle(0,0,0)
|
|
|
|
self.EngineSound1 = CreateSound(self,"npc/combine_gunship/dropship_engine_distant_loop1.wav")
|
|
self.EngineSound1:SetSoundLevel(130)
|
|
self.EngineSound1:Play()
|
|
self.EngineSound1:ChangePitch(90)
|
|
self.EngineSound1:ChangeVolume(0.75)
|
|
|
|
self.EngineSound2 = CreateSound(self,"npc/combine_gunship/dropship_onground_loop1.wav")
|
|
self.EngineSound2:SetSoundLevel(100)
|
|
self.EngineSound2:Play()
|
|
self.EngineSound2:ChangePitch(110)
|
|
|
|
self.ShootSound = CreateSound(self,"npc/combine_gunship/gunship_fire_loop1.wav")
|
|
self.ShootSound:SetSoundLevel(130)
|
|
|
|
self.AlarmSound = CreateSound(self,"npc/combine_gunship/dropship_dropping_pod_loop1.wav")
|
|
self.AlarmSound:SetSoundLevel(120)
|
|
end
|
|
|
|
function ENT:MovementThink()
|
|
|
|
local sin = math.sin
|
|
local time = CurTime()
|
|
|
|
local AngleNoiseSpeedMult = 2
|
|
local pitchAdd_noise = sin(time*self.pitchAdd_NoiseSpeedOffset*AngleNoiseSpeedMult + self.AngleNoiseOffset)
|
|
local rollAdd_noise = sin(time*self.rollAdd_NoiseSpeedOffset*AngleNoiseSpeedMult + self.AngleNoiseOffset)
|
|
|
|
if self.ContainerDeployed or self.IsDeployingContainer or self.DeployingAPC or self.DeployingStrider or self.StriderUnfolding then
|
|
self:SetAngles(self.DeployAngle)
|
|
else
|
|
self:SetAngles( self:GetAngles() + Angle(pitchAdd_noise*0.5, 0, rollAdd_noise*0.5) )
|
|
end
|
|
|
|
local MoveNoiseIntensity = 15
|
|
local move_x_noise = sin(time*self.MoveX_NoiseSpeedOffset + self.MoveNoiseOffset)
|
|
local move_y_noise = sin(time*self.MoveY_NoiseSpeedOffset + self.MoveNoiseOffset)
|
|
local move_z_noise = sin(time*self.MoveZ_NoiseSpeedOffset + self.MoveNoiseOffset)
|
|
|
|
if self.AA_CurrentMovePos or self.MovementType == VJ_MOVETYPE_STATIONARY then
|
|
self:SetVelocity( Vector(move_x_noise,move_y_noise,move_z_noise)*MoveNoiseIntensity )
|
|
else
|
|
self:SetLocalVelocity( Vector(move_x_noise,move_y_noise,move_z_noise)*MoveNoiseIntensity )
|
|
end
|
|
|
|
end
|
|
|
|
function ENT:CustomOnThink()
|
|
|
|
self:MovementThink()
|
|
|
|
if IsValid(self.Soldier) && self.ContainerDeployed && self.DropshipDropPoint && self.Soldier:GetPos():Distance(self.DropshipDropPoint) < 175 then
|
|
|
|
local dir = (self.Soldier:GetPos() - self.DropshipDropPoint):GetNormalized()
|
|
|
|
local soldierclass = self.Soldier:GetClass()
|
|
|
|
if soldierclass != "npc_vj_rollermine_z" && soldierclass != "npc_vj_rollermine_explosive_z" then
|
|
self.Soldier:SetVelocity( Vector(dir.x ,dir.y ,0) * 300 )
|
|
self.Soldier:SetAngles(Angle(0,self.Container:GetAngles().y,0))
|
|
end
|
|
|
|
end
|
|
|
|
-- local tr = util.TraceLine({
|
|
-- start = self:GetPos(),
|
|
-- endpos = self:GetPos() + self:GetUp() * -10000,
|
|
-- mask = MASK_NPCWORLDSTATIC,
|
|
-- })
|
|
-- if self.NextDustTime != 0 then
|
|
-- self.NextDustTime = self.NextDustTime - 1
|
|
-- end
|
|
-- if self:GetPos():Distance(tr.HitPos) <= 400 && self.NextDustTime == 0 then
|
|
-- if !self.CloseToGround then
|
|
-- self.CloseToGround = true
|
|
-- self:EmitSound("NPC_CombineDropship.OnGroundRotorLoop", 100, 100)
|
|
-- end
|
|
-- self.NextDustTime = 2
|
|
-- local effectdata = EffectData()
|
|
-- effectdata:SetOrigin(tr.HitPos)
|
|
-- effectdata:SetEntity( self )
|
|
-- effectdata:SetScale( 90 )
|
|
-- util.Effect( "ThumperDust", effectdata )
|
|
-- elseif self:GetPos():Distance(tr.HitPos) > 400 && self.CloseToGround then
|
|
-- self.CloseToGround = false
|
|
-- self:EmitSound("NPC_CombineDropship.OnGroundRotorLoop", 100, 100, 1, CHAN_AUTO, SND_STOP)
|
|
-- end
|
|
|
|
end
|
|
|
|
function ENT:IsOnGroundCheck()
|
|
|
|
self.DroppingContainer = true
|
|
timer.Simple(1.5,function() if IsValid(self) then
|
|
|
|
local center = self:OBBCenter()
|
|
local OBBmins = self:OBBMins() * 0.66
|
|
local OBBmaxs = self:OBBMaxs() * 0.66
|
|
|
|
local tr_FINAL = util.TraceHull({
|
|
start = self:GetPos() + Vector(center.x,center.y,center.z),
|
|
endpos = self:GetPos() + Vector(center.x,center.y,center.z - 110),
|
|
mins = OBBmins,
|
|
maxs = OBBmaxs,
|
|
filter = self,
|
|
})
|
|
|
|
if tr_FINAL.HitWorld or self:IsOnGround() then
|
|
|
|
--print("tr_FINAL.HitWorld: " .. tostring(tr_FINAL.HitWorld))
|
|
--print("self:IsOnGround(): " .. tostring(self:IsOnGround()))
|
|
|
|
self.Behavior = VJ_BEHAVIOR_PASSIVE
|
|
self:SetCollisionBounds( Vector (160,160,150) , Vector (-160,-160,50) )
|
|
self.Container:ResetSequence(self.Container:LookupSequence("open"))
|
|
self.ContainerDeployed = true
|
|
self.IsDeployingContainer = false
|
|
self.Container:SetParent(nil)
|
|
self:VJ_ACT_PLAYACTIVITY("idle",true,1,false)
|
|
self.AnimTbl_IdleStand = {self:GetSequenceActivity(self:LookupSequence("idle"))}
|
|
self.Aerial_AnimTbl_Calm = {"idle"}
|
|
self.Aerial_AnimTbl_Alerted = {"idle"}
|
|
--ZIPPYCOMBINES_FadeAndRemove(self.Container,30)
|
|
else
|
|
self.DroppingContainer = false
|
|
end
|
|
end end)
|
|
|
|
end
|
|
|
|
local strider_deploydist_ground = 625
|
|
|
|
function ENT:DeployFinish()
|
|
|
|
self.AlarmSound:Stop()
|
|
self.ContainerDeployed = false
|
|
self.ContainerUsed = true
|
|
self.DropshipDropPoint = nil
|
|
|
|
if self.Container then
|
|
self.Container:ResetSequence(self.Container:LookupSequence("close"))
|
|
self.Container:SetParent(self)
|
|
self.Container:SetPos(self:GetPos())
|
|
self.Container:SetAngles(self:GetAngles())
|
|
self.ContainerPhys:Remove()
|
|
self:VJ_ACT_PLAYACTIVITY("cargo_idle",true,1,false)
|
|
self.MovementType = VJ_MOVETYPE_AERIAL
|
|
self.AnimTbl_IdleStand = {self:GetSequenceActivity(self:LookupSequence("cargo_idle"))}
|
|
self.Aerial_AnimTbl_Calm = {"cargo_idle"}
|
|
self.Aerial_AnimTbl_Alerted = {"cargo_idle"}
|
|
end
|
|
|
|
if self.APC then
|
|
local apcNPC = ents.Create("npc_vj_combine_apc_z")
|
|
apcNPC:SetPos(self.APC:GetPos())
|
|
apcNPC:SetAngles(self.APC:GetAngles() + Angle(0,90,0))
|
|
apcNPC.VJ_NPC_Class = self.VJ_NPC_Class
|
|
apcNPC:Spawn()
|
|
self.APC:Remove()
|
|
self.DeployingAPC = false
|
|
self:VJ_ACT_PLAYACTIVITY("idle",true,1,false)
|
|
self.MovementType = VJ_MOVETYPE_AERIAL
|
|
self.AnimTbl_IdleStand = {self:GetSequenceActivity(self:LookupSequence("idle"))}
|
|
self.Aerial_AnimTbl_Calm = {"idle"}
|
|
self.Aerial_AnimTbl_Alerted = {"idle"}
|
|
self:SetVelocity(Vector(0,0,100))
|
|
elseif self.Strider then
|
|
local duration = 5
|
|
|
|
local tr = util.TraceLine({
|
|
start = self:GetPos(),
|
|
endpos = self:GetPos()-Vector(0,0,strider_deploydist_ground),
|
|
mask = MASK_NPCWORLDSTATIC,
|
|
})
|
|
|
|
local striderNPC = ents.Create("npc_vj_strider_synth_z")
|
|
striderNPC:SetPoseParameter("body_height",500)
|
|
striderNPC:SetPos(tr.HitPos)
|
|
striderNPC:SetAngles(Angle(0,self.Strider:GetAngles().y,0))
|
|
striderNPC.VJ_NPC_Class = self.VJ_NPC_Class
|
|
striderNPC:Spawn()
|
|
striderNPC:VJ_ACT_PLAYACTIVITY("deploy",true,duration,false)
|
|
striderNPC.IsBeingDroppedByDropship = true
|
|
striderNPC:SetNoDraw(true)
|
|
|
|
timer.Simple(0.2, function() if IsValid(striderNPC) && IsValid(self) then striderNPC:SetNoDraw(false) self.Strider:Remove() end end)
|
|
|
|
self.StriderUnfolding = true
|
|
timer.Simple(duration-2, function() if IsValid(striderNPC) && IsValid(self) then
|
|
self.StriderUnfolding = false
|
|
self.MovementType = VJ_MOVETYPE_AERIAL
|
|
self:VJ_ACT_PLAYACTIVITY("idle",true,1,false)
|
|
self.AnimTbl_IdleStand = {self:GetSequenceActivity(self:LookupSequence("idle"))}
|
|
self.Aerial_AnimTbl_Calm = {"idle"}
|
|
--striderNPC:EmitSound("NPC_Strider.Footstep")
|
|
end end)
|
|
|
|
timer.Simple(duration, function() if IsValid(striderNPC) then striderNPC.IsBeingDroppedByDropship = false end end)
|
|
|
|
self.DeployingStrider = false
|
|
|
|
--self:SetVelocity(Vector(0,0,100))
|
|
end
|
|
|
|
local fadetime = GetConVar("vj_zippycombines_dropship_fadetime"):GetInt()
|
|
if fadetime > -1 then
|
|
ZIPPYCOMBINES_FadeAndRemove(self,fadetime)
|
|
if self.Container then
|
|
ZIPPYCOMBINES_FadeAndRemove(self.Container,fadetime)
|
|
end
|
|
end
|
|
|
|
end
|
|
|
|
function ENT:CustomOnThink_AIEnabled()
|
|
|
|
if self.ContainerDeployed then
|
|
local dist = self:GetPos():Distance(self.Container:GetPos())
|
|
|
|
if dist < 40 then
|
|
self:SetVelocity(Vector(0,0,18))
|
|
else
|
|
self.PosAquired = true
|
|
end
|
|
|
|
if self.PosAquired then
|
|
self:SetVelocity(-self:GetVelocity()*0.3)
|
|
end
|
|
elseif self.DeployingStrider or self.StriderUnfolding then
|
|
self:SetVelocity(-self:GetVelocity()*0.3)
|
|
end
|
|
|
|
local tr_startdeploy = util.TraceHull({
|
|
start = self:GetPos(),
|
|
endpos = self:GetPos() + self:GetUp() * -10000,
|
|
mask = MASK_NPCWORLDSTATIC,
|
|
})
|
|
|
|
if ((IsValid(self:GetEnemy()) && self:GetEnemy():GetPos():Distance(self:GetPos()) < self.DeployDist)) && (math.abs(self:GetEnemy():GetPos().z - tr_startdeploy.HitPos.z) < 200 or self:GetEnemy().MovementType == VJ_MOVETYPE_AERIAL) && !(self.IsDeployingContainer or self.DeployingAPC or self.DeployingStrider) && !self.ContainerDeployed && !self.ContainerUsed then
|
|
local yaw_difference = self:WorldToLocalAngles( ( self:GetEnemy():GetPos()-self:GetPos() ):Angle() ).y
|
|
|
|
if math.abs(yaw_difference) < 22.5 then
|
|
self.MovementType = VJ_MOVETYPE_STATIONARY
|
|
self.Behavior = VJ_BEHAVIOR_PASSIVE
|
|
self.ConstantlyFaceEnemy = false
|
|
self.ConstantlyFaceEnemy_IfAttacking = false
|
|
self.ConstantlyFaceEnemyDistance = 0
|
|
self.CombatFaceEnemy = false -- If enemy exists and is visible
|
|
self.DeployAngle = Angle(0,self:GetAngles().y,0)
|
|
self.AlarmSound:Play()
|
|
self.AlarmSound:ChangePitch(math.random(105,115))
|
|
|
|
if self.APC then
|
|
self.DeployingAPC = true
|
|
elseif self.Strider then
|
|
self.DeployingStrider = true
|
|
else
|
|
self.IsDeployingContainer = true
|
|
end
|
|
|
|
end
|
|
end
|
|
if self.IsDeployingContainer or self.DeployingAPC or self.DeployingStrider then
|
|
|
|
local tr_too_close_for_strider = util.TraceLine({
|
|
start = self:GetPos(),
|
|
endpos = self:GetPos()-Vector(0,0,strider_deploydist_ground*0.75),
|
|
mask = MASK_NPCWORLDSTATIC,
|
|
})
|
|
|
|
local downspeed = 4
|
|
if self.DeployingStrider then
|
|
|
|
if tr_too_close_for_strider.Hit then
|
|
downspeed = -8 -- Go up if strider is too close to ground
|
|
else
|
|
downspeed = 8
|
|
end
|
|
elseif self.DeployingAPC then
|
|
downspeed = 8
|
|
end
|
|
|
|
self:SetVelocity(Vector(-self:GetVelocity().x,-self:GetVelocity().y,-downspeed))
|
|
|
|
if self.IsDeployingContainer && !self.DroppingContainer then
|
|
self:IsOnGroundCheck()
|
|
end
|
|
|
|
if self.APC then
|
|
local deploydist_ground = 100
|
|
local tr = util.TraceEntity({start = self.APC:GetPos(), endpos = self.APC:GetPos()-Vector(0,0,deploydist_ground), mask=MASK_NPCWORLDSTATIC}, self.APC)
|
|
if tr.HitWorld then
|
|
self:DeployFinish()
|
|
end
|
|
elseif self.Strider then
|
|
local tr = util.TraceLine({
|
|
start = self:GetPos(),
|
|
endpos = self:GetPos()-Vector(0,0,strider_deploydist_ground),
|
|
mask = MASK_NPCWORLDSTATIC,
|
|
})
|
|
if tr.Hit && !tr_too_close_for_strider.Hit then
|
|
self:DeployFinish()
|
|
end
|
|
end
|
|
|
|
end
|
|
|
|
|
|
if self.Container then
|
|
if self.NextSoldierTime != 0 && self.ContainerDeployed then
|
|
self.NextSoldierTime = self.NextSoldierTime - 1
|
|
end
|
|
if self.ContainerDeployed && self.NextSoldierTime == 0 && self.SoldiersSpawned < table.Count(self.DropTable) then
|
|
|
|
self.DropshipDropPoint = self.Container:GetPos()
|
|
|
|
local SoldierType = self.DropTable[self.CurrentSoldierIdx].class
|
|
|
|
self.Soldier = ents.Create(SoldierType)
|
|
self.Soldier:SetPos(self.Container:GetPos() - Vector(0,0,30))
|
|
self.Soldier:SetAngles(Angle(0,self.Container:GetAngles().y,0))
|
|
self.Soldier.IsBeingDroppedByDropship = true
|
|
self.Soldier:Spawn()
|
|
--self.Soldier.CanFlinch = 0
|
|
self.ContainerPhys:SetSolid(SOLID_VPHYSICS)
|
|
timer.Simple(2,function() if IsValid(self.Soldier) then self.Soldier.IsBeingDroppedByDropship = false end end)
|
|
timer.Simple(1.5,function() if IsValid(self.ContainerPhys) then self.ContainerPhys:SetSolid(SOLID_NONE) end end)
|
|
self.Soldier.VJ_NPC_Class = self.VJ_NPC_Class
|
|
|
|
local wep = self.DropTable[self.CurrentSoldierIdx].weapon
|
|
if wep != "" then
|
|
self.Soldier:Give(wep)
|
|
end
|
|
|
|
if SoldierType == "npc_vj_rollermine_z" or SoldierType == "npc_vj_rollermine_explosive_z" then
|
|
self.Soldier:RollTo(self.Container:GetPos() + self.Container:GetForward() * 400, 1.5, true)
|
|
self.Soldier:SetPos(self.Container:GetPos() + Vector(0,0,15))
|
|
elseif SoldierType == "npc_vj_hunter2_z" then
|
|
self.Soldier:VJ_ACT_PLAYACTIVITY("jump_rail",true,3,false)
|
|
self.Soldier:SetVelocity(self.Soldier:GetForward() * 200 + Vector(0,0,100))
|
|
elseif SoldierType == "npc_vj_vortigaunt_synth_z" then
|
|
self.Soldier:VJ_ACT_PLAYACTIVITY("jump_down128",true,3,false)
|
|
self.Soldier:SetVelocity(self.Soldier:GetForward() * 100 + Vector(0,0,50))
|
|
elseif SoldierType == "npc_vj_overwatch_assassin_z" or SoldierType == "npc_vj_assassin_synth_z" then
|
|
if SoldierType == "npc_vj_assassin_synth_z" then
|
|
self.Soldier:VJ_ACT_PLAYACTIVITY("falling",true,0.4,false)
|
|
else
|
|
self.Soldier:VJ_ACT_PLAYACTIVITY("jumploop",true,0.4,false)
|
|
end
|
|
self.Soldier:SetVelocity(self.Soldier:GetForward() * 150 + Vector(0,0,75))
|
|
else
|
|
self.Soldier:VJ_ACT_PLAYACTIVITY("dropship_deploy",true,2,false)
|
|
end
|
|
|
|
self.SoldiersSpawned = self.SoldiersSpawned + 1
|
|
self.NextSoldierTime = 18
|
|
self.CurrentSoldierIdx = self.CurrentSoldierIdx + 1
|
|
elseif self.SoldiersSpawned >= table.Count(self.DropTable) && self.NextSoldierTime == 0 && !self.ContainerUsed then
|
|
|
|
self:DeployFinish()
|
|
|
|
end
|
|
end
|
|
|
|
|
|
-- for _,v in pairs( ents.FindByClass("npc_vj_dropship_z") ) do
|
|
-- if v != self && v:GetPos():Distance(self:GetPos()) < 500 then
|
|
-- self:SetVelocity((self:GetPos() - v:GetPos()) * (40 / self:GetPos():Distance(v:GetPos())))
|
|
-- end
|
|
-- end
|
|
|
|
|
|
local FlySpeed = self.Aerial_FlyingSpeed_Alerted
|
|
if math.floor(self:GetVelocity():Distance(self:GetForward() * FlySpeed)) == FlySpeed or
|
|
math.ceil(self:GetVelocity():Distance(self:GetForward() * FlySpeed)) == FlySpeed then
|
|
self.FlexForwardInput = 0.3
|
|
else
|
|
self.FlexForwardInput = 1.3 - (self:GetVelocity():Distance(self:GetForward() * FlySpeed) / FlySpeed)
|
|
end
|
|
if self.FlexForwardInput > 0 then
|
|
self.FlexForwardOutput = math.Clamp(self.FlexForwardOutput + 0.1,-1,self.FlexForwardInput)
|
|
else
|
|
self.FlexForwardOutput = math.Clamp(self.FlexForwardOutput - 0.1,self.FlexForwardInput,1)
|
|
end
|
|
self:SetPoseParameter("cargo_body_accel", self.FlexForwardOutput)
|
|
|
|
|
|
if self.Container then
|
|
if self.IsShooting && IsValid(self:GetEnemy()) && self.Container:GetParent() == self then
|
|
if !self.HasStartedShooting then
|
|
self.ShootSound:Play()
|
|
self.ShootSound:ChangePitch(math.random(80,90))
|
|
self.HasStartedShooting = true
|
|
end
|
|
local expLight = ents.Create("light_dynamic")
|
|
expLight:SetKeyValue("brightness", "5")
|
|
expLight:SetKeyValue("distance", "250")
|
|
expLight:Fire("Color", "0 75 255")
|
|
expLight:SetPos(self.Container:GetAttachment(3).Pos)
|
|
expLight:Spawn()
|
|
expLight:Activate()
|
|
expLight:SetParent(self.Container,3)
|
|
expLight:Fire("TurnOn", "", 0)
|
|
timer.Simple(0.1,function() if IsValid(expLight) then expLight:Remove() end end)
|
|
self:DeleteOnRemove(expLight)
|
|
ParticleEffectAttach("vj_rifle_full_blue",PATTACH_POINT_FOLLOW,self.Container,3)
|
|
local bullet = {
|
|
Src = self.Container:GetAttachment(3).Pos,
|
|
Dir = (self:GetEnemy():GetPos() + self:GetEnemy():OBBCenter() ) - self.Container:GetAttachment(3).Pos,
|
|
Spread = Vector(100 / (self.RangeDistance / self:GetEnemy():GetPos():Distance(self:GetPos())),100 / (self.RangeDistance / self:GetEnemy():GetPos():Distance(self:GetPos())),0),
|
|
Damage = 4,
|
|
Force = 50,
|
|
TracerName = "AR2Tracer",
|
|
-- Callback = function(attacker, tracer)
|
|
-- local effectdata = EffectData()
|
|
-- effectdata:SetOrigin(tracer.HitPos)
|
|
-- effectdata:SetNormal(tracer.HitNormal)
|
|
-- effectdata:SetRadius( 5 )
|
|
-- util.Effect( "cball_bounce", effectdata )
|
|
-- end,
|
|
}
|
|
self.Container:FireBullets(bullet)
|
|
--self:EmitSound( "Weapon_AR2.NPC_Single", 100, 100, 0.25, CHAN_AUTO )
|
|
elseif self.IsShooting && (self.Container:GetParent() != self or !IsValid(self:GetEnemy())) then
|
|
self.IsShooting = false
|
|
self.HasStartedShooting = false
|
|
self:EmitSound( "NPC_CombineGunship.CannonStopSound", 100, 100)
|
|
self.ShootSound:Stop()
|
|
end
|
|
end
|
|
|
|
end
|
|
|
|
function ENT:CustomRangeAttackCode()
|
|
if !self.Container then return end
|
|
self:EmitSound( "NPC_CombineGunship.CannonStartSound", 100, 100)
|
|
|
|
self.AttackDuration = math.random(2,4)
|
|
timer.Simple(1,function() if IsValid(self) then self.IsShooting = true end end)
|
|
timer.Simple(self.AttackDuration,function() if IsValid(self) && self.IsShooting then
|
|
self.ShootSound:Stop()
|
|
self.IsShooting = false
|
|
self.HasStartedShooting = false
|
|
end end)
|
|
|
|
end
|
|
|
|
function ENT:CustomOn_PoseParameterLookingCode(pitch, yaw, roll)
|
|
self.CurrentAimPoseParamAng = LerpAngle(0.33, self.CurrentAimPoseParamAng, Angle(pitch, yaw, roll))
|
|
|
|
-- if self.Behavior == VJ_BEHAVIOR_AGRESSIVE then
|
|
-- self:SetPoseParameter("cargo_body_sway",self.CurrentAimPoseParamAng.y/90)
|
|
-- else
|
|
-- self:SetPoseParameter("cargo_body_sway",0)
|
|
-- end
|
|
|
|
if IsValid(self.Container) && self.Container:GetParent() == self then
|
|
self.Container:SetPoseParameter("weapon_pitch",-self.CurrentAimPoseParamAng.x)
|
|
self.Container:SetPoseParameter("weapon_yaw",self.CurrentAimPoseParamAng.y)
|
|
end
|
|
end
|
|
|
|
function ENT:DoSpark(pos,intensity)
|
|
|
|
intensity = intensity or 1
|
|
|
|
local spark = ents.Create("env_spark")
|
|
spark:SetKeyValue("Magnitude",tostring(intensity))
|
|
spark:SetKeyValue("Spark Trail Length",tostring(intensity))
|
|
spark:SetPos(pos)
|
|
spark:Spawn()
|
|
spark:Fire("StartSpark", "", 0)
|
|
timer.Simple(0.1, function() if IsValid(spark) then spark:Remove() end end)
|
|
|
|
end
|
|
|
|
function ENT:CustomOnTakeDamage_BeforeDamage(dmginfo, hitgroup)
|
|
|
|
if dmginfo:IsExplosionDamage() then
|
|
self:DoSpark(dmginfo:GetDamagePosition(), 6)
|
|
elseif dmginfo:IsBulletDamage() then
|
|
dmginfo:SetDamage(0)
|
|
else
|
|
self:DoSpark(dmginfo:GetDamagePosition(), 2)
|
|
dmginfo:SetDamage(dmginfo:GetDamage()*0.25)
|
|
end
|
|
|
|
end
|
|
|
|
function ENT:CustomOnDeath_AfterCorpseSpawned(dmginfo, hitgroup, corpseEnt)
|
|
|
|
corpseEnt:EmitSound("NPC_CombineGunship.Explode", 120, 100)
|
|
ParticleEffect("vj_explosion1", self:GetPos(), Angle(0,0,0))
|
|
local effectdata = EffectData()
|
|
effectdata:SetOrigin(self:GetPos())
|
|
effectdata:SetScale( 500 )
|
|
util.Effect( "Explosion", effectdata )
|
|
self:EmitSound( "Explo.ww2bomb", 130, 100)
|
|
|
|
if IsValid(self.Container) then
|
|
ParticleEffect("vj_explosion1", self.Container:GetPos(), Angle(0,0,0))
|
|
self:CreateGibEntity("obj_vj_gib","models/container_chunk01.mdl",{BloodType = "",Pos = self.Container:GetPos(), CollideSound = {"SolidMetal.ImpactSoft"}})
|
|
self:CreateGibEntity("obj_vj_gib","models/container_chunk02.mdl",{BloodType = "",Pos = self.Container:GetPos(), CollideSound = {"SolidMetal.ImpactSoft"}})
|
|
self:CreateGibEntity("obj_vj_gib","models/container_chunk03.mdl",{BloodType = "",Pos = self.Container:GetPos(), CollideSound = {"SolidMetal.ImpactSoft"}})
|
|
self:CreateGibEntity("obj_vj_gib","models/container_chunk04.mdl",{BloodType = "",Pos = self.Container:GetPos(), CollideSound = {"SolidMetal.ImpactSoft"}})
|
|
self:CreateGibEntity("obj_vj_gib","models/container_chunk05.mdl",{BloodType = "",Pos = self.Container:GetPos(), CollideSound = {"SolidMetal.ImpactSoft"}})
|
|
self:CreateGibEntity("obj_vj_gib","models/container_chunk01.mdl",{BloodType = "",Pos = self.Container:GetPos(), CollideSound = {"SolidMetal.ImpactSoft"}})
|
|
self:CreateGibEntity("obj_vj_gib","models/container_chunk02.mdl",{BloodType = "",Pos = self.Container:GetPos(), CollideSound = {"SolidMetal.ImpactSoft"}})
|
|
self:CreateGibEntity("obj_vj_gib","models/container_chunk03.mdl",{BloodType = "",Pos = self.Container:GetPos(), CollideSound = {"SolidMetal.ImpactSoft"}})
|
|
self:CreateGibEntity("obj_vj_gib","models/container_chunk04.mdl",{BloodType = "",Pos = self.Container:GetPos(), CollideSound = {"SolidMetal.ImpactSoft"}})
|
|
self:CreateGibEntity("obj_vj_gib","models/container_chunk05.mdl",{BloodType = "",Pos = self.Container:GetPos(), CollideSound = {"SolidMetal.ImpactSoft"}})
|
|
end
|
|
|
|
if IsValid(self.APC) then
|
|
ParticleEffect("vj_explosion1", self.APC:GetPos(), Angle(0,0,0))
|
|
self:CreateGibEntity("obj_vj_gib","models/combine_apc_destroyed_gib01.mdl",{Pos = self.APC:GetPos(), BloodType = "",Vel = self:GetVelocity()+VectorRand()*100, CollideSound = {"SolidMetal.ImpactSoft"}})
|
|
self:CreateGibEntity("obj_vj_gib","models/combine_apc_destroyed_gib02.mdl",{Pos = self.APC:GetPos(), BloodType = "",Vel = self:GetVelocity()+VectorRand()*600, CollideSound = {"SolidMetal.ImpactSoft"}})
|
|
self:CreateGibEntity("obj_vj_gib","models/combine_apc_destroyed_gib03.mdl",{Pos = self.APC:GetPos(), BloodType = "",Vel = self:GetVelocity()+VectorRand()*600, CollideSound = {"SolidMetal.ImpactSoft"}})
|
|
self:CreateGibEntity("obj_vj_gib","models/combine_apc_destroyed_gib04.mdl",{Pos = self.APC:GetPos(), BloodType = "",Vel = self:GetVelocity()+VectorRand()*600, CollideSound = {"SolidMetal.ImpactSoft"}})
|
|
self:CreateGibEntity("obj_vj_gib","models/combine_apc_destroyed_gib05.mdl",{Pos = self.APC:GetPos(), BloodType = "",Vel = self:GetVelocity()+VectorRand()*600, CollideSound = {"SolidMetal.ImpactSoft"}})
|
|
end
|
|
|
|
if IsValid(self.Strider) then
|
|
ParticleEffect("vj_explosion1", self.Strider:GetPos(), Angle(0,0,0))
|
|
ParticleEffect( "striderbuster_explode_goop", self.Strider:GetPos(), self:GetAngles() )
|
|
self:CreateGibEntity("obj_vj_gib","models/gibs/strider_gib1.mdl",{Pos = self.Strider:GetPos(), BloodType = "",Vel = self:GetVelocity()+VectorRand()*600, CollideSound = {"SolidMetal.ImpactSoft"}})
|
|
self:CreateGibEntity("obj_vj_gib","models/gibs/strider_gib2.mdl",{Pos = self.Strider:GetPos(), BloodType = "",Vel = self:GetVelocity()+VectorRand()*600, CollideSound = {"SolidMetal.ImpactSoft"}})
|
|
self:CreateGibEntity("obj_vj_gib","models/gibs/strider_gib3.mdl",{Pos = self.Strider:GetPos(), BloodType = "",Vel = self:GetVelocity()+VectorRand()*600, CollideSound = {"SolidMetal.ImpactSoft"}})
|
|
self:CreateGibEntity("obj_vj_gib","models/gibs/strider_gib4.mdl",{Pos = self.Strider:GetPos(), BloodType = "",Vel = self:GetVelocity()+VectorRand()*600, CollideSound = {"SolidMetal.ImpactSoft"}})
|
|
self:CreateGibEntity("obj_vj_gib","models/gibs/strider_gib5.mdl",{Pos = self.Strider:GetPos(), BloodType = "",Vel = self:GetVelocity()+VectorRand()*600, CollideSound = {"SolidMetal.ImpactSoft"}})
|
|
self:CreateGibEntity("obj_vj_gib","models/gibs/strider_gib6.mdl",{Pos = self.Strider:GetPos(), BloodType = "",Vel = self:GetVelocity()+VectorRand()*600, CollideSound = {"SolidMetal.ImpactSoft"}})
|
|
self:CreateGibEntity("obj_vj_gib","models/gibs/strider_gib7.mdl",{Pos = self.Strider:GetPos(), BloodType = "",Vel = self:GetVelocity()+VectorRand()*600, CollideSound = {"SolidMetal.ImpactSoft"}})
|
|
|
|
self:CreateGibEntity("prop_ragdoll","models/gibs/strider_head.mdl",{Pos = self.Strider:GetPos(), BloodType = "",Vel = self:GetVelocity()+VectorRand()*600, CollideSound = {"SolidMetal.ImpactSoft"}})
|
|
self:CreateGibEntity("prop_ragdoll","models/gibs/strider_weapon.mdl",{Pos = self.Strider:GetPos(), BloodType = "",Vel = self:GetVelocity()+VectorRand()*600, CollideSound = {"SolidMetal.ImpactSoft"}})
|
|
|
|
self:CreateGibEntity("prop_ragdoll","models/gibs/strider_back_leg.mdl",{Pos = self.Strider:GetPos(), BloodType = "",Vel = self:GetVelocity()+VectorRand()*600, CollideSound = {"SolidMetal.ImpactSoft"}})
|
|
self:CreateGibEntity("prop_ragdoll","models/gibs/strider_left_leg.mdl",{Pos = self.Strider:GetPos(), BloodType = "",Vel = self:GetVelocity()+VectorRand()*600, CollideSound = {"SolidMetal.ImpactSoft"}})
|
|
self:CreateGibEntity("prop_ragdoll","models/gibs/strider_right_leg.mdl",{Pos = self.Strider:GetPos(), BloodType = "",Vel = self:GetVelocity()+VectorRand()*600, CollideSound = {"SolidMetal.ImpactSoft"}})
|
|
end
|
|
end
|
|
|
|
function ENT:CustomOnRemove()
|
|
|
|
if IsValid(self.Container) && self.Container:GetParent() != self && !self.ContainerUsed then
|
|
self.Container:Remove()
|
|
end
|
|
|
|
self.EngineSound1:Stop()
|
|
self.EngineSound2:Stop()
|
|
self.ShootSound:Stop()
|
|
self.AlarmSound:Stop()
|
|
|
|
end
|
|
/*--------------------------------------------------
|
|
*** Copyright (c) 2012-2021 by DrVrej, All rights reserved. ***
|
|
No parts of this code or any of its contents may be reproduced, copied, modified or adapted,
|
|
without the prior written consent of the author, unless otherwise indicated for stand-alone materials.
|
|
--------------------------------------------------*/ |