897 lines
29 KiB
Lua
897 lines
29 KiB
Lua
AddCSLuaFile()
|
|
require("mw_utils")
|
|
|
|
function SWEP:StopCustomizing()
|
|
if (self:HasFlag("Customizing")) then
|
|
self:Customize(false)
|
|
end
|
|
end
|
|
|
|
function SWEP:GetCustomizationCount()
|
|
if (!self.Customization) then
|
|
return 0
|
|
end
|
|
|
|
return #self.Customization
|
|
end
|
|
|
|
function SWEP:GetAttachmentCount(slot)
|
|
if (!self.Customization) then
|
|
return 0
|
|
end
|
|
|
|
return #self.Customization[slot]
|
|
end
|
|
|
|
function SWEP:CanCustomize()
|
|
if (self:CanPump() && !self:HasFlag("Rechambered")) then
|
|
return false
|
|
end
|
|
|
|
return !self:HasFlag("Reloading")
|
|
&& !self:HasFlag("Drawing")
|
|
&& !self:HasFlag("Holstering")
|
|
&& CurTime() > self:GetNextPrimaryFire()
|
|
--&& self:Clip1() > 0
|
|
&& self.Customization != nil
|
|
&& self:GetAimDelta() <= 0
|
|
&& !self:HasFlag("Sprinting")
|
|
&& GetConVar("mgbase_sv_customization"):GetBool()
|
|
end
|
|
|
|
function SWEP:CanPlayInspectAfterCustomization() --people lagging could still be playing draws
|
|
return !self:HasFlag("Drawing")
|
|
end
|
|
|
|
function SWEP:Customize(state)
|
|
state = tobool(state)
|
|
|
|
if (state == true && !self:CanCustomize()) then
|
|
return
|
|
end
|
|
|
|
if (state) then
|
|
self:AddFlag("Customizing")
|
|
self:RemoveFlag("StoppedInspectAnimation")
|
|
else
|
|
self:RemoveFlag("Customizing")
|
|
end
|
|
|
|
if (state) then
|
|
self:AddFlag("Customizing")
|
|
self:SetNextInspectTime(0)
|
|
else
|
|
self:RemoveFlag("Customizing")
|
|
end
|
|
|
|
self:RemoveFlag("Lowered")
|
|
|
|
if (CLIENT) then
|
|
self:CustomizationMenu()
|
|
end
|
|
|
|
if (self:HasFlag("Customizing") && self:CanPlayInspectAfterCustomization()) then
|
|
local inspIndex = (self:Clip1() <= 0 && self:GetAnimation("Inspect_Empty") != nil) && "Inspect_Empty" || "Inspect"
|
|
self:PlayViewModelAnimation(inspIndex)
|
|
end
|
|
|
|
if (game.SinglePlayer() && SERVER) then
|
|
self:CallOnClient("Customize", tostring(state))
|
|
end
|
|
end
|
|
|
|
function SWEP:Attach(slot, attIndex)
|
|
if (self.Customization[slot] == nil) then
|
|
return
|
|
end
|
|
|
|
local attachmentClass = self.Customization[slot][attIndex]
|
|
|
|
self:CreateAttachmentForUse(attachmentClass)
|
|
|
|
--BUILD:
|
|
self:BuildCustomizedGun()
|
|
|
|
--reset inspect animation
|
|
if (CLIENT) then
|
|
self:GetViewModel():UpdateAnimation()
|
|
end
|
|
end
|
|
|
|
function SWEP:IsBodygroupAllowed(bgName)
|
|
for slot, att in pairs(self:GetAllAttachmentsInUse()) do
|
|
if (att.BlockedBodygroups != nil && table.HasValue(att.BlockedBodygroups, bgName)) then
|
|
return false
|
|
end
|
|
end
|
|
|
|
return true
|
|
end
|
|
|
|
local function doAttBodygroups(wep, model)
|
|
for i = 0, model:GetNumBodyGroups(), 1 do
|
|
model:SetBodygroup(i, 0)
|
|
end
|
|
|
|
for slot, att in pairs(wep:GetAllAttachmentsInUse()) do
|
|
if (att.AttachmentBodygroups != nil) then
|
|
for bodyGroupName, value in pairs(att.AttachmentBodygroups) do
|
|
if (!wep:IsBodygroupAllowed(bodyGroupName)) then
|
|
continue
|
|
end
|
|
local id = model:FindBodygroupByName(bodyGroupName)
|
|
if (id != -1) then
|
|
model:SetBodygroup(id, value)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
local function doMaterialOverride(att, model, funcName)
|
|
for i, mat in pairs(model:GetMaterials()) do
|
|
local originalPath, originalName = string.GetPathFromFilename(mat), string.GetFileFromFilename(mat)
|
|
local path, name = att[funcName](att, originalPath, originalName)
|
|
if (path != originalPath || name != originalName) then
|
|
local material = Material(path..name)
|
|
if (!material:IsError()) then
|
|
model:SetSubMaterial(i - 1, path..name)
|
|
model.CustomizationAnimationDelta = 1
|
|
model.CustomizationAnimationColor = att.UIColor || Color(255, 255, 255, 255)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
function SWEP:CreateAttachmentModel(attachment)
|
|
if (SERVER) then
|
|
return
|
|
end
|
|
|
|
doMaterialOverride(attachment, self:GetViewModel(), "OverrideWeaponMaterial")
|
|
doMaterialOverride(attachment, self, "OverrideWeaponMaterial")
|
|
|
|
for slot, att in pairs(self:GetAllAttachmentsInUse()) do
|
|
if (att == attachment) then
|
|
continue
|
|
end
|
|
|
|
if (IsValid(att.m_Model)) then
|
|
doMaterialOverride(attachment, att.m_Model, "OverrideAttachmentsMaterial")
|
|
end
|
|
|
|
if (IsValid(att.m_TpModel)) then
|
|
doMaterialOverride(attachment, att.m_TpModel, "OverrideAttachmentsMaterial")
|
|
end
|
|
end
|
|
|
|
if (attachment.Model == nil) then
|
|
return
|
|
end
|
|
|
|
if (!IsValid(attachment.m_Model)) then
|
|
attachment.m_Model = ClientsideModel(attachment.Model, RENDERGROUP_VIEWMODEL)
|
|
attachment.m_Model:SetRenderMode(RENDERMODE_ENVIROMENTAL)
|
|
attachment.m_Model:SetMoveType(MOVETYPE_NONE)
|
|
attachment.m_Model:SetSolid(SOLID_NONE)
|
|
attachment.m_Model:SetNotSolid(true)
|
|
attachment.m_Model:SetOwner(self:GetViewModel())
|
|
attachment.m_Model.bAttachmentRenderOverride = attachment.RenderOverride
|
|
attachment.m_Model:AddEffects(EF_PARENT_ANIMATES)
|
|
mw_utils.DealWithFullUpdate(attachment.m_Model)
|
|
|
|
if (attachment.VElement == nil) then
|
|
attachment.m_Model:AddEffects(EF_BONEMERGE)
|
|
attachment.m_Model:AddEffects(EF_BONEMERGE_FASTCULL)
|
|
attachment.m_Model:SetParent(self:GetViewModel())
|
|
else
|
|
attachment.m_Model:FollowBone(self:GetViewModel(), mw_utils.LookupBoneCached(self:GetViewModel(), attachment.VElement.Bone))
|
|
end
|
|
|
|
attachment.m_Model.CustomizationAnimationDelta = 0
|
|
attachment.m_Model.CustomizationAnimationColor = Color(255, 255, 255, 255)
|
|
|
|
--this is for the highlight effect on the attachments
|
|
if (attachment.Index > 1) then
|
|
attachment.m_Model.CustomizationAnimationDelta = 1
|
|
attachment.m_Model.CustomizationAnimationColor = attachment.UIColor || attachment.m_Model.CustomizationAnimationColor
|
|
end
|
|
end
|
|
|
|
if (attachment.VElement != nil) then
|
|
self:MoveVElement(self:GetViewModel(), attachment)
|
|
end
|
|
|
|
if (!IsValid(attachment.m_TpModel)) then
|
|
attachment.m_TpModel = ClientsideModel(attachment.Model, self.RenderGroup)
|
|
attachment.m_TpModel:SetRenderMode(self.RenderMode)
|
|
attachment.m_TpModel:SetMoveType(MOVETYPE_NONE)
|
|
attachment.m_TpModel:SetSolid(SOLID_NONE)
|
|
attachment.m_TpModel:SetNotSolid(true)
|
|
attachment.m_TpModel:SetOwner(self)
|
|
attachment.m_TpModel:SetNoDraw(true) --perf
|
|
attachment.m_TpModel.ShowOnWorldModel = attachment.ShowOnWorldModel
|
|
attachment.m_TpModel:AddEffects(EF_PARENT_ANIMATES)
|
|
mw_utils.DealWithFullUpdate(attachment.m_TpModel)
|
|
|
|
if (attachment.VElement == nil) then
|
|
attachment.m_TpModel:AddEffects(EF_BONEMERGE)
|
|
attachment.m_TpModel:AddEffects(EF_BONEMERGE_FASTCULL)
|
|
attachment.m_TpModel:SetParent(self)
|
|
else
|
|
attachment.m_TpModel:FollowBone(self, mw_utils.LookupBoneCached(self, attachment.VElement.Bone))
|
|
end
|
|
|
|
attachment:PostInitModels(self)
|
|
end
|
|
|
|
if (attachment.VElement != nil) then
|
|
self:MoveVElement(self, attachment)
|
|
end
|
|
|
|
doAttBodygroups(self, attachment.m_Model)
|
|
doAttBodygroups(self, attachment.m_TpModel)
|
|
doMaterialOverride(attachment, attachment.m_Model, "OverrideMaterial")
|
|
doMaterialOverride(attachment, attachment.m_TpModel, "OverrideMaterial")
|
|
end
|
|
|
|
function SWEP:ShouldInvalidateBoneCache()
|
|
for _, att in pairs(self:GetAllAttachmentsInUse()) do
|
|
if (!IsValid(att.m_Model) || !att.m_Model:IsEffectActive(EF_FOLLOWBONE)) then
|
|
continue
|
|
end
|
|
|
|
if (att.m_Model:GetAttachments() != nil) then
|
|
return true
|
|
end
|
|
end
|
|
|
|
return false
|
|
end
|
|
|
|
function SWEP:GetAttachmentInUseForSlot(slot)
|
|
return self.m_CustomizationInUse[slot]
|
|
end
|
|
|
|
function SWEP:GetAttachmentInUseByCategory(cat)
|
|
for _, att in pairs(self:GetAllAttachmentsInUse()) do
|
|
if (att.Category == cat) then
|
|
return att
|
|
end
|
|
end
|
|
|
|
return nil
|
|
end
|
|
|
|
function SWEP:GetAllAttachmentsInUse()
|
|
return self.m_CustomizationInUse
|
|
end
|
|
|
|
function SWEP:BuildCustomizedGun()
|
|
--this resets gun to defaults, but keeps the internal variables
|
|
self:DeepObjectCopy(weapons.Get(self:GetClass()), self)
|
|
|
|
local oldSkin = IsValid(self:GetViewModel()) && self:GetViewModel():GetSkin() || 0
|
|
self:ResetBodygroups()
|
|
|
|
self:SetBurstRounds(0)
|
|
|
|
self.reticle = nil
|
|
self.flashlight = nil
|
|
self.laser = nil
|
|
self.bipod = nil
|
|
|
|
if (self.Customization == nil) then
|
|
return
|
|
end
|
|
|
|
clearBaseClass(self.Customization)
|
|
clearBaseClass(self.Animations)
|
|
|
|
local vmspeed = 1
|
|
|
|
if (IsValid(self:GetViewModel())) then
|
|
vmspeed = self:GetViewModel():GetPlaybackRate()
|
|
self:GetViewModel():SetPlaybackRate(0)
|
|
self:GetViewModel():SetModel(self.VModel)
|
|
end
|
|
|
|
self:SetModel(self.WorldModel)
|
|
|
|
if (CLIENT) then
|
|
if (IsValid(self:GetViewModel())) then
|
|
self:GetViewModel():SetSubMaterial()
|
|
self:GetViewModel().m_LeftHandGripPoseParameter = nil
|
|
self:GetViewModel().m_RightHandGripPoseParameter = nil
|
|
end
|
|
|
|
for slot, att in pairs(self:GetAllAttachmentsInUse()) do
|
|
if (att.Model != nil) then
|
|
if (IsValid(att.m_TpModel)) then
|
|
att.m_TpModel:SetSubMaterial()
|
|
end
|
|
|
|
if (IsValid(att.m_Model)) then
|
|
att.m_Model:SetSubMaterial()
|
|
end
|
|
end
|
|
end
|
|
self:SetSubMaterial()
|
|
end
|
|
|
|
--check if atts are allowed
|
|
for slot, att in pairs(self:GetAllAttachmentsInUse()) do
|
|
if (att == nil || !self:IsAttachmentAllowed(att)) then
|
|
self:CreateAttachmentForUse(self.Customization[slot][1])
|
|
end
|
|
end
|
|
|
|
--this is needed for level transitions
|
|
for slot, att in pairs(self:GetAllAttachmentsInUse()) do
|
|
table.Inherit(att, self:GetStoredAttachment(att.ClassName))
|
|
end
|
|
|
|
self:PreAttachments()
|
|
|
|
local stats = {}
|
|
self:DeepObjectCopy(self:GetTable(), stats)
|
|
|
|
stats.SetViewModel = function(self, vm)
|
|
mw_utils.ErrorPrint("SetViewModel: Don't call this in Stats!")
|
|
end
|
|
|
|
local c = 0
|
|
|
|
for slot, attachment in pairs(self:GetAllAttachmentsInUse()) do
|
|
if (attachment.Flashlight != nil) then
|
|
self.flashlight = attachment
|
|
end
|
|
|
|
if (attachment.Laser != nil) then
|
|
self.laser = attachment
|
|
end
|
|
|
|
if (attachment.Reticle != nil) then
|
|
self.reticle = attachment
|
|
end
|
|
|
|
if (attachment.Bipod) then
|
|
self.bipod = attachment
|
|
end
|
|
|
|
attachment:Stats(stats)
|
|
|
|
if (attachment.Index > 1) then
|
|
self:MakeBreadcrumbsForAttachment(attachment)
|
|
end
|
|
end
|
|
|
|
--check if customization changed
|
|
local bChanged = false
|
|
for slot, att in pairs(self:GetAllAttachmentsInUse()) do
|
|
if (stats.Customization[slot] == nil) then
|
|
mw_utils.DevPrint("BuildCustomizedGun: Slot "..slot.." got removed!")
|
|
self:RemoveAttachment(att)
|
|
bChanged = true
|
|
continue
|
|
end
|
|
|
|
if (att.ClassName != stats.Customization[slot][att.Index]) then
|
|
local classToChangeTo = stats.Customization[slot][att.Index] != nil && stats.Customization[slot][att.Index] || stats.Customization[slot][1]
|
|
|
|
mw_utils.DevPrint("BuildCustomizedGun: "..att.ClassName.." changed to "..classToChangeTo)
|
|
local newAtt = self:CreateAttachmentForUse(classToChangeTo, stats.Customization)
|
|
|
|
if (CLIENT) then
|
|
if (newAtt.Base == att.ClassName || att.Base == newAtt.ClassName) then
|
|
if (mw_utils.IsAssetFavorite(self:GetClass(), att.ClassName)) then
|
|
mw_utils.FavoriteAsset(self:GetClass(), newAtt.ClassName)
|
|
else
|
|
mw_utils.UnfavoriteAsset(self:GetClass(), newAtt.ClassName)
|
|
end
|
|
end
|
|
end
|
|
|
|
bChanged = true
|
|
end
|
|
end
|
|
|
|
if (bChanged) then
|
|
mw_utils.DevPrint("BuildCustomizedGun: Customization changed! Redoing...")
|
|
self:BuildCustomizedGun()
|
|
return
|
|
end
|
|
|
|
clearBaseClass(stats)
|
|
self:DeepObjectCopy(stats, self)
|
|
|
|
local oldVm = self.SetViewModel
|
|
self.SetViewModel = function(self, vm)
|
|
self.VModel = vm
|
|
end
|
|
|
|
for slot, att in pairs(self:GetAllAttachmentsInUse()) do
|
|
local oldModel = self.VModel
|
|
att:PostProcess(self)
|
|
|
|
if (self.VModel != oldModel && IsValid(self:GetViewModel())) then
|
|
self:GetViewModel().CustomizationAnimationColor = att.UIColor || Color(255, 255, 255, 255)
|
|
self:GetViewModel().CustomizationAnimationDelta = 1
|
|
end
|
|
end
|
|
|
|
self.SetViewModel = oldVm
|
|
|
|
if (IsValid(self:GetViewModel())) then
|
|
self:GetViewModel():SetModel(self.VModel)
|
|
end
|
|
|
|
self:SetModel(self.WorldModel)
|
|
|
|
for slot, att in pairs(self:GetAllAttachmentsInUse()) do
|
|
self:PostAttachment(att) --letting all atts do their thing and then run ours
|
|
end
|
|
|
|
--check magazine:
|
|
if (IsValid(self:GetOwner())) then
|
|
local maxClip = self:GetMaxClip1WithChamber()
|
|
|
|
if (!self:HasFlag("PlayFirstDraw")) then
|
|
if (self:Clip1() > maxClip) then
|
|
local diff = self:Clip1() - maxClip
|
|
self:SetClip1(self:Clip1() - diff)
|
|
self:GetOwner():SetAmmo(self:GetOwner():GetAmmoCount(self:GetPrimaryAmmoType()) + diff, self:GetPrimaryAmmoType())
|
|
end
|
|
else
|
|
self:SetClip1(maxClip)
|
|
end
|
|
end
|
|
|
|
--check if we can keep aim mode
|
|
if (!self:CanChangeAimMode()) then
|
|
self:SetAimMode(0)
|
|
end
|
|
|
|
--create models:
|
|
for slot, att in pairs(self:GetAllAttachmentsInUse()) do
|
|
self:CreateAttachmentModel(att)
|
|
end
|
|
|
|
--bodygroups:
|
|
for slot, att in pairs(self:GetAllAttachmentsInUse()) do
|
|
if (att.Bodygroups != nil) then
|
|
for bg, v in pairs(att.Bodygroups) do
|
|
if (!self:IsBodygroupAllowed(bg)) then
|
|
continue
|
|
end
|
|
self:DoBodygroup(bg, v)
|
|
end
|
|
end
|
|
end
|
|
|
|
self:SetBonemergeParents()
|
|
self:GenerateAimOffset()
|
|
|
|
if (CLIENT) then
|
|
local curSkin = IsValid(self:GetViewModel()) && self:GetViewModel():GetSkin() || 0
|
|
local skinCount = IsValid(self:GetViewModel()) && self:GetViewModel():SkinCount() || 0
|
|
|
|
for slot, att in pairs(self:GetAllAttachmentsInUse()) do
|
|
att:Appearance(self:GetViewModel(), "Weapon")
|
|
if (curSkin != oldSkin && curSkin > 0 && curSkin <= skinCount) then
|
|
self:GetViewModel().CustomizationAnimationColor = att.UIColor || Color(255, 255, 255, 255)
|
|
self:GetViewModel().CustomizationAnimationDelta = 1
|
|
end
|
|
|
|
att:Appearance(self, "Weapon")
|
|
|
|
for _, att2 in pairs(self:GetAllAttachmentsInUse()) do
|
|
if (att2.Model != nil) then
|
|
att:Appearance(att2.m_Model, att2.Category)
|
|
|
|
if (att2.m_Model:GetSkin() != oldSkin && att2.m_Model:GetSkin() > 0 && att2.m_Model:GetSkin() <= att2.m_Model:SkinCount()) then
|
|
att2.m_Model.CustomizationAnimationColor = att.UIColor || Color(255, 255, 255, 255)
|
|
att2.m_Model.CustomizationAnimationDelta = 1
|
|
end
|
|
|
|
att:Appearance(att2.m_TpModel, att2.Category)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
--meme marine
|
|
self:SetHoldType("camera")
|
|
timer.Simple(0, function()
|
|
if !IsValid(self) then return end
|
|
self:SetShouldHoldType(true)
|
|
end)
|
|
|
|
--apply firemode first while resetting defaults:
|
|
self:ApplyFiremodeStats()
|
|
|
|
--shadowdark was here
|
|
--this hook passes the swep object after stats are built, allowing for custom 3rd party stat scaling
|
|
hook.Call("OnBuildCustomizedGun", nil, self)
|
|
|
|
if (IsValid(self:GetViewModel())) then
|
|
self:GetViewModel():SetPlaybackRate(vmspeed)
|
|
end
|
|
end
|
|
|
|
--old way was just overcomplicated for no reason
|
|
function SWEP:MakeBreadcrumbsForAttachment(attachment)
|
|
if (attachment.Breadcrumbs == nil) then
|
|
--make breadcrumbs
|
|
--make another copy of swep
|
|
local breadcrumbs = {}
|
|
self:DeepObjectCopy(weapons.Get(self:GetClass()), breadcrumbs)
|
|
attachment:Stats(breadcrumbs) --run stats (lol he doesnt know its actually not a gun!!)
|
|
|
|
--make bcs
|
|
local holder = {}
|
|
self:MakeBreadcrumbs(holder, weapons.Get(self:GetClass()), breadcrumbs) --looks at differences in numbers only
|
|
|
|
attachment.Breadcrumbs = {}
|
|
|
|
for statInfo, crumb in pairs(holder) do
|
|
crumb.statInfo = statInfo
|
|
table.insert(attachment.Breadcrumbs, crumb)
|
|
end
|
|
|
|
local sort = function(a, b)
|
|
local aStat = self.StatInfo[a.statInfo]
|
|
local bStat = self.StatInfo[b.statInfo]
|
|
|
|
local baPositive = a.Current <= a.Original
|
|
|
|
if (aStat.ProIfMore) then
|
|
baPositive = !baPositive
|
|
end
|
|
|
|
local bbPositive = b.Current <= b.Original
|
|
|
|
if (bStat.ProIfMore) then
|
|
bbPositive = !bbPositive
|
|
end
|
|
|
|
if (baPositive && !bbPositive) then
|
|
return true
|
|
elseif (!baPositive && bbPositive) then
|
|
return false
|
|
elseif ((baPositive && bbPositive) || (!baPositive && !bbPositive)) then
|
|
local aName = aStat.Name
|
|
local bName = bStat.Name
|
|
|
|
return aName < bName
|
|
end
|
|
end
|
|
table.sort(attachment.Breadcrumbs, sort)
|
|
end
|
|
end
|
|
|
|
function SWEP:MakeBreadcrumbs(holder, original, changed, currentPath)
|
|
currentPath = currentPath || "SWEP"
|
|
|
|
for k, v in pairs(original) do
|
|
if (tostring(k) == "BaseClass" || tostring(k) == "m_Index") then
|
|
continue
|
|
end
|
|
|
|
if (isnumber(v)) then
|
|
if (changed[k] != v) then
|
|
local path = currentPath.."."..tostring(k)
|
|
if (self.StatDefinitions[path] == nil) then
|
|
continue
|
|
end
|
|
|
|
holder[self.StatDefinitions[path]] = holder[self.StatDefinitions[path]] || {}
|
|
table.Merge(holder[self.StatDefinitions[path]], {Original = v, Current = changed[k]})
|
|
end
|
|
elseif (istable(v) && changed[k] != nil) then
|
|
self:MakeBreadcrumbs(holder, v, changed[k], currentPath.."."..tostring(k))
|
|
end
|
|
end
|
|
end
|
|
|
|
function SWEP:SetBonemergeParents()
|
|
if (SERVER) then
|
|
return
|
|
end
|
|
|
|
for slot, attachment in pairs(self:GetAllAttachmentsInUse()) do
|
|
if (attachment.Model == nil) then
|
|
continue
|
|
end
|
|
|
|
if (attachment.VElement == nil) then
|
|
for slot, attParent in pairs(self:GetAllAttachmentsInUse()) do
|
|
if (attParent.Model == nil) then
|
|
continue
|
|
end
|
|
|
|
if (attParent == attachment) then
|
|
continue
|
|
end
|
|
|
|
if (attachment.BonemergeToCategory != nil && table.HasValue(attachment.BonemergeToCategory, attParent.Category)) then
|
|
attachment.m_Model:SetParent(attParent.m_Model)
|
|
attachment.m_TpModel:SetParent(attParent.m_TpModel)
|
|
|
|
attachment.m_Model:SetupBones()
|
|
attParent.m_Model:SetupBones()
|
|
|
|
if (!mw_utils.CheckMatchingBones(attachment.m_Model, attParent.m_Model)) then
|
|
attachment.m_Model:SetParent(self:GetViewModel())
|
|
attachment.m_TpModel:SetParent(self)
|
|
else
|
|
break
|
|
end
|
|
end
|
|
|
|
if (attachment.BonemergeToAttachment != nil && table.HasValue(attachment.BonemergeToAttachment, attParent.ClassName)) then
|
|
if (mw_utils.CheckMatchingBones(attachment.m_Model, attParent.m_Model)) then
|
|
attachment.m_Model:SetParent(attParent.m_Model)
|
|
attachment.m_TpModel:SetParent(attParent.m_TpModel)
|
|
break
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
function SWEP:GenerateAimOffset()
|
|
if (SERVER) then
|
|
return
|
|
end
|
|
|
|
for _, attachment in pairs(self:GetAllAttachmentsInUse()) do
|
|
if (attachment.Model == nil) then
|
|
continue
|
|
end
|
|
|
|
if (attachment.Reticle != nil) then
|
|
self:GetViewModel():SetPoseParameter("hybrid_offset", 0)
|
|
self:GetViewModel():InvalidateBoneCache()
|
|
self:GetViewModel():SetupBones()
|
|
|
|
local alignAttachmentId = mw_utils.LookupAttachmentCached(self:GetViewModel(), self.ViewModelOffsets.Aim.AlignAttachment || "align")
|
|
|
|
if (alignAttachmentId != nil) then
|
|
attachment.m_Model:InvalidateBoneCache()
|
|
attachment.m_Model:SetupBones() --shaky otherwise
|
|
attachment.m_Model:GetParent():InvalidateBoneCache()
|
|
attachment.m_Model:GetParent():SetupBones()
|
|
|
|
local data = self:GetViewModel():GetAttachment(alignAttachmentId)
|
|
local reticleData = attachment.m_Model:GetAttachment(attachment.m_Model:LookupAttachment(attachment.Reticle.Attachment))
|
|
|
|
local localPos, localAng = WorldToLocal(data.Pos, data.Ang, reticleData.Pos, reticleData.Ang)
|
|
attachment.AimPos = Vector(-localPos.y, localPos.x + 4, localPos.z) --converted from stupid cod forward
|
|
attachment.AimAng = Angle(localAng.p, localAng.y, -localAng.r) --shouldnt need to change aim angles
|
|
|
|
if (attachment.ReticleHybrid != nil) then
|
|
local reticle2Data = attachment.m_Model:GetAttachment(attachment.m_Model:LookupAttachment(attachment.ReticleHybrid.Attachment))
|
|
|
|
localPos, localAng = WorldToLocal(reticle2Data.Pos, reticle2Data.Ang, reticleData.Pos, reticleData.Ang)
|
|
attachment.HybridAimPos = attachment.AimPos + Vector(localPos.y, -localPos.x, -localPos.z)
|
|
attachment.HybridAimAng = attachment.AimAng + Angle(localAng.p, localAng.y, -localAng.r)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
function SWEP:MoveVElement(model, attachment)
|
|
local attModel = model == self:GetViewModel() && attachment.m_Model || attachment.m_TpModel
|
|
local ve = attachment.VElement
|
|
local bone = mw_utils.LookupBoneCached(model, ve.Bone)
|
|
local oPos, oAng = self:GetTotalAttachmentOffset(attachment)
|
|
|
|
local ang = Angle()
|
|
ang:RotateAroundAxis(ang:Forward(), ve.Angles.r + oAng.r)
|
|
ang:RotateAroundAxis(ang:Right(), ve.Angles.y + oAng.y)
|
|
ang:RotateAroundAxis(ang:Up(), ve.Angles.p + oAng.p)
|
|
|
|
local pos = Vector()
|
|
mw_math.VectorAddAndMul(pos, ang:Forward(), ve.Position.y + oPos.y)
|
|
mw_math.VectorAddAndMul(pos, ang:Right(), ve.Position.x + oPos.x)
|
|
mw_math.VectorAddAndMul(pos, ang:Up(), ve.Position.z + oPos.z)
|
|
|
|
attModel:SetLocalPos(pos)
|
|
attModel:SetLocalAngles(ang)
|
|
end
|
|
|
|
function SWEP:GetTotalAttachmentOffset(currentAttachment)
|
|
local pos = Vector()
|
|
local ang = Angle()
|
|
|
|
local offsets = currentAttachment.VElement.Offsets
|
|
|
|
if offsets != nil then
|
|
for slot, attachment in pairs(self:GetAllAttachmentsInUse()) do
|
|
if (offsets[attachment.ClassName] != nil) then
|
|
pos:Add(offsets[attachment.ClassName][1])
|
|
ang:Add(offsets[attachment.ClassName][2])
|
|
end
|
|
end
|
|
end
|
|
|
|
return pos, ang
|
|
end
|
|
|
|
function SWEP:DoBodygroup(name, value)
|
|
local ind = self:GetViewModel():FindBodygroupByName(name)
|
|
|
|
if (ind != -1) then
|
|
self:GetViewModel():SetBodygroup(ind, value)
|
|
end
|
|
|
|
ind = self:FindBodygroupByName(name)
|
|
|
|
if (ind != -1) then
|
|
self:SetBodygroup(ind, value)
|
|
end
|
|
end
|
|
|
|
function SWEP:ResetBodygroups()
|
|
if (IsValid(self:GetViewModel())) then
|
|
self:GetViewModel():SetSkin(0)
|
|
|
|
for b = 0, self:GetViewModel():GetNumBodyGroups() do
|
|
self:GetViewModel():SetBodygroup(b, 0)
|
|
end
|
|
end
|
|
|
|
if (IsValid(self)) then
|
|
self:SetSkin(0)
|
|
|
|
for b = 0, self:GetNumBodyGroups() do
|
|
self:SetBodygroup(b, 0)
|
|
end
|
|
end
|
|
end
|
|
|
|
function SWEP:GetAttachmentModels(slot)
|
|
return self.m_CustomizationInUse[slot].m_Model, self.m_CustomizationInUse[slot].m_TpModel
|
|
end
|
|
|
|
function SWEP:GetSight()
|
|
return self.reticle
|
|
end
|
|
|
|
function SWEP:GetLaser()
|
|
return self.laser
|
|
end
|
|
|
|
function SWEP:GetFlashlightAttachment()
|
|
return self.flashlight
|
|
end
|
|
|
|
function SWEP:GetBipod()
|
|
return self.bipod
|
|
end
|
|
|
|
hook.Add("PlayerSwitchFlashlight", "MW19_PlayerSwitchFlashlight", function(ply, enabled)
|
|
local w = ply:GetActiveWeapon()
|
|
if (ply:CanUseFlashlight() && !ply:FlashlightIsOn() && IsValid(w) && weapons.IsBasedOn(w:GetClass(), "mg_base")) then
|
|
if (w:GetFlashlightAttachment() != nil) then
|
|
ply:EmitSound("MW.Flashlight")
|
|
w:ToggleFlag("FlashlightOn")
|
|
return false
|
|
end
|
|
end
|
|
end)
|
|
|
|
function SWEP:HasAttachment(class)
|
|
if (self.Customization == nil) then
|
|
return false
|
|
end
|
|
|
|
if (self.m_CustomizationInUse == nil) then
|
|
return false
|
|
end
|
|
|
|
for slot, att in pairs(self:GetAllAttachmentsInUse()) do
|
|
if (att.ClassName == class) then
|
|
return true
|
|
end
|
|
end
|
|
|
|
return false
|
|
end
|
|
|
|
function SWEP:GetBlockerAttachment(attachment)
|
|
for slot, attachmentInUseInSlot in pairs(self:GetAllAttachmentsInUse()) do
|
|
--by class name (very specific)
|
|
if (attachmentInUseInSlot.ExcludedAttachments != nil) then
|
|
if (table.HasValue(attachmentInUseInSlot.ExcludedAttachments, attachment.ClassName)) then
|
|
return attachmentInUseInSlot
|
|
end
|
|
end
|
|
|
|
--by category name (broad for more attachments)
|
|
if (attachmentInUseInSlot.ExcludedCategories != nil) then
|
|
if (table.HasValue(attachmentInUseInSlot.ExcludedCategories, attachment.Category)) then
|
|
return attachmentInUseInSlot
|
|
end
|
|
end
|
|
|
|
if (attachment.ExcludedByAttachments != nil && table.HasValue(attachment.ExcludedByAttachments, attachmentInUseInSlot.ClassName)) then
|
|
return attachmentInUseInSlot
|
|
end
|
|
|
|
if (attachment.ExcludedByCategories != nil && table.HasValue(attachment.ExcludedByCategories, attachmentInUseInSlot.Category) && attachmentInUseInSlot.Index > 1) then
|
|
return attachmentInUseInSlot
|
|
end
|
|
end
|
|
|
|
return nil
|
|
end
|
|
|
|
function SWEP:IsAttachmentAllowed(attachment)
|
|
if (attachment.Index == nil || attachment.Index > 1) then
|
|
if (!attachment.CosmeticChange) then
|
|
local attLimit = GetConVar("mgbase_sv_customization_limit"):GetInt()
|
|
local currentCount = 0
|
|
|
|
for slot, attachmentInUseInSlot in pairs(self:GetAllAttachmentsInUse()) do
|
|
if (attachment != attachmentInUseInSlot && attachmentInUseInSlot.Index > 1 && !attachmentInUseInSlot.CosmeticChange) then
|
|
currentCount = currentCount + 1
|
|
end
|
|
end
|
|
|
|
if (attLimit > 0 && currentCount >= attLimit) then
|
|
return false
|
|
end
|
|
end
|
|
|
|
if (hook.Run("MW19_AllowAttachment", self, attachment) == false) then
|
|
return false
|
|
end
|
|
|
|
if (self:GetBlockerAttachment(attachment) != nil) then
|
|
return false
|
|
end
|
|
end
|
|
|
|
return true
|
|
end
|
|
|
|
function SWEP:SetGripPoseParameter(value)
|
|
if (CLIENT) then
|
|
if (self.GripPoseParameters == nil) then
|
|
mw_utils.ErrorPrint("SetGripPoseParameter: No left hand grip pose parameters have been defined!")
|
|
return
|
|
end
|
|
|
|
if (!table.HasValue(self.GripPoseParameters, value)) then
|
|
mw_utils.ErrorPrint("SetGripPoseParameter: Left hand grip pose parameter " ..value.. " was not defined in GripPoseParameters!")
|
|
return
|
|
end
|
|
|
|
self:GetViewModel().m_LeftHandGripPoseParameter = value
|
|
end
|
|
end
|
|
|
|
function SWEP:SetGripPoseParameter2(value)
|
|
if (CLIENT) then
|
|
if (self.GripPoseParameters2 == nil) then
|
|
mw_utils.ErrorPrint("SetGripPoseParameter2: No right hand grip pose parameters have been defined!")
|
|
return
|
|
end
|
|
|
|
if (!table.HasValue(self.GripPoseParameters2, value)) then
|
|
mw_utils.ErrorPrint("SetGripPoseParameter2: Right hand grip pose parameter " ..value.. " was not defined in GripPoseParameters2!")
|
|
return
|
|
end
|
|
|
|
self:GetViewModel().m_RightHandGripPoseParameter = value
|
|
end
|
|
end
|
|
|
|
function SWEP:SetWorldModel(path)
|
|
self:SetModel(path)
|
|
self.WorldModel = path
|
|
end |