This commit is contained in:
lifestorm
2024-08-04 23:54:45 +03:00
parent 8064ba84d8
commit 6a58f406b1
7522 changed files with 4011896 additions and 15 deletions

View 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

View 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

View 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

View File

@@ -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

View 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

View 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

View 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

View 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

View 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 )

View File

@@ -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

View 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

View 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

View 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

View 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

View 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

View File

@@ -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

View 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_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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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)

View 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)

View 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

View 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

View 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)