mirror of
https://github.com/CHOMPStation2/CHOMPStation2.git
synced 2026-07-19 04:08:55 +01:00
Merge branch 'master' of https://github.com/VOREStation/VOREStation into self
# Conflicts: # code/_helpers/unsorted.dm # code/controllers/subsystems/mapping_vr.dm # code/datums/datum.dm # code/datums/datumvars.dm # code/datums/supplypacks/voidsuits.dm # code/game/machinery/suit_storage_unit.dm # code/game/objects/items/devices/defib.dm # code/game/objects/items/weapons/tools/weldingtool.dm # code/game/world.dm # code/modules/client/preference_setup/loadout/loadout_accessories.dm # code/modules/client/preference_setup/loadout/loadout_eyes.dm # code/modules/client/preference_setup/loadout/loadout_head.dm # code/modules/client/preference_setup/loadout/loadout_suit.dm # code/modules/client/preference_setup/loadout/loadout_uniform.dm # code/modules/clothing/glasses/glasses.dm # code/modules/food/food/snacks.dm # code/modules/mob/living/carbon/human/species/station/station_vr.dm # code/modules/reagents/Chemistry-Recipes.dm # code/world.dm # config/custom_items.txt # config/example/config.txt # config/example/game_options.txt # icons/mob/robots.dmi # icons/obj/mining.dmi # maps/submaps/surface_submaps/wilderness/wilderness.dm # vorestation.dme
This commit is contained in:
@@ -64,7 +64,7 @@ datum/admins/proc/DB_ban_record(var/bantype, var/mob/banned_mob, var/duration =
|
||||
a_ip = src.owner:address
|
||||
|
||||
var/who
|
||||
for(var/client/C in clients)
|
||||
for(var/client/C in GLOB.clients)
|
||||
if(!who)
|
||||
who = "[C]"
|
||||
else
|
||||
|
||||
@@ -239,7 +239,7 @@ proc/admin_notice(var/message, var/rights)
|
||||
|
||||
// Display the notes on the current page
|
||||
var/number_pages = note_keys.len / PLAYER_NOTES_ENTRIES_PER_PAGE
|
||||
// Emulate ceil(why does BYOND not have ceil)
|
||||
// Emulate CEILING(why does BYOND not have ceil, 1)
|
||||
if(number_pages != round(number_pages))
|
||||
number_pages = round(number_pages) + 1
|
||||
var/page_index = page - 1
|
||||
@@ -286,7 +286,7 @@ proc/admin_notice(var/message, var/rights)
|
||||
dat += "<body>"
|
||||
|
||||
var/p_age = "unknown"
|
||||
for(var/client/C in clients)
|
||||
for(var/client/C in GLOB.clients)
|
||||
if(C.ckey == key)
|
||||
p_age = C.player_age
|
||||
break
|
||||
@@ -730,28 +730,28 @@ var/datum/announcement/minor/admin_min_announcer = new
|
||||
//Split on pipe or \n
|
||||
decomposed = splittext(message,regex("\\||$","m"))
|
||||
decomposed += "0" //Tack on a final 0 sleep to make 3-per-message evenly
|
||||
|
||||
|
||||
//Time to find how they screwed up.
|
||||
//Wasn't the right length
|
||||
if((decomposed.len) % 3) //+1 to accomidate the lack of a wait time for the last message
|
||||
to_chat(usr,"<span class='warning'>You passed [decomposed.len] segments (senders+messages+pauses). You must pass a multiple of 3, minus 1 (no pause after the last message). That means a sender and message on every other line (starting on the first), separated by a pipe character (|), and a number every other line that is a pause in seconds.</span>")
|
||||
return
|
||||
|
||||
|
||||
//Too long a conversation
|
||||
if((decomposed.len / 3) > 20)
|
||||
to_chat(usr,"<span class='warning'>This conversation is too long! 20 messages maximum, please.</span>")
|
||||
return
|
||||
|
||||
|
||||
//Missed some sleeps, or sanitized to nothing.
|
||||
for(var/i = 1; i < decomposed.len; i++)
|
||||
|
||||
|
||||
//Sanitize sender
|
||||
var/clean_sender = sanitize(decomposed[i])
|
||||
if(!clean_sender)
|
||||
to_chat(usr,"<span class='warning'>One part of your conversation was not able to be sanitized. It was the sender of the [(i+2)/3]\th message.</span>")
|
||||
return
|
||||
decomposed[i] = clean_sender
|
||||
|
||||
|
||||
//Sanitize message
|
||||
var/clean_message = sanitize(decomposed[++i])
|
||||
if(!clean_message)
|
||||
|
||||
@@ -106,7 +106,7 @@ var/list/admin_ranks = list() //list of all ranks with associated rights
|
||||
world.SetConfig("APP/admin", ckey, "role=admin")
|
||||
|
||||
//find the client for a ckey if they are connected and associate them with the new admin datum
|
||||
D.associate(directory[ckey])
|
||||
D.associate(GLOB.directory[ckey])
|
||||
|
||||
else
|
||||
//The current admin system uses SQL
|
||||
@@ -134,7 +134,7 @@ var/list/admin_ranks = list() //list of all ranks with associated rights
|
||||
world.SetConfig("APP/admin", ckey, "role=admin")
|
||||
|
||||
//find the client for a ckey if they are connected and associate them with the new admin datum
|
||||
D.associate(directory[ckey])
|
||||
D.associate(GLOB.directory[ckey])
|
||||
if(!admin_datums)
|
||||
error("The database query in load_admins() resulted in no admins being added to the list. Reverting to legacy system.")
|
||||
log_misc("The database query in load_admins() resulted in no admins being added to the list. Reverting to legacy system.")
|
||||
|
||||
@@ -6,6 +6,7 @@ var/list/admin_verbs_default = list(
|
||||
/client/proc/hide_verbs, //hides all our adminverbs,
|
||||
/client/proc/hide_most_verbs, //hides all our hideable adminverbs,
|
||||
/client/proc/debug_variables, //allows us to -see- the variables of any instance in the game. +VAREDIT needed to modify,
|
||||
/client/proc/mark_datum_mapview,
|
||||
/client/proc/cmd_check_new_players, //allows us to see every new player
|
||||
// /client/proc/check_antagonists, //shows all antags,
|
||||
// /client/proc/cmd_mod_say,
|
||||
@@ -214,9 +215,8 @@ var/list/admin_verbs_debug = list(
|
||||
/client/proc/show_plant_genes,
|
||||
/client/proc/enable_debug_verbs,
|
||||
/client/proc/callproc,
|
||||
/client/proc/callproc_target,
|
||||
/client/proc/debug_process,
|
||||
/client/proc/SDQL_query,
|
||||
/client/proc/callproc_datum,
|
||||
/client/proc/debug_process, //VOREStation Add,
|
||||
/client/proc/SDQL2_query,
|
||||
/client/proc/Jump,
|
||||
/client/proc/debug_rogueminer,
|
||||
@@ -235,8 +235,8 @@ var/list/admin_verbs_debug = list(
|
||||
|
||||
var/list/admin_verbs_paranoid_debug = list(
|
||||
/client/proc/callproc,
|
||||
/client/proc/callproc_target,
|
||||
/client/proc/debug_process,
|
||||
/client/proc/callproc_datum,
|
||||
/client/proc/debug_process, //VOREStation Add,
|
||||
/client/proc/debug_controller
|
||||
)
|
||||
|
||||
@@ -304,8 +304,8 @@ var/list/admin_verbs_hideable = list(
|
||||
/client/proc/restart_controller,
|
||||
/client/proc/cmd_admin_list_open_jobs,
|
||||
/client/proc/callproc,
|
||||
/client/proc/callproc_target,
|
||||
/client/proc/debug_process,
|
||||
/client/proc/callproc_datum,
|
||||
/client/proc/debug_process, //VOREStation Add,
|
||||
/client/proc/Debug2,
|
||||
/client/proc/reload_admins,
|
||||
/client/proc/kill_air,
|
||||
@@ -373,7 +373,7 @@ var/list/admin_verbs_event_manager = list(
|
||||
/proc/possess,
|
||||
/proc/release,
|
||||
/client/proc/callproc,
|
||||
/client/proc/callproc_target,
|
||||
/client/proc/callproc_datum,
|
||||
/client/proc/debug_controller,
|
||||
/client/proc/show_gm_status,
|
||||
/datum/admins/proc/change_weather,
|
||||
@@ -646,7 +646,7 @@ var/list/admin_verbs_event_manager = list(
|
||||
return
|
||||
|
||||
var/datum/preferences/D
|
||||
var/client/C = directory[warned_ckey]
|
||||
var/client/C = GLOB.directory[warned_ckey]
|
||||
if(C) D = C.prefs
|
||||
else D = preferences_datums[warned_ckey]
|
||||
|
||||
@@ -920,7 +920,7 @@ var/list/admin_verbs_event_manager = list(
|
||||
set category = "Admin"
|
||||
|
||||
if(!check_rights(R_ADMIN)) return
|
||||
var sec_level = input(usr, "It's currently code [get_security_level()].", "Select Security Level") as null|anything in (list("green","blue","red","delta")-get_security_level())
|
||||
var sec_level = input(usr, "It's currently code [get_security_level()].", "Select Security Level") as null|anything in (list("green","yellow","violet","orange","blue","red","delta")-get_security_level())
|
||||
if(alert("Switch from code [get_security_level()] to code [sec_level]?","Change security level?","Yes","No") == "Yes")
|
||||
set_security_level(sec_level)
|
||||
log_admin("[key_name(usr)] changed the security level to code [sec_level].")
|
||||
|
||||
@@ -1,152 +1,210 @@
|
||||
|
||||
/client/proc/callproc()
|
||||
set category = "Debug"
|
||||
set name = "Advanced ProcCall"
|
||||
|
||||
if(!check_rights(R_DEBUG)) return
|
||||
if(config.debugparanoid && !check_rights(R_ADMIN)) return
|
||||
|
||||
var/target = null
|
||||
var/targetselected = 0
|
||||
|
||||
switch(alert("Proc owned by something?",, "Yes", "No", "Cancel"))
|
||||
if("Yes")
|
||||
targetselected=1
|
||||
switch(input("Proc owned by...", "Owner", null) as null|anything in list("Obj", "Mob", "Area or Turf", "Client"))
|
||||
if("Obj")
|
||||
target = input("Select target:", "Target") as null|obj in world
|
||||
if("Mob")
|
||||
target = input("Select target:", "Target", usr) as null|mob in world
|
||||
if("Area or Turf")
|
||||
target = input("Select target:", "Target", get_turf(usr)) as null|area|turf in world
|
||||
if("Client")
|
||||
target = input("Select target:", "Target", usr.client) as null|anything in clients
|
||||
else
|
||||
return
|
||||
if(!target)
|
||||
usr << "Proc call cancelled."
|
||||
return
|
||||
if("Cancel")
|
||||
return
|
||||
if("No")
|
||||
; // do nothing
|
||||
|
||||
callproc_targetpicked(targetselected, target)
|
||||
|
||||
/client/proc/callproc_target(atom/A in world)
|
||||
set category = "Debug"
|
||||
set name = "Advanced ProcCall Target"
|
||||
|
||||
if(!check_rights(R_DEBUG)) return
|
||||
if(config.debugparanoid && !check_rights(R_ADMIN)) return
|
||||
|
||||
callproc_targetpicked(1, A)
|
||||
|
||||
/client/proc/callproc_targetpicked(hastarget, datum/target)
|
||||
|
||||
// this needs checking again here because VV's 'Call Proc' option directly calls this proc with the target datum
|
||||
if(!check_rights(R_DEBUG)) return
|
||||
if(config.debugparanoid && !check_rights(R_ADMIN)) return
|
||||
|
||||
var/returnval = null
|
||||
|
||||
var/procname = input("Proc name", "Proc") as null|text
|
||||
if(!procname) return
|
||||
|
||||
if(hastarget)
|
||||
if(!target)
|
||||
usr << "Your callproc target no longer exists."
|
||||
return
|
||||
if(!hascall(target, procname))
|
||||
usr << "\The [target] has no call [procname]()"
|
||||
return
|
||||
|
||||
var/list/arguments = list()
|
||||
var/done = 0
|
||||
var/current = null
|
||||
|
||||
while(!done)
|
||||
if(hastarget && !target)
|
||||
usr << "Your callproc target no longer exists."
|
||||
return
|
||||
switch(input("Type of [arguments.len+1]\th variable", "argument [arguments.len+1]") as null|anything in list(
|
||||
"finished", "null", "text", "num", "type", "obj reference", "mob reference",
|
||||
"area/turf reference", "icon", "file", "client", "mob's area", "marked datum"))
|
||||
if(null)
|
||||
return
|
||||
|
||||
if("finished")
|
||||
done = 1
|
||||
|
||||
if("null")
|
||||
current = null
|
||||
|
||||
if("text")
|
||||
current = input("Enter text for [arguments.len+1]\th argument") as null|text
|
||||
if(isnull(current)) return
|
||||
|
||||
if("num")
|
||||
current = input("Enter number for [arguments.len+1]\th argument") as null|num
|
||||
if(isnull(current)) return
|
||||
|
||||
if("type")
|
||||
current = input("Select type for [arguments.len+1]\th argument") as null|anything in typesof(/obj, /mob, /area, /turf)
|
||||
if(isnull(current)) return
|
||||
|
||||
if("obj reference")
|
||||
current = input("Select object for [arguments.len+1]\th argument") as null|obj in world
|
||||
if(isnull(current)) return
|
||||
|
||||
if("mob reference")
|
||||
current = input("Select mob for [arguments.len+1]\th argument") as null|mob in world
|
||||
if(isnull(current)) return
|
||||
|
||||
if("area/turf reference")
|
||||
current = input("Select area/turf for [arguments.len+1]\th argument") as null|area|turf in world
|
||||
if(isnull(current)) return
|
||||
|
||||
if("icon")
|
||||
current = input("Provide icon for [arguments.len+1]\th argument") as null|icon
|
||||
if(isnull(current)) return
|
||||
|
||||
if("client")
|
||||
current = input("Select client for [arguments.len+1]\th argument") as null|anything in clients
|
||||
if(isnull(current)) return
|
||||
|
||||
if("mob's area")
|
||||
var/mob/M = input("Select mob to take area for [arguments.len+1]\th argument") as null|mob in world
|
||||
if(!M) return
|
||||
current = get_area(M)
|
||||
if(!current)
|
||||
switch(alert("\The [M] appears to not have an area; do you want to pass null instead?",, "Yes", "Cancel"))
|
||||
if("Yes")
|
||||
; // do nothing
|
||||
if("Cancel")
|
||||
return
|
||||
|
||||
if("marked datum")
|
||||
current = holder.marked_datum
|
||||
if(!current)
|
||||
switch(alert("You do not currently have a marked datum; do you want to pass null instead?",, "Yes", "Cancel"))
|
||||
if("Yes")
|
||||
; // do nothing
|
||||
if("Cancel")
|
||||
return
|
||||
if(!done)
|
||||
arguments += current
|
||||
|
||||
if(hastarget)
|
||||
if(!target)
|
||||
usr << "Your callproc target no longer exists."
|
||||
return
|
||||
log_admin("[key_name(src)] called [target]'s [procname]() with [arguments.len ? "the arguments [list2params(arguments)]" : "no arguments"].")
|
||||
if(arguments.len)
|
||||
returnval = call(target, procname)(arglist(arguments))
|
||||
else
|
||||
returnval = call(target, procname)()
|
||||
else
|
||||
log_admin("[key_name(src)] called [procname]() with [arguments.len ? "the arguments [list2params(arguments)]" : "no arguments"].")
|
||||
returnval = call(procname)(arglist(arguments))
|
||||
|
||||
usr << "<span class='info'>[procname]() returned: [isnull(returnval) ? "null" : returnval]</span>"
|
||||
feedback_add_details("admin_verb","APC") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
/client/proc/callproc()
|
||||
set category = "Debug"
|
||||
set name = "Advanced ProcCall"
|
||||
set waitfor = 0
|
||||
|
||||
if(!check_rights(R_DEBUG))
|
||||
return
|
||||
|
||||
var/datum/target = null
|
||||
var/targetselected = 0
|
||||
var/returnval = null
|
||||
|
||||
switch(alert("Proc owned by something?",,"Yes","No"))
|
||||
if("Yes")
|
||||
targetselected = 1
|
||||
var/list/value = vv_get_value(default_class = VV_ATOM_REFERENCE, classes = list(VV_ATOM_REFERENCE, VV_DATUM_REFERENCE, VV_MOB_REFERENCE, VV_CLIENT))
|
||||
if (!value["class"] || !value["value"])
|
||||
return
|
||||
target = value["value"]
|
||||
if("No")
|
||||
target = null
|
||||
targetselected = 0
|
||||
|
||||
var/procname = input("Proc path, eg: /proc/fake_blood","Path:", null) as text|null
|
||||
if(!procname)
|
||||
return
|
||||
|
||||
//hascall() doesn't support proc paths (eg: /proc/gib(), it only supports "gib")
|
||||
var/testname = procname
|
||||
if(targetselected)
|
||||
//Find one of the 3 possible ways they could have written /proc/PROCNAME
|
||||
if(findtext(procname, "/proc/"))
|
||||
testname = replacetext(procname, "/proc/", "")
|
||||
else if(findtext(procname, "/proc"))
|
||||
testname = replacetext(procname, "/proc", "")
|
||||
else if(findtext(procname, "proc/"))
|
||||
testname = replacetext(procname, "proc/", "")
|
||||
//Clear out any parenthesis if they're a dummy
|
||||
testname = replacetext(testname, "()", "")
|
||||
|
||||
if(targetselected && !hascall(target,testname))
|
||||
to_chat(usr, "<font color='red'>Error: callproc(): type [target.type] has no proc named [procname].</font>")
|
||||
return
|
||||
else
|
||||
var/procpath = text2path(procname)
|
||||
if (!procpath)
|
||||
to_chat(usr, "<font color='red'>Error: callproc(): proc [procname] does not exist. (Did you forget the /proc/ part?)</font>")
|
||||
return
|
||||
var/list/lst = get_callproc_args()
|
||||
if(!lst)
|
||||
return
|
||||
|
||||
if(targetselected)
|
||||
if(!target)
|
||||
to_chat(usr, "<font color='red'>Error: callproc(): owner of proc no longer exists.</font>")
|
||||
return
|
||||
var/msg = "[key_name(src)] called [target]'s [procname]() with [lst.len ? "the arguments [list2params(lst)]":"no arguments"]."
|
||||
log_admin(msg)
|
||||
//message_admins(msg) //Proccall announce removed.
|
||||
admin_ticket_log(target, msg)
|
||||
returnval = WrapAdminProcCall(target, procname, lst) // Pass the lst as an argument list to the proc
|
||||
else
|
||||
//this currently has no hascall protection. wasn't able to get it working.
|
||||
log_admin("[key_name(src)] called [procname]() with [lst.len ? "the arguments [list2params(lst)]":"no arguments"].")
|
||||
//message_admins("[key_name(src)] called [procname]() with [lst.len ? "the arguments [list2params(lst)]":"no arguments"].") //Proccall announce removed.
|
||||
returnval = WrapAdminProcCall(GLOBAL_PROC, procname, lst) // Pass the lst as an argument list to the proc
|
||||
. = get_callproc_returnval(returnval, procname)
|
||||
if(.)
|
||||
to_chat(usr, .)
|
||||
feedback_add_details("admin_verb","APC") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
GLOBAL_VAR(AdminProcCaller)
|
||||
GLOBAL_PROTECT(AdminProcCaller)
|
||||
GLOBAL_VAR_INIT(AdminProcCallCount, 0)
|
||||
GLOBAL_PROTECT(AdminProcCallCount)
|
||||
GLOBAL_VAR(LastAdminCalledTargetRef)
|
||||
GLOBAL_PROTECT(LastAdminCalledTargetRef)
|
||||
GLOBAL_VAR(LastAdminCalledTarget)
|
||||
GLOBAL_PROTECT(LastAdminCalledTarget)
|
||||
GLOBAL_VAR(LastAdminCalledProc)
|
||||
GLOBAL_PROTECT(LastAdminCalledProc)
|
||||
GLOBAL_LIST_EMPTY(AdminProcCallSpamPrevention)
|
||||
GLOBAL_PROTECT(AdminProcCallSpamPrevention)
|
||||
|
||||
/proc/WrapAdminProcCall(datum/target, procname, list/arguments)
|
||||
if(target && procname == "Del")
|
||||
to_chat(usr, "Calling Del() is not allowed")
|
||||
return
|
||||
|
||||
if(target != GLOBAL_PROC && !target.CanProcCall(procname))
|
||||
to_chat(usr, "Proccall on [target.type]/proc/[procname] is disallowed!")
|
||||
return
|
||||
var/current_caller = GLOB.AdminProcCaller
|
||||
var/ckey = usr ? usr.client.ckey : GLOB.AdminProcCaller
|
||||
if(!ckey)
|
||||
CRASH("WrapAdminProcCall with no ckey: [target] [procname] [english_list(arguments)]")
|
||||
if(current_caller && current_caller != ckey)
|
||||
if(!GLOB.AdminProcCallSpamPrevention[ckey])
|
||||
to_chat(usr, "<span class='adminnotice'>Another set of admin called procs are still running, your proc will be run after theirs finish.</span>")
|
||||
GLOB.AdminProcCallSpamPrevention[ckey] = TRUE
|
||||
UNTIL(!GLOB.AdminProcCaller)
|
||||
to_chat(usr, "<span class='adminnotice'>Running your proc</span>")
|
||||
GLOB.AdminProcCallSpamPrevention -= ckey
|
||||
else
|
||||
UNTIL(!GLOB.AdminProcCaller)
|
||||
GLOB.LastAdminCalledProc = procname
|
||||
if(target != GLOBAL_PROC)
|
||||
GLOB.LastAdminCalledTargetRef = "\ref[target]"
|
||||
GLOB.AdminProcCaller = ckey //if this runtimes, too bad for you
|
||||
++GLOB.AdminProcCallCount
|
||||
. = world.WrapAdminProcCall(target, procname, arguments)
|
||||
if(--GLOB.AdminProcCallCount == 0)
|
||||
GLOB.AdminProcCaller = null
|
||||
|
||||
//adv proc call this, ya nerds
|
||||
/world/proc/WrapAdminProcCall(datum/target, procname, list/arguments)
|
||||
if(target == GLOBAL_PROC)
|
||||
return call(procname)(arglist(arguments))
|
||||
else if(target != world)
|
||||
return call(target, procname)(arglist(arguments))
|
||||
else
|
||||
log_admin("[key_name(usr)] attempted to call world/proc/[procname] with arguments: [english_list(arguments)]")
|
||||
|
||||
/proc/IsAdminAdvancedProcCall()
|
||||
#ifdef TESTING
|
||||
return FALSE
|
||||
#else
|
||||
return usr && usr.client && GLOB.AdminProcCaller == usr.client.ckey
|
||||
#endif
|
||||
|
||||
/client/proc/callproc_datum(datum/A as null|area|mob|obj|turf)
|
||||
set category = "Debug"
|
||||
set name = "Atom ProcCall"
|
||||
set waitfor = 0
|
||||
|
||||
if(!check_rights(R_DEBUG))
|
||||
return
|
||||
|
||||
var/procname = input("Proc name, eg: fake_blood","Proc:", null) as text|null
|
||||
if(!procname)
|
||||
return
|
||||
if(!hascall(A,procname))
|
||||
to_chat(usr, "<font color='red'>Error: callproc_datum(): type [A.type] has no proc named [procname].</font>")
|
||||
return
|
||||
var/list/lst = get_callproc_args()
|
||||
if(!lst)
|
||||
return
|
||||
|
||||
if(!A || !IsValidSrc(A))
|
||||
to_chat(usr, "<span class='warning'>Error: callproc_datum(): owner of proc no longer exists.</span>")
|
||||
return
|
||||
var/msg = "[key_name(src)] called [A]'s [procname]() with [lst.len ? "the arguments [list2params(lst)]":"no arguments"]."
|
||||
log_admin(msg)
|
||||
//message_admins(msg)
|
||||
admin_ticket_log(A, msg)
|
||||
feedback_add_details("admin_verb","TPC") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
var/returnval = WrapAdminProcCall(A, procname, lst) // Pass the lst as an argument list to the proc
|
||||
. = get_callproc_returnval(returnval,procname)
|
||||
if(.)
|
||||
to_chat(usr, .)
|
||||
|
||||
/client/proc/get_callproc_args()
|
||||
var/argnum = input("Number of arguments","Number:",0) as num|null
|
||||
if(isnull(argnum))
|
||||
return null //Cancel
|
||||
|
||||
. = list()
|
||||
//var/list/named_args = list() //Named arguments are removed, due to them making proccalling take too long.
|
||||
while(argnum--)
|
||||
/* //Named arguments are removed, due to them making proccalling take too long.
|
||||
var/named_arg = input("Leave blank for positional argument. Positional arguments will be considered as if they were added first.", "Named argument") as text|null
|
||||
if(isnull(named_arg))
|
||||
return null //Cancel
|
||||
*/
|
||||
var/value = vv_get_value(restricted_classes = list(VV_RESTORE_DEFAULT))
|
||||
if (!value["class"])
|
||||
return null //Cancel
|
||||
/* //Named arguments are removed, due to them making proccalling take too long.
|
||||
if(named_arg)
|
||||
named_args[named_arg] = value["value"]
|
||||
else
|
||||
. += value["value"]
|
||||
if(LAZYLEN(named_args))
|
||||
. += named_args
|
||||
*/
|
||||
. += value["value"]
|
||||
|
||||
/client/proc/get_callproc_returnval(returnval,procname)
|
||||
. = ""
|
||||
if(islist(returnval))
|
||||
var/list/returnedlist = returnval
|
||||
. = "<font color='blue'>"
|
||||
if(returnedlist.len)
|
||||
var/assoc_check = returnedlist[1]
|
||||
if(istext(assoc_check) && (returnedlist[assoc_check] != null))
|
||||
. += "[procname] returned an associative list:"
|
||||
for(var/key in returnedlist)
|
||||
. += "\n[key] = [returnedlist[key]]"
|
||||
|
||||
else
|
||||
. += "[procname] returned a list:"
|
||||
for(var/elem in returnedlist)
|
||||
. += "\n[elem]"
|
||||
else
|
||||
. = "[procname] returned an empty list"
|
||||
. += "</font>"
|
||||
|
||||
else
|
||||
. = "<font color='blue'>[procname] returned: [!isnull(returnval) ? returnval : "null"]</font>"
|
||||
|
||||
@@ -47,6 +47,12 @@ var/list/admin_datums = list()
|
||||
owner.deadmin_holder = null
|
||||
owner.add_admin_verbs()
|
||||
|
||||
/datum/admins/vv_edit_var(var_name, var_value)
|
||||
if(var_name == NAMEOF(src, rights) || var_name == NAMEOF(src, owner) || var_name == NAMEOF(src, rank))
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
//TODO: Proccall guard, when all try/catch are removed and WrapAdminProccall is ported.
|
||||
|
||||
/*
|
||||
checks if usr is an admin with at least ONE of the flags in rights_required. (Note, they don't need all the flags)
|
||||
@@ -95,7 +101,18 @@ NOTE: It checks usr by default. Supply the "user" argument if you wish to check
|
||||
usr << "<font color='red'>Error: Cannot proceed. They have more or equal rights to us.</font>"
|
||||
return 0
|
||||
|
||||
/client/proc/mark_datum(datum/D)
|
||||
if(!holder)
|
||||
return
|
||||
if(holder.marked_datum)
|
||||
vv_update_display(holder.marked_datum, "marked", "")
|
||||
holder.marked_datum = D
|
||||
vv_update_display(D, "marked", VV_MSG_MARKED)
|
||||
|
||||
/client/proc/mark_datum_mapview(datum/D as mob|obj|turf|area in view(view))
|
||||
set category = "Debug"
|
||||
set name = "Mark Object"
|
||||
mark_datum(D)
|
||||
|
||||
/client/proc/deadmin()
|
||||
if(holder)
|
||||
|
||||
+20
-20
@@ -175,7 +175,7 @@
|
||||
else
|
||||
D = new /datum/admins(new_rank, rights, adm_ckey)
|
||||
|
||||
var/client/C = directory[adm_ckey] //find the client with the specified ckey (if they are logged in)
|
||||
var/client/C = GLOB.directory[adm_ckey] //find the client with the specified ckey (if they are logged in)
|
||||
D.associate(C) //link up with the client and add verbs
|
||||
|
||||
message_admins("[key_name_admin(usr)] edited the admin rank of [adm_ckey] to [new_rank]")
|
||||
@@ -280,21 +280,21 @@
|
||||
if("larva") M.change_mob_type( /mob/living/carbon/alien/larva , null, null, delmob )
|
||||
if("nymph") M.change_mob_type( /mob/living/carbon/alien/diona , null, null, delmob )
|
||||
if("human") M.change_mob_type( /mob/living/carbon/human , null, null, delmob, href_list["species"])
|
||||
if("slime") M.change_mob_type( /mob/living/simple_animal/slime , null, null, delmob )
|
||||
if("slime") M.change_mob_type( /mob/living/simple_mob/slime/xenobio , null, null, delmob )
|
||||
if("monkey") M.change_mob_type( /mob/living/carbon/human/monkey , null, null, delmob )
|
||||
if("robot") M.change_mob_type( /mob/living/silicon/robot , null, null, delmob )
|
||||
if("cat") M.change_mob_type( /mob/living/simple_animal/cat , null, null, delmob )
|
||||
if("runtime") M.change_mob_type( /mob/living/simple_animal/cat/fluff/Runtime , null, null, delmob )
|
||||
if("corgi") M.change_mob_type( /mob/living/simple_animal/corgi , null, null, delmob )
|
||||
if("ian") M.change_mob_type( /mob/living/simple_animal/corgi/Ian , null, null, delmob )
|
||||
if("crab") M.change_mob_type( /mob/living/simple_animal/crab , null, null, delmob )
|
||||
if("coffee") M.change_mob_type( /mob/living/simple_animal/crab/Coffee , null, null, delmob )
|
||||
if("parrot") M.change_mob_type( /mob/living/simple_animal/parrot , null, null, delmob )
|
||||
if("polyparrot") M.change_mob_type( /mob/living/simple_animal/parrot/Poly , null, null, delmob )
|
||||
if("constructarmoured") M.change_mob_type( /mob/living/simple_animal/construct/armoured , null, null, delmob )
|
||||
if("constructbuilder") M.change_mob_type( /mob/living/simple_animal/construct/builder , null, null, delmob )
|
||||
if("constructwraith") M.change_mob_type( /mob/living/simple_animal/construct/wraith , null, null, delmob )
|
||||
if("shade") M.change_mob_type( /mob/living/simple_animal/shade , null, null, delmob )
|
||||
if("cat") M.change_mob_type( /mob/living/simple_mob/animal/passive/cat , null, null, delmob )
|
||||
if("runtime") M.change_mob_type( /mob/living/simple_mob/animal/passive/cat/runtime , null, null, delmob )
|
||||
if("corgi") M.change_mob_type( /mob/living/simple_mob/animal/passive/dog/corgi , null, null, delmob )
|
||||
if("ian") M.change_mob_type( /mob/living/simple_mob/animal/passive/dog/corgi/Ian , null, null, delmob )
|
||||
if("crab") M.change_mob_type( /mob/living/simple_mob/animal/passive/crab , null, null, delmob )
|
||||
if("coffee") M.change_mob_type( /mob/living/simple_mob/animal/passive/crab/Coffee , null, null, delmob )
|
||||
if("parrot") M.change_mob_type( /mob/living/simple_mob/animal/passive/bird/parrot , null, null, delmob )
|
||||
if("polyparrot") M.change_mob_type( /mob/living/simple_mob/animal/passive/bird/parrot/poly , null, null, delmob )
|
||||
if("constructarmoured") M.change_mob_type( /mob/living/simple_mob/construct/juggernaut , null, null, delmob )
|
||||
if("constructbuilder") M.change_mob_type( /mob/living/simple_mob/construct/artificer , null, null, delmob )
|
||||
if("constructwraith") M.change_mob_type( /mob/living/simple_mob/construct/wraith , null, null, delmob )
|
||||
if("shade") M.change_mob_type( /mob/living/simple_mob/construct/shade , null, null, delmob )
|
||||
|
||||
|
||||
/////////////////////////////////////new ban stuff
|
||||
@@ -790,13 +790,13 @@
|
||||
if (ismob(M))
|
||||
if(!check_if_greater_rights_than(M.client))
|
||||
return
|
||||
var/reason = sanitize(input("Please enter reason"))
|
||||
var/reason = sanitize(input("Please enter reason.") as null|message)
|
||||
if(!reason)
|
||||
M << "<font color='red'>You have been kicked from the server</font>"
|
||||
else
|
||||
M << "<font color='red'>You have been kicked from the server: [reason]</font>"
|
||||
log_admin("[key_name(usr)] booted [key_name(M)].")
|
||||
message_admins("<font color='blue'>[key_name_admin(usr)] booted [key_name_admin(M)].</font>", 1)
|
||||
return
|
||||
|
||||
to_chat(M, span("critical", "You have been kicked from the server: [reason]"))
|
||||
log_admin("[key_name(usr)] booted [key_name(M)] for reason: '[reason]'.")
|
||||
message_admins("<font color='blue'>[key_name_admin(usr)] booted [key_name_admin(M)] for reason '[reason]'.</font>", 1)
|
||||
//M.client = null
|
||||
qdel(M.client)
|
||||
|
||||
|
||||
@@ -1,497 +0,0 @@
|
||||
|
||||
//Structured Datum Query Language. Basically SQL meets BYOND objects.
|
||||
|
||||
//Note: For use in BS12, need text_starts_with proc, and to modify the action on select to use BS12's object edit command(s).
|
||||
|
||||
/client/proc/SDQL_query(query_text as message)
|
||||
set category = "Admin"
|
||||
if(!check_rights(R_DEBUG)) //Shouldn't happen... but just to be safe.
|
||||
message_admins("<font color='red'>ERROR: Non-admin [usr.key] attempted to execute a SDQL query!</font>")
|
||||
log_admin("Non-admin [usr.key] attempted to execute a SDQL query!")
|
||||
|
||||
var/list/query_list = SDQL_tokenize(query_text)
|
||||
|
||||
if(query_list.len < 2)
|
||||
if(query_list.len > 0)
|
||||
usr << "<font color='red'>SDQL: Too few discrete tokens in query \"[query_text]\". Please check your syntax and try again.</font>"
|
||||
return
|
||||
|
||||
if(!(lowertext(query_list[1]) in list("select", "delete", "update")))
|
||||
usr << "<font color='red'>SDQL: Unknown query type: \"[query_list[1]]\" in query \"[query_text]\". Please check your syntax and try again.</font>"
|
||||
return
|
||||
|
||||
var/list/types = list()
|
||||
|
||||
var/i
|
||||
for(i = 2; i <= query_list.len; i += 2)
|
||||
types += query_list[i]
|
||||
|
||||
if(i + 1 >= query_list.len || query_list[i + 1] != ",")
|
||||
break
|
||||
|
||||
i++
|
||||
|
||||
var/list/from = list()
|
||||
|
||||
if(i <= query_list.len)
|
||||
if(lowertext(query_list[i]) in list("from", "in"))
|
||||
for(i++; i <= query_list.len; i += 2)
|
||||
from += query_list[i]
|
||||
|
||||
if(i + 1 >= query_list.len || query_list[i + 1] != ",")
|
||||
break
|
||||
|
||||
i++
|
||||
|
||||
if(from.len < 1)
|
||||
from += "world"
|
||||
|
||||
var/list/set_vars = list()
|
||||
|
||||
if(lowertext(query_list[1]) == "update")
|
||||
if(i <= query_list.len && lowertext(query_list[i]) == "set")
|
||||
for(i++; i <= query_list.len; i++)
|
||||
if(i + 2 <= query_list.len && query_list[i + 1] == "=")
|
||||
set_vars += query_list[i]
|
||||
set_vars[query_list[i]] = query_list[i + 2]
|
||||
|
||||
else
|
||||
usr << "<font color='red'>SDQL: Invalid set parameter in query \"[query_text]\". Please check your syntax and try again.</font>"
|
||||
return
|
||||
|
||||
i += 3
|
||||
|
||||
if(i >= query_list.len || query_list[i] != ",")
|
||||
break
|
||||
|
||||
if(set_vars.len < 1)
|
||||
usr << "<font color='red'>SDQL: Invalid or missing set in query \"[query_text]\". Please check your syntax and try again.</font>"
|
||||
return
|
||||
|
||||
var/list/where = list()
|
||||
|
||||
if(i <= query_list.len && lowertext(query_list[i]) == "where")
|
||||
where = query_list.Copy(i + 1)
|
||||
|
||||
var/list/from_objs = list()
|
||||
if("world" in from)
|
||||
from_objs += world
|
||||
else
|
||||
for(var/f in from)
|
||||
if(copytext(f, 1, 2) == "'" || copytext(f, 1, 2) == "\"")
|
||||
from_objs += locate(copytext(f, 2, length(f)))
|
||||
else if(copytext(f, 1, 2) != "/")
|
||||
from_objs += locate(f)
|
||||
else
|
||||
var/f2 = text2path(f)
|
||||
if(text_starts_with(f, "/mob"))
|
||||
for(var/mob/m in mob_list)
|
||||
if(istype(m, f2))
|
||||
from_objs += m
|
||||
|
||||
else if(text_starts_with(f, "/turf/space"))
|
||||
for(var/turf/space/m in turfs)
|
||||
if(istype(m, f2))
|
||||
from_objs += m
|
||||
|
||||
else if(text_starts_with(f, "/turf/simulated"))
|
||||
for(var/turf/simulated/m in turfs)
|
||||
if(istype(m, f2))
|
||||
from_objs += m
|
||||
|
||||
else if(text_starts_with(f, "/turf/unsimulated"))
|
||||
for(var/turf/unsimulated/m in turfs)
|
||||
if(istype(m, f2))
|
||||
from_objs += m
|
||||
|
||||
else if(text_starts_with(f, "/turf"))
|
||||
for(var/turf/m in turfs)
|
||||
if(istype(m, f2))
|
||||
from_objs += m
|
||||
|
||||
else if(text_starts_with(f, "/area"))
|
||||
for(var/area/m in all_areas)
|
||||
if(istype(m, f2))
|
||||
from_objs += m
|
||||
|
||||
else if(text_starts_with(f, "/obj/item"))
|
||||
for(var/obj/item/m in world)
|
||||
if(istype(m, f2))
|
||||
from_objs += m
|
||||
|
||||
else if(text_starts_with(f, "/obj/machinery"))
|
||||
for(var/obj/machinery/m in machines)
|
||||
if(istype(m, f2))
|
||||
from_objs += m
|
||||
|
||||
else if(text_starts_with(f, "/obj"))
|
||||
for(var/obj/m in world)
|
||||
if(istype(m, f2))
|
||||
from_objs += m
|
||||
|
||||
else if(text_starts_with(f, "/atom"))
|
||||
for(var/atom/m in world)
|
||||
if(istype(m, f2))
|
||||
from_objs += m
|
||||
/*
|
||||
else
|
||||
for(var/datum/m in nope)
|
||||
if(istype(m, f2))
|
||||
from_objs += m
|
||||
*/
|
||||
|
||||
var/list/objs = list()
|
||||
|
||||
for(var/from_obj in from_objs)
|
||||
if("*" in types)
|
||||
objs += from_obj:contents
|
||||
else
|
||||
for(var/f in types)
|
||||
if(copytext(f, 1, 2) == "'" || copytext(f, 1, 2) == "\"")
|
||||
objs += locate(copytext(f, 2, length(f))) in from_obj
|
||||
else if(copytext(f, 1, 2) != "/")
|
||||
objs += locate(f) in from_obj
|
||||
else
|
||||
var/f2 = text2path(f)
|
||||
if(text_starts_with(f, "/mob"))
|
||||
for(var/mob/m in from_obj)
|
||||
if(istype(m, f2))
|
||||
objs += m
|
||||
|
||||
else if(text_starts_with(f, "/turf/space"))
|
||||
for(var/turf/space/m in from_obj)
|
||||
if(istype(m, f2))
|
||||
objs += m
|
||||
|
||||
else if(text_starts_with(f, "/turf/simulated"))
|
||||
for(var/turf/simulated/m in from_obj)
|
||||
if(istype(m, f2))
|
||||
objs += m
|
||||
|
||||
else if(text_starts_with(f, "/turf/unsimulated"))
|
||||
for(var/turf/unsimulated/m in from_obj)
|
||||
if(istype(m, f2))
|
||||
objs += m
|
||||
|
||||
else if(text_starts_with(f, "/turf"))
|
||||
for(var/turf/m in from_obj)
|
||||
if(istype(m, f2))
|
||||
objs += m
|
||||
|
||||
else if(text_starts_with(f, "/area"))
|
||||
for(var/area/m in from_obj)
|
||||
if(istype(m, f2))
|
||||
objs += m
|
||||
|
||||
else if(text_starts_with(f, "/obj/item"))
|
||||
for(var/obj/item/m in from_obj)
|
||||
if(istype(m, f2))
|
||||
objs += m
|
||||
|
||||
else if(text_starts_with(f, "/obj/machinery"))
|
||||
for(var/obj/machinery/m in from_obj)
|
||||
if(istype(m, f2))
|
||||
objs += m
|
||||
|
||||
else if(text_starts_with(f, "/obj"))
|
||||
for(var/obj/m in from_obj)
|
||||
if(istype(m, f2))
|
||||
objs += m
|
||||
|
||||
else if(text_starts_with(f, "/atom"))
|
||||
for(var/atom/m in from_obj)
|
||||
if(istype(m, f2))
|
||||
objs += m
|
||||
|
||||
else
|
||||
for(var/datum/m in from_obj)
|
||||
if(istype(m, f2))
|
||||
objs += m
|
||||
|
||||
|
||||
for(var/datum/t in objs)
|
||||
var/currently_false = 0
|
||||
for(i = 1, i - 1 < where.len, i++)
|
||||
var/v = where[i++]
|
||||
var/compare_op = where[i++]
|
||||
if(!(compare_op in list("==", "=", "<>", "<", ">", "<=", ">=", "!=")))
|
||||
usr << "<font color='red'>SDQL: Unknown comparison operator [compare_op] in where clause following [v] in query \"[query_text]\". Please check your syntax and try again.</font>"
|
||||
return
|
||||
|
||||
var/j
|
||||
for(j = i, j <= where.len, j++)
|
||||
if(lowertext(where[j]) in list("and", "or", ";"))
|
||||
break
|
||||
|
||||
if(!currently_false)
|
||||
var/value = SDQL_text2value(t, v)
|
||||
var/result = SDQL_evaluate(t, where.Copy(i, j))
|
||||
|
||||
switch(compare_op)
|
||||
if("=", "==")
|
||||
currently_false = !(value == result)
|
||||
|
||||
if("!=", "<>")
|
||||
currently_false = !(value != result)
|
||||
|
||||
if("<")
|
||||
currently_false = !(value < result)
|
||||
|
||||
if(">")
|
||||
currently_false = !(value > result)
|
||||
|
||||
if("<=")
|
||||
currently_false = !(value <= result)
|
||||
|
||||
if(">=")
|
||||
currently_false = !(value >= result)
|
||||
|
||||
|
||||
if(j > where.len || lowertext(where[j]) == ";")
|
||||
break
|
||||
else if(lowertext(where[j]) == "or")
|
||||
if(currently_false)
|
||||
currently_false = 0
|
||||
else
|
||||
break
|
||||
|
||||
i = j
|
||||
|
||||
if(currently_false)
|
||||
objs -= t
|
||||
|
||||
|
||||
|
||||
usr << "<font color='blue'>SQDL Query: [query_text]</font>"
|
||||
message_admins("[usr] executed SDQL query: \"[query_text]\".")
|
||||
/*
|
||||
for(var/t in types)
|
||||
usr << "Type: [t]"
|
||||
|
||||
for(var/t in from)
|
||||
usr << "From: [t]"
|
||||
|
||||
for(var/t in set_vars)
|
||||
usr << "Set: [t] = [set_vars[t]]"
|
||||
|
||||
if(where.len)
|
||||
var/where_str = ""
|
||||
for(var/t in where)
|
||||
where_str += "[t] "
|
||||
|
||||
usr << "Where: [where_str]"
|
||||
|
||||
usr << "From objects:"
|
||||
for(var/datum/t in from_objs)
|
||||
usr << t
|
||||
|
||||
usr << "Objects:"
|
||||
for(var/datum/t in objs)
|
||||
usr << t
|
||||
*/
|
||||
switch(lowertext(query_list[1]))
|
||||
if("delete")
|
||||
for(var/datum/t in objs)
|
||||
qdel(t)
|
||||
|
||||
if("update")
|
||||
for(var/datum/t in objs)
|
||||
objs[t] = list()
|
||||
for(var/v in set_vars)
|
||||
if(v in t.vars)
|
||||
objs[t][v] = SDQL_text2value(t, set_vars[v])
|
||||
|
||||
for(var/datum/t in objs)
|
||||
for(var/v in objs[t])
|
||||
t.vars[v] = objs[t][v]
|
||||
|
||||
if("select")
|
||||
var/text = ""
|
||||
for(var/datum/t in objs)
|
||||
if(istype(t, /atom))
|
||||
var/atom/a = t
|
||||
|
||||
if(a.x)
|
||||
text += "<a href='?src=\ref[t];SDQL_select=\ref[t]'>\ref[t]</a>: [t] at ([a.x], [a.y], [a.z])<br>"
|
||||
|
||||
else if(a.loc && a.loc.x)
|
||||
text += "<a href='?src=\ref[t];SDQL_select=\ref[t]'>\ref[t]</a>: [t] in [a.loc] at ([a.loc.x], [a.loc.y], [a.loc.z])<br>"
|
||||
|
||||
else
|
||||
text += "<a href='?src=\ref[t];SDQL_select=\ref[t]'>\ref[t]</a>: [t]<br>"
|
||||
|
||||
else
|
||||
text += "<a href='?src=\ref[t];SDQL_select=\ref[t]'>\ref[t]</a>: [t]<br>"
|
||||
|
||||
//text += "[t]<br>"
|
||||
usr << browse(text, "window=sdql_result")
|
||||
|
||||
|
||||
/client/Topic(href,href_list[],hsrc)
|
||||
if(href_list["SDQL_select"])
|
||||
debug_variables(locate(href_list["SDQL_select"]))
|
||||
|
||||
..()
|
||||
|
||||
|
||||
/proc/SDQL_evaluate(datum/object, list/equation)
|
||||
if(equation.len == 0)
|
||||
return null
|
||||
|
||||
else if(equation.len == 1)
|
||||
return SDQL_text2value(object, equation[1])
|
||||
|
||||
else if(equation[1] == "!")
|
||||
return !SDQL_evaluate(object, equation.Copy(2))
|
||||
|
||||
else if(equation[1] == "-")
|
||||
return -SDQL_evaluate(object, equation.Copy(2))
|
||||
|
||||
|
||||
else
|
||||
usr << "<font color='red'>SDQL: Sorry, equations not yet supported :(</font>"
|
||||
return null
|
||||
|
||||
|
||||
/proc/SDQL_text2value(datum/object, text)
|
||||
if(text2num(text) != null)
|
||||
return text2num(text)
|
||||
else if(text == "null")
|
||||
return null
|
||||
else if(copytext(text, 1, 2) == "'" || copytext(text, 1, 2) == "\"" )
|
||||
return copytext(text, 2, length(text))
|
||||
else if(copytext(text, 1, 2) == "/")
|
||||
return text2path(text)
|
||||
else
|
||||
if(findtext(text, "."))
|
||||
var/split = findtext(text, ".")
|
||||
var/v = copytext(text, 1, split)
|
||||
|
||||
if((v in object.vars) && istype(object.vars[v], /datum))
|
||||
return SDQL_text2value(object.vars[v], copytext(text, split + 1))
|
||||
else
|
||||
return null
|
||||
|
||||
else
|
||||
if(text in object.vars)
|
||||
return object.vars[text]
|
||||
else
|
||||
return null
|
||||
|
||||
|
||||
/proc/text_starts_with(text, start)
|
||||
if(copytext(text, 1, length(start) + 1) == start)
|
||||
return 1
|
||||
else
|
||||
return 0
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/proc/SDQL_tokenize(query_text)
|
||||
|
||||
var/list/whitespace = list(" ", "\n", "\t")
|
||||
var/list/single = list("(", ")", ",", "+", "-")
|
||||
var/list/multi = list(
|
||||
"=" = list("", "="),
|
||||
"<" = list("", "=", ">"),
|
||||
">" = list("", "="),
|
||||
"!" = list("", "="))
|
||||
|
||||
var/word = ""
|
||||
var/list/query_list = list()
|
||||
var/len = length(query_text)
|
||||
|
||||
for(var/i = 1, i <= len, i++)
|
||||
var/char = copytext(query_text, i, i + 1)
|
||||
|
||||
if(char in whitespace)
|
||||
if(word != "")
|
||||
query_list += word
|
||||
word = ""
|
||||
|
||||
else if(char in single)
|
||||
if(word != "")
|
||||
query_list += word
|
||||
word = ""
|
||||
|
||||
query_list += char
|
||||
|
||||
else if(char in multi)
|
||||
if(word != "")
|
||||
query_list += word
|
||||
word = ""
|
||||
|
||||
var/char2 = copytext(query_text, i + 1, i + 2)
|
||||
|
||||
if(char2 in multi[char])
|
||||
query_list += "[char][char2]"
|
||||
i++
|
||||
|
||||
else
|
||||
query_list += char
|
||||
|
||||
else if(char == "'")
|
||||
if(word != "")
|
||||
usr << "<font color='red'>SDQL: You have an error in your SDQL syntax, unexpected ' in query:</font> \"<font color=gray>[query_text]</font>\" following \"<font color=gray>[word]</font>\". Please check your syntax, and try again."
|
||||
return null
|
||||
|
||||
word = "'"
|
||||
|
||||
for(i++, i <= len, i++)
|
||||
char = copytext(query_text, i, i + 1)
|
||||
|
||||
if(char == "'")
|
||||
if(copytext(query_text, i + 1, i + 2) == "'")
|
||||
word += "'"
|
||||
i++
|
||||
|
||||
else
|
||||
break
|
||||
|
||||
else
|
||||
word += char
|
||||
|
||||
if(i > len)
|
||||
usr << "<font color='red'>SDQL: You have an error in your SDQL syntax, unmatched ' in query: </font>\"<font color=gray>[query_text]</font>\". Please check your syntax, and try again."
|
||||
return null
|
||||
|
||||
query_list += "[word]'"
|
||||
word = ""
|
||||
|
||||
else if(char == "\"")
|
||||
if(word != "")
|
||||
usr << "<font color='red'>SDQL: You have an error in your SDQL syntax, unexpected \" in query: </font>\"<font color=gray>[query_text]</font>\" following \"<font color=gray>[word]</font>\". Please check your syntax, and try again."
|
||||
return null
|
||||
|
||||
word = "\""
|
||||
|
||||
for(i++, i <= len, i++)
|
||||
char = copytext(query_text, i, i + 1)
|
||||
|
||||
if(char == "\"")
|
||||
if(copytext(query_text, i + 1, i + 2) == "'")
|
||||
word += "\""
|
||||
i++
|
||||
|
||||
else
|
||||
break
|
||||
|
||||
else
|
||||
word += char
|
||||
|
||||
if(i > len)
|
||||
usr << "<font color='red'>SDQL: You have an error in your SDQL syntax, unmatched \" in query: </font>\"<font color=gray>[query_text]</font>\". Please check your syntax, and try again."
|
||||
return null
|
||||
|
||||
query_list += "[word]\""
|
||||
word = ""
|
||||
|
||||
else
|
||||
word += char
|
||||
|
||||
if(word != "")
|
||||
query_list += word
|
||||
|
||||
return query_list
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,635 @@
|
||||
|
||||
//I'm pretty sure that this is a recursive [s]descent[/s] ascent parser.
|
||||
|
||||
|
||||
//Spec
|
||||
|
||||
//////////
|
||||
//
|
||||
// query : select_query | delete_query | update_query | call_query | explain
|
||||
// explain : 'EXPLAIN' query
|
||||
// select_query : 'SELECT' object_selectors
|
||||
// delete_query : 'DELETE' object_selectors
|
||||
// update_query : 'UPDATE' object_selectors 'SET' assignments
|
||||
// call_query : 'CALL' variable 'ON' object_selectors // Note here: 'variable' does function calls. This simplifies parsing.
|
||||
//
|
||||
// select_item : '*' | object_type
|
||||
//
|
||||
// object_selectors : select_item [('FROM' | 'IN') from_item] [modifier_list]
|
||||
// modifier_list : ('WHERE' bool_expression | 'MAP' expression) [modifier_list]
|
||||
//
|
||||
// from_item : 'world' | expression
|
||||
//
|
||||
// call_function : <function name> '(' [arguments] ')'
|
||||
// arguments : expression [',' arguments]
|
||||
//
|
||||
// object_type : <type path>
|
||||
//
|
||||
// assignments : assignment [',' assignments]
|
||||
// assignment : <variable name> '=' expression
|
||||
// variable : <variable name> | <variable name> '.' variable | '[' <hex number> ']' | '[' <hex number> ']' '.' variable
|
||||
//
|
||||
// bool_expression : expression comparitor expression [bool_operator bool_expression]
|
||||
// expression : ( unary_expression | '(' expression ')' | value ) [binary_operator expression]
|
||||
// unary_expression : unary_operator ( unary_expression | value | '(' expression ')' )
|
||||
// comparitor : '=' | '==' | '!=' | '<>' | '<' | '<=' | '>' | '>='
|
||||
// value : variable | string | number | 'null' | object_type
|
||||
// unary_operator : '!' | '-' | '~'
|
||||
// binary_operator : comparitor | '+' | '-' | '/' | '*' | '&' | '|' | '^' | '%'
|
||||
// bool_operator : 'AND' | '&&' | 'OR' | '||'
|
||||
//
|
||||
// string : ''' <some text> ''' | '"' <some text > '"'
|
||||
// number : <some digits>
|
||||
//
|
||||
//////////
|
||||
|
||||
/datum/SDQL_parser
|
||||
var/query_type
|
||||
var/error = 0
|
||||
|
||||
var/list/query
|
||||
var/list/tree
|
||||
|
||||
var/list/boolean_operators = list("and", "or", "&&", "||")
|
||||
var/list/unary_operators = list("!", "-", "~")
|
||||
var/list/binary_operators = list("+", "-", "/", "*", "&", "|", "^", "%")
|
||||
var/list/comparitors = list("=", "==", "!=", "<>", "<", "<=", ">", ">=")
|
||||
|
||||
/datum/SDQL_parser/New(query_list)
|
||||
query = query_list
|
||||
|
||||
/datum/SDQL_parser/proc/parse_error(error_message)
|
||||
error = 1
|
||||
to_chat(usr, "<span class='warning'>SQDL2 Parsing Error: [error_message]</span>")
|
||||
return query.len + 1
|
||||
|
||||
/datum/SDQL_parser/proc/parse()
|
||||
tree = list()
|
||||
query_options(1, tree)
|
||||
|
||||
if(error)
|
||||
return list()
|
||||
else
|
||||
return tree
|
||||
|
||||
/datum/SDQL_parser/proc/token(i)
|
||||
if(i <= query.len)
|
||||
return query[i]
|
||||
|
||||
else
|
||||
return null
|
||||
|
||||
/datum/SDQL_parser/proc/tokens(i, num)
|
||||
if(i + num <= query.len)
|
||||
return query.Copy(i, i + num)
|
||||
|
||||
else
|
||||
return null
|
||||
|
||||
/datum/SDQL_parser/proc/tokenl(i)
|
||||
return lowertext(token(i))
|
||||
|
||||
/datum/SDQL_parser/proc/query_options(i, list/node)
|
||||
var/list/options = list()
|
||||
if(tokenl(i) == "using")
|
||||
i = option_assignments(i + 1, node, options)
|
||||
query(i, node)
|
||||
if(length(options))
|
||||
node["options"] = options
|
||||
|
||||
//option_assignment: query_option '=' define
|
||||
/datum/SDQL_parser/proc/option_assignment(i, list/node, list/assignment_list = list())
|
||||
var/type = tokenl(i)
|
||||
if(!(type in SDQL2_VALID_OPTION_TYPES))
|
||||
parse_error("Invalid option type: [type]")
|
||||
if(!(token(i + 1) == "="))
|
||||
parse_error("Invalid option assignment symbol: [token(i + 1)]")
|
||||
var/val = tokenl(i + 2)
|
||||
if(!(val in SDQL2_VALID_OPTION_VALUES))
|
||||
parse_error("Invalid optoin value: [val]")
|
||||
assignment_list[type] = val
|
||||
return (i + 3)
|
||||
|
||||
//option_assignments: option_assignment, [',' option_assignments]
|
||||
/datum/SDQL_parser/proc/option_assignments(i, list/node, list/store)
|
||||
i = option_assignment(i, node, store)
|
||||
|
||||
if(token(i) == ",")
|
||||
i = option_assignments(i + 1, node, store)
|
||||
|
||||
return i
|
||||
|
||||
//query: select_query | delete_query | update_query
|
||||
/datum/SDQL_parser/proc/query(i, list/node)
|
||||
query_type = tokenl(i)
|
||||
|
||||
switch(query_type)
|
||||
if("select")
|
||||
select_query(i, node)
|
||||
|
||||
if("delete")
|
||||
delete_query(i, node)
|
||||
|
||||
if("update")
|
||||
update_query(i, node)
|
||||
|
||||
if("call")
|
||||
call_query(i, node)
|
||||
|
||||
if("explain")
|
||||
node += "explain"
|
||||
node["explain"] = list()
|
||||
query(i + 1, node["explain"])
|
||||
|
||||
|
||||
// select_query: 'SELECT' object_selectors
|
||||
/datum/SDQL_parser/proc/select_query(i, list/node)
|
||||
var/list/select = list()
|
||||
i = object_selectors(i + 1, select)
|
||||
|
||||
node["select"] = select
|
||||
return i
|
||||
|
||||
|
||||
//delete_query: 'DELETE' object_selectors
|
||||
/datum/SDQL_parser/proc/delete_query(i, list/node)
|
||||
var/list/select = list()
|
||||
i = object_selectors(i + 1, select)
|
||||
|
||||
node["delete"] = select
|
||||
|
||||
return i
|
||||
|
||||
|
||||
//update_query: 'UPDATE' object_selectors 'SET' assignments
|
||||
/datum/SDQL_parser/proc/update_query(i, list/node)
|
||||
var/list/select = list()
|
||||
i = object_selectors(i + 1, select)
|
||||
|
||||
node["update"] = select
|
||||
|
||||
if(tokenl(i) != "set")
|
||||
i = parse_error("UPDATE has misplaced SET")
|
||||
|
||||
var/list/set_assignments = list()
|
||||
i = assignments(i + 1, set_assignments)
|
||||
|
||||
node["set"] = set_assignments
|
||||
|
||||
return i
|
||||
|
||||
|
||||
//call_query: 'CALL' call_function ['ON' object_selectors]
|
||||
/datum/SDQL_parser/proc/call_query(i, list/node)
|
||||
var/list/func = list()
|
||||
i = variable(i + 1, func) // Yes technically does anything variable() matches but I don't care, if admins fuck up this badly then they shouldn't be allowed near SDQL.
|
||||
|
||||
node["call"] = func
|
||||
|
||||
if(tokenl(i) != "on")
|
||||
return parse_error("You need to specify what to call ON.")
|
||||
|
||||
var/list/select = list()
|
||||
i = object_selectors(i + 1, select)
|
||||
|
||||
node["on"] = select
|
||||
|
||||
return i
|
||||
|
||||
// object_selectors: select_item [('FROM' | 'IN') from_item] [modifier_list]
|
||||
/datum/SDQL_parser/proc/object_selectors(i, list/node)
|
||||
i = select_item(i, node)
|
||||
|
||||
if (tokenl(i) == "from" || tokenl(i) == "in")
|
||||
i++
|
||||
var/list/from = list()
|
||||
i = from_item(i, from)
|
||||
node[++node.len] = from
|
||||
|
||||
else
|
||||
node[++node.len] = list("world")
|
||||
|
||||
i = modifier_list(i, node)
|
||||
return i
|
||||
|
||||
// modifier_list: ('WHERE' bool_expression | 'MAP' expression) [modifier_list]
|
||||
/datum/SDQL_parser/proc/modifier_list(i, list/node)
|
||||
while (TRUE)
|
||||
if (tokenl(i) == "where")
|
||||
i++
|
||||
node += "where"
|
||||
var/list/expr = list()
|
||||
i = bool_expression(i, expr)
|
||||
node[++node.len] = expr
|
||||
|
||||
else if (tokenl(i) == "map")
|
||||
i++
|
||||
node += "map"
|
||||
var/list/expr = list()
|
||||
i = expression(i, expr)
|
||||
node[++node.len] = expr
|
||||
|
||||
else
|
||||
return i
|
||||
|
||||
//select_list:select_item [',' select_list]
|
||||
/datum/SDQL_parser/proc/select_list(i, list/node)
|
||||
i = select_item(i, node)
|
||||
|
||||
if(token(i) == ",")
|
||||
i = select_list(i + 1, node)
|
||||
|
||||
return i
|
||||
|
||||
//assignments: assignment, [',' assignments]
|
||||
/datum/SDQL_parser/proc/assignments(i, list/node)
|
||||
i = assignment(i, node)
|
||||
|
||||
if(token(i) == ",")
|
||||
i = assignments(i + 1, node)
|
||||
|
||||
return i
|
||||
|
||||
|
||||
//select_item: '*' | select_function | object_type
|
||||
/datum/SDQL_parser/proc/select_item(i, list/node)
|
||||
if (token(i) == "*")
|
||||
node += "*"
|
||||
i++
|
||||
|
||||
else if (copytext(token(i), 1, 2) == "/")
|
||||
i = object_type(i, node)
|
||||
|
||||
else
|
||||
i = parse_error("Expected '*' or type path for select item")
|
||||
|
||||
return i
|
||||
|
||||
// Standardized method for handling the IN/FROM and WHERE options.
|
||||
/datum/SDQL_parser/proc/selectors(i, list/node)
|
||||
while (token(i))
|
||||
var/tok = tokenl(i)
|
||||
if (tok in list("from", "in"))
|
||||
var/list/from = list()
|
||||
i = from_item(i + 1, from)
|
||||
|
||||
node["from"] = from
|
||||
continue
|
||||
|
||||
if (tok == "where")
|
||||
var/list/where = list()
|
||||
i = bool_expression(i + 1, where)
|
||||
|
||||
node["where"] = where
|
||||
continue
|
||||
|
||||
parse_error("Expected either FROM, IN or WHERE token, found [token(i)] instead.")
|
||||
return i + 1
|
||||
|
||||
if (!node.Find("from"))
|
||||
node["from"] = list("world")
|
||||
|
||||
return i
|
||||
|
||||
//from_item: 'world' | expression
|
||||
/datum/SDQL_parser/proc/from_item(i, list/node)
|
||||
if(token(i) == "world")
|
||||
node += "world"
|
||||
i++
|
||||
|
||||
else
|
||||
i = expression(i, node)
|
||||
|
||||
return i
|
||||
|
||||
|
||||
//bool_expression: expression [bool_operator bool_expression]
|
||||
/datum/SDQL_parser/proc/bool_expression(i, list/node)
|
||||
|
||||
var/list/bool = list()
|
||||
i = expression(i, bool)
|
||||
|
||||
node[++node.len] = bool
|
||||
|
||||
if(tokenl(i) in boolean_operators)
|
||||
i = bool_operator(i, node)
|
||||
i = bool_expression(i, node)
|
||||
|
||||
return i
|
||||
|
||||
|
||||
//assignment: <variable name> '=' expression
|
||||
/datum/SDQL_parser/proc/assignment(var/i, var/list/node, var/list/assignment_list = list())
|
||||
assignment_list += token(i)
|
||||
|
||||
if(token(i + 1) == ".")
|
||||
i = assignment(i + 2, node, assignment_list)
|
||||
|
||||
else if(token(i + 1) == "=")
|
||||
var/exp_list = list()
|
||||
node[assignment_list] = exp_list
|
||||
|
||||
i = expression(i + 2, exp_list)
|
||||
|
||||
else
|
||||
parse_error("Assignment expected, but no = found")
|
||||
|
||||
return i
|
||||
|
||||
|
||||
//variable: <variable name> | <variable name> '.' variable | '[' <hex number> ']' | '[' <hex number> ']' '.' variable
|
||||
/datum/SDQL_parser/proc/variable(i, list/node)
|
||||
var/list/L = list(token(i))
|
||||
node[++node.len] = L
|
||||
|
||||
if(token(i) == "{")
|
||||
L += token(i + 1)
|
||||
i += 2
|
||||
|
||||
if(token(i) != "}")
|
||||
parse_error("Missing } at end of pointer.")
|
||||
|
||||
if(token(i + 1) == ".")
|
||||
L += "."
|
||||
i = variable(i + 2, L)
|
||||
|
||||
else if (token(i + 1) == "(") // OH BOY PROC
|
||||
var/list/arguments = list()
|
||||
i = call_function(i, null, arguments)
|
||||
L += ":"
|
||||
L[++L.len] = arguments
|
||||
|
||||
else if (token(i + 1) == "\[")
|
||||
var/list/expression = list()
|
||||
i = expression(i + 2, expression)
|
||||
if (token(i) != "]")
|
||||
parse_error("Missing ] at the end of list access.")
|
||||
|
||||
L += "\["
|
||||
L[++L.len] = expression
|
||||
i++
|
||||
|
||||
else
|
||||
i++
|
||||
|
||||
return i
|
||||
|
||||
|
||||
//object_type: <type path>
|
||||
/datum/SDQL_parser/proc/object_type(i, list/node)
|
||||
|
||||
if (copytext(token(i), 1, 2) != "/")
|
||||
return parse_error("Expected type, but it didn't begin with /")
|
||||
|
||||
var/path = text2path(token(i))
|
||||
if (path == null)
|
||||
return parse_error("Nonexistant type path: [token(i)]")
|
||||
|
||||
node += path
|
||||
|
||||
return i + 1
|
||||
|
||||
|
||||
//comparitor: '=' | '==' | '!=' | '<>' | '<' | '<=' | '>' | '>='
|
||||
/datum/SDQL_parser/proc/comparitor(i, list/node)
|
||||
|
||||
if(token(i) in list("=", "==", "!=", "<>", "<", "<=", ">", ">="))
|
||||
node += token(i)
|
||||
|
||||
else
|
||||
parse_error("Unknown comparitor [token(i)]")
|
||||
|
||||
return i + 1
|
||||
|
||||
|
||||
//bool_operator: 'AND' | '&&' | 'OR' | '||'
|
||||
/datum/SDQL_parser/proc/bool_operator(i, list/node)
|
||||
|
||||
if(tokenl(i) in list("and", "or", "&&", "||"))
|
||||
node += token(i)
|
||||
|
||||
else
|
||||
parse_error("Unknown comparitor [token(i)]")
|
||||
|
||||
return i + 1
|
||||
|
||||
|
||||
//string: ''' <some text> ''' | '"' <some text > '"'
|
||||
/datum/SDQL_parser/proc/string(i, list/node)
|
||||
|
||||
if(copytext(token(i), 1, 2) in list("'", "\""))
|
||||
node += token(i)
|
||||
|
||||
else
|
||||
parse_error("Expected string but found '[token(i)]'")
|
||||
|
||||
return i + 1
|
||||
|
||||
//array: '[' expression, expression, ... ']'
|
||||
/datum/SDQL_parser/proc/array(var/i, var/list/node)
|
||||
// Arrays get turned into this: list("[", list(exp_1a = exp_1b, ...), ...), "[" is to mark the next node as an array.
|
||||
if(copytext(token(i), 1, 2) != "\[")
|
||||
parse_error("Expected an array but found '[token(i)]'")
|
||||
return i + 1
|
||||
|
||||
node += token(i) // Add the "["
|
||||
|
||||
var/list/expression_list = list()
|
||||
|
||||
i++
|
||||
if(token(i) != "]")
|
||||
var/list/temp_expression_list = list()
|
||||
var/tok
|
||||
do
|
||||
tok = token(i)
|
||||
if (tok == "," || tok == ":")
|
||||
if (temp_expression_list == null)
|
||||
parse_error("Found ',' or ':' without expression in an array.")
|
||||
return i + 1
|
||||
|
||||
expression_list[++expression_list.len] = temp_expression_list
|
||||
temp_expression_list = null
|
||||
if (tok == ":")
|
||||
temp_expression_list = list()
|
||||
i = expression(i + 1, temp_expression_list)
|
||||
expression_list[expression_list[expression_list.len]] = temp_expression_list
|
||||
temp_expression_list = null
|
||||
tok = token(i)
|
||||
if (tok != ",")
|
||||
if (tok == "]")
|
||||
break
|
||||
|
||||
parse_error("Expected ',' or ']' after array assoc value, but found '[token(i)]'")
|
||||
return i
|
||||
|
||||
|
||||
i++
|
||||
continue
|
||||
|
||||
temp_expression_list = list()
|
||||
i = expression(i, temp_expression_list)
|
||||
|
||||
// Ok, what the fuck BYOND?
|
||||
// Not having these lines here causes the parser to die
|
||||
// on an error saying that list/token() doesn't exist as a proc.
|
||||
// These lines prevent that.
|
||||
// I assume the compiler/VM is shitting itself and swapping out some variables internally?
|
||||
// While throwing in debug logging it disappeared
|
||||
// And these 3 lines prevent it from happening while being quiet.
|
||||
// So.. it works.
|
||||
// Don't touch it.
|
||||
var/whatthefuck = i
|
||||
whatthefuck = src.type
|
||||
whatthefuck = whatthefuck
|
||||
|
||||
while(token(i) && token(i) != "]")
|
||||
|
||||
if (temp_expression_list)
|
||||
expression_list[++expression_list.len] = temp_expression_list
|
||||
|
||||
node[++node.len] = expression_list
|
||||
|
||||
return i + 1
|
||||
|
||||
//call_function: <function name> ['(' [arguments] ')']
|
||||
/datum/SDQL_parser/proc/call_function(i, list/node, list/arguments)
|
||||
if(length(tokenl(i)))
|
||||
var/procname = ""
|
||||
if(tokenl(i) == "global" && token(i + 1) == ".") // Global proc.
|
||||
i += 2
|
||||
procname = "global."
|
||||
node += procname + token(i++)
|
||||
if(token(i) != "(")
|
||||
parse_error("Expected ( but found '[token(i)]'")
|
||||
|
||||
else if(token(i + 1) != ")")
|
||||
var/list/temp_expression_list = list()
|
||||
do
|
||||
i = expression(i + 1, temp_expression_list)
|
||||
if(token(i) == ",")
|
||||
arguments[++arguments.len] = temp_expression_list
|
||||
temp_expression_list = list()
|
||||
continue
|
||||
|
||||
while(token(i) && token(i) != ")")
|
||||
|
||||
arguments[++arguments.len] = temp_expression_list // The code this is copy pasted from won't be executed when it's the last param, this fixes that.
|
||||
else
|
||||
i++
|
||||
else
|
||||
parse_error("Expected a function but found nothing")
|
||||
return i + 1
|
||||
|
||||
|
||||
//expression: ( unary_expression | '(' expression ')' | value ) [binary_operator expression]
|
||||
/datum/SDQL_parser/proc/expression(i, list/node)
|
||||
|
||||
if(token(i) in unary_operators)
|
||||
i = unary_expression(i, node)
|
||||
|
||||
else if(token(i) == "(")
|
||||
var/list/expr = list()
|
||||
|
||||
i = expression(i + 1, expr)
|
||||
|
||||
if(token(i) != ")")
|
||||
parse_error("Missing ) at end of expression.")
|
||||
|
||||
else
|
||||
i++
|
||||
|
||||
node[++node.len] = expr
|
||||
|
||||
else
|
||||
i = value(i, node)
|
||||
|
||||
if(token(i) in binary_operators)
|
||||
i = binary_operator(i, node)
|
||||
i = expression(i, node)
|
||||
|
||||
else if(token(i) in comparitors)
|
||||
i = binary_operator(i, node)
|
||||
|
||||
var/list/rhs = list()
|
||||
i = expression(i, rhs)
|
||||
|
||||
node[++node.len] = rhs
|
||||
|
||||
|
||||
return i
|
||||
|
||||
|
||||
//unary_expression: unary_operator ( unary_expression | value | '(' expression ')' )
|
||||
/datum/SDQL_parser/proc/unary_expression(i, list/node)
|
||||
|
||||
if(token(i) in unary_operators)
|
||||
var/list/unary_exp = list()
|
||||
|
||||
unary_exp += token(i)
|
||||
i++
|
||||
|
||||
if(token(i) in unary_operators)
|
||||
i = unary_expression(i, unary_exp)
|
||||
|
||||
else if(token(i) == "(")
|
||||
var/list/expr = list()
|
||||
|
||||
i = expression(i + 1, expr)
|
||||
|
||||
if(token(i) != ")")
|
||||
parse_error("Missing ) at end of expression.")
|
||||
|
||||
else
|
||||
i++
|
||||
|
||||
unary_exp[++unary_exp.len] = expr
|
||||
|
||||
else
|
||||
i = value(i, unary_exp)
|
||||
|
||||
node[++node.len] = unary_exp
|
||||
|
||||
|
||||
else
|
||||
parse_error("Expected unary operator but found '[token(i)]'")
|
||||
|
||||
return i
|
||||
|
||||
|
||||
//binary_operator: comparitor | '+' | '-' | '/' | '*' | '&' | '|' | '^' | '%'
|
||||
/datum/SDQL_parser/proc/binary_operator(i, list/node)
|
||||
|
||||
if(token(i) in (binary_operators + comparitors))
|
||||
node += token(i)
|
||||
|
||||
else
|
||||
parse_error("Unknown binary operator [token(i)]")
|
||||
|
||||
return i + 1
|
||||
|
||||
|
||||
//value: variable | string | number | 'null' | object_type
|
||||
/datum/SDQL_parser/proc/value(i, list/node)
|
||||
if(token(i) == "null")
|
||||
node += "null"
|
||||
i++
|
||||
|
||||
else if(lowertext(copytext(token(i), 1, 3)) == "0x" && isnum(hex2num(copytext(token(i), 3))))
|
||||
node += hex2num(copytext(token(i), 3))
|
||||
i++
|
||||
|
||||
else if(isnum(text2num(token(i))))
|
||||
node += text2num(token(i))
|
||||
i++
|
||||
|
||||
else if(copytext(token(i), 1, 2) in list("'", "\""))
|
||||
i = string(i, node)
|
||||
|
||||
else if(copytext(token(i), 1, 2) == "\[") // Start a list.
|
||||
i = array(i, node)
|
||||
else if(copytext(token(i), 1, 2) == "/")
|
||||
i = object_type(i, node)
|
||||
else
|
||||
i = variable(i, node)
|
||||
|
||||
return i
|
||||
@@ -0,0 +1,215 @@
|
||||
// Wrappers for BYOND default procs which can't directly be called by call().
|
||||
|
||||
/proc/_abs(A)
|
||||
return abs(A)
|
||||
|
||||
/proc/_animate(atom/A, set_vars, time = 10, loop = 1, easing = LINEAR_EASING, flags = null)
|
||||
var/mutable_appearance/MA = new()
|
||||
for(var/v in set_vars)
|
||||
MA.vars[v] = set_vars[v]
|
||||
animate(A, appearance = MA, time, loop, easing, flags)
|
||||
|
||||
/proc/_acrccos(A)
|
||||
return arccos(A)
|
||||
|
||||
/proc/_arcsin(A)
|
||||
return arcsin(A)
|
||||
|
||||
/proc/_ascii2text(A)
|
||||
return ascii2text(A)
|
||||
|
||||
/proc/_block(Start, End)
|
||||
return block(Start, End)
|
||||
|
||||
/proc/_ckey(Key)
|
||||
return ckey(Key)
|
||||
|
||||
/proc/_ckeyEx(Key)
|
||||
return ckeyEx(Key)
|
||||
|
||||
/proc/_copytext(T, Start = 1, End = 0)
|
||||
return copytext(T, Start, End)
|
||||
|
||||
/proc/_cos(X)
|
||||
return cos(X)
|
||||
|
||||
/proc/_get_dir(Loc1, Loc2)
|
||||
return get_dir(Loc1, Loc2)
|
||||
|
||||
/proc/_get_dist(Loc1, Loc2)
|
||||
return get_dist(Loc1, Loc2)
|
||||
|
||||
/proc/_get_step(Ref, Dir)
|
||||
return get_step(Ref, Dir)
|
||||
|
||||
/proc/_hearers(Depth = world.view, Center = usr)
|
||||
return hearers(Depth, Center)
|
||||
|
||||
/proc/_image(icon, loc, icon_state, layer, dir)
|
||||
return image(icon, loc, icon_state, layer, dir)
|
||||
|
||||
/proc/_istype(object, type)
|
||||
return istype(object, type)
|
||||
|
||||
/proc/_ispath(path, type)
|
||||
return ispath(path, type)
|
||||
|
||||
/proc/_length(E)
|
||||
return length(E)
|
||||
|
||||
/proc/_link(thing, url)
|
||||
thing << link(url)
|
||||
|
||||
/proc/_locate(X, Y, Z)
|
||||
if (isnull(Y)) // Assuming that it's only a single-argument call.
|
||||
return locate(X)
|
||||
|
||||
return locate(X, Y, Z)
|
||||
|
||||
/proc/_log(X, Y)
|
||||
return log(X, Y)
|
||||
|
||||
/proc/_lowertext(T)
|
||||
return lowertext(T)
|
||||
|
||||
/proc/_matrix(a, b, c, d, e, f)
|
||||
return matrix(a, b, c, d, e, f)
|
||||
|
||||
/proc/_max(...)
|
||||
return max(arglist(args))
|
||||
|
||||
/proc/_md5(T)
|
||||
return md5(T)
|
||||
|
||||
/proc/_min(...)
|
||||
return min(arglist(args))
|
||||
|
||||
/proc/_new(type, arguments)
|
||||
return new type (arglist(arguments))
|
||||
|
||||
/proc/_num2text(N, SigFig = 6)
|
||||
return num2text(N, SigFig)
|
||||
|
||||
/proc/_ohearers(Dist, Center = usr)
|
||||
return ohearers(Dist, Center)
|
||||
|
||||
/proc/_orange(Dist, Center = usr)
|
||||
return orange(Dist, Center)
|
||||
|
||||
/proc/_output(thing, msg, control)
|
||||
thing << output(msg, control)
|
||||
|
||||
/proc/_oview(Dist, Center = usr)
|
||||
return oview(Dist, Center)
|
||||
|
||||
/proc/_oviewers(Dist, Center = usr)
|
||||
return oviewers(Dist, Center)
|
||||
|
||||
/proc/_params2list(Params)
|
||||
return params2list(Params)
|
||||
|
||||
/proc/_pick(...)
|
||||
return pick(arglist(args))
|
||||
|
||||
/proc/_prob(P)
|
||||
return prob(P)
|
||||
|
||||
/proc/_rand(L = 0, H = 1)
|
||||
return rand(L, H)
|
||||
|
||||
/proc/_range(Dist, Center = usr)
|
||||
return range(Dist, Center)
|
||||
|
||||
/proc/_regex(pattern, flags)
|
||||
return regex(pattern, flags)
|
||||
|
||||
/proc/_REGEX_QUOTE(text)
|
||||
return REGEX_QUOTE(text)
|
||||
|
||||
/proc/_REGEX_QUOTE_REPLACEMENT(text)
|
||||
return REGEX_QUOTE_REPLACEMENT(text)
|
||||
|
||||
/proc/_replacetext(Haystack, Needle, Replacement, Start = 1,End = 0)
|
||||
return replacetext(Haystack, Needle, Replacement, Start, End)
|
||||
|
||||
/proc/_replacetextEx(Haystack, Needle, Replacement, Start = 1,End = 0)
|
||||
return replacetextEx(Haystack, Needle, Replacement, Start, End)
|
||||
|
||||
/proc/_rgb(R, G, B)
|
||||
return rgb(R, G, B)
|
||||
|
||||
/proc/_rgba(R, G, B, A)
|
||||
return rgb(R, G, B, A)
|
||||
|
||||
/proc/_roll(dice)
|
||||
return roll(dice)
|
||||
|
||||
/proc/_round(A, B = 1)
|
||||
return round(A, B)
|
||||
|
||||
/proc/_sin(X)
|
||||
return sin(X)
|
||||
|
||||
/proc/_list_add(list/L, ...)
|
||||
if (args.len < 2)
|
||||
return
|
||||
L += args.Copy(2)
|
||||
|
||||
/proc/_list_copy(list/L, Start = 1, End = 0)
|
||||
return L.Copy(Start, End)
|
||||
|
||||
/proc/_list_cut(list/L, Start = 1, End = 0)
|
||||
L.Cut(Start, End)
|
||||
|
||||
/proc/_list_find(list/L, Elem, Start = 1, End = 0)
|
||||
return L.Find(Elem, Start, End)
|
||||
|
||||
/proc/_list_insert(list/L, Index, Item)
|
||||
return L.Insert(Index, Item)
|
||||
|
||||
/proc/_list_join(list/L, Glue, Start = 0, End = 1)
|
||||
return L.Join(Glue, Start, End)
|
||||
|
||||
/proc/_list_remove(list/L, ...)
|
||||
if (args.len < 2)
|
||||
return
|
||||
L -= args.Copy(2)
|
||||
|
||||
/proc/_list_set(list/L, key, value)
|
||||
L[key] = value
|
||||
|
||||
/proc/_list_numerical_add(L, key, num)
|
||||
L[key] += num
|
||||
|
||||
/proc/_list_swap(list/L, Index1, Index2)
|
||||
L.Swap(Index1, Index2)
|
||||
|
||||
/proc/_walk(ref, dir, lag)
|
||||
walk(ref, dir, lag)
|
||||
|
||||
/proc/_walk_towards(ref, trg, lag)
|
||||
walk_towards(ref, trg, lag)
|
||||
|
||||
/proc/_walk_to(ref, trg, min, lag)
|
||||
walk_to(ref, trg, min, lag)
|
||||
|
||||
/proc/_walk_away(ref, trg, max, lag)
|
||||
walk_away(ref, trg, max, lag)
|
||||
|
||||
/proc/_walk_rand(ref, lag)
|
||||
walk_rand(ref, lag)
|
||||
|
||||
/proc/_step(ref, dir)
|
||||
step(ref, dir)
|
||||
|
||||
/proc/_step_rand(ref)
|
||||
step_rand(ref)
|
||||
|
||||
/proc/_step_to(ref, trg, min)
|
||||
step_to(ref, trg, min)
|
||||
|
||||
/proc/_step_towards(ref, trg)
|
||||
step_towards(ref, trg)
|
||||
|
||||
/proc/_step_away(ref, trg, max)
|
||||
step_away(ref, trg, max)
|
||||
@@ -1,426 +0,0 @@
|
||||
|
||||
|
||||
/client/proc/SDQL2_query(query_text as message)
|
||||
set category = "Admin"
|
||||
if(!check_rights(R_DEBUG)) //Shouldn't happen... but just to be safe.
|
||||
message_admins("<font color='red'>ERROR: Non-admin [usr.key] attempted to execute a SDQL query!</font>")
|
||||
log_admin("Non-admin [usr.key] attempted to execute a SDQL query!")
|
||||
|
||||
if(!query_text || length(query_text) < 1)
|
||||
return
|
||||
|
||||
//world << query_text
|
||||
|
||||
var/list/query_list = SDQL2_tokenize(query_text)
|
||||
|
||||
if(!query_list || query_list.len < 1)
|
||||
return
|
||||
|
||||
var/list/query_tree = SDQL_parse(query_list)
|
||||
|
||||
if(query_tree.len < 1)
|
||||
return
|
||||
|
||||
var/list/from_objs = list()
|
||||
var/list/select_types = list()
|
||||
|
||||
switch(query_tree[1])
|
||||
if("explain")
|
||||
SDQL_testout(query_tree["explain"])
|
||||
return
|
||||
|
||||
if("call")
|
||||
if("on" in query_tree)
|
||||
select_types = query_tree["on"]
|
||||
else
|
||||
return
|
||||
|
||||
if("select", "delete", "update")
|
||||
select_types = query_tree[query_tree[1]]
|
||||
|
||||
from_objs = SDQL_from_objs(query_tree["from"])
|
||||
|
||||
var/list/objs = list()
|
||||
|
||||
for(var/type in select_types)
|
||||
var/char = copytext(type, 1, 2)
|
||||
|
||||
if(char == "/" || char == "*")
|
||||
for(var/from in from_objs)
|
||||
objs += SDQL_get_all(type, from)
|
||||
|
||||
else if(char == "'" || char == "\"")
|
||||
objs += locate(copytext(type, 2, length(type)))
|
||||
|
||||
if("where" in query_tree)
|
||||
var/objs_temp = objs
|
||||
objs = list()
|
||||
for(var/datum/d in objs_temp)
|
||||
if(SDQL_expression(d, query_tree["where"]))
|
||||
objs += d
|
||||
|
||||
//usr << "Query: [query_text]"
|
||||
message_admins("[usr] executed SDQL query: \"[query_text]\".")
|
||||
|
||||
switch(query_tree[1])
|
||||
if("delete")
|
||||
for(var/datum/d in objs)
|
||||
qdel(d)
|
||||
|
||||
if("select")
|
||||
var/text = ""
|
||||
for(var/datum/t in objs)
|
||||
if(istype(t, /atom))
|
||||
var/atom/a = t
|
||||
|
||||
if(a.x)
|
||||
text += "<a href='?src=\ref[t];SDQL_select=\ref[t]'>\ref[t]</a>: [t] at ([a.x], [a.y], [a.z])<br>"
|
||||
|
||||
else if(a.loc && a.loc.x)
|
||||
text += "<a href='?src=\ref[t];SDQL_select=\ref[t]'>\ref[t]</a>: [t] in [a.loc] at ([a.loc.x], [a.loc.y], [a.loc.z])<br>"
|
||||
|
||||
else
|
||||
text += "<a href='?src=\ref[t];SDQL_select=\ref[t]'>\ref[t]</a>: [t]<br>"
|
||||
|
||||
else
|
||||
text += "<a href='?src=\ref[t];SDQL_select=\ref[t]'>\ref[t]</a>: [t]<br>"
|
||||
|
||||
usr << browse(text, "window=SDQL-result")
|
||||
|
||||
if("update")
|
||||
if("set" in query_tree)
|
||||
var/list/set_list = query_tree["set"]
|
||||
for(var/datum/d in objs)
|
||||
var/list/vals = list()
|
||||
for(var/v in set_list)
|
||||
if(v in d.vars)
|
||||
vals += v
|
||||
vals[v] = SDQL_expression(d, set_list[v])
|
||||
|
||||
if(istype(d, /turf))
|
||||
for(var/v in vals)
|
||||
if(v == "x" || v == "y" || v == "z")
|
||||
continue
|
||||
|
||||
d.vars[v] = vals[v]
|
||||
|
||||
else
|
||||
for(var/v in vals)
|
||||
d.vars[v] = vals[v]
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/proc/SDQL_parse(list/query_list)
|
||||
var/datum/SDQL_parser/parser = new(query_list)
|
||||
var/list/query_tree = parser.parse()
|
||||
|
||||
qdel(parser)
|
||||
|
||||
return query_tree
|
||||
|
||||
|
||||
|
||||
/proc/SDQL_testout(list/query_tree, indent = 0)
|
||||
var/spaces = ""
|
||||
for(var/s = 0, s < indent, s++)
|
||||
spaces += " "
|
||||
|
||||
for(var/item in query_tree)
|
||||
if(istype(item, /list))
|
||||
world << "[spaces]("
|
||||
SDQL_testout(item, indent + 1)
|
||||
world << "[spaces])"
|
||||
|
||||
else
|
||||
world << "[spaces][item]"
|
||||
|
||||
if(!isnum(item) && query_tree[item])
|
||||
|
||||
if(istype(query_tree[item], /list))
|
||||
world << "[spaces] ("
|
||||
SDQL_testout(query_tree[item], indent + 2)
|
||||
world << "[spaces] )"
|
||||
|
||||
else
|
||||
world << "[spaces] [query_tree[item]]"
|
||||
|
||||
|
||||
|
||||
/proc/SDQL_from_objs(list/tree)
|
||||
if("world" in tree)
|
||||
return list(world)
|
||||
|
||||
var/list/out = list()
|
||||
|
||||
for(var/type in tree)
|
||||
var/char = copytext(type, 1, 2)
|
||||
|
||||
if(char == "/")
|
||||
out += SDQL_get_all(type, world)
|
||||
|
||||
else if(char == "'" || char == "\"")
|
||||
out += locate(copytext(type, 2, length(type)))
|
||||
|
||||
return out
|
||||
|
||||
|
||||
/proc/SDQL_get_all(type, location)
|
||||
var/list/out = list()
|
||||
|
||||
if(type == "*")
|
||||
for(var/datum/d in location)
|
||||
out += d
|
||||
|
||||
return out
|
||||
|
||||
type = text2path(type)
|
||||
|
||||
if(ispath(type, /mob))
|
||||
for(var/mob/d in location)
|
||||
if(istype(d, type))
|
||||
out += d
|
||||
|
||||
else if(ispath(type, /turf))
|
||||
for(var/turf/d in location)
|
||||
if(istype(d, type))
|
||||
out += d
|
||||
|
||||
else if(ispath(type, /obj))
|
||||
for(var/obj/d in location)
|
||||
if(istype(d, type))
|
||||
out += d
|
||||
|
||||
else if(ispath(type, /area))
|
||||
for(var/area/d in location)
|
||||
if(istype(d, type))
|
||||
out += d
|
||||
|
||||
else if(ispath(type, /atom))
|
||||
for(var/atom/d in location)
|
||||
if(istype(d, type))
|
||||
out += d
|
||||
|
||||
else
|
||||
for(var/datum/d in location)
|
||||
if(istype(d, type))
|
||||
out += d
|
||||
|
||||
return out
|
||||
|
||||
|
||||
/proc/SDQL_expression(datum/object, list/expression, start = 1)
|
||||
var/result = 0
|
||||
var/val
|
||||
|
||||
for(var/i = start, i <= expression.len, i++)
|
||||
var/op = ""
|
||||
|
||||
if(i > start)
|
||||
op = expression[i]
|
||||
i++
|
||||
|
||||
var/list/ret = SDQL_value(object, expression, i)
|
||||
val = ret["val"]
|
||||
i = ret["i"]
|
||||
|
||||
if(op != "")
|
||||
switch(op)
|
||||
if("+")
|
||||
result += val
|
||||
if("-")
|
||||
result -= val
|
||||
if("*")
|
||||
result *= val
|
||||
if("/")
|
||||
result /= val
|
||||
if("&")
|
||||
result &= val
|
||||
if("|")
|
||||
result |= val
|
||||
if("^")
|
||||
result ^= val
|
||||
if("=", "==")
|
||||
result = (result == val)
|
||||
if("!=", "<>")
|
||||
result = (result != val)
|
||||
if("<")
|
||||
result = (result < val)
|
||||
if("<=")
|
||||
result = (result <= val)
|
||||
if(">")
|
||||
result = (result > val)
|
||||
if(">=")
|
||||
result = (result >= val)
|
||||
if("and", "&&")
|
||||
result = (result && val)
|
||||
if("or", "||")
|
||||
result = (result || val)
|
||||
else
|
||||
usr << "<font color='red'>SDQL2: Unknown op [op]</font>"
|
||||
result = null
|
||||
else
|
||||
result = val
|
||||
|
||||
return result
|
||||
|
||||
/proc/SDQL_value(datum/object, list/expression, start = 1)
|
||||
var/i = start
|
||||
var/val = null
|
||||
|
||||
if(i > expression.len)
|
||||
return list("val" = null, "i" = i)
|
||||
|
||||
if(istype(expression[i], /list))
|
||||
val = SDQL_expression(object, expression[i])
|
||||
|
||||
else if(expression[i] == "!")
|
||||
var/list/ret = SDQL_value(object, expression, i + 1)
|
||||
val = !ret["val"]
|
||||
i = ret["i"]
|
||||
|
||||
else if(expression[i] == "~")
|
||||
var/list/ret = SDQL_value(object, expression, i + 1)
|
||||
val = ~ret["val"]
|
||||
i = ret["i"]
|
||||
|
||||
else if(expression[i] == "-")
|
||||
var/list/ret = SDQL_value(object, expression, i + 1)
|
||||
val = -ret["val"]
|
||||
i = ret["i"]
|
||||
|
||||
else if(expression[i] == "null")
|
||||
val = null
|
||||
|
||||
else if(isnum(expression[i]))
|
||||
val = expression[i]
|
||||
|
||||
else if(copytext(expression[i], 1, 2) in list("'", "\""))
|
||||
val = copytext(expression[i], 2, length(expression[i]))
|
||||
|
||||
else
|
||||
val = SDQL_var(object, expression, i)
|
||||
i = expression.len
|
||||
|
||||
return list("val" = val, "i" = i)
|
||||
|
||||
/proc/SDQL_var(datum/object, list/expression, start = 1)
|
||||
|
||||
if(expression[start] in object.vars)
|
||||
|
||||
if(start < expression.len && expression[start + 1] == ".")
|
||||
return SDQL_var(object.vars[expression[start]], expression[start + 2])
|
||||
|
||||
else
|
||||
return object.vars[expression[start]]
|
||||
|
||||
else
|
||||
return null
|
||||
|
||||
/proc/SDQL2_tokenize(query_text)
|
||||
|
||||
var/list/whitespace = list(" ", "\n", "\t")
|
||||
var/list/single = list("(", ")", ",", "+", "-", ".")
|
||||
var/list/multi = list(
|
||||
"=" = list("", "="),
|
||||
"<" = list("", "=", ">"),
|
||||
">" = list("", "="),
|
||||
"!" = list("", "="))
|
||||
|
||||
var/word = ""
|
||||
var/list/query_list = list()
|
||||
var/len = length(query_text)
|
||||
|
||||
for(var/i = 1, i <= len, i++)
|
||||
var/char = copytext(query_text, i, i + 1)
|
||||
|
||||
if(char in whitespace)
|
||||
if(word != "")
|
||||
query_list += word
|
||||
word = ""
|
||||
|
||||
else if(char in single)
|
||||
if(word != "")
|
||||
query_list += word
|
||||
word = ""
|
||||
|
||||
query_list += char
|
||||
|
||||
else if(char in multi)
|
||||
if(word != "")
|
||||
query_list += word
|
||||
word = ""
|
||||
|
||||
var/char2 = copytext(query_text, i + 1, i + 2)
|
||||
|
||||
if(char2 in multi[char])
|
||||
query_list += "[char][char2]"
|
||||
i++
|
||||
|
||||
else
|
||||
query_list += char
|
||||
|
||||
else if(char == "'")
|
||||
if(word != "")
|
||||
usr << "<font color='red'>SDQL2: You have an error in your SDQL syntax, unexpected ' in query: \"<font color=gray>[query_text]</font>\" following \"<font color=gray>[word]</font>\". Please check your syntax, and try again.</font>"
|
||||
return null
|
||||
|
||||
word = "'"
|
||||
|
||||
for(i++, i <= len, i++)
|
||||
char = copytext(query_text, i, i + 1)
|
||||
|
||||
if(char == "'")
|
||||
if(copytext(query_text, i + 1, i + 2) == "'")
|
||||
word += "'"
|
||||
i++
|
||||
|
||||
else
|
||||
break
|
||||
|
||||
else
|
||||
word += char
|
||||
|
||||
if(i > len)
|
||||
usr << "<font color='red'>SDQL2: You have an error in your SDQL syntax, unmatched ' in query: \"<font color=gray>[query_text]</font>\". Please check your syntax, and try again.</font>"
|
||||
return null
|
||||
|
||||
query_list += "[word]'"
|
||||
word = ""
|
||||
|
||||
else if(char == "\"")
|
||||
if(word != "")
|
||||
usr << "<font color='red'>SDQL2: You have an error in your SDQL syntax, unexpected \" in query: \"<font color=gray>[query_text]</font>\" following \"<font color=gray>[word]</font>\". Please check your syntax, and try again.</font>"
|
||||
return null
|
||||
|
||||
word = "\""
|
||||
|
||||
for(i++, i <= len, i++)
|
||||
char = copytext(query_text, i, i + 1)
|
||||
|
||||
if(char == "\"")
|
||||
if(copytext(query_text, i + 1, i + 2) == "'")
|
||||
word += "\""
|
||||
i++
|
||||
|
||||
else
|
||||
break
|
||||
|
||||
else
|
||||
word += char
|
||||
|
||||
if(i > len)
|
||||
usr << "<font color='red'>SDQL2: You have an error in your SDQL syntax, unmatched \" in query: \"<font color=gray>[query_text]</font>\". Please check your syntax, and try again.</font>"
|
||||
return null
|
||||
|
||||
query_list += "[word]\""
|
||||
word = ""
|
||||
|
||||
else
|
||||
word += char
|
||||
|
||||
if(word != "")
|
||||
query_list += word
|
||||
|
||||
return query_list
|
||||
@@ -1,531 +0,0 @@
|
||||
//I'm pretty sure that this is a recursive [s]descent[/s] ascent parser.
|
||||
|
||||
|
||||
|
||||
//Spec
|
||||
|
||||
//////////
|
||||
//
|
||||
// query : select_query | delete_query | update_query | call_query | explain
|
||||
// explain : 'EXPLAIN' query
|
||||
//
|
||||
// select_query : 'SELECT' select_list [('FROM' | 'IN') from_list] ['WHERE' bool_expression]
|
||||
// delete_query : 'DELETE' select_list [('FROM' | 'IN') from_list] ['WHERE' bool_expression]
|
||||
// update_query : 'UPDATE' select_list [('FROM' | 'IN') from_list] 'SET' assignments ['WHERE' bool_expression]
|
||||
// call_query : 'CALL' call_function ['ON' select_list [('FROM' | 'IN') from_list] ['WHERE' bool_expression]]
|
||||
//
|
||||
// select_list : select_item [',' select_list]
|
||||
// select_item : '*' | select_function | object_type
|
||||
// select_function : count_function
|
||||
// count_function : 'COUNT' '(' '*' ')' | 'COUNT' '(' object_types ')'
|
||||
//
|
||||
// from_list : from_item [',' from_list]
|
||||
// from_item : 'world' | object_type
|
||||
//
|
||||
// call_function : <function name> ['(' [arguments] ')']
|
||||
// arguments : expression [',' arguments]
|
||||
//
|
||||
// object_type : <type path> | string
|
||||
//
|
||||
// assignments : assignment, [',' assignments]
|
||||
// assignment : <variable name> '=' expression
|
||||
// variable : <variable name> | <variable name> '.' variable
|
||||
//
|
||||
// bool_expression : expression comparitor expression [bool_operator bool_expression]
|
||||
// expression : ( unary_expression | '(' expression ')' | value ) [binary_operator expression]
|
||||
// unary_expression : unary_operator ( unary_expression | value | '(' expression ')' )
|
||||
// comparitor : '=' | '==' | '!=' | '<>' | '<' | '<=' | '>' | '>='
|
||||
// value : variable | string | number | 'null'
|
||||
// unary_operator : '!' | '-' | '~'
|
||||
// binary_operator : comparitor | '+' | '-' | '/' | '*' | '&' | '|' | '^'
|
||||
// bool_operator : 'AND' | '&&' | 'OR' | '||'
|
||||
//
|
||||
// string : ''' <some text> ''' | '"' <some text > '"'
|
||||
// number : <some digits>
|
||||
//
|
||||
//////////
|
||||
|
||||
/datum/SDQL_parser
|
||||
var/query_type
|
||||
var/error = 0
|
||||
|
||||
var/list/query
|
||||
var/list/tree
|
||||
|
||||
var/list/select_functions = list("count")
|
||||
var/list/boolean_operators = list("and", "or", "&&", "||")
|
||||
var/list/unary_operators = list("!", "-", "~")
|
||||
var/list/binary_operators = list("+", "-", "/", "*", "&", "|", "^")
|
||||
var/list/comparitors = list("=", "==", "!=", "<>", "<", "<=", ">", ">=")
|
||||
|
||||
|
||||
|
||||
/datum/SDQL_parser/New(query_list)
|
||||
query = query_list
|
||||
|
||||
|
||||
|
||||
/datum/SDQL_parser/proc/parse_error(error_message)
|
||||
error = 1
|
||||
usr << "<font color='red'>SQDL2 Parsing Error: [error_message]</font>"
|
||||
return query.len + 1
|
||||
|
||||
/datum/SDQL_parser/proc/parse()
|
||||
tree = list()
|
||||
query(1, tree)
|
||||
|
||||
if(error)
|
||||
return list()
|
||||
else
|
||||
return tree
|
||||
|
||||
/datum/SDQL_parser/proc/token(i)
|
||||
if(i <= query.len)
|
||||
return query[i]
|
||||
|
||||
else
|
||||
return null
|
||||
|
||||
/datum/SDQL_parser/proc/tokens(i, num)
|
||||
if(i + num <= query.len)
|
||||
return query.Copy(i, i + num)
|
||||
|
||||
else
|
||||
return null
|
||||
|
||||
/datum/SDQL_parser/proc/tokenl(i)
|
||||
return lowertext(token(i))
|
||||
|
||||
|
||||
|
||||
/datum/SDQL_parser/proc
|
||||
|
||||
//query: select_query | delete_query | update_query
|
||||
query(i, list/node)
|
||||
query_type = tokenl(i)
|
||||
|
||||
switch(query_type)
|
||||
if("select")
|
||||
select_query(i, node)
|
||||
|
||||
if("delete")
|
||||
delete_query(i, node)
|
||||
|
||||
if("update")
|
||||
update_query(i, node)
|
||||
|
||||
if("call")
|
||||
call_query(i, node)
|
||||
|
||||
if("explain")
|
||||
node += "explain"
|
||||
node["explain"] = list()
|
||||
query(i + 1, node["explain"])
|
||||
|
||||
|
||||
// select_query: 'SELECT' select_list [('FROM' | 'IN') from_list] ['WHERE' bool_expression]
|
||||
select_query(i, list/node)
|
||||
var/list/select = list()
|
||||
i = select_list(i + 1, select)
|
||||
|
||||
node += "select"
|
||||
node["select"] = select
|
||||
|
||||
var/list/from = list()
|
||||
if(tokenl(i) in list("from", "in"))
|
||||
i = from_list(i + 1, from)
|
||||
else
|
||||
from += "world"
|
||||
|
||||
node += "from"
|
||||
node["from"] = from
|
||||
|
||||
if(tokenl(i) == "where")
|
||||
var/list/where = list()
|
||||
i = bool_expression(i + 1, where)
|
||||
|
||||
node += "where"
|
||||
node["where"] = where
|
||||
|
||||
return i
|
||||
|
||||
|
||||
//delete_query: 'DELETE' select_list [('FROM' | 'IN') from_list] ['WHERE' bool_expression]
|
||||
delete_query(i, list/node)
|
||||
var/list/select = list()
|
||||
i = select_list(i + 1, select)
|
||||
|
||||
node += "delete"
|
||||
node["delete"] = select
|
||||
|
||||
var/list/from = list()
|
||||
if(tokenl(i) in list("from", "in"))
|
||||
i = from_list(i + 1, from)
|
||||
else
|
||||
from += "world"
|
||||
|
||||
node += "from"
|
||||
node["from"] = from
|
||||
|
||||
if(tokenl(i) == "where")
|
||||
var/list/where = list()
|
||||
i = bool_expression(i + 1, where)
|
||||
|
||||
node += "where"
|
||||
node["where"] = where
|
||||
|
||||
return i
|
||||
|
||||
|
||||
//update_query: 'UPDATE' select_list [('FROM' | 'IN') from_list] 'SET' assignments ['WHERE' bool_expression]
|
||||
update_query(i, list/node)
|
||||
var/list/select = list()
|
||||
i = select_list(i + 1, select)
|
||||
|
||||
node += "update"
|
||||
node["update"] = select
|
||||
|
||||
var/list/from = list()
|
||||
if(tokenl(i) in list("from", "in"))
|
||||
i = from_list(i + 1, from)
|
||||
else
|
||||
from += "world"
|
||||
|
||||
node += "from"
|
||||
node["from"] = from
|
||||
|
||||
if(tokenl(i) != "set")
|
||||
i = parse_error("UPDATE has misplaced SET")
|
||||
|
||||
var/list/set_assignments = list()
|
||||
i = assignments(i + 1, set_assignments)
|
||||
|
||||
node += "set"
|
||||
node["set"] = set_assignments
|
||||
|
||||
if(tokenl(i) == "where")
|
||||
var/list/where = list()
|
||||
i = bool_expression(i + 1, where)
|
||||
|
||||
node += "where"
|
||||
node["where"] = where
|
||||
|
||||
return i
|
||||
|
||||
|
||||
//call_query: 'CALL' call_function ['ON' select_list [('FROM' | 'IN') from_list] ['WHERE' bool_expression]]
|
||||
call_query(i, list/node)
|
||||
var/list/func = list()
|
||||
i = call_function(i + 1, func)
|
||||
|
||||
node += "call"
|
||||
node["call"] = func
|
||||
|
||||
if(tokenl(i) != "on")
|
||||
return i
|
||||
|
||||
var/list/select = list()
|
||||
i = select_list(i + 1, select)
|
||||
|
||||
node += "on"
|
||||
node["on"] = select
|
||||
|
||||
var/list/from = list()
|
||||
if(tokenl(i) in list("from", "in"))
|
||||
i = from_list(i + 1, from)
|
||||
else
|
||||
from += "world"
|
||||
|
||||
node += "from"
|
||||
node["from"] = from
|
||||
|
||||
if(tokenl(i) == "where")
|
||||
var/list/where = list()
|
||||
i = bool_expression(i + 1, where)
|
||||
|
||||
node += "where"
|
||||
node["where"] = where
|
||||
|
||||
return i
|
||||
|
||||
|
||||
//select_list: select_item [',' select_list]
|
||||
select_list(i, list/node)
|
||||
i = select_item(i, node)
|
||||
|
||||
if(token(i) == ",")
|
||||
i = select_list(i + 1, node)
|
||||
|
||||
return i
|
||||
|
||||
|
||||
//from_list: from_item [',' from_list]
|
||||
from_list(i, list/node)
|
||||
i = from_item(i, node)
|
||||
|
||||
if(token(i) == ",")
|
||||
i = from_list(i + 1, node)
|
||||
|
||||
return i
|
||||
|
||||
|
||||
//assignments: assignment, [',' assignments]
|
||||
assignments(i, list/node)
|
||||
i = assignment(i, node)
|
||||
|
||||
if(token(i) == ",")
|
||||
i = assignments(i + 1, node)
|
||||
|
||||
return i
|
||||
|
||||
|
||||
//select_item: '*' | select_function | object_type
|
||||
select_item(i, list/node)
|
||||
|
||||
if(token(i) == "*")
|
||||
node += "*"
|
||||
i++
|
||||
|
||||
else if(tokenl(i) in select_functions)
|
||||
i = select_function(i, node)
|
||||
|
||||
else
|
||||
i = object_type(i, node)
|
||||
|
||||
return i
|
||||
|
||||
|
||||
//from_item: 'world' | object_type
|
||||
from_item(i, list/node)
|
||||
|
||||
if(token(i) == "world")
|
||||
node += "world"
|
||||
i++
|
||||
|
||||
else
|
||||
i = object_type(i, node)
|
||||
|
||||
return i
|
||||
|
||||
|
||||
//bool_expression: expression [bool_operator bool_expression]
|
||||
bool_expression(i, list/node)
|
||||
|
||||
var/list/bool = list()
|
||||
i = expression(i, bool)
|
||||
|
||||
node[++node.len] = bool
|
||||
|
||||
if(tokenl(i) in boolean_operators)
|
||||
i = bool_operator(i, node)
|
||||
i = bool_expression(i, node)
|
||||
|
||||
return i
|
||||
|
||||
|
||||
//assignment: <variable name> '=' expression
|
||||
assignment(i, list/node)
|
||||
|
||||
node += token(i)
|
||||
|
||||
if(token(i + 1) == "=")
|
||||
var/varname = token(i)
|
||||
node[varname] = list()
|
||||
|
||||
i = expression(i + 2, node[varname])
|
||||
|
||||
else
|
||||
parse_error("Assignment expected, but no = found")
|
||||
|
||||
return i
|
||||
|
||||
|
||||
//variable: <variable name> | <variable name> '.' variable
|
||||
variable(i, list/node)
|
||||
var/list/L = list(token(i))
|
||||
node[++node.len] = L
|
||||
|
||||
if(token(i + 1) == ".")
|
||||
L += "."
|
||||
i = variable(i + 2, L)
|
||||
|
||||
else
|
||||
i++
|
||||
|
||||
return i
|
||||
|
||||
|
||||
//object_type: <type path> | string
|
||||
object_type(i, list/node)
|
||||
|
||||
if(copytext(token(i), 1, 2) == "/")
|
||||
node += token(i)
|
||||
|
||||
else
|
||||
i = string(i, node)
|
||||
|
||||
return i + 1
|
||||
|
||||
|
||||
//comparitor: '=' | '==' | '!=' | '<>' | '<' | '<=' | '>' | '>='
|
||||
comparitor(i, list/node)
|
||||
|
||||
if(token(i) in list("=", "==", "!=", "<>", "<", "<=", ">", ">="))
|
||||
node += token(i)
|
||||
|
||||
else
|
||||
parse_error("Unknown comparitor [token(i)]")
|
||||
|
||||
return i + 1
|
||||
|
||||
|
||||
//bool_operator: 'AND' | '&&' | 'OR' | '||'
|
||||
bool_operator(i, list/node)
|
||||
|
||||
if(tokenl(i) in list("and", "or", "&&", "||"))
|
||||
node += token(i)
|
||||
|
||||
else
|
||||
parse_error("Unknown comparitor [token(i)]")
|
||||
|
||||
return i + 1
|
||||
|
||||
|
||||
//string: ''' <some text> ''' | '"' <some text > '"'
|
||||
string(i, list/node)
|
||||
|
||||
if(copytext(token(i), 1, 2) in list("'", "\""))
|
||||
node += token(i)
|
||||
|
||||
else
|
||||
parse_error("Expected string but found '[token(i)]'")
|
||||
|
||||
return i + 1
|
||||
|
||||
|
||||
//call_function: <function name> ['(' [arguments] ')']
|
||||
call_function(i, list/node)
|
||||
|
||||
parse_error("Sorry, function calls aren't available yet")
|
||||
|
||||
return i
|
||||
|
||||
|
||||
//select_function: count_function
|
||||
select_function(i, list/node)
|
||||
|
||||
parse_error("Sorry, function calls aren't available yet")
|
||||
|
||||
return i
|
||||
|
||||
|
||||
//expression: ( unary_expression | '(' expression ')' | value ) [binary_operator expression]
|
||||
expression(i, list/node)
|
||||
|
||||
if(token(i) in unary_operators)
|
||||
i = unary_expression(i, node)
|
||||
|
||||
else if(token(i) == "(")
|
||||
var/list/expr = list()
|
||||
|
||||
i = expression(i + 1, expr)
|
||||
|
||||
if(token(i) != ")")
|
||||
parse_error("Missing ) at end of expression.")
|
||||
|
||||
else
|
||||
i++
|
||||
|
||||
node[++node.len] = expr
|
||||
|
||||
else
|
||||
i = value(i, node)
|
||||
|
||||
if(token(i) in binary_operators)
|
||||
i = binary_operator(i, node)
|
||||
i = expression(i, node)
|
||||
|
||||
else if(token(i) in comparitors)
|
||||
i = binary_operator(i, node)
|
||||
|
||||
var/list/rhs = list()
|
||||
i = expression(i, rhs)
|
||||
|
||||
node[++node.len] = rhs
|
||||
|
||||
|
||||
return i
|
||||
|
||||
|
||||
//unary_expression: unary_operator ( unary_expression | value | '(' expression ')' )
|
||||
unary_expression(i, list/node)
|
||||
|
||||
if(token(i) in unary_operators)
|
||||
var/list/unary_exp = list()
|
||||
|
||||
unary_exp += token(i)
|
||||
i++
|
||||
|
||||
if(token(i) in unary_operators)
|
||||
i = unary_expression(i, unary_exp)
|
||||
|
||||
else if(token(i) == "(")
|
||||
var/list/expr = list()
|
||||
|
||||
i = expression(i + 1, expr)
|
||||
|
||||
if(token(i) != ")")
|
||||
parse_error("Missing ) at end of expression.")
|
||||
|
||||
else
|
||||
i++
|
||||
|
||||
unary_exp[++unary_exp.len] = expr
|
||||
|
||||
else
|
||||
i = value(i, unary_exp)
|
||||
|
||||
node[++node.len] = unary_exp
|
||||
|
||||
|
||||
else
|
||||
parse_error("Expected unary operator but found '[token(i)]'")
|
||||
|
||||
return i
|
||||
|
||||
|
||||
//binary_operator: comparitor | '+' | '-' | '/' | '*' | '&' | '|' | '^'
|
||||
binary_operator(i, list/node)
|
||||
|
||||
if(token(i) in (binary_operators + comparitors))
|
||||
node += token(i)
|
||||
|
||||
else
|
||||
parse_error("Unknown binary operator [token(i)]")
|
||||
|
||||
return i + 1
|
||||
|
||||
|
||||
//value: variable | string | number | 'null'
|
||||
value(i, list/node)
|
||||
|
||||
if(token(i) == "null")
|
||||
node += "null"
|
||||
i++
|
||||
|
||||
else if(isnum(text2num(token(i))))
|
||||
node += text2num(token(i))
|
||||
i++
|
||||
|
||||
else if(copytext(token(i), 1, 2) in list("'", "\""))
|
||||
i = string(i, node)
|
||||
|
||||
else
|
||||
i = variable(i, node)
|
||||
|
||||
return i
|
||||
|
||||
|
||||
|
||||
|
||||
/*EXPLAIN SELECT * WHERE 42 = 6 * 9 OR val = - 5 == 7*/
|
||||
@@ -349,8 +349,8 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new)
|
||||
return
|
||||
|
||||
var/msg = "<font color='red' size='4'><b>- AdminHelp marked as IC issue! -</b></font><br>"
|
||||
msg += "<font color='red'><b>This is something that can be solved ICly, and does not currently require admin intervention.</b></font><br>" //VOREStation Edit
|
||||
msg += "<font color='red'>Your AdminHelp may also be unable to be answered due to ongoing events.</font>" //VOREStation Edit
|
||||
msg += "<font color='red'><b>This is something that can be solved ICly, and does not currently require staff intervention.</b></font><br>"
|
||||
msg += "<font color='red'>Your AdminHelp may also be unanswerable due to ongoing events.</font>"
|
||||
|
||||
if(initiator)
|
||||
to_chat(initiator, msg)
|
||||
|
||||
@@ -127,6 +127,18 @@
|
||||
usr << "<span class='notice'>Right Mouse Button on turf/obj/mob = Reset glowing</span>"
|
||||
usr << "<span class='notice'>Right Mouse Button on buildmode button = Change glow properties</span>"
|
||||
usr << "<span class='notice'>***********************************************************</span>"
|
||||
if(9) // Control mobs with ai_holders.
|
||||
usr << "<span class='notice'>***********************************************************</span>"
|
||||
usr << "<span class='notice'>Left Mouse Button on AI mob = Select/Deselect mob</span>"
|
||||
usr << "<span class='notice'>Left Mouse Button + alt on AI mob = Toggle hostility on mob</span>"
|
||||
usr << "<span class='notice'>Left Mouse Button + ctrl on AI mob = Reset target/following/movement</span>"
|
||||
usr << "<span class='notice'>Right Mouse Button on enemy mob = Command selected mobs to attack mob</span>"
|
||||
usr << "<span class='notice'>Right Mouse Button on allied mob = Command selected mobs to follow mob</span>"
|
||||
usr << "<span class='notice'>Right Mouse Button + shift on any mob = Command selected mobs to follow mob regardless of faction</span>"
|
||||
usr << "<span class='notice'>Right Mouse Button on tile = Command selected mobs to move to tile (will cancel if enemies are seen)</span>"
|
||||
usr << "<span class='notice'>Right Mouse Button + shift on tile = Command selected mobs to reposition to tile (will not be inturrupted by enemies)</span>"
|
||||
usr << "<span class='notice'>Right Mouse Button + alt on obj/turfs = Command selected mobs to attack obj/turf</span>"
|
||||
usr << "<span class='notice'>***********************************************************</span>"
|
||||
return 1
|
||||
|
||||
/obj/effect/bmode/buildquit
|
||||
@@ -146,6 +158,7 @@
|
||||
var/obj/effect/bmode/buildmode/buildmode = null
|
||||
var/obj/effect/bmode/buildquit/buildquit = null
|
||||
var/atom/movable/throw_atom = null
|
||||
var/list/selected_mobs = list()
|
||||
|
||||
/obj/effect/bmode/buildholder/Destroy()
|
||||
qdel(builddir)
|
||||
@@ -157,9 +170,21 @@
|
||||
qdel(buildquit)
|
||||
buildquit = null
|
||||
throw_atom = null
|
||||
for(var/mob/living/unit in selected_mobs)
|
||||
deselect_AI_mob(cl, unit)
|
||||
selected_mobs.Cut()
|
||||
cl = null
|
||||
return ..()
|
||||
|
||||
/obj/effect/bmode/buildholder/proc/select_AI_mob(client/C, mob/living/unit)
|
||||
selected_mobs += unit
|
||||
C.images += unit.selected_image
|
||||
|
||||
/obj/effect/bmode/buildholder/proc/deselect_AI_mob(client/C, mob/living/unit)
|
||||
selected_mobs -= unit
|
||||
C.images -= unit.selected_image
|
||||
|
||||
|
||||
/obj/effect/bmode/buildmode
|
||||
icon_state = "buildmode1"
|
||||
screen_loc = "NORTH,WEST+2"
|
||||
@@ -210,6 +235,9 @@
|
||||
master.cl.buildmode = 8
|
||||
src.icon_state = "buildmode8"
|
||||
if(8)
|
||||
master.cl.buildmode = 9
|
||||
src.icon_state = "buildmode9"
|
||||
if(9)
|
||||
master.cl.buildmode = 1
|
||||
src.icon_state = "buildmode1"
|
||||
|
||||
@@ -416,6 +444,86 @@
|
||||
if(pa.Find("right"))
|
||||
if(object)
|
||||
object.set_light(0, 0, "#FFFFFF")
|
||||
if(9) // AI control
|
||||
if(pa.Find("left"))
|
||||
if(isliving(object))
|
||||
var/mob/living/L = object
|
||||
// Reset processes.
|
||||
if(pa.Find("ctrl"))
|
||||
if(!isnull(L.get_AI_stance())) // Null means there's no AI datum or it has one but is player controlled w/o autopilot on.
|
||||
var/datum/ai_holder/AI = L.ai_holder
|
||||
AI.forget_everything()
|
||||
to_chat(user, span("notice", "\The [L]'s AI has forgotten its target/movement destination/leader."))
|
||||
else
|
||||
to_chat(user, span("warning", "\The [L] is not AI controlled."))
|
||||
return
|
||||
|
||||
// Toggle hostility
|
||||
if(pa.Find("alt"))
|
||||
if(!isnull(L.get_AI_stance()))
|
||||
var/datum/ai_holder/AI = L.ai_holder
|
||||
AI.hostile = !AI.hostile
|
||||
to_chat(user, span("notice", "\The [L] is now [AI.hostile ? "hostile" : "passive"]."))
|
||||
else
|
||||
to_chat(user, span("warning", "\The [L] is not AI controlled."))
|
||||
return
|
||||
|
||||
// Select/Deselect
|
||||
if(!isnull(L.get_AI_stance()))
|
||||
if(L in holder.selected_mobs)
|
||||
holder.deselect_AI_mob(user.client, L)
|
||||
to_chat(user, span("notice", "Deselected \the [L]."))
|
||||
else
|
||||
holder.select_AI_mob(user.client, L)
|
||||
to_chat(user, span("notice", "Selected \the [L]."))
|
||||
else
|
||||
to_chat(user, span("warning", "\The [L] is not AI controlled."))
|
||||
|
||||
if(pa.Find("right"))
|
||||
if(istype(object, /atom)) // Force attack.
|
||||
var/atom/A = object
|
||||
|
||||
if(pa.Find("alt"))
|
||||
var/i = 0
|
||||
for(var/mob/living/unit in holder.selected_mobs)
|
||||
var/datum/ai_holder/AI = unit.ai_holder
|
||||
AI.give_target(A)
|
||||
i++
|
||||
to_chat(user, span("notice", "Commanded [i] mob\s to attack \the [A]."))
|
||||
return
|
||||
|
||||
if(isliving(object)) // Follow or attack.
|
||||
var/mob/living/L = object
|
||||
var/i = 0 // Attacking mobs.
|
||||
var/j = 0 // Following mobs.
|
||||
for(var/mob/living/unit in holder.selected_mobs)
|
||||
var/datum/ai_holder/AI = unit.ai_holder
|
||||
if(L.IIsAlly(unit) || !AI.hostile || pa.Find("shift"))
|
||||
AI.set_follow(L)
|
||||
j++
|
||||
else
|
||||
AI.give_target(L)
|
||||
i++
|
||||
var/message = "Commanded "
|
||||
if(i)
|
||||
message += "[i] mob\s to attack \the [L]"
|
||||
if(j)
|
||||
message += ", and "
|
||||
else
|
||||
message += "."
|
||||
if(j)
|
||||
message += "[j] mob\s to follow \the [L]."
|
||||
to_chat(user, span("notice", message))
|
||||
|
||||
if(isturf(object)) // Move or reposition.
|
||||
var/turf/T = object
|
||||
var/i = 0
|
||||
for(var/mob/living/unit in holder.selected_mobs)
|
||||
var/datum/ai_holder/AI = unit.ai_holder
|
||||
AI.give_destination(T, 1, pa.Find("shift")) // If shift is held, the mobs will not stop moving to attack a visible enemy.
|
||||
i++
|
||||
to_chat(user, span("notice", "Commanded [i] mob\s to move to \the [T]."))
|
||||
|
||||
|
||||
/obj/effect/bmode/buildmode/proc/get_path_from_partial_text(default_path)
|
||||
var/desired_path = input("Enter full or partial typepath.","Typepath","[default_path]")
|
||||
|
||||
@@ -592,7 +592,7 @@
|
||||
if("Dead Mobs")
|
||||
usr << jointext(dead_mob_list,",")
|
||||
if("Clients")
|
||||
usr << jointext(clients,",")
|
||||
usr << jointext(GLOB.clients,",")
|
||||
|
||||
/client/proc/cmd_debug_using_map()
|
||||
set category = "Debug"
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
src << "<font color='red'>Only Admins may use this command.</font>"
|
||||
return
|
||||
|
||||
var/client/target = input(src,"Choose somebody to grant access to the server's runtime logs (permissions expire at the end of each round):","Grant Permissions",null) as null|anything in clients
|
||||
var/client/target = input(src,"Choose somebody to grant access to the server's runtime logs (permissions expire at the end of each round):","Grant Permissions",null) as null|anything in GLOB.clients
|
||||
if(!istype(target,/client))
|
||||
src << "<font color='red'>Error: giveruntimelog(): Client not found.</font>"
|
||||
return
|
||||
@@ -99,7 +99,7 @@
|
||||
set category = "Admin"
|
||||
set name = "Show Server Attack Log"
|
||||
set desc = "Shows today's server attack log."
|
||||
|
||||
|
||||
to_chat(usr,"This verb doesn't actually do anything.")
|
||||
|
||||
/*
|
||||
@@ -113,4 +113,3 @@
|
||||
feedback_add_details("admin_verb","SSAL") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
return
|
||||
*/
|
||||
|
||||
@@ -1,115 +1,99 @@
|
||||
/client/proc/admin_lightning_strike()
|
||||
set name = "Lightning Strike"
|
||||
set desc = "Causes lightning to strike on your tile. This will hurt things on or nearby it severely."
|
||||
set category = "Fun"
|
||||
|
||||
if(!check_rights(R_FUN))
|
||||
return
|
||||
|
||||
var/result = alert(src, "Really strike your tile with lightning?", "Confirm Badmin" , "No", "Yes (Cosmetic)", "Yes (Real)")
|
||||
|
||||
if(result == "No")
|
||||
return
|
||||
var/fake_lightning = result == "Yes (Cosmetic)"
|
||||
|
||||
lightning_strike(get_turf(usr), fake_lightning)
|
||||
log_and_message_admins("[key_name(src)] has caused [fake_lightning ? "cosmetic":"harmful"] lightning to strike at their position ([src.mob.x], [src.mob.y], [src.mob.z]). \
|
||||
(<A HREF='?_src_=holder;adminplayerobservecoodjump=1;X=[src.mob.x];Y=[src.mob.y];Z=[src.mob.z]'>JMP</a>)")
|
||||
|
||||
#define LIGHTNING_REDIRECT_RANGE 28 // How far in tiles certain things draw lightning from.
|
||||
#define LIGHTNING_ZAP_RANGE 3 // How far the tesla effect zaps, as well as the bad effects from a direct strike.
|
||||
#define LIGHTNING_POWER 20000 // How much 'zap' is in a strike, used for tesla_zap().
|
||||
|
||||
// The real lightning proc.
|
||||
// This is global until I can figure out a better place for it.
|
||||
// T is the turf that is being struck. If cosmetic is true, the lightning won't actually hurt anything.
|
||||
/proc/lightning_strike(turf/T, cosmetic = FALSE)
|
||||
// First, visuals.
|
||||
|
||||
// Do a lightning flash for the whole planet, if the turf belongs to a planet.
|
||||
var/datum/planet/P = null
|
||||
P = SSplanets.z_to_planet[T.z]
|
||||
if(P)
|
||||
var/datum/weather_holder/holder = P.weather_holder
|
||||
flick("lightning_flash", holder.special_visuals)
|
||||
|
||||
// Before we do the other visuals, we need to see if something is going to hijack our intended target.
|
||||
var/obj/machinery/power/grounding_rod/ground = null // Most of the bad effects of lightning will get negated if a grounding rod is nearby.
|
||||
var/obj/machinery/power/tesla_coil/coil = null // However a tesla coil has higher priority and the strike will bounce.
|
||||
|
||||
for(var/obj/machinery/power/thing in range(LIGHTNING_REDIRECT_RANGE, T))
|
||||
if(istype(thing, /obj/machinery/power/tesla_coil))
|
||||
var/turf/simulated/coil_turf = get_turf(thing)
|
||||
if(istype(coil_turf) && thing.anchored && coil_turf.outdoors)
|
||||
coil = thing
|
||||
break
|
||||
|
||||
if(istype(thing, /obj/machinery/power/grounding_rod))
|
||||
var/turf/simulated/rod_turf = get_turf(thing)
|
||||
if(istype(rod_turf) && thing.anchored && rod_turf.outdoors)
|
||||
ground = thing
|
||||
|
||||
if(coil) // Coil gets highest priority.
|
||||
T = coil.loc
|
||||
else if(ground)
|
||||
T = ground.loc
|
||||
|
||||
// Now make the lightning strike sprite. It will fade and delete itself in a second.
|
||||
new /obj/effect/temporary_effect/lightning_strike(T)
|
||||
|
||||
// For those close up.
|
||||
playsound(T, 'sound/effects/lightningbolt.ogg', 100, 1)
|
||||
|
||||
// And for those far away. If the strike happens on a planet, everyone on the planet will hear it.
|
||||
// Otherwise only those on the current z-level will hear it.
|
||||
var/sound = get_sfx("thunder")
|
||||
for(var/mob/M in player_list)
|
||||
if((P && M.z in P.expected_z_levels) || M.z == T.z)
|
||||
M.playsound_local(get_turf(M), soundin = sound, vol = 70, vary = FALSE, is_global = TRUE)
|
||||
|
||||
if(cosmetic) // Everything beyond here involves potentially damaging things. If we don't want to do that, stop now.
|
||||
return
|
||||
|
||||
if(ground) // All is well.
|
||||
ground.tesla_act(LIGHTNING_POWER, FALSE)
|
||||
return
|
||||
|
||||
else if(coil) // Otherwise lets bounce off the tesla coil.
|
||||
coil.tesla_act(LIGHTNING_POWER, TRUE)
|
||||
|
||||
else // Striking the turf directly.
|
||||
tesla_zap(T, zap_range = LIGHTNING_ZAP_RANGE, power = LIGHTNING_POWER, explosive = FALSE, stun_mobs = TRUE)
|
||||
|
||||
// Some extra effects.
|
||||
// Some apply to those within zap range, others if they were a bit farther away.
|
||||
for(var/mob/living/L in view(5, T))
|
||||
if(get_dist(L, T) <= LIGHTNING_ZAP_RANGE) // They probably got zapped.
|
||||
// The actual damage/electrocution is handled by tesla_zap().
|
||||
L.Paralyse(5)
|
||||
L.stuttering += 20
|
||||
L.make_jittery(20)
|
||||
L.emp_act(1)
|
||||
to_chat(L, span("critical", "You've been struck by lightning!"))
|
||||
|
||||
// If a non-player simplemob was struck, inflict huge damage.
|
||||
// If the damage is fatal, the SA is turned to ash.
|
||||
if(istype(L, /mob/living/simple_animal) && !L.key)
|
||||
var/mob/living/simple_animal/SA = L
|
||||
SA.adjustFireLoss(200)
|
||||
SA.updatehealth()
|
||||
if(SA.health <= 0) // Might be best to check/give simple_mobs siemens when this gets ported to new mobs.
|
||||
SA.visible_message(span("critical", "\The [SA] disintegrates into ash!"))
|
||||
SA.ash()
|
||||
continue // No point deafening something that wont exist.
|
||||
|
||||
// Deafen them.
|
||||
if(L.get_ear_protection() < 2)
|
||||
L.AdjustSleeping(-100)
|
||||
if(iscarbon(L))
|
||||
var/mob/living/carbon/C = L
|
||||
C.ear_deaf += 10
|
||||
to_chat(L, span("danger", "Lightning struck nearby, and the thunderclap is deafening!"))
|
||||
|
||||
#undef GROUNDING_ROD_RANGE
|
||||
#undef LIGHTNING_ZAP_RANGE
|
||||
#undef LIGHTNING_POWER
|
||||
/client/proc/admin_lightning_strike()
|
||||
set name = "Lightning Strike"
|
||||
set desc = "Causes lightning to strike on your tile. This will hurt things on or nearby it severely."
|
||||
set category = "Fun"
|
||||
|
||||
if(!check_rights(R_FUN))
|
||||
return
|
||||
|
||||
var/result = alert(src, "Really strike your tile with lightning?", "Confirm Badmin" , "No", "Yes (Cosmetic)", "Yes (Real)")
|
||||
|
||||
if(result == "No")
|
||||
return
|
||||
var/fake_lightning = result == "Yes (Cosmetic)"
|
||||
|
||||
lightning_strike(get_turf(usr), fake_lightning)
|
||||
log_and_message_admins("[key_name(src)] has caused [fake_lightning ? "cosmetic":"harmful"] lightning to strike at their position ([src.mob.x], [src.mob.y], [src.mob.z]). \
|
||||
(<A HREF='?_src_=holder;adminplayerobservecoodjump=1;X=[src.mob.x];Y=[src.mob.y];Z=[src.mob.z]'>JMP</a>)")
|
||||
|
||||
#define LIGHTNING_REDIRECT_RANGE 28 // How far in tiles certain things draw lightning from.
|
||||
#define LIGHTNING_ZAP_RANGE 3 // How far the tesla effect zaps, as well as the bad effects from a direct strike.
|
||||
#define LIGHTNING_POWER 20000 // How much 'zap' is in a strike, used for tesla_zap().
|
||||
|
||||
// The real lightning proc.
|
||||
// This is global until I can figure out a better place for it.
|
||||
// T is the turf that is being struck. If cosmetic is true, the lightning won't actually hurt anything.
|
||||
/proc/lightning_strike(turf/T, cosmetic = FALSE)
|
||||
// First, visuals.
|
||||
|
||||
// Do a lightning flash for the whole planet, if the turf belongs to a planet.
|
||||
var/datum/planet/P = null
|
||||
P = SSplanets.z_to_planet[T.z]
|
||||
if(P)
|
||||
var/datum/weather_holder/holder = P.weather_holder
|
||||
flick("lightning_flash", holder.special_visuals)
|
||||
|
||||
// Before we do the other visuals, we need to see if something is going to hijack our intended target.
|
||||
var/obj/machinery/power/grounding_rod/ground = null // Most of the bad effects of lightning will get negated if a grounding rod is nearby.
|
||||
var/obj/machinery/power/tesla_coil/coil = null // However a tesla coil has higher priority and the strike will bounce.
|
||||
|
||||
for(var/obj/machinery/power/thing in range(LIGHTNING_REDIRECT_RANGE, T))
|
||||
if(istype(thing, /obj/machinery/power/tesla_coil))
|
||||
var/turf/simulated/coil_turf = get_turf(thing)
|
||||
if(istype(coil_turf) && thing.anchored && coil_turf.outdoors)
|
||||
coil = thing
|
||||
break
|
||||
|
||||
if(istype(thing, /obj/machinery/power/grounding_rod))
|
||||
var/turf/simulated/rod_turf = get_turf(thing)
|
||||
if(istype(rod_turf) && thing.anchored && rod_turf.outdoors)
|
||||
ground = thing
|
||||
|
||||
if(coil) // Coil gets highest priority.
|
||||
T = coil.loc
|
||||
else if(ground)
|
||||
T = ground.loc
|
||||
|
||||
// Now make the lightning strike sprite. It will fade and delete itself in a second.
|
||||
new /obj/effect/temporary_effect/lightning_strike(T)
|
||||
|
||||
// For those close up.
|
||||
playsound(T, 'sound/effects/lightningbolt.ogg', 100, 1)
|
||||
|
||||
// And for those far away. If the strike happens on a planet, everyone on the planet will hear it.
|
||||
// Otherwise only those on the current z-level will hear it.
|
||||
var/sound = get_sfx("thunder")
|
||||
for(var/mob/M in player_list)
|
||||
if((P && M.z in P.expected_z_levels) || M.z == T.z)
|
||||
M.playsound_local(get_turf(M), soundin = sound, vol = 70, vary = FALSE, is_global = TRUE)
|
||||
|
||||
if(cosmetic) // Everything beyond here involves potentially damaging things. If we don't want to do that, stop now.
|
||||
return
|
||||
|
||||
if(ground) // All is well.
|
||||
ground.tesla_act(LIGHTNING_POWER, FALSE)
|
||||
return
|
||||
|
||||
else if(coil) // Otherwise lets bounce off the tesla coil.
|
||||
coil.tesla_act(LIGHTNING_POWER, TRUE)
|
||||
|
||||
else // Striking the turf directly.
|
||||
tesla_zap(T, zap_range = LIGHTNING_ZAP_RANGE, power = LIGHTNING_POWER, explosive = FALSE, stun_mobs = TRUE)
|
||||
|
||||
// Some extra effects.
|
||||
// Some apply to those within zap range, others if they were a bit farther away.
|
||||
for(var/mob/living/L in view(5, T))
|
||||
if(get_dist(L, T) <= LIGHTNING_ZAP_RANGE) // They probably got zapped.
|
||||
L.lightning_act()
|
||||
|
||||
// Deafen them.
|
||||
if(L.get_ear_protection() < 2)
|
||||
L.AdjustSleeping(-100)
|
||||
if(iscarbon(L))
|
||||
var/mob/living/carbon/C = L
|
||||
C.ear_deaf += 10
|
||||
to_chat(L, span("danger", "Lightning struck nearby, and the thunderclap is deafening!"))
|
||||
|
||||
#undef GROUNDING_ROD_RANGE
|
||||
#undef LIGHTNING_ZAP_RANGE
|
||||
#undef LIGHTNING_POWER
|
||||
|
||||
@@ -5,15 +5,18 @@
|
||||
var/datum/map_template/template
|
||||
|
||||
|
||||
var/map = input(usr, "Choose a Map Template to place at your CURRENT LOCATION","Place Map Template") as null|anything in map_templates
|
||||
var/map = input(usr, "Choose a Map Template to place at your CURRENT LOCATION","Place Map Template") as null|anything in SSmapping.map_templates
|
||||
if(!map)
|
||||
return
|
||||
template = map_templates[map]
|
||||
template = SSmapping.map_templates[map]
|
||||
|
||||
var/orientation = text2dir(input(usr, "Choose an orientation for this Map Template.", "Orientation") as null|anything in list("North", "South", "East", "West"))
|
||||
if(!orientation)
|
||||
return
|
||||
|
||||
// Convert dir to degrees rotation
|
||||
orientation = dir2angle(orientation)
|
||||
|
||||
var/turf/T = get_turf(mob)
|
||||
if(!T)
|
||||
return
|
||||
@@ -41,16 +44,19 @@
|
||||
|
||||
var/datum/map_template/template
|
||||
|
||||
var/map = input(usr, "Choose a Map Template to place on a new Z-level.","Place Map Template") as null|anything in map_templates
|
||||
var/map = input(usr, "Choose a Map Template to place on a new Z-level.","Place Map Template") as null|anything in SSmapping.map_templates
|
||||
if(!map)
|
||||
return
|
||||
template = map_templates[map]
|
||||
template = SSmapping.map_templates[map]
|
||||
|
||||
var/orientation = text2dir(input(usr, "Choose an orientation for this Map Template.", "Orientation") as null|anything in list("North", "South", "East", "West"))
|
||||
if(!orientation)
|
||||
return
|
||||
|
||||
if(((orientation & (NORTH|SOUTH) && template.width > world.maxx || template.height > world.maxy) || ((orientation & (EAST|WEST)) && template.width > world.maxy || template.height > world.maxx)))
|
||||
// Convert dir to degrees rotation
|
||||
orientation = dir2angle(orientation)
|
||||
|
||||
if((!(orientation%180) && template.width > world.maxx || template.height > world.maxy) || (orientation%180 && template.width > world.maxy || template.height > world.maxx))
|
||||
if(alert(usr,"This template is larger than the existing z-levels. It will EXPAND ALL Z-LEVELS to match the size of the template. This may cause chaos. Are you sure you want to do this?","DANGER!!!","Cancel","Yes") == "Cancel")
|
||||
to_chat(usr,"Template placement aborted.")
|
||||
return
|
||||
@@ -76,7 +82,7 @@
|
||||
var/datum/map_template/M = new(map, "[map]")
|
||||
if(M.preload_size(map))
|
||||
to_chat(usr, "Map template '[map]' ready to place ([M.width]x[M.height])")
|
||||
map_templates[M.name] = M
|
||||
SSmapping.map_templates[M.name] = M
|
||||
message_admins("<span class='adminnotice'>[key_name_admin(usr)] has uploaded a map template ([map])</span>")
|
||||
else
|
||||
to_chat(usr, "Map template '[map]' failed to load properly")
|
||||
|
||||
@@ -1,375 +0,0 @@
|
||||
/client/proc/cmd_mass_modify_object_variables(atom/A, var/var_name)
|
||||
set category = "Debug"
|
||||
set name = "Mass Edit Variables"
|
||||
set desc="(target) Edit all instances of a target item's variables"
|
||||
|
||||
var/method = 0 //0 means strict type detection while 1 means this type and all subtypes (IE: /obj/item with this set to 1 will set it to ALL itms)
|
||||
|
||||
if(!check_rights(R_VAREDIT)) return
|
||||
|
||||
if(A && A.type)
|
||||
if(typesof(A.type))
|
||||
switch(input("Strict object type detection?") as null|anything in list("Strictly this type","This type and subtypes", "Cancel"))
|
||||
if("Strictly this type")
|
||||
method = 0
|
||||
if("This type and subtypes")
|
||||
method = 1
|
||||
if("Cancel")
|
||||
return
|
||||
if(null)
|
||||
return
|
||||
|
||||
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) )
|
||||
usr << "<font color='red'>It is forbidden to edit this object's variables.</font>"
|
||||
return
|
||||
|
||||
var/list/names = list()
|
||||
for (var/V in O.vars)
|
||||
names += V
|
||||
|
||||
names = sortList(names)
|
||||
|
||||
var/variable = ""
|
||||
|
||||
if(!var_name)
|
||||
variable = input("Which var?","Var") as null|anything in names
|
||||
else
|
||||
variable = var_name
|
||||
|
||||
if(!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(isnull(var_value))
|
||||
usr << "Unable to determine variable type."
|
||||
|
||||
else if(isnum(var_value))
|
||||
usr << "Variable appears to be <b>NUM</b>."
|
||||
default = "num"
|
||||
dir = 1
|
||||
|
||||
else if(istext(var_value))
|
||||
usr << "Variable appears to be <b>TEXT</b>."
|
||||
default = "text"
|
||||
|
||||
else if(isloc(var_value))
|
||||
usr << "Variable appears to be <b>REFERENCE</b>."
|
||||
default = "reference"
|
||||
|
||||
else if(isicon(var_value))
|
||||
usr << "Variable appears to be <b>ICON</b>."
|
||||
var_value = "\icon[var_value]"
|
||||
default = "icon"
|
||||
|
||||
else if(istype(var_value,/atom) || istype(var_value,/datum))
|
||||
usr << "Variable appears to be <b>TYPE</b>."
|
||||
default = "type"
|
||||
|
||||
else if(istype(var_value,/list))
|
||||
usr << "Variable appears to be <b>LIST</b>."
|
||||
default = "list"
|
||||
|
||||
else if(istype(var_value,/client))
|
||||
usr << "Variable appears to be <b>CLIENT</b>."
|
||||
default = "cancel"
|
||||
|
||||
else
|
||||
usr << "Variable appears to be <b>FILE</b>."
|
||||
default = "file"
|
||||
|
||||
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)
|
||||
usr << "If a direction, direction is: [dir]"
|
||||
|
||||
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(!class)
|
||||
return
|
||||
|
||||
var/original_name
|
||||
|
||||
if (!istype(O, /atom))
|
||||
original_name = "\ref[O] ([O])"
|
||||
else
|
||||
original_name = O:name
|
||||
|
||||
switch(class)
|
||||
|
||||
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]
|
||||
|
||||
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 turfs)
|
||||
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 turfs)
|
||||
if (A.type == O.type)
|
||||
A.vars[variable] = O.vars[variable]
|
||||
|
||||
if("edit referenced object")
|
||||
return .(O.vars[variable])
|
||||
|
||||
if("text")
|
||||
var/new_value = input("Enter new text:","Text",O.vars[variable]) as text|null//todo: sanitize ???
|
||||
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 turfs)
|
||||
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 turfs)
|
||||
if (A.type == O.type)
|
||||
A.vars[variable] = O.vars[variable]
|
||||
|
||||
if("num")
|
||||
var/new_value = input("Enter new number:","Num",\
|
||||
O.vars[variable]) as num|null
|
||||
if(new_value == null) return
|
||||
|
||||
if(variable=="light_range")
|
||||
O.set_light(new_value)
|
||||
else
|
||||
O.vars[variable] = new_value
|
||||
|
||||
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(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(istype(O, /turf))
|
||||
for(var/turf/A in turfs)
|
||||
if ( istype(A , O.type) )
|
||||
if(variable=="light_range")
|
||||
A.set_light(new_value)
|
||||
else
|
||||
A.vars[variable] = O.vars[variable]
|
||||
|
||||
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(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 turfs)
|
||||
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 turfs)
|
||||
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 turfs)
|
||||
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 turfs)
|
||||
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 turfs)
|
||||
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 turfs)
|
||||
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 turfs)
|
||||
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)
|
||||
@@ -1,591 +0,0 @@
|
||||
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", "client", "virus", "viruses", "cuffed", "last_eaten", "unlock_content", "bound_x", "bound_y", "step_x", "step_y", "force_ending", "queued_priority")
|
||||
var/list/VVicon_edit_lock = list("icon", "icon_state", "overlays", "underlays")
|
||||
var/list/VVckey_edit = list("key", "ckey")
|
||||
|
||||
/*
|
||||
/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!
|
||||
*/
|
||||
|
||||
/client/proc/cmd_modify_ticker_variables()
|
||||
set category = "Debug"
|
||||
set name = "Edit Ticker Variables"
|
||||
|
||||
if (ticker == null)
|
||||
src << "Game hasn't started yet."
|
||||
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!
|
||||
|
||||
/client/proc/mod_list_add_ass() //haha
|
||||
|
||||
var/class = "text"
|
||||
if(src.holder && src.holder.marked_datum)
|
||||
class = input("What kind of variable?","Variable Type") as null|anything in list("text",
|
||||
"num","type","reference","mob reference", "icon","file","list","edit referenced object","restore to default","marked datum ([holder.marked_datum.type])")
|
||||
else
|
||||
class = input("What kind of variable?","Variable Type") as null|anything in list("text",
|
||||
"num","type","reference","mob reference", "icon","file","list","edit referenced object","restore to default")
|
||||
|
||||
if(!class)
|
||||
return
|
||||
|
||||
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|text
|
||||
|
||||
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("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
|
||||
|
||||
return var_value
|
||||
|
||||
|
||||
/client/proc/mod_list_add(var/list/L, atom/O, original_name, objectvar)
|
||||
|
||||
var/class = "text"
|
||||
if(src.holder && src.holder.marked_datum)
|
||||
class = input("What kind of variable?","Variable Type") as null|anything in list("text",
|
||||
"num","type","reference","mob reference", "icon","file","list","edit referenced object","restore to default","marked datum ([holder.marked_datum.type])")
|
||||
else
|
||||
class = input("What kind of variable?","Variable Type") as null|anything in list("text",
|
||||
"num","type","reference","mob reference", "icon","file","list","edit referenced object","restore to default")
|
||||
|
||||
if(!class)
|
||||
return
|
||||
|
||||
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 text
|
||||
|
||||
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("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"))
|
||||
if("Yes")
|
||||
L += var_value
|
||||
L[var_value] = mod_list_add_ass() //haha
|
||||
if("No")
|
||||
L += var_value
|
||||
world.log << "### ListVarEdit by [src]: [O.type] [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, atom/O, original_name, objectvar)
|
||||
if(!check_rights(R_VAREDIT)) return
|
||||
if(!istype(L,/list)) src << "Not a List."
|
||||
|
||||
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/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
|
||||
usr << "List appears to be associative."
|
||||
|
||||
var/list/names = null
|
||||
if(!assoc)
|
||||
names = sortList(L)
|
||||
|
||||
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, O, original_name, objectvar)
|
||||
return
|
||||
|
||||
if(assoc)
|
||||
assoc_key = variable
|
||||
variable = L[assoc_key]
|
||||
|
||||
if(!assoc && !variable || assoc && !assoc_key)
|
||||
return
|
||||
|
||||
var/default
|
||||
|
||||
var/dir
|
||||
|
||||
if(variable in VVlocked)
|
||||
if(!check_rights(R_DEBUG)) return
|
||||
if(variable in VVckey_edit)
|
||||
if(!check_rights(R_SPAWN|R_DEBUG)) return
|
||||
if(variable in VVicon_edit_lock)
|
||||
if(!check_rights(R_FUN|R_DEBUG)) return
|
||||
|
||||
if(isnull(variable))
|
||||
usr << "Unable to determine variable type."
|
||||
|
||||
else if(isnum(variable))
|
||||
usr << "Variable appears to be <b>NUM</b>."
|
||||
default = "num"
|
||||
dir = 1
|
||||
|
||||
else if(istext(variable))
|
||||
usr << "Variable appears to be <b>TEXT</b>."
|
||||
default = "text"
|
||||
|
||||
else if(isloc(variable))
|
||||
usr << "Variable appears to be <b>REFERENCE</b>."
|
||||
default = "reference"
|
||||
|
||||
else if(isicon(variable))
|
||||
usr << "Variable appears to be <b>ICON</b>."
|
||||
variable = "\icon[variable]"
|
||||
default = "icon"
|
||||
|
||||
else if(istype(variable,/atom) || istype(variable,/datum))
|
||||
usr << "Variable appears to be <b>TYPE</b>."
|
||||
default = "type"
|
||||
|
||||
else if(istype(variable,/list))
|
||||
usr << "Variable appears to be <b>LIST</b>."
|
||||
default = "list"
|
||||
|
||||
else if(istype(variable,/client))
|
||||
usr << "Variable appears to be <b>CLIENT</b>."
|
||||
default = "cancel"
|
||||
|
||||
else
|
||||
usr << "Variable appears to be <b>FILE</b>."
|
||||
default = "file"
|
||||
|
||||
usr << "Variable contains: [variable]"
|
||||
if(dir)
|
||||
switch(variable)
|
||||
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)
|
||||
usr << "If a direction, direction is: [dir]"
|
||||
|
||||
var/class = "text"
|
||||
if(src.holder && src.holder.marked_datum)
|
||||
class = input("What kind of variable?","Variable Type",default) as null|anything in list("text",
|
||||
"num","type","reference","mob reference", "icon","file","list","edit referenced object","restore to default","marked datum ([holder.marked_datum.type])", "DELETE FROM LIST")
|
||||
else
|
||||
class = input("What kind of variable?","Variable Type",default) as null|anything in list("text",
|
||||
"num","type","reference","mob reference", "icon","file","list","edit referenced object","restore to default", "DELETE FROM LIST")
|
||||
|
||||
if(!class)
|
||||
return
|
||||
|
||||
if(holder.marked_datum && class == "marked datum ([holder.marked_datum.type])")
|
||||
class = "marked datum"
|
||||
|
||||
var/original_var
|
||||
if(assoc)
|
||||
original_var = L[assoc_key]
|
||||
else
|
||||
original_var = L[L.Find(variable)]
|
||||
|
||||
var/new_var
|
||||
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, O, original_name, objectvar)
|
||||
|
||||
if("restore to default")
|
||||
new_var = initial(variable)
|
||||
if(assoc)
|
||||
L[assoc_key] = new_var
|
||||
else
|
||||
L[L.Find(variable)] = new_var
|
||||
|
||||
if("edit referenced object")
|
||||
modify_variables(variable)
|
||||
|
||||
if("DELETE FROM LIST")
|
||||
world.log << "### ListVarEdit by [src]: [O.type] [objectvar]: REMOVED=[html_encode("[variable]")]"
|
||||
log_admin("[key_name(src)] modified [original_name]'s [objectvar]: REMOVED=[variable]")
|
||||
message_admins("[key_name_admin(src)] modified [original_name]'s [objectvar]: REMOVED=[variable]")
|
||||
L -= variable
|
||||
return
|
||||
|
||||
if("text")
|
||||
new_var = input("Enter new text:","Text") as text
|
||||
if(assoc)
|
||||
L[assoc_key] = new_var
|
||||
else
|
||||
L[L.Find(variable)] = new_var
|
||||
|
||||
if("num")
|
||||
new_var = input("Enter new number:","Num") as num
|
||||
if(assoc)
|
||||
L[assoc_key] = new_var
|
||||
else
|
||||
L[L.Find(variable)] = new_var
|
||||
|
||||
if("type")
|
||||
new_var = input("Enter type:","Type") in typesof(/obj,/mob,/area,/turf)
|
||||
if(assoc)
|
||||
L[assoc_key] = new_var
|
||||
else
|
||||
L[L.Find(variable)] = new_var
|
||||
|
||||
if("reference")
|
||||
new_var = input("Select reference:","Reference") as mob|obj|turf|area in world
|
||||
if(assoc)
|
||||
L[assoc_key] = new_var
|
||||
else
|
||||
L[L.Find(variable)] = new_var
|
||||
|
||||
if("mob reference")
|
||||
new_var = input("Select reference:","Reference") as mob in world
|
||||
if(assoc)
|
||||
L[assoc_key] = new_var
|
||||
else
|
||||
L[L.Find(variable)] = new_var
|
||||
|
||||
if("file")
|
||||
new_var = input("Pick file:","File") as file
|
||||
if(assoc)
|
||||
L[assoc_key] = new_var
|
||||
else
|
||||
L[L.Find(variable)] = new_var
|
||||
|
||||
if("icon")
|
||||
new_var = input("Pick icon:","Icon") as icon
|
||||
if(assoc)
|
||||
L[assoc_key] = new_var
|
||||
else
|
||||
L[L.Find(variable)] = new_var
|
||||
|
||||
if("marked datum")
|
||||
new_var = holder.marked_datum
|
||||
if(assoc)
|
||||
L[assoc_key] = new_var
|
||||
else
|
||||
L[L.Find(variable)] = new_var
|
||||
|
||||
world.log << "### ListVarEdit by [src]: [O.type] [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]")
|
||||
|
||||
/client/proc/modify_variables(var/atom/O, var/param_var_name = null, var/autodetect_class = 0)
|
||||
if(!check_rights(R_VAREDIT)) return
|
||||
|
||||
for(var/p in forbidden_varedit_object_types)
|
||||
if( istype(O,p) )
|
||||
usr << "<span class='danger'>It is forbidden to edit this object's variables.</span>"
|
||||
return
|
||||
|
||||
if(istype(O, /client) && (param_var_name == "ckey" || param_var_name == "key"))
|
||||
usr << "<span class='danger'>You cannot edit ckeys on client objects.</span>"
|
||||
return
|
||||
|
||||
var/class
|
||||
var/variable
|
||||
var/var_value
|
||||
|
||||
if(param_var_name)
|
||||
if(!param_var_name in O.vars)
|
||||
src << "A variable with this name ([param_var_name]) doesn't exist in this atom ([O])"
|
||||
return
|
||||
|
||||
if(param_var_name in VVlocked)
|
||||
if(!check_rights(R_DEBUG)) return
|
||||
if(param_var_name in VVckey_edit)
|
||||
if(!check_rights(R_SPAWN|R_DEBUG)) return
|
||||
if(param_var_name in VVicon_edit_lock)
|
||||
if(!check_rights(R_FUN|R_DEBUG)) return
|
||||
|
||||
variable = param_var_name
|
||||
|
||||
var_value = O.vars[variable]
|
||||
|
||||
if(autodetect_class)
|
||||
if(isnull(var_value))
|
||||
usr << "Unable to determine variable type."
|
||||
class = null
|
||||
autodetect_class = null
|
||||
else if(isnum(var_value))
|
||||
usr << "Variable appears to be <b>NUM</b>."
|
||||
class = "num"
|
||||
dir = 1
|
||||
|
||||
else if(istext(var_value))
|
||||
usr << "Variable appears to be <b>TEXT</b>."
|
||||
class = "text"
|
||||
|
||||
else if(isloc(var_value))
|
||||
usr << "Variable appears to be <b>REFERENCE</b>."
|
||||
class = "reference"
|
||||
|
||||
else if(isicon(var_value))
|
||||
usr << "Variable appears to be <b>ICON</b>."
|
||||
var_value = "\icon[var_value]"
|
||||
class = "icon"
|
||||
|
||||
else if(istype(var_value,/atom) || istype(var_value,/datum))
|
||||
usr << "Variable appears to be <b>TYPE</b>."
|
||||
class = "type"
|
||||
|
||||
else if(istype(var_value,/list))
|
||||
usr << "Variable appears to be <b>LIST</b>."
|
||||
class = "list"
|
||||
|
||||
else if(istype(var_value,/client))
|
||||
usr << "Variable appears to be <b>CLIENT</b>."
|
||||
class = "cancel"
|
||||
|
||||
else
|
||||
usr << "Variable appears to be <b>FILE</b>."
|
||||
class = "file"
|
||||
|
||||
else
|
||||
|
||||
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
|
||||
if(!variable) return
|
||||
var_value = O.vars[variable]
|
||||
|
||||
if(variable in VVlocked)
|
||||
if(!check_rights(R_DEBUG)) return
|
||||
if(variable in VVckey_edit)
|
||||
if(!check_rights(R_SPAWN|R_DEBUG)) return
|
||||
if(variable in VVicon_edit_lock)
|
||||
if(!check_rights(R_FUN|R_DEBUG)) return
|
||||
|
||||
if(!autodetect_class)
|
||||
|
||||
var/dir
|
||||
var/default
|
||||
if(isnull(var_value))
|
||||
usr << "Unable to determine variable type."
|
||||
|
||||
else if(isnum(var_value))
|
||||
usr << "Variable appears to be <b>NUM</b>."
|
||||
default = "num"
|
||||
dir = 1
|
||||
|
||||
else if(istext(var_value))
|
||||
usr << "Variable appears to be <b>TEXT</b>."
|
||||
default = "text"
|
||||
|
||||
else if(isloc(var_value))
|
||||
usr << "Variable appears to be <b>REFERENCE</b>."
|
||||
default = "reference"
|
||||
|
||||
else if(isicon(var_value))
|
||||
usr << "Variable appears to be <b>ICON</b>."
|
||||
var_value = "\icon[var_value]"
|
||||
default = "icon"
|
||||
|
||||
else if(istype(var_value,/atom) || istype(var_value,/datum))
|
||||
usr << "Variable appears to be <b>TYPE</b>."
|
||||
default = "type"
|
||||
|
||||
else if(istype(var_value,/list))
|
||||
usr << "Variable appears to be <b>LIST</b>."
|
||||
default = "list"
|
||||
|
||||
else if(istype(var_value,/client))
|
||||
usr << "Variable appears to be <b>CLIENT</b>."
|
||||
default = "cancel"
|
||||
|
||||
else
|
||||
usr << "Variable appears to be <b>FILE</b>."
|
||||
default = "file"
|
||||
|
||||
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)
|
||||
usr << "If a direction, direction is: [dir]"
|
||||
|
||||
if(src.holder && src.holder.marked_datum)
|
||||
class = input("What kind of variable?","Variable Type",default) as null|anything in list("text",
|
||||
"num","type","reference","mob reference", "icon","file","list","edit referenced object","restore to default","marked datum ([holder.marked_datum.type])")
|
||||
else
|
||||
class = input("What kind of variable?","Variable Type",default) as null|anything in list("text",
|
||||
"num","type","reference","mob reference", "icon","file","list","edit referenced object","restore to default")
|
||||
|
||||
if(!class)
|
||||
return
|
||||
|
||||
var/original_name
|
||||
|
||||
if (!istype(O, /atom))
|
||||
original_name = "\ref[O] ([O])"
|
||||
else
|
||||
original_name = O:name
|
||||
|
||||
if(holder.marked_datum && class == "marked datum ([holder.marked_datum.type])")
|
||||
class = "marked datum"
|
||||
|
||||
switch(class)
|
||||
|
||||
if("list")
|
||||
mod_list(O.vars[variable], O, original_name, variable)
|
||||
return
|
||||
|
||||
if("restore to default")
|
||||
O.vars[variable] = initial(O.vars[variable])
|
||||
|
||||
if("edit referenced object")
|
||||
return .(O.vars[variable])
|
||||
|
||||
if("text")
|
||||
var/var_new = input("Enter new text:","Text",O.vars[variable]) as null|text
|
||||
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")
|
||||
var/var_new = input("Enter new number:","Num",O.vars[variable]) as null|num
|
||||
if(var_new == null) return
|
||||
if((O.vars[variable] == 2) && (var_new < 2))//Bringing the dead back to life
|
||||
dead_mob_list -= O
|
||||
living_mob_list += O
|
||||
if((O.vars[variable] < 2) && (var_new == 2))//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("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
|
||||
|
||||
world.log << "### VarEdit by [src]: [O.type] [variable]=[html_encode("[O.vars[variable]]")]"
|
||||
log_admin("[key_name(src)] modified [original_name]'s [variable] to [O.vars[variable]]")
|
||||
message_admins("[key_name_admin(src)] modified [original_name]'s [variable] to [O.vars[variable]]")
|
||||
@@ -62,7 +62,7 @@
|
||||
|
||||
var/highlight_special_characters = 1
|
||||
|
||||
for(var/client/C in clients)
|
||||
for(var/client/C in GLOB.clients)
|
||||
if(C.player_age == "Requires database")
|
||||
missing_ages = 1
|
||||
continue
|
||||
@@ -363,7 +363,7 @@ Traitors and the like can also be revived with the previous role mostly intact.
|
||||
return
|
||||
|
||||
//I frontload all the questions so we don't have a half-done process while you're reading.
|
||||
var/client/picked_client = input(src, "Please specify which client's character to spawn.", "Client", "") as null|anything in clients
|
||||
var/client/picked_client = input(src, "Please specify which client's character to spawn.", "Client", "") as null|anything in GLOB.clients
|
||||
if(!picked_client)
|
||||
return
|
||||
|
||||
@@ -603,12 +603,7 @@ Traitors and the like can also be revived with the previous role mostly intact.
|
||||
if (!holder)
|
||||
src << "Only administrators may use this command."
|
||||
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)
|
||||
feedback_add_details("admin_verb","DEL") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
qdel(O)
|
||||
admin_delete(O)
|
||||
|
||||
/client/proc/cmd_admin_list_open_jobs()
|
||||
set category = "Admin"
|
||||
|
||||
@@ -18,14 +18,15 @@
|
||||
feedback_add_details("admin_verb","SMITEV") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
switch(smite_choice)
|
||||
/*
|
||||
if(SMITE_SHADEKIN_ATTACK)
|
||||
var/turf/Tt = get_turf(target) //Turf for target
|
||||
|
||||
|
||||
if(target.loc != Tt)
|
||||
return //Too hard to attack someone in something
|
||||
|
||||
|
||||
var/turf/Ts //Turf for shadekin
|
||||
|
||||
|
||||
//Try to find nondense turf
|
||||
for(var/direction in cardinal)
|
||||
var/turf/T = get_step(target,direction)
|
||||
@@ -34,7 +35,7 @@
|
||||
if(!Ts)
|
||||
return //Didn't find shadekin spawn turf
|
||||
|
||||
var/mob/living/simple_animal/shadekin/red/shadekin = new(Ts)
|
||||
var/mob/living/simple_mob/shadekin/red/shadekin = new(Ts)
|
||||
//Abuse of shadekin
|
||||
shadekin.real_name = shadekin.name
|
||||
shadekin.init_vore()
|
||||
@@ -47,33 +48,34 @@
|
||||
//Remove when done
|
||||
spawn(10 SECONDS)
|
||||
if(shadekin)
|
||||
shadekin.death()
|
||||
shadekin.death()*/ //VORESTATION AI TEMPORARY REMOVAL
|
||||
|
||||
if(SMITE_SHADEKIN_NOMF)
|
||||
/*if(SMITE_SHADEKIN_NOMF)
|
||||
var/list/kin_types = list(
|
||||
"Red Eyes (Dark)" = /mob/living/simple_animal/shadekin/red/dark,
|
||||
"Red Eyes (Light)" = /mob/living/simple_animal/shadekin/red/white,
|
||||
"Red Eyes (Brown)" = /mob/living/simple_animal/shadekin/red/brown,
|
||||
"Blue Eyes (Dark)" = /mob/living/simple_animal/shadekin/blue/dark,
|
||||
"Blue Eyes (Light)" = /mob/living/simple_animal/shadekin/blue/white,
|
||||
"Blue Eyes (Brown)" = /mob/living/simple_animal/shadekin/blue/brown,
|
||||
"Purple Eyes (Dark)" = /mob/living/simple_animal/shadekin/purple/dark,
|
||||
"Purple Eyes (Light)" = /mob/living/simple_animal/shadekin/purple/white,
|
||||
"Purple Eyes (Brown)" = /mob/living/simple_animal/shadekin/purple/brown,
|
||||
"Yellow Eyes (Dark)" = /mob/living/simple_animal/shadekin/yellow/dark,
|
||||
"Yellow Eyes (Light)" = /mob/living/simple_animal/shadekin/yellow/white,
|
||||
"Yellow Eyes (Brown)" = /mob/living/simple_animal/shadekin/yellow/brown,
|
||||
"Green Eyes (Dark)" = /mob/living/simple_animal/shadekin/green/dark,
|
||||
"Green Eyes (Light)" = /mob/living/simple_animal/shadekin/green/white,
|
||||
"Green Eyes (Brown)" = /mob/living/simple_animal/shadekin/green/brown,
|
||||
"Orange Eyes (Dark)" = /mob/living/simple_animal/shadekin/orange/dark,
|
||||
"Orange Eyes (Light)" = /mob/living/simple_animal/shadekin/orange/white,
|
||||
"Orange Eyes (Brown)" = /mob/living/simple_animal/shadekin/orange/brown,
|
||||
"Rivyr (Unique)" = /mob/living/simple_animal/shadekin/blue/rivyr)
|
||||
"Red Eyes (Dark)" = /mob/living/simple_mob/shadekin/red/dark,
|
||||
"Red Eyes (Light)" = /mob/living/simple_mob/shadekin/red/white,
|
||||
"Red Eyes (Brown)" = /mob/living/simple_mob/shadekin/red/brown,
|
||||
"Blue Eyes (Dark)" = /mob/living/simple_mob/shadekin/blue/dark,
|
||||
"Blue Eyes (Light)" = /mob/living/simple_mob/shadekin/blue/white,
|
||||
"Blue Eyes (Brown)" = /mob/living/simple_mob/shadekin/blue/brown,
|
||||
"Purple Eyes (Dark)" = /mob/living/simple_mob/shadekin/purple/dark,
|
||||
"Purple Eyes (Light)" = /mob/living/simple_mob/shadekin/purple/white,
|
||||
"Purple Eyes (Brown)" = /mob/living/simple_mob/shadekin/purple/brown,
|
||||
"Yellow Eyes (Dark)" = /mob/living/simple_mob/shadekin/yellow/dark,
|
||||
"Yellow Eyes (Light)" = /mob/living/simple_mob/shadekin/yellow/white,
|
||||
"Yellow Eyes (Brown)" = /mob/living/simple_mob/shadekin/yellow/brown,
|
||||
"Green Eyes (Dark)" = /mob/living/simple_mob/shadekin/green/dark,
|
||||
"Green Eyes (Light)" = /mob/living/simple_mob/shadekin/green/white,
|
||||
"Green Eyes (Brown)" = /mob/living/simple_mob/shadekin/green/brown,
|
||||
"Orange Eyes (Dark)" = /mob/living/simple_mob/shadekin/orange/dark,
|
||||
"Orange Eyes (Light)" = /mob/living/simple_mob/shadekin/orange/white,
|
||||
"Orange Eyes (Brown)" = /mob/living/simple_mob/shadekin/orange/brown,
|
||||
"Rivyr (Unique)" = /mob/living/simple_mob/shadekin/blue/rivyr)
|
||||
var/kin_type = input("Select the type of shadekin for [target] nomf","Shadekin Type Choice") as null|anything in kin_types
|
||||
if(!kin_type || !target)
|
||||
return
|
||||
|
||||
|
||||
kin_type = kin_types[kin_type]
|
||||
|
||||
var/myself = alert("Control the shadekin yourself or delete pred and prey after?","Control Shadekin?","Control","Cancel","Delete")
|
||||
@@ -81,13 +83,13 @@
|
||||
return
|
||||
|
||||
var/turf/Tt = get_turf(target)
|
||||
|
||||
|
||||
if(target.loc != Tt)
|
||||
return //Can't nom when not exposed
|
||||
|
||||
//Begin abuse
|
||||
target.transforming = TRUE //Cheap hack to stop them from moving
|
||||
var/mob/living/simple_animal/shadekin/shadekin = new kin_type(Tt)
|
||||
var/mob/living/simple_mob/shadekin/shadekin = new kin_type(Tt)
|
||||
shadekin.real_name = shadekin.name
|
||||
shadekin.init_vore()
|
||||
shadekin.can_be_drop_pred = TRUE
|
||||
@@ -117,6 +119,7 @@
|
||||
target.ghostize()
|
||||
qdel(target)
|
||||
qdel(shadekin)
|
||||
*/
|
||||
|
||||
if(SMITE_REDSPACE_ABDUCT)
|
||||
redspace_abduction(target, src)
|
||||
@@ -160,7 +163,7 @@ var/redspace_abduction_z
|
||||
//Lower left corner of a working box
|
||||
var/llc_x = max(0,halfbox-target.x) + min(target.x+halfbox, world.maxx) - size_of_square
|
||||
var/llc_y = max(0,halfbox-target.y) + min(target.y+halfbox, world.maxy) - size_of_square
|
||||
|
||||
|
||||
//Copy them all
|
||||
for(var/x = llc_x to llc_x+size_of_square)
|
||||
for(var/y = llc_y to llc_y+size_of_square)
|
||||
@@ -196,7 +199,7 @@ var/redspace_abduction_z
|
||||
T.density = FALSE
|
||||
T.opacity = FALSE
|
||||
T.vis_contents.Cut()
|
||||
|
||||
|
||||
for(var/x = llc_x to llc_x+size_of_square) //Bottom
|
||||
for(var/y = llc_y to llc_y+1)
|
||||
if(prob(50))
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
/client/proc/admin_delete(datum/D)
|
||||
var/atom/A = D
|
||||
var/coords = ""
|
||||
var/jmp_coords = ""
|
||||
if(istype(A))
|
||||
var/turf/T = get_turf(A)
|
||||
if(T)
|
||||
coords = "at [COORD(T)]"
|
||||
jmp_coords = "at [ADMIN_COORDJMP(T)]"
|
||||
else
|
||||
jmp_coords = coords = "in nullspace"
|
||||
|
||||
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] [jmp_coords]")
|
||||
feedback_add_details("admin_verb","ADEL") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
/*if(isturf(D)) //Polaris doesn't support baseturfs yet.
|
||||
var/turf/T = D
|
||||
T.ScrapeAway()
|
||||
else*/
|
||||
vv_update_display(D, "deleted", VV_MSG_DELETED)
|
||||
qdel(D)
|
||||
if(!QDELETED(D))
|
||||
vv_update_display(D, "deleted", "")
|
||||
@@ -0,0 +1,76 @@
|
||||
#define VV_HTML_ENCODE(thing) ( sanitize ? html_encode(thing) : thing )
|
||||
/proc/debug_variable(name, value, level, datum/DA = null, sanitize = TRUE)
|
||||
var/header
|
||||
if(DA)
|
||||
if (islist(DA))
|
||||
var/index = name
|
||||
if (value)
|
||||
name = DA[name] //name is really the index until this line
|
||||
else
|
||||
value = DA[name]
|
||||
header = "<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=\ref[DA];varnameedit=[name]'>E</a>) (<a href='?_src_=vars;datumchange=\ref[DA];varnamechange=[name]'>C</a>) (<a href='?_src_=vars;datummass=\ref[DA];varnamemass=[name]'>M</a>) "
|
||||
else
|
||||
header = "<li>"
|
||||
|
||||
var/item
|
||||
if (isnull(value))
|
||||
item = "[VV_HTML_ENCODE(name)] = <span class='value'>null</span>"
|
||||
|
||||
else if (istext(value))
|
||||
item = "[VV_HTML_ENCODE(name)] = <span class='value'>\"[VV_HTML_ENCODE(value)]\"</span>"
|
||||
|
||||
else if (isicon(value))
|
||||
#ifdef VARSICON
|
||||
var/icon/I = new/icon(value)
|
||||
var/rnd = rand(1,10000)
|
||||
var/rname = "tmp\ref[I][rnd].png"
|
||||
usr << browse_rsc(I, rname)
|
||||
item = "[VV_HTML_ENCODE(name)] = (<span class='value'>[value]</span>) <img class=icon src=\"[rname]\">"
|
||||
#else
|
||||
item = "[VV_HTML_ENCODE(name)] = /icon (<span class='value'>[value]</span>)"
|
||||
#endif
|
||||
|
||||
else if (isfile(value))
|
||||
item = "[VV_HTML_ENCODE(name)] = <span class='value'>'[value]'</span>"
|
||||
|
||||
else if (istype(value, /datum))
|
||||
var/datum/D = value
|
||||
if ("[D]" != "[D.type]") //if the thing as a name var, lets use it.
|
||||
item = "<a href='?_src_=vars;Vars=\ref[value]'>[VV_HTML_ENCODE(name)] \ref[value]</a> = [D] [D.type]"
|
||||
else
|
||||
item = "<a href='?_src_=vars;Vars=\ref[value]'>[VV_HTML_ENCODE(name)] \ref[value]</a> = [D.type]"
|
||||
|
||||
else if (islist(value))
|
||||
var/list/L = value
|
||||
var/list/items = list()
|
||||
|
||||
if (L.len > 0 && !(name == "underlays" || name == "overlays" || L.len > (IS_NORMAL_LIST(L) ? VV_NORMAL_LIST_NO_EXPAND_THRESHOLD : VV_SPECIAL_LIST_NO_EXPAND_THRESHOLD)))
|
||||
for (var/i in 1 to L.len)
|
||||
var/key = L[i]
|
||||
var/val
|
||||
if (IS_NORMAL_LIST(L) && !isnum(key))
|
||||
val = L[key]
|
||||
if (isnull(val)) // we still want to display non-null false values, such as 0 or ""
|
||||
val = key
|
||||
key = i
|
||||
|
||||
items += debug_variable(key, val, level + 1, sanitize = sanitize)
|
||||
|
||||
item = "<a href='?_src_=vars;Vars=\ref[value]'>[VV_HTML_ENCODE(name)] = /list ([L.len])</a><ul>[items.Join()]</ul>"
|
||||
else
|
||||
item = "<a href='?_src_=vars;Vars=\ref[value]'>[VV_HTML_ENCODE(name)] = /list ([L.len])</a>"
|
||||
|
||||
else if (name in GLOB.bitfields)
|
||||
var/list/flags = list()
|
||||
for (var/i in GLOB.bitfields[name])
|
||||
if (value & GLOB.bitfields[name][i])
|
||||
flags += i
|
||||
item = "[VV_HTML_ENCODE(name)] = [VV_HTML_ENCODE(jointext(flags, ", "))]"
|
||||
else
|
||||
item = "[VV_HTML_ENCODE(name)] = <span class='value'>[VV_HTML_ENCODE(value)]</span>"
|
||||
|
||||
return "[header][item]</li>"
|
||||
|
||||
#undef VV_HTML_ENCODE
|
||||
@@ -0,0 +1,250 @@
|
||||
/client/proc/vv_get_class(var/var_name, var/var_value)
|
||||
if(isnull(var_value))
|
||||
. = VV_NULL
|
||||
|
||||
else if (isnum(var_value))
|
||||
if (var_name in GLOB.bitfields)
|
||||
. = VV_BITFIELD
|
||||
else
|
||||
. = VV_NUM
|
||||
|
||||
else if (istext(var_value))
|
||||
if (findtext(var_value, "\n"))
|
||||
. = VV_MESSAGE
|
||||
else
|
||||
. = VV_TEXT
|
||||
|
||||
else if (isicon(var_value))
|
||||
. = VV_ICON
|
||||
|
||||
else if (ismob(var_value))
|
||||
. = VV_MOB_REFERENCE
|
||||
|
||||
else if (isloc(var_value))
|
||||
. = VV_ATOM_REFERENCE
|
||||
|
||||
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
|
||||
. = VV_NULL
|
||||
|
||||
/client/proc/vv_get_value(class, default_class, current_value, list/restricted_classes, list/extra_classes, list/classes, var_name)
|
||||
. = 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_FILE,
|
||||
VV_NEW_ATOM,
|
||||
VV_NEW_DATUM,
|
||||
VV_NEW_TYPE,
|
||||
VV_NEW_LIST,
|
||||
VV_NULL,
|
||||
VV_RESTORE_DEFAULT
|
||||
)
|
||||
|
||||
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_BITFIELD)
|
||||
.["value"] = input_bitfield(usr, "Editing bitfield: [var_name]", var_name, current_value)
|
||||
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_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 GLOB.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
|
||||
var/atom/newguy = new type()
|
||||
newguy.datum_flags |= DF_VAR_EDITED
|
||||
.["value"] = newguy
|
||||
|
||||
if (VV_NEW_DATUM)
|
||||
var/type = pick_closest_path(FALSE, get_fancy_list_of_datum_types())
|
||||
if (!type)
|
||||
.["class"] = null
|
||||
return
|
||||
.["type"] = type
|
||||
var/datum/newguy = new type()
|
||||
newguy.datum_flags |= DF_VAR_EDITED
|
||||
.["value"] = newguy
|
||||
|
||||
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
|
||||
var/datum/newguy = new type()
|
||||
if(istype(newguy))
|
||||
newguy.datum_flags |= DF_VAR_EDITED
|
||||
.["value"] = newguy
|
||||
|
||||
|
||||
if (VV_NEW_LIST)
|
||||
.["value"] = list()
|
||||
.["type"] = /list
|
||||
@@ -1,194 +0,0 @@
|
||||
|
||||
/datum/proc/get_view_variables_header()
|
||||
return "<b>[src]</b>"
|
||||
|
||||
/atom/get_view_variables_header()
|
||||
return {"
|
||||
<a href='?_src_=vars;datumedit=\ref[src];varnameedit=name'><b>[src]</b></a>
|
||||
<br><font size='1'>
|
||||
<a href='?_src_=vars;rotatedatum=\ref[src];rotatedir=left'><<</a>
|
||||
<a href='?_src_=vars;datumedit=\ref[src];varnameedit=dir'>[dir2text(dir)]</a>
|
||||
<a href='?_src_=vars;rotatedatum=\ref[src];rotatedir=right'>>></a>
|
||||
</font>
|
||||
"}
|
||||
|
||||
/mob/living/get_view_variables_header()
|
||||
return {"
|
||||
<a href='?_src_=vars;rename=\ref[src]'><b>[src]</b></a><font size='1'>
|
||||
<br><a href='?_src_=vars;rotatedatum=\ref[src];rotatedir=left'><<</a> <a href='?_src_=vars;datumedit=\ref[src];varnameedit=dir'>[dir2text(dir)]</a> <a href='?_src_=vars;rotatedatum=\ref[src];rotatedir=right'>>></a>
|
||||
<br><a href='?_src_=vars;datumedit=\ref[src];varnameedit=ckey'>[ckey ? ckey : "No ckey"]</a> / <a href='?_src_=vars;datumedit=\ref[src];varnameedit=real_name'>[real_name ? real_name : "No real name"]</a>
|
||||
<br>
|
||||
BRUTE:<a href='?_src_=vars;mobToDamage=\ref[src];adjustDamage=brute'>[getBruteLoss()]</a>
|
||||
FIRE:<a href='?_src_=vars;mobToDamage=\ref[src];adjustDamage=fire'>[getFireLoss()]</a>
|
||||
TOXIN:<a href='?_src_=vars;mobToDamage=\ref[src];adjustDamage=toxin'>[getToxLoss()]</a>
|
||||
OXY:<a href='?_src_=vars;mobToDamage=\ref[src];adjustDamage=oxygen'>[getOxyLoss()]</a>
|
||||
CLONE:<a href='?_src_=vars;mobToDamage=\ref[src];adjustDamage=clone'>[getCloneLoss()]</a>
|
||||
BRAIN:<a href='?_src_=vars;mobToDamage=\ref[src];adjustDamage=brain'>[getBrainLoss()]</a>
|
||||
</font>
|
||||
"}
|
||||
|
||||
/datum/proc/get_view_variables_options()
|
||||
return ""
|
||||
|
||||
/mob/get_view_variables_options()
|
||||
return ..() + {"
|
||||
<option value='?_src_=vars;mob_player_panel=\ref[src]'>Show player panel</option>
|
||||
<option>---</option>
|
||||
<option value='?_src_=vars;give_modifier=\ref[src]'>Give Modifier</option>
|
||||
<option value='?_src_=vars;give_spell=\ref[src]'>Give Spell</option>
|
||||
<option value='?_src_=vars;give_disease2=\ref[src]'>Give Disease</option>
|
||||
<option value='?_src_=vars;give_disease=\ref[src]'>Give TG-style Disease</option>
|
||||
<option value='?_src_=vars;godmode=\ref[src]'>Toggle Godmode</option>
|
||||
<option value='?_src_=vars;build_mode=\ref[src]'>Toggle Build Mode</option>
|
||||
|
||||
<option value='?_src_=vars;ninja=\ref[src]'>Make Space Ninja</option>
|
||||
<option value='?_src_=vars;make_skeleton=\ref[src]'>Make 2spooky</option>
|
||||
|
||||
<option value='?_src_=vars;direct_control=\ref[src]'>Assume Direct Control</option>
|
||||
<option value='?_src_=vars;drop_everything=\ref[src]'>Drop Everything</option>
|
||||
|
||||
<option value='?_src_=vars;regenerateicons=\ref[src]'>Regenerate Icons</option>
|
||||
<option value='?_src_=vars;addlanguage=\ref[src]'>Add Language</option>
|
||||
<option value='?_src_=vars;remlanguage=\ref[src]'>Remove Language</option>
|
||||
<option value='?_src_=vars;addorgan=\ref[src]'>Add Organ</option>
|
||||
<option value='?_src_=vars;remorgan=\ref[src]'>Remove Organ</option>
|
||||
|
||||
<option value='?_src_=vars;fix_nano=\ref[src]'>Fix NanoUI</option>
|
||||
|
||||
<option value='?_src_=vars;addverb=\ref[src]'>Add Verb</option>
|
||||
<option value='?_src_=vars;remverb=\ref[src]'>Remove Verb</option>
|
||||
<option>---</option>
|
||||
<option value='?_src_=vars;gib=\ref[src]'>Gib</option>
|
||||
<option value='?_src_=vars;explode=\ref[src]'>Trigger explosion</option>
|
||||
<option value='?_src_=vars;emp=\ref[src]'>Trigger EM pulse</option>
|
||||
"}
|
||||
|
||||
/mob/living/carbon/human/get_view_variables_options()
|
||||
return ..() + {"
|
||||
<option value='?_src_=vars;setspecies=\ref[src]'>Set Species</option>
|
||||
<option value='?_src_=vars;makeai=\ref[src]'>Make AI</option>
|
||||
<option value='?_src_=vars;makerobot=\ref[src]'>Make cyborg</option>
|
||||
<option value='?_src_=vars;makemonkey=\ref[src]'>Make monkey</option>
|
||||
<option value='?_src_=vars;makealien=\ref[src]'>Make alien</option>
|
||||
"}
|
||||
|
||||
/obj/get_view_variables_options()
|
||||
return ..() + {"
|
||||
<option value='?_src_=vars;delall=\ref[src]'>Delete all of type</option>
|
||||
<option value='?_src_=vars;explode=\ref[src]'>Trigger explosion</option>
|
||||
<option value='?_src_=vars;emp=\ref[src]'>Trigger EM pulse</option>
|
||||
"}
|
||||
|
||||
/turf/get_view_variables_options()
|
||||
return ..() + {"
|
||||
<option value='?_src_=vars;explode=\ref[src]'>Trigger explosion</option>
|
||||
<option value='?_src_=vars;emp=\ref[src]'>Trigger EM pulse</option>
|
||||
"}
|
||||
|
||||
/datum/proc/get_variables()
|
||||
. = vars - VV_hidden()
|
||||
if(!usr || !check_rights(R_ADMIN|R_DEBUG, FALSE))
|
||||
. -= VV_secluded()
|
||||
|
||||
/datum/proc/get_variable_value(varname)
|
||||
return vars[varname]
|
||||
|
||||
/datum/proc/set_variable_value(varname, value)
|
||||
vars[varname] = value
|
||||
|
||||
/datum/proc/get_initial_variable_value(varname)
|
||||
return initial(vars[varname])
|
||||
|
||||
/datum/proc/make_view_variables_variable_entry(var/varname, var/value, var/hide_watch = 0)
|
||||
return {"
|
||||
(<a href='?_src_=vars;datumedit=\ref[src];varnameedit=[varname]'>E</a>)
|
||||
(<a href='?_src_=vars;datumchange=\ref[src];varnamechange=[varname]'>C</a>)
|
||||
(<a href='?_src_=vars;datummass=\ref[src];varnamemass=[varname]'>M</a>)
|
||||
[hide_watch ? "" : "(<a href='?_src_=vars;datumwatch=\ref[src];varnamewatch=[varname]'>W</a>)"]
|
||||
"}
|
||||
|
||||
// No mass editing of clients
|
||||
/client/make_view_variables_variable_entry(var/varname, var/value, var/hide_watch = 0)
|
||||
return {"
|
||||
(<a href='?_src_=vars;datumedit=\ref[src];varnameedit=[varname]'>E</a>)
|
||||
(<a href='?_src_=vars;datumchange=\ref[src];varnamechange=[varname]'>C</a>)
|
||||
[hide_watch ? "" : "(<a href='?_src_=vars;datumwatch=\ref[src];varnamewatch=[varname]'>W</a>)"]
|
||||
"}
|
||||
|
||||
// These methods are all procs and don't use stored lists to avoid VV exploits
|
||||
|
||||
// The following vars cannot be viewed by anyone
|
||||
/datum/proc/VV_hidden()
|
||||
return list()
|
||||
|
||||
// The following vars can only be viewed by R_ADMIN|R_DEBUG
|
||||
/datum/proc/VV_secluded()
|
||||
return list()
|
||||
|
||||
/datum/configuration/VV_secluded()
|
||||
return vars
|
||||
|
||||
// The following vars cannot be edited by anyone
|
||||
/datum/proc/VV_static()
|
||||
return list("parent_type")
|
||||
|
||||
/atom/VV_static()
|
||||
return ..() + list("bound_x", "bound_y", "bound_height", "bound_width", "bounds", "step_x", "step_y", "step_size")
|
||||
|
||||
/client/VV_static()
|
||||
return ..() + list("holder", "prefs")
|
||||
|
||||
/datum/admins/VV_static()
|
||||
return vars
|
||||
|
||||
// The following vars require R_DEBUG to edit
|
||||
/datum/proc/VV_locked()
|
||||
return list("vars", "virus", "viruses", "cuffed")
|
||||
|
||||
/client/VV_locked()
|
||||
return list("vars", "mob")
|
||||
|
||||
/mob/VV_locked()
|
||||
return ..() + list("client")
|
||||
|
||||
// The following vars require R_FUN|R_DEBUG to edit
|
||||
/datum/proc/VV_icon_edit_lock()
|
||||
return list()
|
||||
|
||||
/atom/VV_icon_edit_lock()
|
||||
return ..() + list("icon", "icon_state", "overlays", "underlays")
|
||||
|
||||
// The following vars require R_SPAWN|R_DEBUG to edit
|
||||
/datum/proc/VV_ckey_edit()
|
||||
return list()
|
||||
|
||||
/mob/VV_ckey_edit()
|
||||
return list("key", "ckey")
|
||||
|
||||
/client/VV_ckey_edit()
|
||||
return list("key", "ckey")
|
||||
|
||||
/datum/proc/may_edit_var(var/user, var/var_to_edit)
|
||||
if(!user)
|
||||
return FALSE
|
||||
if(!(var_to_edit in vars))
|
||||
to_chat(user, "<span class='warning'>\The [src] does not have a var '[var_to_edit]'</span>")
|
||||
return FALSE
|
||||
if(var_to_edit in VV_static())
|
||||
return FALSE
|
||||
if((var_to_edit in VV_secluded()) && !check_rights(R_ADMIN|R_DEBUG, FALSE, C = user))
|
||||
return FALSE
|
||||
if((var_to_edit in VV_locked()) && !check_rights(R_DEBUG, C = user))
|
||||
return FALSE
|
||||
if((var_to_edit in VV_ckey_edit()) && !check_rights(R_SPAWN|R_DEBUG, C = user))
|
||||
return FALSE
|
||||
if((var_to_edit in VV_icon_edit_lock()) && !check_rights(R_FUN|R_DEBUG, C = user))
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/proc/forbidden_varedit_object_types()
|
||||
return 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
|
||||
)
|
||||
@@ -0,0 +1,48 @@
|
||||
//This entire file needs to be removed eventually
|
||||
/datum/proc/get_view_variables_options()
|
||||
return ""
|
||||
|
||||
/mob/get_view_variables_options()
|
||||
return ..() + {"
|
||||
<option value='?_src_=vars;mob_player_panel=\ref[src]'>Show player panel</option>
|
||||
<option>---</option>
|
||||
<option value='?_src_=vars;give_modifier=\ref[src]'>Give Modifier</option>
|
||||
<option value='?_src_=vars;give_spell=\ref[src]'>Give Spell</option>
|
||||
<option value='?_src_=vars;give_disease2=\ref[src]'>Give Disease</option>
|
||||
<option value='?_src_=vars;give_disease=\ref[src]'>Give TG-style Disease</option>
|
||||
<option value='?_src_=vars;godmode=\ref[src]'>Toggle Godmode</option>
|
||||
<option value='?_src_=vars;build_mode=\ref[src]'>Toggle Build Mode</option>
|
||||
|
||||
<option value='?_src_=vars;ninja=\ref[src]'>Make Space Ninja</option>
|
||||
<option value='?_src_=vars;make_skeleton=\ref[src]'>Make 2spooky</option>
|
||||
|
||||
<option value='?_src_=vars;direct_control=\ref[src]'>Assume Direct Control</option>
|
||||
<option value='?_src_=vars;drop_everything=\ref[src]'>Drop Everything</option>
|
||||
|
||||
<option value='?_src_=vars;regenerateicons=\ref[src]'>Regenerate Icons</option>
|
||||
<option value='?_src_=vars;addlanguage=\ref[src]'>Add Language</option>
|
||||
<option value='?_src_=vars;remlanguage=\ref[src]'>Remove Language</option>
|
||||
<option value='?_src_=vars;addorgan=\ref[src]'>Add Organ</option>
|
||||
<option value='?_src_=vars;remorgan=\ref[src]'>Remove Organ</option>
|
||||
|
||||
<option value='?_src_=vars;fix_nano=\ref[src]'>Fix NanoUI</option>
|
||||
|
||||
<option value='?_src_=vars;addverb=\ref[src]'>Add Verb</option>
|
||||
<option value='?_src_=vars;remverb=\ref[src]'>Remove Verb</option>
|
||||
<option>---</option>
|
||||
<option value='?_src_=vars;gib=\ref[src]'>Gib</option>
|
||||
"}
|
||||
|
||||
/mob/living/carbon/human/get_view_variables_options()
|
||||
return ..() + {"
|
||||
<option value='?_src_=vars;setspecies=\ref[src]'>Set Species</option>
|
||||
<option value='?_src_=vars;makeai=\ref[src]'>Make AI</option>
|
||||
<option value='?_src_=vars;makerobot=\ref[src]'>Make cyborg</option>
|
||||
<option value='?_src_=vars;makemonkey=\ref[src]'>Make monkey</option>
|
||||
<option value='?_src_=vars;makealien=\ref[src]'>Make alien</option>
|
||||
"}
|
||||
|
||||
/obj/get_view_variables_options()
|
||||
return ..() + {"
|
||||
<option value='?_src_=vars;delall=\ref[src]'>Delete all of type</option>
|
||||
"}
|
||||
@@ -0,0 +1,265 @@
|
||||
/client/proc/cmd_mass_modify_object_variables(atom/A, var_name)
|
||||
set category = "Debug"
|
||||
set name = "Mass Edit Variables"
|
||||
set desc="(target) Edit all instances of a target item's variables"
|
||||
|
||||
var/method = 0 //0 means strict type detection while 1 means this type and all subtypes (IE: /obj/item with this set to 1 will set it to ALL items)
|
||||
|
||||
if(!check_rights(R_VAREDIT))
|
||||
return
|
||||
|
||||
if(A && A.type)
|
||||
method = vv_subtype_prompt(A.type)
|
||||
|
||||
src.massmodify_variables(A, var_name, method)
|
||||
feedback_add_details("admin_verb","MVV") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
/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)
|
||||
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 || !O.can_vv_get(variable))
|
||||
return
|
||||
var/default
|
||||
var/var_value = O.vars[variable]
|
||||
|
||||
if(variable in GLOB.VVckey_edit)
|
||||
to_chat(src, "It's forbidden to mass-modify ckeys. It'll crash everyone's client you dummy.")
|
||||
return
|
||||
if(variable in GLOB.VVlocked)
|
||||
if(!check_rights(R_DEBUG))
|
||||
return
|
||||
if(variable in GLOB.VVicon_edit_lock)
|
||||
if(!check_rights(R_FUN|R_DEBUG))
|
||||
return
|
||||
if(variable in GLOB.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
|
||||
|
||||
default = vv_get_class(variable, var_value)
|
||||
|
||||
if(isnull(default))
|
||||
to_chat(src, "Unable to determine variable type.")
|
||||
else
|
||||
to_chat(src, "Variable appears to be <b>[uppertext(default)]</b>.")
|
||||
|
||||
to_chat(src, "Variable contains: [var_value]")
|
||||
|
||||
if(default == VV_NUM)
|
||||
var/dir_text = ""
|
||||
if(var_value > 0 && var_value < 16)
|
||||
if(var_value & 1)
|
||||
dir_text += "NORTH"
|
||||
if(var_value & 2)
|
||||
dir_text += "SOUTH"
|
||||
if(var_value & 4)
|
||||
dir_text += "EAST"
|
||||
if(var_value & 8)
|
||||
dir_text += "WEST"
|
||||
|
||||
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
|
||||
|
||||
if (class == VV_MESSAGE)
|
||||
class = VV_TEXT
|
||||
|
||||
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(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]]")
|
||||
|
||||
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]]")
|
||||
|
||||
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
|
||||
many = FALSE
|
||||
|
||||
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()
|
||||
|
||||
if (D.vv_edit_var(variable, new_value) != FALSE)
|
||||
accepted++
|
||||
else
|
||||
rejected++
|
||||
new_value = null
|
||||
CHECK_TICK
|
||||
|
||||
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
|
||||
|
||||
|
||||
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")
|
||||
|
||||
log_world("### 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)")
|
||||
|
||||
|
||||
/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 (ispath(T, /obj/machinery/door))
|
||||
for(var/obj/machinery/door/thing in world)
|
||||
if (typecache[thing.type])
|
||||
. += thing
|
||||
CHECK_TICK
|
||||
|
||||
else if (ispath(T, /obj/machinery))
|
||||
for(var/obj/machinery/thing in machines)
|
||||
if (typecache[thing.type])
|
||||
. += thing
|
||||
CHECK_TICK
|
||||
|
||||
else if (ispath(T, /obj))
|
||||
for(var/obj/thing in world)
|
||||
if (typecache[thing.type])
|
||||
. += thing
|
||||
CHECK_TICK
|
||||
|
||||
else if (ispath(T, /atom/movable))
|
||||
for(var/atom/movable/thing in world)
|
||||
if (typecache[thing.type])
|
||||
. += thing
|
||||
CHECK_TICK
|
||||
|
||||
else if (ispath(T, /turf))
|
||||
for(var/turf/thing in world)
|
||||
if (typecache[thing.type])
|
||||
. += thing
|
||||
CHECK_TICK
|
||||
|
||||
else if (ispath(T, /atom))
|
||||
for(var/atom/thing in world)
|
||||
if (typecache[thing.type])
|
||||
. += thing
|
||||
CHECK_TICK
|
||||
|
||||
else if (ispath(T, /client))
|
||||
for(var/client/thing in GLOB.clients)
|
||||
if (typecache[thing.type])
|
||||
. += thing
|
||||
CHECK_TICK
|
||||
|
||||
else if (ispath(T, /datum))
|
||||
for(var/datum/thing)
|
||||
if (typecache[thing.type])
|
||||
. += thing
|
||||
CHECK_TICK
|
||||
|
||||
else
|
||||
for(var/datum/thing in world)
|
||||
if (typecache[thing.type])
|
||||
. += thing
|
||||
CHECK_TICK
|
||||
@@ -0,0 +1,387 @@
|
||||
GLOBAL_LIST_INIT(VVlocked, list("vars", "datum_flags", "client", "mob")) //Requires DEBUG
|
||||
GLOBAL_PROTECT(VVlocked)
|
||||
GLOBAL_LIST_INIT(VVicon_edit_lock, list("icon", "icon_state", "overlays", "underlays")) //Requires DEBUG or FUN
|
||||
GLOBAL_PROTECT(VVicon_edit_lock)
|
||||
GLOBAL_LIST_INIT(VVckey_edit, list("key", "ckey")) //Requires DEBUG or SPAWN
|
||||
GLOBAL_PROTECT(VVckey_edit)
|
||||
GLOBAL_LIST_INIT(VVpixelmovement, list("bound_x", "bound_y", "step_x", "step_y", "step_size", "bound_height", "bound_width", "bounds")) //No editing ever.
|
||||
GLOBAL_PROTECT(VVpixelmovement)
|
||||
|
||||
/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) //hehe
|
||||
|
||||
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(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(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(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]]")
|
||||
|
||||
if (O)
|
||||
L = L.Copy()
|
||||
|
||||
L += var_value
|
||||
|
||||
switch(alert("Would you like to associate a value with the list entry?",,"Yes","No"))
|
||||
if("Yes")
|
||||
L[var_value] = mod_list_add_ass(O) //hehe
|
||||
if (O)
|
||||
if (O.vv_edit_var(objectvar, L) == FALSE)
|
||||
to_chat(src, "Your edit was rejected by the object.")
|
||||
return
|
||||
log_world("### 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(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/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_world("### 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_world("### 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_world("### 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/assoc_key
|
||||
if (index == null)
|
||||
return
|
||||
var/assoc = 0
|
||||
var/prompt = alert(src, "Do you want to edit the key or its 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
|
||||
var/old_assoc_value //EXPERIMENTAL - Keep old associated value while modifying key, if any
|
||||
if (assoc)
|
||||
variable = L[assoc_key]
|
||||
else
|
||||
variable = L[index]
|
||||
//EXPERIMENTAL - Keep old associated value while modifying key, if any
|
||||
var/found = L[variable]
|
||||
if(!isnull(found))
|
||||
old_assoc_value = found
|
||||
//
|
||||
|
||||
default = vv_get_class(objectvar, variable)
|
||||
|
||||
to_chat(src, "Variable appears to be <b>[uppertext(default)]</b>.")
|
||||
|
||||
to_chat(src, "Variable contains: [variable]")
|
||||
|
||||
if(default == VV_NUM)
|
||||
var/dir_text = ""
|
||||
var/tdir = variable
|
||||
if(tdir > 0 && tdir < 16)
|
||||
if(tdir & 1)
|
||||
dir_text += "NORTH"
|
||||
if(tdir & 2)
|
||||
dir_text += "SOUTH"
|
||||
if(tdir & 4)
|
||||
dir_text += "EAST"
|
||||
if(tdir & 8)
|
||||
dir_text += "WEST"
|
||||
|
||||
if(dir_text)
|
||||
to_chat(usr, "If a direction, direction is: [dir_text]")
|
||||
|
||||
var/original_var = variable
|
||||
|
||||
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(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(VV_LIST)
|
||||
mod_list(variable, O, original_name, objectvar)
|
||||
|
||||
if("DELETE FROM LIST")
|
||||
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_world("### 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(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]]")
|
||||
|
||||
|
||||
if(assoc)
|
||||
L[assoc_key] = new_var
|
||||
else
|
||||
L[index] = new_var
|
||||
if(!isnull(old_assoc_value) && IS_VALID_ASSOC_KEY(new_var))
|
||||
L[new_var] = old_assoc_value
|
||||
if (O)
|
||||
if (O.vv_edit_var(objectvar, L) == FALSE)
|
||||
to_chat(src, "Your edit was rejected by the object.")
|
||||
return
|
||||
log_world("### 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]")
|
||||
|
||||
/proc/vv_varname_lockcheck(param_var_name)
|
||||
if(param_var_name in GLOB.VVlocked)
|
||||
if(!check_rights(R_DEBUG))
|
||||
return FALSE
|
||||
if(param_var_name in GLOB.VVckey_edit)
|
||||
if(!check_rights(R_SPAWN|R_DEBUG))
|
||||
return FALSE
|
||||
if(param_var_name in GLOB.VVicon_edit_lock)
|
||||
if(!check_rights(R_FUN|R_DEBUG))
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/client/proc/modify_variables(atom/O, param_var_name = null, autodetect_class = 0)
|
||||
if(!check_rights(R_VAREDIT))
|
||||
return
|
||||
|
||||
var/class
|
||||
var/variable
|
||||
var/var_value
|
||||
|
||||
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 datum ([O])")
|
||||
return
|
||||
variable = param_var_name
|
||||
|
||||
else
|
||||
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
|
||||
if(!variable)
|
||||
return
|
||||
|
||||
if(!O.can_vv_get(variable))
|
||||
return
|
||||
|
||||
var_value = O.vars[variable]
|
||||
if(!vv_varname_lockcheck(variable))
|
||||
return
|
||||
|
||||
var/default = vv_get_class(variable, var_value)
|
||||
|
||||
if(isnull(default))
|
||||
to_chat(src, "Unable to determine variable type.")
|
||||
else
|
||||
to_chat(src, "Variable appears to be <b>[uppertext(default)]</b>.")
|
||||
|
||||
to_chat(src, "Variable contains: [var_value]")
|
||||
|
||||
if(default == VV_NUM)
|
||||
var/dir_text = ""
|
||||
if(var_value > 0 && var_value < 16)
|
||||
if(var_value & 1)
|
||||
dir_text += "NORTH"
|
||||
if(var_value & 2)
|
||||
dir_text += "SOUTH"
|
||||
if(var_value & 4)
|
||||
dir_text += "EAST"
|
||||
if(var_value & 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), var_name = variable)
|
||||
class = value["class"]
|
||||
|
||||
if (!class)
|
||||
return
|
||||
var/var_new = value["value"]
|
||||
|
||||
if(class == VV_MESSAGE)
|
||||
class = VV_TEXT
|
||||
|
||||
var/original_name = "[O]"
|
||||
|
||||
switch(class)
|
||||
if(VV_LIST)
|
||||
if(!islist(var_value))
|
||||
mod_list(list(), O, original_name, variable)
|
||||
|
||||
mod_list(var_value, O, original_name, variable)
|
||||
return
|
||||
|
||||
if(VV_RESTORE_DEFAULT)
|
||||
var_new = initial(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 (O.vv_edit_var(variable, var_new) == FALSE)
|
||||
to_chat(src, "Your edit was rejected by the object.")
|
||||
return
|
||||
vv_update_display(O, "varedited", VV_MSG_EDITED)
|
||||
log_world("### VarEdit by [key_name(src)]: [O.type] [variable]=[var_value] => [var_new]")
|
||||
log_admin("[key_name(src)] modified [original_name]'s [variable] from [html_encode("[var_value]")] to [html_encode("[var_new]")]")
|
||||
var/msg = "[key_name_admin(src)] modified [original_name]'s [variable] from [var_value] to [var_new]"
|
||||
message_admins(msg)
|
||||
admin_ticket_log(O, msg)
|
||||
return TRUE
|
||||
@@ -1,8 +1,12 @@
|
||||
|
||||
//DO NOT ADD MORE TO THIS FILE.
|
||||
//Use vv_do_topic()!
|
||||
/client/proc/view_var_Topic(href, href_list, hsrc)
|
||||
//This should all be moved over to datum/admins/Topic() or something ~Carn
|
||||
if( (usr.client != src) || !src.holder )
|
||||
if((usr.client != src) || !src.holder)
|
||||
return
|
||||
var/datum/target = locate(href_list["target"])
|
||||
if(target)
|
||||
target.vv_do_topic(href_list)
|
||||
|
||||
if(href_list["Vars"])
|
||||
debug_variables(locate(href_list["Vars"]))
|
||||
|
||||
@@ -163,11 +167,12 @@
|
||||
href_list["datumrefresh"] = href_list["make_skeleton"]
|
||||
|
||||
else if(href_list["delall"])
|
||||
if(!check_rights(R_DEBUG|R_SERVER)) return
|
||||
if(!check_rights(R_DEBUG|R_SERVER))
|
||||
return
|
||||
|
||||
var/obj/O = locate(href_list["delall"])
|
||||
if(!isobj(O))
|
||||
usr << "This can only be used on instances of type /obj"
|
||||
to_chat(usr, "This can only be used on instances of type /obj")
|
||||
return
|
||||
|
||||
var/action_type = alert("Strict type ([O.type]) or type and all subtypes?",,"Strict type","Type and subtypes","Cancel")
|
||||
@@ -188,55 +193,24 @@
|
||||
if(Obj.type == O_type)
|
||||
i++
|
||||
qdel(Obj)
|
||||
CHECK_TICK
|
||||
if(!i)
|
||||
usr << "No objects of this type exist"
|
||||
to_chat(usr, "No objects of this type exist")
|
||||
return
|
||||
log_admin("[key_name(usr)] deleted all objects of type [O_type] ([i] objects deleted)")
|
||||
message_admins("<span class='notice'>[key_name(usr)] deleted all objects of type [O_type] ([i] objects deleted)</span>")
|
||||
log_admin("[key_name(usr)] deleted all objects of type [O_type] ([i] objects deleted) ")
|
||||
message_admins("<span class='notice'>[key_name(usr)] deleted all objects of type [O_type] ([i] objects deleted) </span>")
|
||||
if("Type and subtypes")
|
||||
var/i = 0
|
||||
for(var/obj/Obj in world)
|
||||
if(istype(Obj,O_type))
|
||||
i++
|
||||
qdel(Obj)
|
||||
CHECK_TICK
|
||||
if(!i)
|
||||
usr << "No objects of this type exist"
|
||||
to_chat(usr, "No objects of this type exist")
|
||||
return
|
||||
log_admin("[key_name(usr)] deleted all objects of type or subtype of [O_type] ([i] objects deleted)")
|
||||
message_admins("<span class='notice'>[key_name(usr)] deleted all objects of type or subtype of [O_type] ([i] objects deleted)</span>")
|
||||
|
||||
else if(href_list["explode"])
|
||||
if(!check_rights(R_DEBUG|R_FUN)) return
|
||||
|
||||
var/atom/A = locate(href_list["explode"])
|
||||
if(!isobj(A) && !ismob(A) && !isturf(A))
|
||||
usr << "This can only be done to instances of type /obj, /mob and /turf"
|
||||
return
|
||||
|
||||
src.cmd_admin_explosion(A)
|
||||
href_list["datumrefresh"] = href_list["explode"]
|
||||
|
||||
else if(href_list["emp"])
|
||||
if(!check_rights(R_DEBUG|R_FUN)) return
|
||||
|
||||
var/atom/A = locate(href_list["emp"])
|
||||
if(!isobj(A) && !ismob(A) && !isturf(A))
|
||||
usr << "This can only be done to instances of type /obj, /mob and /turf"
|
||||
return
|
||||
|
||||
src.cmd_admin_emp(A)
|
||||
href_list["datumrefresh"] = href_list["emp"]
|
||||
|
||||
else if(href_list["mark_object"])
|
||||
if(!check_rights(0)) return
|
||||
|
||||
var/datum/D = locate(href_list["mark_object"])
|
||||
if(!istype(D))
|
||||
usr << "This can only be done to instances of type /datum"
|
||||
return
|
||||
|
||||
src.holder.marked_datum = D
|
||||
href_list["datumrefresh"] = href_list["mark_object"]
|
||||
log_admin("[key_name(usr)] deleted all objects of type or subtype of [O_type] ([i] objects deleted) ")
|
||||
message_admins("<span class='notice'>[key_name(usr)] deleted all objects of type or subtype of [O_type] ([i] objects deleted) </span>")
|
||||
|
||||
else if(href_list["rotatedatum"])
|
||||
if(!check_rights(0)) return
|
||||
@@ -519,15 +493,31 @@
|
||||
log_admin("[key_name(usr)] dealt [amount] amount of [Text] damage to [L]")
|
||||
message_admins("<span class='notice'>[key_name(usr)] dealt [amount] amount of [Text] damage to [L]</span>")
|
||||
href_list["datumrefresh"] = href_list["mobToDamage"]
|
||||
|
||||
else if(href_list["call_proc"])
|
||||
var/datum/D = locate(href_list["call_proc"])
|
||||
if(istype(D) || istype(D, /client)) // can call on clients too, not just datums
|
||||
callproc_targetpicked(1, D)
|
||||
else if(href_list["expose"])
|
||||
if(!check_rights(R_ADMIN, FALSE))
|
||||
return
|
||||
var/thing = locate(href_list["expose"])
|
||||
if(!thing) //Do NOT QDELETED check!
|
||||
return
|
||||
var/value = vv_get_value(VV_CLIENT)
|
||||
if (value["class"] != VV_CLIENT)
|
||||
return
|
||||
var/client/C = value["value"]
|
||||
if (!C)
|
||||
return
|
||||
var/prompt = alert("Do you want to grant [C] access to view this VV window? (they will not be able to edit or change anysrc nor open nested vv windows unless they themselves are an admin)", "Confirm", "Yes", "No")
|
||||
if (prompt != "Yes")
|
||||
return
|
||||
if(!thing)
|
||||
to_chat(usr, "<span class='warning'>The object you tried to expose to [C] no longer exists (GC'd)</span>")
|
||||
return
|
||||
message_admins("[key_name_admin(usr)] Showed [key_name_admin(C)] a <a href='?_src_=vars;datumrefresh=\ref[thing]'>VV window</a>")
|
||||
log_admin("Admin [key_name(usr)] Showed [key_name(C)] a VV window of a [src]")
|
||||
to_chat(C, "[holder.fakekey ? "an Administrator" : "[usr.client.key]"] has granted you access to view a View Variables window")
|
||||
C.debug_variables(thing)
|
||||
|
||||
if(href_list["datumrefresh"])
|
||||
var/datum/DAT = locate(href_list["datumrefresh"])
|
||||
if(istype(DAT, /datum) || istype(DAT, /client))
|
||||
debug_variables(DAT)
|
||||
|
||||
return
|
||||
|
||||
@@ -1,183 +1,284 @@
|
||||
|
||||
// Variables to not even show in the list.
|
||||
// step_* and bound_* are here because they literally break the game and do nothing else.
|
||||
// parent_type is here because it's pointless to show in VV.
|
||||
/var/list/view_variables_hide_vars = list("bound_x", "bound_y", "bound_height", "bound_width", "bounds", "parent_type", "step_x", "step_y", "step_size")
|
||||
// Variables not to expand the lists of. Vars is pointless to expand, and overlays/underlays cannot be expanded.
|
||||
/var/list/view_variables_dont_expand = list("overlays", "underlays", "vars")
|
||||
|
||||
/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(!check_rights(0))
|
||||
if(!usr.client || !usr.client.holder) //The usr vs src abuse in this proc is intentional and must not be changed
|
||||
to_chat(usr, "<span class='danger'>You need to be an administrator to access this.</span>")
|
||||
return
|
||||
|
||||
if(!D)
|
||||
return
|
||||
|
||||
var/icon/sprite
|
||||
if(istype(D, /atom))
|
||||
var/atom/A = D
|
||||
if(A.icon && A.icon_state)
|
||||
sprite = icon(A.icon, A.icon_state)
|
||||
usr << browse_rsc(sprite, "view_vars_sprite.png")
|
||||
var/islist = islist(D)
|
||||
if (!islist && !istype(D))
|
||||
return
|
||||
|
||||
usr << browse_rsc('code/js/view_variables.js', "view_variables.js")
|
||||
var/title = ""
|
||||
var/refid = "\ref[D]"
|
||||
var/icon/sprite
|
||||
var/hash
|
||||
|
||||
var/type = /list
|
||||
if (!islist)
|
||||
type = D.type
|
||||
|
||||
if(istype(D, /atom))
|
||||
var/atom/AT = D
|
||||
if(AT.icon && AT.icon_state)
|
||||
sprite = new /icon(AT.icon, AT.icon_state)
|
||||
hash = md5(AT.icon)
|
||||
hash = md5(hash + AT.icon_state)
|
||||
src << browse_rsc(sprite, "vv[hash].png")
|
||||
|
||||
title = "[D] (\ref[D]) = [type]"
|
||||
var/formatted_type = replacetext("[type]", "/", "<wbr>/")
|
||||
|
||||
var/sprite_text
|
||||
if(sprite)
|
||||
sprite_text = "<img src='vv[hash].png'></td><td>"
|
||||
var/list/header = islist(D)? list("<b>/list</b>") : D.vv_get_header()
|
||||
|
||||
var/marked
|
||||
if(holder && holder.marked_datum && holder.marked_datum == D)
|
||||
marked = VV_MSG_MARKED
|
||||
var/varedited_line = ""
|
||||
if(!islist && (D.datum_flags & DF_VAR_EDITED))
|
||||
varedited_line = VV_MSG_EDITED
|
||||
var/deleted_line
|
||||
if(!islist && D.gc_destroyed)
|
||||
deleted_line = VV_MSG_DELETED
|
||||
|
||||
var/list/dropdownoptions = list()
|
||||
var/autoconvert_dropdown = FALSE
|
||||
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]",
|
||||
"Show VV To Player" = "?_src_=vars;expose=[refid]"
|
||||
)
|
||||
autoconvert_dropdown = TRUE
|
||||
else
|
||||
dropdownoptions = D.vv_get_dropdown()
|
||||
var/list/dropdownoptions_html = list()
|
||||
if(autoconvert_dropdown)
|
||||
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>"
|
||||
else
|
||||
dropdownoptions_html = dropdownoptions + D.get_view_variables_options()
|
||||
|
||||
var/list/names = list()
|
||||
if (!islist)
|
||||
for (var/V in D.vars)
|
||||
names += V
|
||||
sleep(1)//For some reason, without this sleep, VVing will cause client to disconnect on certain objects.
|
||||
|
||||
var/list/variable_html = list()
|
||||
if (islist)
|
||||
var/list/L = D
|
||||
for (var/i in 1 to L.len)
|
||||
var/key = L[i]
|
||||
var/value
|
||||
if (IS_NORMAL_LIST(L) && !isnum(key))
|
||||
value = L[key]
|
||||
variable_html += debug_variable(i, value, 0, D)
|
||||
else
|
||||
|
||||
names = sortList(names)
|
||||
for (var/V in names)
|
||||
if(D.can_vv_get(V))
|
||||
variable_html += D.vv_get_var(V)
|
||||
|
||||
var/html = {"
|
||||
<html>
|
||||
<head>
|
||||
<script src='view_variables.js'></script>
|
||||
<title>[D] (\ref[D] - [D.type])</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()'; onkeyup='updateSearch()'>
|
||||
<div align='center'>
|
||||
<table width='100%'><tr>
|
||||
<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()' onkeydown='return handle_keydown()' onkeyup='handle_keyup()'>
|
||||
<script type="text/javascript">
|
||||
// onload
|
||||
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 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 "";
|
||||
}
|
||||
|
||||
// main search functionality
|
||||
var last_filter = "";
|
||||
function updateSearch() {
|
||||
var filter = document.getElementById('filter').value.toLowerCase();
|
||||
var vars_ol = document.getElementById("vars");
|
||||
|
||||
if (filter === last_filter) {
|
||||
// An event triggered an update but nothing has changed.
|
||||
return;
|
||||
} else if (filter.indexOf(last_filter) === 0) {
|
||||
// The new filter starts with the old filter, fast path by removing only.
|
||||
var children = vars_ol.childNodes;
|
||||
for (var i = children.length - 1; i >= 0; --i) {
|
||||
try {
|
||||
var li = children\[i];
|
||||
if (li.innerText.toLowerCase().indexOf(filter) == -1) {
|
||||
vars_ol.removeChild(li);
|
||||
}
|
||||
} catch(err) {}
|
||||
}
|
||||
} else {
|
||||
// Remove everything and put back what matches.
|
||||
while (vars_ol.hasChildNodes()) {
|
||||
vars_ol.removeChild(vars_ol.lastChild);
|
||||
}
|
||||
|
||||
for (var i = 0; i < complete_list.length; ++i) {
|
||||
try {
|
||||
var li = complete_list\[i];
|
||||
if (!filter || li.innerText.toLowerCase().indexOf(filter) != -1) {
|
||||
vars_ol.appendChild(li);
|
||||
}
|
||||
} catch(err) {}
|
||||
}
|
||||
}
|
||||
|
||||
last_filter = filter;
|
||||
document.cookie="[refid][cookieoffset]search="+encodeURIComponent(filter);
|
||||
|
||||
}
|
||||
|
||||
// onkeydown
|
||||
function handle_keydown() {
|
||||
if(event.keyCode == 116) { //F5 (to refresh properly)
|
||||
document.getElementById("refresh_link").click();
|
||||
event.preventDefault ? event.preventDefault() : (event.returnValue = false);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// onkeyup
|
||||
function handle_keyup() {
|
||||
updateSearch();
|
||||
}
|
||||
|
||||
// onchange
|
||||
function handle_dropdown(list) {
|
||||
var value = list.options\[list.selectedIndex].value;
|
||||
if (value !== "") {
|
||||
location.href = value;
|
||||
}
|
||||
list.selectedIndex = 0;
|
||||
document.getElementById('filter').focus();
|
||||
}
|
||||
|
||||
// byjax
|
||||
function replace_span(what) {
|
||||
var idx = what.indexOf(':');
|
||||
document.getElementById(what.substr(0, idx)).innerHTML = what.substr(idx + 1);
|
||||
}
|
||||
</script>
|
||||
<div align='center'>
|
||||
<table width='100%'>
|
||||
<tr>
|
||||
<td width='50%'>
|
||||
<table align='center' width='100%'><tr>
|
||||
[sprite ? "<td><img src='view_vars_sprite.png'></td>" : ""]
|
||||
<td><div align='center'>[D.get_view_variables_header()]</div></td>
|
||||
</tr></table>
|
||||
<table align='center' width='100%'>
|
||||
<tr>
|
||||
<td>
|
||||
[sprite_text]
|
||||
<div align='center'>
|
||||
[header.Join()]
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<div align='center'>
|
||||
<b><font size='1'>[replacetext("[D.type]", "/", "/<wbr>")]</font></b>
|
||||
[holder.marked_datum == D ? "<br/><font size='1' color='red'><b>Marked Object</b></font>" : ""]
|
||||
<b><font size='1'>[formatted_type]</font></b>
|
||||
<span id='marked'>[marked]</span>
|
||||
<span id='varedited'>[varedited_line]</span>
|
||||
<span id='deleted'>[deleted_line]</span>
|
||||
</div>
|
||||
</td>
|
||||
<td width='50%'>
|
||||
<div align='center'>
|
||||
<a href='?_src_=vars;datumrefresh=\ref[D]'>Refresh</a>
|
||||
<a id='refresh_link' href='?_src_=vars;
|
||||
datumrefresh=[refid]'>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>Select option</option>
|
||||
<option />
|
||||
<option value='?_src_=vars;mark_object=\ref[D]'>Mark Object</option>
|
||||
<option value='?_src_=vars;call_proc=\ref[D]'>Call Proc</option>
|
||||
[D.get_view_variables_options()]
|
||||
<select name="file" size="1"
|
||||
onchange="handle_dropdown(this)"
|
||||
onmouseclick="this.focus()">
|
||||
<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>
|
||||
</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%;' />
|
||||
<input type='text' id='filter' name='filter_text' value='' style='width:100%;'>
|
||||
</td>
|
||||
</tr></table>
|
||||
<hr/>
|
||||
<ol id='vars'>
|
||||
[make_view_variables_var_list(D)]
|
||||
</ol>
|
||||
</body>
|
||||
</html>
|
||||
"}
|
||||
</tr>
|
||||
</table>
|
||||
<hr>
|
||||
<ol id='vars'>
|
||||
[variable_html.Join()]
|
||||
</ol>
|
||||
<script type='text/javascript'>
|
||||
var complete_list = \[\];
|
||||
var lis = document.getElementById("vars").children;
|
||||
for(var i = lis.length; i--;) complete_list\[i\] = lis\[i\];
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
"}
|
||||
src << browse(html, "window=variables[refid];size=475x650")
|
||||
|
||||
usr << browse(html, "window=variables\ref[D];size=475x650")
|
||||
|
||||
|
||||
/proc/make_view_variables_var_list(datum/D)
|
||||
. = ""
|
||||
var/list/variables = list()
|
||||
for(var/x in D.vars)
|
||||
if(x in view_variables_hide_vars)
|
||||
continue
|
||||
variables += x
|
||||
variables = sortList(variables)
|
||||
for(var/x in variables)
|
||||
. += make_view_variables_var_entry(D, x, D.vars[x])
|
||||
|
||||
/proc/make_view_variables_var_entry(datum/D, varname, value, level=0)
|
||||
var/ecm = null
|
||||
var/vtext = null
|
||||
var/extra = null
|
||||
|
||||
if(D)
|
||||
ecm = {"
|
||||
(<a href='?_src_=vars;datumedit=\ref[D];varnameedit=[varname]'>E</a>)
|
||||
(<a href='?_src_=vars;datumchange=\ref[D];varnamechange=[varname]'>C</a>)
|
||||
(<a href='?_src_=vars;datummass=\ref[D];varnamemass=[varname]'>M</a>)
|
||||
"}
|
||||
|
||||
if(isnull(value))
|
||||
vtext = "null"
|
||||
else if(istext(value))
|
||||
vtext = "\"[value]\""
|
||||
else if(isicon(value))
|
||||
vtext = "[value]"
|
||||
else if(isfile(value))
|
||||
vtext = "'[value]'"
|
||||
else if(istype(value, /datum))
|
||||
var/datum/DA = value
|
||||
if("[DA]" == "[DA.type]" || !"[DA]")
|
||||
vtext = "<a href='?_src_=vars;Vars=\ref[DA]'>\ref[DA]</a> - [DA.type]"
|
||||
else
|
||||
vtext = "<a href='?_src_=vars;Vars=\ref[DA]'>\ref[DA]</a> - [DA] ([DA.type])"
|
||||
else if(istype(value, /client))
|
||||
var/client/C = value
|
||||
vtext = "<a href='?_src_=vars;Vars=\ref[C]'>\ref[C]</a> - [C] ([C.type])"
|
||||
else if(islist(value))
|
||||
var/list/L = value
|
||||
var/removed = 0
|
||||
if(varname == "contents")
|
||||
var/list/original = value
|
||||
L = original.Copy() //We'll take a copy to manipulate
|
||||
removed = D.view_variables_filter_contents(L)
|
||||
vtext = "/list ([L.len]+[removed]H)"
|
||||
if(!(varname in view_variables_dont_expand) && L.len > 0 && L.len < 100)
|
||||
extra = "<ul>"
|
||||
var/index = 1
|
||||
for (var/entry in L)
|
||||
if(istext(entry))
|
||||
extra += make_view_variables_var_entry(null, entry, L[entry], level+1)
|
||||
else
|
||||
extra += make_view_variables_var_entry(null, index, L[index], level+1)
|
||||
index++
|
||||
extra += "</ul>"
|
||||
else
|
||||
vtext = "[value]"
|
||||
|
||||
return "<li>[ecm][varname] = <span class='value'>[vtext]</span>[extra]</li>"
|
||||
|
||||
//Allows us to mask out some contents when it's not necessary to show them
|
||||
//For example, organs on humans, as the organs are stored in other lists which will also be present
|
||||
//So there's really no need to list them twice.
|
||||
/datum/proc/view_variables_filter_contents(list/L)
|
||||
return 0 //Return how many items you removed.
|
||||
|
||||
/mob/living/carbon/human/view_variables_filter_contents(list/L)
|
||||
. = ..()
|
||||
L -= ability_master
|
||||
.++
|
||||
|
||||
/mob/living/carbon/human/view_variables_filter_contents(list/L)
|
||||
. = ..()
|
||||
var/len_before = L.len
|
||||
L -= organs
|
||||
L -= internal_organs
|
||||
. += len_before - L.len
|
||||
/client/proc/vv_update_display(datum/D, span, content)
|
||||
src << output("[span]:[content]", "variables\ref[D].browser:replace_span")
|
||||
|
||||
Reference in New Issue
Block a user