[MIRROR] View Variables Update (2) (#11149)

Co-authored-by: Selis <12716288+ItsSelis@users.noreply.github.com>
Co-authored-by: Kashargul <144968721+Kashargul@users.noreply.github.com>
This commit is contained in:
CHOMPStation2StaffMirrorBot
2025-07-05 19:08:25 -07:00
committed by GitHub
parent d4c88eacdd
commit 76310c6448
137 changed files with 6803 additions and 2316 deletions

View File

@@ -39,112 +39,105 @@ GLOBAL_VAR_INIT(floorIsLava, 0)
///////////////////////////////////////////////////////////////////////////////////////////////Panels
/datum/admins/proc/show_player_panel(var/mob/M in mob_list)
set category = "Admin.Game"
set name = "Show Player Panel"
set desc="Edit player (respawn, ban, heal, etc)"
ADMIN_VERB_ONLY_CONTEXT_MENU(show_player_panel, R_HOLDER, "Show Player Panel", mob/player in world)
log_admin("[key_name(user)] checked the individual player panel for [key_name(player)][isobserver(user.mob)?"":" while in game"].")
if(!M)
to_chat(usr, "You seem to be selecting a mob that doesn't exist anymore.")
return
if (!istype(src,/datum/admins))
src = usr.client.holder
if (!istype(src,/datum/admins))
to_chat(usr, "Error: you are not an admin!")
if(!player)
to_chat(user, "You seem to be selecting a mob that doesn't exist anymore.")
return
var/body = "Options panel for " + span_bold("[M]")
if(M.client)
body += " played by " + span_bold("[M.client]")
body += "\[<A href='byond://?src=\ref[src];[HrefToken()];editrights=show'>[M.client.holder ? M.client.holder.rank_names() : "Player"]</A>\]"
var/body = "Options panel for " + span_bold("[player]")
if(player.client)
body += " played by " + span_bold("[player.client]")
body += "\[<A href='byond://?_src_=holder;[HrefToken()];editrights=[(GLOB.admin_datums[player.client.ckey] || GLOB.deadmins[player.client.ckey]) ? "rank" : "add"];key=[player.key]'>[player.client.holder ? player.client.holder.rank_names() : "Player"]</A>\]"
if(isnewplayer(M))
body += span_bold(" Hasn't Entered Game")
if(isnewplayer(player))
body += span_bold("Hasn't Entered Game")
else
body += " \[<A href='byond://?src=\ref[src];[HrefToken()];revive=\ref[M]'>Heal</A>\] "
body += " \[<A href='byond://?_src_=holder;[HrefToken()];revive=[REF(player)]'>Heal</A>\] "
if(M.client)
body += "<br>" + span_bold("First connection:") + "[M.client.player_age] days ago"
body += "<br>" + span_bold("BYOND account created:") + "[M.client.account_join_date]"
body += "<br>" + span_bold("BYOND account age (days):") + "[M.client.account_age]"
if(player.client)
body += "<br>" + span_bold("First connection:") + "[player.client.player_age] days ago"
body += "<br>" + span_bold("BYOND account created:") + "[player.client.account_join_date]"
body += "<br>" + span_bold("BYOND account age (days):") + "[player.client.account_age]"
body += {"
<br><br>\[
<a href='byond://?_src_=vars;[HrefToken()];Vars=\ref[M]'>VV</a> -
<a href='byond://?src=\ref[src];[HrefToken()];traitor=\ref[M]'>TP</a> -
<a href='byond://?src=\ref[usr];[HrefToken()];priv_msg=\ref[M]'>PM</a> -
<a href='byond://?src=\ref[src];[HrefToken()];subtlemessage=\ref[M]'>SM</a> -
[admin_jump_link(M, src)]\] <br>
"} + span_bold("Mob type:") + {"[M.type]<br>
"} + span_bold("Inactivity time:") + {" [M.client ? "[M.client.inactivity/600] minutes" : "Logged out"]<br/><br/>
<A href='byond://?src=\ref[src];[HrefToken()];boot2=\ref[M]'>Kick</A> |
<A href='byond://?_src_=holder;[HrefToken()];warn=[M.ckey]'>Warn</A> |
<A href='byond://?src=\ref[src];[HrefToken()];newban=\ref[M]'>Ban</A> |
<A href='byond://?src=\ref[src];[HrefToken()];jobban2=\ref[M]'>Jobban</A> |
<A href='byond://?src=\ref[src];[HrefToken()];notes=show;mob=\ref[M]'>Notes</A>
<a href='byond://?_src_=vars;[HrefToken()];Vars=\ref[player]'>VV</a> -
<a href='byond://?_src_=holder;[HrefToken()];traitor=\ref[player]'>TP</a> -
<a href='byond://??_src_=holder;[HrefToken()];priv_msg=\ref[player]'>PM</a> -
<a href='byond://?_src_=holder;[HrefToken()];subtlemessage=\ref[player]'>SM</a> -
[admin_jump_link(player, src)]\] <br>
"} + span_bold("Mob type:") + {"[player.type]<br>
"} + span_bold("Inactivity time:") + {" [player.client ? "[player.client.inactivity/600] minutes" : "Logged out"]<br/><br/>
<A href='byond://?_src_=holder;[HrefToken()];boot2=\ref[player]'>Kick</A> |
<A href='byond://?_src_=holder;[HrefToken()];warn=[player.ckey]'>Warn</A> |
<A href='byond://?_src_=holder;[HrefToken()];newban=\ref[player]'>Ban</A> |
<A href='byond://?_src_=holder;[HrefToken()];jobban2=\ref[player]'>Jobban</A> |
<A href='byond://?_src_=holder;[HrefToken()];notes=show;mob=\ref[player]'>Notes</A>
"}
if(M.client)
body += "| <A href='byond://?src=\ref[src];[HrefToken()];sendtoprison=\ref[M]'>Prison</A> | "
body += "\ <A href='byond://?src=\ref[src];[HrefToken()];sendbacktolobby=\ref[M]'>Send back to Lobby</A> | "
var/muted = M.client.prefs.muted
if(player.client)
body += "| <A href='byond://?_src_=holder;[HrefToken()];sendtoprison=\ref[player]'>Prison</A> | "
body += "\ <A href='byond://?_src_=holder;[HrefToken()];sendbacktolobby=\ref[player]'>Send back to Lobby</A> | "
var/muted = player.client.prefs.muted
body += {"<br>"} + span_bold("Mute: ") + {"
\[<A href='byond://?src=\ref[src];[HrefToken()];mute=\ref[M];mute_type=[MUTE_IC]'>[(muted & MUTE_IC) ? span_red("IC") : span_blue("IC")]</a> |
<A href='byond://?src=\ref[src];[HrefToken()];mute=\ref[M];mute_type=[MUTE_OOC]'>[(muted & MUTE_OOC) ? span_red("OOC") : span_blue("OOC")]</a> |
<A href='byond://?src=\ref[src];[HrefToken()];mute=\ref[M];mute_type=[MUTE_LOOC]'>[(muted & MUTE_LOOC) ? span_red("LOOC") : span_blue("LOOC")]</a> |
<A href='byond://?src=\ref[src];[HrefToken()];mute=\ref[M];mute_type=[MUTE_PRAY]'>[(muted & MUTE_PRAY) ? span_red("PRAY") : span_blue("PRAY")]</a> |
<A href='byond://?src=\ref[src];[HrefToken()];mute=\ref[M];mute_type=[MUTE_ADMINHELP]'>[(muted & MUTE_ADMINHELP) ? span_red("ADMINHELP") : span_blue("ADMINHELP")]</a> |
<A href='byond://?src=\ref[src];[HrefToken()];mute=\ref[M];mute_type=[MUTE_DEADCHAT]'>[(muted & MUTE_DEADCHAT) ? span_red("DEADCHAT") : span_blue("DEADCHAT")]</a>\]
(<A href='byond://?src=\ref[src];[HrefToken()];mute=\ref[M];mute_type=[MUTE_ALL]'>[(muted & MUTE_ALL) ? span_red("toggle all") : span_blue("toggle all")]</a>)
\[<A href='byond://?_src_=holder;[HrefToken()];mute=\ref[player];mute_type=[MUTE_IC]'>[(muted & MUTE_IC) ? span_red("IC") : span_blue("IC")]</a> |
<A href='byond://?_src_=holder;[HrefToken()];mute=\ref[player];mute_type=[MUTE_OOC]'>[(muted & MUTE_OOC) ? span_red("OOC") : span_blue("OOC")]</a> |
<A href='byond://?_src_=holder;[HrefToken()];mute=\ref[player];mute_type=[MUTE_LOOC]'>[(muted & MUTE_LOOC) ? span_red("LOOC") : span_blue("LOOC")]</a> |
<A href='byond://?_src_=holder;[HrefToken()];mute=\ref[player];mute_type=[MUTE_PRAY]'>[(muted & MUTE_PRAY) ? span_red("PRAY") : span_blue("PRAY")]</a> |
<A href='byond://?_src_=holder;[HrefToken()];mute=\ref[player];mute_type=[MUTE_ADMINHELP]'>[(muted & MUTE_ADMINHELP) ? span_red("ADMINHELP") : span_blue("ADMINHELP")]</a> |
<A href='byond://?_src_=holder;[HrefToken()];mute=\ref[player];mute_type=[MUTE_DEADCHAT]'>[(muted & MUTE_DEADCHAT) ? span_red("DEADCHAT") : span_blue("DEADCHAT")]</a>\]
(<A href='byond://?_src_=holder;[HrefToken()];mute=\ref[player];mute_type=[MUTE_ALL]'>[(muted & MUTE_ALL) ? span_red("toggle all") : span_blue("toggle all")]</a>)
"}
body += {"<br><br>
<A href='byond://?src=\ref[src];[HrefToken()];jumpto=\ref[M]'>"} + span_bold("Jump to") + {"</A> |
<A href='byond://?src=\ref[src];[HrefToken()];getmob=\ref[M]'>Get</A> |
<A href='byond://?src=\ref[src];[HrefToken()];sendmob=\ref[M]'>Send To</A>
<A href='byond://?_src_=holder;[HrefToken()];jumpto=\ref[player]'>"} + span_bold("Jump to") + {"</A> |
<A href='byond://?_src_=holder;[HrefToken()];getmob=\ref[player]'>Get</A> |
<A href='byond://?_src_=holder;[HrefToken()];sendmob=\ref[player]'>Send To</A>
<br><br>
[check_rights(R_ADMIN|R_MOD|R_EVENT,0) ? "<A href='byond://?src=\ref[src];[HrefToken()];traitor=\ref[M]'>Traitor panel</A> | " : "" ]
<A href='byond://?src=\ref[src];[HrefToken()];narrateto=\ref[M]'>Narrate to</A> |
<A href='byond://?src=\ref[src];[HrefToken()];subtlemessage=\ref[M]'>Subtle message</A>
[check_rights(R_ADMIN|R_MOD|R_EVENT,0) ? "<A href='byond://?_src_=holder;[HrefToken()];traitor=\ref[player]'>Traitor panel</A> | " : "" ]
<A href='byond://?_src_=holder;[HrefToken()];narrateto=\ref[player]'>Narrate to</A> |
<A href='byond://?_src_=holder;[HrefToken()];subtlemessage=\ref[player]'>Subtle message</A>
"}
if (M.client)
if(!isnewplayer(M))
if (player.client)
if(!isnewplayer(player))
body += "<br><br>"
body += span_bold("Transformation:")
body += "<br>"
//Monkey
if(issmall(M))
if(issmall(player))
body += span_bold("Monkeyized") + " | "
else
body += "<A href='byond://?src=\ref[src];[HrefToken()];monkeyone=\ref[M]'>Monkeyize</A> | "
body += "<A href='byond://?_src_=holder;[HrefToken()];monkeyone=\ref[player]'>Monkeyize</A> | "
//Corgi
if(iscorgi(M))
if(iscorgi(player))
body += span_bold("Corgized") + " | "
else
body += "<A href='byond://?src=\ref[src];[HrefToken()];corgione=\ref[M]'>Corgize</A> | "
body += "<A href='byond://?_src_=holder;[HrefToken()];corgione=\ref[player]'>Corgize</A> | "
//AI / Cyborg
if(isAI(M))
if(isAI(player))
body += span_bold("Is an AI ")
else if(ishuman(M))
body += {"<A href='byond://?src=\ref[src];[HrefToken()];makeai=\ref[M]'>Make AI</A> |
<A href='byond://?src=\ref[src];[HrefToken()];makerobot=\ref[M]'>Make Robot</A> |
<A href='byond://?src=\ref[src];[HrefToken()];makealien=\ref[M]'>Make Alien</A>
else if(ishuman(player))
body += {"<A href='byond://?_src_=holder;[HrefToken()];makeai=\ref[player]'>Make AI</A> |
<A href='byond://?_src_=holder;[HrefToken()];makerobot=\ref[player]'>Make Robot</A> |
<A href='byond://?_src_=holder;[HrefToken()];makealien=\ref[player]'>Make Alien</A>
"}
//Simple Animals
if(isanimal(M))
body += "<A href='byond://?src=\ref[src];[HrefToken()];makeanimal=\ref[M]'>Re-Animalize</A> | "
if(isanimal(player))
body += "<A href='byond://?_src_=holder;[HrefToken()];makeanimal=\ref[player]'>Re-Animalize</A> | "
else
body += "<A href='byond://?src=\ref[src];[HrefToken()];makeanimal=\ref[M]'>Animalize</A> | "
body += "<A href='byond://?_src_=holder;[HrefToken()];makeanimal=\ref[player]'>Animalize</A> | "
body += "<A href='byond://?src=\ref[src];[HrefToken()];respawn=\ref[M.client]'>Respawn</A> | "
body += "<A href='byond://?_src_=holder;[HrefToken()];respawn=\ref[player.client]'>Respawn</A> | "
// DNA2 - Admin Hax
if(M.dna && iscarbon(M))
if(player.dna && iscarbon(player))
body += "<br><br>"
body += span_bold("DNA Blocks:") + "<br><table border='0'><tr><th>&nbsp;</th><th>1</th><th>2</th><th>3</th><th>4</th><th>5</th>"
var/bname
@@ -165,7 +158,7 @@ GLOBAL_VAR_INIT(floorIsLava, 0)
bname = ""
body += "<td>"
if(bname)
var/bstate=(bname in M.active_genes) // Traitgenes more reliable way to check gene states
var/bstate=(bname in player.active_genes) // Traitgenes more reliable way to check gene states
// Traitgenes show trait linked names on mouseover
var/tname = bname
if(istype(gene,/datum/gene/trait))
@@ -173,11 +166,11 @@ GLOBAL_VAR_INIT(floorIsLava, 0)
tname = T.get_name()
if(bstate)
bname = span_green(bname)
else if(!bstate && M.dna.GetSEState(block)) // Gene isn't active, but the dna says it is... Was blocked by another gene!
else if(!bstate && player.dna.GetSEState(block)) // Gene isn't active, but the dna says it is... Was blocked by another gene!
bname = span_orange(bname)
else
bname = span_red(bname)
body += "<A href='byond://?src=\ref[src];[HrefToken()];togmutate=\ref[M];block=[block]' title='[tname]'>[bname]</A><sub>[block]</sub>" // Traitgenes edit - show trait linked names on mouseover
body += "<A href='byond://?_src_=holder;[HrefToken()];togmutate=\ref[player];block=[block]' title='[tname]'>[bname]</A><sub>[block]</sub>" // Traitgenes edit - show trait linked names on mouseover
else
body += "[block]"
body+="</td>"
@@ -185,45 +178,45 @@ GLOBAL_VAR_INIT(floorIsLava, 0)
body += {"<br><br>
"} + span_bold("Rudimentary transformation:") + span_normal("<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.") + {"<br>
<A href='byond://?src=\ref[src];[HrefToken()];simplemake=observer;mob=\ref[M]'>Observer</A> |
\[ Xenos: <A href='byond://?src=\ref[src];[HrefToken()];simplemake=larva;mob=\ref[M]'>Larva</A>
<A href='byond://?src=\ref[src];[HrefToken()];simplemake=human;species=Xenomorph Drone;mob=\ref[M]'>Drone</A>
<A href='byond://?src=\ref[src];[HrefToken()];simplemake=human;species=Xenomorph Hunter;mob=\ref[M]'>Hunter</A>
<A href='byond://?src=\ref[src];[HrefToken()];simplemake=human;species=Xenomorph Sentinel;mob=\ref[M]'>Sentinel</A>
<A href='byond://?src=\ref[src];[HrefToken()];simplemake=human;species=Xenomorph Queen;mob=\ref[M]'>Queen</A> \] |
\[ Crew: <A href='byond://?src=\ref[src];[HrefToken()];simplemake=human;mob=\ref[M]'>Human</A>
<A href='byond://?src=\ref[src];[HrefToken()];simplemake=human;species=Unathi;mob=\ref[M]'>Unathi</A>
<A href='byond://?src=\ref[src];[HrefToken()];simplemake=human;species=Tajaran;mob=\ref[M]'>Tajaran</A>
<A href='byond://?src=\ref[src];[HrefToken()];simplemake=human;species=Skrell;mob=\ref[M]'>Skrell</A> \] | \[
<A href='byond://?src=\ref[src];[HrefToken()];simplemake=nymph;mob=\ref[M]'>Nymph</A>
<A href='byond://?src=\ref[src];[HrefToken()];simplemake=human;species='Diona';mob=\ref[M]'>Diona</A> \] |
\[ slime: <A href='byond://?src=\ref[src];[HrefToken()];simplemake=slime;mob=\ref[M]'>Baby</A>,
<A href='byond://?src=\ref[src];[HrefToken()];simplemake=adultslime;mob=\ref[M]'>Adult</A> \]
<A href='byond://?src=\ref[src];[HrefToken()];simplemake=monkey;mob=\ref[M]'>Monkey</A> |
<A href='byond://?src=\ref[src];[HrefToken()];simplemake=robot;mob=\ref[M]'>Cyborg</A> |
<A href='byond://?src=\ref[src];[HrefToken()];simplemake=cat;mob=\ref[M]'>Cat</A> |
<A href='byond://?src=\ref[src];[HrefToken()];simplemake=runtime;mob=\ref[M]'>Runtime</A> |
<A href='byond://?src=\ref[src];[HrefToken()];simplemake=corgi;mob=\ref[M]'>Corgi</A> |
<A href='byond://?src=\ref[src];[HrefToken()];simplemake=ian;mob=\ref[M]'>Ian</A> |
<A href='byond://?src=\ref[src];[HrefToken()];simplemake=crab;mob=\ref[M]'>Crab</A> |
<A href='byond://?src=\ref[src];[HrefToken()];simplemake=coffee;mob=\ref[M]'>Coffee</A> |
\[ Construct: <A href='byond://?src=\ref[src];[HrefToken()];simplemake=constructarmoured;mob=\ref[M]'>Armoured</A> ,
<A href='byond://?src=\ref[src];[HrefToken()];simplemake=constructbuilder;mob=\ref[M]'>Builder</A> ,
<A href='byond://?src=\ref[src];[HrefToken()];simplemake=constructwraith;mob=\ref[M]'>Wraith</A> \]
<A href='byond://?src=\ref[src];[HrefToken()];simplemake=shade;mob=\ref[M]'>Shade</A>
<A href='byond://?_src_=holder;[HrefToken()];simplemake=observer;mob=\ref[player]'>Observer</A> |
\[ Xenos: <A href='byond://?_src_=holder;[HrefToken()];simplemake=larva;mob=\ref[player]'>Larva</A>
<A href='byond://?_src_=holder;[HrefToken()];simplemake=human;species=Xenomorph Drone;mob=\ref[player]'>Drone</A>
<A href='byond://?_src_=holder;[HrefToken()];simplemake=human;species=Xenomorph Hunter;mob=\ref[player]'>Hunter</A>
<A href='byond://?_src_=holder;[HrefToken()];simplemake=human;species=Xenomorph Sentinel;mob=\ref[player]'>Sentinel</A>
<A href='byond://?_src_=holder;[HrefToken()];simplemake=human;species=Xenomorph Queen;mob=\ref[player]'>Queen</A> \] |
\[ Crew: <A href='byond://?_src_=holder;[HrefToken()];simplemake=human;mob=\ref[player]'>Human</A>
<A href='byond://?_src_=holder;[HrefToken()];simplemake=human;species=Unathi;mob=\ref[player]'>Unathi</A>
<A href='byond://?_src_=holder;[HrefToken()];simplemake=human;species=Tajaran;mob=\ref[player]'>Tajaran</A>
<A href='byond://?_src_=holder;[HrefToken()];simplemake=human;species=Skrell;mob=\ref[player]'>Skrell</A> \] | \[
<A href='byond://?_src_=holder;[HrefToken()];simplemake=nymph;mob=\ref[player]'>Nymph</A>
<A href='byond://?_src_=holder;[HrefToken()];simplemake=human;species='Diona';mob=\ref[player]'>Diona</A> \] |
\[ slime: <A href='byond://?_src_=holder;[HrefToken()];simplemake=slime;mob=\ref[player]'>Baby</A>,
<A href='byond://?_src_=holder;[HrefToken()];simplemake=adultslime;mob=\ref[player]'>Adult</A> \]
<A href='byond://?_src_=holder;[HrefToken()];simplemake=monkey;mob=\ref[player]'>Monkey</A> |
<A href='byond://?_src_=holder;[HrefToken()];simplemake=robot;mob=\ref[player]'>Cyborg</A> |
<A href='byond://?_src_=holder;[HrefToken()];simplemake=cat;mob=\ref[player]'>Cat</A> |
<A href='byond://?_src_=holder;[HrefToken()];simplemake=runtime;mob=\ref[player]'>Runtime</A> |
<A href='byond://?_src_=holder;[HrefToken()];simplemake=corgi;mob=\ref[player]'>Corgi</A> |
<A href='byond://?_src_=holder;[HrefToken()];simplemake=ian;mob=\ref[player]'>Ian</A> |
<A href='byond://?_src_=holder;[HrefToken()];simplemake=crab;mob=\ref[player]'>Crab</A> |
<A href='byond://?_src_=holder;[HrefToken()];simplemake=coffee;mob=\ref[player]'>Coffee</A> |
\[ Construct: <A href='byond://?_src_=holder;[HrefToken()];simplemake=constructarmoured;mob=\ref[player]'>Armoured</A> ,
<A href='byond://?_src_=holder;[HrefToken()];simplemake=constructbuilder;mob=\ref[player]'>Builder</A> ,
<A href='byond://?_src_=holder;[HrefToken()];simplemake=constructwraith;mob=\ref[player]'>Wraith</A> \]
<A href='byond://?_src_=holder;[HrefToken()];simplemake=shade;mob=\ref[player]'>Shade</A>
<br>
"}
body += {"<br><br>
"} + span_bold("Other actions:") + {"
<br>
<A href='byond://?src=\ref[src];[HrefToken()];forcespeech=\ref[M]'>Forcesay</A>
<A href='byond://?_src_=holder;[HrefToken()];forcespeech=\ref[player]'>Forcesay</A>
"}
if (M.client)
if (player.client)
body += {" |
<A href='byond://?src=\ref[src];[HrefToken()];tdome1=\ref[M]'>Thunderdome 1</A> |
<A href='byond://?src=\ref[src];[HrefToken()];tdome2=\ref[M]'>Thunderdome 2</A> |
<A href='byond://?src=\ref[src];[HrefToken()];tdomeadmin=\ref[M]'>Thunderdome Admin</A> |
<A href='byond://?src=\ref[src];[HrefToken()];tdomeobserve=\ref[M]'>Thunderdome Observer</A> |
<A href='byond://?_src_=holder;[HrefToken()];tdome1=\ref[player]'>Thunderdome 1</A> |
<A href='byond://?_src_=holder;[HrefToken()];tdome2=\ref[player]'>Thunderdome 2</A> |
<A href='byond://?_src_=holder;[HrefToken()];tdomeadmin=\ref[player]'>Thunderdome Admin</A> |
<A href='byond://?_src_=holder;[HrefToken()];tdomeobserve=\ref[player]'>Thunderdome Observer</A> |
"}
// language toggles
body += "<br><br>" + span_bold("Languages:") + "<br>"
@@ -233,17 +226,17 @@ GLOBAL_VAR_INIT(floorIsLava, 0)
if(!(L.flags & INNATE))
if(!f) body += " | "
else f = 0
if(L in M.languages)
if(L in player.languages)
k = span_green(k)
body += "<a href='byond://?src=\ref[src];[HrefToken()];toglang=\ref[M];lang=[html_encode(k)]'>[k]</a>"
body += "<a href='byond://?_src_=holder;[HrefToken()];toglang=\ref[player];lang=[html_encode(k)]'>[k]</a>"
else
k = span_red(k)
body += "<a href='byond://?src=\ref[src];[HrefToken()];toglang=\ref[M];lang=[html_encode(k)]'>[k]</a>"
body += "<a href='byond://?_src_=holder;[HrefToken()];toglang=\ref[player];lang=[html_encode(k)]'>[k]</a>"
body += {"<br>"}
var/datum/browser/popup = new(owner, "adminplayeropts", "Edit Player", 550, 515)
popup.add_head_content("<title>Options for [M.key]</title>")
var/datum/browser/popup = new(user, "adminplayeropts", "Edit Player", 550, 515)
popup.add_head_content("<title>Options for [player.key]</title>")
popup.set_content(body)
popup.open()

View File

@@ -14,13 +14,11 @@ var/list/admin_verbs_admin = list(
/datum/admins/proc/intercom, //send a fake intercom message, like an arrivals announcement,
/datum/admins/proc/intercom_convo, //send a fake intercom conversation, like an ATC exchange,
/client/proc/admin_ghost, //allows us to ghost/reenter body at will,
/datum/admins/proc/show_player_panel, //shows an interface for individual players, with various links (links require additional flags, //VOREStation Add,
/client/proc/player_panel_new, //shows an interface for all players, with links to various panels, //VOREStation Add,
/client/proc/player_panel, //VOREStation Add,
/client/proc/hide_verbs, //hides all our adminverbs, //VOREStation Add,
/client/proc/hide_most_verbs, //hides all our hideable adminverbs, //VOREStation Add,
/client/proc/debug_variables, //allows us to -see- the variables of any instance in the game. +VAREDIT needed to modify, //VOREStation Add,
/client/proc/mark_datum_mapview, //VOREStation Add,
/client/proc/cmd_check_new_players, //allows us to see every new player, //VOREStation Add,
/client/proc/toggle_view_range, //changes how far we can see,
/client/proc/cmd_admin_pm_context, //right-click adminPM interface,
@@ -106,7 +104,6 @@ var/list/admin_verbs_sounds = list(
var/list/admin_verbs_fun = list(
/client/proc/object_talk,
/datum/admins/proc/cmd_admin_dress,
/client/proc/cmd_admin_gib_self,
/client/proc/drop_bomb,
/client/proc/everyone_random,
/client/proc/cinematic,
@@ -210,20 +207,16 @@ var/list/admin_verbs_debug = list(
/client/proc/delete_random_map,
/client/proc/show_plant_genes,
/client/proc/enable_debug_verbs,
/client/proc/callproc,
/client/proc/callproc_datum,
/client/proc/Jump,
/client/proc/jumptomob,
/client/proc/jumptocoord,
/client/proc/dsay,
/client/proc/admin_ghost, //allows us to ghost/reenter body at will,
/datum/admins/proc/show_player_panel, //shows an interface for individual players, with various links (links require additional flags, //VOREStation Add,
/client/proc/player_panel_new, //shows an interface for all players, with links to various panels, //VOREStation Add,
/client/proc/player_panel, //VOREStation Add,
/client/proc/hide_verbs, //hides all our adminverbs, //VOREStation Add,
/client/proc/hide_most_verbs, //hides all our hideable adminverbs, //VOREStation Add,
/client/proc/debug_variables, //allows us to -see- the variables of any instance in the game. +VAREDIT needed to modify, //VOREStation Add,
/client/proc/mark_datum_mapview, //VOREStation Add,
/client/proc/cmd_check_new_players, //allows us to see every new player, //VOREStation Add,
/datum/admins/proc/view_runtimes,
// /client/proc/show_gm_status, // VOREStation Edit - We don't use SSgame_master yet.
@@ -244,11 +237,6 @@ var/list/admin_verbs_debug = list(
/client/proc/reload_configuration //CHOMPAdd
)
var/list/admin_verbs_paranoid_debug = list(
/client/proc/callproc,
/client/proc/callproc_datum,
)
//verbs which can be hidden - needs work
var/list/admin_verbs_hideable = list(
// /client/proc/deadchat,
@@ -274,7 +262,6 @@ var/list/admin_verbs_hideable = list(
/client/proc/play_web_sound,
/client/proc/object_talk,
/datum/admins/proc/cmd_admin_dress,
/client/proc/cmd_admin_gib_self,
/client/proc/drop_bomb,
/client/proc/cinematic,
/datum/admins/proc/toggle_aliens,
@@ -299,8 +286,6 @@ var/list/admin_verbs_hideable = list(
/datum/admins/proc/adspawn,
/datum/admins/proc/adjump,
/client/proc/cmd_admin_list_open_jobs,
/client/proc/callproc,
/client/proc/callproc_datum,
/client/proc/Debug2,
/client/proc/reload_admins,
/client/proc/kill_air,
@@ -326,19 +311,16 @@ var/list/admin_verbs_mod = list(
/client/proc/debug_variables, //allows us to -see- the variables of any instance in the game.,
/datum/admins/proc/PlayerNotes,
/client/proc/admin_ghost, //allows us to ghost/reenter body at will,
/datum/admins/proc/show_player_panel, //shows an interface for individual players, with various links (links require additional flags, //VOREStation Add,
/client/proc/player_panel_new, //shows an interface for all players, with links to various panels, //VOREStation Add,
/client/proc/player_panel, //VOREStation Add,
/client/proc/hide_verbs, //hides all our adminverbs, //VOREStation Add,
/client/proc/hide_most_verbs, //hides all our hideable adminverbs, //VOREStation Add,
/client/proc/debug_variables, //allows us to -see- the variables of any instance in the game. +VAREDIT needed to modify, //VOREStation Add,
/client/proc/mark_datum_mapview, //VOREStation Add,
/client/proc/cmd_check_new_players, //allows us to see every new player, //VOREStation Add,
/datum/admins/proc/show_player_info,
/datum/admins/proc/show_traitor_panel,
/client/proc/player_panel_new,
/client/proc/dsay,
/datum/admins/proc/show_player_panel,
/client/proc/check_antagonists,
/client/proc/aooc,
/client/proc/cmd_admin_subtle_message, //send an message to somebody as a 'voice in their head',
@@ -357,13 +339,11 @@ var/list/admin_verbs_event_manager = list(
/client/proc/cmd_admin_pm_context,
/client/proc/cmd_admin_pm_panel,
/client/proc/admin_ghost,
/datum/admins/proc/show_player_panel, //shows an interface for individual players, with various links (links require additional flags, //VOREStation Add,
/client/proc/player_panel_new, //shows an interface for all players, with links to various panels, //VOREStation Add,
/client/proc/player_panel, //VOREStation Add,
/client/proc/hide_verbs, //hides all our adminverbs, //VOREStation Add,
/client/proc/hide_most_verbs, //hides all our hideable adminverbs, //VOREStation Add,
/client/proc/debug_variables, //allows us to -see- the variables of any instance in the game. +VAREDIT needed to modify, //VOREStation Add,
/client/proc/mark_datum_mapview, //VOREStation Add,
/client/proc/cmd_check_new_players, //allows us to see every new player, //VOREStation Add,
/datum/admins/proc/show_player_info,
/client/proc/dsay,
@@ -390,7 +370,6 @@ var/list/admin_verbs_event_manager = list(
/client/proc/make_sound,
/client/proc/toggle_random_events,
/datum/admins/proc/cmd_admin_dress,
/client/proc/cmd_admin_gib_self,
/client/proc/drop_bomb,
/client/proc/cmd_admin_add_freeform_ai_law,
/client/proc/cmd_admin_add_random_ai_law,
@@ -401,8 +380,6 @@ var/list/admin_verbs_event_manager = list(
/datum/admins/proc/call_supply_drop,
/datum/admins/proc/call_drop_pod,
/datum/admins/proc/PlayerNotes,
/client/proc/callproc,
/client/proc/callproc_datum,
/datum/admins/proc/change_weather,
/datum/admins/proc/change_time,
/client/proc/cmd_regenerate_asset_cache,
@@ -410,7 +387,6 @@ var/list/admin_verbs_event_manager = list(
/client/proc/cmd_reload_robot_sprite_test,
/client/proc/admin_give_modifier,
/datum/admins/proc/cmd_admin_dress,
/client/proc/cmd_admin_gib_self,
/datum/admins/proc/set_tcrystals,
/datum/admins/proc/add_tcrystals,
/client/proc/invisimin, //allows our mob to go invisible/visible,

View File

@@ -2,19 +2,15 @@
// OLD ADMIN VERB SYSTEM
var/rights = holder.rank_flags()
if(rights & R_HOLDER)
if(rights & R_BUILDMODE) add_verb(src, /client/proc/togglebuildmodeself)
if(rights & R_ADMIN) add_verb(src, admin_verbs_admin)
if(rights & R_BUILDMODE) add_verb(src, /client/proc/togglebuildmodeself)
if(rights & R_ADMIN) add_verb(src, admin_verbs_admin)
if(rights & R_FUN) add_verb(src, admin_verbs_fun)
if(rights & R_SERVER) add_verb(src, admin_verbs_server)
if(rights & R_DEBUG)
add_verb(src, admin_verbs_debug)
if(CONFIG_GET(flag/debugparanoid) && !(rights & R_ADMIN))
remove_verb(src, admin_verbs_paranoid_debug) //Right now it's just callproc but we can easily add others later on.
if(rights & R_STEALTH) add_verb(src, /client/proc/stealth)
if(rights & R_DEBUG) add_verb(src, admin_verbs_debug)
if(rights & R_SOUNDS) add_verb(src, admin_verbs_sounds)
if(rights & R_SPAWN) add_verb(src, admin_verbs_spawn)
if(rights & R_SPAWN) add_verb(src, admin_verbs_spawn)
if(rights & R_MOD) add_verb(src, admin_verbs_mod)
if(rights & R_EVENT) add_verb(src, admin_verbs_event_manager)
if(rights & R_EVENT) add_verb(src, admin_verbs_event_manager)
// NEW ADMIN VERBS SYSTEM
SSadmin_verbs.assosciate_admin(src)
@@ -27,7 +23,6 @@
admin_verbs_fun,
admin_verbs_server,
admin_verbs_debug,
/client/proc/stealth,
admin_verbs_sounds,
admin_verbs_spawn,
debug_verbs
@@ -217,25 +212,22 @@ ADMIN_VERB(game_panel, R_ADMIN|R_SERVER|R_FUN, "Game Panel", "Look at the state
i = 0
GLOB.stealthminID["[ckey]"] = "@[num2text(num)]"
/client/proc/stealth()
set category = "Admin.Game"
set name = "Stealth Mode"
if(check_rights(R_HOLDER))
if(holder.fakekey)
holder.fakekey = null
if(isnewplayer(src.mob))
mob.name = capitalize(ckey)
else
var/new_key = ckeyEx(tgui_input_text(usr, "Enter your desired display name.", "Fake Key", key))
if(!new_key)
return
if(length(new_key) >= 26)
new_key = copytext(new_key, 1, 26)
holder.fakekey = new_key
createStealthKey()
if(isnewplayer(mob))
mob.name = new_key
log_and_message_admins("has turned stealth mode [holder.fakekey ? "ON" : "OFF"]", usr)
ADMIN_VERB(stealth, R_STEALTH, "Stealth Mode", "Toggle stealth.", "Admin.Game")
if(user.holder.fakekey)
user.holder.fakekey = null
if(isnewplayer(user.mob))
user.mob.name = capitalize(user.ckey)
else
var/new_key = ckeyEx(tgui_input_text(user, "Enter your desired display name.", "Fake Key", user.key))
if(!new_key)
return
if(length(new_key) >= 26)
new_key = copytext(new_key, 1, 26)
user.holder.fakekey = new_key
user.createStealthKey()
if(isnewplayer(user.mob))
user.mob.name = new_key
log_and_message_admins("has turned stealth mode [user.holder.fakekey ? "ON" : "OFF"]", usr)
feedback_add_details("admin_verb","SM") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
#define MAX_WARNS 3
@@ -532,16 +524,35 @@ ADMIN_VERB(deadmin, R_NONE, "DeAdmin", "Shed your admin powers.", ADMIN_CATEGORY
log_admin("[key_name(usr)] told everyone to man up and deal with it.")
message_admins(span_blue("[key_name_admin(usr)] told everyone to man up and deal with it."), 1)
/client/proc/give_spell(mob/T as mob in mob_list) // -- Urist
set category = "Fun.Event Kit"
set name = "Give Spell"
set desc = "Gives a spell to a mob."
var/spell/S = tgui_input_list(usr, "Choose the spell to give to that guy", "ABRAKADABRA", spells)
if(!S) return
T.spell_list += new S
ADMIN_VERB(give_spell, R_FUN, "Give Spell", ADMIN_VERB_NO_DESCRIPTION, ADMIN_CATEGORY_HIDDEN, mob/spell_recipient)
var/spell/S = tgui_input_list(user, "Choose the spell to give to that guy", "ABRAKADABRA", spells)
if(!S)
return
spell_recipient.spell_list += new S
feedback_add_details("admin_verb","GS") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
log_admin("[key_name(usr)] gave [key_name(T)] the spell [S].")
message_admins(span_blue("[key_name_admin(usr)] gave [key_name(T)] the spell [S]."), 1)
log_admin("[key_name(usr)] gave [key_name(spell_recipient)] the spell [S].")
message_admins(span_blue("[key_name_admin(usr)] gave [key_name(spell_recipient)] the spell [S]."), 1)
ADMIN_VERB(remove_spell, R_FUN, "Remove Spell", ADMIN_VERB_NO_DESCRIPTION, ADMIN_CATEGORY_HIDDEN, mob/removal_target)
var/list/target_spell_list = list()
for(var/spell/spell in removal_target.spell_list)
target_spell_list[spell.name] = spell
if(!length(target_spell_list))
return
var/chosen_spell = tgui_input_list(user, "Choose the spell to remove from [removal_target]", "ABRAKADABRA", sortList(target_spell_list))
if(isnull(chosen_spell))
return
var/spell/to_remove = target_spell_list[chosen_spell]
if(!istype(to_remove))
return
qdel(to_remove)
log_admin("[key_name(user)] removed the spell [chosen_spell] from [key_name(removal_target)].")
message_admins("[key_name_admin(user)] removed the spell [chosen_spell] from [key_name_admin(removal_target)].")
feedback_add_details("admin_verb","RS") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
//BLACKBOX_LOG_ADMIN_VERB("Remove Spell")
ADMIN_VERB(debug_statpanel, R_DEBUG, "Debug Stat Panel", "Toggles local debug of the stat panel", "Debug.Misc")
user.stat_panel.send_message("create_debug")

View File

@@ -1,75 +1,169 @@
/client/proc/callproc()
set category = "Debug.Events"
set name = "Advanced ProcCall"
set waitfor = 0
GLOBAL_DATUM_INIT(AdminProcCallHandler, /mob/proccall_handler, new())
GLOBAL_PROTECT(AdminProcCallHandler)
/// Used to handle proccalls called indirectly by an admin (e.g. tgs, circuits).
/// Has to be a mob because IsAdminAdvancedProcCall() checks usr, which is a mob variable.
/// So usr is set to this for any proccalls that don't have any usr mob/client to refer to.
/mob/proccall_handler
name = "ProcCall Handler"
desc = "If you are seeing this, tell a coder."
var/list/callers = list()
invisibility = INVISIBILITY_ABSTRACT
density = FALSE
/// Adds a caller.
/mob/proccall_handler/proc/add_caller(caller_name)
callers += caller_name
name = "[initial(name)] ([callers.Join(") (")])"
/// Removes a caller.
/mob/proccall_handler/proc/remove_caller(caller_name)
callers -= caller_name
name = "[initial(name)] ([callers.Join(") (")])"
/mob/proccall_handler/Initialize(mapload)
. = ..()
if(GLOB.AdminProcCallHandler && GLOB.AdminProcCallHandler != src)
return INITIALIZE_HINT_QDEL
GLOB.AdminProcCallHandler = src
/mob/proccall_handler/vv_edit_var(var_name, var_value)
if(GLOB.AdminProcCallHandler != src)
return ..()
return FALSE
/mob/proccall_handler/vv_do_topic(list/href_list)
if(GLOB.AdminProcCallHandler != src)
return ..()
return FALSE
/mob/proccall_handler/CanProcCall(procname)
if(GLOB.AdminProcCallHandler != src)
return ..()
return FALSE
// Shit will break if this is allowed to be deleted
/mob/proccall_handler/Destroy(force)
if(GLOB.AdminProcCallHandler != src)
return ..()
if(!force)
stack_trace("Attempted deletion on [type] - [name], aborting.")
return QDEL_HINT_LETMELIVE
return ..()
/**
* Handles a userless proccall, used by circuits.
*
* Arguments:
* * user - a string used to identify the user
* * target - the target to proccall on
* * proc - the proc to call
* * arguments - any arguments
*/
/proc/HandleUserlessProcCall(user, datum/target, procname, list/arguments)
if(IsAdminAdvancedProcCall())
return
var/mob/proccall_handler/handler = GLOB.AdminProcCallHandler
handler.add_caller(user)
var/lastusr = usr
usr = handler
. = WrapAdminProcCall(target, procname, arguments)
usr = lastusr
handler.remove_caller(user)
/**
* Handles a userless sdql, used by circuits and tgs.
*
* Arguments:
* * user - a string used to identify the user
* * query_text - the query text
*/
/proc/HandleUserlessSDQL(user, query_text)
if(IsAdminAdvancedProcCall())
return
var/mob/proccall_handler/handler = GLOB.AdminProcCallHandler
handler.add_caller(user)
var/lastusr = usr
usr = handler
. = world.SDQL2_query(query_text, user, user)
usr = lastusr
handler.remove_caller(user)
ADMIN_VERB(advanced_proc_call, R_DEBUG, "Advanced ProcCall", "Call a proc on any datum in the server.", ADMIN_CATEGORY_DEBUG)
user.callproc_blocking()
/client/proc/callproc_blocking(list/get_retval)
if(!check_rights(R_DEBUG))
return
var/datum/target = null
var/targetselected = 0
var/returnval = null
var/datum/target
var/targetselected = FALSE
var/returnval
switch(tgui_alert(usr, "Proc owned by something?","Call Proc",list("Yes","No")))
if(null)
return
switch(tgui_alert(usr, "Proc owned by something?",,list("Yes","No")))
if("Yes")
targetselected = 1
var/list/value = vv_get_value(default_class = VV_ATOM_REFERENCE, classes = list(VV_ATOM_REFERENCE, VV_DATUM_REFERENCE, VV_MOB_REFERENCE, VV_CLIENT))
targetselected = TRUE
var/list/value = vv_get_value(default_class = VV_ATOM_REFERENCE, classes = list(VV_ATOM_REFERENCE, VV_DATUM_REFERENCE, VV_MOB_REFERENCE, VV_CLIENT, VV_MARKED_DATUM, VV_TEXT_LOCATE, VV_PROCCALL_RETVAL))
if (!value["class"] || !value["value"])
return
target = value["value"]
if(!istype(target))
to_chat(usr, span_danger("Invalid target."), confidential = TRUE)
return
if("No")
target = null
targetselected = 0
targetselected = FALSE
var/procname = tgui_input_text(usr, "Proc path, eg: /proc/fake_blood","Path:", null)
if(!procname)
var/procpath = tgui_input_text(usr, "Proc path, eg: /proc/fake_blood","Path:", null)
if(!procpath)
return
//hascall() doesn't support proc paths (eg: /proc/gib(), it only supports "gib")
var/testname = procname
//strip away everything but the proc name
var/list/proclist = splittext(procpath, "/")
if (!length(proclist))
return
var/procname = proclist[proclist.len]
var/proctype = ("verb" in proclist) ? "verb" :"proc"
if(targetselected)
//Find one of the 3 possible ways they could have written /proc/PROCNAME
if(findtext(procname, "/proc/"))
testname = replacetext(procname, "/proc/", "")
else if(findtext(procname, "/proc"))
testname = replacetext(procname, "/proc", "")
else if(findtext(procname, "proc/"))
testname = replacetext(procname, "proc/", "")
//Clear out any parenthesis if they're a dummy
testname = replacetext(testname, "()", "")
if(targetselected && !hascall(target,testname))
to_chat(usr, span_filter_adminlog(span_red("Error: callproc(): type [target.type] has no proc named [procname].")))
return
else
var/procpath = text2path(procname)
if (!procpath)
to_chat(usr, span_filter_adminlog(span_red("Error: callproc(): proc [procname] does not exist. (Did you forget the /proc/ part?)")))
if(!hascall(target, procname))
to_chat(usr, span_warning("Error: callproc(): type [target.type] has no [proctype] named [procpath]."), confidential = TRUE)
return
else
procpath = "/[proctype]/[procname]"
if(!text2path(procpath))
to_chat(usr, span_warning("Error: callproc(): [procpath] does not exist."), confidential = TRUE)
return
var/list/lst = get_callproc_args()
if(!lst)
return
if(targetselected)
if(!target)
to_chat(usr, span_filter_adminlog(span_red("Error: callproc(): owner of proc no longer exists.")))
to_chat(usr, span_red("Error: callproc(): owner of proc no longer exists."), confidential = TRUE)
return
var/msg = "[key_name(src)] called [target]'s [procname]() with [lst.len ? "the arguments [list2params(lst)]":"no arguments"]."
log_admin(msg)
//message_admins(msg) //Proccall announce removed.
message_admins(msg) //Proccall announce removed.
admin_ticket_log(target, msg)
returnval = WrapAdminProcCall(target, procname, lst) // Pass the lst as an argument list to the proc
else
//this currently has no hascall protection. wasn't able to get it working.
log_admin("[key_name(src)] called [procname]() with [lst.len ? "the arguments [list2params(lst)]":"no arguments"].")
//message_admins("[key_name(src)] called [procname]() with [lst.len ? "the arguments [list2params(lst)]":"no arguments"].") //Proccall announce removed.
message_admins("[key_name(src)] called [procname]() with [lst.len ? "the arguments [list2params(lst)]":"no arguments"].") //Proccall announce removed.
returnval = WrapAdminProcCall(GLOBAL_PROC, procname, lst) // Pass the lst as an argument list to the proc
feedback_add_details("admin_verb","APC") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
//BLACKBOX_LOG_ADMIN_VERB("Advanced ProcCall")
if(get_retval)
get_retval += returnval
. = get_callproc_returnval(returnval, procname)
if(.)
to_chat(usr, .)
feedback_add_details("admin_verb","APC") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
to_chat(usr, ., confidential = TRUE)
GLOBAL_VAR(AdminProcCaller)
GLOBAL_PROTECT(AdminProcCaller)
@@ -81,43 +175,47 @@ GLOBAL_VAR(LastAdminCalledTarget)
GLOBAL_PROTECT(LastAdminCalledTarget)
GLOBAL_VAR(LastAdminCalledProc)
GLOBAL_PROTECT(LastAdminCalledProc)
GLOBAL_LIST_EMPTY(AdminProcCallSpamPrevention)
GLOBAL_PROTECT(AdminProcCallSpamPrevention)
/// Wrapper for proccalls where the datum is flagged as vareditted
/proc/WrapAdminProcCall(datum/target, procname, list/arguments)
if(target && procname == "Del")
to_chat(usr, span_filter_adminlog("Calling Del() is not allowed"))
to_chat(usr, "Calling Del() is not allowed", confidential = TRUE)
return
if(target != GLOBAL_PROC && !target.CanProcCall(procname))
to_chat(usr, span_filter_adminlog("Proccall on [target.type]/proc/[procname] is disallowed!"))
to_chat(usr, "Proccall on [target.type]/proc/[procname] is disallowed!", confidential = TRUE)
return
var/current_caller = GLOB.AdminProcCaller
var/ckey = usr ? usr.client.ckey : GLOB.AdminProcCaller
if(!ckey)
var/user_identifier = usr ? usr.client?.ckey : GLOB.AdminProcCaller
var/is_remote_handler = usr == GLOB.AdminProcCallHandler
if(is_remote_handler)
user_identifier = GLOB.AdminProcCallHandler.name
if(!user_identifier)
CRASH("WrapAdminProcCall with no ckey: [target] [procname] [english_list(arguments)]")
if(current_caller && current_caller != ckey)
if(!GLOB.AdminProcCallSpamPrevention[ckey])
to_chat(usr, span_adminnotice("Another set of admin called procs are still running, your proc will be run after theirs finish."))
GLOB.AdminProcCallSpamPrevention[ckey] = TRUE
UNTIL(!GLOB.AdminProcCaller)
to_chat(usr, span_adminnotice("Running your proc"))
GLOB.AdminProcCallSpamPrevention -= ckey
else
UNTIL(!GLOB.AdminProcCaller)
if(!is_remote_handler && current_caller && current_caller != user_identifier)
to_chat(usr, span_adminnotice("Another set of admin called procs are still running. Try again later."), confidential = TRUE)
return
GLOB.LastAdminCalledProc = procname
if(target != GLOBAL_PROC)
GLOB.LastAdminCalledTargetRef = "\ref[target]"
GLOB.AdminProcCaller = ckey //if this runtimes, too bad for you
++GLOB.AdminProcCallCount
. = world.WrapAdminProcCall(target, procname, arguments)
if(--GLOB.AdminProcCallCount == 0)
GLOB.AdminProcCaller = null
GLOB.LastAdminCalledTargetRef = REF(target)
if(!is_remote_handler)
GLOB.AdminProcCaller = user_identifier //if this runtimes, too bad for you
++GLOB.AdminProcCallCount
. = world.WrapAdminProcCall(target, procname, arguments)
GLOB.AdminProcCallCount--
if(GLOB.AdminProcCallCount == 0)
GLOB.AdminProcCaller = null
else
. = world.WrapAdminProcCall(target, procname, arguments)
//adv proc call this, ya nerds
/world/proc/WrapAdminProcCall(datum/target, procname, list/arguments)
if(target == GLOBAL_PROC)
return call(procname)(arglist(arguments))
return call("/proc/[procname]")(arglist(arguments))
else if(target != world)
return call(target, procname)(arglist(arguments))
else
@@ -127,66 +225,53 @@ GLOBAL_PROTECT(AdminProcCallSpamPrevention)
#ifdef TESTING
return FALSE
#else
return usr && usr.client && GLOB.AdminProcCaller == usr.client.ckey
return (GLOB.AdminProcCaller && GLOB.AdminProcCaller == usr?.client?.ckey) || (GLOB.AdminProcCallHandler && usr == GLOB.AdminProcCallHandler)
#endif
/client/proc/callproc_datum(datum/A as null|area|mob|obj|turf)
set category = "Debug.Events"
set name = "Atom ProcCall"
set waitfor = 0
if(!check_rights(R_DEBUG))
return
var/procname = tgui_input_text(usr, "Proc name, eg: fake_blood","Proc:")
ADMIN_VERB_ONLY_CONTEXT_MENU(call_proc_datum, R_DEBUG, "Atom ProcCall", datum/thing as null|area|mob|obj|turf)
var/procname = tgui_input_text(user, "Proc name, eg: fake_blood","Proc:", null)
if(!procname)
return
if(!hascall(A,procname))
to_chat(usr, span_filter_adminlog(span_red("Error: callproc_datum(): type [A.type] has no proc named [procname].")))
if(!hascall(thing, procname))
to_chat(user, span_red("Error: callproc_datum(): type [thing.type] has no proc named [procname]."), confidential = TRUE)
return
var/list/lst = get_callproc_args()
var/list/lst = user.get_callproc_args()
if(!lst)
return
if(!A || !IsValidSrc(A))
to_chat(usr, span_warning("Error: callproc_datum(): owner of proc no longer exists."))
if(!thing || !is_valid_src(thing))
to_chat(user, span_warning("Error: callproc_datum(): owner of proc no longer exists."), confidential = TRUE)
return
var/msg = "[key_name(src)] called [A]'s [procname]() with [lst.len ? "the arguments [list2params(lst)]":"no arguments"]."
log_admin(msg)
//message_admins(msg)
admin_ticket_log(A, msg)
log_admin("[key_name(user)] called [thing]'s [procname]() with [lst.len ? "the arguments [list2params(lst)]":"no arguments"].")
var/msg = "[key_name(user)] called [thing]'s [procname]() with [lst.len ? "the arguments [list2params(lst)]":"no arguments"]."
message_admins(msg)
admin_ticket_log(thing, msg)
feedback_add_details("admin_verb","TPC") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
//BLACKBOX_LOG_ADMIN_VERB("Atom ProcCall")
var/returnval = WrapAdminProcCall(A, procname, lst) // Pass the lst as an argument list to the proc
. = get_callproc_returnval(returnval,procname)
var/returnval = WrapAdminProcCall(thing, procname, lst) // Pass the lst as an argument list to the proc
. = user.get_callproc_returnval(returnval,procname)
if(.)
to_chat(usr, .)
to_chat(user, ., confidential = TRUE)
/client/proc/get_callproc_args()
var/argnum = tgui_input_number(usr, "Number of arguments","Number:",0)
if(isnull(argnum))
return null //Cancel
return
. = list()
//var/list/named_args = list() //Named arguments are removed, due to them making proccalling take too long.
var/list/named_args = list()
while(argnum--)
/* //Named arguments are removed, due to them making proccalling take too long.
var/named_arg = tgui_input_text(usr,"Leave blank for positional argument. Positional arguments will be considered as if they were added first.", "Named argument")
if(isnull(named_arg))
return null //Cancel
*/
var/named_arg = tgui_input_text(usr, "Leave blank for positional argument. Positional arguments will be considered as if they were added first.", "Named argument")
var/value = vv_get_value(restricted_classes = list(VV_RESTORE_DEFAULT))
if (!value["class"])
return null //Cancel
/* //Named arguments are removed, due to them making proccalling take too long.
return
if(named_arg)
named_args[named_arg] = value["value"]
else
. += value["value"]
. += LIST_VALUE_WRAP_LISTS(value["value"])
if(LAZYLEN(named_args))
. += named_args
*/
. += value["value"]
/client/proc/get_callproc_returnval(returnval,procname)
. = ""

View File

@@ -21,6 +21,7 @@ GLOBAL_PROTECT(href_token)
var/datum/feed_channel/admincaster_feed_channel = new /datum/feed_channel
var/admincaster_signature //What you'll sign the newsfeeds as
/// Code security critcal token used for authorizing href topic calls
var/href_token
/// Link from the database pointing to the admin's feedback forum
@@ -28,6 +29,12 @@ GLOBAL_PROTECT(href_token)
var/deadmined
var/datum/filter_editor/filteriffic
var/datum/particle_editor/particle_test
/// A lazylist of tagged datums, for quick reference with the View Tags verb
var/list/tagged_datums
var/given_profiling = FALSE
@@ -250,19 +257,6 @@ you will have to do something like if(client.rights & R_ADMIN) yourself.
return subject.holder.check_for_rights(rights_required)
return FALSE
/client/proc/mark_datum(datum/D)
if(!holder)
return
if(holder.marked_datum)
vv_update_display(holder.marked_datum, "marked", "")
holder.marked_datum = D
vv_update_display(D, "marked", VV_MSG_MARKED)
/client/proc/mark_datum_mapview(datum/D as mob|obj|turf|area in view(view))
set category = "Debug.Game"
set name = "Mark Object"
mark_datum(D)
/proc/GenerateToken()
. = ""
for(var/I in 1 to 32)

View File

@@ -160,7 +160,7 @@
/datum/eventkit/modify_robot/tgui_state(mob/user)
return GLOB.tgui_admin_state
return ADMIN_STATE(R_ADMIN|R_EVENT|R_DEBUG)
/datum/eventkit/modify_robot/tgui_act(action, params, datum/tgui/ui)
. = ..()

View File

@@ -223,7 +223,7 @@ ADMIN_VERB(edit_admin_permissions, R_PERMISSIONS, "Permissions Panel", "Edit adm
if(admin_ckey)
. = admin_ckey
else
admin_key = input("New admin's key","Admin key") as text|null
admin_key = tgui_input_text(usr, "New admin's key","Admin key")
. = ckey(admin_key)
if(!.)
return FALSE
@@ -333,7 +333,7 @@ ADMIN_VERB(edit_admin_permissions, R_PERMISSIONS, "Permissions Panel", "Edit adm
if (!(rank_name in display_rank_names))
display_rank_names += rank_name
var/next_rank = input("Please select a rank, or select [RANK_DONE] if you are finished.") as null|anything in display_rank_names
var/next_rank = tgui_input_list(usr, "Please select a rank, or select [RANK_DONE] if you are finished.", "Pick Rank", display_rank_names)
if (isnull(next_rank))
return
@@ -350,7 +350,7 @@ ADMIN_VERB(edit_admin_permissions, R_PERMISSIONS, "Permissions Panel", "Edit adm
continue
if (next_rank == "*New Rank*")
var/new_rank_name = input("Please input a new rank", "New custom rank") as text|null
var/new_rank_name = tgui_input_text(usr, "Please input a new rank", "New custom rank")
if (!new_rank_name)
return

View File

@@ -37,7 +37,7 @@
return data
/datum/eventkit/player_effects/tgui_state(mob/user)
return GLOB.tgui_admin_state
return ADMIN_STATE(R_ADMIN|R_EVENT|R_DEBUG)
/datum/eventkit/player_effects/tgui_act(action, list/params, datum/tgui/ui)
. = ..()
@@ -724,7 +724,7 @@
user.client.cmd_admin_direct_narrate(target)
if("player_panel")
user.client.holder.show_player_panel(target)
SSadmin_verbs.dynamic_invoke_verb(user, /datum/admin_verb/show_player_panel, target)
if("view_variables")
user.client.debug_variables(target)

102
code/modules/admin/tag.dm Normal file
View File

@@ -0,0 +1,102 @@
/**
* Inserts the target_datum into [/datum/admins/var/tagged_datums], for later reference.
*
* Arguments:
* * target_datum - The datum you want to create a tag for
*/
/datum/admins/proc/add_tagged_datum(datum/target_datum)
if(LAZYFIND(tagged_datums, target_datum))
to_chat(owner, span_warning("[target_datum] is already tagged!"))
return
LAZYADD(tagged_datums, target_datum)
RegisterSignal(target_datum, COMSIG_PARENT_QDELETING, PROC_REF(handle_tagged_del), override = TRUE)
to_chat(owner, span_notice("[target_datum] has been tagged."))
/// Get ahead of the curve with deleting
/datum/admins/proc/handle_tagged_del(datum/source)
SIGNAL_HANDLER
if(owner)
to_chat(owner, span_boldnotice("Tagged datum [source] ([source.type]) has been deleted."))
remove_tagged_datum(source, silent = TRUE)
/**
* Attempts to remove the specified datum from [/datum/admins/var/tagged_datums] if it exists
*
* Arguments:
* * target_datum - The datum you want to remove from the tagged_datums list
* * silent - If TRUE, won't print messages to the owner's chat
*/
/datum/admins/proc/remove_tagged_datum(datum/target_datum, silent=FALSE)
if(!istype(target_datum))
return
if(LAZYFIND(tagged_datums, target_datum))
LAZYREMOVE(tagged_datums, target_datum)
if(!silent)
to_chat(owner, span_notice("[target_datum] has been untagged."))
else if(!silent)
to_chat(owner, span_warning("[target_datum] was not already tagged."))
/// Quick define for readability
#define TAG_DEL(X) span_bold("(<A href='byond://?_src_=holder;[HrefToken(forceGlobal = TRUE)];del_tag=[REF(X)]'>UNTAG</a>)")
#define TAG_MARK(X) span_bold("(<A href='byond://?_src_=holder;[HrefToken(forceGlobal = TRUE)];mark_datum=[REF(X)]'>MARK</a>)")
#define TAG_SIMPLE_HEALTH(X) span_red(span_bold("Health: [X.health]"))
#define TAG_CARBON_HEALTH(X) span_red(span_bold("Health: [X.health]")) +" (\
" + span_brute("[X.getBruteLoss()]") + " \
" + span_burn("[X.getFireLoss()]") + " \
" + span_tox("[X.getToxLoss()]") + " \
" + span_oxy("[X.getOxyLoss()]") + " \
" + span_clone("[X.getCloneLoss()]")
ADMIN_VERB(display_tags, R_ADMIN, "View Tags", "Display all of the tagged datums.", ADMIN_CATEGORY_GAME)
var/index = 0
var/list/dat = list()
var/list/tagged_datums = user.holder.tagged_datums
var/list/marked_datum = user.holder.marked_datum
dat += "<br><a href='byond://?_src_=holder;[HrefToken(forceGlobal = TRUE)];show_tags=1'>Refresh</a><br>"
if(LAZYLEN(tagged_datums))
for(var/datum/iter_datum as anything in tagged_datums)
index++
var/specific_info
if(isnull(iter_datum))
dat += "\t[index]: Null reference - Check runtime logs!"
stack_trace("Null datum found in tagged datum menu! User: [user]")
continue
else if(iscarbon(iter_datum))
var/mob/living/carbon/resolved_carbon = iter_datum
specific_info = "[TAG_CARBON_HEALTH(resolved_carbon)] | [AREACOORD(resolved_carbon)] [ADMIN_PP(iter_datum)] [ADMIN_FLW(iter_datum)]"
else if(isliving(iter_datum))
var/mob/living/resolved_living = iter_datum
specific_info = "[TAG_SIMPLE_HEALTH(resolved_living)] | [AREACOORD(resolved_living)] [ADMIN_PP(iter_datum)] [ADMIN_FLW(iter_datum)]"
else if(ismob(iter_datum))
var/atom/resolved_atom = iter_datum // needed for ADMIN_JMP
specific_info = "[AREACOORD(resolved_atom)] [ADMIN_PP(iter_datum)] [ADMIN_FLW(iter_datum)]"
else if(ismovable(iter_datum))
var/atom/resolved_atom = iter_datum // needed for ADMIN_JMP
specific_info = "[AREACOORD(resolved_atom)] [ADMIN_FLW(iter_datum)]"
else if(isatom(iter_datum))
var/atom/resolved_atom = iter_datum // needed for ADMIN_JMP
specific_info = "[AREACOORD(resolved_atom)] [ADMIN_JMP(resolved_atom)]"
else if(istype(iter_datum, /datum/controller/subsystem))
var/datum/controller/subsystem/resolved_subsystem = iter_datum
specific_info = "[resolved_subsystem.stat_entry()]"
// else, it's just a /datum
dat += "\t[index]: [iter_datum] | [specific_info] | [ADMIN_VV(iter_datum)] | [TAG_DEL(iter_datum)] | [iter_datum == marked_datum ? "<b>Marked</b>" : TAG_MARK(iter_datum)] "
dat += "\t(" + span_bold(span_normal("[iter_datum.type])"))
else
dat += "No datums tagged :("
var/datum/browser/browser = new(user.mob, "tag", "Tag Menu", 800, 480)
browser.set_content(dat.Join("<br>"))
browser.open()
#undef TAG_DEL
#undef TAG_MARK
#undef TAG_SIMPLE_HEALTH
#undef TAG_CARBON_HEALTH

View File

@@ -1245,11 +1245,11 @@
return
var/block=text2num(href_list["block"])
usr.client.cmd_admin_toggle_block(H,block)
show_player_panel(H)
SSadmin_verbs.dynamic_invoke_verb(usr.client, /datum/admin_verb/show_player_panel, H)
else if(href_list["adminplayeropts"])
var/mob/M = locate(href_list["adminplayeropts"])
show_player_panel(M)
SSadmin_verbs.dynamic_invoke_verb(usr.client, /datum/admin_verb/show_player_panel, M)
else if(href_list["adminplayerobservejump"])
if(!check_rights(R_MOD|R_ADMIN|R_SERVER)) return //VOREStation Edit
@@ -1958,7 +1958,7 @@
if(!M.add_language(lang2toggle))
to_chat(usr, span_filter_adminlog("Failed to add language '[lang2toggle]' from \the [M]!"))
show_player_panel(M)
SSadmin_verbs.dynamic_invoke_verb(usr.client, /datum/admin_verb/show_player_panel, M)
else if(href_list["cryoplayer"])
if(!check_rights(R_ADMIN|R_EVENT)) return

View File

@@ -0,0 +1,75 @@
ADMIN_VERB(admin_explosion, R_ADMIN|R_FUN, "Explosion", ADMIN_VERB_NO_DESCRIPTION, ADMIN_CATEGORY_HIDDEN, atom/orignator as obj|mob|turf)
var/devastation = tgui_input_number(user, "Range of total devastation. -1 to none", text("Input"), min_value=-1)
if(devastation == null)
return
var/heavy = tgui_input_number(user, "Range of heavy impact. -1 to none", text("Input"), min_value=-1)
if(heavy == null)
return
var/light = tgui_input_number(user, "Range of light impact. -1 to none", text("Input"), min_value=-1)
if(light == null)
return
var/flash = tgui_input_number(user, "Range of flash. -1 to none", text("Input"), min_value=-1)
if(flash == null)
return
if ((devastation != -1) || (heavy != -1) || (light != -1) || (flash != -1))
if ((devastation > 20) || (heavy > 20) || (light > 20))
if (tgui_alert(user, "Are you sure you want to do this? It will laaag.", "Confirmation", list("Yes", "No")) != "Yes")
return
explosion(orignator, devastation, heavy, light, flash)
log_admin("[key_name(user)] created an explosion ([devastation],[heavy],[light],[flash]) at ([orignator.x],[orignator.y],[orignator.z])")
message_admins("[key_name_admin(user)] created an explosion ([devastation],[heavy],[light],[flash]) at ([orignator.x],[orignator.y],[orignator.z])", 1)
feedback_add_details("admin_verb","EXPL") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
ADMIN_VERB(admin_emp, R_ADMIN|R_FUN, "EM Pulse", ADMIN_VERB_NO_DESCRIPTION, ADMIN_CATEGORY_HIDDEN, atom/orignator as obj|mob|turf)
var/heavy = tgui_input_number(user, "Range of heavy pulse.", text("Input"))
if(heavy == null)
return
var/med = tgui_input_number(user, "Range of medium pulse.", text("Input"))
if(med == null)
return
var/light = tgui_input_number(user, "Range of light pulse.", text("Input"))
if(light == null)
return
var/long = tgui_input_number(user, "Range of long pulse.", text("Input"))
if(long == null)
return
if (heavy || med || light || long)
empulse(orignator, heavy, med, light, long)
log_admin("[key_name(user)] created an EM Pulse ([heavy],[med],[light],[long]) at ([orignator.x],[orignator.y],[orignator.z])")
message_admins("[key_name_admin(user)] created an EM PUlse ([heavy],[med],[light],[long]) at ([orignator.x],[orignator.y],[orignator.z])", 1)
feedback_add_details("admin_verb","EMP") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
ADMIN_VERB(gib_them, (R_ADMIN|R_FUN), "Gib", ADMIN_VERB_NO_DESCRIPTION, ADMIN_CATEGORY_HIDDEN, mob/victim in mob_list)
var/confirm = tgui_alert(user, "You sure?", "Confirm", list("Yes", "No"))
if(confirm != "Yes")
return
//Due to the delay here its easy for something to have happened to the mob
if(!victim)
return
log_admin("[key_name(user)] has gibbed [key_name(victim)]")
message_admins("[key_name_admin(user)] has gibbed [key_name_admin(victim)]", 1)
if(isobserver(victim))
gibs(victim.loc)
return
victim.gib()
feedback_add_details("admin_verb","GIB") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
ADMIN_VERB(gib_self, R_HOLDER, "Gibself", "Give yourself the same treatment you give others.", ADMIN_CATEGORY_FUN)
var/confirm = tgui_alert(user, "You sure?", "Confirm", list("Yes", "No"))
if(!confirm)
return
if(confirm == "Yes")
if (isobserver(user.mob)) // so they don't spam gibs everywhere
return
else
user.mob.gib()
log_admin("[key_name(user)] used gibself.")
message_admins(span_blue("[key_name_admin(user)] used gibself."), 1)
feedback_add_details("admin_verb","GIBS") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!

View File

@@ -9,7 +9,7 @@
if(!H) return
log_and_message_admins("is altering the appearance of [H].")
H.change_appearance(APPEARANCE_ALL, usr, check_species_whitelist = 0, state = GLOB.tgui_admin_state)
H.change_appearance(APPEARANCE_ALL, usr, check_species_whitelist = 0, state = ADMIN_STATE(R_FUN))
feedback_add_details("admin_verb","CHAA") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
/client/proc/change_human_appearance_self()

View File

@@ -304,22 +304,21 @@
log_admin("[key_name(src)] has granted [M.key] full access.")
message_admins(span_blue("[key_name_admin(usr)] has granted [M.key] full access."), 1)
/client/proc/cmd_assume_direct_control(var/mob/M in mob_list)
set category = "Admin.Game"
set name = "Assume direct control"
set desc = "Direct intervention"
if(!check_rights(R_DEBUG|R_ADMIN|R_EVENT)) return
ADMIN_VERB(cmd_assume_direct_control, (R_DEBUG|R_ADMIN|R_EVENT), "Assume Direct Control", "Assume direct control of a mob.", "Admin.Game", mob/M)
if(M.ckey)
if(tgui_alert(usr, "This mob is being controlled by [M.ckey]. Are you sure you wish to assume control of it? [M.ckey] will be made a ghost.","Confirmation",list("Yes","No")) != "Yes")
if(tgui_alert(user, "This mob is being controlled by [M.ckey]. Are you sure you wish to assume control of it? [M.ckey] will be made a ghost.","Confirmation",list("Yes","No")) != "Yes")
return
else
var/mob/observer/dead/ghost = new/mob/observer/dead(M,1)
ghost.ckey = M.ckey
message_admins(span_blue("[key_name_admin(usr)] assumed direct control of [M]."), 1)
log_admin("[key_name(usr)] assumed direct control of [M].")
var/mob/adminmob = src.mob
M.ckey = src.ckey
if(!M || QDELETED(M))
to_chat(user, span_warning("The target mob no longer exists."))
return
var/mob/observer/dead/ghost = new/mob/observer/dead(M,1)
ghost.ckey = M.ckey
message_admins(span_blue("[key_name_admin(user)] assumed direct control of [M]."), 1)
log_admin("[key_name(user)] assumed direct control of [M].")
var/mob/adminmob = user.mob
M.ckey = user.ckey
if( isobserver(adminmob) )
qdel(adminmob)
feedback_add_details("admin_verb","ADC") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!

View File

@@ -172,7 +172,7 @@ ADMIN_VERB(narrate_mob_args, R_FUN, "Narrate Entity", "Narrate entities using po
/datum/entity_narrate/tgui_state(mob/user)
return GLOB.tgui_admin_state
return ADMIN_STATE(R_FUN)
/datum/entity_narrate/tgui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)

View File

@@ -1,7 +1,7 @@
ADMIN_VERB_VISIBILITY(set_server_fps, ADMIN_VERB_VISIBLITY_FLAG_MAPPING_DEBUG)
ADMIN_VERB(set_server_fps, R_DEBUG, "Set Server FPS", "Sets game speed in frames-per-second. Can potentially break the game", ADMIN_CATEGORY_DEBUG)
var/cfg_fps = CONFIG_GET(number/fps)
var/new_fps = round(input(user, "Sets game frames-per-second. Can potentially break the game (default: [cfg_fps])","FPS", world.fps) as num|null)
var/new_fps = round(tgui_input_number(user, "Sets game frames-per-second. Can potentially break the game (default: [cfg_fps])","FPS", world.fps))
if(new_fps <= 0)
to_chat(user, span_danger("Error: set_server_fps(): Invalid world.fps value. No changes made."), confidential = TRUE)

View File

@@ -138,7 +138,6 @@ var/list/debug_verbs = list (
,/client/proc/powerdebug
,/client/proc/count_objects_on_z_level
,/client/proc/count_objects_all
,/client/proc/cmd_assume_direct_control
,/client/proc/jump_to_dead_group
,/client/proc/startSinglo
,/client/proc/cmd_admin_grantfullaccess

View File

@@ -1,22 +1,20 @@
GLOBAL_VAR_INIT(global_vantag_hud, 0)
/client/proc/cmd_admin_drop_everything(mob/M as mob in mob_list)
set category = null
set name = "Drop Everything"
if(!holder)
return
var/confirm = tgui_alert(src, "Make [M] drop everything?", "Message", list("Yes", "No"))
ADMIN_VERB(drop_everything, R_ADMIN, "Drop Everything", ADMIN_VERB_NO_DESCRIPTION, ADMIN_CATEGORY_HIDDEN, mob/living/dropee in mob_list)
var/confirm = tgui_alert(src, "Make [dropee] drop everything?", "Message", list("Yes", "No"))
if(confirm != "Yes")
return
for(var/obj/item/W in M)
for(var/obj/item/W in dropee)
if(istype(W, /obj/item/implant/backup) || istype(W, /obj/item/nif)) //There's basically no reason to remove either of these
continue
M.drop_from_inventory(W)
dropee.drop_from_inventory(W)
log_admin("[key_name(usr)] made [key_name(M)] drop everything!")
message_admins("[key_name_admin(usr)] made [key_name_admin(M)] drop everything!", 1)
dropee.regenerate_icons()
log_admin("[key_name(user)] made [key_name(dropee)] drop everything!")
var/msg = "[key_name_admin(user)] made [ADMIN_LOOKUPFLW(dropee)] drop everything!"
message_admins(msg)
feedback_add_details("admin_verb","DEVR") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
/client/proc/cmd_admin_prison(mob/M as mob in mob_list)
@@ -715,100 +713,6 @@ ADMIN_VERB(respawn_character, (R_ADMIN|R_REJUVINATE), "Spawn Character", "(Re)Sp
to_chat(src, "[job.title]: [job.total_positions]")
feedback_add_details("admin_verb","LFS") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
/client/proc/cmd_admin_explosion(atom/O as obj|mob|turf in world)
set category = "Fun.Do Not"
set name = "Explosion"
if(!check_rights(R_DEBUG|R_FUN)) return
var/devastation = tgui_input_number(usr, "Range of total devastation. -1 to none", text("Input"), min_value=-1)
if(devastation == null) return
var/heavy = tgui_input_number(usr, "Range of heavy impact. -1 to none", text("Input"), min_value=-1)
if(heavy == null) return
var/light = tgui_input_number(usr, "Range of light impact. -1 to none", text("Input"), min_value=-1)
if(light == null) return
var/flash = tgui_input_number(usr, "Range of flash. -1 to none", text("Input"), min_value=-1)
if(flash == null) return
if ((devastation != -1) || (heavy != -1) || (light != -1) || (flash != -1))
if ((devastation > 20) || (heavy > 20) || (light > 20))
if (tgui_alert(src, "Are you sure you want to do this? It will laaag.", "Confirmation", list("Yes", "No")) != "Yes")
return
explosion(O, devastation, heavy, light, flash)
log_admin("[key_name(usr)] created an explosion ([devastation],[heavy],[light],[flash]) at ([O.x],[O.y],[O.z])")
message_admins("[key_name_admin(usr)] created an explosion ([devastation],[heavy],[light],[flash]) at ([O.x],[O.y],[O.z])", 1)
feedback_add_details("admin_verb","EXPL") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
return
else
return
/client/proc/cmd_admin_emp(atom/O as obj|mob|turf in world)
set category = "Fun.Do Not"
set name = "EM Pulse"
if(!check_rights(R_DEBUG|R_FUN)) return
var/heavy = tgui_input_number(usr, "Range of heavy pulse.", text("Input"))
if(heavy == null) return
var/med = tgui_input_number(usr, "Range of medium pulse.", text("Input"))
if(med == null) return
var/light = tgui_input_number(usr, "Range of light pulse.", text("Input"))
if(light == null) return
var/long = tgui_input_number(usr, "Range of long pulse.", text("Input"))
if(long == null) return
if (heavy || med || light || long)
empulse(O, heavy, med, light, long)
log_admin("[key_name(usr)] created an EM Pulse ([heavy],[med],[light],[long]) at ([O.x],[O.y],[O.z])")
message_admins("[key_name_admin(usr)] created an EM PUlse ([heavy],[med],[light],[long]) at ([O.x],[O.y],[O.z])", 1)
feedback_add_details("admin_verb","EMP") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
return
else
return
/client/proc/cmd_admin_gib(mob/M as mob in mob_list)
set category = "Fun.Do Not"
set name = "Gib"
if(!check_rights(R_ADMIN|R_FUN)) return
var/confirm = tgui_alert(src, "You sure?", "Confirm", list("Yes", "No"))
if(confirm != "Yes") return
//Due to the delay here its easy for something to have happened to the mob
if(!M) return
log_admin("[key_name(usr)] has gibbed [key_name(M)]")
message_admins("[key_name_admin(usr)] has gibbed [key_name_admin(M)]", 1)
if(isobserver(M))
gibs(M.loc)
return
M.gib()
feedback_add_details("admin_verb","GIB") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
/client/proc/cmd_admin_gib_self()
set name = "Gibself"
set category = "Fun.Do Not"
if(!holder)
return
var/confirm = tgui_alert(src, "You sure?", "Confirm", list("Yes", "No"))
if(!confirm)
return
if(confirm == "Yes")
if (isobserver(mob)) // so they don't spam gibs everywhere
return
else
mob.gib()
log_admin("[key_name(usr)] used gibself.")
message_admins(span_blue("[key_name_admin(usr)] used gibself."), 1)
feedback_add_details("admin_verb","GIBS") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
/*
/client/proc/cmd_manual_ban()
set name = "Manual Ban"

View File

@@ -21,7 +21,7 @@ ADMIN_VERB(secrets, R_HOLDER, "Secrets", "Abuse harder than you ever have before
is_funmin = check_rights(R_FUN)
/datum/secrets_menu/tgui_state(mob/user)
return GLOB.tgui_admin_state// TGUI_ADMIN_STATE(R_NONE)
return ADMIN_STATE(R_HOLDER)
/datum/secrets_menu/tgui_close()
qdel(src)
@@ -368,7 +368,7 @@ ADMIN_VERB(secrets, R_HOLDER, "Secrets", "Abuse harder than you ever have before
return
//SSblackbox.record_feedback("nested tally", "admin_secrets_fun_used", 1, list("Bomb Cap"))
//var/newBombCap = input(holder,"What would you like the new bomb cap to be. (entered as the light damage range (the 3rd number in common (1,2,3) notation)) Must be above 4)", "New Bomb Cap", GLOB.MAX_EX_LIGHT_RANGE) as num|null
//var/newBombCap = tgui_input_list(holder,"What would you like the new bomb cap to be. (entered as the light damage range (the 3rd number in common (1,2,3) notation)) Must be above 4)", "New Bomb Cap", GLOB.MAX_EX_LIGHT_RANGE)
//if (!CONFIG_SET(number/bombcap, newBombCap))
// return

View File

@@ -5,27 +5,25 @@
if(istype(A))
var/turf/T = get_turf(A)
if(T)
coords = "at [COORD(T)]"
jmp_coords = "at [ADMIN_COORDJMP(T)]"
var/atom/a_loc = A.loc
var/is_turf = isturf(a_loc)
coords = "[is_turf ? "at" : "from [a_loc] at"] [AREACOORD(T)]"
jmp_coords = "[is_turf ? "at" : "from [a_loc] at"] [ADMIN_VERBOSEJMP(T)]"
else
jmp_coords = coords = "in nullspace"
if (tgui_alert(src, "Are you sure you want to delete:\n[D]\n[coords]?", "Confirmation", list("Yes", "No")) == "Yes")
if (tgui_alert(usr, "Are you sure you want to delete:\n[D]\n[coords]?", "Confirmation", list("Yes", "No")) == "Yes")
log_admin("[key_name(usr)] deleted [D] [coords]")
message_admins("[key_name_admin(usr)] deleted [D] [jmp_coords]")
//BLACKBOX_LOG_ADMIN_VERB("Delete")
feedback_add_details("admin_verb","ADEL") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
/*if(isturf(D)) //Polaris doesn't support baseturfs yet.
var/turf/T = D
T.ScrapeAway()
else*/
vv_update_display(D, "deleted", VV_MSG_DELETED)
// turfs are special snowflakes that'll explode if qdel'd outside ChangeTurf
if (isturf(D))
SEND_SIGNAL(D, COMSIG_ADMIN_DELETING, src)
if(isturf(D))
var/turf/T = D
//T.ScrapeAway()
T.ChangeTurf(world.turf)
else
vv_update_display(D, "deleted", VV_MSG_DELETED)
qdel(D)
if(!QDELETED(D))
vv_update_display(D, "deleted", "")
if(!QDELETED(D))
vv_update_display(D, "deleted", "")

View File

@@ -0,0 +1,85 @@
/datum/color_matrix_editor
var/client/owner
var/datum/weakref/target
var/atom/movable/screen/map_view/proxy_view
var/list/current_color
var/closed
/datum/color_matrix_editor/New(user, atom/_target = null)
owner = CLIENT_FROM_VAR(user)
if(islist(_target?.color))
current_color = _target.color
else if(istext(_target?.color))
current_color = color_hex2color_matrix(_target.color)
else
current_color = COLOR_MATRIX_IDENTITY
var/mutable_appearance/view = image('icons/testing/colortest.dmi', "colors")
if(_target)
target = WEAKREF(_target)
if(!(_target.appearance_flags & PLANE_MASTER))
view = image(_target)
proxy_view = new
proxy_view.generate_view("color_matrix_proxy_[REF(src)]")
proxy_view.appearance = view
proxy_view.color = current_color
/datum/color_matrix_editor/Destroy(force)
QDEL_NULL(proxy_view)
return ..()
/datum/color_matrix_editor/tgui_state(mob/user)
return ADMIN_STATE(R_VAREDIT)
/datum/color_matrix_editor/tgui_static_data(mob/user)
var/list/data = list()
data["mapRef"] = proxy_view.assigned_map
return data
/datum/color_matrix_editor/tgui_data(mob/user)
var/list/data = list()
data["currentColor"] = current_color
return data
/datum/color_matrix_editor/tgui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "ColorMatrixEditor")
ui.open()
proxy_view.display_to(owner.mob, ui.window)
/datum/color_matrix_editor/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state)
. = ..()
if(.)
return
switch(action)
if("transition_color")
current_color = params["color"]
animate(proxy_view, time = 4, color = current_color)
if("confirm")
on_confirm()
SStgui.close_uis(src)
/datum/color_matrix_editor/tgui_close(mob/user)
. = ..()
closed = TRUE
/datum/color_matrix_editor/proc/on_confirm()
var/atom/target_atom = target?.resolve()
if(istype(target_atom))
target_atom.vv_edit_var("color", current_color)
/datum/color_matrix_editor/proc/wait()
while(!closed)
stoplag(1)
/client/proc/open_color_matrix_editor(atom/in_atom)
var/datum/color_matrix_editor/editor = new /datum/color_matrix_editor(src, in_atom)
editor.tgui_interact(mob)
editor.wait()
. = editor.current_color
qdel(editor)

View File

@@ -0,0 +1,79 @@
/// Shows a header name on top when you investigate an appearance/image
/image/vv_get_header()
. = list()
var/icon_name = "<b>[icon || "null"]</b><br/>"
. += replacetext(icon_name, "icons/obj", "") // shortens the name. We know the path already.
if(icon)
. += icon_state ? "\"[icon_state]\"" : "(icon_state = null)"
/// Makes nice short vv names for images
/image/debug_variable_value(name, level, datum/owner, sanitize, display_flags)
var/display_name = "[type]"
if("[src]" != "[type]") // If we have a name var, let's use it.
display_name = "[src] [type]"
var/display_value
var/list/icon_file_name = splittext("[icon]", "/")
if(length(icon_file_name))
display_value = icon_file_name[length(icon_file_name)]
else
display_value = "null"
if(icon_state)
display_value = "[display_value]:[icon_state]"
var/display_ref = get_vv_link_ref()
return "<a href='byond://?_src_=vars;[HrefToken()];Vars=[display_ref]'>[display_name] (<span class='value'>[display_value]</span>) [display_ref]</a>"
/// Returns the ref string to use when displaying this image in the vv menu of something else
/image/proc/get_vv_link_ref()
return REF(src)
// It is endlessly annoying to display /appearance directly for stupid byond reasons, so we copy everything we care about into a holder datum
// That we can override procs on and store other vars on and such.
/mutable_appearance/appearance_mirror
// So people can see where it came from
var/appearance_ref
// arg is actually an appearance, typed as mutable_appearance as closest mirror
/mutable_appearance/appearance_mirror/New(mutable_appearance/appearance_father)
. = ..() // /mutable_appearance/New() copies over all the appearance vars MAs care about by default
appearance_ref = REF(appearance_father)
// This means if the appearance loses refs before a click it's gone, but that's consistent to other datums so it's fine
// Need to ref the APPEARANCE because we just free on our own, which sorta fucks this operation up you know?
/mutable_appearance/appearance_mirror/get_vv_link_ref()
return appearance_ref
/mutable_appearance/appearance_mirror/can_vv_get(var_name)
var/static/datum/beloved = new()
if(beloved.vars.Find(var_name)) // If datums have it, get out
return FALSE
// If it is one of the two args on /image, yeet (I am sorry)
if(var_name == NAMEOF(src, realized_overlays))
return FALSE
if(var_name == NAMEOF(src, realized_underlays))
return FALSE
// Could make an argument for this but I think they will just confuse people, so yeeet
if(var_name == NAMEOF(src, vis_contents))
return FALSE
return ..()
/mutable_appearance/appearance_mirror/vv_get_var(var_name)
// No editing for you
var/value = vars[var_name]
return "<li style='backgroundColor:white'>(READ ONLY) [var_name] = [_debug_variable_value(var_name, value, 0, src, sanitize = TRUE, display_flags = NONE)]</li>"
/mutable_appearance/appearance_mirror/vv_get_dropdown()
SHOULD_CALL_PARENT(FALSE)
. = list()
VV_DROPDOWN_OPTION("", "---")
VV_DROPDOWN_OPTION(VV_HK_CALLPROC, "Call Proc")
VV_DROPDOWN_OPTION(VV_HK_MARK, "Mark Object")
VV_DROPDOWN_OPTION(VV_HK_TAG, "Tag Datum")
VV_DROPDOWN_OPTION(VV_HK_DELETE, "Delete")
VV_DROPDOWN_OPTION(VV_HK_EXPOSE, "Show VV To Player")
/proc/get_vv_appearance(mutable_appearance/appearance) // actually appearance yadeeyada
return new /mutable_appearance/appearance_mirror(appearance)

View File

@@ -1,77 +1,128 @@
#define VV_HTML_ENCODE(thing) ( sanitize ? html_encode(thing) : thing )
/proc/debug_variable(name, value, level, datum/DA = null, sanitize = TRUE)
var/header
if(DA)
if (islist(DA))
var/list/data_list = DA
/// Get displayed variable in VV variable list
/proc/debug_variable(name, value, level, datum/owner, sanitize = TRUE, display_flags = NONE) //if D is a list, name will be index, and value will be assoc value.
if(owner)
if(islist(owner))
var/list/list_owner = owner
var/index = name
if (value)
name = data_list[name] //name is really the index until this line
if (isnull(value))
value = list_owner[name]
else
value = data_list[name]
header = "<li>(<a href='byond://?_src_=vars;[HrefToken()];[VV_HK_LIST_EDIT]=1;target=\ref[DA];index=[index]'>E</a>) (<a href='byond://?_src_=vars;[HrefToken()];[VV_HK_LIST_CHANGE]=1;target=\ref[DA];index=[index]'>C</a>) (<a href='byond://?_src_=vars;[HrefToken()];[VV_HK_LIST_REMOVE]=1;target=\ref[DA];index=[index]'>-</a>) "
name = list_owner[name] //name is really the index until this line
. = "<li style='backgroundColor:white'>([VV_HREF_TARGET_1V(owner, VV_HK_LIST_EDIT, "E", index)]) ([VV_HREF_TARGET_1V(owner, VV_HK_LIST_CHANGE, "C", index)]) ([VV_HREF_TARGET_1V(owner, VV_HK_LIST_REMOVE, "-", index)]) "
else
header = "<li>(<a href='byond://?_src_=vars;[HrefToken()];datumedit=\ref[DA];varnameedit=[name]'>E</a>) (<a href='byond://?_src_=vars;[HrefToken()];datumchange=\ref[DA];varnamechange=[name]'>C</a>) (<a href='byond://?_src_=vars;[HrefToken()];datummass=\ref[DA];varnamemass=[name]'>M</a>) "
. = "<li style='backgroundColor:white'>([VV_HREF_TARGET_1V(owner, VV_HK_BASIC_EDIT, "E", name)]) ([VV_HREF_TARGET_1V(owner, VV_HK_BASIC_CHANGE, "C", name)]) ([VV_HREF_TARGET_1V(owner, VV_HK_BASIC_MASSEDIT, "M", name)]) "
else
header = "<li>"
. = "<li>"
var/item
if (isnull(value))
item = "[VV_HTML_ENCODE(name)] = <span class='value'>null</span>"
var/name_part = VV_HTML_ENCODE(name)
if(level > 0 || islist(owner)) //handling keys in assoc lists
if(istype(name,/datum))
name_part = "<a href='byond://?_src_=vars;[HrefToken()];Vars=[REF(name)]'>[VV_HTML_ENCODE(name)] [REF(name)]</a>"
else if(islist(name))
var/list/list_value = name
name_part = "<a href='byond://?_src_=vars;[HrefToken()];Vars=[REF(name)]'> /list ([length(list_value)]) [REF(name)]</a>"
else if (istext(value))
item = "[VV_HTML_ENCODE(name)] = <span class='value'>\"[VV_HTML_ENCODE(value)]\"</span>"
. = "[.][name_part] = "
else if (isicon(value))
var/item = _debug_variable_value(name, value, level, owner, sanitize, display_flags)
return "[.][item]</li>"
// This is split into a separate proc mostly to make errors that happen not break things too much
/proc/_debug_variable_value(name, value, level, datum/owner, sanitize, display_flags)
if(isappearance(value))
value = get_vv_appearance(value)
. = span_red("DISPLAY_ERROR:") + " ([value] [REF(value)])" // Make sure this line can never runtime
if(isnull(value))
return span_value("null")
if(istext(value))
return span_value("\"[VV_HTML_ENCODE(value)]\"")
if(isicon(value))
#ifdef VARSICON
var/icon/I = new/icon(value)
var/icon/icon_value = icon(value)
var/rnd = rand(1,10000)
var/rname = "tmp\ref[I][rnd].png"
usr << browse_rsc(I, rname)
item = "[VV_HTML_ENCODE(name)] = (<span class='value'>[value]</span>) <img class=icon src=\"[rname]\">"
var/rname = "tmp[REF(icon_value)][rnd].png"
usr << browse_rsc(icon_value, rname)
return "(" + span_value("[value]") + ") <img class=icon src=\"[rname]\">"
#else
item = "[VV_HTML_ENCODE(name)] = /icon (<span class='value'>[value]</span>)"
return "/icon (" + span_value("[value]") + ")"
#endif
else if (isfile(value))
item = "[VV_HTML_ENCODE(name)] = <span class='value'>'[value]'</span>"
if(isfilter(value))
var/datum/filter_value = value
return "/filter (" + span_value("[filter_value.type] [REF(filter_value)]") + ")"
else if (istype(value, /datum))
var/datum/D = value
if ("[D]" != "[D.type]") //if the thing as a name var, lets use it.
item = "<a href='byond://?_src_=vars;[HrefToken()];Vars=\ref[value]'>[VV_HTML_ENCODE(name)] \ref[value]</a> = [D] [D.type]"
else
item = "<a href='byond://?_src_=vars;[HrefToken()];Vars=\ref[value]'>[VV_HTML_ENCODE(name)] \ref[value]</a> = [D.type]"
if(isfile(value))
return span_value("'[value]'")
else if (islist(value))
var/list/L = value
if(isdatum(value))
var/datum/datum_value = value
return datum_value.debug_variable_value(name, level, owner, sanitize, display_flags)
if(islist(value) || (name in GLOB.vv_special_lists)) // Some special lists aren't detectable as a list through istype
var/list/list_value = value
var/list/items = list()
if (L.len > 0 && !(name == "underlays" || name == "overlays" || L.len > (IS_NORMAL_LIST(L) ? VV_NORMAL_LIST_NO_EXPAND_THRESHOLD : VV_SPECIAL_LIST_NO_EXPAND_THRESHOLD)))
for (var/i in 1 to L.len)
var/key = L[i]
// This is because some lists either don't count as lists or a locate on their ref will return null
var/link_vars = "Vars=[REF(value)]"
if(name in GLOB.vv_special_lists)
link_vars = "Vars=[REF(owner)];special_varname=[name]"
if (!(display_flags & VV_ALWAYS_CONTRACT_LIST) && list_value.len > 0 && list_value.len <= (IS_NORMAL_LIST(list_value) ? VV_NORMAL_LIST_NO_EXPAND_THRESHOLD : VV_SPECIAL_LIST_NO_EXPAND_THRESHOLD))
for (var/i in 1 to list_value.len)
var/key = list_value[i]
var/val
if (IS_NORMAL_LIST(L) && !isnum(key))
val = L[key]
if (isnull(val)) // we still want to display non-null false values, such as 0 or ""
if (IS_NORMAL_LIST(list_value) && !isnum(key))
val = list_value[key]
if (isnull(val)) // we still want to display non-null false values, such as 0 or ""
val = key
key = i
items += debug_variable(key, val, level + 1, sanitize = sanitize)
item = "<a href='byond://?_src_=vars;[HrefToken()];Vars=\ref[value]'>[VV_HTML_ENCODE(name)] = /list ([L.len])</a><ul>[items.Join()]</ul>"
else
item = "<a href='byond://?_src_=vars;[HrefToken()];Vars=\ref[value]'>[VV_HTML_ENCODE(name)] = /list ([L.len])</a>"
return "<a href='byond://?_src_=vars;[HrefToken()];[link_vars]'>/list ([list_value.len])</a><ul>[items.Join()]</ul>"
return "<a href='byond://?_src_=vars;[HrefToken()];[link_vars]'>/list ([list_value.len])</a>"
else if (name in GLOB.bitfields)
var/list/flags = list()
for (var/i in GLOB.bitfields[name])
if (value & GLOB.bitfields[name][i])
flags += i
item = "[VV_HTML_ENCODE(name)] = [VV_HTML_ENCODE(jointext(flags, ", "))]"
// if it's a number, is it a bitflag?
var/list/valid_bitflags
if(!isnum(name))
valid_bitflags = get_valid_bitflags(name)
if(!length(valid_bitflags))
return span_value("[VV_HTML_ENCODE(value)]")
var/list/flags = list()
for (var/bit_name in valid_bitflags)
if (value & valid_bitflags[bit_name])
flags += bit_name
if(length(flags))
return "[VV_HTML_ENCODE(flags.Join(", "))]"
return "NONE"
/datum/proc/debug_variable_value(name, level, datum/owner, sanitize, display_flags)
if("[src]" != "[type]") // If we have a name var, let's use it.
return "<a href='byond://?_src_=vars;[HrefToken()];Vars=[REF(src)]'>[src] [type] [REF(src)]</a>"
else
item = "[VV_HTML_ENCODE(name)] = <span class='value'>[VV_HTML_ENCODE(value)]</span>"
return "<a href='byond://?_src_=vars;[HrefToken()];Vars=[REF(src)]'>[type] [REF(src)]</a>"
return "[header][item]</li>"
/datum/weakref/debug_variable_value(name, level, datum/owner, sanitize, display_flags)
. = ..()
return "[.] <a href='byond://?_src_=vars;[HrefToken()];Vars=[reference]'>(Resolve)</a>"
/matrix/debug_variable_value(name, level, datum/owner, sanitize, display_flags)
return span_value("\
<table class='matrixbrak'><tbody><tr><td class='lbrak'>&nbsp;</td><td>\
<table class='matrix'>\
<tbody>\
<tr><td>[a]</td><td>[d]</td><td>0</td></tr>\
<tr><td>[b]</td><td>[e]</td><td>0</td></tr>\
<tr><td>[c]</td><td>[f]</td><td>1</td></tr>\
</tbody>\
</table></td><td class='rbrak'>&nbsp;</td></tr></tbody></table>") //TODO link to modify_transform wrapper for all matrices
#undef VV_HTML_ENCODE

View File

@@ -0,0 +1,97 @@
/datum/filter_editor
var/atom/target
/datum/filter_editor/New(atom/target)
src.target = target
/datum/filter_editor/tgui_state(mob/user)
return ADMIN_STATE(R_VAREDIT)
/datum/filter_editor/tgui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "Filteriffic")
ui.open()
/datum/filter_editor/tgui_static_data(mob/user)
var/list/data = list()
data["filter_info"] = GLOB.master_filter_info
return data
/datum/filter_editor/tgui_data()
var/list/data = list()
data["target_name"] = target.name
data["target_filter_data"] = target.filter_data
return data
/datum/filter_editor/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state)
. = ..()
if(.)
return
switch(action)
if("add_filter")
var/target_name = params["name"]
while(target.filter_data && target.filter_data[target_name])
target_name = "[target_name]-dupe"
target.add_filter(target_name, params["priority"], list("type" = params["type"]))
. = TRUE
if("remove_filter")
target.remove_filter(params["name"])
. = TRUE
if("rename_filter")
var/list/filter_data = target.filter_data[params["name"]]
target.remove_filter(params["name"])
target.add_filter(params["new_name"], filter_data["priority"], filter_data)
. = TRUE
if("edit_filter")
target.remove_filter(params["name"])
target.add_filter(params["name"], params["priority"], params["new_filter"])
. = TRUE
if("change_priority")
var/new_priority = params["new_priority"]
target.change_filter_priority(params["name"], new_priority)
. = TRUE
if("transition_filter_value")
target.transition_filter(params["name"], params["new_data"], 4)
. = TRUE
if("modify_filter_value")
var/list/old_filter_data = target.filter_data[params["name"]]
var/list/new_filter_data = old_filter_data.Copy()
for(var/entry in params["new_data"])
new_filter_data[entry] = params["new_data"][entry]
for(var/entry in new_filter_data)
if(entry == GLOB.master_filter_info[old_filter_data["type"]]["defaults"][entry])
new_filter_data.Remove(entry)
target.remove_filter(params["name"])
target.add_filter(params["name"], old_filter_data["priority"], new_filter_data)
. = TRUE
if("modify_color_value")
var/new_color = tgui_color_picker(usr, "Pick new filter color", "Filteriffic Colors!")
if(new_color)
target.transition_filter(params["name"], list("color" = new_color), 4)
. = TRUE
if("modify_icon_value")
var/icon/new_icon = pick_and_customize_icon()
if(new_icon)
target.filter_data[params["name"]]["icon"] = new_icon
target.update_filters()
. = TRUE
if("mass_apply")
if(!check_rights_for(usr.client, R_FUN))
to_chat(usr, span_userdanger("Stay in your lane, jannie."))
return
var/target_path = text2path(params["path"])
if(!target_path)
return
var/filters_to_copy = target.filters
var/filter_data_to_copy = target.filter_data
var/count = 0
for(var/thing in world.contents)
if(istype(thing, target_path))
var/atom/thing_at = thing
thing_at.filters = filters_to_copy
thing_at.filter_data = filter_data_to_copy
count += 1
message_admins("LOCAL CLOWN [usr.ckey] JUST MASS FILTER EDITED [count] WITH PATH OF [params["path"]]!")
log_admin("LOCAL CLOWN [usr.ckey] JUST MASS FILTER EDITED [count] WITH PATH OF [params["path"]]!")

View File

@@ -1,59 +1,69 @@
/client/proc/vv_get_class(var/var_name, var/var_value)
/client/proc/vv_get_class(var_name, var_value)
if(isnull(var_value))
. = VV_NULL
else if (isnum(var_value))
if (var_name in GLOB.bitfields)
else if(isnum(var_value))
if(length(get_valid_bitflags(var_name)))
. = VV_BITFIELD
else
. = VV_NUM
else if (istext(var_value))
if (findtext(var_value, "\n"))
else if(istext(var_value))
if(findtext(var_value, "\n"))
. = VV_MESSAGE
else if(findtext(var_value, GLOB.is_color))
. = VV_COLOR
else
. = VV_TEXT
else if (isicon(var_value))
else if(isicon(var_value))
. = VV_ICON
else if (ismob(var_value))
else if(ismob(var_value))
. = VV_MOB_REFERENCE
else if (isloc(var_value))
else if(isloc(var_value))
. = VV_ATOM_REFERENCE
else if (istype(var_value, /client))
else if(istype(var_value, /client))
. = VV_CLIENT
else if (istype(var_value, /datum))
else if(isweakref(var_value))
. = VV_WEAKREF
else if(isdatum(var_value))
. = VV_DATUM_REFERENCE
else if (ispath(var_value))
if (ispath(var_value, /atom))
else if(ispath(var_value))
if(ispath(var_value, /atom))
. = VV_ATOM_TYPE
else if (ispath(var_value, /datum))
else if(ispath(var_value, /datum))
. = VV_DATUM_TYPE
else
. = VV_TYPE
else if (islist(var_value))
. = VV_LIST
else if(islist(var_value))
if(var_name in GLOB.color_vars)
. = VV_COLOR_MATRIX
else
. = VV_LIST
else if (isfile(var_value))
else if(isfile(var_value))
. = VV_FILE
else
. = VV_NULL
/client/proc/vv_get_value(class, default_class, current_value, list/restricted_classes, list/extra_classes, list/classes, var_name)
. = list("class" = class, "value" = null)
if (!class)
if (!classes)
if(!class)
if(!classes)
classes = list (
VV_NUM,
VV_TEXT,
VV_MESSAGE,
VV_ICON,
VV_COLOR,
//VV_COLOR_MATRIX,
VV_ATOM_REFERENCE,
VV_DATUM_REFERENCE,
VV_MOB_REFERENCE,
@@ -67,147 +77,187 @@
VV_NEW_TYPE,
VV_NEW_LIST,
VV_NULL,
VV_RESTORE_DEFAULT
VV_INFINITY,
VV_RESTORE_DEFAULT,
VV_TEXT_LOCATE,
VV_PROCCALL_RETVAL,
VV_WEAKREF,
)
if(holder && holder.marked_datum && !(VV_MARKED_DATUM in restricted_classes))
classes += "[VV_MARKED_DATUM] ([holder.marked_datum.type])"
if (restricted_classes)
var/markstring
if(!(VV_MARKED_DATUM in restricted_classes))
markstring = "[VV_MARKED_DATUM] (CURRENT: [(istype(holder) && istype(holder.marked_datum))? holder.marked_datum.type : "NULL"])"
classes += markstring
var/list/tagstrings = new
if(!(VV_TAGGED_DATUM in restricted_classes) && holder && LAZYLEN(holder.tagged_datums))
var/i = 0
for(var/datum/iter_tagged_datum as anything in holder.tagged_datums)
i++
var/new_tagstring = "[VV_TAGGED_DATUM] #[i]: [iter_tagged_datum.type])"
tagstrings[new_tagstring] = iter_tagged_datum
classes += new_tagstring
if(restricted_classes)
classes -= restricted_classes
if (extra_classes)
if(extra_classes)
classes += extra_classes
.["class"] = tgui_input_list(src, "What kind of data?", "Variable Type", classes, default_class)
if (holder && holder.marked_datum && .["class"] == "[VV_MARKED_DATUM] ([holder.marked_datum.type])")
if(holder && holder.marked_datum && .["class"] == markstring)
.["class"] = VV_MARKED_DATUM
if(holder && tagstrings[.["class"]])
var/datum/chosen_datum = tagstrings[.["class"]]
.["value"] = chosen_datum
.["class"] = VV_TAGGED_DATUM
switch(.["class"])
if (VV_TEXT)
if(VV_TEXT)
.["value"] = tgui_input_text(usr, "Enter new text:", "Text", current_value)
if (.["value"] == null)
if(.["value"] == null)
.["class"] = null
return
if (VV_MESSAGE)
if(VV_MESSAGE)
.["value"] = tgui_input_text(usr, "Enter new text:", "Text", current_value, multiline = TRUE)
if (.["value"] == null)
if(.["value"] == null)
.["class"] = null
return
if (VV_NUM)
if(VV_NUM)
.["value"] = tgui_input_number(usr, "Enter new number:", "Num", current_value, INFINITY, -INFINITY, round_value = FALSE)
if (.["value"] == null)
if(.["value"] == null)
.["class"] = null
return
if (VV_BITFIELD)
if(VV_BITFIELD)
.["value"] = input_bitfield(usr, "Editing bitfield: [var_name]", var_name, current_value)
if (.["value"] == null)
if(.["value"] == null)
.["class"] = null
return
if (VV_ATOM_TYPE)
if(VV_ATOM_TYPE)
.["value"] = pick_closest_path(FALSE)
if (.["value"] == null)
if(.["value"] == null)
.["class"] = null
return
if (VV_DATUM_TYPE)
if(VV_DATUM_TYPE)
.["value"] = pick_closest_path(FALSE, get_fancy_list_of_datum_types())
if (.["value"] == null)
if(.["value"] == null)
.["class"] = null
return
if (VV_TYPE)
if(VV_TYPE)
var/type = current_value
var/error = ""
do
type = tgui_input_text(usr, "Enter type:[error]", "Type", type)
if (!type)
if(!type)
break
type = text2path(type)
error = "\nType not found, Please try again"
while(!type)
if (!type)
if(!type)
.["class"] = null
return
.["value"] = type
if (VV_ATOM_REFERENCE)
if(VV_ATOM_REFERENCE)
var/type = pick_closest_path(FALSE)
var/subtypes = vv_subtype_prompt(type)
if (subtypes == null)
if(subtypes == null)
.["class"] = null
return
var/list/things = vv_reference_list(type, subtypes)
var/value = tgui_input_list(usr, "Select reference:", "Reference", things, current_value)
if (!value)
if(!value)
.["class"] = null
return
.["value"] = things[value]
if (VV_DATUM_REFERENCE)
if(VV_DATUM_REFERENCE)
var/type = pick_closest_path(FALSE, get_fancy_list_of_datum_types())
var/subtypes = vv_subtype_prompt(type)
if (subtypes == null)
if(subtypes == null)
.["class"] = null
return
var/list/things = vv_reference_list(type, subtypes)
var/value = tgui_input_list(usr, "Select reference:", "Reference", things, current_value)
if (!value)
if(!value)
.["class"] = null
return
.["value"] = things[value]
if (VV_MOB_REFERENCE)
if(VV_MOB_REFERENCE)
var/type = pick_closest_path(FALSE, make_types_fancy(typesof(/mob)))
var/subtypes = vv_subtype_prompt(type)
if (subtypes == null)
if(subtypes == null)
.["class"] = null
return
var/list/things = vv_reference_list(type, subtypes)
var/value = tgui_input_list(usr, "Select reference:", "Reference", things, current_value)
if (!value)
if(!value)
.["class"] = null
return
.["value"] = things[value]
if(VV_WEAKREF)
var/type = pick_closest_path(FALSE, get_fancy_list_of_datum_types())
var/subtypes = vv_subtype_prompt(type)
if(subtypes == null)
.["class"] = null
return
var/list/things = vv_reference_list(type, subtypes)
var/value = tgui_input_list(usr, "Select reference:", "Reference", things, current_value)
if(!value)
.["class"] = null
return
.["value"] = WEAKREF(things[value])
if (VV_CLIENT)
if(VV_CLIENT)
.["value"] = tgui_input_list(usr, "Select reference:", "Reference", GLOB.clients, current_value)
if (.["value"] == null)
if(.["value"] == null)
.["class"] = null
return
if (VV_FILE)
if(VV_FILE)
.["value"] = input(usr, "Pick file:", "File") as null|file
if (.["value"] == null)
if(.["value"] == null)
.["class"] = null
return
if (VV_ICON)
.["value"] = input(usr, "Pick icon:", "Icon") as null|icon
if (.["value"] == null)
if(VV_ICON)
.["value"] = pick_and_customize_icon(pick_only=TRUE)
if(.["value"] == null)
.["class"] = null
return
if (VV_MARKED_DATUM)
if(VV_MARKED_DATUM)
.["value"] = holder.marked_datum
if (.["value"] == null)
if(.["value"] == null)
.["class"] = null
return
if(VV_TAGGED_DATUM)
if(.["value"] == null)
.["class"] = null
return
if (VV_NEW_ATOM)
if(VV_PROCCALL_RETVAL)
var/list/get_retval = list()
callproc_blocking(get_retval)
.["value"] = get_retval[1] //should have been set in proccall!
if(.["value"] == null)
.["class"] = null
return
if(VV_NEW_ATOM)
var/type = pick_closest_path(FALSE)
if (!type)
if(!type)
.["class"] = null
return
.["type"] = type
@@ -215,9 +265,9 @@
newguy.datum_flags |= DF_VAR_EDITED
.["value"] = newguy
if (VV_NEW_DATUM)
if(VV_NEW_DATUM)
var/type = pick_closest_path(FALSE, get_fancy_list_of_datum_types())
if (!type)
if(!type)
.["class"] = null
return
.["type"] = type
@@ -225,17 +275,17 @@
newguy.datum_flags |= DF_VAR_EDITED
.["value"] = newguy
if (VV_NEW_TYPE)
if(VV_NEW_TYPE)
var/type = current_value
var/error = ""
do
type = tgui_input_text(usr, "Enter type:[error]", "Type", type)
if (!type)
if(!type)
break
type = text2path(type)
error = "\nType not found, Please try again"
while(!type)
if (!type)
if(!type)
.["class"] = null
return
.["type"] = type
@@ -244,7 +294,52 @@
newguy.datum_flags |= DF_VAR_EDITED
.["value"] = newguy
if (VV_NEW_LIST)
.["value"] = list()
if(VV_NEW_LIST)
.["type"] = /list
var/list/value = list()
var/expectation = alert("Would you like to populate the list", "Populate List?", "Yes", "No")
if(!expectation || expectation == "No")
.["value"] = value
return .
var/list/insert = null
while(TRUE)
insert = vv_get_value(restricted_classes = list(VV_RESTORE_DEFAULT))
if(!insert["class"])
break
value += LIST_VALUE_WRAP_LISTS(insert["value"])
.["value"] = value
if(VV_TEXT_LOCATE)
var/datum/D
do
var/ref = tgui_input_text(usr, "Enter reference:", "Reference")
if(!ref)
break
D = locate(ref)
if(!D)
tgui_alert(usr,"Invalid ref!")
continue
if(!D.can_vv_mark())
tgui_alert(usr,"Datum can not be marked!")
continue
while(!D)
.["type"] = D.type
.["value"] = D
if(VV_COLOR)
.["value"] = tgui_color_picker(src, "Enter new color:", "Color", current_value)
if(.["value"] == null)
.["class"] = null
return
//if(VV_COLOR_MATRIX)
// .["value"] = open_color_matrix_editor()
// if(.["value"] == COLOR_MATRIX_IDENTITY) //identity is equivalent to null
// .["class"] = null
if(VV_INFINITY)
.["value"] = INFINITY

View File

@@ -1,199 +0,0 @@
// Keep these two together, they *must* be defined on both
// If /client ever becomes /datum/client or similar, they can be merged
/datum/proc/get_view_variables_header()
return span_bold("[src]")
/atom/get_view_variables_header()
return {"
<a href='byond://?_src_=vars;[HrefToken()];datumedit=\ref[src];varnameedit=name'>"} + span_bold("[src]") + {"</a>
<br>
"} + span_small("<a href='byond://?_src_=vars;[HrefToken()];rotatedatum=\ref[src];rotatedir=left'><<</a>") + {"
"} + span_small("<a href='byond://?_src_=vars;[HrefToken()];datumedit=\ref[src];varnameedit=dir'>[dir2text(dir)]</a>") + {"
"} + span_small("<a href='byond://?_src_=vars;[HrefToken()];rotatedatum=\ref[src];rotatedir=right'>>></a>") + {"
"}
/mob/living/get_view_variables_header()
return {"
<a href='byond://?_src_=vars;[HrefToken()];rename=\ref[src]'>"} + span_bold("[src]") + {"</a>
"} + span_small("<br><a href='byond://?_src_=vars;[HrefToken()];rotatedatum=\ref[src];rotatedir=left'><<</a> <a href='byond://?_src_=vars;[HrefToken()];datumedit=\ref[src];varnameedit=dir'>[dir2text(dir)]</a> <a href='byond://?_src_=vars;[HrefToken()];rotatedatum=\ref[src];rotatedir=right'>>></a>") + {"
"} + span_small("<br><a href='byond://?_src_=vars;[HrefToken()];datumedit=\ref[src];varnameedit=ckey'>[ckey ? ckey : "No ckey"]</a> / <a href='byond://?_src_=vars;[HrefToken()];datumedit=\ref[src];varnameedit=real_name'>[real_name ? real_name : "No real name"]</a>") + {"
<br>
"} + span_small("BRUTE:<a href='byond://?_src_=vars;[HrefToken()];mobToDamage=\ref[src];adjustDamage=brute'>[getBruteLoss()]</a>") + {"
"} + span_small("FIRE:<a href='byond://?_src_=vars;[HrefToken()];mobToDamage=\ref[src];adjustDamage=fire'>[getFireLoss()]</a>") + {"
"} + span_small("TOXIN:<a href='byond://?_src_=vars;[HrefToken()];mobToDamage=\ref[src];adjustDamage=toxin'>[getToxLoss()]</a>") + {"
"} + span_small("OXY:<a href='byond://?_src_=vars;[HrefToken()];mobToDamage=\ref[src];adjustDamage=oxygen'>[getOxyLoss()]</a>") + {"
"} + span_small("CLONE:<a href='byond://?_src_=vars;[HrefToken()];mobToDamage=\ref[src];adjustDamage=clone'>[getCloneLoss()]</a>") + {"
"} + span_small("BRAIN:<a href='byond://?_src_=vars;[HrefToken()];mobToDamage=\ref[src];adjustDamage=brain'>[getBrainLoss()]</a>") + {"
"}
//This entire file needs to be removed eventually
/datum/proc/get_view_variables_options()
return ""
/mob/get_view_variables_options()
return ..() + {"
<option value='?_src_=vars;[HrefToken()];mob_player_panel=\ref[src]'>Show player panel</option>
<option>---</option>
<option value='?_src_=vars;[HrefToken()];give_modifier=\ref[src]'>Give Modifier</option>
<option value='?_src_=vars;[HrefToken()];give_wound_internal=\ref[src]'>Give Internal Bleeding</option>
<option value='?_src_=vars;[HrefToken()];give_spell=\ref[src]'>Give Spell</option>
<option value='?_src_=vars;[HrefToken()];give_disease2=\ref[src]'>Give Disease</option>
<option value='?_src_=vars;[HrefToken()];give_disease=\ref[src]'>Give TG-style Disease</option>
<option value='?_src_=vars;[HrefToken()];godmode=\ref[src]'>Toggle Godmode</option>
<option value='?_src_=vars;[HrefToken()];build_mode=\ref[src]'>Toggle Build Mode</option>
<option value='?_src_=vars;[HrefToken()];ninja=\ref[src]'>Make Space Ninja</option>
<option value='?_src_=vars;[HrefToken()];make_skeleton=\ref[src]'>Make 2spooky</option>
<option value='?_src_=vars;[HrefToken()];direct_control=\ref[src]'>Assume Direct Control</option>
<option value='?_src_=vars;[HrefToken()];give_ai=\ref[src]'>Enable/Modify A.I</option>
<option value='?_src_=vars;[HrefToken()];drop_everything=\ref[src]'>Drop Everything</option>
<option value='?_src_=vars;[HrefToken()];regenerateicons=\ref[src]'>Regenerate Icons</option>
<option value='?_src_=vars;[HrefToken()];addlanguage=\ref[src]'>Add Language</option>
<option value='?_src_=vars;[HrefToken()];remlanguage=\ref[src]'>Remove Language</option>
<option value='?_src_=vars;[HrefToken()];addorgan=\ref[src]'>Add Organ</option>
<option value='?_src_=vars;[HrefToken()];remorgan=\ref[src]'>Remove Organ</option>
<option value='?_src_=vars;[HrefToken()];fix_nano=\ref[src]'>Fix NanoUI</option>
<option value='?_src_=vars;[HrefToken()];addverb=\ref[src]'>Add Verb</option>
<option value='?_src_=vars;[HrefToken()];remverb=\ref[src]'>Remove Verb</option>
<option>---</option>
<option value='?_src_=vars;[HrefToken()];gib=\ref[src]'>Gib</option>
"}
/mob/living/carbon/human/get_view_variables_options()
return ..() + {"
<option value='?_src_=vars;[HrefToken()];setspecies=\ref[src]'>Set Species</option>
<option value='?_src_=vars;[HrefToken()];makeai=\ref[src]'>Make AI</option>
<option value='?_src_=vars;[HrefToken()];makerobot=\ref[src]'>Make cyborg</option>
<option value='?_src_=vars;[HrefToken()];makemonkey=\ref[src]'>Make monkey</option>
<option value='?_src_=vars;[HrefToken()];makealien=\ref[src]'>Make alien</option>
"}
/obj/get_view_variables_options()
return ..() + {"
<option value='?_src_=vars;[HrefToken()];delall=\ref[src]'>Delete all of type</option>
"}
/turf/get_view_variables_options()
return ..() + {"
<option value='?_src_=vars;[HrefToken()];explode=\ref[src]'>Trigger explosion</option>
<option value='?_src_=vars;[HrefToken()];emp=\ref[src]'>Trigger EM pulse</option>
"}
/obj/item/pda/get_view_variables_options()
return ..() + {"
<option value='?_src_=vars;[HrefToken()];fakepdapropconvo=\ref[src]'>Add Fake Prop Conversation</option>
"}
/datum/proc/get_variables()
. = vars - VV_hidden()
if(!usr || !check_rights(R_ADMIN|R_DEBUG, FALSE))
. -= VV_secluded()
/datum/proc/get_variable_value(varname)
return vars[varname]
/datum/proc/set_variable_value(varname, value)
vars[varname] = value
/datum/proc/get_initial_variable_value(varname)
return initial(vars[varname])
/datum/proc/make_view_variables_variable_entry(var/varname, var/value, var/hide_watch = 0)
return {"
(<a href='byond://?_src_=vars;[HrefToken()];datumedit=\ref[src];varnameedit=[varname]'>E</a>)
(<a href='byond://?_src_=vars;[HrefToken()];datumchange=\ref[src];varnamechange=[varname]'>C</a>)
(<a href='byond://?_src_=vars;[HrefToken()];datummass=\ref[src];varnamemass=[varname]'>M</a>)
[hide_watch ? "" : "(<a href='byond://?_src_=vars;[HrefToken()];datumwatch=\ref[src];varnamewatch=[varname]'>W</a>)"]
"}
// No mass editing of clients
/client/make_view_variables_variable_entry(var/varname, var/value, var/hide_watch = 0)
return {"
(<a href='byond://?_src_=vars;[HrefToken()];datumedit=\ref[src];varnameedit=[varname]'>E</a>)
(<a href='byond://?_src_=vars;[HrefToken()];datumchange=\ref[src];varnamechange=[varname]'>C</a>)
[hide_watch ? "" : "(<a href='byond://?_src_=vars;[HrefToken()];datumwatch=\ref[src];varnamewatch=[varname]'>W</a>)"]
"}
// These methods are all procs and don't use stored lists to avoid VV exploits
// The following vars cannot be viewed by anyone
/datum/proc/VV_hidden()
return list()
// The following vars can only be viewed by R_ADMIN|R_DEBUG
/datum/proc/VV_secluded()
return list()
/datum/configuration/VV_secluded()
return vars
// The following vars cannot be edited by anyone
/datum/proc/VV_static()
return list("parent_type")
/atom/VV_static()
return ..() + list("bound_x", "bound_y", "bound_height", "bound_width", "bounds", "step_x", "step_y", "step_size")
/client/VV_static()
return ..() + list("holder", "prefs")
/datum/admins/VV_static()
return vars
// The following vars require R_DEBUG to edit
/datum/proc/VV_locked()
return list("vars", "cuffed")
/client/VV_locked()
return list("vars", "mob")
/mob/VV_locked()
return ..() + list("client")
// The following vars require R_FUN|R_DEBUG to edit
/datum/proc/VV_icon_edit_lock()
return list()
/atom/VV_icon_edit_lock()
return ..() + list("icon", "icon_state", "overlays", "underlays")
// The following vars require R_SPAWN|R_DEBUG to edit
/datum/proc/VV_ckey_edit()
return list()
/mob/VV_ckey_edit()
return list("key", "ckey")
/client/VV_ckey_edit()
return list("key", "ckey")
/datum/proc/may_edit_var(var/user, var/var_to_edit) //User must be a CLIENT that is passed to this.
if(!user)
return FALSE
if(ismob(user)) //Failsafe catch in case someone feeds a mob into us.
var/mob/living = user
user = living.client
if(!(var_to_edit in vars))
to_chat(user, span_warning("\The [src] does not have a var '[var_to_edit]'"))
return FALSE
if(var_to_edit in VV_static())
return FALSE
if((var_to_edit in VV_secluded()) && !check_rights_for(user, R_ADMIN|R_DEBUG))
return FALSE
if((var_to_edit in VV_locked()) && !check_rights_for(user, R_DEBUG))
return FALSE
if((var_to_edit in VV_ckey_edit()) && !check_rights_for(user, R_SPAWN|R_DEBUG))
return FALSE
if((var_to_edit in VV_icon_edit_lock()) && !check_rights_for(user, R_FUN|R_DEBUG))
return FALSE
return TRUE
/proc/forbidden_varedit_object_types()
return list(
/datum/admins //Admins editing their own admin-power object? Yup, sounds like a good idea.
)

View File

@@ -0,0 +1,17 @@
/client/proc/mark_datum(datum/D)
if(!holder)
return
if(holder.marked_datum)
holder.UnregisterSignal(holder.marked_datum, COMSIG_PARENT_QDELETING)
vv_update_display(holder.marked_datum, "marked", "")
holder.marked_datum = D
holder.RegisterSignal(holder.marked_datum, COMSIG_PARENT_QDELETING, TYPE_PROC_REF(/datum/admins, handle_marked_del))
vv_update_display(D, "marked", VV_MSG_MARKED)
ADMIN_VERB_ONLY_CONTEXT_MENU(mark_datum, R_HOLDER, "Mark Object", datum/target as mob|obj|turf|area in view())
user.mark_datum(target)
/datum/admins/proc/handle_marked_del(datum/source)
SIGNAL_HANDLER
UnregisterSignal(marked_datum, COMSIG_PARENT_QDELETING)
marked_datum = null

View File

@@ -1,29 +1,29 @@
/client/proc/cmd_mass_modify_object_variables(atom/A, var_name)
set category = "Debug"
set name = "Mass Edit Variables"
set desc="(target) Edit all instances of a target item's variables"
var/method = 0 //0 means strict type detection while 1 means this type and all subtypes (IE: /obj/item with this set to 1 will set it to ALL items)
/client/proc/cmd_mass_modify_object_variables(datum/target, var_name)
if(tgui_alert(src, "Are you sure you'd like to mass-modify every instance of the [var_name] variable? This can break everything if you do not know what you are doing.", "Slow down, chief!", list("Yes", "No"), 60 SECONDS) != "Yes")
return
if(!check_rights(R_VAREDIT))
return
if(A && A.type)
method = vv_subtype_prompt(A.type)
/// if false get only the strict type, get all subtypes too otherwise
var/strict_type = FALSE
if(target?.type)
strict_type = vv_subtype_prompt(target.type)
src.massmodify_variables(A, var_name, method)
massmodify_variables(target, var_name, strict_type)
feedback_add_details("admin_verb","MVV") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
//BLACKBOX_LOG_ADMIN_VERB("Mass Edit Variables")
/client/proc/massmodify_variables(datum/O, var_name = "", method = 0)
/client/proc/massmodify_variables(datum/target, var_name = "", strict_type = FALSE)
if(!check_rights(R_VAREDIT))
return
if(!istype(O))
if(!istype(target))
return
var/variable = ""
if(!var_name)
var/list/names = list()
for (var/V in O.vars)
for (var/V in target.vars)
names += V
names = sortList(names)
@@ -32,13 +32,13 @@
else
variable = var_name
if(!variable || !O.can_vv_get(variable))
if(!variable || !target.can_vv_get(variable))
return
var/default
var/var_value = O.vars[variable]
var/var_value = target.vars[variable]
if(variable in GLOB.VVckey_edit)
to_chat(src, "It's forbidden to mass-modify ckeys. It'll crash everyone's client you dummy.")
to_chat(src, "It's forbidden to mass-modify ckeys. It'll crash everyone's client you dummy.", confidential = TRUE)
return
if(variable in GLOB.VVlocked)
if(!check_rights(R_DEBUG))
@@ -49,18 +49,18 @@
if(variable in GLOB.VVpixelmovement)
if(!check_rights(R_DEBUG))
return
var/prompt = tgui_alert(src, "Editing this var may irreparably break tile gliding for the rest of the round. THIS CAN'T BE UNDONE", "DANGER", list("ABORT","Continue","ABORT"))
var/prompt = tgui_alert(src, "Editing this var may irreparably break tile gliding for the rest of the round. THIS CAN'T BE UNDONE", "DANGER", list("ABORT ", "Continue", " ABORT"))
if (prompt != "Continue")
return
default = vv_get_class(variable, var_value)
if(isnull(default))
to_chat(src, "Unable to determine variable type.")
to_chat(src, "Unable to determine variable type.", confidential = TRUE)
else
to_chat(src, "Variable appears to be <b>[uppertext(default)]</b>.")
to_chat(src, "Variable appears to be " + span_bold("[uppertext(default)]") + ".", confidential = TRUE)
to_chat(src, "Variable contains: [var_value]")
to_chat(src, "Variable contains: [var_value]", confidential = TRUE)
if(default == VV_NUM)
var/dir_text = ""
@@ -75,7 +75,7 @@
dir_text += "WEST"
if(dir_text)
to_chat(src, "If a direction, direction is: [dir_text]")
to_chat(src, "If a direction, direction is: [dir_text]", confidential = TRUE)
var/value = vv_get_value(default_class = default)
var/new_value = value["value"]
@@ -90,16 +90,16 @@
if (value["type"])
class = VV_NEW_TYPE
var/original_name = "[O]"
var/original_name = "[target]"
var/rejected = 0
var/accepted = 0
switch(class)
if(VV_RESTORE_DEFAULT)
to_chat(src, "Finding items...")
var/list/items = get_all_of_type(O.type, method)
to_chat(src, "Changing [items.len] items...")
to_chat(src, "Finding items...", confidential = TRUE)
var/list/items = get_all_of_type(target.type, strict_type)
to_chat(src, "Changing [items.len] items...", confidential = TRUE)
for(var/thing in items)
if (!thing)
continue
@@ -111,23 +111,21 @@
CHECK_TICK
if(VV_TEXT)
var/list/varsvars = vv_parse_text(O, new_value)
var/list/varsvars = vv_parse_text(target, new_value)
var/pre_processing = new_value
var/unique
if (varsvars && varsvars.len)
unique = tgui_alert(usr, "Process vars unique to each instance, or same for all?", "Variable Association", list("Unique", "Same"))
if(!unique)
return
if (varsvars?.len)
unique = tgui_alert(src, "Process vars unique to each instance, or same for all?", "Variable Association", list("Unique", "Same"))
if(unique == "Unique")
unique = TRUE
else
unique = FALSE
for(var/V in varsvars)
new_value = replacetext(new_value,"\[[V]]","[O.vars[V]]")
new_value = replacetext(new_value,"\[[V]]","[target.vars[V]]")
to_chat(src, "Finding items...")
var/list/items = get_all_of_type(O.type, method)
to_chat(src, "Changing [items.len] items...")
to_chat(src, "Finding items...", confidential = TRUE)
var/list/items = get_all_of_type(target.type, strict_type)
to_chat(src, "Changing [items.len] items...", confidential = TRUE)
for(var/thing in items)
if (!thing)
continue
@@ -145,7 +143,7 @@
if (VV_NEW_TYPE)
var/many = tgui_alert(src, "Create only one [value["type"]] and assign each or a new one for each thing", "How Many", list("One", "Many", "Cancel"))
if (!many || many == "Cancel")
if (many == "Cancel")
return
if (many == "Many")
many = TRUE
@@ -153,9 +151,9 @@
many = FALSE
var/type = value["type"]
to_chat(src, "Finding items...")
var/list/items = get_all_of_type(O.type, method)
to_chat(src, "Changing [items.len] items...")
to_chat(src, "Finding items...", confidential = TRUE)
var/list/items = get_all_of_type(target.type, strict_type)
to_chat(src, "Changing [items.len] items...", confidential = TRUE)
for(var/thing in items)
if (!thing)
continue
@@ -171,9 +169,9 @@
CHECK_TICK
else
to_chat(src, "Finding items...")
var/list/items = get_all_of_type(O.type, method)
to_chat(src, "Changing [items.len] items...")
to_chat(src, "Finding items...", confidential = TRUE)
var/list/items = get_all_of_type(target.type, strict_type)
to_chat(src, "Changing [items.len] items...", confidential = TRUE)
for(var/thing in items)
if (!thing)
continue
@@ -187,27 +185,27 @@
var/count = rejected+accepted
if (!count)
to_chat(src, "No objects found")
to_chat(src, "No objects found", confidential = TRUE)
return
if (!accepted)
to_chat(src, "Every object rejected your edit")
to_chat(src, "Every object rejected your edit", confidential = TRUE)
return
if (rejected)
to_chat(src, "[rejected] out of [count] objects rejected your edit")
to_chat(src, "[rejected] out of [count] objects rejected your edit", confidential = TRUE)
log_world("### MassVarEdit by [src]: [O.type] (A/R [accepted]/[rejected]) [variable]=[html_encode("[O.vars[variable]]")]([list2params(value)])")
log_admin("[key_name(src)] mass modified [original_name]'s [variable] to [O.vars[variable]] ([accepted] objects modified)")
message_admins("[key_name_admin(src)] mass modified [original_name]'s [variable] to [O.vars[variable]] ([accepted] objects modified)")
log_world("### MassVarEdit by [src]: [target.type] (A/R [accepted]/[rejected]) [variable]=[html_encode("[target.vars[variable]]")]([list2params(value)])")
log_admin("[key_name(src)] mass modified [original_name]'s [variable] to [target.vars[variable]] ([accepted] objects modified)")
message_admins("[key_name_admin(src)] mass modified [original_name]'s [variable] to [target.vars[variable]] ([accepted] objects modified)")
/proc/get_all_of_type(var/T, subtypes = TRUE)
//not using global lists as vv is a debug function and debug functions should rely on as less things as possible.
/proc/get_all_of_type(T, subtypes = TRUE)
var/list/typecache = list()
typecache[T] = 1
if (subtypes)
typecache = typecacheof(typecache)
. = list()
if (ispath(T, /mob))
for(var/mob/thing in mob_list)
for(var/mob/thing in world)
if (typecache[thing.type])
. += thing
CHECK_TICK
@@ -219,7 +217,13 @@
CHECK_TICK
else if (ispath(T, /obj/machinery))
for(var/obj/machinery/thing in GLOB.machines)
for(var/obj/machinery/thing in world)
if (typecache[thing.type])
. += thing
CHECK_TICK
else if (ispath(T, /obj/item))
for(var/obj/item/thing in world)
if (typecache[thing.type])
. += thing
CHECK_TICK

View File

@@ -1,10 +1,10 @@
GLOBAL_LIST_INIT(VVlocked, list("vars", "datum_flags", "client", "mob")) //Requires DEBUG
GLOBAL_LIST_INIT(VVlocked, list("vars", "datum_flags", "client", "mob")) //Requires DEBUG
GLOBAL_PROTECT(VVlocked)
GLOBAL_LIST_INIT(VVicon_edit_lock, list("icon", "icon_state", "overlays", "underlays")) //Requires DEBUG or FUN
GLOBAL_LIST_INIT(VVicon_edit_lock, list("icon", "icon_state", "overlays", "underlays")) //Requires DEBUG or FUN
GLOBAL_PROTECT(VVicon_edit_lock)
GLOBAL_LIST_INIT(VVckey_edit, list("key", "ckey")) //Requires DEBUG or SPAWN
GLOBAL_LIST_INIT(VVckey_edit, list("key", "ckey")) //Requires DEBUG or SPAWN
GLOBAL_PROTECT(VVckey_edit)
GLOBAL_LIST_INIT(VVpixelmovement, list("bound_x", "bound_y", "step_x", "step_y", "step_size", "bound_height", "bound_width", "bounds")) //No editing ever.
GLOBAL_LIST_INIT(VVpixelmovement, list("bound_x", "bound_y", "step_x", "step_y", "step_size", "bound_height", "bound_width", "bounds")) //No editing ever.
GLOBAL_PROTECT(VVpixelmovement)
/client/proc/vv_parse_text(O, new_var)
@@ -17,14 +17,14 @@ GLOBAL_PROTECT(VVpixelmovement)
//FALSE = no subtypes, strict exact type pathing (or the type doesn't have subtypes)
//TRUE = Yes subtypes
//NULL = User cancelled at the prompt or invalid type given
/client/proc/vv_subtype_prompt(var/type)
/client/proc/vv_subtype_prompt(type)
if (!ispath(type))
return
var/list/subtypes = subtypesof(type)
if (!subtypes || !subtypes.len)
return FALSE
if (subtypes && subtypes.len)
switch(tgui_alert(usr, "Strict object type detection?", "Type detection", list("Strictly this type", "This type and subtypes", "Cancel")))
if (subtypes?.len)
switch(tgui_alert(usr,"Strict object type detection?", "Type detection", list("Strictly this type","This type and subtypes", "Cancel")))
if("Strictly this type")
return FALSE
if("This type and subtypes")
@@ -46,25 +46,25 @@ GLOBAL_PROTECT(VVpixelmovement)
var/things = get_all_of_type(type, subtypes)
var/i = 0
for(var/datum/D as anything in things)
for(var/thing in things)
var/datum/D = thing
i++
//try one of 3 methods to shorten the type text:
// fancy type,
// fancy type with the base type removed from the begaining,
// the type with the base type removed from the begaining
// fancy type,
// fancy type with the base type removed from the begaining,
// the type with the base type removed from the begaining
var/fancytype = types[D.type]
if (findtext(fancytype, types[type]))
fancytype = copytext(fancytype, length(types[type])+1)
var/shorttype = copytext("[D.type]", length("[type]")+1)
if (length(shorttype) > length(fancytype))
fancytype = copytext(fancytype, length(types[type]) + 1)
var/shorttype = copytext("[D.type]", length("[type]") + 1)
if (length_char(shorttype) > length_char(fancytype))
shorttype = fancytype
if (!length(shorttype))
shorttype = "/"
.["[D]([shorttype])\ref[D]#[i]"] = D
.["[D]([shorttype])[REF(D)]#[i]"] = D
/client/proc/mod_list_add_ass(atom/O) //hehe
var/list/L = vv_get_value(restricted_classes = list(VV_RESTORE_DEFAULT))
var/class = L["class"]
if (!class)
@@ -94,15 +94,14 @@ GLOBAL_PROTECT(VVpixelmovement)
if (O)
L = L.Copy()
L += var_value
L += list(var_value) //var_value could be a list
if(IS_VALID_ASSOC_KEY(var_value))
switch(tgui_alert(usr, "Would you like to associate a value with the list entry?","List VV",list("Yes","No")))
if("Yes")
L[var_value] = mod_list_add_ass(O) //hehe
switch(tgui_alert(usr,"Would you like to associate a value with the list entry?",,list("Yes","No")))
if("Yes")
L[var_value] = mod_list_add_ass(O) //hehe
if (O)
if (O.vv_edit_var(objectvar, L) == FALSE)
to_chat(src, "Your edit was rejected by the object.")
to_chat(src, "Your edit was rejected by the object.", confidential = TRUE)
return
log_world("### ListVarEdit by [src]: [(O ? O.type : "/list")] [objectvar]: ADDED=[var_value]")
log_admin("[key_name(src)] modified [original_name]'s [objectvar]: ADDED=[var_value]")
@@ -112,27 +111,26 @@ GLOBAL_PROTECT(VVpixelmovement)
if(!check_rights(R_VAREDIT))
return
if(!istype(L, /list))
to_chat(src, "Not a List.")
to_chat(src, "Not a List.", confidential = TRUE)
return
if(L.len > 1000)
var/confirm = tgui_alert(src, "The list you're trying to edit is very long, continuing may crash the server.", "Long List!", list("Warning", "Continue", "Abort"))
var/confirm = tgui_alert(usr, "The list you're trying to edit is very long, continuing may crash the server.", "Warning", list("Continue", "Abort"))
if(confirm != "Continue")
return
var/is_normal_list = IS_NORMAL_LIST(L)
var/list/names = list()
for (var/i in 1 to L.len)
var/key = L[i]
var/value
if (IS_NORMAL_LIST(L) && !isnum(key))
if (is_normal_list && !isnum(key))
value = L[key]
if (value == null)
value = "null"
names["#[i] [key] = [value]"] = i
if (!index)
var/variable = tgui_input_list(usr, "Which var?","Var", names + "(ADD VAR)" + "(CLEAR NULLS)" + "(CLEAR DUPES)" + "(SHUFFLE)")
var/variable = tgui_input_list(usr, "Which var?", "Var", names + "(ADD VAR)" + "(CLEAR NULLS)" + "(CLEAR DUPES)" + "(SHUFFLE)")
if(variable == null)
return
@@ -143,9 +141,9 @@ GLOBAL_PROTECT(VVpixelmovement)
if(variable == "(CLEAR NULLS)")
L = L.Copy()
listclearnulls(L)
list_clear_nulls(L)
if (!O.vv_edit_var(objectvar, L))
to_chat(src, "Your edit was rejected by the object.")
to_chat(src, "Your edit was rejected by the object.", confidential = TRUE)
return
log_world("### ListVarEdit by [src]: [O.type] [objectvar]: CLEAR NULLS")
log_admin("[key_name(src)] modified [original_name]'s [objectvar]: CLEAR NULLS")
@@ -155,7 +153,7 @@ GLOBAL_PROTECT(VVpixelmovement)
if(variable == "(CLEAR DUPES)")
L = uniqueList(L)
if (!O.vv_edit_var(objectvar, L))
to_chat(src, "Your edit was rejected by the object.")
to_chat(src, "Your edit was rejected by the object.", confidential = TRUE)
return
log_world("### ListVarEdit by [src]: [O.type] [objectvar]: CLEAR DUPES")
log_admin("[key_name(src)] modified [original_name]'s [objectvar]: CLEAR DUPES")
@@ -165,7 +163,7 @@ GLOBAL_PROTECT(VVpixelmovement)
if(variable == "(SHUFFLE)")
L = shuffle(L)
if (!O.vv_edit_var(objectvar, L))
to_chat(src, "Your edit was rejected by the object.")
to_chat(src, "Your edit was rejected by the object.", confidential = TRUE)
return
log_world("### ListVarEdit by [src]: [O.type] [objectvar]: SHUFFLE")
log_admin("[key_name(src)] modified [original_name]'s [objectvar]: SHUFFLE")
@@ -179,32 +177,32 @@ GLOBAL_PROTECT(VVpixelmovement)
if (index == null)
return
var/assoc = 0
if(IS_VALID_ASSOC_KEY(L[index]))
var/prompt = tgui_alert(src, "Do you want to edit the key or its assigned value?", "Associated List", list("Key", "Assigned Value", "Cancel"))
if (!prompt || prompt == "Cancel")
return
if (prompt == "Assigned Value")
assoc = 1
assoc_key = L[index]
var/prompt = tgui_alert(usr, "Do you want to edit the key or its assigned value?", "Associated List", list("Key", "Assigned Value", "Cancel"))
if (prompt == "Cancel")
return
if (prompt == "Assigned Value")
assoc = 1
assoc_key = L[index]
var/default
var/variable
var/old_assoc_value //EXPERIMENTAL - Keep old associated value while modifying key, if any
if (assoc)
variable = L[assoc_key]
else
variable = L[index]
//EXPERIMENTAL - Keep old associated value while modifying key, if any
if(IS_VALID_ASSOC_KEY(variable))
var/found = L[variable]
if(!isnull(found))
old_assoc_value = found
//
var/old_assoc_value //EXPERIMENTAL - Keep old associated value while modifying key, if any
if(is_normal_list)
if (assoc)
variable = L[assoc_key]
else
variable = L[index]
//EXPERIMENTAL - Keep old associated value while modifying key, if any
if(IS_VALID_ASSOC_KEY(variable))
var/found = L[variable]
if(!isnull(found))
old_assoc_value = found
//
default = vv_get_class(objectvar, variable)
to_chat(src, "Variable appears to be <b>[uppertext(default)]</b>.")
to_chat(src, "Variable appears to be " + span_bold("[uppertext(default)]") + ".", confidential = TRUE)
to_chat(src, "Variable contains: [variable]")
to_chat(src, "Variable contains: [variable]", confidential = TRUE)
if(default == VV_NUM)
var/dir_text = ""
@@ -220,7 +218,7 @@ GLOBAL_PROTECT(VVpixelmovement)
dir_text += "WEST"
if(dir_text)
to_chat(usr, "If a direction, direction is: [dir_text]")
to_chat(usr, "If a direction, direction is: [dir_text]", confidential = TRUE)
var/original_var = variable
@@ -248,7 +246,7 @@ GLOBAL_PROTECT(VVpixelmovement)
L.Cut(index, index+1)
if (O)
if (O.vv_edit_var(objectvar, L))
to_chat(src, "Your edit was rejected by the object.")
to_chat(src, "Your edit was rejected by the object.", confidential = TRUE)
return
log_world("### ListVarEdit by [src]: [O.type] [objectvar]: REMOVED=[html_encode("[original_var]")]")
log_admin("[key_name(src)] modified [original_name]'s [objectvar]: REMOVED=[original_var]")
@@ -261,15 +259,16 @@ GLOBAL_PROTECT(VVpixelmovement)
new_var = replacetext(new_var,"\[[V]]","[O.vars[V]]")
if(assoc)
L[assoc_key] = new_var
else
L[index] = new_var
if(!isnull(old_assoc_value) && IS_VALID_ASSOC_KEY(new_var))
L[new_var] = old_assoc_value
if(is_normal_list)
if(assoc)
L[assoc_key] = new_var
else
L[index] = new_var
if(!isnull(old_assoc_value) && IS_VALID_ASSOC_KEY(new_var))
L[new_var] = old_assoc_value
if (O)
if (O.vv_edit_var(objectvar, L) == FALSE)
to_chat(src, "Your edit was rejected by the object.")
to_chat(src, "Your edit was rejected by the object.", confidential = TRUE)
return
log_world("### ListVarEdit by [src]: [(O ? O.type : "/list")] [objectvar]: [original_var]=[new_var]")
log_admin("[key_name(src)] modified [original_name]'s [objectvar]: [original_var]=[new_var]")
@@ -297,7 +296,7 @@ GLOBAL_PROTECT(VVpixelmovement)
if(param_var_name)
if(!(param_var_name in O.vars))
to_chat(src, "A variable with this name ([param_var_name]) doesn't exist in this datum ([O])")
to_chat(src, "A variable with this name ([param_var_name]) doesn't exist in this datum ([O])", confidential = TRUE)
return
variable = param_var_name
@@ -308,17 +307,10 @@ GLOBAL_PROTECT(VVpixelmovement)
names = sortList(names)
variable = tgui_input_list(usr, "Which var?","Var", names)
variable = tgui_input_list(usr, "Which var?", "Var", names)
if(!variable)
return
if(variable in GLOB.VVpixelmovement)
if(!check_rights(R_DEBUG))
return
var/prompt = tgui_alert(src, "Editing this var may irreparably break tile gliding for the rest of the round. THIS CAN'T BE UNDONE", "DANGER", list("ABORT","Continue","ABORT"))
if (prompt != "Continue")
return
if(!O.can_vv_get(variable))
return
@@ -329,11 +321,11 @@ GLOBAL_PROTECT(VVpixelmovement)
var/default = vv_get_class(variable, var_value)
if(isnull(default))
to_chat(src, "Unable to determine variable type.")
to_chat(src, "Unable to determine variable type.", confidential = TRUE)
else
to_chat(src, "Variable appears to be <b>[uppertext(default)]</b>.")
to_chat(src, "Variable appears to be " + span_bold("[uppertext(default)]") + ".", confidential = TRUE)
to_chat(src, "Variable contains: [var_value]")
to_chat(src, "Variable contains: [var_value]", confidential = TRUE)
if(default == VV_NUM)
var/dir_text = ""
@@ -348,7 +340,7 @@ GLOBAL_PROTECT(VVpixelmovement)
dir_text += "WEST"
if(dir_text)
to_chat(src, "If a direction, direction is: [dir_text]")
to_chat(src, "If a direction, direction is: [dir_text]", confidential = TRUE)
if(autodetect_class && default != VV_NULL)
if (default == VV_TEXT)
@@ -385,9 +377,10 @@ GLOBAL_PROTECT(VVpixelmovement)
if (O.vv_edit_var(variable, var_new) == FALSE)
to_chat(src, "Your edit was rejected by the object.")
to_chat(src, "Your edit was rejected by the object.", confidential = TRUE)
return
vv_update_display(O, "varedited", VV_MSG_EDITED)
SEND_GLOBAL_SIGNAL(COMSIG_GLOB_VAR_EDIT, args)
log_world("### VarEdit by [key_name(src)]: [O.type] [variable]=[var_value] => [var_new]")
log_admin("[key_name(src)] modified [original_name]'s [variable] from [html_encode("[var_value]")] to [html_encode("[var_new]")]")
var/msg = "[key_name_admin(src)] modified [original_name]'s [variable] from [var_value] to [var_new]"

View File

@@ -0,0 +1,80 @@
/**
* ## nobody wants to learn matrix math!
*
* More than just a completely true statement, this datum is created as a tgui interface
* allowing you to modify each vector until you know what you're doing.
* Much like filteriffic, 'nobody wants to learn matrix math' is meant for developers like you and I
* to implement interesting matrix transformations without the hassle if needing to know... algebra? Damn, i'm stupid.
*/
/datum/nobody_wants_to_learn_matrix_math
var/atom/target
var/matrix/testing_matrix
/datum/nobody_wants_to_learn_matrix_math/New(atom/target)
src.target = target
testing_matrix = matrix(target.transform)
/datum/nobody_wants_to_learn_matrix_math/Destroy(force)
QDEL_NULL(testing_matrix)
return ..()
/datum/nobody_wants_to_learn_matrix_math/tgui_state(mob/user)
return ADMIN_STATE(R_VAREDIT)
/datum/nobody_wants_to_learn_matrix_math/tgui_close(mob/user)
qdel(src)
/datum/nobody_wants_to_learn_matrix_math/tgui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "MatrixMathTester")
ui.open()
/datum/nobody_wants_to_learn_matrix_math/tgui_data()
var/list/data = list()
data["matrix_a"] = testing_matrix.a
data["matrix_b"] = testing_matrix.b
data["matrix_c"] = testing_matrix.c
data["matrix_d"] = testing_matrix.d
data["matrix_e"] = testing_matrix.e
data["matrix_f"] = testing_matrix.f
data["pixelated"] = target.appearance_flags & PIXEL_SCALE
return data
/datum/nobody_wants_to_learn_matrix_math/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state)
. = ..()
if(.)
return
switch(action)
if("change_var")
var/matrix_var_name = params["var_name"]
var/matrix_var_value = params["var_value"]
if(testing_matrix.vv_edit_var(matrix_var_name, matrix_var_value) == FALSE)
to_chat(src, "Your edit was rejected by the object. This is a bug with the matrix tester, not your fault, so report it on GitHub.", confidential = TRUE)
return
set_transform()
if("scale")
testing_matrix.Scale(params["x"], params["y"])
set_transform()
if("translate")
testing_matrix.Translate(params["x"], params["y"])
set_transform()
if("shear")
testing_matrix.Shear(params["x"], params["y"])
set_transform()
if("turn")
testing_matrix.Turn(params["angle"])
set_transform()
if("toggle_pixel")
target.appearance_flags ^= PIXEL_SCALE
/datum/nobody_wants_to_learn_matrix_math/proc/set_transform()
animate(target, transform = testing_matrix, time = 0.5 SECONDS)
testing_matrix = matrix(target.transform)
/client/proc/open_matrix_tester(atom/in_atom)
if(holder)
var/datum/nobody_wants_to_learn_matrix_math/matrix_tester = new(in_atom)
matrix_tester.tgui_interact(mob)

View File

@@ -0,0 +1,212 @@
/datum/particle_editor
/// movable whose particles we want to be editing
var/atom/movable/target
/datum/particle_editor/New(atom/target)
src.target = target
/datum/particle_editor/tgui_state(mob/user)
return ADMIN_STATE(R_VAREDIT)
/datum/particle_editor/tgui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "ParticleEdit")
ui.open()
/datum/particle_editor/ui_assets(mob/user)
. = ..()
. += get_asset_datum(/datum/asset/simple/particle_editor)
///returns ui_data values for the particle editor
/particles/proc/return_ui_representation(mob/user)
var/data = list()
//affect entire set: no generators
data["width"] = width //float
data["height"] = height //float
data["count"] = count //float
data["spawning"] = spawning //float
data["bound1"] = islist(bound1) ? bound1 : list(bound1,bound1,bound1) //float OR list(x, y, z)
data["bound2"] = islist(bound2) ? bound2 : list(bound2,bound2,bound2) //float OR list(x, y, z)
data["gravity"] = gravity //list(x, y, z)
var/list/tgui_grad_list = list()
for(var/entry in gradient)
if(entry == "space")
tgui_grad_list += list(list("[entry]" = gradient[entry])) // package this thing else json encoding breaks
continue
tgui_grad_list += entry
data["gradient"] = tgui_grad_list //gradient array list(number, string, number, string, "loop", "space"=COLORSPACE_RGB)
data["transform"] = transform //list(a, b, c, d, e, f) OR list(xx,xy,xz, yx,yy,yz, zx,zy,zz) OR list(xx,xy,xz, yx,yy,yz, zx,zy,zz, cx,cy,cz) OR list(xx,xy,xz,xw, yx,yy,yz,yw, zx,zy,zz,zw, wx,wy,wz,ww)
//applied on spawn
if(islist(icon))
var/list/icon_data = list()
for(var/file in icon)
icon_data["[file]"] = icon[file]
data["icon"] = icon_data
else
data["icon"] = "[icon]" //list(icon = weight) OR file reference
data["icon_state"] = icon_state // list(icon_state = weight) OR string
if(isgenerator(lifespan))
data["lifespan"] = return_generator_args(lifespan)
else
data["lifespan"] = lifespan //float
if(isgenerator(fade))
data["fade"] = return_generator_args(fade)
else
data["fade"] = fade //float
if(isgenerator(fadein))
data["fadein"] = return_generator_args(fadein)
else
data["fadein"] = fadein //float
if(isgenerator(color))
data["color"] = return_generator_args(color)
else
data["color"] = color //float OR string
if(isgenerator(color_change))
data["color_change"] = return_generator_args(color_change)
else
data["color_change"] = color_change //float
if(isgenerator(position))
data["position"] = return_generator_args(position)
else
data["position"] = position //list(x,y) OR list(x,y,z)
if(isgenerator(velocity))
data["velocity"] = return_generator_args(velocity)
else
data["velocity"] = velocity //list(x,y) OR list(x,y,z)
if(isgenerator(scale))
data["scale"] = return_generator_args(scale)
else
data["scale"] = scale
if(isgenerator(grow))
data["grow"] = return_generator_args(grow)
else
data["grow"] = grow //float OR list(x,y)
if(isgenerator(rotation))
data["rotation"] = return_generator_args(rotation)
else
data["rotation"] = rotation
if(isgenerator(spin))
data["spin"] = return_generator_args(spin)
else
data["spin"] = spin //float
if(isgenerator(friction))
data["friction"] = return_generator_args(friction)
else
data["friction"] = friction //float: 0-1
//evaluated every tick
if(isgenerator(drift))
data["drift"] = return_generator_args(drift)
else
data["drift"] = drift
return data
/datum/particle_editor/tgui_data(mob/user)
var/list/data = list()
data["target_name"] = target.name
if(!target.particles)
target.particles = new /particles
data["particle_data"] = target.particles.return_ui_representation(user)
return data
/datum/particle_editor/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state)
. = ..()
if(.)
return
switch(action)
if("delete_and_close")
ui.close()
target.particles = null
target = null
. = FALSE
if("new_type")
var/new_type = pick_closest_path(/particles, make_types_fancy(typesof(/particles)))
if(!new_type)
return FALSE
target.particles = new new_type
target.particles.datum_flags |= DF_VAR_EDITED
. = TRUE
if("transform_size")
var/list/matrix_size = list("Simple Matrix" = 6, "Complex Matrix" = 12, "Projection Matrix" = 16)
var/new_size = matrix_size[params["new_value"]]
if(!new_size)
return FALSE
. = TRUE
target.particles.datum_flags |= DF_VAR_EDITED
if(!target.particles.transform || length(target.particles.transform) != new_size)
switch(new_size)
if(6)
target.particles.transform = list(1,0,0, 1,0,0) // TRANSFORM_MATRIX_IDENTITY seems wrong for only particles?
if(12)
target.particles.transform = TRANSFORM_COMPLEX_MATRIX_IDENTITY
if(16)
target.particles.transform = TRANSFORM_PROJECTION_MATRIX_IDENTITY
return
if("edit")
var/particles/owner = target.particles
var/param_var_name = params["var"]
if(!(param_var_name in owner.vars))
return FALSE
var/var_value = params["new_value"]
var/var_mod = params["var_mod"]
// we can only return arrays from tgui so lets convert it to something usable if needed
switch(var_mod)
if(P_DATA_GENERATOR)
//these MUST be vectors and the others MUST be floats
if(var_value[1] in list(GEN_VECTOR, GEN_BOX))
if(!islist(var_value[2]))
var_value[2] = list(var_value[2],var_value[2],var_value[2])
if(!islist(var_value[3]))
var_value[3] = list(var_value[3],var_value[3],var_value[3])
//this means we just switched off a vector-requiring generator type
else if(islist(var_value[2]) && islist(var_value[3]))
var_value[2] = var_value[1]
var_value[3] = var_value[1]
var_value = generator(arglist(var_value))
if(P_DATA_ICON_ADD)
var_value = pick_and_customize_icon(ui.user, pick_only=TRUE)
if(!var_value)
return FALSE
var/list/new_values = list()
new_values += var_value
new_values[var_value] = 1
if(isicon(owner.icon))
new_values[owner.icon] = 1
owner.icon = new_values
else if(islist(owner.icon))
owner.icon[var_value] = 1
else
owner.icon = new_values
target.particles.datum_flags |= DF_VAR_EDITED
return TRUE
if(P_DATA_ICON_REMOVE)
for(var/file in owner.icon)
if("[file]" == var_value)
owner.icon -= file
UNSETEMPTY(owner.icon)
target.particles.datum_flags |= DF_VAR_EDITED
return TRUE
if(P_DATA_ICON_WEIGHT)
// [filename, new_weight]
var/list/mod_data = var_value
for(var/file in owner.icon)
if("[file]" == mod_data[1])
owner.icon[file] = mod_data[2]
target.particles.datum_flags |= DF_VAR_EDITED
return TRUE
if(P_DATA_GRADIENT)
var/list/new_grad_list = list()
for(var/entry in var_value)
new_grad_list += entry // Unpackage nested lists
owner.gradient = new_grad_list
target.particles.datum_flags |= DF_VAR_EDITED
return TRUE
owner.vars[param_var_name] = var_value
target.particles.datum_flags |= DF_VAR_EDITED
return TRUE

View File

@@ -0,0 +1,207 @@
#ifdef REFERENCE_TRACKING
#define REFSEARCH_RECURSE_LIMIT 64
/datum/proc/find_references(references_to_clear = INFINITY)
if(usr?.client)
if(tgui_alert(usr,"Running this will lock everything up for about 5 minutes. Would you like to begin the search?", "Find References", list("Yes", "No")) != "Yes")
return
src.references_to_clear = references_to_clear
//this keeps the garbage collector from failing to collect objects being searched for in here
SSgarbage.can_fire = FALSE
_search_references()
//restart the garbage collector
SSgarbage.can_fire = TRUE
SSgarbage.update_nextfire(reset_time = TRUE)
/datum/proc/_search_references()
log_reftracker("Beginning search for references to a [type], looking for [references_to_clear] refs.")
var/starting_time = world.time
//Time to search the whole game for our ref
DoSearchVar(GLOB, "GLOB", starting_time) //globals
log_reftracker("Finished searching globals")
if(src.references_to_clear == 0)
return
//Yes we do actually need to do this. The searcher refuses to read weird lists
//And global.vars is a really weird list
var/global_vars = list()
for(var/key in global.vars)
global_vars[key] = global.vars[key]
DoSearchVar(global_vars, "Native Global", starting_time)
log_reftracker("Finished searching native globals")
if(src.references_to_clear == 0)
return
for(var/datum/thing in world) //atoms (don't beleive its lies)
DoSearchVar(thing, "World -> [thing.type]", starting_time)
if(src.references_to_clear == 0)
break
log_reftracker("Finished searching atoms")
if(src.references_to_clear == 0)
return
for(var/datum/thing) //datums
DoSearchVar(thing, "Datums -> [thing.type]", starting_time)
if(src.references_to_clear == 0)
break
log_reftracker("Finished searching datums")
if(src.references_to_clear == 0)
return
//Warning, attempting to search clients like this will cause crashes if done on live. Watch yourself
#ifndef REFERENCE_DOING_IT_LIVE
for(var/client/thing) //clients
DoSearchVar(thing, "Clients -> [thing.type]", starting_time)
if(src.references_to_clear == 0)
break
log_reftracker("Finished searching clients")
if(src.references_to_clear == 0)
return
#endif
log_reftracker("Completed search for references to a [type].")
/datum/proc/DoSearchVar(potential_container, container_name, search_time, recursion_count, is_special_list)
if(recursion_count >= REFSEARCH_RECURSE_LIMIT)
log_reftracker("Recursion limit reached. [container_name]")
return
if(references_to_clear == 0)
return
//Check each time you go down a layer. This makes it a bit slow, but it won't effect the rest of the game at all
#ifndef FIND_REF_NO_CHECK_TICK
CHECK_TICK
#endif
if(isdatum(potential_container))
var/datum/datum_container = potential_container
if(datum_container.last_find_references == search_time)
return
datum_container.last_find_references = search_time
var/list/vars_list = datum_container.vars
var/is_atom = FALSE
var/is_area = FALSE
if(isatom(datum_container))
is_atom = TRUE
if(isarea(datum_container))
is_area = TRUE
for(var/varname in vars_list)
var/variable = vars_list[varname]
if(islist(variable))
//Fun fact, vis_locs don't count for references
if(varname == "vars" || (is_atom && (varname == "vis_locs" || varname == "overlays" || varname == "underlays" || varname == "filters" || varname == "verbs" || (is_area && varname == "contents"))))
continue
// We do this after the varname check to avoid area contents (reading it incures a world loop's worth of cost)
if(!length(variable))
continue
DoSearchVar(variable,\
"[container_name] [datum_container.ref_search_details()] -> [varname] (list)",\
search_time,\
recursion_count + 1,\
/*is_special_list = */ is_atom && (varname == "contents" || varname == "vis_contents" || varname == "locs"))
else if(variable == src)
#ifdef REFERENCE_TRACKING_DEBUG
if(SSgarbage.should_save_refs)
if(!found_refs)
found_refs = list()
found_refs[varname] = TRUE
continue //End early, don't want these logging
else
log_reftracker("Found [type] [text_ref(src)] in [datum_container.type]'s [datum_container.ref_search_details()] [varname] var. [container_name]")
#else
log_reftracker("Found [type] [text_ref(src)] in [datum_container.type]'s [datum_container.ref_search_details()] [varname] var. [container_name]")
#endif
references_to_clear -= 1
if(references_to_clear == 0)
log_reftracker("All references to [type] [text_ref(src)] found, exiting.")
return
continue
else if(islist(potential_container))
var/list/potential_cache = potential_container
for(var/element_in_list in potential_cache)
//Check normal sublists
if(islist(element_in_list))
if(length(element_in_list))
DoSearchVar(element_in_list, "[container_name] -> [element_in_list] (list)", search_time, recursion_count + 1)
//Check normal entrys
else if(element_in_list == src)
#ifdef REFERENCE_TRACKING_DEBUG
if(SSgarbage.should_save_refs)
if(!found_refs)
found_refs = list()
found_refs[potential_cache] = TRUE
continue
else
log_reftracker("Found [type] [text_ref(src)] in list [container_name].")
#else
log_reftracker("Found [type] [text_ref(src)] in list [container_name].")
#endif
// This is dumb as hell I'm sorry
// I don't want the garbage subsystem to count as a ref for the purposes of this number
// If we find all other refs before it I want to early exit, and if we don't I want to keep searching past it
var/ignore_ref = FALSE
var/list/queues = SSgarbage.queues
for(var/list/queue in queues)
if(potential_cache in queue)
ignore_ref = TRUE
break
if(ignore_ref)
log_reftracker("[container_name] does not count as a ref for our count")
else
references_to_clear -= 1
if(references_to_clear == 0)
log_reftracker("All references to [type] [text_ref(src)] found, exiting.")
return
if(!isnum(element_in_list) && !is_special_list)
// This exists to catch an error that throws when we access a special list
// is_special_list is a hint, it can be wrong
try
var/assoc_val = potential_cache[element_in_list]
//Check assoc sublists
if(islist(assoc_val))
if(length(assoc_val))
DoSearchVar(potential_container[element_in_list], "[container_name]\[[element_in_list]\] -> [assoc_val] (list)", search_time, recursion_count + 1)
//Check assoc entry
else if(assoc_val == src)
#ifdef REFERENCE_TRACKING_DEBUG
if(SSgarbage.should_save_refs)
if(!found_refs)
found_refs = list()
found_refs[potential_cache] = TRUE
continue
else
log_reftracker("Found [type] [text_ref(src)] in list [container_name]\[[element_in_list]\]")
#else
log_reftracker("Found [type] [text_ref(src)] in list [container_name]\[[element_in_list]\]")
#endif
references_to_clear -= 1
if(references_to_clear == 0)
log_reftracker("All references to [type] [text_ref(src)] found, exiting.")
return
catch
// So if it goes wrong we kill it
is_special_list = TRUE
log_reftracker("Curiosity: [container_name] lead to an error when acessing [element_in_list], what is it?")
#undef REFSEARCH_RECURSE_LIMIT
#endif
// Kept outside the ifdef so overrides are easy to implement
/// Return info about us for reference searching purposes
/// Will be logged as a representation of this datum if it's a part of a search chain
/datum/proc/ref_search_details()
return text_ref(src)
/datum/callback/ref_search_details()
return "[text_ref(src)] (obj: [object] proc: [delegate] args: [json_encode(arguments)] user: [user?.resolve() || "null"])"

View File

@@ -0,0 +1,16 @@
/client/proc/tag_datum(datum/target_datum)
if(!holder || QDELETED(target_datum))
return
holder.add_tagged_datum(target_datum)
/client/proc/toggle_tag_datum(datum/target_datum)
if(!holder || !target_datum)
return
if(LAZYFIND(holder.tagged_datums, target_datum))
holder.remove_tagged_datum(target_datum)
else
holder.add_tagged_datum(target_datum)
ADMIN_VERB_ONLY_CONTEXT_MENU(tag_datum, R_NONE, "Tag Datum", datum/target_datum as mob|obj|turf|area in view())
user.tag_datum(target_datum)

View File

@@ -1,587 +1,157 @@
//DO NOT ADD MORE TO THIS FILE.
//Use vv_do_topic()!
//Use vv_do_topic() for datums!
/client/proc/view_var_Topic(href, href_list, hsrc)
if((usr.client != src) || !check_rights(R_HOLDER))
if(!check_rights_for(src, R_VAREDIT) || !holder.CheckAdminHref(href, href_list))
return
var/datum/target = locate(href_list["target"])
if(istype(target))
target.vv_do_topic(href_list)
var/target = GET_VV_TARGET
vv_do_basic(target, href_list, href)
if(isdatum(target))
var/datum/D = target
D.vv_do_topic(href_list)
else if(islist(target))
vv_do_list(target, href_list)
if(href_list["Vars"])
debug_variables(locate(href_list["Vars"]))
var/datum/vars_target = locate(href_list["Vars"])
if(href_list["special_varname"]) // Some special vars can't be located even if you have their ref, you have to use this instead
vars_target = vars_target.vars[href_list["special_varname"]]
debug_variables(vars_target)
//~CARN: for renaming mobs (updates their name, real_name, mind.name, their ID/PDA and datacore records).
else if(href_list["rename"])
if(!check_rights(R_VAREDIT)) return
//~CARN: for renaming mobs (updates their name, real_name, mind.name, their ID/PDA and datacore records).
if(href_list["rename"])
var/mob/M = locate(href_list["rename"])
var/mob/M = locate(href_list["rename"]) in mob_list
if(!istype(M))
to_chat(src, "This can only be used on instances of type /mob")
to_chat(usr, "This can only be used on instances of type /mob", confidential = TRUE)
return
var/new_name = sanitize(tgui_input_text(src,"What would you like to name this mob?","Input a name",M.real_name,MAX_NAME_LEN), MAX_NAME_LEN)
if( !new_name || !M ) return
var/new_name = stripped_input(usr,"What would you like to name this mob?","Input a name",M.real_name,MAX_NAME_LEN)
// If the new name is something that would be restricted by IC chat filters,
// give the admin a warning but allow them to do it anyway if they want.
//if(is_ic_filtered(new_name) || is_soft_ic_filtered(new_name) && tgui_alert(usr, "Your selected name contains words restricted by IC chat filters. Confirm this new name?", "IC Chat Filter Conflict", list("Confirm", "Cancel")) == "Cancel")
// return
if( !new_name || !M )
return
message_admins("Admin [key_name_admin(usr)] renamed [key_name_admin(M)] to [new_name].")
M.fully_replace_character_name(M.real_name,new_name)
href_list["datumrefresh"] = href_list["rename"]
else if(href_list["varnameedit"] && href_list["datumedit"])
if(!check_rights(R_VAREDIT)) return
var/D = locate(href_list["datumedit"])
if(!istype(D,/datum) && !istype(D,/client))
to_chat(src, "This can only be used on instances of types /client or /datum")
return
modify_variables(D, href_list["varnameedit"], 1)
else if(href_list["varnamechange"] && href_list["datumchange"])
if(!check_rights(R_VAREDIT)) return
var/D = locate(href_list["datumchange"])
if(!istype(D,/datum) && !istype(D,/client))
to_chat(src, "This can only be used on instances of types /client or /datum")
return
modify_variables(D, href_list["varnamechange"], 0)
else if(href_list["varnamemass"] && href_list["datummass"])
if(!check_rights(R_VAREDIT)) return
var/atom/A = locate(href_list["datummass"])
if(!istype(A))
to_chat(src, "This can only be used on instances of type /atom")
return
cmd_mass_modify_object_variables(A, href_list["varnamemass"])
else if(href_list["mob_player_panel"])
if(!check_rights(0)) return
var/mob/M = locate(href_list["mob_player_panel"])
if(!istype(M))
to_chat(src, "This can only be used on instances of type /mob")
return
src.holder.show_player_panel(M)
href_list["datumrefresh"] = href_list["mob_player_panel"]
else if(href_list["give_spell"])
if(!check_rights(R_ADMIN|R_FUN|R_EVENT)) return
var/mob/M = locate(href_list["give_spell"])
if(!istype(M))
to_chat(src, "This can only be used on instances of type /mob")
return
src.give_spell(M)
href_list["datumrefresh"] = href_list["give_spell"]
else if(href_list["give_modifier"])
if(!check_rights(R_ADMIN|R_FUN|R_DEBUG|R_EVENT))
return
var/mob/living/M = locate(href_list["give_modifier"])
if(!istype(M))
to_chat(src, "This can only be used on instances of type /mob/living")
return
src.admin_give_modifier(M)
href_list["datumrefresh"] = href_list["give_modifier"]
else if(href_list["give_wound_internal"])
if(!check_rights(R_ADMIN|R_FUN|R_DEBUG|R_EVENT))
return
var/mob/living/carbon/human/H = locate(href_list["give_wound_internal"])
if(!istype(H))
to_chat(src, span_notice("This can only be used on instances of type /mob/living/carbon/human"))
return
var/severity = tgui_input_number(src, "How much damage should the bleeding internal wound cause? \
Bleed timer directly correlates with this. 0 cancels. Input is rounded to nearest integer.",
"Wound Severity", 0)
if(!severity) return
var/obj/item/organ/external/chosen_organ = tgui_input_list(src, "Choose an external organ to inflict IB on!", "Organ Choice", H.organs)
if(!chosen_organ || !istype(chosen_organ))
to_chat(usr, span_notice("The chosen organ is of inappropriate type or no longer exists."))
return
var/datum/wound/internal_bleeding/I = new /datum/wound/internal_bleeding(severity)
if(!I || !istype(I))
to_chat(src, span_notice("Could not initialize internal wound"))
log_debug("[usr] attempted to create an internal bleeding wound on [H]'s [chosen_organ] of [severity] damage \
and wound initialization failed")
chosen_organ.wounds += I
chosen_organ.update_wounds()
chosen_organ.update_damages()
H.bad_external_organs += chosen_organ
H.handle_organs()
if(H.client)
H.custom_pain("You feel a throbbing pain inside your [chosen_organ]", severity, force=TRUE)
log_and_message_admins("created an Internal Bleeding wound on [H.ckey]'s mob [H] on [chosen_organ] of [severity] damage", usr)
href_list["datumrefresh"] = href_list["give_wound_internal"]
else if(href_list["godmode"])
if(!check_rights(R_REJUVINATE)) return
var/mob/M = locate(href_list["godmode"])
if(!istype(M))
to_chat(src, "This can only be used on instances of type /mob")
return
src.cmd_admin_godmode(M)
href_list["datumrefresh"] = href_list["godmode"]
else if(href_list["gib"])
if(!check_rights(0)) return
var/mob/M = locate(href_list["gib"])
if(!istype(M))
to_chat(src, "This can only be used on instances of type /mob")
return
src.cmd_admin_gib(M)
else if(href_list["build_mode"])
if(!check_rights(R_BUILDMODE)) return
var/mob/M = locate(href_list["build_mode"])
if(!istype(M))
to_chat(src, "This can only be used on instances of type /mob")
return
togglebuildmode(M)
href_list["datumrefresh"] = href_list["build_mode"]
else if(href_list["drop_everything"])
if(!check_rights(R_DEBUG|R_ADMIN|R_EVENT)) return
var/mob/M = locate(href_list["drop_everything"])
if(!istype(M))
to_chat(src, "This can only be used on instances of type /mob")
return
if(usr.client)
usr.client.cmd_admin_drop_everything(M)
else if(href_list["direct_control"])
if(!check_rights(0)) return
var/mob/M = locate(href_list["direct_control"])
if(!istype(M))
to_chat(src, "This can only be used on instances of type /mob")
return
if(usr.client)
usr.client.cmd_assume_direct_control(M)
else if(href_list["give_ai"])
if(!check_rights(0)) return
var/mob/M = locate(href_list["give_ai"])
if(!isliving(M))
to_chat(src, span_notice("This can only be used on instances of type /mob/living"))
return
var/mob/living/L = M
if(L.client || L.teleop)
to_chat(src, span_warning("This cannot be used on player mobs!"))
return
if(L.ai_holder) //Cleaning up the original ai
var/ai_holder_old = L.ai_holder
L.ai_holder = null
qdel(ai_holder_old) //Only way I could make #TESTING - Unable to be GC'd to stop. del() logs show it works.
L.ai_holder_type = tgui_input_list(src, "Choose AI holder", "AI Type", typesof(/datum/ai_holder/))
L.initialize_ai_holder()
L.faction = sanitize(tgui_input_text(src, "Please input AI faction", "AI faction", "neutral"))
L.a_intent = tgui_input_list(src, "Please choose AI intent", "AI intent", list(I_HURT, I_HELP))
if(tgui_alert(src, "Make mob wake up? This is needed for carbon mobs.", "Wake mob?", list("Yes", "No")) == "Yes")
L.AdjustSleeping(-100)
else if(href_list["make_skeleton"])
if(!check_rights(R_FUN)) return
var/mob/living/carbon/human/H = locate(href_list["make_skeleton"])
if(!istype(H))
to_chat(src, "This can only be used on instances of type /mob/living/carbon/human")
return
H.ChangeToSkeleton()
href_list["datumrefresh"] = href_list["make_skeleton"]
else if(href_list["delall"])
if(!check_rights(R_DEBUG|R_SERVER))
return
var/obj/O = locate(href_list["delall"])
if(!isobj(O))
to_chat(src, "This can only be used on instances of type /obj")
return
var/action_type = tgui_alert(src, "Strict type ([O.type]) or type and all subtypes?","Type Selection",list("Strict type","Type and subtypes","Cancel"))
if(action_type == "Cancel" || !action_type)
return
if(tgui_alert(src, "Are you really sure you want to delete all objects of type [O.type]?","Delete All?",list("Yes","No")) != "Yes")
return
if(tgui_alert(src, "Second confirmation required. Delete?","REALLY?",list("Yes","No")) != "Yes")
return
var/O_type = O.type
switch(action_type)
if("Strict type")
var/i = 0
for(var/obj/Obj in world)
if(Obj.type == O_type)
i++
qdel(Obj)
CHECK_TICK
if(!i)
to_chat(src, "No objects of this type exist")
return
log_admin("[key_name(usr)] deleted all objects of type [O_type] ([i] objects deleted) ")
message_admins(span_notice("[key_name(usr)] deleted all objects of type [O_type] ([i] objects deleted) "))
if("Type and subtypes")
var/i = 0
for(var/obj/Obj in world)
if(istype(Obj,O_type))
i++
qdel(Obj)
CHECK_TICK
if(!i)
to_chat(src, "No objects of this type exist")
return
log_admin("[key_name(usr)] deleted all objects of type or subtype of [O_type] ([i] objects deleted) ")
message_admins(span_notice("[key_name(usr)] deleted all objects of type or subtype of [O_type] ([i] objects deleted) "))
else if(href_list["fakepdapropconvo"])
if(!check_rights(R_FUN)) return
var/obj/item/pda/P = locate(href_list["fakepdapropconvo"])
if(!istype(P))
to_chat(src, span_warning("This can only be done to instances of type /pda"))
return
P.createPropFakeConversation_admin(usr)
vv_update_display(M, "name", new_name)
vv_update_display(M, "real_name", M.real_name || "No real name")
else if(href_list["rotatedatum"])
if(!check_rights(0)) return
var/atom/A = locate(href_list["rotatedatum"])
if(!istype(A))
to_chat(src, "This can only be done to instances of type /atom")
to_chat(usr, "This can only be done to instances of type /atom", confidential = TRUE)
return
switch(href_list["rotatedir"])
if("right") A.set_dir(turn(A.dir, -45))
if("left") A.set_dir(turn(A.dir, 45))
href_list["datumrefresh"] = href_list["rotatedatum"]
if("right")
A.set_dir(turn(A.dir, -45))
if("left")
A.set_dir(turn(A.dir, 45))
vv_update_display(A, "dir", dir2text(A.dir))
else if(href_list["makemonkey"])
if(!check_rights(R_SPAWN)) return
var/mob/living/carbon/human/H = locate(href_list["makemonkey"])
if(!istype(H))
to_chat(src, "This can only be done to instances of type /mob/living/carbon/human")
return
if(tgui_alert(src, "Confirm mob type change?","Confirm",list("Transform","Cancel")) != "Transform") return
if(!H)
to_chat(src, "Mob doesn't exist anymore")
return
holder.Topic(href, list("monkeyone"=href_list["makemonkey"]))
else if(href_list["makerobot"])
if(!check_rights(R_SPAWN)) return
var/mob/living/carbon/human/H = locate(href_list["makerobot"])
if(!istype(H))
to_chat(src, "This can only be done to instances of type /mob/living/carbon/human")
return
if(tgui_alert(src, "Confirm mob type change?","Confirm",list("Transform","Cancel")) != "Transform") return
if(!H)
to_chat(src, "Mob doesn't exist anymore")
return
holder.Topic(href, list("makerobot"=href_list["makerobot"]))
else if(href_list["makealien"])
if(!check_rights(R_SPAWN)) return
var/mob/living/carbon/human/H = locate(href_list["makealien"])
if(!istype(H))
to_chat(src, "This can only be done to instances of type /mob/living/carbon/human")
return
if(tgui_alert(src, "Confirm mob type change?","Confirm",list("Transform","Cancel")) != "Transform") return
if(!H)
to_chat(src, "Mob doesn't exist anymore")
return
holder.Topic(href, list("makealien"=href_list["makealien"]))
else if(href_list["makeai"])
if(!check_rights(R_SPAWN)) return
var/mob/living/carbon/human/H = locate(href_list["makeai"])
if(!istype(H))
to_chat(src, "This can only be done to instances of type /mob/living/carbon/human")
return
if(tgui_alert(src, "Confirm mob type change?","Confirm",list("Transform","Cancel")) != "Transform") return
if(!H)
to_chat(src, "Mob doesn't exist anymore")
return
holder.Topic(href, list("makeai"=href_list["makeai"]))
else if(href_list["setspecies"])
if(!check_rights(R_SPAWN)) return
var/mob/living/carbon/human/H = locate(href_list["setspecies"])
if(!istype(H))
to_chat(src, "This can only be done to instances of type /mob/living/carbon/human")
return
var/new_species = tgui_input_list(src, "Please choose a new species.","Species", GLOB.all_species)
if(!H)
to_chat(src, "Mob doesn't exist anymore")
return
if(H.set_species(new_species))
to_chat(src, "Set species of [H] to [H.species].")
else
to_chat(src, "Failed! Something went wrong.")
else if(href_list["addlanguage"])
if(!check_rights(R_SPAWN)) return
var/mob/H = locate(href_list["addlanguage"])
if(!istype(H))
to_chat(src, "This can only be done to instances of type /mob")
return
var/new_language = tgui_input_list(src, "Please choose a language to add.","Language", GLOB.all_languages)
if(!new_language)
return
if(!H)
to_chat(src, "Mob doesn't exist anymore")
return
if(H.add_language(new_language))
to_chat(src, "Added [new_language] to [H].")
else
to_chat(src, "Mob already knows that language.")
else if(href_list["remlanguage"])
if(!check_rights(R_SPAWN)) return
var/mob/H = locate(href_list["remlanguage"])
if(!istype(H))
to_chat(src, "This can only be done to instances of type /mob")
return
if(!H.languages.len)
to_chat(src, "This mob knows no languages.")
return
var/datum/language/rem_language = tgui_input_list(src, "Please choose a language to remove.","Language", H.languages)
if(!rem_language)
return
if(!H)
to_chat(src, "Mob doesn't exist anymore")
return
if(H.remove_language(rem_language.name))
to_chat(src, "Removed [rem_language] from [H].")
else
to_chat(src, "Mob doesn't know that language.")
else if(href_list["addverb"])
if(!check_rights(R_DEBUG)) return
var/mob/H = locate(href_list["addverb"])
if(!ismob(H))
to_chat(src, "This can only be done to instances of type /mob")
return
var/list/possibleverbs = list()
possibleverbs += "Cancel" // One for the top...
possibleverbs += typesof(/mob/proc, /mob/verb)
if(isobserver(H))
possibleverbs += typesof(/mob/observer/dead/proc,/mob/observer/dead/verb)
if(isliving(H))
possibleverbs += typesof(/mob/living/proc,/mob/living/verb)
if(ishuman(H))
possibleverbs += typesof(/mob/living/carbon/proc,/mob/living/carbon/verb,/mob/living/carbon/human/verb,/mob/living/carbon/human/proc)
if(isrobot(H))
possibleverbs += typesof(/mob/living/silicon/proc,/mob/living/silicon/robot/proc,/mob/living/silicon/robot/verb)
if(isAI(H))
possibleverbs += typesof(/mob/living/silicon/proc,/mob/living/silicon/ai/proc,/mob/living/silicon/ai/verb)
if(isanimal(H))
possibleverbs += typesof(/mob/living/simple_mob/proc)
possibleverbs -= H.verbs
possibleverbs += "Cancel" // ...And one for the bottom
var/verb = tgui_input_list(src, "Select a verb!", "Verbs", possibleverbs)
if(!H)
to_chat(src, "Mob doesn't exist anymore")
return
if(!verb || verb == "Cancel")
return
else
add_verb(H, verb)
else if(href_list["remverb"])
if(!check_rights(R_DEBUG)) return
var/mob/H = locate(href_list["remverb"])
if(!istype(H))
to_chat(src, "This can only be done to instances of type /mob")
return
var/verb = tgui_input_list(src, "Please choose a verb to remove.","Verbs", H.verbs)
if(!H)
to_chat(src, "Mob doesn't exist anymore")
return
if(!verb)
return
else
remove_verb(H, verb)
else if(href_list["addorgan"])
if(!check_rights(R_SPAWN)) return
var/mob/living/carbon/M = locate(href_list["addorgan"])
if(!istype(M))
to_chat(src, "This can only be done to instances of type /mob/living/carbon")
return
var/new_organ = tgui_input_list(src, "Please choose an organ to add.","Organ", subtypesof(/obj/item/organ))
if(!new_organ) return
if(!M)
to_chat(src, "Mob doesn't exist anymore")
return
if(locate(new_organ) in M.internal_organs)
to_chat(src, "Mob already has that organ.")
return
new new_organ(M)
else if(href_list["remorgan"])
if(!check_rights(R_SPAWN)) return
var/mob/living/carbon/M = locate(href_list["remorgan"])
if(!istype(M))
to_chat(src, "This can only be done to instances of type /mob/living/carbon")
return
var/obj/item/organ/rem_organ = tgui_input_list(src, "Please choose an organ to remove.","Organ", M.internal_organs)
if(!M)
to_chat(src, "Mob doesn't exist anymore")
return
if(!(locate(rem_organ) in M.internal_organs))
to_chat(src, "Mob does not have that organ.")
return
to_chat(src, "Removed [rem_organ] from [M].")
rem_organ.removed()
qdel(rem_organ)
else if(href_list["fix_nano"])
if(!check_rights(R_DEBUG)) return
var/mob/H = locate(href_list["fix_nano"])
if(!istype(H) || !H.client)
to_chat(src, "This can only be done on mobs with clients")
return
H.client.send_resources()
to_chat(src, "Resource files sent")
to_chat(H, "Your NanoUI Resource files have been refreshed")
log_admin("[key_name(usr)] resent the NanoUI resource files to [key_name(H)] ")
else if(href_list["regenerateicons"])
if(!check_rights(0)) return
var/mob/M = locate(href_list["regenerateicons"])
if(!ismob(M))
to_chat(src, "This can only be done to instances of type /mob")
return
M.regenerate_icons()
else if(href_list["adjustDamage"] && href_list["mobToDamage"])
if(!check_rights(R_DEBUG|R_ADMIN|R_FUN|R_EVENT)) return
var/mob/living/L = locate(href_list["mobToDamage"])
if(!istype(L)) return
var/mob/living/L = locate(href_list["mobToDamage"]) in mob_list
if(!istype(L))
return
var/Text = href_list["adjustDamage"]
var/amount = tgui_input_number(src, "Deal how much damage to mob? (Negative values here heal)","Adjust [Text]loss",0, min_value=-INFINITY, round_value=FALSE)
var/amount = tgui_input_number(src, "Deal how much damage to mob? (Negative values here heal)", "Adjust [Text]loss", 0, min_value=-INFINITY, round_value=FALSE)
if(!L)
to_chat(src, "Mob doesn't exist anymore")
if (isnull(amount))
return
if(!L)
to_chat(usr, "Mob doesn't exist anymore", confidential = TRUE)
return
var/newamt
switch(Text)
if("brute") L.adjustBruteLoss(amount)
if("fire") L.adjustFireLoss(amount)
if("toxin") L.adjustToxLoss(amount)
if("oxygen")L.adjustOxyLoss(amount)
if("brain") L.adjustBrainLoss(amount)
if("clone") L.adjustCloneLoss(amount)
if("brute")
L.adjustBruteLoss(amount)
newamt = L.getBruteLoss()
if("fire")
L.adjustFireLoss(amount)
newamt = L.getFireLoss()
if("toxin")
L.adjustToxLoss(amount)
newamt = L.getToxLoss()
if("oxygen")
L.adjustOxyLoss(amount)
newamt = L.getOxyLoss()
if("brain")
L.adjustBrainLoss(amount)
newamt = L.getBrainLoss()
if("clone")
L.adjustCloneLoss(amount)
newamt = L.getCloneLoss()
//if("brain")
// L.adjustOrganLoss(ORGAN_SLOT_BRAIN, amount)
// newamt = L.get_organ_loss(ORGAN_SLOT_BRAIN)
//if("stamina")
// L.adjustStaminaLoss(amount, forced = TRUE)
// newamt = L.getStaminaLoss()
else
to_chat(src, "You caused an error. DEBUG: Text:[Text] Mob:[L]")
to_chat(usr, "You caused an error. DEBUG: Text:[Text] Mob:[L]", confidential = TRUE)
return
if(amount != 0)
log_admin("[key_name(usr)] dealt [amount] amount of [Text] damage to [L]")
message_admins(span_notice("[key_name(usr)] dealt [amount] amount of [Text] damage to [L]"))
href_list["datumrefresh"] = href_list["mobToDamage"]
else if(href_list["expose"])
if(!check_rights(R_ADMIN, FALSE))
return
var/thing = locate(href_list["expose"])
if(!thing) //Do NOT QDELETED check!
return
var/value = vv_get_value(VV_CLIENT)
if (value["class"] != VV_CLIENT)
return
var/client/C = value["value"]
if (!C)
return
var/prompt = tgui_alert(src, "Do you want to grant [C] access to view this VV window? (they will not be able to edit or change anysrc nor open nested vv windows unless they themselves are an admin)", "Confirm", list("Yes", "No"))
if (prompt != "Yes")
return
if(!thing)
to_chat(src, span_warning("The object you tried to expose to [C] no longer exists (GC'd)"))
return
message_admins("[key_name_admin(usr)] Showed [key_name_admin(C)] a <a href='byond://?_src_=vars;[HrefToken(TRUE)];datumrefresh=\ref[thing]'>VV window</a>")
log_admin("Admin [key_name(usr)] Showed [key_name(C)] a VV window of a [src]")
to_chat(C, "[holder.fakekey ? "an Administrator" : "[usr.client.key]"] has granted you access to view a View Variables window")
C.debug_variables(thing)
var/log_msg = "[key_name(usr)] dealt [amount] amount of [Text] damage to [key_name(L)]"
message_admins("[key_name(usr)] dealt [amount] amount of [Text] damage to [ADMIN_LOOKUPFLW(L)]")
log_admin(log_msg)
admin_ticket_log(L, "<font color='blue'>[log_msg]</font>")
vv_update_display(L, Text, "[newamt]")
else if(href_list["item_to_tweak"] && href_list["var_tweak"])
var/obj/item/editing = locate(href_list["item_to_tweak"])
if(!istype(editing) || QDELING(editing))
return
var/existing_val = -1
switch(href_list["var_tweak"])
if("damtype")
existing_val = editing.damtype
if("force")
existing_val = editing.force
//if("wound")
// existing_val = editing.wound_bonus
//if("bare wound")
// existing_val = editing.exposed_wound_bonus
else
CRASH("Invalid var_tweak passed to item vv set var: [href_list["var_tweak"]]")
var/new_val
if(href_list["var_tweak"] == "damtype")
//new_val = tgui_input_list(usr, "Enter the new damage type for [editing]", "Set Damtype", list(BRUTE, BURN, TOX, OXY, STAMINA, BRAIN), existing_val)
new_val = tgui_input_list(usr, "Enter the new damage type for [editing]","Set Damtype", list(BRUTE, BURN, TOX, OXY, CLONE, HALLOSS, ELECTROCUTE, BIOACID, SEARING, ELECTROMAG), existing_val)
else
new_val = tgui_input_number(usr, "Enter the new value for [editing]'s [href_list["var_tweak"]]","Set [href_list["var_tweak"]]", existing_val)
if(isnull(new_val) || new_val == existing_val || QDELETED(editing) || !check_rights(R_VAREDIT))
return
switch(href_list["var_tweak"])
if("damtype")
editing.damtype = new_val
if("force")
editing.force = new_val
//if("wound")
// editing.wound_bonus = new_val
//if("bare wound")
// editing.exposed_wound_bonus = new_val
message_admins("[key_name(usr)] set [editing]'s [href_list["var_tweak"]] to [new_val] (was [existing_val])")
log_admin("[key_name(usr)] set [editing]'s [href_list["var_tweak"]] to [new_val] (was [existing_val])")
vv_update_display(editing, href_list["var_tweak"], istext(new_val) ? uppertext(new_val) : new_val)
//Finally, refresh if something modified the list.
if(href_list["datumrefresh"])
var/datum/DAT = locate(href_list["datumrefresh"])
if(istype(DAT, /datum) || istype(DAT, /client) || islist(DAT))
if(isdatum(DAT) || istype(DAT, /client) || islist(DAT))
debug_variables(DAT)

View File

@@ -0,0 +1,145 @@
//Not using datum.vv_do_topic for very basic/low level debug things, incase the datum's vv_do_topic is runtiming/whatnot.
/client/proc/vv_do_basic(datum/target, href_list)
var/target_var = GET_VV_VAR_TARGET
if(check_rights(R_VAREDIT))
if(target_var)
if(href_list[VV_HK_BASIC_EDIT])
if(!modify_variables(target, target_var, 1))
return
switch(target_var)
if("name")
vv_update_display(target, "name", "[target]")
if("dir")
var/atom/A = target
if(istype(A))
vv_update_display(target, "dir", dir2text(A.dir) || A.dir)
if("ckey")
var/mob/living/L = target
if(istype(L))
vv_update_display(target, "ckey", L.ckey || "No ckey")
if("real_name")
var/mob/living/L = target
if(istype(L))
vv_update_display(target, "real_name", L.real_name || "No real name")
if(href_list[VV_HK_BASIC_CHANGE])
modify_variables(target, target_var, 0)
if(href_list[VV_HK_BASIC_MASSEDIT])
cmd_mass_modify_object_variables(target, target_var)
if(check_rights(R_ADMIN, FALSE))
if(href_list[VV_HK_EXPOSE])
var/value = vv_get_value(VV_CLIENT)
if (value["class"] != VV_CLIENT)
return
var/client/C = value["value"]
if (!C)
return
if(!target)
to_chat(usr, span_warning("The object you tried to expose to [C] no longer exists (nulled or hard-deled)"), confidential = TRUE)
return
message_admins("[key_name_admin(usr)] Showed [key_name_admin(C)] a <a href='byond://?_src_=vars;datumrefresh=[REF(target)]'>VV window</a>")
log_admin("Admin [key_name(usr)] Showed [key_name(C)] a VV window of a [target]")
to_chat(C, "[holder.fakekey ? "an Administrator" : "[usr.client.key]"] has granted you access to view a View Variables window", confidential = TRUE)
C.debug_variables(target)
if(check_rights(R_DEBUG))
if(href_list[VV_HK_DELETE])
usr.client.admin_delete(target)
if (isturf(target)) // show the turf that took its place
usr.client.debug_variables(target)
return
if(href_list[VV_HK_MARK])
usr.client.mark_datum(target)
if(href_list[VV_HK_TAG])
usr.client.tag_datum(target)
if(href_list[VV_HK_ADDCOMPONENT])
if(!check_rights(NONE))
return
var/list/names = list()
var/list/componentsubtypes = sortList(subtypesof(/datum/component), GLOBAL_PROC_REF(cmp_typepaths_asc))
names += "---Components---"
names += componentsubtypes
names += "---Elements---"
names += sortList(subtypesof(/datum/element), GLOBAL_PROC_REF(cmp_typepaths_asc))
var/result = tgui_input_list(usr, "Choose a component/element to add", "Add Component", names)
if(isnull(result))
return
if(!usr || result == "---Components---" || result == "---Elements---")
return
if(QDELETED(src))
to_chat(usr, "That thing doesn't exist anymore!", confidential = TRUE)
return
var/add_source
if(ispath(result, /datum/component))
var/datum/component/comp_path = result
if(initial(comp_path.dupe_mode) == COMPONENT_DUPE_SOURCES)
add_source = tgui_input_text(usr, "Enter a source for the component", "Add Component", "ADMIN-ABUSE")
if(isnull(add_source))
return
var/list/lst = get_callproc_args()
if(!lst)
return
var/datumname = "error"
lst.Insert(1, result)
if(result in componentsubtypes)
datumname = "component"
target._AddComponent(lst, add_source)
else
datumname = "element"
target._AddElement(lst)
log_admin("[key_name(usr)] has added [result] [datumname] to [key_name(target)].")
message_admins(span_notice("[key_name_admin(usr)] has added [result] [datumname] to [key_name_admin(target)]."))
if(href_list[VV_HK_REMOVECOMPONENT] || href_list[VV_HK_MASS_REMOVECOMPONENT])
if(!check_rights(NONE))
return
var/mass_remove = href_list[VV_HK_MASS_REMOVECOMPONENT]
var/list/components = target._datum_components.Copy()
var/list/names = list()
names += "---Components---"
if(length(components))
names += sortList(components, GLOBAL_PROC_REF(cmp_typepaths_asc))
names += "---Elements---"
// We have to list every element here because there is no way to know what element is on this object without doing some sort of hack.
names += sortList(subtypesof(/datum/element), GLOBAL_PROC_REF(cmp_typepaths_asc))
var/path = tgui_input_list(usr, "Choose a component/element to remove. All elements listed here may not be on the datum.", "Remove element", names)
if(isnull(path))
return
if(!usr || path == "---Components---" || path == "---Elements---")
return
if(QDELETED(src))
to_chat(usr, "That thing doesn't exist anymore!")
return
var/list/targets_to_remove_from = list(target)
if(mass_remove)
var/method = vv_subtype_prompt(target.type)
targets_to_remove_from = get_all_of_type(target.type, method)
if(alert(usr, "Are you sure you want to mass-delete [path] on [target.type]?", "Mass Remove Confirmation", "Yes", "No") == "No")
return
for(var/datum/target_to_remove_from as anything in targets_to_remove_from)
if(ispath(path, /datum/element))
var/list/lst = get_callproc_args()
if(!lst)
lst = list()
lst.Insert(1, path)
target._RemoveElement(lst)
else
var/list/components_actual = target_to_remove_from.GetComponents(path)
for(var/to_delete in components_actual)
qdel(to_delete)
message_admins(span_notice("[key_name_admin(usr)] has [mass_remove? "mass" : ""] removed [path] component from [mass_remove? target.type : key_name_admin(target)]."))
//if(href_list[VV_HK_MODIFY_GREYSCALE])
// if(!check_rights(NONE))
// return
// var/datum/greyscale_modify_menu/menu = new(target, usr, SSgreyscale.configurations, unlocked = TRUE)
// menu.ui_interact(usr)
if(href_list[VV_HK_CALLPROC])
return SSadmin_verbs.dynamic_invoke_verb(usr, /datum/admin_verb/call_proc_datum, target)

View File

@@ -1,44 +1,43 @@
//LISTS - CAN NOT DO VV_DO_TOPIC BECAUSE LISTS AREN'T DATUMS :(
/client/proc/vv_do_list(list/target, href_list)
if(!check_rights(R_VAREDIT))
return
var/target_index = text2num(href_list["index"])
if(target_index)
if(href_list[VV_HK_LIST_EDIT])
mod_list(target, null, "list", "contents", target_index, autodetect_class = TRUE)
if(href_list[VV_HK_LIST_CHANGE])
mod_list(target, null, "list", "contents", target_index, autodetect_class = FALSE)
if(href_list[VV_HK_LIST_REMOVE])
var/variable = target[target_index]
var/prompt = tgui_alert(usr, "Do you want to remove item number [target_index] from list?", "Confirm", list("Yes", "No"))
if (prompt != "Yes")
var/target_index = text2num(GET_VV_VAR_TARGET)
if(check_rights(R_VAREDIT))
if(target_index)
if(href_list[VV_HK_LIST_EDIT])
mod_list(target, null, "list", "contents", target_index, autodetect_class = TRUE)
if(href_list[VV_HK_LIST_CHANGE])
mod_list(target, null, "list", "contents", target_index, autodetect_class = FALSE)
if(href_list[VV_HK_LIST_REMOVE])
var/variable = target[target_index]
var/prompt = tgui_alert(usr,"Do you want to remove item number [target_index] from list?", "Confirm", list("Yes", "No"))
if (prompt != "Yes")
return
target.Cut(target_index, target_index+1)
log_world("### ListVarEdit by [src]: /list's contents: REMOVED=[html_encode("[variable]")]")
log_admin("[key_name(src)] modified list's contents: REMOVED=[variable]")
message_admins("[key_name_admin(src)] modified list's contents: REMOVED=[variable]")
if(href_list[VV_HK_LIST_ADD])
mod_list_add(target, null, "list", "contents")
if(href_list[VV_HK_LIST_ERASE_DUPES])
uniqueList_inplace(target)
log_world("### ListVarEdit by [src]: /list contents: CLEAR DUPES")
log_admin("[key_name(src)] modified list's contents: CLEAR DUPES")
message_admins("[key_name_admin(src)] modified list's contents: CLEAR DUPES")
if(href_list[VV_HK_LIST_ERASE_NULLS])
list_clear_nulls(target)
log_world("### ListVarEdit by [src]: /list contents: CLEAR NULLS")
log_admin("[key_name(src)] modified list's contents: CLEAR NULLS")
message_admins("[key_name_admin(src)] modified list's contents: CLEAR NULLS")
if(href_list[VV_HK_LIST_SET_LENGTH])
var/value = vv_get_value(VV_NUM)
if (value["class"] != VV_NUM || value["value"] > max(50000, target.len)) //safety - would rather someone not put an extra 0 and erase the server's memory lmao.
return
target.Cut(target_index, target_index+1)
log_world("### ListVarEdit by [src]: /list's contents: REMOVED=[html_encode("[variable]")]")
log_admin("[key_name(src)] modified list's contents: REMOVED=[variable]")
message_admins("[key_name_admin(src)] modified list's contents: REMOVED=[variable]")
if(href_list[VV_HK_LIST_ADD])
mod_list_add(target, null, "list", "contents")
if(href_list[VV_HK_LIST_ERASE_DUPES])
uniqueList_inplace(target)
log_world("### ListVarEdit by [src]: /list contents: CLEAR DUPES")
log_admin("[key_name(src)] modified list's contents: CLEAR DUPES")
message_admins("[key_name_admin(src)] modified list's contents: CLEAR DUPES")
if(href_list[VV_HK_LIST_ERASE_NULLS])
listclearnulls(target)
log_world("### ListVarEdit by [src]: /list contents: CLEAR NULLS")
log_admin("[key_name(src)] modified list's contents: CLEAR NULLS")
message_admins("[key_name_admin(src)] modified list's contents: CLEAR NULLS")
if(href_list[VV_HK_LIST_SET_LENGTH])
var/value = vv_get_value(VV_NUM)
if (value["class"] != VV_NUM || value["value"] > max(5000, target.len)) //safety - would rather someone not put an extra 0 and erase the server's memory lmao.
return
target.len = value["value"]
log_world("### ListVarEdit by [src]: /list len: [target.len]")
log_admin("[key_name(src)] modified list's len: [target.len]")
message_admins("[key_name_admin(src)] modified list's len: [target.len]")
if(href_list[VV_HK_LIST_SHUFFLE])
shuffle_inplace(target)
log_world("### ListVarEdit by [src]: /list contents: SHUFFLE")
log_admin("[key_name(src)] modified list's contents: SHUFFLE")
message_admins("[key_name_admin(src)] modified list's contents: SHUFFLE")
target.len = value["value"]
log_world("### ListVarEdit by [src]: /list len: [target.len]")
log_admin("[key_name(src)] modified list's len: [target.len]")
message_admins("[key_name_admin(src)] modified list's len: [target.len]")
if(href_list[VV_HK_LIST_SHUFFLE])
shuffle_inplace(target)
log_world("### ListVarEdit by [src]: /list contents: SHUFFLE")
log_admin("[key_name(src)] modified list's contents: SHUFFLE")
message_admins("[key_name_admin(src)] modified list's contents: SHUFFLE")

View File

@@ -5,17 +5,17 @@ ADMIN_VERB_AND_CONTEXT_MENU(debug_variables, (R_DEBUG|R_SERVER|R_ADMIN|R_SPAWN|R
user.debug_variables(thing)
// This is kept as a separate proc because admins are able to show VV to non-admins
/client/proc/debug_variables(datum/D in world)
/client/proc/debug_variables(datum/thing in world)
set category = "Debug.Investigate"
set name = "View Variables"
//set src in world
var/static/cookieoffset = rand(1, 9999) //to force cookies to reset after the round.
if(!usr.client || !usr.client.holder) //The usr vs src abuse in this proc is intentional and must not be changed
to_chat(usr, span_danger("You need to be an administrator to access this."))
if(!usr.client || !usr.client.holder) //This is usr because admins can call the proc on other clients, even if they're not admins, to show them VVs.
to_chat(usr, span_danger("You need to be an administrator to access this."), confidential = TRUE)
return
if(!D)
if(!thing)
return
var/dark = usr.client.prefs ? usr.client.prefs.read_preference(/datum/preference/toggle/holder/vv_dark) : TRUE
@@ -24,305 +24,306 @@ ADMIN_VERB_AND_CONTEXT_MENU(debug_variables, (R_DEBUG|R_SERVER|R_ADMIN|R_SPAWN|R
var/datum/asset/asset_cache_datum = get_asset_datum(/datum/asset/simple/vv)
asset_cache_datum.send(usr)
var/islist = islist(D) || (!isdatum(D) && hascall(D, "Cut")) // Some special lists don't count as lists, but can be detected by if they have list procs
if(!islist && !isdatum(D))
if(isappearance(thing))
thing = get_vv_appearance(thing) // this is /mutable_appearance/our_bs_subtype
var/islist = islist(thing) || (!isdatum(thing) && hascall(thing, "Cut")) // Some special lists don't count as lists, but can be detected by if they have list procs
if(!islist && !isdatum(thing))
return
//VOREStation Edit Start - the rest of this proc in a spawn
spawn(0)
var/title = ""
var/refid = "\ref[D]"
var/icon/sprite
var/hash
var/title = ""
var/refid = REF(thing)
var/icon/sprite
var/hash
var/type = islist ? /list : D.type
var/no_icon = FALSE
var/type = islist ? /list : thing.type
var/no_icon = FALSE
if(isatom(D))
var/atom/AT = D
if(use_gfi)
sprite = getFlatIcon(D)
if(!sprite)
no_icon = TRUE
else if(AT.icon && AT.icon_state)
sprite = new /icon(AT.icon, AT.icon_state)
else
if(isatom(thing))
var/atom/AT = thing
if(use_gfi)
sprite = getFlatIcon(thing)
if(!sprite)
no_icon = TRUE
else if(AT.icon && AT.icon_state)
sprite = new /icon(AT.icon, AT.icon_state)
else
no_icon = TRUE
else if(isimage(D))
// icon_state=null shows first image even if dmi has no icon_state for null name.
// This list remembers which dmi has null icon_state, to determine if icon_state=null should display a sprite
// (NOTE: icon_state="" is correct, but saying null is obvious)
var/static/list/dmi_nullstate_checklist = list()
var/image/image_object = D
var/icon_filename_text = "[image_object.icon]" // "icon(null)" type can exist. textifying filters it.
if(icon_filename_text)
if(image_object.icon_state)
else if(isimage(thing))
// icon_state=null shows first image even if dmi has no icon_state for null name.
// This list remembers which dmi has null icon_state, to determine if icon_state=null should display a sprite
// (NOTE: icon_state="" is correct, but saying null is obvious)
var/static/list/dmi_nullstate_checklist = list()
var/image/image_object = thing
var/icon_filename_text = "[image_object.icon]" // "icon(null)" type can exist. textifying filters it.
if(icon_filename_text)
if(image_object.icon_state)
sprite = icon(image_object.icon, image_object.icon_state)
else // it means: icon_state=""
if(!dmi_nullstate_checklist[icon_filename_text])
dmi_nullstate_checklist[icon_filename_text] = ICON_STATE_CHECKED
if(icon_exists(image_object.icon, ""))
// this dmi has nullstate. We'll allow "icon_state=null" to show image.
dmi_nullstate_checklist[icon_filename_text] = ICON_STATE_NULL
if(dmi_nullstate_checklist[icon_filename_text] == ICON_STATE_NULL)
sprite = icon(image_object.icon, image_object.icon_state)
else // it means: icon_state=""
if(!dmi_nullstate_checklist[icon_filename_text])
dmi_nullstate_checklist[icon_filename_text] = ICON_STATE_CHECKED
if(icon_exists(image_object.icon, ""))
// this dmi has nullstate. We'll allow "icon_state=null" to show image.
dmi_nullstate_checklist[icon_filename_text] = ICON_STATE_NULL
var/sprite_text
if(sprite)
hash = md5(sprite)
src << browse_rsc(sprite, "vv[hash].png")
sprite_text = no_icon ? "\[NO ICON\]" : "<img src='vv[hash].png'></td><td>"
if(dmi_nullstate_checklist[icon_filename_text] == ICON_STATE_NULL)
sprite = icon(image_object.icon, image_object.icon_state)
title = "[thing] ([REF(thing)]) = [type]"
var/formatted_type = replacetext("[type]", "/", "<wbr>/")
var/sprite_text
if(sprite)
hash = md5(sprite)
src << browse_rsc(sprite, "vv[hash].png")
sprite_text = no_icon ? "\[NO ICON\]" : "<img src='vv[hash].png'></td><td>"
var/list/header = islist ? list("<b>/list</b>") : thing.vv_get_header()
title = "[D] (\ref[D]) = [type]"
var/formatted_type = replacetext("[type]", "/", "<wbr>/")
var/ref_line = "@[copytext(refid, 2, -1)]" // get rid of the brackets, add a @ prefix for copy pasting in asay
var/list/header = islist(D)? list(span_bold("/list")) : D.vv_get_header()
var/marked_line
if(holder && holder.marked_datum && holder.marked_datum == thing)
marked_line = VV_MSG_MARKED
var/tagged_line
if(holder && LAZYFIND(holder.tagged_datums, thing))
var/tag_index = LAZYFIND(holder.tagged_datums, thing)
tagged_line = VV_MSG_TAGGED(tag_index)
var/varedited_line
if(!islist && (thing.datum_flags & DF_VAR_EDITED))
varedited_line = VV_MSG_EDITED
var/deleted_line
if(!islist && thing.gc_destroyed)
deleted_line = VV_MSG_DELETED
var/ref_line = "@[copytext(refid, 2, -1)]" // get rid of the brackets, add a @ prefix for copy pasting in asay
var/list/dropdownoptions
if (islist)
dropdownoptions = list(
"---",
"Add Item" = VV_HREF_TARGETREF_INTERNAL(refid, VV_HK_LIST_ADD),
"Remove Nulls" = VV_HREF_TARGETREF_INTERNAL(refid, VV_HK_LIST_ERASE_NULLS),
"Remove Dupes" = VV_HREF_TARGETREF_INTERNAL(refid, VV_HK_LIST_ERASE_DUPES),
"Set len" = VV_HREF_TARGETREF_INTERNAL(refid, VV_HK_LIST_SET_LENGTH),
"Shuffle" = VV_HREF_TARGETREF_INTERNAL(refid, VV_HK_LIST_SHUFFLE),
"Show VV To Player" = VV_HREF_TARGETREF_INTERNAL(refid, VV_HK_EXPOSE),
"---"
)
for(var/i in 1 to length(dropdownoptions))
var/name = dropdownoptions[i]
var/link = dropdownoptions[name]
dropdownoptions[i] = "<option value[link? "='[link]'":""]>[name]</option>"
else
dropdownoptions = thing.vv_get_dropdown()
var/marked_line
if(holder && holder.marked_datum && holder.marked_datum == D)
marked_line = VV_MSG_MARKED
var/varedited_line = ""
if(!islist && (D.datum_flags & DF_VAR_EDITED))
varedited_line = VV_MSG_EDITED
var/deleted_line
if(!islist && D.gc_destroyed)
deleted_line = VV_MSG_DELETED
var/list/names = list()
if(!islist)
for(var/varname in thing.vars)
names += varname
var/list/dropdownoptions = list()
var/autoconvert_dropdown = FALSE
if (islist)
dropdownoptions = list(
"---",
"Add Item" = "?_src_=vars;[HrefToken()];[VV_HK_LIST_ADD]=TRUE;target=[refid]",
"Remove Nulls" = "?_src_=vars;[HrefToken()];[VV_HK_LIST_ERASE_NULLS]=TRUE;target=[refid]",
"Remove Dupes" = "?_src_=vars;[HrefToken()];[VV_HK_LIST_ERASE_DUPES]=TRUE;target=[refid]",
"Set len" = "?_src_=vars;[HrefToken()];[VV_HK_LIST_SET_LENGTH]=TRUE;target=[refid]",
"Shuffle" = "?_src_=vars;[HrefToken()];[VV_HK_LIST_SHUFFLE]=TRUE;target=[refid]",
// "Show VV To Player" = "?_src_=vars;[HrefToken()];[VV_HK_EXPOSE]=TRUE;target=[refid]" // TODO - Not yet implemented for lists
)
autoconvert_dropdown = TRUE
else
dropdownoptions = D.vv_get_dropdown()
var/list/dropdownoptions_html = list()
if(autoconvert_dropdown)
for (var/name in dropdownoptions)
var/link = dropdownoptions[name]
if (link)
dropdownoptions_html += "<option value='[link]'>[name]</option>"
else
dropdownoptions_html += "<option value>[name]</option>"
else
dropdownoptions_html = dropdownoptions + D.get_view_variables_options()
sleep(1 TICKS)
var/list/names = list()
if (!islist)
names = D.get_variables()
//sleep(1)//For some reason, without this sleep, VVing will cause client to disconnect on certain objects. //VOREStation edit - commented out, replaced with spawn(0) above
var/ui_scale = prefs?.read_preference(/datum/preference/toggle/ui_scale)
var/ui_scale = prefs?.read_preference(/datum/preference/toggle/ui_scale)
var/list/variable_html = list()
if(islist)
var/list/list_value = thing
for(var/i in 1 to list_value.len)
var/key = list_value[i]
var/value
if(IS_NORMAL_LIST(list_value) && IS_VALID_ASSOC_KEY(key))
value = list_value[key]
variable_html += debug_variable(i, value, 0, list_value)
else
names = sortList(names)
for(var/varname in names)
if(thing.can_vv_get(varname))
variable_html += thing.vv_get_var(varname)
var/list/variable_html = list()
if(islist)
var/list/L = D
for (var/i in 1 to L.len)
var/key = L[i]
var/value
if(IS_NORMAL_LIST(L) && IS_VALID_ASSOC_KEY(key))
value = L[key]
variable_html += debug_variable(i, value, 0, D)
else
names = sortList(names)
for (var/V in names)
if(D.can_vv_get(V))
variable_html += D.vv_get_var(V)
var/html = {"
<!DOCTYPE html>
<html class="[dark ? "dark" : ""]">
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta charset="utf-8" />
<title>[title]</title>
<link rel="stylesheet" type="text/css" href="[SSassets.transport.get_asset_url("view_variables.css")]">
[!ui_scale && window_scaling ? "<style>body {zoom: [100 / window_scaling]%;}</style>" : ""]
</head>
<body onload='selectTextField()' onkeydown='return handle_keydown()' onkeyup='handle_keyup()'>
<script type="text/javascript">
// onload
function selectTextField() {
var filter_text = document.getElementById('filter');
filter_text.focus();
filter_text.select();
var lastsearch = getCookie("[refid][cookieoffset]search");
if (lastsearch) {
filter_text.value = lastsearch;
updateSearch();
}
}
function getCookie(cname) {
var name = cname + "=";
var ca = document.cookie.split(';');
for(var i=0; i<ca.length; i++) {
var c = ca\[i];
while (c.charAt(0)==' ') c = c.substring(1,c.length);
if (c.indexOf(name)==0) return c.substring(name.length,c.length);
}
return "";
}
// main search functionality
var last_filter = "";
function updateSearch() {
var filter = document.getElementById('filter').value.toLowerCase();
var vars_ol = document.getElementById("vars");
if (filter === last_filter) {
// An event triggered an update but nothing has changed.
return;
} else if (filter.indexOf(last_filter) === 0) {
// The new filter starts with the old filter, fast path by removing only.
var children = vars_ol.childNodes;
for (var i = children.length - 1; i >= 0; --i) {
try {
var li = children\[i];
if (li.innerText.toLowerCase().indexOf(filter) == -1) {
vars_ol.removeChild(li);
}
} catch(err) {}
}
} else {
// Remove everything and put back what matches.
while (vars_ol.hasChildNodes()) {
vars_ol.removeChild(vars_ol.lastChild);
}
for (var i = 0; i < complete_list.length; ++i) {
try {
var li = complete_list\[i];
if (!filter || li.innerText.toLowerCase().indexOf(filter) != -1) {
vars_ol.appendChild(li);
}
} catch(err) {}
}
}
last_filter = filter;
document.cookie="[refid][cookieoffset]search="+encodeURIComponent(filter);
}
// onkeydown
function handle_keydown() {
if(event.keyCode == 116) { //F5 (to refresh properly)
document.getElementById("refresh_link").click();
event.preventDefault ? event.preventDefault() : (event.returnValue = false);
return false;
}
return true;
}
// onkeyup
function handle_keyup() {
var/html = {"
<html class="[dark ? "dark" : ""]">
<head>
<meta http-equiv='Content-Type' content='text/html; charset=UTF-8'>
<title>[title]</title>
<link rel="stylesheet" type="text/css" href="[SSassets.transport.get_asset_url("view_variables.css")]">
[!ui_scale && window_scaling ? "<style>body {zoom: [100 / window_scaling]%;}</style>" : ""]
</head>
<body onload='selectTextField()' onkeydown='return handle_keydown()' onkeyup='handle_keyup()'>
<script type="text/javascript">
// onload
function selectTextField() {
var filter_text = document.getElementById('filter');
filter_text.focus();
filter_text.select();
var lastsearch = getCookie("[refid][cookieoffset]search");
if (lastsearch) {
filter_text.value = lastsearch;
updateSearch();
}
}
function getCookie(cname) {
var name = cname + "=";
var ca = document.cookie.split(';');
for(var i=0; i<ca.length; i++) {
var c = ca\[i];
while (c.charAt(0) == ' ') c = c.substring(1,c.length);
if (c.indexOf(name) == 0) return c.substring(name.length,c.length);
}
return "";
}
// onchange
function handle_dropdown(list) {
var value = list.options\[list.selectedIndex].value;
if (value !== "") {
location.href = value;
// main search functionality
var last_filter = "";
function updateSearch() {
var filter = document.getElementById('filter').value.toLowerCase();
var vars_ol = document.getElementById("vars");
if (filter === last_filter) {
// An event triggered an update but nothing has changed.
return;
} else if (filter.indexOf(last_filter) === 0) {
// The new filter starts with the old filter, fast path by removing only.
var children = vars_ol.childNodes;
for (var i = children.length - 1; i >= 0; --i) {
try {
var li = children\[i];
if (li.innerText.toLowerCase().indexOf(filter) == -1) {
vars_ol.removeChild(li);
}
} catch(err) {}
}
} else {
// Remove everything and put back what matches.
while (vars_ol.hasChildNodes()) {
vars_ol.removeChild(vars_ol.lastChild);
}
for (var i = 0; i < complete_list.length; ++i) {
try {
var li = complete_list\[i];
if (!filter || li.innerText.toLowerCase().indexOf(filter) != -1) {
vars_ol.appendChild(li);
}
} catch(err) {}
}
list.selectedIndex = 0;
document.getElementById('filter').focus();
}
// byjax
function replace_span(what) {
var idx = what.indexOf(':');
document.getElementById(what.substr(0, idx)).innerHTML = what.substr(idx + 1);
last_filter = filter;
document.cookie="[refid][cookieoffset]search="+encodeURIComponent(filter);
}
// onkeydown
function handle_keydown() {
if(event.keyCode == 116) { //F5 (to refresh properly)
document.getElementById("refresh_link").click();
event.preventDefault ? event.preventDefault() : (event.returnValue = false);
return false;
}
</script>
<div align='center'>
<table width='100%'>
<tr>
<td width='50%'>
<table align='center' width='100%'>
<tr>
<td>
[sprite_text]
<div align='center'>
[header.Join()]
</div>
</td>
</tr>
</table>
<div align='center'>
<b><font size='1'>[formatted_type]</font></b>
<br><b><font size='1'>[ref_line]</font></b>
<span id='marked'>[marked_line]</span>
<span id='varedited'>[varedited_line]</span>
<span id='deleted'>[deleted_line]</span>
</div>
</td>
<td width='50%'>
<div align='center'>
<a id='refresh_link' href='byond://?_src_=vars;
datumrefresh=[refid]'>Refresh</a>
<form>
<select name="file" size="1"
onchange="handle_dropdown(this)"
onmouseclick="this.focus()">
<option value selected>Select option</option>
[dropdownoptions_html.Join()]
</select>
</form>
</div>
</td>
</tr>
</table>
</div>
<hr>
<b>E</b> - Edit, tries to determine the variable type by itself.<br>
<b>C</b> - Change, asks you for the var type first.<br>
<b>M</b> - Mass modify: changes this variable for all objects of this type.<br>
<hr>
return true;
}
// onkeyup
function handle_keyup() {
updateSearch();
}
// onchange
function handle_dropdown(list) {
var value = list.options\[list.selectedIndex].value;
if (value !== "") {
location.href = value;
}
list.selectedIndex = 0;
document.getElementById('filter').focus();
}
// byjax
function replace_span(what) {
var idx = what.indexOf(':');
document.getElementById(what.substr(0, idx)).innerHTML = what.substr(idx + 1);
}
</script>
<div align='center'>
<table width='100%'>
<tr>
<td width='20%'>
<td width='50%'>
<table align='center' width='100%'>
<tr>
<td>
[sprite_text]
<div align='center'>
[header.Join()]
</div>
</td>
</tr>
</table>
<div align='center'>
<b>Search:</b>
<b><font size='1'>[formatted_type]</font></b>
<br><b><font size='1'>[ref_line]</font></b>
<span id='marked'>[marked_line]</span>
<span id='tagged'>[tagged_line]</span>
<span id='varedited'>[varedited_line]</span>
<span id='deleted'>[deleted_line]</span>
</div>
</td>
<td width='80%'>
<input type='text' id='filter' name='filter_text' value='' style='width:100%;'>
<td width='50%'>
<div align='center'>
<a id='refresh_link' href='byond://?_src_=vars;
datumrefresh=[refid];[HrefToken()]'>Refresh</a>
<form>
<select name="file" size="1"
onchange="handle_dropdown(this)"
onmouseclick="this.focus()">
<option value selected>Select option</option>
[dropdownoptions.Join()]
</select>
</form>
</div>
</td>
</tr>
</table>
<hr>
<ol id='vars'>
[variable_html.Join()]
</ol>
<script type='text/javascript'>
var complete_list = \[\];
var lis = document.getElementById("vars").children;
for(var i = lis.length; i--;) complete_list\[i\] = lis\[i\];
</script>
</body>
</html>
"}
var/size_string = "size=475x650";
if(ui_scale && window_scaling)
size_string = "size=[475 * window_scaling]x[650 * window_scaling]"
</div>
<hr>
<font size='1'>
<b>E</b> - Edit, tries to determine the variable type by itself.<br>
<b>C</b> - Change, asks you for the var type first.<br>
<b>M</b> - Mass modify: changes this variable for all objects of this type.<br>
</font>
<hr>
<table width='100%'>
<tr>
<td width='20%'>
<div align='center'>
<b>Search:</b>
</div>
</td>
<td width='80%'>
<input type='text' id='filter' name='filter_text' value='' style='width:100%;'>
</td>
</tr>
</table>
<hr>
<ol id='vars'>
[variable_html.Join()]
</ol>
<script type='text/javascript'>
var complete_list = \[\];
var lis = document.getElementById("vars").children;
for(var i = lis.length; i--;) complete_list\[i\] = lis\[i\];
</script>
</body>
</html>
"}
src << browse(html, "window=variables[refid];[size_string]")
var/size_string = "size=475x650";
if(ui_scale && window_scaling)
size_string = "size=[475 * window_scaling]x[650 * window_scaling]"
/client/proc/vv_update_display(datum/D, span, content)
src << output("[span]:[content]", "variables\ref[D].browser:replace_span")
src << browse(html, "window=variables[refid];[size_string]")
/client/proc/vv_update_display(datum/thing, span, content)
src << output("[span]:[content]", "variables[REF(thing)].browser:replace_span")
#undef ICON_STATE_CHECKED
#undef ICON_STATE_NULL

View File

@@ -1,86 +0,0 @@
/proc/readglobal(which)
. = global.vars[which]
/proc/writeglobal(which, newval)
global.vars[which] = newval
/proc/getallglobals()
. = list()
for(var/some_global in global.vars)
. += some_global
/var/decl/global_vars/global_vars_
/decl/global_vars
var/name = span_bold("Global Variables")
/decl/global_vars/get_view_variables_options()
return "" // Ensuring changes to the base proc never affect us
/decl/global_vars/get_variables()
. = getallglobals() - VV_hidden()
if(!usr || !check_rights(R_ADMIN|R_DEBUG, FALSE))
. -= VV_secluded()
/decl/global_vars/get_variable_value(varname)
return readglobal(varname)
/decl/global_vars/set_variable_value(varname, value)
writeglobal(varname, value)
/decl/global_vars/make_view_variables_variable_entry(varname, value)
return "(<a href='byond://?_src_=vars;[HrefToken()];datumedit=\ref[src];varnameedit=[varname]'>E</a>) "
/decl/global_vars/VV_locked()
return vars
/decl/global_vars/VV_hidden()
return list(
"sqladdress",
"sqldb",
"sqllogin",
"sqlpass",
"sqlport",
"comms_password",
"ban_comms_password",
"login_export_addr",
"admin_verbs_default",
"admin_verbs_admin",
"admin_verbs_ban",
"admin_verbs_sounds",
"admin_verbs_fun",
"admin_verbs_spawn",
"admin_verbs_server",
"admin_verbs_debug",
"admin_verbs_paranoid_debug",
"admin_verbs_possess",
"admin_verbs_permissions",
"admin_verbs_rejuv",
"admin_verbs_hideable",
"admin_verbs_mod",
"admin_verbs_event_manager",
"adminProcCallCount",
"adminProcCaller",
"AdminProcCallSpamPrevention",
"admins",
"admin_datums",
"admin_log",
"admin_ranks",
"admin_state",
"alien_whitelist",
"GLOB.alldirs",
"ahelp_tickets",
"adminfaxes",
"adminlogs",
"GLOB.cardinal",
"cardinalz",
"IClog"
)
/client/proc/debug_global_variables()
set category = "Debug"
set name = "View Global Variables"
if(!global_vars_)
global_vars_ = new()
debug_variables(global_vars_)