--Code created by Zwataketa and enhanced by RAYTEK-- local autospec = CV_RegisterVar{ name = "autospec", defaultvalue = "On", PossibleValue = CV_OnOff, } local autospec_timer = CV_RegisterVar{ name = "autospec_timer", defaultvalue = 5, PossibleValue = CV_Unsigned, } local autospec_timer_level_completed = CV_RegisterVar{ name = "autospec_timer_level_completed", defaultvalue = 2, PossibleValue = CV_Unsigned, } local autospec_switch_timer = CV_RegisterVar{ name = "autospec_switch_timer", defaultvalue = 10, PossibleValue = CV_Natural, } local autospec_afk_timer = CV_RegisterVar{ name = "autospec_afk_timer", defaultvalue = 5, PossibleValue = CV_Natural, } local autospec_timer_remaining = autospec_timer.value local switch_timer_remaining = autospec_switch_timer.value local players_afk_timer_table = {} -- table to store the afk timer for each player. if timer is 0, player is considered afk COM_AddCommand('autospec_activate', function(player) autospec.value = true autospec_timer_remaining = 0 switch_timer_remaining = autospec_switch_timer.value end) COM_AddCommand('autospec_toggle', function(player) autospec.value = not autospec.value autospec_timer_remaining = 0 switch_timer_remaining = autospec_switch_timer.value end) local function arrayContainsValue(t,v) if not t then return false end for i = 1, #t do if t[i] == v then return true end end return false end local function playerHasCompletedLevel(player) -- check if a player has completed the level return (player.exiting or (player.pflags & PF_FINISHED)) end local function isPlayerValid(player, excludedplayers) -- check if a player is valid to spectate return (player.playerstate == PST_LIVE and players_afk_timer_table[#player] and (not playerHasCompletedLevel(player)) and (not arrayContainsValue(excludedplayers, player))) end local function getValidPlayerTable() -- get a table of players that are valid to spectate local player_table = {} -- collected players for player in players.iterate do if isPlayerValid(player, {consoleplayer, displayplayer}) then -- exclude players : self, currently viewed, afk, dead, completed the level table.insert(player_table, player) end end return player_table end local function spectateRand() -- spectate a random player local player_table = getValidPlayerTable() if #player_table > 0 then displayplayer = player_table[P_RandomRange(1,#player_table)] end end local function playerAfkHandler(player) -- set players to afk if they don't move for a certain amount of time if not player.speed then -- player is not moving if players_afk_timer_table[#player] > 0 then players_afk_timer_table[#player] = $ - 1 end else -- player is moving players_afk_timer_table[#player] = autospec_afk_timer.value end end local function playerSpectateHandler() -- spectate a random player and switch players after a certain amount of time or if the currently spectated player become invalid if switch_timer_remaining == autospec_switch_timer.value or not isPlayerValid(displayplayer) then spectateRand() end if switch_timer_remaining == 0 then switch_timer_remaining = autospec_switch_timer.value else switch_timer_remaining = $ - 1 end end local function playerAutospecTimer(player) -- check if a player should spectate if not player.speed then -- player is not moving if autospec_timer_remaining > 0 then autospec_timer_remaining = $ - 1 end else -- player is moving if playerHasCompletedLevel(player) then -- player has completed the level, use a faster timer autospec_timer_remaining = autospec_timer_level_completed.value else -- player has not completed the level, use the default timer autospec_timer_remaining = autospec_timer.value end end end addHook("PlayerSpawn", function(player) players_afk_timer_table[#player] = autospec_afk_timer.value end) addHook("PlayerThink", function(player) if not autospec.value or (leveltime % TICRATE) != 0 then return end playerAfkHandler(player) if player == consoleplayer then playerAutospecTimer(player) if autospec_timer_remaining == 0 then playerSpectateHandler() -- start spectating a random player and switch players after a certain amount of time else switch_timer_remaining = autospec_switch_timer.value end end end)