diff --git a/citadel.dme b/citadel.dme index 0d1f7b51809..e0c4fd5244c 100644 --- a/citadel.dme +++ b/citadel.dme @@ -531,6 +531,7 @@ #include "code\_globals\tgui.dm" #include "code\_globals\time_vars.dm" #include "code\_globals\traits.dm" +#include "code\_globals\lists\admin.dm" #include "code\_globals\lists\clients.dm" #include "code\_globals\lists\clothing.dm" #include "code\_globals\lists\keybindings.dm" @@ -2487,6 +2488,7 @@ #include "code\modules\admin\verbs\server\set_next_map.dm" #include "code\modules\admin\view_variables\admin_delete.dm" #include "code\modules\admin\view_variables\color_matrix_editor.dm" +#include "code\modules\admin\view_variables\debug_variable_appearance.dm" #include "code\modules\admin\view_variables\debug_variables.dm" #include "code\modules\admin\view_variables\filteriffic.dm" #include "code\modules\admin\view_variables\get_variables.dm" @@ -2494,6 +2496,7 @@ #include "code\modules\admin\view_variables\mark_datum.dm" #include "code\modules\admin\view_variables\mass_edit_variables.dm" #include "code\modules\admin\view_variables\modify_variables.dm" +#include "code\modules\admin\view_variables\nobody_wants_to_learn_matrix_math.dm" #include "code\modules\admin\view_variables\reference_tracking.dm" #include "code\modules\admin\view_variables\topic.dm" #include "code\modules\admin\view_variables\topic_basic.dm" @@ -3953,7 +3956,6 @@ #include "code\modules\mob\living\say.dm" #include "code\modules\mob\living\status_procs.dm" #include "code\modules\mob\living\throwing.dm" -#include "code\modules\mob\living\vv.dm" #include "code\modules\mob\living\bot\assembly.dm" #include "code\modules\mob\living\bot\bot.dm" #include "code\modules\mob\living\bot\cleanbot.dm" diff --git a/code/__DEFINES/_core.dm b/code/__DEFINES/_core.dm index c90a3c5c705..4d3fd8b3c9a 100644 --- a/code/__DEFINES/_core.dm +++ b/code/__DEFINES/_core.dm @@ -15,3 +15,9 @@ /// A null statement to guard against EmptyBlock lint without necessitating the use of pass() /// Used to avoid proc-call overhead. But use sparingly. Probably pointless in most places. #define EMPTY_BLOCK_GUARD ; + +// THIS IS ON THIS FILE NOT IN `typeids.dm` DUE TO DEFINE LOAD ORDER!!! +// Refs contain a type id within their string that can be used to identify byond types. +// Custom types that we define don't get a unique id, but this is useful for identifying +// types that don't normally have a way to run istype() on them. +#define TYPEID(thing) copytext(REF(thing), 4, 6) diff --git a/code/__DEFINES/is_helpers.dm b/code/__DEFINES/is_helpers.dm index 2790d21bef0..ccfb7dd1814 100644 --- a/code/__DEFINES/is_helpers.dm +++ b/code/__DEFINES/is_helpers.dm @@ -17,20 +17,29 @@ #define isatom(A) (isloc(A)) -#define isdatum(D) (istype(D, /datum)) - -#define ismutableappearance(D) (istype(D, /mutable_appearance)) - -#define isimage(D) (istype(D, /image)) +#define isdatum(thing) (istype(thing, /datum)) #define isweakref(D) (istype(D, /datum/weakref)) +#define isimage(thing) (istype(thing, /image)) + +GLOBAL_VAR_INIT(magic_appearance_detecting_image, new /image) // appearances are awful to detect safely, but this seems to be the best way ~ninjanomnom +#define isappearance(thing) (!isimage(thing) && !ispath(thing) && istype(GLOB.magic_appearance_detecting_image, thing)) + +// The filters list has the same ref type id as a filter, but isnt one and also isnt a list, so we have to check if the thing has Cut() instead +GLOBAL_VAR_INIT(refid_filter, TYPEID(filter(type="angular_blur"))) +#define isfilter(thing) (!hascall(thing, "Cut") && TYPEID(thing) == GLOB.refid_filter) + +#define ismutableappearance(D) (istype(D, /mutable_appearance)) + //Datums #define isTaurTail(A) istype(A, /datum/sprite_accessory/tail/legacy_taur) //Turfs +//#define isturf(A) (istype(A, /turf)) This is actually a byond built-in. Added here for completeness sake. + #define isfloorturf(A) (istype(A, /turf/simulated/floor)) #define isopenturf(A) istype(A, /turf/simulated/open) @@ -39,9 +48,10 @@ #define ismineralturf(A) istype(A, /turf/simulated/mineral) -//Objs +//Objects ///override the byond proc because it returns true on children of /atom/movable that aren't objs #define isobj(A) istype(A, /obj) + #define isitem(A) (istype(A, /obj/item)) #define isclothing(A) (istype(A, /obj/item/clothing)) @@ -68,49 +78,50 @@ //Mobs -#define isAI(A) istype(A, /mob/living/silicon/ai) - -#define isalien(A) istype(A, /mob/living/carbon/alien) - -#define isanimal_legacy_this_is_broken(A) istype(A, /mob/living/simple_animal) +#define isliving(A) istype(A, /mob/living) #define isbrain(A) istype(A, /mob/living/carbon/brain) +//Carbon mobs + #define iscarbon(A) istype(A, /mob/living/carbon) -#define iscorgi(A) istype(A, /mob/living/simple_mob/animal/passive/dog/corgi) - -#define isDrone(A) istype(A, /mob/living/silicon/robot/drone) - -#define isEye(A) istype(A, /mob/observer/eye) - #define ishuman(A) istype(A, /mob/living/carbon/human) -#define isliving(A) istype(A, /mob/living) +#define isdummy(A) (istype(A, /mob/living/carbon/human/dummy)) +//More carbon mobs +#define isalien(A) istype(A, /mob/living/carbon/alien) + +//Silicon mobs +#define issilicon(A) istype(A, /mob/living/silicon) +#define isAI(A) istype(A, /mob/living/silicon/ai) +#define isrobot(A) istype(A, /mob/living/silicon/robot) +#define ispAI(A) istype(A, /mob/living/silicon/pai) +#define isDrone(A) istype(A, /mob/living/silicon/robot/drone) #define isMatriarchDrone(A) istype(A, /mob/living/silicon/robot/drone/matriarch) -#define ismouse(A) istype(A, /mob/living/simple_mob/animal/passive/mouse/) + +//Simple animals +#define issimplemob(A) istype(A, /mob/living/simple_mob) +#define isanimal_legacy_this_is_broken(A) istype(A, /mob/living/simple_animal) + +#define iscorgi(A) istype(A, /mob/living/simple_mob/animal/passive/dog/corgi) +#define ismouse(A) istype(A, /mob/living/simple_mob/animal/passive/mouse) +#define isslime(A) istype(A, /mob/living/simple_mob/slime) +#define isxeno(A) istype(A, /mob/living/simple_mob/xeno) + +//Eye mobs +#define isEye(A) istype(A, /mob/observer/eye) + +//Dead mobs +#define isobserver(A) istype(A, /mob/observer/dead) #define isnewplayer(A) istype(A, /mob/new_player) -#define isobserver(A) istype(A, /mob/observer/dead) - -#define ispAI(A) istype(A, /mob/living/silicon/pai) - -#define isrobot(A) istype(A, /mob/living/silicon/robot) - -#define issilicon(A) istype(A, /mob/living/silicon) - -#define isvoice(A) istype(A, /mob/living/voice) - -#define isslime(A) istype(A, /mob/living/simple_mob/slime) - +//Misc mobs #define isbot(A) istype(A, /mob/living/bot) - -#define isxeno(A) istype(A, /mob/living/simple_mob/xeno) - -#define issimplemob(A) istype(A, /mob/living/simple_mob) +#define isvoice(A) istype(A, /mob/living/voice) /proc/is_species_type(atom/A, path) if(!istype(A, /mob/living/carbon/human)) diff --git a/code/__DEFINES/vv.dm b/code/__DEFINES/vv.dm index 223d833136f..4128f7a0312 100644 --- a/code/__DEFINES/vv.dm +++ b/code/__DEFINES/vv.dm @@ -1,6 +1,8 @@ #define VV_NUM "Number" #define VV_TEXT "Text" -#define VV_MESSAGE "Mutiline Text" +#define VV_MESSAGE "Multiline Text" +#define VV_COLOR "Color" +#define VV_COLOR_MATRIX "Color Matrix" #define VV_ICON "Icon" #define VV_ATOM_REFERENCE "Atom Reference" #define VV_DATUM_REFERENCE "Datum Reference" @@ -18,11 +20,13 @@ #define VV_NEW_LIST "New List" #define VV_NEW_ALIST "New A-List" #define VV_NULL "NULL" +#define VV_INFINITY "Infinity" #define VV_RESTORE_DEFAULT "Restore to Default" #define VV_MARKED_DATUM "Marked Datum" #define VV_BITFIELD "Bitfield" #define VV_TEXT_LOCATE "Custom Reference Locate" #define VV_PROCCALL_RETVAL "Return Value of Proccall" +#define VV_WEAKREF "Weak Reference Datum" #define VV_MSG_MARKED "
Marked Object" #define VV_MSG_EDITED "
Var Edited" @@ -32,11 +36,11 @@ #define VV_SPECIAL_LIST_NO_EXPAND_THRESHOLD 150 //#define IS_VALID_ASSOC_KEY(V) (istext(V) || ispath(V) || isdatum(V) || islist(V)) -///hhmmm.. -#define IS_VALID_ASSOC_KEY(V) (!isnum(V)) +#define IS_VALID_ASSOC_KEY(V) (!isnum(V)) //hhmmm.. + //General helpers -#define VV_HREF_TARGET_INTERNAL(target, href_key) "?_src_=vars;[HrefToken()];[href_key]=TRUE;[VV_HK_TARGET]=[REF(target)]" -#define VV_HREF_TARGETREF_INTERNAL(targetref, href_key) "?_src_=vars;[HrefToken()];[href_key]=TRUE;[VV_HK_TARGET]=[targetref]" +#define VV_HREF_TARGET_INTERNAL(target, href_key) "byond://?_src_=vars;[HrefToken()];[href_key]=TRUE;[VV_HK_TARGET]=[REF(target)]" +#define VV_HREF_TARGETREF_INTERNAL(targetref, href_key) "byond://?_src_=vars;[HrefToken()];[href_key]=TRUE;[VV_HK_TARGET]=[targetref]" #define VV_HREF_TARGET(target, href_key, text) "[text]" #define VV_HREF_TARGETREF(targetref, href_key, text) "[text]" ///for stuff like basic varedits, one variable @@ -47,25 +51,16 @@ #define GET_VV_VAR_TARGET href_list[VV_HK_VARNAME] //Helper for getting something to vv_do_topic in general -#define VV_TOPIC_LINK(datum, href_key, text) "text" +#define VV_TOPIC_LINK(datum, href_key, text) "text" //Helpers for vv_get_dropdown() #define VV_DROPDOWN_OPTION(href_key, name) . += "" -//! enums for vv target types -/// is datum -#define VVING_A_DATUM 1 -/// is list -#define VVING_A_LIST 2 -/// is appearance -#define VVING_A_APPEARANCE 3 - // VV HREF KEYS #define VV_HK_TARGET "target" ///name or index of var for 1 variable targetting hrefs. #define VV_HK_VARNAME "targetvar" -/// to view an appearance virtual object -#define VV_HK_VIEW_APPEARANCE "vv_appearance" + // vv_do_list() keys #define VV_HK_LIST_ADD "listadd" #define VV_HK_LIST_EDIT "listedit" @@ -87,6 +82,8 @@ #define VV_HK_CALLPROC "proc_call" #define VV_HK_MARK "mark" #define VV_HK_ADDCOMPONENT "addcomponent" +#define VV_HK_REMOVECOMPONENT "removecomponent" +#define VV_HK_MASS_REMOVECOMPONENT "massremovecomponent" #define VV_HK_MODIFY_TRAITS "modtraits" // /atom @@ -98,9 +95,24 @@ #define VV_HK_TRIGGER_EXPLOSION "explode" #define VV_HK_EDIT_FILTERS "edit_filters" #define VV_HK_EDIT_COLOR_MATRIX "edit_color_matrix" +#define VV_HK_TEST_MATRIXES "test_matrixes" #define VV_HK_EDIT_ARMOR "edit_armor" +// /atom/movable +#define VV_HK_GET_MOVABLE "get_movable" + +// /obj +#define VV_HK_MASS_DEL_TYPE "mass_delete_type" + // /mob +#define VV_HK_GIB "gib" +#define VV_HK_GIVE_SPELL "give_spell" +#define VV_HK_GIVE_DISEASE "give_disease" +#define VV_HK_GODMODE "godmode" +#define VV_HK_DROP_ALL "dropall" +#define VV_HK_PLAYER_PANEL "player_panel" +#define VV_HK_BUILDMODE "buildmode" +#define VV_HK_DIRECT_CONTROL "direct_control" #define VV_HK_TRIGGER_OFFER_MOB_TO_GHOSTS "offer_mob_to_ghosts" /// used on /mob as well as /obj/item/organ #define VV_HK_ADD_PHYSIOLOGY_MODIFIER "add_physiology_mod" @@ -114,3 +126,8 @@ #define VV_HK_ID_MOD "id_mod" #define VV_HK_WEAKREF_RESOLVE "weakref_resolve" + +// Flags for debug_variable() that do little things to what we end up rendering + +/// ALWAYS render a reduced list, useful for fuckoff big datums that need to be condensed for the sake of client load +#define VV_ALWAYS_CONTRACT_LIST (1<<0) diff --git a/code/__HELPERS/_lists_tg.dm b/code/__HELPERS/_lists_tg.dm index 6d04dfad755..017f6e397b1 100644 --- a/code/__HELPERS/_lists_tg.dm +++ b/code/__HELPERS/_lists_tg.dm @@ -1,3 +1,11 @@ +// Generic listoflist safe add and removal macros: +///If value is a list, wrap it in a list so it can be used with list add/remove operations +#define LIST_VALUE_WRAP_LISTS(value) (islist(value) ? list(value) : value) +///Add an untyped item to a list, taking care to handle list items by wrapping them in a list to remove the footgun +#define UNTYPED_LIST_ADD(list, item) (list += LIST_VALUE_WRAP_LISTS(item)) +///Remove an untyped item to a list, taking care to handle list items by wrapping them in a list to remove the footgun +#define UNTYPED_LIST_REMOVE(list, item) (list -= LIST_VALUE_WRAP_LISTS(item)) + //Removes any null entries from the list //Returns TRUE if the list had nulls, FALSE otherwise diff --git a/code/__HELPERS/ref.dm b/code/__HELPERS/ref.dm index b22983ef6ad..a5e73cec571 100644 --- a/code/__HELPERS/ref.dm +++ b/code/__HELPERS/ref.dm @@ -1,10 +1,10 @@ /** * \ref behaviour got changed in 512 so this is necesary to replicate old behaviour. * If it ever becomes necesary to get a more performant REF(), this lies here in wait - * #define REF(thing) (thing && istype(thing, /datum) && (thing:datum_flags & DF_USE_TAG) && thing:tag ? "[thing:tag]" : "\ref[thing]") + * #define REF(thing) (thing && isdatum(thing) && (thing:datum_flags & DF_USE_TAG) && thing:tag ? "[thing:tag]" : ref(thing)) */ /proc/REF(input) - if(istype(input, /datum)) + if(isdatum(input)) var/datum/thing = input if(thing.datum_flags & DF_USE_TAG) if(!thing.tag) diff --git a/code/_globals/lists/admin.dm b/code/_globals/lists/admin.dm new file mode 100644 index 00000000000..003fff141aa --- /dev/null +++ b/code/_globals/lists/admin.dm @@ -0,0 +1,16 @@ + +// A list of all the special byond lists that need to be handled different by vv +GLOBAL_LIST_INIT(vv_special_lists, init_special_list_names()) + +/proc/init_special_list_names() + var/list/output = list() + var/obj/sacrifice = new + for(var/varname in sacrifice.vars) + var/value = sacrifice.vars[varname] + if(!islist(value)) + if(!isdatum(value) && hascall(value, "Cut")) + output += varname + continue + if(isnull(locate(REF(value)))) + output += varname + return output diff --git a/code/_globals/lists/misc.dm b/code/_globals/lists/misc.dm index 50633060ed1..ec2c596bfaa 100644 --- a/code/_globals/lists/misc.dm +++ b/code/_globals/lists/misc.dm @@ -12,3 +12,5 @@ GLOBAL_LIST_EMPTY(tagger_locations) /// Cache of the width and height of icon files, to avoid repeating the same expensive operation GLOBAL_LIST_EMPTY(icon_dimensions) + +GLOBAL_LIST_INIT(color_vars, list("color")) diff --git a/code/datums/datumvars.dm b/code/datums/datumvars.dm index 745ad7051e4..34de9c789ba 100644 --- a/code/datums/datumvars.dm +++ b/code/datums/datumvars.dm @@ -42,14 +42,18 @@ VV_DROPDOWN_OPTION(VV_HK_DELETE, "Delete") VV_DROPDOWN_OPTION(VV_HK_EXPOSE, "Show VV To Player") VV_DROPDOWN_OPTION(VV_HK_ADDCOMPONENT, "Add Component/Element") + VV_DROPDOWN_OPTION(VV_HK_REMOVECOMPONENT, "Remove Component/Element") + VV_DROPDOWN_OPTION(VV_HK_MASS_REMOVECOMPONENT, "Mass Remove Component/Element") VV_DROPDOWN_OPTION(VV_HK_MODIFY_TRAITS, "Modify Traits") -//This proc is only called if everything topic-wise is verified. The only verifications that should happen here is things like permission checks! -//href_list is a reference, modifying it in these procs WILL change the rest of the proc in topic.dm of admin/view_variables! -//This proc is for "high level" actions like admin heal/set species/etc/etc. The low level debugging things should go in admin/view_variables/topic_basic.dm incase this runtimes. +/** + * This proc is only called if everything topic-wise is verified. The only verifications that should happen here is things like permission checks! + * href_list is a reference, modifying it in these procs WILL change the rest of the proc in topic.dm of admin/view_variables! + * This proc is for "high level" actions like admin heal/set species/etc/etc. The low level debugging things should go in admin/view_variables/topic_basic.dm in case this runtimes. + */ /datum/proc/vv_do_topic(list/href_list) - if(!usr || !usr.client || !usr.client.holder || !check_rights(NONE)) - return FALSE //This is VV, not to be called by anything else. + if(!usr || !usr.client || !usr.client.holder || !check_rights(R_VAREDIT)) + return FALSE //This is VV, not to be called by anything else. if(href_list[VV_HK_MODIFY_TRAITS]) usr.client.holder.modify_traits(src) return TRUE diff --git a/code/datums/weakref.dm b/code/datums/weakref.dm index e0ddef6c723..767dbccc344 100644 --- a/code/datums/weakref.dm +++ b/code/datums/weakref.dm @@ -68,7 +68,7 @@ var/reference /datum/weakref/New(datum/thing) - reference = ref(thing) + reference = REF(thing) /datum/weakref/Destroy(force) var/datum/target = resolve() diff --git a/code/game/atoms/atom-vv.dm b/code/game/atoms/atom-vv.dm index 1ec689354fe..4c62851fa68 100644 --- a/code/game/atoms/atom-vv.dm +++ b/code/game/atoms/atom-vv.dm @@ -19,7 +19,7 @@ VV_DROPDOWN_OPTION(VV_HK_TRIGGER_EXPLOSION, "Explosion") VV_DROPDOWN_OPTION(VV_HK_EDIT_FILTERS, "Edit Filters") VV_DROPDOWN_OPTION(VV_HK_EDIT_COLOR_MATRIX, "Edit Color as Matrix") - // VV_DROPDOWN_OPTION(VV_HK_TEST_MATRIXES, "Test Matrices") + VV_DROPDOWN_OPTION(VV_HK_TEST_MATRIXES, "Test Matrices") // VV_DROPDOWN_OPTION(VV_HK_ADD_AI, "Add AI controller") VV_DROPDOWN_OPTION(VV_HK_EDIT_ARMOR, "Edit Armor") @@ -29,14 +29,16 @@ if(!.) return - if(href_list[VV_HK_ADD_REAGENT] && check_rights(R_VAREDIT)) + if(href_list[VV_HK_ADD_REAGENT]) + if(!check_rights(R_VAREDIT)) + return if(!reagents) var/amount = input(usr, "Specify the reagent size of [src]", "Set Reagent Size", 50) as num|null if(amount) create_reagents(amount) if(reagents) var/chosen_id - switch(alert(usr, "Choose a method.", "Add Reagents", "Search", "Choose from a list", "I'm feeling lucky")) + switch(tgui_alert(usr, "Choose a method.", "Add Reagents", list("Search", "Choose from a list", "I'm feeling lucky"))) if("Search") var/valid_id while(!valid_id) @@ -50,7 +52,7 @@ else valid_id = TRUE if(!valid_id) - to_chat(usr, "A reagent with that ID doesn't exist!") + to_chat(usr, SPAN_WARNING("A reagent with that ID doesn't exist!"), confidential = TRUE) if("Choose from a list") chosen_id = input(usr, "Choose a reagent to add.", "Choose a reagent.") as null|anything in sortList(subtypesof(/datum/reagent), GLOBAL_PROC_REF(cmp_typepaths_asc)) if("I'm feeling lucky") @@ -68,7 +70,9 @@ if(href_list[VV_HK_TRIGGER_EMP] && check_rights(R_FUN)) usr.client.cmd_admin_emp(src) - if(href_list[VV_HK_MODIFY_TRANSFORM] && check_rights(R_VAREDIT)) + if(href_list[VV_HK_MODIFY_TRANSFORM]) + if(!check_rights(R_VAREDIT)) + return var/result = input(usr, "Choose the transformation to apply","Transform Mod") as null|anything in list("Scale","Translate","Rotate","Shear") var/matrix/M = transform if(!result) @@ -109,8 +113,8 @@ num_spins = -1 if(!num_spins) return - var/spin_speed = input(usr, "How fast?", "Spin Animation") as null|num - if(!spin_speed) + var/spins_per_sec = input(usr, "How many spins per second?", "Spin Animation") as null|num + if(!spins_per_sec) return var/direction = input(usr, "Which direction?", "Spin Animation") in list("Clockwise", "Counter-clockwise") switch(direction) @@ -120,7 +124,7 @@ direction = 0 else return - SpinAnimation(spin_speed, num_spins, direction) + SpinAnimation(1 SECONDS / spins_per_sec, num_spins, direction) if(href_list[VV_HK_STOP_ALL_ANIMATIONS]) if(!check_rights(R_VAREDIT)) @@ -130,13 +134,20 @@ animate(src, transform = null, flags = ANIMATION_END_NOW) // Literally just fucking stop animating entirely because admin said so return - if(href_list[VV_HK_EDIT_FILTERS] && check_rights(R_VAREDIT)) - var/client/C = usr.client - C?.open_filter_editor(src) + if(href_list[VV_HK_EDIT_FILTERS]) + if(!check_rights(R_VAREDIT)) + return + usr.client?.open_filter_editor(src) - if(href_list[VV_HK_EDIT_COLOR_MATRIX] && check_rights(R_VAREDIT)) - var/client/C = usr.client - C?.open_color_matrix_editor(src) + if(href_list[VV_HK_EDIT_COLOR_MATRIX]) + if(!check_rights(R_VAREDIT)) + return + usr.client?.open_color_matrix_editor(src) + + if(href_list[VV_HK_TEST_MATRIXES]) + if(!check_rights(R_VAREDIT)) + return + usr.client?.open_matrix_tester(src) if(href_list[VV_HK_EDIT_ARMOR] && check_rights(R_VAREDIT)) // todo: tgui armor editor? @@ -157,10 +168,10 @@ /atom/vv_get_header() . = ..() - if(!isliving(src)) - var/refid = REF(src) - . += "[VV_HREF_TARGETREF_1V(refid, VV_HK_BASIC_EDIT, "[src]", NAMEOF(src, name))]" - . += "
<< [dir2text(dir) || dir] >>" + var/refid = REF(src) + // . += "[VV_HREF_TARGETREF(refid, VV_HK_AUTO_RENAME, "[src]")]" + . += "[src]" + . += "
<< [dir2text(dir) || dir] >>" /** * call back when a var is edited on this atom diff --git a/code/game/atoms/movable/movable.dm b/code/game/atoms/movable/movable.dm index 887b73b3430..03880dd2636 100644 --- a/code/game/atoms/movable/movable.dm +++ b/code/game/atoms/movable/movable.dm @@ -569,3 +569,21 @@ if(!isnull(render_target)) return render_target = "[make_us_invisible? "*":""][REF(src)]-[rand(1,1000)]-[world.time]" + +/atom/movable/vv_get_dropdown() + . = ..() + VV_DROPDOWN_OPTION("", "---------") + VV_DROPDOWN_OPTION(VV_HK_GET_MOVABLE, "Get Movable") + +/atom/movable/vv_do_topic(list/href_list) + . = ..() + + if(!.) + return + + if(href_list[VV_HK_GET_MOVABLE]) + if(!check_rights(R_ADMIN)) + return + if(QDELETED(src)) + return + forceMove(get_turf(usr)) diff --git a/code/game/objects/obj.dm b/code/game/objects/obj.dm index ec6442c14e6..73ee673d647 100644 --- a/code/game/objects/obj.dm +++ b/code/game/objects/obj.dm @@ -1044,3 +1044,51 @@ switch(var_name) if(NAMEOF(src, hides_underfloor)) set_hides_underfloor(var_value) + +/obj/vv_get_dropdown() + . = ..() + VV_DROPDOWN_OPTION("", "---") + VV_DROPDOWN_OPTION(VV_HK_MASS_DEL_TYPE, "Delete all of type") + +/obj/vv_do_topic(list/href_list) + . = ..() + + if(!.) + return + + if(href_list[VV_HK_MASS_DEL_TYPE]) + if(!check_rights(R_DEBUG|R_SERVER)) + return + var/action_type = tgui_alert(usr, "Strict type ([type]) or type and all subtypes?",,list("Strict type","Type and subtypes","Cancel")) + if(action_type == "Cancel" || !action_type) + return + if(tgui_alert(usr, "Are you really sure you want to delete all objects of type [type]?",,list("Yes","No")) != "Yes") + return + if(tgui_alert(usr, "Second confirmation required. Delete?",,list("Yes","No")) != "Yes") + return + var/O_type = 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(usr, "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(usr, "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) ")) diff --git a/code/modules/admin/view_variables/debug_variable_appearance.dm b/code/modules/admin/view_variables/debug_variable_appearance.dm new file mode 100644 index 00000000000..36cd09a169a --- /dev/null +++ b/code/modules/admin/view_variables/debug_variable_appearance.dm @@ -0,0 +1,73 @@ +/// Shows a header name on top when you investigate an appearance/image +/image/vv_get_header() + . = list() + var/icon_name = "[icon || "null"]
" + . += 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 "[display_name] ([display_value]) [display_ref]" + +/// 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 + // 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 "
  • (READ ONLY) [var_name] = [_debug_variable_value(var_name, value, 0, src, sanitize = TRUE, display_flags = NONE)]
  • " + +/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_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) diff --git a/code/modules/admin/view_variables/debug_variables.dm b/code/modules/admin/view_variables/debug_variables.dm index 133dfff0884..78f732763bb 100644 --- a/code/modules/admin/view_variables/debug_variables.dm +++ b/code/modules/admin/view_variables/debug_variables.dm @@ -1,86 +1,132 @@ #define VV_HTML_ENCODE(thing) ( sanitize ? html_encode(thing) : thing ) -/proc/debug_variable(name, value, level, datum/D, sanitize = TRUE) //if D is a list, name will be index, and value will be assoc value. - var/header - if(D) - if(islist(D)) - var/list/D_l = D +/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 = D_l[name] //name is really the index until this line + if (isnull(value)) + value = list_owner[name] else - value = D_l[name] - header = "
  • ([VV_HREF_TARGET_1V(D, VV_HK_LIST_EDIT, "E", index)]) ([VV_HREF_TARGET_1V(D, VV_HK_LIST_CHANGE, "C", index)]) ([VV_HREF_TARGET_1V(D, VV_HK_LIST_REMOVE, "-", index)]) " + name = list_owner[name] //name is really the index until this line + . = "
  • ([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 = "
  • ([VV_HREF_TARGET_1V(D, VV_HK_BASIC_EDIT, "E", name)]) ([VV_HREF_TARGET_1V(D, VV_HK_BASIC_CHANGE, "C", name)]) ([VV_HREF_TARGET_1V(D, VV_HK_BASIC_MASSEDIT, "M", name)]) " + . = "
  • ([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 = "
  • " + . = "
  • " - var/item - var/datum/bitfield/maybe_bitfield - if (isnull(value)) - item = "[VV_HTML_ENCODE(name)] = null" + var/name_part = VV_HTML_ENCODE(name) + if(level > 0 || islist(owner)) //handling keys in assoc lists + if(istype(name,/datum)) + name_part = "[VV_HTML_ENCODE(name)] [REF(name)]" + else if(islist(name)) + var/list/list_value = name + name_part = " /list ([length(list_value)]) [REF(name)]" - else if(IS_APPEARANCE(value)) - item = "[VV_HTML_ENCODE(name)] [ref(value)] = /appearance" + . = "[.][name_part] = " - else if (istext(value)) - item = "[VV_HTML_ENCODE(name)] = \"[VV_HTML_ENCODE(value)]\"" + var/item = _debug_variable_value(name, value, level, owner, sanitize, display_flags) - else if (isicon(value)) + return "[.][item]
  • " + +// 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) + + . = "DISPLAY_ERROR: ([value] [REF(value)])" // Make sure this line can never runtime + + if(isnull(value)) + return "null" + + if(istext(value)) + return "\"[VV_HTML_ENCODE(value)]\"" + + if(isicon(value)) #ifdef VARSICON - var/icon/I = 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)] = ([value]) " + var/rname = "tmp[REF(icon_value)][rnd].png" + usr << browse_rsc(icon_value, rname) + return "([value]) " #else - item = "[VV_HTML_ENCODE(name)] = /icon ([value])" + return "/icon ([value])" #endif - else if (isfile(value)) - item = "[VV_HTML_ENCODE(name)] = '[value]'" + if(isfilter(value)) + var/datum/filter_value = value + return "/filter ([filter_value.type] [REF(filter_value)])" - else if (istype(value, /datum)) - var/datum/DV = value - if ("[DV]" != "[DV.type]") //if the thing as a name var, lets use it. - item = "[VV_HTML_ENCODE(name)] [REF(value)] = [DV] [DV.type]" - else - item = "[VV_HTML_ENCODE(name)] [REF(value)] = [DV.type]" + if(isfile(value)) + return "'[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() - // don't expand if it's: - // 1. overlays - this info is rarely needing to be accessed unless you're doing overlay debugging - // 2. underlays - ditto - // 3. GLOB - there's a metric ton of lists on global variables and we want to avoid admins needing to download MB's of data instantly - // 4. if the list is too long otherwise - if (L.len > 0 && !(name == "underlays" || name == "overlays" || D == GLOB || 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 = "[VV_HTML_ENCODE(name)] = /list ([L.len])" - else - item = "[VV_HTML_ENCODE(name)] = /list ([L.len])" + return "/list ([list_value.len])" + return "/list ([list_value.len])" - else if (istype(D) && isnum(value) && (maybe_bitfield = fetch_bitfield(D.type, name))) - var/list/flags = list() + // if it's a number, is it a bitflag? + var/list/valid_bitflags = list() + if(!isnum(name) && istype(owner)) + var/datum/bitfield/maybe_bitfield = fetch_bitfield(owner.type, name) + if (!maybe_bitfield) + return "[VV_HTML_ENCODE(value)]" for(var/i in 1 to maybe_bitfield.get_declared_count()) var/bit = maybe_bitfield.bits[i] - if(value & bit) - flags += maybe_bitfield.names[i] - item = "[VV_HTML_ENCODE(name)] = [jointext(flags, ", ")]" - else - item = "[VV_HTML_ENCODE(name)] = [VV_HTML_ENCODE(value)]" + valid_bitflags[maybe_bitfield.get_bit_name(bit)] = bit - return "[header][item]" + if(!length(valid_bitflags)) + return "[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 "[src] [type] [REF(src)]" + else + return "[type] [REF(src)]" + +/datum/weakref/debug_variable_value(name, level, datum/owner, sanitize, display_flags) + . = ..() + return "[.] (Resolve)" + +/matrix/debug_variable_value(name, level, datum/owner, sanitize, display_flags) + return {" +
      + + + + + + +
    [a][d]0
    [b][e]0
    [c][f]1
     
    "} //TODO link to modify_transform wrapper for all matrices #undef VV_HTML_ENCODE diff --git a/code/modules/admin/view_variables/get_variables.dm b/code/modules/admin/view_variables/get_variables.dm index 8e21287e482..fb04c5ba1d9 100644 --- a/code/modules/admin/view_variables/get_variables.dm +++ b/code/modules/admin/view_variables/get_variables.dm @@ -11,6 +11,8 @@ 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 @@ -26,7 +28,10 @@ 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)) @@ -38,7 +43,11 @@ . = VV_TYPE else if(islist(var_value)) - . = VV_LIST + if(var_name in GLOB.color_vars) + . = VV_COLOR_MATRIX + else + . = VV_LIST + else if(isalist(var_value)) . = VV_ALIST @@ -56,6 +65,8 @@ VV_TEXT, VV_MESSAGE, VV_ICON, + VV_COLOR, + VV_COLOR_MATRIX, VV_ATOM_REFERENCE, VV_DATUM_REFERENCE, VV_MOB_REFERENCE, @@ -70,9 +81,11 @@ VV_NEW_LIST, VV_NEW_ALIST, VV_NULL, + VV_INFINITY, VV_RESTORE_DEFAULT, VV_TEXT_LOCATE, VV_PROCCALL_RETVAL, + VV_WEAKREF, ) var/markstring @@ -178,6 +191,19 @@ 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 = input("Select reference:", "Reference", current_value) as null|anything in things + if(!value) + .["class"] = null + return + .["value"] = WEAKREF(things[value]) + if(VV_CLIENT) .["value"] = input("Select reference:", "Reference", current_value) as null|anything in GLOB.clients if(.["value"] == null) @@ -250,8 +276,22 @@ .["value"] = newguy if(VV_NEW_LIST) - .["value"] = 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_NEW_ALIST) .["value"] = alist() @@ -265,14 +305,25 @@ break D = locate(ref) if(!D) - alert("Invalid ref!") - continue - if(!istype(D)) - alert("Not a datum.") + tgui_alert(usr,"Invalid ref!") continue if(!D.can_vv_mark()) - alert("Datum can not be marked!") + tgui_alert(usr,"Datum can not be marked!") continue while(!D) .["type"] = D.type .["value"] = D + + if(VV_COLOR) + .["value"] = input("Enter new color:", "Color", current_value) as color|null + 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 diff --git a/code/modules/admin/view_variables/helpers_LEGACY.dm b/code/modules/admin/view_variables/helpers_LEGACY.dm index faa691443ea..b4d2b302832 100644 --- a/code/modules/admin/view_variables/helpers_LEGACY.dm +++ b/code/modules/admin/view_variables/helpers_LEGACY.dm @@ -7,21 +7,11 @@ /mob/get_view_variables_options_legacy() return ..() + {" - - - - - - - - - - @@ -32,10 +22,6 @@ - - - - "} /mob/living/carbon/human/get_view_variables_options_legacy() @@ -46,8 +32,3 @@ "} - -/obj/get_view_variables_options_legacy() - return ..() + {" - - "} diff --git a/code/modules/admin/view_variables/mark_datum.dm b/code/modules/admin/view_variables/mark_datum.dm index b608c57abab..756fc74da1c 100644 --- a/code/modules/admin/view_variables/mark_datum.dm +++ b/code/modules/admin/view_variables/mark_datum.dm @@ -2,10 +2,17 @@ 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) +/datum/admins/proc/handle_marked_del(datum/source) + SIGNAL_HANDLER + UnregisterSignal(marked_datum, COMSIG_PARENT_QDELETING) + marked_datum = null + /client/proc/mark_datum_mapview(datum/D in world) set category = "Debug" set name = "Mark Object" diff --git a/code/modules/admin/view_variables/modify_variables.dm b/code/modules/admin/view_variables/modify_variables.dm index 1865898d413..8e2ab1053b3 100644 --- a/code/modules/admin/view_variables/modify_variables.dm +++ b/code/modules/admin/view_variables/modify_variables.dm @@ -1,15 +1,15 @@ -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")) +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) if(O && findtext(new_var,"\[")) - var/process_vars = alert(usr,"\[] detected in string, process as variables?","Process Variables?","Yes","No") + var/process_vars = tgui_alert(usr,"\[] detected in string, process as variables?","Process Variables?",list("Yes","No")) if(process_vars == "Yes") . = string2listofvars(new_var, O) @@ -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(alert("Strict object type detection?", "Type detection", "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") @@ -50,14 +50,14 @@ GLOBAL_PROTECT(VVpixelmovement) 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 = "/" @@ -65,7 +65,6 @@ GLOBAL_PROTECT(VVpixelmovement) .["[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) @@ -79,7 +78,6 @@ GLOBAL_PROTECT(VVpixelmovement) return var_value - /client/proc/mod_list_add(list/L, atom/O, original_name, objectvar) var/list/LL = vv_get_value(restricted_classes = list(VV_RESTORE_DEFAULT)) var/class = LL["class"] @@ -95,15 +93,14 @@ GLOBAL_PROTECT(VVpixelmovement) if (O) L = L.Copy() - L.len++ - L[L.len] = var_value + L += list(var_value) //var_value could be a list - switch(alert("Would you like to associate a value with the list entry?",,"Yes","No")) + 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]") @@ -113,11 +110,11 @@ 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 = alert(src, "The list you're trying to edit is very long, continuing may crash the server.", "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 @@ -145,7 +142,7 @@ GLOBAL_PROTECT(VVpixelmovement) L = L.Copy() listclearnulls(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 +152,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 +162,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") @@ -174,12 +171,11 @@ GLOBAL_PROTECT(VVpixelmovement) index = names[variable] - var/assoc_key if (index == null) return var/assoc = 0 - var/prompt = alert(src, "Do you want to edit the key or its assigned value?", "Associated List", "Key", "Assigned Value", "Cancel") + 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") @@ -187,7 +183,7 @@ GLOBAL_PROTECT(VVpixelmovement) assoc_key = L[index] var/default var/variable - var/old_assoc_value //EXPERIMENTAL - Keep old associated value while modifying key, if any + var/old_assoc_value //EXPERIMENTAL - Keep old associated value while modifying key, if any if(is_normal_list) if (assoc) variable = L[assoc_key] @@ -202,9 +198,9 @@ GLOBAL_PROTECT(VVpixelmovement) default = vv_get_class(objectvar, variable) - to_chat(src, "Variable appears to be [uppertext(default)].") + to_chat(src, "Variable appears to be [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 +216,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 @@ -250,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]") @@ -262,7 +258,6 @@ GLOBAL_PROTECT(VVpixelmovement) for(var/V in varsvars) new_var = replacetext(new_var,"\[[V]]","[O.vars[V]]") - if(is_normal_list) if(assoc) L[assoc_key] = new_var @@ -272,7 +267,7 @@ GLOBAL_PROTECT(VVpixelmovement) 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]") @@ -300,7 +295,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 @@ -325,11 +320,11 @@ GLOBAL_PROTECT(VVpixelmovement) var/default = vv_get_class(variable, var_value, O) 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 [uppertext(default)].") + to_chat(src, "Variable appears to be [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 = "" @@ -344,7 +339,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) @@ -391,7 +386,7 @@ 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) log_world("### VarEdit by [key_name(src)]: [O.type] [variable]=[var_value] => [var_new]") diff --git a/code/modules/admin/view_variables/nobody_wants_to_learn_matrix_math.dm b/code/modules/admin/view_variables/nobody_wants_to_learn_matrix_math.dm new file mode 100644 index 00000000000..625057051fe --- /dev/null +++ b/code/modules/admin/view_variables/nobody_wants_to_learn_matrix_math.dm @@ -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 filterrific, '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/ui_state(mob/user) + return ADMIN_STATE(R_VAREDIT) + +/datum/nobody_wants_to_learn_matrix_math/on_ui_close(mob/user, datum/tgui/ui, embedded) + qdel(src) + +/datum/nobody_wants_to_learn_matrix_math/ui_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/ui_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/ui_act(action, list/params, datum/tgui/ui, datum/ui_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.ui_interact(mob) diff --git a/code/modules/admin/view_variables/topic.dm b/code/modules/admin/view_variables/topic.dm index 1454199bead..f03198a45dc 100644 --- a/code/modules/admin/view_variables/topic.dm +++ b/code/modules/admin/view_variables/topic.dm @@ -1,33 +1,51 @@ //DO NOT ADD MORE TO THIS FILE. //Use vv_do_topic() for datums! /client/proc/view_var_Topic(href, href_list, hsrc) - if( (usr.client != src) || !src.holder || !holder.CheckAdminHref(href, href_list)) + if(!check_rights_for(src, R_VAREDIT) || !holder.CheckAdminHref(href, href_list)) return var/target = GET_VV_TARGET vv_do_basic(target, href_list, href) - if(istype(target, /datum)) + 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 - - var/mob/M = locate(href_list["rename"]) + var/mob/M = locate(href_list["rename"]) in GLOB.mob_list if(!istype(M)) - to_chat(usr, "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(input(usr,"What would you like to name this mob?","Input a name",M.real_name) as text|null, 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( !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"] + vv_update_display(M, "name", new_name) + vv_update_display(M, "real_name", M.real_name || "No real name") + + else if(href_list["rotatedatum"]) + + var/atom/A = locate(href_list["rotatedatum"]) + if(!istype(A)) + to_chat(usr, "This can only be done to instances of type /atom", confidential = TRUE) + return + + switch(href_list["rotatedir"]) + if("right") + A.setDir(turn(A.dir, -45)) + if("left") + A.setDir(turn(A.dir, 45)) + vv_update_display(A, "dir", dir2text(A.dir)) else if(href_list["varnameedit"] && href_list["datumedit"]) if(!check_rights(R_VAREDIT)) return @@ -39,48 +57,6 @@ 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(usr, "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(usr, "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(usr, "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)) return - - var/mob/M = locate(href_list["give_spell"]) - if(!istype(M)) - to_chat(usr, "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)) return @@ -93,71 +69,6 @@ src.admin_give_modifier(M) href_list["datumrefresh"] = href_list["give_modifier"] - else if(href_list["give_disease2"]) - if(!check_rights(R_ADMIN|R_FUN)) return - - var/mob/M = locate(href_list["give_disease2"]) - if(!istype(M)) - to_chat(usr, "This can only be used on instances of type /mob") - return - - src.give_disease2(M) - href_list["datumrefresh"] = href_list["give_spell"] - - else if(href_list["godmode"]) - if(!check_rights(R_REJUVINATE)) return - - var/mob/M = locate(href_list["godmode"]) - if(!istype(M)) - to_chat(usr, "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(usr, "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(usr, "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)) return - - var/mob/M = locate(href_list["drop_everything"]) - if(!istype(M)) - to_chat(usr, "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(usr, "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["make_skeleton"]) if(!check_rights(R_FUN)) return @@ -169,95 +80,6 @@ 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(usr, "This can only be used on instances of type /obj") - return - - var/action_type = alert(usr, "Strict type ([O.type]) or type and all subtypes?","Type Selection", "Strict type","Type and subtypes","Cancel") - if(action_type == "Cancel" || !action_type) - return - - if(alert(usr, "Are you really sure you want to delete all objects of type [O.type]?","Delete All?", "Yes","No") != "Yes") - return - - if(alert(usr, "Second confirmation required. Delete?","REALLY?", "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) - if(!i) - to_chat(usr, "No objects of this type exist") - return - log_admin("[key_name(usr)] deleted all objects of type [O_type] ([i] objects deleted)") - message_admins("[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) - if(!i) - to_chat(usr, "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("[key_name(usr)] deleted all objects of type or subtype of [O_type] ([i] objects deleted)") - - else if(href_list["explode"]) - if(!check_rights(R_DEBUG|R_FUN)) return - - var/atom/A = locate(href_list["explode"]) - if(!isobj(A) && !ismob(A) && !isturf(A)) - to_chat(usr, "This can only be done to instances of type /obj, /mob and /turf") - return - - src.cmd_admin_explosion(A) - href_list["datumrefresh"] = href_list["explode"] - - else if(href_list["emp"]) - if(!check_rights(R_DEBUG|R_FUN)) return - - var/atom/A = locate(href_list["emp"]) - if(!isobj(A) && !ismob(A) && !isturf(A)) - to_chat(usr, "This can only be done to instances of type /obj, /mob and /turf") - return - - src.cmd_admin_emp(A) - href_list["datumrefresh"] = href_list["emp"] - - else if(href_list["mark_object"]) - if(!check_rights(0)) return - - var/datum/D = locate(href_list["mark_object"]) - if(!istype(D)) - to_chat(usr, "This can only be done to instances of type /datum") - return - - src.holder.marked_datum = D - href_list["datumrefresh"] = href_list["mark_object"] - - else if(href_list["rotatedatum"]) - if(!check_rights(0)) return - - var/atom/A = locate(href_list["rotatedatum"]) - if(!istype(A)) - to_chat(usr, "This can only be done to instances of type /atom") - return - - switch(href_list["rotatedir"]) - if("right") A.setDir(turn(A.dir, -45)) - if("left") A.setDir(turn(A.dir, 45)) - href_list["datumrefresh"] = href_list["rotatedatum"] - else if(href_list["makemonkey"]) if(!check_rights(R_SPAWN)) return @@ -485,32 +307,51 @@ 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 GLOB.mob_list + if(!istype(L)) + return var/Text = href_list["adjustDamage"] - var/amount = input(usr, "Deal how much damage to mob? (Negative values here heal)","Adjust [Text]loss",0) as num + var/amount = input("Deal how much damage to mob? (Negative values here heal)","Adjust [Text]loss",0) as num|null - if(!L) - to_chat(usr, "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") amount > 0? L.take_overall_damage(brute = amount) : L.heal_overall_damage(brute = -amount) - if("fire") amount > 0? L.take_overall_damage(burn = amount) : L.heal_overall_damage(burn = -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() else - to_chat(usr, "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("[key_name(usr)] dealt [amount] amount of [Text] damage to [L]") - href_list["datumrefresh"] = href_list["mobToDamage"] + 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, "[log_msg]") + vv_update_display(L, Text, "[newamt]") else if(href_list["expose"]) if(!check_rights(R_ADMIN, FALSE)) @@ -535,7 +376,8 @@ to_chat(C, "[is_under_stealthmin() ? "an Administrator" : "[usr.client.key]"] has granted you access to view a View Variables window") C.debug_variables(thing) + //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) diff --git a/code/modules/admin/view_variables/topic_basic.dm b/code/modules/admin/view_variables/topic_basic.dm index 98a5b3f999c..0811e2c8453 100644 --- a/code/modules/admin/view_variables/topic_basic.dm +++ b/code/modules/admin/view_variables/topic_basic.dm @@ -21,6 +21,7 @@ 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]) @@ -34,51 +35,95 @@ if (!C) return if(!target) - to_chat(usr, "The object you tried to expose to [C] no longer exists (nulled or hard-deled)") + 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 VV window") + message_admins("[key_name_admin(usr)] Showed [key_name_admin(C)] a VV window") log_admin("Admin [key_name(usr)] Showed [key_name(C)] a VV window of a [target]") - to_chat(C, "[is_under_stealthmin() ? "an Administrator" : "[usr.client.key]"] has granted you access to view a View Variables window") + to_chat(C, "[is_under_stealthmin() ? "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(src)) // show the turf that took its place - usr.client.debug_variables(src) + if (isturf(target)) // show the turf that took its place + usr.client.debug_variables(target) return - if(href_list[VV_HK_VIEW_APPEARANCE]) - var/appearance/A = locate(href_list[VV_HK_VIEW_APPEARANCE]) - if(!A || !IS_APPEARANCE(A)) - to_chat(usr, SPAN_WARNING("Invalid ref: [href_list[VV_HK_VIEW_APPEARANCE]]")) - return - usr.client.debug_variables(A) + if(href_list[VV_HK_MARK]) usr.client.mark_datum(target) if(href_list[VV_HK_ADDCOMPONENT]) if(!check_rights(NONE)) return var/list/names = list() - var/list/componentsubtypes = subtypesof(/datum/component) + var/list/componentsubtypes = sortList(subtypesof(/datum/component), GLOBAL_PROC_REF(cmp_typepaths_asc)) + names += "---Components---" names += componentsubtypes - names += subtypesof(/datum/element) - var/result = tgui_input_list(usr, "Choose a component/element to add", "better know what ur fuckin doin pal", names) - if(!usr || !result || result == "---Components---" || result == "---Elements---") + 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!") + to_chat(usr, "That thing doesn't exist anymore!", confidential = TRUE) return + var/list/lst = get_callproc_args() if(!lst) return - lst.Insert(1, result) + var/datumname = "error" + lst.Insert(1, result) if(result in componentsubtypes) datumname = "component" target._AddComponent(lst) else datumname = "element" target._AddElement(lst) - log_admin("[key_name(usr)] has added [result] [datumname] to [key_name(src)].") - message_admins("[key_name_admin(usr)] has added [result] [datumname] to [target] ([ADMIN_VV(target)]).") + 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_CALLPROC]) usr.client.callproc_datum(target) diff --git a/code/modules/admin/view_variables/topic_list.dm b/code/modules/admin/view_variables/topic_list.dm index 349d9da698a..c5dece8139f 100644 --- a/code/modules/admin/view_variables/topic_list.dm +++ b/code/modules/admin/view_variables/topic_list.dm @@ -9,7 +9,7 @@ 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 = alert("Do you want to remove item number [target_index] from list?", "Confirm", "Yes", "No") + 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) @@ -30,7 +30,7 @@ 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. + 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.len = value["value"] log_world("### ListVarEdit by [src]: /list len: [target.len]") diff --git a/code/modules/admin/view_variables/view_variables.dm b/code/modules/admin/view_variables/view_variables.dm index a08f7d7b6ab..555d19355c4 100644 --- a/code/modules/admin/view_variables/view_variables.dm +++ b/code/modules/admin/view_variables/view_variables.dm @@ -1,44 +1,87 @@ -// todo: refactor number.. 4? -// thise is all snowflakey. -/client/proc/debug_variables(datum/D in world) +#define ICON_STATE_CHECKED 1 /// this dmi is checked. We don't check this one anymore. +#define ICON_STATE_NULL 2 /// this dmi has null-named icon_state, allowing it to show a sprite on vv editor. + +/client/proc/debug_variables(datum/thing in world) set category = "Debug" 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) //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, "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/vtype - var/type - var/refid = REF(D) - var/ref = ref(D) - var/list/header - var/title = "#unkw" + SSassets.send_asset_pack(usr, /datum/asset_pack/simple/vv) + + 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 + + var/title = "" + var/refid = REF(thing) + var/icon/sprite + var/hash + + var/type = islist ? /list : thing.type + var/no_icon = FALSE + + if(isatom(thing)) + sprite = get_flat_icon(thing) + if(!sprite) + no_icon = TRUE + + 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) + + var/sprite_text + if(sprite) + hash = md5(sprite) + src << browse_rsc(sprite, "vv[hash].png") + sprite_text = no_icon ? "\[NO ICON\]" : "" + + title = "[thing] ([REF(thing)]) = [type]" + var/formatted_type = replacetext("[type]", "/", "/") + + var/list/header = islist ? list("/list") : thing.vv_get_header() + + var/ref_line = "@[copytext(refid, 2, -1)]" // get rid of the brackets, add a @ prefix for copy pasting in asay + + var/marked_line + if(holder && holder.marked_datum && holder.marked_datum == thing) + marked_line = VV_MSG_MARKED + 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/list/dropdownoptions - // welcome to yanderedev - // but i assure you this is necessary unless we switch(typeid). - // vv refactor #4 when? - if(isdatum(D)) - vtype = VVING_A_DATUM - type = D.type - header = D.vv_get_header() - if(refid == ref) - title = "[D] ([ref]) = [type]" - else - title = "[D] ([refid]/[ref]) = [type]" - dropdownoptions = D.vv_get_dropdown() - dropdownoptions += D.get_view_variables_options_legacy() - header += D.get_view_variables_header_legacy() - else if(islist(D)) - vtype = VVING_A_LIST - type = /list - header = list("/list [ref]") - title = "/list [ref]" + if (islist) dropdownoptions = list( "---", "Add Item" = VV_HREF_TARGETREF_INTERNAL(refid, VV_HK_LIST_ADD), @@ -53,89 +96,38 @@ var/name = dropdownoptions[i] var/link = dropdownoptions[name] dropdownoptions[i] = "" - else if(IS_APPEARANCE(D)) - vtype = VVING_A_APPEARANCE - type = /appearance - header = list("virtual appearance [ref]") - title = "virtual appearance [ref]" - dropdownoptions = list() else - to_chat(usr, "Invalid vtype.") - return - - var/icon/sprite - var/hash - - var/no_icon = FALSE - - if(istype(D, /atom)) - sprite = get_flat_icon(D) - if(sprite) - hash = md5(sprite) - src << browse_rsc(sprite, "vv[hash].png") - else - no_icon = TRUE - - var/formatted_type = replacetext("[type]", "/", "/") - - var/sprite_text - if(sprite) - sprite_text = no_icon? "\[NO ICON\]" : "" - - var/marked_line - if(holder && holder.marked_datum && holder.marked_datum == D) - marked_line = VV_MSG_MARKED - var/varedited_line - if(vtype == VVING_A_DATUM && (D.datum_flags & DF_VAR_EDITED)) - varedited_line = VV_MSG_EDITED - var/deleted_line - if(vtype == VVING_A_DATUM && D.gc_destroyed) - deleted_line = VV_MSG_DELETED + dropdownoptions = thing.vv_get_dropdown() var/list/names = list() - var/list/variable_html = list() - switch(vtype) - if(VVING_A_DATUM) - for(var/V in D.vars) - names += V - if(VVING_A_LIST) - if(VVING_A_APPEARANCE) - for(var/V in global._appearance_var_list) - names += V - sleep(1) - switch(vtype) - if(VVING_A_DATUM) - names = sortList(names) - for(var/V in names) - if(D.can_vv_get(V)) - variable_html += D.vv_get_var(V, TRUE) - if(VVING_A_LIST) - 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, L) - if(VVING_A_APPEARANCE) - // lol, lmao - for(var/V in names) - variable_html += __appearance_v_debug(D, V) + if(!islist) + for(var/varname in thing.vars) + names += varname + sleep(1 TICKS) + + 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/datum/asset_pack/simple/vv/asset = SSassets.resolve_asset_pack(/datum/asset_pack/simple/vv) var/html = {" + [title] - +