-- tricksies.lua -- Author: achoo -- This lua script is designed to go along with -- mvm_decoy_expert_little_tricksies -- Don't @ me for my shit code this is my first project in either lua or vscript if not BOT_ATTRIBUTES then BOT_ATTRIBUTES = { ["BULLET_IMMUNE"] = 1 << 23, ["BLAST_IMMUNE"] = 1 << 24, ["FIRE_IMMUNE"] = 1 << 25 } end AddGlobalCallback("OnWaveSpawnBot", function(bot, wave, tags) bot:RunScriptCode(([[ local attr_blast_immune = %d local attr_bullet_immune = %d local attr_fire_immune = %d if (activator.HasBotAttribute(attr_blast_immune) && activator.HasBotAttribute(attr_bullet_immune) && activator.HasBotAttribute(attr_fire_immune)) { return } else { activator.AddCustomAttribute("mult dmgtaken from melee", 1.5, 0) } ]]):format(1 << 24, 1 << 23, 1 << 25), bot, bot) -- fan of war mobbing for _, tag in pairs(tags) do local split = {} for k, _ in string.gmatch(tag, "([^_]+)") do table.insert(split, k) end if split[1]:lower() == "target" and split[2]:lower() == "single" and split[3]:lower() == "player" then --util.PrintToChatAll("targeting single player") MobSinglePlayerBehavior(bot) end end end) -- a bot with this tag completely ignores the bomb and targets one single player randomly until death function MobSinglePlayerBehavior(bot) local interruptActionStr = "interrupt_action -posent %s -lookposent %s -killlook -waituntildone -alwayslook -distance 1" local function selectRandomPlayer() local players = ents.GetAllPlayers() for i, player in ipairs(players) do if not player:IsRealPlayer() or not player:IsAlive()then --util.PrintToChatAll("removed player due to death/being a bot") table.remove(players, i) end end local selectPlayerIndex = math.random(1, #players) for i, player in ipairs(players) do if i == selectPlayerIndex then --util.PrintToChatAll(("found a player (index %d)"):format(i)) return player end end --util.PrintToChatAll("no player found") return nil end local selectedPlayer = selectRandomPlayer() local interruptActive = false local function startInterrupt() if interruptActive then return end --util.PrintToChatAll("interrupt active") interruptActive = true bot:BotCommand(interruptAction) end local function stopInterrupt() if not interruptActive then return end --util.PrintToChatAll("deactivating interrupt") interruptActive = false bot:BotCommand("stop interrupt action") bot:BotCommand("clear_interrupt_action_queue") end local timerId timerId = timer.Create(0.15, function() -- look for new player if bad if not selectedPlayer or not IsValid(selectedPlayer) or not selectedPlayer:IsAlive() then --util.PrintToChatAll("reselecting") stopInterrupt() selectedPlayer = selectRandomPlayer() return end interruptAction = interruptActionStr:format(selectedPlayer:GetName(), selectedPlayer:GetName()) startInterrupt() end) end -- when the mission switches to Little Tricksies, for some reason, -- people who were already in the server don't get OnPlayerConnected called -- for them, so OnWaveInit checks this and adds the callback. tPlayersWithTricksiesCallback = {} function TricksiesOnPlayerConnected(player) if not player:IsRealPlayer() then return end local function onEquipItemCallback(ent, weapon) -- because lua doesn't have CBaseCombatWeapon::GetSlot() if weapon == ent:GetPlayerItemBySlot(LOADOUT_POSITION_SECONDARY) then if ent.m_iClass == TF_CLASS_DEMOMAN then if weapon:GetClassname():lower() ~= "tf_wearable_demoshield" then util.PrintToChat(ent, "Psst, did you know that shields allow you to upgrade damage on swords? In this mission they even give you extra money collection radius!") end end end end util.PrintToChat(player, "Welcome to Little Tricksies!") util.PrintToChat(player, "\x07F7694D[BALANCE] \x01Most supports in this mission are only a part of the final subwave of each wave.") -- util.PrintToChat(player, "\x07F7694D[BALANCE] \x01All uber medics in this mission have 130 health. :)") local justLoaded = true local function onSpawnCallback(ent) local melee = ent:GetPlayerItemBySlot(LOADOUT_POSITION_MELEE) if melee then --util.PrintToChat(ent, "\x07F7694D[MELEE] \x07FFFFFFDouble damage to non-triple-vaccinated enemies and tanks. +10 health per hit.") -- melee:SetAttributeValue("mult dmg vs tanks", 2) util.PrintToChat(ent, "\x07F7694D[MELEE] \x011.5x damage to non-triple-vaccinated. +10 health per hit.") melee:SetAttributeValue("heal on hit for slowfire", 10) if melee:GetClassname():lower() == "tf_weapon_knife" then util.PrintToChat(ent, "\x07F7694D[KNIVES] \x01-40% damage to giants.") --melee:SetAttributeValue("armor piercing", -0.5) melee:SetAttributeValue("mult dmg vs giants", 0.6) end end local secondary = ent:GetPlayerItemBySlot(LOADOUT_POSITION_SECONDARY) -- shields give the player 3x money collection radius -- util.PrintToChat(ent, secondary:GetClassname()) if secondary then if secondary:GetClassname():lower() == "tf_wearable_demoshield" then util.PrintToChat(ent, "\x07F7694D[SHIELD] \x013x money collection radius (scout's is 4x)") secondary:SetAttributeValue("mult credit collect range", 3) end end if justLoaded then justLoaded = false onEquipItemCallback(ent, ent:GetPlayerItemBySlot(LOADOUT_POSITION_MELEE)) onEquipItemCallback(ent, ent:GetPlayerItemBySlot(LOADOUT_POSITION_SECONDARY)) onEquipItemCallback(ent, ent:GetPlayerItemBySlot(LOADOUT_POSITION_PRIMARY)) end end player:AddCallback(ON_SPAWN, onSpawnCallback) -- give information for shields on equip item, not spawn player:AddCallback(ON_EQUIP_ITEM, onEquipItemCallback) -- onEquipItemCallback(player, player:GetPlayerItemBySlot(LOADOUT_POSITION_PRIMARY)) -- onEquipItemCallback(player, player:GetPlayerItemBySlot(LOADOUT_POSITION_SECONDARY)) -- onEquipItemCallback(player, player:GetPlayerItemBySlot(LOADOUT_POSITION_MELEE)) tPlayersWithTricksiesCallback[player:GetUserId()] = player end AddGlobalCallback("OnPlayerConnected", TricksiesOnPlayerConnected) AddGlobalCallback("OnPlayerDisconnected", function(player) tPlayersWithTricksiesCallback[player:GetUserId()] = nil end) AddGlobalCallback("OnWaveInit", function(wave) -- print("on wave init") players = ents.GetAllPlayers() for _, player in pairs(players) do if not tPlayersWithTricksiesCallback[player:GetUserId()] then TricksiesOnPlayerConnected(player) -- util.PrintToConsole(player, "WaveInit instead of OnPlayerConnected") end end end)