diff --git a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_carbon.dm b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_carbon.dm index 2428eddf1346..b28463f50ec6 100644 --- a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_carbon.dm +++ b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_carbon.dm @@ -1,3 +1,6 @@ +/// from base of [/mob/living/changeNext_Move()] (next_move) +#define COMSIG_LIVING_CHANGENEXT_MOVE "living_changenext_move" + ///Called from /mob/living/carbon/help_shake_act, before any hugs have ocurred. (mob/living/helper) #define COMSIG_CARBON_PRE_HELP_ACT "carbon_pre_help" /// Stops the rest of help act (hugging, etc) from occuring diff --git a/code/_onclick/click.dm b/code/_onclick/click.dm index a6f81d8ca4f1..3d3777521f26 100644 --- a/code/_onclick/click.dm +++ b/code/_onclick/click.dm @@ -29,6 +29,8 @@ adj += S.nextmove_adjust() next_move = world.time + ((num + adj)*mod) + SEND_SIGNAL(src, COMSIG_LIVING_CHANGENEXT_MOVE, next_move) + /** * Before anything else, defer these calls to a per-mobtype handler. This allows us to * remove istype() spaghetti code, but requires the addition of other handler procs to simplify it. diff --git a/code/_onclick/hud/hud.dm b/code/_onclick/hud/hud.dm index 1e59295205eb..6a9e50474bfa 100644 --- a/code/_onclick/hud/hud.dm +++ b/code/_onclick/hud/hud.dm @@ -60,6 +60,8 @@ GLOBAL_LIST_INIT(available_ui_styles, list( var/atom/movable/screen/healths var/atom/movable/screen/healthdoll var/atom/movable/screen/internals + + var/atom/movable/screen/progbar_container/use_timer // subtypes can override this to force a specific UI style var/ui_style @@ -119,6 +121,7 @@ GLOBAL_LIST_INIT(available_ui_styles, list( QDEL_LIST(screenoverlays) mymob = null QDEL_NULL(screentip_text) + QDEL_NULL(use_timer) return ..() diff --git a/code/_onclick/hud/human.dm b/code/_onclick/hud/human.dm index 0833d606927f..4786a803486b 100644 --- a/code/_onclick/hud/human.dm +++ b/code/_onclick/hud/human.dm @@ -354,6 +354,10 @@ ammo_counter = new /atom/movable/screen/ammo_counter(null, src) infodisplay += ammo_counter + use_timer = new(null, src) + use_timer.RegisterSignal(mymob, COMSIG_LIVING_CHANGENEXT_MOVE, TYPE_PROC_REF(/atom/movable/screen/progbar_container, on_changenext)) + static_inventory += use_timer + for(var/atom/movable/screen/inventory/inv in (static_inventory + toggleable_inventory)) if(inv.slot_id) inv.hud = src diff --git a/code/_onclick/hud/screen_objects.dm b/code/_onclick/hud/screen_objects.dm index bf171d339912..bd1240762039 100644 --- a/code/_onclick/hud/screen_objects.dm +++ b/code/_onclick/hud/screen_objects.dm @@ -717,3 +717,42 @@ intent_icon.pixel_x = 16 * (i - 1) - 8 * length(streak) add_overlay(intent_icon) return ..() + +/atom/movable/screen/progbar_container + name = "swing cooldown" + icon_state = "" + screen_loc = "CENTER,SOUTH:16" + var/datum/world_progressbar/progbar + var/iteration = 0 + +/atom/movable/screen/progbar_container/Initialize(mapload) + . = ..() + progbar = new(src) + progbar.qdel_when_done = FALSE + progbar.bar.vis_flags = VIS_INHERIT_ID | VIS_INHERIT_LAYER | VIS_INHERIT_PLANE + progbar.bar.appearance_flags = APPEARANCE_UI + +/atom/movable/screen/progbar_container/Destroy() + QDEL_NULL(progbar) + return ..() + +/atom/movable/screen/progbar_container/proc/on_changenext(datum/source, next_move) + SIGNAL_HANDLER + + iteration++ + progbar.goal = next_move - world.time + progbar.bar.icon_state = "prog_bar_0" + + progbar_process(next_move) + +/atom/movable/screen/progbar_container/proc/progbar_process(next_move) + set waitfor = FALSE + + var/start_time = world.time + var/iteration = src.iteration + while(iteration == src.iteration && (world.time < next_move)) + progbar.update(world.time - start_time) + sleep(1) + + if(iteration == src.iteration) + progbar.end_progress() diff --git a/code/datums/progressbar.dm b/code/datums/progressbar.dm index 7134d2e8ecef..568c5742bfbe 100644 --- a/code/datums/progressbar.dm +++ b/code/datums/progressbar.dm @@ -136,5 +136,84 @@ QDEL_IN(src, PROGRESSBAR_ANIMATION_TIME) + +/datum/world_progressbar + ///The progress bar visual element. + var/obj/effect/abstract/progbar/bar + ///The atom who "created" the bar + var/atom/movable/owner + ///Effectively the number of steps the progress bar will need to do before reaching completion. + var/goal = 1 + ///Control check to see if the progress was interrupted before reaching its goal. + var/last_progress = 0 + ///Variable to ensure smooth visual stacking on multiple progress bars. + var/listindex = 0 + ///Does this qdelete on completion? + var/qdel_when_done = TRUE + +/datum/world_progressbar/New(atom/movable/_owner, _goal, image/underlay) + if(!_owner) + return + + owner = _owner + goal = _goal + + bar = new() + + if(underlay) + if(!istype(underlay)) + underlay = image(underlay, dir = SOUTH) + underlay.filters += filter(type = "outline", size = 1) + + underlay.pixel_y += 2 + underlay.alpha = 200 + underlay.plane = GAME_PLANE + underlay.layer = FLY_LAYER + underlay.appearance_flags = APPEARANCE_UI + bar.underlays += underlay + + owner:vis_contents += bar + + animate(bar, alpha = 255, time = PROGRESSBAR_ANIMATION_TIME, easing = SINE_EASING) + + RegisterSignal(owner, COMSIG_PARENT_QDELETING, PROC_REF(owner_delete)) + +/datum/world_progressbar/Destroy() + owner = null + QDEL_NULL(bar) + return ..() + + +/datum/world_progressbar/proc/owner_delete() + qdel(src) + +///Updates the progress bar image visually. +/datum/world_progressbar/proc/update(progress) + progress = clamp(progress, 0, goal) + if(progress == last_progress) + return + last_progress = progress + bar.icon_state = "prog_bar_[round(((progress / goal) * 100), 5)]" + +/datum/world_progressbar/proc/end_progress() + if(last_progress != goal) + bar.icon_state = "[bar.icon_state]_fail" + + if(qdel_when_done) + animate(bar, alpha = 0, time = PROGRESSBAR_ANIMATION_TIME) + QDEL_IN(src, PROGRESSBAR_ANIMATION_TIME) + else + bar.icon_state = "prog_bar_0" + #undef PROGRESSBAR_ANIMATION_TIME #undef PROGRESSBAR_HEIGHT + +/obj/effect/abstract/progbar + icon = 'icons/effects/progressbar.dmi' + icon_state = "prog_bar_0" + plane = ABOVE_HUD_PLANE + appearance_flags = APPEARANCE_UI | KEEP_APART + pixel_y = 32 + alpha = 0 + mouse_opacity = MOUSE_OPACITY_TRANSPARENT + vis_flags = NONE //We don't want VIS_INHERIT_PLANE