--[[ | 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/ --]] -- Used to prevent stack overflow. Set false here so luarefresh clears it ArcCW.BuffStack = false ArcCW.ConVar_BuffMults = { ["Mult_Damage"] = "arccw_mult_damage", ["Mult_DamageMin"] = "arccw_mult_damage", ["Mult_DamageNPC"] = "arccw_mult_npcdamage", ["Mult_HipDispersion"] = "arccw_mult_hipfire", ["Mult_ReloadTime"] = "arccw_mult_reloadtime", ["Mult_SightTime"] = "arccw_mult_sighttime", ["Mult_RPM"] = "arccw_mult_rpm", ["Mult_CycleTime"] = "arccw_mult_rpm", ["Mult_Range"] = "arccw_mult_range", ["Mult_Recoil"] = "arccw_mult_recoil", ["Mult_MoveDispersion"] = "arccw_mult_movedisp", ["Mult_AccuracyMOA"] = "arccw_mult_accuracy", ["Mult_Penetration"] = "arccw_mult_penetration", ["Mult_Sway"] = "arccw_mult_sway", ["Mult_MeleeDamage"] = "arccw_mult_meleedamage", ["Mult_MeleeTime"] = "arccw_mult_meleetime", } ArcCW.ConVar_BuffAdds = { ["Add_Sway"] = "arccw_add_sway", } ArcCW.ConVar_BuffOverrides = { ["Override_ShootWhileSprint"] = "arccw_mult_shootwhilesprinting" } SWEP.TickCache_Overrides = {} SWEP.TickCache_Adds = {} SWEP.TickCache_Mults = {} SWEP.TickCache_Hooks = {} SWEP.TickCache_IsShotgun = nil SWEP.TickCache_Tick_Overrides = {} SWEP.TickCache_Tick_Adds = {} SWEP.TickCache_Tick_Mults = {} SWEP.AttCache_Hooks = {} -- debug: enable/disable modified caching local MODIFIED_CACHE = true -- print if a variable presumed to never change actually changes (this also happens right after attaching/detaching) -- only works if MODIFIED_CACHE is false local VERIFY_MODIFIED_CACHE = false -- Conditions not listed are are presumed to never change; this is done for optimization purposes SWEP.ModifiedCache = {} function SWEP:RecalcAllBuffs() self.TickCache_Overrides = {} self.TickCache_Adds = {} self.TickCache_Mults = {} self.TickCache_Hooks = {} self.TickCache_IsShotgun = nil self.TickCache_Tick_Overrides = {} self.TickCache_Tick_Adds = {} self.TickCache_Tick_Mults = {} self.ReferencePosCache = {} self.AttCache_Hooks = {} self.NextMalfunction = nil -- for the customization page if CLIENT then self.Infos_Stats = nil self.Infos_Ballistics = nil self.Infos_Breakpoints = nil end -- this function is not always called right before AdjustAtts --self.ModifiedCache = {} end function SWEP:GetIsShotgun() if self.TickCache_IsShotgun == nil then local shotgun = self:GetBuff_Override("Override_IsShotgun") if shotgun != nil then self.TickCache_IsShotgun = shotgun end local num = self.Num if self.TickCache_IsShotgun == nil and num > 1 then self.TickCache_IsShotgun = true end end return self.TickCache_IsShotgun end function SWEP:GetIsManualAction() local manual = self:GetBuff_Override("Override_ManualAction") if manual != false then manual = manual or self.ManualAction end -- A manual action gun CAN have automatic firemode, this is intended behavior!!! -- It's used for slamfiring --[[] local mode = self:GetCurrentFiremode().Mode if mode != 0 and mode != 1 then return false end ]] return manual end -- ONE FUNCTION TO RULE THEM ALL function SWEP:GetBuff(buff, defaultnil, defaultvar) local stable = self:GetTable() local result = stable[buff] or defaultvar if !result and defaultnil then result = nil elseif !result then result = 1 end result = self:GetBuff_Override("Override_" .. buff, result) if isnumber(result) then result = self:GetBuff_Add("Add_" .. buff) + result result = self:GetBuff_Mult("Mult_" .. buff) * result end return result end function SWEP:GetBuff_Stat(buff, slot) local slottbl = self.Attachments[slot] if !slottbl then return end local atttbl = ArcCW.AttachmentTable[slottbl.Installed] if !atttbl then return end local num = slottbl.ToggleNum or 1 if atttbl.ToggleStats and atttbl.ToggleStats[num] and (atttbl.ToggleStats[num][buff] != nil) then return atttbl.ToggleStats[num][buff] else return atttbl[buff] end end function SWEP:GetBuff_Hook(buff, data, defaultnil) -- call through hook function, args = data. return nil to do nothing. return false to prevent thing from happening. if !self.AttCache_Hooks[buff] then self.AttCache_Hooks[buff] = {} for i, k in pairs(self.Attachments) do if !k.Installed then continue end local atttbl = ArcCW.AttachmentTable[k.Installed] if !atttbl then continue end if isfunction(atttbl[buff]) then table.insert(self.AttCache_Hooks[buff], {atttbl[buff], atttbl[buff .. "_Priority"] or 0}) elseif atttbl.ToggleStats and k.ToggleNum and atttbl.ToggleStats[k.ToggleNum] and isfunction(atttbl.ToggleStats[k.ToggleNum][buff]) then table.insert(self.AttCache_Hooks[buff], {atttbl.ToggleStats[k.ToggleNum][buff], atttbl.ToggleStats[k.ToggleNum][buff .. "_Priority"] or 0}) end end local cfm = self:GetCurrentFiremode() if cfm and isfunction(cfm[buff]) then table.insert(self.AttCache_Hooks[buff], {cfm[buff], cfm[buff .. "_Priority"] or 0}) end for i, e in pairs(self:GetActiveElements()) do local ele = self.AttachmentElements[e] if ele and ele[buff] then table.insert(self.AttCache_Hooks[buff], {ele[buff], ele[buff .. "_Priority"] or 0}) end end if isfunction(self:GetTable()[buff]) then table.insert(self.AttCache_Hooks[buff], {self:GetTable()[buff], self:GetTable()[buff .. "_Priority"] or 0}) end table.sort(self.AttCache_Hooks[buff], function(a, b) return a[2] >= b[2] end)shouldsort = true end local retvalue = nil for i, k in ipairs(self.AttCache_Hooks[buff]) do local ret = k[1](self, data) if ret == false then return elseif ret != nil then retvalue = ret break end end if retvalue then data = retvalue elseif defaultnil then data = nil end data = hook.Call(buff, nil, self, data) or data return data end function SWEP:GetBuff_Override(buff, default) local level = 0 local current = nil local winningslot = nil if MODIFIED_CACHE and !self.ModifiedCache[buff] then -- ArcCW.ConVar_BuffOverrides[buff] isn't actually implemented?? if !ArcCW.BuffStack then ArcCW.BuffStack = true local out = (self:GetBuff_Hook("O_Hook_" .. buff, {buff = buff}) or {}) current = out.current or current winningslot = out.winningslot or winningslot ArcCW.BuffStack = false end return current or default, winningslot end if self.TickCache_Overrides[buff] then current = self.TickCache_Overrides[buff][1] winningslot = self.TickCache_Overrides[buff][2] local data = { buff = buff, current = current, winningslot = winningslot } if !ArcCW.BuffStack then ArcCW.BuffStack = true local out = (self:GetBuff_Hook("O_Hook_" .. buff, data) or {}) current = out.current or current winningslot = out.winningslot or winningslot ArcCW.BuffStack = false end if current == nil then return default else return current, winningslot end end for i, k in pairs(self.Attachments) do if !k.Installed then continue end local atttbl = ArcCW.AttachmentTable[k.Installed] if !atttbl then continue end if atttbl[buff] != nil then local pri = atttbl[buff .. "_Priority"] or 1 if level == 0 or (pri > level) then current = atttbl[buff] level = pri winningslot = i end end if atttbl.ToggleStats and k.ToggleNum and atttbl.ToggleStats[k.ToggleNum] and atttbl.ToggleStats[k.ToggleNum][buff] then local pri = atttbl.ToggleStats[k.ToggleNum][buff .. "_Priority"] or 1 if level == 0 or (pri > level) then current = atttbl.ToggleStats[k.ToggleNum][buff] level = pri winningslot = i end end end if !ArcCW.BuffStack then ArcCW.BuffStack = true local cfm = self:GetCurrentFiremode() if cfm and cfm[buff] != nil then local pri = cfm[buff .. "_Priority"] or 1 if level == 0 or (pri > level) then current = cfm[buff] level = pri end end ArcCW.BuffStack = false end if !ArcCW.BuffStack then ArcCW.BuffStack = true for i, e in pairs(self:GetActiveElements()) do local ele = self.AttachmentElements[e] if ele and ele[buff] != nil then local pri = ele[buff .. "_Priority"] or 1 if level == 0 or (pri > level) then current = ele[buff] level = pri winningslot = i end end end ArcCW.BuffStack = false end if self:GetTable()[buff] != nil then local pri = self:GetTable()[buff .. "_Priority"] or 1 if level == 0 or (pri > level) then current = self:GetTable()[buff] level = pri end end self.TickCache_Overrides[buff] = {current, winningslot} if VERIFY_MODIFIED_CACHE and !self.ModifiedCache[buff] and current != nil then print("ArcCW: Presumed non-changing buff '" .. buff .. "' is modified (" .. tostring(current) .. ")!") end local data = { buff = buff, current = current, winningslot = winningslot } if !ArcCW.BuffStack then ArcCW.BuffStack = true current = (self:GetBuff_Hook("O_Hook_" .. buff, data) or {}).current or current ArcCW.BuffStack = false end if current == nil then current = default end return current, winningslot end function SWEP:GetBuff_Mult(buff) local mult = 1 if MODIFIED_CACHE and !self.ModifiedCache[buff] then if !ArcCW.BuffStack then ArcCW.BuffStack = true mult = (self:GetBuff_Hook("M_Hook_" .. buff, {buff = buff, mult = 1}) or {}).mult or mult ArcCW.BuffStack = false end if ArcCW.ConVar_BuffMults[buff] then if buff == "Mult_CycleTime" then mult = mult / GetConVar(ArcCW.ConVar_BuffMults[buff]):GetFloat() else mult = mult * GetConVar(ArcCW.ConVar_BuffMults[buff]):GetFloat() end end return mult end if self.TickCache_Mults[buff] then mult = self.TickCache_Mults[buff] local data = { buff = buff, mult = mult } if !ArcCW.BuffStack then ArcCW.BuffStack = true mult = (self:GetBuff_Hook("M_Hook_" .. buff, data) or {}).mult or mult ArcCW.BuffStack = false end if ArcCW.ConVar_BuffMults[buff] then if buff == "Mult_CycleTime" then mult = mult / GetConVar(ArcCW.ConVar_BuffMults[buff]):GetFloat() else mult = mult * GetConVar(ArcCW.ConVar_BuffMults[buff]):GetFloat() end end return mult end for i, k in pairs(self.Attachments) do if !k.Installed then continue end local atttbl = ArcCW.AttachmentTable[k.Installed] if atttbl[buff] then mult = mult * atttbl[buff] end if atttbl.ToggleStats and k.ToggleNum and atttbl.ToggleStats[k.ToggleNum] and atttbl.ToggleStats[k.ToggleNum][buff] then mult = mult * atttbl.ToggleStats[k.ToggleNum][buff] end end local cfm = self:GetCurrentFiremode() if cfm and cfm[buff] then mult = mult * cfm[buff] end if self:GetTable()[buff] then mult = mult * self:GetTable()[buff] end for i, e in pairs(self:GetActiveElements()) do local ele = self.AttachmentElements[e] if ele and ele[buff] then mult = mult * ele[buff] end end self.TickCache_Mults[buff] = mult if VERIFY_MODIFIED_CACHE and !self.ModifiedCache[buff] and mult != 1 then print("ArcCW: Presumed non-changing buff '" .. buff .. "' is modified (" .. tostring(mult) .. ")!") end if ArcCW.ConVar_BuffMults[buff] then if buff == "Mult_CycleTime" then mult = mult / GetConVar(ArcCW.ConVar_BuffMults[buff]):GetFloat() else mult = mult * GetConVar(ArcCW.ConVar_BuffMults[buff]):GetFloat() end end local data = { buff = buff, mult = mult } if !ArcCW.BuffStack then ArcCW.BuffStack = true mult = (self:GetBuff_Hook("M_Hook_" .. buff, data) or {}).mult or mult ArcCW.BuffStack = false end return mult end function SWEP:GetBuff_Add(buff) local add = 0 if MODIFIED_CACHE and !self.ModifiedCache[buff] then if !ArcCW.BuffStack then ArcCW.BuffStack = true add = (self:GetBuff_Hook("A_Hook_" .. buff, {buff = buff, add = 0}) or {}).add or add ArcCW.BuffStack = false end if ArcCW.ConVar_BuffAdds[buff] then add = add + GetConVar(ArcCW.ConVar_BuffAdds[buff]):GetFloat() end return add end if self.TickCache_Adds[buff] then add = self.TickCache_Adds[buff] local data = { buff = buff, add = add } if !ArcCW.BuffStack then ArcCW.BuffStack = true add = (self:GetBuff_Hook("A_Hook_" .. buff, data) or {}).add or add ArcCW.BuffStack = false end if ArcCW.ConVar_BuffAdds[buff] then add = add + GetConVar(ArcCW.ConVar_BuffAdds[buff]):GetFloat() end return add end for i, k in pairs(self.Attachments) do if !k.Installed then continue end local atttbl = ArcCW.AttachmentTable[k.Installed] if atttbl[buff] then add = add + atttbl[buff] end if atttbl.ToggleStats and k.ToggleNum and atttbl.ToggleStats[k.ToggleNum] and atttbl.ToggleStats[k.ToggleNum][buff] then add = add + atttbl.ToggleStats[k.ToggleNum][buff] end end local cfm = self:GetCurrentFiremode() if cfm and cfm[buff] then add = add + cfm[buff] end for i, e in pairs(self:GetActiveElements()) do local ele = self.AttachmentElements[e] if ele and ele[buff] then add = add + ele[buff] end end self.TickCache_Adds[buff] = add if VERIFY_MODIFIED_CACHE and !self.ModifiedCache[buff] and add != 0 then print("ArcCW: Presumed non-changing buff '" .. buff .. "' is modified (" .. tostring(add) .. ")!") end if ArcCW.ConVar_BuffAdds[buff] then add = add + GetConVar(ArcCW.ConVar_BuffAdds[buff]):GetFloat() end local data = { buff = buff, add = add } if !ArcCW.BuffStack then ArcCW.BuffStack = true add = (self:GetBuff_Hook("A_Hook_" .. buff, data) or {}).add or add ArcCW.BuffStack = false end return add end SWEP.ActiveElementCache = nil function SWEP:GetActiveElements(recache) if self.ActiveElementCache and !recache then return self.ActiveElementCache end if ArcCW.Overflow and self.ActiveElementCache then return self.ActiveElementCache end local eles = {} for _, i in pairs(self.Attachments) do if !i.Installed then if i.DefaultEles then table.Add(eles, i.DefaultEles) end continue end if i.InstalledEles and i.Installed != i.EmptyFallback then table.Add(eles, i.InstalledEles) end local atttbl = ArcCW.AttachmentTable[i.Installed] if atttbl.ActivateElements then table.Add(eles, atttbl.ActivateElements) end local num = i.ToggleNum or 1 if atttbl.ToggleStats and atttbl.ToggleStats[num] and (atttbl.ToggleStats[num]["ActivateElements"] != nil) then table.Add(eles, atttbl.ToggleStats[num]["ActivateElements"]) --atttbl.ToggleStats[num][buff] end local slots = atttbl.Slot if isstring(slots) then slots = {slots} end table.Add(eles, slots or {}) table.insert(eles, i.Installed) end table.Add(eles, self.DefaultElements) local mode = self:GetCurrentFiremode() table.Add(eles, (mode or {}).ActivateElements or {}) local eles2 = {} ArcCW.Overflow = true for f, i in pairs(eles) do local e = self.AttachmentElements[i] if !e then continue end if !self:CheckFlags(e.ExcludeFlags, e.RequireFlags) then continue end local a = false local c = 0 for g = f, table.Count(eles) do if eles[g] == i then c = c + 1 end if a then continue end if c > 1 then a = true end end if a then continue end table.insert(eles2, i) end table.Add(eles2, self:GetWeaponFlags()) ArcCW.Overflow = false self.ActiveElementCache = eles2 return eles2 end function SWEP:GetMuzzleDevice(wm) local model = self.WM local muzz = self.WMModel or self if !wm then model = self.VM muzz = self:GetOwner():GetViewModel() end if model then for _, ele in pairs(model) do if ele.IsMuzzleDevice then muzz = ele.Model or muzz end end end if self:GetInUBGL() then local _, slot = self:GetBuff_Override("UBGL") if wm then muzz = (self.Attachments[slot].WMuzzleDeviceElement or {}).Model or muzz else muzz = (self.Attachments[slot].VMuzzleDeviceElement or {}).Model or muzz end end return muzz end function SWEP:GetTracerOrigin() local ow = self:GetOwner() local wm = nil local muzz = nil if !ow:IsNPC() and !ow:IsNextBot() and ow:IsValid() then wm = !ow:GetViewModel():IsValid() or ow:ShouldDrawLocalPlayer() muzz = self:GetMuzzleDevice(wm) end if muzz and muzz:IsValid() then local posang = muzz:GetAttachment(self:GetBuff_Override("Override_MuzzleEffectAttachment", self.MuzzleEffectAttachment) or 1) if !posang then return muzz:GetPos() end local pos = posang.Pos return pos end end function SWEP:CheckFlags(reject, need) local flags if ArcCW.Overflow then flags = self:GetWeaponFlags() else flags = self:GetActiveElements() end reject = reject or {} need = need or {} if !istable(reject) then reject = {reject} end if !istable(need) then need = {need} end for _, i in pairs(reject) do if table.HasValue(flags, i) then return false end end for _, i in pairs(need) do if !table.HasValue(flags, i) then return false end end return true end function SWEP:GetWeaponFlags() local flags = {} if self.DefaultFlags then table.Add(flags, self.DefaultFlags) end for id, i in pairs(self.Attachments) do if !i.Installed then if i.DefaultFlags then table.Add(flags, i.DefaultFlags) end continue end local buff = self:GetBuff_Stat("GivesFlags", id) if buff then table.Add(flags, buff) end if i.GivesFlags then table.Add(flags, i.GivesFlags) end local extras = {} self:GetBuff_Hook("Hook_ExtraFlags", extras) table.Add(flags, extras) table.Add(flags, {i.Installed}) end return flags end function SWEP:PlayerOwnsAtt(att) local qty = ArcCW:PlayerGetAtts(self:GetOwner(), att) return qty > 0 end function SWEP:NetworkWeapon(sendto) net.Start("arccw_networkatts") net.WriteEntity(self) -- self entity net.WriteUInt(table.Count(self.Attachments), 8) for _, i in pairs(self.Attachments) do if !i.Installed then net.WriteUInt(0, ArcCW.GetBitNecessity()) continue end local atttbl = ArcCW.AttachmentTable[i.Installed] local id = atttbl.ID net.WriteUInt(id, ArcCW.GetBitNecessity()) if i.SlideAmount then net.WriteFloat(i.SlidePos or 0.5) end if atttbl.ToggleStats then net.WriteUInt(i.ToggleNum or 1, 8) -- look if you want more than 255 fucking toggle options you're insane and stupid just don't ok end -- if atttbl.ColorOptionsTable then -- net.WriteUInt(i.ColorOptionIndex or 1, 8) -- look if you want more than 256 fucking color options you're insane and stupid and just don't ok -- end end if sendto then net.Send(sendto) else -- net.SendPVS(self:GetPos()) net.Broadcast() end end function SWEP:SendDetail_ColorIndex(slot) net.Start("arccw_colorindex") net.WriteUInt(slot, 8) net.WriteUInt(self.Attachments[slot].ColorOptionIndex) net.SendToServer() end function SWEP:SendDetail_SlidePos(slot, hmm) if !self.Attachments then return end if !self.Attachments[slot].SlidePos then return end net.Start("arccw_slidepos") net.WriteUInt(slot, 8) net.WriteFloat(self.Attachments[slot].SlidePos or 0.5) net.SendToServer() end function SWEP:SendDetail_ToggleNum(slot, hmm) if !self.Attachments or !self.Attachments[slot] then return end if !self.Attachments[slot].ToggleNum then return end net.Start("arccw_togglenum") net.WriteUInt(slot, 8) net.WriteUInt(self.Attachments[slot].ToggleNum or 1, 8) net.SendToServer() end function SWEP:SendAllDetails() for i, k in pairs(self.Attachments) do self:SendDetail_SlidePos(i, true) self:SendDetail_ToggleNum(i, true) end end function SWEP:CountAttachments() local total = 0 for _, i in pairs(self.Attachments) do if i.Installed and !i.FreeSlot then local ins = ArcCW.AttachmentTable[i.Installed] if ins and !ins.IgnorePickX then total = total + 1 end end end return total end function SWEP:SetBodygroupTr(ind, bg) self.Bodygroups[ind] = bg end function SWEP:RefreshBGs() local vm local vmm = self:GetBuff_Override("Override_VMMaterial") or self.VMMaterial or "" local wmm = self:GetBuff_Override("Override_WMMaterial") or self.WMMaterial or "" local vmc = self:GetBuff_Override("Override_VMColor") or self.VMColor or Color(255, 255, 255) local wmc = self:GetBuff_Override("Override_WMColor") or self.WMColor or Color(255, 255, 255) local vms = self:GetBuff_Override("Override_VMSkin") or self.DefaultSkin local wms = self:GetBuff_Override("Override_WMSkin") or self.DefaultWMSkin local vmp = self.DefaultPoseParams local wmp = self.DefaultWMPoseParams if self.MirrorVMWM then wmm = vmm wmc = vmc wms = vms wmp = vmp end if self:GetOwner():IsPlayer() then vm = self:GetOwner():GetViewModel() end if vm and vm:IsValid() then ArcCW.SetBodyGroups(vm, self.DefaultBodygroups) vm:SetMaterial(vmm) vm:SetColor(vmc) vm:SetSkin(vms) vmp["BaseClass"] = nil for i, k in pairs(vmp) do vm:SetPoseParameter(i, k) end end self:SetMaterial(wmm) self:SetColor(wmc) self:SetSkin(wms) if self.WMModel and self.WMModel:IsValid() then ArcCW.SetBodyGroups(self.WMModel, self.MirrorVMWM and self.DefaultBodygroups or self.DefaultWMBodygroups) self.WMModel:SetMaterial(wmm) self.WMModel:SetColor(wmc) self.WMModel:SetSkin(wms) wmp["BaseClass"] = nil for i, k in pairs(wmp) do self.WMModel:SetPoseParameter(i, k) end end local ae = self:GetActiveElements() for _, e in pairs(ae) do local ele = self.AttachmentElements[e] if !ele then continue end if ele.VMPoseParams and vm and IsValid(vm) then ele.VMPoseParams["BaseClass"] = nil for i, k in pairs(ele.VMPoseParams) do vm:SetPoseParameter(i, k) end end if self.WMModel and self.WMModel:IsValid() then if self.MirrorVMWM and ele.VMPoseParams then ele.VMPoseParams["BaseClass"] = nil for i, k in pairs(ele.VMPoseParams) do self.WMModel:SetPoseParameter(i, k) end end if ele.WMPoseParams then ele.WMPoseParams["BaseClass"] = nil for i, k in pairs(ele.WMPoseParams) do self.WMModel:SetPoseParameter(i, k) end end end if ele.VMSkin and vm and IsValid(vm) then vm:SetSkin(ele.VMSkin) end if self.WMModel and self.WMModel:IsValid() then if self.MirrorVMWM and ele.VMSkin then self.WMModel:SetSkin(ele.VMSkin) self:SetSkin(ele.VMSkin) end if ele.WMSkin then self.WMModel:SetSkin(ele.WMSkin) self:SetSkin(ele.WMSkin) end end if ele.VMColor and vm and IsValid(vm) then vm:SetColor(ele.VMColor) end if self.WMModel and self.WMModel:IsValid() then if self.MirrorVMWM and ele.VMSkin then self.WMModel:SetColor(ele.VMColor or color_white) self:SetColor(ele.VMColor or color_white) end if ele.WMSkin then self.WMModel:SetColor(ele.WMColor or color_white) self:SetColor(ele.WMColor or color_white) end end if ele.VMMaterial and vm and IsValid(vm) then vm:SetMaterial(ele.VMMaterial) end if self.WMModel and self.WMModel:IsValid() then if self.MirrorVMWM and ele.VMMaterial then self.WMModel:SetMaterial(ele.VMMaterial) self:SetMaterial(ele.VMMaterial) end if ele.WMMaterial then self.WMModel:SetMaterial(ele.WMMaterial) self:SetMaterial(ele.WMMaterial) end end if ele.VMBodygroups then for _, i in pairs(ele.VMBodygroups) do if !i.ind or !i.bg then continue end if vm and IsValid(vm) and vm:GetBodygroup(i.ind) != i.bg then vm:SetBodygroup(i.ind, i.bg) end end if self.MirrorVMWM then for _, i in pairs(ele.VMBodygroups) do if !i.ind or !i.bg then continue end if self.WMModel and IsValid(self.WMModel) and self.WMModel:GetBodygroup(i.ind) != i.bg then self.WMModel:SetBodygroup(i.ind, i.bg) end if self:GetBodygroup(i.ind) != i.bg then self:SetBodygroup(i.ind, i.bg) end end end end if ele.WMBodygroups then for _, i in pairs(ele.WMBodygroups) do if !i.ind or !i.bg then continue end if self.WMModel and IsValid(self.WMModel) and self.WMModel:GetBodygroup(i.ind) != i.bg then self.WMModel:SetBodygroup(i.ind, i.bg) end if self:GetBodygroup(i.ind) != i.bg then self:SetBodygroup(i.ind, i.bg) end end end if ele.VMBoneMods then for bone, i in pairs(ele.VMBoneMods) do local boneind = vm:LookupBone(bone) if !boneind then continue end vm:ManipulateBonePosition(boneind, i) end if self.MirrorVMWM then for bone, i in pairs(ele.VMBoneMods) do if !(self.WMModel and self.WMModel:IsValid()) then break end local boneind = self:LookupBone(bone) if !boneind then continue end self:ManipulateBonePosition(boneind, i) end end end if ele.WMBoneMods then for bone, i in pairs(ele.WMBoneMods) do if !(self.WMModel and self.WMModel:IsValid()) then break end local boneind = self:LookupBone(bone) if !boneind then continue end self:ManipulateBonePosition(boneind, i) end end if SERVER then self:SetupShields() end end local tpmdl = IsValid(self.WMModel) and self.WMModel or self if IsValid(vm) then for i = 0, (vm:GetNumBodyGroups()) do if self.Bodygroups[i] then vm:SetBodygroup(i, self.Bodygroups[i]) end end self:GetBuff_Hook("Hook_ModifyBodygroups", {vm = vm, eles = ae, wm = false}) end for i = 0, (tpmdl:GetNumBodyGroups()) do if self.Bodygroups[i] then tpmdl:SetBodygroup(i, self.Bodygroups[i]) end end self:GetBuff_Hook("Hook_ModifyBodygroups", {vm = tpmdl, eles = ae, wm = true}) for slot, v in pairs(self.Attachments) do if !v.Installed then continue end local func = self:GetBuff_Stat("Hook_ModifyAttBodygroups", slot) if func and v.VElement and IsValid(v.VElement.Model) and IsValid(vm) then func(self, {vm = vm, element = v.VElement, slottbl = v, wm = false}) end if func and v.WElement and IsValid(v.WElement.Model) then func(self, {vm = tpmdl, element = v.WElement, slottbl = v, wm = true}) end end end function SWEP:GetPickX() return ArcCW.ConVars["atts_pickx"]:GetInt() end function SWEP:Attach(slot, attname, silent, noadjust) silent = silent or false local attslot = self.Attachments[slot] if !attslot then return end if attslot.Installed == attname then return end if attslot.Internal then return end -- Make an additional check to see if we can detach the current attachment if attslot.Installed and !ArcCW:PlayerCanAttach(self:GetOwner(), self, attslot.Installed, slot, attname) then if CLIENT and !silent then surface.PlaySound("items/medshotno1.wav") end return end if !ArcCW:PlayerCanAttach(self:GetOwner(), self, attname, slot, false) then if CLIENT and !silent then surface.PlaySound("items/medshotno1.wav") end return end local pick = self:GetPickX() if pick > 0 and self:CountAttachments() >= pick and !attslot.FreeSlot and !attslot.Installed then if CLIENT and !silent then surface.PlaySound("items/medshotno1.wav") end return end local atttbl = ArcCW.AttachmentTable[attname] if !atttbl then return end if !ArcCW:SlotAcceptsAtt(attslot.Slot, self, attname) then return end if !self:CheckFlags(atttbl.ExcludeFlags, atttbl.RequireFlags) then return end if !self:PlayerOwnsAtt(attname) then return end local max = atttbl.Max if max then local amt = 0 for i, k in pairs(self.Attachments) do if k.Installed == attname then amt = amt + 1 end end if amt >= max then return end end if attslot.SlideAmount then attslot.SlidePos = 0.5 end if atttbl.MountPositionOverride then attslot.SlidePos = atttbl.MountPositionOverride end if atttbl.AdditionalSights then self.SightMagnifications = {} end if atttbl.ToggleStats then attslot.ToggleNum = 1 end attslot.ToggleLock = atttbl.ToggleLockDefault or false if CLIENT then -- we are asking to attach something self:SendAllDetails() net.Start("arccw_asktoattach") net.WriteUInt(slot, 8) net.WriteUInt(atttbl.ID, 24) net.SendToServer() if !silent then surface.PlaySound(atttbl.AttachSound or "weapons/arccw/install.wav") end else self:DetachAllMergeSlots(slot) for i, k in pairs(self.Attachments) do if table.HasValue(k.MergeSlots or {}, slot) then self:DetachAllMergeSlots(i) end end end attslot.Installed = attname if atttbl.Health then attslot.HP = self:GetAttachmentMaxHP(slot) end if atttbl.ColorOptionsTable then attslot.ColorOptionIndex = 1 end ArcCW:PlayerTakeAtt(self:GetOwner(), attname) --[[] local fmt = self:GetBuff_Override("Override_Firemodes") or self.Firemodes local fmi = self:GetFireMode() if fmi > table.Count(fmt) then self:SetFireMode(1) end ]] --self.UnReady = false if SERVER then self:NetworkWeapon() self:SetupModel(false) self:SetupModel(true) ArcCW:PlayerSendAttInv(self:GetOwner()) if engine.ActiveGamemode() == "terrortown" then self:TTT_PostAttachments() end else self:SetupActiveSights() self.LHIKAnimation = 0 self.LHIKAnimationStart = 0 self.LHIKAnimationTime = 0 self.LHIKDelta = {} self.LHIKDeltaAng = {} self.ViewModel_Hit = Vector(0, 0, 0) if !silent then self:SavePreset("autosave") end end for s, i in pairs(self.Attachments) do if !self:CheckFlags(i.ExcludeFlags, i.RequireFlags) then self:Detach(s, true, true) end end if !noadjust then self:AdjustAtts() end if atttbl.UBGL then local ubgl_ammo = self:GetBuff_Override("UBGL_Ammo") local ubgl_clip = self:GetBuff_Override("UBGL_Capacity") if self:GetOwner():IsPlayer() and ArcCW.ConVars["atts_ubglautoload"]:GetBool() and ubgl_ammo then local amt = math.min(ubgl_clip - self:Clip2(), self:GetOwner():GetAmmoCount(ubgl_ammo)) self:SetClip2(self:Clip2() + amt) self:GetOwner():RemoveAmmo(amt, ubgl_ammo) end end self:RefreshBGs() return true end function SWEP:DetachAllMergeSlots(slot, silent) local slots = {slot} table.Add(slots, (self.Attachments[slot] or {}).MergeSlots or {}) for _, i in pairs(slots) do self:Detach(i, silent, nil, true) end end function SWEP:Detach(slot, silent, noadjust, nocheck) if !slot then return end if !self.Attachments[slot] then return end if !self.Attachments[slot].Installed then return end if self.Attachments[slot].Internal then return end if !nocheck and !ArcCW:PlayerCanAttach(self:GetOwner(), self, self.Attachments[slot].Installed, slot, true) then if CLIENT and !silent then surface.PlaySound("items/medshotno1.wav") end return end if self.Attachments[slot].Installed == self.Attachments[slot].EmptyFallback then return end local previnstall = self.Attachments[slot].Installed local atttbl = ArcCW.AttachmentTable[previnstall] if atttbl.UBGL then local clip = self:Clip2() local ammo = atttbl.UBGL_Ammo or "smg1_grenade" if SERVER and IsValid(self:GetOwner()) then self:GetOwner():GiveAmmo(clip, ammo, true) end self:SetClip2(0) self:DeselectUBGL() end if self.Attachments[slot].EmptyFallback then -- is this a good name self.Attachments[slot].Installed = self.Attachments[slot].EmptyFallback else self.Attachments[slot].Installed = nil end if self.Attachments[slot].SubAtts then for i, k in pairs(self.Attachments[slot].SubAtts) do self:Detach(k, true, true) end end if self:GetAttachmentHP(slot) >= self:GetAttachmentMaxHP(slot) then ArcCW:PlayerGiveAtt(self:GetOwner(), previnstall) end if CLIENT then self:SendAllDetails() -- we are asking to detach something net.Start("arccw_asktodetach") net.WriteUInt(slot, 8) net.SendToServer() if !silent then surface.PlaySound(atttbl.DetachSound or "weapons/arccw/uninstall.wav") end self:SetupActiveSights() self.LHIKAnimation = 0 self.LHIKAnimationStart = 0 self.LHIKAnimationTime = 0 if !silent then self:SavePreset("autosave") end else self:NetworkWeapon() self:SetupModel(false) self:SetupModel(true) ArcCW:PlayerSendAttInv(self:GetOwner()) if engine.ActiveGamemode() == "terrortown" then self:TTT_PostAttachments() end end self:RefreshBGs() if !noadjust then self:AdjustAtts() end return true end function SWEP:ToggleSlot(slot, num, silent, back) local atttbl = ArcCW.AttachmentTable[self.Attachments[slot].Installed] if !atttbl.ToggleStats then return end local amt = 1 if back then amt = -1 end if !num then self.Attachments[slot].ToggleNum = (self.Attachments[slot].ToggleNum or 1) + amt if self.Attachments[slot].ToggleNum > #atttbl.ToggleStats then self.Attachments[slot].ToggleNum = 1 elseif self.Attachments[slot].ToggleNum < 1 then self.Attachments[slot].ToggleNum = #atttbl.ToggleStats end else self.Attachments[slot].ToggleNum = math.Clamp(num, 1, #catttbl.ToggleStats) end if CLIENT then self:SendDetail_ToggleNum(slot) self:SetupActiveSights() elseif SERVER then self:NetworkWeapon() self:SetupModel(false) self:SetupModel(true) end self:AdjustAtts() for s, i in pairs(self.Attachments) do if !self:CheckFlags(i.ExcludeFlags, i.RequireFlags) then self:Detach(s, true) end end self:RefreshBGs() if CLIENT and !silent and self:GetBuff_Stat("ToggleSound", slot) != false then surface.PlaySound(self:GetBuff_Stat("ToggleSound", slot) or (atttbl.ToggleStats[slot] or {}).ToggleSound or "weapons/arccw/firemode.wav") end end function SWEP:AdjustAmmo(old_inf) local new_inf = self:HasInfiniteAmmo() local wpn = weapons.Get(self:GetClass()) local ammo = self:GetBuff_Override("Override_Ammo", wpn.Primary.Ammo) local oldammo = self.OldAmmo or self.Primary.Ammo if old_inf and (!new_inf or ammo != oldammo) then self:SetClip1(0) elseif (!old_inf and new_inf) or ammo != oldammo then self:Unload() end self.Primary.Ammo = ammo self.OldAmmo = self.Primary.Ammo end function SWEP:AdjustAtts() local old_inf = self:HasInfiniteAmmo() self:RecalcAllBuffs() -- Recalculate active elements so dependencies aren't fucked self.ActiveElementCache = nil self:GetActiveElements(true) self.ModifiedCache = {} -- Tempoarily disable modified cache, since we're building it right now MODIFIED_CACHE = false for i, k in pairs(self.Attachments) do if !k.Installed then continue end local ok = true if !ArcCW:SlotAcceptsAtt(k.Slot, self, k.Installed) then ok = false end if ok and !self:CheckFlags(k.ExcludeFlags, k.RequireFlags) then ok = false end local atttbl = ArcCW.AttachmentTable[k.Installed] if !atttbl then continue end if ok and !self:CheckFlags(atttbl.ExcludeFlags, atttbl.RequireFlags) then ok = false end if !ok then self:Detach(i, true) continue end -- Cache all possible value modifiers for var, v in pairs(atttbl) do self.ModifiedCache[var] = true if var == "ToggleStats" or var == "Override_Firemodes" then for _, v2 in pairs(v) do for var2, _ in pairs(v2) do self.ModifiedCache[var2] = true end end end end end for _, e in pairs(self.AttachmentElements) do if !istable(e) then continue end for var, v in pairs(e) do self.ModifiedCache[var] = true end end for _, e in pairs(self.Firemodes) do if !istable(e) then continue end for var, v in pairs(e) do self.ModifiedCache[var] = true end end MODIFIED_CACHE = true if SERVER then local cs = self:GetCapacity() + self:GetChamberSize() if self:Clip1() > cs and self:Clip1() != ArcCW.BottomlessMagicNumber then local diff = self:Clip1() - cs self:SetClip1(cs) if self:GetOwner():IsValid() and !self:GetOwner():IsNPC() then self:GetOwner():GiveAmmo(diff, self.Primary.Ammo, true) end end else local se = self:GetBuff_Override("Override_ShootEntity") or self.ShootEntity if se then local path = "arccw/weaponicons/" .. self:GetClass() local mat = Material(path) if !mat:IsError() then local tex = mat:GetTexture("$basetexture") local texpath = tex:GetName() killicon.Add(se, texpath, Color(255, 255, 255)) end end end local ubgl_ammo = self:GetBuff_Override("UBGL_Ammo") local ubgl_clip = self:GetBuff_Override("UBGL_Capacity") self.Secondary.ClipSize = ubgl_clip or -1 self.Secondary.Ammo = ubgl_ammo or "none" --[[] if ubgl_clip then self.Secondary.ClipSize = ubgl_clip if self:GetOwner():IsPlayer() and ArcCW.ConVars["atts_ubglautoload"]:GetBool() and ubgl_ammo then local amt = math.min(ubgl_clip - self:Clip2(), self:GetOwner():GetAmmoCount(ubgl_ammo)) self:SetClip2(self:Clip2() + amt) self:GetOwner():RemoveAmmo(amt, ubgl_ammo) end else self.Secondary.ClipSize = -1 end ]] self:RebuildSubSlots() local fmt = self:GetBuff_Override("Override_Firemodes", self.Firemodes) fmt["BaseClass"] = nil local fmi = self:GetFireMode() if !fmt[fmi] then self:SetFireMode(1) end self:AdjustAmmo(old_inf) end function SWEP:GetAttachmentMaxHP(slot) if !self.Attachments[slot] then return 100 end if !self.Attachments[slot].Installed then return 100 end local maxhp = 100 local atttbl = ArcCW.AttachmentTable[self.Attachments[slot].Installed] if atttbl.Health then maxhp = atttbl.Health end return maxhp end function SWEP:GetAttachmentHP(slot) if !self.Attachments[slot] then return 100 end if !self.Attachments[slot].Installed then return 100 end if self.Attachments[slot].HP then return self.Attachments[slot].HP end self.Attachments[slot].HP = self:GetAttachmentMaxHP(slot) return self.Attachments[slot].HP end function SWEP:ApplyAttachmentShootDamage() local any = false for j, i in pairs(self.Attachments) do if !i.Installed then continue end local atttbl = ArcCW.AttachmentTable[i.Installed] if !atttbl.Health then continue end if atttbl.DamageOnShoot then self:DamageAttachment(j, atttbl.DamageOnShoot) any = true end end if any then self:SendAttHP() end end function SWEP:DamageAttachment(slot, dmg) if !self.Attachments[slot] then return end if !self.Attachments[slot].Installed then return end self.Attachments[slot].HP = self:GetAttachmentHP(slot) - dmg if self:GetAttachmentHP(slot) <= 0 then local atttbl = ArcCW.AttachmentTable[self.Attachments[slot].Installed] if atttbl.Hook_AttDestroyed then atttbl.Hook_AttDestroyed(self, {slot = slot, dmg = dmg}) end self:Detach(slot, true) end end function SWEP:SendAttHP() net.Start("arccw_sendatthp") for i, k in pairs(self.Attachments) do if !k.Installed then continue end local atttbl = ArcCW.AttachmentTable[k.Installed] if atttbl.Health then net.WriteBool(true) net.WriteUInt(i, 8) net.WriteFloat(self:GetAttachmentHP(i)) end end net.WriteBool(false) net.Send(self:GetOwner()) end -- local node = {b = {}, i = "" t = 0} -- b: branches -- i: installed -- t: toggle -- s: slide -- h: hp -- recursive function -- gets a tree of all the attachments installed in subslots subordinate to a particular slot function SWEP:GetSubSlotTree(i) if !self.Attachments[i] then return nil end if !self.Attachments[i].Installed then return nil end if !self.Attachments[i].SubAtts then return { b = {}, i = self.Attachments[i].Installed, t = self.Attachments[i].ToggleNum, s = self.Attachments[i].SlidePos, h = self.Attachments[i].Health} end local ss = {} for j, k in pairs(self.Attachments[i].SubAtts) do if k == i then continue end local sst = self:GetSubSlotTree(k) if sst then ss[j] = sst end end return {b = ss, i = self.Attachments[i].Installed} end function SWEP:SubSlotTreeReinstall(slot, subslottree) for i, k in pairs(self.Attachments[slot].SubAtts or {}) do -- i = index -- k = slot self.Attachments[k].Installed = subslottree[i].i self.Attachments[k].ToggleNum = subslottree[i].t self.Attachments[k].SlidePos = subslottree[i].s self.Attachments[k].Health = subslottree[i].h if subslottree.b[i] then self:SubSlotTreeReinstall(i, subslottree.b[i]) end end end function SWEP:RebuildSubSlots() -- this function rebuilds the subslots while preserving installed attachment data local subslottrees = {} local baseatts = table.Count(weapons.Get(self:GetClass()).Attachments) self.Attachments.BaseClass = nil for i = 1, baseatts do subslottrees[baseatts] = self:GetSubSlotTree(i) end -- remove all sub slots for i, k in pairs(self.Attachments) do if !isnumber(i) then continue end if !istable(k) then continue end if i > baseatts then self.Attachments[i] = nil else self.Attachments[i].SubAtts = nil end end self.SubSlotCount = 0 -- add the sub slots back for i, k in pairs(self.Attachments) do if !k.Installed then continue end local att = ArcCW.AttachmentTable[k.Installed] if !att then continue end if !istable(k) then continue end if att.SubSlots then self:AddSubSlot(i, k.Installed) end end -- add the sub slot data back for i, k in pairs(subslottrees) do self:SubSlotTreeReinstall(i, k) end end function SWEP:AddSubSlot(i, attname) local baseatts = table.Count(weapons.Get(self:GetClass()).Attachments) local att = ArcCW.AttachmentTable[attname] if att.SubSlots then self.Attachments[i].SubAtts = {} local og_slot = self.Attachments[i] for ind, slot in pairs(att.SubSlots) do if !istable(slot) then continue end self.SubSlotCount = self.SubSlotCount + 1 local index = baseatts + self.SubSlotCount self.Attachments[index] = slot self.Attachments[index].Bone = og_slot.Bone self.Attachments[index].WMBone = og_slot.WMBone self.Attachments[index].ExtraSightDist = 0--self.Attachments[index].ExtraSightDist or og_slot.ExtraSightDist self.Attachments[index].CorrectivePos = og_slot.CorrectivePos self.Attachments[index].CorrectiveAng = og_slot.CorrectiveAng og_slot.SubAtts[ind] = index if slot.MergeSlots then self.Attachments[index].MergeSlots = {} for _, k2 in pairs(slot.MergeSlots) do table.insert(self.Attachments[index].MergeSlots, k2 + index) end end if slot.Offset then self.Attachments[index].Offset = { vpos = Vector(0, 0, 0), vang = Angle(0, 0, 0), wpos = Vector(0, 0, 0), wang = Angle(0, 0, 0) } if slot.Offset.vang then self.Attachments[index].Offset.vang = slot.Offset.vang + (og_slot.Offset.vang or Angle(0, 0, 0)) end if slot.Offset.wang then self.Attachments[index].Offset.wang = slot.Offset.wang + (og_slot.Offset.wang or Angle(0, 0, 0)) end if slot.Offset.vpos then self.Attachments[index].Offset.vpos = LocalToWorld(slot.Offset.vpos, self.Attachments[index].Offset.vang, og_slot.Offset.vpos, og_slot.Offset.vang or Angle(0, 0, 0)) end if slot.Offset.wpos then self.Attachments[index].Offset.wpos = LocalToWorld(slot.Offset.wpos, self.Attachments[index].Offset.wang, og_slot.Offset.wpos, og_slot.Offset.wang or Angle(0, 0, 0)) end end self.Attachments[index].SubAtts = {} end end end function SWEP:OnReloaded() self:RecalcAllBuffs() self:SetupActiveSights() end