-- the stuff below is made by Royal -- they deserve a LOT of kudos for everything here --local deathCounts = {} local soloMode = false -- solo runs local soloist_uid = nil local waveActive = false local extraMoneyMode = false local infMoneyMode = false -- the timo648 special local betaMode = false -- the divine_delusions_beta_test special local waveCount = 0 local joinedIn = {} local hypercd = 60 local invscd = 30 local hyper_cd_player = {} local invs_cd_player = {} local player_kill_count = {} -- local player_taunt_speed = {} local waveMoneyEarned = {} local totalMoneyEarned = {} local waveKills = {} local player_total_kill = {} local playerPurchased = {} local playerBonuses = {} local playerDynamicWeight = {} local playerLastBonus = {} local playerExtraLuckyChances = {} local playerCashback = {} local playerCurrentCash = {} local playerWeakenedMannpower = {} local playerMannpower = {} local cooldownTableCountdown = {} local function round(num) return math.floor(num + 0.5) -- Rounds to the nearest integer end -- '[cur] aerumnosae?' / -- '[cui] aerumnosae?' / -- 'cur lacrimosae?' / -- 'cui lacrimosae?' // -- luna, claras terras lustra (assurge, o luna etsi tantum manent dura) / -- sicut aves per umbras vola (corda nostra premunt obscura, purdoque manet) / -- et unda vasta foeda purga (sed luna ascendet, nec cora peribunt una) / -- pro turba fida spem crastinam serva (audies fremitus undae, postea venient gaudia) // -- a luna nova, surgat luna pura casta / -- fugio aerumnam, tecum nulla fleta // -- sub luna rursus fiet clara terra local moonPhaseNames = {"New Moon", "Waxing Crescent", "First Quarter", "Waxing Gibbous", "Full Moon", "Waning Gibbous", "Last Quarter", "Waning Crescent"} local prev_new_moon = os.time({year = 2026, month = 1, day = 19, hour = 3, minute = 51}) -- based on utc+8, which is the same timezone as SGP servers and the philippines (sorry US players lmao) local lunarCycle = 29.3059 * 24 * 3600 -- 29.3059 is the average number of days in the lunar cycle, 24 is the number of hours in a full day, 3600 is the number of seconds that comprise a full hour -- (this will be used for a set of custom items) local function moonPhase() local phaseThreshold = 0.0625 -- this function will input all 8 known phases, and based on my calculations (read: delusions) this is the best compromise possible local today = os.time() local secondsIntoCycle = today - prev_new_moon local currentMoonAge = secondsIntoCycle % lunarCycle local lunarCycleLevel = currentMoonAge / lunarCycle local moonPhases = { -- my biggest pet peeve in lua is that its starting index is 1 which confuses my 0-starting ass [0.0] = 1, [0.125] = 2, [0.25] = 3, [0.375] = 4, [0.5] = 5, [0.625] = 6, [0.75] = 7, [0.875] = 8 } for phaseLevel, returnValue in pairs(moonPhases) do -- the pairs function shits out the k-vs in a random order but that doesn't matter here local minLevel = phaseLevel - phaseThreshold -- exclusive local maxLevel = phaseLevel + phaseThreshold -- inclusive if phaseLevel == 0 then -- new moon is weird lmao minLevel = 1 - phaseThreshold if lunarCycleLevel > minLevel or lunarCycleLevel <= maxLevel then return 1 end else if lunarCycleLevel > minLevel and lunarCycleLevel <= maxLevel then return returnValue end end end return 1 -- default to 1 a.k.a. new moon, otherwise the game's gonna panic hard end local function cooldownCountdown(handle, actionName) if cooldownTableCountdown[handle][actionName] == nil then return end if cooldownTableCountdown[handle][actionName] > 0 then cooldownTableCountdown[handle][actionName] = cooldownTableCountdown[handle][actionName] - 1 timer.Simple(1, function() cooldownCountdown(handle, actionName) end) end end local function spahtext(actionName) if actionName == "hyperjump" then return "Hyperjump" elseif actionName == "invis" then return "Invisibility" else -- fallback that should be impossible to occur, so for it to happen means something is very wrong return "Special Ability" end end local function applyCooldown(player, cooldownTable, cooldownDuration, action, actionName) local handle = player:GetHandleIndex() cooldownTableCountdown[handle] = cooldownTableCountdown[handle] or {} if cooldownTable[handle] then local cd = cooldownTableCountdown[handle][actionName] or 0 local act = spahtext(actionName) if player.m_iClass == 8 then player:Print(1, act .. " is on cooldown for " .. cd .. " seconds.") end return end cooldownTable[handle] = true cooldownTableCountdown[handle][actionName] = cooldownDuration timer.Simple(cooldownDuration + 0.01, function() cooldownTable[handle] = nil local act = spahtext(actionName) if player.m_iClass == 8 then player:Print(1, act .. "'s cooldown has been refreshed.") end end) timer.Simple(1, function() cooldownCountdown(handle, actionName) end) if player.m_iClass == 8 then player:Print(1, spahtext(actionName) .. " activated.") end action(player) end local function perform_hyper(player) local angle = Vector(100, 0, 500) player:SetForwardVelocity(2000) player:AddOutput("BaseVelocity " .. tostring(angle)) end local function perform_invs(player) player:AddCond(64, 5) end --function OnPlayerConnected(player) -- local handle = player:GetHandleIndex() -- -- deathCounts[handle] = 0 -- -- player:AddCallback(ON_DEATH, function() -- deathCounts[handle] = deathCounts[handle] + 1 -- end) --end --function OnPlayerDisconnected(player) -- deathCounts[player:GetHandleIndex()] = nil --end function OnPlayerDisconnected(player) if player:IsRealPlayer() then local playerSteamId = player:GetSteamId() local i = 1 if waveCount <= 5 then -- while it's still early, remove them from the list if they leave, they might change their minds later for _, savedSteamId in ipairs(joinedIn) do if savedSteamId == playerSteamId then table.remove(joinedIn, i) break else i = i + 1 end end end end end function OnWaveInit() waveActive = false DoublePointsText = "" FireSaleText = "" InstakillText = "" DoublePointsDuration = 0 FireSaleDuration = 0 InstakillDuration = 0 --DumpsterCost = 950 ents.FindByName("lobby_music"):AcceptInput("StopSound") ents.FindByName("lobby_music"):AcceptInput("Volume", 0) end --function OnWaveStart() -- waveActive = true --end function ActivateExtraMoneyMode() extraMoneyMode = true end function ActivateInfMoneyMode() infMoneyMode = true end function ActivateDebugMode() betaMode = true end function rejuvenatorHit(damage, activator, caller) local damageThreshold = 1 local curHealth = caller.m_iHealth local immuneToRevBullshit = { -- bosses and mutants, do i need to elaborate further ["Mutant Zombie"] = true, ["Mutant Grappler Zombie"] = true, ["Mutant Burning Man"] = true, ["Mutant Corroder Zombie"] = true, ["Mutant Crawler Zombie"] = true, ["Mutant Tiny Desk"] = true, ["Mutant Mad Scientist"] = true, ["Mutant Camouflage Zombie"] = true, ["Mutant Bruiser Zombie"] = true, ["Mutant Infectious Zombie"] = true, ["Mutant Tank"] = true, ["Giant Treadonator"] = true, ["Giant Battlelord"] = true, ["Giant Corrupted"] = true, -- these guys are just built different i suppose ["Tank"] = true, ["Screamer Zombie"] = true, ["Tiny Desk Zombie"] = true, ["Tomb Detonator"] = true } print("zombie health:", curHealth) print("damage:", damage) print("curhealth > 0:", curHealth > 0) if curHealth > 1 then return end if not immuneToRevBullshit[caller.m_szNetname] then caller.m_iHealth = 2000 caller:AddCond(43, 11, activator) -- reprogrammed condition caller:AddCond(18, 11, activator) -- visual effect caller:AddCond(16, 11, activator) -- buffban effect caller:AddCond(26, 11, activator) -- battback effect caller:AddCond(29, 11, activator) -- conch effect caller:AddCond(72, 11, activator) -- whatever this is caller:AddCond(113, 11, activator) -- king effect without the powerup (hopefully) caller:AddCond(114, 11, activator) -- le glow caller:AddCond(32, 11, activator) -- ??? caller:AddCond(51, 3, activator) -- 3s uber on teamswap resurrection caller:AddCond(130, 11, activator) -- ??? caller:SetAttributeValue("dmg penalty vs players", 8) timer.Simple(10, function() caller:Suicide() end) end end function jenovaShenanigans(damage, activator, caller) local damageThreshold = 1 local curHealth = caller.m_iHealth local immuneToRevBullshit = { -- bosses and mutants, do i need to elaborate further ["Mutant Zombie"] = true, ["Mutant Grappler Zombie"] = true, ["Mutant Burning Man"] = true, ["Mutant Corroder Zombie"] = true, ["Mutant Crawler Zombie"] = true, ["Mutant Tiny Desk"] = true, ["Mutant Mad Scientist"] = true, ["Mutant Camouflage Zombie"] = true, ["Mutant Bruiser Zombie"] = true, ["Mutant Infectious Zombie"] = true, ["Mutant Tank"] = true, ["Giant Treadonator"] = true, ["Giant Battlelord"] = true, ["Giant Corrupted"] = true, -- these guys are just built different i suppose ["Tank"] = true, ["Screamer Zombie"] = true, ["Tiny Desk Zombie"] = true, ["Tomb Detonator"] = true } if immuneToRevBullshit[caller.m_szNetname] then return end print("zombie health:", curHealth) print("damage:", damage) print("curhealth > 0:", curHealth > 0) if curHealth > 1 then caller:AddCond(43, 6, activator) -- reprogrammed condition caller:AddCond(18, 6, activator) -- visual effect caller:AddCond(16, 6, activator) -- buffban effect caller:AddCond(26, 6, activator) -- battback effect caller:AddCond(29, 6, activator) -- conch effect caller:AddCond(72, 6, activator) -- whatever this is caller:AddCond(113, 6, activator) -- king effect without the powerup (hopefully) caller:AddCond(32, 6, activator) -- ??? caller:AddCond(51, 1.75, activator) -- 3s uber on teamswap resurrection caller:AddCond(130, 6, activator) -- ??? caller:SetAttributeValue("dmg penalty vs players", 8) timer.Simple(5, function() caller:SetAttributeValue("dmg penalty vs players", nil) end) return end if not immuneToRevBullshit[caller.m_szNetname] then caller.m_iHealth = 2000 caller:AddCond(43, 11, activator) -- reprogrammed condition caller:AddCond(18, 11, activator) -- visual effect caller:AddCond(16, 11, activator) -- buffban effect caller:AddCond(26, 11, activator) -- battback effect caller:AddCond(29, 11, activator) -- conch effect caller:AddCond(72, 11, activator) -- whatever this is caller:AddCond(113, 11, activator) -- king effect without the powerup (hopefully) caller:AddCond(114, 11, activator) -- le glow caller:AddCond(32, 11, activator) -- ??? caller:AddCond(51, 3, activator) -- 3s uber on teamswap resurrection caller:AddCond(130, 11, activator) -- ??? caller:SetAttributeValue("dmg penalty vs players", 8) timer.Simple(10, function() caller:Suicide() end) end end function glowOnHit(damage, activator, caller) if caller:IsAlive() and caller.m_iTeamNum == 3 then local glow_yellow = ents.CreateWithKeys("tf_glow", { GlowColor = "255 255 0 255", target = "bignet", targetname = "bot_glow", startdisabled = 0, mode = 0, }, true, true) glow_yellow.m_hTarget = caller local glowRemovalTimer = timer.Simple(10, function() if glow_yellow and glow_yellow:IsValid() then glow_yellow:Remove() end end) caller:AddCallback(ON_DEATH, function() if glow_yellow and glow_yellow:IsValid() then glow_yellow:Remove() timer:Remove(glowRemovalTimer) end end) end end function snatcherHit(damage, activator, caller) if not caller:IsAlive() or not activator:IsAlive() or caller.m_iTeamNum ~= 2 then return end if caller:InCond(5) == true or caller:InCond(51) == true or caller:InCond(52) == true then return end -- don't apply effect to ubercharged players local conditions = {90, 92, 93, 91, 97, 96, 95, 94, 103, 109, 110} for _, cond in ipairs(conditions) do if activator:InCond(cond) == true then return end if caller:InCond(cond) == true then activator:AddCond(cond) caller:RemoveCond(cond) break end end end function mutSnatcherHit(damage, activator, caller) -- ehe~ if not caller:IsAlive() or not activator:IsAlive() or caller.m_iTeamNum ~= 2 then return end if caller:InCond(5) == true or caller:InCond(51) == true or caller:InCond(52) == true then return end -- don't apply effect to ubercharged players activator.mutSnatched = activator.mutSnatched or {} local conditions = {90, 92, 93, 91, 97, 96, 95, 94, 103, 109, 110} for _, cond in ipairs(conditions) do if activator:InCond(cond) == true then for _, snatched in ipairs(activator.mutSnatched) do if activator:InCond(snatched) then return end end end if caller:InCond(cond) == true then table.insert(activator.mutSnatched, cond) activator:AddCond(cond) caller:RemoveCond(cond) break end end end function OCHit(damage, activator, caller) if activator.m_hActiveWeapon.m_iClassname == "tf_weapon_sniperrifle" or activator.m_hActiveWeapon.m_iClassname == "tf_weapon_sniperrifle_classic" or activator.m_hActiveWeapon.m_iClassname == "tf_weapon_sniperrifle_decap" then if caller:InCond(112) == true then return end if caller:IsAlive() and caller.m_iTeamNum == 3 then local toxicZombies = { ["Mutant Zombie"] = true, ["Mutant Grappler Zombie"] = true, ["Mutant Burning Man"] = true, ["Mutant Corroder Zombie"] = true, ["Mutant Crawler Zombie"] = true, ["Mutant Tiny Desk"] = true, ["Mutant Mad Scientist"] = true, ["Mutant Camouflage Zombie"] = true, ["Mutant Bruiser Zombie"] = true, ["Mutant Infectious Zombie"] = true, ["Mutant Tank"] = true, ["Giant Treadonator"] = true, ["Giant Battlelord"] = true, ["Giant Corrupted"] = true, } if not toxicZombies[caller.m_szNetname] then caller:AddCond(112,8, activator) end end end end function atomKill(damage, activator, caller) if not activator:IsRealPlayer() then return end local handle = activator:GetHandleIndex() if not player_kill_count[handle] then player_kill_count[handle] = 0 end player_kill_count[handle] = player_kill_count[handle] + 1 if player_kill_count[handle] >= 10 then local activeWeapon = activator.m_hActiveWeapon if activeWeapon and activeWeapon:GetItemName() == "Atom Launcher" then activeWeapon:SetAttributeValue("reload full clip at once", 1) activator:Print(2, "Full clip reload after 10 kills!") activator:PlaySoundToSelf("ui/quest_alert.wav") timer.Simple(5, function() activeWeapon:SetAttributeValue("reload full clip at once", nil) end) player_kill_count[handle] = 0 end end end function aa12Kill(damage, activator, caller) local weapon = activator.m_hActiveWeapon if weapon and weapon:GetItemName() == "Drummed Devastator" then local currentClipSizeBonus = weapon:GetAttributeValue("clip size bonus") or 1 if currentClipSizeBonus <= 50 then currentClipSizeBonus = currentClipSizeBonus + 0.1 weapon:SetAttributeValue("clip size bonus", currentClipSizeBonus) end local currentReloadTimeDecrease = weapon:GetAttributeValue("Reload time decreased") or 1 if currentReloadTimeDecrease >= -3 then currentReloadTimeDecrease = currentReloadTimeDecrease - 0.01 weapon:SetAttributeValue("Reload time decreased", currentReloadTimeDecrease) end end end function extendedEyelander(damage, activator, caller) timer.Simple(0.1, function() local weapon = activator:GetPlayerItemBySlot(LOADOUT_POSITION_MELEE) if weapon:GetItemName() ~= "Golden Eyelander" then return end -- don't waste time if it's not the eyelander uberweapon local decap = activator.m_iDecapitations or 0 if decap <= 0 then weapon:SetAttributeValue("max health additive bonus", nil) weapon:SetAttributeValue("move speed bonus", nil) weapon:SetAttributeValue("dmg penalty vs players", nil) activator:SetAttributeValue("damage penalty", nil) else if decap > 4 then weapon:SetAttributeValue("max health additive bonus", 10 * math.max(math.min(decap - 4, 6), 0)) weapon:SetAttributeValue("move speed bonus", 1 + 0.05 * math.max(math.min(decap - 4, 6), 0)) end weapon:SetAttributeValue("dmg penalty vs players", 1 + 0.075 * math.min(decap, 10)) activator:SetAttributeValue("damage penalty", 1 + 0.05 * math.min(decap, 10)) end end) end function StunOnDetonation(damage, activator, caller) if caller:IsAlive() and caller.m_iTeamNum == 3 then caller:AddCond(71,7) caller:AddCond(51,7) caller:PlaySoundToSelf("player/pl_stunned.wav") end end function chargerLogic(_, activator) local callbacks = {} local function removeCallbacks() for _, callbackData in pairs(callbacks) do activator:RemoveCallback(callbackData.Type, callbackData.ID) end end callbacks.keypress = { -- Apply animation when bot pushes M2 Type = 7, ID = activator:AddCallback(7, function(_, key) if key ~= IN_ATTACK2 then return end if activator.m_flChargeMeter < 95 then -- from 100, so the chargers have a bit of a 'tell' when they're getting ready to charge return end activator:PlaySequence("Charger_Charge") end), } callbacks.spawned = { Type = 1, ID = activator:AddCallback(1, function() removeCallbacks() end), } callbacks.died = { Type = 9, ID = activator:AddCallback(9, function() removeCallbacks() end), } end local killcounter_chances = { [0] = { [0] = 1, [1] = 0 }, [2] = { [0] = 2, [1] = 1, [2] = 0 }, [4] = { [0] = 3, [1] = 2, [2] = 1, [3] = 0 } } function RightSideKillCounter(damage, activator, caller) timer.Simple(0.15, function() local playerID = activator:GetHandleIndex() local handle = activator:GetSteamId() local extraChances = activator:GetAttributeValue("cannot pick up intelligence") or 0 local regularChances = playerPurchased[playerID] or 0 local tm = totalMoneyEarned[handle] or 0 local wm = waveMoneyEarned[handle] or 0 local tk = player_total_kill[handle] or 0 local wk = waveKills[handle] or 0 local ec = (playerExtraLuckyChances[handle] or 0) + (killcounter_chances[extraChances][regularChances]) local tx = "Kills: " .. tk .. " (+" .. wk .. ")" .. "\nTotal Earned: $" .. tm .. " (+$" .. wm .. ")" .. "\nUnused Lucky Chances: " .. ec activator:Print(PRINT_TARGET_RIGHT, tx) end) end local function cashforhits(activator) if not activator then return end if not activator.AddCallback then return end local callbacks = {} local function removeCallbacks() for _, callbackId in pairs(callbacks) do activator:RemoveCallback(callbackId) end end callbacks.damagetype = activator:AddCallback(ON_DAMAGE_RECEIVED_PRE, function(_, damageInfo) -- PrintTable(damageInfo) local mult = (DoublePointsDuration and DoublePointsDuration > 0) and 2 or 1 local damage = damageInfo.Damage if damage <= 0 then return end local damageType = damageInfo.DamageType local damageCustom = damageInfo.DamageCustom local hitter = damageInfo.Attacker local curHealth = activator.m_iHealth local function addCurrency(amount) -- local handle = hitter:GetHandleIndex() local handle = hitter:GetSteamId() local bonuscash = hitter:GetAttributeValue("currency bonus") or 1 if not waveMoneyEarned[handle] then waveMoneyEarned[handle] = 0 end if not totalMoneyEarned[handle] then totalMoneyEarned[handle] = 0 end hitter:AddCurrency(round(amount * mult * bonuscash)) waveMoneyEarned[handle] = waveMoneyEarned[handle] + round(amount * bonuscash) totalMoneyEarned[handle] = totalMoneyEarned[handle] + round(amount * bonuscash) end local immuneToRevBullshit = { -- bosses and mutants, do i need to elaborate further ["Mutant Zombie"] = true, ["Mutant Grappler Zombie"] = true, ["Mutant Headless Zombie"] = true, ["Mutant Burning Man"] = true, ["Mutant Corroder Zombie"] = true, ["Mutant Tiny Desk"] = true, ["Mutant Crawler Zombie"] = true, ["Mutant Mad Scientist"] = true, ["Mutant Camouflage Zombie"] = true, ["Mutant Bruiser Zombie"] = true, ["Mutant Infectious Zombie"] = true, ["Mutant Tank"] = true, ["Giant Treadonator"] = true, ["Giant Battlelord"] = true, ["Giant Corrupted"] = true, -- these guys are just built different i suppose ["Tank"] = true, ["Screamer Zombie"] = true, ["Tiny Desk Zombie"] = true, ["Tomb Detonator"] = true } local function invasiveRevival(seconds) if type(seconds) ~= "number" or seconds < 1 then seconds = 10 end addCurrency(1) RightSideKillCounter(damage, hitter, activator) activator.m_iHealth = math.max(15000, 15000 * waveCount) activator:AddCond(43, seconds + 1, hitter) -- reprogrammed condition if activator.m_szNetname ~= "Headless Zombie" then activator:AddCond(16, seconds + 1, hitter) -- buffban effect end activator:AddCond(26, seconds + 1, hitter) -- battback effect activator:AddCond(29, seconds + 1, hitter) -- conch effect activator:AddCond(72, seconds + 1, hitter) -- whatever this is activator:AddCond(113, seconds + 1, hitter) -- king effect without the powerup (hopefully) activator:AddCond(114, seconds + 1, hitter) -- le glow activator:AddCond(32, seconds + 1, hitter) -- ??? activator:AddCond(51, seconds * 0.3, hitter) -- 3s uber on teamswap resurrection activator:AddCond(130, seconds + 1, hitter) -- ??? activator:SetAttributeValue("dmg penalty vs players", 8) activator:SetAttributeValue("melee range multiplier", 4.20) activator:SetAttributeValue("melee bounds multiplier", 1.35) activator:SetAttributeValue("attach particle effect", 3162) hitter:PlaySoundToSelf("sound_effect_from_fortnut_that_is_used_for_dna_rejuv.wav") timer.Simple(seconds, function() local handle = hitter:GetSteamId() if not waveKills[handle] then waveKills[handle] = 0 end if not player_total_kill[handle] then player_total_kill[handle] = 0 end waveKills[handle] = waveKills[handle] + 1 player_total_kill[handle] = player_total_kill[handle] + 1 addCurrency(75) activator:Suicide() RightSideKillCounter(damage, hitter, activator) end) end if damageInfo.Weapon and damageInfo.Weapon:GetItemName() == "DNA Rejuvenator" then if damage >= curHealth and not immuneToRevBullshit[activator.m_szNetname] then invasiveRevival(10) damageInfo.Damage = 1 end elseif damageInfo.Weapon and damageInfo.Weapon:GetItemName() == "Jenova" then if immuneToRevBullshit[activator.m_szNetname] then goto RejuvImmune end if damage >= curHealth then invasiveRevival(20) damageInfo.Damage = 1 else -- damageInfo.Damage = damage activator:AddCond(43, 6, hitter) -- reprogrammed condition if activator.m_szNetname ~= "Headless Zombie" then activator:AddCond(16, 5.5, hitter) -- buffban effect end activator:AddCond(26, 5.5, hitter) -- battback effect activator:AddCond(72, 5.5, hitter) -- whatever this is activator:AddCond(32, 5.5, hitter) -- ??? activator:AddCond(51, 1.75, hitter) -- 3s uber on teamswap resurrection activator:SetAttributeValue("dmg penalty vs players", 5) activator:SetAttributeValue("melee range multiplier", 4.20) activator:SetAttributeValue("melee bounds multiplier", 1.35) activator:SetAttributeValue("attach particle effect", 3149) addCurrency(1) RightSideKillCounter(damage, hitter, activator) timer.Simple(5.5, function() activator:SetAttributeValue("dmg penalty vs players", nil) activator:SetAttributeValue("melee range multiplier", nil) activator:SetAttributeValue("melee bounds multiplier", nil) activator:SetAttributeValue("attach particle effect", nil) end) end -- elseif damageCustom == TF_DMG_CUSTOM_BACKSTAB and hitter:GetPlayerItemByName("Lethal Resurrector") then -- local zombie_maxhealth = activator.m_iMaxHealth -- local hitter_maxhealth = hitter.m_iMaxHealth -- local hitterhealth = hitter.m_iHealth -- damageInfo.damage = 1 -- if damageInfo.Weapon:GetAttributeValue("sanguisuge") then -- kunai effect -- end end ::RejuvImmune:: if hitter:InCond(43) then hitter = hitter:GetConditionProvider(43) elseif activator:InCond(43) then hitter = activator:GetConditionProvider(43) end if (damageType & DMG_BURN) ~= 0 then return end local isCrit = (damageType & DMG_CRITICAL) ~= 0 if isCrit then damage = damage * 3 end local curHealth = activator.m_iHealth if (InstakillDuration and InstakillDuration > 0) and activator.m_szNetname == "Zombie" and hitter:InCond(56) == true then --instakill functionality -washy damage = curHealth activator.m_iHealth = 0 end if damage > curHealth and activator.m_szNetname == "Tank" then -- snuck in here so we don't need a separate function for it hitter:SpeakResponseConcept("TLK_MVM_TANK_DEAD") -- ding dong the tank is dead end if activator.m_szNetname == "Zombie" and hitter.m_szNetname == "Tank" then damage = curHealth activator.m_iHealth = 0 -- if converted zombie is hit by Tank, treat it as Instakill end --local isLethal = curHealth - (damage + 1) <= 0 --[[ if not isLethal then ]] if waveActive == false then -- stop ppl from using whatever exploits to farm money before the mission starts addCurrency(0) elseif activator.m_iTeamNum ~= 3 then -- exploit failsafe addCurrency(0) elseif activator:InCond(5) == true or activator:InCond(51) == true or activator:InCond(52) == true then -- for some reasons, money is still being given on ubered zombies addCurrency(0) elseif (activator.m_szNetname == "Mutant Mad Scientist") then -- anti money printing addCurrency(0) elseif (damageType & DMG_BULLET) ~= 0 then addCurrency(1) elseif (damageType & DMG_USE_HITLOCATIONS) ~= 0 then addCurrency(1) elseif (damageType & DMG_IGNITE) ~= 0 and hitter.m_hActiveWeapon:GetItemName() == "Prototype SM2" then addCurrency(0) elseif (damageType & DMG_IGNITE) ~= 0 then addCurrency(1) elseif (damageType & DMG_RADIUS_MAX) ~= 0 then addCurrency(0) elseif (damageType & DMG_SLASH) ~= 0 then addCurrency(0) else addCurrency(1) end --[[ return end if IsLethal then addCurrency(75) return end if (damageType & DMG_BLAST) ~= 0 then addCurrency(75) -- used to be 50 -- print("explosive?") elseif (damageType & DMG_MELEE) ~= 0 then addCurrency(150) -- print("melee?") elseif (damageType & DMG_MELEE) == 0 and (damageType & DMG_CRITICAL) ~= 0 then -- this is used for headshots, may overlap with Instakill addCurrency(100) -- print("crit?") elseif (damageType & DMG_BULLET) ~= 0 then addCurrency(75) -- print("bullet?") elseif (damageType & DMG_USE_HITLOCATIONS) ~= 0 then addCurrency(75) -- print("fancier bullet?") else addCurrency(75) -- print("hell if I know") end ]] RightSideKillCounter(damage, hitter, activator) end) callbacks.killed = activator:AddCallback(ON_DEATH, function(_, damageInfo) -- PrintTable(damageInfo) local mult = (DoublePointsDuration and DoublePointsDuration > 0) and 2 or 1 local damage = damageInfo.Damage if damage <= 0 then return end local damageType = damageInfo.DamageType local hitter = damageInfo.Attacker local zombieAssist = false if hitter:InCond(43) then hitter = hitter:GetConditionProvider(43) zombieAssist = true elseif activator:InCond(43) then hitter = activator:GetConditionProvider(43) zombieAssist = true end --if (damageType & DMG_BURN) ~= 0 then -- return --end local isCrit = (damageType & DMG_CRITICAL) ~= 0 if isCrit then damage = damage * 3 end local curHealth = activator.m_iHealth if (InstakillDuration and InstakillDuration > 0) and activator.m_szNetname == "Zombie" and hitter:InCond(56) == true then --instakill functionality -washy damage = curHealth activator.m_iHealth = 0 end if damage > curHealth and activator.m_szNetname == "Tank" then -- snuck in here so we don't need a separate function for it hitter:SpeakResponseConcept("TLK_MVM_TANK_DEAD") -- ding dong the tank is dead end -- local handle = hitter:GetHandleIndex() local handle = hitter:GetSteamId() if not waveKills[handle] then waveKills[handle] = 0 end if not player_total_kill[handle] then player_total_kill[handle] = 0 end waveKills[handle] = waveKills[handle] + 1 player_total_kill[handle] = player_total_kill[handle] + 1 local function addCurrency(amount) -- local handle = hitter:GetHandleIndex() local handle = hitter:GetSteamId() local bonuscash = hitter:GetAttributeValue("currency bonus") or 1 if not waveMoneyEarned[handle] then waveMoneyEarned[handle] = 0 end if not totalMoneyEarned[handle] then totalMoneyEarned[handle] = 0 end local killCashBonus = hitter:GetAttributeValue("unusualifier_attribute_template_name") or 0 hitter:AddCurrency(round(amount * mult * bonuscash) + killCashBonus) waveMoneyEarned[handle] = waveMoneyEarned[handle] + round(amount * bonuscash) totalMoneyEarned[handle] = totalMoneyEarned[handle] + round(amount * bonuscash) end if extraMoneyMode == false then local zombieRewards = { ["Tiny Desk Zombie"] = 20, ["Tank"] = 750, ["Mutant Zombie"] = 2000, ["Mutant Grappler Zombie"] = 2000, ["Mutant Burning Man"] = 2000, ["Mutant Corroder Zombie"] = 2000, ["Mutant Crawler Zombie"] = 2000, ["Mutant Mad Scientist"] = 2000, ["Mutant Camouflage Zombie"] = 2000, ["Mutant Bruiser Zombie"] = 2000, ["Mutant Infectious Zombie"] = 2000, ["Mutant Tank"] = 5000, ["Mutant Tiny Desk"] = 200 } local meleeslot = hitter:GetPlayerItemBySlot(LOADOUT_POSITION_MELEE) or nil local OCcheck = meleeslot:GetAttributeValue("loot rarity") or 0 local specBCheck = hitter:GetAttributeValue("loot rarity") or 0 local sovietPugilist = hitter:GetAttributeValue("has pipboy build interface") or 0 local knockout = hitter:GetAttributeValue("ubercharge rate penalty") or 1 local canMeleeEarn = (OCcheck == 2 or specBCheck == 1 or sovietPugilist == 29 or knockout == 1.01 or zombieAssist) if damageInfo.Weapon then if damageInfo.Weapon:GetItemName() == "The Payoff" or damageInfo.Weapon:GetItemName() == "One-hit Wonder" then addCurrency(300) elseif damageInfo.Weapon:GetItemName() == "Golden Cashback" then addCurrency(450) elseif damageInfo.Weapon:GetItemName() == "Golden Eyelander" then local decap = hitter.m_iDecapitations or 0 addCurrency(math.min(80, 10 * decap)) elseif damageInfo.Weapon:GetItemName() == "Undying Macula M" or damageInfo.Weapon:GetItemName() == "Undying Macula V" then addCurrency(50) end end if zombieRewards[activator.m_szNetname] then addCurrency(zombieRewards[activator.m_szNetname]) -- specific zombie types bonus elseif (damageType & DMG_BLAST) ~= 0 then addCurrency(200) -- used to be 50 -- print("explosive?") -- elseif hitter.m_hActiveWeapon:GetItemName() == "The Payoff" then -- addCurrency(300) -- -- print("payoff effect") elseif hitter.m_hActiveWeapon.m_iClassname == "tf_weapon_knife" and hitter.m_iClass == 8 and not canMeleeEarn then addCurrency(100) -- print("spy's knife treatment") elseif (damageType & DMG_MELEE) ~= 0 and not canMeleeEarn then addCurrency(25) -- print("melee?") elseif (damageType & DMG_MELEE) == 0 and (damageType & DMG_CRITICAL) ~= 0 then -- this is used for headshots, may overlap with Instakill addCurrency(220) -- print("crit?") elseif (damageType & DMG_BULLET) ~= 0 then addCurrency(200) -- print("bullet?") elseif (damageType & DMG_IGNITE) ~= 0 then addCurrency(200) -- print("flamethrower kill") elseif (damageType & DMG_BURN) ~= 0 then addCurrency(200) -- print("flamethrower kill from afterburn") elseif (damageType & DMG_USE_HITLOCATIONS) ~= 0 then addCurrency(200) -- print("fancier bullet?") else addCurrency(200) -- print("hell if I know") end else local zombieRewards = { ["Tiny Desk Zombie"] = 10, ["Tank"] = 325, ["Mutant Zombie"] = 1000, ["Mutant Grappler Zombie"] = 1000, ["Mutant Burning Man"] = 1000, ["Mutant Corroder Zombie"] = 1000, ["Mutant Crawler Zombie"] = 1000, ["Mutant Mad Scientist"] = 1000, ["Mutant Camouflage Zombie"] = 1000, ["Mutant Bruiser Zombie"] = 1000, ["Mutant Infectious Zombie"] = 1000, ["Mutant Tank"] = 2500, ["Mutant Tiny Desk"] = 100 } local meleeslot = hitter:GetPlayerItemBySlot(LOADOUT_POSITION_MELEE) local OCcheck = meleeslot:GetAttributeValue("loot rarity") or 0 local specBCheck = hitter:GetAttributeValue("loot rarity") or 0 local sovietPugilist = hitter:GetAttributeValue("has pipboy build interface") or 0 local knockout = hitter:GetAttributeValue("ubercharge rate penalty") or 1 local canMeleeEarn = (OCcheck == 2 or specBCheck == 1 or sovietPugilist == 29 or knockout == 1.01 or zombieAssist) if hitter.m_hActiveWeapon:GetItemName() == "The Payoff" or hitter.m_hActiveWeapon:GetItemName() == "One-hit Wonder" then addCurrency(150) elseif hitter.m_hActiveWeapon:GetItemName() == "Golden Cashback" then addCurrency(200) elseif hitter.m_hActiveWeapon:GetItemName() == "Golden Eyelander" then local decap = hitter.m_iDecapitations or 0 addCurrency(math.min(50, 5 * decap)) elseif hitter.m_hActiveWeapon:GetItemName() == "Undying Macula M" or hitter.m_hActiveWeapon:GetItemName() == "Undying Macula V" then addCurrency(25) end if zombieRewards[activator.m_szNetname] then addCurrency(zombieRewards[activator.m_szNetname]) -- specific zombie types bonus elseif (damageType & DMG_BLAST) ~= 0 then addCurrency(100) -- used to be 50 -- print("explosive?") -- elseif hitter.m_hActiveWeapon:GetItemName() == "The Payoff" then -- addCurrency(125) -- -- print("payoff effect") elseif hitter.m_hActiveWeapon.m_iClassname == "tf_weapon_knife" and hitter.m_iClass == 8 and not canMeleeEarn then addCurrency(50) -- print("spy's knife treatment") elseif (damageType & DMG_MELEE) ~= 0 and not canMeleeEarn then addCurrency(10) -- print("melee?") elseif (damageType & DMG_MELEE) == 0 and (damageType & DMG_CRITICAL) ~= 0 then -- this is used for headshots, may overlap with Instakill addCurrency(110) -- print("crit?") elseif (damageType & DMG_BULLET) ~= 0 then addCurrency(100) -- print("bullet?") elseif (damageType & DMG_IGNITE) ~= 0 then addCurrency(100) -- print("flamethrower kill") elseif (damageType & DMG_BURN) ~= 0 then addCurrency(100) -- print("flamethrower kill from afterburn") elseif (damageType & DMG_USE_HITLOCATIONS) ~= 0 then addCurrency(100) -- print("fancier bullet?") else addCurrency(100) -- print("hell if I know") end end if activator.m_szNetname == "Mutant Burning Man" and waveCount == 16 then local secretlySolo = false local hascond = false local players = 0 for _, aplayer in pairs(ents.GetAllPlayers()) do if aplayer:IsRealPlayer() and aplayer.m_iTeamNum == 2 and classNames[aplayer.m_iClass] then players = players + 1 end end if players == 1 then secretlySolo = true end local conditions = {97, 90, 92, 93, 91, 96, 95, 94, 103, 109, 110} local pstid = hitter:GetSteamId() for _, cond in ipairs(conditions) do if hitter:InCond(cond) then hascond = true if not secretlySolo then playerMannpower[pstid] = nil hitter:RemoveCond(cond) end end end if (not secretlySolo) or (not hascond and secretlySolo) then hitter:AddCond(110) end end RightSideKillCounter(damage, hitter, activator) end) callbacks.spawned = activator:AddCallback(1, function() removeCallbacks() end) callbacks.died = activator:AddCallback(9, function() removeCallbacks() end) end -- future thing for solo mode players -- local soloMode_bossDMGTakenMod = { -- ["Mutant Zombie"] = { -- [2] = 1, -- [20] = 1.4 -- }, -- ["Mutant Grappler Zombie"] = { -- [4] = 1, -- [18] = 1.25 -- }, -- ["Mutant Burning Man"] = { -- [6] = 1, -- [16] = 1.33 -- }, -- ["Mutant Corroder Zombie"] = 1, -- ["Mutant Mad Scientist"] = 1, -- ["Mutant Tank"] = 1.4, -- ["Mutant Crawler Zombie"] = 1.1, -- ["Mutant Camouflage Zombie"] = 1.2, -- ["Mutant Bruiser Zombie"] = 1.33, -- ["Mutant Infectious Zombie"] = 1.25, -- ["Giant Treadonator"] = 1.2, -- ["Giant Battlelord"] = 1.4, -- ["Giant Corrupted"] = 1.4, -- } -- mutank's reactive damage reduction only applies if the server's not in solo mode. -- local MUTANK_KILLTIME = 150 -- in seconds -- "dmg taken increased" function OnWaveSpawnBot(bot) timer.Simple(1, function() cashforhits(bot) -- if soloMode then -- if bot.m_szNetname ~= "Mutant Tank" and soloMode then -- local dmginc = soloMode_bossDMGTakenMod[bot.m_szNetname] or nil -- if dmginc then -- if type(dmginc) == "table" then -- dmginc = soloMode_bossDMGTakenMod[bot.m_szNetname][waveCount] or nil -- if dmginc then -- bot.SetAttributeValue("dmg taken increased", dmginc) -- end -- else -- bot.SetAttributeValue("dmg taken increased", dmginc) -- end -- end -- end -- if bot.m_szNetname == "Mutant Tank" and not soloMode then -- if bot.m_szNetname == "Mutant Tank" then -- bot.currenttime = 0 -- timer.Simple(1, function() -- if bot.currenttime < MUTANK_KILLTIME then -- bot.currenttime = bot.currenttime + 1 -- end -- end) -- bot.mutank_rdr = bot:AddCallback(ON_DAMAGE_RECEIVED_POST, function(bot, damageinfo, prevhealth) -- if bot.currenttime >= MUTANK_KILLTIME then -- bot.SetAttributeValue("dmg taken increased", nil) -- activator:RemoveCallback(bot.mutank_rdr) -- return -- end -- local healthratio = (prevhealth - damageinfo.Damage) / 1200000 -- local timeratio = bot.currenttime / MUTANK_KILLTIME -- if healthratio + timeratio >= 1 then -- return -- then just don't. -- end -- local rdrval = 1 - (1 / (2 - healthratio - timeratio)) -- bot.SetAttributeValue("dmg taken increased", (1 - rdrval)) -- for _, player in pairs(ent.GetAllPlayers()) do -- if player:IsRealPlayer() and betaMode then -- local dbt = "mutank rdr value: " .. (1 - rdrval) .. "%" -- player:Print(2, dbt) -- end -- end -- end) -- end end) end function playertracker(_, activator) -- the only other thing here made by Sntr local callbacks = {} local function removeCallbacks() for _, callbackId in pairs(callbacks) do activator:RemoveCallback(callbackId) end end --local function DeathCounter() -- if not waveActive then -- return -- end -- -- local deathcount = deathCounts[activator:GetHandleIndex()] -- -- if deathcount >= 3 and deathcount < 4 -- then -- util.PrintToChat(activator,"You have received a $250 comeback bonus.") -- activator:AddCurrency(250) -- end -- if deathcount >= 5 and deathcount < 6 -- then -- util.PrintToChat(activator,"You have received a $500 comeback bonus.") -- activator:AddCurrency(500) -- end -- if deathcount > 7 and deathcount < 8 -- then -- util.PrintToChat(activator,"You have received a $1000 comeback bonus.") -- activator:AddCurrency(1000) -- end --end callbacks.damagetype = activator:AddCallback(ON_DAMAGE_RECEIVED_PRE, function(_, damageInfo) if activator:InCond(5) == true or activator:InCond(51) == true or activator:InCond(52) == true then damageInfo.Damage = 0 return end -- disallow friendly fire, allow self damage if damageInfo.Attacker:GetHandleIndex() ~= activator:GetHandleIndex() then if damageInfo.Attacker.m_iTeamNum == activator.m_iTeamNum then damageInfo.Damage = 0 return end end local damage = damageInfo.Damage local curHealth = activator.m_iHealth if damage > curHealth and activator:InCond(70) == true then -- give full heal + uber when condition 70 is removed local spec3check = activator:GetAttributeValue("no self blast dmg") or 0 if damageInfo.Attacker:GetHandleIndex() == activator:GetHandleIndex() and math.floor(spec3check) == 2 then damageInfo.Damage = 0 else activator:AddCond(5,7.5) activator:AddCond(32,7.5) activator:AddHealth(2000,1) activator:PlaySoundToSelf("misc/halloween/merasmus_stun.wav") -- activator:RemoveCond(130) activator:RemoveCond(70) -- so people can't be undying forever activator.vm_quickrev = false -- added this for compatibility -washy end end end) -- callbacks.output = activator:AddCallback(ON_INPUT, function(_, medicbonus_relay) -- -- local playerclass = activator.m_iClass -- local playercount = math_counter.m_OutValue -- -- if playerclass == 5 -- then -- activator:AddCurrency( playercount * 75 ) -- end -- end) callbacks.spawned = activator:AddCallback(1, function() removeCallbacks() end) callbacks.died = activator:AddCallback(9, function() removeCallbacks() --DeathCounter() end) end function WaveCountAdd() waveCount = waveCount + 1 print("CURRENT WAVE: ", waveCount) if waveCount == 1 then for _, player in pairs(ents.GetAllPlayers()) do if player:IsRealPlayer() and player.m_iTeamNum == 2 and classNames[player.m_iClass] then RightSideKillCounter(0, player, nil) end end end end function StageClearText() for _, player in pairs(ents.GetAllPlayers()) do if player:IsRealPlayer() then player:Print(3, "Stage cleared - Get to a Saxxy table.\nYou have 60 seconds to prepare.") end end end function StageClearExtendedText() for _, player in pairs(ents.GetAllPlayers()) do if player:IsRealPlayer() then player:Print(3, "Stage cleared - Get to a Saxxy table.\nYou have 75 seconds to prepare.") end end end function StageClearTreadText() for _, player in pairs(ents.GetAllPlayers()) do if player:IsRealPlayer() then player:Print(3, "Stage cleared - Get ready to face a Boss Zombie.\nYou have 45 seconds to prepare.") end end end function StageClearMiniText() for _, player in pairs(ents.GetAllPlayers()) do if player:IsRealPlayer() then player:Print(3, "Raid stage cleared - Get to a Saxxy table.\nYou have 60 seconds to prepare.") end end end function ALittleWarning() for _, player in pairs(ents.GetAllPlayers()) do if player:IsRealPlayer() then player:DisplayTextChat("\x07FF0000WARNING: Mutant Zombies from this point onwards will be equipped with unremovable powerups and appear in pairs!") end end end function StageClearFinaleText() for _, player in pairs(ents.GetAllPlayers()) do if player:IsRealPlayer() then player:Print(3, "Stage cleared - FINAL CHANCE TO UPGRADE.\nYou have 75 seconds to make your dying wish.\nMake it count.") end end end function StageClearTankText() for _, player in pairs(ents.GetAllPlayers()) do if player:IsRealPlayer() then player:Print(3, "Tank stage cleared - Get to a Saxxy table.\nYou have 60 seconds to prepare.") end end end function TeamRespawn() if not soloMode then ents.FindByName("respawner"):AcceptInput("ForceTeamRespawn", "2") end end -- and here's the stuff made by Washy -- likewise, plenty of kudos function OnWaveReset() print("Current Moon Phase:", moonPhaseNames[moonPhase()]) waveCount = 0 joinedIn = {} extraMoneyMode = false infMoneyMode = false betaMode = false soloMode = false soloist_uid = nil -- player_taunt_speed = {} local initialMoney = {} local captureDelay = 2 -- Total delay to wait before capturing starting money local checkInterval = 0.5 -- Interval to keep checking money during the delay local maxChecks = captureDelay / checkInterval -- Number of checks to perform local checksRemaining = maxChecks for _, player in pairs(ents.GetAllPlayers()) do if player:IsRealPlayer() then -- Initialize loadout table if it doesn't exist if not player.loadout then player.loadout = {} end -- Set all loadout slots to "Default" for weapon = 0, 3, 1 do player.loadout[weapon] = "Default" end -- Function to validate money after initialization local function CheckStartingMoney() for _, player in pairs(ents.GetAllPlayers()) do if player:IsRealPlayer() then local handle = player:GetHandleIndex() local currentMoney = player.m_nCurrency -- Log for debugging --print("Player " .. handle .. " money: " .. tostring(currentMoney)) -- Check for excessive starting money if currentMoney == 26132 then -- if currentMoney > 25000 and currentMoney ~= 999995 and currentMoney ~= 999999 then ActivateExtraMoneyMode() player:DisplayTextChat("\x07ffdd00Excessive starting money detected. All players will receive only half the money from kills.") --else -- extraMoneyMode = false end if currentMoney == 999999 or currentMoney == 999995 then -- ActivateExtraMoneyMode() ActivateInfMoneyMode() end if currentMoney == 10005 or currentMoney == 12005 or currentMoney == 15005 or currentMoney == 18005 or currentMoney == 350005 or currentMoney == 999995 then ActivateDebugMode() end end end end -- Repeated checks during initialization local function PerformChecks() if checksRemaining > 0 then checksRemaining = checksRemaining - 1 for _, player in pairs(ents.GetAllPlayers()) do if player:IsRealPlayer() then local handle = player:GetHandleIndex() local currentMoney = player.m_nCurrency -- Log each check for debugging --print("Checking money for player " .. handle .. ": " .. tostring(currentMoney)) -- Save initial money value during checks if not initialMoney[handle] then initialMoney[handle] = currentMoney end end end -- Schedule the next check timer.Simple(checkInterval, PerformChecks) else -- Perform final validation after all checks CheckStartingMoney() end end -- Start the repeated checks PerformChecks() table.insert(joinedIn, player:GetHandleIndex()) end end player_kill_count = {} waveMoneyEarned = {} totalMoneyEarned = {} waveKills = {} player_total_kill = {} playerPurchased = {} playerBonuses = {} playerDynamicWeight = {} playerLastBonus = {} playerExtraLuckyChances = {} playerCashback = {} playerCurrentCash = {} playerWeakenedMannpower = {} playerMannpower = {} hyper_cd_player = {} invs_cd_player = {} cooldownTableCountdown = {} -- Stop the sound or adjust its volume ents.FindByName("lobby_music"):AcceptInput("StopSound") ents.FindByName("lobby_music"):AcceptInput("Volume", 0) end local Set_Buffs = { ["Pyroland Buff"] = { class = nil, -- use nil to denote all-class, a table of TF_CLASS_* / integer to denote multi-class, or a specific TF_CLASS_* / integer requiredItems = 2, -- number of required items to activate the set buff missingText = "Equip another Pyroland-related item to activate this item's \"Pyroland Buff\"!", -- special description text for equipped set items with an inactive set buff items = { { -- note: duplicates based on the itemName will be ignored itemName = "The Rainblower", -- item name as it appears in the item schema. can be a table of item names to denote same/similar item. can also be "player" to make buffs apply to players attributes = { -- list of attributes in a key-value format, where the key is the attribute name as a string ["damage bonus"] = 2, ["airblast cost decreased"] = 0, ["mult airblast refire time"] = 0.25 }, activeBuffDescription = "+100% damage, no airblast cost, +75% faster airblast refire" -- special description text for this item when the set buff is active, will replace missingText }, { itemName = "The Lollichop", attributes = { ["heal on kill"] = 50, ["mult_player_movespeed_active"] = 1.15, ["add cond when active"] = 11 }, activeBuffDescription = "+50 health on kill, +15% move speed on active, always crit" }, { itemName = {"Pyrovision Goggles", "Autogrant Pyrovision Goggles"}, attributes = { ["attach particle effect"] = 145, ["max health additive bonus"] = 25, ["dmg taken increased"] = 0.9 }, activeBuffDescription = "+25 max health, +10% damage resistance" }, { itemName = "The Infernal Orchestrina", attributes = { ["max health additive bonus"] = 15, ["dmg taken increased"] = 0.9 }, activeBuffDescription = "+15 max health, +10% damage resistance" }, { itemName = "The Burning Bongos", attributes = { ["max health additive bonus"] = 15, ["dmg taken increased"] = 0.9 }, activeBuffDescription = "+15 max health, +10% damage resistance" }, { itemName = {"Pet Balloonicorn", "Pet Reindoonicorn"}, attributes = { ["max health additive bonus"] = 15, ["dmg taken increased"] = 0.9 }, activeBuffDescription = "+15 max health, +10% damage resistance" }, { -- activeBuffDescription can safely be ignored when applying effects to players, but will be applied if defined itemName = "player", attributes = { ["effect bar recharge rate increased"] = 0.75 } } } }, ["Special Delivery Buff"] = { class = TF_CLASS_SCOUT, requiredItems = 3, missingText = "Equip {remaining} more {itemplurality} from \"The Special Delivery\" item set to unlock this item's \"Special Delivery Buff\"!", -- you can also use {remaining} and {itemplurality} to tell players about how many items left to equip to activate the set buff items = { { itemName = "The Shortstop", attributes = { ["damage bonus"] = 1.75, ["Reload time decreased"] = 0.5 }, activeBuffDescription = "+75% damage, +50% faster reload" }, { itemName = {"Mad Milk", "Mutated Milk"}, attributes = { ["afterburn immunity"] = 1, ["fire retardant"] = 1, ["attribute immunity"] = "healing received penalty" }, activeBuffDescription = "Passive afterburn and anti-heal immunity" }, { itemName = {"The Holy Mackerel", "Festive Holy Mackerel"}, attributes = { ["add cond on hit"] = 25943, ["add cond on hit duration"] = 0.6, ["max health additive bonus"] = 25 }, activeBuffDescription = "+25 max health, 0.6 seconds of stun on melee hit" }, { itemName = "The Milkman", attributes = { ["dmg taken increased"] = 0.9, ["dmg taken from crit reduced"] = 0.75 }, activeBuffDescription = "+10% damage resistance, +25% crit resistance" }, { itemName = "player", attributes = { ["effect bar recharge rate increased"] = 0.75 }, activeBuffDescription = "+25% faster effect bar recharge rate" } }, extraLoadoutItems = { [LOADOUT_POSITION_HEAD] = "The Milkman" } }, ["1001 Demoknights Buff"] = { class = TF_CLASS_DEMOMAN, requiredItems = 3, missingText = "Equip {remaining} more {itemplurality} from \"One Thousand and One Demoknights\" item set to unlock this item's \"1001 Demoknights Buff\"!", items = { { itemName = "Ali Baba's Wee Booties", attributes = { ["max health additive bonus"] = 150, ["kill refills meter"] = 0.25 }, activeBuffDescription = "+75 max health, +20% charge on melee kill" }, { itemName = "The Splendid Screen", attributes = { ["dmg taken from crit reduced"] = 0.35, ["dmg taken from bullets reduced"] = 0.45, ["dmg taken from blast reduced"] = 0.35, ["dmg taken from fire reduced"] = 0.35, ["mult dmgtaken from melee"] = 0.65 }, activeBuffDescription = "+65% crit damage resistance, +55% bullet resistance, +45% blast and fire resistance, +35% melee resistance" }, { itemName = "The Persian Persuader", attributes = { ["damage bonus HIDDEN"] = 9.231, ["dmg pierces resists absorbs"] = 1 }, revertAttributes = { ["damage bonus HIDDEN"] = 2.308 }, activeBuffDescription = "4x base damage (600 damage), damage ignores resistances" }, { itemName = "Sultan's Ceremonial", attributes = { ["health regen"] = 15 }, activeBuffDescription = "+15 health regen" }, { itemName = "player", attributes = { ["attribute immunity"] = "healing received penalty", ["charge recharge rate increased"] = 0.45 }, activeBuffDescription = "+35% shield charge recharge rate, passive anti-heal immunity" } }, extraLoadoutItems = { [LOADOUT_POSITION_HEAD] = "Sultan's Ceremonial" } }, ["Clinical Trial Buff"] = { class = TF_CLASS_MEDIC, requiredItems = 3, missingText = "Equip all items from the \"Clinical Trial\" item set to unlock this item's \"Clinical Trial Buff\"!", items = { { itemName = "The Overdose", attributes = { ["damage bonus"] = 2, ["damage penalty"] = 1, ["bleeding duration"] = 8, ["add cond on hit"] = 24, ["add cond on hit duration"] = 10, ["loot rarity"] = 1, ["heal on hit for rapidfire"] = 3, ["add uber charge on hit"] = 0.02 }, activeBuffDescription = "+115% damage bonus, 8 seconds of bleed, 10 seconds of Jarate, applies both \"Experimental Projectiles\" and \"Overdose Therapy\" overclocks without drawbacks" }, { itemName = "The Quick-Fix", attributes = { ["heal rate penalty"] = 1.5, ["overheal penalty"] = 1, ["overheal decay bonus"] = 0, ["overheal fill rate reduced"] = 2, ["ubercharge overheal rate penalty"] = 1.5, ["medigun self drain"] = 0 }, activeBuffDescription = "+50% heal rate, removed max overheal penalty, +100% overheal build rate, +50% Ubercharge rate on overhealed patients, ignores all Medi-Gun Overclock drawbacks" }, { itemName = "The Solemn Vow", attributes = { ["dmg penalty vs players"] = 2, ["add uber charge on hit"] = 0.15, ["fire rate penalty"] = 0.85, ["health regen"] = 10, ["add attributes when active"] = "teleport instead of die|0.35" }, activeBuffDescription = "+100% damage bonus, +25% faster fire rate, +15% Ubercharge on hit, +10 health regen, 35% chance of self-revive while weapon is active" } } }, ["Howitzer Hybridknight's Blessing"] = { class = TF_CLASS_DEMOMAN, requiredItems = 3, hiddenWhenInactive = true, -- can be safely omitted, but when set to true, will keep this set buff's existence hidden when inactive. has higher priority over missingText. missingText = nil, items = { { itemName = "Howitzer", attributes = { ["Reload time decreased"] = 0.5 }, activeBuffDescription = "+50% faster reload speed" }, { itemName = "Gearshift", attributes = { ["dmg taken from crit reduced"] = 0.25 }, activeBuffDescription = "+75% crit resistance", specialItemDescriptionAttr = "special item description 4" -- substitute attribute for "special item description" attribute if it is used already, use nil or omit otherwise. MUST be "special item description [N]" where [N] is a number from 2 to 4, or it will default to "special item description" }, { itemName = {"The Chargin' Targe", "Festive Targe 2014", "The Splendid Screen", "The Tide Turner"}, attributes = { ["dmg taken from crit reduced"] = 0.5, ["dmg taken from bullets reduced"] = 0.67 }, activeBuffDescription = "+50% crit resistance, +33% bullet resistance" }, { itemName = "Assault and Battering Ram", attributes = { ["dmg taken from fire reduced"] = 0.5, ["dmg taken from blast reduced"] = 0.7 }, activeBuffDescription = "+50% fire resistance, +30% blast resistance" }, { itemName = {"The Eyelander", "Festive Eyelander", "The Horseless Headless Horseman's Headtaker", "Nessie's Nine Iron", "Golden Eyelander"}, attributes = { ["max health additive penalty"] = 0 }, revertAttributes = { ["max health additive penalty"] = -50 }, activeBuffDescription = "Removed max health penalty", specialItemDescriptionAttr = "special item description 4" }, { itemName = {"Hellbent Axe", "The Half-Zatoichi", "Tempered Honor"}, attributes = { ["dmg pierces resists absorbs"] = 1 }, activeBuffDescription = "Damage ignores resistances" }, { itemName = "Reclaimed Glory", attributes = { ["fire rate bonus"] = 0.5 }, activeBuffDescription = "+50% faster swing speed" } } }, ["Public Enemy Buff"] = { class = TF_CLASS_SCOUT, requiredItems = 2, missingText = "Equip another item from \"The Public Enemy\" item set to activate this item's \"Public Enemy Buff\"!", items = { { itemName = {"Baby Face's Blaster", "Baby Face's Blaster 2012"}, attributes = { ["damage bonus HIDDEN"] = 6 }, revertAttributes = { ["damage bonus HIDDEN"] = 2.75 }, activeBuffDescription = "6x base damage (36 damage per pellet)" }, { itemName = "Pretty Boy's Pocket Pistol", attributes = { ["provide on active"] = 0, ["max health additive bonus"] = 50 }, revertAttributes = { ["provide on active"] = 1 }, activeBuffDescription = "+50 max health, weapon effects no longer require holding it" }, { itemName = "The Fed-Fightin' Fedora", attributes = { ["move speed bonus"] = 1.1 }, activeBuffDescription = "+10% move speed" }, { itemName = "Dillinger's Duffel", attributes = { ["dmg taken increased"] = 0.85 }, activeBuffDescription = "+15% damage resistance" } }, extraLoadoutItems = { [LOADOUT_POSITION_HEAD] = "The Fed-Fightin' Fedora", [LOADOUT_POSITION_MISC] = "Dillinger's Duffel" } }, ["Man of Honor Buff"] = { class = TF_CLASS_SPY, requiredItems = 2, missingText = "Equip another item from \"The Man of Honor\" item set to activate this item's \"Man of Honor Buff\"!", items = { { itemName = "The Enforcer", attributes = { ["fire rate bonus HIDDEN"] = 0.8, ["reload time increased hidden"] = 0.8 }, activeBuffDescription = "+20% faster fire rate and reload speed" }, { itemName = "The Big Earner", attributes = { ["dmg penalty vs players"] = 1.5, ["sanguisuge"] = 1 }, activeBuffDescription = "+50% damage bonus, absorbs the health of your victim on backstab" }, { itemName = "Cosa Nostra Cap", attributes = { ["mult cloak meter regen rate"] = 1.25 }, activeBuffDescription = "+25% cloak regen rate" }, { itemName = "The Made Man", attributes = { ["cloak consume rate decreased"] = 0.67 }, activeBuffDescription = "+33% cloak duration" } }, extraLoadoutItems = { [LOADOUT_POSITION_HEAD] = "Cosa Nostra Cap", [LOADOUT_POSITION_MISC] = "The Made Man" } }, ["Lawrence of Australia Buff"] = { class = TF_CLASS_SNIPER, requiredItems = 2, missingText = "Equip another item from the \"Lawrence of Australia\" item set to activate this item's \"Lawrence of Australia Buff\"!", items = { { itemName = "The Bazaar Bargain", attributes = { ["sniper charge per sec"] = 1.75, ["sniper only fire zoomed"] = 0 }, revertAttributes = { ["sniper only fire zoomed"] = 1 }, activeBuffDescription = "+75% charge rate, scoping no longer required to fire" }, { itemName = "The Shahanshah", attributes = { ["dmg bonus while half dead"] = 5, ["dmg penalty while half alive"] = 1 }, activeBuffDescription = "+375% damage while health is less than 50%, no damage penalty while health is 50% or more" }, { itemName = "Desert Marauder", attributes = { ["attribute immunity"] = "healing received penalty" }, activeBuffDescription = "Passive anti-heal immunity" } }, extraLoadoutItems = { [LOADOUT_POSITION_HEAD] = "Desert Marauder" } }, ["Croc-o-Style Buff"] = { class = TF_CLASS_SNIPER, requiredItems = 3, missingText = "Equip {remaining} more {itemplurality} from \"The Croc-o-Style Kit\" item set to activate this item's \"Croc-o-Style Buff\"!", items = { { itemName = "The Sydney Sleeper", attributes = { ["radius sleeper"] = 1, ["sniper no headshots"] = 0, ["minicrits become crits"] = 1 }, revertAttributes = { ["sniper no headshots"] = 1 }, activeBuffDescription = "Applies the \"Radius Sleeper\" overclock, minicrits become crits" }, { itemName = "Darwin's Danger Shield", attributes = { ["max health additive bonus"] = 50, ["mult dmgtaken from melee"] = 0.25, ["dmg taken from fire reduced"] = 0.25, ["dmg taken from crit reduced"] = 0.67 }, revertAttributes = { ["dmg taken from fire reduced"] = 0.5 }, activeBuffDescription = "+50 max health, +75% melee resist, +33% crit resist, +25% fire resist" }, { itemName = "The Bushwacka", attributes = { ["dmg taken increased"] = 1, ["mult crit dmg"] = 1.5 }, revertAttributes = { ["dmg taken increased"] = 1.2 }, activeBuffDescription = "+50% critical damage, no damage vulnerability on wearer" }, { itemName = "Ol' Snaggletooth", attributes = { ["addcond immunity"] = 123, ["mult stun resistance"] = 0, ["dmg taken from fire reduced"] = 0.35 }, activeBuffDescription = "Applies the Pyro's SPECIAL III upgrade (Gas immunity, +65% fire resistance)" } }, extraLoadoutItems = { [LOADOUT_POSITION_HEAD] = "Ol' Snaggletooth" } }, ["Dr. Grordbort's Brainiac Buff"] = { class = TF_CLASS_ENGINEER, requiredItems = 2, missingText = "Equip another item from \"Dr. Grordbort's Brainiac Pack\" item set to activate this item's \"Dr. Grordbort's Brainiac Buff\"!", items = { { itemName = "The Pomson 6000", attributes = { ["CARD: damage bonus"] = 1.75, ["energy weapon penetration"] = 1 }, activeBuffDescription = "+75% damage bonus, projectile changed to Bison's (can penetrate enemies)" }, { itemName = "Undying Macula V", -- pomson 6000 uberweapon attributes = { ["CARD: damage bonus"] = 1.45, ["projectile spread angle penalty"] = 5 }, specialItemDescriptionAttr = "special item description 4", activeBuffDescription = "+45% damage bonus, +5 degrees projectile deviation" -- the last one's practically a buff since UM fires the whole clip normally }, { itemName = "The Eureka Effect", attributes = { ["Construction rate decreased"] = 1.25, ["metal_pickup_decreased"] = 1.2, ["fire rate bonus"] = 0.85 }, revertAttributes = { ["Construction rate decreased"] = 0.75, ["metal_pickup_decreased"] = 0.8 }, activeBuffDescription = "+15% fire rate, weapon's downsides are inverted" }, { itemName = "The Brainiac Goggles", attributes = { ["upgrade rate decrease"] = 4 }, activeBuffDescription = "4x faster upgrade rate" }, { itemName = "The Brainiac Hairpiece", attributes = { ["engy sentry damage bonus"] = 2, ["dmg taken increased"] = 0.8 }, activeBuffDescription = "+100% bullet sentry damage, +20% damage resistance" } }, extraLoadoutItems = { [LOADOUT_POSITION_MISC] = "The Brainiac Goggles", [LOADOUT_POSITION_MISC2] = "The Brainiac Hairpiece" } }, ["Tank Buster Buff"] = { class = TF_CLASS_SOLDIER, requiredItems = 2, missingText = "Equip another item from \"The Tank Buster\" item set to activate this item's \"Tank Buster Buff\"!", items = { { itemName = "The Black Box", attributes = { ["health on radius damage"] = 50, ["fire full clip at once"] = 1, ["ignores other projectiles"] = 1, ["projectile spread angle penalty"] = 2, ["clip size penalty"] = 1.25, ["projectile speed decreased"] = 1.2, ["rocket jump damage reduction"] = 0.5 }, revertAttributes = { ["health on radius damage"] = 5, ["clip size penalty"] = 0.75, ["projectile speed decreased"] = 0.8 }, activeBuffDescription = "Up to +50 health on hit, fires entire clip at once, weapon's downsides are inverted" }, { itemName = "The Battalion's Backup", attributes = { ["effect add attributes"] = "mult dmgtaken from melee|0.5|dmg taken increased|0.65|uber on damage taken|0.1|teleport instead of die|1" }, revertAttributes = { ["effect add attributes"] = "mult dmgtaken from melee|0.65" }, activeBuffDescription = "While effect is active - +50% melee resist, +35% damage resist, 10% chance of uber on hit, and 100% chance of teleporting to spawn instead of dying", specialItemDescriptionAttr = "special item description 2" }, { itemName = "The Grenadier's Softcap", attributes = { ["maxammo primary increased"] = 1.25, ["move speed bonus"] = 1.1 }, activeBuffDescription = "+25% max primary ammo, +10% move speed" }, { itemName = "player", attributes = { ["attribute immunity"] = "healing received penalty" }, activeBuffDescription = "Passive anti-heal immunity" } }, extraLoadoutItems = { [LOADOUT_POSITION_HEAD] = "The Grenadier's Softcap" } }, ["Hibernating Bear Buff"] = { class = TF_CLASS_HEAVYWEAPONS, requiredItems = 3, missingText = "Equip {remaining} more {itemplurality} from \"The Hibernating Bear\" item set to activate this item's \"Hibernating Bear Buff\"!", items = { { itemName = "The Brass Beast", attributes = { ["damage bonus"] = 2, ["aiming movespeed decreased"] = 1.6, ["minigun spinup time increased"] = 0.5, ["spunup_damage_resistance"] = 0.25 }, revertAttributes = { ["damage bonus"] = 1.2, ["aiming movespeed decreased"] = 0.4, ["minigun spinup time increased"] = 1.5, ["spunup_damage_resistance"] = 0.25 }, activeBuffDescription = "+80% damage bonus, +55% damage resistance while deployed with <50% health, weapon's downsides are inverted" }, { itemName = "The Buffalo Steak Sandvich", attributes = { ["effect add attributes"] = "minicrits become crits|1|dmg current health|0.01", ["energy buff dmg taken multiplier"] = 1 }, revertAttributes = { ["energy buff dmg taken multiplier"] = 1.2 }, activeBuffDescription = "While effect is active - deal 1% of target's current health as damage and turn minicrits into crits" }, { itemName = "Warrior's Spirit", attributes = { ["provide on active"] = 0, ["dmg taken increased"] = 0.7, ["heal on kill"] = 150 }, revertAttributes = { ["provide on active"] = 1, ["dmg taken increased"] = 1.3, ["heal on kill"] = 50 }, activeBuffDescription = "+100 health on melee kill, weapon's downside is inverted, weapon effects (only damage resistance) no longer require holding it" }, { itemName = "Big Chief", attributes = { ["move speed bonus"] = 1.15 }, activeBuffDescription = "+15% move speed" } }, extraLoadoutItems = { [LOADOUT_POSITION_HEAD] = "Big Chief" } }, ["Isolated Merc Set"] = { -- alien: isolation item set, this is an exception instead of the rule class = TF_CLASS_PYRO, requiredItems = 2, hiddenWhenInactive = true, -- secret set buff since this is a 1-weapon item set missingText = nil, items = { { itemName = "The Nostromo Napalmer", attributes = { ["damage bonus"] = 2, ["airblast cost decreased"] = 0, ["mult airblast refire time"] = 0.25 }, activeBuffDescription = "+100% damage, no airblast cost, +75% faster airblast refire" }, { itemName = "The MK 50", attributes = { ["attribute immunity"] = "healing received penalty", ["health regen"] = 10 }, activeBuffDescription = "+10 health regen, passive anti-heal immunity" } } }, ["Isolationist Pack"] = { -- alien: isolation item set, this is an exception instead of the rule class = TF_CLASS_SCOUT, requiredItems = 3, hiddenWhenInactive = true, -- secret set buff since it's an all-cosmetic item set missingText = nil, items = { { itemName = "The Alien Cranium", attributes = { ["dmg taken from crit reduced"] = 0.5 }, activeBuffDescription = "+50% crit resistance" }, { itemName = "The Biomech Backpack", attributes = { ["dmg taken from fire reduced"] = 0.25, ["dmg taken from blast reduced"] = 0.5, ["dmg taken from bullets reduced"] = 0.5, ["mult dmgtaken from melee"] = 0.5 }, activeBuffDescription = "+75% fire resist, +50% resist from other types of damage" }, { itemName = "The Xeno Suit", attributes = { ["move speed bonus"] = 1.1, ["damage bonus"] = 1.25, ["health regen"] = 5 }, activeBuffDescription = "+5 health regen, +25% damage bonus, +10% move speed" } } }, ["Gas Jockey's Buff"] = { class = TF_CLASS_PYRO, requiredItems = 2, missingText = "Equip another item from \"The Gas Jockey's Gear\" item set to activate this item's \"Gas Jockey's Buff\"!", items = { { itemName = "The Degreaser", attributes = { ["damage bonus"] = 1.75, ["airblast cost decreased"] = 0, ["mult airblast refire time"] = 0.25, ["airblast cost increased"] = 1, ["weapon burn dmg reduced"] = 1.66 }, revertAttributes = { ["airblast cost increased"] = 1.25, ["weapon burn dmg reduced"] = 0.34 }, activeBuffDescription = "+75% damage bonus and faster airblast refire, no airblast cost, afterburn damage penalty is inverted" }, { itemName = "The Powerjack", attributes = { ["provide on active"] = 0, ["dmg taken increased"] = 0.8, ["dmg taken from crit reduced"] = 0.5 }, revertAttributes = { ["provide on active"] = 1, ["dmg taken increased"] = 1.2 }, activeBuffDescription = "+50% crit resist, weapon downside is inverted, weapon effects (except heal on kill) no longer require holding it" }, { itemName = "The Attendant", attributes = { ["max health additive bonus"] = 50 }, activeBuffDescription = "+50 max health" } }, extraLoadoutItems = { [LOADOUT_POSITION_HEAD] = "The Attendant" } }, ["Black Market Business Buff"] = { class = TF_CLASS_HEAVYWEAPONS, requiredItems = 3, missingText = "Equip {remaining} more {itemplurality} from the \"Black Market Business\" item set to activate this item's \"Black Market Business Buff\"!", items = { { itemName = "Tomislav", attributes = { ["damage bonus"] = 1.5, ["weapon spread bonus"] = 0.1, ["fire rate penalty"] = 0.5 }, revertAttributes = { ["weapon spread bonus"] = 0.8, ["fire rate penalty"] = 1.2 }, activeBuffDescription = "+70% faster fire rate and increased accuracy, +50% damage bonus" }, { itemName = "The Family Business", attributes = { ["damage penalty"] = 1.6, ["reload time increased hidden"] = 0.85 }, revertAttributes = { ["damage penalty"] = 0.85 }, activeBuffDescription = "+75% damage bonus, +15% faster reload speed" }, { itemName = "The Eviction Notice", attributes = { ["maxammo primary increased"] = 2, ["maxammo secondary increased"] = 2, ["move speed bonus"] = 1.15, ["provide on active"] = 0, ["mod_maxhealth_drain_rate"] = 0, ["mult_player_movespeed_active"] = 1, ["self mark for death"] = 0, ["dmg taken from crit increased"] = 0, ["damage penalty"] = 1.6 }, revertAttributes = { ["provide on active"] = 1, ["mult_player_movespeed_active"] = 1.15, ["mod_maxhealth_drain_rate"] = 0, ["self mark for death"] = 1, ["dmg taken from crit increased"] = 1.05, ["damage penalty"] = 0.4 }, activeBuffDescription = "+100% max ammo, damage penalty is inverted, passive move speed bonus no longer requires holding this weapon" }, { itemName = "Capone's Capper", attributes = { ["max health additive bonus"] = 100, ["dmg taken from bullets reduced"] = 0.5 }, activeBuffDescription = "+100 max health, +50% bullet resistance" }, { itemName = "player", -- today i learned that this attribute is horribly bugged attributes = { ["mod_maxhealth_drain_rate"] = -10 } } }, extraLoadoutItems = { [LOADOUT_POSITION_HEAD] = "Capone's Capper" } }, ["Medieval Medic Buff"] = { class = TF_CLASS_MEDIC, requiredItems = 2, missingText = "Equip another item from \"The Medieval Medic\" item set to activate this item's \"Medieval Medic Buff\"!", items = { { itemName = {"The Crusader's Crossbow", "Festive Crusader's Crossbow"}, attributes = { ["maxammo primary reduced"] = 1, ["penetration damage penalty"] = 1.5, ["projectile penetration"] = 1 }, revertAttributes = { ["maxammo primary reduced"] = 0.25 }, activeBuffDescription = "Crossbow bolts can penetrate and have +50% penetration damage, no max primary ammo penalty" }, { itemName = "The Amputator", attributes = { ["provide on active"] = 0, ["damage penalty"] = 1.2, ["health regen"] = 10, ["healing received bonus"] = 1.5, ["attribute immunity"] = "healing received penalty", ["aoe heal chance"] = 150 }, revertAttributes = { ["provide on active"] = 1, ["damage penalty"] = 0.8, ["health regen"] = 3 }, activeBuffDescription = "+7 health regen, +50% received healing, damage penalty is inverted, passive anti-heal immunity, chance of AoE heal on hit, weapon's passive effects no longer require holding it" }, { itemName = "Berliner's Bucket Helm", attributes = { ["dmg taken from crit reduced"] = 0.75, ["dmg taken from bullets reduced"] = 0.5, ["dmg taken from blast reduced"] = 0.5, ["mult dmgtaken from melee"] = 0.5 }, activeBuffDescription = "+50% bullet, blast and melee resist, +25% crit resist" } }, extraLoadoutItems = { [LOADOUT_POSITION_HEAD] = "Berliner's Bucket Helm" } }, ["Expert's Ordnance Buff"] = { class = TF_CLASS_DEMOMAN, requiredItems = 2, missingText = "Equip another item from \"The Expert's Ordnance\" item set to activate this item's \"Expert's Ordnance Buff\"!", items = { { itemName = "The Loch-n-Load", attributes = { ["sticky air burst mode"] = 0, ["CARD: damage bonus"] = 1.5, ["Blast radius decreased"] = 2, ["clip size penalty"] = 1.25 }, revertAttributes = { ["Blast radius decreased"] = 0.75, ["clip size penalty"] = 0.75 }, activeBuffDescription = "+125% blast radius, +50% damage bonus, clip size penalty is inverted" }, { itemName = "Howitzer", attributes = { ["Reload time decreased"] = 0.8 }, activeBuffDescription = "+20% faster reload speed", hiddenWhenInactive = true -- can also be set on individual items, but is overriden by set-wide hiddenWhenInactive }, { itemName = "The Ullapool Caber", attributes = { ["dmg penalty vs players"] = 1.1 }, revertAttributes = { ["dmg penalty vs players"] = 0.8 }, activeBuffDescription = "+30% damage bonus", specialItemDescriptionAttr = "special item description 3" }, { itemName = "Scotch Bonnet", attributes = { ["dmg taken increased"] = 0.65, ["maxammo primary increased"] = 1.15, ["maxammo secondary increased"] = 1.15 }, activeBuffDescription = "+35% damage resistance, +15% max ammo" } }, extraLoadoutItems = { [LOADOUT_POSITION_HEAD] = "Scotch Bonnet" } }, ["Swashbuckler's Buff"] = { class = TF_CLASS_DEMOMAN, requiredItems = 2, missingText = "Equip another item from the \"Swashbuckler's Swag\" item set to activate this item's \"Swashbuckler's Buff\"!", items = { { itemName = "The Bootlegger", attributes = { ["max health additive bonus"] = 150, ["kill refills meter"] = 0.25, ["maxammo secondary increased"] = 1.2 }, revertAttributes = { ["max health additive bonus"] = 75, ["kill refills meter"] = 0.05 }, activeBuffDescription = "+75 max health, +20% charge on melee kill, +20% max secondary ammo" }, { itemName = "The Scottish Handshake", attributes = { ["damage bonus"] = 2, ["enables aoe heal"] = 1, ["heal on kill"] = 75, ["mult_player_movespeed_active"] = 1.2, ["add cond when active"] = 11 }, activeBuffDescription = "+100% damage bonus, +20% move speed while active, +75 health on kill, AoE healing while taunting with this weapon, always crits" }, { itemName = "The Buccaneer's Bicorne", attributes = { ["dmg taken increased"] = 0.8 }, activeBuffDescription = "+20% damage resistance" }, { itemName = "A Whiff of the Old Brimstone", attributes = { ["damage bonus"] = 1.5 }, activeBuffDescription = "+50% damage bonus on all weapons" } }, extraLoadoutItems = { [LOADOUT_POSITION_HEAD] = "The Buccaneer's Bicorne", [LOADOUT_POSITION_MISC] = "A Whiff of the Old Brimstone" } }, ["Dr. Grordbort's Victory Buff"] = { class = TF_CLASS_SOLDIER, requiredItems = 2, missingText = "Equip another item from \"Dr. Grordbort's Victory Pack\" item set to activate this item's \"Dr. Grordbort's Victory Buff\"!", items = { { itemName = "The Cow Mangler 5000", attributes = { ["CARD: damage bonus"] = 1.5, ["minicrits become crits"] = 1, ["crits_become_minicrits"] = 0 }, revertAttributes = { ["crits_become_minicrits"] = 1 }, activeBuffDescription = "+50% damage bonus, minicrits-crits conversion is reversed" }, { itemName = "The Righteous Bison", attributes = { ["CARD: damage bonus"] = 1.75, ["projectile spread angle penalty"] = 0.25 }, revertAttributes = { ["projectile spread angle penalty"] = 0.5 }, activeBuffDescription = "+75% damage bonus, -0.25 degrees projectile spread" }, { itemName = "Undying Macula M", -- righteous bison uberweapon attributes = { ["CARD: damage bonus"] = 1.45, ["projectile spread angle penalty"] = 5 }, specialItemDescriptionAttr = "special item description 4", activeBuffDescription = "+45% damage bonus, +5 degrees projectile deviation" -- the last one's practically a buff since UM fires the whole clip normally }, { itemName = "Lord Cockswain's Pith Helmet", attributes = { ["health regen"] = 10 }, activeBuffDescription = "+10 health regen" }, { itemName = "Lord Cockswain's Novelty Mutton Chops and Pipe", attributes = { ["dmg taken increased"] = 0.75 }, activeBuffDescription = "+25% damage resistance" } }, extraLoadoutItems = { [LOADOUT_POSITION_HEAD] = "Lord Cockswain's Pith Helmet", [LOADOUT_POSITION_MISC] = "Lord Cockswain's Novelty Mutton Chops and Pipe" } }, ["Dr. Grordbort's Moonman Buff"] = { -- arguably the second-largest set after the pyroland items class = TF_CLASS_PYRO, requiredItems = 3, missingText = "Equip {remaining} more {itemplurality} from \"Dr. Grordbort's Moonman Pack\" item set to activate this item's \"Dr. Grordbort's Moonman Buff\"!", items = { { itemName = "The Phlogistinator", attributes = { ["mult crit dmg"] = 1.5, ["dmg taken increased"] = 0.67 }, activeBuffDescription = "+50% critical damage, +33% damage resistance" }, { itemName = "Incinerator", -- phlog uberweapon attributes = { ["flame ammopersec increased"] = 1.5 }, specialItemDescriptionAttr = "special item description 4", activeBuffDescription = "-50% ammo consumption" }, { itemName = "The Manmelter", attributes = { ["CARD: damage bonus"] = 3.5, ["mult crit dmg"] = 1.75, ["fire rate penalty HIDDEN"] = 0.65, ["minicrits become crits"] = 1, ["damage bonus vs burning"] = 2 }, activeBuffDescription = "+250% damage, +100% damage vs burning zombies, +75% critical damage, +35% fire rate, minicrits become crits" }, { itemName = "The Third Degree", attributes = { ["crit vs burning players"] = 1 }, activeBuffDescription = "Crits vs burning players" }, { itemName = "The Bubble Pipe", attributes = { ["dmg taken increased"] = 0.8 }, activeBuffDescription = "+20% damage resistance" }, { itemName = "The Moonman Backpack", attributes = { ["maxammo primary increased"] = 1.5 }, activeBuffDescription = "+50% max primary ammo" } }, extraLoadoutItems = { [LOADOUT_POSITION_HEAD] = "The Bubble Pipe", [LOADOUT_POSITION_MISC] = "The Moonman Backpack" } }, ["#1 Fan's Buff"] = { class = TF_CLASS_SCOUT, requiredItems = 3, missingText = "Equip {remaining} more {itemplurality} from \"The #1 Fan\" item set to activate this item's \"#1 Fan's Buff\"!", items = { { itemName = "The Soda Popper", attributes = { ["minicrits become crits"] = 1, ["maxammo secondary increased"] = 2 }, activeBuffDescription = "Minicrits become crits, +100% max secondary ammo" }, { itemName = "The Winger", attributes = { ["clip size penalty"] = 1.6, ["maxammo primary increased"] = 1.5 }, revertAttributes = { ["clip size penalty"] = 0.4 }, activeBuffDescription = "Clip size penalty is inverted, +50% max primary ammo" }, { itemName = "The Atomizer", attributes = { ["single wep deploy time increased"] = 0.5, ["dmg penalty vs players"] = 1.5, ["mult_player_movespeed_active"] = 1.15 }, revertAttributes = { ["single wep deploy time increased"] = 1.5, ["dmg penalty vs players"] = 0.85 }, activeBuffDescription = "+65% damage bonus, +15% move speed on active, deploy time penalty is inverted" }, { itemName = "Bonk Boy", attributes = { ["move speed as health decreases"] = 2 }, activeBuffDescription = "Move speed increases as health decreases" } }, extraLoadoutItems = { [LOADOUT_POSITION_MISC] = "Bonk Boy" } }, ["Urban Professional Buff"] = { class = TF_CLASS_SNIPER, requiredItems = 2, missingText = "Equip another item from \"The Urban Professional\" item set to activate this item's \"Urban Professional Buff\"!", items = { { itemName = "The Hitman's Heatmaker", attributes = { ["sniper only fire zoomed"] = 0 }, revertAttributes = { ["sniper only fire zoomed"] = 1 }, activeBuffDescription = "Scoping no longer required to fire" }, { itemName = "The Cleaner's Carbine", attributes = { ["effect cond override"] = 11 }, activeBuffDescription = "CRIKEY effect grants crits instead of minicrits" }, { itemName = "Liquidator's Lid", attributes = { ["heal on kill"] = 25 }, activeBuffDescription = "+25 health on kill" } }, extraLoadoutItems = { [LOADOUT_POSITION_HEAD] = "Liquidator's Lid" } }, ["Airborne Armanents Buff"] = { -- WAS the final official item set to receive a set buff, at least until valve adds more item sets again class = TF_CLASS_SOLDIER, requiredItems = 3, missingText = "Equip {remaining} more {itemplurality} from \"The Airborne Armanents\" item set to activate this item's \"Airborne Armanents Buff\"!", items = { { itemName = "The Liberty Launcher", attributes = { ["self dmg push force increased"] = 30 }, activeBuffDescription = "Allows rocket jumping in Divine Delusions/Infinite Insanity" }, { itemName = "The Reserve Shooter", attributes = { ["add cond when active"] = 19 }, activeBuffDescription = "Always mini-crits when active (unless there's a Crit boost)" }, { itemName = "The Market Gardener", attributes = { ["speed_boost_on_kill"] = 8, ["fire rate bonus"] = 0.70 }, activeBuffDescription = "+30% faster fire rate, 8 seconds of speed boost on kill" }, { itemName = "Jumper's Jeepcap", attributes = { ["afterburn immunity"] = 1, ["fire retardant"] = 1, ["attribute immunity"] = "healing received penalty" }, activeBuffDescription = "Passive afterburn and anti-heal immunity" }, { itemName = "player", attributes = { ["parachute attribute"] = 1, ["parachute redeploy"] = 1, ["boots falling stomp"] = 1 }, activeBuffDescription = "Can deploy parachute, Mantreads stomp" } }, extraLoadoutItems = { [LOADOUT_POSITION_HEAD] = "Jumper's Jeepcap" } }, ["General's Formals Buff"] = { -- so as it turns out, the mantreads wasn't actually banned in the mission. i just got mandela effect'd class = TF_CLASS_SOLDIER, requiredItems = 2, missingText = "Equip another item from \"The General's Formals\" item set to activate this item's \"General's Formals Buff\"!", items = { { itemName = "The Mantreads", attributes = { ["parachute attribute"] = 1, ["parachute redeploy"] = 1 }, activeBuffDescription = "Can deploy parachute" }, { itemName = "The Disciplinary Action", attributes = { ["speed_boost_on_hit_enemy"] = 2, ["damage penalty"] = 1 }, activeBuffDescription = "Speed boost also applies to self when hitting the enemy, damage penalty is removed" }, { itemName = "Armored Authority", attributes = { ["rocket jump damage reduction"] = 0.4 }, activeBuffDescription = "-60% self-damage on rocket jumping" }, { itemName = "Fancy Dress Uniform", attributes = { ["health regen"] = 10 }, activeBuffDescription = "+10 health regen" }, { itemName = "player", attributes = { ["self dmg push force increased"] = 30 }, activeBuffDescription = "Allows rocket jumping in Divine Delusions/Infinite Insanity" } }, extraLoadoutItems = { [LOADOUT_POSITION_HEAD] = "Armored Authority", [LOADOUT_POSITION_MISC] = "Fancy Dress Uniform" } }, ["Soviet Pugilist Buff"] = { -- the first custom item set in the game class = TF_CLASS_HEAVYWEAPONS, requiredItems = 2, missingText = "Equip both the \"Steel Commanders\" and the \"Heavy-Duty Armor\" to activate this item's \"Soviet Pugilist Buff\"!", items = { { itemName = "Heavy-Duty Armor", -- primary item that traded raw DPS for strong passive buffs attributes = { ["max health additive bonus"] = 100, ["health regen"] = 10, ["dmg taken increased"] = 0.6 }, specialItemDescriptionAttr = "special item description 3", activeBuffDescription = "+100 flat max health, +10 health regen, +40% damage resistance" }, { itemName = "Steel Commanders", -- secondary item that traded reliability for strong passive buffs attributes = { ["move speed bonus"] = 1.25, ["dmg taken from crit reduced"] = 0.5, ["dmg taken increased"] = 0.75 }, revertAttributes = { ["move speed bonus"] = 1.1 }, activeBuffDescription = "+50% crit resistance, +25% damage resistance, +15% move speed" }, { itemName = "player", attributes = { ["speed_boost_on_hit"] = 10, ["speed_boost_on_kill"] = 10, ["has pipboy build interface"] = 29 } } } } } local function SIDSanitizer(string) if string ~= "special item description 2" and string ~= "special item description 3" and string ~= "special item description 4" then return "special item description" end return string end -- fun fact: this function worked perfectly without a hitch the first time. no, really. no bugs, no logic errors, no syntax errors, no accidentally fucking up the entire lua file, nothing. local function ApplySetBuffs(player, setBuffName) -- check if specified set buff exists local schema = Set_Buffs[setBuffName] or nil if not schema then return end -- check if proper class local setBuffClass = schema.class if type(setBuffClass) == "table" then local niceclass = false for _, class in ipairs(setBuffClass) do if player.m_iClass == class then niceclass = true end end if not niceclass then return end elseif setBuffClass ~= nil then if player.m_iClass ~= setBuffClass then return end end -- equipped item evaluation -- equippedItems structure: -- { -- [] = { -- item = Entity from player:GetPlayerItemByName, -- data = table from the items sub-table -- } -- } local itemCount = 0 local equippedItems = {} for _, data in ipairs(schema.items) do local iname = data.itemName local itemgot = nil if type(iname) == "table" then for _, nm in ipairs(iname) do itemgot = player:GetPlayerItemByName(nm) or nil if itemgot then iname = nm break end end elseif iname == "player" then equippedItems["player"] = {} equippedItems["player"].item = player equippedItems["player"].data = data goto continue_A else itemgot = player:GetPlayerItemByName(data.itemName) or nil end if itemgot then itemCount = itemCount + 1 equippedItems[iname] = {} equippedItems[iname].item = itemgot equippedItems[iname].data = data end ::continue_A:: end -- case F: not enough set items equipped if itemCount < schema.requiredItems then for name, sd in pairs(equippedItems) do local data = sd.data local item = sd.item local SID = SIDSanitizer(data.specialItemDescriptionAttr or "special item description") if name == "player" then for attr, value in pairs(data.attributes) do if data.revertAttributes then player:SetAttributeValue(attr, data.revertAttributes[attr] or nil) else player:SetAttributeValue(attr, nil) end end player:SetAttributeValue(SID, nil) else for attr, value in pairs(data.attributes) do if data.revertAttributes then item:SetAttributeValue(attr, data.revertAttributes[attr] or nil) else item:SetAttributeValue(attr, nil) end end if schema.hiddenWhenInactive and schema.hiddenWhenInactive == true then item:SetAttributeValue(SID, nil) elseif data.hiddenWhenInactive and data.hiddenWhenInactive == true then item:SetAttributeValue(SID, nil) elseif schema.missingText ~= nil then local mtext = schema.missingText mtext = string.gsub(mtext, "{remaining}", schema.requiredItems - itemCount) mtext = string.gsub(mtext, "{itemplurality}", schema.requiredItems - itemCount == 1 and "item" or "items") -- and-or idiom is NOT a good substitute for ternary operator imo item:SetAttributeValue(SID, mtext) end end end if schema.extraLoadoutItems then for slot, item in pairs(schema.extraLoadoutItems) do player:AcceptInput("$StripExtraItem", item) end end return end -- case P: apply set item buffs (and player buffs) for name, sd in pairs(equippedItems) do local data = sd.data local item = sd.item local SID = SIDSanitizer(data.specialItemDescriptionAttr or "special item description") for attr, value in pairs(data.attributes) do item:SetAttributeValue(attr, value) end if name == "player" and not data.activeBuffDescription then goto continue_B end if data.activeBuffDescription ~= nil then item:SetAttributeValue(SID, string.format( "%s: %s", setBuffName, data.activeBuffDescription or "???" )) end ::continue_B:: if schema.extraLoadoutItems then for slot, item in pairs(schema.extraLoadoutItems) do player:AcceptInput("$AwardExtraItem", item) end end end end -- lasagna code, ladies and gentlemen. local Lunar_Items = { "Moonlight Runner", "Saturn V", "Moonman's Torch", "Dirge of Syzygy", "Moonwalker", "Selenium Saber", "Luna 2", "Synodic Crescent", "Lunistice", "Soothing Lunacy", "Nocturnal Frost", "Night Vigil", "Moonlight Prowler", "Silvermoon Wing" } function LunarItemEffect(player, item) local currentMoonPhase = moonPhase() local phaseName = moonPhaseNames[currentMoonPhase] if item:GetItemName() == "Lunistice" then local sentryTypes = { "Homing Rocket Sentry", "Jarate Bolt Sentry Lunistice Edition", "Fire Sentry Lunistice Edition", "Bomb Sentry Lunistice Edition", nil, "Homing Fire Sentry", "Rocket Sentry Lunistice Edition", "Arrow Sentry Lunistice Edition" } local ammoTypeName = {"Homing Rocket", "Jarate Bolt", "Flaming", "Bomb", "Bullet", "Homing Flare", "Rocket", "Arrow"} local buildingRGB = { ["Homing Rocket Sentry"] = 65280, ["Jarate Bolt Sentry Lunistice Edition"] = 65535, ["Fire Sentry Lunistice Edition"] = 16711680, ["Bomb Sentry Lunistice Edition"] = 255, ["Homing Fire Sentry"] = 16711680, ["Rocket Sentry Lunistice Edition"] = 65280, ["Arrow Sentry Lunistice Edition"] = 16777113, } local phaseBasedType = sentryTypes[currentMoonPhase] local buildingColor = buildingRGB[phaseBasedType] or nil local currentSentryType = item:GetAttributeValue("sentry bullet weapon") or nil if phaseBasedType ~= currentSentryType then player:Print(1, string.format( "Lunar Phase has progressed to: %s. Sentry bullet type has been changed to %s.", phaseName, ammoTypeName[currentMoonPhase] )) item:SetAttributeValue("special item description", string.format("%s: Sentry bullet type is set to %s.", phaseName, ammoTypeName[currentMoonPhase])) item:SetAttributeValue("sentry bullet weapon", phaseBasedType) item:SetAttributeValue("building color rgb", buildingColor) end end end function OnGameTick() for _, marker in pairs(ents.FindAllByClass("entity_revive_marker")) do local owner = marker.m_hOwner if IsValid(owner) then -- If the owner is alive or not on Red Team, remove the marker and button if owner:IsAlive() or owner.m_iTeamNum ~= 2 then if marker.skymarker and IsValid(marker.skymarker) then marker.skymarker:Remove() marker.skymarker = nil end marker:Remove() end end end for _, player in pairs(ents.GetAll()) do -- changing from GetAllPlayers to GetAll if player:IsRealPlayer() then if player.m_bUsingActionSlot == 1 and player.InteractCooldown ~= true then player.HoldTime = player.HoldTime + 1 if player.HoldTime > 13 and player.InteractWith ~= nil then Interact(player) player.InteractCooldown = true player.HoldTime = 0 timer.Simple(1, function() player.InteractCooldown = false end) end else player.holdTime = 0 end player:GetUserId() for k, v in pairs(ents.FindByClass("tf_player_manager"):DumpProperties().m_iUserID) do if v == player:GetUserId() then ents.FindByClass("tf_player_manager"):AcceptInput("$SetProp$m_iCurrencyCollected$" .. k-1, player.m_nCurrency) end end --if player.m_nCurrencyDiff ~= player.m_nCurrency then -- if player.m_nCurrency - player.m_nCurrencyDiff > 0 then -- player.CashText = 132 -- player:ShowHudText({channel = 4, x = 0.04, y = 0.91, b1 = 0, b2 = 0}, "+"..player.m_nCurrency - player.m_nCurrencyDiff) -- else -- player.CashText = 132 -- player:ShowHudText({channel = 4, x = 0.04, y = 0.91, g1 = 25, g2 = 25, b1 = 0, b2 = 0,}, player.m_nCurrency - player.m_nCurrencyDiff) -- end --end --player.m_nCurrencyDiff = player.m_nCurrency --player.CashText = player.CashText - 1 --if player.CashText == 0 then player:ShowHudText({channel = 4}, "") end local function disableSapper() if player.m_iClass ~= 8 then return end player:WeaponStripSlot(1) end disableSapper() -- Mannpower balances ------------------------------------------------------- local function setAttributes(cond, attributes) if player:InCond(cond) == true then for attr, value in pairs(attributes) do player:SetAttributeValue(attr, value) end else for attr, _ in pairs(attributes) do player:SetAttributeValue(attr, nil) end end end setAttributes(97, {["increased jump height from weapon"] = 0.55, ["mult_player_movespeed_active"] = 0.8}) -- Agility setAttributes(92, {["health drain"] = 10}) -- Regeneration setAttributes(91, {["fire rate penalty"] = 2, ["move speed bonus"] = 0.769}) -- Haste setAttributes(94, {["dmg taken increased"] = 2.5}) -- Vampire setAttributes(103, {["dmg penalty vs players"] = 6, ["ubercharge rate penalty"] = 1.01, ["dmg taken increased"] = 0.5}) -- Knockout, since Mannpower removal is virtually useless after Tread (uber rate "penalty" is for removal of melee's money penalty) setAttributes(110, {["dmg taken increased"] = 0.33, ["health drain"] = 25, ["mult bleeding dmg"] = 1.5, ["dmg penalty vs players"] = 2}) -- Plague ----------------------------------------------------------------------------- local function applyWarlockEffects(cond, class, packDecrease) if player:InCond(cond) == true and player.m_iClass == class then if packDecrease then player:SetAttributeValue("health from packs decreased", packDecrease) end elseif player:InCond(cond) ~= true and player.m_iClass == class then if packDecrease then player:SetAttributeValue("health from packs decreased", nil) end end end local function applyKnockoutEffects(cond, class, packIncrease, fireRateBonus) if player:InCond(cond) == true and player.m_iClass == class then player:SetAttributeValue("health from packs increased", packIncrease) player:SetAttributeValue("dmg pierces resists absorbs", 1) if fireRateBonus then player:SetAttributeValue("fire rate bonus", fireRateBonus) end --player:WeaponStripSlot(0) --player:WeaponStripSlot(1) player:WeaponSwitchSlot(2) elseif player:InCond(cond) ~= true and player.m_iClass == class then player:SetAttributeValue("health from packs increased", nil) if player.m_iClass == 6 then local spec2Check = player:GetAttributeValue("is_operation_pass") or 0 if spec2Check ~= 29 then player:SetAttributeValue("dmg pierces resists absorbs", nil) end elseif player.m_iClass == 5 then local specACheck = player:GetAttributeValue("cannot giftwrap") or 0 if specACheck ~= 1 then player:SetAttributeValue("dmg pierces resists absorbs", nil) end else player:SetAttributeValue("dmg pierces resists absorbs", nil) end if fireRateBonus then player:SetAttributeValue("fire rate bonus", nil) end end end -- Warlock effects (Condition 95) applyWarlockEffects(95, 1, 1.5) -- Scout applyWarlockEffects(95, 2, 1.5) -- Soldier applyWarlockEffects(95, 7, 1.5) -- Pyro applyWarlockEffects(95, 4, 1.5) -- Demoman applyWarlockEffects(95, 6, 1.5) -- Heavy applyWarlockEffects(95, 9, 1.5) -- Engineer applyWarlockEffects(95, 5, 1.5) -- Medic applyWarlockEffects(95, 2, 1.5) -- Sniper applyWarlockEffects(95, 8, 1.25) -- Spy -- Knockout effects (Condition 103) applyKnockoutEffects(103, 1, 0.625) -- Scout applyKnockoutEffects(103, 3, 0.625, 0.85) -- Soldier applyKnockoutEffects(103, 7, 0.625, 0.85) -- Pyro applyKnockoutEffects(103, 4, 0.625, 0.85) -- Demoman applyKnockoutEffects(103, 6, 0.625, 0.85) -- Heavy applyKnockoutEffects(103, 9, 0.625, 0.85) -- Engineer applyKnockoutEffects(103, 5, 0.625, 0.85) -- Medic applyKnockoutEffects(103, 2, 0.625, 0.85) -- Sniper applyKnockoutEffects(103, 8, 0.625, 0.85) -- Spy ----------------------------------------------------------------------------------------------------------- limit to 1 job local conditions = {97, 90, 92, 93, 91, 96, 95, 94, 103, 109, 110} local function removeIfHasOtherConditions(cond) for _, otherCond in ipairs(conditions) do if cond ~= otherCond and player:InCond(otherCond) == true then player:RemoveCond(cond) return end end end for _, cond in ipairs(conditions) do if player:InCond(cond) == true then removeIfHasOtherConditions(cond) end end local steamid = player:GetSteamId() local recordedMannpower = playerMannpower[steamid] or nil for _, mcond in ipairs(conditions) do if player:IsAlive() then if recordedMannpower then if recordedMannpower == mcond and not player:InCond(mcond) then player:Print(2, "You cannot remove your Mannpower powerup.") player:AddCond(mcond) end elseif not recordedMannpower and player:InCond(mcond) then playerMannpower[steamid] = mcond end end end -- local primaryslot = player:GetPlayerItemBySlot(LOADOUT_POSITION_PRIMARY) -- if player.m_iClass == 7 and primaryslot:GetItemName() == "Incinerator" then -- player:SetAttributeValue("rage receive scale", 0.01) -- phlog-like flamethrowers literally gain a lot of mmmph in a short time -- else -- player:SetAttributeValue("rage receive scale", nil) -- end if player:InCond(64) or player:InCond(4) then player:SetAttributeValue("ignored by bots", 1) else player:SetAttributeValue("ignored by bots", nil) end if infMoneyMode and player.m_nCurrency ~= 290204 then player.m_nCurrency = 290204 end if player.m_iTeamNum == 2 and waveCount > 0 then playerCurrentCash[player:GetSteamId()] = player.m_nCurrency end local dsp = player:SetAttributeValue("SET BONUS: special dsp") or 0 if player:InCond(74) then player:SetAttributeValue("SET BONUS: special dsp", 45) elseif player:InCond(75) then player:SetAttributeValue("SET BONUS: special dsp", 44) elseif dsp ~= 134 then player:SetAttributeValue("SET BONUS: special dsp", nil) end if soloMode then -- no revive markers in solo mode player:SetAttributeValue("no revive", 1) end playerWeakenedMannpower[player] = playerWeakenedMannpower[player] or false if playerWeakenedMannpower[player] then player:AddCond(129) else player:RemoveCond(129) end -- set buffs are disabled in hardmode because they're very powerful -- the code remains tho to not break shit -- ApplySetBuffs(player, "Pyroland Buff") -- ApplySetBuffs(player, "Howitzer Hybridknight's Blessing") -- ApplySetBuffs(player, "Special Delivery Buff") -- ApplySetBuffs(player, "1001 Demoknights Buff") -- ApplySetBuffs(player, "Clinical Trial Buff") -- ApplySetBuffs(player, "Public Enemy Buff") -- ApplySetBuffs(player, "Man of Honor Buff") -- ApplySetBuffs(player, "Lawrence of Australia Buff") -- ApplySetBuffs(player, "Croc-o-Style Buff") -- ApplySetBuffs(player, "Dr. Grordbort's Brainiac Buff") -- ApplySetBuffs(player, "Tank Buster Buff") -- ApplySetBuffs(player, "Hibernating Bear Buff") -- ApplySetBuffs(player, "Isolated Merc Set") -- ApplySetBuffs(player, "Isolationist Pack") -- ApplySetBuffs(player, "Gas Jockey's Buff") -- ApplySetBuffs(player, "Black Market Business Buff") -- ApplySetBuffs(player, "Medieval Medic Buff") -- ApplySetBuffs(player, "Expert's Ordnance Buff") -- ApplySetBuffs(player, "Swashbuckler's Buff") -- ApplySetBuffs(player, "Dr. Grordbort's Victory Buff") -- ApplySetBuffs(player, "Dr. Grordbort's Moonman Buff") -- ApplySetBuffs(player, "#1 Fan's Buff") -- ApplySetBuffs(player, "Urban Professional Buff") -- ApplySetBuffs(player, "Airborne Armanents Buff") -- ApplySetBuffs(player, "General's Formals Buff") -- ApplySetBuffs(player, "Soviet Pugilist Buff") -- WE ARE GOING TO STEAL THE MOON!!! for _, lunaritemname in ipairs(Lunar_Items) do local lunaritem = player:GetPlayerItemByName(lunaritemname) or nil if lunaritem then LunarItemEffect(player, lunaritem) end end elseif player:IsBot() then if player.m_szNetname == "Mutant Burning Man" and waveCount >= 16 and player:InCond(91) ~= true then player:AddCond(91) -- mutant burning man is always fast now end elseif player:IsObject() then -- not supposed to be "player" but whatever if not player.antitrample and player.m_iObjectType ~= 3 and player.m_bMiniBuilding ~= 1 then player.antitrample = true -- no more spontaneously destroyed dispensers!!! (replicated a similar thing from trespasser remaster via rafmod/lua) player:AddCallback(ON_DAMAGE_RECEIVED_PRE, function(_, damageInfo) local weapon = damageInfo.Weapon local damageType = damageInfo.DamageType local damageCustom = damageInfo.DamageCustom if weapon == nil then damageInfo.Damage = 0 end return true end) player:AddCallback(ON_DEATH, function() player.antitrample = false player:RemoveAllCallbacks() end) end end end if DoublePointsDuration and DoublePointsDuration > 0 then DoublePointsDuration = DoublePointsDuration - 1 -- DoublePointsText = "Double Points: ".. math.floor(DoublePointsDuration/66+1) --else -- DoublePointsText = "" end --if FireSaleDuration > 0 then -- FireSaleDuration = FireSaleDuration - 1 -- FireSaleText = "Fire Sale: ".. math.floor(FireSaleDuration/66+1) --else -- FireSaleText = "" --end if InstakillDuration and InstakillDuration > 0 then InstakillDuration = InstakillDuration - 1 -- InstakillText = "Instakill: ".. math.floor(InstakillDuration/66+1) --else -- InstakillText = "" end end function ShuffleInPlace(t) --copied from stack overflow for i = #t, 2, -1 do local j = math.random(i) t[i], t[j] = t[j], t[i] end end function OnWaveStart() BoxTable = {} waveActive = true --ThunderGunTaken = false --RejuvenatorTaken = false --DumpsterRoulette = {1,2,3,4,5} --DumpsterRouletteIndex = 1 PowerupTable = { [1] = "DoublePoints", [2] = "Instakill", [3] = "Nuke", [4] = "MaxAmmo", [5] = "BonusPoints", [6] = "Overheal", [7] = "Agility", [8] = "ReviveAll", [9] = "Plague", [10] = "Strength", [11] = "Uber", [12] = "Vision", [13] = "RandomPower", [14] = "PowerPlay" } PowerupTableIndex = 1 --ShuffleInPlace(DumpsterRoulette) ShuffleInPlace(PowerupTable) --for box = 1, 5, 1 do -- ents.FindByName("dumpster_spawner"..box):Teleport(ents.FindByName("dumpster_tele_out"):GetAbsOrigin()) -- ents.FindByName("dumpster_spawner"..box):AcceptInput("ForceSpawn") -- BoxTable[box] = {message = 0, weapon = "", text = "", slot = "", response = "", firesale = false, dud = true, timer = 0, count = 0, spawned = false, opened = false} --end --SpawnDumpsterBox(DumpsterRoulette[DumpsterRouletteIndex]) timer.Simple(0.5,function() ents.FindByName("vm_jugmsg"):AddCallback(ON_START_TOUCH, function(_, player) if player:IsRealPlayer() and player.m_nCurrency >= 2500 then player.InteractWith = "vm_jugbutton" end end) ents.FindByName("vm_jugmsg"):AddCallback(ON_END_TOUCH, function(_, player) if player:IsRealPlayer() then player.InteractWith = "nothing" player:Print(2,"") end end) ents.FindByName("vm_quickrevmsg"):AddCallback(ON_START_TOUCH, function(_, player) if player:IsRealPlayer() and player.m_nCurrency >= 50000 then player.InteractWith = "vm_quickrevbutton" end end) ents.FindByName("vm_quickrevmsg"):AddCallback(ON_END_TOUCH, function(_, player) if player:IsRealPlayer() then player.InteractWith = "nothing" player:Print(2,"") end end) ents.FindByName("vm_speedmsg"):AddCallback(ON_START_TOUCH, function(_, player) if player:IsRealPlayer() and player.m_nCurrency >= 3000 then player.InteractWith = "vm_speedbutton" end end) ents.FindByName("vm_speedmsg"):AddCallback(ON_END_TOUCH, function(_, player) if player:IsRealPlayer() then player.InteractWith = "nothing" player:Print(2,"") end end) ents.FindByName("vm_blastermsg"):AddCallback(ON_START_TOUCH, function(_, player) if player:IsRealPlayer() and player.m_nCurrency >= 1500 then player.InteractWith = "vm_blasterbutton" end end) ents.FindByName("vm_blastermsg"):AddCallback(ON_END_TOUCH, function(_, player) if player:IsRealPlayer() then player.InteractWith = "nothing" player:Print(2,"") end end) ents.FindByName("vm_dtmsg"):AddCallback(ON_START_TOUCH, function(_, player) if player:IsRealPlayer() and player.m_nCurrency >= 2000 then player.InteractWith = "vm_dtbutton" end end) ents.FindByName("vm_dtmsg"):AddCallback(ON_END_TOUCH, function(_, player) if player:IsRealPlayer() then player.InteractWith = "nothing" player:Print(2,"") end end) ents.FindByName("vm_mannmsg"):AddCallback(ON_START_TOUCH, function(_, player) -- local handle = player:GetHandleIndex() local handle = player:GetSteamId() if not player_total_kill[handle] then player_total_kill[handle] = 0 end if player:IsRealPlayer() and player.m_nCurrency >= 20000 and player_total_kill[handle] >= 200 then player.InteractWith = "vm_mannbutton" end end) ents.FindByName("vm_mannmsg"):AddCallback(ON_END_TOUCH, function(_, player) if player:IsRealPlayer() then player.InteractWith = "nothing" player:Print(2,"") end end) ents.FindByName("vm_roommsg"):AddCallback(ON_START_TOUCH, function(_, player) -- local handle = player:GetHandleIndex() local handle = player:GetSteamId() if not player_total_kill[handle] then player_total_kill[handle] = 0 end if player:IsRealPlayer() and player.m_nCurrency >= 1000 and player_total_kill[handle] >= 100 then player.InteractWith = "vm_roombutton" end end) ents.FindByName("vm_roommsg"):AddCallback(ON_END_TOUCH, function(_, player) if player:IsRealPlayer() then player.InteractWith = "nothing" player:Print(2,"") end end) ents.FindByName("vm_classemsg"):AddCallback(ON_START_TOUCH, function(_, player) if player:IsRealPlayer() and player.m_nCurrency >= 25000 then player.InteractWith = "vm_classebutton" end end) ents.FindByName("vm_classemsg"):AddCallback(ON_END_TOUCH, function(_, player) if player:IsRealPlayer() then player.InteractWith = "nothing" player:Print(2,"") end end) ents.FindByName("vm_luckemsg"):AddCallback(ON_START_TOUCH, function(_, player) if player:IsRealPlayer() and player.m_nCurrency >= 2000 then player.InteractWith = "vm_luckebutton" end end) ents.FindByName("vm_luckemsg"):AddCallback(ON_END_TOUCH, function(_, player) if player:IsRealPlayer() then player.InteractWith = "nothing" player:Print(2,"") end end) -- local players = 0 -- for _, player in pairs(ents.GetAllPlayers()) do -- if player:IsRealPlayer() and player.m_iTeamNum == 2 then -- players = players + 1 -- soloist_uid = player:GetUserId() -- only really matters in solo runs -- end -- end -- if players == 1 then -- soloMode = true -- for _, player in pairs(ents.GetAllPlayers()) do -- if player:IsRealPlayer() then -- player:DisplayTextChat("\x07ffdd00Solo Mode\x07FFFFFF has been activated. \x0707FF00Random Suicide is disabled\x07FFFFFF, \x0707FF00'Revive All' effects are replaced with Power Play instead\x07FFFFFF,") -- player:DisplayTextChat("\x07FF0000all other players cannot be revived\x07FFFFFF, and \x07FF0000any attempts of re/spawning are met with a quick death\x07FFFFFF.") -- end -- end -- local soloist = ents.GetPlayerByUserId(soloist_uid) -- local chances = soloist:GetAttributeValue("cannot pick up intelligence") or 0 -- if chances == 0 then -- soloist:SetAttributeValue("cannot pick up intelligence", 2) -- soloist:Print(2, "You have been granted SPECIAL E for the whole game!") -- end -- end end) --TextDisplay = timer.Create(1, function() --ents.FindByName("poweruptext"):AcceptInput("$SetKey$message",FireSaleText .. "\n" ..InstakillText .. "\n" ..DoublePointsText) --ents.FindByName("poweruptext"):AcceptInput("Display") --ents.FindByName("enemytext"):AcceptInput("Display") --ents.FindByName("roundtext"):AcceptInput("Display") end, 0) end function Interact(player) if not player.InteractWith then return end if player.InteractWith == "nothing" then return end -- do not remove in case i want to bring back the almanac again -- if not player.InteractWith or player.InteractWith == "nothing" then -- local actionslot = player:GetPlayerItemBySlot(LOADOUT_POSITION_ACTION) or nil -- if not actionslot then -- return -- elseif actionslot:GetItemName() ~= "The Almanac" then -- return -- else -- ents.FindByName("almanac"):AcceptInput("$DisplayMenu", player) -- end -- end if player.InteractWith:find("revive_button_") then if soloMode then player:Print(2, "Cannot revive other players in Solo Mode.") return else print("Button pressed, trying to trigger revivelogic: " .. player.InteractWith) local button = ents.FindByName(player.InteractWith) -- Ensure the player is not in conditions that prevent reviving (Ubercharged, Cloaked, etc.) if (player:InCond(5) and not player:InCond(6)) or player:InCond(51) or player:InCond(64) or player.m_hActiveWeapon.m_iClassname == "tf_weapon_pda_engineer_build" or player.m_hActiveWeapon.m_iClassname == "tf_weapon_pda_engineer_destroy" then print("Player is in an invalid state for reviving.") if (player:InCond(5) and not player:InCond(6)) or player:InCond(51) then player:Print(2, "Cannot revive due to active ÜberCharge effect.") elseif player:InCond(64) then player:Print(2, "Cannot revive due to active invisibility effect.") elseif player.m_hActiveWeapon.m_iClassname == "tf_weapon_pda_engineer_build" or player.m_hActiveWeapon.m_iClassname == "tf_weapon_pda_engineer_destroy" then player:Print(2, "Swap to a different weapon to revive this dead teammate.") end return end -- Safely call AcceptInput on a valid button if IsValid(button) then button:AcceptInput("Press", _, player) revivelogic(_, player) else print("Button is not valid when trying to accept input.") -- bruteforce anyways since button is already pressed revivelogic(_, player) end -- Set cooldown timers timer.Simple(1, function() player.InteractCooldown = true end) timer.Simple(3.75, function() player.InteractCooldown = false end) end end --[[if player.InteractWith == "dumpsterbutton1" and player.m_nCurrency >= DumpsterCost and ents.FindByName("dumpster_light1").m_On == false then OpenDumpsterBox(player, 1) player.m_nCurrency = player.m_nCurrency - DumpsterCost elseif player.InteractWith == "tradeweapon1" then DumpsterBoxTakeWeapon(player, 1) elseif player.InteractWith == "dumpsterbutton2" and player.m_nCurrency >= DumpsterCost and ents.FindByName("dumpster_light2").m_On == false then OpenDumpsterBox(player, 2) player.m_nCurrency = player.m_nCurrency - DumpsterCost elseif player.InteractWith == "tradeweapon2" then DumpsterBoxTakeWeapon(player, 2) elseif player.InteractWith == "dumpsterbutton3" and player.m_nCurrency >= DumpsterCost and ents.FindByName("dumpster_light3").m_On == false then OpenDumpsterBox(player, 3) player.m_nCurrency = player.m_nCurrency - DumpsterCost elseif player.InteractWith == "tradeweapon3" then DumpsterBoxTakeWeapon(player, 3) elseif player.InteractWith == "dumpsterbutton4" and player.m_nCurrency >= DumpsterCost and ents.FindByName("dumpster_light4").m_On == false then OpenDumpsterBox(player, 4) player.m_nCurrency = player.m_nCurrency - DumpsterCost elseif player.InteractWith == "tradeweapon4" then DumpsterBoxTakeWeapon(player, 4) elseif player.InteractWith == "dumpsterbutton5" and player.m_nCurrency >= DumpsterCost and ents.FindByName("dumpster_light5").m_On == false then OpenDumpsterBox(player, 5) player.m_nCurrency = player.m_nCurrency - DumpsterCost elseif player.InteractWith == "tradeweapon5" then DumpsterBoxTakeWeapon(player, 5)]] -- local handle = player:GetHandleIndex() local handle = player:GetSteamId() if not player_total_kill[handle] then player_total_kill[handle] = 0 end if player.InteractWith == "vm_mannbutton" and player.m_nCurrency >= 20000 and player_total_kill[handle] >= 200 then ents.FindByName("vm_mannbutton"):AcceptInput("Press",_,player) elseif player.InteractWith == "vm_roombutton" and player.m_nCurrency >= 1000 and player_total_kill[handle] >= 100 then ents.FindByName("vm_roombutton"):AcceptInput("Press",_,player) elseif player.InteractWith == "vm_classebutton" and player.m_nCurrency >= 25000 then ents.FindByName("vm_classebutton"):AcceptInput("Press",_,player) elseif player.InteractWith == "vm_luckebutton" and player.m_nCurrency >= 2000 then ents.FindByName("vm_luckebutton"):AcceptInput("Press",_,player) elseif player.InteractWith == "vm_jugbutton" and player.m_nCurrency >= 2500 then if player:GetAttributeValue("max health additive bonus") == nil then ents.FindByName("vm_jugbutton"):AcceptInput("Press",_,player) if player:GetPlayerItemBySlot(1):GetClassname() ~= "tf_weapon_pipebomblauncher" then PlayViewmodelSequence(player) end timer.Simple(1, function() player.InteractCooldown = true end) timer.Simple(2.3, function() player.InteractCooldown = false end) else player:Print(2,"You already have this perk!") end elseif player.InteractWith == "vm_quickrevbutton" and player.m_nCurrency >= 50000 then if player:InCond(70) == false then ents.FindByName("vm_quickrevbutton"):AcceptInput("Press",_,player) -- if player:GetPlayerItemBySlot(1):GetClassname() ~= "tf_weapon_pipebomblauncher" then PlayViewmodelSequence(player) end timer.Simple(1, function() player.InteractCooldown = true end) timer.Simple(2.3, function() player.InteractCooldown = false end) elseif player:InCond(70) == true then player:Print(2,"You already have this perk!") end elseif player.InteractWith == "vm_speedbutton" and player.m_nCurrency >= 3000 then if player:GetAttributeValue("move speed bonus") == nil then ents.FindByName("vm_speedbutton"):AcceptInput("Press",_,player) if player:GetPlayerItemBySlot(1):GetClassname() ~= "tf_weapon_pipebomblauncher" then PlayViewmodelSequence(player) end timer.Simple(1, function() player.InteractCooldown = true end) timer.Simple(2.3, function() player.InteractCooldown = false end) else player:Print(2,"You already have this perk!") end elseif player.InteractWith == "vm_blasterbutton" and player.m_nCurrency >= 1500 then if player:GetAttributeValue("explosive sniper shot") == nil then ents.FindByName("vm_blasterbutton"):AcceptInput("Press",_,player) if player:GetPlayerItemBySlot(1):GetClassname() ~= "tf_weapon_pipebomblauncher" then PlayViewmodelSequence(player) end timer.Simple(1, function() player.InteractCooldown = true end) timer.Simple(2.3, function() player.InteractCooldown = false end) else player:Print(2,"You already have this perk!") end elseif player.InteractWith == "vm_dtbutton" and player.m_nCurrency >= 2000 then if player:GetAttributeValue("fire rate bonus") == nil then ents.FindByName("vm_dtbutton"):AcceptInput("Press",_,player) if player:GetPlayerItemBySlot(1):GetClassname() ~= "tf_weapon_pipebomblauncher" then PlayViewmodelSequence(player) end timer.Simple(1, function() player.InteractCooldown = true end) timer.Simple(2.3, function() player.InteractCooldown = false end) else player:Print(2,"You already have this perk!") end end end function PlayViewmodelSequence(player) for k,v in pairs(ents.FindAllByClass("tf_viewmodel")) do if v.m_hOwner == player then local PreviousPrimary = player:GetPlayerItemBySlot(0) local PreviousSecondary = player:GetPlayerItemBySlot(1) if player:GetPlayerItemBySlot(0) ~= nil then PreviousPrimary = player:GetPlayerItemBySlot(0):GetItemName() end if player:GetPlayerItemBySlot(1) ~= nil then PreviousSecondary = player:GetPlayerItemBySlot(1):GetItemName() if player:GetPlayerItemBySlot(1).m_flChargeLevel ~= nil then PreviousUbercharge = player:GetPlayerItemBySlot(1).m_flChargeLevel end end local PreviousMelee = player:GetPlayerItemBySlot(2):GetItemName() player:WeaponStripSlot(0) player:WeaponStripSlot(2) player:GiveItem("Bonk! Atomic Punch") player:WeaponSwitchSlot(1) v.m_flPlaybackRate = 0.8 if player.m_iClass == 1 then v.m_nSequence = 41 elseif player.m_iClass == 2 then v.m_nSequence = 34 elseif player.m_iClass == 3 then v.m_nSequence = 52 elseif player.m_iClass == 4 then v.m_nSequence = 34 elseif player.m_iClass == 5 then v.m_nSequence = 23 elseif player.m_iClass == 6 then v.m_nSequence = 32 elseif player.m_iClass == 7 then v.m_nSequence = 29 elseif player.m_iClass == 8 then v.m_nSequence = 31 elseif player.m_iClass == 9 then --spy skipped v.m_nSequence = 52 end timer.Simple(2.2, function() player:WeaponStripSlot(1) if PreviousPrimary ~= nil then player:GiveItem(PreviousPrimary) end if PreviousSecondary ~= nil then player:GiveItem(PreviousSecondary) if player:GetPlayerItemBySlot(1).m_flChargeLevel ~= nil then player:GetPlayerItemBySlot(1).m_flChargeLevel = PreviousUbercharge end end player:GiveItem(PreviousMelee) end) end end end function DropPowerup(player) ents.FindByName(PowerupTable[PowerupTableIndex] .. "_spawner"):Teleport(player:GetAbsOrigin()) ents.FindByName(PowerupTable[PowerupTableIndex] .. "_spawner"):AcceptInput("ForceSpawn") if PowerupTableIndex == 9 then ShuffleInPlace(PowerupTable) PowerupTableIndex = 0 end PowerupTableIndex = PowerupTableIndex + 1 end local rarityConfig = { Common = {multiplier = 1, chance = 0, color = "07FF00", label = "[Common]"}, Uncommon = {multiplier = 2, chance = 0, color = "87CEFA", label = "[Uncommon]"}, Rare = {multiplier = 3, chance = 0, color = "FFA500", label = "[Rare]"}, Legendary = {multiplier = 5, chance = 0, color = "800080", label = "[Legendary]"}, Divine = {multiplier = 10, chance = 100, color = "EB2DF8", label = "[Divine]"} } local possibleBonuses = { { -- rewritten the fire rate bonus to only apply it to melees up to 40% fire rate func = function(player, multiplier, playSound) -- local currentFireRateBonus = player:GetAttributeValue("fire rate penalty HIDDEN") or 1 -- local extraFireRateBonus = player:GetAttributeValue("halloween fire rate bonus") or 1 local pattr = player:GetAttributeValue("non economy") or 0 -- local appliedBonus = 0.02 * multiplier pattr = pattr + 2 * multiplier local totalBonus = pattr / 100 -- currentFireRateBonus - 0.02 * multiplier -- saving this one for posterity if pattr > 40 then -- starting from 42% since it affects only the guns (and possibly the grenade launchers too) player:SetAttributeValue("halloween fire rate bonus", 1.4 - totalBonus) player:SetAttributeValue("fire rate penalty HIDDEN", 0.6) -- no longer matters anyway, might as well set it as is, now that it reached the limit else -- up to 40% because this attribute also affects melee fire rate, and melees are bonkers in this gamemode player:SetAttributeValue("fire rate penalty HIDDEN", 1 - totalBonus) end player:SetAttributeValue("non economy", pattr) if playSound then player:PlaySoundToSelf("shadows/perk_doubletap.mp3") end end, description = function(player, multiplier) -- local currentFireRateBonus = player:GetAttributeValue("fire rate penalty HIDDEN") or 1 local pattr = player:GetAttributeValue("non economy") or 0 -- local currentFireRateBonus = (pattr * 2) / 100 * multiplier local appliedBonus = 2 * multiplier -- return "You received +" .. round(appliedBonus) .. "% fire rate bonus! Current bonus: " .. round((1 - currentFireRateBonus) * 100) .. "% fire rate bonus!" return "You received +" .. round(appliedBonus) .. "% fire rate bonus! Current bonus: " .. round(pattr) .. "% fire rate bonus!" end, shortdesc = function(multiplier) return "+" .. round(2 * multiplier) .. "% fire rate bonus" end, currenttotal = function(player) -- local currentFireRateBonus = player:GetAttributeValue("fire rate penalty HIDDEN") or 1 local pattr = player:GetAttributeValue("non economy") or 0 -- local currentFireRateBonus = (pattr * 2) / 100 * multiplier -- return "+" .. round((1 - currentFireRateBonus) * 100) .. "% fire rate" return "+" .. round(pattr) .. "% faster fire rate" end, -- attribute = "fire rate penalty HIDDEN", attribute = "non economy", debugname = "fr", weight = 11, bancheck = function(player) local pattr = player:GetAttributeValue("non economy") or 0 return pattr >= 120 end }, { func = function(player, multiplier, playSound) local currentReloadSpeedBonus = player:GetAttributeValue("Reload time decreased") or 1 player:SetAttributeValue("Reload time decreased", math.max(0.01, currentReloadSpeedBonus - 0.02 * multiplier)) if playSound then player:PlaySoundToSelf("shadows/perk_doubletap.mp3") end end, description = function(player, multiplier) local currentReloadSpeedBonus = player:GetAttributeValue("Reload time decreased") or 1 local appliedBonus = 2 * multiplier return "You received +" .. round(appliedBonus) .. "% faster reload speed! Current bonus: " .. round((1 - currentReloadSpeedBonus) * 100) .. "% faster reload speed!" end, shortdesc = function(multiplier) return "+" .. round(2 * multiplier) .. "% faster reload speed" end, currenttotal = function(player) local currentReloadSpeedBonus = player:GetAttributeValue("Reload time decreased") or 1 return "+" .. round((1 - currentReloadSpeedBonus) * 100) .. "% reload speed" end, attribute = "Reload time decreased", debugname = "rl", weight = 11, bancheck = function(player) local rs = player:GetAttributeValue("Reload time decreased") or 1 return rs <= 0.01 end }, { func = function(player, multiplier, playSound) -- local currentPrimAmmoBonus = player:GetAttributeValue("maxammo primary increased") or 1 local currentSecondAmmoBonus = player:GetAttributeValue("maxammo secondary increased") or 1 -- local totalBonus = (currentPrimAmmoBonus + currentSecondAmmoBonus) * 0.1 * multiplier local placeholderAttribute = player:GetAttributeValue("sapper damage penalty hidden") or 1 player:SetAttributeValue("maxammo primary increased", currentSecondAmmoBonus + 0.1 * multiplier) player:SetAttributeValue("maxammo secondary increased", currentSecondAmmoBonus + 0.1 * multiplier) -- player:SetAttributeValue("maxammo secondary increased", currentSecondAmmoBonus + 0.1 * multiplier) -- player:SetAttributeValue("sapper damage penalty hidden", placeholderAttribute + 0.1 * multiplier) -- placeholder attribute if playSound then player:PlaySoundToSelf("shadows/perk_doubletap.mp3") end end, description = function(player, multiplier) local totalBonus = 10 * multiplier local placeholderAttribute = player:GetAttributeValue("maxammo secondary increased") or 1 -- local placeholderAttribute = player:GetAttributeValue("sapper damage penalty hidden") or 1 return "You received +" .. totalBonus .. "% max ammo! Current bonus: +" .. round((placeholderAttribute - 1) * 100) .. "% max ammo!" end, shortdesc = function(multiplier) return "+" .. (10 * multiplier) .. "% max ammo" end, currenttotal = function(player) local placeholderAttribute = player:GetAttributeValue("maxammo secondary increased") or 1 return "+" .. round((placeholderAttribute - 1) * 100) .. "% max ammo" end, -- attribute = {"maxammo primary increased", "maxammo secondary increased"}, attribute = "maxammo secondary increased", debugname = "ma", weight = 11, bancheck = function(player) return false end }, { func = function(player, multiplier, playSound) local damageBonus = player:GetAttributeValue("damage bonus") or 1 player:SetAttributeValue("damage bonus", damageBonus + 0.1 * multiplier) if playSound then player:PlaySoundToSelf("shadows/perk_meraslixir.mp3") end end, description = function(player, multiplier) local damageBonus = player:GetAttributeValue("damage bonus") or 1 local appliedBonus = 10 * multiplier return "You received +" .. round(appliedBonus) .. "% damage bonus! Current bonus: " .. round((damageBonus - 1) * 100) .. "% damage bonus!" end, shortdesc = function(multiplier) return "+" .. round(10 * multiplier) .. "% damage bonus" end, currenttotal = function(player) local damageBonus = player:GetAttributeValue("damage bonus") or 1 return "+" .. round((damageBonus - 1) * 100) .. "% damage bonus" end, attribute = "damage bonus", debugname = "dmg", weight = 11, bancheck = function(player) return false end }, { func = function(player, multiplier, playSound) local movespeedBonus = player:GetAttributeValue("SET BONUS: move speed set bonus") or 1 player:SetAttributeValue("SET BONUS: move speed set bonus", movespeedBonus + 0.02 * multiplier) if playSound then player:PlaySoundToSelf("shadows/perk_meraslixir.mp3") end end, description = function(player, multiplier) local movespeedBonus = player:GetAttributeValue("SET BONUS: move speed set bonus") or 1 local appliedBonus = 2 * multiplier return "You received +" .. round(appliedBonus) .. "% faster move speed! Current bonus: " .. round((movespeedBonus - 1) * 100) .. "% faster move speed!" end, shortdesc = function(multiplier) return "+" .. round(2 * multiplier) .. "% faster move speed" end, currenttotal = function(player) local movespeedBonus = player:GetAttributeValue("SET BONUS: move speed set bonus") or 1 return "+" .. round((movespeedBonus - 1) * 100) .. "% move speed" end, attribute = "SET BONUS: move speed set bonus", debugname = "spd", weight = 11, banstid = {}, -- legacy code bancheck = function(player) local playerspeed = player:GetAttributeValue("CARD: move speed bonus") or 1 local bonusspeed = player:GetAttributeValue("SET BONUS: move speed set bonus") or 1 return (playerspeed + bonusspeed) >= 3 end }, { func = function(player, multiplier, playSound) local ammoregBonus = player:GetAttributeValue("ammo regen") or 0 player:SetAttributeValue("ammo regen", ammoregBonus + 0.02 * multiplier) if playSound then player:PlaySoundToSelf("shadows/perk_meraslixir.mp3") end end, description = function(player, multiplier) local ammoregBonus = player:GetAttributeValue("ammo regen") or 0 local appliedBonus = 2 * multiplier return "You received +" .. round(appliedBonus) .. "% ammo regenerated / 5s! Current bonus: " .. round(ammoregBonus * 100) .. "% ammo regenerated / 5s!" end, shortdesc = function(multiplier) return "+" .. round(2 * multiplier) .. "% ammo regenerated / 5s" end, currenttotal = function(player) local ammoregBonus = player:GetAttributeValue("ammo regen") or 0 return "+" .. round(ammoregBonus * 100) .. "% ammo regen" end, attribute = "ammo regen", debugname = "ar", weight = 11, bancheck = function(player) local ammoregen = player:GetAttributeValue("ammo regen") or 0 return ammoregen >= 1 end }, { func = function(player, multiplier, playSound) local maxhealthBonus = player:GetAttributeValue("SET BONUS: max health additive bonus") or 0 player:SetAttributeValue("SET BONUS: max health additive bonus", maxhealthBonus + 10 * multiplier) if playSound then player:PlaySoundToSelf("shadows/perk_saxton.mp3") end end, description = function(player, multiplier) local maxhealthBonus = player:GetAttributeValue("SET BONUS: max health additive bonus") or 0 local appliedBonus = 10 * multiplier return "You received +" .. round(appliedBonus) .. " max HP! Current bonus: " .. round(maxhealthBonus) .. " max HP!" end, shortdesc = function(multiplier) return "+" .. round(10 * multiplier) .. " max HP" end, currenttotal = function(player) local maxhealthBonus = player:GetAttributeValue("SET BONUS: max health additive bonus") or 0 return "+" .. round(maxhealthBonus) .. " max HP" end, attribute = "SET BONUS: max health additive bonus", debugname = "hp", weight = 11, bancheck = function(player) return false end }, { func = function(player, multiplier, playSound) local currentKillCashBonus = player:GetAttributeValue("unusualifier_attribute_template_name") or 0 player:SetAttributeValue("unusualifier_attribute_template_name", currentKillCashBonus + 10 * multiplier) if playSound then player:PlaySoundToSelf("shadows/perk_saxton.mp3") end end, description = function(player, multiplier) local currentKillCashBonus = player:GetAttributeValue("unusualifier_attribute_template_name") or 0 local appliedBonus = 10 * multiplier return "You receive +" .. appliedBonus .. "$ per kill! Current bonus: " .. round(currentKillCashBonus) .. "$ per kill!" end, shortdesc = function(multiplier) return "+" .. (10 * multiplier) .. "$ per kill" end, currenttotal = function(player) local currentKillCashBonus = player:GetAttributeValue("unusualifier_attribute_template_name") or 0 return "+" .. round(currentKillCashBonus) .. "$ per kill" end, attribute = "unusualifier_attribute_template_name", debugname = "$/k", noInfMoneyMode = true, weight = 11, bancheck = function(player) return false end }, -- { -- func = function(player, multiplier, playSound) -- local currentKillCashBonus = player:GetAttributeValue("currency bonus") or 1 -- player:SetAttributeValue("currency bonus", currentKillCashBonus + 0.025 * multiplier) -- if playSound then -- player:PlaySoundToSelf("shadows/perk_saxton.mp3") -- end -- end, -- description = function(player, multiplier) -- local currentKillCashBonus = player:GetAttributeValue("currency bonus") or 1 -- local appliedBonus = 2.5 * multiplier -- return "You receive +" .. appliedBonus .. "% more money per hit / kill! Current bonus: +" .. round((currentKillCashBonus - 1) * 100) .. "% more money!" -- end, -- shortdesc = function(multiplier) -- return "+" .. (2.5 * multiplier) .. "% money gained" -- end, -- currenttotal = function(player) -- local currentKillCashBonus = player:GetAttributeValue("currency bonus") or 1 -- return "+" .. round((currentKillCashBonus - 1) * 100) .. "% money gain" -- end, -- attribute = "currency bonus", -- debugname = "$%", -- noInfMoneyMode = true, -- weight = 11, -- bancheck = function(player) -- return false -- end -- }, { func = function(player, multiplier, playSound) local healonkillBonus = player:GetAttributeValue("heal on kill") or 0 player:SetAttributeValue("heal on kill", healonkillBonus + 5 * multiplier) if playSound then player:PlaySoundToSelf("shadows/perk_saxton.mp3") end end, description = function(player, multiplier) local healonkillBonus = player:GetAttributeValue("heal on kill") or 0 local appliedBonus = 5 * multiplier return "You received +" .. round(appliedBonus) .. " HP restored on kill! Current bonus: " .. round(healonkillBonus) .. " HP restored on kill!" end, shortdesc = function(multiplier) return "+" .. round(5 * multiplier) .. " HP restored on kill" end, currenttotal = function(player) local healonkillBonus = player:GetAttributeValue("heal on kill") or 0 return "+" .. round(healonkillBonus) .. " HP per kill" end, attribute = "heal on kill", debugname = "hok", weight = 11, bancheck = function(player) return false end }, { -- if you get hit by the scam i am very sorry, it's now much, *much* more painful than all other variants func = function(player, multiplier, playSound) playerWeakenedMannpower[player] = true timer.Simple(30 * multiplier, function() playerWeakenedMannpower[player] = false print("this player is no longer mannpower-weakened:", player.m_szNetname) end) if not infMoneyMode then local scamamount = -5000 * multiplier player:AddCurrency(scamamount + 2000) end player:SetAttributeValue("is marketable", nil) if playSound then player:PlaySoundToSelf("shadows/powerup_dud_03.mp3") end end, description = function(player, multiplier) if infMoneyMode then local duration = 30 * multiplier return "You used 2000$ to roll and received a " .. duration .. "-second Mannpower weakening effect, better luck next time!" else local amountLost = 5000 * multiplier local duration = 30 * multiplier return "You used 2000$ to roll and got scammed out of $" .. amountLost .. " and your powerup weakened for " .. duration .. " seconds..." end end, shortdesc = function(multiplier) if infMoneyMode then local duration = 30 * multiplier return "Weakened Mannpower effect for " .. duration .. " seconds" else local amountLost = 5000 * multiplier local duration = 30 * multiplier return "Get scammed for " .. amountLost .. "$ and weakened Mannpower for " .. duration .. " seconds" end end, attribute = "is marketable", debugname = "rip", noRestore = true, weight = 11, bancheck = function(player) return false end }, } local function getRandomRarity() local roll = math.random(1, 100) local cumulativeChance = 0 for rarity, config in pairs(rarityConfig) do cumulativeChance = cumulativeChance + config.chance if roll <= cumulativeChance then return rarity, config end end return "Common", rarityConfig.Common -- Fallback end function ApplyLuckyBonus(_, player) -- DETAILS ABOUT THE NEW LUCKY BONUS SELECTION SYSTEM: -- - Bonus selection is weight-based instead of an equal chance -- - Except for the scam (its weight is set to 1), all bonuses start with a weight of 11 -- - Bonus weights are dynamically increased or decreased based on multiple factors: -- - Whether or not the scam is chosen (in which case, all bonuses receive a big increase in their weighting) -- - Whether or not a bonus is chosen -- - If it is chosen and: -- - it is different from the previously chosen bonus, its current weight will be reset to the base weight -- - it is repeated consecutively, its weight will be reduced instead of reset -- - If it is not chosen, its weight will be increased -- - Increased/decreased weights are player-bound and will differ for every player in the game RestoreBonuses(player) -- refresh since item swapping kills some bonuses every time local playerID = player:GetHandleIndex() local playerSteamId = player:GetSteamId() -- mainly used for bonus restoration, and also makes it possible to restore bonuses after a client crash playerPurchased[playerID] = playerPurchased[playerID] or 0 local freeChances = playerExtraLuckyChances[playerSteamId] or 0 local freeChanceUsed = false local chancesLeft = -1 -- this variable is more or less a mere formality local extraChances = player:GetAttributeValue("cannot pick up intelligence") or 0 local purchaseLimitReached = (extraChances == 4 and playerPurchased[playerID] >= 3) or (extraChances == 2 and playerPurchased[playerID] >= 2) or (extraChances == 0 and playerPurchased[playerID] >= 1) if purchaseLimitReached then if freeChances > 0 then freeChanceUsed = true else player:Print(2, "You have already purchased a Lucky Bonus this round!") player:AddCurrency(2000) return end else if extraChances == 4 then if playerPurchased[playerID] == 0 then chancesLeft = 2 elseif playerPurchased[playerID] == 1 then chancesLeft = 1 end elseif (extraChances == 2 and playerPurchased[playerID] < 1) then chancesLeft = 1 end end if not purchaseLimitReached then playerPurchased[playerID] = playerPurchased[playerID] + 1 end -- local movespeedbanned = false -- local totalmovespeed = player:GetAttributeValue("CARD: move speed bonus") or 1 -- local tempms = player:GetAttributeValue("SET BONUS: move speed set bonus") or 1 -- local totalmovespeed = totalmovespeed + (tempms - 1) -- if totalmovespeed >= 2.2 then -- for _, stid in ipairs(possibleBonuses[5].banstid) do -- if stid == playerSteamId then -- movespeedbanned = true -- break -- end -- end -- if not movespeedbanned then -- table.insert(possibleBonuses[5].banstid, playerSteamId) -- movespeedbanned = true -- end -- else -- for _, stid in ipairs(possibleBonuses[5].banstid) do -- if stid == playerSteamId then -- table.remove(possibleBonuses[5].banstid, playerSteamId) -- break -- end -- end -- end -- set dynamic weighting with player-bound weight modifiers, if not yet set -- the scam will also be included but it will not be touched at any point if not playerDynamicWeight[playerID] then playerDynamicWeight[playerID] = {} for _, possibleBonus in ipairs(possibleBonuses) do playerDynamicWeight[playerID][possibleBonus] = 0 end end -- get the total weight of lucky bonuses, including player-bound weight modifiers -- bonus weight cannot be less than 1 local totalWeight = 0 local bannedBonuses = {} -- helps trim potentially longer lines of code local pityCheck = nil for i, possibleBonus in ipairs(possibleBonuses) do if possibleBonus.bancheck(player) then bannedBonuses[possibleBonus] = true elseif infMoneyMode and possibleBonus.noInfMoneyMode then bannedBonuses[possibleBonus] = true else bannedBonuses[possibleBonus] = false if playerDynamicWeight[playerID][possibleBonus] >= 69 then pityCheck = pityCheck or {} table.insert(pityCheck, possibleBonus) end totalWeight = totalWeight + math.max(1, possibleBonus.weight + playerDynamicWeight[playerID][possibleBonus]) end end local bonus if pityCheck then -- pity system: if a bonus reaches at least 69 bonus weight *when* it's time to draw, it will be selected -- if there are multiple bonuses in the pity box a bonus will be selected at random, equal chance -- scam will never be in the pity box as it's permanently set to 1 bonus = pityCheck[math.random(#pityCheck)] else -- roll a random number from 1 to total weight local selection = math.random(totalWeight) local eventually = 1 -- iterate through the possible bonuses and compare bonus's weight with random number -- bonus weight cannot be less than 1 for _, possibleBonus in ipairs(possibleBonuses) do if not bannedBonuses[possibleBonus] then eventually = eventually + math.max(1, possibleBonus.weight + playerDynamicWeight[playerID][possibleBonus]) if selection < eventually then bonus = possibleBonus break end end end end -- if in infinite money mode the bonus is somehow still not selected, draw lots if not bonus and infMoneyMode then repeat bonus = possibleBonuses[math.random(#possibleBonuses)] until not bannedBonuses[bonus] end -- if not yet set, or if the scam is rolled, only record the last bonus -- if set: -- 1. if the same bonus is rerolled again, subtract its weight modifier by a sizable amount -- 2. if a different bonus is rolled, reset the new bonus's weight modifier, then record it as the last bonus -- the scam bonus can never have a decreased chance of getting rolled if not playerLastBonus[playerID] or bonus.noRestore then -- case 1: not yet set, OR rolled the scam playerLastBonus[playerID] = bonus else -- case 2: normal if playerLastBonus[playerID] == bonus then playerDynamicWeight[playerID][bonus] = playerDynamicWeight[playerID][bonus] - math.random(10, 17) else if playerDynamicWeight[playerID][bonus] > 0 then -- playerDynamicWeight[playerID][bonus] = math.max(0, playerDynamicWeight[playerID][bonus] - 3) playerDynamicWeight[playerID][bonus] = 0 end playerLastBonus[playerID] = bonus end end -- add the weight modifiers of all other unchosen bonuses by a certain number -- 1. if the bonus rolled is a scam, add the weight modifiers of all other bonuses by 15 -- 2. if the bonus is not a scam, add the weight modifiers of all other bonuses EXCEPT scam by a random amount -- the scam bonus can never have an increased chance of getting rolled for _, possibleBonus in ipairs(possibleBonuses) do if bonus.noRestore then -- case 1: rolled the scam if not possibleBonus.noRestore and bannedBonuses[possibleBonus] ~= false then playerDynamicWeight[playerID][possibleBonus] = playerDynamicWeight[playerID][possibleBonus] + 25 end else -- case 2: bonus is not selected and not scam if bonus ~= possibleBonus and not possibleBonus.noRestore and not bannedBonuses[possibleBonus] then playerDynamicWeight[playerID][possibleBonus] = playerDynamicWeight[playerID][possibleBonus] + math.random(4, 9) end end end -- local bonus -- repeat -- bonus = possibleBonuses[math.random(#possibleBonuses)] -- until not bonus.rarityExclusion local rarity, rarityDetails = getRandomRarity() local multiplier = rarityDetails.multiplier playerBonuses[playerSteamId] = playerBonuses[playerSteamId] or {} if not bonus.noRestore then if type(bonus.attribute) == "table" then for _, attribute in ipairs(bonus.attribute) do playerBonuses[playerSteamId][attribute] = playerBonuses[playerSteamId][attribute] or {} local data = { func = bonus.func, mult = multiplier } table.insert(playerBonuses[playerSteamId][attribute], data) end else playerBonuses[playerSteamId][bonus.attribute] = playerBonuses[playerSteamId][bonus.attribute] or {} local data = { func = bonus.func, mult = multiplier } table.insert(playerBonuses[playerSteamId][bonus.attribute], data) end end bonus.func(player, multiplier, true) local bonusDescription = bonus.description(player, multiplier) local textstring = rarityDetails.label .. " " .. bonusDescription if chancesLeft ~= -1 then textstring = textstring .. "\nLucky Bonus Chances left: " .. (chancesLeft + freeChances) -- if freeChances > 0 then -- textstring = textstring .. " + " .. freeChances .. " extra" -- end else if freeChances > 0 then if freeChanceUsed then playerExtraLuckyChances[playerSteamId] = playerExtraLuckyChances[playerSteamId] - 1 end freeChances = playerExtraLuckyChances[playerSteamId] or 0 textstring = textstring .. "\nLucky Bonus Chances left: " .. freeChances end end if betaMode then local totalweight = 0 textstring = textstring .. "\nplayer-based bonus weights: " for _, abonus in ipairs(possibleBonuses) do if not bannedBonuses[abonus] then local debugname = abonus.debugname if not debugname then debugname = abonus.attribute end textstring = textstring .. " " .. playerDynamicWeight[playerID][abonus] .. debugname totalweight = totalweight + playerDynamicWeight[playerID][abonus] end end textstring = textstring .. "\ntotal bonus weights: " .. totalweight end player:Print(2, textstring) for _, aplayer in pairs(ents.GetAllPlayers()) do if aplayer:IsRealPlayer() then if not bonus.currenttotal then aplayer:DisplayTextChat("\x07FF0000" .. player:GetPlayerName() .. " \x01has received a Lucky Bonus: \x07" .. rarityDetails.color .. rarityDetails.label .. " \x07ffdd00" .. bonus.shortdesc(multiplier)) else aplayer:DisplayTextChat("\x07FF0000" .. player:GetPlayerName() .. " \x01has received a Lucky Bonus: \x07" .. rarityDetails.color .. rarityDetails.label .. " \x07ffdd00" .. bonus.shortdesc(multiplier) .. " \x01(Current: \x07ffdd00" .. bonus.currenttotal(player) .. "\x01)") end end end RightSideKillCounter(0, player, nil) CashbackLuckyBonus(_, player) -- placed here as a "safety net" in the event that an unfortunate soul gets scammed end function RestoreBonuses(player) -- local playerID = player:GetHandleIndex() local playerSteamId = player:GetSteamId() local storedBonuses = playerBonuses[playerSteamId] if storedBonuses then for attribute, increments in pairs(storedBonuses) do if type(attribute) == "table" then -- shouldn't trigger -- Handle multi-attribute bonuses for _, subAttribute in ipairs(attribute) do player:SetAttributeValue(subAttribute, nil) end -- Reapply all increments for each attribute in the group -- for _, applyIncrement in ipairs(increments) do -- applyIncrement(player, false) -- end for _, luckybonus in ipairs(increments) do luckybonus.func(player, luckybonus.mult, false) end else -- Handle single-attribute bonuses player:SetAttributeValue(attribute, nil) -- Reapply all increments for the bonus -- for _, applyIncrement in ipairs(increments) do -- applyIncrement(player, false) -- end for _, luckybonus in ipairs(increments) do luckybonus.func(player, luckybonus.mult, false) end end end end end function CashbackRoomBonus(_, player) local handle = player:GetHandleIndex() local canCashback_old = player:GetAttributeValue("is australium item") or 0 local canCashback = player:GetAttributeValue("cannot trade") or 0 local savings = round(1000 * 0.25) if canCashback == 7 or canCashback_old == 7 then player:AddCurrency(savings) else playerCashback[handle] = playerCashback[handle] or 0 playerCashback[handle] = playerCashback[handle] + savings end end function CashbackMannpower(_, player) local handle = player:GetHandleIndex() local canCashback_old = player:GetAttributeValue("is australium item") or 0 local canCashback = player:GetAttributeValue("cannot trade") or 0 local savings = round(20000 * 0.25) if canCashback == 7 or canCashback_old == 7 then player:AddCurrency(savings) else playerCashback[handle] = playerCashback[handle] or 0 playerCashback[handle] = playerCashback[handle] + savings end end function CashbackClassEnhance(_, player) local handle = player:GetHandleIndex() local canCashback_old = player:GetAttributeValue("is australium item") or 0 local canCashback = player:GetAttributeValue("cannot trade") or 0 local savings = round(25000 * 0.25) if canCashback == 7 or canCashback_old == 7 then player:AddCurrency(savings) else playerCashback[handle] = playerCashback[handle] or 0 playerCashback[handle] = playerCashback[handle] + savings end end function CashbackLuckyBonus(_, player) local handle = player:GetHandleIndex() local canCashback_old = player:GetAttributeValue("is australium item") or 0 local canCashback = player:GetAttributeValue("cannot trade") or 0 local savings = round(2000 * 0.25) if canCashback == 7 or canCashback_old == 7 then player:AddCurrency(savings) else playerCashback[handle] = playerCashback[handle] or 0 playerCashback[handle] = playerCashback[handle] + savings end end function CashbackOstarionsReserve(_, player) local handle = player:GetHandleIndex() local canCashback_old = player:GetAttributeValue("is australium item") or 0 local canCashback = player:GetAttributeValue("cannot trade") or 0 local savings = round(50000 * 0.25) if canCashback == 7 or canCashback_old == 7 then player:AddCurrency(savings) else playerCashback[handle] = playerCashback[handle] or 0 playerCashback[handle] = playerCashback[handle] + savings end end function CashbackInterestPayout(_, player) local handle = player:GetHandleIndex() savings = playerCashback[handle] or 0 -- print(player:GetPlayerName() .. " savings: " .. savings) if savings > 0 then player:AddCurrency(playerCashback[handle]) player:Print(2, "$" .. playerCashback[handle] .. " worth 25% of your total past vending purchases have been returned to you!") playerCashback[handle] = 0 end end local classNames = { [1] = "Scout", [2] = "Sniper", [3] = "Soldier", [4] = "Demoman", [5] = "Medic", [6] = "Heavy", [7] = "Pyro", [8] = "Spy", [9] = "Engineer" } function LuckyBonusReset() if waveCount <= 1 then playerPurchased = {} return end for _, player in pairs(ents.GetAllPlayers()) do if player:IsRealPlayer() and player.m_iTeamNum == 2 and classNames[player.m_iClass] then local handle = player:GetHandleIndex() local playerSteamId = player:GetSteamId() local OCcheck = player:GetAttributeValue("cannot pick up intelligence") or 0 local extrachances = playerExtraLuckyChances[playerSteamId] or 0 playerPurchased[handle] = playerPurchased[handle] or 0 if OCcheck == 4 and playerPurchased[handle] < 3 then playerExtraLuckyChances[playerSteamId] = extrachances + (3 - playerPurchased[handle]) elseif OCcheck == 2 and playerPurchased[handle] < 2 then playerExtraLuckyChances[playerSteamId] = extrachances + (2 - playerPurchased[handle]) elseif playerPurchased[handle] == 0 then playerExtraLuckyChances[playerSteamId] = extrachances + 1 end end end playerPurchased = {} end function StoredLuckyBonusReset() playerBonuses = {} end function WaveMoneyAndKillReset() waveMoneyEarned = {} waveKills = {} end function DisplayLeaderboard() local leaderboard = {} -- Collect player data into a table if soloMode then local player = ents.GetPlayerByUserId(soloist_uid) local handle = player:GetSteamId() table.insert(leaderboard, { name = player.m_szNetname, className = classNames[player.m_iClass] or "Unknown", waveMoney = waveMoneyEarned[handle] or 0, totalMoney = totalMoneyEarned[handle] or 0, waveKill = waveKills[handle] or 0, totalKill = player_total_kill[handle] or 0, }) else for _, player in pairs(ents.GetAllPlayers()) do if player:IsRealPlayer() and player.m_iTeamNum == 2 and classNames[player.m_iClass] then -- local handle = player:GetHandleIndex() local handle = player:GetSteamId() table.insert(leaderboard, { name = player.m_szNetname, className = classNames[player.m_iClass] or "Unknown", waveMoney = waveMoneyEarned[handle] or 0, totalMoney = totalMoneyEarned[handle] or 0, waveKill = waveKills[handle] or 0, totalKill = player_total_kill[handle] or 0, }) -- leaderboard[handle] = { -- name = player.m_szNetname, -- className = classNames[player.m_iClass] or "Unknown", -- waveMoney = waveMoneyEarned[handle] or 0, -- totalMoney = totalMoneyEarned[handle] or 0, -- waveKill = waveKills[handle] or 0, -- totalKill = player_total_kill[handle] or 0 -- } end end end -- Sort the leaderboard table by totalMoney, then totalKill table.sort(leaderboard, function(a, b) if a.totalMoney == b.totalMoney then return a.totalKill > b.totalKill -- Sort by totalKill if totalMoney is the same end return a.totalMoney > b.totalMoney -- Sort by totalMoney first end) -- Display the sorted leaderboard for _, player in pairs(ents.GetAllPlayers()) do if player:IsRealPlayer() then for i, playerData in ipairs(leaderboard) do if i == 1 then -- Display leaderboard header only once player:DisplayTextChat("\x07FF0000Player\x07FFFFFF (\x0707FF00Class\x07FFFFFF) \x07EB2DF8||\x07FFFFFF Wave $ / \x07ffdd00Total $\x07FFFFFF \x07EB2DF8||\x07FFFFFF Wave kills / \x07ffdd00Total kills\x07FFFFFF") player:DisplayTextChat("--------------- [\x0787CEFALeaderboard\x07FFFFFF] ---------------") end player:DisplayTextChat( string.format( "- \x07FF0000%s\x07FFFFFF (\x0707FF00%s\x07FFFFFF) \x07EB2DF8||\x07FFFFFF %d$ / \x07ffdd00%d$\x07FFFFFF \x07EB2DF8||\x07FFFFFF %d / \x07ffdd00%d\x07FFFFFF", playerData.name, playerData.className, playerData.waveMoney, playerData.totalMoney, playerData.waveKill, playerData.totalKill ) ) end player:DisplayTextChat("------------------------------------------------") end end end function ActivateDoublePoints() DoublePointsDuration = DoublePointsDuration + 1980 -- 1980 ticks divided by 66 tick rate = 30 seconds for _, player in pairs(ents.GetAllPlayers()) do if player:IsRealPlayer() then player:Print(2,"Double Points!") player:PlaySoundToSelf("shadows/powerup_doublepoints.mp3") player:PlaySoundToSelf("ui/quest_status_tick_advanced.wav") end end end --function ActivateFireSale() -- for _, player in pairs(ents.GetAllPlayers()) do -- if player:IsRealPlayer() then -- player:Print(2,"Fire Sale!") -- player:PlaySoundToSelf("shadows/powerup_firesale01.mp3") -- player:PlaySoundToSelf("mvm/mvm_bought_upgrade.wav") -- if FireSaleDuration <= 0 then -- timer.Simple(1,function() ents.FindByName("firesale_music"):AcceptInput("PlaySound") end) -- end -- end -- end -- FireSaleDuration = FireSaleDuration + 1980 -- 1980 ticks divided by 66 tick rate = 30 seconds -- DumpsterCost = 10 -- for box = 1, 5, 1 do -- if BoxTable[box].spawned == false then -- SpawnDumpsterBox(box) -- end -- BoxTable[box].firesale = true -- BoxTable[box].dud = false -- end -- BoxTable[DumpsterRouletteIndex].firesale = false -- timer.Create(1, -- function() if FireSaleDuration <= 0 then -- DumpsterCost = 950 -- for box = 1, 5, 1 do -- if BoxTable[box].firesale == true and BoxTable[box].opened == false then -- ents.FindByName("dumpster_warp_eff"..box):AcceptInput("Start") -- ents.FindByName("dumpster_warp_beam"..box):AcceptInput("Stop") -- ents.FindByName("dumpster_disappear"..box):AcceptInput("PlaySound") -- timer.Simple(1, function() ents.FindByName("dumpster_prop"..box):AcceptInput("$TeleportToEntity","dumpster_tele_out") end) -- timer.Simple(1, function() ents.FindByName("dumpster_msg"..box):AcceptInput("Disable") end) -- BoxTable[box].spawned = false -- BoxTable[DumpsterRouletteIndex].dud = true -- end -- end -- return false -- end end, 0) --end function ActivateInstakill(_,player) InstakillDuration = 1980 -- 1980 ticks divided by 66 tick rate = 30 seconds for _, player in pairs(ents.GetAllPlayers()) do if player:IsRealPlayer() then player:Print(2,"Team Critical!") player:PlaySoundToSelf("items/powerup_pickup_crits.wav") player:PlaySoundToSelf("shadows/powerup_instagib.mp3") player:AddCond(37,30) -- player:AddCond(56,30) end end end function ActivateNuke(_, player) if player:InCond(43) then -- oops forgot to do this player = player:GetConditionProvider(43) end damagebonus = player:GetAttributeValue("damage bonus") or 1 dmgmod = 1 + ((damagebonus - 1) / 1.5) dmgcalc = round(4500 * dmgmod) for _, aplayer in pairs(ents.GetAllPlayers()) do if aplayer:IsRealPlayer() then if aplayer == player then aplayer:Print(2,"Nuke ( +400$ )!\nDamage: " .. dmgcalc) else aplayer:Print(2,"Nuke ( +400$ )!") end aplayer:AddCurrency(400) timer.Simple(1,function() player:PlaySoundToSelf("shadows/powerup_nuke_01.mp3") end) elseif aplayer.m_iTeamNum == 3 then aplayer:TakeDamage({Attacker = player, Damage = dmgcalc}) end end RightSideKillCounter(dmgcalc, player, nil) end function ActivateEndNuke() for _, player in pairs(ents.GetAllPlayers()) do if player.m_iTeamNum == 3 and player.m_szNetname ~= "WinBot" then player:TakeDamage({Attacker = player, Damage = 999999}) end end end function ActivatePlague() for _, player in pairs(ents.GetAllPlayers()) do if player:IsRealPlayer() then player:Print(2,"Weaker Zombies!") player:PlaySoundToSelf("items/powerup_pickup_plague_infected.wav") end if player.m_iTeamNum == 3 then player:SetAttributeValue("move speed penalty", 0.5) timer.Simple(30, function() -- delay so the removal can work player:SetAttributeValue("move speed penalty", nil) end) end end end function ActivateStrength() for _, player in pairs(ents.GetAllPlayers()) do if player:IsRealPlayer() then player:Print(2,"Increased max HP!") player:PlaySoundToSelf("items/powerup_pickup_strength.wav") player:SetAttributeValue("max health additive penalty", 150) timer.Simple(60, function() -- delay so the removal can work player:SetAttributeValue("max health additive penalty", 0) end) end end end function ActivateUber() for _, player in pairs(ents.GetAllPlayers()) do if player:IsRealPlayer() then player:Print(2,"Team ÜberCharge!") player:PlaySoundToSelf("items/powerup_pickup_uber.wav") player:AddCond(51,15) end end end function ActivateVision() for _, player in pairs(ents.GetAllPlayers()) do if player:IsRealPlayer() then player:Print(2,"Increased Visibility!") player:PlaySoundToSelf("items/powerup_pickup_supernova_activate.wav") end end end function ActivateRandomPower(_,player) local zombiepickup = false if player:InCond(43) then -- oops forgot to do this player = player:GetConditionProvider(43) zombiepickup = true end local random local shieldslot = player:GetPlayerItemBySlot(LOADOUT_POSITION_SECONDARY) local OCcheck = shieldslot:GetAttributeValue("loot rarity") or 0 if OCcheck ~= 29 then if soloMode or zombiepickup then -- solo mode excludes suicide (15) -- revive all is replaced by power play local solopwrup = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 18} random = solopwrup[math.random(#solopwrup)] else random = math.random(18) end else random = math.random(11) end if random == 1 then -- Double Points DoublePointsDuration = DoublePointsDuration + 1980 -- 1980 ticks divided by 66 tick rate = 30 seconds for _, aplayer in pairs(ents.GetAllPlayers()) do if aplayer:IsRealPlayer() then aplayer:Print(2,"Random Powerup: Double Points!") aplayer:PlaySoundToSelf("items/spawn_item.wav") end end --elseif random == 2 then -- Fire Sale -- for _, aplayer in pairs(ents.GetAllPlayers()) do -- if aplayer:IsRealPlayer() then -- aplayer:Print(2,"Random Powerup: Fire Sale!") -- player:PlaySoundToSelf("items/spawn_item.wav") -- if FireSaleDuration <= 0 then -- timer.Simple(1,function() ents.FindByName("firesale_music"):AcceptInput("PlaySound") end) -- end -- end -- end -- FireSaleDuration = FireSaleDuration + 1980 -- 1980 ticks divided by 66 tick rate = 30 seconds -- DumpsterCost = 10 -- for box = 1, 5, 1 do -- if BoxTable[box].spawned == false then -- SpawnDumpsterBox(box) -- end -- BoxTable[box].firesale = true -- BoxTable[box].dud = false -- end -- BoxTable[DumpsterRouletteIndex].firesale = false -- timer.Create(1, -- function() if FireSaleDuration <= 0 then -- DumpsterCost = 950 -- for box = 1, 5, 1 do -- if BoxTable[box].firesale == true and BoxTable[box].opened == false then -- ents.FindByName("dumpster_warp_eff"..box):AcceptInput("Start") -- ents.FindByName("dumpster_warp_beam"..box):AcceptInput("Stop") -- ents.FindByName("dumpster_disappear"..box):AcceptInput("PlaySound") -- timer.Simple(1, function() ents.FindByName("dumpster_prop"..box):AcceptInput("$TeleportToEntity","dumpster_tele_out") end) -- timer.Simple(1, function() ents.FindByName("dumpster_msg"..box):AcceptInput("Disable") end) -- BoxTable[box].spawned = false -- BoxTable[DumpsterRouletteIndex].dud = true -- end -- end -- return false -- end end, 0) elseif random == 2 then -- Team Critical InstakillDuration = 1980 for _, aplayer in pairs(ents.GetAllPlayers()) do if aplayer:IsRealPlayer() then aplayer:Print(2,"Random Powerup: Team Critical!") aplayer:PlaySoundToSelf("items/spawn_item.wav") aplayer:AddCond(37,30) -- aplayer:AddCond(56,30) end end elseif random == 3 then -- Nuke damagebonus = player:GetAttributeValue("damage bonus") or 1 dmgmod = 1 + ((damagebonus - 1) / 1.25) dmgcalc = round(4500 * dmgmod) for _, aplayer in pairs(ents.GetAllPlayers()) do if aplayer:IsRealPlayer() then if aplayer == player then aplayer:Print(2,"Random Powerup: Nuke ( +400$ )!\nDamage: " .. dmgcalc) else aplayer:Print(2,"Random Powerup: Nuke ( +400$ )!") end aplayer:AddCurrency(400) aplayer:PlaySoundToSelf("items/spawn_item.wav") timer.Simple(1,function() aplayer:PlaySoundToSelf("shadows/powerup_nuke_01.mp3") end) elseif aplayer.m_iTeamNum == 3 then aplayer:TakeDamage({Attacker = player, Damage = dmgcalc}) end end RightSideKillCounter(dmgcalc, player, nil) elseif random == 4 then -- Plague for _, aplayer in pairs(ents.GetAllPlayers()) do if aplayer:IsRealPlayer() then aplayer:Print(2,"Random Powerup: Weaker Zombies!") aplayer:PlaySoundToSelf("items/spawn_item.wav") end if aplayer.m_iTeamNum == 3 then aplayer:SetAttributeValue("move speed penalty", 0.5) timer.Simple(30, function() -- delay so the removal can work aplayer:SetAttributeValue("move speed penalty", nil) end) end end elseif random == 5 then -- Strength for _, aplayer in pairs(ents.GetAllPlayers()) do if aplayer:IsRealPlayer() then aplayer:Print(2,"Random Powerup: Increased Max HP!") aplayer:PlaySoundToSelf("items/spawn_item.wav") aplayer:SetAttributeValue("max health additive penalty", 150) timer.Simple(60, function() -- delay so the removal can work aplayer:SetAttributeValue("max health additive penalty", 0) end) end end elseif random == 6 then -- Uber for _, aplayer in pairs(ents.GetAllPlayers()) do if aplayer:IsRealPlayer() then aplayer:Print(2,"Random Powerup: Team ÜberCharge!") aplayer:PlaySoundToSelf("items/spawn_item.wav") aplayer:AddCond(51,15) end end elseif random == 7 then -- Max Ammo for _, aplayer in pairs(ents.GetAllPlayers()) do if aplayer:IsRealPlayer() then aplayer:Print(2,"Random Powerup: Unlimited Ammo!") aplayer:PlaySoundToSelf("items/spawn_item.wav") aplayer:SetAttributeValue("maxammo primary reduced", 500) aplayer:SetAttributeValue("maxammo secondary reduced", 500) aplayer:RefillAmmo() timer.Simple(60, function() -- delay so the removal can work aplayer:SetAttributeValue("maxammo primary reduced", nil) aplayer:SetAttributeValue("maxammo secondary reduced", nil) end) end end elseif random == 8 then -- Bonus Points for _, aplayer in pairs(ents.GetAllPlayers()) do if aplayer:IsRealPlayer() then -- Generate a random number between 500 and 5000 local bonusCash = math.random(500, 5000) -- Print the correct bonus cash amount on the player's screen aplayer:Print(2, "Random Powerup: Stimulus Check: ( +" .. bonusCash .. "$ )!") -- Give the player the random bonus cash aplayer:AcceptInput("$AddCurrency", bonusCash) -- Play the sounds for the bonus points aplayer:PlaySoundToSelf("items/spawn_item.wav") end end elseif random == 9 then -- Overheal for _, aplayer in pairs(ents.GetAllPlayers()) do if aplayer:IsRealPlayer() then aplayer:Print(2,"Random Powerup: Overhealed!") aplayer:PlaySoundToSelf("items/spawn_item.wav") aplayer:AddCond(73,10) end end elseif random == 10 then -- Agility for _, aplayer in pairs(ents.GetAllPlayers()) do if aplayer:IsRealPlayer() then aplayer:Print(2,"Random Powerup: Movement Speed Boost!") aplayer:PlaySoundToSelf("items/spawn_item.wav") aplayer:AddCond(32,30) end end elseif random == 11 then -- Revive All / Power Play if soloMode then player:Print(2,"Random Powerup: Power Play!") player:PlaySoundToSelf("items/spawn_item.wav") player:AddCond(51,20) player:AddCond(32,20) player:AddCond(33,20) player:AddCond(58,20) player:AddCond(59,20) player:AddCond(60,20) else local deadnum = 0 for _, aplayer in pairs(ents.GetAllPlayers()) do if aplayer:IsRealPlayer() and aplayer.m_iTeamNum == 2 and classNames[aplayer.m_iClass] then if not aplayer:IsAlive() then deadnum = deadnum + 1 end end end if deadnum >= 1 then for _, aplayer in pairs(ents.GetAllPlayers()) do if aplayer:IsRealPlayer() then aplayer:Print(2,"Random Powerup: Revive All Dead Players!") aplayer:PlaySoundToSelf("items/spawn_item.wav") if not aplayer:IsAlive() then aplayer:ForceRespawnDead() aplayer:PlaySoundToSelf("mvm/mvm_revive.wav") aplayer:SpeakResponseConcept("TLK_RESURRECTED") aplayer:AddCond(51,4) end end end else for _, aplayer in pairs(ents.GetAllPlayers()) do if aplayer:IsRealPlayer() then aplayer:Print(2,"Random Powerup: Team Power Play!") aplayer:PlaySoundToSelf("items/spawn_item.wav") if aplayer.m_iTeamNum == 2 then aplayer:AddCond(51,20) aplayer:AddCond(32,20) aplayer:AddCond(33,20) aplayer:AddCond(58,20) aplayer:AddCond(59,20) aplayer:AddCond(60,20) end end end end end --elseif random == 13 then -- Overpriced Sale -- for _, aplayer in pairs(ents.GetAllPlayers()) do -- if aplayer:IsRealPlayer() then -- aplayer:Print(2,"Random Powerup: Overpriced Sale...") -- aplayer:PlaySoundToSelf("items/spawn_item.wav") -- if FireSaleDuration <= 0 then -- timer.Simple(1,function() ents.FindByName("firesale_music"):AcceptInput("PlaySound") end) -- end -- end -- end -- FireSaleDuration = FireSaleDuration + 1980 -- 1980 ticks divided by 66 tick rate = 30 seconds -- DumpsterCost = 4500 -- for box = 1, 5, 1 do -- if BoxTable[box].spawned == false then -- SpawnDumpsterBox(box) -- end -- BoxTable[box].firesale = true -- BoxTable[box].dud = false -- end -- BoxTable[DumpsterRouletteIndex].firesale = false -- timer.Create(1, -- function() if FireSaleDuration <= 0 then -- DumpsterCost = 950 -- for box = 1, 5, 1 do -- if BoxTable[box].firesale == true and BoxTable[box].opened == false then -- ents.FindByName("dumpster_warp_eff"..box):AcceptInput("Start") -- ents.FindByName("dumpster_warp_beam"..box):AcceptInput("Stop") -- ents.FindByName("dumpster_disappear"..box):AcceptInput("PlaySound") -- timer.Simple(1, function() ents.FindByName("dumpster_prop"..box):AcceptInput("$TeleportToEntity","dumpster_tele_out") end) -- timer.Simple(1, function() ents.FindByName("dumpster_msg"..box):AcceptInput("Disable") end) -- BoxTable[box].spawned = false -- BoxTable[DumpsterRouletteIndex].dud = true -- end -- end -- return false -- end end, 0) elseif random == 12 then -- Zombie Critical for _, aplayer in pairs(ents.GetAllPlayers()) do if aplayer:IsRealPlayer() then aplayer:Print(2,"Random Powerup: Zombie Critical...") aplayer:PlaySoundToSelf("items/spawn_item.wav") end if aplayer.m_iTeamNum == 3 then aplayer:AddCond(56,30) end end elseif random == 13 then -- Zombie Movement Speed Boost for _, aplayer in pairs(ents.GetAllPlayers()) do if aplayer:IsRealPlayer() then aplayer:Print(2,"Random Powerup: Zombies Movement Speed Boost...") aplayer:PlaySoundToSelf("items/spawn_item.wav") end if aplayer.m_iTeamNum == 3 then aplayer:AddCond(32,30) end end elseif random == 14 then -- Weakness for _, aplayer in pairs(ents.GetAllPlayers()) do if aplayer:IsRealPlayer() then aplayer:Print(2,"Random Powerup: Decreased Max HP...") aplayer:PlaySoundToSelf("items/spawn_item.wav") aplayer:SetAttributeValue("max health additive penalty", -50) timer.Simple(60, function() -- delay so the removal can work aplayer:SetAttributeValue("max health additive penalty", 0) end) end end elseif random == 15 then -- Suicide for _, aplayer in pairs(ents.GetAllPlayers()) do if aplayer:IsRealPlayer() then if aplayer:GetSteamId() == player:GetSteamId() then aplayer:Print(2,"Random Powerup: Suicide...") aplayer:PlaySoundToSelf("player/pl_fallpain.wav") aplayer:Suicide() else aplayer:Print(2,"Random Powerup: " .. player.m_szNetname .. "'s Suicide...") aplayer:PlaySoundToSelf("items/spawn_item.wav") end end end elseif random == 16 then -- No Ammo for _, aplayer in pairs(ents.GetAllPlayers()) do if aplayer:IsRealPlayer() then aplayer:Print(2,"Random Powerup: Ammo Shortage...") aplayer:PlaySoundToSelf("items/spawn_item.wav") aplayer:SetAttributeValue("maxammo primary reduced", 0.1) aplayer:SetAttributeValue("maxammo secondary reduced", 0.1) aplayer:RefillAmmo() timer.Simple(60, function() -- delay so the removal can work aplayer:SetAttributeValue("maxammo primary reduced", nil) aplayer:SetAttributeValue("maxammo secondary reduced", nil) end) end end elseif random == 17 then -- Zombie Uber for _, aplayer in pairs(ents.GetAllPlayers()) do if aplayer:IsRealPlayer() then aplayer:Print(2,"Random Powerup: Zombie ÜberCharge...") aplayer:PlaySoundToSelf("items/spawn_item.wav") end if aplayer.m_iTeamNum == 3 then aplayer:AddCond(52,15) end end elseif random == 18 then -- Points Stolen for _, aplayer in pairs(ents.GetAllPlayers()) do if aplayer:IsRealPlayer() then -- Generate a random number between 500 and 7500 local deductedCash = math.random(500, 7500) -- Print the correct bonus cash amount on the player's screen aplayer:Print(2, "Random Powerup: Points Donated To Charity: ( -" .. deductedCash .. "$ )...") -- Give the player the random bonus cash aplayer:AcceptInput("$AddCurrency", -deductedCash) -- Play the sounds for the bonus points aplayer:PlaySoundToSelf("items/spawn_item.wav") end end end end function ActivateMaxAmmo() for _, player in pairs(ents.GetAllPlayers()) do if player:IsRealPlayer() then player:Print(2,"Unlimited Ammo!") player:PlaySoundToSelf("items/powerup_pickup_agility.wav") player:PlaySoundToSelf("shadows/powerup_resupply_01.mp3") player:PlaySoundToSelf("weapons/dispenser_generate_metal.wav") player:SetAttributeValue("maxammo primary reduced", 500) player:SetAttributeValue("maxammo secondary reduced", 500) player:RefillAmmo() timer.Simple(60, function() -- delay so the removal can work player:SetAttributeValue("maxammo primary reduced", nil) player:SetAttributeValue("maxammo secondary reduced", nil) end) end end end function ActivateBonusPoints() for _, player in pairs(ents.GetAllPlayers()) do if player:IsRealPlayer() then -- Generate a random number between 500 and 5000 local bonusCash = math.random(500, 5000) -- Print the correct bonus cash amount on the player's screen player:Print(2, "Stimulus Check: ( +" .. bonusCash .. "$ )!") -- Give the player the random bonus cash player:AcceptInput("$AddCurrency", bonusCash) -- Play the sounds for the bonus points player:PlaySoundToSelf("shadows/powerup_money_01.mp3") player:PlaySoundToSelf("mvm/mvm_money_pickup.wav") end end end function ActivateOverheal() for _, player in pairs(ents.GetAllPlayers()) do if player:IsRealPlayer() then player:Print(2,"Overhealed!") player:PlaySoundToSelf("items/powerup_pickup_regeneration.wav") player:PlaySoundToSelf("weapons/dispenser_heal.wav") player:AddCond(73,10) end end end function ActivateAgility() for _, player in pairs(ents.GetAllPlayers()) do if player:IsRealPlayer() then player:Print(2,"Movement Speed Boost!") player:PlaySoundToSelf("items/powerup_pickup_agility.wav") player:AddCond(32,30) end end end function ActivatePowerPlay(_,player) if player:InCond(43) then -- oops forgot to do this player = player:GetConditionProvider(43) end InstakillDuration = 1320 -- 1320 ticks divided by 66 tick rate = 20 seconds player:Print(2,"Power Play!") player:PlaySoundToSelf("items/powerup_pickup_base.wav") player:AddCond(51,20) player:AddCond(32,20) player:AddCond(33,20) player:AddCond(58,20) player:AddCond(59,20) player:AddCond(60,20) end function KinestraRevive(_, player) -- WILDLY DIFFERENT FUNCTIONALITY IN DIVINE DELUSIONS / INFINITE INSANITY: -- - If human players == 1 (or if Solo Mode is active in Divine Delusions), then activate Power Play instead. -- - If human players > 1: -- - If dead human players >= 1, activate intended team revive effect. -- - If dead human players == 0, activate Team-Wide Power Play instead (!!!) if soloMode then ActivatePowerPlay(_, player) else local deadnum = 0 for _, aplayer in pairs(ents.GetAllPlayers()) do if aplayer:IsRealPlayer() and aplayer.m_iTeamNum == 2 and classNames[aplayer.m_iClass] then if not aplayer:IsAlive() then deadnum = deadnum + 1 end end end if deadnum >= 1 then for _, aplayer in pairs(ents.GetAllPlayers()) do if aplayer:IsRealPlayer() then aplayer:Print(2,"Revive All Dead Players!") aplayer:PlaySoundToSelf("items/powerup_pickup_agility.wav") if not aplayer:IsAlive() then aplayer:ForceRespawnDead() aplayer:PlaySoundToSelf("mvm/mvm_revive.wav") aplayer:SpeakResponseConcept("TLK_RESURRECTED") aplayer:AddCond(51,4) end end end else for _, aplayer in pairs(ents.GetAllPlayers()) do if aplayer:IsRealPlayer() then aplayer:Print(2,"Team Power Play!") aplayer:PlaySoundToSelf("items/powerup_pickup_base.wav") if aplayer.m_iTeamNum == 2 then aplayer:AddCond(51,20) aplayer:AddCond(32,20) aplayer:AddCond(33,20) aplayer:AddCond(58,20) aplayer:AddCond(59,20) aplayer:AddCond(60,20) end end end end end end BoxRoulette = { [1] = --scout { {text = "The Shortstop", itemname = "The Shortstop", model = "models/weapons/c_models/c_shortstop/c_shortstop.mdl", slot = "primary", response = "TLK_MVM_LOOT_COMMON"}, {text = "The Shortstop", itemname = "The Shortstop", model = "models/weapons/c_models/c_shortstop/c_shortstop.mdl", slot = "primary", response = "TLK_MVM_LOOT_COMMON"}, {text = "The SMG", itemname = "TF_WEAPON_SMG", model = "models/weapons/w_models/w_smg.mdl", slot = "secondary", response = "TLK_MVM_LOOT_COMMON"}, {text = "The SMG", itemname = "TF_WEAPON_SMG", model = "models/weapons/w_models/w_smg.mdl", slot = "secondary", response = "TLK_MVM_LOOT_COMMON"}, {text = "The Stickybomb Launcher", itemname = "TF_WEAPON_PIPEBOMBLAUNCHER", model = "models/weapons/w_models/w_stickybomb_launcher.mdl", slot = "secondary", response = "TLK_MVM_LOOT_COMMON"}, {text = "The Stickybomb Launcher", itemname = "TF_WEAPON_PIPEBOMBLAUNCHER", model = "models/weapons/w_models/w_stickybomb_launcher.mdl", slot = "secondary", response = "TLK_MVM_LOOT_COMMON"}, {text = "The Force-A-Nature", itemname = "The Force-a-Nature", model = "models/weapons/c_models/c_double_barrel.mdl", slot = "primary", response = "TLK_MVM_LOOT_COMMON"}, {text = "The Force-A-Nature", itemname = "The Force-a-Nature", model = "models/weapons/c_models/c_double_barrel.mdl", slot = "primary", response = "TLK_MVM_LOOT_COMMON"}, {text = "The Scattergun", itemname = "TF_WEAPON_SCATTERGUN", model = "models/weapons/w_models/w_scattergun.mdl", slot = "primary", response = "TLK_MVM_LOOT_COMMON"}, {text = "The Scattergun", itemname = "TF_WEAPON_SCATTERGUN", model = "models/weapons/w_models/w_scattergun.mdl", slot = "primary", response = "TLK_MVM_LOOT_COMMON"}, {text = "The Tomislav", itemname = "Tomislav", model = "models/weapons/c_models/c_tomislav/c_tomislav.mdl", slot = "primary", response = "TLK_MVM_LOOT_COMMON"}, {text = "The Tomislav", itemname = "Tomislav", model = "models/weapons/c_models/c_tomislav/c_tomislav.mdl", slot = "primary", response = "TLK_MVM_LOOT_COMMON"}, {text = "The Pistol", itemname = "TF_WEAPON_PISTOL", model = "models/weapons/c_models/c_pistol/c_pistol.mdl", slot = "secondary", response = "TLK_MVM_LOOT_COMMON"}, {text = "The Pistol", itemname = "TF_WEAPON_PISTOL", model = "models/weapons/c_models/c_pistol/c_pistol.mdl", slot = "secondary", response = "TLK_MVM_LOOT_COMMON"}, {text = "Nail Gun", itemname = "Nail Gun", model = "models/workshop/weapons/c_models/c_nailgun/c_nailgun.mdl", slot = "primary", response = "TLK_MVM_LOOT_COMMON"}, {text = "Nail Gun", itemname = "Nail Gun", model = "models/workshop/weapons/c_models/c_nailgun/c_nailgun.mdl", slot = "primary", response = "TLK_MVM_LOOT_COMMON"}, {text = "The Punch Packer", itemname = "The Punch Packer", model = "models/weapons/c_models/c_packer.mdl", slot = "primary", response = "TLK_MVM_LOOT_RARE"}, {text = "The Punch Packer", itemname = "The Punch Packer", model = "models/weapons/c_models/c_packer.mdl", slot = "primary", response = "TLK_MVM_LOOT_RARE"}, {text = "The Punch Packer", itemname = "The Punch Packer", model = "models/weapons/c_models/c_packer.mdl", slot = "primary", response = "TLK_MVM_LOOT_RARE"}, {text = "Baby Face's Blaster 2012", itemname = "Baby Face's Blaster 2012", model = "models/weapons/c_models/c_pep_scattergun.mdl", slot = "primary", response = "TLK_MVM_LOOT_RARE"}, {text = "a dud", itemname = "Dud", model = "models/workshop/weapons/c_models/c_invasion_pistol/c_invasion_pistol.mdl"}, }, [2] = --sniper { -- {text = "The Shotgun", itemname = "TF_WEAPON_SHOTGUN_PYRO", model = "models/weapons/w_models/w_shotgun.mdl", slot = "secondary", response = "TLK_MVM_LOOT_COMMON"}, -- no more sniper shotgun -- {text = "The Shotgun", itemname = "TF_WEAPON_SHOTGUN_PYRO", model = "models/weapons/w_models/w_shotgun.mdl", slot = "secondary", response = "TLK_MVM_LOOT_COMMON"}, -- uberupgrade makes this overtake Primary weapon {text = "The Scattergun", itemname = "TF_WEAPON_SCATTERGUN", model = "models/weapons/w_models/w_scattergun.mdl", slot = "primary", response = "TLK_MVM_LOOT_COMMON"}, {text = "The Scattergun", itemname = "TF_WEAPON_SCATTERGUN", model = "models/weapons/w_models/w_scattergun.mdl", slot = "primary", response = "TLK_MVM_LOOT_COMMON"}, {text = "The Double Barrel", itemname = "Double Barrel", model = "models/weapons/c_models/c_shotfun/c_shotfun.mdl", slot = "secondary", response = "TLK_MVM_LOOT_COMMON"}, {text = "The Double Barrel", itemname = "Double Barrel", model = "models/weapons/c_models/c_shotfun/c_shotfun.mdl", slot = "secondary", response = "TLK_MVM_LOOT_COMMON"}, {text = "The Stickybomb Launcher", itemname = "TF_WEAPON_PIPEBOMBLAUNCHER", model = "models/weapons/w_models/w_stickybomb_launcher.mdl", slot = "secondary", response = "TLK_MVM_LOOT_COMMON"}, {text = "The Stickybomb Launcher", itemname = "TF_WEAPON_PIPEBOMBLAUNCHER", model = "models/weapons/w_models/w_stickybomb_launcher.mdl", slot = "secondary", response = "TLK_MVM_LOOT_COMMON"}, {text = "The Crusader's Crossbow", itemname = "The Crusader's Crossbow", model = "models/weapons/c_models/c_crusaders_crossbow/c_crusaders_crossbow.mdl", slot = "primary", response = "TLK_MVM_LOOT_COMMON"}, {text = "The Crusader's Crossbow", itemname = "The Crusader's Crossbow", model = "models/weapons/c_models/c_crusaders_crossbow/c_crusaders_crossbow.mdl", slot = "primary", response = "TLK_MVM_LOOT_COMMON"}, {text = "The Rescue Ranger", itemname = "The Rescue Ranger", model = "models/weapons/c_models/c_tele_shotgun/c_tele_shotgun.mdl", slot = "primary", response = "TLK_MVM_LOOT_RARE"}, {text = "The Beam Rifle", itemname = "Beam Rifle", model = "models/workshop/weapons/c_models/c_drg_pomson/c_drg_pomson.mdl", slot = "secondary", response = "TLK_MVM_LOOT_RARE"}, {text = "The Punch Packer", itemname = "The Punch Packer", model = "models/weapons/c_models/c_packer.mdl", slot = "primary", response = "TLK_MVM_LOOT_RARE"}, {text = "AK-47", itemname = "AK-47", model = "models/weapons/c_models/c_ak47/c_mmg.mdl", slot = "secondary", response = "TLK_MVM_LOOT_RARE"}, {text = "The Ray Gun", itemname = "The Ray Gun", model = "models/workshop/weapons/c_models/c_invasion_pistol/c_invasion_pistol.mdl", slot = "secondary", response = "TLK_MVM_LOOT_RARE"}, {text = "The Cleaner's Carbine", itemname = "The Cleaner's Carbine", model = "models/workshop/weapons/c_models/c_pro_smg/c_pro_smg.mdl", slot = "secondary", response = "TLK_MVM_LOOT_COMMON"}, {text = "a dud", itemname = "Dud", model = "models/workshop/weapons/c_models/c_invasion_pistol/c_invasion_pistol.mdl"}, }, [3] = --Soldier { {text = "The Double Barrel", itemname = "Double Barrel", model = "models/weapons/c_models/c_shotfun/c_shotfun.mdl", slot = "secondary", response = "TLK_MVM_LOOT_COMMON"}, {text = "The Double Barrel", itemname = "Double Barrel", model = "models/weapons/c_models/c_shotfun/c_shotfun.mdl", slot = "secondary", response = "TLK_MVM_LOOT_COMMON"}, {text = "The SMG", itemname = "TF_WEAPON_SMG", model = "models/weapons/w_models/w_smg.mdl", slot = "secondary", response = "TLK_MVM_LOOT_COMMON"}, {text = "The SMG", itemname = "TF_WEAPON_SMG", model = "models/weapons/w_models/w_smg.mdl", slot = "secondary", response = "TLK_MVM_LOOT_COMMON"}, {text = "The Beam Rifle", itemname = "Beam Rifle", model = "models/workshop/weapons/c_models/c_drg_pomson/c_drg_pomson.mdl", slot = "secondary", response = "TLK_MVM_LOOT_RARE"}, {text = "The Tactigatling", itemname = "Tactigatling", model = "models/weapons/c_models/c_tgat/c_tgat.mdl", slot = "secondary", response = "TLK_MVM_LOOT_RARE"}, {text = "The Ray Gun", itemname = "The Ray Gun", model = "models/workshop/weapons/c_models/c_invasion_pistol/c_invasion_pistol.mdl", slot = "secondary", response = "TLK_MVM_LOOT_RARE"}, {text = "The Cleaner's Carbine", itemname = "The Cleaner's Carbine", model = "models/workshop/weapons/c_models/c_pro_smg/c_pro_smg.mdl", slot = "secondary", response = "TLK_MVM_LOOT_COMMON"}, {text = "The Cleaner's Carbine", itemname = "The Cleaner's Carbine", model = "models/workshop/weapons/c_models/c_pro_smg/c_pro_smg.mdl", slot = "secondary", response = "TLK_MVM_LOOT_COMMON"}, {text = "The Rocket Launcher", itemname = "TF_WEAPON_ROCKETLAUNCHER", model = "models/weapons/w_models/w_rocketlauncher.mdl", slot = "primary", response = "TLK_MVM_LOOT_RARE"}, {text = "The Black Box", itemname = "The Black Box", model = "models/workshop/weapons/c_models/c_blackbox/c_blackbox.mdl", slot = "primary", response = "TLK_MVM_LOOT_RARE"}, {text = "W.A.S.P Launcher", itemname = "W.A.S.P Launcher", model = "models/weapons/c_models/c_wasp_launcher/c_wasp_launcher_1.mdl", slot = "primary", response = "TLK_MVM_LOOT_RARE"}, {text = "The Thunder Gun", itemname = "Thunder Gun", model = "models/weapons/c_models/c_drg_phlogistinator/c_drg_phlogistinator.mdl", slot = "secondary", response = "TLK_MVM_LOOT_ULTRARARE"}, {text = "a dud", itemname = "Dud", model = "models/workshop/weapons/c_models/c_invasion_pistol/c_invasion_pistol.mdl"}, }, [4] = --Demoman { -- {text = "The Shotgun", itemname = "TF_WEAPON_SHOTGUN_PYRO", model = "models/weapons/w_models/w_shotgun.mdl", slot = "secondary", response = "TLK_MVM_LOOT_COMMON"}, -- removed due to loadout issues -- {text = "The Shotgun", itemname = "TF_WEAPON_SHOTGUN_PYRO", model = "models/weapons/w_models/w_shotgun.mdl", slot = "secondary", response = "TLK_MVM_LOOT_COMMON"}, -- uberupgrade takes away Primary weapon {text = "The Double Barrel", itemname = "Double Barrel", model = "models/weapons/c_models/c_shotfun/c_shotfun.mdl", slot = "secondary", response = "TLK_MVM_LOOT_COMMON"}, {text = "The Double Barrel", itemname = "Double Barrel", model = "models/weapons/c_models/c_shotfun/c_shotfun.mdl", slot = "secondary", response = "TLK_MVM_LOOT_COMMON"}, {text = "The SMG", itemname = "TF_WEAPON_SMG", model = "models/weapons/w_models/w_smg.mdl", slot = "secondary", response = "TLK_MVM_LOOT_COMMON"}, {text = "The SMG", itemname = "TF_WEAPON_SMG", model = "models/weapons/w_models/w_smg.mdl", slot = "secondary", response = "TLK_MVM_LOOT_COMMON"}, {text = "The Stickybomb Launcher", itemname = "TF_WEAPON_PIPEBOMBLAUNCHER", model = "models/weapons/w_models/w_stickybomb_launcher.mdl", slot = "secondary", response = "TLK_MVM_LOOT_COMMON"}, {text = "The Stickybomb Launcher", itemname = "TF_WEAPON_PIPEBOMBLAUNCHER", model = "models/weapons/w_models/w_stickybomb_launcher.mdl", slot = "secondary", response = "TLK_MVM_LOOT_COMMON"}, {text = "The Iron Bomber", itemname = "The Iron Bomber", model = "models/workshop/weapons/c_models/c_quadball/c_quadball.mdl", slot = "primary", response = "TLK_MVM_LOOT_COMMON"}, {text = "The Iron Bomber", itemname = "The Iron Bomber", model = "models/workshop/weapons/c_models/c_quadball/c_quadball.mdl", slot = "primary", response = "TLK_MVM_LOOT_COMMON"}, {text = "The Chargin' Targe", itemname = "The Chargin' Targe", model = "models/weapons/c_models/c_targe/c_targe.mdl", slot = "secondary", response = "TLK_MVM_LOOT_RARE"}, {text = "The Beam Rifle", itemname = "Beam Rifle", model = "models/workshop/weapons/c_models/c_drg_pomson/c_drg_pomson.mdl", slot = "secondary", response = "TLK_MVM_LOOT_RARE"}, {text = "The Tactigatling", itemname = "Tactigatling", model = "models/weapons/c_models/c_tgat/c_tgat.mdl", slot = "secondary", response = "TLK_MVM_LOOT_RARE"}, {text = "The Grenade Launcher", itemname = "TF_WEAPON_GRENADELAUNCHER", model = "models/weapons/c_models/c_grenadelauncher/c_grenadelauncher.mdl", slot = "primary", response = "TLK_MVM_LOOT_RARE"}, {text = "The Ray Gun", itemname = "The Ray Gun", model = "models/workshop/weapons/c_models/c_invasion_pistol/c_invasion_pistol.mdl", slot = "secondary", response = "TLK_MVM_LOOT_RARE"}, {text = "a dud", itemname = "Dud", model = "models/workshop/weapons/c_models/c_invasion_pistol/c_invasion_pistol.mdl"}, }, [5] = --medic { {text = "The Scattergun", itemname = "TF_WEAPON_SCATTERGUN", model = "models/weapons/w_models/w_scattergun.mdl", slot = "primary", response = "TLK_MVM_LOOT_COMMON"}, {text = "The Scattergun", itemname = "TF_WEAPON_SCATTERGUN", model = "models/weapons/w_models/w_scattergun.mdl", slot = "primary", response = "TLK_MVM_LOOT_COMMON"}, {text = "The Flamethrower", itemname = "TF_WEAPON_FLAMETHROWER", model = "models/weapons/c_models/c_flamethrower/c_flamethrower.mdl", slot = "primary", response = "TLK_MVM_LOOT_COMMON"}, {text = "The Flamethrower", itemname = "TF_WEAPON_FLAMETHROWER", model = "models/weapons/c_models/c_flamethrower/c_flamethrower.mdl", slot = "primary", response = "TLK_MVM_LOOT_COMMON"}, {text = "The Punch Packer", itemname = "The Punch Packer", model = "models/weapons/c_models/c_packer.mdl", slot = "primary", response = "TLK_MVM_LOOT_COMMON"}, {text = "The Punch Packer", itemname = "The Punch Packer", model = "models/weapons/c_models/c_packer.mdl", slot = "primary", response = "TLK_MVM_LOOT_COMMON"}, {text = "The SMG", itemname = "Primary SMG", model = "models/weapons/w_models/w_smg.mdl", slot = "primary", response = "TLK_MVM_LOOT_COMMON"}, {text = "The SMG", itemname = "Primary SMG", model = "models/weapons/w_models/w_smg.mdl", slot = "primary", response = "TLK_MVM_LOOT_COMMON"}, {text = "The Crusader's Crossbow", itemname = "The Crusader's Crossbow", model = "models/weapons/c_models/c_crusaders_crossbow/c_crusaders_crossbow.mdl", slot = "primary", response = "TLK_MVM_LOOT_COMMON"}, {text = "The Crusader's Crossbow", itemname = "The Crusader's Crossbow", model = "models/weapons/c_models/c_crusaders_crossbow/c_crusaders_crossbow.mdl", slot = "primary", response = "TLK_MVM_LOOT_COMMON"}, {text = "The DNA Rejuvenator", itemname = "DNA Rejuvenator", model = "models/workshop/weapons/c_models/c_uberneedle/c_uberneedle.mdl", slot = "melee", response = "TLK_MVM_LOOT_ULTRARARE"}, {text = "The Black Box", itemname = "The Black Box", model = "models/workshop/weapons/c_models/c_blackbox/c_blackbox.mdl", slot = "primary", response = "TLK_MVM_LOOT_RARE"}, {text = "Das Maschinenpistole", itemname = "Das Maschinenpistole", model = "models/weapons/c_models/c_mp40/c_mp40.mdl", slot = "primary", response = "TLK_MVM_LOOT_RARE"}, {text = "Das Maschinenpistole", itemname = "Das Maschinenpistole", model = "models/weapons/c_models/c_mp40/c_mp40.mdl", slot = "primary", response = "TLK_MVM_LOOT_RARE"}, {text = "a dud", itemname = "Dud", model = "models/workshop/weapons/c_models/c_invasion_pistol/c_invasion_pistol.mdl"}, }, [6] = --heavy { {text = "The Double Barrel", itemname = "Double Barrel", model = "models/weapons/c_models/c_shotfun/c_shotfun.mdl", slot = "secondary", response = "TLK_MVM_LOOT_COMMON"}, {text = "The Double Barrel", itemname = "Double Barrel", model = "models/weapons/c_models/c_shotfun/c_shotfun.mdl", slot = "secondary", response = "TLK_MVM_LOOT_COMMON"}, {text = "The Flamethrower", itemname = "TF_WEAPON_FLAMETHROWER", model = "models/weapons/c_models/c_flamethrower/c_flamethrower.mdl", slot = "primary", response = "TLK_MVM_LOOT_COMMON"}, {text = "The Flamethrower", itemname = "TF_WEAPON_FLAMETHROWER", model = "models/weapons/c_models/c_flamethrower/c_flamethrower.mdl", slot = "primary", response = "TLK_MVM_LOOT_COMMON"}, {text = "The Minigun", itemname = "TF_WEAPON_MINIGUN", model = "models/weapons/w_models/w_minigun.mdl", slot = "primary", response = "TLK_MVM_LOOT_COMMON"}, {text = "The Minigun", itemname = "TF_WEAPON_MINIGUN", model = "models/weapons/w_models/w_minigun.mdl", slot = "primary", response = "TLK_MVM_LOOT_COMMON"}, {text = "The Tomislav", itemname = "Tomislav", model = "models/weapons/c_models/c_tomislav/c_tomislav.mdl", slot = "primary", response = "TLK_MVM_LOOT_COMMON"}, {text = "The Tomislav", itemname = "Tomislav", model = "models/weapons/c_models/c_tomislav/c_tomislav.mdl", slot = "primary", response = "TLK_MVM_LOOT_COMMON"}, {text = "The SMG", itemname = "TF_WEAPON_SMG", model = "models/weapons/w_models/w_smg.mdl", slot = "secondary", response = "TLK_MVM_LOOT_COMMON"}, {text = "The SMG", itemname = "TF_WEAPON_SMG", model = "models/weapons/w_models/w_smg.mdl", slot = "secondary", response = "TLK_MVM_LOOT_COMMON"}, {text = "The Beam Rifle", itemname = "Beam Rifle", model = "models/workshop/weapons/c_models/c_drg_pomson/c_drg_pomson.mdl", slot = "secondary", response = "TLK_MVM_LOOT_RARE"}, {text = "The Tactigatling", itemname = "Tactigatling", model = "models/weapons/c_models/c_tgat/c_tgat.mdl", slot = "secondary", response = "TLK_MVM_LOOT_RARE"}, {text = "Chainsaw", itemname = "Chainsaw", model = "models/weapons/c_models/c_w_chainsaw/c_w_chainsaw.mdl", slot = "primary", response = "TLK_MVM_LOOT_RARE"}, {text = "The Ray Gun", itemname = "The Ray Gun", model = "models/workshop/weapons/c_models/c_invasion_pistol/c_invasion_pistol.mdl", slot = "secondary", response = "TLK_MVM_LOOT_RARE"}, {text = "The Thunder Gun", itemname = "Thunder Gun", model = "models/weapons/c_models/c_drg_phlogistinator/c_drg_phlogistinator.mdl", slot = "secondary", response = "TLK_MVM_LOOT_ULTRARARE"}, {text = "a dud", itemname = "Dud", model = "models/workshop/weapons/c_models/c_invasion_pistol/c_invasion_pistol.mdl"}, }, [7] = --pyro { {text = "The Dragon's Fury", itemname = "The Dragon's Fury", model = "models/weapons/c_models/c_flameball/c_flameball.mdl", slot = "primary", response = "TLK_MVM_LOOT_COMMON"}, {text = "The Dragon's Fury", itemname = "The Dragon's Fury", model = "models/weapons/c_models/c_flameball/c_flameball.mdl", slot = "primary", response = "TLK_MVM_LOOT_COMMON"}, {text = "The Double Barrel", itemname = "Double Barrel", model = "models/weapons/c_models/c_shotfun/c_shotfun.mdl", slot = "secondary", response = "TLK_MVM_LOOT_COMMON"}, {text = "The Double Barrel", itemname = "Double Barrel", model = "models/weapons/c_models/c_shotfun/c_shotfun.mdl", slot = "secondary", response = "TLK_MVM_LOOT_COMMON"}, {text = "The Flamethrower", itemname = "TF_WEAPON_FLAMETHROWER", model = "models/weapons/c_models/c_flamethrower/c_flamethrower.mdl", slot = "primary", response = "TLK_MVM_LOOT_COMMON"}, {text = "The Flamethrower", itemname = "TF_WEAPON_FLAMETHROWER", model = "models/weapons/c_models/c_flamethrower/c_flamethrower.mdl", slot = "primary", response = "TLK_MVM_LOOT_COMMON"}, {text = "The Minigun", itemname = "TF_WEAPON_MINIGUN", model = "models/weapons/w_models/w_minigun.mdl", slot = "primary", response = "TLK_MVM_LOOT_COMMON"}, {text = "The Minigun", itemname = "TF_WEAPON_MINIGUN", model = "models/weapons/w_models/w_minigun.mdl", slot = "primary", response = "TLK_MVM_LOOT_COMMON"}, {text = "The SMG", itemname = "TF_WEAPON_SMG", model = "models/weapons/w_models/w_smg.mdl", slot = "secondary", response = "TLK_MVM_LOOT_COMMON"}, {text = "The SMG", itemname = "TF_WEAPON_SMG", model = "models/weapons/w_models/w_smg.mdl", slot = "secondary", response = "TLK_MVM_LOOT_COMMON"}, {text = "The Iron Bomber", itemname = "The Iron Bomber", model = "models/workshop/weapons/c_models/c_quadball/c_quadball.mdl", slot = "primary", response = "TLK_MVM_LOOT_COMMON"}, {text = "The Iron Bomber", itemname = "The Iron Bomber", model = "models/workshop/weapons/c_models/c_quadball/c_quadball.mdl", slot = "primary", response = "TLK_MVM_LOOT_COMMON"}, {text = "The Detonator", itemname = "The Detonator", model = "models/weapons/c_models/c_detonator/c_detonator.mdl", slot = "secondary", response = "TLK_MVM_LOOT_COMMON"}, {text = "The Detonator", itemname = "The Detonator", model = "models/weapons/c_models/c_detonator/c_detonator.mdl", slot = "secondary", response = "TLK_MVM_LOOT_COMMON"}, {text = "The Tactigatling", itemname = "Tactigatling", model = "models/weapons/c_models/c_tgat/c_tgat.mdl", slot = "secondary", response = "TLK_MVM_LOOT_RARE"}, {text = "The Ray Gun", itemname = "The Ray Gun", model = "models/workshop/weapons/c_models/c_invasion_pistol/c_invasion_pistol.mdl", slot = "secondary", response = "TLK_MVM_LOOT_RARE"}, {text = "The Thunder Gun", itemname = "Thunder Gun", model = "models/weapons/c_models/c_drg_phlogistinator/c_drg_phlogistinator.mdl", slot = "secondary", response = "TLK_MVM_LOOT_ULTRARARE"}, {text = "a dud", itemname = "Dud", model = "models/workshop/weapons/c_models/c_invasion_pistol/c_invasion_pistol.mdl"}, }, [8] = --spy { {text = "The SMG", itemname = "TF_WEAPON_SMG", model = "models/weapons/w_models/w_smg.mdl", slot = "secondary", response = "TLK_MVM_LOOT_COMMON"}, {text = "The SMG", itemname = "TF_WEAPON_SMG", model = "models/weapons/w_models/w_smg.mdl", slot = "secondary", response = "TLK_MVM_LOOT_COMMON"}, {text = "The Ambassador", itemname = "The Ambassador", model = "models/weapons/c_models/c_ambassador/c_ambassador.mdl", slot = "secondary", response = "TLK_MVM_LOOT_COMMON"}, {text = "The Ambassador", itemname = "The Ambassador", model = "models/weapons/c_models/c_ambassador/c_ambassador.mdl", slot = "secondary", response = "TLK_MVM_LOOT_COMMON"}, {text = "The Shortstop", itemname = "The Shortstop", model = "models/weapons/c_models/c_shortstop/c_shortstop.mdl", slot = "primary", response = "TLK_MVM_LOOT_COMMON"}, {text = "The Shortstop", itemname = "The Shortstop", model = "models/weapons/c_models/c_shortstop/c_shortstop.mdl", slot = "primary", response = "TLK_MVM_LOOT_COMMON"}, {text = "The Winger", itemname = "The Winger", model = "models/weapons/c_models/c_winger_pistol/c_winger_pistol.mdl", slot = "secondary", response = "TLK_MVM_LOOT_COMMON"}, {text = "The Winger", itemname = "The Winger", model = "models/weapons/c_models/c_winger_pistol/c_winger_pistol.mdl", slot = "secondary", response = "TLK_MVM_LOOT_COMMON"}, {text = "The Pistol", itemname = "TF_WEAPON_PISTOL", model = "models/weapons/c_models/c_pistol/c_pistol.mdl", slot = "secondary", response = "TLK_MVM_LOOT_COMMON"}, {text = "The Pistol", itemname = "TF_WEAPON_PISTOL", model = "models/weapons/c_models/c_pistol/c_pistol.mdl", slot = "secondary", response = "TLK_MVM_LOOT_COMMON"}, {text = "Nail Gun", itemname = "Nail Gun", model = "models/workshop/weapons/c_models/c_nailgun/c_nailgun.mdl", slot = "primary", response = "TLK_MVM_LOOT_COMMON"}, {text = "Nail Gun", itemname = "Nail Gun", model = "models/workshop/weapons/c_models/c_nailgun/c_nailgun.mdl", slot = "primary", response = "TLK_MVM_LOOT_COMMON"}, {text = "Injuste", itemname = "Injuste", model = "models/weapons/c_models/c_death_blossom/c_death_blossom.mdl", slot = "secondary", response = "TLK_MVM_LOOT_RARE"}, {text = "The Ray Gun", itemname = "The Ray Gun", model = "models/workshop/weapons/c_models/c_invasion_pistol/c_invasion_pistol.mdl", slot = "secondary", response = "TLK_MVM_LOOT_RARE"}, {text = "a dud", itemname = "Dud", model = "models/workshop/weapons/c_models/c_invasion_pistol/c_invasion_pistol.mdl"}, }, [9] = --engineer { {text = "The Shotgun", itemname = "TF_WEAPON_SHOTGUN_PRIMARY", model = "models/weapons/w_models/w_shotgun.mdl", slot = "primary", response = "TLK_MVM_LOOT_COMMON"}, {text = "The Shotgun", itemname = "TF_WEAPON_SHOTGUN_PRIMARY", model = "models/weapons/w_models/w_shotgun.mdl", slot = "primary", response = "TLK_MVM_LOOT_COMMON"}, {text = "The Scattergun", itemname = "TF_WEAPON_SCATTERGUN", model = "models/weapons/w_models/w_scattergun.mdl", slot = "primary", response = "TLK_MVM_LOOT_COMMON"}, {text = "The SMG", itemname = "TF_WEAPON_SMG", model = "models/weapons/w_models/w_smg.mdl", slot = "secondary", response = "TLK_MVM_LOOT_COMMON"}, {text = "The SMG", itemname = "TF_WEAPON_SMG", model = "models/weapons/w_models/w_smg.mdl", slot = "secondary", response = "TLK_MVM_LOOT_COMMON"}, {text = "The B.M.M.H", itemname = "The B.M.M.H", model = "models/weapons/c_models/c_bmmh/c_bmmh.mdl", slot = "primary", response = "TLK_MVM_LOOT_COMMON"}, {text = "The B.M.M.H", itemname = "The B.M.M.H", model = "models/weapons/c_models/c_bmmh/c_bmmh.mdl", slot = "primary", response = "TLK_MVM_LOOT_COMMON"}, {text = "The Nostromo Napalmer", itemname = "The Nostromo Napalmer", model = "models/workshop_partner/weapons/c_models/c_ai_flamethrower/c_ai_flamethrower.mdl", slot = "primary", response = "TLK_MVM_LOOT_COMMON"}, {text = "The Nostromo Napalmer", itemname = "The Nostromo Napalmer", model = "models/workshop_partner/weapons/c_models/c_ai_flamethrower/c_ai_flamethrower.mdl", slot = "primary", response = "TLK_MVM_LOOT_COMMON"}, {text = "The Pistol", itemname = "TF_WEAPON_PISTOL", model = "models/weapons/c_models/c_pistol/c_pistol.mdl", slot = "secondary", response = "TLK_MVM_LOOT_COMMON"}, {text = "The Pistol", itemname = "TF_WEAPON_PISTOL", model = "models/weapons/c_models/c_pistol/c_pistol.mdl", slot = "secondary", response = "TLK_MVM_LOOT_COMMON"}, {text = "The Rescue Ranger", itemname = "The Rescue Ranger", model = "models/weapons/c_models/c_tele_shotgun/c_tele_shotgun.mdl", slot = "primary", response = "TLK_MVM_LOOT_RARE"}, {text = "The Punch Packer", itemname = "The Punch Packer", model = "models/weapons/c_models/c_packer.mdl", slot = "primary", response = "TLK_MVM_LOOT_RARE"}, {text = "The Ray Gun", itemname = "The Ray Gun", model = "models/workshop/weapons/c_models/c_invasion_pistol/c_invasion_pistol.mdl", slot = "secondary", response = "TLK_MVM_LOOT_RARE"}, {text = "a dud", itemname = "Dud", model = "models/workshop/weapons/c_models/c_invasion_pistol/c_invasion_pistol.mdl"}, } } --[[function SpawnDumpsterBox(box) if FireSaleDuration <= 0 then BoxTable[box].firesale = false BoxTable[box].dud = true end if BoxTable[box].spawned == false then BoxTable[box].spawned = true ents.FindByName("dumpster_push"..box):AcceptInput("$TeleportToEntity","dumpster_tele_"..box) ents.FindByName("dumpster_push"..box):AcceptInput("Enable") ents.FindByName("dumpster_lid"..box):AcceptInput("TurnOff") ents.FindByName("dumpster_weapon"..box):AcceptInput("TurnOff") ents.FindByName("dumpster_prop"..box):AcceptInput("TurnOff") ents.FindByName("dumpster_light"..box):AcceptInput("TurnOff") ents.FindByName("dumpster_msg"..box):AcceptInput("Disable") ents.FindByName("dumpster_weapon"..box):AcceptInput("SetParent","dumpster_train"..box) timer.Simple(1, function() ents.FindByName("dumpster_prop"..box):AcceptInput("$TeleportToEntity","dumpster_tele_"..box) end) timer.Simple(1, function() ents.FindByName("dumpster_warp_eff"..box):AcceptInput("Start") end) timer.Simple(1, function() ents.FindByName("dumpster_warp_beam"..box):AcceptInput("Start") end) timer.Simple(1.5, function() ents.FindByName("dumpster_appear"..box):AcceptInput("PlaySound") end) timer.Simple(2, function() ents.FindByName("dumpster_lid"..box):AcceptInput("TurnOn") end) timer.Simple(2, function() ents.FindByName("dumpster_prop"..box):AcceptInput("TurnOn") end) timer.Simple(2, function() ents.FindByName("dumpster_msg"..box):AcceptInput("Enable") end) timer.Simple(2, function() ents.FindByName("dumpster_push"..box):AcceptInput("Disable") end) timer.Simple(3.2, function() ents.FindByName("dumpster_warp_eff"..box):AcceptInput("Stop") end) BoxTable[box].message = ents.FindByName("dumpster_msg"..box):AddCallback(ON_START_TOUCH, function(_, player) if player:IsRealPlayer() then player.InteractWith = "dumpsterbutton"..box player:Print(2,"Hold Action key (Default H) to receive a weapon for $"..DumpsterCost) end end) ents.FindByName("dumpster_msg"..box):AddCallback(ON_END_TOUCH, function(_, player) if player:IsRealPlayer() then player.InteractWith = "nothing" player:Print(2,"") end end) end end function OpenDumpsterBox(player, box) local owner = player BoxTable[box].count = BoxTable[box].count + 1 BoxTable[box].opened = true ents.FindByName("dumpster_rotdoor"..box):AcceptInput("Open") ents.FindByName("dumpster_light"..box):AcceptInput("TurnOn") ents.FindByName("dumpster_msg"..box):AcceptInput("Disable") ents.FindByName("dumpster_train"..box):AcceptInput("SetSpeed", "0.2") ents.FindByName("dumpster_jingle"..box):AcceptInput("PlaySound") ents.FindByName("dumpster_weapon"..box):AcceptInput("Enable") ents.FindByName("dumpster_particles"..box):AcceptInput("Start") ents.FindByName("dumpster_train"..box):AcceptInput("TeleportToPathTrack", "dumpster_track1"..box) ents.FindByName("dumpster_msg"..box):RemoveCallback(14,BoxTable[box].message) local ChangeWeapon = timer.Create(0.1, function() local number = math.random(1, #BoxRoulette[player.m_iClass]) ents.FindByName("dumpster_weapon"..box):AcceptInput("$SetModel", BoxRoulette[player.m_iClass][number].model) BoxTable[box].weapon = BoxRoulette[player.m_iClass][number].itemname BoxTable[box].text = BoxRoulette[player.m_iClass][number].text BoxTable[box].slot = BoxRoulette[player.m_iClass][number].slot BoxTable[box].response = BoxRoulette[player.m_iClass][number].response end, 0 ) timer.Simple(4, function() timer.Stop(ChangeWeapon) if BoxTable[box].weapon == "Dud" then if BoxTable[box].dud == true and BoxTable[box].firesale == false and BoxTable[box].count >= 4 then BoxTable[box].count = 0 if DumpsterRouletteIndex == 5 then ShuffleInPlace(DumpsterRoulette) DumpsterRouletteIndex = 0 end DumpsterRouletteIndex = DumpsterRouletteIndex+1 ents.FindByName("dumpster_dudprop"..box):AcceptInput("Enable") ents.FindByName("dumpster_weapon"..box):AcceptInput("Disable") player:AddCurrency("950") player:PlaySoundToSelf("misc/happy_birthday_tf_10.wav") timer.Simple(1, function() player:PlaySoundToSelf("shadows/powerup_dud_03.mp3") end) timer.Simple(3, function() ents.FindByName("dumpster_warp_eff"..box):AcceptInput("Start") end) timer.Simple(3, function() ents.FindByName("dumpster_warp_beam"..box):AcceptInput("Stop") end) timer.Simple(3, function() ents.FindByName("dumpster_disappear"..box):AcceptInput("PlaySound") end) timer.Simple(4, function() ents.FindByName("dumpster_prop"..box):AcceptInput("$TeleportToEntity","dumpster_tele_out") end) timer.Simple(4, function() ents.FindByName("dumpster_dudprop"..box):AcceptInput("Disable") end) timer.Simple(4, function() BoxTable[box].spawned = false end) timer.Simple(24, function() SpawnDumpsterBox(DumpsterRouletteIndex) end) else number = math.random(1, #BoxRoulette[player.m_iClass]-1) ents.FindByName("dumpster_weapon"..box):AcceptInput("$SetModel", BoxRoulette[player.m_iClass][number].model) BoxTable[box].weapon = BoxRoulette[player.m_iClass][number].itemname BoxTable[box].text = BoxRoulette[player.m_iClass][number].text BoxTable[box].slot = BoxRoulette[player.m_iClass][number].slot BoxTable[box].response = BoxRoulette[player.m_iClass][number].response BoxTable[box].message = ents.FindByName("dumpster_msg"..box):AddCallback(ON_START_TOUCH, function(_, player) if player:IsRealPlayer() and player == owner then player.InteractWith = "tradeweapon"..box player:Print(2,"Hold Action key (Default H) to trade your " .. BoxTable[box].slot .. " weapon with " .. BoxTable[box].text) end end) ents.FindByName("dumpster_msg"..box):AcceptInput("Enable") ents.FindByName("dumpster_train"..box):AcceptInput("TeleportToPathTrack", "dumpster_track2"..box) ents.FindByName("dumpster_train"..box):AcceptInput("SetSpeedDir", "0.02") end elseif BoxTable[box].weapon == "Thunder Gun" and ThunderGunTaken == true then ents.FindByName("dumpster_weapon"..box):AcceptInput("$SetModel", "models/weapons/c_models/c_shotfun/c_shotfun.mdl") BoxTable[box].weapon = "Double Barrel" BoxTable[box].text = "The Double Barrel" BoxTable[box].slot = "secondary" BoxTable[box].response = "TLK_MVM_LOOT_COMMON" elseif BoxTable[box].weapon == "DNA Rejuvenator" and RejuvenatorTaken == true then ents.FindByName("dumpster_weapon"..box):AcceptInput("$SetModel", "models/weapons/w_models/w_smg.mdl") BoxTable[box].weapon = "Primary SMG" BoxTable[box].text = "The SMG" BoxTable[box].slot = "primary" BoxTable[box].response = "TLK_MVM_LOOT_COMMON" BoxTable[box].message = ents.FindByName("dumpster_msg"..box):AddCallback(ON_START_TOUCH, function(_, player) if player:IsRealPlayer() and player == owner then player.InteractWith = "tradeweapon"..box player:Print(2,"Hold Action key (Default H) to trade your " .. BoxTable[box].slot .. " weapon with " .. BoxTable[box].text) end end) else BoxTable[box].message = ents.FindByName("dumpster_msg"..box):AddCallback(ON_START_TOUCH, function(_, player) if player:IsRealPlayer() and player == owner then player.InteractWith = "tradeweapon"..box player:Print(2,"Hold Action key (Default H) to trade your " .. BoxTable[box].slot .. " weapon with " .. BoxTable[box].text) end end) ents.FindByName("dumpster_msg"..box):AcceptInput("Enable") ents.FindByName("dumpster_train"..box):AcceptInput("TeleportToPathTrack", "dumpster_track2"..box) ents.FindByName("dumpster_train"..box):AcceptInput("SetSpeedDir", "0.02") end end) BoxTable[box].timer = timer.Simple(14, function() ents.FindByName("dumpster_msg"..box):AcceptInput("Disable") ents.FindByName("dumpster_msg"..box):RemoveCallback(14,BoxTable[box].message) BoxTable[box].message = ents.FindByName("dumpster_msg"..box):AddCallback(ON_START_TOUCH, function(_, player) if player:IsRealPlayer() then player.InteractWith = "dumpsterbutton"..box player:Print(2,"Hold Action key (Default H) to receive a weapon for $"..DumpsterCost) end end) timer.Simple(1, function() ents.FindByName("dumpster_msg"..box):AcceptInput("Enable") end) timer.Simple(1, function() BoxTable[box].opened = false end) ents.FindByName("dumpster_rotdoor"..box):AcceptInput("Close") ents.FindByName("dumpster_particles"..box):AcceptInput("Stop") ents.FindByName("dumpster_light"..box):AcceptInput("TurnOff") ents.FindByName("dumpster_weapon"..box):AcceptInput("Disable") if BoxTable[box].firesale == true and FireSaleDuration <= 0 then ents.FindByName("dumpster_warp_eff"..box):AcceptInput("Start") ents.FindByName("dumpster_warp_beam"..box):AcceptInput("Stop") ents.FindByName("dumpster_disappear"..box):AcceptInput("PlaySound") timer.Simple(1, function() ents.FindByName("dumpster_prop"..box):AcceptInput("$TeleportToEntity","dumpster_tele_out") end) timer.Simple(1, function() ents.FindByName("dumpster_msg"..box):AcceptInput("Disable") end) BoxTable[box].spawned = false end end) end function DumpsterBoxTakeWeapon(player, box) ents.FindByName("dumpster_msg"..box):AcceptInput("Disable") ents.FindByName("dumpster_particles"..box):AcceptInput("Stop") ents.FindByName("dumpster_rotdoor"..box):AcceptInput("Close") ents.FindByName("dumpster_light"..box):AcceptInput("TurnOff") ents.FindByName("dumpster_weapon"..box):AcceptInput("Disable") player:GiveItem(BoxTable[box].weapon) if BoxTable[box].weapon == "Thunder Gun" then ThunderGunTaken = true end if BoxTable[box].weapon == "DNA Rejuvenator" then RejuvenatorTaken = true end -- nuh uh you get only one of these like tgun if BoxTable[box].slot == "primary" then player.loadout[0] = BoxTable[box].weapon end if BoxTable[box].slot == "secondary" then player.loadout[1] = BoxTable[box].weapon end if BoxTable[box].slot == "melee" then player.loadout[2] = BoxTable[box].weapon end -- this line is for a single weapon :^) player:RefillAmmo() player:SpeakResponseConcept(BoxTable[box].response, 0.6) player:PlaySoundToSelf("items/gunpickup2.wav") player:DisplayTextChat("You've received: " .. BoxTable[box].text .. "!") timer.Stop(BoxTable[box].timer) ents.FindByName("dumpster_msg"..box):RemoveCallback(14,BoxTable[box].message) BoxTable[box].message = ents.FindByName("dumpster_msg"..box):AddCallback(ON_START_TOUCH, function(_, player) if player:IsRealPlayer() then player.InteractWith = "dumpsterbutton"..box player:Print(2,"Hold Action key (Default H) to receive a weapon for $"..DumpsterCost) end end) timer.Simple(1, function() ents.FindByName("dumpster_msg"..box):AcceptInput("Enable") end) timer.Simple(1, function() BoxTable[box].opened = false end) if BoxTable[box].firesale == true and FireSaleDuration <= 0 then ents.FindByName("dumpster_warp_eff"..box):AcceptInput("Start") ents.FindByName("dumpster_warp_beam"..box):AcceptInput("Stop") ents.FindByName("dumpster_disappear"..box):AcceptInput("PlaySound") timer.Simple(1, function() ents.FindByName("dumpster_prop"..box):AcceptInput("$TeleportToEntity","dumpster_tele_out") end) timer.Simple(1, function() ents.FindByName("dumpster_msg"..box):AcceptInput("Disable") end) BoxTable[box].spawned = false end end]] function GiveSuperShank(_,player) player:GiveItem("Super Shank") player.loadout[2] = "Super Shank" end function spawn_revive_marker(_, activator) -- Checks if (activator and activator:IsAlive()) or activator.m_iTeamNum ~= 2 or soloMode then return end local marker = nil for _, existingMarker in pairs(ents.FindAllByClass("entity_revive_marker")) do if existingMarker.m_hOwner == activator then marker = existingMarker break end end if not marker then -- If no marker exists, spawn a new one marker = ents.CreateWithKeys("entity_revive_marker", {m_hOwner = activator}) end local templateEnts = ents.SpawnTemplate("Revivemarker", {parent = marker}) local skymarker = ents.CreateWithKeys("info_particle_system", { origin = tostring(activator:GetAbsOrigin() + Vector(0, 0, 24)), start_active = "0", effect_name = "teleporter_mvm_bot_persist", render_in_front = "1", targetname = "testsky", parentname = marker, }, true, true) local revive_button = ents.CreateWithKeys("func_button", { targetname = "revive_button_" .. activator:GetHandleIndex(), origin = tostring(activator:GetAbsOrigin()), mins = "-12 -10 -6", maxs = "24 10 6", movedir = "0 180 0", spawnflags = "513", damagefilter = "filter_redteam", speed = "5", wait = "20", sounds = "3", }, true, true) revive_button:Teleport(activator:GetAbsOrigin(), nil, nil) if not activator:IsAlive() and activator.m_iTeamNum == 2 then skymarker:Teleport(activator:GetAbsOrigin(), nil, nil) skymarker:AcceptInput("Start", nil, skymarker) end marker.skymarker = skymarker revive_button:SetParent(marker) marker.revive_button = revive_button marker:AddCallback(ON_REMOVE, function() if marker.skymarker and IsValid(marker.skymarker) then marker.skymarker:Remove() marker.skymarker = nil end if marker.revive_button and IsValid(marker.revive_button) then marker.revive_button:Remove() marker.revive_button = nil end end) activator:AddCallback(ON_SPAWN, function() if (activator:IsAlive() or activator.m_iTeamNum ~= 2 or not activator or not activator:IsRealPlayer()) and IsValid(marker) and marker.skymarker and IsValid(marker.skymarker) then RestoreBonuses(activator) marker.skymarker:Remove() marker.skymarker = nil end end) activator:AddCallback(ON_REMOVE, function() if IsValid(marker) and marker.skymarker and IsValid(marker.skymarker) then marker.skymarker:Remove() marker.skymarker = nil end end) activator:AddCallback(ON_DEATH, function() if activator.m_iTeamNum ~= 2 and IsValid(marker) and marker.skymarker and IsValid(marker.skymarker) then marker.skymarker:Remove() marker.skymarker = nil end end) local allEntities = ents.GetAll() for _, entity in ipairs(allEntities) do if entity:GetName():find("revive_trigger") then entity:AddCallback(ON_START_TOUCH, function(_, player) if player:IsRealPlayer() and player:IsAlive() and not activator:IsAlive() then player.InteractWith = "revive_button_" .. activator:GetHandleIndex() print("Player can now interact with revive button:", player.InteractWith) end end) entity:AddCallback(ON_END_TOUCH, function(_, player) if player:IsRealPlayer() then player.InteractWith = nil player:Print(2, "") end end) end end end local revive_taunts = { -- universal [0] = { "Taunt: Second Rate Sorcery", "Laugh Taunt", "The Shred Alert", "Taunt: The Scaredy-Cat!", "Taunt: Mourning Mercs", "Taunt: Unleashed Rage", "Taunt: The Final Score", "Taunt: Killer Joke" }, -- scout [1] = { [9] = "Taunt: The Boston Breakdance", [10] = "Deep Fried Desire Taunt", [11] = "Taunt: Foul Play", [12] = "Taunt: Healthcare Hog", [13] = "Taunt: Peace Out" }, -- sniper [2] = { [9] = "Taunt: The Killer Solo", [10] = "Taunt: Most Wanted", [11] = "Taunt: Straight Shooter Tutor" }, -- soldier [3] = { [9] = "Taunt: Can It!", [10] = "Fresh Brewed Victory Taunt", [11] = "Taunt: The Fubar Fanfare", [12] = "Taunt: Soldier's Requiem", [13] = "Taunt: Star-Spangled Strategy" }, -- demoman [4] = { [9] = "Taunt: True Scotsman's Call", -- you would not be able to guess what this taunt is in-game without looking it up [10] = "Oblooterated Taunt", [11] = "Taunt: Roar O'War" }, -- medic [5] = { [9] = "Taunt: Borrowed Bones", [10] = "Taunt: Doctor's Defibrillators", [11] = "Taunt: The Head Doctor", [12] = "Taunt: Heartbreaker", [13] = "Meet the Medic Heroic Taunt", [14] = "Results Are In Taunt" }, -- heavy [6] = { [9] = "Taunt: Crushing Defeat", [10] = "Taunt: The Proletariat Showoff", [11] = "Taunt: Ring King" }, -- pyro [7] = { [9] = "Taunt: Cremator's Condolences", [10] = "Taunt: The Headcase", [11] = "Party Trick Taunt" }, -- spy [8] = { [9] = "Buy A Life Taunt", [10] = "Taunt: Disco Fever", [11] = "Taunt: The Punchline", }, -- engineer [9] = { [9] = "Taunt: Bucking Bronco", [10] = "Taunt: Texas Twirl 'Em" } } local revive_taunt_count = { 13, 11, 13, 11, 14, 11, 11, 11, 10 } function revivelogic(_, activator) print("Revive logic triggered by:", activator:GetPlayerName()) local uberChant = activator:GetAttributeValue("purchased") or 0 if not IsValid(activator) or not activator:IsAlive() then print("Activator is not valid or is alive.") return end -- -- anti-taunt speed goes here -- local activeWeapon = player.m_hActiveWeapon -- if activeWeapon then -- local taunt_speed = activeWeapon:GetAttributeValue("gesture speed increase") or 1 -- if taunt_speed ~= 1 then -- player_taunt_speed[activator] = taunt_speed -- activeWeapon:SetAttributeValue("gesture speed increase", 1) -- end -- end local tauntRand reviverClass = activator.m_iClass tauntRand = math.random(revive_taunt_count[reviverClass]) theTaunt = revive_taunts[0][tauntRand] or revive_taunts[reviverClass][tauntRand] if theTaunt then activator:TauntFromItem(theTaunt) else -- fallback activator:TauntFromItem("Taunt: Second Rate Sorcery") end print("Revive action pending...") if uberChant == 4 then -- activator:AddCond(52, 4.65) activator:AddCond(52, 5.5) timer.Simple(2.95, function() local closestMarker = nil local closestDistance = 150 for _, reanimator in pairs(ents.FindInSphere(activator:GetAbsOrigin(), 150)) do if reanimator:GetClassname() == "entity_revive_marker" then local owner = reanimator.m_hOwner if IsValid(owner) and not owner:IsAlive() and owner ~= activator then local distance = activator:GetAbsOrigin():Distance(reanimator:GetAbsOrigin()) if distance < closestDistance then closestMarker = reanimator closestDistance = distance end end end end if closestMarker and activator:IsAlive() then local owner = closestMarker.m_hOwner owner:ForceRespawnDead() print("Successfully revived:", owner:GetPlayerName()) owner:PlaySoundToSelf("mvm/mvm_revive.wav") owner:SpeakResponseConcept("TLK_RESURRECTED") activator:PlaySoundToSelf("mvm/mvm_revive.wav") owner:Teleport(activator:GetAbsOrigin()) owner:AddCond(51, 2) activator:StunPlayer(0.2, 1, TF_STUNFLAG_BONKSTUCK) closestMarker:Remove() --if closestMarker.revive_button and IsValid(closestMarker.revive_button) then -- closestMarker.revive_button:Remove() -- closestMarker.revive_button = nil --end timer.Simple(0.9, function() -- remove uber shortly after successful revive activator:RemoveCond(52) end) activator.InteractWith = nil end end) else timer.Simple(2.75, function() local closestMarker = nil local closestDistance = 150 for _, reanimator in pairs(ents.FindInSphere(activator:GetAbsOrigin(), 150)) do if reanimator:GetClassname() == "entity_revive_marker" then local owner = reanimator.m_hOwner if IsValid(owner) and not owner:IsAlive() and owner ~= activator then local distance = activator:GetAbsOrigin():Distance(reanimator:GetAbsOrigin()) if distance < closestDistance then closestMarker = reanimator closestDistance = distance end end end end if closestMarker and activator:IsAlive() then local owner = closestMarker.m_hOwner owner:ForceRespawnDead() print("Successfully revived:", owner:GetPlayerName()) owner:PlaySoundToSelf("mvm/mvm_revive.wav") owner:SpeakResponseConcept("TLK_RESURRECTED") activator:PlaySoundToSelf("mvm/mvm_revive.wav") owner:Teleport(activator:GetAbsOrigin()) owner:AddCond(51, 2) activator:StunPlayer(0.2, 1, TF_STUNFLAG_BONKSTUCK) closestMarker:Remove() --if closestMarker.revive_button and IsValid(closestMarker.revive_button) then -- closestMarker.revive_button:Remove() -- closestMarker.revive_button = nil --end activator.InteractWith = nil end end) end end local gear_lvl = { [1] = { text = "DEF ([1——————]) SPD", attr = { ["dmg taken increased"] = 0.65, -- +35% res ["move speed penalty"] = 0.61 -- 39% slower } }, [2] = { text = "DEF ([—2—————]) SPD", attr = { ["dmg taken increased"] = 0.75, -- +25% res ["move speed penalty"] = 0.74 -- 26% slower } }, [3] = { text = "DEF ([——3————]) SPD", attr = { ["dmg taken increased"] = 0.85, -- +15% res ["move speed penalty"] = 0.87 -- 13% slower } }, [4] = { text = "DEF ([———4———]) SPD", attr = { ["dmg taken increased"] = 1, ["move speed penalty"] = 1 } }, [5] = { text = "DEF ([————5——]) SPD", attr = { ["dmg taken increased"] = 1.25, -- +25% vuln ["move speed penalty"] = 1.1 -- 10% faster } }, [6] = { text = "DEF ([—————6—]) SPD", attr = { ["dmg taken increased"] = 1.5, -- +50% vuln ["move speed penalty"] = 1.2 -- 20% faster } }, [7] = { text = "DEF ([——————7]) SPD", attr = { ["dmg taken increased"] = 1.75, -- +75% vuln ["move speed penalty"] = 1.3 -- 30% faster } } } -- "DEF ▱▱▱▱▱▰ SPD"—–-−= function gearshiftInit(_, player) timer.Simple(0.75, function() -- local shieldslot = player:GetPlayerItemBySlot(LOADOUT_POSITION_SECONDARY) -- local gear = shieldslot:GetAttributeValue("non economy") or 4 -- local noticeGiven = shieldslot:GetAttributeValue("no double jump") or 1 -- a little bit of notice checking -- if noticeGiven == 1 then -- -- because divine_delusions_inf_money exists and hasn't updated its popfile yet -- shieldslot:SetAttributeValue("non economy", 4) -- shieldslot:SetAttributeValue("dmg taken increased", 1) -- shieldslot:SetAttributeValue("move speed penalty", 1) -- player:Print(2, "Press [RELOAD] to shift gear down and [MOUSE3] to shift gear up\nLower gear = Stronger resistances, but sluggish speed\nHigher gear = Faster speed, but more damage taken") -- shieldslot:SetAttributeValue("no double jump", 2) -- else -- local extratext = "" -- if betaMode then -- local def = gear_lvl[gear].attr["dmg taken increased"] -- local spd = gear_lvl[gear].attr["move speed penalty"] -- extratext = "\nresistance mod: " .. ((def - 1) * -100) .. "%\nspeed mod: " .. ((spd - 1) * 100) .. "%" -- end -- extratext = gear_lvl[gear].text .. extratext -- player:Print(2, extratext) -- end player:Print(2, "Press [RELOAD] to shift gear down and [MOUSE3] to shift gear up\nLower gear = Stronger resistances, but sluggish speed\nHigher gear = Faster speed, but more damage taken") end) end function gearShift(player, how_much) -- note: setting how_much to any value lower than -1 or higher than 1 defaults to those values instead -- zero... obviously does nothing local shieldslot = player:GetPlayerItemBySlot(LOADOUT_POSITION_SECONDARY) local gear = shieldslot:GetAttributeValue("non economy") or 1 if how_much < 0 then shieldslot:SetAttributeValue("non economy", math.max(1, gear - 1)) elseif how_much > 0 then shieldslot:SetAttributeValue("non economy", math.min(7, gear + 1)) else return end local newgear = shieldslot:GetAttributeValue("non economy") or 1 -- get the value again local extratext = "" if betaMode then local def = gear_lvl[newgear].attr["dmg taken increased"] local spd = gear_lvl[newgear].attr["move speed penalty"] extratext = "\nresistance mod: " .. ((def - 1) * -100) .. "%\nspeed mod: " .. ((spd - 1) * 100) .. "%" end extratext = gear_lvl[newgear].text .. extratext player:Print(2, extratext) player:PlaySoundToSelf(")weapons/vaccinator_toggle.wav") if newgear ~= gear then for attr, val in pairs(gear_lvl[newgear].attr) do -- print(attr .. " " .. val) shieldslot:SetAttributeValue(attr, val) end end end -- note: in infinite money mode, money compensation will not be applied and lucky chances are increased by 50% -- structure: -- [number] = { -- number defines the INCLUSIVE maximum wave threshold of this set of compensations -- MoneyCompensation = number, -- self-explanatory -- LuckyChanceCompensation = number -- self-explanatory -- } local waveThresholds = { [2] = { MoneyCompensation = 0, LuckyChanceCompensation = 0 }, [5] = { MoneyCompensation = 12000, LuckyChanceCompensation = 3 }, [8] = { MoneyCompensation = 24000, LuckyChanceCompensation = 6 }, [11] = { MoneyCompensation = 36000, LuckyChanceCompensation = 9 }, [13] = { MoneyCompensation = 48000, LuckyChanceCompensation = 12 }, [15] = { MoneyCompensation = 60000, LuckyChanceCompensation = 14 }, [18] = { MoneyCompensation = 90000, LuckyChanceCompensation = 16 }, [999999] = { MoneyCompensation = 120000, LuckyChanceCompensation = 18 } } function OnPlayerConnected(player) if player:IsRealPlayer() then player:AddCallback(ON_SPAWN, function() if not soloMode then return end local currentSoloist = ents.GetPlayerByUserId(soloist_uid) if soloMode and player ~= currentSoloist then player:DisplayTextChat("\x07ffdd00Solo Mode\x07FFFFFF has been activated. \x0707FF00Random Suicide is disabled\x07FFFFFF, \x0707FF00'Revive All' effects are replaced with Power Play instead\x07FFFFFF,") player:DisplayTextChat("\x07FF0000all other players cannot be revived\x07FFFFFF, and \x07FF0000any attempts of re/spawning are met with a quick death\x07FFFFFF.") player:DisplayTextChat(string.format("Current Solo Player: \x07FF0000%s", currentSoloist.m_szNetname)) -- player:SetAttributeValue("is suicide counter", 9999) player:Suicide() -- does the same thing except it will not force death after winning a solo mode (i think) end end) player:AddCallback(ON_DEATH, function() local stid = player:GetSteamId() playerMannpower[stid] = nil if soloMode and player ~= ents.GetPlayerByUserId(soloist_uid) then player:Print(2, "Solo Mode is active. Please wait or move to Spectator team until it ends.") end end) local function funnyDeathShriek() for _, aplayer in pairs(ents.GetAllPlayers()) do if aplayer:IsRealPlayer() then aplayer:PlaySoundToSelf("npc/stalker/go_alert2.wav") end end end -- funny trespasser death shriek because people kept asking for it lmao player:AddCallback(ON_DEATH, function() -- if not waveActive then return end if soloMode then local currentSoloist = ents.GetPlayerByUserId(soloist_uid) if player == currentSoloist then funnyDeathShriek() end else funnyDeathShriek() end end) player:AddCallback(ON_KEY_PRESSED, function() if soloMode then -- prevent medic from reviving anyone else with the medigun player:SetAttributeValue("revive rate", 0.01) end end) player.HoldTime = 0 player.InteractWith = nil player.InteractCooldown = false player.loadout = {[0] = "Default", [1] = "Default", [2] = "Default"} player.m_nCurrencyDiff = 0 local handle = player:GetHandleIndex() --deathCounts[handle] = 0 --player:AddCallback(ON_DEATH, function() -- deathCounts[handle] = deathCounts[handle] + 1 --end) player:AddCallback(ON_SPAWN, function() for weapon = 0, 3, 1 do if player.loadout[weapon] and player.loadout[weapon] ~= "Default" then player:GiveItem(player.loadout[weapon]) end end end) else player:AddCallback(ON_DEATH, function() local number = math.random(1,100) if number <= 5 then -- 2% chance DropPowerup(player) end end); end if player:IsRealPlayer() then -- spy ability player:AddCallback(ON_KEY_PRESSED, function(_, key) if player.m_iClass ~= 8 then return end local spec3check = player:GetAttributeValue("tool needs giftwrap") or 0 local cd = nil local cdtable = nil local perform = nil local name = nil if key == IN_ATTACK3 then cd = hypercd cdtable = hyper_cd_player perform = perform_hyper name = "hyperjump" if spec3check == 1 then cd = cd // 1.25 -- equivalent to cd - (cd * 0.2) end elseif key == IN_RELOAD then cd = invscd cdtable = invs_cd_player perform = perform_invs name = "invis" if spec3check == 1 then cd = cd // 1.25 -- equivalent to cd - (cd * 0.2) end end if cd and cdtable and perform and name then applyCooldown(player, cdtable, cd, perform, name) end end) end if player:IsRealPlayer() then -- m16a1 automatic mode player:AddCallback(ON_KEY_PRESSED, function(_, key) local activeWeapon = player.m_hActiveWeapon if not activeWeapon or activeWeapon:GetItemName() ~= "M16A1" then return end -- Check if activeWeapon exists and is the M16A1 local ml = player:GetPlayerItemBySlot(LOADOUT_POSITION_PRIMARY) if not ml then return end local autoCheck = ml:GetAttributeValue("fire rate penalty") if key == IN_RELOAD then player:PlaySoundToSelf("weapons/default_reload.wav") if autoCheck == 2 then player:Print(2,"Full automatic mode") ml:SetAttributeValue("fire rate penalty", 1.2) ml:SetAttributeValue("weapon spread bonus", 2) elseif autoCheck ~= 2 then player:Print(2,"Semi automatic mode") ml:SetAttributeValue("fire rate penalty", 2) ml:SetAttributeValue("weapon spread bonus", nil) end else goto continue end ::continue:: end) end if player:IsRealPlayer() then -- m16a2 burst mode player:AddCallback(ON_KEY_PRESSED, function(_, key) local activeWeapon = player.m_hActiveWeapon local ml = player:GetPlayerItemBySlot(LOADOUT_POSITION_PRIMARY) if not ml then return end local m16a2Check = ml:GetAttributeValue("loot rarity") if not activeWeapon or activeWeapon:GetItemName() ~= "M16A1" or m16a2Check ~= 1 then return end -- Check if activeWeapon exists and is the M16A2 local burstCheck = ml:GetAttributeValue("burst fire count") if key == IN_RELOAD then player:PlaySoundToSelf("weapons/default_reload.wav") if burstCheck == nil then player:Print(2,"Burst fire mode") ml:SetAttributeValue("burst fire count", -3) ml:SetAttributeValue("burst fire rate mult", 3.5) ml:SetAttributeValue("fire rate penalty", 0.8) elseif burstCheck ~= nil then player:Print(2,"Full automatic mode") ml:SetAttributeValue("burst fire count", nil) ml:SetAttributeValue("burst fire rate mult", nil) ml:SetAttributeValue("fire rate penalty", 1.2) end else goto continue end ::continue:: end) end if player:IsRealPlayer() then -- ak-47 grenade launcher mode player:AddCallback(ON_KEY_PRESSED, function(_, key) local activeWeapon = player.m_hActiveWeapon local ml = player:GetPlayerItemBySlot(LOADOUT_POSITION_PRIMARY) if not ml then return end if not activeWeapon or activeWeapon:GetItemName() ~= "AK-47" then return end -- Check if activeWeapon exists local glCheck = ml:GetAttributeValue("override projectile type") if key == IN_RELOAD then player:PlaySoundToSelf("weapons/default_reload.wav") if glCheck == 1 then player:Print(2,"Grenade launcher mode ON") ml:SetAttributeValue("override projectile type", 2) ml:SetAttributeValue("projectile gravity", 1000) ml:SetAttributeValue("fire rate penalty", 12) ml:SetAttributeValue("mod ammo per shot", 30) ml:SetAttributeValue("damage bonus", 15) ml:SetAttributeValue("custom weapon fire sound", "=80|weapons/grenade_launcher_shoot.wav") ml:SetAttributeValue("explosion particle", "ExplosionCore_buildings") ml:SetAttributeValue("projectile trail particle", "rockettrail") elseif glCheck ~= 1 then player:Print(2,"Grenade launcher mode OFF") ml:SetAttributeValue("override projectile type", 1) ml:SetAttributeValue("projectile gravity", nil) ml:SetAttributeValue("fire rate penalty", 1.2) ml:SetAttributeValue("mod ammo per shot", nil) ml:SetAttributeValue("damage bonus", nil) ml:SetAttributeValue("custom weapon fire sound", "=80|ak47_shoot.wav") ml:SetAttributeValue("explosion particle", nil) ml:SetAttributeValue("projectile trail particle", nil) end else goto continue end ::continue:: end) end if player:IsRealPlayer() then -- Prototype SM2 toggleable modes player:AddCallback(ON_KEY_PRESSED, function(_, key) local activeWeapon = player.m_hActiveWeapon local primaryWeapon = player:GetPlayerItemBySlot(LOADOUT_POSITION_PRIMARY) if not primaryWeapon or not activeWeapon then return end -- if activeWeapon:GetItemName() ~= "Prototype SM2" then return end -- Ensure correct weapon is active if activeWeapon:GetItemName() ~= "The Airblaster" then return end -- Ensure correct weapon is active local mode = primaryWeapon:GetAttributeValue("spawn with physics toy") or 1 -- Default to mode 1 if undefined if key == IN_RELOAD then player:PlaySoundToSelf("weapons/default_reload.wav") mode = (mode % 4) + 1 -- Cycle through modes (1 → 2 → 3 → 4 → 1) if mode == 1 then player:Print(2, "Mode 1: Normal Airblast") primaryWeapon:SetAttributeValue("reverse airblast", nil) primaryWeapon:SetAttributeValue("mult airblast refire time", 0.25) primaryWeapon:SetAttributeValue("airblast pushback scale", nil) primaryWeapon:SetAttributeValue("airblast cost increased", nil) elseif mode == 2 then player:Print(2, "Mode 2: Reverse Airblast") primaryWeapon:SetAttributeValue("reverse airblast", 1) primaryWeapon:SetAttributeValue("mult airblast refire time", 0.25) primaryWeapon:SetAttributeValue("airblast pushback scale", nil) primaryWeapon:SetAttributeValue("airblast cost increased", nil) elseif mode == 3 then player:Print(2, "Mode 3: Airblast Dashes") primaryWeapon:SetAttributeValue("airblast dashes", 1) primaryWeapon:SetAttributeValue("mult airblast refire time", 0.33) primaryWeapon:SetAttributeValue("reverse airblast", nil) primaryWeapon:SetAttributeValue("airblast pushback scale", 2.5) primaryWeapon:SetAttributeValue("airblast cost increased", nil) elseif mode == 4 then player:Print(2, "Mode 4: Enhanced Airblast") primaryWeapon:SetAttributeValue("airblast dashes", nil) primaryWeapon:SetAttributeValue("mult airblast refire time", 0.5) primaryWeapon:SetAttributeValue("reverse airblast", nil) primaryWeapon:SetAttributeValue("airblast pushback scale", 4) primaryWeapon:SetAttributeValue("airblast cost increased", 4) end -- Save the updated mode to the weapon's attributes primaryWeapon:SetAttributeValue("spawn with physics toy", mode) else goto continue end ::continue:: end) end if player:IsRealPlayer() then -- Bong! Atomic Punch toggleable modes player:AddCallback(ON_KEY_PRESSED, function(_, key) local activeWeapon = player.m_hActiveWeapon local secondaryWeapon = player:GetPlayerItemBySlot(LOADOUT_POSITION_SECONDARY) if not secondaryWeapon or not activeWeapon then return end if activeWeapon:GetItemName() ~= "Bong! Atomic Punch" then return end -- Ensure correct weapon is active local mode = secondaryWeapon:GetAttributeValue("spawn with physics toy") or 1 -- Default to mode 1 if undefined if key == IN_RELOAD then player:PlaySoundToSelf("weapons/default_reload.wav") mode = (mode % 11) + 1 if mode == 1 then player:Print(2, "Energy type: Bonk!") secondaryWeapon:SetAttributeValue("effect cond override", nil) secondaryWeapon:SetAttributeValue("effect add attributes", nil) secondaryWeapon:SetAttributeValue("increase buff duration HIDDEN", nil) elseif mode == 2 then player:Print(2, "Energy type: Cloak") secondaryWeapon:SetAttributeValue("effect cond override", 64) secondaryWeapon:SetAttributeValue("effect add attributes", nil) secondaryWeapon:SetAttributeValue("increase buff duration HIDDEN", nil) elseif mode == 3 then player:Print(2, "Energy type: Buff Banner") secondaryWeapon:SetAttributeValue("effect cond override", 16) secondaryWeapon:SetAttributeValue("effect add attributes", nil) secondaryWeapon:SetAttributeValue("increase buff duration HIDDEN", nil) elseif mode == 4 then player:Print(2, "Energy type: Concheror") secondaryWeapon:SetAttributeValue("effect cond override", 29) secondaryWeapon:SetAttributeValue("effect add attributes", nil) secondaryWeapon:SetAttributeValue("increase buff duration HIDDEN", nil) elseif mode == 5 then player:Print(2, "Energy type: Battalion's Backup") secondaryWeapon:SetAttributeValue("effect cond override", 26) secondaryWeapon:SetAttributeValue("effect add attributes", nil) secondaryWeapon:SetAttributeValue("increase buff duration HIDDEN", nil) elseif mode == 6 then player:Print(2, "Energy type: Bullet Resistance") secondaryWeapon:SetAttributeValue("effect cond override", 58) secondaryWeapon:SetAttributeValue("effect add attributes", nil) secondaryWeapon:SetAttributeValue("increase buff duration HIDDEN", nil) elseif mode == 7 then player:Print(2, "Energy type: Blast Resistance") secondaryWeapon:SetAttributeValue("effect cond override", 59) secondaryWeapon:SetAttributeValue("effect add attributes", nil) secondaryWeapon:SetAttributeValue("increase buff duration HIDDEN", nil) elseif mode == 8 then player:Print(2, "Energy type: Fire Resistance") secondaryWeapon:SetAttributeValue("effect cond override", 60) secondaryWeapon:SetAttributeValue("effect add attributes", nil) secondaryWeapon:SetAttributeValue("increase buff duration HIDDEN", nil) elseif mode == 9 then player:Print(2, "Energy type: Bumper Car") secondaryWeapon:SetAttributeValue("effect cond override", 82) secondaryWeapon:SetAttributeValue("effect add attributes", nil) secondaryWeapon:SetAttributeValue("increase buff duration HIDDEN", nil) elseif mode == 10 then player:Print(2, "Energy type: Giant") -- secondaryWeapon:SetAttributeValue("effect cond override", 74) secondaryWeapon:SetAttributeValue("effect cond override", 19017) secondaryWeapon:SetAttributeValue("effect add attributes", "health drain|255|dmg taken increased|0.8") secondaryWeapon:SetAttributeValue("increase buff duration HIDDEN", 3.75) elseif mode == 11 then player:Print(2, "Energy type: Mega Heal") secondaryWeapon:SetAttributeValue("effect cond override", 73) secondaryWeapon:SetAttributeValue("effect add attributes", "health drain|75|attribute immunity|'healing received penalty'") secondaryWeapon:SetAttributeValue("increase buff duration HIDDEN", nil) end -- Save the updated mode to the weapon's attributes secondaryWeapon:SetAttributeValue("spawn with physics toy", mode) else goto continue end ::continue:: end) end if player:IsRealPlayer() then -- Gearshift player:AddCallback(ON_KEY_PRESSED, function(_, key) local shieldslot = player:GetPlayerItemBySlot(LOADOUT_POSITION_SECONDARY) or nil if not shieldslot then return end if shieldslot:GetItemName() ~= "Gearshift" then return end if key == IN_RELOAD then gearShift(player, -1) elseif key == IN_ATTACK3 then gearShift(player, 1) end end) end if player:IsRealPlayer() then -- desperation, desperation player:AddCallback(ON_DAMAGE_RECEIVED_PRE, function() local shieldslot = player:GetPlayerItemBySlot(LOADOUT_POSITION_SECONDARY) or nil if not shieldslot then return end local OCcheck = shieldslot:GetAttributeValue("loot rarity") or 0 if OCcheck == 4 then player:AcceptInput("$AddPlayerAttribute", "mult dmg with reduced health|1.75") player:AcceptInput("$AddPlayerAttribute", "fire rate bonus with reduced health|0.75") else player:SetAttributeValue("mult dmg with reduced health", nil) player:SetAttributeValue("fire rate bonus with reduced health", nil) end end) end if player:IsRealPlayer() then -- it's a desperate race against the mine, and a race against time player:AddCallback(ON_KEY_PRESSED, function(_, key) -- CashbackInterestPayout(_, player) local shieldslot = player:GetPlayerItemBySlot(LOADOUT_POSITION_SECONDARY) or nil if not shieldslot then return end local OCcheck = shieldslot:GetAttributeValue("loot rarity") or 0 if OCcheck == 4 then player:AcceptInput("$AddPlayerAttribute", "mult dmg with reduced health|1.75") player:AcceptInput("$AddPlayerAttribute", "fire rate bonus with reduced health|0.75") else player:SetAttributeValue("mult dmg with reduced health", nil) player:SetAttributeValue("fire rate bonus with reduced health", nil) end end) end if player:IsRealPlayer() then player:AddCallback(ON_SPAWN, function() local shieldslot = player:GetPlayerItemBySlot(LOADOUT_POSITION_SECONDARY) or nil if not shieldslot then return end local OCcheck = shieldslot:GetAttributeValue("loot rarity") or 0 if OCcheck == 4 then player:AcceptInput("$AddPlayerAttribute", "mult dmg with reduced health|1.75") player:AcceptInput("$AddPlayerAttribute", "fire rate bonus with reduced health|0.75") else player:SetAttributeValue("mult dmg with reduced health", nil) player:SetAttributeValue("fire rate bonus with reduced health", nil) end end) end if player:IsRealPlayer() then player:AddCallback(ON_KEY_PRESSED, function() local canCashback_old = player:GetAttributeValue("is australium item") or 0 local canCashback = player:GetAttributeValue("cannot trade") or 0 if canCashback == 7 or canCashback_old == 7 then CashbackInterestPayout(_, player) end end) end -- heavy-duty armor start if player:IsRealPlayer() then player:AddCallback(ON_KEY_PRESSED, function() local primslot = player:GetPlayerItemBySlot(LOADOUT_POSITION_PRIMARY) or nil if primslot == nil then player:SetAttributeValue("CARD: damage bonus", nil) if player.m_iClass == 6 or player:InCond(7443) == false then player:SetAttributeValue("fire rate bonus HIDDEN", nil) end return end if primslot:GetItemName() == "Heavy-Duty Armor" then player:SetAttributeValue("CARD: damage bonus", 1.45) if player:InCond(7443) == true then player:SetAttributeValue("fire rate bonus HIDDEN", 0.55) else player:SetAttributeValue("fire rate bonus HIDDEN", 0.85) end else player:SetAttributeValue("CARD: damage bonus", nil) if player.m_iClass == 6 or player:InCond(7443) == false then player:SetAttributeValue("fire rate bonus HIDDEN", nil) end end end) player:AddCallback(ON_PROVIDE_ITEMS, function() local primslot = player:GetPlayerItemBySlot(LOADOUT_POSITION_PRIMARY) or nil if primslot == nil then player:SetAttributeValue("CARD: damage bonus", nil) if player.m_iClass == 6 or player:InCond(7443) == false then player:SetAttributeValue("fire rate bonus HIDDEN", nil) end return end if primslot:GetItemName() == "Heavy-Duty Armor" then player:SetAttributeValue("CARD: damage bonus", 1.45) if player:InCond(7443) == true then player:SetAttributeValue("fire rate bonus HIDDEN", 0.55) else player:SetAttributeValue("fire rate bonus HIDDEN", 0.85) end else player:SetAttributeValue("CARD: damage bonus", nil) if player.m_iClass == 6 or player:InCond(7443) == false then player:SetAttributeValue("fire rate bonus HIDDEN", nil) end end end) end -- heavy-duty armor end if player:IsRealPlayer() then -- incinerator's -99% rage gain player:AddCallback(ON_KEY_PRESSED, function() if player.m_iClass ~= 7 then return end local primaryslot = player:GetPlayerItemBySlot(LOADOUT_POSITION_PRIMARY) or nil if not primaryslot then return end if primaryslot:GetItemName() == "Incinerator" then player:SetAttributeValue("rage receive scale", 0.01) -- phlog-like flamethrowers literally gain a lot of mmmph in a short time else player:SetAttributeValue("rage receive scale", nil) end end) player:AddCallback(ON_PROVIDE_ITEMS, function() if player.m_iClass ~= 7 then return end local primaryslot = player:GetPlayerItemBySlot(LOADOUT_POSITION_PRIMARY) or nil if not primaryslot then return end if primaryslot:GetItemName() == "Incinerator" then player:SetAttributeValue("rage receive scale", 0.01) -- phlog-like flamethrowers literally gain a lot of mmmph in a short time else player:SetAttributeValue("rage receive scale", nil) end end) end if player:IsRealPlayer() then -- hypocritical oath scaling with player's dmg bonus player:AddCallback(ON_KEY_PRESSED, function() if player.m_iClass ~= 5 then return end local medigun = player:GetPlayerItemBySlot(LOADOUT_POSITION_SECONDARY) or nil if not medigun then return end local OCcheck = medigun:GetAttributeValue("loot rarity") or 0 local luckydmg = player:GetAttributeValue("damage bonus") or 1 local OCmodifier = 1 local baseHurtingJuice = 20 if medigun:GetItemName() == "Strahlblitz" then baseHurtingJuice = 50 if OCcheck == 9 then OCmodifier = 2 end end local medidamage = baseHurtingJuice + ((luckydmg - 1) * 20) / OCmodifier if medigun:GetItemName() == "Strahlblitz" or OCcheck == 9 then medigun:SetAttributeValue("medigun attack enemy", medidamage) else medigun:SetAttributeValue("medigun attack enemy", nil) end end) end if player:IsRealPlayer() then -- bullet sentry damage scaling with player's lucky bonus dmg player:AddCallback(ON_KEY_PRESSED, function() if player.m_iClass ~= 9 then return end -- engineer gaming local pda = player:GetPlayerItemBySlot(LOADOUT_POSITION_PDA) or nil if not pda then return end -- should not be possible actually local luckydmg = player:GetAttributeValue("damage bonus") or 1 if luckydmg > 1 then pda:SetAttributeValue("engy sentry damage bonus", luckydmg) else pda:SetAttributeValue("engy sentry damage bonus", nil) end end) end if player:IsRealPlayer() then -- golden eyelander, PT 1 player:AddCallback(ON_KEY_PRESSED, function() local melee = player:GetPlayerItemBySlot(LOADOUT_POSITION_MELEE) or nil if not melee then return end if melee:GetItemName() ~= "Golden Eyelander" then return end extendedEyelander(0, player, nil) end) end if player:IsRealPlayer() then -- golden eyelander, on death player:AddCallback(ON_DEATH, function() local melee = player:GetPlayerItemBySlot(LOADOUT_POSITION_MELEE) or nil if not melee then return end if melee:GetItemName() ~= "Golden Eyelander" then return end melee:SetAttributeValue("max health additive bonus", nil) melee:SetAttributeValue("move speed bonus", nil) melee:SetAttributeValue("dmg penalty vs players", nil) player:SetAttributeValue("damage penalty", nil) end) end if player:IsRealPlayer() then player:AddCallback(ON_SPAWN, function() local stid = player:GetSteamId() if playerCurrentCash[stid] then player:SetCurrency(playerCurrentCash[stid]) end RestoreBonuses(player) end) end if player:IsRealPlayer() then player:AddCallback(ON_SPAWN, function() -- undying macula testing -- local primary = player:GetPlayerItemBySlot(LOADOUT_POSITION_PRIMARY) or nil -- local secondary = player:GetPlayerItemBySlot(LOADOUT_POSITION_SECONDARY) or nil -- if primary then -- if primary:GetItemName() == "The Pomson 6000" and player:GetSteamId() == 76561199026795791 then -- player:GiveItem("Undying Macula V") -- end -- end -- if secondary then -- if secondary:GetItemName() == "The Righteous Bison" and player:GetSteamId() == 76561199026795791 then -- player:GiveItem("Undying Macula M") -- end -- end local melee = player:GetPlayerItemBySlot(LOADOUT_POSITION_MELEE) or nil if not melee then return end if soloMode then return end -- it gets annoying having to see it in the chat multiple times and they just spontaneously die timer.Simple(0.75, function() -- a bit of delay local playerSteamId = player:GetSteamId() local existed = false -- check if player has joined in before for _, savedSteamId in ipairs(joinedIn) do if savedSteamId == playerSteamId then existed = true break end end -- if playerSteamId == 76561199026795791 then -- playerExtraLuckyChances[playerSteamId] = 999 -- end -- if not, then commence compensation (if applicable) -- also let the others know if not existed then table.insert(joinedIn, playerSteamId) local moneyCompensation = 0 local luckyChanceCompensation = 0 local wTcounts = {2, 5, 8, 11, 13, 15, 18, 999999} -- jfc lua tables are wack sometimes for _, waveThreshold in ipairs(wTcounts) do if waveCount <= waveThreshold then local compensations = waveThresholds[waveThreshold] moneyCompensation = compensations.MoneyCompensation luckyChanceCompensation = compensations.LuckyChanceCompensation break end end if moneyCompensation == 0 and luckyChanceCompensation == 0 then return elseif infMoneyMode then -- infinite money mode: -- - money compensation is set to 0 because it's meaningless -- - lucky chance compensation is increased by 50%, rounded down moneyCompensation = 0 luckyChanceCompensation = math.floor(luckyChanceCompensation * 1.5) end player:Teleport(Vector(0, 1325, -4860)) -- new joiners go directly to the barn player:AddCurrency(moneyCompensation) playerExtraLuckyChances[playerSteamId] = luckyChanceCompensation -- if playerSteamId == 76561199026795791 then -- playerExtraLuckyChances[playerSteamId] = 999 -- end -- let people know about it for _, aplayer in pairs(ents.GetAllPlayers()) do if aplayer:IsRealPlayer() and player == aplayer then if moneyCompensation > 0 and luckyChanceCompensation > 0 then player:Print(2, "You have received " .. moneyCompensation .. "$ and " .. luckyChanceCompensation .. " extra Lucky Bonus chances due to joining late the first time!") elseif moneyCompensation == 0 and luckyChanceCompensation > 0 then player:Print(2, "You have received " .. luckyChanceCompensation .. " extra Lucky Bonus chances due to joining late the first time!") elseif moneyCompensation > 0 and luckyChanceCompensation == 0 then player:Print(2, "You have received " .. moneyCompensation .. "$ due to joining late the first time!") end elseif aplayer:IsRealPlayer() then if moneyCompensation > 0 and luckyChanceCompensation > 0 then aplayer:DisplayTextChat( string.format( "\x07FF0000%s\x07FFFFFF has received \x07ffdd00%d$\x07FFFFFF and \x07ffdd00%d extra Lucky Bonus chances\x07FFFFFF as compensation for joining late the first time.", player.m_szNetname, moneyCompensation, luckyChanceCompensation ) ) elseif moneyCompensation == 0 and luckyChanceCompensation > 0 then aplayer:DisplayTextChat( string.format( "\x07FF0000%s\x07FFFFFF has received \x07ffdd00%d extra Lucky Bonus chances\x07FFFFFF as compensation for joining late the first time.", player.m_szNetname, luckyChanceCompensation ) ) elseif moneyCompensation > 0 and luckyChanceCompensation == 0 then aplayer:DisplayTextChat( string.format( "\x07FF0000%s\x07FFFFFF has received \x07ffdd00%d$\x07FFFFFF as compensation for joining late the first time.", player.m_szNetname, moneyCompensation ) ) end end end end end) end) end end local function removeCallbacks(player, callbacks) if not IsValid(player) then return end for _, callbackId in pairs(callbacks) do player:RemoveCallback(callbackId) end end