From 52a066371a92dc03aefad3fb9a55ac2e13d5be07 Mon Sep 17 00:00:00 2001 From: Benjamin <9423435+benbot16@users.noreply.github.com> Date: Wed, 10 Jun 2026 10:11:33 -0700 Subject: [PATCH] Fixes borg/drone lights and adds some emissives. (#22602) This PR fixes the intent-based lights and emissives on silicons (borgs/drones). It also adds an emissive to the combat shielding robot module, since it seems logical for that module to have it, and adds a slight emissive to robots in emergency power mode to differentiate between the out-of-power and disabled states. Due to issues with tables in particular, a drone's emissives will be disabled when it hides to prevent through-table emissive displays. Robots with various states below: Top: dead/out of power Bottom: normal/hidden drone/unhidden drone/milborg with shield image --- .../signals/signals_mob/signals_mob_main.dm | 3 + code/modules/mob/living/living_powers.dm | 1 + .../mob/living/silicon/robot/drone/drone.dm | 25 +++++---- .../silicon/robot/drone/drone_abilities.dm | 9 +++ .../robot/items/modules/robot_shield.dm | 10 +++- code/modules/mob/living/silicon/robot/life.dm | 8 ++- .../modules/mob/living/silicon/robot/robot.dm | 13 ++++- .../mob/living/silicon/robot/robot_helpers.dm | 56 +++++++++++++------ html/changelogs/benbot16-eyefix.yml | 15 +++++ 9 files changed, 107 insertions(+), 33 deletions(-) create mode 100644 html/changelogs/benbot16-eyefix.yml diff --git a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_main.dm b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_main.dm index e692d92b97f..1f0e8e9fa28 100644 --- a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_main.dm +++ b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_main.dm @@ -49,6 +49,9 @@ /// Sent from /mob/proc/update_canmove() when the mob transitions into lying down. #define COMSIG_MOB_LYING_DOWN "mob_lying_down" +/// Sent from /mob/living/proc/hide(). Sent after the mob's layer is updated. +#define COMSIG_MOB_ON_HIDE "mob_on_hide" + /// From /obj/item/organ/external/take_damage. Updates the limb's colour matrix. Very laggy, so we do it on reaction to stuff. #define COMSIG_UPDATE_LIMB_IMAGE "update_limb_image" diff --git a/code/modules/mob/living/living_powers.dm b/code/modules/mob/living/living_powers.dm index fa6d664207c..8fe22cebac0 100644 --- a/code/modules/mob/living/living_powers.dm +++ b/code/modules/mob/living/living_powers.dm @@ -12,6 +12,7 @@ else layer = MOB_LAYER to_chat(src, SPAN_NOTICE("You have stopped hiding.")) + SEND_SIGNAL(src, COMSIG_MOB_ON_HIDE) /mob/living/verb/set_walk_speed() set category = "IC.Maneuver" diff --git a/code/modules/mob/living/silicon/robot/drone/drone.dm b/code/modules/mob/living/silicon/robot/drone/drone.dm index 0b8ab25b3ce..c0723e651d8 100644 --- a/code/modules/mob/living/silicon/robot/drone/drone.dm +++ b/code/modules/mob/living/silicon/robot/drone/drone.dm @@ -94,6 +94,7 @@ default_language = GLOB.all_languages[LANGUAGE_LOCAL_DRONE] add_verb(src, /mob/living/proc/hide) + RegisterSignal(src, COMSIG_MOB_ON_HIDE, PROC_REF(on_hide)) remove_language(LANGUAGE_ROBOT) add_language(LANGUAGE_ROBOT, FALSE) add_language(LANGUAGE_DRONE, TRUE) @@ -297,29 +298,31 @@ /mob/living/silicon/robot/drone/setup_eye_cache() cached_eye_overlays = list( - I_HELP = image(icon, "[icon_state]-eyes_help"), - I_HURT = image(icon, "[icon_state]-eyes_harm"), - "emag" = image(icon, "[icon_state]-eyes_emag") + I_HELP = mutable_appearance(icon, "[icon_state]-eyes_help"), + I_HURT = mutable_appearance(icon, "[icon_state]-eyes_harm"), + "emag" = mutable_appearance(icon, "[icon_state]-eyes_emag") ) if(eye_overlay) - CutOverlays(eye_overlay) + CutOverlays(list(eye_overlay, eye_emissive)) eye_overlay = cached_eye_overlays[a_intent] - AddOverlays(eye_overlay) + // Disables emissives while hiding due to table-clipping issues + eye_emissive = (layer == MOB_LAYER ? emissive_appearance(icon, "[icon_state]-eyes_help") : null) + AddOverlays(list(eye_overlay, eye_emissive)) /mob/living/silicon/robot/drone/setup_panel_cache() cached_panel_overlays = list( - ROBOT_PANEL_EXPOSED = image(icon, "[icon_state]-openpanel+w"), - ROBOT_PANEL_CELL = image(icon, "[icon_state]-openpanel+c"), - ROBOT_PANEL_NO_CELL = image(icon, "[icon_state]-openpanel-c") + ROBOT_PANEL_EXPOSED = mutable_appearance(icon, "[icon_state]-openpanel+w"), + ROBOT_PANEL_CELL = mutable_appearance(icon, "[icon_state]-openpanel+c"), + ROBOT_PANEL_NO_CELL = mutable_appearance(icon, "[icon_state]-openpanel-c") ) /mob/living/silicon/robot/drone/set_intent(var/set_intent) a_intent = set_intent - CutOverlays(eye_overlay) + CutOverlays(list(eye_overlay, eye_emissive)) if(!stat) eye_overlay = cached_eye_overlays[emagged ? "emag" : set_intent] - AddOverlays(eye_overlay) + AddOverlays(list(eye_overlay, eye_emissive)) /mob/living/silicon/robot/drone/choose_icon() return @@ -411,7 +414,7 @@ to_chat(src, "Obey these laws:") laws.show_laws(src) to_chat(src, SPAN_DANGER("ALERT: [user.real_name] is your new master. Obey your new laws and their commands.")) - set_intent(I_HURT) // force them to hurt to update the eyes, they can swap to and fro if they wish, though - geeves + set_intent(a_intent) // Send an intent update so their eyes change to "emag" return TRUE /mob/living/silicon/robot/drone/proc/ai_hack(var/mob/user) diff --git a/code/modules/mob/living/silicon/robot/drone/drone_abilities.dm b/code/modules/mob/living/silicon/robot/drone/drone_abilities.dm index a2830a7ce76..8229ffb9158 100644 --- a/code/modules/mob/living/silicon/robot/drone/drone_abilities.dm +++ b/code/modules/mob/living/silicon/robot/drone/drone_abilities.dm @@ -1,4 +1,8 @@ // DRONE ABILITIES + +/** + * Sets a drone's mail tag, allowing it to traverse the mail system like a package would. + */ /mob/living/silicon/robot/drone/verb/set_mail_tag() set name = "Set Mail Tag" set desc = "Tag yourself for delivery through the disposals system." @@ -19,6 +23,11 @@ to_chat(src, SPAN_NOTICE("\The [D] acknowledges your signal.")) D.flush_count = D.flush_every_ticks +/// Override to allow us to process our eye cache +/mob/living/silicon/robot/drone/proc/on_hide() + SIGNAL_HANDLER + setup_eye_cache() + /mob/living/silicon/robot/drone/mouse_drop_dragged(atom/over, mob/user, src_location, over_location, params) var/mob/living/carbon/H = over if(!istype(H) || !Adjacent(H)) diff --git a/code/modules/mob/living/silicon/robot/items/modules/robot_shield.dm b/code/modules/mob/living/silicon/robot/items/modules/robot_shield.dm index ff6c2f35a1b..a555b3d7567 100644 --- a/code/modules/mob/living/silicon/robot/items/modules/robot_shield.dm +++ b/code/modules/mob/living/silicon/robot/items/modules/robot_shield.dm @@ -1,4 +1,7 @@ -//Personal shielding for the combat module. +/** + * Personal shield for the military robot module. + * Deploys an energy shield that blocks a configurable percentage of damage using a robot's internal cell. + */ /obj/item/borg/combat/shield name = "personal shielding" desc = "A powerful experimental module that turns aside or absorbs incoming attacks at the cost of charge." @@ -8,10 +11,11 @@ /obj/item/borg/combat/shield/on_module_activate(mob/living/silicon/robot/R) R.shield_overlay = image(R.icon, "[R.module_sprites[R.icontype][ROBOT_CHASSIS]]-shield") - R.AddOverlays(R.shield_overlay) + R.shield_emissive = emissive_appearance(R.icon, "[R.module_sprites[R.icontype][ROBOT_CHASSIS]]-shield") + R.AddOverlays(list(R.shield_overlay, R.shield_emissive)) /obj/item/borg/combat/shield/on_module_deactivate(mob/living/silicon/robot/R) - R.CutOverlays(R.shield_overlay) + R.CutOverlays(list(R.shield_overlay, R.shield_emissive)) /obj/item/borg/combat/shield/verb/set_shield_level() set name = "Set shield level" diff --git a/code/modules/mob/living/silicon/robot/life.dm b/code/modules/mob/living/silicon/robot/life.dm index 8151b6c41ec..6e4da71c644 100644 --- a/code/modules/mob/living/silicon/robot/life.dm +++ b/code/modules/mob/living/silicon/robot/life.dm @@ -17,10 +17,16 @@ if(stat) CutOverlays(eye_overlay) has_cut_eye_overlay = TRUE + if(stat == DEAD) // Leave a bit of glow in the eyes while we're on backup power + CutOverlays(eye_emissive) + has_cut_eye_emissive = TRUE else if(has_cut_eye_overlay) eye_overlay = cached_eye_overlays[a_intent] AddOverlays(eye_overlay) - has_cut_eye_overlay = null + has_cut_eye_overlay = FALSE + if(has_cut_eye_emissive) + AddOverlays(eye_emissive) + has_cut_eye_emissive = FALSE if(stat != DEAD) //still using power use_power() process_killswitch() diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm index f4ca8cb60e0..332414665e0 100644 --- a/code/modules/mob/living/silicon/robot/robot.dm +++ b/code/modules/mob/living/silicon/robot/robot.dm @@ -129,13 +129,24 @@ ) // Overlays + /// Used to keep track of our eye_overlay when we remove it due to being offline/depowered var/has_cut_eye_overlay + /// Used to keep track of our eye_emissive overlay, so that it can be removed/added seperately from the eye overlay. + var/has_cut_eye_emissive + /// The robot's active eye overlay var/image/eye_overlay + /// The robot's active eye emissive + var/image/eye_emissive + /// A list of cached eye overlays relevant to the robot's current module var/list/image/cached_eye_overlays = list() + /// The robot's active panel overlay, used when a robot is open and undergoing maintenance var/image/panel_overlay + /// A list of cached panel overlays relevant to the robot's current module. var/list/image/cached_panel_overlays = list() + /// The robot's active shield overlay. Used by the military module's shielding systems. var/image/shield_overlay - var/datum/weakref/holo_map + /// The robot's active shield emissive. + var/image/shield_emissive /mob/living/silicon/robot/Initialize(mapload, unfinished = FALSE) spark_system = bind_spark(src, 5) diff --git a/code/modules/mob/living/silicon/robot/robot_helpers.dm b/code/modules/mob/living/silicon/robot/robot_helpers.dm index 55b970565eb..ac635108dc5 100644 --- a/code/modules/mob/living/silicon/robot/robot_helpers.dm +++ b/code/modules/mob/living/silicon/robot/robot_helpers.dm @@ -1,14 +1,21 @@ +/** + * Sets our eyes to match our a_intent if we have that set up, and builds the eye cache if we haven't gotten that built yet + */ /mob/living/silicon/robot/set_intent(var/set_intent) a_intent = set_intent - CutOverlays(eye_overlay) + CutOverlays(list(eye_overlay, eye_emissive)) if(!length(module_sprites)) return if(!length(cached_eye_overlays)) setup_eye_cache() if(!stat) eye_overlay = cached_eye_overlays[a_intent] - AddOverlays(eye_overlay) + AddOverlays(list(eye_overlay, eye_emissive)) +/** + * Handles updating the panel's sprite on the robot. + * panel_overlay is scoped to the robot. + */ /mob/living/silicon/robot/proc/handle_panel_overlay() CutOverlays(panel_overlay) if(!length(cached_panel_overlays)) @@ -28,41 +35,53 @@ setup_eye_cache() setup_panel_cache() +/** + * Creates a list of mutable_appearances and emissive_appearances for our robot indexed by intent. + * eye_overlay is scoped to the robot. + */ /mob/living/silicon/robot/proc/setup_eye_cache() if(!module_sprites?[icontype]?[ROBOT_EYES]) return - var/eye_plane = src.plane - if(layer == MOB_LAYER) // In case you're hiding. So eyes don't go through tables. - eye_plane = MOB_EMISSIVE_LAYER var/eyeprefix = module_sprites[icontype][ROBOT_EYES] + var/cached_eye_emissive if(speed == -2) // For combat drones with the mobility module. cached_eye_overlays = list( - I_HELP = image(icon, "[eyeprefix]-roll-eyes_help"), - I_HURT = image(icon, "[eyeprefix]-roll-eyes_harm") + I_HELP = mutable_appearance(icon, "[eyeprefix]-roll-eyes_help"), + I_HURT = mutable_appearance(icon, "[eyeprefix]-roll-eyes_harm") ) + cached_eye_emissive = emissive_appearance(icon, "[eyeprefix]-roll-eyes_help") else cached_eye_overlays = list( - I_HELP = image(icon, "[eyeprefix]-eyes_help"), //Changed so icontype goes in front. Helps with parsing in this godforsaken engine known as BYOND. - I_HURT = image(icon, "[eyeprefix]-eyes_harm") + I_HELP = mutable_appearance(icon, "[eyeprefix]-eyes_help"), + I_HURT = mutable_appearance(icon, "[eyeprefix]-eyes_harm") ) - if(eye_overlay) - CutOverlays(eye_overlay) + cached_eye_emissive = emissive_appearance(icon, "[eyeprefix]-eyes_help") + if(eye_overlay) // We should always have both an eye_overlay and an eye_emissive. + CutOverlays(list(eye_overlay, eye_emissive)) eye_overlay = cached_eye_overlays[a_intent] - eye_overlay.plane = eye_plane - AddOverlays(eye_overlay) + eye_emissive = cached_eye_emissive + AddOverlays(list(eye_overlay, eye_emissive)) + +/** + * Creates a list of panel appearances for our robot based on the current state of the robot's panel. + * If the robot doesn't have a panel, we don't create the cache. + */ /mob/living/silicon/robot/proc/setup_panel_cache() if(!length(module_sprites)) return if(!module_sprites?[icontype]?[ROBOT_PANEL]) return - var/panelprefix = custom_sprite ? src.ckey : module_sprites[icontype][ROBOT_PANEL] // Shoutout to Geeves. + var/panelprefix = custom_sprite ? src.ckey : module_sprites[icontype][ROBOT_PANEL] cached_panel_overlays = list( - ROBOT_PANEL_EXPOSED = image(icon, "[panelprefix]-openpanel+w"), - ROBOT_PANEL_CELL = image(icon, "[panelprefix]-openpanel+c"), - ROBOT_PANEL_NO_CELL = image(icon, "[panelprefix]-openpanel-c") + ROBOT_PANEL_EXPOSED = mutable_appearance(icon, "[panelprefix]-openpanel+w"), + ROBOT_PANEL_CELL = mutable_appearance(icon, "[panelprefix]-openpanel+c"), + ROBOT_PANEL_NO_CELL = mutable_appearance(icon, "[panelprefix]-openpanel-c") ) +/** + * Handles module activation/deactivation effects. + */ /mob/living/silicon/robot/proc/set_module_active(var/obj/item/given_module) if(module_active) module_active.on_module_deactivate(src) @@ -70,6 +89,9 @@ if(given_module) given_module.on_module_activate(src) +/** + * Handles module storing effects and clears up the module's icon. + */ /mob/living/silicon/robot/proc/store_module(var/obj/item/stored_module) stored_module.on_module_store(src) stored_module.loc = module diff --git a/html/changelogs/benbot16-eyefix.yml b/html/changelogs/benbot16-eyefix.yml new file mode 100644 index 00000000000..aecc6c40bb7 --- /dev/null +++ b/html/changelogs/benbot16-eyefix.yml @@ -0,0 +1,15 @@ +# Your name. +author: Benbot16 + +# Optional: Remove this file after generating master changelog. Useful for PR changelogs that won't get used again. +delete-after: True + +# Any changes you've made. See valid prefix list above. +# INDENT WITH TWO SPACES. NOT TABS. SPACES. +# SCREW THIS UP AND IT WON'T WORK. +# Also, this gets changed to [] after reading. Just remove the brackets when you add new shit. +# Please surround your changes in double quotes ("). It works without them, but if you use certain characters it screws up compiling. The quotes will not show up in the changelog. +changes: + - bugfix: "Fixed borg/drone lights and emissives not displaying properly." + - rscadd: "Adds emissives to borg shielding systems." + - bugfix: "Drones now disable emissives while hiding, preventing them from being visible through tables."