::respawnoverride <- SpawnEntityFromTable("trigger_player_respawn_override", { targetname = "respawnoverride", RespawnTime = 9999.0, spawnflags = 1 }) respawnoverride.SetSolid(2); respawnoverride.KeyValueFromString("mins", "-1 -1 -1") respawnoverride.KeyValueFromString("maxs", "1 1 1") //fix delayed starttouch crash function RespawnStartTouch() { return (activator == null) ? false : true; } function RespawnEndTouch() { return (activator == null) ? false : true; } respawnoverride.ValidateScriptScope(); respawnoverride.GetScriptScope().InputStartTouch <- RespawnStartTouch; respawnoverride.GetScriptScope().Inputstarttouch <- RespawnStartTouch; respawnoverride.GetScriptScope().InputEndTouch <- RespawnEndTouch; respawnoverride.GetScriptScope().Inputendtouch <- RespawnEndTouch; // function PlayRobotSounds(bot) // { // } local w3support = [] for (local support; support = FindByName(support, "boss_fight_support");) w3support.append(support) ::ApplyGlobalBotAttributes <- function(bot) { // bot.AddCustomAttribute("voice pitch scale", 0.55, -1); bot.AddCustomAttribute("voice pitch scale", 0.0, -1); bot.AddCustomAttribute("cannot pick up intelligence", 1 , -1); // first bot spawn is still given bomb before this attrib is applied bot.AddCustomAttribute("health from packs decreased", 0 , -1); bot.AddCustomAttribute("damage force reduction", 0.001 , -1); AddAttributeToLoadout(bot, "maxammo primary increased", 999) AddAttributeToLoadout(bot, "maxammo secondary increased", 999) AddAttributeToLoadout(bot, "health from packs decreased", 0); AddAttributeToLoadout(bot, "ammo regen", 999); AddAttributeToLoadout(bot, "crit mod disabled hidden", 0); SetPropIntArray(bot, "m_iAmmo", 99999, SLOT_PRIMARY+1) SetPropIntArray(bot, "m_iAmmo", 99999, SLOT_SECONDARY+1) if (!bot.HasBotAttribute(DISABLE_DODGE)) bot.AddBotAttribute(DISABLE_DODGE); //strip all unused bot weapons to reduce edicts //don't strip w1 conch giant or passive weapon hack demos, only their melees // if (bot.GetPlayerClass() == TF_CLASS_DEMOMAN || (bot.GetPlayerClass() == TF_CLASS_SOLDIER && (bot.IsMiniBoss() || GetItemIndex(bot.GetActiveWeapon()) == ID_ROCKET_JUMPER))) return; // EntFireByHandle(bot, "RunScriptCode", "try StripEverythingExcept(self, self.GetActiveWeapon().GetSlot(), false) catch(e) printl(e);", -1, null, null); //errors when we end the wave } ::W3Boss <- { function MorphIntoClass(bot, playerclass = -1, morphduration = 2.0) { bot.AddCondEx(TF_COND_STEALTHED_USER_BUFF_FADING, morphduration, null) if (playerclass == -1) playerclass = RandomInt(2, 5) switch(bot.GetPlayerClass()) { case TF_CLASS_SOLDIER: break case TF_CLASS_PYRO: break case TF_CLASS_DEMOMAN: break case TF_CLASS_HEAVYWEAPONS: break } } } ::W3BotTeleport <- function(bot) { if (bot.GetPlayerClass() == TF_CLASS_SNIPER) return //hardcode scout out of this if (bot.HasBotTag("boss_support")) return local isboss = bot.HasBotTag("boss") local origin = Vector() isboss ? origin = FindByName(null, "boss_fight_dude").GetOrigin() : origin = w3support[RandomInt(0, w3support.len() - 1)].GetOrigin() isboss ? bot.SetOrigin(origin) : bot.TakeDamage(INT_MAX, DMG_GENERIC, null) if (!isboss) return EntFireByHandle(bot, "RunScriptCode", "StunBoss(self)", -1, null, null) EntFireByHandle(bot, "RunScriptCode", "self.AddCond(TF_COND_PHASE)", 1, null, null) DoEntFire("boss_beam_target", "SetParent", "!activator", -1, bot, bot) DoEntFire("boss_beam_target", "SetParentAttachment", "back_lower", -1, bot, bot) EntFire("boss_fight_support", "Disable") } ::CFEvents <- { function OnGameEvent_player_spawn(params) { local player = GetPlayerFromUserID(params.userid); player.ValidateScriptScope(); local scope = player.GetScriptScope(); //stuff we want to put in player scope local items = { weapontable = {} thinktable = {} lastannouncement = "" maxammo = [] sequencearray = [] cooldown = 0 cooldowntime = 0 lastreload = 0 drainedamount = 0 maxmetal = 0 hinted = false ccactive = false dfdrained = false ammodrained = false fflooping = false } foreach (k,v in items) if (!(k in scope)) scope[k] <- v local itemsforcereset = { paulingspeaking = false } foreach(k, v in itemsforcereset) scope[k] <- v local buildings = [-1, array(2), -1] if (player.GetPlayerClass() == TF_CLASS_ENGINEER && !(buildings in scope)) scope.buildings <- buildings; if (params.team == TF_TEAM_PVE_INVADERS && player.GetScriptThinkFunc() != "ReverseTeams") AddThinkToEnt(player, "ReverseTeams"); } //THE BIG ONE //this runs slow in pre-round, a non-issue but would be nice to optimize. w2hint = false wave3thisshouldntbehere = false function OnGameEvent_post_inventory_application(params) { //hack if (!w2hint && __wavenum == 2) { w2hint = true; PaulingAnnouncement("Nice work, you made it to RED's base|Stock up on upgrades, looks like you'll need them|Still no signs of life anywhere, what the hell was RED doing?", PAULING_SUCCESS); } local player = GetPlayerFromUserID(params.userid); //player stuff if (!IsPlayerABot(player)) { local buildings = [-1, array(2), -1]; local scope = player.GetScriptScope(); if (player.GetPlayerClass() == TF_CLASS_ENGINEER && !(buildings in scope)) scope.buildings <- buildings; //team switch if (player.GetTeam() != TF_TEAM_PVE_INVADERS && player in playertable) { ChangePlayerTeamMvM(player, TF_TEAM_PVE_INVADERS); player.ForceRespawn(); } else if (!(player in playertable) && player.GetTeam() != TEAM_SPECTATOR) ChangePlayerTeamMvM(player, TEAM_SPECTATOR); if (player.GetScriptThinkFunc() != "ReverseTeams") AddThinkToEnt(player, "ReverseTeams"); EntFireByHandle(player, "RunScriptCode", "SetPropBool(self, `m_bGlowEnabled`, false)", -1, null, null); EntFireByHandle(player, "RunScriptCode", "SetPropBool(self, `m_bGlowEnabled`, true)", 0.1, null, null); //we already stripped everything if (!player || (GetWeaponInSlot(player, SLOT_PRIMARY) == null && GetWeaponInSlot(player, SLOT_SECONDARY) == null)) return; //override respawn times for players EntFireByHandle(respawnoverride, "StartTouch", "", -1, player, player); // EntFireByHandle(__clientcommand, "Command", "r_screenoverlay colorcorrection/downpour", -1, player, player); // local cc = FindByName(null, format("__cc%d", player.entindex())); // if (cc == null) cc = SpawnEntityFromTable("color_correction", { // // origin = player.GetOrigin() + Vector(0, 0, 40) // targetname = format("__cc%d", player.entindex()), // filename = "materials/colorcorrection/downpour.raw", // origin = player.GetOrigin() // spawnflags = 2, // maxweight = 0.4, // minfalloff = 1, // maxfalloff = 1, // fadeInDuration = 3, // fadeOutDuration = 3 // }) // SetPropFloat(cc, "m_flCurWeight", 0.0) player.AddCustomAttribute("deploy time decreased", INT_MIN, 0.1); player.AddCustomAttribute("reload time increased hidden", FLT_SMALL, 1); if (InUpgradeZone(player) && scope.weapontable.len()) { //fuck it just do this here. if (__wavenum == 3 && !wave3thisshouldntbehere) { DoEntFire("gamerules", "RunScriptCode", "PaulingAnnouncement(`Heads up, I'm seeing movement nearby|Upgrade fast, they're close`)", 10, null, null); DoEntFire("playerspawnred*", "Enable", "", 15, null, null); wave3thisshouldntbehere = true } //doesn't work foreach (k, v in scope.weapontable) { if (k == ID_FAMILY_BUSINESS || k == ID_RESERVE_SHOOTER || k == ID_PRETTY_BOYS_POCKET_PISTOL || k == ID_WINGER) { switch(player.GetPlayerClass()) { case TF_CLASS_SOLDIER: SetItemIndex(GetWeaponInSlot(player, SLOT_SECONDARY), ID_SHOTGUN_SOLDIER); break; case TF_CLASS_PYRO: SetItemIndex(GetWeaponInSlot(player, SLOT_SECONDARY), ID_SHOTGUN_PYRO); // printl(GetItemIndex(GetWeaponInSlot(player, SLOT_SECONDARY)) + " : " + v[0] + " : " + v[1]) break; case TF_CLASS_HEAVYWEAPONS: if (k != ID_RESERVE_SHOOTER) break; SetItemIndex(GetWeaponInSlot(player, SLOT_SECONDARY), ID_SHOTGUN_HWG); break; case TF_CLASS_ENGINEER: if (startswith(v[0], "tf_weapon_shotgun")) SetItemIndex(GetWeaponInSlot(player, SLOT_PRIMARY), ID_SHOTGUN_PRIMARY); else SetItemIndex(GetWeaponInSlot(player, SLOT_SECONDARY), ID_PISTOL); break; } } } //give players their loadout back every upgrade (upgrade station regenerates players and deletes their loadout) StripEverythingExcept(player, SLOT_MELEE); GiveLastKnownLoadout(player); local ammoslots = [] foreach (i, m in scope.maxammo) ammoslots.append(GetAmmoInSlot(player, i)) // foreach(i, a in ammoslots) // printl(a) SetPlayerWeaponInfo(player, GetPlayerWeaponInfo(player)[0], ammoslots, GetReserveMetal(player)); } // if (GetPropInt(player, "m_Shared.m_iDesiredPlayerClass") == TF_CLASS_HEAVYWEAPONS && player.GetPlayerClass() != TF_CLASS_HEAVYWEAPONS) // SetPropInt(player, "m_Shared.m_iDesiredPlayerClass", player.GetPlayerClass()) else { local scope = player.GetScriptScope(); StripEverythingExcept(player, SLOT_MELEE); if ("numgascans" in scope) delete scope.numgascans try { if (scope.weapontable.len() > 1) { if (__wavenum == 1 && !__wavestart) scope.weapontable.clear(); else { EntFireByHandle(player, "RunScriptCode", "GiveLastKnownLoadout(self)", -1, null, null); EntFireByHandle(player, "RunScriptCode", "self.GetActiveWeapon().SetClip1(self.GetActiveWeapon().GetMaxClip1())", -1, null, null); EntFireByHandle(player, "RunScriptCode", "SetReserveAmmo(self.GetActiveWeapon(), self.GetScriptScope().maxammo[0], SLOT_PRIMARY);", 0.1, null, null) EntFireByHandle(player, "RunScriptCode", "SetReserveAmmo(self.GetActiveWeapon(), self.GetScriptScope().maxammo[1], SLOT_SECONDARY)", 0.1, null, null) } // SetReserveAmmo(player.GetActiveWeapon(), scope.maxammo[0], SLOT_PRIMARY); // SetReserveAmmo(player.GetActiveWeapon(), scope.maxammo[1], SLOT_SECONDARY); } } catch (err) { printl(err) } } //weapon attribs local specialammo = [TF_CLASS_SCOUT, TF_CLASS_SNIPER, TF_CLASS_MEDIC, TF_CLASS_ENGINEER] if (specialammo.find(player.GetPlayerClass()) != null) EntFireByHandle(player, "RunScriptCode", "self.AddCustomAttribute(`maxammo primary reduced`, 0.5, 0)", -1, null, null); else if (player.GetPlayerClass() == TF_CLASS_PYRO) EntFireByHandle(player, "RunScriptCode", "self.AddCustomAttribute(`maxammo primary reduced`, 0.375, 0)", -1, null, null); else EntFireByHandle(player, "RunScriptCode", "self.AddCustomAttribute(`maxammo primary reduced`, 0.25, 0)", -1, null, null); if (player.GetPlayerClass() == TF_CLASS_DEMOMAN) EntFireByHandle(player, "RunScriptCode", "self.AddCustomAttribute(`maxammo secondary reduced`, 0.25, 0)", -1, null, null); if (player.GetPlayerClass() == TF_CLASS_MEDIC) EntFireByHandle(player, "RunScriptCode", "self.AddCustomAttribute(`mad milk syringes`, 1, 0)", -1, null, null); if (player.GetPlayerClass() == TF_CLASS_ENGINEER) EntFireByHandle(player, "RunScriptCode", "GetWeaponInSlot(self, SLOT_MELEE).AddAttribute(`upgrade rate decrease`, 0.0, -1); GetWeaponInSlot(self, SLOT_MELEE).ReapplyProvision()", -1, null, null); // if (player.GetPlayerClass() == TF_CLASS_ENGINEER || player.GetPlayerClass() == TF_CLASS_SPY) // { // ClientPrint(player, HUD_PRINTCENTER, "THIS CLASS IS TEMPORARILY DISABLED"); // ForceChangeClass(player, RandomInt(1, 9)); // } return; } //bot stuff local bot = player //no blood (does not work?) // printl(GetPropInt(bot, "m_bloodColor")) // 0 for red SetPropInt(bot, "m_bloodColor", -1); //remove romevision cosmetics from every bot StripRomevision(bot); if (bot.GetTeam() != TF_TEAM_PVE_DEFENDERS) { //tags r fuk if (bot.HasBotTag("bluebot")) return; bot.ForceChangeTeam(TF_TEAM_PVE_DEFENDERS, true); if (bot.GetPlayerClass() > TF_CLASS_SNIPER && bot.GetPlayerClass() < TF_CLASS_SPY) EntFireByHandle(bot, "RunScriptCode", "SetModels(self, self.GetPlayerClass())", -1, null, null); //add a delay, otherwise models are applied before giant stats } EntFireByHandle(bot, "RunScriptCode", @" if (self.HasBotTag(`generator1`) || self.HasBotTag(`generator2`) || self.HasBotTag(`generator3`)) self.TakeDamage(self.GetMaxHealth() - 1, DMG_GENERIC, self) ", -1, null, null) EntFireByHandle(bot, "RunScriptCode", @" if (self.HasBotTag(`generator1`) || self.HasBotTag(`generator2`) || self.HasBotTag(`generator3`)) { self.GetScriptScope().GenBotThink <- function() { if (self.GetHealth() >= self.GetMaxHealth()) self.TakeDamage(INT_MAX, DMG_GENERIC, self) } AddThinkToEnt(self, `GenBotThink`) } ", 1, null, null) EntFireByHandle(bot, "RunScriptCode", "ApplyGlobalBotAttributes(self)", 1, null, null); // if (bot.HasBotTag("bot_gardener")) if (GetItemIndex(bot.GetActiveWeapon()) == ID_ROCKET_JUMPER) { bot.ValidateScriptScope(); bot.GetScriptScope().MarketGardenerThink <- MarketGardenerThink; AddThinkToEnt(bot, "MarketGardenerThink") } // ApplyGlobalBotAttributes(bot) if (__wavenum == 3 && __bombdeployed) EntFireByHandle(bot, "RunScriptCode", "W3BotTeleport(self)", 1, null, null) } //player death stuff firstdeath = false function OnGameEvent_player_death(params) { local player = GetPlayerFromUserID( params.userid ); local scope = player.GetScriptScope(); scope.ccactive = false; if (FindByName(null, format("__cc%d", player.entindex())) != null) FindByName(null, format("__cc%d", player.entindex())).Kill(); if (IsPlayerABot(player)) { SetPropString(player, "m_iszScriptThinkFunction", ""); EntFireByHandle(player, "RunScriptCode", "self.ForceChangeTeam(TEAM_SPECTATOR, false)", 1, null, null); return; } //forcibly move bots to spectator // IsPlayerABot(player) ? EntFireByHandle(player, "RunScriptCode", "self.ForceChangeTeam(TEAM_SPECTATOR, false)", 1, null, null) : EntFireByHandle(player, "RunScriptCode", "self.ForceChangeTeam(TEAM_SPECTATOR, false)", -1, null, null) //spawn respawn crystals on player death if (__wavestart && !firstdeath) { // DoEntFire("startcrystals", "Trigger", "", -1, null, null); ClientPrint(null, HUD_PRINTTALK, "\x071337ADRespawn crystals spawning soon...\x07") DoEntFire("gamerules", "CallScriptFunction", "GetValidCrystalSpots", 20, null, null); firstdeath = true; return; } // player.GetScriptScope().weapontable.clear(); // player.ForceRespawn(); } function OnGameEvent_player_team(params) { local player = GetPlayerFromUserID(params.userid) if (!IsPlayerABot(player) && params.team == TEAM_SPECTATOR && !__wavestart) ChangePlayerTeamMvM(player, TF_TEAM_PVE_INVADERS) } //wipe loadout on class change function OnGameEvent_player_changeclass(params) { if (IsPlayerABot(GetPlayerFromUserID(params.userid))) return; local player = GetPlayerFromUserID(params.userid); local scope = player.GetScriptScope() try scope.weapontable.clear() catch(err) printl(err); EntFireByHandle(player, "RunScriptCode", "StripEverythingExcept(self, SLOT_MELEE)", -1, null, null); } function OnGameEvent_player_say(params) { local player = GetPlayerFromUserID(params.userid) if (params.text == ".pauling" && !player.GetScriptScope().paulingspeaking) PaulingAnnouncement(player.GetScriptScope().lastannouncement, PAULING_GAG, player) } function OnGameEvent_teamplay_round_start(params) { foreach (player, userid in playertable) { if (player == null) continue; if (player.GetTeam() != TF_TEAM_PVE_INVADERS) { ChangePlayerTeamMvM(player, TF_TEAM_PVE_INVADERS); player.ForceRespawn(); } } local wind = Entities.FindByClassname(null, "env_wind"); RemoveOutput(wind, "OnGustStart", "windshuffle", "PickRandomShuffle", ""); RemoveOutput(wind, "OnGustStart", "shakeit2", "StartShake", ""); RemoveOutput(wind, "OnGustEnd", "shakeit2", "StopShake", ""); } function OnGameEvent_mvm_begin_wave(params) { WaveStart() } //forcibly move red bots back to spectator function OnGameEvent_mvm_wave_failed(params) { foreach (bot, userid in bottable) try bot.ForceChangeTeam(TEAM_SPECTATOR, true) catch(err) printl(err); } function OnGameEvent_mvm_wave_complete(params) { SetPropString(__startrelay, "m_iszScriptThinkFunction", ""); __waveended = false; } //manually set engi ammo for buildings function OnGameEvent_player_builtobject(params) { local OBJ_DISPENSER = 0; local OBJ_TELEPORTER = 1; local OBJ_SENTRYGUN = 2; local player = GetPlayerFromUserID(params.userid); local scope = player.GetScriptScope(); local curmetal = GetReserveMetal(player); // don't drain metal if this buildings entindex exists in the players scope if (scope.buildings.find(params.index) != null || scope.buildings[1].find(params.index) != null) return; // add entindexes to player scope if (params.object == OBJ_TELEPORTER) if (GetPropInt(EntIndexToHScript(params.index), "m_iTeleportType") == TTYPE_ENTRANCE) scope.buildings[1][0] = params.index; else scope.buildings[1][1] = params.index; else scope.buildings[params.object] = params.index; switch(params.object) { case OBJ_DISPENSER: SetReserveMetal(player, curmetal - 100); break; case OBJ_TELEPORTER: if (HasItem(player, "tf_weapon_wrench", ID_EUREKA_EFFECT)) SetReserveMetal(player, curmetal - 25); else SetReserveMetal(player, curmetal - 50); break; case OBJ_SENTRYGUN: if (HasItem(player, "tf_weapon_robot_arm", ID_GUNSLINGER)) SetReserveMetal(player, curmetal - 100); else SetReserveMetal(player, curmetal - 130); break; } if (GetReserveMetal(player) < 0) EntFireByHandle(player, "RunScriptCode", "SetReserveMetal(player, 0)", -1, null, null); } function OnGameEvent_object_destroyed(params) { try local player = GetPlayerFromUserID(params.userid) catch(err) return; //map-placed/unowned sentries will error here try local scope = player.GetScriptScope() catch(err) return; //map-placed/unowned sentries will error here if (scope.buildings.find(params.index) != null) scope.buildings.remove(scope.buildings.find(params.index)) if (scope.buildings[1].find(params.index) != null) scope.buildings[1].remove(scope.buildings[1].find(params.index)) } function OnScriptHook_OnTakeDamage(params) { local player = params.attacker, victim = params.const_entity; // //gib bots on explosive/crit dmg, doesn't work // if (!victim.IsMiniBoss() && (params.damage_type & DMG_CRITICAL || params.damage_type & DMG_BLAST)) // { // victim.SetModelScale(1.00000001, 0.0); // // EntFireByHandle(victim, "CallScriptFunction", "dmg", -1, null, null); //wait 1 frame // return; // } //re-enable headshots for snipers and ambassador if (!player.IsPlayer() || !victim.IsPlayer() || IsPlayerABot(player)) return; //check if non-bot victim if (player.GetPlayerClass() != TF_CLASS_SPY && player.GetPlayerClass() != TF_CLASS_SNIPER) return; //check if we're spy/sniper if (GetPropInt(victim, "m_LastHitGroup") != HITGROUP_HEAD) return; //check for headshot if (player.GetPlayerClass() == TF_CLASS_SNIPER && (player.GetActiveWeapon().GetSlot() == SLOT_SECONDARY || GetItemIndex(player.GetActiveWeapon()) == ID_SYDNEY_SLEEPER)) return; //ignore sydney sleeper and SMGs if (player.GetPlayerClass() == TF_CLASS_SPY && GetItemIndex(player.GetActiveWeapon()) != ID_AMBASSADOR) return; //ambassador only // params.damage_type = params.damage_type | DMG_CRITICAL; //add crit bit, DMG_USE_HITLOCATIONS does not work params.damage_type | (DMG_USE_HITLOCATIONS|DMG_CRITICAL) params.damage_stats = TF_DMG_CUSTOM_HEADSHOT return; } }; __CollectGameEventCallbacks(CFEvents);