Files
wnsrc/lua/entities/npc_vj_rollermine_z/init.lua
lifestorm 94063e4369 Upload
2024-08-04 22:55:00 +03:00

480 lines
18 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")
ENT.Model = {"models/Roller.mdl"}
ENT.SightAngle = 180
ENT.VJ_NPC_Class = {"CLASS_COMBINE"}
ENT.StartHealth = 55
ENT.CallForHelpDistance = 10000
ENT.HasMeleeAttack = false
ENT.HasGibOnDeathSounds = false
ENT.HasItemDropsOnDeath = true
ENT.ItemDropsOnDeathChance = 2
ENT.ItemDropsOnDeath_EntityList = {
"item_battery",
}
ENT.MaxMoveSpeed = 675
ENT.CurrentMoveSpeed = 0
ENT.AccelSpeed = 75
ENT.DeaccelSpeed = 150
ENT.MineColor = "0 75 255"
ENT.MineSkin = 0
ENT.SpikeDeployDist = 400
ENT.HasExplosionAttack = false
ENT.ExplodeDist = 0
ENT.HasShockAttack = true
ENT.ShockDamage = 12
ENT.ShockRadius = 125
ENT.ShockDelay = {
min = 1,
max = 2,
}
ENT.NextFindNewAllyParentDelay = 8
ENT.MaxFindAllyParentDist = 1750
ENT.AllyParent_MinFollowDist = 200
ENT.SoundTbl_Alert = {"npc/roller/mine/rmine_tossed1.wav"}
ENT.SoundTbl_Idle = {"npc/roller/mine/rmine_chirp_quest1.wav","npc/roller/mine/rmine_blip1.wav"}
ENT.SoundTbl_CombatIdle = {"npc/roller/mine/rmine_taunt1.wav","npc/roller/mine/rmine_taunt2.wav"}
ENT.SoundTbl_Pain = {"npc/roller/mine/rmine_shockvehicle1.wav","npc/roller/mine/rmine_shockvehicle2.wav"}
ENT.VJC_Data = {
CameraMode = 2, -- Sets the default camera mode | 1 = Third Person, 2 = First Person
ThirdP_Offset = Vector(0, 0, 0), -- The offset for the controller when the camera is in third person
FirstP_Bone = "polymsh2", -- If left empty, the base will attempt to calculate a position for first person
FirstP_Offset = Vector(0, 0, 0), -- The offset for the controller when the camera is in first person
FirstP_ShrinkBone = true, -- Should the bone shrink? Useful if the bone is obscuring the player's view
FirstP_CameraBoneAng = 0, -- Should the camera's angle be affected by the bone's angle? | 0 = No, 1 = Pitch, 2 = Yaw, 3 = Roll
FirstP_CameraBoneAng_Offset = 0, -- How much should the camera's angle be rotated by? | Useful for weird bone angles
}
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
function ENT:RollerInit() end
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
function ENT:CustomOnInitialize()
self:RollerInit()
self:SetSkin(self.MineSkin)
self:SetCollisionBounds(Vector(-12.5,-12.5,-12.5), Vector(12.5,12.5,12.5))
self.MoveAutoStopTimerName = "VJRollerMineAutoStopTimer" .. self:EntIndex()
self:RollTo(self:GetPos())
self.SpikeModel = ents.Create("prop_dynamic")
self.SpikeModel:SetModel("models/roller_spikes.mdl")
self.SpikeModel:SetPos(self:GetPos())
self.SpikeModel:Spawn()
self.SpikeModel:SetParent(self)
self.SpikeModel:SetNoDraw(true)
self.SpikeModel:SetSkin(self:GetSkin())
self.NextShockTime = CurTime()
self.AllyParent = NULL
self.NextFindNewAllyParentTime = CurTime()
--self:SetBloodColor(BLOOD_COLOR_MECH)
end
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
function ENT:MovementThink()
self.Rolling = true
if self:GetPos():Distance(self.CurrentDestination) < 60 then
self.Rolling = false
self.BeingForcedToMove = false
end
if self.Rolling then
self.CurrentMoveSpeed = math.Clamp(self.CurrentMoveSpeed + self.AccelSpeed, 0, self.MaxMoveSpeed)
else
self.CurrentMoveSpeed = math.Clamp(self.CurrentMoveSpeed - self.DeaccelSpeed, 0, self.MaxMoveSpeed)
end
if self.CurrentMoveSpeed > 0 then
local cur_angs = self:GetAngles()
self:SetAngles(Angle( cur_angs.x + self.CurrentMoveSpeed * 0.1, cur_angs.y , cur_angs.z ))
local destination = self.CurrentDestination
if !self.Rolling then
destination = self:GetForward() * 100
end
local movedir = (destination - self:GetPos()):GetNormalized()
if self:IsOnGround() then
self:SetVelocity(Vector( movedir.x*self.CurrentMoveSpeed , movedir.y*self.CurrentMoveSpeed , math.Rand(0, 100) ))
else
self:SetVelocity(Vector( movedir.x*50 , movedir.y*50 , 0 ))
end
self:SetIdealYawAndUpdate( ( self.CurrentDestination - self:GetPos() ):Angle().y )
end
end
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
function ENT:RollTo(pos,autostoptime,force)
if self.BeingForcedToMove then return end
if force then
self.BeingForcedToMove = true
end
autostoptime = autostoptime or 4
self.CurrentDestination = pos
timer.Create(self.MoveAutoStopTimerName, autostoptime, 1, function() if IsValid(self) then
self:RollTo(self:GetPos())
self.BeingForcedToMove = false
--print("holding position..")
end end)
end
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
function ENT:CustomOnThink()
self:MovementThink()
if self:WaterLevel() > 1 then
self:TakeDamage(10000000, self, self)
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:DeploySpikes()
if self.SpikesDeployed then return end
self.SpikesDeployed = true
self.SpikeModel:SetNoDraw(false)
self:SetNoDraw(true)
self.DeployedLight = ents.Create("light_dynamic")
self.DeployedLight:SetKeyValue("brightness", "1")
self.DeployedLight:SetKeyValue("distance", "150")
self.DeployedLight:Fire("Color", self.MineColor)
self.DeployedLight:SetPos(self:GetPos())
self.DeployedLight:SetParent(self)
self.DeployedLight:Spawn()
self.DeployedLight:Fire("TurnOn", "", 0)
self:DoSpark(self:GetPos())
self:SetVelocity(Vector(0,0,75))
self:EmitSound("npc/roller/blade_out.wav", 80, math.random(90, 110))
end
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
function ENT:RetractSpikes()
if !self.SpikesDeployed then return end
self.SpikesDeployed = false
self.SpikeModel:SetNoDraw(true)
self:SetNoDraw(false)
self.DeployedLight:Remove()
self:EmitSound("npc/roller/blade_cut.wav", 80, math.random(90, 110))
end
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
function ENT:Shock()
if self.NextShockTime > CurTime() then return end
local realisticRadius = true
local shocked_ents = util.VJ_SphereDamage(self, self, self:GetPos(), self.ShockRadius, self.ShockDamage, bit.bor(DMG_DISSOLVE,DMG_SHOCK,DMG_NEVERGIB), true, realisticRadius)
local shock_successful = nil
for _,ent in pairs(shocked_ents) do
if ent:IsSolid() then
shock_successful = true
end
end
if !shock_successful then return end
local HasDoneSelfPushback = false
local max_effects = 3
local effects_used = 0
for _,ent in pairs(shocked_ents) do
if ent:IsSolid() then
local hitpos = ent:GetPos() + ent:OBBCenter()
if effects_used < max_effects then
util.ParticleTracerEx( "st_elmos_fire", self:GetPos(), hitpos , false, self:EntIndex() , 0)
effects_used = effects_used + 1
end
local attack_dir = (hitpos - self:GetPos()):GetNormalized()
if !HasDoneSelfPushback then
self:SetVelocity(-attack_dir * 300 + Vector(0,0,200))
HasDoneSelfPushback = true
end
if ent:IsNPC() or ent:IsPlayer() then
ent:SetVelocity(Vector( attack_dir.x , attack_dir.y , 0 ) * 300)
self:DoSpark(hitpos)
end
if ent:GetMoveType() == MOVETYPE_VPHYSICS then
local physobj = ent:GetPhysicsObject()
if IsValid(physobj) then
physobj:SetVelocity(attack_dir * 200)
end
end
end
end
self:EmitSound("npc/roller/mine/rmine_explode_shock1.wav", 95, math.random(90, 110))
self.NextShockTime = CurTime() + math.Rand( self.ShockDelay.min , self.ShockDelay.max )
end
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
function ENT:CustomOnResetEnemy()
self:RollTo(self:GetPos())
end
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
function ENT:IsAlly(ent)
if !ent.VJ_NPC_Class then return end
for _,npcclass in pairs(ent.VJ_NPC_Class) do
for _,mynpcclass in pairs(self.VJ_NPC_Class) do
if npcclass == mynpcclass then
return true
end
end
end
end
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
function ENT:FindNewAllyParent()
local closest_ally = nil
local closest_ally_dist = nil
for _,ent in pairs( ents.FindInSphere(self:GetPos(), self.MaxFindAllyParentDist) ) do
if !ent:IsOnGround() or ent:GetClass() == "npc_vj_rollermine_z" or ent:GetClass() == "npc_vj_rollermine_explosive_z" or ent:GetClass() == "npc_vj_combine_apc_z" or !self:IsAlly(ent) then continue end
local dist = ent:GetPos():Distance(self:GetPos())
if !closest_ally_dist or dist < closest_ally_dist then
closest_ally = ent
closest_ally_dist = dist
end
end
if closest_ally then self.AllyParent = closest_ally end
end
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
function ENT:TryFollowAllyParent()
if !IsValid(self.AllyParent) then return end
ally_parent_distace = self:GetPos():Distance(self.AllyParent:GetPos())
if self:Visible(self.AllyParent) && ally_parent_distace > self.AllyParent_MinFollowDist then
self:RollTo(self.AllyParent:GetPos())
end
end
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
function ENT:Controller_IntMsg(ply, controlEnt)
ply:ChatPrint("Hold W (forward key): Move")
ply:ChatPrint("Hold MOUSE1 (primary attack key): Spikes")
ply:ChatPrint("Please don't use thirdperson, it's kinda broken.")
end
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
function ENT:CustomOnThink_AIEnabled()
if self.IsExploding then
sound.EmitHint(SOUND_DANGER, self:GetPos(), 300, 0.5, self)
return
end
local enemy = self:GetEnemy()
if IsValid(enemy) then
local enemydist = self:GetPos():Distance(enemy:GetPos())
if self.VJ_IsBeingControlled then
local controller = self.VJ_TheController
if controller:KeyDown(IN_FORWARD) then
local pos = enemy:GetPos()
pos = Vector(pos.x,pos.y,0)
self:RollTo(pos,0.5)
end
if controller:KeyDown(IN_ATTACK) then
self:DeploySpikes()
else
self:RetractSpikes()
end
else
if self:Visible(enemy) then
self:RollTo(enemy:GetPos())
else
self:TryFollowAllyParent()
end
if enemydist < self.SpikeDeployDist then
self:DeploySpikes()
else
self:RetractSpikes()
end
end
if self.HasExplosionAttack then
if self.VJ_IsBeingControlled then
if self.VJ_TheController:KeyDown(IN_ATTACK2) then
self.IsExploding = true
self:SetVelocity(Vector(0,0,290))
self:EmitSound("npc/roller/mine/rmine_predetonate.wav", 90, math.random(90, 110))
timer.Simple(0.75, function() if IsValid(self) then self:TakeDamage(10000000, self, self) end end)
end
else
if enemydist < self.ExplodeDist then
self.IsExploding = true
self:SetVelocity(Vector(0,0,290))
self:EmitSound("npc/roller/mine/rmine_predetonate.wav", 90, math.random(90, 110))
timer.Simple(0.75, function() if IsValid(self) then self:TakeDamage(10000000, self, self) end end)
end
end
end
else
self:RetractSpikes()
if self.NextFindNewAllyParentTime < CurTime() then
self:FindNewAllyParent()
self.NextFindNewAllyParentTime = CurTime() + self.NextFindNewAllyParentDelay
end
self:TryFollowAllyParent()
end
if self.HasShockAttack && self.SpikesDeployed then
self:Shock()
end
end
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
function ENT:CustomOnTakeDamage_BeforeDamage(dmginfo, hitgroup)
if !dmginfo:IsExplosionDamage() then
dmginfo:SetDamage(dmginfo:GetDamage() * 0.5)
if math.random(1, 3) == 1 then
self:EmitSound("weapons/fx/rics/ric1.wav", 82, math.random(85, 115))
local spark = ents.Create("env_spark")
spark:SetPos(dmginfo:GetDamagePosition())
spark:Spawn()
spark:Fire("StartSpark", "", 0)
spark:Fire("StopSpark", "", 0.001)
self:DeleteOnRemove(spark)
end
end
if !self.IsExploding then
self:SetVelocity(VectorRand()*125)
end
end
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
function ENT:CustomOnPriorToKilled(dmginfo, hitgroup)
self:EmitSound("physics/metal/metal_box_break" .. math.random(1, 2) .. ".wav", 90, math.random(90, 110), 0.75)
self:EmitSound("npc/roller/mine/rmine_explode_shock1.wav", 90, math.random(130, 150))
ParticleEffect("explosion_turret_break",self:GetPos(),self:GetAngles())
end
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
function ENT:SetUpGibesOnDeath(dmginfo, hitgroup)
self:CreateGibEntity("obj_vj_gib","models/gibs/manhack_gib01.mdl",{BloodType = "",Pos = self:LocalToWorld(Vector(0,0,0)), CollideSound = {"SolidMetal.ImpactSoft"}})
self:CreateGibEntity("obj_vj_gib","models/gibs/manhack_gib04.mdl",{BloodType = "",Pos = self:LocalToWorld(Vector(0,0,0)), CollideSound = {"SolidMetal.ImpactSoft"}})
self:CreateGibEntity("obj_vj_gib","models/combine_turrets/floor_turret_gib2.mdl",{BloodType = "",Pos = self:LocalToWorld(Vector(0,0,0)), CollideSound = {"SolidMetal.ImpactSoft"}})
self:CreateGibEntity("obj_vj_gib","models/gibs/scanner_gib02.mdl",{BloodType = "",Pos = self:LocalToWorld(Vector(0,0,0)), CollideSound = {"SolidMetal.ImpactSoft"}})
return true
end
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
function ENT:CustomOnDeath_AfterCorpseSpawned(dmginfo, hitgroup, corpseEnt)
corpseEnt:GetPhysicsObject():SetVelocity( self:GetVelocity() * 0.38 + Vector(0,0,125) )
corpseEnt:SetAngles(self:GetAngles())
ParticleEffectAttach("electrical_arc_01_system", PATTACH_ABSORIGIN_FOLLOW, corpseEnt,0)
end
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------