mirror of
https://github.com/ParadiseSS13/Paradise.git
synced 2026-07-13 16:13:19 +01:00
Merge branch 'master' into 3/4th-closet
This commit is contained in:
@@ -27,6 +27,12 @@
|
||||
if(A && (A.rights & R_ADMIN))
|
||||
admin = 1
|
||||
|
||||
// Lets see if they are logged in on another paradise server
|
||||
if(SSdbcore.IsConnected())
|
||||
var/other_server_login = SSinstancing.check_player(ckey)
|
||||
if(other_server_login)
|
||||
return list("reason"="duplicate login", "desc"="\nReason: You are already logged in on server '[other_server_login]'. Please contact the server host if you believe this is an error.")
|
||||
|
||||
//Guest Checking
|
||||
if(GLOB.configuration.general.guest_ban && IsGuestKey(key))
|
||||
log_adminwarn("Failed Login: [key] [computer_id] [address] - Guests not allowed")
|
||||
|
||||
+79
-38
@@ -13,12 +13,8 @@ GLOBAL_VAR_INIT(nologevent, 0)
|
||||
if(!GLOB.nologevent)
|
||||
var/rendered = "<span class=\"admin\"><span class=\"prefix\">ATTACK:</span> <span class=\"message\">[text]</span></span>"
|
||||
for(var/client/C in GLOB.admins)
|
||||
if(R_ADMIN & C.holder.rights)
|
||||
if(C.prefs.atklog == ATKLOG_NONE)
|
||||
continue
|
||||
var/msg = rendered
|
||||
if(C.prefs.atklog <= loglevel)
|
||||
to_chat(C, msg)
|
||||
if((C.holder.rights & R_ADMIN) && (C.prefs?.atklog <= loglevel))
|
||||
to_chat(C, rendered)
|
||||
|
||||
/**
|
||||
* Sends a message to the staff able to see admin tickets
|
||||
@@ -624,43 +620,88 @@ GLOBAL_VAR_INIT(nologevent, 0)
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////ADMIN HELPER PROCS
|
||||
|
||||
/proc/is_special_character(mob/M as mob) // returns 1 for specail characters and 2 for heroes of gamemode
|
||||
if(!SSticker || !SSticker.mode)
|
||||
return 0
|
||||
/**
|
||||
* A proc that return whether the mob is a "Special Character" aka Antagonist
|
||||
*
|
||||
* Arguments:
|
||||
* * M - the mob you're checking
|
||||
*/
|
||||
/proc/is_special_character(mob/M)
|
||||
if(!SSticker.mode)
|
||||
return FALSE
|
||||
if(!istype(M))
|
||||
return 0
|
||||
if((M.mind in SSticker.mode.head_revolutionaries) || (M.mind in SSticker.mode.revolutionaries))
|
||||
if(SSticker.mode.config_tag == "revolution")
|
||||
return 2
|
||||
return 1
|
||||
if(M.mind in SSticker.mode.cult)
|
||||
if(SSticker.mode.config_tag == "cult")
|
||||
return 2
|
||||
return 1
|
||||
if(M.mind in SSticker.mode.syndicates)
|
||||
if(SSticker.mode.config_tag == "nuclear")
|
||||
return 2
|
||||
return 1
|
||||
if(M.mind in SSticker.mode.wizards)
|
||||
if(SSticker.mode.config_tag == "wizard")
|
||||
return 2
|
||||
return 1
|
||||
if(M.mind in SSticker.mode.changelings)
|
||||
if(SSticker.mode.config_tag == "changeling")
|
||||
return 2
|
||||
return 1
|
||||
if(M.mind in SSticker.mode.abductors)
|
||||
if(SSticker.mode.config_tag == "abduction")
|
||||
return 2
|
||||
return 1
|
||||
return FALSE
|
||||
if(isrobot(M))
|
||||
var/mob/living/silicon/robot/R = M
|
||||
if(R.emagged)
|
||||
return 1
|
||||
if(M.mind&&M.mind.special_role)//If they have a mind and special role, they are some type of traitor or antagonist.
|
||||
return 1
|
||||
return TRUE
|
||||
if(M.mind?.special_role)//If they have a mind and special role, they are some type of traitor or antagonist.
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
return 0
|
||||
/**
|
||||
* A proc that return an array of capitalized strings containing name of the antag types they are
|
||||
*
|
||||
* Arguments:
|
||||
* * M - the mob you're checking
|
||||
*/
|
||||
/proc/get_antag_type_strings_list(mob/M) // return an array of all the antag types they are with name
|
||||
var/list/antag_list = list()
|
||||
|
||||
if(!SSticker.mode || !istype(M) || !M.mind)
|
||||
return FALSE
|
||||
|
||||
if(M.mind in SSticker.mode.head_revolutionaries)
|
||||
antag_list += "Head Rev"
|
||||
if(M.mind in SSticker.mode.revolutionaries)
|
||||
antag_list += "Revolutionary"
|
||||
if(M.mind in SSticker.mode.cult)
|
||||
antag_list += "Cultist"
|
||||
if(M.mind in SSticker.mode.syndicates)
|
||||
antag_list += "Nuclear Operative"
|
||||
if(M.mind in SSticker.mode.wizards)
|
||||
antag_list += "Wizard"
|
||||
if(M.mind in SSticker.mode.changelings)
|
||||
antag_list += "Changeling"
|
||||
if(M.mind in SSticker.mode.abductors)
|
||||
antag_list += "Abductor"
|
||||
if(M.mind in SSticker.mode.vampires)
|
||||
antag_list += "Vampire"
|
||||
if(M.mind in SSticker.mode.vampire_enthralled)
|
||||
antag_list += "Vampire Thrall"
|
||||
if(M.mind in SSticker.mode.shadows)
|
||||
antag_list += "Shadowling"
|
||||
if(M.mind in SSticker.mode.shadowling_thralls)
|
||||
antag_list += "Shadowling Thrall"
|
||||
if(M.mind.has_antag_datum(/datum/antagonist/traitor))
|
||||
antag_list += "Traitor"
|
||||
if(M.mind.has_antag_datum(/datum/antagonist/mindslave))
|
||||
antag_list += "Mindslave"
|
||||
if(isrobot(M))
|
||||
var/mob/living/silicon/robot/R = M
|
||||
if(R.emagged)
|
||||
antag_list += "Emagged Borg"
|
||||
if(!length(antag_list) && M.mind.special_role) // Snowflake check. If none of the above but still special, then other antag. Technically not accurate.
|
||||
antag_list += "Other Antag(s)"
|
||||
return antag_list
|
||||
|
||||
/**
|
||||
* A proc that return a string containing all the singled out antags . Empty string if not antag
|
||||
*
|
||||
* Usually, you'd return a FALSE, but since this is consumed by javascript you're in
|
||||
* for a world of hurt if you pass a byond FALSE which get converted into a fucking string anyway and pass for TRUE in check. Fuck.
|
||||
* It always append "(May be other antag)"
|
||||
* Arguments:
|
||||
* * M - the mob you're checking
|
||||
* *
|
||||
*/
|
||||
/proc/get_antag_type_truncated_plaintext_string(mob/M as mob)
|
||||
var/list/antag_list = get_antag_type_strings_list(M)
|
||||
|
||||
if(length(antag_list))
|
||||
return antag_list.Join(" & ") + " " + "(May be other antag)"
|
||||
|
||||
return ""
|
||||
|
||||
/datum/admins/proc/spawn_atom(object as text)
|
||||
set category = "Debug"
|
||||
|
||||
@@ -45,6 +45,7 @@ GLOBAL_LIST_INIT(admin_verbs_admin, list(
|
||||
/datum/admins/proc/toggleemoji, /*toggles using emoji in ooc for everyone*/
|
||||
/client/proc/game_panel, /*game panel, allows to change game-mode etc*/
|
||||
/client/proc/cmd_admin_say, /*admin-only ooc chat*/
|
||||
/client/proc/gsay, /*cross-server asay*/
|
||||
/datum/admins/proc/PlayerNotes,
|
||||
/client/proc/cmd_mentor_say,
|
||||
/datum/admins/proc/show_player_notes,
|
||||
@@ -67,7 +68,8 @@ GLOBAL_LIST_INIT(admin_verbs_admin, list(
|
||||
/client/proc/toggle_mentor_chat,
|
||||
/client/proc/toggle_advanced_interaction, /*toggle admin ability to interact with not only machines, but also atoms such as buttons and doors*/
|
||||
/client/proc/list_ssds_afks,
|
||||
/client/proc/ccbdb_lookup_ckey
|
||||
/client/proc/ccbdb_lookup_ckey,
|
||||
/client/proc/view_instances
|
||||
))
|
||||
GLOBAL_LIST_INIT(admin_verbs_ban, list(
|
||||
/client/proc/ban_panel,
|
||||
@@ -362,17 +364,20 @@ GLOBAL_LIST_INIT(admin_verbs_ticket, list(
|
||||
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
if(!isliving(mob))
|
||||
return
|
||||
|
||||
if(mob)
|
||||
if(mob.invisibility == INVISIBILITY_OBSERVER)
|
||||
mob.invisibility = initial(mob.invisibility)
|
||||
to_chat(mob, "<span class='danger'>Invisimin off. Invisibility reset.</span>")
|
||||
mob.add_to_all_human_data_huds()
|
||||
//TODO: Make some kind of indication for the badmin that they are currently invisible
|
||||
else
|
||||
mob.invisibility = INVISIBILITY_OBSERVER
|
||||
to_chat(mob, "<span class='notice'>Invisimin on. You are now as invisible as a ghost.</span>")
|
||||
mob.remove_from_all_data_huds()
|
||||
if(mob.invisibility == INVISIBILITY_OBSERVER)
|
||||
mob.invisibility = initial(mob.invisibility)
|
||||
mob.add_to_all_human_data_huds()
|
||||
to_chat(mob, "<span class='danger'>Invisimin off. Invisibility reset.</span>")
|
||||
log_admin("[key_name(mob)] has turned Invisimin OFF")
|
||||
else
|
||||
mob.invisibility = INVISIBILITY_OBSERVER
|
||||
mob.remove_from_all_data_huds()
|
||||
to_chat(mob, "<span class='notice'>Invisimin on. You are now as invisible as a ghost.</span>")
|
||||
log_admin("[key_name(mob)] has turned Invisimin ON")
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Invisimin")
|
||||
|
||||
/client/proc/player_panel_new()
|
||||
set name = "Player Panel"
|
||||
@@ -701,8 +706,9 @@ GLOBAL_LIST_INIT(admin_verbs_ticket, list(
|
||||
|
||||
if(istext(flags))
|
||||
flags = text2num(flags)
|
||||
var/client/check_client = GLOB.directory[ckey]
|
||||
// Do a little check here
|
||||
if(GLOB.configuration.system.is_production && (flags & R_ADMIN) && prefs._2fa_status == _2FA_DISABLED) // If they are an admin and their 2FA is disabled
|
||||
if(GLOB.configuration.system.is_production && (flags & R_ADMIN) && check_client.prefs._2fa_status == _2FA_DISABLED) // If they are an admin and their 2FA is disabled
|
||||
to_chat(src,"<span class='boldannounce'><big>You do not have 2FA enabled. Admin verbs will be unavailable until you have enabled 2FA.</big></span>") // Very fucking obvious
|
||||
qdel(admin_read)
|
||||
return
|
||||
|
||||
@@ -146,8 +146,8 @@
|
||||
qdel(adm_query)
|
||||
|
||||
var/datum/db_query/query_insert = SSdbcore.NewQuery({"
|
||||
INSERT INTO ban (`id`,`bantime`,`serverip`,`bantype`,`reason`,`job`,`duration`,`rounds`,`expiration_time`,`ckey`,`computerid`,`ip`,`a_ckey`,`a_computerid`,`a_ip`,`who`,`adminwho`,`edits`,`unbanned`,`unbanned_datetime`,`unbanned_ckey`,`unbanned_computerid`,`unbanned_ip`,`ban_round_id`,`unbanned_round_id`)
|
||||
VALUES (null, Now(), :serverip, :bantype_str, :reason, :job, :duration, :rounds, Now() + INTERVAL :duration MINUTE, :ckey, :computerid, :ip, :a_ckey, :a_computerid, :a_ip, :who, :adminwho, '', null, null, null, null, null, :roundid, null)
|
||||
INSERT INTO ban (`id`,`bantime`,`serverip`,`bantype`,`reason`,`job`,`duration`,`rounds`,`expiration_time`,`ckey`,`computerid`,`ip`,`a_ckey`,`a_computerid`,`a_ip`,`who`,`adminwho`,`edits`,`unbanned`,`unbanned_datetime`,`unbanned_ckey`,`unbanned_computerid`,`unbanned_ip`,`ban_round_id`,`unbanned_round_id`, `server_id`)
|
||||
VALUES (null, Now(), :serverip, :bantype_str, :reason, :job, :duration, :rounds, Now() + INTERVAL :duration MINUTE, :ckey, :computerid, :ip, :a_ckey, :a_computerid, :a_ip, :who, :adminwho, '', null, null, null, null, null, :roundid, null, :server_id)
|
||||
"}, list(
|
||||
// Get ready for parameters
|
||||
"serverip" = serverip,
|
||||
@@ -164,7 +164,8 @@
|
||||
"a_ip" = a_ip,
|
||||
"who" = who,
|
||||
"adminwho" = adminwho,
|
||||
"roundid" = GLOB.round_id
|
||||
"roundid" = GLOB.round_id,
|
||||
"server_id" = GLOB.configuration.system.instance_id
|
||||
))
|
||||
if(!query_insert.warn_execute())
|
||||
qdel(query_insert)
|
||||
|
||||
@@ -65,7 +65,7 @@
|
||||
|
||||
}
|
||||
|
||||
function expand(id,job,name,real_name,image,key,ip,antagonist,mobUID,client_ckey,eyeUID){
|
||||
function expand(id,job,name,real_name,image,key,ip,antagonists,mobUID,client_ckey,eyeUID){
|
||||
|
||||
clearAll();
|
||||
|
||||
@@ -89,8 +89,8 @@
|
||||
if(eyeUID)
|
||||
body += "|<a href='?src=[UID()];adminplayerobservefollow="+eyeUID+"'>EYE</a>"
|
||||
body += "<br>"
|
||||
if(antagonist > 0)
|
||||
body += "<font size='2'><a href='?src=[UID()];check_antagonist=1'><font color='red'><b>Antagonist</b></font></a></font>";
|
||||
if(antagonists)
|
||||
body += "<font size='2'><a href='?src=[UID()];check_antagonist=1'><font color='red'><b>"+antagonists+"</b></font></a></font>";
|
||||
|
||||
body += "</td></tr></table>";
|
||||
|
||||
@@ -227,7 +227,7 @@
|
||||
var/color = "#e6e6e6"
|
||||
if(i%2 == 0)
|
||||
color = "#f2f2f2"
|
||||
var/is_antagonist = is_special_character(M)
|
||||
var/antagonist_string = get_antag_type_truncated_plaintext_string(M)
|
||||
|
||||
var/M_job = ""
|
||||
|
||||
@@ -305,7 +305,7 @@
|
||||
<td align='center' bgcolor='[color]'>
|
||||
<span id='notice_span[i]'></span>
|
||||
<a id='link[i]'
|
||||
onmouseover='expand("item[i]","[M_job]","[M_name]","[M_rname]","--unused--","[M_key]","[M.lastKnownIP]",[is_antagonist],"[M.UID()]","[client_ckey]","[M_eyeUID]")'
|
||||
onmouseover='expand("item[i]","[M_job]","[M_name]","[M_rname]","--unused--","[M_key]","[M.lastKnownIP]","[antagonist_string]","[M.UID()]","[client_ckey]","[M_eyeUID]")'
|
||||
>
|
||||
<b id='search[i]'>[M_name] - [M_rname] - [M_key] ([M_job])</b>
|
||||
</a>
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
// Do not attemtp to remove the blank string from the server arg. It will break DB saving.
|
||||
/proc/add_note(target_ckey, notetext, timestamp, adminckey, logged = 1, server = "", checkrights = 1, show_after = TRUE, automated = FALSE)
|
||||
/proc/add_note(target_ckey, notetext, timestamp, adminckey, logged = 1, checkrights = 1, show_after = TRUE, automated = FALSE)
|
||||
if(checkrights && !check_rights(R_ADMIN|R_MOD))
|
||||
return
|
||||
if(!SSdbcore.IsConnected())
|
||||
@@ -53,10 +52,6 @@
|
||||
else if(usr && (usr.ckey == ckey(adminckey))) // Don't ckeyize special note sources
|
||||
adminckey = ckey(adminckey)
|
||||
|
||||
if(!server)
|
||||
if(GLOB.configuration.general.server_name)
|
||||
server = GLOB.configuration.general.server_name
|
||||
|
||||
// Force cast this to 1/0 incase someone tries to feed bad data
|
||||
automated = !!automated
|
||||
|
||||
@@ -67,7 +62,7 @@
|
||||
"targetckey" = target_ckey,
|
||||
"notetext" = notetext,
|
||||
"adminkey" = adminckey,
|
||||
"server" = server,
|
||||
"server" = GLOB.configuration.system.instance_id,
|
||||
"crewnum" = crew_number,
|
||||
"roundid" = GLOB.round_id,
|
||||
"automated" = automated
|
||||
|
||||
@@ -47,16 +47,8 @@ GLOBAL_LIST_INIT(adminhelp_ignored_words, list("unknown", "the", "a", "an", "of"
|
||||
SSdiscord.send2discord_simple_noadmins("**\[Adminhelp]** [key_name(src)]: [msg]", check_send_always = TRUE)
|
||||
|
||||
if("Mentorhelp")
|
||||
var/alerttext
|
||||
var/list/mentorcount = staff_countup(R_MENTOR)
|
||||
var/active_mentors = mentorcount[1]
|
||||
var/inactive_mentors = mentorcount[3]
|
||||
|
||||
if(active_mentors <= 0)
|
||||
if(inactive_mentors)
|
||||
alerttext = " | **ALL MENTORS AFK**"
|
||||
else
|
||||
alerttext = " | **NO MENTORS ONLINE**"
|
||||
|
||||
log_admin("[selected_type]: [key_name(src)]: [msg] - heard by [active_mentors] non-AFK mentors.")
|
||||
SSdiscord.send2discord_simple(DISCORD_WEBHOOK_MENTOR, "[key_name(src)]: [msg][alerttext]")
|
||||
SSdiscord.send2discord_simple_mentor("[key_name(src)]: [msg]")
|
||||
|
||||
@@ -357,8 +357,8 @@ GLOBAL_PROTECT(AdminProcCallSpamPrevention)
|
||||
pai.real_name = pai.name
|
||||
pai.key = choice.key
|
||||
card.setPersonality(pai)
|
||||
for(var/datum/paiCandidate/candidate in GLOB.paiController.pai_candidates)
|
||||
if(candidate.key == choice.key)
|
||||
for(var/datum/pai_save/candidate in GLOB.paiController.pai_candidates)
|
||||
if(candidate.owner.ckey == choice.ckey)
|
||||
GLOB.paiController.pai_candidates.Remove(candidate)
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Make pAI") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
// GSAY
|
||||
// Like asay but global between instances!
|
||||
// *Insert changeling hivemind :g joke here*
|
||||
|
||||
/client/proc/gsay(msg as text)
|
||||
set name = "gsay"
|
||||
set hidden = TRUE
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
|
||||
if(!msg)
|
||||
return
|
||||
msg = sanitize(copytext(msg, 1, MAX_MESSAGE_LEN))
|
||||
|
||||
// To whoever says "Why dont you just topic the full message with formatting"
|
||||
// This lets us use this in other apps, like a discord bot, without HTML parsing
|
||||
// It also removes a way to put whatever HTML we want in the chat window
|
||||
var/built_topic = "gsay&msg=[url_encode(msg)]&usr=[url_encode(usr.ckey)]&src=[url_encode(GLOB.configuration.system.instance_id)]"
|
||||
|
||||
// Send to peers
|
||||
SSinstancing.topic_all_peers(built_topic)
|
||||
// Send to online admins
|
||||
for(var/client/C in GLOB.admins)
|
||||
if(R_ADMIN & C.holder.rights)
|
||||
to_chat(C, "<span class='admin_channel'>GSAY: [usr.ckey]@[GLOB.configuration.system.instance_id]: [msg]</span>")
|
||||
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "gsay") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
@@ -203,7 +203,7 @@
|
||||
|
||||
log_world("### MassVarEdit by [src]: [O.type] (A/R [accepted]/[rejected]) [variable]=[html_encode("[O.vars[variable]]")]([list2params(value)])")
|
||||
log_admin("[key_name(src)] mass modified [original_name]'s [variable] to [O.vars[variable]] ([accepted] objects modified)")
|
||||
message_admins("[key_name_admin(src)] mass modified [original_name]'s [variable] to [O.vars[variable]] ([accepted] objects modified)")
|
||||
message_admins("[key_name_admin(src)] mass modified [original_name]'s [variable] to [html_encode("[O.vars[variable]]")] ([accepted] objects modified)")
|
||||
|
||||
/proc/get_all_of_type(T, subtypes = TRUE)
|
||||
var/list/typecache = list()
|
||||
|
||||
@@ -355,7 +355,7 @@ GLOBAL_LIST_INIT(VVpixelmovement, list("step_x", "step_y", "step_size", "bound_h
|
||||
return
|
||||
log_world("### ListVarEdit by [src]: [(O ? O.type : "/list")] [objectvar]: ADDED=[var_value]")
|
||||
log_admin("[key_name(src)] modified [original_name]'s [objectvar]: ADDED=[var_value]")
|
||||
message_admins("[key_name_admin(src)] modified [original_name]'s [objectvar]: ADDED=[var_value]")
|
||||
message_admins("[key_name_admin(src)] modified [original_name]'s [objectvar]: ADDED=[html_encode("[var_value]")]")
|
||||
|
||||
/client/proc/mod_list(list/L, atom/O, original_name, objectvar, index, autodetect_class = FALSE)
|
||||
if(!check_rights(R_VAREDIT))
|
||||
@@ -495,7 +495,7 @@ GLOBAL_LIST_INIT(VVpixelmovement, list("step_x", "step_y", "step_size", "bound_h
|
||||
return
|
||||
log_world("### ListVarEdit by [src]: [O.type] [objectvar]: REMOVED=[html_encode("[original_var]")]")
|
||||
log_admin("[key_name(src)] modified [original_name]'s [objectvar]: REMOVED=[original_var]")
|
||||
message_admins("[key_name_admin(src)] modified [original_name]'s [objectvar]: REMOVED=[original_var]")
|
||||
message_admins("[key_name_admin(src)] modified [original_name]'s [objectvar]: REMOVED=[html_encode("[original_var]")]")
|
||||
return
|
||||
|
||||
if(VV_TEXT)
|
||||
@@ -514,7 +514,7 @@ GLOBAL_LIST_INIT(VVpixelmovement, list("step_x", "step_y", "step_size", "bound_h
|
||||
return
|
||||
log_world("### ListVarEdit by [src]: [(O ? O.type : "/list")] [objectvar]: [original_var]=[new_var]")
|
||||
log_admin("[key_name(src)] modified [original_name]'s [objectvar]: [original_var]=[new_var]")
|
||||
message_admins("[key_name_admin(src)] modified [original_name]'s varlist [objectvar]: [original_var]=[new_var]")
|
||||
message_admins("[key_name_admin(src)] modified [original_name]'s varlist [objectvar]: [original_var]=[html_encode("[new_var]")]")
|
||||
|
||||
/proc/vv_varname_lockcheck(param_var_name)
|
||||
if(param_var_name in GLOB.VVlocked)
|
||||
@@ -630,5 +630,5 @@ GLOBAL_LIST_INIT(VVpixelmovement, list("step_x", "step_y", "step_size", "bound_h
|
||||
SEND_GLOBAL_SIGNAL(COMSIG_GLOB_VAR_EDIT, args)
|
||||
log_world("### VarEdit by [src]: [O.type] [variable]=[html_encode("[var_new]")]")
|
||||
log_admin("[key_name(src)] modified [original_name]'s [variable] to [var_new]")
|
||||
var/msg = "[key_name_admin(src)] modified [original_name]'s [variable] to [var_new]"
|
||||
var/msg = "[key_name_admin(src)] modified [original_name]'s [variable] to [html_encode("[var_new]")]"
|
||||
message_admins(msg)
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
/client/proc/view_instances()
|
||||
set name = "View Server Instances"
|
||||
set desc = "View the running server instances"
|
||||
set category = "Server"
|
||||
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
|
||||
to_chat(usr, "<b>Server instances info</b>")
|
||||
var/datum/db_query/dbq1 = SSdbcore.NewQuery({"
|
||||
SELECT server_id, key_name, key_value FROM instance_data_cache WHERE server_id IN
|
||||
(SELECT server_id FROM instance_data_cache WHERE
|
||||
key_name='heartbeat' AND last_updated BETWEEN NOW() - INTERVAL 60 SECOND AND NOW())
|
||||
AND key_name IN ("playercount")"})
|
||||
if(!dbq1.warn_execute())
|
||||
qdel(dbq1)
|
||||
return
|
||||
|
||||
var/servers_outer = list()
|
||||
while(dbq1.NextRow())
|
||||
if(!servers_outer[dbq1.item[1]])
|
||||
servers_outer[dbq1.item[1]] = list()
|
||||
|
||||
servers_outer[dbq1.item[1]][dbq1.item[2]] = dbq1.item[3] // This should assoc load our data
|
||||
|
||||
qdel(dbq1)
|
||||
|
||||
for(var/server in servers_outer)
|
||||
var/server_data = servers_outer[server]
|
||||
var/players = text2num(server_data["playercount"])
|
||||
|
||||
to_chat(usr, "<code>[server]</code> - [players] player[players == 1 ? "" : "s"] online.")
|
||||
to_chat(usr, "<i>Offline instances are not reported</i>")
|
||||
Reference in New Issue
Block a user