Files
Yogstation/code/modules/admin/admin.dm
Ling a6d7e3fd15 TGUI Preferences Menu + total rewrite of the preferences backend (#17381)
* TGUI Preferences Menu + total rewrite of the preferences backend (#17368)

* It compiles

* It opens

* Sync 1

* Add asset caching

* Sync 2

* It opens without dev now

* Update a few packages

* Sync 3

* Sync 4

keybind fix

* start of dehardcoded species

* Small fixes

* Add more individual preferences

* ASS sync

* Automatic changelog generation #17368 [ci skip]

* AHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH

* e

* Fix some TS stuff

* Sort quirks starting from good

* Fix skin tone selector

* Jamie Fixes

* Update moth.dm

* Fix latejoin menu + tweaks

* Some fixes

* Finally fix job selection

* e

* Ling

* MORE

* config

* Convert pref: ooccolor

* Convert pref: asay color

* Convert pref: tooltips

* Convert pref: ui style

* Convert pref: buttons locked

* Convert pref: hotkeys

* Convert pref: tgui stuff

* Convert pref: windowflashing

* Convert pref: ghost stuff

* Convert pref: map & antag

* Convert pref: PDA stuff

* Convert pref: credits & glasses


1

* Convert pref: name

* Convert pref: appearances 1

* Convert pref: appearances 2

* Convert pref: jobless role

* Convert pref: runechat

* Convert pref: yogtoggles + tail wagging


1

* Convert pref: client fps

* Convert pref: graphic settings

* Convert pref: pda uplink & menuoptions

* Convert pref: map & flare

* Convert pref: Bar choice

* Fix setup character button

* Convert pref: alt announcer

* Fix

* Add cycle background button

* Convert pref: disable balloon alert

* fix

* Clean savefile

* Fix backpack pref

* Fix underwear selection

* Fixes some shit

* Updates

* Fix computer runtime

* Fix pref names

* Convert pref: donor item & hat

* More computer fixes

* Convert pref: borg hat

* Convert pref: donor pda (broken)

* Convert pref: purrbation

* Convert pref: afreeze

* Convert pref: accent

* Various savefile improvements

* Convert pref: persistent scars


1

* A few pref fixes

* Some more fixes

* Various SSoverlays improvements

* Add IPC appearances

* Add polysmorph appearances

* No icons for ipc and polysmorph

* Podpeople deserve death

* Add plasmaman appearance

* h

* fix

* fix2

* asdf

* fsdf

* aaaaa

* FUCK MOTHS

* Preternis color

* e

* e

* Update human.dmi

* icon fix

* un snowflake

* fix underwear icon

* remove color from here

* donor ree

* aa

* maybe

* Restore a bunch of TGUI files

* More TGUI fixes

* test

* Fix more errors

* a

* test

* e?

* a;lso this

* maybe

* Fix

* Revert "maybe"

This reverts commit 14d044a7e3.

* fuck off m8

* e

* fak off m8

* e2?

* AHHH

* AHA

* AHHH

* fix linter 2

* debug

* fix runtime

* Update dynamic.json

* Revert "debug"

This reverts commit 18681432bd.

* 2

* who sleeps in an async?

* Hack

* e

* Fix a few blocking calls

* Oh bother

* Stay dead

* fuck

* Update jobs.dm

* move debugging

* Update jobs.dm

* Test

* YEET

* Revert "YEET"

This reverts commit 4082e3b133.

* Update jobs.dm

* Update jobs.dm

* e

* Fix sechailer runtime

* Fix human hair color

* d

* Ports part of that job refactor

* Convert latejoin to new departments

* Fix ghost form

* Quirk validation

* Hopefully pod color fix

* oops

* Prayge job fix

* test

* Better unit test asset loading

* Remove print

* Add error just in case

* Remove brief outfit and bypass centcom deadmin

* Remove broadcast login/logout

* Remove darkened flash

* Remove fov darkness

* Remove ghost lighting

* Remove some tgui prefs

* Typo fix

* Small fixes

* IPC name fix

* IPC and pod colors

* Jobless fix

* Donor item fix

* Oopsie

* Quirk bandaid

* Misc

* Move new prefs to Preferences tab for now

* Add skillcape

* FUCK THIS SHIT

* Remove /tg/ gamer cloak

* Restrict some job related preferences to clean up UI

* Remove useless client var

* e

* Small tweaks

* Dont allow selecting mood quirks if mood is disabled

* AHHH

* Filter ckey-locked donor items

* stupid jamie

* AI core display fix

* Move donor stuff back to the top

* Remove TODOs

* Clean up perks

* Linter fixes

* e

* WORKS

* LORE

* Fix skillcape list

* Backpack why

* Fixes

* Fix cargo console

* Remove these

* Add horns, frills and mark

* Fix not applying all features

* Add some missing mutant bodyparts

* Update numberinput

* Makes animatednumber cooler

* Oops

* Add default ghost orbit

* Default to normal backpack

* Fixes skillcapes not being filtered

* Donor fix prayge

* yep

* Adds fallback latejoin menu

* Rework donor stuff a bit

* Fix donor tgui logic

* Delete unused proc

* Update FA

* Un-yogify quirks

* Better checking of quirks

* Update tgfont

* Fix quirk icons

* Fix backup name

* Fix donor stuff

* A few runtime fixes

* Fix another runtime

* Give fallback latejoin verb upon connecting

* Update AirAlarm interface

* maybe this works

* Test

* Sentient

* Remove AI core display preview icons

* Fix resetting plasmaman helmet style

* Equip plasman in preview

* Fix plasmaman preview icon

* fuck keybind fix

* Extra keybind sanity

---------

Co-authored-by: Yogbot-13 <admin@yogstation.net>
Co-authored-by: Jamie D <993128+JamieD1@users.noreply.github.com>
Co-authored-by: TheGamerdk <5618080+TheGamerdk@users.noreply.github.com>
Co-authored-by: adamsong <adamsong@users.noreply.github.com>
2023-01-28 15:26:19 +00:00

1067 lines
53 KiB
Plaintext
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
////////////////////////////////
/proc/message_admins(msg)
msg = span_admin("<span class=\"prefix\">ADMIN LOG:</span> <span class=\"message\">[msg]</span>")
to_chat(GLOB.permissions.admins,
type = MESSAGE_TYPE_ADMINLOG,
html = msg,
confidential = TRUE)
/proc/relay_msg_admins(msg)
msg = span_admin("<span class=\"prefix\">RELAY:</span> <span class=\"message\">[msg]</span>")
to_chat(GLOB.permissions.admins,
type = MESSAGE_TYPE_ADMINLOG,
html = msg,
confidential = TRUE)
///////////////////////////////////////////////////////////////////////////////////////////////Panels
/datum/admins/proc/show_player_panel(mob/M in GLOB.mob_list)
set category = "Misc.Unused"
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.", confidential=TRUE)
return
if(M.oobe_client) //yogs start
if(M.oobe_client.mob)
.(M.oobe_client.mob) //using . because show_player_panel(M.oobe_client.mob) caused "Runtime in admin.dm,30: undefined proc or verb /client/Show Player Panel()."
else
to_chat(usr, span_warning("Cannot open player panel because [key_name(M)] has (a)ghosted, but does not appear to have a mob."), confidential=TRUE)
return //yogs end
var/body = "<html><head><meta charset='UTF-8'><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.permissions.admin_datums[M.client.ckey] || GLOB.permissions.deadmins[M.client.ckey]) ? "rank" : "add"];key=[M.key]'>[M.client.holder ? M.client.holder.rank_name() : "Player"]</A>\]"
if(CONFIG_GET(flag/use_exp_tracking))
body += "\[<A href='?_src_=holder;[HrefToken()];getplaytimewindow=[REF(M)]'>" + M.client.get_exp_living() + "</a> | "
body += " <A href='?_src_=holder;[HrefToken()];toggleexempt=[REF(M.client)]'>Toggle Exempt</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>CentCom Galactic Ban DB: </b> "
if(CONFIG_GET(string/centcom_ban_db))
body += "<a href='?_src_=holder;[HrefToken()];centcomlookup=[M.client.ckey]'>Search</a>"
else
body += "<i>Disabled</i>"
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> \]"
if(CONFIG_GET(string/vpn_lookup_api) && CONFIG_GET(string/vpn_lookup_key) && M.lastKnownIP)
body += " \[<a href='?_src_=holder;[HrefToken()];vpnlookup=[M.lastKnownIP]'>Check for VPN</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> | "
if(M.client)
body += "<A href='?_src_=holder;[HrefToken()];newbankey=[M.key];newbanip=[M.client.address];newbancid=[M.client.computer_id]'>Ban</A> | "
else
body += "<A href='?_src_=holder;[HrefToken()];newbankey=[M.key]'>Ban</A> | "
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_MENTORHELP]'><font color='[(muted & MUTE_MENTORHELP)?"red":"blue"]'>MENTORHELP</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 += "<A href='?_src_=holder;[HrefToken()];afreeze=[REF(M)];'><font color='[M.client.afreeze ? "red":"blue"]'>FREEZE</font></a>" //yogs - adminfreezing
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>"
body += "<br><br>"
body += "<A href='?_src_=holder;[HrefToken()];antag_token_give=[M.ckey]'>Give Antag Token</A> | "
body += "<A href='?_src_=holder;[HrefToken()];antag_token_redeem=[M.ckey]'>Redeem Antag Token</A> | "
body += "<A href='?_src_=holder;[HrefToken()];searchAntagTokenByKey=[M.ckey]'>See Antag Tokens</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> "
body += "<A href='?_src_=holder;[HrefToken()];checkAIDash=[REF(M)]'>Access AI Dashboard | </A>"
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.YogsPPoptions(M) // YOGS - Player panel stuff, big PP
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 = "Admin.Round Interaction"
set name = "Access Newscaster"
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!", confidential=TRUE)
return
var/dat
dat = text("<HEAD><meta charset='UTF-8'><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 = {"
<HTML><HEAD><meta charset='UTF-8'></HEAD><BODY>
<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(SSticker.is_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>"
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>"
dat += "</BODY></HTML>"
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")
if(check_rights(R_SERVER, FALSE))
options += list("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 SECONDS, check_rights(R_SERVER, FALSE)) // Force if they have +SERVER
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 = tgui_alert(usr, "End the round and restart the game world?", "End Round", list("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 = "Server.Global Messages"
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 = "Admin"
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/toggleoocdead()
set category = "Server"
set desc="Toggle dis bitch"
set name="Toggle Dead OOC"
toggle_dooc()
log_admin("[key_name(usr)] toggled 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/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)
if(!SSticker.start_immediately)
var/localhost_addresses = list("127.0.0.1", "::1")
if(!(isnull(usr.client.address) || (usr.client.address in localhost_addresses)))
if(tgui_alert(usr, "Are you sure you want to start the round?","Start Now",list("Start Now","Cancel")) != "Start Now")
return FALSE
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 TRUE
SSticker.start_immediately = FALSE
SSticker.SetTimeLeft(1800)
to_chat(world, "<span class='infoplain'><b>The game will start in 180 seconds.</b></span>")
SEND_SOUND(world, sound('sound/ai/default/attention.ogg'))
message_admins("<font color='blue'>[usr.key] has cancelled immediate game start. Game will start in 180 seconds.</font>")
log_admin("[usr.key] has cancelled immediate game start.")
else
to_chat(usr, "<font color='red'>Error: Start Now: Game has already started.</font>", confidential=TRUE)
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>")
message_admins(span_adminnotice("[key_name_admin(usr)] toggled new player game entering, no players may enter."))
else
to_chat(world, "<B>New players may now enter the game.</B>")
message_admins(span_adminnotice("[key_name_admin(usr)] toggled new player game entering, players can now enter the game freely."))
log_admin("[key_name(usr)] toggled new player game entering.")
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/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_adminnotice("[key_name_admin(usr)] toggled respawn to [!new_nores ? "On" : "Off"]."))
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"
set name="Delay Start/End"
if(!check_rights(R_ADMIN)) //YOGS - R_SERVER -> R_ADMIN
return
if(SSticker.current_state < GAME_STATE_PLAYING)
var/newtime = input("Set a new time in seconds. Set -1 for indefinite delay.","Set Delay",round(SSticker.GetTimeLeft()/10)) as num|null
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.")
message_admins("[key_name(usr)] delayed the round start.")
else
to_chat(world, "<b>The game will start in [DisplayTimeText(newtime)].</b>")
SEND_SOUND(world, sound('sound/ai/default/attention.ogg'))
message_admins("[key_name(usr)] set the pre-game delay to [DisplayTimeText(newtime)].")
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!
else
if(!SSticker.delay_end)
SSticker.admin_delay_notice = input(usr, "Enter a reason for delaying the round end", "Round Delay Reason") as null|text
if(isnull(SSticker.admin_delay_notice))
return
else
SSticker.admin_delay_notice = null
SSticker.delay_end = !SSticker.delay_end
var/reason = SSticker.delay_end ? "for reason: [SSticker.admin_delay_notice]" : ""
var/msg = "[SSticker.delay_end ? "delayed" : "undelayed"] the round end [reason]"
log_admin("[key_name(usr)] [msg]")
message_admins("[key_name_admin(usr)] [msg]")
if(SSticker.ready_for_reboot && !SSticker.delay_end) //we undelayed after standard reboot would occur
if(tgui_alert(usr,"Restart the round?.","Round restart",list("Yes","No")) == "Yes")
SSticker.Reboot(delay = 100, force = TRUE)
/datum/admins/proc/unprison(mob/M in GLOB.mob_list)
set category = "Admin.Player Interaction"
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
tgui_alert(usr, "[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 = "Misc.Server 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
var/turf/T = get_turf(usr)
if(ispath(chosen, /turf))
T.ChangeTurf(chosen)
else
var/atom/A = new chosen(T)
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/podspawn_atom(object as text)
set category = "Misc.Server Debug"
set desc = "(atom path) Spawn an atom via supply drop"
set name = "Podspawn"
if(!check_rights(R_SPAWN))
return
var/chosen = pick_closest_path(object)
if(!chosen)
return
var/turf/T = get_turf(usr)
if(ispath(chosen, /turf))
T.ChangeTurf(chosen)
else
var/obj/structure/closet/supplypod/centcompod/pod = new()
var/atom/A = new chosen(pod)
A.flags_1 |= ADMIN_SPAWNED_1
new /obj/effect/DPtarget(T, pod)
log_admin("[key_name(usr)] pod-spawned [chosen] at [AREACOORD(usr)]")
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!
/datum/admins/proc/spawn_cargo(object as text)
set category = "Misc.Server 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.Player Interaction"
set desc = "Edit mobs's memory and role"
set name = "Show Traitor Panel"
if(!check_rights(R_ADMIN))
return
if(!istype(M))
to_chat(usr, "This can only be used on instances of type /mob", confidential=TRUE)
return
if(!M.mind)
to_chat(usr, "This mob has no mind!", confidential=TRUE)
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 = "Misc.Server 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_adminnotice("[key_name_admin(usr)] toggled guests game entering [!new_guest_ban ? "" : "dis"]allowed."))
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() // Yogs -- Overridden in yogstation/code/modules/admin/admin.dm
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>", confidential=TRUE)
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>", confidential=TRUE)
else if (ispAI(S))
to_chat(usr, "<b>pAI [key_name(S, usr)]'s laws:</b>", confidential=TRUE)
else
to_chat(usr, "<b>SOMETHING SILICON [key_name(S, usr)]'s laws:</b>", confidential=TRUE)
if (S.laws == null)
to_chat(usr, "[key_name(S, usr)]'s laws are null?? Contact a coder.", confidential=TRUE)
else
S.laws.show_laws(usr)
if(!ai_number)
to_chat(usr, "<b>No AIs located</b>" , confidential=TRUE)
/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(), confidential=TRUE)
if(!devil_number)
to_chat(usr, "<b>No Devils located</b>" , confidential=TRUE)
/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(), confidential=TRUE)
else
to_chat(usr, "<b>[M] is not a devil.", confidential=TRUE)
/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)
tgui_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>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/>
<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/>
"}
user << browse(dat, "window=dyn_mode_options;size=900x650")
/datum/admins/proc/create_or_modify_area()
set category = "Misc.Server Debug"
set name = "Create or modify area"
create_area(usr)
/datum/admins/proc/observe_follow(atom/movable/AM)
if(!isobserver(owner.mob) && !check_rights(R_ADMIN))
return
var/can_ghost = TRUE
if(!isobserver(owner.mob))
can_ghost = owner.admin_ghost()
if(!can_ghost)
return
var/mob/dead/observer/A = owner.mob
var/mob/living/silicon/ai/I = AM //yogs start - adminfollow now follows AI eyes instead of the core
if(istype(I) && I.eyeobj)
A.ManualFollow(I.eyeobj)
else
A.ManualFollow(AM) //yogs stop - adminfollow now follows AI eyes instead of the core
//
//
//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, confidential=TRUE)
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 = tgui_alert(usr, question, "Place ghost in control of mob?", list("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_adminnotice("[key_name_admin(usr)] has put [frommob.key] in control of [tomob.name]."))
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
/datum/admins/proc/adminmoreinfo(mob/M)
if(!ismob(M))
to_chat(usr, "This can only be used on instances of type /mob.", confidential=TRUE)
return
var/location_description = ""
var/special_role_description = ""
var/health_description = ""
var/gender_description = ""
var/turf/T = get_turf(M)
//Location
if(isturf(T))
if(isarea(T.loc))
location_description = "([M.loc == T ? "at coordinates " : "in [M.loc] at coordinates "] [T.x], [T.y], [T.z] in area <b>[T.loc]</b>)"
else
location_description = "([M.loc == T ? "at coordinates " : "in [M.loc] at coordinates "] [T.x], [T.y], [T.z])"
//Job + antagonist
if(M.mind)
special_role_description = "Role: <b>[M.mind.assigned_role]</b>; Antagonist: <font color='red'><b>[M.mind.special_role]</b></font>"
else
special_role_description = "Role: <i>Mind datum missing</i> Antagonist: <i>Mind datum missing</i>"
//Health
if(isliving(M))
var/mob/living/L = M
var/status
switch (M.stat)
if(CONSCIOUS)
status = "Alive"
if(SOFT_CRIT)
status = "<font color='orange'><b>Dying</b></font>"
if(UNCONSCIOUS)
status = "<font color='orange'><b>[L.InCritical() ? "Unconscious and Dying" : "Unconscious"]</b></font>"
if(DEAD)
status = "<font color='red'><b>Dead</b></font>"
health_description = "Status = [status]"
health_description += "<BR>Oxy: [L.getOxyLoss()] - Tox: [L.getToxLoss()] - Fire: [L.getFireLoss()] - Brute: [L.getBruteLoss()] - Clone: [L.getCloneLoss()] - Brain: [L.getOrganLoss(ORGAN_SLOT_BRAIN)] - Stamina: [L.getStaminaLoss()]"
else
health_description = "This mob type has no health to speak of."
//Gender
switch(M.gender)
if(MALE,FEMALE)
gender_description = "[M.gender]"
else
gender_description = "<font color='red'><b>[M.gender]</b></font>"
to_chat(src.owner, "<b>Info about [M.name]:</b> ", confidential=TRUE)
to_chat(src.owner, "Mob type = [M.type]; Gender = [gender_description] Damage = [health_description]", confidential=TRUE)
to_chat(src.owner, "Name = <b>[M.name]</b>; Real_name = [M.real_name]; Mind_name = [M.mind?"[M.mind.name]":""]; Key = <b>[M.key]</b>;", confidential=TRUE)
to_chat(src.owner, "Location = [location_description];", confidential=TRUE)
to_chat(src.owner, "[special_role_description]", confidential=TRUE)
to_chat(src.owner, ADMIN_FULLMONTY_NONAME(M), confidential=TRUE)
/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]")