mirror of
https://github.com/lifestorm/wnsrc.git
synced 2025-12-17 05:43:46 +03:00
493 lines
12 KiB
Lua
493 lines
12 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()
|
||
|
|
|
||
|
|
if (CLIENT) then
|
||
|
|
SWEP.PrintName = "CV-2000 Stun Baton"
|
||
|
|
SWEP.Slot = 0
|
||
|
|
SWEP.SlotPos = 5
|
||
|
|
SWEP.DrawAmmo = false
|
||
|
|
SWEP.DrawCrosshair = false
|
||
|
|
end
|
||
|
|
|
||
|
|
SWEP.Category = "HL2 RP"
|
||
|
|
SWEP.Author = "Chessnut"
|
||
|
|
SWEP.Instructions = "Primary Fire: Stun.\nALT + Primary Fire: Toggle stun.\nSecondary Fire: Push/Knock."
|
||
|
|
SWEP.Purpose = "Hitting things and knocking on doors."
|
||
|
|
SWEP.Drop = false
|
||
|
|
|
||
|
|
SWEP.HoldType = "melee"
|
||
|
|
|
||
|
|
SWEP.Spawnable = true
|
||
|
|
SWEP.AdminOnly = true
|
||
|
|
|
||
|
|
SWEP.ViewModelFOV = 47
|
||
|
|
SWEP.ViewModelFlip = false
|
||
|
|
SWEP.AnimPrefix = "melee"
|
||
|
|
|
||
|
|
SWEP.ViewTranslation = 4
|
||
|
|
|
||
|
|
SWEP.Primary.ClipSize = -1
|
||
|
|
SWEP.Primary.DefaultClip = -1
|
||
|
|
SWEP.Primary.Automatic = false
|
||
|
|
SWEP.Primary.Ammo = ""
|
||
|
|
SWEP.Primary.Damage = 15
|
||
|
|
SWEP.Primary.Delay = 0.7
|
||
|
|
|
||
|
|
SWEP.Secondary.ClipSize = -1
|
||
|
|
SWEP.Secondary.DefaultClip = 0
|
||
|
|
SWEP.Secondary.Automatic = false
|
||
|
|
SWEP.Secondary.Ammo = ""
|
||
|
|
|
||
|
|
SWEP.ViewModel = Model("models/weapons/c_wn_stunstick.mdl")
|
||
|
|
SWEP.WorldModel = Model("models/weapons/w_wn_stunbaton.mdl")
|
||
|
|
|
||
|
|
SWEP.UseHands = true
|
||
|
|
SWEP.LowerAngles = Angle(15, -10, -20)
|
||
|
|
|
||
|
|
SWEP.FireWhenLowered = true
|
||
|
|
|
||
|
|
function SWEP:SetupDataTables()
|
||
|
|
self:NetworkVar("Bool", 0, "Activated")
|
||
|
|
self:NetworkVarNotify( "Activated", self.OnActiveToggle )
|
||
|
|
end
|
||
|
|
|
||
|
|
function SWEP:Precache()
|
||
|
|
util.PrecacheSound("physics/wood/wood_crate_impact_hard3.wav")
|
||
|
|
end
|
||
|
|
|
||
|
|
function SWEP:StartStunstickSound()
|
||
|
|
if (SERVER) then
|
||
|
|
local client = self:GetOwner()
|
||
|
|
|
||
|
|
self.patch1 = CreateSound(client, "wn_stunstick/stunstick_idle_"..math.random(1, 6)..".wav")
|
||
|
|
self.patch1:SetSoundLevel(40)
|
||
|
|
self.patch1:SetDSP(7)
|
||
|
|
self.patch1:Play()
|
||
|
|
|
||
|
|
self:SoundTimer()
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
function SWEP:StopStunstickSound()
|
||
|
|
if (SERVER) then
|
||
|
|
local patchToStop
|
||
|
|
if (self.patch1 and self.patch1:IsPlaying()) then
|
||
|
|
patchToStop = self.patch1
|
||
|
|
else
|
||
|
|
patchToStop = self.patch2
|
||
|
|
end
|
||
|
|
|
||
|
|
if (!patchToStop) then return end
|
||
|
|
|
||
|
|
patchToStop:FadeOut(1)
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
-- for when someone primary fires or w/e
|
||
|
|
function SWEP:DuckStunstickSound(vol, delta)
|
||
|
|
if (SERVER) then
|
||
|
|
if (!delta) then
|
||
|
|
delta = 0.5
|
||
|
|
end
|
||
|
|
|
||
|
|
if (!vol) then
|
||
|
|
vol = 0.25
|
||
|
|
end
|
||
|
|
|
||
|
|
local patchToDuck = self.patch1 and self.patch1:IsPlaying() and self.patch1 or self.patch2
|
||
|
|
if (!patchToDuck) then return end
|
||
|
|
|
||
|
|
patchToDuck:ChangeVolume(vol, delta)
|
||
|
|
timer.Simple(delta + 0.1, function()
|
||
|
|
patchToDuck:ChangeVolume(1, delta)
|
||
|
|
end)
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
function SWEP:OnActiveToggle(name, old, new)
|
||
|
|
if (new) then
|
||
|
|
self:StartStunstickSound()
|
||
|
|
else
|
||
|
|
self:StopStunstickSound()
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
function SWEP:SoundTimer()
|
||
|
|
if (SERVER) then
|
||
|
|
local client = self:GetOwner()
|
||
|
|
|
||
|
|
local tName = "stunstick_idle_"..client:SteamID64().."_timer"
|
||
|
|
|
||
|
|
if timer.Exists(tName) then timer.Remove(tName) end
|
||
|
|
|
||
|
|
timer.Create(tName, 7, 0, function()
|
||
|
|
if (!IsValid(client)) then
|
||
|
|
timer.Remove(tName)
|
||
|
|
return
|
||
|
|
end
|
||
|
|
|
||
|
|
if (!IsValid(self) or !self:GetActivated()) then
|
||
|
|
return
|
||
|
|
end
|
||
|
|
|
||
|
|
local patchToStart
|
||
|
|
local patchToStop
|
||
|
|
if (self.patch1 and self.patch1:IsPlaying()) then
|
||
|
|
patchToStart = self.patch2
|
||
|
|
patchToStop = self.patch1
|
||
|
|
else
|
||
|
|
patchToStart = self.patch1
|
||
|
|
patchToStop = self.patch2
|
||
|
|
end
|
||
|
|
|
||
|
|
if (!patchToStop) then
|
||
|
|
timer.Remove(tName)
|
||
|
|
return
|
||
|
|
end
|
||
|
|
|
||
|
|
patchToStop:FadeOut(1)
|
||
|
|
|
||
|
|
patchToStart = CreateSound(client, "wn_stunstick/stunstick_idle_"..math.random(1, 6)..".wav")
|
||
|
|
patchToStart:SetSoundLevel(40) -- maybe make this configurable idk
|
||
|
|
patchToStart:SetDSP(7)
|
||
|
|
patchToStart:Play()
|
||
|
|
patchToStart:ChangeVolume( 0.1, 0 )
|
||
|
|
patchToStart:ChangeVolume(1, 1)
|
||
|
|
|
||
|
|
if (self.patch1 and self.patch1:IsPlaying()) then
|
||
|
|
self.patch2 = patchToStart
|
||
|
|
else
|
||
|
|
self.patch1 = patchToStart
|
||
|
|
end
|
||
|
|
end)
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
function SWEP:CreateWMParticle()
|
||
|
|
if self.particle and self.particle:IsValid() then
|
||
|
|
self.particle:StopEmissionAndDestroyImmediately()
|
||
|
|
end
|
||
|
|
|
||
|
|
self.particle = CreateParticleSystem(self, "wn_stunstick_fx", PATTACH_POINT_FOLLOW, 1, Vector(0, 0, 0))
|
||
|
|
end
|
||
|
|
|
||
|
|
function SWEP:Initialize()
|
||
|
|
self:SetHoldType(self.HoldType)
|
||
|
|
end
|
||
|
|
|
||
|
|
function SWEP:OnRaised()
|
||
|
|
self.lastRaiseTime = CurTime()
|
||
|
|
end
|
||
|
|
|
||
|
|
function SWEP:OnLowered()
|
||
|
|
self:SetActivated(false)
|
||
|
|
|
||
|
|
if (CLIENT) then
|
||
|
|
if (self.particle and IsValid(self.particle)) then
|
||
|
|
self.particle:StopEmissionAndDestroyImmediately()
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
function SWEP:Holster(nextWep)
|
||
|
|
if self.patch1 and self.patch1:IsPlaying() or self.patch2 and self.patch2:IsPlaying() then
|
||
|
|
self:StopStunstickSound()
|
||
|
|
end
|
||
|
|
|
||
|
|
self:OnLowered()
|
||
|
|
|
||
|
|
return true
|
||
|
|
end
|
||
|
|
|
||
|
|
local STUNSTICK_GLOW_MATERIAL2 = Material("effects/blueflare1")
|
||
|
|
local STUNSTICK_GLOW_MATERIAL_NOZ = Material("sprites/light_glow02_add_noz")
|
||
|
|
|
||
|
|
function SWEP:DrawWorldModel()
|
||
|
|
self:DrawModel()
|
||
|
|
|
||
|
|
if (!self.particle or self.particle and !self.particle:IsValid()) then
|
||
|
|
if self:GetActivated() then
|
||
|
|
self:CreateWMParticle()
|
||
|
|
end
|
||
|
|
elseif (self.particle and self.particle:IsValid()) then
|
||
|
|
if !self:GetActivated() then
|
||
|
|
self.particle:StopEmissionAndDestroyImmediately()
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
if (self:GetActivated()) then
|
||
|
|
local size = math.Rand(2.0, 6.0)
|
||
|
|
local glow = math.Rand(0.6, 0.8) * 255
|
||
|
|
local color = Color(glow / 2, glow / 1.5, glow / 1.1)
|
||
|
|
local attachment = self:GetAttachment(1)
|
||
|
|
|
||
|
|
if (attachment) then
|
||
|
|
local position = attachment.Pos
|
||
|
|
|
||
|
|
render.SetMaterial(STUNSTICK_GLOW_MATERIAL2)
|
||
|
|
render.DrawSprite(position, size * 2, size * 2, color)
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
local NUM_BEAM_ATTACHEMENTS = 9
|
||
|
|
local BEAM_ATTACH_CORE_NAME = "sparkrear"
|
||
|
|
|
||
|
|
SWEP.nextSpark = 0
|
||
|
|
|
||
|
|
function SWEP:PostDrawViewModel()
|
||
|
|
if (!self:GetActivated()) then
|
||
|
|
return
|
||
|
|
end
|
||
|
|
|
||
|
|
local viewModel = LocalPlayer():GetViewModel()
|
||
|
|
|
||
|
|
if (!IsValid(viewModel)) then
|
||
|
|
return
|
||
|
|
end
|
||
|
|
|
||
|
|
cam.Start3D(EyePos(), EyeAngles())
|
||
|
|
local size = math.Rand(3.0, 4.0)
|
||
|
|
local color = Color(75, 100, 150, 50 + math.sin(RealTime() * 2)*20)
|
||
|
|
|
||
|
|
STUNSTICK_GLOW_MATERIAL_NOZ:SetFloat("$alpha", color.a / 255)
|
||
|
|
|
||
|
|
render.SetMaterial(STUNSTICK_GLOW_MATERIAL_NOZ)
|
||
|
|
|
||
|
|
local attachment = viewModel:GetAttachment(1)
|
||
|
|
|
||
|
|
if (attachment) then
|
||
|
|
render.DrawSprite(attachment.Pos, size * 10, size * 15, color)
|
||
|
|
end
|
||
|
|
|
||
|
|
for i = 1, NUM_BEAM_ATTACHEMENTS do
|
||
|
|
attachment = viewModel:GetAttachment(viewModel:LookupAttachment("spark"..i.."a"))
|
||
|
|
size = math.Rand(2.5, 5.0)
|
||
|
|
|
||
|
|
if (attachment and attachment.Pos) then
|
||
|
|
render.DrawSprite(attachment.Pos, size, size, color)
|
||
|
|
end
|
||
|
|
|
||
|
|
attachment = viewModel:GetAttachment(viewModel:LookupAttachment("spark"..i.."b"))
|
||
|
|
size = math.Rand(2.5, 5.0)
|
||
|
|
|
||
|
|
if (attachment and attachment.Pos) then
|
||
|
|
render.DrawSprite(attachment.Pos, size, size, color)
|
||
|
|
end
|
||
|
|
end
|
||
|
|
cam.End3D()
|
||
|
|
|
||
|
|
local sparkAttachment = viewModel:GetAttachment(1)
|
||
|
|
|
||
|
|
if self.nextSpark <= CurTime() then
|
||
|
|
self.nextSpark = CurTime() + math.random(1, 10)
|
||
|
|
|
||
|
|
local ef = EffectData()
|
||
|
|
ef:SetOrigin(sparkAttachment.Pos)
|
||
|
|
ef:SetMagnitude(math.random(1, 2))
|
||
|
|
ef:SetScale(0.1)
|
||
|
|
util.Effect("ElectricSpark", ef)
|
||
|
|
|
||
|
|
self:EmitSound("wn_stunstick/spark".. math.random(1, 4) ..".wav", nil, math.random(80, 120))
|
||
|
|
end
|
||
|
|
|
||
|
|
if (self.particle and self.particle:IsValid() and self:GetActivated()) then
|
||
|
|
self.particle:StopEmissionAndDestroyImmediately()
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
function SWEP:PrimaryAttack()
|
||
|
|
self:SetNextPrimaryFire(CurTime() + self.Primary.Delay)
|
||
|
|
|
||
|
|
if (!self:GetOwner():IsWepRaised()) then
|
||
|
|
return
|
||
|
|
end
|
||
|
|
|
||
|
|
if (self:GetOwner():KeyDown(IN_WALK)) then
|
||
|
|
if (SERVER) then
|
||
|
|
self:SetActivated(!self:GetActivated())
|
||
|
|
|
||
|
|
local state = self:GetActivated()
|
||
|
|
|
||
|
|
if (state) then
|
||
|
|
self:GetOwner():EmitSound("Weapon_StunStick.Activate")
|
||
|
|
else
|
||
|
|
self:GetOwner():EmitSound("Weapon_StunStick.Deactivate")
|
||
|
|
end
|
||
|
|
|
||
|
|
local model = string.lower(self:GetOwner():GetModel())
|
||
|
|
|
||
|
|
if (ix.anim.GetModelClass(model) == "metrocop") then
|
||
|
|
self:GetOwner():ForceSequence(state and "activatebaton" or "deactivatebaton", nil, nil, true)
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
if (CLIENT) then
|
||
|
|
timer.Simple(0, function()
|
||
|
|
if !(IsValid(self)) then return end
|
||
|
|
if (self:GetActivated()) then
|
||
|
|
self:CreateWMParticle()
|
||
|
|
else
|
||
|
|
if (self.particle and self.particle:IsValid()) then
|
||
|
|
self.particle:StopEmissionAndDestroyImmediately()
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end)
|
||
|
|
end
|
||
|
|
|
||
|
|
return
|
||
|
|
end
|
||
|
|
|
||
|
|
|
||
|
|
local result = hook.Run("CanDoMeleeAttack", self)
|
||
|
|
if (result == false) then
|
||
|
|
return
|
||
|
|
end
|
||
|
|
|
||
|
|
if (self:GetActivated()) then
|
||
|
|
self:DuckStunstickSound()
|
||
|
|
end
|
||
|
|
|
||
|
|
self:EmitSound("wn_stunstick/stunstick_swing".. math.random(1, 3) ..".wav")
|
||
|
|
self:SendWeaponAnim(ACT_VM_HITCENTER)
|
||
|
|
|
||
|
|
local damage = self.Primary.Damage
|
||
|
|
|
||
|
|
if (self:GetActivated()) then
|
||
|
|
damage = 10
|
||
|
|
end
|
||
|
|
|
||
|
|
self:GetOwner():SetAnimation(PLAYER_ATTACK1)
|
||
|
|
self:GetOwner():ViewPunch(Angle(1, 0, 0.125))
|
||
|
|
|
||
|
|
timer.Simple(0.1, function()
|
||
|
|
if !IsValid(self) then return end
|
||
|
|
self:GetOwner():LagCompensation(true)
|
||
|
|
local data = {}
|
||
|
|
data.start = self:GetOwner():GetShootPos()
|
||
|
|
data.endpos = data.start + self:GetOwner():GetAimVector()*72
|
||
|
|
data.filter = self:GetOwner()
|
||
|
|
local trace = util.TraceLine(data)
|
||
|
|
self:GetOwner():LagCompensation(false)
|
||
|
|
|
||
|
|
if (SERVER and trace.Hit) then
|
||
|
|
if (self:GetActivated()) then
|
||
|
|
local effect = EffectData()
|
||
|
|
effect:SetStart(trace.HitPos)
|
||
|
|
effect:SetNormal(trace.HitNormal)
|
||
|
|
effect:SetOrigin(trace.HitPos)
|
||
|
|
util.Effect("StunstickImpact", effect, true, true)
|
||
|
|
end
|
||
|
|
|
||
|
|
self:GetOwner():EmitSound("wn_stunstick/stunstick_fleshhit".. math.random(1, 3) ..".wav")
|
||
|
|
|
||
|
|
local entity = trace.Entity
|
||
|
|
|
||
|
|
if (IsValid(entity)) then
|
||
|
|
if (entity:IsPlayer()) then
|
||
|
|
if (self:GetActivated()) then
|
||
|
|
entity.ixStuns = (entity.ixStuns or 0) + 1
|
||
|
|
|
||
|
|
timer.Simple(10, function()
|
||
|
|
if (!entity.ixStuns) then return end
|
||
|
|
entity.ixStuns = math.max(entity.ixStuns - 1, 0)
|
||
|
|
end)
|
||
|
|
end
|
||
|
|
|
||
|
|
entity:ViewPunch(Angle(-20, math.random(-15, 15), math.random(-10, 10)))
|
||
|
|
|
||
|
|
if (self:GetActivated() and entity.ixStuns > 2) then
|
||
|
|
entity:SetRagdolled(true, 60)
|
||
|
|
ix.log.Add(entity, "knockedOut", "hit by stunstick owned by "..self:GetOwner():GetName())
|
||
|
|
entity.ixStuns = 0
|
||
|
|
|
||
|
|
return
|
||
|
|
end
|
||
|
|
elseif (entity:IsRagdoll()) then
|
||
|
|
damage = self:GetActivated() and 2 or 10
|
||
|
|
end
|
||
|
|
|
||
|
|
local damageInfo = DamageInfo()
|
||
|
|
damageInfo:SetAttacker(self:GetOwner())
|
||
|
|
damageInfo:SetInflictor(self)
|
||
|
|
damageInfo:SetDamage(damage)
|
||
|
|
damageInfo:SetDamageType(DMG_CLUB)
|
||
|
|
damageInfo:SetDamagePosition(trace.HitPos)
|
||
|
|
damageInfo:SetDamageForce(self:GetOwner():GetAimVector() * 10000)
|
||
|
|
entity:DispatchTraceAttack(damageInfo, data.start, data.endpos)
|
||
|
|
|
||
|
|
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end)
|
||
|
|
end
|
||
|
|
|
||
|
|
function SWEP:SecondaryAttack()
|
||
|
|
self:GetOwner():LagCompensation(true)
|
||
|
|
local data = {}
|
||
|
|
data.start = self:GetOwner():GetShootPos()
|
||
|
|
data.endpos = data.start + self:GetOwner():GetAimVector()*72
|
||
|
|
data.filter = self:GetOwner()
|
||
|
|
data.mins = Vector(-8, -8, -30)
|
||
|
|
data.maxs = Vector(8, 8, 10)
|
||
|
|
local trace = util.TraceHull(data)
|
||
|
|
local entity = trace.Entity
|
||
|
|
self:GetOwner():LagCompensation(false)
|
||
|
|
|
||
|
|
if (SERVER and IsValid(entity)) then
|
||
|
|
local bPushed = false
|
||
|
|
|
||
|
|
if (entity:IsDoor()) then
|
||
|
|
if (hook.Run("PlayerCanKnockOnDoor", self:GetOwner(), entity) == false) then
|
||
|
|
return
|
||
|
|
end
|
||
|
|
|
||
|
|
self:GetOwner():ViewPunch(Angle(-1.3, 1.8, 0))
|
||
|
|
self:GetOwner():EmitSound("physics/wood/wood_crate_impact_hard3.wav")
|
||
|
|
self:GetOwner():SetAnimation(PLAYER_ATTACK1)
|
||
|
|
|
||
|
|
self:SetNextSecondaryFire(CurTime() + 0.4)
|
||
|
|
self:SetNextPrimaryFire(CurTime() + 1)
|
||
|
|
elseif (entity:IsPlayer()) then
|
||
|
|
local direction = self:GetOwner():GetAimVector() * (300 + (self:GetOwner():GetCharacter():GetAttribute("str", 0) * 3))
|
||
|
|
direction.z = 0
|
||
|
|
entity:SetVelocity(direction)
|
||
|
|
|
||
|
|
hook.Run("PlayerPushedPlayer", self:GetOwner(), entity)
|
||
|
|
|
||
|
|
bPushed = true
|
||
|
|
else
|
||
|
|
local physObj = entity:GetPhysicsObject()
|
||
|
|
|
||
|
|
if (IsValid(physObj)) then
|
||
|
|
physObj:SetVelocity(self:GetOwner():GetAimVector() * 180)
|
||
|
|
end
|
||
|
|
|
||
|
|
bPushed = true
|
||
|
|
end
|
||
|
|
|
||
|
|
if (bPushed) then
|
||
|
|
self:SetNextSecondaryFire(CurTime() + 1.5)
|
||
|
|
self:SetNextPrimaryFire(CurTime() + 1.5)
|
||
|
|
self:GetOwner():EmitSound("Weapon_Crossbow.BoltHitBody")
|
||
|
|
|
||
|
|
local model = string.lower(self:GetOwner():GetModel())
|
||
|
|
|
||
|
|
if (ix.anim.GetModelClass(model) == "metrocop") then
|
||
|
|
self:GetOwner():ForceSequence("pushplayer")
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|