diff --git a/code/__defines/subsystems.dm b/code/__defines/subsystems.dm index 4e333dac06..3778d0bba2 100644 --- a/code/__defines/subsystems.dm +++ b/code/__defines/subsystems.dm @@ -57,6 +57,7 @@ var/global/list/runlevel_flags = list(RUNLEVEL_LOBBY, RUNLEVEL_SETUP, RUNLEVEL_G #define INIT_ORDER_SKYBOX 30 #define INIT_ORDER_MAPPING 25 #define INIT_ORDER_DECALS 20 +#define INIT_ORDER_PING 18 #define INIT_ORDER_JOB 17 #define INIT_ORDER_ALARM 16 // Must initialize before atoms. #define INIT_ORDER_ATOMS 15 @@ -89,6 +90,7 @@ var/global/list/runlevel_flags = list(RUNLEVEL_LOBBY, RUNLEVEL_SETUP, RUNLEVEL_G #define FIRE_PRIORITY_NIGHTSHIFT 5 #define FIRE_PRIORITY_ORBIT 8 #define FIRE_PRIORITY_VOTE 9 +#define FIRE_PRIORITY_PING 9 #define FIRE_PRIORITY_AI 10 #define FIRE_PRIORITY_GARBAGE 15 #define FIRE_PRIORITY_ALARM 20 diff --git a/code/controllers/subsystems/ping.dm b/code/controllers/subsystems/ping.dm new file mode 100644 index 0000000000..4078028418 --- /dev/null +++ b/code/controllers/subsystems/ping.dm @@ -0,0 +1,30 @@ +#define PING_BUFFER_TIME 25 + +SUBSYSTEM_DEF(ping) + name = "Ping" + wait = 6 + flags = SS_NO_INIT|SS_POST_FIRE_TIMING + priority = FIRE_PRIORITY_PING + init_order = INIT_ORDER_PING + runlevels = RUNLEVEL_LOBBY|RUNLEVEL_SETUP|RUNLEVEL_GAME|RUNLEVEL_POSTGAME + var/list/currentrun + +/datum/controller/subsystem/ping/fire(resumed = FALSE) + if (!resumed) + src.currentrun = GLOB.clients.Copy() + + var/list/currentrun = src.currentrun + while (length(currentrun)) + var/client/C = currentrun[currentrun.len] + currentrun.len-- + if (!C || world.time - C.connection_time < PING_BUFFER_TIME) + if (MC_TICK_CHECK) + return + continue + winset(C, null, "command=.update_ping+[world.time+world.tick_lag*world.tick_usage/100]") + if (MC_TICK_CHECK) //one day, when ss13 has 1000 people per server, you guys are gonna be glad I added this tick check + return + + currentrun = null + +#undef PING_BUFFER_TIME \ No newline at end of file diff --git a/code/modules/client/client defines.dm b/code/modules/client/client defines.dm index 2c0d6ca7ac..a74918c1a7 100644 --- a/code/modules/client/client defines.dm +++ b/code/modules/client/client defines.dm @@ -73,3 +73,6 @@ var/connection_realtime ///world.timeofday they connected var/connection_timeofday + + var/lastping = 0 + var/avgping = 0 diff --git a/code/modules/client/client procs.dm b/code/modules/client/client procs.dm index 60b635932c..8c7d36a3bf 100644 --- a/code/modules/client/client procs.dm +++ b/code/modules/client/client procs.dm @@ -490,4 +490,4 @@ client/verb/character_setup() //Went fine else ip_reputation = score - return TRUE + return TRUE \ No newline at end of file diff --git a/code/game/verbs/advanced_who.dm b/code/modules/client/verbs/advanced_who.dm similarity index 95% rename from code/game/verbs/advanced_who.dm rename to code/modules/client/verbs/advanced_who.dm index 4498136b2b..d618405c1f 100644 --- a/code/game/verbs/advanced_who.dm +++ b/code/modules/client/verbs/advanced_who.dm @@ -66,6 +66,8 @@ entry += "[round(seconds / 60)] minutes, " entry += "[seconds % 60] seconds)" + entry += "" + entry += " ([round(C.avgping, 1)]ms)" entry += "" entry += " (?)" entry += "" @@ -85,6 +87,8 @@ entry += " - In Lobby
" else entry += " - Playing
" + + entry += " ([round(C.avgping, 1)]ms)" Lines += entry msg += "" diff --git a/code/game/verbs/ignore.dm b/code/modules/client/verbs/ignore.dm similarity index 100% rename from code/game/verbs/ignore.dm rename to code/modules/client/verbs/ignore.dm diff --git a/code/game/verbs/ooc.dm b/code/modules/client/verbs/ooc.dm similarity index 97% rename from code/game/verbs/ooc.dm rename to code/modules/client/verbs/ooc.dm index d7b649505d..e51c3423d8 100644 --- a/code/game/verbs/ooc.dm +++ b/code/modules/client/verbs/ooc.dm @@ -1,186 +1,186 @@ - -/client/verb/ooc(msg as text) - set name = "OOC" - set category = "OOC" - - if(say_disabled) //This is here to try to identify lag problems - to_chat(usr, "Speech is currently admin-disabled.") - return - - if(!mob) return - if(IsGuestKey(key)) - to_chat(src, "Guests may not use OOC.") - return - - msg = sanitize(msg) - if(!msg) return - - if(!is_preference_enabled(/datum/client_preference/show_ooc)) - to_chat(src, "You have OOC muted.") - return - - if(!holder) - if(!config.ooc_allowed) - to_chat(src, "OOC is globally muted.") - return - if(!config.dooc_allowed && (mob.stat == DEAD)) - to_chat(usr, "OOC for dead mobs has been turned off.") - return - if(prefs.muted & MUTE_OOC) - to_chat(src, "You cannot use OOC (muted).") - return - if(findtext(msg, "byond://") && !config.allow_byond_links) - to_chat(src, "Advertising other servers is not allowed.") - log_admin("[key_name(src)] has attempted to advertise in OOC: [msg]") - message_admins("[key_name_admin(src)] has attempted to advertise in OOC: [msg]") - return - if(findtext(msg, "discord.gg") && !config.allow_discord_links) - to_chat(src, "Advertising discords is not allowed.") - log_admin("[key_name(src)] has attempted to advertise a discord server in OOC: [msg]") - message_admins("[key_name_admin(src)] has attempted to advertise a discord server in OOC: [msg]") - return - if((findtext(msg, "http://") || findtext(msg, "https://")) && !config.allow_url_links) - to_chat(src, "Posting external links is not allowed.") - log_admin("[key_name(src)] has attempted to post a link in OOC: [msg]") - message_admins("[key_name_admin(src)] has attempted to post a link in OOC: [msg]") - return - - log_ooc(msg, src) - - if(msg) - handle_spam_prevention(MUTE_OOC) - - var/ooc_style = "everyone" - if(holder && !holder.fakekey) - ooc_style = "elevated" - if(holder.rights & R_ADMIN) - ooc_style = "admin" - else if(holder.rights & R_EVENT) - ooc_style = "event_manager" - else if(holder.rights & R_DEBUG) - ooc_style = "developer" - else if(holder.rights & R_MOD) - ooc_style = "moderator" - - - for(var/client/target in GLOB.clients) - if(target.is_preference_enabled(/datum/client_preference/show_ooc)) - if(target.is_key_ignored(key)) // If we're ignored by this person, then do nothing. - continue - var/display_name = src.key - if(holder) - if(holder.fakekey) - if(target.holder) - display_name = "[holder.fakekey]/([src.key])" - else - display_name = holder.fakekey - if(holder && !holder.fakekey && (holder.rights & R_ADMIN|R_FUN|R_EVENT) && config.allow_admin_ooccolor && (src.prefs.ooccolor != initial(src.prefs.ooccolor))) // keeping this for the badmins - to_chat(target, "" + create_text_tag("ooc", "OOC:", target) + " [display_name]: [msg]") - else - to_chat(target, "" + create_text_tag("ooc", "OOC:", target) + " [display_name]: [msg]") - -/client/verb/looc(msg as text) - set name = "LOOC" - set desc = "Local OOC, seen only by those in view." - set category = "OOC" - - if(say_disabled) //This is here to try to identify lag problems - to_chat(usr, "Speech is currently admin-disabled.") - return - - if(!mob) - return - - if(IsGuestKey(key)) - to_chat(src, "Guests may not use OOC.") - return - - msg = sanitize(msg) - if(!msg) - return - - if(!is_preference_enabled(/datum/client_preference/show_looc)) - to_chat(src, "You have LOOC muted.") - return - - if(!holder) - if(!config.looc_allowed) - to_chat(src, "LOOC is globally muted.") - return - if(!config.dooc_allowed && (mob.stat == DEAD)) - to_chat(usr, "OOC for dead mobs has been turned off.") - return - if(prefs.muted & MUTE_OOC) - to_chat(src, "You cannot use OOC (muted).") - return - if(findtext(msg, "byond://") && !config.allow_byond_links) - to_chat(src, "Advertising other servers is not allowed.") - log_admin("[key_name(src)] has attempted to advertise in OOC: [msg]") - message_admins("[key_name_admin(src)] has attempted to advertise in OOC: [msg]") - return - if(findtext(msg, "discord.gg") && !config.allow_discord_links) - to_chat(src, "Advertising discords is not allowed.") - log_admin("[key_name(src)] has attempted to advertise a discord server in OOC: [msg]") - message_admins("[key_name_admin(src)] has attempted to advertise a discord server in OOC: [msg]") - return - if((findtext(msg, "http://") || findtext(msg, "https://")) && !config.allow_url_links) - to_chat(src, "Posting external links is not allowed.") - log_admin("[key_name(src)] has attempted to post a link in OOC: [msg]") - message_admins("[key_name_admin(src)] has attempted to post a link in OOC: [msg]") - return - - log_looc(msg,src) - - if(msg) - handle_spam_prevention(MUTE_OOC) - - var/mob/source = mob.get_looc_source() - var/turf/T = get_turf(source) - if(!T) return - var/list/in_range = get_mobs_and_objs_in_view_fast(T,world.view,0) - var/list/m_viewers = in_range["mobs"] - - var/list/receivers = list() //Clients, not mobs. - var/list/r_receivers = list() - - var/display_name = key - if(holder && holder.fakekey) - display_name = holder.fakekey - if(mob.stat != DEAD) - display_name = mob.name - - // Everyone in normal viewing range of the LOOC - for(var/mob/viewer in m_viewers) - if(viewer.client && viewer.client.is_preference_enabled(/datum/client_preference/show_looc)) - receivers |= viewer.client - else if(istype(viewer,/mob/observer/eye)) // For AI eyes and the like - var/mob/observer/eye/E = viewer - if(E.owner && E.owner.client) - receivers |= E.owner.client - - // Admins with RLOOC displayed who weren't already in - for(var/client/admin in admins) - if(!(admin in receivers) && admin.is_preference_enabled(/datum/client_preference/holder/show_rlooc)) - r_receivers |= admin - - // Send a message - for(var/client/target in receivers) - var/admin_stuff = "" - - if(target in admins) - admin_stuff += "/([key])" - - to_chat(target, "" + create_text_tag("looc", "LOOC:", target) + " [display_name][admin_stuff]: [msg]") - - for(var/client/target in r_receivers) - var/admin_stuff = "/([key])([admin_jump_link(mob, target.holder)])" - - to_chat(target, "" + create_text_tag("looc", "LOOC:", target) + " (R)[display_name][admin_stuff]: [msg]") - -/mob/proc/get_looc_source() - return src - -/mob/living/silicon/ai/get_looc_source() - if(eyeobj) - return eyeobj - return src + +/client/verb/ooc(msg as text) + set name = "OOC" + set category = "OOC" + + if(say_disabled) //This is here to try to identify lag problems + to_chat(usr, "Speech is currently admin-disabled.") + return + + if(!mob) return + if(IsGuestKey(key)) + to_chat(src, "Guests may not use OOC.") + return + + msg = sanitize(msg) + if(!msg) return + + if(!is_preference_enabled(/datum/client_preference/show_ooc)) + to_chat(src, "You have OOC muted.") + return + + if(!holder) + if(!config.ooc_allowed) + to_chat(src, "OOC is globally muted.") + return + if(!config.dooc_allowed && (mob.stat == DEAD)) + to_chat(usr, "OOC for dead mobs has been turned off.") + return + if(prefs.muted & MUTE_OOC) + to_chat(src, "You cannot use OOC (muted).") + return + if(findtext(msg, "byond://") && !config.allow_byond_links) + to_chat(src, "Advertising other servers is not allowed.") + log_admin("[key_name(src)] has attempted to advertise in OOC: [msg]") + message_admins("[key_name_admin(src)] has attempted to advertise in OOC: [msg]") + return + if(findtext(msg, "discord.gg") && !config.allow_discord_links) + to_chat(src, "Advertising discords is not allowed.") + log_admin("[key_name(src)] has attempted to advertise a discord server in OOC: [msg]") + message_admins("[key_name_admin(src)] has attempted to advertise a discord server in OOC: [msg]") + return + if((findtext(msg, "http://") || findtext(msg, "https://")) && !config.allow_url_links) + to_chat(src, "Posting external links is not allowed.") + log_admin("[key_name(src)] has attempted to post a link in OOC: [msg]") + message_admins("[key_name_admin(src)] has attempted to post a link in OOC: [msg]") + return + + log_ooc(msg, src) + + if(msg) + handle_spam_prevention(MUTE_OOC) + + var/ooc_style = "everyone" + if(holder && !holder.fakekey) + ooc_style = "elevated" + if(holder.rights & R_ADMIN) + ooc_style = "admin" + else if(holder.rights & R_EVENT) + ooc_style = "event_manager" + else if(holder.rights & R_DEBUG) + ooc_style = "developer" + else if(holder.rights & R_MOD) + ooc_style = "moderator" + + + for(var/client/target in GLOB.clients) + if(target.is_preference_enabled(/datum/client_preference/show_ooc)) + if(target.is_key_ignored(key)) // If we're ignored by this person, then do nothing. + continue + var/display_name = src.key + if(holder) + if(holder.fakekey) + if(target.holder) + display_name = "[holder.fakekey]/([src.key])" + else + display_name = holder.fakekey + if(holder && !holder.fakekey && (holder.rights & R_ADMIN|R_FUN|R_EVENT) && config.allow_admin_ooccolor && (src.prefs.ooccolor != initial(src.prefs.ooccolor))) // keeping this for the badmins + to_chat(target, "" + create_text_tag("ooc", "OOC:", target) + " [display_name]: [msg]") + else + to_chat(target, "" + create_text_tag("ooc", "OOC:", target) + " [display_name]: [msg]") + +/client/verb/looc(msg as text) + set name = "LOOC" + set desc = "Local OOC, seen only by those in view." + set category = "OOC" + + if(say_disabled) //This is here to try to identify lag problems + to_chat(usr, "Speech is currently admin-disabled.") + return + + if(!mob) + return + + if(IsGuestKey(key)) + to_chat(src, "Guests may not use OOC.") + return + + msg = sanitize(msg) + if(!msg) + return + + if(!is_preference_enabled(/datum/client_preference/show_looc)) + to_chat(src, "You have LOOC muted.") + return + + if(!holder) + if(!config.looc_allowed) + to_chat(src, "LOOC is globally muted.") + return + if(!config.dooc_allowed && (mob.stat == DEAD)) + to_chat(usr, "OOC for dead mobs has been turned off.") + return + if(prefs.muted & MUTE_OOC) + to_chat(src, "You cannot use OOC (muted).") + return + if(findtext(msg, "byond://") && !config.allow_byond_links) + to_chat(src, "Advertising other servers is not allowed.") + log_admin("[key_name(src)] has attempted to advertise in OOC: [msg]") + message_admins("[key_name_admin(src)] has attempted to advertise in OOC: [msg]") + return + if(findtext(msg, "discord.gg") && !config.allow_discord_links) + to_chat(src, "Advertising discords is not allowed.") + log_admin("[key_name(src)] has attempted to advertise a discord server in OOC: [msg]") + message_admins("[key_name_admin(src)] has attempted to advertise a discord server in OOC: [msg]") + return + if((findtext(msg, "http://") || findtext(msg, "https://")) && !config.allow_url_links) + to_chat(src, "Posting external links is not allowed.") + log_admin("[key_name(src)] has attempted to post a link in OOC: [msg]") + message_admins("[key_name_admin(src)] has attempted to post a link in OOC: [msg]") + return + + log_looc(msg,src) + + if(msg) + handle_spam_prevention(MUTE_OOC) + + var/mob/source = mob.get_looc_source() + var/turf/T = get_turf(source) + if(!T) return + var/list/in_range = get_mobs_and_objs_in_view_fast(T,world.view,0) + var/list/m_viewers = in_range["mobs"] + + var/list/receivers = list() //Clients, not mobs. + var/list/r_receivers = list() + + var/display_name = key + if(holder && holder.fakekey) + display_name = holder.fakekey + if(mob.stat != DEAD) + display_name = mob.name + + // Everyone in normal viewing range of the LOOC + for(var/mob/viewer in m_viewers) + if(viewer.client && viewer.client.is_preference_enabled(/datum/client_preference/show_looc)) + receivers |= viewer.client + else if(istype(viewer,/mob/observer/eye)) // For AI eyes and the like + var/mob/observer/eye/E = viewer + if(E.owner && E.owner.client) + receivers |= E.owner.client + + // Admins with RLOOC displayed who weren't already in + for(var/client/admin in admins) + if(!(admin in receivers) && admin.is_preference_enabled(/datum/client_preference/holder/show_rlooc)) + r_receivers |= admin + + // Send a message + for(var/client/target in receivers) + var/admin_stuff = "" + + if(target in admins) + admin_stuff += "/([key])" + + to_chat(target, "" + create_text_tag("looc", "LOOC:", target) + " [display_name][admin_stuff]: [msg]") + + for(var/client/target in r_receivers) + var/admin_stuff = "/([key])([admin_jump_link(mob, target.holder)])" + + to_chat(target, "" + create_text_tag("looc", "LOOC:", target) + " (R)[display_name][admin_stuff]: [msg]") + +/mob/proc/get_looc_source() + return src + +/mob/living/silicon/ai/get_looc_source() + if(eyeobj) + return eyeobj + return src diff --git a/code/modules/client/verbs/ping.dm b/code/modules/client/verbs/ping.dm new file mode 100644 index 0000000000..eae9755d36 --- /dev/null +++ b/code/modules/client/verbs/ping.dm @@ -0,0 +1,22 @@ +/client/verb/update_ping(time as num) + set instant = TRUE + set name = ".update_ping" + var/ping = pingfromtime(time) + lastping = ping + if (!avgping) + avgping = ping + else + avgping = MC_AVERAGE_SLOW(avgping, ping) + +/client/proc/pingfromtime(time) + return ((world.time+world.tick_lag*world.tick_usage/100)-time)*100 + +/client/verb/display_ping(time as num) + set instant = TRUE + set name = ".display_ping" + to_chat(src, "Round trip ping took [round(pingfromtime(time),1)]ms") + +/client/verb/ping() + set name = "Ping" + set category = "OOC" + winset(src, null, "command=.display_ping+[world.time+world.tick_lag*world.tick_usage/100]") \ No newline at end of file diff --git a/code/game/verbs/who.dm b/code/modules/client/verbs/who.dm similarity index 95% rename from code/game/verbs/who.dm rename to code/modules/client/verbs/who.dm index e82b4ccb32..622fa4fd00 100644 --- a/code/game/verbs/who.dm +++ b/code/modules/client/verbs/who.dm @@ -1,186 +1,190 @@ - -/client/verb/who() - set name = "Who" - set category = "OOC" - - var/msg = "Current Players:\n" - - var/list/Lines = list() - - if(holder && (R_ADMIN & holder.rights || R_MOD & holder.rights)) - for(var/client/C in GLOB.clients) - var/entry = "\t[C.key]" - if(C.holder && C.holder.fakekey) - entry += " (as [C.holder.fakekey])" - entry += " - Playing as [C.mob.real_name]" - switch(C.mob.stat) - if(UNCONSCIOUS) - entry += " - Unconscious" - if(DEAD) - if(isobserver(C.mob)) - var/mob/observer/dead/O = C.mob - if(O.started_as_observer) - entry += " - Observing" - else - entry += " - DEAD" - else - entry += " - DEAD" - - var/age - if(isnum(C.player_age)) - age = C.player_age - else - age = 0 - - if(age <= 1) - age = "[age]" - else if(age < 10) - age = "[age]" - - entry += " - [age]" - - if(is_special_character(C.mob)) - entry += " - Antagonist" - - if(C.is_afk()) - var/seconds = C.last_activity_seconds() - entry += " (AFK - " - entry += "[round(seconds / 60)] minutes, " - entry += "[seconds % 60] seconds)" - - entry += " (?)" - Lines += entry - else - for(var/client/C in GLOB.clients) - if(C.holder && C.holder.fakekey) - Lines += C.holder.fakekey - else - Lines += C.key - - for(var/line in sortList(Lines)) - msg += "[line]\n" - - msg += "Total Players: [length(Lines)]" - to_chat(src,msg) - -/client/verb/staffwho() - set category = "Admin" - set name = "Staffwho" - - var/msg = "" - var/modmsg = "" - var/devmsg = "" - var/eventMmsg = "" - var/num_mods_online = 0 - var/num_admins_online = 0 - var/num_devs_online = 0 - var/num_event_managers_online = 0 - if(holder) - for(var/client/C in admins) - if(R_ADMIN & C.holder.rights || (!R_MOD & C.holder.rights && !R_EVENT & C.holder.rights)) //Used to determine who shows up in admin rows - - if(C.holder.fakekey && (!R_ADMIN & holder.rights && !R_MOD & holder.rights)) //Event Managerss can't see stealthmins - continue - - msg += "\t[C] is a [C.holder.rank]" - - if(C.holder.fakekey) - msg += " (as [C.holder.fakekey])" - - if(isobserver(C.mob)) - msg += " - Observing" - else if(istype(C.mob,/mob/new_player)) - msg += " - Lobby" - else - msg += " - Playing" - - if(C.is_afk()) - var/seconds = C.last_activity_seconds() - msg += " (AFK - " - msg += "[round(seconds / 60)] minutes, " - msg += "[seconds % 60] seconds)" - msg += "\n" - - num_admins_online++ - else if(R_MOD & C.holder.rights) //Who shows up in mod rows. - modmsg += "\t[C] is a [C.holder.rank]" - - if(isobserver(C.mob)) - modmsg += " - Observing" - else if(istype(C.mob,/mob/new_player)) - modmsg += " - Lobby" - else - modmsg += " - Playing" - - if(C.is_afk()) - var/seconds = C.last_activity_seconds() - modmsg += " (AFK - " - modmsg += "[round(seconds / 60)] minutes, " - modmsg += "[seconds % 60] seconds)" - modmsg += "\n" - num_mods_online++ - - else if(R_SERVER & C.holder.rights) - devmsg += "\t[C] is a [C.holder.rank]" - if(isobserver(C.mob)) - devmsg += " - Observing" - else if(istype(C.mob,/mob/new_player)) - devmsg += " - Lobby" - else - devmsg += " - Playing" - - if(C.is_afk()) - var/seconds = C.last_activity_seconds() - devmsg += "(AFK - " - devmsg += "[round(seconds / 60)] minutes, " - devmsg += "[seconds % 60] seconds)" - devmsg += "\n" - num_devs_online++ - - else if(R_EVENT & C.holder.rights) - eventMmsg += "\t[C] is a [C.holder.rank]" - if(isobserver(C.mob)) - eventMmsg += " - Observing" - else if(istype(C.mob,/mob/new_player)) - eventMmsg += " - Lobby" - else - eventMmsg += " - Playing" - - if(C.is_afk()) - var/seconds = C.last_activity_seconds() - eventMmsg += " (AFK - " - eventMmsg += "[round(seconds / 60)] minutes, " - eventMmsg += "[seconds % 60] seconds)" - eventMmsg += "\n" - num_event_managers_online++ - - else - for(var/client/C in admins) - if(R_ADMIN & C.holder.rights || (!R_MOD & C.holder.rights && !R_EVENT & C.holder.rights)) - if(!C.holder.fakekey) - msg += "\t[C] is a [C.holder.rank]\n" - num_admins_online++ - else if (R_MOD & C.holder.rights) - modmsg += "\t[C] is a [C.holder.rank]\n" - num_mods_online++ - else if (R_SERVER & C.holder.rights) - devmsg += "\t[C] is a [C.holder.rank]\n" - num_devs_online++ - else if (R_EVENT & C.holder.rights) - eventMmsg += "\t[C] is a [C.holder.rank]\n" - num_event_managers_online++ - - if(config.admin_irc) - to_chat(src, "Adminhelps are also sent to IRC. If no admins are available in game try anyway and an admin on IRC may see it and respond.") - msg = "Current Admins ([num_admins_online]):\n" + msg - - if(config.show_mods) - msg += "\n Current Moderators ([num_mods_online]):\n" + modmsg - - if(config.show_devs) - msg += "\n Current Developers ([num_devs_online]):\n" + devmsg - - if(config.show_event_managers) - msg += "\n Current Event Managers ([num_event_managers_online]):\n" + eventMmsg - - to_chat(src,msg) + +/client/verb/who() + set name = "Who" + set category = "OOC" + + var/msg = "Current Players:\n" + + var/list/Lines = list() + + if(holder && (R_ADMIN & holder.rights || R_MOD & holder.rights)) + for(var/client/C in GLOB.clients) + var/entry = "\t[C.key]" + if(C.holder && C.holder.fakekey) + entry += " (as [C.holder.fakekey])" + entry += " - Playing as [C.mob.real_name]" + switch(C.mob.stat) + if(UNCONSCIOUS) + entry += " - Unconscious" + if(DEAD) + if(isobserver(C.mob)) + var/mob/observer/dead/O = C.mob + if(O.started_as_observer) + entry += " - Observing" + else + entry += " - DEAD" + else + entry += " - DEAD" + + var/age + if(isnum(C.player_age)) + age = C.player_age + else + age = 0 + + if(age <= 1) + age = "[age]" + else if(age < 10) + age = "[age]" + + entry += " - [age]" + + if(is_special_character(C.mob)) + entry += " - Antagonist" + + if(C.is_afk()) + var/seconds = C.last_activity_seconds() + entry += " (AFK - " + entry += "[round(seconds / 60)] minutes, " + entry += "[seconds % 60] seconds)" + + entry += " (?)" + entry += " ([round(C.avgping, 1)]ms)" + Lines += entry + else + for(var/client/C in GLOB.clients) + var/entry + if(C.holder && C.holder.fakekey) + entry = C.holder.fakekey + else + entry = C.key + entry += " ([round(C.avgping, 1)]ms)" + Lines += entry + + for(var/line in sortList(Lines)) + msg += "[line]\n" + + msg += "Total Players: [length(Lines)]" + to_chat(src,msg) + +/client/verb/staffwho() + set category = "Admin" + set name = "Staffwho" + + var/msg = "" + var/modmsg = "" + var/devmsg = "" + var/eventMmsg = "" + var/num_mods_online = 0 + var/num_admins_online = 0 + var/num_devs_online = 0 + var/num_event_managers_online = 0 + if(holder) + for(var/client/C in admins) + if(R_ADMIN & C.holder.rights || (!R_MOD & C.holder.rights && !R_EVENT & C.holder.rights)) //Used to determine who shows up in admin rows + + if(C.holder.fakekey && (!R_ADMIN & holder.rights && !R_MOD & holder.rights)) //Event Managerss can't see stealthmins + continue + + msg += "\t[C] is a [C.holder.rank]" + + if(C.holder.fakekey) + msg += " (as [C.holder.fakekey])" + + if(isobserver(C.mob)) + msg += " - Observing" + else if(istype(C.mob,/mob/new_player)) + msg += " - Lobby" + else + msg += " - Playing" + + if(C.is_afk()) + var/seconds = C.last_activity_seconds() + msg += " (AFK - " + msg += "[round(seconds / 60)] minutes, " + msg += "[seconds % 60] seconds)" + msg += "\n" + + num_admins_online++ + else if(R_MOD & C.holder.rights) //Who shows up in mod rows. + modmsg += "\t[C] is a [C.holder.rank]" + + if(isobserver(C.mob)) + modmsg += " - Observing" + else if(istype(C.mob,/mob/new_player)) + modmsg += " - Lobby" + else + modmsg += " - Playing" + + if(C.is_afk()) + var/seconds = C.last_activity_seconds() + modmsg += " (AFK - " + modmsg += "[round(seconds / 60)] minutes, " + modmsg += "[seconds % 60] seconds)" + modmsg += "\n" + num_mods_online++ + + else if(R_SERVER & C.holder.rights) + devmsg += "\t[C] is a [C.holder.rank]" + if(isobserver(C.mob)) + devmsg += " - Observing" + else if(istype(C.mob,/mob/new_player)) + devmsg += " - Lobby" + else + devmsg += " - Playing" + + if(C.is_afk()) + var/seconds = C.last_activity_seconds() + devmsg += "(AFK - " + devmsg += "[round(seconds / 60)] minutes, " + devmsg += "[seconds % 60] seconds)" + devmsg += "\n" + num_devs_online++ + + else if(R_EVENT & C.holder.rights) + eventMmsg += "\t[C] is a [C.holder.rank]" + if(isobserver(C.mob)) + eventMmsg += " - Observing" + else if(istype(C.mob,/mob/new_player)) + eventMmsg += " - Lobby" + else + eventMmsg += " - Playing" + + if(C.is_afk()) + var/seconds = C.last_activity_seconds() + eventMmsg += " (AFK - " + eventMmsg += "[round(seconds / 60)] minutes, " + eventMmsg += "[seconds % 60] seconds)" + eventMmsg += "\n" + num_event_managers_online++ + + else + for(var/client/C in admins) + if(R_ADMIN & C.holder.rights || (!R_MOD & C.holder.rights && !R_EVENT & C.holder.rights)) + if(!C.holder.fakekey) + msg += "\t[C] is a [C.holder.rank]\n" + num_admins_online++ + else if (R_MOD & C.holder.rights) + modmsg += "\t[C] is a [C.holder.rank]\n" + num_mods_online++ + else if (R_SERVER & C.holder.rights) + devmsg += "\t[C] is a [C.holder.rank]\n" + num_devs_online++ + else if (R_EVENT & C.holder.rights) + eventMmsg += "\t[C] is a [C.holder.rank]\n" + num_event_managers_online++ + + if(config.admin_irc) + to_chat(src, "Adminhelps are also sent to IRC. If no admins are available in game try anyway and an admin on IRC may see it and respond.") + msg = "Current Admins ([num_admins_online]):\n" + msg + + if(config.show_mods) + msg += "\n Current Moderators ([num_mods_online]):\n" + modmsg + + if(config.show_devs) + msg += "\n Current Developers ([num_devs_online]):\n" + devmsg + + if(config.show_event_managers) + msg += "\n Current Event Managers ([num_event_managers_online]):\n" + eventMmsg + + to_chat(src,msg) diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index bf183013b6..95890becac 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -627,6 +627,8 @@ if(.) if(statpanel("Status")) + if(client) + stat(null, "Ping: [round(client.lastping, 1)]ms (Average: [round(client.avgping, 1)]ms)") stat(null, "Time Dilation: [round(SStime_track.time_dilation_current,1)]% AVG:([round(SStime_track.time_dilation_avg_fast,1)]%, [round(SStime_track.time_dilation_avg,1)]%, [round(SStime_track.time_dilation_avg_slow,1)]%)") if(ticker && ticker.current_state != GAME_STATE_PREGAME) stat("Station Time", stationtime2text()) diff --git a/polaris.dme b/polaris.dme index f497af1b64..d757573bba 100644 --- a/polaris.dme +++ b/polaris.dme @@ -235,6 +235,7 @@ #include "code\controllers\subsystems\orbits.dm" #include "code\controllers\subsystems\overlays.dm" #include "code\controllers\subsystems\persistence.dm" +#include "code\controllers\subsystems\ping.dm" #include "code\controllers\subsystems\planets.dm" #include "code\controllers\subsystems\radiation.dm" #include "code\controllers\subsystems\shuttles.dm" @@ -1335,11 +1336,7 @@ #include "code\game\turfs\unsimulated\planetary.dm" #include "code\game\turfs\unsimulated\shuttle.dm" #include "code\game\turfs\unsimulated\walls.dm" -#include "code\game\verbs\advanced_who.dm" -#include "code\game\verbs\ignore.dm" -#include "code\game\verbs\ooc.dm" #include "code\game\verbs\suicide.dm" -#include "code\game\verbs\who.dm" #include "code\js\byjax.dm" #include "code\js\menus.dm" #include "code\modules\admin\admin.dm" @@ -1462,8 +1459,8 @@ #include "code\modules\ai\ai_holder_targeting.dm" #include "code\modules\ai\interfaces.dm" #include "code\modules\ai\say_list.dm" -#include "code\modules\ai\aI_holder_subtypes\simple_mob_ai.dm" -#include "code\modules\ai\aI_holder_subtypes\slime_xenobio_ai.dm" +#include "code\modules\ai\ai_holder_subtypes\simple_mob_ai.dm" +#include "code\modules\ai\ai_holder_subtypes\slime_xenobio_ai.dm" #include "code\modules\alarm\alarm.dm" #include "code\modules\alarm\alarm_handler.dm" #include "code\modules\alarm\atmosphere_alarm.dm" @@ -1581,6 +1578,11 @@ #include "code\modules\client\preference_setup\traits\trait_defines.dm" #include "code\modules\client\preference_setup\traits\traits.dm" #include "code\modules\client\preference_setup\volume_sliders\01_volume.dm" +#include "code\modules\client\verbs\advanced_who.dm" +#include "code\modules\client\verbs\ignore.dm" +#include "code\modules\client\verbs\ooc.dm" +#include "code\modules\client\verbs\ping.dm" +#include "code\modules\client\verbs\who.dm" #include "code\modules\clothing\chameleon.dm" #include "code\modules\clothing\clothing.dm" #include "code\modules\clothing\clothing_accessories.dm"