Adds support for multiple callback checks for the do_after and incapacitated procs (#13057)

* do_after refactor

Update slime.dm

fix a comment

if you read this you get a cookie!

* some little tweaks

Changes a TRUE to FALSE in a comment, got confused there.

Removes the code that checks for non-callbacks in the extra_checks list and removes them. It should be up to the dev to not add non-callbacks to this list. I'd rather have it runtime instead

* check_for_true_callbacks

* CRLF to LF

Co-authored-by: SteelSlayer <SteelSlayer@users.noreply.github.com>
This commit is contained in:
SteelSlayer
2020-03-21 18:21:12 -06:00
committed by GitHub
co-authored by SteelSlayer
parent bdafa40b40
commit 63ea21b20e
7 changed files with 64 additions and 28 deletions
+39 -14
View File
@@ -355,24 +355,35 @@ This is always put in the attack log.
if(progress)
qdel(progbar)
/proc/do_after(mob/user, delay, needhand = 1, atom/target = null, progress = 1, datum/callback/extra_checks = null)
/* Use this proc when you want to have code under it execute after a delay, and ensure certain conditions are met during that delay...
* Such as the user not being interrupted via getting stunned or by moving off the tile they're currently on.
*
* Example usage:
*
* if(do_after(user, 50, target = sometarget, extra_checks = list(callback_check1, callback_check2)))
* do_stuff()
*
* This will create progress bar that lasts for 5 seconds. If the user doesn't move or otherwise do something that would cause the checks to fail in those 5 seconds, do_stuff() would execute.
* The Proc returns TRUE upon success (the progress bar reached the end), or FALSE upon failure (the user moved or some other check failed)
*/
/proc/do_after(mob/user, delay, needhand = 1, atom/target = null, progress = 1, list/extra_checks = list(), use_default_checks = TRUE)
if(!user)
return 0
return FALSE
var/atom/Tloc = null
if(target)
Tloc = target.loc
var/atom/Uloc = user.loc
var/drifting = 0
var/drifting = FALSE
if(!user.Process_Spacemove(0) && user.inertia_dir)
drifting = 1
drifting = TRUE
var/holding = user.get_active_hand()
var/holdingnull = 1 //User's hand started out empty, check for an empty hand
var/holdingnull = TRUE //User's hand started out empty, check for an empty hand
if(holding)
holdingnull = 0 //Users hand started holding something, check to see if it's still holding that
holdingnull = FALSE //Users hand started holding something, check to see if it's still holding that
var/datum/progressbar/progbar
if(progress)
@@ -380,22 +391,29 @@ This is always put in the attack log.
var/endtime = world.time + delay
var/starttime = world.time
. = 1
. = TRUE
// By default, checks for weakness and stunned get added to the extra_checks list.
// Setting `use_default_checks` to FALSE means that you don't want the do_after to check for these statuses, or that you will be supplying your own checks.
if(use_default_checks)
extra_checks += CALLBACK(user, /mob.proc/IsWeakened)
extra_checks += CALLBACK(user, /mob.proc/IsStunned)
while(world.time < endtime)
sleep(1)
if(progress)
progbar.update(world.time - starttime)
if(drifting && !user.inertia_dir)
drifting = 0
drifting = FALSE
Uloc = user.loc
if(!user || user.stat || user.IsWeakened() || user.stunned || (!drifting && user.loc != Uloc)|| (extra_checks && !extra_checks.Invoke()))
. = 0
if(!user || user.stat || (!drifting && user.loc != Uloc) || check_for_true_callbacks(extra_checks))
. = FALSE
break
if(Tloc && (!target || Tloc != target.loc))
. = 0
. = FALSE
break
if(needhand)
@@ -403,14 +421,21 @@ This is always put in the attack log.
//i.e the hand is used to pull some item/tool out of the construction
if(!holdingnull)
if(!holding)
. = 0
. = FALSE
break
if(user.get_active_hand() != holding)
. = 0
. = FALSE
break
if(progress)
qdel(progbar)
// Upon any of the callbacks in the list returning TRUE, the proc will return TRUE.
/proc/check_for_true_callbacks(list/extra_checks)
for(var/datum/callback/CB in extra_checks)
if(CB.Invoke())
return TRUE
return FALSE
#define DOAFTERONCE_MAGIC "Magic~~"
GLOBAL_LIST_INIT(do_after_once_tracker, list())
/proc/do_after_once(mob/user, delay, needhand = 1, atom/target = null, progress = 1, attempt_cancel_message = "Attempt cancelled.")
@@ -423,7 +448,7 @@ GLOBAL_LIST_INIT(do_after_once_tracker, list())
to_chat(user, "<span class='warning'>[attempt_cancel_message]</span>")
return FALSE
GLOB.do_after_once_tracker[cache_key] = TRUE
. = do_after(user, delay, needhand, target, progress, extra_checks = CALLBACK(GLOBAL_PROC, .proc/do_after_once_checks, cache_key))
. = do_after(user, delay, needhand, target, progress, extra_checks = list(CALLBACK(GLOBAL_PROC, .proc/do_after_once_checks, cache_key)))
GLOB.do_after_once_tracker[cache_key] = FALSE
/proc/do_after_once_checks(cache_key)
+2 -2
View File
@@ -1003,7 +1003,7 @@ About the new airlock wires panel:
"<span class='notice'>You begin [welded ? "unwelding":"welding"] the airlock...</span>", \
"<span class='italics'>You hear welding.</span>")
if(I.use_tool(src, user, 40, volume = I.tool_volume, extra_checks = CALLBACK(src, .proc/weld_checks, I, user)))
if(I.use_tool(src, user, 40, volume = I.tool_volume, extra_checks = list(CALLBACK(src, .proc/weld_checks, I, user))))
if(!density && !welded)
return
welded = !welded
@@ -1014,7 +1014,7 @@ About the new airlock wires panel:
user.visible_message("[user] is welding the airlock.", \
"<span class='notice'>You begin repairing the airlock...</span>", \
"<span class='italics'>You hear welding.</span>")
if(I.use_tool(src, user, 40, volume = I.tool_volume, extra_checks = CALLBACK(src, .proc/weld_checks, I, user)))
if(I.use_tool(src, user, 40, volume = I.tool_volume, extra_checks = list(CALLBACK(src, .proc/weld_checks, I, user))))
obj_integrity = max_integrity
stat &= ~BROKEN
user.visible_message("[user.name] has repaired [src].", \
@@ -16,11 +16,11 @@
var/datum/callback/tool_check = CALLBACK(src, .proc/tool_check_callback, user, target, amount, extra_checks)
if(ismob(target))
if(!do_mob(user, target, delay, extra_checks=tool_check))
if(!do_mob(user, target, delay, extra_checks = list(tool_check)))
return
else
if(!do_after(user, delay, target=target, extra_checks=tool_check))
if(!do_after(user, delay, target=target, extra_checks = list(tool_check)))
return
else
// Invoke the extra checks once, just in case.
+5 -5
View File
@@ -254,7 +254,7 @@ GLOBAL_LIST_INIT(wcCommon, pick(list("#379963", "#0d8395", "#58b5c3", "#49e46e",
if(!can_be_reached(user))
return
to_chat(user, "<span class='notice'>You begin to lever the window [state == WINDOW_OUT_OF_FRAME ? "into":"out of"] the frame...</span>")
if(!I.use_tool(src, user, decon_speed, volume = I.tool_volume, extra_checks = CALLBACK(src, .proc/check_state_and_anchored, state, anchored)))
if(!I.use_tool(src, user, decon_speed, volume = I.tool_volume, extra_checks = list(CALLBACK(src, .proc/check_state_and_anchored, state, anchored))))
return
state = (state == WINDOW_OUT_OF_FRAME ? WINDOW_IN_FRAME : WINDOW_OUT_OF_FRAME)
to_chat(user, "<span class='notice'>You pry the window [state == WINDOW_IN_FRAME ? "into":"out of"] the frame.</span>")
@@ -268,20 +268,20 @@ GLOBAL_LIST_INIT(wcCommon, pick(list("#379963", "#0d8395", "#58b5c3", "#49e46e",
if(reinf)
if(state == WINDOW_SCREWED_TO_FRAME || state == WINDOW_IN_FRAME)
to_chat(user, "<span class='notice'>You begin to [state == WINDOW_SCREWED_TO_FRAME ? "unscrew the window from":"screw the window to"] the frame...</span>")
if(!I.use_tool(src, user, decon_speed, volume = I.tool_volume, extra_checks = CALLBACK(src, .proc/check_state_and_anchored, state, anchored)))
if(!I.use_tool(src, user, decon_speed, volume = I.tool_volume, extra_checks = list(CALLBACK(src, .proc/check_state_and_anchored, state, anchored))))
return
state = (state == WINDOW_IN_FRAME ? WINDOW_SCREWED_TO_FRAME : WINDOW_IN_FRAME)
to_chat(user, "<span class='notice'>You [state == WINDOW_IN_FRAME ? "unfasten the window from":"fasten the window to"] the frame.</span>")
else if(state == WINDOW_OUT_OF_FRAME)
to_chat(user, "<span class='notice'>You begin to [anchored ? "unscrew the frame from":"screw the frame to"] the floor...</span>")
if(!I.use_tool(src, user, decon_speed, volume = I.tool_volume, extra_checks = CALLBACK(src, .proc/check_state_and_anchored, state, anchored)))
if(!I.use_tool(src, user, decon_speed, volume = I.tool_volume, extra_checks = list(CALLBACK(src, .proc/check_state_and_anchored, state, anchored))))
return
anchored = !anchored
update_nearby_icons()
to_chat(user, "<span class='notice'>You [anchored ? "fasten the frame to":"unfasten the frame from"] the floor.</span>")
else //if we're not reinforced, we don't need to check or update state
to_chat(user, "<span class='notice'>You begin to [anchored ? "unscrew the window from":"screw the window to"] the floor...</span>")
if(!I.use_tool(src, user, decon_speed, volume = I.tool_volume, extra_checks = CALLBACK(src, .proc/check_anchored, anchored)))
if(!I.use_tool(src, user, decon_speed, volume = I.tool_volume, extra_checks = list(CALLBACK(src, .proc/check_anchored, anchored))))
return
anchored = !anchored
air_update_turf(TRUE)
@@ -297,7 +297,7 @@ GLOBAL_LIST_INIT(wcCommon, pick(list("#379963", "#0d8395", "#58b5c3", "#49e46e",
if(!can_be_reached(user))
return
TOOL_ATTEMPT_DISMANTLE_MESSAGE
if(!I.use_tool(src, user, decon_speed, volume = I.tool_volume, extra_checks = CALLBACK(src, .proc/check_state_and_anchored, state, anchored)))
if(!I.use_tool(src, user, decon_speed, volume = I.tool_volume, extra_checks = list(CALLBACK(src, .proc/check_state_and_anchored, state, anchored))))
return
var/obj/item/stack/sheet/G = new glass_type(user.loc, glass_amount)
G.add_fingerprint(user)
@@ -146,11 +146,13 @@
return
var/limb_select = input(H, "Choose a limb to regrow", "Limb Regrowth") as null|anything in missing_limbs
if(!limb_select) // If the user hit cancel on the popup, return
return
var/chosen_limb = missing_limbs[limb_select]
H.visible_message("<span class='notice'>[H] begins to hold still and concentrate on [H.p_their()] missing [limb_select]...</span>", "<span class='notice'>You begin to focus on regrowing your missing [limb_select]... (This will take [round(SLIMEPERSON_REGROWTHDELAY/10)] seconds, and you must hold still.)</span>")
if(do_after(H, SLIMEPERSON_REGROWTHDELAY, needhand = 0, target = H))
if(H.incapacitated())
if(do_after(H, SLIMEPERSON_REGROWTHDELAY, FALSE, H, extra_checks = list(CALLBACK(H, /mob.proc/IsStunned)), use_default_checks = FALSE)) // Override the check for weakness, only check for stunned
if(H.incapacitated(ignore_lying = TRUE, extra_checks = list(CALLBACK(H, /mob.proc/IsStunned)), use_default_checks = FALSE)) // Override the check for weakness, only check for stunned
to_chat(H, "<span class='warning'>You cannot regenerate missing limbs in your current state.</span>")
return
@@ -196,4 +198,4 @@
#undef SLIMEPERSON_HUNGERCOST
#undef SLIMEPERSON_MINHUNGER
#undef SLIMEPERSON_REGROWTHDELAY
#undef SLIMEPERSON_REGROWTHDELAY
+8 -2
View File
@@ -65,8 +65,14 @@
return !(IsWeakened() || paralysis || stat || (status_flags & FAKEDEATH))
// Whether the mob is capable of actions or not
/mob/living/incapacitated(ignore_restraints = FALSE, ignore_grab = FALSE, ignore_lying = FALSE)
if(stat || paralysis || stunned || IsWeakened() || (!ignore_restraints && restrained()) || (!ignore_lying && lying))
/mob/living/incapacitated(ignore_restraints = FALSE, ignore_grab = FALSE, ignore_lying = FALSE, list/extra_checks = list(), use_default_checks = TRUE)
// By default, checks for weakness and stunned get added to the extra_checks list.
// Setting `use_default_checks` to FALSE means that you don't want it checking for these statuses or you are supplying your own checks.
if(use_default_checks)
extra_checks += CALLBACK(src, /mob.proc/IsWeakened)
extra_checks += CALLBACK(src, /mob.proc/IsStunned)
if(stat || paralysis || (!ignore_restraints && restrained()) || (!ignore_lying && lying) || check_for_true_callbacks(extra_checks))
return TRUE
// wonderful proc names, I know - used to check whether the blur overlay
+3
View File
@@ -173,6 +173,9 @@
/mob/proc/Stun()
return
/mob/proc/IsStunned()
return stunned
/mob/proc/SetStunned()
return