diff --git a/code/__HELPERS/atoms.dm b/code/__HELPERS/atoms.dm index 309aa36db11..a9f1a550e54 100644 --- a/code/__HELPERS/atoms.dm +++ b/code/__HELPERS/atoms.dm @@ -65,3 +65,15 @@ c_dist++ return atom_list + +/// Returns an x and y value require to reverse the transformations made to center an oversized icon +/atom/proc/get_oversized_icon_offsets() + if (pixel_x == 0 && pixel_y == 0) + return list("x" = 0, "y" = 0) + var/list/icon_dimensions = get_icon_dimensions(icon) + var/icon_width = icon_dimensions["width"] + var/icon_height = icon_dimensions["height"] + return list( + "x" = icon_width > world.icon_size && pixel_x != 0 ? (icon_width - world.icon_size) * 0.5 : 0, + "y" = icon_height > world.icon_size && pixel_y != 0 ? (icon_height - world.icon_size) * 0.5 : 0, + ) diff --git a/code/__HELPERS/unsorted.dm b/code/__HELPERS/unsorted.dm index d5687fc0d23..96a2e38f389 100644 --- a/code/__HELPERS/unsorted.dm +++ b/code/__HELPERS/unsorted.dm @@ -786,7 +786,7 @@ Turf and target are seperate in case you want to teleport some distance from a t USE_FEEDBACK_FAILURE("You must remain targeting the same zone to perform that action!") if(!QDELETED(progbar)) - progbar.endProgress() + progbar.end_progress() if ((do_flags & DO_USER_UNIQUE_ACT) && user.do_unique_user_handle == initial_handle) user.do_unique_user_handle = 0 if ((do_flags & DO_TARGET_UNIQUE_ACT) && target) diff --git a/code/_onclick/hud/screen_objects.dm b/code/_onclick/hud/screen_objects.dm index 1910b75133e..52b25db57e5 100644 --- a/code/_onclick/hud/screen_objects.dm +++ b/code/_onclick/hud/screen_objects.dm @@ -464,8 +464,8 @@ if(user.max_stamina == -1 || user.stamina == user.max_stamina) if(user.stamina_bar) - user.stamina_bar.endProgress() - user.stamina_bar = null + user.stamina_bar.end_progress() + QDEL_NULL(user.stamina_bar) //Because otherwise they stack weirdly when calculating the progress bar offsets else if(!user.stamina_bar) user.stamina_bar = new(user, user.max_stamina, src) diff --git a/code/datums/progressbar.dm b/code/datums/progressbar.dm index 07a0837ee35..20271be0d32 100644 --- a/code/datums/progressbar.dm +++ b/code/datums/progressbar.dm @@ -2,75 +2,64 @@ #define PROGRESSBAR_ANIMATION_TIME 5 /datum/progressbar - ///The progress bar visual element + ///The progress bar visual element. var/image/bar - ///The target where this target bar is applied and where it is shown + ///The target where this progress bar is applied and where it is shown. var/atom/bar_loc - ///The mob whose client sees the progress bar + ///The mob whose client sees the progress bar. var/mob/user - ///The client seeing the progress bar + ///The client seeing the progress bar. var/client/user_client - ///Effectively the number of steps the progress bar will need before reaching completion + ///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 + ///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 + ///Variable to ensure smooth visual stacking on multiple progress bars. var/listindex = 0 ///The type of our last value for bar_loc, for debugging var/location_type - ///Whether to immediately destroy a progress bar when full, rather than wait for an animation - var/destroy_on_full = FALSE + ///Where to draw the progress bar above the icon + var/offset_y /datum/progressbar/New(mob/User, goal_number, atom/target) . = ..() if (!istype(target)) - stack_trace("Invalid target [target] passed in /datum/progressbar") + stack_trace("Invalid target [target] passed in") qdel(src) return - if (QDELETED(User) || !istype(User)) - stack_trace("[isnull(User) ? "Null" : "Invalid"] user passed in /datum/progressbar") + if(QDELETED(User) || !istype(User)) + stack_trace("/datum/progressbar created with [isnull(User) ? "null" : "invalid"] user") qdel(src) return - if (goal_number) - goal = goal_number + if(!isnum(goal_number)) + stack_trace("/datum/progressbar created with [isnull(User) ? "null" : "invalid"] goal_number") + qdel(src) + return + goal = goal_number bar_loc = target location_type = bar_loc.type - bar = image('icons/effects/progressbar.dmi', bar_loc, "prog_bar_0") - bar.layer = HUD_ABOVE_ITEM_LAYER + + var/list/icon_offsets = target.get_oversized_icon_offsets() + var/offset_x = icon_offsets["x"] + offset_y = icon_offsets["y"] + + bar = image('icons/effects/progressbar.dmi', bar_loc, "prog_bar_0", pixel_x = offset_x) + // SET_PLANE_EXPLICIT(bar, ABOVE_HUD_PLANE, User) bar.plane = HUD_PLANE - bar.appearance_flags = RESET_COLOR|RESET_TRANSFORM|NO_CLIENT_COLOR|RESET_ALPHA|PIXEL_SCALE + bar.appearance_flags = APPEARANCE_UI_IGNORE_ALPHA user = User LAZYADDASSOCLIST(user.progressbars, bar_loc, src) var/list/bars = user.progressbars[bar_loc] listindex = bars.len - if(user) + if(user.client) user_client = user.client - addProgBarImageToClient() + add_prog_bar_image_to_client() - RegisterSignal(user, COMSIG_QDELETING, PROC_REF(onUserDelete)) - RegisterSignal(user, COMSIG_MOB_LOGOUT, PROC_REF(cleanUserClient)) - RegisterSignal(user, COMSIG_MOB_LOGIN, PROC_REF(onUserLogin)) - -///Updates the progress bar image visually. -/datum/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)]" - if(destroy_on_full && progress == goal) - QDEL_IN(src, 5) - -///Called on progress end, be it successful or a failure. Wraps up things to delete the datum and bar. -/datum/progressbar/proc/endProgress() - if(last_progress != goal) - bar.icon_state = "[bar.icon_state]_fail" - - animate(bar, alpha = 0, time = PROGRESSBAR_ANIMATION_TIME) - - QDEL_IN(src, PROGRESSBAR_ANIMATION_TIME) + RegisterSignal(user, COMSIG_QDELETING, PROC_REF(on_user_delete)) + RegisterSignal(user, COMSIG_MOB_LOGOUT, PROC_REF(clean_user_client)) + RegisterSignal(user, COMSIG_MOB_LOGIN, PROC_REF(on_user_login)) /datum/progressbar/Destroy() @@ -79,64 +68,90 @@ var/datum/progressbar/progress_bar = pb if(progress_bar == src || progress_bar.listindex <= listindex) continue - --listindex - bar.pixel_y = 32 + (PROGRESSBAR_HEIGHT * (listindex - 1)) - var/dist_to_travel = 32 + (PROGRESSBAR_HEIGHT * (listindex - 1)) - PROGRESSBAR_HEIGHT - animate(bar, pixel_y = dist_to_travel, time = PROGRESSBAR_ANIMATION_TIME, easing = SINE_EASING) + progress_bar.listindex-- + + progress_bar.bar.pixel_y = world.icon_size + offset_y + (PROGRESSBAR_HEIGHT * (progress_bar.listindex - 1)) + var/dist_to_travel = world.icon_size + offset_y + (PROGRESSBAR_HEIGHT * (progress_bar.listindex - 1)) - PROGRESSBAR_HEIGHT + animate(progress_bar.bar, pixel_y = dist_to_travel, time = PROGRESSBAR_ANIMATION_TIME, easing = SINE_EASING) LAZYREMOVEASSOC(user.progressbars, bar_loc, src) user = null + if(user_client) - cleanUserClient() + clean_user_client() bar_loc = null - - if(bar) - QDEL_NULL(bar) + bar = null return ..() -///Adds a smoothly-appearing progress bar image to the player's screen. -/datum/progressbar/proc/addProgBarImageToClient() - bar.pixel_y = 0 - bar.alpha = 0 - user_client.images += bar - animate(bar, pixel_y = 32 + (PROGRESSBAR_HEIGHT * (listindex - 1)), alpha = 255, time = PROGRESSBAR_ANIMATION_TIME, easing = SINE_EASING) ///Called right before the user's Destroy() -/datum/progressbar/proc/onUserDelete(datum/source) +/datum/progressbar/proc/on_user_delete(datum/source) SIGNAL_HANDLER user.progressbars = null //We can simply nuke the list and stop worrying about updating other prog bars if the user itself is gone. user = null qdel(src) -///Removes the progress bar from the user_client and nulls the variables if it exists -/datum/progressbar/proc/cleanUserClient(datum/source) + +///Removes the progress bar image from the user_client and nulls the variable, if it exists. +/datum/progressbar/proc/clean_user_client(datum/source) SIGNAL_HANDLER - if(!user_client) //Disconnected, already gone + if(!user_client) //Disconnected, already gone. return user_client.images -= bar user_client = null + ///Called by user's Login(), it transfers the progress bar image to the new client. -/datum/progressbar/proc/onUserLogin(datum/source) +/datum/progressbar/proc/on_user_login(datum/source) SIGNAL_HANDLER - // Sanity checking to ensure client is mob and that the client did not log off again if(user_client) - if(user_client == user.client) + if(user_client == user.client) //If this was not client handling I'd condemn this sanity check. But clients are fickle things. return - cleanUserClient() - if(!user.client) + clean_user_client() + if(!user.client) //Clients can vanish at any time, the bastards. return - user_client = user.client - addProgBarImageToClient() + add_prog_bar_image_to_client() -/datum/progressbar/autocomplete - destroy_on_full = TRUE + +///Adds a smoothly-appearing progress bar image to the player's screen. +/datum/progressbar/proc/add_prog_bar_image_to_client() + bar.pixel_y = 0 + bar.alpha = 0 + user_client.images += bar + animate(bar, pixel_y = world.icon_size + offset_y + (PROGRESSBAR_HEIGHT * (listindex - 1)), alpha = 255, time = PROGRESSBAR_ANIMATION_TIME, easing = SINE_EASING) + + +///Updates the progress bar image visually. +/datum/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)]" + + +///Called on progress end, be it successful or a failure. Wraps up things to delete the datum and bar. +/datum/progressbar/proc/end_progress() + if(last_progress != goal) + bar.icon_state = "[bar.icon_state]_fail" + + animate(bar, alpha = 0, time = PROGRESSBAR_ANIMATION_TIME) + + QDEL_IN(src, PROGRESSBAR_ANIMATION_TIME) + +///Progress bars are very generic, and what hangs a ref to them depends heavily on the context in which they're used +///So let's make hunting harddels easier yeah? +/datum/progressbar/dump_harddel_info() + if(harddel_deets_dumped) + return + harddel_deets_dumped = TRUE + return "Owner's type: [location_type]" #undef PROGRESSBAR_ANIMATION_TIME #undef PROGRESSBAR_HEIGHT diff --git a/code/game/objects/items/devices/memorywiper.dm b/code/game/objects/items/devices/memorywiper.dm index d0572ec61c6..c0e30b07f80 100644 --- a/code/game/objects/items/devices/memorywiper.dm +++ b/code/game/objects/items/devices/memorywiper.dm @@ -80,7 +80,7 @@ var/wipe_time = rand(20 SECONDS, 40 SECONDS) addtimer(CALLBACK(src, PROC_REF(memorywipe)), wipe_time) - wipe_bar = new /datum/progressbar/autocomplete(src, wipe_time, attached) + wipe_bar = new /datum/progressbar(src, wipe_time, attached) wipe_start_time = world.time wipe_bar.update(0) if(anchored) diff --git a/code/modules/mob/living/simple_animal/borer/borer.dm b/code/modules/mob/living/simple_animal/borer/borer.dm index 2cb0e14610b..3be44f6d8ae 100644 --- a/code/modules/mob/living/simple_animal/borer/borer.dm +++ b/code/modules/mob/living/simple_animal/borer/borer.dm @@ -28,7 +28,7 @@ hunger_enabled = FALSE var/used_dominate - var/datum/progressbar/autocomplete/ability_bar + var/datum/progressbar/ability_bar var/ability_start_time = 0 var/obj/screen/borer/chemicals/chem_hud var/chemicals = 10 // Chemicals used for reproduction and spitting neurotoxin. @@ -92,7 +92,7 @@ /mob/living/simple_animal/borer/proc/start_ability(var/atom/target, var/time) if(!QDELETED(ability_bar)) return FALSE - ability_bar = new /datum/progressbar/autocomplete(src, time, target) + ability_bar = new /datum/progressbar(src, time, target) ability_start_time = world.time ability_bar.update(0) return TRUE diff --git a/code/modules/mob/living/simple_animal/borer/borer_captive.dm b/code/modules/mob/living/simple_animal/borer/borer_captive.dm index b04ccd6fef1..367d8694529 100644 --- a/code/modules/mob/living/simple_animal/borer/borer_captive.dm +++ b/code/modules/mob/living/simple_animal/borer/borer_captive.dm @@ -48,7 +48,7 @@ var/resist_time = rand(40 SECONDS, 1 MINUTE) addtimer(CALLBACK(src, PROC_REF(eject_borer), B, H), resist_time) - resist_bar = new /datum/progressbar/autocomplete(src, resist_time, B.host) + resist_bar = new /datum/progressbar(src, resist_time, B.host) resist_start_time = world.time resist_bar.update(0) return diff --git a/html/changelogs/fluffyghost-updateprogressbar.yml b/html/changelogs/fluffyghost-updateprogressbar.yml new file mode 100644 index 00000000000..7d2c1b099e5 --- /dev/null +++ b/html/changelogs/fluffyghost-updateprogressbar.yml @@ -0,0 +1,58 @@ +################################ +# Example Changelog File +# +# Note: This file, and files beginning with ".", and files that don't end in ".yml" will not be read. If you change this file, you will look really dumb. +# +# Your changelog will be merged with a master changelog. (New stuff added only, and only on the date entry for the day it was merged.) +# When it is, any changes listed below will disappear. +# +# Valid Prefixes: +# bugfix +# - (fixes bugs) +# wip +# - (work in progress) +# qol +# - (quality of life) +# soundadd +# - (adds a sound) +# sounddel +# - (removes a sound) +# rscadd +# - (adds a feature) +# rscdel +# - (removes a feature) +# imageadd +# - (adds an image or sprite) +# imagedel +# - (removes an image or sprite) +# spellcheck +# - (fixes spelling or grammar) +# experiment +# - (experimental change) +# balance +# - (balance changes) +# code_imp +# - (misc internal code change) +# refactor +# - (refactors code) +# config +# - (makes a change to the config files) +# admin +# - (makes changes to administrator tools) +# server +# - (miscellaneous changes to server) +################################# + +# Your name. +author: FluffyGhost + +# Optional: Remove this file after generating master changelog. Useful for PR changelogs that won't get used again. +delete-after: True + +# Any changes you've made. See valid prefix list above. +# INDENT WITH TWO SPACES. NOT TABS. SPACES. +# SCREW THIS UP AND IT WON'T WORK. +# Also, this gets changed to [] after reading. Just remove the brackets when you add new shit. +# Please surround your changes in double quotes ("). It works without them, but if you use certain characters it screws up compiling. The quotes will not show up in the changelog. +changes: + - refactor: "Updated progress bar datum to the latest iteration."