mirror of
https://github.com/lifestorm/wnsrc.git
synced 2025-12-17 05:43:46 +03:00
Upload
This commit is contained in:
515
gamemodes/terrortown/gamemode/cl_equip.lua
Normal file
515
gamemodes/terrortown/gamemode/cl_equip.lua
Normal file
@@ -0,0 +1,515 @@
|
||||
--[[
|
||||
| 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 menu
|
||||
|
||||
local GetTranslation = LANG.GetTranslation
|
||||
local GetPTranslation = LANG.GetParamTranslation
|
||||
|
||||
-- Buyable weapons are loaded automatically. Buyable items are defined in
|
||||
-- equip_items_shd.lua
|
||||
|
||||
local Equipment = nil
|
||||
function GetEquipmentForRole(role)
|
||||
-- need to build equipment cache?
|
||||
if not Equipment then
|
||||
-- start with all the non-weapon goodies
|
||||
local tbl = table.Copy(EquipmentItems)
|
||||
|
||||
-- find buyable weapons to load info from
|
||||
for k, v in pairs(weapons.GetList()) do
|
||||
if v and v.CanBuy then
|
||||
local data = v.EquipMenuData or {}
|
||||
local base = {
|
||||
id = WEPS.GetClass(v),
|
||||
name = v.PrintName or "Unnamed",
|
||||
limited = v.LimitedStock,
|
||||
kind = v.Kind or WEAPON_NONE,
|
||||
slot = (v.Slot or 0) + 1,
|
||||
material = v.Icon or "vgui/ttt/icon_id",
|
||||
-- the below should be specified in EquipMenuData, in which case
|
||||
-- these values are overwritten
|
||||
type = "Type not specified",
|
||||
model = "models/weapons/w_bugbait.mdl",
|
||||
desc = "No description specified."
|
||||
};
|
||||
|
||||
-- Force material to nil so that model key is used when we are
|
||||
-- explicitly told to do so (ie. material is false rather than nil).
|
||||
if data.modelicon then
|
||||
base.material = nil
|
||||
end
|
||||
|
||||
table.Merge(base, data)
|
||||
|
||||
-- add this buyable weapon to all relevant equipment tables
|
||||
for _, r in pairs(v.CanBuy) do
|
||||
table.insert(tbl[r], base)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- mark custom items
|
||||
for r, is in pairs(tbl) do
|
||||
for _, i in pairs(is) do
|
||||
if i and i.id then
|
||||
i.custom = not table.HasValue(DefaultEquipment[r], i.id)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Equipment = tbl
|
||||
end
|
||||
|
||||
return Equipment and Equipment[role] or {}
|
||||
end
|
||||
|
||||
|
||||
local function ItemIsWeapon(item) return not tonumber(item.id) end
|
||||
local function CanCarryWeapon(item) return LocalPlayer():CanCarryType(item.kind) end
|
||||
|
||||
local color_bad = Color(220, 60, 60, 255)
|
||||
local color_good = Color(0, 200, 0, 255)
|
||||
|
||||
-- Creates tabel of labels showing the status of ordering prerequisites
|
||||
local function PreqLabels(parent, x, y)
|
||||
local tbl = {}
|
||||
|
||||
tbl.credits = vgui.Create("DLabel", parent)
|
||||
tbl.credits:SetTooltip(GetTranslation("equip_help_cost"))
|
||||
tbl.credits:SetPos(x, y)
|
||||
tbl.credits.Check = function(s, sel)
|
||||
local credits = LocalPlayer():GetCredits()
|
||||
return credits > 0, GetPTranslation("equip_cost", {num = credits})
|
||||
end
|
||||
|
||||
tbl.owned = vgui.Create("DLabel", parent)
|
||||
tbl.owned:SetTooltip(GetTranslation("equip_help_carry"))
|
||||
tbl.owned:CopyPos(tbl.credits)
|
||||
tbl.owned:MoveBelow(tbl.credits, y)
|
||||
tbl.owned.Check = function(s, sel)
|
||||
if ItemIsWeapon(sel) and (not CanCarryWeapon(sel)) then
|
||||
return false, GetPTranslation("equip_carry_slot", {slot = sel.slot})
|
||||
elseif (not ItemIsWeapon(sel)) and LocalPlayer():HasEquipmentItem(sel.id) then
|
||||
return false, GetTranslation("equip_carry_own")
|
||||
else
|
||||
return true, GetTranslation("equip_carry")
|
||||
end
|
||||
end
|
||||
|
||||
tbl.bought = vgui.Create("DLabel", parent)
|
||||
tbl.bought:SetTooltip(GetTranslation("equip_help_stock"))
|
||||
tbl.bought:CopyPos(tbl.owned)
|
||||
tbl.bought:MoveBelow(tbl.owned, y)
|
||||
tbl.bought.Check = function(s, sel)
|
||||
if sel.limited and LocalPlayer():HasBought(tostring(sel.id)) then
|
||||
return false, GetTranslation("equip_stock_deny")
|
||||
else
|
||||
return true, GetTranslation("equip_stock_ok")
|
||||
end
|
||||
end
|
||||
|
||||
for k, pnl in pairs(tbl) do
|
||||
pnl:SetFont("TabLarge")
|
||||
end
|
||||
|
||||
return function(selected)
|
||||
local allow = true
|
||||
for k, pnl in pairs(tbl) do
|
||||
local result, text = pnl:Check(selected)
|
||||
pnl:SetTextColor(result and color_good or color_bad)
|
||||
pnl:SetText(text)
|
||||
pnl:SizeToContents()
|
||||
|
||||
allow = allow and result
|
||||
end
|
||||
return allow
|
||||
end
|
||||
end
|
||||
|
||||
-- quick, very basic override of DPanelSelect
|
||||
local PANEL = {}
|
||||
local function DrawSelectedEquipment(pnl)
|
||||
surface.SetDrawColor(255, 200, 0, 255)
|
||||
surface.DrawOutlinedRect(0, 0, pnl:GetWide(), pnl:GetTall())
|
||||
end
|
||||
|
||||
function PANEL:SelectPanel(pnl)
|
||||
self.BaseClass.SelectPanel(self, pnl)
|
||||
if pnl then
|
||||
pnl.PaintOver = DrawSelectedEquipment
|
||||
end
|
||||
end
|
||||
vgui.Register("EquipSelect", PANEL, "DPanelSelect")
|
||||
|
||||
|
||||
local SafeTranslate = LANG.TryTranslation
|
||||
|
||||
local color_darkened = Color(255,255,255, 80)
|
||||
-- TODO: make set of global role colour defs, these are same as wepswitch
|
||||
local color_slot = {
|
||||
[ROLE_TRAITOR] = Color(180, 50, 40, 255),
|
||||
[ROLE_DETECTIVE] = Color(50, 60, 180, 255)
|
||||
}
|
||||
|
||||
local fieldstbl = {"name", "type", "desc"}
|
||||
|
||||
local eqframe = nil
|
||||
local function TraitorMenuPopup()
|
||||
local ply = LocalPlayer()
|
||||
if not IsValid(ply) or not ply:IsActiveSpecial() then
|
||||
return
|
||||
end
|
||||
|
||||
-- Close any existing traitor menu
|
||||
if eqframe and IsValid(eqframe) then eqframe:Close() end
|
||||
|
||||
local credits = ply:GetCredits()
|
||||
local can_order = credits > 0
|
||||
|
||||
local dframe = vgui.Create("DFrame")
|
||||
local w, h = 570, 412
|
||||
dframe:SetSize(w, h)
|
||||
dframe:Center()
|
||||
dframe:SetTitle(GetTranslation("equip_title"))
|
||||
dframe:SetVisible(true)
|
||||
dframe:ShowCloseButton(true)
|
||||
dframe:SetMouseInputEnabled(true)
|
||||
dframe:SetDeleteOnClose(true)
|
||||
|
||||
local m = 5
|
||||
|
||||
local dsheet = vgui.Create("DPropertySheet", dframe)
|
||||
|
||||
-- Add a callback when switching tabs
|
||||
local oldfunc = dsheet.SetActiveTab
|
||||
dsheet.SetActiveTab = function(self, new)
|
||||
if self.m_pActiveTab != new and self.OnTabChanged then
|
||||
self:OnTabChanged(self.m_pActiveTab, new)
|
||||
end
|
||||
oldfunc(self, new)
|
||||
end
|
||||
|
||||
dsheet:SetPos(0,0)
|
||||
dsheet:StretchToParent(m,m + 25,m,m)
|
||||
local padding = dsheet:GetPadding()
|
||||
|
||||
local dequip = vgui.Create("DPanel", dsheet)
|
||||
dequip:SetPaintBackground(false)
|
||||
dequip:StretchToParent(padding,padding,padding,padding)
|
||||
|
||||
-- Determine if we already have equipment
|
||||
local owned_ids = {}
|
||||
for _, wep in ipairs(ply:GetWeapons()) do
|
||||
if IsValid(wep) and wep:IsEquipment() then
|
||||
table.insert(owned_ids, wep:GetClass())
|
||||
end
|
||||
end
|
||||
|
||||
-- Stick to one value for no equipment
|
||||
if #owned_ids == 0 then
|
||||
owned_ids = nil
|
||||
end
|
||||
|
||||
--- Construct icon listing
|
||||
local dlist = vgui.Create("EquipSelect", dequip)
|
||||
dlist:SetPos(0,0)
|
||||
dlist:SetSize(216, h - 75)
|
||||
dlist:EnableVerticalScrollbar()
|
||||
dlist:EnableHorizontal(true)
|
||||
dlist:SetPadding(4)
|
||||
|
||||
|
||||
local items = GetEquipmentForRole(ply:GetRole())
|
||||
|
||||
local to_select = nil
|
||||
for k, item in pairs(items) do
|
||||
local ic = nil
|
||||
|
||||
-- Create icon panel
|
||||
if item.material then
|
||||
if item.custom then
|
||||
-- Custom marker icon
|
||||
ic = vgui.Create("LayeredIcon", dlist)
|
||||
|
||||
local marker = vgui.Create("DImage")
|
||||
marker:SetImage("vgui/ttt/custom_marker")
|
||||
marker.PerformLayout = function(s)
|
||||
s:AlignBottom(2)
|
||||
s:AlignRight(2)
|
||||
s:SetSize(16, 16)
|
||||
end
|
||||
marker:SetTooltip(GetTranslation("equip_custom"))
|
||||
|
||||
ic:AddLayer(marker)
|
||||
|
||||
ic:EnableMousePassthrough(marker)
|
||||
elseif not ItemIsWeapon(item) then
|
||||
ic = vgui.Create("SimpleIcon", dlist)
|
||||
else
|
||||
ic = vgui.Create("LayeredIcon", dlist)
|
||||
end
|
||||
|
||||
-- Slot marker icon
|
||||
if ItemIsWeapon(item) then
|
||||
local slot = vgui.Create("SimpleIconLabelled")
|
||||
slot:SetIcon("vgui/ttt/slotcap")
|
||||
slot:SetIconColor(color_slot[ply:GetRole()] or COLOR_GREY)
|
||||
slot:SetIconSize(16)
|
||||
|
||||
slot:SetIconText(item.slot)
|
||||
|
||||
slot:SetIconProperties(COLOR_WHITE,
|
||||
"DefaultBold",
|
||||
{opacity=220, offset=1},
|
||||
{10, 8})
|
||||
|
||||
ic:AddLayer(slot)
|
||||
ic:EnableMousePassthrough(slot)
|
||||
end
|
||||
|
||||
ic:SetIconSize(64)
|
||||
ic:SetIcon(item.material)
|
||||
elseif item.model then
|
||||
ic = vgui.Create("SpawnIcon", dlist)
|
||||
ic:SetModel(item.model)
|
||||
else
|
||||
ErrorNoHalt("Equipment item does not have model or material specified: " .. tostring(item) .. "\n")
|
||||
end
|
||||
|
||||
ic.item = item
|
||||
|
||||
local tip = SafeTranslate(item.name) .. " (" .. SafeTranslate(item.type) .. ")"
|
||||
ic:SetTooltip(tip)
|
||||
|
||||
-- If we cannot order this item, darken it
|
||||
if ((not can_order) or
|
||||
-- already owned
|
||||
table.HasValue(owned_ids, item.id) or
|
||||
(tonumber(item.id) and ply:HasEquipmentItem(tonumber(item.id))) or
|
||||
-- already carrying a weapon for this slot
|
||||
(ItemIsWeapon(item) and (not CanCarryWeapon(item))) or
|
||||
-- already bought the item before
|
||||
(item.limited and ply:HasBought(tostring(item.id)))) then
|
||||
|
||||
ic:SetIconColor(color_darkened)
|
||||
end
|
||||
|
||||
dlist:AddPanel(ic)
|
||||
end
|
||||
|
||||
local dlistw = 216
|
||||
|
||||
local bw, bh = 100, 25
|
||||
|
||||
local dih = h - bh - m*5
|
||||
local diw = w - dlistw - m*6 - 2
|
||||
local dinfobg = vgui.Create("DPanel", dequip)
|
||||
dinfobg:SetPaintBackground(false)
|
||||
dinfobg:SetSize(diw, dih)
|
||||
dinfobg:SetPos(dlistw + m, 0)
|
||||
|
||||
local dinfo = vgui.Create("ColoredBox", dinfobg)
|
||||
dinfo:SetColor(Color(90, 90, 95))
|
||||
dinfo:SetPos(0,0)
|
||||
dinfo:StretchToParent(0, 0, 0, dih - 135)
|
||||
|
||||
local dfields = {}
|
||||
for _, k in ipairs(fieldstbl) do
|
||||
dfields[k] = vgui.Create("DLabel", dinfo)
|
||||
dfields[k]:SetTooltip(GetTranslation("equip_spec_" .. k))
|
||||
dfields[k]:SetPos(m*3, m*2)
|
||||
end
|
||||
|
||||
dfields.name:SetFont("TabLarge")
|
||||
|
||||
dfields.type:SetFont("DermaDefault")
|
||||
dfields.type:MoveBelow(dfields.name)
|
||||
|
||||
dfields.desc:SetFont("DermaDefaultBold")
|
||||
dfields.desc:SetContentAlignment(7)
|
||||
dfields.desc:MoveBelow(dfields.type, 1)
|
||||
|
||||
local iw, ih = dinfo:GetSize()
|
||||
|
||||
local dhelp = vgui.Create("ColoredBox", dinfobg)
|
||||
dhelp:SetColor(Color(90, 90, 95))
|
||||
dhelp:SetSize(diw, dih - 205)
|
||||
dhelp:MoveBelow(dinfo, m)
|
||||
|
||||
local update_preqs = PreqLabels(dhelp, m*3, m*2)
|
||||
|
||||
dhelp:SizeToContents()
|
||||
|
||||
local dconfirm = vgui.Create("DButton", dinfobg)
|
||||
dconfirm:SetPos(0, dih - bh*2)
|
||||
dconfirm:SetSize(bw, bh)
|
||||
dconfirm:SetDisabled(true)
|
||||
dconfirm:SetText(GetTranslation("equip_confirm"))
|
||||
|
||||
|
||||
dsheet:AddSheet(GetTranslation("equip_tabtitle"), dequip, "icon16/bomb.png", false, false, GetTranslation("equip_tooltip_main"))
|
||||
|
||||
-- Item control
|
||||
if ply:HasEquipmentItem(EQUIP_RADAR) then
|
||||
local dradar = RADAR.CreateMenu(dsheet, dframe)
|
||||
dsheet:AddSheet(GetTranslation("radar_name"), dradar, "icon16/magnifier.png", false, false, GetTranslation("equip_tooltip_radar"))
|
||||
end
|
||||
|
||||
if ply:HasEquipmentItem(EQUIP_DISGUISE) then
|
||||
local ddisguise = DISGUISE.CreateMenu(dsheet)
|
||||
dsheet:AddSheet(GetTranslation("disg_name"), ddisguise, "icon16/user.png", false, false, GetTranslation("equip_tooltip_disguise"))
|
||||
end
|
||||
|
||||
-- Weapon/item control
|
||||
if IsValid(ply.radio) or ply:HasWeapon("weapon_ttt_radio") then
|
||||
local dradio = TRADIO.CreateMenu(dsheet)
|
||||
dsheet:AddSheet(GetTranslation("radio_name"), dradio, "icon16/transmit.png", false, false, GetTranslation("equip_tooltip_radio"))
|
||||
end
|
||||
|
||||
-- Credit transferring
|
||||
if credits > 0 then
|
||||
local dtransfer = CreateTransferMenu(dsheet)
|
||||
dsheet:AddSheet(GetTranslation("xfer_name"), dtransfer, "icon16/group_gear.png", false, false, GetTranslation("equip_tooltip_xfer"))
|
||||
end
|
||||
|
||||
hook.Run("TTTEquipmentTabs", dsheet)
|
||||
|
||||
|
||||
-- couple panelselect with info
|
||||
dlist.OnActivePanelChanged = function(self, _, new)
|
||||
for k,v in pairs(new.item) do
|
||||
if dfields[k] then
|
||||
dfields[k]:SetText(SafeTranslate(v))
|
||||
dfields[k]:SizeToContents()
|
||||
end
|
||||
end
|
||||
|
||||
-- Trying to force everything to update to
|
||||
-- the right size is a giant pain, so just
|
||||
-- force a good size.
|
||||
dfields.desc:SetTall(70)
|
||||
|
||||
can_order = update_preqs(new.item)
|
||||
|
||||
dconfirm:SetDisabled(not can_order)
|
||||
end
|
||||
|
||||
-- select first
|
||||
dlist:SelectPanel(to_select or dlist:GetItems()[1])
|
||||
|
||||
-- prep confirm action
|
||||
dconfirm.DoClick = function()
|
||||
local pnl = dlist.SelectedPanel
|
||||
if not pnl or not pnl.item then return end
|
||||
local choice = pnl.item
|
||||
RunConsoleCommand("ttt_order_equipment", choice.id)
|
||||
dframe:Close()
|
||||
end
|
||||
|
||||
-- update some basic info, may have changed in another tab
|
||||
-- specifically the number of credits in the preq list
|
||||
dsheet.OnTabChanged = function(s, old, new)
|
||||
if not IsValid(new) then return end
|
||||
|
||||
if new:GetPanel() == dequip then
|
||||
can_order = update_preqs(dlist.SelectedPanel.item)
|
||||
dconfirm:SetDisabled(not can_order)
|
||||
end
|
||||
end
|
||||
|
||||
local dcancel = vgui.Create("DButton", dframe)
|
||||
dcancel:SetPos(w - 13 - bw, h - bh - 16)
|
||||
dcancel:SetSize(bw, bh)
|
||||
dcancel:SetDisabled(false)
|
||||
dcancel:SetText(GetTranslation("close"))
|
||||
dcancel.DoClick = function() dframe:Close() end
|
||||
|
||||
dframe:MakePopup()
|
||||
dframe:SetKeyboardInputEnabled(false)
|
||||
|
||||
eqframe = dframe
|
||||
end
|
||||
concommand.Add("ttt_cl_traitorpopup", TraitorMenuPopup)
|
||||
|
||||
local function ForceCloseTraitorMenu(ply, cmd, args)
|
||||
if IsValid(eqframe) then
|
||||
eqframe:Close()
|
||||
end
|
||||
end
|
||||
concommand.Add("ttt_cl_traitorpopup_close", ForceCloseTraitorMenu)
|
||||
|
||||
function GM:OnContextMenuOpen()
|
||||
local r = GetRoundState()
|
||||
if r == ROUND_ACTIVE and not (LocalPlayer():GetTraitor() or LocalPlayer():GetDetective()) then
|
||||
return
|
||||
elseif r == ROUND_POST or r == ROUND_PREP then
|
||||
CLSCORE:Toggle()
|
||||
return
|
||||
end
|
||||
|
||||
if IsValid(eqframe) then
|
||||
eqframe:Close()
|
||||
else
|
||||
RunConsoleCommand("ttt_cl_traitorpopup")
|
||||
end
|
||||
end
|
||||
|
||||
local function ReceiveEquipment()
|
||||
local ply = LocalPlayer()
|
||||
if not IsValid(ply) then return end
|
||||
|
||||
ply.equipment_items = net.ReadUInt(16)
|
||||
end
|
||||
net.Receive("TTT_Equipment", ReceiveEquipment)
|
||||
|
||||
local function ReceiveCredits()
|
||||
local ply = LocalPlayer()
|
||||
if not IsValid(ply) then return end
|
||||
|
||||
ply.equipment_credits = net.ReadUInt(8)
|
||||
end
|
||||
net.Receive("TTT_Credits", ReceiveCredits)
|
||||
|
||||
local r = 0
|
||||
local function ReceiveBought()
|
||||
local ply = LocalPlayer()
|
||||
if not IsValid(ply) then return end
|
||||
|
||||
ply.bought = {}
|
||||
local num = net.ReadUInt(8)
|
||||
for i=1,num do
|
||||
local s = net.ReadString()
|
||||
if s != "" then
|
||||
table.insert(ply.bought, s)
|
||||
end
|
||||
end
|
||||
|
||||
-- This usermessage sometimes fails to contain the last weapon that was
|
||||
-- bought, even though resending then works perfectly. Possibly a bug in
|
||||
-- bf_read. Anyway, this hack is a workaround: we just request a new umsg.
|
||||
if num != #ply.bought and r < 10 then -- r is an infinite loop guard
|
||||
RunConsoleCommand("ttt_resend_bought")
|
||||
r = r + 1
|
||||
else
|
||||
r = 0
|
||||
end
|
||||
end
|
||||
net.Receive("TTT_Bought", ReceiveBought)
|
||||
|
||||
-- Player received the item he has just bought, so run clientside init
|
||||
local function ReceiveBoughtItem()
|
||||
local is_item = net.ReadBit() == 1
|
||||
local id = is_item and net.ReadUInt(16) or net.ReadString()
|
||||
|
||||
-- I can imagine custom equipment wanting this, so making a hook
|
||||
hook.Run("TTTBoughtItem", is_item, id)
|
||||
end
|
||||
net.Receive("TTT_BoughtItem", ReceiveBoughtItem)
|
||||
Reference in New Issue
Block a user