This commit is contained in:
lifestorm
2024-08-04 22:55:00 +03:00
parent 0e770b2b49
commit 94063e4369
7342 changed files with 1718932 additions and 14 deletions

View File

@@ -0,0 +1,727 @@
--[[
| 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/
--]]
-- Copyright (c) 2018-2020 TFA Base Devs
-- Permission is hereby granted, free of charge, to any person obtaining a copy
-- of this software and associated documentation files (the "Software"), to deal
-- in the Software without restriction, including without limitation the rights
-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-- copies of the Software, and to permit persons to whom the Software is
-- furnished to do so, subject to the following conditions:
-- The above copyright notice and this permission notice shall be included in all
-- copies or substantial portions of the Software.
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-- SOFTWARE.
local ATT_DIMENSION
local ATT_MAX_SCREEN_RATIO = 1 / 3
local tableCopy = table.Copy
SWEP.Attachments = {} --[MDL_ATTACHMENT] = = { offset = { 0, 0 }, atts = { "sample_attachment_1", "sample_attachment_2" }, sel = 1, order = 1 } --offset will move the offset the display from the weapon attachment when using CW2.0 style attachment display --atts is a table containing the visible attachments --sel allows you to have an attachment pre-selected, and is used internally by the base to show which attachment is selected in each category. --order is the order it will appear in the TFA style attachment menu
SWEP.AttachmentCache = {} --["att_name"] = true
SWEP.AttachmentTableCache = {}
SWEP.AttachmentCount = 0
SWEP.AttachmentDependencies = {} --{["si_acog"] = {"bg_rail"}}
SWEP.AttachmentExclusions = {} --{ ["si_iron"] = {"bg_heatshield"} }
SWEP.AttachmentTableOverride = {}
local pairs, type, tonumber = pairs, type, tonumber
local string, IsValid = string, IsValid
local table = table
function SWEP:RemoveUnusedAttachments()
for k, v in pairs(self.Attachments) do
if v.atts then
local t = {}
local i = 1
for _, b in pairs(v.atts) do
if TFA.Attachments.Atts[b] then
t[i] = b
i = i + 1
end
end
v.atts = tableCopy(t)
end
if #v.atts <= 0 then
self.Attachments[k] = nil
end
end
end
local function select_function_table(target)
-- idk
local found_table
for i_index, base_value in pairs(target) do
if istable(base_value) then
found_table = base_value
end
end
if not found_table then
found_table = {}
table.insert(target, found_table)
end
return found_table
end
local function get(path, target)
if #path == 1 then
return target[path[1]]
end
local _target = target[path[1]]
if _target == nil then
target[path[1]] = {}
_target = target[path[1]]
end
for i = 2, #path do
if not istable(_target) then
return
end
if _target[path[i]] == nil then _target[path[i]] = {} end
if istable(_target[path[i]]) and _target[path[i]].functionTable and i ~= #path then
_target = select_function_table(_target[path[i]])
else
_target = _target[path[i]]
end
end
return _target
end
local function set(path, target, value)
if #path == 1 then
target[path[1]] = value
return value
end
local _target = target[path[1]]
if _target == nil then
target[path[1]] = {}
_target = target[path[1]]
end
for i = 2, #path - 1 do
if not istable(_target) then
return value
end
if _target[path[i]] == nil then _target[path[i]] = {} end
if _target[path[i]].functionTable then
_target = select_function_table(_target[path[i]])
else
_target = _target[path[i]]
end
end
if istable(_target) then
if istable(_target[path[#path]]) and _target[path[#path]].functionTable then
table.insert(select_function_table(_target[path[#path]]), value)
else
_target[path[#path]] = value
end
end
return value
end
local function CloneTableRecursive(source, target, root, source_version, target_version)
for index, value in pairs(source) do
local _root = root == "" and index or (root .. "." .. index)
-- merge two tables
if istable(value) then
local baseTable = get(TFA.GetStatPath(_root, source_version, target_version), target)
-- target is a function table
if istable(baseTable) and baseTable.functionTable then
local found_table
for i_index, base_value in pairs(baseTable) do
if istable(base_value) then
found_table = base_value
end
end
if not found_table then
found_table = {}
table.insert(baseTable, 1, found_table)
end
CloneTableRecursive(value, target, _root, source_version, target_version)
-- target is a regular table
else
if not istable(baseTable) then
set(TFA.GetStatPath(_root, source_version, target_version), target, {})
end
CloneTableRecursive(value, target, _root, source_version, target_version)
end
-- final value is determined by function
elseif isfunction(value) then
local temp
local get_path = TFA.GetStatPath(_root, source_version, target_version)
local get_table = get(get_path, target)
if get_table ~= nil and not istable(get_table) then
temp = get_table
end
local get_value = not istable(get_table) and set(get_path, target, {}) or get_table
-- mark this table as function based
get_value.functionTable = true
if temp ~= nil then
-- insert variable that was there before
table.insert(get_value, temp)
end
-- insert function
table.insert(get_value, value)
-- final value is a scalar
else
local get_table = get(TFA.GetStatPath(_root, source_version, target_version), target)
if istable(get_table) and get_table.functionTable then
table.insert(get_table, 1, value)
else
set(TFA.GetStatPath(_root, source_version, target_version), target, value)
end
end
end
end
function SWEP:BuildAttachmentCache()
self.AttachmentCount = 0
for k, v in pairs(self.Attachments) do
if v.atts then
for l, b in pairs(v.atts) do
self.AttachmentCount = self.AttachmentCount + 1
self.AttachmentCache[b] = (v.sel == l) and k or false
end
end
end
table.Empty(self.AttachmentTableCache)
for attName, sel in pairs(self.AttachmentCache) do
if not sel then goto CONTINUE end
if not TFA.Attachments.Atts[attName] then goto CONTINUE end
local srctbl = TFA.Attachments.Atts[attName].WeaponTable
if istable(srctbl) then
CloneTableRecursive(srctbl, self.AttachmentTableCache, "", TFA.Attachments.Atts[attName].TFADataVersion or 0, self.TFADataVersion or 0)
end
if istable(self.AttachmentTableOverride[attName]) then
CloneTableRecursive(self.AttachmentTableOverride[attName], self.AttachmentTableCache, "", self.TFADataVersion or 0, self.TFADataVersion or 0)
end
::CONTINUE::
end
self:ClearStatCache()
self:ClearMaterialCache()
end
function SWEP:IsAttached(attn)
return isnumber(self.AttachmentCache[attn])
end
local tc
function SWEP:CanAttach(attn)
local retVal = hook.Run("TFA_PreCanAttach", self, attn)
if retVal ~= nil then return retVal end
local self2 = self:GetTable()
if not self2.HasBuiltMutualExclusions then
tc = tableCopy(self2.AttachmentExclusions)
for k, v in pairs(tc) do
if k ~= "BaseClass" then
for _, b in pairs(v) do
self2.AttachmentExclusions[b] = self2.AttachmentExclusions[b] or {}
if not table.HasValue(self2.AttachmentExclusions[b]) then
self2.AttachmentExclusions[b][#self2.AttachmentExclusions[b] + 1] = k
end
end
end
end
self2.HasBuiltMutualExclusions = true
end
if self.AttachmentExclusions[attn] then
for _, v in pairs(self.AttachmentExclusions[attn]) do
if self:IsAttached(v) then return false end
end
end
if self2.AttachmentDependencies[attn] then
local t = self2.AttachmentDependencies[attn]
if isstring(t) then
if t ~= "BaseClass" and not self2.IsAttached(self, t) then return false end
elseif istable(t) then
t.type = t.type or "OR"
if t.type == "AND" then
for k, v in pairs(self.AttachmentDependencies[attn]) do
if k ~= "BaseClass" and k ~= "type" and not self2.IsAttached(self, v) then return false end
end
else
local cnt = 0
for k, v in pairs(self.AttachmentDependencies[attn]) do
if k ~= "BaseClass" and k ~= "type" and self2.IsAttached(self, v) then
cnt = cnt + 1
end
end
if cnt == 0 then return false end
end
end
end
local atTable = TFA.Attachments.Atts[attn]
if not atTable or not atTable:CanAttach(self) then return false end
local retVal2 = hook.Run("TFA_CanAttach", self, attn)
if retVal2 ~= nil then return retVal2 end
return true
end
local ATTACHMENT_SORTING_DEPENDENCIES = false
function SWEP:ForceAttachmentReqs(attn)
if not ATTACHMENT_SORTING_DEPENDENCIES then
ATTACHMENT_SORTING_DEPENDENCIES = true
local related = {}
for k, v in pairs(self.AttachmentDependencies) do
if istable(v) then
for _, b in pairs(v) do
if k == attn then
related[b] = true
elseif b == attn then
related[k] = true
end
end
elseif isstring(v) then
if k == attn then
related[v] = true
elseif v == attn then
related[k] = true
end
end
end
for k, v in pairs(self.AttachmentExclusions) do
if istable(v) then
for _, b in pairs(v) do
if k == attn then
related[b] = true
elseif b == attn then
related[k] = true
end
end
elseif isstring(v) then
if k == attn then
related[v] = true
elseif v == attn then
related[k] = true
end
end
end
for k, v in pairs(self.AttachmentCache) do
if v and related[k] and not self:CanAttach(k) then
self:SetTFAAttachment(v, 0, true, true)
end
end
ATTACHMENT_SORTING_DEPENDENCIES = false
end
end
do
local self3, att_neue, att_old
local function attach()
att_neue:Attach(self3)
end
local function detach()
att_old:Detach(self3)
end
function SWEP:SetTFAAttachment(cat, id, nw, force)
self3 = self
local self2 = self:GetTable()
if not self2.Attachments[cat] then return false end
if isstring(id) then
if id == "" then
id = -1
else
id = table.KeyFromValue(self2.Attachments[cat].atts, id)
if not id then return false end
end
end
if id <= 0 and self2.Attachments[cat].default and type(self2.Attachments[cat].default) == "string" and self2.Attachments[cat].default ~= "" then
return self2.SetTFAAttachment(self, cat, self2.Attachments[cat].default, nw, force)
end
local attn = self2.Attachments[cat].atts[id] or ""
local attn_old = self2.Attachments[cat].atts[self2.Attachments[cat].sel or -1] or ""
if SERVER and id > 0 and not (force or self2.CanAttach(self, attn)) then return false end
if id ~= self2.Attachments[cat].sel then
att_old = TFA.Attachments.Atts[self2.Attachments[cat].atts[self2.Attachments[cat].sel] or -1]
local detach_status = att_old == nil
if att_old then
detach_status = ProtectedCall(detach)
if detach_status then
hook.Run("TFA_Attachment_Detached", self, attn_old, att_old, cat, id, force)
end
end
att_neue = TFA.Attachments.Atts[self2.Attachments[cat].atts[id] or -1]
local attach_status = att_neue == nil
if detach_status then
if att_neue then
attach_status = ProtectedCall(attach)
if attach_status then
hook.Run("TFA_Attachment_Attached", self, attn, att_neue, cat, id, force)
end
end
end
if detach_status and attach_status then
if id > 0 then
self2.Attachments[cat].sel = id
else
self2.Attachments[cat].sel = nil
end
end
end
self2.BuildAttachmentCache(self)
self2.ForceAttachmentReqs(self, (id > 0) and attn or attn_old)
if nw and (not isentity(nw) or SERVER) then
net.Start("TFA_Attachment_Set")
net.WriteUInt(cat, 8)
net.WriteString(attn)
if SERVER then
net.WriteEntity(self)
if isentity(nw) then
local filter = RecipientFilter()
filter:AddPVS(self:GetPos())
filter:RemovePlayer(nw)
net.Send(filter)
else
net.SendPVS(self:GetPos())
end
elseif CLIENT then
net.SendToServer()
end
end
return true
end
end
function SWEP:Attach(attname, force)
if not attname or not IsValid(self) then return false end
if self.AttachmentCache[attname] == nil then return false end
for cat, tbl in pairs(self.Attachments) do
local atts = tbl.atts
for id, att in ipairs(atts) do
if att == attname then return self:SetTFAAttachment(cat, id, true, force) end
end
end
return false
end
function SWEP:Detach(attname, force)
if not attname or not IsValid(self) then return false end
local cat = self.AttachmentCache[attname]
if not cat then return false end
return self:SetTFAAttachment(cat, 0, true, force)
end
function SWEP:RandomizeAttachments(force)
for key, slot in pairs(self.AttachmentCache) do
if slot then
self:Detach(key)
end
end
for category, def in pairs(self.Attachments) do
if istable(def) and istable(def.atts) and #def.atts > 0 then
if math.random() > 0.3 then
local randkey = math.random(1, #def.atts)
self:SetTFAAttachment(category, randkey, true, force)
end
end
end
end
local attachments_sorted_alphabetically = GetConVar("sv_tfa_attachments_alphabetical")
function SWEP:InitAttachments()
if self.HasInitAttachments then return end
hook.Run("TFA_PreInitAttachments", self)
self.HasInitAttachments = true
for k, v in pairs(self.Attachments) do
if type(k) == "string" then
local tatt = self:VMIV() and self.OwnerViewModel:LookupAttachment(k) or self:LookupAttachment(k)
if tatt > 0 then
self.Attachments[tatt] = v
end
self.Attachments[k] = nil
elseif (not attachments_sorted_alphabetically) and attachments_sorted_alphabetically:GetBool() then
local sval = v.atts[v.sel]
table.sort(v.atts, function(a, b)
local aname = ""
local bname = ""
local att_a = TFA.Attachments.Atts[a]
if att_a then
aname = att_a.Name or a
end
local att_b = TFA.Attachments.Atts[b]
if att_b then
bname = att_b.Name or b
end
return aname < bname
end)
if sval then
v.sel = table.KeyFromValue(v.atts, sval) or v.sel
end
end
end
for k, v in pairs(self.Attachments) do
if v.sel then
local vsel = v.sel
v.sel = nil
if type(vsel) == "string" then
vsel = table.KeyFromValue(v.atts, vsel) or tonumber(vsel)
if not vsel then goto CONTINUE end
end
timer.Simple(0, function()
if IsValid(self) and self.SetTFAAttachment then
self:SetTFAAttachment(k, vsel, false)
end
end)
if SERVER and game.SinglePlayer() then
timer.Simple(0.05, function()
if IsValid(self) and self.SetTFAAttachment then
self:SetTFAAttachment(k, vsel, true)
end
end)
end
end
::CONTINUE::
end
hook.Run("TFA_PostInitAttachments", self)
self:RemoveUnusedAttachments()
self:BuildAttachmentCache()
hook.Run("TFA_FinalInitAttachments", self)
end
function SWEP:GenerateVGUIAttachmentTable()
self.VGUIAttachments = {}
local keyz = table.GetKeys(self.Attachments)
table.RemoveByValue(keyz, "BaseClass")
table.sort(keyz, function(a, b)
--A and B are keys
local v1 = self.Attachments[a]
local v2 = self.Attachments[b]
if v1 and v2 and (v1.order or v2.order) then
return (v1.order or a) < (v2.order or b)
else
return a < b
end
end)
for _, k in ipairs(keyz) do
local v = self.Attachments[k]
if not v.hidden then
local aTbl = tableCopy(v)
aTbl.cat = k
aTbl.offset = nil
aTbl.order = nil
table.insert(self.VGUIAttachments, aTbl)
end
end
ATT_DIMENSION = math.Round(TFA.ScaleH(TFA.Attachments.IconSize))
local max_row_atts = math.floor(ScrW() * ATT_MAX_SCREEN_RATIO / ATT_DIMENSION)
local i = 1
while true do
local v = self.VGUIAttachments[i]
if not v then break end
i = i + 1
for l, b in pairs(v.atts) do
if not istable(b) then
v.atts[l] = {b, l} --name, ID
end
end
if (#v.atts > max_row_atts) then
while (#v.atts > max_row_atts) do
local t = tableCopy(v)
for _ = 1, max_row_atts do
table.remove(t.atts, 1)
end
for _ = 1, #v.atts - max_row_atts do
table.remove(v.atts)
end
table.insert(self.VGUIAttachments, i, t)
end
end
end
end
local bgt = {}
SWEP.ViewModelBodygroups = {}
SWEP.WorldModelBodygroups = {}
function SWEP:IterateBodygroups(entity, tablename, version)
local self2 = self:GetTable()
bgt = self2.GetStatVersioned(self, tablename, version or 0, self2[tablename])
for k, v in pairs(bgt) do
if isnumber(k) then
local bgn = entity:GetBodygroupName(k)
if bgt[bgn] then
v = bgt[bgn]
end
if entity:GetBodygroup(k) ~= v then
entity:SetBodygroup(k, v)
end
end
end
end
function SWEP:ProcessBodygroups()
local self2 = self:GetTable()
local ViewModelBodygroups = self:GetStatRawL("ViewModelBodygroups")
local WorldModelBodygroups = self:GetStatRawL("WorldModelBodygroups")
if not self2.HasFilledBodygroupTables then
if self2.VMIV(self) then
for i = 0, #(self2.OwnerViewModel:GetBodyGroups() or ViewModelBodygroups) do
ViewModelBodygroups[i] = ViewModelBodygroups[i] or 0
end
end
for i = 0, #(self:GetBodyGroups() or WorldModelBodygroups) do
WorldModelBodygroups[i] = WorldModelBodygroups[i] or 0
end
self2.HasFilledBodygroupTables = true
end
if self2.VMIV(self) then
self2.IterateBodygroups(self, self2.OwnerViewModel, "ViewModelBodygroups", TFA.LatestDataVersion)
end
self2.IterateBodygroups(self, self, "WorldModelBodygroups", TFA.LatestDataVersion)
end
function SWEP:CallAttFunc(funcName, ...)
for attName, sel in pairs(self.AttachmentCache or {}) do
if not sel then goto CONTINUE end
local att = TFA.Attachments.Atts[attName]
if not att then goto CONTINUE end
local attFunc = att[funcName]
if attFunc and type(attFunc) == "function" then
local _ret1, _ret2, _ret3, _ret4, _ret5, _ret6, _ret7, _ret8, _ret9, _ret10 = attFunc(att, self, ...)
if _ret1 ~= nil then
return _ret1, _ret2, _ret3, _ret4, _ret5, _ret6, _ret7, _ret8, _ret9, _ret10
end
end
::CONTINUE::
end
return nil
end