diff --git a/code/modules/admin/callproc/callproc.dm b/code/modules/admin/callproc/callproc.dm
index fd168b15e42..36fc9a8f9c2 100644
--- a/code/modules/admin/callproc/callproc.dm
+++ b/code/modules/admin/callproc/callproc.dm
@@ -1,149 +1,133 @@
-
/client/proc/callproc()
set category = "Debug"
set name = "Advanced ProcCall"
+ set waitfor = 0
- if(!check_rights(R_DEBUG)) return
- if(config.debugparanoid && !check_rights(R_ADMIN)) return
+ if(!check_rights(R_DEBUG))
+ return
- var/target = null
+ var/datum/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)
+ 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
-<<<<<<< HEAD
- if("finished")
- done = 1
+ var/procname = input("Proc path, eg: /proc/fake_blood","Path:", null) as text|null
+ if(!procname)
+ return
- if("null")
- current = null
+ //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("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."
+ if(targetselected && !hascall(target,testname))
+ to_chat(usr, "Error: callproc(): type [target.type] has no proc named [procname].")
+ return
+ else
+ var/procpath = text2path(procname)
+ if (!procpath)
+ to_chat(usr, "Error: callproc(): proc [procname] does not exist. (Did you forget the /proc/ part?)")
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))
-=======
+ var/list/lst = get_callproc_args()
+ if(!lst)
+ return
+
+ if(targetselected)
+ if(!target)
+ to_chat(usr, "Error: callproc(): owner of proc no longer exists.")
+ 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, "Another set of admin called procs are still running, your proc will be run after theirs finish.")
+ GLOB.AdminProcCallSpamPrevention[ckey] = TRUE
+ UNTIL(!GLOB.AdminProcCaller)
+ to_chat(usr, "Running your proc")
+ 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"
@@ -218,12 +202,9 @@
. += "[procname] returned a list:"
for(var/elem in returnedlist)
. += "\n[elem]"
->>>>>>> 158d8d3... Merge pull request #5905 from kevinz000/patch-2
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))
+ . = "[procname] returned an empty list"
+ . += ""
- usr << "[procname]() returned: [isnull(returnval) ? "null" : returnval]"
- feedback_add_details("admin_verb","APC") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
+ else
+ . = "[procname] returned: [!isnull(returnval) ? returnval : "null"]"