From df319dea276696ccfd8e8c61fe36f26f0b8ab86e Mon Sep 17 00:00:00 2001 From: EvilDragonfiend <87972842+EvilDragonfiend@users.noreply.github.com> Date: Thu, 21 Nov 2024 14:31:16 +0900 Subject: [PATCH] Port VV expansion from Upstream Bee --- code/__DEFINES/_helpers.dm | 5 + code/__DEFINES/is_helpers.dm | 9 + code/__DEFINES/keybinding.dm | 1 + code/__DEFINES/typeids.dm | 4 +- code/__DEFINES/vv.dm | 16 ++ code/__HELPERS/_lists.dm | 15 +- code/_globalvars/lists/vv.dm | 17 ++ code/_onclick/click.dm | 12 + code/controllers/globals.dm | 6 + code/datums/datumvars.dm | 17 +- code/datums/keybinding/admin.dm | 13 ++ code/datums/weakrefs.dm | 16 ++ code/game/atoms.dm | 5 + code/modules/admin/admin_verbs.dm | 2 + code/modules/admin/callproc/callproc.dm | 2 +- code/modules/admin/holder2.dm | 3 + code/modules/admin/tag.dm | 108 +++++++++ code/modules/admin/topic.dm | 29 +++ .../view_variables/color_matrix_editor.dm | 129 +++++++++++ .../admin/view_variables/debug_variables.dm | 209 +++++++++++------- .../admin/view_variables/get_variables.dm | 88 +++++++- .../modules/admin/view_variables/tag_datum.dm | 18 ++ code/modules/admin/view_variables/topic.dm | 5 +- .../admin/view_variables/topic_basic.dm | 2 + .../admin/view_variables/view_variables.dm | 90 ++++---- icons/misc/colortest.dmi | Bin 0 -> 352 bytes nsv13.dme | 3 + .../tgui/interfaces/ColorMatrixEditor.js | 68 ++++++ 28 files changed, 752 insertions(+), 140 deletions(-) create mode 100644 code/_globalvars/lists/vv.dm create mode 100644 code/modules/admin/tag.dm create mode 100644 code/modules/admin/view_variables/color_matrix_editor.dm create mode 100644 code/modules/admin/view_variables/tag_datum.dm create mode 100644 icons/misc/colortest.dmi create mode 100644 tgui/packages/tgui/interfaces/ColorMatrixEditor.js diff --git a/code/__DEFINES/_helpers.dm b/code/__DEFINES/_helpers.dm index 22ca001ae4e..5fc95acb1af 100644 --- a/code/__DEFINES/_helpers.dm +++ b/code/__DEFINES/_helpers.dm @@ -7,3 +7,8 @@ //Returns an integer given a hex input, supports negative values "-ff" //skips preceding invalid characters #define hex2num(X) text2num(X, 16) + +// 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 b04cbd356e3..03391cbdf63 100644 --- a/code/__DEFINES/is_helpers.dm +++ b/code/__DEFINES/is_helpers.dm @@ -13,6 +13,15 @@ #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) + // simple check whether or not a player is a guest using their key #define IS_GUEST_KEY(key) (findtextEx(key, "Guest-", 1, 7)) diff --git a/code/__DEFINES/keybinding.dm b/code/__DEFINES/keybinding.dm index 602660074ac..6994ab4a9a4 100644 --- a/code/__DEFINES/keybinding.dm +++ b/code/__DEFINES/keybinding.dm @@ -11,6 +11,7 @@ #define COMSIG_KB_ADMIN_AGHOST_DOWN "keybinding_admin_aghost_down" #define COMSIG_KB_ADMIN_PLAYERPANEL_DOWN "keybinding_admin_playerpanelnew_down" #define COMSIG_KB_ADMIN_INVISIMINTOGGLE_DOWN "keybinding_admin_invisimintoggle_down" +#define COMSIG_KB_ADMIN_VIEWTAGS_DOWN "keybinding_admin_viewtags_down" //Carbon #define COMSIG_KB_CARBON_TOGGLETHROWMODE_DOWN "keybinding_carbon_togglethrowmode_down" diff --git a/code/__DEFINES/typeids.dm b/code/__DEFINES/typeids.dm index 275f7719f07..16a71266bec 100644 --- a/code/__DEFINES/typeids.dm +++ b/code/__DEFINES/typeids.dm @@ -3,6 +3,6 @@ #define TYPEID_NORMAL_LIST "f" //helper macros #define GET_TYPEID(ref) ( ( (length(ref) <= 10) ? "TYPEID_NULL" : copytext(ref, 4, -7) ) ) +// Only allowed raw ref, since this is for lists explicitly and they will get no use from it +// Also it tends to be used in a hot context so let's be nice yes? #define IS_NORMAL_LIST(L) (GET_TYPEID("\ref[L]") == TYPEID_NORMAL_LIST) - - diff --git a/code/__DEFINES/vv.dm b/code/__DEFINES/vv.dm index 4938ca5e772..a82fb540270 100644 --- a/code/__DEFINES/vv.dm +++ b/code/__DEFINES/vv.dm @@ -2,6 +2,8 @@ #define VV_TEXT "Text" #define VV_MESSAGE "Mutiline Text" #define VV_ICON "Icon" +#define VV_COLOR "Color" +#define VV_COLOR_MATRIX "Color Matrix" #define VV_ATOM_REFERENCE "Atom Reference" #define VV_DATUM_REFERENCE "Datum Reference" #define VV_MOB_REFERENCE "Mob Reference" @@ -16,13 +18,17 @@ #define VV_NEW_TYPE "New Custom Typepath" #define VV_NEW_LIST "New List" #define VV_NULL "NULL" +#define VV_INFINITY "Infinity" #define VV_RESTORE_DEFAULT "Restore to Default" #define VV_MARKED_DATUM "Marked Datum" +#define VV_TAGGED_DATUM "Tagged 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_TAGGED(num) "
Tagged Datum #[num]" #define VV_MSG_EDITED "
Var Edited" #define VV_MSG_DELETED "
Deleted" @@ -73,12 +79,16 @@ #define VV_HK_EXPOSE "expose" #define VV_HK_CALLPROC "proc_call" #define VV_HK_MARK "mark" +#define VV_HK_TAG "tag" #define VV_HK_ADDCOMPONENT "addcomponent" #define VV_HK_MODIFY_TRAITS "modtraits" #ifdef REFERENCE_TRACKING #define VV_HK_VIEW_REFERENCES "viewreferences" #endif +// /datum/weakref +#define VV_HK_WEAKREF_RESOLVE "weakref_resolve" + // /atom #define VV_HK_MODIFY_TRANSFORM "atom_transform" #define VV_HK_MODIFY_GREYSCALE "modify_greyscale" @@ -87,6 +97,7 @@ #define VV_HK_TRIGGER_EXPLOSION "explode" #define VV_HK_AUTO_RENAME "auto_rename" #define VV_HK_EDIT_FILTERS "edit_filters" +#define VV_HK_EDIT_COLOR_MATRIX "edit_color_matrix" #define VV_HK_ADD_AI "add_ai" // /datum/gas_mixture @@ -143,3 +154,8 @@ // paintings #define VV_HK_REMOVE_PAINTING "remove_painting" + +// 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.dm b/code/__HELPERS/_lists.dm index 001912a2b1d..d080c8f088d 100644 --- a/code/__HELPERS/_lists.dm +++ b/code/__HELPERS/_lists.dm @@ -9,6 +9,15 @@ * Misc */ +// 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)) + +// Lazylist macros #define LAZYINITLIST(L) if (!L) { L = list(); } #define UNSETEMPTY(L) if (L && !length(L)) L = null #define ASSOC_UNSETEMPTY(L, K) if (!length(L[K])) L -= K; //NSV13 @@ -251,8 +260,8 @@ var/list/result = new if(skiprep) for(var/e in first) - if(!(e in result) && !(e in second)) - result += e + if(!(e in result) && !(e in second))f + UNTYPED_LIST_ADD(result, e) else result = first - second return result @@ -685,4 +694,4 @@ . = list() for(var/i in L) if(condition.Invoke(i)) - . |= i + . |= LIST_VALUE_WRAP_LISTS(i) diff --git a/code/_globalvars/lists/vv.dm b/code/_globalvars/lists/vv.dm new file mode 100644 index 00000000000..2f14bd240de --- /dev/null +++ b/code/_globalvars/lists/vv.dm @@ -0,0 +1,17 @@ +// 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 + +GLOBAL_LIST_INIT(color_vars, list("color")) diff --git a/code/_onclick/click.dm b/code/_onclick/click.dm index d186b39abfd..88232ecd152 100644 --- a/code/_onclick/click.dm +++ b/code/_onclick/click.dm @@ -86,6 +86,9 @@ CtrlShiftClickOn(A) return if(modifiers["middle"]) + if(modifiers["ctrl"]) + CtrlMiddleClickOn(A) // basically for vv tag datum + return MiddleClickOn(A) return if(modifiers["shift"]) @@ -344,6 +347,15 @@ H.changeNext_move(CLICK_CD_MELEE) else ..() + +/mob/proc/CtrlMiddleClickOn(atom/A) + // specifically made for admin feature. + if(check_rights_for(client, R_ADMIN)) + client.toggle_tag_datum(A) + return + A.CtrlClick(src) // this assumes you did CtrlClick instead of MiddleClick + return + /* Alt click Unused except for AI diff --git a/code/controllers/globals.dm b/code/controllers/globals.dm index 1e393f61fa5..b05d74eabf0 100644 --- a/code/controllers/globals.dm +++ b/code/controllers/globals.dm @@ -43,6 +43,12 @@ GLOBAL_REAL(GLOB, /datum/controller/global_vars) return FALSE return ..() +/datum/controller/global_vars/vv_get_var(var_name) + switch(var_name) + if (NAMEOF(src, vars)) + return debug_variable(var_name, list(), 0, src) + return debug_variable(var_name, vars[var_name], 0, src, display_flags = VV_ALWAYS_CONTRACT_LIST) + /datum/controller/global_vars/can_vv_get(var_name) if(var_name == "gvars_datum_protected_varlist" || var_name == "gvars_datum_in_built_vars") return FALSE diff --git a/code/datums/datumvars.dm b/code/datums/datumvars.dm index f9d39be51b9..0707320767c 100644 --- a/code/datums/datumvars.dm +++ b/code/datums/datumvars.dm @@ -20,21 +20,28 @@ /datum/proc/can_vv_mark() return TRUE -//please call . = ..() first and append to the result, that way parent items are always at the top and child items are further down -//add separaters by doing . += "---" +/** + * Gets all the dropdown options in the vv menu. + * When overriding, make sure to call . = ..() first and appent to the result, that way parent items are always at the top and child items are further down. + * Add seperators by doing VV_DROPDOWN_OPTION("", "---") + */ /datum/proc/vv_get_dropdown() + SHOULD_CALL_PARENT(TRUE) . = list() VV_DROPDOWN_OPTION("", "---") VV_DROPDOWN_OPTION(VV_HK_CALLPROC, "Call Proc") VV_DROPDOWN_OPTION(VV_HK_MARK, "Mark Object") + VV_DROPDOWN_OPTION(VV_HK_TAG, "Tag Datum") VV_DROPDOWN_OPTION(VV_HK_DELETE, "Delete") VV_DROPDOWN_OPTION(VV_HK_EXPOSE, "Show VV To Player") VV_DROPDOWN_OPTION(VV_HK_ADDCOMPONENT, "Add 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 incase 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. diff --git a/code/datums/keybinding/admin.dm b/code/datums/keybinding/admin.dm index 4a7c000d9b3..03ae8943807 100644 --- a/code/datums/keybinding/admin.dm +++ b/code/datums/keybinding/admin.dm @@ -98,6 +98,19 @@ user.invisimin() return TRUE +/datum/keybinding/admin/view_tags + key = "F9" + name = "view_tags" + full_name = "View Tags" + description = "Open the View-Tags menu" + keybind_signal = COMSIG_KB_ADMIN_VIEWTAGS_DOWN + +/datum/keybinding/admin/view_tags/down(client/user) + . = ..() + if(.) + return + user.holder?.display_tags() + return TRUE /datum/keybinding/admin/dead_say key = "F10" diff --git a/code/datums/weakrefs.dm b/code/datums/weakrefs.dm index c243f35f343..089055e4aa5 100644 --- a/code/datums/weakrefs.dm +++ b/code/datums/weakrefs.dm @@ -28,3 +28,19 @@ var/datum/D = locate(reference) return (!QDELETED(D) && D.weak_reference == src) ? D : null +/datum/weakref/vv_get_dropdown() + . = ..() + VV_DROPDOWN_OPTION(VV_HK_WEAKREF_RESOLVE, "Go to reference") + +/datum/weakref/vv_do_topic(list/href_list) + . = ..() + + if(!.) + return + + if(href_list[VV_HK_WEAKREF_RESOLVE]) + if(!check_rights(NONE)) + return + var/datum/R = resolve() + if(R) + usr.client.debug_variables(R) diff --git a/code/game/atoms.dm b/code/game/atoms.dm index a9bf421feb8..78251c3d28e 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -1117,6 +1117,7 @@ VV_DROPDOWN_OPTION(VV_HK_TRIGGER_EMP, "EMP Pulse") 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_ADD_AI, "Add AI controller") if(greyscale_colors) VV_DROPDOWN_OPTION(VV_HK_MODIFY_GREYSCALE, "Modify greyscale colors") @@ -1211,6 +1212,10 @@ var/client/C = usr.client C?.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) + /atom/vv_get_header() . = ..() var/refid = REF(src) diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm index b6aedb6184e..2d331e35aa5 100644 --- a/code/modules/admin/admin_verbs.dm +++ b/code/modules/admin/admin_verbs.dm @@ -19,6 +19,7 @@ GLOBAL_PROTECT(admin_verbs_default) /client/proc/cmd_admin_pm_panel, /*admin-pm list*/ /client/proc/stop_sounds, /client/proc/mark_datum_mapview, + /client/proc/tag_datum_mapview, /client/proc/requests, /client/proc/fax_manager ) @@ -83,6 +84,7 @@ GLOBAL_PROTECT(admin_verbs_admin) /client/proc/battle_royale, /client/proc/delete_book, /client/proc/cmd_admin_send_pda_msg, + /datum/admins/proc/display_tags, /client/proc/changeranks, //NSV13 - verb to change rank structure /client/proc/system_manager, //Nsv13 - Fleet + starsystem management /client/proc/instance_overmap_menu, //Nsv13 - Midround ship creation. diff --git a/code/modules/admin/callproc/callproc.dm b/code/modules/admin/callproc/callproc.dm index b06241e919a..8a585584161 100644 --- a/code/modules/admin/callproc/callproc.dm +++ b/code/modules/admin/callproc/callproc.dm @@ -172,7 +172,7 @@ GLOBAL_PROTECT(LastAdminCalledProc) if(named_arg) named_args[named_arg] = value["value"] else - . += value["value"] + . += LIST_VALUE_WRAP_LISTS(value["value"]) if(LAZYLEN(named_args)) . += named_args diff --git a/code/modules/admin/holder2.dm b/code/modules/admin/holder2.dm index 694b60c13d5..45a905b8550 100644 --- a/code/modules/admin/holder2.dm +++ b/code/modules/admin/holder2.dm @@ -33,6 +33,9 @@ GLOBAL_PROTECT(href_token) var/datum/filter_editor/filteriffic + /// A lazylist of tagged datums, for quick reference with the View Tags verb + var/list/tagged_datums + /datum/admins/New(datum/admin_rank/R, ckey, force_active = FALSE, protected) if(IsAdminAdvancedProcCall()) var/msg = " has tried to elevate permissions!" diff --git a/code/modules/admin/tag.dm b/code/modules/admin/tag.dm new file mode 100644 index 00000000000..3c72607366c --- /dev/null +++ b/code/modules/admin/tag.dm @@ -0,0 +1,108 @@ +/** + * Inserts the target_datum into [/datum/admins/var/tagged_datums], for later reference. + * + * Arguments: + * * target_datum - The datum you want to create a tag for + */ +/datum/admins/proc/add_tagged_datum(datum/target_datum) + if(LAZYFIND(tagged_datums, target_datum)) + to_chat(owner, "[target_datum] is already tagged!") + return + + LAZYADD(tagged_datums, target_datum) + RegisterSignal(target_datum, COMSIG_PARENT_QDELETING, PROC_REF(handle_tagged_del), override = TRUE) + to_chat(owner, "[target_datum] has been tagged.") + +/// Get ahead of the curve with deleting +/datum/admins/proc/handle_tagged_del(datum/source) + SIGNAL_HANDLER + + if(owner) + to_chat(owner, "Tagged datum [source] ([source.type]) has been deleted.") + remove_tagged_datum(source, silent = TRUE) + +/** + * Attempts to remove the specified datum from [/datum/admins/var/tagged_datums] if it exists + * + * Arguments: + * * target_datum - The datum you want to remove from the tagged_datums list + * * silent - If TRUE, won't print messages to the owner's chat + */ +/datum/admins/proc/remove_tagged_datum(datum/target_datum, silent=FALSE) + if(!istype(target_datum)) + return + + if(LAZYFIND(tagged_datums, target_datum)) + LAZYREMOVE(tagged_datums, target_datum) + if(!silent) + to_chat(owner, "[target_datum] has been untagged.") + else if(!silent) + to_chat(owner, "[target_datum] was not already tagged.") + +/// Quick define for readability +#define TAG_DEL(X) "(UNTAG)" +#define TAG_MARK(X) "(MARK)" +#define TAG_SIMPLE_HEALTH(X) "Health: [X.health]" +#define TAG_CARBON_HEALTH(X) "Health: [X.health] (\ + [X.getBruteLoss()] \ + [X.getFireLoss()] \ + [X.getToxLoss()] \ + [X.getOxyLoss()]\ + [X.getCloneLoss() ? " [X.getCloneLoss()]" : ""])" + +/// Display all of the tagged datums +/datum/admins/proc/display_tags() + set category = "Admin.Game" + set name = "View Tags" + + if (!istype(src, /datum/admins)) + src = usr.client.holder + if (!istype(src, /datum/admins)) + to_chat(usr, "Error: you are not an admin!") + return + + var/index = 0 + var/list/dat = list("
Tag Menu

") + + dat += "
Refresh
" + if(LAZYLEN(tagged_datums)) + for(var/datum/iter_datum as anything in tagged_datums) + index++ + var/specific_info + + if(isnull(iter_datum)) + dat += "\t[index]: Null reference - Check runtime logs!" + stack_trace("Null datum found in tagged datum menu! User: [usr]") + continue + else if(iscarbon(iter_datum)) + var/mob/living/carbon/resolved_carbon = iter_datum + specific_info = "[TAG_CARBON_HEALTH(resolved_carbon)] | [AREACOORD(resolved_carbon)] [ADMIN_PP(iter_datum)] [ADMIN_FLW(iter_datum)]" + else if(isliving(iter_datum)) + var/mob/living/resolved_living = iter_datum + specific_info = "[TAG_SIMPLE_HEALTH(resolved_living)] | [AREACOORD(resolved_living)] [ADMIN_PP(iter_datum)] [ADMIN_FLW(iter_datum)]" + else if(ismob(iter_datum)) + var/atom/resolved_atom = iter_datum // needed for ADMIN_JMP + specific_info = "[AREACOORD(resolved_atom)] [ADMIN_PP(iter_datum)] [ADMIN_FLW(iter_datum)]" + else if(ismovable(iter_datum)) + var/atom/resolved_atom = iter_datum // needed for ADMIN_JMP + specific_info = "[AREACOORD(resolved_atom)] [ADMIN_FLW(iter_datum)]" + else if(isatom(iter_datum)) + var/atom/resolved_atom = iter_datum // needed for ADMIN_JMP + specific_info = "[AREACOORD(resolved_atom)] [ADMIN_JMP(resolved_atom)]" + else if(istype(iter_datum, /datum/controller/subsystem)) + var/datum/controller/subsystem/resolved_subsystem = iter_datum + specific_info = "[resolved_subsystem.stat_entry()]" + // else, it's just a /datum + + dat += "\t[index]: [iter_datum] | [specific_info] | [ADMIN_VV(iter_datum)]| [TAG_DEL(iter_datum)] | [iter_datum == marked_datum ? "Marked" : TAG_MARK(iter_datum)] " + dat += "\t([iter_datum.type])" + else + dat += "No datums tagged :(" + + dat = dat.Join("
") + usr << browse(dat, "window=tag;size=800x480") + +#undef TAG_DEL +#undef TAG_MARK +#undef TAG_SIMPLE_HEALTH +#undef TAG_CARBON_HEALTH diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm index 907f29f1fdf..821c230a1f6 100644 --- a/code/modules/admin/topic.dm +++ b/code/modules/admin/topic.dm @@ -2157,6 +2157,35 @@ return GLOB.interviews.ui_interact(usr) + else if(href_list["tag_datum"]) + if(!check_rights(R_ADMIN)) + return + var/datum/datum_to_tag = locate(href_list["tag_datum"]) + if(!datum_to_tag) + return + return add_tagged_datum(datum_to_tag) + + else if(href_list["del_tag"]) + if(!check_rights(R_ADMIN)) + return + var/datum/datum_to_remove = locate(href_list["del_tag"]) + if(!datum_to_remove) + return + return remove_tagged_datum(datum_to_remove) + + else if(href_list["show_tags"]) + if(!check_rights(R_ADMIN)) + return + return display_tags() + + else if(href_list["mark_datum"]) + if(!check_rights(R_ADMIN)) + return + var/datum/datum_to_mark = locate(href_list["mark_datum"]) + if(!datum_to_mark) + return + return usr.client?.mark_datum(datum_to_mark) + /datum/admins/proc/HandleCMode() if(!check_rights(R_ADMIN)) return diff --git a/code/modules/admin/view_variables/color_matrix_editor.dm b/code/modules/admin/view_variables/color_matrix_editor.dm new file mode 100644 index 00000000000..1f1634a284b --- /dev/null +++ b/code/modules/admin/view_variables/color_matrix_editor.dm @@ -0,0 +1,129 @@ +INITIALIZE_IMMEDIATE(/atom/movable/screen/color_matrix_proxy_view) + +/atom/movable/screen/color_matrix_proxy_view + name = "color_matrix_proxy_view" + del_on_map_removal = FALSE + layer = GAME_PLANE + plane = GAME_PLANE + + var/list/plane_masters = list() + + /// The client that is watching this view + var/client/client + +/atom/movable/screen/color_matrix_proxy_view/Initialize(mapload) + . = ..() + + assigned_map = "color_matrix_proxy_[REF(src)]" + set_position(1, 1) + +/atom/movable/screen/color_matrix_proxy_view/Destroy() + for (var/plane_master in plane_masters) + client?.screen -= plane_master + qdel(plane_master) + + client?.clear_map(assigned_map) + + client = null + plane_masters = null + + return ..() + +/atom/movable/screen/color_matrix_proxy_view/proc/register_to_client(client/client) + QDEL_LIST(plane_masters) + + src.client = client + + if (!client) + return + + for (var/plane_master_type in subtypesof(/atom/movable/screen/plane_master) - /atom/movable/screen/plane_master/blackness) + var/atom/movable/screen/plane_master/plane_master = new plane_master_type() + plane_master.screen_loc = "[assigned_map]:CENTER" + client?.screen |= plane_master + + plane_masters += plane_master + + client?.register_map_obj(src) + +/datum/color_matrix_editor + var/client/owner + var/datum/weakref/target + var/atom/movable/screen/color_matrix_proxy_view/proxy_view + var/list/current_color + var/closed + +/datum/color_matrix_editor/New(user, atom/_target = null) + owner = CLIENT_FROM_VAR(user) + if(islist(_target?.color)) + current_color = _target.color + else if(istext(_target?.color)) + current_color = color_hex2color_matrix(_target.color) + else + current_color = color_matrix_identity() + proxy_view = new + if(_target) + target = WEAKREF(_target) + proxy_view.appearance = image(_target) + else + proxy_view.appearance = image('icons/misc/colortest.dmi', "colors") + + proxy_view.color = current_color + proxy_view.register_to_client(owner) + +/datum/color_matrix_editor/Destroy(force, ...) + QDEL_NULL(proxy_view) + return ..() + +/datum/color_matrix_editor/ui_state(mob/user) + return GLOB.admin_state + +/datum/color_matrix_editor/ui_static_data(mob/user) + var/list/data = list() + data["mapRef"] = proxy_view.assigned_map + + return data + +/datum/color_matrix_editor/ui_data(mob/user) + var/list/data = list() + data["currentColor"] = current_color + + return data + +/datum/color_matrix_editor/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "ColorMatrixEditor") + ui.open() + +/datum/color_matrix_editor/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) + . = ..() + if(.) + return + switch(action) + if("transition_color") + current_color = params["color"] + animate(proxy_view, time = 4, color = current_color) + if("confirm") + on_confirm() + SStgui.close_uis(src) + +/datum/color_matrix_editor/ui_close(mob/user) + . = ..() + closed = TRUE + +/datum/color_matrix_editor/proc/on_confirm() + var/atom/target_atom = target?.resolve() + if(istype(target_atom)) + target_atom.add_atom_colour(current_color, ADMIN_COLOUR_PRIORITY) + +/datum/color_matrix_editor/proc/wait() + while(!closed) + stoplag(1) + +/client/proc/open_color_matrix_editor(atom/in_atom) + var/datum/color_matrix_editor/editor = new /datum/color_matrix_editor(src, in_atom) + editor.ui_interact(mob) + editor.wait() + . = editor.current_color + qdel(editor) diff --git a/code/modules/admin/view_variables/debug_variables.dm b/code/modules/admin/view_variables/debug_variables.dm index 0ef5615f043..1f1634a284b 100644 --- a/code/modules/admin/view_variables/debug_variables.dm +++ b/code/modules/admin/view_variables/debug_variables.dm @@ -1,88 +1,129 @@ -#define VV_HTML_ENCODE(thing) ( sanitize ? html_encode(thing) : thing ) -/// Get displayed variable in VV variable list -/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/index = name - if (value) - name = D[name] //name is really the index until this line - else - value = D[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)]) " - 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)]) " +INITIALIZE_IMMEDIATE(/atom/movable/screen/color_matrix_proxy_view) + +/atom/movable/screen/color_matrix_proxy_view + name = "color_matrix_proxy_view" + del_on_map_removal = FALSE + layer = GAME_PLANE + plane = GAME_PLANE + + var/list/plane_masters = list() + + /// The client that is watching this view + var/client/client + +/atom/movable/screen/color_matrix_proxy_view/Initialize(mapload) + . = ..() + + assigned_map = "color_matrix_proxy_[REF(src)]" + set_position(1, 1) + +/atom/movable/screen/color_matrix_proxy_view/Destroy() + for (var/plane_master in plane_masters) + client?.screen -= plane_master + qdel(plane_master) + + client?.clear_map(assigned_map) + + client = null + plane_masters = null + + return ..() + +/atom/movable/screen/color_matrix_proxy_view/proc/register_to_client(client/client) + QDEL_LIST(plane_masters) + + src.client = client + + if (!client) + return + + for (var/plane_master_type in subtypesof(/atom/movable/screen/plane_master) - /atom/movable/screen/plane_master/blackness) + var/atom/movable/screen/plane_master/plane_master = new plane_master_type() + plane_master.screen_loc = "[assigned_map]:CENTER" + client?.screen |= plane_master + + plane_masters += plane_master + + client?.register_map_obj(src) + +/datum/color_matrix_editor + var/client/owner + var/datum/weakref/target + var/atom/movable/screen/color_matrix_proxy_view/proxy_view + var/list/current_color + var/closed + +/datum/color_matrix_editor/New(user, atom/_target = null) + owner = CLIENT_FROM_VAR(user) + if(islist(_target?.color)) + current_color = _target.color + else if(istext(_target?.color)) + current_color = color_hex2color_matrix(_target.color) else - header = "
  • " - - var/item - if (isnull(value)) - item = "[VV_HTML_ENCODE(name)] = null" - - else if (istext(value)) - item = "[VV_HTML_ENCODE(name)] = \"[VV_HTML_ENCODE(value)]\"" - - else if (isicon(value)) - #ifdef VARSICON - var/icon/I = 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]) " - #else - item = "[VV_HTML_ENCODE(name)] = /icon ([value])" - #endif - - else if (isfile(value)) - item = "[VV_HTML_ENCODE(name)] = '[value]'" - - else if(istype(value,/matrix)) // Needs to be before datum - var/matrix/M = value - item = {"[VV_HTML_ENCODE(name)] = -
      - - - - - - -
    [M.a][M.d]0
    [M.b][M.e]0
    [M.c][M.f]1
     
    "} //TODO link to modify_transform wrapper for all matrices - 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]" - - else if (islist(value)) - var/list/L = value - var/list/items = list() - - if (L.len > 0 && !(name == "underlays" || name == "overlays" || L.len > (IS_NORMAL_LIST(L) ? VV_NORMAL_LIST_NO_EXPAND_THRESHOLD : VV_SPECIAL_LIST_NO_EXPAND_THRESHOLD))) - for (var/i in 1 to L.len) - var/key = L[i] - var/val - if (IS_NORMAL_LIST(L) && !isnum_safe(key)) - val = L[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])" - - else if (name in GLOB.bitfields) - var/list/flags = list() - for (var/i in GLOB.bitfields[name]) - if (value & GLOB.bitfields[name][i]) - flags += i - item = "[VV_HTML_ENCODE(name)] = [VV_HTML_ENCODE(jointext(flags, ", "))]" + current_color = color_matrix_identity() + proxy_view = new + if(_target) + target = WEAKREF(_target) + proxy_view.appearance = image(_target) else - item = "[VV_HTML_ENCODE(name)] = [VV_HTML_ENCODE(value)]" + proxy_view.appearance = image('icons/misc/colortest.dmi', "colors") + + proxy_view.color = current_color + proxy_view.register_to_client(owner) + +/datum/color_matrix_editor/Destroy(force, ...) + QDEL_NULL(proxy_view) + return ..() + +/datum/color_matrix_editor/ui_state(mob/user) + return GLOB.admin_state + +/datum/color_matrix_editor/ui_static_data(mob/user) + var/list/data = list() + data["mapRef"] = proxy_view.assigned_map + + return data + +/datum/color_matrix_editor/ui_data(mob/user) + var/list/data = list() + data["currentColor"] = current_color + + return data + +/datum/color_matrix_editor/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "ColorMatrixEditor") + ui.open() + +/datum/color_matrix_editor/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) + . = ..() + if(.) + return + switch(action) + if("transition_color") + current_color = params["color"] + animate(proxy_view, time = 4, color = current_color) + if("confirm") + on_confirm() + SStgui.close_uis(src) + +/datum/color_matrix_editor/ui_close(mob/user) + . = ..() + closed = TRUE + +/datum/color_matrix_editor/proc/on_confirm() + var/atom/target_atom = target?.resolve() + if(istype(target_atom)) + target_atom.add_atom_colour(current_color, ADMIN_COLOUR_PRIORITY) - return "[header][item]
  • " +/datum/color_matrix_editor/proc/wait() + while(!closed) + stoplag(1) -#undef VV_HTML_ENCODE +/client/proc/open_color_matrix_editor(atom/in_atom) + var/datum/color_matrix_editor/editor = new /datum/color_matrix_editor(src, in_atom) + editor.ui_interact(mob) + editor.wait() + . = editor.current_color + qdel(editor) diff --git a/code/modules/admin/view_variables/get_variables.dm b/code/modules/admin/view_variables/get_variables.dm index 45d3a823482..c59391371df 100644 --- a/code/modules/admin/view_variables/get_variables.dm +++ b/code/modules/admin/view_variables/get_variables.dm @@ -2,7 +2,7 @@ if(isnull(var_value)) . = VV_NULL - else if(isnum_safe(var_value)) + else if(isnum(var_value)) if(var_name in GLOB.bitfields) . = VV_BITFIELD else @@ -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,10 @@ . = VV_TYPE else if(islist(var_value)) - . = VV_LIST + if(var_name in GLOB.color_vars) + . = VV_COLOR_MATRIX + else + . = VV_LIST else if(isfile(var_value)) . = VV_FILE @@ -54,6 +62,8 @@ VV_TEXT, VV_MESSAGE, VV_ICON, + VV_COLOR, + VV_COLOR_MATRIX, VV_ATOM_REFERENCE, VV_DATUM_REFERENCE, VV_MOB_REFERENCE, @@ -67,9 +77,11 @@ VV_NEW_TYPE, VV_NEW_LIST, VV_NULL, + VV_INFINITY, VV_RESTORE_DEFAULT, VV_TEXT_LOCATE, VV_PROCCALL_RETVAL, + VV_WEAKREF, ) var/markstring @@ -77,6 +89,15 @@ markstring = "[VV_MARKED_DATUM] (CURRENT: [(istype(holder) && istype(holder.marked_datum))? holder.marked_datum.type : "NULL"])" classes += markstring + var/list/tagstrings = new + if(!(VV_TAGGED_DATUM in restricted_classes) && holder && LAZYLEN(holder.tagged_datums)) + var/i = 0 + for(var/datum/iter_tagged_datum as anything in holder.tagged_datums) + i++ + var/new_tagstring = "[VV_TAGGED_DATUM] #[i]: [iter_tagged_datum.type])" + tagstrings[new_tagstring] = iter_tagged_datum + classes += new_tagstring + if(restricted_classes) classes -= restricted_classes @@ -87,6 +108,12 @@ if(holder && holder.marked_datum && .["class"] == markstring) .["class"] = VV_MARKED_DATUM + if(holder && tagstrings[.["class"]]) + var/datum/chosen_datum = tagstrings[.["class"]] + .["value"] = chosen_datum + .["class"] = VV_TAGGED_DATUM + + switch(.["class"]) if(VV_TEXT) .["value"] = input("Enter new text:", "Text", current_value) as null|text @@ -178,6 +205,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) @@ -202,10 +242,15 @@ .["class"] = null return + if(VV_TAGGED_DATUM) + if(.["value"] == null) + .["class"] = null + return + if(VV_PROCCALL_RETVAL) var/list/get_retval = list() callproc_blocking(get_retval) - .["value"] = get_retval[1] //should have been set in proccall! + .["value"] = get_retval[1] //should have been set in proccall! if(.["value"] == null) .["class"] = null return @@ -250,8 +295,23 @@ .["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_TEXT_LOCATE) var/datum/D @@ -261,11 +321,25 @@ break D = locate(ref) if(!D) - alert("Invalid ref!") + 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/tag_datum.dm b/code/modules/admin/view_variables/tag_datum.dm new file mode 100644 index 00000000000..3b611e3cdf9 --- /dev/null +++ b/code/modules/admin/view_variables/tag_datum.dm @@ -0,0 +1,18 @@ +/client/proc/tag_datum(datum/target_datum) + if(!holder || QDELETED(target_datum)) + return + holder.add_tagged_datum(target_datum) + +/client/proc/toggle_tag_datum(datum/target_datum) + if(!holder || !target_datum) + return + + if(LAZYFIND(holder.tagged_datums, target_datum)) + holder.remove_tagged_datum(target_datum) + else + holder.add_tagged_datum(target_datum) + +/client/proc/tag_datum_mapview(datum/target_datum as mob|obj|turf|area in view(view)) + set category = "Debug" + set name = "Tag Datum" + tag_datum(target_datum) diff --git a/code/modules/admin/view_variables/topic.dm b/code/modules/admin/view_variables/topic.dm index 9a0956174b0..f753221828c 100644 --- a/code/modules/admin/view_variables/topic.dm +++ b/code/modules/admin/view_variables/topic.dm @@ -11,7 +11,10 @@ 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) //Stuff below aren't in dropdowns/etc. diff --git a/code/modules/admin/view_variables/topic_basic.dm b/code/modules/admin/view_variables/topic_basic.dm index f1640a70f4c..74682142d0c 100644 --- a/code/modules/admin/view_variables/topic_basic.dm +++ b/code/modules/admin/view_variables/topic_basic.dm @@ -57,6 +57,8 @@ if(href_list[VV_HK_MARK] && check_rights(R_VAREDIT)) usr.client.mark_datum(target) + if(href_list[VV_HK_TAG]) + usr.client.tag_datum(target) if(href_list[VV_HK_ADDCOMPONENT]) if(!check_rights(R_VAREDIT)) diff --git a/code/modules/admin/view_variables/view_variables.dm b/code/modules/admin/view_variables/view_variables.dm index a48d1ee4296..103a5203b8e 100644 --- a/code/modules/admin/view_variables/view_variables.dm +++ b/code/modules/admin/view_variables/view_variables.dm @@ -1,52 +1,65 @@ -/client/proc/debug_variables(datum/D in world) +/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. + 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.") return - if(!D) + if(!thing) return var/datum/asset/asset_cache_datum = get_asset_datum(/datum/asset/simple/vv) asset_cache_datum.send(usr) - var/islist = islist(D) - if(!islist && !istype(D)) + var/islist = islist(thing) || (!isdatum(thing) && hascall(thing, "Cut")) // Some special lists dont count as lists, but can be detected by if they have list procs + if(!islist && !isdatum(thing)) return var/title = "" - var/refid = REF(D) + var/refid = REF(thing) var/icon/sprite var/hash - var/type = islist? /list : D.type + var/type = islist? /list : thing.type + var/no_icon = FALSE - if(istype(D, /atom)) - sprite = getFlatIcon(D) - hash = md5(icon2base64(sprite)) - if(hash) //Fixes VV shitting it's pants if the icon isn't valid - src << browse_rsc(sprite, "vv[hash].png") + if(isatom(thing)) + sprite = getFlatIcon(thing) + if(!sprite) + no_icon = TRUE - title = "[D] ([REF(D)]) = [type]" - var/formatted_type = replacetext("[type]", "/", "/") + else if(isimage(thing)) + var/image/image_object = thing + sprite = icon(image_object.icon, image_object.icon_state) var/sprite_text if(sprite) - sprite_text = "" - var/list/header = islist(D)? list("/list") : D.vv_get_header() + 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 == D) + if(holder && holder.marked_datum && holder.marked_datum == thing) marked_line = VV_MSG_MARKED + var/tagged_line + if(holder && LAZYFIND(holder.tagged_datums, thing)) + var/tag_index = LAZYFIND(holder.tagged_datums, thing) + tagged_line = VV_MSG_TAGGED(tag_index) var/varedited_line - if(!islist && (D.datum_flags & DF_VAR_EDITED)) + if(!islist && (thing.datum_flags & DF_VAR_EDITED)) varedited_line = VV_MSG_EDITED var/deleted_line - if(!islist && D.gc_destroyed) + if(!islist && thing.gc_destroyed) deleted_line = VV_MSG_DELETED var/list/dropdownoptions @@ -69,28 +82,29 @@ var/link = dropdownoptions[name] dropdownoptions[i] = "" else - dropdownoptions = D.vv_get_dropdown() + dropdownoptions = thing.vv_get_dropdown() var/list/names = list() if(!islist) - for(var/V in D.vars) - names += V - sleep(1) + for(var/varname in thing.vars) + names += varname + + sleep(1 TICKS) var/list/variable_html = list() if(islist) - var/list/L = D - for(var/i in 1 to L.len) - var/key = L[i] + 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(L) && IS_VALID_ASSOC_KEY(key)) - value = L[key] - variable_html += debug_variable(i, value, 0, L) + 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/V in names) - if(D.can_vv_get(V)) - variable_html += D.vv_get_var(V) + names = sort_list(names) + for(var/varname in names) + if(thing.can_vv_get(varname)) + variable_html += thing.vv_get_var(varname) var/html = {" @@ -117,8 +131,8 @@ var ca = document.cookie.split(';'); for(var i=0; i
    [formatted_type] +
    [ref_line] [marked_line] + [tagged_line] [varedited_line] [deleted_line]
    @@ -266,5 +282,5 @@ datumrefresh=[refid];[HrefToken()]'>Refresh "} src << browse(html, "window=variables[refid];size=475x650") -/client/proc/vv_update_display(datum/D, span, content) - src << output("[span]:[content]", "variables[REF(D)].browser:replace_span") +/client/proc/vv_update_display(datum/thing, span, content) + src << output("[span]:[content]", "variables[REF(thing)].browser:replace_span") diff --git a/icons/misc/colortest.dmi b/icons/misc/colortest.dmi new file mode 100644 index 0000000000000000000000000000000000000000..0f74685ebc24d90bc3227e01ec7cb9a06d785725 GIT binary patch literal 352 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=c~v11B`&GO$wiq3C7Jno3=9=> zRF7}uYETeiy>RopsQB&04!2?sakT$p_w-&UR1>uS{)IBX=E7NTxi&{sIX#?`pRr<_ z@<+9JWfL}6rM8kIzuH%?W|S&Aovx?j`6EO^%C>Xw4(&gA25Z^UHhy7@oh7yW_U>)r zK%3Wkx;TbZ%z1mmkn6C42p?6=yDxT%o>&amMexKRQDXe%te%A)LX%b|EiN z{A-IDkh~&%i-F;W+=G8Qb%&}CEG}k+XkcJifMn7=X0iYOAMRv=DrX4r&tL`y7SNmn a?-=Z-Zsv}B(s=|FmJFV*elF{r5}E)m#EDG+ literal 0 HcmV?d00001 diff --git a/nsv13.dme b/nsv13.dme index 2abd39ff698..c278efcfd3b 100644 --- a/nsv13.dme +++ b/nsv13.dme @@ -1493,6 +1493,7 @@ #include "code\modules\admin\sql_ban_system.dm" #include "code\modules\admin\sql_message_system.dm" #include "code\modules\admin\stickyban.dm" +#include "code\modules\admin\tag.dm" #include "code\modules\admin\team_panel.dm" #include "code\modules\admin\topic.dm" #include "code\modules\admin\whitelist.dm" @@ -1542,6 +1543,7 @@ #include "code\modules\admin\verbs\SDQL2\SDQL_2_parser.dm" #include "code\modules\admin\verbs\SDQL2\SDQL_2_wrappers.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_variables.dm" #include "code\modules\admin\view_variables\filterrific.dm" #include "code\modules\admin\view_variables\get_variables.dm" @@ -1549,6 +1551,7 @@ #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\reference_tracking.dm" +#include "code\modules\admin\view_variables\tag_datum.dm" #include "code\modules\admin\view_variables\topic.dm" #include "code\modules\admin\view_variables\topic_basic.dm" #include "code\modules\admin\view_variables\topic_list.dm" diff --git a/tgui/packages/tgui/interfaces/ColorMatrixEditor.js b/tgui/packages/tgui/interfaces/ColorMatrixEditor.js new file mode 100644 index 00000000000..4bf3883afc6 --- /dev/null +++ b/tgui/packages/tgui/interfaces/ColorMatrixEditor.js @@ -0,0 +1,68 @@ +import { useBackend } from '../backend'; +import { toFixed } from 'common/math'; +import { Box, Stack, Section, ByondUi, NumberInput, Button } from '../components'; +import { Window } from '../layouts'; + +export const ColorMatrixEditor = (props, context) => { + const { act, data } = useBackend(context); + const { mapRef, currentColor } = data; + const [[rr, rg, rb, ra], [gr, gg, gb, ga], [br, bg, bb, ba], [ar, ag, ab, aa], [cr, cg, cb, ca]] = currentColor; + const prefixes = ['r', 'g', 'b', 'a', 'c']; + return ( + + + + + + + +
    + + {[0, 1, 2, 3].map((col, key) => ( + + + {[0, 1, 2, 3, 4].map((row, key) => ( + + + {`${prefixes[row]}${prefixes[col]}:`} + + toFixed(value, 2)} + onDrag={(e, value) => { + let retColor = currentColor; + retColor[row * 4 + col] = value; + act('transition_color', { color: retColor }); + }} + /> + + ))} + + + ))} + +
    +
    + + + act('confirm')} /> + +
    +
    + + + +
    +
    +
    + ); +};