@@ -0,0 +1,987 @@
|
||||
|
||||
////////////////////////////////
|
||||
/proc/message_admins(msg)
|
||||
msg = "<span class=\"admin\"><span class=\"prefix\">ADMIN LOG:</span> <span class=\"message linkify\">[msg]</span></span>"
|
||||
to_chat(GLOB.admins, msg)
|
||||
|
||||
/proc/relay_msg_admins(msg)
|
||||
msg = "<span class=\"admin\"><span class=\"prefix\">RELAY:</span> <span class=\"message linkify\">[msg]</span></span>"
|
||||
to_chat(GLOB.admins, msg)
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////Panels
|
||||
|
||||
/datum/admins/proc/show_player_panel(mob/M in GLOB.mob_list)
|
||||
set category = "Admin"
|
||||
set name = "Show Player Panel"
|
||||
set desc="Edit player (respawn, ban, heal, etc)"
|
||||
|
||||
if(!check_rights())
|
||||
return
|
||||
|
||||
log_admin("[key_name(usr)] checked the individual player panel for [key_name(M)][isobserver(usr)?"":" while in game"].")
|
||||
|
||||
if(!M)
|
||||
to_chat(usr, "You seem to be selecting a mob that doesn't exist anymore.")
|
||||
return
|
||||
|
||||
var/body = "<html><head><title>Options for [M.key]</title></head>"
|
||||
body += "<body>Options panel for <b>[M]</b>"
|
||||
if(M.client)
|
||||
body += " played by <b>[M.client]</b> "
|
||||
body += "\[<A href='?_src_=holder;[HrefToken()];editrights=[(GLOB.admin_datums[M.client.ckey] || GLOB.deadmins[M.client.ckey]) ? "rank" : "add"];key=[M.key]'>[M.client.holder ? M.client.holder.rank : "Player"]</A>\]"
|
||||
if(CONFIG_GET(flag/use_exp_tracking))
|
||||
body += "\[<A href='?_src_=holder;[HrefToken()];getplaytimewindow=[REF(M)]'>" + M.client.get_exp_living() + "</a>\]"
|
||||
|
||||
if(isnewplayer(M))
|
||||
body += " <B>Hasn't Entered Game</B> "
|
||||
else
|
||||
body += " \[<A href='?_src_=holder;[HrefToken()];revive=[REF(M)]'>Heal</A>\] "
|
||||
|
||||
if(M.client)
|
||||
body += "<br>\[<b>First Seen:</b> [M.client.player_join_date]\]\[<b>Byond account registered on:</b> [M.client.account_join_date]\]"
|
||||
body += "<br><br><b>Show related accounts by:</b> "
|
||||
body += "\[ <a href='?_src_=holder;[HrefToken()];showrelatedacc=cid;client=[REF(M.client)]'>CID</a> | "
|
||||
body += "<a href='?_src_=holder;[HrefToken()];showrelatedacc=ip;client=[REF(M.client)]'>IP</a> \]"
|
||||
var/rep = 0
|
||||
rep += SSpersistence.antag_rep[M.ckey]
|
||||
body += "<br><br>Antagonist reputation: [rep]"
|
||||
body += "<br><a href='?_src_=holder;[HrefToken()];modantagrep=add;mob=[REF(M)]'>\[increase\]</a> "
|
||||
body += "<a href='?_src_=holder;[HrefToken()];modantagrep=subtract;mob=[REF(M)]'>\[decrease\]</a> "
|
||||
body += "<a href='?_src_=holder;[HrefToken()];modantagrep=set;mob=[REF(M)]'>\[set\]</a> "
|
||||
body += "<a href='?_src_=holder;[HrefToken()];modantagrep=zero;mob=[REF(M)]'>\[zero\]</a>"
|
||||
var/full_version = "Unknown"
|
||||
if(M.client.byond_version)
|
||||
full_version = "[M.client.byond_version].[M.client.byond_build ? M.client.byond_build : "xxx"]"
|
||||
body += "<br>\[<b>Byond version:</b> [full_version]\]<br>"
|
||||
|
||||
|
||||
body += "<br><br>\[ "
|
||||
body += "<a href='?_src_=vars;[HrefToken()];Vars=[REF(M)]'>VV</a> - "
|
||||
if(M.mind)
|
||||
body += "<a href='?_src_=holder;[HrefToken()];traitor=[REF(M)]'>TP</a> - "
|
||||
else
|
||||
body += "<a href='?_src_=holder;[HrefToken()];initmind=[REF(M)]'>Init Mind</a> - "
|
||||
if (iscyborg(M))
|
||||
body += "<a href='?_src_=holder;[HrefToken()];borgpanel=[REF(M)]'>BP</a> - "
|
||||
body += "<a href='?priv_msg=[M.ckey]'>PM</a> - "
|
||||
body += "<a href='?_src_=holder;[HrefToken()];subtlemessage=[REF(M)]'>SM</a> - "
|
||||
if (ishuman(M) && M.mind)
|
||||
body += "<a href='?_src_=holder;[HrefToken()];HeadsetMessage=[REF(M)]'>HM</a> - "
|
||||
body += "<a href='?_src_=holder;[HrefToken()];adminplayerobservefollow=[REF(M)]'>FLW</a> - "
|
||||
//Default to client logs if available
|
||||
var/source = LOGSRC_MOB
|
||||
if(M.client)
|
||||
source = LOGSRC_CLIENT
|
||||
body += "<a href='?_src_=holder;[HrefToken()];individuallog=[REF(M)];log_src=[source]'>LOGS</a>\] <br>"
|
||||
|
||||
body += "<b>Mob type</b> = [M.type]<br><br>"
|
||||
|
||||
body += "<A href='?_src_=holder;[HrefToken()];boot2=[REF(M)]'>Kick</A> | "
|
||||
body += "<A href='?_src_=holder;[HrefToken()];newban=[REF(M)]'>Ban</A> | "
|
||||
body += "<A href='?_src_=holder;[HrefToken()];jobban2=[REF(M)]'>Jobban</A> | "
|
||||
body += "<A href='?_src_=holder;[HrefToken()];appearanceban=[REF(M)]'>Identity Ban</A> | "
|
||||
var/rm = REF(M)
|
||||
if(jobban_isbanned(M, "OOC"))
|
||||
body+= "<A href='?_src_=holder;[HrefToken()];jobban3=OOC;jobban4=[rm]'><font color=red>OOCBan</font></A> | "
|
||||
else
|
||||
body+= "<A href='?_src_=holder;[HrefToken()];jobban3=OOC;jobban4=[rm]'>OOCBan</A> | "
|
||||
if(QDELETED(M) || QDELETED(usr))
|
||||
return
|
||||
if(jobban_isbanned(M, "emote"))
|
||||
body+= "<A href='?_src_=holder;[HrefToken()];jobban3=emote;jobban4=[rm]'><font color=red>EmoteBan</font></A> | "
|
||||
else
|
||||
body+= "<A href='?_src_=holder;[HrefToken()];jobban3=emote;jobban4=[rm]'>Emoteban</A> | "
|
||||
if(QDELETED(M) || QDELETED(usr))
|
||||
return
|
||||
|
||||
body += "<A href='?_src_=holder;[HrefToken()];showmessageckey=[M.ckey]'>Notes | Messages | Watchlist</A> | "
|
||||
if(M.client)
|
||||
body += "| <A href='?_src_=holder;[HrefToken()];sendtoprison=[REF(M)]'>Prison</A> | "
|
||||
body += "\ <A href='?_src_=holder;[HrefToken()];sendbacktolobby=[REF(M)]'>Send back to Lobby</A> | "
|
||||
var/muted = M.client.prefs.muted
|
||||
body += "<br><b>Mute: </b> "
|
||||
body += "\[<A href='?_src_=holder;[HrefToken()];mute=[M.ckey];mute_type=[MUTE_IC]'><font color='[(muted & MUTE_IC)?"red":"blue"]'>IC</font></a> | "
|
||||
body += "<A href='?_src_=holder;[HrefToken()];mute=[M.ckey];mute_type=[MUTE_OOC]'><font color='[(muted & MUTE_OOC)?"red":"blue"]'>OOC</font></a> | "
|
||||
body += "<A href='?_src_=holder;[HrefToken()];mute=[M.ckey];mute_type=[MUTE_PRAY]'><font color='[(muted & MUTE_PRAY)?"red":"blue"]'>PRAY</font></a> | "
|
||||
body += "<A href='?_src_=holder;[HrefToken()];mute=[M.ckey];mute_type=[MUTE_ADMINHELP]'><font color='[(muted & MUTE_ADMINHELP)?"red":"blue"]'>ADMINHELP</font></a> | "
|
||||
body += "<A href='?_src_=holder;[HrefToken()];mute=[M.ckey];mute_type=[MUTE_DEADCHAT]'><font color='[(muted & MUTE_DEADCHAT)?"red":"blue"]'>DEADCHAT</font></a>\]"
|
||||
body += "(<A href='?_src_=holder;[HrefToken()];mute=[M.ckey];mute_type=[MUTE_ALL]'><font color='[(muted & MUTE_ALL)?"red":"blue"]'>toggle all</font></a>)"
|
||||
|
||||
body += "<br><br>"
|
||||
body += "<A href='?_src_=holder;[HrefToken()];jumpto=[REF(M)]'><b>Jump to</b></A> | "
|
||||
body += "<A href='?_src_=holder;[HrefToken()];getmob=[REF(M)]'>Get</A> | "
|
||||
body += "<A href='?_src_=holder;[HrefToken()];sendmob=[REF(M)]'>Send To</A>"
|
||||
|
||||
body += "<br><br>"
|
||||
body += "<A href='?_src_=holder;[HrefToken()];traitor=[REF(M)]'>Traitor panel</A> | "
|
||||
body += "<A href='?_src_=holder;[HrefToken()];narrateto=[REF(M)]'>Narrate to</A> | "
|
||||
body += "<A href='?_src_=holder;[HrefToken()];subtlemessage=[REF(M)]'>Subtle message</A> | "
|
||||
body += "<A href='?_src_=holder;[HrefToken()];languagemenu=[REF(M)]'>Language Menu</A>"
|
||||
|
||||
if (M.client)
|
||||
if(!isnewplayer(M))
|
||||
body += "<br><br>"
|
||||
body += "<b>Transformation:</b>"
|
||||
body += "<br>"
|
||||
|
||||
//Human
|
||||
if(ishuman(M))
|
||||
body += "<B>Human</B> | "
|
||||
else
|
||||
body += "<A href='?_src_=holder;[HrefToken()];humanone=[REF(M)]'>Humanize</A> | "
|
||||
|
||||
//Monkey
|
||||
if(ismonkey(M))
|
||||
body += "<B>Monkeyized</B> | "
|
||||
else
|
||||
body += "<A href='?_src_=holder;[HrefToken()];monkeyone=[REF(M)]'>Monkeyize</A> | "
|
||||
|
||||
//Corgi
|
||||
if(iscorgi(M))
|
||||
body += "<B>Corgized</B> | "
|
||||
else
|
||||
body += "<A href='?_src_=holder;[HrefToken()];corgione=[REF(M)]'>Corgize</A> | "
|
||||
|
||||
//AI / Cyborg
|
||||
if(isAI(M))
|
||||
body += "<B>Is an AI</B> "
|
||||
else if(ishuman(M))
|
||||
body += "<A href='?_src_=holder;[HrefToken()];makeai=[REF(M)]'>Make AI</A> | "
|
||||
body += "<A href='?_src_=holder;[HrefToken()];makerobot=[REF(M)]'>Make Robot</A> | "
|
||||
body += "<A href='?_src_=holder;[HrefToken()];makealien=[REF(M)]'>Make Alien</A> | "
|
||||
body += "<A href='?_src_=holder;[HrefToken()];makeslime=[REF(M)]'>Make Slime</A> | "
|
||||
body += "<A href='?_src_=holder;[HrefToken()];makeblob=[REF(M)]'>Make Blob</A> | "
|
||||
|
||||
//Simple Animals
|
||||
if(isanimal(M))
|
||||
body += "<A href='?_src_=holder;[HrefToken()];makeanimal=[REF(M)]'>Re-Animalize</A> | "
|
||||
else
|
||||
body += "<A href='?_src_=holder;[HrefToken()];makeanimal=[REF(M)]'>Animalize</A> | "
|
||||
|
||||
body += "<br><br>"
|
||||
body += "<b>Rudimentary transformation:</b><font size=2><br>These transformations only create a new mob type and copy stuff over. They do not take into account MMIs and similar mob-specific things. The buttons in 'Transformations' are preferred, when possible.</font><br>"
|
||||
body += "<A href='?_src_=holder;[HrefToken()];simplemake=observer;mob=[REF(M)]'>Observer</A> | "
|
||||
body += "\[ Alien: <A href='?_src_=holder;[HrefToken()];simplemake=drone;mob=[REF(M)]'>Drone</A>, "
|
||||
body += "<A href='?_src_=holder;[HrefToken()];simplemake=hunter;mob=[REF(M)]'>Hunter</A>, "
|
||||
body += "<A href='?_src_=holder;[HrefToken()];simplemake=sentinel;mob=[REF(M)]'>Sentinel</A>, "
|
||||
body += "<A href='?_src_=holder;[HrefToken()];simplemake=praetorian;mob=[REF(M)]'>Praetorian</A>, "
|
||||
body += "<A href='?_src_=holder;[HrefToken()];simplemake=queen;mob=[REF(M)]'>Queen</A>, "
|
||||
body += "<A href='?_src_=holder;[HrefToken()];simplemake=larva;mob=[REF(M)]'>Larva</A> \] "
|
||||
body += "<A href='?_src_=holder;[HrefToken()];simplemake=human;mob=[REF(M)]'>Human</A> "
|
||||
body += "\[ slime: <A href='?_src_=holder;[HrefToken()];simplemake=slime;mob=[REF(M)]'>Baby</A>, "
|
||||
body += "<A href='?_src_=holder;[HrefToken()];simplemake=adultslime;mob=[REF(M)]'>Adult</A> \] "
|
||||
body += "<A href='?_src_=holder;[HrefToken()];simplemake=monkey;mob=[REF(M)]'>Monkey</A> | "
|
||||
body += "<A href='?_src_=holder;[HrefToken()];simplemake=robot;mob=[REF(M)]'>Cyborg</A> | "
|
||||
body += "<A href='?_src_=holder;[HrefToken()];simplemake=cat;mob=[REF(M)]'>Cat</A> | "
|
||||
body += "<A href='?_src_=holder;[HrefToken()];simplemake=runtime;mob=[REF(M)]'>Runtime</A> | "
|
||||
body += "<A href='?_src_=holder;[HrefToken()];simplemake=corgi;mob=[REF(M)]'>Corgi</A> | "
|
||||
body += "<A href='?_src_=holder;[HrefToken()];simplemake=ian;mob=[REF(M)]'>Ian</A> | "
|
||||
body += "<A href='?_src_=holder;[HrefToken()];simplemake=crab;mob=[REF(M)]'>Crab</A> | "
|
||||
body += "<A href='?_src_=holder;[HrefToken()];simplemake=coffee;mob=[REF(M)]'>Coffee</A> | "
|
||||
body += "\[ Construct: <A href='?_src_=holder;[HrefToken()];simplemake=constructarmored;mob=[REF(M)]'>Juggernaut</A> , "
|
||||
body += "<A href='?_src_=holder;[HrefToken()];simplemake=constructbuilder;mob=[REF(M)]'>Artificer</A> , "
|
||||
body += "<A href='?_src_=holder;[HrefToken()];simplemake=constructwraith;mob=[REF(M)]'>Wraith</A> \] "
|
||||
body += "<A href='?_src_=holder;[HrefToken()];simplemake=shade;mob=[REF(M)]'>Shade</A>"
|
||||
body += "<br>"
|
||||
|
||||
if (M.client)
|
||||
body += "<br><br>"
|
||||
body += "<b>Other actions:</b>"
|
||||
body += "<br>"
|
||||
body += "<A href='?_src_=holder;[HrefToken()];forcespeech=[REF(M)]'>Forcesay</A> | "
|
||||
body += "<A href='?_src_=holder;[HrefToken()];tdome1=[REF(M)]'>Thunderdome 1</A> | "
|
||||
body += "<A href='?_src_=holder;[HrefToken()];tdome2=[REF(M)]'>Thunderdome 2</A> | "
|
||||
body += "<A href='?_src_=holder;[HrefToken()];tdomeadmin=[REF(M)]'>Thunderdome Admin</A> | "
|
||||
body += "<A href='?_src_=holder;[HrefToken()];tdomeobserve=[REF(M)]'>Thunderdome Observer</A> | "
|
||||
|
||||
body += usr.client.citaPPoptions(M) // CITADEL
|
||||
|
||||
body += "<br>"
|
||||
body += "</body></html>"
|
||||
|
||||
usr << browse(body, "window=adminplayeropts-[REF(M)];size=550x515")
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Player Panel") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
|
||||
/datum/admins/proc/access_news_network() //MARKER
|
||||
set category = "Fun"
|
||||
set name = "Access Newscaster Network"
|
||||
set desc = "Allows you to view, add and edit news feeds."
|
||||
|
||||
if (!istype(src, /datum/admins))
|
||||
src = usr.client.holder
|
||||
if (!istype(src, /datum/admins))
|
||||
to_chat(usr, "Error: you are not an admin!")
|
||||
return
|
||||
var/dat
|
||||
dat = text("<HEAD><TITLE>Admin Newscaster</TITLE></HEAD><H3>Admin Newscaster Unit</H3>")
|
||||
|
||||
switch(admincaster_screen)
|
||||
if(0)
|
||||
dat += "Welcome to the admin newscaster.<BR> Here you can add, edit and censor every newspiece on the network."
|
||||
dat += "<BR>Feed channels and stories entered through here will be uneditable and handled as official news by the rest of the units."
|
||||
dat += "<BR>Note that this panel allows full freedom over the news network, there are no constrictions except the few basic ones. Don't break things!</FONT>"
|
||||
if(GLOB.news_network.wanted_issue.active)
|
||||
dat+= "<HR><A href='?src=[REF(src)];[HrefToken()];ac_view_wanted=1'>Read Wanted Issue</A>"
|
||||
dat+= "<HR><BR><A href='?src=[REF(src)];[HrefToken()];ac_create_channel=1'>Create Feed Channel</A>"
|
||||
dat+= "<BR><A href='?src=[REF(src)];[HrefToken()];ac_view=1'>View Feed Channels</A>"
|
||||
dat+= "<BR><A href='?src=[REF(src)];[HrefToken()];ac_create_feed_story=1'>Submit new Feed story</A>"
|
||||
dat+= "<BR><BR><A href='?src=[REF(usr)];[HrefToken()];mach_close=newscaster_main'>Exit</A>"
|
||||
var/wanted_already = 0
|
||||
if(GLOB.news_network.wanted_issue.active)
|
||||
wanted_already = 1
|
||||
dat+="<HR><B>Feed Security functions:</B><BR>"
|
||||
dat+="<BR><A href='?src=[REF(src)];[HrefToken()];ac_menu_wanted=1'>[(wanted_already) ? ("Manage") : ("Publish")] \"Wanted\" Issue</A>"
|
||||
dat+="<BR><A href='?src=[REF(src)];[HrefToken()];ac_menu_censor_story=1'>Censor Feed Stories</A>"
|
||||
dat+="<BR><A href='?src=[REF(src)];[HrefToken()];ac_menu_censor_channel=1'>Mark Feed Channel with Nanotrasen D-Notice (disables and locks the channel).</A>"
|
||||
dat+="<BR><HR><A href='?src=[REF(src)];[HrefToken()];ac_set_signature=1'>The newscaster recognises you as:<BR> <FONT COLOR='green'>[src.admin_signature]</FONT></A>"
|
||||
if(1)
|
||||
dat+= "Station Feed Channels<HR>"
|
||||
if( isemptylist(GLOB.news_network.network_channels) )
|
||||
dat+="<I>No active channels found...</I>"
|
||||
else
|
||||
for(var/datum/newscaster/feed_channel/CHANNEL in GLOB.news_network.network_channels)
|
||||
if(CHANNEL.is_admin_channel)
|
||||
dat+="<B><FONT style='BACKGROUND-COLOR: LightGreen'><A href='?src=[REF(src)];ac_show_channel=[REF(CHANNEL)]'>[CHANNEL.channel_name]</A></FONT></B><BR>"
|
||||
else
|
||||
dat+="<B><A href='?src=[REF(src)];[HrefToken()];ac_show_channel=[REF(CHANNEL)]'>[CHANNEL.channel_name]</A> [(CHANNEL.censored) ? ("<FONT COLOR='red'>***</FONT>") : ""]<BR></B>"
|
||||
dat+="<BR><HR><A href='?src=[REF(src)];[HrefToken()];ac_refresh=1'>Refresh</A>"
|
||||
dat+="<BR><A href='?src=[REF(src)];[HrefToken()];ac_setScreen=[0]'>Back</A>"
|
||||
if(2)
|
||||
dat+="Creating new Feed Channel..."
|
||||
dat+="<HR><B><A href='?src=[REF(src)];[HrefToken()];ac_set_channel_name=1'>Channel Name</A>:</B> [src.admincaster_feed_channel.channel_name]<BR>"
|
||||
dat+="<B><A href='?src=[REF(src)];[HrefToken()];ac_set_signature=1'>Channel Author</A>:</B> <FONT COLOR='green'>[src.admin_signature]</FONT><BR>"
|
||||
dat+="<B><A href='?src=[REF(src)];[HrefToken()];ac_set_channel_lock=1'>Will Accept Public Feeds</A>:</B> [(src.admincaster_feed_channel.locked) ? ("NO") : ("YES")]<BR><BR>"
|
||||
dat+="<BR><A href='?src=[REF(src)];[HrefToken()];ac_submit_new_channel=1'>Submit</A><BR><BR><A href='?src=[REF(src)];[HrefToken()];ac_setScreen=[0]'>Cancel</A><BR>"
|
||||
if(3)
|
||||
dat+="Creating new Feed Message..."
|
||||
dat+="<HR><B><A href='?src=[REF(src)];[HrefToken()];ac_set_channel_receiving=1'>Receiving Channel</A>:</B> [src.admincaster_feed_channel.channel_name]<BR>" //MARK
|
||||
dat+="<B>Message Author:</B> <FONT COLOR='green'>[src.admin_signature]</FONT><BR>"
|
||||
dat+="<B><A href='?src=[REF(src)];[HrefToken()];ac_set_new_message=1'>Message Body</A>:</B> [src.admincaster_feed_message.returnBody(-1)] <BR>"
|
||||
dat+="<BR><A href='?src=[REF(src)];[HrefToken()];ac_submit_new_message=1'>Submit</A><BR><BR><A href='?src=[REF(src)];[HrefToken()];ac_setScreen=[0]'>Cancel</A><BR>"
|
||||
if(4)
|
||||
dat+="Feed story successfully submitted to [src.admincaster_feed_channel.channel_name].<BR><BR>"
|
||||
dat+="<BR><A href='?src=[REF(src)];[HrefToken()];ac_setScreen=[0]'>Return</A><BR>"
|
||||
if(5)
|
||||
dat+="Feed Channel [src.admincaster_feed_channel.channel_name] created successfully.<BR><BR>"
|
||||
dat+="<BR><A href='?src=[REF(src)];[HrefToken()];ac_setScreen=[0]'>Return</A><BR>"
|
||||
if(6)
|
||||
dat+="<B><FONT COLOR='maroon'>ERROR: Could not submit Feed story to Network.</B></FONT><HR><BR>"
|
||||
if(src.admincaster_feed_channel.channel_name=="")
|
||||
dat+="<FONT COLOR='maroon'>Invalid receiving channel name.</FONT><BR>"
|
||||
if(src.admincaster_feed_message.returnBody(-1) == "" || src.admincaster_feed_message.returnBody(-1) == "\[REDACTED\]")
|
||||
dat+="<FONT COLOR='maroon'>Invalid message body.</FONT><BR>"
|
||||
dat+="<BR><A href='?src=[REF(src)];[HrefToken()];ac_setScreen=[3]'>Return</A><BR>"
|
||||
if(7)
|
||||
dat+="<B><FONT COLOR='maroon'>ERROR: Could not submit Feed Channel to Network.</B></FONT><HR><BR>"
|
||||
if(src.admincaster_feed_channel.channel_name =="" || src.admincaster_feed_channel.channel_name == "\[REDACTED\]")
|
||||
dat+="<FONT COLOR='maroon'>Invalid channel name.</FONT><BR>"
|
||||
var/check = 0
|
||||
for(var/datum/newscaster/feed_channel/FC in GLOB.news_network.network_channels)
|
||||
if(FC.channel_name == src.admincaster_feed_channel.channel_name)
|
||||
check = 1
|
||||
break
|
||||
if(check)
|
||||
dat+="<FONT COLOR='maroon'>Channel name already in use.</FONT><BR>"
|
||||
dat+="<BR><A href='?src=[REF(src)];[HrefToken()];ac_setScreen=[2]'>Return</A><BR>"
|
||||
if(9)
|
||||
dat+="<B>[admincaster_feed_channel.channel_name]: </B><FONT SIZE=1>\[created by: <FONT COLOR='maroon'>[admincaster_feed_channel.returnAuthor(-1)]</FONT>\]</FONT><HR>"
|
||||
if(src.admincaster_feed_channel.censored)
|
||||
dat+="<FONT COLOR='red'><B>ATTENTION: </B></FONT>This channel has been deemed as threatening to the welfare of the station, and marked with a Nanotrasen D-Notice.<BR>"
|
||||
dat+="No further feed story additions are allowed while the D-Notice is in effect.</FONT><BR><BR>"
|
||||
else
|
||||
if( isemptylist(src.admincaster_feed_channel.messages) )
|
||||
dat+="<I>No feed messages found in channel...</I><BR>"
|
||||
else
|
||||
var/i = 0
|
||||
for(var/datum/newscaster/feed_message/MESSAGE in src.admincaster_feed_channel.messages)
|
||||
i++
|
||||
dat+="-[MESSAGE.returnBody(-1)] <BR>"
|
||||
if(MESSAGE.img)
|
||||
usr << browse_rsc(MESSAGE.img, "tmp_photo[i].png")
|
||||
dat+="<img src='tmp_photo[i].png' width = '180'><BR><BR>"
|
||||
dat+="<FONT SIZE=1>\[Story by <FONT COLOR='maroon'>[MESSAGE.returnAuthor(-1)]</FONT>\]</FONT><BR>"
|
||||
dat+="[MESSAGE.comments.len] comment[MESSAGE.comments.len > 1 ? "s" : ""]:<br>"
|
||||
for(var/datum/newscaster/feed_comment/comment in MESSAGE.comments)
|
||||
dat+="[comment.body]<br><font size=1>[comment.author] [comment.time_stamp]</font><br>"
|
||||
dat+="<br>"
|
||||
dat+="<BR><HR><A href='?src=[REF(src)];[HrefToken()];ac_refresh=1'>Refresh</A>"
|
||||
dat+="<BR><A href='?src=[REF(src)];[HrefToken()];ac_setScreen=[1]'>Back</A>"
|
||||
if(10)
|
||||
dat+="<B>Nanotrasen Feed Censorship Tool</B><BR>"
|
||||
dat+="<FONT SIZE=1>NOTE: Due to the nature of news Feeds, total deletion of a Feed Story is not possible.<BR>"
|
||||
dat+="Keep in mind that users attempting to view a censored feed will instead see the \[REDACTED\] tag above it.</FONT>"
|
||||
dat+="<HR>Select Feed channel to get Stories from:<BR>"
|
||||
if(isemptylist(GLOB.news_network.network_channels))
|
||||
dat+="<I>No feed channels found active...</I><BR>"
|
||||
else
|
||||
for(var/datum/newscaster/feed_channel/CHANNEL in GLOB.news_network.network_channels)
|
||||
dat+="<A href='?src=[REF(src)];[HrefToken()];ac_pick_censor_channel=[REF(CHANNEL)]'>[CHANNEL.channel_name]</A> [(CHANNEL.censored) ? ("<FONT COLOR='red'>***</FONT>") : ""]<BR>"
|
||||
dat+="<BR><A href='?src=[REF(src)];[HrefToken()];ac_setScreen=[0]'>Cancel</A>"
|
||||
if(11)
|
||||
dat+="<B>Nanotrasen D-Notice Handler</B><HR>"
|
||||
dat+="<FONT SIZE=1>A D-Notice is to be bestowed upon the channel if the handling Authority deems it as harmful for the station's"
|
||||
dat+="morale, integrity or disciplinary behaviour. A D-Notice will render a channel unable to be updated by anyone, without deleting any feed"
|
||||
dat+="stories it might contain at the time. You can lift a D-Notice if you have the required access at any time.</FONT><HR>"
|
||||
if(isemptylist(GLOB.news_network.network_channels))
|
||||
dat+="<I>No feed channels found active...</I><BR>"
|
||||
else
|
||||
for(var/datum/newscaster/feed_channel/CHANNEL in GLOB.news_network.network_channels)
|
||||
dat+="<A href='?src=[REF(src)];[HrefToken()];ac_pick_d_notice=[REF(CHANNEL)]'>[CHANNEL.channel_name]</A> [(CHANNEL.censored) ? ("<FONT COLOR='red'>***</FONT>") : ""]<BR>"
|
||||
|
||||
dat+="<BR><A href='?src=[REF(src)];[HrefToken()];ac_setScreen=[0]'>Back</A>"
|
||||
if(12)
|
||||
dat+="<B>[src.admincaster_feed_channel.channel_name]: </B><FONT SIZE=1>\[ created by: <FONT COLOR='maroon'>[src.admincaster_feed_channel.returnAuthor(-1)]</FONT> \]</FONT><BR>"
|
||||
dat+="<FONT SIZE=2><A href='?src=[REF(src)];[HrefToken()];ac_censor_channel_author=[REF(src.admincaster_feed_channel)]'>[(src.admincaster_feed_channel.authorCensor) ? ("Undo Author censorship") : ("Censor channel Author")]</A></FONT><HR>"
|
||||
|
||||
if( isemptylist(src.admincaster_feed_channel.messages) )
|
||||
dat+="<I>No feed messages found in channel...</I><BR>"
|
||||
else
|
||||
for(var/datum/newscaster/feed_message/MESSAGE in src.admincaster_feed_channel.messages)
|
||||
dat+="-[MESSAGE.returnBody(-1)] <BR><FONT SIZE=1>\[Story by <FONT COLOR='maroon'>[MESSAGE.returnAuthor(-1)]</FONT>\]</FONT><BR>"
|
||||
dat+="<FONT SIZE=2><A href='?src=[REF(src)];[HrefToken()];ac_censor_channel_story_body=[REF(MESSAGE)]'>[(MESSAGE.bodyCensor) ? ("Undo story censorship") : ("Censor story")]</A> - <A href='?src=[REF(src)];[HrefToken()];ac_censor_channel_story_author=[REF(MESSAGE)]'>[(MESSAGE.authorCensor) ? ("Undo Author Censorship") : ("Censor message Author")]</A></FONT><BR>"
|
||||
dat+="[MESSAGE.comments.len] comment[MESSAGE.comments.len > 1 ? "s" : ""]: <a href='?src=[REF(src)];[HrefToken()];ac_lock_comment=[REF(MESSAGE)]'>[MESSAGE.locked ? "Unlock" : "Lock"]</a><br>"
|
||||
for(var/datum/newscaster/feed_comment/comment in MESSAGE.comments)
|
||||
dat+="[comment.body] <a href='?src=[REF(src)];[HrefToken()];ac_del_comment=[REF(comment)];ac_del_comment_msg=[REF(MESSAGE)]'>X</a><br><font size=1>[comment.author] [comment.time_stamp]</font><br>"
|
||||
dat+="<BR><A href='?src=[REF(src)];[HrefToken()];ac_setScreen=[10]'>Back</A>"
|
||||
if(13)
|
||||
dat+="<B>[src.admincaster_feed_channel.channel_name]: </B><FONT SIZE=1>\[ created by: <FONT COLOR='maroon'>[src.admincaster_feed_channel.returnAuthor(-1)]</FONT> \]</FONT><BR>"
|
||||
dat+="Channel messages listed below. If you deem them dangerous to the station, you can <A href='?src=[REF(src)];[HrefToken()];ac_toggle_d_notice=[REF(src.admincaster_feed_channel)]'>Bestow a D-Notice upon the channel</A>.<HR>"
|
||||
if(src.admincaster_feed_channel.censored)
|
||||
dat+="<FONT COLOR='red'><B>ATTENTION: </B></FONT>This channel has been deemed as threatening to the welfare of the station, and marked with a Nanotrasen D-Notice.<BR>"
|
||||
dat+="No further feed story additions are allowed while the D-Notice is in effect.</FONT><BR><BR>"
|
||||
else
|
||||
if( isemptylist(src.admincaster_feed_channel.messages) )
|
||||
dat+="<I>No feed messages found in channel...</I><BR>"
|
||||
else
|
||||
for(var/datum/newscaster/feed_message/MESSAGE in src.admincaster_feed_channel.messages)
|
||||
dat+="-[MESSAGE.returnBody(-1)] <BR><FONT SIZE=1>\[Story by <FONT COLOR='maroon'>[MESSAGE.returnAuthor(-1)]</FONT>\]</FONT><BR>"
|
||||
dat+="<BR><A href='?src=[REF(src)];[HrefToken()];ac_setScreen=[11]'>Back</A>"
|
||||
if(14)
|
||||
dat+="<B>Wanted Issue Handler:</B>"
|
||||
var/wanted_already = 0
|
||||
var/end_param = 1
|
||||
if(GLOB.news_network.wanted_issue.active)
|
||||
wanted_already = 1
|
||||
end_param = 2
|
||||
if(wanted_already)
|
||||
dat+="<FONT SIZE=2><BR><I>A wanted issue is already in Feed Circulation. You can edit or cancel it below.</FONT></I>"
|
||||
dat+="<HR>"
|
||||
dat+="<A href='?src=[REF(src)];[HrefToken()];ac_set_wanted_name=1'>Criminal Name</A>: [src.admincaster_wanted_message.criminal] <BR>"
|
||||
dat+="<A href='?src=[REF(src)];[HrefToken()];ac_set_wanted_desc=1'>Description</A>: [src.admincaster_wanted_message.body] <BR>"
|
||||
if(wanted_already)
|
||||
dat+="<B>Wanted Issue created by:</B><FONT COLOR='green'>[GLOB.news_network.wanted_issue.scannedUser]</FONT><BR>"
|
||||
else
|
||||
dat+="<B>Wanted Issue will be created under prosecutor:</B><FONT COLOR='green'>[src.admin_signature]</FONT><BR>"
|
||||
dat+="<BR><A href='?src=[REF(src)];[HrefToken()];ac_submit_wanted=[end_param]'>[(wanted_already) ? ("Edit Issue") : ("Submit")]</A>"
|
||||
if(wanted_already)
|
||||
dat+="<BR><A href='?src=[REF(src)];[HrefToken()];ac_cancel_wanted=1'>Take down Issue</A>"
|
||||
dat+="<BR><A href='?src=[REF(src)];[HrefToken()];ac_setScreen=[0]'>Cancel</A>"
|
||||
if(15)
|
||||
dat+="<FONT COLOR='green'>Wanted issue for [src.admincaster_wanted_message.criminal] is now in Network Circulation.</FONT><BR><BR>"
|
||||
dat+="<BR><A href='?src=[REF(src)];[HrefToken()];ac_setScreen=[0]'>Return</A><BR>"
|
||||
if(16)
|
||||
dat+="<B><FONT COLOR='maroon'>ERROR: Wanted Issue rejected by Network.</B></FONT><HR><BR>"
|
||||
if(src.admincaster_wanted_message.criminal =="" || src.admincaster_wanted_message.criminal == "\[REDACTED\]")
|
||||
dat+="<FONT COLOR='maroon'>Invalid name for person wanted.</FONT><BR>"
|
||||
if(src.admincaster_wanted_message.body == "" || src.admincaster_wanted_message.body == "\[REDACTED\]")
|
||||
dat+="<FONT COLOR='maroon'>Invalid description.</FONT><BR>"
|
||||
dat+="<BR><A href='?src=[REF(src)];[HrefToken()];ac_setScreen=[0]'>Return</A><BR>"
|
||||
if(17)
|
||||
dat+="<B>Wanted Issue successfully deleted from Circulation</B><BR>"
|
||||
dat+="<BR><A href='?src=[REF(src)];[HrefToken()];ac_setScreen=[0]'>Return</A><BR>"
|
||||
if(18)
|
||||
dat+="<B><FONT COLOR ='maroon'>-- STATIONWIDE WANTED ISSUE --</B></FONT><BR><FONT SIZE=2>\[Submitted by: <FONT COLOR='green'>[GLOB.news_network.wanted_issue.scannedUser]</FONT>\]</FONT><HR>"
|
||||
dat+="<B>Criminal</B>: [GLOB.news_network.wanted_issue.criminal]<BR>"
|
||||
dat+="<B>Description</B>: [GLOB.news_network.wanted_issue.body]<BR>"
|
||||
dat+="<B>Photo:</B>: "
|
||||
if(GLOB.news_network.wanted_issue.img)
|
||||
usr << browse_rsc(GLOB.news_network.wanted_issue.img, "tmp_photow.png")
|
||||
dat+="<BR><img src='tmp_photow.png' width = '180'>"
|
||||
else
|
||||
dat+="None"
|
||||
dat+="<BR><A href='?src=[REF(src)];[HrefToken()];ac_setScreen=[0]'>Back</A><BR>"
|
||||
if(19)
|
||||
dat+="<FONT COLOR='green'>Wanted issue for [src.admincaster_wanted_message.criminal] successfully edited.</FONT><BR><BR>"
|
||||
dat+="<BR><A href='?src=[REF(src)];[HrefToken()];ac_setScreen=[0]'>Return</A><BR>"
|
||||
else
|
||||
dat+="I'm sorry to break your immersion. This shit's bugged. Report this bug to Agouri, polyxenitopalidou@gmail.com"
|
||||
|
||||
usr << browse(dat, "window=admincaster_main;size=400x600")
|
||||
onclose(usr, "admincaster_main")
|
||||
|
||||
|
||||
/datum/admins/proc/Game()
|
||||
if(!check_rights(0))
|
||||
return
|
||||
|
||||
var/dat = {"
|
||||
<center><B>Game Panel</B></center><hr>\n
|
||||
<A href='?src=[REF(src)];[HrefToken()];c_mode=1'>Change Game Mode</A><br>
|
||||
"}
|
||||
if(GLOB.master_mode == "secret")
|
||||
dat += "<A href='?src=[REF(src)];[HrefToken()];f_secret=1'>(Force Secret Mode)</A><br>"
|
||||
|
||||
if(GLOB.master_mode == "dynamic")
|
||||
if(SSticker.current_state <= GAME_STATE_PREGAME)
|
||||
dat += "<A href='?src=[REF(src)];[HrefToken()];f_dynamic_roundstart=1'>(Force Roundstart Rulesets)</A><br>"
|
||||
if (GLOB.dynamic_forced_roundstart_ruleset.len > 0)
|
||||
for(var/datum/dynamic_ruleset/roundstart/rule in GLOB.dynamic_forced_roundstart_ruleset)
|
||||
dat += {"<A href='?src=[REF(src)];[HrefToken()];f_dynamic_roundstart_remove=\ref[rule]'>-> [rule.name] <-</A><br>"}
|
||||
dat += "<A href='?src=[REF(src)];[HrefToken()];f_dynamic_roundstart_clear=1'>(Clear Rulesets)</A><br>"
|
||||
dat += "<A href='?src=[REF(src)];[HrefToken()];f_dynamic_options=1'>(Dynamic mode options)</A><br>"
|
||||
else if (SSticker.IsRoundInProgress())
|
||||
dat += "<A href='?src=[REF(src)];[HrefToken()];f_dynamic_latejoin=1'>(Force Next Latejoin Ruleset)</A><br>"
|
||||
if (SSticker && SSticker.mode && istype(SSticker.mode,/datum/game_mode/dynamic))
|
||||
var/datum/game_mode/dynamic/mode = SSticker.mode
|
||||
if (mode.forced_latejoin_rule)
|
||||
dat += {"<A href='?src=[REF(src)];[HrefToken()];f_dynamic_latejoin_clear=1'>-> [mode.forced_latejoin_rule.name] <-</A><br>"}
|
||||
dat += "<A href='?src=[REF(src)];[HrefToken()];f_dynamic_midround=1'>(Execute Midround Ruleset!)</A><br>"
|
||||
dat += "<hr/>"
|
||||
if(SSticker.IsRoundInProgress())
|
||||
dat += "<a href='?src=[REF(src)];[HrefToken()];gamemode_panel=1'>(Game Mode Panel)</a><BR>"
|
||||
|
||||
dat += {"
|
||||
<BR>
|
||||
<A href='?src=[REF(src)];[HrefToken()];create_object=1'>Create Object</A><br>
|
||||
<A href='?src=[REF(src)];[HrefToken()];quick_create_object=1'>Quick Create Object</A><br>
|
||||
<A href='?src=[REF(src)];[HrefToken()];create_turf=1'>Create Turf</A><br>
|
||||
<A href='?src=[REF(src)];[HrefToken()];create_mob=1'>Create Mob</A><br>
|
||||
"}
|
||||
|
||||
if(marked_datum && istype(marked_datum, /atom))
|
||||
dat += "<A href='?src=[REF(src)];[HrefToken()];dupe_marked_datum=1'>Duplicate Marked Datum</A><br>"
|
||||
|
||||
usr << browse(dat, "window=admin2;size=210x200")
|
||||
return
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////admins2.dm merge
|
||||
//i.e. buttons/verbs
|
||||
|
||||
|
||||
/datum/admins/proc/restart()
|
||||
set category = "Server"
|
||||
set name = "Reboot World"
|
||||
set desc="Restarts the world immediately"
|
||||
if (!usr.client.holder)
|
||||
return
|
||||
|
||||
var/list/options = list("Regular Restart", "Hard Restart (No Delay/Feeback Reason)", "Hardest Restart (No actions, just reboot)")
|
||||
if(world.TgsAvailable())
|
||||
options += "Server Restart (Kill and restart DD)";
|
||||
|
||||
var/rebootconfirm
|
||||
if(SSticker.admin_delay_notice)
|
||||
if(alert(usr, "Are you sure? An admin has already delayed the round end for the following reason: [SSticker.admin_delay_notice]", "Confirmation", "Yes", "No") == "Yes")
|
||||
rebootconfirm = TRUE
|
||||
else
|
||||
rebootconfirm = TRUE
|
||||
if(rebootconfirm)
|
||||
var/result = input(usr, "Select reboot method", "World Reboot", options[1]) as null|anything in options
|
||||
if(result)
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Reboot World") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
var/init_by = "Initiated by [usr.client.holder.fakekey ? "Admin" : usr.key]."
|
||||
switch(result)
|
||||
if("Regular Restart")
|
||||
SSticker.Reboot(init_by, "admin reboot - by [usr.key] [usr.client.holder.fakekey ? "(stealth)" : ""]", 10)
|
||||
if("Hard Restart (No Delay, No Feeback Reason)")
|
||||
to_chat(world, "World reboot - [init_by]")
|
||||
world.Reboot()
|
||||
if("Hardest Restart (No actions, just reboot)")
|
||||
to_chat(world, "Hard world reboot - [init_by]")
|
||||
world.Reboot(fast_track = TRUE)
|
||||
if("Server Restart (Kill and restart DD)")
|
||||
to_chat(world, "Server restart - [init_by]")
|
||||
world.TgsEndProcess()
|
||||
|
||||
/datum/admins/proc/end_round()
|
||||
set category = "Server"
|
||||
set name = "End Round"
|
||||
set desc = "Attempts to produce a round end report and then restart the server organically."
|
||||
|
||||
if (!usr.client.holder)
|
||||
return
|
||||
var/confirm = alert("End the round and restart the game world?", "End Round", "Yes", "Cancel")
|
||||
if(confirm == "Cancel")
|
||||
return
|
||||
if(confirm == "Yes")
|
||||
SSticker.force_ending = 1
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "End Round") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
|
||||
/datum/admins/proc/announce()
|
||||
set category = "Special Verbs"
|
||||
set name = "Announce"
|
||||
set desc="Announce your desires to the world"
|
||||
if(!check_rights(0))
|
||||
return
|
||||
|
||||
var/message = input("Global message to send:", "Admin Announce", null, null) as message
|
||||
if(message)
|
||||
if(!check_rights(R_SERVER,0))
|
||||
message = adminscrub(message,500)
|
||||
to_chat(world, "<span class='adminnotice'><b>[usr.client.holder.fakekey ? "Administrator" : usr.key] Announces:</b></span>\n \t [message]")
|
||||
log_admin("Announce: [key_name(usr)] : [message]")
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Announce") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
/datum/admins/proc/set_admin_notice()
|
||||
set category = "Special Verbs"
|
||||
set name = "Set Admin Notice"
|
||||
set desc ="Set an announcement that appears to everyone who joins the server. Only lasts this round"
|
||||
if(!check_rights(0))
|
||||
return
|
||||
|
||||
var/new_admin_notice = input(src,"Set a public notice for this round. Everyone who joins the server will see it.\n(Leaving it blank will delete the current notice):","Set Notice",GLOB.admin_notice) as message|null
|
||||
if(new_admin_notice == null)
|
||||
return
|
||||
if(new_admin_notice == GLOB.admin_notice)
|
||||
return
|
||||
if(new_admin_notice == "")
|
||||
message_admins("[key_name(usr)] removed the admin notice.")
|
||||
log_admin("[key_name(usr)] removed the admin notice:\n[GLOB.admin_notice]")
|
||||
else
|
||||
message_admins("[key_name(usr)] set the admin notice.")
|
||||
log_admin("[key_name(usr)] set the admin notice:\n[new_admin_notice]")
|
||||
to_chat(world, "<span class ='adminnotice'><b>Admin Notice:</b>\n \t [new_admin_notice]</span>")
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Set Admin Notice") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
GLOB.admin_notice = new_admin_notice
|
||||
return
|
||||
|
||||
/datum/admins/proc/toggleooc()
|
||||
set category = "Server"
|
||||
set desc="Toggle dis bitch"
|
||||
set name="Toggle OOC"
|
||||
toggle_ooc()
|
||||
log_admin("[key_name(usr)] toggled OOC.")
|
||||
message_admins("[key_name_admin(usr)] toggled OOC.")
|
||||
SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Toggle OOC", "[GLOB.ooc_allowed ? "Enabled" : "Disabled"]")) //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
/datum/admins/proc/toggleooclocal()
|
||||
set category = "Server"
|
||||
set desc="Toggle dat bitch"
|
||||
set name="Toggle Local OOC"
|
||||
toggle_looc()
|
||||
log_admin("[key_name(usr)] toggled LOOC.")
|
||||
message_admins("[key_name_admin(usr)] toggled LOOC.")
|
||||
SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Toggle Local OOC", "[GLOB.ooc_allowed ? "Enabled" : "Disabled"]")) //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
/datum/admins/proc/toggleoocdead()
|
||||
set category = "Server"
|
||||
set desc="Toggle dis bitch"
|
||||
set name="Toggle Dead OOC"
|
||||
toggle_dooc()
|
||||
|
||||
log_admin("[key_name(usr)] toggled Dead OOC.")
|
||||
message_admins("[key_name_admin(usr)] toggled Dead OOC.")
|
||||
SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Toggle Dead OOC", "[GLOB.dooc_allowed ? "Enabled" : "Disabled"]")) //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
/datum/admins/proc/toggleaooc()
|
||||
set category = "Server"
|
||||
set desc="Toggle to bitch"
|
||||
set name="Toggle Antag OOC"
|
||||
toggle_aooc()
|
||||
log_admin("[key_name(usr)] toggled Antagonist OOC.")
|
||||
message_admins("[key_name_admin(usr)] toggled Antagonist OOC.")
|
||||
SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Toggle Antag OOC", "[GLOB.aooc_allowed ? "Enabled" : "Disabled"]")) //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
/datum/admins/proc/startnow()
|
||||
set category = "Server"
|
||||
set desc="Start the round RIGHT NOW"
|
||||
set name="Start Now"
|
||||
if(SSticker.current_state == GAME_STATE_PREGAME || SSticker.current_state == GAME_STATE_STARTUP)
|
||||
SSticker.start_immediately = TRUE
|
||||
log_admin("[usr.key] has started the game.")
|
||||
var/msg = ""
|
||||
if(SSticker.current_state == GAME_STATE_STARTUP)
|
||||
msg = " (The server is still setting up, but the round will be \
|
||||
started as soon as possible.)"
|
||||
message_admins("<font color='blue'>\
|
||||
[usr.key] has started the game.[msg]</font>")
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Start Now") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
return 1
|
||||
else
|
||||
to_chat(usr, "<font color='red'>Error: Start Now: Game has already started.</font>")
|
||||
|
||||
return 0
|
||||
|
||||
/datum/admins/proc/toggleenter()
|
||||
set category = "Server"
|
||||
set desc="People can't enter"
|
||||
set name="Toggle Entering"
|
||||
GLOB.enter_allowed = !( GLOB.enter_allowed )
|
||||
if (!( GLOB.enter_allowed ))
|
||||
to_chat(world, "<B>New players may no longer enter the game.</B>")
|
||||
else
|
||||
to_chat(world, "<B>New players may now enter the game.</B>")
|
||||
log_admin("[key_name(usr)] toggled new player game entering.")
|
||||
message_admins("<span class='adminnotice'>[key_name_admin(usr)] toggled new player game entering.</span>")
|
||||
world.update_status()
|
||||
SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Toggle Entering", "[GLOB.enter_allowed ? "Enabled" : "Disabled"]")) //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
/datum/admins/proc/toggleAI()
|
||||
set category = "Server"
|
||||
set desc="People can't be AI"
|
||||
set name="Toggle AI"
|
||||
var/alai = CONFIG_GET(flag/allow_ai)
|
||||
CONFIG_SET(flag/allow_ai, !alai)
|
||||
if (alai)
|
||||
to_chat(world, "<B>The AI job is no longer chooseable.</B>")
|
||||
else
|
||||
to_chat(world, "<B>The AI job is chooseable now.</B>")
|
||||
log_admin("[key_name(usr)] toggled AI allowed.")
|
||||
world.update_status()
|
||||
SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Toggle AI", "[!alai ? "Disabled" : "Enabled"]")) //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
/datum/admins/proc/toggleMulticam()
|
||||
set category = "Server"
|
||||
set desc="Turns mutlicam on and off."
|
||||
set name="Toggle Multicam"
|
||||
var/almcam = CONFIG_GET(flag/allow_ai_multicam)
|
||||
CONFIG_SET(flag/allow_ai_multicam, !almcam)
|
||||
if (almcam)
|
||||
to_chat(world, "<B>The AI no longer has multicam.</B>")
|
||||
for(var/i in GLOB.ai_list)
|
||||
var/mob/living/silicon/ai/aiPlayer = i
|
||||
if(aiPlayer.multicam_on)
|
||||
aiPlayer.end_multicam()
|
||||
else
|
||||
to_chat(world, "<B>The AI now has multicam.</B>")
|
||||
log_admin("[key_name(usr)] toggled AI multicam.")
|
||||
world.update_status()
|
||||
SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Toggle Multicam", "[!almcam ? "Disabled" : "Enabled"]")) //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
/datum/admins/proc/toggleaban()
|
||||
set category = "Server"
|
||||
set desc="Respawn basically"
|
||||
set name="Toggle Respawn"
|
||||
var/new_nores = !CONFIG_GET(flag/norespawn)
|
||||
CONFIG_SET(flag/norespawn, new_nores)
|
||||
if (!new_nores)
|
||||
to_chat(world, "<B>You may now respawn.</B>")
|
||||
else
|
||||
to_chat(world, "<B>You may no longer respawn :(</B>")
|
||||
message_admins("<span class='adminnotice'>[key_name_admin(usr)] toggled respawn to [!new_nores ? "On" : "Off"].</span>")
|
||||
log_admin("[key_name(usr)] toggled respawn to [!new_nores ? "On" : "Off"].")
|
||||
world.update_status()
|
||||
SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Toggle Respawn", "[!new_nores ? "Enabled" : "Disabled"]")) //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
/datum/admins/proc/delay()
|
||||
set category = "Server"
|
||||
set desc="Delay the game start"
|
||||
set name="Delay pre-game"
|
||||
|
||||
var/newtime = input("Set a new time in seconds. Set -1 for indefinite delay.","Set Delay",round(SSticker.GetTimeLeft()/10)) as num|null
|
||||
if(SSticker.current_state > GAME_STATE_PREGAME)
|
||||
return alert("Too late... The game has already started!")
|
||||
if(newtime)
|
||||
newtime = newtime*10
|
||||
SSticker.SetTimeLeft(newtime)
|
||||
if(newtime < 0)
|
||||
to_chat(world, "<b>The game start has been delayed.</b>")
|
||||
log_admin("[key_name(usr)] delayed the round start.")
|
||||
else
|
||||
to_chat(world, "<b>The game will start in [DisplayTimeText(newtime)].</b>")
|
||||
SEND_SOUND(world, sound(get_announcer_sound("attention")))
|
||||
log_admin("[key_name(usr)] set the pre-game delay to [DisplayTimeText(newtime)].")
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Delay Game Start") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
/datum/admins/proc/toggledynamicvote()
|
||||
set category = "Server"
|
||||
set desc="Switches between secret/extended and dynamic voting"
|
||||
set name="Toggle Dynamic Vote"
|
||||
var/prev_dynamic_voting = CONFIG_GET(flag/dynamic_voting)
|
||||
CONFIG_SET(flag/dynamic_voting,!prev_dynamic_voting)
|
||||
if (!prev_dynamic_voting)
|
||||
to_chat(world, "<B>Vote is now between extended and dynamic chaos.</B>")
|
||||
else
|
||||
to_chat(world, "<B>Vote is now between extended and secret.</B>")
|
||||
log_admin("[key_name(usr)] [prev_dynamic_voting ? "disabled" : "enabled"] dynamic voting.")
|
||||
message_admins("<span class='adminnotice'>[key_name_admin(usr)] toggled dynamic voting.</span>")
|
||||
SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Toggle Dynamic Voting", "[prev_dynamic_voting ? "Disabled" : "Enabled"]")) //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
/datum/admins/proc/unprison(mob/M in GLOB.mob_list)
|
||||
set category = "Admin"
|
||||
set name = "Unprison"
|
||||
if (is_centcom_level(M.z))
|
||||
SSjob.SendToLateJoin(M)
|
||||
message_admins("[key_name_admin(usr)] has unprisoned [key_name_admin(M)]")
|
||||
log_admin("[key_name(usr)] has unprisoned [key_name(M)]")
|
||||
else
|
||||
alert("[M.name] is not prisoned.")
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Unprison") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////ADMIN HELPER PROCS
|
||||
|
||||
/datum/admins/proc/spawn_atom(object as text)
|
||||
set category = "Debug"
|
||||
set desc = "(atom path) Spawn an atom"
|
||||
set name = "Spawn"
|
||||
|
||||
if(!check_rights(R_SPAWN))
|
||||
return
|
||||
|
||||
var/chosen = pick_closest_path(object)
|
||||
if(!chosen)
|
||||
return
|
||||
if(ispath(chosen, /turf))
|
||||
var/turf/T = get_turf(usr.loc)
|
||||
T.ChangeTurf(chosen)
|
||||
else
|
||||
var/atom/A = new chosen(usr.loc)
|
||||
A.flags_1 |= ADMIN_SPAWNED_1
|
||||
|
||||
log_admin("[key_name(usr)] spawned [chosen] at [AREACOORD(usr)]")
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Spawn Atom") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
/datum/admins/proc/spawn_cargo(object as text)
|
||||
set category = "Debug"
|
||||
set desc = "(atom path) Spawn a cargo crate"
|
||||
set name = "Spawn Cargo"
|
||||
|
||||
if(!check_rights(R_SPAWN))
|
||||
return
|
||||
|
||||
var/chosen = pick_closest_path(object, make_types_fancy(subtypesof(/datum/supply_pack)))
|
||||
if(!chosen)
|
||||
return
|
||||
var/datum/supply_pack/S = new chosen
|
||||
S.admin_spawned = TRUE
|
||||
S.generate(get_turf(usr))
|
||||
|
||||
log_admin("[key_name(usr)] spawned cargo pack [chosen] at [AREACOORD(usr)]")
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Spawn Cargo") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
|
||||
/datum/admins/proc/show_traitor_panel(mob/M in GLOB.mob_list)
|
||||
set category = "Admin"
|
||||
set desc = "Edit mobs's memory and role"
|
||||
set name = "Show Traitor Panel"
|
||||
|
||||
if(!istype(M))
|
||||
to_chat(usr, "This can only be used on instances of type /mob")
|
||||
return
|
||||
if(!M.mind)
|
||||
to_chat(usr, "This mob has no mind!")
|
||||
return
|
||||
|
||||
M.mind.traitor_panel()
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Traitor Panel") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
|
||||
/datum/admins/proc/toggletintedweldhelmets()
|
||||
set category = "Debug"
|
||||
set desc="Reduces view range when wearing welding helmets"
|
||||
set name="Toggle tinted welding helmes"
|
||||
GLOB.tinted_weldhelh = !( GLOB.tinted_weldhelh )
|
||||
if (GLOB.tinted_weldhelh)
|
||||
to_chat(world, "<B>The tinted_weldhelh has been enabled!</B>")
|
||||
else
|
||||
to_chat(world, "<B>The tinted_weldhelh has been disabled!</B>")
|
||||
log_admin("[key_name(usr)] toggled tinted_weldhelh.")
|
||||
message_admins("[key_name_admin(usr)] toggled tinted_weldhelh.")
|
||||
SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Toggle Tinted Welding Helmets", "[GLOB.tinted_weldhelh ? "Enabled" : "Disabled"]")) //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
/datum/admins/proc/toggleguests()
|
||||
set category = "Server"
|
||||
set desc="Guests can't enter"
|
||||
set name="Toggle guests"
|
||||
var/new_guest_ban = !CONFIG_GET(flag/guest_ban)
|
||||
CONFIG_SET(flag/guest_ban, new_guest_ban)
|
||||
if (new_guest_ban)
|
||||
to_chat(world, "<B>Guests may no longer enter the game.</B>")
|
||||
else
|
||||
to_chat(world, "<B>Guests may now enter the game.</B>")
|
||||
log_admin("[key_name(usr)] toggled guests game entering [!new_guest_ban ? "" : "dis"]allowed.")
|
||||
message_admins("<span class='adminnotice'>[key_name_admin(usr)] toggled guests game entering [!new_guest_ban ? "" : "dis"]allowed.</span>")
|
||||
SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Toggle Guests", "[!new_guest_ban ? "Enabled" : "Disabled"]")) //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
/datum/admins/proc/output_ai_laws()
|
||||
var/ai_number = 0
|
||||
for(var/i in GLOB.silicon_mobs)
|
||||
var/mob/living/silicon/S = i
|
||||
ai_number++
|
||||
if(isAI(S))
|
||||
to_chat(usr, "<b>AI [key_name(S, usr)]'s laws:</b>")
|
||||
else if(iscyborg(S))
|
||||
var/mob/living/silicon/robot/R = S
|
||||
to_chat(usr, "<b>CYBORG [key_name(S, usr)] [R.connected_ai?"(Slaved to: [key_name(R.connected_ai)])":"(Independent)"]: laws:</b>")
|
||||
else if (ispAI(S))
|
||||
to_chat(usr, "<b>pAI [key_name(S, usr)]'s laws:</b>")
|
||||
else
|
||||
to_chat(usr, "<b>SOMETHING SILICON [key_name(S, usr)]'s laws:</b>")
|
||||
|
||||
if (S.laws == null)
|
||||
to_chat(usr, "[key_name(S, usr)]'s laws are null?? Contact a coder.")
|
||||
else
|
||||
S.laws.show_laws(usr)
|
||||
if(!ai_number)
|
||||
to_chat(usr, "<b>No AIs located</b>" )
|
||||
|
||||
/datum/admins/proc/output_all_devil_info()
|
||||
var/devil_number = 0
|
||||
for(var/datum/mind/D in SSticker.mode.devils)
|
||||
devil_number++
|
||||
var/datum/antagonist/devil/devil = D.has_antag_datum(/datum/antagonist/devil)
|
||||
to_chat(usr, "Devil #[devil_number]:<br><br>" + devil.printdevilinfo())
|
||||
if(!devil_number)
|
||||
to_chat(usr, "<b>No Devils located</b>" )
|
||||
|
||||
/datum/admins/proc/output_devil_info(mob/living/M)
|
||||
if(is_devil(M))
|
||||
var/datum/antagonist/devil/devil = M.mind.has_antag_datum(/datum/antagonist/devil)
|
||||
to_chat(usr, devil.printdevilinfo())
|
||||
else
|
||||
to_chat(usr, "<b>[M] is not a devil.")
|
||||
|
||||
/datum/admins/proc/manage_free_slots()
|
||||
if(!check_rights())
|
||||
return
|
||||
var/datum/browser/browser = new(usr, "jobmanagement", "Manage Free Slots", 520)
|
||||
var/list/dat = list()
|
||||
var/count = 0
|
||||
|
||||
if(!SSjob.initialized)
|
||||
alert(usr, "You cannot manage jobs before the job subsystem is initialized!")
|
||||
return
|
||||
|
||||
dat += "<table>"
|
||||
|
||||
for(var/j in SSjob.occupations)
|
||||
var/datum/job/job = j
|
||||
count++
|
||||
var/J_title = html_encode(job.title)
|
||||
var/J_opPos = html_encode(job.total_positions - (job.total_positions - job.current_positions))
|
||||
var/J_totPos = html_encode(job.total_positions)
|
||||
dat += "<tr><td>[J_title]:</td> <td>[J_opPos]/[job.total_positions < 0 ? " (unlimited)" : J_totPos]"
|
||||
|
||||
dat += "</td>"
|
||||
dat += "<td>"
|
||||
if(job.total_positions >= 0)
|
||||
dat += "<A href='?src=[REF(src)];[HrefToken()];customjobslot=[job.title]'>Custom</A> | "
|
||||
dat += "<A href='?src=[REF(src)];[HrefToken()];addjobslot=[job.title]'>Add 1</A> | "
|
||||
if(job.total_positions > job.current_positions)
|
||||
dat += "<A href='?src=[REF(src)];[HrefToken()];removejobslot=[job.title]'>Remove</A> | "
|
||||
else
|
||||
dat += "Remove | "
|
||||
dat += "<A href='?src=[REF(src)];[HrefToken()];unlimitjobslot=[job.title]'>Unlimit</A></td>"
|
||||
else
|
||||
dat += "<A href='?src=[REF(src)];[HrefToken()];limitjobslot=[job.title]'>Limit</A></td>"
|
||||
|
||||
browser.height = min(100 + count * 20, 650)
|
||||
browser.set_content(dat.Join())
|
||||
browser.open()
|
||||
|
||||
/datum/admins/proc/dynamic_mode_options(mob/user)
|
||||
var/dat = {"
|
||||
<center><B><h2>Dynamic Mode Options</h2></B></center><hr>
|
||||
<br/>
|
||||
<h3>Common options</h3>
|
||||
<i>All these options can be changed midround.</i> <br/>
|
||||
<br/>
|
||||
<b>Force extended:</b> - Option is <a href='?src=[REF(src)];[HrefToken()];f_dynamic_force_extended=1'> <b>[GLOB.dynamic_forced_extended ? "ON" : "OFF"]</a></b>.
|
||||
<br/>This will force the round to be extended. No rulesets will be drafted. <br/>
|
||||
<br/>
|
||||
<b>No stacking:</b> - Option is <a href='?src=[REF(src)];[HrefToken()];f_dynamic_no_stacking=1'> <b>[GLOB.dynamic_no_stacking ? "ON" : "OFF"]</b></a>.
|
||||
<br/>Unless the threat goes above [GLOB.dynamic_stacking_limit], only one "round-ender" ruleset will be drafted. <br/>
|
||||
<br/>
|
||||
<b>Classic secret mode:</b> - Option is <a href='?src=[REF(src)];[HrefToken()];f_dynamic_classic_secret=1'> <b>[GLOB.dynamic_classic_secret ? "ON" : "OFF"]</b></a>.
|
||||
<br/>Only one roundstart ruleset will be drafted. Only traitors and minor roles will latespawn. <br/>
|
||||
<br/>
|
||||
<br/>
|
||||
<b>Forced threat level:</b> Current value : <a href='?src=[REF(src)];[HrefToken()];f_dynamic_forced_threat=1'><b>[GLOB.dynamic_forced_threat_level]</b></a>.
|
||||
<br/>The value threat is set to if it is higher than -1.<br/>
|
||||
<br/>
|
||||
<b>High population limit:</b> Current value : <a href='?src=[REF(src)];[HrefToken()];f_dynamic_high_pop_limit=1'><b>[GLOB.dynamic_high_pop_limit]</b></a>.
|
||||
<br/>The threshold at which "high population override" will be in effect. <br/>
|
||||
<br/>
|
||||
<b>Stacking threeshold:</b> Current value : <a href='?src=[REF(src)];[HrefToken()];f_dynamic_stacking_limit=1'><b>[GLOB.dynamic_stacking_limit]</b></a>.
|
||||
<br/>The threshold at which "round-ender" rulesets will stack. A value higher than 100 ensure this never happens. <br/>
|
||||
<h3>Advanced parameters</h3>
|
||||
Curve centre: <A href='?src=[REF(src)];[HrefToken()];f_dynamic_roundstart_centre=1'>-> [GLOB.dynamic_curve_centre] <-</A><br>
|
||||
Curve width: <A href='?src=[REF(src)];[HrefToken()];f_dynamic_roundstart_width=1'>-> [GLOB.dynamic_curve_width] <-</A><br>
|
||||
Latejoin injection delay:<br>
|
||||
Minimum: <A href='?src=[REF(src)];[HrefToken()];f_dynamic_roundstart_latejoin_min=1'>-> [GLOB.dynamic_latejoin_delay_min / 60 / 10] <-</A> Minutes<br>
|
||||
Maximum: <A href='?src=[REF(src)];[HrefToken()];f_dynamic_roundstart_latejoin_max=1'>-> [GLOB.dynamic_latejoin_delay_max / 60 / 10] <-</A> Minutes<br>
|
||||
Midround injection delay:<br>
|
||||
Minimum: <A href='?src=[REF(src)];[HrefToken()];f_dynamic_roundstart_midround_min=1'>-> [GLOB.dynamic_midround_delay_min / 60 / 10] <-</A> Minutes<br>
|
||||
Maximum: <A href='?src=[REF(src)];[HrefToken()];f_dynamic_roundstart_midround_max=1'>-> [GLOB.dynamic_midround_delay_max / 60 / 10] <-</A> Minutes<br>
|
||||
"}
|
||||
|
||||
user << browse(dat, "window=dyn_mode_options;size=900x650")
|
||||
|
||||
/datum/admins/proc/create_or_modify_area()
|
||||
set category = "Debug"
|
||||
set name = "Create or modify area"
|
||||
create_area(usr)
|
||||
|
||||
//
|
||||
//
|
||||
//ALL DONE
|
||||
//*********************************************************************************************************
|
||||
//TO-DO:
|
||||
//
|
||||
//
|
||||
|
||||
//RIP ferry snowflakes
|
||||
|
||||
//Kicks all the clients currently in the lobby. The second parameter (kick_only_afk) determins if an is_afk() check is ran, or if all clients are kicked
|
||||
//defaults to kicking everyone (afk + non afk clients in the lobby)
|
||||
//returns a list of ckeys of the kicked clients
|
||||
/proc/kick_clients_in_lobby(message, kick_only_afk = 0)
|
||||
var/list/kicked_client_names = list()
|
||||
for(var/client/C in GLOB.clients)
|
||||
if(isnewplayer(C.mob))
|
||||
if(kick_only_afk && !C.is_afk()) //Ignore clients who are not afk
|
||||
continue
|
||||
if(message)
|
||||
to_chat(C, message)
|
||||
kicked_client_names.Add("[C.key]")
|
||||
qdel(C)
|
||||
return kicked_client_names
|
||||
|
||||
//returns 1 to let the dragdrop code know we are trapping this event
|
||||
//returns 0 if we don't plan to trap the event
|
||||
/datum/admins/proc/cmd_ghost_drag(mob/dead/observer/frommob, mob/tomob)
|
||||
|
||||
//this is the exact two check rights checks required to edit a ckey with vv.
|
||||
if (!check_rights(R_VAREDIT,0) || !check_rights(R_SPAWN|R_DEBUG,0))
|
||||
return 0
|
||||
|
||||
if (!frommob.ckey)
|
||||
return 0
|
||||
|
||||
var/question = ""
|
||||
if (tomob.ckey)
|
||||
question = "This mob already has a user ([tomob.key]) in control of it! "
|
||||
question += "Are you sure you want to place [frommob.name]([frommob.key]) in control of [tomob.name]?"
|
||||
|
||||
var/ask = alert(question, "Place ghost in control of mob?", "Yes", "No")
|
||||
if (ask != "Yes")
|
||||
return 1
|
||||
|
||||
if (!frommob || !tomob) //make sure the mobs don't go away while we waited for a response
|
||||
return 1
|
||||
|
||||
tomob.ghostize(0)
|
||||
|
||||
message_admins("<span class='adminnotice'>[key_name_admin(usr)] has put [frommob.key] in control of [tomob.name].</span>")
|
||||
log_admin("[key_name(usr)] stuffed [frommob.key] into [tomob.name].")
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Ghost Drag Control")
|
||||
|
||||
tomob.ckey = frommob.ckey
|
||||
qdel(frommob)
|
||||
|
||||
return 1
|
||||
|
||||
/client/proc/adminGreet(logout)
|
||||
if(SSticker.HasRoundStarted())
|
||||
var/string
|
||||
if(logout && CONFIG_GET(flag/announce_admin_logout))
|
||||
string = pick(
|
||||
"Admin logout: [key_name(src)]")
|
||||
else if(!logout && CONFIG_GET(flag/announce_admin_login) && (prefs.toggles & ANNOUNCE_LOGIN))
|
||||
string = pick(
|
||||
"Admin login: [key_name(src)]")
|
||||
if(string)
|
||||
message_admins("[string]")
|
||||
@@ -0,0 +1,719 @@
|
||||
//admin verb groups - They can overlap if you so wish. Only one of each verb will exist in the verbs list regardless
|
||||
//the procs are cause you can't put the comments in the GLOB var define
|
||||
GLOBAL_LIST_INIT(admin_verbs_default, world.AVerbsDefault())
|
||||
GLOBAL_PROTECT(admin_verbs_default)
|
||||
/world/proc/AVerbsDefault()
|
||||
return list(
|
||||
/client/proc/deadmin, /*destroys our own admin datum so we can play as a regular player*/
|
||||
/client/proc/cmd_admin_say, /*admin-only ooc chat*/
|
||||
/client/proc/dsay, /*talk in deadchat using our ckey/fakekey*/
|
||||
/client/proc/deadchat,
|
||||
/client/proc/investigate_show, /*various admintools for investigation. Such as a singulo grief-log*/
|
||||
/client/proc/debug_variables, /*allows us to -see- the variables of any instance in the game. +VAREDIT needed to modify*/
|
||||
/client/proc/toggleprayers,
|
||||
/client/proc/toggleadminhelpsound
|
||||
)
|
||||
GLOBAL_LIST_INIT(admin_verbs_admin, world.AVerbsAdmin())
|
||||
GLOBAL_PROTECT(admin_verbs_admin)
|
||||
/world/proc/AVerbsAdmin()
|
||||
return list(
|
||||
/client/proc/invisimin, /*allows our mob to go invisible/visible*/
|
||||
// /datum/admins/proc/show_traitor_panel, /*interface which shows a mob's mind*/ -Removed due to rare practical use. Moved to debug verbs ~Errorage
|
||||
/datum/admins/proc/show_player_panel, /*shows an interface for individual players, with various links (links require additional flags*/
|
||||
/datum/verbs/menu/Admin/verb/playerpanel,
|
||||
/client/proc/game_panel, /*game panel, allows to change game-mode etc*/
|
||||
/client/proc/check_ai_laws, /*shows AI and borg laws*/
|
||||
/datum/admins/proc/toggleooc, /*toggles ooc on/off for everyone*/
|
||||
/datum/admins/proc/toggleooclocal, /*toggles looc on/off for everyone*/
|
||||
/datum/admins/proc/toggleoocdead, /*toggles ooc on/off for everyone who is dead*/
|
||||
/datum/admins/proc/toggleaooc, /*toggles antag ooc on/off*/
|
||||
/datum/admins/proc/toggleenter, /*toggles whether people can join the current game*/
|
||||
/datum/admins/proc/toggleguests, /*toggles whether guests can join the current game*/
|
||||
/datum/admins/proc/announce, /*priority announce something to all clients.*/
|
||||
/datum/admins/proc/set_admin_notice, /*announcement all clients see when joining the server.*/
|
||||
/client/proc/admin_ghost, /*allows us to ghost/reenter body at will*/
|
||||
/client/proc/toggle_view_range, /*changes how far we can see*/
|
||||
/client/proc/getserverlogs, /*for accessing server logs*/
|
||||
/client/proc/cmd_admin_subtle_message, /*send an message to somebody as a 'voice in their head'*/
|
||||
/client/proc/cmd_admin_headset_message, /*send an message to somebody through their headset as CentCom*/
|
||||
/client/proc/cmd_admin_delete, /*delete an instance/object/mob/etc*/
|
||||
/client/proc/cmd_admin_check_contents, /*displays the contents of an instance*/
|
||||
/client/proc/centcom_podlauncher,/*Open a window to launch a Supplypod and configure it or it's contents*/
|
||||
/client/proc/check_antagonists, /*shows all antags*/
|
||||
/datum/admins/proc/access_news_network, /*allows access of newscasters*/
|
||||
/client/proc/jumptocoord, /*we ghost and jump to a coordinate*/
|
||||
/client/proc/getcurrentlogs, /*for accessing server logs for the current round*/
|
||||
/client/proc/Getmob, /*teleports a mob to our location*/
|
||||
/client/proc/Getkey, /*teleports a mob with a certain ckey to our location*/
|
||||
// /client/proc/sendmob, /*sends a mob somewhere*/ -Removed due to it needing two sorting procs to work, which were executed every time an admin right-clicked. ~Errorage
|
||||
/client/proc/jumptoarea,
|
||||
/client/proc/jumptokey, /*allows us to jump to the location of a mob with a certain ckey*/
|
||||
/client/proc/jumptomob, /*allows us to jump to a specific mob*/
|
||||
/client/proc/jumptoturf, /*allows us to jump to a specific turf*/
|
||||
/client/proc/admin_call_shuttle, /*allows us to call the emergency shuttle*/
|
||||
/client/proc/admin_cancel_shuttle, /*allows us to cancel the emergency shuttle, sending it back to centcom*/
|
||||
/client/proc/cmd_admin_direct_narrate, /*send text directly to a player with no padding. Useful for narratives and fluff-text*/
|
||||
/client/proc/cmd_admin_world_narrate, /*sends text to all players with no padding*/
|
||||
/client/proc/cmd_admin_local_narrate, /*sends text to all mobs within view of atom*/
|
||||
/client/proc/cmd_admin_man_up, //CIT CHANGE - adds man up verb
|
||||
/client/proc/cmd_admin_man_up_global, //CIT CHANGE - ditto
|
||||
/client/proc/cmd_admin_create_centcom_report,
|
||||
/client/proc/cmd_change_command_name,
|
||||
/client/proc/cmd_admin_check_player_exp, /* shows players by playtime */
|
||||
/client/proc/toggle_combo_hud, // toggle display of the combination pizza antag and taco sci/med/eng hud
|
||||
/client/proc/toggle_AI_interact, /*toggle admin ability to interact with machines as an AI*/
|
||||
/client/proc/open_shuttle_manipulator, /* Opens shuttle manipulator UI */
|
||||
/client/proc/respawn_character,
|
||||
/client/proc/secrets,
|
||||
/client/proc/toggle_hear_radio, /*allows admins to hide all radio output*/
|
||||
/client/proc/reload_admins,
|
||||
/client/proc/reestablish_db_connection, /*reattempt a connection to the database*/
|
||||
/client/proc/cmd_admin_pm_context, /*right-click adminPM interface*/
|
||||
/client/proc/cmd_admin_pm_panel, /*admin-pm list*/
|
||||
/client/proc/panicbunker,
|
||||
/client/proc/addbunkerbypass,
|
||||
/client/proc/revokebunkerbypass,
|
||||
/client/proc/stop_sounds,
|
||||
/client/proc/hide_verbs, /*hides all our adminverbs*/
|
||||
/client/proc/hide_most_verbs, /*hides all our hideable adminverbs*/
|
||||
/datum/admins/proc/open_borgopanel
|
||||
)
|
||||
GLOBAL_LIST_INIT(admin_verbs_ban, list(/client/proc/unban_panel, /client/proc/DB_ban_panel, /client/proc/stickybanpanel))
|
||||
GLOBAL_PROTECT(admin_verbs_ban)
|
||||
GLOBAL_LIST_INIT(admin_verbs_sounds, list(/client/proc/play_local_sound, /client/proc/play_sound, /client/proc/set_round_end_sound))
|
||||
GLOBAL_PROTECT(admin_verbs_sounds)
|
||||
GLOBAL_LIST_INIT(admin_verbs_fun, list(
|
||||
/client/proc/cmd_admin_dress,
|
||||
/client/proc/cmd_admin_gib_self,
|
||||
/client/proc/drop_bomb,
|
||||
/client/proc/set_dynex_scale,
|
||||
/client/proc/drop_dynex_bomb,
|
||||
/client/proc/cinematic,
|
||||
/client/proc/one_click_antag,
|
||||
/client/proc/cmd_admin_add_freeform_ai_law,
|
||||
/client/proc/object_say,
|
||||
/client/proc/toggle_random_events,
|
||||
/client/proc/set_ooc,
|
||||
/client/proc/reset_ooc,
|
||||
/client/proc/forceEvent,
|
||||
/client/proc/admin_change_sec_level,
|
||||
/client/proc/toggle_nuke,
|
||||
/client/proc/run_weather,
|
||||
/client/proc/mass_zombie_infection,
|
||||
/client/proc/mass_zombie_cure,
|
||||
/client/proc/polymorph_all,
|
||||
/client/proc/show_tip,
|
||||
/client/proc/smite,
|
||||
/client/proc/admin_away,
|
||||
/client/proc/roll_dices //CIT CHANGE - Adds dice verb
|
||||
))
|
||||
GLOBAL_PROTECT(admin_verbs_fun)
|
||||
GLOBAL_LIST_INIT(admin_verbs_spawn, list(/datum/admins/proc/spawn_atom, /datum/admins/proc/spawn_cargo, /datum/admins/proc/spawn_objasmob, /client/proc/respawn_character))
|
||||
GLOBAL_PROTECT(admin_verbs_spawn)
|
||||
GLOBAL_LIST_INIT(admin_verbs_server, world.AVerbsServer())
|
||||
/world/proc/AVerbsServer()
|
||||
return list(
|
||||
/datum/admins/proc/startnow,
|
||||
/datum/admins/proc/restart,
|
||||
/datum/admins/proc/end_round,
|
||||
/datum/admins/proc/delay,
|
||||
/datum/admins/proc/toggleaban,
|
||||
/client/proc/everyone_random,
|
||||
/datum/admins/proc/toggleAI,
|
||||
/datum/admins/proc/toggleMulticam,
|
||||
/datum/admins/proc/toggledynamicvote,
|
||||
/client/proc/cmd_admin_delete, /*delete an instance/object/mob/etc*/
|
||||
/client/proc/cmd_debug_del_all,
|
||||
/client/proc/toggle_random_events,
|
||||
/client/proc/forcerandomrotate,
|
||||
/client/proc/adminchangemap,
|
||||
/client/proc/toggle_hub
|
||||
)
|
||||
GLOBAL_PROTECT(admin_verbs_server)
|
||||
GLOBAL_LIST_INIT(admin_verbs_debug, world.AVerbsDebug())
|
||||
/world/proc/AVerbsDebug()
|
||||
return list(
|
||||
/client/proc/restart_controller,
|
||||
/client/proc/cmd_admin_list_open_jobs,
|
||||
/client/proc/Debug2,
|
||||
/client/proc/cmd_debug_make_powernets,
|
||||
/client/proc/cmd_debug_mob_lists,
|
||||
/client/proc/cmd_admin_delete,
|
||||
/client/proc/cmd_debug_del_all,
|
||||
/client/proc/restart_controller,
|
||||
/client/proc/enable_debug_verbs,
|
||||
/client/proc/callproc,
|
||||
/client/proc/callproc_datum,
|
||||
/client/proc/SDQL2_query,
|
||||
/client/proc/test_movable_UI,
|
||||
/client/proc/test_snap_UI,
|
||||
/client/proc/debugNatureMapGenerator,
|
||||
/client/proc/check_bomb_impacts,
|
||||
/proc/machine_upgrade,
|
||||
/client/proc/populate_world,
|
||||
/client/proc/get_dynex_power, //*debug verbs for dynex explosions.
|
||||
/client/proc/get_dynex_range, //*debug verbs for dynex explosions.
|
||||
/client/proc/set_dynex_scale,
|
||||
/client/proc/cmd_display_del_log,
|
||||
/client/proc/create_outfits,
|
||||
/client/proc/modify_goals,
|
||||
/client/proc/debug_huds,
|
||||
/client/proc/map_template_load,
|
||||
/client/proc/map_template_upload,
|
||||
/client/proc/jump_to_ruin,
|
||||
/client/proc/clear_dynamic_transit,
|
||||
/client/proc/toggle_medal_disable,
|
||||
/client/proc/view_runtimes,
|
||||
/client/proc/pump_random_event,
|
||||
/client/proc/cmd_display_init_log,
|
||||
/client/proc/cmd_display_overlay_log,
|
||||
/client/proc/reload_configuration,
|
||||
/datum/admins/proc/create_or_modify_area,
|
||||
/client/proc/generate_wikichem_list //DO NOT PRESS UNLESS YOU WANT SUPERLAG
|
||||
)
|
||||
GLOBAL_PROTECT(admin_verbs_debug)
|
||||
GLOBAL_LIST_INIT(admin_verbs_possess, list(/proc/possess, /proc/release))
|
||||
GLOBAL_PROTECT(admin_verbs_possess)
|
||||
GLOBAL_LIST_INIT(admin_verbs_permissions, list(/client/proc/edit_admin_permissions))
|
||||
GLOBAL_PROTECT(admin_verbs_permissions)
|
||||
GLOBAL_LIST_INIT(admin_verbs_poll, list(/client/proc/create_poll))
|
||||
|
||||
//verbs which can be hidden - needs work
|
||||
GLOBAL_PROTECT(admin_verbs_poll)
|
||||
GLOBAL_LIST_INIT(admin_verbs_hideable, list(
|
||||
/client/proc/set_ooc,
|
||||
/client/proc/reset_ooc,
|
||||
/client/proc/deadmin,
|
||||
/datum/admins/proc/show_traitor_panel,
|
||||
/datum/admins/proc/toggleenter,
|
||||
/datum/admins/proc/toggleguests,
|
||||
/datum/admins/proc/announce,
|
||||
/datum/admins/proc/set_admin_notice,
|
||||
/client/proc/admin_ghost,
|
||||
/client/proc/toggle_view_range,
|
||||
/client/proc/cmd_admin_subtle_message,
|
||||
/client/proc/cmd_admin_headset_message,
|
||||
/client/proc/cmd_admin_check_contents,
|
||||
/datum/admins/proc/access_news_network,
|
||||
/client/proc/admin_call_shuttle,
|
||||
/client/proc/admin_cancel_shuttle,
|
||||
/client/proc/cmd_admin_direct_narrate,
|
||||
/client/proc/cmd_admin_world_narrate,
|
||||
/client/proc/cmd_admin_local_narrate,
|
||||
/client/proc/play_local_sound,
|
||||
/client/proc/play_sound,
|
||||
/client/proc/set_round_end_sound,
|
||||
/client/proc/cmd_admin_dress,
|
||||
/client/proc/cmd_admin_gib_self,
|
||||
/client/proc/drop_bomb,
|
||||
/client/proc/drop_dynex_bomb,
|
||||
/client/proc/get_dynex_range,
|
||||
/client/proc/get_dynex_power,
|
||||
/client/proc/set_dynex_scale,
|
||||
/client/proc/cinematic,
|
||||
/client/proc/cmd_admin_add_freeform_ai_law,
|
||||
/client/proc/cmd_admin_create_centcom_report,
|
||||
/client/proc/cmd_change_command_name,
|
||||
/client/proc/object_say,
|
||||
/client/proc/toggle_random_events,
|
||||
/datum/admins/proc/startnow,
|
||||
/datum/admins/proc/restart,
|
||||
/datum/admins/proc/delay,
|
||||
/datum/admins/proc/toggleaban,
|
||||
/client/proc/everyone_random,
|
||||
/datum/admins/proc/toggleAI,
|
||||
/client/proc/restart_controller,
|
||||
/client/proc/cmd_admin_list_open_jobs,
|
||||
/client/proc/callproc,
|
||||
/client/proc/callproc_datum,
|
||||
/client/proc/Debug2,
|
||||
/client/proc/reload_admins,
|
||||
/client/proc/cmd_debug_make_powernets,
|
||||
/client/proc/startSinglo,
|
||||
/client/proc/cmd_debug_mob_lists,
|
||||
/client/proc/cmd_debug_del_all,
|
||||
/client/proc/enable_debug_verbs,
|
||||
/proc/possess,
|
||||
/proc/release,
|
||||
/client/proc/reload_admins,
|
||||
/client/proc/panicbunker,
|
||||
/client/proc/addbunkerbypass,
|
||||
/client/proc/revokebunkerbypass,
|
||||
/client/proc/admin_change_sec_level,
|
||||
/client/proc/toggle_nuke,
|
||||
/client/proc/cmd_display_del_log,
|
||||
/client/proc/toggle_combo_hud,
|
||||
/client/proc/debug_huds,
|
||||
/client/proc/cmd_admin_man_up, //CIT CHANGE - adds man up verb
|
||||
/client/proc/cmd_admin_man_up_global //CIT CHANGE - ditto
|
||||
))
|
||||
GLOBAL_PROTECT(admin_verbs_hideable)
|
||||
|
||||
/client/proc/add_admin_verbs()
|
||||
if(holder)
|
||||
control_freak = CONTROL_FREAK_SKIN | CONTROL_FREAK_MACROS
|
||||
|
||||
var/rights = holder.rank.rights
|
||||
verbs += GLOB.admin_verbs_default
|
||||
if(rights & R_BUILDMODE)
|
||||
verbs += /client/proc/togglebuildmodeself
|
||||
if(rights & R_ADMIN)
|
||||
verbs += GLOB.admin_verbs_admin
|
||||
if(rights & R_BAN)
|
||||
verbs += GLOB.admin_verbs_ban
|
||||
if(rights & R_FUN)
|
||||
verbs += GLOB.admin_verbs_fun
|
||||
if(rights & R_SERVER)
|
||||
verbs += GLOB.admin_verbs_server
|
||||
if(rights & R_DEBUG)
|
||||
verbs += GLOB.admin_verbs_debug
|
||||
if(rights & R_POSSESS)
|
||||
verbs += GLOB.admin_verbs_possess
|
||||
if(rights & R_PERMISSIONS)
|
||||
verbs += GLOB.admin_verbs_permissions
|
||||
if(rights & R_STEALTH)
|
||||
verbs += /client/proc/stealth
|
||||
if(rights & R_ADMIN)
|
||||
verbs += GLOB.admin_verbs_poll
|
||||
if(rights & R_SOUNDS)
|
||||
verbs += GLOB.admin_verbs_sounds
|
||||
if(CONFIG_GET(string/invoke_youtubedl))
|
||||
verbs += /client/proc/play_web_sound
|
||||
if(rights & R_SPAWN)
|
||||
verbs += GLOB.admin_verbs_spawn
|
||||
|
||||
/client/proc/remove_admin_verbs()
|
||||
verbs.Remove(
|
||||
GLOB.admin_verbs_default,
|
||||
/client/proc/togglebuildmodeself,
|
||||
GLOB.admin_verbs_admin,
|
||||
GLOB.admin_verbs_ban,
|
||||
GLOB.admin_verbs_fun,
|
||||
GLOB.admin_verbs_server,
|
||||
GLOB.admin_verbs_debug,
|
||||
GLOB.admin_verbs_possess,
|
||||
GLOB.admin_verbs_permissions,
|
||||
/client/proc/stealth,
|
||||
GLOB.admin_verbs_poll,
|
||||
GLOB.admin_verbs_sounds,
|
||||
/client/proc/play_web_sound,
|
||||
GLOB.admin_verbs_spawn,
|
||||
/*Debug verbs added by "show debug verbs"*/
|
||||
GLOB.admin_verbs_debug_mapping,
|
||||
/client/proc/disable_debug_verbs,
|
||||
/client/proc/readmin
|
||||
)
|
||||
|
||||
/client/proc/hide_most_verbs()//Allows you to keep some functionality while hiding some verbs
|
||||
set name = "Adminverbs - Hide Most"
|
||||
set category = "Admin"
|
||||
|
||||
verbs.Remove(/client/proc/hide_most_verbs, GLOB.admin_verbs_hideable)
|
||||
verbs += /client/proc/show_verbs
|
||||
|
||||
to_chat(src, "<span class='interface'>Most of your adminverbs have been hidden.</span>")
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Hide Most Adminverbs") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
return
|
||||
|
||||
/client/proc/hide_verbs()
|
||||
set name = "Adminverbs - Hide All"
|
||||
set category = "Admin"
|
||||
|
||||
remove_admin_verbs()
|
||||
verbs += /client/proc/show_verbs
|
||||
|
||||
to_chat(src, "<span class='interface'>Almost all of your adminverbs have been hidden.</span>")
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Hide All Adminverbs") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
return
|
||||
|
||||
/client/proc/show_verbs()
|
||||
set name = "Adminverbs - Show"
|
||||
set category = "Admin"
|
||||
|
||||
verbs -= /client/proc/show_verbs
|
||||
add_admin_verbs()
|
||||
|
||||
to_chat(src, "<span class='interface'>All of your adminverbs are now visible.</span>")
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Show Adminverbs") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
|
||||
|
||||
|
||||
/client/proc/admin_ghost()
|
||||
set category = "Admin"
|
||||
set name = "Aghost"
|
||||
if(!holder)
|
||||
return
|
||||
if(isobserver(mob))
|
||||
//re-enter
|
||||
var/mob/dead/observer/ghost = mob
|
||||
if(!ghost.mind || !ghost.mind.current) //won't do anything if there is no body
|
||||
return
|
||||
if(!ghost.can_reenter_corpse)
|
||||
log_admin("[key_name(usr)] re-entered corpse")
|
||||
message_admins("[key_name_admin(usr)] re-entered corpse")
|
||||
ghost.can_reenter_corpse = 1 //force re-entering even when otherwise not possible
|
||||
ghost.reenter_corpse()
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Admin Reenter") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
else if(isnewplayer(mob))
|
||||
to_chat(src, "<font color='red'>Error: Aghost: Can't admin-ghost whilst in the lobby. Join or Observe first.</font>")
|
||||
else
|
||||
//ghostize
|
||||
log_admin("[key_name(usr)] admin ghosted.")
|
||||
message_admins("[key_name_admin(usr)] admin ghosted.")
|
||||
var/mob/body = mob
|
||||
body.ghostize(1)
|
||||
if(body && !body.key)
|
||||
body.key = "@[key]" //Haaaaaaaack. But the people have spoken. If it breaks; blame adminbus
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Admin Ghost") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
|
||||
/client/proc/invisimin()
|
||||
set name = "Invisimin"
|
||||
set category = "Admin"
|
||||
set desc = "Toggles ghost-like invisibility (Don't abuse this)"
|
||||
if(holder && mob)
|
||||
if(mob.invisibility == INVISIBILITY_OBSERVER)
|
||||
mob.invisibility = initial(mob.invisibility)
|
||||
to_chat(mob, "<span class='boldannounce'>Invisimin off. Invisibility reset.</span>")
|
||||
else
|
||||
mob.invisibility = INVISIBILITY_OBSERVER
|
||||
to_chat(mob, "<span class='adminnotice'><b>Invisimin on. You are now as invisible as a ghost.</b></span>")
|
||||
|
||||
/client/proc/check_antagonists()
|
||||
set name = "Check Antagonists"
|
||||
set category = "Admin"
|
||||
if(holder)
|
||||
holder.check_antagonists()
|
||||
log_admin("[key_name(usr)] checked antagonists.") //for tsar~
|
||||
if(!isobserver(usr) && SSticker.HasRoundStarted())
|
||||
message_admins("[key_name_admin(usr)] checked antagonists.")
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Check Antagonists") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
/client/proc/unban_panel()
|
||||
set name = "Unban Panel"
|
||||
set category = "Admin"
|
||||
if(holder)
|
||||
if(CONFIG_GET(flag/ban_legacy_system))
|
||||
holder.unbanpanel()
|
||||
else
|
||||
holder.DB_ban_panel()
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Unban Panel") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
/client/proc/game_panel()
|
||||
set name = "Game Panel"
|
||||
set category = "Admin"
|
||||
if(holder)
|
||||
holder.Game()
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Game Panel") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
/client/proc/secrets()
|
||||
set name = "Secrets"
|
||||
set category = "Admin"
|
||||
if (holder)
|
||||
holder.Secrets()
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Secrets Panel") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
|
||||
/client/proc/findStealthKey(txt)
|
||||
if(txt)
|
||||
for(var/P in GLOB.stealthminID)
|
||||
if(GLOB.stealthminID[P] == txt)
|
||||
return P
|
||||
txt = GLOB.stealthminID[ckey]
|
||||
return txt
|
||||
|
||||
/client/proc/createStealthKey()
|
||||
var/num = (rand(0,1000))
|
||||
var/i = 0
|
||||
while(i == 0)
|
||||
i = 1
|
||||
for(var/P in GLOB.stealthminID)
|
||||
if(num == GLOB.stealthminID[P])
|
||||
num++
|
||||
i = 0
|
||||
GLOB.stealthminID["[ckey]"] = "@[num2text(num)]"
|
||||
|
||||
/client/proc/stealth()
|
||||
set category = "Admin"
|
||||
set name = "Stealth Mode"
|
||||
if(holder)
|
||||
if(holder.fakekey)
|
||||
holder.fakekey = null
|
||||
if(isobserver(mob))
|
||||
mob.invisibility = initial(mob.invisibility)
|
||||
mob.alpha = initial(mob.alpha)
|
||||
mob.name = initial(mob.name)
|
||||
mob.mouse_opacity = initial(mob.mouse_opacity)
|
||||
else
|
||||
var/new_key = ckeyEx(input("Enter your desired display name.", "Fake Key", key) as text|null)
|
||||
if(!new_key)
|
||||
return
|
||||
if(length(new_key) >= 26)
|
||||
new_key = copytext(new_key, 1, 26)
|
||||
holder.fakekey = new_key
|
||||
createStealthKey()
|
||||
if(isobserver(mob))
|
||||
mob.invisibility = INVISIBILITY_MAXIMUM //JUST IN CASE
|
||||
mob.alpha = 0 //JUUUUST IN CASE
|
||||
mob.name = " "
|
||||
mob.mouse_opacity = MOUSE_OPACITY_TRANSPARENT
|
||||
log_admin("[key_name(usr)] has turned stealth mode [holder.fakekey ? "ON" : "OFF"]")
|
||||
message_admins("[key_name_admin(usr)] has turned stealth mode [holder.fakekey ? "ON" : "OFF"]")
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Stealth Mode") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
/client/proc/drop_bomb()
|
||||
set category = "Special Verbs"
|
||||
set name = "Drop Bomb"
|
||||
set desc = "Cause an explosion of varying strength at your location."
|
||||
|
||||
var/list/choices = list("Small Bomb (1, 2, 3, 3)", "Medium Bomb (2, 3, 4, 4)", "Big Bomb (3, 5, 7, 5)", "Maxcap", "Custom Bomb")
|
||||
var/choice = input("What size explosion would you like to produce? NOTE: You can do all this rapidly and in an IC manner (using cruise missiles!) with the Config/Launch Supplypod verb. WARNING: These ignore the maxcap") as null|anything in choices
|
||||
var/turf/epicenter = mob.loc
|
||||
|
||||
switch(choice)
|
||||
if(null)
|
||||
return 0
|
||||
if("Small Bomb (1, 2, 3, 3)")
|
||||
explosion(epicenter, 1, 2, 3, 3, TRUE, TRUE)
|
||||
if("Medium Bomb (2, 3, 4, 4)")
|
||||
explosion(epicenter, 2, 3, 4, 4, TRUE, TRUE)
|
||||
if("Big Bomb (3, 5, 7, 5)")
|
||||
explosion(epicenter, 3, 5, 7, 5, TRUE, TRUE)
|
||||
if("Maxcap")
|
||||
explosion(epicenter, GLOB.MAX_EX_DEVESTATION_RANGE, GLOB.MAX_EX_HEAVY_RANGE, GLOB.MAX_EX_LIGHT_RANGE, GLOB.MAX_EX_FLASH_RANGE)
|
||||
if("Custom Bomb")
|
||||
var/devastation_range = input("Devastation range (in tiles):") as null|num
|
||||
if(devastation_range == null)
|
||||
return
|
||||
var/heavy_impact_range = input("Heavy impact range (in tiles):") as null|num
|
||||
if(heavy_impact_range == null)
|
||||
return
|
||||
var/light_impact_range = input("Light impact range (in tiles):") as null|num
|
||||
if(light_impact_range == null)
|
||||
return
|
||||
var/flash_range = input("Flash range (in tiles):") as null|num
|
||||
if(flash_range == null)
|
||||
return
|
||||
if(devastation_range > GLOB.MAX_EX_DEVESTATION_RANGE || heavy_impact_range > GLOB.MAX_EX_HEAVY_RANGE || light_impact_range > GLOB.MAX_EX_LIGHT_RANGE || flash_range > GLOB.MAX_EX_FLASH_RANGE)
|
||||
if(alert("Bomb is bigger than the maxcap. Continue?",,"Yes","No") != "Yes")
|
||||
return
|
||||
epicenter = mob.loc //We need to reupdate as they may have moved again
|
||||
explosion(epicenter, devastation_range, heavy_impact_range, light_impact_range, flash_range, TRUE, TRUE)
|
||||
message_admins("[ADMIN_LOOKUPFLW(usr)] creating an admin explosion at [epicenter.loc].")
|
||||
log_admin("[key_name(usr)] created an admin explosion at [epicenter.loc].")
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Drop Bomb") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
/client/proc/drop_dynex_bomb()
|
||||
set category = "Special Verbs"
|
||||
set name = "Drop DynEx Bomb"
|
||||
set desc = "Cause an explosion of varying strength at your location."
|
||||
|
||||
var/ex_power = input("Explosive Power:") as null|num
|
||||
var/turf/epicenter = mob.loc
|
||||
if(ex_power && epicenter)
|
||||
dyn_explosion(epicenter, ex_power)
|
||||
message_admins("[ADMIN_LOOKUPFLW(usr)] creating an admin explosion at [epicenter.loc].")
|
||||
log_admin("[key_name(usr)] created an admin explosion at [epicenter.loc].")
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Drop Dynamic Bomb") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
/client/proc/get_dynex_range()
|
||||
set category = "Debug"
|
||||
set name = "Get DynEx Range"
|
||||
set desc = "Get the estimated range of a bomb, using explosive power."
|
||||
|
||||
var/ex_power = input("Explosive Power:") as null|num
|
||||
if (isnull(ex_power))
|
||||
return
|
||||
var/range = round((2 * ex_power)**GLOB.DYN_EX_SCALE)
|
||||
to_chat(usr, "Estimated Explosive Range: (Devastation: [round(range*0.25)], Heavy: [round(range*0.5)], Light: [round(range)])")
|
||||
|
||||
/client/proc/get_dynex_power()
|
||||
set category = "Debug"
|
||||
set name = "Get DynEx Power"
|
||||
set desc = "Get the estimated required power of a bomb, to reach a specific range."
|
||||
|
||||
var/ex_range = input("Light Explosion Range:") as null|num
|
||||
if (isnull(ex_range))
|
||||
return
|
||||
var/power = (0.5 * ex_range)**(1/GLOB.DYN_EX_SCALE)
|
||||
to_chat(usr, "Estimated Explosive Power: [power]")
|
||||
|
||||
/client/proc/set_dynex_scale()
|
||||
set category = "Debug"
|
||||
set name = "Set DynEx Scale"
|
||||
set desc = "Set the scale multiplier of dynex explosions. The default is 0.5."
|
||||
|
||||
var/ex_scale = input("New DynEx Scale:") as null|num
|
||||
if(!ex_scale)
|
||||
return
|
||||
GLOB.DYN_EX_SCALE = ex_scale
|
||||
log_admin("[key_name(usr)] has modified Dynamic Explosion Scale: [ex_scale]")
|
||||
message_admins("[key_name_admin(usr)] has modified Dynamic Explosion Scale: [ex_scale]")
|
||||
|
||||
/client/proc/give_spell(mob/T in GLOB.mob_list)
|
||||
set category = "Fun"
|
||||
set name = "Give Spell"
|
||||
set desc = "Gives a spell to a mob."
|
||||
|
||||
var/list/spell_list = list()
|
||||
var/type_length = length("/obj/effect/proc_holder/spell") + 2
|
||||
for(var/A in GLOB.spells)
|
||||
spell_list[copytext("[A]", type_length)] = A
|
||||
var/obj/effect/proc_holder/spell/S = input("Choose the spell to give to that guy", "ABRAKADABRA") as null|anything in spell_list
|
||||
if(!S)
|
||||
return
|
||||
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Give Spell") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
log_admin("[key_name(usr)] gave [key_name(T)] the spell [S].")
|
||||
message_admins("<span class='adminnotice'>[key_name_admin(usr)] gave [key_name(T)] the spell [S].</span>")
|
||||
|
||||
S = spell_list[S]
|
||||
if(T.mind)
|
||||
T.mind.AddSpell(new S)
|
||||
else
|
||||
T.AddSpell(new S)
|
||||
message_admins("<span class='danger'>Spells given to mindless mobs will not be transferred in mindswap or cloning!</span>")
|
||||
|
||||
/client/proc/remove_spell(mob/T in GLOB.mob_list)
|
||||
set category = "Fun"
|
||||
set name = "Remove Spell"
|
||||
set desc = "Remove a spell from the selected mob."
|
||||
|
||||
if(T && T.mind)
|
||||
var/obj/effect/proc_holder/spell/S = input("Choose the spell to remove", "NO ABRAKADABRA") as null|anything in T.mind.spell_list
|
||||
if(S)
|
||||
T.mind.RemoveSpell(S)
|
||||
log_admin("[key_name(usr)] removed the spell [S] from [key_name(T)].")
|
||||
message_admins("<span class='adminnotice'>[key_name_admin(usr)] removed the spell [S] from [key_name(T)].</span>")
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Remove Spell") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
/client/proc/give_disease(mob/living/T in GLOB.mob_living_list)
|
||||
set category = "Fun"
|
||||
set name = "Give Disease"
|
||||
set desc = "Gives a Disease to a mob."
|
||||
if(!istype(T))
|
||||
to_chat(src, "<span class='notice'>You can only give a disease to a mob of type /mob/living.</span>")
|
||||
return
|
||||
var/datum/disease/D = input("Choose the disease to give to that guy", "ACHOO") as null|anything in SSdisease.diseases
|
||||
if(!D)
|
||||
return
|
||||
T.ForceContractDisease(new D, FALSE, TRUE)
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Give Disease") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
log_admin("[key_name(usr)] gave [key_name(T)] the disease [D].")
|
||||
message_admins("<span class='adminnotice'>[key_name_admin(usr)] gave [key_name(T)] the disease [D].</span>")
|
||||
|
||||
/client/proc/object_say(obj/O in world)
|
||||
set category = "Special Verbs"
|
||||
set name = "OSay"
|
||||
set desc = "Makes an object say something."
|
||||
var/message = input(usr, "What do you want the message to be?", "Make Sound") as text | null
|
||||
if(!message)
|
||||
return
|
||||
O.say(message)
|
||||
log_admin("[key_name(usr)] made [O] at [AREACOORD(O)] say \"[message]\"")
|
||||
message_admins("<span class='adminnotice'>[key_name_admin(usr)] made [O] at [AREACOORD(O)]. say \"[message]\"</span>")
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Object Say") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
/client/proc/togglebuildmodeself()
|
||||
set name = "Toggle Build Mode Self"
|
||||
set category = "Special Verbs"
|
||||
if (!(holder.rank.rights & R_BUILDMODE))
|
||||
return
|
||||
if(src.mob)
|
||||
togglebuildmode(src.mob)
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Toggle Build Mode") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
/client/proc/check_ai_laws()
|
||||
set name = "Check AI Laws"
|
||||
set category = "Admin"
|
||||
if(holder)
|
||||
src.holder.output_ai_laws()
|
||||
|
||||
/client/proc/deadmin()
|
||||
set name = "Deadmin"
|
||||
set category = "Admin"
|
||||
set desc = "Shed your admin powers."
|
||||
|
||||
if(!holder)
|
||||
return
|
||||
|
||||
if(has_antag_hud())
|
||||
toggle_combo_hud()
|
||||
|
||||
holder.deactivate()
|
||||
|
||||
to_chat(src, "<span class='interface'>You are now a normal player.</span>")
|
||||
log_admin("[src] deadmined themself.")
|
||||
message_admins("[src] deadmined themself.")
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Deadmin")
|
||||
|
||||
/client/proc/readmin()
|
||||
set name = "Readmin"
|
||||
set category = "Admin"
|
||||
set desc = "Regain your admin powers."
|
||||
|
||||
var/datum/admins/A = GLOB.deadmins[ckey]
|
||||
|
||||
if(!A)
|
||||
A = GLOB.admin_datums[ckey]
|
||||
if (!A)
|
||||
var/msg = " is trying to readmin but they have no deadmin entry"
|
||||
message_admins("[key_name_admin(src)][msg]")
|
||||
log_admin_private("[key_name(src)][msg]")
|
||||
return
|
||||
|
||||
A.associate(src)
|
||||
|
||||
if (!holder)
|
||||
return //This can happen if an admin attempts to vv themself into somebody elses's deadmin datum by getting ref via brute force
|
||||
|
||||
to_chat(src, "<span class='interface'>You are now an admin.</span>")
|
||||
message_admins("[src] re-adminned themselves.")
|
||||
log_admin("[src] re-adminned themselves.")
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Readmin")
|
||||
|
||||
/client/proc/populate_world(amount = 50 as num)
|
||||
set name = "Populate World"
|
||||
set category = "Debug"
|
||||
set desc = "(\"Amount of mobs to create\") Populate the world with test mobs."
|
||||
|
||||
if (amount > 0)
|
||||
var/area/area
|
||||
var/list/candidates
|
||||
var/turf/open/floor/tile
|
||||
var/j,k
|
||||
|
||||
for (var/i = 1 to amount)
|
||||
j = 100
|
||||
|
||||
do
|
||||
area = pick(GLOB.the_station_areas)
|
||||
|
||||
if (area)
|
||||
|
||||
candidates = get_area_turfs(area)
|
||||
|
||||
if (candidates.len)
|
||||
k = 100
|
||||
|
||||
do
|
||||
tile = pick(candidates)
|
||||
while ((!tile || !istype(tile)) && --k > 0)
|
||||
|
||||
if (tile)
|
||||
var/mob/living/carbon/human/hooman = new(tile)
|
||||
hooman.equipOutfit(pick(subtypesof(/datum/outfit)))
|
||||
testing("Spawned test mob at [COORD(tile)]")
|
||||
while (!area && --j > 0)
|
||||
|
||||
/client/proc/toggle_AI_interact()
|
||||
set name = "Toggle Admin AI Interact"
|
||||
set category = "Admin"
|
||||
set desc = "Allows you to interact with most machines as an AI would as a ghost"
|
||||
|
||||
AI_Interact = !AI_Interact
|
||||
if(mob && IsAdminGhost(mob))
|
||||
mob.has_unlimited_silicon_privilege = AI_Interact
|
||||
|
||||
log_admin("[key_name(usr)] has [AI_Interact ? "activated" : "deactivated"] Admin AI Interact")
|
||||
message_admins("[key_name_admin(usr)] has [AI_Interact ? "activated" : "deactivated"] their AI interaction")
|
||||
@@ -0,0 +1,46 @@
|
||||
|
||||
/datum/admins/proc/create_mob(mob/user)
|
||||
var/static/create_mob_html
|
||||
if (!create_mob_html)
|
||||
var/mobjs = null
|
||||
mobjs = jointext(typesof(/mob), ";")
|
||||
create_mob_html = file2text('html/create_object.html')
|
||||
create_mob_html = replacetext(create_mob_html, "Create Object", "Create Mob")
|
||||
create_mob_html = replacetext(create_mob_html, "null /* object types */", "\"[mobjs]\"")
|
||||
|
||||
user << browse(create_panel_helper(create_mob_html), "window=create_mob;size=425x475")
|
||||
|
||||
/proc/randomize_human(mob/living/carbon/human/H)
|
||||
H.gender = pick(MALE, FEMALE)
|
||||
H.real_name = random_unique_name(H.gender)
|
||||
H.name = H.real_name
|
||||
H.underwear = random_underwear(H.gender)
|
||||
H.undie_color = random_short_color()
|
||||
H.undershirt = random_undershirt(H.gender)
|
||||
H.shirt_color = random_short_color()
|
||||
H.skin_tone = random_skin_tone()
|
||||
H.hair_style = random_hair_style(H.gender)
|
||||
H.facial_hair_style = random_facial_hair_style(H.gender)
|
||||
H.hair_color = random_short_color()
|
||||
H.facial_hair_color = H.hair_color
|
||||
H.eye_color = random_eye_color()
|
||||
H.dna.blood_type = random_blood_type()
|
||||
H.saved_underwear = H.underwear
|
||||
H.saved_undershirt = H.undershirt
|
||||
H.saved_socks = H.socks
|
||||
|
||||
// Mutant randomizing, doesn't affect the mob appearance unless it's the specific mutant.
|
||||
H.dna.features["mcolor"] = random_short_color()
|
||||
H.dna.features["tail_lizard"] = pick(GLOB.tails_list_lizard)
|
||||
H.dna.features["snout"] = pick(GLOB.snouts_list)
|
||||
H.dna.features["horns"] = pick(GLOB.horns_list)
|
||||
H.dna.features["frills"] = pick(GLOB.frills_list)
|
||||
H.dna.features["spines"] = pick(GLOB.spines_list)
|
||||
H.dna.features["body_markings"] = pick(GLOB.body_markings_list)
|
||||
H.dna.features["insect_wings"] = pick(GLOB.insect_wings_list)
|
||||
H.dna.features["deco_wings"] = pick(GLOB.deco_wings_list)
|
||||
H.dna.features["insect_fluff"] = pick(GLOB.insect_fluffs_list)
|
||||
|
||||
H.update_body()
|
||||
H.update_hair()
|
||||
H.update_body_parts()
|
||||
@@ -0,0 +1,754 @@
|
||||
/datum/admins/proc/Secrets()
|
||||
if(!check_rights(0))
|
||||
return
|
||||
|
||||
var/list/dat = list("<B>The first rule of adminbuse is: you don't talk about the adminbuse.</B><HR>")
|
||||
|
||||
dat +={"
|
||||
<B>General Secrets</B><BR>
|
||||
<BR>
|
||||
<A href='?src=[REF(src)];[HrefToken()];secrets=admin_log'>Admin Log</A><BR>
|
||||
<A href='?src=[REF(src)];[HrefToken()];secrets=show_admins'>Show Admin List</A><BR>
|
||||
<A href='?src=[REF(src)];[HrefToken()];secrets=mentor_log'>Mentor Log</A><BR>
|
||||
<BR>
|
||||
"}
|
||||
|
||||
if(check_rights(R_ADMIN,0))
|
||||
dat += {"
|
||||
<B>Admin Secrets</B><BR>
|
||||
<BR>
|
||||
<A href='?src=[REF(src)];[HrefToken()];secrets=clear_virus'>Cure all diseases currently in existence</A><BR>
|
||||
<A href='?src=[REF(src)];[HrefToken()];secrets=list_bombers'>Bombing List</A><BR>
|
||||
<A href='?src=[REF(src)];[HrefToken()];secrets=check_antagonist'>Show current traitors and objectives</A><BR>
|
||||
<A href='?src=[REF(src)];[HrefToken()];secrets=list_signalers'>Show last [length(GLOB.lastsignalers)] signalers</A><BR>
|
||||
<A href='?src=[REF(src)];[HrefToken()];secrets=list_lawchanges'>Show last [length(GLOB.lawchanges)] law changes</A><BR>
|
||||
<A href='?src=[REF(src)];[HrefToken()];secrets=showailaws'>Show AI Laws</A><BR>
|
||||
<A href='?src=[REF(src)];[HrefToken()];secrets=showgm'>Show Game Mode</A><BR>
|
||||
<A href='?src=[REF(src)];[HrefToken()];secrets=manifest'>Show Crew Manifest</A><BR>
|
||||
<A href='?src=[REF(src)];[HrefToken()];secrets=DNA'>List DNA (Blood)</A><BR>
|
||||
<A href='?src=[REF(src)];[HrefToken()];secrets=fingerprints'>List Fingerprints</A><BR>
|
||||
<A href='?src=[REF(src)];[HrefToken()];secrets=ctfbutton'>Enable/Disable CTF</A><BR><BR>
|
||||
<A href='?src=[REF(src)];[HrefToken()];secrets=tdomereset'>Reset Thunderdome to default state</A><BR>
|
||||
<A href='?src=[REF(src)];[HrefToken()];secrets=set_name'>Rename Station Name</A><BR>
|
||||
<A href='?src=[REF(src)];[HrefToken()];secrets=reset_name'>Reset Station Name</A><BR>
|
||||
<A href='?src=[REF(src)];[HrefToken()];secrets=night_shift_set'>Set Night Shift Mode</A><BR>
|
||||
<BR>
|
||||
<B>Shuttles</B><BR>
|
||||
<BR>
|
||||
<A href='?src=[REF(src)];[HrefToken()];secrets=moveferry'>Move Ferry</A><BR>
|
||||
<A href='?src=[REF(src)];[HrefToken()];secrets=togglearrivals'>Toggle Arrivals Ferry</A><BR>
|
||||
<A href='?src=[REF(src)];[HrefToken()];secrets=moveminingshuttle'>Move Mining Shuttle</A><BR>
|
||||
<A href='?src=[REF(src)];[HrefToken()];secrets=movelaborshuttle'>Move Labor Shuttle</A><BR>
|
||||
<BR>
|
||||
"}
|
||||
|
||||
if(check_rights(R_FUN,0))
|
||||
dat += {"
|
||||
<B>Fun Secrets</B><BR>
|
||||
<BR>
|
||||
<A href='?src=[REF(src)];[HrefToken()];secrets=virus'>Trigger a Virus Outbreak</A><BR>
|
||||
<A href='?src=[REF(src)];[HrefToken()];secrets=monkey'>Turn all humans into monkeys</A><BR>
|
||||
<A href='?src=[REF(src)];[HrefToken()];secrets=anime'>Chinese Cartoons</A><BR>
|
||||
<A href='?src=[REF(src)];[HrefToken()];secrets=allspecies'>Change the species of all humans</A><BR>
|
||||
<A href='?src=[REF(src)];[HrefToken()];secrets=power'>Make all areas powered</A><BR>
|
||||
<A href='?src=[REF(src)];[HrefToken()];secrets=unpower'>Make all areas unpowered</A><BR>
|
||||
<A href='?src=[REF(src)];[HrefToken()];secrets=quickpower'>Power all SMES</A><BR>
|
||||
<A href='?src=[REF(src)];[HrefToken()];secrets=tripleAI'>Triple AI mode (needs to be used in the lobby)</A><BR>
|
||||
<A href='?src=[REF(src)];[HrefToken()];secrets=traitor_all'>Everyone is the traitor</A><BR>
|
||||
<A href='?src=[REF(src)];[HrefToken()];secrets=ak47s'>AK-47s For Everyone!</A><BR>
|
||||
<A href='?src=[REF(src)];[HrefToken()];secrets=guns'>Summon Guns</A><BR>
|
||||
<A href='?src=[REF(src)];[HrefToken()];secrets=magic'>Summon Magic</A><BR>
|
||||
<A href='?src=[REF(src)];[HrefToken()];secrets=events'>Summon Events (Toggle)</A><BR>
|
||||
<A href='?src=[REF(src)];[HrefToken()];secrets=onlyone'>There can only be one!</A><BR>
|
||||
<A href='?src=[REF(src)];[HrefToken()];secrets=delayed_onlyone'>There can only be one! (40-second delay)</A><BR>
|
||||
<A href='?src=[REF(src)];[HrefToken()];secrets=retardify'>Make all players retarded</A><BR>
|
||||
<A href='?src=[REF(src)];[HrefToken()];secrets=eagles'>Egalitarian Station Mode</A><BR>
|
||||
<A href='?src=[REF(src)];[HrefToken()];secrets=blackout'>Break all lights</A><BR>
|
||||
<A href='?src=[REF(src)];[HrefToken()];secrets=whiteout'>Fix all lights</A><BR>
|
||||
<A href='?src=[REF(src)];[HrefToken()];secrets=floorlava'>The floor is lava! (DANGEROUS: extremely lame)</A><BR>
|
||||
<A href='?src=[REF(src)];[HrefToken()];secrets=customportal'>Spawn a custom portal storm</A><BR>
|
||||
<BR>
|
||||
<A href='?src=[REF(src)];[HrefToken()];secrets=flipmovement'>Flip client movement directions</A><BR>
|
||||
<A href='?src=[REF(src)];[HrefToken()];secrets=randommovement'>Randomize client movement directions</A><BR>
|
||||
<A href='?src=[REF(src)];[HrefToken()];secrets=custommovement'>Set each movement direction manually</A><BR>
|
||||
<A href='?src=[REF(src)];[HrefToken()];secrets=resetmovement'>Reset movement directions to default</A><BR>
|
||||
<BR>
|
||||
<A href='?src=[REF(src)];[HrefToken()];secrets=changebombcap'>Change bomb cap</A><BR>
|
||||
<A href='?src=[REF(src)];[HrefToken()];secrets=masspurrbation'>Mass Purrbation</A><BR>
|
||||
<A href='?src=[REF(src)];[HrefToken()];secrets=massremovepurrbation'>Mass Remove Purrbation</A><BR>
|
||||
"}
|
||||
|
||||
dat += "<BR>"
|
||||
|
||||
if(check_rights(R_DEBUG,0))
|
||||
dat += {"
|
||||
<B>Security Level Elevated</B><BR>
|
||||
<BR>
|
||||
<A href='?src=[REF(src)];[HrefToken()];secrets=maint_access_engiebrig'>Change all maintenance doors to engie/brig access only</A><BR>
|
||||
<A href='?src=[REF(src)];[HrefToken()];secrets=maint_access_brig'>Change all maintenance doors to brig access only</A><BR>
|
||||
<A href='?src=[REF(src)];[HrefToken()];secrets=infinite_sec'>Remove cap on security officers</A><BR>
|
||||
<BR>
|
||||
"}
|
||||
|
||||
usr << browse(dat.Join(), "window=secrets")
|
||||
return
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/datum/admins/proc/Secrets_topic(item,href_list)
|
||||
var/datum/round_event/E
|
||||
var/ok = 0
|
||||
switch(item)
|
||||
if("admin_log")
|
||||
var/dat = "<B>Admin Log<HR></B>"
|
||||
for(var/l in GLOB.admin_log)
|
||||
dat += "<li>[l]</li>"
|
||||
if(!GLOB.admin_log.len)
|
||||
dat += "No-one has done anything this round!"
|
||||
usr << browse(dat, "window=admin_log")
|
||||
|
||||
if("mentor_log")
|
||||
CitadelMentorLogSecret()
|
||||
|
||||
if("show_admins")
|
||||
var/dat = "<B>Current admins:</B><HR>"
|
||||
if(GLOB.admin_datums)
|
||||
for(var/ckey in GLOB.admin_datums)
|
||||
var/datum/admins/D = GLOB.admin_datums[ckey]
|
||||
dat += "[ckey] - [D.rank.name]<br>"
|
||||
usr << browse(dat, "window=showadmins;size=600x500")
|
||||
|
||||
if("tdomereset")
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
var/delete_mobs = alert("Clear all mobs?","Confirm","Yes","No","Cancel")
|
||||
if(delete_mobs == "Cancel")
|
||||
return
|
||||
|
||||
log_admin("[key_name(usr)] reset the thunderdome to default with delete_mobs==[delete_mobs].", 1)
|
||||
message_admins("<span class='adminnotice'>[key_name_admin(usr)] reset the thunderdome to default with delete_mobs==[delete_mobs].</span>")
|
||||
|
||||
var/area/thunderdome = locate(/area/tdome/arena)
|
||||
if(delete_mobs == "Yes")
|
||||
for(var/mob/living/mob in thunderdome)
|
||||
qdel(mob) //Clear mobs
|
||||
for(var/obj/obj in thunderdome)
|
||||
if(!istype(obj, /obj/machinery/camera))
|
||||
qdel(obj) //Clear objects
|
||||
|
||||
var/area/template = locate(/area/tdome/arena_source)
|
||||
template.copy_contents_to(thunderdome)
|
||||
|
||||
if("clear_virus")
|
||||
|
||||
var/choice = input("Are you sure you want to cure all disease?") in list("Yes", "Cancel")
|
||||
if(choice == "Yes")
|
||||
message_admins("[key_name_admin(usr)] has cured all diseases.")
|
||||
for(var/thing in SSdisease.active_diseases)
|
||||
var/datum/disease/D = thing
|
||||
D.cure(0)
|
||||
if("set_name")
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
var/new_name = input(usr, "Please input a new name for the station.", "What?", "") as text|null
|
||||
if(!new_name)
|
||||
return
|
||||
set_station_name(new_name)
|
||||
log_admin("[key_name(usr)] renamed the station to \"[new_name]\".")
|
||||
message_admins("<span class='adminnotice'>[key_name_admin(usr)] renamed the station to: [new_name].</span>")
|
||||
priority_announce("[command_name()] has renamed the station to \"[new_name]\".")
|
||||
if("night_shift_set")
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
var/val = alert(usr, "What do you want to set night shift to? This will override the automatic system until set to automatic again.", "Night Shift", "On", "Off", "Automatic")
|
||||
switch(val)
|
||||
if("Automatic")
|
||||
if(CONFIG_GET(flag/enable_night_shifts))
|
||||
SSnightshift.can_fire = TRUE
|
||||
SSnightshift.fire()
|
||||
else
|
||||
SSnightshift.update_nightshift(FALSE, TRUE)
|
||||
if("On")
|
||||
SSnightshift.can_fire = FALSE
|
||||
SSnightshift.update_nightshift(TRUE, TRUE)
|
||||
if("Off")
|
||||
SSnightshift.can_fire = FALSE
|
||||
SSnightshift.update_nightshift(FALSE, TRUE)
|
||||
|
||||
if("reset_name")
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
var/new_name = new_station_name()
|
||||
set_station_name(new_name)
|
||||
log_admin("[key_name(usr)] reset the station name.")
|
||||
message_admins("<span class='adminnotice'>[key_name_admin(usr)] reset the station name.</span>")
|
||||
priority_announce("[command_name()] has renamed the station to \"[new_name]\".")
|
||||
|
||||
if("list_bombers")
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
var/dat = "<B>Bombing List</B><HR>"
|
||||
for(var/l in GLOB.bombers)
|
||||
dat += text("[l]<BR>")
|
||||
usr << browse(dat, "window=bombers")
|
||||
|
||||
if("list_signalers")
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
var/dat = "<B>Showing last [length(GLOB.lastsignalers)] signalers.</B><HR>"
|
||||
for(var/sig in GLOB.lastsignalers)
|
||||
dat += "[sig]<BR>"
|
||||
usr << browse(dat, "window=lastsignalers;size=800x500")
|
||||
|
||||
if("list_lawchanges")
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
var/dat = "<B>Showing last [length(GLOB.lawchanges)] law changes.</B><HR>"
|
||||
for(var/sig in GLOB.lawchanges)
|
||||
dat += "[sig]<BR>"
|
||||
usr << browse(dat, "window=lawchanges;size=800x500")
|
||||
|
||||
if("moveminingshuttle")
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
SSblackbox.record_feedback("nested tally", "admin_secrets_fun_used", 1, list("Send Mining Shuttle"))
|
||||
if(!SSshuttle.toggleShuttle("mining","mining_home","mining_away"))
|
||||
message_admins("[key_name_admin(usr)] moved mining shuttle")
|
||||
log_admin("[key_name(usr)] moved the mining shuttle")
|
||||
|
||||
if("movelaborshuttle")
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
SSblackbox.record_feedback("nested tally", "admin_secrets_fun_used", 1, list("Send Labor Shuttle"))
|
||||
if(!SSshuttle.toggleShuttle("laborcamp","laborcamp_home","laborcamp_away"))
|
||||
message_admins("[key_name_admin(usr)] moved labor shuttle")
|
||||
log_admin("[key_name(usr)] moved the labor shuttle")
|
||||
|
||||
if("moveferry")
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
SSblackbox.record_feedback("nested tally", "admin_secrets_fun_used", 1, list("Send CentCom Ferry"))
|
||||
if(!SSshuttle.toggleShuttle("ferry","ferry_home","ferry_away"))
|
||||
message_admins("[key_name_admin(usr)] moved the CentCom ferry")
|
||||
log_admin("[key_name(usr)] moved the CentCom ferry")
|
||||
|
||||
if("togglearrivals")
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
var/obj/docking_port/mobile/arrivals/A = SSshuttle.arrivals
|
||||
if(A)
|
||||
var/new_perma = !A.perma_docked
|
||||
A.perma_docked = new_perma
|
||||
SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Permadock Arrivals Shuttle", "[new_perma ? "Enabled" : "Disabled"]"))
|
||||
message_admins("[key_name_admin(usr)] [new_perma ? "stopped" : "started"] the arrivals shuttle")
|
||||
log_admin("[key_name(usr)] [new_perma ? "stopped" : "started"] the arrivals shuttle")
|
||||
else
|
||||
to_chat(usr, "<span class='admin'>There is no arrivals shuttle</span>")
|
||||
if("showailaws")
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
output_ai_laws()
|
||||
if("showgm")
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
if(!SSticker.HasRoundStarted())
|
||||
alert("The game hasn't started yet!")
|
||||
else if (SSticker.mode)
|
||||
alert("The game mode is [SSticker.mode.name]")
|
||||
else alert("For some reason there's a SSticker, but not a game mode")
|
||||
if("manifest")
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
var/dat = "<B>Showing Crew Manifest.</B><HR>"
|
||||
dat += "<table cellspacing=5><tr><th>Name</th><th>Position</th></tr>"
|
||||
for(var/datum/data/record/t in GLOB.data_core.general)
|
||||
dat += "<tr><td>[t.fields["name"]]</td><td>[t.fields["rank"]]</td></tr>"
|
||||
dat += "</table>"
|
||||
usr << browse(dat, "window=manifest;size=440x410")
|
||||
if("DNA")
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
var/dat = "<B>Showing DNA from blood.</B><HR>"
|
||||
dat += "<table cellspacing=5><tr><th>Name</th><th>DNA</th><th>Blood Type</th></tr>"
|
||||
for(var/mob/living/carbon/human/H in GLOB.carbon_list)
|
||||
if(H.ckey)
|
||||
dat += "<tr><td>[H]</td><td>[H.dna.unique_enzymes]</td><td>[H.dna.blood_type]</td></tr>"
|
||||
dat += "</table>"
|
||||
usr << browse(dat, "window=DNA;size=440x410")
|
||||
if("fingerprints")
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
var/dat = "<B>Showing Fingerprints.</B><HR>"
|
||||
dat += "<table cellspacing=5><tr><th>Name</th><th>Fingerprints</th></tr>"
|
||||
for(var/mob/living/carbon/human/H in GLOB.carbon_list)
|
||||
if(H.ckey)
|
||||
dat += "<tr><td>[H]</td><td>[md5(H.dna.uni_identity)]</td></tr>"
|
||||
dat += "</table>"
|
||||
usr << browse(dat, "window=fingerprints;size=440x410")
|
||||
|
||||
if("monkey")
|
||||
if(!check_rights(R_FUN))
|
||||
return
|
||||
SSblackbox.record_feedback("nested tally", "admin_secrets_fun_used", 1, list("Monkeyize All Humans"))
|
||||
for(var/mob/living/carbon/human/H in GLOB.carbon_list)
|
||||
spawn(0)
|
||||
H.monkeyize()
|
||||
ok = 1
|
||||
|
||||
if("allspecies")
|
||||
if(!check_rights(R_FUN))
|
||||
return
|
||||
var/result = input(usr, "Please choose a new species","Species") as null|anything in GLOB.species_list
|
||||
if(result)
|
||||
SSblackbox.record_feedback("nested tally", "admin_secrets_fun_used", 1, list("Mass Species Change", "[result]"))
|
||||
log_admin("[key_name(usr)] turned all humans into [result]", 1)
|
||||
message_admins("\blue [key_name_admin(usr)] turned all humans into [result]")
|
||||
var/newtype = GLOB.species_list[result]
|
||||
for(var/mob/living/carbon/human/H in GLOB.carbon_list)
|
||||
H.set_species(newtype)
|
||||
|
||||
if("tripleAI")
|
||||
if(!check_rights(R_FUN))
|
||||
return
|
||||
usr.client.triple_ai()
|
||||
SSblackbox.record_feedback("nested tally", "admin_secrets_fun_used", 1, list("Triple AI"))
|
||||
|
||||
if("power")
|
||||
if(!check_rights(R_FUN))
|
||||
return
|
||||
SSblackbox.record_feedback("nested tally", "admin_secrets_fun_used", 1, list("Power All APCs"))
|
||||
log_admin("[key_name(usr)] made all areas powered", 1)
|
||||
message_admins("<span class='adminnotice'>[key_name_admin(usr)] made all areas powered</span>")
|
||||
power_restore()
|
||||
|
||||
if("unpower")
|
||||
if(!check_rights(R_FUN))
|
||||
return
|
||||
SSblackbox.record_feedback("nested tally", "admin_secrets_fun_used", 1, list("Depower All APCs"))
|
||||
log_admin("[key_name(usr)] made all areas unpowered", 1)
|
||||
message_admins("<span class='adminnotice'>[key_name_admin(usr)] made all areas unpowered</span>")
|
||||
power_failure()
|
||||
|
||||
if("quickpower")
|
||||
if(!check_rights(R_FUN))
|
||||
return
|
||||
SSblackbox.record_feedback("nested tally", "admin_secrets_fun_used", 1, list("Power All SMESs"))
|
||||
log_admin("[key_name(usr)] made all SMESs powered", 1)
|
||||
message_admins("<span class='adminnotice'>[key_name_admin(usr)] made all SMESs powered</span>")
|
||||
power_restore_quick()
|
||||
|
||||
if("traitor_all")
|
||||
if(!check_rights(R_FUN))
|
||||
return
|
||||
if(!SSticker.HasRoundStarted())
|
||||
alert("The game hasn't started yet!")
|
||||
return
|
||||
var/objective = copytext(sanitize(input("Enter an objective")),1,MAX_MESSAGE_LEN)
|
||||
if(!objective)
|
||||
return
|
||||
SSblackbox.record_feedback("nested tally", "admin_secrets_fun_used", 1, list("Traitor All", "[objective]"))
|
||||
for(var/mob/living/H in GLOB.player_list)
|
||||
if(!(ishuman(H)||istype(H, /mob/living/silicon/)))
|
||||
continue
|
||||
if(H.stat == DEAD || !H.client || !H.mind || ispAI(H))
|
||||
continue
|
||||
if(is_special_character(H))
|
||||
continue
|
||||
var/datum/antagonist/traitor/T = new()
|
||||
T.give_objectives = FALSE
|
||||
var/datum/objective/new_objective = new
|
||||
new_objective.owner = H
|
||||
new_objective.explanation_text = objective
|
||||
T.add_objective(new_objective)
|
||||
H.mind.add_antag_datum(T)
|
||||
message_admins("<span class='adminnotice'>[key_name_admin(usr)] used everyone is a traitor secret. Objective is [objective]</span>")
|
||||
log_admin("[key_name(usr)] used everyone is a traitor secret. Objective is [objective]")
|
||||
|
||||
if("changebombcap")
|
||||
if(!check_rights(R_FUN))
|
||||
return
|
||||
SSblackbox.record_feedback("nested tally", "admin_secrets_fun_used", 1, list("Bomb Cap"))
|
||||
|
||||
var/newBombCap = input(usr,"What would you like the new bomb cap to be. (entered as the light damage range (the 3rd number in common (1,2,3) notation)) Must be above 4)", "New Bomb Cap", GLOB.MAX_EX_LIGHT_RANGE) as num|null
|
||||
if (!CONFIG_SET(number/bombcap, newBombCap))
|
||||
return
|
||||
|
||||
message_admins("<span class='boldannounce'>[key_name_admin(usr)] changed the bomb cap to [GLOB.MAX_EX_DEVESTATION_RANGE], [GLOB.MAX_EX_HEAVY_RANGE], [GLOB.MAX_EX_LIGHT_RANGE]</span>")
|
||||
log_admin("[key_name(usr)] changed the bomb cap to [GLOB.MAX_EX_DEVESTATION_RANGE], [GLOB.MAX_EX_HEAVY_RANGE], [GLOB.MAX_EX_LIGHT_RANGE]")
|
||||
|
||||
if("blackout")
|
||||
if(!check_rights(R_FUN))
|
||||
return
|
||||
SSblackbox.record_feedback("nested tally", "admin_secrets_fun_used", 1, list("Break All Lights"))
|
||||
message_admins("[key_name_admin(usr)] broke all lights")
|
||||
for(var/obj/machinery/light/L in GLOB.machines)
|
||||
L.break_light_tube()
|
||||
|
||||
if("anime")
|
||||
if(!check_rights(R_FUN))
|
||||
return
|
||||
var/animetype = alert("Would you like to have the clothes be changed?",,"Yes","No","Cancel")
|
||||
|
||||
var/droptype
|
||||
if(animetype =="Yes")
|
||||
droptype = alert("Make the uniforms Nodrop?",,"Yes","No","Cancel")
|
||||
|
||||
if(animetype == "Cancel" || droptype == "Cancel")
|
||||
return
|
||||
SSblackbox.record_feedback("nested tally", "admin_secrets_fun_used", 1, list("Chinese Cartoons"))
|
||||
message_admins("[key_name_admin(usr)] made everything kawaii.")
|
||||
for(var/mob/living/carbon/human/H in GLOB.carbon_list)
|
||||
SEND_SOUND(H, sound(get_announcer_sound("animes")))
|
||||
|
||||
if(H.dna.species.id == "human")
|
||||
if(H.dna.features["tail_human"] == "None" || H.dna.features["ears"] == "None")
|
||||
var/obj/item/organ/ears/cat/ears = new
|
||||
var/obj/item/organ/tail/cat/tail = new
|
||||
ears.Insert(H, drop_if_replaced=FALSE)
|
||||
tail.Insert(H, drop_if_replaced=FALSE)
|
||||
var/list/honorifics = list("[MALE]" = list("kun"), "[FEMALE]" = list("chan","tan"), "[NEUTER]" = list("san")) //John Robust -> Robust-kun
|
||||
var/list/names = splittext(H.real_name," ")
|
||||
var/forename = names.len > 1 ? names[2] : names[1]
|
||||
var/newname = "[forename]-[pick(honorifics["[H.gender]"])]"
|
||||
H.fully_replace_character_name(H.real_name,newname)
|
||||
H.update_mutant_bodyparts()
|
||||
if(animetype == "Yes")
|
||||
var/seifuku = pick(typesof(/obj/item/clothing/under/schoolgirl))
|
||||
var/obj/item/clothing/under/schoolgirl/I = new seifuku
|
||||
var/olduniform = H.w_uniform
|
||||
H.temporarilyRemoveItemFromInventory(H.w_uniform, TRUE, FALSE)
|
||||
H.equip_to_slot_or_del(I, SLOT_W_UNIFORM)
|
||||
qdel(olduniform)
|
||||
if(droptype == "Yes")
|
||||
ADD_TRAIT(I, TRAIT_NODROP, ADMIN_TRAIT)
|
||||
else
|
||||
to_chat(H, "You're not kawaii enough for this.")
|
||||
|
||||
if("whiteout")
|
||||
if(!check_rights(R_FUN))
|
||||
return
|
||||
SSblackbox.record_feedback("nested tally", "admin_secrets_fun_used", 1, list("Fix All Lights"))
|
||||
message_admins("[key_name_admin(usr)] fixed all lights")
|
||||
for(var/obj/machinery/light/L in GLOB.machines)
|
||||
L.fix()
|
||||
|
||||
if("floorlava")
|
||||
SSweather.run_weather(/datum/weather/floor_is_lava)
|
||||
|
||||
if("virus")
|
||||
if(!check_rights(R_FUN))
|
||||
return
|
||||
SSblackbox.record_feedback("nested tally", "admin_secrets_fun_used", 1, list("Virus Outbreak"))
|
||||
switch(alert("Do you want this to be a random disease or do you have something in mind?",,"Make Your Own","Random","Choose"))
|
||||
if("Make Your Own")
|
||||
AdminCreateVirus(usr.client)
|
||||
if("Random")
|
||||
E = new /datum/round_event/disease_outbreak()
|
||||
if("Choose")
|
||||
var/virus = input("Choose the virus to spread", "BIOHAZARD") as null|anything in typesof(/datum/disease)
|
||||
E = new /datum/round_event/disease_outbreak{}()
|
||||
var/datum/round_event/disease_outbreak/DO = E
|
||||
DO.virus_type = virus
|
||||
|
||||
if("retardify")
|
||||
if(!check_rights(R_FUN))
|
||||
return
|
||||
SSblackbox.record_feedback("nested tally", "admin_secrets_fun_used", 1, list("Mass Braindamage"))
|
||||
for(var/mob/living/carbon/human/H in GLOB.player_list)
|
||||
to_chat(H, "<span class='boldannounce'>You suddenly feel stupid.</span>")
|
||||
H.adjustOrganLoss(ORGAN_SLOT_BRAIN, 60, 80)
|
||||
message_admins("[key_name_admin(usr)] made everybody retarded")
|
||||
|
||||
if("eagles")//SCRAW
|
||||
if(!check_rights(R_FUN))
|
||||
return
|
||||
SSblackbox.record_feedback("nested tally", "admin_secrets_fun_used", 1, list("Egalitarian Station"))
|
||||
for(var/obj/machinery/door/airlock/W in GLOB.machines)
|
||||
if(is_station_level(W.z) && !istype(get_area(W), /area/bridge) && !istype(get_area(W), /area/crew_quarters) && !istype(get_area(W), /area/security/prison))
|
||||
W.req_access = list()
|
||||
message_admins("[key_name_admin(usr)] activated Egalitarian Station mode")
|
||||
priority_announce("CentCom airlock control override activated. Please take this time to get acquainted with your coworkers.", null, "commandreport")
|
||||
|
||||
if("ak47s")
|
||||
if(!check_rights(R_FUN))
|
||||
return
|
||||
message_admins("[key_name_admin(usr)] activated AK-47s for Everyone!")
|
||||
usr.client.ak47s()
|
||||
sound_to_playing_players('sound/misc/ak47s.ogg')
|
||||
|
||||
if("guns")
|
||||
if(!check_rights(R_FUN))
|
||||
return
|
||||
SSblackbox.record_feedback("nested tally", "admin_secrets_fun_used", 1, list("Summon Guns"))
|
||||
var/survivor_probability = 0
|
||||
switch(alert("Do you want this to create survivors antagonists?",,"No Antags","Some Antags","All Antags!"))
|
||||
if("Some Antags")
|
||||
survivor_probability = 25
|
||||
if("All Antags!")
|
||||
survivor_probability = 100
|
||||
|
||||
rightandwrong(SUMMON_GUNS, usr, survivor_probability)
|
||||
|
||||
if("magic")
|
||||
if(!check_rights(R_FUN))
|
||||
return
|
||||
SSblackbox.record_feedback("nested tally", "admin_secrets_fun_used", 1, list("Summon Magic"))
|
||||
var/survivor_probability = 0
|
||||
switch(alert("Do you want this to create survivors antagonists?",,"No Antags","Some Antags","All Antags!"))
|
||||
if("Some Antags")
|
||||
survivor_probability = 25
|
||||
if("All Antags!")
|
||||
survivor_probability = 100
|
||||
|
||||
rightandwrong(SUMMON_MAGIC, usr, survivor_probability)
|
||||
|
||||
if("events")
|
||||
if(!check_rights(R_FUN))
|
||||
return
|
||||
if(!SSevents.wizardmode)
|
||||
if(alert("Do you want to toggle summon events on?",,"Yes","No") == "Yes")
|
||||
summonevents()
|
||||
SSblackbox.record_feedback("nested tally", "admin_secrets_fun_used", 1, list("Summon Events", "Activate"))
|
||||
|
||||
else
|
||||
switch(alert("What would you like to do?",,"Intensify Summon Events","Turn Off Summon Events","Nothing"))
|
||||
if("Intensify Summon Events")
|
||||
summonevents()
|
||||
SSblackbox.record_feedback("nested tally", "admin_secrets_fun_used", 1, list("Summon Events", "Intensify"))
|
||||
if("Turn Off Summon Events")
|
||||
SSevents.toggleWizardmode()
|
||||
SSevents.resetFrequency()
|
||||
SSblackbox.record_feedback("nested tally", "admin_secrets_fun_used", 1, list("Summon Events", "Disable"))
|
||||
|
||||
if("dorf")
|
||||
if(!check_rights(R_FUN))
|
||||
return
|
||||
SSblackbox.record_feedback("nested tally", "admin_secrets_fun_used", 1, list("Dwarf Beards"))
|
||||
for(var/mob/living/carbon/human/B in GLOB.carbon_list)
|
||||
B.facial_hair_style = "Dward Beard"
|
||||
B.update_hair()
|
||||
message_admins("[key_name_admin(usr)] activated dorf mode")
|
||||
|
||||
if("onlyone")
|
||||
if(!check_rights(R_FUN))
|
||||
return
|
||||
SSblackbox.record_feedback("nested tally", "admin_secrets_fun_used", 1, list("There Can Be Only One"))
|
||||
usr.client.only_one()
|
||||
sound_to_playing_players('sound/misc/highlander.ogg')
|
||||
|
||||
if("delayed_onlyone")
|
||||
if(!check_rights(R_FUN))
|
||||
return
|
||||
SSblackbox.record_feedback("nested tally", "admin_secrets_fun_used", 1, list("There Can Be Only One"))
|
||||
usr.client.only_one_delayed()
|
||||
sound_to_playing_players('sound/misc/highlander_delayed.ogg')
|
||||
|
||||
if("maint_access_brig")
|
||||
if(!check_rights(R_DEBUG))
|
||||
return
|
||||
for(var/obj/machinery/door/airlock/maintenance/M in GLOB.machines)
|
||||
M.check_access()
|
||||
if (ACCESS_MAINT_TUNNELS in M.req_access)
|
||||
M.req_access = list(ACCESS_BRIG)
|
||||
message_admins("[key_name_admin(usr)] made all maint doors brig access-only.")
|
||||
if("maint_access_engiebrig")
|
||||
if(!check_rights(R_DEBUG))
|
||||
return
|
||||
for(var/obj/machinery/door/airlock/maintenance/M in GLOB.machines)
|
||||
M.check_access()
|
||||
if (ACCESS_MAINT_TUNNELS in M.req_access)
|
||||
M.req_access = list()
|
||||
M.req_one_access = list(ACCESS_BRIG,ACCESS_ENGINE)
|
||||
message_admins("[key_name_admin(usr)] made all maint doors engineering and brig access-only.")
|
||||
if("infinite_sec")
|
||||
if(!check_rights(R_DEBUG))
|
||||
return
|
||||
var/datum/job/J = SSjob.GetJob("Security Officer")
|
||||
if(!J)
|
||||
return
|
||||
J.total_positions = -1
|
||||
J.spawn_positions = -1
|
||||
message_admins("[key_name_admin(usr)] has removed the cap on security officers.")
|
||||
|
||||
if("ctfbutton")
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
toggle_all_ctf(usr)
|
||||
if("masspurrbation")
|
||||
if(!check_rights(R_FUN))
|
||||
return
|
||||
mass_purrbation()
|
||||
message_admins("[key_name_admin(usr)] has put everyone on \
|
||||
purrbation!")
|
||||
log_admin("[key_name(usr)] has put everyone on purrbation.")
|
||||
if("massremovepurrbation")
|
||||
if(!check_rights(R_FUN))
|
||||
return
|
||||
mass_remove_purrbation()
|
||||
message_admins("[key_name_admin(usr)] has removed everyone from \
|
||||
purrbation.")
|
||||
log_admin("[key_name(usr)] has removed everyone from purrbation.")
|
||||
|
||||
if("flipmovement")
|
||||
if(!check_rights(R_FUN))
|
||||
return
|
||||
if(alert("Flip all movement controls?","Confirm","Yes","Cancel") == "Cancel")
|
||||
return
|
||||
var/list/movement_keys = SSinput.movement_keys
|
||||
for(var/i in 1 to movement_keys.len)
|
||||
var/key = movement_keys[i]
|
||||
movement_keys[key] = turn(movement_keys[key], 180)
|
||||
message_admins("[key_name_admin(usr)] has flipped all movement directions.")
|
||||
log_admin("[key_name(usr)] has flipped all movement directions.")
|
||||
|
||||
if("randommovement")
|
||||
if(!check_rights(R_FUN))
|
||||
return
|
||||
if(alert("Randomize all movement controls?","Confirm","Yes","Cancel") == "Cancel")
|
||||
return
|
||||
var/list/movement_keys = SSinput.movement_keys
|
||||
for(var/i in 1 to movement_keys.len)
|
||||
var/key = movement_keys[i]
|
||||
movement_keys[key] = turn(movement_keys[key], 45 * rand(1, 8))
|
||||
message_admins("[key_name_admin(usr)] has randomized all movement directions.")
|
||||
log_admin("[key_name(usr)] has randomized all movement directions.")
|
||||
|
||||
if("custommovement")
|
||||
if(!check_rights(R_FUN))
|
||||
return
|
||||
if(alert("Are you sure you want to change every movement key?","Confirm","Yes","Cancel") == "Cancel")
|
||||
return
|
||||
var/list/movement_keys = SSinput.movement_keys
|
||||
var/list/new_movement = list()
|
||||
for(var/i in 1 to movement_keys.len)
|
||||
var/key = movement_keys[i]
|
||||
|
||||
var/msg = "Please input the new movement direction when the user presses [key]. Ex. northeast"
|
||||
var/title = "New direction for [key]"
|
||||
var/new_direction = text2dir(input(usr, msg, title) as text|null)
|
||||
if(!new_direction)
|
||||
new_direction = movement_keys[key]
|
||||
|
||||
new_movement[key] = new_direction
|
||||
SSinput.movement_keys = new_movement
|
||||
message_admins("[key_name_admin(usr)] has configured all movement directions.")
|
||||
log_admin("[key_name(usr)] has configured all movement directions.")
|
||||
|
||||
if("resetmovement")
|
||||
if(!check_rights(R_FUN))
|
||||
return
|
||||
if(alert("Are you sure you want to reset movement keys to default?","Confirm","Yes","Cancel") == "Cancel")
|
||||
return
|
||||
SSinput.setup_default_movement_keys()
|
||||
message_admins("[key_name_admin(usr)] has reset all movement keys.")
|
||||
log_admin("[key_name(usr)] has reset all movement keys.")
|
||||
|
||||
if("customportal")
|
||||
if(!check_rights(R_FUN))
|
||||
return
|
||||
|
||||
var/list/settings = list(
|
||||
"mainsettings" = list(
|
||||
"typepath" = list("desc" = "Path to spawn", "type" = "datum", "path" = "/mob/living", "subtypesonly" = TRUE, "value" = /mob/living/simple_animal/hostile/poison/bees),
|
||||
"humanoutfit" = list("desc" = "Outfit if human", "type" = "datum", "path" = "/datum/outfit", "subtypesonly" = TRUE, "value" = /datum/outfit),
|
||||
"amount" = list("desc" = "Number per portal", "type" = "number", "value" = 1),
|
||||
"portalnum" = list("desc" = "Number of total portals", "type" = "number", "value" = 10),
|
||||
"offerghosts" = list("desc" = "Get ghosts to play mobs", "type" = "boolean", "value" = "No"),
|
||||
"minplayers" = list("desc" = "Minimum number of ghosts", "type" = "number", "value" = 1),
|
||||
"playersonly" = list("desc" = "Only spawn ghost-controlled mobs", "type" = "boolean", "value" = "No"),
|
||||
"ghostpoll" = list("desc" = "Ghost poll question", "type" = "string", "value" = "Do you want to play as %TYPE% portal invader?"),
|
||||
"delay" = list("desc" = "Time between portals, in deciseconds", "type" = "number", "value" = 50),
|
||||
"color" = list("desc" = "Portal color", "type" = "color", "value" = "#00FF00"),
|
||||
"playlightning" = list("desc" = "Play lightning sounds on announcement", "type" = "boolean", "value" = "Yes"),
|
||||
"announce_players" = list("desc" = "Make an announcement", "type" = "boolean", "value" = "Yes"),
|
||||
"announcement" = list("desc" = "Announcement", "type" = "string", "value" = "Massive bluespace anomaly detected en route to %STATION%. Brace for impact."),
|
||||
)
|
||||
)
|
||||
|
||||
message_admins("[key_name(usr)] is creating a custom portal storm...")
|
||||
var/list/prefreturn = presentpreflikepicker(usr,"Customize Portal Storm", "Customize Portal Storm", Button1="Ok", width = 600, StealFocus = 1,Timeout = 0, settings=settings)
|
||||
|
||||
if (prefreturn["button"] == 1)
|
||||
var/list/prefs = settings["mainsettings"]
|
||||
|
||||
if (prefs["amount"]["value"] < 1 || prefs["portalnum"]["value"] < 1)
|
||||
to_chat(usr, "Number of portals and mobs to spawn must be at least 1")
|
||||
return
|
||||
|
||||
var/mob/pathToSpawn = prefs["typepath"]["value"]
|
||||
if (!ispath(pathToSpawn))
|
||||
pathToSpawn = text2path(pathToSpawn)
|
||||
|
||||
if (!ispath(pathToSpawn))
|
||||
to_chat(usr, "Invalid path [pathToSpawn]")
|
||||
return
|
||||
|
||||
var/list/candidates = list()
|
||||
|
||||
if (prefs["offerghosts"]["value"] == "Yes")
|
||||
candidates = pollGhostCandidates(replacetext(prefs["ghostpoll"]["value"], "%TYPE%", initial(pathToSpawn.name)), ROLE_TRAITOR)
|
||||
|
||||
if (prefs["playersonly"]["value"] == "Yes" && length(candidates) < prefs["minplayers"]["value"])
|
||||
message_admins("Not enough players signed up to create a portal storm, the minimum was [prefs["minplayers"]["value"]] and the number of signups [length(candidates)]")
|
||||
return
|
||||
|
||||
if (prefs["announce_players"]["value"] == "Yes")
|
||||
portalAnnounce(prefs["announcement"]["value"], (prefs["playlightning"]["value"] == "Yes" ? TRUE : FALSE))
|
||||
|
||||
var/mutable_appearance/storm = mutable_appearance('icons/obj/tesla_engine/energy_ball.dmi', "energy_ball_fast", FLY_LAYER)
|
||||
storm.color = prefs["color"]["value"]
|
||||
|
||||
message_admins("[key_name_admin(usr)] has created a customized portal storm that will spawn [prefs["portalnum"]["value"]] portals, each of them spawning [prefs["amount"]["value"]] of [pathToSpawn]")
|
||||
log_admin("[key_name(usr)] has created a customized portal storm that will spawn [prefs["portalnum"]["value"]] portals, each of them spawning [prefs["amount"]["value"]] of [pathToSpawn]")
|
||||
|
||||
var/outfit = prefs["humanoutfit"]["value"]
|
||||
if (!ispath(outfit))
|
||||
outfit = text2path(outfit)
|
||||
|
||||
for (var/i in 1 to prefs["portalnum"]["value"])
|
||||
if (length(candidates)) // if we're spawning players, gotta be a little tricky and also not spawn players on top of NPCs
|
||||
var/ghostcandidates = list()
|
||||
for (var/j in 1 to min(prefs["amount"]["value"], length(candidates)))
|
||||
ghostcandidates += pick_n_take(candidates)
|
||||
addtimer(CALLBACK(GLOBAL_PROC, .proc/doPortalSpawn, get_random_station_turf(), pathToSpawn, length(ghostcandidates), storm, ghostcandidates, outfit), i*prefs["delay"]["value"])
|
||||
else if (prefs["playersonly"]["value"] != "Yes")
|
||||
addtimer(CALLBACK(GLOBAL_PROC, .proc/doPortalSpawn, get_random_station_turf(), pathToSpawn, prefs["amount"]["value"], storm, null, outfit), i*prefs["delay"]["value"])
|
||||
|
||||
if(E)
|
||||
E.processing = FALSE
|
||||
if(E.announceWhen>0)
|
||||
if(alert(usr, "Would you like to alert the crew?", "Alert", "Yes", "No") == "No")
|
||||
E.announceWhen = -1
|
||||
E.processing = TRUE
|
||||
if (usr)
|
||||
log_admin("[key_name(usr)] used secret [item]")
|
||||
if (ok)
|
||||
to_chat(world, text("<B>A secret has been activated by []!</B>", usr.key))
|
||||
|
||||
/proc/portalAnnounce(announcement, playlightning)
|
||||
set waitfor = 0
|
||||
if (playlightning)
|
||||
sound_to_playing_players('sound/magic/lightning_chargeup.ogg')
|
||||
sleep(80)
|
||||
priority_announce(replacetext(announcement, "%STATION%", station_name()))
|
||||
if (playlightning)
|
||||
sleep(20)
|
||||
sound_to_playing_players('sound/magic/lightningbolt.ogg')
|
||||
|
||||
/proc/doPortalSpawn(turf/loc, mobtype, numtospawn, portal_appearance, players, humanoutfit)
|
||||
for (var/i in 1 to numtospawn)
|
||||
var/mob/spawnedMob = new mobtype(loc)
|
||||
if (length(players))
|
||||
var/mob/chosen = players[1]
|
||||
if (chosen.client)
|
||||
chosen.client.prefs.copy_to(spawnedMob)
|
||||
chosen.transfer_ckey(spawnedMob)
|
||||
players -= chosen
|
||||
if (ishuman(spawnedMob) && ispath(humanoutfit, /datum/outfit))
|
||||
var/mob/living/carbon/human/H = spawnedMob
|
||||
H.equipOutfit(humanoutfit)
|
||||
var/turf/T = get_step(loc, SOUTHWEST)
|
||||
flick_overlay_static(portal_appearance, T, 15)
|
||||
playsound(T, 'sound/magic/lightningbolt.ogg', rand(80, 100), 1)
|
||||
@@ -0,0 +1,603 @@
|
||||
/proc/create_message(type, target_key, admin_ckey, text, timestamp, server, secret, logged = 1, browse, expiry, note_severity)
|
||||
if(!SSdbcore.Connect())
|
||||
to_chat(usr, "<span class='danger'>Failed to establish database connection.</span>")
|
||||
return
|
||||
if(!type)
|
||||
return
|
||||
var/target_ckey = ckey(target_key)
|
||||
if(!target_key && (type == "note" || type == "message" || type == "watchlist entry"))
|
||||
var/new_key = input(usr,"Who would you like to create a [type] for?","Enter a key or ckey",null) as null|text
|
||||
if(!new_key)
|
||||
return
|
||||
var/new_ckey = sanitizeSQL(ckey(new_key))
|
||||
var/datum/DBQuery/query_find_ckey = SSdbcore.NewQuery("SELECT ckey FROM [format_table_name("player")] WHERE ckey = '[new_ckey]'")
|
||||
if(!query_find_ckey.warn_execute())
|
||||
qdel(query_find_ckey)
|
||||
return
|
||||
if(!query_find_ckey.NextRow())
|
||||
if(alert(usr, "[new_key]/([new_ckey]) has not been seen before, are you sure you want to create a [type] for them?", "Unknown ckey", "Yes", "No", "Cancel") != "Yes")
|
||||
qdel(query_find_ckey)
|
||||
return
|
||||
qdel(query_find_ckey)
|
||||
target_ckey = new_ckey
|
||||
target_key = new_key
|
||||
if(QDELETED(usr))
|
||||
return
|
||||
if(target_ckey)
|
||||
target_ckey = sanitizeSQL(target_ckey)
|
||||
if(!target_key)
|
||||
target_key = target_ckey
|
||||
if(!admin_ckey)
|
||||
admin_ckey = usr.ckey
|
||||
if(!admin_ckey)
|
||||
return
|
||||
admin_ckey = sanitizeSQL(admin_ckey)
|
||||
if(!target_ckey)
|
||||
target_ckey = admin_ckey
|
||||
if(!text)
|
||||
text = input(usr,"Write your [type]","Create [type]") as null|message
|
||||
if(!text)
|
||||
return
|
||||
text = sanitizeSQL(text)
|
||||
if(!timestamp)
|
||||
timestamp = SQLtime()
|
||||
if(!server)
|
||||
var/ssqlname = CONFIG_GET(string/serversqlname)
|
||||
if (ssqlname)
|
||||
server = ssqlname
|
||||
server = sanitizeSQL(server)
|
||||
if(isnull(secret))
|
||||
switch(alert("Hide note from being viewed by players?", "Secret note?","Yes","No","Cancel"))
|
||||
if("Yes")
|
||||
secret = 1
|
||||
if("No")
|
||||
secret = 0
|
||||
else
|
||||
return
|
||||
if(isnull(expiry))
|
||||
if(alert(usr, "Set an expiry time? Expired messages are hidden like deleted ones.", "Expiry time?", "Yes", "No", "Cancel") == "Yes")
|
||||
var/expire_time = input("Set expiry time for [type] as format YYYY-MM-DD HH:MM:SS. All times in server time. HH:MM:SS is optional and 24-hour. Must be later than current time for obvious reasons.", "Set expiry time", SQLtime()) as null|text
|
||||
if(!expire_time)
|
||||
return
|
||||
expire_time = sanitizeSQL(expire_time)
|
||||
var/datum/DBQuery/query_validate_expire_time = SSdbcore.NewQuery("SELECT IF(STR_TO_DATE('[expire_time]','%Y-%c-%d %T') > NOW(), STR_TO_DATE('[expire_time]','%Y-%c-%d %T'), 0)")
|
||||
if(!query_validate_expire_time.warn_execute())
|
||||
qdel(query_validate_expire_time)
|
||||
return
|
||||
if(query_validate_expire_time.NextRow())
|
||||
var/checktime = text2num(query_validate_expire_time.item[1])
|
||||
if(!checktime)
|
||||
to_chat(usr, "Datetime entered is improperly formatted or not later than current server time.")
|
||||
qdel(query_validate_expire_time)
|
||||
return
|
||||
expiry = query_validate_expire_time.item[1]
|
||||
qdel(query_validate_expire_time)
|
||||
if(type == "note" && isnull(note_severity))
|
||||
note_severity = input("Set the severity of the note.", "Severity", null, null) as null|anything in list("High", "Medium", "Minor", "None")
|
||||
if(!note_severity)
|
||||
return
|
||||
note_severity = sanitizeSQL(note_severity)
|
||||
var/datum/DBQuery/query_create_message = SSdbcore.NewQuery("INSERT INTO [format_table_name("messages")] (type, targetckey, adminckey, text, timestamp, server, server_ip, server_port, round_id, secret, expire_timestamp, severity) VALUES ('[type]', '[target_ckey]', '[admin_ckey]', '[text]', '[timestamp]', '[server]', INET_ATON(IF('[world.internet_address]' LIKE '', '0', '[world.internet_address]')), '[world.port]', '[GLOB.round_id]','[secret]', [expiry ? "'[expiry]'" : "NULL"], [note_severity ? "'[note_severity]'" : "NULL"])")
|
||||
var/pm = "[key_name(usr)] has created a [type][(type == "note" || type == "message" || type == "watchlist entry") ? " for [target_key]" : ""]: [text]"
|
||||
var/header = "[key_name_admin(usr)] has created a [type][(type == "note" || type == "message" || type == "watchlist entry") ? " for [target_key]" : ""]"
|
||||
if(!query_create_message.warn_execute())
|
||||
qdel(query_create_message)
|
||||
return
|
||||
qdel(query_create_message)
|
||||
if(logged)
|
||||
log_admin_private(pm)
|
||||
message_admins("[header]:<br>[text]")
|
||||
admin_ticket_log(target_ckey, "<font color='blue'>[header]</font>")
|
||||
admin_ticket_log(target_ckey, text)
|
||||
if(browse)
|
||||
browse_messages("[type]")
|
||||
else
|
||||
browse_messages(target_ckey = target_ckey, agegate = TRUE)
|
||||
|
||||
/proc/delete_message(message_id, logged = 1, browse)
|
||||
if(!SSdbcore.Connect())
|
||||
to_chat(usr, "<span class='danger'>Failed to establish database connection.</span>")
|
||||
return
|
||||
message_id = text2num(message_id)
|
||||
if(!message_id)
|
||||
return
|
||||
var/type
|
||||
var/target_key
|
||||
var/text
|
||||
var/user_key_name = key_name(usr)
|
||||
var/user_name_admin = key_name_admin(usr)
|
||||
var/datum/DBQuery/query_find_del_message = SSdbcore.NewQuery("SELECT type, IFNULL((SELECT byond_key FROM [format_table_name("player")] WHERE ckey = targetckey), targetckey), text FROM [format_table_name("messages")] WHERE id = [message_id] AND deleted = 0")
|
||||
if(!query_find_del_message.warn_execute())
|
||||
qdel(query_find_del_message)
|
||||
return
|
||||
if(query_find_del_message.NextRow())
|
||||
type = query_find_del_message.item[1]
|
||||
target_key = query_find_del_message.item[2]
|
||||
text = query_find_del_message.item[3]
|
||||
qdel(query_find_del_message)
|
||||
var/datum/DBQuery/query_del_message = SSdbcore.NewQuery("UPDATE [format_table_name("messages")] SET deleted = 1 WHERE id = [message_id]")
|
||||
if(!query_del_message.warn_execute())
|
||||
qdel(query_del_message)
|
||||
return
|
||||
qdel(query_del_message)
|
||||
if(logged)
|
||||
var/m1 = "[user_key_name] has deleted a [type][(type == "note" || type == "message" || type == "watchlist entry") ? " for" : " made by"] [target_key]: [text]"
|
||||
var/m2 = "[user_name_admin] has deleted a [type][(type == "note" || type == "message" || type == "watchlist entry") ? " for" : " made by"] [target_key]:<br>[text]"
|
||||
log_admin_private(m1)
|
||||
message_admins(m2)
|
||||
if(browse)
|
||||
browse_messages("[type]")
|
||||
else
|
||||
browse_messages(target_ckey = ckey(target_key), agegate = TRUE)
|
||||
|
||||
/proc/edit_message(message_id, browse)
|
||||
if(!SSdbcore.Connect())
|
||||
to_chat(usr, "<span class='danger'>Failed to establish database connection.</span>")
|
||||
return
|
||||
message_id = text2num(message_id)
|
||||
if(!message_id)
|
||||
return
|
||||
var/editor_ckey = sanitizeSQL(usr.ckey)
|
||||
var/editor_key = sanitizeSQL(usr.key)
|
||||
var/kn = key_name(usr)
|
||||
var/kna = key_name_admin(usr)
|
||||
var/datum/DBQuery/query_find_edit_message = SSdbcore.NewQuery("SELECT type, IFNULL((SELECT byond_key FROM [format_table_name("player")] WHERE ckey = targetckey), targetckey), IFNULL((SELECT byond_key FROM [format_table_name("player")] WHERE ckey = adminckey), targetckey), text FROM [format_table_name("messages")] WHERE id = [message_id] AND deleted = 0")
|
||||
if(!query_find_edit_message.warn_execute())
|
||||
qdel(query_find_edit_message)
|
||||
return
|
||||
if(query_find_edit_message.NextRow())
|
||||
var/type = query_find_edit_message.item[1]
|
||||
var/target_key = query_find_edit_message.item[2]
|
||||
var/admin_key = query_find_edit_message.item[3]
|
||||
var/old_text = query_find_edit_message.item[4]
|
||||
var/new_text = input("Input new [type]", "New [type]", "[old_text]") as null|message
|
||||
if(!new_text)
|
||||
qdel(query_find_edit_message)
|
||||
return
|
||||
new_text = sanitizeSQL(new_text)
|
||||
var/edit_text = sanitizeSQL("Edited by [editor_key] on [SQLtime()] from<br>[old_text]<br>to<br>[new_text]<hr>")
|
||||
var/datum/DBQuery/query_edit_message = SSdbcore.NewQuery("UPDATE [format_table_name("messages")] SET text = '[new_text]', lasteditor = '[editor_ckey]', edits = CONCAT(IFNULL(edits,''),'[edit_text]') WHERE id = [message_id] AND deleted = 0")
|
||||
if(!query_edit_message.warn_execute())
|
||||
qdel(query_edit_message)
|
||||
return
|
||||
qdel(query_edit_message)
|
||||
log_admin_private("[kn] has edited a [type] [(type == "note" || type == "message" || type == "watchlist entry") ? " for [target_key]" : ""] made by [admin_key] from [old_text] to [new_text]")
|
||||
message_admins("[kna] has edited a [type] [(type == "note" || type == "message" || type == "watchlist entry") ? " for [target_key]" : ""] made by [admin_key] from<br>[old_text]<br>to<br>[new_text]")
|
||||
if(browse)
|
||||
browse_messages("[type]")
|
||||
else
|
||||
browse_messages(target_ckey = ckey(target_key), agegate = TRUE)
|
||||
qdel(query_find_edit_message)
|
||||
|
||||
/proc/edit_message_expiry(message_id, browse)
|
||||
if(!SSdbcore.Connect())
|
||||
to_chat(usr, "<span class='danger'>Failed to establish database connection.</span>")
|
||||
return
|
||||
message_id = text2num(message_id)
|
||||
if(!message_id)
|
||||
return
|
||||
var/editor_ckey = sanitizeSQL(usr.ckey)
|
||||
var/editor_key = sanitizeSQL(usr.key)
|
||||
var/kn = key_name(usr)
|
||||
var/kna = key_name_admin(usr)
|
||||
var/datum/DBQuery/query_find_edit_expiry_message = SSdbcore.NewQuery("SELECT type, IFNULL((SELECT byond_key FROM [format_table_name("player")] WHERE ckey = targetckey), targetckey), IFNULL((SELECT byond_key FROM [format_table_name("player")] WHERE ckey = adminckey), adminckey), expire_timestamp FROM [format_table_name("messages")] WHERE id = [message_id] AND deleted = 0")
|
||||
if(!query_find_edit_expiry_message.warn_execute())
|
||||
qdel(query_find_edit_expiry_message)
|
||||
return
|
||||
if(query_find_edit_expiry_message.NextRow())
|
||||
var/type = query_find_edit_expiry_message.item[1]
|
||||
var/target_key = query_find_edit_expiry_message.item[2]
|
||||
var/admin_key = query_find_edit_expiry_message.item[3]
|
||||
var/old_expiry = query_find_edit_expiry_message.item[4]
|
||||
var/new_expiry
|
||||
var/expire_time = input("Set expiry time for [type] as format YYYY-MM-DD HH:MM:SS. All times in server time. HH:MM:SS is optional and 24-hour. Must be later than current time for obvious reasons. Enter -1 to remove expiry time.", "Set expiry time", old_expiry) as null|text
|
||||
if(!expire_time)
|
||||
qdel(query_find_edit_expiry_message)
|
||||
return
|
||||
if(expire_time == "-1")
|
||||
new_expiry = "non-expiring"
|
||||
else
|
||||
expire_time = sanitizeSQL(expire_time)
|
||||
var/datum/DBQuery/query_validate_expire_time_edit = SSdbcore.NewQuery("SELECT IF(STR_TO_DATE('[expire_time]','%Y-%c-%d %T') > NOW(), STR_TO_DATE('[expire_time]','%Y-%c-%d %T'), 0)")
|
||||
if(!query_validate_expire_time_edit.warn_execute())
|
||||
qdel(query_validate_expire_time_edit)
|
||||
qdel(query_find_edit_expiry_message)
|
||||
return
|
||||
if(query_validate_expire_time_edit.NextRow())
|
||||
var/checktime = text2num(query_validate_expire_time_edit.item[1])
|
||||
if(!checktime)
|
||||
to_chat(usr, "Datetime entered is improperly formatted or not later than current server time.")
|
||||
qdel(query_validate_expire_time_edit)
|
||||
qdel(query_find_edit_expiry_message)
|
||||
return
|
||||
new_expiry = query_validate_expire_time_edit.item[1]
|
||||
qdel(query_validate_expire_time_edit)
|
||||
var/edit_text = sanitizeSQL("Expiration time edited by [editor_key] on [SQLtime()] from [old_expiry] to [new_expiry]<hr>")
|
||||
var/datum/DBQuery/query_edit_message_expiry = SSdbcore.NewQuery("UPDATE [format_table_name("messages")] SET expire_timestamp = [expire_time == "-1" ? "NULL" : "'[new_expiry]'"], lasteditor = '[editor_ckey]', edits = CONCAT(IFNULL(edits,''),'[edit_text]') WHERE id = [message_id] AND deleted = 0")
|
||||
if(!query_edit_message_expiry.warn_execute())
|
||||
qdel(query_edit_message_expiry)
|
||||
qdel(query_find_edit_expiry_message)
|
||||
return
|
||||
qdel(query_edit_message_expiry)
|
||||
log_admin_private("[kn] has edited the expiration time of a [type] [(type == "note" || type == "message" || type == "watchlist entry") ? " for [target_key]" : ""] made by [admin_key] from [old_expiry] to [new_expiry]")
|
||||
message_admins("[kna] has edited the expiration time of a [type] [(type == "note" || type == "message" || type == "watchlist entry") ? " for [target_key]" : ""] made by [admin_key] from [old_expiry] to [new_expiry]")
|
||||
if(browse)
|
||||
browse_messages("[type]")
|
||||
else
|
||||
browse_messages(target_ckey = ckey(target_key), agegate = TRUE)
|
||||
qdel(query_find_edit_expiry_message)
|
||||
|
||||
/proc/edit_message_severity(message_id)
|
||||
if(!SSdbcore.Connect())
|
||||
to_chat(usr, "<span class='danger'>Failed to establish database connection.</span>")
|
||||
return
|
||||
message_id = text2num(message_id)
|
||||
if(!message_id)
|
||||
return
|
||||
var/kn = key_name(usr)
|
||||
var/kna = key_name_admin(usr)
|
||||
var/datum/DBQuery/query_find_edit_note_severity = SSdbcore.NewQuery("SELECT type, IFNULL((SELECT byond_key FROM [format_table_name("player")] WHERE ckey = targetckey), targetckey), IFNULL((SELECT byond_key FROM [format_table_name("player")] WHERE ckey = adminckey), adminckey), severity FROM [format_table_name("messages")] WHERE id = [message_id] AND deleted = 0")
|
||||
if(!query_find_edit_note_severity.warn_execute())
|
||||
qdel(query_find_edit_note_severity)
|
||||
return
|
||||
if(query_find_edit_note_severity.NextRow())
|
||||
var/type = query_find_edit_note_severity.item[1]
|
||||
var/target_key = query_find_edit_note_severity.item[2]
|
||||
var/admin_key = query_find_edit_note_severity.item[3]
|
||||
var/old_severity = query_find_edit_note_severity.item[4]
|
||||
if(!old_severity)
|
||||
old_severity = "NA"
|
||||
var/editor_key = sanitizeSQL(usr.key)
|
||||
var/editor_ckey = sanitizeSQL(usr.ckey)
|
||||
var/new_severity = input("Set the severity of the note.", "Severity", null, null) as null|anything in list("high", "medium", "minor", "none") //lowercase for edit log consistency
|
||||
if(!new_severity)
|
||||
qdel(query_find_edit_note_severity)
|
||||
return
|
||||
new_severity = sanitizeSQL(new_severity)
|
||||
var/edit_text = sanitizeSQL("Note severity edited by [editor_key] on [SQLtime()] from [old_severity] to [new_severity]<hr>")
|
||||
var/datum/DBQuery/query_edit_note_severity = SSdbcore.NewQuery("UPDATE [format_table_name("messages")] SET severity = '[new_severity]', lasteditor = '[editor_ckey]', edits = CONCAT(IFNULL(edits,''),'[edit_text]') WHERE id = [message_id] AND deleted = 0")
|
||||
if(!query_edit_note_severity.warn_execute(async = TRUE))
|
||||
qdel(query_edit_note_severity)
|
||||
qdel(qdel(query_find_edit_note_severity))
|
||||
return
|
||||
qdel(query_edit_note_severity)
|
||||
log_admin_private("[kn] has edited the severity of a [type] for [target_key] made by [admin_key] from [old_severity] to [new_severity]")
|
||||
message_admins("[kna] has edited the severity time of a [type] for [target_key] made by [admin_key] from [old_severity] to [new_severity]")
|
||||
browse_messages(target_ckey = ckey(target_key), agegate = TRUE)
|
||||
qdel(query_find_edit_note_severity)
|
||||
|
||||
/proc/toggle_message_secrecy(message_id)
|
||||
if(!SSdbcore.Connect())
|
||||
to_chat(usr, "<span class='danger'>Failed to establish database connection.</span>")
|
||||
return
|
||||
message_id = text2num(message_id)
|
||||
if(!message_id)
|
||||
return
|
||||
var/editor_ckey = sanitizeSQL(usr.ckey)
|
||||
var/editor_key = sanitizeSQL(usr.key)
|
||||
var/kn = key_name(usr)
|
||||
var/kna = key_name_admin(usr)
|
||||
var/datum/DBQuery/query_find_message_secret = SSdbcore.NewQuery("SELECT type, IFNULL((SELECT byond_key FROM [format_table_name("player")] WHERE ckey = targetckey), targetckey), IFNULL((SELECT byond_key FROM [format_table_name("player")] WHERE ckey = adminckey), targetckey), secret FROM [format_table_name("messages")] WHERE id = [message_id] AND deleted = 0")
|
||||
if(!query_find_message_secret.warn_execute())
|
||||
qdel(query_find_message_secret)
|
||||
return
|
||||
if(query_find_message_secret.NextRow())
|
||||
var/type = query_find_message_secret.item[1]
|
||||
var/target_key = query_find_message_secret.item[2]
|
||||
var/admin_key = query_find_message_secret.item[3]
|
||||
var/secret = text2num(query_find_message_secret.item[4])
|
||||
var/edit_text = "Made [secret ? "not secret" : "secret"] by [editor_key] on [SQLtime()]<hr>"
|
||||
var/datum/DBQuery/query_message_secret = SSdbcore.NewQuery("UPDATE [format_table_name("messages")] SET secret = NOT secret, lasteditor = '[editor_ckey]', edits = CONCAT(IFNULL(edits,''),'[edit_text]') WHERE id = [message_id]")
|
||||
if(!query_message_secret.warn_execute())
|
||||
qdel(query_find_message_secret)
|
||||
qdel(query_message_secret)
|
||||
return
|
||||
qdel(query_message_secret)
|
||||
log_admin_private("[kn] has toggled [target_key]'s [type] made by [admin_key] to [secret ? "not secret" : "secret"]")
|
||||
message_admins("[kna] has toggled [target_key]'s [type] made by [admin_key] to [secret ? "not secret" : "secret"]")
|
||||
browse_messages(target_ckey = ckey(target_key), agegate = TRUE)
|
||||
qdel(query_find_message_secret)
|
||||
|
||||
/proc/browse_messages(type, target_ckey, index, linkless = FALSE, filter, agegate = FALSE)
|
||||
if(!SSdbcore.Connect())
|
||||
to_chat(usr, "<span class='danger'>Failed to establish database connection.</span>")
|
||||
return
|
||||
var/list/output = list()
|
||||
var/ruler = "<hr style='background:#000000; border:0; height:3px'>"
|
||||
var/list/navbar = list("<a href='?_src_=holder;[HrefToken()];nonalpha=1'>All</a><a href='?_src_=holder;[HrefToken()];nonalpha=2'>#</a>")
|
||||
for(var/letter in GLOB.alphabet)
|
||||
navbar += "<a href='?_src_=holder;[HrefToken()];showmessages=[letter]'>[letter]</a>"
|
||||
navbar += "<a href='?_src_=holder;[HrefToken()];showmemo=1'>Memos</a><a href='?_src_=holder;[HrefToken()];showwatch=1'>Watchlist</a>"
|
||||
navbar += "<br><form method='GET' name='search' action='?'>\
|
||||
<input type='hidden' name='_src_' value='holder'>\
|
||||
[HrefTokenFormField()]\
|
||||
<input type='text' name='searchmessages' value='[index]'>\
|
||||
<input type='submit' value='Search'></form>"
|
||||
if(!linkless)
|
||||
output = navbar
|
||||
if(type == "memo" || type == "watchlist entry")
|
||||
if(type == "memo")
|
||||
output += "<h2><center>Admin memos</h2>"
|
||||
output += "<a href='?_src_=holder;[HrefToken()];addmemo=1'>Add memo</a></center>"
|
||||
else if(type == "watchlist entry")
|
||||
output += "<h2><center>Watchlist entries</h2>"
|
||||
output += "<a href='?_src_=holder;[HrefToken()];addwatchempty=1'>Add watchlist entry</a>"
|
||||
if(filter)
|
||||
output += "<a href='?_src_=holder;[HrefToken()];showwatch=1'>Unfilter clients</a></center>"
|
||||
else
|
||||
output += "<a href='?_src_=holder;[HrefToken()];showwatchfilter=1'>Filter offline clients</a></center>"
|
||||
output += ruler
|
||||
var/datum/DBQuery/query_get_type_messages = SSdbcore.NewQuery("SELECT id, IFNULL((SELECT byond_key FROM [format_table_name("player")] WHERE ckey = targetckey), targetckey), targetckey, IFNULL((SELECT byond_key FROM [format_table_name("player")] WHERE ckey = adminckey), adminckey), text, timestamp, server, IFNULL((SELECT byond_key FROM [format_table_name("player")] WHERE ckey = lasteditor), lasteditor), expire_timestamp FROM [format_table_name("messages")] WHERE type = '[type]' AND deleted = 0 AND (expire_timestamp > NOW() OR expire_timestamp IS NULL)")
|
||||
if(!query_get_type_messages.warn_execute())
|
||||
qdel(query_get_type_messages)
|
||||
return
|
||||
while(query_get_type_messages.NextRow())
|
||||
if(QDELETED(usr))
|
||||
return
|
||||
var/id = query_get_type_messages.item[1]
|
||||
var/t_key = query_get_type_messages.item[2]
|
||||
var/t_ckey = query_get_type_messages.item[3]
|
||||
if(type == "watchlist entry" && filter && !(t_ckey in GLOB.directory))
|
||||
continue
|
||||
var/admin_key = query_get_type_messages.item[4]
|
||||
var/text = query_get_type_messages.item[5]
|
||||
var/timestamp = query_get_type_messages.item[6]
|
||||
var/server = query_get_type_messages.item[7]
|
||||
var/editor_key = query_get_type_messages.item[8]
|
||||
var/expire_timestamp = query_get_type_messages.item[9]
|
||||
output += "<b>"
|
||||
if(type == "watchlist entry")
|
||||
output += "[t_key] | "
|
||||
output += "[timestamp] | [server] | [admin_key]"
|
||||
if(expire_timestamp)
|
||||
output += " | Expires [expire_timestamp]"
|
||||
output += "</b>"
|
||||
output += " <a href='?_src_=holder;[HrefToken()];editmessageexpiryempty=[id]'>Change Expiry Time</a>"
|
||||
output += " <a href='?_src_=holder;[HrefToken()];deletemessageempty=[id]'>Delete</a>"
|
||||
output += " <a href='?_src_=holder;[HrefToken()];editmessageempty=[id]'>Edit</a>"
|
||||
if(editor_key)
|
||||
output += " <font size='2'>Last edit by [editor_key] <a href='?_src_=holder;[HrefToken()];messageedits=[id]'>(Click here to see edit log)</a></font>"
|
||||
output += "<br>[text]<hr style='background:#000000; border:0; height:1px'>"
|
||||
qdel(query_get_type_messages)
|
||||
if(target_ckey)
|
||||
target_ckey = sanitizeSQL(target_ckey)
|
||||
var/target_key
|
||||
var/datum/DBQuery/query_get_messages = SSdbcore.NewQuery("SELECT type, secret, id, IFNULL((SELECT byond_key FROM [format_table_name("player")] WHERE ckey = adminckey), adminckey), text, timestamp, server, IFNULL((SELECT byond_key FROM [format_table_name("player")] WHERE ckey = lasteditor), lasteditor), DATEDIFF(NOW(), timestamp), IFNULL((SELECT byond_key FROM [format_table_name("player")] WHERE ckey = targetckey), targetckey), expire_timestamp, severity FROM [format_table_name("messages")] WHERE type <> 'memo' AND targetckey = '[target_ckey]' AND deleted = 0 AND (expire_timestamp > NOW() OR expire_timestamp IS NULL) ORDER BY timestamp DESC")
|
||||
if(!query_get_messages.warn_execute())
|
||||
qdel(query_get_messages)
|
||||
return
|
||||
var/list/messagedata = list()
|
||||
var/list/watchdata = list()
|
||||
var/list/notedata = list()
|
||||
var/skipped = 0
|
||||
while(query_get_messages.NextRow())
|
||||
if(QDELETED(usr))
|
||||
return
|
||||
type = query_get_messages.item[1]
|
||||
if(type == "memo")
|
||||
continue
|
||||
var/secret = text2num(query_get_messages.item[2])
|
||||
if(linkless && secret)
|
||||
continue
|
||||
var/id = query_get_messages.item[3]
|
||||
var/admin_key = query_get_messages.item[4]
|
||||
var/text = query_get_messages.item[5]
|
||||
var/timestamp = query_get_messages.item[6]
|
||||
var/server = query_get_messages.item[7]
|
||||
var/editor_key = query_get_messages.item[8]
|
||||
var/age = text2num(query_get_messages.item[9])
|
||||
target_key = query_get_messages.item[10]
|
||||
var/expire_timestamp = query_get_messages.item[11]
|
||||
var/severity = query_get_messages.item[12]
|
||||
var/alphatext = ""
|
||||
var/nsd = CONFIG_GET(number/note_stale_days)
|
||||
var/nfd = CONFIG_GET(number/note_fresh_days)
|
||||
if (agegate && type == "note" && isnum(nsd) && isnum(nfd) && nsd > nfd)
|
||||
var/alpha = CLAMP(100 - (age - nfd) * (85 / (nsd - nfd)), 15, 100)
|
||||
if (alpha < 100)
|
||||
if (alpha <= 15)
|
||||
if (skipped)
|
||||
skipped++
|
||||
continue
|
||||
alpha = 10
|
||||
skipped = TRUE
|
||||
alphatext = "filter: alpha(opacity=[alpha]); opacity: [alpha/100];"
|
||||
var/list/data = list("<div style='margin:0px;[alphatext]'><p class='severity'>")
|
||||
if(severity)
|
||||
data += "<img src='[severity]_button.png' height='24' width='24'></img> "
|
||||
data += "<b>[timestamp] | [server] | [admin_key][secret ? " | <i>- Secret</i>" : ""]"
|
||||
if(expire_timestamp)
|
||||
data += " | Expires [expire_timestamp]"
|
||||
data += "</b></p><center>"
|
||||
if(!linkless)
|
||||
if(type == "note")
|
||||
if(severity)
|
||||
data += "<a href='?_src_=holder;[HrefToken()];editmessageseverity=[id]'>[severity=="none" ? "No" : "[capitalize(severity)]"] Severity</a>"
|
||||
else
|
||||
data += "<a href='?_src_=holder;[HrefToken()];editmessageseverity=[id]'>N/A Severity</a>"
|
||||
data += " <a href='?_src_=holder;[HrefToken()];editmessageexpiry=[id]'>Change Expiry Time</a>"
|
||||
data += " <a href='?_src_=holder;[HrefToken()];deletemessage=[id]'>Delete</a>"
|
||||
if(type == "note")
|
||||
data += " <a href='?_src_=holder;[HrefToken()];secretmessage=[id]'>[secret ? "<b>Secret</b>" : "Not secret"]</a>"
|
||||
if(type == "message sent")
|
||||
data += " <font size='2'>Message has been sent</font>"
|
||||
if(editor_key)
|
||||
data += "|"
|
||||
else
|
||||
data += " <a href='?_src_=holder;[HrefToken()];editmessage=[id]'>Edit</a>"
|
||||
if(editor_key)
|
||||
data += " <font size='2'>Last edit by [editor_key] <a href='?_src_=holder;[HrefToken()];messageedits=[id]'>(Click here to see edit log)</a></font>"
|
||||
data += "</div></center>"
|
||||
data += "<p style='[alphatext]'>[text]</p><hr style='background:#000000; border:0; height:1px; [alphatext]'>"
|
||||
switch(type)
|
||||
if("message")
|
||||
messagedata += data
|
||||
if("message sent")
|
||||
messagedata += data
|
||||
if("watchlist entry")
|
||||
watchdata += data
|
||||
if("note")
|
||||
notedata += data
|
||||
qdel(query_get_messages)
|
||||
if(!target_key)
|
||||
var/datum/DBQuery/query_get_message_key = SSdbcore.NewQuery("SELECT byond_key FROM [format_table_name("player")] WHERE ckey = '[target_ckey]'")
|
||||
if(!query_get_message_key.warn_execute())
|
||||
qdel(query_get_message_key)
|
||||
return
|
||||
if(query_get_message_key.NextRow())
|
||||
target_key = query_get_message_key.item[1]
|
||||
qdel(query_get_message_key)
|
||||
output += "<h2><center>[target_key]</center></h2><center>"
|
||||
if(!linkless)
|
||||
output += "<a href='?_src_=holder;[HrefToken()];addnote=[target_key]'>Add note</a>"
|
||||
output += " <a href='?_src_=holder;[HrefToken()];addmessage=[target_key]'>Add message</a>"
|
||||
output += " <a href='?_src_=holder;[HrefToken()];addwatch=[target_key]'>Add to watchlist</a>"
|
||||
output += " <a href='?_src_=holder;[HrefToken()];showmessageckey=[target_ckey]'>Refresh page</a></center>"
|
||||
else
|
||||
output += " <a href='?_src_=holder;[HrefToken()];showmessageckeylinkless=[target_ckey]'>Refresh page</a></center>"
|
||||
output += ruler
|
||||
if(messagedata)
|
||||
output += "<h2>Messages</h2>"
|
||||
output += messagedata
|
||||
if(watchdata)
|
||||
output += "<h2>Watchlist</h2>"
|
||||
output += watchdata
|
||||
if(notedata)
|
||||
output += "<h2>Notes</h2>"
|
||||
output += notedata
|
||||
if(!linkless)
|
||||
if (agegate)
|
||||
if (skipped) //the first skipped message is still shown so that we can put this link over it.
|
||||
output += "<center><a href='?_src_=holder;[HrefToken()];showmessageckey=[target_ckey];showall=1' style='position: relative; top: -3em;'>Show [skipped] hidden messages</a></center>"
|
||||
else
|
||||
output += "<center><a href='?_src_=holder;[HrefToken()];showmessageckey=[target_ckey];showall=1'>Show All</a></center>"
|
||||
else
|
||||
output += "<center><a href='?_src_=holder;[HrefToken()];showmessageckey=[target_ckey]'>Hide Old</a></center>"
|
||||
if(index)
|
||||
var/search
|
||||
output += "<center><a href='?_src_=holder;[HrefToken()];addmessageempty=1'>Add message</a><a href='?_src_=holder;[HrefToken()];addwatchempty=1'>Add watchlist entry</a><a href='?_src_=holder;[HrefToken()];addnoteempty=1'>Add note</a></center>"
|
||||
output += ruler
|
||||
if(!isnum(index))
|
||||
index = sanitizeSQL(index)
|
||||
switch(index)
|
||||
if(1)
|
||||
search = "^."
|
||||
if(2)
|
||||
search = "^\[^\[:alpha:\]\]"
|
||||
else
|
||||
search = "^[index]"
|
||||
var/datum/DBQuery/query_list_messages = SSdbcore.NewQuery("SELECT DISTINCT targetckey, (SELECT byond_key FROM [format_table_name("player")] WHERE ckey = targetckey) FROM [format_table_name("messages")] WHERE type <> 'memo' AND targetckey REGEXP '[search]' AND deleted = 0 AND (expire_timestamp > NOW() OR expire_timestamp IS NULL) ORDER BY targetckey")
|
||||
if(!query_list_messages.warn_execute())
|
||||
qdel(query_list_messages)
|
||||
return
|
||||
while(query_list_messages.NextRow())
|
||||
if(QDELETED(usr))
|
||||
return
|
||||
var/index_ckey = query_list_messages.item[1]
|
||||
var/index_key = query_list_messages.item[2]
|
||||
if(!index_key)
|
||||
index_key = index_ckey
|
||||
output += "<a href='?_src_=holder;[HrefToken()];showmessageckey=[index_ckey]'>[index_key]</a><br>"
|
||||
qdel(query_list_messages)
|
||||
else if(!type && !target_ckey && !index)
|
||||
output += "<center><a href='?_src_=holder;[HrefToken()];addmessageempty=1'>Add message</a><a href='?_src_=holder;[HrefToken()];addwatchempty=1'>Add watchlist entry</a><a href='?_src_=holder;[HrefToken()];addnoteempty=1'>Add note</a></center>"
|
||||
output += ruler
|
||||
var/datum/browser/browser = new(usr, "Note panel", "Manage player notes", 1000, 500)
|
||||
var/datum/asset/notes_assets = get_asset_datum(/datum/asset/simple/notes)
|
||||
notes_assets.send(usr.client)
|
||||
browser.set_content(jointext(output, ""))
|
||||
browser.open()
|
||||
|
||||
/proc/get_message_output(type, target_ckey)
|
||||
if(!SSdbcore.Connect())
|
||||
to_chat(usr, "<span class='danger'>Failed to establish database connection.</span>")
|
||||
return
|
||||
if(!type)
|
||||
return
|
||||
var/output
|
||||
if(target_ckey)
|
||||
target_ckey = sanitizeSQL(target_ckey)
|
||||
var/query = "SELECT id, IFNULL((SELECT byond_key FROM [format_table_name("player")] WHERE ckey = adminckey), adminckey), text, timestamp, IFNULL((SELECT byond_key FROM [format_table_name("player")] WHERE ckey = lasteditor), lasteditor) FROM [format_table_name("messages")] WHERE type = '[type]' AND deleted = 0 AND (expire_timestamp > NOW() OR expire_timestamp IS NULL)"
|
||||
if(type == "message" || type == "watchlist entry")
|
||||
query += " AND targetckey = '[target_ckey]'"
|
||||
var/datum/DBQuery/query_get_message_output = SSdbcore.NewQuery(query)
|
||||
if(!query_get_message_output.warn_execute())
|
||||
qdel(query_get_message_output)
|
||||
return
|
||||
while(query_get_message_output.NextRow())
|
||||
var/message_id = query_get_message_output.item[1]
|
||||
var/admin_key = query_get_message_output.item[2]
|
||||
var/text = query_get_message_output.item[3]
|
||||
var/timestamp = query_get_message_output.item[4]
|
||||
var/editor_key = query_get_message_output.item[5]
|
||||
switch(type)
|
||||
if("message")
|
||||
output += "<font color='red' size='3'><b>Admin message left by <span class='prefix'>[admin_key]</span> on [timestamp]</b></font>"
|
||||
output += "<br><font color='red'>[text]</font><br>"
|
||||
var/datum/DBQuery/query_message_read = SSdbcore.NewQuery("UPDATE [format_table_name("messages")] SET type = 'message sent' WHERE id = [message_id]")
|
||||
if(!query_message_read.warn_execute())
|
||||
qdel(query_get_message_output)
|
||||
qdel(query_message_read)
|
||||
return
|
||||
qdel(query_message_read)
|
||||
if("watchlist entry")
|
||||
message_admins("<font color='red'><B>Notice: </B></font><font color='blue'>[key_name_admin(target_ckey)] has been on the watchlist since [timestamp] and has just connected - Reason: [text]</font>")
|
||||
send2irc_adminless_only("Watchlist", "[key_name(target_ckey)] is on the watchlist and has just connected - Reason: [text]")
|
||||
if("memo")
|
||||
output += "<span class='memo'>Memo by <span class='prefix'>[admin_key]</span> on [timestamp]"
|
||||
if(editor_key)
|
||||
output += "<br><span class='memoedit'>Last edit by [editor_key] <A href='?_src_=holder;[HrefToken()];messageedits=[message_id]'>(Click here to see edit log)</A></span>"
|
||||
output += "<br>[text]</span><br>"
|
||||
qdel(query_get_message_output)
|
||||
return output
|
||||
|
||||
#define NOTESFILE "data/player_notes.sav"
|
||||
//if the AUTOCONVERT_NOTES is turned on, anytime a player connects this will be run to try and add all their notes to the databas
|
||||
/proc/convert_notes_sql(ckey)
|
||||
if(!fexists(NOTESFILE))
|
||||
return
|
||||
|
||||
var/savefile/notesfile = new(NOTESFILE)
|
||||
if(!notesfile)
|
||||
log_game("Error: Cannot access [NOTESFILE]")
|
||||
return
|
||||
notesfile.cd = "/[ckey]"
|
||||
while(!notesfile.eof)
|
||||
var/notetext
|
||||
notesfile >> notetext
|
||||
var/server
|
||||
var/ssqlname = CONFIG_GET(string/serversqlname)
|
||||
if (ssqlname)
|
||||
server = ssqlname
|
||||
var/regex/note = new("^(\\d{2}-\\w{3}-\\d{4}) \\| (.+) ~(\\w+)$", "i")
|
||||
note.Find(notetext)
|
||||
var/timestamp = note.group[1]
|
||||
notetext = note.group[2]
|
||||
var/admin_ckey = note.group[3]
|
||||
var/datum/DBQuery/query_convert_time = SSdbcore.NewQuery("SELECT ADDTIME(STR_TO_DATE('[timestamp]','%d-%b-%Y'), '0')")
|
||||
if(!query_convert_time.Execute())
|
||||
qdel(query_convert_time)
|
||||
return
|
||||
if(query_convert_time.NextRow())
|
||||
timestamp = query_convert_time.item[1]
|
||||
qdel(query_convert_time)
|
||||
if(ckey && notetext && timestamp && admin_ckey && server)
|
||||
create_message("note", ckey, admin_ckey, notetext, timestamp, server, 1, 0, null, 0, 0)
|
||||
notesfile.cd = "/"
|
||||
notesfile.dir.Remove(ckey)
|
||||
|
||||
/*alternatively this proc can be run once to pass through every note and attempt to convert it before deleting the file, if done then AUTOCONVERT_NOTES should be turned off
|
||||
this proc can take several minutes to execute fully if converting and cause DD to hang if converting a lot of notes; it's not advised to do so while a server is live
|
||||
/proc/mass_convert_notes()
|
||||
to_chat(world, "Beginning mass note conversion")
|
||||
var/savefile/notesfile = new(NOTESFILE)
|
||||
if(!notesfile)
|
||||
log_game("Error: Cannot access [NOTESFILE]")
|
||||
return
|
||||
notesfile.cd = "/"
|
||||
for(var/ckey in notesfile.dir)
|
||||
convert_notes_sql(ckey)
|
||||
to_chat(world, "Deleting NOTESFILE")
|
||||
fdel(NOTESFILE)
|
||||
to_chat(world, "Finished mass note conversion, remember to turn off AUTOCONVERT_NOTES")*/
|
||||
#undef NOTESFILE
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,699 @@
|
||||
/client/var/adminhelptimerid = 0 //a timer id for returning the ahelp verb
|
||||
/client/var/datum/admin_help/current_ticket //the current ticket the (usually) not-admin client is dealing with
|
||||
|
||||
//
|
||||
//TICKET MANAGER
|
||||
//
|
||||
|
||||
GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new)
|
||||
|
||||
/datum/admin_help_tickets
|
||||
var/list/active_tickets = list()
|
||||
var/list/closed_tickets = list()
|
||||
var/list/resolved_tickets = list()
|
||||
|
||||
var/obj/effect/statclick/ticket_list/astatclick = new(null, null, AHELP_ACTIVE)
|
||||
var/obj/effect/statclick/ticket_list/cstatclick = new(null, null, AHELP_CLOSED)
|
||||
var/obj/effect/statclick/ticket_list/rstatclick = new(null, null, AHELP_RESOLVED)
|
||||
|
||||
/datum/admin_help_tickets/Destroy()
|
||||
QDEL_LIST(active_tickets)
|
||||
QDEL_LIST(closed_tickets)
|
||||
QDEL_LIST(resolved_tickets)
|
||||
QDEL_NULL(astatclick)
|
||||
QDEL_NULL(cstatclick)
|
||||
QDEL_NULL(rstatclick)
|
||||
return ..()
|
||||
|
||||
/datum/admin_help_tickets/proc/TicketByID(id)
|
||||
var/list/lists = list(active_tickets, closed_tickets, resolved_tickets)
|
||||
for(var/I in lists)
|
||||
for(var/J in I)
|
||||
var/datum/admin_help/AH = J
|
||||
if(AH.id == id)
|
||||
return J
|
||||
|
||||
/datum/admin_help_tickets/proc/TicketsByCKey(ckey)
|
||||
. = list()
|
||||
var/list/lists = list(active_tickets, closed_tickets, resolved_tickets)
|
||||
for(var/I in lists)
|
||||
for(var/J in I)
|
||||
var/datum/admin_help/AH = J
|
||||
if(AH.initiator_ckey == ckey)
|
||||
. += AH
|
||||
|
||||
//private
|
||||
/datum/admin_help_tickets/proc/ListInsert(datum/admin_help/new_ticket)
|
||||
var/list/ticket_list
|
||||
switch(new_ticket.state)
|
||||
if(AHELP_ACTIVE)
|
||||
ticket_list = active_tickets
|
||||
if(AHELP_CLOSED)
|
||||
ticket_list = closed_tickets
|
||||
if(AHELP_RESOLVED)
|
||||
ticket_list = resolved_tickets
|
||||
else
|
||||
CRASH("Invalid ticket state: [new_ticket.state]")
|
||||
var/num_closed = ticket_list.len
|
||||
if(num_closed)
|
||||
for(var/I in 1 to num_closed)
|
||||
var/datum/admin_help/AH = ticket_list[I]
|
||||
if(AH.id > new_ticket.id)
|
||||
ticket_list.Insert(I, new_ticket)
|
||||
return
|
||||
ticket_list += new_ticket
|
||||
|
||||
//opens the ticket listings for one of the 3 states
|
||||
/datum/admin_help_tickets/proc/BrowseTickets(state)
|
||||
var/list/l2b
|
||||
var/title
|
||||
switch(state)
|
||||
if(AHELP_ACTIVE)
|
||||
l2b = active_tickets
|
||||
title = "Active Tickets"
|
||||
if(AHELP_CLOSED)
|
||||
l2b = closed_tickets
|
||||
title = "Closed Tickets"
|
||||
if(AHELP_RESOLVED)
|
||||
l2b = resolved_tickets
|
||||
title = "Resolved Tickets"
|
||||
if(!l2b)
|
||||
return
|
||||
var/list/dat = list("<html><head><title>[title]</title></head>")
|
||||
dat += "<A href='?_src_=holder;[HrefToken()];ahelp_tickets=[state]'>Refresh</A><br><br>"
|
||||
for(var/I in l2b)
|
||||
var/datum/admin_help/AH = I
|
||||
dat += "<span class='adminnotice'><span class='adminhelp'>Ticket #[AH.id]</span>: <A href='?_src_=holder;[HrefToken()];ahelp=[REF(AH)];ahelp_action=ticket'>[AH.initiator_key_name]: [AH.name]</A></span><br>"
|
||||
|
||||
usr << browse(dat.Join(), "window=ahelp_list[state];size=600x480")
|
||||
|
||||
//Tickets statpanel
|
||||
/datum/admin_help_tickets/proc/stat_entry()
|
||||
var/num_disconnected = 0
|
||||
stat("Active Tickets:", astatclick.update("[active_tickets.len]"))
|
||||
for(var/I in active_tickets)
|
||||
var/datum/admin_help/AH = I
|
||||
if(AH.initiator)
|
||||
stat("#[AH.id]. [AH.initiator_key_name]:", AH.statclick.update())
|
||||
else
|
||||
++num_disconnected
|
||||
if(num_disconnected)
|
||||
stat("Disconnected:", astatclick.update("[num_disconnected]"))
|
||||
stat("Closed Tickets:", cstatclick.update("[closed_tickets.len]"))
|
||||
stat("Resolved Tickets:", rstatclick.update("[resolved_tickets.len]"))
|
||||
|
||||
//Reassociate still open ticket if one exists
|
||||
/datum/admin_help_tickets/proc/ClientLogin(client/C)
|
||||
C.current_ticket = CKey2ActiveTicket(C.ckey)
|
||||
if(C.current_ticket)
|
||||
C.current_ticket.initiator = C
|
||||
C.current_ticket.AddInteraction("Client reconnected.")
|
||||
|
||||
//Dissasociate ticket
|
||||
/datum/admin_help_tickets/proc/ClientLogout(client/C)
|
||||
if(C.current_ticket)
|
||||
C.current_ticket.AddInteraction("Client disconnected.")
|
||||
C.current_ticket.initiator = null
|
||||
C.current_ticket = null
|
||||
|
||||
//Get a ticket given a ckey
|
||||
/datum/admin_help_tickets/proc/CKey2ActiveTicket(ckey)
|
||||
for(var/I in active_tickets)
|
||||
var/datum/admin_help/AH = I
|
||||
if(AH.initiator_ckey == ckey)
|
||||
return AH
|
||||
|
||||
//
|
||||
//TICKET LIST STATCLICK
|
||||
//
|
||||
|
||||
/obj/effect/statclick/ticket_list
|
||||
var/current_state
|
||||
|
||||
/obj/effect/statclick/ticket_list/New(loc, name, state)
|
||||
current_state = state
|
||||
..()
|
||||
|
||||
/obj/effect/statclick/ticket_list/Click()
|
||||
GLOB.ahelp_tickets.BrowseTickets(current_state)
|
||||
|
||||
//
|
||||
//TICKET DATUM
|
||||
//
|
||||
|
||||
/datum/admin_help
|
||||
var/id
|
||||
var/name
|
||||
var/state = AHELP_ACTIVE
|
||||
|
||||
var/opened_at
|
||||
var/closed_at
|
||||
|
||||
var/client/initiator //semi-misnomer, it's the person who ahelped/was bwoinked
|
||||
var/initiator_ckey
|
||||
var/initiator_key_name
|
||||
var/heard_by_no_admins = FALSE
|
||||
|
||||
var/list/_interactions //use AddInteraction() or, preferably, admin_ticket_log()
|
||||
|
||||
var/obj/effect/statclick/ahelp/statclick
|
||||
|
||||
var/static/ticket_counter = 0
|
||||
|
||||
//call this on its own to create a ticket, don't manually assign current_ticket
|
||||
//msg is the title of the ticket: usually the ahelp text
|
||||
//is_bwoink is TRUE if this ticket was started by an admin PM
|
||||
/datum/admin_help/New(msg, client/C, is_bwoink)
|
||||
//clean the input msg
|
||||
msg = sanitize(copytext(msg,1,MAX_MESSAGE_LEN))
|
||||
if(!msg || !C || !C.mob)
|
||||
qdel(src)
|
||||
return
|
||||
|
||||
id = ++ticket_counter
|
||||
opened_at = world.time
|
||||
|
||||
name = msg
|
||||
|
||||
initiator = C
|
||||
initiator_ckey = initiator.ckey
|
||||
initiator_key_name = key_name(initiator, FALSE, TRUE)
|
||||
if(initiator.current_ticket) //This is a bug
|
||||
stack_trace("Multiple ahelp current_tickets")
|
||||
initiator.current_ticket.AddInteraction("Ticket erroneously left open by code")
|
||||
initiator.current_ticket.Close()
|
||||
initiator.current_ticket = src
|
||||
|
||||
TimeoutVerb()
|
||||
|
||||
statclick = new(null, src)
|
||||
_interactions = list()
|
||||
|
||||
if(is_bwoink)
|
||||
AddInteraction("<font color='blue'>[key_name_admin(usr)] PM'd [LinkedReplyName()]</font>")
|
||||
message_admins("<font color='blue'>Ticket [TicketHref("#[id]")] created</font>")
|
||||
else
|
||||
MessageNoRecipient(msg)
|
||||
|
||||
//send it to irc if nobody is on and tell us how many were on
|
||||
var/admin_number_present = send2irc_adminless_only(initiator_ckey, "Ticket #[id]: [name]")
|
||||
log_admin_private("Ticket #[id]: [key_name(initiator)]: [name] - heard by [admin_number_present] non-AFK admins who have +BAN.")
|
||||
if(admin_number_present <= 0)
|
||||
to_chat(C, "<span class='notice'>No active admins are online, your adminhelp was sent to the admin irc.</span>")
|
||||
heard_by_no_admins = TRUE
|
||||
|
||||
GLOB.ahelp_tickets.active_tickets += src
|
||||
|
||||
/datum/admin_help/Destroy()
|
||||
RemoveActive()
|
||||
GLOB.ahelp_tickets.closed_tickets -= src
|
||||
GLOB.ahelp_tickets.resolved_tickets -= src
|
||||
return ..()
|
||||
|
||||
/datum/admin_help/proc/AddInteraction(formatted_message)
|
||||
if(heard_by_no_admins && usr && usr.ckey != initiator_ckey)
|
||||
heard_by_no_admins = FALSE
|
||||
send2irc(initiator_ckey, "Ticket #[id]: Answered by [key_name(usr)]")
|
||||
_interactions += "[TIME_STAMP("hh:mm:ss", FALSE)]: [formatted_message]"
|
||||
|
||||
//Removes the ahelp verb and returns it after 2 minutes
|
||||
/datum/admin_help/proc/TimeoutVerb()
|
||||
initiator.verbs -= /client/verb/adminhelp
|
||||
initiator.adminhelptimerid = addtimer(CALLBACK(initiator, /client/proc/giveadminhelpverb), 1200, TIMER_STOPPABLE) //2 minute cooldown of admin helps
|
||||
|
||||
//private
|
||||
/datum/admin_help/proc/FullMonty(ref_src)
|
||||
if(!ref_src)
|
||||
ref_src = "[REF(src)]"
|
||||
. = ADMIN_FULLMONTY_NONAME(initiator.mob)
|
||||
if(state == AHELP_ACTIVE)
|
||||
. += ClosureLinks(ref_src)
|
||||
|
||||
//private
|
||||
/datum/admin_help/proc/ClosureLinks(ref_src)
|
||||
if(!ref_src)
|
||||
ref_src = "[REF(src)]"
|
||||
. = " (<A HREF='?_src_=holder;[HrefToken(TRUE)];ahelp=[ref_src];ahelp_action=reject'>REJT</A>)"
|
||||
. += " (<A HREF='?_src_=holder;[HrefToken(TRUE)];ahelp=[ref_src];ahelp_action=icissue'>IC</A>)"
|
||||
. += " (<A HREF='?_src_=holder;[HrefToken(TRUE)];ahelp=[ref_src];ahelp_action=close'>CLOSE</A>)"
|
||||
. += " (<A HREF='?_src_=holder;[HrefToken(TRUE)];ahelp=[ref_src];ahelp_action=resolve'>RSLVE</A>)"
|
||||
. += " (<A HREF='?_src_=holder;[HrefToken(TRUE)];ahelp=[ref_src];ahelp_action=handleissue'>HANDLE</A>)"
|
||||
|
||||
//private
|
||||
/datum/admin_help/proc/LinkedReplyName(ref_src)
|
||||
if(!ref_src)
|
||||
ref_src = "[REF(src)]"
|
||||
return "<A HREF='?_src_=holder;[HrefToken(TRUE)];ahelp=[ref_src];ahelp_action=reply'>[initiator_key_name]</A>"
|
||||
|
||||
//private
|
||||
/datum/admin_help/proc/TicketHref(msg, ref_src, action = "ticket")
|
||||
if(!ref_src)
|
||||
ref_src = "[REF(src)]"
|
||||
return "<A HREF='?_src_=holder;[HrefToken(TRUE)];ahelp=[ref_src];ahelp_action=[action]'>[msg]</A>"
|
||||
|
||||
//message from the initiator without a target, all admins will see this
|
||||
//won't bug irc
|
||||
/datum/admin_help/proc/MessageNoRecipient(msg)
|
||||
var/ref_src = "[REF(src)]"
|
||||
//Message to be sent to all admins
|
||||
var/admin_msg = "<span class='adminnotice'><span class='adminhelp'>Ticket [TicketHref("#[id]", ref_src)]</span><b>: [LinkedReplyName(ref_src)] [FullMonty(ref_src)]:</b> <span class='linkify'>[keywords_lookup(msg)]</span></span>"
|
||||
|
||||
AddInteraction("<font color='red'>[LinkedReplyName(ref_src)]: [msg]</font>")
|
||||
|
||||
//send this msg to all admins
|
||||
for(var/client/X in GLOB.admins)
|
||||
if(X.prefs.toggles & SOUND_ADMINHELP)
|
||||
SEND_SOUND(X, sound('sound/effects/adminhelp.ogg'))
|
||||
window_flash(X, ignorepref = TRUE)
|
||||
to_chat(X, admin_msg)
|
||||
|
||||
//show it to the person adminhelping too
|
||||
to_chat(initiator, "<span class='adminnotice'>PM to-<b>Admins</b>: <span class='linkify'>[msg]</span></span>")
|
||||
|
||||
//Reopen a closed ticket
|
||||
/datum/admin_help/proc/Reopen()
|
||||
if(state == AHELP_ACTIVE)
|
||||
to_chat(usr, "<span class='warning'>This ticket is already open.</span>")
|
||||
return
|
||||
|
||||
if(GLOB.ahelp_tickets.CKey2ActiveTicket(initiator_ckey))
|
||||
to_chat(usr, "<span class='warning'>This user already has an active ticket, cannot reopen this one.</span>")
|
||||
return
|
||||
|
||||
statclick = new(null, src)
|
||||
GLOB.ahelp_tickets.active_tickets += src
|
||||
GLOB.ahelp_tickets.closed_tickets -= src
|
||||
GLOB.ahelp_tickets.resolved_tickets -= src
|
||||
switch(state)
|
||||
if(AHELP_CLOSED)
|
||||
SSblackbox.record_feedback("tally", "ahelp_stats", -1, "closed")
|
||||
if(AHELP_RESOLVED)
|
||||
SSblackbox.record_feedback("tally", "ahelp_stats", -1, "resolved")
|
||||
state = AHELP_ACTIVE
|
||||
closed_at = null
|
||||
if(initiator)
|
||||
initiator.current_ticket = src
|
||||
|
||||
AddInteraction("<font color='purple'>Reopened by [key_name_admin(usr)]</font>")
|
||||
var/msg = "<span class='adminhelp'>Ticket [TicketHref("#[id]")] reopened by [key_name_admin(usr)].</span>"
|
||||
message_admins(msg)
|
||||
log_admin_private(msg)
|
||||
SSblackbox.record_feedback("tally", "ahelp_stats", 1, "reopened")
|
||||
TicketPanel() //can only be done from here, so refresh it
|
||||
|
||||
//private
|
||||
/datum/admin_help/proc/RemoveActive()
|
||||
if(state != AHELP_ACTIVE)
|
||||
return
|
||||
closed_at = world.time
|
||||
QDEL_NULL(statclick)
|
||||
GLOB.ahelp_tickets.active_tickets -= src
|
||||
if(initiator && initiator.current_ticket == src)
|
||||
initiator.current_ticket = null
|
||||
|
||||
//Mark open ticket as closed/meme
|
||||
/datum/admin_help/proc/Close(key_name = key_name_admin(usr), silent = FALSE)
|
||||
if(state != AHELP_ACTIVE)
|
||||
return
|
||||
RemoveActive()
|
||||
state = AHELP_CLOSED
|
||||
GLOB.ahelp_tickets.ListInsert(src)
|
||||
to_chat(initiator, "<span class='adminhelp'>Ticket closed by [usr?.client?.holder?.fakekey? usr.client.holder.fakekey : "an administrator"].</span>")
|
||||
AddInteraction("<font color='red'>Closed by [key_name].</font>")
|
||||
if(!silent)
|
||||
SSblackbox.record_feedback("tally", "ahelp_stats", 1, "closed")
|
||||
var/msg = "Ticket [TicketHref("#[id]")] closed by [key_name]."
|
||||
message_admins(msg)
|
||||
log_admin_private(msg)
|
||||
|
||||
//Mark open ticket as resolved/legitimate, returns ahelp verb
|
||||
/datum/admin_help/proc/Resolve(key_name = key_name_admin(usr), silent = FALSE)
|
||||
if(state != AHELP_ACTIVE)
|
||||
return
|
||||
RemoveActive()
|
||||
state = AHELP_RESOLVED
|
||||
GLOB.ahelp_tickets.ListInsert(src)
|
||||
|
||||
addtimer(CALLBACK(initiator, /client/proc/giveadminhelpverb), 50)
|
||||
|
||||
AddInteraction("<font color='green'>Resolved by [key_name].</font>")
|
||||
to_chat(initiator, "<span class='adminhelp'>Your ticket has been resolved by [usr?.client?.holder?.fakekey? usr.client.holder.fakekey : "an administrator"]. The Adminhelp verb will be returned to you shortly.</span>")
|
||||
if(!silent)
|
||||
SSblackbox.record_feedback("tally", "ahelp_stats", 1, "resolved")
|
||||
var/msg = "Ticket [TicketHref("#[id]")] resolved by [key_name]"
|
||||
message_admins(msg)
|
||||
log_admin_private(msg)
|
||||
|
||||
//Close and return ahelp verb, use if ticket is incoherent
|
||||
/datum/admin_help/proc/Reject(key_name = key_name_admin(usr))
|
||||
if(state != AHELP_ACTIVE)
|
||||
return
|
||||
|
||||
if(initiator)
|
||||
initiator.giveadminhelpverb()
|
||||
|
||||
SEND_SOUND(initiator, sound('sound/effects/adminhelp.ogg'))
|
||||
|
||||
to_chat(initiator, "<font color='red' size='4'><b>- AdminHelp Rejected by [usr?.client?.holder?.fakekey? usr.client.holder.fakekey : "an administrator"]! -</b></font>")
|
||||
to_chat(initiator, "<font color='red'><b>Your admin help was rejected.</b> The adminhelp verb has been returned to you so that you may try again.</font>")
|
||||
to_chat(initiator, "Please try to be calm, clear, and descriptive in admin helps, do not assume the admin has seen any related events, and clearly state the names of anybody you are reporting.")
|
||||
|
||||
SSblackbox.record_feedback("tally", "ahelp_stats", 1, "rejected")
|
||||
var/msg = "Ticket [TicketHref("#[id]")] rejected by [key_name]"
|
||||
message_admins(msg)
|
||||
log_admin_private(msg)
|
||||
AddInteraction("Rejected by [key_name].")
|
||||
Close(silent = TRUE)
|
||||
|
||||
//Resolve ticket with IC Issue message
|
||||
/datum/admin_help/proc/ICIssue(key_name = key_name_admin(usr))
|
||||
if(state != AHELP_ACTIVE)
|
||||
return
|
||||
|
||||
var/msg = "<font color='red' size='4'><b>- AdminHelp marked as IC issue by [usr?.client?.holder?.fakekey? usr.client.holder.fakekey : "an administrator"]! -</b></font><br>"
|
||||
msg += "<font color='red'><b>Losing is part of the game!</b></font><br>"
|
||||
msg += "<font color='red'>It is also possible that your ahelp is unable to be answered properly, due to events occurring in the round.</font>"
|
||||
if(initiator)
|
||||
to_chat(initiator, msg)
|
||||
|
||||
SSblackbox.record_feedback("tally", "ahelp_stats", 1, "IC")
|
||||
msg = "Ticket [TicketHref("#[id]")] marked as IC by [key_name]"
|
||||
message_admins(msg)
|
||||
log_admin_private(msg)
|
||||
AddInteraction("Marked as IC issue by [key_name]")
|
||||
Resolve(silent = TRUE)
|
||||
|
||||
//Let the initiator know their ahelp is being handled
|
||||
/datum/admin_help/proc/HandleIssue(key_name = key_name_admin(usr))
|
||||
if(state != AHELP_ACTIVE)
|
||||
return
|
||||
|
||||
var/msg = "<span class ='adminhelp'>Your ticket is now being handled by an admin. Please be patient.</span>"
|
||||
|
||||
if(initiator)
|
||||
to_chat(initiator, msg)
|
||||
|
||||
SSblackbox.record_feedback("tally", "ahelp_stats", 1, "handling")
|
||||
msg = "Ticket [TicketHref("#[id]")] is being handled by [key_name]"
|
||||
message_admins(msg)
|
||||
log_admin_private(msg)
|
||||
AddInteraction("Being handled by [key_name]")
|
||||
|
||||
//Show the ticket panel
|
||||
/datum/admin_help/proc/TicketPanel()
|
||||
var/list/dat = list("<html><head><title>Ticket #[id]</title></head>")
|
||||
var/ref_src = "[REF(src)]"
|
||||
dat += "<h4>Admin Help Ticket #[id]: [LinkedReplyName(ref_src)]</h4>"
|
||||
dat += "<b>State: "
|
||||
switch(state)
|
||||
if(AHELP_ACTIVE)
|
||||
dat += "<font color='red'>OPEN</font>"
|
||||
if(AHELP_RESOLVED)
|
||||
dat += "<font color='green'>RESOLVED</font>"
|
||||
if(AHELP_CLOSED)
|
||||
dat += "CLOSED"
|
||||
else
|
||||
dat += "UNKNOWN"
|
||||
dat += "</b>[FOURSPACES][TicketHref("Refresh", ref_src)][FOURSPACES][TicketHref("Re-Title", ref_src, "retitle")]"
|
||||
if(state != AHELP_ACTIVE)
|
||||
dat += "[FOURSPACES][TicketHref("Reopen", ref_src, "reopen")]"
|
||||
dat += "<br><br>Opened at: [GAMETIMESTAMP("hh:mm:ss", closed_at)] (Approx [DisplayTimeText(world.time - opened_at)] ago)"
|
||||
if(closed_at)
|
||||
dat += "<br>Closed at: [GAMETIMESTAMP("hh:mm:ss", closed_at)] (Approx [DisplayTimeText(world.time - closed_at)] ago)"
|
||||
dat += "<br><br>"
|
||||
if(initiator)
|
||||
dat += "<b>Actions:</b> [FullMonty(ref_src)]<br>"
|
||||
else
|
||||
dat += "<b>DISCONNECTED</b>[FOURSPACES][ClosureLinks(ref_src)]<br>"
|
||||
dat += "<br><b>Log:</b><br><br>"
|
||||
for(var/I in _interactions)
|
||||
dat += "[I]<br>"
|
||||
|
||||
usr << browse(dat.Join(), "window=ahelp[id];size=620x480")
|
||||
|
||||
/datum/admin_help/proc/Retitle()
|
||||
var/new_title = input(usr, "Enter a title for the ticket", "Rename Ticket", name) as text|null
|
||||
if(new_title)
|
||||
name = new_title
|
||||
//not saying the original name cause it could be a long ass message
|
||||
var/msg = "Ticket [TicketHref("#[id]")] titled [name] by [key_name_admin(usr)]"
|
||||
message_admins(msg)
|
||||
log_admin_private(msg)
|
||||
TicketPanel() //we have to be here to do this
|
||||
|
||||
//Forwarded action from admin/Topic
|
||||
/datum/admin_help/proc/Action(action)
|
||||
testing("Ahelp action: [action]")
|
||||
switch(action)
|
||||
if("ticket")
|
||||
TicketPanel()
|
||||
if("retitle")
|
||||
Retitle()
|
||||
if("reject")
|
||||
Reject()
|
||||
if("reply")
|
||||
usr.client.cmd_ahelp_reply(initiator)
|
||||
if("icissue")
|
||||
ICIssue()
|
||||
if("close")
|
||||
Close()
|
||||
if("resolve")
|
||||
Resolve()
|
||||
if("handleissue")
|
||||
HandleIssue()
|
||||
if("reopen")
|
||||
Reopen()
|
||||
|
||||
//
|
||||
// TICKET STATCLICK
|
||||
//
|
||||
|
||||
/obj/effect/statclick/ahelp
|
||||
var/datum/admin_help/ahelp_datum
|
||||
|
||||
/obj/effect/statclick/ahelp/Initialize(mapload, datum/admin_help/AH)
|
||||
ahelp_datum = AH
|
||||
. = ..()
|
||||
|
||||
/obj/effect/statclick/ahelp/update()
|
||||
return ..(ahelp_datum.name)
|
||||
|
||||
/obj/effect/statclick/ahelp/Click()
|
||||
ahelp_datum.TicketPanel()
|
||||
|
||||
/obj/effect/statclick/ahelp/Destroy()
|
||||
ahelp_datum = null
|
||||
return ..()
|
||||
|
||||
//
|
||||
// CLIENT PROCS
|
||||
//
|
||||
|
||||
/client/proc/giveadminhelpverb()
|
||||
src.verbs |= /client/verb/adminhelp
|
||||
deltimer(adminhelptimerid)
|
||||
adminhelptimerid = 0
|
||||
|
||||
// Used for methods where input via arg doesn't work
|
||||
/client/proc/get_adminhelp()
|
||||
var/msg = input(src, "Please describe your problem concisely and an admin will help as soon as they're able.", "Adminhelp contents") as text
|
||||
adminhelp(msg)
|
||||
|
||||
/client/verb/adminhelp(msg as text)
|
||||
set category = "Admin"
|
||||
set name = "Adminhelp"
|
||||
|
||||
if(GLOB.say_disabled) //This is here to try to identify lag problems
|
||||
to_chat(usr, "<span class='danger'>Speech is currently admin-disabled.</span>")
|
||||
return
|
||||
|
||||
//handle muting and automuting
|
||||
if(prefs.muted & MUTE_ADMINHELP)
|
||||
to_chat(src, "<span class='danger'>Error: Admin-PM: You cannot send adminhelps (Muted).</span>")
|
||||
return
|
||||
if(handle_spam_prevention(msg,MUTE_ADMINHELP))
|
||||
return
|
||||
|
||||
msg = trim(msg)
|
||||
|
||||
if(!msg)
|
||||
return
|
||||
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Adminhelp") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
if(current_ticket)
|
||||
if(alert(usr, "You already have a ticket open. Is this for the same issue?",,"Yes","No") != "No")
|
||||
if(current_ticket)
|
||||
current_ticket.MessageNoRecipient(msg)
|
||||
current_ticket.TimeoutVerb()
|
||||
return
|
||||
else
|
||||
to_chat(usr, "<span class='warning'>Ticket not found, creating new one...</span>")
|
||||
else
|
||||
current_ticket.AddInteraction("[key_name_admin(usr)] opened a new ticket.")
|
||||
current_ticket.Close()
|
||||
|
||||
new /datum/admin_help(msg, src, FALSE)
|
||||
|
||||
//
|
||||
// LOGGING
|
||||
//
|
||||
|
||||
//Use this proc when an admin takes action that may be related to an open ticket on what
|
||||
//what can be a client, ckey, or mob
|
||||
/proc/admin_ticket_log(what, message)
|
||||
var/client/C
|
||||
var/mob/Mob = what
|
||||
if(istype(Mob))
|
||||
C = Mob.client
|
||||
else
|
||||
C = what
|
||||
if(istype(C) && C.current_ticket)
|
||||
C.current_ticket.AddInteraction(message)
|
||||
return C.current_ticket
|
||||
if(istext(what)) //ckey
|
||||
var/datum/admin_help/AH = GLOB.ahelp_tickets.CKey2ActiveTicket(what)
|
||||
if(AH)
|
||||
AH.AddInteraction(message)
|
||||
return AH
|
||||
|
||||
//
|
||||
// HELPER PROCS
|
||||
//
|
||||
|
||||
/proc/get_admin_counts(requiredflags = R_BAN)
|
||||
. = list("total" = list(), "noflags" = list(), "afk" = list(), "stealth" = list(), "present" = list())
|
||||
for(var/client/X in GLOB.admins)
|
||||
.["total"] += X
|
||||
if(requiredflags != 0 && !check_rights_for(X, requiredflags))
|
||||
.["noflags"] += X
|
||||
else if(X.is_afk())
|
||||
.["afk"] += X
|
||||
else if(X.holder.fakekey)
|
||||
.["stealth"] += X
|
||||
else
|
||||
.["present"] += X
|
||||
|
||||
/proc/send2irc_adminless_only(source, msg, requiredflags = R_BAN)
|
||||
var/list/adm = get_admin_counts(requiredflags)
|
||||
var/list/activemins = adm["present"]
|
||||
. = activemins.len
|
||||
if(. <= 0)
|
||||
var/final = ""
|
||||
var/list/afkmins = adm["afk"]
|
||||
var/list/stealthmins = adm["stealth"]
|
||||
var/list/powerlessmins = adm["noflags"]
|
||||
var/list/allmins = adm["total"]
|
||||
if(!afkmins.len && !stealthmins.len && !powerlessmins.len)
|
||||
final = "[msg] - No admins online"
|
||||
else
|
||||
final = "[msg] - All admins stealthed\[[english_list(stealthmins)]\], AFK\[[english_list(afkmins)]\], or lacks +BAN\[[english_list(powerlessmins)]\]! Total: [allmins.len] "
|
||||
send2irc(source,final)
|
||||
send2otherserver(source,final)
|
||||
|
||||
|
||||
/proc/send2irc(msg,msg2)
|
||||
msg = replacetext(replacetext(msg, "\proper", ""), "\improper", "")
|
||||
msg2 = replacetext(replacetext(msg2, "\proper", ""), "\improper", "")
|
||||
world.TgsTargetedChatBroadcast("[msg] | [msg2]", TRUE)
|
||||
|
||||
/proc/send2otherserver(source,msg,type = "Ahelp")
|
||||
var/comms_key = CONFIG_GET(string/comms_key)
|
||||
if(!comms_key)
|
||||
return
|
||||
var/list/message = list()
|
||||
message["message_sender"] = source
|
||||
message["message"] = msg
|
||||
message["source"] = "([CONFIG_GET(string/cross_comms_name)])"
|
||||
message["key"] = comms_key
|
||||
message += type
|
||||
|
||||
var/list/servers = CONFIG_GET(keyed_list/cross_server)
|
||||
for(var/I in servers)
|
||||
world.Export("[servers[I]]?[list2params(message)]")
|
||||
|
||||
|
||||
/proc/ircadminwho()
|
||||
var/list/message = list("Admins: ")
|
||||
var/list/admin_keys = list()
|
||||
for(var/adm in GLOB.admins)
|
||||
var/client/C = adm
|
||||
admin_keys += "[C][C.holder.fakekey ? "(Stealth)" : ""][C.is_afk() ? "(AFK)" : ""]"
|
||||
|
||||
for(var/admin in admin_keys)
|
||||
if(LAZYLEN(message) > 1)
|
||||
message += ", [admin]"
|
||||
else
|
||||
message += "[admin]"
|
||||
|
||||
return jointext(message, "")
|
||||
|
||||
/proc/keywords_lookup(msg,irc)
|
||||
|
||||
//This is a list of words which are ignored by the parser when comparing message contents for names. MUST BE IN LOWER CASE!
|
||||
var/list/adminhelp_ignored_words = list("unknown","the","a","an","of","monkey","alien","as", "i")
|
||||
|
||||
//explode the input msg into a list
|
||||
var/list/msglist = splittext(msg, " ")
|
||||
|
||||
//generate keywords lookup
|
||||
var/list/surnames = list()
|
||||
var/list/forenames = list()
|
||||
var/list/ckeys = list()
|
||||
var/founds = ""
|
||||
for(var/mob/M in GLOB.mob_list)
|
||||
var/list/indexing = list(M.real_name, M.name)
|
||||
if(M.mind)
|
||||
indexing += M.mind.name
|
||||
|
||||
for(var/string in indexing)
|
||||
var/list/L = splittext(string, " ")
|
||||
var/surname_found = 0
|
||||
//surnames
|
||||
for(var/i=L.len, i>=1, i--)
|
||||
var/word = ckey(L[i])
|
||||
if(word)
|
||||
surnames[word] = M
|
||||
surname_found = i
|
||||
break
|
||||
//forenames
|
||||
for(var/i=1, i<surname_found, i++)
|
||||
var/word = ckey(L[i])
|
||||
if(word)
|
||||
forenames[word] = M
|
||||
//ckeys
|
||||
ckeys[M.ckey] = M
|
||||
|
||||
var/ai_found = 0
|
||||
msg = ""
|
||||
var/list/mobs_found = list()
|
||||
for(var/original_word in msglist)
|
||||
var/word = ckey(original_word)
|
||||
if(word)
|
||||
if(!(word in adminhelp_ignored_words))
|
||||
if(word == "ai")
|
||||
ai_found = 1
|
||||
else
|
||||
var/mob/found = ckeys[word]
|
||||
if(!found)
|
||||
found = surnames[word]
|
||||
if(!found)
|
||||
found = forenames[word]
|
||||
if(found)
|
||||
if(!(found in mobs_found))
|
||||
mobs_found += found
|
||||
if(!ai_found && isAI(found))
|
||||
ai_found = 1
|
||||
var/is_antag = 0
|
||||
if(found.mind && found.mind.special_role)
|
||||
is_antag = 1
|
||||
founds += "Name: [found.name]([found.real_name]) Key: [found.key] Ckey: [found.ckey] [is_antag ? "(Antag)" : null] "
|
||||
msg += "[original_word]<font size='1' color='[is_antag ? "red" : "black"]'>(<A HREF='?_src_=holder;[HrefToken(TRUE)];adminmoreinfo=[REF(found)]'>?</A>|<A HREF='?_src_=holder;[HrefToken(TRUE)];adminplayerobservefollow=[REF(found)]'>F</A>)</font> "
|
||||
continue
|
||||
msg += "[original_word] "
|
||||
if(irc)
|
||||
if(founds == "")
|
||||
return "Search Failed"
|
||||
else
|
||||
return founds
|
||||
|
||||
return msg
|
||||
@@ -0,0 +1,97 @@
|
||||
/proc/show_air_status_to(turf/target, mob/user)
|
||||
var/datum/gas_mixture/env = target.return_air()
|
||||
var/list/env_gases = env.gases
|
||||
var/burning = FALSE
|
||||
if(isopenturf(target))
|
||||
var/turf/open/T = target
|
||||
if(T.active_hotspot)
|
||||
burning = TRUE
|
||||
|
||||
var/list/lines = list("<span class='adminnotice'>[AREACOORD(target)]: [env.temperature] K ([env.temperature - T0C] C), [env.return_pressure()] kPa[(burning)?(", <font color='red'>burning</font>"):(null)]</span>")
|
||||
for(var/id in env_gases)
|
||||
var/moles = env_gases[id]
|
||||
if (moles >= 0.00001)
|
||||
lines += "[GLOB.meta_gas_names[id]]: [moles] mol"
|
||||
to_chat(usr, lines.Join("\n"))
|
||||
|
||||
/client/proc/air_status(turf/target)
|
||||
set category = "Debug"
|
||||
set name = "Display Air Status"
|
||||
|
||||
if(!isturf(target))
|
||||
return
|
||||
show_air_status_to(target, usr)
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Show Air Status") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
/client/proc/fix_next_move()
|
||||
set category = "Debug"
|
||||
set name = "Unfreeze Everyone"
|
||||
var/largest_move_time = 0
|
||||
var/largest_click_time = 0
|
||||
var/mob/largest_move_mob = null
|
||||
var/mob/largest_click_mob = null
|
||||
for(var/mob/M in world)
|
||||
if(!M.client)
|
||||
continue
|
||||
if(M.next_move >= largest_move_time)
|
||||
largest_move_mob = M
|
||||
if(M.next_move > world.time)
|
||||
largest_move_time = M.next_move - world.time
|
||||
else
|
||||
largest_move_time = 1
|
||||
if(M.next_click >= largest_click_time)
|
||||
largest_click_mob = M
|
||||
if(M.next_click > world.time)
|
||||
largest_click_time = M.next_click - world.time
|
||||
else
|
||||
largest_click_time = 0
|
||||
log_admin("DEBUG: [key_name(M)] next_move = [M.next_move] lastDblClick = [M.next_click] world.time = [world.time]")
|
||||
M.next_move = 1
|
||||
M.next_click = 0
|
||||
message_admins("[ADMIN_LOOKUPFLW(largest_move_mob)] had the largest move delay with [largest_move_time] frames / [DisplayTimeText(largest_move_time)]!")
|
||||
message_admins("[ADMIN_LOOKUPFLW(largest_click_mob)] had the largest click delay with [largest_click_time] frames / [DisplayTimeText(largest_click_time)]!")
|
||||
message_admins("world.time = [world.time]")
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Unfreeze Everyone") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
return
|
||||
|
||||
/client/proc/radio_report()
|
||||
set category = "Debug"
|
||||
set name = "Radio report"
|
||||
|
||||
var/output = "<b>Radio Report</b><hr>"
|
||||
for (var/fq in SSradio.frequencies)
|
||||
output += "<b>Freq: [fq]</b><br>"
|
||||
var/datum/radio_frequency/fqs = SSradio.frequencies[fq]
|
||||
if (!fqs)
|
||||
output += " <b>ERROR</b><br>"
|
||||
continue
|
||||
for (var/filter in fqs.devices)
|
||||
var/list/f = fqs.devices[filter]
|
||||
if (!f)
|
||||
output += " [filter]: ERROR<br>"
|
||||
continue
|
||||
output += " [filter]: [f.len]<br>"
|
||||
for (var/device in f)
|
||||
if (istype(device, /atom))
|
||||
var/atom/A = device
|
||||
output += " [device] ([AREACOORD(A)])<br>"
|
||||
else
|
||||
output += " [device]<br>"
|
||||
|
||||
usr << browse(output,"window=radioreport")
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Show Radio Report") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
/client/proc/reload_admins()
|
||||
set name = "Reload Admins"
|
||||
set category = "Admin"
|
||||
|
||||
if(!src.holder)
|
||||
return
|
||||
|
||||
var/confirm = alert(src, "Are you sure you want to reload all admins?", "Confirm", "Yes", "No")
|
||||
if(confirm !="Yes")
|
||||
return
|
||||
|
||||
load_admins()
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Reload All Admins") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
message_admins("[key_name_admin(usr)] manually reloaded admins")
|
||||
@@ -0,0 +1,358 @@
|
||||
//- Are all the floors with or without air, as they should be? (regular or airless)
|
||||
//- Does the area have an APC?
|
||||
//- Does the area have an Air Alarm?
|
||||
//- Does the area have a Request Console?
|
||||
//- Does the area have lights?
|
||||
//- Does the area have a light switch?
|
||||
//- Does the area have enough intercoms?
|
||||
//- Does the area have enough security cameras? (Use the 'Camera Range Display' verb under Debug)
|
||||
//- Is the area connected to the scrubbers air loop?
|
||||
//- Is the area connected to the vent air loop? (vent pumps)
|
||||
//- Is everything wired properly?
|
||||
//- Does the area have a fire alarm and firedoors?
|
||||
//- Do all pod doors work properly?
|
||||
//- Are accesses set properly on doors, pod buttons, etc.
|
||||
//- Are all items placed properly? (not below vents, scrubbers, tables)
|
||||
//- Does the disposal system work properly from all the disposal units in this room and all the units, the pipes of which pass through this room?
|
||||
//- Check for any misplaced or stacked piece of pipe (air and disposal)
|
||||
//- Check for any misplaced or stacked piece of wire
|
||||
//- Identify how hard it is to break into the area and where the weak points are
|
||||
//- Check if the area has too much empty space. If so, make it smaller and replace the rest with maintenance tunnels.
|
||||
|
||||
GLOBAL_LIST_INIT(admin_verbs_debug_mapping, list(
|
||||
/client/proc/camera_view, //-errorage
|
||||
/client/proc/sec_camera_report, //-errorage
|
||||
/client/proc/intercom_view, //-errorage
|
||||
/client/proc/air_status, //Air things
|
||||
/client/proc/Cell, //More air things
|
||||
/client/proc/atmosscan, //check plumbing
|
||||
/client/proc/powerdebug, //check power
|
||||
/client/proc/count_objects_on_z_level,
|
||||
/client/proc/count_objects_all,
|
||||
/client/proc/cmd_assume_direct_control, //-errorage
|
||||
/client/proc/startSinglo,
|
||||
/client/proc/set_server_fps, //allows you to set the ticklag.
|
||||
/client/proc/cmd_admin_grantfullaccess,
|
||||
/client/proc/cmd_admin_areatest_all,
|
||||
/client/proc/cmd_admin_areatest_station,
|
||||
/client/proc/cmd_admin_test_atmos_controllers,
|
||||
/client/proc/cmd_admin_rejuvenate,
|
||||
/datum/admins/proc/show_traitor_panel,
|
||||
/client/proc/disable_communication,
|
||||
/client/proc/cmd_show_at_list,
|
||||
/client/proc/cmd_show_at_markers,
|
||||
/client/proc/manipulate_organs,
|
||||
/client/proc/start_line_profiling,
|
||||
/client/proc/stop_line_profiling,
|
||||
/client/proc/show_line_profiling,
|
||||
/client/proc/create_mapping_job_icons,
|
||||
/client/proc/debug_z_levels,
|
||||
/client/proc/place_ruin
|
||||
))
|
||||
GLOBAL_PROTECT(admin_verbs_debug_mapping)
|
||||
|
||||
/obj/effect/debugging/mapfix_marker
|
||||
name = "map fix marker"
|
||||
icon = 'icons/mob/screen_gen.dmi'
|
||||
icon_state = "mapfixmarker"
|
||||
desc = "I am a mappers mistake."
|
||||
|
||||
/obj/effect/debugging/marker
|
||||
icon = 'icons/turf/areas.dmi'
|
||||
icon_state = "yellow"
|
||||
|
||||
/obj/effect/debugging/marker/Move()
|
||||
return 0
|
||||
|
||||
/client/proc/camera_view()
|
||||
set category = "Mapping"
|
||||
set name = "Camera Range Display"
|
||||
|
||||
var/on = FALSE
|
||||
for(var/turf/T in world)
|
||||
if(T.maptext)
|
||||
on = TRUE
|
||||
T.maptext = null
|
||||
|
||||
if(!on)
|
||||
var/list/seen = list()
|
||||
for(var/obj/machinery/camera/C in GLOB.cameranet.cameras)
|
||||
for(var/turf/T in C.can_see())
|
||||
seen[T]++
|
||||
for(var/turf/T in seen)
|
||||
T.maptext = "[seen[T]]"
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Show Camera Range") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Show Camera Range")
|
||||
|
||||
|
||||
|
||||
/client/proc/sec_camera_report()
|
||||
set category = "Mapping"
|
||||
set name = "Camera Report"
|
||||
|
||||
if(!Master)
|
||||
alert(usr,"Master_controller not found.","Sec Camera Report")
|
||||
return 0
|
||||
|
||||
var/list/obj/machinery/camera/CL = list()
|
||||
|
||||
for(var/obj/machinery/camera/C in GLOB.cameranet.cameras)
|
||||
CL += C
|
||||
|
||||
var/output = {"<B>Camera Abnormalities Report</B><HR>
|
||||
<B>The following abnormalities have been detected. The ones in red need immediate attention: Some of those in black may be intentional.</B><BR><ul>"}
|
||||
|
||||
for(var/obj/machinery/camera/C1 in CL)
|
||||
for(var/obj/machinery/camera/C2 in CL)
|
||||
if(C1 != C2)
|
||||
if(C1.c_tag == C2.c_tag)
|
||||
output += "<li><font color='red'>c_tag match for cameras at [ADMIN_VERBOSEJMP(C1)] and [ADMIN_VERBOSEJMP(C2)] - c_tag is [C1.c_tag]</font></li>"
|
||||
if(C1.loc == C2.loc && C1.dir == C2.dir && C1.pixel_x == C2.pixel_x && C1.pixel_y == C2.pixel_y)
|
||||
output += "<li><font color='red'>FULLY overlapping cameras at [ADMIN_VERBOSEJMP(C1)] Networks: [json_encode(C1.network)] and [json_encode(C2.network)]</font></li>"
|
||||
if(C1.loc == C2.loc)
|
||||
output += "<li>Overlapping cameras at [ADMIN_VERBOSEJMP(C1)] Networks: [json_encode(C1.network)] and [json_encode(C2.network)]</li>"
|
||||
var/turf/T = get_step(C1,turn(C1.dir,180))
|
||||
if(!T || !isturf(T) || !T.density )
|
||||
if(!(locate(/obj/structure/grille) in T))
|
||||
var/window_check = 0
|
||||
for(var/obj/structure/window/W in T)
|
||||
if (W.dir == turn(C1.dir,180) || W.dir in list(5,6,9,10) )
|
||||
window_check = 1
|
||||
break
|
||||
if(!window_check)
|
||||
output += "<li><font color='red'>Camera not connected to wall at [ADMIN_VERBOSEJMP(C1)] Network: [json_encode(C1.network)]</font></li>"
|
||||
|
||||
output += "</ul>"
|
||||
usr << browse(output,"window=airreport;size=1000x500")
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Show Camera Report") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
/client/proc/intercom_view()
|
||||
set category = "Mapping"
|
||||
set name = "Intercom Range Display"
|
||||
|
||||
var/static/intercom_range_display_status = FALSE
|
||||
intercom_range_display_status = !intercom_range_display_status //blame cyberboss if this breaks something
|
||||
|
||||
for(var/obj/effect/debugging/marker/M in world)
|
||||
qdel(M)
|
||||
|
||||
if(intercom_range_display_status)
|
||||
for(var/obj/item/radio/intercom/I in world)
|
||||
for(var/turf/T in orange(7,I))
|
||||
var/obj/effect/debugging/marker/F = new/obj/effect/debugging/marker(T)
|
||||
if (!(F in view(7,I.loc)))
|
||||
qdel(F)
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Show Intercom Range") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
/client/proc/cmd_show_at_list()
|
||||
set category = "Mapping"
|
||||
set name = "Show roundstart AT list"
|
||||
set desc = "Displays a list of active turfs coordinates at roundstart"
|
||||
|
||||
var/dat = {"<b>Coordinate list of Active Turfs at Roundstart</b>
|
||||
<br>Real-time Active Turfs list you can see in Air Subsystem at active_turfs var<br>"}
|
||||
|
||||
for(var/t in GLOB.active_turfs_startlist)
|
||||
var/turf/T = t
|
||||
dat += "[ADMIN_VERBOSEJMP(T)]\n"
|
||||
dat += "<br>"
|
||||
|
||||
usr << browse(dat, "window=at_list")
|
||||
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Show Roundstart Active Turfs") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
/client/proc/cmd_show_at_markers()
|
||||
set category = "Mapping"
|
||||
set name = "Show roundstart AT markers"
|
||||
set desc = "Places a marker on all active-at-roundstart turfs"
|
||||
|
||||
var/count = 0
|
||||
for(var/obj/effect/abstract/marker/at/AT in GLOB.all_abstract_markers)
|
||||
qdel(AT)
|
||||
count++
|
||||
|
||||
if(count)
|
||||
to_chat(usr, "[count] AT markers removed.")
|
||||
else
|
||||
for(var/t in GLOB.active_turfs_startlist)
|
||||
new /obj/effect/abstract/marker/at(t)
|
||||
count++
|
||||
to_chat(usr, "[count] AT markers placed.")
|
||||
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Show Roundstart Active Turf Markers")
|
||||
|
||||
/client/proc/enable_debug_verbs()
|
||||
set category = "Debug"
|
||||
set name = "Debug verbs - Enable"
|
||||
if(!check_rights(R_DEBUG))
|
||||
return
|
||||
verbs -= /client/proc/enable_debug_verbs
|
||||
verbs.Add(/client/proc/disable_debug_verbs, GLOB.admin_verbs_debug_mapping)
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Enable Debug Verbs") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
/client/proc/disable_debug_verbs()
|
||||
set category = "Debug"
|
||||
set name = "Debug verbs - Disable"
|
||||
verbs.Remove(/client/proc/disable_debug_verbs, GLOB.admin_verbs_debug_mapping)
|
||||
verbs += /client/proc/enable_debug_verbs
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Disable Debug Verbs") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
/client/proc/count_objects_on_z_level()
|
||||
set category = "Mapping"
|
||||
set name = "Count Objects On Level"
|
||||
var/level = input("Which z-level?","Level?") as text
|
||||
if(!level)
|
||||
return
|
||||
var/num_level = text2num(level)
|
||||
if(!num_level)
|
||||
return
|
||||
if(!isnum(num_level))
|
||||
return
|
||||
|
||||
var/type_text = input("Which type path?","Path?") as text
|
||||
if(!type_text)
|
||||
return
|
||||
var/type_path = text2path(type_text)
|
||||
if(!type_path)
|
||||
return
|
||||
|
||||
var/count = 0
|
||||
|
||||
var/list/atom/atom_list = list()
|
||||
|
||||
for(var/atom/A in world)
|
||||
if(istype(A,type_path))
|
||||
var/atom/B = A
|
||||
while(!(isturf(B.loc)))
|
||||
if(B && B.loc)
|
||||
B = B.loc
|
||||
else
|
||||
break
|
||||
if(B)
|
||||
if(B.z == num_level)
|
||||
count++
|
||||
atom_list += A
|
||||
|
||||
to_chat(world, "There are [count] objects of type [type_path] on z-level [num_level]")
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Count Objects Zlevel") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
/client/proc/count_objects_all()
|
||||
set category = "Mapping"
|
||||
set name = "Count Objects All"
|
||||
|
||||
var/type_text = input("Which type path?","") as text
|
||||
if(!type_text)
|
||||
return
|
||||
var/type_path = text2path(type_text)
|
||||
if(!type_path)
|
||||
return
|
||||
|
||||
var/count = 0
|
||||
|
||||
for(var/atom/A in world)
|
||||
if(istype(A,type_path))
|
||||
count++
|
||||
|
||||
to_chat(world, "There are [count] objects of type [type_path] in the game world")
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Count Objects All") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
|
||||
//This proc is intended to detect lag problems relating to communication procs
|
||||
GLOBAL_VAR_INIT(say_disabled, FALSE)
|
||||
/client/proc/disable_communication()
|
||||
set category = "Mapping"
|
||||
set name = "Disable all communication verbs"
|
||||
|
||||
GLOB.say_disabled = !GLOB.say_disabled
|
||||
if(GLOB.say_disabled)
|
||||
message_admins("[key] used 'Disable all communication verbs', killing all communication methods.")
|
||||
else
|
||||
message_admins("[key] used 'Disable all communication verbs', restoring all communication methods.")
|
||||
|
||||
//This generates the icon states for job starting location landmarks.
|
||||
/client/proc/create_mapping_job_icons()
|
||||
set name = "Generate job landmarks icons"
|
||||
set category = "Mapping"
|
||||
var/icon/final = icon()
|
||||
var/mob/living/carbon/human/dummy/D = new(locate(1,1,1)) //spawn on 1,1,1 so we don't have runtimes when items are deleted
|
||||
D.setDir(SOUTH)
|
||||
for(var/job in subtypesof(/datum/job))
|
||||
var/datum/job/JB = new job
|
||||
switch(JB.title)
|
||||
if("AI")
|
||||
final.Insert(icon('icons/mob/ai.dmi', "ai", SOUTH, 1), "AI")
|
||||
if("Cyborg")
|
||||
final.Insert(icon('icons/mob/robots.dmi', "robot", SOUTH, 1), "Cyborg")
|
||||
else
|
||||
for(var/obj/item/I in D)
|
||||
qdel(I)
|
||||
randomize_human(D)
|
||||
JB.equip(D, TRUE, FALSE)
|
||||
COMPILE_OVERLAYS(D)
|
||||
var/icon/I = icon(getFlatIcon(D), frame = 1)
|
||||
final.Insert(I, JB.title)
|
||||
qdel(D)
|
||||
//Also add the x
|
||||
for(var/x_number in 1 to 4)
|
||||
final.Insert(icon('icons/mob/screen_gen.dmi', "x[x_number == 1 ? "" : x_number]"), "x[x_number == 1 ? "" : x_number]")
|
||||
fcopy(final, "icons/mob/landmarks.dmi")
|
||||
|
||||
/client/proc/debug_z_levels()
|
||||
set name = "Debug Z-Levels"
|
||||
set category = "Mapping"
|
||||
|
||||
var/list/z_list = SSmapping.z_list
|
||||
var/list/messages = list()
|
||||
messages += "<b>World</b>: [world.maxx] x [world.maxy] x [world.maxz]<br>"
|
||||
|
||||
var/list/linked_levels = list()
|
||||
var/min_x = INFINITY
|
||||
var/min_y = INFINITY
|
||||
var/max_x = -INFINITY
|
||||
var/max_y = -INFINITY
|
||||
|
||||
for(var/z in 1 to max(world.maxz, z_list.len))
|
||||
if (z > z_list.len)
|
||||
messages += "<b>[z]</b>: Unmanaged (out of bounds)<br>"
|
||||
continue
|
||||
var/datum/space_level/S = z_list[z]
|
||||
if (!S)
|
||||
messages += "<b>[z]</b>: Unmanaged (null)<br>"
|
||||
continue
|
||||
var/linkage
|
||||
switch (S.linkage)
|
||||
if (UNAFFECTED)
|
||||
linkage = "no linkage"
|
||||
if (SELFLOOPING)
|
||||
linkage = "self-looping"
|
||||
if (CROSSLINKED)
|
||||
linkage = "linked at ([S.xi], [S.yi])"
|
||||
linked_levels += S
|
||||
min_x = min(min_x, S.xi)
|
||||
min_y = min(min_y, S.yi)
|
||||
max_x = max(max_x, S.xi)
|
||||
max_y = max(max_y, S.yi)
|
||||
else
|
||||
linkage = "unknown linkage '[S.linkage]'"
|
||||
|
||||
messages += "<b>[z]</b>: [S.name], [linkage], traits: [json_encode(S.traits)]<br>"
|
||||
if (S.z_value != z)
|
||||
messages += "-- z_value is [S.z_value], should be [z]<br>"
|
||||
if (S.name == initial(S.name))
|
||||
messages += "-- name not set<br>"
|
||||
if (z > world.maxz)
|
||||
messages += "-- exceeds max z"
|
||||
|
||||
var/grid[max_x - min_x + 1][max_y - min_y + 1]
|
||||
for(var/datum/space_level/S in linked_levels)
|
||||
grid[S.xi - min_x + 1][S.yi - min_y + 1] = S.z_value
|
||||
|
||||
messages += "<table border='1'>"
|
||||
for(var/y in max_y to min_y step -1)
|
||||
var/list/part = list()
|
||||
for(var/x in min_x to max_x)
|
||||
part += "[grid[x - min_x + 1][y - min_y + 1]]"
|
||||
messages += "<tr><td>[part.Join("</td><td>")]</td></tr>"
|
||||
messages += "</table>"
|
||||
|
||||
to_chat(src, messages.Join(""))
|
||||
@@ -0,0 +1,644 @@
|
||||
GLOBAL_LIST_INIT(VVlocked, list("vars", "datum_flags", "client", "virus", "viruses", "cuffed", "last_eaten", "unlock_content", "force_ending"))
|
||||
GLOBAL_PROTECT(VVlocked)
|
||||
GLOBAL_LIST_INIT(VVicon_edit_lock, list("icon", "icon_state", "overlays", "underlays", "resize"))
|
||||
GLOBAL_PROTECT(VVicon_edit_lock)
|
||||
GLOBAL_LIST_INIT(VVckey_edit, list("key", "ckey"))
|
||||
GLOBAL_PROTECT(VVckey_edit)
|
||||
GLOBAL_LIST_INIT(VVpixelmovement, list("step_x", "step_y", "bound_height", "bound_width", "bound_x", "bound_y"))
|
||||
GLOBAL_PROTECT(VVpixelmovement)
|
||||
|
||||
|
||||
/client/proc/vv_get_class(var/var_name, var/var_value)
|
||||
if(isnull(var_value))
|
||||
. = VV_NULL
|
||||
|
||||
else if (isnum(var_value))
|
||||
if (var_name in GLOB.bitfields)
|
||||
. = VV_BITFIELD
|
||||
else
|
||||
. = VV_NUM
|
||||
|
||||
else if (istext(var_value))
|
||||
if (findtext(var_value, "\n"))
|
||||
. = VV_MESSAGE
|
||||
else
|
||||
. = VV_TEXT
|
||||
|
||||
else if (isicon(var_value))
|
||||
. = VV_ICON
|
||||
|
||||
else if (ismob(var_value))
|
||||
. = VV_MOB_REFERENCE
|
||||
|
||||
else if (isloc(var_value))
|
||||
. = VV_ATOM_REFERENCE
|
||||
|
||||
else if (istype(var_value, /client))
|
||||
. = VV_CLIENT
|
||||
|
||||
else if (istype(var_value, /datum))
|
||||
. = VV_DATUM_REFERENCE
|
||||
|
||||
else if (ispath(var_value))
|
||||
if (ispath(var_value, /atom))
|
||||
. = VV_ATOM_TYPE
|
||||
else if (ispath(var_value, /datum))
|
||||
. = VV_DATUM_TYPE
|
||||
else
|
||||
. = VV_TYPE
|
||||
|
||||
else if (islist(var_value))
|
||||
. = VV_LIST
|
||||
|
||||
else if (isfile(var_value))
|
||||
. = VV_FILE
|
||||
else
|
||||
. = VV_NULL
|
||||
|
||||
/client/proc/vv_get_value(class, default_class, current_value, list/restricted_classes, list/extra_classes, list/classes, var_name)
|
||||
. = list("class" = class, "value" = null)
|
||||
if (!class)
|
||||
if (!classes)
|
||||
classes = list (
|
||||
VV_NUM,
|
||||
VV_TEXT,
|
||||
VV_MESSAGE,
|
||||
VV_ICON,
|
||||
VV_ATOM_REFERENCE,
|
||||
VV_DATUM_REFERENCE,
|
||||
VV_MOB_REFERENCE,
|
||||
VV_CLIENT,
|
||||
VV_ATOM_TYPE,
|
||||
VV_DATUM_TYPE,
|
||||
VV_TYPE,
|
||||
VV_FILE,
|
||||
VV_NEW_ATOM,
|
||||
VV_NEW_DATUM,
|
||||
VV_NEW_TYPE,
|
||||
VV_NEW_LIST,
|
||||
VV_NULL,
|
||||
VV_RESTORE_DEFAULT
|
||||
)
|
||||
|
||||
if(holder && holder.marked_datum && !(VV_MARKED_DATUM in restricted_classes))
|
||||
classes += "[VV_MARKED_DATUM] ([holder.marked_datum.type])"
|
||||
if (restricted_classes)
|
||||
classes -= restricted_classes
|
||||
|
||||
if (extra_classes)
|
||||
classes += extra_classes
|
||||
|
||||
.["class"] = input(src, "What kind of data?", "Variable Type", default_class) as null|anything in classes
|
||||
if (holder && holder.marked_datum && .["class"] == "[VV_MARKED_DATUM] ([holder.marked_datum.type])")
|
||||
.["class"] = VV_MARKED_DATUM
|
||||
|
||||
|
||||
switch(.["class"])
|
||||
if (VV_TEXT)
|
||||
.["value"] = input("Enter new text:", "Text", current_value) as null|text
|
||||
if (.["value"] == null)
|
||||
.["class"] = null
|
||||
return
|
||||
if (VV_MESSAGE)
|
||||
.["value"] = input("Enter new text:", "Text", current_value) as null|message
|
||||
if (.["value"] == null)
|
||||
.["class"] = null
|
||||
return
|
||||
|
||||
|
||||
if (VV_NUM)
|
||||
.["value"] = input("Enter new number:", "Num", current_value) as null|num
|
||||
if (.["value"] == null)
|
||||
.["class"] = null
|
||||
return
|
||||
|
||||
if (VV_BITFIELD)
|
||||
.["value"] = input_bitfield(usr, "Editing bitfield: [var_name]", var_name, current_value)
|
||||
if (.["value"] == null)
|
||||
.["class"] = null
|
||||
return
|
||||
|
||||
if (VV_ATOM_TYPE)
|
||||
.["value"] = pick_closest_path(FALSE)
|
||||
if (.["value"] == null)
|
||||
.["class"] = null
|
||||
return
|
||||
|
||||
if (VV_DATUM_TYPE)
|
||||
.["value"] = pick_closest_path(FALSE, get_fancy_list_of_datum_types())
|
||||
if (.["value"] == null)
|
||||
.["class"] = null
|
||||
return
|
||||
|
||||
if (VV_TYPE)
|
||||
var/type = current_value
|
||||
var/error = ""
|
||||
do
|
||||
type = input("Enter type:[error]", "Type", type) as null|text
|
||||
if (!type)
|
||||
break
|
||||
type = text2path(type)
|
||||
error = "\nType not found, Please try again"
|
||||
while(!type)
|
||||
if (!type)
|
||||
.["class"] = null
|
||||
return
|
||||
.["value"] = type
|
||||
|
||||
|
||||
if (VV_ATOM_REFERENCE)
|
||||
var/type = pick_closest_path(FALSE)
|
||||
var/subtypes = vv_subtype_prompt(type)
|
||||
if (subtypes == null)
|
||||
.["class"] = null
|
||||
return
|
||||
var/list/things = vv_reference_list(type, subtypes)
|
||||
var/value = input("Select reference:", "Reference", current_value) as null|anything in things
|
||||
if (!value)
|
||||
.["class"] = null
|
||||
return
|
||||
.["value"] = things[value]
|
||||
|
||||
if (VV_DATUM_REFERENCE)
|
||||
var/type = pick_closest_path(FALSE, get_fancy_list_of_datum_types())
|
||||
var/subtypes = vv_subtype_prompt(type)
|
||||
if (subtypes == null)
|
||||
.["class"] = null
|
||||
return
|
||||
var/list/things = vv_reference_list(type, subtypes)
|
||||
var/value = input("Select reference:", "Reference", current_value) as null|anything in things
|
||||
if (!value)
|
||||
.["class"] = null
|
||||
return
|
||||
.["value"] = things[value]
|
||||
|
||||
if (VV_MOB_REFERENCE)
|
||||
var/type = pick_closest_path(FALSE, make_types_fancy(typesof(/mob)))
|
||||
var/subtypes = vv_subtype_prompt(type)
|
||||
if (subtypes == null)
|
||||
.["class"] = null
|
||||
return
|
||||
var/list/things = vv_reference_list(type, subtypes)
|
||||
var/value = input("Select reference:", "Reference", current_value) as null|anything in things
|
||||
if (!value)
|
||||
.["class"] = null
|
||||
return
|
||||
.["value"] = things[value]
|
||||
|
||||
|
||||
|
||||
if (VV_CLIENT)
|
||||
.["value"] = input("Select reference:", "Reference", current_value) as null|anything in GLOB.clients
|
||||
if (.["value"] == null)
|
||||
.["class"] = null
|
||||
return
|
||||
|
||||
|
||||
if (VV_FILE)
|
||||
.["value"] = input("Pick file:", "File") as null|file
|
||||
if (.["value"] == null)
|
||||
.["class"] = null
|
||||
return
|
||||
|
||||
|
||||
if (VV_ICON)
|
||||
.["value"] = input("Pick icon:", "Icon") as null|icon
|
||||
if (.["value"] == null)
|
||||
.["class"] = null
|
||||
return
|
||||
|
||||
|
||||
if (VV_MARKED_DATUM)
|
||||
.["value"] = holder.marked_datum
|
||||
if (.["value"] == null)
|
||||
.["class"] = null
|
||||
return
|
||||
|
||||
|
||||
if (VV_NEW_ATOM)
|
||||
var/type = pick_closest_path(FALSE)
|
||||
if (!type)
|
||||
.["class"] = null
|
||||
return
|
||||
.["type"] = type
|
||||
var/atom/newguy = new type()
|
||||
newguy.datum_flags |= DF_VAR_EDITED
|
||||
.["value"] = newguy
|
||||
|
||||
if (VV_NEW_DATUM)
|
||||
var/type = pick_closest_path(FALSE, get_fancy_list_of_datum_types())
|
||||
if (!type)
|
||||
.["class"] = null
|
||||
return
|
||||
.["type"] = type
|
||||
var/datum/newguy = new type()
|
||||
newguy.datum_flags |= DF_VAR_EDITED
|
||||
.["value"] = newguy
|
||||
|
||||
if (VV_NEW_TYPE)
|
||||
var/type = current_value
|
||||
var/error = ""
|
||||
do
|
||||
type = input("Enter type:[error]", "Type", type) as null|text
|
||||
if (!type)
|
||||
break
|
||||
type = text2path(type)
|
||||
error = "\nType not found, Please try again"
|
||||
while(!type)
|
||||
if (!type)
|
||||
.["class"] = null
|
||||
return
|
||||
.["type"] = type
|
||||
var/datum/newguy = new type()
|
||||
if(istype(newguy))
|
||||
newguy.datum_flags |= DF_VAR_EDITED
|
||||
.["value"] = newguy
|
||||
|
||||
|
||||
if (VV_NEW_LIST)
|
||||
.["value"] = list()
|
||||
.["type"] = /list
|
||||
|
||||
/client/proc/vv_parse_text(O, new_var)
|
||||
if(O && findtext(new_var,"\["))
|
||||
var/process_vars = alert(usr,"\[] detected in string, process as variables?","Process Variables?","Yes","No")
|
||||
if(process_vars == "Yes")
|
||||
. = string2listofvars(new_var, O)
|
||||
|
||||
//do they want you to include subtypes?
|
||||
//FALSE = no subtypes, strict exact type pathing (or the type doesn't have subtypes)
|
||||
//TRUE = Yes subtypes
|
||||
//NULL = User cancelled at the prompt or invalid type given
|
||||
/client/proc/vv_subtype_prompt(var/type)
|
||||
if (!ispath(type))
|
||||
return
|
||||
var/list/subtypes = subtypesof(type)
|
||||
if (!subtypes || !subtypes.len)
|
||||
return FALSE
|
||||
if (subtypes && subtypes.len)
|
||||
switch(alert("Strict object type detection?", "Type detection", "Strictly this type","This type and subtypes", "Cancel"))
|
||||
if("Strictly this type")
|
||||
return FALSE
|
||||
if("This type and subtypes")
|
||||
return TRUE
|
||||
else
|
||||
return
|
||||
|
||||
/client/proc/vv_reference_list(type, subtypes)
|
||||
. = list()
|
||||
var/list/types = list(type)
|
||||
if (subtypes)
|
||||
types = typesof(type)
|
||||
|
||||
var/list/fancytypes = make_types_fancy(types)
|
||||
|
||||
for(var/fancytype in fancytypes) //swap the assoication
|
||||
types[fancytypes[fancytype]] = fancytype
|
||||
|
||||
var/things = get_all_of_type(type, subtypes)
|
||||
|
||||
var/i = 0
|
||||
for(var/thing in things)
|
||||
var/datum/D = thing
|
||||
i++
|
||||
//try one of 3 methods to shorten the type text:
|
||||
// fancy type,
|
||||
// fancy type with the base type removed from the begaining,
|
||||
// the type with the base type removed from the begaining
|
||||
var/fancytype = types[D.type]
|
||||
if (findtext(fancytype, types[type]))
|
||||
fancytype = copytext(fancytype, length(types[type])+1)
|
||||
var/shorttype = copytext("[D.type]", length("[type]")+1)
|
||||
if (length(shorttype) > length(fancytype))
|
||||
shorttype = fancytype
|
||||
if (!length(shorttype))
|
||||
shorttype = "/"
|
||||
|
||||
.["[D]([shorttype])[REF(D)]#[i]"] = D
|
||||
|
||||
/client/proc/mod_list_add_ass(atom/O) //hehe
|
||||
|
||||
var/list/L = vv_get_value(restricted_classes = list(VV_RESTORE_DEFAULT))
|
||||
var/class = L["class"]
|
||||
if (!class)
|
||||
return
|
||||
var/var_value = L["value"]
|
||||
|
||||
if(class == VV_TEXT || class == VV_MESSAGE)
|
||||
var/list/varsvars = vv_parse_text(O, var_value)
|
||||
for(var/V in varsvars)
|
||||
var_value = replacetext(var_value,"\[[V]]","[O.vars[V]]")
|
||||
|
||||
return var_value
|
||||
|
||||
|
||||
/client/proc/mod_list_add(list/L, atom/O, original_name, objectvar)
|
||||
var/list/LL = vv_get_value(restricted_classes = list(VV_RESTORE_DEFAULT))
|
||||
var/class = LL["class"]
|
||||
if (!class)
|
||||
return
|
||||
var/var_value = LL["value"]
|
||||
|
||||
if(class == VV_TEXT || class == VV_MESSAGE)
|
||||
var/list/varsvars = vv_parse_text(O, var_value)
|
||||
for(var/V in varsvars)
|
||||
var_value = replacetext(var_value,"\[[V]]","[O.vars[V]]")
|
||||
|
||||
if (O)
|
||||
L = L.Copy()
|
||||
|
||||
L += var_value
|
||||
|
||||
switch(alert("Would you like to associate a value with the list entry?",,"Yes","No"))
|
||||
if("Yes")
|
||||
L[var_value] = mod_list_add_ass(O) //hehe
|
||||
if (O)
|
||||
if (O.vv_edit_var(objectvar, L) == FALSE)
|
||||
to_chat(src, "Your edit was rejected by the object.")
|
||||
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]")
|
||||
|
||||
/client/proc/mod_list(list/L, atom/O, original_name, objectvar, index, autodetect_class = FALSE)
|
||||
if(!check_rights(R_VAREDIT))
|
||||
return
|
||||
if(!istype(L, /list))
|
||||
to_chat(src, "Not a List.")
|
||||
return
|
||||
|
||||
if(L.len > 1000)
|
||||
var/confirm = alert(src, "The list you're trying to edit is very long, continuing may crash the server.", "Warning", "Continue", "Abort")
|
||||
if(confirm != "Continue")
|
||||
return
|
||||
|
||||
|
||||
|
||||
var/list/names = list()
|
||||
for (var/i in 1 to L.len)
|
||||
var/key = L[i]
|
||||
var/value
|
||||
if (IS_NORMAL_LIST(L) && !isnum(key))
|
||||
value = L[key]
|
||||
if (value == null)
|
||||
value = "null"
|
||||
names["#[i] [key] = [value]"] = i
|
||||
if (!index)
|
||||
var/variable = input("Which var?","Var") as null|anything in names + "(ADD VAR)" + "(CLEAR NULLS)" + "(CLEAR DUPES)" + "(SHUFFLE)"
|
||||
|
||||
if(variable == null)
|
||||
return
|
||||
|
||||
if(variable == "(ADD VAR)")
|
||||
mod_list_add(L, O, original_name, objectvar)
|
||||
return
|
||||
|
||||
if(variable == "(CLEAR NULLS)")
|
||||
L = L.Copy()
|
||||
listclearnulls(L)
|
||||
if (!O.vv_edit_var(objectvar, L))
|
||||
to_chat(src, "Your edit was rejected by the object.")
|
||||
return
|
||||
log_world("### ListVarEdit by [src]: [O.type] [objectvar]: CLEAR NULLS")
|
||||
log_admin("[key_name(src)] modified [original_name]'s [objectvar]: CLEAR NULLS")
|
||||
message_admins("[key_name_admin(src)] modified [original_name]'s list [objectvar]: CLEAR NULLS")
|
||||
return
|
||||
|
||||
if(variable == "(CLEAR DUPES)")
|
||||
L = uniqueList(L)
|
||||
if (!O.vv_edit_var(objectvar, L))
|
||||
to_chat(src, "Your edit was rejected by the object.")
|
||||
return
|
||||
log_world("### ListVarEdit by [src]: [O.type] [objectvar]: CLEAR DUPES")
|
||||
log_admin("[key_name(src)] modified [original_name]'s [objectvar]: CLEAR DUPES")
|
||||
message_admins("[key_name_admin(src)] modified [original_name]'s list [objectvar]: CLEAR DUPES")
|
||||
return
|
||||
|
||||
if(variable == "(SHUFFLE)")
|
||||
L = shuffle(L)
|
||||
if (!O.vv_edit_var(objectvar, L))
|
||||
to_chat(src, "Your edit was rejected by the object.")
|
||||
return
|
||||
log_world("### ListVarEdit by [src]: [O.type] [objectvar]: SHUFFLE")
|
||||
log_admin("[key_name(src)] modified [original_name]'s [objectvar]: SHUFFLE")
|
||||
message_admins("[key_name_admin(src)] modified [original_name]'s list [objectvar]: SHUFFLE")
|
||||
return
|
||||
|
||||
index = names[variable]
|
||||
|
||||
|
||||
var/assoc_key
|
||||
if (index == null)
|
||||
return
|
||||
var/assoc = 0
|
||||
var/prompt = alert(src, "Do you want to edit the key or its assigned value?", "Associated List", "Key", "Assigned Value", "Cancel")
|
||||
if (prompt == "Cancel")
|
||||
return
|
||||
if (prompt == "Assigned Value")
|
||||
assoc = 1
|
||||
assoc_key = L[index]
|
||||
var/default
|
||||
var/variable
|
||||
if (assoc)
|
||||
variable = L[assoc_key]
|
||||
else
|
||||
variable = L[index]
|
||||
|
||||
default = vv_get_class(objectvar, variable)
|
||||
|
||||
to_chat(src, "Variable appears to be <b>[uppertext(default)]</b>.")
|
||||
|
||||
to_chat(src, "Variable contains: [variable]")
|
||||
|
||||
if(default == VV_NUM)
|
||||
var/dir_text = ""
|
||||
var/tdir = variable
|
||||
if(tdir > 0 && tdir < 16)
|
||||
if(tdir & 1)
|
||||
dir_text += "NORTH"
|
||||
if(tdir & 2)
|
||||
dir_text += "SOUTH"
|
||||
if(tdir & 4)
|
||||
dir_text += "EAST"
|
||||
if(tdir & 8)
|
||||
dir_text += "WEST"
|
||||
|
||||
if(dir_text)
|
||||
to_chat(usr, "If a direction, direction is: [dir_text]")
|
||||
|
||||
var/original_var = variable
|
||||
|
||||
if (O)
|
||||
L = L.Copy()
|
||||
var/class
|
||||
if(autodetect_class)
|
||||
if (default == VV_TEXT)
|
||||
default = VV_MESSAGE
|
||||
class = default
|
||||
var/list/LL = vv_get_value(default_class = default, current_value = original_var, restricted_classes = list(VV_RESTORE_DEFAULT), extra_classes = list(VV_LIST, "DELETE FROM LIST"))
|
||||
class = LL["class"]
|
||||
if (!class)
|
||||
return
|
||||
var/new_var = LL["value"]
|
||||
|
||||
if(class == VV_MESSAGE)
|
||||
class = VV_TEXT
|
||||
|
||||
switch(class) //Spits a runtime error if you try to modify an entry in the contents list. Dunno how to fix it, yet.
|
||||
if(VV_LIST)
|
||||
mod_list(variable, O, original_name, objectvar)
|
||||
|
||||
if("DELETE FROM LIST")
|
||||
L.Cut(index, index+1)
|
||||
if (O)
|
||||
if (O.vv_edit_var(objectvar, L))
|
||||
to_chat(src, "Your edit was rejected by the object.")
|
||||
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]")
|
||||
return
|
||||
|
||||
if(VV_TEXT)
|
||||
var/list/varsvars = vv_parse_text(O, new_var)
|
||||
for(var/V in varsvars)
|
||||
new_var = replacetext(new_var,"\[[V]]","[O.vars[V]]")
|
||||
|
||||
|
||||
if(assoc)
|
||||
L[assoc_key] = new_var
|
||||
else
|
||||
L[index] = new_var
|
||||
if (O)
|
||||
if (O.vv_edit_var(objectvar, L) == FALSE)
|
||||
to_chat(src, "Your edit was rejected by the object.")
|
||||
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]")
|
||||
|
||||
/proc/vv_varname_lockcheck(param_var_name)
|
||||
if(param_var_name in GLOB.VVlocked)
|
||||
if(!check_rights(R_DEBUG))
|
||||
return FALSE
|
||||
if(param_var_name in GLOB.VVckey_edit)
|
||||
if(!check_rights(R_SPAWN|R_DEBUG))
|
||||
return FALSE
|
||||
if(param_var_name in GLOB.VVicon_edit_lock)
|
||||
if(!check_rights(R_FUN|R_DEBUG))
|
||||
return FALSE
|
||||
if(param_var_name in GLOB.VVpixelmovement)
|
||||
if(!check_rights(R_DEBUG))
|
||||
return FALSE
|
||||
var/prompt = alert(usr, "Editing this var may irreparably break tile gliding for the rest of the round. THIS CAN'T BE UNDONE", "DANGER", "ABORT ", "Continue", " ABORT")
|
||||
if (prompt != "Continue")
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
|
||||
/client/proc/modify_variables(atom/O, param_var_name = null, autodetect_class = 0)
|
||||
if(!check_rights(R_VAREDIT))
|
||||
return
|
||||
|
||||
var/class
|
||||
var/variable
|
||||
var/var_value
|
||||
|
||||
if(param_var_name)
|
||||
if(!(param_var_name in O.vars))
|
||||
to_chat(src, "A variable with this name ([param_var_name]) doesn't exist in this datum ([O])")
|
||||
return
|
||||
variable = param_var_name
|
||||
|
||||
else
|
||||
var/list/names = list()
|
||||
for (var/V in O.vars)
|
||||
names += V
|
||||
|
||||
names = sortList(names)
|
||||
|
||||
variable = input("Which var?","Var") as null|anything in names
|
||||
if(!variable)
|
||||
return
|
||||
|
||||
if(!O.can_vv_get(variable))
|
||||
return
|
||||
|
||||
var_value = O.vars[variable]
|
||||
if(!vv_varname_lockcheck(variable))
|
||||
return
|
||||
if(istype(O, /datum/armor))
|
||||
var/prompt = alert(src, "Editing this var changes this value on potentially thousands of items that share the same combination of armor values. If you want to edit the armor of just one item, use the \"Modify armor values\" dropdown item", "DANGER", "ABORT ", "Continue", " ABORT")
|
||||
if (prompt != "Continue")
|
||||
return
|
||||
|
||||
|
||||
var/default = vv_get_class(variable, var_value)
|
||||
|
||||
if(isnull(default))
|
||||
to_chat(src, "Unable to determine variable type.")
|
||||
else
|
||||
to_chat(src, "Variable appears to be <b>[uppertext(default)]</b>.")
|
||||
|
||||
to_chat(src, "Variable contains: [var_value]")
|
||||
|
||||
if(default == VV_NUM)
|
||||
var/dir_text = ""
|
||||
if(var_value > 0 && var_value < 16)
|
||||
if(var_value & 1)
|
||||
dir_text += "NORTH"
|
||||
if(var_value & 2)
|
||||
dir_text += "SOUTH"
|
||||
if(var_value & 4)
|
||||
dir_text += "EAST"
|
||||
if(var_value & 8)
|
||||
dir_text += "WEST"
|
||||
|
||||
if(dir_text)
|
||||
to_chat(src, "If a direction, direction is: [dir_text]")
|
||||
|
||||
if(autodetect_class && default != VV_NULL)
|
||||
if (default == VV_TEXT)
|
||||
default = VV_MESSAGE
|
||||
class = default
|
||||
|
||||
var/list/value = vv_get_value(class, default, var_value, extra_classes = list(VV_LIST), var_name = variable)
|
||||
class = value["class"]
|
||||
|
||||
if (!class)
|
||||
return
|
||||
var/var_new = value["value"]
|
||||
|
||||
if(class == VV_MESSAGE)
|
||||
class = VV_TEXT
|
||||
|
||||
var/original_name = "[O]"
|
||||
|
||||
switch(class)
|
||||
if(VV_LIST)
|
||||
if(!islist(var_value))
|
||||
mod_list(list(), O, original_name, variable)
|
||||
|
||||
mod_list(var_value, O, original_name, variable)
|
||||
return
|
||||
|
||||
if(VV_RESTORE_DEFAULT)
|
||||
var_new = initial(O.vars[variable])
|
||||
|
||||
if(VV_TEXT)
|
||||
var/list/varsvars = vv_parse_text(O, var_new)
|
||||
for(var/V in varsvars)
|
||||
var_new = replacetext(var_new,"\[[V]]","[O.vars[V]]")
|
||||
|
||||
|
||||
if (O.vv_edit_var(variable, var_new) == FALSE)
|
||||
to_chat(src, "Your edit was rejected by the object.")
|
||||
return
|
||||
vv_update_display(O, "varedited", VV_MSG_EDITED)
|
||||
SEND_GLOBAL_SIGNAL(COMSIG_GLOB_VAR_EDIT, args)
|
||||
log_world("### VarEdit by [key_name(src)]: [O.type] [variable]=[var_value] => [var_new]")
|
||||
log_admin("[key_name(src)] modified [original_name]'s [variable] from [html_encode("[var_value]")] to [html_encode("[var_new]")]")
|
||||
var/msg = "[key_name_admin(src)] modified [original_name]'s [variable] from [var_value] to [var_new]"
|
||||
message_admins(msg)
|
||||
admin_ticket_log(O, msg)
|
||||
return TRUE
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,70 @@
|
||||
/datum/admins/proc/spawn_objasmob(object as text)
|
||||
set category = "Debug"
|
||||
set desc = "(obj path) Spawn object-mob"
|
||||
set name = "Spawn object-mob"
|
||||
|
||||
if(!check_rights(R_SPAWN))
|
||||
return
|
||||
|
||||
var/chosen = pick_closest_path(object, make_types_fancy(subtypesof(/obj)))
|
||||
|
||||
if (!chosen)
|
||||
return
|
||||
|
||||
var/mob/living/simple_animal/hostile/mimic/copy/basemob = /mob/living/simple_animal/hostile/mimic/copy
|
||||
|
||||
var/obj/chosen_obj = text2path(chosen)
|
||||
|
||||
var/list/settings = list(
|
||||
"mainsettings" = list(
|
||||
"name" = list("desc" = "Name", "type" = "string", "value" = "Bob"),
|
||||
"maxhealth" = list("desc" = "Max. health", "type" = "number", "value" = 100),
|
||||
"access" = list("desc" = "Access ID", "type" = "datum", "path" = "/obj/item/card/id", "value" = "Default"),
|
||||
"objtype" = list("desc" = "Base obj type", "type" = "datum", "path" = "/obj", "value" = "[chosen]"),
|
||||
"googlyeyes" = list("desc" = "Googly eyes", "type" = "boolean", "value" = "No"),
|
||||
"disableai" = list("desc" = "Disable AI", "type" = "boolean", "value" = "Yes"),
|
||||
"idledamage" = list("desc" = "Damaged while idle", "type" = "boolean", "value" = "No"),
|
||||
"dropitem" = list("desc" = "Drop obj on death", "type" = "boolean", "value" = "Yes"),
|
||||
"mobtype" = list("desc" = "Base mob type", "type" = "datum", "path" = "/mob/living/simple_animal/hostile/mimic/copy", "value" = "/mob/living/simple_animal/hostile/mimic/copy"),
|
||||
"ckey" = list("desc" = "ckey", "type" = "ckey", "value" = "none"),
|
||||
)
|
||||
)
|
||||
|
||||
var/list/prefreturn = presentpreflikepicker(usr,"Customize mob", "Customize mob", Button1="Ok", width = 450, StealFocus = 1,Timeout = 0, settings=settings)
|
||||
if (prefreturn["button"] == 1)
|
||||
settings = prefreturn["settings"]
|
||||
var/mainsettings = settings["mainsettings"]
|
||||
chosen_obj = text2path(mainsettings["objtype"]["value"])
|
||||
|
||||
basemob = text2path(mainsettings["mobtype"]["value"])
|
||||
if (!ispath(basemob, /mob/living/simple_animal/hostile/mimic/copy) || !ispath(chosen_obj, /obj))
|
||||
to_chat(usr, "Mob or object path invalid")
|
||||
|
||||
basemob = new basemob(get_turf(usr), new chosen_obj(get_turf(usr)), usr, mainsettings["dropitem"]["value"] == "Yes" ? FALSE : TRUE, (mainsettings["googlyeyes"]["value"] == "Yes" ? FALSE : TRUE))
|
||||
|
||||
if (mainsettings["disableai"]["value"] == "Yes")
|
||||
basemob.toggle_ai(AI_OFF)
|
||||
|
||||
if (mainsettings["idledamage"]["value"] == "No")
|
||||
basemob.idledamage = FALSE
|
||||
|
||||
if (mainsettings["access"])
|
||||
var/newaccess = text2path(mainsettings["access"]["value"])
|
||||
if (ispath(newaccess))
|
||||
basemob.access_card = new newaccess
|
||||
|
||||
if (mainsettings["maxhealth"]["value"])
|
||||
if (!isnum(mainsettings["maxhealth"]["value"]))
|
||||
mainsettings["maxhealth"]["value"] = text2num(mainsettings["maxhealth"]["value"])
|
||||
if (mainsettings["maxhealth"]["value"] > 0)
|
||||
basemob.maxHealth = basemob.maxHealth = mainsettings["maxhealth"]["value"]
|
||||
|
||||
if (mainsettings["name"]["value"])
|
||||
basemob.name = basemob.real_name = html_decode(mainsettings["name"]["value"])
|
||||
|
||||
if (mainsettings["ckey"]["value"] != "none")
|
||||
basemob.ckey = mainsettings["ckey"]["value"]
|
||||
|
||||
|
||||
log_admin("[key_name(usr)] spawned a sentient object-mob [basemob] from [chosen_obj] at [AREACOORD(usr)]")
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Spawn object-mob") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
Reference in New Issue
Block a user