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
🆑
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
/🆑
This commit is contained in:
SmArtKar
2024-12-26 15:06:04 +01:00
committed by GitHub
parent e8d0611341
commit 8d48f8d4d2
21 changed files with 228 additions and 250 deletions
+3
View File
@@ -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.
+4
View File
@@ -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)))
-4
View File
@@ -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
+3 -11
View File
@@ -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)
+4 -4
View File
@@ -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]"
@@ -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
+2 -2
View File
@@ -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)
+161 -171
View File
@@ -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
@@ -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)
@@ -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)
@@ -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
+13 -17
View File
@@ -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)
+9 -10
View File
@@ -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
@@ -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))
@@ -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))
+1 -1
View File
@@ -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)
+7 -9
View File
@@ -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()
@@ -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)
+1 -1
View File
@@ -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.
+1 -1
View File
@@ -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,
+1 -1
View File
@@ -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,