diff --git a/code/__HELPERS/mobs.dm b/code/__HELPERS/mobs.dm index 6be2b411376..ff127fd3a48 100644 --- a/code/__HELPERS/mobs.dm +++ b/code/__HELPERS/mobs.dm @@ -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, "[attempt_cancel_message]") 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) diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm index bf83e6c5d49..692024899a2 100644 --- a/code/game/machinery/doors/airlock.dm +++ b/code/game/machinery/doors/airlock.dm @@ -1003,7 +1003,7 @@ About the new airlock wires panel: "You begin [welded ? "unwelding":"welding"] the airlock...", \ "You hear welding.") - 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.", \ "You begin repairing the airlock...", \ "You hear welding.") - 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].", \ diff --git a/code/game/objects/items/tools/tool_behaviour.dm b/code/game/objects/items/tools/tool_behaviour.dm index c937f80c30d..80b00dcd1ed 100644 --- a/code/game/objects/items/tools/tool_behaviour.dm +++ b/code/game/objects/items/tools/tool_behaviour.dm @@ -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. diff --git a/code/game/objects/structures/window.dm b/code/game/objects/structures/window.dm index 9faab45cf97..8fe46ca052d 100644 --- a/code/game/objects/structures/window.dm +++ b/code/game/objects/structures/window.dm @@ -254,7 +254,7 @@ GLOBAL_LIST_INIT(wcCommon, pick(list("#379963", "#0d8395", "#58b5c3", "#49e46e", if(!can_be_reached(user)) return to_chat(user, "You begin to lever the window [state == WINDOW_OUT_OF_FRAME ? "into":"out of"] the frame...") - 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, "You pry the window [state == WINDOW_IN_FRAME ? "into":"out of"] the frame.") @@ -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, "You begin to [state == WINDOW_SCREWED_TO_FRAME ? "unscrew the window from":"screw the window to"] the frame...") - 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, "You [state == WINDOW_IN_FRAME ? "unfasten the window from":"fasten the window to"] the frame.") else if(state == WINDOW_OUT_OF_FRAME) to_chat(user, "You begin to [anchored ? "unscrew the frame from":"screw the frame to"] the floor...") - 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, "You [anchored ? "fasten the frame to":"unfasten the frame from"] the floor.") else //if we're not reinforced, we don't need to check or update state to_chat(user, "You begin to [anchored ? "unscrew the window from":"screw the window to"] the floor...") - 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) diff --git a/code/modules/mob/living/carbon/human/species/slime.dm b/code/modules/mob/living/carbon/human/species/slime.dm index d9fa1ccbf3c..622e0919b45 100644 --- a/code/modules/mob/living/carbon/human/species/slime.dm +++ b/code/modules/mob/living/carbon/human/species/slime.dm @@ -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("[H] begins to hold still and concentrate on [H.p_their()] missing [limb_select]...", "You begin to focus on regrowing your missing [limb_select]... (This will take [round(SLIMEPERSON_REGROWTHDELAY/10)] seconds, and you must hold still.)") - 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, "You cannot regenerate missing limbs in your current state.") return @@ -196,4 +198,4 @@ #undef SLIMEPERSON_HUNGERCOST #undef SLIMEPERSON_MINHUNGER -#undef SLIMEPERSON_REGROWTHDELAY +#undef SLIMEPERSON_REGROWTHDELAY \ No newline at end of file diff --git a/code/modules/mob/living/update_status.dm b/code/modules/mob/living/update_status.dm index 20cc969119f..d24301b0dd0 100644 --- a/code/modules/mob/living/update_status.dm +++ b/code/modules/mob/living/update_status.dm @@ -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 diff --git a/code/modules/mob/status_procs.dm b/code/modules/mob/status_procs.dm index 0aeb9beef84..b61ce171194 100644 --- a/code/modules/mob/status_procs.dm +++ b/code/modules/mob/status_procs.dm @@ -173,6 +173,9 @@ /mob/proc/Stun() return +/mob/proc/IsStunned() + return stunned + /mob/proc/SetStunned() return