mirror of
https://github.com/lifestorm/wnsrc.git
synced 2025-12-17 13:53:45 +03:00
Upload
This commit is contained in:
181
lua/weapons/tfa_gun_base/common/ai_translations.lua
Normal file
181
lua/weapons/tfa_gun_base/common/ai_translations.lua
Normal file
@@ -0,0 +1,181 @@
|
||||
--[[
|
||||
| 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 HoldTypeTable = {
|
||||
["melee"] = {
|
||||
[ACT_IDLE] = ACT_IDLE_MELEE,
|
||||
[ACT_IDLE_ANGRY] = ACT_IDLE_MELEE,
|
||||
[ACT_IDLE_RELAXED] = ACT_IDLE_MELEE,
|
||||
[ACT_IDLE_STIMULATED] = ACT_IDLE_MELEE,
|
||||
[ACT_IDLE_AGITATED] = ACT_IDLE_MELEE,
|
||||
[ACT_IDLE_AIM_RELAXED] = ACT_IDLE_MELEE,
|
||||
[ACT_IDLE_AIM_STIMULATED] = ACT_IDLE_MELEE,
|
||||
[ACT_IDLE_AIM_AGITATED] = ACT_IDLE_MELEE,
|
||||
[ACT_RANGE_ATTACK1] = ACT_RANGE_ATTACK_THROW,
|
||||
[ACT_RANGE_ATTACK1_LOW] = ACT_MELEE_ATTACK_SWING,
|
||||
[ACT_MELEE_ATTACK1] = ACT_MELEE_ATTACK_SWING,
|
||||
[ACT_MELEE_ATTACK2] = ACT_MELEE_ATTACK_SWING,
|
||||
[ACT_SPECIAL_ATTACK1] = ACT_RANGE_ATTACK_THROW,
|
||||
[ACT_RANGE_AIM_LOW] = ACT_IDLE_MELEE,
|
||||
[ACT_COVER_LOW] = ACT_IDLE_MELEE,
|
||||
[ACT_WALK] = ACT_WALK_SUITCASE,
|
||||
[ACT_WALK_RELAXED] = ACT_WALK_SUITCASE,
|
||||
[ACT_WALK_STIMULATED] = ACT_WALK_SUITCASE,
|
||||
[ACT_WALK_AGITATED] = ACT_WALK_SUITCASE,
|
||||
[ACT_RUN_CROUCH] = ACT_RUN_CROUCH,
|
||||
[ACT_RUN_CROUCH_AIM] = ACT_RUN_CROUCH,
|
||||
[ACT_RUN] = ACT_RUN,
|
||||
[ACT_RUN_AIM_RELAXED] = ACT_RUN,
|
||||
[ACT_RUN_AIM_STIMULATED] = ACT_RUN,
|
||||
[ACT_RUN_AIM_AGITATED] = ACT_RUN,
|
||||
[ACT_RUN_AIM] = ACT_RUN,
|
||||
[ACT_SMALL_FLINCH] = ACT_RANGE_ATTACK_PISTOL,
|
||||
[ACT_BIG_FLINCH] = ACT_RANGE_ATTACK_PISTOL
|
||||
},
|
||||
["melee2"] = {
|
||||
[ACT_IDLE] = ACT_IDLE_ANGRY_MELEE,
|
||||
[ACT_IDLE_ANGRY] = ACT_IDLE_ANGRY_MELEE,
|
||||
[ACT_IDLE_RELAXED] = ACT_IDLE,
|
||||
[ACT_IDLE_STIMULATED] = ACT_IDLE,
|
||||
[ACT_IDLE_AGITATED] = ACT_IDLE_ANGRY_MELEE,
|
||||
[ACT_MP_RUN] = ACT_HL2MP_RUN_SUITCASE,
|
||||
[ACT_RUN] = ACT_RUN,
|
||||
[ACT_RUN_AIM_RELAXED] = ACT_RUN,
|
||||
[ACT_RUN_AIM_STIMULATED] = ACT_RUN,
|
||||
[ACT_RUN_AIM_AGITATED] = ACT_RUN,
|
||||
[ACT_RUN_AIM] = ACT_RUN,
|
||||
[ACT_WALK] = ACT_WALK_SUITCASE,
|
||||
[ACT_MELEE_ATTACK1] = ACT_MELEE_ATTACK_SWING,
|
||||
[ACT_RANGE_ATTACK1] = ACT_MELEE_ATTACK_SWING,
|
||||
[ACT_MELEE_ATTACK2] = ACT_MELEE_ATTACK_SWING,
|
||||
[ACT_RANGE_ATTACK2] = ACT_MELEE_ATTACK_SWING,
|
||||
[ACT_SPECIAL_ATTACK1] = ACT_RANGE_ATTACK_THROW,
|
||||
[ACT_SMALL_FLINCH] = ACT_RANGE_ATTACK_PISTOL,
|
||||
[ACT_BIG_FLINCH] = ACT_RANGE_ATTACK_PISTOL
|
||||
},
|
||||
["pistol"] = {
|
||||
[ACT_IDLE] = ACT_IDLE_PISTOL,
|
||||
[ACT_IDLE_ANGRY] = ACT_IDLE_ANGRY_PISTOL,
|
||||
[ACT_IDLE_AGITATED] = ACT_IDLE_ANGRY_PISTOL,
|
||||
[ACT_RANGE_ATTACK1] = ACT_RANGE_ATTACK_PISTOL,
|
||||
[ACT_RELOAD] = ACT_RELOAD_PISTOL,
|
||||
[ACT_WALK] = ACT_WALK_PISTOL,
|
||||
[ACT_WALK_AIM] = ACT_WALK_AIM_PISTOL,
|
||||
[ACT_RUN] = ACT_RUN_PISTOL,
|
||||
[ACT_RUN_AIM] = ACT_RUN_AIM_PISTOL,
|
||||
[ACT_RANGE_ATTACK1] = ACT_RANGE_ATTACK_PISTOL,
|
||||
[ACT_GESTURE_RANGE_ATTACK1] = ACT_GESTURE_RANGE_ATTACK_PISTOL,
|
||||
[ACT_RELOAD_LOW] = ACT_RELOAD_PISTOL_LOW,
|
||||
[ACT_RANGE_ATTACK1_LOW] = ACT_RANGE_ATTACK_PISTOL_LOW,
|
||||
[ACT_COVER_LOW] = ACT_COVER_PISTOL_LOW,
|
||||
[ACT_RANGE_AIM_LOW] = ACT_RANGE_AIM_PISTOL_LOW,
|
||||
[ACT_GESTURE_RELOAD] = ACT_GESTURE_RELOAD_PISTOL
|
||||
},
|
||||
["ar2"] = {
|
||||
[ACT_RANGE_ATTACK1] = ACT_RANGE_ATTACK_AR2,
|
||||
[ACT_RELOAD] = ACT_RELOAD_SMG1,
|
||||
[ACT_IDLE] = ACT_IDLE_SMG1,
|
||||
[ACT_IDLE_ANGRY] = ACT_IDLE_ANGRY_SMG1,
|
||||
[ACT_WALK] = ACT_WALK_RIFLE,
|
||||
[ACT_IDLE_RELAXED] = ACT_IDLE_SMG1_RELAXED,
|
||||
[ACT_IDLE_STIMULATED] = ACT_IDLE_SMG1_STIMULATED,
|
||||
[ACT_IDLE_AGITATED] = ACT_IDLE_ANGRY_SMG1,
|
||||
[ACT_WALK_RELAXED] = ACT_WALK_RIFLE_RELAXED,
|
||||
[ACT_WALK_STIMULATED] = ACT_WALK_RIFLE_STIMULATED,
|
||||
[ACT_WALK_AGITATED] = ACT_WALK_AIM_RIFLE,
|
||||
[ACT_RUN_RELAXED] = ACT_RUN_RIFLE_RELAXED,
|
||||
[ACT_RUN_STIMULATED] = ACT_RUN_RIFLE_STIMULATED,
|
||||
[ACT_RUN_AGITATED] = ACT_RUN_AIM_RIFLE,
|
||||
[ACT_IDLE_AIM_RELAXED] = ACT_IDLE_SMG1_RELAXED,
|
||||
[ACT_IDLE_AIM_STIMULATED] = ACT_IDLE_AIM_RIFLE_STIMULATED,
|
||||
[ACT_IDLE_AIM_AGITATED] = ACT_IDLE_ANGRY_SMG1,
|
||||
[ACT_WALK_AIM_RELAXED] = ACT_WALK_RIFLE_RELAXED,
|
||||
[ACT_WALK_AIM_STIMULATED] = ACT_WALK_AIM_RIFLE_STIMULATED,
|
||||
[ACT_WALK_AIM_AGITATED] = ACT_WALK_AIM_RIFLE,
|
||||
[ACT_RUN_AIM_RELAXED] = ACT_RUN_RIFLE_RELAXED,
|
||||
[ACT_RUN_AIM_STIMULATED] = ACT_RUN_AIM_RIFLE_STIMULATED,
|
||||
[ACT_RUN_AIM_AGITATED] = ACT_RUN_AIM_RIFLE,
|
||||
[ACT_WALK_AIM] = ACT_WALK_AIM_RIFLE,
|
||||
[ACT_WALK_CROUCH] = ACT_WALK_CROUCH_RIFLE,
|
||||
[ACT_WALK_CROUCH_AIM] = ACT_WALK_CROUCH_AIM_RIFLE,
|
||||
[ACT_RUN] = ACT_RUN_RIFLE,
|
||||
[ACT_RUN_AIM] = ACT_RUN_AIM_RIFLE,
|
||||
[ACT_RUN_CROUCH] = ACT_RUN_CROUCH_RIFLE,
|
||||
[ACT_RUN_CROUCH_AIM] = ACT_RUN_CROUCH_AIM_RIFLE,
|
||||
[ACT_GESTURE_RANGE_ATTACK1] = ACT_GESTURE_RANGE_ATTACK_AR2,
|
||||
[ACT_COVER_LOW] = ACT_COVER_SMG1_LOW,
|
||||
[ACT_RANGE_AIM_LOW] = ACT_RANGE_AIM_AR2_LOW,
|
||||
[ACT_RANGE_ATTACK1_LOW] = ACT_RANGE_ATTACK_SMG1_LOW,
|
||||
[ACT_RELOAD_LOW] = ACT_RELOAD_SMG1_LOW,
|
||||
[ACT_GESTURE_RELOAD] = ACT_GESTURE_RELOAD_SMG1
|
||||
},
|
||||
["smg"] = {
|
||||
[ACT_IDLE] = ACT_IDLE_SMG1,
|
||||
[ACT_IDLE_ANGRY] = ACT_IDLE_ANGRY_SMG1,
|
||||
[ACT_RANGE_ATTACK1] = ACT_RANGE_ATTACK_SMG1,
|
||||
[ACT_RELOAD] = ACT_RELOAD_SMG1,
|
||||
[ACT_WALK_AIM] = ACT_WALK_AIM_RIFLE,
|
||||
[ACT_RUN_AIM] = ACT_RUN_AIM_RIFLE,
|
||||
[ACT_GESTURE_RANGE_ATTACK1] = ACT_GESTURE_RANGE_ATTACK_SMG1,
|
||||
[ACT_RELOAD_LOW] = ACT_RELOAD_SMG1_LOW,
|
||||
[ACT_RANGE_ATTACK1_LOW] = ACT_RANGE_ATTACK_SMG1_LOW,
|
||||
[ACT_COVER_LOW] = ACT_COVER_SMG1_LOW,
|
||||
[ACT_RANGE_AIM_LOW] = ACT_RANGE_AIM_SMG1_LOW,
|
||||
[ACT_GESTURE_RELOAD] = ACT_GESTURE_RELOAD_SMG1
|
||||
}
|
||||
}
|
||||
|
||||
function SWEP:SetupWeaponHoldTypeForAI(t)
|
||||
local usedT = HoldTypeTable[t or "ar2"] or HoldTypeTable["ar2"]
|
||||
self.ActivityTranslateAI = table.Copy(usedT)
|
||||
end
|
||||
|
||||
function SWEP:TranslateActivity(act)
|
||||
if (self:GetOwner():IsNPC()) then
|
||||
if (self.ActivityTranslateAI[act]) then return self.ActivityTranslateAI[act] end
|
||||
|
||||
return -1
|
||||
end
|
||||
|
||||
if (self.ActivityTranslate[act] ~= nil) then return self.ActivityTranslate[act] end
|
||||
|
||||
return -1
|
||||
end
|
||||
|
||||
function SWEP:GetCapabilities()
|
||||
local ht = self.DefaultHoldType or self.HoldType or "pistol"
|
||||
|
||||
if ht == "melee" or ht == "melee2" or ht == "knife" or self.IsKnife then
|
||||
return CAP_WEAPON_MELEE_ATTACK1
|
||||
else
|
||||
return bit.bor(CAP_WEAPON_RANGE_ATTACK1, CAP_INNATE_RANGE_ATTACK1)
|
||||
end
|
||||
end
|
||||
59
lua/weapons/tfa_gun_base/common/akimbo.lua
Normal file
59
lua/weapons/tfa_gun_base/common/akimbo.lua
Normal file
@@ -0,0 +1,59 @@
|
||||
--[[
|
||||
| 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.
|
||||
|
||||
SWEP.AnimCycle = SWEP.ViewModelFlip and 0 or 1
|
||||
|
||||
function SWEP:FixAkimbo()
|
||||
if not self:GetStatL("IsAkimbo") or self.Secondary_TFA.ClipSize <= 0 then return end
|
||||
|
||||
self.Primary_TFA.ClipSize = self.Primary_TFA.ClipSize + self.Secondary_TFA.ClipSize
|
||||
self.Secondary_TFA.ClipSize = -1
|
||||
self.Primary_TFA.RPM = self.Primary_TFA.RPM * 2
|
||||
self.Akimbo_Inverted = self.ViewModelFlip
|
||||
self.AnimCycle = self.ViewModelFlip and 0 or 1
|
||||
self:SetAnimCycle(self.AnimCycle)
|
||||
self:ClearStatCache()
|
||||
|
||||
timer.Simple(FrameTime(), function()
|
||||
timer.Simple(0.01, function()
|
||||
if IsValid(self) and self:OwnerIsValid() then
|
||||
self:SetClip1(self.Primary_TFA.ClipSize)
|
||||
end
|
||||
end)
|
||||
end)
|
||||
end
|
||||
|
||||
function SWEP:ToggleAkimbo(arg1)
|
||||
if self:GetStatL("IsAkimbo") then
|
||||
self:SetAnimCycle(1 - self:GetAnimCycle())
|
||||
self.AnimCycle = self:GetAnimCycle()
|
||||
end
|
||||
end
|
||||
1370
lua/weapons/tfa_gun_base/common/anims.lua
Normal file
1370
lua/weapons/tfa_gun_base/common/anims.lua
Normal file
File diff suppressed because it is too large
Load Diff
727
lua/weapons/tfa_gun_base/common/attachments.lua
Normal file
727
lua/weapons/tfa_gun_base/common/attachments.lua
Normal 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
|
||||
797
lua/weapons/tfa_gun_base/common/autodetection.lua
Normal file
797
lua/weapons/tfa_gun_base/common/autodetection.lua
Normal file
@@ -0,0 +1,797 @@
|
||||
--[[
|
||||
| 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.
|
||||
|
||||
function SWEP:FixSprintAnimBob()
|
||||
local self2 = self:GetTable()
|
||||
|
||||
if self:GetStatRawL("Sprint_Mode") == TFA.Enum.LOCOMOTION_ANI then
|
||||
self:SetStatRawL("SprintBobMult", 0)
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:FixWalkAnimBob()
|
||||
local self2 = self:GetTable()
|
||||
if self:GetStatRawL("Walk_Mode") == TFA.Enum.LOCOMOTION_ANI then
|
||||
self:SetStatRawL("WalkBobMult_Iron", self:GetStatRawL("WalkBobMult"))
|
||||
self:SetStatRawL("WalkBobMult", 0)
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:PatchAmmoTypeAccessors()
|
||||
local self2 = self:GetTable()
|
||||
self:SetStatRawL("GetPrimaryAmmoTypeOld", self:GetStatRawL("GetPrimaryAmmoTypeOld") or self:GetStatRawL("GetPrimaryAmmoType"))
|
||||
self:SetStatRawL("GetPrimaryAmmoType", function(myself, ...) return myself.GetPrimaryAmmoTypeC(myself, ...) end)
|
||||
self:SetStatRawL("GetSecondaryAmmoTypeOld", self:GetStatRawL("GetSecondaryAmmoTypeOld") or self:GetStatRawL("GetSecondaryAmmoType"))
|
||||
self:SetStatRawL("GetSecondaryAmmoType", function(myself, ...) return myself.GetSecondaryAmmoTypeC(myself, ...) end)
|
||||
end
|
||||
|
||||
function SWEP:FixProjectile()
|
||||
local self2 = self:GetTable()
|
||||
if self:GetStatRawL("ProjectileEntity") and self:GetStatRawL("ProjectileEntity") ~= "" then
|
||||
self:SetStatRawL("Primary.Projectile", self:GetStatRawL("ProjectileEntity"))
|
||||
self:SetStatRawL("ProjectileEntity", nil)
|
||||
end
|
||||
|
||||
if self:GetStatRawL("ProjectileModel") and self:GetStatRawL("ProjectileModel") ~= "" then
|
||||
self:SetStatRawL("Primary.ProjectileModel", self:GetStatRawL("ProjectileModel"))
|
||||
self:SetStatRawL("ProjectileModel", nil)
|
||||
end
|
||||
|
||||
if self:GetStatRawL("ProjectileVelocity") and self:GetStatRawL("ProjectileVelocity") ~= "" then
|
||||
self:SetStatRawL("Primary.ProjectileVelocity", self:GetStatRawL("ProjectileVelocity"))
|
||||
self:SetStatRawL("ProjectileVelocity", nil)
|
||||
end
|
||||
end
|
||||
|
||||
local sv_tfa_range_modifier = GetConVar("sv_tfa_range_modifier")
|
||||
|
||||
function SWEP:AutoDetectRange()
|
||||
local self2 = self:GetTable()
|
||||
|
||||
if self:GetStatL("Primary.FalloffMetricBased") and not self:GetStatRawL("Primary.RangeFalloffLUT") then
|
||||
self:SetStatRawL("Primary.RangeFalloffLUT_IsConverted", true)
|
||||
|
||||
self:SetStatRawL("Primary.RangeFalloffLUT", {
|
||||
bezier = false,
|
||||
range_func = "linear", -- function to spline range
|
||||
units = "meters",
|
||||
lut = {
|
||||
{range = self:GetStatL("Primary.MinRangeStartFalloff"), damage = 1},
|
||||
{range = self:GetStatL("Primary.MinRangeStartFalloff") + self:GetStatL("Primary.MaxFalloff") / self:GetStatL("Primary.FalloffByMeter"),
|
||||
damage = (self:GetStatL("Primary.Damage") - self:GetStatL("Primary.MaxFalloff")) / self:GetStatL("Primary.Damage")},
|
||||
}
|
||||
})
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
if self:GetStatL("Primary.FalloffMetricBased") or self:GetStatL("Primary.RangeFalloffLUT") then return end
|
||||
|
||||
if self:GetStatL("Primary.Range") <= 0 then
|
||||
self:SetStatRawL("Primary.Range", math.sqrt(self:GetStatL("Primary.Damage") / 32) * self:MetersToUnits(350) * self:AmmoRangeMultiplier())
|
||||
end
|
||||
|
||||
if self:GetStatL("Primary.RangeFalloff") <= 0 then
|
||||
self:SetStatRawL("Primary.RangeFalloff", 0.5)
|
||||
end
|
||||
|
||||
self:SetStatRawL("Primary.RangeFalloffLUT_IsConverted", true)
|
||||
|
||||
self:SetStatRawL("Primary.RangeFalloffLUT", {
|
||||
bezier = false,
|
||||
range_func = "linear", -- function to spline range
|
||||
units = "hammer",
|
||||
lut = {
|
||||
{range = self:GetStatL("Primary.Range") * self:GetStatL("Primary.RangeFalloff"), damage = 1},
|
||||
{range = self:GetStatL("Primary.Range"), damage = 1 - sv_tfa_range_modifier:GetFloat()},
|
||||
}
|
||||
})
|
||||
end
|
||||
|
||||
function SWEP:FixProceduralReload()
|
||||
-- do nothing
|
||||
end
|
||||
|
||||
function SWEP:FixRPM()
|
||||
local self2 = self:GetTable()
|
||||
if not self:GetStatRawL("Primary.RPM") then
|
||||
if self:GetStatRawL("Primary.Delay") then
|
||||
self:SetStatRawL("Primary.RPM", 60 / self:GetStatRawL("Primary.Delay"))
|
||||
else
|
||||
self:SetStatRawL("Primary.RPM", 120)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:FixCone()
|
||||
local self2 = self:GetTable()
|
||||
if self:GetStatRawL("Primary.Cone") then
|
||||
if (not self:GetStatRawL("Primary.Spread")) or self:GetStatRawL("Primary.Spread") < 0 then
|
||||
self:SetStatRawL("Primary.Spread", self:GetStatRawL("Primary.Cone"))
|
||||
end
|
||||
|
||||
self:SetStatRawL("Primary.Cone", nil)
|
||||
end
|
||||
end
|
||||
|
||||
--legacy compatibility
|
||||
function SWEP:FixIdles()
|
||||
local self2 = self:GetTable()
|
||||
if self:GetStatRawL("DisableIdleAnimations") ~= nil and self:GetStatRawL("DisableIdleAnimations") == true then
|
||||
self:SetStatRawL("Idle_Mode", TFA.Enum.IDLE_LUA)
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:FixIS()
|
||||
local self2 = self:GetTable()
|
||||
if self:GetStatRawL("SightsPos") and (not self:GetStatRawL("IronSightsPosition") or (self:GetStatRawL("IronSightsPosition").x ~= self:GetStatRawL("SightsPos").x and self:GetStatRawL("SightsPos").x ~= 0)) then
|
||||
self:SetStatRawL("IronSightsPosition", self:GetStatRawL("SightsPos") or Vector())
|
||||
self:SetStatRawL("IronSightsAngle", self:GetStatRawL("SightsAng") or Vector())
|
||||
end
|
||||
end
|
||||
|
||||
local legacy_spread_cv = GetConVar("sv_tfa_spread_legacy")
|
||||
|
||||
function SWEP:AutoDetectSpread()
|
||||
local self2 = self:GetTable()
|
||||
if legacy_spread_cv and legacy_spread_cv:GetBool() then
|
||||
self:SetUpSpreadLegacy()
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
if self:GetStatRawL("Primary.SpreadMultiplierMax") == -1 or not self:GetStatRawL("Primary.SpreadMultiplierMax") then
|
||||
self:SetStatRawL("Primary.SpreadMultiplierMax", math.Clamp(math.sqrt(math.sqrt(self:GetStatRawL("Primary.Damage") / 35) * 10 / 5) * 5, 0.01 / self:GetStatRawL("Primary.Spread"), 0.1 / self:GetStatRawL("Primary.Spread")))
|
||||
end
|
||||
|
||||
if self:GetStatRawL("Primary.SpreadIncrement") == -1 or not self:GetStatRawL("Primary.SpreadIncrement") then
|
||||
self:SetStatRawL("Primary.SpreadIncrement", self:GetStatRawL("Primary.SpreadMultiplierMax") * 60 / self:GetStatRawL("Primary.RPM") * 0.85 * 1.5)
|
||||
end
|
||||
|
||||
if self:GetStatRawL("Primary.SpreadRecovery") == -1 or not self:GetStatRawL("Primary.SpreadRecovery") then
|
||||
self:SetStatRawL("Primary.SpreadRecovery", math.max(self:GetStatRawL("Primary.SpreadMultiplierMax") * math.pow(self:GetStatRawL("Primary.RPM") / 600, 1 / 3) * 0.75, self:GetStatRawL("Primary.SpreadMultiplierMax") / 1.5))
|
||||
end
|
||||
end
|
||||
|
||||
--[[
|
||||
Function Name: AutoDetectMuzzle
|
||||
Syntax: self:AutoDetectMuzzle(). Call only once, or it's redundant.
|
||||
Returns: Nothing.
|
||||
Notes: Detects the proper muzzle flash effect if you haven't specified one.
|
||||
Purpose: Autodetection
|
||||
]]
|
||||
--
|
||||
function SWEP:AutoDetectMuzzle()
|
||||
local self2 = self:GetTable()
|
||||
if not self:GetStatRawL("MuzzleFlashEffect") then
|
||||
local a = string.lower(self:GetStatRawL("Primary.Ammo"))
|
||||
local cat = string.lower(self:GetStatRawL("Category") and self:GetStatRawL("Category") or "")
|
||||
|
||||
if self:GetStatRawL("Silenced") or self:GetSilenced() then
|
||||
self:SetStatRawL("MuzzleFlashEffect", "tfa_muzzleflash_silenced")
|
||||
elseif string.find(a, "357") or self:GetStatRawL("Revolver") or string.find(cat, "revolver") then
|
||||
self:SetStatRawL("MuzzleFlashEffect", "tfa_muzzleflash_revolver")
|
||||
elseif self:GetStatL("LoopedReload") or a == "buckshot" or a == "slam" or a == "airboatgun" or string.find(cat, "shotgun") then
|
||||
self:SetStatRawL("MuzzleFlashEffect", "tfa_muzzleflash_shotgun")
|
||||
elseif string.find(a, "smg") or string.find(cat, "smg") or string.find(cat, "submachine") or string.find(cat, "sub-machine") then
|
||||
self:SetStatRawL("MuzzleFlashEffect", "tfa_muzzleflash_smg")
|
||||
elseif string.find(a, "sniper") or string.find(cat, "sniper") then
|
||||
self:SetStatRawL("MuzzleFlashEffect", "tfa_muzzleflash_sniper")
|
||||
elseif string.find(a, "pistol") or string.find(cat, "pistol") then
|
||||
self:SetStatRawL("MuzzleFlashEffect", "tfa_muzzleflash_pistol")
|
||||
elseif string.find(a, "ar2") or string.find(a, "rifle") or (string.find(cat, "revolver") and not string.find(cat, "rifle")) then
|
||||
self:SetStatRawL("MuzzleFlashEffect", "tfa_muzzleflash_rifle")
|
||||
else
|
||||
self:SetStatRawL("MuzzleFlashEffect", "tfa_muzzleflash_generic")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--[[
|
||||
Function Name: AutoDetectDamage
|
||||
Syntax: self:AutoDetectDamage(). Call only once. Hopefully you call this only once on like SWEP:Initialize() or something.
|
||||
Returns: Nothing.
|
||||
Notes: Fixes the damage for GDCW.
|
||||
Purpose: Autodetection
|
||||
]]
|
||||
--
|
||||
function SWEP:AutoDetectDamage()
|
||||
local self2 = self:GetTable()
|
||||
if self:GetStatRawL("Primary.Damage") and self:GetStatRawL("Primary.Damage") ~= -1 then return end
|
||||
|
||||
if self:GetStatRawL("Primary.Round") then
|
||||
local rnd = string.lower(self:GetStatRawL("Primary.Round"))
|
||||
|
||||
if string.find(rnd, ".50bmg") then
|
||||
self:SetStatRawL("Primary.Damage", 185)
|
||||
elseif string.find(rnd, "5.45x39") then
|
||||
self:SetStatRawL("Primary.Damage", 22)
|
||||
elseif string.find(rnd, "5.56x45") then
|
||||
self:SetStatRawL("Primary.Damage", 30)
|
||||
elseif string.find(rnd, "338_lapua") then
|
||||
self:SetStatRawL("Primary.Damage", 120)
|
||||
elseif string.find(rnd, "338") then
|
||||
self:SetStatRawL("Primary.Damage", 100)
|
||||
elseif string.find(rnd, "7.62x51") then
|
||||
self:SetStatRawL("Primary.Damage", 100)
|
||||
elseif string.find(rnd, "9x39") then
|
||||
self:SetStatRawL("Primary.Damage", 32)
|
||||
elseif string.find(rnd, "9mm") then
|
||||
self:SetStatRawL("Primary.Damage", 22)
|
||||
elseif string.find(rnd, "9x19") then
|
||||
self:SetStatRawL("Primary.Damage", 22)
|
||||
elseif string.find(rnd, "9x18") then
|
||||
self:SetStatRawL("Primary.Damage", 20)
|
||||
end
|
||||
|
||||
if string.find(rnd, "ap") then
|
||||
self:SetStatRawL("Primary.Damage", self:GetStatRawL("Primary.Damage") * 1.2)
|
||||
end
|
||||
end
|
||||
|
||||
if (not self:GetStatRawL("Primary.Damage")) or (self:GetStatRawL("Primary.Damage") <= 0.01) and self:GetStatRawL("Velocity") then
|
||||
self:SetStatRawL("Primary.Damage", self:GetStatRawL("Velocity") / 5)
|
||||
end
|
||||
|
||||
if (not self:GetStatRawL("Primary.Damage")) or (self:GetStatRawL("Primary.Damage") <= 0.01) then
|
||||
self:SetStatRawL("Primary.Damage", (self:GetStatRawL("Primary.KickUp") + self:GetStatRawL("Primary.KickUp") + self:GetStatRawL("Primary.KickUp")) * 10)
|
||||
end
|
||||
end
|
||||
|
||||
--[[
|
||||
Function Name: AutoDetectDamageType
|
||||
Syntax: self:AutoDetectDamageType(). Call only once. Hopefully you call this only once on like SWEP:Initialize() or something.
|
||||
Returns: Nothing.
|
||||
Notes: Sets a damagetype
|
||||
Purpose: Autodetection
|
||||
]]
|
||||
--
|
||||
function SWEP:AutoDetectDamageType()
|
||||
local self2 = self:GetTable()
|
||||
if self:GetStatRawL("Primary.DamageType") == -1 or not self:GetStatRawL("Primary.DamageType") then
|
||||
if self:GetStatRawL("DamageType") and not self:GetStatRawL("Primary.DamageType") then
|
||||
self:SetStatRawL("Primary.DamageType", self:GetStatRawL("DamageType"))
|
||||
else
|
||||
self:SetStatRawL("Primary.DamageType", DMG_BULLET)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--[[
|
||||
Function Name: AutoDetectForce
|
||||
Syntax: self:AutoDetectForce(). Call only once. Hopefully you call this only once on like SWEP:Initialize() or something.
|
||||
Returns: Nothing.
|
||||
Notes: Detects force from damage
|
||||
Purpose: Autodetection
|
||||
]]
|
||||
--
|
||||
function SWEP:AutoDetectForce()
|
||||
local self2 = self:GetTable()
|
||||
if self:GetStatRawL("Primary.Force") == -1 or not self:GetStatRawL("Primary.Force") then
|
||||
self:SetStatRawL("Primary.Force", self:GetStatRawL("Force") or (math.sqrt(self:GetStatRawL("Primary.Damage") / 16) * 3 / math.sqrt(self:GetStatRawL("Primary.NumShots"))))
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:AutoDetectPenetrationPower()
|
||||
local self2 = self:GetTable()
|
||||
|
||||
if self:GetStatRawL("Primary.PenetrationPower") == -1 or not self:GetStatRawL("Primary.PenetrationPower") then
|
||||
local am = string.lower(self:GetStatL("Primary.Ammo"))
|
||||
local m = 1
|
||||
|
||||
if (am == "pistol") then
|
||||
m = 0.4
|
||||
elseif (am == "357") then
|
||||
m = 1.75
|
||||
elseif (am == "smg1") then
|
||||
m = 0.34
|
||||
elseif (am == "ar2") then
|
||||
m = 1.1
|
||||
elseif (am == "buckshot") then
|
||||
m = 0.3
|
||||
elseif (am == "airboatgun") then
|
||||
m = 2.25
|
||||
elseif (am == "sniperpenetratedround") then
|
||||
m = 3
|
||||
end
|
||||
|
||||
self:SetStatRawL("Primary.PenetrationPower", self:GetStatRawL("PenetrationPower") or math.sqrt(self:GetStatRawL("Primary.Force") * 200 * m))
|
||||
end
|
||||
end
|
||||
|
||||
--[[
|
||||
Function Name: AutoDetectKnockback
|
||||
Syntax: self:AutoDetectKnockback(). Call only once. Hopefully you call this only once on like SWEP:Initialize() or something.
|
||||
Returns: Nothing.
|
||||
Notes: Detects knockback from force
|
||||
Purpose: Autodetection
|
||||
]]
|
||||
--
|
||||
function SWEP:AutoDetectKnockback()
|
||||
local self2 = self:GetTable()
|
||||
if self:GetStatRawL("Primary.Knockback") == -1 or not self:GetStatRawL("Primary.Knockback") then
|
||||
self:SetStatRawL("Primary.Knockback", self:GetStatRawL("Knockback") or math.max(math.pow(self:GetStatRawL("Primary.Force") - 3.25, 2), 0) * math.pow(self:GetStatRawL("Primary.NumShots"), 1 / 3))
|
||||
end
|
||||
end
|
||||
|
||||
--[[
|
||||
Function Name: IconFix
|
||||
Syntax: self:IconFix(). Call only once. Hopefully you call this only once on like SWEP:Initialize() or something.
|
||||
Returns: Nothing.
|
||||
Notes: Fixes the icon. Call this if you give it a texture path, or just nothing.
|
||||
Purpose: Autodetection
|
||||
]]
|
||||
--
|
||||
local selicon_final = {}
|
||||
|
||||
function SWEP:IconFix()
|
||||
local self2 = self:GetTable()
|
||||
|
||||
if not surface then return end
|
||||
|
||||
local class = self2.ClassName
|
||||
|
||||
if selicon_final[class] then
|
||||
self:SetStatRawL("WepSelectIcon", selicon_final[class])
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
if self2.WepSelectIcon and type(self2.WepSelectIcon) == "string" then
|
||||
self:SetStatRawL("WepSelectIcon", surface.GetTextureID(self2.WepSelectIcon))
|
||||
else
|
||||
if file.Exists("materials/vgui/hud/" .. class .. ".png", "GAME") then
|
||||
self:SetStatRawL("WepSelectIcon", Material("vgui/hud/" .. class .. ".png", "smooth noclamp")) -- NOTHING should access this variable directly and our DrawWeaponSelection override supports IMaterial.
|
||||
elseif file.Exists("materials/vgui/hud/" .. class .. ".vmt", "GAME") then
|
||||
self:SetStatRawL("WepSelectIcon", surface.GetTextureID("vgui/hud/" .. class))
|
||||
end
|
||||
end
|
||||
|
||||
selicon_final[class] = self2.WepSelectIcon
|
||||
end
|
||||
|
||||
--[[
|
||||
Function Name: CorrectScopeFOV
|
||||
Syntax: self:CorrectScopeFOV( fov ). Call only once. Hopefully you call this only once on like SWEP:Initialize() or something.
|
||||
Returns: Nothing.
|
||||
Notes: If you're using scopezoom instead of FOV, this translates it.
|
||||
Purpose: Autodetection
|
||||
]]
|
||||
--
|
||||
function SWEP:CorrectScopeFOV(fov)
|
||||
local self2 = self:GetTable()
|
||||
fov = fov or self:GetStatRawL("DefaultFOV")
|
||||
|
||||
if not self:GetStatRawL("Secondary.OwnerFOV") or self:GetStatRawL("Secondary.OwnerFOV") <= 0 then
|
||||
if self:GetStatRawL("Scoped") then
|
||||
self:SetStatRawL("Secondary.OwnerFOV", fov / (self:GetStatRawL("Secondary.ScopeZoom") and self:GetStatRawL("Secondary.ScopeZoom") or 2))
|
||||
else
|
||||
self:SetStatRawL("Secondary.OwnerFOV", 32)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--[[
|
||||
Function Name: CreateFireModes
|
||||
Syntax: self:CreateFireModes( is first draw). Call as much as you like. isfirstdraw controls whether the default fire mode is set.
|
||||
Returns: Nothing.
|
||||
Notes: Autodetects fire modes depending on what params you set up.
|
||||
Purpose: Autodetection
|
||||
]]
|
||||
--
|
||||
SWEP.FireModeCache = {}
|
||||
|
||||
function SWEP:CreateFireModes(isfirstdraw)
|
||||
local self2 = self:GetTable()
|
||||
if not self2.FireModes then
|
||||
self:SetStatRawL("FireModes", {})
|
||||
local burstcnt = self:FindEvenBurstNumber()
|
||||
|
||||
if self2.SelectiveFire then
|
||||
if self2.OnlyBurstFire then
|
||||
if burstcnt then
|
||||
self2.FireModes[1] = burstcnt .. "Burst"
|
||||
self2.FireModes[2] = "Single"
|
||||
else
|
||||
self2.FireModes[1] = "Single"
|
||||
end
|
||||
else
|
||||
self2.FireModes[1] = "Automatic"
|
||||
|
||||
if self2.DisableBurstFire then
|
||||
self2.FireModes[2] = "Single"
|
||||
else
|
||||
if burstcnt then
|
||||
self2.FireModes[2] = burstcnt .. "Burst"
|
||||
self2.FireModes[3] = "Single"
|
||||
else
|
||||
self2.FireModes[2] = "Single"
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
if self2.Primary_TFA.Automatic then
|
||||
self2.FireModes[1] = "Automatic"
|
||||
|
||||
if self2.OnlyBurstFire and burstcnt then
|
||||
self2.FireModes[1] = burstcnt .. "Burst"
|
||||
end
|
||||
else
|
||||
self2.FireModes[1] = "Single"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if self2.FireModes[#self2.FireModes] ~= "Safe" then
|
||||
self2.FireModes[#self2.FireModes + 1] = "Safe"
|
||||
end
|
||||
|
||||
if not self2.FireModeCache or #self2.FireModeCache <= 0 then
|
||||
for k, v in ipairs(self2.FireModes) do
|
||||
self2.FireModeCache[v] = k
|
||||
end
|
||||
|
||||
if type(self2.DefaultFireMode) == "number" then
|
||||
self:SetFireMode(self2.DefaultFireMode or (self2.Primary_TFA.Automatic and 1 or #self2.FireModes - 1))
|
||||
else
|
||||
self:SetFireMode(self2.FireModeCache[self2.DefaultFireMode] or (self2.Primary_TFA.Automatic and 1 or #self2.FireModes - 1))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--[[
|
||||
Function Name: CacheAnimations
|
||||
Syntax: self:CacheAnimations(). Call as much as you like.
|
||||
Returns: Nothing.
|
||||
Notes: This is what autodetects animations for the SWEP.SequenceEnabled and SWEP.SequenceLength tables.
|
||||
Purpose: Autodetection
|
||||
]]
|
||||
--
|
||||
--SWEP.actlist = {ACT_VM_DRAW, ACT_VM_DRAW_EMPTY, ACT_VM_DRAW_SILENCED, ACT_VM_DRAW_DEPLOYED, ACT_VM_HOLSTER, ACT_VM_HOLSTER_EMPTY, ACT_VM_IDLE, ACT_VM_IDLE_EMPTY, ACT_VM_IDLE_SILENCED, ACT_VM_PRIMARYATTACK, ACT_VM_PRIMARYATTACK_1, ACT_VM_PRIMARYATTACK_EMPTY, ACT_VM_PRIMARYATTACK_SILENCED, ACT_VM_SECONDARYATTACK, ACT_VM_RELOAD, ACT_VM_RELOAD_EMPTY, ACT_VM_RELOAD_SILENCED, ACT_VM_ATTACH_SILENCER, ACT_VM_RELEASE, ACT_VM_DETACH_SILENCER, ACT_VM_FIDGET, ACT_VM_FIDGET_EMPTY, ACT_VM_FIDGET_SILENCED, ACT_SHOTGUN_RELOAD_START, ACT_VM_DRYFIRE, ACT_VM_DRYFIRE_SILENCED }
|
||||
--If you really want, you can remove things from SWEP.actlist and manually enable animations and set their lengths.
|
||||
SWEP.SequenceEnabled = {}
|
||||
SWEP.SequenceLength = {}
|
||||
SWEP.SequenceLengthOverride = {} --Override this if you want to change the length of a sequence but not the next idle
|
||||
SWEP.ActCache = {}
|
||||
local vm, seq
|
||||
|
||||
function SWEP:CacheAnimations()
|
||||
local self2 = self:GetTable()
|
||||
table.Empty(self2.ActCache)
|
||||
|
||||
if self:GetStatRawL("CanBeSilenced") and self2.SequenceEnabled[ACT_VM_IDLE_SILENCED] == nil then
|
||||
self2.SequenceEnabled[ACT_VM_IDLE_SILENCED] = true
|
||||
end
|
||||
|
||||
if not self:VMIV() then return end
|
||||
vm = self2.OwnerViewModel
|
||||
|
||||
if IsValid(vm) then
|
||||
self:BuildAnimActivities()
|
||||
|
||||
for _, v in ipairs(table.GetKeys(self2.AnimationActivities)) do
|
||||
if isnumber(v) then
|
||||
seq = vm:SelectWeightedSequence(v)
|
||||
|
||||
if seq ~= -1 and vm:GetSequenceActivity(seq) == v and not self2.ActCache[seq] then
|
||||
self2.SequenceEnabled[v] = true
|
||||
self2.SequenceLength[v] = vm:SequenceDuration(seq)
|
||||
self2.ActCache[seq] = v
|
||||
else
|
||||
self2.SequenceEnabled[v] = false
|
||||
self2.SequenceLength[v] = 0.0
|
||||
end
|
||||
else
|
||||
local s = vm:LookupSequence(v)
|
||||
|
||||
if s and s > 0 then
|
||||
self2.SequenceEnabled[v] = true
|
||||
self2.SequenceLength[v] = vm:SequenceDuration(s)
|
||||
self2.ActCache[s] = v
|
||||
else
|
||||
self2.SequenceEnabled[v] = false
|
||||
self2.SequenceLength[v] = 0.0
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
return false
|
||||
end
|
||||
|
||||
if self:GetStatRawL("ProceduralHolsterEnabled") == nil then
|
||||
if self2.SequenceEnabled[ACT_VM_HOLSTER] then
|
||||
self:SetStatRawL("ProceduralHolsterEnabled", false)
|
||||
else
|
||||
self:SetStatRawL("ProceduralHolsterEnabled", true)
|
||||
end
|
||||
end
|
||||
|
||||
self:SetStatRawL("HasDetectedValidAnimations", true)
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function SWEP:GetType()
|
||||
local self2 = self:GetTable()
|
||||
if self:GetStatRawL("Type") then return self:GetStatRawL("Type") end
|
||||
local at = string.lower(self:GetStatRawL("Primary.Ammo") or "")
|
||||
local ht = string.lower((self:GetStatRawL("DefaultHoldType") or self:GetStatRawL("HoldType")) or "")
|
||||
local rpm = self:GetStatRawL("Primary.RPM_Displayed") or self:GetStatRawL("Primary.RPM") or 600
|
||||
|
||||
if self:GetStatRawL("Primary.ProjectileEntity") or self:GetStatRawL("ProjectileEntity") then
|
||||
if (self:GetStatRawL("ProjectileVelocity") or self:GetStatRawL("Primary.ProjectileVelocity")) > 400 then
|
||||
self:SetStatRawL("Type", "Launcher")
|
||||
else
|
||||
self:SetStatRawL("Type", "Grenade")
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
if at == "buckshot" then
|
||||
self:SetStatRawL("Type", "Shotgun")
|
||||
|
||||
return self:GetType()
|
||||
end
|
||||
|
||||
if self:GetStatRawL("Pistol") or (at == "pistol" and ht == "pistol") then
|
||||
self:SetStatRawL("Type", "Pistol")
|
||||
|
||||
return self:GetType()
|
||||
end
|
||||
|
||||
if self:GetStatRawL("SMG") or (at == "smg1" and (ht == "smg" or ht == "pistol" or ht == "357")) then
|
||||
self:SetStatRawL("Type", "Sub-Machine Gun")
|
||||
|
||||
return self:GetType()
|
||||
end
|
||||
|
||||
if self:GetStatRawL("Revolver") or (at == "357" and ht == "revolver") then
|
||||
self:SetStatRawL("Type", "Revolver")
|
||||
|
||||
return self:GetType()
|
||||
end
|
||||
|
||||
--Detect Sniper Type
|
||||
if ( (self:GetStatRawL("Scoped") or self:GetStatRawL("Scoped_3D")) and rpm < 600 ) or at == "sniperpenetratedround" then
|
||||
if rpm > 180 and (self:GetStatRawL("Primary.Automatic") or self:GetStatRawL("Primary.SelectiveFire")) then
|
||||
self:SetStatRawL("Type", "Designated Marksman Rifle")
|
||||
|
||||
return self:GetType()
|
||||
else
|
||||
self:SetStatRawL("Type", "Sniper Rifle")
|
||||
|
||||
return self:GetType()
|
||||
end
|
||||
end
|
||||
|
||||
--Detect based on holdtype
|
||||
if ht == "pistol" then
|
||||
if self:GetStatRawL("Primary.Automatic") then
|
||||
self:SetStatRawL("Type", "Machine Pistol")
|
||||
else
|
||||
self:SetStatRawL("Type", "Pistol")
|
||||
end
|
||||
|
||||
return self:GetType()
|
||||
end
|
||||
|
||||
if ht == "duel" then
|
||||
if at == "pistol" then
|
||||
self:SetStatRawL("Type", "Dual Pistols")
|
||||
|
||||
return self:GetType()
|
||||
elseif at == "357" then
|
||||
self:SetStatRawL("Type", "Dual Revolvers")
|
||||
|
||||
return self:GetType()
|
||||
elseif at == "smg1" then
|
||||
self:SetStatRawL("Type", "Dual Sub-Machine Guns")
|
||||
|
||||
return self:GetType()
|
||||
else
|
||||
self:SetStatRawL("Type", "Dual Guns")
|
||||
|
||||
return self:GetType()
|
||||
end
|
||||
end
|
||||
|
||||
--If it's using rifle ammo, it's a rifle or a carbine
|
||||
if at == "ar2" then
|
||||
if self:GetStatRawL("Primary.ClipSize") >= 60 then
|
||||
self:SetStatRawL("Type", "Light Machine Gun")
|
||||
|
||||
return self:GetType()
|
||||
elseif ht == "rpg" or ht == "revolver" then
|
||||
self:SetStatRawL("Type", "Carbine")
|
||||
|
||||
return self:GetType()
|
||||
else
|
||||
self:SetStatRawL("Type", "Rifle")
|
||||
|
||||
return self:GetType()
|
||||
end
|
||||
end
|
||||
|
||||
--Check SMG one last time
|
||||
if ht == "smg" or at == "smg1" then
|
||||
self:SetStatRawL("Type", "Sub-Machine Gun")
|
||||
|
||||
return self:GetType()
|
||||
end
|
||||
|
||||
--Fallback to generic
|
||||
self:SetStatRawL("Type", "Weapon")
|
||||
|
||||
return self:GetType()
|
||||
end
|
||||
|
||||
function SWEP:SetUpSpreadLegacy()
|
||||
local self2 = self:GetTable()
|
||||
local ht = self:GetStatRawL("DefaultHoldType") and self:GetStatRawL("DefaultHoldType") or self:GetStatRawL("HoldType")
|
||||
|
||||
if not self:GetStatRawL("Primary.SpreadMultiplierMax") or self:GetStatRawL("Primary.SpreadMultiplierMax") <= 0 or self:GetStatRawL("AutoDetectSpreadMultiplierMax") then
|
||||
self:SetStatRawL("Primary.SpreadMultiplierMax", 2.5 * math.max(self:GetStatRawL("Primary.RPM"), 400) / 600 * math.sqrt(self:GetStatRawL("Primary.Damage") / 30 * self:GetStatRawL("Primary.NumShots"))) --How far the spread can expand when you shoot.
|
||||
|
||||
if ht == "smg" then
|
||||
self:SetStatRawL("Primary.SpreadMultiplierMax", self:GetStatRawL("Primary.SpreadMultiplierMax") * 0.8)
|
||||
end
|
||||
|
||||
if ht == "revolver" then
|
||||
self:SetStatRawL("Primary.SpreadMultiplierMax", self:GetStatRawL("Primary.SpreadMultiplierMax") * 2)
|
||||
end
|
||||
|
||||
if self:GetStatRawL("Scoped") then
|
||||
self:SetStatRawL("Primary.SpreadMultiplierMax", self:GetStatRawL("Primary.SpreadMultiplierMax") * 1.5)
|
||||
end
|
||||
|
||||
self:SetStatRawL("AutoDetectSpreadMultiplierMax", true)
|
||||
end
|
||||
|
||||
if not self:GetStatRawL("Primary.SpreadIncrement") or self:GetStatRawL("Primary.SpreadIncrement") <= 0 or self:GetStatRawL("AutoDetectSpreadIncrement") then
|
||||
self:SetStatRawL("AutoDetectSpreadIncrement", true)
|
||||
self:SetStatRawL("Primary.SpreadIncrement", 1 * math.Clamp(math.sqrt(self:GetStatRawL("Primary.RPM")) / 24.5, 0.7, 3) * math.sqrt(self:GetStatRawL("Primary.Damage") / 30 * self:GetStatRawL("Primary.NumShots"))) --What percentage of the modifier is added on, per shot.
|
||||
|
||||
if ht == "revolver" then
|
||||
self:SetStatRawL("Primary.SpreadIncrement", self:GetStatRawL("Primary.SpreadIncrement") * 2)
|
||||
end
|
||||
|
||||
if ht == "pistol" then
|
||||
self:SetStatRawL("Primary.SpreadIncrement", self:GetStatRawL("Primary.SpreadIncrement") * 1.35)
|
||||
end
|
||||
|
||||
if ht == "ar2" or ht == "rpg" then
|
||||
self:SetStatRawL("Primary.SpreadIncrement", self:GetStatRawL("Primary.SpreadIncrement") * 0.65)
|
||||
end
|
||||
|
||||
if ht == "smg" then
|
||||
self:SetStatRawL("Primary.SpreadIncrement", self:GetStatRawL("Primary.SpreadIncrement") * 1.75)
|
||||
self:SetStatRawL("Primary.SpreadIncrement", self:GetStatRawL("Primary.SpreadIncrement") * (math.Clamp((self:GetStatRawL("Primary.RPM") - 650) / 150, 0, 1) + 1))
|
||||
end
|
||||
|
||||
if ht == "pistol" and self:GetStatRawL("Primary.Automatic") == true then
|
||||
self:SetStatRawL("Primary.SpreadIncrement", self:GetStatRawL("Primary.SpreadIncrement") * 1.5)
|
||||
end
|
||||
|
||||
if self:GetStatRawL("Scoped") then
|
||||
self:SetStatRawL("Primary.SpreadIncrement", self:GetStatRawL("Primary.SpreadIncrement") * 1.25)
|
||||
end
|
||||
|
||||
self:SetStatRawL("Primary.SpreadIncrement", self:GetStatRawL("Primary.SpreadIncrement") * math.sqrt(self:GetStatRawL("Primary.Recoil") * (self:GetStatRawL("Primary.KickUp") + self:GetStatRawL("Primary.KickDown") + self:GetStatRawL("Primary.KickHorizontal"))) * 0.8)
|
||||
end
|
||||
|
||||
if not self:GetStatRawL("Primary.SpreadRecovery") or self:GetStatRawL("Primary.SpreadRecovery") <= 0 or self:GetStatRawL("AutoDetectSpreadRecovery") then
|
||||
self:SetStatRawL("AutoDetectSpreadRecovery", true)
|
||||
self:SetStatRawL("Primary.SpreadRecovery", math.sqrt(math.max(self:GetStatRawL("Primary.RPM"), 300)) / 29 * 4) --How much the spread recovers, per second.
|
||||
|
||||
if ht == "smg" then
|
||||
self:SetStatRawL("Primary.SpreadRecovery", self:GetStatRawL("Primary.SpreadRecovery") * (1 - math.Clamp((self:GetStatRawL("Primary.RPM") - 600) / 200, 0, 1) * 0.33))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
SWEP.LowAmmoSoundTypeBlacklist = {
|
||||
["launcher"] = true,
|
||||
["grenade"] = true,
|
||||
}
|
||||
|
||||
SWEP.LowAmmoSoundByType = {
|
||||
["handgun"] = "TFA.LowAmmo.Handgun",
|
||||
["pistol"] = "TFA.LowAmmo.Handgun",
|
||||
["dualpistols"] = "TFA.LowAmmo.Handgun",
|
||||
["machinepistol"] = "TFA.LowAmmo.Handgun",
|
||||
["handcannon"] = "TFA.LowAmmo.Revolver",
|
||||
["revolver"] = "TFA.LowAmmo.Revolver",
|
||||
["dualrevolvers"] = "TFA.LowAmmo.Revolver",
|
||||
["shotgun"] = "TFA.LowAmmo.Shotgun",
|
||||
["machinegun"] = "TFA.LowAmmo.MachineGun",
|
||||
["lightmachinegun"] = "TFA.LowAmmo.MachineGun",
|
||||
["heavymachinegun"] = "TFA.LowAmmo.MachineGun",
|
||||
["carbine"] = "TFA.LowAmmo.AssaultRifle",
|
||||
["rifle"] = "TFA.LowAmmo.AssaultRifle",
|
||||
["assaultrifle"] = "TFA.LowAmmo.AssaultRifle",
|
||||
["dmr"] = "TFA.LowAmmo.DMR",
|
||||
["designatedmarksmanrifle"] = "TFA.LowAmmo.DMR",
|
||||
["sniperrifle"] = "TFA.LowAmmo.Sniper",
|
||||
["smg"] = "TFA.LowAmmo.SMG",
|
||||
["submachinegun"] = "TFA.LowAmmo.SMG",
|
||||
}
|
||||
SWEP.LastAmmoSoundByType = {
|
||||
["handgun"] = "TFA.LowAmmo.Handgun_Dry",
|
||||
["pistol"] = "TFA.LowAmmo.Handgun_Dry",
|
||||
["dualpistols"] = "TFA.LowAmmo.Handgun_Dry",
|
||||
["machinepistol"] = "TFA.LowAmmo.Handgun_Dry",
|
||||
["handcannon"] = "TFA.LowAmmo.Revolver_Dry",
|
||||
["revolver"] = "TFA.LowAmmo.Revolver_Dry",
|
||||
["dualrevolvers"] = "TFA.LowAmmo.Revolver_Dry",
|
||||
["shotgun"] = "TFA.LowAmmo.Shotgun_Dry",
|
||||
["machinegun"] = "TFA.LowAmmo.MachineGun_Dry",
|
||||
["lightmachinegun"] = "TFA.LowAmmo.MachineGun_Dry",
|
||||
["heavymachinegun"] = "TFA.LowAmmo.MachineGun_Dry",
|
||||
["carbine"] = "TFA.LowAmmo.AssaultRifle_Dry",
|
||||
["rifle"] = "TFA.LowAmmo.AssaultRifle_Dry",
|
||||
["assaultrifle"] = "TFA.LowAmmo.AssaultRifle_Dry",
|
||||
["dmr"] = "TFA.LowAmmo.DMR_Dry",
|
||||
["designatedmarksmanrifle"] = "TFA.LowAmmo.DMR_Dry",
|
||||
["sniperrifle"] = "TFA.LowAmmo.Sniper_Dry",
|
||||
["smg"] = "TFA.LowAmmo.SMG_Dry",
|
||||
["submachinegun"] = "TFA.LowAmmo.SMG_Dry",
|
||||
}
|
||||
|
||||
function SWEP:AutoDetectLowAmmoSound()
|
||||
if not self.FireSoundAffectedByClipSize then return end
|
||||
|
||||
local t1, t2 = self:GetType():lower():gsub("[^%w]+", ""), (self:GetStatRawL("Type_Displayed") or ""):lower():gsub("[^%w]+", "")
|
||||
|
||||
if self.LowAmmoSoundTypeBlacklist[t2] or self.LowAmmoSoundTypeBlacklist[t1] then return end
|
||||
|
||||
local clip1 = self:GetStatRawL("Primary.ClipSize")
|
||||
if (not clip1 or clip1 <= 4) then return end
|
||||
|
||||
if not self.LowAmmoSound then
|
||||
local snd = self.LowAmmoSoundByType[t2] or self.LowAmmoSoundByType[t1] or "TFA.LowAmmo"
|
||||
|
||||
if (t2 == "shotgun" or t1 == "shotgun") and not self:GetStatL("LoopedReload") then
|
||||
snd = "TFA.LowAmmo.AutoShotgun"
|
||||
end
|
||||
|
||||
self:SetStatRawL("LowAmmoSound", snd)
|
||||
end
|
||||
|
||||
if not self.LastAmmoSound then
|
||||
local snd = self.LastAmmoSoundByType[t2] or self.LastAmmoSoundByType[t1] or "TFA.LowAmmo_Dry"
|
||||
|
||||
if (t2 == "shotgun" or t1 == "shotgun") and not self:GetStatL("LoopedReload") then
|
||||
snd = "TFA.LowAmmo.AutoShotgun_Dry"
|
||||
end
|
||||
|
||||
self:SetStatRawL("LastAmmoSound", snd)
|
||||
end
|
||||
end
|
||||
1151
lua/weapons/tfa_gun_base/common/bullet.lua
Normal file
1151
lua/weapons/tfa_gun_base/common/bullet.lua
Normal file
File diff suppressed because it is too large
Load Diff
313
lua/weapons/tfa_gun_base/common/calc.lua
Normal file
313
lua/weapons/tfa_gun_base/common/calc.lua
Normal file
@@ -0,0 +1,313 @@
|
||||
--[[
|
||||
| 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.
|
||||
|
||||
TFA.GUESS_NPC_WALKSPEED = 160
|
||||
|
||||
local function l_Lerp(t, a, b) return a + (b - a) * t end
|
||||
local function l_mathMin(a, b) return (a < b) and a or b end
|
||||
local function l_mathMax(a, b) return (a > b) and a or b end
|
||||
local function l_ABS(a) return (a < 0) and -a or a end
|
||||
local function l_mathClamp(t, a, b)
|
||||
if a > b then return b end
|
||||
|
||||
if t > b then
|
||||
return b
|
||||
end
|
||||
|
||||
if t < a then
|
||||
return a
|
||||
end
|
||||
|
||||
return t
|
||||
end
|
||||
|
||||
local function l_mathApproach(a, b, delta)
|
||||
if a < b then
|
||||
return l_mathMin(a + l_ABS(delta), b)
|
||||
else
|
||||
return l_mathMax(a - l_ABS(delta), b)
|
||||
end
|
||||
end
|
||||
|
||||
local sprint_cv = GetConVar("sv_tfa_sprint_enabled")
|
||||
local sv_tfa_weapon_weight = GetConVar("sv_tfa_weapon_weight")
|
||||
|
||||
function SWEP:TFAFinishMove(ply, velocity, movedata)
|
||||
local ft = FrameTime()
|
||||
local self2 = self:GetTable()
|
||||
local isply = ply:IsPlayer()
|
||||
|
||||
if CLIENT then
|
||||
self2.LastUnpredictedVelocity = velocity
|
||||
end
|
||||
|
||||
local speedmult = Lerp(self:GetIronSightsProgress(), sv_tfa_weapon_weight:GetBool() and self:GetStatL("RegularMoveSpeedMultiplier") or 1, self:GetStatL("AimingDownSightsSpeedMultiplier"))
|
||||
|
||||
local jr_targ = math.min(math.abs(velocity.z) / 500, 1)
|
||||
self:SetJumpRatio(l_mathApproach(self:GetJumpRatio(), jr_targ, (jr_targ - self:GetJumpRatio()) * ft * 20))
|
||||
self2.JumpRatio = self:GetJumpRatio()
|
||||
self:SetCrouchingRatio(l_mathApproach(self:GetCrouchingRatio(), (self:IsOwnerCrouching()) and 1 or 0, ft / self2.ToCrouchTime))
|
||||
self2.CrouchingRatio = self:GetCrouchingRatio()
|
||||
|
||||
local status = self2.GetStatus(self)
|
||||
local oldsprinting, oldwalking = self:GetSprinting(), self:GetWalking()
|
||||
local vellen = velocity:Length2D()
|
||||
|
||||
--if TFA.Enum.ReloadStatus[status] then
|
||||
-- self:SetSprinting(false)
|
||||
--elseif sprint_cv:GetBool() and not self:GetStatL("AllowSprintAttack", false) and movedata then
|
||||
if sprint_cv:GetBool() and not self:GetStatL("AllowSprintAttack", false) and movedata then
|
||||
self:SetSprinting(vellen > ply:GetRunSpeed() * 0.6 * speedmult and movedata:KeyDown(IN_SPEED) and ply:OnGround())
|
||||
else
|
||||
self:SetSprinting(false)
|
||||
end
|
||||
|
||||
self:SetWalking(vellen > ((isply and ply:GetWalkSpeed() or TFA.GUESS_NPC_WALKSPEED) * (sv_tfa_weapon_weight:GetBool() and self:GetStatL("RegularMoveSpeedMultiplier", 1) or 1) * .75) and ply:GetNW2Bool("TFA_IsWalking") and ply:OnGround() and not self:GetSprinting() and not self:GetCustomizing())
|
||||
|
||||
self2.walking_updated = oldwalking ~= self:GetWalking()
|
||||
self2.sprinting_updated = oldsprinting ~= self:GetSprinting()
|
||||
|
||||
if self:GetCustomizing() and (self2.GetIronSights(self) or self:GetSprinting() or not TFA.Enum.ReadyStatus[status]) then
|
||||
self:ToggleCustomize()
|
||||
end
|
||||
|
||||
local spr = self:GetSprinting()
|
||||
local walk = self:GetWalking()
|
||||
|
||||
local sprt = spr and 1 or 0
|
||||
local walkt = walk and 1 or 0
|
||||
local adstransitionspeed = (spr or walk) and 7.5 or 12.5
|
||||
|
||||
self:SetSprintProgress(l_mathApproach(self:GetSprintProgress(), sprt, (sprt - self:GetSprintProgress()) * ft * adstransitionspeed))
|
||||
self:SetWalkProgress(l_mathApproach(self:GetWalkProgress(), walkt, (walkt - self:GetWalkProgress()) * ft * adstransitionspeed))
|
||||
|
||||
self:SetLastVelocity(vellen)
|
||||
end
|
||||
|
||||
local sp = game.SinglePlayer()
|
||||
local sv_tfa_recoil_legacy = GetConVar("sv_tfa_recoil_legacy")
|
||||
|
||||
function SWEP:CalculateRatios()
|
||||
local owent = self:GetOwner()
|
||||
--if not IsValid(owent) or not owent:IsPlayer() then return end
|
||||
if not IsValid(owent) then return end
|
||||
|
||||
local self2 = self:GetTable()
|
||||
|
||||
if self2.ratios_calc == nil then
|
||||
self2.ratios_calc = true
|
||||
end
|
||||
|
||||
local ft = FrameTime()
|
||||
local time = CurTime()
|
||||
|
||||
if ft <= 0 then return end
|
||||
|
||||
local is = self2.GetIronSights(self)
|
||||
local spr = self2.GetSprinting(self)
|
||||
local walk = self2.GetWalking(self)
|
||||
|
||||
local ist = is and 1 or 0
|
||||
local sprt = spr and 1 or 0
|
||||
local adstransitionspeed
|
||||
|
||||
if is then
|
||||
adstransitionspeed = 12.5 / (self:GetStatL("IronSightTime") / 0.3)
|
||||
elseif spr or walk then
|
||||
adstransitionspeed = 7.5
|
||||
else
|
||||
adstransitionspeed = 12.5
|
||||
end
|
||||
|
||||
if not owent:IsPlayer() then
|
||||
self:TFAFinishMove(owent, owent:GetVelocity())
|
||||
end
|
||||
|
||||
local lastrecoiltime = self2.GetLastRecoil(self, -1)
|
||||
|
||||
if lastrecoiltime < 0 or time >= (lastrecoiltime + self2.GetStatL(self, "Primary.SpreadRecoveryDelay")) then
|
||||
self:SetSpreadRatio(l_mathClamp(self:GetSpreadRatio() - self2.GetStatL(self, "Primary.SpreadRecovery") * ft, 1, self2.GetStatL(self, "Primary.SpreadMultiplierMax")))
|
||||
end
|
||||
|
||||
self:SetIronSightsProgress(l_mathApproach(self:GetIronSightsProgress(), ist, (ist - self:GetIronSightsProgress()) * ft * adstransitionspeed))
|
||||
self:SetProceduralHolsterProgress(l_mathApproach(self:GetProceduralHolsterProgress(), sprt, (sprt - self:GetSprintProgress()) * ft * self2.ProceduralHolsterTime * 15))
|
||||
self:SetInspectingProgress(l_mathApproach(self:GetInspectingProgress(), self:GetCustomizing() and 1 or 0, ((self:GetCustomizing() and 1 or 0) - self:GetInspectingProgress()) * ft * 10))
|
||||
|
||||
if self:GetRecoilThink() then
|
||||
if self:GetRecoilLoop() then
|
||||
-- loop or after loop
|
||||
|
||||
if self:GetRecoilLoopWait() < time then
|
||||
self:SetRecoilOutProgress(l_mathMin(1, self:GetRecoilOutProgress() + ft / self2.Primary_TFA.RecoilLUT["out"].cooldown_speed))
|
||||
|
||||
if self:GetRecoilOutProgress() == 1 then
|
||||
self:SetRecoilThink(false)
|
||||
self:SetRecoilLoop(false)
|
||||
self:SetRecoilLoopProgress(0)
|
||||
self:SetRecoilInProgress(0)
|
||||
self:SetRecoilOutProgress(0)
|
||||
end
|
||||
end
|
||||
else
|
||||
-- IN only
|
||||
|
||||
if self:GetRecoilInWait() < time then
|
||||
self:SetRecoilInProgress(l_mathMax(0, self:GetRecoilInProgress() - ft / self2.Primary_TFA.RecoilLUT["in"].cooldown_speed))
|
||||
|
||||
if self:GetRecoilInProgress() == 0 then
|
||||
self:SetRecoilThink(false)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if not sv_tfa_recoil_legacy:GetBool() then
|
||||
ft = l_mathClamp(ft, 0, 1)
|
||||
self:SetViewPunchBuild(l_mathMax(0, self:GetViewPunchBuild() - self:GetViewPunchBuild() * ft))
|
||||
local build = l_mathMax(0, 4.5 - self:GetViewPunchBuild())
|
||||
ft = ft * build * build
|
||||
self:SetViewPunchP(self:GetViewPunchP() - self:GetViewPunchP() * ft)
|
||||
self:SetViewPunchY(self:GetViewPunchY() - self:GetViewPunchY() * ft)
|
||||
end
|
||||
|
||||
self2.SpreadRatio = self:GetSpreadRatio()
|
||||
self2.IronSightsProgress = self:GetIronSightsProgress()
|
||||
self2.SprintProgress = self:GetSprintProgress()
|
||||
self2.WalkProgress = self:GetWalkProgress()
|
||||
self2.ProceduralHolsterProgress = self:GetProceduralHolsterProgress()
|
||||
self2.InspectingProgress = self:GetInspectingProgress()
|
||||
|
||||
if sp and CLIENT then
|
||||
self2.Inspecting = self:GetCustomizing() --compatibility
|
||||
end
|
||||
|
||||
self2.CLIronSightsProgress = self:GetIronSightsProgress() --compatibility
|
||||
end
|
||||
|
||||
SWEP.Primary.IronRecoilMultiplier = 0.5 --Multiply recoil by this factor when we're in ironsights. This is proportional, not inversely.
|
||||
SWEP.CrouchRecoilMultiplier = 0.65 --Multiply recoil by this factor when we're crouching. This is proportional, not inversely.
|
||||
SWEP.JumpRecoilMultiplier = 1.3 --Multiply recoil by this factor when we're crouching. This is proportional, not inversely.
|
||||
SWEP.WallRecoilMultiplier = 1.1 --Multiply recoil by this factor when we're changing state e.g. not completely ironsighted. This is proportional, not inversely.
|
||||
SWEP.ChangeStateRecoilMultiplier = 1.3 --Multiply recoil by this factor when we're crouching. This is proportional, not inversely.
|
||||
SWEP.CrouchAccuracyMultiplier = 0.5 --Less is more. Accuracy * 0.5 = Twice as accurate, Accuracy * 0.1 = Ten times as accurate
|
||||
SWEP.ChangeStateAccuracyMultiplier = 1.5 --Less is more. A change of state is when we're in the progress of doing something, like crouching or ironsighting. Accuracy * 2 = Half as accurate. Accuracy * 5 = 1/5 as accurate
|
||||
SWEP.JumpAccuracyMultiplier = 2 --Less is more. Accuracy * 2 = Half as accurate. Accuracy * 5 = 1/5 as accurate
|
||||
SWEP.WalkAccuracyMultiplier = 1.35 --Less is more. Accuracy * 2 = Half as accurate. Accuracy * 5 = 1/5 as accurate
|
||||
SWEP.ToCrouchTime = 0.25
|
||||
|
||||
local mult_cvar = GetConVar("sv_tfa_spread_multiplier")
|
||||
local dynacc_cvar = GetConVar("sv_tfa_dynamicaccuracy")
|
||||
local ccon, crec
|
||||
|
||||
SWEP.JumpRatio = 0
|
||||
|
||||
function SWEP:CalculateConeRecoil()
|
||||
local dynacc = false
|
||||
local self2 = self:GetTable()
|
||||
local isr = self:GetIronSightsProgress()
|
||||
|
||||
if dynacc_cvar:GetBool() and (self2.GetStatL(self, "Primary.NumShots") <= 1) then
|
||||
dynacc = true
|
||||
end
|
||||
|
||||
local isr_1 = l_mathClamp(isr * 2, 0, 1)
|
||||
local isr_2 = l_mathClamp((isr - 0.5) * 2, 0, 1)
|
||||
local acv = self2.GetStatL(self, "Primary.Spread") or self2.GetStatL(self, "Primary.Accuracy")
|
||||
local recv = self2.GetStatL(self, "Primary.Recoil") * 5
|
||||
|
||||
if dynacc then
|
||||
ccon = l_Lerp(isr_2, l_Lerp(isr_1, acv, acv * self2.GetStatL(self, "ChangeStateAccuracyMultiplier")), self2.GetStatL(self, "Primary.IronAccuracy"))
|
||||
crec = l_Lerp(isr_2, l_Lerp(isr_1, recv, recv * self2.GetStatL(self, "ChangeStateRecoilMultiplier")), recv * self2.GetStatL(self, "Primary.IronRecoilMultiplier"))
|
||||
else
|
||||
ccon = l_Lerp(isr, acv, self2.GetStatL(self, "Primary.IronAccuracy"))
|
||||
crec = l_Lerp(isr, recv, recv * self2.GetStatL(self, "Primary.IronRecoilMultiplier"))
|
||||
end
|
||||
|
||||
local crc_1 = l_mathClamp(self:GetCrouchingRatio() * 2, 0, 1)
|
||||
local crc_2 = l_mathClamp((self:GetCrouchingRatio() - 0.5) * 2, 0, 1)
|
||||
|
||||
if dynacc then
|
||||
ccon = l_Lerp(crc_2, l_Lerp(crc_1, ccon, ccon * self2.GetStatL(self, "ChangeStateAccuracyMultiplier")), ccon * self2.GetStatL(self, "CrouchAccuracyMultiplier"))
|
||||
crec = l_Lerp(crc_2, l_Lerp(crc_1, crec, self2.GetStatL(self, "Primary.Recoil") * self2.GetStatL(self, "ChangeStateRecoilMultiplier")), crec * self2.GetStatL(self, "CrouchRecoilMultiplier"))
|
||||
end
|
||||
|
||||
local owner = self:GetOwner()
|
||||
local isply = owner:IsPlayer()
|
||||
local ovel
|
||||
|
||||
if IsValid(owner) then
|
||||
if owner:IsPlayer() then
|
||||
ovel = self:GetLastVelocity()
|
||||
else
|
||||
ovel = owner:GetVelocity():Length2D()
|
||||
end
|
||||
else
|
||||
ovel = 0
|
||||
end
|
||||
|
||||
local vfc_1 = l_mathClamp(ovel / (isply and owner:GetWalkSpeed() or TFA.GUESS_NPC_WALKSPEED), 0, 2)
|
||||
|
||||
if dynacc then
|
||||
ccon = l_Lerp(vfc_1, ccon, ccon * self2.GetStatL(self, "WalkAccuracyMultiplier"))
|
||||
crec = l_Lerp(vfc_1, crec, crec * self2.GetStatL(self, "WallRecoilMultiplier"))
|
||||
end
|
||||
|
||||
local jr = self:GetJumpRatio()
|
||||
|
||||
if dynacc then
|
||||
ccon = l_Lerp(jr, ccon, ccon * self2.GetStatL(self, "JumpAccuracyMultiplier"))
|
||||
crec = l_Lerp(jr, crec, crec * self2.GetStatL(self, "JumpRecoilMultiplier"))
|
||||
end
|
||||
|
||||
ccon = ccon * self:GetSpreadRatio()
|
||||
|
||||
if mult_cvar then
|
||||
ccon = ccon * mult_cvar:GetFloat()
|
||||
end
|
||||
|
||||
if not isply and IsValid(owner) then
|
||||
local prof = owner:GetCurrentWeaponProficiency()
|
||||
|
||||
if prof == WEAPON_PROFICIENCY_POOR then
|
||||
ccon = ccon * 8
|
||||
elseif prof == WEAPON_PROFICIENCY_AVERAGE then
|
||||
ccon = ccon * 5
|
||||
elseif prof == WEAPON_PROFICIENCY_GOOD then
|
||||
ccon = ccon * 3
|
||||
elseif prof == WEAPON_PROFICIENCY_VERY_GOOD then
|
||||
ccon = ccon * 2
|
||||
elseif prof == WEAPON_PROFICIENCY_PERFECT then
|
||||
ccon = ccon * 1.5
|
||||
end
|
||||
end
|
||||
|
||||
return ccon, crec
|
||||
end
|
||||
383
lua/weapons/tfa_gun_base/common/effects.lua
Normal file
383
lua/weapons/tfa_gun_base/common/effects.lua
Normal file
@@ -0,0 +1,383 @@
|
||||
--[[
|
||||
| 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 fx, sp = nil, game.SinglePlayer()
|
||||
local shelltype
|
||||
|
||||
function SWEP:PCFTracer(bul, hitpos, ovrride)
|
||||
if bul.PCFTracer then
|
||||
self:UpdateMuzzleAttachment()
|
||||
local mzp = self:GetMuzzlePos()
|
||||
if bul.PenetrationCount > 0 and not ovrride then return end --Taken care of with the pen effect
|
||||
|
||||
if (CLIENT or game.SinglePlayer()) and self.Scoped and self:IsCurrentlyScoped() and self:IsFirstPerson() then
|
||||
TFA.ParticleTracer(bul.PCFTracer, self:GetOwner():GetShootPos() - self:GetOwner():EyeAngles():Up() * 5, hitpos, false, 0, -1)
|
||||
else
|
||||
local vent = self
|
||||
|
||||
if (CLIENT or game.SinglePlayer()) and self:IsFirstPerson() then
|
||||
vent = self.OwnerViewModel
|
||||
end
|
||||
|
||||
if sp and not self:IsFirstPerson() then
|
||||
TFA.ParticleTracer(bul.PCFTracer, self:GetOwner():GetShootPos() + self:GetOwner():GetAimVector() * 32, hitpos, false)
|
||||
else
|
||||
TFA.ParticleTracer(bul.PCFTracer, mzp.Pos, hitpos, false, vent, self.MuzzleAttachmentRaw or 1)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:EventShell()
|
||||
if SERVER and self.processing_events and sp then return end
|
||||
|
||||
if SERVER then
|
||||
net.Start("tfaBaseShellSV", true)
|
||||
net.WriteEntity(self)
|
||||
|
||||
if self:GetOwner():IsPlayer() then
|
||||
if sp then
|
||||
net.Broadcast()
|
||||
else
|
||||
net.SendOmit(self:GetOwner())
|
||||
end
|
||||
else
|
||||
net.SendPVS(self:GetPos())
|
||||
end
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
self:MakeShellBridge()
|
||||
end
|
||||
|
||||
function SWEP:MakeShellBridge(ifp)
|
||||
if ifp == false then return end
|
||||
|
||||
if self.LuaShellEjectDelay > 0 then
|
||||
self.LuaShellRequestTime = CurTime() + self.LuaShellEjectDelay / self:GetAnimationRate(ACT_VM_PRIMARYATTACK)
|
||||
else
|
||||
self:MakeShell()
|
||||
end
|
||||
end
|
||||
|
||||
SWEP.ShellEffectOverride = nil -- ???
|
||||
SWEP.ShellEjectionQueue = 0
|
||||
|
||||
function SWEP:GetShellAttachmentID(ent, isVM)
|
||||
local raw = self:GetStatL("ShellAttachmentRaw")
|
||||
local israw = false
|
||||
local attid
|
||||
|
||||
if raw and ent:GetAttachment(raw) then
|
||||
attid = raw
|
||||
israw = true
|
||||
else
|
||||
attid = ent:LookupAttachment(self:GetStatL("ShellAttachment"))
|
||||
end
|
||||
|
||||
if self:GetStatL("IsAkimbo") and not israw then
|
||||
return 3 + self:GetAnimCycle()
|
||||
end
|
||||
|
||||
if attid and attid <= 0 then attid = 2 end
|
||||
|
||||
attid = math.Clamp(attid and attid or 2, 1, 127)
|
||||
|
||||
return attid
|
||||
end
|
||||
|
||||
function SWEP:GetShellEjectPosition(ent, isVM)
|
||||
local attid = self:GetShellAttachmentID(ent, isVM)
|
||||
|
||||
local angpos = ent:GetAttachment(attid)
|
||||
|
||||
if angpos then
|
||||
return angpos.Pos, angpos.Ang, attid
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:MakeShell(eject_now)
|
||||
if not self:IsValid() then return end -- what
|
||||
if self.current_event_iftp == false then return end
|
||||
|
||||
local retVal = hook.Run("TFA_MakeShell", self)
|
||||
|
||||
if retVal ~= nil then
|
||||
return retVal
|
||||
end
|
||||
|
||||
if self:GetStatL("ShellEffectOverride") then
|
||||
shelltype = self:GetStatL("ShellEffectOverride")
|
||||
elseif TFA.GetLegacyShellsEnabled() then
|
||||
shelltype = "tfa_shell_legacy"
|
||||
else
|
||||
shelltype = "tfa_shell"
|
||||
end
|
||||
|
||||
local ent = self
|
||||
local isVM = false
|
||||
|
||||
if self:IsFirstPerson() then
|
||||
if not eject_now and CLIENT then
|
||||
self.ShellEjectionQueue = self.ShellEjectionQueue + 1
|
||||
return
|
||||
end
|
||||
|
||||
ent = self.OwnerViewModel or self
|
||||
isVM = ent == self.OwnerViewModel
|
||||
end
|
||||
|
||||
self:EjectionSmoke(true)
|
||||
|
||||
if not isstring(shelltype) or shelltype == "" then return end -- allows to disable shells by setting override to "" - will shut up all rp fags
|
||||
|
||||
if not IsValid(ent) then return end
|
||||
local pos, ang, attid = self:GetShellEjectPosition(ent, isVM)
|
||||
|
||||
if not pos then return end
|
||||
|
||||
fx = EffectData()
|
||||
fx:SetEntity(self)
|
||||
fx:SetAttachment(attid)
|
||||
fx:SetMagnitude(1)
|
||||
fx:SetScale(1)
|
||||
fx:SetOrigin(pos)
|
||||
fx:SetNormal(ang:Forward())
|
||||
TFA.Effects.Create(shelltype, fx)
|
||||
end
|
||||
|
||||
--[[
|
||||
Function Name: CleanParticles
|
||||
Syntax: self:CleanParticles().
|
||||
Returns: Nothing.
|
||||
Notes: Cleans up particles.
|
||||
Purpose: FX
|
||||
]]
|
||||
--
|
||||
function SWEP:CleanParticles()
|
||||
if not IsValid(self) then return end
|
||||
|
||||
if self.StopParticles then
|
||||
self:StopParticles()
|
||||
end
|
||||
|
||||
if self.StopParticleEmission then
|
||||
self:StopParticleEmission()
|
||||
end
|
||||
|
||||
if not self:VMIV() then return end
|
||||
local vm = self.OwnerViewModel
|
||||
|
||||
if IsValid(vm) then
|
||||
if vm.StopParticles then
|
||||
vm:StopParticles()
|
||||
end
|
||||
|
||||
if vm.StopParticleEmission then
|
||||
vm:StopParticleEmission()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--[[
|
||||
Function Name: EjectionSmoke
|
||||
Syntax: self:EjectionSmoke().
|
||||
Returns: Nothing.
|
||||
Notes: Puff of smoke on shell attachment.
|
||||
Purpose: FX
|
||||
]]
|
||||
--
|
||||
function SWEP:EjectionSmoke(ovrr)
|
||||
local retVal = hook.Run("TFA_EjectionSmoke",self)
|
||||
if retVal ~= nil then
|
||||
return retVal
|
||||
end
|
||||
if TFA.GetEJSmokeEnabled() and (self:GetStatL("EjectionSmokeEnabled") or ovrr) then
|
||||
local vm = self:IsFirstPerson() and self.OwnerViewModel or self
|
||||
|
||||
if IsValid(vm) then
|
||||
local att = vm:LookupAttachment(self:GetStatL("ShellAttachment"))
|
||||
|
||||
if not att or att <= 0 then
|
||||
att = 2
|
||||
end
|
||||
|
||||
local oldatt = att
|
||||
att = self:GetStatL("ShellAttachmentRaw", att)
|
||||
local angpos = vm:GetAttachment(att)
|
||||
|
||||
if not angpos then
|
||||
att = oldatt
|
||||
angpos = vm:GetAttachment(att)
|
||||
end
|
||||
|
||||
if angpos then
|
||||
fx = EffectData()
|
||||
fx:SetEntity(self)
|
||||
fx:SetOrigin(angpos.Pos)
|
||||
fx:SetAttachment(att)
|
||||
fx:SetNormal(angpos.Ang:Forward())
|
||||
TFA.Effects.Create("tfa_shelleject_smoke", fx)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--[[
|
||||
Function Name: ShootEffectsCustom
|
||||
Syntax: self:ShootEffectsCustom().
|
||||
Returns: Nothing.
|
||||
Notes: Calls the proper muzzleflash, muzzle smoke, muzzle light code.
|
||||
Purpose: FX
|
||||
]]
|
||||
--
|
||||
function SWEP:MuzzleSmoke(spv)
|
||||
local retVal = hook.Run("TFA_MuzzleSmoke",self)
|
||||
if retVal ~= nil then
|
||||
return retVal
|
||||
end
|
||||
if self.SmokeParticle == nil then
|
||||
self.SmokeParticle = self.SmokeParticles[self.DefaultHoldType or self.HoldType]
|
||||
end
|
||||
|
||||
if self:GetStatL("SmokeParticle") and self:GetStatL("SmokeParticle") ~= "" then
|
||||
self:UpdateMuzzleAttachment()
|
||||
local att = self:GetMuzzleAttachment()
|
||||
fx = EffectData()
|
||||
fx:SetOrigin(self:GetOwner():GetShootPos())
|
||||
fx:SetNormal(self:GetOwner():EyeAngles():Forward())
|
||||
fx:SetEntity(self)
|
||||
fx:SetAttachment(att)
|
||||
TFA.Effects.Create("tfa_muzzlesmoke", fx)
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:MuzzleFlashCustom(spv)
|
||||
local retVal = hook.Run("TFA_MuzzleFlash",self)
|
||||
if retVal ~= nil then
|
||||
return retVal
|
||||
end
|
||||
local att = self:GetMuzzleAttachment()
|
||||
fx = EffectData()
|
||||
fx:SetOrigin(self:GetOwner():GetShootPos())
|
||||
fx:SetNormal(self:GetOwner():EyeAngles():Forward())
|
||||
fx:SetEntity(self)
|
||||
fx:SetAttachment(att)
|
||||
local mzsil = self:GetStatL("MuzzleFlashEffectSilenced")
|
||||
|
||||
if (self:GetSilenced() and mzsil and mzsil ~= "") then
|
||||
TFA.Effects.Create(mzsil, fx)
|
||||
else
|
||||
TFA.Effects.Create(self:GetStatL("MuzzleFlashEffect", self.MuzzleFlashEffect or ""), fx)
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:ShootEffectsCustom(ifp)
|
||||
if self.DoMuzzleFlash ~= nil then
|
||||
self.MuzzleFlashEnabled = self.DoMuzzleFlash
|
||||
self.DoMuzzleFlash = nil
|
||||
end
|
||||
|
||||
if not self.MuzzleFlashEnabled then return end
|
||||
if self:IsFirstPerson() and not self:VMIV() then return end
|
||||
if not self:GetOwner().GetShootPos then return end
|
||||
ifp = ifp or IsFirstTimePredicted()
|
||||
|
||||
if (SERVER and sp and self.ParticleMuzzleFlash) or (SERVER and not sp) then
|
||||
net.Start("tfa_base_muzzle_mp", true)
|
||||
net.WriteEntity(self)
|
||||
|
||||
if sp or not self:GetOwner():IsPlayer() then
|
||||
net.SendPVS(self:GetPos())
|
||||
else
|
||||
net.SendOmit(self:GetOwner())
|
||||
end
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
if (CLIENT and ifp and not sp) or (sp and SERVER) then
|
||||
self:UpdateMuzzleAttachment()
|
||||
self:MuzzleFlashCustom(sp)
|
||||
self:MuzzleSmoke(sp)
|
||||
end
|
||||
end
|
||||
|
||||
--[[
|
||||
Function Name: CanDustEffect
|
||||
Syntax: self:CanDustEffect( concise material name ).
|
||||
Returns: True/False
|
||||
Notes: Used for the impact effect. Should be used with GetMaterialConcise.
|
||||
Purpose: Utility
|
||||
]]
|
||||
--
|
||||
local DustEffects = {
|
||||
[MAT_DIRT] = true,
|
||||
[MAT_CONCRETE] = true,
|
||||
[MAT_PLASTIC] = true,
|
||||
[MAT_WOOD] = true
|
||||
}
|
||||
function SWEP:CanDustEffect(matv)
|
||||
if DustEffects[matv] then return true end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
--[[
|
||||
Function Name: CanSparkEffect
|
||||
Syntax: self:CanSparkEffect( concise material name ).
|
||||
Returns: True/False
|
||||
Notes: Used for the impact effect. Should be used with GetMaterialConcise.
|
||||
Purpose: Utility
|
||||
]]
|
||||
--
|
||||
local SparkEffects = {
|
||||
[MAT_METAL] = true,
|
||||
[MAT_GRATE] = true,
|
||||
[MAT_VENT] = true
|
||||
}
|
||||
function SWEP:CanSparkEffect(matv)
|
||||
if SparkEffects[matv] then return true end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
-- Returns muzzle attachment position for HL2 tracers
|
||||
function SWEP:GetTracerOrigin(...)
|
||||
local att = self:GetMuzzleAttachment()
|
||||
|
||||
local attpos = (self:IsFirstPerson() and self.OwnerViewModel or self):GetAttachment(att)
|
||||
|
||||
if attpos and attpos.Pos then
|
||||
return attpos.Pos
|
||||
end
|
||||
end
|
||||
625
lua/weapons/tfa_gun_base/common/events.lua
Normal file
625
lua/weapons/tfa_gun_base/common/events.lua
Normal file
@@ -0,0 +1,625 @@
|
||||
--[[
|
||||
| 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 lshift = bit.lshift
|
||||
local band = bit.band
|
||||
local bor = bit.bor
|
||||
|
||||
local sp = game.SinglePlayer()
|
||||
local l_CT = CurTime
|
||||
|
||||
local is, spr, wlk, cst
|
||||
|
||||
--[[
|
||||
Function Name: ResetEvents
|
||||
Syntax: self:ResetEvents()
|
||||
Returns: Nothing.
|
||||
Purpose: Cleans up events table.
|
||||
]]--
|
||||
function SWEP:ResetEvents()
|
||||
self:SetEventStatus1(0x00000000)
|
||||
self:SetEventStatus2(0x00000000)
|
||||
self:SetEventStatus3(0x00000000)
|
||||
self:SetEventStatus4(0x00000000)
|
||||
self:SetEventStatus5(0x00000000)
|
||||
self:SetEventStatus6(0x00000000)
|
||||
self:SetEventStatus7(0x00000000)
|
||||
self:SetEventStatus8(0x00000000)
|
||||
|
||||
self:SetEventTimer(l_CT())
|
||||
-- self:SetFirstDeployEvent(false)
|
||||
|
||||
if self.EventTable then
|
||||
for _, eventtable in pairs(self.EventTable) do
|
||||
for i = 1, #eventtable do
|
||||
eventtable[i].called = false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if self.event_table_overflow then
|
||||
local editcts = self.EventTableEdict
|
||||
|
||||
if editcts[0] then
|
||||
editcts[0].called = false
|
||||
|
||||
for i = 1, #editcts do
|
||||
editcts[i].called = false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if sp then
|
||||
self:CallOnClient("ResetEvents", "")
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:GetEventPlayed(event_slot)
|
||||
if self.event_table_overflow then
|
||||
return assert(self.EventTableEdict[event_slot], string.format("Unknown event %d", event_slot)).called
|
||||
end
|
||||
|
||||
local inner_index = event_slot % 32
|
||||
local outer_index = (event_slot - inner_index) / 32 + 1
|
||||
local lindex = lshift(1, inner_index)
|
||||
return band(self.get_event_status_lut[outer_index](self), lindex) ~= 0, inner_index, outer_index, lindex
|
||||
end
|
||||
|
||||
function SWEP:SetEventPlayed(event_slot)
|
||||
if self.event_table_overflow then
|
||||
assert(self.EventTableEdict[event_slot], string.format("Unknown event %d", event_slot)).called = true
|
||||
return
|
||||
end
|
||||
|
||||
local inner_index = event_slot % 32
|
||||
local outer_index = (event_slot - inner_index) / 32 + 1
|
||||
local lindex = lshift(1, inner_index)
|
||||
|
||||
self.set_event_status_lut[outer_index](self, bor(self.get_event_status_lut[outer_index](self), lindex))
|
||||
return inner_index, outer_index, lindex
|
||||
end
|
||||
|
||||
--[[
|
||||
Function Name: ProcessEvents
|
||||
Syntax: self:ProcessEvents().
|
||||
Returns: Nothing.
|
||||
Notes: Critical for the event table to function.
|
||||
Purpose: Main SWEP function
|
||||
]]--
|
||||
|
||||
SWEP._EventSlotCount = 0
|
||||
SWEP.EventTableEdict = {}
|
||||
|
||||
function SWEP:DispatchLuaEvent(arg)
|
||||
if not self.event_table_built then
|
||||
self:RebuildEventEdictTable()
|
||||
end
|
||||
|
||||
local fn = assert(assert(self.EventTableEdict[tonumber(arg)], "No such event with edict " .. arg).value, "Event is missing a function to call")
|
||||
assert(isfunction(fn), "Event " .. arg .. " is not a Lua event")
|
||||
fn(self, self:VMIV(), true)
|
||||
end
|
||||
|
||||
function SWEP:DispatchBodygroupEvent(arg)
|
||||
if not self.event_table_built then
|
||||
self:RebuildEventEdictTable()
|
||||
end
|
||||
|
||||
local event = assert(self.EventTableEdict[tonumber(arg)], "No such event with edict " .. arg)
|
||||
assert(isstring(event.name), "Event " .. arg .. " is missing bodygroup name to set")
|
||||
assert(isstring(event.value), "Event " .. arg .. " is missing bodygroup value to set")
|
||||
|
||||
if event.view then
|
||||
self.ViewModelBodygroups[event.name] = event.value
|
||||
end
|
||||
|
||||
if event.world then
|
||||
self.WorldModelBodygroups[event.name] = event.value
|
||||
end
|
||||
end
|
||||
|
||||
local isstring = isstring
|
||||
|
||||
local function eventtablesorter(a, b)
|
||||
local sa, sb = isstring(a), isstring(b)
|
||||
|
||||
if sa and not sb or not sa and sb then
|
||||
if sa then
|
||||
return false
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
return a < b
|
||||
end
|
||||
|
||||
function SWEP:RebuildEventEdictTable()
|
||||
local self2 = self:GetTable()
|
||||
local slot = 0
|
||||
|
||||
for i = #self2.EventTableEdict, 0, -1 do
|
||||
self2.EventTableEdict[i] = nil
|
||||
end
|
||||
|
||||
self:ResetEvents()
|
||||
|
||||
local eventtable = self2.EventTable
|
||||
local keys = table.GetKeys(eventtable)
|
||||
table.sort(keys, eventtablesorter)
|
||||
|
||||
for _, key in ipairs(keys) do
|
||||
local value = eventtable[key]
|
||||
|
||||
if istable(value) then
|
||||
for _, event in SortedPairs(value) do
|
||||
if istable(event) then
|
||||
event.slot = slot
|
||||
slot = slot + 1
|
||||
|
||||
if not event.autodetect then
|
||||
if event.type == "lua" then
|
||||
if event.server == nil then
|
||||
event.server = true
|
||||
end
|
||||
elseif event.type == "snd" or event.type == "sound" then
|
||||
if event.server == nil then
|
||||
event.server = false
|
||||
end
|
||||
elseif event.type == "bg" or event.type == "bodygroup" then
|
||||
if event.server == nil then event.server = true end
|
||||
if event.view == nil then event.view = true end
|
||||
if event.world == nil then event.world = true end
|
||||
end
|
||||
|
||||
if event.client == nil then
|
||||
event.client = true
|
||||
end
|
||||
|
||||
event.autodetect = true
|
||||
end
|
||||
|
||||
event.called = false
|
||||
|
||||
if slot > 256 and not self.event_table_warning then
|
||||
ErrorNoHalt("[TFA Base] Weapon " .. self:GetClass() .. " got too many events! 256 is maximum! Event table would NOT be properly predicted this time!\n")
|
||||
self.event_table_warning = true
|
||||
end
|
||||
|
||||
self2.EventTableEdict[event.slot] = event
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
self.event_table_overflow = slot > 256
|
||||
self._built_event_debug_string_fn = nil
|
||||
|
||||
self._EventSlotCount = math.ceil(slot / 32)
|
||||
self._EventSlotNum = slot - 1
|
||||
self.event_table_built = true
|
||||
end
|
||||
|
||||
function SWEP:ProcessEvents(firstprediction)
|
||||
local viewmodel = self:VMIVNPC()
|
||||
if not viewmodel then return end
|
||||
|
||||
if not self.event_table_built then
|
||||
self:RebuildEventEdictTable()
|
||||
end
|
||||
|
||||
if sp and CLIENT then return end
|
||||
if sp and SERVER then return self:ProcessEventsSP() end
|
||||
|
||||
local ply = self:GetOwner()
|
||||
local isplayer = ply:IsPlayer()
|
||||
|
||||
local evtbl = self.EventTable[self:GetLastActivity() or -1] or self.EventTable[viewmodel:GetSequenceName(viewmodel:GetSequence())]
|
||||
if not evtbl then return end
|
||||
|
||||
local curtime = l_CT()
|
||||
local eventtimer = self:GetEventTimer()
|
||||
local is_local = CLIENT and ply == LocalPlayer()
|
||||
local animrate = self:GetAnimationRate(self:GetLastActivity() or -1)
|
||||
|
||||
self.current_event_iftp = firstprediction
|
||||
self.processing_events = true
|
||||
|
||||
for i = 1, #evtbl do
|
||||
local event = evtbl[i]
|
||||
if self:GetEventPlayed(event.slot) or curtime < eventtimer + event.time / animrate then goto CONTINUE end
|
||||
self:SetEventPlayed(event.slot)
|
||||
event.called = true
|
||||
|
||||
if not event.autodetect then
|
||||
if event.type == "lua" then
|
||||
if event.server == nil then
|
||||
event.server = true
|
||||
end
|
||||
elseif event.type == "snd" or event.type == "sound" then
|
||||
if event.server == nil then
|
||||
event.server = false
|
||||
end
|
||||
elseif event.type == "bg" or event.type == "bodygroup" then
|
||||
if event.server == nil then event.server = true end
|
||||
if event.view == nil then event.view = true end
|
||||
if event.world == nil then event.world = true end
|
||||
end
|
||||
|
||||
if event.client == nil then
|
||||
event.client = true
|
||||
end
|
||||
|
||||
event.autodetect = true
|
||||
end
|
||||
|
||||
if event.type == "lua" then
|
||||
if ((event.client and CLIENT and (not event.client_predictedonly or is_local)) or (event.server and SERVER)) and event.value then
|
||||
event.value(self, viewmodel, firstprediction)
|
||||
end
|
||||
elseif event.type == "snd" or event.type == "sound" then
|
||||
if SERVER then
|
||||
if event.client then
|
||||
if not isplayer and player.GetCount() ~= 0 then
|
||||
net.Start("tfaSoundEvent", true)
|
||||
net.WriteEntity(self)
|
||||
net.WriteString(event.value or "")
|
||||
net.SendPVS(self:GetPos())
|
||||
elseif isplayer then
|
||||
net.Start("tfaSoundEvent", true)
|
||||
net.WriteEntity(self)
|
||||
net.WriteString(event.value or "")
|
||||
net.SendOmit(ply)
|
||||
end
|
||||
elseif event.server and event.value and event.value ~= "" then
|
||||
self:EmitSound(event.value)
|
||||
end
|
||||
elseif event.client and is_local and not sp and event.value and event.value ~= "" then
|
||||
if firstprediction or firstprediction == nil then
|
||||
if event.time <= 0.01 then
|
||||
self:EmitSoundSafe(event.value)
|
||||
else
|
||||
self:EmitSound(event.value)
|
||||
end
|
||||
end
|
||||
end
|
||||
elseif event.type == "bg" or event.type == "bodygroup" then
|
||||
if ((event.client and CLIENT and (not event.client_predictedonly or is_local)) or
|
||||
(event.server and SERVER)) and (event.name and event.value and event.value ~= "") then
|
||||
|
||||
if event.view then
|
||||
self.ViewModelBodygroups[event.name] = event.value
|
||||
end
|
||||
|
||||
if event.world then
|
||||
self.WorldModelBodygroups[event.name] = event.value
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
::CONTINUE::
|
||||
end
|
||||
|
||||
self.processing_events = false
|
||||
self.current_event_iftp = nil
|
||||
end
|
||||
|
||||
-- This function is exclusively targeting singleplayer
|
||||
function SWEP:ProcessEventsSP(firstprediction)
|
||||
local viewmodel = self:VMIVNPC()
|
||||
if not viewmodel then return end
|
||||
|
||||
local evtbl = self.EventTable[self:GetLastActivity() or -1] or self.EventTable[viewmodel:GetSequenceName(viewmodel:GetSequence())]
|
||||
if not evtbl then return end
|
||||
|
||||
local curtime = l_CT()
|
||||
local eventtimer = self:GetEventTimer()
|
||||
local is_local = self:GetOwner() == Entity(1)
|
||||
local animrate = self:GetAnimationRate(self:GetLastActivity() or -1)
|
||||
|
||||
self.processing_events = true
|
||||
|
||||
for i = 1, #evtbl do
|
||||
local event = evtbl[i]
|
||||
if self:GetEventPlayed(event.slot) or curtime < eventtimer + event.time / animrate then goto CONTINUE end
|
||||
self:SetEventPlayed(event.slot)
|
||||
event.called = true
|
||||
|
||||
if not event.autodetect then
|
||||
if event.type == "lua" then
|
||||
if event.server == nil then
|
||||
event.server = true
|
||||
end
|
||||
elseif event.type == "snd" or event.type == "sound" then
|
||||
if event.server == nil then
|
||||
event.server = false
|
||||
end
|
||||
elseif event.type == "bg" or event.type == "bodygroup" then
|
||||
if event.server == nil then event.server = true end
|
||||
if event.view == nil then event.view = true end
|
||||
if event.world == nil then event.world = true end
|
||||
end
|
||||
|
||||
if event.client == nil then
|
||||
event.client = true
|
||||
end
|
||||
|
||||
event.autodetect = true
|
||||
end
|
||||
|
||||
if event.type == "lua" then
|
||||
if event.value then
|
||||
if event.server then
|
||||
event.value(self, viewmodel, true)
|
||||
end
|
||||
|
||||
if event.client and (not event.client_predictedonly or is_local) then
|
||||
self:CallOnClient("DispatchLuaEvent", tostring(event.slot))
|
||||
end
|
||||
end
|
||||
elseif event.type == "snd" or event.type == "sound" then
|
||||
if event.client then
|
||||
net.Start("tfaSoundEvent", true)
|
||||
net.WriteEntity(self)
|
||||
net.WriteString(event.value or "")
|
||||
net.Broadcast()
|
||||
elseif event.server and event.value and event.value ~= "" then
|
||||
self:EmitSound(event.value)
|
||||
end
|
||||
elseif event.type == "bg" or event.type == "bodygroup" then
|
||||
if event.name and event.value and event.value ~= "" then
|
||||
if event.server then
|
||||
if event.view then
|
||||
self.ViewModelBodygroups[event.name] = event.value
|
||||
end
|
||||
|
||||
if event.world then
|
||||
self.WorldModelBodygroups[event.name] = event.value
|
||||
end
|
||||
end
|
||||
|
||||
if event.client and (not event.client_predictedonly or is_local) then
|
||||
self:CallOnClient("DispatchBodygroupEvent", tostring(event.slot))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
::CONTINUE::
|
||||
end
|
||||
|
||||
self.processing_events = false
|
||||
end
|
||||
|
||||
function SWEP:EmitSoundSafe(snd)
|
||||
timer.Simple(0, function()
|
||||
if IsValid(self) and snd then self:EmitSound(snd) end
|
||||
end)
|
||||
end
|
||||
|
||||
local ct, stat, statend, finalstat, waittime, lact
|
||||
|
||||
function SWEP:ProcessStatus()
|
||||
local self2 = self:GetTable()
|
||||
|
||||
is = self2.GetIronSightsRaw(self)
|
||||
spr = self2.GetSprinting(self)
|
||||
wlk = self2.GetWalking(self)
|
||||
cst = self2.GetCustomizing(self)
|
||||
|
||||
local ply = self:GetOwner()
|
||||
local isplayer = ply:IsPlayer()
|
||||
|
||||
if stat == TFA.Enum.STATUS_FIDGET and is then
|
||||
self:SetStatusEnd(0)
|
||||
|
||||
self2.Idle_Mode_Old = self2.Idle_Mode
|
||||
self2.Idle_Mode = TFA.Enum.IDLE_BOTH
|
||||
self2.ChooseIdleAnim(self)
|
||||
|
||||
if sp then
|
||||
self:CallOnClient("ChooseIdleAnim", "")
|
||||
end
|
||||
|
||||
self2.Idle_Mode = self2.Idle_Mode_Old
|
||||
self2.Idle_Mode_Old = nil
|
||||
statend = -1
|
||||
end
|
||||
|
||||
is = self:GetIronSights()
|
||||
stat = self:GetStatus()
|
||||
statend = self:GetStatusEnd()
|
||||
|
||||
ct = l_CT()
|
||||
|
||||
if stat ~= TFA.Enum.STATUS_IDLE and ct > statend then
|
||||
self:SetFirstDeployEvent(false)
|
||||
finalstat = TFA.Enum.STATUS_IDLE
|
||||
|
||||
--Holstering
|
||||
if stat == TFA.Enum.STATUS_HOLSTER then
|
||||
finalstat = TFA.Enum.STATUS_HOLSTER_READY
|
||||
self:SetStatusEnd(ct)
|
||||
elseif stat == TFA.Enum.STATUS_HOLSTER_READY then
|
||||
self2.FinishHolster(self)
|
||||
finalstat = TFA.Enum.STATUS_HOLSTER_FINAL
|
||||
self:SetStatusEnd(ct + 0.6)
|
||||
elseif stat == TFA.Enum.STATUS_RELOADING_LOOP_START_EMPTY then
|
||||
--Shotgun Reloading from empty
|
||||
if not self2.IsJammed(self) then
|
||||
self2.TakePrimaryAmmo(self, 1, true)
|
||||
self2.TakePrimaryAmmo(self, -1)
|
||||
end
|
||||
|
||||
if self2.Ammo1(self) <= 0 or self:Clip1() >= self2.GetPrimaryClipSize(self) or self:GetReloadLoopCancel() then
|
||||
finalstat = TFA.Enum.STATUS_RELOADING_LOOP_END
|
||||
local _, tanim = self2.ChooseShotgunPumpAnim(self)
|
||||
self:SetStatusEnd(ct + self:GetActivityLength(tanim))
|
||||
self:SetReloadLoopCancel(false)
|
||||
|
||||
if not self:GetReloadLoopCancel() then
|
||||
self:SetJammed(false)
|
||||
end
|
||||
else
|
||||
lact = self:GetLastActivity()
|
||||
waittime = self2.GetActivityLength(self, lact, false) - self2.GetActivityLength(self, lact, true)
|
||||
|
||||
if waittime > 0.01 then
|
||||
finalstat = TFA.Enum.STATUS_RELOADING_WAIT
|
||||
self:SetStatusEnd(ct + waittime)
|
||||
else
|
||||
finalstat = self2.LoadShell(self)
|
||||
end
|
||||
|
||||
self:SetJammed(false)
|
||||
--finalstat = self:LoadShell()
|
||||
--self:SetStatusEnd( self:GetNextPrimaryFire() )
|
||||
end
|
||||
elseif stat == TFA.Enum.STATUS_RELOADING_LOOP_START then
|
||||
--Shotgun Reloading
|
||||
finalstat = self2.LoadShell(self)
|
||||
elseif stat == TFA.Enum.STATUS_RELOADING_LOOP then
|
||||
self2.TakePrimaryAmmo(self, 1, true)
|
||||
self2.TakePrimaryAmmo(self, -1)
|
||||
lact = self:GetLastActivity()
|
||||
|
||||
if self2.GetActivityLength(self, lact, true) < self2.GetActivityLength(self, lact, false) - 0.01 then
|
||||
local sht = self2.GetStatL(self, "LoopedReloadInsertTime")
|
||||
|
||||
if sht then
|
||||
sht = sht / self2.GetAnimationRate(self, ACT_VM_RELOAD)
|
||||
end
|
||||
|
||||
waittime = (sht or self2.GetActivityLength(self, lact, false)) - self2.GetActivityLength(self, lact, true)
|
||||
else
|
||||
waittime = 0
|
||||
end
|
||||
|
||||
if waittime > 0.01 then
|
||||
finalstat = TFA.Enum.STATUS_RELOADING_WAIT
|
||||
self:SetStatusEnd(ct + waittime)
|
||||
else
|
||||
if self2.Ammo1(self) <= 0 or self:Clip1() >= self:GetPrimaryClipSize() or self:GetReloadLoopCancel() then
|
||||
finalstat = TFA.Enum.STATUS_RELOADING_LOOP_END
|
||||
local _, tanim = self2.ChooseShotgunPumpAnim(self)
|
||||
self:SetStatusEnd(ct + self:GetActivityLength(tanim))
|
||||
self:SetReloadLoopCancel(false)
|
||||
else
|
||||
finalstat = self2.LoadShell(self)
|
||||
end
|
||||
end
|
||||
elseif stat == TFA.Enum.STATUS_RELOADING then
|
||||
self2.CompleteReload(self)
|
||||
lact = self:GetLastActivity()
|
||||
waittime = self2.GetActivityLength(self, lact, false) - self2.GetActivityLength(self, lact, true)
|
||||
|
||||
if waittime > 0.01 then
|
||||
finalstat = TFA.Enum.STATUS_RELOADING_WAIT
|
||||
self:SetStatusEnd(ct + waittime)
|
||||
end
|
||||
elseif stat == TFA.Enum.STATUS_SILENCER_TOGGLE then
|
||||
--self:SetStatusEnd( self:GetNextPrimaryFire() )
|
||||
self:SetSilenced(not self:GetSilenced())
|
||||
self2.Silenced = self:GetSilenced()
|
||||
elseif stat == TFA.Enum.STATUS_RELOADING_WAIT and self:GetStatL("LoopedReload") then
|
||||
if self2.Ammo1(self) <= 0 or self:Clip1() >= self:GetPrimaryClipSize() or self:GetReloadLoopCancel() then
|
||||
finalstat = TFA.Enum.STATUS_RELOADING_LOOP_END
|
||||
local _, tanim = self2.ChooseShotgunPumpAnim(self)
|
||||
self:SetStatusEnd(ct + self:GetActivityLength(tanim))
|
||||
--self:SetReloadLoopCancel( false )
|
||||
else
|
||||
finalstat = self2.LoadShell(self)
|
||||
end
|
||||
elseif stat == TFA.Enum.STATUS_RELOADING_LOOP_END and self:GetStatL("LoopedReload") then
|
||||
self:SetReloadLoopCancel(false)
|
||||
elseif self2.GetStatL(self, "PumpAction") and stat == TFA.Enum.STATUS_PUMP then
|
||||
self:SetReloadLoopCancel(false)
|
||||
elseif stat == TFA.Enum.STATUS_SHOOTING and self2.GetStatL(self, "PumpAction") then
|
||||
if self:Clip1() == 0 and self2.GetStatL(self, "PumpAction").value_empty then
|
||||
--finalstat = TFA.Enum.STATUS_PUMP_READY
|
||||
self:SetReloadLoopCancel(true)
|
||||
elseif (self2.GetStatL(self, "Primary.ClipSize") < 0 or self:Clip1() > 0) and self2.GetStatL(self, "PumpAction").value then
|
||||
--finalstat = TFA.Enum.STATUS_PUMP_READY
|
||||
self:SetReloadLoopCancel(true)
|
||||
end
|
||||
end
|
||||
|
||||
--self:SetStatusEnd( math.huge )
|
||||
self:SetStatus(finalstat)
|
||||
local smi = self2.Sights_Mode == TFA.Enum.LOCOMOTION_HYBRID or self2.Sights_Mode == TFA.Enum.LOCOMOTION_ANI
|
||||
local spi = self2.Sprint_Mode == TFA.Enum.LOCOMOTION_HYBRID or self2.Sprint_Mode == TFA.Enum.LOCOMOTION_ANI
|
||||
local wmi = self2.Walk_Mode == TFA.Enum.LOCOMOTION_HYBRID or self2.Walk_Mode == TFA.Enum.LOCOMOTION_ANI
|
||||
local cmi = self2.Customize_Mode == TFA.Enum.LOCOMOTION_HYBRID or self2.Customize_Mode == TFA.Enum.LOCOMOTION_ANI
|
||||
|
||||
if
|
||||
not TFA.Enum.ReadyStatus[stat] and
|
||||
stat ~= TFA.Enum.STATUS_SHOOTING and
|
||||
stat ~= TFA.Enum.STATUS_PUMP and
|
||||
finalstat == TFA.Enum.STATUS_IDLE and
|
||||
((smi or spi) or (cst and cmi))
|
||||
then
|
||||
is = self2.GetIronSights(self, true)
|
||||
|
||||
if (is and smi) or (spr and spi) or (wlk and wmi) or (cst and cmi) then
|
||||
local success, _ = self2.Locomote(self, is and smi, is, spr and spi, spr, wlk and wmi, wlk, cst and cmi, cst)
|
||||
|
||||
if success == false then
|
||||
self:SetNextIdleAnim(-1)
|
||||
else
|
||||
self:SetNextIdleAnim(math.max(self:GetNextIdleAnim(), ct + 0.1))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
self2.LastBoltShoot = nil
|
||||
|
||||
if self:GetBurstCount() > 0 then
|
||||
if finalstat ~= TFA.Enum.STATUS_SHOOTING and finalstat ~= TFA.Enum.STATUS_IDLE then
|
||||
self:SetBurstCount(0)
|
||||
elseif self:GetBurstCount() < self:GetMaxBurst() and self:Clip1() > 0 then
|
||||
self:PrimaryAttack()
|
||||
else
|
||||
self:SetBurstCount(0)
|
||||
self:SetNextPrimaryFire(self2.GetNextCorrectedPrimaryFire(self, self2.GetBurstDelay(self)))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--if stat == TFA.Enum.STATUS_IDLE and self:GetReloadLoopCancel() and (self2.GetStatL(self, "AllowSprintAttack") or self:GetSprintProgress() < 0.1) then
|
||||
if stat == TFA.Enum.STATUS_IDLE and self:GetReloadLoopCancel() then
|
||||
if self2.GetStatL(self, "PumpAction") then
|
||||
if ct > self:GetNextPrimaryFire() and not self:KeyDown(IN_ATTACK) then
|
||||
self2.DoPump(self)
|
||||
end
|
||||
else
|
||||
self:SetReloadLoopCancel(false)
|
||||
end
|
||||
end
|
||||
end
|
||||
126
lua/weapons/tfa_gun_base/common/nzombies.lua
Normal file
126
lua/weapons/tfa_gun_base/common/nzombies.lua
Normal file
@@ -0,0 +1,126 @@
|
||||
--[[
|
||||
| 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.
|
||||
|
||||
SWEP.OldPaP = false
|
||||
SWEP.OldSpCola = false
|
||||
SWEP.SpeedColaFactor = 2 --Amount to speed up by when u get dat speed cola
|
||||
SWEP.SpeedColaActivities = {
|
||||
[ACT_VM_DRAW] = true,
|
||||
[ACT_VM_DRAW_EMPTY] = true,
|
||||
[ACT_VM_DRAW_SILENCED] = true,
|
||||
[ACT_VM_DRAW_DEPLOYED or 0] = true,
|
||||
[ACT_VM_RELOAD] = true,
|
||||
[ACT_VM_RELOAD_EMPTY] = true,
|
||||
[ACT_VM_RELOAD_SILENCED] = true,
|
||||
[ACT_VM_HOLSTER] = true,
|
||||
[ACT_VM_HOLSTER_EMPTY] = true,
|
||||
[ACT_VM_HOLSTER_SILENCED] = true,
|
||||
[ACT_SHOTGUN_RELOAD_START] = true,
|
||||
[ACT_SHOTGUN_RELOAD_FINISH] = true
|
||||
}
|
||||
SWEP.DTapActivities = {
|
||||
[ACT_VM_PRIMARYATTACK] = true,
|
||||
[ACT_VM_PRIMARYATTACK_EMPTY] = true,
|
||||
[ACT_VM_PRIMARYATTACK_SILENCED] = true,
|
||||
[ACT_VM_PRIMARYATTACK_1] = true,
|
||||
[ACT_VM_SECONDARYATTACK] = true,
|
||||
[ACT_VM_HITCENTER] = true,
|
||||
[ACT_SHOTGUN_PUMP] = true
|
||||
}
|
||||
SWEP.DTapSpeed = 1 / 0.8
|
||||
SWEP.DTap2Speed = 1 / 0.8
|
||||
|
||||
local nzombies
|
||||
|
||||
local count, upperclamp
|
||||
|
||||
function SWEP:NZMaxAmmo()
|
||||
if nzombies == nil then
|
||||
nzombies = engine.ActiveGamemode() == "nzombies"
|
||||
end
|
||||
local at = self:GetPrimaryAmmoType()
|
||||
local at2 = self.GetSecondaryAmmoType and self:GetSecondaryAmmoType() or self.Secondary_TFA.Ammo
|
||||
|
||||
if IsValid(self:GetOwner()) then
|
||||
if self:GetStatL("Primary.ClipSize") <= 0 then
|
||||
count = math.Clamp(10, 300 / (self:GetStatL("Primary.Damage") / 30), 10, 300)
|
||||
if self.Primary_TFA.NZMaxAmmo and self.Primary_TFA.NZMaxAmmo > 0 then
|
||||
count = self.Primary_TFA.NZMaxAmmo
|
||||
if self:GetPaP() then
|
||||
count = count * 5 / 3
|
||||
end
|
||||
end
|
||||
self:GetOwner():SetAmmo(count, at)
|
||||
else
|
||||
upperclamp = self:GetPaP() and 600 or 300
|
||||
count = math.Clamp(math.abs(self:GetStatL("Primary.ClipSize")) * 10, 10, upperclamp)
|
||||
count = count + self:GetStatL("Primary.ClipSize") - self:Clip1()
|
||||
if self.Primary_TFA.NZMaxAmmo and self.Primary_TFA.NZMaxAmmo > 0 then
|
||||
count = self.Primary_TFA.NZMaxAmmo
|
||||
if self:GetPaP() then
|
||||
count = count * 5 / 3
|
||||
end
|
||||
end
|
||||
self:GetOwner():SetAmmo(count, at)
|
||||
end
|
||||
if self:GetStatL("Secondary.ClipSize") > 0 or self:GetSecondaryAmmoType() >= 0 then
|
||||
if self:GetStatL("Secondary.ClipSize") <= 0 then
|
||||
count = math.ceil( math.Clamp(10, 300 / math.pow( ( self:GetStatL("Secondary.Damage") or 100 ) / 30, 2 ), 10, 300) / 5 ) * 5
|
||||
if self.Secondary_TFA.NZMaxAmmo and self.Secondary_TFA.NZMaxAmmo > 0 then
|
||||
count = self.Secondary_TFA.NZMaxAmmo
|
||||
if self:GetPaP() then
|
||||
count = count * 5 / 3
|
||||
end
|
||||
end
|
||||
self:GetOwner():SetAmmo(count, at2)
|
||||
else
|
||||
upperclamp = self:GetPaP() and 600 or 300
|
||||
count = math.Clamp(math.abs(self:GetStatL("Secondary.ClipSize")) * 10, 10, upperclamp)
|
||||
count = count + self:GetStatL("Secondary.ClipSize") - self:Clip2()
|
||||
if self.Secondary_TFA.NZMaxAmmo and self.Secondary_TFA.NZMaxAmmo > 0 then
|
||||
count = self.Secondary_TFA.NZMaxAmmo
|
||||
if self:GetPaP() then
|
||||
count = count * 5 / 3
|
||||
end
|
||||
end
|
||||
self:GetOwner():SetAmmo(count, at2)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:GetPaP()
|
||||
return ( self.HasNZModifier and self:HasNZModifier("pap") ) or self.pap or false
|
||||
end
|
||||
|
||||
function SWEP:IsPaP()
|
||||
return self:GetPaP()
|
||||
end
|
||||
69
lua/weapons/tfa_gun_base/common/skins.lua
Normal file
69
lua/weapons/tfa_gun_base/common/skins.lua
Normal file
@@ -0,0 +1,69 @@
|
||||
--[[
|
||||
| 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.
|
||||
|
||||
SWEP.MaterialTable = {}
|
||||
SWEP.MaterialTable_V = {}
|
||||
SWEP.MaterialTable_W = {}
|
||||
|
||||
function SWEP:InitializeMaterialTable()
|
||||
if not self.HasSetMaterialMeta then
|
||||
setmetatable(self.MaterialTable_V, {
|
||||
["__index"] = function(t,k) return self:GetStatL("MaterialTable")[k] end
|
||||
})
|
||||
|
||||
setmetatable(self.MaterialTable_W, {
|
||||
["__index"] = function(t,k) return self:GetStatL("MaterialTable")[k] end
|
||||
})
|
||||
|
||||
self.HasSetMaterialMeta = true
|
||||
end
|
||||
end
|
||||
|
||||
--if both nil then we can just clear it all
|
||||
function SWEP:ClearMaterialCache(view, world)
|
||||
if view == nil and world == nil then
|
||||
self.MaterialCached_V = nil
|
||||
self.MaterialCached_W = nil
|
||||
self.MaterialCached = nil
|
||||
self.SCKMaterialCached_V = nil
|
||||
self.SCKMaterialCached_W = nil
|
||||
else
|
||||
if view then
|
||||
self.MaterialCached_V = nil
|
||||
self.SCKMaterialCached_V = nil
|
||||
end
|
||||
|
||||
if world then
|
||||
self.MaterialCached_W = nil
|
||||
self.SCKMaterialCached_W = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
413
lua/weapons/tfa_gun_base/common/stat.lua
Normal file
413
lua/weapons/tfa_gun_base/common/stat.lua
Normal file
@@ -0,0 +1,413 @@
|
||||
--[[
|
||||
| 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 tableCopy = table.Copy
|
||||
|
||||
function SWEP:GetStatRecursive(srctbl, stbl, ...)
|
||||
local val = srctbl[stbl[1]]
|
||||
for i = 2, #stbl do
|
||||
if (val) then
|
||||
val = val[stbl[i]]
|
||||
else
|
||||
return true, ...
|
||||
end
|
||||
end
|
||||
|
||||
if val == nil then
|
||||
return true, ...
|
||||
end
|
||||
|
||||
if istable(val) and val.functionTable then
|
||||
local currentStat, isFinal, nocache, nct
|
||||
nocache = false
|
||||
|
||||
for i = 1, #val do
|
||||
local v = val[i]
|
||||
|
||||
if isfunction(v) then
|
||||
if currentStat == nil then
|
||||
currentStat, isFinal, nct = v(self, ...)
|
||||
else
|
||||
currentStat, isFinal, nct = v(self, currentStat)
|
||||
end
|
||||
|
||||
nocache = nocache or nct
|
||||
|
||||
if isFinal then break end
|
||||
elseif v then
|
||||
currentStat = v
|
||||
end
|
||||
end
|
||||
|
||||
if currentStat ~= nil then
|
||||
return false, currentStat, nocache
|
||||
end
|
||||
|
||||
return true, ...
|
||||
end
|
||||
|
||||
return false, val
|
||||
end
|
||||
|
||||
SWEP.StatCache_Blacklist = {
|
||||
["ViewModelBoneMods"] = true,
|
||||
["WorldModelBoneMods"] = true,
|
||||
["MaterialTable"] = true,
|
||||
["MaterialTable_V"] = true,
|
||||
["MaterialTable_W"] = true,
|
||||
["ViewModelBodygroups"] = true,
|
||||
["Bodygroups_V"] = true,
|
||||
["WorldModelBodygroups"] = true,
|
||||
["Skin"] = true
|
||||
}
|
||||
|
||||
SWEP.StatCache = {}
|
||||
SWEP.StatCache2 = {}
|
||||
SWEP.StatStringCache = {}
|
||||
|
||||
SWEP.LastClearStatCache = 0
|
||||
SWEP.ClearStatCacheWarnCount = 0
|
||||
SWEP.ClearStatCacheWarned = false
|
||||
|
||||
local IdealCSCDeltaTime = engine.TickInterval() * 2
|
||||
|
||||
local LatestDataVersion = TFA.LatestDataVersion
|
||||
|
||||
function SWEP:ClearStatCache(vn)
|
||||
return self:ClearStatCacheVersioned(vn, 0)
|
||||
end
|
||||
|
||||
function SWEP:ClearStatCacheL(vn)
|
||||
return self:ClearStatCacheVersioned(vn, LatestDataVersion)
|
||||
end
|
||||
|
||||
local trigger_lut_rebuild = {
|
||||
FalloffMetricBased = true,
|
||||
Range = true,
|
||||
RangeFalloff = true,
|
||||
}
|
||||
|
||||
function SWEP:ClearStatCacheVersioned(vn, path_version)
|
||||
local self2 = self:GetTable()
|
||||
self2.ignore_stat_cache = true
|
||||
local getpath, getpath2
|
||||
|
||||
if isstring(vn) then
|
||||
vn = TFA.RemapStatPath(vn, path_version, self.TFADataVersion)
|
||||
end
|
||||
|
||||
if not vn and not self2.ClearStatCacheWarned then
|
||||
local ct = CurTime()
|
||||
local delta = ct - self2.LastClearStatCache
|
||||
|
||||
if delta < IdealCSCDeltaTime and debug.traceback():find("Think2") then
|
||||
self2.ClearStatCacheWarnCount = self2.ClearStatCacheWarnCount + 1
|
||||
|
||||
if self2.ClearStatCacheWarnCount >= 5 then
|
||||
self2.ClearStatCacheWarned = true
|
||||
|
||||
print(("[TFA Base] Weapon %s (%s) is abusing ClearStatCache function from Think2! This will lead to really bad performance issues, tell weapon's author to fix it ASAP!"):format(self2.PrintName, self:GetClass()))
|
||||
end
|
||||
elseif self2.ClearStatCacheWarnCount > 0 then
|
||||
self2.ClearStatCacheWarnCount = 0
|
||||
end
|
||||
|
||||
self2.LastClearStatCache = ct
|
||||
end
|
||||
|
||||
if vn then
|
||||
local list = TFA.GetStatPathChildren(vn, path_version, self.TFADataVersion)
|
||||
|
||||
for i = 1, #list do
|
||||
self2.StatCache[list[i]] = nil
|
||||
self2.StatCache2[list[i]] = nil
|
||||
end
|
||||
|
||||
getpath2 = self2.GetStatPath(self, vn)
|
||||
getpath = getpath2[1]
|
||||
else
|
||||
table.Empty(self2.StatCache)
|
||||
table.Empty(self2.StatCache2)
|
||||
end
|
||||
|
||||
if vn == "Primary" or not vn then
|
||||
table.Empty(self2.Primary)
|
||||
|
||||
local temp = {}
|
||||
|
||||
setmetatable(self2.Primary, {
|
||||
__index = function(self3, key)
|
||||
return self2.GetStatVersioned(self, "Primary." .. key, self2.TFADataVersion)
|
||||
end,
|
||||
|
||||
__newindex = function() end
|
||||
})
|
||||
|
||||
for k in pairs(self2.Primary_TFA) do
|
||||
if isstring(k) then
|
||||
temp[k] = self2.GetStatVersioned(self, "Primary." .. k, self2.TFADataVersion)
|
||||
end
|
||||
end
|
||||
|
||||
setmetatable(self2.Primary, nil)
|
||||
|
||||
for k, v in pairs(temp) do
|
||||
self2.Primary[k] = v
|
||||
end
|
||||
|
||||
if self2.Primary_TFA.RangeFalloffLUT_IsConverted then
|
||||
self2.Primary_TFA.RangeFalloffLUT = nil
|
||||
self2.AutoDetectRange(self)
|
||||
end
|
||||
|
||||
local getLUT = self2.GetStatL(self, "Primary.RangeFalloffLUT", nil, true)
|
||||
|
||||
if getLUT then
|
||||
self2.Primary.RangeFalloffLUTBuilt = self:BuildFalloffTable(getLUT)
|
||||
end
|
||||
|
||||
if self2.Primary_TFA.RecoilLUT then
|
||||
if self2.Primary_TFA.RecoilLUT["in"] then
|
||||
self2.Primary_TFA.RecoilLUT["in"].points_p = {0}
|
||||
self2.Primary_TFA.RecoilLUT["in"].points_y = {0}
|
||||
|
||||
for _, point in ipairs(self2.Primary_TFA.RecoilLUT["in"].points) do
|
||||
table.insert(self2.Primary_TFA.RecoilLUT["in"].points_p, point.p)
|
||||
table.insert(self2.Primary_TFA.RecoilLUT["in"].points_y, point.y)
|
||||
end
|
||||
end
|
||||
|
||||
if self2.Primary_TFA.RecoilLUT["loop"] then
|
||||
self2.Primary_TFA.RecoilLUT["loop"].points_p = {}
|
||||
self2.Primary_TFA.RecoilLUT["loop"].points_y = {}
|
||||
|
||||
for _, point in ipairs(self2.Primary_TFA.RecoilLUT["loop"].points) do
|
||||
table.insert(self2.Primary_TFA.RecoilLUT["loop"].points_p, point.p)
|
||||
table.insert(self2.Primary_TFA.RecoilLUT["loop"].points_y, point.y)
|
||||
end
|
||||
|
||||
table.insert(self2.Primary_TFA.RecoilLUT["loop"].points_p, self2.Primary_TFA.RecoilLUT["loop"].points[1].p)
|
||||
table.insert(self2.Primary_TFA.RecoilLUT["loop"].points_y, self2.Primary_TFA.RecoilLUT["loop"].points[1].y)
|
||||
end
|
||||
|
||||
if self2.Primary_TFA.RecoilLUT["out"] then
|
||||
self2.Primary_TFA.RecoilLUT["out"].points_p = {0}
|
||||
self2.Primary_TFA.RecoilLUT["out"].points_y = {0}
|
||||
|
||||
for _, point in ipairs(self2.Primary_TFA.RecoilLUT["out"].points) do
|
||||
table.insert(self2.Primary_TFA.RecoilLUT["out"].points_p, point.p)
|
||||
table.insert(self2.Primary_TFA.RecoilLUT["out"].points_y, point.y)
|
||||
end
|
||||
|
||||
table.insert(self2.Primary_TFA.RecoilLUT["out"].points_p, 0)
|
||||
table.insert(self2.Primary_TFA.RecoilLUT["out"].points_y, 0)
|
||||
end
|
||||
end
|
||||
elseif getpath == "Primary_TFA" and isstring(getpath2[2]) then
|
||||
if trigger_lut_rebuild[getpath2[2]] and self2.Primary_TFA.RangeFalloffLUT_IsConverted then
|
||||
self2.Primary_TFA.RangeFalloffLUT = nil
|
||||
self2.AutoDetectRange(self)
|
||||
end
|
||||
|
||||
self2.Primary[getpath[2]] = self2.GetStatVersioned(self, vn, path_version)
|
||||
end
|
||||
|
||||
if vn == "Secondary" or not vn then
|
||||
table.Empty(self2.Secondary)
|
||||
|
||||
local temp = {}
|
||||
|
||||
setmetatable(self2.Secondary, {
|
||||
__index = function(self3, key)
|
||||
return self2.GetStatVersioned(self, "Secondary." .. key, self2.TFADataVersion)
|
||||
end,
|
||||
|
||||
__newindex = function() end
|
||||
})
|
||||
|
||||
for k in pairs(self.Secondary_TFA) do
|
||||
if isstring(k) then
|
||||
temp[k] = self2.GetStatVersioned(self, "Secondary." .. k, self2.TFADataVersion)
|
||||
end
|
||||
end
|
||||
|
||||
setmetatable(self2.Secondary, nil)
|
||||
|
||||
for k, v in pairs(temp) do
|
||||
self2.Secondary[k] = v
|
||||
end
|
||||
elseif getpath == "Secondary_TFA" and isstring(getpath2[2]) then
|
||||
self2.Secondary[getpath[2]] = self2.GetStatVersioned(self, vn, path_version)
|
||||
end
|
||||
|
||||
if CLIENT then
|
||||
self:RebuildModsRenderOrder()
|
||||
end
|
||||
|
||||
self2.ignore_stat_cache = false
|
||||
hook.Run("TFA_ClearStatCache", self)
|
||||
end
|
||||
|
||||
local ccv = GetConVar("cl_tfa_debug_cache")
|
||||
|
||||
function SWEP:GetStatPath(stat, path_version)
|
||||
return TFA.GetStatPath(stat, path_version or 0, self.TFADataVersion)
|
||||
end
|
||||
|
||||
function SWEP:RemapStatPath(stat, path_version)
|
||||
return TFA.RemapStatPath(stat, path_version or 0, self.TFADataVersion)
|
||||
end
|
||||
|
||||
function SWEP:GetStatPathRaw(stat)
|
||||
return TFA.GetStatPathRaw(stat)
|
||||
end
|
||||
|
||||
function SWEP:GetStatRaw(stat, path_version)
|
||||
local self2 = self:GetTable()
|
||||
local path = TFA.GetStatPath(stat, path_version or 0, self2.TFADataVersion)
|
||||
local value = self2[path[1]]
|
||||
|
||||
for i = 2, #path do
|
||||
if not istable(value) then return end
|
||||
value = value[path[i]]
|
||||
end
|
||||
|
||||
return value
|
||||
end
|
||||
|
||||
function SWEP:GetStatRawL(stat)
|
||||
return self:GetStatRaw(stat, LatestDataVersion)
|
||||
end
|
||||
|
||||
function SWEP:SetStatRaw(stat, path_version, _value)
|
||||
local self2 = self:GetTable()
|
||||
local path = TFA.GetStatPath(stat, path_version or 0, self2.TFADataVersion)
|
||||
|
||||
if #path == 1 then
|
||||
self2[path[1]] = _value
|
||||
return self
|
||||
end
|
||||
|
||||
local value = self2[path[1]]
|
||||
|
||||
for i = 2, #path - 1 do
|
||||
if not istable(value) then return self end
|
||||
value = value[path[i]]
|
||||
end
|
||||
|
||||
if istable(value) then
|
||||
value[path[#path]] = _value
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
function SWEP:SetStatRawL(stat, _value)
|
||||
return self:SetStatRaw(stat, LatestDataVersion, _value)
|
||||
end
|
||||
|
||||
function SWEP:GetStat(stat, default, dontMergeTables)
|
||||
return self:GetStatVersioned(stat, 0, default, dontMergeTables)
|
||||
end
|
||||
|
||||
function SWEP:GetStatL(stat, default, dontMergeTables)
|
||||
return self:GetStatVersioned(stat, LatestDataVersion, default, dontMergeTables)
|
||||
end
|
||||
|
||||
function SWEP:GetStatVersioned(stat, path_version, default, dontMergeTables)
|
||||
local self2 = self:GetTable()
|
||||
local statPath, currentVersionStat, translate = self2.GetStatPath(self, stat, path_version)
|
||||
|
||||
if self2.StatCache2[currentVersionStat] ~= nil then
|
||||
local finalReturn
|
||||
|
||||
if self2.StatCache[currentVersionStat] ~= nil then
|
||||
finalReturn = self2.StatCache[currentVersionStat]
|
||||
else
|
||||
local isDefault, retval = self2.GetStatRecursive(self, self2, statPath)
|
||||
|
||||
if retval ~= nil then
|
||||
if not isDefault then
|
||||
self2.StatCache[currentVersionStat] = retval
|
||||
end
|
||||
|
||||
finalReturn = retval
|
||||
else
|
||||
finalReturn = istable(default) and tableCopy(default) or default
|
||||
end
|
||||
end
|
||||
|
||||
local getstat = hook.Run("TFA_GetStat", self, currentVersionStat, finalReturn)
|
||||
if getstat ~= nil then return translate(getstat) end
|
||||
|
||||
return translate(finalReturn)
|
||||
end
|
||||
|
||||
if not self2.OwnerIsValid(self) then
|
||||
local finalReturn = default
|
||||
|
||||
if IsValid(self) then
|
||||
local _
|
||||
_, finalReturn = self2.GetStatRecursive(self, self2, statPath, istable(default) and tableCopy(default) or default)
|
||||
end
|
||||
|
||||
local getstat = hook.Run("TFA_GetStat", self, currentVersionStat, finalReturn)
|
||||
if getstat ~= nil then return translate(getstat) end
|
||||
|
||||
return translate(finalReturn)
|
||||
end
|
||||
|
||||
local isDefault, statSelf = self2.GetStatRecursive(self, self2, statPath, istable(default) and tableCopy(default) or default)
|
||||
local isDefaultAtt, statAttachment, noCache = self2.GetStatRecursive(self, self2.AttachmentTableCache, statPath, istable(statSelf) and tableCopy(statSelf) or statSelf)
|
||||
local shouldCache = not noCache and
|
||||
not (self2.StatCache_Blacklist_Real or self2.StatCache_Blacklist)[currentVersionStat] and
|
||||
not (self2.StatCache_Blacklist_Real or self2.StatCache_Blacklist)[statPath[1]] and
|
||||
not (ccv and ccv:GetBool())
|
||||
|
||||
if istable(statAttachment) and istable(statSelf) and not dontMergeTables then
|
||||
statSelf = table.Merge(tableCopy(statSelf), statAttachment)
|
||||
else
|
||||
statSelf = statAttachment
|
||||
end
|
||||
|
||||
if shouldCache and not self2.ignore_stat_cache then
|
||||
if not isDefault or not isDefaultAtt then
|
||||
self2.StatCache[currentVersionStat] = statSelf
|
||||
end
|
||||
|
||||
self2.StatCache2[currentVersionStat] = true
|
||||
end
|
||||
|
||||
local getstat = hook.Run("TFA_GetStat", self, currentVersionStat, statSelf)
|
||||
if getstat ~= nil then return translate(getstat) end
|
||||
|
||||
return translate(statSelf)
|
||||
end
|
||||
224
lua/weapons/tfa_gun_base/common/ttt.lua
Normal file
224
lua/weapons/tfa_gun_base/common/ttt.lua
Normal file
@@ -0,0 +1,224 @@
|
||||
--[[
|
||||
| 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.
|
||||
|
||||
SWEP.HeadshotMultiplier = 2.7
|
||||
SWEP.StoredAmmo = 0
|
||||
SWEP.IsDropped = false
|
||||
SWEP.DeploySpeed = 1.4
|
||||
SWEP.fingerprints = {}
|
||||
|
||||
-- crosshair
|
||||
if CLIENT then
|
||||
-- luacheck: globals LANG Key
|
||||
local SafeTranslation = function(x) return x end
|
||||
local GetPTranslation = LANG and LANG.GetParamTranslation or SafeTranslation
|
||||
|
||||
-- Many non-gun weapons benefit from some help
|
||||
local help_spec = {
|
||||
text = "",
|
||||
font = "TabLarge",
|
||||
xalign = TEXT_ALIGN_CENTER
|
||||
}
|
||||
|
||||
function SWEP:DrawHelp()
|
||||
local data = self.HUDHelp
|
||||
local translate = data.translatable
|
||||
local primary = data.primary
|
||||
local secondary = data.secondary
|
||||
|
||||
if translate then
|
||||
primary = primary and GetPTranslation(primary, data.translate_params)
|
||||
secondary = secondary and GetPTranslation(secondary, data.translate_params)
|
||||
end
|
||||
|
||||
help_spec.pos = {ScrW() / 2.0, ScrH() - 40}
|
||||
help_spec.text = secondary or primary
|
||||
draw.TextShadow(help_spec, 2)
|
||||
|
||||
-- if no secondary exists, primary is drawn at the bottom and no top line
|
||||
-- is drawn
|
||||
if secondary then
|
||||
help_spec.pos[2] = ScrH() - 60
|
||||
help_spec.text = primary
|
||||
draw.TextShadow(help_spec, 2)
|
||||
end
|
||||
end
|
||||
|
||||
local function SafeKey(binding, default)
|
||||
local b = input.LookupBinding(binding)
|
||||
if not b then return default end
|
||||
|
||||
return string.upper(b)
|
||||
end
|
||||
|
||||
local Key = Key or SafeKey
|
||||
|
||||
-- mousebuttons are enough for most weapons
|
||||
local default_key_params = {
|
||||
primaryfire = Key("+attack", "LEFT MOUSE"),
|
||||
secondaryfire = Key("+attack2", "RIGHT MOUSE"),
|
||||
usekey = Key("+use", "USE")
|
||||
}
|
||||
|
||||
function SWEP:AddHUDHelp(primary_text, secondary_text, translate, extra_params)
|
||||
extra_params = extra_params or {}
|
||||
|
||||
self.HUDHelp = {
|
||||
primary = primary_text,
|
||||
secondary = secondary_text,
|
||||
translatable = translate,
|
||||
translate_params = table.Merge(extra_params, default_key_params)
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:GetHeadshotMultiplier(victim, dmginfo)
|
||||
return self.HeadshotMultiplier or 2
|
||||
end
|
||||
|
||||
function SWEP:IsEquipment()
|
||||
-- luacheck: globals WEPS
|
||||
if WEPS and WEPS.IsEquipment then
|
||||
local val = WEPS.IsEquipment(self)
|
||||
|
||||
if val ~= nil then
|
||||
return val
|
||||
else
|
||||
return false
|
||||
end
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
-- The OnDrop() hook is useless for this as it happens AFTER the drop. OwnerChange
|
||||
-- does not occur when a drop happens for some reason. Hence this thing.
|
||||
function SWEP:PreDrop()
|
||||
if not IsValid(self) then return end
|
||||
if not self.Ammo1 then return end
|
||||
|
||||
if SERVER and IsValid(self:GetOwner()) and self.Primary_TFA.Ammo ~= "none" then
|
||||
local ammo = self:Ammo1()
|
||||
|
||||
-- Do not drop ammo if we have another gun that uses this type
|
||||
for _, w in pairs(self:GetOwner():GetWeapons()) do
|
||||
if IsValid(w) and w ~= self and w:GetPrimaryAmmoType() == self:GetPrimaryAmmoType() then
|
||||
ammo = 0
|
||||
end
|
||||
end
|
||||
|
||||
self.StoredAmmo = ammo
|
||||
|
||||
if ammo > 0 then
|
||||
self:GetOwner():RemoveAmmo(ammo, self.Primary_TFA.Ammo)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:DampenDrop()
|
||||
if not IsValid(self) then return end
|
||||
-- For some reason gmod drops guns on death at a speed of 400 units, which
|
||||
-- catapults them away from the body. Here we want people to actually be able
|
||||
-- to find a given corpse's weapon, so we override the velocity here and call
|
||||
-- this when dropping guns on death.
|
||||
local phys = self:GetPhysicsObject()
|
||||
|
||||
if IsValid(phys) then
|
||||
phys:SetVelocityInstantaneous(Vector(0, 0, -75) + phys:GetVelocity() * 0.001)
|
||||
phys:AddAngleVelocity(phys:GetAngleVelocity() * -0.99)
|
||||
end
|
||||
end
|
||||
|
||||
local SF_WEAPON_START_CONSTRAINED = 1
|
||||
|
||||
-- Picked up by player. Transfer of stored ammo and such.
|
||||
function SWEP:EquipTTT(newowner)
|
||||
if engine.ActiveGamemode() ~= "terrortown" then return end
|
||||
|
||||
if SERVER then
|
||||
if self:IsOnFire() then
|
||||
self:Extinguish()
|
||||
end
|
||||
|
||||
self.fingerprints = self.fingerprints or {}
|
||||
|
||||
if not table.HasValue(self.fingerprints, newowner) then
|
||||
table.insert(self.fingerprints, newowner)
|
||||
end
|
||||
|
||||
if self:HasSpawnFlags(SF_WEAPON_START_CONSTRAINED) then
|
||||
-- If this weapon started constrained, unset that spawnflag, or the
|
||||
-- weapon will be re-constrained and float
|
||||
local flags = self:GetSpawnFlags()
|
||||
local newflags = bit.band(flags, bit.bnot(SF_WEAPON_START_CONSTRAINED))
|
||||
self:SetKeyValue("spawnflags", newflags)
|
||||
end
|
||||
end
|
||||
|
||||
if not self.Ammo1 then return end
|
||||
|
||||
if SERVER and IsValid(newowner) and self.StoredAmmo > 0 and self.Primary_TFA.Ammo ~= "none" then
|
||||
local ammo = newowner:GetAmmoCount(self.Primary_TFA.Ammo)
|
||||
self.Primary_TFA.ClipMax = self.Primary_TFA.ClipMax or (math.abs(self.Primary_TFA.ClipSize) * 4)
|
||||
local given = math.min(self.StoredAmmo, self.Primary_TFA.ClipMax - ammo)
|
||||
newowner:GiveAmmo(given, self.Primary_TFA.Ammo)
|
||||
self.StoredAmmo = 0
|
||||
end
|
||||
end
|
||||
|
||||
-- We were bought as special equipment, some weapons will want to do something
|
||||
-- extra for their buyer
|
||||
function SWEP:WasBought(buyer)
|
||||
end
|
||||
|
||||
function SWEP:DyingShot()
|
||||
local fired = false
|
||||
-- if self:GetIronSightsProgress() and self:GetIronSightsProgress() > 0.01 then
|
||||
self:SetIronSightsRaw(false)
|
||||
if self:GetNextPrimaryFire() > CurTime() then return fired end
|
||||
|
||||
-- Owner should still be alive here
|
||||
if IsValid(self:GetOwner()) then
|
||||
local punch = self.Primary_TFA.Recoil or 5
|
||||
-- Punch view to disorient aim before firing dying shot
|
||||
local eyeang = self:GetOwner():EyeAngles()
|
||||
eyeang.pitch = eyeang.pitch - math.Rand(-punch, punch)
|
||||
eyeang.yaw = eyeang.yaw - math.Rand(-punch, punch)
|
||||
self:GetOwner():SetEyeAngles(eyeang)
|
||||
MsgN(self:GetOwner():Nick() .. " fired his DYING SHOT")
|
||||
self:GetOwner().dying_wep = self
|
||||
self:PrimaryAttack()
|
||||
fired = true
|
||||
end
|
||||
-- end
|
||||
|
||||
return fired
|
||||
end
|
||||
1202
lua/weapons/tfa_gun_base/common/utils.lua
Normal file
1202
lua/weapons/tfa_gun_base/common/utils.lua
Normal file
File diff suppressed because it is too large
Load Diff
107
lua/weapons/tfa_gun_base/common/viewmodel.lua
Normal file
107
lua/weapons/tfa_gun_base/common/viewmodel.lua
Normal 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/
|
||||
--]]
|
||||
|
||||
|
||||
-- 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 vector_origin = Vector()
|
||||
local angle_zero = Angle()
|
||||
|
||||
SWEP.WeaponLength = 0
|
||||
|
||||
SWEP.NearWallVector = Vector(0.091287083923817, -0.4564354121685, -0.18257416784763)
|
||||
SWEP.NearWallVectorADS = Vector(0, 0, 0)
|
||||
|
||||
SWEP.ViewModelPunchPitchMultiplier = 0.5
|
||||
SWEP.ViewModelPunchPitchMultiplier_IronSights = 0.09
|
||||
|
||||
SWEP.ViewModelPunch_MaxVertialOffset = 3
|
||||
SWEP.ViewModelPunch_MaxVertialOffset_IronSights = 1.95
|
||||
SWEP.ViewModelPunch_VertialMultiplier = 1
|
||||
SWEP.ViewModelPunch_VertialMultiplier_IronSights = 0.25
|
||||
|
||||
SWEP.ViewModelPunchYawMultiplier = 0.6
|
||||
SWEP.ViewModelPunchYawMultiplier_IronSights = 0.25
|
||||
|
||||
local onevec = Vector(1, 1, 1)
|
||||
|
||||
local function RBP(vm)
|
||||
local bc = vm:GetBoneCount()
|
||||
if not bc or bc <= 0 then return end
|
||||
|
||||
for i = 0, bc do
|
||||
vm:ManipulateBoneScale(i, onevec)
|
||||
vm:ManipulateBoneAngles(i, angle_zero)
|
||||
vm:ManipulateBonePosition(i, vector_origin)
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:ApplyViewModelModifications()
|
||||
local self2 = self:GetTable()
|
||||
if not self2.VMIV(self) then return end
|
||||
|
||||
local vm = self2.OwnerViewModel
|
||||
|
||||
local bgcount = #(vm:GetBodyGroups() or {})
|
||||
local ViewModelBodygroups = self2.GetStatRawL(self, "ViewModelBodygroups")
|
||||
local bgt = ViewModelBodygroups or self2.Bodygroups or {}
|
||||
|
||||
for i = 0, bgcount - 1 do
|
||||
vm:SetBodygroup(i, bgt[i] or 0)
|
||||
end
|
||||
|
||||
local skinind = self2.GetStatL(self, "Skin")
|
||||
|
||||
if skinind and isnumber(skinind) then
|
||||
vm:SetSkin(skinind)
|
||||
self:SetSkin(skinind)
|
||||
end
|
||||
|
||||
self2.ClearMaterialCache(self)
|
||||
end
|
||||
|
||||
function SWEP:ResetViewModelModifications()
|
||||
local self2 = self:GetTable()
|
||||
if not self2.VMIV(self) then return end
|
||||
|
||||
local vm = self2.OwnerViewModel
|
||||
|
||||
RBP(vm)
|
||||
|
||||
vm:SetSkin(0)
|
||||
|
||||
local matcount = #(vm:GetMaterials() or {})
|
||||
|
||||
for i = 0, matcount do
|
||||
vm:SetSubMaterial(i, "")
|
||||
end
|
||||
|
||||
for i = 0, #(vm:GetBodyGroups() or {}) - 1 do
|
||||
vm:SetBodygroup(i, 0)
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user