From e5a1515de1f41716eb20e079fa4d7282fd1a38b0 Mon Sep 17 00:00:00 2001 From: adamsong Date: Sun, 13 Mar 2022 06:22:11 -0500 Subject: [PATCH] Refactors VV (#13312) * Refactors VV * Copied more tg code * Fixes renameing by copying more tg code * Copies some code from yogs this time --- code/__DEFINES/vv.dm | 43 + code/datums/datumvars.dm | 1541 +---------------- code/game/atoms.dm | 109 +- code/game/atoms_movable.dm | 5 +- code/game/objects/objs.dm | 75 +- code/game/objects/structures/artstuff.dm | 23 +- code/modules/admin/verbs/hiddenprints.dm | 30 + .../admin/view_variables/debug_variables.dm | 93 + .../admin/view_variables/mark_datum.dm | 13 + .../{verbs => view_variables}/massmodvar.dm | 0 .../modifyvariables.dm | 0 code/modules/admin/view_variables/topic.dm | 114 ++ .../admin/view_variables/topic_basic.dm | 54 + .../admin/view_variables/topic_list.dm | 43 + .../admin/view_variables/view_variables.dm | 375 ++++ code/modules/events/spacevine.dm | 17 +- code/modules/mob/living/carbon/carbon.dm | 116 +- code/modules/mob/living/carbon/human/human.dm | 65 +- code/modules/mob/living/living.dm | 16 + code/modules/mob/mob.dm | 76 +- yogstation.dme | 11 +- 21 files changed, 1235 insertions(+), 1584 deletions(-) create mode 100644 code/modules/admin/verbs/hiddenprints.dm create mode 100644 code/modules/admin/view_variables/debug_variables.dm create mode 100644 code/modules/admin/view_variables/mark_datum.dm rename code/modules/admin/{verbs => view_variables}/massmodvar.dm (100%) rename code/modules/admin/{verbs => view_variables}/modifyvariables.dm (100%) create mode 100644 code/modules/admin/view_variables/topic.dm create mode 100644 code/modules/admin/view_variables/topic_basic.dm create mode 100644 code/modules/admin/view_variables/topic_list.dm create mode 100644 code/modules/admin/view_variables/view_variables.dm diff --git a/code/__DEFINES/vv.dm b/code/__DEFINES/vv.dm index f0e51ee0b223..303d090af3df 100644 --- a/code/__DEFINES/vv.dm +++ b/code/__DEFINES/vv.dm @@ -38,9 +38,12 @@ #define VV_TOPIC_LINK(datum, href_key, text) "text" //Helpers for vv_get_dropdown() #define VV_DROPDOWN_OPTION(href_key, name) . += "" +#define VV_DROPDOWN_SEPERATOR VV_DROPDOWN_OPTION("", "-----") + // VV HREF KEYS #define VV_HK_TARGET "target" #define VV_HK_VARNAME "targetvar" //name or index of var for 1 variable targetting hrefs. + // vv_do_list() keys #define VV_HK_LIST_ADD "listadd" #define VV_HK_LIST_EDIT "listedit" @@ -50,10 +53,12 @@ #define VV_HK_LIST_ERASE_DUPES "listdupes" #define VV_HK_LIST_SHUFFLE "listshuffle" #define VV_HK_LIST_SET_LENGTH "listlen" + // vv_do_basic() keys #define VV_HK_BASIC_EDIT "datumedit" #define VV_HK_BASIC_CHANGE "datumchange" #define VV_HK_BASIC_MASSEDIT "massedit" + // /datum #define VV_HK_DELETE "delete" #define VV_HK_EXPOSE "expose" @@ -69,6 +74,44 @@ #define VV_HK_TRIGGER_EXPLOSION "explode" #define VV_HK_AUTO_RENAME "auto_rename" #define VV_HK_RADIATE "radiate" +#define VV_HK_SHOW_HIDDENPRINTS "show_hiddenprints" // /obj #define VV_HK_OSAY "osay" +#define VV_HK_MASS_DEL_TYPE "mass_delete_type" +#define VV_HK_ARMOR_MOD "mod_obj_armor" + +// /obj/structure/sign/painting +#define VV_HK_REMOVE_PAINTING "delete_paint" + +// /mob +#define VV_HK_GIB "gib" +#define VV_HK_GIVE_SPELL "give_spell" +#define VV_HK_REMOVE_SPELL "remove_spell" +#define VV_HK_GIVE_DISEASE "give_disease" +#define VV_HK_GODMODE "godmode" +#define VV_HK_DROP_ALL "dropall" +#define VV_HK_REGEN_ICONS "regen_icons" +#define VV_HK_PLAYER_PANEL "player_panel" +#define VV_HK_BUILDMODE "buildmode" +#define VV_HK_DIRECT_CONTROL "direct_control" +#define VV_HK_OFFER_GHOSTS "offer_ghosts" +#define VV_HK_SET_AFK_TIMER "set_afk_timer" + +// /mob/living/carbon/human +#define VV_HK_SET_SPECIES "set_species" +#define VV_HK_PURRBATION "toggle_purrbation" +#define VV_HK_COPY_OUTFIT "copy_outfit" +#define VV_HK_MOD_QUIRKS "mod_quirks" + +// misc +#define VV_HK_SPACEVINE_PURGE "spacevine_purge" + +// /mob/living/carbon +#define VV_HK_MAKE_AI "aiify" +#define VV_HK_MODIFY_BODYPART "mod_bodypart" +#define VV_HK_MODIFY_ORGANS "organs_modify" +#define VV_HK_HALLUCINATION "force_hallucinate" +#define VV_HK_MARTIAL_ART "give_martial_art" +#define VV_HK_GIVE_TRAUMA "give_trauma" +#define VV_HK_CURE_TRAUMA "cure_trauma" diff --git a/code/datums/datumvars.dm b/code/datums/datumvars.dm index 5b9f2d5b4d42..2f272cf9dce3 100644 --- a/code/datums/datumvars.dm +++ b/code/datums/datumvars.dm @@ -25,1531 +25,24 @@ //add separaters by doing . += "---" /datum/proc/vv_get_dropdown() . = list() - . += "---" - .["Call Proc"] = "?_src_=vars;[HrefToken()];proc_call=[REF(src)]" - .["Mark Object"] = "?_src_=vars;[HrefToken()];mark_object=[REF(src)]" - .["Delete"] = "?_src_=vars;[HrefToken()];delete=[REF(src)]" - .["Show VV To Player"] = "?_src_=vars;[HrefToken(TRUE)];expose=[REF(src)]" - + VV_DROPDOWN_SEPERATOR + 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") /datum/proc/on_reagent_change(changetype) return - -/client/proc/debug_variables(datum/D in world) - set category = "Misc.Server 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) //The usr vs src abuse in this proc is intentional and must not be changed - to_chat(usr, span_danger("You need to be an administrator to access this.")) - return - - if(!D) - return - - var/islist = islist(D) - var/isappearance = isappearance(D) - if (!islist && !istype(D) && !isappearance) - return - - var/title = "" - var/refid = REF(D) - var/icon/sprite - var/hash - - var/type = /list - if (isappearance) - type = /image - else if (!islist) - type = D.type - - - - if(istype(D, /atom) || isappearance) - var/atom/AT = D - if(AT.icon && AT.icon_state) - sprite = new /icon(AT.icon, AT.icon_state) - hash = md5(AT.icon) - hash = md5(hash + AT.icon_state) - src << browse_rsc(sprite, "vv[hash].png") - - title = "[D] ([REF(D)]) = [type]" - var/formatted_type = replacetext("[type]", "/", "/") - - var/sprite_text - if(sprite) - sprite_text = "" - var/list/atomsnowflake = list() - - if(istype(D, /atom)) - var/atom/A = D - if(isliving(A)) - atomsnowflake += "[D]" - atomsnowflake += "
<< [dir2text(A.dir) || A.dir] >>" - var/mob/living/M = A - - atomsnowflake += {" -
[M.ckey || "No ckey"] / [M.real_name || "No real name"] -
- BRUTE:[M.getBruteLoss()] - FIRE:[M.getFireLoss()] - TOXIN:[M.getToxLoss()] - OXY:[M.getOxyLoss()] - CLONE:[M.getCloneLoss()] - BRAIN:[M.getOrganLoss(ORGAN_SLOT_BRAIN)] - STAMINA:[M.getStaminaLoss()] - - "} - else - atomsnowflake += "[D]" - atomsnowflake += "
<< [dir2text(A.dir) || A.dir] >>" - else if(!isappearance && ("name" in D.vars)) - atomsnowflake += "[D]" - else - atomsnowflake += "[formatted_type]" - formatted_type = null - - var/marked - if(holder && holder.marked_datum && holder.marked_datum == D) - marked = VV_MSG_MARKED - var/varedited_line = "" - if(!isappearance && !islist && (D.datum_flags & DF_VAR_EDITED)) - varedited_line = VV_MSG_EDITED - var/deleted_line - if(!isappearance && !islist && D.gc_destroyed) - deleted_line = VV_MSG_DELETED - - var/list/dropdownoptions = list() - if (islist) - dropdownoptions = list( - "---", - "Add Item" = "?_src_=vars;[HrefToken()];listadd=[refid]", - "Remove Nulls" = "?_src_=vars;[HrefToken()];listnulls=[refid]", - "Remove Dupes" = "?_src_=vars;[HrefToken()];listdupes=[refid]", - "Set len" = "?_src_=vars;[HrefToken()];listlen=[refid]", - "Shuffle" = "?_src_=vars;[HrefToken()];listshuffle=[refid]", - "Show VV To Player" = "?_src_=vars;[HrefToken()];expose=[refid]" - ) - else if (!isappearance) - dropdownoptions = D.vv_get_dropdown() - var/list/dropdownoptions_html = list() - - for (var/name in dropdownoptions) - var/link = dropdownoptions[name] - if (link) - dropdownoptions_html += "" - else - dropdownoptions_html += "" - - var/list/names = list() - if (!islist && !isappearance) - for (var/V in D.vars) - names += V - sleep(1)//For some reason, without this sleep, VVing will cause client to disconnect on certain objects. - - var/list/variable_html = list() - if (islist) - var/list/L = D - for (var/i in 1 to L.len) - var/key = L[i] - var/value - if (IS_NORMAL_LIST(L) && !isnum(key)) - value = L[key] - variable_html += debug_variable(i, value, 0, D) - else if(isappearance(D)) - variable_html += debug_variable("type", D:type, 0, D) - variable_html += debug_variable("name", D:name, 0, D) - variable_html += debug_variable("desc", D:desc, 0, D) - variable_html += debug_variable("suffix", D:suffix, 0, D) - variable_html += debug_variable("text", D:text, 0, D) - variable_html += debug_variable("icon", D:icon, 0, D) - variable_html += debug_variable("icon_state", D:icon_state, 0, D) - variable_html += debug_variable("visibility", D:visibility, 0, D) - variable_html += debug_variable("luminosity", D:luminosity, 0, D) - variable_html += debug_variable("opacity", D:opacity, 0, D) - variable_html += debug_variable("density", D:density, 0, D) - variable_html += debug_variable("verbs", D:verbs, 0, D) - variable_html += debug_variable("dir", D:dir, 0, D) - variable_html += debug_variable("gender", D:gender, 0, D) - variable_html += debug_variable("tag", D:tag, 0, D) - variable_html += debug_variable("overlays", D:overlays, 0, D) - variable_html += debug_variable("underlays", D:underlays, 0, D) - variable_html += debug_variable("layer", D:layer, 0, D) - variable_html += debug_variable("parent_type", D:parent_type, 0, D) - variable_html += debug_variable("mouse_over_pointer", D:mouse_over_pointer, 0, D) - variable_html += debug_variable("mouse_drag_pointer", D:mouse_drag_pointer, 0, D) - variable_html += debug_variable("mouse_drop_pointer", D:mouse_drop_pointer, 0, D) - variable_html += debug_variable("mouse_drop_zone", D:mouse_drop_zone, 0, D) - variable_html += debug_variable("animate_movement", D:animate_movement, 0, D) - variable_html += debug_variable("screen_loc", D:screen_loc, 0, D) - variable_html += debug_variable("infra_luminosity", D:infra_luminosity, 0, D) - variable_html += debug_variable("invisibility", D:invisibility, 0, D) - variable_html += debug_variable("mouse_opacity", D:mouse_opacity, 0, D) - variable_html += debug_variable("pixel_x", D:pixel_x, 0, D) - variable_html += debug_variable("pixel_y", D:pixel_y, 0, D) - variable_html += debug_variable("pixel_step_size", D:pixel_step_size, 0, D) - variable_html += debug_variable("pixel_z", D:pixel_z, 0, D) - variable_html += debug_variable("override", D:override, 0, D) - variable_html += debug_variable("glide_size", D:glide_size, 0, D) - variable_html += debug_variable("maptext", D:maptext, 0, D) - variable_html += debug_variable("maptext_width", D:maptext_width, 0, D) - variable_html += debug_variable("maptext_height", D:maptext_height, 0, D) - variable_html += debug_variable("transform", D:transform, 0, D) - variable_html += debug_variable("alpha", D:alpha, 0, D) - variable_html += debug_variable("color", D:color, 0, D) - variable_html += debug_variable("blend_mode", D:blend_mode, 0, D) - variable_html += debug_variable("appearance", D:appearance, 0, D) - variable_html += debug_variable("maptext_x", D:maptext_x, 0, D) - variable_html += debug_variable("maptext_y", D:maptext_y, 0, D) - variable_html += debug_variable("plane", D:plane, 0, D) - variable_html += debug_variable("appearance_flags", D:appearance_flags, 0, D) - variable_html += debug_variable("pixel_w", D:pixel_w, 0, D) - variable_html += debug_variable("render_source", D:render_source, 0, D) - variable_html += debug_variable("render_target", D:render_target, 0, D) - else - - names = sortList(names) - for (var/V in names) - if(D.can_vv_get(V)) - variable_html += D.vv_get_var(V) - - var/html = {" - - - - [title] - - - - -
- - - - - -
- - - - -
- [sprite_text] -
- [atomsnowflake.Join()] -
-
-
- [formatted_type] - [marked] - [varedited_line] - [deleted_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()] -
- - - -"} - 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") - - -#define VV_HTML_ENCODE(thing) ( sanitize ? html_encode(thing) : thing ) -/// Get displayed variable in VV variable list -/proc/debug_variable(name, value, level, datum/DA = null, sanitize = TRUE) - var/header - if(DA && !isappearance(DA)) - if (islist(DA)) - var/index = name - if (value) - name = DA[name] //name is really the index until this line - else - value = DA[name] - header = "
  • (E) (C) (-) " - else - header = "
  • (E) (C) (M) " - else - header = "
  • " - - var/item - if (isnull(value)) - item = "[VV_HTML_ENCODE(name)] = [span_value("null")]" - - else if (istext(value)) - item = "[VV_HTML_ENCODE(name)] = [span_value("\"[VV_HTML_ENCODE(value)]\"")]" - - else if (isicon(value)) - #ifdef VARSICON - var/icon/I = new/icon(value) - var/rnd = rand(1,10000) - var/rname = "tmp[REF(I)][rnd].png" - usr << browse_rsc(I, rname) - item = "[VV_HTML_ENCODE(name)] = ([span_value("[value]")]) " - #else - item = "[VV_HTML_ENCODE(name)] = /icon ([span_value("[value]")])" - #endif - - else if (isfile(value)) - item = "[VV_HTML_ENCODE(name)] = [span_value("'[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(isappearance(value)) - var/image/I = value - item = "[VV_HTML_ENCODE(name)] [REF(value)] = appearance([span_value("[I.icon]")], [span_value("\"[I.icon_state]\"")])" - - else if (istype(value, /datum)) - var/datum/D = value - if ("[D]" != "[D.type]") //if the thing as a name var, lets use it. - item = "[VV_HTML_ENCODE(name)] [REF(value)] = [D] [D.type]" - else - item = "[VV_HTML_ENCODE(name)] [REF(value)] = [D.type]" - - else if (islist(value)) - var/list/L = value - var/list/items = list() - - if (L.len > 0 && !(L.len > (IS_NORMAL_LIST(L) ? 50 : 150))) - for (var/i in 1 to L.len) - var/key = L[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 "" - val = key - key = i - - items += debug_variable(key, val, level + 1, sanitize = sanitize) - - item = "[VV_HTML_ENCODE(name)] = /list ([L.len])
      [items.Join()]
    " - 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, ", "))]" - else - item = "[VV_HTML_ENCODE(name)] = [span_value("[VV_HTML_ENCODE(value)]")]" - - return "[header][item]
  • " - -#undef VV_HTML_ENCODE - -/client/proc/view_var_Topic(href, href_list, hsrc) - if( (usr.client != src) || !src.holder || !holder.CheckAdminHref(href, href_list)) - return - if(href_list["Vars"]) - debug_variables(locate(href_list["Vars"])) - - else if(href_list["datumrefresh"]) - var/datum/DAT = locate(href_list["datumrefresh"]) - if(!DAT) //can't be an istype() because /client etc aren't datums - return - src.debug_variables(DAT) - - else if(href_list["mob_player_panel"]) - if(!check_rights(NONE)) - return - - var/mob/M = locate(href_list["mob_player_panel"]) in GLOB.mob_list - if(!istype(M)) - to_chat(usr, "This can only be used on instances of type /mob") - return - - src.holder.show_player_panel(M) - - else if(href_list["godmode"]) - if(!check_rights(R_ADMIN)) - return - - var/mob/M = locate(href_list["godmode"]) in GLOB.mob_list - if(!istype(M)) - to_chat(usr, "This can only be used on instances of type /mob") - return - - src.cmd_admin_godmode(M) - - else if(href_list["mark_object"]) - if(!check_rights(NONE)) - 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 - - if(holder.marked_datum) - vv_update_display(holder.marked_datum, "marked", "") - holder.marked_datum = D - vv_update_display(D, "marked", VV_MSG_MARKED) - - else if(href_list["proc_call"]) - if(!check_rights(NONE)) - return - - var/T = locate(href_list["proc_call"]) - - if(T) - callproc_datum(T) - - else if(href_list["delete"]) - if(!check_rights(R_DEBUG, 0)) - return - - var/datum/D = locate(href_list["delete"]) - if(!istype(D)) - to_chat(usr, "Unable to locate item!") - admin_delete(D) - if (isturf(D)) // show the turf that took its place - debug_variables(D) - - else if(href_list["osay"]) - if(!check_rights(R_FUN, 0)) - return - usr.client.object_say(locate(href_list["osay"])) - - else if(href_list["regenerateicons"]) - if(!check_rights(NONE)) - return - - var/mob/M = locate(href_list["regenerateicons"]) in GLOB.mob_list - if(!ismob(M)) - to_chat(usr, "This can only be done to instances of type /mob") - return - M.regenerate_icons() - else if(href_list["expose"]) - if(!check_rights(R_ADMIN, FALSE)) - return - var/thing = locate(href_list["expose"]) - if (!thing) - return - var/value = vv_get_value(VV_CLIENT) - if (value["class"] != VV_CLIENT) - return - var/client/C = value["value"] - if (!C) - return - var/prompt = alert("Do you want to grant [C] access to view this VV window? (they will not be able to edit or change anything nor open nested vv windows unless they themselves are an admin)", "Confirm", "Yes", "No") - if (prompt != "Yes" || !usr.client) - return - 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 [thing]") - to_chat(C, "[usr.client.holder.fakekey ? "an Administrator" : "[usr.client.key]"] has granted you access to view a View Variables window") - C.debug_variables(thing) - // yogs start - offer control can now be used by mods - else if(href_list["offer_control"]) - if(!check_rights(R_ADMIN)) - return - - var/mob/M = locate(href_list["offer_control"]) in GLOB.mob_list - if(!istype(M)) - to_chat(usr, "This can only be used on instances of type /mob") - return - offer_control(M) - // yogs end - - //~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_ADMIN)) - return - - 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") - 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) - vv_update_display(M, "name", new_name) - vv_update_display(M, "real_name", M.real_name || "No real name") - -//Needs +VAREDIT past this point - - - else if(check_rights(R_VAREDIT)) - - if(href_list["varnameedit"] && href_list["datumedit"]) - if(!check_rights(NONE)) - return - - var/datum/D = locate(href_list["datumedit"]) - if(!istype(D, /datum)) - to_chat(usr, "This can only be used on datums") - return - - if (!modify_variables(D, href_list["varnameedit"], 1)) - return - switch(href_list["varnameedit"]) - if("name") - vv_update_display(D, "name", "[D]") - if("dir") - var/atom/A = D - if(istype(A)) - vv_update_display(D, "dir", dir2text(A.dir) || A.dir) - if("ckey") - var/mob/living/L = D - if(istype(L)) - vv_update_display(D, "ckey", L.ckey || "No ckey") - if("real_name") - var/mob/living/L = D - if(istype(L)) - vv_update_display(D, "real_name", L.real_name || "No real name") - - else if(href_list["varnamechange"] && href_list["datumchange"]) - if(!check_rights(NONE)) - return - - var/D = locate(href_list["datumchange"]) - if(!istype(D, /datum)) - to_chat(usr, "This can only be used on datums") - return - - modify_variables(D, href_list["varnamechange"], 0) - - else if(href_list["varnamemass"] && href_list["datummass"]) - if(!check_rights(NONE)) - return - - var/datum/D = locate(href_list["datummass"]) - if(!istype(D)) - to_chat(usr, "This can only be used on instances of type /datum") - return - - cmd_mass_modify_object_variables(D, href_list["varnamemass"]) - - else if(href_list["listedit"] && href_list["index"]) - var/index = text2num(href_list["index"]) - if (!index) - return - - var/list/L = locate(href_list["listedit"]) - if (!istype(L)) - to_chat(usr, "This can only be used on instances of type /list") - return - - mod_list(L, null, "list", "contents", index, autodetect_class = TRUE) - - else if(href_list["listchange"] && href_list["index"]) - var/index = text2num(href_list["index"]) - if (!index) - return - - var/list/L = locate(href_list["listchange"]) - if (!istype(L)) - to_chat(usr, "This can only be used on instances of type /list") - return - - mod_list(L, null, "list", "contents", index, autodetect_class = FALSE) - - else if(href_list["listremove"] && href_list["index"]) - var/index = text2num(href_list["index"]) - if (!index) - return - - var/list/L = locate(href_list["listremove"]) - if (!istype(L)) - to_chat(usr, "This can only be used on instances of type /list") - return - - var/variable = L[index] - var/prompt = alert("Do you want to remove item number [index] from list?", "Confirm", "Yes", "No") - if (prompt != "Yes") - return - L.Cut(index, index+1) - log_world("### ListVarEdit by [src]: /list's contents: REMOVED=[html_encode("[variable]")]") - log_admin("[key_name(src)] modified list's contents: REMOVED=[variable]") - message_admins("[key_name_admin(src)] modified list's contents: REMOVED=[variable]") - - else if(href_list["listadd"]) - var/list/L = locate(href_list["listadd"]) - if (!istype(L)) - to_chat(usr, "This can only be used on instances of type /list") - return - - mod_list_add(L, null, "list", "contents") - - else if(href_list["listdupes"]) - var/list/L = locate(href_list["listdupes"]) - if (!istype(L)) - to_chat(usr, "This can only be used on instances of type /list") - return - - uniqueList_inplace(L) - log_world("### ListVarEdit by [src]: /list contents: CLEAR DUPES") - log_admin("[key_name(src)] modified list's contents: CLEAR DUPES") - message_admins("[key_name_admin(src)] modified list's contents: CLEAR DUPES") - - else if(href_list["listnulls"]) - var/list/L = locate(href_list["listnulls"]) - if (!istype(L)) - to_chat(usr, "This can only be used on instances of type /list") - return - - listclearnulls(L) - log_world("### ListVarEdit by [src]: /list contents: CLEAR NULLS") - log_admin("[key_name(src)] modified list's contents: CLEAR NULLS") - message_admins("[key_name_admin(src)] modified list's contents: CLEAR NULLS") - - else if(href_list["listlen"]) - var/list/L = locate(href_list["listlen"]) - if (!istype(L)) - to_chat(usr, "This can only be used on instances of type /list") - return - var/value = vv_get_value(VV_NUM) - if (value["class"] != VV_NUM) - return - - L.len = value["value"] - log_world("### ListVarEdit by [src]: /list len: [L.len]") - log_admin("[key_name(src)] modified list's len: [L.len]") - message_admins("[key_name_admin(src)] modified list's len: [L.len]") - - else if(href_list["listshuffle"]) - var/list/L = locate(href_list["listshuffle"]) - if (!istype(L)) - to_chat(usr, "This can only be used on instances of type /list") - return - - shuffle_inplace(L) - log_world("### ListVarEdit by [src]: /list contents: SHUFFLE") - log_admin("[key_name(src)] modified list's contents: SHUFFLE") - message_admins("[key_name_admin(src)] modified list's contents: SHUFFLE") - - else if(href_list["give_spell"]) - if(!check_rights(NONE)) - return - - var/mob/M = locate(href_list["give_spell"]) in GLOB.mob_list - if(!istype(M)) - to_chat(usr, "This can only be used on instances of type /mob") - return - - src.give_spell(M) - - else if(href_list["remove_spell"]) - if(!check_rights(NONE)) - return - - var/mob/M = locate(href_list["remove_spell"]) in GLOB.mob_list - if(!istype(M)) - to_chat(usr, "This can only be used on instances of type /mob") - return - - remove_spell(M) - - else if(href_list["give_disease"]) - if(!check_rights(NONE)) - return - - var/mob/M = locate(href_list["give_disease"]) in GLOB.mob_list - if(!istype(M)) - to_chat(usr, "This can only be used on instances of type /mob") - return - - src.give_disease(M) - - else if(href_list["gib"]) - if(!check_rights(R_FUN)) - return - - var/mob/M = locate(href_list["gib"]) in GLOB.mob_list - 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"]) in GLOB.mob_list - if(!istype(M)) - to_chat(usr, "This can only be used on instances of type /mob") - return - - togglebuildmode(M) - - else if(href_list["drop_everything"]) - if(!check_rights(NONE)) - return - - var/mob/M = locate(href_list["drop_everything"]) in GLOB.mob_list - 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(NONE)) - return - - var/mob/M = locate(href_list["direct_control"]) in GLOB.mob_list - 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) - - // yogs - offer control moved up - - else if(href_list["set_afk"]) - if(!check_rights(R_ADMIN)) - return - - var/mob/M = locate(href_list["set_afk"]) in GLOB.mob_list - if(!istype(M)) - to_chat(usr, "This can only be used on instances of type /mob") - return - - if(!M.mind) - to_chat(usr, "This cannot be used on mobs without a mind") - return - - var/timer = input("Input AFK length in minutes, 0 to cancel the current timer", text("Input")) as num|null - if(timer == null) // Explicit null check for cancel, rather than generic truthyness, so 0 is handled differently - return - - deltimer(M.mind.afk_verb_timer) - M.mind.afk_verb_used = FALSE - - if(!timer) - return - - M.mind.afk_verb_used = TRUE - M.mind.afk_verb_timer = addtimer(VARSET_CALLBACK(M.mind, afk_verb_used, FALSE), timer MINUTES, TIMER_STOPPABLE); - - - else if (href_list["modarmor"]) - if(!check_rights(NONE)) - return - - var/obj/O = locate(href_list["modarmor"]) - if(!istype(O)) - to_chat(usr, "This can only be used on instances of type /obj") - return - - var/list/pickerlist = list() - var/list/armorlist = O.armor.getList() - - for (var/i in armorlist) - pickerlist += list(list("value" = armorlist[i], "name" = i)) - - var/list/result = presentpicker(usr, "Modify armor", "Modify armor: [O]", Button1="Save", Button2 = "Cancel", Timeout=FALSE, inputtype = "text", values = pickerlist) - - if (islist(result)) - if (result["button"] == 2) // If the user pressed the cancel button - return - // text2num conveniently returns a null on invalid values - O.armor = O.armor.setRating(melee = text2num(result["values"]["melee"]),\ - bullet = text2num(result["values"]["bullet"]),\ - laser = text2num(result["values"]["laser"]),\ - energy = text2num(result["values"]["energy"]),\ - bomb = text2num(result["values"]["bomb"]),\ - bio = text2num(result["values"]["bio"]),\ - rad = text2num(result["values"]["rad"]),\ - fire = text2num(result["values"]["fire"]),\ - acid = text2num(result["values"]["acid"])) - log_admin("[key_name(usr)] modified the armor on [O] ([O.type]) to melee: [O.armor.melee], bullet: [O.armor.bullet], laser: [O.armor.laser], energy: [O.armor.energy], bomb: [O.armor.bomb], bio: [O.armor.bio], rad: [O.armor.rad], fire: [O.armor.fire], acid: [O.armor.acid]") - message_admins(span_notice("[key_name_admin(usr)] modified the armor on [O] ([O.type]) to melee: [O.armor.melee], bullet: [O.armor.bullet], laser: [O.armor.laser], energy: [O.armor.energy], bomb: [O.armor.bomb], bio: [O.armor.bio], rad: [O.armor.rad], fire: [O.armor.fire], acid: [O.armor.acid]")) - else - return - - 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("Strict type ([O.type]) or type and all subtypes?",,"Strict type","Type and subtypes","Cancel") - if(action_type == "Cancel" || !action_type) - return - - if(alert("Are you really sure you want to delete all objects of type [O.type]?",,"Yes","No") != "Yes") - return - - if(alert("Second confirmation required. Delete?",,"Yes","No") != "Yes") - return - - var/O_type = O.type - switch(action_type) - if("Strict type") - var/i = 0 - for(var/obj/Obj in world) - if(Obj.type == O_type) - i++ - qdel(Obj) - CHECK_TICK - if(!i) - to_chat(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) ")) - - else if(href_list["addreagent"]) - if(!check_rights(NONE)) - return - - var/atom/A = locate(href_list["addreagent"]) - - if(!A.reagents) - var/amount = input(usr, "Specify the reagent size of [A]", "Set Reagent Size", 50) as num - if(amount) - A.create_reagents(amount) - - if(A.reagents) - var/chosen_id - var/list/reagent_options = sortList(GLOB.chemical_reagents_list) - switch(alert(usr, "Choose a method.", "Add Reagents", "Enter ID", "Choose ID")) - if("Enter ID") - var/valid_id - while(!valid_id) - chosen_id = stripped_input(usr, "Enter the name of the reagent you want to add. (Case Sensitive!)") - if(!chosen_id) //Get me out of here! - break - for(var/ID in reagent_options) - var/datum/reagent/selected = reagent_options[ID] - if(selected?.name == chosen_id) //apparently I have to do this because the other method wasn't WORKING - valid_id = TRUE - chosen_id = ID - if(!valid_id) - to_chat(usr, span_warning("A reagent with that ID doesn't exist!")) - if("Choose ID") - chosen_id = input(usr, "Choose a reagent to add.", "Choose a reagent.") as null|anything in reagent_options - if(chosen_id) - var/amount = input(usr, "Choose the amount to add.", "Choose the amount.", A.reagents.maximum_volume) as num - if(amount) - A.reagents.add_reagent(chosen_id, amount) - log_admin("[key_name(usr)] has added [amount] units of [chosen_id] to \the [A]") - message_admins(span_notice("[key_name(usr)] has added [amount] units of [chosen_id] to \the [A]")) - - else if(href_list["explode"]) - if(!check_rights(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) - - else if(href_list["radiate"] && check_rights(R_FUN)) - var/atom/A = locate(href_list["radiate"]) - var/strength = input(usr, "Choose the radiation strength.", "Choose the strength.") as num|null - if(!isnull(strength)) - A.AddComponent(/datum/component/radioactive, strength, src) - - else if(href_list["emp"]) - if(!check_rights(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) - - else if(href_list["modtransform"]) - if(!check_rights(R_DEBUG)) - return - - var/atom/A = locate(href_list["modtransform"]) - if(!istype(A)) - to_chat(usr, "This can only be done to atoms.") - return - - var/result = input(usr, "Choose the transformation to apply","Transform Mod") as null|anything in list("Scale","Translate","Rotate") - var/matrix/M = A.transform - switch(result) - if("Scale") - var/x = input(usr, "Choose x mod","Transform Mod") as null|num - var/y = input(usr, "Choose y mod","Transform Mod") as null|num - if(!isnull(x) && !isnull(y)) - A.transform = M.Scale(x,y) - if("Translate") - var/x = input(usr, "Choose x mod","Transform Mod") as null|num - var/y = input(usr, "Choose y mod","Transform Mod") as null|num - if(!isnull(x) && !isnull(y)) - A.transform = M.Translate(x,y) - if("Rotate") - var/angle = input(usr, "Choose angle to rotate","Transform Mod") as null|num - if(!isnull(angle)) - A.transform = M.Turn(angle) - - else if(href_list["rotatedatum"]) - if(!check_rights(NONE)) - 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)) - vv_update_display(A, "dir", dir2text(A.dir)) - - else if(href_list["editorgans"]) - if(!check_rights(NONE)) - return - - var/mob/living/carbon/C = locate(href_list["editorgans"]) in GLOB.mob_list - if(!istype(C)) - to_chat(usr, "This can only be done to instances of type /mob/living/carbon") - return - - manipulate_organs(C) - - else if(href_list["givemartialart"]) - if(!check_rights(NONE)) - return - - var/mob/living/carbon/C = locate(href_list["givemartialart"]) in GLOB.carbon_list - if(!istype(C)) - to_chat(usr, "This can only be done to instances of type /mob/living/carbon") - return - - var/list/artpaths = subtypesof(/datum/martial_art) - var/list/artnames = list() - for(var/i in artpaths) - var/datum/martial_art/M = i - artnames[initial(M.name)] = M - - var/result = input(usr, "Choose the martial art to teach","JUDO CHOP") as null|anything in artnames - if(!usr) - return - if(QDELETED(C)) - to_chat(usr, "Mob doesn't exist anymore") - return - - if(result) - var/chosenart = artnames[result] - var/datum/martial_art/MA = new chosenart - MA.teach(C) - log_admin("[key_name(usr)] has taught [MA] to [key_name(C)].") - message_admins(span_notice("[key_name_admin(usr)] has taught [MA] to [key_name_admin(C)].")) - - else if(href_list["givetrauma"]) - if(!check_rights(NONE)) - return - - var/mob/living/carbon/C = locate(href_list["givetrauma"]) in GLOB.mob_list - if(!istype(C)) - to_chat(usr, "This can only be done to instances of type /mob/living/carbon") - return - - var/list/traumas = subtypesof(/datum/brain_trauma) - var/result = input(usr, "Choose the brain trauma to apply","Traumatize") as null|anything in traumas - if(!usr) - return - if(QDELETED(C)) - to_chat(usr, "Mob doesn't exist anymore") - return - - if(!result) - return - - var/datum/brain_trauma/BT = C.gain_trauma(result) - if(BT) - log_admin("[key_name(usr)] has traumatized [key_name(C)] with [BT.name]") - message_admins(span_notice("[key_name_admin(usr)] has traumatized [key_name_admin(C)] with [BT.name].")) - - else if(href_list["curetraumas"]) - if(!check_rights(NONE)) - return - - var/mob/living/carbon/C = locate(href_list["curetraumas"]) in GLOB.mob_list - if(!istype(C)) - to_chat(usr, "This can only be done to instances of type /mob/living/carbon") - return - - C.cure_all_traumas(TRAUMA_RESILIENCE_ABSOLUTE) - log_admin("[key_name(usr)] has cured all traumas from [key_name(C)].") - message_admins(span_notice("[key_name_admin(usr)] has cured all traumas from [key_name_admin(C)].")) - - else if(href_list["hallucinate"]) - if(!check_rights(NONE)) - return - - var/mob/living/carbon/C = locate(href_list["hallucinate"]) in GLOB.mob_list - if(!istype(C)) - to_chat(usr, "This can only be done to instances of type /mob/living/carbon") - return - - var/list/hallucinations = subtypesof(/datum/hallucination) - var/result = input(usr, "Choose the hallucination to apply","Send Hallucination") as null|anything in hallucinations - if(!usr) - return - if(QDELETED(C)) - to_chat(usr, "Mob doesn't exist anymore") - return - - if(result) - new result(C, TRUE) - - else if(href_list["makehuman"]) - if(!check_rights(R_SPAWN)) - return - - var/mob/living/carbon/monkey/Mo = locate(href_list["makehuman"]) in GLOB.mob_list - if(!istype(Mo)) - to_chat(usr, "This can only be done to instances of type /mob/living/carbon/monkey") - return - - if(alert("Confirm mob type change?",,"Transform","Cancel") != "Transform") - return - if(!Mo) - to_chat(usr, "Mob doesn't exist anymore") - return - holder.Topic(href, list("humanone"=href_list["makehuman"])) - - else if(href_list["makemonkey"]) - if(!check_rights(R_SPAWN)) - return - - var/mob/living/carbon/human/H = locate(href_list["makemonkey"]) in GLOB.mob_list - if(!istype(H)) - to_chat(usr, "This can only be done to instances of type /mob/living/carbon/human") - return - - if(alert("Confirm mob type change?",,"Transform","Cancel") != "Transform") - return - if(!H) - to_chat(usr, "Mob doesn't exist anymore") - return - holder.Topic(href, list("monkeyone"=href_list["makemonkey"])) - - else if(href_list["makerobot"]) - if(!check_rights(R_SPAWN)) - return - - var/mob/living/carbon/human/H = locate(href_list["makerobot"]) in GLOB.mob_list - if(!istype(H)) - to_chat(usr, "This can only be done to instances of type /mob/living/carbon/human") - return - - if(alert("Confirm mob type change?",,"Transform","Cancel") != "Transform") - return - if(!H) - to_chat(usr, "Mob doesn't exist anymore") - return - holder.Topic(href, list("makerobot"=href_list["makerobot"])) - - else if(href_list["makealien"]) - if(!check_rights(R_SPAWN)) - return - - var/mob/living/carbon/human/H = locate(href_list["makealien"]) in GLOB.mob_list - if(!istype(H)) - to_chat(usr, "This can only be done to instances of type /mob/living/carbon/human") - return - - if(alert("Confirm mob type change?",,"Transform","Cancel") != "Transform") - return - if(!H) - to_chat(usr, "Mob doesn't exist anymore") - return - holder.Topic(href, list("makealien"=href_list["makealien"])) - - else if(href_list["makeslime"]) - if(!check_rights(R_SPAWN)) - return - - var/mob/living/carbon/human/H = locate(href_list["makeslime"]) in GLOB.mob_list - if(!istype(H)) - to_chat(usr, "This can only be done to instances of type /mob/living/carbon/human") - return - - if(alert("Confirm mob type change?",,"Transform","Cancel") != "Transform") - return - if(!H) - to_chat(usr, "Mob doesn't exist anymore") - return - holder.Topic(href, list("makeslime"=href_list["makeslime"])) - - else if(href_list["makeai"]) - if(!check_rights(R_SPAWN)) - return - - var/mob/living/carbon/H = locate(href_list["makeai"]) in GLOB.mob_list - if(!istype(H)) - to_chat(usr, "This can only be done to instances of type /mob/living/carbon") - return - - if(alert("Confirm mob type change?",,"Transform","Cancel") != "Transform") - return - if(!H) - to_chat(usr, "Mob doesn't exist anymore") - return - holder.Topic(href, list("makeai"=href_list["makeai"])) - - else if(href_list["setspecies"]) - if(!check_rights(R_SPAWN)) - return - - var/mob/living/carbon/human/H = locate(href_list["setspecies"]) in GLOB.mob_list - if(!istype(H)) - to_chat(usr, "This can only be done to instances of type /mob/living/carbon/human") - return - - var/result = input(usr, "Please choose a new species","Species") as null|anything in GLOB.species_list - - if(!H) - to_chat(usr, "Mob doesn't exist anymore") - return - - if(result) - var/newtype = GLOB.species_list[result] - admin_ticket_log("[key_name(usr)] has modified the bodyparts of [H] to [result]") // yogs - Yog Tickets - H.set_species(newtype) - - else if(href_list["editbodypart"]) - if(!check_rights(R_SPAWN)) - return - - var/mob/living/carbon/C = locate(href_list["editbodypart"]) in GLOB.mob_list - if(!istype(C)) - to_chat(usr, "This can only be done to instances of type /mob/living/carbon") - return - - var/edit_action = input(usr, "What would you like to do?","Modify Body Part") as null|anything in list("add","remove", "augment") - if(!edit_action) - return - var/list/limb_list = list() - if(edit_action == "remove" || edit_action == "augment") - for(var/obj/item/bodypart/B in C.bodyparts) - limb_list += B.body_zone - if(edit_action == "remove") - limb_list -= BODY_ZONE_CHEST - else - limb_list = list(BODY_ZONE_HEAD, BODY_ZONE_L_ARM, BODY_ZONE_R_ARM, BODY_ZONE_L_LEG, BODY_ZONE_R_LEG) - for(var/obj/item/bodypart/B in C.bodyparts) - limb_list -= B.body_zone - - var/result = input(usr, "Please choose which body part to [edit_action]","[capitalize(edit_action)] Body Part") as null|anything in limb_list - - if(!C) - to_chat(usr, "Mob doesn't exist anymore") - return - - if(result) - var/obj/item/bodypart/BP = C.get_bodypart(result) - switch(edit_action) - if("remove") - if(BP) - BP.drop_limb() - else - to_chat(usr, "[C] doesn't have such bodypart.") - if("add") - if(BP) - to_chat(usr, "[C] already has such bodypart.") - else - if(!C.regenerate_limb(result)) - to_chat(usr, "[C] cannot have such bodypart.") - if("augment") - if(ishuman(C)) - if(BP) - BP.change_bodypart_status(BODYPART_ROBOTIC, TRUE, TRUE) - else - to_chat(usr, "[C] doesn't have such bodypart.") - else - to_chat(usr, "Only humans can be augmented.") - admin_ticket_log("[key_name(usr)] has modified the bodyparts of [C]") // yogs - Yog Tickets - - - else if(href_list["purrbation"]) - if(!check_rights(R_SPAWN)) - return - - var/mob/living/carbon/human/H = locate(href_list["purrbation"]) in GLOB.mob_list - if(!istype(H)) - to_chat(usr, "This can only be done to instances of type /mob/living/carbon/human") - return - if(!ishumanbasic(H)) - to_chat(usr, "This can only be done to the basic human species at the moment.") - return - - if(!H) - to_chat(usr, "Mob doesn't exist anymore") - return - - var/success = purrbation_toggle(H) - if(success) - to_chat(usr, "Put [H] on purrbation.") - log_admin("[key_name(usr)] has put [key_name(H)] on purrbation.") - var/msg = "[key_name(usr)] has put [key_name(H)] on purrbation." // yogs - Yog Tickets - message_admins(msg) - admin_ticket_log(H, msg) - - else - to_chat(usr, "Removed [H] from purrbation.") - log_admin("[key_name(usr)] has removed [key_name(H)] from purrbation.") - var/msg = "[key_name(usr)] has removed [key_name(H)] from purrbation." // yogs - Yog Tickets - message_admins(msg) - admin_ticket_log(H, msg) - - else if(href_list["cluwneing"]) // yogs start -- adds cluwneify verb in VV - if(!check_rights(R_SPAWN)) return - var/mob/living/carbon/human/H = locate(href_list["cluwneing"]) - if(!H) - to_chat(usr, "Mob doesn't exist anymore") - return - H.cluwneify() - message_admins(span_notice("[key_name(usr)] has made [key_name(H)] into a Cluwne.")) - return // yogs end - - else if(href_list["makepacman"]) - if(!check_rights(R_SPAWN)) - return - - var/mob/living/carbon/human/H = locate(href_list["makepacman"]) in GLOB.mob_list - if(!istype(H)) - to_chat(usr, "This can only be done to instances of type /mob/living/carbon/human") - return - - if(alert("Confirm mob type change?",,"Transform","Cancel") != "Transform") - return - if(!H) - to_chat(usr, "Mob doesn't exist anymore") - return - holder.Topic(href, list("makepacman"=href_list["makepacman"])) - - - else if(href_list["adjustDamage"] && href_list["mobToDamage"]) - if(!check_rights(NONE)) - 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("Deal how much damage to mob? (Negative values here heal)","Adjust [Text]loss",0) as num - - if(!L) - to_chat(usr, "Mob doesn't exist anymore") - return - - var/newamt - switch(Text) - 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.adjustOrganLoss(ORGAN_SLOT_BRAIN, amount) - newamt = L.getOrganLoss(ORGAN_SLOT_BRAIN) - if("clone") - L.adjustCloneLoss(amount) - newamt = L.getCloneLoss() - if("stamina") - L.adjustStaminaLoss(amount) - newamt = L.getStaminaLoss() - else - to_chat(usr, "You caused an error. DEBUG: Text:[Text] Mob:[L]") - return - - if(amount != 0) - 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["copyoutfit"]) - if(!check_rights(R_SPAWN)) - return - var/mob/living/carbon/human/H = locate(href_list["copyoutfit"]) in GLOB.carbon_list - if(istype(H)) - H.copy_outfit() - else if(href_list["modquirks"]) - if(!check_rights(R_SPAWN)) - return - - var/mob/living/carbon/human/H = locate(href_list["modquirks"]) in GLOB.mob_list - if(!istype(H)) - to_chat(usr, "This can only be done to instances of type /mob/living/carbon/human") - return - - var/list/options = list("Clear"="Clear") - for(var/x in subtypesof(/datum/quirk)) - var/datum/quirk/T = x - var/qname = initial(T.name) - options[H.has_quirk(T) ? "[qname] (Remove)" : "[qname] (Add)"] = T - - var/result = input(usr, "Choose quirk to add/remove","Quirk Mod") as null|anything in options - if(result) - if(result == "Clear") - for(var/datum/quirk/q in H.roundstart_quirks) - H.remove_quirk(q.type) - else - var/T = options[result] - if(H.has_quirk(T)) - H.remove_quirk(T) - else - H.add_quirk(T,TRUE) - else if(href_list["delete_paint"]) - if(!check_rights(R_ADMIN)) - return - - var/obj/structure/sign/painting/P = locate(href_list["delete_paint"]) - - var/mob/user = usr - if(!P.persistence_id || !P.C) - to_chat(user,span_warning("This is not a persistent painting.")) - return - var/md5 = md5(P.C.get_data_string()) - var/author = P.C.author_ckey - var/list/current = SSpersistence.paintings[P.persistence_id] - if(current) - for(var/list/entry in current) - if(entry["md5"] == md5) - current -= entry - var/png = "data/paintings/[P.persistence_id]/[md5].png" - fdel(png) - for(var/obj/structure/sign/painting/PA in SSpersistence.painting_frames) - if(PA.C && md5(PA.C.get_data_string()) == md5) - QDEL_NULL(PA.C) - log_admin("[key_name(user)] has deleted a persistent painting made by [author].") - message_admins(span_notice("[key_name_admin(user)] has deleted persistent painting made by [author].")) +//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. + return TRUE + +/datum/proc/vv_get_header() + . = list() + if(("name" in vars) && !isatom(src)) + . += "[vars["name"]]
    " diff --git a/code/game/atoms.dm b/code/game/atoms.dm index 01a78ab83c35..f857064f2f04 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -908,15 +908,106 @@ */ /atom/vv_get_dropdown() . = ..() - . += "---" - var/turf/curturf = get_turf(src) - if (curturf) - .["Jump to"] = "?_src_=holder;[HrefToken()];adminplayerobservecoodjump=1;X=[curturf.x];Y=[curturf.y];Z=[curturf.z]" - .["Modify Transform"] = "?_src_=vars;[HrefToken()];modtransform=[REF(src)]" - .["Add reagent"] = "?_src_=vars;[HrefToken()];addreagent=[REF(src)]" - .["Trigger EM pulse"] = "?_src_=vars;[HrefToken()];emp=[REF(src)]" - .["Trigger explosion"] = "?_src_=vars;[HrefToken()];explode=[REF(src)]" - .["Radiate"] = "?_src_=vars;[HrefToken()];radiate=[REF(src)]" + VV_DROPDOWN_SEPERATOR + if(!ismovable(src)) + var/turf/curturf = get_turf(src) + if (curturf) + . += "" + VV_DROPDOWN_OPTION(VV_HK_MODIFY_TRANSFORM, "Modify Transform") + VV_DROPDOWN_OPTION(VV_HK_SHOW_HIDDENPRINTS, "Show Hiddenprint log") + VV_DROPDOWN_OPTION(VV_HK_ADD_REAGENT, "Add Reagent") + VV_DROPDOWN_OPTION(VV_HK_TRIGGER_EMP, "EMP Pulse") + VV_DROPDOWN_OPTION(VV_HK_TRIGGER_EXPLOSION, "Explosion") + VV_DROPDOWN_OPTION(VV_HK_RADIATE, "Radiate") + +/atom/vv_do_topic(list/href_list) + . = ..() + if(href_list[VV_HK_ADD_REAGENT] && check_rights(R_VAREDIT)) + 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", list("Search", "Choose from a list", "I'm feeling lucky"))) + if("Search") + var/valid_id + while(!valid_id) + chosen_id = input(usr, "Enter the ID of the reagent you want to add.", "Search reagents") as null|text + if(isnull(chosen_id)) //Get me out of here! + break + if (!ispath(text2path(chosen_id))) + chosen_id = pick_closest_path(chosen_id, make_types_fancy(subtypesof(/datum/reagent))) + if (ispath(chosen_id)) + valid_id = TRUE + else + valid_id = TRUE + if(!valid_id) + to_chat(usr, span_warning("A reagent with that ID doesn't exist!")) + 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), /proc/cmp_typepaths_asc) + if("I'm feeling lucky") + chosen_id = pick(subtypesof(/datum/reagent)) + if(chosen_id) + var/amount = input(usr, "Choose the amount to add.", "Choose the amount.", reagents.maximum_volume) as num|null + if(amount) + reagents.add_reagent(chosen_id, amount) + log_admin("[key_name(usr)] has added [amount] units of [chosen_id] to [src]") + message_admins(span_notice("[key_name(usr)] has added [amount] units of [chosen_id] to [src]")) + + if(href_list[VV_HK_TRIGGER_EXPLOSION] && check_rights(R_FUN)) + usr.client.cmd_admin_explosion(src) + + if(href_list[VV_HK_TRIGGER_EMP] && check_rights(R_FUN)) + usr.client.cmd_admin_emp(src) + + if(href_list[VV_HK_SHOW_HIDDENPRINTS]) + usr.client.cmd_show_hiddenprints(src) + + if(href_list[VV_HK_RADIATE] && check_rights(R_FUN)) + var/strength = input(usr, "Choose the radiation strength.", "Choose the strength.") as num|null + if(!isnull(strength)) + AddComponent(/datum/component/radioactive, strength) + + if(href_list[VV_HK_MODIFY_TRANSFORM] && check_rights(R_VAREDIT)) + var/result = input(usr, "Choose the transformation to apply","Transform Mod") as null|anything in list("Scale","Translate","Rotate") + var/matrix/M = transform + if(!result) + return + switch(result) + if("Scale") + var/x = input(usr, "Choose x mod","Transform Mod") as null|num + var/y = input(usr, "Choose y mod","Transform Mod") as null|num + if(isnull(x) || isnull(y)) + return + transform = M.Scale(x,y) + if("Translate") + var/x = input(usr, "Choose x mod (negative = left, positive = right)","Transform Mod") as null|num + var/y = input(usr, "Choose y mod (negative = down, positive = up)","Transform Mod") as null|num + if(isnull(x) || isnull(y)) + return + transform = M.Translate(x,y) + if("Rotate") + var/angle = input(usr, "Choose angle to rotate","Transform Mod") as null|num + if(isnull(angle)) + return + transform = M.Turn(angle) + + if(href_list[VV_HK_AUTO_RENAME] && check_rights(R_VAREDIT)) + var/newname = input(usr, "What do you want to rename this to?", "Automatic Rename") as null|text + // Check the new name against the chat filter. If it triggers the IC chat filter, give an option to confirm. + if(newname) + vv_auto_rename(newname) + +/atom/proc/vv_auto_rename(newname) + name = newname + +/atom/vv_get_header() + . = ..() + var/refid = REF(src) + . += "[VV_HREF_TARGETREF(refid, VV_HK_AUTO_RENAME, "[src]")]" + . += "
    << [dir2text(dir) || dir] >>" ///Where atoms should drop if taken from this atom /atom/proc/drop_location() diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm index e7b9a1ff08a8..9e05d55325b1 100644 --- a/code/game/atoms_movable.dm +++ b/code/game/atoms_movable.dm @@ -829,9 +829,8 @@ /atom/movable/vv_get_dropdown() . = ..() - . -= "Jump to" - .["Follow"] = "?_src_=holder;[HrefToken()];adminplayerobservefollow=[REF(src)]" - .["Get"] = "?_src_=holder;[HrefToken()];admingetmovable=[REF(src)]" + . += "" + . += "" /atom/movable/proc/ex_check(ex_id) if(!ex_id) diff --git a/code/game/objects/objs.dm b/code/game/objects/objs.dm index 2db54d2e6416..d9372cd69b83 100644 --- a/code/game/objects/objs.dm +++ b/code/game/objects/objs.dm @@ -221,9 +221,78 @@ /obj/vv_get_dropdown() . = ..() - .["Delete all of type"] = "?_src_=vars;[HrefToken()];delall=[REF(src)]" - .["Osay"] = "?_src_=vars;[HrefToken()];osay[REF(src)]" - .["Modify armor values"] = "?_src_=vars;[HrefToken()];modarmor=[REF(src)]" + VV_DROPDOWN_SEPERATOR + VV_DROPDOWN_OPTION(VV_HK_MASS_DEL_TYPE, "Delete all of type") + VV_DROPDOWN_OPTION(VV_HK_OSAY, "Object Say") + VV_DROPDOWN_OPTION(VV_HK_ARMOR_MOD, "Modify armor values") + +/obj/vv_do_topic(list/href_list) + if(!(. = ..())) + return + if(href_list[VV_HK_OSAY]) + if(check_rights(R_FUN, FALSE)) + usr.client.object_say(src) + if(href_list[VV_HK_ARMOR_MOD]) + var/list/pickerlist = list() + var/list/armorlist = armor.getList() + + for (var/i in armorlist) + pickerlist += list(list("value" = armorlist[i], "name" = i)) + + var/list/result = presentpicker(usr, "Modify armor", "Modify armor: [src]", Button1="Save", Button2 = "Cancel", Timeout=FALSE, inputtype = "text", values = pickerlist) + + if (islist(result)) + if (result["button"] != 2) // If the user pressed the cancel button + // text2num conveniently returns a null on invalid values + armor = armor.setRating(melee = text2num(result["values"]["melee"]),\ + bullet = text2num(result["values"]["bullet"]),\ + laser = text2num(result["values"]["laser"]),\ + energy = text2num(result["values"]["energy"]),\ + bomb = text2num(result["values"]["bomb"]),\ + bio = text2num(result["values"]["bio"]),\ + rad = text2num(result["values"]["rad"]),\ + fire = text2num(result["values"]["fire"]),\ + acid = text2num(result["values"]["acid"])) + log_admin("[key_name(usr)] modified the armor on [src] ([type]) to melee: [armor.melee], bullet: [armor.bullet], laser: [armor.laser], energy: [armor.energy], bomb: [armor.bomb], bio: [armor.bio], fire: [armor.fire], acid: [armor.acid]") + message_admins(span_notice("[key_name_admin(usr)] modified the armor on [src] ([type]) to melee: [armor.melee], bullet: [armor.bullet], laser: [armor.laser], energy: [armor.energy], bomb: [armor.bomb], bio: [armor.bio], fire: [armor.fire], acid: [armor.acid]")) + if(href_list[VV_HK_MASS_DEL_TYPE]) + if(check_rights(R_DEBUG|R_SERVER)) + var/action_type = 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(alert(usr, "Are you really sure you want to delete all objects of type [type]?",,list("Yes","No")) != "Yes") + return + + if(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) ")) /obj/examine(mob/user) . = ..() diff --git a/code/game/objects/structures/artstuff.dm b/code/game/objects/structures/artstuff.dm index 4eed032c3b7e..02bb9607c5b2 100644 --- a/code/game/objects/structures/artstuff.dm +++ b/code/game/objects/structures/artstuff.dm @@ -400,4 +400,25 @@ /obj/structure/sign/painting/vv_get_dropdown() . = ..() - .["Remove Persistent Painting"] = "?_src_=vars;[HrefToken()];delete_paint=[REF(src)]" + VV_DROPDOWN_OPTION(VV_HK_REMOVE_PAINTING, "Remove Persistent Painting") + +/obj/structure/sign/painting/vv_do_topic(list/href_list) + . = ..() + var/mob/user = usr + if(!persistence_id || !C) + to_chat(user,span_warning("This is not a persistent painting.")) + return + var/md5 = md5(C.get_data_string()) + var/author = C.author_ckey + var/list/current = SSpersistence.paintings[persistence_id] + if(current) + for(var/list/entry in current) + if(entry["md5"] == md5) + current -= entry + var/png = "data/paintings/[persistence_id]/[md5].png" + fdel(png) + for(var/obj/structure/sign/painting/PA in SSpersistence.painting_frames) + if(PA.C && md5(PA.C.get_data_string()) == md5) + QDEL_NULL(PA.C) + log_admin("[key_name(user)] has deleted a persistent painting made by [author].") + message_admins(span_notice("[key_name_admin(user)] has deleted persistent painting made by [author].")) diff --git a/code/modules/admin/verbs/hiddenprints.dm b/code/modules/admin/verbs/hiddenprints.dm new file mode 100644 index 000000000000..c7410b8d6502 --- /dev/null +++ b/code/modules/admin/verbs/hiddenprints.dm @@ -0,0 +1,30 @@ +/client/proc/cmd_show_hiddenprints(atom/victim) + if(!check_rights(R_ADMIN)) + return + + var/interface = "A log of every player who has touched [victim], sorted by last touch.

      " + var/victim_hiddenprints = victim.return_hiddenprints() + + if(!islist(victim_hiddenprints)) + victim_hiddenprints = list() + + var/list/hiddenprints = flatten_list(victim_hiddenprints) + listclearnulls(hiddenprints) + + if(!length(hiddenprints)) + hiddenprints = list("Nobody has touched this yet!") + + hiddenprints = sortList(hiddenprints, /proc/cmp_hiddenprint_lasttime_dsc) + for(var/record in hiddenprints) + interface += "
    1. [record]

    2. " + + interface += "
    " + + var/datum/browser/hiddenprint_view = new(usr, "view_hiddenprints_[REF(victim)]", "[victim]'s hiddenprints", 450, 760) + hiddenprint_view.set_content(interface) + hiddenprint_view.open() + +/proc/cmp_hiddenprint_lasttime_dsc(a, b) + var/last_a = copytext(a, findtext(a, "\nLast: ")) + var/last_b = copytext(b, findtext(b, "\nLast: ")) + return cmp_text_dsc(last_a, last_b) diff --git a/code/modules/admin/view_variables/debug_variables.dm b/code/modules/admin/view_variables/debug_variables.dm new file mode 100644 index 000000000000..e115576a52b7 --- /dev/null +++ b/code/modules/admin/view_variables/debug_variables.dm @@ -0,0 +1,93 @@ +#define VV_HTML_ENCODE(thing) ( sanitize ? html_encode(thing) : thing ) +/// Get displayed variable in VV variable list +/proc/debug_variable(name, value, level, datum/DA = null, sanitize = TRUE) + var/header + if(DA && !isappearance(DA)) + if (islist(DA)) + var/index = name + if (value) + name = DA[name] //name is really the index until this line + else + value = DA[name] + header = "
  • ([VV_HREF_TARGET_1V(DA, VV_HK_LIST_EDIT, "E", index)]) ([VV_HREF_TARGET_1V(DA, VV_HK_LIST_CHANGE, "C", index)]) ([VV_HREF_TARGET_1V(DA, VV_HK_LIST_REMOVE, "-", index)]) " + else + header = "
  • ([VV_HREF_TARGET_1V(DA, VV_HK_BASIC_EDIT, "E", name)]) ([VV_HREF_TARGET_1V(DA, VV_HK_BASIC_CHANGE, "C", name)]) ([VV_HREF_TARGET_1V(DA, VV_HK_BASIC_MASSEDIT, "M", name)]) " + else + header = "
  • " + + var/item + if (isnull(value)) + item = "[VV_HTML_ENCODE(name)] = [span_value("null")]" + + else if (istext(value)) + item = "[VV_HTML_ENCODE(name)] = [span_value("\"[VV_HTML_ENCODE(value)]\"")]" + + else if (isicon(value)) + #ifdef VARSICON + var/icon/I = new/icon(value) + var/rnd = rand(1,10000) + var/rname = "tmp[REF(I)][rnd].png" + usr << browse_rsc(I, rname) + item = "[VV_HTML_ENCODE(name)] = ([span_value("[value]")]) " + #else + item = "[VV_HTML_ENCODE(name)] = /icon ([span_value("[value]")])" + #endif + + else if (isfile(value)) + item = "[VV_HTML_ENCODE(name)] = [span_value("'[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(isappearance(value)) + var/image/I = value + item = "[VV_HTML_ENCODE(name)] [REF(value)] = appearance([span_value("[I.icon]")], [span_value("\"[I.icon_state]\"")])" + + else if (istype(value, /datum)) + var/datum/D = value + if ("[D]" != "[D.type]") //if the thing as a name var, lets use it. + item = "[VV_HTML_ENCODE(name)] [REF(value)] = [D] [D.type]" + else + item = "[VV_HTML_ENCODE(name)] [REF(value)] = [D.type]" + + else if (islist(value)) + var/list/L = value + var/list/items = list() + + if (L.len > 0 && !(L.len > (IS_NORMAL_LIST(L) ? 50 : 150))) + for (var/i in 1 to L.len) + var/key = L[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 "" + val = key + key = i + + items += debug_variable(key, val, level + 1, sanitize = sanitize) + + item = "[VV_HTML_ENCODE(name)] = /list ([L.len])
      [items.Join()]
    " + 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, ", "))]" + else + item = "[VV_HTML_ENCODE(name)] = [span_value("[VV_HTML_ENCODE(value)]")]" + + return "[header][item]
  • " + +#undef VV_HTML_ENCODE diff --git a/code/modules/admin/view_variables/mark_datum.dm b/code/modules/admin/view_variables/mark_datum.dm new file mode 100644 index 000000000000..e381d56630ae --- /dev/null +++ b/code/modules/admin/view_variables/mark_datum.dm @@ -0,0 +1,13 @@ +/client/proc/mark_datum(datum/D) + if(!holder) + return + if(holder.marked_datum) + holder.UnregisterSignal(holder.marked_datum, COMSIG_PARENT_QDELETING) + vv_update_display(holder.marked_datum, "marked", "") + holder.marked_datum = D + holder.RegisterSignal(holder.marked_datum, COMSIG_PARENT_QDELETING, /datum/admins/proc/handle_marked_del) + vv_update_display(D, "marked", VV_MSG_MARKED) + +/datum/admins/proc/handle_marked_del(datum/source) + UnregisterSignal(marked_datum, COMSIG_PARENT_QDELETING) + marked_datum = null diff --git a/code/modules/admin/verbs/massmodvar.dm b/code/modules/admin/view_variables/massmodvar.dm similarity index 100% rename from code/modules/admin/verbs/massmodvar.dm rename to code/modules/admin/view_variables/massmodvar.dm diff --git a/code/modules/admin/verbs/modifyvariables.dm b/code/modules/admin/view_variables/modifyvariables.dm similarity index 100% rename from code/modules/admin/verbs/modifyvariables.dm rename to code/modules/admin/view_variables/modifyvariables.dm diff --git a/code/modules/admin/view_variables/topic.dm b/code/modules/admin/view_variables/topic.dm new file mode 100644 index 000000000000..73f7059c33ed --- /dev/null +++ b/code/modules/admin/view_variables/topic.dm @@ -0,0 +1,114 @@ +//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)) + return + var/target = GET_VV_TARGET + vv_do_basic(target, href_list, href) + if(istype(target, /datum)) + 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"])) + + //Stuff below aren't in dropdowns/etc. + + //~CARN: for renaming mobs (updates their name, real_name, mind.name, their ID/PDA and datacore records). + if(href_list["rename"]) + if(!check_rights(R_ADMIN)) + return + + 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", confidential = TRUE) + 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) + vv_update_display(M, "name", new_name) + vv_update_display(M, "real_name", M.real_name || "No real name") + + else if(check_rights(R_VAREDIT)) + if(href_list["rotatedatum"]) + if(!check_rights(NONE)) + return + + 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["adjustDamage"] && href_list["mobToDamage"]) + if(!check_rights(NONE)) + 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("Deal how much damage to mob? (Negative values here heal)","Adjust [Text]loss",0) as num|null + + if (isnull(amount)) + return + + if(!L) + to_chat(usr, "Mob doesn't exist anymore", confidential = TRUE) + return + + var/newamt + switch(Text) + if("brute") + L.adjustBruteLoss(amount) + 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.adjustOrganLoss(ORGAN_SLOT_BRAIN, amount) + newamt = L.getOrganLoss(ORGAN_SLOT_BRAIN) + if("clone") + L.adjustCloneLoss(amount) + newamt = L.getCloneLoss() + if("stamina") + L.adjustStaminaLoss(amount) + newamt = L.getStaminaLoss() + else + to_chat(usr, "You caused an error. DEBUG: Text:[Text] Mob:[L]", confidential = TRUE) + return + + if(amount != 0) + 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]") + + + //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)) + debug_variables(DAT) diff --git a/code/modules/admin/view_variables/topic_basic.dm b/code/modules/admin/view_variables/topic_basic.dm new file mode 100644 index 000000000000..a20ffacd1414 --- /dev/null +++ b/code/modules/admin/view_variables/topic_basic.dm @@ -0,0 +1,54 @@ +//Not using datum.vv_do_topic for very basic/low level debug things, incase the datum's vv_do_topic is runtiming/whatnot. +/client/proc/vv_do_basic(datum/target, href_list) + var/target_var = GET_VV_VAR_TARGET + if(check_rights(R_VAREDIT)) + if(target_var) + if(href_list[VV_HK_BASIC_EDIT]) + if(!modify_variables(target, target_var, 1)) + return + switch(target_var) + if("name") + vv_update_display(target, "name", "[target]") + if("dir") + var/atom/A = target + if(istype(A)) + vv_update_display(target, "dir", dir2text(A.dir) || A.dir) + if("ckey") + var/mob/living/L = target + if(istype(L)) + vv_update_display(target, "ckey", L.ckey || "No ckey") + if("real_name") + var/mob/living/L = target + if(istype(L)) + vv_update_display(target, "real_name", L.real_name || "No real name") + + if(href_list[VV_HK_BASIC_CHANGE]) + modify_variables(target, target_var, 0) + if(href_list[VV_HK_BASIC_MASSEDIT]) + cmd_mass_modify_object_variables(target, target_var) + if(check_rights(R_ADMIN, FALSE)) + if(href_list[VV_HK_EXPOSE]) + var/value = vv_get_value(VV_CLIENT) + if (value["class"] != VV_CLIENT) + return + var/client/C = value["value"] + if (!C) + return + if(!target) + to_chat(usr, span_warning("The object you tried to expose to [C] no longer exists (nulled or hard-deled)"), confidential = TRUE) + return + message_admins("[key_name_admin(usr)] Showed [key_name_admin(C)] a VV window") + log_admin("Admin [key_name(usr)] Showed [key_name(C)] a VV window of a [target]") + to_chat(C, "[holder.fakekey ? "an Administrator" : "[usr.client.key]"] has granted you access to view a View Variables window", confidential = TRUE) + C.debug_variables(target) + if(check_rights(R_DEBUG)) + if(href_list[VV_HK_DELETE]) + usr.client.admin_delete(target) + if (isturf(target)) // show the turf that took its place + usr.client.debug_variables(target) + return + + if(href_list[VV_HK_MARK]) + usr.client.mark_datum(target) + if(href_list[VV_HK_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 new file mode 100644 index 000000000000..7fe1a9c715fe --- /dev/null +++ b/code/modules/admin/view_variables/topic_list.dm @@ -0,0 +1,43 @@ +//LISTS - CAN NOT DO VV_DO_TOPIC BECAUSE LISTS AREN'T DATUMS :( +/client/proc/vv_do_list(list/target, href_list) + var/target_index = text2num(GET_VV_VAR_TARGET) + if(check_rights(R_VAREDIT)) + if(target_index) + if(href_list[VV_HK_LIST_EDIT]) + mod_list(target, null, "list", "contents", target_index, autodetect_class = TRUE) + if(href_list[VV_HK_LIST_CHANGE]) + mod_list(target, null, "list", "contents", target_index, autodetect_class = FALSE) + if(href_list[VV_HK_LIST_REMOVE]) + var/variable = target[target_index] + var/prompt = alert(usr,"Do you want to remove item number [target_index] from list?", "Confirm", list("Yes", "No")) + if (prompt != "Yes") + return + target.Cut(target_index, target_index+1) + log_world("### ListVarEdit by [src]: /list's contents: REMOVED=[html_encode("[variable]")]") + log_admin("[key_name(src)] modified list's contents: REMOVED=[variable]") + message_admins("[key_name_admin(src)] modified list's contents: REMOVED=[variable]") + if(href_list[VV_HK_LIST_ADD]) + mod_list_add(target, null, "list", "contents") + if(href_list[VV_HK_LIST_ERASE_DUPES]) + uniqueList_inplace(target) + log_world("### ListVarEdit by [src]: /list contents: CLEAR DUPES") + log_admin("[key_name(src)] modified list's contents: CLEAR DUPES") + message_admins("[key_name_admin(src)] modified list's contents: CLEAR DUPES") + if(href_list[VV_HK_LIST_ERASE_NULLS]) + listclearnulls(target) + log_world("### ListVarEdit by [src]: /list contents: CLEAR NULLS") + log_admin("[key_name(src)] modified list's contents: CLEAR NULLS") + message_admins("[key_name_admin(src)] modified list's contents: CLEAR NULLS") + if(href_list[VV_HK_LIST_SET_LENGTH]) + var/value = vv_get_value(VV_NUM) + if (value["class"] != VV_NUM || value["value"] > max(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]") + log_admin("[key_name(src)] modified list's len: [target.len]") + message_admins("[key_name_admin(src)] modified list's len: [target.len]") + if(href_list[VV_HK_LIST_SHUFFLE]) + shuffle_inplace(target) + log_world("### ListVarEdit by [src]: /list contents: SHUFFLE") + log_admin("[key_name(src)] modified list's contents: SHUFFLE") + message_admins("[key_name_admin(src)] modified list's contents: SHUFFLE") diff --git a/code/modules/admin/view_variables/view_variables.dm b/code/modules/admin/view_variables/view_variables.dm new file mode 100644 index 000000000000..1466f50fb80e --- /dev/null +++ b/code/modules/admin/view_variables/view_variables.dm @@ -0,0 +1,375 @@ +/client/proc/debug_variables(datum/D in world) + set category = "Misc.Server 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) //The usr vs src abuse in this proc is intentional and must not be changed + to_chat(usr, span_danger("You need to be an administrator to access this."), confidential = TRUE) + return + + if(!D) + return + + var/islist = islist(D) + var/isappearance = isappearance(D) + if (!islist && !istype(D) && !isappearance) + return + + var/title = "" + var/refid = REF(D) + var/icon/sprite + var/hash + + var/type = /list + if (isappearance) + type = /image + else if (!islist) + type = D.type + + + + if(istype(D, /atom) || isappearance) + var/atom/AT = D + if(AT.icon && AT.icon_state) + sprite = new /icon(AT.icon, AT.icon_state) + hash = md5(AT.icon) + hash = md5(hash + AT.icon_state) + src << browse_rsc(sprite, "vv[hash].png") + + title = "[D] ([REF(D)]) = [type]" + var/formatted_type = replacetext("[type]", "/", "/") + + var/sprite_text + if(sprite) + sprite_text = "" + var/list/header = islist(D)? list("/list") : D.vv_get_header() + + var/marked_line + if(holder && holder.marked_datum && holder.marked_datum == D) + marked_line = VV_MSG_MARKED + var/varedited_line + if(!isappearance && !islist && (D.datum_flags & DF_VAR_EDITED)) + varedited_line = VV_MSG_EDITED + var/deleted_line + if(!isappearance && !islist && D.gc_destroyed) + deleted_line = VV_MSG_DELETED + + var/list/dropdownoptions = list() + 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 if (!isappearance) + dropdownoptions = D.vv_get_dropdown() + + var/list/names = list() + if (!islist && !isappearance) + for (var/V in D.vars) + names += V + sleep(1)//For some reason, without this sleep, VVing will cause client to disconnect on certain objects. + + var/list/variable_html = list() + if (islist) + var/list/L = D + for (var/i in 1 to L.len) + var/key = L[i] + var/value + if (IS_NORMAL_LIST(L) && !isnum(key)) + value = L[key] + variable_html += debug_variable(i, value, 0, D) + else if(isappearance(D)) + variable_html += debug_variable("type", D:type, 0, D) + variable_html += debug_variable("name", D:name, 0, D) + variable_html += debug_variable("desc", D:desc, 0, D) + variable_html += debug_variable("suffix", D:suffix, 0, D) + variable_html += debug_variable("text", D:text, 0, D) + variable_html += debug_variable("icon", D:icon, 0, D) + variable_html += debug_variable("icon_state", D:icon_state, 0, D) + variable_html += debug_variable("visibility", D:visibility, 0, D) + variable_html += debug_variable("luminosity", D:luminosity, 0, D) + variable_html += debug_variable("opacity", D:opacity, 0, D) + variable_html += debug_variable("density", D:density, 0, D) + variable_html += debug_variable("verbs", D:verbs, 0, D) + variable_html += debug_variable("dir", D:dir, 0, D) + variable_html += debug_variable("gender", D:gender, 0, D) + variable_html += debug_variable("tag", D:tag, 0, D) + variable_html += debug_variable("overlays", D:overlays, 0, D) + variable_html += debug_variable("underlays", D:underlays, 0, D) + variable_html += debug_variable("layer", D:layer, 0, D) + variable_html += debug_variable("parent_type", D:parent_type, 0, D) + variable_html += debug_variable("mouse_over_pointer", D:mouse_over_pointer, 0, D) + variable_html += debug_variable("mouse_drag_pointer", D:mouse_drag_pointer, 0, D) + variable_html += debug_variable("mouse_drop_pointer", D:mouse_drop_pointer, 0, D) + variable_html += debug_variable("mouse_drop_zone", D:mouse_drop_zone, 0, D) + variable_html += debug_variable("animate_movement", D:animate_movement, 0, D) + variable_html += debug_variable("screen_loc", D:screen_loc, 0, D) + variable_html += debug_variable("infra_luminosity", D:infra_luminosity, 0, D) + variable_html += debug_variable("invisibility", D:invisibility, 0, D) + variable_html += debug_variable("mouse_opacity", D:mouse_opacity, 0, D) + variable_html += debug_variable("pixel_x", D:pixel_x, 0, D) + variable_html += debug_variable("pixel_y", D:pixel_y, 0, D) + variable_html += debug_variable("pixel_step_size", D:pixel_step_size, 0, D) + variable_html += debug_variable("pixel_z", D:pixel_z, 0, D) + variable_html += debug_variable("override", D:override, 0, D) + variable_html += debug_variable("glide_size", D:glide_size, 0, D) + variable_html += debug_variable("maptext", D:maptext, 0, D) + variable_html += debug_variable("maptext_width", D:maptext_width, 0, D) + variable_html += debug_variable("maptext_height", D:maptext_height, 0, D) + variable_html += debug_variable("transform", D:transform, 0, D) + variable_html += debug_variable("alpha", D:alpha, 0, D) + variable_html += debug_variable("color", D:color, 0, D) + variable_html += debug_variable("blend_mode", D:blend_mode, 0, D) + variable_html += debug_variable("appearance", D:appearance, 0, D) + variable_html += debug_variable("maptext_x", D:maptext_x, 0, D) + variable_html += debug_variable("maptext_y", D:maptext_y, 0, D) + variable_html += debug_variable("plane", D:plane, 0, D) + variable_html += debug_variable("appearance_flags", D:appearance_flags, 0, D) + variable_html += debug_variable("pixel_w", D:pixel_w, 0, D) + variable_html += debug_variable("render_source", D:render_source, 0, D) + variable_html += debug_variable("render_target", D:render_target, 0, D) + else + names = sortList(names) + for (var/V in names) + if(D.can_vv_get(V)) + variable_html += D.vv_get_var(V) + + var/html = {" + + + + [title] + + + + +
    + + + + + +
    + + + + +
    + [sprite_text] +
    + [header.Join()] +
    +
    +
    + [formatted_type] + [marked_line] + [varedited_line] + [deleted_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()] +
    + + + +"} + 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") diff --git a/code/modules/events/spacevine.dm b/code/modules/events/spacevine.dm index 032cf232da71..03cdb446322a 100644 --- a/code/modules/events/spacevine.dm +++ b/code/modules/events/spacevine.dm @@ -391,17 +391,14 @@ /datum/spacevine_controller/vv_get_dropdown() . = ..() - . += "---" - .["Delete Vines"] = "?_src_=[REF(src)];[HrefToken()];purge_vines=1" + VV_DROPDOWN_SEPERATOR + VV_DROPDOWN_OPTION(VV_HK_SPACEVINE_PURGE, "Delete Vines") -/datum/spacevine_controller/Topic(href, href_list) - if(..() || !check_rights(R_ADMIN, FALSE) || !usr.client.holder.CheckAdminHref(href, href_list)) - return - - if(href_list["purge_vines"]) - if(alert(usr, "Are you sure you want to delete this spacevine cluster?", "Delete Vines", "Yes", "No") != "Yes") - return - DeleteVines() +/datum/spacevine_controller/vv_do_topic(href_list) + . = ..() + if(href_list[VV_HK_SPACEVINE_PURGE]) + if(alert(usr, "Are you sure you want to delete this spacevine cluster?", "Delete Vines", list("Yes", "No")) == "Yes") + DeleteVines() /datum/spacevine_controller/proc/DeleteVines() //this is kill QDEL_LIST(vines) //this will also qdel us diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index 4d4457389c49..cdf4a2f5c056 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -952,14 +952,114 @@ /mob/living/carbon/vv_get_dropdown() . = ..() - . += "---" - .["Make AI"] = "?_src_=vars;[HrefToken()];makeai=[REF(src)]" - .["Modify bodypart"] = "?_src_=vars;[HrefToken()];editbodypart=[REF(src)]" - .["Modify organs"] = "?_src_=vars;[HrefToken()];editorgans=[REF(src)]" - .["Hallucinate"] = "?_src_=vars;[HrefToken()];hallucinate=[REF(src)]" - .["Give martial arts"] = "?_src_=vars;[HrefToken()];givemartialart=[REF(src)]" - .["Give brain trauma"] = "?_src_=vars;[HrefToken()];givetrauma=[REF(src)]" - .["Cure brain traumas"] = "?_src_=vars;[HrefToken()];curetraumas=[REF(src)]" + VV_DROPDOWN_SEPERATOR + VV_DROPDOWN_OPTION(VV_HK_MODIFY_BODYPART, "Modify bodypart") + VV_DROPDOWN_OPTION(VV_HK_MODIFY_ORGANS, "Modify organs") + VV_DROPDOWN_OPTION(VV_HK_HALLUCINATION, "Hallucinate") + VV_DROPDOWN_OPTION(VV_HK_MARTIAL_ART, "Give Martial Arts") + VV_DROPDOWN_OPTION(VV_HK_GIVE_TRAUMA, "Give Brain Trauma") + VV_DROPDOWN_OPTION(VV_HK_CURE_TRAUMA, "Cure Brain Traumas") + +/mob/living/carbon/vv_do_topic(list/href_list) + . = ..() + if(href_list[VV_HK_MODIFY_BODYPART]) + if(!check_rights(R_SPAWN)) + return + var/edit_action = input(usr, "What would you like to do?","Modify Body Part") as null|anything in list("add","remove", "augment") + if(!edit_action) + return + var/list/limb_list = list() + if(edit_action == "remove" || edit_action == "augment") + for(var/obj/item/bodypart/B in bodyparts) + limb_list += B.body_zone + if(edit_action == "remove") + limb_list -= BODY_ZONE_CHEST + else + limb_list = list(BODY_ZONE_HEAD, BODY_ZONE_L_ARM, BODY_ZONE_R_ARM, BODY_ZONE_L_LEG, BODY_ZONE_R_LEG) + for(var/obj/item/bodypart/B in bodyparts) + limb_list -= B.body_zone + var/result = input(usr, "Please choose which body part to [edit_action]","[capitalize(edit_action)] Body Part") as null|anything in sortList(limb_list) + if(result) + var/obj/item/bodypart/BP = get_bodypart(result) + switch(edit_action) + if("remove") + if(BP) + BP.drop_limb() + else + to_chat(usr, span_boldwarning("[src] doesn't have such bodypart.")) + if("add") + if(BP) + to_chat(usr, span_boldwarning("[src] already has such bodypart.")) + else + if(!regenerate_limb(result)) + to_chat(usr, span_boldwarning("[src] cannot have such bodypart.")) + if("augment") + if(ishuman(src)) + if(BP) + BP.change_bodypart_status(BODYPART_ROBOTIC, TRUE, TRUE) + else + to_chat(usr, span_boldwarning("[src] doesn't have such bodypart.")) + else + to_chat(usr, span_boldwarning("Only humans can be augmented.")) + admin_ticket_log("[key_name_admin(usr)] has modified the bodyparts of [src]") + if(href_list[VV_HK_MODIFY_ORGANS]) + if(!check_rights(NONE)) + return + usr.client.manipulate_organs(src) + if(href_list[VV_HK_MARTIAL_ART]) + if(!check_rights(NONE)) + return + var/list/artpaths = subtypesof(/datum/martial_art) + var/list/artnames = list() + for(var/i in artpaths) + var/datum/martial_art/M = i + artnames[initial(M.name)] = M + var/result = input(usr, "Choose the martial art to teach","JUDO CHOP") as null|anything in sortList(artnames, /proc/cmp_typepaths_asc) + if(!usr) + return + if(QDELETED(src)) + to_chat(usr, span_boldwarning("Mob doesn't exist anymore.")) + return + if(result) + var/chosenart = artnames[result] + var/datum/martial_art/MA = new chosenart + MA.teach(src) + log_admin("[key_name(usr)] has taught [MA] to [key_name(src)].") + message_admins(span_notice("[key_name_admin(usr)] has taught [MA] to [key_name_admin(src)].")) + if(href_list[VV_HK_GIVE_TRAUMA]) + if(!check_rights(NONE)) + return + var/list/traumas = subtypesof(/datum/brain_trauma) + var/result = input(usr, "Choose the brain trauma to apply","Traumatize") as null|anything in sortList(traumas, /proc/cmp_typepaths_asc) + if(!usr) + return + if(QDELETED(src)) + to_chat(usr, "Mob doesn't exist anymore") + return + if(!result) + return + var/datum/brain_trauma/BT = gain_trauma(result) + if(BT) + log_admin("[key_name(usr)] has traumatized [key_name(src)] with [BT.name]") + message_admins(span_notice("[key_name_admin(usr)] has traumatized [key_name_admin(src)] with [BT.name].")) + if(href_list[VV_HK_CURE_TRAUMA]) + if(!check_rights(NONE)) + return + cure_all_traumas(TRAUMA_RESILIENCE_ABSOLUTE) + log_admin("[key_name(usr)] has cured all traumas from [key_name(src)].") + message_admins(span_notice("[key_name_admin(usr)] has cured all traumas from [key_name_admin(src)].")) + if(href_list[VV_HK_HALLUCINATION]) + if(!check_rights(NONE)) + return + var/list/hallucinations = subtypesof(/datum/hallucination) + var/result = input(usr, "Choose the hallucination to apply","Send Hallucination") as null|anything in sortList(hallucinations, /proc/cmp_typepaths_asc) + if(!usr) + return + if(QDELETED(src)) + to_chat(usr, "Mob doesn't exist anymore") + return + if(result) + new result(src, TRUE) /mob/living/carbon/can_resist() return bodyparts.len > 2 && ..() diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index 6aa6e38d7e75..f26c6d22ec0b 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -881,17 +881,60 @@ /mob/living/carbon/human/vv_get_dropdown() . = ..() - . += "---" - .["Make monkey"] = "?_src_=vars;[HrefToken()];makemonkey=[REF(src)]" - .["Set Species"] = "?_src_=vars;[HrefToken()];setspecies=[REF(src)]" - .["Make cyborg"] = "?_src_=vars;[HrefToken()];makerobot=[REF(src)]" - .["Make alien"] = "?_src_=vars;[HrefToken()];makealien=[REF(src)]" - .["Make slime"] = "?_src_=vars;[HrefToken()];makeslime=[REF(src)]" - .["Toggle Purrbation"] = "?_src_=vars;[HrefToken()];purrbation=[REF(src)]" - .["Copy outfit"] = "?_src_=vars;[HrefToken()];copyoutfit=[REF(src)]" - .["Add/Remove Quirks"] = "?_src_=vars;[HrefToken()];modquirks=[REF(src)]" - .["Make Cluwne"] = "?_src_=vars;[HrefToken()];cluwneing=[REF(src)]" // yogs -- make cluwne - .["Make Pacman"] = "?_src_=vars;[HrefToken()];makepacman=[REF(src)]" //I LOVE PACMAN + VV_DROPDOWN_SEPERATOR + VV_DROPDOWN_OPTION(VV_HK_SET_SPECIES, "Set Species") + VV_DROPDOWN_OPTION(VV_HK_PURRBATION, "Toggle Purrbation") + VV_DROPDOWN_OPTION(VV_HK_COPY_OUTFIT, "Copy Outfit") + VV_DROPDOWN_OPTION(VV_HK_MOD_QUIRKS, "Add/Remove Quirks") + +/mob/living/carbon/human/vv_do_topic(list/href_list) + . = ..() + if(href_list[VV_HK_SET_SPECIES] && check_rights(R_SPAWN)) + var/result = input(usr, "Please choose a new species","Species") as null|anything in GLOB.species_list + + if(result) + var/newtype = GLOB.species_list[result] + admin_ticket_log(src, "[key_name(usr)] has modified the species of [src] to [result]") // yogs - Yog Tickets + set_species(newtype) + if(href_list[VV_HK_PURRBATION] && check_rights(R_SPAWN)) + if(!ishumanbasic(src)) + to_chat(usr, "This can only be done to the basic human species at the moment.") + return + + var/success = purrbation_toggle(src) + if(success) + to_chat(usr, "Put [src] on purrbation.") + log_admin("[key_name(usr)] has put [key_name(src)] on purrbation.") + var/msg = "[key_name(usr)] has put [key_name(src)] on purrbation." // yogs - Yog Tickets + message_admins(msg) + admin_ticket_log(src, msg) + + else + to_chat(usr, "Removed [src] from purrbation.") + log_admin("[key_name(usr)] has removed [key_name(src)] from purrbation.") + var/msg = "[key_name(usr)] has removed [key_name(src)] from purrbation." // yogs - Yog Tickets + message_admins(msg) + admin_ticket_log(src, msg) + if(href_list[VV_HK_COPY_OUTFIT] && check_rights(R_SPAWN)) + copy_outfit() + if(href_list[VV_HK_MOD_QUIRKS] && check_rights(R_SPAWN)) + var/list/options = list("Clear"="Clear") + for(var/x in subtypesof(/datum/quirk)) + var/datum/quirk/T = x + var/qname = initial(T.name) + options[has_quirk(T) ? "[qname] (Remove)" : "[qname] (Add)"] = T + + var/result = input(usr, "Choose quirk to add/remove","Quirk Mod") as null|anything in options + if(result) + if(result == "Clear") + for(var/datum/quirk/q in roundstart_quirks) + remove_quirk(q.type) + else + var/T = options[result] + if(has_quirk(T)) + remove_quirk(T) + else + add_quirk(T,TRUE) /mob/living/carbon/human/MouseDrop_T(mob/living/target, mob/living/user) if(pulling == target && grab_state >= GRAB_AGGRESSIVE && stat == CONSCIOUS) diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index 78855140bdc4..5005cc5994df 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -1385,6 +1385,22 @@ if("lighting_alpha") sync_lighting_plane_alpha() +/mob/living/vv_get_header() + . = ..() + var/refid = REF(src) + . += {" +
    [ckey || "No ckey"] / [VV_HREF_TARGETREF_1V(refid, VV_HK_BASIC_EDIT, "[real_name || "no real name"]", NAMEOF(src, real_name))] +
    + BRUTE:[getBruteLoss()] + FIRE:[getFireLoss()] + TOXIN:[getToxLoss()] + OXY:[getOxyLoss()] + CLONE:[getCloneLoss()] + BRAIN:[getOrganLoss(ORGAN_SLOT_BRAIN)] + STAMINA:[getStaminaLoss()] + + "} + /mob/living/proc/is_convert_antag() var/list/bad_antags = list( /datum/antagonist/clockcult, diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index b0cae501bfff..272ae1681937 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -1187,19 +1187,63 @@ */ /mob/vv_get_dropdown() . = ..() - . += "---" - .["Gib"] = "?_src_=vars;[HrefToken()];gib=[REF(src)]" - .["Give Spell"] = "?_src_=vars;[HrefToken()];give_spell=[REF(src)]" - .["Remove Spell"] = "?_src_=vars;[HrefToken()];remove_spell=[REF(src)]" - .["Give Disease"] = "?_src_=vars;[HrefToken()];give_disease=[REF(src)]" - .["Toggle Godmode"] = "?_src_=vars;[HrefToken()];godmode=[REF(src)]" - .["Drop Everything"] = "?_src_=vars;[HrefToken()];drop_everything=[REF(src)]" - .["Regenerate Icons"] = "?_src_=vars;[HrefToken()];regenerateicons=[REF(src)]" - .["Show player panel"] = "?_src_=vars;[HrefToken()];mob_player_panel=[REF(src)]" - .["Toggle Build Mode"] = "?_src_=vars;[HrefToken()];build_mode=[REF(src)]" - .["Assume Direct Control"] = "?_src_=vars;[HrefToken()];direct_control=[REF(src)]" - .["Offer Control to Ghosts"] = "?_src_=vars;[HrefToken()];offer_control=[REF(src)]" - .["Set AFK Timer"] = "?_src_=vars;[HrefToken()];set_afk=[REF(src)]" + VV_DROPDOWN_SEPERATOR + VV_DROPDOWN_OPTION(VV_HK_GIB, "Gib") + VV_DROPDOWN_OPTION(VV_HK_GIVE_SPELL, "Give Spell") + VV_DROPDOWN_OPTION(VV_HK_REMOVE_SPELL, "Remove Spell") + VV_DROPDOWN_OPTION(VV_HK_GIVE_DISEASE, "Give Disease") + VV_DROPDOWN_OPTION(VV_HK_GODMODE, "Toggle Godmode") + VV_DROPDOWN_OPTION(VV_HK_DROP_ALL, "Drop Everything") + VV_DROPDOWN_OPTION(VV_HK_REGEN_ICONS, "Regenerate Icons") + VV_DROPDOWN_OPTION(VV_HK_PLAYER_PANEL, "Show player panel") + VV_DROPDOWN_OPTION(VV_HK_BUILDMODE, "Toggle Buildmode") + VV_DROPDOWN_OPTION(VV_HK_DIRECT_CONTROL, "Assume Direct Control") + VV_DROPDOWN_OPTION(VV_HK_OFFER_GHOSTS, "Offer Control to Ghosts") + VV_DROPDOWN_OPTION(VV_HK_SET_AFK_TIMER, "Set AFK Timer") + + +/mob/vv_do_topic(list/href_list) + . = ..() + if(href_list[VV_HK_REGEN_ICONS] && check_rights(R_VAREDIT)) + regenerate_icons() + if(href_list[VV_HK_PLAYER_PANEL]) + usr.client.holder.show_player_panel(src) + if(href_list[VV_HK_GODMODE] && check_rights(R_ADMIN)) + usr.client.cmd_admin_godmode(src) + if(href_list[VV_HK_GIVE_SPELL] && check_rights(R_VAREDIT)) + usr.client.give_spell(src) + if(href_list[VV_HK_REMOVE_SPELL] && check_rights(R_VAREDIT)) + usr.client.remove_spell(src) + if(href_list[VV_HK_GIVE_DISEASE] && check_rights(R_VAREDIT)) + usr.client.give_disease(src) + if(href_list[VV_HK_GIB] && check_rights(R_FUN)) + usr.client.cmd_admin_gib(src) + if(href_list[VV_HK_BUILDMODE] && check_rights(R_BUILDMODE)) + togglebuildmode(src) + if(href_list[VV_HK_DROP_ALL] && check_rights(R_ADMIN)) + usr.client.cmd_admin_drop_everything(src) + if(href_list[VV_HK_DIRECT_CONTROL] && check_rights(R_VAREDIT)) + usr.client.cmd_assume_direct_control(src) + if(href_list[VV_HK_OFFER_GHOSTS] && check_rights(R_ADMIN)) + offer_control(src) + if(href_list[VV_HK_SET_AFK_TIMER] && check_rights(R_ADMIN)) + if(!mind) + to_chat(usr, "This cannot be used on mobs without a mind") + return + + var/timer = input("Input AFK length in minutes, 0 to cancel the current timer", text("Input")) as num|null + if(timer == null) // Explicit null check for cancel, rather than generic truthyness, so 0 is handled differently + return + + deltimer(mind.afk_verb_timer) + mind.afk_verb_used = FALSE + + if(!timer) + return + + mind.afk_verb_used = TRUE + mind.afk_verb_timer = addtimer(VARSET_CALLBACK(mind, afk_verb_used, FALSE), timer MINUTES, TIMER_STOPPABLE); + /** * extra var handling for the logging var @@ -1210,6 +1254,12 @@ return debug_variable(var_name, logging, 0, src, FALSE) . = ..() +/mob/vv_auto_rename(new_name) + //Do not do parent's actions, as we *usually* do this differently. + fully_replace_character_name(real_name, new_name) + usr.client.vv_update_display(src, "name", new_name) + usr.client.vv_update_display(src, "real_name", real_name || "No real name") + ///Show the language menu for this mob /mob/verb/open_language_menu() set name = "Open Language Menu" diff --git a/yogstation.dme b/yogstation.dme index f54e65c82b71..d8b43594e1f3 100644 --- a/yogstation.dme +++ b/yogstation.dme @@ -1314,14 +1314,13 @@ #include "code\modules\admin\verbs\fps.dm" #include "code\modules\admin\verbs\getlogs.dm" #include "code\modules\admin\verbs\ghost_pool_protection.dm" +#include "code\modules\admin\verbs\hiddenprints.dm" #include "code\modules\admin\verbs\individual_logging.dm" #include "code\modules\admin\verbs\machine_upgrade.dm" #include "code\modules\admin\verbs\manipulate_organs.dm" #include "code\modules\admin\verbs\map_template_loadverb.dm" #include "code\modules\admin\verbs\mapping.dm" #include "code\modules\admin\verbs\maprotation.dm" -#include "code\modules\admin\verbs\massmodvar.dm" -#include "code\modules\admin\verbs\modifyvariables.dm" #include "code\modules\admin\verbs\one_click_antag.dm" #include "code\modules\admin\verbs\onlyone.dm" #include "code\modules\admin\verbs\panicbunker.dm" @@ -1336,6 +1335,14 @@ #include "code\modules\admin\verbs\SDQL2\SDQL_2.dm" #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\topic_basic.dm" +#include "code\modules\admin\view_variables\topic_list.dm" +#include "code\modules\admin\view_variables\mark_datum.dm" +#include "code\modules\admin\view_variables\modifyvariables.dm" +#include "code\modules\admin\view_variables\massmodvar.dm" +#include "code\modules\admin\view_variables\topic.dm" +#include "code\modules\admin\view_variables\debug_variables.dm" +#include "code\modules\admin\view_variables\view_variables.dm" #include "code\modules\antagonists\_common\antag_datum.dm" #include "code\modules\antagonists\_common\antag_helpers.dm" #include "code\modules\antagonists\_common\antag_hud.dm"