const CFIVE_MAXPLAYERS = 6; const DEBUG = false; ::overflow <- [] ::playertable <- {}; ::bottable <- {} ::CountAllPlayers <- function() { return playertable.len(); } local roundwin = null; for (local win; win = FindByClassname(win, "game_round_win");) if (win.GetTeam() == TF_TEAM_PVE_INVADERS) { roundwin = win; break; } ::CountAlivePlayers <- function(printout = false) { if (!__wavestart || CountAllPlayers() == 0) return; local playersalive = 0; foreach (player, userid in playertable) { //bug or something //player.GetHealth() always returns 1 even if the player is dead? //we shitfix this by not allowing player to survive at 1hp in the player_hurt event lol if (player == null || IsPlayerDead(player)) continue; playersalive++; } if (printout) { ClientPrint(null, HUD_PRINTTALK, format("Players Alive: %d", playersalive)); printf("Players Alive: %d\n", playersalive) } if (CountAllPlayers() < playersalive) playersalive == CountAllPlayers(); return playersalive; } // this is dumb, but used so post_inventory_application player counter can catch the first player on first mission load SpawnEntityFromTable("prop_dynamic", {targetname = "locker_model", model = "models/props_gameplay/resupply_locker.mdl", parentname = "tempregen", rendermode = 10}) local tempregen = SpawnEntityFromTable("func_regenerate", { targetname = "tempregen" origin = Vector(1954.000000, -4800.000000, 333.031311) associatedmodel = "locker_model" TeamNum = 0 }) tempregen.SetSolid(2) tempregen.SetSize(Vector(-600, -600, -600), Vector(600, 600, 600)) if (__wavenum == 2) tempregen.SetOrigin(Vector(-3012.770020, -993.942993, 84.031319)) if (__wavenum == 3) tempregen.SetOrigin(Vector(3451, -1177, -61)) ::Counter <- { CountAllPlayers = function() { return playertable.len(); }, //shitfix //params.health sometimes still says 1hp despite the player being dead //we check if the player has 1hp and just kill them to work around this lol function OnGameEvent_player_hurt(params) { if (IsPlayerABot(GetPlayerFromUserID(params.userid)) || params.health > 1) return; local player = GetPlayerFromUserID(params.userid) if (params.health == 1) player.TakeDamage(INT_MAX, DMG_GENERIC, player); } //put bots in their own array function OnGameEvent_teamplay_round_start(params) { for (local i = 1; i <= MAX_CLIENTS; i++) { local player = PlayerInstanceFromIndex(i) if (player == null || !IsPlayerABot(player)) continue; bottable[player] <- GetPlayerUserID(player) } } //check if the wave somehow started when everyone disconnected function OnGameEvent_mvm_begin_wave(params) { DoEntFire("tempregen", "KillHierarchy", "", -1, null, null); if (CountAlivePlayers(true) == 0) DoEntFire("win_bots", "RoundWin", "", -1, null, null); } //add players to the array //this only checks the playercount, playersalive is handled in the CountAlivePlayers() function function OnGameEvent_post_inventory_application(params) { // GetEntityOutputs(FindByName(null, "PT_SWITCHBUTTON2"), "OnPressed") local player = GetPlayerFromUserID(params.userid); // if (IsPlayerABot(player) || player in playertable || playertable.len()) return; // if (playertable.len() > CFIVE_MAXPLAYERS) // overflow.append(player); // else // playertable.append(player); IsPlayerABot(player) ? bottable[player] <- params.userid : playertable[player] <- params.userid player.AddCustomAttribute("deploy time decreased", FLT_SMALL, 0.1); player.RemoveCustomAttribute("health drain"); } function OnGameEvent_player_disconnect(params) { local player = GetPlayerFromUserID(params.userid); if (player in playertable) delete playertable[player] //force fail the wave when there's 0 players if (CountAllPlayers() == 0 && __wavestart) { DoEntFire("win_bots", "RoundWin", "", -1, null, null); // DoEntFire("respawnoverride", "DisableAndEndTouch", "", -1, null, null); return; } printf("Players: %d\n", CountAllPlayers()); } function OnGameEvent_player_death(params) { //ignore bots and dead ringer (dead ringer triggers this event but player health is still > 1) local player = GetPlayerFromUserID(params.userid) if (player == null || IsPlayerABot(player) || player.GetHealth() > 1) return; //force respawn in pre-round to avoid fucking up the counter as soon as the wave starts //still technically possible, but harder to time if (!__wavestart) { DoEntFire("gamerules", "RunScriptCode", format("try GetPlayerFromUserID(%d).ForceRespawn() catch(err) return;", params.userid), -1, null, null); return; } DoEntFire("gamerules", "RunScriptCode", "if (CountAlivePlayers(true) == 0) { DoEntFire(`win_bots`, `RoundWin`, ``, -1, null, null); StunBots(); }", -1, null, null); } }; __CollectGameEventCallbacks(Counter) // printl("Player Counter Loaded")