#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. ADMIN_VERB_AND_CONTEXT_MENU(debug_variables, (R_DEBUG|R_SERVER|R_ADMIN|R_SPAWN|R_FUN|R_EVENT), "View Variables", "View the variables of a datum.", "Debug.Investigate", datum/thing in world) user.debug_variables(thing) // This is kept as a separate proc because admins are able to show VV to non-admins /client/proc/debug_variables(datum/thing in world) set category = "Debug.Investigate" set name = "View Variables" //set src in world var/static/cookieoffset = rand(1, 9999) //to force cookies to reset after the round. if(!usr.client || !check_rights_for(usr.client, R_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(!thing) return var/dark = usr.client.prefs ? usr.client.prefs.read_preference(/datum/preference/toggle/holder/vv_dark) : TRUE var/use_gfi = usr.client.prefs ? usr.client.prefs.read_preference(/datum/preference/toggle/holder/vv_gfi) : TRUE var/datum/asset/asset_cache_datum = get_asset_datum(/datum/asset/simple/vv) asset_cache_datum.send(usr) 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 var/cord_line if(isatom(thing)) var/atom/AT = thing cord_line = "x:[AT.x] y:[AT.y] z:[AT.z] " if(use_gfi) sprite = getFlatIcon(thing) if(!sprite) no_icon = TRUE else if(AT.icon && AT.icon_state) sprite = new /icon(AT.icon, AT.icon_state) else no_icon = TRUE else if(isimage(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/tagged_line if(holder && LAZYFIND(holder.tagged_datums, thing)) var/tag_index = LAZYFIND(holder.tagged_datums, thing) tagged_line = VV_MSG_TAGGED(tag_index) var/varedited_line if(!islist && (thing.datum_flags & DF_VAR_EDITED)) varedited_line = VV_MSG_EDITED var/deleted_line if(!islist && thing.gc_destroyed) deleted_line = VV_MSG_DELETED var/list/dropdownoptions if (islist) dropdownoptions = list( "---", "Add Item" = VV_HREF_TARGETREF_INTERNAL(refid, VV_HK_LIST_ADD), "Remove Nulls" = VV_HREF_TARGETREF_INTERNAL(refid, VV_HK_LIST_ERASE_NULLS), "Remove Dupes" = VV_HREF_TARGETREF_INTERNAL(refid, VV_HK_LIST_ERASE_DUPES), "Set len" = VV_HREF_TARGETREF_INTERNAL(refid, VV_HK_LIST_SET_LENGTH), "Shuffle" = VV_HREF_TARGETREF_INTERNAL(refid, VV_HK_LIST_SHUFFLE), "Show VV To Player" = VV_HREF_TARGETREF_INTERNAL(refid, VV_HK_EXPOSE), "---" ) for(var/i in 1 to length(dropdownoptions)) var/name = dropdownoptions[i] var/link = dropdownoptions[name] dropdownoptions[i] = "" else dropdownoptions = thing.vv_get_dropdown() var/list/names = list() if(!islist) for(var/varname in thing.vars) names += varname sleep(1 TICKS) var/ui_scale = prefs?.read_preference(/datum/preference/toggle/ui_scale) var/list/variable_html = list() if(islist) var/list/list_value = thing for(var/i in 1 to list_value.len) var/key = list_value[i] var/value if(IS_NORMAL_LIST(list_value) && IS_VALID_ASSOC_KEY(key)) value = list_value[key] variable_html += debug_variable(i, value, 0, list_value) else names = sortList(names) for(var/varname in names) if(thing.can_vv_get(varname)) variable_html += thing.vv_get_var(varname) var/html = {" [title] [!ui_scale && window_scaling ? "" : ""]
[sprite_text]
[header.Join()]
[formatted_type]
[ref_line] [marked_line] [tagged_line] [varedited_line] [deleted_line]
[cord_line]
Refresh

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

Search:

    [variable_html.Join()]
"} var/size_string = "size=475x650"; if(ui_scale && window_scaling) size_string = "size=[475 * window_scaling]x[650 * window_scaling]" src << browse(html, "window=variables[refid];[size_string]") /client/proc/vv_update_display(datum/thing, span, content) src << output("[span]:[content]", "variables[REF(thing)].browser:replace_span") #undef ICON_STATE_CHECKED #undef ICON_STATE_NULL