diff --git a/code/datums/elements/immerse.dm b/code/datums/elements/immerse.dm index b23623d51b0..f0fcd06a6d5 100644 --- a/code/datums/elements/immerse.dm +++ b/code/datums/elements/immerse.dm @@ -245,8 +245,17 @@ GLOBAL_LIST_INIT(immerse_ignored_movable, typecacheof(list( // This determines if the overlay should cover the entire surface of the object or not var/layer_to_check = IS_TOPDOWN_PLANE(movable.plane) ? TOPDOWN_WATER_LEVEL_LAYER : WATER_LEVEL_LAYER var/is_below_water = (movable.layer < layer_to_check) ? "underwater-" : "" + var/x_offset = 0 + var/y_offset = 0 + var/movable_width = movable.get_cached_width() + if (ishuman(movable)) + var/mob/living/carbon/human/as_human = movable + if (as_human.cached_body_min_x_offset && movable_width > ICON_SIZE_X) + x_offset = as_human.cached_body_min_x_offset + if (as_human.cached_body_min_y_offset && movable.get_cached_height() > ICON_SIZE_Y) + y_offset = as_human.cached_body_min_y_offset // Tall mobs still only get covered to their feet, unless they're offset down - var/mutable_appearance/immerse_mask = generate_immerse_mask(movable.get_cached_width(), max(ICON_SIZE_Y - movable.pixel_z, ICON_SIZE_Y), is_below_water) + var/mutable_appearance/immerse_mask = generate_immerse_mask(movable_width, max(ICON_SIZE_Y - movable.pixel_z - y_offset, ICON_SIZE_Y), is_below_water) if (!immerse_mask) return var/atom/movable/immerse_mask/effect_relay = generated_visual_overlays[movable] @@ -256,6 +265,8 @@ GLOBAL_LIST_INIT(immerse_ignored_movable, typecacheof(list( generated_visual_overlays[movable] = effect_relay var/mutable_appearance/mask_copy = new(immerse_mask) effect_relay.appearance = mask_copy + effect_relay.pixel_w += x_offset + effect_relay.pixel_z += y_offset effect_relay.render_target = "*immerse_[REF(movable)]" SEND_SIGNAL(movable, COMSIG_MOVABLE_EDIT_UNIQUE_IMMERSE_OVERLAY, effect_relay) // Should always render above any other filters that could be adding visuals diff --git a/code/game/data_huds.dm b/code/game/data_huds.dm index a38ba684758..4e0bdb2873a 100644 --- a/code/game/data_huds.dm +++ b/code/game/data_huds.dm @@ -497,6 +497,18 @@ Diagnostic HUDs! var/list/dimensions = get_icon_dimensions(icon) return dimensions[CACHED_HEIGHT_INDEX] +/image/proc/get_cached_width() + if (isnull(icon)) + return 0 + var/list/dimensions = get_icon_dimensions(icon) + return dimensions[CACHED_WIDTH_INDEX] + +/image/proc/get_cached_height() + if (isnull(icon)) + return 0 + var/list/dimensions = get_icon_dimensions(icon) + return dimensions[CACHED_HEIGHT_INDEX] + #undef CACHED_WIDTH_INDEX #undef CACHED_HEIGHT_INDEX @@ -522,12 +534,18 @@ Diagnostic HUDs! ) return max(scale_list) - min(scale_list) +/atom/proc/get_hud_x_offset() + return -(get_cached_width() - ICON_SIZE_X) / 2 + +/atom/proc/get_hud_y_offset() + return get_cached_height() - ICON_SIZE_Y + /atom/proc/adjust_hud_position(image/holder, animate_time = null) if (animate_time) - animate(holder, pixel_w = -(get_cached_width() - ICON_SIZE_X) / 2, pixel_z = get_cached_height() - ICON_SIZE_Y, time = animate_time) + animate(holder, pixel_w = get_hud_x_offset(), pixel_z = get_hud_y_offset(), time = animate_time) return - holder.pixel_w = -(get_cached_width() - ICON_SIZE_X) / 2 - holder.pixel_z = get_cached_height() - ICON_SIZE_Y + holder.pixel_w = get_hud_x_offset() + holder.pixel_z = get_hud_y_offset() /atom/proc/set_hud_image_state(hud_type, hud_state, x_offset = 0, y_offset = 0) if (!hud_list) // Still initializing diff --git a/code/modules/mining/equipment/monster_organs/brimdust_sac.dm b/code/modules/mining/equipment/monster_organs/brimdust_sac.dm index 9c741ae0680..2c047792c8e 100644 --- a/code/modules/mining/equipment/monster_organs/brimdust_sac.dm +++ b/code/modules/mining/equipment/monster_organs/brimdust_sac.dm @@ -169,6 +169,12 @@ dust_overlay.alpha = stacks * BRIMDUST_ALPHA_PER_STACK dust_overlay.color = COLOR_RED_LIGHT dust_overlay.blend_mode = BLEND_INSET_OVERLAY + if (ishuman(owner)) + var/mob/living/carbon/human/as_human = owner + if (as_human.cached_body_min_x_offset && target_width > ICON_SIZE_X) + dust_overlay.pixel_w = as_human.cached_body_min_x_offset + if (as_human.cached_body_min_y_offset && target_height > ICON_SIZE_Y) + dust_overlay.pixel_z = as_human.cached_body_min_y_offset ADD_KEEP_TOGETHER(owner, REF(src)) owner.add_overlay(dust_overlay) var/obj/effect/holder = owner.add_shared_particles(/particles/brimdust, "brimdust_coating-[owner.base_pixel_w]") diff --git a/code/modules/mob/living/basic/boss/blood_drunk_miner/_blood_drunk_miner.dm b/code/modules/mob/living/basic/boss/blood_drunk_miner/_blood_drunk_miner.dm index 0e9e734a21d..a251db94200 100644 --- a/code/modules/mob/living/basic/boss/blood_drunk_miner/_blood_drunk_miner.dm +++ b/code/modules/mob/living/basic/boss/blood_drunk_miner/_blood_drunk_miner.dm @@ -86,6 +86,9 @@ Difficulty: Medium QDEL_NULL(miner_saw) return ..() +/mob/living/basic/boss/blood_drunk_miner/get_hud_x_offset() + return 0 + /// Returns a list of innate actions for the blood-drunk miner. /mob/living/basic/boss/blood_drunk_miner/proc/get_innate_actions() var/list/innate_abilities = list( diff --git a/code/modules/mob/living/basic/lavaland/goldgrub/goldgrub.dm b/code/modules/mob/living/basic/lavaland/goldgrub/goldgrub.dm index b43f2149893..7422e705104 100644 --- a/code/modules/mob/living/basic/lavaland/goldgrub/goldgrub.dm +++ b/code/modules/mob/living/basic/lavaland/goldgrub/goldgrub.dm @@ -87,6 +87,9 @@ if(has_emissive) update_appearance(UPDATE_OVERLAYS) +/mob/living/basic/mining/goldgrub/get_hud_x_offset() + return -4 + /mob/living/basic/mining/goldgrub/proc/block_bullets(datum/source, obj/projectile/hitting_projectile) SIGNAL_HANDLER diff --git a/code/modules/mob/living/basic/lavaland/goliath/goliath.dm b/code/modules/mob/living/basic/lavaland/goliath/goliath.dm index 82eb6de7a04..972127977ed 100644 --- a/code/modules/mob/living/basic/lavaland/goliath/goliath.dm +++ b/code/modules/mob/living/basic/lavaland/goliath/goliath.dm @@ -87,6 +87,9 @@ QDEL_NULL(tentacle_line) return ..() +/mob/living/basic/mining/goliath/get_hud_x_offset() + return -4 + /mob/living/basic/mining/goliath/examine(mob/user) . = ..() if (saddled) diff --git a/code/modules/mob/living/basic/lavaland/raptor/_raptor.dm b/code/modules/mob/living/basic/lavaland/raptor/_raptor.dm index 610682fd7a3..59a3727c38f 100644 --- a/code/modules/mob/living/basic/lavaland/raptor/_raptor.dm +++ b/code/modules/mob/living/basic/lavaland/raptor/_raptor.dm @@ -139,6 +139,9 @@ GLOBAL_LIST_EMPTY(raptor_population) return return ..() +/mob/living/basic/raptor/get_hud_x_offset() + return -4 + /mob/living/basic/raptor/examine(mob/user) . = ..() if (stat == DEAD) diff --git a/code/modules/mob/living/basic/space_fauna/carp/megacarp.dm b/code/modules/mob/living/basic/space_fauna/carp/megacarp.dm index d82120a37e0..c86250c5f90 100644 --- a/code/modules/mob/living/basic/space_fauna/carp/megacarp.dm +++ b/code/modules/mob/living/basic/space_fauna/carp/megacarp.dm @@ -33,3 +33,6 @@ melee_damage_upper += rand(10,20) maxHealth += rand(30,60) health = maxHealth + +/mob/living/basic/carp/mega/get_hud_x_offset() + return -5 diff --git a/code/modules/mob/living/carbon/human/human_defines.dm b/code/modules/mob/living/carbon/human/human_defines.dm index 67e6185d28e..091ac22cf80 100644 --- a/code/modules/mob/living/carbon/human/human_defines.dm +++ b/code/modules/mob/living/carbon/human/human_defines.dm @@ -93,3 +93,12 @@ /// Tracks how long in seconds we've been in a low pressure environment VAR_FINAL/seconds_in_low_pressure = 0 + + /// Combined width of our body sprite + VAR_PRIVATE/cached_body_width = ICON_SIZE_X + /// Combined height of our body sprite + VAR_PRIVATE/cached_body_height = ICON_SIZE_Y + /// Leftmost offset of our overlays + var/cached_body_min_x_offset = 0 + /// Rightmost offset of our overlays + var/cached_body_min_y_offset = 0 diff --git a/code/modules/mob/living/carbon/human/human_helpers.dm b/code/modules/mob/living/carbon/human/human_helpers.dm index 523c3656802..c0e5b21b233 100644 --- a/code/modules/mob/living/carbon/human/human_helpers.dm +++ b/code/modules/mob/living/carbon/human/human_helpers.dm @@ -286,6 +286,7 @@ mob_height = dna?.species?.update_species_heights(src) || base_mob_height if(old_height != mob_height) regenerate_icons() + readjust_atom_huds() SEND_SIGNAL(src, COMSIG_HUMAN_HEIGHT_UPDATED, old_height) /** diff --git a/code/modules/mob/living/carbon/human/human_update_icons.dm b/code/modules/mob/living/carbon/human/human_update_icons.dm index 55fbb4cec72..39506b1fb4c 100644 --- a/code/modules/mob/living/carbon/human/human_update_icons.dm +++ b/code/modules/mob/living/carbon/human/human_update_icons.dm @@ -946,3 +946,52 @@ generate/load female uniform sprites matching all previously decided variables return appearance #undef RESOLVE_ICON_STATE + +// Wide organs or bodyparts shouldn't offset human HUD directly +/mob/living/carbon/human/get_hud_x_offset() + return 0 + +// But they are affected by height +/mob/living/carbon/human/get_hud_y_offset() + return GLOB.human_heights_to_offsets[mob_height]["[UPPER_BODY]"] + +/mob/living/carbon/human/get_cached_width() + return cached_body_width + +/mob/living/carbon/human/get_cached_height() + return cached_body_height + +#define SUB_OVERLAY_X_INDEX 1 +#define SUB_OVERLAY_Y_INDEX 1 + +/mob/living/carbon/human/update_body_parts(update_limb_data) + . = ..() + if (!.) + return + cached_body_width = ICON_SIZE_X + cached_body_height = ICON_SIZE_Y + var/list/bodypart_overlays = overlays_standing[BODYPARTS_LAYER] + if (!length(bodypart_overlays)) + return + var/list/parsed_overlays = bodypart_overlays.Copy() + var/i = 1 + while (i <= length(parsed_overlays)) + var/mutable_appearance/overlay = parsed_overlays[i] + if (!isimage(overlay)) // Malformed overlays, etc + i += 1 + continue + var/overlay_x = overlay.pixel_x + overlay.pixel_w + var/overlay_y = overlay.pixel_y + overlay.pixel_z + if (!isnull(parsed_overlays[overlay])) // Nested overlay + overlay_x += parsed_overlays[overlay][SUB_OVERLAY_X_INDEX] + overlay_y += parsed_overlays[overlay][SUB_OVERLAY_Y_INDEX] + cached_body_width = max(cached_body_width, overlay.get_cached_width()) + cached_body_height = max(cached_body_height, overlay.get_cached_height()) + cached_body_min_x_offset = min(cached_body_min_x_offset, overlay_x) + cached_body_min_y_offset = min(cached_body_min_y_offset, overlay_y) + for (var/sub_overlay in overlay.overlays) + parsed_overlays[sub_overlay] = list(overlay_x, overlay_y) + i += 1 + +#undef SUB_OVERLAY_X_INDEX +#undef SUB_OVERLAY_Y_INDEX diff --git a/code/modules/mob/living/living_update_icons.dm b/code/modules/mob/living/living_update_icons.dm index 274a5a4f101..cd328b3a801 100644 --- a/code/modules/mob/living/living_update_icons.dm +++ b/code/modules/mob/living/living_update_icons.dm @@ -52,14 +52,17 @@ var/is_opposite_angle = REVERSE_ANGLE(lying_angle) == lying_prev var/animate_time = is_opposite_angle ? 0 : UPDATE_TRANSFORM_ANIMATION_TIME animate(src, transform = ntransform, time = animate_time, dir = final_dir, easing = SINE_EASING) + readjust_atom_huds(animate_time) + + SEND_SIGNAL(src, COMSIG_LIVING_POST_UPDATE_TRANSFORM, resize, lying_angle, is_opposite_angle) + return TRUE + +/mob/living/proc/readjust_atom_huds(animate_time = null) for (var/hud_key in hud_list) var/image/hud_image = hud_list[hud_key] if (istype(hud_image)) adjust_hud_position(hud_image, animate_time = animate_time) - SEND_SIGNAL(src, COMSIG_LIVING_POST_UPDATE_TRANSFORM, resize, lying_angle, is_opposite_angle) - return TRUE - /// Calculates how far vertically the mob's transform should translate according to its size (1 being "default") /mob/living/proc/get_transform_translation_size(value) return (value - 1) * 16