[MIRROR] Progress bars & cleaning particles will centre on the tile occupied by large icon objects [MDB IGNORE] (#23394)

* Progress bars & cleaning particles will centre on the tile occupied by large icon objects (#77940)

## About The Pull Request

Do_after bars always draw based on the top-left corner of the targetted
atom, for atoms with sprites that are larger than 32x32 this gives them
a weird offset instead of being centred, which bugs me.
I have tried my best to figure out a way to reverse this which does not
interfere with atoms which use pixel_x/pixel_y to visually appear to be
on a different tile.

## Why It's Good For The Game

Before:

![image](https://github.com/tgstation/tgstation/assets/7483112/a1127695-58fa-40fc-aa0a-6bc8a0589e74)
he hates how you missed him completely 😦

After:

![image](https://github.com/tgstation/tgstation/assets/7483112/deb4fbb8-e286-46b4-84a7-82b65b4f1eee)
now you're cleaning his feet 🙂

## Changelog

🆑
image: progress bars and cleaning particles are now centered on the tile
occupied by the target, if it is a big sprite
/🆑

* Progress bars & cleaning particles will centre on the tile occupied by large icon objects

---------

Co-authored-by: Jacquerel <hnevard@gmail.com>
This commit is contained in:
SkyratBot
2023-08-29 05:40:16 +02:00
committed by GitHub
parent c1b2e59174
commit 91837e26b4
16 changed files with 66 additions and 34 deletions

View File

@@ -323,3 +323,15 @@ rough example of the "cone" made by the 3 dirs checked
if(!storage_datum)
return
. += storage_datum.real_location?.resolve()
/// 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,
)

View File

@@ -1461,3 +1461,10 @@ GLOBAL_LIST_EMPTY(transformation_animation_objects)
else
bound_width = world.icon_size
bound_height = size * world.icon_size
/// Returns a list containing the width and height of an icon file
/proc/get_icon_dimensions(icon_path)
if (isnull(GLOB.icon_dimensions[icon_path]))
var/icon/my_icon = icon(icon_path)
GLOB.icon_dimensions[icon_path] = list("width" = my_icon.Width(), "height" = my_icon.Height())
return GLOB.icon_dimensions[icon_path]

View File

@@ -216,7 +216,7 @@ Turf and target are separate in case you want to teleport some distance from a t
var/list/offsets = get_visual_offset(checked_atom)
return pixel_offset_turf(atom_turf, offsets)
/**
* Returns how visually "off" the atom is from its source turf as a list of x, y (in pixel steps)
* it takes into account:
@@ -232,9 +232,9 @@ Turf and target are separate in case you want to teleport some distance from a t
var/pixel_y_offset = checked_atom.pixel_y + atom_matrix.get_y_shift()
//Irregular objects
var/icon/checked_atom_icon = icon(checked_atom.icon, checked_atom.icon_state)
var/checked_atom_icon_height = checked_atom_icon.Height()
var/checked_atom_icon_width = checked_atom_icon.Width()
var/list/icon_dimensions = get_icon_dimensions(checked_atom.icon)
var/checked_atom_icon_height = icon_dimensions["width"]
var/checked_atom_icon_width = icon_dimensions["height"]
if(checked_atom_icon_height != world.icon_size || checked_atom_icon_width != world.icon_size)
pixel_x_offset += ((checked_atom_icon_width / world.icon_size) - 1) * (world.icon_size * 0.5)
pixel_y_offset += ((checked_atom_icon_height / world.icon_size) - 1) * (world.icon_size * 0.5)

View File

@@ -0,0 +1,2 @@
/// Cache of the width and height of icon files, to avoid repeating the same expensive operation
GLOBAL_LIST_EMPTY(icon_dimensions)

View File

@@ -98,6 +98,11 @@
RegisterSignal(target, COMSIG_MOVABLE_Z_CHANGED, PROC_REF(cleaning_target_moved))
var/mutable_appearance/low_bubble = mutable_appearance('icons/effects/effects.dmi', "bubbles", FLOOR_CLEAN_LAYER, target, GAME_PLANE)
var/mutable_appearance/high_bubble = mutable_appearance('icons/effects/effects.dmi', "bubbles", FLOOR_CLEAN_LAYER, target, ABOVE_GAME_PLANE)
var/list/icon_offsets = target.get_oversized_icon_offsets()
low_bubble.pixel_x = icon_offsets["x"]
low_bubble.pixel_y = icon_offsets["y"]
high_bubble.pixel_x = icon_offsets["x"]
high_bubble.pixel_y = icon_offsets["y"]
if(target.plane > low_bubble.plane) //check if the higher overlay is necessary
target.add_overlay(high_bubble)
else if(target.plane == low_bubble.plane)

View File

@@ -139,9 +139,9 @@
* without otherwise affecting other movables with identical overlays.
*/
/datum/element/immerse/proc/add_immerse_overlay(atom/movable/movable)
var/icon/movable_icon = icon(movable.icon)
var/width = movable_icon.Width() || world.icon_size
var/height = movable_icon.Height() || world.icon_size
var/list/icon_dimensions = get_icon_dimensions(movable.icon)
var/width = icon_dimensions["width"] || world.icon_size
var/height = icon_dimensions["height"] || world.icon_size
var/is_below_water = movable.layer < WATER_LEVEL_LAYER ? "underwater-" : ""

View File

@@ -193,9 +193,9 @@
/// Reads layer configurations to take out some useful overall information
/datum/greyscale_config/proc/ReadMetadata()
var/icon/source = icon(icon_file)
height = source.Height()
width = source.Width()
var/list/icon_dimensions = get_icon_dimensions(icon_file)
height = icon_dimensions["width"]
width = icon_dimensions["height"]
var/list/datum/greyscale_layer/all_layers = list()
for(var/state in icon_states)

View File

@@ -18,6 +18,8 @@
var/listindex = 0
///The type of our last value for bar_loc, for debugging
var/location_type
///Where to draw the progress bar above the icon
var/offset_y
/datum/progressbar/New(mob/User, goal_number, atom/target)
. = ..()
@@ -36,7 +38,12 @@
goal = goal_number
bar_loc = target
location_type = bar_loc.type
bar = image('icons/effects/progressbar.dmi', bar_loc, "prog_bar_0")
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.appearance_flags = APPEARANCE_UI_IGNORE_ALPHA
user = User
@@ -62,8 +69,8 @@
continue
progress_bar.listindex--
progress_bar.bar.pixel_y = 32 + (PROGRESSBAR_HEIGHT * (progress_bar.listindex - 1))
var/dist_to_travel = 32 + (PROGRESSBAR_HEIGHT * (progress_bar.listindex - 1)) - PROGRESSBAR_HEIGHT
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)
@@ -118,7 +125,7 @@
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)
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.

View File

@@ -23,9 +23,10 @@
/mob/living/simple_animal/revenant/ranged_secondary_attack(atom/target, modifiers)
if(revealed || notransform || inhibited || !Adjacent(target) || !incorporeal_move_check(target))
return
var/icon/I = icon(target.icon,target.icon_state,target.dir)
var/orbitsize = (I.Width()+I.Height())*0.5
orbitsize -= (orbitsize/world.icon_size)*(world.icon_size*0.25)
var/list/icon_dimensions = get_icon_dimensions(target.icon)
var/orbitsize = (icon_dimensions["width"] + icon_dimensions["height"]) * 0.5
orbitsize -= (orbitsize / world.icon_size) * (world.icon_size * 0.25)
orbit(target, orbitsize)
//Harvest; activated by clicking the target, will try to drain their essence.

View File

@@ -478,8 +478,8 @@ Moving interrupts
user.balloon_alert(user, "no sculpt target!")
return FALSE
//No big icon things
var/icon/thing_icon = icon(target.icon, target.icon_state)
if(thing_icon.Height() != world.icon_size || thing_icon.Width() != world.icon_size)
var/list/icon_dimensions = get_icon_dimensions(target.icon)
if(icon_dimensions["width"] != world.icon_size || icon_dimensions["height"] != world.icon_size)
user.balloon_alert(user, "sculpt target is too big!")
return FALSE
return TRUE

View File

@@ -136,10 +136,10 @@
// Scale the preview if it's bigger than one tile
var/mutable_appearance/preview_overlay = new(typepath)
var/icon/size_check = icon(initial(typepath.icon), icon_state = initial(typepath.icon_state))
var/list/icon_dimensions = get_icon_dimensions(initial(typepath.icon))
var/width = icon_dimensions["width"]
var/height = icon_dimensions["height"]
var/scale = 1
var/width = size_check.Width()
var/height = size_check.Height()
if(width > world.icon_size || height > world.icon_size)
if(width >= height)
scale = world.icon_size / width

View File

@@ -148,11 +148,10 @@
for (var/atom/movable/ingredient as anything in ingredients)
var/image/ingredient_overlay = image(ingredient, src)
var/icon/ingredient_icon = icon(ingredient.icon, ingredient.icon_state)
var/list/icon_dimensions = get_icon_dimensions(ingredient.icon)
ingredient_overlay.transform = ingredient_overlay.transform.Scale(
MICROWAVE_INGREDIENT_OVERLAY_SIZE / ingredient_icon.Width(),
MICROWAVE_INGREDIENT_OVERLAY_SIZE / ingredient_icon.Height(),
MICROWAVE_INGREDIENT_OVERLAY_SIZE / icon_dimensions["width"],
MICROWAVE_INGREDIENT_OVERLAY_SIZE / icon_dimensions["height"],
)
ingredient_overlay.pixel_y = -4

View File

@@ -502,9 +502,8 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
if (!istype(target) || (is_secret_level(target.z) && !client?.holder))
return
var/icon/I = icon(target.icon,target.icon_state,target.dir)
var/orbitsize = (I.Width()+I.Height())*0.5
var/list/icon_dimensions = get_icon_dimensions(target.icon)
var/orbitsize = (icon_dimensions["width"] + icon_dimensions["height"]) * 0.5
orbitsize -= (orbitsize/world.icon_size)*(world.icon_size*0.25)
var/rot_seg

View File

@@ -354,8 +354,8 @@ Difficulty: Extremely Hard
if(!owner.stat)
to_chat(owner, span_userdanger("You become frozen in a cube!"))
cube = icon('icons/effects/freeze.dmi', "ice_cube")
var/icon/size_check = icon(owner.icon, owner.icon_state)
cube.Scale(size_check.Width(), size_check.Height())
var/list/icon_dimensions = get_icon_dimensions(owner.icon)
cube.Scale(icon_dimensions["width"], icon_dimensions["height"])
owner.add_overlay(cube)
return ..()

View File

@@ -146,11 +146,10 @@
)
miniball.transform *= pick(0.3, 0.4, 0.5, 0.6, 0.7)
var/icon/I = icon(icon, icon_state,dir)
var/list/icon_dimensions = get_icon_dimensions(icon)
var/orbitsize = (I.Width() + I.Height()) * pick(0.4, 0.5, 0.6, 0.7, 0.8)
var/orbitsize = (icon_dimensions["width"] + icon_dimensions["height"]) * pick(0.4, 0.5, 0.6, 0.7, 0.8)
orbitsize -= (orbitsize / world.icon_size) * (world.icon_size * 0.25)
miniball.orbit(src, orbitsize, pick(FALSE, TRUE), rand(10, 25), pick(3, 4, 5, 6, 36))
/obj/energy_ball/Bump(atom/A)

View File

@@ -574,6 +574,7 @@
#include "code\_globalvars\lists\client.dm"
#include "code\_globalvars\lists\color.dm"
#include "code\_globalvars\lists\flavor_misc.dm"
#include "code\_globalvars\lists\icons.dm"
#include "code\_globalvars\lists\keybindings.dm"
#include "code\_globalvars\lists\maintenance_loot.dm"
#include "code\_globalvars\lists\mapping.dm"