--[[ | This file was obtained through the combined efforts | of Madbluntz & Plymouth Antiquarian Society. | | Credits: lifestorm, Gregory Wayne Rossel JR., | Maloy, DrPepper10 @ RIP, Atle! | | Visit for more: https://plymouth.thetwilightzone.ru/ --]] --[[ Please, for the love of god, don't create objects in functions that are called multiple times per frame. The garbage collector will explode and so will players' comptuters. That means minimize usage of things that generate new objects, including: calls to Vector() or Angle(); use vector_origin and angle_zero if the value isn't modified arithmetic using +, -, * and / on Vectors and Angles; modifying individual parameters is fine functions like Angle:Right() and Vector:Angle(); however functions like Vector:Add() and Angle:Add() are fine Cache them if you use them more than one time! ]] local mth = math local m_appor = mth.Approach local m_clamp = mth.Clamp local f_lerp = Lerp local srf = surface SWEP.ActualVMData = false local swayxmult, swayymult, swayzmult, swayspeed = 1, 1, 1, 1 local lookxmult, lookymult = 1, 1 SWEP.VMPos = Vector() SWEP.VMAng = Angle() SWEP.VMPosOffset = Vector() SWEP.VMAngOffset = Angle() SWEP.VMPosOffset_Lerp = Vector() SWEP.VMAngOffset_Lerp = Angle() SWEP.VMLookLerp = Angle() SWEP.StepBob = 0 SWEP.StepBobLerp = 0 SWEP.StepRandomX = 1 SWEP.StepRandomY = 1 SWEP.LastEyeAng = Angle() SWEP.SmoothEyeAng = Angle() SWEP.LastVelocity = Vector() SWEP.Velocity_Lerp = Vector() SWEP.VelocityLastDiff = 0 SWEP.Breath_Intensity = 1 SWEP.Breath_Rate = 1 -- magic variables local sprint_vec1 = Vector(-2, 5, 2) local sprint_vec2 = Vector(0, 7, 3) local sprint_ang1 = Angle(-15, -15, 0) local spring_ang2 = Angle(-15, 15, -22) local sight_vec1 = Vector(0, 15, -4) local sight_vec2 = Vector(1, 5, -1) local sight_ang1 = Angle(0, 0, -45) local sight_ang2 = Angle(-5, 0, -10) local sextra_vec = Vector(0.0002, 0.001, 0.005) local procdraw_vec = Vector(0, 0, -5) local procdraw_ang = Angle(-70, 30, 0) local prochol_ang = Angle(-70, 30, 10) local lst = SysTime() local function scrunkly() local ret = (SysTime() - (lst or SysTime())) * GetConVar("host_timescale"):GetFloat() return ret end local function LerpC(t, a, b, powa) return a + (b - a) * math.pow(t, powa) end local function ApproachMod(usrobj, to, dlt) usrobj[1] = m_appor(usrobj[1], to[1], dlt) usrobj[2] = m_appor(usrobj[2], to[2], dlt) usrobj[3] = m_appor(usrobj[3], to[3], dlt) end local function LerpMod(usrobj, to, dlt, clamp_ang) usrobj[1] = f_lerp(dlt, usrobj[1], to[1]) usrobj[2] = f_lerp(dlt, usrobj[2], to[2]) usrobj[3] = f_lerp(dlt, usrobj[3], to[3]) if clamp_ang then for i = 1, 3 do usrobj[i] = math.NormalizeAngle(usrobj[i]) end end end local function LerpMod2(from, usrobj, dlt, clamp_ang) usrobj[1] = f_lerp(dlt, from[1], usrobj[1]) usrobj[2] = f_lerp(dlt, from[2], usrobj[2]) usrobj[3] = f_lerp(dlt, from[3], usrobj[3]) if clamp_ang then for i = 1, 3 do usrobj[i] = math.NormalizeAngle(usrobj[i]) end end end -- debug for testing garbage count -- TODO: comment this out or something before actually going into main branch local sw = false local tries = {} local totaltries = 1000 local sw_start = 0 local sw_orig = 0 concommand.Add("arccw_dev_stopwatch", function() tries = {} sw = true end) local function stopwatch(name) if !sw then return end if name == true then local d = (collectgarbage("count") - sw_orig) if #tries == 0 then print(" total garbage: " .. d) end table.insert(tries, d) if #tries == totaltries then sw = false local average = 0 for _, v in ipairs(tries) do average = average + v end average = average / totaltries print("----------------------------------") print("average over " .. totaltries .. " tries: " .. average) end return end local gb = collectgarbage("count") if name then if #tries == 0 then print(name .. ": " .. (gb - sw_start)) end else if #tries == 0 then print("----------------------------------") end sw_orig = gb end sw_start = gb end function SWEP:Move_Process(EyePos, EyeAng, velocity) local VMPos, VMAng = self.VMPos, self.VMAng local VMPosOffset, VMAngOffset = self.VMPosOffset, self.VMAngOffset local VMPosOffset_Lerp, VMAngOffset_Lerp = self.VMPosOffset_Lerp, self.VMAngOffset_Lerp local FT = scrunkly() local sightedmult = (self:GetState() == ArcCW.STATE_SIGHTS and 0.05) or 1 local sg = self:GetSightDelta() VMPos:Set(EyePos) VMAng:Set(EyeAng) VMPosOffset.x = math.Clamp(velocity.z * 0.0025, -1, 1) * sightedmult VMPosOffset.x = VMPosOffset.x + (velocity.x * 0.001 * sg) VMPosOffset.y = math.Clamp(velocity.y * -0.002, -1, 1) * sightedmult VMPosOffset.z = math.Clamp(VMPosOffset.x * -2, -4, 4) VMPosOffset_Lerp.x = Lerp(8 * FT, VMPosOffset_Lerp.x, VMPosOffset.x) VMPosOffset_Lerp.y = Lerp(8 * FT, VMPosOffset_Lerp.y, VMPosOffset.y) VMPosOffset_Lerp.z = Lerp(8 * FT, VMPosOffset_Lerp.z, VMPosOffset.z) --VMAngOffset.x = math.Clamp(VMPosOffset.x * 8, -4, 4) VMAngOffset.y = VMPosOffset.y VMAngOffset.z = VMPosOffset.y * 0.5 + (VMPosOffset.x * -5) + (velocity.x * -0.005 * sg) VMAngOffset_Lerp.x = LerpC(10 * FT, VMAngOffset_Lerp.x, VMAngOffset.x, 0.75) VMAngOffset_Lerp.y = LerpC(5 * FT, VMAngOffset_Lerp.y, VMAngOffset.y, 0.6) VMAngOffset_Lerp.z = Lerp(25 * FT, VMAngOffset_Lerp.z, VMAngOffset.z) VMPos:Add(VMAng:Up() * VMPosOffset_Lerp.x) VMPos:Add(VMAng:Right() * VMPosOffset_Lerp.y) VMPos:Add(VMAng:Forward() * VMPosOffset_Lerp.z) VMAngOffset_Lerp:Normalize() VMAng:Add(VMAngOffset_Lerp) end local stepend = math.pi * 4 function SWEP:Step_Process(EyePos, EyeAng, velocity) local VMPos, VMAng = self.VMPos, self.VMAng local VMPosOffset, VMAngOffset = self.VMPosOffset, self.VMAngOffset local VMPosOffset_Lerp = self.VMPosOffset_Lerp local state = self:GetState() local sprd = self:GetSprintDelta() if state == ArcCW.STATE_SPRINT and self:SelectAnimation("idle_sprint") and !self:GetReloading() and !self:CanShootWhileSprint() then velocity = 0 else velocity = math.min(velocity:Length(), 400) * Lerp(sprd, 1, 1.25) end local delta = math.abs(self.StepBob * 2 / stepend - 1) local FT = scrunkly() --FrameTime() local sightedmult = (state == ArcCW.STATE_SIGHTS and 0.25) or 1 local sprintmult = (state == ArcCW.STATE_SPRINT and !self:CanShootWhileSprint() and 2) or 1 local pronemult = (self:IsProne() and 10) or 1 local onground = self:GetOwner():OnGround() self.StepBob = self.StepBob + (velocity * 0.00015 + (math.pow(delta, 0.01) * 0.03)) * swayspeed * FT * 300 if self.StepBob >= stepend then self.StepBob = 0 self.StepRandomX = math.Rand(1, 1.5) self.StepRandomY = math.Rand(1, 1.5) end if velocity == 0 then self.StepBob = 0 end if onground then -- oh no it says sex tra local sextra = vector_origin if (state == ArcCW.STATE_SPRINT and !self:CanShootWhileSprint() and !self:SelectAnimation("idle_sprint")) or true then sextra = LerpVector(sprd, vector_origin, sextra_vec) end VMPosOffset.x = (math.sin(self.StepBob) * velocity * (0.000375 + sextra.x) * sightedmult * swayxmult) * self.StepRandomX VMPosOffset.y = (math.sin(self.StepBob * 0.5) * velocity * (0.0005 + sextra.y) * sightedmult * sprintmult * pronemult * swayymult) * self.StepRandomY VMPosOffset.z = math.sin(self.StepBob * 0.75) * velocity * (0.002 + sextra.z) * sightedmult * pronemult * swayzmult end VMPosOffset_Lerp.x = Lerp(32 * FT, VMPosOffset_Lerp.x, VMPosOffset.x) VMPosOffset_Lerp.y = Lerp(4 * FT, VMPosOffset_Lerp.y, VMPosOffset.y) VMPosOffset_Lerp.z = Lerp(2 * FT, VMPosOffset_Lerp.z, VMPosOffset.z) VMAngOffset.x = VMPosOffset_Lerp.x * 2 VMAngOffset.y = VMPosOffset_Lerp.y * -7.5 VMAngOffset.z = VMPosOffset_Lerp.y * 10 VMPos:Add(VMAng:Up() * VMPosOffset_Lerp.x) VMPos:Add(VMAng:Right() * VMPosOffset_Lerp.y) VMPos:Add(VMAng:Forward() * VMPosOffset_Lerp.z) VMAng:Add(VMAngOffset) end function SWEP:Breath_Health() local owner = self:GetOwner() if !IsValid(owner) then return end local health = owner:Health() local maxhealth = owner:GetMaxHealth() self.Breath_Intensity = math.Clamp(maxhealth / health, 0, 2) self.Breath_Rate = math.Clamp((maxhealth * 0.5) / health, 1, 1.5) end function SWEP:Breath_StateMult() local owner = self:GetOwner() if !IsValid(owner) then return end local sightedmult = (self:GetState() == ArcCW.STATE_SIGHTS and 0.05) or 1 self.Breath_Intensity = self.Breath_Intensity * sightedmult end function SWEP:Breath_Process(EyePos, EyeAng) local VMPos, VMAng = self.VMPos, self.VMAng local VMPosOffset, VMAngOffset = self.VMPosOffset, self.VMAngOffset -- self:Breath_Health() Snaps around when regenerating self:Breath_StateMult() VMPosOffset.x = (math.sin(CurTime() * 2 * self.Breath_Rate) * 0.1) * self.Breath_Intensity VMPosOffset.y = (math.sin(CurTime() * 2.5 * self.Breath_Rate) * 0.025) * self.Breath_Intensity VMAngOffset.x = VMPosOffset.x * 1.5 VMAngOffset.y = VMPosOffset.y * 2 VMAngOffset.z = VMPosOffset.y * VMPosOffset.x * -40 VMPos:Add(VMAng:Up() * VMPosOffset.x) VMPos:Add(VMAng:Right() * VMPosOffset.y) VMAng:Add(VMAngOffset) end function SWEP:Look_Process(EyePos, EyeAng, velocity) local VMPos, VMAng = self.VMPos, self.VMAng local VMPosOffset, VMAngOffset = self.VMPosOffset, self.VMAngOffset local FT = scrunkly() local sightedmult = (self:GetState() == ArcCW.STATE_SIGHTS and 0.25) or 1 self.SmoothEyeAng = LerpAngle(0.05, self.SmoothEyeAng, EyeAng - self.LastEyeAng) -- local xd, yd = (velocity.z / 10), (velocity.y / 200) VMPosOffset.x = -self.SmoothEyeAng.x * -0.5 * sightedmult * lookxmult VMPosOffset.y = self.SmoothEyeAng.y * 0.5 * sightedmult * lookymult VMAngOffset.x = VMPosOffset.x * 0.75 VMAngOffset.y = VMPosOffset.y * 2.5 VMAngOffset.z = VMPosOffset.x * 2 + VMPosOffset.y * -2 self.VMLookLerp.y = Lerp(FT * 10, self.VMLookLerp.y, VMAngOffset.y * -1.5 + self.SmoothEyeAng.y) VMAng.y = VMAng.y - self.VMLookLerp.y VMPos:Add(VMAng:Up() * VMPosOffset.x) VMPos:Add(VMAng:Right() * VMPosOffset.y) VMAng:Add(VMAngOffset) end function SWEP:GetVMPosition(EyePos, EyeAng) local velocity = self:GetOwner():GetVelocity() velocity = WorldToLocal(velocity, angle_zero, vector_origin, EyeAng) self:Move_Process(EyePos, EyeAng, velocity) stopwatch("Move_Process") self:Step_Process(EyePos, EyeAng, velocity) stopwatch("Step_Process") self:Breath_Process(EyePos, EyeAng) stopwatch("Breath_Process") self:Look_Process(EyePos, EyeAng, velocity) stopwatch("Look_Process") self.LastEyeAng = EyeAng self.LastEyePos = EyePos self.LastVelocity = velocity return self.VMPos, self.VMAng end SWEP.TheJ = {posa = Vector(), anga = Angle()} local rap_pos = Vector() local rap_ang = Angle() local actual local target = {pos = Vector(), ang = Angle()} local GunDriverFix = Angle( 0, 90, 90 ) function SWEP:GetViewModelPosition(pos, ang) if ArcCW.ConVars["dev_benchgun"]:GetBool() then if ArcCW.ConVars["dev_benchgun_custom"]:GetString() then local bgc = ArcCW.ConVars["dev_benchgun_custom"]:GetString() if string.Left(bgc, 6) != "setpos" then return vector_origin, angle_zero end bgc = string.TrimLeft(bgc, "setpos ") bgc = string.Replace(bgc, ";setang", "") bgc = string.Explode(" ", bgc) return Vector(bgc[1], bgc[2], bgc[3]), Angle(bgc[4], bgc[5], bgc[6]) else return vector_origin, angle_zero end end stopwatch() local owner = self:GetOwner() if !IsValid(owner) or !owner:Alive() then return end local FT = scrunkly() local CT = CurTime() local TargetTick = (1 / FT) / 66.66 local cdelta = math.Clamp(math.ease.InOutSine((owner:GetViewOffset().z - owner:GetCurrentViewOffset().z) / (owner:GetViewOffset().z - owner:GetViewOffsetDucked().z)),0,1) if TargetTick < 1 then FT = FT * TargetTick end local vm = LocalPlayer():GetViewModel() local asight = self:GetActiveSights() local state = self:GetState() local sgtd = self:GetSightDelta() local sprd = self:GetSprintDelta() local sprinted = self.Sprinted or state == ArcCW.STATE_SPRINT and !self:CanShootWhileSprint() local sighted = self.Sighted or state == ArcCW.STATE_SIGHTS local holstered = self:GetCurrentFiremode().Mode == 0 if game.SinglePlayer() then sprinted = state == ArcCW.STATE_SPRINT and !self:CanShootWhileSprint() sighted = state == ArcCW.STATE_SIGHTS end local oldpos, oldang = Vector(), Angle() oldpos:Set(pos) oldang:Set(ang) ang:Sub(self:GetOurViewPunchAngles()) actual = self.ActualVMData or { pos = Vector(), ang = Angle(), down = 1, sway = 1, bob = 1, evpos = Vector(), evang = Angle(), } local apos, aang = self:GetBuff_Override("Override_ActivePos", self.ActivePos), self:GetBuff_Override("Override_ActiveAng", self.ActiveAng) local cpos, cang = self:GetBuff("CrouchPos", true) or apos, self:GetBuff("CrouchAng", true) or aang target.down = 1 target.sway = 2 target.bob = 2 stopwatch("set") if self:InBipod() and self:GetBipodAngle() then local bpos = self:GetBuff_Override("Override_InBipodPos", self.InBipodPos) target.pos:Set(asight and asight.Pos or apos) target.ang:Set(asight and asight.Ang or aang) local BEA = (self.BipodStartAngle or self:GetBipodAngle()) - owner:EyeAngles() target.pos:Add(BEA:Right() * bpos.x * self.InBipodMult.x) target.pos:Add(BEA:Forward() * bpos.y * self.InBipodMult.y) target.pos:Add(BEA:Up() * bpos.z * self.InBipodMult.z) target.sway = 0.2 -- elseif (owner:Crouching() or owner:KeyDown(IN_DUCK)) and !self:GetReloading() then -- target.pos:Set(self:GetBuff("CrouchPos", true) or apos) -- target.ang:Set(self:GetBuff("CrouchAng", true) or aang) elseif self:GetReloading() then target.pos:Set(self:GetBuff("ReloadPos", true) or apos) target.ang:Set(self:GetBuff("ReloadAng", true) or aang) else target.pos:Set(apos) target.ang:Set(aang) LerpMod(target.pos, cpos, cdelta) LerpMod(target.ang, cang, cdelta, true) end if (owner:Crouching() or owner:KeyDown(IN_DUCK)) then target.down = 0 end stopwatch("reload, crouch, bipod") target.pos.x = target.pos.x + ArcCW.ConVars["vm_right"]:GetFloat() target.pos.y = target.pos.y + ArcCW.ConVars["vm_forward"]:GetFloat() target.pos.z = target.pos.z + ArcCW.ConVars["vm_up"]:GetFloat() target.ang.p = target.ang.p + ArcCW.ConVars["vm_pitch"]:GetFloat() target.ang.y = target.ang.y + ArcCW.ConVars["vm_yaw"]:GetFloat() target.ang.r = target.ang.r + ArcCW.ConVars["vm_roll"]:GetFloat() if state == ArcCW.STATE_CUSTOMIZE then target.down = 1 target.sway = 3 target.bob = 1 local mx, my = input.GetCursorPos() mx = 2 * mx / ScrW() my = 2 * my / ScrH() target.pos:Set(self:GetBuff_Override("Override_CustomizePos", self.CustomizePos)) target.ang:Set(self:GetBuff_Override("Override_CustomizeAng", self.CustomizeAng)) target.pos.x = target.pos.x + mx target.pos.z = target.pos.z + my target.ang.y = target.ang.y + my * 2 target.ang.r = target.ang.r + mx * 2 if self.InAttMenu then target.ang.y = target.ang.y - 5 end end stopwatch("cust") -- Sprinting local hpos, spos = self:GetBuff("HolsterPos", true), self:GetBuff("SprintPos", true) local hang, sang = self:GetBuff("HolsterAng", true), self:GetBuff("SprintAng", true) do local aaaapos = holstered and (hpos or spos) or (spos or hpos) local aaaaang = holstered and (hang or sang) or (sang or hang) local sd = (self:GetReloading() and 0) or (self:IsProne() and math.Clamp(owner:GetVelocity():Length() / prone.Config.MoveSpeed, 0, 1)) or (holstered and 1) or (!self:CanShootWhileSprint() and sprd) or 0 sd = math.pow(math.sin(sd * math.pi * 0.5), 2) local d = math.pow(math.sin(sd * math.pi * 0.5), math.pi) local coolilove = d * math.cos(d * math.pi * 0.5) local joffset, jaffset if !sprinted then joffset = sprint_vec2 jaffset = spring_ang2 else joffset = sprint_vec1 jaffset = sprint_ang1 end LerpMod(target.pos, aaaapos, sd) LerpMod(target.ang, aaaaang, sd, true) for i = 1, 3 do target.pos[i] = target.pos[i] + joffset[i] * coolilove target.ang[i] = target.ang[i] + jaffset[i] * coolilove end local fu_sprint = (sprinted and self:SelectAnimation("idle_sprint")) target.sway = target.sway * f_lerp(sd, 1, fu_sprint and 0 or 2) target.bob = target.bob * f_lerp(sd, 1, fu_sprint and 0 or 2) end stopwatch("sprint") -- Sighting if asight then local delta = sgtd delta = math.pow(math.sin(delta * math.pi * 0.5), math.pi) local im = asight.Midpoint local coolilove = delta * math.cos(delta * math.pi * 0.5) local joffset, jaffset if !sighted then joffset = sight_vec2 jaffset = sight_ang2 else joffset = (im and im.Pos or sight_vec1) jaffset = (im and im.Ang or sight_ang1) end target.pos.z = target.pos.z - 1 LerpMod2(asight.Pos, target.pos, delta) LerpMod2(asight.Ang, target.ang, delta) for i = 1, 3 do target.pos[i] = target.pos[i] + joffset[i] * coolilove target.ang[i] = target.ang[i] + jaffset[i] * coolilove end target.evpos = f_lerp(delta, asight.EVPos or vector_origin, vector_origin) target.evang = f_lerp(delta, asight.EVAng or angle_zero, angle_zero) target.down = 0 target.sway = target.sway * f_lerp(delta, 0.1, 1) target.bob = target.bob * f_lerp(delta, 0.1, 1) end stopwatch("sight") local deg = self:GetBarrelNearWall() if deg > 0 and ArcCW.ConVars["vm_nearwall"]:GetBool() then LerpMod(target.pos, hpos, deg) LerpMod(target.ang, hang, deg) target.down = 2 * math.max(sgtd, 0.5) end if !isangle(target.ang) then target.ang = Angle(target.ang) end target.ang.y = target.ang.y + (self:GetFreeAimOffset().y * 0.5) target.ang.p = target.ang.p - (self:GetFreeAimOffset().p * 0.5) if self.InProcDraw then self.InProcHolster = false local delta = m_clamp((CT - self.ProcDrawTime) / (0.5 * self:GetBuff_Mult("Mult_DrawTime")), 0, 1) target.pos = LerpVector(delta, procdraw_vec, target.pos) target.ang = LerpAngle(delta, procdraw_ang, target.ang) target.down = target.down target.sway = target.sway target.bob = target.bob end if self.InProcHolster then self.InProcDraw = false local delta = 1 - m_clamp((CT - self.ProcHolsterTime) / (0.25 * self:GetBuff_Mult("Mult_DrawTime")), 0, 1) target.pos = LerpVector(delta, procdraw_vec, target.pos) target.ang = LerpAngle(delta, prochol_ang, target.ang) target.down = target.down target.sway = target.sway target.bob = target.bob end if self.InProcBash then self.InProcDraw = false local mult = self:GetBuff_Mult("Mult_MeleeTime") local mtime = self.MeleeTime * mult local delta = 1 - m_clamp((CT - self.ProcBashTime) / mtime, 0, 1) local bp, ba if delta > 0.3 then bp = self:GetBuff_Override("Override_BashPreparePos", self.BashPreparePos) ba = self:GetBuff_Override("Override_BashPrepareAng", self.BashPrepareAng) delta = (delta - 0.5) * 2 else bp = self:GetBuff_Override("Override_BashPos", self.BashPos) ba = self:GetBuff_Override("Override_BashAng", self.BashAng) delta = delta * 2 end LerpMod2(bp, target.pos, delta) LerpMod2(ba, target.ang, delta) target.speed = 10 if delta == 0 then self.InProcBash = false end end stopwatch("proc") -- local gunbone, gbslot = self:GetBuff_Override("LHIK_GunDriver") -- if gunbone and IsValid(self.Attachments[gbslot].VElement.Model) and self.LHIKGunPos and self.LHIKGunAng then -- local magnitude = 1 --Lerp(sgtd, 0.1, 1) -- local lhik_model = self.Attachments[gbslot].VElement.Model -- local att = lhik_model:GetAttachment(lhik_model:LookupAttachment(gunbone)) -- local attang = att.Ang -- local attpos = att.Pos -- attang = lhik_model:WorldToLocalAngles(attang) -- attpos = lhik_model:WorldToLocal(attpos) -- attang:Sub(self.LHIKGunAng) -- attpos:Sub(self.LHIKGunPos) -- attang:Mul(magnitude) -- attpos:Mul(magnitude) -- --target.ang:Add(attang) -- --target.pos:Add(attpos) -- --debugoverlay.Axis(lhik_model:GetPos() + attpos, att.Ang, 8, FrameTime() * 3, true) -- debugoverlay.Axis(lhik_model:GetPos(), att.Ang, 8, FrameTime() * 3, true) -- end -- stopwatch("gunbone") local vmhit = self.ViewModel_Hit if vmhit then if !vmhit:IsZero() then target.pos.x = target.pos.x + m_clamp(vmhit.y, -1, 1) * 0.25 target.pos.y = target.pos.y + vmhit.y target.pos.z = target.pos.z + m_clamp(vmhit.x, -1, 1) * 1 target.ang.x = target.ang.x + m_clamp(vmhit.x, -1, 1) * 5 target.ang.y = target.ang.y + m_clamp(vmhit.y, -1, 1) * -2 target.ang.z = target.ang.z + m_clamp(vmhit.z, -1, 1) * 12.5 end local spd = vmhit:Length() * 5 vmhit.x = m_appor(vmhit.x, 0, FT * spd) vmhit.y = m_appor(vmhit.y, 0, FT * spd) vmhit.z = m_appor(vmhit.z, 0, FT * spd) end if ArcCW.ConVars["shakevm"]:GetBool() and !engine.IsRecordingDemo() then target.pos:Add(VectorRand() * self.RecoilAmount * 0.2 * self.RecoilVMShake) end stopwatch("vmhit") local speed = 15 * FT * (game.SinglePlayer() and 1 or 2) LerpMod(actual.pos, target.pos, speed) LerpMod(actual.ang, target.ang, speed, true) LerpMod(actual.evpos, target.evpos or vector_origin, speed) LerpMod(actual.evang, target.evang or angle_zero, speed, true) actual.down = f_lerp(speed, actual.down, target.down) actual.sway = f_lerp(speed, actual.sway, target.sway) actual.bob = f_lerp(speed, actual.bob, target.bob) ApproachMod(actual.pos, target.pos, speed * 0.1) ApproachMod(actual.ang, target.ang, speed * 0.1) actual.down = m_appor(actual.down, target.down, speed * 0.1) stopwatch("actual -> target") local coolsway = ArcCW.ConVars["vm_coolsway"]:GetBool() self.SwayScale = (coolsway and 0) or actual.sway self.BobScale = (coolsway and 0) or actual.bob if coolsway then swayxmult = ArcCW.ConVars["vm_sway_zmult"]:GetFloat() or 1 swayymult = ArcCW.ConVars["vm_sway_xmult"]:GetFloat() or 1 swayzmult = ArcCW.ConVars["vm_sway_ymult"]:GetFloat() or 1 swayspeed = ArcCW.ConVars["vm_sway_speedmult"]:GetFloat() or 1 lookxmult = ArcCW.ConVars["vm_look_xmult"]:GetFloat() or 1 lookymult = ArcCW.ConVars["vm_look_ymult"]:GetFloat() or 1 local sd = self:GetSightDelta() lookxmult = Lerp(sd, 0, lookxmult) lookymult = Lerp(sd, 0, lookymult) swayxmult = Lerp(sd, 0, swayxmult) swayymult = Lerp(sd, 0, swayymult) swayzmult = Lerp(sd, 0, swayzmult) swayspeed = Lerp(sd, 0, swayspeed) stopwatch("before vmposition") local npos, nang = self:GetVMPosition(oldpos, oldang) pos:Set(npos) ang:Set(nang) end local old_r, old_f, old_u = oldang:Right(), oldang:Forward(), oldang:Up() pos:Add(math.min(self.RecoilPunchBack, Lerp(sgtd, self.RecoilPunchBackMaxSights or 1, self.RecoilPunchBackMax)) * -old_f) ang:RotateAroundAxis(old_r, actual.ang.x) ang:RotateAroundAxis(old_u, actual.ang.y) ang:RotateAroundAxis(old_f, actual.ang.z) ang:RotateAroundAxis(old_r, actual.evang.x) ang:RotateAroundAxis(old_u, actual.evang.y) ang:RotateAroundAxis(old_f, actual.evang.z) local new_r, new_f, new_u = ang:Right(), ang:Forward(), ang:Up() old_r:Mul(actual.evpos.x) old_f:Mul(actual.evpos.y) old_u:Mul(actual.evpos.z) pos:Add(old_r) pos:Add(old_f) pos:Add(old_u) new_r:Mul(actual.pos.x) new_f:Mul(actual.pos.y) new_u:Mul(actual.pos.z) pos:Add(new_r) pos:Add(new_f) pos:Add(new_u) pos.z = pos.z - actual.down ang:Add(self:GetOurViewPunchAngles() * Lerp(sgtd, 1, -1)) local gunbone, gbslot = self:GetBuff_Override("LHIK_GunDriver") local lhik_model = gbslot and self.Attachments[gbslot].VElement and self.Attachments[gbslot].VElement.Model -- Visual M203 attachment local lhik_anim_model = gbslot and self.Attachments[gbslot].GodDriver and self.Attachments[gbslot].GodDriver.Model -- M203 anim and camera local lhik_refl_model = gbslot and self.Attachments[gbslot].ReflectDriver and self.Attachments[gbslot].ReflectDriver.Model -- Rifle if IsValid(lhik_model) and IsValid(lhik_anim_model) and IsValid(lhik_refl_model) and lhik_anim_model:GetAttachment(lhik_anim_model:LookupAttachment(gunbone)) then local att = lhik_anim_model:LookupAttachment(gunbone) local offset = lhik_anim_model:GetAttachment(att).Pos local affset = lhik_anim_model:GetAttachment(att).Ang affset:Sub( GunDriverFix ) local r = affset.r affset.r = affset.p affset.p = -r affset.y = -affset.y local anchor = self.Attachments[gbslot].VMOffsetPos local looku = lhik_refl_model:LookupBone( self.Attachments[gbslot].Bone ) local bonp, bona = lhik_refl_model:GetBonePosition( looku ) if bonp == lhik_refl_model:GetPos() then bonp = lhik_refl_model:GetBoneMatrix( looku ):GetTranslation() bona = lhik_refl_model:GetBoneMatrix( looku ):GetAngles() end if anchor and bonp then -- Not ready / deploying anchor = ( bonp + ( (bona:Forward()*anchor.x) + (bona:Right()*anchor.y) + (bona:Up()*anchor.z) ) ) debugoverlay.Axis(anchor, angle_zero, 4, FrameTime(), true) rap_pos, rap_ang = ArcCW.RotateAroundPoint2(pos, ang, anchor, offset, affset) rap_pos:Sub(pos) rap_ang:Sub(ang) pos:Add(rap_pos) ang:Add(rap_ang) end end self.ActualVMData = actual stopwatch("apply actual") stopwatch(true) lst = SysTime() return pos, ang end function SWEP:ShouldCheapWorldModel() local lp = LocalPlayer() if lp:GetObserverMode() == OBS_MODE_IN_EYE and lp:GetObserverTarget() == self:GetOwner() then return true end if !IsValid(self:GetOwner()) and !ArcCW.ConVars["att_showground"]:GetBool() then return true end return !ArcCW.ConVars["att_showothers"]:GetBool() end local bird = Material("arccw/hud/arccw_bird.png", "mips smooth") local iw = 32 function SWEP:DrawWorldModel() local cvar2d3d = ArcCW.ConVars["2d3d"]:GetInt() if !IsValid(self:GetOwner()) and !TTT2 and (cvar2d3d == 2 or (cvar2d3d == 1 and LocalPlayer():GetEyeTrace().Entity == self)) and (EyePos() - self:WorldSpaceCenter()):LengthSqr() <= 262144 then -- 512^2 local ang = LocalPlayer():EyeAngles() ang:RotateAroundAxis(ang:Forward(), 180) ang:RotateAroundAxis(ang:Right(), 90) ang:RotateAroundAxis(ang:Up(), 90) cam.Start3D2D(self:WorldSpaceCenter() + Vector(0, 0, 16), ang, 0.1) srf.SetFont("ArcCW_32_Unscaled") local w = srf.GetTextSize(self.PrintName) srf.SetTextPos(-w / 2 + 2, 2) srf.SetTextColor(0, 0, 0, 150) srf.DrawText(self.PrintName) srf.SetTextPos(-w / 2, 0) srf.SetTextColor(255, 255, 255, 255) srf.DrawText(self.PrintName) local icons = {} for i, slot in pairs(self.Attachments or {}) do if slot.Installed then local atttbl = ArcCW.AttachmentTable[slot.Installed] if !atttbl then continue end local icon = atttbl.Icon if !icon or icon:IsError() then icon = bird end table.insert(icons, icon) end end local ind = math.min(6, #icons) surface.SetDrawColor(255, 255, 255) for i = 1, ind do if i == 6 and #icons > 6 then local str = "+" .. (#icons - ind) local strw = srf.GetTextSize(str) srf.SetTextPos(-ind * iw / 2 + (i - 1) * iw + 2 + strw / 2, iw + 14) srf.SetTextColor(0, 0, 0, 150) srf.DrawText(str) srf.SetTextPos(-ind * iw / 2 + (i - 1) * iw + strw / 2, iw + 12) srf.SetTextColor(255, 255, 255, 255) srf.DrawText(str) else local icon = icons[i] surface.SetMaterial(icon) surface.DrawTexturedRect(-ind * iw / 2 + (i - 1) * iw, iw + 12, iw, iw) end end -- srf.SetFont("ArcCW_24_Unscaled") -- local count = self:CountAttachments() -- if count > 0 then -- local t = tostring(count) .. " Attachments" -- w = srf.GetTextSize(t) -- srf.SetTextPos(-w / 2, 32) -- srf.SetTextColor(255, 255, 255, 255) -- srf.DrawText(t) -- end cam.End3D2D() end self:DrawCustomModel(true) self:DoLaser(true) if self:ShouldGlint() then self:DoScopeGlint() end if !self.CertainAboutAtts and !self.AttReqSent and !IsValid(self:GetOwner()) then self.AttReqSent = true -- print(self, "network weapon from cl_viewmodel") -- debugoverlay.Cross(self:GetPos(), 8, 10, color_white, true) -- debugoverlay.EntityTextAtPosition(self:GetPos(), 1, tostring(self) .. " requesting networking data", 10, color_white) net.Start("arccw_rqwpnnet") net.WriteEntity(self) net.SendToServer() end end function SWEP:ShouldCheapScope() if !ArcCW.ConVars["cheapscopes"]:GetBool() then return end end local POSTVMDONE = nil local POSTVMDONE_TIME = 0 local lst2 = SysTime() function SWEP:PreDrawViewModel(vm) if ArcCW.VM_OverDraw then return end if !vm then return end if self:GetState() == ArcCW.STATE_CUSTOMIZE then self:BlurNotWeapon() end if ArcCW.ConVars["cheapscopesautoconfig"]:GetBool() then local fps = 1 / (SysTime() - lst2) lst2 = SysTime() local lowfps = fps <= 45 ArcCW.ConVars["cheapscopes"]:SetBool(lowfps) ArcCW.ConVars["cheapscopesautoconfig"]:SetBool(false) end local asight = self:GetActiveSights() if asight and ((ArcCW.ConVars["cheapscopes"]:GetBool() and self:GetSightDelta() < 1 and asight.MagnifiedOptic) or (self:GetSightDelta() < 1 and asight.ScopeTexture)) then -- Necessary to call here since physbullets are not drawn until PreDrawEffects; cheap scope implementation will not allow them to be visible -- Introduces a bug when we try to call GetAttachment on the viewmodel in DrawPhysBullets here, so set a workaround variable to not call it ArcCW:DrawPhysBullets(true) self:FormCheapScope() end local coolFOV = self.CurrentViewModelFOV or self.ViewModelFOV if ArcCW.VMInRT then local mag = asight.ScopeMagnification coolFOV = self.ViewModelFOV - mag * 4 - (ArcCW.ConVars["vm_add_ads"]:GetFloat() * 3 or 0) ArcCW.VMInRT = false end cam.Start3D(EyePos(), EyeAngles(), self:QuickFOVix(coolFOV), nil, nil, nil, nil, 0.5, 1000) cam.IgnoreZ(true) self:DrawCustomModel(false) self:DoLHIK() if !ArcCW.Overdraw then self:DoLaser(false, true) end -- patrol if POSTVMDONE == false and POSTVMDONE_TIME <= CurTime() then POSTVMDONE_TIME = CurTime() + 1 print( "[ArcCW] Warning: PostDrawViewModel failed response!! cam.End3D errors may be inbound!! You may have an addon conflict!!") print( "[ArcCW] Follow the troubleshooting guide at https://github.com/HaodongMo/ArcCW/wiki/Help-&-Troubleshooting#camend3d-errors") end POSTVMDONE = false end function SWEP:PostDrawViewModel() POSTVMDONE = true if ArcCW.VM_OverDraw then return end render.SetBlend(1) cam.End3D() cam.Start3D(EyePos(), EyeAngles(), self:QuickFOVix(self.CurrentViewModelFOV or self.ViewModelFOV), nil, nil, nil, nil, 0.5, 1000) cam.IgnoreZ(true) if ArcCW.Overdraw then ArcCW.Overdraw = false else --self:DoLaser() self:DoHolosight() end cam.End3D() end