diff --git a/code/__defines/flags.dm b/code/__defines/flags.dm
index 8ac15ebc53..0d06544a7e 100644
--- a/code/__defines/flags.dm
+++ b/code/__defines/flags.dm
@@ -34,6 +34,7 @@ GLOBAL_LIST_INIT(bitflags, list(1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 204
#define PHORONGUARD (1<<5) // Does not get contaminated by phoron.
#define NOREACT (1<<6) // Reagents don't react inside this container.
#define OVERLAY_QUEUED (1<<7)// Atom queued to SSoverlay for COMPILE_OVERLAYS
+#define IS_BUSY (1<<8) // Atom has a TASK_TARGET_EXCLUSIVE do_after with it as the target.
//Flags for items (equipment) - Used in /obj/item/var/item_flags
#define THICKMATERIAL (1<<0) // Prevents syringes, parapens and hyposprays if equipped to slot_suit or slot_head.
@@ -49,3 +50,8 @@ GLOBAL_LIST_INIT(bitflags, list(1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 204
#define PASSGRILLE (1<<2)
#define PASSBLOB (1<<3)
#define PASSMOB (1<<4)
+
+// Flags for do_after/do_mob exclusivity.
+#define TASK_TARGET_EXCLUSIVE (1<<1)
+#define TASK_USER_EXCLUSIVE (1<<2)
+#define TASK_ALL_EXCLUSIVE TASK_TARGET_EXCLUSIVE | TASK_USER_EXCLUSIVE
\ No newline at end of file
diff --git a/code/_helpers/mobs.dm b/code/_helpers/mobs.dm
index dc5c92f708..c9b37eae95 100644
--- a/code/_helpers/mobs.dm
+++ b/code/_helpers/mobs.dm
@@ -155,12 +155,15 @@ Proc for attack log creation, because really why not
/proc/do_mob(mob/user , mob/target, time = 30, target_zone = 0, uninterruptible = FALSE, progress = TRUE, ignore_movement = FALSE, exclusive = FALSE)
if(!user || !target)
- return 0
+ return FALSE
if(!time)
- return 1 //Done!
+ return TRUE //Done!
if(user.status_flags & DOING_TASK)
to_chat(user, "You're in the middle of doing something else already.")
- return 0 //Performing an exclusive do_after or do_mob already
+ return FALSE //Performing an exclusive do_after or do_mob already
+ if(target?.flags & IS_BUSY)
+ to_chat(user, "Someone is already doing something with \the [target].")
+ return FALSE
var/user_loc = user.loc
var/target_loc = target.loc
@@ -172,8 +175,10 @@ Proc for attack log creation, because really why not
var/endtime = world.time+time
var/starttime = world.time
- if(exclusive)
+ if(exclusive & TASK_USER_EXCLUSIVE)
user.status_flags |= DOING_TASK
+ if(target && exclusive & TASK_TARGET_EXCLUSIVE)
+ target.flags |= IS_BUSY
. = TRUE
while (world.time < endtime)
@@ -206,20 +211,26 @@ Proc for attack log creation, because really why not
. = FALSE
break
- if(exclusive)
+ if(exclusive & TASK_USER_EXCLUSIVE)
user.status_flags &= ~DOING_TASK
+ if(exclusive & TASK_TARGET_EXCLUSIVE)
+ target?.status_flags &= ~IS_BUSY
if (progbar)
qdel(progbar)
/proc/do_after(mob/user, delay, atom/target = null, needhand = TRUE, progress = TRUE, incapacitation_flags = INCAPACITATION_DEFAULT, ignore_movement = FALSE, max_distance = null, exclusive = FALSE)
if(!user)
- return 0
+ return FALSE
if(!delay)
- return 1 //Okay. Done.
+ return TRUE //Okay. Done.
if(user.status_flags & DOING_TASK)
to_chat(user, "You're in the middle of doing something else already.")
- return 0 //Performing an exclusive do_after or do_mob already
+ return FALSE //Performing an exclusive do_after or do_mob already
+ if(target?.flags & IS_BUSY)
+ to_chat(user, "Someone is already doing something with \the [target].")
+ return FALSE
+
var/atom/target_loc = null
if(target)
target_loc = target.loc
@@ -241,10 +252,13 @@ Proc for attack log creation, because really why not
var/endtime = world.time + delay
var/starttime = world.time
- if(exclusive)
+ if(exclusive & TASK_USER_EXCLUSIVE)
user.status_flags |= DOING_TASK
+
+ if(target && exclusive & TASK_TARGET_EXCLUSIVE)
+ target.flags |= IS_BUSY
- . = 1
+ . = TRUE
while (world.time < endtime)
stoplag(1)
if(progress)
@@ -280,8 +294,10 @@ Proc for attack log creation, because really why not
. = FALSE
break
- if(exclusive)
+ if(exclusive & TASK_USER_EXCLUSIVE)
user.status_flags &= ~DOING_TASK
+ if(target & exclusive & TASK_TARGET_EXCLUSIVE)
+ target.flags &= ~IS_BUSY
if(progbar)
qdel(progbar)
diff --git a/code/game/objects/items/devices/denecrotizer_vr.dm b/code/game/objects/items/devices/denecrotizer_vr.dm
index 7305a49e53..72a2022089 100644
--- a/code/game/objects/items/devices/denecrotizer_vr.dm
+++ b/code/game/objects/items/devices/denecrotizer_vr.dm
@@ -145,7 +145,7 @@
return FALSE
if(!target.mind)
user.visible_message("[user] gently presses [src] to [target]...", runemessage = "presses [src] to [target]")
- if(do_after(user, revive_time, exclusive = 1, target = target))
+ if(do_after(user, revive_time, exclusive = TASK_USER_EXCLUSIVE, target = target))
target.faction = user.faction
target.revivedby = user.name
target.ghostjoin = 1
@@ -166,7 +166,7 @@
/obj/item/device/denecrotizer/proc/ghostjoin_rez(mob/living/simple_mob/target, mob/living/user)
user.visible_message("[user] gently presses [src] to [target]...", runemessage = "presses [src] to [target]")
- if(do_after(user, revive_time, exclusive = 1, target = target))
+ if(do_after(user, revive_time, exclusive = TASK_ALL_EXCLUSIVE, target = target))
target.faction = user.faction
target.revivedby = user.name
target.revive()
@@ -189,7 +189,7 @@
/obj/item/device/denecrotizer/proc/basic_rez(mob/living/simple_mob/target, mob/living/user) //so medical can have a way to bring back people's pets or whatever, does not change any settings about the mob or offer it to ghosts.
user.visible_message("[user] presses [src] to [target]...", runemessage = "presses [src] to [target]")
- if(do_after(user, revive_time, exclusive = 1, target = target))
+ if(do_after(user, revive_time, exclusive = TASK_ALL_EXCLUSIVE, target = target))
target.revive()
target.sight = initial(target.sight)
target.see_in_dark = initial(target.see_in_dark)
diff --git a/code/game/objects/items/stacks/medical.dm b/code/game/objects/items/stacks/medical.dm
index 629a383433..f065ec3ea1 100644
--- a/code/game/objects/items/stacks/medical.dm
+++ b/code/game/objects/items/stacks/medical.dm
@@ -408,7 +408,7 @@
to_chat(user, "You can't apply a splint to the arm you're using!")
return
user.visible_message("[user] starts to apply \the [src] to their [limb].", "You start to apply \the [src] to your [limb].", "You hear something being wrapped.")
- if(do_after(user, 50, M, exclusive = TRUE))
+ if(do_after(user, 50, M, exclusive = TASK_USER_EXCLUSIVE))
if(affecting.splinted)
to_chat(user, "[M]'s [limb] is already splinted!")
return
diff --git a/code/game/objects/items/stacks/nanopaste.dm b/code/game/objects/items/stacks/nanopaste.dm
index 10c85fa7e4..ba5db2b33b 100644
--- a/code/game/objects/items/stacks/nanopaste.dm
+++ b/code/game/objects/items/stacks/nanopaste.dm
@@ -16,7 +16,7 @@
if (istype(M,/mob/living/silicon/robot)) //Repairing cyborgs
var/mob/living/silicon/robot/R = M
if (R.getBruteLoss() || R.getFireLoss())
- if(do_after(user, 7 * toolspeed, exclusive = TRUE))
+ if(do_after(user, 7 * toolspeed, R, exclusive = TASK_ALL_EXCLUSIVE))
R.adjustBruteLoss(-15)
R.adjustFireLoss(-15)
R.updatehealth()
@@ -51,9 +51,9 @@
else if(can_use(1))
user.setClickCooldown(user.get_attack_speed(src))
if(S.open >= 2)
- if(do_after(user, 5 * toolspeed, exclusive = TRUE))
+ if(do_after(user, 5 * toolspeed, S, exclusive = TASK_ALL_EXCLUSIVE))
S.heal_damage(restoration_internal, restoration_internal, robo_repair = 1)
- else if(do_after(user, 5 * toolspeed, exclusive = TRUE))
+ else if(do_after(user, 5 * toolspeed, S, exclusive = TASK_ALL_EXCLUSIVE))
S.heal_damage(restoration_external,restoration_external, robo_repair =1)
H.updatehealth()
use(1)
diff --git a/code/game/objects/items/weapons/storage/pouches.dm b/code/game/objects/items/weapons/storage/pouches.dm
index 38d0660894..24a81f4112 100644
--- a/code/game/objects/items/weapons/storage/pouches.dm
+++ b/code/game/objects/items/weapons/storage/pouches.dm
@@ -23,7 +23,7 @@
if(user.get_active_hand() == src || user.get_inactive_hand() == src)
return TRUE // Skip delay
- if(insert_delay && !do_after(user, 2 SECONDS, src, needhand = TRUE, exclusive = TRUE))
+ if(insert_delay && !do_after(user, 2 SECONDS, src, needhand = TRUE, exclusive = TASK_USER_EXCLUSIVE))
return FALSE // Moved or whatever
if(W in src)
@@ -36,7 +36,7 @@
if(user.get_active_hand() == src || user.get_inactive_hand() == src)
return TRUE // Skip delay
- if(remove_delay && !do_after(user, 2 SECONDS, src, needhand = TRUE, exclusive = TRUE))
+ if(remove_delay && !do_after(user, 2 SECONDS, src, needhand = TRUE, exclusive = TASK_USER_EXCLUSIVE))
return FALSE // Moved or whatever
if(W in src)
diff --git a/code/game/objects/structures/door_assembly.dm b/code/game/objects/structures/door_assembly.dm
index 5a786cacd8..2b57235299 100644
--- a/code/game/objects/structures/door_assembly.dm
+++ b/code/game/objects/structures/door_assembly.dm
@@ -176,7 +176,7 @@
playsound(src, WT.usesound, 50, 1)
if(istext(glass))
user.visible_message("[user] welds the [glass] plating off the airlock assembly.", "You start to weld the [glass] plating off the airlock assembly.")
- if(do_after(user, 40 * WT.toolspeed))
+ if(do_after(user, 4 SECONDS * WT.toolspeed, src, exclusive = TASK_ALL_EXCLUSIVE))
if(!src || !WT.isOn()) return
to_chat(user, "You welded the [glass] plating off!")
var/M = text2path("/obj/item/stack/material/[glass]")
@@ -184,14 +184,14 @@
glass = 0
else if(glass == 1)
user.visible_message("[user] welds the glass panel out of the airlock assembly.", "You start to weld the glass panel out of the airlock assembly.")
- if(do_after(user, 40 * WT.toolspeed))
+ if(do_after(user, 4 SECONDS * WT.toolspeed, src, exclusive = TASK_ALL_EXCLUSIVE))
if(!src || !WT.isOn()) return
to_chat(user, "You welded the glass panel out!")
new /obj/item/stack/material/glass/reinforced(src.loc)
glass = 0
else if(!anchored)
user.visible_message("[user] dissassembles the airlock assembly.", "You start to dissassemble the airlock assembly.")
- if(do_after(user, 40 * WT.toolspeed))
+ if(do_after(user, 4 SECONDS * WT.toolspeed, src, exclusive = TASK_ALL_EXCLUSIVE))
if(!src || !WT.isOn()) return
to_chat(user, "You dissasembled the airlock assembly!")
new /obj/item/stack/material/steel(src.loc, 4)
@@ -207,7 +207,7 @@
else
user.visible_message("[user] begins securing the airlock assembly to the floor.", "You starts securing the airlock assembly to the floor.")
- if(do_after(user, 40 * W.toolspeed))
+ if(do_after(user, 4 SECONDS * W.toolspeed, src, exclusive = TASK_ALL_EXCLUSIVE))
if(!src) return
to_chat(user, "You [anchored? "un" : ""]secured the airlock assembly!")
anchored = !anchored
@@ -218,7 +218,7 @@
to_chat(user, "You need one length of coil to wire the airlock assembly.")
return
user.visible_message("[user] wires the airlock assembly.", "You start to wire the airlock assembly.")
- if(do_after(user, 40) && state == 0 && anchored)
+ if(do_after(user, 4 SECONDS, src, exclusive = TASK_ALL_EXCLUSIVE) && state == 0 && anchored)
if (C.use(1))
src.state = 1
to_chat(user, "You wire the airlock.")
@@ -227,7 +227,7 @@
playsound(src, W.usesound, 100, 1)
user.visible_message("[user] cuts the wires from the airlock assembly.", "You start to cut the wires from airlock assembly.")
- if(do_after(user, 40 * W.toolspeed))
+ if(do_after(user, 4 SECONDS * W.toolspeed, src, exclusive = TASK_ALL_EXCLUSIVE))
if(!src) return
to_chat(user, "You cut the airlock wires.!")
new/obj/item/stack/cable_coil(src.loc, 1)
@@ -237,7 +237,7 @@
playsound(src, W.usesound, 100, 1)
user.visible_message("[user] installs the electronics into the airlock assembly.", "You start to install electronics into the airlock assembly.")
- if(do_after(user, 40))
+ if(do_after(user, 4 SECONDS, src, exclusive = TASK_ALL_EXCLUSIVE))
if(!src) return
user.drop_item()
W.loc = src
@@ -255,7 +255,7 @@
playsound(src, W.usesound, 100, 1)
user.visible_message("\The [user] starts removing the electronics from the airlock assembly.", "You start removing the electronics from the airlock assembly.")
- if(do_after(user, 40 * W.toolspeed))
+ if(do_after(user, 4 SECONDS * W.toolspeed, src, exclusive = TASK_ALL_EXCLUSIVE))
if(!src) return
to_chat(user, "You removed the airlock electronics!")
src.state = 1
@@ -270,7 +270,7 @@
if(material_name == "rglass")
playsound(src, 'sound/items/Crowbar.ogg', 100, 1)
user.visible_message("[user] adds [S.name] to the airlock assembly.", "You start to install [S.name] into the airlock assembly.")
- if(do_after(user, 40) && !glass)
+ if(do_after(user, 4 SECONDS, src, exclusive = TASK_ALL_EXCLUSIVE) && !glass)
if (S.use(1))
to_chat(user, "You installed reinforced glass windows into the airlock assembly.")
glass = 1
@@ -282,7 +282,7 @@
if(S.get_amount() >= 2)
playsound(src, 'sound/items/Crowbar.ogg', 100, 1)
user.visible_message("[user] adds [S.name] to the airlock assembly.", "You start to install [S.name] into the airlock assembly.")
- if(do_after(user, 40) && !glass)
+ if(do_after(user, 4 SECONDS, src, exclusive = TASK_ALL_EXCLUSIVE) && !glass)
if (S.use(2))
to_chat(user, "You installed [material_display_name(material_name)] plating into the airlock assembly.")
glass = material_name
@@ -291,7 +291,7 @@
playsound(src, W.usesound, 100, 1)
to_chat(user, "Now finishing the airlock.")
- if(do_after(user, 40 * W.toolspeed))
+ if(do_after(user, 4 SECONDS * W.toolspeed, src, exclusive = TASK_ALL_EXCLUSIVE))
if(!src) return
to_chat(user, "You finish the airlock!")
var/path
diff --git a/code/modules/mob/living/carbon/human/species/station/station_special_abilities_vr.dm b/code/modules/mob/living/carbon/human/species/station/station_special_abilities_vr.dm
index 9150ce1877..3f5bb51148 100644
--- a/code/modules/mob/living/carbon/human/species/station/station_special_abilities_vr.dm
+++ b/code/modules/mob/living/carbon/human/species/station/station_special_abilities_vr.dm
@@ -910,7 +910,7 @@
to_chat(src, "You can't weave here!")
return
- if(do_after(src, desired_result.time, exclusive = TRUE))
+ if(do_after(src, desired_result.time, exclusive = TASK_USER_EXCLUSIVE))
if(desired_result.cost > species.silk_reserve)
to_chat(src, "You don't have enough silk to weave that!")
return
@@ -969,7 +969,7 @@
to_chat(src, "You can't weave here!")
return
- if(do_after(src, desired_result.time, exclusive = TRUE))
+ if(do_after(src, desired_result.time, exclusive = TASK_USER_EXCLUSIVE))
if(desired_result.cost > species.silk_reserve)
to_chat(src, "You don't have enough silk to weave that!")
return
diff --git a/code/modules/mob/living/simple_mob/subtypes/vore/softdog.dm b/code/modules/mob/living/simple_mob/subtypes/vore/softdog.dm
index cc2cc62e5b..e6c9ff410b 100644
--- a/code/modules/mob/living/simple_mob/subtypes/vore/softdog.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/vore/softdog.dm
@@ -254,7 +254,7 @@
return ..()
if(M.a_intent == I_HELP)
M.visible_message("[M] pets [src].", runemessage = "pets [src]")
- if(do_after(M, 30 SECONDS, exclusive = 1, target = src))
+ if(do_after(M, 30 SECONDS, exclusive = TASK_USER_EXCLUSIVE, target = src))
faction = M.faction
revive()
sight = initial(sight)
diff --git a/code/modules/vore/eating/living_vr.dm b/code/modules/vore/eating/living_vr.dm
index 503f76d566..30ba2bc199 100644
--- a/code/modules/vore/eating/living_vr.dm
+++ b/code/modules/vore/eating/living_vr.dm
@@ -546,7 +546,7 @@
prey.ai_holder?.react_to_attack(user)
//Timer and progress bar
- if(!do_after(user, swallow_time, prey, exclusive = TRUE))
+ if(!do_after(user, swallow_time, prey, exclusive = TASK_USER_EXCLUSIVE))
return FALSE // Prey escpaed (or user disabled) before timer expired.
// If we got this far, nom successful! Announce it!
@@ -832,7 +832,7 @@
playsound(src, 'sound/items/eatfood.ogg', rand(10,50), 1)
var/T = (istype(M) ? M.hardness/40 : 1) SECONDS //1.5 seconds to eat a sheet of metal. 2.5 for durasteel and diamond & 1 by default (applies to some ores like raw carbon, slag, etc.
to_chat(src, "You start crunching on [I] with your powerful jaws, attempting to tear it apart...")
- if(do_after(feeder, T, ignore_movement = TRUE, exclusive = TRUE)) //Eat on the move, but not multiple things at once.
+ if(do_after(feeder, T, ignore_movement = TRUE, exclusive = TASK_ALL_EXCLUSIVE)) //Eat on the move, but not multiple things at once.
if(feeder != src)
to_chat(feeder, "You feed [I] to [src].")
log_admin("VORE: [feeder] fed [src] [I].")