Залив
This commit is contained in:
329
lua/weapons/mg_base/modules/shared/sh_aim_behaviour.lua
Normal file
329
lua/weapons/mg_base/modules/shared/sh_aim_behaviour.lua
Normal 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
|
||||
40
lua/weapons/mg_base/modules/shared/sh_aim_mode_behavior.lua
Normal file
40
lua/weapons/mg_base/modules/shared/sh_aim_mode_behavior.lua
Normal 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
|
||||
69
lua/weapons/mg_base/modules/shared/sh_bipod_behavior.lua
Normal file
69
lua/weapons/mg_base/modules/shared/sh_bipod_behavior.lua
Normal 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
|
||||
23
lua/weapons/mg_base/modules/shared/sh_button_dispatcher.lua
Normal file
23
lua/weapons/mg_base/modules/shared/sh_button_dispatcher.lua
Normal 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
|
||||
897
lua/weapons/mg_base/modules/shared/sh_customization.lua
Normal file
897
lua/weapons/mg_base/modules/shared/sh_customization.lua
Normal 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
|
||||
130
lua/weapons/mg_base/modules/shared/sh_datatables.lua
Normal file
130
lua/weapons/mg_base/modules/shared/sh_datatables.lua
Normal 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
|
||||
64
lua/weapons/mg_base/modules/shared/sh_firemode_behaviour.lua
Normal file
64
lua/weapons/mg_base/modules/shared/sh_firemode_behaviour.lua
Normal 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
|
||||
135
lua/weapons/mg_base/modules/shared/sh_holdtypes.lua
Normal file
135
lua/weapons/mg_base/modules/shared/sh_holdtypes.lua
Normal 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_*)
|
||||
70
lua/weapons/mg_base/modules/shared/sh_inspect_behavior.lua
Normal file
70
lua/weapons/mg_base/modules/shared/sh_inspect_behavior.lua
Normal 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
|
||||
54
lua/weapons/mg_base/modules/shared/sh_melee_behaviour.lua
Normal file
54
lua/weapons/mg_base/modules/shared/sh_melee_behaviour.lua
Normal 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
|
||||
@@ -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)
|
||||
202
lua/weapons/mg_base/modules/shared/sh_reload_behaviour.lua
Normal file
202
lua/weapons/mg_base/modules/shared/sh_reload_behaviour.lua
Normal 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
|
||||
25
lua/weapons/mg_base/modules/shared/sh_safety_behavior.lua
Normal file
25
lua/weapons/mg_base/modules/shared/sh_safety_behavior.lua
Normal 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
|
||||
65
lua/weapons/mg_base/modules/shared/sh_sprint_behaviour.lua
Normal file
65
lua/weapons/mg_base/modules/shared/sh_sprint_behaviour.lua
Normal 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
|
||||
250
lua/weapons/mg_base/modules/shared/sh_stats.lua
Normal file
250
lua/weapons/mg_base/modules/shared/sh_stats.lua
Normal 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
|
||||
},
|
||||
}
|
||||
89
lua/weapons/mg_base/modules/shared/sh_think.lua
Normal file
89
lua/weapons/mg_base/modules/shared/sh_think.lua
Normal 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
|
||||
176
lua/weapons/mg_base/modules/shared/sh_trigger_behavior.lua
Normal file
176
lua/weapons/mg_base/modules/shared/sh_trigger_behavior.lua
Normal 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
|
||||
Reference in New Issue
Block a user