From 8d48f8d4d2f8ec00350e289fc991cdd035a585db Mon Sep 17 00:00:00 2001 From: SmArtKar <44720187+SmArtKar@users.noreply.github.com> Date: Thu, 26 Dec 2024 17:06:04 +0300 Subject: [PATCH] Fixes an 8 year old bug which colored your HUDs with you (#88667) ## About The Pull Request Partially a port of https://github.com/DaedalusDock/daedalusdock/pull/1163 which is a port of my own code from bitbus Closes #88579 Instead of manually setting hud images and positioning we now can use set_hud_image_state which also updates their position to ensure that they scale with the owner atom. HUDs had RESET_COLOR and RESET_TRANSFORM but no KEEP_APART, so they were stuck with mobs all this time. I replaced RESET_TRANSFORM with PIXEL_SCALE (shouldn't be reserved to mob huds only to be honest) and added KEEP_APART, so that HUDs still scale/rotate with their owner but don't inherit their color. Also fixed the dragon issue, that's where this PR actually started. Closes https://github.com/tgstation/tgstation/issues/45411 ## Why It's Good For The Game I don't want my HUDs to be pretty pink when I make a barbie Clarke. ## Changelog :cl: refactor: Rewrote some of HUD code so they're no longer colored in their owner's color fix: Space dragons no longer turn invisible when toggling seethrough mode /:cl: --- code/__DEFINES/maths.dm | 3 + code/__DEFINES/mobs.dm | 4 + code/__HELPERS/maths.dm | 4 - code/datums/components/life_link.dm | 14 +- code/datums/components/seethrough_mob.dm | 8 +- .../datums/components/throwbonus_on_windup.dm | 2 +- code/datums/drift_handler.dm | 4 +- code/game/data_huds.dm | 332 +++++++++--------- .../temporary_visuals/miscellaneous.dm | 2 +- .../antagonists/abductor/equipment/gland.dm | 8 +- .../changeling/powers/transform.dm | 7 +- code/modules/mob/living/basic/bots/bot_hud.dm | 30 +- code/modules/mob/living/basic/drone/_drone.dm | 19 +- .../mob/living/basic/space_fauna/morph.dm | 6 +- .../space_fauna/space_dragon/space_dragon.dm | 2 +- code/modules/mob/living/carbon/carbon.dm | 2 +- code/modules/mob/living/living.dm | 16 +- .../modules/mob/living/living_update_icons.dm | 9 +- code/modules/mob/mob.dm | 2 +- code/modules/power/solar.dm | 2 +- code/modules/power/tracker.dm | 2 +- 21 files changed, 228 insertions(+), 250 deletions(-) diff --git a/code/__DEFINES/maths.dm b/code/__DEFINES/maths.dm index 35c8d3edaf6..a96a950559a 100644 --- a/code/__DEFINES/maths.dm +++ b/code/__DEFINES/maths.dm @@ -132,6 +132,9 @@ // E.g: 540 becomes 180. -180 becomes 180. #define SIMPLIFY_DEGREES(degrees) (MODULUS((degrees), 360)) +// 180s an angle +#define REVERSE_ANGLE(degrees) (SIMPLIFY_DEGREES(degrees + 180)) + #define GET_ANGLE_OF_INCIDENCE(face, input) (MODULUS((face) - (input), 360)) //Finds the shortest angle that angle A has to change to get to angle B. Aka, whether to move clock or counterclockwise. diff --git a/code/__DEFINES/mobs.dm b/code/__DEFINES/mobs.dm index 42f45c2a2aa..7407bdf6556 100644 --- a/code/__DEFINES/mobs.dm +++ b/code/__DEFINES/mobs.dm @@ -871,6 +871,10 @@ GLOBAL_LIST_INIT(layers_to_offset, list( /// The default mob sprite size (used for shrinking or enlarging the mob sprite to regular size) #define RESIZE_DEFAULT_SIZE 1 +//Lying angles, which way your head points +#define LYING_ANGLE_EAST 90 +#define LYING_ANGLE_WEST 270 + /// Get the client from the var #define CLIENT_FROM_VAR(I) (ismob(I) ? I:client : (istype(I, /client) ? I : (istype(I, /datum/mind) ? I:current?:client : null))) diff --git a/code/__HELPERS/maths.dm b/code/__HELPERS/maths.dm index 27d3c5d38ab..fbd76a1d0be 100644 --- a/code/__HELPERS/maths.dm +++ b/code/__HELPERS/maths.dm @@ -249,7 +249,3 @@ for(var/zero in 1 to how_many_zeros) zeros += "0" return "[zeros][number]" - -/// 180s an angle -/proc/reverse_angle(angle) - return (angle + 180) % 360 diff --git a/code/datums/components/life_link.dm b/code/datums/components/life_link.dm index 26484674e80..98858f61c3c 100644 --- a/code/datums/components/life_link.dm +++ b/code/datums/components/life_link.dm @@ -123,22 +123,14 @@ /// Update our health on the medical hud /datum/component/life_link/proc/update_med_hud_health(mob/living/mob_parent) - var/image/holder = mob_parent.hud_list?[HEALTH_HUD] - if(isnull(holder)) - return - holder.icon_state = "hud[RoundHealth(host)]" - holder.pixel_y = mob_parent.get_cached_height() - ICON_SIZE_Y + mob_parent.set_hud_image_state(HEALTH_HUD, "hud[RoundHealth(host)]") /// Update our vital status on the medical hud /datum/component/life_link/proc/update_med_hud_status(mob/living/mob_parent) - var/image/holder = mob_parent.hud_list?[STATUS_HUD] - if(isnull(holder)) - return - holder.pixel_y = mob_parent.get_cached_height() - ICON_SIZE_Y if(host.stat == DEAD || HAS_TRAIT(host, TRAIT_FAKEDEATH)) - holder.icon_state = "huddead" + mob_parent.set_hud_image_state(STATUS_HUD, "huddead") else - holder.icon_state = "hudhealthy" + mob_parent.set_hud_image_state(STATUS_HUD, "hudhealthy") /// When our status tab updates, draw how much HP our host has in there /datum/component/life_link/proc/on_status_tab_updated(mob/living/source, list/items) diff --git a/code/datums/components/seethrough_mob.dm b/code/datums/components/seethrough_mob.dm index a788ef6e861..23b860ac566 100644 --- a/code/datums/components/seethrough_mob.dm +++ b/code/datums/components/seethrough_mob.dm @@ -17,7 +17,7 @@ ///This component's personal uid var/personal_uid -/datum/component/seethrough_mob/Initialize(target_alpha = 100, animation_time = 0.5 SECONDS, clickthrough = TRUE) +/datum/component/seethrough_mob/Initialize(target_alpha = 100, animation_time = 0.5 SECONDS, clickthrough = TRUE, keep_color = FALSE) . = ..() if(!ismob(parent)) @@ -33,9 +33,9 @@ uid++ src.personal_uid = uid - render_source_atom.appearance_flags |= ( RESET_COLOR | RESET_TRANSFORM) + render_source_atom.appearance_flags |= KEEP_APART - render_source_atom.vis_flags |= (VIS_INHERIT_ID | VIS_INHERIT_PLANE | VIS_INHERIT_LAYER) + render_source_atom.vis_flags |= (VIS_INHERIT_ID|VIS_INHERIT_PLANE|VIS_INHERIT_LAYER) render_source_atom.render_source = "*transparent_bigmob[personal_uid]" @@ -56,7 +56,7 @@ seethrough.unhide_plane(fool) render_source_atom.pixel_x = -fool.pixel_x - render_source_atom.pixel_y = (fool.get_cached_height() - ICON_SIZE_Y * 0.5) + render_source_atom.pixel_y = ((fool.get_cached_height() - ICON_SIZE_Y) * 0.5) initial_render_target_value = fool.render_target fool.render_target = "*transparent_bigmob[personal_uid]" diff --git a/code/datums/components/throwbonus_on_windup.dm b/code/datums/components/throwbonus_on_windup.dm index a96d9294e80..56e3de5cd81 100644 --- a/code/datums/components/throwbonus_on_windup.dm +++ b/code/datums/components/throwbonus_on_windup.dm @@ -52,7 +52,7 @@ return if(throw_text) to_chat(our_holder, span_warning(throw_text)) - var/x_position = CEILING(our_holder.get_cached_width() * 0.5, 1) + var/x_position = CEILING(our_holder.get_visual_width() * 0.5, 1) our_bar = new() our_bar.maximum_count = maximum_bonus our_bar.pixel_x = x_position diff --git a/code/datums/drift_handler.dm b/code/datums/drift_handler.dm index dcf0771d8a5..559ea9e13ca 100644 --- a/code/datums/drift_handler.dm +++ b/code/datums/drift_handler.dm @@ -241,7 +241,7 @@ /// Lack of angle means that we are trying to halt movement if (isnull(target_angle)) // Going through newtonian_move ensures that all Process_Spacemove code runs properly, instead of directly adjusting forces - parent.newtonian_move(reverse_angle(drifting_loop.angle), drift_force = min(drift_force, stabilization_force)) + parent.newtonian_move(REVERSE_ANGLE(drifting_loop.angle), drift_force = min(drift_force, stabilization_force)) return // Force required to be applied in order to get to the desired movement vector, with projection of current movement onto desired vector to ensure that we only compensate for excess @@ -264,4 +264,4 @@ var/projected_force = max(0, cos(target_angle - drifting_loop.angle)) * drift_force if (projected_force > 0) - parent.newtonian_move(reverse_angle(target_angle), projected_force) + parent.newtonian_move(REVERSE_ANGLE(target_angle), projected_force) diff --git a/code/game/data_huds.dm b/code/game/data_huds.dm index 0c44e35a746..e32d09309c1 100644 --- a/code/game/data_huds.dm +++ b/code/game/data_huds.dm @@ -166,70 +166,65 @@ Medical HUD! Basic mode needs suit sensors on. //called when a living mob changes health /mob/living/proc/med_hud_set_health() - var/image/holder = hud_list?[HEALTH_HUD] - if (isnull(holder)) - return + set_hud_image_state(HEALTH_HUD, "hud[RoundHealth(src)]") - holder.icon_state = "hud[RoundHealth(src)]" - holder.pixel_y = get_cached_height() - ICON_SIZE_Y - -//for carbon suit sensors -/mob/living/carbon/med_hud_set_health() - ..() - -//called when a carbon changes stat, virus or XENO_HOST +// Called when a carbon changes stat, virus or XENO_HOST +// Returns TRUE if the mob is considered "perfectly healthy", FALSE otherwise /mob/living/proc/med_hud_set_status() - var/image/holder = hud_list?[STATUS_HUD] - if (isnull(holder)) - return - - holder.pixel_y = get_cached_height() - ICON_SIZE_Y if(stat == DEAD || (HAS_TRAIT(src, TRAIT_FAKEDEATH))) - holder.icon_state = "huddead" - else - holder.icon_state = "hudhealthy" + set_hud_image_state(STATUS_HUD, "huddead") + return FALSE + + set_hud_image_state(STATUS_HUD, "hudhealthy") + return TRUE /mob/living/carbon/med_hud_set_status() - var/image/holder = hud_list?[STATUS_HUD] - if (isnull(holder)) - return + if(HAS_TRAIT(src, TRAIT_XENO_HOST)) + set_hud_image_state(STATUS_HUD, "hudxeno") + return FALSE + + if(stat == DEAD || (HAS_TRAIT(src, TRAIT_FAKEDEATH))) + if(HAS_TRAIT(src, TRAIT_MIND_TEMPORARILY_GONE) || can_defib_client()) + set_hud_image_state(STATUS_HUD, "huddefib") + else if(HAS_TRAIT(src, TRAIT_GHOSTROLE_ON_REVIVE)) + set_hud_image_state(STATUS_HUD, "hudghost") + else + set_hud_image_state(STATUS_HUD, "huddead") + return FALSE var/virus_threat = check_virus() - holder.pixel_y = get_cached_height() - ICON_SIZE_Y - if(HAS_TRAIT(src, TRAIT_XENO_HOST)) - holder.icon_state = "hudxeno" - else if(stat == DEAD || (HAS_TRAIT(src, TRAIT_FAKEDEATH))) - if(HAS_TRAIT(src, TRAIT_MIND_TEMPORARILY_GONE) || can_defib_client()) - holder.icon_state = "huddefib" - else if(HAS_TRAIT(src, TRAIT_GHOSTROLE_ON_REVIVE)) - holder.icon_state = "hudghost" - else - holder.icon_state = "huddead" - else - switch(virus_threat) - if(DISEASE_SEVERITY_UNCURABLE) - holder.icon_state = "hudill6" - if(DISEASE_SEVERITY_BIOHAZARD) - holder.icon_state = "hudill5" - if(DISEASE_SEVERITY_DANGEROUS) - holder.icon_state = "hudill4" - if(DISEASE_SEVERITY_HARMFUL) - holder.icon_state = "hudill3" - if(DISEASE_SEVERITY_MEDIUM) - holder.icon_state = "hudill2" - if(DISEASE_SEVERITY_MINOR) - holder.icon_state = "hudill1" - if(DISEASE_SEVERITY_NONTHREAT) - holder.icon_state = "hudill0" - if(DISEASE_SEVERITY_POSITIVE) - holder.icon_state = "hudbuff" - if(null) - holder.icon_state = "hudhealthy" - if(ishuman(src)) - var/mob/living/carbon/human/crew = src - var/obj/item/clothing/under/uniform = crew.w_uniform - if(uniform && uniform.has_sensor == BROKEN_SENSORS) - holder.icon_state = "hudnosensor" + if (!virus_threat) + set_hud_image_state(STATUS_HUD, "hudhealthy") + return TRUE + + switch(virus_threat) + if(DISEASE_SEVERITY_UNCURABLE) + set_hud_image_state(STATUS_HUD, "hudill6") + if(DISEASE_SEVERITY_BIOHAZARD) + set_hud_image_state(STATUS_HUD, "hudill5") + if(DISEASE_SEVERITY_DANGEROUS) + set_hud_image_state(STATUS_HUD, "hudill4") + if(DISEASE_SEVERITY_HARMFUL) + set_hud_image_state(STATUS_HUD, "hudill3") + if(DISEASE_SEVERITY_MEDIUM) + set_hud_image_state(STATUS_HUD, "hudill2") + if(DISEASE_SEVERITY_MINOR) + set_hud_image_state(STATUS_HUD, "hudill1") + if(DISEASE_SEVERITY_NONTHREAT) + set_hud_image_state(STATUS_HUD, "hudill0") + if(DISEASE_SEVERITY_POSITIVE) + set_hud_image_state(STATUS_HUD, "hudbuff") + return FALSE + +/mob/living/carbon/human/med_hud_set_status() + . = ..() + if (!.) + return + var/obj/item/clothing/under/uniform = w_uniform + if(istype(uniform) && uniform.has_sensor == BROKEN_SENSORS) + set_hud_image_state(STATUS_HUD, "hudnosensor") + return FALSE + /*********************************************** FAN HUDs! For identifying other fans on-sight. @@ -238,28 +233,22 @@ FAN HUDs! For identifying other fans on-sight. //HOOKS /mob/living/carbon/human/proc/fan_hud_set_fandom() - var/image/holder = hud_list[FAN_HUD] - holder.pixel_y = get_cached_height() - ICON_SIZE_Y - holder.icon_state = "hudfan_no" - var/obj/item/clothing/under/undershirt = w_uniform if(!istype(undershirt)) set_hud_image_inactive(FAN_HUD) return + set_hud_image_active(FAN_HUD) for(var/accessory in undershirt.attached_accessories) if(istype(accessory, /obj/item/clothing/accessory/mime_fan_pin)) - holder.icon_state = "mime_fan_pin" - break + set_hud_image_state(FAN_HUD, "mime_fan_pin") + return if(istype(accessory, /obj/item/clothing/accessory/clown_enjoyer_pin)) - holder.icon_state = "clown_enjoyer_pin" - break - - set_hud_image_active(FAN_HUD) - return - + set_hud_image_state(FAN_HUD, "clown_enjoyer_pin") + return + set_hud_image_state(FAN_HUD, "hudfan_no") /*********************************************** Security HUDs! Basic mode shows only the job. @@ -268,43 +257,31 @@ Security HUDs! Basic mode shows only the job. //HOOKS /mob/living/carbon/human/proc/sec_hud_set_ID() - var/image/holder = hud_list[ID_HUD] - holder.pixel_y = get_cached_height() - ICON_SIZE_Y var/sechud_icon_state = wear_id?.get_sechud_job_icon_state() if(!sechud_icon_state || HAS_TRAIT(src, TRAIT_UNKNOWN)) sechud_icon_state = "hudno_id" - holder.icon_state = sechud_icon_state + set_hud_image_state(ID_HUD, sechud_icon_state) sec_hud_set_security_status() /mob/living/proc/sec_hud_set_implants() - var/image/holder - for(var/i in (list(IMPSEC_FIRST_HUD, IMPLOYAL_HUD, IMPSEC_SECOND_HUD) & hud_list)) - holder = hud_list[i] - holder.icon_state = null - set_hud_image_inactive(i) + for(var/hud_type in (list(IMPSEC_FIRST_HUD, IMPLOYAL_HUD, IMPSEC_SECOND_HUD) & hud_list)) + set_hud_image_inactive(hud_type) var/security_slot = 1 //Which of the two security hud slots are we putting found security implants in? for(var/obj/item/implant/current_implant in implants) if(current_implant.implant_flags & IMPLANT_TYPE_SECURITY) switch(security_slot) if(1) - holder = hud_list[IMPSEC_FIRST_HUD] - holder.pixel_y = get_cached_height() - ICON_SIZE_Y - holder.icon_state = current_implant.hud_icon_state + set_hud_image_state(IMPSEC_FIRST_HUD, current_implant.hud_icon_state) set_hud_image_active(IMPSEC_FIRST_HUD) security_slot++ if(2) //Theoretically if we somehow get multiple sec implants, whatever the most recently implanted implant is will take over the 2nd position - holder = hud_list[IMPSEC_SECOND_HUD] - holder.pixel_y = get_cached_height() - ICON_SIZE_Y - holder.pixel_x = initial(holder.pixel_x) + (ICON_SIZE_X / 4 - 1) //Adds an offset that mirrors the hud blip to the other side of the mob. - holder.icon_state = current_implant.hud_icon_state + set_hud_image_state(IMPSEC_SECOND_HUD, current_implant.hud_icon_state, x_offset = (ICON_SIZE_X / 4 - 1)) //Adds an offset that mirrors the hud blip to the other side of the mob set_hud_image_active(IMPSEC_SECOND_HUD) if(HAS_TRAIT(src, TRAIT_MINDSHIELD)) - holder = hud_list[IMPLOYAL_HUD] - holder.pixel_y = get_cached_height() - ICON_SIZE_Y - holder.icon_state = "hud_imp_loyal" + set_hud_image_state(IMPLOYAL_HUD, "hud_imp_loyal") set_hud_image_active(IMPLOYAL_HUD) /mob/living/carbon/human/proc/sec_hud_set_security_status() @@ -312,38 +289,33 @@ Security HUDs! Basic mode shows only the job. // We haven't finished initializing yet, huds will be updated once we are return - var/image/holder = hud_list[WANTED_HUD] - holder.pixel_y = get_cached_height() - ICON_SIZE_Y - if (HAS_TRAIT(src, TRAIT_ALWAYS_WANTED)) - holder.icon_state = "hudwanted" + set_hud_image_state(WANTED_HUD, "hudwanted") set_hud_image_active(WANTED_HUD) return var/perp_name = get_face_name(get_id_name("")) if(!perp_name || !GLOB.manifest) - holder.icon_state = null set_hud_image_inactive(WANTED_HUD) return var/datum/record/crew/target = find_record(perp_name) if(!target || target.wanted_status == WANTED_NONE) - holder.icon_state = null set_hud_image_inactive(WANTED_HUD) return switch(target.wanted_status) if(WANTED_ARREST) - holder.icon_state = "hudwanted" + set_hud_image_state(WANTED_HUD, "hudwanted") if(WANTED_PRISONER) - holder.icon_state = "hudincarcerated" + set_hud_image_state(WANTED_HUD, "hudincarcerated") if(WANTED_SUSPECT) - holder.icon_state = "hudsuspected" + set_hud_image_state(WANTED_HUD, "hudsuspected") if(WANTED_PAROLE) - holder.icon_state = "hudparolled" + set_hud_image_state(WANTED_HUD, "hudparolled") if(WANTED_DISCHARGED) - holder.icon_state = "huddischarged" + set_hud_image_state(WANTED_HUD, "huddischarged") set_hud_image_active(WANTED_HUD) @@ -388,156 +360,131 @@ Diagnostic HUDs! //Sillycone hooks /mob/living/silicon/proc/diag_hud_set_health() - var/image/holder = hud_list[DIAG_HUD] - holder.pixel_y = get_cached_height() - ICON_SIZE_Y if(stat == DEAD) - holder.icon_state = "huddiagdead" + set_hud_image_state(DIAG_HUD, "huddiagdead") else - holder.icon_state = "huddiag[RoundDiagBar(health/maxHealth)]" + set_hud_image_state(DIAG_HUD, "huddiag[RoundDiagBar(health/maxHealth)]") /mob/living/silicon/proc/diag_hud_set_status() - var/image/holder = hud_list[DIAG_STAT_HUD] - holder.pixel_y = get_cached_height() - ICON_SIZE_Y switch(stat) if(CONSCIOUS) - holder.icon_state = "hudstat" + set_hud_image_state(DIAG_STAT_HUD, "hudstat") if(UNCONSCIOUS, HARD_CRIT) - holder.icon_state = "hudoffline" + set_hud_image_state(DIAG_STAT_HUD, "hudoffline") else - holder.icon_state = "huddead2" + set_hud_image_state(DIAG_STAT_HUD, "huddead2") //Borgie battery tracking! /mob/living/silicon/robot/proc/diag_hud_set_borgcell() - var/image/holder = hud_list[DIAG_BATT_HUD] - holder.pixel_y = get_cached_height() - ICON_SIZE_Y if(cell) var/chargelvl = (cell.charge/cell.maxcharge) - holder.icon_state = "hudbatt[RoundDiagBar(chargelvl)]" + set_hud_image_state(DIAG_BATT_HUD, "hudbatt[RoundDiagBar(chargelvl)]") else - holder.icon_state = "hudnobatt" + set_hud_image_state(DIAG_BATT_HUD, "hudnobatt") //borg-AI shell tracking -/mob/living/silicon/robot/proc/diag_hud_set_aishell() //Shows tracking beacons on the mech - var/image/holder = hud_list[DIAG_TRACK_HUD] - holder.pixel_y = get_cached_height() - ICON_SIZE_Y +/mob/living/silicon/robot/proc/diag_hud_set_aishell() //Shows if AI is controlling a cyborg via a BORIS module if(!shell) //Not an AI shell - holder.icon_state = null set_hud_image_inactive(DIAG_TRACK_HUD) return - else if(deployed) //AI shell in use by an AI - holder.icon_state = "hudtrackingai" + if(deployed) //AI shell in use by an AI + set_hud_image_state(DIAG_TRACK_HUD, "hudtrackingai") else //Empty AI shell - holder.icon_state = "hudtracking" + set_hud_image_state(DIAG_TRACK_HUD, "hudtracking") set_hud_image_active(DIAG_TRACK_HUD) //AI side tracking of AI shell control -/mob/living/silicon/ai/proc/diag_hud_set_deployed() //Shows tracking beacons on the mech - var/image/holder = hud_list[DIAG_TRACK_HUD] - holder.pixel_y = get_cached_height() - ICON_SIZE_Y +/mob/living/silicon/ai/proc/diag_hud_set_deployed() //Shows if AI is currently shunted into a BORIS borg if(!deployed_shell) - holder.icon_state = null set_hud_image_inactive(DIAG_TRACK_HUD) - else //AI is currently controlling a shell - holder.icon_state = "hudtrackingai" - set_hud_image_active(DIAG_TRACK_HUD) + return + //AI is currently controlling a shell + set_hud_image_state(DIAG_TRACK_HUD, "hudtrackingai") + set_hud_image_active(DIAG_TRACK_HUD) /*~~~~~~~~~~~~~~~~~~~~ BIG STOMPY MECHS ~~~~~~~~~~~~~~~~~~~~~*/ /obj/vehicle/sealed/mecha/proc/diag_hud_set_mechhealth() - var/image/holder = hud_list[DIAG_MECH_HUD] - holder.pixel_y = get_cached_height() - ICON_SIZE_Y - holder.icon_state = "huddiag[RoundDiagBar(atom_integrity/max_integrity)]" - + set_hud_image_state(DIAG_MECH_HUD, "huddiag[RoundDiagBar(atom_integrity/max_integrity)]") /obj/vehicle/sealed/mecha/proc/diag_hud_set_mechcell() - var/image/holder = hud_list[DIAG_BATT_HUD] - holder.pixel_y = get_cached_height() - ICON_SIZE_Y if(cell) var/chargelvl = cell.charge/cell.maxcharge - holder.icon_state = "hudbatt[RoundDiagBar(chargelvl)]" + set_hud_image_state(DIAG_BATT_HUD, "hudbatt[RoundDiagBar(chargelvl)]") else - holder.icon_state = "hudnobatt" + set_hud_image_state(DIAG_BATT_HUD, "hudnobatt") /obj/vehicle/sealed/mecha/proc/diag_hud_set_mechstat() - var/image/holder = hud_list[DIAG_STAT_HUD] - holder.pixel_y = get_cached_height() - ICON_SIZE_Y - if(internal_damage) - holder.icon_state = "hudwarn" - set_hud_image_active(DIAG_STAT_HUD) + if(!internal_damage) + set_hud_image_inactive(DIAG_STAT_HUD) return - holder.icon_state = null - set_hud_image_inactive(DIAG_STAT_HUD) + + set_hud_image_state(DIAG_STAT_HUD, "hudwarn") + set_hud_image_active(DIAG_STAT_HUD) ///Shows tracking beacons on the mech /obj/vehicle/sealed/mecha/proc/diag_hud_set_mechtracking() - var/image/holder = hud_list[DIAG_TRACK_HUD] - holder.pixel_y = get_cached_height() - ICON_SIZE_Y var/new_icon_state //This var exists so that the holder's icon state is set only once in the event of multiple mech beacons. - for(var/obj/item/mecha_parts/mecha_tracking/T in trackers) - if(T.ai_beacon) //Beacon with AI uplink + for(var/obj/item/mecha_parts/mecha_tracking/tracker in trackers) + if(tracker.ai_beacon) //Beacon with AI uplink new_icon_state = "hudtrackingai" break //Immediately terminate upon finding an AI beacon to ensure it is always shown over the normal one, as mechs can have several trackers. else new_icon_state = "hudtracking" - holder.icon_state = new_icon_state + set_hud_image_state(DIAG_TRACK_HUD, new_icon_state) ///Shows inbuilt camera on the mech; if the camera's view range was affected by an EMP, shows a red blip while it's affected /obj/vehicle/sealed/mecha/proc/diag_hud_set_camera() - var/image/holder = hud_list[DIAG_CAMERA_HUD] - holder.pixel_y = get_cached_height() - ICON_SIZE_Y - if(chassis_camera?.is_emp_scrambled) - holder.icon_state = "hudcamera_empd" + if(!chassis_camera) + set_hud_image_inactive(DIAG_CAMERA_HUD) return - holder.icon_state = "hudcamera" + + set_hud_image_active(DIAG_CAMERA_HUD) + if(chassis_camera?.is_emp_scrambled) + set_hud_image_state(DIAG_CAMERA_HUD, "hudcamera_empd") + else + set_hud_image_state(DIAG_CAMERA_HUD, "hudcamera") /*~~~~~~~~~ Bots! ~~~~~~~~~~*/ /mob/living/simple_animal/bot/proc/diag_hud_set_bothealth() - var/image/holder = hud_list[DIAG_HUD] - holder.pixel_y = get_cached_height() - ICON_SIZE_Y - holder.icon_state = "huddiag[RoundDiagBar(health/maxHealth)]" + set_hud_image_state(DIAG_HUD, "huddiag[RoundDiagBar(health/maxHealth)]") /mob/living/simple_animal/bot/proc/diag_hud_set_botstat() //On (With wireless on or off), Off, EMP'ed - var/image/holder = hud_list[DIAG_STAT_HUD] - holder.pixel_y = get_cached_height() - ICON_SIZE_Y if(bot_mode_flags & BOT_MODE_ON) - holder.icon_state = "hudstat" + set_hud_image_state(DIAG_STAT_HUD, "hudstat") else if(stat) //Generally EMP causes this - holder.icon_state = "hudoffline" + set_hud_image_state(DIAG_STAT_HUD, "hudoffline") else //Bot is off - holder.icon_state = "huddead2" + set_hud_image_state(DIAG_STAT_HUD, "huddead2") /mob/living/simple_animal/bot/proc/diag_hud_set_botmode() //Shows a bot's current operation - var/image/holder = hud_list[DIAG_BOT_HUD] - holder.pixel_y = get_cached_height() - ICON_SIZE_Y if(client) //If the bot is player controlled, it will not be following mode logic! - holder.icon_state = "hudsentient" + set_hud_image_state(DIAG_BOT_HUD, "hudsentient") return switch(mode) if(BOT_SUMMON, BOT_RESPONDING) //Responding to PDA or AI summons - holder.icon_state = "hudcalled" + set_hud_image_state(DIAG_BOT_HUD, "hudcalled") if(BOT_CLEANING, BOT_HEALING) //Cleanbot cleaning, repairbot fixing, or Medibot Healing - holder.icon_state = "hudworking" + set_hud_image_state(DIAG_BOT_HUD, "hudworking") if(BOT_PATROL, BOT_START_PATROL) //Patrol mode - holder.icon_state = "hudpatrol" + set_hud_image_state(DIAG_BOT_HUD, "hudpatrol") if(BOT_PREP_ARREST, BOT_ARREST, BOT_HUNT) //STOP RIGHT THERE, CRIMINAL SCUM! - holder.icon_state = "hudalert" + set_hud_image_state(DIAG_BOT_HUD, "hudalert") if(BOT_MOVING, BOT_DELIVER, BOT_GO_HOME, BOT_NAV) //Moving to target for normal bots, moving to deliver or go home for MULES. - holder.icon_state = "hudmove" + set_hud_image_state(DIAG_BOT_HUD, "hudmove") else - holder.icon_state = "" + set_hud_image_state(DIAG_BOT_HUD, "") /mob/living/simple_animal/bot/mulebot/proc/diag_hud_set_mulebotcell() - var/image/holder = hud_list[DIAG_BATT_HUD] - holder.pixel_y = get_cached_height() - ICON_SIZE_Y if(cell) var/chargelvl = (cell.charge/cell.maxcharge) - holder.icon_state = "hudbatt[RoundDiagBar(chargelvl)]" + set_hud_image_state(DIAG_BATT_HUD, "hudbatt[RoundDiagBar(chargelvl)]") else - holder.icon_state = "hudnobatt" + set_hud_image_state(DIAG_STAT_HUD, "hudnobatt") /*~~~~~~~~~~~~ Airlocks! @@ -575,3 +522,46 @@ Diagnostic HUDs! #undef CACHED_WIDTH_INDEX #undef CACHED_HEIGHT_INDEX + +/atom/proc/get_visual_width() + var/width = get_cached_width() + var/height = get_cached_height() + var/scale_list = list( + width * transform.a + height * transform.b + transform.c, + width * transform.a + transform.c, + height * transform.b + transform.c, + transform.c + ) + return max(scale_list) - min(scale_list) + +/atom/proc/get_visual_height() + var/width = get_cached_width() + var/height = get_cached_height() + var/scale_list = list( + width * transform.d + height * transform.e + transform.f, + width * transform.d + transform.f, + height * transform.e + transform.f, + transform.f + ) + return max(scale_list) - min(scale_list) + +/atom/proc/adjust_hud_position(image/holder, animate_time = null) + if (animate_time) + animate(holder, pixel_x = -(get_cached_width() - ICON_SIZE_X) / 2, pixel_y = get_cached_height() - ICON_SIZE_Y, time = animate_time) + return + holder.pixel_x = -(get_cached_width() - ICON_SIZE_X) / 2 + holder.pixel_y = get_cached_height() - ICON_SIZE_Y + +/atom/proc/set_hud_image_state(hud_type, hud_state, x_offset = 0, y_offset = 0) + if (!hud_list) // Still initializing + return + var/image/holder = hud_list[hud_type] + if (!holder) + return + if (!istype(holder)) // Can contain lists for HUD_LIST_LIST hinted HUDs, if someone fucks up and passes this here we wanna know about it + CRASH("[src] ([type]) had a HUD_LIST_LIST hud_type [hud_type] passed into set_hud_image_state!") + holder.icon_state = hud_state + adjust_hud_position(holder) + if (x_offset || y_offset) + holder.pixel_x += x_offset + holder.pixel_y += y_offset diff --git a/code/game/objects/effects/temporary_visuals/miscellaneous.dm b/code/game/objects/effects/temporary_visuals/miscellaneous.dm index 0df5c1baee6..491ab61d3f4 100644 --- a/code/game/objects/effects/temporary_visuals/miscellaneous.dm +++ b/code/game/objects/effects/temporary_visuals/miscellaneous.dm @@ -443,7 +443,7 @@ var/size_matrix = matrix() if(size_calc_target) layer = size_calc_target.layer + 0.01 - size_matrix = matrix() * (size_calc_target.get_cached_height()/ICON_SIZE_Y) + size_matrix = matrix() * (size_calc_target.get_visual_height() / ICON_SIZE_Y) transform = size_matrix //scale the bleed overlay's size based on the target's icon size var/matrix/M = transform if(shrink) diff --git a/code/modules/antagonists/abductor/equipment/gland.dm b/code/modules/antagonists/abductor/equipment/gland.dm index 02af10227e8..4b82067ddc5 100644 --- a/code/modules/antagonists/abductor/equipment/gland.dm +++ b/code/modules/antagonists/abductor/equipment/gland.dm @@ -49,14 +49,12 @@ /obj/item/organ/heart/gland/proc/update_gland_hud() if(!owner) return - var/image/holder = owner.hud_list[GLAND_HUD] - holder.pixel_y = owner.get_cached_height() - ICON_SIZE_Y if(active_mind_control) - holder.icon_state = "hudgland_active" + owner.set_hud_image_state(GLAND_HUD, "hudgland_active") else if(mind_control_uses) - holder.icon_state = "hudgland_ready" + owner.set_hud_image_state(GLAND_HUD, "hudgland_ready") else - holder.icon_state = "hudgland_spent" + owner.set_hud_image_state(GLAND_HUD, "hudgland_spent") /obj/item/organ/heart/gland/proc/mind_control(command, mob/living/user) if(!ownerCheck() || !mind_control_uses || active_mind_control) diff --git a/code/modules/antagonists/changeling/powers/transform.dm b/code/modules/antagonists/changeling/powers/transform.dm index b13b07f7f36..20519d2d8b7 100644 --- a/code/modules/antagonists/changeling/powers/transform.dm +++ b/code/modules/antagonists/changeling/powers/transform.dm @@ -139,10 +139,9 @@ /obj/item/changeling/id/equipped(mob/user, slot, initial) . = ..() - if(hud_icon) - var/image/holder = user.hud_list[ID_HUD] - holder.pixel_y = user.get_cached_height() - ICON_SIZE_Y - holder.icon_state = hud_icon + if(!hud_icon) + return + user.set_hud_image_state(ID_HUD, hud_icon) /** * Returns cached flat icon of the ID, creates one if there is not one already cached diff --git a/code/modules/mob/living/basic/bots/bot_hud.dm b/code/modules/mob/living/basic/bots/bot_hud.dm index 0edcaad6a7e..08a7f9e3fbb 100644 --- a/code/modules/mob/living/basic/bots/bot_hud.dm +++ b/code/modules/mob/living/basic/bots/bot_hud.dm @@ -1,39 +1,35 @@ /mob/living/basic/bot/proc/diag_hud_set_bothealth() - var/image/holder = hud_list[DIAG_HUD] - holder.pixel_y = get_cached_height() - ICON_SIZE_Y - holder.icon_state = "huddiag[RoundDiagBar(health/maxHealth)]" + set_hud_image_state(DIAG_HUD, "huddiag[RoundDiagBar(health/maxHealth)]") /mob/living/basic/bot/proc/diag_hud_set_botstat() //On (With wireless on or off), Off, EMP'ed - var/image/holder = hud_list[DIAG_STAT_HUD] - holder.pixel_y = get_cached_height() - ICON_SIZE_Y if(bot_mode_flags & BOT_MODE_ON) - holder.icon_state = "hudstat" + set_hud_image_state(DIAG_STAT_HUD, "hudstat") return + if(stat != CONSCIOUS) - holder.icon_state = "hudoffline" + set_hud_image_state(DIAG_STAT_HUD, "hudoffline") return - holder.icon_state = "huddead2" + + set_hud_image_state(DIAG_STAT_HUD, "huddead2") /mob/living/basic/bot/proc/diag_hud_set_botmode() //Shows a bot's current operation - var/image/holder = hud_list[DIAG_BOT_HUD] - holder.pixel_y = get_cached_height() - ICON_SIZE_Y if(client) //If the bot is player controlled, it will not be following mode logic! - holder.icon_state = "hudsentient" + set_hud_image_state(DIAG_BOT_HUD, "hudsentient") return switch(mode) if(BOT_SUMMON, BOT_RESPONDING) //Responding to PDA or AI summons - holder.icon_state = "hudcalled" + set_hud_image_state(DIAG_BOT_HUD, "hudcalled") if(BOT_CLEANING, BOT_HEALING) //Cleanbot cleaning, Floorbot fixing, or Medibot Healing - holder.icon_state = "hudworking" + set_hud_image_state(DIAG_BOT_HUD, "hudworking") if(BOT_PATROL, BOT_START_PATROL) //Patrol mode - holder.icon_state = "hudpatrol" + set_hud_image_state(DIAG_BOT_HUD, "hudpatrol") if(BOT_PREP_ARREST, BOT_ARREST, BOT_HUNT) //STOP RIGHT THERE, CRIMINAL SCUM! - holder.icon_state = "hudalert" + set_hud_image_state(DIAG_BOT_HUD, "hudalert") if(BOT_MOVING, BOT_DELIVER, BOT_GO_HOME, BOT_NAV) //Moving to target for normal bots, moving to deliver or go home for MULES. - holder.icon_state = "hudmove" + set_hud_image_state(DIAG_BOT_HUD, "hudmove") else - holder.icon_state = "" + set_hud_image_state(DIAG_BOT_HUD, "") ///proc that handles drawing and transforming the bot's path onto diagnostic huds /mob/living/basic/bot/proc/generate_bot_path(datum/move_loop/has_target/jps/source) diff --git a/code/modules/mob/living/basic/drone/_drone.dm b/code/modules/mob/living/basic/drone/_drone.dm index a0be86ecc6a..ba315dade64 100644 --- a/code/modules/mob/living/basic/drone/_drone.dm +++ b/code/modules/mob/living/basic/drone/_drone.dm @@ -219,19 +219,18 @@ listener.RegisterSignal(src, COMSIG_LIVING_REVIVE, TYPE_PROC_REF(/datum/alarm_listener, allow_alarm_changes)) /mob/living/basic/drone/med_hud_set_health() - var/image/holder = hud_list[DIAG_HUD] - holder.pixel_y = get_cached_height() - ICON_SIZE_Y - holder.icon_state = "huddiag[RoundDiagBar(health/maxHealth)]" + set_hud_image_state(DIAG_HUD, "huddiag[RoundDiagBar(health/maxHealth)]") /mob/living/basic/drone/med_hud_set_status() - var/image/holder = hud_list[DIAG_STAT_HUD] - holder.pixel_y = get_cached_height() - ICON_SIZE_Y if(stat == DEAD) - holder.icon_state = "huddead2" - else if(incapacitated) - holder.icon_state = "hudoffline" - else - holder.icon_state = "hudstat" + set_hud_image_state(DIAG_STAT_HUD, "huddead2") + return + + if(incapacitated) + set_hud_image_state(DIAG_STAT_HUD, "hudoffline") + return + + set_hud_image_state(DIAG_STAT_HUD, "hudstat") /mob/living/basic/drone/Destroy() GLOB.drones_list -= src diff --git a/code/modules/mob/living/basic/space_fauna/morph.dm b/code/modules/mob/living/basic/space_fauna/morph.dm index f205474af81..a7a3c147625 100644 --- a/code/modules/mob/living/basic/space_fauna/morph.dm +++ b/code/modules/mob/living/basic/space_fauna/morph.dm @@ -77,16 +77,14 @@ return ..() //we hide medical hud while in regular state or an item - var/image/holder = hud_list[HEALTH_HUD] - holder.icon_state = null + set_hud_image_state(HEALTH_HUD, null) /mob/living/basic/morph/med_hud_set_status() if(isliving(form_typepath)) return ..() //we hide medical hud while in regular state or an item - var/image/holder = hud_list[STATUS_HUD] - holder.icon_state = null + set_hud_image_state(STATUS_HUD, null) /mob/living/basic/morph/death(gibbed) if(HAS_TRAIT(src, TRAIT_DISGUISED)) diff --git a/code/modules/mob/living/basic/space_fauna/space_dragon/space_dragon.dm b/code/modules/mob/living/basic/space_fauna/space_dragon/space_dragon.dm index b1acd8f9631..662242ce60f 100644 --- a/code/modules/mob/living/basic/space_fauna/space_dragon/space_dragon.dm +++ b/code/modules/mob/living/basic/space_fauna/space_dragon/space_dragon.dm @@ -74,7 +74,7 @@ AddElement(/datum/element/content_barfer) AddElement(/datum/element/wall_tearer, tear_time = 4 SECONDS, reinforced_multiplier = 3, do_after_key = DOAFTER_SOURCE_SPACE_DRAGON_INTERACTION) AddElement(/datum/element/door_pryer, pry_time = 4 SECONDS, interaction_key = DOAFTER_SOURCE_SPACE_DRAGON_INTERACTION) - AddComponent(/datum/component/seethrough_mob) + AddComponent(/datum/component/seethrough_mob, keep_color = TRUE) AddComponent(/datum/component/profound_fisher, new /obj/item/fishing_rod/mob_fisher/dragon(src)) RegisterSignal(src, COMSIG_HOSTILE_PRE_ATTACKINGTARGET, PROC_REF(pre_attack)) RegisterSignal(src, COMSIG_MOB_STATCHANGE, PROC_REF(on_stat_changed)) diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index bd3f4cd5db5..6274f08c612 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -1380,7 +1380,7 @@ /// Special carbon interaction on lying down, to transform its sprite by a rotation. /mob/living/carbon/proc/lying_angle_on_lying_down(new_lying_angle) if(!new_lying_angle) - set_lying_angle(pick(90, 270)) + set_lying_angle(pick(LYING_ANGLE_EAST, LYING_ANGLE_WEST)) else set_lying_angle(new_lying_angle) diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index 70607a983ee..6077a845477 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -480,12 +480,12 @@ if(SOUTH) animate(M, pixel_x = target_pixel_x, pixel_y = target_pixel_y - offset, 3) if(EAST) - if(M.lying_angle == 270) //update the dragged dude's direction if we've turned - M.set_lying_angle(90) + if(M.lying_angle == LYING_ANGLE_WEST) //update the dragged dude's direction if we've turned + M.set_lying_angle(LYING_ANGLE_EAST) animate(M, pixel_x = target_pixel_x + offset, pixel_y = target_pixel_y, 3) if(WEST) - if(M.lying_angle == 90) - M.set_lying_angle(270) + if(M.lying_angle == LYING_ANGLE_EAST) + M.set_lying_angle(LYING_ANGLE_WEST) animate(M, pixel_x = target_pixel_x - offset, pixel_y = target_pixel_y, 3) /mob/living/proc/reset_pull_offsets(mob/living/M, override) @@ -731,7 +731,6 @@ if(rotate_on_lying) body_position_pixel_y_offset = PIXEL_Y_OFFSET_LYING - /// Proc to append behavior related to lying down. /mob/living/proc/on_standing_up() if(layer == LYING_MOB_LAYER) @@ -1046,9 +1045,9 @@ ///Called by mob Move() when the lying_angle is different than zero, to better visually simulate crawling. /mob/living/proc/lying_angle_on_movement(direct) if(direct & EAST) - set_lying_angle(90) + set_lying_angle(LYING_ANGLE_EAST) else if(direct & WEST) - set_lying_angle(270) + set_lying_angle(LYING_ANGLE_WEST) /mob/living/carbon/alien/adult/lying_angle_on_movement(direct) return @@ -2618,8 +2617,7 @@ GLOBAL_LIST_EMPTY(fire_appearances) on_fall() if(body_position == STANDING_UP) //force them on the ground set_body_position(LYING_DOWN) - set_lying_angle(pick(90, 270)) - + set_lying_angle(pick(LYING_ANGLE_EAST, LYING_ANGLE_WEST)) /// Proc to append behavior to the condition of being floored. Called when the condition ends. /mob/living/proc/on_floored_end() diff --git a/code/modules/mob/living/living_update_icons.dm b/code/modules/mob/living/living_update_icons.dm index 4e8b809e047..20f36ab96b0 100644 --- a/code/modules/mob/living/living_update_icons.dm +++ b/code/modules/mob/living/living_update_icons.dm @@ -61,7 +61,12 @@ ADD_TRAIT(src, TRAIT_NO_FLOATING_ANIM, UPDATE_TRANSFORM_TRAIT) addtimer(TRAIT_CALLBACK_REMOVE(src, TRAIT_NO_FLOATING_ANIM, UPDATE_TRANSFORM_TRAIT), 0.3 SECONDS, TIMER_UNIQUE|TIMER_OVERRIDE) //if true, we want to avoid any animation time, it'll tween and not rotate at all otherwise. - var/is_opposite_angle = SIMPLIFY_DEGREES(lying_angle+180) == lying_prev - animate(src, transform = ntransform, time = is_opposite_angle ? 0 : UPDATE_TRANSFORM_ANIMATION_TIME, pixel_y = final_pixel_y, dir = final_dir, easing = (EASE_IN|EASE_OUT)) + 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, pixel_y = final_pixel_y, dir = final_dir, easing = (EASE_IN|EASE_OUT)) + 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) diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index acc14dc7a00..6be0304fda4 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -179,7 +179,7 @@ else var/image/I = image('icons/mob/huds/hud.dmi', src, "") - I.appearance_flags = RESET_COLOR|RESET_TRANSFORM + I.appearance_flags = RESET_COLOR|PIXEL_SCALE|KEEP_APART hud_list[hud] = I set_hud_image_active(hud, update_huds = FALSE) //by default everything is active. but dont add it to huds to keep control. diff --git a/code/modules/power/solar.dm b/code/modules/power/solar.dm index 1823f086228..4cd1692cc3e 100644 --- a/code/modules/power/solar.dm +++ b/code/modules/power/solar.dm @@ -170,7 +170,7 @@ // actually flip to other direction? if(abs(angle - azimuth_current) > 180) - mid_azimuth = reverse_angle(mid_azimuth) + mid_azimuth = REVERSE_ANGLE(mid_azimuth) // Split into 2 parts so it doesn't distort on large changes animate(part, diff --git a/code/modules/power/tracker.dm b/code/modules/power/tracker.dm index 0855e63ed4b..4b103080b16 100644 --- a/code/modules/power/tracker.dm +++ b/code/modules/power/tracker.dm @@ -90,7 +90,7 @@ // actually flip to other direction? if(abs(angle - azimuth_current) > 180) - mid_azimuth = reverse_angle(mid_azimuth) + mid_azimuth = REVERSE_ANGLE(mid_azimuth) // Split into 2 parts so it doesn't distort on large changes animate(part,