diff --git a/code/__DEFINES/typeids.dm b/code/__DEFINES/typeids.dm new file mode 100644 index 00000000000..4fd2c390fa7 --- /dev/null +++ b/code/__DEFINES/typeids.dm @@ -0,0 +1,6 @@ +//Byond type ids +#define TYPEID_NULL "0" +#define TYPEID_NORMAL_LIST "f" +//helper macros +#define GET_TYPEID(ref) ( ( (lentext(ref) <= 10) ? "TYPEID_NULL" : copytext(ref, 4, lentext(ref) - 6) ) ) +#define IS_NORMAL_LIST(L) (GET_TYPEID("\ref[L]") == TYPEID_NORMAL_LIST) \ No newline at end of file diff --git a/code/__DEFINES/vv.dm b/code/__DEFINES/vv.dm new file mode 100644 index 00000000000..3acd09a1a81 --- /dev/null +++ b/code/__DEFINES/vv.dm @@ -0,0 +1,21 @@ +#define VV_NUM "Number" +#define VV_TEXT "Text" +#define VV_MESSAGE "Mutiline Text" +#define VV_ICON "Icon" +#define VV_ATOM_REFERENCE "Atom Reference" +#define VV_DATUM_REFERENCE "Datum Reference" +#define VV_MOB_REFERENCE "Mob Reference" +#define VV_CLIENT "Client" +#define VV_ATOM_TYPE "Atom Typepath" +#define VV_DATUM_TYPE "Datum Typepath" +#define VV_TYPE "Custom Typepath" +#define VV_MATRIX "Matrix" +#define VV_FILE "File" +#define VV_LIST "List" +#define VV_NEW_ATOM "New Atom" +#define VV_NEW_DATUM "New Datum" +#define VV_NEW_TYPE "New Custom Typepath" +#define VV_NEW_LIST "New List" +#define VV_NULL "NULL" +#define VV_RESTORE_DEFAULT "Restore to Default" +#define VV_MARKED_DATUM "Marked Datum" \ No newline at end of file diff --git a/code/__HELPERS/lists.dm b/code/__HELPERS/lists.dm index 3556ef2d6f4..6ee5097a76e 100644 --- a/code/__HELPERS/lists.dm +++ b/code/__HELPERS/lists.dm @@ -654,3 +654,28 @@ proc/dd_sortedObjectList(list/incoming) // LAZYING PT 2: THE LAZENING #define LAZYREINITLIST(L) LAZYCLEARLIST(L); LAZYINITLIST(L); + + +//same, but returns nothing and acts on list in place +/proc/shuffle_inplace(list/L) + if(!L) + return + + for(var/i=1, i list("A dog said hi ","name]!" + // jointext() --> "A dog said hi name]!" + // splittext() --> list("A","dog","said","hi","name]!") + + t_string = replacetext(t_string, "\[", "\[ ")//Necessary to resolve "word[var_name]" scenarios + var/list/list_value = splittext(t_string, "\[") + var/intermediate_stage = jointext(list_value, null) + + list_value = splittext(intermediate_stage, " ") + for(var/value in list_value) + if(findtext(value, "]")) + value = splittext(value, "]") //"name]!" --> list("name","!") + for(var/A in value) + if(var_source.vars.Find(A)) + . += A \ No newline at end of file diff --git a/code/__HELPERS/unique_ids.dm b/code/__HELPERS/unique_ids.dm index 9363df4252e..f6f9393d937 100644 --- a/code/__HELPERS/unique_ids.dm +++ b/code/__HELPERS/unique_ids.dm @@ -32,6 +32,7 @@ var/global/next_unique_datum_id = 1 unique_datum_id = "\ref[src]_[next_unique_datum_id++]" return unique_datum_id + /proc/locateUID(uid) if(!istext(uid)) return null diff --git a/code/__HELPERS/unsorted.dm b/code/__HELPERS/unsorted.dm index 3900ba2ba33..892dd3f8107 100644 --- a/code/__HELPERS/unsorted.dm +++ b/code/__HELPERS/unsorted.dm @@ -1730,53 +1730,81 @@ var/mob/dview/dview_mob = new closest_atom = A return closest_atom -/proc/pick_closest_path(value) - var/list/matches = get_fancy_list_of_types() - if(!isnull(value) && value!="") +/proc/pick_closest_path(value, list/matches = get_fancy_list_of_atom_types()) + if(value == FALSE) //nothing should be calling us with a number, so this is safe + value = input("Enter type to find (blank for all, cancel to cancel)", "Search for type") as null|text + if(isnull(value)) + return + value = trim(value) + if(!isnull(value) && value != "") matches = filter_fancy_list(matches, value) - if(matches.len==0) + if(matches.len == 0) return var/chosen - if(matches.len==1) + if(matches.len == 1) chosen = matches[1] else - chosen = input("Select an atom type", "Spawn Atom", matches[1]) as null|anything in matches + chosen = input("Select a type", "Pick Type", matches[1]) as null|anything in matches if(!chosen) return chosen = matches[chosen] return chosen +/proc/make_types_fancy(var/list/types) + if(ispath(types)) + types = list(types) + . = list() + for(var/type in types) + var/typename = "[type]" + var/static/list/TYPES_SHORTCUTS = list( + /obj/effect/decal/cleanable = "CLEANABLE", + /obj/item/device/radio/headset = "HEADSET", + /obj/item/clothing/head/helmet/space = "SPESSHELMET", + /obj/item/weapon/book/manual = "MANUAL", + /obj/item/weapon/reagent_containers/food/drinks = "DRINK", //longest paths comes first + /obj/item/weapon/reagent_containers/food = "FOOD", + /obj/item/weapon/reagent_containers = "REAGENT_CONTAINERS", + /obj/item/weapon = "WEAPON", + /obj/machinery/atmospherics = "ATMOS_MECH", + /obj/machinery/portable_atmospherics = "PORT_ATMOS", + /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack = "MECHA_MISSILE_RACK", + /obj/item/mecha_parts/mecha_equipment = "MECHA_EQUIP", + /obj/item/organ = "ORGAN", + /obj/item = "ITEM", + /obj/machinery = "MACHINERY", + /obj/effect = "EFFECT", + /obj = "O", + /datum = "D", + /turf/simulated/floor = "FLOOR", + /turf/simulated/wall = "WALL", + /turf = "T", + /mob/living/carbon = "CARBON", + /mob/living/simple_animal = "SIMPLE", + /mob/living = "LIVING", + /mob = "M" + ) + for(var/tn in TYPES_SHORTCUTS) + if(copytext(typename, 1, length("[tn]/") + 1) == "[tn]/") + typename = TYPES_SHORTCUTS[tn]+copytext(typename,length("[tn]/")) + break + .[typename] = type -var/list/TYPES_SHORTCUTS = list( - /obj/effect/decal/cleanable = "CLEANABLE", - /obj/item/device/radio/headset = "HEADSET", - /obj/item/clothing/head/helmet/space = "SPESSHELMET", - /obj/item/weapon/book/manual = "MANUAL", - /obj/item/weapon/reagent_containers/food/drinks = "DRINK", //longest paths comes first - /obj/item/weapon/reagent_containers/food = "FOOD", - /obj/item/weapon/reagent_containers = "REAGENT_CONTAINERS", - /obj/machinery/atmospherics = "ATMOS", - /obj/machinery/portable_atmospherics = "PORT_ATMOS", -// /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/missile_rack = "MECHA_MISSILE_RACK", - /obj/item/mecha_parts/mecha_equipment = "MECHA_EQUIP", -// /obj/item/organ/internal = "ORGAN_INT", -) -var/global/list/g_fancy_list_of_types = null -/proc/get_fancy_list_of_types() - if(isnull(g_fancy_list_of_types)) //init - var/list/temp = sortList(subtypesof(/atom) - typesof(/area) - /atom/movable) - g_fancy_list_of_types = new(temp.len) - for(var/type in temp) - var/typename = "[type]" - for(var/tn in TYPES_SHORTCUTS) - if(copytext(typename,1, length("[tn]/")+1)=="[tn]/" /*findtextEx(typename,"[tn]/",1,2)*/ ) - typename = TYPES_SHORTCUTS[tn]+copytext(typename,length("[tn]/")) - break - g_fancy_list_of_types[typename] = type - return g_fancy_list_of_types +/proc/get_fancy_list_of_atom_types() + var/static/list/pre_generated_list + if(!pre_generated_list) //init + pre_generated_list = make_types_fancy(typesof(/atom)) + return pre_generated_list + + +/proc/get_fancy_list_of_datum_types() + var/static/list/pre_generated_list + if(!pre_generated_list) //init + pre_generated_list = make_types_fancy(sortList(typesof(/datum) - typesof(/atom))) + return pre_generated_list + /proc/filter_fancy_list(list/L, filter as text) var/list/matches = new diff --git a/code/datums/datumvars.dm b/code/datums/datumvars.dm index 9b3d413e94d..b7ac60b84d7 100644 --- a/code/datums/datumvars.dm +++ b/code/datums/datumvars.dm @@ -1,441 +1,519 @@ // reference: /client/proc/modify_variables(var/atom/O, var/param_var_name = null, var/autodetect_class = 0) /datum - var/var_edited = 0 //Warrenty void if seal is broken + var/var_edited = FALSE //Warranty void if seal is broken -/datum/proc/on_varedit(modified_var) //called whenever a var is edited - var_edited = 1 +/datum/proc/can_vv_get(var_name) + return TRUE + +/client/proc/can_vv_get(var_name) + return TRUE + +/datum/proc/vv_edit_var(var_name, var_value) //called whenever a var is edited + switch(var_name) + if("vars") + return FALSE + if("var_edited") + return FALSE + var_edited = TRUE + vars[var_name] = var_value + +/client/proc/vv_edit_var(var_name, var_value) //called whenever a var is edited + switch(var_name) + if("vars") + return FALSE + if("var_edited") + return FALSE + var_edited = TRUE + vars[var_name] = var_value + +/datum/proc/vv_get_var(var_name) + switch(var_name) + if("vars") + return debug_variable(var_name, list(), 0, src) + return debug_variable(var_name, vars[var_name], 0, src) + +/client/proc/vv_get_var(var_name) + switch(var_name) + if("vars") + return debug_variable(var_name, list(), 0, src) + return debug_variable(var_name, vars[var_name], 0, src) + +/datum/proc/can_vv_delete() + return TRUE + +//please call . = ..() first and append to the result, that way parent items are always at the top and child items are further down +//add seperaters by doing . += "---" +/datum/proc/vv_get_dropdown() + . = list() + . += "---" + .["Call Proc"] = "?_src_=vars;proc_call=[UID()]" + .["Mark Object"] = "?_src_=vars;mark_object=[UID()]" + .["Jump to Object"] = "?_src_=vars;jump_to=[UID()]" + .["Delete"] = "?_src_=vars;delete=[UID()]" + . += "---" + +/client/proc/vv_get_dropdown() + . = list() + . += "---" + .["Call Proc"] = "?_src_=vars;proc_call=[UID()]" + .["Mark Object"] = "?_src_=vars;mark_object=[UID()]" + .["Delete"] = "?_src_=vars;delete=[UID()]" + . += "---" /client/proc/debug_variables(datum/D in world) set category = "Debug" set name = "View Variables" - //set src in world + var/static/cookieoffset = rand(1, 9999) //to force cookies to reset after the round. if(!is_admin(usr)) to_chat(usr, "You need to be an administrator to access this.") return + if(!D) + return + + + var/islist = islist(D) + var/isclient = isclient(D) + if(!islist && !isclient && !istype(D)) + return var/title = "" - var/list/body = list() + var/icon/sprite + var/hash + var/refid - if(!D) return - if(istype(D, /atom)) - var/atom/A = D - title = "[A.name] (\ref[A]) = [A.type]" - - #ifdef VARSICON - if(A.icon) - body += debug_variable("icon", new/icon(A.icon, A.icon_state, A.dir), 0) - #endif - - var/sprite - - if(istype(D,/atom)) - var/atom/AT = D - if(AT.icon && AT.icon_state) - sprite = 1 - - title = "[D] (\ref[D]) = [D.type]" - - body += {" "} - - body += "" - - body += "
" - - if(sprite) - body += "" - - body += "
[bicon(D, use_class=0)]" + if(!islist) + refid = "[D.UID()]" else - body += "
" + refid = "\ref[D]" - body += "
" + var/type = /list + if(!islist) + type = D.type - if(istype(D,/atom)) + if(isatom(D)) + var/atom/A = D + if(A.icon && A.icon_state) + sprite = new /icon(A.icon, A.icon_state) + hash = md5(A.icon) + hash = md5(hash + A.icon_state) + usr << browse_rsc(sprite, "vv[hash].png") + + + var/sprite_text + if(sprite) + sprite_text = "
" + + + var/list/atomsnowflake = list() + if(isatom(D)) var/atom/A = D if(isliving(A)) - body += "[D]" - if(A.dir) - body += "
<< [dir2text(A.dir)] >>" - var/mob/living/M = A - body += "
[M.ckey ? M.ckey : "No ckey"] / [M.real_name ? M.real_name : "No real name"]" - body += {" -
- BRUTE:[M.getBruteLoss()] - FIRE:[M.getFireLoss()] - TOXIN:[M.getToxLoss()] - OXY:[M.getOxyLoss()] - CLONE:[M.getCloneLoss()] - BRAIN:[M.getBrainLoss()] - - - + var/mob/living/L = A + atomsnowflake += "[L]" + if(L.dir) + atomsnowflake += "
<< [dir2text(L.dir)] >>" + atomsnowflake += {" +
[L.ckey ? L.ckey : "No ckey"] / [L.real_name ? L.real_name : "No real name"] +
+ BRUTE:[L.getBruteLoss()] + FIRE:[L.getFireLoss()] + TOXIN:[L.getToxLoss()] + OXY:[L.getOxyLoss()] + CLONE:[L.getCloneLoss()] + BRAIN:[L.getBrainLoss()] + STAMINA:[L.getStaminaLoss()] + "} else - body += "[D]" + atomsnowflake += "[A]" if(A.dir) - body += "
<< [dir2text(A.dir)] >>" + atomsnowflake += "
<< [dir2text(A.dir)] >>" else - body += "[D]" + atomsnowflake += "[D]" - body += "" - body += "
" - - var/formatted_type = text("[D.type]") + var/formatted_type = "[type]" if(length(formatted_type) > 25) var/middle_point = length(formatted_type) / 2 - var/splitpoint = findtext(formatted_type,"/",middle_point) + var/splitpoint = findtext(formatted_type, "/", middle_point) if(splitpoint) - formatted_type = "[copytext(formatted_type,1,splitpoint)]
[copytext(formatted_type,splitpoint)]" + formatted_type = "[copytext(formatted_type, 1, splitpoint)]
[copytext(formatted_type, splitpoint)]" else formatted_type = "Type too long" //No suitable splitpoint (/) found. - body += "
[formatted_type]" - if(src.holder && src.holder.marked_datum && src.holder.marked_datum == D) - body += "
Marked Object" + var/marked + if(holder.marked_datum && holder.marked_datum == D) + marked = "
Marked Object" - if(D.var_edited) - body += "
Var Edited" - if(istype(D, /atom)) + var/varedited_line = "" + if(isatom(D)) var/atom/A = D if(A.admin_spawned) - body += "
Admin Spawned" - - body += "
" - - body += "
Refresh" - - body += {"
-
" - - body += "

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

" - - body += "
Search:

" - - body += "
    " var/list/names = list() - for(var/V in D.vars) - names += V + if(!islist) + for(var/V in D.vars) + names += V - names = sortList(names) - for(var/V in names) - body += debug_variable(V, D.vars[V], 0, D) + sleep(1) // Without a sleep here, VV sometimes disconnects clients - body += "
" - var/html = "" - if(title) - html += "[title]" - html += {""} - html += "" - html += body.Join("") + 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 + names = sortList(names) + for(var/V in names) + if(D.can_vv_get(V)) + variable_html += D.vv_get_var(V) - html += {" + var/html = {" + + + [title] + + + + +
+ + + + + +
+ + + + +
+ [sprite_text] +
+ [atomsnowflake.Join()] +
+
+
+ [formatted_type] + [marked] + [varedited_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()] +
+ + "} - html += "" - - usr << browse(html, "window=variables[D.UID()];size=475x650") - - return - -/client/proc/debug_variable(name, value, level, var/datum/DA = null) - var/list/html = list() + usr << browse(html, "window=variables[refid];size=475x650") +#define VV_HTML_ENCODE(thing) ( sanitize ? html_encode(thing) : thing ) +/proc/debug_variable(name, value, level, var/datum/DA = null, sanitize = TRUE) + var/header if(DA) - html += "
  • (E) (C) (M) " + 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 - html += "
  • " + header = "
  • " + var/item if(isnull(value)) - html += "[name] = null" + item = "[VV_HTML_ENCODE(name)] = null" else if(istext(value)) - html += "[name] = \"[value]\"" + item = "[VV_HTML_ENCODE(name)] = \"[VV_HTML_ENCODE(value)]\"" else if(isicon(value)) #ifdef VARSICON - html += "[name] = /icon ([value]) [bicon(value, use_class=0)]" + item = "[name] = /icon ([value]) [bicon(value, use_class=0)]" #else - html += "[name] = /icon ([value])" + item = "[name] = /icon ([value])" #endif - + else if(istype(value, /image)) var/image/I = value #ifdef VARSICON - html += "[name] \ref[value] = /image ([value]) [bicon(value, use_class=0)]" + item = "[name] \ref[value] = /image ([value]) [bicon(value, use_class=0)]" #else - html += "[name] \ref[value] = /image ([value])" - #endif - + item = "[name] \ref[value] = /image ([value])" + #endif + else if(isfile(value)) - html += "[name] = '[value]'" + item = "[VV_HTML_ENCODE(name)] = '[value]'" else if(istype(value, /datum)) var/datum/D = value - html += "[name] \ref[value] = [D.type]" + item = "[VV_HTML_ENCODE(name)] \ref[value] = [D.type]" else if(istype(value, /client)) var/client/C = value - html += "[name] \ref[value] = [C] [C.type]" + item = "[VV_HTML_ENCODE(name)] \ref[value] = [C] [C.type]" // - else if(istype(value, /list)) + else if(islist(value)) var/list/L = value - html += "[name] = /list ([L.len])" + var/list/items = list() - if(L.len > 0 && !(name == "underlays" || name == "overlays" || name == "vars" || L.len > 500)) - // not sure if this is completely right... - if(0) //(L.vars.len > 0) - html += "
      " - html += "
    " - else - html += "
      " - var/index = 1 - for(var/entry in L) - if(istext(entry)) - html += debug_variable(entry, L[entry], level + 1) - else - html += debug_variable(index, L[index], level + 1) - index++ - html += "
    " + if(L.len > 0 && !(name == "underlays" || name == "overlays" || name == "vars" || 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(!val) + 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 - html += "[name] = [value]" - /* - // Bitfield stuff - if(round(value)==value) // Require integers. - var/idx=0 - var/bit=0 - var/bv=0 - html += "
    " - for(var/block=0;block<8;block++) - html += " " - for(var/i=0;i<4;i++) - idx=(block*4)+i - to_chat(bit=1, idx) - bv=value & bit - html += "[bv?1:0]" - html += "" - html += "
    " - */ - html += "
  • " + item = "[VV_HTML_ENCODE(name)] = [VV_HTML_ENCODE(value)]" - return html.Join("") + return "[header][item]" + +#undef VV_HTML_ENCODE /client/proc/view_var_Topic(href, href_list, hsrc) //This should all be moved over to datum/admins/Topic() or something ~Carn if(!check_rights(R_ADMIN|R_MOD)) return + if(view_var_Topic_list(href, href_list, hsrc)) // done because you can't use UIDs with lists and I don't want to snowflake into the below check to supress warnings + return + // Correct and warn about any VV topic links that aren't using UIDs for(var/paramname in href_list) if(findtext(href_list[paramname], "]_")) @@ -516,6 +594,7 @@ body cmd_mass_modify_object_variables(A, href_list["varnamemass"]) + else if(href_list["mob_player_panel"]) if(!check_rights(R_ADMIN|R_MOD)) return @@ -645,6 +724,16 @@ body to_chat(M, "There were no ghosts willing to take control.") message_admins("No ghosts were willing to take control of [key_name_admin(M)])") + else if(href_list["delete"]) + if(!check_rights(R_DEBUG, 0)) + return + + var/datum/D = locateUID(href_list["delete"]) + if(!D) + to_chat(usr, "Unable to locate item!") + admin_delete(D) + href_list["datumrefresh"] = href_list["delete"] + else if(href_list["delall"]) if(!check_rights(R_DEBUG|R_SERVER)) return @@ -1099,6 +1188,7 @@ body if("oxygen")L.adjustOxyLoss(amount) if("brain") L.adjustBrainLoss(amount) if("clone") L.adjustCloneLoss(amount) + if("stamina") L.adjustStaminaLoss(amount) else to_chat(usr, "You caused an error. DEBUG: Text:[Text] Mob:[L]") return @@ -1110,8 +1200,123 @@ body if(href_list["datumrefresh"]) var/datum/DAT = locateUID(href_list["datumrefresh"]) - if(!istype(DAT, /datum)) + if(!istype(DAT, /datum) && !isclient(DAT)) return src.debug_variables(DAT) return + +/client/proc/view_var_Topic_list(href, href_list, hsrc) + if(href_list["VarsList"]) + debug_variables(locate(href_list["VarsList"])) + return TRUE + + if(href_list["listedit"] && href_list["index"]) + var/index = text2num(href_list["index"]) + if(!index) + return TRUE + + 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) + return TRUE + + if(href_list["listchange"] && href_list["index"]) + var/index = text2num(href_list["index"]) + if(!index) + return TRUE + + 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) + return TRUE + + if(href_list["listremove"] && href_list["index"]) + var/index = text2num(href_list["index"]) + if(!index) + return TRUE + + 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_to_dd("### 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]") + return TRUE + + 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 TRUE + + mod_list_add(L, null, "list", "contents") + return TRUE + + 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 TRUE + + uniqueList_inplace(L) + log_to_dd("### 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") + return TRUE + + 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 TRUE + + listclearnulls(L) + log_to_dd("### 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") + return TRUE + + 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 TRUE + var/value = vv_get_value(VV_NUM) + if(value["class"] != VV_NUM) + return TRUE + + L.len = value["value"] + log_to_dd("### 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]") + return TRUE + + 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 TRUE + + shuffle_inplace(L) + log_to_dd("### 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") + return TRUE + + if(href_list["listrefresh"]) + debug_variables(locate(href_list["listrefresh"])) + return TRUE \ No newline at end of file diff --git a/code/game/atoms.dm b/code/game/atoms.dm index 8c12e452d1d..22cadfaa659 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -616,7 +616,20 @@ var/list/blood_splatter_icons = list() /atom/proc/speech_bubble(var/bubble_state = "",var/bubble_loc = src, var/list/bubble_recipients = list()) return -/atom/on_varedit(modified_var) +/atom/vv_edit_var(var_name, var_value) if(!Debug2) admin_spawned = TRUE - ..() + . = ..() + switch(var_name) + if("light_power", "light_range", "light_color") + update_light() + + +/atom/vv_get_dropdown() + . = ..() + var/turf/curturf = get_turf(src) + if(curturf) + .["Jump to turf"] = "?_src_=holder;adminplayerobservecoodjump=1;X=[curturf.x];Y=[curturf.y];Z=[curturf.z]" + .["Add reagent"] = "?_src_=vars;addreagent=[UID()]" + .["Trigger explosion"] = "?_src_=vars;explode=[UID()]" + .["Trigger EM pulse"] = "?_src_=vars;emp=[UID()]" \ No newline at end of file diff --git a/code/game/objects/items/weapons/power_cells.dm b/code/game/objects/items/weapons/power_cells.dm index d291329f354..8996f97fbea 100644 --- a/code/game/objects/items/weapons/power_cells.dm +++ b/code/game/objects/items/weapons/power_cells.dm @@ -28,13 +28,14 @@ processing_objects.Remove(src) return ..() -/obj/item/weapon/stock_parts/cell/on_varedit(modified_var) - if(modified_var == "self_recharge") - if(self_recharge) - processing_objects.Add(src) - else - processing_objects.Remove(src) - ..() +/obj/item/weapon/stock_parts/cell/vv_edit_var(var_name, var_value) + switch(var_name) + if("self_recharge") + if(var_value) + processing_objects.Add(src) + else + processing_objects.Remove(src) + . = ..() /obj/item/weapon/stock_parts/cell/suicide_act(mob/user) to_chat(viewers(user), "[user] is licking the electrodes of the [src.name]! It looks like \he's trying to commit suicide.") diff --git a/code/game/objects/objs.dm b/code/game/objects/objs.dm index 197b742f307..60f9538fde0 100644 --- a/code/game/objects/objs.dm +++ b/code/game/objects/objs.dm @@ -310,4 +310,8 @@ a { Item.fire_act() //Set them on fire, too /obj/proc/on_mob_move(dir, mob/user) - return \ No newline at end of file + return + +/obj/vv_get_dropdown() + . = ..() + .["Delete all of type"] = "?_src_=vars;delall=[UID()]" diff --git a/code/modules/admin/holder2.dm b/code/modules/admin/holder2.dm index de22d5ea098..f3715eaab31 100644 --- a/code/modules/admin/holder2.dm +++ b/code/modules/admin/holder2.dm @@ -100,3 +100,9 @@ you will have to do something like if(client.holder.rights & R_ADMIN) yourself. return 0 return 1 return 0 + +/datum/admins/vv_edit_var(var_name, var_value) + return FALSE // no admin abuse + +/datum/admins/can_vv_delete() + return FALSE // don't break shit either \ No newline at end of file diff --git a/code/modules/admin/verbs/SDQL2/SDQL_2.dm b/code/modules/admin/verbs/SDQL2/SDQL_2.dm index 7b111e8ed20..859ff3ecf2b 100644 --- a/code/modules/admin/verbs/SDQL2/SDQL_2.dm +++ b/code/modules/admin/verbs/SDQL2/SDQL_2.dm @@ -89,8 +89,12 @@ if("delete") for(var/d in objs) - if(!datum_is_forbidden(d)) - qdel(d) + if(istype(d, /datum)) + var/datum/D = d + if(!D.can_vv_delete()) + to_chat(usr, "[D] rejected your deletion") + continue + qdel(d) if("select") var/text = "" @@ -118,9 +122,6 @@ if("set" in query_tree) var/list/set_list = query_tree["set"] for(var/d in objs) - // Forbid explicitly modifying an admin datum's vars - if(datum_is_forbidden(d)) - return for(var/list/sets in set_list) var/datum/temp = d var/i = 0 @@ -128,11 +129,10 @@ if(++i == sets.len) if(istype(temp, /turf) && (v == "x" || v == "y" || v == "z")) continue - if(!datum_is_forbidden(temp.vars[v])) - return - temp.vars[v] = SDQL_expression(d, set_list[sets]) + if(!temp.vv_edit_var(v, SDQL_expression(d, set_list[sets]))) + to_chat(usr, "[temp] rejected your varedit.") break - if(temp.vars.Find(v) && (istype(temp.vars[v], /datum) || istype(temp.vars[v], /client)) && !datum_is_forbidden(temp.vars[v])) + if(temp.vars.Find(v) && (istype(temp.vars[v], /datum) || istype(temp.vars[v], /client))) temp = temp.vars[v] else break @@ -440,11 +440,6 @@ for(var/arg in arguments) new_args[++new_args.len] = SDQL_expression(source, arg) - for(var/p in forbidden_varedit_object_types) - if(istype(object, p)) - to_chat(usr, "It is forbidden to run this object's procs.") - return - if(object == world) // Global proc. procname = "/proc/[procname]" return call(procname)(arglist(new_args)) diff --git a/code/modules/admin/verbs/massmodvar.dm b/code/modules/admin/verbs/massmodvar.dm index c7b2d6d537e..084057498bb 100644 --- a/code/modules/admin/verbs/massmodvar.dm +++ b/code/modules/admin/verbs/massmodvar.dm @@ -22,360 +22,251 @@ src.massmodify_variables(A, var_name, method) feedback_add_details("admin_verb","MEV") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! - -/client/proc/massmodify_variables(var/atom/O, var/var_name = "", var/method = 0) - if(!check_rights(R_VAREDIT)) return - - var/list/locked = list("vars", "key", "ckey", "client") - - for(var/p in forbidden_varedit_object_types) - if( istype(O,p) ) - to_chat(usr, "It is forbidden to edit this object's variables.") - return - - var/list/names = list() - for(var/V in O.vars) - names += V - - names = sortList(names) +/client/proc/massmodify_variables(datum/O, var_name = "", method = 0) + if(!check_rights(R_VAREDIT)) + return + if(!istype(O)) + return var/variable = "" - if(!var_name) - variable = input("Which var?","Var") as null|anything in names + var/list/names = list() + for(var/V in O.vars) + names += V + + names = sortList(names) + + variable = input("Which var?", "Var") as null|anything in names else variable = var_name - if(!variable) return + if(!variable || !O.can_vv_get(variable)) + return var/default var/var_value = O.vars[variable] - var/dir - if(variable == "holder" || (variable in locked)) - if(!check_rights(R_DEBUG)) return + if(variable in VVckey_edit) + to_chat(src, "It's forbidden to mass-modify ckeys. It'll crash everyone's client you dummy.") + return + if(variable in VVlocked) + if(!check_rights(R_DEBUG)) + return + if(variable in VVicon_edit_lock) + if(!check_rights(R_EVENT | R_DEBUG)) + return + if(variable in VVpixelmovement) + if(!check_rights(R_DEBUG)) + return + var/prompt = alert(src, "Editing this var may irreparably break tile gliding for the rest of the round. THIS CAN'T BE UNDONE", "DANGER", "ABORT ", "Continue", " ABORT") + if(prompt != "Continue") + return - if(isnull(var_value)) - to_chat(usr, "Unable to determine variable type.") - - else if(isnum(var_value)) - to_chat(usr, "Variable appears to be NUM.") - default = "num" - dir = 1 - - else if(istext(var_value)) - to_chat(usr, "Variable appears to be TEXT.") - default = "text" - - else if(isloc(var_value)) - to_chat(usr, "Variable appears to be REFERENCE.") - default = "reference" - - else if(isicon(var_value)) - to_chat(usr, "Variable appears to be ICON.") - var_value = "[bicon(var_value)]" - default = "icon" - - else if(istype(var_value,/atom) || istype(var_value,/datum)) - to_chat(usr, "Variable appears to be TYPE.") - default = "type" - - else if(istype(var_value,/list)) - to_chat(usr, "Variable appears to be LIST.") - default = "list" - - else if(istype(var_value,/client)) - to_chat(usr, "Variable appears to be CLIENT.") - default = "cancel" + default = vv_get_class(var_value) + if(isnull(default)) + to_chat(src, "Unable to determine variable type.") else - to_chat(usr, "Variable appears to be FILE.") - default = "file" + to_chat(src, "Variable appears to be [uppertext(default)].") - to_chat(usr, "Variable contains: [var_value]") - if(dir) - switch(var_value) - if(1) - dir = "NORTH" - if(2) - dir = "SOUTH" - if(4) - dir = "EAST" - if(8) - dir = "WEST" - if(5) - dir = "NORTHEAST" - if(6) - dir = "SOUTHEAST" - if(9) - dir = "NORTHWEST" - if(10) - dir = "SOUTHWEST" - else - dir = null - if(dir) - to_chat(usr, "If a direction, direction is: [dir]") + to_chat(src, "Variable contains: [var_value]") - var/class = input("What kind of variable?","Variable Type",default) as null|anything in list("text", - "num","type","icon","file","edit referenced object","restore to default") + if(default == VV_NUM) + var/dir_text = "" + if(dir < 0 && dir < 16) + if(dir & 1) + dir_text += "NORTH" + if(dir & 2) + dir_text += "SOUTH" + if(dir & 4) + dir_text += "EAST" + if(dir & 8) + dir_text += "WEST" - if(!class) + if(dir_text) + to_chat(src, "If a direction, direction is: [dir_text]") + + var/value = vv_get_value(default_class = default) + var/new_value = value["value"] + var/class = value["class"] + + if(!class || !new_value == null && class != VV_NULL) return - var/original_name + if(class == VV_MESSAGE) + class = VV_TEXT - if(!istype(O, /atom)) - original_name = "\ref[O] ([O])" - else - original_name = O:name + if(value["type"]) + class = VV_NEW_TYPE + + var/original_name = "[O]" + + var/rejected = 0 + var/accepted = 0 switch(class) + if(VV_RESTORE_DEFAULT) + to_chat(src, "Finding items...") + var/list/items = get_all_of_type(O.type, method) + to_chat(src, "Changing [items.len] items...") + for(var/thing in items) + if(!thing) + continue + var/datum/D = thing + if(D.vv_edit_var(variable, initial(D.vars[variable])) != FALSE) + accepted++ + else + rejected++ + CHECK_TICK - if("restore to default") - O.vars[variable] = initial(O.vars[variable]) - if(method) - if(istype(O, /mob)) - for(var/mob/M in mob_list) - if( istype(M , O.type) ) - M.vars[variable] = O.vars[variable] - M.on_varedit(variable) + if(VV_TEXT) + var/list/varsvars = vv_parse_text(O, new_value) + var/pre_processing = new_value + var/unique + if(varsvars && varsvars.len) + unique = alert(usr, "Process vars unique to each instance, or same for all?", "Variable Association", "Unique", "Same") + if(unique == "Unique") + unique = TRUE + else + unique = FALSE + for(var/V in varsvars) + new_value = replacetext(new_value,"\[[V]]","[O.vars[V]]") - else if(istype(O, /obj)) - for(var/obj/A in world) - if( istype(A , O.type) ) - A.vars[variable] = O.vars[variable] - A.on_varedit(variable) + to_chat(src, "Finding items...") + var/list/items = get_all_of_type(O.type, method) + to_chat(src, "Changing [items.len] items...") + for(var/thing in items) + if(!thing) + continue + var/datum/D = thing + if(unique) + new_value = pre_processing + for(var/V in varsvars) + new_value = replacetext(new_value,"\[[V]]","[D.vars[V]]") - else if(istype(O, /turf)) - for(var/turf/A in world) - if( istype(A , O.type) ) - A.vars[variable] = O.vars[variable] - A.on_varedit(variable) + if(D.vv_edit_var(variable, new_value) != FALSE) + accepted++ + else + rejected++ + CHECK_TICK + if(VV_NEW_TYPE) + var/many = alert(src, "Create only one [value["type"]] and assign each or a new one for each thing", "How Many", "One", "Many", "Cancel") + if(many == "Cancel") + return + if(many == "Many") + many = TRUE else - if(istype(O, /mob)) - for(var/mob/M in mob_list) - if(M.type == O.type) - M.vars[variable] = O.vars[variable] - M.on_varedit(variable) + many = FALSE - else if(istype(O, /obj)) - for(var/obj/A in world) - if(A.type == O.type) - A.vars[variable] = O.vars[variable] - A.on_varedit(variable) + var/type = value["type"] + to_chat(src, "Finding items...") + var/list/items = get_all_of_type(O.type, method) + to_chat(src, "Changing [items.len] items...") + for(var/thing in items) + if(!thing) + continue + var/datum/D = thing + if(many && !new_value) + new_value = new type() - else if(istype(O, /turf)) - for(var/turf/A in world) - if(A.type == O.type) - A.vars[variable] = O.vars[variable] - A.on_varedit(variable) + if(D.vv_edit_var(variable, new_value) != FALSE) + accepted++ + else + rejected++ + new_value = null + CHECK_TICK - if("edit referenced object") - return .(O.vars[variable]) + else + to_chat(src, "Finding items...") + var/list/items = get_all_of_type(O.type, method) + to_chat(src, "Changing [items.len] items...") + for(var/thing in items) + if(!thing) + continue + var/datum/D = thing + if(D.vv_edit_var(variable, new_value) != FALSE) + accepted++ + else + rejected++ + CHECK_TICK - if("text") - var/new_value = input("Enter new text:","Text",O.vars[variable]) as message|null - if(new_value == null) return - O.vars[variable] = new_value - if(method) - if(istype(O, /mob)) - for(var/mob/M in mob_list) - if( istype(M , O.type) ) - M.vars[variable] = O.vars[variable] + var/count = rejected+accepted + if(!count) + to_chat(src, "No objects found") + return + if(!accepted) + to_chat(src, "Every object rejected your edit") + return + if(rejected) + to_chat(src, "[rejected] out of [count] objects rejected your edit") - else if(istype(O, /obj)) - for(var/obj/A in world) - if( istype(A , O.type) ) - A.vars[variable] = O.vars[variable] + log_to_dd("### MassVarEdit by [src]: [O.type] (A/R [accepted]/[rejected]) [variable]=[html_encode("[O.vars[variable]]")]([list2params(value)])") + log_admin("[key_name(src)] mass modified [original_name]'s [variable] to [O.vars[variable]] ([accepted] objects modified)") + message_admins("[key_name_admin(src)] mass modified [original_name]'s [variable] to [O.vars[variable]] ([accepted] objects modified)") - else if(istype(O, /turf)) - for(var/turf/A in world) - if( istype(A , O.type) ) - A.vars[variable] = O.vars[variable] - else - if(istype(O, /mob)) - for(var/mob/M in mob_list) - if(M.type == O.type) - M.vars[variable] = O.vars[variable] +/proc/get_all_of_type(var/T, subtypes = TRUE) + var/list/typecache = list() + typecache[T] = 1 + if(subtypes) + typecache = typecacheof(typecache) + . = list() + if(ispath(T, /mob)) + for(var/mob/thing in mob_list) + if(typecache[thing.type]) + . += thing + CHECK_TICK - else if(istype(O, /obj)) - for(var/obj/A in world) - if(A.type == O.type) - A.vars[variable] = O.vars[variable] + else if(ispath(T, /obj/machinery/door)) + for(var/obj/machinery/door/thing in airlocks) + if(typecache[thing.type]) + . += thing + CHECK_TICK - else if(istype(O, /turf)) - for(var/turf/A in world) - if(A.type == O.type) - A.vars[variable] = O.vars[variable] + else if(ispath(T, /obj/machinery)) + for(var/obj/machinery/thing in machines) + if(typecache[thing.type]) + . += thing + CHECK_TICK - if("num") - var/new_value = input("Enter new number:","Num",\ - O.vars[variable]) as num|null - if(new_value == null) return + else if(ispath(T, /obj)) + for(var/obj/thing in world) + if(typecache[thing.type]) + . += thing + CHECK_TICK - if(variable=="light_range") - O.set_light(new_value) - else - O.vars[variable] = new_value + else if(ispath(T, /atom/movable)) + for(var/atom/movable/thing in world) + if(typecache[thing.type]) + . += thing + CHECK_TICK - if(method) - if(istype(O, /mob)) - for(var/mob/M in mob_list) - if( istype(M , O.type) ) - if(variable=="light_range") - M.set_light(new_value) - else - M.vars[variable] = O.vars[variable] + else if(ispath(T, /turf)) + for(var/turf/thing in world) + if(typecache[thing.type]) + . += thing + CHECK_TICK - else if(istype(O, /obj)) - for(var/obj/A in world) - if( istype(A , O.type) ) - if(variable=="light_range") - A.set_light(new_value) - else - A.vars[variable] = O.vars[variable] + else if(ispath(T, /atom)) + for(var/atom/thing in world) + if(typecache[thing.type]) + . += thing + CHECK_TICK - else if(istype(O, /turf)) - for(var/turf/A in world) - if( istype(A , O.type) ) - if(variable=="light_range") - A.set_light(new_value) - else - A.vars[variable] = O.vars[variable] + else if(ispath(T, /client)) + for(var/client/thing in clients) + if(typecache[thing.type]) + . += thing + CHECK_TICK - else - if(istype(O, /mob)) - for(var/mob/M in mob_list) - if(M.type == O.type) - if(variable=="light_range") - M.set_light(new_value) - else - M.vars[variable] = O.vars[variable] + else if(ispath(T, /datum)) + for(var/datum/thing) + if(typecache[thing.type]) + . += thing + CHECK_TICK - else if(istype(O, /obj)) - for(var/obj/A in world) - if(A.type == O.type) - if(variable=="light_range") - A.set_light(new_value) - else - A.vars[variable] = O.vars[variable] - - else if(istype(O, /turf)) - for(var/turf/A in world) - if(A.type == O.type) - if(variable=="light_range") - A.set_light(new_value) - else - A.vars[variable] = O.vars[variable] - - if("type") - var/new_value - new_value = input("Enter type:","Type",O.vars[variable]) as null|anything in typesof(/obj,/mob,/area,/turf) - if(new_value == null) return - O.vars[variable] = new_value - if(method) - if(istype(O, /mob)) - for(var/mob/M in mob_list) - if( istype(M , O.type) ) - M.vars[variable] = O.vars[variable] - - else if(istype(O, /obj)) - for(var/obj/A in world) - if( istype(A , O.type) ) - A.vars[variable] = O.vars[variable] - - else if(istype(O, /turf)) - for(var/turf/A in world) - if( istype(A , O.type) ) - A.vars[variable] = O.vars[variable] - else - if(istype(O, /mob)) - for(var/mob/M in mob_list) - if(M.type == O.type) - M.vars[variable] = O.vars[variable] - - else if(istype(O, /obj)) - for(var/obj/A in world) - if(A.type == O.type) - A.vars[variable] = O.vars[variable] - - else if(istype(O, /turf)) - for(var/turf/A in world) - if(A.type == O.type) - A.vars[variable] = O.vars[variable] - - if("file") - var/new_value = input("Pick file:","File",O.vars[variable]) as null|file - if(new_value == null) return - O.vars[variable] = new_value - - if(method) - if(istype(O, /mob)) - for(var/mob/M in mob_list) - if( istype(M , O.type) ) - M.vars[variable] = O.vars[variable] - - else if(istype(O.type, /obj)) - for(var/obj/A in world) - if( istype(A , O.type) ) - A.vars[variable] = O.vars[variable] - - else if(istype(O.type, /turf)) - for(var/turf/A in world) - if( istype(A , O.type) ) - A.vars[variable] = O.vars[variable] - else - if(istype(O, /mob)) - for(var/mob/M in mob_list) - if(M.type == O.type) - M.vars[variable] = O.vars[variable] - - else if(istype(O.type, /obj)) - for(var/obj/A in world) - if(A.type == O.type) - A.vars[variable] = O.vars[variable] - - else if(istype(O.type, /turf)) - for(var/turf/A in world) - if(A.type == O.type) - A.vars[variable] = O.vars[variable] - - if("icon") - var/new_value = input("Pick icon:","Icon",O.vars[variable]) as null|icon - if(new_value == null) return - O.vars[variable] = new_value - if(method) - if(istype(O, /mob)) - for(var/mob/M in mob_list) - if( istype(M , O.type) ) - M.vars[variable] = O.vars[variable] - - else if(istype(O, /obj)) - for(var/obj/A in world) - if( istype(A , O.type) ) - A.vars[variable] = O.vars[variable] - - else if(istype(O, /turf)) - for(var/turf/A in world) - if( istype(A , O.type) ) - A.vars[variable] = O.vars[variable] - - else - if(istype(O, /mob)) - for(var/mob/M in mob_list) - if(M.type == O.type) - M.vars[variable] = O.vars[variable] - - else if(istype(O, /obj)) - for(var/obj/A in world) - if(A.type == O.type) - A.vars[variable] = O.vars[variable] - - else if(istype(O, /turf)) - for(var/turf/A in world) - if(A.type == O.type) - A.vars[variable] = O.vars[variable] - - log_admin("[key_name(src)] mass modified [original_name]'s [variable] to [O.vars[variable]]") - message_admins("[key_name_admin(src)] mass modified [original_name]'s [variable] to [O.vars[variable]]", 1) \ No newline at end of file + else + for(var/datum/thing in world) + if(typecache[thing.type]) + . += thing + CHECK_TICK \ No newline at end of file diff --git a/code/modules/admin/verbs/modifyvariables.dm b/code/modules/admin/verbs/modifyvariables.dm index cb50d2e6391..0ad266ecaa1 100644 --- a/code/modules/admin/verbs/modifyvariables.dm +++ b/code/modules/admin/verbs/modifyvariables.dm @@ -1,294 +1,512 @@ -var/list/forbidden_varedit_object_types = list( - /datum/admins, //Admins editing their own admin-power object? Yup, sounds like a good idea. - /obj/machinery/blackbox_recorder, //Prevents people messing with feedback gathering - /datum/feedback_variable //Prevents people messing with feedback gathering - ) +var/list/VVlocked = list("vars", "var_edited", "client", "firemut", "ishulk", "telekinesis", "xray", "ka", "virus", "viruses", "cuffed", "last_eaten", "unlock_content") // R_DEBUG +var/list/VVicon_edit_lock = list("icon", "icon_state", "overlays", "underlays", "resize") // R_EVENT | R_DEBUG +var/list/VVckey_edit = list("key", "ckey") // R_EVENT | R_DEBUG +var/list/VVpixelmovement = list("step_x", "step_y", "bound_height", "bound_width", "bound_x", "bound_y") // R_DEBUG + warning +/client/proc/vv_get_class(var/var_value) + if(isnull(var_value)) + . = VV_NULL -/* -/client/proc/cmd_modify_object_variables(obj/O as obj|mob|turf|area in world) - set category = "Debug" - set name = "Edit Variables" - set desc="(target) Edit a target item's variables" - src.modify_variables(O) - feedback_add_details("admin_verb","EDITV") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! -*/ + else if(isnum(var_value)) + . = VV_NUM -/proc/datum_is_forbidden(type) - for(var/p in forbidden_varedit_object_types) - if(istype(type, p)) - to_chat(usr, "It is forbidden to tamper with this object.") - return FALSE - return TRUE + else if(istext(var_value)) + if(findtext(var_value, "\n")) + . = VV_MESSAGE + else + . = VV_TEXT + else if(isicon(var_value)) + . = VV_ICON -/client/proc/cmd_modify_ticker_variables() - set category = "Debug" - set name = "Edit Ticker Variables" + else if(ismob(var_value)) + . = VV_MOB_REFERENCE - if(ticker == null) - to_chat(src, "Game hasn't started yet.") + else if(isloc(var_value)) + . = VV_ATOM_REFERENCE + + else if(istype(var_value, /matrix)) + . = VV_MATRIX + + else if(istype(var_value,/client)) + . = VV_CLIENT + + else if(istype(var_value, /datum)) + . = VV_DATUM_REFERENCE + + else if(ispath(var_value)) + if(ispath(var_value, /atom)) + . = VV_ATOM_TYPE + else if(ispath(var_value, /datum)) + . = VV_DATUM_TYPE + else + . = VV_TYPE + + else if(islist(var_value)) + . = VV_LIST + + else if(isfile(var_value)) + . = VV_FILE else - src.modify_variables(ticker) - feedback_add_details("admin_verb","ETV") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + . = VV_NULL -/client/proc/mod_list_add_ass() //haha +/client/proc/vv_get_value(class, default_class, current_value, list/restricted_classes, list/extra_classes, list/classes) + . = list("class" = class, "value" = null) + if(!class) + if(!classes) + classes = list( + VV_NUM, + VV_TEXT, + VV_MESSAGE, + VV_ICON, + VV_ATOM_REFERENCE, + VV_DATUM_REFERENCE, + VV_MOB_REFERENCE, + VV_CLIENT, + VV_ATOM_TYPE, + VV_DATUM_TYPE, + VV_TYPE, + VV_MATRIX, + VV_FILE, + VV_NEW_ATOM, + VV_NEW_DATUM, + VV_NEW_TYPE, + VV_NEW_LIST, + VV_NULL, + VV_RESTORE_DEFAULT + ) - var/class = "text" - var/list/allowed_types = list("text", "num","type", "type from text","reference","mob reference", "icon","file","list","edit referenced object","restore to default") - if(src.holder && src.holder.marked_datum) - allowed_types += "marked datum ([holder.marked_datum.type])" - class = input("What kind of variable?","Variable Type") as null|anything in allowed_types + if(holder && holder.marked_datum && !(VV_MARKED_DATUM in restricted_classes)) + classes += "[VV_MARKED_DATUM] ([holder.marked_datum.type])" + if(restricted_classes) + classes -= restricted_classes + + if(extra_classes) + classes += extra_classes + + .["class"] = input(src, "What kind of data?", "Variable Type", default_class) as null|anything in classes + if(holder && holder.marked_datum && .["class"] == "[VV_MARKED_DATUM] ([holder.marked_datum.type])") + .["class"] = VV_MARKED_DATUM + + + switch(.["class"]) + if(VV_TEXT) + .["value"] = input("Enter new text:", "Text", current_value) as null|text + if(.["value"] == null) + .["class"] = null + return + if(VV_MESSAGE) + .["value"] = input("Enter new text:", "Text", current_value) as null|message + if(.["value"] == null) + .["class"] = null + return + + + if(VV_NUM) + .["value"] = input("Enter new number:", "Num", current_value) as null|num + if(.["value"] == null) + .["class"] = null + return + + + if(VV_ATOM_TYPE) + .["value"] = pick_closest_path(FALSE) + if(.["value"] == null) + .["class"] = null + return + + if(VV_DATUM_TYPE) + .["value"] = pick_closest_path(FALSE, get_fancy_list_of_datum_types()) + if(.["value"] == null) + .["class"] = null + return + + if(VV_TYPE) + var/type = current_value + var/error = "" + do + type = input("Enter type:[error]", "Type", type) as null|text + if(!type) + break + type = text2path(type) + error = "\nType not found, Please try again" + while(!type) + if(!type) + .["class"] = null + return + .["value"] = type + + if(VV_MATRIX) + .["value"] = text2matrix(input("Enter a, b, c, d, e, and f, seperated by a space.", "Matrix", "1 0 0 0 1 0") as null|text) + if(.["value"] == null) + .["class"] = null + return + + + if(VV_ATOM_REFERENCE) + var/type = pick_closest_path(FALSE) + var/subtypes = vv_subtype_prompt(type) + if(subtypes == null) + .["class"] = null + return + var/list/things = vv_reference_list(type, subtypes) + var/value = input("Select reference:", "Reference", current_value) as null|anything in things + if(!value) + .["class"] = null + return + .["value"] = things[value] + + if(VV_DATUM_REFERENCE) + var/type = pick_closest_path(FALSE, get_fancy_list_of_datum_types()) + var/subtypes = vv_subtype_prompt(type) + if(subtypes == null) + .["class"] = null + return + var/list/things = vv_reference_list(type, subtypes) + var/value = input("Select reference:", "Reference", current_value) as null|anything in things + if(!value) + .["class"] = null + return + .["value"] = things[value] + + if(VV_MOB_REFERENCE) + var/type = pick_closest_path(FALSE, make_types_fancy(typesof(/mob))) + var/subtypes = vv_subtype_prompt(type) + if(subtypes == null) + .["class"] = null + return + var/list/things = vv_reference_list(type, subtypes) + var/value = input("Select reference:", "Reference", current_value) as null|anything in things + if(!value) + .["class"] = null + return + .["value"] = things[value] + + + + if(VV_CLIENT) + .["value"] = input("Select reference:", "Reference", current_value) as null|anything in clients + if(.["value"] == null) + .["class"] = null + return + + + if(VV_FILE) + .["value"] = input("Pick file:", "File") as null|file + if(.["value"] == null) + .["class"] = null + return + + + if(VV_ICON) + .["value"] = input("Pick icon:", "Icon") as null|icon + if(.["value"] == null) + .["class"] = null + return + + + if(VV_MARKED_DATUM) + .["value"] = holder.marked_datum + if(.["value"] == null) + .["class"] = null + return + + if(VV_NEW_ATOM) + var/type = pick_closest_path(FALSE) + if(!type) + .["class"] = null + return + .["type"] = type + .["value"] = new type() + + if(VV_NEW_DATUM) + var/type = pick_closest_path(FALSE, get_fancy_list_of_datum_types()) + if(!type) + .["class"] = null + return + .["type"] = type + .["value"] = new type() + + if(VV_NEW_TYPE) + var/type = current_value + var/error = "" + do + type = input("Enter type:[error]", "Type", type) as null|text + if(!type) + break + type = text2path(type) + error = "\nType not found, Please try again" + while(!type) + if(!type) + .["class"] = null + return + .["type"] = type + .["value"] = new type() + + + if(VV_NEW_LIST) + .["value"] = list() + .["type"] = /list + +/client/proc/vv_parse_text(O, new_var) + if(O && findtext(new_var, "\[")) + var/process_vars = alert(usr, "\[] detected in string, process as variables?", "Process Variables?", "Yes", "No") + if(process_vars == "Yes") + . = string2listofvars(new_var, O) + +//do they want you to include subtypes? +//FALSE = no subtypes, strict exact type pathing (or the type doesn't have subtypes) +//TRUE = Yes subtypes +//NULL = User cancelled at the prompt or invalid type given +/client/proc/vv_subtype_prompt(var/type) + if(!ispath(type)) + return + var/list/subtypes = subtypesof(type) + if(!subtypes || !subtypes.len) + return FALSE + if(subtypes && subtypes.len) + switch(alert("Strict object type detection?", "Type detection", "Strictly this type","This type and subtypes", "Cancel")) + if("Strictly this type") + return FALSE + if("This type and subtypes") + return TRUE + else + return + +/client/proc/vv_reference_list(type, subtypes) + . = list() + var/list/types = list(type) + if(subtypes) + types = typesof(type) + + var/list/fancytypes = make_types_fancy(types) + + for(var/fancytype in fancytypes) //swap the assoication + types[fancytypes[fancytype]] = fancytype + + var/things = get_all_of_type(type, subtypes) + + var/i = 0 + for(var/thing in things) + var/datum/D = thing + i++ + //try one of 3 methods to shorten the type text: + // fancy type, + // fancy type with the base type removed from the begaining, + // the type with the base type removed from the begaining + var/fancytype = types[D.type] + if(findtext(fancytype, types[type])) + fancytype = copytext(fancytype, lentext(types[type])+1) + var/shorttype = copytext("[D.type]", lentext("[type]")+1) + if(lentext(shorttype) > lentext(fancytype)) + shorttype = fancytype + if(!lentext(shorttype)) + shorttype = "/" + + .["[D]([shorttype])\ref[D]#[i]"] = D + +/client/proc/mod_list_add_ass(atom/O) //haha + var/list/L = vv_get_value(restricted_classes = list(VV_RESTORE_DEFAULT)) + var/class = L["class"] if(!class) return + var/var_value = L["value"] - if(holder.marked_datum && class == "marked datum ([holder.marked_datum.type])") - class = "marked datum" - - var/var_value = null - - switch(class) - - if("text") - var_value = input("Enter new text:","Text") as null|message - - if("num") - var_value = input("Enter new number:","Num") as null|num - - if("type") - var_value = input("Enter type:","Type") as null|anything in typesof(/obj,/mob,/area,/turf) - - if("type from text") - var/type_text = input("Enter type:", "Type") as null|message - var_value = text2path(type_text) - if(!var_value) - to_chat(src, "[type_text] is not a valid path!") - - if("reference") - var_value = input("Select reference:","Reference") as null|mob|obj|turf|area in world - - if("mob reference") - var_value = input("Select reference:","Reference") as null|mob in world - - if("file") - var_value = input("Pick file:","File") as null|file - - if("icon") - var_value = input("Pick icon:","Icon") as null|icon - - if("marked datum") - var_value = holder.marked_datum - - if(!var_value) return + if(class == VV_TEXT || class == VV_MESSAGE) + var/list/varsvars = vv_parse_text(O, var_value) + for(var/V in varsvars) + var_value = replacetext(var_value,"\[[V]]","[O.vars[V]]") return var_value - -/client/proc/mod_list_add(var/list/L) - - var/class = "text" - var/list/allowed_types = list("text", "num","type", "type from text","reference","mob reference", "icon","file","list","edit referenced object","restore to default") - if(src.holder && src.holder.marked_datum) - allowed_types += "marked datum ([holder.marked_datum.type])" - class = input("What kind of variable?","Variable Type") as null|anything in allowed_types - +/client/proc/mod_list_add(list/L, atom/O, original_name, objectvar) + var/list/LL = vv_get_value(restricted_classes = list(VV_RESTORE_DEFAULT)) + var/class = LL["class"] if(!class) return + var/var_value = LL["value"] - if(holder.marked_datum && class == "marked datum ([holder.marked_datum.type])") - class = "marked datum" + if(class == VV_TEXT || class == VV_MESSAGE) + var/list/varsvars = vv_parse_text(O, var_value) + for(var/V in varsvars) + var_value = replacetext(var_value,"\[[V]]","[O.vars[V]]") - var/var_value = null + if(O) + L = L.Copy() - switch(class) + L += var_value - if("text") - var_value = input("Enter new text:","Text") as message|null - - if("num") - var_value = input("Enter new number:","Num") as num - - if("type") - var_value = input("Enter type:","Type") in typesof(/obj,/mob,/area,/turf) - - if("type from text") - var/type_text = input("Enter type:", "Type") as null|message - var_value = text2path(type_text) - if(!var_value) - to_chat(src, "[type_text] is not a valid path!") - - if("reference") - var_value = input("Select reference:","Reference") as mob|obj|turf|area in world - - if("mob reference") - var_value = input("Select reference:","Reference") as mob in world - - if("file") - var_value = input("Pick file:","File") as file - - if("icon") - var_value = input("Pick icon:","Icon") as icon - - if("marked datum") - var_value = holder.marked_datum - - if(!var_value) return - - switch(alert("Would you like to associate a var with the list entry?",,"Yes","No")) + switch(alert("Would you like to associate a value with the list entry?",,"Yes","No")) if("Yes") - L += var_value - L[var_value] = mod_list_add_ass() //haha - if("No") - L += var_value + L[var_value] = mod_list_add_ass(O) //hehe + if(O) + if(!O.vv_edit_var(objectvar, L)) + to_chat(src, "Your edit was rejected by the object.") + return + log_to_dd("### ListVarEdit by [src]: [(O ? O.type : "/list")] [objectvar]: ADDED=[var_value]") + log_admin("[key_name(src)] modified [original_name]'s [objectvar]: ADDED=[var_value]") + message_admins("[key_name_admin(src)] modified [original_name]'s [objectvar]: ADDED=[var_value]") -/client/proc/mod_list(var/list/L) - if(!check_rights(R_VAREDIT)) return - - if(!istype(L,/list)) +/client/proc/mod_list(list/L, atom/O, original_name, objectvar, index, autodetect_class = FALSE) + if(!check_rights(R_VAREDIT)) + return + if(!istype(L, /list)) to_chat(src, "Not a List.") + return + if(L.len > 1000) var/confirm = alert(src, "The list you're trying to edit is very long, continuing may crash the server.", "Warning", "Continue", "Abort") if(confirm != "Continue") return - var/list/locked = list("vars", "key", "ckey", "client", "firemut", "ishulk", "telekinesis", "xray", "virus", "viruses", "cuffed", "ka", "last_eaten", "urine", "poo", "icon", "icon_state", "step_x", "step_y") - var/assoc = 0 - if(L.len > 0) - var/a = L[1] - if(istext(a) && L[a] != null) - assoc = 1 //This is pretty weak test but i can't think of anything else - to_chat(usr, "List appears to be associative.") - var/list/names = null - if(!assoc) - names = sortList(L) + var/list/names = list() + for(var/i in 1 to L.len) + var/key = L[i] + var/value + if(IS_NORMAL_LIST(L) && !isnum(key)) + value = L[key] + if(value == null) + value = "null" + names["#[i] [key] = [value]"] = i + if(!index) + var/variable = input("Which var?","Var") as null|anything in names + "(ADD VAR)" + "(CLEAR NULLS)" + "(CLEAR DUPES)" + "(SHUFFLE)" + + if(variable == null) + return + + if(variable == "(ADD VAR)") + mod_list_add(L, O, original_name, objectvar) + return + + if(variable == "(CLEAR NULLS)") + L = L.Copy() + listclearnulls(L) + if(!O.vv_edit_var(objectvar, L)) + to_chat(src, "Your edit was rejected by the object.") + return + log_to_dd("### ListVarEdit by [src]: [O.type] [objectvar]: CLEAR NULLS") + log_admin("[key_name(src)] modified [original_name]'s [objectvar]: CLEAR NULLS") + message_admins("[key_name_admin(src)] modified [original_name]'s list [objectvar]: CLEAR NULLS") + return + + if(variable == "(CLEAR DUPES)") + L = uniqueList(L) + if(!O.vv_edit_var(objectvar, L)) + to_chat(src, "Your edit was rejected by the object.") + return + log_to_dd("### ListVarEdit by [src]: [O.type] [objectvar]: CLEAR DUPES") + log_admin("[key_name(src)] modified [original_name]'s [objectvar]: CLEAR DUPES") + message_admins("[key_name_admin(src)] modified [original_name]'s list [objectvar]: CLEAR DUPES") + return + + if(variable == "(SHUFFLE)") + L = shuffle(L) + if(!O.vv_edit_var(objectvar, L)) + to_chat(src, "Your edit was rejected by the object.") + return + log_to_dd("### ListVarEdit by [src]: [O.type] [objectvar]: SHUFFLE") + log_admin("[key_name(src)] modified [original_name]'s [objectvar]: SHUFFLE") + message_admins("[key_name_admin(src)] modified [original_name]'s list [objectvar]: SHUFFLE") + return + + index = names[variable] + - var/variable var/assoc_key - if(assoc) - variable = input("Which var?","Var") as null|anything in L + "(ADD VAR)" - else - variable = input("Which var?","Var") as null|anything in names + "(ADD VAR)" - - if(variable == "(ADD VAR)") - mod_list_add(L) + if(index == null) return - - if(assoc) - assoc_key = variable - variable = L[assoc_key] - - if(!assoc && !variable || assoc && !assoc_key) + var/assoc = 0 + var/prompt = alert(src, "Do you want to edit the key or it's assigned value?", "Associated List", "Key", "Assigned Value", "Cancel") + if(prompt == "Cancel") return - + if(prompt == "Assigned Value") + assoc = 1 + assoc_key = L[index] var/default + var/variable + if(assoc) + variable = L[assoc_key] + else + variable = L[index] - var/dir + default = vv_get_class(variable) - if(variable in locked) - if(!check_rights(R_DEBUG)) return + to_chat(src, "Variable appears to be [uppertext(default)].") - default = variable_to_type(variable) + to_chat(src, "Variable contains: [L[index]]") - to_chat(usr, "Variable contains: [variable]") - if(default == "num") - dir = dir2text(variable) + if(default == VV_NUM) + var/dir_text = "" + if(dir < 0 && dir < 16) + if(dir & 1) + dir_text += "NORTH" + if(dir & 2) + dir_text += "SOUTH" + if(dir & 4) + dir_text += "EAST" + if(dir & 8) + dir_text += "WEST" - if(dir) - to_chat(usr, "If a direction, direction is: [dir]") - - var/class = "text" - var/list/allowed_types = list("text", "num","type", "type from text", "reference","mob reference", "icon","file","list","edit referenced object","restore to default","DELETE FROM LIST") - if(src.holder && src.holder.marked_datum) - allowed_types += "marked datum ([holder.marked_datum.type])" - - class = input("What kind of variable?","Variable Type",default) as null|anything in allowed_types + if(dir_text) + to_chat(src, "If a direction, direction is: [dir_text]") + var/original_var + if(assoc) + original_var = L[assoc_key] + else + original_var = L[index] + if(O) + L = L.Copy() + var/class + if(autodetect_class) + if(default == VV_TEXT) + default = VV_MESSAGE + class = default + var/list/LL = vv_get_value(default_class = default, current_value = original_var, restricted_classes = list(VV_RESTORE_DEFAULT), extra_classes = list(VV_LIST, "DELETE FROM LIST")) + class = LL["class"] if(!class) return + var/new_var = LL["value"] - if(holder.marked_datum && class == "marked datum ([holder.marked_datum.type])") - class = "marked datum" + if(class == VV_MESSAGE) + class = VV_TEXT switch(class) //Spits a runtime error if you try to modify an entry in the contents list. Dunno how to fix it, yet. - - if("list") - mod_list(variable) - - if("restore to default") - if(assoc) - L[assoc_key] = initial(variable) - else - L[L.Find(variable)]=initial(variable) - - if("edit referenced object") - modify_variables(variable) + if(VV_LIST) + mod_list(variable, O, original_name, objectvar) if("DELETE FROM LIST") - L -= variable + L.Cut(index, index+1) + if(O) + if(!O.vv_edit_var(objectvar, L)) + to_chat(src, "Your edit was rejected by the object.") + return + log_to_dd("### ListVarEdit by [src]: [O.type] [objectvar]: REMOVED=[html_encode("[original_var]")]") + log_admin("[key_name(src)] modified [original_name]'s [objectvar]: REMOVED=[original_var]") + message_admins("[key_name_admin(src)] modified [original_name]'s [objectvar]: REMOVED=[original_var]") return - if("text") - if(assoc) - L[assoc_key] = input("Enter new text:","Text") as text - else - L[L.Find(variable)] = input("Enter new text:","Text") as text - - if("num") - if(assoc) - L[assoc_key] = input("Enter new number:","Num") as num - else - L[L.Find(variable)] = input("Enter new number:","Num") as num - - if("type") - if(assoc) - L[assoc_key] = input("Enter type:","Type") in typesof(/obj,/mob,/area,/turf) - else - L[L.Find(variable)] = input("Enter type:","Type") in typesof(/obj,/mob,/area,/turf) - - if("reference") - if(assoc) - L[assoc_key] = input("Select reference:","Reference") as mob|obj|turf|area in world - else - L[L.Find(variable)] = input("Select reference:","Reference") as mob|obj|turf|area in world - - if("mob reference") - if(assoc) - L[assoc_key] = input("Select reference:","Reference") as mob in world - else - L[L.Find(variable)] = input("Select reference:","Reference") as mob in world - - if("file") - if(assoc) - L[assoc_key] = input("Pick file:","File") as file - else - L[L.Find(variable)] = input("Pick file:","File") as file - - if("icon") - if(assoc) - L[assoc_key] = input("Pick icon:","Icon") as icon - else - L[L.Find(variable)] = input("Pick icon:","Icon") as icon - - if("marked datum") - if(assoc) - L[assoc_key] = holder.marked_datum - else - L[L.Find(variable)] = holder.marked_datum + if(VV_TEXT) + var/list/varsvars = vv_parse_text(O, new_var) + for(var/V in varsvars) + new_var = replacetext(new_var,"\[[V]]","[O.vars[V]]") -/client/proc/modify_variables(var/atom/O, var/param_var_name = null, var/autodetect_class = 0) - if(!check_rights(R_VAREDIT)) return - - var/list/locked = list("vars", "key", "ckey", "client", "firemut", "ishulk", "telekinesis", "xray", "virus", "cuffed", "ka", "last_eaten", "icon", "icon_state") - - for(var/p in forbidden_varedit_object_types) - if( istype(O,p) ) - to_chat(usr, "It is forbidden to edit this object's variables.") + if(assoc) + L[assoc_key] = new_var + else + L[index] = new_var + if(O) + if(!O.vv_edit_var(objectvar, L)) + to_chat(src, "Your edit was rejected by the object.") return + log_to_dd("### ListVarEdit by [src]: [(O ? O.type : "/list")] [objectvar]: [original_var]=[new_var]") + log_admin("[key_name(src)] modified [original_name]'s [objectvar]: [original_var]=[new_var]") + message_admins("[key_name_admin(src)] modified [original_name]'s varlist [objectvar]: [original_var]=[new_var]") - if(istype(O, /client) && (param_var_name == "ckey" || param_var_name == "key")) - to_chat(usr, "You cannot edit ckeys on client objects.") +/client/proc/modify_variables(atom/O, param_var_name = null, autodetect_class = 0) + if(!check_rights(R_VAREDIT)) return var/class @@ -297,24 +515,11 @@ var/list/forbidden_varedit_object_types = list( if(param_var_name) if(!param_var_name in O.vars) - to_chat(src, "A variable with this name ([param_var_name]) doesn't exist in this atom ([O])") + to_chat(src, "A variable with this name ([param_var_name]) doesn't exist in this datum ([O])") return - - if(param_var_name == "holder" || (param_var_name in locked)) - if(!check_rights(R_DEBUG)) return - variable = param_var_name - var_value = O.vars[variable] - - if(autodetect_class) - class = variable_to_type(var_value) - if(!class) - autodetect_class = null - else if(class == "num") - dir = 1 else - var/list/names = list() for(var/V in O.vars) names += V @@ -322,187 +527,92 @@ var/list/forbidden_varedit_object_types = list( names = sortList(names) variable = input("Which var?","Var") as null|anything in names - if(!variable) return - var_value = O.vars[variable] - - if(variable == "holder" || (variable in locked)) - if(!check_rights(R_DEBUG)) return - - if(!autodetect_class) - - var/dir - var/default - default = variable_to_type(var_value) - if(default == "num") - dir = 1 - else if(default == "icon") - var_value = "[bicon(var_value)]" - - to_chat(usr, "Variable contains: [var_value]") - if(dir) - dir = dir2text(var_value) - if(dir) - to_chat(usr, "If a direction, direction is: [dir]") - - var/list/allowed_types = list("text", "num","type","reference","mob reference", "path", "matrix", "icon","file","list","edit referenced object","restore to default") - if(src.holder && src.holder.marked_datum) - allowed_types += "marked datum ([holder.marked_datum.type])" - - class = input("What kind of variable?","Variable Type",default) as null|anything in allowed_types - - if(!class) + if(!variable) return - var/original_name + if(!O.can_vv_get(variable)) + return - if(!istype(O, /atom)) - original_name = "\ref[O] ([O])" + var_value = O.vars[variable] + + if(variable in VVlocked) + if(!check_rights(R_DEBUG)) + return + if(variable in VVckey_edit) + if(!check_rights(R_EVENT | R_DEBUG)) + return + if(variable in VVicon_edit_lock) + if(!check_rights(R_EVENT | R_DEBUG)) + return + if(variable in VVpixelmovement) + if(!check_rights(R_DEBUG)) + return + var/prompt = alert(src, "Editing this var may irreparably break tile gliding for the rest of the round. THIS CAN'T BE UNDONE", "DANGER", "ABORT ", "Continue", " ABORT") + if(prompt != "Continue") + return + + + var/default = vv_get_class(var_value) + + if(isnull(default)) + to_chat(src, "Unable to determine variable type.") else - original_name = O:name + to_chat(src, "Variable appears to be [uppertext(default)].") - if(holder.marked_datum && class == "marked datum ([holder.marked_datum.type])") - class = "marked datum" + to_chat(src, "Variable contains: [var_value]") + + if(default == VV_NUM) + var/dir_text = "" + if(dir < 0 && dir < 16) + if(dir & 1) + dir_text += "NORTH" + if(dir & 2) + dir_text += "SOUTH" + if(dir & 4) + dir_text += "EAST" + if(dir & 8) + dir_text += "WEST" + + if(dir_text) + to_chat(src, "If a direction, direction is: [dir_text]") + + if(autodetect_class && default != VV_NULL) + if(default == VV_TEXT) + default = VV_MESSAGE + class = default + + var/list/value = vv_get_value(class, default, var_value, extra_classes = list(VV_LIST)) + class = value["class"] + + if(!class) + return + var/var_new = value["value"] + + if(class == VV_MESSAGE) + class = VV_TEXT + + var/original_name = "[O]" - var/var_as_text = null switch(class) + if(VV_LIST) + if(!islist(var_value)) + mod_list(list(), O, original_name, variable) - if("list") - mod_list(O.vars[variable]) + mod_list(var_value, O, original_name, variable) return - if("restore to default") - O.vars[variable] = initial(O.vars[variable]) + if(VV_RESTORE_DEFAULT) + var_new = initial(O.vars[variable]) - if("edit referenced object") - return .(O.vars[variable]) + if(VV_TEXT) + var/list/varsvars = vv_parse_text(O, var_new) + for(var/V in varsvars) + var_new = replacetext(var_new,"\[[V]]","[O.vars[V]]") - if("text") - var/var_new = input("Enter new text:","Text",O.vars[variable]) as null|message - if(var_new==null) return - O.vars[variable] = var_new - - if("num") - if(variable=="light_range") - var/var_new = input("Enter new number:","Num",O.vars[variable]) as null|num - if(var_new == null) return - O.set_light(var_new) - else if(variable=="stat") // ow, but I guess I'm glad you're trying to prevent at least one kind of inconsistent state...? This is the VARIABLE EDITOR, I'm not sure we need to worry...? - var/var_new = input("Enter new number:","Num",O.vars[variable]) as null|num - if(var_new == null) return - if((O.vars[variable] == DEAD) && (var_new < DEAD))//Bringing the dead back to life - dead_mob_list -= O - living_mob_list += O - if((O.vars[variable] < DEAD) && (var_new == DEAD))//Kill he - living_mob_list -= O - dead_mob_list += O - O.vars[variable] = var_new - else - var/var_new = input("Enter new number:","Num",O.vars[variable]) as null|num - if(var_new==null) return - O.vars[variable] = var_new - - if("type") - var/var_new = input("Enter type:","Type",O.vars[variable]) as null|anything in typesof(/obj,/mob,/area,/turf) - if(var_new==null) return - O.vars[variable] = var_new - - if("path") - var/path_text = input("Enter path:", "Path",O.vars[variable]) as null|text - var/var_new = text2path(path_text) - if(!var_new && path_text != null) // So aborting doesn't bother the VVer - to_chat(usr, "[path_text] does not appear to be a valid path.") - return - O.vars[variable] = var_new - - if("matrix") - var/matrix_text = input("Enter a, b, c, d, e, and f, separated by a space.", "Matrix", "1 0 0 0 1 0") as null|text - var/var_new = text2matrix(matrix_text) - if(!var_new && matrix_text != null) - to_chat(usr, "[matrix_text] is not a valid matrix string.") - return - O.vars[variable] = var_new - var_as_text = "matrix([matrix_text])" - - if("reference") - var/var_new = input("Select reference:","Reference",O.vars[variable]) as null|mob|obj|turf|area in world - if(var_new==null) return - O.vars[variable] = var_new - - if("mob reference") - var/var_new = input("Select reference:","Reference",O.vars[variable]) as null|mob in world - if(var_new==null) return - O.vars[variable] = var_new - - if("file") - var/var_new = input("Pick file:","File",O.vars[variable]) as null|file - if(var_new==null) return - O.vars[variable] = var_new - - if("icon") - var/var_new = input("Pick icon:","Icon",O.vars[variable]) as null|icon - if(var_new==null) return - O.vars[variable] = var_new - - if("marked datum") - O.vars[variable] = holder.marked_datum - - if(var_as_text == null) - var_as_text = "[O.vars[variable]]" - O.on_varedit(variable) - log_to_dd("### VarEdit by [src]: [O.type] [variable]=[html_encode("[var_as_text]")]") - log_admin("[key_name(src)] modified [original_name]'s [variable] to [var_as_text]") - message_admins("[key_name_admin(src)] modified [original_name]'s [variable] to [var_as_text]", 1) - -// Let's get this all in one place. -// You'll need to take care of setting dir or iconizing the variable yourself once you've called this -/proc/variable_to_type(var/variable) - var/class - if(isnull(variable)) - to_chat(usr, "Unable to determine variable type.") - class = null - else if(isnum(variable)) - to_chat(usr, "Variable appears to be NUM.") - class = "num" - - else if(istext(variable)) - to_chat(usr, "Variable appears to be TEXT.") - class = "text" - - else if(isloc(variable)) - to_chat(usr, "Variable appears to be REFERENCE.") - class = "reference" - - else if(isicon(variable)) - to_chat(usr, "Variable appears to be ICON.") - variable = "[bicon(variable)]" - class = "icon" - - else if(istype(variable,/matrix)) - to_chat(usr, "Variable appears to be MATRIX") - class = "matrix" - - else if(istype(variable,/atom) || istype(variable,/datum)) - to_chat(usr, "Variable appears to be TYPE.") - class = "type" - - else if(istype(variable,/list)) - to_chat(usr, "Variable appears to be LIST.") - class = "list" - - else if(istype(variable,/client)) - to_chat(usr, "Variable appears to be CLIENT.") - class = "cancel" - - else if(ispath(variable)) - to_chat(usr, "Variable appears to be PATH.") - class = "path" - - else if(isfile(variable)) - to_chat(usr, "Variable appears to be FILE.") - class = "file" - - else - to_chat(usr, "Variable type is UNKNOWN.") - class = null - - return class + if(!O.vv_edit_var(variable, var_new)) + to_chat(src, "Your edit was rejected by the object.") + return + log_to_dd("### VarEdit by [src]: [O.type] [variable]=[html_encode("[var_new]")]") + log_admin("[key_name(src)] modified [original_name]'s [variable] to [var_new]") + var/msg = "[key_name_admin(src)] modified [original_name]'s [variable] to [var_new]" + message_admins(msg) \ No newline at end of file diff --git a/code/modules/admin/verbs/randomverbs.dm b/code/modules/admin/verbs/randomverbs.dm index fdfbdfba6b2..ccae0db2988 100644 --- a/code/modules/admin/verbs/randomverbs.dm +++ b/code/modules/admin/verbs/randomverbs.dm @@ -588,22 +588,30 @@ Traitors and the like can also be revived with the previous role mostly intact. feedback_add_details("admin_verb","CCR") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! -/client/proc/cmd_admin_delete(atom/O as obj|mob|turf in view()) +/client/proc/cmd_admin_delete(atom/A as obj|mob|turf in view()) set category = "Admin" set name = "Delete" if(!check_rights(R_ADMIN)) return - if(alert(src, "Are you sure you want to delete:\n[O]\nat ([O.x], [O.y], [O.z])?", "Confirmation", "Yes", "No") == "Yes") - log_admin("[key_name(usr)] deleted [O] at ([O.x],[O.y],[O.z])") - message_admins("[key_name_admin(usr)] deleted [O] at ([O.x],[O.y],[O.z])", 1) + admin_delete(A) + +/client/proc/admin_delete(datum/D) + if(istype(D) && !D.can_vv_delete()) + to_chat(src, "[D] rejected your deletion") + return + var/atom/A = D + var/coords = istype(A) ? "at ([A.x], [A.y], [A.z])" : "" + if(alert(src, "Are you sure you want to delete:\n[D]\n[coords]?", "Confirmation", "Yes", "No") == "Yes") + log_admin("[key_name(usr)] deleted [D][coords]") + message_admins("[key_name_admin(usr)] deleted [D][coords]", 1) feedback_add_details("admin_verb","DEL") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! - if(istype(O, /turf)) - var/turf/T = O + if(isturf(D)) + var/turf/T = D T.ChangeTurf(/turf/space) - return - qdel(O) + else + qdel(D) /client/proc/cmd_admin_list_open_jobs() set category = "Admin" diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index 82c478ce0da..6a223324268 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -2033,7 +2033,21 @@ ..() -mob/living/carbon/human/get_taste_sensitivity() + +/mob/living/carbon/human/vv_get_dropdown() + . = ..() + . += "---" + .["Set Species"] = "?_src_=vars;setspecies=[UID()]" + .["Make AI"] = "?_src_=vars;makeai=[UID()]" + .["Make Mask of Nar'sie"] = "?_src_=vars;makemask=[UID()]" + .["Make cyborg"] = "?_src_=vars;makerobot=[UID()]" + .["Make monkey"] = "?_src_=vars;makemonkey=[UID()]" + .["Make alien"] = "?_src_=vars;makealien=[UID()]" + .["Make slime"] = "?_src_=vars;makeslime=[UID()]" + .["Make superhero"] = "?_src_=vars;makesuper=[UID()]" + . += "---" + +/mob/living/carbon/human/get_taste_sensitivity() if(species) return species.taste_sensitivity else diff --git a/code/modules/mob/living/update_status.dm b/code/modules/mob/living/update_status.dm index 9466806a78b..f7498392c02 100644 --- a/code/modules/mob/living/update_status.dm +++ b/code/modules/mob/living/update_status.dm @@ -97,8 +97,9 @@ /mob/living/proc/update_stamina() return -/mob/living/on_varedit(modified_var) - switch(modified_var) +/mob/living/vv_edit_var(var_name, var_value) + . = ..() + switch(var_name) if("weakened") SetWeakened(weakened) if("stunned") @@ -120,5 +121,4 @@ if("maxHealth") updatehealth() if("resize") - update_transform() - ..() \ No newline at end of file + update_transform() \ No newline at end of file diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index 03bc97c2d73..85028040cdc 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -1237,3 +1237,31 @@ var/list/slot_equipment_priority = list( \ attack_log += new_log last_log = world.timeofday + +/mob/vv_get_dropdown() + . = ..() + .["Show player panel"] = "?_src_=vars;mob_player_panel=[UID()]" + + .["Give Spell"] = "?_src_=vars;give_spell=[UID()]" + .["Give Disease"] = "?_src_=vars;give_disease=[UID()]" + .["Toggle Godmode"] = "?_src_=vars;godmode=[UID()]" + .["Toggle Build Mode"] = "?_src_=vars;build_mode=[UID()]" + + .["Make 2spooky"] = "?_src_=vars;make_skeleton=[UID()]" + + .["Assume Direct Control"] = "?_src_=vars;direct_control=[UID()]" + .["Offer Control to Ghosts"] = "?_src_=vars;offer_control=[UID()]" + .["Drop Everything"] = "?_src_=vars;drop_everything=[UID()]" + + .["Regenerate Icons"] = "?_src_=vars;regenerateicons=[UID()]" + .["Add Language"] = "?_src_=vars;addlanguage=[UID()]" + .["Remove Language"] = "?_src_=vars;remlanguage=[UID()]" + .["Add Organ"] = "?_src_=vars;addorgan=[UID()]" + .["Remove Organ"] = "?_src_=vars;remorgan=[UID()]" + + .["Fix NanoUI"] = "?_src_=vars;fix_nano=[UID()]" + + .["Add Verb"] = "?_src_=vars;addverb=[UID()]" + .["Remove Verb"] = "?_src_=vars;remverb=[UID()]" + + .["Gib"] = "?_src_=vars;gib=[UID()]" \ No newline at end of file diff --git a/code/modules/projectiles/guns/energy.dm b/code/modules/projectiles/guns/energy.dm index 7b848dca5c7..1d05f415f51 100644 --- a/code/modules/projectiles/guns/energy.dm +++ b/code/modules/projectiles/guns/energy.dm @@ -163,13 +163,14 @@ playsound(loc, 'sound/weapons/empty.ogg', 50, 1, -1) return (OXYLOSS) -/obj/item/weapon/gun/energy/on_varedit(modified_var) - if(modified_var == "selfcharge") - if(selfcharge) - processing_objects.Add(src) - else - processing_objects.Remove(src) - ..() +/obj/item/weapon/gun/energy/vv_edit_var(var_name, var_value) + switch(var_name) + if("selfcharge") + if(var_value) + processing_objects.Add(src) + else + processing_objects.Remove(src) + . = ..() /obj/item/weapon/gun/energy/proc/robocharge() if(isrobot(loc)) diff --git a/code/modules/research/message_server.dm b/code/modules/research/message_server.dm index 52fa9596d92..86d507d34de 100644 --- a/code/modules/research/message_server.dm +++ b/code/modules/research/message_server.dm @@ -140,6 +140,9 @@ var/global/list/obj/machinery/message_server/message_servers = list() variable = param_variable value = param_value +/datum/feedback_variable/vv_edit_var(var_name, var_value) + return FALSE // come on guys don't break the stats + /datum/feedback_variable/proc/inc(var/num = 1) if(isnum(value)) value += num @@ -189,6 +192,7 @@ var/global/list/obj/machinery/message_server/message_servers = list() var/obj/machinery/blackbox_recorder/blackbox +//TODO: kill whoever designed this cancer /obj/machinery/blackbox_recorder icon = 'icons/obj/stationobjs.dmi' icon_state = "blackbox" @@ -314,6 +318,9 @@ var/obj/machinery/blackbox_recorder/blackbox var/DBQuery/query_insert = dbcon.NewQuery(sql) query_insert.Execute() +/obj/machinery/blackbox_recorder/vv_edit_var(var_name, var_value) + return FALSE // don't fuck with the stupid blackbox shit + proc/feedback_set(var/variable,var/value) if(!blackbox) return diff --git a/paradise.dme b/paradise.dme index dd05488bf3c..fb3c89d71b0 100644 --- a/paradise.dme +++ b/paradise.dme @@ -52,6 +52,8 @@ #include "code\__DEFINES\sound.dm" #include "code\__DEFINES\stat.dm" #include "code\__DEFINES\tick.dm" +#include "code\__DEFINES\typeids.dm" +#include "code\__DEFINES\vv.dm" #include "code\__DEFINES\zlevel.dm" #include "code\__HELPERS\_string_lists.dm" #include "code\__HELPERS\AnimationLibrary.dm"