//vscript by stardustspy //do not use without my credit PLEASE!!!!!!!!! ::TEAM_RED <- 2 ::TEAM_BLU <- 3 ::TF_NAV_SPAWN_ROOM_RED <- 2 ::TF_NAV_SPAWN_ROOM_BLUE <- 4 ::TF_BOT_FAKE_CLIENT <- 1337 ::MAX_COUNT_WEAPON_EQUPPED <- 8 ::TEAM_SPECTATOR <- 1 ::SOLID_NONE <- 0 ::CONTENTS_SOLID <- 1 ::CONTENTS_WINDOW <- 2 ::CONTENTS_GRATE <- 8 ::CONTENTS_MOVEABLE <- 16384 ::CONTENTS_PLAYERCLIP <- 65536 ::MASK_NPCWORLDSTATIC <- 131083 ::MASK_PLAYERSOLID <- 33636363 ::MASK_NPCSOLID <- 33701899 ::MASK_SOLID <- 33570827 ::MASK_SHOT <- 1174421507 ::MASK_SHOT_HULL <- 100679691 ::IN_ATTACK2 <- 2048 ::PI <- 3.14159265359 ::PRIMARY_FIRE <- Constants.FButtons.IN_ATTACK ::SECONDARY_FIRE <- Constants.FButtons.IN_ATTACK2 ::gamerules <- Entities.FindByClassname(null, "tf_gamerules") ::player_manager <- Entities.FindByClassname(null, "tf_player_manager") ::WORLD_SPAWN <- Entities.FindByClassname(null, "worldspawn") ::MAX_COUNT_PLAYERS <- MaxClients().tointeger() ::MASK_VISIBLE_AND_NPCS <- 33579137 ::DMG_CRITICAL <- 1048576 ::TF_DMG_CUSTOM_HEADSHOT <- 1 ::TF_DMG_CUSTOM_BACKSTAB <- 2 ::TF_DMG_CRITICAL <- 1048576 ::SND_NOFLAGS <- 0 ::SND_CHANGE_VOL <- 1 ::SND_CHANGE_PITCH <- 2 ::SND_STOP <- 4 ::SND_SPAWNING <- 8 ::SND_DELAY <- 16 ::SND_STOP_LOOPING <- 32 ::SND_SPEAKER <- 64 ::SND_SHOULDPAUSE <- 128 ::SND_IGNORE_PHONEMES <- 256 ::SND_IGNORE_NAME <- 512 ::SND_DO_NOT_OVERWRITE_EXISTING_ON_CHANNEL <- 1024 const STRING_NETPROP_ITEMDEF = "m_AttributeManager.m_Item.m_iItemDefinitionIndex" const SLOT_COUNT = 7 const EFL_USER = 1048576 // EFL_IS_BEING_LIFTED_BY_BARNACLE const EFL_USER2 = 1073741824 //EFL_NO_PHYSCANNON_INTERACTION const SINGLE_TICK = 0.015 const DMG_NO_BULLET_FALLOFF = 2097152 PrecacheSound("ambient/energy/weld1.wav") PrecacheSound("ambient/energy/weld2.wav") PrecacheSound("player/recharged.wav") PrecacheSound("npc/assassin/ball_zap1.wav") PrecacheSound("weapons/drg_wrench_teleport.wav") PrecacheSound("misc/halloween/spell_lightning_ball_cast.wav") PrecacheSound("misc/halloween/spell_meteor_impact.wav") PrecacheSound("misc/halloween/spell_spawn_boss.wav") ::ROOT <- getroottable() ::MAX_CLIENTS <- MaxClients().tointeger() // get all players that can spawn in a server // Credit to Lite for folds if (!("ConstantNamingConvention" in ROOT)) foreach(a, b in Constants) foreach(k, v in b) ROOT[k] <- v != null ? v : 0 foreach(k, v in ::NetProps.getclass()) if (k != "IsValid" && !(k in ROOT)) ROOT[k] <- ::NetProps[k].bindenv(::NetProps) foreach(k, v in ::Entities.getclass()) if (k != "IsValid" && !(k in ROOT)) ROOT[k] <- ::Entities[k].bindenv(::Entities) foreach(k, v in ::EntityOutputs.getclass()) if (k != "IsValid" && !(k in ROOT)) ROOT[k] <- ::EntityOutputs[k].bindenv(::EntityOutputs) foreach(k, v in ::NavMesh.getclass()) if (k != "IsValid" && !(k in ROOT)) ROOT[k] <- ::NavMesh[k].bindenv(::NavMesh) ::gamerules <- FindByClassname(null, "tf_gamerules") ::player_manager <- FindByClassname(null, "tf_player_manager") ::WORLD_SPAWN <- FindByClassname(null, "worldspawn") //Teams ::TEAM_SPECTATOR <- 1 ::TEAM_RED <- 2 ::TEAM_BLU <- 3 ::TF_NAV_SPAWN_ROOM_RED <- 2 ::TF_NAV_SPAWN_ROOM_BLUE <- 4 ::TF_BOT_FAKE_CLIENT <- 1337 ::playableRobot <- { Player_Cleanup_Table = [] Player_ChangeClass_Table = [] //non-util funcs MissionSetup = function() { local bombpath_relay_ent = Entities.FindByName(null, "bombpath_choose_random_relay") local no_rain_relay_ent = Entities.FindByName(null, "weather_norain_relay") local bot_spawn = SpawnEntityFromTable("prop_dynamic", { angles = "0 0 0" DisableBoneFollowers = "0" model = "models/props_mvm/robot_spawnpoint.mdl" modelscale = "1.0" skin = "0" solid = "0" spawnflags = "0" targetname = "bot_controller_prop" origin = "480 3072 -63" DefaultAnim = "idle" }) for (local bomb; bomb = FindByClassname(bomb, "item_teamflag");) { bomb.SetModelSimple("models/props_halloween/flask_tub.mdl") bomb.SetModelScale(5, 0) } bombpath_relay_ent.AcceptInput("Trigger", "", null, null) no_rain_relay_ent.AcceptInput("Trigger", "", null, null) SetSkyboxTexture("sky_halloween") } // utility funcs RemovePlayerWearables = function(player) { for (local wearable = player.FirstMoveChild(); wearable != null; wearable = wearable.NextMovePeer()) { if (wearable.GetClassname() == "tf_wearable") wearable.Destroy() } return } GetItemId = function(item) { return GetPropInt(item, STRING_NETPROP_ITEMDEF) } GiveWeapon = function(player, className, itemID) { if (typeof itemID == "string" && className == "tf_wearable") { CTFBot.GenerateAndWearItem.call(player, itemID) return } local weapon = CreateByClassname(className) SetPropInt(weapon, STRING_NETPROP_ITEMDEF, itemID) SetPropBool(weapon, "m_AttributeManager.m_Item.m_bInitialized", true) SetPropBool(weapon, "m_bValidatedAttachedEntity", true) weapon.SetTeam(player.GetTeam()) DispatchSpawn(weapon) // remove existing weapon in same slot for (local i = 0; i < SLOT_COUNT; i++) { local heldWeapon = GetPropEntityArray(player, "m_hMyWeapons", i) if (heldWeapon == null || heldWeapon.GetSlot() != weapon.GetSlot()) continue heldWeapon.Destroy() SetPropEntityArray(player, "m_hMyWeapons", null, i) break } player.Weapon_Equip(weapon) player.Weapon_Switch(weapon) return weapon } ReplacePlayerCosmetics = function(victim, player, removePlayerHat = false) { player.ValidateScriptScope() local player_scope = player.GetScriptScope() ///running .kill causes issues with .NextMovePeer for (local wearable = player.FirstMoveChild(); wearable != null; wearable = wearable.NextMovePeer()) { if (wearable.GetClassname() == "tf_wearable") { EntFireByHandle(wearable, "Kill", "", -1, null, null) } } //get the cosmetic of victim and add them to player for (local wearable = victim.FirstMoveChild(); wearable != null; wearable = wearable.NextMovePeer()) { if (wearable.GetClassname() == "tf_wearable_demoshield") { printl("found shield") local base_entity = CreateByClassname(wearable.GetClassname()) local hat_id = GetPropInt(wearable, "m_AttributeManager.m_Item.m_iItemDefinitionIndex") SetPropInt(base_entity, "m_AttributeManager.m_Item.m_iItemDefinitionIndex", hat_id) SetPropBool(base_entity, "m_AttributeManager.m_Item.m_bInitialized", true) base_entity.SetTeam(player.GetTeam()) base_entity.DispatchSpawn() base_entity.SetOwner(player) EntFireByHandle(base_entity, "SetParent", "activator", -1, player, player) GiveWeapon(player, wearable.GetClassname(), hat_id) } if (wearable.GetClassname() == "tf_wearable") { local new_hat_model = wearable.GetModelName() local base_entity = CreateByClassname("tf_weapon_parachute") local hat_id = GetPropInt(wearable, "m_AttributeManager.m_Item.m_iItemDefinitionIndex") SetPropInt(base_entity, "m_AttributeManager.m_Item.m_iItemDefinitionIndex", 1101) SetPropBool(base_entity, "m_AttributeManager.m_Item.m_bInitialized", true) base_entity.SetTeam(player.GetTeam()) base_entity.DispatchSpawn() player.Weapon_Equip(base_entity) local new_hat = NetProps.GetPropEntity(base_entity, "m_hExtraWearable") base_entity.Kill() NetProps.SetPropInt(new_hat, "m_AttributeManager.m_Item.m_iItemDefinitionIndex", hat_id) // refreshes econ item to update the new itemID NetProps.SetPropBool(new_hat, "m_AttributeManager.m_Item.m_bInitialized", true) new_hat.DispatchSpawn() new_hat.SetModelSimple(new_hat_model) player_scope.cosmetics_to_remove.append(new_hat) } } } InButton = function(player, button) { return (GetPropInt(player, "m_nButtons") & button) } SilentKillPlayer = function(player) { NetProps.SetPropInt(player, "m_iObserverLastMode", 5) local team = player.GetTeam() NetProps.SetPropInt(player, "m_iTeamNum", 1) player.DispatchSpawn() NetProps.SetPropInt(player, "m_iTeamNum", TEAM_SPECTATOR) } ForceChangeClass = function(player, classindex = 1) { player.SetPlayerClass(classindex); SetPropInt(player, "m_Shared.m_iDesiredPlayerClass", classindex); player.ForceRegenerateAndRespawn(); } ForceChangeClassNoRespawn = function(player, classindex = 1) { player.SetPlayerClass(classindex); SetPropInt(player, "m_Shared.m_iDesiredPlayerClass", classindex); } PrintTable = function(table) { if (table == null) return; this.DoPrintTable(table, 0) } DoPrintTable = function(table, indent) { local line = "" for (local i = 0; i < indent; i++) { line += " " } line += typeof table == "array" ? "[" : "{"; ClientPrint(null, 2, line) indent += 2 foreach(k, v in table) { line = "" for (local i = 0; i < indent; i++) { line += " " } line += k.tostring() line += " = " if (typeof v == "table" || typeof v == "array") { ClientPrint(null, 2, line) this.DoPrintTable(v, indent) } else { try { line += v.tostring() } catch (e) { line += typeof v } ClientPrint(null, 2, line) } } indent -= 2 line = "" for (local i = 0; i < indent; i++) { line += " " } line += typeof table == "array" ? "]" : "}"; ClientPrint(null, 2, line) } PlayerCleanup = function(player) { foreach (key, ent in Player_Cleanup_Table) { // ensure that when we call the func, we are cleaning the correct player if (ent != player) { continue; } //printl("Cleaning: " + ent) player.ValidateScriptScope() local scope = player.GetScriptScope() if (scope.len() <= 5) return local ignore_table = { "self" : null, "__vname" : null, "__vrefs" : null }; foreach (think, v in scope) { if (!(think in ignore_table)) { //printl("Deleted Think: " + scope[think]) delete scope[think] } } // Remove player entry by key Player_Cleanup_Table.remove(key) //PrintTable(Player_Cleanup_Table) break; } } Cleanup = function() { for (local player; player = FindByClassname(player, "player");) { PlayerCleanup(player) } // keep this at the end delete ::playableRobot } // mandatory events OnGameEvent_recalculate_holidays = function(_) { if (GetRoundState() == 3) { Cleanup() } } OnGameEvent_mvm_wave_complete = function(_) { Cleanup() } //Thinks PlayerControlledRobot = function() { local player_class = self.GetPlayerClass() local active_wep = self.GetActiveWeapon() local origin = self.GetOrigin() if (typeof(attribs_player) == "null") { attribs_player = []; } if (typeof(attribs_weapon) == "null") { attribs_weapon = []; } //creating copy local possible_attribs = { "Blast radius decreased" : 1, "Reload time decreased" : 1, "airblast pushback scale" : 1, "bullets per shot bonus" : 1, "clip size bonus" : 1, "clip size penalty" : 1, "clip size upgrade atomic" : 1, "cloak consume rate increased" : 1, "damage bonus" : 1, "damage penalty" : 1, "effect bar recharge rate increased" : 1, "faster reload rate" : 1, "fire rate bonus" : 1, "fire rate penalty" : 1, "scattergun knockback mult" : 1, "ubercharge rate bonus" : 1, "Projectile speed increased" : 1 "move speed bonus" : 1 "damage force reduction" : 1 "airblast vulnerability multiplier" : 1 "airblast vertical vulnerability multiplier" : 1 "heal rate bonus" : 1 "rage giving scale" : 1 "increase buff duration" : 1 //additive "use large smoke explosion" : 0 "projectile spread angle penalty" : 0, "projectile penetration" : 0, "uber duration bonus" : 0, "damage causes airblast" : 0, "critboost on kill" : 0, "attack projectiles" : 0, "override footstep sound set" : 0 "health regen" : 0 }; function IsAttribInArray(array_to_check, attrib) { foreach (pair in array_to_check) { if (pair[0] == attrib) // Check if the attribute already exists { return true; } } return false; } foreach (attrib, value in possible_attribs) { if (active_wep == null || self == null) { break } local grab_attrib_value_wep = active_wep.GetAttribute(attrib, value); local grab_attrib_value_player = self.GetCustomAttribute(attrib, value); // Only add to attribs_weapon if the attribute isn't already present if (grab_attrib_value_wep != value && !IsAttribInArray(attribs_weapon, attrib)) { printl("We found " + grab_attrib_value_wep + " on the weapon! Add it to the array"); attribs_weapon.append([attrib, grab_attrib_value_wep]); } // Only add to attribs_player if the attribute isn't already present if (grab_attrib_value_player != value && !IsAttribInArray(attribs_player, attrib)) { printl("We found " + grab_attrib_value_player + " on the player! Add it to the array"); attribs_player.append([attrib, grab_attrib_value_player]); } } local hull_min = Vector(-100, -100, -100); // Bounding box min local hull_max = Vector(100, 100, 100); // Bounding box max // Check all players in the game for (local player; player = FindByClassname(player, "player");) { if (player.IsBotOfType(TF_BOT_FAKE_CLIENT)) { continue } // Ensure the player is on the same team if (player.GetTeam() == self.GetTeam()) { local bRemoveFromTable = false local player_pos = player.GetOrigin(); // AABB check to see if the player is within the defined bounds local is_within_bounds = ( player_pos.x >= (origin.x + hull_min.x) && player_pos.x <= (origin.x + hull_max.x) && player_pos.y >= (origin.y + hull_min.y) && player_pos.y <= (origin.y + hull_max.y) && player_pos.z >= (origin.z + hull_min.z) && player_pos.z <= (origin.z + hull_max.z) ); // Check if the player is within bounds if ((player && is_within_bounds) && (!(player_priority.find(player) != null))) { player_priority.append(player) } else if (player && !(is_within_bounds)) { bRemoveFromTable = true } foreach (key, ent in player_priority) { if (key == 0 && InButton(ent, IN_ATTACK3)) { // TODO // remove resist attributes by setting them to 1 // ensure miscs such as demo shields work // Fix wearables not working when using zombie souls/shirt cosmetics (?) local pilot_class = ent.GetPlayerClass() playableRobot.Player_ChangeClass_Table.append([ent, pilot_class]) PrintTable(playableRobot.Player_ChangeClass_Table) ClientPrint(ent, 4, "YOU GIANT") ForceChangeClass(ent, player_class) ReplacePlayerCosmetics(self, ent, true) ent.Teleport(true, self.GetOrigin() + Vector(0, 0, 5), true, self.EyeAngles(), false, Vector()) local giant_weapon = GiveWeapon(ent, active_wep.GetClassname(), GetItemId(active_wep)) foreach (attrib_pair in attribs_weapon) { local attrib = attrib_pair[0]; // First element is the attribute name local value = attrib_pair[1]; // Second element is the attribute value // Add the custom attribute to the entity giant_weapon.AddAttribute(attrib, value, -1); // Note: Parameters are swapped } foreach (attrib_pair in attribs_player) { local attrib = attrib_pair[0]; // First element is the attribute name local value = attrib_pair[1]; // Second element is the attribute value // Add the custom attribute to the entity ent.AddCustomAttribute(attrib, value, -1); // Note: Parameters are swapped } ent.AddCustomAttribute("max health additive bonus", self.GetMaxHealth() - ent.GetHealth(), -1) giant_weapon.AddAttribute("provide on active", 1, -1) giant_weapon.AddAttribute("disable weapon switch", 1, -1) ent.SetIsMiniBoss(true) ent.SetCustomModelWithClassAnimations(self.GetModelName()) ent.SetModelScale(self.GetModelScale(), 0) SilentKillPlayer(self) } if (bRemoveFromTable == true && ent == player) { player_priority.remove(key) } } } } } PlayerSpawn = function(player) { if (Player_Cleanup_Table.find(player) == null) { //printl("putting "+player+" in table") Player_Cleanup_Table.append(player) } player.ValidateScriptScope() local scope = player.GetScriptScope() if (!("PlayerThinkTable" in scope)) { //printl("Created think table") scope.PlayerThinkTable <- {} } scope.PlayerThinks <- function() { //printl("Running multiple Player Thinks!") foreach (name, func in scope.PlayerThinkTable) { func.call(scope); } return -1 } AddThinkToEnt(player, "PlayerThinks") if (player.IsBotOfType(TF_BOT_FAKE_CLIENT)) { if (player.HasBotTag("can_be_controlled")) { player.ValidateScriptScope() local scope = player.GetScriptScope() // Initial setup scope.attribs_weapon <- [] scope.attribs_player <- [] scope.player_priority <- [] scope.PrintTable <- PrintTable scope.DoPrintTable <- DoPrintTable scope.InButton <- InButton scope.GetItemId <- GetItemId scope.GiveWeapon <- GiveWeapon scope.ForceChangeClass <- ForceChangeClass scope.RemovePlayerWearables <- RemovePlayerWearables scope.SilentKillPlayer <- SilentKillPlayer scope.PlayerThinkTable.PlayerControlledRobot <- PlayerControlledRobot scope.ReplacePlayerCosmetics <- ReplacePlayerCosmetics local get_class_string = ["", "scout", "sniper", "soldier", "demo", "medic", "heavy", "pyro", "spy", "engineer", "civilian"] local get_cur_class = get_class_string[player.GetPlayerClass()] local invalid_giant_classes = ["Sniper", "Spy", "Medic", "Engineer", "Civilian"] local class_model_string = format("models/bots/%s_boss/bot_%s_boss.mdl", get_cur_class, get_cur_class) printl(class_model_string) PrecacheModel(class_model_string) player.SetCustomModelWithClassAnimations(class_model_string) } } if (!(player.IsBotOfType(TF_BOT_FAKE_CLIENT))) { scope.cosmetics_to_remove <- [] } } // Event Hooks OnGameEvent_player_death = function(params) { local player = GetPlayerFromUserID(params.userid) local scope = player.GetScriptScope() if (!(player.IsBotOfType(TF_BOT_FAKE_CLIENT))) { foreach (pair in playableRobot.Player_ChangeClass_Table) { local entity = pair[0] local entity_class = pair[1] if (player == entity) { player.AddCustomAttribute("voice pitch scale", 0, 3) ForceChangeClassNoRespawn(entity, entity_class) } } //ForceChangeClass(player, change_to_class) } PlayerCleanup(player) } OnGameEvent_player_spawn = function(params) { local player = GetPlayerFromUserID(params.userid) player.ValidateScriptScope() local playerscope = player.GetScriptScope() } OnGameEvent_post_inventory_application = function(params) { local player = GetPlayerFromUserID(params.userid) player.ValidateScriptScope() local playerscope = player.GetScriptScope() if (player && player.GetTeam() == TEAM_RED) { PlayerSpawn(player) } else if (player && player.GetTeam() == TEAM_BLU) { PlayerSpawn(player) } } OnScriptHook_OnTakeDamage = function(params) { local victim = params.const_entity local weapon = params.weapon local attacker = params.attacker local entity = params.inflictor local damage = params.damage local dmgtype = params.damage_type local dmg_special = params.damage_stats } }; for (local i = 1, player; i <= MaxClients(); i++) { if (player = PlayerInstanceFromIndex(i), player && player.GetTeam() == 2) { playableRobot.PlayerSpawn(player) } } __CollectGameEventCallbacks(playableRobot)