#define AFK_WARNED 1 #define AFK_CRYOD 2 #define AFK_ADMINS_WARNED 3 SUBSYSTEM_DEF(afk) name = "AFK Watcher" wait = 300 flags = SS_BACKGROUND cpu_display = SS_CPUDISPLAY_LOW offline_implications = "Players will no longer be marked as AFK. No immediate action is needed." var/list/afk_players = list() // Associative list. ckey as key and AFK state as value var/list/non_cryo_antags /datum/controller/subsystem/afk/Initialize() if(GLOB.configuration.afk.warning_minutes <= 0 || GLOB.configuration.afk.auto_cryo_minutes <= 0 || GLOB.configuration.afk.auto_despawn_minutes <= 0) flags |= SS_NO_FIRE else non_cryo_antags = list(SPECIAL_ROLE_ABDUCTOR_AGENT, SPECIAL_ROLE_ABDUCTOR_SCIENTIST, SPECIAL_ROLE_WIZARD, SPECIAL_ROLE_WIZARD_APPRENTICE, SPECIAL_ROLE_NUKEOPS) /datum/controller/subsystem/afk/fire() var/list/toRemove = list() for(var/thing in GLOB.human_list) var/mob/living/carbon/human/H = thing if(!H?.ckey) // Useless non ckey creatures continue var/turf/T // Only players and players with the AFK watch enabled // No dead, unconcious, restrained, people without jobs or people on other Z levels than the station if(!H.client || !(H.client.prefs.toggles2 & PREFTOGGLE_2_AFKWATCH) || !H.mind || \ H.stat || H.restrained() || !H.job || !is_station_level((T = get_turf(H)).z)) // Assign the turf as last. Small optimization if(afk_players[H.ckey]) toRemove += H.ckey continue var/mins_afk = round(H.client.inactivity / 600) if(mins_afk < GLOB.configuration.afk.warning_minutes) if(afk_players[H.ckey]) toRemove += H.ckey continue if(!afk_players[H.ckey]) afk_players[H.ckey] = AFK_WARNED warn(H, "You are AFK for [mins_afk] minutes. You will be cryod after [GLOB.configuration.afk.auto_cryo_minutes] total minutes and fully despawned after [GLOB.configuration.afk.auto_despawn_minutes] total minutes. Please move or click in game if you want to avoid being despawned.") else var/area/A = T.loc // Turfs loc is the area if(afk_players[H.ckey] == AFK_WARNED) if(mins_afk >= GLOB.configuration.afk.auto_cryo_minutes && A.can_get_auto_cryod) if(A.fast_despawn) toRemove += H.ckey warn(H, "You have been despawned after being AFK for [mins_afk] minutes. You have been despawned instantly due to you being in a secure area.") log_afk_action(H, mins_afk, T, "despawned", "AFK in a fast despawn area") force_cryo_human(H) else if(!(H.mind.special_role in non_cryo_antags)) if(cryo_ssd(H)) H.create_log(MISC_LOG, "Put into cryostorage by the AFK subsystem") afk_players[H.ckey] = AFK_CRYOD log_afk_action(H, mins_afk, T, "put into cryostorage") warn(H, "You are AFK for [mins_afk] minutes and have been moved to cryostorage. \ After being AFK for another [GLOB.configuration.afk.auto_despawn_minutes] minutes you will be fully despawned. \ Please eject yourself (right click, eject) out of the cryostorage if you want to avoid being despawned.") else message_admins("[key_name_admin(H)] at ([get_area(T).name] [ADMIN_JMP(T)]) is AFK for [mins_afk] and can't be automatically cryod due to it's antag status: ([H.mind.special_role]).") afk_players[H.ckey] = AFK_ADMINS_WARNED else if(afk_players[H.ckey] != AFK_ADMINS_WARNED && mins_afk >= GLOB.configuration.afk.auto_despawn_minutes) log_afk_action(H, mins_afk, T, "despawned") warn(H, "You have been despawned after being AFK for [mins_afk] minutes.") toRemove += H.ckey force_cryo_human(H) removeFromWatchList(toRemove) /datum/controller/subsystem/afk/proc/warn(mob/living/carbon/human/H, text) to_chat(H, text) SEND_SOUND(H, sound('sound/effects/adminhelp.ogg')) if(H.client) window_flash(H.client) /datum/controller/subsystem/afk/proc/log_afk_action(mob/living/carbon/human/H, mins_afk, turf/location, action, info) log_admin("[key_name(H)] has been [action] by the AFK Watcher subsystem after being AFK for [mins_afk] minutes.[info ? " Extra info:" + info : ""]") /datum/controller/subsystem/afk/proc/removeFromWatchList(list/toRemove) for(var/C in toRemove) for(var/i in 1 to afk_players.len) if(afk_players[i] == C) afk_players.Cut(i, i + 1) break #undef AFK_WARNED #undef AFK_CRYOD #undef AFK_ADMINS_WARNED