Skip to content

Commit

Permalink
Updated progress bar datum to the latest iteration (Aurorastation#19672)
Browse files Browse the repository at this point in the history
Updated progress bar datum to the latest iteration
  • Loading branch information
FluffyGhoster authored Jul 27, 2024
1 parent f26e4a0 commit dc812d3
Show file tree
Hide file tree
Showing 8 changed files with 160 additions and 75 deletions.
12 changes: 12 additions & 0 deletions code/__HELPERS/atoms.dm
Original file line number Diff line number Diff line change
Expand Up @@ -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,
)
2 changes: 1 addition & 1 deletion code/__HELPERS/unsorted.dm
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
4 changes: 2 additions & 2 deletions code/_onclick/hud/screen_objects.dm
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
151 changes: 83 additions & 68 deletions code/datums/progressbar.dm
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand All @@ -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()


///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)

/datum/progressbar/autocomplete
destroy_on_full = TRUE

///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
2 changes: 1 addition & 1 deletion code/game/objects/items/devices/memorywiper.dm
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
4 changes: 2 additions & 2 deletions code/modules/mob/living/simple_animal/borer/borer.dm
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
58 changes: 58 additions & 0 deletions html/changelogs/fluffyghost-updateprogressbar.yml
Original file line number Diff line number Diff line change
@@ -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."

0 comments on commit dc812d3

Please sign in to comment.