VV Refactor

Ports /tg/'s VV refactor. Most of this is just cleaning up and making it
easier on the coders, but everyone else benefits too:

 - Mass mod no longer freezes the server (CHECK_TICK <3)
 - Attempting to change any of the step_* values or anything that will
 otherwise disable pixel movement will now prompt you and ask if you are
 sure you want to continue
 - You can actually enter |text| again in a box, rather than being
 forced to always use the multi-line input
 - Cookies! VV saves your search and scroll position for a given UID,
 rather convenient for debugging
 - The refresh button on /clients works finally
 - You can view lists in detail by clicking on them like any other
 reference, and edit them directly that way. This also means there is no
 hard limit on how many variables you can see in a list before it's
 truncated- it will just be hidden until you view the list in VV
 directly.
 - You can shuffle lists and clear duplicate/null entries.
 - Mildly reordered the stuff in the dropdown, inconvenient but
 necessary.
This commit is contained in:
tigercat2000
2017-09-14 14:08:38 -07:00
parent eb69af1321
commit 60e287c019
18 changed files with 1520 additions and 1128 deletions
+6
View File
@@ -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)
+21
View File
@@ -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"
+25
View File
@@ -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<L.len, ++i)
L.Swap(i,rand(i,L.len))
//Return a list with no duplicate entries
/proc/uniqueList(list/L)
. = list()
for(var/i in L)
. |= i
//same, but returns nothing and acts on list in place (also handles associated values properly)
/proc/uniqueList_inplace(list/L)
var/temp = L.Copy()
L.len = 0
for(var/key in temp)
if(isnum(key))
L |= key
else
L[key] = temp[key]
+37
View File
@@ -328,3 +328,40 @@
var/e = matrix_list[5]
var/f = matrix_list[6]
return matrix(a, b, c, d, e, f)
//This is a weird one:
//It returns a list of all var names found in the string
//These vars must be in the [var_name] format
//It's only a proc because it's used in more than one place
//Takes a string and a datum
//The string is well, obviously the string being checked
//The datum is used as a source for var names, to check validity
//Otherwise every single word could technically be a variable!
/proc/string2listofvars(var/t_string, var/datum/var_source)
if(!t_string || !var_source)
return list()
. = list()
var/var_found = findtext(t_string, "\[") //Not the actual variables, just a generic "should we even bother" check
if(var_found)
//Find var names
// "A dog said hi [name]!"
// splittext() --> 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
+1
View File
@@ -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
+61 -33
View File
@@ -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
+538 -345
View File
@@ -1,441 +1,517 @@
// 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)
//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, "<span class='warning'>You need to be an administrator to access this.</span>")
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 += {"<script type="text/javascript">
function updateSearch(){
var filter_text = document.getElementById('filter');
var filter = filter_text.value.toLowerCase();
if(event.keyCode == 13){ //Enter / return
var vars_ol = document.getElementById('vars');
var lis = vars_ol.getElementsByTagName("li");
for( var i = 0; i < lis.length; ++i )
{
try{
var li = lis\[i\];
if( li.style.backgroundColor == "#ffee88" )
{
alist = lis\[i\].getElementsByTagName("a")
if(alist.length > 0){
location.href=alist\[0\].href;
}
}
}catch(err) { }
}
return
}
if(event.keyCode == 38){ //Up arrow
var vars_ol = document.getElementById('vars');
var lis = vars_ol.getElementsByTagName("li");
for( var i = 0; i < lis.length; ++i )
{
try{
var li = lis\[i\];
if( li.style.backgroundColor == "#ffee88" )
{
if( (i-1) >= 0){
var li_new = lis\[i-1\];
li.style.backgroundColor = "white";
li_new.style.backgroundColor = "#ffee88";
return
}
}
}catch(err) { }
}
return
}
if(event.keyCode == 40){ //Down arrow
var vars_ol = document.getElementById('vars');
var lis = vars_ol.getElementsByTagName("li");
for( var i = 0; i < lis.length; ++i )
{
try{
var li = lis\[i\];
if( li.style.backgroundColor == "#ffee88" )
{
if( (i+1) < lis.length){
var li_new = lis\[i+1\];
li.style.backgroundColor = "white";
li_new.style.backgroundColor = "#ffee88";
return
}
}
}catch(err) { }
}
return
}
//This part here resets everything to how it was at the start so the filter is applied to the complete list. Screw efficiency, it's client-side anyway and it only looks through 200 or so variables at maximum anyway (mobs).
if(complete_list != null && complete_list != ""){
var vars_ol1 = document.getElementById("vars");
vars_ol1.innerHTML = complete_list
}
if(filter.value == ""){
return;
}else{
var vars_ol = document.getElementById('vars');
var lis = vars_ol.getElementsByTagName("li");
for( var i = 0; i < lis.length; ++i )
{
try{
var li = lis\[i\];
if( li.innerText.toLowerCase().indexOf(filter) == -1 )
{
vars_ol.removeChild(li);
i--;
}
}catch(err) { }
}
}
var lis_new = vars_ol.getElementsByTagName("li");
for( var j = 0; j < lis_new.length; ++j )
{
var li1 = lis\[j\];
if(j == 0){
li1.style.backgroundColor = "#ffee88";
}else{
li1.style.backgroundColor = "white";
}
}
}
function selectTextField(){
var filter_text = document.getElementById('filter');
filter_text.focus();
filter_text.select();
}
function loadPage(list) {
if(list.options\[list.selectedIndex\].value == ""){
return;
}
location.href=list.options\[list.selectedIndex\].value;
}
</script> "}
body += "<body onload='selectTextField(); updateSearch()' onkeyup='updateSearch()'>"
body += "<div align='center'><table width='100%'><tr><td width='50%'>"
if(sprite)
body += "<table align='center' width='100%'><tr><td>[bicon(D, use_class=0)]</td><td>"
if(!islist)
refid = "[D.UID()]"
else
body += "<table align='center' width='100%'><tr><td>"
refid = "\ref[D]"
body += "<div align='center'>"
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 = "<img src='vv[hash].png'></td><td>"
var/list/atomsnowflake = list()
if(isatom(D))
var/atom/A = D
if(isliving(A))
body += "<a href='?_src_=vars;rename=[D.UID()]'><b>[D]</b></a>"
if(A.dir)
body += "<br><font size='1'><a href='?_src_=vars;rotatedatum=[D.UID()];rotatedir=left'><<</a> <a href='?_src_=vars;datumedit=[D.UID()];varnameedit=dir'>[dir2text(A.dir)]</a> <a href='?_src_=vars;rotatedatum=[D.UID()];rotatedir=right'>>></a></font>"
var/mob/living/M = A
body += "<br><font size='1'><a href='?_src_=vars;datumedit=[D.UID()];varnameedit=ckey'>[M.ckey ? M.ckey : "No ckey"]</a> / <a href='?_src_=vars;datumedit=[D.UID()];varnameedit=real_name'>[M.real_name ? M.real_name : "No real name"]</a></font>"
body += {"
<br><font size='1'>
BRUTE:<font size='1'><a href='?_src_=vars;mobToDamage=[D.UID()];adjustDamage=brute'>[M.getBruteLoss()]</a>
FIRE:<font size='1'><a href='?_src_=vars;mobToDamage=[D.UID()];adjustDamage=fire'>[M.getFireLoss()]</a>
TOXIN:<font size='1'><a href='?_src_=vars;mobToDamage=[D.UID()];adjustDamage=toxin'>[M.getToxLoss()]</a>
OXY:<font size='1'><a href='?_src_=vars;mobToDamage=[D.UID()];adjustDamage=oxygen'>[M.getOxyLoss()]</a>
CLONE:<font size='1'><a href='?_src_=vars;mobToDamage=[D.UID()];adjustDamage=clone'>[M.getCloneLoss()]</a>
BRAIN:<font size='1'><a href='?_src_=vars;mobToDamage=[D.UID()];adjustDamage=brain'>[M.getBrainLoss()]</a>
</font>
var/mob/living/L = A
atomsnowflake += "<a href='?_src_=vars;rename=[L.UID()]'><b>[L]</b></a>"
if(L.dir)
atomsnowflake += "<br><font size='1'><a href='?_src_=vars;rotatedatum=[L.UID()];rotatedir=left'><<</a> <a href='?_src_=vars;datumedit=[L.UID()];varnameedit=dir'>[dir2text(L.dir)]</a> <a href='?_src_=vars;rotatedatum=[L.UID()];rotatedir=right'>>></a></font>"
atomsnowflake += {"
<br><font size='1'><a href='?_src_=vars;datumedit=[L.UID()];varnameedit=ckey'>[L.ckey ? L.ckey : "No ckey"]</a> / <a href='?_src_=vars;datumedit=[L.UID()];varnameedit=real_name'>[L.real_name ? L.real_name : "No real name"]</a></font>
<br><font size='1'>
BRUTE:<font size='1'><a href='?_src_=vars;mobToDamage=[L.UID()];adjustDamage=brute'>[L.getBruteLoss()]</a>
FIRE:<font size='1'><a href='?_src_=vars;mobToDamage=[L.UID()];adjustDamage=fire'>[L.getFireLoss()]</a>
TOXIN:<font size='1'><a href='?_src_=vars;mobToDamage=[L.UID()];adjustDamage=toxin'>[L.getToxLoss()]</a>
OXY:<font size='1'><a href='?_src_=vars;mobToDamage=[L.UID()];adjustDamage=oxygen'>[L.getOxyLoss()]</a>
CLONE:<font size='1'><a href='?_src_=vars;mobToDamage=[L.UID()];adjustDamage=clone'>[L.getCloneLoss()]</a>
BRAIN:<font size='1'><a href='?_src_=vars;mobToDamage=[L.UID()];adjustDamage=brain'>[L.getBrainLoss()]</a>
STAMINA:<font size='1'><a href='?_src_=vars;mobToDamage=[L.UID()];adjustDamage=stamina'>[L.getStaminaLoss()]</a>
</font>
"}
else
body += "<a href='?_src_=vars;datumedit=[D.UID()];varnameedit=name'><b>[D]</b></a>"
atomsnowflake += "<a href='?_src_=vars;datumedit=[A.UID()];varnameedit=name'><b>[A]</b></a>"
if(A.dir)
body += "<br><font size='1'><a href='?_src_=vars;rotatedatum=[D.UID()];rotatedir=left'><<</a> <a href='?_src_=vars;datumedit=[D.UID()];varnameedit=dir'>[dir2text(A.dir)]</a> <a href='?_src_=vars;rotatedatum=[D.UID()];rotatedir=right'>>></a></font>"
atomsnowflake += "<br><font size='1'><a href='?_src_=vars;rotatedatum=[A.UID()];rotatedir=left'><<</a> <a href='?_src_=vars;datumedit=[A.UID()];varnameedit=dir'>[dir2text(A.dir)]</a> <a href='?_src_=vars;rotatedatum=[D.UID()];rotatedir=right'>>></a></font>"
else
body += "<b>[D]</b>"
atomsnowflake += "<b>[D]</b>"
body += "</div>"
body += "</tr></td></table>"
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)]<br>[copytext(formatted_type,splitpoint)]"
formatted_type = "[copytext(formatted_type, 1, splitpoint)]<br>[copytext(formatted_type, splitpoint)]"
else
formatted_type = "Type too long" //No suitable splitpoint (/) found.
body += "<div align='center'><b><font size='1'>[formatted_type]</font></b>"
if(src.holder && src.holder.marked_datum && src.holder.marked_datum == D)
body += "<br><font size='1' color='red'><b>Marked Object</b></font>"
var/marked
if(holder.marked_datum && holder.marked_datum == D)
marked = "<br><font size='1' color='red'><b>Marked Object</b></font>"
if(D.var_edited)
body += "<br><font size='1' color='red'><b>Var Edited</b></font>"
if(istype(D, /atom))
var/varedited_line = ""
if(isatom(D))
var/atom/A = D
if(A.admin_spawned)
body += "<br><font size='1' color='red'><b>Admin Spawned</b></font>"
body += "</div>"
body += "</div></td>"
body += "<td width='50%'><div align='center'><a href='?_src_=vars;datumrefresh=[D.UID()]'>Refresh</a>"
body += {" <form>
<select name="file" size="1"
onchange="loadPage(this.form.elements\[0\])"
target="_parent._top"
onmouseclick="this.focus()"
style="background-color:#ffffff">
"}
body += {" <option value>Select option</option>
<option value> </option>
"}
varedited_line += "<br><font size='1' color='red'><b>Admin Spawned</b></font>"
body += "<option value='?_src_=vars;mark_object=[D.UID()]'>Mark Object</option>"
body += "<option value='?_src_=vars;proc_call=[D.UID()]'>Call Proc</option>"
body += "<option value='?_src_=vars;jump_to=[D.UID()]'>Jump to Object</option>"
if(ismob(D))
body += "<option value='?_src_=vars;mob_player_panel=[D.UID()]'>Show player panel</option>"
if(!islist && D.var_edited)
varedited_line += "<br><font size='1' color='red'><b>Var Edited</b></font>"
body += "<option value>---</option>"
if(ismob(D))
body += "<option value='?_src_=vars;give_spell=[D.UID()]'>Give Spell</option>"
body += "<option value='?_src_=vars;give_disease=[D.UID()]'>Give Disease</option>"
body += "<option value='?_src_=vars;godmode=[D.UID()]'>Toggle Godmode</option>"
body += "<option value='?_src_=vars;build_mode=[D.UID()]'>Toggle Build Mode</option>"
var/dropdownoptions = list()
if(islist)
dropdownoptions = list(
"---",
"Add Item" = "?_src_=vars;listadd=[refid]",
"Remove Nulls" = "?_src_=vars;listnulls=[refid]",
"Remove Dupes" = "?_src_=vars;listdupes=[refid]",
"Set len" = "?_src_=vars;listlen=[refid]",
"Shuffle" = "?_src_=vars;listshuffle=[refid]"
)
else
dropdownoptions = D.vv_get_dropdown()
body += "<option value='?_src_=vars;make_skeleton=[D.UID()]'>Make 2spooky</option>"
body += "<option value='?_src_=vars;direct_control=[D.UID()]'>Assume Direct Control</option>"
body += "<option value='?_src_=vars;offer_control=[D.UID()]'>Offer Control to Ghosts</option>"
body += "<option value='?_src_=vars;drop_everything=[D.UID()]'>Drop Everything</option>"
var/list/dropdownoptions_html = list()
for(var/name in dropdownoptions)
var/link = dropdownoptions[name]
if(link)
dropdownoptions_html += "<option value='[link]'>[name]</option>"
else
dropdownoptions_html += "<option value>[name]</option>"
body += "<option value='?_src_=vars;regenerateicons=[D.UID()]'>Regenerate Icons</option>"
body += "<option value='?_src_=vars;addlanguage=[D.UID()]'>Add Language</option>"
body += "<option value='?_src_=vars;remlanguage=[D.UID()]'>Remove Language</option>"
body += "<option value='?_src_=vars;addorgan=[D.UID()]'>Add Organ</option>"
body += "<option value='?_src_=vars;remorgan=[D.UID()]'>Remove Organ</option>"
body += "<option value='?_src_=vars;fix_nano=[D.UID()]'>Fix NanoUI</option>"
body += "<option value='?_src_=vars;addverb=[D.UID()]'>Add Verb</option>"
body += "<option value='?_src_=vars;remverb=[D.UID()]'>Remove Verb</option>"
if(ishuman(D))
body += "<option value>---</option>"
body += "<option value='?_src_=vars;setspecies=[D.UID()]'>Set Species</option>"
body += "<option value='?_src_=vars;makeai=[D.UID()]'>Make AI</option>"
body += "<option value='?_src_=vars;makemask=[D.UID()]'>Make Mask of Nar'sie</option>"
body += "<option value='?_src_=vars;makerobot=[D.UID()]'>Make cyborg</option>"
body += "<option value='?_src_=vars;makemonkey=[D.UID()]'>Make monkey</option>"
body += "<option value='?_src_=vars;makealien=[D.UID()]'>Make alien</option>"
body += "<option value='?_src_=vars;makeslime=[D.UID()]'>Make slime</option>"
body += "<option value='?_src_=vars;makesuper=[D.UID()]'>Make superhero</option>"
body += "<option value>---</option>"
body += "<option value='?_src_=vars;gib=[D.UID()]'>Gib</option>"
if(isobj(D))
body += "<option value='?_src_=vars;delall=[D.UID()]'>Delete all of type</option>"
if(isobj(D) || ismob(D) || isturf(D))
body += "<option value='?_src_=vars;addreagent=[D.UID()]'>Add reagent</option>"
body += "<option value='?_src_=vars;explode=[D.UID()]'>Trigger explosion</option>"
body += "<option value='?_src_=vars;emp=[D.UID()]'>Trigger EM pulse</option>"
body += "</select></form>"
body += "</div></td></tr></table></div><hr>"
body += "<font size='1'><b>E</b> - Edit, tries to determine the variable type by itself.<br>"
body += "<b>C</b> - Change, asks you for the var type first.<br>"
body += "<b>M</b> - Mass modify: changes this variable for all objects of this type.</font><br>"
body += "<hr><table width='100%'><tr><td width='20%'><div align='center'><b>Search:</b></div></td><td width='80%'><input type='text' id='filter' name='filter_text' value='' style='width:100%;'></td></tr></table><hr>"
body += "<ol id='vars'>"
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 += "</ol>"
var/html = "<html><head>"
if(title)
html += "<title>[title]</title>"
html += {"<style>
body
{
font-family: Verdana, sans-serif;
font-size: 9pt;
}
.value
{
font-family: "Courier New", monospace;
font-size: 8pt;
}
</style>"}
html += "</head><body>"
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 = {"
<html>
<head>
<title>[title]</title>
<style>
body {
font-family: Verdana, sans-serif;
font-size: 9pt;
}
.value {
font-family: "Courier New", monospace;
font-size: 8pt;
}
</style>
</head>
<body onload='selectTextField(); updateSearch()' onkeydown='return checkreload()' onkeyup='updateSearch()'>
<script type="text/javascript">
function checkreload() {
if(event.keyCode == 116){ //F5 (to refresh properly)
document.getElementById("refresh_link").click();
event.preventDefault ? event.preventDefault() : (event.returnValue = false)
return false;
}
return true;
}
function updateSearch(){
var filter_text = document.getElementById('filter');
var filter = filter_text.value.toLowerCase();
if(event.keyCode == 13){ //Enter / return
var vars_ol = document.getElementById('vars');
var lis = vars_ol.getElementsByTagName("li");
for ( var i = 0; i < lis.length; ++i )
{
try{
var li = lis\[i\];
if ( li.style.backgroundColor == "#ffee88" )
{
alist = lis\[i\].getElementsByTagName("a")
if(alist.length > 0){
location.href=alist\[0\].href;
}
}
}catch(err) { }
}
return
}
if(event.keyCode == 38){ //Up arrow
var vars_ol = document.getElementById('vars');
var lis = vars_ol.getElementsByTagName("li");
for ( var i = 0; i < lis.length; ++i )
{
try{
var li = lis\[i\];
if ( li.style.backgroundColor == "#ffee88" )
{
if( (i-1) >= 0){
var li_new = lis\[i-1\];
li.style.backgroundColor = "white";
li_new.style.backgroundColor = "#ffee88";
return
}
}
}catch(err) { }
}
return
}
if(event.keyCode == 40){ //Down arrow
var vars_ol = document.getElementById('vars');
var lis = vars_ol.getElementsByTagName("li");
for ( var i = 0; i < lis.length; ++i )
{
try{
var li = lis\[i\];
if ( li.style.backgroundColor == "#ffee88" )
{
if( (i+1) < lis.length){
var li_new = lis\[i+1\];
li.style.backgroundColor = "white";
li_new.style.backgroundColor = "#ffee88";
return
}
}
}catch(err) { }
}
return
}
//This part here resets everything to how it was at the start so the filter is applied to the complete list. Screw efficiency, it's client-side anyway and it only looks through 200 or so variables at maximum anyway (mobs).
if(complete_list != null && complete_list != ""){
var vars_ol1 = document.getElementById("vars");
vars_ol1.innerHTML = complete_list
}
document.cookie="[refid][cookieoffset]search="+encodeURIComponent(filter);
if(filter == ""){
return;
}else{
var vars_ol = document.getElementById('vars');
var lis = vars_ol.getElementsByTagName("li");
for ( var i = 0; i < lis.length; ++i )
{
try{
var li = lis\[i\];
if ( li.innerText.toLowerCase().indexOf(filter) == -1 )
{
vars_ol.removeChild(li);
i--;
}
}catch(err) { }
}
}
var lis_new = vars_ol.getElementsByTagName("li");
for ( var j = 0; j < lis_new.length; ++j )
{
var li1 = lis\[j\];
if (j == 0){
li1.style.backgroundColor = "#ffee88";
}else{
li1.style.backgroundColor = "white";
}
}
}
function selectTextField() {
var filter_text = document.getElementById('filter');
filter_text.focus();
filter_text.select();
var lastsearch = getCookie("[refid][cookieoffset]search");
if (lastsearch) {
filter_text.value = lastsearch;
updateSearch();
}
}
function loadPage(list) {
if(list.options\[list.selectedIndex\].value == ""){
return;
}
location.href=list.options\[list.selectedIndex\].value;
}
function getCookie(cname) {
var name = cname + "=";
var ca = document.cookie.split(';');
for(var i=0; i<ca.length; i++) {
var c = ca\[i\];
while (c.charAt(0)==' ') c = c.substring(1,c.length);
if (c.indexOf(name)==0) return c.substring(name.length,c.length);
}
return "";
}
</script>
<div align='center'>
<table width='100%'>
<tr>
<td width='50%'>
<table align='center' width='100%'>
<tr>
<td>
[sprite_text]
<div align='center'>
[atomsnowflake.Join()]
</div>
</td>
</tr>
</table>
<div align='center'>
<b><font size='1'>[formatted_type]</font></b>
[marked]
[varedited_line]
</div>
</td>
<td width='50%'>
<div align='center'>
<a id='refresh_link' href='?_src_=vars;[islist ? "listrefresh=\ref[D]" : "datumrefresh=[D.UID()]"]'>Refresh</a>
<form>
<select name="file" size="1"
onchange="loadPage(this.form.elements\[0\])"
target="_parent._top"
onmouseclick="this.focus()"
style="background-color:#ffffff">
<option value selected>Select option</option>
[dropdownoptions_html.Join()]
</select>
</form>
</div>
</td>
</tr>
</table>
</div>
<hr>
<font size='1'>
<b>E</b> - Edit, tries to determine the variable type by itself.<br>
<b>C</b> - Change, asks you for the var type first.<br>
<b>M</b> - Mass modify: changes this variable for all objects of this type.<br>
</font>
<hr>
<table width='100%'>
<tr>
<td width='20%'>
<div align='center'>
<b>Search:</b>
</div>
</td>
<td width='80%'>
<input type='text' id='filter' name='filter_text' value='' style='width:100%;'>
</td>
</tr>
</table>
<hr>
<ol id='vars'>
[variable_html.Join()]
</ol>
<script type='text/javascript'>
var vars_ol = document.getElementById("vars");
var complete_list = vars_ol.innerHTML;
</script>
</body>
</html>
"}
html += "</body></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 += "<li style='backgroundColor:white'>(<a href='?_src_=vars;datumedit=[DA.UID()];varnameedit=[name]'>E</a>) (<a href='?_src_=vars;datumchange=[DA.UID()];varnamechange=[name]'>C</a>) (<a href='?_src_=vars;datummass=[DA.UID()];varnamemass=[name]'>M</a>) "
if(islist(DA))
var/index = name
if(value)
name = DA[name] // name is really the index until this line
else
value = DA[name]
header = "<li style='backgroundColor:white'>(<a href='?_src_=vars;listedit=\ref[DA];index=[index]'>E</a>) (<a href='?_src_=vars;listchange=\ref[DA];index=[index]'>C</a>) (<a href='?_src_=vars;listremove=\ref[DA];index=[index]'>-</a>) "
else
header = "<li style='backgroundColor:white'>(<a href='?_src_=vars;datumedit=[DA.UID()];varnameedit=[name]'>E</a>) (<a href='?_src_=vars;datumchange=[DA.UID()];varnamechange=[name]'>C</a>) (<a href='?_src_=vars;datummass=[DA.UID()];varnamemass=[name]'>M</a>) "
else
html += "<li>"
header = "<li>"
var/item
if(isnull(value))
html += "[name] = <span class='value'>null</span>"
item = "[VV_HTML_ENCODE(name)] = <span class='value'>null</span>"
else if(istext(value))
html += "[name] = <span class='value'>\"[value]\"</span>"
item = "[VV_HTML_ENCODE(name)] = <span class='value'>\"[VV_HTML_ENCODE(value)]\"</span>"
else if(isicon(value))
#ifdef VARSICON
html += "[name] = /icon (<span class='value'>[value]</span>) [bicon(value, use_class=0)]"
item = "[name] = /icon (<span class='value'>[value]</span>) [bicon(value, use_class=0)]"
#else
html += "[name] = /icon (<span class='value'>[value]</span>)"
item = "[name] = /icon (<span class='value'>[value]</span>)"
#endif
else if(istype(value, /image))
var/image/I = value
#ifdef VARSICON
html += "<a href='?_src_=vars;Vars=[I.UID()]'>[name] \ref[value]</a> = /image (<span class='value'>[value]</span>) [bicon(value, use_class=0)]"
item = "<a href='?_src_=vars;Vars=[I.UID()]'>[name] \ref[value]</a> = /image (<span class='value'>[value]</span>) [bicon(value, use_class=0)]"
#else
html += "<a href='?_src_=vars;Vars=[I.UID()]'>[name] \ref[value]</a> = /image (<span class='value'>[value]</span>)"
#endif
item = "<a href='?_src_=vars;Vars=[I.UID()]'>[name] \ref[value]</a> = /image (<span class='value'>[value]</span>)"
#endif
else if(isfile(value))
html += "[name] = <span class='value'>'[value]'</span>"
item = "[VV_HTML_ENCODE(name)] = <span class='value'>'[value]'</span>"
else if(istype(value, /datum))
var/datum/D = value
html += "<a href='?_src_=vars;Vars=[D.UID()]'>[name] \ref[value]</a> = [D.type]"
item = "<a href='?_src_=vars;Vars=[D.UID()]'>[VV_HTML_ENCODE(name)] \ref[value]</a> = [D.type]"
else if(istype(value, /client))
var/client/C = value
html += "<a href='?_src_=vars;Vars=[C.UID()]'>[name] \ref[value]</a> = [C] [C.type]"
item = "<a href='?_src_=vars;Vars=[C.UID()]'>[VV_HTML_ENCODE(name)] \ref[value]</a> = [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 += "<ol>"
html += "</ol>"
else
html += "<ul>"
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 += "</ul>"
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 = "<a href='?_src_=vars;VarsList=\ref[L]'>[VV_HTML_ENCODE(name)] = /list ([L.len])</a><ul>[items.Join()]</ul>"
else
item = "<a href='?_src_=vars;VarsList=\ref[L]'>[VV_HTML_ENCODE(name)] = /list ([L.len])</a>"
else
html += "[name] = <span class='value'>[value]</span>"
/*
// Bitfield stuff
if(round(value)==value) // Require integers.
var/idx=0
var/bit=0
var/bv=0
html += "<div class='value binary'>"
for(var/block=0;block<8;block++)
html += " <span class='block'>"
for(var/i=0;i<4;i++)
idx=(block*4)+i
to_chat(bit=1, idx)
bv=value & bit
html += "<a href='?_src_=vars;togbit=[idx];var=[name];subject=[DA.UID()]' title='bit [idx] ([bit])'>[bv?1:0]</a>"
html += "</span>"
html += "</div>"
*/
html += "</li>"
item = "[VV_HTML_ENCODE(name)] = <span class='value'>[VV_HTML_ENCODE(value)]</span>"
return html.Join("")
return "[header][item]</li>"
#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 +592,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
@@ -1099,6 +1176,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 +1188,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
+15 -2
View File
@@ -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()]"
@@ -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), "<span class='suicide'>[user] is licking the electrodes of the [src.name]! It looks like \he's trying to commit suicide.</span>")
+5 -1
View File
@@ -310,4 +310,8 @@ a {
Item.fire_act() //Set them on fire, too
/obj/proc/on_mob_move(dir, mob/user)
return
return
/obj/vv_get_dropdown()
. = ..()
.["Delete all of type"] = "?_src_=vars;delall=[UID()]"
+3
View File
@@ -100,3 +100,6 @@ 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
+207 -316
View File
@@ -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, "<span class='danger'>It is forbidden to edit this object's variables.</span>")
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 <b>NUM</b>.")
default = "num"
dir = 1
else if(istext(var_value))
to_chat(usr, "Variable appears to be <b>TEXT</b>.")
default = "text"
else if(isloc(var_value))
to_chat(usr, "Variable appears to be <b>REFERENCE</b>.")
default = "reference"
else if(isicon(var_value))
to_chat(usr, "Variable appears to be <b>ICON</b>.")
var_value = "[bicon(var_value)]"
default = "icon"
else if(istype(var_value,/atom) || istype(var_value,/datum))
to_chat(usr, "Variable appears to be <b>TYPE</b>.")
default = "type"
else if(istype(var_value,/list))
to_chat(usr, "Variable appears to be <b>LIST</b>.")
default = "list"
else if(istype(var_value,/client))
to_chat(usr, "Variable appears to be <b>CLIENT</b>.")
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 <b>FILE</b>.")
default = "file"
to_chat(src, "Variable appears to be <b>[uppertext(default)]</b>.")
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)
else
for(var/datum/thing in world)
if(typecache[thing.type])
. += thing
CHECK_TICK
File diff suppressed because it is too large Load Diff
+15 -1
View File
@@ -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
+4 -4
View File
@@ -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()
..()
update_transform()
+28
View File
@@ -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()]"
+8 -7
View File
@@ -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))
+2
View File
@@ -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"