--Made by wacev --you can in theory use this on other maps, but this lua file contains mvm_casino_city specific logic local BotCredits = 0 local WaveNum = ents.FindByClass('tf_objective_resource').m_nMannVsMachineWaveCount local BombReturnTimeVar = 30 local TankSpeedVar = 75 local ChipReward = 1 local DevMode = false local Luck = 0 local LuckMult = 1 local TF_BOTBASE_FIRERATE = 1 local TF_BOTBASE_RELOAD = 1 local TF_BOTBASE_DAMAGE = 1 local TF_BOTBASE_HOK = 0 local TF_BOTBASE_CBOK = 0 local TF_BOTBASE_HEALTH = 0 local TF_BOTBASE_MOVESPEED = 1 local TF_BOTBASE_ATKPROJ = 0 local TF_BOTBASE_BLASTRAD = 1 local TF_BOTBASE_ACCBONUS = 1 local TF_BOTBASE_PENETRATION = 0 local TF_BOTBASE_BOMBRETURNDELAY = 30 local TF_BOTBASE_REGEN = 0 local TF_BOTBASE_CLIP = 1 local TF_BOTBASE_PROJSPEED = 1 local TF_BOTBASE_ROCKSPEC = 0 local TF_BOTBASE_UBERDUR = 0 local TF_BOTBASE_UBERRATE = 1 local TF_BOTBASE_HEALRATE = 1 local TF_BOTBASE_TANKSPEED = 1 local TF_BOTBASE_FASTERRECHARGE = 1 local TF_BOTBASE_LUCKCHANCE = 1 local TF_BOTBASE_CANTEENUBER = 0 local TF_BOTBASE_CANTEENCRIT = 0 local TF_BOTBASE_CANTEENAMMO = 0 local TF_BOTUPGRADE_FIRERATE = 1 local TF_BOTUPGRADE_RELOAD = 2 local TF_BOTUPGRADE_DAMAGE = 3 local TF_BOTUPGRADE_HOK = 4 local TF_BOTUPGRADE_CBOK = 5 local TF_BOTUPGRADE_HEALTH = 6 local TF_BOTUPGRADE_MOVESPEED = 7 local TF_BOTUPGRADE_ATKPROJ = 8 local TF_BOTUPGRADE_BLASTRAD = 9 local TF_BOTUPGRADE_ACCBONUS = 10 local TF_BOTUPGRADE_PENETRATION = 11 local TF_BOTUPGRADE_BOMBRETURNDELAY = 12 local TF_BOTUPGRADE_REGEN = 13 local TF_BOTUPGRADE_CLIP = 14 local TF_BOTUPGRADE_PROJSPEED = 15 local TF_BOTUPGRADE_ROCKSPEC = 16 local TF_BOTUPGRADE_UBERDUR = 17 local TF_BOTUPGRADE_UBERRATE = 18 local TF_BOTUPGRADE_HEALRATE = 19 local TF_BOTUPGRADE_TANKSPEED = 20 local TF_BOTUPGRADE_FASTERRECHARGE = 21 local TF_BOTUPGRADE_LUCKCHANCE = 22 local TF_BOTUPGRADE_CANTEENUBER = 23 local TF_BOTUPGRADE_CANTEENCRIT = 24 local TF_BOTUPGRADE_CANTEENAMMO = 25 local TF_BOTPERK_REFLECT = 1 local TF_BOTPERK_IMMOVABLE = 2 local TF_BOTPERK_EFFICIENT_SUPPLY = 3 local TF_BOTPERK_ASSASSIN_SUPPORT = 4 local TF_BOTPERK_MEDICAL_SUPPORT = 5 local TF_BOTPERK_HITMAN = 6 local TF_BOTPERK_SHORT_TEMPER = 7 local TF_BOTPERK_BLAZING_PAYLOAD = 8 local TF_BOTPERK_GHEAVY_SUPPORT = 9 local TF_BOTPERK_SNIPER_MASTER = 10 local TF_BOTPERK_EXCESSIVE_FIREPOWER = 11 local TF_BOTPERK_VANGUARD = 12 local TF_BOTPERK_HARD_RUSH = 13 local TF_BOTPERK_JUGGERNAUT = 14 local TF_BOTPERK_PHASE_SHIFTING = 15 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 local UpgradeTable = { [TF_BOTUPGRADE_FIRERATE] = { attribute = "melee attack rate bonus", increment = -0.1, cap = 0.4, cost = 300, value = TF_BOTBASE_FIRERATE, text = "", special = "Fire Rate Bonus", base = TF_BOTBASE_FIRERATE}, [TF_BOTUPGRADE_RELOAD] = { attribute = "halloween reload time decreased", increment = -0.15, cap = 0.25, cost = 500, value = TF_BOTBASE_RELOAD, text = "", special = "Reload Rate Bonus", base = TF_BOTBASE_RELOAD}, [TF_BOTUPGRADE_DAMAGE] = { attribute = "CARD: damage bonus", increment = 0.2, cap = 2147483647, cost = 600, value = TF_BOTBASE_DAMAGE, text = "", special = "Damage Bonus", base = TF_BOTBASE_DAMAGE}, [TF_BOTUPGRADE_HOK] = { attribute = "heal on kill", increment = 25, cap = 2147483647, cost = 200, value = TF_BOTBASE_HOK, text = "", special = "Health on Kill", base = TF_BOTBASE_HOK}, [TF_BOTUPGRADE_CBOK] = { attribute = "critboost on kill", increment = 1, cap = 2147483647, cost = 300, value = TF_BOTBASE_CBOK, text = "", special = "Crit Boost on Kill", base = TF_BOTBASE_CBOK}, [TF_BOTUPGRADE_HEALTH] = { attribute = "max health additive bonus", increment = 25, cap = 2147483647, cost = 250, value = TF_BOTBASE_HEALTH, text = "", special = "Health Bonus", base = TF_BOTBASE_HEALTH}, [TF_BOTUPGRADE_MOVESPEED] = { attribute = "major move speed bonus", increment = 0.1, cap = 2, cost = 400, value = TF_BOTBASE_MOVESPEED, text = "", special = "Move Bonus", base = TF_BOTBASE_MOVESPEED}, [TF_BOTUPGRADE_ATKPROJ] = { attribute = "attack projectiles", increment = 1, cap = 1, cost = 1200, value = TF_BOTBASE_ATKPROJ, text = "", special = "Attack Projectiles", base = TF_BOTBASE_ATKPROJ}, [TF_BOTUPGRADE_BLASTRAD] = { attribute = "Blast radius increased", increment = 0.1, cap = 2, cost = 400, value = TF_BOTBASE_BLASTRAD, text = "", special = "Blast Radius Bonus", base = TF_BOTBASE_BLASTRAD}, [TF_BOTUPGRADE_ACCBONUS] = { attribute = "weapon spread bonus", increment = -0.1, cap = 0.5, cost = 300, value = TF_BOTBASE_ACCBONUS, text = "", special = "Accuracy Bonus", base = TF_BOTBASE_ACCBONUS}, [TF_BOTUPGRADE_PENETRATION] = { attribute = "projectile penetration heavy", increment = 1, cap = 6, cost = 400, value = TF_BOTBASE_PENETRATION, text = "", special = "Penetration", base = TF_BOTBASE_PENETRATION}, [TF_BOTUPGRADE_BOMBRETURNDELAY] = { attribute = nil, increment = 5, cap = 2147483647, cost = 600, special = "Bomb Return Time", value = TF_BOTBASE_BOMBRETURNDELAY, text = "", base = TF_BOTBASE_BOMBRETURNDELAY}, [TF_BOTUPGRADE_REGEN] = { attribute = "CARD: health regen", increment = 10, cap = 100, cost = 800, value = TF_BOTBASE_REGEN, text = "", special = "Health Regen", base = TF_BOTBASE_REGEN}, [TF_BOTUPGRADE_CLIP] = { attribute = "clip size penalty", increment = 0.25, cap = 2147483647, cost = 300, value = TF_BOTBASE_CLIP, text = "", special = "Clip Size Bonus", base = TF_BOTBASE_CLIP}, [TF_BOTUPGRADE_PROJSPEED] = { attribute = "projectile speed increased", increment = 0.15, cap = 1.9, cost = 750, value = TF_BOTBASE_PROJSPEED, text = "", special = "Projectile Speed Bonus", base = TF_BOTBASE_PROJSPEED}, [TF_BOTUPGRADE_ROCKSPEC] = { attribute = "rocket specialist", increment = 1, cap = 1, cost = 1600, value = TF_BOTBASE_ROCKSPEC, text = "", special = "Rocket Specialist", base = TF_BOTBASE_ROCKSPEC}, [TF_BOTUPGRADE_UBERDUR] = { attribute = "uber duration bonus", increment = 1, cap = 2147483647, cost = 350, value = TF_BOTBASE_UBERDUR, text = "", special = "Uber Duration Bonus", base = TF_BOTBASE_UBERDUR}, [TF_BOTUPGRADE_UBERRATE] = { attribute = "ubercharge rate penalty", increment = 0.2, cap = 2147483647, cost = 400, value = TF_BOTBASE_UBERRATE, text = "", special = "Uber Rate Bonus", base = TF_BOTBASE_UBERRATE}, [TF_BOTUPGRADE_HEALRATE] = { attribute = "heal rate penalty", increment = 0.5, cap = 2147483647, cost = 500, value = TF_BOTBASE_UBERRATE, text = "", special = "Heal Rate Bonus", base = TF_BOTBASE_UBERRATE}, [TF_BOTUPGRADE_TANKSPEED] = { attribute = nil, increment = 0.25, cap = 3, cost = 750, special = "Tank Speed Multiplier", value = TF_BOTBASE_TANKSPEED, text = "", base = TF_BOTBASE_TANKSPEED}, [TF_BOTUPGRADE_FASTERRECHARGE] = { attribute = "mult_item_meter_charge_rate", increment = -0.25, cap = 0.25, cost = 300, special = "Recharge Rate", value = TF_BOTBASE_FASTERRECHARGE, text = "", base = TF_BOTBASE_FASTERRECHARGE}, --[TF_BOTUPGRADE_LUCKCHANCE] = { attribute = nil, increment = 0.1, cap = 10, cost = 300, special = "Luck Multiplier", value = TF_BOTBASE_LUCKCHANCE, text = "", base = TF_BOTBASE_LUCKCHANCE}, [TF_BOTUPGRADE_CANTEENUBER] = { attribute = "tag__summer2014", increment = 1, cap = 1, cost = 3500, special = "Uber Canteen", value = TF_BOTBASE_CANTEENUBER, text = "", base = TF_BOTBASE_CANTEENUBER}, [TF_BOTUPGRADE_CANTEENCRIT] = { attribute = "tag__eotlearlysupport", increment = 3, cap = 3, cost = 2250, special = "Crit Canteen", value = TF_BOTBASE_CANTEENCRIT, text = "", base = TF_BOTBASE_CANTEENCRIT}, [TF_BOTUPGRADE_CANTEENAMMO] = { attribute = "purchased", increment = 3, cap = 3, cost = 1800, special = "Ammo Canteen", value = TF_BOTBASE_CANTEENAMMO, text = "", base = TF_BOTBASE_CANTEENAMMO} } local PerkTable = { [TF_BOTPERK_REFLECT] = { internalname = tf_bot_melee_reflect_perk, luck = 5, printname = "Reflect: Melee hits airblast players!", unlocked = false, class = -1, giantstoo = true, new = false }, [TF_BOTPERK_IMMOVABLE] = { internalname = tf_bot_anti_slow, luck = 10, printname = "Immovable: Common bots no longer recieve movement impairing effects!", unlocked = false, class = -1, giantstoo = false, new = false }, [TF_BOTPERK_EFFICIENT_SUPPLY] = { internalname = tf_bot_cooldown_reduction, luck = 8, printname = "Efficient Supply: Bar items recharge faster!", unlocked = false, class = -1, giantstoo = true, new = false }, [TF_BOTPERK_ASSASSIN_SUPPORT] = { internalname = tf_bot_support_sniper_spy, luck = 6, printname = "Assassin Support: Support snipers and spies now spawn!", unlocked = false, class = -1, giantstoo = false, new = false }, [TF_BOTPERK_MEDICAL_SUPPORT] = { internalname = tf_bot_support_medic, luck = 16, printname = "Medical Support: Support medics now spawn!", unlocked = false, class = -1, giantstoo = false, new = false }, [TF_BOTPERK_HITMAN] = { internalname = tf_bot_hitman, luck = 20, printname = "Hitman: Chance for spy support to spawn in as a hitman!", unlocked = false, class = 8, giantstoo = false, new = false }, [TF_BOTPERK_SHORT_TEMPER] = { internalname = tf_bot_short_temper, luck = 15, printname = "Short Temper: Heavies deal extra damage when on low hp!", unlocked = false, class = 6, giantstoo = true, new = false }, [TF_BOTPERK_BLAZING_PAYLOAD] = { internalname = tf_bot_blazing_payload, luck = 18, printname = "Blazing Payload: Pyro bots gain a gas passer attack that deals high after burn damage!", unlocked = false, class = 7, giantstoo = true, new = false }, [TF_BOTPERK_GHEAVY_SUPPORT] = { internalname = tf_bot_support_gheavy, luck = 24, printname = "Heavy Support: Support giant heavies now sppawn!", unlocked = false, class = -1, giantstoo = false, new = false }, [TF_BOTPERK_SNIPER_MASTER] = { internalname = tf_bot_support_sniper_master, luck = 54, printname = "Master Snipers: Suppot snipers can now headshot and track better!", unlocked = false, class = -1, giantstoo = false, new = false }, [TF_BOTPERK_EXCESSIVE_FIREPOWER] = { internalname = tf_bot_excessive_firepower, luck = 58, printname = "Excessive Firepower: Soldier bots without a banner now attack and reload faster!", unlocked = false, class = 3, giantstoo = true, new = false }, [TF_BOTPERK_VANGUARD] = { internalname = tf_bot_support_vanguard, luck = 55, printname = "Vanguard: Support engineer bots now teleport in the soldier bot bodyguards!", unlocked = false, class = -1, giantstoo = false, new = false }, [TF_BOTPERK_HARD_RUSH] = { internalname = tf_bot_scout_death_boost, luck = 96, printname = "Hard Rush: Scout bots now spawn a boost beacon on death!", unlocked = false, class = 1, giantstoo = true, new = false }, [TF_BOTPERK_JUGGERNAUT] = { internalname = tf_bot_support_juggernaut, luck = 105, printname = "Juggernaut: A highly skilled and upgraded giant demo bot periodically spawns in!", unlocked = false, class = -1, giantstoo = false, new = false }, [TF_BOTPERK_PHASE_SHIFTING] = { internalname = tf_bot_support_phase_shifting, luck = 120, printname = "Phase Shifting: Giant bots can not be bodyblocked by players nor buildings!", unlocked = false, class = -1, giantstoo = true, new = false } } function DoPerks() Luck = ( (WaveNum - 1) * 3 ) * LuckMult Luck = Luck + math.random(-2,4) Luck = Luck * 100 --dev testing if Luck <= 0 then Luck = 1 end for index,_ in pairs(PerkTable) do PerkTable[index].new = false if PerkTable[index].luck <= Luck and (PerkTable[index].unlocked == false) then PerkTable[index].unlocked = true Luck = Luck - PerkTable[index].luck PerkTable[index].new = true if PerkTable[index].internalname == tf_bot_support_sniper_spy then ents.FindByName("perk_support_sniper"):AcceptInput("enable") ents.FindByName("perk_support_spy"):AcceptInput("enable") elseif PerkTable[index].internalname == tf_bot_support_medic then ents.FindByName("perk_support_medic"):AcceptInput("enable") elseif PerkTable[index].internalname == tf_bot_support_gheavy then ents.FindByName("perk_support_giant_heavy"):AcceptInput("enable") elseif PerkTable[index].internalname == tf_bot_support_sniper_master then ents.FindByName("perk_support_sniper"):AcceptInput("disable") ents.FindByName("perk_support_sniper_master"):AcceptInput("enable") elseif PerkTable[index].internalname == tf_bot_support_vanguard then ents.FindByName("perk_support_vangaurd"):AcceptInput("enable") elseif PerkTable[index].internalname == tf_bot_support_juggernaut then ents.FindByName("perk_support_juggernaut"):AcceptInput("enable") end end end end function PrintPerks() util.PrintToChatAll("") util.PrintToChatAll("\x0799CCFFBot Perks:") util.PrintToChatAll("") for index,_ in pairs(PerkTable) do if PerkTable[index].unlocked then if PerkTable[index].new then util.PrintToChatAll("\x079ec34f" .. PerkTable[index].printname .. " (New)") else util.PrintToChatAll(PerkTable[index].printname) end end end end function DoUpgrades() ShuffleInPlace(UpgradeTable) BotCredits = ( 800 + ( (WaveNum - 2) * 100 ) ) for index,_ in pairs(UpgradeTable) do UpgradeTable[index].text = UpgradeTable[index].special .. ": " .. UpgradeTable[index].value .. "!" if UpgradeTable[index].cost <= BotCredits and (math.random() > 0.667) then if ( UpgradeTable[index].attribute ~= nil ) then if ( UpgradeTable[index].value < UpgradeTable[index].cap and ( UpgradeTable[index].cap >= 1 ) ) or ( UpgradeTable[index].value + UpgradeTable[index].increment > UpgradeTable[index].cap and ( UpgradeTable[index].cap < 1 ) ) then UpgradeTable[index].text = "\x079ec34f" .. UpgradeTable[index].special .. ": " .. UpgradeTable[index].value + UpgradeTable[index].increment .. "! " .. " (Upgraded!)" UpgradeTable[index].value = UpgradeTable[index].value + UpgradeTable[index].increment BotCredits = BotCredits - UpgradeTable[index].cost end elseif UpgradeTable[index].special == "Tank Speed Multiplier" and ( UpgradeTable[index].value < UpgradeTable[index].cap ) then UpgradeTable[index].text = "\x079ec34f" .. UpgradeTable[index].special .. ": " .. UpgradeTable[index].value + UpgradeTable[index].increment .. "! " .. " (Upgraded!)" UpgradeTable[index].value = UpgradeTable[index].value + UpgradeTable[index].increment TankSpeedVar = TankSpeedVar * UpgradeTable[index].value elseif UpgradeTable[index].special == "Bomb Return Time" and ( UpgradeTable[index].value < UpgradeTable[index].cap ) then UpgradeTable[index].text = "\x079ec34f" .. UpgradeTable[index].special .. ": " .. UpgradeTable[index].value + UpgradeTable[index].increment .. "! " .. " (Upgraded!)" UpgradeTable[index].value = UpgradeTable[index].value + UpgradeTable[index].increment BombReturnTimeVar = UpgradeTable[index].value elseif UpgradeTable[index].special == "Luck Multiplier" and ( UpgradeTable[index].value < UpgradeTable[index].cap ) then UpgradeTable[index].text = "\x079ec34f" .. UpgradeTable[index].special .. ": " .. UpgradeTable[index].value + UpgradeTable[index].increment .. "! " .. " (Upgraded!)" UpgradeTable[index].value = UpgradeTable[index].value + UpgradeTable[index].increment LuckMult = UpgradeTable[index].value end end end if BotCredits >= 200 then DoUpgradesLoop() else PrintUpgrades() end end function DoUpgradesLoop() for index,_ in pairs(UpgradeTable) do if UpgradeTable[index].cost <= BotCredits and (math.random() > 0.333) then if ( UpgradeTable[index].attribute ~= nil ) then if ( UpgradeTable[index].value < UpgradeTable[index].cap and ( UpgradeTable[index].cap >= 1 ) ) or ( UpgradeTable[index].value + UpgradeTable[index].increment > UpgradeTable[index].cap and ( UpgradeTable[index].cap < 1 ) ) then UpgradeTable[index].text = "\x079ec34f" .. UpgradeTable[index].special .. ": " .. UpgradeTable[index].value + UpgradeTable[index].increment .. "! " .. " (Upgraded!)" UpgradeTable[index].value = UpgradeTable[index].value + UpgradeTable[index].increment BotCredits = BotCredits - UpgradeTable[index].cost end elseif UpgradeTable[index].special == "Tank Speed Multiplier" and ( UpgradeTable[index].value < UpgradeTable[index].cap ) then UpgradeTable[index].text = "\x079ec34f" .. UpgradeTable[index].special .. ": " .. UpgradeTable[index].value + UpgradeTable[index].increment .. "! " .. " (Upgraded!)" UpgradeTable[index].value = UpgradeTable[index].value + UpgradeTable[index].increment TankSpeedVar = TankSpeedVar * UpgradeTable[index].value elseif UpgradeTable[index].special == "Bomb Return" and ( UpgradeTable[index].value < UpgradeTable[index].cap ) then UpgradeTable[index].text = "\x079ec34f" .. UpgradeTable[index].special .. ": " .. UpgradeTable[index].value + UpgradeTable[index].increment .. "! " .. " (Upgraded!)" UpgradeTable[index].value = UpgradeTable[index].value + UpgradeTable[index].increment BombReturnTimeVar = UpgradeTable[index].value elseif UpgradeTable[index].special == "Luck Multiplier" and ( UpgradeTable[index].value < UpgradeTable[index].cap ) then UpgradeTable[index].text = "\x079ec34f" .. UpgradeTable[index].special .. ": " .. UpgradeTable[index].value + UpgradeTable[index].increment .. "! " .. " (Upgraded!)" UpgradeTable[index].value = UpgradeTable[index].value + UpgradeTable[index].increment LuckMult = UpgradeTable[index].value end end end if BotCredits >= 200 then DoUpgradesLoop() else PrintUpgrades() end end function ApplyPerks(bot) for index,_ in pairs(PerkTable) do -- tier 1 if PerkTable[index].internalname == tf_bot_melee_reflect_perk then bot:GetPlayerItemBySlot(2):SetAttributeValue("damage causes airblast", 1) elseif PerkTable[index].internalname == tf_bot_anti_slow then bot:Addcond(28) elseif PerkTable[index].internalname == tf_bot_cooldown_reduction then bot:SetAttributeValue("mult_item_meter_charge_rate", 0.5) -- tier 2 elseif PerkTable[index].internalname == tf_bot_hitman then if math.random > 0.4 then bot:SetAttributeValue("max health addivite bonus", 250) bot:WeaponStripSlot(2) bot:WeaponStripSlot(4) bot:WeaponStripSlot(5) bot:WeaponStripSlot(6) bot:AcceptInput("$BotCommand","switch_action Mobber") end elseif PerkTable[index].internalname == tf_bot_short_temper then bot.Temper = true elseif PerkTable[index].internalname == tf_bot_blazing_payload then bot:GiveItem("The Gas Passer") bot:GetPlayerItemBySlot(1):SetAttributeValue("force weapon switch", 1) bot:GetPlayerItemBySlot(1):SetAttributeValue("item_meter_charge_rate", 20) bot:GetPlayerItemBySlot(1):SetAttributeValue("weapon burn dmg increased", 3.75) -- tier 3 elseif PerkTable[index].internalname == tf_bot_excessive_firepower then if bot:GetPlayerItemBySlot(1) ~= "The Buff Banner" or bot:GetPlayerItemBySlot(1) ~= "The Battalion's Backup" or bot:GetPlayerItemBySlot(1) ~= "The Concheror" then bot:GetPlayerItemBySlot(0)SetAttributeValue("melee attack rate bonus", 0.5) bot:GetPlayerItemBySlot(0)SetAttributeValue("halloween reload time decreased", 0.5) end -- tier 4 elseif PerkTable[index].internalname == tf_bot_scout_death_boost then bot.DeathBoost = true elseif PerkTable[index].internalname == tf_bot_support_phase_shifting then if bot.m_bIsMiniBoss then bot:SetAttributeValue("not solid to players", 1) end end end end function ApplyUpgrades(bot) for index,_ in pairs(UpgradeTable) do if UpgradeTable[index].attribute ~= nil then bot:SetAttributeValue(UpgradeTable[index].attribute, UpgradeTable[index].value) end end --[[ for index,_ in pairs(PerkTable) do print('table class', PerkTable[index].class) print('bot class', bot.m_iClass) print('equal check', PerkTable[index].class == bot.m_iClass) if PerkTable[index].unlocked then if PerkTable[index].class == -1 then if PerkTable[index].giantstoo then ApplyPerks(bot) else if bot.m_bIsMiniBoss == false then ApplyPerks(bot) end end else if PerkTable[index].class == bot.m_iClass then if PerkTable[index].giantstoo then ApplyPerks(bot) else if bot.m_bIsMiniBoss == false then ApplyPerks(bot) end end end end end end --]] end function PrintUpgrades() util.PrintToChatAll("\x0799CCFFBot Upgrades:") util.PrintToChatAll("") for index,_ in pairs(UpgradeTable) do if string.match(UpgradeTable[index].text, "(Upgraded!)") then util.PrintToChatAll(UpgradeTable[index].text) end end --PrintPerks() end function OnGameTick() for _,tank in pairs(ents.FindAllByClass("tank_boss")) do if tank:IsValid() then tank:AcceptInput("SetSpeed", TankSpeedVar) end end for _, player in pairs(ents.GetAllPlayers()) do if player:IsRealPlayer() then if player:InCond(81) and ( not player:IsMidair() ) then player:RemoveCond(81) end if player:InCond(12) and ( not player:IsMidair() ) then player:RemoveCond(12) end if player:InCond(12) and player:InCond(80) then player:SetAttributeValue("no_jump", 1) else player:SetAttributeValue("no_jump",nil) end end end end function has_value (tab, val) --copied from stack overflow for index, value in ipairs(tab) do if value == val then return true end end return false end function PrintChatText(text) --currently colored text is limited to lua scripts, idk why util.PrintToChatAll(text) --to create colored text, start with "\x07" then add the color in hexadecimal form end function OnWaveSpawnBot(bot, wave, tags) timer.Simple(0.1, function() ApplyUpgrades(bot) end) if bot.m_iClass ~= TF_CLASS_SPY then local usesLeft = 3 local maxHealth = bot.m_iHealth local curHealth = bot.m_iHealth local enraged = false local ShotCount = 0 local enrageCount = 0 local maxammo = bot.m_hActiveWeapon.m_iClip1 bot:AddCallback(ON_DAMAGE_RECEIVED_POST, function(ent, damage, previousHealth) curHealth = bot.m_iHealth if IsValid(bot:GetPlayerItemBySlot(0)) then if bot:GetPlayerItemBySlot(0):GetItemName() == "The Phlogistinator" and ( not has_value(tags, "bot_boss") ) then --phlog taunt when injured function. if curHealth <= maxHealth*0.8 and ( enraged == false ) then enraged = true bot:Taunt("TAUNT_BASE_WEAPON", 0) end end end if has_value(tags, "bot_enragable") then --enrage bot function if curHealth <= maxHealth*0.65 and ( enraged == false ) then enraged = true bot:AddCond(34,6) bot:AddCond(26,6) bot:AddCond(71,1) bot:ChangeAttributes("Enraged") timer.Simple(6, function() bot:ChangeAttributes("Defualt") end) end end end) bot:AddCallback(ON_DAMAGE_RECEIVED_PRE, function(ent, damage) curHealth = bot.m_iHealth if has_value(tags, "bot_canteenuber") or ( IsValid(bot:GetAttributeValue("tag__summer2014")) ) then --uber canteen bot function if not bot:InCond(8) then if curHealth <= maxHealth*0.25 and ( enraged == false ) then bot:AddCond(52,5) PrintChatText('\x0799CCFF' .. tostring(bot:GetPlayerName()) .. ' \x07FBECCBhas used thier \x079ec34fÜBERCHARGE \x07FBECCBPower Up Canteen!') for _, player in pairs(ents.GetAllPlayers()) do --play the canteen sound to all players if player:IsRealPlayer() then player:PlaySoundToSelf("MVM.PlayerUsedPowerup") player:PlaySoundToSelf("MVM.PlayerUsedPowerup") end end enraged = true elseif damage.Damage >= curHealth and ( enraged == false ) then --makes the uber canteen bot servive a lethal strike -- damage.Damage = 0 bot:AddCond(52,5) bot:SetHealth(1) PrintChatText('\x0799CCFF' .. tostring(bot:GetPlayerName()) .. ' \x07FBECCBhas used thier \x079ec34fÜBERCHARGE \x07FBECCBPower Up Canteen!') for _, player in pairs(ents.GetAllPlayers()) do --play the canteen sound to all players if player:IsRealPlayer() then player:PlaySoundToSelf("MVM.PlayerUsedPowerup") player:PlaySoundToSelf("MVM.PlayerUsedPowerup") end end enraged = true end end end end) timer.Simple(0.5, function() bot.m_hActiveWeapon:AddCallback(ON_FIRE_WEAPON_PRE, function(ent) if has_value(tags, "bot_canteencrit") or ( IsValid(bot:GetAttributeValue("tag__eotlearlysupport")) ) then --crit canteen bot function if ( not bot:InCond(34) ) and ( not bot:InCond(51) ) then --only increment shot count when not critboosted and not in spawn ShotCount = ShotCount + 1 if ShotCount >= 3 and ( enrageCount < 3 ) then ShotCount = 0 enrageCount = enrageCount + 1 bot:AddCond(34,5) PrintChatText('\x0799CCFF' .. tostring(bot:GetPlayerName()) .. ' \x07FBECCBhas used thier \x079ec34fCRITS \x07FBECCBPower Up Canteen!') --what an ungodly parameter for _, player in pairs(ents.GetAllPlayers()) do --play the canteen sound to all players if player:IsRealPlayer() then player:PlaySoundToSelf("MVM.PlayerUsedPowerup") player:PlaySoundToSelf("MVM.PlayerUsedPowerup") end end end else ShotCount = 0 --to prevent back to back to back crit canteens end end if has_value(tags, "bot_canteenammo") or ( IsValid(bot:GetAttributeValue("purchased")) ) then --ammo canteen bot function if ent.m_iClip1 == 0 and (usesLeft ~= 0) then usesLeft = usesLeft - 1 ent.m_iClip1 = maxammo PrintChatText('\x0799CCFF' .. tostring(bot:GetPlayerName()) .. ' \x07FBECCBhas used thier \x079ec34fAMMO REFILL \x07FBECCBPower Up Canteen!') for _, player in pairs(ents.GetAllPlayers()) do --play the canteen sound to all players if player:IsRealPlayer() then player:PlaySoundToSelf("MVM.PlayerUsedPowerup") player:PlaySoundToSelf("MVM.PlayerUsedPowerup") end end end end end) end) end end function OnWaveInit() WaveNum = ents.FindByClass('tf_objective_resource').m_nMannVsMachineWaveCount end function OnWaveSuccess() if not DevMode then DoUpgrades() --DoPerks() for _, player in pairs(ents.GetAllPlayers()) do if player:IsRealPlayer() then player:Print(2,"Upgrading bots...") player:PlaySoundToSelf("Halloween.ClockTick") player:PlaySoundToSelf("Halloween.ClockTick") end end timer.Simple(5, function() GiveChips() end) end end function OnWaveFail() if not DevMode then for _, player in pairs(ents.GetAllPlayers()) do if player:IsRealPlayer() then player:Print(2,"Defeat! Reseting to wave 1!") player:PlaySoundToSelf("Game.YourTeamLost") player:PlaySoundToSelf("Game.YourTeamLost") end end timer.Simple(1, function() for index,_ in pairs(UpgradeTable) do UpgradeTable[index].value = UpgradeTable[index].base UpgradeTable[index].text = "" end for index,_ in pairs(PerkTable) do PerkTable[index].unlocked = false end end) timer.Simple(3, function() ents.FindByClass("point_populator_interface"):AcceptInput("$JumpToWave", 1) end) end end function OnWaveStart(wave) for _,bomb in pairs(ents.FindAllByClass("item_teamflag")) do bomb:AcceptInput("SetReturnTime", BombReturnTimeVar) end end function ToggleDevMode() if DevMode then DevMode = false else DevMode = true end print(DevMode) end function GiveChips() local rand = math.random(13,53) local sound = "Halloween.spelltick_a" local finalsound = "Halloween.spelltick_set" timer.Create(0.05, function() if ChipReward == 1 then if math.random() > 0.2 then ChipReward = 3 sound = "Halloween.spelltick_a" finalsound = "Halloween.spelltick_set" else ChipReward = 0 sound = "Halloween.spelltick_a" finalsound = "Passtime.Crowd.Boo" end elseif ChipReward == 3 then ChipReward = 5 sound = "Halloween.spelltick_b" finalsound = "Halloween.spelltick_set" elseif ChipReward == 5 then if math.random() > 0.1 then ChipReward = 10 sound = "Halloween.spelltick_a" finalsound = "Passtime.Crowd.Cheer" else ChipReward = "JACKPOT!!!" sound = "Halloween.spelltick_a" finalsound = "Passtime.Crowd.Cheer" end elseif ChipReward == 10 then ChipReward = 1 sound = "Halloween.spelltick_b" finalsound = "Passtime.Crowd.Boo" elseif ChipReward == "JACKPOT!!!" then ChipReward = 0 sound = "Halloween.spelltick_a" finalsound = "Passtime.Crowd.Boo" elseif ChipReward == 0 then ChipReward = 1 sound = "Halloween.spelltick_b" finalsound = "Passtime.Crowd.Boo" end for _, player in pairs(ents.GetAllPlayers()) do if player:IsRealPlayer() then player:Print(2,"Chip Reward: " .. ChipReward) player:PlaySoundToSelf(sound) end end end, rand) timer.Simple( (rand*0.05) + 0.6, function() if ChipReward ~= "JACKPOT!!!" and ChipReward ~= 0 then ents.FindByName("chips_add_" .. ChipReward .. "_relay"):AcceptInput("trigger") for _, player in pairs(ents.GetAllPlayers()) do if player:IsRealPlayer() then player:PlaySoundToSelf(finalsound) end end elseif ChipReward == "JACKPOT!!!" then timer.Create(0.1, function() ents.FindByName("chips_add_10_relay"):AcceptInput("trigger") end, 10) for _, player in pairs(ents.GetAllPlayers()) do if player:IsRealPlayer() then player:PlaySoundToSelf(finalsound) player:PlaySoundToSelf(finalsound) end end elseif ChipReward == 0 then for _, player in pairs(ents.GetAllPlayers()) do if player:IsRealPlayer() then player:PlaySoundToSelf(finalsound) end end end end) end function DevForceChips() GiveChips() end function teslaZap(damage, activator, caller) for _, player in pairs(ents.FindInSphere(activator:GetAbsOrigin(),192)) do if activator.m_iTeamNum ~= player.m_iTeamNum and (player:IsPlayer()) then --not same team local upgradeLvl = activator:GetPlayerItemBySlot(0):GetAttributeValue("damage bonus") if upgradeLvl == nil then upgradeLvl = 1 end if player:IsPlayer() then player:TakeDamage({Attacker = activator, Damage = 11 * upgradeLvl, DamageType = DMG_SHOCK, DamageCustom = TF_DMG_CUSTOM_PLASMA}) else player:TakeDamage({Attacker = activator, Damage = 7 * upgradeLvl, DamageType = DMG_SHOCK, DamageCustom = TF_DMG_CUSTOM_PLASMA}) end end end end function JugglerHit(damage, activator, caller) --activator is the one with the weapon, caller is the one that got hit if caller:IsPlayer() and ( caller.m_iTeamNum ~= activator.m_iTeamNum ) then timer.Simple(0.1,function() caller:AddCond(80) end) end end function JugglerHitEnemy(damage, activator, caller) --activator is the one with the weapon, caller is the one that got hit if caller:IsPlayer() and ( caller.m_iTeamNum ~= activator.m_iTeamNum ) then timer.Simple(0.1,function() caller:AddCond(80) caller:AddCond(12) ReserveCombo(_,activator) end) end end function Payout(damage, activator, caller) --activator is the one with the weapon, caller is the one that got hit if caller:IsPlayer() then local payout = damage * 0.1 if payout > 50 then payout = 50 elseif payout < 1 then payout = 1 end for _, player in pairs(ents.GetAllPlayers()) do if player:IsRealPlayer() then player:AddCurrency(payout) end end end end function JawBreaker(damage, activator, caller) --activator is the one with the weapon, caller is the one that got hit if caller:IsPlayer() and ( caller.m_iTeamNum ~= activator.m_iTeamNum ) then ents.FindByName("JB_fx_spawner"):Teleport(caller:GetAbsOrigin()) ents.FindByName("JB_fx_spawner"):AcceptInput("ForceSpawn") caller:PlaySound("Weapon_LooseCannon.Explode") caller:PlaySound("Weapon_LooseCannon.Explode") caller:PlaySound("Weapon_LooseCannon.Explode") local BlastDamageMult = activator:GetPlayerItemBySlot(0):GetAttributeValue("damage bonus") local BlastRadiusMult = activator:GetPlayerItemBySlot(0):GetAttributeValue("blast radius increased") if BlastRadiusMult == nil then BlastRadiusMult = 1 end if BlastDamageMult == nil then BlastDamageMult = 1 end if damage ~= 50 * BlastDamageMult then --detect if hit was a minicrit or full crit BlastDamageMult = BlastDamageMult + ( ( damage / ( 50 * BlastDamageMult ) ) - 1 ) end for _, others in pairs(ents.FindInSphere(caller:GetAbsOrigin(),128 * BlastRadiusMult)) do if others:IsPlayer() and ( others.m_iTeamNum ~= activator.m_iTeamNum ) then others:TakeDamage({Damage = 80 * BlastDamageMult, Attacker = activator, DamageType = DMG_BLAST}) end end end end function ExplosiveBow(damage, activator, caller) --activator is the one with the weapon, caller is the one that got hit if caller:IsPlayer() and ( caller.m_iTeamNum ~= activator.m_iTeamNum ) then ents.FindByName("JB_fx_spawner"):Teleport(caller:GetAbsOrigin()) ents.FindByName("JB_fx_spawner"):AcceptInput("ForceSpawn") caller:PlaySound("Weapon_LooseCannon.Explode") caller:PlaySound("Weapon_LooseCannon.Explode") caller:PlaySound("Weapon_LooseCannon.Explode") local BlastDamage = damage * 0.5 local BlastRadius = damage * 0.75 local BlastDamageMult = activator:GetPlayerItemBySlot(0):GetAttributeValue("throwable damage") local BlastRadiusMult = activator:GetPlayerItemBySlot(0):GetAttributeValue("blast radius increased") if BlastDamageMult == nil then BlastDamageMult = 1 end if BlastRadiusMult == nil then BlastRadiusMult = 1 end if BlastDamage > 100 then BlastDamage = 100 end if BlastRadius > 147 then BlastRadius = 147 end BlastDamage = BlastDamage * BlastDamageMult BlastRadius = BlastRadius * BlastRadiusMult for _, others in pairs(ents.FindInSphere(caller:GetAbsOrigin(),BlastRadius)) do if others:IsPlayer() and ( others.m_iTeamNum ~= activator.m_iTeamNum ) then others:TakeDamage({Damage = BlastDamage, Attacker = activator, DamageType = DMG_BLAST}) end end end end function FlareRaider(damage, activator, caller) --activator is the one with the weapon, caller is the one that got hit if caller == activator then activator:Addcond(81) end end function TeslaOrbDamage(_, activator) for _, others in pairs(ents.FindInSphere(activator:GetAbsOrigin(),128)) do if others:IsBot() then others:TakeDamage({ Damage = 12, Attacker = others, DamageType = DMG_SHOCK, DamageCustom = TF_DMG_CUSTOM_PLASMA }) end end end function Uberdose(damage, activator, caller) --activator is the one with the weapon, caller is the one that got hit if caller.m_iTeamNum ~= activator.m_iTeamNum and (IsValid(activator:GetPlayerItemBySlot(1))) then DamageMult = activator:GetPlayerItemBySlot(1).m_flChargeLevel caller:TakeDamage({ Damage = damage * DamageMult, Attacker = activator, DamageType = DMG_BULLET }) end end function SummonFireStorm(_, activator) for _, player in pairs(ents.GetAllPlayers()) do if player:IsRealPlayer() then ents.FindByName("SFS_Attack_Spawner"):Teleport(player:GetAbsOrigin()) ents.FindByName("SFS_Attack_Spawner"):AcceptInput("ForceSpawn") end end end function RingofFire(_, activator) local angle = 0 local amount = 24 for i=0, amount - 1 do ents.FindByName("RoF_Attack_Spawner"):Teleport(activator:GetAbsOrigin(), Vector(0,angle,0)) ents.FindByName("RoF_Attack_Spawner"):SetAbsAngles(Vector(0,angle,0)) ents.FindByName("RoF_Attack_Spawner"):AcceptInput("ForceSpawn") angle = angle + 360 / amount end end function FireSurge(_, activator) local amount = 30 local delay = 0.5 for _, player in pairs(ents.GetAllPlayers()) do if player:IsRealPlayer() then timer.Create(delay,function() ents.FindByName("FS_Attack_Spawner"):Teleport(player:GetAbsOrigin()) ents.FindByName("FS_Attack_Spawner"):AcceptInput("ForceSpawn") end, amount) end end end CEntity.IsMidair = function(self) if (IsValidAlivePlayer(self)) then return not (self.movetype == MOVETYPE_WALK and (self.m_fFlags & FL_ONGROUND ~= 0)); end end function IsValidAlivePlayer(ent) return IsValid(ent) and ent:IsPlayer() and ent:IsAlive(); end --following stuff copied from bot_reserve_combo.lua so that the boss works propperly --Script made by Therealscroob/Crilly, this script's goal is to get blast soldiers with the reserve shooter to pull out their --reserve shooter to attack targets airborne targets function removeCallbacks(player, callbacks) if not IsValid(player) then return end for _, callbackId in pairs(callbacks) do player:RemoveCallback(callbackId) end end function ReserveCombo(_, activator) local callbacks = {} local check local terminated = false local secondary = activator:GetPlayerItemBySlot(1) function terminate() if terminated then return end terminated = true timer.Stop(check) removeCallbacks(activator, callbacks) end check = timer.Create(0.015, function() if not IsValid(activator) or not IsValid(secondary) then terminate() return end --Find all players within 1000 units of the activator, may be decreased due to how low the reserve shooter's damage is at range --this would be a nice base for a potential master AI script. local botLocation = activator:GetAbsOrigin() local sphereResults = ents.FindInSphere(botLocation, 1000) local filteredSphereResults = {} local lastEntry if sphereResults then for _, entity in pairs(sphereResults) do if entity:IsPlayer() and entity.m_iTeamNum ~= activator.m_iTeamNum and entity ~= lastEntry then if entity:InCond(81) or entity:InCond(98) or entity:InCond(99) or entity:InCond(125)then if not entity:InCond(4) and not entity:InCond(3) and not entity:InCond(66) then --so spies don't get assblasted table.insert(filteredSphereResults, entity) lastEntry = entity end end end end --PrintTable(filteredSphereResults) if filteredSphereResults and lastEntry then activator:WeaponSwitchSlot(1) secondary:SetAttributeValue("disable weapon switch", 1) --This is taken from build_ally_bot.lua, by royal. Mince was thanked in the original comment that appeared with this. local targetAngles = (lastEntry:GetAbsOrigin() - (activator:GetAbsOrigin() + Vector(0,0,activator["m_vecViewOffset[2]"]))):ToAngles() targetAngles = Vector(targetAngles[1], targetAngles[2], 0) activator:SnapEyeAngles(targetAngles) --print("Aim") activator:RunScriptCode("activator.PressFireButton(0.01)", activator) else secondary:SetAttributeValue("disable weapon switch", 0) activator:WeaponSwitchSlot(0) end else return end end, 0) callbacks.died = activator:AddCallback(ON_DEATH, function() terminate() end) callbacks.removed = activator:AddCallback(ON_REMOVE, function() terminate() end) callbacks.spawned = activator:AddCallback(ON_SPAWN, function() terminate() end) end