This commit is contained in:
lifestorm
2024-08-04 23:12:27 +03:00
parent 0e770b2b49
commit ba1fc01b16
7084 changed files with 2173495 additions and 14 deletions

View File

@@ -0,0 +1,174 @@
--[[
| 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/
--]]
local gradient = ix.util.GetMaterial("vgui/gradient-u")
local gradient2 = ix.util.GetMaterial("vgui/gradient-d")
local PANEL = {}
AccessorFunc(PANEL, "color", "Color")
AccessorFunc(PANEL, "value", "Value", FORCE_NUMBER)
AccessorFunc(PANEL, "boostValue", "Boost", FORCE_NUMBER)
AccessorFunc(PANEL, "max", "Max", FORCE_NUMBER)
function PANEL:Init()
self:SetTall(20)
self.add = self:Add("DImageButton")
self.add:SetSize(16, 16)
self.add:Dock(RIGHT)
self.add:DockMargin(2, 2, 2, 2)
self.add:SetImage("icon16/add.png")
self.add.OnMousePressed = function()
self.pressing = 1
self:DoChange()
self.add:SetAlpha(150)
end
self.add.OnMouseReleased = function()
if (self.pressing) then
self.pressing = nil
self.add:SetAlpha(255)
end
end
self.add.OnCursorExited = self.add.OnMouseReleased
self.sub = self:Add("DImageButton")
self.sub:SetSize(16, 16)
self.sub:Dock(LEFT)
self.sub:DockMargin(2, 2, 2, 2)
self.sub:SetImage("icon16/delete.png")
self.sub.OnMousePressed = function()
self.pressing = -1
self:DoChange()
self.sub:SetAlpha(150)
end
self.sub.OnMouseReleased = function()
if (self.pressing) then
self.pressing = nil
self.sub:SetAlpha(255)
end
end
self.sub.OnCursorExited = self.sub.OnMouseReleased
self.value = 0
self.deltaValue = self.value
self.max = 10
self.bar = self:Add("DPanel")
self.bar:Dock(FILL)
self.bar.Paint = function(this, w, h)
surface.SetDrawColor(35, 35, 35, 250)
surface.DrawRect(0, 0, w, h)
w, h = w - 4, h - 4
local value = self.deltaValue / self.max
if (value > 0) then
local color = self.color and self.color or ix.config.Get("color")
local boostedValue = self.boostValue or 0
local add = 0
if (self.deltaValue != self.value) then
add = 35
end
-- your stat
do
if !(boostedValue < 0 and math.abs(boostedValue) > self.value) then
surface.SetDrawColor(color.r + add, color.g + add, color.b + add, 230)
surface.DrawRect(2, 2, w * value, h)
surface.SetDrawColor(255, 255, 255, 35)
surface.SetMaterial(gradient)
surface.DrawTexturedRect(2, 2, w * value, h)
end
end
-- boosted stat
do
local boostValue
if (boostedValue != 0) then
if (boostedValue < 0) then
local please = math.min(self.value, math.abs(boostedValue))
boostValue = ((please or 0) / self.max) * (self.deltaValue / self.value)
else
boostValue = ((boostedValue or 0) / self.max) * (self.deltaValue / self.value)
end
if (boostedValue < 0) then
surface.SetDrawColor(200, 40, 40, 230)
local bWidth = math.abs(w * boostValue)
surface.DrawRect(2 + w * value - bWidth, 2, bWidth, h)
surface.SetDrawColor(255, 255, 255, 35)
surface.SetMaterial(gradient)
surface.DrawTexturedRect(2 + w * value - bWidth, 2, bWidth, h)
else
surface.SetDrawColor(40, 200, 40, 230)
surface.DrawRect(2 + w * value, 2, w * boostValue, h)
surface.SetDrawColor(255, 255, 255, 35)
surface.SetMaterial(gradient)
surface.DrawTexturedRect(2 + w * value, 2, w * boostValue, h)
end
end
end
end
surface.SetDrawColor(255, 255, 255, 5)
surface.SetMaterial(gradient2)
surface.DrawTexturedRect(2, 2, w, h)
end
self.label = self.bar:Add("DLabel")
self.label:Dock(FILL)
self.label:SetExpensiveShadow(1, Color(0, 0, 60))
self.label:SetContentAlignment(5)
end
function PANEL:Think()
if (self.pressing) then
if ((self.nextPress or 0) < CurTime()) then
self:DoChange()
end
end
self.deltaValue = math.Approach(self.deltaValue, self.value, FrameTime() * 15)
end
function PANEL:DoChange()
if ((self.value == 0 and self.pressing == -1) or (self.value == self.max and self.pressing == 1)) then
return
end
self.nextPress = CurTime() + 0.2
if (self:OnChanged(self.pressing) != false) then
self.value = math.Clamp(self.value + self.pressing, 0, self.max)
end
end
function PANEL:OnChanged(difference)
end
function PANEL:SetText(text)
self.label:SetText(text)
end
function PANEL:SetReadOnly()
self.sub:Remove()
self.add:Remove()
end
vgui.Register("ixAttributeBar", PANEL, "DPanel")

View File

@@ -0,0 +1,207 @@
--[[
| 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/
--]]
-- bar manager
-- this manages positions for bar panels
local PANEL = {}
AccessorFunc(PANEL, "padding", "Padding", FORCE_NUMBER)
function PANEL:Init()
self:SetSize(ScrW() * 0.35, ScrH())
self:SetPos(4, 4)
self:ParentToHUD()
self.bars = {}
self.padding = 2
-- add bars that were registered before manager creation
for _, v in ipairs(ix.bar.list) do
v.panel = self:AddBar(v.index, v.color, v.priority)
end
end
function PANEL:GetAll()
return self.bars
end
function PANEL:Clear()
for k, v in ipairs(self.bars) do
v:Remove()
table.remove(self.bars, k)
end
end
function PANEL:AddBar(index, color, priority)
local panel = self:Add("ixInfoBar")
panel:SetSize(self:GetWide(), BAR_HEIGHT)
panel:SetVisible(false)
panel:SetID(index)
panel:SetColor(color)
panel:SetPriority(priority)
self.bars[#self.bars + 1] = panel
self:Sort()
return panel
end
function PANEL:RemoveBar(panel)
local toRemove
for k, v in ipairs(self.bars) do
if (v == panel) then
toRemove = k
break
end
end
if (toRemove) then
table.remove(self.bars, toRemove)
-- Decrease index value for the next bars
for i = toRemove, #self.bars do
ix.bar.list[i].index = i
self.bars[i]:SetID(i)
end
end
panel:Remove()
self:Sort()
end
-- sort bars by priority
function PANEL:Sort()
table.sort(self.bars, function(a, b)
return a:GetPriority() < b:GetPriority()
end)
end
-- update target Y positions
function PANEL:Organize()
local currentY = 0
for _, v in ipairs(self.bars) do
if (!v:IsVisible()) then
continue
end
v:SetPos(0, currentY)
currentY = currentY + self.padding + v:GetTall()
end
self:SetSize(self:GetWide(), currentY)
end
function PANEL:Think()
local menu = (IsValid(ix.gui.characterMenu) and !ix.gui.characterMenu:IsClosing()) and ix.gui.characterMenu
or IsValid(ix.gui.menu) and ix.gui.menu
local fraction = menu and 1 - menu.currentAlpha / 255 or 1
self:SetAlpha(255 * fraction)
-- don't update bars when not visible
if (fraction == 0) then
return
end
local curTime = CurTime()
local bShouldHide = hook.Run("ShouldHideBars")
local bAlwaysShow = ix.option.Get("alwaysShowBars", false)
for _, v in ipairs(self.bars) do
local info = ix.bar.list[v:GetID()]
local realValue, barText = info.GetValue()
if (bShouldHide or realValue == false) then
v:SetVisible(false)
continue
end
if (v:GetDelta() != realValue) then
v:SetLifetime(curTime + 5)
end
if (v:GetLifetime() < curTime and !info.visible and !bAlwaysShow and !hook.Run("ShouldBarDraw", info)) then
v:SetVisible(false)
continue
end
v:SetVisible(true)
v:SetValue(realValue)
v:SetText(isstring(barText) and barText or "")
end
self:Organize()
end
function PANEL:OnRemove()
self:Clear()
end
vgui.Register("ixInfoBarManager", PANEL, "Panel")
PANEL = {}
AccessorFunc(PANEL, "index", "ID", FORCE_NUMBER)
AccessorFunc(PANEL, "color", "Color")
AccessorFunc(PANEL, "priority", "Priority", FORCE_NUMBER)
AccessorFunc(PANEL, "value", "Value", FORCE_NUMBER)
AccessorFunc(PANEL, "delta", "Delta", FORCE_NUMBER)
AccessorFunc(PANEL, "lifetime", "Lifetime", FORCE_NUMBER)
function PANEL:Init()
self.value = 0
self.delta = 0
self.lifetime = 0
self.bar = self:Add("DPanel")
self.bar:SetPaintedManually(true)
self.bar:Dock(FILL)
self.bar:DockMargin(2, 2, 2, 2)
self.bar.Paint = function(this, width, height)
width = width * math.min(self.delta, 1)
derma.SkinFunc("PaintInfoBar", self, width, height, self.color)
end
self.label = self:Add("DLabel")
self.label:SetFont("ixSmallFont")
self.label:SetContentAlignment(5)
self.label:SetText("")
self.label:SetTextColor(Color(240, 240, 240))
self.label:SetExpensiveShadow(2, Color(20, 20, 20))
self.label:SetPaintedManually(true)
self.label:SizeToContents()
self.label:Dock(FILL)
end
function PANEL:SetText(text)
self.label:SetText(text)
self.label:SizeToContents()
end
function PANEL:Think()
self.delta = math.Approach(self.delta, self.value, FrameTime())
end
function PANEL:Paint(width, height)
derma.SkinFunc("PaintInfoBarBackground", self, width, height)
end
vgui.Register("ixInfoBar", PANEL, "Panel")
if (IsValid(ix.gui.bars)) then
ix.gui.bars:Remove()
ix.gui.bars = vgui.Create("ixInfoBarManager")
end

View File

@@ -0,0 +1,513 @@
--[[
| 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/
--]]
local PANEL = {}
function PANEL:Init()
-- being relative.
local size = 120
self:SetSize(size, size * 1.4)
end
function PANEL:SetItem(itemTable)
self.itemName = L(itemTable.name):lower()
self.price = self:Add("DLabel")
self.price:Dock(BOTTOM)
self.price:SetText(itemTable.price and ix.currency.Get(itemTable.price) or L"free":utf8upper())
self.price:SetContentAlignment(5)
self.price:SetTextColor(color_white)
self.price:SetFont("ixSmallFont")
self.price:SetExpensiveShadow(1, Color(0, 0, 0, 200))
self.name = self:Add("DLabel")
self.name:Dock(TOP)
self.name:SetText(itemTable.GetName and itemTable:GetName() or L(itemTable.name))
self.name:SetContentAlignment(5)
self.name:SetTextColor(color_white)
self.name:SetFont("ixSmallFont")
self.name:SetExpensiveShadow(1, Color(0, 0, 0, 200))
self.name.Paint = function(this, w, h)
surface.SetDrawColor(0, 0, 0, 75)
surface.DrawRect(0, 0, w, h)
end
self.icon = self:Add("SpawnIcon")
self.icon:SetZPos(1)
self.icon:SetSize(self:GetWide(), self:GetWide())
self.icon:Dock(FILL)
self.icon:DockMargin(5, 5, 5, 10)
self.icon:InvalidateLayout(true)
self.icon:SetModel(itemTable:GetModel(), itemTable:GetSkin())
self.icon:SetHelixTooltip(function(tooltip)
ix.hud.PopulateItemTooltip(tooltip, itemTable)
end)
self.icon.itemTable = itemTable
self.icon.DoClick = function(this)
if (IsValid(ix.gui.checkout)) then
return
end
local parent = ix.gui.business
local bAdded = parent:BuyItem(itemTable.uniqueID)
if (bAdded) then
surface.PlaySound("buttons/button14.wav")
end
end
self.icon.PaintOver = function(this)
if (itemTable and itemTable.PaintOver) then
local w, h = this:GetSize()
itemTable.PaintOver(this, itemTable, w, h)
end
end
if ((itemTable.iconCam and !ICON_RENDER_QUEUE[itemTable.uniqueID]) or itemTable.forceRender) then
local iconCam = itemTable.iconCam
iconCam = {
cam_pos = iconCam.pos,
cam_fov = iconCam.fov,
cam_ang = iconCam.ang,
}
ICON_RENDER_QUEUE[itemTable.uniqueID] = true
self.icon:RebuildSpawnIconEx(
iconCam
)
end
end
vgui.Register("ixBusinessItem", PANEL, "DPanel")
PANEL = {}
function PANEL:Init()
ix.gui.business = self
self:SetSize(self:GetParent():GetSize())
self.categories = self:Add("DScrollPanel")
self.categories:Dock(LEFT)
self.categories:SetWide(260)
self.categories.Paint = function(this, w, h)
surface.SetDrawColor(0, 0, 0, 150)
surface.DrawRect(0, 0, w, h)
end
self.categories:DockPadding(5, 5, 5, 5)
self.categories:DockMargin(0, 46, 0, 0)
self.categoryPanels = {}
self.scroll = self:Add("DScrollPanel")
self.scroll:Dock(FILL)
self.search = self:Add("DTextEntry")
self.search:Dock(TOP)
self.search:SetTall(36)
self.search:SetFont("ixMediumFont")
self.search:DockMargin(10 + self:GetWide() * 0.35, 0, 5, 5)
self.search.OnTextChanged = function(this)
local text = self.search:GetText():lower()
if (self.selected) then
self:LoadItems(self.selected.category, text:find("%S") and text or nil)
self.scroll:InvalidateLayout()
end
end
self.search.PaintOver = function(this, cw, ch)
if (self.search:GetValue() == "" and !self.search:HasFocus()) then
ix.util.DrawText("V", 10, ch/2 - 1, color_black, 3, 1, "ixIconsSmall")
end
end
self.itemList = self.scroll:Add("DIconLayout")
self.itemList:Dock(TOP)
self.itemList:DockMargin(10, 1, 5, 5)
self.itemList:SetSpaceX(10)
self.itemList:SetSpaceY(10)
self.itemList:SetMinimumSize(128, 400)
self.checkout = self:Add("DButton")
self.checkout:Dock(BOTTOM)
self.checkout:SetTextColor(color_white)
self.checkout:SetTall(36)
self.checkout:SetFont("ixMediumFont")
self.checkout:DockMargin(10, 10, 0, 0)
self.checkout:SetExpensiveShadow(1, Color(0, 0, 0, 150))
self.checkout:SetText(L("checkout", 0))
self.checkout.DoClick = function()
if (!IsValid(ix.gui.checkout) and self:GetCartCount() > 0) then
vgui.Create("ixBusinessCheckout"):SetCart(self.cart)
end
end
self.cart = {}
local dark = Color(0, 0, 0, 50)
local first = true
for k, v in pairs(ix.item.list) do
if (hook.Run("CanPlayerUseBusiness", LocalPlayer(), k) == false) then
continue
end
if (!self.categoryPanels[L(v.category)]) then
self.categoryPanels[L(v.category)] = v.category
end
end
for category, realName in SortedPairs(self.categoryPanels) do
local button = self.categories:Add("DButton")
button:SetTall(36)
button:SetText(category)
button:Dock(TOP)
button:SetTextColor(color_white)
button:DockMargin(5, 5, 5, 0)
button:SetFont("ixMediumFont")
button:SetExpensiveShadow(1, Color(0, 0, 0, 150))
button.Paint = function(this, w, h)
surface.SetDrawColor(self.selected == this and ix.config.Get("color") or dark)
surface.DrawRect(0, 0, w, h)
surface.SetDrawColor(0, 0, 0, 50)
surface.DrawOutlinedRect(0, 0, w, h)
end
button.DoClick = function(this)
if (self.selected != this) then
self.selected = this
self:LoadItems(realName)
timer.Simple(0.01, function()
self.scroll:InvalidateLayout()
end)
end
end
button.category = realName
if (first) then
self.selected = button
first = false
end
self.categoryPanels[realName] = button
end
if (self.selected) then
self:LoadItems(self.selected.category)
end
end
function PANEL:GetCartCount()
local count = 0
for _, v in pairs(self.cart) do
count = count + v
end
return count
end
function PANEL:BuyItem(uniqueID)
local currentCount = self.cart[uniqueID] or 0
if (currentCount >= 10) then
return false
end
self.cart[uniqueID] = currentCount + 1
self.checkout:SetText(L("checkout", self:GetCartCount()))
return true
end
function PANEL:LoadItems(category, search)
category = category or "misc"
local items = ix.item.list
self.itemList:Clear()
self.itemList:InvalidateLayout(true)
for uniqueID, itemTable in SortedPairsByMemberValue(items, "name") do
if (hook.Run("CanPlayerUseBusiness", LocalPlayer(), uniqueID) == false) then
continue
end
if (itemTable.category == category) then
if (search and search != "" and !L(itemTable.name):lower():find(search, 1, true)) then
continue
end
self.itemList:Add("ixBusinessItem"):SetItem(itemTable)
end
end
end
function PANEL:SetPage()
end
function PANEL:GetPageItems()
end
vgui.Register("ixBusiness", PANEL, "EditablePanel")
DEFINE_BASECLASS("DFrame")
PANEL = {}
function PANEL:Init()
if (IsValid(ix.gui.checkout)) then
ix.gui.checkout:Remove()
end
ix.gui.checkout = self
self:SetTitle(L("checkout", 0))
self:SetSize(ScrW() / 4 > 200 and ScrW() / 4 or ScrW() / 2, ScrH() / 2 > 300 and ScrH() / 2 or ScrH())
self:MakePopup()
self:Center()
self:SetBackgroundBlur(true)
self:SetSizable(true)
self.items = self:Add("DScrollPanel")
self.items:Dock(FILL)
self.items.Paint = function(this, w, h)
surface.SetDrawColor(0, 0, 0, 100)
surface.DrawRect(0, 0, w, h)
end
self.items:DockMargin(0, 0, 0, 4)
self.buy = self:Add("DButton")
self.buy:Dock(BOTTOM)
self.buy:SetText(L"purchase")
self.buy:SetTextColor(color_white)
self.buy.DoClick = function(this)
if ((this.nextClick or 0) < CurTime()) then
this.nextClick = CurTime() + 0.5
else
return
end
if (self.preventBuy) then
self.finalGlow:SetText(self.final:GetText())
self.finalGlow:SetAlpha(255)
self.finalGlow:AlphaTo(0, 0.5)
return surface.PlaySound("buttons/button11.wav")
end
net.Start("ixBusinessBuy")
net.WriteUInt(table.Count(self.itemData), 8)
for k, v in pairs(self.itemData) do
net.WriteString(k)
net.WriteUInt(v, 8)
end
net.SendToServer()
self.itemData = {}
self.items:Remove()
self.data:Remove()
self.buy:Remove()
self:ShowCloseButton(false)
if (IsValid(ix.gui.business)) then
ix.gui.business.cart = {}
ix.gui.business.checkout:SetText(L("checkout", 0))
end
self.text = self:Add("DLabel")
self.text:Dock(FILL)
self.text:SetContentAlignment(5)
self.text:SetTextColor(color_white)
self.text:SetText(L"purchasing")
self.text:SetFont("ixMediumFont")
net.Receive("ixBusinessResponse", function()
if (IsValid(self)) then
self.text:SetText(L"buyGood")
self.done = true
self:ShowCloseButton(true)
surface.PlaySound("buttons/button3.wav")
end
end)
timer.Simple(4, function()
if (IsValid(self) and !self.done) then
self.text:SetText(L"buyFailed")
self:ShowCloseButton(true)
surface.PlaySound("buttons/button11.wav")
end
end)
end
self.data = self:Add("DPanel")
self.data:Dock(BOTTOM)
self.data:SetTall(64)
self.data:DockMargin(0, 0, 0, 4)
self.current = self.data:Add("DLabel")
self.current:SetFont("ixSmallFont")
self.current:SetContentAlignment(6)
self.current:SetTextColor(color_white)
self.current:Dock(TOP)
self.current:SetTextInset(4, 0)
self.total = self.data:Add("DLabel")
self.total:SetFont("ixSmallFont")
self.total:SetContentAlignment(6)
self.total:SetTextColor(color_white)
self.total:Dock(TOP)
self.total:SetTextInset(4, 0)
local line = self.data:Add("DPanel")
line:SetTall(1)
line:DockMargin(128, 0, 4, 0)
line:Dock(TOP)
line.Paint = function(this, w, h)
surface.SetDrawColor(255, 255, 255, 150)
surface.DrawLine(0, 0, w, 0)
end
self.final = self.data:Add("DLabel")
self.final:SetFont("ixSmallFont")
self.final:SetContentAlignment(6)
self.final:SetTextColor(color_white)
self.final:Dock(TOP)
self.final:SetTextInset(4, 0)
self.finalGlow = self.final:Add("DLabel")
self.finalGlow:Dock(FILL)
self.finalGlow:SetFont("ixSmallFont")
self.finalGlow:SetTextColor(color_white)
self.finalGlow:SetContentAlignment(6)
self.finalGlow:SetAlpha(0)
self.finalGlow:SetTextInset(4, 0)
self:SetFocusTopLevel(true)
self.itemData = {}
self:OnQuantityChanged()
end
function PANEL:OnQuantityChanged()
local price = 0
local money = LocalPlayer():GetCharacter():GetMoney()
local valid = 0
for k, v in pairs(self.itemData) do
local itemTable = ix.item.list[k]
if (itemTable and v > 0) then
valid = valid + 1
price = price + (v * (itemTable.price or 0))
end
end
self.current:SetText(L"currentMoney" .. ix.currency.Get(money))
self.total:SetText("- " .. ix.currency.Get(price))
self.final:SetText(L"moneyLeft" .. ix.currency.Get(money - price))
self.final:SetTextColor((money - price) >= 0 and Color(46, 204, 113) or Color(217, 30, 24))
self.preventBuy = (money - price) < 0 or valid == 0
if (IsValid(ix.gui.business)) then
ix.gui.business.checkout:SetText(L("checkout", ix.gui.business:GetCartCount()))
end
end
function PANEL:SetCart(items)
self.itemData = items
for k, v in SortedPairs(items) do
local itemTable = ix.item.list[k]
if (itemTable) then
local slot = self.items:Add("DPanel")
slot:SetTall(36)
slot:Dock(TOP)
slot:DockMargin(5, 5, 5, 0)
slot.icon = slot:Add("SpawnIcon")
slot.icon:SetPos(2, 2)
slot.icon:SetSize(32, 32)
slot.icon:SetModel(itemTable:GetModel())
slot.icon:SetTooltip()
slot.name = slot:Add("DLabel")
slot.name:SetPos(40, 2)
slot.name:SetFont("ixChatFont")
slot.name:SetText(string.format(
"%s (%s)",
L(itemTable.GetName and itemTable:GetName() or L(itemTable.name)),
itemTable.price and ix.currency.Get(itemTable.price) or L"free":utf8upper()
))
slot.name:SetTextColor(color_white)
slot.name:SizeToContents()
slot.name:DockMargin(40, 0, 0, 0)
slot.name:Dock(FILL)
slot.quantity = slot:Add("DTextEntry")
slot.quantity:SetSize(32, 32)
slot.quantity:Dock(RIGHT)
slot.quantity:DockMargin(4, 4, 4, 4)
slot.quantity:SetContentAlignment(5)
slot.quantity:SetNumeric(true)
slot.quantity:SetText(v)
slot.quantity:SetFont("ixChatFont")
slot.quantity.OnTextChanged = function(this)
local value = tonumber(this:GetValue())
if (!value) then
this:SetValue(1)
return
end
value = math.Clamp(math.Round(value), 0, 10)
if (value == 0) then
items[k] = nil
slot:Remove()
else
items[k] = value
end
self:OnQuantityChanged()
end
slot.quantity.OnLoseFocus = function(this)
local value = math.Clamp(tonumber(this:GetValue()) or 1, 0, 10)
this:SetText(value)
end
else
items[k] = nil
end
end
self:OnQuantityChanged()
end
function PANEL:Think()
if (!self:HasFocus()) then
self:MakePopup()
end
BaseClass.Think(self)
end
vgui.Register("ixBusinessCheckout", PANEL, "DFrame")
hook.Add("CreateMenuButtons", "ixBusiness", function(tabs)
if (hook.Run("BuildBusinessMenu") != false) then
tabs["business"] = function(container)
container:Add("ixBusiness")
end
end
end)

View File

@@ -0,0 +1,551 @@
--[[
| 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/
--]]
local gradient = surface.GetTextureID("vgui/gradient-d")
local audioFadeInTime = 2
local animationTime = 0.5
local matrixZScale = Vector(1, 1, 0.0001)
-- character menu panel
DEFINE_BASECLASS("ixSubpanelParent")
local PANEL = {}
function PANEL:Init()
self:SetSize(self:GetParent():GetSize())
self:SetPos(0, 0)
self.childPanels = {}
self.subpanels = {}
self.activeSubpanel = ""
self.currentDimAmount = 0
self.currentY = 0
self.currentScale = 1
self.currentAlpha = 255
self.targetDimAmount = 255
self.targetScale = 0.9
end
function PANEL:Dim(length, callback)
length = length or animationTime
self.currentDimAmount = 0
self:CreateAnimation(length, {
target = {
currentDimAmount = self.targetDimAmount,
currentScale = self.targetScale
},
easing = "outCubic",
OnComplete = callback
})
self:OnDim()
end
function PANEL:Undim(length, callback)
length = length or animationTime
self.currentDimAmount = self.targetDimAmount
self:CreateAnimation(length, {
target = {
currentDimAmount = 0,
currentScale = 1
},
easing = "outCubic",
OnComplete = callback
})
self:OnUndim()
end
function PANEL:OnDim()
end
function PANEL:OnUndim()
end
function PANEL:Paint(width, height)
local amount = self.currentDimAmount
local bShouldScale = self.currentScale != 1
local matrix
-- draw child panels with scaling if needed
if (bShouldScale) then
matrix = Matrix()
matrix:Scale(matrixZScale * self.currentScale)
matrix:Translate(Vector(
ScrW() * 0.5 - (ScrW() * self.currentScale * 0.5),
ScrH() * 0.5 - (ScrH() * self.currentScale * 0.5),
1
))
cam.PushModelMatrix(matrix)
self.currentMatrix = matrix
end
BaseClass.Paint(self, width, height)
if (bShouldScale) then
cam.PopModelMatrix()
self.currentMatrix = nil
end
if (amount > 0) then
local color = Color(0, 0, 0, amount)
surface.SetDrawColor(color)
surface.DrawRect(0, 0, width, height)
end
end
vgui.Register("ixCharMenuPanel", PANEL, "ixSubpanelParent")
-- character menu main button list
PANEL = {}
function PANEL:Init()
local parent = self:GetParent()
self:SetSize(parent:GetWide() * 0.25, parent:GetTall())
self:GetVBar():SetWide(0)
self:GetVBar():SetVisible(false)
end
function PANEL:Add(name)
local panel = vgui.Create(name, self)
panel:Dock(TOP)
return panel
end
function PANEL:SizeToContents()
self:GetCanvas():InvalidateLayout(true)
-- if the canvas has extra space, forcefully dock to the bottom so it doesn't anchor to the top
if (self:GetTall() > self:GetCanvas():GetTall()) then
self:GetCanvas():Dock(BOTTOM)
else
self:GetCanvas():Dock(NODOCK)
end
end
vgui.Register("ixCharMenuButtonList", PANEL, "DScrollPanel")
-- main character menu panel
PANEL = {}
AccessorFunc(PANEL, "bUsingCharacter", "UsingCharacter", FORCE_BOOL)
function PANEL:Init()
local parent = self:GetParent()
local padding = self:GetPadding()
local halfWidth = ScrW() * 0.5
local halfPadding = padding * 0.5
local bHasCharacter = #ix.characters > 0
self.bUsingCharacter = LocalPlayer().GetCharacter and LocalPlayer():GetCharacter()
self:DockPadding(padding, padding, padding, padding)
local infoLabel = self:Add("DLabel")
infoLabel:SetTextColor(Color(255, 255, 255, 25))
infoLabel:SetFont("ixMenuMiniFont")
infoLabel:SetText(L("helix") .. " " .. GAMEMODE.Version)
infoLabel:SizeToContents()
infoLabel:SetPos(ScrW() - infoLabel:GetWide() - 4, ScrH() - infoLabel:GetTall() - 4)
local logoPanel = self:Add("Panel")
logoPanel:SetSize(ScrW(), ScrH() * 0.25)
logoPanel:SetPos(0, ScrH() * 0.25)
logoPanel.Paint = function(panel, width, height)
local matrix = self.currentMatrix
-- don't scale the background because it fucks the blur
if (matrix) then
cam.PopModelMatrix()
end
local newHeight = Lerp(1 - (self.currentDimAmount / 255), 0, height)
local y = height * 0.5 - newHeight * 0.5
local _, screenY = panel:LocalToScreen(0, 0)
screenY = screenY + y
render.SetScissorRect(0, screenY, width, screenY + newHeight, true)
ix.util.DrawBlur(panel, 15, nil, 200)
-- background dim
surface.SetDrawColor(0, 0, 0, 100)
surface.DrawRect(0, y, width, newHeight)
-- border lines
surface.SetDrawColor(ix.config.Get("color") or color_white)
surface.DrawRect(0, y, width, 1)
surface.DrawRect(0, y + newHeight - 1, width, 1)
if (matrix) then
cam.PushModelMatrix(matrix)
end
for _, v in ipairs(panel:GetChildren()) do
v:PaintManual()
end
render.SetScissorRect(0, 0, 0, 0, false)
end
-- draw schema logo material instead of text if available
local logo = Schema.logo and ix.util.GetMaterial(Schema.logo)
if (logo and !logo:IsError()) then
local logoImage = logoPanel:Add("DImage")
logoImage:SetMaterial(logo)
logoImage:SetSize(halfWidth, halfWidth * logo:Height() / logo:Width())
logoImage:SetPos(halfWidth - logoImage:GetWide() * 0.5, halfPadding)
logoImage:SetPaintedManually(true)
logoPanel:SetTall(logoImage:GetTall() + padding)
else
local newHeight = padding
local subtitle = L2("schemaDesc") or Schema.description
local titleLabel = logoPanel:Add("DLabel")
titleLabel:SetTextColor(color_white)
titleLabel:SetFont("ixTitleFont")
titleLabel:SetText(L2("schemaName") or Schema.name or L"unknown")
titleLabel:SizeToContents()
titleLabel:SetPos(halfWidth - titleLabel:GetWide() * 0.5, halfPadding)
titleLabel:SetPaintedManually(true)
newHeight = newHeight + titleLabel:GetTall()
if (subtitle) then
local subtitleLabel = logoPanel:Add("DLabel")
subtitleLabel:SetTextColor(color_white)
subtitleLabel:SetFont("ixSubTitleFont")
subtitleLabel:SetText(subtitle)
subtitleLabel:SizeToContents()
subtitleLabel:SetPos(halfWidth - subtitleLabel:GetWide() * 0.5, 0)
subtitleLabel:MoveBelow(titleLabel)
subtitleLabel:SetPaintedManually(true)
newHeight = newHeight + subtitleLabel:GetTall()
end
logoPanel:SetTall(newHeight)
end
-- button list
self.mainButtonList = self:Add("ixCharMenuButtonList")
self.mainButtonList:Dock(LEFT)
-- create character button
local createButton = self.mainButtonList:Add("ixMenuButton")
createButton:SetText("create")
createButton:SizeToContents()
createButton.DoClick = function()
local maximum = hook.Run("GetMaxPlayerCharacter", LocalPlayer()) or ix.config.Get("maxCharacters", 5)
-- don't allow creation if we've hit the character limit
if (#ix.characters >= maximum) then
self:GetParent():ShowNotice(3, L("maxCharacters"))
return
end
self:Dim()
parent.newCharacterPanel:SetActiveSubpanel("faction", 0)
parent.newCharacterPanel:SlideUp()
end
-- load character button
self.loadButton = self.mainButtonList:Add("ixMenuButton")
self.loadButton:SetText("load")
self.loadButton:SizeToContents()
self.loadButton.DoClick = function()
self:Dim()
parent.loadCharacterPanel:SlideUp()
end
if (!bHasCharacter) then
self.loadButton:SetDisabled(true)
end
-- community button
local extraURL = ix.config.Get("communityURL", "")
local extraText = ix.config.Get("communityText", "@community")
if (extraURL != "" and extraText != "") then
if (extraText:sub(1, 1) == "@") then
extraText = L(extraText:sub(2))
end
local extraButton = self.mainButtonList:Add("ixMenuButton")
extraButton:SetText(extraText, true)
extraButton:SizeToContents()
extraButton.DoClick = function()
gui.OpenURL(extraURL)
end
end
-- leave/return button
self.returnButton = self.mainButtonList:Add("ixMenuButton")
self:UpdateReturnButton()
self.returnButton.DoClick = function()
if (self.bUsingCharacter) then
parent:Close()
else
RunConsoleCommand("disconnect")
end
end
self.mainButtonList:SizeToContents()
end
function PANEL:UpdateReturnButton(bValue)
if (bValue == nil) then
bValue = self.bUsingCharacter
end
self.returnButton:SetText(bValue and "return" or "leave")
self.returnButton:SizeToContents()
end
function PANEL:OnDim()
-- disable input on this panel since it will still be in the background while invisible - prone to stray clicks if the
-- panels overtop slide out of the way
self:SetMouseInputEnabled(false)
self:SetKeyboardInputEnabled(false)
end
function PANEL:OnUndim()
self:SetMouseInputEnabled(true)
self:SetKeyboardInputEnabled(true)
-- we may have just deleted a character so update the status of the return button
self.bUsingCharacter = LocalPlayer().GetCharacter and LocalPlayer():GetCharacter()
self:UpdateReturnButton()
end
function PANEL:OnClose()
for _, v in pairs(self:GetChildren()) do
if (IsValid(v)) then
v:SetVisible(false)
end
end
end
function PANEL:PerformLayout(width, height)
local padding = self:GetPadding()
self.mainButtonList:SetPos(padding, height - self.mainButtonList:GetTall() - padding)
end
vgui.Register("ixCharMenuMain", PANEL, "ixCharMenuPanel")
-- container panel
PANEL = {}
function PANEL:Init()
if (IsValid(ix.gui.loading)) then
ix.gui.loading:Remove()
end
if (IsValid(ix.gui.characterMenu)) then
if (IsValid(ix.gui.characterMenu.channel)) then
ix.gui.characterMenu.channel:Stop()
end
ix.gui.characterMenu:Remove()
end
self:SetSize(ScrW(), ScrH())
self:SetPos(0, 0)
-- main menu panel
self.mainPanel = self:Add("ixCharMenuMain")
-- new character panel
self.newCharacterPanel = self:Add("ixCharMenuNew")
self.newCharacterPanel:SlideDown(0)
-- load character panel
self.loadCharacterPanel = self:Add("ixCharMenuLoad")
self.loadCharacterPanel:SlideDown(0)
-- notice bar
self.notice = self:Add("ixNoticeBar")
-- finalization
self:MakePopup()
self.currentAlpha = 255
self.volume = 0
ix.gui.characterMenu = self
if (!IsValid(ix.gui.intro)) then
self:PlayMusic()
end
hook.Run("OnCharacterMenuCreated", self)
end
function PANEL:PlayMusic()
local path = "sound/" .. ix.config.Get("music")
local url = path:match("http[s]?://.+")
local play = url and sound.PlayURL or sound.PlayFile
path = url and url or path
play(path, "noplay", function(channel, error, message)
if (!IsValid(channel)) then
return
end
channel:SetVolume(self.volume or 0)
channel:Play()
self.channel = channel
self:CreateAnimation(audioFadeInTime, {
index = 10,
target = {volume = 1},
Think = function(animation, panel)
if (IsValid(panel.channel)) then
panel.channel:SetVolume(self.volume * 0.5)
end
end
})
end)
end
function PANEL:ShowNotice(type, text)
self.notice:SetType(type)
self.notice:SetText(text)
self.notice:Show()
end
function PANEL:HideNotice()
if (IsValid(self.notice) and !self.notice:GetHidden()) then
self.notice:Slide("up", 0.5, true)
end
end
function PANEL:OnCharacterDeleted(character)
if (#ix.characters == 0) then
self.mainPanel.loadButton:SetDisabled(true)
self.mainPanel:Undim() -- undim since the load panel will slide down
else
self.mainPanel.loadButton:SetDisabled(false)
end
self.loadCharacterPanel:OnCharacterDeleted(character)
end
function PANEL:OnCharacterLoadFailed(error)
self.loadCharacterPanel:SetMouseInputEnabled(true)
self.loadCharacterPanel:SlideUp()
self:ShowNotice(3, error)
end
function PANEL:IsClosing()
return self.bClosing
end
function PANEL:Close(bFromMenu)
self.bClosing = true
self.bFromMenu = bFromMenu
local fadeOutTime = animationTime * 8
self:CreateAnimation(fadeOutTime, {
index = 1,
target = {currentAlpha = 0},
Think = function(animation, panel)
panel:SetAlpha(panel.currentAlpha)
end,
OnComplete = function(animation, panel)
panel:Remove()
end
})
self:CreateAnimation(fadeOutTime - 0.1, {
index = 10,
target = {volume = 0},
Think = function(animation, panel)
if (IsValid(panel.channel)) then
panel.channel:SetVolume(self.volume * 0.5)
end
end,
OnComplete = function(animation, panel)
if (IsValid(panel.channel)) then
panel.channel:Stop()
panel.channel = nil
end
end
})
-- hide children if we're already dimmed
if (bFromMenu) then
for _, v in pairs(self:GetChildren()) do
if (IsValid(v)) then
v:SetVisible(false)
end
end
else
-- fade out the main panel quicker because it significantly blocks the screen
self.mainPanel.currentAlpha = 255
self.mainPanel:CreateAnimation(animationTime * 2, {
target = {currentAlpha = 0},
easing = "outQuint",
Think = function(animation, panel)
panel:SetAlpha(panel.currentAlpha)
end,
OnComplete = function(animation, panel)
panel:SetVisible(false)
end
})
end
-- relinquish mouse control
self:SetMouseInputEnabled(false)
self:SetKeyboardInputEnabled(false)
gui.EnableScreenClicker(false)
end
function PANEL:Paint(width, height)
surface.SetTexture(gradient)
surface.SetDrawColor(0, 0, 0, 255)
surface.DrawTexturedRect(0, 0, width, height)
if (!ix.option.Get("cheapBlur", false)) then
surface.SetDrawColor(0, 0, 0, 150)
surface.DrawTexturedRect(0, 0, width, height)
ix.util.DrawBlur(self, Lerp((self.currentAlpha - 200) / 255, 0, 10))
end
end
function PANEL:PaintOver(width, height)
if (self.bClosing and self.bFromMenu) then
surface.SetDrawColor(color_black)
surface.DrawRect(0, 0, width, height)
end
end
vgui.Register("ixCharMenu", PANEL, "EditablePanel")
if (IsValid(ix.gui.characterMenu)) then
ix.gui.characterMenu:Remove()
--TODO: REMOVE ME
ix.gui.characterMenu = vgui.Create("ixCharMenu")
end

View File

@@ -0,0 +1,509 @@
--[[
| 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/
--]]
local padding = ScreenScale(32)
-- create character panel
DEFINE_BASECLASS("ixCharMenuPanel")
local PANEL = {}
function PANEL:Init()
local parent = self:GetParent()
local halfWidth = parent:GetWide() * 0.5 - (padding * 2)
local halfHeight = parent:GetTall() * 0.5 - (padding * 2)
local modelFOV = (ScrW() > ScrH() * 1.8) and 100 or 78
self:ResetPayload(true)
self.factionButtons = {}
self.repopulatePanels = {}
-- faction selection subpanel
self.factionPanel = self:AddSubpanel("faction", true)
self.factionPanel:SetTitle("chooseFaction")
self.factionPanel.OnSetActive = function()
-- if we only have one faction, we are always selecting that one so we can skip to the description section
if (#self.factionButtons == 1) then
self:SetActiveSubpanel("description", 0)
end
end
local modelList = self.factionPanel:Add("Panel")
modelList:Dock(RIGHT)
modelList:SetSize(halfWidth + padding * 2, halfHeight)
local proceed = modelList:Add("ixMenuButton")
proceed:SetText("proceed")
proceed:SetContentAlignment(6)
proceed:Dock(BOTTOM)
proceed:SizeToContents()
proceed.DoClick = function()
self.progress:IncrementProgress()
self:Populate()
self:SetActiveSubpanel("description")
end
self.factionModel = modelList:Add("ixModelPanel")
self.factionModel:Dock(FILL)
self.factionModel:SetModel("models/error.mdl")
self.factionModel:SetFOV(modelFOV)
self.factionModel.PaintModel = self.factionModel.Paint
self.factionButtonsPanel = self.factionPanel:Add("ixCharMenuButtonList")
self.factionButtonsPanel:SetWide(halfWidth)
self.factionButtonsPanel:Dock(FILL)
local factionBack = self.factionPanel:Add("ixMenuButton")
factionBack:SetText("return")
factionBack:SizeToContents()
factionBack:Dock(BOTTOM)
factionBack.DoClick = function()
self.progress:DecrementProgress()
self:SetActiveSubpanel("faction", 0)
self:SlideDown()
parent.mainPanel:Undim()
end
-- character customization subpanel
self.description = self:AddSubpanel("description")
self.description:SetTitle("chooseDescription")
local descriptionModelList = self.description:Add("Panel")
descriptionModelList:Dock(LEFT)
descriptionModelList:SetSize(halfWidth, halfHeight)
local descriptionBack = descriptionModelList:Add("ixMenuButton")
descriptionBack:SetText("return")
descriptionBack:SetContentAlignment(4)
descriptionBack:SizeToContents()
descriptionBack:Dock(BOTTOM)
descriptionBack.DoClick = function()
self.progress:DecrementProgress()
if (#self.factionButtons == 1) then
factionBack:DoClick()
else
self:SetActiveSubpanel("faction")
end
end
self.descriptionModel = descriptionModelList:Add("ixModelPanel")
self.descriptionModel:Dock(FILL)
self.descriptionModel:SetModel(self.factionModel:GetModel())
self.descriptionModel:SetFOV(modelFOV - 13)
self.descriptionModel.PaintModel = self.descriptionModel.Paint
self.descriptionPanel = self.description:Add("Panel")
self.descriptionPanel:SetWide(halfWidth + padding * 2)
self.descriptionPanel:Dock(RIGHT)
local descriptionProceed = self.descriptionPanel:Add("ixMenuButton")
descriptionProceed:SetText("proceed")
descriptionProceed:SetContentAlignment(6)
descriptionProceed:SizeToContents()
descriptionProceed:Dock(BOTTOM)
descriptionProceed.DoClick = function()
if (self:VerifyProgression("description")) then
-- there are no panels on the attributes section other than the create button, so we can just create the character
if (#self.attributesPanel:GetChildren() < 2) then
self:SendPayload()
return
end
self.progress:IncrementProgress()
self:SetActiveSubpanel("attributes")
end
end
-- attributes subpanel
self.attributes = self:AddSubpanel("attributes")
self.attributes:SetTitle("chooseSkills")
local attributesModelList = self.attributes:Add("Panel")
attributesModelList:Dock(LEFT)
attributesModelList:SetSize(halfWidth, halfHeight)
local attributesBack = attributesModelList:Add("ixMenuButton")
attributesBack:SetText("return")
attributesBack:SetContentAlignment(4)
attributesBack:SizeToContents()
attributesBack:Dock(BOTTOM)
attributesBack.DoClick = function()
self.progress:DecrementProgress()
self:SetActiveSubpanel("description")
end
self.attributesModel = attributesModelList:Add("ixModelPanel")
self.attributesModel:Dock(FILL)
self.attributesModel:SetModel(self.factionModel:GetModel())
self.attributesModel:SetFOV(modelFOV - 13)
self.attributesModel.PaintModel = self.attributesModel.Paint
self.attributesPanel = self.attributes:Add("Panel")
self.attributesPanel:SetWide(halfWidth + padding * 2)
self.attributesPanel:Dock(RIGHT)
local create = self.attributesPanel:Add("ixMenuButton")
create:SetText("finish")
create:SetContentAlignment(6)
create:SizeToContents()
create:Dock(BOTTOM)
create.DoClick = function()
self:SendPayload()
end
-- creation progress panel
self.progress = self:Add("ixSegmentedProgress")
self.progress:SetBarColor(ix.config.Get("color"))
self.progress:SetSize(parent:GetWide(), 0)
self.progress:SizeToContents()
self.progress:SetPos(0, parent:GetTall() - self.progress:GetTall())
-- setup payload hooks
self:AddPayloadHook("model", function(value)
local faction = ix.faction.indices[self.payload.faction]
if (faction) then
local model = faction:GetModels(LocalPlayer())[value]
-- assuming bodygroups
if (istable(model)) then
self.factionModel:SetModel(model[1], model[2] or 0, model[3])
self.descriptionModel:SetModel(model[1], model[2] or 0, model[3])
self.attributesModel:SetModel(model[1], model[2] or 0, model[3])
else
self.factionModel:SetModel(model)
self.descriptionModel:SetModel(model)
self.attributesModel:SetModel(model)
end
end
end)
-- setup character creation hooks
net.Receive("ixCharacterAuthed", function()
timer.Remove("ixCharacterCreateTimeout")
self.awaitingResponse = false
local id = net.ReadUInt(32)
local indices = net.ReadUInt(6)
local charList = {}
for _ = 1, indices do
charList[#charList + 1] = net.ReadUInt(32)
end
ix.characters = charList
self:SlideDown()
if (!IsValid(self) or !IsValid(parent)) then
return
end
if (LocalPlayer():GetCharacter()) then
parent.mainPanel:Undim()
parent:ShowNotice(2, L("charCreated"))
elseif (id) then
self.bMenuShouldClose = true
net.Start("ixCharacterChoose")
net.WriteUInt(id, 32)
net.SendToServer()
else
self:SlideDown()
end
end)
net.Receive("ixCharacterAuthFailed", function()
timer.Remove("ixCharacterCreateTimeout")
self.awaitingResponse = false
local fault = net.ReadString()
local args = net.ReadTable()
self:SlideDown()
parent.mainPanel:Undim()
parent:ShowNotice(3, L(fault, unpack(args)))
end)
end
function PANEL:SendPayload()
if (self.awaitingResponse or !self:VerifyProgression()) then
return
end
self.awaitingResponse = true
timer.Create("ixCharacterCreateTimeout", 10, 1, function()
if (IsValid(self) and self.awaitingResponse) then
local parent = self:GetParent()
self.awaitingResponse = false
self:SlideDown()
parent.mainPanel:Undim()
parent:ShowNotice(3, L("unknownError"))
end
end)
self.payload:Prepare()
net.Start("ixCharacterCreate")
net.WriteUInt(table.Count(self.payload), 8)
for k, v in pairs(self.payload) do
net.WriteString(k)
net.WriteType(v)
end
net.SendToServer()
end
function PANEL:OnSlideUp()
self:ResetPayload()
self:Populate()
self.progress:SetProgress(1)
-- the faction subpanel will skip to next subpanel if there is only one faction to choose from,
-- so we don't have to worry about it here
self:SetActiveSubpanel("faction", 0)
end
function PANEL:OnSlideDown()
end
function PANEL:ResetPayload(bWithHooks)
if (bWithHooks) then
self.hooks = {}
end
self.payload = {}
-- TODO: eh..
function self.payload.Set(payload, key, value)
self:SetPayload(key, value)
end
function self.payload.AddHook(payload, key, callback)
self:AddPayloadHook(key, callback)
end
function self.payload.Prepare(payload)
self.payload.Set = nil
self.payload.AddHook = nil
self.payload.Prepare = nil
end
end
function PANEL:SetPayload(key, value)
self.payload[key] = value
self:RunPayloadHook(key, value)
end
function PANEL:AddPayloadHook(key, callback)
if (!self.hooks[key]) then
self.hooks[key] = {}
end
self.hooks[key][#self.hooks[key] + 1] = callback
end
function PANEL:RunPayloadHook(key, value)
local hooks = self.hooks[key] or {}
for _, v in ipairs(hooks) do
v(value)
end
end
function PANEL:GetContainerPanel(name)
-- TODO: yuck
if (name == "description") then
return self.descriptionPanel
elseif (name == "attributes") then
return self.attributesPanel
end
return self.descriptionPanel
end
function PANEL:AttachCleanup(panel)
self.repopulatePanels[#self.repopulatePanels + 1] = panel
end
function PANEL:Populate()
if (!self.bInitialPopulate) then
-- setup buttons for the faction panel
-- TODO: make this a bit less janky
local lastSelected
for _, v in pairs(self.factionButtons) do
if (v:GetSelected()) then
lastSelected = v.faction
end
if (IsValid(v)) then
v:Remove()
end
end
self.factionButtons = {}
for _, v in SortedPairs(ix.faction.teams) do
if (ix.faction.HasWhitelist(v.index)) then
local button = self.factionButtonsPanel:Add("ixMenuSelectionButton")
button:SetBackgroundColor(v.color or color_white)
button:SetText(L(v.name):utf8upper())
button:SizeToContents()
button:SetButtonList(self.factionButtons)
button.faction = v.index
button.OnSelected = function(panel)
local faction = ix.faction.indices[panel.faction]
local models = faction:GetModels(LocalPlayer())
self.payload:Set("faction", panel.faction)
self.payload:Set("model", math.random(1, #models))
end
if ((lastSelected and lastSelected == v.index) or (!lastSelected and v.isDefault)) then
button:SetSelected(true)
lastSelected = v.index
end
end
end
end
-- remove panels created for character vars
for i = 1, #self.repopulatePanels do
self.repopulatePanels[i]:Remove()
end
self.repopulatePanels = {}
-- payload is empty because we attempted to send it - for whatever reason we're back here again so we need to repopulate
if (!self.payload.faction) then
for _, v in pairs(self.factionButtons) do
if (v:GetSelected()) then
v:SetSelected(true)
break
end
end
end
self.factionButtonsPanel:SizeToContents()
local zPos = 1
-- set up character vars
for k, v in SortedPairsByMemberValue(ix.char.vars, "index") do
if (!v.bNoDisplay and k != "__SortedIndex") then
local container = self:GetContainerPanel(v.category or "description")
if (v.ShouldDisplay and v:ShouldDisplay(container, self.payload) == false) then
continue
end
local panel
-- if the var has a custom way of displaying, we'll use that instead
if (v.OnDisplay) then
panel = v:OnDisplay(container, self.payload)
elseif (isstring(v.default)) then
panel = container:Add("ixTextEntry")
panel:Dock(TOP)
panel:SetFont("ixMenuButtonHugeFont")
panel:SetUpdateOnType(true)
panel.OnValueChange = function(this, text)
self.payload:Set(k, text)
end
end
if (IsValid(panel)) then
-- add label for entry
local label = container:Add("DLabel")
label:SetFont("ixMenuButtonLabelFont")
label:SetText(L(k):utf8upper())
label:SizeToContents()
label:DockMargin(0, 16, 0, 2)
label:Dock(TOP)
-- we need to set the docking order so the label is above the panel
label:SetZPos(zPos - 1)
panel:SetZPos(zPos)
self:AttachCleanup(label)
self:AttachCleanup(panel)
if (v.OnPostSetup) then
v:OnPostSetup(panel, self.payload)
end
zPos = zPos + 2
end
end
end
if (!self.bInitialPopulate) then
-- setup progress bar segments
if (#self.factionButtons > 1) then
self.progress:AddSegment("@faction")
end
self.progress:AddSegment("@description")
if (#self.attributesPanel:GetChildren() > 1) then
self.progress:AddSegment("@skills")
end
-- we don't need to show the progress bar if there's only one segment
if (#self.progress:GetSegments() == 1) then
self.progress:SetVisible(false)
end
end
self.bInitialPopulate = true
end
function PANEL:VerifyProgression(name)
for k, v in SortedPairsByMemberValue(ix.char.vars, "index") do
if (name ~= nil and (v.category or "description") != name) then
continue
end
local value = self.payload[k]
if (!v.bNoDisplay or v.OnValidate) then
if (v.OnValidate) then
local result = {v:OnValidate(value, self.payload, LocalPlayer())}
if (result[1] == false) then
self:GetParent():ShowNotice(3, L(unpack(result, 2)))
return false
end
end
self.payload[k] = value
end
end
return true
end
function PANEL:Paint(width, height)
derma.SkinFunc("PaintCharacterCreateBackground", self, width, height)
BaseClass.Paint(self, width, height)
end
vgui.Register("ixCharMenuNew", PANEL, "ixCharMenuPanel")

View File

@@ -0,0 +1,486 @@
--[[
| 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/
--]]
local errorModel = "models/error.mdl"
local PANEL = {}
AccessorFunc(PANEL, "animationTime", "AnimationTime", FORCE_NUMBER)
local function SetCharacter(self, character)
self.character = character
if (character) then
self:SetModel(character:GetModel())
self:SetSkin(character:GetData("skin", 0))
for i = 0, (self:GetNumBodyGroups() - 1) do
self:SetBodygroup(i, 0)
end
local bodygroups = character:GetData("groups", nil)
if (istable(bodygroups)) then
for k, v in pairs(bodygroups) do
self:SetBodygroup(k, v)
end
end
else
self:SetModel(errorModel)
end
end
local function GetCharacter(self)
return self.character
end
function PANEL:Init()
self.activeCharacter = ClientsideModel(errorModel)
self.activeCharacter:SetNoDraw(true)
self.activeCharacter.SetCharacter = SetCharacter
self.activeCharacter.GetCharacter = GetCharacter
self.lastCharacter = ClientsideModel(errorModel)
self.lastCharacter:SetNoDraw(true)
self.lastCharacter.SetCharacter = SetCharacter
self.lastCharacter.GetCharacter = GetCharacter
self.animationTime = 0.5
self.shadeY = 0
self.shadeHeight = 0
self.cameraPosition = Vector(80, 0, 35)
self.cameraAngle = Angle(0, 180, 0)
self.lastPaint = 0
end
function PANEL:ResetSequence(model, lastModel)
local sequence = model:LookupSequence("idle_unarmed")
if (sequence <= 0) then
sequence = model:SelectWeightedSequence(ACT_IDLE)
end
if (sequence > 0) then
model:ResetSequence(sequence)
else
local found = false
for _, v in ipairs(model:GetSequenceList()) do
if ((v:lower():find("idle") or v:lower():find("fly")) and v != "idlenoise") then
model:ResetSequence(v)
found = true
break
end
end
if (!found) then
model:ResetSequence(4)
end
end
model:SetIK(false)
-- copy cycle if we can to avoid a jarring transition from resetting the sequence
if (lastModel) then
model:SetCycle(lastModel:GetCycle())
end
end
function PANEL:RunAnimation(model)
model:FrameAdvance((RealTime() - self.lastPaint) * 0.5)
end
function PANEL:LayoutEntity(model)
model:SetIK(false)
self:RunAnimation(model)
end
function PANEL:SetActiveCharacter(character)
self.shadeY = self:GetTall()
self.shadeHeight = self:GetTall()
-- set character immediately if we're an error (something isn't selected yet)
if (self.activeCharacter:GetModel() == errorModel) then
self.activeCharacter:SetCharacter(character)
self:ResetSequence(self.activeCharacter)
return
end
-- if the animation is already playing, we update its parameters so we can avoid restarting
local shade = self:GetTweenAnimation(1)
local shadeHide = self:GetTweenAnimation(2)
if (shade) then
shade.newCharacter = character
return
elseif (shadeHide) then
shadeHide.queuedCharacter = character
return
end
self.lastCharacter:SetCharacter(self.activeCharacter:GetCharacter())
self:ResetSequence(self.lastCharacter, self.activeCharacter)
shade = self:CreateAnimation(self.animationTime * 0.5, {
index = 1,
target = {
shadeY = 0,
shadeHeight = self:GetTall()
},
easing = "linear",
OnComplete = function(shadeAnimation, shadePanel)
shadePanel.activeCharacter:SetCharacter(shadeAnimation.newCharacter)
shadePanel:ResetSequence(shadePanel.activeCharacter)
shadePanel:CreateAnimation(shadePanel.animationTime, {
index = 2,
target = {shadeHeight = 0},
easing = "outQuint",
OnComplete = function(animation, panel)
if (animation.queuedCharacter) then
panel:SetActiveCharacter(animation.queuedCharacter)
else
panel.lastCharacter:SetCharacter(nil)
end
end
})
end
})
shade.newCharacter = character
end
function PANEL:Paint(width, height)
local x, y = self:LocalToScreen(0, 0)
local bTransition = self.lastCharacter:GetModel() != errorModel
local modelFOV = (ScrW() > ScrH() * 1.8) and 92 or 70
cam.Start3D(self.cameraPosition, self.cameraAngle, modelFOV, x, y, width, height)
render.SuppressEngineLighting(true)
render.SetLightingOrigin(self.activeCharacter:GetPos())
-- setup lighting
render.SetModelLighting(0, 1.5, 1.5, 1.5)
for i = 1, 4 do
render.SetModelLighting(i, 0.4, 0.4, 0.4)
end
render.SetModelLighting(5, 0.04, 0.04, 0.04)
-- clip anything out of bounds
local curparent = self
local rightx = self:GetWide()
local leftx = 0
local topy = 0
local bottomy = self:GetTall()
local previous = curparent
while (curparent:GetParent() != nil) do
local lastX, lastY = previous:GetPos()
curparent = curparent:GetParent()
topy = math.Max(lastY, topy + lastY)
leftx = math.Max(lastX, leftx + lastX)
bottomy = math.Min(lastY + previous:GetTall(), bottomy + lastY)
rightx = math.Min(lastX + previous:GetWide(), rightx + lastX)
previous = curparent
end
ix.util.ResetStencilValues()
render.SetStencilEnable(true)
render.SetStencilWriteMask(30)
render.SetStencilTestMask(30)
render.SetStencilReferenceValue(31)
render.SetStencilCompareFunction(STENCIL_ALWAYS)
render.SetStencilPassOperation(STENCIL_REPLACE)
render.SetStencilFailOperation(STENCIL_KEEP)
render.SetStencilZFailOperation(STENCIL_KEEP)
self:LayoutEntity(self.activeCharacter)
if (bTransition) then
-- only need to layout while it's used
self:LayoutEntity(self.lastCharacter)
render.SetScissorRect(leftx, topy, rightx, bottomy - (self:GetTall() - self.shadeHeight), true)
self.lastCharacter:DrawModel()
render.SetScissorRect(leftx, topy + self.shadeHeight, rightx, bottomy, true)
self.activeCharacter:DrawModel()
render.SetScissorRect(leftx, topy, rightx, bottomy, true)
else
self.activeCharacter:DrawModel()
end
render.SetStencilCompareFunction(STENCIL_EQUAL)
render.SetStencilPassOperation(STENCIL_KEEP)
cam.Start2D()
derma.SkinFunc("PaintCharacterTransitionOverlay", self, 0, self.shadeY, width, self.shadeHeight)
cam.End2D()
render.SetStencilEnable(false)
render.SetScissorRect(0, 0, 0, 0, false)
render.SuppressEngineLighting(false)
cam.End3D()
self.lastPaint = RealTime()
end
function PANEL:OnRemove()
self.lastCharacter:Remove()
self.activeCharacter:Remove()
end
vgui.Register("ixCharMenuCarousel", PANEL, "Panel")
-- character load panel
PANEL = {}
AccessorFunc(PANEL, "animationTime", "AnimationTime", FORCE_NUMBER)
AccessorFunc(PANEL, "backgroundFraction", "BackgroundFraction", FORCE_NUMBER)
function PANEL:Init()
local parent = self:GetParent()
local padding = self:GetPadding()
local halfWidth = parent:GetWide() * 0.5 - (padding * 2)
local halfHeight = parent:GetTall() * 0.5 - (padding * 2)
local modelFOV = (ScrW() > ScrH() * 1.8) and 102 or 78
self.animationTime = 1
self.backgroundFraction = 1
-- main panel
self.panel = self:AddSubpanel("main")
self.panel:SetTitle("loadTitle")
self.panel.OnSetActive = function()
self:CreateAnimation(self.animationTime, {
index = 2,
target = {backgroundFraction = 1},
easing = "outQuint",
})
end
-- character button list
local controlList = self.panel:Add("Panel")
controlList:Dock(LEFT)
controlList:SetSize(halfWidth, halfHeight)
local back = controlList:Add("ixMenuButton")
back:Dock(BOTTOM)
back:SetText("return")
back:SizeToContents()
back.DoClick = function()
self:SlideDown()
parent.mainPanel:Undim()
end
self.characterList = controlList:Add("ixCharMenuButtonList")
self.characterList.buttons = {}
self.characterList:Dock(FILL)
-- right-hand side with carousel and buttons
local infoPanel = self.panel:Add("Panel")
infoPanel:Dock(FILL)
local infoButtons = infoPanel:Add("Panel")
infoButtons:Dock(BOTTOM)
infoButtons:SetTall(back:GetTall()) -- hmm...
local continueButton = infoButtons:Add("ixMenuButton")
continueButton:Dock(FILL)
continueButton:SetText("choose")
continueButton:SetContentAlignment(6)
continueButton:SizeToContents()
continueButton.DoClick = function()
self:SetMouseInputEnabled(false)
self:Slide("down", self.animationTime, function()
net.Start("ixCharacterChoose")
net.WriteUInt(self.character:GetID(), 32)
net.SendToServer()
end, true)
end
local deleteButton = infoButtons:Add("ixMenuButton")
deleteButton:Dock(LEFT)
deleteButton:SetText("delete")
deleteButton:SetContentAlignment(5)
deleteButton:SetTextInset(0, 0)
deleteButton:SizeToContents()
deleteButton:SetTextColor(derma.GetColor("Error", deleteButton))
deleteButton.DoClick = function()
self:SetActiveSubpanel("delete")
end
self.carousel = infoPanel:Add("ixCharMenuCarousel")
self.carousel:Dock(FILL)
-- character deletion panel
self.delete = self:AddSubpanel("delete")
self.delete:SetTitle(nil)
self.delete.OnSetActive = function()
self.deleteModel:SetModel(self.character:GetModel())
self:CreateAnimation(self.animationTime, {
index = 2,
target = {backgroundFraction = 0},
easing = "outQuint"
})
end
local deleteInfo = self.delete:Add("Panel")
deleteInfo:SetSize(parent:GetWide() * 0.5, parent:GetTall())
deleteInfo:Dock(LEFT)
local deleteReturn = deleteInfo:Add("ixMenuButton")
deleteReturn:Dock(BOTTOM)
deleteReturn:SetText("no")
deleteReturn:SizeToContents()
deleteReturn.DoClick = function()
self:SetActiveSubpanel("main")
end
local deleteConfirm = self.delete:Add("ixMenuButton")
deleteConfirm:Dock(BOTTOM)
deleteConfirm:SetText("yes")
deleteConfirm:SetContentAlignment(6)
deleteConfirm:SizeToContents()
deleteConfirm:SetTextColor(derma.GetColor("Error", deleteConfirm))
deleteConfirm.DoClick = function()
local id = self.character:GetID()
parent:ShowNotice(1, L("deleteComplete", self.character:GetName()))
self:Populate(id)
self:SetActiveSubpanel("main")
net.Start("ixCharacterDelete")
net.WriteUInt(id, 32)
net.SendToServer()
end
self.deleteModel = deleteInfo:Add("ixModelPanel")
self.deleteModel:Dock(FILL)
self.deleteModel:SetModel(errorModel)
self.deleteModel:SetFOV(modelFOV)
self.deleteModel.PaintModel = self.deleteModel.Paint
local deleteNag = self.delete:Add("Panel")
deleteNag:SetTall(parent:GetTall() * 0.5)
deleteNag:Dock(BOTTOM)
local deleteTitle = deleteNag:Add("DLabel")
deleteTitle:SetFont("ixTitleFont")
deleteTitle:SetText(L("areYouSure"):utf8upper())
deleteTitle:SetTextColor(ix.config.Get("color"))
deleteTitle:SizeToContents()
deleteTitle:Dock(TOP)
local deleteText = deleteNag:Add("DLabel")
deleteText:SetFont("ixMenuButtonFont")
deleteText:SetText(L("deleteConfirm"))
deleteText:SetTextColor(color_white)
deleteText:SetContentAlignment(7)
deleteText:Dock(FILL)
-- finalize setup
self:SetActiveSubpanel("main", 0)
end
function PANEL:OnCharacterDeleted(character)
if (self.bActive and #ix.characters == 0) then
self:SlideDown()
end
end
function PANEL:Populate(ignoreID)
self.characterList:Clear()
self.characterList.buttons = {}
local bSelected
-- loop backwards to preserve order since we're docking to the bottom
for i = 1, #ix.characters do
local id = ix.characters[i]
local character = ix.char.loaded[id]
if (!character or character:GetID() == ignoreID) then
continue
end
local index = character:GetFaction()
local faction = ix.faction.indices[index]
local color = faction and faction.color or color_white
local button = self.characterList:Add("ixMenuSelectionButton")
button:SetBackgroundColor(color)
button:SetText(character:GetName())
button:SizeToContents()
button:SetButtonList(self.characterList.buttons)
button.character = character
button.OnSelected = function(panel)
self:OnCharacterButtonSelected(panel)
end
-- select currently loaded character if available
local localCharacter = LocalPlayer().GetCharacter and LocalPlayer():GetCharacter()
if (localCharacter and character:GetID() == localCharacter:GetID()) then
button:SetSelected(true)
self.characterList:ScrollToChild(button)
bSelected = true
end
end
if (!bSelected) then
local buttons = self.characterList.buttons
if (#buttons > 0) then
local button = buttons[#buttons]
button:SetSelected(true)
self.characterList:ScrollToChild(button)
else
self.character = nil
end
end
self.characterList:SizeToContents()
end
function PANEL:OnSlideUp()
self.bActive = true
self:Populate()
end
function PANEL:OnSlideDown()
self.bActive = false
end
function PANEL:OnCharacterButtonSelected(panel)
self.carousel:SetActiveCharacter(panel.character)
self.character = panel.character
end
function PANEL:Paint(width, height)
derma.SkinFunc("PaintCharacterLoadBackground", self, width, height)
end
vgui.Register("ixCharMenuLoad", PANEL, "ixCharMenuPanel")

View File

@@ -0,0 +1,169 @@
--[[
| 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/
--]]
local PANEL = {}
function PANEL:Init()
self:SetTall(64)
local function AssignClick(panel)
panel.OnMousePressed = function()
self.pressing = -1
self:OnClick()
end
panel.OnMouseReleased = function()
if (self.pressing) then
self.pressing = nil
end
end
end
self.icon = self:Add("SpawnIcon")
self.icon:SetSize(128, 64)
self.icon:InvalidateLayout(true)
self.icon:Dock(LEFT)
self.icon.PaintOver = function(this, w, h)
end
AssignClick(self.icon)
self.limit = self:Add("DLabel")
self.limit:Dock(RIGHT)
self.limit:SetMouseInputEnabled(true)
self.limit:SetCursor("hand")
self.limit:SetExpensiveShadow(1, Color(0, 0, 60))
self.limit:SetContentAlignment(5)
self.limit:SetFont("ixMediumFont")
self.limit:SetWide(64)
AssignClick(self.limit)
self.label = self:Add("DLabel")
self.label:Dock(FILL)
self.label:SetMouseInputEnabled(true)
self.label:SetCursor("hand")
self.label:SetExpensiveShadow(1, Color(0, 0, 60))
self.label:SetContentAlignment(5)
self.label:SetFont("ixMediumFont")
AssignClick(self.label)
end
function PANEL:OnClick()
ix.command.Send("BecomeClass", self.class)
end
function PANEL:SetNumber(number)
local limit = self.data.limit
if (limit > 0) then
self.limit:SetText(Format("%s/%s", number, limit))
else
self.limit:SetText("")
end
end
function PANEL:SetClass(data)
if (data.model) then
local model = data.model
if (istable(model)) then
model = table.Random(model)
end
self.icon:SetModel(model)
else
local char = LocalPlayer():GetCharacter()
local model = LocalPlayer():GetModel()
if (char) then
model = char:GetModel()
end
self.icon:SetModel(model)
end
self.label:SetText(L(data.name))
self.data = data
self.class = data.index
self:SetNumber(#ix.class.GetPlayers(data.index))
end
vgui.Register("ixClassPanel", PANEL, "DPanel")
PANEL = {}
function PANEL:Init()
ix.gui.classes = self
self:SetSize(self:GetParent():GetSize())
self.list = vgui.Create("DPanelList", self)
self.list:Dock(FILL)
self.list:EnableVerticalScrollbar()
self.list:SetSpacing(5)
self.list:SetPadding(5)
self.classPanels = {}
self:LoadClasses()
end
function PANEL:LoadClasses()
self.list:Clear()
for k, v in ipairs(ix.class.list) do
local no, why = ix.class.CanSwitchTo(LocalPlayer(), k)
local itsFull = ("class is full" == why)
if (no or itsFull) then
local panel = vgui.Create("ixClassPanel", self.list)
panel:SetClass(v)
table.insert(self.classPanels, panel)
self.list:AddItem(panel)
end
end
end
vgui.Register("ixClasses", PANEL, "EditablePanel")
hook.Add("CreateMenuButtons", "ixClasses", function(tabs)
local cnt = table.Count(ix.class.list)
if (cnt <= 1) then return end
for k, _ in ipairs(ix.class.list) do
if (!ix.class.CanSwitchTo(LocalPlayer(), k)) then
continue
else
tabs["classes"] = function(container)
container:Add("ixClasses")
end
return
end
end
end)
net.Receive("ixClassUpdate", function()
local client = net.ReadEntity()
if (ix.gui.classes and ix.gui.classes:IsVisible()) then
if (client == LocalPlayer()) then
ix.gui.classes:LoadClasses()
else
for _, v in ipairs(ix.gui.classes.classPanels) do
local data = v.data
v:SetNumber(#ix.class.GetPlayers(data.index))
end
end
end
end)

View File

@@ -0,0 +1,210 @@
--[[
| 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/
--]]
-- config manager
local PANEL = {}
function PANEL:Init()
self:Dock(FILL)
self:SetSearchEnabled(true)
self:Populate()
end
function PANEL:Populate()
-- gather categories
local categories = {}
local categoryIndices = {}
for k, v in pairs(ix.config.stored) do
local index = v.data and v.data.category or "misc"
categories[index] = categories[index] or {}
categories[index][k] = v
end
-- sort by category phrase
for k, _ in pairs(categories) do
categoryIndices[#categoryIndices + 1] = k
end
table.sort(categoryIndices, function(a, b)
return L(a) < L(b)
end)
-- add panels
for _, category in ipairs(categoryIndices) do
local categoryPhrase = L(category)
self:AddCategory(categoryPhrase)
-- we can use sortedpairs since configs don't have phrases to account for
for k, v in SortedPairs(categories[category]) do
if (isfunction(v.hidden) and v.hidden()) then
continue
end
local data = v.data.data
local type = v.type
local value = ix.util.SanitizeType(type, ix.config.Get(k))
local row = self:AddRow(type, categoryPhrase)
row:SetText(ix.util.ExpandCamelCase(k))
-- type-specific properties
if (type == ix.type.number) then
row:SetMin(data and data.min or 0)
row:SetMax(data and data.max or 1)
row:SetDecimals(data and data.decimals or 0)
end
row:SetValue(value, true)
row:SetShowReset(value != v.default, k, v.default)
row.OnValueChanged = function(panel)
local newValue = ix.util.SanitizeType(type, panel:GetValue())
panel:SetShowReset(newValue != v.default, k, v.default)
net.Start("ixConfigSet")
net.WriteString(k)
net.WriteType(newValue)
net.SendToServer()
end
row.OnResetClicked = function(panel)
panel:SetValue(v.default, true)
panel:SetShowReset(false)
net.Start("ixConfigSet")
net.WriteString(k)
net.WriteType(v.default)
net.SendToServer()
end
row:GetLabel():SetHelixTooltip(function(tooltip)
local title = tooltip:AddRow("name")
title:SetImportant()
title:SetText(k)
title:SizeToContents()
title:SetMaxWidth(math.max(title:GetMaxWidth(), ScrW() * 0.5))
local description = tooltip:AddRow("description")
description:SetText(v.description)
description:SizeToContents()
end)
end
end
self:SizeToContents()
end
vgui.Register("ixConfigManager", PANEL, "ixSettings")
-- plugin manager
PANEL = {}
function PANEL:Init()
self:Dock(FILL)
self:SetSearchEnabled(true)
self.loadedCategory = L("loadedPlugins")
self.unloadedCategory = L("unloadedPlugins")
if (!ix.gui.bReceivedUnloadedPlugins) then
net.Start("ixConfigRequestUnloadedList")
net.SendToServer()
end
self:Populate()
end
function PANEL:OnPluginToggled(uniqueID, bEnabled)
net.Start("ixConfigPluginToggle")
net.WriteString(uniqueID)
net.WriteBool(bEnabled)
net.SendToServer()
end
function PANEL:Populate()
self:AddCategory(self.loadedCategory)
self:AddCategory(self.unloadedCategory)
-- add loaded plugins
for k, v in SortedPairsByMemberValue(ix.plugin.list, "name") do
local row = self:AddRow(ix.type.bool, self.loadedCategory)
row.id = k
row.setting:SetEnabledText(L("on"):utf8upper())
row.setting:SetDisabledText(L("off"):utf8upper())
row.setting:SizeToContents()
-- if this plugin is not in the unloaded list currently, then it's queued for an unload
row:SetValue(!ix.plugin.unloaded[k], true)
row:SetText(v.name)
row.OnValueChanged = function(panel, bEnabled)
self:OnPluginToggled(k, bEnabled)
end
row:GetLabel():SetHelixTooltip(function(tooltip)
local title = tooltip:AddRow("name")
title:SetImportant()
title:SetText(v.name)
title:SizeToContents()
title:SetMaxWidth(math.max(title:GetMaxWidth(), ScrW() * 0.5))
local description = tooltip:AddRow("description")
description:SetText(v.description)
description:SizeToContents()
end)
end
self:UpdateUnloaded(true)
self:SizeToContents()
end
function PANEL:UpdatePlugin(uniqueID, bEnabled)
for _, v in pairs(self:GetRows()) do
if (v.id == uniqueID) then
v:SetValue(bEnabled, true)
end
end
end
-- called from Populate and from the ixConfigUnloadedList net message
function PANEL:UpdateUnloaded(bNoSizeToContents)
for _, v in pairs(self:GetRows()) do
if (ix.plugin.unloaded[v.id]) then
v:SetValue(false, true)
end
end
for k, _ in SortedPairs(ix.plugin.unloaded) do
if (ix.plugin.list[k]) then
-- if this plugin is in the loaded plugins list then it's queued for an unload - don't display it in this category
continue
end
local row = self:AddRow(ix.type.bool, self.unloadedCategory)
row:SetText(k)
row:SetValue(false, true)
row.OnValueChanged = function(panel, bEnabled)
self:OnPluginToggled(k, bEnabled)
end
end
if (!bNoSizeToContents) then
self:SizeToContents()
end
end
vgui.Register("ixPluginManager", PANEL, "ixSettings")

View File

@@ -0,0 +1,318 @@
--[[
| 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/
--]]
local CREDITS = {
{"Alex Grist", "76561197979205163", {"creditLeadDeveloper", "creditManager"}},
{"Igor Radovanovic", "76561197990111113", {"creditLeadDeveloper", "creditUIDesigner"}},
{"Jaydawg", "76561197970371430", {"creditTester"}}
}
local SPECIALS = {
{
{"Luna", "76561197988658543"},
{"Rain GBizzle", "76561198036111376"}
},
{
{"Black Tea", "76561197999893894"}
}
}
local MISC = {
{"nebulous", "Staff members finding bugs and providing input"},
{"Contributors", "Ongoing support from various developers via GitHub"},
{"NutScript", "Providing the base framework to build upon"}
}
local url = "https://gethelix.co/"
local padding = 32
-- logo
local PANEL = {}
function PANEL:Init()
self:SetTall(ScrH() * 0.60)
self:Dock(TOP)
end
function PANEL:Paint(width, height)
derma.SkinFunc("DrawHelixCurved", width * 0.5, height * 0.5, width * 0.25)
-- title
surface.SetFont("ixIntroSubtitleFont")
local text = L("helix"):lower()
local textWidth, textHeight = surface.GetTextSize(text)
surface.SetTextColor(color_white)
surface.SetTextPos(width * 0.5 - textWidth * 0.5, height * 0.5 - textHeight * 0.5)
surface.DrawText(text)
-- version
surface.SetFont("ixMenuMiniFont")
surface.SetTextColor(200, 200, 200, 255)
surface.SetTextPos(width * 0.5 + textWidth * 0.5, height * 0.5 - textHeight * 0.5)
surface.DrawText(GAMEMODE.Version)
end
vgui.Register("ixCreditsLogo", PANEL, "Panel")
-- nametag
PANEL = {}
function PANEL:Init()
self.name = self:Add("DLabel")
self.name:SetFont("ixMenuButtonFontThick")
self.avatar = self:Add("AvatarImage")
end
function PANEL:SetName(name)
self.name:SetText(name)
end
function PANEL:SetAvatar(steamid)
self.avatar:SetSteamID(steamid, 64)
end
function PANEL:PerformLayout(width, height)
self.name:SetPos(width - self.name:GetWide(), 0)
self.avatar:MoveLeftOf(self.name, padding * 0.5)
end
function PANEL:SizeToContents()
self.name:SizeToContents()
local tall = self.name:GetTall()
self.avatar:SetSize(tall, tall)
self:SetSize(self.name:GetWide() + self.avatar:GetWide() + padding * 0.5, self.name:GetTall())
end
vgui.Register("ixCreditsNametag", PANEL, "Panel")
-- name row
PANEL = {}
function PANEL:Init()
self:DockMargin(0, padding, 0, 0)
self:Dock(TOP)
self.nametag = self:Add("ixCreditsNametag")
self.tags = self:Add("DLabel")
self.tags:SetFont("ixMenuButtonFont")
self:SizeToContents()
end
function PANEL:SetName(name)
self.nametag:SetName(name)
end
function PANEL:SetAvatar(steamid)
self.nametag:SetAvatar(steamid)
end
function PANEL:SetTags(tags)
for i = 1, #tags do
tags[i] = L(tags[i])
end
self.tags:SetText(table.concat(tags, "\n"))
end
function PANEL:Paint(width, height)
surface.SetDrawColor(ix.config.Get("color"))
surface.DrawRect(width * 0.5 - 1, 0, 1, height)
end
function PANEL:PerformLayout(width, height)
self.nametag:SetPos(width * 0.5 - self.nametag:GetWide() - padding, 0)
self.tags:SetPos(width * 0.5 + padding, 0)
end
function PANEL:SizeToContents()
self.nametag:SizeToContents()
self.tags:SizeToContents()
self:SetTall(math.max(self.nametag:GetTall(), self.tags:GetTall()))
end
vgui.Register("ixCreditsRow", PANEL, "Panel")
PANEL = {}
function PANEL:Init()
self.left = {}
self.right = {}
end
function PANEL:AddLeft(name, steamid)
local nametag = self:Add("ixCreditsNametag")
nametag:SetName(name)
nametag:SetAvatar(steamid)
nametag:SizeToContents()
self.left[#self.left + 1] = nametag
end
function PANEL:AddRight(name, steamid)
local nametag = self:Add("ixCreditsNametag")
nametag:SetName(name)
nametag:SetAvatar(steamid)
nametag:SizeToContents()
self.right[#self.right + 1] = nametag
end
function PANEL:PerformLayout(width, height)
local y = 0
for _, v in ipairs(self.left) do
v:SetPos(width * 0.25 - v:GetWide() * 0.5, y)
y = y + v:GetTall() + padding
end
y = 0
for _, v in ipairs(self.right) do
v:SetPos(width * 0.75 - v:GetWide() * 0.5, y)
y = y + v:GetTall() + padding
end
if (IsValid(self.center)) then
self.center:SetPos(width * 0.5 - self.center:GetWide() * 0.5, y)
end
end
function PANEL:SizeToContents()
local heightLeft, heightRight, centerHeight = 0, 0, 0
if (#self.left > #self.right) then
local center = self.left[#self.left]
centerHeight = center:GetTall()
self.center = center
self.left[#self.left] = nil
elseif (#self.right > #self.left) then
local center = self.right[#self.right]
centerHeight = center:GetTall()
self.center = center
self.right[#self.right] = nil
end
for _, v in ipairs(self.left) do
heightLeft = heightLeft + v:GetTall() + padding
end
for _, v in ipairs(self.right) do
heightRight = heightRight + v:GetTall() + padding
end
self:SetTall(math.max(heightLeft, heightRight) + centerHeight)
end
vgui.Register("ixCreditsSpecials", PANEL, "Panel")
PANEL = {}
function PANEL:Init()
self:Add("ixCreditsLogo")
local link = self:Add("DLabel", self)
link:SetFont("ixMenuMiniFont")
link:SetTextColor(Color(200, 200, 200, 255))
link:SetText(url)
link:SetContentAlignment(5)
link:Dock(TOP)
link:SizeToContents()
link:SetMouseInputEnabled(true)
link:SetCursor("hand")
link.OnMousePressed = function()
gui.OpenURL(url)
end
for _, v in ipairs(CREDITS) do
local row = self:Add("ixCreditsRow")
row:SetName(v[1])
row:SetAvatar(v[2])
row:SetTags(v[3])
row:SizeToContents()
end
local specials = self:Add("ixLabel")
specials:SetFont("ixMenuButtonFont")
specials:SetText(L("creditSpecial"):utf8upper())
specials:SetTextColor(ix.config.Get("color"))
specials:SetDropShadow(1)
specials:SetKerning(16)
specials:SetContentAlignment(5)
specials:DockMargin(0, padding * 2, 0, padding)
specials:Dock(TOP)
specials:SizeToContents()
local specialList = self:Add("ixCreditsSpecials")
specialList:DockMargin(0, padding, 0, 0)
specialList:Dock(TOP)
for _, v in ipairs(SPECIALS[1]) do
specialList:AddLeft(v[1], v[2])
end
for _, v in ipairs(SPECIALS[2]) do
specialList:AddRight(v[1], v[2])
end
specialList:SizeToContents()
-- less more padding if there's a center column nametag
if (IsValid(specialList.center)) then
specialList:DockMargin(0, padding, 0, padding)
end
for _, v in ipairs(MISC) do
local title = self:Add("DLabel")
title:SetFont("ixMenuButtonFontThick")
title:SetText(v[1])
title:SetContentAlignment(5)
title:SizeToContents()
title:DockMargin(0, padding, 0, 0)
title:Dock(TOP)
local description = self:Add("DLabel")
description:SetFont("ixSmallTitleFont")
description:SetText(v[2])
description:SetContentAlignment(5)
description:SizeToContents()
description:Dock(TOP)
end
self:Dock(TOP)
self:SizeToContents()
end
function PANEL:SizeToContents()
local height = padding
for _, v in pairs(self:GetChildren()) do
local _, top, _, bottom = v:GetDockMargin()
height = height + v:GetTall() + top + bottom
end
self:SetTall(height)
end
vgui.Register("ixCredits", PANEL, "Panel")
hook.Add("PopulateHelpMenu", "ixCredits", function(tabs)
tabs["credits"] = function(container)
container:Add("ixCredits")
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/
--]]
--Icon Editor Base and Math Scale Functions from: https://github.com/TeslaCloud/flux-ce/tree/master
local scaleFactorX = 1 / 1920
local scaleFactorY = 1 / 1080
local function scale(size)
return math.floor(size * (ScrH() * scaleFactorY))
end
local function scale_x(size)
return math.floor(size * (ScrW() * scaleFactorX))
end
local PANEL = {}
function PANEL:Init()
if (IsValid(ix.gui.dev_icon)) then
ix.gui.dev_icon:Remove()
end
ix.gui.dev_icon = self
local pW, pH = ScrW() * 0.6, ScrH() * 0.6
self:SetSize(pW, pH)
self:MakePopup()
self:Center()
local buttonSize = scale(48)
self.model = vgui.Create("DAdjustableModelPanel", self)
self.model:SetSize(pW * 0.5, pH - buttonSize)
self.model:Dock(LEFT)
self.model:DockMargin(0, 0, 0, buttonSize + scale(8))
self.model:SetModel("models/props_borealis/bluebarrel001.mdl")
self.model:SetLookAt(Vector(0, 0, 0))
self.model.LayoutEntity = function() end
local x = scale_x(4)
self.best = vgui.Create("DButton", self)
self.best:SetSize(buttonSize, buttonSize)
self.best:SetPos(x, pH - buttonSize - scale(4))
self.best:SetFont("ixIconsMenuButton")
self.best:SetText("b")
self.best:SetTooltip(L("iconEditorAlignBest"))
self.best.DoClick = function()
local entity = self.model:GetEntity()
local pos = entity:GetPos()
local camData = PositionSpawnIcon(entity, pos)
if (camData) then
self.model:SetCamPos(camData.origin)
self.model:SetFOV(camData.fov)
self.model:SetLookAng(camData.angles)
end
end
x = x + buttonSize + scale_x(4)
self.front = vgui.Create("DButton", self)
self.front:SetSize(buttonSize, buttonSize)
self.front:SetPos(x, pH - buttonSize - scale(4))
self.front:SetFont("ixIconsMenuButton")
self.front:SetText("m")
self.front:SetTooltip(L("iconEditorAlignFront"))
self.front.DoClick = function()
local entity = self.model:GetEntity()
local pos = entity:GetPos()
local camPos = pos + Vector(-200, 0, 0)
self.model:SetCamPos(camPos)
self.model:SetFOV(45)
self.model:SetLookAng((camPos * -1):Angle())
end
x = x + buttonSize + scale_x(4)
self.above = vgui.Create("DButton", self)
self.above:SetSize(buttonSize, buttonSize)
self.above:SetPos(x, pH - buttonSize - scale(4))
self.above:SetFont("ixIconsMenuButton")
self.above:SetText("u")
self.above:SetTooltip(L("iconEditorAlignAbove"))
self.above.DoClick = function()
local entity = self.model:GetEntity()
local pos = entity:GetPos()
local camPos = pos + Vector(0, 0, 200)
self.model:SetCamPos(camPos)
self.model:SetFOV(45)
self.model:SetLookAng((camPos * -1):Angle())
end
x = x + buttonSize + scale_x(4)
self.right = vgui.Create("DButton", self)
self.right:SetSize(buttonSize, buttonSize)
self.right:SetPos(x, pH - buttonSize - scale(4))
self.right:SetFont("ixIconsMenuButton")
self.right:SetText("t")
self.right:SetTooltip(L("iconEditorAlignRight"))
self.right.DoClick = function()
local entity = self.model:GetEntity()
local pos = entity:GetPos()
local camPos = pos + Vector(0, 200, 0)
self.model:SetCamPos(camPos)
self.model:SetFOV(45)
self.model:SetLookAng((camPos * -1):Angle())
end
x = x + buttonSize + scale_x(4)
self.center = vgui.Create("DButton", self)
self.center:SetSize(buttonSize, buttonSize)
self.center:SetPos(x, pH - buttonSize - scale(4))
self.center:SetFont("ixIconsMenuButton")
self.center:SetText("T")
self.center:SetTooltip(L("iconEditorAlignCenter"))
self.center.DoClick = function()
local entity = self.model:GetEntity()
local pos = entity:GetPos()
self.model:SetCamPos(pos)
self.model:SetFOV(45)
self.model:SetLookAng(Angle(0, -180, 0))
end
self.best:DoClick()
self.preview = vgui.Create("DPanel", self)
self.preview:Dock(FILL)
self.preview:DockMargin(scale_x(4), 0, 0, 0)
self.preview:DockPadding(scale_x(4), scale(4), scale_x(4), scale(4))
self.preview.Paint = function(pnl, w, h)
draw.RoundedBox(0, 0, 0, w, h, Color(0, 0, 0, 100))
end
self.modelLabel = self.preview:Add("DLabel")
self.modelLabel:Dock(TOP)
self.modelLabel:SetText("Model")
self.modelLabel:SetFont("ixMenuButtonFontSmall")
self.modelLabel:DockMargin(4, 4, 4, 4)
self.modelPath = vgui.Create("ixTextEntry", self.preview)
self.modelPath:SetValue(self.model:GetModel())
self.modelPath:Dock(TOP)
self.modelPath:SetFont("ixMenuButtonFontSmall")
self.modelPath:SetPlaceholderText("Model...")
self.modelPath.OnEnter = function(pnl)
local model = pnl:GetValue()
if (model and model != "") then
self.model:SetModel(model)
self.item:Rebuild()
end
end
self.modelPath.OnLoseFocus = function(pnl)
local model = pnl:GetValue()
if (model and model != "") then
self.model:SetModel(model)
self.item:Rebuild()
end
end
self.width = vgui.Create("ixSettingsRowNumber", self.preview)
self.width:Dock(TOP)
self.width:SetText(L("iconEditorWidth"))
self.width:SetMin(1)
self.width:SetMax(24)
self.width:SetDecimals(0)
self.width:SetValue(1)
self.width.OnValueChanged = function(pnl, value)
self.item:Rebuild()
end
self.height = vgui.Create("ixSettingsRowNumber", self.preview)
self.height:Dock(TOP)
self.height:SetText(L("iconEditorHeight"))
self.height:SetMin(1)
self.height:SetMax(24)
self.height:SetDecimals(0)
self.height:SetValue(1)
self.height.OnValueChanged = function(pnl, value)
self.item:Rebuild()
end
self.itemPanel = vgui.Create("DPanel", self.preview)
self.itemPanel:Dock(FILL)
self.itemPanel.Paint = function(pnl, w, h)
draw.RoundedBox(0, 0, 0, w, h, Color(0, 0, 0, 100))
end
self.item = vgui.Create("DModelPanel", self.itemPanel)
self.item:SetMouseInputEnabled(false)
self.item.LayoutEntity = function() end
self.item.PaintOver = function(pnl, w, h)
surface.SetDrawColor(color_white)
surface.DrawOutlinedRect(0, 0, w, h)
end
self.item.Rebuild = function(pnl)
local slotSize = 64
local padding = scale(2)
local slotWidth, slotHeight = math.Round(self.width:GetValue()), math.Round(self.height:GetValue())
local w, h = slotWidth * (slotSize + padding) - padding, slotHeight * (slotSize + padding) - padding
pnl:SetModel(self.model:GetModel())
pnl:SetCamPos(self.model:GetCamPos())
pnl:SetFOV(self.model:GetFOV())
pnl:SetLookAng(self.model:GetLookAng())
pnl:SetSize(w, h)
pnl:Center()
end
self.item:Rebuild()
timer.Create("ix_icon_editor_update", 0.5, 0, function()
if IsValid(self) and IsValid(self.model) then
self.item:Rebuild()
else
timer.Remove("ix_icon_editor_update")
end
end)
self.copy = vgui.Create("DButton", self)
self.copy:SetSize(buttonSize, buttonSize)
self.copy:SetPos(pW - buttonSize - scale_x(12), pH - buttonSize - scale(12))
self.copy:SetFont("ixIconsMenuButton")
self.copy:SetText("}")
self.copy:SetTooltip(L("iconEditorCopy"))
self.copy.DoClick = function()
local camPos = self.model:GetCamPos()
local camAng = self.model:GetLookAng()
local str = "ITEM.model = \""..self.model:GetModel().."\"\n"
.."ITEM.width = "..math.Round(self.width:GetValue()).."\n"
.."ITEM.height = "..math.Round(self.height:GetValue()).."\n"
.."ITEM.iconCam = {\n"
.." pos = Vector("..math.Round(camPos.x, 2)..", "..math.Round(camPos.y, 2)..", "..math.Round(camPos.z, 2).."),\n"
.." ang = Angle("..math.Round(camAng.p, 2)..", "..math.Round(camAng.y, 2)..", "..math.Round(camAng.r, 2).."),\n"
.." fov = "..math.Round(self.model:GetFOV(), 2).."\n"
.."}\n"
SetClipboardText(str)
ix.util.Notify(L("iconEditorCopied"))
end
end
vgui.Register("ix_icon_editor", PANEL, "DFrame")
concommand.Add("ix_dev_icon", function()
if (LocalPlayer():IsAdmin()) then
vgui.Create("ix_icon_editor")
end
end)

View File

@@ -0,0 +1,287 @@
--[[
| 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/
--]]
local animationTime = 1
local padding = 32
-- entity menu button
DEFINE_BASECLASS("ixMenuButton")
local PANEL = {}
AccessorFunc(PANEL, "callback", "Callback")
function PANEL:Init()
self:SetTall(ScrH() * 0.1)
self:Dock(TOP)
end
function PANEL:DoClick()
local bStatus = true
local parent = ix.menu.panel
local entity = parent:GetEntity()
if (parent.bClosing) then
return
end
if (isfunction(self.callback)) then
bStatus = self.callback()
end
if (bStatus != false) then
ix.menu.NetworkChoice(entity, self.originalText, bStatus)
end
parent:Remove()
end
function PANEL:SetText(text)
self.originalText = text
BaseClass.SetText(self, text)
end
vgui.Register("ixEntityMenuButton", PANEL, "ixMenuButton")
-- entity menu list
DEFINE_BASECLASS("EditablePanel")
PANEL = {}
function PANEL:Init()
self.list = {}
end
function PANEL:AddOption(text, callback)
local panel = self:Add("ixEntityMenuButton")
panel:SetText(text)
panel:SetCallback(callback)
panel:Dock(TOP)
if (self.bPaintedManually) then
panel:SetPaintedManually(true)
end
self.list[#self.list + 1] = panel
end
function PANEL:SizeToContents()
local height = 0
for i = 1, #self.list do
height = height + self.list[i]:GetTall()
end
self:SetSize(ScrW() * 0.5 - padding * 2, height)
end
function PANEL:Center()
local parent = self:GetParent()
self:SetPos(
ScrW() * 0.5 + padding,
parent:GetTall() * 0.5 - self:GetTall() * 0.5
)
end
function PANEL:SetPaintedManually(bValue)
if (bValue) then
for i = 1, #self.list do
self.list[i]:SetPaintedManually(true)
end
self.bPaintedManually = true
end
BaseClass.SetPaintedManually(self, bValue)
end
function PANEL:PaintManual()
BaseClass.PaintManual(self)
local list = self.list
for i = 1, #list do
list[i]:PaintManual()
end
end
vgui.Register("ixEntityMenuList", PANEL, "EditablePanel")
-- entity menu
DEFINE_BASECLASS("EditablePanel")
PANEL = {}
AccessorFunc(PANEL, "entity", "Entity")
AccessorFunc(PANEL, "bClosing", "IsClosing", FORCE_BOOL)
AccessorFunc(PANEL, "desiredHeight", "DesiredHeight", FORCE_NUMBER)
function PANEL:Init()
if (IsValid(ix.menu.panel)) then
self:Remove()
return
end
-- close entity tooltip if it's open
if (IsValid(ix.gui.entityInfo)) then
ix.gui.entityInfo:Remove()
end
ix.menu.panel = self
self:SetSize(ScrW(), ScrH())
self:SetPos(0, 0)
self.list = self:Add("ixEntityMenuList")
self.list:SetPaintedManually(true)
self.desiredHeight = 0
self.blur = 0
self.alpha = 1
self.bClosing = false
self.lastPosition = vector_origin
self:CreateAnimation(animationTime, {
target = {blur = 1},
easing = "outQuint"
})
self:MakePopup()
end
function PANEL:SetOptions(options)
for k, v in pairs(options) do
self.list:AddOption(k, v)
end
self.list:SizeToContents()
self.list:Center()
end
function PANEL:GetApproximateScreenHeight(entity, distanceSqr)
return IsValid(entity) and
(entity:BoundingRadius() * (entity:IsPlayer() and 1.5 or 1) or 0) / math.sqrt(distanceSqr) * self:GetTall() or 0
end
function PANEL:Think()
local entity = self.entity
local distance = 0
if (IsValid(entity)) then
local position = entity:GetPos()
distance = LocalPlayer():GetShootPos():DistToSqr(position)
if (distance > 65536) then
self:Remove()
return
end
self.lastPosition = position
end
self.desiredHeight = math.max(self.list:GetTall() + padding * 2, self:GetApproximateScreenHeight(entity, distance))
end
function PANEL:Paint(width, height) -- luacheck: ignore 312
local selfHalf = self:GetTall() * 0.5
local entity = self.entity
height = self.desiredHeight + padding * 2
width = self.blur * width
local y = selfHalf - height * 0.5
DisableClipping(true) -- for cheap blur
render.SetScissorRect(0, y, width, y + height, true)
if (IsValid(entity)) then
cam.Start3D()
ix.util.ResetStencilValues()
render.SetStencilEnable(true)
cam.IgnoreZ(true)
render.SetStencilWriteMask(29)
render.SetStencilTestMask(29)
render.SetStencilReferenceValue(29)
render.SetStencilCompareFunction(STENCIL_ALWAYS)
render.SetStencilPassOperation(STENCIL_REPLACE)
render.SetStencilFailOperation(STENCIL_KEEP)
render.SetStencilZFailOperation(STENCIL_KEEP)
entity:DrawModel()
render.SetStencilCompareFunction(STENCIL_NOTEQUAL)
render.SetStencilPassOperation(STENCIL_KEEP)
cam.Start2D()
ix.util.DrawBlur(self, 10)
cam.End2D()
cam.IgnoreZ(false)
render.SetStencilEnable(false)
cam.End3D()
else
ix.util.DrawBlur(self, 10)
end
render.SetScissorRect(0, 0, 0, 0, false)
DisableClipping(false)
-- scissor again because 3d rendering messes with the clipping apparently?
render.SetScissorRect(0, y, width, y + height, true)
surface.SetDrawColor(ix.config.Get("color"))
surface.DrawRect(ScrW() * 0.5, y + padding, 1, height - padding * 2)
self.list:PaintManual()
render.SetScissorRect(0, 0, 0, 0, false)
end
function PANEL:GetOverviewInfo(origin, angles)
local entity = self.entity
if (IsValid(entity)) then
local radius = entity:BoundingRadius() * (entity:IsPlayer() and 0.5 or 1)
local center = entity:LocalToWorld(entity:OBBCenter()) + LocalPlayer():GetRight() * radius
return LerpAngle(self.bClosing and self.alpha or self.blur, angles, (center - origin):Angle())
end
return angles
end
function PANEL:OnMousePressed(code)
if (code == MOUSE_LEFT) then
self:Remove()
end
end
function PANEL:Remove()
if (self.bClosing) then
return
end
self.bClosing = true
self:SetMouseInputEnabled(false)
self:SetKeyboardInputEnabled(false)
gui.EnableScreenClicker(false)
self:CreateAnimation(animationTime * 0.5, {
target = {alpha = 0},
index = 2,
easing = "outQuint",
Think = function(animation, panel)
panel:SetAlpha(panel.alpha * 255)
end,
OnComplete = function(animation, panel)
ix.menu.panel = nil
BaseClass.Remove(self)
end
})
end
vgui.Register("ixEntityMenu", PANEL, "EditablePanel")

View File

@@ -0,0 +1,933 @@
--[[
| 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/
--]]
-- generic panels that are applicable anywhere
-- used for prominent text entries
DEFINE_BASECLASS("DTextEntry")
local PANEL = {}
AccessorFunc(PANEL, "backgroundColor", "BackgroundColor")
function PANEL:Init()
self:SetPaintBackground(false)
self:SetTextColor(color_white)
self.backgroundColor = Color(255, 255, 255, 25)
end
function PANEL:SetFont(font)
surface.SetFont(font)
local _, height = surface.GetTextSize("W@")
self:SetTall(height)
BaseClass.SetFont(self, font)
end
function PANEL:Paint(width, height)
derma.SkinFunc("DrawImportantBackground", 0, 0, width, height, self.backgroundColor)
BaseClass.Paint(self, width, height)
end
vgui.Register("ixTextEntry", PANEL, "DTextEntry")
-- similar to a frame, but is mainly used for grouping panels together in a list
PANEL = {}
AccessorFunc(PANEL, "text", "Text", FORCE_STRING)
AccessorFunc(PANEL, "color", "Color")
function PANEL:Init()
self.text = ""
self.paddingTop = 32
local skin = self:GetSkin()
if (skin and skin.fontCategoryBlur) then
surface.SetFont(skin.fontCategoryBlur)
self.paddingTop = select(2, surface.GetTextSize("W@")) + 6
end
self:DockPadding(1, self.paddingTop, 1, 1)
end
function PANEL:SizeToContents()
local height = self.paddingTop + 1
for _, v in ipairs(self:GetChildren()) do
if (IsValid(v) and v:IsVisible()) then
local _, top, _, bottom = v:GetDockMargin()
height = height + v:GetTall() + top + bottom
end
end
self:SetTall(height)
end
function PANEL:Paint(width, height)
derma.SkinFunc("PaintCategoryPanel", self, self.text, self.color)
end
vgui.Register("ixCategoryPanel", PANEL, "EditablePanel")
-- segmented progress bar
PANEL = {}
AccessorFunc(PANEL, "font", "Font", FORCE_STRING)
AccessorFunc(PANEL, "barColor", "BarColor")
AccessorFunc(PANEL, "textColor", "TextColor")
AccessorFunc(PANEL, "progress", "Progress", FORCE_NUMBER)
AccessorFunc(PANEL, "padding", "Padding", FORCE_NUMBER)
AccessorFunc(PANEL, "animationTime", "AnimationTime", FORCE_NUMBER)
AccessorFunc(PANEL, "easingType", "EasingType", FORCE_STRING)
function PANEL:Init()
self.segments = {}
self.padding = ScrH() * 0.01
self.fraction = 0
self.animationTime = 0.5
self.easingType = "outQuint"
self.progress = 0
end
function PANEL:AddSegment(text)
local id = #self.segments + 1
if (text:sub(1, 1) == "@") then
text = L(text:sub(2))
end
self.segments[id] = text
return id
end
function PANEL:AddSegments(...)
local segments = {...}
for i = 1, #segments do
self:AddSegment(segments[i])
end
end
function PANEL:GetSegments()
return self.segments
end
function PANEL:SetProgress(segment)
self.progress = math.Clamp(segment, 0, #self.segments)
self:CreateAnimation(self.animationTime, {
target = {fraction = self.progress / #self.segments},
easing = self.easingType
})
end
function PANEL:IncrementProgress(amount)
self:SetProgress(self.progress + (amount or 1))
end
function PANEL:DecrementProgress(amount)
self:SetProgress(self.progress - (amount or 1))
end
function PANEL:GetFraction()
return self.fraction
end
function PANEL:SizeToContents()
self:SetTall(draw.GetFontHeight(self.font or self:GetSkin().fontSegmentedProgress) + self.padding)
end
function PANEL:Paint(width, height)
derma.SkinFunc("PaintSegmentedProgressBackground", self, width, height)
if (#self.segments > 0) then
derma.SkinFunc("PaintSegmentedProgress", self, width, height)
end
end
vgui.Register("ixSegmentedProgress", PANEL, "Panel")
-- list of labelled information
PANEL = {}
AccessorFunc(PANEL, "labelColor", "LabelColor")
AccessorFunc(PANEL, "textColor", "TextColor")
AccessorFunc(PANEL, "list", "List")
AccessorFunc(PANEL, "minWidth", "MinimumWidth", FORCE_NUMBER)
function PANEL:Init()
self.label = self:Add("DLabel")
self.label:SetFont("ixMediumFont")
self.label:SetExpensiveShadow(1)
self.label:SetTextColor(color_white)
self.label:SetText("Label")
self.label:SetContentAlignment(5)
self.label:Dock(LEFT)
self.label:DockMargin(0, 0, 4, 0)
self.label:SizeToContents()
self.label.Paint = function(this, width, height)
derma.SkinFunc("PaintListRow", this, width, height)
end
self.text = self:Add("DLabel")
self.text:SetFont("ixMediumLightFont")
self.text:SetTextColor(color_white)
self.text:SetText("Text")
self.text:SetTextInset(8, 0)
self.text:Dock(FILL)
self.text:DockMargin(4, 0, 0, 0)
self.text:SizeToContents()
self.text.Paint = function(this, width, height)
derma.SkinFunc("PaintListRow", this, width, height)
end
self:DockMargin(0, 0, 0, 8)
self.list = {}
self.minWidth = 100
end
function PANEL:SetRightPanel(panel)
self.text:Remove()
self.text = self:Add(panel)
self.text:Dock(FILL)
self.text:DockMargin(8, 4, 4, 4)
self.text:SizeToContents()
end
function PANEL:SetList(list, bNoAdd)
if (!bNoAdd) then
list[#list + 1] = self
end
self.list = list
end
function PANEL:UpdateLabelWidths()
local maxWidth = self.label:GetWide()
for i = 1, #self.list do
maxWidth = math.max(self.list[i]:GetLabelWidth(), maxWidth)
end
maxWidth = math.max(self.minWidth, maxWidth)
for i = 1, #self.list do
self.list[i]:SetLabelWidth(maxWidth)
end
end
function PANEL:SetLabelColor(color)
self.label:SetTextColor(color)
end
function PANEL:SetTextColor(color)
self.text:SetTextColor(color)
end
function PANEL:SetLabelText(text)
self.label:SetText(text)
self.label:SizeToContents()
self:UpdateLabelWidths()
end
function PANEL:SetText(text)
self.text:SetText(text)
self.text:SizeToContents()
end
function PANEL:SetLabelWidth(width)
self.label:SetWide(width)
end
function PANEL:GetLabelWidth(bWithoutMargin)
if (!bWithoutMargin) then
return self.label:GetWide()
end
local left, _, right, _ = self.label:GetDockMargin()
return self.label:GetWide() + left + right
end
function PANEL:SizeToContents()
self:SetTall(math.max(self.label:GetTall(), self.text:GetTall()) + 8)
end
vgui.Register("ixListRow", PANEL, "Panel")
-- alternative checkbox
DEFINE_BASECLASS("EditablePanel")
PANEL = {}
AccessorFunc(PANEL, "enabledText", "EnabledText", FORCE_STRING)
AccessorFunc(PANEL, "disabledText", "DisabledText", FORCE_STRING)
AccessorFunc(PANEL, "font", "Font", FORCE_STRING)
AccessorFunc(PANEL, "bChecked", "Checked", FORCE_BOOL)
AccessorFunc(PANEL, "animationTime", "AnimationTime", FORCE_NUMBER)
AccessorFunc(PANEL, "labelPadding", "LabelPadding", FORCE_NUMBER)
PANEL.GetValue = PANEL.GetChecked
function PANEL:Init()
self:SetMouseInputEnabled(true)
self:SetCursor("hand")
self.enabledText = L("yes"):utf8upper()
self.disabledText = L("no"):utf8upper()
self.font = "ixMenuButtonFont"
self.animationTime = 0.5
self.bChecked = false
self.labelPadding = 8
self.animationOffset = 0
self:SizeToContents()
end
function PANEL:SizeToContents()
BaseClass.SizeToContents(self)
surface.SetFont(self.font)
self:SetWide(math.max(surface.GetTextSize(self.enabledText), surface.GetTextSize(self.disabledText)) + self.labelPadding)
end
-- can be overidden to change audio params
function PANEL:GetAudioFeedback()
return "weapons/ar2/ar2_empty.wav", 75, self.bChecked and 150 or 125, 0.25
end
function PANEL:EmitFeedback()
LocalPlayer():EmitSound(self:GetAudioFeedback())
end
function PANEL:SetChecked(bChecked, bInstant)
self.bChecked = tobool(bChecked)
self:CreateAnimation(bInstant and 0 or self.animationTime, {
index = 1,
target = {
animationOffset = bChecked and 1 or 0
},
easing = "outElastic"
})
if (!bInstant) then
self:EmitFeedback()
end
end
function PANEL:OnMousePressed(code)
if (code == MOUSE_LEFT) then
self:SetChecked(!self.bChecked)
self:DoClick()
end
end
function PANEL:DoClick()
end
function PANEL:Paint(width, height)
surface.SetDrawColor(derma.GetColor("DarkerBackground", self))
surface.DrawRect(0, 0, width, height)
local offset = self.animationOffset
surface.SetFont(self.font)
local text = self.disabledText
local textWidth, textHeight = surface.GetTextSize(text)
local y = offset * -textHeight
surface.SetTextColor(250, 60, 60, 255)
surface.SetTextPos(width * 0.5 - textWidth * 0.5, y + height * 0.5 - textHeight * 0.5)
surface.DrawText(text)
text = self.enabledText
y = y + textHeight
textWidth, textHeight = surface.GetTextSize(text)
surface.SetTextColor(30, 250, 30, 255)
surface.SetTextPos(width * 0.5 - textWidth * 0.5, y + height * 0.5 - textHeight * 0.5)
surface.DrawText(text)
end
vgui.Register("ixCheckBox", PANEL, "EditablePanel")
-- alternative num slider
PANEL = {}
AccessorFunc(PANEL, "labelPadding", "LabelPadding", FORCE_NUMBER)
function PANEL:Init()
self.labelPadding = 8
surface.SetFont("ixMenuButtonFont")
local totalWidth = surface.GetTextSize("999") -- start off with 3 digit width
self.label = self:Add("DLabel")
self.label:Dock(RIGHT)
self.label:SetWide(totalWidth + self.labelPadding)
self.label:SetContentAlignment(5)
self.label:SetFont("ixMenuButtonFont")
self.label.Paint = function(panel, width, height)
surface.SetDrawColor(derma.GetColor("DarkerBackground", self))
surface.DrawRect(0, 0, width, height)
end
self.label.SizeToContents = function(panel)
surface.SetFont(panel:GetFont())
local textWidth = surface.GetTextSize(panel:GetText())
if (textWidth > totalWidth) then
panel:SetWide(textWidth + self.labelPadding)
elseif (panel:GetWide() > totalWidth + self.labelPadding) then
panel:SetWide(totalWidth + self.labelPadding)
end
end
self.slider = self:Add("ixSlider")
self.slider:Dock(FILL)
self.slider:DockMargin(0, 0, 4, 0)
self.slider.OnValueChanged = function(panel)
self:OnValueChanged()
end
self.slider.OnValueUpdated = function(panel)
self.label:SetText(string.format("%0." .. tostring(panel:GetDecimals()) .. "f", tostring(panel:GetValue())))
self.label:SizeToContents()
self:OnValueUpdated()
end
end
function PANEL:GetLabel()
return self.label
end
function PANEL:GetSlider()
return self.slider
end
function PANEL:SetValue(value, bNoNotify)
value = tonumber(value) or self.slider:GetMin()
self.slider:SetValue(value, bNoNotify)
self.label:SetText(string.format("%0." .. tostring(self:GetDecimals()) .. "f", tostring(self.slider:GetValue())))
self.label:SizeToContents()
end
function PANEL:GetValue()
return self.slider:GetValue()
end
function PANEL:GetFraction()
return self.slider:GetFraction()
end
function PANEL:GetVisualFraction()
return self.slider:GetVisualFraction()
end
function PANEL:SetMin(value)
self.slider:SetMin(value)
end
function PANEL:SetMax(value)
self.slider:SetMax(value)
end
function PANEL:GetMin()
return self.slider:GetMin()
end
function PANEL:GetMax()
return self.slider:GetMax()
end
function PANEL:SetDecimals(value)
self.slider:SetDecimals(value)
end
function PANEL:GetDecimals()
return self.slider:GetDecimals()
end
-- called when changed by user
function PANEL:OnValueChanged()
end
-- called when changed while dragging bar
function PANEL:OnValueUpdated()
end
vgui.Register("ixNumSlider", PANEL, "Panel")
-- alternative slider
PANEL = {}
AccessorFunc(PANEL, "bDragging", "Dragging", FORCE_BOOL)
AccessorFunc(PANEL, "min", "Min", FORCE_NUMBER)
AccessorFunc(PANEL, "max", "Max", FORCE_NUMBER)
AccessorFunc(PANEL, "decimals", "Decimals", FORCE_NUMBER)
function PANEL:Init()
self.min = 0
self.max = 10
self.value = 0
self.visualValue = 0
self.decimals = 0
self:SetCursor("hand")
end
function PANEL:SetValue(value, bNoNotify)
self.value = math.Clamp(math.Round(tonumber(value) or self.min, self.decimals), self.min, self.max)
self:ValueUpdated(bNoNotify)
if (!bNoNotify) then
self:OnValueChanged()
end
end
function PANEL:GetValue()
return self.value
end
function PANEL:GetFraction()
return math.Remap(self.value, self.min, self.max, 0, 1)
end
function PANEL:GetVisualFraction()
return math.Remap(self.visualValue, self.min, self.max, 0, 1)
end
function PANEL:OnMousePressed(key)
if (key == MOUSE_LEFT) then
self.bDragging = true
self:MouseCapture(true)
self:OnCursorMoved(self:CursorPos())
end
end
function PANEL:OnMouseReleased(key)
if (self.bDragging) then
self:OnValueChanged()
end
self.bDragging = false
self:MouseCapture(false)
end
function PANEL:OnCursorMoved(x, y)
if (!self.bDragging) then
return
end
x = math.Clamp(x, 0, self:GetWide())
local oldValue = self.value
self.value = math.Clamp(math.Round(
math.Remap(x / self:GetWide(), 0, 1, self.min, self.max), self.decimals
), self.min, self.max)
self:CreateAnimation(0.5, {
index = 1,
target = {visualValue = self.value},
easing = "outQuint"
})
if (self.value != oldValue) then
self:ValueUpdated()
end
end
function PANEL:OnValueChanged()
end
function PANEL:ValueUpdated(bNoNotify)
self:CreateAnimation(bNoNotify and 0 or 0.5, {
index = 1,
target = {visualValue = self.value},
easing = "outQuint"
})
if (!bNoNotify) then
self:OnValueUpdated()
end
end
function PANEL:OnValueUpdated()
end
function PANEL:Paint(width, height)
derma.SkinFunc("PaintHelixSlider", self, width, height)
end
vgui.Register("ixSlider", PANEL, "EditablePanel")
--- Alternative to DLabel that adds extra functionality.
-- This panel is meant for drawing single-line text. It can add extra kerning (spaces between letters), and it can forcefully
-- scale the text down to fit the current width, without cutting off any letters. Text scaling is most useful when docking this
-- this panel without knowing what the width could be. For example, text scaling is used for the character name in the character
-- status menu.
-- local label = vgui.Create("ixLabel")
-- label:SetText("hello world")
-- label:SetFont("ixMenuButtonHugeFont")
-- label:SetContentAlignment(5)
-- label:SetTextColor(Color(255, 255, 255, 255))
-- label:SetBackgroundColor(Color(200, 30, 30, 255))
-- label:SetPadding(8)
-- label:SetScaleWidth(true)
-- label:SizeToContents()
-- @panel ixLabel
PANEL = {}
--- Sets the text for this label to display.
-- @realm client
-- @string text Text to display
-- @function SetText
--- Returns the current text for this panel.
-- @realm client
-- @treturn string Current text
-- @function GetText
AccessorFunc(PANEL, "text", "Text", FORCE_STRING)
--- Sets the color of the text to use when drawing.
-- @realm client
-- @color color New color to use
-- @function SetTextColor
--- Returns the current text color for this panel.
-- @realm client
-- @treturn color Current text color
-- @function GetTextColor
AccessorFunc(PANEL, "color", "TextColor")
--- Sets the color of the background to draw behind the text.
-- @realm client
-- @color color New color to use
-- @function SetBackgroundColor
--- Returns the current background color for this panel.
-- @realm client
-- @treturn color Current background color
-- @function GetBackgroundColor
AccessorFunc(PANEL, "backgroundColor", "BackgroundColor")
--- Sets the spacing between each character of the text in pixels. Set to `0` to disable. Kerning is disabled by default.
-- @realm client
-- @number kerning How far apart to draw each letter
-- @function SetKerning
--- Returns the current kerning for this panel.
-- @realm client
-- @treturn number Current kerning
-- @function GetKerning
AccessorFunc(PANEL, "kerning", "Kerning", FORCE_NUMBER)
--- Sets the font used to draw the text.
-- @realm client
-- @string font Name of the font to use
-- @function SetFont
--- Returns the current font for this panel.
-- @realm client
-- @treturn string Name of current font
-- @function GetFont
AccessorFunc(PANEL, "font", "Font", FORCE_STRING)
--- Changes how the text is aligned when drawing. Valid content alignment values include numbers `1` through `9`. Each number's
-- corresponding alignment is based on its position on a numpad. For example, `1` is bottom-left, `5` is centered, `9` is
-- top-right, etc.
-- @realm client
-- @number alignment Alignment to use
-- @function SetContentAlignment
--- Returns the current content alignment for this panel.
-- @realm client
-- @treturn number Current content alignment
-- @function GetContentAlignment
AccessorFunc(PANEL, "contentAlignment", "ContentAlignment", FORCE_NUMBER)
--- Whether or not to scale the width of the text down to fit the width of this panel, if needed.
-- @realm client
-- @bool bScale Whether or not to scale
-- @function SetScaleWidth
--- Returns whether or not this panel will scale its text down to fit its width.
-- @realm client
-- @treturn bool Whether or not this panel will scale its text
-- @function GetScaleWidth
AccessorFunc(PANEL, "bScaleWidth", "ScaleWidth", FORCE_BOOL)
--- How much spacing to use around the text when its drawn. This uses uniform padding on the top, left, right, and bottom of
-- this panel.
-- @realm client
-- @number padding Padding to use
-- @function SetPadding
--- Returns how much padding this panel has around its text.
-- @realm client
-- @treturn number Current padding
-- @function GetPadding
AccessorFunc(PANEL, "padding", "Padding", FORCE_NUMBER)
function PANEL:Init()
self.text = ""
self.color = color_white
self.backgroundColor = Color(255, 255, 255, 0)
self.kerning = 0
self.font = "DermaDefault"
self.scaledFont = "DermaDefault"
self.contentAlignment = 5
self.bScaleWidth = false
self.padding = 0
self.shadowDistance = 0
self.bCurrentlyScaling = false
end
function PANEL:SetText(text)
self.text = tostring(text)
end
function PANEL:SetFont(font)
self.font = font
self.scaledFont = font
end
--- Sets the drop shadow to draw behind the text.
-- @realm client
-- @number distance How far away to draw the shadow in pixels. Set to `0` to disable
-- @color[opt] color Color of the shadow. Defaults to a dimmed version of the text color
function PANEL:SetDropShadow(distance, color)
self.shadowDistance = distance or 1
self.shadowColor = color or ix.util.DimColor(self.color, 0.5)
end
PANEL.SetExpensiveShadow = PANEL.SetDropShadow -- aliasing for easier conversion from DLabels
--- Returns the X and Y location of the text taking into account the text alignment and padding.
-- @realm client
-- @internal
-- @number width Width of the panel
-- @number height Height of the panel
-- @number textWidth Width of the text
-- @number textHeight Height of the text
-- @treturn number X location to draw the text
-- @treturn number Y location to draw the text
function PANEL:CalculateAlignment(width, height, textWidth, textHeight)
local alignment = self.contentAlignment
local x, y
if (self.bCurrentlyScaling) then
-- if the text is currently being scaled down, then it's always centered
x = width * 0.5 - textWidth * 0.5
else
-- x alignment
if (alignment == 7 or alignment == 4 or alignment == 1) then
-- left
x = self.padding
elseif (alignment == 8 or alignment == 5 or alignment == 2) then
-- center
x = width * 0.5 - textWidth * 0.5
elseif (alignment == 9 or alignment == 6 or alignment == 3) then
x = width - textWidth - self.padding
end
end
-- y alignment
if (alignment <= 3) then
-- bottom
y = height - textHeight - self.padding
elseif (alignment <= 6) then
-- center
y = height * 0.5 - textHeight * 0.5
else
-- top
y = self.padding
end
return x, y
end
--- Draws the current text with the current kerning.
-- @realm client
-- @internal
-- @number width Width of the panel
-- @number height Height of the panel
function PANEL:DrawKernedText(width, height)
local contentWidth, contentHeight = self:GetContentSize()
local x, y = self:CalculateAlignment(width, height, contentWidth, contentHeight)
for i = 1, self.text:utf8len() do
local character = self.text:utf8sub(i, i)
local textWidth, _ = surface.GetTextSize(character)
local kerning = i == 1 and 0 or self.kerning
local shadowDistance = self.shadowDistance
-- shadow
if (self.shadowDistance > 0) then
surface.SetTextColor(self.shadowColor)
surface.SetTextPos(x + kerning + shadowDistance, y + shadowDistance)
surface.DrawText(character)
end
-- character
surface.SetTextColor(self.color)
surface.SetTextPos(x + kerning, y)
surface.DrawText(character)
x = x + textWidth + kerning
end
end
--- Draws the current text.
-- @realm client
-- @internal
-- @number width Width of the panel
-- @number height Height of the panel
function PANEL:DrawText(width, height)
local textWidth, textHeight = surface.GetTextSize(self.text)
local x, y = self:CalculateAlignment(width, height, textWidth, textHeight)
-- shadow
if (self.shadowDistance > 0) then
surface.SetTextColor(self.shadowColor)
surface.SetTextPos(x + self.shadowDistance, y + self.shadowDistance)
surface.DrawText(self.text)
end
-- text
surface.SetTextColor(self.color)
surface.SetTextPos(x, y)
surface.DrawText(self.text)
end
function PANEL:Paint(width, height)
surface.SetFont(self.font)
surface.SetDrawColor(self.backgroundColor)
surface.DrawRect(0, 0, width, height)
if (self.bScaleWidth) then
local contentWidth, contentHeight = self:GetContentSize()
if (contentWidth > (width - self.padding * 2)) then
local x, y = self:LocalToScreen(self:GetPos())
local scale = width / (contentWidth + self.padding * 2)
local translation = Vector(x + width * 0.5, y - contentHeight * 0.5 + self.padding, 0)
local matrix = Matrix()
matrix:Translate(translation)
matrix:Scale(Vector(scale, scale, 0))
matrix:Translate(-translation)
cam.PushModelMatrix(matrix, true)
render.PushFilterMin(TEXFILTER.ANISOTROPIC)
DisableClipping(true)
self.bCurrentlyScaling = true
end
end
if (self.kerning > 0) then
self:DrawKernedText(width, height)
else
self:DrawText(width, height)
end
if (self.bCurrentlyScaling) then
DisableClipping(false)
render.PopFilterMin()
cam.PopModelMatrix()
self.bCurrentlyScaling = false
end
end
--- Returns the size of the text, taking into account the current kerning.
-- @realm client
-- @bool[opt=false] bCalculate Whether or not to recalculate the content size instead of using the cached copy
-- @treturn number Width of the text
-- @treturn number Height of the text
function PANEL:GetContentSize(bCalculate)
if (bCalculate or !self.contentSize) then
surface.SetFont(self.font)
if (self.kerning > 0) then
local width = 0
for i = 1, self.text:utf8len() do
local textWidth, _ = surface.GetTextSize(self.text:utf8sub(i, i))
width = width + textWidth + self.kerning
end
self.contentSize = {width, draw.GetFontHeight(self.font)}
else
self.contentSize = {surface.GetTextSize(self.text)}
end
end
return self.contentSize[1], self.contentSize[2]
end
--- Sets the size of the panel to fit the content size with the current padding. The content size is recalculated when this
-- method is called.
-- @realm client
function PANEL:SizeToContents()
local contentWidth, contentHeight = self:GetContentSize(true)
self:SetSize(contentWidth + self.padding * 2, contentHeight + self.padding * 2)
end
vgui.Register("ixLabel", PANEL, "Panel")
-- text entry with icon
DEFINE_BASECLASS("ixTextEntry")
PANEL = {}
AccessorFunc(PANEL, "icon", "Icon", FORCE_STRING)
AccessorFunc(PANEL, "iconColor", "IconColor")
function PANEL:Init()
self:SetIcon("V")
self:SetFont("ixSmallTitleFont")
self.iconColor = Color(200, 200, 200, 160)
end
function PANEL:SetIcon(newIcon)
surface.SetFont("ixSmallTitleIcons")
self.iconWidth, self.iconHeight = surface.GetTextSize(newIcon)
self.icon = newIcon
self:DockMargin(self.iconWidth + 4, 0, 0, 8)
end
function PANEL:Paint(width, height)
BaseClass.Paint(self, width, height)
-- there's no inset for text entries so we'll have to get creative
DisableClipping(true)
surface.SetDrawColor(self:GetBackgroundColor())
surface.DrawRect(-self.iconWidth - 4, 0, self.iconWidth + 4, height)
surface.SetFont("ixSmallTitleIcons")
surface.SetTextColor(self.iconColor)
surface.SetTextPos(-self.iconWidth - 2, 0)
surface.DrawText(self:GetIcon())
DisableClipping(false)
end
vgui.Register("ixIconTextEntry", PANEL, "ixTextEntry")

View File

@@ -0,0 +1,379 @@
--[[
| 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/
--]]
local backgroundColor = Color(0, 0, 0, 66)
local PANEL = {}
AccessorFunc(PANEL, "maxWidth", "MaxWidth", FORCE_NUMBER)
function PANEL:Init()
self:SetWide(180)
self:Dock(LEFT)
self.maxWidth = ScrW() * 0.2
end
function PANEL:Paint(width, height)
surface.SetDrawColor(backgroundColor)
surface.DrawRect(0, 0, width, height)
end
function PANEL:SizeToContents()
local width = 0
for _, v in ipairs(self:GetChildren()) do
width = math.max(width, v:GetWide())
end
self:SetSize(math.max(32, math.min(width, self.maxWidth)), self:GetParent():GetTall())
end
vgui.Register("ixHelpMenuCategories", PANEL, "EditablePanel")
-- help menu
PANEL = {}
function PANEL:Init()
self:Dock(FILL)
self.categories = {}
self.categorySubpanels = {}
self.categoryPanel = self:Add("ixHelpMenuCategories")
self.canvasPanel = self:Add("EditablePanel")
self.canvasPanel:Dock(FILL)
self.idlePanel = self.canvasPanel:Add("Panel")
self.idlePanel:Dock(FILL)
self.idlePanel:DockMargin(8, 0, 0, 0)
self.idlePanel.Paint = function(_, width, height)
surface.SetDrawColor(backgroundColor)
surface.DrawRect(0, 0, width, height)
derma.SkinFunc("DrawHelixCurved", width * 0.5, height * 0.5, width * 0.25)
surface.SetFont("ixIntroSubtitleFont")
local text = L("helix"):lower()
local textWidth, textHeight = surface.GetTextSize(text)
surface.SetTextColor(color_white)
surface.SetTextPos(width * 0.5 - textWidth * 0.5, height * 0.5 - textHeight * 0.75)
surface.DrawText(text)
surface.SetFont("ixMediumLightFont")
text = L("helpIdle")
local infoWidth, _ = surface.GetTextSize(text)
surface.SetTextColor(color_white)
surface.SetTextPos(width * 0.5 - infoWidth * 0.5, height * 0.5 + textHeight * 0.25)
surface.DrawText(text)
end
local categories = {}
hook.Run("PopulateHelpMenu", categories)
for k, v in SortedPairs(categories) do
if (!isstring(k)) then
ErrorNoHalt("expected string for help menu key\n")
continue
elseif (!isfunction(v)) then
ErrorNoHalt(string.format("expected function for help menu entry '%s'\n", k))
continue
end
self:AddCategory(k)
self.categories[k] = v
end
self.categoryPanel:SizeToContents()
if (ix.gui.lastHelpMenuTab) then
self:OnCategorySelected(ix.gui.lastHelpMenuTab)
end
end
function PANEL:AddCategory(name)
local button = self.categoryPanel:Add("ixMenuButton")
button:SetText(L(name))
button:SizeToContents()
-- @todo don't hardcode this but it's the only panel that needs docking at the bottom so it'll do for now
button:Dock(name == "credits" and BOTTOM or TOP)
button.DoClick = function()
self:OnCategorySelected(name)
end
local panel = self.canvasPanel:Add("DScrollPanel")
panel:SetVisible(false)
panel:Dock(FILL)
panel:DockMargin(8, 0, 0, 0)
panel:GetCanvas():DockPadding(8, 8, 8, 8)
panel.Paint = function(_, width, height)
surface.SetDrawColor(backgroundColor)
surface.DrawRect(0, 0, width, height)
end
-- reverts functionality back to a standard panel in the case that a category will manage its own scrolling
panel.DisableScrolling = function()
panel:GetCanvas():SetVisible(false)
panel:GetVBar():SetVisible(false)
panel.OnChildAdded = function() end
end
self.categorySubpanels[name] = panel
end
function PANEL:OnCategorySelected(name)
local panel = self.categorySubpanels[name]
if (!IsValid(panel)) then
return
end
if (!panel.bPopulated) then
self.categories[name](panel)
panel.bPopulated = true
end
if (IsValid(self.activeCategory)) then
self.activeCategory:SetVisible(false)
end
panel:SetVisible(true)
self.idlePanel:SetVisible(false)
self.activeCategory = panel
ix.gui.lastHelpMenuTab = name
end
vgui.Register("ixHelpMenu", PANEL, "EditablePanel")
local function DrawHelix(width, height, color) -- luacheck: ignore 211
local segments = 76
local radius = math.min(width, height) * 0.375
surface.SetTexture(-1)
for i = 1, math.ceil(segments) do
local angle = math.rad((i / segments) * -360)
local x = width * 0.5 + math.sin(angle + math.pi * 2) * radius
local y = height * 0.5 + math.cos(angle + math.pi * 2) * radius
local barOffset = math.sin(SysTime() + i * 0.5)
local barHeight = barOffset * radius * 0.25
if (barOffset > 0) then
surface.SetDrawColor(color)
else
surface.SetDrawColor(color.r * 0.5, color.g * 0.5, color.b * 0.5, color.a)
end
surface.DrawTexturedRectRotated(x, y, 4, barHeight, math.deg(angle))
end
end
hook.Add("CreateMenuButtons", "ixHelpMenu", function(tabs)
tabs["help"] = function(container)
container:Add("ixHelpMenu")
end
end)
hook.Add("PopulateHelpMenu", "ixHelpMenu", function(tabs)
tabs["commands"] = function(container)
-- info text
local info = container:Add("DLabel")
info:SetFont("ixSmallFont")
info:SetText(L("helpCommands"))
info:SetContentAlignment(5)
info:SetTextColor(color_white)
info:SetExpensiveShadow(1, color_black)
info:Dock(TOP)
info:DockMargin(0, 0, 0, 8)
info:SizeToContents()
info:SetTall(info:GetTall() + 16)
info.Paint = function(_, width, height)
surface.SetDrawColor(ColorAlpha(derma.GetColor("Info", info), 160))
surface.DrawRect(0, 0, width, height)
end
-- commands
for uniqueID, command in SortedPairs(ix.command.list) do
if (command.OnCheckAccess and !command:OnCheckAccess(LocalPlayer())) then
continue
end
local bIsAlias = false
local aliasText = ""
-- we want to show aliases in the same entry for better readability
if (command.alias) then
local alias = istable(command.alias) and command.alias or {command.alias}
for _, v in ipairs(alias) do
if (v:lower() == uniqueID) then
bIsAlias = true
break
end
aliasText = aliasText .. ", /" .. v
end
if (bIsAlias) then
continue
end
end
-- command name
local title = container:Add("DLabel")
title:SetFont("ixMediumLightFont")
title:SetText("/" .. command.name .. aliasText)
title:Dock(TOP)
title:SetTextColor(ix.config.Get("color"))
title:SetExpensiveShadow(1, color_black)
title:SizeToContents()
-- syntax
local syntaxText = command.syntax
local syntax
if (syntaxText != "" and syntaxText != "[none]") then
syntax = container:Add("DLabel")
syntax:SetFont("ixMediumLightFont")
syntax:SetText(syntaxText)
syntax:Dock(TOP)
syntax:SetTextColor(color_white)
syntax:SetExpensiveShadow(1, color_black)
syntax:SetWrap(true)
syntax:SetAutoStretchVertical(true)
syntax:SizeToContents()
end
-- description
local descriptionText = command:GetDescription()
if (descriptionText != "") then
local description = container:Add("DLabel")
description:SetFont("ixSmallFont")
description:SetText(descriptionText)
description:Dock(TOP)
description:SetTextColor(color_white)
description:SetExpensiveShadow(1, color_black)
description:SetWrap(true)
description:SetAutoStretchVertical(true)
description:SizeToContents()
description:DockMargin(0, 0, 0, 8)
elseif (syntax) then
syntax:DockMargin(0, 0, 0, 8)
else
title:DockMargin(0, 0, 0, 8)
end
end
end
tabs["flags"] = function(container)
-- info text
local info = container:Add("DLabel")
info:SetFont("ixSmallFont")
info:SetText(L("helpFlags"))
info:SetContentAlignment(5)
info:SetTextColor(color_white)
info:SetExpensiveShadow(1, color_black)
info:Dock(TOP)
info:DockMargin(0, 0, 0, 8)
info:SizeToContents()
info:SetTall(info:GetTall() + 16)
info.Paint = function(_, width, height)
surface.SetDrawColor(ColorAlpha(derma.GetColor("Info", info), 160))
surface.DrawRect(0, 0, width, height)
end
-- flags
for k, v in SortedPairs(ix.flag.list) do
local background = ColorAlpha(
LocalPlayer():GetCharacter():HasFlags(k) and derma.GetColor("Success", info) or derma.GetColor("Error", info), 88
)
local panel = container:Add("Panel")
panel:Dock(TOP)
panel:DockMargin(0, 0, 0, 8)
panel:DockPadding(4, 4, 4, 4)
panel.Paint = function(_, width, height)
derma.SkinFunc("DrawImportantBackground", 0, 0, width, height, background)
end
local flag = panel:Add("DLabel")
flag:SetFont("ixMonoMediumFont")
flag:SetText(string.format("[%s]", k))
flag:Dock(LEFT)
flag:SetTextColor(color_white)
flag:SetExpensiveShadow(1, color_black)
flag:SetTextInset(4, 0)
flag:SizeToContents()
flag:SetTall(flag:GetTall() + 8)
local description = panel:Add("DLabel")
description:SetFont("ixMediumLightFont")
description:SetText(v.description)
description:Dock(FILL)
description:SetTextColor(color_white)
description:SetExpensiveShadow(1, color_black)
description:SetTextInset(8, 0)
description:SizeToContents()
description:SetTall(description:GetTall() + 8)
panel:SizeToChildren(false, true)
end
end
tabs["plugins"] = function(container)
for _, v in SortedPairsByMemberValue(ix.plugin.list, "name") do
-- name
local title = container:Add("DLabel")
title:SetFont("ixMediumLightFont")
title:SetText(v.name or "Unknown")
title:Dock(TOP)
title:SetTextColor(ix.config.Get("color"))
title:SetExpensiveShadow(1, color_black)
title:SizeToContents()
-- author
local author = container:Add("DLabel")
author:SetFont("ixSmallFont")
author:SetText(string.format("%s: %s", L("author"), v.author))
author:Dock(TOP)
author:SetTextColor(color_white)
author:SetExpensiveShadow(1, color_black)
author:SetWrap(true)
author:SetAutoStretchVertical(true)
author:SizeToContents()
-- description
local descriptionText = v.description
if (descriptionText != "") then
local description = container:Add("DLabel")
description:SetFont("ixSmallFont")
description:SetText(descriptionText)
description:Dock(TOP)
description:SetTextColor(color_white)
description:SetExpensiveShadow(1, color_black)
description:SetWrap(true)
description:SetAutoStretchVertical(true)
description:SizeToContents()
description:DockMargin(0, 0, 0, 8)
else
author:DockMargin(0, 0, 0, 8)
end
end
end
end)

View File

@@ -0,0 +1,283 @@
--[[
| 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/
--]]
local PANEL = {}
function PANEL:Init()
local parent = self:GetParent()
self:SetSize(parent:GetWide() * 0.6, parent:GetTall())
self:Dock(RIGHT)
self:DockMargin(0, ScrH() * 0.05, 0, 0)
self.VBar:SetWide(0)
-- entry setup
local suppress = {}
hook.Run("CanCreateCharacterInfo", suppress)
if (!suppress.time) then
local format = "%A, %B %d, %Y. %H:%M"
self.time = self:Add("DLabel")
self.time:SetFont("ixMediumFont")
self.time:SetTall(28)
self.time:SetContentAlignment(5)
self.time:Dock(TOP)
self.time:SetTextColor(color_white)
self.time:SetExpensiveShadow(1, Color(0, 0, 0, 150))
self.time:DockMargin(0, 0, 0, 32)
self.time:SetText(ix.date.GetFormatted(format))
self.time.Think = function(this)
if ((this.nextTime or 0) < CurTime()) then
this:SetText(ix.date.GetFormatted(format))
this.nextTime = CurTime() + 0.5
end
end
end
if (!suppress.name) then
self.name = self:Add("ixLabel")
self.name:Dock(TOP)
self.name:DockMargin(0, 0, 0, 8)
self.name:SetFont("ixMenuButtonHugeFont")
self.name:SetContentAlignment(5)
self.name:SetTextColor(color_white)
self.name:SetPadding(8)
self.name:SetScaleWidth(true)
end
if (!suppress.description) then
self.description = self:Add("DLabel")
self.description:Dock(TOP)
self.description:DockMargin(0, 0, 0, 8)
self.description:SetFont("ixMenuButtonFont")
self.description:SetTextColor(color_white)
self.description:SetContentAlignment(5)
self.description:SetMouseInputEnabled(true)
self.description:SetCursor("hand")
self.description.Paint = function(this, width, height)
surface.SetDrawColor(0, 0, 0, 150)
surface.DrawRect(0, 0, width, height)
end
self.description.OnMousePressed = function(this, code)
if (code == MOUSE_LEFT) then
ix.command.Send("CharDesc")
if (IsValid(ix.gui.menu)) then
ix.gui.menu:Remove()
end
end
end
self.description.SizeToContents = function(this)
if (this.bWrap) then
-- sizing contents after initial wrapping does weird things so we'll just ignore (lol)
return
end
local width, height = this:GetContentSize()
if (width > self:GetWide()) then
this:SetWide(self:GetWide())
this:SetTextInset(16, 8)
this:SetWrap(true)
this:SizeToContentsY()
this:SetTall(this:GetTall() + 16) -- eh
-- wrapping doesn't like middle alignment so we'll do top-center
self.description:SetContentAlignment(8)
this.bWrap = true
else
this:SetSize(width + 16, height + 16)
end
end
end
if (!suppress.characterInfo) then
self.characterInfo = self:Add("Panel")
self.characterInfo.list = {}
self.characterInfo:Dock(TOP) -- no dock margin because this is handled by ixListRow
self.characterInfo.SizeToContents = function(this)
local height = 0
for _, v in ipairs(this:GetChildren()) do
if (IsValid(v) and v:IsVisible()) then
local _, top, _, bottom = v:GetDockMargin()
height = height + v:GetTall() + top + bottom
end
end
this:SetTall(height)
end
if (!suppress.faction) then
self.faction = self.characterInfo:Add("ixListRow")
self.faction:SetList(self.characterInfo.list)
self.faction:Dock(TOP)
end
if (!suppress.class) then
self.class = self.characterInfo:Add("ixListRow")
self.class:SetList(self.characterInfo.list)
self.class:Dock(TOP)
end
if (!suppress.money) then
self.money = self.characterInfo:Add("ixListRow")
self.money:SetList(self.characterInfo.list)
self.money:Dock(TOP)
self.money:SizeToContents()
end
hook.Run("CreateCharacterInfo", self.characterInfo)
self.characterInfo:SizeToContents()
end
-- no need to update since we aren't showing the attributes panel
if (!suppress.attributes) then
local character = LocalPlayer().GetCharacter and LocalPlayer():GetCharacter()
if (character) then
self.attributes = self:Add("ixCategoryPanel")
self.attributes:SetText(L("attributes"))
self.attributes:Dock(TOP)
self.attributes:DockMargin(0, 0, 0, 8)
local boost = character:GetBoosts()
local bFirst = true
for k, v in SortedPairsByMemberValue(ix.attributes.list, "name") do
local attributeBoost = 0
if (boost[k]) then
for _, bValue in pairs(boost[k]) do
attributeBoost = attributeBoost + bValue
end
end
local bar = self.attributes:Add("ixAttributeBar")
bar:Dock(TOP)
if (!bFirst) then
bar:DockMargin(0, 3, 0, 0)
else
bFirst = false
end
local value = character:GetAttribute(k, 0)
if (attributeBoost) then
bar:SetValue(value - attributeBoost or 0)
else
bar:SetValue(value)
end
local maximum = v.maxValue or ix.config.Get("maxAttributes", 100)
bar:SetMax(maximum)
bar:SetReadOnly()
bar:SetText(Format("%s [%.1f/%.1f] (%.1f%%)", L(v.name), value, maximum, value / maximum * 100))
if (attributeBoost) then
bar:SetBoost(attributeBoost)
end
end
self.attributes:SizeToContents()
end
end
hook.Run("CreateCharacterInfoCategory", self)
end
function PANEL:Update(character)
if (!character) then
return
end
local faction = ix.faction.indices[character:GetFaction()]
local class = ix.class.list[character:GetClass()]
if (self.name) then
self.name:SetText(character:GetName())
if (faction) then
self.name.backgroundColor = ColorAlpha(faction.color, 150) or Color(0, 0, 0, 150)
end
self.name:SizeToContents()
end
if (self.description) then
self.description:SetText(character:GetDescription())
self.description:SizeToContents()
end
if (self.faction) then
self.faction:SetLabelText(L("faction"))
self.faction:SetText(L(faction.name))
self.faction:SizeToContents()
end
if (self.class) then
-- don't show class label if the class is the same name as the faction
if (class and class.name != faction.name) then
self.class:SetLabelText(L("class"))
self.class:SetText(L(class.name))
self.class:SizeToContents()
else
self.class:SetVisible(false)
end
end
if (self.money) then
self.money:SetLabelText(L("money"))
self.money:SetText(ix.currency.Get(character:GetMoney()))
self.money:SizeToContents()
end
hook.Run("UpdateCharacterInfo", self.characterInfo, character)
self.characterInfo:SizeToContents()
hook.Run("UpdateCharacterInfoCategory", self, character)
end
function PANEL:OnSubpanelRightClick()
properties.OpenEntityMenu(LocalPlayer())
end
vgui.Register("ixCharacterInfo", PANEL, "DScrollPanel")
hook.Add("CreateMenuButtons", "ixCharInfo", function(tabs)
tabs["you"] = {
bHideBackground = true,
buttonColor = team.GetColor(LocalPlayer():Team()),
Create = function(info, container)
container.infoPanel = container:Add("ixCharacterInfo")
container.OnMouseReleased = function(this, key)
if (key == MOUSE_RIGHT) then
this.infoPanel:OnSubpanelRightClick()
end
end
end,
OnSelected = function(info, container)
container.infoPanel:Update(LocalPlayer():GetCharacter())
ix.gui.menu:SetCharacterOverview(true)
end,
OnDeselected = function(info, container)
ix.gui.menu:SetCharacterOverview(false)
end
}
end)

View File

@@ -0,0 +1,378 @@
--[[
| 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/
--]]
local waveSegments = 32
local helixSegments = 76
local helixHeight = 64
local backgroundColor = Color(115, 53, 142)
local dimColor = Color(165, 134, 179)
DEFINE_BASECLASS("EditablePanel")
local PANEL = {}
function PANEL:Init()
if (IsValid(ix.gui.intro)) then
ix.gui.intro:Remove()
end
ix.gui.intro = self
self:SetSize(ScrW(), ScrH())
self:SetPos(0, 0)
self:SetZPos(99999)
self:MakePopup()
-- animation parameters
self.bBackground = true
self.volume = 1
self.sunbeamOffset = 0
self.textOne = 0
self.textTwo = 0
self.kickTarget = 0
self.helix = 0
self.helixAlpha = 0
self.continueText = 0
self.pulse = 0
self.waves = {
{1.1, 0},
{1.1, math.pi},
{1.1, math.pi * 1.6},
{1.1, math.pi * 0.5}
}
end
-- @todo h a c k
function PANEL:Think()
if (IsValid(LocalPlayer())) then
self:BeginIntro()
self.Think = nil
end
end
function PANEL:BeginIntro()
-- something could have errored on startup and invalidated all options, so we'll be extra careful with setting the option
-- because if it errors here, the sound will play each tick and proceed to hurt ears
local bLoaded = false
if (ix and ix.option and ix.option.Set) then
local bSuccess, _ = pcall(ix.option.Set, "showIntro", false)
bLoaded = bSuccess
end
if (!bLoaded) then
self:Remove()
if (ix and ix.gui and IsValid(ix.gui.characterMenu)) then
ix.gui.characterMenu:Remove()
end
ErrorNoHalt(
"[Helix] Something has errored and prevented the framework from loading correctly - check your console for errors!\n")
return
end
self:MoveToFront()
self:RequestFocus()
sound.PlayFile("sound/buttons/combine_button2.wav", "", function()
timer.Create("ixIntroStart", 2, 1, function()
sound.PlayFile("sound/helix/intro.mp3", "", function(channel, status, error)
if (IsValid(channel)) then
channel:SetVolume(self.volume)
self.channel = channel
end
self:BeginAnimation()
end)
end)
end)
end
function PANEL:AnimateWaves(target, bReverse)
for i = bReverse and #self.waves or 1,
bReverse and 1 or #self.waves,
bReverse and -1 or 1 do
local animation = self:CreateAnimation(2, {
index = 20 + (bReverse and (#self.waves - i) or i),
bAutoFire = false,
target = {
waves = {
[i] = {target}
}
},
easing = bReverse and "inQuart" or "outQuint"
})
timer.Simple((bReverse and (#self.waves - i) or i) * 0.1, function()
if (IsValid(self) and animation) then
animation:Fire()
end
end)
-- return last animation that plays
if ((bReverse and i == 1) or (!bReverse and i == #self.waves)) then
return animation
end
end
end
function PANEL:BeginAnimation()
self:CreateAnimation(2, {
target = {textOne = 1},
easing = "inQuint",
bIgnoreConfig = true
})
:CreateAnimation(2, {
target = {textOne = 0},
easing = "inQuint",
bIgnoreConfig = true
})
:CreateAnimation(2, {
target = {textTwo = 1},
easing = "inQuint",
bIgnoreConfig = true,
OnComplete = function(animation, panel)
self:AnimateWaves(0)
end
})
:CreateAnimation(2, {
target = {textTwo = 0},
easing = "inQuint",
bIgnoreConfig = true
})
:CreateAnimation(4, {
target = {sunbeamOffset = 1},
bIgnoreConfig = true,
OnComplete = function()
self:CreateAnimation(2,{
target = {helixAlpha = 1},
easing = "inCubic"
})
end
})
:CreateAnimation(2, {
target = {helix = 1},
easing = "outQuart",
bIgnoreConfig = true
})
:CreateAnimation(2, {
target = {continueText = 1},
easing = "linear",
bIgnoreConfig = true
})
end
function PANEL:PaintCurve(y, width, offset, scale)
offset = offset or 1
scale = scale or 32
local points = {
[1] = {
x = 0,
y = ScrH()
}
}
for i = 0, waveSegments do
local angle = math.rad((i / waveSegments) * -360)
points[#points + 1] = {
x = (width / waveSegments) * i,
y = y + (math.sin(angle * 0.5 + offset) - 1) * scale
}
end
points[#points + 1] = {
x = width,
y = ScrH()
}
draw.NoTexture()
surface.DrawPoly(points)
end
function PANEL:Paint(width, height)
local time = SysTime()
local text = L("helix"):lower()
local centerY = height * self.waves[#self.waves][1] + height * 0.5
local sunbeamOffsetEasing = math.sin(math.pi * self.sunbeamOffset)
local textWidth, textHeight
local fft
-- background
if (self.bBackground) then
surface.SetDrawColor(0, 0, 0, 255)
surface.DrawRect(0, 0, width, height)
end
if (self.sunbeamOffset == 1) then
fft = {}
if (IsValid(self.channel)) then
self.channel:FFT(fft, FFT_2048)
local kick = (fft[4] or 0) * 8192
self.kickTarget = math.Approach(self.kickTarget, kick, 8 * math.abs(kick - self.kickTarget) * FrameTime())
end
end
-- waves
for i = 1, #self.waves do
local wave = self.waves[i]
local ratio = i / #self.waves
local color = Color(
backgroundColor.r * ratio,
backgroundColor.g * ratio,
backgroundColor.b * ratio,
self.bBackground and 255 or (ratio * 320)
)
surface.SetDrawColor(color)
self:PaintCurve(height * wave[1], width, wave[2])
end
-- helix
if (self.helix > 0) then
local alpha = self.helixAlpha * 255
derma.SkinFunc("DrawHelixCurved",
width * 0.5, centerY,
math.min(ScreenScale(72), 128) * 2, -- font sizes are clamped to 128
helixSegments * self.helix, helixHeight, self.helix,
ColorAlpha(color_white, alpha),
ColorAlpha(dimColor, alpha)
)
end
-- title text glow
surface.SetTextColor(255, 255, 255,
self.sunbeamOffset == 1 and self.kickTarget or sunbeamOffsetEasing * 255
)
surface.SetFont("ixIntroTitleBlurFont")
local logoTextWidth, logoTextHeight = surface.GetTextSize(text)
surface.SetTextPos(width * 0.5 - logoTextWidth * 0.5, centerY - logoTextHeight * 0.5)
surface.DrawText(text)
-- title text
surface.SetTextColor(255, 255, 255, self.sunbeamOffset * 255)
surface.SetFont("ixIntroTitleFont")
logoTextWidth, logoTextHeight = surface.GetTextSize(text)
surface.SetTextPos(width * 0.5 - logoTextWidth * 0.5, centerY - logoTextHeight * 0.5)
surface.DrawText(text)
-- text one
surface.SetFont("ixIntroSubtitleFont")
text = L("introTextOne"):lower()
textWidth = surface.GetTextSize(text)
surface.SetTextColor(255, 255, 255, self.textOne * 255)
surface.SetTextPos(width * 0.5 - textWidth * 0.5, height * 0.66)
surface.DrawText(text)
-- text two
text = L("introTextTwo", Schema.author or "nebulous"):lower()
textWidth = surface.GetTextSize(text)
surface.SetTextColor(255, 255, 255, self.textTwo * 255)
surface.SetTextPos(width * 0.5 - textWidth * 0.5, height * 0.66)
surface.DrawText(text)
-- continue text
surface.SetFont("ixIntroSmallFont")
text = L("introContinue"):lower()
textWidth, textHeight = surface.GetTextSize(text)
if (self.continueText == 1) then
self.pulse = self.pulse + 6 * FrameTime()
if (self.pulse >= 360) then
self.pulse = 0
end
end
surface.SetTextColor(255, 255, 255, self.continueText * 255 - (math.sin(self.pulse) * 100), 0)
surface.SetTextPos(width * 0.5 - textWidth * 0.5, centerY * 2 - textHeight * 2)
surface.DrawText(text)
-- sunbeams
if (self.sunbeamOffset > 0 and self.sunbeamOffset != 1) then
DrawSunbeams(0.25, sunbeamOffsetEasing * 0.1, 0.02,
(((width * 0.5 - logoTextWidth * 0.5) - 32) / width) + ((logoTextWidth + 64) / width) * self.sunbeamOffset,
0.5 + math.sin(time * 2) * 0.01
)
end
end
function PANEL:OnKeyCodePressed(key)
if (key == KEY_SPACE and self.continueText > 0.25) then
self:Remove()
end
end
function PANEL:OnRemove()
timer.Remove("ixIntroStart")
if (IsValid(self.channel)) then
self.channel:Stop()
end
if (IsValid(ix.gui.characterMenu)) then
ix.gui.characterMenu:PlayMusic()
end
end
function PANEL:Remove(bForce)
if (bForce) then
BaseClass.Remove(self)
return
end
if (self.bClosing) then
return
end
self.bClosing = true
self.bBackground = nil
-- waves
local animation = self:AnimateWaves(1.1, true)
animation.OnComplete = function(anim, panel)
panel:SetMouseInputEnabled(false)
panel:SetKeyboardInputEnabled(false)
end
-- audio
self:CreateAnimation(4.5, {
index = 1,
target = {volume = 0},
Think = function(anim, panel)
if (IsValid(panel.channel)) then
panel.channel:SetVolume(panel.volume)
end
end,
OnComplete = function()
timer.Simple(0, function()
BaseClass.Remove(self)
end)
end
})
end
vgui.Register("ixIntro", PANEL, "EditablePanel")

View File

@@ -0,0 +1,806 @@
--[[
| 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/
--]]
local RECEIVER_NAME = "ixInventoryItem"
-- The queue for the rendered icons.
ICON_RENDER_QUEUE = ICON_RENDER_QUEUE or {}
-- To make making inventory variant, This must be followed up.
local function RenderNewIcon(panel, itemTable)
local model = itemTable:GetModel()
-- re-render icons
if ((itemTable.iconCam and !ICON_RENDER_QUEUE[string.lower(model)]) or itemTable.forceRender) then
local iconCam = itemTable.iconCam
iconCam = {
cam_pos = iconCam.pos,
cam_ang = iconCam.ang,
cam_fov = iconCam.fov,
}
ICON_RENDER_QUEUE[string.lower(model)] = true
panel.Icon:RebuildSpawnIconEx(
iconCam
)
end
end
local function InventoryAction(action, itemID, invID, data)
net.Start("ixInventoryAction")
net.WriteString(action)
net.WriteUInt(itemID, 32)
net.WriteUInt(invID, 32)
net.WriteTable(data or {})
net.SendToServer()
end
local PANEL = {}
AccessorFunc(PANEL, "itemTable", "ItemTable")
AccessorFunc(PANEL, "inventoryID", "InventoryID")
function PANEL:Init()
self:Droppable(RECEIVER_NAME)
end
function PANEL:OnMousePressed(code)
if (code == MOUSE_LEFT and self:IsDraggable()) then
self:MouseCapture(true)
self:DragMousePress(code)
self.clickX, self.clickY = input.GetCursorPos()
elseif (code == MOUSE_RIGHT and self.DoRightClick) then
self:DoRightClick()
end
end
function PANEL:OnMouseReleased(code)
-- move the item into the world if we're dropping on something that doesn't handle inventory item drops
if (!dragndrop.m_ReceiverSlot or dragndrop.m_ReceiverSlot.Name != RECEIVER_NAME) then
self:OnDrop(dragndrop.IsDragging())
end
self:DragMouseRelease(code)
self:SetZPos(99)
self:MouseCapture(false)
end
function PANEL:DoRightClick()
local itemTable = self.itemTable
local inventory = self.inventoryID
if (itemTable and inventory) then
itemTable.player = LocalPlayer()
local menu = DermaMenu()
local override = hook.Run("CreateItemInteractionMenu", self, menu, itemTable)
if (override == true) then
if (menu.Remove) then
menu:Remove()
end
return
end
for k, v in SortedPairs(itemTable.functions) do
if (k == "drop" or k == "combine" or (v.OnCanRun and v.OnCanRun(itemTable) == false)) then
continue
end
-- is Multi-Option Function
if (v.isMulti) then
local subMenu, subMenuOption = menu:AddSubMenu(L(v.name or k), function()
itemTable.player = LocalPlayer()
local send = true
if (v.OnClick) then
send = v.OnClick(itemTable)
end
if (v.sound) then
surface.PlaySound(v.sound)
end
if (send != false) then
InventoryAction(k, itemTable.id, inventory)
end
itemTable.player = nil
end)
subMenuOption:SetImage(v.icon or "icon16/brick.png")
if (v.multiOptions) then
local options = isfunction(v.multiOptions) and v.multiOptions(itemTable, LocalPlayer()) or v.multiOptions
for _, sub in pairs(options) do
subMenu:AddOption(L(sub.name or "subOption"), function()
itemTable.player = LocalPlayer()
local send = true
if (sub.OnClick) then
send = sub.OnClick(itemTable)
end
if (sub.sound) then
surface.PlaySound(sub.sound)
end
if (send != false) then
InventoryAction(k, itemTable.id, inventory, sub.data)
end
itemTable.player = nil
end)
end
end
else
menu:AddOption(L(v.name or k), function()
itemTable.player = LocalPlayer()
local send = true
if (v.OnClick) then
send = v.OnClick(itemTable)
end
if (v.sound) then
surface.PlaySound(v.sound)
end
if (send != false) then
InventoryAction(k, itemTable.id, inventory)
end
itemTable.player = nil
end):SetImage(v.icon or "icon16/brick.png")
end
end
-- we want drop to show up as the last option
local info = itemTable.functions.drop
if (info and info.OnCanRun and info.OnCanRun(itemTable) != false) then
menu:AddOption(L(info.name or "drop"), function()
itemTable.player = LocalPlayer()
local send = true
if (info.OnClick) then
send = info.OnClick(itemTable)
end
if (info.sound) then
surface.PlaySound(info.sound)
end
if (send != false) then
InventoryAction("drop", itemTable.id, inventory)
end
itemTable.player = nil
end):SetImage(info.icon or "icon16/brick.png")
end
menu:Open()
itemTable.player = nil
end
end
function PANEL:OnDrop(bDragging, inventoryPanel, inventory, gridX, gridY)
local item = self.itemTable
if (!item or !bDragging) then
return
end
if (!IsValid(inventoryPanel)) then
local inventoryID = self.inventoryID
if (inventoryID) then
InventoryAction("drop", item.id, inventoryID, {})
end
elseif (inventoryPanel:IsAllEmpty(gridX, gridY, item.width, item.height, self)) then
local oldX, oldY = self.gridX, self.gridY
if (oldX != gridX or oldY != gridY or self.inventoryID != inventoryPanel.invID) then
self:Move(gridX, gridY, inventoryPanel)
end
elseif (inventoryPanel.combineItem) then
local combineItem = inventoryPanel.combineItem
local inventoryID = combineItem.invID
if (inventoryID) then
combineItem.player = LocalPlayer()
if (combineItem.functions.combine.sound) then
surface.PlaySound(combineItem.functions.combine.sound)
end
InventoryAction("combine", combineItem.id, inventoryID, {item.id})
combineItem.player = nil
end
end
end
function PANEL:Move(newX, newY, givenInventory, bNoSend)
local iconSize = givenInventory.iconSize
local oldX, oldY = self.gridX, self.gridY
local oldParent = self:GetParent()
if (givenInventory:OnTransfer(oldX, oldY, newX, newY, oldParent, bNoSend) == false) then
return
end
local x = (newX - 1) * iconSize + 4
local y = (newY - 1) * iconSize + givenInventory:GetPadding(2)
self.gridX = newX
self.gridY = newY
self:SetParent(givenInventory)
self:SetPos(x, y)
if (self.slots) then
for _, v in ipairs(self.slots) do
if (IsValid(v) and v.item == self) then
v.item = nil
end
end
end
self.slots = {}
for currentX = 1, self.gridW do
for currentY = 1, self.gridH do
local slot = givenInventory.slots[self.gridX + currentX - 1][self.gridY + currentY - 1]
slot.item = self
self.slots[#self.slots + 1] = slot
end
end
end
function PANEL:PaintOver(width, height)
local itemTable = self.itemTable
if (itemTable and itemTable.PaintOver) then
itemTable.PaintOver(self, itemTable, width, height)
end
end
function PANEL:ExtraPaint(width, height)
end
function PANEL:Paint(width, height)
surface.SetDrawColor(0, 0, 0, 85)
surface.DrawRect(2, 2, width - 4, height - 4)
self:ExtraPaint(width, height)
end
vgui.Register("ixItemIcon", PANEL, "SpawnIcon")
PANEL = {}
DEFINE_BASECLASS("DFrame")
AccessorFunc(PANEL, "iconSize", "IconSize", FORCE_NUMBER)
AccessorFunc(PANEL, "bHighlighted", "Highlighted", FORCE_BOOL)
function PANEL:Init()
self:SetIconSize(64)
self:ShowCloseButton(false)
self:SetDraggable(true)
self:SetSizable(true)
self:SetTitle(L"inv")
self:Receiver(RECEIVER_NAME, self.ReceiveDrop)
self.btnMinim:SetVisible(false)
self.btnMinim:SetMouseInputEnabled(false)
self.btnMaxim:SetVisible(false)
self.btnMaxim:SetMouseInputEnabled(false)
self.panels = {}
end
function PANEL:GetPadding(index)
return select(index, self:GetDockPadding())
end
function PANEL:SetTitle(text)
if (text == nil) then
self.oldPadding = {self:GetDockPadding()}
self.lblTitle:SetText("")
self.lblTitle:SetVisible(false)
self:DockPadding(5, 5, 5, 5)
else
if (self.oldPadding) then
self:DockPadding(unpack(self.oldPadding))
self.oldPadding = nil
end
BaseClass.SetTitle(self, text)
end
end
function PANEL:FitParent(invWidth, invHeight)
local parent = self:GetParent()
if (!IsValid(parent)) then
return
end
local width, height = parent:GetSize()
local padding = 4
local iconSize
if (invWidth > invHeight) then
iconSize = (width - padding * 2) / invWidth
elseif (invHeight > invWidth) then
iconSize = (height - padding * 2) / invHeight
else
-- we use height because the titlebar will make it more tall than it is wide
iconSize = (height - padding * 2) / invHeight - 4
end
self:SetSize(iconSize * invWidth + padding * 2, iconSize * invHeight + padding * 2)
self:SetIconSize(iconSize)
end
function PANEL:OnRemove()
if (self.childPanels) then
for _, v in ipairs(self.childPanels) do
if (v != self) then
v:Remove()
end
end
end
end
function PANEL:ViewOnly()
self.viewOnly = true
for _, icon in pairs(self.panels) do
icon.OnMousePressed = nil
icon.OnMouseReleased = nil
icon.doRightClick = nil
end
end
function PANEL:SetInventory(inventory, bFitParent)
if (inventory.slots) then
local invWidth, invHeight = inventory:GetSize()
self.invID = inventory:GetID()
if (IsValid(ix.gui.inv1) and ix.gui.inv1.childPanels and inventory != LocalPlayer():GetCharacter():GetInventory()) then
self:SetIconSize(ix.gui.inv1:GetIconSize())
self:SetPaintedManually(true)
self.bNoBackgroundBlur = true
ix.gui.inv1.childPanels[#ix.gui.inv1.childPanels + 1] = self
elseif (bFitParent) then
self:FitParent(invWidth, invHeight)
else
self:SetSize(self.iconSize, self.iconSize)
end
self:SetGridSize(invWidth, invHeight)
for x, items in pairs(inventory.slots) do
for y, data in pairs(items) do
if (!data.id) then continue end
local item = ix.item.instances[data.id]
if (item and !IsValid(self.panels[item.id])) then
local icon = self:AddIcon(item:GetModel() or "models/props_junk/popcan01a.mdl",
x, y, item.width, item.height, item:GetSkin())
if (IsValid(icon)) then
icon:SetHelixTooltip(function(tooltip)
ix.hud.PopulateItemTooltip(tooltip, item)
end)
self.panels[item.id] = icon
end
end
end
end
end
end
function PANEL:SetGridSize(w, h)
local iconSize = self.iconSize
local newWidth = w * iconSize + 8
local newHeight = h * iconSize + self:GetPadding(2) + self:GetPadding(4)
self.gridW = w
self.gridH = h
self:SetSize(newWidth, newHeight)
self:SetMinWidth(newWidth)
self:SetMinHeight(newHeight)
self:BuildSlots()
end
function PANEL:PerformLayout(width, height)
BaseClass.PerformLayout(self, width, height)
if (self.Sizing and self.gridW and self.gridH) then
local newWidth = (width - 8) / self.gridW
local newHeight = (height - self:GetPadding(2) + self:GetPadding(4)) / self.gridH
self:SetIconSize((newWidth + newHeight) / 2)
self:RebuildItems()
end
end
function PANEL:BuildSlots()
local iconSize = self.iconSize
self.slots = self.slots or {}
for _, v in ipairs(self.slots) do
for _, v2 in ipairs(v) do
v2:Remove()
end
end
self.slots = {}
for x = 1, self.gridW do
self.slots[x] = {}
for y = 1, self.gridH do
local slot = self:Add("DPanel")
slot:SetZPos(-999)
slot.gridX = x
slot.gridY = y
slot:SetPos((x - 1) * iconSize + 4, (y - 1) * iconSize + self:GetPadding(2))
slot:SetSize(iconSize, iconSize)
slot.Paint = function(panel, width, height)
derma.SkinFunc("PaintInventorySlot", panel, width, height)
end
self.slots[x][y] = slot
end
end
end
function PANEL:RebuildItems()
local iconSize = self.iconSize
for x = 1, self.gridW do
for y = 1, self.gridH do
local slot = self.slots[x][y]
slot:SetPos((x - 1) * iconSize + 4, (y - 1) * iconSize + self:GetPadding(2))
slot:SetSize(iconSize, iconSize)
end
end
for _, v in pairs(self.panels) do
if (IsValid(v)) then
v:SetPos(self.slots[v.gridX][v.gridY]:GetPos())
v:SetSize(v.gridW * iconSize, v.gridH * iconSize)
end
end
end
function PANEL:PaintDragPreview(width, height, mouseX, mouseY, itemPanel)
local iconSize = self.iconSize
local item = itemPanel:GetItemTable()
if (item) then
local inventory = ix.item.inventories[self.invID]
local dropX = math.ceil((mouseX - 4 - (itemPanel.gridW - 1) * 32) / iconSize)
local dropY = math.ceil((mouseY - self:GetPadding(2) - (itemPanel.gridH - 1) * 32) / iconSize)
local hoveredPanel = vgui.GetHoveredPanel()
if (IsValid(hoveredPanel) and hoveredPanel != itemPanel and hoveredPanel.GetItemTable) then
local hoveredItem = hoveredPanel:GetItemTable()
if (hoveredItem) then
local info = hoveredItem.functions.combine
if (info and info.OnCanRun and info.OnCanRun(hoveredItem, {item.id}) != false) then
surface.SetDrawColor(ColorAlpha(derma.GetColor("Info", self, Color(200, 0, 0)), 20))
surface.DrawRect(
hoveredPanel.x,
hoveredPanel.y,
hoveredPanel:GetWide(),
hoveredPanel:GetTall()
)
self.combineItem = hoveredItem
return
end
end
end
self.combineItem = nil
-- don't draw grid if we're dragging it out of bounds
if (inventory) then
local invWidth, invHeight = inventory:GetSize()
if (dropX < 1 or dropY < 1 or
dropX + itemPanel.gridW - 1 > invWidth or
dropY + itemPanel.gridH - 1 > invHeight) then
return
end
end
local bEmpty = true
for x = 0, itemPanel.gridW - 1 do
for y = 0, itemPanel.gridH - 1 do
local x2 = dropX + x
local y2 = dropY + y
bEmpty = self:IsEmpty(x2, y2, itemPanel)
if (!bEmpty) then
-- no need to iterate further since we know something is blocking the hovered grid cells, break through both loops
goto finish
end
end
end
::finish::
local previewColor = ColorAlpha(derma.GetColor(bEmpty and "Success" or "Error", self, Color(200, 0, 0)), 20)
surface.SetDrawColor(previewColor)
surface.DrawRect(
(dropX - 1) * iconSize + 4,
(dropY - 1) * iconSize + self:GetPadding(2),
itemPanel:GetWide(),
itemPanel:GetTall()
)
end
end
function PANEL:PaintOver(width, height)
local panel = self.previewPanel
if (IsValid(panel)) then
local itemPanel = (dragndrop.GetDroppable() or {})[1]
if (IsValid(itemPanel)) then
self:PaintDragPreview(width, height, self.previewX, self.previewY, itemPanel)
end
end
self.previewPanel = nil
end
function PANEL:IsEmpty(x, y, this)
return (self.slots[x] and self.slots[x][y]) and (!IsValid(self.slots[x][y].item) or self.slots[x][y].item == this)
end
function PANEL:IsAllEmpty(x, y, width, height, this)
for x2 = 0, width - 1 do
for y2 = 0, height - 1 do
if (!self:IsEmpty(x + x2, y + y2, this)) then
return false
end
end
end
return true
end
function PANEL:OnTransfer(oldX, oldY, x, y, oldInventory, noSend)
local inventories = ix.item.inventories
local inventory = inventories[oldInventory.invID]
local inventory2 = inventories[self.invID]
local item
if (inventory) then
item = inventory:GetItemAt(oldX, oldY)
if (!item) then
return false
end
if (hook.Run("CanTransferItem", item, inventories[oldInventory.invID], inventories[self.invID]) == false) then
return false, "notAllowed"
end
if (item.CanTransfer and
item:CanTransfer(inventory, inventory != inventory2 and inventory2 or nil) == false) then
return false
end
end
if (!noSend) then
net.Start("ixInventoryMove")
net.WriteUInt(oldX, 6)
net.WriteUInt(oldY, 6)
net.WriteUInt(x, 6)
net.WriteUInt(y, 6)
net.WriteUInt(oldInventory.invID, 32)
net.WriteUInt(self != oldInventory and self.invID or oldInventory.invID, 32)
net.SendToServer()
end
if (inventory) then
inventory.slots[oldX][oldY] = nil
end
if (item and inventory2) then
inventory2.slots[x] = inventory2.slots[x] or {}
inventory2.slots[x][y] = item
end
end
function PANEL:AddIcon(model, x, y, w, h, skin)
local iconSize = self.iconSize
w = w or 1
h = h or 1
if (self.slots[x] and self.slots[x][y]) then
local panel = self:Add("ixItemIcon")
panel:SetSize(w * iconSize, h * iconSize)
panel:SetZPos(999)
panel:InvalidateLayout(true)
panel:SetModel(model, skin)
panel:SetPos(self.slots[x][y]:GetPos())
panel.gridX = x
panel.gridY = y
panel.gridW = w
panel.gridH = h
local inventory = ix.item.inventories[self.invID]
if (!inventory) then
return
end
local itemTable = inventory:GetItemAt(panel.gridX, panel.gridY)
panel:SetInventoryID(inventory:GetID())
panel:SetItemTable(itemTable)
if (self.panels[itemTable:GetID()]) then
self.panels[itemTable:GetID()]:Remove()
end
if (itemTable.exRender) then
panel.Icon:SetVisible(false)
panel.ExtraPaint = function(this, panelX, panelY)
local exIcon = ikon:GetIcon(itemTable.uniqueID)
if (exIcon) then
surface.SetMaterial(exIcon)
surface.SetDrawColor(color_white)
surface.DrawTexturedRect(0, 0, panelX, panelY)
else
ikon:renderIcon(
itemTable.uniqueID,
itemTable.width,
itemTable.height,
itemTable:GetModel(),
itemTable.iconCam
)
end
end
else
-- yeah..
RenderNewIcon(panel, itemTable)
end
panel.slots = {}
for i = 0, w - 1 do
for i2 = 0, h - 1 do
local slot = self.slots[x + i] and self.slots[x + i][y + i2]
if (IsValid(slot)) then
slot.item = panel
panel.slots[#panel.slots + 1] = slot
else
for _, v in ipairs(panel.slots) do
v.item = nil
end
panel:Remove()
return
end
end
end
return panel
end
end
function PANEL:ReceiveDrop(panels, bDropped, menuIndex, x, y)
local panel = panels[1]
if (!IsValid(panel)) then
self.previewPanel = nil
return
end
if (bDropped) then
local inventory = ix.item.inventories[self.invID]
if (inventory and panel.OnDrop) then
local dropX = math.ceil((x - 4 - (panel.gridW - 1) * 32) / self.iconSize)
local dropY = math.ceil((y - self:GetPadding(2) - (panel.gridH - 1) * 32) / self.iconSize)
panel:OnDrop(true, self, inventory, dropX, dropY)
end
self.previewPanel = nil
else
self.previewPanel = panel
self.previewX = x
self.previewY = y
end
end
vgui.Register("ixInventory", PANEL, "DFrame")
hook.Add("CreateMenuButtons", "ixInventory", function(tabs)
if (hook.Run("CanPlayerViewInventory") == false) then
return
end
tabs["inv"] = {
bDefault = true,
Create = function(info, container)
local canvas = container:Add("DTileLayout")
local canvasLayout = canvas.PerformLayout
canvas.PerformLayout = nil -- we'll layout after we add the panels instead of each time one is added
canvas:SetBorder(0)
canvas:SetSpaceX(2)
canvas:SetSpaceY(2)
canvas:Dock(FILL)
ix.gui.menuInventoryContainer = canvas
local panel = canvas:Add("ixInventory")
panel:SetPos(0, 0)
panel:SetDraggable(false)
panel:SetSizable(false)
panel:SetTitle(nil)
panel.bNoBackgroundBlur = true
panel.childPanels = {}
local inventory = LocalPlayer():GetCharacter():GetInventory()
if (inventory) then
panel:SetInventory(inventory)
end
ix.gui.inv1 = panel
if (ix.option.Get("openBags", true)) then
for _, v in pairs(inventory:GetItems()) do
if (!v.isBag) then
continue
end
v.functions.View.OnClick(v)
end
end
canvas.PerformLayout = canvasLayout
canvas:Layout()
end
}
end)
hook.Add("PostRenderVGUI", "ixInvHelper", function()
local pnl = ix.gui.inv1
hook.Run("PostDrawInventory", pnl)
end)

View File

@@ -0,0 +1,501 @@
--[[
| 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/
--]]
local animationTime = 1
local matrixZScale = Vector(1, 1, 0.0001)
DEFINE_BASECLASS("ixSubpanelParent")
local PANEL = {}
AccessorFunc(PANEL, "bCharacterOverview", "CharacterOverview", FORCE_BOOL)
function PANEL:Init()
if (IsValid(ix.gui.menu)) then
ix.gui.menu:Remove()
end
ix.gui.menu = self
-- properties
self.manualChildren = {}
self.noAnchor = CurTime() + 0.4
self.anchorMode = true
self.rotationOffset = Angle(0, 180, 0)
self.projectedTexturePosition = Vector(0, 0, 6)
self.projectedTextureRotation = Angle(-45, 60, 0)
self.bCharacterOverview = false
self.bOverviewOut = false
self.overviewFraction = 0
self.currentAlpha = 0
self.currentBlur = 0
-- setup
self:SetPadding(ScreenScale(16), true)
self:SetSize(ScrW(), ScrH())
self:SetPos(0, 0)
self:SetLeftOffset(self:GetWide() * 0.25 + self:GetPadding())
-- main button panel
self.buttons = self:Add("Panel")
self.buttons:SetSize(self:GetWide() * 0.25, self:GetTall() - self:GetPadding() * 2)
self.buttons:Dock(LEFT)
self.buttons:SetPaintedManually(true)
local close = self.buttons:Add("ixMenuButton")
close:SetText("return")
close:SizeToContents()
close:Dock(BOTTOM)
close.DoClick = function()
self:Remove()
end
local characters = self.buttons:Add("ixMenuButton")
characters:SetText("characters")
characters:SizeToContents()
characters:Dock(BOTTOM)
characters.DoClick = function()
self:Remove()
vgui.Create("ixCharMenu")
end
-- @todo make a better way to avoid clicks in the padding PLEASE
self.guard = self:Add("Panel")
self.guard:SetPos(0, 0)
self.guard:SetSize(self:GetPadding(), self:GetTall())
-- tabs
self.tabs = self.buttons:Add("Panel")
self.tabs.buttons = {}
self.tabs:Dock(FILL)
self:PopulateTabs()
self:MakePopup()
self:OnOpened()
end
function PANEL:OnOpened()
self:SetAlpha(0)
self:CreateAnimation(animationTime, {
target = {currentAlpha = 255},
easing = "outQuint",
Think = function(animation, panel)
panel:SetAlpha(panel.currentAlpha)
end
})
end
function PANEL:GetActiveTab()
return (self:GetActiveSubpanel() or {}).subpanelName
end
function PANEL:TransitionSubpanel(id)
local lastSubpanel = self:GetActiveSubpanel()
-- don't transition to the same panel
if (IsValid(lastSubpanel) and lastSubpanel.subpanelID == id) then
return
end
local subpanel = self:GetSubpanel(id)
if (IsValid(subpanel)) then
if (!subpanel.bPopulated) then
-- we need to set the size of the subpanel if it's a section since it will be 0, 0
if (subpanel.sectionParent) then
subpanel:SetSize(self:GetStandardSubpanelSize())
end
local info = subpanel.info
subpanel.Paint = nil
if (istable(info) and info.Create) then
info:Create(subpanel)
elseif (isfunction(info)) then
info(subpanel)
end
hook.Run("MenuSubpanelCreated", subpanel.subpanelName, subpanel)
subpanel.bPopulated = true
end
-- only play whoosh sound only when the menu was already open
if (IsValid(lastSubpanel)) then
LocalPlayer():EmitSound("Helix.Whoosh")
end
self:SetActiveSubpanel(id)
end
subpanel = self:GetActiveSubpanel()
local info = subpanel.info
local bHideBackground = istable(info) and (info.bHideBackground != nil and info.bHideBackground or false) or false
if (bHideBackground) then
self:HideBackground()
else
self:ShowBackground()
end
-- call hooks if we've changed subpanel
if (IsValid(lastSubpanel) and istable(lastSubpanel.info) and lastSubpanel.info.OnDeselected) then
lastSubpanel.info:OnDeselected(lastSubpanel)
end
if (IsValid(subpanel) and istable(subpanel.info) and subpanel.info.OnSelected) then
subpanel.info:OnSelected(subpanel)
end
ix.gui.lastMenuTab = id
end
function PANEL:SetCharacterOverview(bValue, length)
bValue = tobool(bValue)
length = length or animationTime
if (bValue) then
if (!IsValid(self.projectedTexture)) then
self.projectedTexture = ProjectedTexture()
end
local faction = ix.faction.indices[LocalPlayer():Team()]
local color = faction and faction.color or color_white
self.projectedTexture:SetEnableShadows(false)
self.projectedTexture:SetNearZ(12)
self.projectedTexture:SetFarZ(64)
self.projectedTexture:SetFOV(90)
self.projectedTexture:SetColor(color)
self.projectedTexture:SetTexture("effects/flashlight/soft")
self:CreateAnimation(length, {
index = 3,
target = {overviewFraction = 1},
easing = "outQuint",
bIgnoreConfig = true
})
self.bOverviewOut = false
self.bCharacterOverview = true
else
self:CreateAnimation(length, {
index = 3,
target = {overviewFraction = 0},
easing = "outQuint",
bIgnoreConfig = true,
OnComplete = function(animation, panel)
panel.bCharacterOverview = false
if (IsValid(panel.projectedTexture)) then
panel.projectedTexture:Remove()
end
end
})
self.bOverviewOut = true
end
end
function PANEL:GetOverviewInfo(origin, angles, fov)
local originAngles = Angle(0, angles.yaw, angles.roll)
local target = LocalPlayer():GetObserverTarget()
local fraction = self.overviewFraction
local bDrawPlayer = ((fraction > 0.2) or (!self.bOverviewOut and (fraction > 0.2))) and !IsValid(target)
local forward = originAngles:Forward() * 58 - originAngles:Right() * 16
forward.z = 0
local newOrigin
if (IsValid(target)) then
newOrigin = target:GetPos() + forward
else
newOrigin = origin - LocalPlayer():OBBCenter() * 0.6 + forward
end
local newAngles = originAngles + self.rotationOffset
newAngles.pitch = 5
newAngles.roll = 0
return LerpVector(fraction, origin, newOrigin), LerpAngle(fraction, angles, newAngles), Lerp(fraction, fov, 90), bDrawPlayer
end
function PANEL:HideBackground()
self:CreateAnimation(animationTime, {
index = 2,
target = {currentBlur = 0},
easing = "outQuint"
})
end
function PANEL:ShowBackground()
self:CreateAnimation(animationTime, {
index = 2,
target = {currentBlur = 1},
easing = "outQuint"
})
end
function PANEL:GetStandardSubpanelSize()
return ScrW() * 0.75 - self:GetPadding() * 3, ScrH() - self:GetPadding() * 2
end
function PANEL:SetupTab(name, info, sectionParent)
local bTable = istable(info)
local buttonColor = (bTable and info.buttonColor) or (ix.config.Get("color") or Color(140, 140, 140, 255))
local bDefault = (bTable and info.bDefault) or false
local qualifiedName = sectionParent and (sectionParent.name .. "/" .. name) or name
-- setup subpanels without populating them so we can retain the order
local subpanel = self:AddSubpanel(qualifiedName, true)
local id = subpanel.subpanelID
subpanel.info = info
subpanel.sectionParent = sectionParent and qualifiedName
subpanel:SetPaintedManually(true)
subpanel:SetTitle(nil)
if (sectionParent) then
-- hide section subpanels if they haven't been populated to seeing more subpanels than necessary
-- fly by as you navigate tabs in the menu
subpanel:SetSize(0, 0)
else
subpanel:SetSize(self:GetStandardSubpanelSize())
-- this is called while the subpanel has not been populated
subpanel.Paint = function(panel, width, height)
derma.SkinFunc("PaintPlaceholderPanel", panel, width, height)
end
end
local button
if (sectionParent) then
button = sectionParent:AddSection(L(name))
name = qualifiedName
else
button = self.tabs:Add("ixMenuSelectionButton")
button:SetText(L(name))
button:SizeToContents()
button:Dock(TOP)
button:SetButtonList(self.tabs.buttons)
button:SetBackgroundColor(buttonColor)
end
button.name = name
button.id = id
button.OnSelected = function()
self:TransitionSubpanel(id)
end
if (bTable and info.PopulateTabButton) then
info:PopulateTabButton(button)
end
-- don't allow sections in sections
if (sectionParent or !bTable or !info.Sections) then
return bDefault, button, subpanel
end
-- create button sections
for sectionName, sectionInfo in pairs(info.Sections) do
self:SetupTab(sectionName, sectionInfo, button)
end
return bDefault, button, subpanel
end
function PANEL:PopulateTabs()
local default
local tabs = {}
hook.Run("CreateMenuButtons", tabs)
for name, info in SortedPairs(tabs) do
local bDefault, button = self:SetupTab(name, info)
if (bDefault) then
default = button
end
end
if (ix.gui.lastMenuTab) then
for i = 1, #self.tabs.buttons do
local button = self.tabs.buttons[i]
if (button.id == ix.gui.lastMenuTab) then
default = button
break
end
end
end
if (!IsValid(default) and #self.tabs.buttons > 0) then
default = self.tabs.buttons[1]
end
if (IsValid(default)) then
default:SetSelected(true)
self:SetActiveSubpanel(default.id, 0)
end
self.buttons:MoveToFront()
self.guard:MoveToBefore(self.buttons)
end
function PANEL:AddManuallyPaintedChild(panel)
panel:SetParent(self)
panel:SetPaintedManually(panel)
self.manualChildren[#self.manualChildren + 1] = panel
end
function PANEL:OnKeyCodePressed(key)
self.noAnchor = CurTime() + 0.5
if (key == KEY_TAB) then
self:Remove()
end
end
function PANEL:Think()
if (IsValid(self.projectedTexture)) then
local forward = LocalPlayer():GetForward()
forward.z = 0
local right = LocalPlayer():GetRight()
right.z = 0
self.projectedTexture:SetBrightness(self.overviewFraction * 4)
self.projectedTexture:SetPos(LocalPlayer():GetPos() + right * 16 - forward * 8 + self.projectedTexturePosition)
self.projectedTexture:SetAngles(forward:Angle() + self.projectedTextureRotation)
self.projectedTexture:Update()
end
if (self.bClosing) then
return
end
local bTabDown = input.IsKeyDown(KEY_TAB)
if (bTabDown and (self.noAnchor or CurTime() + 0.4) < CurTime() and self.anchorMode) then
self.anchorMode = false
surface.PlaySound("buttons/lightswitch2.wav")
end
if ((!self.anchorMode and !bTabDown) or gui.IsGameUIVisible()) then
self:Remove()
end
end
function PANEL:Paint(width, height)
derma.SkinFunc("PaintMenuBackground", self, width, height, self.currentBlur)
local bShouldScale = self.currentAlpha != 255
if (bShouldScale) then
local currentScale = Lerp(self.currentAlpha / 255, 0.9, 1)
local matrix = Matrix()
matrix:Scale(matrixZScale * currentScale)
matrix:Translate(Vector(
ScrW() * 0.5 - (ScrW() * currentScale * 0.5),
ScrH() * 0.5 - (ScrH() * currentScale * 0.5),
1
))
cam.PushModelMatrix(matrix)
end
BaseClass.Paint(self, width, height)
self:PaintSubpanels(width, height)
self.buttons:PaintManual()
for i = 1, #self.manualChildren do
self.manualChildren[i]:PaintManual()
end
if (IsValid(ix.gui.inv1) and ix.gui.inv1.childPanels) then
for i = 1, #ix.gui.inv1.childPanels do
local panel = ix.gui.inv1.childPanels[i]
if (IsValid(panel)) then
panel:PaintManual()
end
end
end
if (bShouldScale) then
cam.PopModelMatrix()
end
end
function PANEL:PerformLayout()
self.guard:SetSize(self.tabs:GetWide() + self:GetPadding() * 2, self:GetTall())
end
function PANEL:Remove()
self.bClosing = true
self:SetMouseInputEnabled(false)
self:SetKeyboardInputEnabled(false)
self:SetCharacterOverview(false, animationTime * 0.5)
-- remove input from opened child panels since they grab focus
if (IsValid(ix.gui.inv1) and ix.gui.inv1.childPanels) then
for i = 1, #ix.gui.inv1.childPanels do
local panel = ix.gui.inv1.childPanels[i]
if (IsValid(panel)) then
panel:SetMouseInputEnabled(false)
panel:SetKeyboardInputEnabled(false)
end
end
end
CloseDermaMenus()
gui.EnableScreenClicker(false)
self:CreateAnimation(animationTime * 0.5, {
index = 2,
target = {currentBlur = 0},
easing = "outQuint"
})
self:CreateAnimation(animationTime * 0.5, {
target = {currentAlpha = 0},
easing = "outQuint",
-- we don't animate the blur because blurring doesn't draw things
-- with amount < 1 very well, resulting in jarring transition
Think = function(animation, panel)
panel:SetAlpha(panel.currentAlpha)
end,
OnComplete = function(animation, panel)
if (IsValid(panel.projectedTexture)) then
panel.projectedTexture:Remove()
end
BaseClass.Remove(panel)
end
})
end
vgui.Register("ixMenu", PANEL, "ixSubpanelParent")
if (IsValid(ix.gui.menu)) then
ix.gui.menu:Remove()
end
ix.gui.lastMenuTab = nil

View File

@@ -0,0 +1,305 @@
--[[
| 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/
--]]
local buttonPadding = ScreenScale(14) * 0.5
local animationTime = 0.5
-- base menu button
DEFINE_BASECLASS("DButton")
local PANEL = {}
AccessorFunc(PANEL, "backgroundColor", "BackgroundColor")
AccessorFunc(PANEL, "backgroundAlpha", "BackgroundAlpha")
function PANEL:Init()
self:SetFont("ixMenuButtonFont")
self:SetTextColor(color_white)
self:SetPaintBackground(false)
self:SetContentAlignment(4)
self:SetTextInset(buttonPadding, 0)
self.padding = {32, 12, 32, 12} -- left, top, right, bottom
self.backgroundColor = Color(0, 0, 0)
self.backgroundAlpha = 128
self.currentBackgroundAlpha = 0
end
function PANEL:GetPadding()
return self.padding
end
function PANEL:SetPadding(left, top, right, bottom)
self.padding = {
left or self.padding[1],
top or self.padding[2],
right or self.padding[3],
bottom or self.padding[4]
}
end
function PANEL:SetText(text, noTranslation)
BaseClass.SetText(self, noTranslation and text:utf8upper() or L(text):utf8upper())
end
function PANEL:SizeToContents()
BaseClass.SizeToContents(self)
local width, height = self:GetSize()
self:SetSize(width + self.padding[1] + self.padding[3], height + self.padding[2] + self.padding[4])
end
function PANEL:PaintBackground(width, height)
surface.SetDrawColor(ColorAlpha(self.backgroundColor, self.currentBackgroundAlpha))
surface.DrawRect(0, 0, width, height)
end
function PANEL:Paint(width, height)
self:PaintBackground(width, height)
BaseClass.Paint(self, width, height)
end
function PANEL:SetTextColorInternal(color)
BaseClass.SetTextColor(self, color)
self:SetFGColor(color)
end
function PANEL:SetTextColor(color)
self:SetTextColorInternal(color)
self.color = color
end
function PANEL:SetDisabled(bValue)
local color = self.color
if (bValue) then
self:SetTextColorInternal(Color(math.max(color.r - 60, 0), math.max(color.g - 60, 0), math.max(color.b - 60, 0)))
else
self:SetTextColorInternal(color)
end
BaseClass.SetDisabled(self, bValue)
end
function PANEL:OnCursorEntered()
if (self:GetDisabled()) then
return
end
local color = self:GetTextColor()
self:SetTextColorInternal(Color(math.max(color.r - 25, 0), math.max(color.g - 25, 0), math.max(color.b - 25, 0)))
self:CreateAnimation(0.15, {
target = {currentBackgroundAlpha = self.backgroundAlpha}
})
LocalPlayer():EmitSound("Helix.Rollover")
end
function PANEL:OnCursorExited()
if (self:GetDisabled()) then
return
end
if (self.color) then
self:SetTextColor(self.color)
else
self:SetTextColor(color_white)
end
self:CreateAnimation(0.15, {
target = {currentBackgroundAlpha = 0}
})
end
function PANEL:OnMousePressed(code)
if (self:GetDisabled()) then
return
end
if (self.color) then
self:SetTextColor(self.color)
else
self:SetTextColor(ix.config.Get("color"))
end
LocalPlayer():EmitSound("Helix.Press")
if (code == MOUSE_LEFT and self.DoClick) then
self:DoClick(self)
elseif (code == MOUSE_RIGHT and self.DoRightClick) then
self:DoRightClick(self)
end
end
function PANEL:OnMouseReleased(key)
if (self:GetDisabled()) then
return
end
if (self.color) then
self:SetTextColor(self.color)
else
self:SetTextColor(color_white)
end
end
vgui.Register("ixMenuButton", PANEL, "DButton")
-- selection menu button
DEFINE_BASECLASS("ixMenuButton")
PANEL = {}
AccessorFunc(PANEL, "backgroundColor", "BackgroundColor")
AccessorFunc(PANEL, "selected", "Selected", FORCE_BOOL)
AccessorFunc(PANEL, "buttonList", "ButtonList")
function PANEL:Init()
self.backgroundColor = color_white
self.selected = false
self.buttonList = {}
self.sectionPanel = nil -- sub-sections this button has; created only if it has any sections
end
function PANEL:PaintBackground(width, height)
local alpha = self.selected and 255 or self.currentBackgroundAlpha
derma.SkinFunc("DrawImportantBackground", 0, 0, width, height, ColorAlpha(self.backgroundColor, alpha))
end
function PANEL:SetSelected(bValue, bSelectedSection)
self.selected = bValue
if (bValue) then
self:OnSelected()
if (self.sectionPanel) then
self.sectionPanel:Show()
elseif (self.sectionParent) then
self.sectionParent.sectionPanel:Show()
end
elseif (self.sectionPanel and self.sectionPanel:IsVisible() and !bSelectedSection) then
self.sectionPanel:Hide()
end
end
function PANEL:SetButtonList(list, bNoAdd)
if (!bNoAdd) then
list[#list + 1] = self
end
self.buttonList = list
end
function PANEL:GetSectionPanel()
return self.sectionPanel
end
function PANEL:AddSection(name)
if (!IsValid(self.sectionPanel)) then
-- add section panel to regular button list
self.sectionPanel = vgui.Create("ixMenuSelectionList", self:GetParent())
self.sectionPanel:Dock(self:GetDock())
self.sectionPanel:SetParentButton(self)
end
return self.sectionPanel:AddButton(name, self.buttonList)
end
function PANEL:OnMousePressed(key)
for _, v in pairs(self.buttonList) do
if (IsValid(v) and v != self) then
v:SetSelected(false, self.sectionParent == v)
end
end
self:SetSelected(true)
BaseClass.OnMousePressed(self, key)
end
function PANEL:OnSelected()
end
vgui.Register("ixMenuSelectionButton", PANEL, "ixMenuButton")
-- collapsable list for menu button sections
PANEL = {}
AccessorFunc(PANEL, "parent", "ParentButton")
function PANEL:Init()
self.parent = nil -- button that is responsible for controlling this list
self.height = 0
self.targetHeight = 0
self:DockPadding(0, 1, 0, 1)
self:SetVisible(false)
self:SetTall(0)
end
function PANEL:AddButton(name, buttonList)
assert(IsValid(self.parent), "attempted to add button to ixMenuSelectionList without a ParentButton")
assert(buttonList ~= nil, "attempted to add button to ixMenuSelectionList without a buttonList")
local button = self:Add("ixMenuSelectionButton")
button.sectionParent = self.parent
button:SetTextInset(buttonPadding * 2, 0)
button:SetPadding(nil, 8, nil, 8)
button:SetFont("ixMenuButtonFontSmall")
button:Dock(TOP)
button:SetText(name)
button:SizeToContents()
button:SetButtonList(buttonList)
button:SetBackgroundColor(self.parent:GetBackgroundColor())
self.targetHeight = self.targetHeight + button:GetTall()
return button
end
function PANEL:Show()
self:SetVisible(true)
self:CreateAnimation(animationTime, {
index = 1,
target = {
height = self.targetHeight + 2 -- +2 for padding
},
easing = "outQuart",
Think = function(animation, panel)
panel:SetTall(panel.height)
end
})
end
function PANEL:Hide()
self:CreateAnimation(animationTime, {
index = 1,
target = {
height = 0
},
easing = "outQuint",
Think = function(animation, panel)
panel:SetTall(panel.height)
end,
OnComplete = function(animation, panel)
panel:SetVisible(false)
end
})
end
function PANEL:Paint(width, height)
surface.SetDrawColor(Color(255, 255, 255, 33))
surface.DrawRect(0, 0, width, 1)
surface.DrawRect(0, height - 1, width, 1)
end
vgui.Register("ixMenuSelectionList", PANEL, "Panel")

View File

@@ -0,0 +1,130 @@
--[[
| 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/
--]]
DEFINE_BASECLASS("DModelPanel")
local PANEL = {}
local MODEL_ANGLE = Angle(0, 45, 0)
function PANEL:Init()
self.brightness = 1
self:SetCursor("none")
end
function PANEL:SetModel(model, skin, bodygroups)
if (IsValid(self.Entity)) then
self.Entity:Remove()
self.Entity = nil
end
if (!ClientsideModel) then
return
end
local entity = ClientsideModel(model, RENDERGROUP_OPAQUE)
if (!IsValid(entity)) then
return
end
entity:SetNoDraw(true)
entity:SetIK(false)
if (skin) then
entity:SetSkin(skin)
end
if (isstring(bodygroups)) then
entity:SetBodyGroups(bodygroups)
end
local sequence = entity:LookupSequence("idle_unarmed")
if (sequence <= 0) then
sequence = entity:SelectWeightedSequence(ACT_IDLE)
end
if (sequence > 0) then
entity:ResetSequence(sequence)
else
local found = false
for _, v in ipairs(entity:GetSequenceList()) do
if ((v:lower():find("idle") or v:lower():find("fly")) and v != "idlenoise") then
entity:ResetSequence(v)
found = true
break
end
end
if (!found) then
entity:ResetSequence(4)
end
end
self.Entity = entity
end
function PANEL:LayoutEntity()
local scrW, scrH = ScrW(), ScrH()
local xRatio = gui.MouseX() / scrW
local yRatio = gui.MouseY() / scrH
local x, _ = self:LocalToScreen(self:GetWide() / 2)
local xRatio2 = x / scrW
local entity = self.Entity
entity:SetPoseParameter("head_pitch", yRatio*90 - 30)
entity:SetPoseParameter("head_yaw", (xRatio - xRatio2)*90 - 5)
entity:SetAngles(MODEL_ANGLE)
entity:SetIK(false)
if (self.copyLocalSequence) then
entity:SetSequence(LocalPlayer():GetSequence())
entity:SetPoseParameter("move_yaw", 360 * LocalPlayer():GetPoseParameter("move_yaw") - 180)
end
self:RunAnimation()
end
function PANEL:DrawModel()
local brightness = self.brightness * 0.4
local brightness2 = self.brightness * 1.5
render.SetStencilEnable(false)
render.SetColorMaterial()
render.SetColorModulation(1, 1, 1)
render.SetModelLighting(0, brightness2, brightness2, brightness2)
for i = 1, 4 do
render.SetModelLighting(i, brightness, brightness, brightness)
end
local fraction = (brightness / 1) * 0.1
render.SetModelLighting(5, fraction, fraction, fraction)
-- Excecute Some stuffs
if (self.enableHook) then
hook.Run("DrawHelixModelView", self, self.Entity)
end
self.Entity:DrawModel()
if (self.enableHook) then
hook.Run("PostDrawHelixModelView", self, self.Entity)
end
end
function PANEL:OnMousePressed()
end
vgui.Register("ixModelPanel", PANEL, "DModelPanel")

View File

@@ -0,0 +1,280 @@
--[[
| 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/
--]]
local animationTime = 0.75
-- notice manager
-- this manages positions/animations for notice panels
local PANEL = {}
AccessorFunc(PANEL, "padding", "Padding", FORCE_NUMBER)
function PANEL:Init()
self:SetSize(ScrW() * 0.4, ScrH())
self:SetPos(ScrW() - ScrW() * 0.4, 0)
self:SetZPos(-99999)
self:SetMouseInputEnabled(false)
self:SetKeyboardInputEnabled(false)
self.notices = {}
self.padding = 4
end
function PANEL:GetAll()
return self.notices
end
function PANEL:Clear()
for _, v in ipairs(self.notices) do
self:RemoveNotice(v)
end
end
function PANEL:AddNotice(text, bError)
if (IsValid(ix.gui.characterMenu) and !ix.gui.characterMenu.bClosing) then
return
end
local textLength = text:utf8len()
local panel = self:Add("ixNotice")
panel:SetText(text)
panel:SetError(bError or text:utf8sub(textLength, textLength) == "!")
panel:SizeToContents()
panel.currentY = -panel:GetTall()
panel:SetPos(self.padding, panel.currentY)
-- setup duration timer
panel:CreateAnimation(ix.option.Get("noticeDuration", 8), {
index = 2,
target = {duration = 1},
bIgnoreConfig = true,
OnComplete = function(animation, this)
self:RemoveNotice(this)
end
})
table.insert(self.notices, 1, panel)
self:Organize()
-- remove old notice if we've hit the limit of notices
if (#self.notices > ix.option.Get("noticeMax", 4)) then
for i = #self.notices, 1, -1 do
local notice = self.notices[i]
if (IsValid(notice) and !notice.bClosing) then
self:RemoveNotice(notice)
break
end
end
end
return panel
end
function PANEL:RemoveNotice(panel)
panel.bClosing = true
panel:CreateAnimation(animationTime, {
index = 3,
target = {outAnimation = 0},
easing = "outQuint",
OnComplete = function(animation, this)
local toRemove
for k, v in ipairs(self.notices) do
if (v == this) then
toRemove = k
break
end
end
if (toRemove) then
table.remove(self.notices, toRemove)
end
this:SetText("") -- (hack) text remains for a frame after remove is called, so let's make sure we don't draw it
this:Remove()
end
})
end
-- update target Y positions and animations
function PANEL:Organize()
local currentTarget = self.padding
for _, v in ipairs(self.notices) do
v:CreateAnimation(animationTime, {
index = 1,
target = {currentY = currentTarget},
easing = "outElastic",
Think = function(animation, panel)
panel:SetPos(
self:GetWide() - panel:GetWide() - self.padding,
math.min(panel.currentY + 1, currentTarget) -- easing eventually hits subpixel movement so we level it off
)
end
})
currentTarget = currentTarget + self.padding + v:GetTall()
end
end
vgui.Register("ixNoticeManager", PANEL, "Panel")
-- notice panel
-- these do not manage their own enter/exit animations or lifetime
DEFINE_BASECLASS("DLabel")
PANEL = {}
AccessorFunc(PANEL, "bError", "Error", FORCE_BOOL)
AccessorFunc(PANEL, "padding", "Padding", FORCE_NUMBER)
function PANEL:Init()
self:SetSize(256, 36)
self:SetContentAlignment(5)
self:SetExpensiveShadow(1, Color(0, 0, 0, 150))
self:SetFont("ixNoticeFont")
self:SetTextColor(color_white)
self:SetDrawOnTop(true)
self:DockPadding(0, 0, 0, 0)
self:DockMargin(0, 0, 0, 0)
self.bError = false
self.bHovered = false
self.errorAnimation = 0
self.padding = 8
self.currentY = 0
self.duration = 0
self.outAnimation = 1
self.alpha = 255
LocalPlayer():EmitSound("Helix.Notify")
end
function PANEL:SetError(bValue)
self.bError = tobool(bValue)
if (bValue) then
self.errorAnimation = 1
self:CreateAnimation(animationTime, {
index = 5,
target = {errorAnimation = 0},
easing = "outQuint"
})
end
end
function PANEL:SizeToContents()
local contentWidth, contentHeight = self:GetContentSize()
contentWidth = contentWidth + self.padding * 2
contentHeight = contentHeight + self.padding * 2
local manager = ix.gui.notices
local maxWidth = math.min(IsValid(manager) and (manager:GetWide() - manager:GetPadding() * 2) or ScrW(), contentWidth)
if (contentWidth > maxWidth) then
self:SetWide(maxWidth)
self:SetTextInset(self.padding * 2, 0)
self:SetWrap(true)
self:SizeToContentsY()
self:SetWide(self:GetContentSize())
else
self:SetSize(contentWidth, contentHeight)
end
end
function PANEL:SizeToContentsY()
BaseClass.SizeToContentsY(self)
self:SetTall(self:GetTall() + self.padding * 2)
end
function PANEL:OnMouseHover()
self:CreateAnimation(animationTime * 0.5, {
index = 4,
target = {alpha = 0},
easing = "outQuint",
Think = function(animation, panel)
panel:SetAlpha(panel.alpha)
end
})
end
function PANEL:OnMouseLeave()
self:CreateAnimation(animationTime * 0.5, {
index = 4,
target = {alpha = 255},
easing = "outQuint",
Think = function(animation, panel)
panel:SetAlpha(panel.alpha)
end
})
end
function PANEL:Paint(width, height)
if (self.outAnimation < 1) then
local x, y = self:LocalToScreen(0, 0)
render.SetScissorRect(x, y, x + self:GetWide(), y + (self:GetTall() * self.outAnimation), true)
end
local x, y = self:LocalToScreen(0, 0)
local mouseX, mouseY = gui.MousePos()
if (mouseX >= x and mouseX <= x + width and
mouseY >= y and mouseY <= y + height) then
if (!self.bHovered) then
self.bHovered = true
self:OnMouseHover()
end
elseif (self.bHovered) then
self.bHovered = false
self:OnMouseLeave()
end
ix.util.DrawBlur(self)
if (self.errorAnimation > 0) then
local color = derma.GetColor("Error", self)
surface.SetDrawColor(
color.r * self.errorAnimation,
color.g * self.errorAnimation,
color.b * self.errorAnimation,
self.errorAnimation * 255 + ((1 - self.errorAnimation) * 66)
)
else
surface.SetDrawColor(0, 0, 0, 66)
end
surface.DrawRect(0, 0, width, height)
surface.SetDrawColor(self.bError and derma.GetColor("Error", self) or ix.config.Get("color"))
surface.DrawRect(0, height - 1, width * self.duration, 1)
end
function PANEL:PaintOver(width, height)
render.SetScissorRect(0, 0, 0, 0, false)
end
vgui.Register("ixNotice", PANEL, "DLabel")
if (IsValid(ix.gui.notices)) then
ix.gui.notices:Remove()
ix.gui.notices = vgui.Create("ixNoticeManager")
else
ix.gui.notices = vgui.Create("ixNoticeManager")
end

View File

@@ -0,0 +1,98 @@
--[[
| 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/
--]]
local PANEL = {
types = {
"Info", -- info
"Success", -- success
"Error" -- error
}
}
AccessorFunc(PANEL, "type", "Type", FORCE_NUMBER)
AccessorFunc(PANEL, "padding", "Padding", FORCE_NUMBER)
AccessorFunc(PANEL, "length", "Length", FORCE_NUMBER)
AccessorFunc(PANEL, "hidden", "Hidden", FORCE_BOOL)
function PANEL:Init()
self.type = 1
self.padding = 8
self.length = 4
self.currentY = 0
self.hidden = true
self.text = self:Add("DLabel")
self.text:SetFont("ixNoticeFont")
self.text:SetContentAlignment(5)
self.text:SetTextColor(color_white)
self.text:SizeToContents()
self.text:Dock(FILL)
self:SetSize(self:GetParent():GetWide() - (self.padding * 4), self.text:GetTall() + (self.padding * 2))
self:SetPos(self.padding * 2, -self:GetTall() - self.padding)
end
function PANEL:SetFont(value)
self.text:SetFont(value)
self.text:SizeToContents()
end
function PANEL:SetText(text)
self.text:SetText(text)
self.text:SizeToContents()
end
function PANEL:Slide(direction, length)
direction = direction or "up"
length = length or 0.5
timer.Remove("ixNoticeBarAnimation")
local x, _ = self:GetPos()
local baseY = direction == "up" and self.padding * 2 or (-self:GetTall() - self.padding)
local targetY = direction == "up" and (-self:GetTall() - self.padding) or self.padding * 2
local easing = direction == "up" and "outQuint" or "outElastic"
self:SetPos(x, baseY)
self.currentY = baseY
self.hidden = direction == "up"
self:CreateAnimation(length, {
target = {currentY = targetY},
easing = easing,
Think = function(animation, panel)
local lastX, _ = panel:GetPos()
panel:SetPos(lastX, panel.currentY)
end
})
end
function PANEL:Show(bRemove)
self:Slide("down")
timer.Create("ixNoticeBarAnimation", self.length - 0.5, 1, function()
if (!IsValid(self)) then
return
end
self:Slide("up")
end)
end
function PANEL:Paint(width, height)
local color = derma.GetColor(self.types[self.type], self)
surface.SetDrawColor(color)
surface.DrawRect(0, 0, width, height)
end
vgui.Register("ixNoticeBar", PANEL, "Panel")

View File

@@ -0,0 +1,253 @@
--[[
| 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/
--]]
-- overrides standard derma panels to add/change functionality
local PANEL = {}
local OVERRIDES = {}
-- @todo remove me when autorefresh support is no longer needed
local function OverridePanel(name, func)
PANEL = vgui.GetControlTable(name)
if (!istable(PANEL)) then
return
end
OVERRIDES = {}
func()
for k, _ in pairs(PANEL) do
local overrideName = "ix" .. k
if (PANEL[overrideName] and !OVERRIDES[k]) then
print("unhooking override ", overrideName)
PANEL[k] = PANEL[overrideName]
PANEL[overrideName] = nil
end
end
end
local function Override(name)
local oldMethod = "ix" .. name
OVERRIDES[name] = true
if (PANEL[oldMethod]) then
return
end
PANEL[oldMethod] = PANEL[name]
end
OverridePanel("DMenuOption", function()
function PANEL:PerformLayout()
self:SizeToContents()
self:SetWide(self:GetWide() + 30)
local w = math.max(self:GetParent():GetWide(), self:GetWide())
self:SetSize(w, self:GetTall() + 4)
if (self.SubMenuArrow) then
self.SubMenuArrow:SetSize(15, 15)
self.SubMenuArrow:CenterVertical()
self.SubMenuArrow:AlignRight(4)
end
DButton.PerformLayout(self)
end
end)
OverridePanel("DMenu", function()
local animationTime = 0.33
Override("Init")
function PANEL:Init(...)
self:ixInit(...)
self.ixAnimation = 0
end
function PANEL:SetFont(font)
for _, v in pairs(self:GetCanvas():GetChildren()) do
v:SetFont(font)
v:SizeToContents()
end
-- reposition for the new font
self:InvalidateLayout(true)
self:Open(self.ixX, self.ixY, false, self.ixOwnerPanel)
end
Override("SetSize")
function PANEL:SetSize(width, height)
self:ixSetSize(width, height)
self.ixTargetHeight = height
end
Override("PerformLayout")
function PANEL:PerformLayout(...)
self:ixPerformLayout(...)
if (self.ixAnimating) then
self.VBar:SetAlpha(0) -- setvisible doesn't seem to work here
self:SetTall(self.ixAnimation * self.ixTargetHeight)
else
self.VBar:SetAlpha(255)
end
end
Override("OnMouseWheeled")
function PANEL:OnMouseWheeled(delta)
self:ixOnMouseWheeled(delta)
-- don't allow the input event to fall through
return true
end
Override("AddOption")
function PANEL:AddOption(...)
local panel = self:ixAddOption(...)
panel:SetTextColor(derma.GetColor("MenuLabel", self, color_black))
panel:SetTextInset(6, 0) -- there is no icon functionality in DComboBoxes
return panel
end
Override("AddSubMenu")
function PANEL:AddSubMenu(...)
local menu, panel = self:ixAddSubMenu(...)
panel:SetTextColor(derma.GetColor("MenuLabel", self, color_black))
panel:SetTextInset(6, 0) -- there is no icon functionality in DComboBoxes
return menu, panel
end
Override("Open")
function PANEL:Open(x, y, bSkipAnimation, ownerPanel)
self.ixX, self.ixY, self.ixOwnerPanel = x, y, ownerPanel
self:ixOpen(x, y, bSkipAnimation, ownerPanel)
if (ix.option.Get("disableAnimations")) then
return
end
-- remove pac3 derma menu hooks since animations don't play nicely
hook.Remove("CloseDermaMenus", self)
hook.Remove("Think", self)
self.ixAnimating = true
self:CreateAnimation(animationTime, {
index = 1,
target = {ixAnimation = 1},
easing = "outQuint",
Think = function(animation, panel)
panel:InvalidateLayout(true)
end,
OnComplete = function(animation, panel)
panel.ixAnimating = nil
end
})
end
Override("Hide")
function PANEL:Hide()
if (ix.option.Get("disableAnimations")) then
self:ixHide()
return
end
self.ixAnimating = true
self:SetVisible(true)
self:CreateAnimation(animationTime * 0.5, {
index = 1,
target = {ixAnimation = 0},
easing = "outQuint",
Think = function(animation, panel)
panel:InvalidateLayout(true)
end,
OnComplete = function(animation, panel)
panel.ixAnimating = false
panel:ixHide()
end
})
end
Override("Remove")
function PANEL:Remove()
if (self.ixRemoving) then
return
end
if (ix.option.Get("disableAnimations")) then
self:ixRemove()
return
end
self.ixAnimating = true
self.ixRemoving = true
self:SetVisible(true)
self:CreateAnimation(animationTime * 0.5, {
index = 1,
target = {ixAnimation = 0},
easing = "outQuint",
Think = function(animation, panel)
panel:InvalidateLayout(true)
end,
OnComplete = function(animation, panel)
panel:ixRemove()
end
})
end
end)
OverridePanel("DComboBox", function()
Override("OpenMenu")
function PANEL:OpenMenu()
self:ixOpenMenu()
if (IsValid(self.Menu)) then
local _, y = self.Menu:LocalToScreen(self.Menu:GetPos())
self.Menu:SetFont(self:GetFont())
self.Menu:SetMaxHeight(ScrH() - y)
end
end
end)
OverridePanel("DScrollPanel", function()
Override("ScrollToChild")
function PANEL:ScrollToChild(panel)
-- docked panels required InvalidateParent in order to retrieve their position correctly
if (panel:GetDock() != NODOCK) then
panel:InvalidateParent(true)
else
self:PerformLayout()
end
local _, y = self.pnlCanvas:GetChildPosition(panel)
y = y + panel:GetTall() * 0.5
y = y - self:GetTall() * 0.5
self.VBar:SetScroll(y)
end
end)

View File

@@ -0,0 +1,359 @@
--[[
| 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/
--]]
local rowPaintFunctions = {
function(width, height)
end,
function(width, height)
surface.SetDrawColor(30, 30, 30, 25)
surface.DrawRect(0, 0, width, height)
end
}
-- character icon
-- we can't customize the rendering of ModelImage so we have to do it ourselves
local PANEL = {}
local BODYGROUPS_EMPTY = "000000000"
AccessorFunc(PANEL, "model", "Model", FORCE_STRING)
AccessorFunc(PANEL, "bHidden", "Hidden", FORCE_BOOL)
function PANEL:Init()
self:SetSize(64, 64)
self.bodygroups = BODYGROUPS_EMPTY
end
function PANEL:SetModel(model, skin, bodygroups)
model = model:gsub("\\", "/")
if (isstring(bodygroups)) then
if (bodygroups:len() == 9) then
for i = 1, bodygroups:len() do
self:SetBodygroup(i, tonumber(bodygroups[i]) or 0)
end
else
self.bodygroups = BODYGROUPS_EMPTY
end
end
self.model = model
self.skin = skin
self.path = "materials/spawnicons/" ..
model:sub(1, #model - 4) .. -- remove extension
((isnumber(skin) and skin > 0) and ("_skin" .. tostring(skin)) or "") .. -- skin number
(self.bodygroups != BODYGROUPS_EMPTY and ("_" .. self.bodygroups) or "") .. -- bodygroups
".png"
local material = Material(self.path, "smooth")
-- we don't have a cached spawnicon texture, so we need to forcefully generate one
if (material:IsError()) then
self.id = "ixScoreboardIcon" .. self.path
self.renderer = self:Add("ModelImage")
self.renderer:SetVisible(false)
self.renderer:SetModel(model, skin, self.bodygroups)
self.renderer:RebuildSpawnIcon()
-- this is the only way to get a callback for generated spawn icons, it's bad but it's only done once
hook.Add("SpawniconGenerated", self.id, function(lastModel, filePath, modelsLeft)
filePath = filePath:gsub("\\", "/"):lower()
if (filePath == self.path) then
hook.Remove("SpawniconGenerated", self.id)
self.material = Material(filePath, "smooth")
self.renderer:Remove()
end
end)
else
self.material = material
end
end
function PANEL:SetBodygroup(k, v)
if (k < 0 or k > 8 or v < 0 or v > 9) then
return
end
self.bodygroups = self.bodygroups:SetChar(k + 1, v)
end
function PANEL:GetModel()
return self.model or "models/error.mdl"
end
function PANEL:GetSkin()
return self.skin or 1
end
function PANEL:DoClick()
end
function PANEL:DoRightClick()
end
function PANEL:OnMouseReleased(key)
if (key == MOUSE_LEFT) then
self:DoClick()
elseif (key == MOUSE_RIGHT) then
self:DoRightClick()
end
end
function PANEL:Paint(width, height)
if (!self.material) then
return
end
surface.SetMaterial(self.material)
surface.SetDrawColor(self.bHidden and color_black or color_white)
surface.DrawTexturedRect(0, 0, width, height)
end
function PANEL:Remove()
if (self.id) then
hook.Remove("SpawniconGenerated", self.id)
end
end
vgui.Register("ixScoreboardIcon", PANEL, "Panel")
-- player row
PANEL = {}
AccessorFunc(PANEL, "paintFunction", "BackgroundPaintFunction")
function PANEL:Init()
self:SetTall(64)
self.icon = self:Add("ixScoreboardIcon")
self.icon:Dock(LEFT)
self.icon.DoRightClick = function()
local client = self.player
if (!IsValid(client)) then
return
end
local menu = DermaMenu()
menu:AddOption(L("viewProfile"), function()
client:ShowProfile()
end)
menu:AddOption(L("copySteamID"), function()
SetClipboardText(client:IsBot() and client:EntIndex() or client:SteamID())
end)
hook.Run("PopulateScoreboardPlayerMenu", client, menu)
menu:Open()
end
self.icon:SetHelixTooltip(function(tooltip)
local client = self.player
if (IsValid(self) and IsValid(client)) then
ix.hud.PopulatePlayerTooltip(tooltip, client)
end
end)
self.name = self:Add("DLabel")
self.name:DockMargin(4, 4, 0, 0)
self.name:Dock(TOP)
self.name:SetTextColor(color_white)
self.name:SetFont("ixGenericFont")
self.description = self:Add("DLabel")
self.description:DockMargin(5, 0, 0, 0)
self.description:Dock(TOP)
self.description:SetTextColor(color_white)
self.description:SetFont("ixSmallFont")
self.paintFunction = rowPaintFunctions[1]
self.nextThink = CurTime() + 1
end
function PANEL:Update()
local client = self.player
local model = client:GetModel()
local skin = client:GetSkin()
local name = client:GetName()
local description = hook.Run("GetCharacterDescription", client) or
(client:GetCharacter() and client:GetCharacter():GetDescription()) or ""
local bRecognize = false
local localCharacter = LocalPlayer():GetCharacter()
local character = IsValid(self.player) and self.player:GetCharacter()
if (localCharacter and character) then
bRecognize = hook.Run("IsCharacterRecognized", localCharacter, character:GetID())
or hook.Run("IsPlayerRecognized", self.player)
end
self.icon:SetHidden(!bRecognize)
self:SetZPos(bRecognize and 1 or 2)
-- no easy way to check bodygroups so we'll just set them anyway
for _, v in pairs(client:GetBodyGroups()) do
self.icon:SetBodygroup(v.id, client:GetBodygroup(v.id))
end
if (self.icon:GetModel() != model or self.icon:GetSkin() != skin) then
self.icon:SetModel(model, skin)
self.icon:SetTooltip(nil)
end
if (self.name:GetText() != name) then
self.name:SetText(name)
self.name:SizeToContents()
end
if (self.description:GetText() != description) then
self.description:SetText(description)
self.description:SizeToContents()
end
end
function PANEL:Think()
if (CurTime() >= self.nextThink) then
local client = self.player
if (!IsValid(client) or !client:GetCharacter() or self.character != client:GetCharacter() or self.team != client:Team()) then
self:Remove()
self:GetParent():SizeToContents()
end
self.nextThink = CurTime() + 1
end
end
function PANEL:SetPlayer(client)
self.player = client
self.team = client:Team()
self.character = client:GetCharacter()
self:Update()
end
function PANEL:Paint(width, height)
self.paintFunction(width, height)
end
vgui.Register("ixScoreboardRow", PANEL, "EditablePanel")
-- faction grouping
PANEL = {}
AccessorFunc(PANEL, "faction", "Faction")
function PANEL:Init()
self:DockMargin(0, 0, 0, 16)
self:SetTall(32)
self.nextThink = 0
end
function PANEL:AddPlayer(client, index)
if (!IsValid(client) or !client:GetCharacter() or hook.Run("ShouldShowPlayerOnScoreboard", client) == false) then
return false
end
local id = index % 2 == 0 and 1 or 2
local panel = self:Add("ixScoreboardRow")
panel:SetPlayer(client)
panel:Dock(TOP)
panel:SetZPos(2)
panel:SetBackgroundPaintFunction(rowPaintFunctions[id])
self:SizeToContents()
client.ixScoreboardSlot = panel
return true
end
function PANEL:SetFaction(faction)
self:SetColor(faction.color)
self:SetText(L(faction.name))
self.faction = faction
end
function PANEL:Update()
local faction = self.faction
if (team.NumPlayers(faction.index) == 0) then
self:SetVisible(false)
self:GetParent():InvalidateLayout()
else
local bHasPlayers
for k, v in ipairs(team.GetPlayers(faction.index)) do
if (!IsValid(v.ixScoreboardSlot)) then
if (self:AddPlayer(v, k)) then
bHasPlayers = true
end
else
v.ixScoreboardSlot:Update()
bHasPlayers = true
end
end
self:SetVisible(bHasPlayers)
end
end
vgui.Register("ixScoreboardFaction", PANEL, "ixCategoryPanel")
-- main scoreboard panel
PANEL = {}
function PANEL:Init()
if (IsValid(ix.gui.scoreboard)) then
ix.gui.scoreboard:Remove()
end
self:Dock(FILL)
self.factions = {}
self.nextThink = 0
for i = 1, #ix.faction.indices do
local faction = ix.faction.indices[i]
local panel = self:Add("ixScoreboardFaction")
panel:SetFaction(faction)
panel:Dock(TOP)
self.factions[i] = panel
end
ix.gui.scoreboard = self
end
function PANEL:Think()
if (CurTime() >= self.nextThink) then
for i = 1, #self.factions do
local factionPanel = self.factions[i]
factionPanel:Update()
end
self.nextThink = CurTime() + 0.5
end
end
vgui.Register("ixScoreboard", PANEL, "DScrollPanel")
hook.Add("CreateMenuButtons", "ixScoreboard", function(tabs)
tabs["scoreboard"] = function(container)
container:Add("ixScoreboard")
end
end)

View File

@@ -0,0 +1,781 @@
--[[
| 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/
--]]
local panelMap = {
[ix.type.bool] = "ixSettingsRowBool",
[ix.type.array] = "ixSettingsRowArray",
[ix.type.string] = "ixSettingsRowString",
[ix.type.number] = "ixSettingsRowNumber",
[ix.type.color] = "ixSettingsRowColor"
}
local function EmitChange(pitch)
LocalPlayer():EmitSound("weapons/ar2/ar2_empty.wav", 75, pitch or 150, 0.25)
end
-- color setting
local PANEL = {}
AccessorFunc(PANEL, "padding", "Padding", FORCE_NUMBER)
function PANEL:Init()
self.color = table.Copy(color_white)
self.padding = 4
self.panel = self:Add("Panel")
self.panel:SetCursor("hand")
self.panel:SetMouseInputEnabled(true)
self.panel:Dock(RIGHT)
self.panel.Paint = function(panel, width, height)
local padding = self.padding
surface.SetDrawColor(derma.GetColor("DarkerBackground", self))
surface.DrawRect(0, 0, width, height)
surface.SetDrawColor(self.color)
surface.DrawRect(padding, padding, width - padding * 2, height - padding * 2)
end
self.panel.OnMousePressed = function(panel, key)
if (key == MOUSE_LEFT) then
self:OpenPicker()
end
end
end
function PANEL:OpenPicker()
if (IsValid(self.picker)) then
self.picker:Remove()
return
end
self.picker = vgui.Create("ixSettingsRowColorPicker")
self.picker:Attach(self)
self.picker:SetValue(self.color)
self.picker.OnValueChanged = function(panel)
local newColor = panel:GetValue()
if (newColor != self.color) then
self.color = newColor
self:OnValueChanged(newColor)
end
end
self.picker.OnValueUpdated = function(panel)
self.color = panel:GetValue()
end
end
function PANEL:SetValue(value)
self.color = Color(value.r or 255, value.g or 255, value.b or 255, value.a or 255)
end
function PANEL:GetValue()
return self.color
end
function PANEL:PerformLayout(width, height)
surface.SetFont("ixMenuButtonFont")
local totalWidth = surface.GetTextSize("999")
self.panel:SetSize(totalWidth + self.padding * 2, height)
end
vgui.Register("ixSettingsRowColor", PANEL, "ixSettingsRow")
-- color setting picker
DEFINE_BASECLASS("Panel")
PANEL = {}
AccessorFunc(PANEL, "bDeleteSelf", "DeleteSelf", FORCE_BOOL)
function PANEL:Init()
self.m_bIsMenuComponent = true
self.bDeleteSelf = true
self.realHeight = 200
self.height = 200
self:SetSize(250, 200)
self:DockPadding(4, 4, 4, 4)
self.picker = self:Add("DColorMixer")
self.picker:Dock(FILL)
self.picker.ValueChanged = function()
self:OnValueUpdated()
end
self:MakePopup()
RegisterDermaMenuForClose(self)
end
function PANEL:SetValue(value)
self.picker:SetColor(Color(value.r or 255, value.g or 255, value.b or 255, value.a or 255))
end
function PANEL:GetValue()
return self.picker:GetColor()
end
function PANEL:Attach(panel)
self.attached = panel
end
function PANEL:Think()
local panel = self.attached
if (IsValid(panel)) then
local width, height = self:GetSize()
local x, y = panel:LocalToScreen(0, 0)
self:SetPos(
math.Clamp(x + panel:GetWide() - width, 0, ScrW() - width),
math.Clamp(y + panel:GetTall(), 0, ScrH() - height)
)
end
end
function PANEL:Paint(width, height)
surface.SetDrawColor(derma.GetColor("DarkerBackground", self))
surface.DrawRect(0, 0, width, height)
end
function PANEL:OnValueChanged()
end
function PANEL:OnValueUpdated()
end
function PANEL:Remove()
if (self.bClosing) then
return
end
self:OnValueChanged()
-- @todo open/close animations
self.bClosing = true
self:SetMouseInputEnabled(false)
self:SetKeyboardInputEnabled(false)
BaseClass.Remove(self)
end
vgui.Register("ixSettingsRowColorPicker", PANEL, "EditablePanel")
-- number setting
PANEL = {}
function PANEL:Init()
self.setting = self:Add("ixNumSlider")
self.setting.nextUpdate = 0
self.setting:Dock(RIGHT)
self.setting.OnValueChanged = function(panel)
self:OnValueChanged(self:GetValue())
end
self.setting.OnValueUpdated = function(panel)
local fraction = panel:GetFraction()
if (fraction == 0) then
EmitChange(75)
return
elseif (fraction == 1) then
EmitChange(120)
return
end
if (SysTime() > panel.nextUpdate) then
EmitChange(85 + fraction * 15)
panel.nextUpdate = SysTime() + 0.05
end
end
local panel = self.setting:GetLabel()
panel:SetCursor("hand")
panel:SetMouseInputEnabled(true)
panel.OnMousePressed = function(_, key)
if (key == MOUSE_LEFT) then
self:OpenEntry()
end
end
end
function PANEL:OpenEntry()
if (IsValid(self.entry)) then
self.entry:Remove()
return
end
self.entry = vgui.Create("ixSettingsRowNumberEntry")
self.entry:Attach(self)
self.entry:SetValue(self:GetValue(), true)
self.entry.OnValueChanged = function(panel)
local value = math.Round(panel:GetValue(), self:GetDecimals())
if (value != self:GetValue()) then
self:SetValue(value, true)
self:OnValueChanged(value)
end
end
end
function PANEL:SetValue(value, bNoNotify)
self.setting:SetValue(value, bNoNotify)
end
function PANEL:GetValue()
return self.setting:GetValue()
end
function PANEL:SetMin(value)
self.setting:SetMin(value)
end
function PANEL:SetMax(value)
self.setting:SetMax(value)
end
function PANEL:SetDecimals(value)
self.setting:SetDecimals(value)
end
function PANEL:GetDecimals()
return self.setting:GetDecimals()
end
function PANEL:PerformLayout(width, height)
self.setting:SetWide(width * 0.5)
end
vgui.Register("ixSettingsRowNumber", PANEL, "ixSettingsRow")
-- number setting entry
DEFINE_BASECLASS("Panel")
PANEL = {}
AccessorFunc(PANEL, "bDeleteSelf", "DeleteSelf", FORCE_BOOL)
function PANEL:Init()
surface.SetFont("ixMenuButtonFont")
local width, height = surface.GetTextSize("999999")
self.m_bIsMenuComponent = true
self.bDeleteSelf = true
self.realHeight = 200
self.height = 200
self:SetSize(width, height)
self:DockPadding(4, 4, 4, 4)
self.textEntry = self:Add("ixTextEntry")
self.textEntry:SetNumeric(true)
self.textEntry:SetFont("ixMenuButtonFont")
self.textEntry:Dock(FILL)
self.textEntry:RequestFocus()
self.textEntry.OnEnter = function()
self:Remove()
end
self:MakePopup()
RegisterDermaMenuForClose(self)
end
function PANEL:SetValue(value, bInitial)
value = tostring(value)
self.textEntry:SetValue(value)
if (bInitial) then
self.textEntry:SetCaretPos(value:utf8len())
end
end
function PANEL:GetValue()
return tonumber(self.textEntry:GetValue()) or 0
end
function PANEL:Attach(panel)
self.attached = panel
end
function PANEL:Think()
local panel = self.attached
if (IsValid(panel)) then
local width, height = self:GetSize()
local x, y = panel:LocalToScreen(0, 0)
self:SetPos(
math.Clamp(x + panel:GetWide() - width, 0, ScrW() - width),
math.Clamp(y + panel:GetTall(), 0, ScrH() - height)
)
end
end
function PANEL:Paint(width, height)
surface.SetDrawColor(derma.GetColor("DarkerBackground", self))
surface.DrawRect(0, 0, width, height)
end
function PANEL:OnValueChanged()
end
function PANEL:OnValueUpdated()
end
function PANEL:Remove()
if (self.bClosing) then
return
end
self:OnValueChanged()
-- @todo open/close animations
self.bClosing = true
self:SetMouseInputEnabled(false)
self:SetKeyboardInputEnabled(false)
BaseClass.Remove(self)
end
vgui.Register("ixSettingsRowNumberEntry", PANEL, "EditablePanel")
-- string setting
PANEL = {}
function PANEL:Init()
self.setting = self:Add("ixTextEntry")
self.setting:Dock(RIGHT)
self.setting:SetFont("ixMenuButtonFont")
self.setting:SetBackgroundColor(derma.GetColor("DarkerBackground", self))
self.setting.OnEnter = function()
self:OnValueChanged(self:GetValue())
end
end
function PANEL:SetValue(value)
self.setting:SetValue(tostring(value))
end
function PANEL:GetValue()
return self.setting:GetValue()
end
function PANEL:PerformLayout(width, height)
self.setting:SetWide(width * 0.5)
end
vgui.Register("ixSettingsRowString", PANEL, "ixSettingsRow")
-- bool setting
PANEL = {}
function PANEL:Init()
self.setting = self:Add("ixCheckBox")
self.setting:Dock(RIGHT)
self.setting.DoClick = function(panel)
self:OnValueChanged(self:GetValue())
end
end
function PANEL:SetValue(bValue)
bValue = tobool(bValue)
self.setting:SetChecked(bValue, true)
end
function PANEL:GetValue()
return self.setting:GetChecked()
end
vgui.Register("ixSettingsRowBool", PANEL, "ixSettingsRow")
-- array setting
PANEL = {}
function PANEL:Init()
self.array = {}
self.setting = self:Add("DComboBox")
self.setting:Dock(RIGHT)
self.setting:SetFont("ixMenuButtonFont")
self.setting:SetTextColor(color_white)
self.setting.OnSelect = function(panel)
self:OnValueChanged(self:GetValue())
panel:SizeToContents()
panel:SetWide(panel:GetWide() + 12) -- padding for arrow (nice)
if (!self.bInitial) then
EmitChange()
end
end
end
function PANEL:Populate(key, info)
if (!isfunction(info.populate)) then
ErrorNoHalt(string.format("expected populate function for array option '%s'", key))
return
end
local entries = info.populate()
local i = 1
for k, v in pairs(entries) do
self.setting:AddChoice(v, k)
self.array[k] = i
i = i + 1
end
end
function PANEL:SetValue(value)
self.bInitial = true
self.setting:ChooseOptionID(self.array[value])
self.bInitial = false
end
function PANEL:GetValue()
return select(2, self.setting:GetSelected())
end
vgui.Register("ixSettingsRowArray", PANEL, "ixSettingsRow")
-- settings row
PANEL = {}
AccessorFunc(PANEL, "backgroundIndex", "BackgroundIndex", FORCE_NUMBER)
AccessorFunc(PANEL, "bShowReset", "ShowReset", FORCE_BOOL)
function PANEL:Init()
self:DockPadding(4, 4, 4, 4)
self.text = self:Add("DLabel")
self.text:Dock(LEFT)
self.text:SetFont("ixMenuButtonFont")
self.text:SetExpensiveShadow(1, color_black)
self.backgroundIndex = 0
end
function PANEL:SetShowReset(value, name, default)
value = tobool(value)
if (value and !IsValid(self.reset)) then
self.reset = self:Add("DButton")
self.reset:SetFont("ixSmallTitleIcons")
self.reset:SetText("x")
self.reset:SetTextColor(ColorAlpha(derma.GetColor("Warning", self), 100))
self.reset:Dock(LEFT)
self.reset:DockMargin(4, 0, 0, 0)
self.reset:SizeToContents()
self.reset.Paint = nil
self.reset.DoClick = function()
self:OnResetClicked()
end
self.reset:SetHelixTooltip(function(tooltip)
local title = tooltip:AddRow("title")
title:SetImportant()
title:SetText(L("resetDefault"))
title:SetBackgroundColor(derma.GetColor("Warning", self))
title:SizeToContents()
local description = tooltip:AddRow("description")
description:SetText(L("resetDefaultDescription", tostring(name), tostring(default)))
description:SizeToContents()
end)
elseif (!value and IsValid(self.reset)) then
self.reset:Remove()
end
self.bShowReset = value
end
function PANEL:Think()
if (IsValid(self.reset)) then
self.reset:SetVisible(self:IsHovered() or self:IsOurChild(vgui.GetHoveredPanel()))
end
end
function PANEL:OnResetClicked()
end
function PANEL:GetLabel()
return self.text
end
function PANEL:SetText(text)
self.text:SetText(text)
self:SizeToContents()
end
function PANEL:GetText()
return self.text:GetText()
end
-- implemented by row types
function PANEL:GetValue()
end
function PANEL:SetValue(value)
end
-- meant for array types to populate combo box values
function PANEL:Populate(key, info)
end
-- called when value is changed by user
function PANEL:OnValueChanged(newValue)
end
function PANEL:SizeToContents()
local _, top, _, bottom = self:GetDockPadding()
self.text:SizeToContents()
self:SetTall(self.text:GetTall() + top + bottom)
self.ixRealHeight = self:GetTall()
self.ixHeight = self.ixRealHeight
end
function PANEL:Paint(width, height)
derma.SkinFunc("PaintSettingsRowBackground", self, width, height)
end
vgui.Register("ixSettingsRow", PANEL, "EditablePanel")
-- settings panel
PANEL = {}
function PANEL:Init()
self:Dock(FILL)
self.rows = {}
self.categories = {}
-- scroll panel
DEFINE_BASECLASS("DScrollPanel")
self.canvas = self:Add("DScrollPanel")
self.canvas:Dock(FILL)
self.canvas.PerformLayout = function(panel)
BaseClass.PerformLayout(panel)
if (!panel.VBar.Enabled) then
panel.pnlCanvas:SetWide(panel:GetWide() - panel.VBar:GetWide())
end
end
end
function PANEL:GetRowPanelName(type)
return panelMap[type] or "ixSettingsRow"
end
function PANEL:AddCategory(name)
local panel = self.categories[name]
if (!IsValid(panel)) then
panel = self.canvas:Add("ixCategoryPanel")
panel:SetText(name)
panel:Dock(TOP)
panel:DockMargin(0, 8, 0, 0)
self.categories[name] = panel
return panel
end
end
function PANEL:AddRow(type, category)
category = self.categories[category]
local id = panelMap[type]
if (!id) then
ErrorNoHalt("attempted to create row with unimplemented type '" .. tostring(ix.type[type]) .. "'\n")
id = "ixSettingsRow"
end
local panel = (IsValid(category) and category or self.canvas):Add(id)
panel:Dock(TOP)
panel:SetBackgroundIndex(#self.rows % 2)
self.rows[#self.rows + 1] = panel
return panel
end
function PANEL:GetRows()
return self.rows
end
function PANEL:Clear()
for _, v in ipairs(self.rows) do
if (IsValid(v)) then
v:Remove()
end
end
self.rows = {}
end
function PANEL:SetSearchEnabled(bValue)
if (!bValue) then
if (IsValid(self.searchEntry)) then
self.searchEntry:Remove()
end
return
end
-- search entry
self.searchEntry = self:Add("ixIconTextEntry")
self.searchEntry:Dock(TOP)
self.searchEntry:SetEnterAllowed(false)
self.searchEntry.OnChange = function(entry)
self:FilterRows(entry:GetValue())
end
end
function PANEL:FilterRows(query)
query = string.PatternSafe(query:lower())
local bEmpty = query == ""
for categoryName, category in pairs(self.categories) do
category.size = 0
category:CreateAnimation(0.5, {
index = 21,
target = {size = 1},
Think = function(animation, panel)
panel:SizeToContents()
end
})
for _, row in ipairs(category:GetChildren()) do
local bFound = bEmpty or row:GetText():lower():find(query) or categoryName:lower():find(query)
row:SetVisible(true)
row:CreateAnimation(0.5, {
index = 21,
target = {ixHeight = bFound and row.ixRealHeight or 0},
easing = "outQuint",
Think = function(animation, panel)
panel:SetTall(bFound and math.min(panel.ixHeight + 2, panel.ixRealHeight) or math.max(panel.ixHeight - 2, 0))
end,
OnComplete = function(animation, panel)
panel:SetVisible(bFound)
-- need this so categories are sized properly when animations are disabled - there is no guaranteed order
-- that animations will think so we SizeToContents here. putting it here will result in redundant calls but
-- I guess we have the performance to spare
if (ix.option.Get("disableAnimations", false)) then
category:SizeToContents()
end
end
})
end
end
end
function PANEL:Paint(width, height)
end
function PANEL:SizeToContents()
for _, v in pairs(self.categories) do
v:SizeToContents()
end
end
vgui.Register("ixSettings", PANEL, "Panel")
hook.Add("CreateMenuButtons", "ixSettings", function(tabs)
tabs["settings"] = {
PopulateTabButton = function(info, button)
local menu = ix.gui.menu
if (!IsValid(menu)) then
return
end
DEFINE_BASECLASS("ixMenuButton")
button:SetZPos(9999)
button.Paint = function(panel, width, height)
BaseClass.Paint(panel, width, height)
surface.SetDrawColor(255, 255, 255, 33)
surface.DrawRect(0, 0, width, 1)
end
end,
Create = function(info, container)
local panel = container:Add("ixSettings")
panel:SetSearchEnabled(true)
for category, options in SortedPairs(ix.option.GetAllByCategories(true)) do
category = L(category)
panel:AddCategory(category)
-- sort options by language phrase rather than the key
table.sort(options, function(a, b)
return L(a.phrase) < L(b.phrase)
end)
for _, data in pairs(options) do
local key = data.key
local row = panel:AddRow(data.type, category)
local value = ix.util.SanitizeType(data.type, ix.option.Get(key))
row:SetText(L(data.phrase))
row:Populate(key, data)
-- type-specific properties
if (data.type == ix.type.number) then
row:SetMin(data.min or 0)
row:SetMax(data.max or 10)
row:SetDecimals(data.decimals or 0)
end
row:SetValue(value, true)
row:SetShowReset(value != data.default, key, data.default)
row.OnValueChanged = function()
local newValue = row:GetValue()
row:SetShowReset(newValue != data.default, key, data.default)
ix.option.Set(key, newValue)
end
row.OnResetClicked = function()
row:SetShowReset(false)
row:SetValue(data.default, true)
ix.option.Set(key, data.default)
end
row:GetLabel():SetHelixTooltip(function(tooltip)
local title = tooltip:AddRow("name")
title:SetImportant()
title:SetText(key)
title:SizeToContents()
title:SetMaxWidth(math.max(title:GetMaxWidth(), ScrW() * 0.5))
local description = tooltip:AddRow("description")
description:SetText(L(data.description))
description:SizeToContents()
end)
end
end
panel:SizeToContents()
container.panel = panel
end,
OnSelected = function(info, container)
container.panel.searchEntry:RequestFocus()
end
}
end)

View File

@@ -0,0 +1,130 @@
--[[
| 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/
--]]
local PANEL = {}
function PANEL:Init()
self:SetSize(460, 360)
self:SetTitle(L"shipment")
self:Center()
self:MakePopup()
self.scroll = self:Add("DScrollPanel")
self.scroll:Dock(FILL)
self.list = self.scroll:Add("DListLayout")
self.list:Dock(FILL)
end
function PANEL:SetItems(entity, items)
self.entity = entity
self.items = true
self.itemPanels = {}
for k, v in SortedPairs(items) do
local itemTable = ix.item.list[k]
if (itemTable) then
local item = self.list:Add("DPanel")
item:SetTall(36)
item:Dock(TOP)
item:DockMargin(4, 4, 4, 0)
item.icon = item:Add("SpawnIcon")
item.icon:SetPos(2, 2)
item.icon:SetSize(32, 32)
item.icon:SetModel(itemTable:GetModel())
item.icon:SetHelixTooltip(function(tooltip)
ix.hud.PopulateItemTooltip(tooltip, itemTable)
end)
item.quantity = item.icon:Add("DLabel")
item.quantity:SetSize(32, 32)
item.quantity:SetContentAlignment(3)
item.quantity:SetTextInset(0, 0)
item.quantity:SetText(v)
item.quantity:SetFont("DermaDefaultBold")
item.quantity:SetExpensiveShadow(1, Color(0, 0, 0, 150))
item.name = item:Add("DLabel")
item.name:SetPos(38, 0)
item.name:SetSize(200, 36)
item.name:SetFont("ixSmallFont")
item.name:SetText(L(itemTable.name))
item.name:SetContentAlignment(4)
item.name:SetTextColor(color_white)
item.take = item:Add("DButton")
item.take:Dock(RIGHT)
item.take:SetText(L"take")
item.take:SetWide(48)
item.take:DockMargin(3, 3, 3, 3)
item.take:SetTextColor(color_white)
item.take.DoClick = function(this)
net.Start("ixShipmentUse")
net.WriteString(k)
net.WriteBool(false)
net.SendToServer()
items[k] = items[k] - 1
item.quantity:SetText(items[k])
if (items[k] <= 0) then
item:Remove()
items[k] = nil
end
if (table.IsEmpty(items)) then
self:Remove()
end
end
item.drop = item:Add("DButton")
item.drop:Dock(RIGHT)
item.drop:SetText(L"drop")
item.drop:SetWide(48)
item.drop:DockMargin(3, 3, 0, 3)
item.drop:SetTextColor(color_white)
item.drop.DoClick = function(this)
net.Start("ixShipmentUse")
net.WriteString(k)
net.WriteBool(true)
net.SendToServer()
items[k] = items[k] - 1
item.quantity:SetText(items[k])
if (items[k] <= 0) then
item:Remove()
end
end
self.itemPanels[k] = item
end
end
end
function PANEL:Close()
net.Start("ixShipmentClose")
net.SendToServer()
self:Remove()
end
function PANEL:Think()
if (self.items and !IsValid(self.entity)) then
self:Remove()
end
end
vgui.Register("ixShipment", PANEL, "DFrame")

View File

@@ -0,0 +1,107 @@
--[[
| 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/
--]]
DEFINE_BASECLASS("DModelPanel")
local PANEL = {}
function PANEL:Init()
self.defaultEyeTarget = Vector(0, 0, 64)
self:SetHidden(false)
for i = 0, 5 do
if (i == 1 or i == 5) then
self:SetDirectionalLight(i, Color(155, 155, 155))
else
self:SetDirectionalLight(i, Color(255, 255, 255))
end
end
end
function PANEL:SetModel(model, skin, hidden)
BaseClass.SetModel(self, model)
local entity = self.Entity
if (skin) then
entity:SetSkin(skin)
end
local sequence = entity:SelectWeightedSequence(ACT_IDLE)
if (sequence <= 0) then
sequence = entity:LookupSequence("idle_unarmed")
end
if (sequence > 0) then
entity:ResetSequence(sequence)
else
local found = false
for _, v in ipairs(entity:GetSequenceList()) do
if ((v:lower():find("idle") or v:lower():find("fly")) and v != "idlenoise") then
entity:ResetSequence(v)
found = true
break
end
end
if (!found) then
entity:ResetSequence(4)
end
end
local data = PositionSpawnIcon(entity, entity:GetPos())
if (data) then
self:SetFOV(data.fov)
self:SetCamPos(data.origin)
self:SetLookAng(data.angles)
end
entity:SetIK(false)
entity:SetEyeTarget(self.defaultEyeTarget)
end
function PANEL:SetHidden(hidden)
if (hidden) then
self:SetAmbientLight(color_black)
self:SetColor(Color(0, 0, 0))
for i = 0, 5 do
self:SetDirectionalLight(i, color_black)
end
else
self:SetAmbientLight(Color(20, 20, 20))
self:SetAlpha(255)
for i = 0, 5 do
if (i == 1 or i == 5) then
self:SetDirectionalLight(i, Color(155, 155, 155))
else
self:SetDirectionalLight(i, Color(255, 255, 255))
end
end
end
end
function PANEL:LayoutEntity()
self:RunAnimation()
end
function PANEL:OnMousePressed()
if (self.DoClick) then
self:DoClick()
end
end
vgui.Register("ixSpawnIcon", PANEL, "DModelPanel")

View File

@@ -0,0 +1,207 @@
--[[
| 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/
--]]
local PANEL = {}
AccessorFunc(PANEL, "money", "Money", FORCE_NUMBER)
function PANEL:Init()
self:DockPadding(1, 1, 1, 1)
self:SetTall(64)
self:Dock(BOTTOM)
self.moneyLabel = self:Add("DLabel")
self.moneyLabel:Dock(TOP)
self.moneyLabel:SetFont("ixGenericFont")
self.moneyLabel:SetText("")
self.moneyLabel:SetTextInset(2, 0)
self.moneyLabel:SizeToContents()
self.moneyLabel.Paint = function(panel, width, height)
derma.SkinFunc("DrawImportantBackground", 0, 0, width, height, ix.config.Get("color"))
end
self.amountEntry = self:Add("ixTextEntry")
self.amountEntry:Dock(FILL)
self.amountEntry:SetFont("ixGenericFont")
self.amountEntry:SetNumeric(true)
self.amountEntry:SetValue("0")
self.transferButton = self:Add("DButton")
self.transferButton:SetFont("ixIconsMedium")
self:SetLeft(false)
self.transferButton.DoClick = function()
local amount = math.max(0, math.Round(tonumber(self.amountEntry:GetValue()) or 0))
self.amountEntry:SetValue("0")
if (amount != 0) then
self:OnTransfer(amount)
end
end
self.bNoBackgroundBlur = true
end
function PANEL:SetLeft(bValue)
if (bValue) then
self.transferButton:Dock(LEFT)
self.transferButton:SetText("s")
else
self.transferButton:Dock(RIGHT)
self.transferButton:SetText("t")
end
end
function PANEL:SetMoney(money)
local name = string.gsub(ix.util.ExpandCamelCase(ix.currency.plural), "%s", "")
self.money = math.max(math.Round(tonumber(money) or 0), 0)
self.moneyLabel:SetText(string.format("%s: %d", name, money))
end
function PANEL:OnTransfer(amount)
end
function PANEL:Paint(width, height)
derma.SkinFunc("PaintBaseFrame", self, width, height)
end
vgui.Register("ixStorageMoney", PANEL, "EditablePanel")
DEFINE_BASECLASS("Panel")
PANEL = {}
AccessorFunc(PANEL, "fadeTime", "FadeTime", FORCE_NUMBER)
AccessorFunc(PANEL, "frameMargin", "FrameMargin", FORCE_NUMBER)
AccessorFunc(PANEL, "storageID", "StorageID", FORCE_NUMBER)
function PANEL:Init()
if (IsValid(ix.gui.openedStorage)) then
ix.gui.openedStorage:Remove()
end
ix.gui.openedStorage = self
self:SetSize(ScrW(), ScrH())
self:SetPos(0, 0)
self:SetFadeTime(0.25)
self:SetFrameMargin(4)
self.storageInventory = self:Add("ixInventory")
self.storageInventory.bNoBackgroundBlur = true
self.storageInventory:ShowCloseButton(true)
self.storageInventory:SetTitle("Storage")
self.storageInventory.Close = function(this)
net.Start("ixStorageClose")
net.SendToServer()
self:Remove()
end
self.storageMoney = self.storageInventory:Add("ixStorageMoney")
self.storageMoney:SetVisible(false)
self.storageMoney.OnTransfer = function(_, amount)
net.Start("ixStorageMoneyTake")
net.WriteUInt(self.storageID, 32)
net.WriteUInt(amount, 32)
net.SendToServer()
end
ix.gui.inv1 = self:Add("ixInventory")
ix.gui.inv1.bNoBackgroundBlur = true
ix.gui.inv1:ShowCloseButton(true)
ix.gui.inv1.Close = function(this)
net.Start("ixStorageClose")
net.SendToServer()
self:Remove()
end
self.localMoney = ix.gui.inv1:Add("ixStorageMoney")
self.localMoney:SetVisible(false)
self.localMoney:SetLeft(true)
self.localMoney.OnTransfer = function(_, amount)
net.Start("ixStorageMoneyGive")
net.WriteUInt(self.storageID, 32)
net.WriteUInt(amount, 32)
net.SendToServer()
end
self:SetAlpha(0)
self:AlphaTo(255, self:GetFadeTime())
self.storageInventory:MakePopup()
ix.gui.inv1:MakePopup()
end
function PANEL:OnChildAdded(panel)
panel:SetPaintedManually(true)
end
function PANEL:SetLocalInventory(inventory)
if (IsValid(ix.gui.inv1) and !IsValid(ix.gui.menu)) then
ix.gui.inv1:SetInventory(inventory)
ix.gui.inv1:SetPos(self:GetWide() / 2 + self:GetFrameMargin() / 2, self:GetTall() / 2 - ix.gui.inv1:GetTall() / 2)
end
end
function PANEL:SetLocalMoney(money)
if (!self.localMoney:IsVisible()) then
self.localMoney:SetVisible(true)
ix.gui.inv1:SetTall(ix.gui.inv1:GetTall() + self.localMoney:GetTall() + 2)
end
self.localMoney:SetMoney(money)
end
function PANEL:SetStorageTitle(title)
self.storageInventory:SetTitle(title)
end
function PANEL:SetStorageInventory(inventory)
self.storageInventory:SetInventory(inventory)
self.storageInventory:SetPos(
self:GetWide() / 2 - self.storageInventory:GetWide() - 2,
self:GetTall() / 2 - self.storageInventory:GetTall() / 2
)
ix.gui["inv" .. inventory:GetID()] = self.storageInventory
end
function PANEL:SetStorageMoney(money)
if (!self.storageMoney:IsVisible()) then
self.storageMoney:SetVisible(true)
self.storageInventory:SetTall(self.storageInventory:GetTall() + self.storageMoney:GetTall() + 2)
end
self.storageMoney:SetMoney(money)
end
function PANEL:Paint(width, height)
ix.util.DrawBlurAt(0, 0, width, height)
for _, v in ipairs(self:GetChildren()) do
v:PaintManual()
end
end
function PANEL:Remove()
self:SetAlpha(255)
self:AlphaTo(0, self:GetFadeTime(), 0, function()
BaseClass.Remove(self)
end)
end
function PANEL:OnRemove()
if (!IsValid(ix.gui.menu)) then
self.storageInventory:Remove()
ix.gui.inv1:Remove()
end
end
vgui.Register("ixStorageView", PANEL, "Panel")

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/
--]]
local DEFAULT_PADDING = ScreenScale(32)
local DEFAULT_ANIMATION_TIME = 1
local DEFAULT_SUBPANEL_ANIMATION_TIME = 0.5
-- parent subpanel
local PANEL = {}
function PANEL:Init()
local parent = self:GetParent()
local padding = parent.GetPadding and parent:GetPadding() or DEFAULT_PADDING
self:SetSize(parent:GetWide() - (padding * 2), parent:GetTall() - (padding * 2))
self:Center()
end
function PANEL:SetTitle(text, bNoTranslation, bNoUpper)
if (text == nil) then
if (IsValid(self.title)) then
self.title:Remove()
end
return
elseif (!IsValid(self.title)) then
self.title = self:Add("DLabel")
self.title:SetFont("ixTitleFont")
self.title:SizeToContents()
self.title:SetTextColor(ix.config.Get("color") or color_white)
self.title:Dock(TOP)
end
local newText = bNoTranslation and text or L(text)
newText = bNoUpper and newText or newText:utf8upper()
self.title:SetText(newText)
self.title:SizeToContents()
end
function PANEL:SetLeftPanel(panel)
self.left = panel
end
function PANEL:GetLeftPanel()
return self.left
end
function PANEL:SetRightPanel(panel)
self.right = panel
end
function PANEL:GetRightPanel()
return self.right
end
function PANEL:OnSetActive()
end
vgui.Register("ixSubpanel", PANEL, "EditablePanel")
-- subpanel parent
DEFINE_BASECLASS("EditablePanel")
PANEL = {}
AccessorFunc(PANEL, "padding", "Padding", FORCE_NUMBER)
AccessorFunc(PANEL, "animationTime", "AnimationTime", FORCE_NUMBER)
AccessorFunc(PANEL, "subpanelAnimationTime", "SubpanelAnimationTime", FORCE_NUMBER)
AccessorFunc(PANEL, "leftOffset", "LeftOffset", FORCE_NUMBER)
function PANEL:Init()
self.subpanels = {}
self.childPanels = {}
self.currentSubpanelX = DEFAULT_PADDING
self.targetSubpanelX = DEFAULT_PADDING
self.padding = DEFAULT_PADDING
self.leftOffset = 0
self.animationTime = DEFAULT_ANIMATION_TIME
self.subpanelAnimationTime = DEFAULT_SUBPANEL_ANIMATION_TIME
end
function PANEL:SetPadding(amount, bSetDockPadding)
self.currentSubpanelX = amount
self.targetSubpanelX = amount
self.padding = amount
if (bSetDockPadding) then
self:DockPadding(amount, amount, amount, amount)
end
end
function PANEL:Add(name)
local panel = BaseClass.Add(self, name)
if (panel.SetPaintedManually) then
panel:SetPaintedManually(true)
self.childPanels[#self.childPanels + 1] = panel
end
return panel
end
function PANEL:AddSubpanel(name)
local id = #self.subpanels + 1
local panel = BaseClass.Add(self, "ixSubpanel")
panel.subpanelName = name
panel.subpanelID = id
panel:SetTitle(L(name))
self.subpanels[id] = panel
self:SetupSubpanelReferences()
return panel
end
function PANEL:SetupSubpanelReferences()
local lastPanel
for i = 1, #self.subpanels do
local panel = self.subpanels[i]
local nextPanel = self.subpanels[i + 1]
if (IsValid(lastPanel)) then
lastPanel:SetRightPanel(panel)
panel:SetLeftPanel(lastPanel)
end
if (IsValid(nextPanel)) then
panel:SetRightPanel(nextPanel)
end
lastPanel = panel
end
end
function PANEL:SetSubpanelPos(id, x)
local currentPanel = self.subpanels[id]
if (!currentPanel) then
return
end
local _, oldY = currentPanel:GetPos()
currentPanel:SetPos(x, oldY)
-- traverse left
while (IsValid(currentPanel)) do
local left = currentPanel:GetLeftPanel()
if (IsValid(left)) then
left:MoveLeftOf(currentPanel, self.padding + self.leftOffset)
end
currentPanel = left
end
currentPanel = self.subpanels[id]
-- traverse right
while (IsValid(currentPanel)) do
local right = currentPanel:GetRightPanel()
if (IsValid(right)) then
right:MoveRightOf(currentPanel, self.padding)
end
currentPanel = right
end
end
function PANEL:SetActiveSubpanel(id, length)
if (isstring(id)) then
for i = 1, #self.subpanels do
if (self.subpanels[i].subpanelName == id) then
id = i
break
end
end
end
local activePanel = self.subpanels[id]
if (!activePanel) then
return false
end
if (length == 0 or !self.activeSubpanel) then
self:SetSubpanelPos(id, self.padding + self.leftOffset)
else
local x, _ = activePanel:GetPos()
local target = self.targetSubpanelX + self.leftOffset
self.currentSubpanelX = x + self.padding + self.leftOffset
self:CreateAnimation(length or self.subpanelAnimationTime, {
index = 420,
target = {currentSubpanelX = target},
easing = "outQuint",
Think = function(animation, panel)
panel:SetSubpanelPos(id, panel.currentSubpanelX)
end,
OnComplete = function(animation, panel)
panel:SetSubpanelPos(id, target)
end
})
end
self.activeSubpanel = id
activePanel:OnSetActive()
return true
end
function PANEL:GetSubpanel(id)
return self.subpanels[id]
end
function PANEL:GetActiveSubpanel()
return self.subpanels[self.activeSubpanel]
end
function PANEL:GetActiveSubpanelID()
return self.activeSubpanel
end
function PANEL:Slide(direction, length, callback, bIgnoreConfig)
local _, height = self:GetParent():GetSize()
local x, _ = self:GetPos()
local targetY = direction == "up" and 0 or height
self:SetVisible(true)
if (length == 0) then
self:SetPos(x, targetY)
else
length = length or self.animationTime
self.currentY = direction == "up" and height or 0
self:CreateAnimation(length or self.animationTime, {
index = -1,
target = {currentY = targetY},
easing = "outExpo",
bIgnoreConfig = bIgnoreConfig,
Think = function(animation, panel)
local currentX, _ = panel:GetPos()
panel:SetPos(currentX, panel.currentY)
end,
OnComplete = function(animation, panel)
if (direction == "down") then
panel:SetVisible(false)
end
if (callback) then
callback(panel)
end
end
})
end
end
function PANEL:SlideUp(...)
self:SetMouseInputEnabled(true)
self:SetKeyboardInputEnabled(true)
self:OnSlideUp()
self:Slide("up", ...)
end
function PANEL:SlideDown(...)
self:SetMouseInputEnabled(false)
self:SetKeyboardInputEnabled(false)
self:OnSlideDown()
self:Slide("down", ...)
end
function PANEL:OnSlideUp()
end
function PANEL:OnSlideDown()
end
function PANEL:Paint(width, height)
for i = 1, #self.childPanels do
self.childPanels[i]:PaintManual()
end
end
function PANEL:PaintSubpanels(width, height)
for i = 1, #self.subpanels do
self.subpanels[i]:PaintManual()
end
end
-- ????
PANEL.Remove = BaseClass.Remove
vgui.Register("ixSubpanelParent", PANEL, "EditablePanel")

View File

@@ -0,0 +1,604 @@
--[[
| 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/
--]]
--- Text container for `ixTooltip`.
-- Rows are the main way of interacting with `ixTooltip`s. These derive from
-- [DLabel](https://wiki.garrysmod.com/page/Category:DLabel) panels, which means that making use of this panel
-- will be largely the same as any DLabel panel.
-- @panel ixTooltipRow
local animationTime = 1
-- panel meta
do
local PANEL = FindMetaTable("Panel")
local ixChangeTooltip = ChangeTooltip
local ixRemoveTooltip = RemoveTooltip
local tooltip
local lastHover
function PANEL:SetHelixTooltip(callback)
self:SetMouseInputEnabled(true)
self.ixTooltip = callback
end
function ChangeTooltip(panel, ...) -- luacheck: globals ChangeTooltip
if (!panel.ixTooltip) then
return ixChangeTooltip(panel, ...)
end
RemoveTooltip()
timer.Create("ixTooltip", 0.1, 1, function()
if (!IsValid(panel) or lastHover != panel) then
return
end
tooltip = vgui.Create("ixTooltip")
panel.ixTooltip(tooltip)
tooltip:SizeToContents()
end)
lastHover = panel
end
function RemoveTooltip() -- luacheck: globals RemoveTooltip
if (IsValid(tooltip)) then
tooltip:Remove()
tooltip = nil
end
timer.Remove("ixTooltip")
lastHover = nil
return ixRemoveTooltip()
end
end
DEFINE_BASECLASS("DLabel")
local PANEL = {}
AccessorFunc(PANEL, "backgroundColor", "BackgroundColor")
AccessorFunc(PANEL, "maxWidth", "MaxWidth", FORCE_NUMBER)
AccessorFunc(PANEL, "bNoMinimal", "MinimalHidden", FORCE_BOOL)
function PANEL:Init()
self:SetFont("ixSmallFont")
self:SetText(L("unknown"))
self:SetTextColor(color_white)
self:SetTextInset(4, 0)
self:SetContentAlignment(4)
self:Dock(TOP)
self.maxWidth = ScrW() * 0.2
self.bNoMinimal = false
self.bMinimal = false
end
--- Whether or not this tooltip row should be displayed in a minimal format. This usually means no background and/or
-- smaller font. You probably won't need this if you're using regular `ixTooltipRow` panels, but you should take into
-- account if you're creating your own panels that derive from `ixTooltipRow`.
-- @realm client
-- @treturn bool True if this tooltip row should be displayed in a minimal format
function PANEL:IsMinimal()
return self.bMinimal
end
--- Sets this row to be more prominent with a larger font and more noticable background color. This should usually
-- be used once per tooltip as a title row. For example, item tooltips have one "important" row consisting of the
-- item's name. Note that this function is a fire-and-forget function; you cannot revert a row back to it's regular state
-- unless you set the font/colors manually.
-- @realm client
function PANEL:SetImportant()
self:SetFont("ixSmallTitleFont")
self:SetExpensiveShadow(1, color_black)
self:SetBackgroundColor(ix.config.Get("color"))
end
--- Sets the background color of this row. This should be used sparingly to avoid overwhelming players with a
-- bunch of different colors that could convey different meanings.
-- @realm client
-- @color color New color of the background. The alpha is clamped to 100-255 to ensure visibility
function PANEL:SetBackgroundColor(color)
color = table.Copy(color)
color.a = math.min(color.a or 255, 100)
self.backgroundColor = color
end
--- Resizes this panel to fit its contents. This should be called after setting the text.
-- @realm client
function PANEL:SizeToContents()
local contentWidth, contentHeight = self:GetContentSize()
contentWidth = contentWidth + 4
contentHeight = contentHeight + 4
if (contentWidth > self.maxWidth) then
self:SetWide(self.maxWidth - 4) -- to account for text inset
self:SetTextInset(4, 0)
self:SetWrap(true)
self:SizeToContentsY()
else
self:SetSize(contentWidth, contentHeight)
end
end
--- Resizes the height of this panel to fit its contents.
-- @internal
-- @realm client
function PANEL:SizeToContentsY()
BaseClass.SizeToContentsY(self)
self:SetTall(self:GetTall() + 4)
end
--- Called when the background of this row should be painted. This will paint the background with the
-- `DrawImportantBackground` function set in the skin by default.
-- @realm client
-- @number width Width of the panel
-- @number height Height of the panel
function PANEL:PaintBackground(width, height)
if (self.backgroundColor) then
derma.SkinFunc("DrawImportantBackground", 0, 0, width, height, self.backgroundColor)
end
end
--- Called when the foreground of this row should be painted. If you are overriding this in a subclassed panel,
-- make sure you call `ixTooltipRow:PaintBackground` at the *beginning* of your function to make its style
-- consistent with the rest of the framework.
-- @realm client
-- @number width Width of the panel
-- @number height Height of the panel
function PANEL:Paint(width, height)
self:PaintBackground(width, height)
end
vgui.Register("ixTooltipRow", PANEL, "DLabel")
--- Generic information panel.
-- Tooltips are used extensively throughout Helix: for item information, character displays, entity status, etc.
-- The tooltip system can be used on any panel or entity you would like to show standardized information for. Tooltips
-- consist of the parent container panel (`ixTooltip`), which is filled with rows of information (usually
-- `ixTooltipRow`, but can be any docked panel if non-text information needs to be shown, like an item's size).
--
-- Tooltips can be added to panel with `panel:SetHelixTooltip()`. An example taken from the scoreboard:
-- panel:SetHelixTooltip(function(tooltip)
-- local name = tooltip:AddRow("name")
-- name:SetImportant()
-- name:SetText(client:SteamName())
-- name:SetBackgroundColor(team.GetColor(client:Team()))
-- name:SizeToContents()
--
-- tooltip:SizeToContents()
-- end)
-- @panel ixTooltip
DEFINE_BASECLASS("Panel")
PANEL = {}
AccessorFunc(PANEL, "entity", "Entity")
AccessorFunc(PANEL, "mousePadding", "MousePadding", FORCE_NUMBER)
AccessorFunc(PANEL, "bDrawArrow", "DrawArrow", FORCE_BOOL)
AccessorFunc(PANEL, "arrowColor", "ArrowColor")
AccessorFunc(PANEL, "bHideArrowWhenRaised", "HideArrowWhenRaised", FORCE_BOOL)
AccessorFunc(PANEL, "bArrowFollowEntity", "ArrowFollowEntity", FORCE_BOOL)
function PANEL:Init()
self.fraction = 0
self.mousePadding = 16
self.arrowColor = ix.config.Get("color")
self.bHideArrowWhenRaised = true
self.bArrowFollowEntity = true
self.bMinimal = false
self.lastX, self.lastY = self:GetCursorPosition()
self.arrowX, self.arrowY = ScrW() * 0.5, ScrH() * 0.5
self:SetAlpha(0)
self:SetSize(0, 0)
self:SetDrawOnTop(true)
self:SetMouseInputEnabled(false)
self:CreateAnimation(animationTime, {
index = 1,
target = {fraction = 1},
easing = "outQuint",
Think = function(animation, panel)
panel:SetAlpha(panel.fraction * 255)
end
})
end
--- Whether or not this tooltip should be displayed in a minimal format.
-- @realm client
-- @treturn bool True if this tooltip should be displayed in a minimal format
-- @see ixTooltipRow:IsMinimal
function PANEL:IsMinimal()
return self.bMinimal
end
-- ensure all children are painted manually
function PANEL:Add(...)
local panel = BaseClass.Add(self, ...)
panel:SetPaintedManually(true)
return panel
end
--- Creates a new `ixTooltipRow` panel and adds it to the bottom of this tooltip.
-- @realm client
-- @string id Name of the new row. This is used to reorder rows if needed
-- @treturn panel Created row
function PANEL:AddRow(id)
local panel = self:Add("ixTooltipRow")
panel.id = id
panel:SetZPos(#self:GetChildren() * 10)
return panel
end
--- Creates a new `ixTooltipRow` and adds it after the row with the given `id`. The order of the rows is set via
-- setting the Z position of the panels, as this is how VGUI handles ordering with docked panels.
-- @realm client
-- @string after Name of the row to insert after
-- @string id Name of the newly created row
-- @treturn panel Created row
function PANEL:AddRowAfter(after, id)
local panel = self:AddRow(id)
after = self:GetRow(after)
if (!IsValid(after)) then
return panel
end
panel:SetZPos(after:GetZPos() + 1)
return panel
end
--- Sets the entity associated with this tooltip. Note that this function is not how you get entities to show tooltips.
-- @internal
-- @realm client
-- @entity entity Entity to associate with this tooltip
function PANEL:SetEntity(entity)
if (!IsValid(entity)) then
self.bEntity = false
return
end
-- don't show entity tooltips if we have an entity menu open
if (IsValid(ix.menu.panel)) then
self:Remove()
return
end
if (entity:IsPlayer()) then
local character = entity:GetCharacter()
if (character) then
-- we want to group things that will most likely have backgrounds (e.g name/health status)
hook.Run("PopulateImportantCharacterInfo", entity, character, self)
hook.Run("PopulateCharacterInfo", entity, character, self)
end
else
if (entity.OnPopulateEntityInfo) then
entity:OnPopulateEntityInfo(self)
else
hook.Run("PopulateEntityInfo", entity, self)
end
end
self:SizeToContents()
self.entity = entity
self.bEntity = true
end
function PANEL:PaintUnder(width, height)
end
function PANEL:Paint(width, height)
self:PaintUnder()
-- directional arrow
self.bRaised = LocalPlayer():IsWepRaised()
if (!self.bClosing) then
if (self.bEntity and IsValid(self.entity) and self.bArrowFollowEntity) then
local entity = self.entity
local position = select(1, entity:GetBonePosition(entity:LookupBone("ValveBiped.Bip01_Spine") or -1)) or
entity:LocalToWorld(entity:OBBCenter())
position = position:ToScreen()
self.arrowX = math.Clamp(position.x, 0, ScrW())
self.arrowY = math.Clamp(position.y, 0, ScrH())
end
end
-- arrow
if (self.bDrawArrow or (self.bDrawArrow and self.bRaised and !self.bHideArrowWhenRaised)) then
local x, y = self:ScreenToLocal(self.arrowX, self.arrowY)
DisableClipping(true)
surface.SetDrawColor(self.arrowColor)
surface.DrawLine(0, 0, x * self.fraction, y * self.fraction)
surface.DrawRect((x - 2) * self.fraction, (y - 2) * self.fraction, 4, 4)
DisableClipping(false)
end
-- contents
local x, y = self:GetPos()
render.SetScissorRect(x, y, x + width * self.fraction, y + height, true)
derma.SkinFunc("PaintTooltipBackground", self, width, height)
for _, v in ipairs(self:GetChildren()) do
if (IsValid(v)) then
v:PaintManual()
end
end
render.SetScissorRect(0, 0, 0, 0, false)
end
--- Returns the current position of the mouse cursor on the screen.
-- @realm client
-- @treturn number X position of cursor
-- @treturn number Y position of cursor
function PANEL:GetCursorPosition()
local width, height = self:GetSize()
local mouseX, mouseY = gui.MousePos()
return math.Clamp(mouseX + self.mousePadding, 0, ScrW() - width), math.Clamp(mouseY, 0, ScrH() - height)
end
function PANEL:Think()
if (!self.bEntity) then
if (!vgui.CursorVisible()) then
self:SetPos(self.lastX, self.lastY)
-- if the cursor isn't visible then we don't really need the tooltip to be shown
if (!self.bClosing) then
self:Remove()
end
else
local newX, newY = self:GetCursorPosition()
self:SetPos(newX, newY)
self.lastX, self.lastY = newX, newY
end
self:MoveToFront() -- dragging a panel w/ tooltip will push the tooltip beneath even the menu panel(???)
elseif (IsValid(self.entity) and !self.bClosing) then
if (self.bRaised) then
self:SetPos(
ScrW() * 0.5 - self:GetWide() * 0.5,
math.min(ScrH() * 0.5 + self:GetTall() + 32, ScrH() - self:GetTall())
)
else
local entity = self.entity
local min, max = entity:GetRotatedAABB(entity:OBBMins() * 0.5, entity:OBBMaxs() * 0.5)
min = entity:LocalToWorld(min):ToScreen().x
max = entity:LocalToWorld(max):ToScreen().x
self:SetPos(
math.Clamp(math.max(min, max), ScrW() * 0.5 + 64, ScrW() - self:GetWide()),
ScrH() * 0.5 - self:GetTall() * 0.5
)
end
end
end
--- Returns an `ixTooltipRow` corresponding to the given name.
-- @realm client
-- @string id Name of the row
-- @treturn[1] panel Corresponding row
-- @treturn[2] nil If the row doesn't exist
function PANEL:GetRow(id)
for _, v in ipairs(self:GetChildren()) do
if (IsValid(v) and v.id == id) then
return v
end
end
end
--- Resizes the tooltip to fit all of the child panels. You should always call this after you are done
-- adding all of your rows.
-- @realm client
function PANEL:SizeToContents()
local height = 0
local width = 0
for _, v in ipairs(self:GetChildren()) do
if (v:GetWide() > width) then
width = v:GetWide()
end
height = height + v:GetTall()
end
self:SetSize(width, height)
end
function PANEL:Remove()
if (self.bClosing) then
return
end
self.bClosing = true
self:CreateAnimation(animationTime * 0.5, {
target = {fraction = 0},
easing = "outQuint",
Think = function(animation, panel)
panel:SetAlpha(panel.fraction * 255)
end,
OnComplete = function(animation, panel)
BaseClass.Remove(panel)
end
})
end
vgui.Register("ixTooltip", PANEL, "Panel")
-- legacy tooltip row
PANEL = {}
function PANEL:Init()
self.bMinimal = true
self.ixAlpha = 0 -- to avoid conflicts if we're animating a non-tooltip panel
self:SetExpensiveShadow(1, color_black)
self:SetContentAlignment(5)
end
function PANEL:SetImportant()
self:SetFont("ixMinimalTitleFont")
self:SetBackgroundColor(ix.config.Get("color"))
end
-- background color will affect text instead in minimal tooltips
function PANEL:SetBackgroundColor(color)
color = table.Copy(color)
color.a = math.min(color.a or 255, 100)
self:SetTextColor(color)
self.backgroundColor = color
end
function PANEL:PaintBackground()
end
vgui.Register("ixTooltipMinimalRow", PANEL, "ixTooltipRow")
-- legacy tooltip
DEFINE_BASECLASS("ixTooltip")
PANEL = {}
function PANEL:Init()
self.bMinimal = true
-- we don't want to animate the alpha since children will handle their own animation, but we want to keep the fraction
-- for the background to animate
self:CreateAnimation(animationTime, {
index = 1,
target = {fraction = 1},
easing = "outQuint",
})
self:SetAlpha(255)
end
-- we don't need the children to be painted manually
function PANEL:Add(...)
local panel = BaseClass.Add(self, ...)
panel:SetPaintedManually(false)
return panel
end
function PANEL:AddRow(id)
local panel = self:Add("ixTooltipMinimalRow")
panel.id = id
panel:SetZPos(#self:GetChildren() * 10)
return panel
end
function PANEL:Paint(width, height)
self:PaintUnder()
derma.SkinFunc("PaintTooltipMinimalBackground", self, width, height)
end
function PANEL:Think()
end
function PANEL:SizeToContents()
-- remove any panels that shouldn't be shown in a minimal tooltip
for _, v in ipairs(self:GetChildren()) do
if (v.bNoMinimal) then
v:Remove()
end
end
BaseClass.SizeToContents(self)
self:SetPos(ScrW() * 0.5 - self:GetWide() * 0.5, ScrH() * 0.5 + self.mousePadding)
-- we create animation here since this is the only function that usually gets called after all the rows are populated
local children = self:GetChildren()
-- sort by z index so we can animate them in order
table.sort(children, function(a, b)
return a:GetZPos() < b:GetZPos()
end)
local i = 1
local count = table.Count(children)
for _, v in ipairs(children) do
v.ixAlpha = v.ixAlpha or 0
v:CreateAnimation((animationTime / count) * i, {
easing = "inSine",
target = {ixAlpha = 255},
Think = function(animation, panel)
panel:SetAlpha(panel.ixAlpha)
end
})
i = i + 1
end
end
DEFINE_BASECLASS("Panel")
function PANEL:Remove()
if (self.bClosing) then
return
end
self.bClosing = true
-- we create animation here since this is the only function that usually gets called after all the rows are populated
local children = self:GetChildren()
-- sort by z index so we can animate them in order
table.sort(children, function(a, b)
return a:GetZPos() > b:GetZPos()
end)
local duration = animationTime * 0.5
local i = 1
local count = table.Count(children)
for _, v in ipairs(children) do
v.ixAlpha = v.ixAlpha or 255
v:CreateAnimation(duration / count * i, {
target = {ixAlpha = 0},
Think = function(animation, panel)
panel:SetAlpha(panel.ixAlpha)
end
})
i = i + 1
end
self:CreateAnimation(duration, {
target = {fraction = 0},
OnComplete = function(animation, panel)
BaseClass.Remove(panel)
end
})
end
vgui.Register("ixTooltipMinimal", PANEL, "ixTooltip")