diff --git a/baystation12.dme b/baystation12.dme index 92d393a37e..2fdcefbb42 100644 --- a/baystation12.dme +++ b/baystation12.dme @@ -144,7 +144,6 @@ #include "code\datums\browser.dm" #include "code\datums\computerfiles.dm" #include "code\datums\datacore.dm" -#include "code\datums\datumvars.dm" #include "code\datums\disease.dm" #include "code\datums\mind.dm" #include "code\datums\mixed.dm" @@ -832,6 +831,7 @@ #include "code\modules\admin\player_panel.dm" #include "code\modules\admin\topic.dm" #include "code\modules\admin\ToRban.dm" +#include "code\modules\admin\callproc\callproc.dm" #include "code\modules\admin\DB ban\functions.dm" #include "code\modules\admin\permissionverbs\permissionedit.dm" #include "code\modules\admin\verbs\adminhelp.dm" @@ -864,6 +864,9 @@ #include "code\modules\admin\verbs\striketeam.dm" #include "code\modules\admin\verbs\ticklag.dm" #include "code\modules\admin\verbs\tripAI.dm" +#include "code\modules\admin\view_variables\helpers.dm" +#include "code\modules\admin\view_variables\topic.dm" +#include "code\modules\admin\view_variables\view_variables.dm" #include "code\modules\alarm\alarm.dm" #include "code\modules\alarm\alarm_handler.dm" #include "code\modules\alarm\atmosphere_alarm.dm" diff --git a/code/js/view_variables.js b/code/js/view_variables.js new file mode 100644 index 0000000000..86ca8cadc6 --- /dev/null +++ b/code/js/view_variables.js @@ -0,0 +1,33 @@ +function updateSearch() { + var filter_text = document.getElementById('filter'); + var filter = filter_text.value.toLowerCase(); + + var vars_ol = document.getElementById('vars'); + var lis = vars_ol.children; + // the above line can be changed to vars_ol.getElementsByTagName("li") to filter child lists too + // potential todo: implement a per-admin toggle for this + + for(var i = 0; i < lis.length; i++) { + var li = lis[i]; + if(filter == "" || li.innerText.toLowerCase().indexOf(filter) != -1) { + li.style.display = "block"; + } else { + li.style.display = "none"; + } + } +} + +function selectTextField() { + var filter_text = document.getElementById('filter'); + filter_text.focus(); + filter_text.select(); +} + +function loadPage(list) { + if(list.options[list.selectedIndex].value == "") { + return; + } + + location.href=list.options[list.selectedIndex].value; + list.selectedIndex = 0; +} diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm index ef4fa997c8..88a52ff85c 100644 --- a/code/modules/admin/admin_verbs.dm +++ b/code/modules/admin/admin_verbs.dm @@ -174,6 +174,7 @@ var/list/admin_verbs_debug = list( /client/proc/show_plant_genes, /client/proc/enable_debug_verbs, /client/proc/callproc, + /client/proc/callproc_target, /client/proc/toggledebuglogs, /client/proc/SDQL_query, /client/proc/SDQL2_query, @@ -181,6 +182,7 @@ var/list/admin_verbs_debug = list( var/list/admin_verbs_paranoid_debug = list( /client/proc/callproc, + /client/proc/callproc_target, /client/proc/debug_controller ) @@ -250,6 +252,7 @@ var/list/admin_verbs_hideable = list( /client/proc/restart_controller, /client/proc/cmd_admin_list_open_jobs, /client/proc/callproc, + /client/proc/callproc_target, /client/proc/Debug2, /client/proc/reload_admins, /client/proc/kill_air, diff --git a/code/modules/admin/callproc/callproc.dm b/code/modules/admin/callproc/callproc.dm new file mode 100644 index 0000000000..a416905e7b --- /dev/null +++ b/code/modules/admin/callproc/callproc.dm @@ -0,0 +1,152 @@ + +/client/proc/callproc() + set category = "Debug" + set name = "Advanced ProcCall" + + if(!check_rights(R_DEBUG)) return + if(config.debugparanoid && !check_rights(R_ADMIN)) return + + var/target = null + var/targetselected = 0 + + switch(alert("Proc owned by something?",, "Yes", "No", "Cancel")) + if("Yes") + targetselected=1 + switch(input("Proc owned by...", "Owner", null) as null|anything in list("Obj", "Mob", "Area or Turf", "Client")) + if("Obj") + target = input("Select target:", "Target") as null|obj in world + if("Mob") + target = input("Select target:", "Target", usr) as null|mob in world + if("Area or Turf") + target = input("Select target:", "Target", get_turf(usr)) as null|area|turf in world + if("Client") + target = input("Select target:", "Target", usr.client) as null|anything in clients + else + return + if(!target) + usr << "Proc call cancelled." + return + if("Cancel") + return + if("No") + ; // BYOND apparently doesn't have 'break' in switch statements. + + callproc_targetpicked(targetselected, target) + +/client/proc/callproc_target(atom/A in world) + set category = "Debug" + set name = "Advanced ProcCall Target" + + if(!check_rights(R_DEBUG)) return + if(config.debugparanoid && !check_rights(R_ADMIN)) return + + callproc_targetpicked(1, A) + +/client/proc/callproc_targetpicked(hastarget, datum/target) + + // this needs checking again here because VV's 'Call Proc' option directly calls this proc with the target datum + if(!check_rights(R_DEBUG)) return + if(config.debugparanoid && !check_rights(R_ADMIN)) return + + var/returnval = null + + var/procname = input("Proc name", "Proc") as null|text + if(!procname) return + + if(hastarget) + if(!target) + usr << "Your callproc target no longer exists." + return + if(!hascall(target, procname)) + usr << "\The [target] has no call [procname]()" + return + + var/list/arguments = list() + var/done = 0 + var/current = null + + while(!done) + if(hastarget && !target) + usr << "Your callproc target no longer exists." + return + switch(input("Type of [arguments.len+1]\th variable", "argument [arguments.len+1]") as null|anything in list( + "finished", "null", "text", "num", "type", "obj reference", "mob reference", + "area/turf reference", "icon", "file", "client", "mob's area", "marked datum")) + if(null) + return + + if("finished") + done = 1 + + if("null") + current = null + + if("text") + current = input("Enter text for [arguments.len+1]\th argument") as null|text + if(isnull(current)) return + + if("num") + current = input("Enter number for [arguments.len+1]\th argument") as null|num + if(isnull(current)) return + + if("type") + current = input("Select type for [arguments.len+1]\th argument") as null|anything in typesof(/obj, /mob, /area, /turf) + if(isnull(current)) return + + if("obj reference") + current = input("Select object for [arguments.len+1]\th argument") as null|obj in world + if(isnull(current)) return + + if("mob reference") + current = input("Select mob for [arguments.len+1]\th argument") as null|mob in world + if(isnull(current)) return + + if("area/turf reference") + current = input("Select area/turf for [arguments.len+1]\th argument") as null|area|turf in world + if(isnull(current)) return + + if("icon") + current = input("Provide icon for [arguments.len+1]\th argument") as null|icon + if(isnull(current)) return + + if("client") + current = input("Select client for [arguments.len+1]\th argument") as null|anything in clients + if(isnull(current)) return + + if("mob's area") + var/mob/M = input("Select mob to take area for [arguments.len+1]\th argument") as null|mob in world + if(!M) return + current = get_area(M) + if(!current) + switch(alert("\The [M] appears to not have an area; do you want to pass null instead?",, "Yes", "Cancel")) + if("Yes") + ; + if("Cancel") + return + + if("marked datum") + current = holder.marked_datum + if(!current) + switch(alert("You do not currently have a marked datum; do you want to pass null instead?",, "Yes", "Cancel")) + if("Yes") + ; + if("Cancel") + return + if(!done) + arguments += current + + if(hastarget) + if(!target) + usr << "Your callproc target no longer exists." + return + log_admin("[key_name(src)] called [target]'s [procname]() with [arguments.len ? "the arguments [list2params(arguments)]" : "no arguments"].") + if(arguments.len) + returnval = call(target, procname)(arglist(arguments)) + else + returnval = call(target, procname)() + else + log_admin("[key_name(src)] called [procname]() with [arguments.len ? "the arguments [list2params(arguments)]" : "no arguments"].") + returnval = call(procname)(arglist(arguments)) + + usr << "[procname]() returned: [isnull(returnval) ? "null" : returnval]" + feedback_add_details("admin_verb","APC") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! diff --git a/code/modules/admin/verbs/debug.dm b/code/modules/admin/verbs/debug.dm index 63eae8e994..7469e333ae 100644 --- a/code/modules/admin/verbs/debug.dm +++ b/code/modules/admin/verbs/debug.dm @@ -14,121 +14,7 @@ feedback_add_details("admin_verb","DG2") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! - - -/* 21st Sept 2010 -Updated by Skie -- Still not perfect but better! -Stuff you can't do: -Call proc /mob/proc/make_dizzy() for some player -Because if you select a player mob as owner it tries to do the proc for -/mob/living/carbon/human/ instead. And that gives a run-time error. -But you can call procs that are of type /mob/living/carbon/human/proc/ for that player. -*/ - -/client/proc/callproc() - set category = "Debug" - set name = "Advanced ProcCall" - - if(!check_rights(R_DEBUG)) return - if(config.debugparanoid && !check_rights(R_ADMIN)) return - - spawn(0) - var/target = null - var/targetselected = 0 - var/lst[] // List reference - lst = new/list() // Make the list - var/returnval = null - var/class = null - - switch(alert("Proc owned by something?",,"Yes","No")) - if("Yes") - targetselected = 1 - class = input("Proc owned by...","Owner",null) as null|anything in list("Obj","Mob","Area or Turf","Client") - switch(class) - if("Obj") - target = input("Enter target:","Target",usr) as obj in world - if("Mob") - target = input("Enter target:","Target",usr) as mob in world - if("Area or Turf") - target = input("Enter target:","Target",usr.loc) as area|turf in world - if("Client") - var/list/keys = list() - for(var/client/C) - keys += C - target = input("Please, select a player!", "Selection", null, null) as null|anything in keys - else - return - if("No") - target = null - targetselected = 0 - - var/procname = input("Proc path, eg: /proc/fake_blood","Path:", null) as text|null - if(!procname) return - - var/argnum = input("Number of arguments","Number:",0) as num|null - if(!argnum && (argnum!=0)) return - - lst.len = argnum // Expand to right length - //TODO: make a list to store whether each argument was initialised as null. - //Reason: So we can abort the proccall if say, one of our arguments was a mob which no longer exists - //this will protect us from a fair few errors ~Carn - - var/i - for(i=1, iError: callproc(): owner of proc no longer exists." - return - if(!hascall(target,procname)) - usr << "Error: callproc(): target has no such call [procname]." - return - log_admin("[key_name(src)] called [target]'s [procname]() with [lst.len ? "the arguments [list2params(lst)]":"no arguments"].") - returnval = call(target,procname)(arglist(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"].") - returnval = call(procname)(arglist(lst)) // Pass the lst as an argument list to the proc - - usr << "[procname] returned: [returnval ? returnval : "null"]" - feedback_add_details("admin_verb","APC") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! +// callproc moved to code/modules/admin/callproc /client/proc/Cell() set category = "Debug" diff --git a/code/modules/admin/view_variables/helpers.dm b/code/modules/admin/view_variables/helpers.dm new file mode 100644 index 0000000000..5ff47b3968 --- /dev/null +++ b/code/modules/admin/view_variables/helpers.dm @@ -0,0 +1,93 @@ + +// Keep these two together, they *must* be defined on both +// If /client ever becomes /datum/client or similar, they can be merged +/client/proc/get_view_variables_header() + return "[src]" +/datum/proc/get_view_variables_header() + return "[src]" + +/atom/get_view_variables_header() + return {" + [src] +
+ << + [dir2text(dir)] + >> + + "} + +/mob/living/get_view_variables_header() + return {" + [src] +
<< [dir2text(dir)] >> +
[ckey ? ckey : "No ckey"] / [real_name ? real_name : "No real name"] +
+ BRUTE:[getBruteLoss()] + FIRE:[getFireLoss()] + TOXIN:[getToxLoss()] + OXY:[getOxyLoss()] + CLONE:[getCloneLoss()] + BRAIN:[getBrainLoss()] +
+ "} + +// Same for these as for get_view_variables_header() above +/client/proc/get_view_variables_options() + return "" +/datum/proc/get_view_variables_options() + return "" + +/mob/get_view_variables_options() + return ..() + {" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + "} + +/mob/living/carbon/human/get_view_variables_options() + return ..() + {" + + + + + + + "} + +/obj/get_view_variables_options() + return ..() + {" + + + + "} + +/turf/get_view_variables_options() + return ..() + {" + + + "} diff --git a/code/datums/datumvars.dm b/code/modules/admin/view_variables/topic.dm similarity index 53% rename from code/datums/datumvars.dm rename to code/modules/admin/view_variables/topic.dm index 7e9fc0cd04..022eccd932 100644 --- a/code/datums/datumvars.dm +++ b/code/modules/admin/view_variables/topic.dm @@ -1,416 +1,3 @@ - -// reference: /client/proc/modify_variables(var/atom/O, var/param_var_name = null, var/autodetect_class = 0) - -client - proc/debug_variables(datum/D in world) - set category = "Debug" - set name = "View Variables" - //set src in world - - - if(!usr.client || !usr.client.holder) - usr << "You need to be an administrator to access this." - return - - - var/title = "" - var/body = "" - - if(!D) return - if(istype(D, /atom)) - var/atom/A = D - title = "[A.name] (\ref[A]) = [A.type]" - - #ifdef VARSICON - if (A.icon) - body += debug_variable("icon", new/icon(A.icon, A.icon_state, A.dir), 0) - #endif - - var/icon/sprite - - if(istype(D,/atom)) - var/atom/AT = D - if(AT.icon && AT.icon_state) - sprite = new /icon(AT.icon, AT.icon_state) - usr << browse_rsc(sprite, "view_vars_sprite.png") - - title = "[D] (\ref[D]) = [D.type]" - - body += {" "} - - body += "" - - body += "
" - - if(sprite) - body += "" - - body += "
" - else - body += "
" - - body += "
" - - if(istype(D,/atom)) - var/atom/A = D - if(isliving(A)) - body += "[D]" - if(A.dir) - body += "
<< [dir2text(A.dir)] >>" - var/mob/living/M = A - body += "
[M.ckey ? M.ckey : "No ckey"] / [M.real_name ? M.real_name : "No real name"]" - body += {" -
- BRUTE:[M.getBruteLoss()] - FIRE:[M.getFireLoss()] - TOXIN:[M.getToxLoss()] - OXY:[M.getOxyLoss()] - CLONE:[M.getCloneLoss()] - BRAIN:[M.getBrainLoss()] - - - - "} - else - body += "[D]" - if(A.dir) - body += "
<< [dir2text(A.dir)] >>" - else - body += "[D]" - - body += "
" - - body += "
" - - var/formatted_type = text("[D.type]") - if(length(formatted_type) > 25) - var/middle_point = length(formatted_type) / 2 - var/splitpoint = findtext(formatted_type,"/",middle_point) - if(splitpoint) - formatted_type = "[copytext(formatted_type,1,splitpoint)]
[copytext(formatted_type,splitpoint)]" - else - formatted_type = "Type too long" //No suitable splitpoint (/) found. - - body += "
[formatted_type]" - - if(src.holder && src.holder.marked_datum && src.holder.marked_datum == D) - body += "
Marked Object" - - body += "
" - - body += "
Refresh" - - //if(ismob(D)) - // body += "
Show player panel

" - - body += {"
-
" - - body += "

" - - body += "E - Edit, tries to determine the variable type by itself.
" - body += "C - Change, asks you for the var type first.
" - body += "M - Mass modify: changes this variable for all objects of this type.

" - - body += "
Search:

" - - body += "
    " - - var/list/names = list() - for (var/V in D.vars) - names += V - - names = sortList(names) - - for (var/V in names) - body += debug_variable(V, D.vars[V], 0, D) - - body += "
" - - var/html = "" - if (title) - html += "[title]" - html += {""} - html += "" - html += body - - html += {" - - "} - - html += "" - - usr << browse(html, "window=variables\ref[D];size=475x650") - - return - - proc/debug_variable(name, value, level, var/datum/DA = null) - var/html = "" - - if(DA) - html += "
  • (E) (C) (M) " - else - html += "
  • " - - if (isnull(value)) - html += "[name] = null" - - else if (istext(value)) - html += "[name] = \"[value]\"" - - else if (isicon(value)) - #ifdef VARSICON - var/icon/I = new/icon(value) - var/rnd = rand(1,10000) - var/rname = "tmp\ref[I][rnd].png" - usr << browse_rsc(I, rname) - html += "[name] = ([value]) " - #else - html += "[name] = /icon ([value])" - #endif - -/* else if (istype(value, /image)) - #ifdef VARSICON - var/rnd = rand(1, 10000) - var/image/I = value - - src << browse_rsc(I.icon, "tmp\ref[value][rnd].png") - html += "[name] = " - #else - html += "[name] = /image ([value])" - #endif -*/ - else if (isfile(value)) - html += "[name] = '[value]'" - - else if (istype(value, /datum)) - var/datum/D = value - html += "[name] \ref[value] = [D.type]" - - else if (istype(value, /client)) - var/client/C = value - html += "[name] \ref[value] = [C] [C.type]" - // - else if (istype(value, /list)) - var/list/L = value - html += "[name] = /list ([L.len])" - - if (L.len > 0 && !(name == "underlays" || name == "overlays" || name == "vars" || L.len > 500)) - // not sure if this is completely right... - if(0) //(L.vars.len > 0) - html += "
      " - html += "
    " - else - html += "" - - else - html += "[name] = [value]" - - html += "
  • " - - return html - /client/proc/view_var_Topic(href, href_list, hsrc) //This should all be moved over to datum/admins/Topic() or something ~Carn if( (usr.client != src) || !src.holder ) @@ -866,7 +453,7 @@ client return new new_organ(M) - + else if(href_list["remorgan"]) if(!check_rights(R_SPAWN)) return @@ -945,11 +532,14 @@ client message_admins("[key_name(usr)] dealt [amount] amount of [Text] damage to [L]") href_list["datumrefresh"] = href_list["mobToDamage"] + else if(href_list["call_proc"]) + var/datum/D = locate(href_list["call_proc"]) + if(istype(D) || istype(D, /client)) // can call on clients too, not just datums + callproc_targetpicked(1, D) + if(href_list["datumrefresh"]) var/datum/DAT = locate(href_list["datumrefresh"]) - if(!istype(DAT, /datum)) - return - src.debug_variables(DAT) + if(istype(DAT, /datum) || istype(DAT, /client)) + debug_variables(DAT) return - diff --git a/code/modules/admin/view_variables/view_variables.dm b/code/modules/admin/view_variables/view_variables.dm new file mode 100644 index 0000000000..e624d2df05 --- /dev/null +++ b/code/modules/admin/view_variables/view_variables.dm @@ -0,0 +1,160 @@ + +// Variables to not even show in the list. +// step_* and bound_* are here because they literally break the game and do nothing else. +// parent_type is here because it's pointless to show in VV. +/var/list/view_variables_hide_vars = list("bound_x", "bound_y", "bound_height", "bound_width", "bounds", "parent_type", "step_x", "step_y", "step_size") +// Variables not to expand the lists of. Vars is pointless to expand, and overlays/underlays cannot be expanded. +/var/list/view_variables_dont_expand = list("overlays", "underlays", "vars") + +/client/proc/debug_variables(datum/D in world) + set category = "Debug" + set name = "View Variables" + + if(!check_rights(0)) + return + + if(!D) + return + + var/icon/sprite + if(istype(D, /atom)) + var/atom/A = D + if(A.icon && A.icon_state) + sprite = icon(A.icon, A.icon_state) + usr << browse_rsc(sprite, "view_vars_sprite.png") + + usr << browse_rsc('code/js/view_variables.js', "view_variables.js") + + var/html = {" + + + + [D] (\ref[D] - [D.type]) + + + +
    + + + +
    + + [sprite ? "" : ""] + +
    [D.get_view_variables_header()]
    +
    + [replacetext("[D.type]", "/", "/")] + [holder.marked_datum == D ? "
    Marked Object" : ""] +
    +
    +
    + Refresh +
    + +
    +
    +
    +
    +
    + + E - Edit, tries to determine the variable type by itself.
    + C - Change, asks you for the var type first.
    + M - Mass modify: changes this variable for all objects of this type.
    +
    +
    + + + +
    +
    + Search: +
    +
    + +
    +
    +
      + [make_view_variables_var_list(D)] +
    + + + "} + + usr << browse(html, "window=variables\ref[D];size=475x650") + + +/proc/make_view_variables_var_list(datum/D) + . = "" + var/list/variables = list() + for(var/x in D.vars) + if(x in view_variables_hide_vars) + continue + variables += x + variables = sortList(variables) + for(var/x in variables) + . += make_view_variables_var_entry(D, x, D.vars[x]) + +/proc/make_view_variables_var_entry(datum/D, varname, value, level=0) + var/ecm = null + var/vtext = null + var/extra = null + + if(D) + ecm = {" + (E) + (C) + (M) + "} + + if(isnull(value)) + vtext = "null" + else if(istext(value)) + vtext = "\"[value]\"" + else if(isicon(value)) + vtext = "[value]" + else if(isfile(value)) + vtext = "'[value]'" + else if(istype(value, /datum)) + var/datum/DA = value + if("[DA]" == "[DA.type]" || !"[DA]") + vtext = "\ref[DA] - [DA.type]" + else + vtext = "\ref[DA] - [DA] ([DA.type])" + else if(istype(value, /client)) + var/client/C = value + vtext = "\ref[C] - [C] ([C.type])" + else if(islist(value)) + var/list/L = value + vtext = "/list ([L.len])" + if(!(varname in view_variables_dont_expand) && L.len > 0 && L.len < 100) + extra = "" + else + vtext = "[value]" + + return "
  • [ecm][varname] = [vtext][extra]
  • "