Files
wnsrc/gamemodes/terrortown/gamemode/cl_wepswitch.lua
lifestorm 94063e4369 Upload
2024-08-04 22:55:00 +03:00

351 lines
8.1 KiB
Lua

--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
-- we need our own weapon switcher because the hl2 one skips empty weapons
local math = math
local draw = draw
local surface = surface
local table = table
WSWITCH = {}
WSWITCH.Show = false
WSWITCH.Selected = -1
WSWITCH.NextSwitch = -1
WSWITCH.WeaponCache = {}
WSWITCH.cv = {}
WSWITCH.cv.stay = CreateConVar("ttt_weaponswitcher_stay", "0", FCVAR_ARCHIVE)
WSWITCH.cv.fast = CreateConVar("ttt_weaponswitcher_fast", "0", FCVAR_ARCHIVE)
WSWITCH.cv.display = CreateConVar("ttt_weaponswitcher_displayfast", "0", FCVAR_ARCHIVE)
local delay = 0.03
local showtime = 3
local margin = 10
local width = 300
local height = 20
local barcorner = surface.GetTextureID( "gui/corner8" )
local col_active = {
tip = {
[ROLE_INNOCENT] = Color(55, 170, 50, 255),
[ROLE_TRAITOR] = Color(180, 50, 40, 255),
[ROLE_DETECTIVE] = Color(50, 60, 180, 255)
},
bg = Color(20, 20, 20, 250),
text_empty = Color(200, 20, 20, 255),
text = Color(255, 255, 255, 255),
shadow = 255
};
local col_dark = {
tip = {
[ROLE_INNOCENT] = Color(60, 160, 50, 155),
[ROLE_TRAITOR] = Color(160, 50, 60, 155),
[ROLE_DETECTIVE] = Color(50, 60, 160, 155),
},
bg = Color(20, 20, 20, 200),
text_empty = Color(200, 20, 20, 100),
text = Color(255, 255, 255, 100),
shadow = 100
};
-- Draw a bar in the style of the the weapon pickup ones
local round = math.Round
function WSWITCH:DrawBarBg(x, y, w, h, col)
local rx = round(x - 4)
local ry = round(y - (h / 2)-4)
local rw = round(w + 9)
local rh = round(h + 8)
local b = 8 --bordersize
local bh = b / 2
local role = LocalPlayer():GetRole() or ROLE_INNOCENT
local c = col.tip[role]
-- Draw the colour tip
surface.SetTexture(barcorner)
surface.SetDrawColor(c.r, c.g, c.b, c.a)
surface.DrawTexturedRectRotated( rx + bh , ry + bh, b, b, 0 )
surface.DrawTexturedRectRotated( rx + bh , ry + rh -bh, b, b, 90 )
surface.DrawRect( rx, ry+b, b, rh-b*2 )
surface.DrawRect( rx+b, ry, h - 4, rh )
-- Draw the remainder
-- Could just draw a full roundedrect bg and overdraw it with the tip, but
-- I don't have to do the hard work here anymore anyway
c = col.bg
surface.SetDrawColor(c.r, c.g, c.b, c.a)
surface.DrawRect( rx+b+h-4, ry, rw - (h - 4) - b*2, rh )
surface.DrawTexturedRectRotated( rx + rw - bh , ry + rh - bh, b, b, 180 )
surface.DrawTexturedRectRotated( rx + rw - bh , ry + bh, b, b, 270 )
surface.DrawRect( rx+rw-b, ry+b, b, rh-b*2 )
end
local TryTranslation = LANG.TryTranslation
function WSWITCH:DrawWeapon(x, y, c, wep)
if not IsValid(wep) then return false end
local name = TryTranslation(wep:GetPrintName() or wep.PrintName or "...")
local cl1, am1 = wep:Clip1(), wep:Ammo1()
local ammo = false
-- Clip1 will be -1 if a melee weapon
-- Ammo1 will be false if weapon has no owner (was just dropped)
if cl1 != -1 and am1 != false then
ammo = Format("%i + %02i", cl1, am1)
end
-- Slot
local spec = {text=wep.Slot+1, font="Trebuchet22", pos={x+4, y}, yalign=TEXT_ALIGN_CENTER, color=c.text}
draw.TextShadow(spec, 1, c.shadow)
-- Name
spec.text = name
spec.font = "TimeLeft"
spec.pos[1] = x + 10 + height
draw.Text(spec)
if ammo then
local col = c.text
if wep:Clip1() == 0 and wep:Ammo1() == 0 then
col = c.text_empty
end
-- Ammo
spec.text = ammo
spec.pos[1] = ScrW() - margin*3
spec.xalign = TEXT_ALIGN_RIGHT
spec.color = col
draw.Text(spec)
end
return true
end
function WSWITCH:Draw(client)
if not self.Show then return end
local weps = self.WeaponCache
local x = ScrW() - width - margin*2
local y = ScrH() - (#weps * (height + margin))
local col = col_dark
for k, wep in pairs(weps) do
if self.Selected == k then
col = col_active
else
col = col_dark
end
self:DrawBarBg(x, y, width, height, col)
if not self:DrawWeapon(x, y, col, wep) then
self:UpdateWeaponCache()
return
end
y = y + height + margin
end
end
local function SlotSort(a, b)
return a and b and a.Slot and b.Slot and a.Slot < b.Slot
end
local function CopyVals(src, dest)
table.Empty(dest)
for k, v in pairs(src) do
if IsValid(v) then
table.insert(dest, v)
end
end
end
function WSWITCH:UpdateWeaponCache()
-- GetWeapons does not always return a proper numeric table it seems
-- self.WeaponCache = LocalPlayer():GetWeapons()
-- So copy over the weapon refs
self.WeaponCache = {}
CopyVals(LocalPlayer():GetWeapons(), self.WeaponCache)
table.sort(self.WeaponCache, SlotSort)
end
function WSWITCH:SetSelected(idx)
self.Selected = idx
self:UpdateWeaponCache()
end
function WSWITCH:SelectNext()
if self.NextSwitch > CurTime() then return end
self:Enable()
local s = self.Selected + 1
if s > #self.WeaponCache then
s = 1
end
self:DoSelect(s)
self.NextSwitch = CurTime() + delay
end
function WSWITCH:SelectPrev()
if self.NextSwitch > CurTime() then return end
self:Enable()
local s = self.Selected - 1
if s < 1 then
s = #self.WeaponCache
end
self:DoSelect(s)
self.NextSwitch = CurTime() + delay
end
-- Select by index
function WSWITCH:DoSelect(idx)
self:SetSelected(idx)
if self.cv.fast:GetBool() then
-- immediately confirm if fastswitch is on
self:ConfirmSelection(self.cv.display:GetBool())
end
end
-- Numeric key access to direct slots
function WSWITCH:SelectSlot(slot)
if not slot then return end
self:Enable()
self:UpdateWeaponCache()
slot = slot - 1
-- find which idx in the weapon table has the slot we want
local toselect = self.Selected
for k, w in pairs(self.WeaponCache) do
if w.Slot == slot then
toselect = k
break
end
end
self:DoSelect(toselect)
self.NextSwitch = CurTime() + delay
end
-- Show the weapon switcher
function WSWITCH:Enable()
if self.Show == false then
self.Show = true
local wep_active = LocalPlayer():GetActiveWeapon()
self:UpdateWeaponCache()
-- make our active weapon the initial selection
local toselect = 1
for k, w in pairs(self.WeaponCache) do
if w == wep_active then
toselect = k
break
end
end
self:SetSelected(toselect)
end
-- cache for speed, checked every Think
self.Stay = self.cv.stay:GetBool()
end
-- Hide switcher
function WSWITCH:Disable()
self.Show = false
end
-- Switch to the currently selected weapon
function WSWITCH:ConfirmSelection(noHide)
if not noHide then self:Disable() end
for k, w in pairs(self.WeaponCache) do
if k == self.Selected and IsValid(w) then
input.SelectWeapon(w)
return
end
end
end
-- Allow for suppression of the attack command
function WSWITCH:PreventAttack()
return self.Show and !self.cv.fast:GetBool()
end
function WSWITCH:Think()
if (not self.Show) or self.Stay then return end
-- hide after period of inaction
if self.NextSwitch < (CurTime() - showtime) then
self:Disable()
end
end
-- Instantly select a slot and switch to it, without spending time in menu
function WSWITCH:SelectAndConfirm(slot)
if not slot then return end
WSWITCH:SelectSlot(slot)
WSWITCH:ConfirmSelection()
end
local function QuickSlot(ply, cmd, args)
if (not IsValid(ply)) or (not args) or #args != 1 then return end
local slot = tonumber(args[1])
if not slot then return end
local wep = ply:GetActiveWeapon()
if IsValid(wep) then
if wep.Slot == (slot - 1) then
RunConsoleCommand("lastinv")
else
WSWITCH:SelectAndConfirm(slot)
end
end
end
concommand.Add("ttt_quickslot", QuickSlot)
local function SwitchToEquipment(ply, cmd, args)
RunConsoleCommand("ttt_quickslot", tostring(7))
end
concommand.Add("ttt_equipswitch", SwitchToEquipment)