mirror of
https://github.com/lifestorm/wnsrc.git
synced 2025-12-17 05:43:46 +03:00
Upload
This commit is contained in:
227
gamemodes/terrortown/entities/weapons/weapon_ttt_beacon.lua
Normal file
227
gamemodes/terrortown/entities/weapons/weapon_ttt_beacon.lua
Normal file
@@ -0,0 +1,227 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
|
||||
-- DISABLED: Beacons are meant to signal locations. In practice no one uses
|
||||
-- them. I'm leaving the weapon in in case I think of a way to make it useful,
|
||||
-- or if you want to experiment with it. Uncomment the two lines that say
|
||||
-- "DISABLED" above them (ie. the AddCSLuaFile and SWEP.CanBuy) and the weapon will
|
||||
-- appear in the detective's equipment menu. Do the same for the ttt_beacon
|
||||
-- entity to make it all work.
|
||||
|
||||
--DISABLED
|
||||
--AddCSLuaFile()
|
||||
|
||||
SWEP.HoldType = "normal"
|
||||
|
||||
if CLIENT then
|
||||
SWEP.PrintName = "Beacon"
|
||||
SWEP.Slot = 6
|
||||
|
||||
SWEP.ViewModelFlip = false
|
||||
SWEP.ViewModelFOV = 10
|
||||
|
||||
SWEP.EquipMenuData = {
|
||||
type="Weapon",
|
||||
model="models/props_lab/reciever01b.mdl",
|
||||
desc="Broadcasts a location to everyone.\n\nUse to warn or group innocents."
|
||||
};
|
||||
|
||||
SWEP.Icon = "vgui/ttt/icon_beacon"
|
||||
end
|
||||
|
||||
SWEP.Base = "weapon_tttbase"
|
||||
|
||||
SWEP.ViewModel = "models/weapons/v_crowbar.mdl"
|
||||
SWEP.WorldModel = "models/props_lab/reciever01b.mdl"
|
||||
|
||||
SWEP.Primary.ClipSize = 3
|
||||
SWEP.Primary.DefaultClip = 1
|
||||
SWEP.Primary.Automatic = true
|
||||
SWEP.Primary.Ammo = "slam"
|
||||
SWEP.Primary.Delay = 1.0
|
||||
|
||||
SWEP.Secondary.ClipSize = -1
|
||||
SWEP.Secondary.DefaultClip = -1
|
||||
SWEP.Secondary.Automatic = true
|
||||
SWEP.Secondary.Ammo = "none"
|
||||
SWEP.Secondary.Delay = 1.0
|
||||
|
||||
SWEP.Kind = WEAPON_EQUIP
|
||||
-- DISABLED
|
||||
--SWEP.CanBuy = {ROLE_DETECTIVE} -- only detectives can buy
|
||||
SWEP.LimitedStock = true -- only buyable once
|
||||
SWEP.WeaponID = AMMO_BEACON
|
||||
|
||||
SWEP.Spawnable = true
|
||||
SWEP.AllowDrop = false
|
||||
SWEP.NoSights = true
|
||||
|
||||
function SWEP:OnDrop()
|
||||
self:Remove()
|
||||
end
|
||||
|
||||
function SWEP:PrimaryAttack()
|
||||
self:SetNextPrimaryFire( CurTime() + self.Primary.Delay )
|
||||
|
||||
if self:CanPrimaryAttack() then
|
||||
self:BeaconDrop()
|
||||
end
|
||||
end
|
||||
function SWEP:SecondaryAttack()
|
||||
self:SetNextSecondaryFire( CurTime() + self.Secondary.Delay )
|
||||
|
||||
if self:CanPrimaryAttack() then
|
||||
self:BeaconStick()
|
||||
end
|
||||
end
|
||||
|
||||
local throwsound = Sound( "Weapon_SLAM.SatchelThrow" )
|
||||
|
||||
-- might be able to move this drop/stick stuff into something more general now
|
||||
-- that a number of weapons use it
|
||||
function SWEP:BeaconDrop()
|
||||
if SERVER then
|
||||
local ply = self:GetOwner()
|
||||
if not IsValid(ply) then return end
|
||||
|
||||
if self.Planted then return end
|
||||
|
||||
local vsrc = ply:GetShootPos()
|
||||
local vang = ply:GetAimVector()
|
||||
local vvel = ply:GetVelocity()
|
||||
|
||||
local vthrow = vvel + vang * 200
|
||||
|
||||
local beacon = ents.Create("ttt_beacon")
|
||||
if IsValid(beacon) then
|
||||
beacon:SetPos(vsrc + vang * 10)
|
||||
beacon:SetOwner(ply)
|
||||
beacon:Spawn()
|
||||
|
||||
beacon:PointAtEntity(ply)
|
||||
|
||||
local ang = beacon:GetAngles()
|
||||
ang:RotateAroundAxis(ang:Right(), 90)
|
||||
beacon:SetAngles(ang)
|
||||
|
||||
beacon:PhysWake()
|
||||
local phys = beacon:GetPhysicsObject()
|
||||
if IsValid(phys) then
|
||||
phys:SetVelocity(vthrow)
|
||||
end
|
||||
|
||||
self:PlacedBeacon()
|
||||
end
|
||||
end
|
||||
|
||||
self:EmitSound(throwsound)
|
||||
end
|
||||
|
||||
function SWEP:BeaconStick()
|
||||
if SERVER then
|
||||
local ply = self:GetOwner()
|
||||
if not IsValid(ply) then return end
|
||||
|
||||
if self.Planted then return end
|
||||
|
||||
local ignore = {ply, self}
|
||||
local spos = ply:GetShootPos()
|
||||
local epos = spos + ply:GetAimVector() * 80
|
||||
local tr = util.TraceLine({start=spos, endpos=epos, filter=ignore, mask=MASK_SOLID})
|
||||
|
||||
if tr.HitWorld then
|
||||
local beacon = ents.Create("ttt_beacon")
|
||||
if IsValid(beacon) then
|
||||
beacon:PointAtEntity(ply)
|
||||
|
||||
local tr_ent = util.TraceEntity({start=spos, endpos=epos, filter=ignore, mask=MASK_SOLID}, beacon)
|
||||
|
||||
if tr_ent.HitWorld then
|
||||
|
||||
local ang = tr_ent.HitNormal:Angle()
|
||||
--ang:RotateAroundAxis(ang:Right(), -90)
|
||||
--ang:RotateAroundAxis(ang:Up(), -180)
|
||||
--ang:RotateAroundAxis(ang:Forward(), 90)
|
||||
|
||||
beacon:SetPos(tr_ent.HitPos + ang:Forward() * 2.5)
|
||||
beacon:SetAngles(ang)
|
||||
beacon:SetOwner(ply)
|
||||
beacon:Spawn()
|
||||
|
||||
local phys = beacon:GetPhysicsObject()
|
||||
if IsValid(phys) then
|
||||
phys:EnableMotion(false)
|
||||
end
|
||||
|
||||
beacon.IsOnWall = true
|
||||
|
||||
self:PlacedBeacon()
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:PlacedBeacon()
|
||||
self:TakePrimaryAmmo(1)
|
||||
|
||||
if not self:CanPrimaryAttack() then
|
||||
self:Remove()
|
||||
|
||||
self.Planted = true
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:PickupBeacon()
|
||||
if self:Clip1() >= self.Primary.ClipSize then
|
||||
return false
|
||||
else
|
||||
self:SetClip1(self:Clip1() + 1)
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
-- Ammo hackery after getting bought
|
||||
function SWEP:WasBought(buyer)
|
||||
self:SetClip1(self:Clip1() + 2)
|
||||
end
|
||||
|
||||
function SWEP:Reload()
|
||||
return false
|
||||
end
|
||||
|
||||
function SWEP:OnRemove()
|
||||
if CLIENT and IsValid(self:GetOwner()) and self:GetOwner() == LocalPlayer() and self:GetOwner():IsTerror() then
|
||||
RunConsoleCommand("lastinv")
|
||||
end
|
||||
end
|
||||
|
||||
if CLIENT then
|
||||
function SWEP:Initialize()
|
||||
self:AddHUDHelp("Click to place the beacon")
|
||||
|
||||
return self.BaseClass.Initialize(self)
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:Deploy()
|
||||
self:GetOwner():DrawViewModel(false)
|
||||
return true
|
||||
end
|
||||
|
||||
function SWEP:DrawWorldModel()
|
||||
if not IsValid(self:GetOwner()) then
|
||||
self:DrawModel()
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:DrawWorldModelTranslucent()
|
||||
end
|
||||
256
gamemodes/terrortown/entities/weapons/weapon_ttt_binoculars.lua
Normal file
256
gamemodes/terrortown/entities/weapons/weapon_ttt_binoculars.lua
Normal file
@@ -0,0 +1,256 @@
|
||||
--[[
|
||||
| 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()
|
||||
|
||||
DEFINE_BASECLASS "weapon_tttbase"
|
||||
|
||||
SWEP.HoldType = "normal"
|
||||
|
||||
if CLIENT then
|
||||
SWEP.PrintName = "binoc_name"
|
||||
SWEP.Slot = 7
|
||||
|
||||
SWEP.ViewModelFOV = 10
|
||||
SWEP.ViewModelFlip = false
|
||||
SWEP.DrawCrosshair = false
|
||||
|
||||
SWEP.EquipMenuData = {
|
||||
type = "item_weapon",
|
||||
desc = "binoc_desc"
|
||||
};
|
||||
|
||||
SWEP.Icon = "vgui/ttt/icon_binoc"
|
||||
end
|
||||
|
||||
SWEP.Base = "weapon_tttbase"
|
||||
|
||||
SWEP.ViewModel = "models/weapons/v_crowbar.mdl"
|
||||
SWEP.WorldModel = "models/props/cs_office/paper_towels.mdl"
|
||||
|
||||
SWEP.Primary.ClipSize = -1
|
||||
SWEP.Primary.DefaultClip = -1
|
||||
SWEP.Primary.Automatic = false
|
||||
SWEP.Primary.Ammo = "none"
|
||||
SWEP.Primary.Delay = 1.0
|
||||
|
||||
SWEP.Secondary.ClipSize = -1
|
||||
SWEP.Secondary.DefaultClip = -1
|
||||
SWEP.Secondary.Automatic = true
|
||||
SWEP.Secondary.Ammo = "none"
|
||||
SWEP.Secondary.Delay = 0.2
|
||||
|
||||
SWEP.Kind = WEAPON_EQUIP2
|
||||
SWEP.CanBuy = {ROLE_DETECTIVE} -- only detectives can buy
|
||||
SWEP.WeaponID = AMMO_BINOCULARS
|
||||
|
||||
SWEP.AllowDrop = true
|
||||
|
||||
SWEP.ZoomLevels = {
|
||||
0,
|
||||
30,
|
||||
20,
|
||||
10
|
||||
};
|
||||
|
||||
SWEP.ProcessingDelay = 5
|
||||
|
||||
function SWEP:SetupDataTables()
|
||||
self:DTVar("Bool", 0, "processing")
|
||||
self:DTVar("Float", 0, "start_time")
|
||||
self:DTVar("Int", 1, "zoom")
|
||||
|
||||
return self.BaseClass.SetupDataTables(self)
|
||||
end
|
||||
|
||||
|
||||
function SWEP:PrimaryAttack()
|
||||
self:SetNextPrimaryFire( CurTime() + 0.1 )
|
||||
|
||||
if self:IsTargetingCorpse() and not self.dt.processing then
|
||||
self:SetNextPrimaryFire( CurTime() + self.Primary.Delay )
|
||||
|
||||
if SERVER then
|
||||
self.dt.processing = true
|
||||
self.dt.start_time = CurTime()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local click = Sound("weapons/sniper/sniper_zoomin.wav")
|
||||
function SWEP:SecondaryAttack()
|
||||
self:SetNextSecondaryFire( CurTime() + self.Secondary.Delay )
|
||||
|
||||
if CLIENT and IsFirstTimePredicted() then
|
||||
LocalPlayer():EmitSound(click)
|
||||
end
|
||||
|
||||
self:CycleZoom()
|
||||
|
||||
self.dt.processing = false
|
||||
self.dt.start_time = 0
|
||||
end
|
||||
|
||||
function SWEP:SetZoom(level)
|
||||
if SERVER then
|
||||
self.dt.zoom = level
|
||||
self:GetOwner():SetFOV(self.ZoomLevels[level], 0.3)
|
||||
|
||||
self:GetOwner():DrawViewModel(false)
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:CycleZoom()
|
||||
self.dt.zoom = self.dt.zoom + 1
|
||||
if not self.ZoomLevels[self.dt.zoom] then
|
||||
self.dt.zoom = 1
|
||||
end
|
||||
|
||||
self:SetZoom(self.dt.zoom)
|
||||
end
|
||||
|
||||
function SWEP:PreDrop()
|
||||
self:SetZoom(1)
|
||||
self.dt.processing = false
|
||||
return self.BaseClass.PreDrop(self)
|
||||
end
|
||||
|
||||
function SWEP:Holster()
|
||||
self:SetZoom(1)
|
||||
self.dt.processing = false
|
||||
return true
|
||||
end
|
||||
|
||||
function SWEP:Deploy()
|
||||
if SERVER and IsValid(self:GetOwner()) then
|
||||
self:GetOwner():DrawViewModel(false)
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
|
||||
function SWEP:Reload()
|
||||
return false
|
||||
end
|
||||
|
||||
function SWEP:IsTargetingCorpse()
|
||||
local tr = self:GetOwner():GetEyeTrace(MASK_SHOT)
|
||||
local ent = tr.Entity
|
||||
|
||||
return (IsValid(ent) and ent:GetClass() == "prop_ragdoll" and
|
||||
CORPSE.GetPlayerNick(ent, false) != false)
|
||||
end
|
||||
|
||||
local confirm = Sound("npc/turret_floor/click1.wav")
|
||||
function SWEP:IdentifyCorpse()
|
||||
if SERVER then
|
||||
local tr = self:GetOwner():GetEyeTrace(MASK_SHOT)
|
||||
CORPSE.ShowSearch(self:GetOwner(), tr.Entity, false, true)
|
||||
elseif IsFirstTimePredicted() then
|
||||
LocalPlayer():EmitSound(confirm)
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:Think()
|
||||
BaseClass.Think(self)
|
||||
if self.dt.processing then
|
||||
if self:IsTargetingCorpse() then
|
||||
if CurTime() > (self.dt.start_time + self.ProcessingDelay) then
|
||||
self:IdentifyCorpse()
|
||||
|
||||
self.dt.processing = false
|
||||
self.dt.start_time = 0
|
||||
end
|
||||
else
|
||||
self.dt.processing = false
|
||||
self.dt.start_time = 0
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function SWEP:OnRemove()
|
||||
if CLIENT and IsValid(self:GetOwner()) and self:GetOwner() == LocalPlayer() and self:GetOwner():Alive() then
|
||||
RunConsoleCommand("lastinv")
|
||||
end
|
||||
end
|
||||
|
||||
if CLIENT then
|
||||
function SWEP:Initialize()
|
||||
self:AddHUDHelp("binoc_help_pri", "binoc_help_sec", true)
|
||||
|
||||
return self.BaseClass.Initialize(self)
|
||||
end
|
||||
|
||||
local T = LANG.GetTranslation
|
||||
function SWEP:DrawHUD()
|
||||
self:DrawHelp()
|
||||
|
||||
local length = 40
|
||||
local gap = 10
|
||||
|
||||
local corpse = self:IsTargetingCorpse()
|
||||
|
||||
if corpse then
|
||||
surface.SetDrawColor(0, 255, 0, 255)
|
||||
gap = 4
|
||||
length = 40
|
||||
else
|
||||
surface.SetDrawColor(0, 255, 0, 200)
|
||||
end
|
||||
|
||||
local x = ScrW() / 2.0
|
||||
local y = ScrH() / 2.0
|
||||
|
||||
surface.DrawLine( x - length, y, x - gap, y )
|
||||
surface.DrawLine( x + length, y, x + gap, y )
|
||||
surface.DrawLine( x, y - length, x, y - gap )
|
||||
surface.DrawLine( x, y + length, x, y + gap )
|
||||
|
||||
|
||||
surface.SetFont("DefaultFixedDropShadow")
|
||||
surface.SetTextColor(0, 255, 0, 200)
|
||||
surface.SetTextPos( x + length, y - length )
|
||||
surface.DrawText(T("binoc_zoom_level") .. " " .. self.dt.zoom)
|
||||
|
||||
if corpse then
|
||||
surface.SetTextPos( x + length, y - length + 15)
|
||||
surface.DrawText(T("binoc_body"))
|
||||
end
|
||||
|
||||
if self.dt.processing then
|
||||
y = y + (y / 2)
|
||||
|
||||
local w, h = 200, 20
|
||||
|
||||
surface.SetDrawColor(0, 255, 0, 255)
|
||||
surface.DrawOutlinedRect(x - w/2, y - h, w, h)
|
||||
|
||||
surface.SetDrawColor(0, 255, 0, 180)
|
||||
local pct = math.Clamp((CurTime() - self.dt.start_time) / self.ProcessingDelay, 0, 1)
|
||||
surface.DrawRect(x - w/2, y - h, w * pct, h)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function SWEP:DrawWorldModel()
|
||||
if not IsValid(self:GetOwner()) then
|
||||
self:DrawModel()
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:AdjustMouseSensitivity()
|
||||
if self.dt.zoom > 0 then
|
||||
return 1 / self.dt.zoom
|
||||
end
|
||||
return -1
|
||||
end
|
||||
end
|
||||
|
||||
182
gamemodes/terrortown/entities/weapons/weapon_ttt_c4.lua
Normal file
182
gamemodes/terrortown/entities/weapons/weapon_ttt_c4.lua
Normal file
@@ -0,0 +1,182 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
|
||||
-- traitor equipment: c4 bomb
|
||||
|
||||
AddCSLuaFile()
|
||||
|
||||
SWEP.HoldType = "slam"
|
||||
|
||||
if CLIENT then
|
||||
SWEP.PrintName = "C4"
|
||||
SWEP.Slot = 6
|
||||
|
||||
SWEP.ViewModelFlip = false
|
||||
SWEP.ViewModelFOV = 54
|
||||
SWEP.DrawCrosshair = false
|
||||
|
||||
SWEP.EquipMenuData = {
|
||||
type = "item_weapon",
|
||||
name = "C4",
|
||||
desc = "c4_desc"
|
||||
};
|
||||
|
||||
SWEP.Icon = "vgui/ttt/icon_c4"
|
||||
SWEP.IconLetter = "I"
|
||||
end
|
||||
|
||||
SWEP.Base = "weapon_tttbase"
|
||||
|
||||
SWEP.Kind = WEAPON_EQUIP
|
||||
SWEP.CanBuy = {ROLE_TRAITOR} -- only traitors can buy
|
||||
SWEP.WeaponID = AMMO_C4
|
||||
|
||||
SWEP.UseHands = true
|
||||
SWEP.ViewModel = Model("models/weapons/cstrike/c_c4.mdl")
|
||||
SWEP.WorldModel = Model("models/weapons/w_c4.mdl")
|
||||
|
||||
SWEP.Primary.ClipSize = -1
|
||||
SWEP.Primary.DefaultClip = -1
|
||||
SWEP.Primary.Automatic = true
|
||||
SWEP.Primary.Ammo = "none"
|
||||
SWEP.Primary.Delay = 5.0
|
||||
|
||||
SWEP.Secondary.ClipSize = -1
|
||||
SWEP.Secondary.DefaultClip = -1
|
||||
SWEP.Secondary.Automatic = true
|
||||
SWEP.Secondary.Ammo = "none"
|
||||
SWEP.Secondary.Delay = 1.0
|
||||
|
||||
SWEP.NoSights = true
|
||||
|
||||
local throwsound = Sound( "Weapon_SLAM.SatchelThrow" )
|
||||
|
||||
function SWEP:PrimaryAttack()
|
||||
self:SetNextPrimaryFire( CurTime() + self.Primary.Delay )
|
||||
self:BombDrop()
|
||||
end
|
||||
|
||||
function SWEP:SecondaryAttack()
|
||||
self:SetNextSecondaryFire( CurTime() + self.Secondary.Delay )
|
||||
self:BombStick()
|
||||
end
|
||||
|
||||
-- mostly replicating HL2DM slam throw here
|
||||
function SWEP:BombDrop()
|
||||
if SERVER then
|
||||
|
||||
local ply = self:GetOwner()
|
||||
if not IsValid(ply) then return end
|
||||
|
||||
if self.Planted then return end
|
||||
|
||||
local vsrc = ply:GetShootPos()
|
||||
local vang = ply:GetAimVector()
|
||||
local vvel = ply:GetVelocity()
|
||||
|
||||
local vthrow = vvel + vang * 200
|
||||
|
||||
local bomb = ents.Create("ttt_c4")
|
||||
if IsValid(bomb) then
|
||||
bomb:SetPos(vsrc + vang * 10)
|
||||
bomb:SetOwner(ply)
|
||||
bomb:SetThrower(ply)
|
||||
bomb:Spawn()
|
||||
|
||||
bomb:PointAtEntity(ply)
|
||||
|
||||
local ang = bomb:GetAngles()
|
||||
ang:RotateAroundAxis(ang:Up(), 180)
|
||||
bomb:SetAngles(ang)
|
||||
|
||||
bomb.fingerprints = self.fingerprints
|
||||
|
||||
bomb:PhysWake()
|
||||
local phys = bomb:GetPhysicsObject()
|
||||
if IsValid(phys) then
|
||||
phys:SetVelocity(vthrow)
|
||||
end
|
||||
self:Remove()
|
||||
|
||||
self.Planted = true
|
||||
|
||||
end
|
||||
|
||||
ply:SetAnimation( PLAYER_ATTACK1 )
|
||||
end
|
||||
|
||||
self:EmitSound(throwsound)
|
||||
self:SendWeaponAnim(ACT_VM_SECONDARYATTACK)
|
||||
end
|
||||
|
||||
-- again replicating slam, now its attach fn
|
||||
function SWEP:BombStick()
|
||||
if SERVER then
|
||||
local ply = self:GetOwner()
|
||||
if not IsValid(ply) then return end
|
||||
|
||||
if self.Planted then return end
|
||||
|
||||
local ignore = {ply, self}
|
||||
local spos = ply:GetShootPos()
|
||||
local epos = spos + ply:GetAimVector() * 80
|
||||
local tr = util.TraceLine({start=spos, endpos=epos, filter=ignore, mask=MASK_SOLID})
|
||||
|
||||
if tr.HitWorld then
|
||||
local bomb = ents.Create("ttt_c4")
|
||||
if IsValid(bomb) then
|
||||
bomb:PointAtEntity(ply)
|
||||
|
||||
local tr_ent = util.TraceEntity({start=spos, endpos=epos, filter=ignore, mask=MASK_SOLID}, bomb)
|
||||
|
||||
if tr_ent.HitWorld then
|
||||
|
||||
local ang = tr_ent.HitNormal:Angle()
|
||||
ang:RotateAroundAxis(ang:Right(), -90)
|
||||
ang:RotateAroundAxis(ang:Up(), 180)
|
||||
|
||||
bomb:SetPos(tr_ent.HitPos)
|
||||
bomb:SetAngles(ang)
|
||||
bomb:SetOwner(ply)
|
||||
bomb:SetThrower(ply)
|
||||
bomb:Spawn()
|
||||
|
||||
bomb.fingerprints = self.fingerprints
|
||||
|
||||
local phys = bomb:GetPhysicsObject()
|
||||
if IsValid(phys) then
|
||||
phys:EnableMotion(false)
|
||||
end
|
||||
|
||||
bomb.IsOnWall = true
|
||||
|
||||
self:Remove()
|
||||
|
||||
self.Planted = true
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
ply:SetAnimation( PLAYER_ATTACK1 )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function SWEP:Reload()
|
||||
return false
|
||||
end
|
||||
|
||||
function SWEP:OnRemove()
|
||||
if CLIENT and IsValid(self:GetOwner()) and self:GetOwner() == LocalPlayer() and self:GetOwner():Alive() then
|
||||
RunConsoleCommand("lastinv")
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,46 @@
|
||||
--[[
|
||||
| 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()
|
||||
|
||||
SWEP.HoldType = "grenade"
|
||||
|
||||
if CLIENT then
|
||||
SWEP.PrintName = "confgrenade_name"
|
||||
SWEP.Slot = 3
|
||||
|
||||
SWEP.ViewModelFlip = false
|
||||
SWEP.ViewModelFOV = 54
|
||||
|
||||
SWEP.Icon = "vgui/ttt/icon_nades"
|
||||
SWEP.IconLetter = "h"
|
||||
end
|
||||
|
||||
SWEP.Base = "weapon_tttbasegrenade"
|
||||
|
||||
SWEP.WeaponID = AMMO_DISCOMB
|
||||
SWEP.Kind = WEAPON_NADE
|
||||
|
||||
SWEP.Spawnable = true
|
||||
SWEP.AutoSpawnable = true
|
||||
|
||||
SWEP.UseHands = true
|
||||
SWEP.ViewModel = "models/weapons/cstrike/c_eq_fraggrenade.mdl"
|
||||
SWEP.WorldModel = "models/weapons/w_eq_fraggrenade.mdl"
|
||||
|
||||
SWEP.Weight = 5
|
||||
|
||||
-- really the only difference between grenade weapons: the model and the thrown
|
||||
-- ent.
|
||||
|
||||
function SWEP:GetGrenadeName()
|
||||
return "ttt_confgrenade_proj"
|
||||
end
|
||||
143
gamemodes/terrortown/entities/weapons/weapon_ttt_cse.lua
Normal file
143
gamemodes/terrortown/entities/weapons/weapon_ttt_cse.lua
Normal file
@@ -0,0 +1,143 @@
|
||||
--[[
|
||||
| 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()
|
||||
|
||||
SWEP.HoldType = "normal"
|
||||
|
||||
if CLIENT then
|
||||
SWEP.PrintName = "vis_name"
|
||||
SWEP.Slot = 6
|
||||
|
||||
SWEP.ViewModelFOV = 10
|
||||
SWEP.ViewModelFlip = false
|
||||
SWEP.DrawCrosshair = false
|
||||
|
||||
SWEP.EquipMenuData = {
|
||||
type = "item_weapon",
|
||||
desc = "vis_desc"
|
||||
};
|
||||
|
||||
SWEP.Icon = "vgui/ttt/icon_cse"
|
||||
end
|
||||
|
||||
SWEP.Base = "weapon_tttbase"
|
||||
|
||||
SWEP.ViewModel = Model("models/weapons/v_crowbar.mdl")
|
||||
SWEP.WorldModel = Model("models/Items/battery.mdl")
|
||||
|
||||
SWEP.Primary.ClipSize = -1
|
||||
SWEP.Primary.DefaultClip = -1
|
||||
SWEP.Primary.Automatic = false
|
||||
SWEP.Primary.Ammo = "none"
|
||||
SWEP.Primary.Delay = 1.0
|
||||
|
||||
SWEP.Secondary.ClipSize = -1
|
||||
SWEP.Secondary.DefaultClip = -1
|
||||
SWEP.Secondary.Automatic = true
|
||||
SWEP.Secondary.Ammo = "none"
|
||||
SWEP.Secondary.Delay = 0.2
|
||||
|
||||
SWEP.Kind = WEAPON_EQUIP
|
||||
SWEP.CanBuy = {ROLE_DETECTIVE} -- only detectives can buy
|
||||
SWEP.WeaponID = AMMO_CSE
|
||||
|
||||
SWEP.LimitedStock = true -- only buyable once
|
||||
SWEP.NoSights = true
|
||||
SWEP.AllowDrop = false
|
||||
|
||||
SWEP.DeathScanDelay = 15
|
||||
|
||||
function SWEP:PrimaryAttack()
|
||||
self:SetNextPrimaryFire( CurTime() + self.Primary.Delay )
|
||||
self:DropDevice()
|
||||
end
|
||||
|
||||
function SWEP:SecondaryAttack()
|
||||
self:SetNextSecondaryFire( CurTime() + self.Secondary.Delay )
|
||||
self:DropDevice()
|
||||
end
|
||||
|
||||
function SWEP:DrawWorldModel()
|
||||
end
|
||||
|
||||
function SWEP:OnDrop()
|
||||
self:Remove()
|
||||
end
|
||||
|
||||
function SWEP:PreDrop(isdeath)
|
||||
if isdeath then
|
||||
local cse = self:DropDevice()
|
||||
if IsValid(cse) then
|
||||
cse:SetDetonateTimer(self.DeathScanDelay or 10)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:Reload()
|
||||
return false
|
||||
end
|
||||
|
||||
function SWEP:OnRemove()
|
||||
if CLIENT and IsValid(self:GetOwner()) and self:GetOwner() == LocalPlayer() and self:GetOwner():Alive() then
|
||||
RunConsoleCommand("lastinv")
|
||||
end
|
||||
end
|
||||
|
||||
local throwsound = Sound( "Weapon_SLAM.SatchelThrow" )
|
||||
|
||||
function SWEP:DropDevice()
|
||||
local cse = nil
|
||||
|
||||
if SERVER then
|
||||
local ply = self:GetOwner()
|
||||
if not IsValid(ply) then return end
|
||||
|
||||
if self.Planted then return end
|
||||
|
||||
local vsrc = ply:GetShootPos()
|
||||
local vang = ply:GetAimVector()
|
||||
local vvel = ply:GetVelocity()
|
||||
|
||||
local vthrow = vvel + vang * 200
|
||||
|
||||
cse = ents.Create("ttt_cse_proj")
|
||||
if IsValid(cse) then
|
||||
cse:SetPos(vsrc + vang * 10)
|
||||
cse:SetOwner(ply)
|
||||
cse:SetThrower(ply)
|
||||
cse:Spawn()
|
||||
|
||||
cse:PhysWake()
|
||||
local phys = cse:GetPhysicsObject()
|
||||
if IsValid(phys) then
|
||||
phys:SetVelocity(vthrow)
|
||||
end
|
||||
|
||||
self:Remove()
|
||||
|
||||
self.Planted = true
|
||||
end
|
||||
end
|
||||
|
||||
self:EmitSound(throwsound)
|
||||
|
||||
return cse
|
||||
end
|
||||
|
||||
if CLIENT then
|
||||
function SWEP:Initialize()
|
||||
self:AddHUDHelp("vis_help_pri", nil, true)
|
||||
|
||||
return self.BaseClass.Initialize(self)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
198
gamemodes/terrortown/entities/weapons/weapon_ttt_decoy.lua
Normal file
198
gamemodes/terrortown/entities/weapons/weapon_ttt_decoy.lua
Normal file
@@ -0,0 +1,198 @@
|
||||
--[[
|
||||
| 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()
|
||||
|
||||
SWEP.HoldType = "normal"
|
||||
|
||||
if CLIENT then
|
||||
SWEP.PrintName = "decoy_name"
|
||||
SWEP.Slot = 7
|
||||
|
||||
SWEP.ViewModelFOV = 10
|
||||
SWEP.ViewModelFlip = false
|
||||
SWEP.DrawCrosshair = false
|
||||
|
||||
SWEP.EquipMenuData = {
|
||||
type = "item_weapon",
|
||||
desc = "decoy_desc"
|
||||
};
|
||||
|
||||
SWEP.Icon = "vgui/ttt/icon_beacon"
|
||||
end
|
||||
|
||||
SWEP.Base = "weapon_tttbase"
|
||||
|
||||
SWEP.ViewModel = "models/weapons/v_crowbar.mdl"
|
||||
SWEP.WorldModel = "models/props_lab/reciever01b.mdl"
|
||||
|
||||
SWEP.Primary.ClipSize = -1
|
||||
SWEP.Primary.DefaultClip = -1
|
||||
SWEP.Primary.Automatic = true
|
||||
SWEP.Primary.Ammo = "none"
|
||||
SWEP.Primary.Delay = 1.0
|
||||
|
||||
SWEP.Secondary.ClipSize = -1
|
||||
SWEP.Secondary.DefaultClip = -1
|
||||
SWEP.Secondary.Automatic = true
|
||||
SWEP.Secondary.Ammo = "none"
|
||||
SWEP.Secondary.Delay = 1.0
|
||||
|
||||
SWEP.Kind = WEAPON_EQUIP2
|
||||
SWEP.CanBuy = {ROLE_TRAITOR}
|
||||
SWEP.LimitedStock = true -- only buyable once
|
||||
SWEP.WeaponID = AMMO_DECOY
|
||||
|
||||
SWEP.AllowDrop = false
|
||||
SWEP.NoSights = true
|
||||
|
||||
function SWEP:OnDrop()
|
||||
self:Remove()
|
||||
end
|
||||
|
||||
function SWEP:PrimaryAttack()
|
||||
self:SetNextPrimaryFire( CurTime() + self.Primary.Delay )
|
||||
|
||||
self:DecoyStick()
|
||||
end
|
||||
function SWEP:SecondaryAttack()
|
||||
self:SetNextSecondaryFire( CurTime() + self.Secondary.Delay )
|
||||
|
||||
self:DecoyStick()
|
||||
end
|
||||
|
||||
local throwsound = Sound( "Weapon_SLAM.SatchelThrow" )
|
||||
|
||||
-- Drop is disabled to prevent traitors from placing the decoy in unreachable
|
||||
-- places.
|
||||
function SWEP:DecoyDrop()
|
||||
if SERVER then
|
||||
local ply = self:GetOwner()
|
||||
if not IsValid(ply) then return end
|
||||
|
||||
if self.Planted then return end
|
||||
|
||||
local vsrc = ply:GetShootPos()
|
||||
local vang = ply:GetAimVector()
|
||||
local vvel = ply:GetVelocity()
|
||||
|
||||
local vthrow = vvel + vang * 200
|
||||
|
||||
local decoy = ents.Create("ttt_decoy")
|
||||
if IsValid(decoy) then
|
||||
decoy:SetPos(vsrc + vang * 10)
|
||||
decoy:SetOwner(ply)
|
||||
decoy:Spawn()
|
||||
|
||||
decoy:PointAtEntity(ply)
|
||||
|
||||
local ang = decoy:GetAngles()
|
||||
ang:RotateAroundAxis(ang:Right(), 90)
|
||||
decoy:SetAngles(ang)
|
||||
|
||||
decoy:PhysWake()
|
||||
local phys = decoy:GetPhysicsObject()
|
||||
if IsValid(phys) then
|
||||
phys:SetVelocity(vthrow)
|
||||
end
|
||||
|
||||
self:PlacedDecoy(decoy)
|
||||
end
|
||||
end
|
||||
|
||||
self:EmitSound(throwsound)
|
||||
end
|
||||
|
||||
function SWEP:DecoyStick()
|
||||
if SERVER then
|
||||
local ply = self:GetOwner()
|
||||
if not IsValid(ply) then return end
|
||||
|
||||
if self.Planted then return end
|
||||
|
||||
local ignore = {ply, self}
|
||||
local spos = ply:GetShootPos()
|
||||
local epos = spos + ply:GetAimVector() * 80
|
||||
local tr = util.TraceLine({start=spos, endpos=epos, filter=ignore, mask=MASK_SOLID})
|
||||
|
||||
if tr.HitWorld then
|
||||
local decoy = ents.Create("ttt_decoy")
|
||||
if IsValid(decoy) then
|
||||
decoy:PointAtEntity(ply)
|
||||
|
||||
local tr_ent = util.TraceEntity({start=spos, endpos=epos, filter=ignore, mask=MASK_SOLID}, decoy)
|
||||
|
||||
if tr_ent.HitWorld then
|
||||
|
||||
local ang = tr_ent.HitNormal:Angle()
|
||||
|
||||
decoy:SetPos(tr_ent.HitPos + ang:Forward() * 2.5)
|
||||
decoy:SetAngles(ang)
|
||||
decoy:SetOwner(ply)
|
||||
decoy:Spawn()
|
||||
|
||||
local phys = decoy:GetPhysicsObject()
|
||||
if IsValid(phys) then
|
||||
phys:EnableMotion(false)
|
||||
end
|
||||
|
||||
decoy.IsOnWall = true
|
||||
|
||||
self:PlacedDecoy(decoy)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:PlacedDecoy(decoy)
|
||||
self:GetOwner().decoy = decoy
|
||||
|
||||
self:TakePrimaryAmmo(1)
|
||||
|
||||
if not self:CanPrimaryAttack() then
|
||||
self:Remove()
|
||||
|
||||
self.Planted = true
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:Reload()
|
||||
return false
|
||||
end
|
||||
|
||||
function SWEP:OnRemove()
|
||||
if CLIENT and IsValid(self:GetOwner()) and self:GetOwner() == LocalPlayer() and self:GetOwner():Alive() then
|
||||
RunConsoleCommand("lastinv")
|
||||
end
|
||||
end
|
||||
|
||||
if CLIENT then
|
||||
function SWEP:Initialize()
|
||||
self:AddHUDHelp("decoy_help_pri", nil, true)
|
||||
|
||||
return self.BaseClass.Initialize(self)
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:Deploy()
|
||||
self:GetOwner():DrawViewModel(false)
|
||||
return true
|
||||
end
|
||||
|
||||
function SWEP:DrawWorldModel()
|
||||
if not IsValid(self:GetOwner()) then
|
||||
self:DrawModel()
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:DrawWorldModelTranslucent()
|
||||
end
|
||||
108
gamemodes/terrortown/entities/weapons/weapon_ttt_defuser.lua
Normal file
108
gamemodes/terrortown/entities/weapons/weapon_ttt_defuser.lua
Normal file
@@ -0,0 +1,108 @@
|
||||
--[[
|
||||
| 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()
|
||||
|
||||
SWEP.HoldType = "slam"
|
||||
|
||||
if CLIENT then
|
||||
SWEP.PrintName = "defuser_name"
|
||||
SWEP.Slot = 7
|
||||
|
||||
SWEP.DrawCrosshair = false
|
||||
SWEP.ViewModelFOV = 10
|
||||
|
||||
SWEP.EquipMenuData = {
|
||||
type = "item_weapon",
|
||||
desc = "defuser_desc"
|
||||
};
|
||||
|
||||
SWEP.Icon = "vgui/ttt/icon_defuser"
|
||||
end
|
||||
|
||||
SWEP.Base = "weapon_tttbase"
|
||||
|
||||
SWEP.ViewModel = "models/weapons/v_crowbar.mdl"
|
||||
SWEP.WorldModel = "models/weapons/w_defuser.mdl"
|
||||
|
||||
SWEP.Primary.ClipSize = -1
|
||||
SWEP.Primary.DefaultClip = -1
|
||||
SWEP.Primary.Automatic = true
|
||||
SWEP.Primary.Delay = 1
|
||||
SWEP.Primary.Ammo = "none"
|
||||
|
||||
SWEP.Secondary.ClipSize = -1
|
||||
SWEP.Secondary.DefaultClip = -1
|
||||
SWEP.Secondary.Automatic = true
|
||||
SWEP.Secondary.Ammo = "none"
|
||||
SWEP.Secondary.Delay = 2
|
||||
|
||||
SWEP.Kind = WEAPON_EQUIP2
|
||||
SWEP.CanBuy = {ROLE_DETECTIVE} -- only detectives can buy
|
||||
SWEP.WeaponID = AMMO_DEFUSER
|
||||
|
||||
--SWEP.AllowDrop = false
|
||||
|
||||
local defuse = Sound("c4.disarmfinish")
|
||||
function SWEP:PrimaryAttack()
|
||||
self:SetNextPrimaryFire( CurTime() + self.Primary.Delay )
|
||||
|
||||
local spos = self:GetOwner():GetShootPos()
|
||||
local sdest = spos + (self:GetOwner():GetAimVector() * 80)
|
||||
|
||||
local tr = util.TraceLine({start=spos, endpos=sdest, filter=self:GetOwner(), mask=MASK_SHOT})
|
||||
|
||||
if IsValid(tr.Entity) and tr.Entity.Defusable then
|
||||
local bomb = tr.Entity
|
||||
if bomb.Defusable==true or bomb:Defusable() then
|
||||
if SERVER and bomb.Disarm then
|
||||
bomb:Disarm(self:GetOwner())
|
||||
sound.Play(defuse, bomb:GetPos())
|
||||
end
|
||||
|
||||
self:SetNextPrimaryFire( CurTime() + (self.Primary.Delay * 2) )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:SecondaryAttack()
|
||||
self:SetNextPrimaryFire( CurTime() + self.Primary.Delay )
|
||||
self:SetNextSecondaryFire( CurTime() + 0.1 )
|
||||
end
|
||||
|
||||
|
||||
if CLIENT then
|
||||
function SWEP:Initialize()
|
||||
self:AddHUDHelp("defuser_help", nil, true)
|
||||
|
||||
return self.BaseClass.Initialize(self)
|
||||
end
|
||||
|
||||
function SWEP:DrawWorldModel()
|
||||
if not IsValid(self:GetOwner()) then
|
||||
self:DrawModel()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:Reload()
|
||||
return false
|
||||
end
|
||||
|
||||
function SWEP:Deploy()
|
||||
if SERVER and IsValid(self:GetOwner()) then
|
||||
self:GetOwner():DrawViewModel(false)
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
|
||||
function SWEP:OnDrop()
|
||||
end
|
||||
216
gamemodes/terrortown/entities/weapons/weapon_ttt_flaregun.lua
Normal file
216
gamemodes/terrortown/entities/weapons/weapon_ttt_flaregun.lua
Normal file
@@ -0,0 +1,216 @@
|
||||
--[[
|
||||
| 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()
|
||||
|
||||
SWEP.HoldType = "pistol"
|
||||
|
||||
if CLIENT then
|
||||
SWEP.PrintName = "flare_name"
|
||||
SWEP.Slot = 6
|
||||
|
||||
SWEP.ViewModelFOV = 54
|
||||
SWEP.ViewModelFlip = false
|
||||
|
||||
SWEP.EquipMenuData = {
|
||||
type = "item_weapon",
|
||||
desc = "flare_desc"
|
||||
};
|
||||
|
||||
SWEP.Icon = "vgui/ttt/icon_flare"
|
||||
end
|
||||
|
||||
SWEP.Base = "weapon_tttbase"
|
||||
|
||||
-- if I run out of ammo types, this weapon is one I could move to a custom ammo
|
||||
-- handling strategy, because you never need to pick up ammo for it
|
||||
SWEP.Primary.Ammo = "AR2AltFire"
|
||||
SWEP.Primary.Recoil = 4
|
||||
SWEP.Primary.Damage = 7
|
||||
SWEP.Primary.Delay = 1.0
|
||||
SWEP.Primary.Cone = 0.01
|
||||
SWEP.Primary.ClipSize = 4
|
||||
SWEP.Primary.Automatic = false
|
||||
SWEP.Primary.DefaultClip = 4
|
||||
SWEP.Primary.ClipMax = 4
|
||||
SWEP.Primary.Sound = Sound( "Weapon_USP.SilencedShot" )
|
||||
|
||||
SWEP.Kind = WEAPON_EQUIP
|
||||
SWEP.CanBuy = {ROLE_TRAITOR} -- only traitors can buy
|
||||
SWEP.LimitedStock = true -- only buyable once
|
||||
SWEP.WeaponID = AMMO_FLARE
|
||||
|
||||
SWEP.Tracer = "AR2Tracer"
|
||||
|
||||
SWEP.UseHands = true
|
||||
SWEP.ViewModel = Model("models/weapons/c_357.mdl")
|
||||
SWEP.WorldModel = Model("models/weapons/w_357.mdl")
|
||||
|
||||
local function RunIgniteTimer(ent, timer_name)
|
||||
if IsValid(ent) and ent:IsOnFire() then
|
||||
if ent:WaterLevel() > 0 then
|
||||
ent:Extinguish()
|
||||
elseif CurTime() > ent.burn_destroy then
|
||||
ent:SetNotSolid(true)
|
||||
ent:Remove()
|
||||
else
|
||||
-- keep on burning
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
timer.Remove(timer_name) -- stop running timer
|
||||
end
|
||||
|
||||
local SendScorches
|
||||
|
||||
if CLIENT then
|
||||
local function ReceiveScorches()
|
||||
local ent = net.ReadEntity()
|
||||
local num = net.ReadUInt(8)
|
||||
for i=1, num do
|
||||
util.PaintDown(net.ReadVector(), "FadingScorch", ent)
|
||||
end
|
||||
|
||||
if IsValid(ent) then
|
||||
util.PaintDown(ent:LocalToWorld(ent:OBBCenter()), "Scorch", ent)
|
||||
end
|
||||
end
|
||||
net.Receive("TTT_FlareScorch", ReceiveScorches)
|
||||
else
|
||||
-- it's sad that decals are so unreliable when drawn serverside, failing to
|
||||
-- draw more often than they work, that I have to do this
|
||||
SendScorches = function(ent, tbl)
|
||||
net.Start("TTT_FlareScorch")
|
||||
net.WriteEntity(ent)
|
||||
net.WriteUInt(#tbl, 8)
|
||||
for _, p in ipairs(tbl) do
|
||||
net.WriteVector(p)
|
||||
end
|
||||
net.Broadcast()
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
local function ScorchUnderRagdoll(ent)
|
||||
if SERVER then
|
||||
local postbl = {}
|
||||
-- small scorches under limbs
|
||||
for i=0, ent:GetPhysicsObjectCount()-1 do
|
||||
local subphys = ent:GetPhysicsObjectNum(i)
|
||||
if IsValid(subphys) then
|
||||
local pos = subphys:GetPos()
|
||||
util.PaintDown(pos, "FadingScorch", ent)
|
||||
|
||||
table.insert(postbl, pos)
|
||||
end
|
||||
end
|
||||
|
||||
SendScorches(ent, postbl)
|
||||
end
|
||||
|
||||
-- big scorch at center
|
||||
local mid = ent:LocalToWorld(ent:OBBCenter())
|
||||
mid.z = mid.z + 25
|
||||
util.PaintDown(mid, "Scorch", ent)
|
||||
end
|
||||
|
||||
|
||||
function IgniteTarget(att, path, dmginfo)
|
||||
local ent = path.Entity
|
||||
if not IsValid(ent) then return end
|
||||
|
||||
if CLIENT and IsFirstTimePredicted() then
|
||||
if ent:GetClass() == "prop_ragdoll" then
|
||||
ScorchUnderRagdoll(ent)
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
if SERVER then
|
||||
|
||||
local dur = ent:IsPlayer() and 5 or 10
|
||||
|
||||
-- disallow if prep or post round
|
||||
if ent:IsPlayer() and (not GAMEMODE:AllowPVP()) then return end
|
||||
|
||||
ent:Ignite(dur, 100)
|
||||
|
||||
ent.ignite_info = {att=dmginfo:GetAttacker(), infl=dmginfo:GetInflictor()}
|
||||
|
||||
if ent:IsPlayer() then
|
||||
timer.Simple(dur + 0.1, function()
|
||||
if IsValid(ent) then
|
||||
ent.ignite_info = nil
|
||||
end
|
||||
end)
|
||||
|
||||
elseif ent:GetClass() == "prop_ragdoll" then
|
||||
ScorchUnderRagdoll(ent)
|
||||
|
||||
local burn_time = 6
|
||||
local tname = Format("ragburn_%d_%d", ent:EntIndex(), math.ceil(CurTime()))
|
||||
|
||||
ent.burn_destroy = CurTime() + burn_time
|
||||
|
||||
timer.Create(tname,
|
||||
0.1,
|
||||
math.ceil(1 + burn_time / 0.1), -- upper limit, failsafe
|
||||
function()
|
||||
RunIgniteTimer(ent, tname)
|
||||
end)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:ShootFlare()
|
||||
local cone = self.Primary.Cone
|
||||
local bullet = {}
|
||||
bullet.Num = 1
|
||||
bullet.Src = self:GetOwner():GetShootPos()
|
||||
bullet.Dir = self:GetOwner():GetAimVector()
|
||||
bullet.Spread = Vector( cone, cone, 0 )
|
||||
bullet.Tracer = 1
|
||||
bullet.Force = 2
|
||||
bullet.Damage = self.Primary.Damage
|
||||
bullet.TracerName = self.Tracer
|
||||
bullet.Callback = IgniteTarget
|
||||
|
||||
self:GetOwner():FireBullets( bullet )
|
||||
end
|
||||
|
||||
function SWEP:PrimaryAttack()
|
||||
self:SetNextPrimaryFire( CurTime() + self.Primary.Delay )
|
||||
|
||||
if not self:CanPrimaryAttack() then return end
|
||||
|
||||
self:EmitSound( self.Primary.Sound )
|
||||
|
||||
self:SendWeaponAnim( ACT_VM_PRIMARYATTACK )
|
||||
|
||||
self:ShootFlare()
|
||||
|
||||
self:TakePrimaryAmmo( 1 )
|
||||
|
||||
if IsValid(self:GetOwner()) then
|
||||
self:GetOwner():SetAnimation( PLAYER_ATTACK1 )
|
||||
|
||||
self:GetOwner():ViewPunch( Angle( math.Rand(-0.2,-0.1) * self.Primary.Recoil, math.Rand(-0.1,0.1) *self.Primary.Recoil, 0 ) )
|
||||
end
|
||||
|
||||
if ( (game.SinglePlayer() && SERVER) || CLIENT ) then
|
||||
self:SetNWFloat( "LastShootTime", CurTime() )
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:SecondaryAttack()
|
||||
end
|
||||
51
gamemodes/terrortown/entities/weapons/weapon_ttt_glock.lua
Normal file
51
gamemodes/terrortown/entities/weapons/weapon_ttt_glock.lua
Normal file
@@ -0,0 +1,51 @@
|
||||
--[[
|
||||
| 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()
|
||||
|
||||
SWEP.HoldType = "pistol"
|
||||
|
||||
if CLIENT then
|
||||
SWEP.PrintName = "Glock"
|
||||
SWEP.Slot = 1
|
||||
|
||||
SWEP.ViewModelFlip = false
|
||||
SWEP.ViewModelFOV = 54
|
||||
|
||||
SWEP.Icon = "vgui/ttt/icon_glock"
|
||||
SWEP.IconLetter = "c"
|
||||
end
|
||||
|
||||
SWEP.Base = "weapon_tttbase"
|
||||
|
||||
SWEP.Primary.Recoil = 0.9
|
||||
SWEP.Primary.Damage = 12
|
||||
SWEP.Primary.Delay = 0.10
|
||||
SWEP.Primary.Cone = 0.028
|
||||
SWEP.Primary.ClipSize = 20
|
||||
SWEP.Primary.Automatic = true
|
||||
SWEP.Primary.DefaultClip = 20
|
||||
SWEP.Primary.ClipMax = 60
|
||||
SWEP.Primary.Ammo = "Pistol"
|
||||
SWEP.Primary.Sound = Sound( "Weapon_Glock.Single" )
|
||||
|
||||
SWEP.AutoSpawnable = true
|
||||
|
||||
SWEP.AmmoEnt = "item_ammo_pistol_ttt"
|
||||
SWEP.Kind = WEAPON_PISTOL
|
||||
SWEP.WeaponID = AMMO_GLOCK
|
||||
|
||||
SWEP.HeadshotMultiplier = 1.75
|
||||
|
||||
SWEP.UseHands = true
|
||||
SWEP.ViewModel = "models/weapons/cstrike/c_pist_glock18.mdl"
|
||||
SWEP.WorldModel = "models/weapons/w_pist_glock18.mdl"
|
||||
|
||||
SWEP.IronSightsPos = Vector( -5.79, -3.9982, 2.8289 )
|
||||
@@ -0,0 +1,137 @@
|
||||
--[[
|
||||
| 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()
|
||||
|
||||
SWEP.HoldType = "normal"
|
||||
|
||||
if CLIENT then
|
||||
SWEP.PrintName = "hstation_name"
|
||||
SWEP.Slot = 6
|
||||
|
||||
SWEP.ViewModelFOV = 10
|
||||
SWEP.DrawCrosshair = false
|
||||
|
||||
SWEP.EquipMenuData = {
|
||||
type = "item_weapon",
|
||||
desc = "hstation_desc"
|
||||
};
|
||||
|
||||
SWEP.Icon = "vgui/ttt/icon_health"
|
||||
end
|
||||
|
||||
SWEP.Base = "weapon_tttbase"
|
||||
|
||||
SWEP.ViewModel = "models/weapons/v_crowbar.mdl"
|
||||
SWEP.WorldModel = "models/props/cs_office/microwave.mdl"
|
||||
|
||||
SWEP.Primary.ClipSize = -1
|
||||
SWEP.Primary.DefaultClip = -1
|
||||
SWEP.Primary.Automatic = true
|
||||
SWEP.Primary.Ammo = "none"
|
||||
SWEP.Primary.Delay = 1.0
|
||||
|
||||
SWEP.Secondary.ClipSize = -1
|
||||
SWEP.Secondary.DefaultClip = -1
|
||||
SWEP.Secondary.Automatic = true
|
||||
SWEP.Secondary.Ammo = "none"
|
||||
SWEP.Secondary.Delay = 1.0
|
||||
|
||||
-- This is special equipment
|
||||
SWEP.Kind = WEAPON_EQUIP
|
||||
SWEP.CanBuy = {ROLE_DETECTIVE} -- only detectives can buy
|
||||
SWEP.LimitedStock = true -- only buyable once
|
||||
SWEP.WeaponID = AMMO_HEALTHSTATION
|
||||
|
||||
SWEP.AllowDrop = false
|
||||
SWEP.NoSights = true
|
||||
|
||||
function SWEP:OnDrop()
|
||||
self:Remove()
|
||||
end
|
||||
|
||||
function SWEP:PrimaryAttack()
|
||||
self:SetNextPrimaryFire( CurTime() + self.Primary.Delay )
|
||||
self:HealthDrop()
|
||||
end
|
||||
function SWEP:SecondaryAttack()
|
||||
self:SetNextSecondaryFire( CurTime() + self.Secondary.Delay )
|
||||
self:HealthDrop()
|
||||
end
|
||||
|
||||
local throwsound = Sound( "Weapon_SLAM.SatchelThrow" )
|
||||
|
||||
-- ye olde droppe code
|
||||
function SWEP:HealthDrop()
|
||||
if SERVER then
|
||||
local ply = self:GetOwner()
|
||||
if not IsValid(ply) then return end
|
||||
|
||||
if self.Planted then return end
|
||||
|
||||
local vsrc = ply:GetShootPos()
|
||||
local vang = ply:GetAimVector()
|
||||
local vvel = ply:GetVelocity()
|
||||
|
||||
local vthrow = vvel + vang * 200
|
||||
|
||||
local health = ents.Create("ttt_health_station")
|
||||
if IsValid(health) then
|
||||
health:SetPos(vsrc + vang * 10)
|
||||
health:Spawn()
|
||||
|
||||
health:SetPlacer(ply)
|
||||
|
||||
health:PhysWake()
|
||||
local phys = health:GetPhysicsObject()
|
||||
if IsValid(phys) then
|
||||
phys:SetVelocity(vthrow)
|
||||
end
|
||||
self:Remove()
|
||||
|
||||
self.Planted = true
|
||||
end
|
||||
end
|
||||
|
||||
self:EmitSound(throwsound)
|
||||
end
|
||||
|
||||
|
||||
function SWEP:Reload()
|
||||
return false
|
||||
end
|
||||
|
||||
function SWEP:OnRemove()
|
||||
if CLIENT and IsValid(self:GetOwner()) and self:GetOwner() == LocalPlayer() and self:GetOwner():Alive() then
|
||||
RunConsoleCommand("lastinv")
|
||||
end
|
||||
end
|
||||
|
||||
if CLIENT then
|
||||
function SWEP:Initialize()
|
||||
self:AddHUDHelp("hstation_help", nil, true)
|
||||
|
||||
return self.BaseClass.Initialize(self)
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:Deploy()
|
||||
if SERVER and IsValid(self:GetOwner()) then
|
||||
self:GetOwner():DrawViewModel(false)
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
function SWEP:DrawWorldModel()
|
||||
end
|
||||
|
||||
function SWEP:DrawWorldModelTranslucent()
|
||||
end
|
||||
|
||||
312
gamemodes/terrortown/entities/weapons/weapon_ttt_knife.lua
Normal file
312
gamemodes/terrortown/entities/weapons/weapon_ttt_knife.lua
Normal file
@@ -0,0 +1,312 @@
|
||||
--[[
|
||||
| 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()
|
||||
|
||||
SWEP.HoldType = "knife"
|
||||
|
||||
if CLIENT then
|
||||
SWEP.PrintName = "knife_name"
|
||||
SWEP.Slot = 6
|
||||
|
||||
SWEP.ViewModelFlip = false
|
||||
SWEP.ViewModelFOV = 54
|
||||
SWEP.DrawCrosshair = false
|
||||
|
||||
SWEP.EquipMenuData = {
|
||||
type = "item_weapon",
|
||||
desc = "knife_desc"
|
||||
};
|
||||
|
||||
SWEP.Icon = "vgui/ttt/icon_knife"
|
||||
SWEP.IconLetter = "j"
|
||||
end
|
||||
|
||||
SWEP.Base = "weapon_tttbase"
|
||||
|
||||
SWEP.UseHands = true
|
||||
SWEP.ViewModel = "models/weapons/cstrike/c_knife_t.mdl"
|
||||
SWEP.WorldModel = "models/weapons/w_knife_t.mdl"
|
||||
|
||||
SWEP.Primary.Damage = 50
|
||||
SWEP.Primary.ClipSize = -1
|
||||
SWEP.Primary.DefaultClip = -1
|
||||
SWEP.Primary.Automatic = true
|
||||
SWEP.Primary.Delay = 1.1
|
||||
SWEP.Primary.Ammo = "none"
|
||||
|
||||
SWEP.Secondary.ClipSize = -1
|
||||
SWEP.Secondary.DefaultClip = -1
|
||||
SWEP.Secondary.Automatic = true
|
||||
SWEP.Secondary.Ammo = "none"
|
||||
SWEP.Secondary.Delay = 1.4
|
||||
|
||||
SWEP.Kind = WEAPON_EQUIP
|
||||
SWEP.CanBuy = {ROLE_TRAITOR} -- only traitors can buy
|
||||
SWEP.LimitedStock = true -- only buyable once
|
||||
SWEP.WeaponID = AMMO_KNIFE
|
||||
|
||||
SWEP.IsSilent = true
|
||||
|
||||
-- Pull out faster than standard guns
|
||||
SWEP.DeploySpeed = 2
|
||||
|
||||
function SWEP:PrimaryAttack()
|
||||
self:SetNextPrimaryFire( CurTime() + self.Primary.Delay )
|
||||
self:SetNextSecondaryFire( CurTime() + self.Secondary.Delay )
|
||||
|
||||
if not IsValid(self:GetOwner()) then return end
|
||||
|
||||
self:GetOwner():LagCompensation(true)
|
||||
|
||||
local spos = self:GetOwner():GetShootPos()
|
||||
local sdest = spos + (self:GetOwner():GetAimVector() * 70)
|
||||
|
||||
local kmins = Vector(1,1,1) * -10
|
||||
local kmaxs = Vector(1,1,1) * 10
|
||||
|
||||
local tr = util.TraceHull({start=spos, endpos=sdest, filter=self:GetOwner(), mask=MASK_SHOT_HULL, mins=kmins, maxs=kmaxs})
|
||||
|
||||
-- Hull might hit environment stuff that line does not hit
|
||||
if not IsValid(tr.Entity) then
|
||||
tr = util.TraceLine({start=spos, endpos=sdest, filter=self:GetOwner(), mask=MASK_SHOT_HULL})
|
||||
end
|
||||
|
||||
local hitEnt = tr.Entity
|
||||
|
||||
-- effects
|
||||
if IsValid(hitEnt) then
|
||||
self:SendWeaponAnim( ACT_VM_HITCENTER )
|
||||
|
||||
local edata = EffectData()
|
||||
edata:SetStart(spos)
|
||||
edata:SetOrigin(tr.HitPos)
|
||||
edata:SetNormal(tr.Normal)
|
||||
edata:SetEntity(hitEnt)
|
||||
|
||||
if hitEnt:IsPlayer() or hitEnt:GetClass() == "prop_ragdoll" then
|
||||
util.Effect("BloodImpact", edata)
|
||||
end
|
||||
else
|
||||
self:SendWeaponAnim( ACT_VM_MISSCENTER )
|
||||
end
|
||||
|
||||
if SERVER then
|
||||
self:GetOwner():SetAnimation( PLAYER_ATTACK1 )
|
||||
end
|
||||
|
||||
|
||||
if SERVER and tr.Hit and tr.HitNonWorld and IsValid(hitEnt) then
|
||||
if hitEnt:IsPlayer() then
|
||||
-- knife damage is never karma'd, so don't need to take that into
|
||||
-- account we do want to avoid rounding error strangeness caused by
|
||||
-- other damage scaling, causing a death when we don't expect one, so
|
||||
-- when the target's health is close to kill-point we just kill
|
||||
if hitEnt:Health() < (self.Primary.Damage + 10) then
|
||||
self:StabKill(tr, spos, sdest)
|
||||
else
|
||||
local dmg = DamageInfo()
|
||||
dmg:SetDamage(self.Primary.Damage)
|
||||
dmg:SetAttacker(self:GetOwner())
|
||||
dmg:SetInflictor(self)
|
||||
dmg:SetDamageForce(self:GetOwner():GetAimVector() * 5)
|
||||
dmg:SetDamagePosition(self:GetOwner():GetPos())
|
||||
dmg:SetDamageType(DMG_SLASH)
|
||||
|
||||
hitEnt:DispatchTraceAttack(dmg, spos + (self:GetOwner():GetAimVector() * 3), sdest)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
self:GetOwner():LagCompensation(false)
|
||||
end
|
||||
|
||||
function SWEP:StabKill(tr, spos, sdest)
|
||||
local target = tr.Entity
|
||||
|
||||
local dmg = DamageInfo()
|
||||
dmg:SetDamage(2000)
|
||||
dmg:SetAttacker(self:GetOwner())
|
||||
dmg:SetInflictor(self)
|
||||
dmg:SetDamageForce(self:GetOwner():GetAimVector())
|
||||
dmg:SetDamagePosition(self:GetOwner():GetPos())
|
||||
dmg:SetDamageType(DMG_SLASH)
|
||||
|
||||
-- now that we use a hull trace, our hitpos is guaranteed to be
|
||||
-- terrible, so try to make something of it with a separate trace and
|
||||
-- hope our effect_fn trace has more luck
|
||||
|
||||
-- first a straight up line trace to see if we aimed nicely
|
||||
local retr = util.TraceLine({start=spos, endpos=sdest, filter=self:GetOwner(), mask=MASK_SHOT_HULL})
|
||||
|
||||
-- if that fails, just trace to worldcenter so we have SOMETHING
|
||||
if retr.Entity != target then
|
||||
local center = target:LocalToWorld(target:OBBCenter())
|
||||
retr = util.TraceLine({start=spos, endpos=center, filter=self:GetOwner(), mask=MASK_SHOT_HULL})
|
||||
end
|
||||
|
||||
|
||||
-- create knife effect creation fn
|
||||
local bone = retr.PhysicsBone
|
||||
local pos = retr.HitPos
|
||||
local norm = tr.Normal
|
||||
local ang = Angle(-28,0,0) + norm:Angle()
|
||||
ang:RotateAroundAxis(ang:Right(), -90)
|
||||
pos = pos - (ang:Forward() * 7)
|
||||
|
||||
local prints = self.fingerprints
|
||||
local ignore = self:GetOwner()
|
||||
|
||||
target.effect_fn = function(rag)
|
||||
-- we might find a better location
|
||||
local rtr = util.TraceLine({start=pos, endpos=pos + norm * 40, filter=ignore, mask=MASK_SHOT_HULL})
|
||||
|
||||
if IsValid(rtr.Entity) and rtr.Entity == rag then
|
||||
bone = rtr.PhysicsBone
|
||||
pos = rtr.HitPos
|
||||
ang = Angle(-28,0,0) + rtr.Normal:Angle()
|
||||
ang:RotateAroundAxis(ang:Right(), -90)
|
||||
pos = pos - (ang:Forward() * 10)
|
||||
|
||||
end
|
||||
|
||||
local knife = ents.Create("prop_physics")
|
||||
knife:SetModel("models/weapons/w_knife_t.mdl")
|
||||
knife:SetPos(pos)
|
||||
knife:SetCollisionGroup(COLLISION_GROUP_DEBRIS)
|
||||
knife:SetAngles(ang)
|
||||
knife.CanPickup = false
|
||||
|
||||
knife:Spawn()
|
||||
|
||||
local phys = knife:GetPhysicsObject()
|
||||
if IsValid(phys) then
|
||||
phys:EnableCollisions(false)
|
||||
end
|
||||
|
||||
constraint.Weld(rag, knife, bone, 0, 0, true)
|
||||
|
||||
-- need to close over knife in order to keep a valid ref to it
|
||||
rag:CallOnRemove("ttt_knife_cleanup", function() SafeRemoveEntity(knife) end)
|
||||
end
|
||||
|
||||
|
||||
-- seems the spos and sdest are purely for effects/forces?
|
||||
target:DispatchTraceAttack(dmg, spos + (self:GetOwner():GetAimVector() * 3), sdest)
|
||||
|
||||
-- target appears to die right there, so we could theoretically get to
|
||||
-- the ragdoll in here...
|
||||
|
||||
self:Remove()
|
||||
end
|
||||
|
||||
function SWEP:SecondaryAttack()
|
||||
self:SetNextPrimaryFire( CurTime() + self.Primary.Delay )
|
||||
self:SetNextSecondaryFire( CurTime() + self.Secondary.Delay )
|
||||
|
||||
|
||||
self:SendWeaponAnim( ACT_VM_MISSCENTER )
|
||||
|
||||
if SERVER then
|
||||
local ply = self:GetOwner()
|
||||
if not IsValid(ply) then return end
|
||||
|
||||
ply:SetAnimation( PLAYER_ATTACK1 )
|
||||
|
||||
local ang = ply:EyeAngles()
|
||||
|
||||
if ang.p < 90 then
|
||||
ang.p = -10 + ang.p * ((90 + 10) / 90)
|
||||
else
|
||||
ang.p = 360 - ang.p
|
||||
ang.p = -10 + ang.p * -((90 + 10) / 90)
|
||||
end
|
||||
|
||||
local vel = math.Clamp((90 - ang.p) * 5.5, 550, 800)
|
||||
|
||||
local vfw = ang:Forward()
|
||||
local vrt = ang:Right()
|
||||
|
||||
local src = ply:GetPos() + (ply:Crouching() and ply:GetViewOffsetDucked() or ply:GetViewOffset())
|
||||
|
||||
src = src + (vfw * 1) + (vrt * 3)
|
||||
|
||||
local thr = vfw * vel + ply:GetVelocity()
|
||||
|
||||
local knife_ang = Angle(-28,0,0) + ang
|
||||
knife_ang:RotateAroundAxis(knife_ang:Right(), -90)
|
||||
|
||||
local knife = ents.Create("ttt_knife_proj")
|
||||
if not IsValid(knife) then return end
|
||||
knife:SetPos(src)
|
||||
knife:SetAngles(knife_ang)
|
||||
|
||||
knife:Spawn()
|
||||
|
||||
knife.Damage = self.Primary.Damage
|
||||
|
||||
knife:SetOwner(ply)
|
||||
|
||||
local phys = knife:GetPhysicsObject()
|
||||
if IsValid(phys) then
|
||||
phys:SetVelocity(thr)
|
||||
phys:AddAngleVelocity(Vector(0, 1500, 0))
|
||||
phys:Wake()
|
||||
end
|
||||
|
||||
self:Remove()
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:Equip()
|
||||
self:SetNextPrimaryFire( CurTime() + (self.Primary.Delay * 1.5) )
|
||||
self:SetNextSecondaryFire( CurTime() + (self.Secondary.Delay * 1.5) )
|
||||
end
|
||||
|
||||
function SWEP:PreDrop()
|
||||
-- for consistency, dropped knife should not have DNA/prints
|
||||
self.fingerprints = {}
|
||||
end
|
||||
|
||||
function SWEP:OnRemove()
|
||||
if CLIENT and IsValid(self:GetOwner()) and self:GetOwner() == LocalPlayer() and self:GetOwner():Alive() then
|
||||
RunConsoleCommand("lastinv")
|
||||
end
|
||||
end
|
||||
|
||||
if CLIENT then
|
||||
local T = LANG.GetTranslation
|
||||
function SWEP:DrawHUD()
|
||||
local tr = self:GetOwner():GetEyeTrace(MASK_SHOT)
|
||||
|
||||
if tr.HitNonWorld and IsValid(tr.Entity) and tr.Entity:IsPlayer()
|
||||
and tr.Entity:Health() < (self.Primary.Damage + 10) then
|
||||
|
||||
local x = ScrW() / 2.0
|
||||
local y = ScrH() / 2.0
|
||||
|
||||
surface.SetDrawColor(255, 0, 0, 255)
|
||||
|
||||
local outer = 20
|
||||
local inner = 10
|
||||
surface.DrawLine(x - outer, y - outer, x - inner, y - inner)
|
||||
surface.DrawLine(x + outer, y + outer, x + inner, y + inner)
|
||||
|
||||
surface.DrawLine(x - outer, y + outer, x - inner, y + inner)
|
||||
surface.DrawLine(x + outer, y - outer, x + inner, y - inner)
|
||||
|
||||
draw.SimpleText(T("knife_instant"), "TabLarge", x, y - 30, COLOR_RED, TEXT_ALIGN_CENTER, TEXT_ALIGN_BOTTOM)
|
||||
end
|
||||
|
||||
return self.BaseClass.DrawHUD(self)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
96
gamemodes/terrortown/entities/weapons/weapon_ttt_m16.lua
Normal file
96
gamemodes/terrortown/entities/weapons/weapon_ttt_m16.lua
Normal file
@@ -0,0 +1,96 @@
|
||||
--[[
|
||||
| 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()
|
||||
|
||||
SWEP.HoldType = "ar2"
|
||||
|
||||
if CLIENT then
|
||||
SWEP.PrintName = "M16"
|
||||
SWEP.Slot = 2
|
||||
|
||||
SWEP.ViewModelFlip = false
|
||||
SWEP.ViewModelFOV = 64
|
||||
|
||||
SWEP.Icon = "vgui/ttt/icon_m16"
|
||||
SWEP.IconLetter = "w"
|
||||
end
|
||||
|
||||
SWEP.Base = "weapon_tttbase"
|
||||
|
||||
SWEP.Kind = WEAPON_HEAVY
|
||||
SWEP.WeaponID = AMMO_M16
|
||||
|
||||
SWEP.Primary.Delay = 0.19
|
||||
SWEP.Primary.Recoil = 1.6
|
||||
SWEP.Primary.Automatic = true
|
||||
SWEP.Primary.Ammo = "Pistol"
|
||||
SWEP.Primary.Damage = 23
|
||||
SWEP.Primary.Cone = 0.018
|
||||
SWEP.Primary.ClipSize = 20
|
||||
SWEP.Primary.ClipMax = 60
|
||||
SWEP.Primary.DefaultClip = 20
|
||||
SWEP.Primary.Sound = Sound( "Weapon_M4A1.Single" )
|
||||
|
||||
SWEP.AutoSpawnable = true
|
||||
SWEP.Spawnable = true
|
||||
SWEP.AmmoEnt = "item_ammo_pistol_ttt"
|
||||
|
||||
SWEP.UseHands = true
|
||||
SWEP.ViewModel = "models/weapons/cstrike/c_rif_m4a1.mdl"
|
||||
SWEP.WorldModel = "models/weapons/w_rif_m4a1.mdl"
|
||||
|
||||
SWEP.IronSightsPos = Vector(-7.58, -9.2, 0.55)
|
||||
SWEP.IronSightsAng = Vector(2.599, -1.3, -3.6)
|
||||
|
||||
function SWEP:SetZoom(state)
|
||||
if not (IsValid(self:GetOwner()) and self:GetOwner():IsPlayer()) then return end
|
||||
if state then
|
||||
self:GetOwner():SetFOV(35, 0.5)
|
||||
else
|
||||
self:GetOwner():SetFOV(0, 0.2)
|
||||
end
|
||||
end
|
||||
|
||||
-- Add some zoom to ironsights for this gun
|
||||
function SWEP:SecondaryAttack()
|
||||
if not self.IronSightsPos then return end
|
||||
if self:GetNextSecondaryFire() > CurTime() then return end
|
||||
|
||||
local bIronsights = not self:GetIronsights()
|
||||
|
||||
self:SetIronsights( bIronsights )
|
||||
|
||||
self:SetZoom( bIronsights )
|
||||
|
||||
self:SetNextSecondaryFire( CurTime() + 0.3 )
|
||||
end
|
||||
|
||||
function SWEP:PreDrop()
|
||||
self:SetZoom(false)
|
||||
self:SetIronsights(false)
|
||||
return self.BaseClass.PreDrop(self)
|
||||
end
|
||||
|
||||
function SWEP:Reload()
|
||||
if (self:Clip1() == self.Primary.ClipSize or
|
||||
self:GetOwner():GetAmmoCount(self.Primary.Ammo) <= 0) then
|
||||
return
|
||||
end
|
||||
self:DefaultReload(ACT_VM_RELOAD)
|
||||
self:SetIronsights(false)
|
||||
self:SetZoom(false)
|
||||
end
|
||||
|
||||
function SWEP:Holster()
|
||||
self:SetIronsights(false)
|
||||
self:SetZoom(false)
|
||||
return true
|
||||
end
|
||||
387
gamemodes/terrortown/entities/weapons/weapon_ttt_phammer.lua
Normal file
387
gamemodes/terrortown/entities/weapons/weapon_ttt_phammer.lua
Normal file
@@ -0,0 +1,387 @@
|
||||
--[[
|
||||
| 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()
|
||||
|
||||
DEFINE_BASECLASS "weapon_tttbase"
|
||||
|
||||
SWEP.HoldType = "ar2"
|
||||
|
||||
if CLIENT then
|
||||
SWEP.PrintName = "polter_name"
|
||||
SWEP.Slot = 7
|
||||
|
||||
SWEP.ViewModelFlip = false
|
||||
SWEP.ViewModelFOV = 54
|
||||
|
||||
SWEP.EquipMenuData = {
|
||||
type = "item_weapon",
|
||||
desc = "polter_desc"
|
||||
};
|
||||
|
||||
SWEP.Icon = "vgui/ttt/icon_polter"
|
||||
end
|
||||
|
||||
SWEP.Base = "weapon_tttbase"
|
||||
|
||||
SWEP.Primary.Recoil = 0.1
|
||||
SWEP.Primary.Delay = 12.0
|
||||
SWEP.Primary.Cone = 0.02
|
||||
SWEP.Primary.ClipSize = 6
|
||||
SWEP.Primary.DefaultClip = 6
|
||||
SWEP.Primary.ClipMax = 6
|
||||
SWEP.Primary.Ammo = "Gravity"
|
||||
SWEP.Primary.Automatic = false
|
||||
SWEP.Primary.Sound = Sound( "weapons/airboat/airboat_gun_energy1.wav" )
|
||||
|
||||
SWEP.Secondary.Automatic = false
|
||||
|
||||
SWEP.Kind = WEAPON_EQUIP2
|
||||
SWEP.CanBuy = {ROLE_TRAITOR} -- only traitors can buy
|
||||
SWEP.WeaponID = AMMO_POLTER
|
||||
|
||||
SWEP.UseHands = true
|
||||
SWEP.ViewModel = "models/weapons/c_irifle.mdl"
|
||||
SWEP.WorldModel = "models/weapons/w_IRifle.mdl"
|
||||
|
||||
SWEP.NoSights = true
|
||||
|
||||
SWEP.IsCharging = false
|
||||
SWEP.NextCharge = 0
|
||||
SWEP.MaxRange = 800
|
||||
|
||||
AccessorFuncDT(SWEP, "charge", "Charge")
|
||||
|
||||
local math = math
|
||||
|
||||
-- Returns if an entity is a valid physhammer punching target. Does not take
|
||||
-- distance into account.
|
||||
local function ValidTarget(ent)
|
||||
return IsValid(ent) and ent:GetMoveType() == MOVETYPE_VPHYSICS and ent:GetPhysicsObject() and (not ent:IsWeapon()) and (not ent:GetNWBool("punched", false)) and (not ent:IsPlayer())
|
||||
-- NOTE: cannot check for motion disabled on client
|
||||
end
|
||||
|
||||
function SWEP:SetupDataTables()
|
||||
self:DTVar("Float", 0, "charge")
|
||||
end
|
||||
|
||||
local ghostmdl = Model("models/Items/combine_rifle_ammo01.mdl")
|
||||
function SWEP:Initialize()
|
||||
if CLIENT then
|
||||
-- create ghosted indicator
|
||||
local ghost = ents.CreateClientProp(ghostmdl)
|
||||
if IsValid(ghost) then
|
||||
ghost:SetPos(self:GetPos())
|
||||
ghost:Spawn()
|
||||
|
||||
-- PhysPropClientside whines here about not being able to parse the
|
||||
-- physmodel. This is not important as we won't use that anyway, and it
|
||||
-- happens in sandbox as well for the ghosted ents used there.
|
||||
|
||||
ghost:SetSolid(SOLID_NONE)
|
||||
ghost:SetMoveType(MOVETYPE_NONE)
|
||||
ghost:SetNotSolid(true)
|
||||
ghost:SetRenderMode(RENDERMODE_TRANSCOLOR)
|
||||
ghost:AddEffects(EF_NOSHADOW)
|
||||
ghost:SetNoDraw(true)
|
||||
|
||||
self.Ghost = ghost
|
||||
end
|
||||
end
|
||||
|
||||
self.IsCharging = false
|
||||
self:SetCharge(0)
|
||||
|
||||
return self.BaseClass.Initialize(self)
|
||||
end
|
||||
|
||||
function SWEP:PreDrop()
|
||||
self.IsCharging = false
|
||||
self:SetCharge(0)
|
||||
|
||||
-- OnDrop does not happen on client
|
||||
self:CallOnClient("HideGhost", "")
|
||||
end
|
||||
|
||||
function SWEP:HideGhost()
|
||||
if IsValid(self.Ghost) then
|
||||
self.Ghost:SetNoDraw(true)
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:PrimaryAttack()
|
||||
self:SetNextPrimaryFire(CurTime() + 0.1)
|
||||
if not self:CanPrimaryAttack() then return end
|
||||
if IsValid(self.hammer) then return end
|
||||
if SERVER then
|
||||
if self.IsCharging then return end
|
||||
|
||||
local ply = self:GetOwner()
|
||||
if not IsValid(ply) then return end
|
||||
|
||||
local tr = util.TraceLine({start=ply:GetShootPos(), endpos=ply:GetShootPos() + ply:GetAimVector() * self.MaxRange, filter={ply, self}, mask=MASK_SOLID})
|
||||
|
||||
if tr.HitNonWorld and ValidTarget(tr.Entity) and tr.Entity:GetPhysicsObject():IsMoveable() then
|
||||
|
||||
self:CreateHammer(tr.Entity, tr.HitPos)
|
||||
|
||||
self:EmitSound(self.Primary.Sound)
|
||||
|
||||
self:TakePrimaryAmmo(1)
|
||||
|
||||
self:SetNextPrimaryFire(CurTime() + self.Primary.Delay)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:SecondaryAttack()
|
||||
if self.IsCharging then return end
|
||||
|
||||
self:SetNextSecondaryFire( CurTime() + 0.1 )
|
||||
|
||||
if not (self:CanPrimaryAttack() and (self:GetNextPrimaryFire() - CurTime()) <= 0) then return end
|
||||
if IsValid(self.hammer) then return end
|
||||
if SERVER then
|
||||
local ply = self:GetOwner()
|
||||
if not IsValid(ply) then return end
|
||||
|
||||
local range = 30000
|
||||
|
||||
local tr = util.TraceLine({start=ply:GetShootPos(), endpos=ply:GetShootPos() + ply:GetAimVector() * range, filter={ply, self}, mask=MASK_SOLID})
|
||||
|
||||
if tr.HitNonWorld and ValidTarget(tr.Entity) and tr.Entity:GetPhysicsObject():IsMoveable() then
|
||||
|
||||
if self.IsCharging and self:GetCharge() >= 1 then
|
||||
return
|
||||
elseif tr.Fraction * range > self.MaxRange then
|
||||
self.IsCharging = true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:CreateHammer(tgt, pos)
|
||||
local hammer = ents.Create("ttt_physhammer")
|
||||
if IsValid(hammer) then
|
||||
local ang = self:GetOwner():GetAimVector():Angle()
|
||||
ang:RotateAroundAxis(ang:Right(), 90)
|
||||
|
||||
hammer:SetPos(pos)
|
||||
hammer:SetAngles(ang)
|
||||
|
||||
hammer:Spawn()
|
||||
|
||||
hammer:SetOwner(self:GetOwner())
|
||||
|
||||
local stuck = hammer:StickTo(tgt)
|
||||
|
||||
if not stuck then hammer:Remove() end
|
||||
self.hammer = hammer
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:OnRemove()
|
||||
if CLIENT and IsValid(self.Ghost) then
|
||||
self.Ghost:Remove()
|
||||
end
|
||||
|
||||
self.IsCharging = false
|
||||
self:SetCharge(0)
|
||||
end
|
||||
|
||||
function SWEP:Holster()
|
||||
if CLIENT and IsValid(self.Ghost) then
|
||||
self.Ghost:SetNoDraw(true)
|
||||
end
|
||||
|
||||
self.IsCharging = false
|
||||
self:SetCharge(0)
|
||||
|
||||
return self.BaseClass.Holster(self)
|
||||
end
|
||||
|
||||
|
||||
if SERVER then
|
||||
|
||||
local CHARGE_AMOUNT = 0.015
|
||||
local CHARGE_DELAY = 0.025
|
||||
|
||||
function SWEP:Think()
|
||||
BaseClass.Think(self)
|
||||
if not IsValid(self:GetOwner()) then return end
|
||||
|
||||
if self.IsCharging and self:GetOwner():KeyDown(IN_ATTACK2) then
|
||||
local tr = self:GetOwner():GetEyeTrace(MASK_SOLID)
|
||||
if tr.HitNonWorld and ValidTarget(tr.Entity) then
|
||||
|
||||
if self:GetCharge() >= 1 then
|
||||
self:CreateHammer(tr.Entity, tr.HitPos)
|
||||
|
||||
self:EmitSound(self.Primary.Sound)
|
||||
|
||||
self:TakePrimaryAmmo(1)
|
||||
|
||||
self:SetNextPrimaryFire(CurTime() + self.Primary.Delay)
|
||||
|
||||
self.IsCharging = false
|
||||
self:SetCharge(0)
|
||||
return true
|
||||
elseif self.NextCharge < CurTime() then
|
||||
local d = tr.Entity:GetPos():Distance(self:GetOwner():GetPos())
|
||||
local f = math.max(1, math.floor(d / self.MaxRange))
|
||||
|
||||
self:SetCharge(math.min(1, self:GetCharge() + (CHARGE_AMOUNT / f)))
|
||||
|
||||
self.NextCharge = CurTime() + CHARGE_DELAY
|
||||
end
|
||||
else
|
||||
self.IsCharging = false
|
||||
self:SetCharge(0)
|
||||
end
|
||||
|
||||
elseif self:GetCharge() > 0 then
|
||||
-- owner let go of rmouse
|
||||
self:SetCharge(0)
|
||||
self.IsCharging = false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function around( val )
|
||||
return math.Round( val * (10 ^ 3) ) / (10 ^ 3);
|
||||
end
|
||||
|
||||
if CLIENT then
|
||||
local surface = surface
|
||||
|
||||
function SWEP:UpdateGhost(pos, c, a)
|
||||
if IsValid(self.Ghost) then
|
||||
if self.Ghost:GetPos() != pos then
|
||||
self.Ghost:SetPos(pos)
|
||||
local ang = LocalPlayer():GetAimVector():Angle()
|
||||
ang:RotateAroundAxis(ang:Right(), 90)
|
||||
|
||||
self.Ghost:SetAngles(ang)
|
||||
|
||||
self.Ghost:SetColor(Color(c.r, c.g, c.b, a))
|
||||
|
||||
self.Ghost:SetNoDraw(false)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local linex = 0
|
||||
local liney = 0
|
||||
local laser = Material("trails/laser")
|
||||
function SWEP:ViewModelDrawn()
|
||||
local client = LocalPlayer()
|
||||
local vm = client:GetViewModel()
|
||||
if not IsValid(vm) then return end
|
||||
|
||||
local plytr = client:GetEyeTrace(MASK_SHOT)
|
||||
|
||||
local muzzle_angpos = vm:GetAttachment(1)
|
||||
local spos = muzzle_angpos.Pos + muzzle_angpos.Ang:Forward() * 10
|
||||
local epos = client:GetShootPos() + client:GetAimVector() * self.MaxRange
|
||||
|
||||
-- Painting beam
|
||||
local tr = util.TraceLine({start=spos, endpos=epos, filter=client, mask=MASK_ALL})
|
||||
|
||||
local c = COLOR_RED
|
||||
local a = 150
|
||||
local d = (plytr.StartPos - plytr.HitPos):Length()
|
||||
if plytr.HitNonWorld then
|
||||
if ValidTarget(plytr.Entity) then
|
||||
if d < self.MaxRange then
|
||||
c = COLOR_GREEN
|
||||
a = 255
|
||||
else
|
||||
c = COLOR_YELLOW
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
self:UpdateGhost(plytr.HitPos, c, a)
|
||||
|
||||
render.SetMaterial(laser)
|
||||
render.DrawBeam(spos, tr.HitPos, 5, 0, 0, c)
|
||||
|
||||
-- Charge indicator
|
||||
local vm_ang = muzzle_angpos.Ang
|
||||
local cpos = muzzle_angpos.Pos + (vm_ang:Up() * -8) + (vm_ang:Forward() * -5.5) + (vm_ang:Right() * 0)
|
||||
local cang = vm:GetAngles()
|
||||
cang:RotateAroundAxis(cang:Forward(), 90)
|
||||
cang:RotateAroundAxis(cang:Right(), 90)
|
||||
cang:RotateAroundAxis(cang:Up(), 90)
|
||||
|
||||
cam.Start3D2D(cpos, cang, 0.05)
|
||||
|
||||
surface.SetDrawColor(255, 55, 55, 50)
|
||||
surface.DrawOutlinedRect(0, 0, 50, 15)
|
||||
|
||||
local sz = 48
|
||||
local next = self:GetNextPrimaryFire()
|
||||
local ready = (next - CurTime()) <= 0
|
||||
local frac = 1.0
|
||||
if not ready then
|
||||
frac = 1 - ((next - CurTime()) / self.Primary.Delay)
|
||||
sz = sz * math.max(0, frac)
|
||||
end
|
||||
|
||||
surface.SetDrawColor(255, 10, 10, 170)
|
||||
surface.DrawRect(1, 1, sz, 13)
|
||||
|
||||
surface.SetTextColor(255,255,255,15)
|
||||
surface.SetFont("Default")
|
||||
surface.SetTextPos(2,0)
|
||||
surface.DrawText(string.format("%.3f", around(frac)))
|
||||
|
||||
surface.SetDrawColor(0,0,0, 80)
|
||||
surface.DrawRect(linex, 1, 3, 13)
|
||||
|
||||
surface.DrawLine(1, liney, 48, liney)
|
||||
|
||||
linex = linex + 3 > 48 and 0 or linex + 1
|
||||
liney = liney > 13 and 0 or liney + 1
|
||||
|
||||
cam.End3D2D()
|
||||
|
||||
end
|
||||
|
||||
local draw = draw
|
||||
function SWEP:DrawHUD()
|
||||
local x = ScrW() / 2.0
|
||||
local y = ScrH() / 2.0
|
||||
|
||||
|
||||
local charge = self.dt.charge
|
||||
|
||||
if charge > 0 then
|
||||
y = y + (y / 3)
|
||||
|
||||
local w, h = 100, 20
|
||||
|
||||
surface.DrawOutlinedRect(x - w/2, y - h, w, h)
|
||||
|
||||
if LocalPlayer():IsTraitor() then
|
||||
surface.SetDrawColor(255, 0, 0, 155)
|
||||
else
|
||||
surface.SetDrawColor(0, 255, 0, 155)
|
||||
end
|
||||
|
||||
surface.DrawRect(x - w/2, y - h, w * charge, h)
|
||||
|
||||
surface.SetFont("TabLarge")
|
||||
surface.SetTextColor(255, 255, 255, 180)
|
||||
surface.SetTextPos( (x - w / 2) + 3, y - h - 15)
|
||||
surface.DrawText("CHARGE")
|
||||
end
|
||||
end
|
||||
end
|
||||
271
gamemodes/terrortown/entities/weapons/weapon_ttt_push.lua
Normal file
271
gamemodes/terrortown/entities/weapons/weapon_ttt_push.lua
Normal file
@@ -0,0 +1,271 @@
|
||||
--[[
|
||||
| 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()
|
||||
|
||||
DEFINE_BASECLASS "weapon_tttbase"
|
||||
|
||||
SWEP.HoldType = "physgun"
|
||||
|
||||
if CLIENT then
|
||||
SWEP.PrintName = "newton_name"
|
||||
SWEP.Slot = 7
|
||||
|
||||
SWEP.ViewModelFlip = false
|
||||
SWEP.ViewModelFOV = 54
|
||||
|
||||
SWEP.EquipMenuData = {
|
||||
type = "item_weapon",
|
||||
desc = "newton_desc"
|
||||
};
|
||||
|
||||
SWEP.Icon = "vgui/ttt/icon_launch"
|
||||
end
|
||||
|
||||
SWEP.Base = "weapon_tttbase"
|
||||
|
||||
SWEP.Primary.Ammo = "none"
|
||||
SWEP.Primary.ClipSize = -1
|
||||
SWEP.Primary.DefaultClip = -1
|
||||
SWEP.Primary.Automatic = true
|
||||
SWEP.Primary.Delay = 3
|
||||
SWEP.Primary.Cone = 0.005
|
||||
SWEP.Primary.Sound = Sound( "weapons/ar2/fire1.wav" )
|
||||
SWEP.Primary.SoundLevel = 54
|
||||
|
||||
SWEP.Secondary.ClipSize = -1
|
||||
SWEP.Secondary.DefaultClip = -1
|
||||
SWEP.Secondary.Automatic = false
|
||||
SWEP.Secondary.Ammo = "none"
|
||||
SWEP.Secondary.Delay = 0.5
|
||||
|
||||
SWEP.NoSights = true
|
||||
|
||||
SWEP.Kind = WEAPON_EQUIP2
|
||||
SWEP.CanBuy = {ROLE_TRAITOR}
|
||||
SWEP.WeaponID = AMMO_PUSH
|
||||
|
||||
SWEP.UseHands = true
|
||||
SWEP.ViewModel = "models/weapons/c_superphyscannon.mdl"
|
||||
SWEP.WorldModel = "models/weapons/w_physics.mdl"
|
||||
|
||||
AccessorFuncDT(SWEP, "charge", "Charge")
|
||||
|
||||
SWEP.IsCharging = false
|
||||
SWEP.NextCharge = 0
|
||||
|
||||
local CHARGE_AMOUNT = 0.02
|
||||
local CHARGE_DELAY = 0.025
|
||||
|
||||
local math = math
|
||||
|
||||
function SWEP:Initialize()
|
||||
if SERVER then
|
||||
self:SetSkin(1)
|
||||
end
|
||||
return self.BaseClass.Initialize(self)
|
||||
end
|
||||
|
||||
function SWEP:SetupDataTables()
|
||||
self:DTVar("Float", 0, "charge")
|
||||
end
|
||||
|
||||
function SWEP:PrimaryAttack()
|
||||
if self.IsCharging then return end
|
||||
|
||||
self:SetNextPrimaryFire( CurTime() + self.Primary.Delay )
|
||||
self:SetNextSecondaryFire( CurTime() + self.Primary.Delay )
|
||||
|
||||
self:FirePulse(600, 300)
|
||||
end
|
||||
|
||||
function SWEP:SecondaryAttack()
|
||||
if self.IsCharging then return end
|
||||
|
||||
self:SetNextPrimaryFire( CurTime() + self.Primary.Delay )
|
||||
self:SetNextSecondaryFire( CurTime() + self.Primary.Delay )
|
||||
|
||||
self.IsCharging = true
|
||||
end
|
||||
|
||||
function SWEP:FirePulse(force_fwd, force_up)
|
||||
if not IsValid(self:GetOwner()) then return end
|
||||
|
||||
self:GetOwner():SetAnimation( PLAYER_ATTACK1 )
|
||||
|
||||
sound.Play(self.Primary.Sound, self:GetPos(), self.Primary.SoundLevel)
|
||||
|
||||
self:SendWeaponAnim(ACT_VM_IDLE)
|
||||
|
||||
local cone = self.Primary.Cone or 0.1
|
||||
local num = 6
|
||||
|
||||
local bullet = {}
|
||||
bullet.Num = num
|
||||
bullet.Src = self:GetOwner():GetShootPos()
|
||||
bullet.Dir = self:GetOwner():GetAimVector()
|
||||
bullet.Spread = Vector( cone, cone, 0 )
|
||||
bullet.Tracer = 1
|
||||
bullet.Force = force_fwd / 10
|
||||
bullet.Damage = 1
|
||||
bullet.TracerName = "AirboatGunHeavyTracer"
|
||||
|
||||
local owner = self:GetOwner()
|
||||
local fwd = force_fwd / num
|
||||
local up = force_up / num
|
||||
bullet.Callback = function(att, tr, dmginfo)
|
||||
local ply = tr.Entity
|
||||
if SERVER and IsValid(ply) and ply:IsPlayer() and (not ply:IsFrozen()) then
|
||||
local pushvel = tr.Normal * fwd
|
||||
|
||||
pushvel.z = math.max(pushvel.z, up)
|
||||
|
||||
ply:SetGroundEntity(nil)
|
||||
ply:SetLocalVelocity(ply:GetVelocity() + pushvel)
|
||||
|
||||
ply.was_pushed = {att=owner, t=CurTime(), wep=self:GetClass()}
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
self:GetOwner():FireBullets( bullet )
|
||||
|
||||
end
|
||||
|
||||
local CHARGE_FORCE_FWD_MIN = 300
|
||||
local CHARGE_FORCE_FWD_MAX = 700
|
||||
local CHARGE_FORCE_UP_MIN = 100
|
||||
local CHARGE_FORCE_UP_MAX = 350
|
||||
function SWEP:ChargedAttack()
|
||||
local charge = math.Clamp(self:GetCharge(), 0, 1)
|
||||
|
||||
self.IsCharging = false
|
||||
self:SetCharge(0)
|
||||
|
||||
if charge <= 0 then return end
|
||||
|
||||
local max = CHARGE_FORCE_FWD_MAX
|
||||
local diff = max - CHARGE_FORCE_FWD_MIN
|
||||
|
||||
local force_fwd = ((charge * diff) - diff) + max
|
||||
|
||||
max = CHARGE_FORCE_UP_MAX
|
||||
diff = max - CHARGE_FORCE_UP_MIN
|
||||
|
||||
local force_up = ((charge * diff) - diff) + max
|
||||
|
||||
self:SetNextPrimaryFire( CurTime() + self.Primary.Delay )
|
||||
self:SetNextSecondaryFire( CurTime() + self.Primary.Delay )
|
||||
|
||||
self:FirePulse(force_fwd, force_up)
|
||||
end
|
||||
|
||||
function SWEP:PreDrop(death_drop)
|
||||
-- allow dropping for now, see if it helps against heisenbug on owner death
|
||||
-- if death_drop then
|
||||
self.IsCharging = false
|
||||
self:SetCharge(0)
|
||||
-- elseif self.IsCharging then
|
||||
-- self:ChargedAttack()
|
||||
-- end
|
||||
end
|
||||
|
||||
function SWEP:OnRemove()
|
||||
self.IsCharging = false
|
||||
self:SetCharge(0)
|
||||
end
|
||||
|
||||
function SWEP:Deploy()
|
||||
self.IsCharging = false
|
||||
self:SetCharge(0)
|
||||
return true
|
||||
end
|
||||
|
||||
function SWEP:Holster()
|
||||
return not self.IsCharging
|
||||
end
|
||||
|
||||
function SWEP:Think()
|
||||
BaseClass.Think(self)
|
||||
if self.IsCharging and IsValid(self:GetOwner()) and self:GetOwner():IsTerror() then
|
||||
-- on client this is prediction
|
||||
if not self:GetOwner():KeyDown(IN_ATTACK2) then
|
||||
self:ChargedAttack()
|
||||
return true
|
||||
end
|
||||
|
||||
|
||||
if SERVER and self:GetCharge() < 1 and self.NextCharge < CurTime() then
|
||||
self:SetCharge(math.min(1, self:GetCharge() + CHARGE_AMOUNT))
|
||||
|
||||
self.NextCharge = CurTime() + CHARGE_DELAY
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if CLIENT then
|
||||
local surface = surface
|
||||
function SWEP:DrawHUD()
|
||||
local x = ScrW() / 2.0
|
||||
local y = ScrH() / 2.0
|
||||
|
||||
local nxt = self:GetNextPrimaryFire()
|
||||
local charge = self.dt.charge
|
||||
|
||||
if LocalPlayer():IsTraitor() then
|
||||
surface.SetDrawColor(255, 0, 0, 255)
|
||||
else
|
||||
surface.SetDrawColor(0, 255, 0, 255)
|
||||
end
|
||||
|
||||
if nxt < CurTime() or CurTime() % 0.5 < 0.2 or charge > 0 then
|
||||
local length = 10
|
||||
local gap = 5
|
||||
|
||||
surface.DrawLine( x - length, y, x - gap, y )
|
||||
surface.DrawLine( x + length, y, x + gap, y )
|
||||
surface.DrawLine( x, y - length, x, y - gap )
|
||||
surface.DrawLine( x, y + length, x, y + gap )
|
||||
end
|
||||
|
||||
if nxt > CurTime() and charge == 0 then
|
||||
local w = 40
|
||||
|
||||
w = (w * ( math.max(0, nxt - CurTime()) / self.Primary.Delay )) / 2
|
||||
|
||||
local bx = x + 30
|
||||
surface.DrawLine(bx, y - w, bx, y + w)
|
||||
|
||||
bx = x - 30
|
||||
surface.DrawLine(bx, y - w, bx, y + w)
|
||||
end
|
||||
|
||||
if charge > 0 then
|
||||
y = y + (y / 3)
|
||||
|
||||
local w, h = 100, 20
|
||||
|
||||
surface.DrawOutlinedRect(x - w/2, y - h, w, h)
|
||||
|
||||
if LocalPlayer():IsTraitor() then
|
||||
surface.SetDrawColor(255, 0, 0, 155)
|
||||
else
|
||||
surface.SetDrawColor(0, 255, 0, 155)
|
||||
end
|
||||
|
||||
surface.DrawRect(x - w/2, y - h, w * charge, h)
|
||||
|
||||
surface.SetFont("TabLarge")
|
||||
surface.SetTextColor(255, 255, 255, 180)
|
||||
surface.SetTextPos( (x - w / 2) + 3, y - h - 15)
|
||||
surface.DrawText("FORCE")
|
||||
end
|
||||
end
|
||||
end
|
||||
185
gamemodes/terrortown/entities/weapons/weapon_ttt_radio.lua
Normal file
185
gamemodes/terrortown/entities/weapons/weapon_ttt_radio.lua
Normal file
@@ -0,0 +1,185 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
-- traitor equipment: radio
|
||||
|
||||
AddCSLuaFile()
|
||||
|
||||
SWEP.HoldType = "normal"
|
||||
|
||||
if CLIENT then
|
||||
SWEP.PrintName = "radio_name"
|
||||
SWEP.Slot = 7
|
||||
|
||||
SWEP.ViewModelFlip = false
|
||||
SWEP.ViewModelFOV = 10
|
||||
SWEP.DrawCrosshair = false
|
||||
|
||||
SWEP.EquipMenuData = {
|
||||
type = "item_weapon",
|
||||
desc = "radio_desc"
|
||||
};
|
||||
|
||||
SWEP.Icon = "vgui/ttt/icon_radio"
|
||||
end
|
||||
|
||||
SWEP.Base = "weapon_tttbase"
|
||||
|
||||
SWEP.ViewModel = "models/weapons/v_crowbar.mdl"
|
||||
SWEP.WorldModel = "models/props/cs_office/radio.mdl"
|
||||
|
||||
SWEP.Primary.ClipSize = -1
|
||||
SWEP.Primary.DefaultClip = -1
|
||||
SWEP.Primary.Automatic = true
|
||||
SWEP.Primary.Ammo = "none"
|
||||
SWEP.Primary.Delay = 1.0
|
||||
|
||||
SWEP.Secondary.ClipSize = -1
|
||||
SWEP.Secondary.DefaultClip = -1
|
||||
SWEP.Secondary.Automatic = true
|
||||
SWEP.Secondary.Ammo = "none"
|
||||
SWEP.Secondary.Delay = 1.0
|
||||
|
||||
SWEP.Kind = WEAPON_EQUIP2
|
||||
SWEP.CanBuy = {ROLE_TRAITOR} -- only traitors can buy
|
||||
SWEP.LimitedStock = true -- only buyable once
|
||||
SWEP.WeaponID = AMMO_RADIO
|
||||
|
||||
SWEP.AllowDrop = false
|
||||
SWEP.NoSights = true
|
||||
|
||||
function SWEP:OnDrop()
|
||||
self:Remove()
|
||||
end
|
||||
|
||||
function SWEP:PrimaryAttack()
|
||||
self:SetNextPrimaryFire( CurTime() + self.Primary.Delay )
|
||||
self:RadioDrop()
|
||||
end
|
||||
function SWEP:SecondaryAttack()
|
||||
self:SetNextSecondaryFire( CurTime() + self.Secondary.Delay )
|
||||
self:RadioStick()
|
||||
end
|
||||
|
||||
local throwsound = Sound( "Weapon_SLAM.SatchelThrow" )
|
||||
|
||||
-- c4 plant but different
|
||||
function SWEP:RadioDrop()
|
||||
if SERVER then
|
||||
local ply = self:GetOwner()
|
||||
if not IsValid(ply) then return end
|
||||
|
||||
if self.Planted then return end
|
||||
|
||||
local vsrc = ply:GetShootPos()
|
||||
local vang = ply:GetAimVector()
|
||||
local vvel = ply:GetVelocity()
|
||||
|
||||
local vthrow = vvel + vang * 200
|
||||
|
||||
local radio = ents.Create("ttt_radio")
|
||||
if IsValid(radio) then
|
||||
radio:SetPos(vsrc + vang * 10)
|
||||
radio:SetOwner(ply)
|
||||
radio:Spawn()
|
||||
|
||||
radio:PhysWake()
|
||||
local phys = radio:GetPhysicsObject()
|
||||
if IsValid(phys) then
|
||||
phys:SetVelocity(vthrow)
|
||||
end
|
||||
self:Remove()
|
||||
|
||||
self.Planted = true
|
||||
end
|
||||
end
|
||||
|
||||
self:EmitSound(throwsound)
|
||||
end
|
||||
|
||||
-- hey look, more C4 code
|
||||
function SWEP:RadioStick()
|
||||
if SERVER then
|
||||
local ply = self:GetOwner()
|
||||
if not IsValid(ply) then return end
|
||||
|
||||
if self.Planted then return end
|
||||
|
||||
local ignore = {ply, self}
|
||||
local spos = ply:GetShootPos()
|
||||
local epos = spos + ply:GetAimVector() * 80
|
||||
local tr = util.TraceLine({start=spos, endpos=epos, filter=ignore, mask=MASK_SOLID})
|
||||
|
||||
if tr.HitWorld then
|
||||
local radio = ents.Create("ttt_radio")
|
||||
if IsValid(radio) then
|
||||
radio:PointAtEntity(ply)
|
||||
|
||||
local tr_ent = util.TraceEntity({start=spos, endpos=epos, filter=ignore, mask=MASK_SOLID}, radio)
|
||||
|
||||
if tr_ent.HitWorld then
|
||||
|
||||
local ang = tr_ent.HitNormal:Angle()
|
||||
ang:RotateAroundAxis(ang:Up(), -180)
|
||||
|
||||
radio:SetPos(tr_ent.HitPos + ang:Forward() * -2.5)
|
||||
radio:SetAngles(ang)
|
||||
radio:SetOwner(ply)
|
||||
radio:Spawn()
|
||||
|
||||
local phys = radio:GetPhysicsObject()
|
||||
if IsValid(phys) then
|
||||
phys:EnableMotion(false)
|
||||
end
|
||||
|
||||
radio.IsOnWall = true
|
||||
|
||||
self:Remove()
|
||||
|
||||
self.Planted = true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:Reload()
|
||||
return false
|
||||
end
|
||||
|
||||
function SWEP:OnRemove()
|
||||
if CLIENT and IsValid(self:GetOwner()) and self:GetOwner() == LocalPlayer() and self:GetOwner():Alive() then
|
||||
RunConsoleCommand("lastinv")
|
||||
end
|
||||
end
|
||||
|
||||
if CLIENT then
|
||||
function SWEP:Initialize()
|
||||
self:AddHUDHelp("radio_help_pri", nil, true)
|
||||
|
||||
return self.BaseClass.Initialize(self)
|
||||
end
|
||||
|
||||
end
|
||||
-- Invisible, same hacks as holstered weapon
|
||||
|
||||
|
||||
function SWEP:Deploy()
|
||||
if SERVER and IsValid(self:GetOwner()) then
|
||||
self:GetOwner():DrawViewModel(false)
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
function SWEP:DrawWorldModel()
|
||||
end
|
||||
|
||||
function SWEP:DrawWorldModelTranslucent()
|
||||
end
|
||||
@@ -0,0 +1,72 @@
|
||||
--[[
|
||||
| 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()
|
||||
|
||||
SWEP.HoldType = "pistol"
|
||||
|
||||
if CLIENT then
|
||||
SWEP.PrintName = "sipistol_name"
|
||||
SWEP.Slot = 6
|
||||
|
||||
SWEP.ViewModelFlip = false
|
||||
SWEP.ViewModelFOV = 54
|
||||
|
||||
SWEP.EquipMenuData = {
|
||||
type = "item_weapon",
|
||||
desc = "sipistol_desc"
|
||||
};
|
||||
|
||||
SWEP.Icon = "vgui/ttt/icon_silenced"
|
||||
SWEP.IconLetter = "a"
|
||||
end
|
||||
|
||||
SWEP.Base = "weapon_tttbase"
|
||||
|
||||
SWEP.Primary.Recoil = 1.35
|
||||
SWEP.Primary.Damage = 28
|
||||
SWEP.Primary.Delay = 0.38
|
||||
SWEP.Primary.Cone = 0.02
|
||||
SWEP.Primary.ClipSize = 20
|
||||
SWEP.Primary.Automatic = true
|
||||
SWEP.Primary.DefaultClip = 20
|
||||
SWEP.Primary.ClipMax = 60
|
||||
SWEP.Primary.Ammo = "Pistol"
|
||||
SWEP.Primary.Sound = Sound( "Weapon_USP.SilencedShot" )
|
||||
SWEP.Primary.SoundLevel = 50
|
||||
|
||||
SWEP.Kind = WEAPON_EQUIP
|
||||
SWEP.CanBuy = {ROLE_TRAITOR} -- only traitors can buy
|
||||
SWEP.WeaponID = AMMO_SIPISTOL
|
||||
|
||||
SWEP.AmmoEnt = "item_ammo_pistol_ttt"
|
||||
SWEP.IsSilent = true
|
||||
|
||||
SWEP.UseHands = true
|
||||
SWEP.ViewModel = "models/weapons/cstrike/c_pist_usp.mdl"
|
||||
SWEP.WorldModel = "models/weapons/w_pist_usp_silencer.mdl"
|
||||
|
||||
SWEP.IronSightsPos = Vector( -5.91, -4, 2.84 )
|
||||
SWEP.IronSightsAng = Vector(-0.5, 0, 0)
|
||||
|
||||
SWEP.PrimaryAnim = ACT_VM_PRIMARYATTACK_SILENCED
|
||||
SWEP.ReloadAnim = ACT_VM_RELOAD_SILENCED
|
||||
|
||||
function SWEP:Deploy()
|
||||
self:SendWeaponAnim(ACT_VM_DRAW_SILENCED)
|
||||
return self.BaseClass.Deploy(self)
|
||||
end
|
||||
|
||||
-- We were bought as special equipment, and we have an extra to give
|
||||
function SWEP:WasBought(buyer)
|
||||
if IsValid(buyer) then -- probably already self:GetOwner()
|
||||
buyer:GiveAmmo( 20, "Pistol" )
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,43 @@
|
||||
--[[
|
||||
| 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()
|
||||
|
||||
SWEP.HoldType = "grenade"
|
||||
|
||||
if CLIENT then
|
||||
SWEP.PrintName = "grenade_smoke"
|
||||
SWEP.Slot = 3
|
||||
|
||||
SWEP.ViewModelFlip = false
|
||||
SWEP.ViewModelFOV = 54
|
||||
|
||||
SWEP.Icon = "vgui/ttt/icon_nades"
|
||||
SWEP.IconLetter = "Q"
|
||||
end
|
||||
|
||||
SWEP.Base = "weapon_tttbasegrenade"
|
||||
|
||||
SWEP.WeaponID = AMMO_SMOKE
|
||||
SWEP.Kind = WEAPON_NADE
|
||||
|
||||
SWEP.UseHands = true
|
||||
SWEP.ViewModel = "models/weapons/cstrike/c_eq_smokegrenade.mdl"
|
||||
SWEP.WorldModel = "models/weapons/w_eq_smokegrenade.mdl"
|
||||
|
||||
SWEP.Weight = 5
|
||||
SWEP.AutoSpawnable = true
|
||||
SWEP.Spawnable = true
|
||||
-- really the only difference between grenade weapons: the model and the thrown
|
||||
-- ent.
|
||||
|
||||
function SWEP:GetGrenadeName()
|
||||
return "ttt_smokegrenade_proj"
|
||||
end
|
||||
125
gamemodes/terrortown/entities/weapons/weapon_ttt_stungun.lua
Normal file
125
gamemodes/terrortown/entities/weapons/weapon_ttt_stungun.lua
Normal file
@@ -0,0 +1,125 @@
|
||||
--[[
|
||||
| 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()
|
||||
|
||||
SWEP.HoldType = "ar2"
|
||||
|
||||
if CLIENT then
|
||||
SWEP.PrintName = "stungun_name"
|
||||
SWEP.Slot = 6
|
||||
|
||||
SWEP.ViewModelFlip = false
|
||||
SWEP.ViewModelFOV = 54
|
||||
|
||||
SWEP.EquipMenuData = {
|
||||
type = "item_weapon",
|
||||
desc = "ump_desc"
|
||||
};
|
||||
|
||||
SWEP.Icon = "vgui/ttt/icon_ump"
|
||||
SWEP.IconLetter = "q"
|
||||
end
|
||||
|
||||
SWEP.Base = "weapon_tttbase"
|
||||
|
||||
SWEP.Kind = WEAPON_EQUIP
|
||||
SWEP.WeaponID = AMMO_STUN
|
||||
SWEP.CanBuy = {ROLE_DETECTIVE}
|
||||
SWEP.LimitedStock = false
|
||||
SWEP.AmmoEnt = "item_ammo_smg1_ttt"
|
||||
|
||||
SWEP.Primary.Damage = 9
|
||||
SWEP.Primary.Delay = 0.1
|
||||
SWEP.Primary.Cone = 0.02
|
||||
SWEP.Primary.ClipSize = 30
|
||||
SWEP.Primary.ClipMax = 60
|
||||
SWEP.Primary.DefaultClip = 30
|
||||
SWEP.Primary.Automatic = true
|
||||
SWEP.Primary.Ammo = "SMG1"
|
||||
SWEP.Primary.Recoil = 1.2
|
||||
SWEP.Primary.Sound = Sound( "Weapon_UMP45.Single" )
|
||||
|
||||
SWEP.UseHands = true
|
||||
SWEP.ViewModel = "models/weapons/cstrike/c_smg_ump45.mdl"
|
||||
SWEP.WorldModel = "models/weapons/w_smg_ump45.mdl"
|
||||
|
||||
SWEP.IronSightsPos = Vector(-8.735, -10, 4.039)
|
||||
SWEP.IronSightsAng = Vector(-1.201, -0.201, -2)
|
||||
|
||||
SWEP.HeadshotMultiplier = 4.5 -- brain fizz
|
||||
--SWEP.DeploySpeed = 3
|
||||
|
||||
function SWEP:ShootBullet( dmg, recoil, numbul, cone )
|
||||
local sights = self:GetIronsights()
|
||||
|
||||
numbul = numbul or 1
|
||||
cone = cone or 0.01
|
||||
|
||||
-- 10% accuracy bonus when sighting
|
||||
cone = sights and (cone * 0.9) or cone
|
||||
|
||||
local bullet = {}
|
||||
bullet.Num = numbul
|
||||
bullet.Src = self:GetOwner():GetShootPos()
|
||||
bullet.Dir = self:GetOwner():GetAimVector()
|
||||
bullet.Spread = Vector( cone, cone, 0 )
|
||||
bullet.Tracer = 4
|
||||
bullet.Force = 5
|
||||
bullet.Damage = dmg
|
||||
|
||||
bullet.Callback = function(att, tr, dmginfo)
|
||||
if SERVER or (CLIENT and IsFirstTimePredicted()) then
|
||||
local ent = tr.Entity
|
||||
if (not tr.HitWorld) and IsValid(ent) then
|
||||
local edata = EffectData()
|
||||
|
||||
edata:SetEntity(ent)
|
||||
edata:SetMagnitude(3)
|
||||
edata:SetScale(2)
|
||||
|
||||
util.Effect("TeslaHitBoxes", edata)
|
||||
|
||||
if SERVER and ent:IsPlayer() then
|
||||
local eyeang = ent:EyeAngles()
|
||||
|
||||
local j = 10
|
||||
eyeang.pitch = math.Clamp(eyeang.pitch + math.Rand(-j, j), -90, 90)
|
||||
eyeang.yaw = math.Clamp(eyeang.yaw + math.Rand(-j, j), -90, 90)
|
||||
ent:SetEyeAngles(eyeang)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
self:GetOwner():FireBullets( bullet )
|
||||
self:SendWeaponAnim(self.PrimaryAnim)
|
||||
|
||||
-- Owner can die after firebullets, giving an error at muzzleflash
|
||||
if not IsValid(self:GetOwner()) or not self:GetOwner():Alive() then return end
|
||||
|
||||
self:GetOwner():MuzzleFlash()
|
||||
self:GetOwner():SetAnimation( PLAYER_ATTACK1 )
|
||||
|
||||
if self:GetOwner():IsNPC() then return end
|
||||
|
||||
if ((game.SinglePlayer() and SERVER) or
|
||||
((not game.SinglePlayer()) and CLIENT and IsFirstTimePredicted() )) then
|
||||
|
||||
-- reduce recoil if ironsighting
|
||||
recoil = sights and (recoil * 0.75) or recoil
|
||||
|
||||
local eyeang = self:GetOwner():EyeAngles()
|
||||
eyeang.pitch = eyeang.pitch - recoil
|
||||
self:GetOwner():SetEyeAngles( eyeang )
|
||||
|
||||
end
|
||||
end
|
||||
350
gamemodes/terrortown/entities/weapons/weapon_ttt_teleport.lua
Normal file
350
gamemodes/terrortown/entities/weapons/weapon_ttt_teleport.lua
Normal file
@@ -0,0 +1,350 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
-- traitor equipment: teleporter
|
||||
|
||||
AddCSLuaFile()
|
||||
|
||||
SWEP.HoldType = "normal"
|
||||
|
||||
if CLIENT then
|
||||
SWEP.PrintName = "tele_name"
|
||||
SWEP.Slot = 7
|
||||
|
||||
SWEP.ViewModelFlip = false
|
||||
SWEP.ViewModelFOV = 10
|
||||
SWEP.DrawCrosshair = false
|
||||
SWEP.CSMuzzleFlashes = false
|
||||
|
||||
SWEP.EquipMenuData = {
|
||||
type = "item_weapon",
|
||||
desc = "tele_desc"
|
||||
};
|
||||
|
||||
SWEP.Icon = "vgui/ttt/icon_tport"
|
||||
end
|
||||
|
||||
SWEP.Base = "weapon_tttbase"
|
||||
|
||||
SWEP.ViewModel = "models/weapons/v_crowbar.mdl"
|
||||
SWEP.WorldModel = "models/weapons/w_slam.mdl"
|
||||
|
||||
SWEP.Primary.ClipSize = 16
|
||||
SWEP.Primary.DefaultClip = 16
|
||||
SWEP.Primary.ClipMax = 16
|
||||
SWEP.Primary.Automatic = false
|
||||
SWEP.Primary.Ammo = "GaussEnergy"
|
||||
SWEP.Primary.Delay = 0.5
|
||||
|
||||
SWEP.Secondary.Automatic = false
|
||||
SWEP.Secondary.Ammo = "none"
|
||||
SWEP.Secondary.Delay = 1.0
|
||||
|
||||
SWEP.Kind = WEAPON_EQUIP2
|
||||
SWEP.CanBuy = {ROLE_TRAITOR, ROLE_DETECTIVE}
|
||||
SWEP.WeaponID = AMMO_TELEPORT
|
||||
|
||||
SWEP.AllowDrop = true
|
||||
SWEP.NoSights = true
|
||||
|
||||
local delay_beamup = 1
|
||||
local delay_beamdown = 1
|
||||
|
||||
local ttt_telefrags = CreateConVar("ttt_teleport_telefrags", "1")
|
||||
|
||||
function SWEP:SetTeleportMark(pos, ang)
|
||||
self.teleport = {pos = pos, ang = ang}
|
||||
end
|
||||
|
||||
function SWEP:GetTeleportMark() return self.teleport end
|
||||
|
||||
function SWEP:PrimaryAttack()
|
||||
self:SetNextPrimaryFire( CurTime() + self.Primary.Delay )
|
||||
|
||||
if self:Clip1() <= 0 then
|
||||
self:DryFire(self.SetNextSecondaryFire)
|
||||
return
|
||||
end
|
||||
|
||||
-- Disallow initiating teleports during post, as it will occur across the
|
||||
-- restart and allow the user an advantage during prep
|
||||
if GetRoundState() == ROUND_POST then return end
|
||||
|
||||
if SERVER then
|
||||
self:TeleportRecall()
|
||||
else
|
||||
surface.PlaySound("buttons/combine_button7.wav")
|
||||
end
|
||||
end
|
||||
function SWEP:SecondaryAttack()
|
||||
self:SetNextSecondaryFire( CurTime() + self.Secondary.Delay )
|
||||
|
||||
if SERVER then
|
||||
self:TeleportStore()
|
||||
else
|
||||
surface.PlaySound("ui/buttonrollover.wav")
|
||||
end
|
||||
end
|
||||
|
||||
local zap = Sound("ambient/levels/labs/electric_explosion4.wav")
|
||||
local unzap = Sound("ambient/levels/labs/electric_explosion2.wav")
|
||||
|
||||
local function Telefrag(victim, attacker, weapon)
|
||||
if not IsValid(victim) then return end
|
||||
|
||||
local dmginfo = DamageInfo()
|
||||
dmginfo:SetDamage(5000)
|
||||
dmginfo:SetDamageType(DMG_SONIC)
|
||||
dmginfo:SetAttacker(attacker)
|
||||
dmginfo:SetInflictor(weapon)
|
||||
dmginfo:SetDamageForce(Vector(0,0,10))
|
||||
dmginfo:SetDamagePosition(attacker:GetPos())
|
||||
|
||||
victim:TakeDamageInfo(dmginfo)
|
||||
end
|
||||
|
||||
|
||||
local function ShouldCollide(ent)
|
||||
local g = ent:GetCollisionGroup()
|
||||
return (g != COLLISION_GROUP_WEAPON and
|
||||
g != COLLISION_GROUP_DEBRIS and
|
||||
g != COLLISION_GROUP_DEBRIS_TRIGGER and
|
||||
g != COLLISION_GROUP_INTERACTIVE_DEBRIS)
|
||||
end
|
||||
|
||||
-- Teleport a player to a {pos, ang}
|
||||
local function TeleportPlayer(ply, teleport)
|
||||
local oldpos = ply:GetPos()
|
||||
local pos = teleport.pos
|
||||
local ang = teleport.ang
|
||||
|
||||
-- print decal on destination
|
||||
util.PaintDown(pos + Vector(0,0,25), "GlassBreak", ply)
|
||||
|
||||
-- perform teleport
|
||||
ply:SetPos(pos)
|
||||
ply:SetEyeAngles(ang) -- ineffective due to freeze...
|
||||
|
||||
timer.Simple(delay_beamdown, function ()
|
||||
if IsValid(ply) then
|
||||
ply:Freeze(false)
|
||||
end
|
||||
end)
|
||||
|
||||
sound.Play(zap, oldpos, 65, 100)
|
||||
sound.Play(unzap, pos, 55, 100)
|
||||
|
||||
-- print decal on source now that we're gone, because else it will refuse
|
||||
-- to draw for some reason
|
||||
util.PaintDown(oldpos + Vector(0,0,25), "GlassBreak", ply)
|
||||
end
|
||||
|
||||
-- Checks teleport destination. Returns bool and table, if bool is true then
|
||||
-- location is blocked by world or prop. If table is non-nil it contains a list
|
||||
-- of blocking players.
|
||||
local function CanTeleportToPos(ply, pos)
|
||||
-- first check if we can teleport here at all, because any solid object or
|
||||
-- brush will make us stuck and therefore kills/blocks us instead, so the
|
||||
-- trace checks for anything solid to players that isn't a player
|
||||
local tr = nil
|
||||
local tres = {start=pos, endpos=pos, mask=MASK_PLAYERSOLID, filter=player.GetAll()}
|
||||
local collide = false
|
||||
|
||||
-- This thing is unnecessary if we can supply a collision group to trace
|
||||
-- functions, like we can in source and sanity suggests we should be able
|
||||
-- to do so, but I have not found a way to do so yet. Until then, re-trace
|
||||
-- while extending our filter whenever we hit something we don't want to
|
||||
-- hit (like weapons or ragdolls).
|
||||
repeat
|
||||
tr = util.TraceEntity(tres, ply)
|
||||
|
||||
if tr.HitWorld then
|
||||
collide = true
|
||||
elseif IsValid(tr.Entity) then
|
||||
if ShouldCollide(tr.Entity) then
|
||||
collide = true
|
||||
else
|
||||
table.insert(tres.filter, tr.Entity)
|
||||
end
|
||||
end
|
||||
until (not tr.Hit) or collide
|
||||
|
||||
if collide then
|
||||
--Telefrag(ply, ply)
|
||||
return true, nil
|
||||
else
|
||||
|
||||
-- find all players in the place where we will be and telefrag them
|
||||
local blockers = ents.FindInBox(pos + Vector(-16, -16, 0),
|
||||
pos + Vector(16, 16, 64))
|
||||
|
||||
local blocking_plys = {}
|
||||
|
||||
for _, block in ipairs(blockers) do
|
||||
if IsValid(block) then
|
||||
if block:IsPlayer() and block != ply then
|
||||
if block:IsTerror() and block:Alive() then
|
||||
table.insert(blocking_plys, block)
|
||||
-- telefrag blocker
|
||||
--Telefrag(block, ply)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return false, blocking_plys
|
||||
end
|
||||
|
||||
return false, nil
|
||||
end
|
||||
|
||||
local function DoTeleport(ply, teleport, weapon)
|
||||
if IsValid(ply) and ply:IsTerror() and teleport then
|
||||
local fail = false
|
||||
|
||||
local block_world, block_plys = CanTeleportToPos(ply, teleport.pos)
|
||||
|
||||
if block_world then
|
||||
-- if blocked by prop/world, always fail
|
||||
fail = true
|
||||
elseif block_plys and #block_plys > 0 then
|
||||
-- if blocked by player, maybe telefrag
|
||||
if ttt_telefrags:GetBool() then
|
||||
for _, p in ipairs(block_plys) do
|
||||
Telefrag(p, ply, weapon)
|
||||
end
|
||||
else
|
||||
fail = true
|
||||
end
|
||||
end
|
||||
|
||||
if not fail then
|
||||
TeleportPlayer(ply, teleport)
|
||||
else
|
||||
ply:Freeze(false)
|
||||
LANG.Msg(ply, "tele_failed")
|
||||
end
|
||||
elseif IsValid(ply) then
|
||||
-- should never happen, but at least unfreeze
|
||||
ply:Freeze(false)
|
||||
LANG.Msg(ply, "tele_failed")
|
||||
end
|
||||
end
|
||||
|
||||
local function StartTeleport(ply, teleport, weapon)
|
||||
if (not IsValid(ply)) or (not ply:IsTerror()) or (not teleport) then
|
||||
return end
|
||||
|
||||
teleport.ang = ply:EyeAngles()
|
||||
|
||||
timer.Simple(delay_beamup, function() DoTeleport(ply, teleport, weapon) end)
|
||||
|
||||
local ang = ply:GetAngles()
|
||||
|
||||
local edata_up = EffectData()
|
||||
edata_up:SetOrigin(ply:GetPos())
|
||||
ang = Angle(0, ang.y, ang.r) -- deep copy
|
||||
edata_up:SetAngles(ang)
|
||||
edata_up:SetEntity(ply)
|
||||
edata_up:SetMagnitude(delay_beamup)
|
||||
edata_up:SetRadius(delay_beamdown)
|
||||
|
||||
util.Effect("teleport_beamup", edata_up)
|
||||
|
||||
local edata_dn = EffectData()
|
||||
edata_dn:SetOrigin(teleport.pos)
|
||||
ang = Angle(0, ang.y, ang.r) -- deep copy
|
||||
edata_dn:SetAngles(ang)
|
||||
edata_dn:SetEntity(ply)
|
||||
edata_dn:SetMagnitude(delay_beamup)
|
||||
edata_dn:SetRadius(delay_beamdown)
|
||||
|
||||
util.Effect("teleport_beamdown", edata_dn)
|
||||
end
|
||||
|
||||
function SWEP:TeleportRecall()
|
||||
local ply = self:GetOwner()
|
||||
if IsValid(ply) and ply:IsTerror() then
|
||||
local mark = self:GetTeleportMark()
|
||||
if mark then
|
||||
|
||||
local g = ply:GetGroundEntity()
|
||||
if g != game.GetWorld() and not IsValid(g) then
|
||||
LANG.Msg(ply, "tele_no_ground")
|
||||
return
|
||||
end
|
||||
|
||||
if ply:Crouching() then
|
||||
LANG.Msg(ply, "tele_no_crouch")
|
||||
return
|
||||
end
|
||||
|
||||
ply:Freeze(true)
|
||||
|
||||
self:TakePrimaryAmmo(1)
|
||||
|
||||
timer.Simple(0.2, function() StartTeleport(ply, mark, self) end)
|
||||
else
|
||||
LANG.Msg(ply, "tele_no_mark")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function CanStoreTeleportPos(ply, pos)
|
||||
local g = ply:GetGroundEntity()
|
||||
if g != game.GetWorld() or (IsValid(g) and g:GetMoveType() != MOVETYPE_NONE) then
|
||||
return false, "tele_no_mark_ground"
|
||||
elseif ply:Crouching() then
|
||||
return false, "tele_no_mark_crouch"
|
||||
end
|
||||
|
||||
return true, nil
|
||||
end
|
||||
|
||||
function SWEP:TeleportStore()
|
||||
local ply = self:GetOwner()
|
||||
if IsValid(ply) and ply:IsTerror() then
|
||||
|
||||
local allow, msg = CanStoreTeleportPos(ply, self:GetPos())
|
||||
if not allow then
|
||||
LANG.Msg(ply, msg)
|
||||
return
|
||||
end
|
||||
|
||||
self:SetTeleportMark(ply:GetPos(), ply:EyeAngles())
|
||||
|
||||
LANG.Msg(ply, "tele_marked")
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
function SWEP:Reload()
|
||||
return false
|
||||
end
|
||||
|
||||
|
||||
if CLIENT then
|
||||
function SWEP:Initialize()
|
||||
self:AddHUDHelp("tele_help_pri", "tele_help_sec", true)
|
||||
|
||||
return self.BaseClass.Initialize(self)
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:Deploy()
|
||||
if SERVER and IsValid(self:GetOwner()) then
|
||||
self:GetOwner():DrawViewModel(false)
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function SWEP:ShootEffects() end
|
||||
83
gamemodes/terrortown/entities/weapons/weapon_ttt_unarmed.lua
Normal file
83
gamemodes/terrortown/entities/weapons/weapon_ttt_unarmed.lua
Normal file
@@ -0,0 +1,83 @@
|
||||
--[[
|
||||
| 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()
|
||||
|
||||
SWEP.HoldType = "normal"
|
||||
|
||||
if CLIENT then
|
||||
SWEP.PrintName = "unarmed_name"
|
||||
SWEP.Slot = 5
|
||||
|
||||
SWEP.ViewModelFOV = 10
|
||||
end
|
||||
|
||||
SWEP.Base = "weapon_tttbase"
|
||||
|
||||
SWEP.ViewModel = "models/weapons/v_crowbar.mdl"
|
||||
SWEP.WorldModel = "models/weapons/w_crowbar.mdl"
|
||||
|
||||
SWEP.Primary.ClipSize = -1
|
||||
SWEP.Primary.DefaultClip = -1
|
||||
SWEP.Primary.Automatic = false
|
||||
SWEP.Primary.Ammo = "none"
|
||||
|
||||
SWEP.Secondary.ClipSize = -1
|
||||
SWEP.Secondary.DefaultClip = -1
|
||||
SWEP.Secondary.Automatic = false
|
||||
SWEP.Secondary.Ammo = "none"
|
||||
|
||||
SWEP.Kind = WEAPON_UNARMED
|
||||
SWEP.InLoadoutFor = {ROLE_INNOCENT, ROLE_TRAITOR, ROLE_DETECTIVE}
|
||||
|
||||
SWEP.AllowDelete = false
|
||||
SWEP.AllowDrop = false
|
||||
SWEP.NoSights = true
|
||||
|
||||
function SWEP:GetClass()
|
||||
return "weapon_ttt_unarmed"
|
||||
end
|
||||
|
||||
function SWEP:OnDrop()
|
||||
self:Remove()
|
||||
end
|
||||
|
||||
function SWEP:ShouldDropOnDie()
|
||||
return false
|
||||
end
|
||||
|
||||
function SWEP:PrimaryAttack()
|
||||
end
|
||||
|
||||
function SWEP:SecondaryAttack()
|
||||
end
|
||||
|
||||
function SWEP:Reload()
|
||||
end
|
||||
|
||||
function SWEP:Deploy()
|
||||
if SERVER and IsValid(self:GetOwner()) then
|
||||
self:GetOwner():DrawViewModel(false)
|
||||
end
|
||||
|
||||
self:DrawShadow(false)
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function SWEP:Holster()
|
||||
return true
|
||||
end
|
||||
|
||||
function SWEP:DrawWorldModel()
|
||||
end
|
||||
|
||||
function SWEP:DrawWorldModelTranslucent()
|
||||
end
|
||||
807
gamemodes/terrortown/entities/weapons/weapon_ttt_wtester.lua
Normal file
807
gamemodes/terrortown/entities/weapons/weapon_ttt_wtester.lua
Normal file
@@ -0,0 +1,807 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
-- DNA Scanner
|
||||
|
||||
AddCSLuaFile()
|
||||
|
||||
DEFINE_BASECLASS "weapon_tttbase"
|
||||
|
||||
SWEP.HoldType = "normal"
|
||||
|
||||
if CLIENT then
|
||||
SWEP.PrintName = "dna_name"
|
||||
SWEP.Slot = 8
|
||||
|
||||
SWEP.ViewModelFOV = 10
|
||||
SWEP.DrawCrosshair = false
|
||||
|
||||
SWEP.EquipMenuData = {
|
||||
type = "item_weapon",
|
||||
desc = "dna_desc"
|
||||
};
|
||||
|
||||
SWEP.Icon = "vgui/ttt/icon_wtester"
|
||||
end
|
||||
|
||||
SWEP.Base = "weapon_tttbase"
|
||||
|
||||
SWEP.ViewModel = "models/weapons/v_crowbar.mdl"
|
||||
SWEP.WorldModel = "models/props_lab/huladoll.mdl"
|
||||
|
||||
SWEP.Primary.ClipSize = -1
|
||||
SWEP.Primary.DefaultClip = -1
|
||||
SWEP.Primary.Automatic = false
|
||||
SWEP.Primary.Delay = 1
|
||||
SWEP.Primary.Ammo = "none"
|
||||
|
||||
SWEP.Secondary.ClipSize = -1
|
||||
SWEP.Secondary.DefaultClip = -1
|
||||
SWEP.Secondary.Automatic = false
|
||||
SWEP.Secondary.Ammo = "none"
|
||||
SWEP.Secondary.Delay = 2
|
||||
|
||||
SWEP.Kind = WEAPON_ROLE
|
||||
SWEP.CanBuy = nil -- no longer a buyable thing
|
||||
SWEP.WeaponID = AMMO_WTESTER
|
||||
|
||||
SWEP.InLoadoutFor = {ROLE_DETECTIVE}
|
||||
|
||||
--SWEP.AllowDrop = false
|
||||
SWEP.AutoSpawnable = false
|
||||
SWEP.NoSights = true
|
||||
|
||||
SWEP.Range = 175
|
||||
|
||||
SWEP.ItemSamples = {}
|
||||
|
||||
SWEP.NowRepeating = nil
|
||||
|
||||
local MAX_ITEM = 30
|
||||
SWEP.MaxItemSamples = MAX_ITEM
|
||||
|
||||
local CHARGE_DELAY = 0.1
|
||||
local CHARGE_RATE = 3
|
||||
local MAX_CHARGE = 1250
|
||||
|
||||
local SAMPLE_PLAYER = 1
|
||||
local SAMPLE_ITEM = 2
|
||||
|
||||
AccessorFuncDT(SWEP, "charge", "Charge")
|
||||
AccessorFuncDT(SWEP, "last_scanned", "LastScanned")
|
||||
|
||||
if CLIENT then
|
||||
CreateClientConVar("ttt_dna_scan_repeat", 1, true, true)
|
||||
else
|
||||
function SWEP:GetRepeating()
|
||||
local ply = self:GetOwner()
|
||||
return IsValid(ply) and ply:GetInfoNum("ttt_dna_scan_repeat", 1) == 1
|
||||
end
|
||||
end
|
||||
|
||||
SWEP.NextCharge = 0
|
||||
|
||||
function SWEP:SetupDataTables()
|
||||
self:DTVar("Int", 0, "charge")
|
||||
self:DTVar("Int", 1, "last_scanned")
|
||||
|
||||
return self.BaseClass.SetupDataTables(self)
|
||||
end
|
||||
|
||||
function SWEP:Initialize()
|
||||
self:SetCharge(MAX_CHARGE)
|
||||
self:SetLastScanned(-1)
|
||||
|
||||
if CLIENT then
|
||||
self:AddHUDHelp("dna_help_primary", "dna_help_secondary", true)
|
||||
end
|
||||
|
||||
return self.BaseClass.Initialize(self)
|
||||
end
|
||||
|
||||
local beep_miss = Sound("player/suit_denydevice.wav")
|
||||
function SWEP:PrimaryAttack()
|
||||
self:SetNextPrimaryFire( CurTime() + self.Primary.Delay )
|
||||
|
||||
-- will be tracing against players
|
||||
self:GetOwner():LagCompensation(true)
|
||||
|
||||
local spos = self:GetOwner():GetShootPos()
|
||||
local sdest = spos + (self:GetOwner():GetAimVector() * self.Range)
|
||||
|
||||
local tr = util.TraceLine({start=spos, endpos=sdest, filter=self:GetOwner(), mask=MASK_SHOT})
|
||||
local ent = tr.Entity
|
||||
if IsValid(ent) and (not ent:IsPlayer()) then
|
||||
if SERVER then
|
||||
if ent:GetClass() == "prop_ragdoll" and ent.killer_sample then
|
||||
if CORPSE.GetFound(ent, false) then
|
||||
self:GatherRagdollSample(ent)
|
||||
else
|
||||
self:Report("dna_identify")
|
||||
end
|
||||
elseif ent.fingerprints and #ent.fingerprints > 0 then
|
||||
self:GatherObjectSample(ent)
|
||||
else
|
||||
self:Report("dna_notfound")
|
||||
end
|
||||
end
|
||||
else
|
||||
if CLIENT then
|
||||
self:GetOwner():EmitSound(beep_miss)
|
||||
end
|
||||
end
|
||||
|
||||
self:GetOwner():LagCompensation(false)
|
||||
end
|
||||
|
||||
function SWEP:GatherRagdollSample(ent)
|
||||
local sample = ent.killer_sample or {t=0, killer=nil}
|
||||
local ply = sample.killer
|
||||
if (not IsValid(ply)) and sample.killer_sid64 then
|
||||
ply = player.GetBySteamID64(sample.killer_sid64)
|
||||
end
|
||||
|
||||
|
||||
if IsValid(ply) then
|
||||
if sample.t < CurTime() then
|
||||
self:Report("dna_decayed")
|
||||
return
|
||||
end
|
||||
|
||||
local added = self:AddPlayerSample(ent, ply)
|
||||
|
||||
if not added then
|
||||
self:Report("dna_limit")
|
||||
else
|
||||
self:Report("dna_killer")
|
||||
|
||||
if self:GetRepeating() and self:GetCharge() == MAX_CHARGE then
|
||||
self:PerformScan(#self.ItemSamples)
|
||||
end
|
||||
end
|
||||
elseif ply != nil then
|
||||
-- not valid but not nil -> disconnected?
|
||||
self:Report("dna_no_killer")
|
||||
else
|
||||
self:Report("dna_notfound")
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:GatherObjectSample(ent)
|
||||
if ent:GetClass() == "ttt_c4" and ent:GetArmed() then
|
||||
self:Report("dna_armed")
|
||||
else
|
||||
local collected, old, own = self:AddItemSample(ent)
|
||||
|
||||
if collected == -1 then
|
||||
self:Report("dna_limit")
|
||||
else
|
||||
self:Report("dna_object", {num = collected})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:Report(msg, params)
|
||||
LANG.Msg(self:GetOwner(), msg, params)
|
||||
end
|
||||
|
||||
function SWEP:AddPlayerSample(corpse, killer)
|
||||
if #self.ItemSamples < self.MaxItemSamples then
|
||||
local prnt = {source=corpse, ply=killer, type=SAMPLE_PLAYER, cls=killer:GetClass()}
|
||||
if not table.HasTable(self.ItemSamples, prnt) then
|
||||
table.insert(self.ItemSamples, prnt)
|
||||
|
||||
DamageLog("SAMPLE:\t " .. self:GetOwner():Nick() .. " retrieved DNA of " .. (IsValid(killer) and killer:Nick() or "<disconnected>") .. " from corpse of " .. (IsValid(corpse) and CORPSE.GetPlayerNick(corpse) or "<invalid>"))
|
||||
|
||||
hook.Call("TTTFoundDNA", GAMEMODE, self:GetOwner(), killer, corpse)
|
||||
end
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function SWEP:AddItemSample(ent)
|
||||
if #self.ItemSamples < self.MaxItemSamples then
|
||||
table.Shuffle(ent.fingerprints)
|
||||
|
||||
local new = 0
|
||||
local old = 0
|
||||
local own = 0
|
||||
for _, p in pairs(ent.fingerprints) do
|
||||
local prnt = {source=ent, ply=p, type=SAMPLE_ITEM, cls=ent:GetClass()}
|
||||
|
||||
if p == self:GetOwner() then
|
||||
own = own + 1
|
||||
elseif table.HasTable(self.ItemSamples, prnt) then
|
||||
old = old + 1
|
||||
else
|
||||
table.insert(self.ItemSamples, prnt)
|
||||
|
||||
DamageLog("SAMPLE:\t " .. self:GetOwner():Nick() .. " retrieved DNA of " .. (IsValid(p) and p:Nick() or "<disconnected>") .. " from " .. ent:GetClass())
|
||||
|
||||
new = new + 1
|
||||
hook.Call("TTTFoundDNA", GAMEMODE, self:GetOwner(), p, ent)
|
||||
end
|
||||
end
|
||||
return new, old, own
|
||||
end
|
||||
return -1
|
||||
end
|
||||
|
||||
function SWEP:RemoveItemSample(idx)
|
||||
if self.ItemSamples[idx] then
|
||||
if self:GetLastScanned() == idx then
|
||||
self:ClearScanState()
|
||||
end
|
||||
|
||||
table.remove(self.ItemSamples, idx)
|
||||
|
||||
self:SendPrints(false)
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:SecondaryAttack()
|
||||
self:SetNextSecondaryFire( CurTime() + 0.05 )
|
||||
|
||||
if CLIENT then return end
|
||||
|
||||
self:SendPrints(true)
|
||||
end
|
||||
|
||||
if SERVER then
|
||||
-- Sending this all in one umsg limits the max number of samples. 17 player
|
||||
-- samples and 20 item samples (with 20 matches) has been verified as
|
||||
-- working in the old DNA sampler.
|
||||
function SWEP:SendPrints(should_open)
|
||||
net.Start("TTT_ShowPrints", self:GetOwner())
|
||||
net.WriteBit(should_open)
|
||||
net.WriteUInt(#self.ItemSamples, 8)
|
||||
|
||||
for k, v in ipairs(self.ItemSamples) do
|
||||
net.WriteString(v.cls)
|
||||
end
|
||||
|
||||
net.Send(self:GetOwner())
|
||||
end
|
||||
|
||||
function SWEP:SendScan(pos)
|
||||
local clear = (pos == nil) or (not IsValid(self:GetOwner()))
|
||||
net.Start("TTT_ScanResult", self:GetOwner())
|
||||
net.WriteBit(clear)
|
||||
if not clear then
|
||||
net.WriteVector(pos)
|
||||
end
|
||||
net.Send(self:GetOwner())
|
||||
end
|
||||
|
||||
function SWEP:ClearScanState()
|
||||
self:SetLastScanned(-1)
|
||||
self.NowRepeating = nil
|
||||
self:SendScan(nil)
|
||||
end
|
||||
|
||||
local function GetScanTarget(sample)
|
||||
if not sample then return end
|
||||
|
||||
local target = sample.ply
|
||||
if not IsValid(target) then return end
|
||||
|
||||
-- decoys always take priority, even after death
|
||||
if IsValid(target.decoy) then
|
||||
target = target.decoy
|
||||
elseif not target:IsTerror() then
|
||||
-- fall back to ragdoll, as long as it's not destroyed
|
||||
target = target.server_ragdoll
|
||||
if not IsValid(target) then return end
|
||||
end
|
||||
|
||||
return target
|
||||
end
|
||||
|
||||
function SWEP:PerformScan(idx, repeated)
|
||||
if self:GetCharge() < MAX_CHARGE then return end
|
||||
|
||||
local sample = self.ItemSamples[idx]
|
||||
if (not sample) or (not IsValid(self:GetOwner())) then
|
||||
if repeated then self:ClearScanState() end
|
||||
return
|
||||
end
|
||||
|
||||
local target = GetScanTarget(sample)
|
||||
if not IsValid(target) then
|
||||
self:Report("dna_gone")
|
||||
self:SetCharge(self:GetCharge() - 50)
|
||||
|
||||
if repeated then self:ClearScanState() end
|
||||
return
|
||||
end
|
||||
|
||||
local pos = target:LocalToWorld(target:OBBCenter())
|
||||
|
||||
self:SendScan(pos)
|
||||
|
||||
self:SetLastScanned(idx)
|
||||
self.NowRepeating = self:GetRepeating()
|
||||
|
||||
local dist = math.ceil(self:GetOwner():GetPos():Distance(pos))
|
||||
|
||||
self:SetCharge(math.max(0, self:GetCharge() - math.max(50, dist / 2)))
|
||||
end
|
||||
|
||||
function SWEP:Think()
|
||||
if self:GetCharge() < MAX_CHARGE then
|
||||
if self.NextCharge < CurTime() then
|
||||
self:SetCharge(math.min(MAX_CHARGE, self:GetCharge() + CHARGE_RATE))
|
||||
|
||||
self.NextCharge = CurTime() + CHARGE_DELAY
|
||||
end
|
||||
elseif self.NowRepeating and IsValid(self:GetOwner()) then
|
||||
-- owner changed his mind since running last scan?
|
||||
if self:GetRepeating() then
|
||||
self:PerformScan(self:GetLastScanned(), true)
|
||||
else
|
||||
self.NowRepeating = self:GetRepeating()
|
||||
end
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
-- Helper to get at a player's scanner, if he has one
|
||||
local function GetTester(ply)
|
||||
if IsValid(ply) then
|
||||
local tester = ply:GetActiveWeapon()
|
||||
if IsValid(tester) and tester:GetClass() == "weapon_ttt_wtester" then
|
||||
return tester
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
|
||||
if CLIENT then
|
||||
|
||||
local T = LANG.GetTranslation
|
||||
local PT = LANG.GetParamTranslation
|
||||
local TT = LANG.TryTranslation
|
||||
|
||||
function SWEP:DrawHUD()
|
||||
self:DrawHelp()
|
||||
|
||||
local spos = self:GetOwner():GetShootPos()
|
||||
local sdest = spos + (self:GetOwner():GetAimVector() * self.Range)
|
||||
|
||||
local tr = util.TraceLine({start=spos, endpos=sdest, filter=self:GetOwner(), mask=MASK_SHOT})
|
||||
|
||||
local length = 20
|
||||
local gap = 6
|
||||
|
||||
local can_sample = false
|
||||
|
||||
local ent = tr.Entity
|
||||
if IsValid(ent) then
|
||||
-- weapon or dropped equipment
|
||||
if ((ent:IsWeapon() or ent.CanHavePrints) or
|
||||
-- knife in corpse, or a ragdoll
|
||||
ent:GetNWBool("HasPrints", false) or
|
||||
(ent:GetClass() == "prop_ragdoll" and
|
||||
CORPSE.GetPlayerNick(ent, false) and
|
||||
CORPSE.GetFound(ent, false))) then
|
||||
|
||||
surface.SetDrawColor(0, 255, 0, 255)
|
||||
gap = 0
|
||||
|
||||
can_sample = true
|
||||
else
|
||||
surface.SetDrawColor(255, 0, 0, 200)
|
||||
gap = 0
|
||||
end
|
||||
else
|
||||
surface.SetDrawColor(255, 255, 255, 200)
|
||||
end
|
||||
|
||||
local x = ScrW() / 2.0
|
||||
local y = ScrH() / 2.0
|
||||
|
||||
surface.DrawLine( x - length, y, x - gap, y )
|
||||
surface.DrawLine( x + length, y, x + gap, y )
|
||||
surface.DrawLine( x, y - length, x, y - gap )
|
||||
surface.DrawLine( x, y + length, x, y + gap )
|
||||
|
||||
if ent and can_sample then
|
||||
surface.SetFont("DefaultFixedDropShadow")
|
||||
surface.SetTextColor(0, 255, 0, 255)
|
||||
surface.SetTextPos( x + length*2, y - length*2 )
|
||||
surface.DrawText(T("dna_hud_type") .. ": " .. (ent:GetClass() == "prop_ragdoll" and T("dna_hud_body") or T("dna_hud_item")))
|
||||
surface.SetTextPos( x + length*2, y - length*2 + 15)
|
||||
surface.DrawText("ID: #" .. ent:EntIndex())
|
||||
end
|
||||
end
|
||||
|
||||
local basedir = "vgui/ttt/icon_"
|
||||
local function GetDisplayData(cls)
|
||||
local wep = util.WeaponForClass(cls)
|
||||
|
||||
local img = basedir .. "nades"
|
||||
local name = "something"
|
||||
|
||||
if cls == "player" then
|
||||
img = basedir .. "corpse"
|
||||
name = "corpse"
|
||||
elseif wep then
|
||||
img = wep.Icon or img
|
||||
name = wep.PrintName or name
|
||||
end
|
||||
|
||||
return img, name
|
||||
end
|
||||
|
||||
local last_panel_selected = 1
|
||||
local function ShowPrintsPopup(item_prints, tester)
|
||||
local m = 10
|
||||
local bw, bh = 100, 25
|
||||
|
||||
local dpanel = vgui.Create("DFrame")
|
||||
local w, h = 400, 250
|
||||
dpanel:SetSize(w, h)
|
||||
|
||||
dpanel:AlignRight(5)
|
||||
dpanel:AlignBottom(5)
|
||||
|
||||
dpanel:SetTitle(T("dna_menu_title"))
|
||||
dpanel:SetVisible(true)
|
||||
dpanel:ShowCloseButton(true)
|
||||
dpanel:SetMouseInputEnabled(true)
|
||||
|
||||
local wrap = vgui.Create("DPanel", dpanel)
|
||||
wrap:StretchToParent(m/2, m + 15, m/2, m + bh)
|
||||
wrap:SetPaintBackground(false)
|
||||
|
||||
-- item sample listing
|
||||
local ilist = vgui.Create("DPanelSelect", wrap)
|
||||
ilist:StretchToParent(0,0,0,0)
|
||||
ilist:EnableHorizontal(true)
|
||||
ilist:SetSpacing(1)
|
||||
ilist:SetPadding(1)
|
||||
|
||||
ilist.OnActivePanelChanged = function(s, old, new)
|
||||
last_panel_selected = new and new.key or 1
|
||||
end
|
||||
|
||||
ilist.OnScan = function(s, scanned_pnl)
|
||||
for k, pnl in pairs(s:GetItems()) do
|
||||
pnl:SetIconColor(COLOR_LGRAY)
|
||||
end
|
||||
|
||||
scanned_pnl:SetIconColor(COLOR_WHITE)
|
||||
end
|
||||
|
||||
if ilist.VBar then
|
||||
ilist.VBar:Remove()
|
||||
ilist.VBar = nil
|
||||
end
|
||||
|
||||
local iscroll = vgui.Create("DHorizontalScroller", ilist)
|
||||
iscroll:SetPos(3,1)
|
||||
iscroll:SetSize(363, 66)
|
||||
iscroll:SetOverlap(1)
|
||||
|
||||
iscroll.LoadFrom = function(s, tbl, layout)
|
||||
ilist:Clear(true)
|
||||
ilist.SelectedPanel = nil
|
||||
|
||||
-- Scroller has no Clear()
|
||||
for k, pnl in pairs(s.Panels) do
|
||||
if IsValid(pnl) then
|
||||
pnl:Remove()
|
||||
end
|
||||
end
|
||||
|
||||
s.Panels = {}
|
||||
|
||||
local last_scan = tester and tester:GetLastScanned() or -1
|
||||
|
||||
for k, v in ipairs(tbl) do
|
||||
local ic = vgui.Create("SimpleIcon", ilist)
|
||||
|
||||
ic:SetIconSize(64)
|
||||
|
||||
local img, name = GetDisplayData(v)
|
||||
|
||||
ic:SetIcon(img)
|
||||
|
||||
local tip = PT("dna_menu_sample", {source = TT(name) or "???"})
|
||||
|
||||
ic:SetTooltip(tip)
|
||||
|
||||
ic.key = k
|
||||
ic.val = v
|
||||
|
||||
if layout then
|
||||
ic:PerformLayout()
|
||||
end
|
||||
|
||||
ilist:AddPanel(ic)
|
||||
s:AddPanel(ic)
|
||||
|
||||
if k == last_panel_selected then
|
||||
ilist:SelectPanel(ic)
|
||||
end
|
||||
|
||||
if last_scan > 0 then
|
||||
ic:SetIconColor(last_scan == k and COLOR_WHITE or COLOR_LGRAY)
|
||||
end
|
||||
end
|
||||
|
||||
iscroll:InvalidateLayout()
|
||||
end
|
||||
|
||||
iscroll:LoadFrom(item_prints)
|
||||
|
||||
local delwrap = vgui.Create("DPanel", wrap)
|
||||
delwrap:SetPos(m, 70)
|
||||
delwrap:SetSize(370, bh)
|
||||
delwrap:SetPaintBackground(false)
|
||||
|
||||
local delitem = vgui.Create("DButton", delwrap)
|
||||
delitem:SetPos(0,0)
|
||||
delitem:SetSize(bw, bh)
|
||||
delitem:SetText(T("dna_menu_remove"))
|
||||
delitem.DoClick = function()
|
||||
if IsValid(ilist) and IsValid(ilist.SelectedPanel) then
|
||||
local idx = ilist.SelectedPanel.key
|
||||
RunConsoleCommand("ttt_wtester_remove", idx)
|
||||
end
|
||||
end
|
||||
|
||||
delitem.Think = function(s)
|
||||
if IsValid(ilist) and IsValid(ilist.SelectedPanel) then
|
||||
s:SetEnabled(true)
|
||||
else
|
||||
s:SetEnabled(false)
|
||||
end
|
||||
end
|
||||
|
||||
local delhlp = vgui.Create("DLabel", delwrap)
|
||||
delhlp:SetPos(bw + m, 0)
|
||||
delhlp:SetText(T("dna_menu_help1"))
|
||||
delhlp:SizeToContents()
|
||||
|
||||
|
||||
-- hammer out layouts
|
||||
wrap:PerformLayout()
|
||||
-- scroller needs to sort itself out so it displays all icons it should
|
||||
iscroll:PerformLayout()
|
||||
|
||||
local mwrap = vgui.Create("DPanel", wrap)
|
||||
mwrap:SetPaintBackground(false)
|
||||
mwrap:SetPos(m,100)
|
||||
mwrap:SetSize(370, 90)
|
||||
|
||||
|
||||
local bar = vgui.Create("TTTProgressBar", mwrap)
|
||||
bar:SetSize(370, 35)
|
||||
bar:SetPos(0, 0)
|
||||
bar:CenterHorizontal()
|
||||
bar:SetMin(0)
|
||||
bar:SetMax(MAX_CHARGE)
|
||||
bar:SetValue(tester and math.min(MAX_CHARGE, tester:GetCharge()))
|
||||
bar:SetColor(COLOR_GREEN)
|
||||
bar:LabelAsPercentage()
|
||||
|
||||
local state = vgui.Create("DLabel", bar)
|
||||
state:SetSize(0, 35)
|
||||
state:SetPos(10, 6)
|
||||
state:SetFont("Trebuchet22")
|
||||
state:SetText(T("dna_menu_ready"))
|
||||
state:SetTextColor(COLOR_WHITE)
|
||||
state:SizeToContents()
|
||||
|
||||
local scan = vgui.Create("DButton", mwrap)
|
||||
scan:SetText(T("dna_menu_scan"))
|
||||
scan:SetSize(bw, bh)
|
||||
scan:SetPos(0, 40)
|
||||
scan:SetEnabled(false)
|
||||
|
||||
scan.DoClick = function(s)
|
||||
if IsValid(ilist) then
|
||||
local i = ilist.SelectedPanel
|
||||
if IsValid(i) then
|
||||
RunConsoleCommand("ttt_wtester_scan", i.key)
|
||||
|
||||
ilist:OnScan(i)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local dcheck = vgui.Create("DCheckBoxLabel", mwrap)
|
||||
dcheck:SetPos(0, 70)
|
||||
dcheck:SetText(T("dna_menu_repeat"))
|
||||
dcheck:SetIndent(7)
|
||||
dcheck:SizeToContents()
|
||||
dcheck:SetConVar("ttt_dna_scan_repeat")
|
||||
--dcheck:SetValue(tester and tester:GetRepeating())
|
||||
|
||||
|
||||
local scanhlp = vgui.Create("DLabel", mwrap)
|
||||
scanhlp:SetPos(bw + m, 40)
|
||||
scanhlp:SetText(T("dna_menu_help2"))
|
||||
scanhlp:SizeToContents()
|
||||
|
||||
-- CLOSE
|
||||
local dbut = vgui.Create("DButton", dpanel)
|
||||
dbut:SetSize(bw, bh)
|
||||
dbut:SetPos(m, h - bh - m/1.5)
|
||||
dbut:CenterHorizontal()
|
||||
dbut:SetText(T("close"))
|
||||
dbut.DoClick = function() dpanel:Close() end
|
||||
|
||||
dpanel:MakePopup()
|
||||
dpanel:SetKeyboardInputEnabled(false)
|
||||
|
||||
-- Expose updating fns
|
||||
dpanel.UpdatePrints = function(s, its)
|
||||
if IsValid(iscroll) then
|
||||
iscroll:LoadFrom(its)
|
||||
end
|
||||
end
|
||||
|
||||
dpanel.Think = function(s)
|
||||
if IsValid(bar) and IsValid(scan) and tester then
|
||||
local charge = tester:GetCharge()
|
||||
bar:SetValue(math.min(MAX_CHARGE, charge))
|
||||
if charge < MAX_CHARGE then
|
||||
bar:SetColor(COLOR_RED)
|
||||
|
||||
state:SetText(T("dna_menu_charge"))
|
||||
state:SizeToContents()
|
||||
|
||||
scan:SetEnabled(false)
|
||||
else
|
||||
bar:SetColor(COLOR_GREEN)
|
||||
|
||||
if IsValid(ilist) and IsValid(ilist.SelectedPanel) then
|
||||
scan:SetEnabled(true)
|
||||
|
||||
state:SetText(T("dna_menu_ready"))
|
||||
state:SizeToContents()
|
||||
else
|
||||
state:SetText(T("dna_menu_select"))
|
||||
state:SizeToContents()
|
||||
scan:SetEnabled(false)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return dpanel
|
||||
end
|
||||
|
||||
local printspanel = nil
|
||||
local function RecvPrints()
|
||||
local should_open = net.ReadBit() == 1
|
||||
|
||||
local num = net.ReadUInt(8)
|
||||
local item_prints = {}
|
||||
for i=1, num do
|
||||
local ent = net.ReadString()
|
||||
table.insert(item_prints, ent)
|
||||
end
|
||||
|
||||
if should_open then
|
||||
if IsValid(printspanel) then
|
||||
printspanel:Remove()
|
||||
end
|
||||
|
||||
local tester = GetTester(LocalPlayer())
|
||||
|
||||
printspanel = ShowPrintsPopup(item_prints, tester)
|
||||
else
|
||||
if IsValid(printspanel) then
|
||||
printspanel:UpdatePrints(item_prints)
|
||||
end
|
||||
end
|
||||
end
|
||||
net.Receive("TTT_ShowPrints", RecvPrints)
|
||||
|
||||
local beep_success = Sound("buttons/blip2.wav")
|
||||
local function RecvScan()
|
||||
local clear = net.ReadBit() == 1
|
||||
if clear then
|
||||
RADAR.samples = {}
|
||||
RADAR.samples_count = 0
|
||||
return
|
||||
end
|
||||
|
||||
local target_pos = net.ReadVector()
|
||||
if not target_pos then return end
|
||||
|
||||
RADAR.samples = {
|
||||
{pos = target_pos}
|
||||
};
|
||||
|
||||
RADAR.samples_count = 1
|
||||
|
||||
surface.PlaySound(beep_success)
|
||||
end
|
||||
net.Receive("TTT_ScanResult", RecvScan)
|
||||
|
||||
function SWEP:ClosePrintsPanel()
|
||||
if IsValid(printspanel) then
|
||||
printspanel:Close()
|
||||
end
|
||||
end
|
||||
|
||||
else -- SERVER
|
||||
|
||||
local function ScanPrint(ply, cmd, args)
|
||||
if #args != 1 then return end
|
||||
|
||||
local tester = GetTester(ply)
|
||||
if IsValid(tester) then
|
||||
local i = tonumber(args[1])
|
||||
|
||||
if i then
|
||||
tester:PerformScan(i)
|
||||
end
|
||||
end
|
||||
end
|
||||
concommand.Add("ttt_wtester_scan", ScanPrint)
|
||||
|
||||
local function RemoveSample(ply, cmd, args)
|
||||
if #args != 1 then return end
|
||||
|
||||
local idx = tonumber(args[1])
|
||||
if not idx then return end
|
||||
|
||||
local tester = GetTester(ply)
|
||||
if IsValid(tester) then
|
||||
tester:RemoveItemSample(idx)
|
||||
end
|
||||
end
|
||||
concommand.Add("ttt_wtester_remove", RemoveSample)
|
||||
|
||||
end
|
||||
|
||||
function SWEP:OnRemove()
|
||||
if CLIENT then
|
||||
self:ClosePrintsPanel()
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:OnDrop()
|
||||
end
|
||||
|
||||
function SWEP:PreDrop()
|
||||
if IsValid(self:GetOwner()) then
|
||||
self:GetOwner().scanner_weapon = nil
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:Reload()
|
||||
return false
|
||||
end
|
||||
|
||||
function SWEP:Deploy()
|
||||
if SERVER and IsValid(self:GetOwner()) then
|
||||
self:GetOwner():DrawViewModel(false)
|
||||
self:GetOwner().scanner_weapon = self
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
if CLIENT then
|
||||
function SWEP:DrawWorldModel()
|
||||
if not IsValid(self:GetOwner()) then
|
||||
self:DrawModel()
|
||||
end
|
||||
end
|
||||
end
|
||||
594
gamemodes/terrortown/entities/weapons/weapon_tttbase.lua
Normal file
594
gamemodes/terrortown/entities/weapons/weapon_tttbase.lua
Normal file
@@ -0,0 +1,594 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
-- Custom weapon base, used to derive from CS one, still very similar
|
||||
|
||||
AddCSLuaFile()
|
||||
|
||||
---- TTT SPECIAL EQUIPMENT FIELDS
|
||||
|
||||
-- This must be set to one of the WEAPON_ types in TTT weapons for weapon
|
||||
-- carrying limits to work properly. See /gamemode/shared.lua for all possible
|
||||
-- weapon categories.
|
||||
SWEP.Kind = WEAPON_NONE
|
||||
|
||||
-- If CanBuy is a table that contains ROLE_TRAITOR and/or ROLE_DETECTIVE, those
|
||||
-- players are allowed to purchase it and it will appear in their Equipment Menu
|
||||
-- for that purpose. If CanBuy is nil this weapon cannot be bought.
|
||||
-- Example: SWEP.CanBuy = { ROLE_TRAITOR }
|
||||
-- (just setting to nil here to document its existence, don't make this buyable)
|
||||
SWEP.CanBuy = nil
|
||||
|
||||
if CLIENT then
|
||||
-- If this is a buyable weapon (ie. CanBuy is not nil) EquipMenuData must be
|
||||
-- a table containing some information to show in the Equipment Menu. See
|
||||
-- default equipment weapons for real-world examples.
|
||||
SWEP.EquipMenuData = nil
|
||||
|
||||
-- Example data:
|
||||
-- SWEP.EquipMenuData = {
|
||||
--
|
||||
---- Type tells players if it's a weapon or item
|
||||
-- type = "Weapon",
|
||||
--
|
||||
---- Desc is the description in the menu. Needs manual linebreaks (via \n).
|
||||
-- desc = "Text."
|
||||
-- };
|
||||
|
||||
-- This sets the icon shown for the weapon in the DNA sampler, search window,
|
||||
-- equipment menu (if buyable), etc.
|
||||
SWEP.Icon = "vgui/ttt/icon_nades" -- most generic icon I guess
|
||||
|
||||
-- You can make your own weapon icon using the template in:
|
||||
-- /garrysmod/gamemodes/terrortown/template/
|
||||
|
||||
-- Open one of TTT's icons with VTFEdit to see what kind of settings to use
|
||||
-- when exporting to VTF. Once you have a VTF and VMT, you can
|
||||
-- resource.AddFile("materials/vgui/...") them here. GIVE YOUR ICON A UNIQUE
|
||||
-- FILENAME, or it WILL be overwritten by other servers! Gmod does not check
|
||||
-- if the files are different, it only looks at the name. I recommend you
|
||||
-- create your own directory so that this does not happen,
|
||||
-- eg. /materials/vgui/ttt/mycoolserver/mygun.vmt
|
||||
end
|
||||
|
||||
---- MISC TTT-SPECIFIC BEHAVIOUR CONFIGURATION
|
||||
|
||||
-- ALL weapons in TTT must have weapon_tttbase as their SWEP.Base. It provides
|
||||
-- some functions that TTT expects, and you will get errors without them.
|
||||
-- Of course this is weapon_tttbase itself, so I comment this out here.
|
||||
-- SWEP.Base = "weapon_tttbase"
|
||||
|
||||
-- If true AND SWEP.Kind is not WEAPON_EQUIP, then this gun can be spawned as
|
||||
-- random weapon by a ttt_random_weapon entity.
|
||||
SWEP.AutoSpawnable = false
|
||||
|
||||
-- Set to true if weapon can be manually dropped by players (with Q)
|
||||
SWEP.AllowDrop = true
|
||||
|
||||
-- Set to true if weapon kills silently (no death scream)
|
||||
SWEP.IsSilent = false
|
||||
|
||||
-- If this weapon should be given to players upon spawning, set a table of the
|
||||
-- roles this should happen for here
|
||||
-- SWEP.InLoadoutFor = { ROLE_TRAITOR, ROLE_DETECTIVE, ROLE_INNOCENT }
|
||||
|
||||
-- DO NOT set SWEP.WeaponID. Only the standard TTT weapons can have it. Custom
|
||||
-- SWEPs do not need it for anything.
|
||||
-- SWEP.WeaponID = nil
|
||||
|
||||
---- YE OLDE SWEP STUFF
|
||||
|
||||
if CLIENT then
|
||||
SWEP.DrawCrosshair = false
|
||||
SWEP.ViewModelFOV = 82
|
||||
SWEP.ViewModelFlip = true
|
||||
SWEP.CSMuzzleFlashes = true
|
||||
end
|
||||
|
||||
SWEP.Base = "weapon_base"
|
||||
|
||||
SWEP.Category = "TTT"
|
||||
SWEP.Spawnable = false
|
||||
|
||||
SWEP.IsGrenade = false
|
||||
|
||||
SWEP.Weight = 5
|
||||
SWEP.AutoSwitchTo = false
|
||||
SWEP.AutoSwitchFrom = false
|
||||
|
||||
SWEP.Primary.Sound = Sound( "Weapon_Pistol.Empty" )
|
||||
SWEP.Primary.Recoil = 1.5
|
||||
SWEP.Primary.Damage = 1
|
||||
SWEP.Primary.NumShots = 1
|
||||
SWEP.Primary.Cone = 0.02
|
||||
SWEP.Primary.Delay = 0.15
|
||||
|
||||
SWEP.Primary.ClipSize = -1
|
||||
SWEP.Primary.DefaultClip = -1
|
||||
SWEP.Primary.Automatic = false
|
||||
SWEP.Primary.Ammo = "none"
|
||||
SWEP.Primary.ClipMax = -1
|
||||
|
||||
SWEP.Secondary.ClipSize = 1
|
||||
SWEP.Secondary.DefaultClip = 1
|
||||
SWEP.Secondary.Automatic = false
|
||||
SWEP.Secondary.Ammo = "none"
|
||||
SWEP.Secondary.ClipMax = -1
|
||||
|
||||
SWEP.HeadshotMultiplier = 2.7
|
||||
|
||||
SWEP.StoredAmmo = 0
|
||||
SWEP.IsDropped = false
|
||||
|
||||
SWEP.DeploySpeed = 1.4
|
||||
|
||||
SWEP.PrimaryAnim = ACT_VM_PRIMARYATTACK
|
||||
SWEP.ReloadAnim = ACT_VM_RELOAD
|
||||
|
||||
SWEP.fingerprints = {}
|
||||
|
||||
local sparkle = CLIENT and CreateConVar("ttt_crazy_sparks", "0", FCVAR_ARCHIVE)
|
||||
|
||||
-- crosshair
|
||||
if CLIENT then
|
||||
local sights_opacity = CreateConVar("ttt_ironsights_crosshair_opacity", "0.8", FCVAR_ARCHIVE)
|
||||
local crosshair_brightness = CreateConVar("ttt_crosshair_brightness", "1.0", FCVAR_ARCHIVE)
|
||||
local crosshair_size = CreateConVar("ttt_crosshair_size", "1.0", FCVAR_ARCHIVE)
|
||||
local disable_crosshair = CreateConVar("ttt_disable_crosshair", "0", FCVAR_ARCHIVE)
|
||||
|
||||
function SWEP:DrawHUD()
|
||||
if self.HUDHelp then
|
||||
self:DrawHelp()
|
||||
end
|
||||
|
||||
local client = LocalPlayer()
|
||||
if disable_crosshair:GetBool() or (not IsValid(client)) then return end
|
||||
|
||||
local sights = (not self.NoSights) and self:GetIronsights()
|
||||
|
||||
local x = math.floor(ScrW() / 2.0)
|
||||
local y = math.floor(ScrH() / 2.0)
|
||||
local scale = math.max(0.2, 10 * self:GetPrimaryCone())
|
||||
|
||||
local LastShootTime = self:LastShootTime()
|
||||
scale = scale * (2 - math.Clamp( (CurTime() - LastShootTime) * 5, 0.0, 1.0 ))
|
||||
|
||||
local alpha = sights and sights_opacity:GetFloat() or 1
|
||||
local bright = crosshair_brightness:GetFloat() or 1
|
||||
|
||||
-- somehow it seems this can be called before my player metatable
|
||||
-- additions have loaded
|
||||
if client.IsTraitor and client:IsTraitor() then
|
||||
surface.SetDrawColor(255 * bright,
|
||||
50 * bright,
|
||||
50 * bright,
|
||||
255 * alpha)
|
||||
else
|
||||
surface.SetDrawColor(0,
|
||||
255 * bright,
|
||||
0,
|
||||
255 * alpha)
|
||||
end
|
||||
|
||||
local gap = math.floor(20 * scale * (sights and 0.8 or 1))
|
||||
local length = math.floor(gap + (25 * crosshair_size:GetFloat()) * scale)
|
||||
surface.DrawLine( x - length, y, x - gap, y )
|
||||
surface.DrawLine( x + length, y, x + gap, y )
|
||||
surface.DrawLine( x, y - length, x, y - gap )
|
||||
surface.DrawLine( x, y + length, x, y + gap )
|
||||
end
|
||||
|
||||
local GetPTranslation = LANG.GetParamTranslation
|
||||
|
||||
-- Many non-gun weapons benefit from some help
|
||||
local help_spec = {text = "", font = "TabLarge", xalign = TEXT_ALIGN_CENTER}
|
||||
function SWEP:DrawHelp()
|
||||
local data = self.HUDHelp
|
||||
|
||||
local translate = data.translatable
|
||||
local primary = data.primary
|
||||
local secondary = data.secondary
|
||||
|
||||
if translate then
|
||||
primary = primary and GetPTranslation(primary, data.translate_params)
|
||||
secondary = secondary and GetPTranslation(secondary, data.translate_params)
|
||||
end
|
||||
|
||||
help_spec.pos = {ScrW() / 2.0, ScrH() - 40}
|
||||
help_spec.text = secondary or primary
|
||||
draw.TextShadow(help_spec, 2)
|
||||
|
||||
-- if no secondary exists, primary is drawn at the bottom and no top line
|
||||
-- is drawn
|
||||
if secondary then
|
||||
help_spec.pos[2] = ScrH() - 60
|
||||
help_spec.text = primary
|
||||
draw.TextShadow(help_spec, 2)
|
||||
end
|
||||
end
|
||||
|
||||
-- mousebuttons are enough for most weapons
|
||||
local default_key_params = {
|
||||
primaryfire = Key("+attack", "LEFT MOUSE"),
|
||||
secondaryfire = Key("+attack2", "RIGHT MOUSE"),
|
||||
usekey = Key("+use", "USE")
|
||||
};
|
||||
|
||||
function SWEP:AddHUDHelp(primary_text, secondary_text, translate, extra_params)
|
||||
extra_params = extra_params or {}
|
||||
|
||||
self.HUDHelp = {
|
||||
primary = primary_text,
|
||||
secondary = secondary_text,
|
||||
translatable = translate,
|
||||
translate_params = table.Merge(extra_params, default_key_params)
|
||||
};
|
||||
end
|
||||
end
|
||||
|
||||
-- Shooting functions largely copied from weapon_cs_base
|
||||
function SWEP:PrimaryAttack(worldsnd)
|
||||
|
||||
self:SetNextSecondaryFire( CurTime() + self.Primary.Delay )
|
||||
self:SetNextPrimaryFire( CurTime() + self.Primary.Delay )
|
||||
|
||||
if not self:CanPrimaryAttack() then return end
|
||||
|
||||
if not worldsnd then
|
||||
self:EmitSound( self.Primary.Sound, self.Primary.SoundLevel )
|
||||
elseif SERVER then
|
||||
sound.Play(self.Primary.Sound, self:GetPos(), self.Primary.SoundLevel)
|
||||
end
|
||||
|
||||
self:ShootBullet( self.Primary.Damage, self.Primary.Recoil, self.Primary.NumShots, self:GetPrimaryCone() )
|
||||
|
||||
self:TakePrimaryAmmo( 1 )
|
||||
|
||||
local owner = self:GetOwner()
|
||||
if not IsValid(owner) or owner:IsNPC() or (not owner.ViewPunch) then return end
|
||||
|
||||
owner:ViewPunch( Angle( util.SharedRandom(self:GetClass(),-0.2,-0.1,0) * self.Primary.Recoil, util.SharedRandom(self:GetClass(),-0.1,0.1,1) * self.Primary.Recoil, 0 ) )
|
||||
end
|
||||
|
||||
function SWEP:DryFire(setnext)
|
||||
if CLIENT and LocalPlayer() == self:GetOwner() then
|
||||
self:EmitSound( "Weapon_Pistol.Empty" )
|
||||
end
|
||||
|
||||
setnext(self, CurTime() + 0.2)
|
||||
|
||||
self:Reload()
|
||||
end
|
||||
|
||||
function SWEP:CanPrimaryAttack()
|
||||
if not IsValid(self:GetOwner()) then return end
|
||||
|
||||
if self:Clip1() <= 0 then
|
||||
self:DryFire(self.SetNextPrimaryFire)
|
||||
return false
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
function SWEP:CanSecondaryAttack()
|
||||
if not IsValid(self:GetOwner()) then return end
|
||||
|
||||
if self:Clip2() <= 0 then
|
||||
self:DryFire(self.SetNextSecondaryFire)
|
||||
return false
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
local function Sparklies(attacker, tr, dmginfo)
|
||||
if tr.HitWorld and tr.MatType == MAT_METAL then
|
||||
local eff = EffectData()
|
||||
eff:SetOrigin(tr.HitPos)
|
||||
eff:SetNormal(tr.HitNormal)
|
||||
util.Effect("cball_bounce", eff)
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:ShootBullet( dmg, recoil, numbul, cone )
|
||||
|
||||
self:SendWeaponAnim(self.PrimaryAnim)
|
||||
|
||||
self:GetOwner():MuzzleFlash()
|
||||
self:GetOwner():SetAnimation( PLAYER_ATTACK1 )
|
||||
|
||||
local sights = self:GetIronsights()
|
||||
|
||||
numbul = numbul or 1
|
||||
cone = cone or 0.01
|
||||
|
||||
local bullet = {}
|
||||
bullet.Num = numbul
|
||||
bullet.Src = self:GetOwner():GetShootPos()
|
||||
bullet.Dir = self:GetOwner():GetAimVector()
|
||||
bullet.Spread = Vector( cone, cone, 0 )
|
||||
bullet.Tracer = 4
|
||||
bullet.TracerName = self.Tracer or "Tracer"
|
||||
bullet.Force = 10
|
||||
bullet.Damage = dmg
|
||||
if CLIENT and sparkle:GetBool() then
|
||||
bullet.Callback = Sparklies
|
||||
end
|
||||
|
||||
self:GetOwner():FireBullets( bullet )
|
||||
|
||||
-- Owner can die after firebullets
|
||||
if (not IsValid(self:GetOwner())) or self:GetOwner():IsNPC() or (not self:GetOwner():Alive()) then return end
|
||||
|
||||
if ((game.SinglePlayer() and SERVER) or
|
||||
((not game.SinglePlayer()) and CLIENT and IsFirstTimePredicted())) then
|
||||
|
||||
-- reduce recoil if ironsighting
|
||||
recoil = sights and (recoil * 0.6) or recoil
|
||||
|
||||
local eyeang = self:GetOwner():EyeAngles()
|
||||
eyeang.pitch = eyeang.pitch - recoil
|
||||
self:GetOwner():SetEyeAngles( eyeang )
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:GetPrimaryCone()
|
||||
local cone = self.Primary.Cone or 0.2
|
||||
-- 15% accuracy bonus when sighting
|
||||
return self:GetIronsights() and (cone * 0.85) or cone
|
||||
end
|
||||
|
||||
function SWEP:GetHeadshotMultiplier(victim, dmginfo)
|
||||
return self.HeadshotMultiplier
|
||||
end
|
||||
|
||||
function SWEP:IsEquipment()
|
||||
return WEPS.IsEquipment(self)
|
||||
end
|
||||
|
||||
function SWEP:DrawWeaponSelection() end
|
||||
|
||||
function SWEP:SecondaryAttack()
|
||||
if self.NoSights or (not self.IronSightsPos) then return end
|
||||
|
||||
self:SetIronsights(not self:GetIronsights())
|
||||
|
||||
self:SetNextSecondaryFire(CurTime() + 0.3)
|
||||
end
|
||||
|
||||
function SWEP:Deploy()
|
||||
self:SetIronsights(false)
|
||||
return true
|
||||
end
|
||||
|
||||
function SWEP:Reload()
|
||||
if ( self:Clip1() == self.Primary.ClipSize or self:GetOwner():GetAmmoCount( self.Primary.Ammo ) <= 0 ) then return end
|
||||
self:DefaultReload(self.ReloadAnim)
|
||||
self:SetIronsights( false )
|
||||
end
|
||||
|
||||
|
||||
function SWEP:OnRestore()
|
||||
self.NextSecondaryAttack = 0
|
||||
self:SetIronsights( false )
|
||||
end
|
||||
|
||||
function SWEP:Ammo1()
|
||||
return IsValid(self:GetOwner()) and self:GetOwner():GetAmmoCount(self.Primary.Ammo) or false
|
||||
end
|
||||
|
||||
-- The OnDrop() hook is useless for this as it happens AFTER the drop. OwnerChange
|
||||
-- does not occur when a drop happens for some reason. Hence this thing.
|
||||
function SWEP:PreDrop()
|
||||
if SERVER and IsValid(self:GetOwner()) and self.Primary.Ammo != "none" then
|
||||
local ammo = self:Ammo1()
|
||||
|
||||
-- Do not drop ammo if we have another gun that uses this type
|
||||
for _, w in ipairs(self:GetOwner():GetWeapons()) do
|
||||
if IsValid(w) and w != self and w:GetPrimaryAmmoType() == self:GetPrimaryAmmoType() then
|
||||
ammo = 0
|
||||
end
|
||||
end
|
||||
|
||||
self.StoredAmmo = ammo
|
||||
|
||||
if ammo > 0 then
|
||||
self:GetOwner():RemoveAmmo(ammo, self.Primary.Ammo)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:DampenDrop()
|
||||
-- For some reason gmod drops guns on death at a speed of 400 units, which
|
||||
-- catapults them away from the body. Here we want people to actually be able
|
||||
-- to find a given corpse's weapon, so we override the velocity here and call
|
||||
-- this when dropping guns on death.
|
||||
local phys = self:GetPhysicsObject()
|
||||
if IsValid(phys) then
|
||||
phys:SetVelocityInstantaneous(Vector(0,0,-75) + phys:GetVelocity() * 0.001)
|
||||
phys:AddAngleVelocity(phys:GetAngleVelocity() * -0.99)
|
||||
end
|
||||
end
|
||||
|
||||
local SF_WEAPON_START_CONSTRAINED = 1
|
||||
|
||||
-- Picked up by player. Transfer of stored ammo and such.
|
||||
function SWEP:Equip(newowner)
|
||||
if SERVER then
|
||||
if self:IsOnFire() then
|
||||
self:Extinguish()
|
||||
end
|
||||
|
||||
self.fingerprints = self.fingerprints or {}
|
||||
|
||||
if not table.HasValue(self.fingerprints, newowner) then
|
||||
table.insert(self.fingerprints, newowner)
|
||||
end
|
||||
|
||||
if self:HasSpawnFlags(SF_WEAPON_START_CONSTRAINED) then
|
||||
-- If this weapon started constrained, unset that spawnflag, or the
|
||||
-- weapon will be re-constrained and float
|
||||
local flags = self:GetSpawnFlags()
|
||||
local newflags = bit.band(flags, bit.bnot(SF_WEAPON_START_CONSTRAINED))
|
||||
self:SetKeyValue("spawnflags", newflags)
|
||||
end
|
||||
end
|
||||
|
||||
if SERVER and IsValid(newowner) and self.StoredAmmo > 0 and self.Primary.Ammo != "none" then
|
||||
local ammo = newowner:GetAmmoCount(self.Primary.Ammo)
|
||||
local given = math.min(self.StoredAmmo, self.Primary.ClipMax - ammo)
|
||||
|
||||
newowner:GiveAmmo( given, self.Primary.Ammo)
|
||||
self.StoredAmmo = 0
|
||||
end
|
||||
end
|
||||
|
||||
-- We were bought as special equipment, some weapons will want to do something
|
||||
-- extra for their buyer
|
||||
function SWEP:WasBought(buyer)
|
||||
end
|
||||
|
||||
function SWEP:SetIronsights(b)
|
||||
if (b ~= self:GetIronsights()) then
|
||||
self:SetIronsightsPredicted(b)
|
||||
self:SetIronsightsTime(CurTime())
|
||||
if CLIENT then
|
||||
self:CalcViewModel()
|
||||
end
|
||||
end
|
||||
end
|
||||
function SWEP:GetIronsights()
|
||||
return self:GetIronsightsPredicted()
|
||||
end
|
||||
|
||||
--- Dummy functions that will be replaced when SetupDataTables runs. These are
|
||||
--- here for when that does not happen (due to e.g. stacking base classes)
|
||||
function SWEP:GetIronsightsTime() return -1 end
|
||||
function SWEP:SetIronsightsTime( time ) end
|
||||
function SWEP:GetIronsightsPredicted() return false end
|
||||
function SWEP:SetIronsightsPredicted( bool ) end
|
||||
|
||||
-- Set up ironsights dt bool. Weapons using their own DT vars will have to make
|
||||
-- sure they call this.
|
||||
function SWEP:SetupDataTables()
|
||||
self:NetworkVar("Bool", 3, "IronsightsPredicted")
|
||||
self:NetworkVar("Float", 3, "IronsightsTime")
|
||||
end
|
||||
|
||||
function SWEP:Initialize()
|
||||
if CLIENT and self:Clip1() == -1 then
|
||||
self:SetClip1(self.Primary.DefaultClip)
|
||||
elseif SERVER then
|
||||
self.fingerprints = {}
|
||||
|
||||
self:SetIronsights(false)
|
||||
end
|
||||
|
||||
self:SetDeploySpeed(self.DeploySpeed)
|
||||
|
||||
-- compat for gmod update
|
||||
if self.SetHoldType then
|
||||
self:SetHoldType(self.HoldType or "pistol")
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:CalcViewModel()
|
||||
if (not CLIENT) or (not IsFirstTimePredicted() and not game.SinglePlayer()) then return end
|
||||
self.bIron = self:GetIronsights()
|
||||
self.fIronTime = self:GetIronsightsTime()
|
||||
self.fCurrentTime = CurTime()
|
||||
self.fCurrentSysTime = SysTime()
|
||||
end
|
||||
|
||||
-- Note that if you override Think in your SWEP, you should call
|
||||
-- BaseClass.Think(self) so as not to break ironsights
|
||||
function SWEP:Think()
|
||||
self:CalcViewModel()
|
||||
end
|
||||
|
||||
function SWEP:DyingShot()
|
||||
local fired = false
|
||||
if self:GetIronsights() then
|
||||
self:SetIronsights(false)
|
||||
|
||||
if self:GetNextPrimaryFire() > CurTime() then
|
||||
return fired
|
||||
end
|
||||
|
||||
-- Owner should still be alive here
|
||||
if IsValid(self:GetOwner()) then
|
||||
local punch = self.Primary.Recoil or 5
|
||||
|
||||
-- Punch view to disorient aim before firing dying shot
|
||||
local eyeang = self:GetOwner():EyeAngles()
|
||||
eyeang.pitch = eyeang.pitch - math.Rand(-punch, punch)
|
||||
eyeang.yaw = eyeang.yaw - math.Rand(-punch, punch)
|
||||
self:GetOwner():SetEyeAngles( eyeang )
|
||||
|
||||
MsgN(self:GetOwner():Nick() .. " fired his DYING SHOT")
|
||||
|
||||
self:GetOwner().dying_wep = self
|
||||
|
||||
self:PrimaryAttack(true)
|
||||
|
||||
fired = true
|
||||
end
|
||||
end
|
||||
|
||||
return fired
|
||||
end
|
||||
|
||||
local ttt_lowered = CreateConVar("ttt_ironsights_lowered", "1", FCVAR_ARCHIVE)
|
||||
local host_timescale = GetConVar("host_timescale")
|
||||
|
||||
local LOWER_POS = Vector(0, 0, -2)
|
||||
|
||||
local IRONSIGHT_TIME = 0.25
|
||||
function SWEP:GetViewModelPosition( pos, ang )
|
||||
if (not self.IronSightsPos) or (self.bIron == nil) then return pos, ang end
|
||||
|
||||
local bIron = self.bIron
|
||||
local time = self.fCurrentTime + (SysTime() - self.fCurrentSysTime) * game.GetTimeScale() * host_timescale:GetFloat()
|
||||
|
||||
if bIron then
|
||||
self.SwayScale = 0.3
|
||||
self.BobScale = 0.1
|
||||
else
|
||||
self.SwayScale = 1.0
|
||||
self.BobScale = 1.0
|
||||
end
|
||||
|
||||
local fIronTime = self.fIronTime
|
||||
if (not bIron) and fIronTime < time - IRONSIGHT_TIME then
|
||||
return pos, ang
|
||||
end
|
||||
|
||||
local mul = 1.0
|
||||
|
||||
if fIronTime > time - IRONSIGHT_TIME then
|
||||
mul = math.Clamp( (time - fIronTime) / IRONSIGHT_TIME, 0, 1 )
|
||||
|
||||
if not bIron then mul = 1 - mul end
|
||||
end
|
||||
|
||||
local offset = self.IronSightsPos + (ttt_lowered:GetBool() and LOWER_POS or vector_origin)
|
||||
|
||||
if self.IronSightsAng then
|
||||
ang = ang * 1
|
||||
ang:RotateAroundAxis( ang:Right(), self.IronSightsAng.x * mul )
|
||||
ang:RotateAroundAxis( ang:Up(), self.IronSightsAng.y * mul )
|
||||
ang:RotateAroundAxis( ang:Forward(), self.IronSightsAng.z * mul )
|
||||
end
|
||||
|
||||
pos = pos + offset.x * ang:Right() * mul
|
||||
pos = pos + offset.y * ang:Forward() * mul
|
||||
pos = pos + offset.z * ang:Up() * mul
|
||||
|
||||
return pos, ang
|
||||
end
|
||||
272
gamemodes/terrortown/entities/weapons/weapon_tttbasegrenade.lua
Normal file
272
gamemodes/terrortown/entities/weapons/weapon_tttbasegrenade.lua
Normal file
@@ -0,0 +1,272 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
-- common code for all types of grenade
|
||||
|
||||
AddCSLuaFile()
|
||||
|
||||
DEFINE_BASECLASS "weapon_tttbase"
|
||||
|
||||
SWEP.HoldReady = "grenade"
|
||||
SWEP.HoldNormal = "slam"
|
||||
|
||||
if CLIENT then
|
||||
SWEP.PrintName = "Incendiary grenade"
|
||||
SWEP.Instructions = "Burn."
|
||||
SWEP.Slot = 3
|
||||
|
||||
SWEP.ViewModelFlip = true
|
||||
SWEP.DrawCrosshair = false
|
||||
|
||||
SWEP.Icon = "vgui/ttt/icon_nades"
|
||||
end
|
||||
|
||||
SWEP.Base = "weapon_tttbase"
|
||||
|
||||
SWEP.ViewModel = "models/weapons/v_eq_flashbang.mdl"
|
||||
SWEP.WorldModel = "models/weapons/w_eq_flashbang.mdl"
|
||||
|
||||
SWEP.Weight = 5
|
||||
SWEP.AutoSwitchFrom = true
|
||||
SWEP.NoSights = true
|
||||
|
||||
SWEP.Primary.ClipSize = -1
|
||||
SWEP.Primary.DefaultClip = -1
|
||||
SWEP.Primary.Automatic = false
|
||||
SWEP.Primary.Delay = 1.0
|
||||
SWEP.Primary.Ammo = "none"
|
||||
|
||||
SWEP.Secondary.ClipSize = -1
|
||||
SWEP.Secondary.DefaultClip = -1
|
||||
SWEP.Secondary.Automatic = false
|
||||
SWEP.Secondary.Ammo = "none"
|
||||
|
||||
SWEP.Kind = WEAPON_NADE
|
||||
SWEP.IsGrenade = true
|
||||
|
||||
SWEP.was_thrown = false
|
||||
SWEP.detonate_timer = 5
|
||||
SWEP.DeploySpeed = 1.5
|
||||
|
||||
AccessorFunc(SWEP, "det_time", "DetTime")
|
||||
|
||||
CreateConVar("ttt_no_nade_throw_during_prep", "1")
|
||||
|
||||
function SWEP:SetupDataTables()
|
||||
self:NetworkVar("Bool", 0, "Pin")
|
||||
self:NetworkVar("Int", 0, "ThrowTime")
|
||||
end
|
||||
|
||||
function SWEP:PrimaryAttack()
|
||||
self:SetNextPrimaryFire(CurTime() + self.Primary.Delay)
|
||||
|
||||
if GetRoundState() == ROUND_PREP and GetConVar("ttt_no_nade_throw_during_prep"):GetBool() then
|
||||
return
|
||||
end
|
||||
|
||||
self:PullPin()
|
||||
end
|
||||
|
||||
function SWEP:SecondaryAttack()
|
||||
end
|
||||
|
||||
function SWEP:PullPin()
|
||||
if self:GetPin() then return end
|
||||
|
||||
local ply = self:GetOwner()
|
||||
if not IsValid(ply) then return end
|
||||
|
||||
self:SendWeaponAnim(ACT_VM_PULLPIN)
|
||||
|
||||
if self.SetHoldType then
|
||||
self:SetHoldType(self.HoldReady)
|
||||
end
|
||||
|
||||
self:SetPin(true)
|
||||
|
||||
self:SetDetTime(CurTime() + self.detonate_timer)
|
||||
end
|
||||
|
||||
|
||||
function SWEP:Think()
|
||||
BaseClass.Think(self)
|
||||
local ply = self:GetOwner()
|
||||
if not IsValid(ply) then return end
|
||||
|
||||
-- pin pulled and attack loose = throw
|
||||
if self:GetPin() then
|
||||
-- we will throw now
|
||||
if not ply:KeyDown(IN_ATTACK) then
|
||||
self:StartThrow()
|
||||
|
||||
self:SetPin(false)
|
||||
self:SendWeaponAnim(ACT_VM_THROW)
|
||||
|
||||
if SERVER then
|
||||
self:GetOwner():SetAnimation( PLAYER_ATTACK1 )
|
||||
end
|
||||
else
|
||||
-- still cooking it, see if our time is up
|
||||
if SERVER and self:GetDetTime() < CurTime() then
|
||||
self:BlowInFace()
|
||||
end
|
||||
end
|
||||
elseif self:GetThrowTime() > 0 and self:GetThrowTime() < CurTime() then
|
||||
self:Throw()
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function SWEP:BlowInFace()
|
||||
local ply = self:GetOwner()
|
||||
if not IsValid(ply) then return end
|
||||
|
||||
if self.was_thrown then return end
|
||||
|
||||
self.was_thrown = true
|
||||
|
||||
-- drop the grenade so it can immediately explode
|
||||
|
||||
local ang = ply:GetAngles()
|
||||
local src = ply:GetPos() + (ply:Crouching() and ply:GetViewOffsetDucked() or ply:GetViewOffset())
|
||||
src = src + (ang:Right() * 10)
|
||||
|
||||
self:CreateGrenade(src, Angle(0,0,0), Vector(0,0,1), Vector(0,0,1), ply)
|
||||
|
||||
self:SetThrowTime(0)
|
||||
self:Remove()
|
||||
end
|
||||
|
||||
function SWEP:StartThrow()
|
||||
self:SetThrowTime(CurTime() + 0.1)
|
||||
end
|
||||
|
||||
function SWEP:Throw()
|
||||
if CLIENT then
|
||||
self:SetThrowTime(0)
|
||||
elseif SERVER then
|
||||
local ply = self:GetOwner()
|
||||
if not IsValid(ply) then return end
|
||||
|
||||
if self.was_thrown then return end
|
||||
|
||||
self.was_thrown = true
|
||||
|
||||
local ang = ply:EyeAngles()
|
||||
local src = ply:GetPos() + (ply:Crouching() and ply:GetViewOffsetDucked() or ply:GetViewOffset())+ (ang:Forward() * 8) + (ang:Right() * 10)
|
||||
local target = ply:GetEyeTraceNoCursor().HitPos
|
||||
local tang = (target-src):Angle() -- A target angle to actually throw the grenade to the crosshair instead of fowards
|
||||
-- Makes the grenade go upgwards
|
||||
if tang.p < 90 then
|
||||
tang.p = -10 + tang.p * ((90 + 10) / 90)
|
||||
else
|
||||
tang.p = 360 - tang.p
|
||||
tang.p = -10 + tang.p * -((90 + 10) / 90)
|
||||
end
|
||||
tang.p=math.Clamp(tang.p,-90,90) -- Makes the grenade not go backwards :/
|
||||
local vel = math.min(800, (90 - tang.p) * 6)
|
||||
local thr = tang:Forward() * vel + ply:GetVelocity()
|
||||
self:CreateGrenade(src, Angle(0,0,0), thr, Vector(600, math.random(-1200, 1200), 0), ply)
|
||||
|
||||
self:SetThrowTime(0)
|
||||
self:Remove()
|
||||
end
|
||||
end
|
||||
|
||||
-- subclasses must override with their own grenade ent
|
||||
function SWEP:GetGrenadeName()
|
||||
ErrorNoHalt("SWEP BASEGRENADE ERROR: GetGrenadeName not overridden! This is probably wrong!\n")
|
||||
return "ttt_firegrenade_proj"
|
||||
end
|
||||
|
||||
|
||||
function SWEP:CreateGrenade(src, ang, vel, angimp, ply)
|
||||
local gren = ents.Create(self:GetGrenadeName())
|
||||
if not IsValid(gren) then return end
|
||||
|
||||
gren:SetPos(src)
|
||||
gren:SetAngles(ang)
|
||||
|
||||
-- gren:SetVelocity(vel)
|
||||
gren:SetOwner(ply)
|
||||
gren:SetThrower(ply)
|
||||
|
||||
gren:SetGravity(0.4)
|
||||
gren:SetFriction(0.2)
|
||||
gren:SetElasticity(0.45)
|
||||
|
||||
gren:Spawn()
|
||||
|
||||
gren:PhysWake()
|
||||
|
||||
local phys = gren:GetPhysicsObject()
|
||||
if IsValid(phys) then
|
||||
phys:SetVelocity(vel)
|
||||
phys:AddAngleVelocity(angimp)
|
||||
end
|
||||
|
||||
-- This has to happen AFTER Spawn() calls gren's Initialize()
|
||||
gren:SetDetonateExact(self:GetDetTime())
|
||||
|
||||
return gren
|
||||
end
|
||||
|
||||
function SWEP:PreDrop()
|
||||
-- if owner dies or drops us while the pin has been pulled, create the armed
|
||||
-- grenade anyway
|
||||
if self:GetPin() then
|
||||
self:BlowInFace()
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:Deploy()
|
||||
|
||||
if self.SetHoldType then
|
||||
self:SetHoldType(self.HoldNormal)
|
||||
end
|
||||
|
||||
self:SetThrowTime(0)
|
||||
self:SetPin(false)
|
||||
return true
|
||||
end
|
||||
|
||||
function SWEP:Holster()
|
||||
if self:GetPin() then
|
||||
return false -- no switching after pulling pin
|
||||
end
|
||||
|
||||
self:SetThrowTime(0)
|
||||
self:SetPin(false)
|
||||
return true
|
||||
end
|
||||
|
||||
function SWEP:Reload()
|
||||
return false
|
||||
end
|
||||
|
||||
function SWEP:Initialize()
|
||||
if self.SetHoldType then
|
||||
self:SetHoldType(self.HoldNormal)
|
||||
end
|
||||
|
||||
self:SetDeploySpeed(self.DeploySpeed)
|
||||
|
||||
self:SetDetTime(0)
|
||||
self:SetThrowTime(0)
|
||||
self:SetPin(false)
|
||||
|
||||
self.was_thrown = false
|
||||
end
|
||||
|
||||
function SWEP:OnRemove()
|
||||
if CLIENT and IsValid(self:GetOwner()) and self:GetOwner() == LocalPlayer() and self:GetOwner():Alive() then
|
||||
RunConsoleCommand("use", "weapon_ttt_unarmed")
|
||||
end
|
||||
end
|
||||
609
gamemodes/terrortown/entities/weapons/weapon_zm_carry.lua
Normal file
609
gamemodes/terrortown/entities/weapons/weapon_zm_carry.lua
Normal file
@@ -0,0 +1,609 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
---- Carry weapon SWEP
|
||||
|
||||
AddCSLuaFile()
|
||||
|
||||
DEFINE_BASECLASS "weapon_tttbase"
|
||||
|
||||
SWEP.HoldType = "pistol"
|
||||
|
||||
if CLIENT then
|
||||
SWEP.PrintName = "magnet_name"
|
||||
SWEP.Slot = 4
|
||||
|
||||
SWEP.DrawCrosshair = false
|
||||
SWEP.ViewModelFlip = false
|
||||
end
|
||||
|
||||
SWEP.Base = "weapon_tttbase"
|
||||
|
||||
SWEP.AutoSpawnable = false
|
||||
|
||||
SWEP.ViewModel = Model("models/weapons/v_stunbaton.mdl")
|
||||
SWEP.WorldModel = Model("models/weapons/w_stunbaton.mdl")
|
||||
|
||||
SWEP.Primary.ClipSize = -1
|
||||
SWEP.Primary.DefaultClip = -1
|
||||
SWEP.Primary.Automatic = true
|
||||
SWEP.Primary.Ammo = "none"
|
||||
SWEP.Primary.Delay = 0.1
|
||||
|
||||
SWEP.Secondary.ClipSize = -1
|
||||
SWEP.Secondary.DefaultClip = -1
|
||||
SWEP.Secondary.Automatic = true
|
||||
SWEP.Secondary.Ammo = "none"
|
||||
SWEP.Secondary.Delay = 0.1
|
||||
|
||||
SWEP.Kind = WEAPON_CARRY
|
||||
SWEP.InLoadoutFor = {ROLE_INNOCENT, ROLE_TRAITOR, ROLE_DETECTIVE}
|
||||
|
||||
SWEP.AllowDelete = false
|
||||
SWEP.AllowDrop = false
|
||||
SWEP.NoSights = true
|
||||
|
||||
SWEP.EntHolding = nil
|
||||
SWEP.CarryHack = nil
|
||||
SWEP.Constr = nil
|
||||
SWEP.PrevOwner = nil
|
||||
|
||||
local allow_rag = CreateConVar("ttt_ragdoll_carrying", "1")
|
||||
local prop_force = CreateConVar("ttt_prop_carrying_force", "60000")
|
||||
local no_throw = CreateConVar("ttt_no_prop_throwing", "0")
|
||||
local pin_rag = CreateConVar("ttt_ragdoll_pinning", "1")
|
||||
local pin_rag_inno = CreateConVar("ttt_ragdoll_pinning_innocents", "0")
|
||||
|
||||
-- Allowing weapon pickups can allow players to cause a crash in the physics
|
||||
-- system (ie. not fixable). Tuning the range seems to make this more
|
||||
-- difficult. Not sure why. It's that kind of crash.
|
||||
local allow_wep = CreateConVar("ttt_weapon_carrying", "0")
|
||||
local wep_range = CreateConVar("ttt_weapon_carrying_range", "50")
|
||||
|
||||
-- not customizable via convars as some objects rely on not being carryable for
|
||||
-- gameplay purposes
|
||||
CARRY_WEIGHT_LIMIT = 45
|
||||
|
||||
local PIN_RAG_RANGE = 90
|
||||
|
||||
local player = player
|
||||
local IsValid = IsValid
|
||||
local CurTime = CurTime
|
||||
|
||||
|
||||
local function SetSubPhysMotionEnabled(ent, enable)
|
||||
if not IsValid(ent) then return end
|
||||
|
||||
for i=0, ent:GetPhysicsObjectCount()-1 do
|
||||
local subphys = ent:GetPhysicsObjectNum(i)
|
||||
if IsValid(subphys) then
|
||||
subphys:EnableMotion(enable)
|
||||
if enable then
|
||||
subphys:Wake()
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function KillVelocity(ent)
|
||||
ent:SetVelocity(vector_origin)
|
||||
|
||||
-- The only truly effective way to prevent all kinds of velocity and
|
||||
-- inertia is motion disabling the entire ragdoll for a tick
|
||||
-- for non-ragdolls this will do the same for their single physobj
|
||||
SetSubPhysMotionEnabled(ent, false)
|
||||
|
||||
timer.Simple(0, function() SetSubPhysMotionEnabled(ent, true) end)
|
||||
end
|
||||
|
||||
function SWEP:Reset(keep_velocity)
|
||||
if IsValid(self.CarryHack) then
|
||||
self.CarryHack:Remove()
|
||||
end
|
||||
|
||||
if IsValid(self.Constr) then
|
||||
self.Constr:Remove()
|
||||
end
|
||||
|
||||
if IsValid(self.EntHolding) then
|
||||
-- it is possible for weapons to be already equipped at this point
|
||||
-- changing the owner in such a case would cause problems
|
||||
if not self.EntHolding:IsWeapon() then
|
||||
if not IsValid(self.PrevOwner) then
|
||||
self.EntHolding:SetOwner(nil)
|
||||
else
|
||||
self.EntHolding:SetOwner(self.PrevOwner)
|
||||
end
|
||||
end
|
||||
|
||||
-- the below ought to be unified with self:Drop()
|
||||
local phys = self.EntHolding:GetPhysicsObject()
|
||||
if IsValid(phys) then
|
||||
phys:ClearGameFlag(FVPHYSICS_PLAYER_HELD)
|
||||
phys:AddGameFlag(FVPHYSICS_WAS_THROWN)
|
||||
phys:EnableCollisions(true)
|
||||
phys:EnableGravity(true)
|
||||
phys:EnableDrag(true)
|
||||
phys:EnableMotion(true)
|
||||
end
|
||||
|
||||
if (not keep_velocity) and (no_throw:GetBool() or self.EntHolding:GetClass() == "prop_ragdoll") then
|
||||
KillVelocity(self.EntHolding)
|
||||
end
|
||||
end
|
||||
|
||||
self.dt.carried_rag = nil
|
||||
|
||||
self.EntHolding = nil
|
||||
self.CarryHack = nil
|
||||
self.Constr = nil
|
||||
end
|
||||
SWEP.reset = SWEP.Reset
|
||||
|
||||
function SWEP:CheckValidity()
|
||||
|
||||
if (not IsValid(self.EntHolding)) or (not IsValid(self.CarryHack)) or (not IsValid(self.Constr)) then
|
||||
|
||||
-- if one of them is not valid but another is non-nil...
|
||||
if (self.EntHolding or self.CarryHack or self.Constr) then
|
||||
self:Reset()
|
||||
end
|
||||
|
||||
return false
|
||||
else
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
local function PlayerStandsOn(ent)
|
||||
for _, ply in player.Iterator() do
|
||||
if ply:GetGroundEntity() == ent and ply:IsTerror() then
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
if SERVER then
|
||||
|
||||
local ent_diff = vector_origin
|
||||
local ent_diff_time = CurTime()
|
||||
|
||||
local stand_time = 0
|
||||
function SWEP:Think()
|
||||
BaseClass.Think(self)
|
||||
if not self:CheckValidity() then return end
|
||||
|
||||
-- If we are too far from our object, force a drop. To avoid doing this
|
||||
-- vector math extremely often (esp. when everyone is carrying something)
|
||||
-- even though the occurrence is very rare, limited to once per
|
||||
-- second. This should be plenty to catch the rare glitcher.
|
||||
if CurTime() > ent_diff_time then
|
||||
ent_diff = self:GetPos() - self.EntHolding:GetPos()
|
||||
if ent_diff:Dot(ent_diff) > 40000 then
|
||||
self:Reset()
|
||||
return
|
||||
end
|
||||
|
||||
ent_diff_time = CurTime() + 1
|
||||
end
|
||||
|
||||
if CurTime() > stand_time then
|
||||
|
||||
if PlayerStandsOn(self.EntHolding) then
|
||||
self:Reset()
|
||||
return
|
||||
end
|
||||
|
||||
stand_time = CurTime() + 0.1
|
||||
end
|
||||
|
||||
self.CarryHack:SetPos(self:GetOwner():EyePos() + self:GetOwner():GetAimVector() * 70)
|
||||
|
||||
self.CarryHack:SetAngles(self:GetOwner():GetAngles())
|
||||
|
||||
self.EntHolding:PhysWake()
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function SWEP:PrimaryAttack()
|
||||
self:DoAttack(false)
|
||||
end
|
||||
|
||||
function SWEP:SecondaryAttack()
|
||||
self:DoAttack(true)
|
||||
end
|
||||
|
||||
function SWEP:MoveObject(phys, pdir, maxforce, is_ragdoll)
|
||||
if not IsValid(phys) then return end
|
||||
local speed = phys:GetVelocity():Length()
|
||||
|
||||
-- remap speed from 0 -> 125 to force 1 -> 4000
|
||||
local force = maxforce + (1 - maxforce) * (speed / 125)
|
||||
|
||||
if is_ragdoll then
|
||||
force = force * 2
|
||||
end
|
||||
|
||||
pdir = pdir * force
|
||||
|
||||
local mass = phys:GetMass()
|
||||
-- scale more for light objects
|
||||
if mass < 50 then
|
||||
pdir = pdir * (mass + 0.5) * (1 / 50)
|
||||
end
|
||||
|
||||
phys:ApplyForceCenter(pdir)
|
||||
end
|
||||
|
||||
function SWEP:GetRange(target)
|
||||
if IsValid(target) and target:IsWeapon() and allow_wep:GetBool() then
|
||||
return wep_range:GetFloat()
|
||||
elseif IsValid(target) and target:GetClass() == "prop_ragdoll" then
|
||||
return 75
|
||||
else
|
||||
return 100
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:AllowPickup(target)
|
||||
local phys = target:GetPhysicsObject()
|
||||
local ply = self:GetOwner()
|
||||
|
||||
return (IsValid(phys) and IsValid(ply) and
|
||||
(not phys:HasGameFlag(FVPHYSICS_NO_PLAYER_PICKUP)) and
|
||||
phys:GetMass() < CARRY_WEIGHT_LIMIT and
|
||||
(not PlayerStandsOn(target)) and
|
||||
(target.CanPickup != false) and
|
||||
(target:GetClass() != "prop_ragdoll" or allow_rag:GetBool()) and
|
||||
((not target:IsWeapon()) or allow_wep:GetBool()))
|
||||
end
|
||||
|
||||
function SWEP:DoAttack(pickup)
|
||||
self:SetNextPrimaryFire( CurTime() + self.Primary.Delay )
|
||||
self:SetNextSecondaryFire( CurTime() + self.Secondary.Delay )
|
||||
|
||||
if IsValid(self.EntHolding) then
|
||||
self:SendWeaponAnim( ACT_VM_MISSCENTER )
|
||||
|
||||
if (not pickup) and self.EntHolding:GetClass() == "prop_ragdoll" then
|
||||
-- see if we can pin this ragdoll to a wall in front of us
|
||||
if not self:PinRagdoll() then
|
||||
-- else just drop it as usual
|
||||
self:Drop()
|
||||
end
|
||||
else
|
||||
self:Drop()
|
||||
end
|
||||
|
||||
self:SetNextSecondaryFire(CurTime() + 0.3)
|
||||
return
|
||||
end
|
||||
|
||||
local ply = self:GetOwner()
|
||||
|
||||
local trace = ply:GetEyeTrace(MASK_SHOT)
|
||||
if IsValid(trace.Entity) then
|
||||
local ent = trace.Entity
|
||||
local phys = trace.Entity:GetPhysicsObject()
|
||||
|
||||
if not IsValid(phys) or not phys:IsMoveable() or phys:HasGameFlag(FVPHYSICS_PLAYER_HELD) then
|
||||
return
|
||||
end
|
||||
|
||||
-- if we let the client mess with physics, desync ensues
|
||||
if CLIENT then return end
|
||||
|
||||
if pickup then
|
||||
if (ply:EyePos() - trace.HitPos):Length() < self:GetRange(ent) then
|
||||
|
||||
if self:AllowPickup(ent) then
|
||||
self:Pickup()
|
||||
self:SendWeaponAnim( ACT_VM_HITCENTER )
|
||||
|
||||
-- make the refire slower to avoid immediately dropping
|
||||
local delay = (ent:GetClass() == "prop_ragdoll") and 0.8 or 0.5
|
||||
|
||||
self:SetNextSecondaryFire(CurTime() + delay)
|
||||
return
|
||||
else
|
||||
local is_ragdoll = trace.Entity:GetClass() == "prop_ragdoll"
|
||||
|
||||
-- pull heavy stuff
|
||||
local ent = trace.Entity
|
||||
local phys = ent:GetPhysicsObject()
|
||||
local pdir = trace.Normal * -1
|
||||
|
||||
if is_ragdoll then
|
||||
|
||||
phys = ent:GetPhysicsObjectNum(trace.PhysicsBone)
|
||||
|
||||
-- increase refire to make rags easier to drag
|
||||
--self:SetNextSecondaryFire(CurTime() + 0.04)
|
||||
end
|
||||
|
||||
if IsValid(phys) then
|
||||
self:MoveObject(phys, pdir, 6000, is_ragdoll)
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
if (ply:EyePos() - trace.HitPos):Length() < 100 then
|
||||
local phys = trace.Entity:GetPhysicsObject()
|
||||
if IsValid(phys) then
|
||||
if IsValid(phys) then
|
||||
local pdir = trace.Normal
|
||||
self:MoveObject(phys, pdir, 6000, (trace.Entity:GetClass() == "prop_ragdoll"))
|
||||
|
||||
self:SetNextPrimaryFire(CurTime() + 0.03)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Perform a pickup
|
||||
function SWEP:Pickup()
|
||||
if CLIENT or IsValid(self.EntHolding) then return end
|
||||
|
||||
local ply = self:GetOwner()
|
||||
local trace = ply:GetEyeTrace(MASK_SHOT)
|
||||
local ent = trace.Entity
|
||||
self.EntHolding = ent
|
||||
local entphys = ent:GetPhysicsObject()
|
||||
|
||||
|
||||
if IsValid(ent) and IsValid(entphys) then
|
||||
|
||||
self.CarryHack = ents.Create("prop_physics")
|
||||
if IsValid(self.CarryHack) then
|
||||
self.CarryHack:SetPos(self.EntHolding:GetPos())
|
||||
|
||||
self.CarryHack:SetModel("models/weapons/w_bugbait.mdl")
|
||||
|
||||
self.CarryHack:SetColor(Color(50, 250, 50, 240))
|
||||
self.CarryHack:SetNoDraw(true)
|
||||
self.CarryHack:DrawShadow(false)
|
||||
|
||||
self.CarryHack:SetHealth(999)
|
||||
self.CarryHack:SetOwner(ply)
|
||||
self.CarryHack:SetCollisionGroup(COLLISION_GROUP_DEBRIS)
|
||||
self.CarryHack:SetSolid(SOLID_NONE)
|
||||
|
||||
-- set the desired angles before adding the constraint
|
||||
self.CarryHack:SetAngles(self:GetOwner():GetAngles())
|
||||
|
||||
self.CarryHack:Spawn()
|
||||
|
||||
-- if we already are owner before pickup, we will not want to disown
|
||||
-- this entity when we drop it
|
||||
-- weapons should not have their owner changed in this way
|
||||
if not self.EntHolding:IsWeapon() then
|
||||
self.PrevOwner = self.EntHolding:GetOwner()
|
||||
|
||||
self.EntHolding:SetOwner(ply)
|
||||
end
|
||||
|
||||
local phys = self.CarryHack:GetPhysicsObject()
|
||||
if IsValid(phys) then
|
||||
phys:SetMass(200)
|
||||
phys:SetDamping(0, 1000)
|
||||
phys:EnableGravity(false)
|
||||
phys:EnableCollisions(false)
|
||||
phys:EnableMotion(false)
|
||||
phys:AddGameFlag(FVPHYSICS_PLAYER_HELD)
|
||||
end
|
||||
|
||||
entphys:AddGameFlag(FVPHYSICS_PLAYER_HELD)
|
||||
local bone = math.Clamp(trace.PhysicsBone, 0, 1)
|
||||
local max_force = prop_force:GetInt()
|
||||
|
||||
if ent:GetClass() == "prop_ragdoll" then
|
||||
self.dt.carried_rag = ent
|
||||
|
||||
bone = trace.PhysicsBone
|
||||
max_force = 0
|
||||
else
|
||||
self.dt.carried_rag = nil
|
||||
end
|
||||
|
||||
self.Constr = constraint.Weld(self.CarryHack, self.EntHolding, 0, bone, max_force, true)
|
||||
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local down = Vector(0, 0, -1)
|
||||
function SWEP:AllowEntityDrop()
|
||||
local ply = self:GetOwner()
|
||||
local ent = self.CarryHack
|
||||
if (not IsValid(ply)) or (not IsValid(ent)) then return false end
|
||||
|
||||
local ground = ply:GetGroundEntity()
|
||||
if ground and (ground:IsWorld() or IsValid(ground)) then return true end
|
||||
|
||||
local diff = (ent:GetPos() - ply:GetShootPos()):GetNormalized()
|
||||
|
||||
return down:Dot(diff) <= 0.75
|
||||
end
|
||||
|
||||
function SWEP:Drop()
|
||||
if not self:CheckValidity() then return end
|
||||
if not self:AllowEntityDrop() then return end
|
||||
|
||||
if SERVER then
|
||||
self.Constr:Remove()
|
||||
self.CarryHack:Remove()
|
||||
|
||||
local ent = self.EntHolding
|
||||
|
||||
local phys = ent:GetPhysicsObject()
|
||||
if IsValid(phys) then
|
||||
phys:EnableCollisions(true)
|
||||
phys:EnableGravity(true)
|
||||
phys:EnableDrag(true)
|
||||
phys:EnableMotion(true)
|
||||
phys:Wake()
|
||||
phys:ApplyForceCenter(self:GetOwner():GetAimVector() * 500)
|
||||
|
||||
phys:ClearGameFlag(FVPHYSICS_PLAYER_HELD)
|
||||
phys:AddGameFlag(FVPHYSICS_WAS_THROWN)
|
||||
end
|
||||
|
||||
-- Try to limit ragdoll slinging
|
||||
if no_throw:GetBool() or ent:GetClass() == "prop_ragdoll" then
|
||||
KillVelocity(ent)
|
||||
end
|
||||
|
||||
ent:SetPhysicsAttacker(self:GetOwner())
|
||||
|
||||
end
|
||||
|
||||
self:Reset()
|
||||
end
|
||||
|
||||
local CONSTRAINT_TYPE = "Rope"
|
||||
|
||||
local function RagdollPinnedTakeDamage(rag, dmginfo)
|
||||
local att = dmginfo:GetAttacker()
|
||||
if not IsValid(att) then return end
|
||||
|
||||
-- drop from pinned position upon dmg
|
||||
constraint.RemoveConstraints(rag, CONSTRAINT_TYPE)
|
||||
rag:PhysWake()
|
||||
|
||||
rag:SetHealth(0)
|
||||
rag.is_pinned = false
|
||||
end
|
||||
|
||||
function SWEP:PinRagdoll()
|
||||
if not pin_rag:GetBool() then return end
|
||||
if (not self:GetOwner():IsTraitor()) and (not pin_rag_inno:GetBool()) then return end
|
||||
|
||||
local rag = self.EntHolding
|
||||
local ply = self:GetOwner()
|
||||
|
||||
local tr = util.TraceLine({start = ply:EyePos(),
|
||||
endpos = ply:EyePos() + (ply:GetAimVector() * PIN_RAG_RANGE),
|
||||
filter = {ply, self, rag, self.CarryHack},
|
||||
mask = MASK_SOLID})
|
||||
|
||||
if tr.HitWorld and (not tr.HitSky) then
|
||||
|
||||
-- find bone we're holding the ragdoll by
|
||||
local bone = self.Constr.Bone2
|
||||
|
||||
-- only allow one rope per bone
|
||||
for _, c in pairs(constraint.FindConstraints(rag, CONSTRAINT_TYPE)) do
|
||||
if c.Bone1 == bone then
|
||||
c.Constraint:Remove()
|
||||
end
|
||||
end
|
||||
|
||||
local bonephys = rag:GetPhysicsObjectNum(bone)
|
||||
if not IsValid(bonephys) then return end
|
||||
|
||||
local bonepos = bonephys:GetPos()
|
||||
local attachpos = tr.HitPos
|
||||
local length = (bonepos - attachpos):Length() * 0.9
|
||||
|
||||
-- we need to convert using this particular physobj to get the right
|
||||
-- coordinates
|
||||
bonepos = bonephys:WorldToLocal(bonepos)
|
||||
|
||||
constraint.Rope(rag, tr.Entity, bone, 0, bonepos, attachpos,
|
||||
length, length * 0.1, 6000,
|
||||
1, "cable/rope", false)
|
||||
|
||||
rag.is_pinned = true
|
||||
rag.OnPinnedDamage = RagdollPinnedTakeDamage
|
||||
|
||||
-- lets EntityTakeDamage run for the ragdoll
|
||||
rag:SetHealth(999999)
|
||||
|
||||
self:Reset(true)
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:SetupDataTables()
|
||||
-- we've got these dt slots anyway, might as well use them instead of a
|
||||
-- globalvar, probably cheaper
|
||||
self:DTVar("Bool", 0, "can_rag_pin")
|
||||
self:DTVar("Bool", 1, "can_rag_pin_inno")
|
||||
|
||||
-- client actually has no idea what we're holding, and almost never needs to
|
||||
-- know
|
||||
self:DTVar("Entity", 0, "carried_rag")
|
||||
return self.BaseClass.SetupDataTables(self)
|
||||
end
|
||||
|
||||
if SERVER then
|
||||
function SWEP:Initialize()
|
||||
self.dt.can_rag_pin = pin_rag:GetBool()
|
||||
self.dt.can_rag_pin_inno = pin_rag_inno:GetBool()
|
||||
self.dt.carried_rag = nil
|
||||
|
||||
return self.BaseClass.Initialize(self)
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:OnRemove()
|
||||
self:Reset()
|
||||
end
|
||||
|
||||
function SWEP:Deploy()
|
||||
self:Reset()
|
||||
return true
|
||||
end
|
||||
|
||||
function SWEP:Holster()
|
||||
self:Reset()
|
||||
return true
|
||||
end
|
||||
|
||||
|
||||
function SWEP:ShouldDropOnDie()
|
||||
return false
|
||||
end
|
||||
|
||||
function SWEP:OnDrop()
|
||||
self:Remove()
|
||||
end
|
||||
|
||||
if CLIENT then
|
||||
local draw = draw
|
||||
local util = util
|
||||
|
||||
local PT = LANG.GetParamTranslation
|
||||
local key_params = {primaryfire = Key("+attack", "LEFT MOUSE")}
|
||||
function SWEP:DrawHUD()
|
||||
self.BaseClass.DrawHUD(self)
|
||||
|
||||
if self.dt.can_rag_pin and IsValid(self.dt.carried_rag) then
|
||||
local client = LocalPlayer()
|
||||
|
||||
if not client:IsSpec() and (self.dt.can_rag_pin_inno or client:IsTraitor()) then
|
||||
local tr = util.TraceLine({start = client:EyePos(),
|
||||
endpos = client:EyePos() + (client:GetAimVector() * PIN_RAG_RANGE),
|
||||
filter = {client, self, self.dt.carried_rag},
|
||||
mask = MASK_SOLID})
|
||||
|
||||
if tr.HitWorld and (not tr.HitSky) then
|
||||
draw.SimpleText(PT("magnet_help", key_params), "TabLarge", ScrW() / 2, ScrH() / 2 - 50, COLOR_RED, TEXT_ALIGN_CENTER)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
272
gamemodes/terrortown/entities/weapons/weapon_zm_improvised.lua
Normal file
272
gamemodes/terrortown/entities/weapons/weapon_zm_improvised.lua
Normal file
@@ -0,0 +1,272 @@
|
||||
--[[
|
||||
| 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()
|
||||
|
||||
SWEP.HoldType = "melee"
|
||||
|
||||
if CLIENT then
|
||||
SWEP.PrintName = "crowbar_name"
|
||||
SWEP.Slot = 0
|
||||
|
||||
SWEP.DrawCrosshair = false
|
||||
SWEP.ViewModelFlip = false
|
||||
SWEP.ViewModelFOV = 54
|
||||
|
||||
SWEP.Icon = "vgui/ttt/icon_cbar"
|
||||
end
|
||||
|
||||
SWEP.Base = "weapon_tttbase"
|
||||
|
||||
SWEP.UseHands = true
|
||||
SWEP.ViewModel = "models/weapons/c_crowbar.mdl"
|
||||
SWEP.WorldModel = "models/weapons/w_crowbar.mdl"
|
||||
|
||||
SWEP.Primary.Damage = 20
|
||||
SWEP.Primary.ClipSize = -1
|
||||
SWEP.Primary.DefaultClip = -1
|
||||
SWEP.Primary.Automatic = true
|
||||
SWEP.Primary.Delay = 0.5
|
||||
SWEP.Primary.Ammo = "none"
|
||||
|
||||
SWEP.Secondary.ClipSize = -1
|
||||
SWEP.Secondary.DefaultClip = -1
|
||||
SWEP.Secondary.Automatic = true
|
||||
SWEP.Secondary.Ammo = "none"
|
||||
SWEP.Secondary.Delay = 5
|
||||
|
||||
SWEP.Kind = WEAPON_MELEE
|
||||
SWEP.WeaponID = AMMO_CROWBAR
|
||||
SWEP.InLoadoutFor = {ROLE_INNOCENT, ROLE_TRAITOR, ROLE_DETECTIVE}
|
||||
|
||||
SWEP.NoSights = true
|
||||
SWEP.IsSilent = true
|
||||
|
||||
SWEP.Weight = 5
|
||||
SWEP.AutoSpawnable = false
|
||||
|
||||
SWEP.AllowDelete = false -- never removed for weapon reduction
|
||||
SWEP.AllowDrop = false
|
||||
|
||||
local sound_single = Sound("Weapon_Crowbar.Single")
|
||||
local sound_open = Sound("DoorHandles.Unlocked3")
|
||||
|
||||
if SERVER then
|
||||
CreateConVar("ttt_crowbar_unlocks", "1", FCVAR_ARCHIVE)
|
||||
CreateConVar("ttt_crowbar_pushforce", "395", FCVAR_NOTIFY)
|
||||
end
|
||||
|
||||
-- only open things that have a name (and are therefore likely to be meant to
|
||||
-- open) and are the right class. Opening behaviour also differs per class, so
|
||||
-- return one of the OPEN_ values
|
||||
local function OpenableEnt(ent)
|
||||
local cls = ent:GetClass()
|
||||
if ent:GetName() == "" then
|
||||
return OPEN_NO
|
||||
elseif cls == "prop_door_rotating" then
|
||||
return OPEN_ROT
|
||||
elseif cls == "func_door" or cls == "func_door_rotating" then
|
||||
return OPEN_DOOR
|
||||
elseif cls == "func_button" then
|
||||
return OPEN_BUT
|
||||
elseif cls == "func_movelinear" then
|
||||
return OPEN_NOTOGGLE
|
||||
else
|
||||
return OPEN_NO
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local function CrowbarCanUnlock(t)
|
||||
return not GAMEMODE.crowbar_unlocks or GAMEMODE.crowbar_unlocks[t]
|
||||
end
|
||||
|
||||
-- will open door AND return what it did
|
||||
function SWEP:OpenEnt(hitEnt)
|
||||
-- Get ready for some prototype-quality code, all ye who read this
|
||||
if SERVER and GetConVar("ttt_crowbar_unlocks"):GetBool() then
|
||||
local openable = OpenableEnt(hitEnt)
|
||||
|
||||
if openable == OPEN_DOOR or openable == OPEN_ROT then
|
||||
local unlock = CrowbarCanUnlock(openable)
|
||||
if unlock then
|
||||
hitEnt:Fire("Unlock", nil, 0)
|
||||
end
|
||||
|
||||
if unlock or hitEnt:HasSpawnFlags(256) then
|
||||
if openable == OPEN_ROT then
|
||||
hitEnt:Fire("OpenAwayFrom", self:GetOwner(), 0)
|
||||
end
|
||||
hitEnt:Fire("Toggle", nil, 0)
|
||||
else
|
||||
return OPEN_NO
|
||||
end
|
||||
elseif openable == OPEN_BUT then
|
||||
if CrowbarCanUnlock(openable) then
|
||||
hitEnt:Fire("Unlock", nil, 0)
|
||||
hitEnt:Fire("Press", nil, 0)
|
||||
else
|
||||
return OPEN_NO
|
||||
end
|
||||
elseif openable == OPEN_NOTOGGLE then
|
||||
if CrowbarCanUnlock(openable) then
|
||||
hitEnt:Fire("Open", nil, 0)
|
||||
else
|
||||
return OPEN_NO
|
||||
end
|
||||
end
|
||||
return openable
|
||||
else
|
||||
return OPEN_NO
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:PrimaryAttack()
|
||||
self:SetNextPrimaryFire( CurTime() + self.Primary.Delay )
|
||||
|
||||
if not IsValid(self:GetOwner()) then return end
|
||||
|
||||
if self:GetOwner().LagCompensation then -- for some reason not always true
|
||||
self:GetOwner():LagCompensation(true)
|
||||
end
|
||||
|
||||
local spos = self:GetOwner():GetShootPos()
|
||||
local sdest = spos + (self:GetOwner():GetAimVector() * 70)
|
||||
|
||||
local tr_main = util.TraceLine({start=spos, endpos=sdest, filter=self:GetOwner(), mask=MASK_SHOT_HULL})
|
||||
local hitEnt = tr_main.Entity
|
||||
|
||||
self:EmitSound(sound_single)
|
||||
|
||||
if IsValid(hitEnt) or tr_main.HitWorld then
|
||||
self:SendWeaponAnim( ACT_VM_HITCENTER )
|
||||
|
||||
if not (CLIENT and (not IsFirstTimePredicted())) then
|
||||
local edata = EffectData()
|
||||
edata:SetStart(spos)
|
||||
edata:SetOrigin(tr_main.HitPos)
|
||||
edata:SetNormal(tr_main.Normal)
|
||||
edata:SetSurfaceProp(tr_main.SurfaceProps)
|
||||
edata:SetHitBox(tr_main.HitBox)
|
||||
--edata:SetDamageType(DMG_CLUB)
|
||||
edata:SetEntity(hitEnt)
|
||||
|
||||
if hitEnt:IsPlayer() or hitEnt:GetClass() == "prop_ragdoll" then
|
||||
util.Effect("BloodImpact", edata)
|
||||
|
||||
-- does not work on players rah
|
||||
--util.Decal("Blood", tr_main.HitPos + tr_main.HitNormal, tr_main.HitPos - tr_main.HitNormal)
|
||||
|
||||
-- do a bullet just to make blood decals work sanely
|
||||
-- need to disable lagcomp because firebullets does its own
|
||||
self:GetOwner():LagCompensation(false)
|
||||
self:GetOwner():FireBullets({Num=1, Src=spos, Dir=self:GetOwner():GetAimVector(), Spread=Vector(0,0,0), Tracer=0, Force=1, Damage=0})
|
||||
else
|
||||
util.Effect("Impact", edata)
|
||||
end
|
||||
end
|
||||
else
|
||||
self:SendWeaponAnim( ACT_VM_MISSCENTER )
|
||||
end
|
||||
|
||||
|
||||
if CLIENT then
|
||||
-- used to be some shit here
|
||||
else -- SERVER
|
||||
|
||||
-- Do another trace that sees nodraw stuff like func_button
|
||||
local tr_all = nil
|
||||
tr_all = util.TraceLine({start=spos, endpos=sdest, filter=self:GetOwner()})
|
||||
|
||||
self:GetOwner():SetAnimation( PLAYER_ATTACK1 )
|
||||
|
||||
if hitEnt and hitEnt:IsValid() then
|
||||
if self:OpenEnt(hitEnt) == OPEN_NO and tr_all.Entity and tr_all.Entity:IsValid() then
|
||||
-- See if there's a nodraw thing we should open
|
||||
self:OpenEnt(tr_all.Entity)
|
||||
end
|
||||
|
||||
local dmg = DamageInfo()
|
||||
dmg:SetDamage(self.Primary.Damage)
|
||||
dmg:SetAttacker(self:GetOwner())
|
||||
dmg:SetInflictor(self)
|
||||
dmg:SetDamageForce(self:GetOwner():GetAimVector() * 1500)
|
||||
dmg:SetDamagePosition(self:GetOwner():GetPos())
|
||||
dmg:SetDamageType(DMG_CLUB)
|
||||
|
||||
hitEnt:DispatchTraceAttack(dmg, spos + (self:GetOwner():GetAimVector() * 3), sdest)
|
||||
|
||||
-- self:SendWeaponAnim( ACT_VM_HITCENTER )
|
||||
|
||||
-- self:GetOwner():TraceHullAttack(spos, sdest, Vector(-16,-16,-16), Vector(16,16,16), 30, DMG_CLUB, 11, true)
|
||||
-- self:GetOwner():FireBullets({Num=1, Src=spos, Dir=self:GetOwner():GetAimVector(), Spread=Vector(0,0,0), Tracer=0, Force=1, Damage=20})
|
||||
|
||||
else
|
||||
-- if tr_main.HitWorld then
|
||||
-- self:SendWeaponAnim( ACT_VM_HITCENTER )
|
||||
-- else
|
||||
-- self:SendWeaponAnim( ACT_VM_MISSCENTER )
|
||||
-- end
|
||||
|
||||
-- See if our nodraw trace got the goods
|
||||
if tr_all.Entity and tr_all.Entity:IsValid() then
|
||||
self:OpenEnt(tr_all.Entity)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if self:GetOwner().LagCompensation then
|
||||
self:GetOwner():LagCompensation(false)
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:SecondaryAttack()
|
||||
self:SetNextPrimaryFire( CurTime() + self.Primary.Delay )
|
||||
self:SetNextSecondaryFire( CurTime() + 0.1 )
|
||||
|
||||
if self:GetOwner().LagCompensation then
|
||||
self:GetOwner():LagCompensation(true)
|
||||
end
|
||||
|
||||
local tr = self:GetOwner():GetEyeTrace(MASK_SHOT)
|
||||
|
||||
if tr.Hit and IsValid(tr.Entity) and tr.Entity:IsPlayer() and (self:GetOwner():EyePos() - tr.HitPos):Length() < 100 then
|
||||
local ply = tr.Entity
|
||||
|
||||
if SERVER and (not ply:IsFrozen()) then
|
||||
local pushvel = tr.Normal * GetConVar("ttt_crowbar_pushforce"):GetFloat()
|
||||
|
||||
-- limit the upward force to prevent launching
|
||||
pushvel.z = math.Clamp(pushvel.z, 50, 100)
|
||||
|
||||
ply:SetVelocity(ply:GetVelocity() + pushvel)
|
||||
self:GetOwner():SetAnimation( PLAYER_ATTACK1 )
|
||||
|
||||
ply.was_pushed = {att=self:GetOwner(), t=CurTime(), wep=self:GetClass()} --, infl=self}
|
||||
end
|
||||
|
||||
self:EmitSound(sound_single)
|
||||
self:SendWeaponAnim( ACT_VM_HITCENTER )
|
||||
|
||||
self:SetNextSecondaryFire( CurTime() + self.Secondary.Delay )
|
||||
end
|
||||
|
||||
if self:GetOwner().LagCompensation then
|
||||
self:GetOwner():LagCompensation(false)
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:GetClass()
|
||||
return "weapon_zm_improvised"
|
||||
end
|
||||
|
||||
function SWEP:OnDrop()
|
||||
self:Remove()
|
||||
end
|
||||
63
gamemodes/terrortown/entities/weapons/weapon_zm_mac10.lua
Normal file
63
gamemodes/terrortown/entities/weapons/weapon_zm_mac10.lua
Normal file
@@ -0,0 +1,63 @@
|
||||
--[[
|
||||
| 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()
|
||||
|
||||
SWEP.HoldType = "ar2"
|
||||
|
||||
if CLIENT then
|
||||
SWEP.PrintName = "MAC10"
|
||||
SWEP.Slot = 2
|
||||
|
||||
SWEP.ViewModelFlip = false
|
||||
SWEP.ViewModelFOV = 54
|
||||
|
||||
SWEP.Icon = "vgui/ttt/icon_mac"
|
||||
SWEP.IconLetter = "l"
|
||||
end
|
||||
|
||||
SWEP.Base = "weapon_tttbase"
|
||||
|
||||
SWEP.Kind = WEAPON_HEAVY
|
||||
SWEP.WeaponID = AMMO_MAC10
|
||||
|
||||
SWEP.Primary.Damage = 12
|
||||
SWEP.Primary.Delay = 0.065
|
||||
SWEP.Primary.Cone = 0.03
|
||||
SWEP.Primary.ClipSize = 30
|
||||
SWEP.Primary.ClipMax = 60
|
||||
SWEP.Primary.DefaultClip = 30
|
||||
SWEP.Primary.Automatic = true
|
||||
SWEP.Primary.Ammo = "SMG1"
|
||||
SWEP.Primary.Recoil = 1.15
|
||||
SWEP.Primary.Sound = Sound( "Weapon_mac10.Single" )
|
||||
|
||||
SWEP.AutoSpawnable = true
|
||||
SWEP.AmmoEnt = "item_ammo_smg1_ttt"
|
||||
|
||||
SWEP.UseHands = true
|
||||
SWEP.ViewModel = "models/weapons/cstrike/c_smg_mac10.mdl"
|
||||
SWEP.WorldModel = "models/weapons/w_smg_mac10.mdl"
|
||||
|
||||
SWEP.IronSightsPos = Vector(-8.921, -9.528, 2.9)
|
||||
SWEP.IronSightsAng = Vector(0.699, -5.301, -7)
|
||||
|
||||
SWEP.DeploySpeed = 3
|
||||
|
||||
function SWEP:GetHeadshotMultiplier(victim, dmginfo)
|
||||
local att = dmginfo:GetAttacker()
|
||||
if not IsValid(att) then return 2 end
|
||||
|
||||
local dist = victim:GetPos():Distance(att:GetPos())
|
||||
local d = math.max(0, dist - 150)
|
||||
|
||||
-- decay from 3.2 to 1.7
|
||||
return 1.7 + math.max(0, (1.5 - 0.002 * (d ^ 1.25)))
|
||||
end
|
||||
43
gamemodes/terrortown/entities/weapons/weapon_zm_molotov.lua
Normal file
43
gamemodes/terrortown/entities/weapons/weapon_zm_molotov.lua
Normal file
@@ -0,0 +1,43 @@
|
||||
--[[
|
||||
| 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()
|
||||
|
||||
SWEP.HoldType = "grenade"
|
||||
|
||||
if CLIENT then
|
||||
SWEP.PrintName = "grenade_fire"
|
||||
SWEP.Slot = 3
|
||||
|
||||
SWEP.ViewModelFlip = false
|
||||
SWEP.ViewModelFOV = 54
|
||||
|
||||
SWEP.Icon = "vgui/ttt/icon_nades"
|
||||
SWEP.IconLetter = "P"
|
||||
end
|
||||
|
||||
SWEP.Base = "weapon_tttbasegrenade"
|
||||
|
||||
SWEP.Kind = WEAPON_NADE
|
||||
SWEP.WeaponID = AMMO_MOLOTOV
|
||||
|
||||
SWEP.UseHands = true
|
||||
SWEP.ViewModel = "models/weapons/cstrike/c_eq_flashbang.mdl"
|
||||
SWEP.WorldModel = "models/weapons/w_eq_flashbang.mdl"
|
||||
|
||||
SWEP.Weight = 5
|
||||
SWEP.AutoSpawnable = true
|
||||
SWEP.Spawnable = true
|
||||
-- really the only difference between grenade weapons: the model and the thrown
|
||||
-- ent.
|
||||
|
||||
function SWEP:GetGrenadeName()
|
||||
return "ttt_firegrenade_proj"
|
||||
end
|
||||
50
gamemodes/terrortown/entities/weapons/weapon_zm_pistol.lua
Normal file
50
gamemodes/terrortown/entities/weapons/weapon_zm_pistol.lua
Normal file
@@ -0,0 +1,50 @@
|
||||
--[[
|
||||
| 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()
|
||||
|
||||
SWEP.HoldType = "pistol"
|
||||
|
||||
if CLIENT then
|
||||
SWEP.PrintName = "pistol_name"
|
||||
SWEP.Slot = 1
|
||||
|
||||
SWEP.ViewModelFlip = false
|
||||
SWEP.ViewModelFOV = 54
|
||||
|
||||
SWEP.Icon = "vgui/ttt/icon_pistol"
|
||||
SWEP.IconLetter = "u"
|
||||
end
|
||||
|
||||
SWEP.Base = "weapon_tttbase"
|
||||
|
||||
SWEP.Kind = WEAPON_PISTOL
|
||||
SWEP.WeaponID = AMMO_PISTOL
|
||||
|
||||
SWEP.Primary.Recoil = 1.5
|
||||
SWEP.Primary.Damage = 25
|
||||
SWEP.Primary.Delay = 0.38
|
||||
SWEP.Primary.Cone = 0.02
|
||||
SWEP.Primary.ClipSize = 20
|
||||
SWEP.Primary.Automatic = true
|
||||
SWEP.Primary.DefaultClip = 20
|
||||
SWEP.Primary.ClipMax = 60
|
||||
SWEP.Primary.Ammo = "Pistol"
|
||||
SWEP.Primary.Sound = Sound( "Weapon_FiveSeven.Single" )
|
||||
|
||||
SWEP.AutoSpawnable = true
|
||||
SWEP.AmmoEnt = "item_ammo_pistol_ttt"
|
||||
|
||||
SWEP.UseHands = true
|
||||
SWEP.ViewModel = "models/weapons/cstrike/c_pist_fiveseven.mdl"
|
||||
SWEP.WorldModel = "models/weapons/w_pist_fiveseven.mdl"
|
||||
|
||||
SWEP.IronSightsPos = Vector(-5.95, -4, 2.799)
|
||||
SWEP.IronSightsAng = Vector(0, 0, 0)
|
||||
52
gamemodes/terrortown/entities/weapons/weapon_zm_revolver.lua
Normal file
52
gamemodes/terrortown/entities/weapons/weapon_zm_revolver.lua
Normal file
@@ -0,0 +1,52 @@
|
||||
--[[
|
||||
| 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()
|
||||
|
||||
SWEP.HoldType = "pistol"
|
||||
|
||||
if CLIENT then
|
||||
SWEP.PrintName = "Deagle"
|
||||
SWEP.Slot = 1
|
||||
|
||||
SWEP.ViewModelFlip = false
|
||||
SWEP.ViewModelFOV = 54
|
||||
|
||||
SWEP.Icon = "vgui/ttt/icon_deagle"
|
||||
end
|
||||
|
||||
SWEP.Base = "weapon_tttbase"
|
||||
|
||||
SWEP.Kind = WEAPON_PISTOL
|
||||
SWEP.WeaponID = AMMO_DEAGLE
|
||||
|
||||
SWEP.Primary.Ammo = "AlyxGun" -- hijack an ammo type we don't use otherwise
|
||||
SWEP.Primary.Recoil = 6
|
||||
SWEP.Primary.Damage = 37
|
||||
SWEP.Primary.Delay = 0.6
|
||||
SWEP.Primary.Cone = 0.02
|
||||
SWEP.Primary.ClipSize = 8
|
||||
SWEP.Primary.ClipMax = 36
|
||||
SWEP.Primary.DefaultClip = 8
|
||||
SWEP.Primary.Automatic = true
|
||||
SWEP.Primary.Sound = Sound( "Weapon_Deagle.Single" )
|
||||
|
||||
SWEP.HeadshotMultiplier = 4
|
||||
|
||||
SWEP.AutoSpawnable = true
|
||||
SWEP.Spawnable = true
|
||||
SWEP.AmmoEnt = "item_ammo_revolver_ttt"
|
||||
|
||||
SWEP.UseHands = true
|
||||
SWEP.ViewModel = "models/weapons/cstrike/c_pist_deagle.mdl"
|
||||
SWEP.WorldModel = "models/weapons/w_pist_deagle.mdl"
|
||||
|
||||
SWEP.IronSightsPos = Vector(-6.361, -3.701, 2.15)
|
||||
SWEP.IronSightsAng = Vector(0, 0, 0)
|
||||
164
gamemodes/terrortown/entities/weapons/weapon_zm_rifle.lua
Normal file
164
gamemodes/terrortown/entities/weapons/weapon_zm_rifle.lua
Normal file
@@ -0,0 +1,164 @@
|
||||
--[[
|
||||
| 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()
|
||||
|
||||
SWEP.HoldType = "ar2"
|
||||
|
||||
if CLIENT then
|
||||
SWEP.PrintName = "rifle_name"
|
||||
SWEP.Slot = 2
|
||||
|
||||
SWEP.ViewModelFlip = false
|
||||
SWEP.ViewModelFOV = 54
|
||||
|
||||
SWEP.Icon = "vgui/ttt/icon_scout"
|
||||
SWEP.IconLetter = "n"
|
||||
end
|
||||
|
||||
SWEP.Base = "weapon_tttbase"
|
||||
|
||||
SWEP.Kind = WEAPON_HEAVY
|
||||
SWEP.WeaponID = AMMO_RIFLE
|
||||
|
||||
SWEP.Primary.Delay = 1.5
|
||||
SWEP.Primary.Recoil = 7
|
||||
SWEP.Primary.Automatic = true
|
||||
SWEP.Primary.Ammo = "357"
|
||||
SWEP.Primary.Damage = 50
|
||||
SWEP.Primary.Cone = 0.005
|
||||
SWEP.Primary.ClipSize = 10
|
||||
SWEP.Primary.ClipMax = 20 -- keep mirrored to ammo
|
||||
SWEP.Primary.DefaultClip = 10
|
||||
SWEP.Primary.Sound = Sound("Weapon_Scout.Single")
|
||||
|
||||
SWEP.Secondary.Sound = Sound("Default.Zoom")
|
||||
|
||||
SWEP.HeadshotMultiplier = 4
|
||||
|
||||
SWEP.AutoSpawnable = true
|
||||
SWEP.Spawnable = true
|
||||
SWEP.AmmoEnt = "item_ammo_357_ttt"
|
||||
|
||||
SWEP.UseHands = true
|
||||
SWEP.ViewModel = Model("models/weapons/cstrike/c_snip_scout.mdl")
|
||||
SWEP.WorldModel = Model("models/weapons/w_snip_scout.mdl")
|
||||
|
||||
SWEP.IronSightsPos = Vector( 5, -15, -2 )
|
||||
SWEP.IronSightsAng = Vector( 2.6, 1.37, 3.5 )
|
||||
|
||||
function SWEP:SetZoom(state)
|
||||
if IsValid(self:GetOwner()) and self:GetOwner():IsPlayer() then
|
||||
if state then
|
||||
self:GetOwner():SetFOV(20, 0.3)
|
||||
else
|
||||
self:GetOwner():SetFOV(0, 0.2)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:PrimaryAttack( worldsnd )
|
||||
self.BaseClass.PrimaryAttack( self, worldsnd )
|
||||
self:SetNextSecondaryFire( CurTime() + 0.1 )
|
||||
end
|
||||
|
||||
-- Add some zoom to ironsights for this gun
|
||||
function SWEP:SecondaryAttack()
|
||||
if not self.IronSightsPos then return end
|
||||
if self:GetNextSecondaryFire() > CurTime() then return end
|
||||
|
||||
local bIronsights = not self:GetIronsights()
|
||||
|
||||
self:SetIronsights( bIronsights )
|
||||
|
||||
self:SetZoom(bIronsights)
|
||||
if (CLIENT) then
|
||||
self:EmitSound(self.Secondary.Sound)
|
||||
end
|
||||
|
||||
self:SetNextSecondaryFire( CurTime() + 0.3)
|
||||
end
|
||||
|
||||
function SWEP:PreDrop()
|
||||
self:SetZoom(false)
|
||||
self:SetIronsights(false)
|
||||
return self.BaseClass.PreDrop(self)
|
||||
end
|
||||
|
||||
function SWEP:Reload()
|
||||
if ( self:Clip1() == self.Primary.ClipSize or self:GetOwner():GetAmmoCount( self.Primary.Ammo ) <= 0 ) then return end
|
||||
self:DefaultReload( ACT_VM_RELOAD )
|
||||
self:SetIronsights( false )
|
||||
self:SetZoom( false )
|
||||
end
|
||||
|
||||
|
||||
function SWEP:Holster()
|
||||
self:SetIronsights(false)
|
||||
self:SetZoom(false)
|
||||
return true
|
||||
end
|
||||
|
||||
if CLIENT then
|
||||
local scope = surface.GetTextureID("sprites/scope")
|
||||
function SWEP:DrawHUD()
|
||||
if self:GetIronsights() then
|
||||
surface.SetDrawColor( 0, 0, 0, 255 )
|
||||
|
||||
local scrW = ScrW()
|
||||
local scrH = ScrH()
|
||||
|
||||
local x = scrW / 2.0
|
||||
local y = scrH / 2.0
|
||||
local scope_size = scrH
|
||||
|
||||
-- crosshair
|
||||
local gap = 80
|
||||
local length = scope_size
|
||||
surface.DrawLine( x - length, y, x - gap, y )
|
||||
surface.DrawLine( x + length, y, x + gap, y )
|
||||
surface.DrawLine( x, y - length, x, y - gap )
|
||||
surface.DrawLine( x, y + length, x, y + gap )
|
||||
|
||||
gap = 0
|
||||
length = 50
|
||||
surface.DrawLine( x - length, y, x - gap, y )
|
||||
surface.DrawLine( x + length, y, x + gap, y )
|
||||
surface.DrawLine( x, y - length, x, y - gap )
|
||||
surface.DrawLine( x, y + length, x, y + gap )
|
||||
|
||||
|
||||
-- cover edges
|
||||
local sh = scope_size / 2
|
||||
local w = (x - sh) + 2
|
||||
surface.DrawRect(0, 0, w, scope_size)
|
||||
surface.DrawRect(x + sh - 2, 0, w, scope_size)
|
||||
|
||||
-- cover gaps on top and bottom of screen
|
||||
surface.DrawLine( 0, 0, scrW, 0 )
|
||||
surface.DrawLine( 0, scrH - 1, scrW, scrH - 1 )
|
||||
|
||||
surface.SetDrawColor(255, 0, 0, 255)
|
||||
surface.DrawLine(x, y, x + 1, y + 1)
|
||||
|
||||
-- scope
|
||||
surface.SetTexture(scope)
|
||||
surface.SetDrawColor(255, 255, 255, 255)
|
||||
|
||||
surface.DrawTexturedRectRotated(x, y, scope_size, scope_size, 0)
|
||||
else
|
||||
return self.BaseClass.DrawHUD(self)
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:AdjustMouseSensitivity()
|
||||
return (self:GetIronsights() and 0.2) or nil
|
||||
end
|
||||
end
|
||||
191
gamemodes/terrortown/entities/weapons/weapon_zm_shotgun.lua
Normal file
191
gamemodes/terrortown/entities/weapons/weapon_zm_shotgun.lua
Normal file
@@ -0,0 +1,191 @@
|
||||
--[[
|
||||
| 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()
|
||||
|
||||
DEFINE_BASECLASS "weapon_tttbase"
|
||||
|
||||
SWEP.HoldType = "shotgun"
|
||||
|
||||
if CLIENT then
|
||||
SWEP.PrintName = "shotgun_name"
|
||||
SWEP.Slot = 2
|
||||
|
||||
SWEP.ViewModelFlip = false
|
||||
SWEP.ViewModelFOV = 54
|
||||
|
||||
SWEP.Icon = "vgui/ttt/icon_shotgun"
|
||||
SWEP.IconLetter = "B"
|
||||
end
|
||||
|
||||
SWEP.Base = "weapon_tttbase"
|
||||
|
||||
SWEP.Kind = WEAPON_HEAVY
|
||||
SWEP.WeaponID = AMMO_SHOTGUN
|
||||
|
||||
SWEP.Primary.Ammo = "Buckshot"
|
||||
SWEP.Primary.Damage = 11
|
||||
SWEP.Primary.Cone = 0.082
|
||||
SWEP.Primary.Delay = 0.8
|
||||
SWEP.Primary.ClipSize = 8
|
||||
SWEP.Primary.ClipMax = 24
|
||||
SWEP.Primary.DefaultClip = 8
|
||||
SWEP.Primary.Automatic = true
|
||||
SWEP.Primary.NumShots = 8
|
||||
SWEP.Primary.Sound = Sound( "Weapon_XM1014.Single" )
|
||||
SWEP.Primary.Recoil = 7
|
||||
|
||||
SWEP.AutoSpawnable = true
|
||||
SWEP.Spawnable = true
|
||||
SWEP.AmmoEnt = "item_box_buckshot_ttt"
|
||||
|
||||
SWEP.UseHands = true
|
||||
SWEP.ViewModel = "models/weapons/cstrike/c_shot_xm1014.mdl"
|
||||
SWEP.WorldModel = "models/weapons/w_shot_xm1014.mdl"
|
||||
|
||||
SWEP.IronSightsPos = Vector(-6.881, -9.214, 2.66)
|
||||
SWEP.IronSightsAng = Vector(-0.101, -0.7, -0.201)
|
||||
|
||||
function SWEP:SetupDataTables()
|
||||
self:NetworkVar("Bool", 0, "Reloading")
|
||||
self:NetworkVar("Float", 0, "ReloadTimer")
|
||||
|
||||
return BaseClass.SetupDataTables(self)
|
||||
end
|
||||
|
||||
function SWEP:Reload()
|
||||
|
||||
if self:GetReloading() then return end
|
||||
|
||||
if self:Clip1() < self.Primary.ClipSize and self:GetOwner():GetAmmoCount( self.Primary.Ammo ) > 0 then
|
||||
|
||||
if self:StartReload() then
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function SWEP:StartReload()
|
||||
if self:GetReloading() then
|
||||
return false
|
||||
end
|
||||
|
||||
self:SetIronsights( false )
|
||||
|
||||
self:SetNextPrimaryFire( CurTime() + self.Primary.Delay )
|
||||
|
||||
local ply = self:GetOwner()
|
||||
|
||||
if not ply or ply:GetAmmoCount(self.Primary.Ammo) <= 0 then
|
||||
return false
|
||||
end
|
||||
|
||||
local wep = self
|
||||
|
||||
if wep:Clip1() >= self.Primary.ClipSize then
|
||||
return false
|
||||
end
|
||||
|
||||
wep:SendWeaponAnim(ACT_SHOTGUN_RELOAD_START)
|
||||
|
||||
self:SetReloadTimer(CurTime() + wep:SequenceDuration())
|
||||
|
||||
self:SetReloading(true)
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function SWEP:PerformReload()
|
||||
local ply = self:GetOwner()
|
||||
|
||||
-- prevent normal shooting in between reloads
|
||||
self:SetNextPrimaryFire( CurTime() + self.Primary.Delay )
|
||||
|
||||
if not ply or ply:GetAmmoCount(self.Primary.Ammo) <= 0 then return end
|
||||
|
||||
if self:Clip1() >= self.Primary.ClipSize then return end
|
||||
|
||||
self:GetOwner():RemoveAmmo( 1, self.Primary.Ammo, false )
|
||||
self:SetClip1( self:Clip1() + 1 )
|
||||
|
||||
self:SendWeaponAnim(ACT_VM_RELOAD)
|
||||
|
||||
self:SetReloadTimer(CurTime() + self:SequenceDuration())
|
||||
end
|
||||
|
||||
function SWEP:FinishReload()
|
||||
self:SetReloading(false)
|
||||
self:SendWeaponAnim(ACT_SHOTGUN_RELOAD_FINISH)
|
||||
|
||||
self:SetReloadTimer(CurTime() + self:SequenceDuration())
|
||||
end
|
||||
|
||||
function SWEP:CanPrimaryAttack()
|
||||
if self:Clip1() <= 0 then
|
||||
self:EmitSound( "Weapon_Shotgun.Empty" )
|
||||
self:SetNextPrimaryFire( CurTime() + self.Primary.Delay )
|
||||
return false
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
function SWEP:Think()
|
||||
BaseClass.Think(self)
|
||||
if self:GetReloading() then
|
||||
if self:GetOwner():KeyDown(IN_ATTACK) then
|
||||
self:FinishReload()
|
||||
return
|
||||
end
|
||||
|
||||
if self:GetReloadTimer() <= CurTime() then
|
||||
|
||||
if self:GetOwner():GetAmmoCount(self.Primary.Ammo) <= 0 then
|
||||
self:FinishReload()
|
||||
elseif self:Clip1() < self.Primary.ClipSize then
|
||||
self:PerformReload()
|
||||
else
|
||||
self:FinishReload()
|
||||
end
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:Deploy()
|
||||
self:SetReloading(false)
|
||||
self:SetReloadTimer(0)
|
||||
return BaseClass.Deploy(self)
|
||||
end
|
||||
|
||||
-- The shotgun's headshot damage multiplier is based on distance. The closer it
|
||||
-- is, the more damage it does. This reinforces the shotgun's role as short
|
||||
-- range weapon by reducing effectiveness at mid-range, where one could score
|
||||
-- lucky headshots relatively easily due to the spread.
|
||||
function SWEP:GetHeadshotMultiplier(victim, dmginfo)
|
||||
local att = dmginfo:GetAttacker()
|
||||
if not IsValid(att) then return 3 end
|
||||
|
||||
local dist = victim:GetPos():Distance(att:GetPos())
|
||||
local d = math.max(0, dist - 140)
|
||||
|
||||
-- Decay from 2 to 1 slowly as distance increases. Note that this used to be
|
||||
-- 3+, but at that time shotgun bullets were treated like in HL2 where half
|
||||
-- of them were hull traces that could not headshot.
|
||||
return 1 + math.max(0, (1.0 - 0.002 * (d ^ 1.25)))
|
||||
end
|
||||
|
||||
function SWEP:SecondaryAttack()
|
||||
if self.NoSights or (not self.IronSightsPos) or self:GetReloading() then return end
|
||||
|
||||
self:SetIronsights(not self:GetIronsights())
|
||||
|
||||
self:SetNextSecondaryFire(CurTime() + 0.3)
|
||||
end
|
||||
52
gamemodes/terrortown/entities/weapons/weapon_zm_sledge.lua
Normal file
52
gamemodes/terrortown/entities/weapons/weapon_zm_sledge.lua
Normal file
@@ -0,0 +1,52 @@
|
||||
--[[
|
||||
| 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()
|
||||
|
||||
SWEP.HoldType = "crossbow"
|
||||
|
||||
if CLIENT then
|
||||
SWEP.PrintName = "H.U.G.E-249"
|
||||
SWEP.Slot = 2
|
||||
|
||||
SWEP.ViewModelFlip = false
|
||||
SWEP.ViewModelFOV = 54
|
||||
|
||||
SWEP.Icon = "vgui/ttt/icon_m249"
|
||||
SWEP.IconLetter = "z"
|
||||
end
|
||||
|
||||
SWEP.Base = "weapon_tttbase"
|
||||
|
||||
SWEP.Spawnable = true
|
||||
SWEP.AutoSpawnable = true
|
||||
|
||||
SWEP.Kind = WEAPON_HEAVY
|
||||
SWEP.WeaponID = AMMO_M249
|
||||
|
||||
SWEP.Primary.Damage = 7
|
||||
SWEP.Primary.Delay = 0.06
|
||||
SWEP.Primary.Cone = 0.09
|
||||
SWEP.Primary.ClipSize = 150
|
||||
SWEP.Primary.ClipMax = 150
|
||||
SWEP.Primary.DefaultClip = 150
|
||||
SWEP.Primary.Automatic = true
|
||||
SWEP.Primary.Ammo = "AirboatGun"
|
||||
SWEP.Primary.Recoil = 1.9
|
||||
SWEP.Primary.Sound = Sound("Weapon_m249.Single")
|
||||
|
||||
SWEP.UseHands = true
|
||||
SWEP.ViewModel = "models/weapons/cstrike/c_mach_m249para.mdl"
|
||||
SWEP.WorldModel = "models/weapons/w_mach_m249para.mdl"
|
||||
|
||||
SWEP.HeadshotMultiplier = 2.2
|
||||
|
||||
SWEP.IronSightsPos = Vector(-5.96, -5.119, 2.349)
|
||||
SWEP.IronSightsAng = Vector(0, 0, 0)
|
||||
Reference in New Issue
Block a user