You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

980 lines
52 KiB

  1. ////////////////////////////////
  2. /proc/message_admins(msg)
  3. msg = "<span class=\"admin\"><span class=\"prefix\">ADMIN LOG:</span> <span class=\"message linkify\">[msg]</span></span>"
  4. to_chat(GLOB.admins, msg, confidential = TRUE)
  5. /proc/relay_msg_admins(msg)
  6. msg = "<span class=\"admin\"><span class=\"prefix\">RELAY:</span> <span class=\"message linkify\">[msg]</span></span>"
  7. to_chat(GLOB.admins, msg, confidential = TRUE)
  8. ///////////////////////////////////////////////////////////////////////////////////////////////Panels
  9. /datum/admins/proc/show_player_panel(mob/M in GLOB.mob_list)
  10. set category = "Admin - Game"
  11. set name = "Show Player Panel"
  12. set desc="Edit player (respawn, ban, heal, etc)"
  13. if(!check_rights())
  14. return
  15. log_admin("[key_name(usr)] checked the individual player panel for [key_name(M)][isobserver(usr)?"":" while in game"].")
  16. if(!M)
  17. to_chat(usr, "<span class='warning'>You seem to be selecting a mob that doesn't exist anymore.</span>", confidential = TRUE)
  18. return
  19. var/body = "<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8'><title>Options for [M.key]</title></head>"
  20. body += "<body>Options panel for <b>[M]</b>"
  21. if(M.client)
  22. body += " played by <b>[M.client]</b> "
  23. 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>\]"
  24. if(CONFIG_GET(flag/use_exp_tracking))
  25. body += "\[<A href='?_src_=holder;[HrefToken()];getplaytimewindow=[REF(M)]'>" + M.client.get_exp_living(FALSE) + "</a>\]"
  26. if(isnewplayer(M))
  27. body += " <B>Hasn't Entered Game</B> "
  28. else
  29. body += " \[<A href='?_src_=holder;[HrefToken()];revive=[REF(M)]'>Heal</A>\] "
  30. if(M.client)
  31. body += "<br>\[<b>First Seen:</b> [M.client.player_join_date]\]\[<b>Byond account registered on:</b> [M.client.account_join_date]\]"
  32. body += "<br><br><b>Show related accounts by:</b> "
  33. body += "\[ <a href='?_src_=holder;[HrefToken()];showrelatedacc=cid;client=[REF(M.client)]'>CID</a> | "
  34. body += "<a href='?_src_=holder;[HrefToken()];showrelatedacc=ip;client=[REF(M.client)]'>IP</a> \]"
  35. var/rep = 0
  36. rep += SSpersistence.antag_rep[M.ckey]
  37. body += "<br><br>Antagonist reputation: [rep]"
  38. body += "<br><a href='?_src_=holder;[HrefToken()];modantagrep=add;mob=[REF(M)]'>\[increase\]</a> "
  39. body += "<a href='?_src_=holder;[HrefToken()];modantagrep=subtract;mob=[REF(M)]'>\[decrease\]</a> "
  40. body += "<a href='?_src_=holder;[HrefToken()];modantagrep=set;mob=[REF(M)]'>\[set\]</a> "
  41. body += "<a href='?_src_=holder;[HrefToken()];modantagrep=zero;mob=[REF(M)]'>\[zero\]</a>"
  42. var/full_version = "Unknown"
  43. if(M.client.byond_version)
  44. full_version = "[M.client.byond_version].[M.client.byond_build ? M.client.byond_build : "xxx"]"
  45. body += "<br>\[<b>Byond version:</b> [full_version]\]<br>"
  46. body += "<br><br>\[ "
  47. body += "<a href='?_src_=vars;[HrefToken()];Vars=[REF(M)]'>VV</a> - "
  48. if(M.mind)
  49. body += "<a href='?_src_=holder;[HrefToken()];traitor=[REF(M)]'>TP</a> - "
  50. else
  51. body += "<a href='?_src_=holder;[HrefToken()];initmind=[REF(M)]'>Init Mind</a> - "
  52. if (iscyborg(M))
  53. body += "<a href='?_src_=holder;[HrefToken()];borgpanel=[REF(M)]'>BP</a> - "
  54. body += "<a href='?priv_msg=[M.ckey]'>PM</a> - "
  55. body += "<a href='?_src_=holder;[HrefToken()];subtlemessage=[REF(M)]'>SM</a> - "
  56. if (ishuman(M) && M.mind)
  57. body += "<a href='?_src_=holder;[HrefToken()];HeadsetMessage=[REF(M)]'>HM</a> - "
  58. body += "<a href='?_src_=holder;[HrefToken()];adminplayerobservefollow=[REF(M)]'>FLW</a> - "
  59. //Default to client logs if available
  60. var/source = LOGSRC_MOB
  61. if(M.client)
  62. source = LOGSRC_CLIENT
  63. body += "<a href='?_src_=holder;[HrefToken()];individuallog=[REF(M)];log_src=[source]'>LOGS</a>\] <br>"
  64. body += "<b>Mob type</b> = [M.type]<br><br>"
  65. body += "<A href='?_src_=holder;[HrefToken()];boot2=[REF(M)]'>Kick</A> | "
  66. if(M.client)
  67. body += "<A href='?_src_=holder;[HrefToken()];newbankey=[M.key];newbanip=[M.client.address];newbancid=[M.client.computer_id]'>Ban</A> | "
  68. else
  69. body += "<A href='?_src_=holder;[HrefToken()];newbankey=[M.key]'>Ban</A> | "
  70. body += "<A href='?_src_=holder;[HrefToken()];showmessageckey=[M.ckey]'>Notes | Messages | Watchlist</A> | "
  71. if(M.client)
  72. body += "| <A href='?_src_=holder;[HrefToken()];sendtoprison=[REF(M)]'>Prison</A> | "
  73. body += "\ <A href='?_src_=holder;[HrefToken()];sendbacktolobby=[REF(M)]'>Send back to Lobby</A> | "
  74. var/muted = M.client.prefs.muted
  75. body += "<br><b>Mute: </b> "
  76. body += "\[<A href='?_src_=holder;[HrefToken()];mute=[M.ckey];mute_type=[MUTE_IC]'><font color='[(muted & MUTE_IC)?"red":"blue"]'>IC</font></a> | "
  77. body += "<A href='?_src_=holder;[HrefToken()];mute=[M.ckey];mute_type=[MUTE_OOC]'><font color='[(muted & MUTE_OOC)?"red":"blue"]'>OOC</font></a> | "
  78. body += "<A href='?_src_=holder;[HrefToken()];mute=[M.ckey];mute_type=[MUTE_PRAY]'><font color='[(muted & MUTE_PRAY)?"red":"blue"]'>PRAY</font></a> | "
  79. body += "<A href='?_src_=holder;[HrefToken()];mute=[M.ckey];mute_type=[MUTE_ADMINHELP]'><font color='[(muted & MUTE_ADMINHELP)?"red":"blue"]'>ADMINHELP</font></a> | "
  80. body += "<A href='?_src_=holder;[HrefToken()];mute=[M.ckey];mute_type=[MUTE_DEADCHAT]'><font color='[(muted & MUTE_DEADCHAT)?"red":"blue"]'>DEADCHAT</font></a>\]"
  81. body += "(<A href='?_src_=holder;[HrefToken()];mute=[M.ckey];mute_type=[MUTE_ALL]'><font color='[(muted & MUTE_ALL)?"red":"blue"]'>toggle all</font></a>)"
  82. body += "<br><br>"
  83. body += "<A href='?_src_=holder;[HrefToken()];jumpto=[REF(M)]'><b>Jump to</b></A> | "
  84. body += "<A href='?_src_=holder;[HrefToken()];getmob=[REF(M)]'>Get</A> | "
  85. body += "<A href='?_src_=holder;[HrefToken()];sendmob=[REF(M)]'>Send To</A>"
  86. body += "<br><br>"
  87. body += "<A href='?_src_=holder;[HrefToken()];traitor=[REF(M)]'>Traitor panel</A> | "
  88. body += "<A href='?_src_=holder;[HrefToken()];narrateto=[REF(M)]'>Narrate to</A> | "
  89. body += "<A href='?_src_=holder;[HrefToken()];subtlemessage=[REF(M)]'>Subtle message</A> | "
  90. body += "<A href='?_src_=holder;[HrefToken()];playsoundto=[REF(M)]'>Play sound to</A> | "
  91. body += "<A href='?_src_=holder;[HrefToken()];languagemenu=[REF(M)]'>Language Menu</A>"
  92. if (M.client)
  93. if(!isnewplayer(M))
  94. body += "<br><br>"
  95. body += "<b>Transformation:</b>"
  96. body += "<br>"
  97. //Human
  98. if(ishuman(M))
  99. body += "<B>Human</B> | "
  100. else
  101. body += "<A href='?_src_=holder;[HrefToken()];humanone=[REF(M)]'>Humanize</A> | "
  102. //Monkey
  103. if(ismonkey(M))
  104. body += "<B>Monkeyized</B> | "
  105. else
  106. body += "<A href='?_src_=holder;[HrefToken()];monkeyone=[REF(M)]'>Monkeyize</A> | "
  107. //Corgi
  108. if(iscorgi(M))
  109. body += "<B>Corgized</B> | "
  110. else
  111. body += "<A href='?_src_=holder;[HrefToken()];corgione=[REF(M)]'>Corgize</A> | "
  112. //AI / Cyborg
  113. if(isAI(M))
  114. body += "<B>Is an AI</B> "
  115. else if(ishuman(M))
  116. body += "<A href='?_src_=holder;[HrefToken()];makeai=[REF(M)]'>Make AI</A> | "
  117. body += "<A href='?_src_=holder;[HrefToken()];makerobot=[REF(M)]'>Make Robot</A> | "
  118. body += "<A href='?_src_=holder;[HrefToken()];makealien=[REF(M)]'>Make Alien</A> | "
  119. body += "<A href='?_src_=holder;[HrefToken()];makeslime=[REF(M)]'>Make Slime</A> | "
  120. body += "<A href='?_src_=holder;[HrefToken()];makeblob=[REF(M)]'>Make Blob</A> | "
  121. //Simple Animals
  122. if(isanimal(M))
  123. body += "<A href='?_src_=holder;[HrefToken()];makeanimal=[REF(M)]'>Re-Animalize</A> | "
  124. else
  125. body += "<A href='?_src_=holder;[HrefToken()];makeanimal=[REF(M)]'>Animalize</A> | "
  126. body += "<br><br>"
  127. 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>"
  128. body += "<A href='?_src_=holder;[HrefToken()];simplemake=observer;mob=[REF(M)]'>Observer</A> | "
  129. body += "\[ Alien: <A href='?_src_=holder;[HrefToken()];simplemake=drone;mob=[REF(M)]'>Drone</A>, "
  130. body += "<A href='?_src_=holder;[HrefToken()];simplemake=hunter;mob=[REF(M)]'>Hunter</A>, "
  131. body += "<A href='?_src_=holder;[HrefToken()];simplemake=sentinel;mob=[REF(M)]'>Sentinel</A>, "
  132. body += "<A href='?_src_=holder;[HrefToken()];simplemake=praetorian;mob=[REF(M)]'>Praetorian</A>, "
  133. body += "<A href='?_src_=holder;[HrefToken()];simplemake=queen;mob=[REF(M)]'>Queen</A>, "
  134. body += "<A href='?_src_=holder;[HrefToken()];simplemake=larva;mob=[REF(M)]'>Larva</A> \] "
  135. body += "<A href='?_src_=holder;[HrefToken()];simplemake=human;mob=[REF(M)]'>Human</A> "
  136. body += "\[ slime: <A href='?_src_=holder;[HrefToken()];simplemake=slime;mob=[REF(M)]'>Baby</A>, "
  137. body += "<A href='?_src_=holder;[HrefToken()];simplemake=adultslime;mob=[REF(M)]'>Adult</A> \] "
  138. body += "<A href='?_src_=holder;[HrefToken()];simplemake=monkey;mob=[REF(M)]'>Monkey</A> | "
  139. body += "<A href='?_src_=holder;[HrefToken()];simplemake=robot;mob=[REF(M)]'>Cyborg</A> | "
  140. body += "<A href='?_src_=holder;[HrefToken()];simplemake=cat;mob=[REF(M)]'>Cat</A> | "
  141. body += "<A href='?_src_=holder;[HrefToken()];simplemake=runtime;mob=[REF(M)]'>Runtime</A> | "
  142. body += "<A href='?_src_=holder;[HrefToken()];simplemake=corgi;mob=[REF(M)]'>Corgi</A> | "
  143. body += "<A href='?_src_=holder;[HrefToken()];simplemake=ian;mob=[REF(M)]'>Ian</A> | "
  144. body += "<A href='?_src_=holder;[HrefToken()];simplemake=crab;mob=[REF(M)]'>Crab</A> | "
  145. body += "<A href='?_src_=holder;[HrefToken()];simplemake=coffee;mob=[REF(M)]'>Coffee</A> | "
  146. body += "\[ Construct: <A href='?_src_=holder;[HrefToken()];simplemake=constructarmored;mob=[REF(M)]'>Juggernaut</A> , "
  147. body += "<A href='?_src_=holder;[HrefToken()];simplemake=constructbuilder;mob=[REF(M)]'>Artificer</A> , "
  148. body += "<A href='?_src_=holder;[HrefToken()];simplemake=constructwraith;mob=[REF(M)]'>Wraith</A> \] "
  149. body += "<A href='?_src_=holder;[HrefToken()];simplemake=shade;mob=[REF(M)]'>Shade</A>"
  150. body += "<br>"
  151. if (M.client)
  152. body += "<br><br>"
  153. body += "<b>Other actions:</b>"
  154. body += "<br>"
  155. body += "<A href='?_src_=holder;[HrefToken()];forcespeech=[REF(M)]'>Forcesay</A> | "
  156. body += "<A href='?_src_=holder;[HrefToken()];tdome1=[REF(M)]'>Thunderdome 1</A> | "
  157. body += "<A href='?_src_=holder;[HrefToken()];tdome2=[REF(M)]'>Thunderdome 2</A> | "
  158. body += "<A href='?_src_=holder;[HrefToken()];tdomeadmin=[REF(M)]'>Thunderdome Admin</A> | "
  159. body += "<A href='?_src_=holder;[HrefToken()];tdomeobserve=[REF(M)]'>Thunderdome Observer</A> | "
  160. body += "<br>"
  161. body += "</body></html>"
  162. usr << browse(body, "window=adminplayeropts-[REF(M)];size=550x515")
  163. 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!
  164. /datum/admins/proc/access_news_network() //MARKER
  165. set category = "Admin - Events"
  166. set name = "Access Newscaster Network"
  167. set desc = "Allows you to view, add and edit news feeds."
  168. if (!istype(src, /datum/admins))
  169. src = usr.client.holder
  170. if (!istype(src, /datum/admins))
  171. to_chat(usr, "Error: you are not an admin!", confidential = TRUE)
  172. return
  173. var/dat
  174. dat = text("<HEAD><TITLE>Admin Newscaster</TITLE></HEAD><H3>Admin Newscaster Unit</H3>")
  175. switch(admincaster_screen)
  176. if(0)
  177. dat += "Welcome to the admin newscaster.<BR> Here you can add, edit and censor every newspiece on the network."
  178. dat += "<BR>Feed channels and stories entered through here will be uneditable and handled as official news by the rest of the units."
  179. 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>"
  180. if(GLOB.news_network.wanted_issue.active)
  181. dat+= "<HR><A href='?src=[REF(src)];[HrefToken()];ac_view_wanted=1'>Read Wanted Issue</A>"
  182. dat+= "<HR><BR><A href='?src=[REF(src)];[HrefToken()];ac_create_channel=1'>Create Feed Channel</A>"
  183. dat+= "<BR><A href='?src=[REF(src)];[HrefToken()];ac_view=1'>View Feed Channels</A>"
  184. dat+= "<BR><A href='?src=[REF(src)];[HrefToken()];ac_create_feed_story=1'>Submit new Feed story</A>"
  185. dat+= "<BR><BR><A href='?src=[REF(usr)];[HrefToken()];mach_close=newscaster_main'>Exit</A>"
  186. var/wanted_already = 0
  187. if(GLOB.news_network.wanted_issue.active)
  188. wanted_already = 1
  189. dat+="<HR><B>Feed Security functions:</B><BR>"
  190. dat+="<BR><A href='?src=[REF(src)];[HrefToken()];ac_menu_wanted=1'>[(wanted_already) ? ("Manage") : ("Publish")] \"Wanted\" Issue</A>"
  191. dat+="<BR><A href='?src=[REF(src)];[HrefToken()];ac_menu_censor_story=1'>Censor Feed Stories</A>"
  192. 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>"
  193. 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>"
  194. if(1)
  195. dat+= "Station Feed Channels<HR>"
  196. if( !length(GLOB.news_network.network_channels) )
  197. dat+="<I>No active channels found...</I>"
  198. else
  199. for(var/datum/newscaster/feed_channel/CHANNEL in GLOB.news_network.network_channels)
  200. if(CHANNEL.is_admin_channel)
  201. dat+="<B><FONT style='BACKGROUND-COLOR: LightGreen'><A href='?src=[REF(src)];ac_show_channel=[REF(CHANNEL)]'>[CHANNEL.channel_name]</A></FONT></B><BR>"
  202. else
  203. 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>"
  204. dat+="<BR><HR><A href='?src=[REF(src)];[HrefToken()];ac_refresh=1'>Refresh</A>"
  205. dat+="<BR><A href='?src=[REF(src)];[HrefToken()];ac_setScreen=[0]'>Back</A>"
  206. if(2)
  207. dat+="Creating new Feed Channel..."
  208. 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>"
  209. dat+="<B><A href='?src=[REF(src)];[HrefToken()];ac_set_signature=1'>Channel Author</A>:</B> <FONT COLOR='green'>[src.admin_signature]</FONT><BR>"
  210. 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>"
  211. 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>"
  212. if(3)
  213. dat+="Creating new Feed Message..."
  214. 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
  215. dat+="<B>Message Author:</B> <FONT COLOR='green'>[src.admin_signature]</FONT><BR>"
  216. dat+="<B><A href='?src=[REF(src)];[HrefToken()];ac_set_new_message=1'>Message Body</A>:</B> [src.admincaster_feed_message.returnBody(-1)] <BR>"
  217. 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>"
  218. if(4)
  219. dat+="Feed story successfully submitted to [src.admincaster_feed_channel.channel_name].<BR><BR>"
  220. dat+="<BR><A href='?src=[REF(src)];[HrefToken()];ac_setScreen=[0]'>Return</A><BR>"
  221. if(5)
  222. dat+="Feed Channel [src.admincaster_feed_channel.channel_name] created successfully.<BR><BR>"
  223. dat+="<BR><A href='?src=[REF(src)];[HrefToken()];ac_setScreen=[0]'>Return</A><BR>"
  224. if(6)
  225. dat+="<B><FONT COLOR='maroon'>ERROR: Could not submit Feed story to Network.</B></FONT><HR><BR>"
  226. if(src.admincaster_feed_channel.channel_name=="")
  227. dat+="<FONT COLOR='maroon'>•Invalid receiving channel name.</FONT><BR>"
  228. if(src.admincaster_feed_message.returnBody(-1) == "" || src.admincaster_feed_message.returnBody(-1) == "\[REDACTED\]")
  229. dat+="<FONT COLOR='maroon'>•Invalid message body.</FONT><BR>"
  230. dat+="<BR><A href='?src=[REF(src)];[HrefToken()];ac_setScreen=[3]'>Return</A><BR>"
  231. if(7)
  232. dat+="<B><FONT COLOR='maroon'>ERROR: Could not submit Feed Channel to Network.</B></FONT><HR><BR>"
  233. if(src.admincaster_feed_channel.channel_name =="" || src.admincaster_feed_channel.channel_name == "\[REDACTED\]")
  234. dat+="<FONT COLOR='maroon'>•Invalid channel name.</FONT><BR>"
  235. var/check = 0
  236. for(var/datum/newscaster/feed_channel/FC in GLOB.news_network.network_channels)
  237. if(FC.channel_name == src.admincaster_feed_channel.channel_name)
  238. check = 1
  239. break
  240. if(check)
  241. dat+="<FONT COLOR='maroon'>•Channel name already in use.</FONT><BR>"
  242. dat+="<BR><A href='?src=[REF(src)];[HrefToken()];ac_setScreen=[2]'>Return</A><BR>"
  243. if(9)
  244. dat+="<B>[admincaster_feed_channel.channel_name]: </B><FONT SIZE=1>\[created by: <FONT COLOR='maroon'>[admincaster_feed_channel.returnAuthor(-1)]</FONT>\]</FONT><HR>"
  245. if(src.admincaster_feed_channel.censored)
  246. 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>"
  247. dat+="No further feed story additions are allowed while the D-Notice is in effect.</FONT><BR><BR>"
  248. else
  249. if( !length(src.admincaster_feed_channel.messages) )
  250. dat+="<I>No feed messages found in channel...</I><BR>"
  251. else
  252. var/i = 0
  253. for(var/datum/newscaster/feed_message/MESSAGE in src.admincaster_feed_channel.messages)
  254. i++
  255. dat+="-[MESSAGE.returnBody(-1)] <BR>"
  256. if(MESSAGE.img)
  257. usr << browse_rsc(MESSAGE.img, "tmp_photo[i].png")
  258. dat+="<img src='tmp_photo[i].png' width = '180'><BR><BR>"
  259. dat+="<FONT SIZE=1>\[Story by <FONT COLOR='maroon'>[MESSAGE.returnAuthor(-1)]</FONT>\]</FONT><BR>"
  260. dat+="[MESSAGE.comments.len] comment[MESSAGE.comments.len > 1 ? "s" : ""]:<br>"
  261. for(var/datum/newscaster/feed_comment/comment in MESSAGE.comments)
  262. dat+="[comment.body]<br><font size=1>[comment.author] [comment.time_stamp]</font><br>"
  263. dat+="<br>"
  264. dat+="<BR><HR><A href='?src=[REF(src)];[HrefToken()];ac_refresh=1'>Refresh</A>"
  265. dat+="<BR><A href='?src=[REF(src)];[HrefToken()];ac_setScreen=[1]'>Back</A>"
  266. if(10)
  267. dat+="<B>Nanotrasen Feed Censorship Tool</B><BR>"
  268. dat+="<FONT SIZE=1>NOTE: Due to the nature of news Feeds, total deletion of a Feed Story is not possible.<BR>"
  269. dat+="Keep in mind that users attempting to view a censored feed will instead see the \[REDACTED\] tag above it.</FONT>"
  270. dat+="<HR>Select Feed channel to get Stories from:<BR>"
  271. if(!length(GLOB.news_network.network_channels))
  272. dat+="<I>No feed channels found active...</I><BR>"
  273. else
  274. for(var/datum/newscaster/feed_channel/CHANNEL in GLOB.news_network.network_channels)
  275. dat+="<A href='?src=[REF(src)];[HrefToken()];ac_pick_censor_channel=[REF(CHANNEL)]'>[CHANNEL.channel_name]</A> [(CHANNEL.censored) ? ("<FONT COLOR='red'>***</FONT>") : ""]<BR>"
  276. dat+="<BR><A href='?src=[REF(src)];[HrefToken()];ac_setScreen=[0]'>Cancel</A>"
  277. if(11)
  278. dat+="<B>Nanotrasen D-Notice Handler</B><HR>"
  279. 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"
  280. dat+="morale, integrity or disciplinary behaviour. A D-Notice will render a channel unable to be updated by anyone, without deleting any feed"
  281. 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>"
  282. if(!length(GLOB.news_network.network_channels))
  283. dat+="<I>No feed channels found active...</I><BR>"
  284. else
  285. for(var/datum/newscaster/feed_channel/CHANNEL in GLOB.news_network.network_channels)
  286. dat+="<A href='?src=[REF(src)];[HrefToken()];ac_pick_d_notice=[REF(CHANNEL)]'>[CHANNEL.channel_name]</A> [(CHANNEL.censored) ? ("<FONT COLOR='red'>***</FONT>") : ""]<BR>"
  287. dat+="<BR><A href='?src=[REF(src)];[HrefToken()];ac_setScreen=[0]'>Back</A>"
  288. if(12)
  289. 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>"
  290. 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>"
  291. if( !length(src.admincaster_feed_channel.messages) )
  292. dat+="<I>No feed messages found in channel...</I><BR>"
  293. else
  294. for(var/datum/newscaster/feed_message/MESSAGE in src.admincaster_feed_channel.messages)
  295. dat+="-[MESSAGE.returnBody(-1)] <BR><FONT SIZE=1>\[Story by <FONT COLOR='maroon'>[MESSAGE.returnAuthor(-1)]</FONT>\]</FONT><BR>"
  296. 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>"
  297. 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>"
  298. for(var/datum/newscaster/feed_comment/comment in MESSAGE.comments)
  299. 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>"
  300. dat+="<BR><A href='?src=[REF(src)];[HrefToken()];ac_setScreen=[10]'>Back</A>"
  301. if(13)
  302. 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>"
  303. 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>"
  304. if(src.admincaster_feed_channel.censored)
  305. 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>"
  306. dat+="No further feed story additions are allowed while the D-Notice is in effect.</FONT><BR><BR>"
  307. else
  308. if( !length(src.admincaster_feed_channel.messages) )
  309. dat+="<I>No feed messages found in channel...</I><BR>"
  310. else
  311. for(var/datum/newscaster/feed_message/MESSAGE in src.admincaster_feed_channel.messages)
  312. dat+="-[MESSAGE.returnBody(-1)] <BR><FONT SIZE=1>\[Story by <FONT COLOR='maroon'>[MESSAGE.returnAuthor(-1)]</FONT>\]</FONT><BR>"
  313. dat+="<BR><A href='?src=[REF(src)];[HrefToken()];ac_setScreen=[11]'>Back</A>"
  314. if(14)
  315. dat+="<B>Wanted Issue Handler:</B>"
  316. var/wanted_already = 0
  317. var/end_param = 1
  318. if(GLOB.news_network.wanted_issue.active)
  319. wanted_already = 1
  320. end_param = 2
  321. if(wanted_already)
  322. dat+="<FONT SIZE=2><BR><I>A wanted issue is already in Feed Circulation. You can edit or cancel it below.</FONT></I>"
  323. dat+="<HR>"
  324. dat+="<A href='?src=[REF(src)];[HrefToken()];ac_set_wanted_name=1'>Criminal Name</A>: [src.admincaster_wanted_message.criminal] <BR>"
  325. dat+="<A href='?src=[REF(src)];[HrefToken()];ac_set_wanted_desc=1'>Description</A>: [src.admincaster_wanted_message.body] <BR>"
  326. if(wanted_already)
  327. dat+="<B>Wanted Issue created by:</B><FONT COLOR='green'>[GLOB.news_network.wanted_issue.scannedUser]</FONT><BR>"
  328. else
  329. dat+="<B>Wanted Issue will be created under prosecutor:</B><FONT COLOR='green'>[src.admin_signature]</FONT><BR>"
  330. dat+="<BR><A href='?src=[REF(src)];[HrefToken()];ac_submit_wanted=[end_param]'>[(wanted_already) ? ("Edit Issue") : ("Submit")]</A>"
  331. if(wanted_already)
  332. dat+="<BR><A href='?src=[REF(src)];[HrefToken()];ac_cancel_wanted=1'>Take down Issue</A>"
  333. dat+="<BR><A href='?src=[REF(src)];[HrefToken()];ac_setScreen=[0]'>Cancel</A>"
  334. if(15)
  335. dat+="<FONT COLOR='green'>Wanted issue for [src.admincaster_wanted_message.criminal] is now in Network Circulation.</FONT><BR><BR>"
  336. dat+="<BR><A href='?src=[REF(src)];[HrefToken()];ac_setScreen=[0]'>Return</A><BR>"
  337. if(16)
  338. dat+="<B><FONT COLOR='maroon'>ERROR: Wanted Issue rejected by Network.</B></FONT><HR><BR>"
  339. if(src.admincaster_wanted_message.criminal =="" || src.admincaster_wanted_message.criminal == "\[REDACTED\]")
  340. dat+="<FONT COLOR='maroon'>•Invalid name for person wanted.</FONT><BR>"
  341. if(src.admincaster_wanted_message.body == "" || src.admincaster_wanted_message.body == "\[REDACTED\]")
  342. dat+="<FONT COLOR='maroon'>•Invalid description.</FONT><BR>"
  343. dat+="<BR><A href='?src=[REF(src)];[HrefToken()];ac_setScreen=[0]'>Return</A><BR>"
  344. if(17)
  345. dat+="<B>Wanted Issue successfully deleted from Circulation</B><BR>"
  346. dat+="<BR><A href='?src=[REF(src)];[HrefToken()];ac_setScreen=[0]'>Return</A><BR>"
  347. if(18)
  348. 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>"
  349. dat+="<B>Criminal</B>: [GLOB.news_network.wanted_issue.criminal]<BR>"
  350. dat+="<B>Description</B>: [GLOB.news_network.wanted_issue.body]<BR>"
  351. dat+="<B>Photo:</B>: "
  352. if(GLOB.news_network.wanted_issue.img)
  353. usr << browse_rsc(GLOB.news_network.wanted_issue.img, "tmp_photow.png")
  354. dat+="<BR><img src='tmp_photow.png' width = '180'>"
  355. else
  356. dat+="None"
  357. dat+="<BR><A href='?src=[REF(src)];[HrefToken()];ac_setScreen=[0]'>Back</A><BR>"
  358. if(19)
  359. dat+="<FONT COLOR='green'>Wanted issue for [src.admincaster_wanted_message.criminal] successfully edited.</FONT><BR><BR>"
  360. dat+="<BR><A href='?src=[REF(src)];[HrefToken()];ac_setScreen=[0]'>Return</A><BR>"
  361. else
  362. dat+="I'm sorry to break your immersion. This shit's bugged. Report this bug to Agouri, polyxenitopalidou@gmail.com"
  363. usr << browse(dat, "window=admincaster_main;size=400x600")
  364. onclose(usr, "admincaster_main")
  365. /datum/admins/proc/Game()
  366. if(!check_rights(0))
  367. return
  368. var/dat = {"
  369. <center><B>Game Panel</B></center><hr>\n
  370. <A href='?src=[REF(src)];[HrefToken()];c_mode=1'>Change Game Mode</A><br>
  371. "}
  372. if(GLOB.master_mode == "secret")
  373. dat += "<A href='?src=[REF(src)];[HrefToken()];f_secret=1'>(Force Secret Mode)</A><br>"
  374. if(GLOB.master_mode == "dynamic")
  375. if(SSticker.current_state <= GAME_STATE_PREGAME)
  376. dat += "<A href='?src=[REF(src)];[HrefToken()];f_dynamic_roundstart=1'>(Force Roundstart Rulesets)</A><br>"
  377. if (GLOB.dynamic_forced_roundstart_ruleset.len > 0)
  378. for(var/datum/dynamic_ruleset/roundstart/rule in GLOB.dynamic_forced_roundstart_ruleset)
  379. dat += {"<A href='?src=[REF(src)];[HrefToken()];f_dynamic_roundstart_remove=\ref[rule]'>-> [rule.name] <-</A><br>"}
  380. dat += "<A href='?src=[REF(src)];[HrefToken()];f_dynamic_roundstart_clear=1'>(Clear Rulesets)</A><br>"
  381. dat += "<A href='?src=[REF(src)];[HrefToken()];f_dynamic_options=1'>(Dynamic mode options)</A><br>"
  382. else if (SSticker.IsRoundInProgress())
  383. dat += "<A href='?src=[REF(src)];[HrefToken()];f_dynamic_latejoin=1'>(Force Next Latejoin Ruleset)</A><br>"
  384. if (SSticker && SSticker.mode && istype(SSticker.mode,/datum/game_mode/dynamic))
  385. var/datum/game_mode/dynamic/mode = SSticker.mode
  386. if (mode.forced_latejoin_rule)
  387. dat += {"<A href='?src=[REF(src)];[HrefToken()];f_dynamic_latejoin_clear=1'>-> [mode.forced_latejoin_rule.name] <-</A><br>"}
  388. dat += "<A href='?src=[REF(src)];[HrefToken()];f_dynamic_midround=1'>(Execute Midround Ruleset!)</A><br>"
  389. dat += "<hr/>"
  390. if(SSticker.IsRoundInProgress())
  391. dat += "<a href='?src=[REF(src)];[HrefToken()];gamemode_panel=1'>(Game Mode Panel)</a><BR>"
  392. dat += {"
  393. <BR>
  394. <A href='?src=[REF(src)];[HrefToken()];create_object=1'>Create Object</A><br>
  395. <A href='?src=[REF(src)];[HrefToken()];quick_create_object=1'>Quick Create Object</A><br>
  396. <A href='?src=[REF(src)];[HrefToken()];create_turf=1'>Create Turf</A><br>
  397. <A href='?src=[REF(src)];[HrefToken()];create_mob=1'>Create Mob</A><br>
  398. "}
  399. if(marked_datum && istype(marked_datum, /atom))
  400. dat += "<A href='?src=[REF(src)];[HrefToken()];dupe_marked_datum=1'>Duplicate Marked Datum</A><br>"
  401. usr << browse(dat, "window=admin2;size=240x280")
  402. return
  403. /////////////////////////////////////////////////////////////////////////////////////////////////admins2.dm merge
  404. //i.e. buttons/verbs
  405. /datum/admins/proc/restart()
  406. set category = "Server"
  407. set name = "Reboot World"
  408. set desc="Restarts the world immediately"
  409. if (!usr.client.holder)
  410. return
  411. var/localhost_addresses = list("127.0.0.1", "::1")
  412. var/list/options = list("Regular Restart", "Regular Restart (with delay)", "Hard Restart (No Delay/Feeback Reason)", "Hardest Restart (No actions, just reboot)")
  413. if(world.TgsAvailable())
  414. options += "Server Restart (Kill and restart DD)";
  415. if(SSticker.admin_delay_notice)
  416. 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")
  417. return FALSE
  418. var/result = input(usr, "Select reboot method", "World Reboot", options[1]) as null|anything in options
  419. if(result)
  420. 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!
  421. var/init_by = "Initiated by [usr.client.holder.fakekey ? "Admin" : usr.key]."
  422. switch(result)
  423. if("Regular Restart")
  424. if(!(isnull(usr.client.address) || (usr.client.address in localhost_addresses)))
  425. if(alert("Are you sure you want to restart the server?","This server is live","Restart","Cancel") != "Restart")
  426. return FALSE
  427. SSticker.Reboot(init_by, "admin reboot - by [usr.key] [usr.client.holder.fakekey ? "(stealth)" : ""]", 10)
  428. if("Regular Restart (with delay)")
  429. var/delay = input("What delay should the restart have (in seconds)?", "Restart Delay", 5) as num|null
  430. if(!delay)
  431. return FALSE
  432. if(!(isnull(usr.client.address) || (usr.client.address in localhost_addresses)))
  433. if(alert("Are you sure you want to restart the server?","This server is live","Restart","Cancel") != "Restart")
  434. return FALSE
  435. SSticker.Reboot(init_by, "admin reboot - by [usr.key] [usr.client.holder.fakekey ? "(stealth)" : ""]", delay * 10)
  436. if("Hard Restart (No Delay, No Feeback Reason)")
  437. to_chat(world, "World reboot - [init_by]")
  438. world.Reboot()
  439. if("Hardest Restart (No actions, just reboot)")
  440. to_chat(world, "Hard world reboot - [init_by]")
  441. world.Reboot(fast_track = TRUE)
  442. if("Server Restart (Kill and restart DD)")
  443. to_chat(world, "Server restart - [init_by]")
  444. world.TgsEndProcess()
  445. /datum/admins/proc/end_round()
  446. set category = "Server"
  447. set name = "End Round"
  448. set desc = "Attempts to produce a round end report and then restart the server organically."
  449. if (!usr.client.holder)
  450. return
  451. var/confirm = alert("End the round and restart the game world?", "End Round", "Yes", "Cancel")
  452. if(confirm == "Cancel")
  453. return
  454. if(confirm == "Yes")
  455. SSticker.force_ending = 1
  456. 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!
  457. /datum/admins/proc/announce()
  458. set category = "Admin"
  459. set name = "Announce"
  460. set desc="Announce your desires to the world"
  461. if(!check_rights(0))
  462. return
  463. var/message = input("Global message to send:", "Admin Announce", null, null) as message
  464. if(message)
  465. if(!check_rights(R_SERVER,0))
  466. message = adminscrub(message,500)
  467. to_chat(world, "<span class='adminnotice'><b>[usr.client.holder.fakekey ? "Administrator" : usr.key] Announces:</b></span>\n \t [message]", confidential = TRUE)
  468. log_admin("Announce: [key_name(usr)] : [message]")
  469. SSblackbox.record_feedback("tally", "admin_verb", 1, "Announce") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
  470. /datum/admins/proc/set_admin_notice()
  471. set category = "Server"
  472. set name = "Set Admin Notice"
  473. set desc ="Set an announcement that appears to everyone who joins the server. Only lasts this round"
  474. if(!check_rights(0))
  475. return
  476. 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
  477. if(new_admin_notice == null)
  478. return
  479. if(new_admin_notice == GLOB.admin_notice)
  480. return
  481. if(new_admin_notice == "")
  482. message_admins("[key_name(usr)] removed the admin notice.")
  483. log_admin("[key_name(usr)] removed the admin notice:\n[GLOB.admin_notice]")
  484. else
  485. message_admins("[key_name(usr)] set the admin notice.")
  486. log_admin("[key_name(usr)] set the admin notice:\n[new_admin_notice]")
  487. to_chat(world, "<span class='adminnotice'><b>Admin Notice:</b>\n \t [new_admin_notice]</span>", confidential = TRUE)
  488. 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!
  489. GLOB.admin_notice = new_admin_notice
  490. return
  491. /datum/admins/proc/toggleooc()
  492. set category = "Server"
  493. set desc="Toggle dis bitch"
  494. set name="Toggle OOC"
  495. toggle_ooc()
  496. log_admin("[key_name(usr)] toggled OOC.")
  497. message_admins("[key_name_admin(usr)] toggled OOC.")
  498. 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!
  499. /datum/admins/proc/toggleoocdead()
  500. set category = "Server"
  501. set desc="Toggle dis bitch"
  502. set name="Toggle Dead OOC"
  503. toggle_dooc()
  504. log_admin("[key_name(usr)] toggled OOC.")
  505. message_admins("[key_name_admin(usr)] toggled Dead OOC.")
  506. 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!
  507. /datum/admins/proc/startnow()
  508. set category = "Server"
  509. set desc="Start the round RIGHT NOW"
  510. set name="Start Now"
  511. if(SSticker.current_state == GAME_STATE_PREGAME || SSticker.current_state == GAME_STATE_STARTUP)
  512. if(!SSticker.start_immediately)
  513. var/localhost_addresses = list("127.0.0.1", "::1")
  514. if(!(isnull(usr.client.address) || (usr.client.address in localhost_addresses)))
  515. if(alert("Are you sure you want to start the round?","Start Now","Start Now","Cancel") != "Start Now")
  516. return FALSE
  517. SSticker.start_immediately = TRUE
  518. log_admin("[usr.key] has started the game.")
  519. var/msg = ""
  520. if(SSticker.current_state == GAME_STATE_STARTUP)
  521. msg = " (The server is still setting up, but the round will be \
  522. started as soon as possible.)"
  523. message_admins("<font color='blue'>[usr.key] has started the game.[msg]</font>")
  524. 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!
  525. return TRUE
  526. SSticker.start_immediately = FALSE
  527. SSticker.SetTimeLeft(1800)
  528. to_chat(world, "<b>The game will start in 180 seconds.</b>")
  529. SEND_SOUND(world, sound('sound/ai/attention.ogg'))
  530. message_admins("<font color='blue'>[usr.key] has cancelled immediate game start. Game will start in 180 seconds.</font>")
  531. log_admin("[usr.key] has cancelled immediate game start.")
  532. else
  533. to_chat(usr, "<font color='red'>Error: Start Now: Game has already started.</font>")
  534. return FALSE
  535. /datum/admins/proc/toggleenter()
  536. set category = "Server"
  537. set desc="People can't enter"
  538. set name="Toggle Entering"
  539. GLOB.enter_allowed = !( GLOB.enter_allowed )
  540. if (!( GLOB.enter_allowed ))
  541. to_chat(world, "<B>New players may no longer enter the game.</B>", confidential = TRUE)
  542. else
  543. to_chat(world, "<B>New players may now enter the game.</B>", confidential = TRUE)
  544. log_admin("[key_name(usr)] toggled new player game entering.")
  545. message_admins("<span class='adminnotice'>[key_name_admin(usr)] toggled new player game entering.</span>")
  546. world.update_status()
  547. 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!
  548. /datum/admins/proc/toggleAI()
  549. set category = "Server"
  550. set desc="People can't be AI"
  551. set name="Toggle AI"
  552. var/alai = CONFIG_GET(flag/allow_ai)
  553. CONFIG_SET(flag/allow_ai, !alai)
  554. if (alai)
  555. to_chat(world, "<B>The AI job is no longer chooseable.</B>", confidential = TRUE)
  556. else
  557. to_chat(world, "<B>The AI job is chooseable now.</B>", confidential = TRUE)
  558. log_admin("[key_name(usr)] toggled AI allowed.")
  559. world.update_status()
  560. 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!
  561. /datum/admins/proc/toggleaban()
  562. set category = "Server"
  563. set desc="Respawn basically"
  564. set name="Toggle Respawn"
  565. var/new_nores = !CONFIG_GET(flag/norespawn)
  566. CONFIG_SET(flag/norespawn, new_nores)
  567. if (!new_nores)
  568. to_chat(world, "<B>You may now respawn.</B>", confidential = TRUE)
  569. else
  570. to_chat(world, "<B>You may no longer respawn :(</B>", confidential = TRUE)
  571. message_admins("<span class='adminnotice'>[key_name_admin(usr)] toggled respawn to [!new_nores ? "On" : "Off"].</span>")
  572. log_admin("[key_name(usr)] toggled respawn to [!new_nores ? "On" : "Off"].")
  573. world.update_status()
  574. 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!
  575. /datum/admins/proc/delay()
  576. set category = "Server"
  577. set desc="Delay the game start"
  578. set name="Delay Pre-Game"
  579. var/newtime = input("Set a new time in seconds. Set -1 for indefinite delay.","Set Delay",round(SSticker.GetTimeLeft()/10)) as num|null
  580. if(SSticker.current_state > GAME_STATE_PREGAME)
  581. return alert("Too late... The game has already started!")
  582. if(newtime)
  583. newtime = newtime*10
  584. SSticker.SetTimeLeft(newtime)
  585. SSticker.start_immediately = FALSE
  586. if(newtime < 0)
  587. to_chat(world, "<b>The game start has been delayed.</b>", confidential = TRUE)
  588. log_admin("[key_name(usr)] delayed the round start.")
  589. else
  590. to_chat(world, "<b>The game will start in [DisplayTimeText(newtime)].</b>", confidential = TRUE)
  591. SEND_SOUND(world, sound('sound/ai/attention.ogg'))
  592. log_admin("[key_name(usr)] set the pre-game delay to [DisplayTimeText(newtime)].")
  593. 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!
  594. /datum/admins/proc/unprison(mob/M in GLOB.mob_list)
  595. set category = "Admin"
  596. set name = "Unprison"
  597. if (is_centcom_level(M.z))
  598. SSjob.SendToLateJoin(M)
  599. message_admins("[key_name_admin(usr)] has unprisoned [key_name_admin(M)]")
  600. log_admin("[key_name(usr)] has unprisoned [key_name(M)]")
  601. else
  602. alert("[M.name] is not prisoned.")
  603. SSblackbox.record_feedback("tally", "admin_verb", 1, "Unprison") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
  604. ////////////////////////////////////////////////////////////////////////////////////////////////ADMIN HELPER PROCS
  605. /datum/admins/proc/spawn_atom(object as text)
  606. set category = "Debug"
  607. set desc = "(atom path) Spawn an atom"
  608. set name = "Spawn"
  609. if(!check_rights(R_SPAWN) || !object)
  610. return
  611. var/list/preparsed = splittext(object,":")
  612. var/path = preparsed[1]
  613. var/amount = 1
  614. if(preparsed.len > 1)
  615. amount = clamp(text2num(preparsed[2]),1,ADMIN_SPAWN_CAP)
  616. var/chosen = pick_closest_path(path)
  617. if(!chosen)
  618. return
  619. var/turf/T = get_turf(usr)
  620. if(ispath(chosen, /turf))
  621. T.ChangeTurf(chosen)
  622. else
  623. for(var/i in 1 to amount)
  624. var/atom/A = new chosen(T)
  625. A.flags_1 |= ADMIN_SPAWNED_1
  626. log_admin("[key_name(usr)] spawned [amount] x [chosen] at [AREACOORD(usr)]")
  627. 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!
  628. /datum/admins/proc/podspawn_atom(object as text)
  629. set category = "Debug"
  630. set desc = "(atom path) Spawn an atom via supply drop"
  631. set name = "Podspawn"
  632. if(!check_rights(R_SPAWN))
  633. return
  634. var/chosen = pick_closest_path(object)
  635. if(!chosen)
  636. return
  637. var/turf/T = get_turf(usr)
  638. if(ispath(chosen, /turf))
  639. T.ChangeTurf(chosen)
  640. else
  641. var/obj/structure/closet/supplypod/centcompod/pod = new()
  642. var/atom/A = new chosen(pod)
  643. A.flags_1 |= ADMIN_SPAWNED_1
  644. new /obj/effect/DPtarget(T, pod)
  645. log_admin("[key_name(usr)] pod-spawned [chosen] at [AREACOORD(usr)]")
  646. SSblackbox.record_feedback("tally", "admin_verb", 1, "Podspawn Atom") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
  647. /datum/admins/proc/spawn_cargo(object as text)
  648. set category = "Debug"
  649. set desc = "(atom path) Spawn a cargo crate"
  650. set name = "Spawn Cargo"
  651. if(!check_rights(R_SPAWN))
  652. return
  653. var/chosen = pick_closest_path(object, make_types_fancy(subtypesof(/datum/supply_pack)))
  654. if(!chosen)
  655. return
  656. var/datum/supply_pack/S = new chosen
  657. S.admin_spawned = TRUE
  658. S.generate(get_turf(usr))
  659. log_admin("[key_name(usr)] spawned cargo pack [chosen] at [AREACOORD(usr)]")
  660. 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!
  661. /datum/admins/proc/show_traitor_panel(mob/M in GLOB.mob_list)
  662. set category = "Admin - Game"
  663. set desc = "Edit mobs's memory and role"
  664. set name = "Show Traitor Panel"
  665. if(!istype(M))
  666. to_chat(usr, "This can only be used on instances of type /mob", confidential = TRUE)
  667. return
  668. if(!M.mind)
  669. to_chat(usr, "This mob has no mind!", confidential = TRUE)
  670. return
  671. M.mind.traitor_panel()
  672. 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!
  673. /datum/admins/proc/toggletintedweldhelmets()
  674. set category = "Debug"
  675. set desc="Reduces view range when wearing welding helmets"
  676. set name="Toggle tinted welding helmes"
  677. GLOB.tinted_weldhelh = !( GLOB.tinted_weldhelh )
  678. if (GLOB.tinted_weldhelh)
  679. to_chat(world, "<B>The tinted_weldhelh has been enabled!</B>", confidential = TRUE)
  680. else
  681. to_chat(world, "<B>The tinted_weldhelh has been disabled!</B>", confidential = TRUE)
  682. log_admin("[key_name(usr)] toggled tinted_weldhelh.")
  683. message_admins("[key_name_admin(usr)] toggled tinted_weldhelh.")
  684. 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!
  685. /datum/admins/proc/toggleguests()
  686. set category = "Server"
  687. set desc="Guests can't enter"
  688. set name="Toggle guests"
  689. var/new_guest_ban = !CONFIG_GET(flag/guest_ban)
  690. CONFIG_SET(flag/guest_ban, new_guest_ban)
  691. if (new_guest_ban)
  692. to_chat(world, "<B>Guests may no longer enter the game.</B>", confidential = TRUE)
  693. else
  694. to_chat(world, "<B>Guests may now enter the game.</B>", confidential = TRUE)
  695. log_admin("[key_name(usr)] toggled guests game entering [!new_guest_ban ? "" : "dis"]allowed.")
  696. message_admins("<span class='adminnotice'>[key_name_admin(usr)] toggled guests game entering [!new_guest_ban ? "" : "dis"]allowed.</span>")
  697. 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!
  698. /datum/admins/proc/output_ai_laws()
  699. var/ai_number = 0
  700. for(var/i in GLOB.silicon_mobs)
  701. var/mob/living/silicon/S = i
  702. ai_number++
  703. if(isAI(S))
  704. to_chat(usr, "<b>AI [key_name(S, usr)]'s laws:</b>", confidential = TRUE)
  705. else if(iscyborg(S))
  706. var/mob/living/silicon/robot/R = S
  707. to_chat(usr, "<b>CYBORG [key_name(S, usr)] [R.connected_ai?"(Slaved to: [key_name(R.connected_ai)])":"(Independent)"]: laws:</b>", confidential = TRUE)
  708. else if (ispAI(S))
  709. to_chat(usr, "<b>pAI [key_name(S, usr)]'s laws:</b>", confidential = TRUE)
  710. else
  711. to_chat(usr, "<b>SOMETHING SILICON [key_name(S, usr)]'s laws:</b>", confidential = TRUE)
  712. if (S.laws == null)
  713. to_chat(usr, "[key_name(S, usr)]'s laws are null?? Contact a coder.", confidential = TRUE)
  714. else
  715. S.laws.show_laws(usr)
  716. if(!ai_number)
  717. to_chat(usr, "<b>No AIs located</b>" , confidential = TRUE)
  718. /datum/admins/proc/output_all_devil_info()
  719. var/devil_number = 0
  720. for(var/datum/mind/D in SSticker.mode.devils)
  721. devil_number++
  722. var/datum/antagonist/devil/devil = D.has_antag_datum(/datum/antagonist/devil)
  723. to_chat(usr, "Devil #[devil_number]:<br><br>" + devil.printdevilinfo(), confidential = TRUE)
  724. if(!devil_number)
  725. to_chat(usr, "<b>No Devils located</b>" , confidential = TRUE)
  726. /datum/admins/proc/output_devil_info(mob/living/M)
  727. if(is_devil(M))
  728. var/datum/antagonist/devil/devil = M.mind.has_antag_datum(/datum/antagonist/devil)
  729. to_chat(usr, devil.printdevilinfo(), confidential = TRUE)
  730. else
  731. to_chat(usr, "<b>[M] is not a devil.", confidential = TRUE)
  732. /datum/admins/proc/manage_free_slots()
  733. if(!check_rights())
  734. return
  735. var/datum/browser/browser = new(usr, "jobmanagement", "Manage Free Slots", 520)
  736. var/list/dat = list()
  737. var/count = 0
  738. if(!SSjob.initialized)
  739. alert(usr, "You cannot manage jobs before the job subsystem is initialized!")
  740. return
  741. dat += "<table>"
  742. for(var/j in SSjob.occupations)
  743. var/datum/job/job = j
  744. count++
  745. var/J_title = html_encode(job.title)
  746. var/J_opPos = html_encode(job.total_positions - (job.total_positions - job.current_positions))
  747. var/J_totPos = html_encode(job.total_positions)
  748. dat += "<tr><td>[J_title]:</td> <td>[J_opPos]/[job.total_positions < 0 ? " (unlimited)" : J_totPos]"
  749. dat += "</td>"
  750. dat += "<td>"
  751. if(job.total_positions >= 0)
  752. dat += "<A href='?src=[REF(src)];[HrefToken()];customjobslot=[job.title]'>Custom</A> | "
  753. dat += "<A href='?src=[REF(src)];[HrefToken()];addjobslot=[job.title]'>Add 1</A> | "
  754. if(job.total_positions > job.current_positions)
  755. dat += "<A href='?src=[REF(src)];[HrefToken()];removejobslot=[job.title]'>Remove</A> | "
  756. else
  757. dat += "Remove | "
  758. dat += "<A href='?src=[REF(src)];[HrefToken()];unlimitjobslot=[job.title]'>Unlimit</A></td>"
  759. else
  760. dat += "<A href='?src=[REF(src)];[HrefToken()];limitjobslot=[job.title]'>Limit</A></td>"
  761. browser.height = min(100 + count * 20, 650)
  762. browser.set_content(dat.Join())
  763. browser.open()
  764. /datum/admins/proc/dynamic_mode_options(mob/user)
  765. var/dat = {"
  766. <center><B><h2>Dynamic Mode Options</h2></B></center><hr>
  767. <br/>
  768. <h3>Common options</h3>
  769. <i>All these options can be changed midround.</i> <br/>
  770. <br/>
  771. <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>.
  772. <br/>This will force the round to be extended. No rulesets will be drafted. <br/>
  773. <br/>
  774. <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>.
  775. <br/>Unless the threat goes above [GLOB.dynamic_stacking_limit], only one "round-ender" ruleset will be drafted. <br/>
  776. <br/>
  777. <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>.
  778. <br/>Only one roundstart ruleset will be drafted. Only traitors and minor roles will latespawn. <br/>
  779. <br/>
  780. <br/>
  781. <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>.
  782. <br/>The value threat is set to if it is higher than -1.<br/>
  783. <br/>
  784. <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>.
  785. <br/>The threshold at which "high population override" will be in effect. <br/>
  786. <br/>
  787. <b>Stacking threeshold:</b> Current value : <a href='?src=[REF(src)];[HrefToken()];f_dynamic_stacking_limit=1'><b>[GLOB.dynamic_stacking_limit]</b></a>.
  788. <br/>The threshold at which "round-ender" rulesets will stack. A value higher than 100 ensure this never happens. <br/>
  789. <h3>Advanced parameters</h3>
  790. Curve centre: <A href='?src=[REF(src)];[HrefToken()];f_dynamic_roundstart_centre=1'>-> [GLOB.dynamic_curve_centre] <-</A><br>
  791. Curve width: <A href='?src=[REF(src)];[HrefToken()];f_dynamic_roundstart_width=1'>-> [GLOB.dynamic_curve_width] <-</A><br>
  792. Latejoin injection delay:<br>
  793. Minimum: <A href='?src=[REF(src)];[HrefToken()];f_dynamic_roundstart_latejoin_min=1'>-> [GLOB.dynamic_latejoin_delay_min / 60 / 10] <-</A> Minutes<br>
  794. Maximum: <A href='?src=[REF(src)];[HrefToken()];f_dynamic_roundstart_latejoin_max=1'>-> [GLOB.dynamic_latejoin_delay_max / 60 / 10] <-</A> Minutes<br>
  795. Midround injection delay:<br>
  796. Minimum: <A href='?src=[REF(src)];[HrefToken()];f_dynamic_roundstart_midround_min=1'>-> [GLOB.dynamic_midround_delay_min / 60 / 10] <-</A> Minutes<br>
  797. Maximum: <A href='?src=[REF(src)];[HrefToken()];f_dynamic_roundstart_midround_max=1'>-> [GLOB.dynamic_midround_delay_max / 60 / 10] <-</A> Minutes<br>
  798. "}
  799. user << browse(dat, "window=dyn_mode_options;size=900x650")
  800. /datum/admins/proc/create_or_modify_area()
  801. set category = "Debug"
  802. set name = "Create or modify area"
  803. create_area(usr)
  804. //
  805. //
  806. //ALL DONE
  807. //*********************************************************************************************************
  808. //TO-DO:
  809. //
  810. //
  811. //RIP ferry snowflakes
  812. //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
  813. //defaults to kicking everyone (afk + non afk clients in the lobby)
  814. //returns a list of ckeys of the kicked clients
  815. /proc/kick_clients_in_lobby(message, kick_only_afk = 0)
  816. var/list/kicked_client_names = list()
  817. for(var/client/C in GLOB.clients)
  818. if(isnewplayer(C.mob))
  819. if(kick_only_afk && !C.is_afk()) //Ignore clients who are not afk
  820. continue
  821. if(message)
  822. to_chat(C, message, confidential = TRUE)
  823. kicked_client_names.Add("[C.key]")
  824. qdel(C)
  825. return kicked_client_names
  826. //returns TRUE to let the dragdrop code know we are trapping this event
  827. //returns FALSE if we don't plan to trap the event
  828. /datum/admins/proc/cmd_ghost_drag(mob/dead/observer/frommob, mob/tomob)
  829. //this is the exact two check rights checks required to edit a ckey with vv.
  830. if (!check_rights(R_VAREDIT,0) || !check_rights(R_SPAWN|R_DEBUG,0))
  831. return FALSE
  832. if (!frommob.ckey)
  833. return FALSE
  834. var/question = ""
  835. if (tomob.ckey)
  836. question = "This mob already has a user ([tomob.key]) in control of it! "
  837. question += "Are you sure you want to place [frommob.name]([frommob.key]) in control of [tomob.name]?"
  838. var/ask = alert(question, "Place ghost in control of mob?", "Yes", "No")
  839. if (ask != "Yes")
  840. return TRUE
  841. if (!frommob || !tomob) //make sure the mobs don't go away while we waited for a response
  842. return TRUE
  843. // Disassociates observer mind from the body mind
  844. if(tomob.client)
  845. tomob.ghostize(FALSE)
  846. else
  847. for(var/mob/dead/observer/ghost in GLOB.dead_mob_list)
  848. if(tomob.mind == ghost.mind)
  849. ghost.mind = null
  850. message_admins("<span class='adminnotice'>[key_name_admin(usr)] has put [frommob.key] in control of [tomob.name].</span>")
  851. log_admin("[key_name(usr)] stuffed [frommob.key] into [tomob.name].")
  852. SSblackbox.record_feedback("tally", "admin_verb", 1, "Ghost Drag Control")
  853. tomob.ckey = frommob.ckey
  854. qdel(frommob)
  855. return TRUE
  856. /client/proc/adminGreet(logout)
  857. if(SSticker.HasRoundStarted())
  858. var/string
  859. if(logout && CONFIG_GET(flag/announce_admin_logout))
  860. string = pick(
  861. "Admin logout: [key_name(src)]")
  862. else if(!logout && CONFIG_GET(flag/announce_admin_login) && (prefs.toggles & ANNOUNCE_LOGIN))
  863. string = pick(
  864. "Admin login: [key_name(src)]")
  865. if(string)
  866. message_admins("[string]")