CEntity.GetModel = function(self) if self:IsValid() then return self.m_ModelName end end CEntity.HasLineOfSight = function( self, tar ) if self and tar then local ignore_tbl = { self, tar } for _, ply in pairs(ents.GetAllPlayers()) do table.insert(ignore_tbl, ply) end local Trace = util.Trace({ start = self:GetAbsOrigin() + Vector(0,0,16), endpos = tar:GetEyePos(), mask = MASK_SOLID, filter = ents.GetAllPlayers() }) local Trace2 = util.Trace({ start = self:GetAbsOrigin(), endpos = tar:GetAbsOrigin(), mask = MASK_SOLID, filter = ents.GetAllPlayers() }) if ( not Trace.Hit ) or ( not Trace2.Hit ) then return true else return false end end end local BOT_SET_SKILL_EASY = "activator.SetDifficulty(0);" local BOT_SET_SKILL_NORMAL = "activator.SetDifficulty(1);" local BOT_SET_SKILL_HARD = "activator.SetDifficulty(2);" local BOT_SET_SKILL_EXPERT = "activator.SetDifficulty(3);" local function weaponMimic(properties) local mimic = ents.CreateWithKeys("tf_point_weapon_mimic", properties) return mimic end function Deposition( damage, activator, caller ) if not caller:IsValid() then return end if ( not caller:IsBot() ) and ( not caller:IsObject() ) and ( not caller:IsNPC() ) then return end if caller:OnTeam(1) then return end if caller.m_iTeamNum == activator.m_iTeamNum then return end activator.m_iAmmo[TF_AMMO_PRIMARY] = math.min( activator.m_iAmmo[TF_AMMO_PRIMARY] + 25, 1000 ) activator.m_iAmmo[TF_AMMO_SECONDARY] = math.min( activator.m_iAmmo[TF_AMMO_SECONDARY] + 2, 160 ) end --Credit to Crilly/TheRealScroob for the base of this function function ReloadOnHit(damage, activator, caller) if not caller:IsValid() then return end if ( not caller:IsBot() ) and ( not caller:IsObject() ) and ( not caller:IsNPC() ) then return end if caller:OnTeam(1) then return end if caller.m_iTeamNum == activator.m_iTeamNum then return end local upgradeLevel = nil if activator:GetPlayerItemBySlot(0):GetAttributeValue("purchased") ~= nil then upgradeLevel = activator:GetPlayerItemBySlot(0):GetAttributeValue("purchased") elseif activator:GetPlayerItemBySlot(1):GetAttributeValue("purchased") ~= nil then upgradeLevel = activator:GetPlayerItemBySlot(1):GetAttributeValue("purchased") elseif activator:GetPlayerItemBySlot(2):GetAttributeValue("purchased") ~= nil then upgradeLevel = activator:GetPlayerItemBySlot(2):GetAttributeValue("purchased") end if upgradeLevel == nil then return end local BASE_CLIP = nil if activator:GetPlayerItemBySlot(0):GetAttributeValue("halloween item") ~= nil then BASE_CLIP = activator:GetPlayerItemBySlot(0):GetAttributeValue("halloween item") elseif activator:GetPlayerItemBySlot(1):GetAttributeValue("halloween item") ~= nil then BASE_CLIP = activator:GetPlayerItemBySlot(1):GetAttributeValue("halloween item") elseif activator:GetPlayerItemBySlot(2):GetAttributeValue("halloween item") ~= nil then BASE_CLIP = activator:GetPlayerItemBySlot(2):GetAttributeValue("halloween item") end if BASE_CLIP == nil then return end local primary = activator:GetPlayerItemBySlot(0) local secondary = activator:GetPlayerItemBySlot(1) if primary:GetItemName() ~= "The Cow Mangler 5000" then local clipBonusMult = primary:GetAttributeValueByClass("mult_clipsize", 1) local clipBonusMult = clipBonusMult * primary:GetAttributeValueByClass("mult_clipsize_upgrade", 1) local clipBonusAtomic = primary:GetAttributeValueByClass("mult_clipsize_upgrade_atomic", 0) local airstrikeKills = 0 local overloadRefundAmount = 0 if primary:GetItemName() == "The Air Strike" then airstrikeKills = activator.m_Shared.m_iDecapitations + 1 end if IsValid( secondary ) and ( secondary:GetItemName() == "The Tide Turner" ) and ( ( secondary:GetAttributeValue("halloween item") or 0 ) == 4 ) and ( activator.m_flChargeMeter <= 1 ) then upgradeLevel = math.round( lerp( 0, 4, math.min( damage / 75, 1 ) ), 0 ) end local maxClip = math.round( ( BASE_CLIP * clipBonusMult ) + clipBonusAtomic + airstrikeKills, 0 ) if activator:IsRealPlayer() == true then activator.m_iAmmo[TF_AMMO_PRIMARY] = activator.m_iAmmo[TF_AMMO_PRIMARY] - upgradeLevel if activator.m_iAmmo[TF_AMMO_PRIMARY] < 0 then upgradeLevel = upgradeLevel + activator.m_iAmmo[TF_AMMO_PRIMARY] activator.m_iAmmo[TF_AMMO_PRIMARY] = 0 end end primary.m_iClip1 = primary.m_iClip1 + upgradeLevel if primary.m_iClip1 > maxClip then overloadRefundAmount = primary.m_iClip1 - maxClip overloadRefundAmount = overloadRefundAmount + upgradeLevel activator.m_iAmmo[TF_AMMO_PRIMARY] = activator.m_iAmmo[TF_AMMO_PRIMARY] + overloadRefundAmount primary.m_iClip1 = maxClip end else local clipBonusMult = primary:GetAttributeValueByClass("mult_clipsize_upgrade", 1) local maxClip = (BASE_CLIP * 5) * clipBonusMult --print( maxClip, ( maxClip * upgradeLevel ), primary.m_flEnergy + ( ( maxClip * upgradeLevel ) ) ) primary.m_flEnergy = primary.m_flEnergy + ( ( maxClip * upgradeLevel ) ) if primary.m_flEnergy > maxClip then primary.m_flEnergy = maxClip end if ( primary.m_flEnergy / 5 ) ~= ( math.floor( primary.m_flEnergy / 5 ) ) then local newClip = math.round( primary.m_flEnergy / 100, 1 ) --gotta love number theory --print( newClip, newClip * 100 ) newClip = newClip * 100 primary.m_flEnergy = newClip --How this works: lets say energy = 47 --47/5 ~= floor(47/5) --47/100 = 0.47 --round to nearest tenth: 0.5 --* by 100 to undo /: 50 --energy = 50 --note that this is called after adding, this can make it go from 45 -> 60 when upgradeLevel = 0.2 end end end function GainAmmoOnHit( info, activator, caller ) if not caller:IsValid() then return end if ( not caller:IsBot() ) and ( not caller:IsObject() ) and ( not caller:IsNPC() ) then return end if caller:OnTeam(1) then return end if caller.m_iTeamNum == activator.m_iTeamNum then return end local _, _, amount, max, slot = string.find( info, "(%d+)|(%d+)|(%d+)" ) amount, max, slot = tonumber(amount), tonumber(max), tonumber(slot) local ammo = TF_AMMO_PRIMARY if tonumber(slot) == 0 then ammo = TF_AMMO_PRIMARY max = max * activator:GetPlayerItemBySlot( slot ):GetAttributeValueByClass( "mult_maxammo_primary", 1 ) elseif slot == 1 then ammo = TF_AMMO_SECONDARY max = max * activator:GetPlayerItemBySlot( slot ):GetAttributeValueByClass( "mult_maxammo_secondary", 1 ) elseif slot == -1 then ammo = TF_AMMO_METAL max = max * activator:GetPlayerItemBySlot( slot ):GetAttributeValueByClass( "mult_maxammo_metal", 1 ) end activator.m_iAmmo[ammo] = math.min( activator.m_iAmmo[ammo] + amount, max ) end function GainMetalOnHit(damage, activator, caller) if not caller:IsValid() then return end if ( not caller:IsBot() ) and ( not caller:IsObject() ) and ( not caller:IsNPC() ) then return end if caller:OnTeam(1) then return end if caller.m_iTeamNum == activator.m_iTeamNum then return end local upgradeLevel = nil if activator:GetPlayerItemBySlot(0):GetAttributeValue("purchased") ~= nil then upgradeLevel = activator:GetPlayerItemBySlot(0):GetAttributeValue("purchased") elseif activator:GetPlayerItemBySlot(1):GetAttributeValue("purchased") ~= nil then upgradeLevel = activator:GetPlayerItemBySlot(1):GetAttributeValue("purchased") elseif activator:GetPlayerItemBySlot(2):GetAttributeValue("purchased") ~= nil then upgradeLevel = activator:GetPlayerItemBySlot(2):GetAttributeValue("purchased") end if upgradeLevel == nil then return end local MAX_CLIP = 200 MAX_CLIP = MAX_CLIP * ( activator:GetAttributeValueByClass("mult_maxammo_metal", 1 ) ) local secondary = activator:GetPlayerItemBySlot(1) if secondary:GetItemName() == "The Short Circuit" then if activator:IsRealPlayer() then activator.m_iAmmo[TF_AMMO_METAL] = math.min( activator.m_iAmmo[TF_AMMO_METAL] + ( damage * upgradeLevel ), MAX_CLIP ) end end end function ChainHitChecks( damage, activator, caller ) if not IsValidPlayer( caller ) then return end if not IsValidPlayer( activator ) then return end if 100 > damage then return end timer.Simple( 0.2, function() ChainAttack( damage, activator, caller, 300 ) end) end function ChainHitChecksDiamond( damage, activator, caller ) if not IsValidPlayer( caller ) then return end if not IsValidPlayer( activator ) then return end timer.Simple( 0.2, function() ChainAttack( damage, activator, caller, 300 ) end) end function ChainAttack( damage, activator, caller, radius ) local enemy_list = {} if activator.LightningJumps >= 10 then activator.LightningJumps = 0; return end --limit this for _, player in pairs( ents.FindInSphere( caller:GetAbsOrigin(), radius ) ) do if player:IsPlayer() and ( player:GetTeam() ~= activator:GetTeam() ) and ( player ~= caller ) and ( CurTime() >= player.ChainedTo ) and ( player:IsAlive() ) and ( not player:OnTeam(2) ) then table.insert( enemy_list, { player, caller:GetAbsOrigin():Distance( player:GetAbsOrigin() ) } ) end end --table.sort( enemy_list, function(a,b) return a[2] < b[2] end ) --find closest player if #enemy_list > 0 then local rand = math.random( 1, #enemy_list ) enemy_list[rand][1].ChainedTo = CurTime() + 1 activator.LightningJumps = activator.LightningJumps + 1 local particle = ents.CreateWithKeys( "info_particle_system", { ["effect_name"] = "dxhr_lightningball_hit_red", ["start_active"] = 1, ["origin"] = caller:GetAbsOrigin()[1] .. " " .. caller:GetAbsOrigin()[2] .. " " .. (caller:GetAbsOrigin()[3] + 0), ["cpoint1"] = enemy_list[rand][1] }, true, true) particle.m_hControlPointEnts[1] = enemy_list[rand][1] timer.Simple( 0.1, function() --feedback particle:Remove() end) enemy_list[rand][1]:TakeDamage({ Damage = damage, Attacker = activator, DamageType = DMG_SHOCK | DMG_NEVERGIB | DMG_PREVENT_PHYSICS_FORCE, DamageCustom = TF_DMG_CUSTOM_PLASMA }) timer.Simple( 0.2, function() ChainAttack( damage, activator, enemy_list[rand][1], 300 ) end) else activator.LightningJumps = 0 end end function Teleported(taunt, activator) if taunt == "scenes/player/engineer/low/taunt_drg_melee.vcd" then local cantp = true local oldpos = activator:GetAbsOrigin() if activator.m_iAmmo[4] < 100 then cantp = false else cantp = true end timer.Simple(1.8, function() if cantp then activator.m_iHealth = activator.m_iHealth - 50 activator.m_iAmmo[4] = activator.m_iAmmo[4] - 100 activator:AddCond( 37, 7.5 ) activator:AddCond( 32, 7.5 ) end end) timer.Simple(2.3, function() if activator.m_iHealth < 1 then activator:AcceptInput("$Suicide") end if not cantp then activator:SetAbsOrigin(oldpos) end end) end end function LockTargetAim( _, activator, caller ) if not IsValid( caller ) then return end if not IsValid( activator ) then return end if caller:GetTeam() == activator:GetTeam() then return end caller:AcceptInput("$BotCommand", "interrupt_action -lookpos " .. tostring( activator:GetAbsOrigin() ) .. " -duration 3 -alwayslook -waituntildone" ) local EMPFX = ents.CreateWithKeys("info_particle_system", { effect_name = "medic_resist_blast", start_active = 1, flag_as_weather = 0, }, true, true) EMPFX:SetAbsOrigin(caller:GetAbsOrigin()) EMPFX:Start() EMPFX:AcceptInput("SetParent", "!activator", caller, nil) timer.Simple( 3.5, function() EMPFX:Remove() end) end function shieldAddcondOnHitFix(damage, activator, caller) --Made by Crilly/TheRealScroob local shield = activator:GetPlayerItemBySlot(1) local selfCond = shield:GetAttributeValue("self add cond on hit", true) local enemyCond = shield:GetAttributeValue("add cond on hit", true) local enemyCondDuration = shield:GetAttributeValue("add cond on hit duration", true) local selfCondDuration = shield:GetAttributeValue("self add cond on hit duration", true) local healOnHit = shield:GetAttributeValueByClass("add_onhit_addhealth", 0) activator.m_iHealth = activator.m_iHealth + healOnHit if selfCond and selfCondDuration then activator:AddCond(selfCond, selfCondDuration, activator) end if enemyCond and enemyCondDuration then caller:AddCond(enemyCond, enemyCondDuration, activator) end end function StunShield( damage, activator, caller ) if IsValidPlayer( caller ) then if not tobool(caller.m_bIsMiniBoss) then caller:StunPlayer( 4, 1, TF_STUNFLAGS_NORMALBONK, activator ) else caller:StunPlayer( 3, 0.65, TF_STUNFLAG_SLOWDOWN, activator ) end end end function BlastShield( damage, activator, caller ) if IsValidPlayer( caller ) and IsValidPlayer( activator ) then local blast_dmg = lerp( 40, 120, damage / 75 ) local melee = activator:GetPlayerItemBySlot(2) local attr = melee:GetAttributeValue( "damage bonus" ) or 1 local blast_radius = 180 blast_dmg = blast_dmg * attr local mimic mimic = weaponMimic({ TeamNum = activator.m_iTeamNum, WeaponType = 3, -- sticky Damage = blast_dmg, Crits = 0, SplashRadius = blast_dmg, SpeedMax = 0, SpeedMin = 0, ["$dmgtype"] = DMG_BLAST | DMG_ALWAYSGIB, ["$killicon"] = "splendid_screen", ["$preventshootparent"] = 1, origin = tostring(activator:GetAbsOrigin()), angles = tostring(Vector(0, 0, 0)), }) if blast_dmg >= 200 then util.ParticleEffect( "hightower_explosion", activator:GetAbsOrigin() + Vector(0,0,32) ) end mimic["$SetOwner"](mimic, activator) mimic["$AddWeaponAttribute"](mimic, "blast radius increased|" .. tostring( math.min( blast_dmg/146, 1 ) ) ) if mimic:IsValid() then mimic:FireOnce() mimic:DetonateStickies() timer.Simple(0.1, function() mimic:Remove() end) end end end function BashReturn( damage, activator, caller ) if IsValidPlayer( activator ) then local MaxHealth = activator.m_iMaxHealth + activator:GetAttributeValueByClass("add_maxhealth_nonbuffed", 0) + activator:GetAttributeValueByClass("add_maxhealth", 0) local fakeEventTable = { patient = activator:GetUserId(), healer = activator:GetUserId(), amount = lerp( 25, 75, math.min( damage / 75, 1 ) ) } FireEvent("player_healed", fakeEventTable) activator:PlaySoundToSelf("HealthKit.Touch") activator.m_iHealPoints = activator.m_iHealPoints + lerp( 25, 75, math.min( damage / 75, 1 ) ) activator.m_iHealth = math.min( activator.m_iHealth + ( lerp( 25, 75, math.min( damage / 75, 1 ) ) ), MaxHealth ) end end function ResetAirDashes(_, activator, caller ) --activator is the one with the weapon, caller is the weapon if activator and IsValidAliveRealPlayer( activator ) and ( not activator.JumpsRest ) and ( activator:IsMidair() ) then activator.m_iAirDash = 0 activator.JumpsRest = true activator:PlaySoundToSelf("items/powerup_pickup_agility.wav") end end function RechargeCleaver( damage, activator, caller ) --activator is the one with the weapon, caller is the one who got hit if activator and IsValidAliveRealPlayer( activator ) and ( IsValid( activator:GetPlayerItemBySlot(1) ) ) then local wep = activator:GetPlayerItemBySlot(1) local charge = wep.m_flEffectBarRegenTime local decrease = lerp( 0.1, 1.2, math.min( damage / 100, 1 ) ) if charge > 0 then wep.m_flEffectBarRegenTime = charge - decrease end end end function RechargeSapper( damage, activator, caller ) --activator is the one with the weapon, caller is the one who got hit if activator and IsValidAliveRealPlayer( activator ) and ( IsValid( activator:GetPlayerItemBySlot(LOADOUT_POSITION_BUILDING) ) ) then local wep = activator:GetPlayerItemBySlot(LOADOUT_POSITION_BUILDING) local max = 2 if activator.m_hActiveWeapon == activator:GetPlayerItemBySlot(2) then max = 1 end local charge = wep.m_flEffectBarRegenTime local decrease = lerp( 0.1, max, math.min( damage / 60, 1 ) ) if charge > 0 then wep.m_flEffectBarRegenTime = charge - decrease end end end function ResetChargeDrain( dmg, activator, caller ) if activator and IsValidAliveRealPlayer( activator ) then if activator:InCond( TF_COND_SHIELD_CHARGE ) and ( activator.m_hActiveWeapon == activator:GetPlayerItemBySlot(2) ) then activator.TrainTimestamp = CurTime() end end end function UseStoredCrits( _, activator, weapon ) local Clip = weapon.m_iClip1 weapon.m_iClip1 = Clip + 1 if activator.StoredCrits > 0 then activator:Print( 2, "You have used your stored crits. " .. tostring(activator.StoredCrits) .. " seconds of crits") activator:AddCond( 56, activator.StoredCrits ) activator.StoredCrits = 0 activator:PlaySoundToSelf("items/powerup_pickup_crits.wav") end end function DropAmmoKit( _, activator, caller ) --activator is the one with the weapon, caller is the one who got hit local giant = tobool( caller.m_bIsMiniBoss ) local callerOrigin = caller:GetAbsOrigin() local class = "item_ammopack_small" if giant then class = "item_ammopack_medium" end local ammoPack = ents.CreateWithKeys( class, { ["origin"] = callerOrigin[1] .. " " .. callerOrigin[2] .. " " .. (callerOrigin[3] + 10) } ) timer.Simple(10, function() if ammoPack:IsValid() then ammoPack:Remove() end end) end function mgExplosion(damage, activator, caller) if ( damage >= 195 ) and ( activator:IsMidair() ) then if caller:IsBot() then for _, others in pairs(ents.FindInSphere(caller:GetAbsOrigin(),150)) do if others:IsBot() then others:TakeDamage({ Damage = 105, Attacker = activator, DamageType = DMG_BLAST, DamageCustom = TF_DMG_CUSTOM_STICKBOMB_EXPLOSION }) if not tobool(others.m_bIsMiniBoss) then others:StunPlayer( 4, 1, TF_STUNFLAGS_NORMALBONK, activator ) else others:StunPlayer( 1, 0.65, TF_STUNFLAG_SLOWDOWN, activator ) end end end util.ParticleEffect( "mvm_loot_explosion", caller:GetAbsOrigin() + Vector(0,0,32) ) caller:PlaySound("BaseExplosionEffect.Sound") end end end function comboExplosion(damage, activator, caller) if ( damage >= 195 ) and ( not activator:IsCritBoosted() ) then if damage > 200 then if caller:IsBot() then for _, others in pairs(ents.FindInSphere(caller:GetAbsOrigin(),300)) do if others:IsBot() then others:TakeDamage({ Damage = 300, Attacker = activator, DamageType = DMG_BLAST, DamageCustom = TF_DMG_CUSTOM_STICKBOMB_EXPLOSION }) if not tobool(others.m_bIsMiniBoss) then others:StunPlayer( 5, 1, TF_STUNFLAGS_NORMALBONK, activator ) else others:StunPlayer( 1, 0.85, TF_STUNFLAG_SLOWDOWN, activator ) end end end util.ParticleEffect( "mvm_loot_explosion", caller:GetAbsOrigin() + Vector(0,0,32) ) caller:PlaySound("BaseExplosionEffect.Sound") end else if caller:IsBot() then for _, others in pairs(ents.FindInSphere(caller:GetAbsOrigin(),150)) do if others:IsBot() then others:TakeDamage({ Damage = 105, Attacker = activator, DamageType = DMG_BLAST, DamageCustom = TF_DMG_CUSTOM_STICKBOMB_EXPLOSION }) if not tobool(others.m_bIsMiniBoss) then others:StunPlayer( 2, 1, TF_STUNFLAGS_NORMALBONK, activator ) else others:StunPlayer( 1, 0.65, TF_STUNFLAG_SLOWDOWN, activator ) end end end util.ParticleEffect( "mvm_loot_explosion", caller:GetAbsOrigin() + Vector(0,0,32) ) caller:PlaySound("BaseExplosionEffect.Sound") end end end end function OnPlayerConnected( player ) if player:IsBot() then SetUpCallBacks( player ) SetUpCallNetpropsBot( player ) end if player:IsRealPlayer() then SetUpPlayerCallBacks( player ) SetUpPlayerNetprops( player ) end SetUpSharedCallBacks( player ) end function OnPlayerDeath(player, attacker, weapon, dmgtype, assister, crit_type, silent_kill) if player == nil or attacker == nil or weapon == nil then return end if player and IsValidPlayer(player) and ( attacker and IsValidPlayer(attacker) ) and ( weapon ) then if crit_type == 1 and ( weapon == "back_scatter" ) then attacker.StoredCrits = math.min( attacker.StoredCrits + 1, 30 ) --called twice for some reason end end end function AddStoredCrit( damage, activator, caller ) if damage > 10 then activator.StoredCrits = math.min( activator.StoredCrits + 1, 30 ) end end local UpdateTimer = CurTime() function OnGameTick() PlayerLogic() --CleaverRechargeLogic() ScreenText() AdrenalineJunkie() RechargeBattery() ExplosiveGroundSlam() ApplyBotEffects() MineLayer() end local MineModel = "models/pickups/emitter.mdl" function removeCallbacks(player, callbacks) if not IsValid(player) then return end for _, callbackId in pairs(callbacks) do player:RemoveCallback(callbackId) end end function MineLayer() for _, mine in pairs( ents.FindAllByClass("tf_projectile_pipe") ) do if mine:GetModel() == MineModel and ( IsValid(mine) ) then if not mine.Grounded then mine.Grounded = false end if not mine.Armed then mine.Armed = false end local callbacks = {} local terminated = false local function terminate() if terminated then return end terminated = true removeCallbacks(mine, callbacks) end if not callbacks.removed then callbacks.removed = mine:AddCallback(ON_REMOVE, function() terminate() mine:StopSound("MineLayer.Deploy") end) end if mine.Grounded == false then local filter = ents.GetAllPlayers() table.insert( filter, mine ) local Tracer = util.Trace({ start = mine:GetAbsOrigin(), distance = 8, angles = Vector(90, 0, 0), mask = MASK_PLAYERSOLID, filter = filter, mins = Vector(-4,-4,0), maxs = Vector(4,4,0) }) if Tracer.Hit then mine.Grounded = true mine.ArmTime = CurTime() + 2 mine:PlaySound("MineLayer.HitGround") mine:AcceptInput( "RunScriptCode", "self.SetForwardVector( Vector(1) )" ) mine:AcceptInput( "RunScriptCode", "self.SetPhysVelocity( Vector() )" ) mine:AcceptInput( "RunScriptCode", "self.SetPhysAngularVelocity( Vector() )" ) end else if CurTime() >= mine.ArmTime and ( not mine.Armed ) then mine.Armed = true mine:AcceptInput( "Skin", 1 ) mine:PlaySound("MineLayer.Deploy") timer.Simple(0.5, function() if mine:IsValid() then mine:StopSound("MineLayer.Deploy") end end) end if mine.Armed then mine.m_bTouched = 0 timer.Simple(0, function() mine.m_bTouched = 0 end) else mine.m_bTouched = 1 end end end end end function ExplosiveGroundSlam() for _, player in pairs(ents.GetAllPlayers()) do if player:IsRealPlayer() then local wep local mult = 1 local need_melee_active = false if IsValid( player:GetPlayerItemBySlot(1) ) and( player:GetPlayerItemBySlot(1):GetAttributeValue("wrench index" ) or 0 ) == 7 then wep = player:GetPlayerItemBySlot(1) elseif IsValid( player:GetPlayerItemBySlot(2) ) and( player:GetPlayerItemBySlot(2):GetAttributeValue("wrench index" ) or 0 ) == 7 then wep = player:GetPlayerItemBySlot(2) mult = 0.75 need_melee_active = true else goto continue end if wep and IsValid(wep) and ( ( wep:GetAttributeValue("wrench index") or 0 ) == 7 ) then local airtime, start_slam, max_slam_time, slam_buff_threshold_1, slam_buff_threshold_2, percent, damage, radius if player:IsMidair() then player.TimeMidair = CurTime() if player.MidairTimestamp == false then player.MidairTimestamp = CurTime() end airtime = player.TimeMidair slam_buff_threshold_1 = player.MidairTimestamp + ( 3 * mult ) slam_buff_threshold_2 = player.MidairTimestamp + ( 6 * mult ) if ( need_melee_active and ( wep ~= player.m_hActiveWeapon ) ) then return end if airtime >= slam_buff_threshold_1 then player:AddCond(19,0.1) end if airtime >= slam_buff_threshold_2 then player:AddCond(56,0.1) end else if player.MidairTimestamp ~= false then if ( need_melee_active and ( wep ~= player.m_hActiveWeapon ) ) then return end airtime = player.TimeMidair start_slam = player.MidairTimestamp + ( 1.5 * mult ) max_slam_time = player.MidairTimestamp + ( 8 * mult ) slam_buff_threshold_1 = player.MidairTimestamp + ( 3 * mult ) slam_buff_threshold_2 = player.MidairTimestamp + ( 6 * mult ) percent = math.clamp( ( ( airtime - player.MidairTimestamp ) - ( 1.5 * mult ) ) / ( ( max_slam_time - player.MidairTimestamp ) - ( 1.5 * mult ) ), 0, 1 ) damage = lerp( 90 * 1.35, 600 / 1.35, math.max( percent, 0 ) ) --minicrits does 35% extra damage radius = lerp( 100, 350, math.max( percent, 0 ) ) local mimic if airtime >= start_slam then mimic = weaponMimic({ TeamNum = player.m_iTeamNum, WeaponType = 3, -- sticky Damage = damage, Crits = 0, SplashRadius = radius, SpeedMax = 0, SpeedMin = 0, ["$dmgtype"] = DMG_BLAST | DMG_ALWAYSGIB | DMG_HALF_FALLOFF, ["$killicon"] = "mantreads", ["$preventshootparent"] = 1, origin = tostring(player:GetAbsOrigin()), angles = tostring(Vector(0, 0, 0)), }) mimic["$SetOwner"](mimic, player) mimic["$AddWeaponAttribute"](mimic, "blast radius increased|" .. tostring( math.min( radius/146, 1 ) ) ) if airtime >= slam_buff_threshold_2 then mimic["$killicon"] = "megaton" mimic["$AddWeaponAttribute"](mimic, "explosion particle|skull_island_explosion") mimic["$AddWeaponAttribute"](mimic, "explosion particle on direct hit|skull_island_explosion") elseif airtime >= slam_buff_threshold_1 then mimic["$killicon"] = "sticky_resistance" mimic["$AddWeaponAttribute"](mimic, "explosion particle|hightower_explosion") mimic["$AddWeaponAttribute"](mimic, "explosion particle on direct hit|hightower_explosion") end if mimic:IsValid() then mimic:FireOnce() mimic:DetonateStickies() timer.Simple(0.1, function() mimic:Remove() end) end end else player.MidairTimestamp = false end player.MidairTimestamp = false end end ::continue:: end end end function AdrenalineJunkie() for _, player in pairs(ents.GetAllPlayers()) do if player:IsRealPlayer() then local wep = player:GetPlayerItemBySlot(0) if wep and IsValid(wep) and ( ( wep:GetAttributeValue("wrench index") or 0 ) == 5 ) then local boost = player.m_flHypeMeter player:SetAttributeValue("halloween reload time decreased", lerp( 1, 0.4, boost / 99) ) player:SetAttributeValue("halloween fire rate bonus", lerp( 1, 0.6, boost / 99) ) player:SetAttributeValue("move speed penalty", lerp( 1, 360/520, boost / 99) ) --bfb move speed doesn't update dynamically so I have counter act it player:SetAttributeValue("major move speed bonus", lerp( 1, 520/360, boost / 99) ) player.m_flHypeMeter = math.max( boost - 0.15, 0 ) --10 seconds to drain end end end end function RechargeBattery() for _, player in pairs(ents.GetAllPlayers()) do if player:IsRealPlayer() then if not player.BatteryTimer then player.BatteryTimer = CurTime() end if CurTime() >= player.BatteryTimer then player.BatteryTimer = CurTime() + 1 local primary = player:GetPlayerItemBySlot(0) if primary and IsValid(primary) and primary.m_flEnergy and ( ( primary:GetAttributeValue("taunt is highfive") or 0 ) > 0 ) then local clipBonusMult = primary:GetAttributeValueByClass("mult_clipsize_upgrade", 1) local maxClip = 20 * clipBonusMult local upgradeLevel = primary:GetAttributeValue("taunt is highfive") or 0 primary.m_flEnergy = primary.m_flEnergy + upgradeLevel if primary.m_flEnergy > maxClip then primary.m_flEnergy = maxClip end end local secondary = player:GetPlayerItemBySlot(1) if secondary and IsValid(secondary) and secondary.m_flEnergy and ( ( secondary:GetAttributeValue("taunt is highfive") or 0 ) > 0 ) then local clipBonusMult = secondary:GetAttributeValueByClass("mult_clipsize_upgrade", 1) local maxClip = 20 * clipBonusMult local upgradeLevel = secondary:GetAttributeValue("taunt is highfive") or 0 secondary.m_flEnergy = secondary.m_flEnergy + upgradeLevel if secondary.m_flEnergy > maxClip then secondary.m_flEnergy = maxClip end end end end end end function AddHeat( damage, activator, caller ) if activator and damage then activator.Heat = math.min( activator.Heat + damage, 500 ) end end function UseHeat( _, activator, weapon ) if activator.Heat >= 100 then activator.Heat = math.max( activator.Heat - 100, 0 ) util.ParticleEffect( "heavy_ring_of_fire_fp", activator:GetAbsOrigin() + Vector( 0, 0, 16 ) ) activator:PlaySound("ambient/fire/ignite.wav") activator:PlaySound("ambient/fire/ignite.wav") for _, others in pairs(ents.FindInSphere(activator:GetAbsOrigin(),240)) do if others:IsBot() and others:IsAlive() and ( not others:OnTeam(2) ) then if others:InCond( TF_COND_BURNING ) then others:TakeDamage({ Attacker = activator, Damage = 35, DamageType = DMG_BURNING, DamageCustom = TF_DMG_CUSTOM_DRAGONS_FURY_BONUS_BURNING, CritType = 2 }) end others:IgnitePlayerDuration( 10, activator ) others.IgnitedByPower = true util.ParticleEffect( "heavy_ring_of_fire", others:GetAbsOrigin() + Vector( 0, 0, 16 ) ) end end end end function FlareRaider(damage, activator, caller) --activator is the one with the weapon, caller is the one that got hit if caller == activator then activator:Addcond(81) end end function ScottishRaider(damage, activator, caller) --activator is the one with the weapon, caller is the one that got hit if caller == activator then activator:Addcond(81) activator:SetAttributeValue( "fire rate bonus", 0.5 ) activator:SetAttributeValue( "blast radius decreased", 0.85 ) end end function SetUpPlayerNetprops( ply ) ply.StoredCrits = 0 ply.Heat = 0 ply.BatteryTimer = CurTime() ply.MidairTimestamp = false ply.TimeMidair = CurTime() ply.RemoveBoost = 0 ply.ChargingAirblast = false ply.ChargeAirblastTimestamp = false ply.ChargeAirblastTime = CurTime() ply.TrainTimestamp = false ply.ParryEndTime = CurTime() ply.TrainTime = CurTime() ply.LightningJumps = 0 ply.Buildings = { nil, nil, nil } ply.InUber = false ply.ChargeLoopCounter = 0 ply.Missed = false ply.HeadShot = false ply.OldCharge = 0 end function SetUpPlayerCallBacks( ply ) if ply and ply:IsValid() then ply:AddCallback( ON_SPAWN, function( ent ) ent.StoredCrits = 0 ent.Heat = 0 ent.RemoveBoost = 0 ent.MidairTimestamp = false ent:GetPlayerItemBySlot(1):SetAttributeValue( "hidden maxhealth non buffed", nil ) ent:SetAttributeValue("fire input on hit", nil) ent.InUber = false ent:SetAttributeValue( "SET BONUS: max health additive bonus", nil ) ent.ChargeLoopCounter = ply.ChargeLoopCounter for _, building in pairs( ent.Buildings ) do if IsValid(building) and ( building.BuiltWith ~= ent:GetPlayerItemBySlot(1) ) then building:RemoveHealth( 69420 ) end end end) ply:AddCallback( ON_DAMAGE_RECEIVED_PRE, function( ent, dmginfo ) if dmginfo.Inflictor == nil then return end if dmginfo.Attacker == nil then return end if dmginfo.Inflictor.m_hLauncher == nil and ( dmginfo.Inflictor:GetOwner() == ent ) then dmginfo.Damage = 0 return true end end) ply:AddCallback( ON_DAMAGE_RECEIVED_PRE, function( ent, dmginfo ) if dmginfo.Attacker == nil then return end if not IsValid( ent:GetPlayerItemBySlot(2) ) then return end local melee = ent:GetPlayerItemBySlot(2) local attr = melee:GetAttributeValue( "wrench index" ) or 0 local heads = math.min( ent.m_iDecapitations, 10 ) if ( attr == 12 ) and ( ent:IsAlive() ) then ent.OldHeads = heads --print( ent.OldHeads ) end end) ply:AddCallback( ON_DEATH, function() if not IsValid( ply:GetPlayerItemBySlot(2) ) then return end local melee = ply:GetPlayerItemBySlot(2) local attr = melee:GetAttributeValue( "wrench index" ) or 0 --REMEMBER TO REMOVE THIS timer.Simple( 0.1, function() -- ply:ForceRespawn() end) if ( attr == 12 ) and ( ply.OldHeads > 0 ) then ply.OldPos = ply:GetAbsOrigin() ply.OldHeads = ply.m_iDecapitations timer.Simple( 0.1, function() ply:ForceRespawn() ply:SetAbsOrigin( ply.OldPos ) ply:StunPlayer( 0.5, 1, TF_STUNFLAG_BONKSTUCK ) ply:SetHealth( lerp( 0, ply.m_iMaxHealth, ply.OldHeads * 0.1 ) ) ply:AddCond( 57, 2 ) ply:AddCond( 36, 2 ) ply:Print( 2, "You were revived at " .. tostring( ply.OldHeads * 10 ) .. "% of your max health." ) ply.OldHeads = 0 end) end end) ply:AddCallback( ON_DAMAGE_RECEIVED_POST, function( ent, dmginfo, previousHealth ) if dmginfo.Inflictor == nil then return end if dmginfo.Attacker == nil then return end local attacker, damage, damagetype = dmginfo.Attacker, dmginfo.Damage, dmginfo.DamageType if attacker:GetTeam() ~= ent:GetTeam() and ( ent.ParryEndTime >= CurTime() ) then -- damage = damage / 0.25 -- if IsDamageType( damagetype, DMG_BULLET ) or IsDamageType( damagetype, DMG_BUCKSHOT ) or IsDamageType( damagetype, DMG_SLASH ) then -- damage = damage / ent:GetAttributeValueByClass("mult_dmgtaken_from_bullets", 1 ) -- end -- if IsDamageType( damagetype, DMG_BLAST ) then -- damage = damage / ent:GetAttributeValueByClass("mult_dmgtaken_from_explosions", 1 ) -- end -- if IsDamageType( damagetype, DMG_BURN ) or IsDamageType( damagetype, DMG_IGNITE ) then -- damage = damage / ent:GetAttributeValueByClass("mult_dmgtaken_from_fire", 1 ) -- end -- damage = damage * 0.75 local particle = ents.CreateWithKeys( "info_particle_system", { ["effect_name"] = "arm_muzzleflash_zap", ["start_active"] = 1, ["origin"] = ent:GetEyePos()[1] .. " " .. ent:GetEyePos()[2] .. " " .. (ent:GetEyePos()[3] + 10), ["cpoint1"] = attacker }, true, true) ent:PlaySound("Powerup.Reflect.Reflect") particle.m_hControlPointEnts[1] = attacker timer.Simple( 0.1, function() --feedback attacker:TakeDamage({ Attacker = ent, Damage = damage, DamageType = damagetype, DamageCustom = dmginfo.DamageCustom, CritType = dmginfo.CritType, Weapon = dmginfo.Weapon }) particle:Remove() end) end end) ply:AddCallback(ON_KEY_PRESSED, function(entity, key) if key == IN_ATTACK2 then if IsValid(ply:GetPlayerItemBySlot(0)) then local attr = ply.m_hActiveWeapon:GetAttributeValue("charged airblast") or 0 if attr > 0 then ply.ChargingAirblast = true end end end if key == IN_JUMP then if ( IsValid( ply:GetPlayerItemBySlot(2) ) ) then if ( ( ply:GetPlayerItemBySlot(2):GetAttributeValue("wrench index") or 0 ) == 14 ) and ( ply.m_iAirDash ~= 0 ) then ply.m_iAirDash = 0 ply:TakeDamage({ Attacker = ply, DamageType = DMG_FALL, Damage = 15 }) end end end end) ply:AddCallback(ON_KEY_RELEASED, function(entity, key) if key == IN_ATTACK2 then ply.ChargingAirblast = false end end) end end function SetUpCallNetpropsBot( bot ) if bot and bot:IsValid() then bot.IgnitedByPower = false bot.ChainedTo = 0 end end function SetUpSharedCallBacks( player ) player:AddCallback(ON_DAMAGE_RECEIVED_PRE, function(ent, dmginfo) --kgb honorbound if ent:IsValid() and dmginfo.Attacker:IsValid() and ent:IsPlayer() and dmginfo.Attacker:IsPlayer() and ( ent ~= dmginfo.Attacker ) and ( ent.m_iTeamNum ~= 1 ) and ( dmginfo.Damage >= 20 ) then -- teamnum 1 is spectators local attacker = dmginfo.Attacker if ( ent.m_hActiveWeapon ) and ( ent.m_hActiveWeapon:IsValid() ) and ( ( ent.m_hActiveWeapon:GetItemName() == "The Killing Gloves of Boxing" ) and ( attacker.m_hActiveWeapon:GetItemName() == "The Killing Gloves of Boxing" ) ) and ( ( ent:GetPlayerItemBySlot(2):GetAttributeValue("honorbound") == 1 ) or ( attacker:GetPlayerItemBySlot(2):GetAttributeValue("honorbound") == 1 ) ) then if ent.m_bIsMiniBoss == 1 then dmginfo.Damage = 500 else dmginfo.Damage = ent.m_iHealth * 5 end if attacker:IsBot() and attacker.m_bIsMiniBoss == 0 then timer.Simple(0.2, function() attacker:Taunt("TAUNT_BASE_WEAPON", 0) end) end return true end end end) end function SetUpCallBacks( bot ) if bot and bot:IsValid() then bot:AddCallback( ON_DAMAGE_RECEIVED_PRE, function( ent, dmginfo ) --bfb dynamo if ( not dmginfo.Attacker ) or ( not dmginfo.Attacker:IsPlayer() ) then return end local attacker = dmginfo.Attacker local damage = dmginfo.Damage --raw damage, before any modifiers local weapon = dmginfo.Weapon if not dmginfo.Inflictor or (dmginfo.Inflictor == nil) or ( not IsValidPlayer(dmginfo.Inflictor ) ) then return end if weapon and ( weapon:GetItemName() == "Baby Face's Blaster" ) and ( ( weapon:GetAttributeValue("wrench index") or 0 ) == 4 ) then damage = damage * weapon:GetAttributeValueByClass("mult_dmg", 1) --make it scale with damage upgrades local mult = lerp( 0, 0.75, attacker.m_flHypeMeter / 99 ) --hype meter goes on a scale of 0-99 so I make it go on a 0-0.75 scale damage = damage * mult c_DMGInfo = { Damage = damage, Attacker = attacker, Weapon = nil, DamageType = dmginfo.DamageType, DamageCustom = dmginfo.DamageCustom, CritType = dmginfo.CritType } ent:TakeDamage( c_DMGInfo ) end end) bot:AddCallback( ON_DAMAGE_RECEIVED_PRE, function( ent, dmginfo, previousHealth ) if ( not dmginfo.Attacker ) or ( not dmginfo.Attacker:IsPlayer() ) then return end local attacker = dmginfo.Attacker local damage = dmginfo.Damage --raw damage, before any modifiers local weapon = dmginfo.Weapon if IsValid( attacker:GetPlayerItemBySlot(1) ) and ( ( attacker:GetPlayerItemBySlot(1):GetAttributeValue("wrench index") or 0 ) == 20 ) then if weapon ~= attacker:GetPlayerItemBySlot(1) then attacker:GetPlayerItemBySlot(1).m_flMinicritCharge = math.min( attacker:GetPlayerItemBySlot(1).m_flMinicritCharge + ( damage / 20 ), 100 ) end end end) bot:AddCallback( ON_DAMAGE_RECEIVED_PRE, function( ent, dmginfo, previousHealth ) if ( not dmginfo.Attacker ) or ( not dmginfo.Attacker:IsPlayer() ) then return end if ent:InCond( TF_COND_BLASTJUMPING ) then ent.BlastJumping = true else ent.BlastJumping = false end if ent:IsMidair() then local attacker = dmginfo.Attacker local wep = attacker:GetPlayerItemBySlot(1) if wep and ( IsValid(wep) ) then local attr = wep:GetAttributeValue("wrench index") or 0 if attr == 8 then ent.MidAir = true if dmginfo.CritType == 0 then dmginfo.CritType = 1 return true end end end else ent.MidAir = false end end) bot:AddCallback( ON_DAMAGE_RECEIVED_PRE, function( ent, dmginfo, previousHealth ) if ent:InCond( TF_COND_BURNING ) and ( ent.IgnitedByPower ) then dmginfo.Damage = dmginfo.Damage * 3 dmginfo.CritType = 2 return true end end) bot:AddCallback( ON_DAMAGE_RECEIVED_PRE, function( ent, dmginfo, previousHealth ) local damage = dmginfo.Damage --raw damage, before any modifiers local weapon = dmginfo.Weapon local inflictor = dmginfo.Inflictor if inflictor and inflictor:IsValid() and weapon and weapon:IsValid() then if ( inflictor:GetClassname() == "tf_projectile_pipe" ) and ( weapon:GetItemName() == "The Scottish Resistance" ) then if inflictor.Armed then dmginfo.Damage = dmginfo.Damage * 2 return true else dmginfo.Damage = dmginfo.Damage * 0.25 return true end end end end) bot:AddCallback( ON_DEATH, function( ent, dmginfo, previousHealth ) ent.IgnitedByPower = false ent.ChainedTo = 0 end) bot:AddCallback( ON_DAMAGE_RECEIVED_POST, function( ent, dmginfo, previousHealth ) if ( not dmginfo.Attacker ) or ( not dmginfo.Attacker:IsPlayer() ) then return end local cur_health = bot.m_iHealth local attacker = dmginfo.Attacker local weapon = dmginfo.Weapon local crit = dmginfo.CritType if not weapon or not attacker then return end local attr = weapon:GetAttributeValue("wrench index") or 0 if ( crit > 0 ) and ( ent.BlastJumping ) and ( attr == 6 ) then if 0 >= cur_health then ent.BlastJumping = false attacker:SetAttributeValue( "add cond when active", 19 ) attacker.RemoveBoost = CurTime() + 5 attacker:AddCond( TF_COND_SPEED_BOOST, 5 ) end end if ( ent.MidAir ) and ( attr == 8 ) then if 0 >= cur_health then ent.MidAir = false attacker:SetAttributeValue( "add cond when active", 19 ) attacker.RemoveBoost = CurTime() + 5 attacker:AddCond( TF_COND_SPEED_BOOST, 5 ) end end end) bot:AddCallback( ON_DAMAGE_RECEIVED_POST, function( ent, dmginfo, previousHealth ) local attacker, inflictor, crit = dmginfo.Attacker, dmginfo.Inflictor, dmginfo.CritType if (not IsValid(ent)) or ( not IsValid(attacker)) or ( not IsValid(inflictor) ) then return end local wep = attacker.m_hActiveWeapon if not IsValid(wep) then return end local wep_name = wep:GetItemName() if crit == 1 then -- 1 = minicrit if ( wep_name == "The Cow Mangler 5000" ) and ( tobool( inflictor.m_bChargedShot ) ) then if ( wep:GetAttributeValue("aiming movespeed increased") or 0 ) ~= 0 then local dmg = wep:GetAttributeValueByClass("mult_dmg", 1) if tobool( ent.m_bIsMiniBoss ) then ent:StunPlayer( 4 * dmg, lerp( 0.35, 0.65, dmg/2), TF_STUNFLAG_SLOWDOWN, attacker ) else ent:StunPlayer( 6 * dmg, 1, TF_STUNFLAGS_NORMALBONK, attacker ) end end end end end) bot:AddCallback( ON_DAMAGE_RECEIVED_PRE, function( ent, dmginfo ) --rocket pen fix for conch healing -- Ugly way to check for rocket penetrations if dmginfo.Inflictor == nil then return end if dmginfo.Attacker == nil then return end if dmginfo.Inflictor:GetClassname() ~= "tf_projectile_pipe" then return end if dmginfo.Weapon ~= nil then return end dmginfo.Weapon = dmginfo.Attacker:GetPlayerItemBySlot(LOADOUT_POSITION_PRIMARY) return true end) end end function ApplyBotEffects() for _, player in pairs(ents.GetAllPlayers()) do if player:IsBot() then if player:InCond( TF_COND_GAS ) then local provider = player:GetConditionProvider( TF_COND_GAS ) if provider:IsValid() then local wep = provider:GetPlayerItemBySlot(1) if wep and IsValid( wep ) then local attr = wep:GetAttributeValue( "applies snare effect" ) or 0 if provider:IsPlayer() and player:GetTeam() ~= provider:GetTeam() and ( attr ~= 0 ) then player:StunPlayer( 1, 1 - attr, TF_STUNFLAG_SLOWDOWN, provider ) end end end end end end end function ScreenText() for _, player in pairs(ents.GetAllPlayers()) do if player:IsRealPlayer() then local enabled = false local text = "" local type local wep if ( IsValid( player:GetPlayerItemBySlot(0) ) ) and ( player:GetPlayerItemBySlot(0):GetAttributeValue("Wrench index") or 0 ) == 3 then enabled = true type = 0 wep = player:GetPlayerItemBySlot(0) elseif ( IsValid( player:GetPlayerItemBySlot(1) ) ) and ( player:GetPlayerItemBySlot(1):GetAttributeValue("Wrench index") or 0 ) == 3 then enabled = true type = 1 wep = player:GetPlayerItemBySlot(1) elseif ( IsValid( player:GetPlayerItemBySlot(2) ) ) and ( player:GetPlayerItemBySlot(2):GetAttributeValue("Wrench index") or 0 ) == 3 then enabled = true type = 2 wep = player:GetPlayerItemBySlot(2) end if enabled then text = wep:GetAttributeValue("hidden string attribute 1") if CurTime() >= UpdateTimer then UpdateTimer = CurTime() + 0.1 if wep:GetItemName() == "The Back Scatter" or ( wep:GetItemName() == "The Gunslinger" ) then player:ShowHudText({channel = 5, y = 0.85, x = 0.70, r1 = 250, r2 = 250, g1 = player.Red, g2 = player.Red, b1 = player.Red, b2 = player.Red, effect = 0, fixTime = 0, fadeinTime = 0, fadeoutTime = 0, holdTime = 0.3}, tostring(text) .. tostring( player.StoredCrits ) ) end --print( wep:GetItemName() ) if wep:GetItemName() == "Sun-on-a-Stick" or wep:GetItemName() == "Sharpened Volcano Fragment" then player:ShowHudText({channel = 5, y = 0.85, x = 0.70, r1 = 250, r2 = 250, g1 = player.Red, g2 = player.Red, b1 = player.Red, b2 = player.Red, effect = 0, fixTime = 0, fadeinTime = 0, fadeoutTime = 0, holdTime = 0.3}, tostring(text) .. tostring( player.Heat / 100 ) .. "/5" ) end if ( wep:GetAttributeValue("charged airblast") or 0 ) ~= 0 and ( player.ChargeAirblastTimestamp ~= false ) then local attr = player:GetPlayerItemBySlot(0):GetAttributeValue("airblast pushback scale") or 1 local chargetime = player.ChargeAirblastTime - player.ChargeAirblastTimestamp or 0 local percent = math.min( math.round( ( chargetime / ( 3 / attr ) ) * 100, 1 ), 100 ) or 0 player:ShowHudText({channel = 5, y = 0.85, x = 0.70, r1 = 250, r2 = 250, g1 = player.Red, g2 = player.Red, b1 = player.Red, b2 = player.Red, effect = 0, fixTime = 0, fadeinTime = 0, fadeoutTime = 0, holdTime = 0.3}, tostring(text) .. tostring( percent ) .. "%" ) end end end end end end function PlayerLogic() for _, player in pairs(ents.GetAllPlayers()) do if player:IsRealPlayer() then if ( not player:IsMidair() ) and ( player.JumpsRest ) then player.JumpsRest = false end if ( IsValid( player:GetPlayerItemBySlot(1) ) ) then if ( player:GetPlayerItemBySlot(1):GetAttributeValue("wrench index") or 0 ) == 2 then if ( player:GetAttributeValue("fire input on hit") or 0 ) == 0 then player:SetAttributeValue("fire input on hit", "popscript^$RechargeCleaver^") end end if ( player:GetPlayerItemBySlot(1):GetAttributeValue("wrench index") or 0 ) == 13 then if ( player:GetAttributeValue("hidden maxhealth non buffed") or 0 ) == 50 then player:GetPlayerItemBySlot(1):SetAttributeValue( "hidden maxhealth non buffed", 100 ) else player:GetPlayerItemBySlot(1):SetAttributeValue( "hidden maxhealth non buffed", nil ) end end end if ( IsValid( player:GetPlayerItemBySlot(2) ) ) then if ( player:GetPlayerItemBySlot(2):GetAttributeValue("wrench index") or 0 ) == 22 then local bonus = lerp( 1, 1.7, math.max( ( player.m_iHealth - player.m_iMaxHealth ) / 140, 0 ) ) player:GetPlayerItemBySlot(2):SetAttributeValue( "dmg penalty vs players", bonus ) end if ( player:GetPlayerItemBySlot(2):GetAttributeValue("wrench index") or 0 ) == 23 then player:SetAttributeValue( "dmg taken increased", math.min( ( player:GetAttributeValue( "dmg taken increased" ) or 1 ) + 0.0008, 1 ) ) --print( player:GetAttributeValue( "dmg taken increased" ) ) end end if ( IsValid( player:GetPlayerItemBySlot(1) ) ) then if ( player:GetPlayerItemBySlot(1):GetAttributeValue("wrench index") or 0 ) == 9 then if ( player:GetAttributeValue("fire input on hit") or 0 ) == 0 then player:SetAttributeValue("fire input on hit", "popscript^$ResetChargeDrain^") end end end if ( IsValid( player:GetPlayerItemBySlot(0) ) ) and ( player.m_hActiveWeapon == player:GetPlayerItemBySlot(0) ) then if ( player.m_hActiveWeapon:GetAttributeValue("wrench index") or 0 ) == 15 then if IsValid( player.Buildings[1] ) then if ( ( player.Buildings[1].m_bPlayerControlled == 0 ) and ( player.Buildings[1].m_nShieldLevel == 1 ) ) or ( player.Buildings[1].m_bDisabled == 1 ) or ( player.Buildings[1].m_bPlasmaDisable == 1 ) then player:AddCond( TF_COND_CRITBOOSTED_CARD_EFFECT, 0.1 ) end end end end if ( IsValid( player:GetPlayerItemBySlot(1) ) ) then if ( player:GetPlayerItemBySlot(1):GetAttributeValue("wrench index") or 0 ) == 24 then if ( player:GetAttributeValue("fire input on hit") or 0 ) == 0 then player:SetAttributeValue("fire input on hit", "popscript^$RechargeSapper^") end end end if ( IsValid( player:GetPlayerItemBySlot(0) ) ) then if player:GetPlayerItemBySlot(0):GetItemName() == "The Rescue Ranger" then local value = ( 60 * player:GetPlayerItemBySlot(0):GetAttributeValueByClass("mult_medigun_healrate", 1) ) player:GetPlayerItemBySlot(0):SetAttributeValue( "arrow heals buildings", value ) end if ( ( player:GetPlayerItemBySlot(0):GetAttributeValue("wrench index") or 1 ) / 17 ) == math.floor( ( player:GetPlayerItemBySlot(0):GetAttributeValue("wrench index") or 0 ) / 17 ) then local maxcount = player:GetPlayerItemBySlot(0):GetAttributeValue("tool escrow until date") or 1 if player:GetPlayerItemBySlot(0).m_flChargedDamage < 1 then player.ChargeLoopCounter = 0 end player:GetPlayerItemBySlot(0):SetAttributeValue( "damage bonus HIDDEN", math.max( ( player.ChargeLoopCounter * 3 ), 1 ) ) if ( player:GetPlayerItemBySlot(0).m_flChargedDamage >= 150 ) and ( player.ChargeLoopCounter < maxcount ) then player:GetPlayerItemBySlot(0).m_flChargedDamage = 1 player.ChargeLoopCounter = player.ChargeLoopCounter + 1 end end if ( player:GetPlayerItemBySlot(0):GetAttributeValue("wrench index") or 0 ) == 18 then if ( player:GetPlayerItemBySlot(0).m_flChargedDamage < 150 ) then player:GetPlayerItemBySlot(0):SetAttributeValue( "crits_become_minicrits", 1 ) else player:GetPlayerItemBySlot(0):SetAttributeValue( "crits_become_minicrits", nil ) end end if ( player:GetPlayerItemBySlot(0):GetAttributeValue("wrench index") or 0 ) == 19 then if ( player:GetPlayerItemBySlot(0).m_flChargedDamage > 0 ) then player.OldCharge = player:GetPlayerItemBySlot(0).m_flChargedDamage if player.Missed then player:GetPlayerItemBySlot(0).m_flChargedDamage = ( 150 ) - ( 150 * player:GetPlayerItemBySlot(0):GetAttributeValueByClass("mult_sniper_charge_after_miss", 1 ) ) player.Missed = false elseif player.HeadShot then player:GetPlayerItemBySlot(0).m_flChargedDamage = ( 150 ) - ( 150 * player:GetPlayerItemBySlot(0):GetAttributeValueByClass("mult_sniper_charge_after_headshot", 1 ) ) player.HeadShot = false end end end if ( player:GetPlayerItemBySlot(0):GetAttributeValue("wrench index") or 0 ) == 21 then local charge = player:GetPlayerItemBySlot(0).m_flChargedDamage if charge > 0 then player:GetPlayerItemBySlot(0):SetAttributeValue( "mult bleeding dmg", lerp( 1, 1.6, (math.max( charge - 50, 0 ) / 100 ) ) ) else player:GetPlayerItemBySlot(0):SetAttributeValue( "mult bleeding dmg", nil ) end end end if (player.m_iTeamNum ~= 1) then if ( IsValidAlivePlayer( player ) ) and ( IsValid( player:GetPlayerItemBySlot(1) ) ) and ( ( player:GetPlayerItemBySlot(1):GetAttributeValue("wrench index") or 0 ) == 16 ) then if player:InCond( TF_COND_MEDIGUN_UBER_BULLET_RESIST ) then player:AddCond( TF_COND_INVULNERABLE_CARD_EFFECT, 0.1, player ) end if player:InCond( TF_COND_MEDIGUN_UBER_BLAST_RESIST ) then player:AddCond( TF_COND_CRITBOOSTED_CARD_EFFECT, 0.1, player ) end if player:InCond( TF_COND_MEDIGUN_UBER_FIRE_RESIST ) then player:AddCond( TF_COND_HALLOWEEN_QUICK_HEAL, 0.1, player ) end if player:InCond( TF_COND_HALLOWEEN_QUICK_HEAL ) then player:SetAttributeValue("healing received bonus", 3) player:SetAttributeValue("heal rate bonus", 3) else player:SetAttributeValue("healing received bonus", nil) player:SetAttributeValue("heal rate bonus", nil) if player.InUber == true then player:SetAttributeValue("hud overlay", nil) player.InUber = false end end player:SetAttributeValue("uber duration bonus", -0.5) end if ( IsValidAlivePlayer( player ) ) then if ( player:InCond( TF_COND_MEDIGUN_UBER_BULLET_RESIST ) ) then local provider = player:GetConditionProvider( TF_COND_MEDIGUN_UBER_BULLET_RESIST ) if ( provider:IsValid() ) and ( player ~= provider ) and ( IsValid( provider:GetPlayerItemBySlot(1) ) ) and ( ( player:GetPlayerItemBySlot(1):GetAttributeValue("wrench index") or 0 ) == 16 ) then player:AddCond( TF_COND_INVULNERABLE_CARD_EFFECT, 0.1, provider ) end end if ( player:InCond( TF_COND_MEDIGUN_UBER_BLAST_RESIST ) ) then local provider = player:GetConditionProvider( TF_COND_MEDIGUN_UBER_BLAST_RESIST ) if ( provider:IsValid() ) and ( player ~= provider ) and ( IsValid( provider:GetPlayerItemBySlot(1) ) ) and ( ( player:GetPlayerItemBySlot(1):GetAttributeValue("wrench index") or 0 ) == 16 ) then player:AddCond( TF_COND_CRITBOOSTED_CARD_EFFECT, 0.1, provider ) end end if ( player:InCond( TF_COND_MEDIGUN_UBER_FIRE_RESIST ) ) then local provider = player:GetConditionProvider( TF_COND_MEDIGUN_UBER_FIRE_RESIST ) if ( provider:IsValid() ) and ( player ~= provider ) and ( IsValid( provider:GetPlayerItemBySlot(1) ) ) and ( ( player:GetPlayerItemBySlot(1):GetAttributeValue("wrench index") or 0 ) == 16 ) then player:AddCond( TF_COND_MEGAHEAL, 0.1, provider ) end end end if ( IsValidAlivePlayer( player ) ) and ( ( IsValid( player:GetPlayerItemBySlot(1) ) ) and ( ( player:GetPlayerItemBySlot(1):GetAttributeValue("wrench index") or 0 ) ~= 16 ) ) then player:SetAttributeValue("uber duration bonus", nil) end end if player.RemoveBoost ~= false and ( CurTime() >= player.RemoveBoost ) then player.RemoveBoost = false player:SetAttributeValue( "add cond when active", nil ) end if player:InCond(81) and ( not player:IsMidair() ) then player:RemoveCond(81) player:SetAttributeValue( "fire rate bonus", nil ) player:SetAttributeValue( "blast radius decreased", nil ) end if player.ChargingAirblast then if player.ChargeAirblastTimestamp == false then player.ChargeAirblastTimestamp = CurTime() end player.ChargeAirblastTime = CurTime() + 0.1 local attr = player:GetPlayerItemBySlot(0):GetAttributeValue("airblast pushback scale") or 1 local chargetime = player.ChargeAirblastTime - player.ChargeAirblastTimestamp local percent = math.min( chargetime / ( 3 / attr ), 1 ) local max_charge = lerp( 3, 1.5, ( attr ) - 1 / 1 ) if player.ChargeAirblastTime > CurTime() then player:SetAttributeValue( "airblast pushback scale", lerp( 1, max_charge, percent ) ) player:SetAttributeValue( "mult reflect velocity", lerp( 1, 3, percent ) ) end else player:SetAttributeValue( "airblast pushback scale", nil ) player:SetAttributeValue( "mult reflect velocity", nil ) player.ChargeAirblastTimestamp = false end if player:InCond( TF_COND_SHIELD_CHARGE ) then if ( IsValid( player:GetPlayerItemBySlot(1) ) ) and ( ( player:GetPlayerItemBySlot(1):GetAttributeValue("wrench index") or 0 ) == 9 ) then player:SetAttributeValue("displace touched enemies", 10) if player.TrainTimestamp == false then player.TrainTimestamp = CurTime() end player.TrainTime = CurTime() local ChargeTime = player.TrainTime local TimeForMinCharge = player.TrainTimestamp + 3 local MaxChargeDur = 10 local MinChargeDur = 0.5 local Charge = lerp( MaxChargeDur, MinChargeDur, math.clamp( ( ChargeTime - player.TrainTimestamp ) / ( TimeForMinCharge - player.TrainTimestamp ), 0, 1 ) ) if player.m_hActiveWeapon == player:GetPlayerItemBySlot(2) then if player.m_flChargeMeter > 33 and ( player.m_flChargeMeter <= 75 ) then player:AddCond(19, 0.1) elseif player.m_flChargeMeter <= 33 then player:AddCond(56, 0.1) end end player:SetAttributeValue( "charge time increased", Charge ) end if ( IsValid( player:GetPlayerItemBySlot(1) ) ) and ( ( player:GetPlayerItemBySlot(1):GetAttributeValue("wrench index") or 0 ) == 10 ) then if player.TrainTimestamp == false then player.TrainTimestamp = CurTime() player.ParryEndTime = CurTime() + ( 1 + ( player:GetAttributeValueByClass("mod_charge_time", 0.5 ) ) ) player:SetAttributeValue("mult_dmgtaken_active", 0.25) end if CurTime() >= player.ParryEndTime then player.TrainTimestamp = false player:SetAttributeValue("mult_dmgtaken_active", nil) end end if ( IsValid( player:GetPlayerItemBySlot(0) ) ) and ( ( player:GetPlayerItemBySlot(0):GetAttributeValue("wrench index") or 0 ) == 11 ) then player:SetAttributeValue( "reload time decreased", 0.5 ) player:SetAttributeValue( "fire rate bonus", 0.5 ) end else player.TrainTimestamp = false if ( IsValid( player:GetPlayerItemBySlot(1) ) ) and ( ( player:GetPlayerItemBySlot(1):GetAttributeValue("wrench index") or 0 ) == 9 ) then player:SetAttributeValue( "charge time increased", 10 ) --just in case player:SetAttributeValue("displace touched enemies", nil) player:RemoveCond(19) player:RemoveCond(56) else player:SetAttributeValue( "charge time increased", nil ) end if ( IsValid( player:GetPlayerItemBySlot(0) ) ) and ( ( player:GetPlayerItemBySlot(0):GetAttributeValue("wrench index") or 0 ) == 11 ) then player:SetAttributeValue( "reload time decreased", nil ) player:SetAttributeValue( "fire rate bonus", nil ) end if CurTime() >= player.ParryEndTime then player.TrainTimestamp = false player:SetAttributeValue("mult_dmgtaken_active", nil) end end end end end -- function CleaverRechargeLogic() -- for _, player in pairs(ents.GetAllPlayers()) do -- if player:IsRealPlayer() then -- if ( IsValid( player:GetPlayerItemBySlot(1) ) ) then -- if ( player:GetPlayerItemBySlot(1):GetAttributeValue("wrench index") or 0 ) == 2 then -- if ( player:GetPlayerItemBySlot(1):GetAttributeValue("fire input on hit") or 0 ) == 0 then -- player:SetAttributeValue("fire input on hit", "popscript^$RechargeCleaver^") -- end -- end -- end -- end -- end -- end -- function OnPlayerHurt( victim, attacker, damage, victim_health, crit, minicrit ) -- if victim == nil or attacker == nil then return end -- local wep = attacker.m_hActiveWeapon -- if not IsValid(wep) then return end -- local wep_name = wep:GetItemName() -- if tobool( minicrit ) then -- if wep and ( wep_name == "The Cow Mangler 5000" ) then -- if ( wep:GetAttributeValue("aiming movespeed increased") or 0 ) ~= 0 then -- local dmg = wep:GetAttributeValueByClass("mult_dmg", 1) -- if tobool( victim.m_bIsMiniBoss ) then -- victim:StunPlayer( 4 * dmg, lerp( 0.75, 0.9, dmg/2), TF_STUNFLAG_SLOWDOWN, attacker ) -- else -- victim:StunPlayer( 6 * dmg, 1, TF_STUNFLAGS_NORMALBONK, attacker ) -- end -- end -- end -- end -- end -- function PlayerHurt( event_table ) -- local userid = event_table.userid -- local victim = ents.GetPlayerByUserId( userid ) -- local victim_health = event_table.health -- local attacker = ents.GetPlayerByUserId(event_table.attacker) -- local damage = event_table.damageamount -- local crit = event_table.crit -- local minicrit = event_table.minicrit -- local weapon = ents.FindByNetIndex( event_table.weaponid ) -- if IsValidFunction( OnPlayerHurt ) and ( victim ) and ( victim:IsValid() ) and ( victim ~= nil ) then -- OnPlayerHurt(victim, attacker, damage, victim_health, crit, minicrit) -- end -- end -- AddEventCallback("player_hurt", PlayerHurt) function EMPBots( duration, activator, caller ) duration = tonumber( duration ) for _, bot in pairs( ents.FindInSphere( activator:GetAbsOrigin(), 250 ) ) do if bot:IsPlayer() and IsValid( bot ) and ( bot:GetTeam() ~= activator:GetTeam() ) and ( bot ~= activator ) and ( bot ~= caller ) and ( not bot:OnTeam( 1 ) ) then bot.OldSkill = bot.m_nBotSkill bot:RunScriptCode(BOT_SET_SKILL_EASY, bot, bot) local EMPFX = ents.CreateWithKeys("info_particle_system", { effect_name = "medic_resist_bullet", start_active = 1, flag_as_weather = 0, }, true, true) EMPFX:SetAbsOrigin(bot:GetAbsOrigin()) EMPFX:Start() EMPFX:AcceptInput("SetParent", "!activator", bot, nil) bot.EMPTimer = timer.Create( duration, function() EMPFX:Remove() if IsValid( bot ) and bot:IsAlive() and ( not bot:OnTeam( 1 ) ) then if bot.OldSkill == 1 then bot:RunScriptCode(BOT_SET_SKILL_NORMAL, bot, bot) elseif bot.OldSkill == 2 then bot:RunScriptCode(BOT_SET_SKILL_HARD, bot, bot) elseif bot.OldSkill == 3 then bot:RunScriptCode(BOT_SET_SKILL_EXPERT, bot, bot) end end end, 1 ) end end end function BazaarShoot( projectile, activator, weapon ) util.StartLagCompensation( activator ) local trace = util.Trace({ start = activator:GetEyePos(), distance = 8192, angles = activator:GetEyeAngles(), mask = MASK_SHOT, filter = ents.GetAllRealPlayers() }) util.FinishLagCompensation( activator ) if trace.Entity:IsWorld() and ( activator:InCond( TF_COND_AIMING ) ) then activator.Missed = true else activator.Missed = false activator.HeadShot = false end if trace.HitGroup == HITGROUP_HEAD and ( activator:InCond( TF_COND_AIMING ) ) then activator.HeadShot = true else activator.HeadShot = false end end function BazaarHit( damage, activator, caller ) if not caller:IsPlayer() then return end local check_dmg = math.max( 50, math.ceil( activator.OldCharge ) ) * activator:GetPlayerItemBySlot(0):GetAttributeValueByClass( "mult_dmg", 1 ) if caller:InCond( TF_COND_DEFENSEBUFF_NO_CRIT_BLOCK ) then check_dmg = check_dmg * 0.65 end if caller:InCond( TF_COND_URINE ) then check_dmg = check_dmg * 1.35 end if activator:InCond( TF_COND_OFFENSEBUFF ) then check_dmg = check_dmg * 1.35 end if activator:InCond( TF_COND_ENERGY_BUFF ) then check_dmg = check_dmg * 1.35 end if caller:IsAlive() and ( IsValid( caller.m_hActiveWeapon ) ) and( caller.m_hActiveWeapon:GetItemName() == "Fists of Steel" ) then check_dmg = check_dmg * 0.6 end if caller:InCond( TF_COND_DEFENSEBUFF ) then check_dmg = 69420 end check_dmg = check_dmg + 5 if damage and activator.Missed and ( activator:InCond( TF_COND_AIMING ) ) then activator.Missed = false end if ( not activator.HeadShot ) and ( activator:InCond( TF_COND_AIMING ) ) then if damage > check_dmg then activator.HeadShot = true end end end function AddHealth( health, activator, caller ) local attr = activator:GetAttributeValue( "SET BONUS: max health additive bonus" ) or 0 activator:SetAttributeValue( "SET BONUS: max health additive bonus", math.min( attr + health, 60 ) ) end function RadialCond( taunt, activator, _ ) local info = activator:GetPlayerItemBySlot(2):GetAttributeValue("hidden string attribute 1") or "5|256|10" local filter = activator:GetPlayerItemBySlot(2):GetAttributeValue("hidden string attribute 2") or nil local _, _, cond, radius, duration = string.find( info, "(%d+)|(%d+)|(%d+)" ) if taunt ~= filter then return end for _, player in pairs( ents.FindInSphere( activator:GetAbsOrigin(), radius, "player" ) ) do if IsValidAlivePlayer( player ) and ( player:GetTeam() == activator:GetTeam() ) then player:AddCond( cond, duration ) end end end function AddResistance( info, activator, caller ) local _, _, res, max = string.find( info, "(%d+)|(%d+)" ) res, max = tonumber( res / 100 ), tonumber( max / 100 ) activator:SetAttributeValue( "dmg taken increased", math.max( ( activator:GetAttributeValue( "dmg taken increased" ) or 1 ) - res, max ) ) end local buildings = { obj_sentrygun = 1, obj_dispenser = 2, obj_teleporter = 3 } function OnBuildingCreated(entity, classname) timer.Simple( 0.1, function() if entity:IsValid() then local ply = entity:GetBuilder() local primary = ply:GetPlayerItemBySlot( 0 ) local melee = ply:GetPlayerItemBySlot( 2 ) ply.Buildings[ buildings[classname] ] = entity entity.BuiltWith = ply:GetPlayerItemBySlot( 1 ) if ( ( melee:GetAttributeValue( "wrench index" ) or 0 ) == 26 ) and ( tostring(classname) == "obj_sentrygun" ) then entity.m_iHighestUpgradeLevel = 2 end if ( ( melee:GetAttributeValue( "wrench index" ) or 0 ) == 27 ) then entity.m_iHighestUpgradeLevel = 2 end if ( ( primary:GetAttributeValue( "wrench index" ) or 0 ) == 28 ) then entity.m_iUpgradeMetalRequired = entity.m_iUpgradeMetalRequired - 50 end end end) end for ent, _ in pairs(buildings) do ents.AddCreateCallback(ent, OnBuildingCreated) end function SecondLife( taunt, activator, _ ) if ((not IsValid(activator) ) or ( not activator:IsAlive() )) then return end if taunt == "scenes/player/heavy/low/taunt04.vcd" then timer.Simple(1.2, function() for _, reanimator in pairs(ents.FindInSphere(activator:GetAbsOrigin(), 200)) do if reanimator:GetClassname() == "entity_revive_marker" then --if reanimator:HasLineOfSight( activator ) then reanimator.m_hOwner:ForceRespawnDead() reanimator.m_hOwner:PlaySoundToSelf( "mvm/mvm_revive.wav" ) reanimator.m_hOwner:SpeakResponseConcept( "TLK_RESURRECTED" ) reanimator.m_hOwner:Teleport( activator:GetAbsOrigin() ) reanimator.m_hOwner:AddCond( 51, 2 ) reanimator.m_hOwner.m_flItemChargeMeter[2] = 50 --start lunchbox items at 50% charge, to avoid chain bananas activator:PlaySoundToSelf( "mvm/mvm_revive.wav" ) activator.m_flItemChargeMeter[2] = 0 activator:StunPlayer( 0.2, 1, TF_STUNFLAG_BONKSTUCK ) activator.m_iHealth = math.min( activator.m_iHealth + 50, activator.m_iMaxHealth ) --end end end end) end end local RAGE_DURATION = 10 local UPDATE_INTERVAL = 0.015 local knockbackHandles = {} local RAGE_OVERRIDES_APPLY = { ["throwable fire speed"] = function(activator) activator:GetPlayerItemBySlot(LOADOUT_POSITION_PRIMARY):SetAttributeValue("heal on hit for rapidfire", 5) end } local RAGE_OVERRIDES_REMOVE = { ["throwable fire speed"] = function(activator) activator:GetPlayerItemBySlot(LOADOUT_POSITION_PRIMARY):SetAttributeValue("heal on hit for rapidfire", nil) end } local function applyKnockbackRageEffect(activator) for attr, func in pairs(RAGE_OVERRIDES_APPLY) do --print( 'adding ', attr, activator:GetPlayerItemBySlot(LOADOUT_POSITION_PRIMARY):GetAttributeValue(attr) ) if activator:GetPlayerItemBySlot(LOADOUT_POSITION_PRIMARY):GetAttributeValue(attr) then func(activator) break end end end local function removeKnockbackRageEffect(activator) for attr, func in pairs(RAGE_OVERRIDES_REMOVE) do --print( 'removing ', attr, activator:GetPlayerItemBySlot(LOADOUT_POSITION_PRIMARY):GetAttributeValue(attr) ) if activator:GetPlayerItemBySlot(LOADOUT_POSITION_PRIMARY):GetAttributeValue(attr) then func(activator) break end end end function KnockbackRageStart(_, activator) --print( activator ) local handleIndex = activator:GetHandleIndex() local draining = false local fakeMeter = 0 local meterLerp = 0 knockbackHandles[handleIndex] = timer.Create(UPDATE_INTERVAL, function () if not IsValid(activator) then KnockbackRageStop(nil, nil, handleIndex) return end if draining then -- fakeMeter = math.max(fakeMeter - (UPDATE_INTERVAL * RAGE_DURATION) * 10, 0) meterLerp = meterLerp + (UPDATE_INTERVAL / RAGE_DURATION * 2) fakeMeter = math.max(100 - lerp(0, 100, meterLerp), 0) activator:SetFakeSendProp("m_flRageMeter", fakeMeter) if fakeMeter <= 0 then activator:GetPlayerItemBySlot(LOADOUT_POSITION_PRIMARY):SetAttributeValue("increase buff duration HIDDEN", nil) activator:ResetFakeSendProp("m_bRageDraining") activator:ResetFakeSendProp("m_flRageMeter") activator.m_flRageMeter = 0 fakeMeter = 0 meterLerp = 0 draining = false removeKnockbackRageEffect(activator) end return end if activator.m_bRageDraining == 0 then return end activator:GetPlayerItemBySlot(LOADOUT_POSITION_PRIMARY):SetAttributeValue("increase buff duration HIDDEN", 100) activator:SetFakeSendProp("m_bRageDraining", 1) activator.m_bRageDraining = 0 activator.m_flRageMeter = -100000 fakeMeter = 100 meterLerp = 0 draining = true applyKnockbackRageEffect(activator) end, 0) end function KnockbackRageStop(_, activator, handle) if activator then activator:ResetFakeSendProp("m_bRageDraining") activator:ResetFakeSendProp("m_flRageMeter") end local handleIndex = handle or activator:GetHandleIndex() pcall(timer.Stop, knockbackHandles[handleIndex]); knockbackHandles[handleIndex] = nil end