diff --git a/code/__defines/mobs.dm b/code/__defines/mobs.dm
index 548cabd73c..c7b1c0eb80 100644
--- a/code/__defines/mobs.dm
+++ b/code/__defines/mobs.dm
@@ -14,6 +14,7 @@
#define GODMODE 0x1000
#define FAKEDEATH 0x2000 // Replaces stuff like changeling.changeling_fakedeath.
#define DISFIGURED 0x4000 // Set but never checked. Remove this sometime and replace occurences with the appropriate organ code
+#define DOING_TASK 0x8000 // Performing a do_after or do_mob that's exclusive
// Grab levels.
#define GRAB_PASSIVE 1
diff --git a/code/_helpers/mobs.dm b/code/_helpers/mobs.dm
index 04b8ede203..73ae811193 100644
--- a/code/_helpers/mobs.dm
+++ b/code/_helpers/mobs.dm
@@ -142,9 +142,14 @@ Proc for attack log creation, because really why not
else
return pick("chest", "groin")
-/proc/do_mob(mob/user , mob/target, time = 30, target_zone = 0, uninterruptible = FALSE, progress = TRUE, ignore_movement = FALSE)
+/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
+ if(!time)
+ return 1 //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
var/user_loc = user.loc
var/target_loc = target.loc
@@ -155,6 +160,10 @@ Proc for attack log creation, because really why not
var/endtime = world.time+time
var/starttime = world.time
+
+ if(exclusive)
+ user.status_flags |= DOING_TASK
+
. = TRUE
while (world.time < endtime)
stoplag(1)
@@ -186,14 +195,20 @@ Proc for attack log creation, because really why not
. = FALSE
break
+ if(exclusive)
+ user.status_flags &= ~DOING_TASK
+
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)
+/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
if(!delay)
return 1 //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
var/atom/target_loc = null
if(target)
target_loc = target.loc
@@ -214,6 +229,10 @@ Proc for attack log creation, because really why not
var/endtime = world.time + delay
var/starttime = world.time
+
+ if(exclusive)
+ user.status_flags |= DOING_TASK
+
. = 1
while (world.time < endtime)
stoplag(1)
@@ -250,6 +269,9 @@ Proc for attack log creation, because really why not
. = FALSE
break
+ if(exclusive)
+ user.status_flags &= ~DOING_TASK
+
if(progbar)
qdel(progbar)
diff --git a/code/datums/progressbar.dm b/code/datums/progressbar.dm
index 01e4119b55..af200c14f1 100644
--- a/code/datums/progressbar.dm
+++ b/code/datums/progressbar.dm
@@ -1,46 +1,70 @@
+#define PROGRESSBAR_HEIGHT 6
+
/datum/progressbar
var/goal = 1
var/image/bar
var/shown = 0
var/mob/user
var/client/client
+ var/listindex
-/datum/progressbar/New(mob/user, goal_number, atom/target)
+/datum/progressbar/New(mob/User, goal_number, atom/target)
. = ..()
- if(!target) target = user
- if (!istype(target))
- EXCEPTION("Invalid target given")
- if (goal_number)
+ if(!istype(target))
+ target = User
+ if(goal_number)
goal = goal_number
- bar = image('icons/effects/progessbar.dmi', target, "prog_bar_0")
- bar.appearance_flags = APPEARANCE_UI_IGNORE_ALPHA
- bar.pixel_y = 32
+ bar = image('icons/effects/progressbar.dmi', target, "prog_bar_0")
+ bar.alpha = 0
bar.plane = PLANE_PLAYER_HUD
- src.user = user
+ bar.appearance_flags = APPEARANCE_UI_IGNORE_ALPHA
+ user = User
if(user)
client = user.client
-/datum/progressbar/Destroy()
- if (client)
- client.images -= bar
- QDEL_NULL(bar)
- user = null
- client = null
- return ..()
+ LAZYINITLIST(user.progressbars)
+ LAZYINITLIST(user.progressbars[bar.loc])
+ var/list/bars = user.progressbars[bar.loc]
+ bars.Add(src)
+ listindex = bars.len
+ animate(bar, pixel_y = 32 + (PROGRESSBAR_HEIGHT * (listindex - 1)), alpha = 255, time = 5, easing = SINE_EASING)
/datum/progressbar/proc/update(progress)
- //to_world("Update [progress] - [goal] - [(progress / goal)] - [((progress / goal) * 100)] - [round(((progress / goal) * 100), 5)]")
- if (!user || !user.client)
+ if(!user || !user.client)
shown = 0
return
- if (user.client != client)
- if (client)
+ if(user.client != client)
+ if(client)
client.images -= bar
- shown = 0
- client = user.client
+ if(user.client)
+ user.client.images += bar
- progress = CLAMP(progress, 0, goal)
+ progress = clamp(progress, 0, goal)
bar.icon_state = "prog_bar_[round(((progress / goal) * 100), 5)]"
- if (!shown && user.is_preference_enabled(/datum/client_preference/show_progress_bar))
+ if(!shown && user.is_preference_enabled(/datum/client_preference/show_progress_bar))
user.client.images += bar
shown = 1
+
+/datum/progressbar/proc/shiftDown()
+ --listindex
+ var/shiftheight = bar.pixel_y - PROGRESSBAR_HEIGHT
+ animate(bar, pixel_y = shiftheight, time = 5, easing = SINE_EASING)
+
+/datum/progressbar/Destroy()
+ for(var/I in user.progressbars[bar.loc])
+ var/datum/progressbar/P = I
+ if(P != src && P.listindex > listindex)
+ P.shiftDown()
+
+ var/list/bars = user.progressbars[bar.loc]
+ bars.Remove(src)
+ if(!bars.len)
+ LAZYREMOVE(user.progressbars, bar.loc)
+ animate(bar, alpha = 0, time = 5)
+ spawn(5)
+ if(client)
+ client.images -= bar
+ qdel(bar)
+ . = ..()
+
+#undef PROGRESSBAR_HEIGHT
\ No newline at end of file
diff --git a/code/game/objects/items/stacks/medical.dm b/code/game/objects/items/stacks/medical.dm
index 8887dd0053..20f098e5d1 100644
--- a/code/game/objects/items/stacks/medical.dm
+++ b/code/game/objects/items/stacks/medical.dm
@@ -111,7 +111,7 @@
continue
if(used == amount)
break
- if(!do_mob(user, M, W.damage/3))
+ if(!do_mob(user, M, W.damage/3, exclusive = TRUE))
to_chat(user, "You must stand still to bandage wounds.")
break
@@ -174,7 +174,7 @@
continue
if(used == amount)
break
- if(!do_mob(user, M, W.damage/5))
+ if(!do_mob(user, M, W.damage/5, exclusive = TRUE))
to_chat(user, "You must stand still to bandage wounds.")
break
@@ -234,7 +234,7 @@
else
user.visible_message("\The [user] starts salving wounds on [M]'s [affecting.name].", \
"You start salving the wounds on [M]'s [affecting.name]." )
- if(!do_mob(user, M, 10))
+ if(!do_mob(user, M, 10, exclusive = TRUE))
to_chat(user, "You must stand still to salve wounds.")
return 1
if(affecting.is_salved()) // We do a second check after the delay, in case it was bandaged after the first check.
@@ -281,7 +281,7 @@
continue
//if(used == amount) //VOREStation Edit
// break //VOREStation Edit
- if(!do_mob(user, M, W.damage/5))
+ if(!do_mob(user, M, W.damage/5, exclusive = TRUE))
to_chat(user, "You must stand still to bandage wounds.")
break
if(affecting.is_bandaged() && affecting.is_disinfected()) // We do a second check after the delay, in case it was bandaged after the first check.
@@ -336,7 +336,7 @@
else
user.visible_message("\The [user] starts salving wounds on [M]'s [affecting.name].", \
"You start salving the wounds on [M]'s [affecting.name]." )
- if(!do_mob(user, M, 10))
+ if(!do_mob(user, M, 10, exclusive = TRUE))
to_chat(user, "You must stand still to salve wounds.")
return 1
if(affecting.is_salved()) // We do a second check after the delay, in case it was bandaged after the first check.
@@ -383,7 +383,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))
+ if(do_after(user, 50, M, exclusive = TRUE))
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 bc1f6486c1..3d5aeffa3d 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))
+ if(do_after(user, 7 * toolspeed, exclusive = TRUE))
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))
+ if(do_after(user, 5 * toolspeed, exclusive = TRUE))
S.heal_damage(restoration_internal, restoration_internal, robo_repair = 1)
- else if(do_after(user,5 * toolspeed))
+ else if(do_after(user, 5 * toolspeed, exclusive = TRUE))
S.heal_damage(restoration_external,restoration_external, robo_repair =1)
H.updatehealth()
use(1)
diff --git a/code/game/objects/items/stacks/stack.dm b/code/game/objects/items/stacks/stack.dm
index 2a25635315..1aa69305f5 100644
--- a/code/game/objects/items/stacks/stack.dm
+++ b/code/game/objects/items/stacks/stack.dm
@@ -145,7 +145,7 @@
if (recipe.time)
to_chat(user, "Building [recipe.title] ...")
- if (!do_after(user, recipe.time))
+ if (!do_after(user, recipe.time, exclusive = TRUE))
return
if (use(required))
diff --git a/code/modules/mob/mob_defines.dm b/code/modules/mob/mob_defines.dm
index 9091e338ab..111bcab799 100644
--- a/code/modules/mob/mob_defines.dm
+++ b/code/modules/mob/mob_defines.dm
@@ -230,3 +230,5 @@
var/attack_icon_state //State for above
var/registered_z
+
+ var/list/progressbars = null //for stacking do_after bars
\ No newline at end of file
diff --git a/code/modules/surgery/surgery.dm b/code/modules/surgery/surgery.dm
index 03fb7ad40f..e6e4554090 100644
--- a/code/modules/surgery/surgery.dm
+++ b/code/modules/surgery/surgery.dm
@@ -162,7 +162,7 @@
// Not staying still fails you too.
if(success)
var/calc_duration = rand(S.min_duration, S.max_duration)
- if(!do_mob(user, M, calc_duration * toolspeed, zone))
+ if(!do_mob(user, M, calc_duration * toolspeed, zone, exclusive = TRUE))
success = FALSE
to_chat(user, "You must remain close to and keep focused on your patient to conduct surgery.")
diff --git a/icons/effects/progessbar.dmi b/icons/effects/progressbar.dmi
similarity index 100%
rename from icons/effects/progessbar.dmi
rename to icons/effects/progressbar.dmi