Залив

This commit is contained in:
Refosel
2026-03-30 10:39:52 +03:00
commit 2b57c019cb
2010 changed files with 185745 additions and 0 deletions

View File

@@ -0,0 +1,329 @@
AddCSLuaFile()
function SWEP:CanPlayAimDownAnim()
return !self:HasFlag("Reloading")
&& !self:HasFlag("Drawing")
&& !self:HasFlag("Holstering")
&& !self:HasFlag("Sprinting")
&& CurTime() > self:GetNextSprintTime()
&& CurTime() > self:GetNextFiremodeTime()
&& CurTime() > self:GetNextMeleeTime()
&& CurTime() > self:GetNextPrimaryFire()
&& !self:HasFlag("Customizing")
end
function SWEP:CanPlayAimUpAnim()
return !self:HasFlag("Reloading")
&& !self:HasFlag("Drawing")
&& !self:HasFlag("Holstering")
&& !self:HasFlag("Sprinting")
&& CurTime() > self:GetNextSprintTime()
&& CurTime() > self:GetNextFiremodeTime()
&& CurTime() > self:GetNextMeleeTime()
&& CurTime() > self:GetNextPrimaryFire()
end
function SWEP:CanAim()
return --[[!self:HasFlag("Reloading")
&&!self:HasFlag("Drawing")
&&]] !self:HasFlag("Holstering")
&& !self:HasFlag("Sprinting")
&& !self:HasFlag("Customizing")
&& !self:HasFlag("PlayFirstDraw")
--&& (!self:GetOwner():KeyDown(IN_USE) || (self:GetOwner():KeyDown(IN_USE) && self:GetAimDelta() > 0))
&& CurTime() > self:GetNextSprintTime()
&& CurTime() > self:GetNextMeleeTime()
--&& !self:HasFlag("Customizing")
&& !(self.CanDisableAimReload && self:HasFlag("Reloading"))
&& !(self:IsOwnerMoving() && self:GetOwner():KeyDown(IN_SPEED))
--&& !self:GetOwner():KeyDown(IN_USE)
--&& CurTime() > self:GetNextFiremodeTime()
end
function SWEP:AimLogic()
if (CLIENT && game.SinglePlayer()) then
return
end
if (self:GetOwner():GetInfoNum("mgbase_toggleaim", 0) >= 1) then
if (self:GetOwner():KeyPressed(IN_ATTACK2)) then
self:SetToggleAim(!self:GetToggleAim())
end
else
self:SetToggleAim(self:GetOwner():KeyDown(IN_ATTACK2))
end
if (self:CanAim() && self:GetToggleAim()) then
self:RemoveFlag("Lowered")
self:SetNextInspectTime(0)
if (!self:HasFlag("Aiming") && self:CanPlayAimUpAnim()) then
self:PlayViewModelAnimation("Ads_In")
end
self:AddFlag("Aiming")
local speed = 1 / self:GetAnimLength("Ads_In");
self:SetAimDelta(math.min(self:GetAimDelta() + speed * FrameTime(), 1))
else
if (self:HasFlag("Aiming") && self:CanPlayAimDownAnim()) then
self:PlayViewModelAnimation("Ads_Out")
end
self:RemoveFlag("Aiming")
local speed = 1 / self:GetAnimLength("Ads_Out");
self:SetAimDelta(math.max(self:GetAimDelta() - speed * FrameTime(), 0))
end
--aim mode
if (self:GetAimMode() > 0) then
local len = self:GetAnimLength("Ads_In") * 0.5
if (self:GetSight() != nil && self:GetSight().ReticleHybrid != nil && self:GetSight().ReticleHybrid.OnAnimation != nil) then
len = self:GetAnimLength(self:GetSight().ReticleHybrid.OnAnimation)
end
local speed = 1 / len;
self:SetAimModeDelta(math.min(self:GetAimModeDelta() + speed * FrameTime(), 1))
else
local len = self:GetAnimLength("Ads_Out") * 0.5
if (self:GetSight() != nil && self:GetSight().ReticleHybrid != nil && self:GetSight().ReticleHybrid.OffAnimation != nil) then
len = self:GetAnimLength(self:GetSight().ReticleHybrid.OffAnimation)
end
local speed = 1 / len;
self:SetAimModeDelta(math.max(self:GetAimModeDelta() - speed * FrameTime(), 0))
end
--breathe
self:BreathingModule()
end
function SWEP:LauncherAimLogic()
if (CLIENT && game.SinglePlayer()) then
return
end
if (self:GetOwner():GetInfoNum("mgbase_toggleaim", 0) >= 1) then
if (self:GetOwner():KeyPressed(IN_ATTACK2)) then
self:SetToggleAim(!self:GetToggleAim())
end
else
self:SetToggleAim(self:GetOwner():KeyDown(IN_ATTACK2))
end
if (self:CanAim() && (self:GetToggleAim() || (self:GetOwner():KeyDown(IN_ATTACK) && !self:HasFlag("Reloading")))) then
self:RemoveFlag("Lowered")
self:SetNextInspectTime(0)
if (!self:HasFlag("Aiming") && self:CanPlayAimUpAnim()) then
self:PlayViewModelAnimation("Ads_In")
end
self:AddFlag("Aiming")
local speed = 1 / self:GetAnimLength("Ads_In");
self:SetAimDelta(math.min(self:GetAimDelta() + speed * FrameTime(), 1))
else
if (self:HasFlag("Aiming") && self:CanPlayAimDownAnim()) then
self:PlayViewModelAnimation("Ads_Out")
end
self:RemoveFlag("Aiming")
local speed = 1 / self:GetAnimLength("Ads_Out");
self:SetAimDelta(math.max(self:GetAimDelta() - speed * FrameTime(), 0))
end
--aim mode
if (self:GetAimMode() > 0) then
local len = self:GetAnimLength("Ads_In") * 0.5
if (self:GetSight() != nil && self:GetSight().ReticleHybrid != nil && self:GetSight().ReticleHybrid.OnAnimation != nil) then
len = self:GetAnimLength(self:GetSight().ReticleHybrid.OnAnimation)
end
local speed = 1 / len;
self:SetAimModeDelta(math.min(self:GetAimModeDelta() + speed * FrameTime(), 1))
else
local len = self:GetAnimLength("Ads_Out") * 0.5
if (self:GetSight() != nil && self:GetSight().ReticleHybrid != nil && self:GetSight().ReticleHybrid.OffAnimation != nil) then
len = self:GetAnimLength(self:GetSight().ReticleHybrid.OffAnimation)
end
local speed = 1 / len;
self:SetAimModeDelta(math.max(self:GetAimModeDelta() - speed * FrameTime(), 0))
end
--breathe
self:BreathingModule()
self:TrackingModule()
end
function SWEP:BreathingModule()
if (self:GetSight() != nil && self:GetSight().Optic != nil && self:GetAimModeDelta() <= self.m_hybridSwitchThreshold && GetConVar("mgbase_sv_breathing"):GetInt() > 0) then
local mul = 0.5
if (self:HasFlag("Aiming")) then
if (self:GetOwner():KeyDown(IN_SPEED) && !self:GetHasRunOutOfBreath()) then
mul = 0.1
self:SetBreathingDelta(math.max(self:GetBreathingDelta() - FrameTime() * 0.3, 0))
if (self:GetBreathingDelta() <= 0) then
self:SetHasRunOutOfBreath(true)
end
end
else
self:SetBreathingDelta(math.min(self:GetBreathingDelta() + FrameTime() * 0.2, 1))
end
if (self:GetHasRunOutOfBreath()) then
mul = 0.5 + (3 * (1 - self:GetBreathingDelta()))
self:SetBreathingDelta(math.min(self:GetBreathingDelta() + FrameTime() * 0.2, 1))
if (self:GetBreathingDelta() >= 1) then
self:SetHasRunOutOfBreath(false)
end
end
local pitch = math.sin(CurTime() * 3) * math.cos(CurTime() * 1.5)
local yaw = math.cos(CurTime() * 1.5) * math.sin(CurTime() * 0.75)
local ang = Angle(pitch * 0.2, yaw * 0.2, 0)
ang:Mul(self:GetAimDelta() * mul)
self:SetBreathingAngle(ang)
else
self:SetBreathingAngle(mw_math.ZeroAngle)
end
end
local function GetAngleDifference(AngA, AngB)
local difference = 0
difference = difference + math.AngleDifference(AngA.p, AngB.p)
difference = difference + math.AngleDifference(AngA.r, AngB.r)
difference = difference + math.AngleDifference(AngA.y, AngB.y)
return difference
end
function SWEP:TrackingModule()
if !self.TrackingInfo then return end
local angleForgiveness = 2.5
local dir
if self.PingedEntity && self.PingedEntity:IsValid() then
dir = self.PingedEntity:WorldSpaceAABB() - self:GetOwner():WorldSpaceAABB()
dir = dir:Angle()
end
if self:GetAimDelta() <= 0.8 then
self:StopPingingEntity()
self:StopTrackingEntity()
else
local tr = self:GetOwner():GetEyeTrace()
if tr.HitWorld || !self:CanTrackEntity(tr.Entity) then
if self.PingedEntity && self.PingedEntity:IsValid() then
local dir = self.PingedEntity:WorldSpaceAABB() - self:GetOwner():WorldSpaceAABB()
dir = dir:Angle()
if GetAngleDifference(self:GetOwner():EyeAngles(), dir) > angleForgiveness then
self:StopPingingEntity()
self:StopTrackingEntity()
end
end
if self.TrackingInfo.TrackWorldPositions && !self.PingedEntity then
self.TrackedPosition = tr.HitPos
self.TrackedEntity = nil
end
elseif tr.Entity || GetAngleDifference(self:GetOwner():EyeAngles(), dir) > angleForgiveness then
if !self.PingData then
self:StartPingingEntity(tr.Entity)
else
if !self.TrackedEntity then
if CurTime() >= self.PingData.TrackTime then
self:StartTrackingEntity(tr.Entity)
else
for k, v in pairs(self.PingData.Pings) do
if !v.WasActivated && CurTime() >= v.Time then
self:EmitSound(self.TrackingInfo.PingSound)
v.WasActivated = true
end
end
end
end
end
else
self:StopTrackingEntity()
end
end
end
function SWEP:StartTrackingEntity(ent)
if !self:CanTrackEntity(ent) then return end
self.TrackedEntity = ent
self.TrackingSound = self:StartLoopingSound(self.TrackingInfo.Sound) --self.TrackingInfo.Sound
end
function SWEP:StopTrackingEntity()
self.TrackedEntity = nil
if self.TrackingSound then
self:StopLoopingSound(self.TrackingSound)
end
end
function SWEP:StartPingingEntity(ent)
if !self:CanTrackEntity(ent) then return end
self.PingedEntity = ent
self.PingData = {
TrackTime = CurTime() + self.TrackingInfo.PingTime * (self.TrackingInfo.PingCount + 1) - self.TrackingInfo.PingTime,
Pings = {}
}
for i = 1, self.TrackingInfo.PingCount, 1 do
self.PingData.Pings[i] = {
Time = (CurTime() + self.TrackingInfo.PingTime * i) - self.TrackingInfo.PingTime,
WasActivated = false,
}
end
end
function SWEP:StopPingingEntity()
self.PingedEntity = nil
self.PingData = nil
end
function SWEP:CanTrackEntity(ent)
return ent:IsNPC() || ent:IsNextBot() || ent:IsVehicle() || ent:IsPlayer()
end
function SWEP:AdjustMouseSensitivity()
local mul = Lerp(self:GetAimModeDelta(), self.Zoom.FovMultiplier, 0.9)
--[[if (self:GetSight() != nil && self:GetSight().Optic != nil && self:GetAimMode() <= 0) then
mul = mul / (self:GetSight().Optic.FOV * 0.95) * GetConVar("mgbase_scopesens"):GetFloat()
end]]
return Lerp(self:GetAimDelta(), 1, mul)
end

View File

@@ -0,0 +1,40 @@
require("mw_math")
AddCSLuaFile()
function SWEP:CanChangeAimMode()
return ((self:GetSight() != nil && self:GetSight().ReticleHybrid != nil) || (self:GetLaser() != nil && self.LaserAimAngles != nil && self.LaserAimPos != nil))
&& !self:HasFlag("Reloading")
&& CurTime() > self:GetNextPrimaryFire()
&& self:HasFlag("Aiming")
&& CurTime() > self:GetNextAimModeTime()
end
function SWEP:ChangeAimMode()
if (!self:CanChangeAimMode()) then
return
end
self:SetAimMode(self:GetAimMode() == 1 && 0 || 1)
if (self:GetAimMode() == 0) then
--self:SetNextAimModeTime(CurTime() + 0.25)
if (self:GetSight() != nil && self:GetSight().ReticleHybrid != nil && self:GetSight().ReticleHybrid.OnAnimation != nil) then
self:PlayViewModelAnimation(self:GetSight().ReticleHybrid.OnAnimation)
self:SetNextPrimaryFire(CurTime() + self:GetAnimLength(self:GetSight().ReticleHybrid.OnAnimation))
self:SetNextAimModeTime(CurTime() + self:GetAnimLength(self:GetSight().ReticleHybrid.OnAnimation))
end
self:EmitSound("Canted.Off")
else
--self:SetNextAimModeTime(CurTime() + 0.25)
if (self:GetSight() != nil && self:GetSight().ReticleHybrid != nil && self:GetSight().ReticleHybrid.OffAnimation != nil) then
self:PlayViewModelAnimation(self:GetSight().ReticleHybrid.OffAnimation)
self:SetNextPrimaryFire(CurTime() + self:GetAnimLength(self:GetSight().ReticleHybrid.OffAnimation))
self:SetNextAimModeTime(CurTime() + self:GetAnimLength(self:GetSight().ReticleHybrid.OffAnimation))
end
self:EmitSound("Canted.On")
end
end

View File

@@ -0,0 +1,69 @@
AddCSLuaFile()
function SWEP:CanDeployBipod()
return !self:HasFlag("Lowered")
&& !self:HasFlag("Drawing")
&& !self:HasFlag("Holstering")
&& !self:HasFlag("Customizing")
&& CurTime() >= self:GetNextMeleeTime()
&& (!self:HasFlag("Reloading") || self:HasFlag("Aiming"))
&& CurTime() >= self:GetNextInspectTime()
end
function SWEP:BipodLogic()
if (CLIENT && game.SinglePlayer()) then
return
end
if (self:GetBipod() == nil || !self:CanDeployBipod()) then
if (self:HasFlag("BipodDeployed")) then
self:EmitSound("ViewModel.BipodExit")
end
self:RemoveFlag("BipodDeployed")
return
end
local bDeployed = false
if (!self:IsOwnerMoving() && self:GetOwner():IsOnGround()) then
local pos = self:GetOwner():EyePos() + Angle(0, self:GetOwner():EyeAngles().y, 0):Forward() * 16
if (!self:GetOwner():Crouching()) then
local tr = util.TraceHull({
start = pos,
endpos = pos - Vector(0, 0, 32),
mins = Vector(-16, -16, 0),
maxs = Vector(16, 16, 2),
filter = player.GetAll(),
mask = MASK_PLAYERSOLID
})
bDeployed = tr.Hit && !tr.StartSolid
else
bDeployed = true
end
end
if (self:HasFlag("BipodDeployed") != bDeployed) then
if (bDeployed) then
self:EmitSound("ViewModel.BipodDeploy")
if (!self:HasFlag("Aiming")) then
self:PlayViewModelAnimation(self.Animations.Bipod_Deploy != nil && "Bipod_Deploy" || "Jog_Out")
end
else
self:EmitSound("ViewModel.BipodExit")
if (!self:HasFlag("Aiming")) then
self:PlayViewModelAnimation(self.Animations.Bipod_Leave != nil && "Bipod_Leave" || "Jump")
end
end
end
if (bDeployed) then
self:AddFlag("BipodDeployed")
else
self:RemoveFlag("BipodDeployed")
end
end

View File

@@ -0,0 +1,23 @@
AddCSLuaFile()
local buttonFunctions = {
["mgbase_binds_melee"] = function(weapon) weapon:Melee() end,
["mgbase_binds_firemode"] = function(weapon) weapon:ChangeFiremode() end,
["mgbase_binds_safety"] = function(weapon) weapon:ChangeSafety() end,
["mgbase_binds_inspect"] = function(weapon) weapon:Inspect() end,
["mgbase_binds_customize"] = function(weapon) weapon:Customize(!weapon:HasFlag("Customizing")) end,
["mgbase_binds_switchsights"] = function(weapon) weapon:ChangeAimMode() end,
["mgbase_binds_holster"] = function(weapon) if (weapon:HasFlag("Holstering") && weapon:GetNextWeapon() != weapon:GetOwner()) then weapon:Deploy() else weapon:Holster() end end
}
function SWEP:HandleButton(btn)
if (btn == 0) then
return
end
for convar, func in pairs(buttonFunctions) do
if (self:GetOwner():GetInfoNum(convar, -1) == btn) then
func(self)
end
end
end

View File

@@ -0,0 +1,897 @@
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

View File

@@ -0,0 +1,130 @@
AddCSLuaFile()
require("mw_utils")
--name, int
SWEP.NetworkedFlags = {}
SWEP.NetworkedFlagIndices = {}
local function getFlagIndex(networkedFlag)
return math.floor(networkedFlag / 31)
end
local function getFlagValue(networkedFlag)
return 2 ^ (networkedFlag % 31)
end
--flag networking. using string literals as it's easier to add flags for custom functionality
--and lua takes care of them for us anyways
local function networkFlag(weapon, name)
local highestFlagValue = table.Count(weapon.NetworkedFlags)
local currentFlagIndex = getFlagIndex(highestFlagValue)
--have to do 31 because it's signed int
if (highestFlagValue % 31 == 0) then
weapon:CustomNetworkVar("Int", "Flags"..currentFlagIndex)
weapon.NetworkedFlagIndices[currentFlagIndex] = "Flags"..currentFlagIndex
mw_utils.DevPrint("networkFlag: Registered new set of flags (Flags"..currentFlagIndex..").")
end
weapon.NetworkedFlags[name] = highestFlagValue
end
SWEP.VarCount = {}
function SWEP:CustomNetworkVar(typ, name)
if (typ == "Flag") then
networkFlag(self, name)
return
end
local count = self.VarCount[typ] || -1
count = count + 1
self:NetworkVar(typ, count, name)
self.VarCount[typ] = count
end
--i've decided to not check if a flag name exists. if you're looking for a flag
--that doesn't exist i'd prefer if you checked your code when it errors
function SWEP:HasFlag(name)
local networkedFlag = self.NetworkedFlags[name]
local flagIndex, flagValue = getFlagIndex(networkedFlag), getFlagValue(networkedFlag)
return bit.band(self.dt[self.NetworkedFlagIndices[flagIndex]], flagValue) == flagValue
end
function SWEP:AddFlag(name)
local networkedFlag = self.NetworkedFlags[name]
local flagIndex, flagValue = getFlagIndex(networkedFlag), getFlagValue(networkedFlag)
local flagDt = self.NetworkedFlagIndices[flagIndex]
self.dt[flagDt] = bit.bor(self.dt[flagDt], flagValue)
end
function SWEP:RemoveFlag(name)
local networkedFlag = self.NetworkedFlags[name]
local flagIndex, flagValue = getFlagIndex(networkedFlag), getFlagValue(networkedFlag)
local flagDt = self.NetworkedFlagIndices[flagIndex]
self.dt[flagDt] = bit.band(self.dt[flagDt], bit.bnot(flagValue))
end
function SWEP:ToggleFlag(name)
if (self:HasFlag(name)) then
self:RemoveFlag(name)
else
self:AddFlag(name)
end
end
--TODO: reconsider a lot of these vars, some probably dont need to be
function SWEP:SetupDataTables()
--idea: most of the gun's actions can be simplified with one timer. this game does not allow for overlayed animations,
--we can't have more than one action playing on the gun at the same time.
--get rid of all these "time" dtvars, just use one
self:CustomNetworkVar("Float", "NextActionTime")
self:CustomNetworkVar("Float", "NextReloadTime")
self:CustomNetworkVar("Float", "NextMagTime")
self:CustomNetworkVar("Float", "NextHolsterTime")
self:CustomNetworkVar("Float", "AimDelta")
self:CustomNetworkVar("Float", "Cone")
self:CustomNetworkVar("Float", "NextSprintTime")
self:CustomNetworkVar("Float", "NextInspectTime")
self:CustomNetworkVar("Float", "NextFiremodeTime")
self:CustomNetworkVar("Float", "NextMeleeTime")
self:CustomNetworkVar("Float", "TriggerDelta")
self:CustomNetworkVar("Float", "NextAimModeTime")
self:CustomNetworkVar("Float", "AimModeDelta")
self:CustomNetworkVar("Float", "BreathingDelta")
self:CustomNetworkVar("Flag", "MagInserted")
self:CustomNetworkVar("Flag", "PlayFirstDraw")
self:CustomNetworkVar("Flag", "Reloading")
self:CustomNetworkVar("Flag", "Drawing")
self:CustomNetworkVar("Flag", "Holstering")
self:CustomNetworkVar("Flag", "Aiming")
self:CustomNetworkVar("Flag", "Sprinting")
self:CustomNetworkVar("Flag", "Rechambered")
self:CustomNetworkVar("Flag", "HoldingTrigger")
self:CustomNetworkVar("Flag", "Customizing")
self:CustomNetworkVar("Flag", "Lowered")
self:CustomNetworkVar("Flag", "FlashlightOn")
self:CustomNetworkVar("Flag", "BipodDeployed")
self:CustomNetworkVar("Flag", "Inspecting")
self:CustomNetworkVar("Flag", "StoppedInspectAnimation")
self:CustomNetworkVar("Bool", "ToggleAim")
self:CustomNetworkVar("Bool", "HasRunOutOfBreath")
self:CustomNetworkVar("Entity", "NextWeapon")
self:CustomNetworkVar("Entity", "ViewModel")
self:CustomNetworkVar("Int", "SprayRounds")
self:CustomNetworkVar("Int", "Firemode")
self:CustomNetworkVar("Int", "BurstRounds")
self:CustomNetworkVar("Int", "PenetrationCount")
self:CustomNetworkVar("Int", "AimMode")
--self:CustomNetworkVar("String", "0", "Camo")
self:CustomNetworkVar("Angle", "BreathingAngle")
end

View File

@@ -0,0 +1,64 @@
AddCSLuaFile()
function SWEP:CanChangeFiremode()
return !self:HasFlag("Reloading")
&& !self:HasFlag("Drawing")
&& !self:HasFlag("Holstering")
&& (!self:HasFlag("Sprinting") || self:HasFlag("Lowered"))
&& CurTime() > self:GetNextSprintTime()
&& CurTime() > self:GetNextPrimaryFire()
&& CurTime() > self:GetNextMeleeTime()
&& CurTime() > self:GetNextFiremodeTime()
&& !self:HasFlag("Customizing")
end
function SWEP:ChangeFiremode()
if (CLIENT && game.SinglePlayer()) then
return
end
if (!self:CanChangeFiremode()) then
return
end
local index = self:GetFiremode()
if (self.Firemodes[index + 1]) then
index = index + 1
else
index = 1
end
if (self:GetFiremode() != index) then
local seqIndex = self:ApplyFiremode(index)
self:PlayViewModelAnimation(seqIndex)
local length = self:GetAnimation(seqIndex).Length || 0.5
self:SetNextFiremodeTime(CurTime() + length)
self:SetBurstRounds(0)
end
end
function SWEP:ApplyFiremodeStats()
return self.Firemodes[self:GetFiremode()].OnSet(self)
end
function SWEP:ApplyFiremode(index)
local seqIndex = "Idle"
if (type(index) == "string") then
index = tonumber(index)
end
self:SetFiremode(index)
if (game.SinglePlayer() || IsFirstTimePredicted()) then
self:BuildCustomizedGun() --to reset to defaults
end
if (game.SinglePlayer() && SERVER) then
self:CallOnClient("ApplyFiremode", index)
end
return self:ApplyFiremodeStats()
end

View File

@@ -0,0 +1,135 @@
AddCSLuaFile()
SWEP.HoldTypes = {
BoltAction = {
Idle = {Crouching = "ar2", Standing = "ar2"},
Aim = {Crouching = "ar2", Standing = "rpg"},
Down = {Crouching = "knife", Standing = "passive"},
Attack = ACT_HL2MP_GESTURE_RANGE_ATTACK_SHOTGUN,
Reload = ACT_HL2MP_GESTURE_RELOAD_SMG1,
Draw = ACT_HL2MP_GESTURE_RANGE_ATTACK_KNIFE,
Melee = ACT_HL2MP_GESTURE_RANGE_ATTACK_MELEE2
},
BigGun = {
Idle = {Crouching = "ar2", Standing = "ar2"},
Aim = {Crouching = "ar2", Standing = "rpg"},
Down = {Crouching = "knife", Standing = "passive"},
Attack = ACT_HL2MP_GESTURE_RANGE_ATTACK_REVOLVER,
Reload = ACT_HL2MP_GESTURE_RELOAD_SMG1,
Draw = ACT_HL2MP_GESTURE_RANGE_ATTACK_KNIFE,
Melee = ACT_HL2MP_GESTURE_RANGE_ATTACK_MELEE2
},
Rifle = {
Idle = {Crouching = "ar2", Standing = "ar2"},
Aim = {Crouching = "ar2", Standing = "rpg"},
Down = {Crouching = "knife", Standing = "passive"},
Attack = ACT_HL2MP_GESTURE_RANGE_ATTACK_SMG1,
Reload = ACT_HL2MP_GESTURE_RELOAD_SMG1,
Draw = ACT_HL2MP_GESTURE_RANGE_ATTACK_KNIFE,
Melee = ACT_HL2MP_GESTURE_RANGE_ATTACK_MELEE2
},
RifleWithVerticalGrip = {
Idle = {Crouching = "smg", Standing = "smg"},
Aim = {Crouching = "smg", Standing = "rpg"},
Down = {Crouching = "knife", Standing = "passive"},
Attack = ACT_HL2MP_GESTURE_RANGE_ATTACK_SMG1,
Reload = ACT_HL2MP_GESTURE_RELOAD_SMG1,
Draw = ACT_HL2MP_GESTURE_RANGE_ATTACK_KNIFE,
Melee = ACT_HL2MP_GESTURE_RANGE_ATTACK_MELEE2
},
RPG = {
Idle = {Crouching = "rpg", Standing = "rpg"},
Aim = {Crouching = "rpg", Standing = "rpg"},
Down = {Crouching = "knife", Standing = "passive"},
Attack = ACT_HL2MP_GESTURE_RANGE_ATTACK_SHOTGUN,
Reload = ACT_HL2MP_GESTURE_RELOAD_SMG1,
Draw = ACT_HL2MP_GESTURE_RANGE_ATTACK_KNIFE,
Melee = ACT_HL2MP_GESTURE_RANGE_ATTACK_MELEE2
},
TinyGun = {
Idle = {Crouching = "ar2", Standing = "rpg"},
Aim = {Crouching = "ar2", Standing = "rpg"},
Down = {Crouching = "normal", Standing = "passive"},
Attack = ACT_HL2MP_GESTURE_RANGE_ATTACK_SMG1,
Reload = ACT_HL2MP_GESTURE_RELOAD_SMG1,
Draw = ACT_HL2MP_GESTURE_RANGE_ATTACK_KNIFE,
Melee = ACT_HL2MP_GESTURE_RANGE_ATTACK_MELEE2
},
Saw = {
Idle = {Crouching = "physgun", Standing = "physgun"},
Aim = {Crouching = "physgun", Standing = "physgun"},
Down = {Crouching = "physgun", Standing = "physgun"},
Attack = ACT_HL2MP_GESTURE_RANGE_ATTACK_SMG1,
Reload = ACT_HL2MP_GESTURE_RELOAD_SMG1,
Draw = ACT_HL2MP_GESTURE_RANGE_ATTACK_KNIFE,
Melee = ACT_HL2MP_GESTURE_RANGE_ATTACK_MELEE2
},
Bipod = {
Idle = {Crouching = "rpg", Standing = "rpg"},
Aim = {Crouching = "rpg", Standing = "rpg"},
Down = {Crouching = "knife", Standing = "passive"},
Attack = ACT_HL2MP_GESTURE_RANGE_ATTACK_SMG1,
Reload = ACT_HL2MP_GESTURE_RELOAD_SMG1,
Draw = ACT_HL2MP_GESTURE_RANGE_ATTACK_KNIFE,
Melee = ACT_HL2MP_GESTURE_RANGE_ATTACK_MELEE2
},
Shotgun = {
Idle = {Crouching = "crossbow", Standing = "crossbow"},
Aim = {Crouching = "crossbow", Standing = "ar2"},
Down = {Crouching = "knife", Standing = "passive"},
Attack = ACT_HL2MP_GESTURE_RANGE_ATTACK_SHOTGUN,
Reload = ACT_HL2MP_GESTURE_RELOAD_SMG1,
Draw = ACT_HL2MP_GESTURE_RANGE_ATTACK_KNIFE,
Melee = ACT_HL2MP_GESTURE_RANGE_ATTACK_MELEE2
},
Pistol = {
Idle = {Crouching = "pistol", Standing = "revolver"},
Aim = {Crouching = "pistol", Standing = "revolver"},
Down = {Crouching = "knife", Standing = "normal"},
Attack = ACT_HL2MP_GESTURE_RANGE_ATTACK_PISTOL,
Reload = ACT_HL2MP_GESTURE_RELOAD_PISTOL,
Draw = ACT_HL2MP_GESTURE_RANGE_ATTACK_KNIFE,
Melee = ACT_HL2MP_GESTURE_RANGE_ATTACK_MELEE2
},
Revolver = {
Idle = {Crouching = "pistol", Standing = "revolver"},
Aim = {Crouching = "pistol", Standing = "revolver"},
Down = {Crouching = "knife", Standing = "normal"},
Attack = ACT_HL2MP_GESTURE_RANGE_ATTACK_PISTOL,
Reload = ACT_HL2MP_GESTURE_RELOAD_REVOLVER,
Draw = ACT_HL2MP_GESTURE_RANGE_ATTACK_KNIFE,
Melee = ACT_HL2MP_GESTURE_RANGE_ATTACK_MELEE2
},
AmmoBox = {
Idle = {Crouching = "fist", Standing = "fist"},
Aim = {Crouching = "fist", Standing = "fist"},
Down = {Crouching = "knife", Standing = "normal"},
Attack = ACT_HL2MP_GESTURE_RANGE_ATTACK_PISTOL,
Draw = ACT_HL2MP_GESTURE_RANGE_ATTACK_KNIFE,
Deploy = ACT_GMOD_GESTURE_ITEM_PLACE,
Melee = ACT_HL2MP_GESTURE_RANGE_ATTACK_MELEE2
},
Shield = {
Idle = {Crouching = "fist", Standing = "fist"},
Aim = {Crouching = "fist", Standing = "fist"},
Down = {Crouching = "knife", Standing = "knife"},
Attack = ACT_HL2MP_GESTURE_RANGE_ATTACK_PISTOL,
Draw = ACT_HL2MP_GESTURE_RANGE_ATTACK_KNIFE,
Deploy = ACT_GMOD_GESTURE_ITEM_PLACE,
Melee = ACT_HL2MP_GESTURE_RANGE_ATTACK_MELEE
}
}
--for reload, attack and draw visit: https://wiki.facepunch.com/gmod/Enums/ACT (only ACT_HL2MP_GESTURE_*)

View File

@@ -0,0 +1,70 @@
AddCSLuaFile()
function SWEP:CanInspect()
if (self:HasFlag("Customizing")) then
return false
end
if (CurTime() < self:GetNextPrimaryFire()) then
return false
end
if (self:HasFlag("Reloading") || self:HasFlag("Holstering") || self:HasFlag("Drawing") || self:HasFlag("Sprinting")) then
return false
end
if (CurTime() < self:GetNextSprintTime()) then
return false
end
if (CurTime() < self:GetNextMeleeTime()) then
return false
end
if (CurTime() < self:GetNextFiremodeTime()) then
return false
end
if (self:GetAimDelta() > 0) then
return false
end
if (self:HasFlag("Sprinting")) then
return
end
if (self:HasFlag("Drawing")) then
return false
end
return CurTime() > self:GetNextInspectTime()
end
function SWEP:Inspect()
if (CurTime() >= self:GetNextInspectTime()) then
self:RemoveFlag("StoppedInspectAnimation")
else
self:ToggleFlag("StoppedInspectAnimation")
end
if (self:CanInspect()) then
local inspIndex = (self:Clip1() <= 0 && self:GetAnimation("Inspect_Empty") != nil) && "Inspect_Empty" || "Inspect"
self:PlayViewModelAnimation(inspIndex)
self:SetNextInspectTime(CurTime() + self:GetAnimLength(inspIndex))
self:RemoveFlag("Lowered")
end
end
function SWEP:InspectLogic()
if (self:HasFlag("StoppedInspectAnimation")) then
self:SetNextInspectTime(self:GetNextInspectTime() + FrameTime())
end
if (CurTime() >= self:GetNextInspectTime()) then
self:RemoveFlag("StoppedInspectAnimation")
else
if (self:GetOwner():KeyDown(IN_ATTACK) && self:Clip1() > 0) then
self:SetNextInspectTime(0)
end
end
end

View File

@@ -0,0 +1,54 @@
AddCSLuaFile()
function SWEP:CanMelee()
return !self:HasFlag("Sprinting")
&& !self:HasFlag("Holstering")
&& !self:HasFlag("Drawing")
&& CurTime() > self:GetNextPrimaryFire()
&& CurTime() > self:GetNextSprintTime()
&& !self:HasFlag("Customizing")
&& CurTime() > self:GetNextMeleeTime()
end
function SWEP:Melee()
if (game.SinglePlayer() && CLIENT) then return end
if (!self:CanMelee()) then
return
end
self:RemoveFlag("Lowered")
self:SetNextInspectTime(0)
self:RemoveFlag("Reloading")
self:PlayerGesture(GESTURE_SLOT_ATTACK_AND_RELOAD, self.HoldTypes[self:GetCurrentHoldType()].Melee)
local size = self:GetAnimation("Melee").Size
local range = self:GetAnimation("Melee").Range
local bHit = false
self:GetOwner():FireBullets({
Src = self:GetOwner():EyePos(),
Dir = self:GetOwner():EyeAngles():Forward(),
Distance = range,
HullSize = size,
Tracer = 0,
Callback = function(attacker, btr, dmgInfo)
dmgInfo:SetDamage(self:GetAnimation("Melee_Hit").Damage)
dmgInfo:SetInflictor(self)
dmgInfo:SetAttacker(self:GetOwner())
dmgInfo:SetDamagePosition(btr.HitPos)
dmgInfo:SetDamageForce(self:GetOwner():EyeAngles():Forward() * (self:GetAnimation("Melee_Hit").Damage * 100))
dmgInfo:SetDamageType(DMG_CLUB + DMG_ALWAYSGIB)
bHit = true
end
})
if (bHit) then
self:SetNextMeleeTime(CurTime() + self:GetAnimLength("Melee_Hit", self:GetAnimation("Melee_Hit").Length))
self:PlayViewModelAnimation("Melee_Hit")
else
self:SetNextMeleeTime(CurTime() + self:GetAnimLength("Melee", self:GetAnimation("Melee").Length))
self:PlayViewModelAnimation("Melee")
end
end

View File

@@ -0,0 +1,708 @@
AddCSLuaFile()
function SWEP:CanAttack()
if (self:Clip1() <= 0) then
return false
end
if (self:GetAnimation("Rechamber") != nil && self:GetAnimation("Reload_Loop") != nil && self:HasFlag("Reloading") && !self:HasFlag("Customizing")) then
return true
end
if (self:GetAnimation("Rechamber") != nil && !self:HasFlag("Rechambered")) then
return false
end
if (self:HasFlag("Customizing")) then
return false
end
if (CurTime() < self:GetNextPrimaryFire()) then
return false
end
if (CurTime() < self:GetNextFiremodeTime()) then
return false
end
--[[if (self:GetOwner():KeyDown(IN_USE)) then
return false
end]]
if ((self:HasFlag("Reloading") && !self:CanAttackInterruptReload()) || self:HasFlag("Holstering") || self:HasFlag("Drawing") || self:HasFlag("Sprinting")) then
return false
end
if (CurTime() < self:GetNextMeleeTime()) then
return false
end
if (CurTime() < self:GetNextSprintTime()) then
return false
end
if (self.Primary.BurstRounds > 1 && self:GetBurstRounds() >= self.Primary.BurstRounds) then
return false
end
--[[if (CurTime() < self:GetNextReloadTime() && self:HasFlag("MagInserted")) then --avoid people from shooting after they canceled their reloads
return false
end]]
--yeah reward it
return !self.Trigger || self:GetTriggerDelta() >= 1
end
function SWEP:GetRecoilDecreaseEveryShotMultiplier()
local globalMul = 1
if (self.Recoil.DecreaseEveryShot != nil) then
globalMul = 1 - (self:GetSprayRounds() * self.Recoil.DecreaseEveryShot)
globalMul = math.max(globalMul, self.Recoil.MinDecreaseEveryShot || 0)
end
return globalMul
end
function SWEP:GetRecoilMultiplier()
if (self:HasFlag("BipodDeployed")) then
return 0.1
end
return 1
end
function SWEP:CalculateRecoil()
math.randomseed(self.Recoil.Seed + self:GetSprayRounds())
local verticalRecoil = math.min(self:GetSprayRounds(), math.min(self:GetMaxClip1() * 0.33, 20)) * 0.1 + math.Rand(self.Recoil.Vertical[1], self.Recoil.Vertical[2]) * GetConVar("mgbase_sv_recoil"):GetFloat()
local horizontalRecoil = math.Rand(self.Recoil.Horizontal[1], self.Recoil.Horizontal[2]) * GetConVar("mgbase_sv_recoil"):GetFloat()
local angles = Angle(-verticalRecoil, horizontalRecoil, horizontalRecoil * -0.3)
return angles * Lerp(self:GetAimDelta(), 1, self.Recoil.AdsMultiplier) * self:GetRecoilDecreaseEveryShotMultiplier() * self:GetRecoilMultiplier()
end
function SWEP:MetersToHU(meters)
return (meters * 100) / 2.54
end
SWEP.FireSurfaces = {
MAT_ANTLION, MAT_BLOODYFLESH, MAT_EGGSHELL, MAT_FLESH, MAT_ALIENFLESH, MAT_PLASTIC, MAT_FOLIAGE, MAT_SLOSH, MAT_GRASS, MAT_WOOD, MAT_DIRT
}
function SWEP:MakeLight(pos, color, brightness, dieTime)
if (SERVER && game.SinglePlayer()) then
local args = "Vector("..pos.x..", "..pos.y..", "..pos.z.."), Color("..color.r..", "..color.g..", "..color.b.."), "..brightness..", "..dieTime
self:GetOwner():SendLua("local e = Entity("..self:EntIndex()..") if (IsValid(e)) then e:MakeLight("..args..") end")
end
if (CLIENT) then
local dlight = DynamicLight(-1)
if (dlight) then
dlight.pos = pos
dlight.r = color.r
dlight.g = color.g
dlight.b = color.b
dlight.brightness = brightness
dlight.Decay = 1000
dlight.Size = 256
dlight.DieTime = dieTime
end
end
end
local function drawHitDebug(self, tr, damage, dist, effectiveRange, dropoffStart)
RunConsoleCommand("clear_debug_overlays")
timer.Simple(0, function()
local original = weapons.Get(self:GetClass())
local ang = tr.HitNormal:Angle()
debugoverlay.EntityTextAtPosition(tr.HitPos, 0, "°", 5, Color(0, 255, 0, 255))
--check if we have any atts that change range
if (self.Bullet.EffectiveRange != original.Bullet.EffectiveRange
|| self.Bullet.DropOffStartRange != original.Bullet.DropOffStartRange
|| self.Bullet.Damage[1] != original.Bullet.Damage[1]
|| self.Bullet.Damage[2] != original.Bullet.Damage[2]) then
debugoverlay.ScreenText(0.55, 0.51, "You have attachments that modify range values!", 5, Color(255, 100, 50, 255))
end
debugoverlay.ScreenText(0.55, 0.52, math.Round(dist - dropoffStart).." / "..math.Round(effectiveRange).." units ("..self.Bullet.EffectiveRange.."m)", 5, Color(0, 200, 50, 255))
debugoverlay.ScreenText(0.55, 0.53, math.floor(damage).." damage (raw)", 5, Color(255, 200, 0, 255))
end)
end
function SWEP:BulletCallbackInternal(attacker, tr, dmgInfo)
local dist = tr.HitPos:Distance(self:GetOwner():GetShootPos())
local effectiveRange = self:MetersToHU(self.Bullet.EffectiveRange)
local dropoffStart = self.Bullet.DropOffStartRange && self:MetersToHU(self.Bullet.DropOffStartRange) || 0
local damage
if !self.Explosive then --regular hitscan damage
damage = Lerp(math.Clamp((dist - dropoffStart) / effectiveRange, 0, 1), self.Bullet.Damage[1], self.Bullet.Damage[2])
damage = math.max(damage / self.Bullet.NumBullets, 1)
else --launcher damage
damage = self.Bullet.Damage[1] / self.Explosive.ImpactBlastRatio
end
local pen = self.Bullet.Penetration
if (SERVER && GetConVar("mgbase_debug_range"):GetInt() > 0) then
drawHitDebug(self, tr, damage, dist, effectiveRange, dropoffStart)
end
local bCanPenetrate = (GetConVar("mgbase_sv_full_penetration"):GetBool() || (self:GetMaxClip1() <= 10 || self:Clip1() % 2 == 0))
&& self.Bullet.NumBullets <= 1
&& (self.Projectile == nil || self.Projectile.Penetrate)
if (bCanPenetrate) then
if (self:GetPenetrationCount() < pen.MaxCount) then
local mul = pen.DamageMultiplier
local c = pen.MaxCount - self:GetPenetrationCount()
while (c > 0) do
mul = mul * pen.DamageMultiplier
c = c - 1
end
damage = damage * mul
end
end
if (tr.Entity:IsPlayer()) then
damage = damage * GetConVar("mgbase_sv_pvpdamage"):GetFloat()
elseif (tr.Entity:IsNPC() || tr.Entity:IsNextBot()) then
damage = damage * GetConVar("mgbase_sv_pvedamage"):GetFloat()
end
local bGenericButHead = tr.Entity:EyePos() != tr.Entity:GetPos() && tr.HitGroup == HITGROUP_GENERIC && tr.HitPos.z > tr.Entity:EyePos().z
local bHeadshot = tr.HitGroup == HITGROUP_HEAD || bGenericButHead
if (bGenericButHead) then
tr.HitGroup = HITGROUP_HEAD
damage = damage * 2
end
if (bHeadshot) then
dmgInfo:SetDamageCustom(1)
damage = damage * (self.Bullet.HeadshotMultiplier || 1)
elseif (tr.HitGroup == HITGROUP_LEFTARM || tr.HitGroup == HITGROUP_RIGHTARM) then
damage = damage * 4
elseif (tr.HitGroup == HITGROUP_LEFTLEG || tr.HitGroup == HITGROUP_RIGHTLEG) then
damage = damage * 2
end
dmgInfo:SetDamage(damage + 1)
if (tr.Entity == self.lastHitEntity && (tr.Entity:IsPlayer() || tr.Entity:IsNPC() || tr.Entity:IsNextBot())) then --if we are penetrating something again (bad coz we apply double damage this way)
dmgInfo:SetDamage(0)
end
if (bCanPenetrate) then
self.lastHitEntity = tr.Entity
end
if (self.Projectile == nil) then
dmgInfo:SetDamageType(DMG_BULLET)
end
dmgInfo:SetDamageForce(tr.Normal * (self.Bullet.Damage[2] * self.Bullet.PhysicsMultiplier * 200) / self.Bullet.NumBullets)
local bInWater = bit.band(util.PointContents(tr.HitPos), CONTENTS_WATER) == CONTENTS_WATER
if (!bInWater) then
for _, att in pairs(self:GetAllAttachmentsInUse()) do
if (att.OnImpact != nil) then
att:OnImpact(self, dmgInfo, tr)
end
end
end
local bCanRicochet = !tr.bFromRicochet && !bWater && (tr.Entity:IsWorld() || tr.Entity:Health() <= 0) && !tr.Entity:IsNPC() && !tr.Entity:IsPlayer() && !tr.Entity:IsNextBot()
math.randomseed(self:Clip1() + self:Ammo1())
if (self.Bullet.Ricochet && bCanRicochet && math.random(1, math.Clamp(self:GetMaxClip1() / 10, 2, 4)) == 1) then
local finalDir = tr.HitNormal + VectorRand()
if (IsFirstTimePredicted()) then
for _, e in pairs(ents.FindInSphere(tr.HitPos, 1024)) do
if (e == self:GetOwner()) then
continue
end
if (!e:IsNPC() && !e:IsPlayer() && !e:IsNextBot()) then
continue
end
if (e:Health() <= 0) then
continue
end
local dir = (e:WorldSpaceCenter() - tr.HitPos):GetNormalized()
local dot = tr.HitNormal:Dot(dir)
if (dot < 0.5) then
continue
end
if (!e:IsLineOfSightClear(tr.HitPos)) then
continue
end
local bCanTarget = (e:IsNPC() || e:IsNextBot())
|| (e:IsPlayer() && (GetConVar("sbox_playershurtplayers"):GetInt() > 0 || e:Team() != self:GetOwner():Team()))
if (bCanTarget) then
finalDir = dir + (VectorRand() * 0.01)
break
end
end
end
if (SERVER) then
sound.Play("^viper/shared/blt_ricco_0"..math.random(1, 6)..".wav", tr.HitPos, 85, math.random(95, 105), 1)
end --i was forced, suppresshostevents does nothing like always
--fire forward
self:GetOwner():FireBullets({
Attacker = self:GetOwner(),
Src = tr.HitPos,
Dir = finalDir,
Num = 1,
Tracer = 0,
Callback = function(attacker, tr, dmgInfo)
tr.bFromRicochet = true
if (IsFirstTimePredicted()) then
local ed = EffectData()
ed:SetScale(5000) --speed
ed:SetStart(tr.StartPos)
ed:SetOrigin(tr.HitPos)
ed:SetNormal(finalDir)
ed:SetEntity(self)
util.Effect("Tracer", ed)
ed = EffectData()
ed:SetOrigin(tr.StartPos)
ed:SetMagnitude(1)
ed:SetScale(1)
ed:SetNormal(tr.HitNormal)
ed:SetRadius(2)
util.Effect("Sparks", ed)
--[[if (CLIENT) then
local dlight = DynamicLight(self:EntIndex())
if (dlight) then
dlight.pos = tr.StartPos
dlight.r = 255
dlight.g = 75
dlight.b = 0
dlight.brightness = 5
dlight.Decay = 500
dlight.Size = 8
dlight.DieTime = CurTime()
end
end]]
end
self:BulletCallback(attacker, tr, dmgInfo)
end
})
return --stop penetration
end
if (damage <= 1.9 || tr.HitTexture == "**displacement**" || bInWater || tr.bFromRicochet) then
return
end
if (bCanPenetrate && self:GetPenetrationCount() > 0) then
if (tr.HitNoDraw || tr.HitSky) then
return
end
local output = {}
local dir = tr.Normal
local start = tr.HitPos
if (IsFirstTimePredicted()) then
--debugoverlay.Axis(tr.HitPos, tr.HitNormal:Angle(), 5, 5, true)
util.TraceLine({
start = tr.HitPos + tr.Normal,
endpos = tr.HitPos + tr.Normal * pen.Thickness,
mask = MASK_SHOT,
filter = {tr.Entity},
ignoreworld = !IsValid(tr.Entity),
output = output
})
util.TraceLine({
start = output.HitPos,
endpos = tr.HitPos,
mask = MASK_SHOT,
output = output
})
--debugoverlay.Line(tr.HitPos, output.HitPos, 5, Color(255, 0, 0, 255), true)
end
if (output != nil && !output.StartSolid && !output.HitNoDraw && !output.HitSky) then
self:SetPenetrationCount(self:GetPenetrationCount() - 1)
--fire back to the wall to make hole
self:GetOwner():FireBullets({
Attacker = self:GetOwner(),
Src = output.StartPos,
Dir = -tr.Normal,
Num = 1,
Tracer = 0,
Damage = 0
})
--fire forward
self:GetOwner():FireBullets({
Attacker = self:GetOwner(),
Src = output.HitPos,
Dir = tr.Normal,
Num = 1,
Tracer = 0,
Callback = function(attacker, tr, dmgInfo)
self:BulletCallback(attacker, tr, dmgInfo)
end
})
end
end
end
function SWEP:BulletCallback(attacker, tr, dmgInfo)
self:BulletCallbackInternal(attacker, tr, dmgInfo)
end
function SWEP:Bullets(hitpos)
self.lastHitEntity = NULL
self:SetPenetrationCount(self.Bullet.Penetration != nil && self.Bullet.Penetration.MaxCount || 0)
local spread = Vector(self:GetCone(), self:GetCone()) * 0.1
if (self.Bullet.NumBullets == 1) then
spread = LerpVector(self:GetAimDelta(), spread, Vector(0, 0))
end
local dir = (self:GetOwner():EyeAngles() + self:GetOwner():GetViewPunchAngles() + self:GetBreathingSwayAngle()):Forward()
if (hitpos != nil && isvector(hitpos)) then
dir = (hitpos - self:GetOwner():EyePos()):GetNormalized()
spread = Vector()
end
local bCanAssist = self:GetAimDelta() > 0.5 && self:GetOwner():GetInfoNum("mgbase_aimassist", 1) > 0 && GetConVar("mgbase_sv_aimassist"):GetInt() > 0
bCanAssist = self.Bullet.NumBullets > 1 || bCanAssist
self:GetOwner():FireBullets({
Attacker = self:GetOwner(),
Src = self:GetOwner():EyePos(),
Dir = dir,
Spread = spread,
Num = self.Bullet.NumBullets,
Damage = self.Bullet.Damage[1], --for some fucking bullet mod or something idk
HullSize = bCanAssist && 1 || 0,
--Force = (self.Bullet.Damage[1] * self.Bullet.PhysicsMultiplier) * 0.01,
Distance = self:MetersToHU(self.Bullet.Range) * GetConVar("mgbase_sv_range"):GetFloat(),
Tracer = self.Bullet.Tracer && 1 || 0,
Callback = function(attacker, tr, dmgInfo)
self:BulletCallback(attacker, tr, dmgInfo, bFromServer)
if (IsFirstTimePredicted() || game.SinglePlayer()) then
self:FireTracer(tr.HitPos)
end
end
})
end
function SWEP:GetTracerOrigin()
--[[local vm = self:GetViewModel()
local att = vm:GetAttachment(vm:LookupAttachment("muzzle"))
if (att == nil) then
return self:GetPos()
end
return att.Pos - Vector(0, 0, 10)]]
if (CLIENT && self:IsCarriedByLocalPlayer()) then
local attEnt, attId = self:GetViewModel():FindAttachment("muzzle")
return attEnt:GetAttachment(attId).Pos
end
return self:GetPos()
end
function SWEP:PrimaryAttack()
if (!self:CanAttack()) then
return
end
self:RemoveFlag("Lowered")
self:SetNextInspectTime(0)
if (self:HasFlag("Reloading")) then
self:EndReload()
if (self:GetAnimation("Rechamber") != nil && self:GetAnimation("Reload_Loop") != nil) then
return
end
end
if (self.Animations.Rechamber || self:Clip1() <= 1) then
self:RemoveFlag("Rechambered")
if (self:Clip1() <= 1 && self.ReloadRechambers) then
self:AddFlag("Rechambered")
end
end
self:SetClip1(self:Clip1() - 1)
self:SetSprayRounds(self:GetSprayRounds() + 1)
--self:GetOwner():DoCustomAnimEvent(PLAYERANIMEVENT_ATTACK_PRIMARY, 0)
self:PlayerGesture(GESTURE_SLOT_ATTACK_AND_RELOAD, self.HoldTypes[self:GetCurrentHoldType()].Attack)
local seqIndex = "Fire"
if (self:Clip1() <= 0 && self:GetAnimation("Fire_Last") != nil) then
seqIndex = "Fire_Last"
end
self:PlayViewModelAnimation(seqIndex)
self:SetNextPrimaryFire(CurTime() + (60 / self.Primary.RPM))
self:SetBurstRounds(self:GetBurstRounds() + 1)
if (self:GetBurstRounds() >= self.Primary.BurstRounds && self.Primary.BurstRounds > 1) then
self:SetNextPrimaryFire(CurTime() + self.Primary.BurstDelay)
if (self.Trigger == nil) then
self:SetBurstRounds(0)
end
end
local punch = self:CalculateRecoil()
self:GetOwner():ViewPunch(punch)
self:HandleReverb()
if (!game.SinglePlayer()) then
self:EmitSound(self.Primary.Sound)
else
self:GetOwner():SendLua("LocalPlayer():EmitSound('"..self.Primary.Sound.."')")
end
if (self.Primary.TrailingSound != nil) then
if (!game.SinglePlayer()) then
self:EmitSound(self.Primary.TrailingSound)
else
self:GetOwner():SendLua("LocalPlayer():EmitSound('"..self.Primary.TrailingSound.."')")
end
end
--bullets
self.lastHitEntity = NULL
if (!self.Projectile) then
self:Bullets()
else
self:Projectiles()
end
--setting the eye angles after we shoot, feels like shit otherwise
if (self.Recoil.Punch != nil) then
if (IsFirstTimePredicted() || game.SinglePlayer()) then
punch:Mul(self.Recoil.Punch)
local ang = self:GetOwner():EyeAngles() + punch
ang.r = 0
self:GetOwner():SetEyeAngles(ang)
end
end
self:SetLastShootTime(CurTime())
--cone
self:SetCone(math.min(self:GetCone() + self.Cone.Increase * Lerp(self:GetAimDelta(), 10, 10 * self.Cone.AdsMultiplier), self:GetConeMax()))
if (CLIENT && IsFirstTimePredicted()) then
self:ShakeCamera()
self:ShakeViewModel()
end
if (SERVER && game.SinglePlayer()) then
self:CallOnClient("ShakeCamera")
self:CallOnClient("ShakeViewModel")
end
end
function SWEP:GetConeDecreaseEveryShotMultiplier()
local recoilGlobalMul = 1
if (self.Cone.DecreaseEveryShot != nil) then
recoilGlobalMul = 1 - (self:GetSprayRounds() * self.Cone.DecreaseEveryShot)
recoilGlobalMul = math.max(recoilGlobalMul, self.Cone.MinDecreaseEveryShot || 0)
end
return recoilGlobalMul
end
function SWEP:GetConeMax()
local cone = (self.Cone.Max * self:GetConeDecreaseEveryShotMultiplier()) / GetConVar("mgbase_sv_accuracy"):GetFloat()
if (self:HasFlag("BipodDeployed")) then
cone = cone * 0.25
end
return cone
end
function SWEP:GetConeMin()
local cone = (Lerp(self:GetAimDelta(), self.Cone.Hip, self.Cone.Ads) * self:GetConeDecreaseEveryShotMultiplier()) / GetConVar("mgbase_sv_accuracy"):GetFloat()
if (self:HasFlag("BipodDeployed")) then
cone = cone * 0.25
end
return cone
end
function SWEP:ShakeCamera()
self.Camera.Shake = self.Recoil.Shake
end
local recoilFuncs = {
[true] = function(w, name) return w.Recoil.ViewModel[name] || 1 end,
[false] = function() return 1 end
}
local function getRecoilValue(w, name)
return recoilFuncs[w.Recoil.ViewModel != nil](w, name)
end
function SWEP:ShakeViewModel()
--local seed = math.randomseed(self:GetSprayRounds())
local vm = self:GetViewModel()
local recoilPos = Vector(0, 3, -0.5)
local recoilAng = Angle(0, 0, -2)
if (self.ViewModelOffsets.Recoil != nil) then
recoilPos = Vector(self.ViewModelOffsets.Recoil.Pos) || recoilPos
recoilAng = Angle(self.ViewModelOffsets.Recoil.Angles) || recoilAng
end
recoilPos:Mul(1 - self:GetAimDelta())
recoilAng.p = recoilAng.p * (1 - self:GetAimDelta())
recoilAng.y = recoilAng.y * (1 - self:GetAimDelta())
local delta = 1 - self:GetAimDelta()
local cone = math.Clamp(self:GetCone(), 0.85, 1.2)
cone = cone * 0.5
cone = Lerp(delta, 0.5, cone)
delta = Lerp(delta, 0.3, 1)
local vpAngles = self:GetOwner():GetViewPunchAngles()
vpAngles.p = (vpAngles.p * Lerp(self:GetAimDelta(), 0, 0.1)) + math.Rand(-cone, cone)
vpAngles.y = vpAngles.y * Lerp(self:GetAimDelta(), 0.1, 0.5) + Lerp(self:GetAimDelta(), math.Rand(-cone, cone), 0)
local ang = Angle()
ang.pitch = (vpAngles.pitch * getRecoilValue(self, "VerticalMultiplier")) + (recoilAng.pitch * delta)
ang.yaw = (-vpAngles.yaw * getRecoilValue(self, "HorizontalMultiplier")) + (recoilAng.yaw * delta)
ang.roll = (math.Rand(-1, 1) * getRecoilValue(self, "HorizontalMultiplier")) + Lerp(delta, recoilAng.roll, recoilAng.roll * 0.5)
local pos = Vector()
pos.y = Lerp(delta, recoilPos.y * 0.5, recoilPos.y) --+ math.sin(math.pi * (math.min(self:GetSprayRounds(), 4) / 4)) * (4 * getRecoilValue(self, "PushBackMultiplier"))
pos.x = (ang.yaw * 1.5 + (ang.roll * -0.5) + recoilPos.x) * delta
pos.z = (ang.pitch * 1.5 + (ang.roll * 0.5) + recoilPos.z) * delta
if (self:HasFlag("BipodDeployed")) then
pos.x = 0
pos.z = 0
ang.pitch = 0
ang.yaw = 0
ang.roll = 0
end
vm:SetRecoilTargets(pos, ang)
vm.m_RecoilRoll = math.Clamp(math.Rand(-1, 1) * 100000, -1, 1) * (self.Recoil.Shake * 3)
end
function SWEP:Projectiles()
if (CLIENT) then
return
end
self:SetPenetrationCount(self.Bullet.Penetration != nil && self.Bullet.Penetration.MaxCount || 0)
local proj = ents.Create(self.Projectile.Class)
local angles = self:GetOwner():EyeAngles() + self:GetOwner():GetViewPunchAngles()
local src = LerpVector(self:GetAimDelta(), self:GetOwner():EyePos() + angles:Up() * -3 + angles:Right() * 3, self:GetOwner():EyePos())
local dir = self:GetOwner():GetEyeTraceNoCursor().HitPos - src
math.randomseed(self:Clip1() + self:Ammo1() + CurTime() + self.Cone.Seed)
local spreadRight = math.Rand(-self:GetCone(), self:GetCone()) * 5
math.randomseed(-self:Clip1() * 0.5 + self:Ammo1() * 2 - CurTime() + self.Cone.Seed)
local spreadUp = math.Rand(-self:GetCone(), self:GetCone()) * 5
local spread = LerpVector(self:GetAimDelta(), Vector(spreadRight, spreadUp), Vector(0, 0))
angles:RotateAroundAxis(angles:Right(), spread.x)
angles:RotateAroundAxis(angles:Up(), spread.y)
proj.Weapon = self
proj:SetPos(src)
proj:SetAngles(angles)
proj:SetOwner(self:GetOwner())
proj:Spawn()
if (self.Projectile.Velocity != nil) then
proj:SetVelocity(angles:Forward() * self.Projectile.Velocity)
end
end
local function doTracer(wep, hitpos)
if (!wep.Bullet) then
return
end
local traceEffect = wep.Bullet.TracerName || "mgbase_tracer"
util.ParticleTracerEx(traceEffect, wep:GetTracerOrigin(), hitpos, false, wep:EntIndex(), -1)
end
function SWEP:FireTracer(pos)
if (self.Projectile != nil) then
return
end
if (CLIENT) then
doTracer(self, pos)
else
net.Start("mgbase_fire_tracer", false)
net.WriteEntity(self)
net.WriteVector(pos)
if (game.SinglePlayer()) then
net.Send(self:GetOwner())
else
net.SendOmit(self:GetOwner())
end
end
end
net.Receive("mgbase_fire_tracer", function()
local wep = net.ReadEntity()
local hitpos = net.ReadVector()
doTracer(wep, hitpos)
end)

View File

@@ -0,0 +1,202 @@
AddCSLuaFile()
function SWEP:CanReload()
if (self:HasFlag("Customizing")) then
return false
end
if (CurTime() < self:GetNextPrimaryFire()) then
return false
end
if (self:HasFlag("Reloading") || self:HasFlag("Holstering") || self:HasFlag("Drawing")) then
return false
end
if (GetConVar("mgbase_sv_sprintreloads"):GetInt() <= 0) then
if (self:HasFlag("Sprinting") || CurTime() < self:GetNextSprintTime()) then
return false
end
end
if (CurTime() < self:GetNextMeleeTime()) then
return false
end
if (CurTime() < self:GetNextFiremodeTime()) then
return false
end
if (CurTime() < self:GetNextReloadTime() && self:HasFlag("MagInserted")) then --avoid people from reloading after they canceled their reloads
return false
end
if (self:Ammo1() <= 0) then
return false
end
--[[if (self:GetOwner():KeyDown(IN_USE)) then
return false
end]]
if (self:HasFlag("Drawing")) then
return false
end
if (self:Clip1() >= self:GetMaxClip1WithChamber()) then
return false
end
return true
end
function SWEP:GetMaxClip1WithChamber()
if (self.CanChamberRound && self:HasFlag("Rechambered")) then
return self:GetMaxClip1() + 1
end
return self:GetMaxClip1()
end
function SWEP:Reload()
if (!self:CanReload()) then
return
end
self:AddFlag("Reloading")
local seqIndex = self:ChooseReloadAnim()
local length = self:GetAnimLength(seqIndex)
local magLength = self:GetAnimLength(seqIndex, self:GetAnimation(seqIndex).MagLength)
self:SetNextReloadTime(CurTime() + length)
self:SetNextMagTime(CurTime() + magLength)
self:RemoveFlag("MagInserted")
self:SetBurstRounds(0)
self:RemoveFlag("Lowered")
self:SetNextInspectTime(0)
if (self.ReloadRechambers) then
self:AddFlag("Rechambered")
end
if (self.EmptyReloadRechambers && seqIndex == "Reload_Empty") then
self:AddFlag("Rechambered")
end
if (self.Animations.Rechamber == nil) then
self:AddFlag("Rechambered")
end
self:PlayerGesture(GESTURE_SLOT_ATTACK_AND_RELOAD, self.HoldTypes[self:GetCurrentHoldType()].Reload)
self:PlayViewModelAnimation(seqIndex)
end
function SWEP:ChooseReloadAnim()
if (self:GetAnimation("Reload_Start") != nil) then
return "Reload_Start"
end
if (self:Clip1() <= 0 && self:GetAnimation("Reload_Empty")) then
return "Reload_Empty"
end
return "Reload"
end
function SWEP:ReloadLogic()
if (!self:HasFlag("Reloading")) then
return
end
if (self:GetAnimation("Reload_Loop") != nil) then
if (CurTime() > self:GetNextMagTime() && !self:HasFlag("MagInserted")) then
self:SetClip1(self:Clip1() + 1)
self:GetOwner():SetAmmo(self:Ammo1() - 1, self:GetPrimaryAmmoType())
self:AddFlag("MagInserted")
end
if (CurTime() > self:GetNextReloadTime()) then
local maxClip = self.Primary.ClipSize
if (GetConVar("mgbase_debug_mag"):GetInt() > 0) then
maxClip = 1
end
if (self:HasFlag("Rechambered")) then
maxClip = self:GetMaxClip1WithChamber()
end
if (self:Clip1() >= maxClip || self:GetOwner():GetAmmoCount(self:GetPrimaryAmmoType()) <= 0) then
self:EndReload()
return
end
self:PlayViewModelAnimation("Reload_Loop")
self:SetNextReloadTime(CurTime() + self:GetAnimLength("Reload_Loop"))
self:SetNextMagTime(CurTime() + self:GetAnimLength("Reload_Loop", self:GetAnimation("Reload_Loop").MagLength))
self:RemoveFlag("MagInserted")
self:PlayerGesture(GESTURE_SLOT_ATTACK_AND_RELOAD, self.HoldTypes[self:GetCurrentHoldType()].Reload)
end
else
if (CurTime() > self:GetNextMagTime() && !self:HasFlag("MagInserted")) then
local maxClip = self:GetMaxClip1()
if (self:Clip1() > 0) then
maxClip = self:GetMaxClip1WithChamber()
end
if (GetConVar("mgbase_debug_mag"):GetInt() > 0) then
maxClip = 1
if (self:Clip1() > 0) then
maxClip = 2
end
end
local ammoNeeded = math.min(maxClip - self:Clip1(), self:Ammo1())
self:SetClip1(self:Clip1() + ammoNeeded)
self:GetOwner():SetAmmo(self:Ammo1() - ammoNeeded, self:GetPrimaryAmmoType())
--self:AddFlag("Rechambered")
self:AddFlag("MagInserted")
end
if (CurTime() > self:GetNextReloadTime()) then
self:RemoveFlag("Reloading")
end
end
end
function SWEP:EndReload()
if (self:Clip1() <= 0) then --dont want to cancel reload if im out of ammo
return
end
if (self:GetAnimation("Reload_End") != nil) then
if (!self:HasFlag("Rechambered") && self:Clip1() > 0 && self:GetAnimation("Reload_End_Empty") != nil) then
self:PlayViewModelAnimation("Reload_End_Empty")
self:SetNextPrimaryFire(CurTime() + self:GetAnimLength("Reload_End_Empty"))
self:AddFlag("Rechambered")
else
self:PlayViewModelAnimation("Reload_End")
self:SetNextPrimaryFire(CurTime() + self:GetAnimLength("Reload_End"))
end
self:RemoveFlag("Reloading")
end
if (self:GetAnimation("Reload_Loop") == nil && GetConVar("mgbase_sv_shootreloads"):GetInt() > 0) then
self:RemoveFlag("Reloading")
end
end
function SWEP:CanPump()
return !self:HasFlag("Holstering")
&& !self:HasFlag("Drawing")
&& self:Clip1() > 0
&& !self:HasFlag("Reloading")
&& CurTime() > self:GetNextMeleeTime()
&& self:GetAnimation("Rechamber") != nil
&& (self:GetOwner():GetInfoNum("mgbase_manualrechamber", 0) <= 0 || self:GetOwner():KeyDown(IN_RELOAD))
end

View File

@@ -0,0 +1,25 @@
AddCSLuaFile()
function SWEP:CanChangeSafety()
return !self:HasFlag("Reloading")
&& !self:HasFlag("Drawing")
&& !self:HasFlag("Holstering")
&& !self:HasFlag("Sprinting") --to avoid having fucked anims
&& CurTime() > self:GetNextSprintTime()
&& CurTime() > self:GetNextPrimaryFire()
&& CurTime() > self:GetNextMeleeTime()
&& CurTime() > self:GetNextFiremodeTime()
&& !self:HasFlag("Customizing")
&& !self:HasFlag("Aiming")
end
function SWEP:ChangeSafety()
if (!self:CanChangeSafety()) then
return
end
self:ToggleFlag("Lowered")
self:SetNextInspectTime(0)
self:PlayViewModelAnimation(self:HasFlag("Lowered") && "Sprint_In" || "Sprint_Out")
self:EmitSound("ViewModel.Medium")
end

View File

@@ -0,0 +1,65 @@
AddCSLuaFile()
function SWEP:IsOwnerMoving()
return self:GetOwner():KeyDown(IN_FORWARD) || self:GetOwner():KeyDown(IN_BACK) || self:GetOwner():KeyDown(IN_MOVERIGHT) || self:GetOwner():KeyDown(IN_MOVELEFT)
end
function SWEP:CanSprint()
local sprintReloads = GetConVar("mgbase_sv_sprintreloads"):GetInt()
return !self:HasFlag("Drawing")
&& !self:HasFlag("Holstering")
&& CurTime() > self:GetNextPrimaryFire()
&& self:IsOwnerMoving() --checking velocity can sometimes cause desyncs (touching server entities while sprinting)
&& !self:GetOwner():Crouching()
&& CurTime() > self:GetNextFiremodeTime()
&& CurTime() > self:GetNextMeleeTime()
&& (sprintReloads <= 0 || (sprintReloads > 0 && !self:HasFlag("Reloading")))
end
function SWEP:CanPlaySprintOutAnim()
return !self:HasFlag("Drawing")
&& !self:HasFlag("Holstering")
&& CurTime() > self:GetNextPrimaryFire()
&& CurTime() > self:GetNextFiremodeTime()
&& !self:HasFlag("Customizing")
&& !self:HasFlag("Reloading")
&& !self:HasFlag("Lowered")
end
function SWEP:DoSprintIn()
self:StopCustomizing()
self:SetNextInspectTime(0)
if (!self:HasFlag("Sprinting") && !self:HasFlag("Lowered")) then
self:PlayViewModelAnimation("Sprint_In")
self:PlayerGesture(GESTURE_SLOT_ATTACK_AND_RELOAD, 0)
end
self:AddFlag("Sprinting")
self:RemoveFlag("Reloading")
end
function SWEP:DoSprintOut()
if (self:HasFlag("Sprinting")) then
self:SetNextSprintTime(CurTime() + self:GetAnimLength("Sprint_Out"))
if (self:CanPlaySprintOutAnim()) then
self:PlayViewModelAnimation("Sprint_Out")
end
end
self:RemoveFlag("Sprinting")
end
function SWEP:SprintLogic()
if (CLIENT && game.SinglePlayer()) then
return
end
if (self:GetOwner():KeyDown(IN_SPEED) && self:CanSprint()) then
self:DoSprintIn()
else
self:DoSprintOut()
end
end

View File

@@ -0,0 +1,250 @@
AddCSLuaFile()
SWEP.StatDefinitions = {
["SWEP.Primary.ClipSize"] = "ClipSize",
["SWEP.Primary.RPM"] = "RPM",
["SWEP.Animations.Ads_Out.Fps"] = "AimSpeed",
["SWEP.Animations.Ads_In.Fps"] = "AimSpeed",
["SWEP.Animations.Sprint_Out.Fps"] = "SprintSpeed",
["SWEP.Animations.Rechamber.Fps"] = "RechamberSpeed",
["SWEP.Cone.Ads"] = "Accuracy",
["SWEP.Cone.Hip"] = "Accuracy",
["SWEP.Cone.Increase"] = "ConeIncrease",
--["SWEP.Animations.Reload.Length"] = "ReloadLength",
-- ["SWEP.Animations.Reload_Empty.Length"] = "ReloadLength", --too confusing for people
["SWEP.Animations.Reload.Fps"] = "ReloadSpeed",
["SWEP.Animations.Reload_Empty.Fps"] = "ReloadSpeed",
["SWEP.Animations.Reload_Start.Fps"] = "ReloadSpeed",
["SWEP.Animations.Draw.Fps"] = "SwitchSpeed",
["SWEP.Animations.Holster.Fps"] = "SwitchSpeed",
["SWEP.Bullet.Damage.1"] = "DamageClose",
["SWEP.Bullet.Damage.2"] = "DamageRange",
["SWEP.Bullet.HeadshotMultiplier"] = "HeadshotMultiplier",
["SWEP.Bullet.EffectiveRange"] = "EffectiveRange",
["SWEP.Bullet.Penetration.Thickness"] = "PenetrationThickness",
["SWEP.Recoil.Vertical.1"] = "VerticalRecoil",
["SWEP.Recoil.AdsMultiplier"] = "Recoil",
["SWEP.Recoil.Vertical.2"] = "VerticalRecoil",
["SWEP.Recoil.Horizontal.1"] = "HorizontalRecoil",
["SWEP.Recoil.Horizontal.2"] = "HorizontalRecoil",
["SWEP.Recoil.Shake"] = "Shake",
["SWEP.Animations.Melee_Hit.Length"] = "MeleeSpeed",
["SWEP.Animations.Melee.Length"] = "MeleeSpeed",
["SWEP.Animations.Melee_Hit.Damage"] = "MeleeDamage",
["SWEP.Projectile.Speed"] = "ProjectileSpeed",
["SWEP.Projectile.Gravity"] = "ProjectileGravity",
["SWEP.Projectile.Stability"] = "ProjectileStability",
["SWEP.Projectile.Fuel"] = "ProjectileFuel",
["SWEP.Projectile.TrackingFraction"] = "TrackingSpeed",
["SWEP.Bullet.NumBullets"] = "Bullets",
["SWEP.Zoom.BreathingMultiplier"] = "AimSway",
["SWEP.Zoom.MovementMultiplier"] = "MovementMultiplier",
["SWEP.Recoil.DecreaseEveryShot"] = "RecoilStability",
["SWEP.Trigger.Time"] = "TriggerTime",
["SWEP.Explosive.BlastRadius"] = "BlastRadius",
["SWEP.Explosive.ImpactBlastRatio"] = "ImpactDamage",
["SWEP.TrackingInfo.PingTime"] = "PingSpeed",
}
SWEP.StatInfo = {
["PingSpeed"] = {
Name = "Tracking Speed",
ProIfMore = false,
ShowPercentage = true
},
["ImpactDamage"] = {
Name = "Impact Damage",
ProIfMore = false,
ShowPercentage = true
},
["BlastRadius"] = {
Name = "Blast Radius",
ProIfMore = true,
ShowPercentage = true
},
["TriggerTime"] = {
Name = "Trigger Weight",
ProIfMore = false,
ShowPercentage = true
},
["RecoilStability"] = {
Name = "Recoil Stability",
ProIfMore = true,
ShowPercentage = true
},
["Shake"] = {
Name = "Aim Stability",
ProIfMore = false,
ShowPercentage = true
},
["AimSway"] = {
Name = "Scope Aim Sway",
ProIfMore = false,
ShowPercentage = true
},
["MovementMultiplier"] = {
Name = "Weapon Moving Steadiness",
ProIfMore = false,
ShowPercentage = true
},
["HeadshotMultiplier"] = {
Name = "Headshot Damage",
ProIfMore = true,
ShowPercentage = true
},
["ProjectileSpeed"] = {
Name = "Projectile Velocity",
ProIfMore = true,
ShowPercentage = true
},
["ProjectileGravity"] = {
Name = "Projectile Drop",
ProIfMore = false,
ShowPercentage = true
},
["ProjectileStability"] = {
Name = "Projectile Stability",
ProIfMore = true,
ShowPercentage = true
},
["TrackingSpeed"] = {
Name = "Tracking Agression",
ProIfMore = true,
ShowPercentage = true
},
["ProjectileFuel"] = {
Name = "Projectile Fuel",
ProIfMore = true,
ShowPercentage = true
},
["ClipSize"] = {
Name = "Magazine Size",
ProIfMore = true,
ShowPercentage = false
},
["RPM"] = {
Name = "Rounds Per Minute",
ProIfMore = true,
ShowPercentage = false
},
["AimSpeed"] = {
Name = "ADS Speed",
ProIfMore = true,
ShowPercentage = true
},
["SprintSpeed"] = {
Name = "Sprint-to-Fire Speed",
ProIfMore = true,
ShowPercentage = true
},
["AimLength"] = {
Name = "ADS Time",
ProIfMore = false,
ShowPercentage = true
},
["RechamberSpeed"] = {
Name = "Rechamber Speed",
ProIfMore = true,
ShowPercentage = true
},
["AimAccuracy"] = {
Name = "ADS Spread",
ProIfMore = false,
ShowPercentage = true
},
["ConeIncrease"] = {
Name = "Firing Inaccuracy",
ProIfMore = false,
ShowPercentage = true
},
["Accuracy"] = {
Name = "Spread",
ProIfMore = false,
ShowPercentage = true
},
["ReloadSpeed"] = {
Name = "Reload Speed",
ProIfMore = true,
ShowPercentage = true
},
["SwitchSpeed"] = {
Name = "Handling Speed",
ProIfMore = true,
ShowPercentage = true
},
["DrawLength"] = {
Name = "Draw Time",
ProIfMore = false,
ShowPercentage = true
},
["HolsterLength"] = {
Name = "Holster Time",
ProIfMore = false,
ShowPercentage = true
},
["ReloadLength"] = {
Name = "Reload Time",
ProIfMore = false,
ShowPercentage = false
},
["DamageClose"] = {
Name = "Damage Close",
ProIfMore = true,
ShowPercentage = true
},
["DamageRange"] = {
Name = "Damage Range",
ProIfMore = true,
ShowPercentage = true
},
["EffectiveRange"] = {
Name = "Effective Range",
ProIfMore = true,
ShowPercentage = true
},
["MaxRange"] = {
Name = "Max Range",
ProIfMore = true,
ShowPercentage = true
},
["PenetrationThickness"] = {
Name = "Penetration Power",
ProIfMore = true,
ShowPercentage = true
},
["HorizontalRecoil"] = {
Name = "Recoil Horizontal",
ProIfMore = false,
ShowPercentage = true
},
["Recoil"] = {
Name = "Recoil Kick",
ProIfMore = false,
ShowPercentage = true
},
["VerticalRecoil"] = {
Name = "Recoil Vertical",
ProIfMore = false,
ShowPercentage = true
},
["MeleeSpeed"] = {
Name = "Melee Recovery",
ProIfMore = false,
ShowPercentage = true
},
["MeleeDamage"] = {
Name = "Damage Melee",
ProIfMore = true,
ShowPercentage = true
},
["Bullets"] = {
Name = "Number Of Pellets",
ProIfMore = true,
ShowPercentage = false
},
["SprintLength"] = {
Name = "Sprint-to-Fire Time",
ProIfMore = false,
ShowPercentage = false
},
}

View File

@@ -0,0 +1,89 @@
AddCSLuaFile()
function SWEP:Think()
self:LoadSpawnPreset()
--fallback initialize
if (!self.m_bInitialized && IsFirstTimePredicted()) then
self:Initialize()
end
--holster
if (self:HasFlag("Holstering") && CurTime() >= self:GetNextHolsterTime() && IsValid(self:GetNextWeapon()) && self:GetNextWeapon() != self && self:GetNextWeapon() != self:GetOwner()) then
if (CLIENT && (IsFirstTimePredicted() || game.SinglePlayer())) then
input.SelectWeapon(self:GetNextWeapon())
end
return
end
--equip
if (self:HasFlag("Drawing") && CurTime() >= self:GetNextActionTime()) then
self:RemoveFlag("Drawing")
self:RemoveFlag("PlayFirstDraw")
end
--spray
if (CurTime() > self:GetNextPrimaryFire() + 0.15) then
self:SetSprayRounds(0)
end
--cone
self:SetCone(math.Approach(self:GetCone(), self:GetConeMin(), 4 * FrameTime()))
if (CurTime() <= self:GetNextMeleeTime()) then
self:SetCone(self:GetConeMax())
end
--burst logic
if (!game.SinglePlayer() || SERVER) then
if (self.Primary.BurstRounds > 1 && self:GetBurstRounds() < self.Primary.BurstRounds && self:GetBurstRounds() > 0) then
self:PrimaryAttack()
end
end
--auto reload
if (self:GetOwner():GetInfoNum("mgbase_autoreload", 1)) >= 1 then
if (self:Clip1() <= 0 && self:GetOwner():GetAmmoCount(self:GetPrimaryAmmoType()) > 0) then
self:Reload()
end
end
self:TriggerLogic()
--pumping, it has to go under trigger logic
if (CurTime() >= self:GetNextPrimaryFire() && self:CanPump()) then
if (!self:HasFlag("Rechambered")) then
self:PlayViewModelAnimation("Rechamber")
self:SetNextPrimaryFire(CurTime() + self:GetAnimLength("Rechamber"))
self:AddFlag("Rechambered")
end
end
self:ReloadLogic()
self:AimLogic()
self:SprintLogic()
self:BipodLogic()
self:InspectLogic()
--ladder
if (self:GetOwner():GetMoveType() == MOVETYPE_LADDER || self:GetOwner():WaterLevel() == 3) then
self:Holster(self:GetOwner())
else
if (self:HasFlag("Holstering") && self:GetNextWeapon() == self:GetOwner()) then
self:Deploy()
end
end
--holdtypes
--new meme marine way
self:SetShouldHoldType()
if (CLIENT && game.SinglePlayer()) then
return
end
if (self:Clip1() > 0 && !self:HasFlag("Reloading") && !self:HasFlag("Sprinting")) then
self:CreateAndResumeReverbJob()
end
end

View File

@@ -0,0 +1,176 @@
local INVALID_TRIGGER_VALUE = -1 --this is used for semis: if its at this value theyt wont fire (otherwise they would go full auto)
AddCSLuaFile()
function SWEP:CanPressTrigger()
if (self:HasFlag("Customizing")) then
return false
end
if (CurTime() < self:GetNextFiremodeTime()) then
return false
end
if ((self:HasFlag("Reloading") && !self:CanAttackInterruptReload()) || self:HasFlag("Holstering") || self:HasFlag("Drawing") || self:HasFlag("Sprinting")) then
return false
end
if (CurTime() < self:GetNextMeleeTime()) then
return false
end
if (CurTime() < self:GetNextSprintTime()) then
return false
end
if (CurTime() < self:GetNextInspectTime()) then
return false
end
return true
end
function SWEP:CanReleaseTrigger()
return (self:GetTriggerDelta() >= 1 || self:GetTriggerDelta() == INVALID_TRIGGER_VALUE)
&& (self:GetBurstRounds() >= self.Primary.BurstRounds || self:Clip1() <= 0)
end
function SWEP:TriggerLogic()
if (CLIENT && game.SinglePlayer()) then
return
end
if (self.Trigger == nil || !self:CanPressTrigger()) then
if (self:HasFlag("HoldingTrigger")) then
if (self.Trigger.ReleasedSound != nil) then
self:EmitSound(self.Trigger.ReleasedSound)
end
end
self:RemoveFlag("HoldingTrigger")
if (CurTime() > self:GetNextPrimaryFire() && self:HasFlag("Rechambered")) then
self:SetTriggerDelta(0)
end
return
end
local bDown = self:GetOwner():KeyDown(IN_ATTACK)
if (bDown && CurTime() >= self:GetNextPrimaryFire()) then
if (!self:HasFlag("HoldingTrigger")) then
if (self.Trigger.PressedSound != nil) then
self:EmitSound(self.Trigger.PressedSound)
end
if (self.Trigger.PressedAnimation) then
self:PlayViewModelAnimation(self.Trigger.PressedAnimation)
elseif (self:Clip1() <= 0) then
self:PlayViewModelAnimation("Land")
end
end
self:AddFlag("HoldingTrigger")
self:RemoveFlag("Lowered")
elseif (!bDown && self:CanReleaseTrigger()) then
if (self:HasFlag("HoldingTrigger")) then
if (self.Trigger.ReleasedSound != nil) then
self:EmitSound(self.Trigger.ReleasedSound)
end
if (self.Trigger.ReleasedAnimation != nil && self:CanPlayTriggerOut()) then
self:PlayViewModelAnimation(self.Trigger.ReleasedAnimation)
end
end
self:RemoveFlag("HoldingTrigger")
end
if (self:HasFlag("HoldingTrigger")) then
if (self:GetTriggerDelta() == INVALID_TRIGGER_VALUE) then
return
end
self:SetTriggerDelta(math.min(self:GetTriggerDelta() + (FrameTime() / self.Trigger.Time), 1))
if (self:GetTriggerDelta() >= 1) then
self:PrimaryAttack()
if (!self.Primary.Automatic && (self:GetBurstRounds() >= self.Primary.BurstRounds || self:Clip1() <= 0)) then
self:SetTriggerDelta(INVALID_TRIGGER_VALUE)
end
end
else
self:SetTriggerDelta(0)
self:SetBurstRounds(0)
end
end
function SWEP:LauncherTriggerLogic()
if (CLIENT && game.SinglePlayer()) then
return
end
if (self.Trigger == nil || !self:CanPressTrigger()) then
if (self:HasFlag("HoldingTrigger")) then
if (self.Trigger.ReleasedSound != nil) then
self:EmitSound(self.Trigger.ReleasedSound)
end
end
self:RemoveFlag("HoldingTrigger")
if (CurTime() > self:GetNextPrimaryFire() && self:HasFlag("Rechambered")) then
self:SetTriggerDelta(0)
end
return
end
local bDown = self:GetOwner():KeyDown(IN_ATTACK)
if (bDown && CurTime() >= self:GetNextPrimaryFire()) then
if (!self:HasFlag("HoldingTrigger")) then
if (self.Trigger.PressedSound != nil) then
self:EmitSound(self.Trigger.PressedSound)
end
--self:PlayViewModelAnimation(self.Trigger.PressedAnimation || "Land")
end
self:AddFlag("HoldingTrigger")
self:RemoveFlag("Lowered")
elseif (!bDown && self:CanReleaseTrigger()) then
if (self:HasFlag("HoldingTrigger")) then
if (self.Trigger.ReleasedSound != nil) then
self:EmitSound(self.Trigger.ReleasedSound)
end
if (self.Trigger.ReleasedAnimation != nil && self:CanPlayTriggerOut()) then
self:PlayViewModelAnimation(self.Trigger.ReleasedAnimation)
end
end
self:RemoveFlag("HoldingTrigger")
end
if (self:HasFlag("HoldingTrigger")) then
if (self:GetTriggerDelta() == INVALID_TRIGGER_VALUE) then
return
end
self:SetTriggerDelta(math.min(self:GetTriggerDelta() + (FrameTime() / self.Trigger.Time), 1))
if (self:GetTriggerDelta() >= 1) then
self:PrimaryAttack()
--if (!self.Primary.Automatic && (self:GetBurstRounds() >= self.Primary.BurstRounds || self:Clip1() <= 0)) then
--self:SetTriggerDelta(INVALID_TRIGGER_VALUE)
--end
end
else
self:SetTriggerDelta(0)
self:SetBurstRounds(0)
end
end