From 16aef3a2fd640e6cd97f5704aaaf5959d75921c3 Mon Sep 17 00:00:00 2001 From: SmArtKar <44720187+SmArtKar@users.noreply.github.com> Date: Thu, 2 Apr 2026 21:20:55 +0200 Subject: [PATCH] Completely refactors HUD element management and datumizes inventory HUDs (#95119) ## About The Pull Request This is a port/revival of Kapu's https://github.com/DaedalusDock/daedalusdock/pull/883 By god, please TM this for a while, as HUDs are rather volatile and I might've missed something (also the original PR had harddel issues, so we should probably be on the lookout for those) Instead of being stored in a metric ton of separate variables, all HUD elements are now kept in a ``key -> element`` assoc list, and separate category lists have been turned into a single ``group_key -> list of elements`` assoc list for easier management. This massively simplifies HUD creation and management, and allows us to sanely dynamically modify HUDs without having to keep track of our elements ourselves (harddel fuel) I've also noticed that plasma vessels had... interesting, to say the least, way of managing their HUD and in humans were unable to display it, which I've changed (the element itself is displayed below stamina in non-aliens, as latter occupies the spot where you'd normally see it) Also fixes a bunch of minor unlikely to occur issues with HUD not updating when it should've sometimes. ## Why It's Good For The Game The two most important results of this is that A) we can fix the issue with items larger than 32x32 not displaying properly in inventories (in a separate PR) and B) this paves the way for datumized inventory slots, although that is a separate nightmare Some of this code is also actually over a decade old, and is an absolute nightmare to work with. ## Changelog :cl: qol: Non-aliens with an implanted plasma vessel now see their plasma level in their HUD instead of just the stat panel refactor: Refactored the entirety of HUD management code, report if anything breaks! /:cl: --------- Co-authored-by: John Willard <53777086+JohnFulpWillard@users.noreply.github.com> --- code/__DEFINES/hud.dm | 165 +++- code/__DEFINES/sight.dm | 1 + code/_onclick/hud/action_group.dm | 209 +++++ code/_onclick/hud/ai.dm | 365 +-------- code/_onclick/hud/alien.dm | 142 +--- code/_onclick/hud/alien_larva.dm | 64 +- code/_onclick/hud/blob_overmind.dm | 208 +---- code/_onclick/hud/drones.dm | 45 +- code/_onclick/hud/generic_dextrous.dm | 84 +- code/_onclick/hud/ghost.dm | 208 +---- code/_onclick/hud/guardian.dm | 193 +---- code/_onclick/hud/hud.dm | 602 +++++--------- code/_onclick/hud/human.dm | 473 ++++------- code/_onclick/hud/inventory_slot.dm | 35 + code/_onclick/hud/living.dm | 46 +- code/_onclick/hud/new_player.dm | 739 +----------------- code/_onclick/hud/ooze.dm | 12 +- code/_onclick/hud/pai.dm | 33 + code/_onclick/hud/parallax/parallax.dm | 2 - code/_onclick/hud/perks.dm | 35 - .../rendering/plane_masters/_plane_master.dm | 3 - code/_onclick/hud/revenanthud.dm | 15 +- code/_onclick/hud/robot.dm | 266 +------ .../hud/{ => screen_objects}/action_button.dm | 35 +- code/_onclick/hud/screen_objects/ai.dm | 250 ++++++ .../hud/{ => screen_objects}/alert.dm | 0 code/_onclick/hud/screen_objects/alien.dm | 24 + code/_onclick/hud/screen_objects/blob.dm | 164 ++++ .../hud/{ => screen_objects}/credits.dm | 0 .../hud/{ => screen_objects}/fullscreen.dm | 0 code/_onclick/hud/screen_objects/ghost.dm | 149 ++++ code/_onclick/hud/screen_objects/guardian.dm | 68 ++ code/_onclick/hud/screen_objects/human.dm | 77 ++ .../hud/{ => screen_objects}/map_popups.dm | 0 .../hud/{ => screen_objects}/map_view.dm | 0 .../movable_screen_objects.dm | 0 .../_onclick/hud/screen_objects/new_player.dm | 724 +++++++++++++++++ .../hud/screen_objects/pai.dm} | 124 +-- code/_onclick/hud/screen_objects/perks.dm | 29 + .../picture_in_picture.dm | 0 .../hud/{ => screen_objects}/radial.dm | 0 .../{ => screen_objects}/radial_persistent.dm | 0 code/_onclick/hud/screen_objects/robot.dm | 113 +++ .../screen_object_holder.dm | 0 .../{ => screen_objects}/screen_objects.dm | 64 +- .../hud/{ => screen_objects}/screentip.dm | 0 .../voidwalker.dm} | 29 +- code/_onclick/hud/soulscythe.dm | 5 +- code/_onclick/hud/voidwalker.dm | 14 + code/datums/actions/action.dm | 2 +- code/datums/components/crafting/crafting.dm | 31 +- code/datums/components/food/edible.dm | 4 +- code/datums/components/fov_handler.dm | 5 +- code/datums/components/life_link.dm | 5 +- code/datums/components/style/style.dm | 40 +- .../datums/elements/attack_zone_randomiser.dm | 4 +- code/datums/keybinding/living.dm | 8 +- code/datums/martial/_martial.dm | 26 +- code/datums/mood.dm | 22 +- .../status_effects/debuffs/screwy_hud.dm | 2 +- code/datums/storage/storage.dm | 16 +- code/datums/wounds/bones.dm | 2 +- code/datums/wounds/cranial_fissure.dm | 2 +- code/datums/wounds/slash.dm | 2 +- .../machinery/computer/operating_computer.dm | 4 +- .../machinery/computer/records/records.dm | 2 +- code/game/objects/items/devices/multitool.dm | 22 +- code/modules/antagonists/blob/overmind.dm | 22 +- .../blood_worm/blood_worm_host_handling.dm | 16 +- .../antagonists/blood_worm/blood_worm_mob.dm | 3 - .../antagonists/changeling/changeling.dm | 51 +- .../changeling/powers/tiny_prick.dm | 17 +- .../antagonists/cult/datums/cult_team.dm | 3 +- .../heretic/heretic_living_heart.dm | 25 +- .../heretic/items/heretic_armor.dm | 36 +- .../equipment/spellbook_entries/perks.dm | 36 +- code/modules/antagonists/wizard/wizard.dm | 2 - code/modules/client/preferences.dm | 4 +- .../clothing/spacesuits/_spacesuits.dm | 24 +- code/modules/engineering/tools/multitool.dm | 11 - code/modules/escape_menu/escape_menu.dm | 3 - code/modules/mob/dead/observer/observer.dm | 5 +- code/modules/mob/inventory.dm | 10 +- .../living/basic/blob_minions/blobbernaut.dm | 11 +- .../basic/space_fauna/revenant/_revenant.dm | 2 +- .../living/carbon/alien/adult/alien_powers.dm | 7 +- .../living/carbon/alien/adult/caste/hunter.dm | 4 +- .../modules/mob/living/carbon/alien/organs.dm | 53 +- .../modules/mob/living/carbon/alien/screen.dm | 53 +- code/modules/mob/living/carbon/carbon.dm | 31 +- .../mob/living/carbon/carbon_update_icons.dm | 10 +- .../mob/living/carbon/human/_species.dm | 6 +- code/modules/mob/living/carbon/human/human.dm | 2 +- .../carbon/human/species_types/vampire.dm | 14 +- code/modules/mob/living/living.dm | 54 +- code/modules/mob/living/living_defense.dm | 3 +- code/modules/mob/living/living_fov.dm | 2 + .../mob/living/living_item_handling.dm | 4 +- code/modules/mob/living/silicon/death.dm | 19 +- .../mob/living/silicon/robot/inventory.dm | 55 +- code/modules/mob/living/silicon/robot/life.dm | 37 +- .../modules/mob/living/silicon/robot/robot.dm | 19 +- .../mob/living/silicon/robot/robot_defines.dm | 15 - .../mob/living/simple_animal/hostile/ooze.dm | 10 +- code/modules/mob/mob.dm | 12 +- code/modules/mob/mob_movement.dm | 28 +- code/modules/mod/mod_control.dm | 8 +- .../reagents/reagent_containers/cups/_cup.dm | 4 +- .../research/xenobiology/xenobio_camera.dm | 69 +- .../surgery/bodyparts/dismemberment.dm | 2 +- code/modules/surgery/bodyparts/parts.dm | 6 +- .../organs/internal/stomach/_stomach.dm | 8 +- code/modules/unit_tests/unequip_defib.dm | 2 +- code/modules/unit_tests/unit_test.dm | 5 +- icons/hud/screen_changeling.dmi | Bin 6755 -> 7108 bytes icons/mob/actions/actions_changeling.dmi | Bin 24497 -> 11025 bytes tgstation.dme | 45 +- 117 files changed, 3218 insertions(+), 3663 deletions(-) create mode 100644 code/_onclick/hud/action_group.dm create mode 100644 code/_onclick/hud/inventory_slot.dm create mode 100644 code/_onclick/hud/pai.dm delete mode 100644 code/_onclick/hud/perks.dm rename code/_onclick/hud/{ => screen_objects}/action_button.dm (97%) create mode 100644 code/_onclick/hud/screen_objects/ai.dm rename code/_onclick/hud/{ => screen_objects}/alert.dm (100%) create mode 100644 code/_onclick/hud/screen_objects/alien.dm create mode 100644 code/_onclick/hud/screen_objects/blob.dm rename code/_onclick/hud/{ => screen_objects}/credits.dm (100%) rename code/_onclick/hud/{ => screen_objects}/fullscreen.dm (100%) create mode 100644 code/_onclick/hud/screen_objects/ghost.dm create mode 100644 code/_onclick/hud/screen_objects/guardian.dm create mode 100644 code/_onclick/hud/screen_objects/human.dm rename code/_onclick/hud/{ => screen_objects}/map_popups.dm (100%) rename code/_onclick/hud/{ => screen_objects}/map_view.dm (100%) rename code/_onclick/hud/{ => screen_objects}/movable_screen_objects.dm (100%) create mode 100644 code/_onclick/hud/screen_objects/new_player.dm rename code/{modules/pai/hud.dm => _onclick/hud/screen_objects/pai.dm} (57%) create mode 100644 code/_onclick/hud/screen_objects/perks.dm rename code/_onclick/hud/{ => screen_objects}/picture_in_picture.dm (100%) rename code/_onclick/hud/{ => screen_objects}/radial.dm (100%) rename code/_onclick/hud/{ => screen_objects}/radial_persistent.dm (100%) create mode 100644 code/_onclick/hud/screen_objects/robot.dm rename code/_onclick/hud/{ => screen_objects}/screen_object_holder.dm (100%) rename code/_onclick/hud/{ => screen_objects}/screen_objects.dm (96%) rename code/_onclick/hud/{ => screen_objects}/screentip.dm (100%) rename code/_onclick/hud/{voidwalkerhud.dm => screen_objects/voidwalker.dm} (73%) create mode 100644 code/_onclick/hud/voidwalker.dm delete mode 100644 code/modules/engineering/tools/multitool.dm diff --git a/code/__DEFINES/hud.dm b/code/__DEFINES/hud.dm index afea0d10c93..75e42833694 100644 --- a/code/__DEFINES/hud.dm +++ b/code/__DEFINES/hud.dm @@ -22,6 +22,155 @@ /// Largest viewport possible, required for checking if someone can see an object #define LARGEST_VIEWPORT_SIZE WIDESCREEN_VIEWPORT_SIZE +// Hud group keys +/// Static elements that are always present in standard hud +#define HUD_GROUP_STATIC 1 +/// Inventory elements toggled by the inventory switch +#define HUD_GROUP_TOGGLEABLE_INVENTORY 2 +/// Info display HUD elements +#define HUD_GROUP_INFO 3 +/// Permanently on-screen elements, regardless of your HUD status +#define HUD_GROUP_SCREEN_OVERLAYS 4 +/// Hotkey buttons +#define HUD_GROUP_HOTKEYS 5 +/// Open storages and items in them +#define HUD_GROUP_STORAGE 6 +/// Total amount of screen groups in use +#define SCREEN_GROUP_AMT 6 + +// Hud keys for accessing hud objects +#define HUD_MOB_TOGGLE_PALETTE "mob_toggle_palette" +#define HUD_MOB_PALETTE_UP "mob_palette_up" +#define HUD_MOB_PALETTE_DOWN "mob_palette_down" +#define HUD_MOB_SCREENTIP "mob_screentips" +#define HUD_MOB_HEALTH "mob_health" +#define HUD_MOB_LANGUAGE_MENU "mob_language" +#define HUD_MOB_NAVIGATE_MENU "mob_navigate" +#define HUD_MOB_INTENTS "mob_intents" +#define HUD_MOB_MOVE_INTENT "mob_move_intent" +#define HUD_MOB_ZONE_SELECTOR "mob_zonesel" +#define HUD_MOB_PULL "mob_pull" +#define HUD_MOB_DROP "mob_drop" +#define HUD_MOB_THROW "mob_throw" +#define HUD_MOB_HUNGER "mob_hunger" +#define HUD_MOB_STAMINA "mob_stamina" +#define HUD_MOB_SPACESUIT "mob_spacesuit" +#define HUD_MOB_COMBO "mob_combo" +#define HUD_MOB_RESIST "mob_resist" +#define HUD_MOB_REST "mob_rest" +#define HUD_MOB_SLEEP "mob_sleep" +#define HUD_MOB_AREA_CREATOR "mob_area_creator" +#define HUD_MOB_SWAPHAND_1 "mob_swaphand1" +#define HUD_MOB_SWAPHAND_2 "mob_swaphand2" +#define HUD_MOB_CRAFTING_MENU "mob_crafting" +#define HUD_MOB_FLOOR_CHANGER "mob_floor_changer" +#define HUD_MOB_BLOOD_LEVEL "mob_blood_level" +#define HUD_MOB_FOV_BLOCKER "mob_fov_blocker" +#define HUD_MOB_STYLE_METER "mob_style_meter" +#define HUD_MOB_MOOD "mob_mood" +#define HUD_MOB_HEALTHDOLL "mob_healthdoll" +#define HUD_MOB_MEMORIES "mob_memories" + +#define HUD_OOZE_NUTRITION_DISPLAY "ooze_nutrition_display" + +#define HUD_HUMAN_TOGGLE_INVENTORY "human_toggle_inventory" + +#define HUD_NEW_PLAYER_START_NOW "new_player_start_now" +#define HUD_NEW_PLAYER_SIGN_UP "newp_layer_sign_up" +#define HUD_KEY_NEW_PLAYER(slot) "newplayer_hud:[slot]" + +#define HUD_SILICON_TAKE_IMAGE "silicon_camera" +#define HUD_SILICON_TABLET "silicon_tablet" +#define HUD_SILICON_ALERTS "silicon_alerts" + +#define HUD_CYBORG_LAMP "cyborg_lamp" +#define HUD_CYBORG_HANDS "cyborg_module" +#define HUD_CYBORG_RADIO "cyborg_radio" +#define HUD_CYBORG_DEATH "cyborg_death" +#define HUD_KEY_CYBORG_MODULE(slot) "cyborg_module:[slot]" + +#define HUD_AI_FLOOR_INDICATOR "ai_floor_indicator" +#define HUD_AI_GO_UP "ai_go_up" +#define HUD_AI_GO_DOWN "ai_go_down" +#define HUD_AI_AICORE "ai_core" +#define HUD_AI_CAMERA_LIST "ai_camera_list" +#define HUD_AI_CAMERA_TRACK "ai_camera_track" +#define HUD_AI_CAMERA_LIGHT "ai_camera_light" +#define HUD_AI_CREW_MONITOR "ai_crew_monitor" +#define HUD_AI_CREW_MANIFEST "ai_crew_manifest" +#define HUD_AI_ANNOUNCEMENT "ai_announce" +#define HUD_AI_CALL_SHUTTLE "ai_shuttle" +#define HUD_AI_STATE_LAWS "ai_state_laws" +#define HUD_AI_TAKE_IMAGE "ai_take_image" +#define HUD_AI_IMAGE_VIEW "ai_view_image" +#define HUD_AI_SENSORS "ai_sensors" +#define HUD_AI_MULTICAM "ai_view_multicam" +#define HUD_AI_ADD_MULTICAM "ai_add_multicam" + +#define HUD_PAI_SOFTWARE "paisoftware" +#define HUD_PAI_SHELL "paishell" +#define HUD_PAI_CHASSIS "paichassis" +#define HUD_PAI_NEWSCASTER "painewscaster" +#define HUD_PAI_HOST_MONITOR "paimonitor" +#define HUD_PAI_GPS "paigps" + +#define HUD_GHOST_SPAWNERS "ghost_spawners" +#define HUD_GHOST_ORBIT "ghost_orbit" +#define HUD_GHOST_REENTER_CORPSE "ghost_corpse" +#define HUD_GHOST_TELEPORT "ghost_teleport" +#define HUD_GHOST_PAI "ghost_pai" +#define HUD_GHOST_MINIGAMES "ghost_minigames" +#define HUD_GHOST_DNR "ghost_dnr" +#define HUD_GHOST_SETTINGS "ghost_settings" +#define HUD_KEY_GHOST_HUDBOX(slot) "ghost_hudbox:[slot]" + +#define HUD_ALIEN_QUEEN_FINDER "alien_queen_finder" +#define HUD_ALIEN_PLASMA_DISPLAY "alien_plasma_display" +#define HUD_ALIEN_HUNTER_LEAP "alien_hunter_leap" + +#define HUD_BLOB_POWER_DISPLAY "blob_power_display" +#define HUD_BLOB_JUMP_TO_CORE "blob_jump_to_core" +#define HUD_BLOB_JUMP_TO_NODE "blob_jump_to_node" +#define HUD_BLOB_BLOBBERNAUT "blob_blobbernaut" +#define HUD_BLOB_RESOURCES "blob_resources" +#define HUD_BLOB_NODE "blob_node" +#define HUD_BLOB_FACTORY "blob_factory" +#define HUD_BLOB_READAPT "blob_readapt" +#define HUD_BLOB_RELOCATE "blob_relocate" + +#define HUD_BLOBBERNAUT_OVERMIND "blobbernaut_overmind" + +#define HUD_GUARDIAN_MANIFEST "guardian_manifest" +#define HUD_GUARDIAN_RECALL "guardian_recall" +#define HUD_GUARDIAN_LIGHT "guardian_light" +#define HUD_GUARDIAN_COMMUNICATE "guardian_communicate" +#define HUD_GUARDIAN_TOGGLE "guardian_toggle" + +#define HUD_VOIDWALKER_SPACE_CAMO "voidwalker_space_camo" +#define HUD_VOIDWALKER_VOID_JUMP "voidwalker_void_jump" + +#define HUD_CHANGELING_CHEMS "changeling_chems" +#define HUD_CHANGELING_STING "changeling_sting" + +#define HUD_CULTIST_ARROW "cultist_arrow" + +#define HUD_HERETIC_ARROW "heretic_arrow" +#define HUD_HERETIC_MOON_HEALTH "heretic_moon_health" + +#define HUD_WIZARD_COMPACT_PERKS "wizard_compact_perks" +#define HUD_WIZARD_PERK(slot) "wizard_perk:[slot]" + +/// Converts item slots to hud keys +#define HUD_KEY_ITEM_SLOT(slot) "item_slot:[slot]" +/// Converts item slots to hud keys as a compiler constant +#define HUD_KEY_ITEM_SLOT_CONST(slot) "item_slot:" + #slot +/// Hand2hudkey +#define HUD_KEY_HAND_SLOT(slot) "hand_slot:[slot]" + +#define HUD_MULTITOOL_ARROW "multitool_arrow" + +#define HUD_XENOBIO_CONSOLE "xenobio_console" + /* These defines specificy screen locations. For more information, see the byond documentation on the screen_loc var. @@ -63,7 +212,7 @@ #define ui_combo "CENTER+4:24,SOUTH+1:7" //combo meter for martial arts //Lower right, persistent menu -#define ui_rest "EAST-1:28,SOUTH+1:7" +#define ui_below_throw "EAST-1:28,SOUTH+1:7" #define ui_drop_throw "EAST-1:28,SOUTH+1:24" #define ui_above_throw "EAST-1:28,SOUTH+1:41" #define ui_above_movement "EAST-2:26,SOUTH+1:7" @@ -71,7 +220,6 @@ #define ui_above_intent "EAST-3:24, SOUTH+1:7" #define ui_movi "EAST-2:26,SOUTH:5" #define ui_acti "EAST-3:24,SOUTH:5" -#define ui_combat_toggle "EAST-3:24,SOUTH:5" #define ui_floor_change "BOTTOM+1:8,RIGHT-1:28" #define ui_zonesel "EAST-1:28,SOUTH:5" #define ui_acti_alt "EAST-1:28,SOUTH:5" //alternative intent switcher for when the interface is hidden (F12) @@ -123,7 +271,7 @@ #define ui_human_navigate "EAST-3:7,SOUTH+1:7" #define ui_human_language "EAST-3:7,SOUTH+1:24" #define ui_human_area "EAST-3:24,SOUTH+1:24" -#define ui_human_memories_area "EAST-4:22,SOUTH+1:7" +#define ui_human_memories_menu "EAST-4:22,SOUTH+1:7" //Drones #define ui_drone_drop "CENTER+1:18,SOUTH:5" @@ -158,6 +306,7 @@ #define ui_alien_navigate_menu "EAST-4:6,SOUTH:5" #define ui_alien_memories_menu "EAST-4:22,SOUTH:1:20" #define ui_alien_floor_change "EAST-3:24,SOUTH:20" +#define ui_alienplasmadisplay_human "EAST,CENTER-5:8" //AI #define ui_ai_core "BOTTOM:6,RIGHT-4" @@ -206,12 +355,12 @@ #define ui_ghost_spawners_menu "SOUTH:6,CENTER-3:24" #define ui_ghost_orbit "SOUTH:6,CENTER-2:24" #define ui_ghost_reenter_corpse "SOUTH:6,CENTER-1:24" -#define ui_dnr "SOUTH:6,CENTER:24" +#define ui_ghost_dnr "SOUTH:6,CENTER:24" #define ui_ghost_teleport "SOUTH:6,CENTER+1:24" -#define ui_ghost_settings "SOUTH: 6, CENTER+2:24" -#define ui_ghost_minigames "SOUTH: 6, CENTER+3:24" -#define ui_ghost_language_menu "SOUTH: 6, CENTER+4:22" -#define ui_ghost_floor_changer "SOUTH: 6, CENTER+4:7" +#define ui_ghost_settings "SOUTH:6,CENTER+2:24" +#define ui_ghost_minigames "SOUTH:6,CENTER+3:24" +#define ui_ghost_language_menu "SOUTH:6,CENTER+4:22" +#define ui_ghost_floor_changer "SOUTH:6,CENTER+4:7" //Voidwalker #define ui_voidwalker_left_of_hands "CENTER+-2:16,SOUTH+0:5" diff --git a/code/__DEFINES/sight.dm b/code/__DEFINES/sight.dm index 0a14db75ef9..ab88e6e2c30 100644 --- a/code/__DEFINES/sight.dm +++ b/code/__DEFINES/sight.dm @@ -76,4 +76,5 @@ #define INVISIBILITY_SOURCE_INVISIMIN "invisimin" #define INVISIBILITY_SOURCE_STEALTHMODE "stealthmode" +#define INVISIBILITY_SOURCE_SLEEP_HUD_BUTTON "sleep_hud_button" diff --git a/code/_onclick/hud/action_group.dm b/code/_onclick/hud/action_group.dm new file mode 100644 index 00000000000..a8766516b23 --- /dev/null +++ b/code/_onclick/hud/action_group.dm @@ -0,0 +1,209 @@ +/datum/action_group + /// The hud we're owned by + var/datum/hud/owner + /// The actions we're managing + var/list/atom/movable/screen/movable/action_button/actions + /// The initial vertical offset of our action buttons + var/north_offset = 0 + /// The pixel vertical offset of our action buttons + var/pixel_north_offset = 0 + /// Max amount of buttons we can have per row + /// Indexes at 1 + var/column_max = 0 + /// How far "ahead" of the first row we start. Lets us "scroll" our rows + /// Indexes at 1 + var/row_offset = 0 + /// How many rows of actions we can have at max before we just stop hiding + /// Indexes at 1 + var/max_rows = INFINITY + /// The screen location we go by + var/location + /// Our landing screen object + var/atom/movable/screen/action_landing/landing + +/datum/action_group/New(datum/hud/owner) + ..() + actions = list() + src.owner = owner + +/datum/action_group/Destroy() + owner = null + QDEL_NULL(landing) + QDEL_LIST(actions) + return ..() + +/datum/action_group/proc/insert_action(atom/movable/screen/action, index) + if(action in actions) + if(actions[index] == action) + return + actions -= action // Don't dupe, come on + if(!index) + index = length(actions) + 1 + index = min(length(actions) + 1, index) + actions.Insert(index, action) + refresh_actions() + +/datum/action_group/proc/remove_action(atom/movable/screen/action) + actions -= action + refresh_actions() + +/datum/action_group/proc/refresh_actions() + + // We don't use size() here because landings are not canon + var/total_rows = ROUND_UP(length(actions) / column_max) + total_rows -= max_rows // Lets get the amount of rows we're off from our max + row_offset = clamp(row_offset, 0, total_rows) // You're not allowed to offset so far that we have a row of blank space + + var/button_number = 0 + for(var/atom/movable/screen/button as anything in actions) + var/postion = ButtonNumberToScreenCoords(button_number ) + button.screen_loc = postion + button_number++ + + if(landing) + var/postion = ButtonNumberToScreenCoords(button_number, landing = TRUE) // Need a good way to count buttons off screen, but allow this to display in the right place if it's being placed with no concern for dropdown + landing.screen_loc = postion + button_number++ + +/// Accepts a number represeting our position in the group, indexes at 0 to make the math nicer +/datum/action_group/proc/ButtonNumberToScreenCoords(number, landing = FALSE) + var/row = round(number / column_max) + row -= row_offset // If you're less then 0, you don't get to render, this lets us "scroll" rows ya feel? + if(row < 0) + return null + + // Could use >= here, but I think it's worth noting that the two start at different places, since row is based on number here + if(row > max_rows - 1) + if(!landing) // If you're not a landing, go away please. thx + return null + // We always want to render landings, even if their action button can't be displayed. + // So we set a row equal to the max amount of rows + 1. Willing to overrun that max slightly to properly display the landing spot + row = max_rows // Remembering that max_rows indexes at 1, and row indexes at 0 + + // We're going to need to set our column to match the first item in the last row, so let's set number properly now + number = row * column_max + + var/visual_row = row + north_offset + var/coord_row = visual_row ? "-[visual_row]" : "+0" + + var/visual_column = number % column_max + var/coord_col = "+[visual_column]" + var/coord_col_offset = 4 + 2 * (visual_column + 1) + return "WEST[coord_col]:[coord_col_offset],NORTH[coord_row]:-[pixel_north_offset]" + +/datum/action_group/proc/check_against_view() + var/owner_view = owner?.mymob?.canon_client?.view + if(!owner_view) + return + // Unlikey as it is, we may have been changed. Want to start from our target position and fail down + column_max = initial(column_max) + // Convert our viewer's view var into a workable offset + var/list/view_size = view_to_pixels(owner_view) + + // We're primarially concerned about width here, if someone makes us 1x2000 I wish them a swift and watery death + var/furthest_screen_loc = ButtonNumberToScreenCoords(column_max - 1) + var/list/offsets = screen_loc_to_offset(furthest_screen_loc, owner_view) + if(offsets[1] > ICON_SIZE_X && offsets[1] < view_size[1] && offsets[2] > ICON_SIZE_Y && offsets[2] < view_size[2]) // We're all good + return + + for(column_max in column_max - 1 to 1 step -1) // Yes I could do this by unwrapping ButtonNumberToScreenCoords, but I don't feel like it + var/tested_screen_loc = ButtonNumberToScreenCoords(column_max) + offsets = screen_loc_to_offset(tested_screen_loc, owner_view) + // We've found a valid max length, pack it in + if(offsets[1] > ICON_SIZE_X && offsets[1] < view_size[1] && offsets[2] > ICON_SIZE_Y && offsets[2] < view_size[2]) + break + // Use our newly resized column max + refresh_actions() + +/// Returns the amount of objects we're storing at the moment +/datum/action_group/proc/size() + var/amount = length(actions) + if(landing) + amount += 1 + return amount + +/datum/action_group/proc/index_of(atom/movable/screen/get_location) + return actions.Find(get_location) + +/// Generates a landing object that can be dropped on to join this group +/datum/action_group/proc/generate_landing() + if(landing) + return + landing = new() + landing.set_owner(src) + refresh_actions() + +/// Clears any landing objects we may currently have +/datum/action_group/proc/clear_landing() + QDEL_NULL(landing) + +/datum/action_group/proc/update_landing() + if(!landing) + return + landing.refresh_owner() + +/datum/action_group/proc/scroll(amount) + row_offset += amount + refresh_actions() + +/datum/action_group/palette + north_offset = 2 + column_max = 3 + max_rows = 3 + location = SCRN_OBJ_IN_PALETTE + +/datum/action_group/palette/insert_action(atom/movable/screen/action, index) + . = ..() + var/atom/movable/screen/button_palette/palette = owner.screen_objects[HUD_MOB_TOGGLE_PALETTE] + palette.play_item_added() + +/datum/action_group/palette/remove_action(atom/movable/screen/action) + . = ..() + var/atom/movable/screen/button_palette/palette = owner.screen_objects[HUD_MOB_TOGGLE_PALETTE] + palette.play_item_removed() + if(!length(actions)) + palette.set_expanded(FALSE) + +/datum/action_group/palette/refresh_actions() + var/atom/movable/screen/button_palette/palette = owner.screen_objects[HUD_MOB_TOGGLE_PALETTE] + var/atom/movable/screen/palette_scroll/scroll_down = owner.screen_objects[HUD_MOB_PALETTE_DOWN] + var/atom/movable/screen/palette_scroll/scroll_up = owner.screen_objects[HUD_MOB_PALETTE_UP] + + var/actions_above = round((owner.listed_actions.size() - 1) / owner.listed_actions.column_max) + north_offset = initial(north_offset) + actions_above + + palette.screen_loc = ui_action_palette_offset(actions_above) + var/action_count = length(owner?.mymob?.actions) + var/our_row_count = round((length(actions) - 1) / column_max) + if(!action_count) + palette.screen_loc = null + + if(palette.expanded && action_count && our_row_count >= max_rows) + scroll_down.screen_loc = ui_palette_scroll_offset(actions_above) + scroll_up.screen_loc = ui_palette_scroll_offset(actions_above) + else + scroll_down.screen_loc = null + scroll_up.screen_loc = null + + return ..() + +/datum/action_group/palette/ButtonNumberToScreenCoords(number, landing) + var/atom/movable/screen/button_palette/palette = owner.screen_objects[HUD_MOB_TOGGLE_PALETTE] + if(palette.expanded) + return ..() + + if(!landing) + return null + + // We only render the landing in this case, so we force it to be the second item displayed (Second rather then first since it looks nicer) + // Remember the number var indexes at 0 + return ..(1 + (row_offset * column_max), landing) + +/datum/action_group/listed + pixel_north_offset = 6 + column_max = 10 + location = SCRN_OBJ_IN_LIST + +/datum/action_group/listed/refresh_actions() + . = ..() + owner?.palette_actions.refresh_actions() // We effect them, so we gotta refresh em diff --git a/code/_onclick/hud/ai.dm b/code/_onclick/hud/ai.dm index 728439e5fad..84e303a8894 100644 --- a/code/_onclick/hud/ai.dm +++ b/code/_onclick/hud/ai.dm @@ -1,345 +1,26 @@ -/atom/movable/screen/ai - icon = 'icons/hud/screen_ai.dmi' - mouse_over_pointer = MOUSE_HAND_POINTER - -/atom/movable/screen/ai/Click() - if(isobserver(usr) || usr.incapacitated) - return TRUE - -/atom/movable/screen/ai/aicore - name = "AI core" - icon_state = "ai_core" - -/atom/movable/screen/ai/aicore/Click() - if(isobserver(usr)) - return - var/mob/living/silicon/ai/AI = usr - AI.view_core() - -/atom/movable/screen/ai/camera_list - name = "Show Camera List" - icon_state = "camera" - -/atom/movable/screen/ai/camera_list/Click() - if(..()) - return - var/mob/living/silicon/ai/AI = usr - AI.show_camera_list() - -/atom/movable/screen/ai/camera_track - name = "Track With Camera" - icon_state = "track" - -/atom/movable/screen/ai/camera_track/Click() - . = ..() - if(.) - return - var/mob/living/silicon/ai/AI = usr - AI.ai_camera_track() - -/atom/movable/screen/ai/camera_light - name = "Toggle Camera Light" - icon_state = "camera_light" - -/atom/movable/screen/ai/camera_light/Click() - if(..()) - return - var/mob/living/silicon/ai/AI = usr - AI.toggle_camera_light() - -/atom/movable/screen/ai/modpc - name = "Messenger" - icon_state = "pda_send" - var/mob/living/silicon/ai/robot - -/atom/movable/screen/ai/modpc/Click() - . = ..() - if(.) - return - robot.modularInterface?.interact(robot) - -/atom/movable/screen/ai/crew_monitor - name = "Crew Monitoring Console" - icon_state = "crew_monitor" - -/atom/movable/screen/ai/crew_monitor/Click() - if(..()) - return - var/mob/living/silicon/ai/AI = usr - GLOB.crewmonitor.show(AI,AI) - -/atom/movable/screen/ai/crew_manifest - name = "Crew Manifest" - icon_state = "manifest" - -/atom/movable/screen/ai/crew_manifest/Click() - if(..()) - return - var/mob/living/silicon/ai/AI = usr - AI.ai_roster() - -/atom/movable/screen/ai/alerts - name = "Show Alerts" - icon_state = "alerts" - -/atom/movable/screen/ai/alerts/Click() - if(..()) - return - var/mob/living/silicon/ai/AI = usr - AI.alert_control.ui_interact(AI) - -/atom/movable/screen/ai/announcement - name = "Make Vox Announcement" - icon_state = "announcement" - -/atom/movable/screen/ai/announcement/Click() - if(..()) - return - var/mob/living/silicon/ai/AI = usr - AI.announcement() - -/atom/movable/screen/ai/call_shuttle - name = "Call Emergency Shuttle" - icon_state = "call_shuttle" - -/atom/movable/screen/ai/call_shuttle/Click() - if(..()) - return - var/mob/living/silicon/ai/AI = usr - AI.ai_call_shuttle() - -/atom/movable/screen/ai/state_laws - name = "State Laws" - icon_state = "state_laws" - -/atom/movable/screen/ai/state_laws/Click() - if(..()) - return - var/mob/living/silicon/ai/AI = usr - AI.checklaws() - -/atom/movable/screen/ai/image_take - name = "Take Image" - icon_state = "take_picture" - -/atom/movable/screen/ai/image_take/Click() - if(..()) - return - if(isAI(usr)) - var/mob/living/silicon/ai/AI = usr - AI.aicamera.toggle_camera_mode(usr) - else if(iscyborg(usr)) - var/mob/living/silicon/robot/R = usr - R.aicamera.toggle_camera_mode(usr) - -/atom/movable/screen/ai/image_view - name = "View Images" - icon_state = "view_images" - -/atom/movable/screen/ai/image_view/Click() - if(..()) - return - if(isAI(usr)) - var/mob/living/silicon/ai/AI = usr - AI.aicamera.viewpictures(usr) - -/atom/movable/screen/ai/sensors - name = "Sensor Augmentation" - icon_state = "ai_sensor" - -/atom/movable/screen/ai/sensors/Click() - if(..()) - return - var/mob/living/silicon/S = usr - S.toggle_sensors() - -/atom/movable/screen/ai/multicam - name = "Multicamera Mode" - icon_state = "multicam" - -/atom/movable/screen/ai/multicam/Click() - if(..()) - return - var/mob/living/silicon/ai/AI = usr - AI.toggle_multicam() - -/atom/movable/screen/ai/add_multicam - name = "New Camera" - icon_state = "new_cam" - -/atom/movable/screen/ai/add_multicam/Click() - if(..()) - return - var/mob/living/silicon/ai/AI = usr - AI.drop_new_multicam() - -/atom/movable/screen/ai/floor_indicator - icon_state = "zindicator" - screen_loc = ui_ai_floor_indicator - -/atom/movable/screen/ai/floor_indicator/Initialize(mapload, datum/hud/hud_owner) - . = ..() - if(istype(hud_owner)) - RegisterSignal(hud_owner, COMSIG_HUD_OFFSET_CHANGED, PROC_REF(update_z)) - update_z() - -/atom/movable/screen/ai/floor_indicator/proc/update_z(datum/hud/source) - SIGNAL_HANDLER - var/mob/living/silicon/ai/ai = get_mob() //if you use this for anyone else i will find you - if(isnull(ai)) - return - var/turf/locturf = isturf(ai.loc) ? get_turf(ai.eyeobj) : get_turf(ai) //must be a var cuz error - var/ai_z = locturf.z - var/text = "Level
[ai_z]" - if(SSmapping.level_trait(ai_z, ZTRAIT_STATION)) - text = "Floor
[ai_z - 1]" - else if (SSmapping.level_trait(ai_z, ZTRAIT_NOPHASE)) - text = "ERROR" - maptext = MAPTEXT_TINY_UNICODE("
[text]
") - -/atom/movable/screen/ai/go_up - name = "go up" - icon_state = "up" - screen_loc = ui_ai_godownup - -/atom/movable/screen/ai/go_up/Initialize(mapload) - . = ..() - register_context() - -/atom/movable/screen/ai/go_up/add_context(atom/source, list/context, obj/item/held_item, mob/user) - . = ..() - context[SCREENTIP_CONTEXT_LMB] = "Go up a floor" - return CONTEXTUAL_SCREENTIP_SET - -/atom/movable/screen/ai/go_up/Click(location,control,params) - var/mob/ai = get_mob() //the core - flick("uppressed",src) - if(!isturf(ai.loc) || usr != ai) //aicard and stuff - return - ai.up() - -/atom/movable/screen/ai/go_up/down - name = "go down" - icon_state = "down" - -/atom/movable/screen/ai/go_up/down/add_context(atom/source, list/context, obj/item/held_item, mob/user) - . = ..() - context[SCREENTIP_CONTEXT_LMB] = "Go down a floor" - return CONTEXTUAL_SCREENTIP_SET - -/atom/movable/screen/ai/go_up/down/Click(location,control,params) - var/mob/ai = get_mob() //the core - flick("downpressed",src) - if(!isturf(ai.loc) || usr != ai) //aicard and stuff - return - ai.down() - /datum/hud/ai ui_style = 'icons/hud/screen_ai.dmi' -/datum/hud/ai/New(mob/owner) - ..() - var/atom/movable/screen/using - var/mob/living/silicon/ai/myai = mymob - -// Language menu - using = new /atom/movable/screen/language_menu(null, src) - using.icon = ui_style - using.screen_loc = ui_ai_language_menu - static_inventory += using - -// Memories - using = new /atom/movable/screen/memories(null, src) - using.icon = ui_style - using.screen_loc = ui_ai_memories_menu - static_inventory += using - -// Z-level floor change - using = new /atom/movable/screen/ai/floor_indicator(null, src) //These come with their own predefined screen locs - static_inventory += using - using = new /atom/movable/screen/ai/go_up(null, src) - static_inventory += using - using = new /atom/movable/screen/ai/go_up/down(null, src) - static_inventory += using - -//AI core - using = new /atom/movable/screen/ai/aicore(null, src) - using.screen_loc = ui_ai_core - static_inventory += using - -//Camera list - using = new /atom/movable/screen/ai/camera_list(null, src) - using.screen_loc = ui_ai_camera_list - static_inventory += using - -//Track - using = new /atom/movable/screen/ai/camera_track(null, src) - using.screen_loc = ui_ai_track_with_camera - static_inventory += using - -//Camera light - using = new /atom/movable/screen/ai/camera_light(null, src) - using.screen_loc = ui_ai_camera_light - static_inventory += using - -//Crew Monitoring - using = new /atom/movable/screen/ai/crew_monitor(null, src) - using.screen_loc = ui_ai_crew_monitor - static_inventory += using - -//Crew Manifest - using = new /atom/movable/screen/ai/crew_manifest(null, src) - using.screen_loc = ui_ai_crew_manifest - static_inventory += using - -//Alerts - using = new /atom/movable/screen/ai/alerts(null, src) - using.screen_loc = ui_ai_alerts - static_inventory += using - -//Announcement - using = new /atom/movable/screen/ai/announcement(null, src) - using.screen_loc = ui_ai_announcement - static_inventory += using - -//Shuttle - using = new /atom/movable/screen/ai/call_shuttle(null, src) - using.screen_loc = ui_ai_shuttle - static_inventory += using - -//Laws - using = new /atom/movable/screen/ai/state_laws(null, src) - using.screen_loc = ui_ai_state_laws - static_inventory += using - -// Modular Interface - using = new /atom/movable/screen/ai/modpc(null, src) - using.screen_loc = ui_ai_mod_int - static_inventory += using - var/atom/movable/screen/ai/modpc/tabletbutton = using - tabletbutton.robot = myai - -//Take image - using = new /atom/movable/screen/ai/image_take(null, src) - using.screen_loc = ui_ai_take_picture - static_inventory += using - -//View images - using = new /atom/movable/screen/ai/image_view(null, src) - using.screen_loc = ui_ai_view_images - static_inventory += using - -//Medical/Security sensors - using = new /atom/movable/screen/ai/sensors(null, src) - using.screen_loc = ui_ai_sensor - static_inventory += using - -//Multicamera mode - using = new /atom/movable/screen/ai/multicam(null, src) - using.screen_loc = ui_ai_multicam - static_inventory += using - -//Add multicamera camera - using = new /atom/movable/screen/ai/add_multicam(null, src) - using.screen_loc = ui_ai_add_multicam - static_inventory += using +/datum/hud/ai/initialize_screen_objects() + . = ..() + add_screen_object(/atom/movable/screen/language_menu, HUD_MOB_LANGUAGE_MENU, HUD_GROUP_STATIC, ui_style, ui_ai_language_menu) + add_screen_object(/atom/movable/screen/memories, HUD_MOB_MEMORIES, HUD_GROUP_STATIC, ui_style, ui_ai_memories_menu) + add_screen_object(/atom/movable/screen/ai/floor_indicator, HUD_AI_FLOOR_INDICATOR) + add_screen_object(/atom/movable/screen/ai/go_up, HUD_AI_GO_UP) + add_screen_object(/atom/movable/screen/ai/go_up/down, HUD_AI_GO_DOWN) + add_screen_object(/atom/movable/screen/ai/aicore, HUD_AI_AICORE) + add_screen_object(/atom/movable/screen/ai/camera_list, HUD_AI_CAMERA_LIST) + add_screen_object(/atom/movable/screen/ai/camera_track, HUD_AI_CAMERA_TRACK) + add_screen_object(/atom/movable/screen/ai/camera_light, HUD_AI_CAMERA_LIGHT) + add_screen_object(/atom/movable/screen/ai/crew_monitor, HUD_AI_CREW_MONITOR) + add_screen_object(/atom/movable/screen/ai/crew_manifest, HUD_AI_CREW_MANIFEST) + add_screen_object(/atom/movable/screen/ai/alerts, HUD_SILICON_ALERTS) + add_screen_object(/atom/movable/screen/ai/announcement, HUD_AI_ANNOUNCEMENT) + add_screen_object(/atom/movable/screen/ai/call_shuttle, HUD_AI_CALL_SHUTTLE) + add_screen_object(/atom/movable/screen/ai/state_laws, HUD_AI_STATE_LAWS) + add_screen_object(/atom/movable/screen/ai/image_take, HUD_AI_TAKE_IMAGE) + add_screen_object(/atom/movable/screen/ai/image_view, HUD_AI_IMAGE_VIEW) + add_screen_object(/atom/movable/screen/ai/sensors, HUD_AI_SENSORS) + add_screen_object(/atom/movable/screen/ai/multicam, HUD_AI_MULTICAM) + add_screen_object(/atom/movable/screen/ai/add_multicam, HUD_AI_ADD_MULTICAM) + add_screen_object(/atom/movable/screen/ai/modpc, HUD_SILICON_TABLET) diff --git a/code/_onclick/hud/alien.dm b/code/_onclick/hud/alien.dm index 822fe712850..4ea86de55e7 100644 --- a/code/_onclick/hud/alien.dm +++ b/code/_onclick/hud/alien.dm @@ -1,136 +1,36 @@ -/atom/movable/screen/alien - icon = 'icons/hud/screen_alien.dmi' - -/atom/movable/screen/alien/leap - name = "toggle leap" - icon_state = "leap_off" - -/atom/movable/screen/alien/leap/Click() - if(isalienhunter(usr)) - var/mob/living/carbon/alien/adult/hunter/AH = usr - AH.toggle_leap() - -/atom/movable/screen/alien/plasma_display - name = "plasma stored" - icon_state = "power_display" - screen_loc = ui_alienplasmadisplay - -/atom/movable/screen/alien/alien_queen_finder - name = "queen sense" - desc = "Allows you to sense the general direction of your Queen." - icon_state = "queen_finder" - screen_loc = ui_alien_queen_finder - /datum/hud/alien ui_style = 'icons/hud/screen_alien.dmi' -/datum/hud/alien/New(mob/living/carbon/alien/adult/owner) - ..() - - var/atom/movable/screen/using - -//equippable shit - -//hands +/datum/hud/alien/initialize_screen_objects() + . = ..() build_hand_slots() -//begin buttons - - using = new /atom/movable/screen/swap_hand(null, src) - using.icon = ui_style + var/atom/movable/screen/using + using = add_screen_object(/atom/movable/screen/swap_hand, HUD_MOB_SWAPHAND_1, HUD_GROUP_STATIC, ui_style, ui_swaphand_position(mymob, 1)) using.icon_state = "swap_1" - using.screen_loc = ui_swaphand_position(owner, 1) - static_inventory += using - - using = new /atom/movable/screen/swap_hand(null, src) - using.icon = ui_style + using = add_screen_object(/atom/movable/screen/swap_hand, HUD_MOB_SWAPHAND_2, HUD_GROUP_STATIC, ui_style, ui_swaphand_position(mymob, 2)) using.icon_state = "swap_2" - using.screen_loc = ui_swaphand_position(owner, 2) - static_inventory += using - action_intent = new /atom/movable/screen/combattoggle/flashy(null, src) - action_intent.icon = ui_style - action_intent.screen_loc = ui_combat_toggle - static_inventory += action_intent + add_screen_object(/atom/movable/screen/combattoggle/flashy, HUD_MOB_INTENTS, HUD_GROUP_STATIC, ui_style) + add_screen_object(/atom/movable/screen/floor_changer, HUD_MOB_FLOOR_CHANGER, HUD_GROUP_STATIC, ui_style, ui_alien_floor_change) + add_screen_object(/atom/movable/screen/language_menu, HUD_MOB_LANGUAGE_MENU, HUD_GROUP_STATIC, ui_style, ui_alien_language_menu) + add_screen_object(/atom/movable/screen/navigate, HUD_MOB_NAVIGATE_MENU, HUD_GROUP_STATIC, ui_style, ui_alien_navigate_menu) + add_screen_object(/atom/movable/screen/zone_sel/alien, HUD_MOB_ZONE_SELECTOR) + add_screen_object(/atom/movable/screen/drop, HUD_MOB_DROP, HUD_GROUP_STATIC, ui_style) + add_screen_object(/atom/movable/screen/pull, HUD_MOB_PULL, HUD_GROUP_STATIC, ui_style, ui_above_movement) + add_screen_object(/atom/movable/screen/resist, HUD_MOB_RESIST, HUD_GROUP_HOTKEYS, ui_style) + add_screen_object(/atom/movable/screen/throw_catch, HUD_MOB_THROW, HUD_GROUP_HOTKEYS, ui_style) + add_screen_object(/atom/movable/screen/rest, HUD_MOB_REST, HUD_GROUP_HOTKEYS, ui_style) + add_screen_object(/atom/movable/screen/sleep, HUD_MOB_SLEEP, HUD_GROUP_HOTKEYS, ui_style) + add_screen_object(/atom/movable/screen/healths/alien, HUD_MOB_HEALTH, HUD_GROUP_INFO) + add_screen_object(/atom/movable/screen/alien/plasma_display, HUD_ALIEN_PLASMA_DISPLAY, HUD_GROUP_INFO) + add_screen_object(/atom/movable/screen/memories, HUD_MOB_MEMORIES, HUD_GROUP_STATIC, ui_style, ui_alien_memories_menu) if(isalienhunter(mymob)) - var/mob/living/carbon/alien/adult/hunter/H = mymob - H.leap_icon = new /atom/movable/screen/alien/leap() - H.leap_icon.screen_loc = ui_alien_storage_r - static_inventory += H.leap_icon - - floor_change = new /atom/movable/screen/floor_changer(null, src) - floor_change.icon = ui_style - floor_change.screen_loc = ui_alien_floor_change - static_inventory += floor_change - - using = new/atom/movable/screen/language_menu(null, src) - using.icon = ui_style - using.screen_loc = ui_alien_language_menu - static_inventory += using - - using = new /atom/movable/screen/navigate(null, src) - using.icon = ui_style - using.screen_loc = ui_alien_navigate_menu - static_inventory += using - - using = new /atom/movable/screen/memories(null, src) - using.icon = ui_style - using.screen_loc = ui_alien_memories_menu - static_inventory += using - - using = new /atom/movable/screen/drop(null, src) - using.icon = ui_style - using.screen_loc = ui_drop_throw - static_inventory += using - - resist_icon = new /atom/movable/screen/resist(null, src) - resist_icon.icon = ui_style - resist_icon.screen_loc = ui_above_movement - resist_icon.update_appearance() - hotkeybuttons += resist_icon - - throw_icon = new /atom/movable/screen/throw_catch(null, src) - throw_icon.icon = ui_style - throw_icon.screen_loc = ui_drop_throw - hotkeybuttons += throw_icon - - pull_icon = new /atom/movable/screen/pull(null, src) - pull_icon.icon = ui_style - pull_icon.update_appearance() - pull_icon.screen_loc = ui_above_movement - static_inventory += pull_icon - - rest_icon = new /atom/movable/screen/rest(null, src) - rest_icon.icon = ui_style - rest_icon.screen_loc = ui_rest - rest_icon.update_appearance() - static_inventory += rest_icon - - sleep_icon = new /atom/movable/screen/sleep(null, src) - sleep_icon.icon = ui_style - sleep_icon.screen_loc = ui_above_throw - -//begin indicators - - healths = new /atom/movable/screen/healths/alien(null, src) - infodisplay += healths - - alien_plasma_display = new /atom/movable/screen/alien/plasma_display(null, src) - infodisplay += alien_plasma_display + add_screen_object(/atom/movable/screen/alien/leap, HUD_ALIEN_HUNTER_LEAP, HUD_GROUP_STATIC, ui_style) if(!isalienqueen(mymob)) - alien_queen_finder = new /atom/movable/screen/alien/alien_queen_finder(null, src) - infodisplay += alien_queen_finder - - zone_select = new /atom/movable/screen/zone_sel/alien(null, src) - zone_select.update_appearance() - static_inventory += zone_select - - for(var/atom/movable/screen/inventory/inv in (static_inventory + toggleable_inventory)) - if(inv.slot_id) - inv_slots[TOBITSHIFT(inv.slot_id) + 1] = inv - inv.update_appearance() + add_screen_object(/atom/movable/screen/alien/plasma_display, HUD_ALIEN_QUEEN_FINDER, HUD_GROUP_INFO) /datum/hud/alien/persistent_inventory_update() if(!mymob) diff --git a/code/_onclick/hud/alien_larva.dm b/code/_onclick/hud/alien_larva.dm index 3331ac8c790..25ae3ba34bb 100644 --- a/code/_onclick/hud/alien_larva.dm +++ b/code/_onclick/hud/alien_larva.dm @@ -1,54 +1,16 @@ /datum/hud/larva ui_style = 'icons/hud/screen_alien.dmi' -/datum/hud/larva/New(mob/owner) - ..() - var/atom/movable/screen/using - - action_intent = new /atom/movable/screen/combattoggle/flashy(null, src) - action_intent.icon = ui_style - action_intent.screen_loc = ui_combat_toggle - static_inventory += action_intent - - floor_change = new /atom/movable/screen/floor_changer(null, src) - floor_change.icon = ui_style - floor_change.screen_loc = ui_alien_floor_change - static_inventory += floor_change - - healths = new /atom/movable/screen/healths/alien(null, src) - infodisplay += healths - - alien_queen_finder = new /atom/movable/screen/alien/alien_queen_finder(null, src) - infodisplay += alien_queen_finder - - pull_icon = new /atom/movable/screen/pull(null, src) - pull_icon.icon = 'icons/hud/screen_alien.dmi' - pull_icon.update_appearance() - pull_icon.screen_loc = ui_above_movement - hotkeybuttons += pull_icon - - rest_icon = new /atom/movable/screen/rest(null, src) - rest_icon.icon = ui_style - rest_icon.screen_loc = ui_rest - rest_icon.update_appearance() - static_inventory += rest_icon - - sleep_icon = new /atom/movable/screen/sleep(null, src) - sleep_icon.icon = ui_style - sleep_icon.screen_loc = ui_drop_throw - - using = new/atom/movable/screen/language_menu(null, src) - using.screen_loc = ui_alien_language_menu - static_inventory += using - - using = new /atom/movable/screen/navigate(null, src) - using.screen_loc = ui_alien_navigate_menu - static_inventory += using - - using = new /atom/movable/screen/memories(null, src) - using.screen_loc = ui_alien_memories_menu - static_inventory += using - - zone_select = new /atom/movable/screen/zone_sel/alien(null, src) - zone_select.update_appearance() - static_inventory += zone_select +/datum/hud/larva/initialize_screen_objects() + . = ..() + add_screen_object(/atom/movable/screen/combattoggle/flashy, HUD_MOB_INTENTS, HUD_GROUP_STATIC, ui_style) + add_screen_object(/atom/movable/screen/floor_changer, HUD_MOB_FLOOR_CHANGER, HUD_GROUP_STATIC, ui_style, ui_alien_floor_change) + add_screen_object(/atom/movable/screen/pull, HUD_MOB_PULL, HUD_GROUP_STATIC, ui_style) + add_screen_object(/atom/movable/screen/rest, HUD_MOB_REST, HUD_GROUP_HOTKEYS, ui_style) + add_screen_object(/atom/movable/screen/sleep, HUD_MOB_SLEEP, HUD_GROUP_HOTKEYS, ui_style, ui_drop_throw) + add_screen_object(/atom/movable/screen/language_menu, HUD_MOB_LANGUAGE_MENU, ui_loc = ui_alien_language_menu) + add_screen_object(/atom/movable/screen/navigate, HUD_MOB_NAVIGATE_MENU, ui_loc = ui_alien_navigate_menu) + add_screen_object(/atom/movable/screen/zone_sel/alien, HUD_MOB_ZONE_SELECTOR) + add_screen_object(/atom/movable/screen/healths/alien, HUD_MOB_HEALTH, HUD_GROUP_INFO) + add_screen_object(/atom/movable/screen/alien/alien_queen_finder, HUD_ALIEN_QUEEN_FINDER, HUD_GROUP_INFO) + add_screen_object(/atom/movable/screen/memories, HUD_MOB_MEMORIES, HUD_GROUP_STATIC, ui_style, ui_alien_memories_menu) diff --git a/code/_onclick/hud/blob_overmind.dm b/code/_onclick/hud/blob_overmind.dm index 6b5213c027b..cf92ff67b47 100644 --- a/code/_onclick/hud/blob_overmind.dm +++ b/code/_onclick/hud/blob_overmind.dm @@ -1,198 +1,12 @@ - -/atom/movable/screen/blob - icon = 'icons/hud/blob.dmi' - mouse_over_pointer = MOUSE_HAND_POINTER - -/atom/movable/screen/blob/MouseEntered(location,control,params) +/datum/hud/blob_overmind/initialize_screen_objects() . = ..() - openToolTip(usr,src,params,title = name,content = desc, theme = "blob") - -/atom/movable/screen/blob/MouseExited() - closeToolTip(usr) - -/atom/movable/screen/blob/jump_to_node - icon_state = "ui_tonode" - name = "Jump to Node" - desc = "Moves your camera to a selected blob node." - -/atom/movable/screen/blob/jump_to_node/Click() - if(!isovermind(usr)) - return FALSE - var/mob/eye/blob/blob = usr - blob.jump_to_node() - -/atom/movable/screen/blob/jump_to_core - icon_state = "ui_tocore" - name = "Jump to Core" - desc = "Moves your camera to your blob core." - -/atom/movable/screen/blob/jump_to_core/MouseEntered(location,control,params) - if(hud?.mymob && isovermind(hud.mymob)) - var/mob/eye/blob/B = hud.mymob - if(!B.placed) - name = "Place Blob Core" - desc = "Attempt to place your blob core at this location." - else - name = initial(name) - desc = initial(desc) - return ..() - -/atom/movable/screen/blob/jump_to_core/Click() - if(!isovermind(usr)) - return FALSE - var/mob/eye/blob/blob = usr - if(!blob.placed) - blob.place_blob_core(BLOB_NORMAL_PLACEMENT) - blob.transport_core() - -/atom/movable/screen/blob/blobbernaut - icon_state = "ui_blobbernaut" - // Name and description get given their proper values on Initialize() - name = "Produce Blobbernaut (ERROR)" - desc = "Produces a strong, smart blobbernaut from a factory blob for (ERROR) resources.
The factory blob used will become fragile and unable to produce spores." - -/atom/movable/screen/blob/blobbernaut/Initialize(mapload, datum/hud/hud_owner) - . = ..() - name = "Produce Blobbernaut ([BLOBMOB_BLOBBERNAUT_RESOURCE_COST])" - desc = "Produces a strong, smart blobbernaut from a factory blob for [BLOBMOB_BLOBBERNAUT_RESOURCE_COST] resources.
The factory blob used will become fragile and unable to produce spores." - -/atom/movable/screen/blob/blobbernaut/Click() - if(!isovermind(usr)) - return FALSE - var/mob/eye/blob/blob = usr - blob.create_blobbernaut() - -/atom/movable/screen/blob/resource_blob - icon_state = "ui_resource" - // Name and description get given their proper values on Initialize() - name = "Produce Resource Blob (ERROR)" - desc = "Produces a resource blob for ERROR resources.
Resource blobs will give you resources every few seconds." - -/atom/movable/screen/blob/resource_blob/Initialize(mapload, datum/hud/hud_owner) - . = ..() - name = "Produce Resource Blob ([BLOB_STRUCTURE_RESOURCE_COST])" - desc = "Produces a resource blob for [BLOB_STRUCTURE_RESOURCE_COST] resources.
Resource blobs will give you resources every few seconds." - -/atom/movable/screen/blob/resource_blob/Click() - if(!isovermind(usr)) - return FALSE - var/mob/eye/blob/blob = usr - blob.create_special(BLOB_STRUCTURE_RESOURCE_COST, /obj/structure/blob/special/resource, BLOB_RESOURCE_MIN_DISTANCE, TRUE) - -/atom/movable/screen/blob/node_blob - icon_state = "ui_node" - // Name and description get given their proper values on Initialize() - name = "Produce Node Blob (ERROR)" - desc = "Produces a node blob for ERROR resources.
Node blobs will expand and activate nearby resource and factory blobs." - -/atom/movable/screen/blob/node_blob/Initialize(mapload, datum/hud/hud_owner) - . = ..() - name = "Produce Node Blob ([BLOB_STRUCTURE_NODE_COST])" - desc = "Produces a node blob for [BLOB_STRUCTURE_NODE_COST] resources.
Node blobs will expand and activate nearby resource and factory blobs." - -/atom/movable/screen/blob/node_blob/Click() - if(!isovermind(usr)) - return FALSE - var/mob/eye/blob/blob = usr - blob.create_special(BLOB_STRUCTURE_NODE_COST, /obj/structure/blob/special/node, BLOB_NODE_MIN_DISTANCE, FALSE) - -/atom/movable/screen/blob/factory_blob - icon_state = "ui_factory" - // Name and description get given their proper values on Initialize() - name = "Produce Factory Blob (ERROR)" - desc = "Produces a factory blob for ERROR resources.
Factory blobs will produce spores every few seconds." - -/atom/movable/screen/blob/factory_blob/Initialize(mapload, datum/hud/hud_owner) - . = ..() - name = "Produce Factory Blob ([BLOB_STRUCTURE_FACTORY_COST])" - desc = "Produces a factory blob for [BLOB_STRUCTURE_FACTORY_COST] resources.
Factory blobs will produce spores every few seconds." - -/atom/movable/screen/blob/factory_blob/Click() - if(!isovermind(usr)) - return FALSE - var/mob/eye/blob/blob = usr - blob.create_special(BLOB_STRUCTURE_FACTORY_COST, /obj/structure/blob/special/factory, BLOB_FACTORY_MIN_DISTANCE, TRUE) - -/atom/movable/screen/blob/readapt_strain - icon_state = "ui_chemswap" - // Description gets given its proper values on Initialize() - name = "Readapt Strain" - desc = "Allows you to choose a new strain from ERROR random choices for ERROR resources." - -/atom/movable/screen/blob/readapt_strain/MouseEntered(location,control,params) - if(hud?.mymob && isovermind(hud.mymob)) - var/mob/eye/blob/B = hud.mymob - if(B.free_strain_rerolls) - name = "[initial(name)] (FREE)" - desc = "Randomly rerolls your strain for free." - else - name = "[initial(name)] ([BLOB_POWER_REROLL_COST])" - desc = "Allows you to choose a new strain from [BLOB_POWER_REROLL_CHOICES] random choices for [BLOB_POWER_REROLL_COST] resources." - return ..() - -/atom/movable/screen/blob/readapt_strain/Click() - if(isovermind(usr)) - var/mob/eye/blob/B = usr - B.strain_reroll() - -/atom/movable/screen/blob/relocate_core - icon_state = "ui_swap" - // Name and description get given their proper values on Initialize() - name = "Relocate Core (ERROR)" - desc = "Swaps a node and your core for ERROR resources." - -/atom/movable/screen/blob/relocate_core/Initialize(mapload, datum/hud/hud_owner) - . = ..() - name = "Relocate Core ([BLOB_POWER_RELOCATE_COST])" - desc = "Swaps a node and your core for [BLOB_POWER_RELOCATE_COST] resources." - -/atom/movable/screen/blob/relocate_core/Click() - if(isovermind(usr)) - var/mob/eye/blob/B = usr - B.relocate_core() - -/atom/movable/screen/blob_power_display - name = "blob power" - icon_state = "block" - screen_loc = ui_health - mouse_opacity = MOUSE_OPACITY_TRANSPARENT - plane = ABOVE_HUD_PLANE - -/datum/hud/blob_overmind/New(mob/owner) - ..() - var/atom/movable/screen/using - - healths = new /atom/movable/screen/healths/blob(null, src) - infodisplay += healths - - using = new /atom/movable/screen/blob/jump_to_node(null, src) - using.screen_loc = ui_inventory - static_inventory += using - - using = new /atom/movable/screen/blob/jump_to_core(null, src) - using.screen_loc = ui_zonesel - static_inventory += using - - using = new /atom/movable/screen/blob/blobbernaut(null, src) - using.screen_loc = ui_belt - static_inventory += using - - using = new /atom/movable/screen/blob/resource_blob(null, src) - using.screen_loc = ui_back - static_inventory += using - - using = new /atom/movable/screen/blob/node_blob(null, src) - using.screen_loc = ui_hand_position(RIGHT_HANDS) - static_inventory += using - - using = new /atom/movable/screen/blob/factory_blob(null, src) - using.screen_loc = ui_hand_position(LEFT_HANDS) - static_inventory += using - - using = new /atom/movable/screen/blob/readapt_strain(null, src) - using.screen_loc = ui_storage1 - static_inventory += using - - using = new /atom/movable/screen/blob/relocate_core(null, src) - using.screen_loc = ui_storage2 - static_inventory += using + add_screen_object(/atom/movable/screen/healths/blob, HUD_MOB_HEALTH, HUD_GROUP_INFO) + add_screen_object(/atom/movable/screen/blob/blob_power, HUD_BLOB_POWER_DISPLAY, HUD_GROUP_INFO) + add_screen_object(/atom/movable/screen/blob/jump_to_node, HUD_BLOB_JUMP_TO_NODE) + add_screen_object(/atom/movable/screen/blob/jump_to_core, HUD_BLOB_JUMP_TO_CORE) + add_screen_object(/atom/movable/screen/blob/blobbernaut, HUD_BLOB_BLOBBERNAUT) + add_screen_object(/atom/movable/screen/blob/resource_blob, HUD_BLOB_RESOURCES) + add_screen_object(/atom/movable/screen/blob/node_blob, HUD_BLOB_NODE, ui_loc = ui_hand_position(RIGHT_HANDS)) + add_screen_object(/atom/movable/screen/blob/factory_blob, HUD_BLOB_FACTORY, ui_loc = ui_hand_position(LEFT_HANDS)) + add_screen_object(/atom/movable/screen/blob/readapt_strain, HUD_BLOB_READAPT) + add_screen_object(/atom/movable/screen/blob/relocate_core, HUD_BLOB_RELOCATE) diff --git a/code/_onclick/hud/drones.dm b/code/_onclick/hud/drones.dm index ad3604a19e7..e7694d5d660 100644 --- a/code/_onclick/hud/drones.dm +++ b/code/_onclick/hud/drones.dm @@ -1,30 +1,5 @@ -/datum/hud/dextrous/drone/New(mob/owner) - ..() - var/atom/movable/screen/inventory/inv_box - - inv_box = new /atom/movable/screen/inventory(null, src) - inv_box.name = "internal storage" - inv_box.icon = ui_style - inv_box.icon_state = "suit_storage" -// inv_box.icon_full = "template" - inv_box.screen_loc = ui_drone_storage - inv_box.slot_id = ITEM_SLOT_DEX_STORAGE - static_inventory += inv_box - - inv_box = new /atom/movable/screen/inventory(null, src) - inv_box.name = "head/mask" - inv_box.icon = ui_style - inv_box.icon_state = "mask" -// inv_box.icon_full = "template" - inv_box.screen_loc = ui_drone_head - inv_box.slot_id = ITEM_SLOT_HEAD - static_inventory += inv_box - - for(var/atom/movable/screen/inventory/inv in (static_inventory + toggleable_inventory)) - if(inv.slot_id) - inv_slots[TOBITSHIFT(inv.slot_id) + 1] = inv - inv.update_appearance() - +/datum/hud/dextrous/drone + inventory_slots = /datum/inventory_slot/drone /datum/hud/dextrous/drone/persistent_inventory_update() if(!mymob) @@ -41,5 +16,19 @@ else drone.internal_storage?.screen_loc = null drone.head?.screen_loc = null - ..() + +/datum/inventory_slot/drone + abstract_type = /datum/inventory_slot/drone + +/datum/inventory_slot/drone/storage + name = "internal storage" + icon_state = "suit_storage" + slot_id = ITEM_SLOT_DEX_STORAGE + screen_loc = ui_drone_storage + +/datum/inventory_slot/drone/head + name = "head/mask" + icon_state = "mask" + slot_id = ITEM_SLOT_HEAD + screen_loc = ui_drone_head diff --git a/code/_onclick/hud/generic_dextrous.dm b/code/_onclick/hud/generic_dextrous.dm index b7f7f7af739..0799edc98ba 100644 --- a/code/_onclick/hud/generic_dextrous.dm +++ b/code/_onclick/hud/generic_dextrous.dm @@ -1,70 +1,36 @@ //Used for normal mobs that have hands. -/datum/hud/dextrous/New(mob/living/owner) - ..() +/datum/hud/dextrous/initialize_screen_objects() + . = ..() var/atom/movable/screen/using - - pull_icon = new /atom/movable/screen/pull(null, src) - pull_icon.icon = ui_style - pull_icon.update_appearance() - pull_icon.screen_loc = ui_drone_pull - static_inventory += pull_icon - - build_hand_slots() - - using = new /atom/movable/screen/drop(null, src) - using.icon = ui_style - using.screen_loc = ui_swaphand_position(owner, 1) - static_inventory += using - - using = new /atom/movable/screen/swap_hand(null, src) - using.icon = ui_style + add_screen_object(/atom/movable/screen/drop, HUD_MOB_DROP, HUD_GROUP_STATIC, ui_style, ui_swaphand_position(mymob, 1)) + using = add_screen_object(/atom/movable/screen/swap_hand, HUD_MOB_SWAPHAND_2, HUD_GROUP_STATIC, ui_style, ui_swaphand_position(mymob, 2)) using.icon_state = "act_swap" - using.screen_loc = ui_swaphand_position(owner, 2) - static_inventory += using - - action_intent = new /atom/movable/screen/combattoggle/flashy(null, src) - action_intent.icon = ui_style - action_intent.screen_loc = ui_movi - static_inventory += action_intent - - floor_change = new /atom/movable/screen/floor_changer(null, src) - floor_change.icon = 'icons/hud/screen_midnight.dmi' - static_inventory += floor_change - - if(HAS_TRAIT(owner, TRAIT_CAN_THROW_ITEMS)) - throw_icon = new /atom/movable/screen/throw_catch(null, src) - throw_icon.icon = ui_style - throw_icon.screen_loc = ui_drop_throw - static_inventory += throw_icon - - zone_select = new /atom/movable/screen/zone_sel(null, src) - zone_select.icon = ui_style - zone_select.update_appearance() - static_inventory += zone_select - - using = new /atom/movable/screen/area_creator(null, src) - using.icon = ui_style - static_inventory += using - - healthdoll = new /atom/movable/screen/healthdoll/living(null, src) - infodisplay += healthdoll mymob.canon_client?.clear_screen() - for(var/atom/movable/screen/inventory/inv in (static_inventory + toggleable_inventory)) - if(inv.slot_id) - inv_slots[TOBITSHIFT(inv.slot_id) + 1] = inv - inv.update_appearance() + build_hand_slots() + + add_screen_object(/atom/movable/screen/pull, HUD_MOB_PULL, HUD_GROUP_STATIC, ui_style, ui_below_throw) + add_screen_object(/atom/movable/screen/combattoggle/flashy, HUD_MOB_INTENTS, HUD_GROUP_STATIC, ui_style, ui_movi) + add_screen_object(/atom/movable/screen/floor_changer, HUD_MOB_FLOOR_CHANGER, HUD_GROUP_STATIC, ui_style, ui_above_movement) + add_screen_object(/atom/movable/screen/zone_sel, HUD_MOB_ZONE_SELECTOR, HUD_GROUP_STATIC, ui_style) + add_screen_object(/atom/movable/screen/area_creator, HUD_MOB_AREA_CREATOR, HUD_GROUP_STATIC, ui_style) + add_screen_object(/atom/movable/screen/memories, HUD_MOB_MEMORIES, HUD_GROUP_STATIC, ui_style) + add_screen_object(/atom/movable/screen/healthdoll/living, HUD_MOB_HEALTHDOLL, HUD_GROUP_INFO) + + if(HAS_TRAIT(mymob, TRAIT_CAN_THROW_ITEMS)) + add_screen_object(/atom/movable/screen/throw_catch, HUD_MOB_THROW, HUD_GROUP_HOTKEYS, ui_style, ui_drop_throw) /datum/hud/dextrous/persistent_inventory_update() if(!mymob) return - var/mob/living/D = mymob + var/mob/living/owner = mymob if(hud_version != HUD_STYLE_NOHUD) - for(var/obj/item/I in D.held_items) - I.screen_loc = ui_hand_position(D.get_held_index_of_item(I)) - D.client.screen += I - else - for(var/obj/item/I in D.held_items) - I.screen_loc = null - D.client.screen -= I + for(var/obj/item/held in owner.held_items) + held.screen_loc = ui_hand_position(owner.get_held_index_of_item(held)) + owner.client.screen += held + return + + for(var/obj/item/held in owner.held_items) + held.screen_loc = null + owner.client.screen -= held diff --git a/code/_onclick/hud/ghost.dm b/code/_onclick/hud/ghost.dm index 14b332d0c3c..b8f5e611e37 100644 --- a/code/_onclick/hud/ghost.dm +++ b/code/_onclick/hud/ghost.dm @@ -1,198 +1,22 @@ -/atom/movable/screen/ghost - icon = 'icons/hud/screen_ghost.dmi' - mouse_over_pointer = MOUSE_HAND_POINTER - -/atom/movable/screen/ghost/MouseEntered(location, control, params) - . = ..() - flick(icon_state + "_anim", src) - -/atom/movable/screen/ghost/spawners_menu - name = "Spawners menu" - icon_state = "spawners" - -/atom/movable/screen/ghost/spawners_menu/Click() - var/mob/dead/observer/observer = usr - observer.open_spawners_menu() - -/atom/movable/screen/ghost/orbit - name = "Orbit" - icon_state = "orbit" - -/atom/movable/screen/ghost/orbit/Click() - GLOB.orbit_menu.show(usr) - -/atom/movable/screen/ghost/reenter_corpse - name = "Reenter corpse" - icon_state = "reenter_corpse" - -/atom/movable/screen/ghost/reenter_corpse/Click() - var/mob/dead/observer/G = usr - G.reenter_corpse() - -/atom/movable/screen/ghost/dnr - name = "Do Not Resuscitate" - icon_state = "dnr" - -/atom/movable/screen/ghost/dnr/Click() - var/mob/dead/observer/dnring = usr - dnring.do_not_resuscitate() - -/atom/movable/screen/ghost/teleport - name = "Teleport" - icon_state = "teleport" - -/atom/movable/screen/ghost/teleport/Click() - var/mob/dead/observer/G = usr - G.dead_tele() - -/atom/movable/screen/ghost/settings - name = "Ghost Settings" - icon_state = "settings" - -/atom/movable/screen/ghost/settings/MouseEntered(location, control, params) - . = ..() - flick(icon_state + "_anim", src) - -/atom/movable/screen/ghost/settings/Click() - GLOB.ghost_menu.ui_interact(usr) - -/atom/movable/screen/ghost/minigames_menu - name ="Minigames" - icon_state = "minigames" - -/atom/movable/screen/ghost/minigames_menu/Click() - var/mob/dead/observer/observer = usr - observer.open_minigames_menu() - -/atom/movable/screen/ghost/hudbox - icon_state = "smallbox" - abstract_type = /atom/movable/screen/ghost/hudbox - /// Icon state used for the overlay representing this hudbox - var/hud_icon_state - /// The flag this hudbox toggles - var/relevant_flag - -/atom/movable/screen/ghost/hudbox/update_overlays() - . = ..() - . += hud_icon_state - -/atom/movable/screen/ghost/hudbox/update_icon_state() - . = ..() - var/mob/dead/observer/observer = hud?.mymob - if(!istype(observer)) - return - - icon_state = "smallbox[is_active(observer) ? "_active" : ""]" - -/atom/movable/screen/ghost/hudbox/proc/is_active(mob/dead/observer/observer) - return (observer.ghost_hud_flags & relevant_flag) - -/atom/movable/screen/ghost/hudbox/Click(location, control, params) - var/mob/dead/observer/observer = usr - switch(relevant_flag) - if(GHOST_DARKNESS_LEVEL) - observer.toggle_darkness() - if(GHOST_TRAY) - observer.tray_view() - else - observer.toggle_ghost_hud_flag(relevant_flag) - - update_appearance(UPDATE_ICON_STATE) - -/atom/movable/screen/ghost/hudbox/health_scanner - name = "Health Scanner" - desc = "Toggles your ability to health scan mobs on click." - hud_icon_state = "health_vision" - relevant_flag = GHOST_HEALTH - -/atom/movable/screen/ghost/hudbox/chem_scanner - name = "Chem Scanner" - desc = "Toggles your ability to chemical scan mobs on click." - hud_icon_state = "chem_vision" - relevant_flag = GHOST_CHEM - -/atom/movable/screen/ghost/hudbox/gas_scanner - name = "Gas Scanner" - desc = "Toggles your ability to gas scan objects on click." - hud_icon_state = "atmos_vision" - relevant_flag = GHOST_GAS - -/atom/movable/screen/ghost/hudbox/ghost - name = "Ghost Vision" - desc = "Toggles whether you can see other ghosts." - hud_icon_state = "ghost_vision" - relevant_flag = GHOST_VISION - -/atom/movable/screen/ghost/hudbox/data_huds - name = "Data HUDs" - desc = "Toggles the display of data HUDs (health, security, diagnostics, etc)." - hud_icon_state = "data_vision" - relevant_flag = GHOST_DATA_HUDS - -/atom/movable/screen/ghost/hudbox/tray_icon - name = "Tray View" - desc = "Shows the t-ray view of the area around your ghost." - hud_icon_state = "tray_vision" - relevant_flag = GHOST_TRAY - -/atom/movable/screen/ghost/hudbox/darkness_level - name = "Darkness Level" - desc = "Cycles through different darkness levels for ghost vision." - hud_icon_state = "darkness_vision" - relevant_flag = GHOST_DARKNESS_LEVEL /datum/hud/ghost ui_style = 'icons/hud/screen_ghost.dmi' -/datum/hud/ghost/New(mob/owner) - ..() - var/atom/movable/screen/using - - using = new /atom/movable/screen/ghost/spawners_menu(null, src) - using.screen_loc = ui_ghost_spawners_menu - static_inventory += using - - using = new /atom/movable/screen/ghost/orbit(null, src) - using.screen_loc = ui_ghost_orbit - static_inventory += using - - using = new /atom/movable/screen/ghost/reenter_corpse(null, src) - using.screen_loc = ui_ghost_reenter_corpse - static_inventory += using - - using = new /atom/movable/screen/ghost/dnr(null, src) - using.screen_loc = ui_dnr - static_inventory += using - - using = new /atom/movable/screen/ghost/teleport(null, src) - using.screen_loc = ui_ghost_teleport - static_inventory += using - - using = new /atom/movable/screen/ghost/settings(null, src) - using.screen_loc = ui_ghost_settings - static_inventory += using - - using = new /atom/movable/screen/ghost/minigames_menu(null, src) - using.screen_loc = ui_ghost_minigames - static_inventory += using - - using = new /atom/movable/screen/language_menu(null, src) - using.icon = ui_style - using.screen_loc = ui_ghost_language_menu - static_inventory += using - - floor_change = new /atom/movable/screen/floor_changer/vertical(null, src) - floor_change.icon = ui_style - floor_change.screen_loc = ui_ghost_floor_changer - static_inventory += floor_change +/datum/hud/ghost/initialize_screen_objects() + . = ..() + add_screen_object(/atom/movable/screen/ghost/spawners_menu, HUD_GHOST_SPAWNERS) + add_screen_object(/atom/movable/screen/ghost/orbit, HUD_GHOST_ORBIT) + add_screen_object(/atom/movable/screen/ghost/reenter_corpse, HUD_GHOST_REENTER_CORPSE) + add_screen_object(/atom/movable/screen/ghost/dnr, HUD_GHOST_DNR) + add_screen_object(/atom/movable/screen/ghost/teleport, HUD_GHOST_TELEPORT) + add_screen_object(/atom/movable/screen/ghost/settings, HUD_GHOST_SETTINGS) + add_screen_object(/atom/movable/screen/ghost/minigames_menu, HUD_GHOST_MINIGAMES) + add_screen_object(/atom/movable/screen/language_menu, HUD_MOB_LANGUAGE_MENU, HUD_GROUP_STATIC, ui_style, ui_ghost_language_menu) + add_screen_object(/atom/movable/screen/floor_changer/vertical, HUD_MOB_FLOOR_CHANGER, HUD_GROUP_STATIC, ui_style, ui_ghost_floor_changer) var/list/hudboxes = valid_subtypesof(/atom/movable/screen/ghost/hudbox) for(var/i in 1 to length(hudboxes)) - var/hudbox_type = hudboxes[i] - var/atom/movable/screen/ghost/hudbox/hudbox = new hudbox_type(null, src) - hudbox.screen_loc = position_hudbox(i - 1) - static_inventory += hudbox - hudbox.update_appearance() + add_screen_object(hudboxes[i], HUD_KEY_GHOST_HUDBOX(i), ui_loc = position_hudbox(i - 1)) /datum/hud/ghost/proc/position_hudbox(i) var/row = floor(i / 3) @@ -211,15 +35,15 @@ return var/mob/screenmob = viewmob || mymob if(screenmob.client.prefs.read_preference(/datum/preference/toggle/ghost_hud)) - screenmob.client.screen |= static_inventory - for(var/atom/movable/screen/ghost/hudbox/hud in static_inventory) + screenmob.client.screen |= screen_groups[HUD_GROUP_STATIC] + for(var/atom/movable/screen/ghost/hudbox/hud in screen_groups[HUD_GROUP_STATIC]) hud.update_appearance() else - screenmob.client.screen -= static_inventory + screenmob.client.screen -= screen_groups[HUD_GROUP_STATIC] //We should only see observed mob alerts. /datum/hud/ghost/reorganize_alerts(mob/viewmob) var/mob/dead/observer/O = mymob if (istype(O) && O.observetarget) return - . = ..() + return ..() diff --git a/code/_onclick/hud/guardian.dm b/code/_onclick/hud/guardian.dm index 68a480d47f8..cabe261b14e 100644 --- a/code/_onclick/hud/guardian.dm +++ b/code/_onclick/hud/guardian.dm @@ -1,169 +1,54 @@ /datum/hud/guardian ui_style = 'icons/hud/guardian.dmi' + inventory_slots = list(/datum/inventory_slot/guardian_storage) -/datum/hud/guardian/New(mob/living/basic/guardian/owner) - ..() - var/atom/movable/screen/using +/datum/hud/guardian/initialize_screen_objects() + . = ..() + add_screen_object(/atom/movable/screen/pull, HUD_MOB_PULL, HUD_GROUP_STATIC, ui_style) + add_screen_object(/atom/movable/screen/guardian/manifest, HUD_GUARDIAN_MANIFEST, ui_loc = ui_hand_position(RIGHT_HANDS)) + add_screen_object(/atom/movable/screen/guardian/recall, HUD_GUARDIAN_RECALL, ui_loc = ui_hand_position(LEFT_HANDS)) + add_screen_object(/atom/movable/screen/guardian/toggle_light, HUD_GUARDIAN_LIGHT) + add_screen_object(/atom/movable/screen/guardian/communicate, HUD_GUARDIAN_COMMUNICATE) - pull_icon = new /atom/movable/screen/pull(null, src) - pull_icon.icon = ui_style - pull_icon.update_appearance() - pull_icon.screen_loc = ui_living_pull - static_inventory += pull_icon + add_screen_object(/atom/movable/screen/healths/guardian, HUD_MOB_HEALTH, HUD_GROUP_INFO) - healths = new /atom/movable/screen/healths/guardian(null, src) - infodisplay += healths + var/mob/living/basic/guardian/owner = mymob + if (istype(owner)) + add_screen_object(owner.toggle_button_type, HUD_GUARDIAN_TOGGLE, ui_loc = ui_storage1) - using = new /atom/movable/screen/guardian/manifest(null, src) - using.screen_loc = ui_hand_position(RIGHT_HANDS) - static_inventory += using +/datum/hud/dextrous/guardian/initialize_screen_objects() + . = ..() + add_screen_object(/atom/movable/screen/pull, HUD_MOB_PULL, HUD_GROUP_STATIC, ui_style) + add_screen_object(/atom/movable/screen/guardian/communicate, HUD_GUARDIAN_COMMUNICATE, ui_loc = ui_sstore1) + add_screen_object(/atom/movable/screen/guardian/manifest, HUD_GUARDIAN_MANIFEST, ui_loc = ui_belt) + add_screen_object(/atom/movable/screen/guardian/recall, HUD_GUARDIAN_RECALL, ui_loc = ui_back) + add_screen_object(/atom/movable/screen/guardian/toggle_light, HUD_GUARDIAN_LIGHT) - using = new /atom/movable/screen/guardian/recall(null, src) - using.screen_loc = ui_hand_position(LEFT_HANDS) - static_inventory += using + add_screen_object(/atom/movable/screen/healths/guardian, HUD_MOB_HEALTH, HUD_GROUP_INFO) - using = new owner.toggle_button_type(null, src) - using.screen_loc = ui_storage1 - static_inventory += using - - using = new /atom/movable/screen/guardian/toggle_light(null, src) - using.screen_loc = ui_inventory - static_inventory += using - - using = new /atom/movable/screen/guardian/communicate(null, src) - using.screen_loc = ui_back - static_inventory += using - -/datum/hud/dextrous/guardian/New(mob/living/basic/guardian/owner) //for a dextrous guardian - ..() - var/atom/movable/screen/using - if(istype(owner, /mob/living/basic/guardian/dextrous)) - var/atom/movable/screen/inventory/inv_box - - inv_box = new /atom/movable/screen/inventory(null, src) - inv_box.name = "internal storage" - inv_box.icon = ui_style - inv_box.icon_state = "suit_storage" - inv_box.screen_loc = ui_id - inv_box.slot_id = ITEM_SLOT_DEX_STORAGE - static_inventory += inv_box - - using = new /atom/movable/screen/guardian/communicate(null, src) - using.screen_loc = ui_sstore1 - static_inventory += using - - else - - using = new /atom/movable/screen/guardian/communicate(null, src) - using.screen_loc = ui_id - static_inventory += using - - pull_icon = new /atom/movable/screen/pull(null, src) - pull_icon.icon = ui_style - pull_icon.update_appearance() - pull_icon.screen_loc = ui_living_pull - static_inventory += pull_icon - - healths = new /atom/movable/screen/healths/guardian(null, src) - infodisplay += healths - - using = new /atom/movable/screen/guardian/manifest(null, src) - using.screen_loc = ui_belt - static_inventory += using - - using = new /atom/movable/screen/guardian/recall(null, src) - using.screen_loc = ui_back - static_inventory += using - - using = new owner.toggle_button_type(null, src) - using.screen_loc = ui_storage2 - static_inventory += using - - using = new /atom/movable/screen/guardian/toggle_light(null, src) - using.screen_loc = ui_inventory - static_inventory += using + var/mob/living/basic/guardian/owner = mymob + if (istype(owner)) + add_screen_object(owner.toggle_button_type, HUD_GUARDIAN_TOGGLE, ui_loc = ui_storage2) /datum/hud/dextrous/guardian/persistent_inventory_update() if(!mymob) return - if(istype(mymob, /mob/living/basic/guardian/dextrous)) - var/mob/living/basic/guardian/dextrous/dex_guardian = mymob - if(hud_shown) - if(dex_guardian.internal_storage) - dex_guardian.internal_storage.screen_loc = ui_id - dex_guardian.client.screen += dex_guardian.internal_storage - else - if(dex_guardian.internal_storage) - dex_guardian.internal_storage.screen_loc = null + if(!istype(mymob, /mob/living/basic/guardian/dextrous)) + return ..() - ..() + var/mob/living/basic/guardian/dextrous/dex_guardian = mymob + if(hud_shown) + if(dex_guardian.internal_storage) + dex_guardian.internal_storage.screen_loc = ui_id + dex_guardian.client.screen += dex_guardian.internal_storage + else + if(dex_guardian.internal_storage) + dex_guardian.internal_storage.screen_loc = null + return ..() -/atom/movable/screen/guardian - icon = 'icons/hud/guardian.dmi' - mouse_over_pointer = MOUSE_HAND_POINTER - -/atom/movable/screen/guardian/manifest - icon_state = "manifest" - name = "Manifest" - desc = "Spring forth into battle!" - -/atom/movable/screen/guardian/manifest/Click() - if(isguardian(usr)) - var/mob/living/basic/guardian/user = usr - user.manifest() - - -/atom/movable/screen/guardian/recall - icon_state = "recall" - name = "Recall" - desc = "Return to your user." - -/atom/movable/screen/guardian/recall/Click() - if(isguardian(usr)) - var/mob/living/basic/guardian/user = usr - user.recall() - -/atom/movable/screen/guardian/toggle_mode - icon_state = "toggle" - name = "Toggle Mode" - desc = "Switch between ability modes." - -/atom/movable/screen/guardian/toggle_mode/Click() - if(isguardian(usr)) - var/mob/living/basic/guardian/user = usr - user.toggle_modes() - -/atom/movable/screen/guardian/toggle_mode/inactive - icon_state = "notoggle" //greyed out so it doesn't look like it'll work - -/atom/movable/screen/guardian/toggle_mode/assassin - icon_state = "stealth" - name = "Toggle Stealth" - desc = "Enter or exit stealth." - -/atom/movable/screen/guardian/toggle_mode/gases - icon_state = "gases" - name = "Toggle Gas" - desc = "Switch between possible gases." - -/atom/movable/screen/guardian/communicate - icon_state = "communicate" - name = "Communicate" - desc = "Communicate telepathically with your user." - -/atom/movable/screen/guardian/communicate/Click() - if(isguardian(usr)) - var/mob/living/basic/guardian/user = usr - user.communicate() - - -/atom/movable/screen/guardian/toggle_light - icon_state = "light" - name = "Toggle Light" - desc = "Glow like star dust." - -/atom/movable/screen/guardian/toggle_light/Click() - if(isguardian(usr)) - var/mob/living/basic/guardian/user = usr - user.toggle_light() +/datum/inventory_slot/guardian_storage + name = "internal storage" + icon_state = "suit_storage" + slot_id = ITEM_SLOT_DEX_STORAGE + screen_loc = ui_id diff --git a/code/_onclick/hud/hud.dm b/code/_onclick/hud/hud.dm index 0f722a1bc11..88eb2d5a6f1 100644 --- a/code/_onclick/hud/hud.dm +++ b/code/_onclick/hud/hud.dm @@ -22,34 +22,15 @@ GLOBAL_LIST_INIT(available_ui_styles, list( /datum/hud var/mob/mymob + /// Used for the HUD toggle (F12) + var/hud_shown = TRUE + /// Current displayed version of the HUD + var/hud_version = HUD_STYLE_STANDARD + /// Equipped item inventory + var/inventory_shown = FALSE + /// This is to hide the buttons that can be used via hotkeys. (hotkeybuttons list of buttons) + var/hotkey_ui_hidden = FALSE - var/hud_shown = TRUE //Used for the HUD toggle (F12) - var/hud_version = HUD_STYLE_STANDARD //Current displayed version of the HUD - var/inventory_shown = FALSE //Equipped item inventory - var/hotkey_ui_hidden = FALSE //This is to hide the buttons that can be used via hotkeys. (hotkeybuttons list of buttons) - - var/atom/movable/screen/alien_plasma_display - var/atom/movable/screen/alien_queen_finder - - var/atom/movable/screen/action_intent - var/atom/movable/screen/zone_select - var/atom/movable/screen/pull_icon - var/atom/movable/screen/rest_icon - var/atom/movable/screen/sleep_icon - var/atom/movable/screen/throw_icon - var/atom/movable/screen/resist_icon - var/atom/movable/screen/floor_change - - var/list/static_inventory = list() //the screen objects which are static - var/list/toggleable_inventory = list() //the screen objects which can be hidden - var/list/atom/movable/screen/hotkeybuttons = list() //the buttons that can be used via hotkeys - var/list/infodisplay = list() //the screen objects that display mob info (health, alien plasma, etc...) - /// Screen objects that never exit view. - var/list/always_visible_inventory = list() - var/list/inv_slots[SLOTS_AMT] // /atom/movable/screen/inventory objects, ordered by their slot ID. - var/list/hand_slots // /atom/movable/screen/inventory/hand objects, assoc list of "[held_index]" = object - /// storages (and its content) currently open by mob - var/list/open_containers = list() /// Assoc list of key => "plane master groups" /// This is normally just the main window, but it'll occasionally contain things like spyglasses windows var/list/datum/plane_master_group/master_groups = list() @@ -62,8 +43,9 @@ GLOBAL_LIST_INIT(available_ui_styles, list( /// Goes from 0 to the max (z level stack size - 1) var/current_plane_offset = 0 - ///UI for screentips that appear when you mouse over things - var/atom/movable/screen/screentip/screentip_text + /// UI for screentips that appear when you mouse over things + /// Stored directly as it is used in very hot MouseEntered code + var/atom/movable/screen/screentip/screentip_text = null /// Whether or not screentips are enabled. /// This is updated by the preference for cheaper reads than would be @@ -78,26 +60,27 @@ GLOBAL_LIST_INIT(available_ui_styles, list( /// The color to use for the screentips. /// This is updated by the preference for cheaper reads than would be - /// had with a proc call, especially on one of the hottest procs in the - /// game (MouseEntered). - var/screentip_color - - var/atom/movable/screen/button_palette/toggle_palette - var/atom/movable/screen/palette_scroll/down/palette_down - var/atom/movable/screen/palette_scroll/up/palette_up - - var/datum/action_group/palette/palette_actions - var/datum/action_group/listed/listed_actions - var/list/floating_actions - - var/atom/movable/screen/healths - var/atom/movable/screen/stamina - var/atom/movable/screen/healthdoll/healthdoll - var/atom/movable/screen/spacesuit/spacesuit_hud - var/atom/movable/screen/hunger/hunger + /// had with a proc call, especially on one of the hottest procs in the game (MouseEntered). + var/screentip_color = null + var/datum/action_group/palette/palette_actions = null + var/datum/action_group/listed/listed_actions = null + var/list/floating_actions = null /// Subtypes can override this to force a specific UI style - var/ui_style + var/ui_style = null + /// Assoc list of all screen objects we hold by their key + var/list/atom/movable/screen/screen_objects = list() + /// List of screen objects by their screen group + var/list/screen_groups[SCREEN_GROUP_AMT] + /// List of all inventory slot screen objects by their slot ID. Some slots are fake and will be missing from here! + var/list/inv_slots[SLOTS_AMT] + /// List of hand slot objects, kept separate from the rest of inventory as mobs can have varying amount of hands + var/list/atom/movable/screen/inventory/hand/hand_slots = null + + /// List of typepaths of /datum/inventory_slot which will be used to automatically create inventory slot UI elements + /// If assigned a typepath instead of a list, it will instead use all valid subtypes of said typepath + /// Safe to change in initialize_screen_objects() but not later + var/list/inventory_slots = null /// List of weakrefs to objects that we add to our screen that we don't expect to DO anything /// They typically use * in their render target. They exist solely so we can reuse them, @@ -111,12 +94,9 @@ GLOBAL_LIST_INIT(available_ui_styles, list( // will fall back to the default if any of these are null ui_style = ui_style2icon(owner.client?.prefs?.read_preference(/datum/preference/choiced/ui_style)) - toggle_palette = new() - toggle_palette.set_hud(src) - palette_down = new() - palette_down.set_hud(src) - palette_up = new() - palette_up.set_hud(src) + add_screen_object(/atom/movable/screen/button_palette, HUD_MOB_TOGGLE_PALETTE) + add_screen_object(/atom/movable/screen/palette_scroll/down, HUD_MOB_PALETTE_DOWN) + add_screen_object(/atom/movable/screen/palette_scroll/up, HUD_MOB_PALETTE_UP) hand_slots = list() @@ -127,8 +107,7 @@ GLOBAL_LIST_INIT(available_ui_styles, list( screentip_color = preferences?.read_preference(/datum/preference/color/screentip_color) screentips_enabled = preferences?.read_preference(/datum/preference/choiced/enable_screentips) screentip_images = preferences?.read_preference(/datum/preference/toggle/screentip_images) - screentip_text = new(null, src) - static_inventory += screentip_text + screentip_text = add_screen_object(/atom/movable/screen/screentip, HUD_MOB_SCREENTIP) for(var/mytype in subtypesof(/atom/movable/plane_master_controller)) var/atom/movable/plane_master_controller/controller_instance = new mytype(null,src) @@ -146,8 +125,73 @@ GLOBAL_LIST_INIT(available_ui_styles, list( RegisterSignal(mymob, COMSIG_MOB_LOGOUT, PROC_REF(clear_client)) RegisterSignal(mymob, COMSIG_MOB_SIGHT_CHANGE, PROC_REF(update_sightflags)) RegisterSignal(mymob, COMSIG_VIEWDATA_UPDATE, PROC_REF(on_viewdata_update)) + + initialize_screen_objects() + create_inventory_slots() + update_locked_slots() + update_sightflags(mymob, mymob.sight, NONE) +/datum/hud/Destroy() + if(mymob.hud_used == src) + mymob.hud_used = null + + QDEL_NULL(palette_actions) + QDEL_NULL(listed_actions) + QDEL_LIST(floating_actions) + screentip_text = null + screen_groups = null + inv_slots.Cut() + hand_slots.Cut() + QDEL_LIST_ASSOC_VAL(screen_objects) + QDEL_LIST_ASSOC_VAL(master_groups) + QDEL_LIST_ASSOC_VAL(plane_master_controllers) + mymob = null + + return ..() + +/// Creates and registers a managed screen object +/datum/hud/proc/add_screen_object(atom/movable/screen/new_object, hud_key, group_key = HUD_GROUP_STATIC, ui_icon, ui_loc, update_screen = FALSE) + if (ispath(new_object)) + new_object = new new_object(null, src) + + if (isnull(hud_key)) + hud_key = REF(new_object) + + if (!isnull(ui_icon)) + new_object.icon = ui_icon + + if (!isnull(ui_loc)) + new_object.screen_loc = ui_loc + + new_object.hud_key = hud_key + if (screen_objects[hud_key]) + CRASH("Attempted to add a new [new_object] screen object to the [src] hud while an object with the same key [hud_key] is already present!") + + screen_objects[hud_key] = new_object + + if (group_key) + LAZYADD(screen_groups[group_key], new_object) + new_object.hud_group_key = group_key + + if (update_screen) + show_hud(hud_version) + return new_object + +/// Removes a screen object and refreshes the hud. Can just be passed a key. +/datum/hud/proc/remove_screen_object(atom/movable/screen/to_remove, update = TRUE) + if (!istype(to_remove)) + to_remove = screen_objects[to_remove] + if (!to_remove) + return + qdel(to_remove) + if (update && !QDELETED(src)) + show_hud(hud_version) + +/// Proc for children to spawn their screen object in +/datum/hud/proc/initialize_screen_objects() + return + /datum/hud/proc/client_refresh(datum/source) SIGNAL_HANDLER var/client/client = mymob.canon_client @@ -212,53 +256,6 @@ GLOBAL_LIST_INIT(available_ui_styles, list( var/datum/plane_master_group/group = master_groups[group_key] group.build_planes_offset(src, new_offset) -/datum/hud/Destroy() - if(mymob.hud_used == src) - mymob.hud_used = null - - QDEL_NULL(toggle_palette) - QDEL_NULL(palette_down) - QDEL_NULL(palette_up) - QDEL_NULL(palette_actions) - QDEL_NULL(listed_actions) - QDEL_LIST(floating_actions) - - QDEL_LIST(static_inventory) - - // all already deleted by static inventory clear - inv_slots.Cut() - action_intent = null - zone_select = null - pull_icon = null - rest_icon = null - sleep_icon = null - floor_change = null - hand_slots.Cut() - - QDEL_LIST(toggleable_inventory) - QDEL_LIST(hotkeybuttons) - throw_icon = null - resist_icon = null - QDEL_LIST(infodisplay) - open_containers = null - - healths = null - stamina = null - healthdoll = null - spacesuit_hud = null - hunger = null - alien_plasma_display = null - alien_queen_finder = null - - QDEL_LIST_ASSOC_VAL(master_groups) - QDEL_LIST_ASSOC_VAL(plane_master_controllers) - QDEL_LIST(always_visible_inventory) - mymob = null - - QDEL_NULL(screentip_text) - - return ..() - /datum/hud/proc/on_plane_increase(datum/source, old_max_offset, new_max_offset) SIGNAL_HANDLER for(var/i in old_max_offset + 1 to new_max_offset) @@ -314,75 +311,73 @@ GLOBAL_LIST_INIT(available_ui_styles, list( * * viewmob - what mob to show the hud to. Can be this hud's mob, can be another mob, can be null (will use this hud's mob if so) */ /datum/hud/proc/show_hud(version = 0, mob/viewmob) - if(!ismob(mymob)) + if (!ismob(mymob)) return FALSE + var/mob/screenmob = viewmob || mymob - if(!screenmob.client) + if (!screenmob.client) return FALSE // This code is the absolute fucking worst, I want it to go die in a fire // Seriously, why + // I'm sorry screenmob.client.clear_screen() screenmob.client.apply_clickcatcher() var/display_hud_version = version - if(!display_hud_version) //If 0 or blank, display the next hud version + if (!display_hud_version) // If 0 or blank, display the next hud version display_hud_version = hud_version + 1 - if(display_hud_version > HUD_VERSIONS) //If the requested version number is greater than the available versions, reset back to the first version - display_hud_version = 1 - switch(display_hud_version) - if(HUD_STYLE_STANDARD) //Default HUD - hud_shown = TRUE //Governs behavior of other procs - if(static_inventory.len) - screenmob.client.screen += static_inventory - if(toggleable_inventory.len && screenmob.hud_used && screenmob.hud_used.inventory_shown) - screenmob.client.screen += toggleable_inventory - if(hotkeybuttons.len && !hotkey_ui_hidden) - screenmob.client.screen += hotkeybuttons - if(infodisplay.len) - screenmob.client.screen += infodisplay - if(always_visible_inventory.len) - screenmob.client.screen += always_visible_inventory - if(open_containers.len && screenmob == mymob) // Don't show open inventories to ghosts - list_clear_nulls(open_containers) - screenmob.client.screen += open_containers - screenmob.client.screen += toggle_palette + // If the requested version number is greater than the available versions, reset back to the first version + if (display_hud_version > HUD_VERSIONS) + display_hud_version = HUD_STYLE_STANDARD - if(HUD_STYLE_REDUCED) //Reduced HUD - hud_shown = FALSE //Governs behavior of other procs - if(static_inventory.len) - screenmob.client.screen -= static_inventory - if(toggleable_inventory.len) - screenmob.client.screen -= toggleable_inventory - if(hotkeybuttons.len) - screenmob.client.screen -= hotkeybuttons - if(infodisplay.len) - screenmob.client.screen += infodisplay - if(always_visible_inventory.len) - screenmob.client.screen += always_visible_inventory + var/list/group_static = screen_groups[HUD_GROUP_STATIC] + var/list/group_toggleable = screen_groups[HUD_GROUP_TOGGLEABLE_INVENTORY] + var/list/group_hotkeys = screen_groups[HUD_GROUP_HOTKEYS] + var/list/group_info = screen_groups[HUD_GROUP_INFO] + var/list/group_screen = screen_groups[HUD_GROUP_SCREEN_OVERLAYS] + var/list/group_storage = screen_groups[HUD_GROUP_STORAGE] + + // Screen overlays get added regardless of the HUD state + if (length(group_screen)) + screenmob.client.screen += group_screen + + var/atom/movable/screen/button_palette/palette = screen_objects[HUD_MOB_TOGGLE_PALETTE] + var/atom/movable/screen/action_intent = screen_objects[HUD_MOB_INTENTS] + + switch (display_hud_version) + if (HUD_STYLE_STANDARD) + hud_shown = TRUE + + if (length(group_static)) + screenmob.client.screen += group_static + if (length(group_toggleable) && screenmob.hud_used && screenmob.hud_used.inventory_shown) + screenmob.client.screen += group_toggleable + if (length(group_hotkeys) && !hotkey_ui_hidden) + screenmob.client.screen += group_hotkeys + if (length(group_info)) + screenmob.client.screen += group_info + if (length(group_storage)) + screenmob.client.screen += group_storage + + screenmob.client.screen += palette + + if (HUD_STYLE_REDUCED) + hud_shown = FALSE + + if (length(group_info)) + screenmob.client.screen += group_info + + // Hands are apart of the static group but still should be presetn in the reduced mode + for (var/atom/movable/screen/hand in hand_slots) + screenmob.client.screen += hand - //These ones are a part of 'static_inventory', 'toggleable_inventory' or 'hotkeybuttons' but we want them to stay - for(var/h in hand_slots) - var/atom/movable/screen/hand = hand_slots[h] - if(hand) - screenmob.client.screen += hand if(action_intent) - screenmob.client.screen += action_intent //we want the intent switcher visible - action_intent.screen_loc = ui_acti_alt //move this to the alternative position, where zone_select usually is. + screenmob.client.screen += action_intent - if(HUD_STYLE_NOHUD) //No HUD - hud_shown = FALSE //Governs behavior of other procs - if(static_inventory.len) - screenmob.client.screen -= static_inventory - if(toggleable_inventory.len) - screenmob.client.screen -= toggleable_inventory - if(hotkeybuttons.len) - screenmob.client.screen -= hotkeybuttons - if(infodisplay.len) - screenmob.client.screen -= infodisplay - if(always_visible_inventory.len) - screenmob.client.screen += always_visible_inventory + if (HUD_STYLE_NOHUD) + hud_shown = FALSE hud_version = display_hud_version persistent_inventory_update(screenmob) @@ -442,12 +437,13 @@ GLOBAL_LIST_INIT(available_ui_styles, list( if (initial(ui_style) || ui_style == new_ui_style) return - for(var/atom/item in static_inventory + toggleable_inventory + hotkeybuttons + infodisplay + always_visible_inventory + inv_slots) - if (item.icon == ui_style) + for(var/hud_key in screen_objects) + var/atom/item = screen_objects[hud_key] + if (item?.icon == ui_style) item.icon = new_ui_style ui_style = new_ui_style - build_hand_slots() + build_hand_slots(update_hud = TRUE) /datum/hud/proc/register_reuse(atom/movable/screen/reuse) asset_refs_for_reuse += WEAKREF(reuse) @@ -476,62 +472,80 @@ GLOBAL_LIST_INIT(available_ui_styles, list( else to_chat(usr, span_warning("This mob type does not use a HUD.")) +/// Rebuilds our mob's hand slot screen elements +/datum/hud/proc/build_hand_slots(update_hud = FALSE) + QDEL_LIST(hand_slots) + hand_slots = new /list(length(mymob.held_items)) -//(re)builds the hand ui slots, throwing away old ones -//not really worth jugglying existing ones so we just scrap+rebuild -//9/10 this is only called once per mob and only for 2 hands -/datum/hud/proc/build_hand_slots() - for(var/h in hand_slots) - var/atom/movable/screen/inventory/hand/H = hand_slots[h] - if(H) - static_inventory -= H - hand_slots = list() - var/atom/movable/screen/inventory/hand/hand_box - for(var/i in 1 to mymob.held_items.len) - hand_box = new /atom/movable/screen/inventory/hand(null, src) + for(var/i in 1 to length(mymob.held_items)) + var/atom/movable/screen/inventory/hand/hand_box = add_screen_object(/atom/movable/screen/inventory/hand, HUD_KEY_HAND_SLOT(i), HUD_GROUP_STATIC, ui_style, ui_hand_position(i)) hand_box.name = mymob.get_held_index_name(i) - hand_box.icon = ui_style hand_box.icon_state = "hand_[mymob.held_index_to_dir(i)]" - hand_box.screen_loc = ui_hand_position(i) hand_box.held_index = i - hand_slots["[i]"] = hand_box - static_inventory += hand_box hand_box.update_appearance() + hand_slots[i] = hand_box var/num_of_swaps = 0 - for(var/atom/movable/screen/swap_hand/swap_hands in static_inventory) + for(var/atom/movable/screen/swap_hand/swap_hands in screen_groups[HUD_GROUP_STATIC]) num_of_swaps += 1 var/hand_num = 1 - for(var/atom/movable/screen/swap_hand/swap_hands in static_inventory) + for(var/atom/movable/screen/swap_hand/swap_hands in screen_groups[HUD_GROUP_STATIC]) var/hand_ind = RIGHT_HANDS if (num_of_swaps > 1) hand_ind = IS_RIGHT_INDEX(hand_num) ? LEFT_HANDS : RIGHT_HANDS swap_hands.screen_loc = ui_swaphand_position(mymob, hand_ind) hand_num += 1 + hand_num = 1 - for(var/atom/movable/screen/drop/swap_hands in static_inventory) + + for(var/atom/movable/screen/drop/swap_hands in screen_groups[HUD_GROUP_STATIC]) var/hand_ind = LEFT_HANDS if (num_of_swaps > 1) hand_ind = IS_LEFT_INDEX(hand_num) ? LEFT_HANDS : RIGHT_HANDS swap_hands.screen_loc = ui_swaphand_position(mymob, hand_ind) hand_num += 1 - if(ismob(mymob) && mymob.hud_used == src) + if(update_hud && mymob?.hud_used == src) show_hud(hud_version) /// Handles dimming inventory slots that a mob can't equip items to in their current state /datum/hud/proc/update_locked_slots() return +/// Creates inventory slot screen elements based on our assigned inventory_slots +/datum/hud/proc/create_inventory_slots() + var/list/created_paths = inventory_slots + if (ispath(inventory_slots)) + created_paths = valid_subtypesof(inventory_slots) + + for (var/datum/inventory_slot/slot_type as anything in created_paths) + var/datum/inventory_slot/inv_slot = GLOB.inventory_slot_datums[slot_type] + if (!inv_slot) + stack_trace("[src] attempted to use an invalid inventory slot: [slot_type]") + continue + inv_slot.create_element(src) + + update_inventory_slots() + +/// Updates all of our inventory slots +/// Avoid calling directly in favor of specific update procs +/datum/hud/proc/update_inventory_slots() + for(var/atom/movable/screen/inventory/inv in screen_groups[HUD_GROUP_STATIC] + screen_groups[HUD_GROUP_TOGGLEABLE_INVENTORY]) + if(inv.slot_id) + inv_slots[TOBITSHIFT(inv.slot_id) + 1] = inv + inv.update_appearance() + /datum/hud/proc/position_action(atom/movable/screen/movable/action_button/button, position) // This is kinda a hack, I'm sorry. // Basically, FLOATING is never a valid position to pass into this proc. It exists as a generic marker for manually positioned buttons // Not as a position to target if(position == SCRN_OBJ_FLOATING) return + if(button.location != SCRN_OBJ_DEFAULT) hide_action(button) + switch(position) if(SCRN_OBJ_DEFAULT) // Reset to the default button.dump_save() // Nuke any existing saves @@ -548,6 +562,7 @@ GLOBAL_LIST_INIT(available_ui_styles, list( floating_actions += button button.screen_loc = position position = SCRN_OBJ_FLOATING + var/atom/movable/screen/button_palette/toggle_palette = screen_objects[HUD_MOB_TOGGLE_PALETTE] toggle_palette.update_state() button.location = position @@ -555,18 +570,24 @@ GLOBAL_LIST_INIT(available_ui_styles, list( /datum/hud/proc/position_action_relative(atom/movable/screen/movable/action_button/button, atom/movable/screen/movable/action_button/relative_to) if(button.location != SCRN_OBJ_DEFAULT) hide_action(button) + switch(relative_to.location) if(SCRN_OBJ_IN_LIST) listed_actions.insert_action(button, listed_actions.index_of(relative_to)) + if(SCRN_OBJ_IN_PALETTE) palette_actions.insert_action(button, palette_actions.index_of(relative_to)) + if(SCRN_OBJ_FLOATING) // If we don't have it as a define, this is a screen_loc, and we should be floating floating_actions += button var/client/our_client = mymob.canon_client if(!our_client) position_action(button, button.linked_action.default_button_position) return - button.screen_loc = get_valid_screen_location(relative_to.screen_loc, ICON_SIZE_ALL, our_client.view_size.getView()) // Asks for a location adjacent to our button that won't overflow the map + + // Asks for a location adjacent to our button that won't overflow the map + button.screen_loc = get_valid_screen_location(relative_to.screen_loc, ICON_SIZE_ALL, our_client.view_size.getView()) + var/atom/movable/screen/button_palette/toggle_palette = screen_objects[HUD_MOB_TOGGLE_PALETTE] toggle_palette.update_state() button.location = relative_to.location @@ -576,32 +597,44 @@ GLOBAL_LIST_INIT(available_ui_styles, list( switch(button.location) if(SCRN_OBJ_DEFAULT) // Invalid CRASH("We just tried to hide an action buttion that somehow has the default position as its location, you done fucked up") + if(SCRN_OBJ_FLOATING) floating_actions -= button + var/atom/movable/screen/button_palette/toggle_palette = screen_objects[HUD_MOB_TOGGLE_PALETTE] toggle_palette.update_state() + if(SCRN_OBJ_IN_LIST) listed_actions.remove_action(button) + if(SCRN_OBJ_IN_PALETTE) palette_actions.remove_action(button) + button.screen_loc = null /// Generates visual landings for all groups that the button is not a memeber of /datum/hud/proc/generate_landings(atom/movable/screen/movable/action_button/button) listed_actions.generate_landing() palette_actions.generate_landing() + var/atom/movable/screen/button_palette/toggle_palette = screen_objects[HUD_MOB_TOGGLE_PALETTE] toggle_palette.activate_landing() /// Clears all currently visible landings /datum/hud/proc/hide_landings() listed_actions.clear_landing() palette_actions.clear_landing() + var/atom/movable/screen/button_palette/toggle_palette = screen_objects[HUD_MOB_TOGGLE_PALETTE] toggle_palette.disable_landing() // Updates any existing "owned" visuals, ensures they continue to be visible /datum/hud/proc/update_our_owner() + var/atom/movable/screen/button_palette/toggle_palette = screen_objects[HUD_MOB_TOGGLE_PALETTE] + var/atom/movable/screen/palette_scroll/palette_down = screen_objects[HUD_MOB_PALETTE_DOWN] + var/atom/movable/screen/palette_scroll/palette_up = screen_objects[HUD_MOB_PALETTE_UP] + toggle_palette.refresh_owner() palette_down.refresh_owner() palette_up.refresh_owner() + listed_actions.update_landing() palette_actions.update_landing() @@ -628,214 +661,3 @@ GLOBAL_LIST_INIT(available_ui_styles, list( action.ShowTo(mymob) else position_action(button, button.location) - -/datum/action_group - /// The hud we're owned by - var/datum/hud/owner - /// The actions we're managing - var/list/atom/movable/screen/movable/action_button/actions - /// The initial vertical offset of our action buttons - var/north_offset = 0 - /// The pixel vertical offset of our action buttons - var/pixel_north_offset = 0 - /// Max amount of buttons we can have per row - /// Indexes at 1 - var/column_max = 0 - /// How far "ahead" of the first row we start. Lets us "scroll" our rows - /// Indexes at 1 - var/row_offset = 0 - /// How many rows of actions we can have at max before we just stop hiding - /// Indexes at 1 - var/max_rows = INFINITY - /// The screen location we go by - var/location - /// Our landing screen object - var/atom/movable/screen/action_landing/landing - -/datum/action_group/New(datum/hud/owner) - ..() - actions = list() - src.owner = owner - -/datum/action_group/Destroy() - owner = null - QDEL_NULL(landing) - QDEL_LIST(actions) - return ..() - -/datum/action_group/proc/insert_action(atom/movable/screen/action, index) - if(action in actions) - if(actions[index] == action) - return - actions -= action // Don't dupe, come on - if(!index) - index = length(actions) + 1 - index = min(length(actions) + 1, index) - actions.Insert(index, action) - refresh_actions() - -/datum/action_group/proc/remove_action(atom/movable/screen/action) - actions -= action - refresh_actions() - -/datum/action_group/proc/refresh_actions() - - // We don't use size() here because landings are not canon - var/total_rows = ROUND_UP(length(actions) / column_max) - total_rows -= max_rows // Lets get the amount of rows we're off from our max - row_offset = clamp(row_offset, 0, total_rows) // You're not allowed to offset so far that we have a row of blank space - - var/button_number = 0 - for(var/atom/movable/screen/button as anything in actions) - var/postion = ButtonNumberToScreenCoords(button_number ) - button.screen_loc = postion - button_number++ - - if(landing) - var/postion = ButtonNumberToScreenCoords(button_number, landing = TRUE) // Need a good way to count buttons off screen, but allow this to display in the right place if it's being placed with no concern for dropdown - landing.screen_loc = postion - button_number++ - -/// Accepts a number represeting our position in the group, indexes at 0 to make the math nicer -/datum/action_group/proc/ButtonNumberToScreenCoords(number, landing = FALSE) - var/row = round(number / column_max) - row -= row_offset // If you're less then 0, you don't get to render, this lets us "scroll" rows ya feel? - if(row < 0) - return null - - // Could use >= here, but I think it's worth noting that the two start at different places, since row is based on number here - if(row > max_rows - 1) - if(!landing) // If you're not a landing, go away please. thx - return null - // We always want to render landings, even if their action button can't be displayed. - // So we set a row equal to the max amount of rows + 1. Willing to overrun that max slightly to properly display the landing spot - row = max_rows // Remembering that max_rows indexes at 1, and row indexes at 0 - - // We're going to need to set our column to match the first item in the last row, so let's set number properly now - number = row * column_max - - var/visual_row = row + north_offset - var/coord_row = visual_row ? "-[visual_row]" : "+0" - - var/visual_column = number % column_max - var/coord_col = "+[visual_column]" - var/coord_col_offset = 4 + 2 * (visual_column + 1) - return "WEST[coord_col]:[coord_col_offset],NORTH[coord_row]:-[pixel_north_offset]" - -/datum/action_group/proc/check_against_view() - var/owner_view = owner?.mymob?.canon_client?.view - if(!owner_view) - return - // Unlikey as it is, we may have been changed. Want to start from our target position and fail down - column_max = initial(column_max) - // Convert our viewer's view var into a workable offset - var/list/view_size = view_to_pixels(owner_view) - - // We're primarially concerned about width here, if someone makes us 1x2000 I wish them a swift and watery death - var/furthest_screen_loc = ButtonNumberToScreenCoords(column_max - 1) - var/list/offsets = screen_loc_to_offset(furthest_screen_loc, owner_view) - if(offsets[1] > ICON_SIZE_X && offsets[1] < view_size[1] && offsets[2] > ICON_SIZE_Y && offsets[2] < view_size[2]) // We're all good - return - - for(column_max in column_max - 1 to 1 step -1) // Yes I could do this by unwrapping ButtonNumberToScreenCoords, but I don't feel like it - var/tested_screen_loc = ButtonNumberToScreenCoords(column_max) - offsets = screen_loc_to_offset(tested_screen_loc, owner_view) - // We've found a valid max length, pack it in - if(offsets[1] > ICON_SIZE_X && offsets[1] < view_size[1] && offsets[2] > ICON_SIZE_Y && offsets[2] < view_size[2]) - break - // Use our newly resized column max - refresh_actions() - -/// Returns the amount of objects we're storing at the moment -/datum/action_group/proc/size() - var/amount = length(actions) - if(landing) - amount += 1 - return amount - -/datum/action_group/proc/index_of(atom/movable/screen/get_location) - return actions.Find(get_location) - -/// Generates a landing object that can be dropped on to join this group -/datum/action_group/proc/generate_landing() - if(landing) - return - landing = new() - landing.set_owner(src) - refresh_actions() - -/// Clears any landing objects we may currently have -/datum/action_group/proc/clear_landing() - QDEL_NULL(landing) - -/datum/action_group/proc/update_landing() - if(!landing) - return - landing.refresh_owner() - -/datum/action_group/proc/scroll(amount) - row_offset += amount - refresh_actions() - -/datum/action_group/palette - north_offset = 2 - column_max = 3 - max_rows = 3 - location = SCRN_OBJ_IN_PALETTE - -/datum/action_group/palette/insert_action(atom/movable/screen/action, index) - . = ..() - var/atom/movable/screen/button_palette/palette = owner.toggle_palette - palette.play_item_added() - -/datum/action_group/palette/remove_action(atom/movable/screen/action) - . = ..() - var/atom/movable/screen/button_palette/palette = owner.toggle_palette - palette.play_item_removed() - if(!length(actions)) - palette.set_expanded(FALSE) - -/datum/action_group/palette/refresh_actions() - var/atom/movable/screen/button_palette/palette = owner.toggle_palette - var/atom/movable/screen/palette_scroll/scroll_down = owner.palette_down - var/atom/movable/screen/palette_scroll/scroll_up = owner.palette_up - - var/actions_above = round((owner.listed_actions.size() - 1) / owner.listed_actions.column_max) - north_offset = initial(north_offset) + actions_above - - palette.screen_loc = ui_action_palette_offset(actions_above) - var/action_count = length(owner?.mymob?.actions) - var/our_row_count = round((length(actions) - 1) / column_max) - if(!action_count) - palette.screen_loc = null - - if(palette.expanded && action_count && our_row_count >= max_rows) - scroll_down.screen_loc = ui_palette_scroll_offset(actions_above) - scroll_up.screen_loc = ui_palette_scroll_offset(actions_above) - else - scroll_down.screen_loc = null - scroll_up.screen_loc = null - - return ..() - -/datum/action_group/palette/ButtonNumberToScreenCoords(number, landing) - var/atom/movable/screen/button_palette/palette = owner.toggle_palette - if(palette.expanded) - return ..() - - if(!landing) - return null - - // We only render the landing in this case, so we force it to be the second item displayed (Second rather then first since it looks nicer) - // Remember the number var indexes at 0 - return ..(1 + (row_offset * column_max), landing) - - -/datum/action_group/listed - pixel_north_offset = 6 - column_max = 10 - location = SCRN_OBJ_IN_LIST - -/datum/action_group/listed/refresh_actions() - . = ..() - owner?.palette_actions.refresh_actions() // We effect them, so we gotta refresh em diff --git a/code/_onclick/hud/human.dm b/code/_onclick/hud/human.dm index 4e6ef6f0e2b..d8d55dccf16 100644 --- a/code/_onclick/hud/human.dm +++ b/code/_onclick/hud/human.dm @@ -1,328 +1,38 @@ -/atom/movable/screen/human - icon = 'icons/hud/screen_midnight.dmi' +/datum/hud/human + inventory_slots = /datum/inventory_slot/human -/atom/movable/screen/human/toggle - name = "toggle" - icon_state = "toggle" - base_icon_state = "toggle" - mouse_over_pointer = MOUSE_HAND_POINTER - -/atom/movable/screen/human/toggle/Click() - - var/mob/targetmob = usr - - if(isobserver(usr)) - if(ishuman(usr.client.eye) && (usr.client.eye != usr)) - var/mob/M = usr.client.eye - targetmob = M - - if(usr.hud_used.inventory_shown && targetmob.hud_used) - usr.hud_used.inventory_shown = FALSE - usr.client.screen -= targetmob.hud_used.toggleable_inventory - else - usr.hud_used.inventory_shown = TRUE - usr.client.screen += targetmob.hud_used.toggleable_inventory - - targetmob.hud_used.hidden_inventory_update(usr) - update_appearance() - -/atom/movable/screen/human/toggle/update_icon_state() - icon_state = "[base_icon_state][hud?.inventory_shown ? "_active" : ""]" - return ..() - -/atom/movable/screen/ling - icon = 'icons/hud/screen_changeling.dmi' - -/atom/movable/screen/ling/chems - name = "chemical storage" - icon_state = "power_display" - screen_loc = ui_lingchemdisplay - ///Boolean on whether a mouse is being hovered over us right now. - var/hovering = FALSE - -/atom/movable/screen/ling/chems/Click(location, control, params) +/datum/hud/human/initialize_screen_objects() . = ..() - to_chat(usr, span_notice("Shows you how many chemicals you have. While hovering over this, it will show the max amount of chemicals you can hold.")) - -/atom/movable/screen/ling/chems/MouseEntered(location,control,params) - if(usr != get_mob()) - return - var/datum/antagonist/changeling/antagonist_datum = IS_CHANGELING(hud.mymob) - if(!antagonist_datum) - return - . = ..() - hovering = TRUE - antagonist_datum.update_chemical_hud() - -/atom/movable/screen/ling/chems/MouseExited(location, control, params) - if(usr != get_mob()) - return - var/datum/antagonist/changeling/antagonist_datum = IS_CHANGELING(hud.mymob) - if(!antagonist_datum) - return - . = ..() - hovering = FALSE - antagonist_datum.update_chemical_hud(antagonist_datum.chem_charges) - -/atom/movable/screen/ling/sting - name = "current sting" - screen_loc = ui_lingstingdisplay - invisibility = INVISIBILITY_ABSTRACT - mouse_over_pointer = MOUSE_HAND_POINTER - -/atom/movable/screen/ling/sting/Click() - if(isobserver(usr)) - return - var/mob/living/carbon/carbon_user = usr - carbon_user.unset_sting() - -/datum/hud/human/New(mob/living/carbon/human/owner) - ..() - var/atom/movable/screen/using - var/atom/movable/screen/inventory/inv_box - - using = new /atom/movable/screen/language_menu(null, src) - using.icon = ui_style - using.screen_loc = ui_human_language - static_inventory += using - - using = new /atom/movable/screen/navigate(null, src) - using.icon = ui_style - using.screen_loc = ui_human_navigate - static_inventory += using - - using = new /atom/movable/screen/area_creator(null, src) - using.icon = ui_style - using.screen_loc = ui_human_area - static_inventory += using - - using = new /atom/movable/screen/memories(null, src) - using.icon = ui_style - using.screen_loc = ui_human_memories_area - static_inventory += using - - action_intent = new /atom/movable/screen/combattoggle/flashy(null, src) - action_intent.icon = ui_style - action_intent.screen_loc = ui_combat_toggle - static_inventory += action_intent - - floor_change = new /atom/movable/screen/floor_changer/vertical(null, src) - floor_change.icon = ui_style - floor_change.screen_loc = ui_human_floor_changer - static_inventory += floor_change - - using = new /atom/movable/screen/mov_intent(null, src) - using.icon = ui_style - using.icon_state = (owner.move_intent == MOVE_INTENT_RUN ? "running" : "walking") - using.screen_loc = ui_movi - static_inventory += using - - inv_box = new /atom/movable/screen/inventory(null, src) - inv_box.name = "uniform" - inv_box.icon = ui_style - inv_box.slot_id = ITEM_SLOT_ICLOTHING - inv_box.icon_state = "uniform" - inv_box.icon_full = "template" - inv_box.screen_loc = ui_iclothing - toggleable_inventory += inv_box - - inv_box = new /atom/movable/screen/inventory(null, src) - inv_box.name = "suit" - inv_box.icon = ui_style - inv_box.slot_id = ITEM_SLOT_OCLOTHING - inv_box.icon_state = "suit" - inv_box.icon_full = "template" - inv_box.screen_loc = ui_oclothing - toggleable_inventory += inv_box - + // Static elements + add_screen_object(/atom/movable/screen/language_menu, HUD_MOB_LANGUAGE_MENU, HUD_GROUP_STATIC, ui_style, ui_human_language) + add_screen_object(/atom/movable/screen/navigate, HUD_MOB_NAVIGATE_MENU, HUD_GROUP_STATIC, ui_style, ui_human_navigate) + add_screen_object(/atom/movable/screen/area_creator, HUD_MOB_AREA_CREATOR, HUD_GROUP_STATIC, ui_style, ui_human_area) + add_screen_object(/atom/movable/screen/combattoggle/flashy, HUD_MOB_INTENTS, HUD_GROUP_STATIC, ui_style) + add_screen_object(/atom/movable/screen/floor_changer/vertical, HUD_MOB_FLOOR_CHANGER, HUD_GROUP_STATIC, ui_style, ui_human_floor_changer) + add_screen_object(/atom/movable/screen/mov_intent, HUD_MOB_MOVE_INTENT, HUD_GROUP_STATIC, ui_style) + add_screen_object(/atom/movable/screen/drop, HUD_MOB_DROP, HUD_GROUP_STATIC, ui_style, ui_swaphand_position(mymob, 1)) + add_screen_object(/atom/movable/screen/human/toggle, HUD_HUMAN_TOGGLE_INVENTORY, HUD_GROUP_STATIC, ui_style) + add_screen_object(/atom/movable/screen/rest, HUD_MOB_REST, HUD_GROUP_STATIC, ui_style) + add_screen_object(/atom/movable/screen/sleep, HUD_MOB_SLEEP, HUD_GROUP_HOTKEYS, ui_style, ui_above_throw) + add_screen_object(/atom/movable/screen/pull, HUD_MOB_PULL, HUD_GROUP_STATIC, ui_style, ui_above_movement_top) + add_screen_object(/atom/movable/screen/zone_sel, HUD_MOB_ZONE_SELECTOR, HUD_GROUP_STATIC, ui_style) + add_screen_object(/atom/movable/screen/memories, HUD_MOB_MEMORIES, HUD_GROUP_STATIC, ui_style, ui_human_memories_menu) build_hand_slots() - using = new /atom/movable/screen/drop(null, src) - using.icon = ui_style - using.screen_loc = ui_swaphand_position(owner, 1) - static_inventory += using - - using = new /atom/movable/screen/swap_hand(null, src) - using.icon = ui_style + using = add_screen_object(/atom/movable/screen/swap_hand, HUD_MOB_SWAPHAND_2, HUD_GROUP_STATIC, ui_style, ui_swaphand_position(mymob, 2)) using.icon_state = "act_swap" - using.screen_loc = ui_swaphand_position(owner, 2) - static_inventory += using - inv_box = new /atom/movable/screen/inventory(null, src) - inv_box.name = "id" - inv_box.icon = ui_style - inv_box.icon_state = "id" - inv_box.icon_full = "template_small" - inv_box.screen_loc = ui_id - inv_box.slot_id = ITEM_SLOT_ID - static_inventory += inv_box + // Hotkey buttons + add_screen_object(/atom/movable/screen/resist, HUD_MOB_RESIST, HUD_GROUP_HOTKEYS, ui_style) + add_screen_object(/atom/movable/screen/throw_catch, HUD_MOB_THROW, HUD_GROUP_HOTKEYS, ui_style) - inv_box = new /atom/movable/screen/inventory(null, src) - inv_box.name = "mask" - inv_box.icon = ui_style - inv_box.icon_state = "mask" - inv_box.icon_full = "template" - inv_box.screen_loc = ui_mask - inv_box.slot_id = ITEM_SLOT_MASK - toggleable_inventory += inv_box - - inv_box = new /atom/movable/screen/inventory(null, src) - inv_box.name = "neck" - inv_box.icon = ui_style - inv_box.icon_state = "neck" - inv_box.icon_full = "template" - inv_box.screen_loc = ui_neck - inv_box.slot_id = ITEM_SLOT_NECK - toggleable_inventory += inv_box - - inv_box = new /atom/movable/screen/inventory(null, src) - inv_box.name = "back" - inv_box.icon = ui_style - inv_box.icon_state = "back" - inv_box.icon_full = "template_small" - inv_box.screen_loc = ui_back - inv_box.slot_id = ITEM_SLOT_BACK - static_inventory += inv_box - - inv_box = new /atom/movable/screen/inventory(null, src) - inv_box.name = "left pocket" - inv_box.icon = ui_style - inv_box.icon_state = "pocket" - inv_box.icon_full = "template_small" - inv_box.screen_loc = ui_storage1 - inv_box.slot_id = ITEM_SLOT_LPOCKET - static_inventory += inv_box - - inv_box = new /atom/movable/screen/inventory(null, src) - inv_box.name = "right pocket" - inv_box.icon = ui_style - inv_box.icon_state = "pocket" - inv_box.icon_full = "template_small" - inv_box.screen_loc = ui_storage2 - inv_box.slot_id = ITEM_SLOT_RPOCKET - static_inventory += inv_box - - inv_box = new /atom/movable/screen/inventory(null, src) - inv_box.name = "suit storage" - inv_box.icon = ui_style - inv_box.icon_state = "suit_storage" - inv_box.icon_full = "template" - inv_box.screen_loc = ui_sstore1 - inv_box.slot_id = ITEM_SLOT_SUITSTORE - static_inventory += inv_box - - resist_icon = new /atom/movable/screen/resist(null, src) - resist_icon.icon = ui_style - resist_icon.screen_loc = ui_above_movement - hotkeybuttons += resist_icon - - using = new /atom/movable/screen/human/toggle(null, src) - using.icon = ui_style - using.screen_loc = ui_inventory - static_inventory += using - - inv_box = new /atom/movable/screen/inventory(null, src) - inv_box.name = "gloves" - inv_box.icon = ui_style - inv_box.icon_state = "gloves" - inv_box.icon_full = "template" - inv_box.screen_loc = ui_gloves - inv_box.slot_id = ITEM_SLOT_GLOVES - toggleable_inventory += inv_box - - inv_box = new /atom/movable/screen/inventory(null, src) - inv_box.name = "eyes" - inv_box.icon = ui_style - inv_box.icon_state = "glasses" - inv_box.icon_full = "template" - inv_box.screen_loc = ui_glasses - inv_box.slot_id = ITEM_SLOT_EYES - toggleable_inventory += inv_box - - inv_box = new /atom/movable/screen/inventory(null, src) - inv_box.name = "ears" - inv_box.icon = ui_style - inv_box.icon_state = "ears" - inv_box.icon_full = "template" - inv_box.screen_loc = ui_ears - inv_box.slot_id = ITEM_SLOT_EARS - toggleable_inventory += inv_box - - inv_box = new /atom/movable/screen/inventory(null, src) - inv_box.name = "head" - inv_box.icon = ui_style - inv_box.icon_state = "head" - inv_box.icon_full = "template" - inv_box.screen_loc = ui_head - inv_box.slot_id = ITEM_SLOT_HEAD - toggleable_inventory += inv_box - - inv_box = new /atom/movable/screen/inventory(null, src) - inv_box.name = "shoes" - inv_box.icon = ui_style - inv_box.icon_state = "shoes" - inv_box.icon_full = "template" - inv_box.screen_loc = ui_shoes - inv_box.slot_id = ITEM_SLOT_FEET - toggleable_inventory += inv_box - - inv_box = new /atom/movable/screen/inventory(null, src) - inv_box.name = "belt" - inv_box.icon = ui_style - inv_box.icon_state = "belt" - inv_box.icon_full = "template_small" - inv_box.screen_loc = ui_belt - inv_box.slot_id = ITEM_SLOT_BELT - static_inventory += inv_box - - throw_icon = new /atom/movable/screen/throw_catch(null, src) - throw_icon.icon = ui_style - throw_icon.screen_loc = ui_drop_throw - hotkeybuttons += throw_icon - - rest_icon = new /atom/movable/screen/rest(null, src) - rest_icon.icon = ui_style - rest_icon.screen_loc = ui_rest - rest_icon.update_appearance() - static_inventory += rest_icon - - sleep_icon = new /atom/movable/screen/sleep(null, src) - sleep_icon.icon = ui_style - sleep_icon.screen_loc = ui_above_throw - - spacesuit_hud = new /atom/movable/screen/spacesuit(null, src) - infodisplay += spacesuit_hud - - healths = new /atom/movable/screen/healths(null, src) - infodisplay += healths - - hunger = new /atom/movable/screen/hunger(null, src) - infodisplay += hunger - - healthdoll = new /atom/movable/screen/healthdoll/human(null, src) - infodisplay += healthdoll - - stamina = new /atom/movable/screen/stamina(null, src) - infodisplay += stamina - - pull_icon = new /atom/movable/screen/pull(null, src) - pull_icon.icon = ui_style - pull_icon.screen_loc = ui_above_movement_top - pull_icon.update_appearance() - static_inventory += pull_icon - - zone_select = new /atom/movable/screen/zone_sel(null, src) - zone_select.icon = ui_style - zone_select.update_appearance() - static_inventory += zone_select - - for(var/atom/movable/screen/inventory/inv in (static_inventory + toggleable_inventory)) - if(inv.slot_id) - inv_slots[TOBITSHIFT(inv.slot_id) + 1] = inv - inv.update_appearance() - - update_locked_slots() + // Info + add_screen_object(/atom/movable/screen/spacesuit, HUD_MOB_SPACESUIT, HUD_GROUP_INFO) + add_screen_object(/atom/movable/screen/healthdoll/human, HUD_MOB_HEALTHDOLL, HUD_GROUP_INFO) + add_screen_object(/atom/movable/screen/stamina, HUD_MOB_STAMINA, HUD_GROUP_INFO) + add_screen_object(/atom/movable/screen/healths, HUD_MOB_HEALTH, HUD_GROUP_INFO) + add_screen_object(/atom/movable/screen/hunger, HUD_MOB_HUNGER, HUD_GROUP_INFO) /datum/hud/human/update_locked_slots() if(!mymob) @@ -355,8 +65,9 @@ if(eyes?.no_glasses) blocked_slots |= ITEM_SLOT_EYES - for(var/atom/movable/screen/inventory/inv in (static_inventory + toggleable_inventory)) - if(!inv.slot_id) + for(var/slot_key in screen_objects) + var/atom/movable/screen/inventory/inv = screen_objects[slot_key] + if(!istype(inv) || !inv.slot_id) continue inv.alpha = (blocked_slots & inv.slot_id) ? 128 : initial(inv.alpha) @@ -415,8 +126,6 @@ if(H.head) screenmob.client.screen -= H.head - - /datum/hud/human/persistent_inventory_update(mob/viewer) if(!mymob) return @@ -468,15 +177,131 @@ I.screen_loc = null screenmob.client.screen -= I - /mob/living/carbon/human/verb/toggle_hotkey_verbs() set category = "OOC" set name = "Toggle hotkey buttons" set desc = "This disables or enables the user interface buttons which can be used with hotkeys." if(hud_used.hotkey_ui_hidden) - client.screen += hud_used.hotkeybuttons + client.screen += hud_used.screen_groups[HUD_GROUP_HOTKEYS] hud_used.hotkey_ui_hidden = FALSE else - client.screen -= hud_used.hotkeybuttons + client.screen -= hud_used.screen_groups[HUD_GROUP_HOTKEYS] hud_used.hotkey_ui_hidden = TRUE + +/datum/inventory_slot/human + abstract_type = /datum/inventory_slot/human + +/datum/inventory_slot/human/uniform + name = "uniform" + slot_id = ITEM_SLOT_ICLOTHING + icon_state = "uniform" + icon_full = "template" + screen_loc = ui_iclothing + screen_group = HUD_GROUP_TOGGLEABLE_INVENTORY + +/datum/inventory_slot/human/suit + name = "suit" + slot_id = ITEM_SLOT_OCLOTHING + icon_state = "suit" + icon_full = "template" + screen_loc = ui_oclothing + screen_group = HUD_GROUP_TOGGLEABLE_INVENTORY + +/datum/inventory_slot/human/id + name = "id" + icon_state = "id" + icon_full = "template_small" + screen_loc = ui_id + slot_id = ITEM_SLOT_ID + +/datum/inventory_slot/human/mask + name = "mask" + icon_state = "mask" + icon_full = "template" + screen_loc = ui_mask + slot_id = ITEM_SLOT_MASK + screen_group = HUD_GROUP_TOGGLEABLE_INVENTORY + +/datum/inventory_slot/human/neck + name = "neck" + icon_state = "neck" + icon_full = "template" + screen_loc = ui_neck + slot_id = ITEM_SLOT_NECK + screen_group = HUD_GROUP_TOGGLEABLE_INVENTORY + +/datum/inventory_slot/human/back + name = "back" + icon_state = "back" + icon_full = "template_small" + screen_loc = ui_back + slot_id = ITEM_SLOT_BACK + +/datum/inventory_slot/human/l_pocket + name = "left pocket" + icon_state = "pocket" + icon_full = "template_small" + screen_loc = ui_storage1 + slot_id = ITEM_SLOT_LPOCKET + +/datum/inventory_slot/human/r_pocket + name = "right pocket" + icon_state = "pocket" + icon_full = "template_small" + screen_loc = ui_storage2 + slot_id = ITEM_SLOT_RPOCKET + +/datum/inventory_slot/human/suit_storage + name = "suit storage" + icon_state = "suit_storage" + icon_full = "template" + screen_loc = ui_sstore1 + slot_id = ITEM_SLOT_SUITSTORE + +/datum/inventory_slot/human/gloves + name = "gloves" + icon_state = "gloves" + icon_full = "template" + screen_loc = ui_gloves + slot_id = ITEM_SLOT_GLOVES + screen_group = HUD_GROUP_TOGGLEABLE_INVENTORY + +/datum/inventory_slot/human/eyes + name = "eyes" + icon_state = "glasses" + icon_full = "template" + screen_loc = ui_glasses + slot_id = ITEM_SLOT_EYES + screen_group = HUD_GROUP_TOGGLEABLE_INVENTORY + +/datum/inventory_slot/human/ears + name = "ears" + icon_state = "ears" + icon_full = "template" + screen_loc = ui_ears + slot_id = ITEM_SLOT_EARS + screen_group = HUD_GROUP_TOGGLEABLE_INVENTORY + +/datum/inventory_slot/human/head + name = "head" + icon_state = "head" + icon_full = "template" + screen_loc = ui_head + slot_id = ITEM_SLOT_HEAD + screen_group = HUD_GROUP_TOGGLEABLE_INVENTORY + +/datum/inventory_slot/human/shoes + name = "shoes" + icon_state = "shoes" + icon_full = "template" + screen_loc = ui_shoes + slot_id = ITEM_SLOT_FEET + screen_group = HUD_GROUP_TOGGLEABLE_INVENTORY + +/datum/inventory_slot/human/belt + name = "belt" + icon_state = "belt" + icon_full = "template_small" + screen_loc = ui_belt + slot_id = ITEM_SLOT_BELT diff --git a/code/_onclick/hud/inventory_slot.dm b/code/_onclick/hud/inventory_slot.dm new file mode 100644 index 00000000000..af3307be551 --- /dev/null +++ b/code/_onclick/hud/inventory_slot.dm @@ -0,0 +1,35 @@ +GLOBAL_LIST_INIT(inventory_slot_datums, initialize_inventory_slots()) + +/proc/initialize_inventory_slots() + var/list/slot_types = list() + for (var/slot_type in valid_subtypesof(/datum/inventory_slot)) + slot_types[slot_type] = new slot_type() + return slot_types + +/// Inventory slot datum (singleton) which holds data about an inventory screen element +/datum/inventory_slot + abstract_type = /datum/inventory_slot + /// Name assigned to the screen element + var/name = "error" + /// Should the slot inherit HUD's ui_style? + var/inherit_style = TRUE + /// Slot ID of the element + var/slot_id = NONE + /// Icon state of the element with nothing in it/unassigned icon_full + var/icon_state = "template" + /// Icon state of the element when it has an item in it + var/icon_full = "template" + /// Location of the element + var/screen_loc = null + /// Screen group to which the element is assigned + var/screen_group = HUD_GROUP_STATIC + /// Typepath of the screen element + var/screen_type = /atom/movable/screen/inventory + +/datum/inventory_slot/proc/create_element(datum/hud/hud) + var/atom/movable/screen/inventory/inv_box = hud.add_screen_object(screen_type, HUD_KEY_ITEM_SLOT(slot_id), screen_group, inherit_style ? hud.ui_style : null, screen_loc) + inv_box.name = name + inv_box.icon_state = icon_state + inv_box.icon_full = icon_full + inv_box.slot_id = slot_id + return inv_box diff --git a/code/_onclick/hud/living.dm b/code/_onclick/hud/living.dm index e9237d6dbb5..cd1575908e0 100644 --- a/code/_onclick/hud/living.dm +++ b/code/_onclick/hud/living.dm @@ -1,37 +1,9 @@ -/datum/hud/living/New(mob/living/owner) - ..() - - pull_icon = new /atom/movable/screen/pull(null, src) - pull_icon.icon = ui_style - pull_icon.update_appearance() - pull_icon.screen_loc = ui_living_pull - static_inventory += pull_icon - - action_intent = new /atom/movable/screen/combattoggle/flashy(null, src) - action_intent.icon = ui_style - action_intent.screen_loc = ui_basic_combat_toggle - static_inventory += action_intent - - floor_change = new /atom/movable/screen/floor_changer(null, src) - floor_change.icon = ui_style - floor_change.screen_loc = ui_floor_change - static_inventory += floor_change - - var/atom/movable/screen/using - - using = new /atom/movable/screen/language_menu(null, src) - using.icon = ui_style - using.screen_loc = ui_basic_language_menu - static_inventory += using - - using = new /atom/movable/screen/memories(null, src) - using.icon = ui_style - using.screen_loc = ui_basic_memories_menu - static_inventory += using - - //mob health doll assumes whatever sprite the mob is - healthdoll = new /atom/movable/screen/healthdoll/living(null, src) - infodisplay += healthdoll - - stamina = new /atom/movable/screen/stamina(null, src) - infodisplay += stamina +/datum/hud/living/initialize_screen_objects() + . = ..() + add_screen_object(/atom/movable/screen/pull, HUD_MOB_PULL, HUD_GROUP_STATIC, ui_style, ui_living_pull) + add_screen_object(/atom/movable/screen/combattoggle/flashy, HUD_MOB_INTENTS, HUD_GROUP_STATIC, ui_style, ui_basic_combat_toggle) + add_screen_object(/atom/movable/screen/healthdoll/living, HUD_MOB_HEALTHDOLL, HUD_GROUP_INFO) + add_screen_object(/atom/movable/screen/stamina, HUD_MOB_STAMINA, HUD_GROUP_INFO) + add_screen_object(/atom/movable/screen/floor_changer, HUD_MOB_FLOOR_CHANGER, HUD_GROUP_STATIC, ui_style, ui_floor_change) + add_screen_object(/atom/movable/screen/language_menu, HUD_MOB_LANGUAGE_MENU, HUD_GROUP_STATIC, ui_style, ui_basic_language_menu) + add_screen_object(/atom/movable/screen/memories, HUD_MOB_MEMORIES, HUD_GROUP_STATIC, ui_style, ui_basic_memories_menu) diff --git a/code/_onclick/hud/new_player.dm b/code/_onclick/hud/new_player.dm index 0b247aaa7da..fa991657de7 100644 --- a/code/_onclick/hud/new_player.dm +++ b/code/_onclick/hud/new_player.dm @@ -1,5 +1,3 @@ -#define SHUTTER_MOVEMENT_DURATION 0.4 SECONDS -#define SHUTTER_WAIT_DURATION 0.2 SECONDS /// Maximum number of station trait buttons we will display, please think hard before creating scenarios where there are more than this #define MAX_STATION_TRAIT_BUTTONS_VERTICAL 3 #define TRAIT_BUTTON_Y_ORIGIN 397 @@ -18,13 +16,11 @@ if (!owner?.client || owner.client.interviewee) return - var/list/buttons = subtypesof(/atom/movable/screen/lobby) - for (var/atom/movable/screen/lobby/lobbyscreen as anything in buttons) + for (var/atom/movable/screen/lobby/lobbyscreen as anything in subtypesof(/atom/movable/screen/lobby)) if (!initial(lobbyscreen.always_available)) continue - lobbyscreen = new lobbyscreen(our_hud = src) + lobbyscreen = add_screen_object(lobbyscreen, HUD_KEY_NEW_PLAYER(lobbyscreen)) lobbyscreen.SlowInit() - static_inventory += lobbyscreen if (!lobbyscreen.always_shown) lobbyscreen.RegisterSignal(src, COMSIG_HUD_LOBBY_COLLAPSED, TYPE_PROC_REF(/atom/movable/screen/lobby, collapse_button)) lobbyscreen.RegisterSignal(src, COMSIG_HUD_LOBBY_EXPANDED, TYPE_PROC_REF(/atom/movable/screen/lobby, expand_button)) @@ -32,9 +28,8 @@ if (!owner.client.is_localhost()) return - var/atom/movable/screen/lobby/button/start_now/start_button = new(our_hud = src) + var/atom/movable/screen/lobby/button/start_now/start_button = add_screen_object(/atom/movable/screen/lobby/button/start_now, HUD_NEW_PLAYER_START_NOW) start_button.SlowInit() - static_inventory += start_button start_button.RegisterSignal(src, COMSIG_HUD_LOBBY_COLLAPSED, TYPE_PROC_REF(/atom/movable/screen/lobby, collapse_button)) start_button.RegisterSignal(src, COMSIG_HUD_LOBBY_EXPANDED, TYPE_PROC_REF(/atom/movable/screen/lobby, expand_button)) @@ -52,9 +47,8 @@ continue if(LAZYACCESS(shown_station_trait_buttons, trait)) continue - var/atom/movable/screen/lobby/button/sign_up/sign_up_button = new(our_hud = src) + var/atom/movable/screen/lobby/button/sign_up/sign_up_button = add_screen_object(/atom/movable/screen/lobby/button/sign_up, HUD_NEW_PLAYER_SIGN_UP) trait.setup_lobby_button(sign_up_button) - static_inventory |= sign_up_button LAZYSET(shown_station_trait_buttons, trait, sign_up_button) RegisterSignal(trait, COMSIG_QDELETING, PROC_REF(remove_station_trait_button)) @@ -93,734 +87,9 @@ return LAZYREMOVE(shown_station_trait_buttons, trait) UnregisterSignal(trait, COMSIG_QDELETING) - static_inventory -= button qdel(button) place_station_trait_buttons() -/atom/movable/screen/lobby - plane = SPLASHSCREEN_PLANE - layer = LOBBY_MENU_LAYER - screen_loc = "TOP,CENTER" - /// Whether this HUD element can be hidden from the client's "screen" (moved off-screen) or not - var/always_shown = FALSE - /// If true we will create this button every time the HUD is generated - var/always_available = TRUE - -///Set the HUD in New, as lobby screens are made before Atoms are Initialized. -/atom/movable/screen/lobby/New(loc, datum/hud/our_hud, ...) - set_new_hud(our_hud) - return ..() - -///Run sleeping actions after initialize -/atom/movable/screen/lobby/proc/SlowInit() - return - -///Animates moving the button off-screen -/atom/movable/screen/lobby/proc/collapse_button() - SIGNAL_HANDLER - //wait for the shutter to come down - animate(src, transform = transform, time = SHUTTER_MOVEMENT_DURATION + SHUTTER_WAIT_DURATION) - //then pull the buttons up with the shutter - animate(transform = transform.Translate(x = 0, y = 146), time = SHUTTER_MOVEMENT_DURATION, easing = CUBIC_EASING|EASE_IN) - -///Animates moving the button back into place -/atom/movable/screen/lobby/proc/expand_button() - SIGNAL_HANDLER - //the buttons are off-screen, so we sync them up to come down with the shutter - animate(src, transform = matrix(), time = SHUTTER_MOVEMENT_DURATION, easing = CUBIC_EASING|EASE_OUT) - -/atom/movable/screen/lobby/background - icon = 'icons/hud/lobby/background.dmi' - icon_state = "background" - layer = LOBBY_BACKGROUND_LAYER - screen_loc = "TOP,CENTER:-61" - -/atom/movable/screen/lobby/button - mouse_over_pointer = MOUSE_HAND_POINTER - ///Is the button currently enabled? - VAR_PROTECTED/enabled = TRUE - ///Is the button currently being hovered over with the mouse? - var/highlighted = FALSE - ///Should this button play the select sound? - var/select_sound_play = TRUE - -/atom/movable/screen/lobby/button/Click(location, control, params) - if(usr != get_mob()) - return - - if(!usr.client || usr.client.interviewee) - return - - . = ..() - - if(!enabled) - return - flick("[base_icon_state]_pressed", src) - if(select_sound_play) - var/sound/ui_select_sound = sound('sound/misc/menu/ui_select1.ogg') - ui_select_sound.frequency = get_rand_frequency_low_range() - SEND_SOUND(hud.mymob, ui_select_sound) - update_appearance(UPDATE_ICON) - return TRUE - -/atom/movable/screen/lobby/button/MouseEntered(location,control,params) - if(usr != get_mob()) - return - - if(!usr.client || usr.client.interviewee) - return - - . = ..() - highlighted = TRUE - update_appearance(UPDATE_ICON) - -/atom/movable/screen/lobby/button/MouseExited() - if(usr != get_mob()) - return - - if(!usr.client || usr.client.interviewee) - return - - . = ..() - highlighted = FALSE - update_appearance(UPDATE_ICON) - -/atom/movable/screen/lobby/button/update_icon(updates) - . = ..() - if(!enabled) - icon_state = "[base_icon_state]_disabled" - return - else if(highlighted) - icon_state = "[base_icon_state]_highlighted" - return - icon_state = base_icon_state - -///Updates the button's status: TRUE to enable interaction with the button, FALSE to disable -/atom/movable/screen/lobby/button/proc/set_button_status(status) - if(status == enabled) - return FALSE - enabled = status - update_appearance(UPDATE_ICON) - mouse_over_pointer = enabled ? MOUSE_HAND_POINTER : MOUSE_INACTIVE_POINTER - return TRUE - -///Prefs menu -/atom/movable/screen/lobby/button/character_setup - name = "View Character Setup" - screen_loc = "TOP:-70,CENTER:-54" - icon = 'icons/hud/lobby/character_setup.dmi' - icon_state = "character_setup_disabled" - base_icon_state = "character_setup" - enabled = FALSE - -/atom/movable/screen/lobby/button/character_setup/Initialize(mapload, datum/hud/hud_owner) - . = ..() - // We need IconForge and the assets to be ready before allowing the menu to open - if(SSearly_assets.initialized == INITIALIZATION_INNEW_REGULAR || SSatoms.initialized == INITIALIZATION_INNEW_REGULAR) - flick("[base_icon_state]_enabled", src) - set_button_status(TRUE) - else - set_button_status(FALSE) - RegisterSignal(SSearly_assets, COMSIG_SUBSYSTEM_POST_INITIALIZE, PROC_REF(enable_character_setup)) - RegisterSignal(SSatoms, COMSIG_SUBSYSTEM_POST_INITIALIZE, PROC_REF(enable_character_setup)) - -/atom/movable/screen/lobby/button/character_setup/Click(location, control, params) - . = ..() - if(!.) - return - - var/datum/preferences/preferences = hud.mymob.canon_client.prefs - preferences.current_window = PREFERENCE_TAB_CHARACTER_PREFERENCES - preferences.update_static_data(usr) - preferences.ui_interact(usr) - -/atom/movable/screen/lobby/button/character_setup/proc/enable_character_setup() - SIGNAL_HANDLER - flick("[base_icon_state]_enabled", src) - set_button_status(TRUE) - UnregisterSignal(SSearly_assets, COMSIG_SUBSYSTEM_POST_INITIALIZE) - UnregisterSignal(SSatoms, COMSIG_SUBSYSTEM_POST_INITIALIZE) - -///Button that appears before the game has started -/atom/movable/screen/lobby/button/ready - name = "Toggle Readiness" - screen_loc = "TOP:-8,CENTER:-65" - icon = 'icons/hud/lobby/ready.dmi' - icon_state = "not_ready" - base_icon_state = "not_ready" - -/atom/movable/screen/lobby/button/ready/Initialize(mapload, datum/hud/hud_owner) - . = ..() - switch(SSticker.current_state) - if(GAME_STATE_PREGAME, GAME_STATE_STARTUP) - RegisterSignal(SSticker, COMSIG_TICKER_ENTER_SETTING_UP, PROC_REF(hide_ready_button)) - if(GAME_STATE_SETTING_UP) - set_button_status(FALSE) - RegisterSignal(SSticker, COMSIG_TICKER_ERROR_SETTING_UP, PROC_REF(show_ready_button)) - else - set_button_status(FALSE) - -/atom/movable/screen/lobby/button/ready/proc/hide_ready_button() - SIGNAL_HANDLER - set_button_status(FALSE) - UnregisterSignal(SSticker, COMSIG_TICKER_ENTER_SETTING_UP) - RegisterSignal(SSticker, COMSIG_TICKER_ERROR_SETTING_UP, PROC_REF(show_ready_button)) - -/atom/movable/screen/lobby/button/ready/proc/show_ready_button() - SIGNAL_HANDLER - set_button_status(TRUE) - UnregisterSignal(SSticker, COMSIG_TICKER_ERROR_SETTING_UP) - RegisterSignal(SSticker, COMSIG_TICKER_ENTER_SETTING_UP, PROC_REF(hide_ready_button)) - -/atom/movable/screen/lobby/button/ready/Click(location, control, params) - . = ..() - if(!.) - return - var/mob/dead/new_player/new_player = hud.mymob - - // switch based on the user, if they aren't ready then we change them to ready, and vice versa - if(new_player.ready == PLAYER_NOT_READY) - new_player.auto_deadmin_on_ready_or_latejoin() - new_player.ready = PLAYER_READY_TO_PLAY - base_icon_state = "ready" - else - new_player.ready = PLAYER_NOT_READY - base_icon_state = "not_ready" - - update_appearance(UPDATE_ICON) - SEND_SIGNAL(hud, COMSIG_HUD_PLAYER_READY_TOGGLE) - -///Shown when the game has started -/atom/movable/screen/lobby/button/join - name = "Join Game" - screen_loc = "TOP:-13,CENTER:-58" - icon = 'icons/hud/lobby/join.dmi' - icon_state = "" //Default to not visible - base_icon_state = "join_game" - enabled = null // set in init - -/atom/movable/screen/lobby/button/join/Initialize(mapload, datum/hud/hud_owner) - . = ..() - switch(SSticker.current_state) - if(GAME_STATE_PREGAME, GAME_STATE_STARTUP) - set_button_status(FALSE) - RegisterSignal(SSticker, COMSIG_TICKER_ENTER_SETTING_UP, PROC_REF(show_join_button)) - if(GAME_STATE_SETTING_UP) - set_button_status(TRUE) - RegisterSignal(SSticker, COMSIG_TICKER_ERROR_SETTING_UP, PROC_REF(hide_join_button)) - else - set_button_status(TRUE) - -/atom/movable/screen/lobby/button/join/Click(location, control, params) - . = ..() - if(!.) - return - - if(!SSticker?.IsRoundInProgress()) - to_chat(hud.mymob, span_boldwarning("The round is either not ready, or has already finished...")) - return - - //Determines Relevent Population Cap - var/relevant_cap - var/hard_popcap = CONFIG_GET(number/hard_popcap) - var/extreme_popcap = CONFIG_GET(number/extreme_popcap) - if(hard_popcap && extreme_popcap) - relevant_cap = min(hard_popcap, extreme_popcap) - else - relevant_cap = max(hard_popcap, extreme_popcap) - - var/mob/dead/new_player/new_player = hud.mymob - - if(SSticker.queued_players.len || (relevant_cap && living_player_count() >= relevant_cap && !(ckey(new_player.key) in GLOB.admin_datums))) - to_chat(new_player, span_danger("[CONFIG_GET(string/hard_popcap_message)]")) - - var/queue_position = SSticker.queued_players.Find(new_player) - if(queue_position == 1) - to_chat(new_player, span_notice("You are next in line to join the game. You will be notified when a slot opens up.")) - else if(queue_position) - to_chat(new_player, span_notice("There are [queue_position-1] players in front of you in the queue to join the game.")) - else - SSticker.queued_players += new_player - to_chat(new_player, span_notice("You have been added to the queue to join the game. Your position in queue is [SSticker.queued_players.len].")) - return - - new_player.auto_deadmin_on_ready_or_latejoin() - - if(!LAZYACCESS(params2list(params), CTRL_CLICK)) - GLOB.latejoin_menu.ui_interact(new_player) - else - to_chat(new_player, span_warning("Opening emergency fallback late join menu! If THIS doesn't show, ahelp immediately!")) - GLOB.latejoin_menu.fallback_ui(new_player) - - -/atom/movable/screen/lobby/button/join/proc/show_join_button() - SIGNAL_HANDLER - set_button_status(TRUE) - UnregisterSignal(SSticker, COMSIG_TICKER_ENTER_SETTING_UP) - RegisterSignal(SSticker, COMSIG_TICKER_ERROR_SETTING_UP, PROC_REF(hide_join_button)) - -/atom/movable/screen/lobby/button/join/proc/hide_join_button() - SIGNAL_HANDLER - set_button_status(FALSE) - UnregisterSignal(SSticker, COMSIG_TICKER_ERROR_SETTING_UP) - RegisterSignal(SSticker, COMSIG_TICKER_ENTER_SETTING_UP, PROC_REF(show_join_button)) - -/atom/movable/screen/lobby/button/observe - name = "Observe" - screen_loc = "TOP:-40,CENTER:-54" - icon = 'icons/hud/lobby/observe.dmi' - icon_state = "observe_disabled" - base_icon_state = "observe" - enabled = null // set in init - -/atom/movable/screen/lobby/button/observe/Initialize(mapload, datum/hud/hud_owner) - . = ..() - if(SSticker.current_state > GAME_STATE_STARTUP) - set_button_status(TRUE) - else - set_button_status(FALSE) - RegisterSignal(SSticker, COMSIG_TICKER_ENTER_PREGAME, PROC_REF(enable_observing)) - -/atom/movable/screen/lobby/button/observe/Click(location, control, params) - . = ..() - if(!.) - return - var/mob/dead/new_player/new_player = hud.mymob - new_player.make_me_an_observer() - -/atom/movable/screen/lobby/button/observe/proc/enable_observing() - SIGNAL_HANDLER - flick("[base_icon_state]_enabled", src) - set_button_status(TRUE) - UnregisterSignal(SSticker, COMSIG_TICKER_ENTER_PREGAME) - -//Subtype the bottom buttons away so the collapse/expand shutter goes behind them -/atom/movable/screen/lobby/button/bottom - layer = LOBBY_BOTTOM_BUTTON_LAYER - icon = 'icons/hud/lobby/bottom_buttons.dmi' - -/atom/movable/screen/lobby/button/bottom/settings - name = "View Game Preferences" - icon_state = "settings_disabled" - base_icon_state = "settings" - screen_loc = "TOP:-122,CENTER:+29" - enabled = FALSE - -/atom/movable/screen/lobby/button/bottom/settings/Initialize(mapload, datum/hud/hud_owner) - . = ..() - // We need IconForge and the assets to be ready before allowing the menu to open - if(SSearly_assets.initialized == INITIALIZATION_INNEW_REGULAR || SSatoms.initialized == INITIALIZATION_INNEW_REGULAR) - set_button_status(TRUE) - else - set_button_status(FALSE) - RegisterSignal(SSearly_assets, COMSIG_SUBSYSTEM_POST_INITIALIZE, PROC_REF(enable_settings)) - RegisterSignal(SSatoms, COMSIG_SUBSYSTEM_POST_INITIALIZE, PROC_REF(enable_settings)) - -/atom/movable/screen/lobby/button/bottom/settings/Click(location, control, params) - . = ..() - if(!.) - return - - var/datum/preferences/preferences = hud.mymob.canon_client.prefs - preferences.current_window = PREFERENCE_TAB_GAME_PREFERENCES - preferences.update_static_data(usr) - preferences.ui_interact(usr) - -/atom/movable/screen/lobby/button/bottom/settings/proc/enable_settings() - SIGNAL_HANDLER - set_button_status(TRUE) - UnregisterSignal(SSearly_assets, COMSIG_SUBSYSTEM_POST_INITIALIZE) - UnregisterSignal(SSatoms, COMSIG_SUBSYSTEM_POST_INITIALIZE) - -/atom/movable/screen/lobby/button/bottom/changelog_button - name = "View Changelog" - icon_state = "changelog" - base_icon_state = "changelog" - screen_loc ="TOP:-122,CENTER:+57" - -/atom/movable/screen/lobby/button/bottom/changelog_button/Click(location, control, params) - . = ..() - usr.client?.changelog() - -/atom/movable/screen/lobby/button/bottom/crew_manifest - name = "View Crew Manifest" - icon_state = "crew_manifest" - base_icon_state = "crew_manifest" - screen_loc = "TOP:-122,CENTER:+2" - -/atom/movable/screen/lobby/button/bottom/crew_manifest/Click(location, control, params) - . = ..() - if(!.) - return - var/mob/dead/new_player/new_player = hud.mymob - new_player.ViewManifest() - -/atom/movable/screen/lobby/button/bottom/poll - name = "View Available Polls" - icon_state = "poll" - base_icon_state = "poll" - screen_loc = "TOP:-122,CENTER:-26" - ///Whether the button should have a New Poll notification overlay - var/new_poll = FALSE - -/atom/movable/screen/lobby/button/bottom/poll/SlowInit(mapload) - . = ..() - if(!usr) - return - var/mob/dead/new_player/new_player = usr - if(is_guest_key(new_player.key)) - set_button_status(FALSE) - return - if(!SSdbcore.Connect()) - set_button_status(FALSE) - return - var/isadmin = FALSE - if(new_player.client?.holder) - isadmin = TRUE - var/datum/db_query/query_get_new_polls = SSdbcore.NewQuery({" - SELECT id FROM [format_table_name("poll_question")] - WHERE (adminonly = 0 OR :isadmin = 1) - AND Now() BETWEEN starttime AND endtime - AND deleted = 0 - AND id NOT IN ( - SELECT pollid FROM [format_table_name("poll_vote")] - WHERE ckey = :ckey - AND deleted = 0 - ) - AND id NOT IN ( - SELECT pollid FROM [format_table_name("poll_textreply")] - WHERE ckey = :ckey - AND deleted = 0 - ) - "}, list("isadmin" = isadmin, "ckey" = new_player.ckey)) - if(!query_get_new_polls.Execute()) - qdel(query_get_new_polls) - set_button_status(FALSE) - return - if(query_get_new_polls.NextRow()) - new_poll = TRUE - else - new_poll = FALSE - update_appearance(UPDATE_OVERLAYS) - qdel(query_get_new_polls) - if(QDELETED(new_player)) - set_button_status(FALSE) - return - -/atom/movable/screen/lobby/button/bottom/poll/update_overlays() - . = ..() - if(new_poll) - . += mutable_appearance('icons/hud/lobby/poll_overlay.dmi', "new_poll") - -/atom/movable/screen/lobby/button/bottom/poll/Click(location, control, params) - . = ..() - if(!.) - return - var/mob/dead/new_player/new_player = hud.mymob - new_player.handle_player_polling() - -/// A generic "sign up" button used by station traits -/atom/movable/screen/lobby/button/sign_up - icon = 'icons/hud/lobby/signup_button.dmi' - icon_state = "signup" - base_icon_state = "signup" - always_available = FALSE - -/atom/movable/screen/lobby/button/sign_up/MouseEntered(location, control, params) - . = ..() - if(QDELETED(src) || !desc) - return - openToolTip(usr, tip_src = src, params = params, title = name, content = desc,) - -/atom/movable/screen/lobby/button/sign_up/MouseExited() - . = ..() - closeToolTip(usr) - -/atom/movable/screen/lobby/button/collapse - name = "Collapse Lobby Menu" - icon = 'icons/hud/lobby/collapse_expand.dmi' - icon_state = "collapse" - base_icon_state = "collapse" - layer = LOBBY_BELOW_MENU_LAYER - screen_loc = "TOP:-82,CENTER:-54" - always_shown = TRUE - - var/blip_enabled = TRUE - -/atom/movable/screen/lobby/button/collapse/Initialize(mapload, datum/hud/hud_owner) - . = ..() - switch(SSticker.current_state) - if(GAME_STATE_PREGAME, GAME_STATE_STARTUP) - RegisterSignal(SSticker, COMSIG_TICKER_ENTER_SETTING_UP, PROC_REF(disable_blip)) - RegisterSignal(hud, COMSIG_HUD_PLAYER_READY_TOGGLE, PROC_REF(on_player_ready_toggle)) - if(GAME_STATE_SETTING_UP) - blip_enabled = FALSE - RegisterSignal(SSticker, COMSIG_TICKER_ERROR_SETTING_UP, PROC_REF(enable_blip)) - else - blip_enabled = FALSE - - add_overlay(get_blip_overlay()) - update_icon(UPDATE_OVERLAYS) - -/atom/movable/screen/lobby/button/collapse/update_overlays() - . = ..() - . += get_blip_overlay() - -/atom/movable/screen/lobby/button/collapse/Click(location, control, params) - . = ..() - if(!.) - return - - if(!istype(hud, /datum/hud/new_player)) - return - var/datum/hud/new_player/our_hud = hud - base_icon_state = our_hud.menu_hud_status ? "expand" : "collapse" - name = "[our_hud.menu_hud_status ? "Expand" : "Collapse"] Lobby Menu" - set_button_status(FALSE) - - //get the shutter object used by our hud - var/atom/movable/screen/lobby/shutter/menu_shutter = locate(/atom/movable/screen/lobby/shutter) in hud.static_inventory - - //animate the shutter - menu_shutter.setup_shutter_animation() - //animate bottom buttons' movement - if(our_hud.menu_hud_status) - collapse_menu() - else - expand_menu() - our_hud.menu_hud_status = !our_hud.menu_hud_status - - //re-enable clicking the button when the shutter animation finishes - //we use sleep here so it can work during game setup, as addtimer would not work until the game would finish setting up - sleep(2 * SHUTTER_MOVEMENT_DURATION + SHUTTER_WAIT_DURATION) - set_button_status(TRUE) - -///Proc to update the ready blip state upon new player's ready status change -/atom/movable/screen/lobby/button/collapse/proc/on_player_ready_toggle() - SIGNAL_HANDLER - update_appearance(UPDATE_ICON) - -///Returns a ready blip overlay depending on the player's ready state -/atom/movable/screen/lobby/button/collapse/proc/get_blip_overlay() - var/blip_icon_state = "ready_blip" - if(blip_enabled && hud) - var/mob/dead/new_player/new_player = hud.mymob - blip_icon_state += "_[new_player.is_ready_to_play() ? "" : "not_"]ready" - else - blip_icon_state += "_disabled" - var/mutable_appearance/ready_blip = mutable_appearance(icon, blip_icon_state) - return ready_blip - -///Disables the ready blip; makes us listen for the setup error to re-enable the blip -/atom/movable/screen/lobby/button/collapse/proc/disable_blip() - SIGNAL_HANDLER - blip_enabled = FALSE - UnregisterSignal(SSticker, COMSIG_TICKER_ENTER_SETTING_UP) - RegisterSignal(SSticker, COMSIG_TICKER_ERROR_SETTING_UP, PROC_REF(enable_blip)) - update_appearance(UPDATE_ICON) - -///Enables the ready blip; makes us listen for the setup completion and game start to disable the blip -/atom/movable/screen/lobby/button/collapse/proc/enable_blip() - SIGNAL_HANDLER - blip_enabled = TRUE - UnregisterSignal(SSticker, COMSIG_TICKER_ERROR_SETTING_UP) - RegisterSignal(SSticker, COMSIG_TICKER_ENTER_SETTING_UP, PROC_REF(disable_blip)) - update_appearance(UPDATE_ICON) - -///Moves the button to the top of the screen, leaving only the screen part in view -///Sends a signal on the hud for the menu hud elements to listen to -/atom/movable/screen/lobby/button/collapse/proc/collapse_menu() - SEND_SIGNAL(hud, COMSIG_HUD_LOBBY_COLLAPSED) - //wait for the shutter to come down - animate(src, transform = transform, time = SHUTTER_MOVEMENT_DURATION + SHUTTER_WAIT_DURATION) - //then pull the button up with the shutter and leave it on the edge of the screen - animate(transform = transform.Translate(x = 0, y = 134), time = SHUTTER_MOVEMENT_DURATION, easing = CUBIC_EASING|EASE_IN) - SEND_SOUND(hud.mymob, sound('sound/misc/menu/menu_rollup1.ogg')) - -///Extends the button back to its usual spot -///Sends a signal on the hud for the menu hud elements to listen to -/atom/movable/screen/lobby/button/collapse/proc/expand_menu() - SEND_SIGNAL(hud, COMSIG_HUD_LOBBY_EXPANDED) - animate(src, transform = matrix(), time = SHUTTER_MOVEMENT_DURATION, easing = CUBIC_EASING|EASE_OUT) - SEND_SOUND(hud.mymob, sound('sound/misc/menu/menu_rolldown1.ogg')) - -/atom/movable/screen/lobby/shutter - icon = 'icons/hud/lobby/shutter.dmi' - icon_state = "shutter" - base_icon_state = "shutter" - screen_loc = "TOP:+143,CENTER:-73" //"home" position is off-screen - layer = LOBBY_SHUTTER_LAYER - always_shown = TRUE - -///Sets up the shutter pulling down and up. It's the same animation for both collapsing and expanding the menu. -/atom/movable/screen/lobby/shutter/proc/setup_shutter_animation() - //bring down the shutter - animate(src, transform = transform.Translate(x = 0, y = -143), time = SHUTTER_MOVEMENT_DURATION, easing = CUBIC_EASING|EASE_OUT) - - //wait a little bit before bringing the shutter up - animate(transform = transform, time = SHUTTER_WAIT_DURATION) - - //pull the shutter back off-screen - animate(transform = matrix(), time = SHUTTER_MOVEMENT_DURATION, easing = CUBIC_EASING|EASE_IN) - -/// LOCALHOST ONLY - Start Now button -/atom/movable/screen/lobby/button/start_now - name = "Start Now (LOCALHOST ONLY)" - screen_loc = "TOP:-146,CENTER:-54" - icon = 'icons/hud/lobby/start_now.dmi' - icon_state = "start_now" - base_icon_state = "start_now" - always_available = FALSE - select_sound_play = FALSE - -/atom/movable/screen/lobby/button/start_now/Click(location, control, params) - . = ..() - if(!. || !usr.client.is_localhost() || !check_rights_for(usr.client, R_SERVER)) - return - SEND_SOUND(hud.mymob, sound('sound/effects/cartoon_sfx/cartoon_splat.ogg', volume = 50)) - SSticker.start_immediately = TRUE - if(SSticker.current_state == GAME_STATE_STARTUP) - to_chat(usr, span_admin("The server is still setting up, but the round will be started as soon as possible.")) - -#define OVERLAY_X_DIFF 12 -#define OVERLAY_Y_DIFF 5 - -///Lobby screen that appears before the game has started showing how many players there are and who is ready. -/atom/movable/screen/lobby/new_player_info - name = "New Player Info" - screen_loc = "EAST-3,CENTER:140" - icon = 'icons/hud/lobby/newplayer.dmi' - icon_state = null //we only show up when we get update appearance called, cause we need our overlay to not look bad. - base_icon_state = "newplayer" - maptext_height = 75 - maptext_width = 80 - maptext_x = OVERLAY_X_DIFF - maptext_y = OVERLAY_Y_DIFF - - ///Boolean on whether or not we should have our static overlay, so we 'turn' the TV off when collapsing. - var/show_static = TRUE - ///Static mutable appearance of a job icon we're displaying on the TV for overflow job. - var/static/mutable_appearance/job_overlay - -/atom/movable/screen/lobby/new_player_info/Initialize(mapload, datum/hud/hud_owner) - . = ..() - START_PROCESSING(SSnewplayer_info, src) - update_text() - - //only go if the station trait is selected, otherwise it'll show "Assistant" every round. - var/datum/station_trait/overflow_job_bureaucracy/overflow_job = locate() in SSstation.station_traits - if(overflow_job && isnull(job_overlay)) - var/icon/job_icon = get_job_hud_icon(SSjob.overflow_role) - if(isnull(job_icon)) - stack_trace("[SSjob.overflow_role::title] was selected as the Job Overflow but has no icon!") - else - job_icon.Scale(ICON_SIZE_X / 2, ICON_SIZE_X / 2) - job_overlay = mutable_appearance(job_icon, offset_spokesman = src, alpha = 120, layer = src.layer+0.02) - var/matrix/job_matrix = matrix() - job_matrix.Translate(6, 14) //this is completely arbitruary just what I thought looked good. - job_overlay.transform = job_matrix - - update_appearance(UPDATE_ICON) - -/atom/movable/screen/lobby/new_player_info/Destroy() - STOP_PROCESSING(SSnewplayer_info, src) - return ..() - -/atom/movable/screen/lobby/new_player_info/MouseEntered(location, control, params) - . = ..() - if(QDELETED(src) || isnull(job_overlay)) - return - openToolTip(usr, src, params, title = "[SSjob.overflow_role::title] overflow", content = "The overflow for the round has been set as [SSjob.overflow_role::title].") - -/atom/movable/screen/lobby/new_player_info/MouseExited() - closeToolTip(usr) - return ..() - -/atom/movable/screen/lobby/new_player_info/update_icon_state() - . = ..() - icon_state = base_icon_state - -/atom/movable/screen/lobby/new_player_info/update_overlays() - . = ..() - . += mutable_appearance(icon, "[base_icon_state]_overlay", layer = src.layer+0.01) - if(!show_static) - return . - if(job_overlay) - . += job_overlay - . += mutable_appearance(icon, "static_base", alpha = 20, layer = src.layer+0.03) - //we have this in a separate file because `generate_icon_alpha_mask` puts lighting even on non-existent pixels, - //giving the icon a weird background color. - var/mutable_appearance/scanline = mutable_appearance(generate_icon_alpha_mask('icons/hud/lobby/newplayer_scanline.dmi', "scanline"), alpha = 20, layer = src.layer+0.04) - scanline.pixel_y = OVERLAY_X_DIFF - scanline.pixel_x = OVERLAY_Y_DIFF - . += scanline - -/atom/movable/screen/lobby/new_player_info/process(seconds_per_tick) - update_text() - -/atom/movable/screen/lobby/new_player_info/collapse_button() - show_static = FALSE - update_text() - //to be in sync with parent, we'll turn the TV off in this time instead. - animate(src, appearance = update_appearance(UPDATE_ICON), time = SHUTTER_MOVEMENT_DURATION + SHUTTER_WAIT_DURATION) - //we go to the right, not up - animate(transform = transform.Translate(x = 146, y = 0), time = SHUTTER_MOVEMENT_DURATION, easing = CUBIC_EASING|EASE_IN) - -/atom/movable/screen/lobby/new_player_info/expand_button() - . = ..() - show_static = TRUE - update_appearance(UPDATE_ICON) - update_text() - -/atom/movable/screen/lobby/new_player_info/proc/update_text() - if(!hud || !show_static) - maptext = null - return - - var/round_started = SSticker.HasRoundStarted() - if(!MC_RUNNING()) - maptext = MAPTEXT("[(round_started ? null : "Starting in [time_remaining_str()]
")]Loading...
") - return - if(SSticker.IsPostgame()) - maptext = MAPTEXT("Game ended,
\ - restart soon
") - return - - var/new_maptext - if(round_started) - new_maptext = "[SSmapping.current_map.map_name]
\ - [LAZYLEN(GLOB.clients)] player\s online
\ - [ROUND_TIME()] in
" - new_maptext += "
" - else - - if(hud.mymob.client?.holder) - new_maptext = "Starting in [time_remaining_str()]
\ - [LAZYLEN(GLOB.clients)] player\s
\ - [SSticker.totalPlayersReady] players ready
\ - [SSticker.total_admins_ready] / [length(GLOB.admins)] admins ready
" - else - new_maptext = "[time_remaining_str()]
\ - [LAZYLEN(GLOB.clients)] player\s" - - maptext = MAPTEXT(new_maptext) - -/atom/movable/screen/lobby/new_player_info/proc/time_remaining_str() - var/time_remaining = SSticker.GetTimeLeft() - if(time_remaining > 0) - time_remaining = "[round(time_remaining/10)]s" - else if(time_remaining == -10) - time_remaining = "DELAYED" - else - time_remaining = "SOON" - - return time_remaining - -#undef OVERLAY_X_DIFF -#undef OVERLAY_Y_DIFF - -#undef SHUTTER_MOVEMENT_DURATION -#undef SHUTTER_WAIT_DURATION #undef MAX_STATION_TRAIT_BUTTONS_VERTICAL #undef TRAIT_BUTTON_Y_ORIGIN #undef TRAIT_BUTTON_X_ORIGIN diff --git a/code/_onclick/hud/ooze.dm b/code/_onclick/hud/ooze.dm index 0962b58126a..e796df33b4a 100644 --- a/code/_onclick/hud/ooze.dm +++ b/code/_onclick/hud/ooze.dm @@ -1,14 +1,8 @@ ///Hud type with targeting dol and a nutrition bar -/datum/hud/ooze/New(mob/living/owner) +/datum/hud/ooze/initialize_screen_objects() . = ..() - - zone_select = new /atom/movable/screen/zone_sel(null, src) - zone_select.icon = ui_style - zone_select.update_appearance() - static_inventory += zone_select - - alien_plasma_display = new /atom/movable/screen/ooze_nutrition_display(null, src) //Just going to use the alien plasma display because making new vars for each object is braindead. - infodisplay += alien_plasma_display + add_screen_object(/atom/movable/screen/zone_sel, HUD_MOB_ZONE_SELECTOR, HUD_GROUP_STATIC, ui_style) + add_screen_object(/atom/movable/screen/ooze_nutrition_display, HUD_OOZE_NUTRITION_DISPLAY) /atom/movable/screen/ooze_nutrition_display icon = 'icons/hud/screen_alien.dmi' diff --git a/code/_onclick/hud/pai.dm b/code/_onclick/hud/pai.dm new file mode 100644 index 00000000000..74da5962b37 --- /dev/null +++ b/code/_onclick/hud/pai.dm @@ -0,0 +1,33 @@ + +/datum/hud/pai + ui_style = 'icons/hud/screen_pai.dmi' + +/datum/hud/pai/initialize_screen_objects() + . = ..() + add_screen_object(/atom/movable/screen/language_menu, HUD_MOB_LANGUAGE_MENU, ui_style, ui_pai_language_menu) + add_screen_object(/atom/movable/screen/navigate, HUD_MOB_NAVIGATE_MENU, ui_style, ui_pai_navigate_menu) + add_screen_object(/atom/movable/screen/memories, HUD_MOB_MEMORIES, HUD_GROUP_STATIC, ui_style, ui_pai_memories_menu) + + add_screen_object(/atom/movable/screen/pai/software, HUD_PAI_SOFTWARE) + add_screen_object(/atom/movable/screen/pai/shell, HUD_PAI_SHELL) + add_screen_object(/atom/movable/screen/pai/chassis, HUD_PAI_CHASSIS) + add_screen_object(/atom/movable/screen/pai/rest, HUD_MOB_REST) + add_screen_object(/atom/movable/screen/pai/light, HUD_CYBORG_LAMP) + add_screen_object(/atom/movable/screen/pai/newscaster, HUD_PAI_NEWSCASTER) + add_screen_object(/atom/movable/screen/pai/host_monitor, HUD_PAI_HOST_MONITOR) + add_screen_object(/atom/movable/screen/pai/crew_manifest, HUD_AI_CREW_MANIFEST) + add_screen_object(/atom/movable/screen/pai/state_laws, HUD_AI_STATE_LAWS) + add_screen_object(/atom/movable/screen/pai/internal_gps, HUD_PAI_GPS) + add_screen_object(/atom/movable/screen/pai/image_take, HUD_AI_TAKE_IMAGE) + add_screen_object(/atom/movable/screen/pai/image_view, HUD_AI_IMAGE_VIEW) + add_screen_object(/atom/movable/screen/pai/radio, HUD_CYBORG_RADIO) + add_screen_object(/atom/movable/screen/pai/modpc, HUD_SILICON_TABLET) + + update_software_buttons() + +/datum/hud/pai/proc/update_software_buttons() + var/mob/living/silicon/pai/owner = mymob + for(var/button_key in screen_objects) + var/atom/movable/screen/pai/button = screen_objects[button_key] + if(istype(button) && button.required_software) + button.color = owner.installed_software.Find(button.required_software) ? null : COLOR_GRAY diff --git a/code/_onclick/hud/parallax/parallax.dm b/code/_onclick/hud/parallax/parallax.dm index 8a2227db588..c29e45dfde7 100644 --- a/code/_onclick/hud/parallax/parallax.dm +++ b/code/_onclick/hud/parallax/parallax.dm @@ -201,7 +201,6 @@ hud_used.set_parallax_movedir(areaobj.parallax_movedir, TRUE) // Root object for parallax, all parallax layers are drawn onto this and it manages them -INITIALIZE_IMMEDIATE(/atom/movable/screen/parallax_home) /atom/movable/screen/parallax_home icon = null blend_mode = BLEND_ADD @@ -293,7 +292,6 @@ INITIALIZE_IMMEDIATE(/atom/movable/screen/parallax_home) QDEL_LIST(parallax_layers_cached) // We need parallax to always pass its args down into initialize, so we immediate init it -INITIALIZE_IMMEDIATE(/atom/movable/screen/parallax_layer) /atom/movable/screen/parallax_layer icon = 'icons/effects/parallax.dmi' var/speed = 1 diff --git a/code/_onclick/hud/perks.dm b/code/_onclick/hud/perks.dm deleted file mode 100644 index 22b08906b66..00000000000 --- a/code/_onclick/hud/perks.dm +++ /dev/null @@ -1,35 +0,0 @@ -/atom/movable/screen/perk - icon = 'icons/hud/perks.dmi' - name = "blank" - icon_state = "blank" - -/atom/movable/screen/perk/more - name = "more" - icon_state = "more" - // When compact we don't show our perk huds in ui. - var/compact = FALSE - // List of all perks that we see on hud. - var/list/perks_on_hud = list() - // List to remember all perks we hide when compact it. - var/list/perks_compacted = list() - -/atom/movable/screen/perk/more/Click(location, control, params) - . = ..() - if(!isliving(usr)) - return - var/mob/living/usr_is_living = usr - var/datum/antagonist/wizard/wizard_datum = usr_is_living.mind.has_antag_datum(/datum/antagonist/wizard) - if(!wizard_datum) - return - compact = !compact - var/datum/hud/user_hud = usr_is_living.hud_used - if(compact) - for(var/atom/movable/screen/perk/perk_on_hud as anything in perks_on_hud) - perks_compacted += perk_on_hud - user_hud.infodisplay -= perk_on_hud - user_hud.show_hud(user_hud.hud_version) - else - for(var/atom/movable/screen/perk/perk_compacted as anything in perks_compacted) - user_hud.infodisplay += perk_compacted - perks_compacted -= perk_compacted - user_hud.show_hud(user_hud.hud_version) diff --git a/code/_onclick/hud/rendering/plane_masters/_plane_master.dm b/code/_onclick/hud/rendering/plane_masters/_plane_master.dm index 02d1f0ca3b4..c1efa44f8a3 100644 --- a/code/_onclick/hud/rendering/plane_masters/_plane_master.dm +++ b/code/_onclick/hud/rendering/plane_masters/_plane_master.dm @@ -1,6 +1,3 @@ -// I hate this place -INITIALIZE_IMMEDIATE(/atom/movable/screen/plane_master) - /atom/movable/screen/plane_master screen_loc = "CENTER" icon_state = "blank" diff --git a/code/_onclick/hud/revenanthud.dm b/code/_onclick/hud/revenanthud.dm index c47ea4c2418..49d89fb159e 100644 --- a/code/_onclick/hud/revenanthud.dm +++ b/code/_onclick/hud/revenanthud.dm @@ -1,14 +1,7 @@ /datum/hud/revenant ui_style = 'icons/hud/screen_gen.dmi' -/datum/hud/revenant/New(mob/owner) - ..() - - pull_icon = new /atom/movable/screen/pull(null, src) - pull_icon.icon = ui_style - pull_icon.update_appearance() - pull_icon.screen_loc = ui_living_pull - static_inventory += pull_icon - - healths = new /atom/movable/screen/healths/revenant(null, src) - infodisplay += healths +/datum/hud/revenant/initialize_screen_objects() + . = ..() + add_screen_object(/atom/movable/screen/pull, HUD_MOB_PULL, HUD_GROUP_STATIC, ui_style, ui_living_pull) + add_screen_object(/atom/movable/screen/healths/revenant, HUD_MOB_HEALTH, HUD_GROUP_INFO) diff --git a/code/_onclick/hud/robot.dm b/code/_onclick/hud/robot.dm index 498d58dccb2..53b146b5b03 100644 --- a/code/_onclick/hud/robot.dm +++ b/code/_onclick/hud/robot.dm @@ -1,184 +1,38 @@ -/atom/movable/screen/robot - icon = 'icons/hud/screen_cyborg.dmi' - mouse_over_pointer = MOUSE_HAND_POINTER - -/atom/movable/screen/robot/module - name = "cyborg module" - icon_state = "nomod" - -/atom/movable/screen/robot/Click(location, control, params) - if(isobserver(usr)) - return TRUE - -/atom/movable/screen/robot/module/Click(location, control, params) - . = ..() - var/mob/living/silicon/robot/robot_owner = hud.mymob - if(robot_owner.model.type == /obj/item/robot_model) - if(.) - return - robot_owner.pick_model() - return - var/list/modifiers = params2list(params) - if(robot_owner.module_active && !LAZYACCESS(modifiers, RIGHT_CLICK) && !.) - robot_owner.uneq_active() - return - - //observers can look at borg's inventories, so we ignore parent return value here, unlike everywhere else. - if(usr.active_storage == robot_owner.model.atom_storage) - robot_owner.model.atom_storage.hide_contents(usr) - else - robot_owner.model.atom_storage.open_storage(usr) - return TRUE - -/atom/movable/screen/robot/module1 - name = "module1" - icon_state = "inv1" - -/atom/movable/screen/robot/module1/Click() - if(..()) - return - var/mob/living/silicon/robot/R = usr - R.toggle_module(1) - -/atom/movable/screen/robot/module2 - name = "module2" - icon_state = "inv2" - -/atom/movable/screen/robot/module2/Click() - if(..()) - return - var/mob/living/silicon/robot/R = usr - R.toggle_module(2) - -/atom/movable/screen/robot/module3 - name = "module3" - icon_state = "inv3" - -/atom/movable/screen/robot/module3/Click() - if(..()) - return - var/mob/living/silicon/robot/R = usr - R.toggle_module(3) - -/atom/movable/screen/robot/radio - name = "radio" - icon_state = "radio" - -/atom/movable/screen/robot/radio/Click() - if(..()) - return - var/mob/living/silicon/robot/R = usr - R.radio.interact(R) - /datum/hud/robot ui_style = 'icons/hud/screen_cyborg.dmi' -/datum/hud/robot/New(mob/owner) - ..() +/datum/hud/robot/initialize_screen_objects() + . = ..() // i, Robit var/mob/living/silicon/robot/robit = mymob - var/atom/movable/screen/using + add_screen_object(/atom/movable/screen/language_menu, HUD_MOB_LANGUAGE_MENU, HUD_GROUP_STATIC, ui_style, ui_borg_language_menu) + add_screen_object(/atom/movable/screen/navigate, HUD_MOB_NAVIGATE_MENU, HUD_GROUP_STATIC, ui_style, ui_borg_navigate_menu) + add_screen_object(/atom/movable/screen/memories, HUD_MOB_MEMORIES, HUD_GROUP_STATIC, ui_style, ui_borg_memories_menu) + add_screen_object(/atom/movable/screen/robot/radio, HUD_CYBORG_RADIO) -// Language - using = new/atom/movable/screen/language_menu(null, src) - using.icon = ui_style - using.screen_loc = ui_borg_language_menu - static_inventory += using + for (var/i in BORG_CHOOSE_MODULE_ONE to BORG_CHOOSE_MODULE_THREE) + var/atom/movable/screen/robot/module_slot/module = add_screen_object(/atom/movable/screen/robot/module_slot, HUD_KEY_CYBORG_MODULE(i)) + module.set_slot(i) -// Navigation - using = new /atom/movable/screen/navigate(null, src) - using.icon = ui_style - using.screen_loc = ui_borg_navigate_menu - static_inventory += using + add_screen_object(/atom/movable/screen/robot/lamp, HUD_CYBORG_LAMP) + add_screen_object(/atom/movable/screen/ai/image_take, HUD_SILICON_TAKE_IMAGE, ui_loc = ui_borg_camera) -// Memories - using = new /atom/movable/screen/memories(null, src) - using.icon = ui_style - using.screen_loc = ui_borg_memories_menu - static_inventory += using - -//Radio - using = new /atom/movable/screen/robot/radio(null, src) - using.screen_loc = ui_borg_radio - static_inventory += using - -//Module select - if(!robit.inv1) - robit.inv1 = new /atom/movable/screen/robot/module1(null, src) - robit.inv1.screen_loc = ui_inv1 - static_inventory += robit.inv1 - - if(!robit.inv2) - robit.inv2 = new /atom/movable/screen/robot/module2(null, src) - robit.inv2.screen_loc = ui_inv2 - static_inventory += robit.inv2 - - if(!robit.inv3) - robit.inv3 = new /atom/movable/screen/robot/module3(null, src) - robit.inv3.screen_loc = ui_inv3 - static_inventory += robit.inv3 - -//End of module select - using = new /atom/movable/screen/robot/lamp(null, src) - using.screen_loc = ui_borg_lamp - static_inventory += using - robit.lampButton = using - var/atom/movable/screen/robot/lamp/lampscreen = using - lampscreen.robot = robit - -//Photography stuff - using = new /atom/movable/screen/ai/image_take(null, src) - using.screen_loc = ui_borg_camera - static_inventory += using - -//Borg Integrated Tablet - using = new /atom/movable/screen/robot/modpc(null, src) - using.screen_loc = ui_borg_tablet - static_inventory += using - robit.interfaceButton = using + var/atom/movable/screen/robot/modpc/tablet = add_screen_object(/atom/movable/screen/robot/modpc, HUD_SILICON_TABLET, HUD_GROUP_STATIC) if(robit.modularInterface) // Just trust me robit.modularInterface.vis_flags |= VIS_INHERIT_PLANE - using.vis_contents += robit.modularInterface - var/atom/movable/screen/robot/modpc/tabletbutton = using - tabletbutton.robot = robit + tablet.vis_contents += robit.modularInterface -//Alerts - using = new /atom/movable/screen/robot/alerts(null, src) - using.screen_loc = ui_borg_alerts - static_inventory += using + add_screen_object(/atom/movable/screen/robot/alerts, HUD_SILICON_ALERTS) + add_screen_object(/atom/movable/screen/combattoggle/robot, HUD_MOB_INTENTS) + add_screen_object(/atom/movable/screen/floor_changer, HUD_MOB_FLOOR_CHANGER, HUD_GROUP_STATIC, ui_style, ui_borg_floor_changer) + add_screen_object(/atom/movable/screen/zone_sel/robot, HUD_MOB_ZONE_SELECTOR) + var/atom/movable/screen/robot/module/module = add_screen_object(/atom/movable/screen/robot/module, HUD_CYBORG_HANDS, ui_loc = ui_borg_module) + module.icon_state = robit.model ? robit.model.model_select_icon : "nomod" - //Combat Mode - action_intent = new /atom/movable/screen/combattoggle/robot(null, src) - action_intent.icon = ui_style - action_intent.screen_loc = ui_borg_intents - static_inventory += action_intent + add_screen_object(/atom/movable/screen/healths/robot, HUD_MOB_HEALTH, HUD_GROUP_INFO) - floor_change = new /atom/movable/screen/floor_changer(null, src) - floor_change.icon = ui_style - floor_change.screen_loc = ui_borg_floor_changer - static_inventory += floor_change - -//Health - healths = new /atom/movable/screen/healths/robot(null, src) - infodisplay += healths - -//Installed Module - robit.hands = new /atom/movable/screen/robot/module(null, src) - robit.hands.icon_state = robit.model ? robit.model.model_select_icon : "nomod" - robit.hands.screen_loc = ui_borg_module - static_inventory += robit.hands - - pull_icon = new /atom/movable/screen/pull(null, src) - pull_icon.icon = 'icons/hud/screen_cyborg.dmi' - pull_icon.screen_loc = ui_borg_pull - pull_icon.update_appearance() - hotkeybuttons += pull_icon - - - zone_select = new /atom/movable/screen/zone_sel/robot(null, src) - zone_select.update_appearance() - static_inventory += zone_select + add_screen_object(/atom/movable/screen/pull, HUD_MOB_PULL, HUD_GROUP_HOTKEYS, ui_style, ui_borg_pull) /datum/hud/robot/persistent_inventory_update(mob/viewer) if(!mymob) @@ -186,74 +40,18 @@ var/mob/living/silicon/robot/R = mymob var/mob/screenmob = viewer || R - - if(screenmob.hud_used) - if(screenmob.hud_used.hud_shown) - for(var/i in 1 to R.held_items.len) - var/obj/item/I = R.held_items[i] - if(I) - switch(i) - if(BORG_CHOOSE_MODULE_ONE) - I.screen_loc = ui_inv1 - if(BORG_CHOOSE_MODULE_TWO) - I.screen_loc = ui_inv2 - if(BORG_CHOOSE_MODULE_THREE) - I.screen_loc = ui_inv3 - else - return - screenmob.client.screen += I - else - for(var/obj/item/I in R.held_items) - screenmob.client.screen -= I - -/atom/movable/screen/robot/lamp - name = "headlamp" - icon_state = "lamp_off" - base_icon_state = "lamp" - var/mob/living/silicon/robot/robot - -/atom/movable/screen/robot/lamp/Click() - . = ..() - if(.) + if(!screenmob.hud_used) return - robot?.toggle_headlamp() - update_appearance() -/atom/movable/screen/robot/lamp/update_icon_state() - icon_state = "[base_icon_state]_[robot?.lamp_enabled ? "on" : "off"]" - return ..() - -/atom/movable/screen/robot/lamp/Destroy() - if(robot) - robot.lampButton = null - robot = null - return ..() - -/atom/movable/screen/robot/modpc - name = "Modular Interface" - icon_state = "template" - var/mob/living/silicon/robot/robot - -/atom/movable/screen/robot/modpc/Click() - . = ..() - if(.) + if(!screenmob.hud_used.hud_shown) + for(var/obj/item/I in R.held_items) + screenmob.client.screen -= I return - robot.modularInterface?.interact(robot) -/atom/movable/screen/robot/modpc/Destroy() - if(robot) - robot.interfaceButton = null - robot = null - return ..() - -/atom/movable/screen/robot/alerts - name = "Alert Panel" - icon = 'icons/hud/screen_ai.dmi' - icon_state = "alerts" - -/atom/movable/screen/robot/alerts/Click() - . = ..() - if(.) - return - var/mob/living/silicon/robot/borgo = usr - borgo.alert_control.ui_interact(borgo) + for(var/i in 1 to length(R.held_items)) + var/obj/item/I = R.held_items[i] + if(!I) + continue + var/atom/movable/screen/robot/module_slot/slot = screen_objects[HUD_KEY_CYBORG_MODULE(i)] + I.screen_loc = slot.screen_loc + screenmob.client.screen += I diff --git a/code/_onclick/hud/action_button.dm b/code/_onclick/hud/screen_objects/action_button.dm similarity index 97% rename from code/_onclick/hud/action_button.dm rename to code/_onclick/hud/screen_objects/action_button.dm index 88508c11e47..0782aabd5c0 100644 --- a/code/_onclick/hud/action_button.dm +++ b/code/_onclick/hud/screen_objects/action_button.dm @@ -31,10 +31,13 @@ viewer?.client?.screen -= src linked_action.viewers -= our_hud viewer.update_action_buttons() + our_hud.screen_objects -= hud_key + our_hud.screen_groups?[hud_group_key] -= src our_hud = null linked_action = null return ..() + /atom/movable/screen/movable/action_button/proc/can_use(mob/user) if(isobserver(user)) var/mob/dead/observer/dead_mob = user @@ -278,15 +281,17 @@ var/color_timer_id /atom/movable/screen/button_palette/Destroy() - if(our_hud) + if (our_hud) our_hud.mymob?.canon_client?.screen -= src - our_hud.toggle_palette = null + our_hud.screen_objects -= hud_key + our_hud.screen_groups?[hud_group_key] -= src our_hud = null return ..() /atom/movable/screen/button_palette/Initialize(mapload, datum/hud/hud_owner) . = ..() update_appearance() + set_hud(hud_owner) /atom/movable/screen/button_palette/proc/set_hud(datum/hud/our_hud) src.our_hud = our_hud @@ -419,6 +424,18 @@ GLOBAL_LIST_INIT(palette_removed_matrix, list(1.4,0,0,0, 0.7,0.4,0,0, 0.4,0,0.6, var/scroll_direction = 0 var/datum/hud/our_hud +/atom/movable/screen/palette_scroll/Initialize(mapload, datum/hud/hud_owner) + . = ..() + set_hud(hud_owner) + +/atom/movable/screen/palette_scroll/Destroy() + if (our_hud) + our_hud.mymob?.canon_client?.screen -= src + our_hud.screen_objects -= hud_key + our_hud.screen_groups?[hud_group_key] -= src + our_hud = null + return ..() + /atom/movable/screen/palette_scroll/proc/can_use(mob/user) if (isobserver(user)) var/mob/dead/observer/O = user @@ -458,26 +475,12 @@ GLOBAL_LIST_INIT(palette_removed_matrix, list(1.4,0,0,0, 0.7,0.4,0,0, 0.4,0,0.6, icon_state = "scroll_down" scroll_direction = 1 -/atom/movable/screen/palette_scroll/down/Destroy() - if(our_hud) - our_hud.mymob?.canon_client?.screen -= src - our_hud.palette_down = null - our_hud = null - return ..() - /atom/movable/screen/palette_scroll/up name = "Scroll Up" desc = "Click on this to scroll the actions above up" icon_state = "scroll_up" scroll_direction = -1 -/atom/movable/screen/palette_scroll/up/Destroy() - if(our_hud) - our_hud.mymob?.canon_client?.screen -= src - our_hud.palette_up = null - our_hud = null - return ..() - /// Exists so you have a place to put your buttons when you move them around /atom/movable/screen/action_landing name = "Button Space" diff --git a/code/_onclick/hud/screen_objects/ai.dm b/code/_onclick/hud/screen_objects/ai.dm new file mode 100644 index 00000000000..ffa18a01e68 --- /dev/null +++ b/code/_onclick/hud/screen_objects/ai.dm @@ -0,0 +1,250 @@ +/atom/movable/screen/ai + icon = 'icons/hud/screen_ai.dmi' + mouse_over_pointer = MOUSE_HAND_POINTER + +/atom/movable/screen/ai/Click() + if(isobserver(usr) || usr.incapacitated) + return TRUE + +/atom/movable/screen/ai/aicore + name = "AI core" + icon_state = "ai_core" + screen_loc = ui_ai_core + +/atom/movable/screen/ai/aicore/Click() + if(!isAI(usr)) + return + + var/mob/living/silicon/ai/AI = usr + AI.view_core() + +/atom/movable/screen/ai/camera_list + name = "Show Camera List" + icon_state = "camera" + screen_loc = ui_ai_camera_list + +/atom/movable/screen/ai/camera_list/Click() + if(..()) + return + var/mob/living/silicon/ai/AI = usr + AI.show_camera_list() + +/atom/movable/screen/ai/camera_track + name = "Track With Camera" + icon_state = "track" + screen_loc = ui_ai_track_with_camera + +/atom/movable/screen/ai/camera_track/Click() + if(..()) + return + var/mob/living/silicon/ai/AI = usr + AI.ai_camera_track() + +/atom/movable/screen/ai/camera_light + name = "Toggle Camera Light" + icon_state = "camera_light" + screen_loc = ui_ai_camera_light + +/atom/movable/screen/ai/camera_light/Click() + if(..()) + return + var/mob/living/silicon/ai/AI = usr + AI.toggle_camera_light() + +/atom/movable/screen/ai/modpc + name = "Messenger" + icon_state = "pda_send" + screen_loc = ui_ai_mod_int + +/atom/movable/screen/ai/modpc/Click() + if(..()) + return + var/mob/living/silicon/ai/AI = usr + AI.modularInterface?.interact(AI) + +/atom/movable/screen/ai/crew_monitor + name = "Crew Monitoring Console" + icon_state = "crew_monitor" + screen_loc = ui_ai_crew_monitor + +/atom/movable/screen/ai/crew_monitor/Click() + if(..()) + return + var/mob/living/silicon/ai/AI = usr + GLOB.crewmonitor.show(AI,AI) + +/atom/movable/screen/ai/crew_manifest + name = "Crew Manifest" + icon_state = "manifest" + screen_loc = ui_ai_crew_manifest + +/atom/movable/screen/ai/crew_manifest/Click() + if(..()) + return + var/mob/living/silicon/ai/AI = usr + AI.ai_roster() + +/atom/movable/screen/ai/alerts + name = "Show Alerts" + icon_state = "alerts" + screen_loc = ui_ai_alerts + +/atom/movable/screen/ai/alerts/Click() + if(..()) + return + var/mob/living/silicon/ai/AI = usr + AI.alert_control.ui_interact(AI) + +/atom/movable/screen/ai/announcement + name = "Make Vox Announcement" + icon_state = "announcement" + screen_loc = ui_ai_announcement + +/atom/movable/screen/ai/announcement/Click() + if(..()) + return + var/mob/living/silicon/ai/AI = usr + AI.announcement() + +/atom/movable/screen/ai/call_shuttle + name = "Call Emergency Shuttle" + icon_state = "call_shuttle" + screen_loc = ui_ai_shuttle + +/atom/movable/screen/ai/call_shuttle/Click() + if(..()) + return + var/mob/living/silicon/ai/AI = usr + AI.ai_call_shuttle() + +/atom/movable/screen/ai/state_laws + name = "State Laws" + icon_state = "state_laws" + screen_loc = ui_ai_state_laws + +/atom/movable/screen/ai/state_laws/Click() + if(..()) + return + var/mob/living/silicon/ai/AI = usr + AI.checklaws() + +/atom/movable/screen/ai/image_take + name = "Take Image" + icon_state = "take_picture" + screen_loc = ui_ai_take_picture + +/atom/movable/screen/ai/image_take/Click() + if(..()) + return + if(isAI(usr)) + var/mob/living/silicon/ai/AI = usr + AI.aicamera.toggle_camera_mode(usr) + else if(iscyborg(usr)) + var/mob/living/silicon/robot/R = usr + R.aicamera.toggle_camera_mode(usr) + +/atom/movable/screen/ai/image_view + name = "View Images" + icon_state = "view_images" + screen_loc = ui_ai_view_images + +/atom/movable/screen/ai/image_view/Click() + if(..()) + return + if(isAI(usr)) + var/mob/living/silicon/ai/AI = usr + AI.aicamera.viewpictures(usr) + +/atom/movable/screen/ai/sensors + name = "Sensor Augmentation" + icon_state = "ai_sensor" + screen_loc = ui_ai_sensor + +/atom/movable/screen/ai/sensors/Click() + if(..()) + return + var/mob/living/silicon/S = usr + S.toggle_sensors() + +/atom/movable/screen/ai/multicam + name = "Multicamera Mode" + icon_state = "multicam" + screen_loc = ui_ai_multicam + +/atom/movable/screen/ai/multicam/Click() + if(..()) + return + var/mob/living/silicon/ai/AI = usr + AI.toggle_multicam() + +/atom/movable/screen/ai/add_multicam + name = "New Camera" + icon_state = "new_cam" + screen_loc = ui_ai_add_multicam + +/atom/movable/screen/ai/add_multicam/Click() + if(..()) + return + var/mob/living/silicon/ai/AI = usr + AI.drop_new_multicam() + +/atom/movable/screen/ai/floor_indicator + icon_state = "zindicator" + screen_loc = ui_ai_floor_indicator + +/atom/movable/screen/ai/floor_indicator/Initialize(mapload, datum/hud/hud_owner) + . = ..() + if(istype(hud_owner)) + RegisterSignal(hud_owner, COMSIG_HUD_OFFSET_CHANGED, PROC_REF(update_z)) + update_z() + +/atom/movable/screen/ai/floor_indicator/proc/update_z(datum/hud/source) + SIGNAL_HANDLER + var/mob/living/silicon/ai/ai = get_mob() //if you use this for anyone else i will find you + if(isnull(ai)) + return + var/turf/locturf = isturf(ai.loc) ? get_turf(ai.eyeobj) : get_turf(ai) //must be a var cuz error + var/ai_z = locturf.z + var/text = "Level
[ai_z]" + if(SSmapping.level_trait(ai_z, ZTRAIT_STATION)) + text = "Floor
[ai_z - 1]" + else if (SSmapping.level_trait(ai_z, ZTRAIT_NOPHASE)) + text = "ERROR" + maptext = MAPTEXT_TINY_UNICODE("
[text]
") + +/atom/movable/screen/ai/go_up + name = "go up" + icon_state = "up" + screen_loc = ui_ai_godownup + +/atom/movable/screen/ai/go_up/Initialize(mapload) + . = ..() + register_context() + +/atom/movable/screen/ai/go_up/add_context(atom/source, list/context, obj/item/held_item, mob/user) + . = ..() + context[SCREENTIP_CONTEXT_LMB] = "Go up a floor" + return CONTEXTUAL_SCREENTIP_SET + +/atom/movable/screen/ai/go_up/Click(location,control,params) + var/mob/ai = get_mob() //the core + flick("uppressed",src) + if(!isturf(ai.loc) || usr != ai) //aicard and stuff + return + ai.up() + +/atom/movable/screen/ai/go_up/down + name = "go down" + icon_state = "down" + +/atom/movable/screen/ai/go_up/down/add_context(atom/source, list/context, obj/item/held_item, mob/user) + . = ..() + context[SCREENTIP_CONTEXT_LMB] = "Go down a floor" + return CONTEXTUAL_SCREENTIP_SET + +/atom/movable/screen/ai/go_up/down/Click(location,control,params) + var/mob/ai = get_mob() //the core + flick("downpressed",src) + if(!isturf(ai.loc) || usr != ai) //aicard and stuff + return + ai.down() diff --git a/code/_onclick/hud/alert.dm b/code/_onclick/hud/screen_objects/alert.dm similarity index 100% rename from code/_onclick/hud/alert.dm rename to code/_onclick/hud/screen_objects/alert.dm diff --git a/code/_onclick/hud/screen_objects/alien.dm b/code/_onclick/hud/screen_objects/alien.dm new file mode 100644 index 00000000000..d99cdc55b35 --- /dev/null +++ b/code/_onclick/hud/screen_objects/alien.dm @@ -0,0 +1,24 @@ +/atom/movable/screen/alien + icon = 'icons/hud/screen_alien.dmi' + +/atom/movable/screen/alien/leap + name = "toggle leap" + icon_state = "leap_off" + screen_loc = ui_alien_storage_r + +/atom/movable/screen/alien/leap/Click() + if(!isalienhunter(usr)) + return + var/mob/living/carbon/alien/adult/hunter/AH = usr + AH.toggle_leap() + +/atom/movable/screen/alien/plasma_display + name = "plasma stored" + icon_state = "power_display" + screen_loc = ui_alienplasmadisplay + +/atom/movable/screen/alien/alien_queen_finder + name = "queen sense" + desc = "Allows you to sense the general direction of your Queen." + icon_state = "queen_finder" + screen_loc = ui_alien_queen_finder diff --git a/code/_onclick/hud/screen_objects/blob.dm b/code/_onclick/hud/screen_objects/blob.dm new file mode 100644 index 00000000000..3f78d94854f --- /dev/null +++ b/code/_onclick/hud/screen_objects/blob.dm @@ -0,0 +1,164 @@ +/atom/movable/screen/blob + icon = 'icons/hud/blob.dmi' + mouse_over_pointer = MOUSE_HAND_POINTER + +/atom/movable/screen/blob/MouseEntered(location,control,params) + . = ..() + openToolTip(usr,src,params,title = name,content = desc, theme = "blob") + +/atom/movable/screen/blob/MouseExited() + closeToolTip(usr) + +/atom/movable/screen/blob/jump_to_node + name = "Jump to Node" + desc = "Moves your camera to a selected blob node." + icon_state = "ui_tonode" + screen_loc = ui_inventory + +/atom/movable/screen/blob/jump_to_node/Click() + if(!isovermind(usr)) + return FALSE + var/mob/eye/blob/blob = usr + blob.jump_to_node() + +/atom/movable/screen/blob/jump_to_core + name = "Jump to Core" + desc = "Moves your camera to your blob core." + icon_state = "ui_tocore" + screen_loc = ui_zonesel + +/atom/movable/screen/blob/jump_to_core/MouseEntered(location,control,params) + if(hud?.mymob && isovermind(hud.mymob)) + var/mob/eye/blob/B = hud.mymob + if(!B.placed) + name = "Place Blob Core" + desc = "Attempt to place your blob core at this location." + else + name = initial(name) + desc = initial(desc) + return ..() + +/atom/movable/screen/blob/jump_to_core/Click() + if(!isovermind(usr)) + return FALSE + var/mob/eye/blob/blob = usr + if(!blob.placed) + blob.place_blob_core(BLOB_NORMAL_PLACEMENT) + blob.transport_core() + +/atom/movable/screen/blob/blobbernaut + // Name and description get given their proper values on Initialize() + name = "Produce Blobbernaut (ERROR)" + desc = "Produces a strong, smart blobbernaut from a factory blob for (ERROR) resources.
The factory blob used will become fragile and unable to produce spores." + icon_state = "ui_blobbernaut" + screen_loc = ui_belt + +/atom/movable/screen/blob/blobbernaut/Initialize(mapload, datum/hud/hud_owner) + . = ..() + name = "Produce Blobbernaut ([BLOBMOB_BLOBBERNAUT_RESOURCE_COST])" + desc = "Produces a strong, smart blobbernaut from a factory blob for [BLOBMOB_BLOBBERNAUT_RESOURCE_COST] resources.
The factory blob used will become fragile and unable to produce spores." + +/atom/movable/screen/blob/blobbernaut/Click() + if(!isovermind(usr)) + return FALSE + var/mob/eye/blob/blob = usr + blob.create_blobbernaut() + +/atom/movable/screen/blob/resource_blob + // Name and description get given their proper values on Initialize() + name = "Produce Resource Blob (ERROR)" + desc = "Produces a resource blob for ERROR resources.
Resource blobs will give you resources every few seconds." + icon_state = "ui_resource" + screen_loc = ui_back + +/atom/movable/screen/blob/resource_blob/Initialize(mapload, datum/hud/hud_owner) + . = ..() + name = "Produce Resource Blob ([BLOB_STRUCTURE_RESOURCE_COST])" + desc = "Produces a resource blob for [BLOB_STRUCTURE_RESOURCE_COST] resources.
Resource blobs will give you resources every few seconds." + +/atom/movable/screen/blob/resource_blob/Click() + if(!isovermind(usr)) + return FALSE + var/mob/eye/blob/blob = usr + blob.create_special(BLOB_STRUCTURE_RESOURCE_COST, /obj/structure/blob/special/resource, BLOB_RESOURCE_MIN_DISTANCE, TRUE) + +/atom/movable/screen/blob/node_blob + // Name and description get given their proper values on Initialize() + name = "Produce Node Blob (ERROR)" + desc = "Produces a node blob for ERROR resources.
Node blobs will expand and activate nearby resource and factory blobs." + icon_state = "ui_node" + +/atom/movable/screen/blob/node_blob/Initialize(mapload, datum/hud/hud_owner) + . = ..() + name = "Produce Node Blob ([BLOB_STRUCTURE_NODE_COST])" + desc = "Produces a node blob for [BLOB_STRUCTURE_NODE_COST] resources.
Node blobs will expand and activate nearby resource and factory blobs." + +/atom/movable/screen/blob/node_blob/Click() + if(!isovermind(usr)) + return FALSE + var/mob/eye/blob/blob = usr + blob.create_special(BLOB_STRUCTURE_NODE_COST, /obj/structure/blob/special/node, BLOB_NODE_MIN_DISTANCE, FALSE) + +/atom/movable/screen/blob/factory_blob + // Name and description get given their proper values on Initialize() + name = "Produce Factory Blob (ERROR)" + desc = "Produces a factory blob for ERROR resources.
Factory blobs will produce spores every few seconds." + icon_state = "ui_factory" + +/atom/movable/screen/blob/factory_blob/Initialize(mapload, datum/hud/hud_owner) + . = ..() + name = "Produce Factory Blob ([BLOB_STRUCTURE_FACTORY_COST])" + desc = "Produces a factory blob for [BLOB_STRUCTURE_FACTORY_COST] resources.
Factory blobs will produce spores every few seconds." + +/atom/movable/screen/blob/factory_blob/Click() + if(!isovermind(usr)) + return FALSE + var/mob/eye/blob/blob = usr + blob.create_special(BLOB_STRUCTURE_FACTORY_COST, /obj/structure/blob/special/factory, BLOB_FACTORY_MIN_DISTANCE, TRUE) + +/atom/movable/screen/blob/readapt_strain + // Description gets given its proper values on Initialize() + name = "Readapt Strain" + desc = "Allows you to choose a new strain from ERROR random choices for ERROR resources." + icon_state = "ui_chemswap" + screen_loc = ui_storage1 + +/atom/movable/screen/blob/readapt_strain/MouseEntered(location,control,params) + if(hud?.mymob && isovermind(hud.mymob)) + var/mob/eye/blob/B = hud.mymob + if(B.free_strain_rerolls) + name = "[initial(name)] (FREE)" + desc = "Randomly rerolls your strain for free." + else + name = "[initial(name)] ([BLOB_POWER_REROLL_COST])" + desc = "Allows you to choose a new strain from [BLOB_POWER_REROLL_CHOICES] random choices for [BLOB_POWER_REROLL_COST] resources." + return ..() + +/atom/movable/screen/blob/readapt_strain/Click() + if(isovermind(usr)) + var/mob/eye/blob/B = usr + B.strain_reroll() + +/atom/movable/screen/blob/relocate_core + // Name and description get given their proper values on Initialize() + name = "Relocate Core (ERROR)" + desc = "Swaps a node and your core for ERROR resources." + icon_state = "ui_swap" + screen_loc = ui_storage2 + +/atom/movable/screen/blob/relocate_core/Initialize(mapload, datum/hud/hud_owner) + . = ..() + name = "Relocate Core ([BLOB_POWER_RELOCATE_COST])" + desc = "Swaps a node and your core for [BLOB_POWER_RELOCATE_COST] resources." + +/atom/movable/screen/blob/relocate_core/Click() + if(isovermind(usr)) + var/mob/eye/blob/B = usr + B.relocate_core() + +/atom/movable/screen/blob/blob_power + name = "blob power" + icon_state = "block" + screen_loc = ui_health + mouse_opacity = MOUSE_OPACITY_TRANSPARENT + plane = ABOVE_HUD_PLANE diff --git a/code/_onclick/hud/credits.dm b/code/_onclick/hud/screen_objects/credits.dm similarity index 100% rename from code/_onclick/hud/credits.dm rename to code/_onclick/hud/screen_objects/credits.dm diff --git a/code/_onclick/hud/fullscreen.dm b/code/_onclick/hud/screen_objects/fullscreen.dm similarity index 100% rename from code/_onclick/hud/fullscreen.dm rename to code/_onclick/hud/screen_objects/fullscreen.dm diff --git a/code/_onclick/hud/screen_objects/ghost.dm b/code/_onclick/hud/screen_objects/ghost.dm new file mode 100644 index 00000000000..532817e558a --- /dev/null +++ b/code/_onclick/hud/screen_objects/ghost.dm @@ -0,0 +1,149 @@ +/atom/movable/screen/ghost + icon = 'icons/hud/screen_ghost.dmi' + mouse_over_pointer = MOUSE_HAND_POINTER + +/atom/movable/screen/ghost/MouseEntered(location, control, params) + . = ..() + flick(icon_state + "_anim", src) + +/atom/movable/screen/ghost/spawners_menu + name = "Spawners menu" + icon_state = "spawners" + screen_loc = ui_ghost_spawners_menu + +/atom/movable/screen/ghost/spawners_menu/Click() + var/mob/dead/observer/observer = usr + observer.open_spawners_menu() + +/atom/movable/screen/ghost/orbit + name = "Orbit" + icon_state = "orbit" + screen_loc = ui_ghost_orbit + +/atom/movable/screen/ghost/orbit/Click() + GLOB.orbit_menu.show(usr) + +/atom/movable/screen/ghost/reenter_corpse + name = "Reenter corpse" + icon_state = "reenter_corpse" + screen_loc = ui_ghost_reenter_corpse + +/atom/movable/screen/ghost/reenter_corpse/Click() + var/mob/dead/observer/G = usr + G.reenter_corpse() + +/atom/movable/screen/ghost/dnr + name = "Do Not Resuscitate" + icon_state = "dnr" + screen_loc = ui_ghost_dnr + +/atom/movable/screen/ghost/dnr/Click() + var/mob/dead/observer/dnring = usr + dnring.do_not_resuscitate() + +/atom/movable/screen/ghost/teleport + name = "Teleport" + icon_state = "teleport" + screen_loc = ui_ghost_teleport + +/atom/movable/screen/ghost/teleport/Click() + var/mob/dead/observer/G = usr + G.dead_tele() + +/atom/movable/screen/ghost/settings + name = "Ghost Settings" + icon_state = "settings" + screen_loc = ui_ghost_settings + +/atom/movable/screen/ghost/settings/MouseEntered(location, control, params) + . = ..() + flick(icon_state + "_anim", src) + +/atom/movable/screen/ghost/settings/Click() + GLOB.ghost_menu.ui_interact(usr) + +/atom/movable/screen/ghost/minigames_menu + name ="Minigames" + icon_state = "minigames" + screen_loc = ui_ghost_minigames + +/atom/movable/screen/ghost/minigames_menu/Click() + var/mob/dead/observer/observer = usr + observer.open_minigames_menu() + +/atom/movable/screen/ghost/hudbox + icon_state = "smallbox" + abstract_type = /atom/movable/screen/ghost/hudbox + /// Icon state used for the overlay representing this hudbox + var/hud_icon_state + /// The flag this hudbox toggles + var/relevant_flag + +/atom/movable/screen/ghost/hudbox/update_overlays() + . = ..() + . += hud_icon_state + +/atom/movable/screen/ghost/hudbox/update_icon_state() + . = ..() + var/mob/dead/observer/observer = hud?.mymob + if(!istype(observer)) + return + + icon_state = "smallbox[is_active(observer) ? "_active" : ""]" + +/atom/movable/screen/ghost/hudbox/proc/is_active(mob/dead/observer/observer) + return (observer.ghost_hud_flags & relevant_flag) + +/atom/movable/screen/ghost/hudbox/Click(location, control, params) + var/mob/dead/observer/observer = usr + switch(relevant_flag) + if(GHOST_DARKNESS_LEVEL) + observer.toggle_darkness() + if(GHOST_TRAY) + observer.tray_view() + else + observer.toggle_ghost_hud_flag(relevant_flag) + + update_appearance(UPDATE_ICON) + +/atom/movable/screen/ghost/hudbox/health_scanner + name = "Health Scanner" + desc = "Toggles your ability to health scan mobs on click." + hud_icon_state = "health_vision" + relevant_flag = GHOST_HEALTH + +/atom/movable/screen/ghost/hudbox/chem_scanner + name = "Chem Scanner" + desc = "Toggles your ability to chemical scan mobs on click." + hud_icon_state = "chem_vision" + relevant_flag = GHOST_CHEM + +/atom/movable/screen/ghost/hudbox/gas_scanner + name = "Gas Scanner" + desc = "Toggles your ability to gas scan objects on click." + hud_icon_state = "atmos_vision" + relevant_flag = GHOST_GAS + +/atom/movable/screen/ghost/hudbox/ghost + name = "Ghost Vision" + desc = "Toggles whether you can see other ghosts." + hud_icon_state = "ghost_vision" + relevant_flag = GHOST_VISION + +/atom/movable/screen/ghost/hudbox/data_huds + name = "Data HUDs" + desc = "Toggles the display of data HUDs (health, security, diagnostics, etc)." + hud_icon_state = "data_vision" + relevant_flag = GHOST_DATA_HUDS + +/atom/movable/screen/ghost/hudbox/tray_icon + name = "Tray View" + desc = "Shows the t-ray view of the area around your ghost." + hud_icon_state = "tray_vision" + relevant_flag = GHOST_TRAY + +/atom/movable/screen/ghost/hudbox/darkness_level + name = "Darkness Level" + desc = "Cycles through different darkness levels for ghost vision." + hud_icon_state = "darkness_vision" + relevant_flag = GHOST_DARKNESS_LEVEL diff --git a/code/_onclick/hud/screen_objects/guardian.dm b/code/_onclick/hud/screen_objects/guardian.dm new file mode 100644 index 00000000000..41282bc45ed --- /dev/null +++ b/code/_onclick/hud/screen_objects/guardian.dm @@ -0,0 +1,68 @@ +/atom/movable/screen/guardian + icon = 'icons/hud/guardian.dmi' + mouse_over_pointer = MOUSE_HAND_POINTER + +/atom/movable/screen/guardian/manifest + name = "Manifest" + desc = "Spring forth into battle!" + icon_state = "manifest" + +/atom/movable/screen/guardian/manifest/Click() + if(isguardian(usr)) + var/mob/living/basic/guardian/user = usr + user.manifest() + +/atom/movable/screen/guardian/recall + name = "Recall" + desc = "Return to your user." + icon_state = "recall" + +/atom/movable/screen/guardian/recall/Click() + if(isguardian(usr)) + var/mob/living/basic/guardian/user = usr + user.recall() + +/atom/movable/screen/guardian/toggle_mode + name = "Toggle Mode" + desc = "Switch between ability modes." + icon_state = "toggle" + +/atom/movable/screen/guardian/toggle_mode/Click() + if(isguardian(usr)) + var/mob/living/basic/guardian/user = usr + user.toggle_modes() + +/atom/movable/screen/guardian/toggle_mode/inactive + icon_state = "notoggle" //greyed out so it doesn't look like it'll work + +/atom/movable/screen/guardian/toggle_mode/assassin + name = "Toggle Stealth" + desc = "Enter or exit stealth." + icon_state = "stealth" + +/atom/movable/screen/guardian/toggle_mode/gases + name = "Toggle Gas" + desc = "Switch between possible gases." + icon_state = "gases" + +/atom/movable/screen/guardian/communicate + name = "Communicate" + desc = "Communicate telepathically with your user." + icon_state = "communicate" + screen_loc = ui_back + +/atom/movable/screen/guardian/communicate/Click() + if(isguardian(usr)) + var/mob/living/basic/guardian/user = usr + user.communicate() + +/atom/movable/screen/guardian/toggle_light + name = "Toggle Light" + desc = "Glow like star dust." + icon_state = "light" + screen_loc = ui_inventory + +/atom/movable/screen/guardian/toggle_light/Click() + if(isguardian(usr)) + var/mob/living/basic/guardian/user = usr + user.toggle_light() diff --git a/code/_onclick/hud/screen_objects/human.dm b/code/_onclick/hud/screen_objects/human.dm new file mode 100644 index 00000000000..b69ceb2143e --- /dev/null +++ b/code/_onclick/hud/screen_objects/human.dm @@ -0,0 +1,77 @@ +/atom/movable/screen/human + icon = 'icons/hud/screen_midnight.dmi' + +/atom/movable/screen/human/toggle + name = "toggle" + icon_state = "toggle" + base_icon_state = "toggle" + mouse_over_pointer = MOUSE_HAND_POINTER + screen_loc = ui_inventory + +/atom/movable/screen/human/toggle/Click() + var/mob/targetmob = usr + + if(isobserver(usr)) + if(ishuman(usr.client.eye) && (usr.client.eye != usr)) + var/mob/M = usr.client.eye + targetmob = M + + if(usr.hud_used.inventory_shown && targetmob.hud_used) + usr.hud_used.inventory_shown = FALSE + usr.client.screen -= targetmob.hud_used.screen_groups[HUD_GROUP_TOGGLEABLE_INVENTORY] + else + usr.hud_used.inventory_shown = TRUE + usr.client.screen += targetmob.hud_used.screen_groups[HUD_GROUP_TOGGLEABLE_INVENTORY] + + targetmob.hud_used.hidden_inventory_update(usr) + update_appearance() + +/atom/movable/screen/human/toggle/update_icon_state() + icon_state = "[base_icon_state][hud?.inventory_shown ? "_active" : ""]" + return ..() + +/atom/movable/screen/ling + icon = 'icons/hud/screen_changeling.dmi' + +/atom/movable/screen/ling/chems + name = "chemical storage" + icon_state = "power_display" + screen_loc = ui_lingchemdisplay + ///Boolean on whether a mouse is being hovered over us right now. + var/hovering = FALSE + +/atom/movable/screen/ling/chems/Click(location, control, params) + . = ..() + to_chat(usr, span_notice("Shows you how many chemicals you have. While hovering over this, it will show the max amount of chemicals you can hold.")) + +/atom/movable/screen/ling/chems/MouseEntered(location,control,params) + if(usr != get_mob()) + return + var/datum/antagonist/changeling/antagonist_datum = IS_CHANGELING(hud.mymob) + if(!antagonist_datum) + return + . = ..() + hovering = TRUE + antagonist_datum.update_chemical_hud() + +/atom/movable/screen/ling/chems/MouseExited(location, control, params) + if(usr != get_mob()) + return + var/datum/antagonist/changeling/antagonist_datum = IS_CHANGELING(hud.mymob) + if(!antagonist_datum) + return + . = ..() + hovering = FALSE + antagonist_datum.update_chemical_hud(antagonist_datum.chem_charges) + +/atom/movable/screen/ling/sting + name = "current sting" + screen_loc = ui_lingstingdisplay + invisibility = INVISIBILITY_ABSTRACT + mouse_over_pointer = MOUSE_HAND_POINTER + +/atom/movable/screen/ling/sting/Click() + if(isobserver(usr)) + return + var/mob/living/carbon/carbon_user = usr + carbon_user.unset_sting() diff --git a/code/_onclick/hud/map_popups.dm b/code/_onclick/hud/screen_objects/map_popups.dm similarity index 100% rename from code/_onclick/hud/map_popups.dm rename to code/_onclick/hud/screen_objects/map_popups.dm diff --git a/code/_onclick/hud/map_view.dm b/code/_onclick/hud/screen_objects/map_view.dm similarity index 100% rename from code/_onclick/hud/map_view.dm rename to code/_onclick/hud/screen_objects/map_view.dm diff --git a/code/_onclick/hud/movable_screen_objects.dm b/code/_onclick/hud/screen_objects/movable_screen_objects.dm similarity index 100% rename from code/_onclick/hud/movable_screen_objects.dm rename to code/_onclick/hud/screen_objects/movable_screen_objects.dm diff --git a/code/_onclick/hud/screen_objects/new_player.dm b/code/_onclick/hud/screen_objects/new_player.dm new file mode 100644 index 00000000000..5a17abfc5d9 --- /dev/null +++ b/code/_onclick/hud/screen_objects/new_player.dm @@ -0,0 +1,724 @@ +#define SHUTTER_MOVEMENT_DURATION 0.4 SECONDS +#define SHUTTER_WAIT_DURATION 0.2 SECONDS + +/atom/movable/screen/lobby + plane = SPLASHSCREEN_PLANE + layer = LOBBY_MENU_LAYER + screen_loc = "TOP,CENTER" + /// Whether this HUD element can be hidden from the client's "screen" (moved off-screen) or not + var/always_shown = FALSE + /// If true we will create this button every time the HUD is generated + var/always_available = TRUE + +///Set the HUD in New, as lobby screens are made before Atoms are Initialized. +/atom/movable/screen/lobby/New(loc, datum/hud/our_hud, ...) + set_new_hud(our_hud) + return ..() + +///Run sleeping actions after initialize +/atom/movable/screen/lobby/proc/SlowInit() + return + +///Animates moving the button off-screen +/atom/movable/screen/lobby/proc/collapse_button() + SIGNAL_HANDLER + //wait for the shutter to come down + animate(src, transform = transform, time = SHUTTER_MOVEMENT_DURATION + SHUTTER_WAIT_DURATION) + //then pull the buttons up with the shutter + animate(transform = transform.Translate(x = 0, y = 146), time = SHUTTER_MOVEMENT_DURATION, easing = CUBIC_EASING|EASE_IN) + +///Animates moving the button back into place +/atom/movable/screen/lobby/proc/expand_button() + SIGNAL_HANDLER + //the buttons are off-screen, so we sync them up to come down with the shutter + animate(src, transform = matrix(), time = SHUTTER_MOVEMENT_DURATION, easing = CUBIC_EASING|EASE_OUT) + +/atom/movable/screen/lobby/background + icon = 'icons/hud/lobby/background.dmi' + icon_state = "background" + layer = LOBBY_BACKGROUND_LAYER + screen_loc = "TOP,CENTER:-61" + +/atom/movable/screen/lobby/button + mouse_over_pointer = MOUSE_HAND_POINTER + ///Is the button currently enabled? + VAR_PROTECTED/enabled = TRUE + ///Is the button currently being hovered over with the mouse? + var/highlighted = FALSE + ///Should this button play the select sound? + var/select_sound_play = TRUE + +/atom/movable/screen/lobby/button/Click(location, control, params) + if(usr != get_mob()) + return + + if(!usr.client || usr.client.interviewee) + return + + . = ..() + + if(!enabled) + return + flick("[base_icon_state]_pressed", src) + if(select_sound_play) + var/sound/ui_select_sound = sound('sound/misc/menu/ui_select1.ogg') + ui_select_sound.frequency = get_rand_frequency_low_range() + SEND_SOUND(hud.mymob, ui_select_sound) + update_appearance(UPDATE_ICON) + return TRUE + +/atom/movable/screen/lobby/button/MouseEntered(location,control,params) + if(usr != get_mob()) + return + + if(!usr.client || usr.client.interviewee) + return + + . = ..() + highlighted = TRUE + update_appearance(UPDATE_ICON) + +/atom/movable/screen/lobby/button/MouseExited() + if(usr != get_mob()) + return + + if(!usr.client || usr.client.interviewee) + return + + . = ..() + highlighted = FALSE + update_appearance(UPDATE_ICON) + +/atom/movable/screen/lobby/button/update_icon(updates) + . = ..() + if(!enabled) + icon_state = "[base_icon_state]_disabled" + return + if(highlighted) + icon_state = "[base_icon_state]_highlighted" + return + icon_state = base_icon_state + +///Updates the button's status: TRUE to enable interaction with the button, FALSE to disable +/atom/movable/screen/lobby/button/proc/set_button_status(status) + if(status == enabled) + return FALSE + enabled = status + update_appearance(UPDATE_ICON) + mouse_over_pointer = enabled ? MOUSE_HAND_POINTER : MOUSE_INACTIVE_POINTER + return TRUE + +///Prefs menu +/atom/movable/screen/lobby/button/character_setup + name = "View Character Setup" + screen_loc = "TOP:-70,CENTER:-54" + icon = 'icons/hud/lobby/character_setup.dmi' + icon_state = "character_setup_disabled" + base_icon_state = "character_setup" + enabled = FALSE + +/atom/movable/screen/lobby/button/character_setup/Initialize(mapload, datum/hud/hud_owner) + . = ..() + // We need IconForge and the assets to be ready before allowing the menu to open + if(SSearly_assets.initialized == INITIALIZATION_INNEW_REGULAR || SSatoms.initialized == INITIALIZATION_INNEW_REGULAR) + flick("[base_icon_state]_enabled", src) + set_button_status(TRUE) + else + set_button_status(FALSE) + RegisterSignal(SSearly_assets, COMSIG_SUBSYSTEM_POST_INITIALIZE, PROC_REF(enable_character_setup)) + RegisterSignal(SSatoms, COMSIG_SUBSYSTEM_POST_INITIALIZE, PROC_REF(enable_character_setup)) + +/atom/movable/screen/lobby/button/character_setup/Click(location, control, params) + . = ..() + if(!.) + return + + var/datum/preferences/preferences = hud.mymob.canon_client.prefs + preferences.current_window = PREFERENCE_TAB_CHARACTER_PREFERENCES + preferences.update_static_data(usr) + preferences.ui_interact(usr) + +/atom/movable/screen/lobby/button/character_setup/proc/enable_character_setup() + SIGNAL_HANDLER + flick("[base_icon_state]_enabled", src) + set_button_status(TRUE) + UnregisterSignal(SSearly_assets, COMSIG_SUBSYSTEM_POST_INITIALIZE) + UnregisterSignal(SSatoms, COMSIG_SUBSYSTEM_POST_INITIALIZE) + +///Button that appears before the game has started +/atom/movable/screen/lobby/button/ready + name = "Toggle Readiness" + screen_loc = "TOP:-8,CENTER:-65" + icon = 'icons/hud/lobby/ready.dmi' + icon_state = "not_ready" + base_icon_state = "not_ready" + +/atom/movable/screen/lobby/button/ready/Initialize(mapload, datum/hud/hud_owner) + . = ..() + switch(SSticker.current_state) + if(GAME_STATE_PREGAME, GAME_STATE_STARTUP) + RegisterSignal(SSticker, COMSIG_TICKER_ENTER_SETTING_UP, PROC_REF(hide_ready_button)) + if(GAME_STATE_SETTING_UP) + set_button_status(FALSE) + RegisterSignal(SSticker, COMSIG_TICKER_ERROR_SETTING_UP, PROC_REF(show_ready_button)) + else + set_button_status(FALSE) + +/atom/movable/screen/lobby/button/ready/proc/hide_ready_button() + SIGNAL_HANDLER + set_button_status(FALSE) + UnregisterSignal(SSticker, COMSIG_TICKER_ENTER_SETTING_UP) + RegisterSignal(SSticker, COMSIG_TICKER_ERROR_SETTING_UP, PROC_REF(show_ready_button)) + +/atom/movable/screen/lobby/button/ready/proc/show_ready_button() + SIGNAL_HANDLER + set_button_status(TRUE) + UnregisterSignal(SSticker, COMSIG_TICKER_ERROR_SETTING_UP) + RegisterSignal(SSticker, COMSIG_TICKER_ENTER_SETTING_UP, PROC_REF(hide_ready_button)) + +/atom/movable/screen/lobby/button/ready/Click(location, control, params) + . = ..() + if(!.) + return + var/mob/dead/new_player/new_player = hud.mymob + + // switch based on the user, if they aren't ready then we change them to ready, and vice versa + if(new_player.ready == PLAYER_NOT_READY) + new_player.auto_deadmin_on_ready_or_latejoin() + new_player.ready = PLAYER_READY_TO_PLAY + base_icon_state = "ready" + else + new_player.ready = PLAYER_NOT_READY + base_icon_state = "not_ready" + + update_appearance(UPDATE_ICON) + SEND_SIGNAL(hud, COMSIG_HUD_PLAYER_READY_TOGGLE) + +///Shown when the game has started +/atom/movable/screen/lobby/button/join + name = "Join Game" + screen_loc = "TOP:-13,CENTER:-58" + icon = 'icons/hud/lobby/join.dmi' + icon_state = "" //Default to not visible + base_icon_state = "join_game" + enabled = null // set in init + +/atom/movable/screen/lobby/button/join/Initialize(mapload, datum/hud/hud_owner) + . = ..() + switch(SSticker.current_state) + if(GAME_STATE_PREGAME, GAME_STATE_STARTUP) + set_button_status(FALSE) + RegisterSignal(SSticker, COMSIG_TICKER_ENTER_SETTING_UP, PROC_REF(show_join_button)) + if(GAME_STATE_SETTING_UP) + set_button_status(TRUE) + RegisterSignal(SSticker, COMSIG_TICKER_ERROR_SETTING_UP, PROC_REF(hide_join_button)) + else + set_button_status(TRUE) + +/atom/movable/screen/lobby/button/join/Click(location, control, params) + . = ..() + if(!.) + return + + if(!SSticker?.IsRoundInProgress()) + to_chat(hud.mymob, span_boldwarning("The round is either not ready, or has already finished...")) + return + + //Determines Relevent Population Cap + var/relevant_cap + var/hard_popcap = CONFIG_GET(number/hard_popcap) + var/extreme_popcap = CONFIG_GET(number/extreme_popcap) + if(hard_popcap && extreme_popcap) + relevant_cap = min(hard_popcap, extreme_popcap) + else + relevant_cap = max(hard_popcap, extreme_popcap) + + var/mob/dead/new_player/new_player = hud.mymob + + if(SSticker.queued_players.len || (relevant_cap && living_player_count() >= relevant_cap && !(ckey(new_player.key) in GLOB.admin_datums))) + to_chat(new_player, span_danger("[CONFIG_GET(string/hard_popcap_message)]")) + + var/queue_position = SSticker.queued_players.Find(new_player) + if(queue_position == 1) + to_chat(new_player, span_notice("You are next in line to join the game. You will be notified when a slot opens up.")) + else if(queue_position) + to_chat(new_player, span_notice("There are [queue_position-1] players in front of you in the queue to join the game.")) + else + SSticker.queued_players += new_player + to_chat(new_player, span_notice("You have been added to the queue to join the game. Your position in queue is [SSticker.queued_players.len].")) + return + + new_player.auto_deadmin_on_ready_or_latejoin() + + if(!LAZYACCESS(params2list(params), CTRL_CLICK)) + GLOB.latejoin_menu.ui_interact(new_player) + else + to_chat(new_player, span_warning("Opening emergency fallback late join menu! If THIS doesn't show, ahelp immediately!")) + GLOB.latejoin_menu.fallback_ui(new_player) + + +/atom/movable/screen/lobby/button/join/proc/show_join_button() + SIGNAL_HANDLER + set_button_status(TRUE) + UnregisterSignal(SSticker, COMSIG_TICKER_ENTER_SETTING_UP) + RegisterSignal(SSticker, COMSIG_TICKER_ERROR_SETTING_UP, PROC_REF(hide_join_button)) + +/atom/movable/screen/lobby/button/join/proc/hide_join_button() + SIGNAL_HANDLER + set_button_status(FALSE) + UnregisterSignal(SSticker, COMSIG_TICKER_ERROR_SETTING_UP) + RegisterSignal(SSticker, COMSIG_TICKER_ENTER_SETTING_UP, PROC_REF(show_join_button)) + +/atom/movable/screen/lobby/button/observe + name = "Observe" + screen_loc = "TOP:-40,CENTER:-54" + icon = 'icons/hud/lobby/observe.dmi' + icon_state = "observe_disabled" + base_icon_state = "observe" + enabled = null // set in init + +/atom/movable/screen/lobby/button/observe/Initialize(mapload, datum/hud/hud_owner) + . = ..() + if(SSticker.current_state > GAME_STATE_STARTUP) + set_button_status(TRUE) + else + set_button_status(FALSE) + RegisterSignal(SSticker, COMSIG_TICKER_ENTER_PREGAME, PROC_REF(enable_observing)) + +/atom/movable/screen/lobby/button/observe/Click(location, control, params) + . = ..() + if(!.) + return + var/mob/dead/new_player/new_player = hud.mymob + new_player.make_me_an_observer() + +/atom/movable/screen/lobby/button/observe/proc/enable_observing() + SIGNAL_HANDLER + flick("[base_icon_state]_enabled", src) + set_button_status(TRUE) + UnregisterSignal(SSticker, COMSIG_TICKER_ENTER_PREGAME) + +//Subtype the bottom buttons away so the collapse/expand shutter goes behind them +/atom/movable/screen/lobby/button/bottom + layer = LOBBY_BOTTOM_BUTTON_LAYER + icon = 'icons/hud/lobby/bottom_buttons.dmi' + +/atom/movable/screen/lobby/button/bottom/settings + name = "View Game Preferences" + icon_state = "settings_disabled" + base_icon_state = "settings" + screen_loc = "TOP:-122,CENTER:+29" + enabled = FALSE + +/atom/movable/screen/lobby/button/bottom/settings/Initialize(mapload, datum/hud/hud_owner) + . = ..() + // We need IconForge and the assets to be ready before allowing the menu to open + if(SSearly_assets.initialized == INITIALIZATION_INNEW_REGULAR || SSatoms.initialized == INITIALIZATION_INNEW_REGULAR) + set_button_status(TRUE) + else + set_button_status(FALSE) + RegisterSignal(SSearly_assets, COMSIG_SUBSYSTEM_POST_INITIALIZE, PROC_REF(enable_settings)) + RegisterSignal(SSatoms, COMSIG_SUBSYSTEM_POST_INITIALIZE, PROC_REF(enable_settings)) + +/atom/movable/screen/lobby/button/bottom/settings/Click(location, control, params) + . = ..() + if(!.) + return + + var/datum/preferences/preferences = hud.mymob.canon_client.prefs + preferences.current_window = PREFERENCE_TAB_GAME_PREFERENCES + preferences.update_static_data(usr) + preferences.ui_interact(usr) + +/atom/movable/screen/lobby/button/bottom/settings/proc/enable_settings() + SIGNAL_HANDLER + set_button_status(TRUE) + UnregisterSignal(SSearly_assets, COMSIG_SUBSYSTEM_POST_INITIALIZE) + UnregisterSignal(SSatoms, COMSIG_SUBSYSTEM_POST_INITIALIZE) + +/atom/movable/screen/lobby/button/bottom/changelog_button + name = "View Changelog" + icon_state = "changelog" + base_icon_state = "changelog" + screen_loc ="TOP:-122,CENTER:+57" + +/atom/movable/screen/lobby/button/bottom/changelog_button/Click(location, control, params) + . = ..() + usr.client?.changelog() + +/atom/movable/screen/lobby/button/bottom/crew_manifest + name = "View Crew Manifest" + icon_state = "crew_manifest" + base_icon_state = "crew_manifest" + screen_loc = "TOP:-122,CENTER:+2" + +/atom/movable/screen/lobby/button/bottom/crew_manifest/Click(location, control, params) + . = ..() + if(!.) + return + var/mob/dead/new_player/new_player = hud.mymob + new_player.ViewManifest() + +/atom/movable/screen/lobby/button/bottom/poll + name = "View Available Polls" + icon_state = "poll" + base_icon_state = "poll" + screen_loc = "TOP:-122,CENTER:-26" + ///Whether the button should have a New Poll notification overlay + var/new_poll = FALSE + +/atom/movable/screen/lobby/button/bottom/poll/SlowInit(mapload) + . = ..() + if(!usr) + return + var/mob/dead/new_player/new_player = usr + if(is_guest_key(new_player.key)) + set_button_status(FALSE) + return + if(!SSdbcore.Connect()) + set_button_status(FALSE) + return + var/isadmin = FALSE + if(new_player.client?.holder) + isadmin = TRUE + var/datum/db_query/query_get_new_polls = SSdbcore.NewQuery({" + SELECT id FROM [format_table_name("poll_question")] + WHERE (adminonly = 0 OR :isadmin = 1) + AND Now() BETWEEN starttime AND endtime + AND deleted = 0 + AND id NOT IN ( + SELECT pollid FROM [format_table_name("poll_vote")] + WHERE ckey = :ckey + AND deleted = 0 + ) + AND id NOT IN ( + SELECT pollid FROM [format_table_name("poll_textreply")] + WHERE ckey = :ckey + AND deleted = 0 + ) + "}, list("isadmin" = isadmin, "ckey" = new_player.ckey)) + if(!query_get_new_polls.Execute()) + qdel(query_get_new_polls) + set_button_status(FALSE) + return + if(query_get_new_polls.NextRow()) + new_poll = TRUE + else + new_poll = FALSE + update_appearance(UPDATE_OVERLAYS) + qdel(query_get_new_polls) + if(QDELETED(new_player)) + set_button_status(FALSE) + return + +/atom/movable/screen/lobby/button/bottom/poll/update_overlays() + . = ..() + if(new_poll) + . += mutable_appearance('icons/hud/lobby/poll_overlay.dmi', "new_poll") + +/atom/movable/screen/lobby/button/bottom/poll/Click(location, control, params) + . = ..() + if(!.) + return + var/mob/dead/new_player/new_player = hud.mymob + new_player.handle_player_polling() + +/// A generic "sign up" button used by station traits +/atom/movable/screen/lobby/button/sign_up + icon = 'icons/hud/lobby/signup_button.dmi' + icon_state = "signup" + base_icon_state = "signup" + always_available = FALSE + +/atom/movable/screen/lobby/button/sign_up/MouseEntered(location, control, params) + . = ..() + if(QDELETED(src) || !desc) + return + openToolTip(usr, tip_src = src, params = params, title = name, content = desc,) + +/atom/movable/screen/lobby/button/sign_up/MouseExited() + . = ..() + closeToolTip(usr) + +/atom/movable/screen/lobby/button/collapse + name = "Collapse Lobby Menu" + icon = 'icons/hud/lobby/collapse_expand.dmi' + icon_state = "collapse" + base_icon_state = "collapse" + layer = LOBBY_BELOW_MENU_LAYER + screen_loc = "TOP:-82,CENTER:-54" + always_shown = TRUE + + var/blip_enabled = TRUE + +/atom/movable/screen/lobby/button/collapse/Initialize(mapload, datum/hud/hud_owner) + . = ..() + switch(SSticker.current_state) + if(GAME_STATE_PREGAME, GAME_STATE_STARTUP) + RegisterSignal(SSticker, COMSIG_TICKER_ENTER_SETTING_UP, PROC_REF(disable_blip)) + RegisterSignal(hud, COMSIG_HUD_PLAYER_READY_TOGGLE, PROC_REF(on_player_ready_toggle)) + if(GAME_STATE_SETTING_UP) + blip_enabled = FALSE + RegisterSignal(SSticker, COMSIG_TICKER_ERROR_SETTING_UP, PROC_REF(enable_blip)) + else + blip_enabled = FALSE + + add_overlay(get_blip_overlay()) + update_icon(UPDATE_OVERLAYS) + +/atom/movable/screen/lobby/button/collapse/update_overlays() + . = ..() + . += get_blip_overlay() + +/atom/movable/screen/lobby/button/collapse/Click(location, control, params) + . = ..() + if(!.) + return + + if(!istype(hud, /datum/hud/new_player)) + return + var/datum/hud/new_player/our_hud = hud + base_icon_state = our_hud.menu_hud_status ? "expand" : "collapse" + name = "[our_hud.menu_hud_status ? "Expand" : "Collapse"] Lobby Menu" + set_button_status(FALSE) + + //get the shutter object used by our hud + var/atom/movable/screen/lobby/shutter/menu_shutter = locate(/atom/movable/screen/lobby/shutter) in hud.screen_groups[HUD_GROUP_STATIC] + + //animate the shutter + menu_shutter.setup_shutter_animation() + //animate bottom buttons' movement + if(our_hud.menu_hud_status) + collapse_menu() + else + expand_menu() + our_hud.menu_hud_status = !our_hud.menu_hud_status + + //re-enable clicking the button when the shutter animation finishes + //we use sleep here so it can work during game setup, as addtimer would not work until the game would finish setting up + sleep(2 * SHUTTER_MOVEMENT_DURATION + SHUTTER_WAIT_DURATION) + set_button_status(TRUE) + +///Proc to update the ready blip state upon new player's ready status change +/atom/movable/screen/lobby/button/collapse/proc/on_player_ready_toggle() + SIGNAL_HANDLER + update_appearance(UPDATE_ICON) + +///Returns a ready blip overlay depending on the player's ready state +/atom/movable/screen/lobby/button/collapse/proc/get_blip_overlay() + var/blip_icon_state = "ready_blip" + if(blip_enabled && hud) + var/mob/dead/new_player/new_player = hud.mymob + blip_icon_state += "_[new_player.is_ready_to_play() ? "" : "not_"]ready" + else + blip_icon_state += "_disabled" + var/mutable_appearance/ready_blip = mutable_appearance(icon, blip_icon_state) + return ready_blip + +///Disables the ready blip; makes us listen for the setup error to re-enable the blip +/atom/movable/screen/lobby/button/collapse/proc/disable_blip() + SIGNAL_HANDLER + blip_enabled = FALSE + UnregisterSignal(SSticker, COMSIG_TICKER_ENTER_SETTING_UP) + RegisterSignal(SSticker, COMSIG_TICKER_ERROR_SETTING_UP, PROC_REF(enable_blip)) + update_appearance(UPDATE_ICON) + +///Enables the ready blip; makes us listen for the setup completion and game start to disable the blip +/atom/movable/screen/lobby/button/collapse/proc/enable_blip() + SIGNAL_HANDLER + blip_enabled = TRUE + UnregisterSignal(SSticker, COMSIG_TICKER_ERROR_SETTING_UP) + RegisterSignal(SSticker, COMSIG_TICKER_ENTER_SETTING_UP, PROC_REF(disable_blip)) + update_appearance(UPDATE_ICON) + +///Moves the button to the top of the screen, leaving only the screen part in view +///Sends a signal on the hud for the menu hud elements to listen to +/atom/movable/screen/lobby/button/collapse/proc/collapse_menu() + SEND_SIGNAL(hud, COMSIG_HUD_LOBBY_COLLAPSED) + //wait for the shutter to come down + animate(src, transform = transform, time = SHUTTER_MOVEMENT_DURATION + SHUTTER_WAIT_DURATION) + //then pull the button up with the shutter and leave it on the edge of the screen + animate(transform = transform.Translate(x = 0, y = 134), time = SHUTTER_MOVEMENT_DURATION, easing = CUBIC_EASING|EASE_IN) + SEND_SOUND(hud.mymob, sound('sound/misc/menu/menu_rollup1.ogg')) + +///Extends the button back to its usual spot +///Sends a signal on the hud for the menu hud elements to listen to +/atom/movable/screen/lobby/button/collapse/proc/expand_menu() + SEND_SIGNAL(hud, COMSIG_HUD_LOBBY_EXPANDED) + animate(src, transform = matrix(), time = SHUTTER_MOVEMENT_DURATION, easing = CUBIC_EASING|EASE_OUT) + SEND_SOUND(hud.mymob, sound('sound/misc/menu/menu_rolldown1.ogg')) + +/atom/movable/screen/lobby/shutter + icon = 'icons/hud/lobby/shutter.dmi' + icon_state = "shutter" + base_icon_state = "shutter" + screen_loc = "TOP:+143,CENTER:-73" //"home" position is off-screen + layer = LOBBY_SHUTTER_LAYER + always_shown = TRUE + +///Sets up the shutter pulling down and up. It's the same animation for both collapsing and expanding the menu. +/atom/movable/screen/lobby/shutter/proc/setup_shutter_animation() + //bring down the shutter + animate(src, transform = transform.Translate(x = 0, y = -143), time = SHUTTER_MOVEMENT_DURATION, easing = CUBIC_EASING|EASE_OUT) + + //wait a little bit before bringing the shutter up + animate(transform = transform, time = SHUTTER_WAIT_DURATION) + + //pull the shutter back off-screen + animate(transform = matrix(), time = SHUTTER_MOVEMENT_DURATION, easing = CUBIC_EASING|EASE_IN) + +/// LOCALHOST ONLY - Start Now button +/atom/movable/screen/lobby/button/start_now + name = "Start Now (LOCALHOST ONLY)" + screen_loc = "TOP:-146,CENTER:-54" + icon = 'icons/hud/lobby/start_now.dmi' + icon_state = "start_now" + base_icon_state = "start_now" + always_available = FALSE + select_sound_play = FALSE + +/atom/movable/screen/lobby/button/start_now/Click(location, control, params) + . = ..() + if(!. || !usr.client.is_localhost() || !check_rights_for(usr.client, R_SERVER)) + return + SEND_SOUND(hud.mymob, sound('sound/effects/cartoon_sfx/cartoon_splat.ogg', volume = 50)) + SSticker.start_immediately = TRUE + if(SSticker.current_state == GAME_STATE_STARTUP) + to_chat(usr, span_admin("The server is still setting up, but the round will be started as soon as possible.")) + +#define OVERLAY_X_DIFF 12 +#define OVERLAY_Y_DIFF 5 + +///Lobby screen that appears before the game has started showing how many players there are and who is ready. +/atom/movable/screen/lobby/new_player_info + name = "New Player Info" + screen_loc = "EAST-3,CENTER:140" + icon = 'icons/hud/lobby/newplayer.dmi' + icon_state = null //we only show up when we get update appearance called, cause we need our overlay to not look bad. + base_icon_state = "newplayer" + maptext_height = 75 + maptext_width = 80 + maptext_x = OVERLAY_X_DIFF + maptext_y = OVERLAY_Y_DIFF + + ///Boolean on whether or not we should have our static overlay, so we 'turn' the TV off when collapsing. + var/show_static = TRUE + ///Static mutable appearance of a job icon we're displaying on the TV for overflow job. + var/static/mutable_appearance/job_overlay + +/atom/movable/screen/lobby/new_player_info/Initialize(mapload, datum/hud/hud_owner) + . = ..() + START_PROCESSING(SSnewplayer_info, src) + update_text() + + //only go if the station trait is selected, otherwise it'll show "Assistant" every round. + var/datum/station_trait/overflow_job_bureaucracy/overflow_job = locate() in SSstation.station_traits + if(overflow_job && isnull(job_overlay)) + var/icon/job_icon = get_job_hud_icon(SSjob.overflow_role) + if(isnull(job_icon)) + stack_trace("[SSjob.overflow_role::title] was selected as the Job Overflow but has no icon!") + else + job_icon.Scale(ICON_SIZE_X / 2, ICON_SIZE_X / 2) + job_overlay = mutable_appearance(job_icon, offset_spokesman = src, alpha = 120, layer = src.layer+0.02) + var/matrix/job_matrix = matrix() + job_matrix.Translate(6, 14) //this is completely arbitruary just what I thought looked good. + job_overlay.transform = job_matrix + + update_appearance(UPDATE_ICON) + +/atom/movable/screen/lobby/new_player_info/Destroy() + STOP_PROCESSING(SSnewplayer_info, src) + return ..() + +/atom/movable/screen/lobby/new_player_info/MouseEntered(location, control, params) + . = ..() + if(QDELETED(src) || isnull(job_overlay)) + return + openToolTip(usr, src, params, title = "[SSjob.overflow_role::title] overflow", content = "The overflow for the round has been set as [SSjob.overflow_role::title].") + +/atom/movable/screen/lobby/new_player_info/MouseExited() + closeToolTip(usr) + return ..() + +/atom/movable/screen/lobby/new_player_info/update_icon_state() + . = ..() + icon_state = base_icon_state + +/atom/movable/screen/lobby/new_player_info/update_overlays() + . = ..() + . += mutable_appearance(icon, "[base_icon_state]_overlay", layer = src.layer+0.01) + if(!show_static) + return . + if(job_overlay) + . += job_overlay + . += mutable_appearance(icon, "static_base", alpha = 20, layer = src.layer+0.03) + //we have this in a separate file because `generate_icon_alpha_mask` puts lighting even on non-existent pixels, + //giving the icon a weird background color. + var/mutable_appearance/scanline = mutable_appearance(generate_icon_alpha_mask('icons/hud/lobby/newplayer_scanline.dmi', "scanline"), alpha = 20, layer = src.layer+0.04) + scanline.pixel_y = OVERLAY_X_DIFF + scanline.pixel_x = OVERLAY_Y_DIFF + . += scanline + +/atom/movable/screen/lobby/new_player_info/process(seconds_per_tick) + update_text() + +/atom/movable/screen/lobby/new_player_info/collapse_button() + show_static = FALSE + update_text() + //to be in sync with parent, we'll turn the TV off in this time instead. + animate(src, appearance = update_appearance(UPDATE_ICON), time = SHUTTER_MOVEMENT_DURATION + SHUTTER_WAIT_DURATION) + //we go to the right, not up + animate(transform = transform.Translate(x = 146, y = 0), time = SHUTTER_MOVEMENT_DURATION, easing = CUBIC_EASING|EASE_IN) + +/atom/movable/screen/lobby/new_player_info/expand_button() + . = ..() + show_static = TRUE + update_appearance(UPDATE_ICON) + update_text() + +/atom/movable/screen/lobby/new_player_info/proc/update_text() + if(!hud || !show_static) + maptext = null + return + + var/round_started = SSticker.HasRoundStarted() + if(!MC_RUNNING()) + maptext = MAPTEXT("[(round_started ? null : "Starting in [time_remaining_str()]
")]Loading...
") + return + + if(SSticker.IsPostgame()) + maptext = MAPTEXT("Game ended,
\ + restart soon
") + return + + var/new_maptext + if(round_started) + new_maptext = "[SSmapping.current_map.map_name]
\ + [LAZYLEN(GLOB.clients)] player\s online
\ + [ROUND_TIME()] in
" + new_maptext += "
" + else + if(hud.mymob.client?.holder) + new_maptext = "Starting in [time_remaining_str()]
\ + [LAZYLEN(GLOB.clients)] player\s
\ + [SSticker.totalPlayersReady] players ready
\ + [SSticker.total_admins_ready] / [length(GLOB.admins)] admins ready
" + else + new_maptext = "[time_remaining_str()]
\ + [LAZYLEN(GLOB.clients)] player\s" + + maptext = MAPTEXT(new_maptext) + +/atom/movable/screen/lobby/new_player_info/proc/time_remaining_str() + var/time_remaining = SSticker.GetTimeLeft() + if(time_remaining > 0) + return "[round(time_remaining/10)]s" + if(time_remaining == -10) + return "DELAYED" + return "SOON" + +#undef OVERLAY_X_DIFF +#undef OVERLAY_Y_DIFF + +#undef SHUTTER_MOVEMENT_DURATION +#undef SHUTTER_WAIT_DURATION diff --git a/code/modules/pai/hud.dm b/code/_onclick/hud/screen_objects/pai.dm similarity index 57% rename from code/modules/pai/hud.dm rename to code/_onclick/hud/screen_objects/pai.dm index fb1fd483116..0965787ef42 100644 --- a/code/modules/pai/hud.dm +++ b/code/_onclick/hud/screen_objects/pai.dm @@ -17,6 +17,7 @@ /atom/movable/screen/pai/software name = "Software Interface" icon_state = "pai" + screen_loc = ui_pai_software /atom/movable/screen/pai/software/Click() if(!..()) @@ -27,6 +28,7 @@ /atom/movable/screen/pai/shell name = "Toggle Holoform" icon_state = "pai_holoform" + screen_loc = ui_pai_shell /atom/movable/screen/pai/shell/Click() if(!..()) @@ -40,6 +42,7 @@ /atom/movable/screen/pai/chassis name = "Holochassis Appearance Composite" icon_state = "pai_chassis" + screen_loc = ui_pai_chassis /atom/movable/screen/pai/chassis/Click() if(!..()) @@ -50,6 +53,7 @@ /atom/movable/screen/pai/rest name = "Rest" icon_state = "pai_rest" + screen_loc = ui_pai_rest /atom/movable/screen/pai/rest/Click() if(!..()) @@ -60,6 +64,7 @@ /atom/movable/screen/pai/light name = "Toggle Integrated Lights" icon_state = "light" + screen_loc = ui_pai_light /atom/movable/screen/pai/light/Click() if(!..()) @@ -70,6 +75,7 @@ /atom/movable/screen/pai/newscaster name = "pAI Newscaster" icon_state = "newscaster" + screen_loc = ui_pai_newscaster required_software = "Newscaster" /atom/movable/screen/pai/newscaster/Click() @@ -81,6 +87,7 @@ /atom/movable/screen/pai/host_monitor name = "Host Health Scan" icon_state = "host_monitor" + screen_loc = ui_pai_host_monitor required_software = "Host Scan" /atom/movable/screen/pai/host_monitor/Click(location, control, params) @@ -99,6 +106,7 @@ /atom/movable/screen/pai/crew_manifest name = "Crew Manifest" icon_state = "manifest" + screen_loc = ui_pai_crew_manifest required_software = "Crew Manifest" /atom/movable/screen/pai/crew_manifest/Click() @@ -110,6 +118,7 @@ /atom/movable/screen/pai/state_laws name = "State Laws" icon_state = "state_laws" + screen_loc = ui_pai_state_laws /atom/movable/screen/pai/state_laws/Click() if(!..()) @@ -120,18 +129,21 @@ /atom/movable/screen/pai/modpc name = "Messenger" icon_state = "pda_send" + screen_loc = ui_pai_mod_int required_software = "Digital Messenger" - var/mob/living/silicon/pai/pAI /atom/movable/screen/pai/modpc/Click() . = ..() if(!.) // this works for some reason. return - pAI.modularInterface?.interact(pAI) + var/mob/living/silicon/pai/pAI = usr + if (istype(pAI)) + pAI.modularInterface?.interact(pAI) /atom/movable/screen/pai/internal_gps name = "Internal GPS" icon_state = "internal_gps" + screen_loc = ui_pai_internal_gps required_software = "Internal GPS" /atom/movable/screen/pai/internal_gps/Click() @@ -146,6 +158,7 @@ /atom/movable/screen/pai/image_take name = "Take Image" icon_state = "take_picture" + screen_loc = ui_pai_take_picture required_software = "Photography Module" /atom/movable/screen/pai/image_take/Click() @@ -158,6 +171,7 @@ /atom/movable/screen/pai/image_view name = "View Images" icon_state = "view_images" + screen_loc = ui_pai_view_images required_software = "Photography Module" /atom/movable/screen/pai/image_view/Click() @@ -170,6 +184,7 @@ name = "radio" icon = 'icons/hud/screen_cyborg.dmi' icon_state = "radio" + screen_loc = ui_pai_radio /atom/movable/screen/pai/radio/Click() if(!..()) @@ -177,109 +192,4 @@ var/mob/living/silicon/pai/pAI = usr pAI.radio.interact(usr) -/datum/hud/pai - ui_style = 'icons/hud/screen_pai.dmi' - -/datum/hud/pai/New(mob/living/silicon/pai/owner) - ..() - var/atom/movable/screen/using - -// Software menu - using = new /atom/movable/screen/pai/software(null, src) - using.screen_loc = ui_pai_software - static_inventory += using - -// Holoform - using = new /atom/movable/screen/pai/shell(null, src) - using.screen_loc = ui_pai_shell - static_inventory += using - -// Chassis Select Menu - using = new /atom/movable/screen/pai/chassis(null, src) - using.screen_loc = ui_pai_chassis - static_inventory += using - -// Rest - using = new /atom/movable/screen/pai/rest(null, src) - using.screen_loc = ui_pai_rest - static_inventory += using - -// Integrated Light - using = new /atom/movable/screen/pai/light(null, src) - using.screen_loc = ui_pai_light - static_inventory += using - -// Newscaster - using = new /atom/movable/screen/pai/newscaster(null, src) - using.screen_loc = ui_pai_newscaster - static_inventory += using - -// Language menu - using = new /atom/movable/screen/language_menu(null, src) - using.icon = ui_style - using.screen_loc = ui_pai_language_menu - static_inventory += using - -// Memories - using = new /atom/movable/screen/memories(null, src) - using.icon = ui_style - using.screen_loc = ui_pai_memories_menu - static_inventory += using - -// Navigation - using = new /atom/movable/screen/navigate(null, src) - using.icon = ui_style - using.screen_loc = ui_pai_navigate_menu - static_inventory += using - -// Host Monitor - using = new /atom/movable/screen/pai/host_monitor(null, src) - using.screen_loc = ui_pai_host_monitor - static_inventory += using - -// Crew Manifest - using = new /atom/movable/screen/pai/crew_manifest(null, src) - using.screen_loc = ui_pai_crew_manifest - static_inventory += using - -// Laws - using = new /atom/movable/screen/pai/state_laws(null, src) - using.screen_loc = ui_pai_state_laws - static_inventory += using - -// Modular Interface - using = new /atom/movable/screen/pai/modpc(null, src) - using.screen_loc = ui_pai_mod_int - static_inventory += using - var/atom/movable/screen/pai/modpc/tablet_button = using - tablet_button.pAI = mymob - -// Internal GPS - using = new /atom/movable/screen/pai/internal_gps(null, src) - using.screen_loc = ui_pai_internal_gps - static_inventory += using - -// Take image - using = new /atom/movable/screen/pai/image_take(null, src) - using.screen_loc = ui_pai_take_picture - static_inventory += using - -// View images - using = new /atom/movable/screen/pai/image_view(null, src) - using.screen_loc = ui_pai_view_images - static_inventory += using - -// Radio - using = new /atom/movable/screen/pai/radio(null, src) - using.screen_loc = ui_pai_radio - static_inventory += using - - update_software_buttons() - -/datum/hud/pai/proc/update_software_buttons() - var/mob/living/silicon/pai/owner = mymob - for(var/atom/movable/screen/pai/button in static_inventory) - if(button.required_software) - button.color = owner.installed_software.Find(button.required_software) ? null : COLOR_GRAY - #undef PAI_MISSING_SOFTWARE_MESSAGE diff --git a/code/_onclick/hud/screen_objects/perks.dm b/code/_onclick/hud/screen_objects/perks.dm new file mode 100644 index 00000000000..5d6be963b02 --- /dev/null +++ b/code/_onclick/hud/screen_objects/perks.dm @@ -0,0 +1,29 @@ +/atom/movable/screen/perk + icon = 'icons/hud/perks.dmi' + name = "blank" + icon_state = "blank" + +/atom/movable/screen/perk/more + name = "more" + icon_state = "more" + // When compact we don't show our perk huds in ui. + var/compact = FALSE + +/atom/movable/screen/perk/more/Click(location, control, params) + . = ..() + if(!isliving(usr)) + return + var/mob/living/usr_is_living = usr + var/datum/antagonist/wizard/wizard_datum = usr_is_living.mind.has_antag_datum(/datum/antagonist/wizard) + if(!wizard_datum) + return + compact = !compact + var/datum/hud/user_hud = usr_is_living.hud_used + for (var/perk_id in 1 to length(wizard_datum.perks)) + var/atom/movable/screen/perk/perk = user_hud.screen_objects[HUD_WIZARD_PERK(perk_id)] + if (!perk) // ?? + continue + if (compact) + perk.SetInvisibility(INVISIBILITY_ABSTRACT, type) + else + perk.RemoveInvisibility(type) diff --git a/code/_onclick/hud/picture_in_picture.dm b/code/_onclick/hud/screen_objects/picture_in_picture.dm similarity index 100% rename from code/_onclick/hud/picture_in_picture.dm rename to code/_onclick/hud/screen_objects/picture_in_picture.dm diff --git a/code/_onclick/hud/radial.dm b/code/_onclick/hud/screen_objects/radial.dm similarity index 100% rename from code/_onclick/hud/radial.dm rename to code/_onclick/hud/screen_objects/radial.dm diff --git a/code/_onclick/hud/radial_persistent.dm b/code/_onclick/hud/screen_objects/radial_persistent.dm similarity index 100% rename from code/_onclick/hud/radial_persistent.dm rename to code/_onclick/hud/screen_objects/radial_persistent.dm diff --git a/code/_onclick/hud/screen_objects/robot.dm b/code/_onclick/hud/screen_objects/robot.dm new file mode 100644 index 00000000000..9dd39e8d4d6 --- /dev/null +++ b/code/_onclick/hud/screen_objects/robot.dm @@ -0,0 +1,113 @@ +/atom/movable/screen/robot + icon = 'icons/hud/screen_cyborg.dmi' + mouse_over_pointer = MOUSE_HAND_POINTER + +/atom/movable/screen/robot/module + name = "cyborg module" + icon_state = "nomod" + +/atom/movable/screen/robot/Click(location, control, params) + if(isobserver(usr)) + return TRUE + +/atom/movable/screen/robot/module/Click(location, control, params) + . = ..() + var/mob/living/silicon/robot/robot_owner = hud.mymob + if(robot_owner.model.type == /obj/item/robot_model) + if(.) + return + robot_owner.pick_model() + return + + var/list/modifiers = params2list(params) + if(robot_owner.module_active && !LAZYACCESS(modifiers, RIGHT_CLICK) && !.) + robot_owner.uneq_active() + return + + // Observers can look at borg's inventories, so we ignore parent return value here, unlike everywhere else. + if(usr.active_storage == robot_owner.model.atom_storage) + robot_owner.model.atom_storage.hide_contents(usr) + else + robot_owner.model.atom_storage.open_storage(usr) + return TRUE + +/atom/movable/screen/robot/module_slot + name = "module" + icon_state = "inv1" + base_icon_state = "inv1" + /// Slot number of the module + var/slot_num = 1 + +/atom/movable/screen/robot/module_slot/proc/set_slot(slot_num) + src.slot_num = slot_num + name = "module[slot_num]" + base_icon_state = "inv[slot_num]" + icon_state = base_icon_state + + switch(slot_num) + if(BORG_CHOOSE_MODULE_ONE) + screen_loc = ui_inv1 + if(BORG_CHOOSE_MODULE_TWO) + screen_loc = ui_inv2 + if(BORG_CHOOSE_MODULE_THREE) + screen_loc = ui_inv3 + +/atom/movable/screen/robot/module_slot/Click() + if(..()) + return + var/mob/living/silicon/robot/R = usr + R.toggle_module(slot_num) + +/atom/movable/screen/robot/radio + name = "radio" + icon_state = "radio" + screen_loc = ui_borg_radio + +/atom/movable/screen/robot/radio/Click() + if(..()) + return + var/mob/living/silicon/robot/R = usr + R.radio.interact(R) + +/atom/movable/screen/robot/lamp + name = "headlamp" + icon_state = "lamp_off" + base_icon_state = "lamp" + screen_loc = ui_borg_lamp + +/atom/movable/screen/robot/lamp/Click() + . = ..() + if(.) + return + var/mob/living/silicon/robot/user = usr + user.toggle_headlamp() + update_appearance() + +/atom/movable/screen/robot/lamp/update_icon_state() + icon_state = "[base_icon_state]_[astype(hud?.mymob, /mob/living/silicon/robot)?.lamp_enabled ? "on" : "off"]" + return ..() + +/atom/movable/screen/robot/modpc + name = "Modular Interface" + icon_state = "template" + screen_loc = ui_borg_tablet + +/atom/movable/screen/robot/modpc/Click() + . = ..() + if(.) + return + var/mob/living/silicon/robot/user = usr + user.modularInterface?.interact(user) + +/atom/movable/screen/robot/alerts + name = "Alert Panel" + icon = 'icons/hud/screen_ai.dmi' + icon_state = "alerts" + screen_loc = ui_borg_alerts + +/atom/movable/screen/robot/alerts/Click() + . = ..() + if(.) + return + var/mob/living/silicon/robot/borgo = usr + borgo.alert_control.ui_interact(borgo) diff --git a/code/_onclick/hud/screen_object_holder.dm b/code/_onclick/hud/screen_objects/screen_object_holder.dm similarity index 100% rename from code/_onclick/hud/screen_object_holder.dm rename to code/_onclick/hud/screen_objects/screen_object_holder.dm diff --git a/code/_onclick/hud/screen_objects.dm b/code/_onclick/hud/screen_objects/screen_objects.dm similarity index 96% rename from code/_onclick/hud/screen_objects.dm rename to code/_onclick/hud/screen_objects/screen_objects.dm index 2514376f911..fc4c8be9e4f 100644 --- a/code/_onclick/hud/screen_objects.dm +++ b/code/_onclick/hud/screen_objects/screen_objects.dm @@ -1,3 +1,4 @@ +INITIALIZE_IMMEDIATE(/atom/movable/screen) // I hate this place /* Screen objects Todo: improve/re-implement @@ -34,6 +35,10 @@ */ var/del_on_map_removal = TRUE + /// A key for cleaning up references in hud datums + var/hud_group_key + var/hud_key + /// If FALSE, this will not be cleared when calling /client/clear_screen() var/clear_with_screen = TRUE /// If TRUE, clicking the screen element will fall through and perform a default "Click" call @@ -50,6 +55,10 @@ set_new_hud(hud_owner) /atom/movable/screen/Destroy() + if(hud) + if (hud_group_key && hud.screen_groups?[hud_group_key]) + hud.screen_groups?[hud_group_key] -= src + hud.screen_objects -= hud_key master_ref = null hud = null return ..() @@ -57,6 +66,7 @@ /atom/movable/screen/Click(location, control, params) if(flags_1 & INITIALIZED_1) SEND_SIGNAL(src, COMSIG_SCREEN_ELEMENT_CLICK, location, control, params, usr) + if(default_click) return ..() @@ -101,7 +111,6 @@ maptext_width = 480 /atom/movable/screen/swap_hand - plane = HUD_PLANE name = "swap hand" mouse_over_pointer = MOUSE_HAND_POINTER @@ -187,7 +196,6 @@ var/icon_full /// The overlay when hovering over with an item in your hand var/image/object_overlay - plane = HUD_PLANE /atom/movable/screen/inventory/Click(location, control, params) // At this point in client Click() code we have passed the 1/10 sec check and little else @@ -304,6 +312,7 @@ icon = 'icons/hud/screen_midnight.dmi' icon_state = "storage_close" mouse_over_pointer = MOUSE_HAND_POINTER + hud_group_key = HUD_GROUP_STORAGE /atom/movable/screen/close/Initialize(mapload, datum/hud/hud_owner, new_master) . = ..() @@ -320,7 +329,6 @@ name = "drop" icon = 'icons/hud/screen_midnight.dmi' icon_state = "act_drop" - plane = HUD_PLANE mouse_over_pointer = MOUSE_HAND_POINTER /atom/movable/screen/drop/Click() @@ -331,7 +339,7 @@ name = "toggle combat mode" icon = 'icons/hud/screen_midnight.dmi' icon_state = "combat_off" - screen_loc = ui_combat_toggle + screen_loc = ui_acti mouse_over_pointer = MOUSE_HAND_POINTER /atom/movable/screen/combattoggle/Initialize(mapload, datum/hud/hud_owner) @@ -470,6 +478,11 @@ icon = 'icons/hud/screen_midnight.dmi' icon_state = "running" mouse_over_pointer = MOUSE_HAND_POINTER + screen_loc = ui_movi + +/atom/movable/screen/mov_intent/Initialize(mapload, datum/hud/hud_owner) + . = ..() + update_appearance(UPDATE_ICON_STATE) /atom/movable/screen/mov_intent/Click() toggle(usr) @@ -496,6 +509,11 @@ icon_state = "pull" base_icon_state = "pull" mouse_over_pointer = MOUSE_HAND_POINTER + screen_loc = ui_living_pull + +/atom/movable/screen/pull/Initialize(mapload, datum/hud/hud_owner) + . = ..() + update_appearance(UPDATE_ICON_STATE) /atom/movable/screen/pull/Click() if(isobserver(usr)) @@ -511,8 +529,8 @@ icon = 'icons/hud/screen_midnight.dmi' icon_state = "act_resist" base_icon_state = "act_resist" - plane = HUD_PLANE mouse_over_pointer = MOUSE_HAND_POINTER + screen_loc = ui_above_movement /atom/movable/screen/resist/Click() flick("[base_icon_state]_on", src) @@ -525,8 +543,12 @@ icon = 'icons/hud/screen_midnight.dmi' icon_state = "act_rest" base_icon_state = "act_rest" - plane = HUD_PLANE mouse_over_pointer = MOUSE_HAND_POINTER + screen_loc = ui_below_throw + +/atom/movable/screen/rest/Initialize(mapload, datum/hud/hud_owner) + . = ..() + update_appearance(UPDATE_ICON_STATE) /atom/movable/screen/rest/Click() if(isliving(usr)) @@ -545,32 +567,38 @@ icon = 'icons/hud/screen_midnight.dmi' icon_state = "act_sleep" base_icon_state = "act_sleep" - plane = HUD_PLANE mouse_over_pointer = MOUSE_HAND_POINTER + screen_loc = ui_above_throw + +/atom/movable/screen/sleep/Initialize(mapload, datum/hud/hud_owner) + . = ..() + // Invisible by default + SetInvisibility(INVISIBILITY_ABSTRACT, "sleep") /atom/movable/screen/sleep/Click() if(!isliving(usr) || HAS_TRAIT(usr, TRAIT_KNOCKEDOUT)) return - if(usr.client?.prefs.read_preference(/datum/preference/toggle/remove_double_click)) - var/tgui_answer = tgui_alert(usr, "You sure you want to sleep for a while?", "Sleeping", list("Yes", "No")) - if(tgui_answer == "Yes" && !HAS_TRAIT(usr, TRAIT_KNOCKEDOUT)) - var/mob/living/L = usr - L.SetSleeping(400) - else + if(!usr.client?.prefs.read_preference(/datum/preference/toggle/remove_double_click)) flick("[base_icon_state]_flick", src) + return + + var/tgui_answer = tgui_alert(usr, "You sure you want to sleep for a while?", "Sleeping", list("Yes", "No")) + if(tgui_answer == "Yes" && !HAS_TRAIT(usr, TRAIT_KNOCKEDOUT)) + var/mob/living/L = usr + L.Sleeping(400) /atom/movable/screen/sleep/DblClick(location, control, params) if(!isliving(usr) || usr.client?.prefs.read_preference(/datum/preference/toggle/remove_double_click)) return if(isliving(usr)) var/mob/living/L = usr - L.SetSleeping(400) + L.Sleeping(400) /atom/movable/screen/storage name = "storage" icon = 'icons/hud/screen_midnight.dmi' icon_state = "storage_cell" - plane = HUD_PLANE + hud_group_key = HUD_GROUP_STORAGE /atom/movable/screen/storage/Initialize(mapload, datum/hud/hud_owner, new_master) . = ..() @@ -638,6 +666,7 @@ icon = 'icons/hud/screen_midnight.dmi' icon_state = "act_throw" mouse_over_pointer = MOUSE_HAND_POINTER + screen_loc = ui_drop_throw /atom/movable/screen/throw_catch/Click() if(isliving(usr)) @@ -653,6 +682,10 @@ var/static/list/hover_overlays_cache = list() var/hovering +/atom/movable/screen/zone_sel/Initialize(mapload, datum/hud/hud_owner) + . = ..() + update_appearance() + /atom/movable/screen/zone_sel/Click(location, control,params) if(isobserver(usr)) return @@ -941,7 +974,6 @@ plane = SPLASHSCREEN_PLANE var/client/holder -INITIALIZE_IMMEDIATE(/atom/movable/screen/splash) /atom/movable/screen/splash/Initialize(mapload, datum/hud/hud_owner, client/C, visible, use_previous_title) . = ..() diff --git a/code/_onclick/hud/screentip.dm b/code/_onclick/hud/screen_objects/screentip.dm similarity index 100% rename from code/_onclick/hud/screentip.dm rename to code/_onclick/hud/screen_objects/screentip.dm diff --git a/code/_onclick/hud/voidwalkerhud.dm b/code/_onclick/hud/screen_objects/voidwalker.dm similarity index 73% rename from code/_onclick/hud/voidwalkerhud.dm rename to code/_onclick/hud/screen_objects/voidwalker.dm index 7ba892f7d7a..6d718ac58d7 100644 --- a/code/_onclick/hud/voidwalkerhud.dm +++ b/code/_onclick/hud/screen_objects/voidwalker.dm @@ -1,30 +1,3 @@ -/datum/hud/dextrous/voidwalker - ui_style = 'icons/hud/screen_voidwalker.dmi' - -/datum/hud/dextrous/voidwalker/New(mob/living/owner) - . = ..() - - floor_change.icon = ui_style - floor_change.screen_loc = ui_rest - static_inventory += floor_change - - resist_icon = new /atom/movable/screen/resist(null, src) - resist_icon.icon = ui_style - resist_icon.screen_loc = ui_voidwalker_left_of_hands - resist_icon.update_appearance() - - action_intent = new /atom/movable/screen/combattoggle/flashy/voidwalker(null, src) - action_intent.icon = ui_style - static_inventory += action_intent - - var/atom/movable/screen/space_camo_toggle = new /atom/movable/screen/space_camo(null, src) - space_camo_toggle.screen_loc = ui_above_movement - static_inventory += space_camo_toggle - - var/atom/movable/screen/vomit_jump/vomit = new /atom/movable/screen/vomit_jump(null, src) - vomit.screen_loc = ui_mood - static_inventory += vomit - /// This exists because for some reason only the combat indicator screen_loc is constantly set to initial /atom/movable/screen/combattoggle/flashy/voidwalker screen_loc = ui_movi @@ -33,6 +6,7 @@ name = "space camouflage toggle" icon = 'icons/hud/screen_voidwalker.dmi' icon_state = "camo_toggle" + screen_loc = ui_above_movement /// Wheter or not we're toggled on or off var/invisibility_toggle = TRUE @@ -57,6 +31,7 @@ name = "vomit tracker" icon = 'icons/hud/screen_voidwalker.dmi' icon_state = "template" + screen_loc = ui_mood /// So we can sort of loop through it var/index = 1 diff --git a/code/_onclick/hud/soulscythe.dm b/code/_onclick/hud/soulscythe.dm index 8c7a3359c8a..e290d960e56 100644 --- a/code/_onclick/hud/soulscythe.dm +++ b/code/_onclick/hud/soulscythe.dm @@ -1,4 +1,3 @@ -/datum/hud/soulscythe/New(mob/living/basic/soulscythe/owner) +/datum/hud/soulscythe/initialize_screen_objects() . = ..() - var/atom/movable/screen/using = new /atom/movable/screen/blood_level(null, src) - static_inventory += using + add_screen_object(/atom/movable/screen/blood_level, HUD_MOB_BLOOD_LEVEL, HUD_GROUP_INFO) diff --git a/code/_onclick/hud/voidwalker.dm b/code/_onclick/hud/voidwalker.dm new file mode 100644 index 00000000000..7fe95fc3f28 --- /dev/null +++ b/code/_onclick/hud/voidwalker.dm @@ -0,0 +1,14 @@ +/datum/hud/dextrous/voidwalker + ui_style = 'icons/hud/screen_voidwalker.dmi' + +/datum/hud/dextrous/voidwalker/initialize_screen_objects() + . = ..() + var/atom/movable/screen/floor_change = screen_objects[HUD_MOB_FLOOR_CHANGER] + floor_change.icon = ui_style + floor_change.screen_loc = ui_below_throw + + add_screen_object(/atom/movable/screen/resist, HUD_MOB_RESIST, HUD_GROUP_HOTKEYS, ui_style, ui_voidwalker_left_of_hands) + add_screen_object(/atom/movable/screen/combattoggle/flashy/voidwalker, HUD_MOB_INTENTS, HUD_GROUP_STATIC, ui_style) + add_screen_object(/atom/movable/screen/space_camo, HUD_VOIDWALKER_SPACE_CAMO) + add_screen_object(/atom/movable/screen/vomit_jump, HUD_VOIDWALKER_VOID_JUMP) + diff --git a/code/datums/actions/action.dm b/code/datums/actions/action.dm index 64f2f2a6c2b..b5993e1894a 100644 --- a/code/datums/actions/action.dm +++ b/code/datums/actions/action.dm @@ -373,7 +373,7 @@ /// Creates an action button movable for the passed mob, and returns it. /datum/action/proc/create_button() - var/atom/movable/screen/movable/action_button/button = new() + var/atom/movable/screen/movable/action_button/button = owner.hud_used.add_screen_object(/atom/movable/screen/movable/action_button) button.linked_action = src button.allow_observer_click = allow_observer_click build_button_icon(button, ALL, TRUE) diff --git a/code/datums/components/crafting/crafting.dm b/code/datums/components/crafting/crafting.dm index d8b6103e338..a042bfe7a02 100644 --- a/code/datums/components/crafting/crafting.dm +++ b/code/datums/components/crafting/crafting.dm @@ -15,20 +15,29 @@ /datum/component/personal_crafting/Initialize(screen_loc_override) src.screen_loc_override = screen_loc_override - if(ismob(parent)) - RegisterSignal(parent, COMSIG_MOB_CLIENT_LOGIN, PROC_REF(create_mob_button)) -/datum/component/personal_crafting/proc/create_mob_button(mob/user, client/user_client) +/datum/component/personal_crafting/RegisterWithParent() + if(!ismob(parent)) + return + + var/mob/user = parent + RegisterSignal(parent, COMSIG_MOB_HUD_CREATED, PROC_REF(on_hud_created)) + if(user.hud_used) + on_hud_created() + +/datum/component/personal_crafting/UnregisterFromParent() + if(!ismob(parent)) + return + var/mob/user = parent + UnregisterSignal(parent, COMSIG_MOB_HUD_CREATED) + user.hud_used?.remove_screen_object(HUD_MOB_CRAFTING_MENU) + +/datum/component/personal_crafting/proc/on_hud_created(datum/source) SIGNAL_HANDLER - var/datum/hud/hud = user.hud_used - var/atom/movable/screen/craft/craft_ui = new() - craft_ui.icon = hud.ui_style - if (screen_loc_override) - craft_ui.screen_loc = screen_loc_override - hud.static_inventory += craft_ui - user_client.screen += craft_ui - RegisterSignal(craft_ui, COMSIG_SCREEN_ELEMENT_CLICK, PROC_REF(component_ui_interact)) + var/mob/user = parent + var/atom/movable/screen/screen_obj = user.hud_used.add_screen_object(/atom/movable/screen/craft, HUD_MOB_CRAFTING_MENU, HUD_GROUP_STATIC, user.hud_used.ui_style, screen_loc_override, update_screen = TRUE) + RegisterSignal(screen_obj, COMSIG_SCREEN_ELEMENT_CLICK, PROC_REF(component_ui_interact)) #define COOKING TRUE #define CRAFTING FALSE diff --git a/code/datums/components/food/edible.dm b/code/datums/components/food/edible.dm index b58ef88a3dc..465b6ae2066 100644 --- a/code/datums/components/food/edible.dm +++ b/code/datums/components/food/edible.dm @@ -504,7 +504,9 @@ Behavior that's still missing from this component that original food items had t var/fraction = 0.3 fraction = min(bite_consumption / owner.reagents.total_volume, 1) owner.reagents.trans_to(eater, bite_consumption, transferred_by = feeder, methods = INGEST) - eater.hud_used?.hunger?.update_hunger_bar() + var/atom/movable/screen/hunger/hunger_bar = eater.hud_used?.screen_objects[HUD_MOB_HUNGER] + if (istype(hunger_bar)) + hunger_bar.update_hunger_bar() bitecount++ checkLiked(fraction, eater) diff --git a/code/datums/components/fov_handler.dm b/code/datums/components/fov_handler.dm index df56df1ff6e..cd3061291a2 100644 --- a/code/datums/components/fov_handler.dm +++ b/code/datums/components/fov_handler.dm @@ -90,8 +90,6 @@ /datum/component/fov_handler/proc/remove_mask() var/mob/parent_mob = parent var/client/parent_client = parent_mob.client - // Prevents stupid ass hard deletes - parent_mob.hud_used.always_visible_inventory -= blocker_mask if(!parent_client) //Love client volatility!! return applied_mask = FALSE @@ -104,7 +102,8 @@ return applied_mask = TRUE parent_client.screen += blocker_mask - parent_mob.hud_used.always_visible_inventory += blocker_mask + parent_mob.hud_used.screen_objects += blocker_mask + parent_mob.hud_used.screen_groups[HUD_GROUP_SCREEN_OVERLAYS] += blocker_mask /// When a direction of the user changes, so do the masks /datum/component/fov_handler/proc/on_dir_change(mob/source, old_dir, new_dir) diff --git a/code/datums/components/life_link.dm b/code/datums/components/life_link.dm index a79758122c5..d1371467682 100644 --- a/code/datums/components/life_link.dm +++ b/code/datums/components/life_link.dm @@ -118,8 +118,9 @@ mob_parent.overlay_fullscreen("brute", /atom/movable/screen/fullscreen/brute, severity) else mob_parent.clear_fullscreen("brute") - if(mob_parent.hud_used?.healths) - mob_parent.hud_used.healths.maptext = MAPTEXT("
[round(healthpercent, 0.5)]%
") + + if(mob_parent.hud_used?.screen_objects[HUD_MOB_HEALTH]) + mob_parent.hud_used.screen_objects[HUD_MOB_HEALTH].maptext = MAPTEXT("
[round(healthpercent, 0.5)]%
") /// Update our health on the medical hud /datum/component/life_link/proc/update_med_hud_health(mob/living/mob_parent) diff --git a/code/datums/components/style/style.dm b/code/datums/components/style/style.dm index 6e1147a7ba3..04ea7b3654c 100644 --- a/code/datums/components/style/style.dm +++ b/code/datums/components/style/style.dm @@ -74,23 +74,7 @@ if(!ismob(parent)) return COMPONENT_INCOMPATIBLE - var/mob/mob_parent = parent - - meter = new() - meter_image = new() - meter.vis_contents += meter_image - meter_image.add_filter("meter_mask", 1, list(type = "alpha", icon = icon('icons/hud/style_meter.dmi', "style_meter"), flags = MASK_INVERSE)) - meter.update_appearance() - meter_image.update_appearance() - - update_screen() - - if(mob_parent.hud_used) - mob_parent.hud_used.static_inventory += meter - mob_parent.hud_used.show_hud(mob_parent.hud_used.hud_version) - START_PROCESSING(SSdcs, src) - if(multitooled) src.multitooled = multitooled @@ -107,7 +91,11 @@ RegisterSignal(parent, COMSIG_LIVING_DEFUSED_GIBTONITE, PROC_REF(on_gibtonite_defuse)) RegisterSignal(parent, COMSIG_LIVING_CRUSHER_DETONATE, PROC_REF(on_crusher_detonate)) RegisterSignal(parent, COMSIG_LIVING_DISCOVERED_GEYSER, PROC_REF(on_geyser_discover)) + RegisterSignal(parent, COMSIG_MOB_HUD_CREATED, PROC_REF(on_hud_created)) ADD_TRAIT(parent, TRAIT_MINING_PARRYING, STYLE_TRAIT) + var/mob/mob_parent = parent + if (mob_parent.hud_used) + on_hud_created() /datum/component/style/UnregisterFromParent() UnregisterSignal(parent, COMSIG_USER_PRE_ITEM_ATTACK) @@ -121,16 +109,31 @@ UnregisterSignal(parent, COMSIG_LIVING_DEFUSED_GIBTONITE) UnregisterSignal(parent, COMSIG_LIVING_CRUSHER_DETONATE) UnregisterSignal(parent, COMSIG_LIVING_DISCOVERED_GEYSER) + UnregisterSignal(parent, COMSIG_MOB_HUD_CREATED) REMOVE_TRAIT(parent, TRAIT_MINING_PARRYING, STYLE_TRAIT) /datum/component/style/Destroy(force) STOP_PROCESSING(SSdcs, src) + QDEL_NULL(meter) + QDEL_NULL(meter_image) var/mob/mob_parent = parent if(mob_parent.hud_used) - mob_parent.hud_used.static_inventory -= meter mob_parent.hud_used.show_hud(mob_parent.hud_used.hud_version) return ..() + +/datum/component/style/proc/on_hud_created(datum/source) + SIGNAL_HANDLER + + var/mob/owner = parent + meter = owner.hud_used.add_screen_object(/atom/movable/screen/style_meter_background, HUD_MOB_STYLE_METER, update_screen = TRUE) + meter_image = new() + meter.vis_contents += meter_image + meter_image.add_filter("meter_mask", 1, list(type = "alpha", icon = icon('icons/hud/style_meter.dmi', "style_meter"), flags = MASK_INVERSE)) + meter.update_appearance() + meter_image.update_appearance() + update_screen() + /datum/component/style/process(seconds_per_tick) point_multiplier = round(max(point_multiplier - 0.2 * seconds_per_tick, 1), 0.1) change_points(-5 * seconds_per_tick * ROUND_UP((style_points + 1) / 200), use_multiplier = FALSE) @@ -195,6 +198,9 @@ mob_parent.balloon_alert(mob_parent, "hotswapping disabled") rank = rank_changed + + if(!meter) + return meter.maptext = "[format_rank_string(rank)][generate_multiplier()][generate_actions()]" meter.maptext_y = initial(meter.maptext_y) - 12 * length(actions) update_meter(point_to_rank(), go_back) diff --git a/code/datums/elements/attack_zone_randomiser.dm b/code/datums/elements/attack_zone_randomiser.dm index 1e364265bab..efd7648bc7c 100644 --- a/code/datums/elements/attack_zone_randomiser.dm +++ b/code/datums/elements/attack_zone_randomiser.dm @@ -21,14 +21,14 @@ SIGNAL_HANDLER if (!iscarbon(target)) return - if (!isnull(source.mind) && !isnull(source.hud_used?.zone_select)) + if (!isnull(source.mind) && !isnull(source.hud_used?.screen_objects[HUD_MOB_ZONE_SELECTOR])) return var/mob/living/living_target = target var/list/blacklist_zones = GLOB.all_body_zones - valid_attack_zones var/new_zone = living_target.get_random_valid_zone(blacklisted_parts = blacklist_zones, bypass_warning = TRUE) if (isnull(new_zone)) new_zone = BODY_ZONE_CHEST - var/atom/movable/screen/zone_sel/zone_selector = source.hud_used?.zone_select + var/atom/movable/screen/zone_sel/zone_selector = source.hud_used?.screen_objects[HUD_MOB_ZONE_SELECTOR] if (isnull(zone_selector)) source.zone_selected = new_zone else diff --git a/code/datums/keybinding/living.dm b/code/datums/keybinding/living.dm index 42eb96bf5da..d9d12020ef2 100644 --- a/code/datums/keybinding/living.dm +++ b/code/datums/keybinding/living.dm @@ -18,8 +18,8 @@ return var/mob/living/owner = user.mob owner.resist() - if (owner.hud_used?.resist_icon) - owner.hud_used.resist_icon.icon_state = "[owner.hud_used.resist_icon.base_icon_state]_on" + if (owner.hud_used?.screen_objects[HUD_MOB_RESIST]) + owner.hud_used.screen_objects[HUD_MOB_RESIST].icon_state = "[owner.hud_used.screen_objects[HUD_MOB_RESIST].base_icon_state]_on" return TRUE /datum/keybinding/living/resist/up(client/user, turf/target) @@ -27,8 +27,8 @@ if(.) return var/mob/living/owner = user.mob - if (owner.hud_used?.resist_icon) - owner.hud_used.resist_icon.icon_state = owner.hud_used.resist_icon.base_icon_state + if (owner.hud_used?.screen_objects[HUD_MOB_RESIST]) + owner.hud_used.screen_objects[HUD_MOB_RESIST].icon_state = owner.hud_used.screen_objects[HUD_MOB_RESIST].base_icon_state /datum/keybinding/living/look_up hotkey_keys = list("L") diff --git a/code/datums/martial/_martial.dm b/code/datums/martial/_martial.dm index 4a0c9c84b30..1281d028b22 100644 --- a/code/datums/martial/_martial.dm +++ b/code/datums/martial/_martial.dm @@ -24,8 +24,6 @@ var/smashes_tables = FALSE /// If TRUE, a combo meter will be displayed on the HUD for the current streak var/display_combos = FALSE - ///The Combo HUD given to display comboes, if we're set to display them. - var/atom/movable/screen/combo/combo_display /// The length of time until streaks are auto-reset. var/combo_timer = 6 SECONDS /// Timer ID for the combo reset timer. @@ -276,8 +274,11 @@ streak += element if(length(streak) > max_streak_length) streak = copytext(streak, 1 + length(streak[1])) - if(display_combos) - timerid = addtimer(CALLBACK(src, PROC_REF(reset_streak), null, FALSE), combo_timer, TIMER_UNIQUE | TIMER_STOPPABLE) + if(!display_combos) + return + timerid = addtimer(CALLBACK(src, PROC_REF(reset_streak), null, FALSE), combo_timer, TIMER_UNIQUE | TIMER_STOPPABLE) + var/atom/movable/screen/combo/combo_display = holder.hud_used?.screen_objects[HUD_MOB_COMBO] + if(istype(combo_display)) combo_display.update_icon_state(streak, combo_timer - 2 SECONDS) /** @@ -292,7 +293,8 @@ deltimer(timerid) current_target = WEAKREF(new_target) streak = "" - if(display_combos && update_icon) + var/atom/movable/screen/combo/combo_display = holder.hud_used?.screen_objects[HUD_MOB_COMBO] + if(istype(combo_display) && display_combos && update_icon) combo_display.update_icon_state(streak) /datum/martial_art/proc/smash_table(mob/living/source, mob/living/pushed_mob, obj/structure/table/table) @@ -383,10 +385,9 @@ RegisterSignal(new_holder, COMSIG_LIVING_GRAB, PROC_REF(attempt_grab)) RegisterSignals(new_holder, list(COMSIG_LIVING_TABLE_SLAMMING, COMSIG_LIVING_TABLE_LIMB_SLAMMING), PROC_REF(smash_table)) if(display_combos) + RegisterSignal(new_holder, COMSIG_MOB_HUD_CREATED, PROC_REF(on_hud_created)) if(new_holder.hud_used) on_hud_created(new_holder) - else - RegisterSignal(new_holder, COMSIG_MOB_HUD_CREATED, PROC_REF(on_hud_created)) /** * Called when this martial art is removed from a mob. @@ -397,19 +398,12 @@ if(help_verb) remove_verb(remove_from, help_verb) UnregisterSignal(remove_from, list(COMSIG_LIVING_UNARMED_ATTACK, COMSIG_LIVING_GRAB, COMSIG_LIVING_TABLE_SLAMMING, COMSIG_LIVING_TABLE_LIMB_SLAMMING)) - if(!isnull(combo_display)) - var/datum/hud/hud_used = remove_from.hud_used - hud_used.infodisplay -= combo_display - hud_used.show_hud(hud_used.hud_version) - QDEL_NULL(combo_display) + remove_from.hud_used?.remove_screen_object(HUD_MOB_COMBO) ///Gives the owner of the martial art the combo HUD. /datum/martial_art/proc/on_hud_created(mob/source) SIGNAL_HANDLER - var/datum/hud/hud_used = source.hud_used - combo_display = new(null, hud_used) - hud_used.infodisplay += combo_display - hud_used.show_hud(hud_used.hud_version) + source.hud_used.add_screen_object(/atom/movable/screen/combo, HUD_MOB_COMBO, HUD_GROUP_INFO, update_screen = TRUE) /mob/living/proc/verb_switch_style() set name = "Swap Style" diff --git a/code/datums/mood.dm b/code/datums/mood.dm index 6ee75391517..afc7824380f 100644 --- a/code/datums/mood.dm +++ b/code/datums/mood.dm @@ -36,8 +36,6 @@ var/sanity_level = SANITY_LEVEL_NEUTRAL /// Is the owner being punished for low mood? if so, how much? var/insanity_effect = 0 - /// The screen object for the current mood level - var/atom/movable/screen/mood/mood_screen_object /// List of mood events currently active on this datum var/list/mood_events = list() @@ -308,7 +306,11 @@ /// Updates the mob's mood icon /datum/mood/proc/update_mood_icon() - if (!(mob_parent.client || mob_parent.hud_used) || isnull(mood_screen_object)) + if (!mob_parent.client || !mob_parent.hud_used) + return + + var/atom/movable/screen/mood/mood_screen_object = mob_parent.hud_used.screen_objects[HUD_MOB_MOOD] + if (!istype(mood_screen_object)) return mood_screen_object.cut_overlays() @@ -356,9 +358,8 @@ SIGNAL_HANDLER var/datum/hud/hud = mob_parent.hud_used - mood_screen_object = new + var/atom/movable/screen/mood/mood_screen_object = hud.add_screen_object(/atom/movable/screen/mood, HUD_MOB_MOOD, HUD_GROUP_INFO, update_screen = TRUE) mood_screen_object.color = "#4b96c4" - hud.infodisplay += mood_screen_object RegisterSignal(hud, COMSIG_QDELETING, PROC_REF(unmodify_hud)) RegisterSignal(mood_screen_object, COMSIG_SCREEN_ELEMENT_CLICK, PROC_REF(hud_click)) @@ -366,12 +367,17 @@ /datum/mood/proc/unmodify_hud(datum/source) SIGNAL_HANDLER + var/datum/hud/hud = mob_parent.hud_used + if (!hud) + return + + var/atom/movable/screen/mood/mood_screen_object = hud.screen_objects[HUD_MOB_MOOD] if(!mood_screen_object) return - var/datum/hud/hud = mob_parent.hud_used - if(hud?.infodisplay) - hud.infodisplay -= mood_screen_object + QDEL_NULL(mood_screen_object) + if (!QDELETED(hud)) + hud.show_hud(hud.hud_version) UnregisterSignal(hud, COMSIG_QDELETING) /// Handles clicking on the mood HUD object diff --git a/code/datums/status_effects/debuffs/screwy_hud.dm b/code/datums/status_effects/debuffs/screwy_hud.dm index 10c20112160..4779db579c6 100644 --- a/code/datums/status_effects/debuffs/screwy_hud.dm +++ b/code/datums/status_effects/debuffs/screwy_hud.dm @@ -40,7 +40,7 @@ if(other_screwy_hud.priority > priority) return - source.hud_used.healths.icon_state = override_icon + source.hud_used?.screen_objects[HUD_MOB_HEALTH]?.icon_state = override_icon return COMPONENT_OVERRIDE_HEALTH_HUD /datum/status_effect/grouped/screwy_hud/fake_dead diff --git a/code/datums/storage/storage.dm b/code/datums/storage/storage.dm index baab88cf239..472f9c6baa6 100644 --- a/code/datums/storage/storage.dm +++ b/code/datums/storage/storage.dm @@ -718,9 +718,12 @@ GLOBAL_LIST_EMPTY(cached_storage_typecaches) SIGNAL_HANDLER for(var/mob/user as anything in is_using) - user.hud_used?.open_containers -= gone + if (user.hud_used?.screen_groups[HUD_GROUP_STORAGE]) + user.hud_used.screen_groups[HUD_GROUP_STORAGE] -= gone + if(!user.client) continue + var/client/cuser = user.client cuser.screen -= gone @@ -1086,9 +1089,10 @@ GLOBAL_LIST_EMPTY(cached_storage_typecaches) LAZYOR(is_using, to_show) - to_show.hud_used.open_containers |= storage_interfaces[to_show].list_ui_elements() + // Don't add to screen_objects as that one gets its contents actually deleted + LAZYOR(to_show.hud_used.screen_groups[HUD_GROUP_STORAGE], storage_interfaces[to_show].list_ui_elements()) to_show.client.screen |= storage_interfaces[to_show].list_ui_elements() - to_show.hud_used.open_containers |= real_location.contents + LAZYOR(to_show.hud_used.screen_groups[HUD_GROUP_STORAGE], real_location.contents) to_show.client.screen |= real_location.contents return TRUE @@ -1116,9 +1120,9 @@ GLOBAL_LIST_EMPTY(cached_storage_typecaches) if(to_hide.client) to_hide.client.screen -= storage_interfaces[to_hide].list_ui_elements() to_hide.client.screen -= real_location.contents - if(to_hide.hud_used) - to_hide.hud_used.open_containers -= storage_interfaces[to_hide].list_ui_elements() - to_hide.hud_used.open_containers -= real_location.contents + if(to_hide.hud_used.screen_groups[HUD_GROUP_STORAGE]) + to_hide.hud_used.screen_groups[HUD_GROUP_STORAGE] -= storage_interfaces[to_hide].list_ui_elements() + to_hide.hud_used.screen_groups[HUD_GROUP_STORAGE] -= real_location.contents QDEL_NULL(storage_interfaces[to_hide]) storage_interfaces -= to_hide diff --git a/code/datums/wounds/bones.dm b/code/datums/wounds/bones.dm index f6ba5f3acb9..695af1eaef9 100644 --- a/code/datums/wounds/bones.dm +++ b/code/datums/wounds/bones.dm @@ -286,7 +286,7 @@ /datum/wound/blunt/bone/moderate/try_handling(mob/living/user) if(user.usable_hands <= 0 || user.pulling != victim) return FALSE - if(!isnull(user.hud_used?.zone_select) && user.zone_selected != limb.body_zone) + if(!isnull(user.hud_used?.screen_objects[HUD_MOB_ZONE_SELECTOR]) && user.zone_selected != limb.body_zone) return FALSE if(user.grab_state == GRAB_PASSIVE) diff --git a/code/datums/wounds/cranial_fissure.dm b/code/datums/wounds/cranial_fissure.dm index e26e3a97d9d..9a2fd0eb439 100644 --- a/code/datums/wounds/cranial_fissure.dm +++ b/code/datums/wounds/cranial_fissure.dm @@ -87,7 +87,7 @@ if (user.usable_hands <= 0 || user.combat_mode) return FALSE - if(!isnull(user.hud_used?.zone_select) && (user.zone_selected != BODY_ZONE_HEAD && user.zone_selected != BODY_ZONE_PRECISE_EYES)) + if(!isnull(user.hud_used?.screen_objects[HUD_MOB_ZONE_SELECTOR]) && (user.zone_selected != BODY_ZONE_HEAD && user.zone_selected != BODY_ZONE_PRECISE_EYES)) return FALSE if (victim.body_position != LYING_DOWN) diff --git a/code/datums/wounds/slash.dm b/code/datums/wounds/slash.dm index 68f6d685ae8..5ed2e8695b7 100644 --- a/code/datums/wounds/slash.dm +++ b/code/datums/wounds/slash.dm @@ -181,7 +181,7 @@ /datum/wound/slash/flesh/try_handling(mob/living/user) if(user.pulling != victim || !HAS_TRAIT(user, TRAIT_WOUND_LICKER) || !victim.try_inject(user, injection_flags = INJECT_TRY_SHOW_ERROR_MESSAGE)) return FALSE - if(!isnull(user.hud_used?.zone_select) && user.zone_selected != limb.body_zone) + if(!isnull(user.hud_used?.screen_objects[HUD_MOB_ZONE_SELECTOR]) && user.zone_selected != limb.body_zone) return FALSE if(DOING_INTERACTION_WITH_TARGET(user, victim)) diff --git a/code/game/machinery/computer/operating_computer.dm b/code/game/machinery/computer/operating_computer.dm index 416f4c16fac..79d9b9279e0 100644 --- a/code/game/machinery/computer/operating_computer.dm +++ b/code/game/machinery/computer/operating_computer.dm @@ -148,7 +148,7 @@ if(!zone_found) return - var/atom/movable/screen/zone_sel/selector = user.hud_used?.zone_select + var/atom/movable/screen/zone_sel/selector = user.hud_used?.screen_objects[HUD_MOB_ZONE_SELECTOR] selector?.set_selected_zone(zone_found, user, FALSE) LAZYREMOVE(zone_on_open, WEAKREF(user)) if(!LAZYLEN(zone_on_open)) @@ -257,7 +257,7 @@ if("change_zone") if(params["new_zone"] in (GLOB.all_body_zones + GLOB.all_precise_body_zones)) target_zone = params["new_zone"] - var/atom/movable/screen/zone_sel/selector = ui.user.hud_used?.zone_select + var/atom/movable/screen/zone_sel/selector = ui.user.hud_used?.screen_objects[HUD_MOB_ZONE_SELECTOR] selector?.set_selected_zone(params["new_zone"], ui.user, FALSE) update_static_data_for_all_viewers() return TRUE diff --git a/code/game/machinery/computer/records/records.dm b/code/game/machinery/computer/records/records.dm index 2f6e429c772..a860e66d4f7 100644 --- a/code/game/machinery/computer/records/records.dm +++ b/code/game/machinery/computer/records/records.dm @@ -111,7 +111,7 @@ if(user.client?.screen_maps[assigned_view]) return - var/atom/movable/screen/map_view/char_preview/new_view = new(null, src) + var/atom/movable/screen/map_view/char_preview/new_view = new(null, null, src) new_view.generate_view(assigned_view) new_view.display_to(user, window) return new_view diff --git a/code/game/objects/items/devices/multitool.dm b/code/game/objects/items/devices/multitool.dm index 6a3ec38c3da..c58e46e7478 100644 --- a/code/game/objects/items/devices/multitool.dm +++ b/code/game/objects/items/devices/multitool.dm @@ -97,19 +97,27 @@ user.balloon_alert(user, balloon_message) var/datum/hud/user_hud = user.hud_used - if(!user_hud || !istype(user_hud, /datum/hud) || !islist(user_hud.infodisplay)) + if(!user_hud) return - var/atom/movable/screen/multitool_arrow/arrow = new(null, user_hud) + var/atom/movable/screen/multitool_arrow/arrow = user_hud.add_screen_object(/atom/movable/screen/multitool_arrow, HUD_MULTITOOL_ARROW, HUD_GROUP_INFO, update_screen = TRUE) arrow.color = arrow_color - arrow.screen_loc = around_player arrow.transform = matrix(dir2angle(dir), MATRIX_ROTATE) - - user_hud.infodisplay += arrow - user_hud.show_hud(user_hud.hud_version) - QDEL_IN(arrow, 1.5 SECONDS) +/atom/movable/screen/multitool_arrow + icon = 'icons/effects/96x96.dmi' + icon_state = "multitool_arrow" + pixel_x = -32 + pixel_y = -32 + screen_loc = around_player + +/atom/movable/screen/multitool_arrow/Destroy() + var/datum/hud/our_hud = hud + . = ..() + if (!QDELETED(our_hud)) + INVOKE_ASYNC(our_hud, TYPE_PROC_REF(/datum/hud, show_hud), our_hud.hud_version) + /obj/item/multitool/suicide_act(mob/living/carbon/user) user.visible_message(span_suicide("[user] puts the [src] to [user.p_their()] chest. It looks like [user.p_theyre()] trying to pulse [user.p_their()] heart off!")) return OXYLOSS//there's a reason it wasn't recommended by doctors diff --git a/code/modules/antagonists/blob/overmind.dm b/code/modules/antagonists/blob/overmind.dm index 2fc737cb365..e6f8ad51e22 100644 --- a/code/modules/antagonists/blob/overmind.dm +++ b/code/modules/antagonists/blob/overmind.dm @@ -61,9 +61,6 @@ GLOBAL_LIST_EMPTY(blob_nodes) /// The list of strains the blob can reroll for. var/list/strain_choices - ///The HUD given to blobs with their power - var/atom/movable/screen/blob_power_display/blob_power_hud - /mob/eye/blob/Initialize(mapload, starting_points = OVERMIND_STARTING_POINTS) ADD_TRAIT(src, TRAIT_BLOB_ALLY, INNATE_TRAIT) validate_location() @@ -85,14 +82,6 @@ GLOBAL_LIST_EMPTY(blob_nodes) START_PROCESSING(SSobj, src) GLOB.blob_telepathy_mobs |= src -/mob/eye/blob/create_mob_hud() - . = ..() - if(!.) - return - blob_power_hud = new(null, src) - hud_used.infodisplay += blob_power_hud - hud_used.show_hud(hud_used.hud_version) - /mob/eye/blob/proc/validate_location() var/turf/T = get_turf(src) if(is_valid_turf(T)) @@ -263,7 +252,6 @@ GLOBAL_LIST_EMPTY(blob_nodes) /mob/eye/blob/Destroy() QDEL_NULL(blobstrain) - QDEL_NULL(blob_power_hud) // Clear references immediately without iterating to avoid blocking all_blobs = null @@ -304,15 +292,15 @@ GLOBAL_LIST_EMPTY(blob_nodes) return FALSE var/current_health = round((blob_core.get_integrity() / blob_core.max_integrity) * 100) var/new_maptext = MAPTEXT("
[current_health]%
") - hud_used.healths.maptext = new_maptext + hud_used.screen_objects[HUD_MOB_HEALTH].maptext = new_maptext for(var/mob/living/basic/blob_minion/blobbernaut/blobbernaut in blob_mobs) - if(isnull(blobbernaut.overmind_hud)) - continue - blobbernaut.overmind_hud.maptext = new_maptext + var/atom/movable/screen/overmind_hud = blobbernaut.hud_used?.screen_objects[HUD_BLOBBERNAUT_OVERMIND] + if (overmind_hud) + overmind_hud.maptext = new_maptext /mob/eye/blob/proc/add_points(points) blob_points = clamp(blob_points + points, 0, max_blob_points) - blob_power_hud.maptext = MAPTEXT("
[round(blob_points)]
") + hud_used.screen_objects[HUD_BLOB_POWER_DISPLAY].maptext = MAPTEXT("
[round(blob_points)]
") /mob/eye/blob/say( message, diff --git a/code/modules/antagonists/blood_worm/blood_worm_host_handling.dm b/code/modules/antagonists/blood_worm/blood_worm_host_handling.dm index 67543842cd0..2b87fd4c9f6 100644 --- a/code/modules/antagonists/blood_worm/blood_worm_host_handling.dm +++ b/code/modules/antagonists/blood_worm/blood_worm_host_handling.dm @@ -132,7 +132,7 @@ host.remove_blood_volume_modifier(REF(src)) sync_health(already_ejecting = TRUE) - remove_host_hud() + host.hud_used?.remove_screen_object(HUD_MOB_BLOOD_LEVEL) host.set_blood_volume(0) @@ -245,16 +245,8 @@ UnregisterSignal(host, COMSIG_MOB_HUD_CREATED) var/datum/hud/hud = host.hud_used - blood_display = new(null, hud) - hud.infodisplay += blood_display - hud.show_hud(hud.hud_version) - -/mob/living/basic/blood_worm/proc/remove_host_hud() - var/datum/hud/hud = host.hud_used - - if (!hud) - QDEL_NULL(blood_display) + var/atom/movable/screen/blood_level/blood_display = hud.screen_objects[HUD_MOB_BLOOD_LEVEL] + if (blood_display) return - hud.infodisplay -= blood_display - QDEL_NULL(blood_display) + blood_display = hud.add_screen_object(/atom/movable/screen/blood_level, HUD_MOB_BLOOD_LEVEL, HUD_GROUP_INFO, update_screen = TRUE) diff --git a/code/modules/antagonists/blood_worm/blood_worm_mob.dm b/code/modules/antagonists/blood_worm/blood_worm_mob.dm index a3a960abcd9..6fe2a41391f 100644 --- a/code/modules/antagonists/blood_worm/blood_worm_mob.dm +++ b/code/modules/antagonists/blood_worm/blood_worm_mob.dm @@ -62,9 +62,6 @@ /// This mob is always dead as it's just a mind holder. var/mob/living/blood_worm_host/backseat - /// The blood display on the left side of the screen, which is shown to the blood worm while in a host, if any. - var/atom/movable/screen/blood_level/blood_display - // Innate and shared actions /// Typed, please initialize with a proper action subtype. (empty = no action) diff --git a/code/modules/antagonists/changeling/changeling.dm b/code/modules/antagonists/changeling/changeling.dm index ad138d35d56..1fdf17ef8d7 100644 --- a/code/modules/antagonists/changeling/changeling.dm +++ b/code/modules/antagonists/changeling/changeling.dm @@ -71,11 +71,6 @@ /// A reference to our cellular emporium action (which opens the UI for the datum). var/datum/action/cellular_emporium/emporium_action - /// UI displaying how many chems we have - var/atom/movable/screen/ling/chems/lingchemdisplay - /// UI displayng our currently active sting - var/atom/movable/screen/ling/sting/lingstingdisplay - /// The name of our "hive" that our ling came from. Flavor. var/hive_name @@ -144,23 +139,14 @@ RegisterSignal(living_mob, COMSIG_LIVING_LIFE, PROC_REF(on_life)) RegisterSignal(living_mob, COMSIG_LIVING_POST_FULLY_HEAL, PROC_REF(on_fullhealed)) RegisterSignal(living_mob, COMSIG_CARBON_GAIN_ORGAN, PROC_REF(new_brain)) + RegisterSignal(living_mob, COMSIG_MOB_HUD_CREATED, PROC_REF(on_hud_created)) RegisterSignals(living_mob, list(COMSIG_MOB_MIDDLECLICKON, COMSIG_MOB_ALTCLICKON), PROC_REF(on_click_sting)) ADD_TRAIT(living_mob, TRAIT_FAKE_SOULLESS, CHANGELING_TRAIT) ADD_TRAIT(living_mob, TRAIT_BRAINLESS_CARBON, CHANGELING_TRAIT) ADD_TRAIT(living_mob, TRAIT_CHANGELING_HIVEMIND, CHANGELING_TRAIT) - if(living_mob.hud_used) - var/datum/hud/hud_used = living_mob.hud_used - - lingchemdisplay = new /atom/movable/screen/ling/chems(null, hud_used) - hud_used.infodisplay += lingchemdisplay - - lingstingdisplay = new /atom/movable/screen/ling/sting(null, hud_used) - hud_used.infodisplay += lingstingdisplay - - hud_used.show_hud(hud_used.hud_version) - else - RegisterSignal(living_mob, COMSIG_MOB_HUD_CREATED, PROC_REF(on_hud_created)) + if (living_mob.hud_used) + on_hud_created() make_brain_decoy(living_mob) @@ -193,14 +179,8 @@ SIGNAL_HANDLER var/datum/hud/ling_hud = owner.current.hud_used - - lingchemdisplay = new(null, ling_hud) - ling_hud.infodisplay += lingchemdisplay - - lingstingdisplay = new(null, ling_hud) - ling_hud.infodisplay += lingstingdisplay - - ling_hud.show_hud(ling_hud.hud_version) + ling_hud.add_screen_object(/atom/movable/screen/ling/chems, HUD_CHANGELING_CHEMS, HUD_GROUP_INFO) + ling_hud.add_screen_object(/atom/movable/screen/ling/sting, HUD_CHANGELING_STING, HUD_GROUP_INFO, update_screen = TRUE) /datum/antagonist/changeling/proc/new_brain(mob/living/carbon/ling, obj/item/organ/new_brain) SIGNAL_HANDLER @@ -228,14 +208,12 @@ for(var/mob/eye/imaginary_friend/hivemind/hivemind_member in living_mob.imaginary_group) qdel(hivemind_member) - if(living_mob.hud_used) - var/datum/hud/hud_used = living_mob.hud_used - - hud_used.infodisplay -= lingchemdisplay - hud_used.infodisplay -= lingstingdisplay - QDEL_NULL(lingchemdisplay) - QDEL_NULL(lingstingdisplay) + if(!living_mob.hud_used) + return + var/datum/hud/hud_used = living_mob.hud_used + hud_used.remove_screen_object(HUD_CHANGELING_CHEMS, update = FALSE) + hud_used.remove_screen_object(HUD_CHANGELING_STING) // The old body's brain still remains a decoy, I guess? /datum/antagonist/changeling/on_removal() @@ -351,12 +329,13 @@ ///Updates the Changeling's chemical HUD to display the information we want it to (chem charges, or max if hovered over). /datum/antagonist/changeling/proc/update_chemical_hud(amount) - if(isnull(lingchemdisplay)) + var/atom/movable/screen/ling/chems/chems = owner.current?.hud_used?.screen_objects[HUD_CHANGELING_CHEMS] + if(isnull(chems)) return - if(lingchemdisplay.hovering) - lingchemdisplay.maptext = FORMAT_CHEM_MAX_TEXT(total_chem_storage) + if(chems.hovering) + chems.maptext = FORMAT_CHEM_MAX_TEXT(total_chem_storage) else - lingchemdisplay.maptext = FORMAT_CHEM_CHARGES_TEXT(amount) + chems.maptext = FORMAT_CHEM_CHARGES_TEXT(amount) /* * Remove changeling powers from the current Changeling's purchased_powers list. diff --git a/code/modules/antagonists/changeling/powers/tiny_prick.dm b/code/modules/antagonists/changeling/powers/tiny_prick.dm index 91d7f8ba059..3368417c2c6 100644 --- a/code/modules/antagonists/changeling/powers/tiny_prick.dm +++ b/code/modules/antagonists/changeling/powers/tiny_prick.dm @@ -1,7 +1,8 @@ /datum/action/changeling/sting//parent path, not meant for users afaik - name = "Tiny Prick" + name = "Tiny Prick" //cellularemporium uses `nameToIconState` to button icon state must match this, on top of matching the hud below. desc = "Stabby stabby" category = "stings" + button_icon_state = "sting_null" //This must be equal to the icon state for `/atom/movable/screen/ling/sting` /datum/action/changeling/sting/Trigger(mob/clicker, trigger_flags) var/mob/user = owner @@ -21,16 +22,20 @@ var/datum/antagonist/changeling/changeling = IS_CHANGELING(user) changeling.chosen_sting = src - changeling.lingstingdisplay.icon_state = button_icon_state - changeling.lingstingdisplay.SetInvisibility(0, id=type) + var/atom/movable/screen/ling/sting/sting = user.hud_used?.screen_objects[HUD_CHANGELING_STING] + if (sting) + sting.icon_state = button_icon_state + sting.SetInvisibility(0, id=type) /datum/action/changeling/sting/proc/unset_sting(mob/user) to_chat(user, span_warning("We retract our sting, we can't sting anyone for now.")) var/datum/antagonist/changeling/changeling = IS_CHANGELING(user) changeling.chosen_sting = null - changeling.lingstingdisplay.icon_state = null - changeling.lingstingdisplay.RemoveInvisibility(type) + var/atom/movable/screen/ling/sting/sting = user.hud_used?.screen_objects[HUD_CHANGELING_STING] + if (sting) + sting.icon_state = null + sting.RemoveInvisibility(type) /mob/living/carbon/proc/unset_sting() if(mind) @@ -71,7 +76,7 @@ For complex humanoids, the transformation is temporarily, but the duration is paused while the victim is dead or in stasis. \ For more simple humanoids, such as monkeys, the transformation is permanent. \ Does not provide a warning to others. Mutations will not be transferred." - button_icon_state = "sting_transform" + button_icon_state = "transformation_sting" chemical_cost = 33 // Low enough that you can sting only two people in quick succession dna_cost = 2 /// A reference to our active profile, which we grab DNA from diff --git a/code/modules/antagonists/cult/datums/cult_team.dm b/code/modules/antagonists/cult/datums/cult_team.dm index 130683a9046..939938f621c 100644 --- a/code/modules/antagonists/cult/datums/cult_team.dm +++ b/code/modules/antagonists/cult/datums/cult_team.dm @@ -169,7 +169,8 @@ SEND_SOUND(cultist.current, sound(SFX_HALLUCINATION_OVER_HERE, 0, 1, 75)) cultist.current.client.images += blood_target_image if (cultist.current.hud_used) - new /atom/movable/screen/navigate_arrow(null, cultist.current.hud_used, get_turf(new_target), COLOR_CULT_RED) + var/atom/movable/screen/navigate_arrow/arrow = cultist.current.hud_used.add_screen_object(/atom/movable/screen/navigate_arrow, HUD_CULTIST_ARROW, HUD_GROUP_INFO, update_screen = TRUE) + arrow.start_effect(get_turf(new_target), COLOR_CULT_RED) if(duration != INFINITY) blood_target_reset_timer = addtimer(CALLBACK(src, PROC_REF(unset_blood_target)), duration, TIMER_STOPPABLE) diff --git a/code/modules/antagonists/heretic/heretic_living_heart.dm b/code/modules/antagonists/heretic/heretic_living_heart.dm index f8f18a8188e..78256b12a63 100644 --- a/code/modules/antagonists/heretic/heretic_living_heart.dm +++ b/code/modules/antagonists/heretic/heretic_living_heart.dm @@ -249,7 +249,8 @@ arrow_color = COLOR_RED if(owner.hud_used) - new /atom/movable/screen/navigate_arrow(null, owner.hud_used, their_turf, arrow_color) + var/atom/movable/screen/navigate_arrow/arrow = owner.hud_used.add_screen_object(/atom/movable/screen/navigate_arrow, HUD_HERETIC_ARROW, HUD_GROUP_INFO, update_screen = TRUE) + arrow.start_effect(their_turf, arrow_color) if(ismob(tracked_thing)) var/mob/tracked_mob = tracked_thing @@ -265,25 +266,21 @@ pixel_x = -32 pixel_y = -32 mouse_opacity = MOUSE_OPACITY_TRANSPARENT + screen_loc = around_player -/atom/movable/screen/navigate_arrow/Initialize(mapload, datum/hud/hud_owner, turf/tracked_turf, arrow_color) - . = ..() +/atom/movable/screen/navigate_arrow/proc/start_effect(turf/tracked_turf, arrow_color) var/mob/owner = get_mob() if (owner) animate(src, transform = matrix(get_angle(owner, tracked_turf), MATRIX_ROTATE), 0.2 SECONDS) - screen_loc = around_player color = arrow_color - if (hud) - hud.infodisplay += src - hud.show_hud(hud.hud_version) addtimer(CALLBACK(src, PROC_REF(end_effect)), 1.6 SECONDS) +/atom/movable/screen/navigate_arrow/Destroy() + var/datum/hud/our_hud = hud + . = ..() + if (!QDELETED(our_hud)) + INVOKE_ASYNC(our_hud, TYPE_PROC_REF(/datum/hud, show_hud), our_hud.hud_version) + /atom/movable/screen/navigate_arrow/proc/end_effect() icon_state = "navigate_arrow_disappear" - addtimer(CALLBACK(src, PROC_REF(null_arrow)), 0.4 SECONDS) - -/atom/movable/screen/navigate_arrow/proc/null_arrow() - if (hud) - hud.infodisplay -= src - hud.show_hud(hud.hud_version) - qdel(src) + QDEL_IN(src, 0.4 SECONDS) diff --git a/code/modules/antagonists/heretic/items/heretic_armor.dm b/code/modules/antagonists/heretic/items/heretic_armor.dm index 8e496353fae..20cdbed7a9a 100644 --- a/code/modules/antagonists/heretic/items/heretic_armor.dm +++ b/code/modules/antagonists/heretic/items/heretic_armor.dm @@ -533,8 +533,6 @@ TRAIT_PACIFISM, TRAIT_NOHUNGER ) - /// Hud that gets shown to the wearer, gives a rough estimate of their current brain damage - var/atom/movable/screen/moon_health/health_hud /// Boolean if you are brain dead so the sound doesn't spam during the delay var/braindead = FALSE //---- Messages that get sent when someone wearing the moon robes is attacked @@ -624,8 +622,7 @@ if(our_brain) REMOVE_TRAIT(our_brain, TRAIT_BRAIN_DAMAGE_NODEATH, REF(src)) braindead = FALSE - if(health_hud in user.hud_used.infodisplay) - on_hud_remove(user) + on_hud_remove(user) /obj/item/clothing/suit/hooded/cultrobes/eldritch/moon/proc/on_apply_modifiers(mob/living/user, damage_mods, damage, damagetype, def_zone, sharpness, attack_direction, attacking_item) SIGNAL_HANDLER @@ -655,35 +652,30 @@ /obj/item/clothing/suit/hooded/cultrobes/eldritch/moon/proc/on_hud_created(mob/living/carbon/human/wearer) SIGNAL_HANDLER var/datum/hud/original_hud = wearer.hud_used - // Remove the old health elements - var/list/to_remove = list(/atom/movable/screen/stamina, /atom/movable/screen/healths, /atom/movable/screen/healthdoll/human) - for(var/removing in original_hud.infodisplay) - if(is_type_in_list(removing, to_remove)) - original_hud.infodisplay -= removing - QDEL_NULL(removing) + + for(var/removing in list(HUD_MOB_STAMINA, HUD_MOB_HEALTH, HUD_MOB_HEALTHDOLL)) + var/atom/movable/screen/to_remove = original_hud.screen_objects[removing] + if (to_remove) + to_remove.SetInvisibility(INVISIBILITY_ABSTRACT, type) wearer.mob_mood.unmodify_hud() // Add the moon health hud element - health_hud = new(null, original_hud) - original_hud.infodisplay += health_hud - original_hud.show_hud(original_hud.hud_version) + original_hud.add_screen_object(/atom/movable/screen/moon_health, HUD_HERETIC_MOON_HEALTH, HUD_GROUP_INFO, update_screen = TRUE) UnregisterSignal(wearer, COMSIG_MOB_HUD_CREATED) signal_registered -= COMSIG_MOB_HUD_CREATED /// Removes the HUD element from the wearer /obj/item/clothing/suit/hooded/cultrobes/eldritch/moon/proc/on_hud_remove(mob/living/carbon/human/wearer) var/datum/hud/original_hud = wearer.hud_used - original_hud.infodisplay -= health_hud - QDEL_NULL(health_hud) + QDEL_NULL(original_hud.screen_objects[HUD_HERETIC_MOON_HEALTH]) // Restore the old health elements - var/atom/movable/screen/stamina/stamina_hud = new(null, original_hud) - var/atom/movable/screen/healths/old_health_hud = new(null, original_hud) - var/atom/movable/screen/healthdoll/human/health_doll_hud = new(null, original_hud) - original_hud.infodisplay += stamina_hud - original_hud.infodisplay += old_health_hud - original_hud.infodisplay += health_doll_hud + for(var/restoring in list(HUD_MOB_STAMINA, HUD_MOB_HEALTH, HUD_MOB_HEALTHDOLL)) + var/atom/movable/screen/to_restore = original_hud.screen_objects[restoring] + if (to_restore) + to_restore.RemoveInvisibility(type) + + // Updates HUD on its own wearer.mob_mood.modify_hud() - original_hud.show_hud(original_hud.hud_version) /obj/item/clothing/suit/hooded/cultrobes/eldritch/moon/can_mob_unequip(mob/user) if(!ishuman(user)) diff --git a/code/modules/antagonists/wizard/equipment/spellbook_entries/perks.dm b/code/modules/antagonists/wizard/equipment/spellbook_entries/perks.dm index 087f9b6a16b..d676c284daa 100644 --- a/code/modules/antagonists/wizard/equipment/spellbook_entries/perks.dm +++ b/code/modules/antagonists/wizard/equipment/spellbook_entries/perks.dm @@ -7,44 +7,28 @@ requires_wizard_garb = FALSE /// Icon that will be shown on wizard hud when purchasing a perk. var/hud_icon - /// Type path to perks hud. - var/atom/movable/screen/perk/hud_to_show = /atom/movable/screen/perk /datum/spellbook_entry/perks/buy_spell(mob/living/carbon/human/user, obj/item/spellbook/book, log_buy) var/datum/antagonist/wizard/wizard_datum = user.mind.has_antag_datum(/datum/antagonist/wizard) if(wizard_datum) wizard_datum.perks += src - create_hud_icon(user, wizard_datum) + RegisterSignal(user, COMSIG_MOB_HUD_CREATED, PROC_REF(on_hud_created)) + if (user.hud_used) + on_hud_created() to_chat(user, span_notice("You got a new perk: [src.name].")) log_purchase(user.key) return TRUE -/datum/spellbook_entry/perks/proc/create_compact_button(mob/living/carbon/human/user, datum/antagonist/wizard/wizard_datum) - var/datum/hud/user_hud = user.hud_used - wizard_datum.compact_button = new /atom/movable/screen/perk/more(null, user_hud) - wizard_datum.compact_button.screen_loc = ui_perk_position(0) - user_hud.infodisplay += wizard_datum.compact_button - user_hud.show_hud(user_hud.hud_version) - -/datum/spellbook_entry/perks/proc/create_hud_icon(mob/living/carbon/human/user, datum/antagonist/wizard/wizard_datum) - if(user.hud_used) - var/datum/hud/user_hud = user.hud_used - if(isnull(wizard_datum.compact_button)) - create_compact_button(user, wizard_datum) - hud_to_show = new hud_to_show(null, user_hud) - hud_to_show.name = name - hud_to_show.icon_state = hud_icon - hud_to_show.screen_loc = ui_perk_position(wizard_datum.perks.len) - user_hud.infodisplay += hud_to_show - user_hud.show_hud(user_hud.hud_version) - wizard_datum.compact_button.perks_on_hud += hud_to_show - else - RegisterSignal(user, COMSIG_MOB_HUD_CREATED, wizard_datum, PROC_REF(on_hud_created)) - /datum/spellbook_entry/perks/proc/on_hud_created(mob/living/carbon/human/user, datum/antagonist/wizard/wizard_datum) SIGNAL_HANDLER - create_hud_icon(user, wizard_datum) + var/datum/hud/user_hud = user.hud_used + if(!user_hud.screen_objects[HUD_WIZARD_COMPACT_PERKS]) + user_hud.add_screen_object(/atom/movable/screen/perk/more, HUD_WIZARD_COMPACT_PERKS, HUD_GROUP_INFO, ui_loc = ui_perk_position(0), update_screen = TRUE) + + var/atom/movable/screen/perk/perk = user_hud.add_screen_object(/atom/movable/screen/perk, HUD_WIZARD_PERK(length(wizard_datum.perks)), HUD_GROUP_INFO, ui_loc = ui_perk_position(length(wizard_datum.perks)), update_screen = TRUE) + perk.name = name + perk.icon_state = hud_icon /datum/spellbook_entry/perks/fourhands name = "Four Hands" diff --git a/code/modules/antagonists/wizard/wizard.dm b/code/modules/antagonists/wizard/wizard.dm index ce38b05c426..d76d90a35c8 100644 --- a/code/modules/antagonists/wizard/wizard.dm +++ b/code/modules/antagonists/wizard/wizard.dm @@ -28,8 +28,6 @@ GLOBAL_LIST_EMPTY(wizard_spellbook_purchases_by_key) var/datum/action/cooldown/grand_ritual/ritual /// Perks that wizard learn var/list/perks = list() - /// Button that hide perks hud. - var/atom/movable/screen/perk/more/compact_button /datum/antagonist/wizard_minion name = "Wizard Minion" diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm index dd280d120f5..af6789d02f4 100644 --- a/code/modules/client/preferences.dm +++ b/code/modules/client/preferences.dm @@ -295,7 +295,7 @@ GLOBAL_LIST_EMPTY(preferences_datums) return TRUE /datum/preferences/proc/create_character_preview_view(mob/user) - character_preview_view = new(null, src) + character_preview_view = new(null, null, src) character_preview_view.generate_view("character_preview_[REF(character_preview_view)]") character_preview_view.update_body() @@ -348,7 +348,7 @@ GLOBAL_LIST_EMPTY(preferences_datums) /// Whether we show current job clothes or nude/loadout only var/show_job_clothes = TRUE -/atom/movable/screen/map_view/char_preview/Initialize(mapload, datum/preferences/preferences) +/atom/movable/screen/map_view/char_preview/Initialize(mapload, datum/hud/hud_owner, datum/preferences/preferences) . = ..() src.preferences = preferences diff --git a/code/modules/clothing/spacesuits/_spacesuits.dm b/code/modules/clothing/spacesuits/_spacesuits.dm index d5283c7c20c..f4535059a05 100644 --- a/code/modules/clothing/spacesuits/_spacesuits.dm +++ b/code/modules/clothing/spacesuits/_spacesuits.dm @@ -123,7 +123,9 @@ STOP_PROCESSING(SSobj, src) var/mob/living/carbon/human/human_user = user if(istype(human_user) && human_user.hud_used) - human_user.hud_used.spacesuit_hud.update_spacesuit_hud_icon(SPACESUIT_NO_ICON) + var/atom/movable/screen/spacesuit/spacesuit_hud = human_user.hud_used.screen_objects[HUD_MOB_SPACESUIT] + if (spacesuit_hud) + spacesuit_hud.update_spacesuit_hud_icon(SPACESUIT_NO_ICON) // Space Suit temperature regulation and power usage /obj/item/clothing/suit/space/process(seconds_per_tick) @@ -159,7 +161,9 @@ QDEL_NULL(cell) var/mob/living/carbon/human/human = src.loc if(istype(human) && human.hud_used) - human.hud_used.spacesuit_hud.update_spacesuit_hud_icon(SPACESUIT_NO_ICON) + var/atom/movable/screen/spacesuit/spacesuit_hud = human.hud_used.screen_objects[HUD_MOB_SPACESUIT] + if (spacesuit_hud) + spacesuit_hud.update_spacesuit_hud_icon(SPACESUIT_NO_ICON) STOP_PROCESSING(SSobj, src) return ..() @@ -306,8 +310,12 @@ if(!show_hud || human.wear_suit != src || isnull(human.hud_used)) return + var/atom/movable/screen/spacesuit/spacesuit_hud = human.hud_used.screen_objects[HUD_MOB_SPACESUIT] + if(!spacesuit_hud) + return + if(!cell) - human.hud_used.spacesuit_hud.update_spacesuit_hud_icon(SPACESUIT_CELL_MISSING, 0, thermal_on) + spacesuit_hud.update_spacesuit_hud_icon(SPACESUIT_CELL_MISSING, 0, thermal_on) return var/cell_percent = cell.percent() @@ -315,17 +323,17 @@ // if there is, whethere the cell's capacity indicates high, medium or low // charge based on it. if(cell.charge < THERMAL_REGULATOR_COST) - human.hud_used.spacesuit_hud.update_spacesuit_hud_icon(SPACESUIT_CELL_EMPTY, cell_percent, thermal_on) + spacesuit_hud.update_spacesuit_hud_icon(SPACESUIT_CELL_EMPTY, cell_percent, thermal_on) return switch(cell_percent) if(0 to 20) - human.hud_used.spacesuit_hud.update_spacesuit_hud_icon(SPACESUIT_CELL_VERY_LOW, cell_percent, thermal_on) + spacesuit_hud.update_spacesuit_hud_icon(SPACESUIT_CELL_VERY_LOW, cell_percent, thermal_on) if(21 to 40) - human.hud_used.spacesuit_hud.update_spacesuit_hud_icon(SPACESUIT_CELL_LOW, cell_percent, thermal_on) + spacesuit_hud.update_spacesuit_hud_icon(SPACESUIT_CELL_LOW, cell_percent, thermal_on) if(41 to 60) - human.hud_used.spacesuit_hud.update_spacesuit_hud_icon(SPACESUIT_CELL_MID, cell_percent, thermal_on) + spacesuit_hud.update_spacesuit_hud_icon(SPACESUIT_CELL_MID, cell_percent, thermal_on) if(61 to 100) - human.hud_used.spacesuit_hud.update_spacesuit_hud_icon(SPACESUIT_CELL_HIGH, cell_percent, thermal_on) + spacesuit_hud.update_spacesuit_hud_icon(SPACESUIT_CELL_HIGH, cell_percent, thermal_on) // zap the cell if we get hit with an emp /obj/item/clothing/suit/space/emp_act(severity) diff --git a/code/modules/engineering/tools/multitool.dm b/code/modules/engineering/tools/multitool.dm deleted file mode 100644 index 47f4857ffc3..00000000000 --- a/code/modules/engineering/tools/multitool.dm +++ /dev/null @@ -1,11 +0,0 @@ -/atom/movable/screen/multitool_arrow - icon = 'icons/effects/96x96.dmi' - icon_state = "multitool_arrow" - pixel_x = -32 - pixel_y = -32 - -/atom/movable/screen/multitool_arrow/Destroy() - if(hud) - hud.infodisplay -= src - INVOKE_ASYNC(hud, TYPE_PROC_REF(/datum/hud, show_hud), hud.hud_version) - return ..() diff --git a/code/modules/escape_menu/escape_menu.dm b/code/modules/escape_menu/escape_menu.dm index 842d70a8c77..0042a6f7332 100644 --- a/code/modules/escape_menu/escape_menu.dm +++ b/code/modules/escape_menu/escape_menu.dm @@ -151,9 +151,6 @@ GLOBAL_LIST_EMPTY(escape_menus) plane = ESCAPE_MENU_PLANE clear_with_screen = FALSE -// The escape menu can be opened before SSatoms -INITIALIZE_IMMEDIATE(/atom/movable/screen/escape_menu) - #undef PAGE_HOME #undef PAGE_LEAVE_BODY #undef PAGE_QUIT_GAME diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm index 80d383faba9..1a8e2a7c00f 100644 --- a/code/modules/mob/dead/observer/observer.dm +++ b/code/modules/mob/dead/observer/observer.dm @@ -644,8 +644,9 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp else remove_data_huds() update_sight() - for(var/atom/movable/screen/ghost/hudbox/hud in hud_used?.static_inventory) - if(hud.relevant_flag & toggled) + for(var/hud_key in hud_used?.screen_objects) + var/atom/movable/screen/ghost/hudbox/hud = hud_used.screen_objects[hud_key] + if(istype(hud) && (hud.relevant_flag & toggled)) hud.update_appearance(UPDATE_ICON_STATE) // This is the ghost's follow verb with an argument diff --git a/code/modules/mob/inventory.dm b/code/modules/mob/inventory.dm index 4c57ced89bb..5fd9172e160 100644 --- a/code/modules/mob/inventory.dm +++ b/code/modules/mob/inventory.dm @@ -675,9 +675,13 @@ dropItemToGround(held_items[i]) held_items.len = amt - if(hud_used) - hud_used.build_hand_slots() - hud_used.healthdoll.update_body_zones() + if(!hud_used) + return + + hud_used.build_hand_slots(update_hud = TRUE) + var/atom/movable/screen/healthdoll/doll = hud_used.screen_objects[HUD_MOB_HEALTHDOLL] + if(doll) + doll.update_body_zones() //GetAllContents that is reasonable and not stupid /mob/living/proc/get_all_gear(equipment_flags = INCLUDE_ACCESSORIES|INCLUDE_PROSTHETICS, recursive = TRUE) diff --git a/code/modules/mob/living/basic/blob_minions/blobbernaut.dm b/code/modules/mob/living/basic/blob_minions/blobbernaut.dm index bbc9c1be16f..703fd0d4d1d 100644 --- a/code/modules/mob/living/basic/blob_minions/blobbernaut.dm +++ b/code/modules/mob/living/basic/blob_minions/blobbernaut.dm @@ -27,8 +27,6 @@ mob_size = MOB_SIZE_LARGE ai_controller = /datum/ai_controller/basic_controller/blobbernaut loot = null - ///The HUD given to blobbernauts, updated by the Blob itself - var/atom/movable/screen/healths/blob/overmind/overmind_hud ///The overlay for veins. var/mutable_appearance/vein_overlay ///The overlay for our eyes @@ -53,11 +51,6 @@ AddComponent(/datum/component/tameable, food_types = food_types, tame_chance = 25, bonus_tame_chance = 15) update_appearance() - -/mob/living/basic/blob_minion/blobbernaut/Destroy() - QDEL_NULL(overmind_hud) - return ..() - /mob/living/basic/blob_minion/blobbernaut/death(gibbed) flick("[icon_state]_death", src) playsound(src, 'sound/mobs/non-humanoids/blobmob/blobbernaut_death.ogg', 100, TRUE) @@ -68,9 +61,7 @@ . = ..() if(!.) return - overmind_hud = new(null, hud_used) - hud_used.infodisplay += overmind_hud - hud_used.show_hud(hud_used.hud_version) + hud_used.add_screen_object(/atom/movable/screen/healths/blob/overmind, HUD_BLOBBERNAUT_OVERMIND, HUD_GROUP_INFO, update_screen = TRUE) /mob/living/basic/blob_minion/blobbernaut/on_strain_updated(mob/eye/blob/overmind, datum/blobstrain/new_strain) . = ..() diff --git a/code/modules/mob/living/basic/space_fauna/revenant/_revenant.dm b/code/modules/mob/living/basic/space_fauna/revenant/_revenant.dm index 436f8e27c89..ea32e7e5d6d 100644 --- a/code/modules/mob/living/basic/space_fauna/revenant/_revenant.dm +++ b/code/modules/mob/living/basic/space_fauna/revenant/_revenant.dm @@ -182,7 +182,7 @@ essencecolor = "#9A5ACB" //oh boy you've got a lot of essence else if(essence <= 0) essencecolor = "#1D2953" //oh jeez you're dying - hud_used.healths.maptext = MAPTEXT("
[essence]E
") + hud_used.screen_objects[HUD_MOB_HEALTH]?.maptext = MAPTEXT("
[essence]E
") /mob/living/basic/revenant/say( message, diff --git a/code/modules/mob/living/carbon/alien/adult/alien_powers.dm b/code/modules/mob/living/carbon/alien/adult/alien_powers.dm index 928b5e16bdd..5633d54fb53 100644 --- a/code/modules/mob/living/carbon/alien/adult/alien_powers.dm +++ b/code/modules/mob/living/carbon/alien/adult/alien_powers.dm @@ -390,12 +390,7 @@ Doesn't work on other aliens/AI.*/ var/obj/item/organ/alien/plasmavessel/vessel = get_organ_by_type(/obj/item/organ/alien/plasmavessel) if(!vessel) return FALSE - vessel.stored_plasma = max(vessel.stored_plasma + amount,0) - vessel.stored_plasma = min(vessel.stored_plasma, vessel.max_plasma) //upper limit of max_plasma, lower limit of 0 + vessel.adjust_plasma(amount) for(var/datum/action/cooldown/alien/ability in actions) ability.build_all_button_icons() return TRUE - -/mob/living/carbon/alien/adjustPlasma(amount) - . = ..() - updatePlasmaDisplay() diff --git a/code/modules/mob/living/carbon/alien/adult/caste/hunter.dm b/code/modules/mob/living/carbon/alien/adult/caste/hunter.dm index c056f663849..995235d5fa2 100644 --- a/code/modules/mob/living/carbon/alien/adult/caste/hunter.dm +++ b/code/modules/mob/living/carbon/alien/adult/caste/hunter.dm @@ -18,7 +18,6 @@ ORGAN_SLOT_EXTERNAL_TAIL = /obj/item/organ/tail/xeno, ) - var/atom/movable/screen/leap_icon = null ///How fast does our pounce move us? var/pounce_speed = 2 @@ -26,7 +25,8 @@ /mob/living/carbon/alien/adult/hunter/proc/toggle_leap(message = 1) leap_on_click = !leap_on_click - leap_icon.icon_state = "leap_[leap_on_click ? "on":"off"]" + var/atom/movable/screen/leap_icon = hud_used?.screen_objects[HUD_ALIEN_HUNTER_LEAP] + leap_icon?.icon_state = "leap_[leap_on_click ? "on":"off"]" update_icons() if(message) to_chat(src, span_noticealien("You will now [leap_on_click ? "leap at":"slash at"] enemies!")) diff --git a/code/modules/mob/living/carbon/alien/organs.dm b/code/modules/mob/living/carbon/alien/organs.dm index f5705c88494..ebbacdf2c02 100644 --- a/code/modules/mob/living/carbon/alien/organs.dm +++ b/code/modules/mob/living/carbon/alien/organs.dm @@ -56,38 +56,55 @@ //Instantly healing to max health in a single tick would be silly. If it takes 8 seconds to fire, then something's fucked. var/delta_time_capped = min(delta_time, 8) //If there are alien weeds on the ground then heal if needed or give some plasma - if(locate(/obj/structure/alien/weeds) in owner.loc) - if(owner.health >= owner.maxHealth) - owner.adjustPlasma(plasma_rate * delta_time) - else - var/heal_amt = heal_rate - if(!isalien(owner)) - heal_amt *= 0.2 - owner.adjustPlasma(0.5 * plasma_rate * delta_time_capped) - owner.adjust_brute_loss(-heal_amt * delta_time_capped) - owner.adjust_fire_loss(-heal_amt * delta_time_capped) - owner.adjust_oxy_loss(-heal_amt * delta_time_capped) - else + if(!(locate(/obj/structure/alien/weeds) in owner.loc)) owner.adjustPlasma(0.1 * plasma_rate * delta_time) + return + + if(owner.health >= owner.maxHealth) + owner.adjustPlasma(plasma_rate * delta_time) + return + + var/heal_amt = heal_rate + if(!isalien(owner)) + heal_amt *= 0.2 + owner.adjustPlasma(0.5 * plasma_rate * delta_time_capped) + owner.adjust_brute_loss(-heal_amt * delta_time_capped) + owner.adjust_fire_loss(-heal_amt * delta_time_capped) + owner.adjust_oxy_loss(-heal_amt * delta_time_capped) + +/obj/item/organ/alien/plasmavessel/proc/adjust_plasma(amount) + stored_plasma = clamp(stored_plasma + amount, 0, max_plasma) + update_plasma_display() + +/obj/item/organ/alien/plasmavessel/proc/on_hud_created(mob/source) + SIGNAL_HANDLER + + if (!owner.hud_used.screen_objects[HUD_ALIEN_PLASMA_DISPLAY]) + owner.hud_used.add_screen_object(/atom/movable/screen/alien/plasma_display, HUD_ALIEN_PLASMA_DISPLAY, HUD_GROUP_INFO, ui_loc = istype(owner.hud_used, /datum/hud/alien) ? null : ui_alienplasmadisplay_human, update_screen = TRUE) + update_plasma_display() /obj/item/organ/alien/plasmavessel/on_mob_insert(mob/living/carbon/organ_owner) . = ..() - if(isalien(organ_owner)) - var/mob/living/carbon/alien/target_alien = organ_owner - target_alien.updatePlasmaDisplay() RegisterSignal(organ_owner, COMSIG_MOB_GET_STATUS_TAB_ITEMS, PROC_REF(get_status_tab_item)) + RegisterSignal(organ_owner, COMSIG_MOB_HUD_CREATED, PROC_REF(on_hud_created)) + if (organ_owner.hud_used) + on_hud_created() /obj/item/organ/alien/plasmavessel/on_mob_remove(mob/living/carbon/organ_owner) . = ..() - if(isalien(organ_owner)) - var/mob/living/carbon/alien/organ_owner_alien = organ_owner - organ_owner_alien.updatePlasmaDisplay() UnregisterSignal(organ_owner, COMSIG_MOB_GET_STATUS_TAB_ITEMS) + UnregisterSignal(organ_owner, COMSIG_MOB_HUD_CREATED) + organ_owner.hud_used?.remove_screen_object(HUD_ALIEN_PLASMA_DISPLAY) /obj/item/organ/alien/plasmavessel/proc/get_status_tab_item(mob/living/carbon/source, list/items) SIGNAL_HANDLER items += "Plasma Stored: [stored_plasma]/[max_plasma]" +/obj/item/organ/alien/plasmavessel/proc/update_plasma_display() + owner.hud_used?.screen_objects[HUD_ALIEN_PLASMA_DISPLAY]?.maptext = MAPTEXT( \ + "
[round(owner.getPlasma())]
" \ + ) + #define QUEEN_DEATH_DEBUFF_DURATION 2400 /obj/item/organ/alien/hivenode diff --git a/code/modules/mob/living/carbon/alien/screen.dm b/code/modules/mob/living/carbon/alien/screen.dm index ca75bb2d789..1526f78a320 100644 --- a/code/modules/mob/living/carbon/alien/screen.dm +++ b/code/modules/mob/living/carbon/alien/screen.dm @@ -1,33 +1,30 @@ -/mob/living/carbon/alien/proc/updatePlasmaDisplay() - if(hud_used) //clientless aliens - hud_used.alien_plasma_display.maptext = MAPTEXT("
[round(getPlasma())]
") - -/mob/living/carbon/alien/larva/updatePlasmaDisplay() - return - /mob/living/carbon/alien/proc/findQueen() - if(hud_used) - hud_used.alien_queen_finder.cut_overlays() - var/mob/queen = get_alien_type(/mob/living/carbon/alien/adult/royal/queen) - if(!queen) - return - var/turf/Q = get_turf(queen) - var/turf/A = get_turf(src) - if(Q.z != A.z) //The queen is on a different Z level, we cannot sense that far. - return - var/Qdir = get_dir(src, Q) - var/Qdist = get_dist(src, Q) - var/finder_icon = "finder_center" //Overlay showed when adjacent to or on top of the queen! - switch(Qdist) - if(2 to 7) - finder_icon = "finder_near" - if(8 to 20) - finder_icon = "finder_med" - if(21 to INFINITY) - finder_icon = "finder_far" - var/image/finder_eye = image('icons/hud/screen_alien.dmi', finder_icon, dir = Qdir) - hud_used.alien_queen_finder.add_overlay(finder_eye) + if(!hud_used) + return + var/atom/movable/screen/alien/alien_queen_finder/finder = hud_used.screen_objects[HUD_ALIEN_QUEEN_FINDER] + if (!finder) + return + finder.cut_overlays() + var/mob/queen = get_alien_type(/mob/living/carbon/alien/adult/royal/queen) + if(!queen) + return + var/turf/Q = get_turf(queen) + var/turf/A = get_turf(src) + if(Q.z != A.z) //The queen is on a different Z level, we cannot sense that far. + return + var/Qdir = get_dir(src, Q) + var/Qdist = get_dist(src, Q) + var/finder_icon = "finder_center" //Overlay showed when adjacent to or on top of the queen! + switch(Qdist) + if(2 to 7) + finder_icon = "finder_near" + if(8 to 20) + finder_icon = "finder_med" + if(21 to INFINITY) + finder_icon = "finder_far" + var/image/finder_eye = image('icons/hud/screen_alien.dmi', finder_icon, dir = Qdir) + finder.add_overlay(finder_eye) /mob/living/carbon/alien/adult/royal/queen/findQueen() return //Queen already knows where she is. Hopefully. diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index 514e7035cba..924227483a9 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -635,11 +635,16 @@ clear_fullscreen("brute") /mob/living/carbon/update_health_hud(shown_health_amount) - if(!client || !hud_used?.healths) + if(!client || !hud_used) + return + + var/atom/movable/screen/healths/health_hud = hud_used.screen_objects[HUD_MOB_HEALTH] + + if (!health_hud) return if(stat == DEAD) - hud_used.healths.icon_state = "health7" + health_hud.icon_state = "health7" return if(SEND_SIGNAL(src, COMSIG_CARBON_UPDATING_HEALTH_HUD, shown_health_amount) & COMPONENT_OVERRIDE_HEALTH_HUD) @@ -649,25 +654,11 @@ shown_health_amount = health if(shown_health_amount >= maxHealth) - hud_used.healths.icon_state = "health0" - - else if(shown_health_amount > maxHealth * 0.8) - hud_used.healths.icon_state = "health1" - - else if(shown_health_amount > maxHealth * 0.6) - hud_used.healths.icon_state = "health2" - - else if(shown_health_amount > maxHealth * 0.4) - hud_used.healths.icon_state = "health3" - - else if(shown_health_amount > maxHealth*0.2) - hud_used.healths.icon_state = "health4" - - else if(shown_health_amount > 0) - hud_used.healths.icon_state = "health5" - + health_hud.icon_state = "health0" + else if(shown_health_amount > 0 && maxHealth > 0) + health_hud.icon_state = "health[6 - ceil(shown_health_amount / (maxHealth * 0.2))]" else - hud_used.healths.icon_state = "health6" + health_hud.icon_state = "health6" /mob/living/carbon/set_health(new_value) . = ..() diff --git a/code/modules/mob/living/carbon/carbon_update_icons.dm b/code/modules/mob/living/carbon/carbon_update_icons.dm index b759c290efe..fb1ceda9558 100644 --- a/code/modules/mob/living/carbon/carbon_update_icons.dm +++ b/code/modules/mob/living/carbon/carbon_update_icons.dm @@ -417,11 +417,11 @@ //update whether handcuffs appears on our hud. /mob/living/carbon/proc/update_hud_handcuffed() - if(hud_used) - for(var/hand in hud_used.hand_slots) - var/atom/movable/screen/inventory/hand/H = hud_used.hand_slots[hand] - if(H) - H.update_appearance() + if(!hud_used) + return + + for(var/atom/movable/screen/inventory/hand/hand in hud_used.hand_slots) + hand.update_appearance() //update whether our head item appears on our hud. /mob/living/carbon/proc/update_hud_head(obj/item/I) diff --git a/code/modules/mob/living/carbon/human/_species.dm b/code/modules/mob/living/carbon/human/_species.dm index 75dbe2f24e9..72f9968d250 100644 --- a/code/modules/mob/living/carbon/human/_species.dm +++ b/code/modules/mob/living/carbon/human/_species.dm @@ -381,7 +381,9 @@ GLOBAL_LIST_EMPTY(features_by_species) human_who_gained_species.butcher_results = knife_butcher_results?.Copy() //update body zones to match what they are supposed to have - human_who_gained_species.hud_used?.healthdoll.update_body_zones() + var/atom/movable/screen/healthdoll/doll = human_who_gained_species.hud_used?.screen_objects[HUD_MOB_HEALTHDOLL] + if (doll) + doll.update_body_zones() if(old_species.type != type) replace_body(human_who_gained_species, src) @@ -433,7 +435,7 @@ GLOBAL_LIST_EMPTY(features_by_species) human_who_gained_species.living_flags &= ~STOP_OVERLAY_UPDATE_BODY_PARTS //we don't allow it to update during species transition, so update it now - human_who_gained_species.hud_used?.healthdoll.update_appearance() + human_who_gained_species.hud_used?.screen_objects[HUD_MOB_HEALTHDOLL]?.update_appearance() /** * Proc called when a carbon is no longer this species. diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index bfac199095d..9d78211d91f 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -690,7 +690,7 @@ . = ..() // Handles changing limb colors and stuff if(!(living_flags & STOP_OVERLAY_UPDATE_BODY_PARTS)) - hud_used.healthdoll?.update_appearance() + hud_used.screen_objects[HUD_MOB_HEALTHDOLL]?.update_appearance() /mob/living/carbon/human/fully_heal(heal_flags = HEAL_ALL) if(heal_flags & HEAL_NEGATIVE_MUTATIONS) diff --git a/code/modules/mob/living/carbon/human/species_types/vampire.dm b/code/modules/mob/living/carbon/human/species_types/vampire.dm index 0539776acbe..6013c6d2b92 100644 --- a/code/modules/mob/living/carbon/human/species_types/vampire.dm +++ b/code/modules/mob/living/carbon/human/species_types/vampire.dm @@ -21,8 +21,6 @@ mutanttongue = /obj/item/organ/tongue/vampire ///some starter text sent to the vampire initially, because vampires have shit to do to stay alive var/info_text = "You are a Vampire. You will slowly but constantly lose blood if outside of a coffin. If inside a coffin, you will slowly heal. You may gain more blood by grabbing a live victim and using your drain ability." - /// UI displaying how much blood we have - var/atom/movable/screen/blood_level/blood_display /datum/species/human/vampire/check_roundstart_eligible() if(check_holidays(HALLOWEEN)) @@ -35,17 +33,14 @@ new_vampire.skin_tone = "albino" new_vampire.update_body(0) RegisterSignal(new_vampire, COMSIG_ATOM_ATTACKBY, PROC_REF(on_attackby)) + RegisterSignal(new_vampire, COMSIG_MOB_HUD_CREATED, PROC_REF(on_hud_created)) if(new_vampire.hud_used) on_hud_created(new_vampire) - else - RegisterSignal(new_vampire, COMSIG_MOB_HUD_CREATED, PROC_REF(on_hud_created)) /datum/species/human/vampire/on_species_loss(mob/living/carbon/human/old_vampire, datum/species/new_species, pref_load) . = ..() UnregisterSignal(old_vampire, COMSIG_ATOM_ATTACKBY) - if(blood_display) - old_vampire.hud_used.infodisplay -= blood_display - QDEL_NULL(blood_display) + old_vampire.hud_used?.remove_screen_object(HUD_MOB_BLOOD_LEVEL) /datum/species/human/vampire/spec_life(mob/living/carbon/human/vampire, seconds_per_tick) . = ..() @@ -72,10 +67,7 @@ ///Gives the blood HUD to the vampire so they always know how much blood they have. /datum/species/human/vampire/proc/on_hud_created(mob/source) SIGNAL_HANDLER - var/datum/hud/blood_hud = source.hud_used - blood_display = new(null, blood_hud) - blood_hud.infodisplay += blood_display - blood_hud.show_hud(blood_hud.hud_version) + source.hud_used.add_screen_object(/atom/movable/screen/blood_level, HUD_MOB_BLOOD_LEVEL, HUD_GROUP_INFO, update_screen = TRUE) /datum/species/human/vampire/proc/on_attackby(mob/living/source, obj/item/attacking_item, mob/living/attacker, list/modifiers, list/attack_modifiers) SIGNAL_HANDLER diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index 9d6ca3159d6..a0a1ae072cc 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -761,15 +761,17 @@ /mob/living/update_rest_hud_icon() . = ..() - if(!.) + if(!. || !hud_used) return FALSE - if(!hud_used.sleep_icon || HAS_TRAIT(src, TRAIT_SLEEPIMMUNE)) + + var/atom/movable/screen/sleep/sleep_icon = hud_used.screen_objects[HUD_MOB_SLEEP] + if(!sleep_icon || HAS_TRAIT(src, TRAIT_SLEEPIMMUNE)) return TRUE + if(resting || HAS_TRAIT(src, TRAIT_FLOORED)) - hud_used.static_inventory |= hud_used.sleep_icon + sleep_icon.RemoveInvisibility(INVISIBILITY_SOURCE_SLEEP_HUD_BUTTON) else - hud_used.static_inventory -= hud_used.sleep_icon - hud_used.show_hud(hud_used.hud_version) + sleep_icon.SetInvisibility(INVISIBILITY_ABSTRACT, INVISIBILITY_SOURCE_SLEEP_HUD_BUTTON) return TRUE //Recursive function to find everything a mob is holding. Really shitty proc tbh. @@ -833,8 +835,8 @@ /mob/living/update_health_hud() var/severity = 0 var/healthpercent = (health/maxHealth) * 100 - if(hud_used?.healthdoll) //to really put you in the boots of a simplemob - var/atom/movable/screen/healthdoll/living/livingdoll = hud_used.healthdoll + var/atom/movable/screen/healthdoll/living/livingdoll = hud_used?.screen_objects[HUD_MOB_HEALTHDOLL] + if(istype(livingdoll)) //to really put you in the boots of a simplemob switch(healthpercent) if(100 to INFINITY) severity = 0 @@ -859,6 +861,7 @@ mob_mask = icon('icons/hud/screen_gen.dmi', health_doll_icon_state) //swap to something generic if they have no special doll livingdoll.add_filter("mob_shape_mask", 1, alpha_mask_filter(icon = mob_mask)) livingdoll.add_filter("inset_drop_shadow", 2, drop_shadow_filter(size = -1)) + if(severity > 0) overlay_fullscreen("brute", /atom/movable/screen/fullscreen/brute, severity) else @@ -1430,32 +1433,27 @@ update_stamina_hud() /mob/living/update_stamina_hud(shown_stamina_loss) - if(!client || !hud_used?.stamina) + if(!client || !hud_used) + return + + var/atom/movable/screen/stamina/stamina = hud_used.screen_objects[HUD_MOB_STAMINA] + if (!stamina) + return + + if(stat == DEAD) + stamina.icon_state = "stamina_dead" return var/stam_crit_threshold = maxHealth - crit_threshold + if(shown_stamina_loss == null) + shown_stamina_loss = get_stamina_loss() - if(stat == DEAD) - hud_used.stamina.icon_state = "stamina_dead" + if(shown_stamina_loss >= stam_crit_threshold) + stamina.icon_state = "stamina_crit" + else if(shown_stamina_loss > 0 && maxHealth > 0) + stamina.icon_state = "stamina_[6 - ceil(shown_stamina_loss / (maxHealth * 0.2))]" else - - if(shown_stamina_loss == null) - shown_stamina_loss = get_stamina_loss() - - if(shown_stamina_loss >= stam_crit_threshold) - hud_used.stamina.icon_state = "stamina_crit" - else if(shown_stamina_loss > maxHealth*0.8) - hud_used.stamina.icon_state = "stamina_5" - else if(shown_stamina_loss > maxHealth*0.6) - hud_used.stamina.icon_state = "stamina_4" - else if(shown_stamina_loss > maxHealth*0.4) - hud_used.stamina.icon_state = "stamina_3" - else if(shown_stamina_loss > maxHealth*0.2) - hud_used.stamina.icon_state = "stamina_2" - else if(shown_stamina_loss > 0) - hud_used.stamina.icon_state = "stamina_1" - else - hud_used.stamina.icon_state = "stamina_full" + stamina.icon_state = "stamina_full" /mob/living/carbon/alien/update_stamina() return diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm index 68bcf1fee29..701b118ebdc 100644 --- a/code/modules/mob/living/living_defense.dm +++ b/code/modules/mob/living/living_defense.dm @@ -225,8 +225,7 @@ . = combat_mode combat_mode = new_mode SEND_SIGNAL(src, COMSIG_COMBAT_MODE_TOGGLED) - if(hud_used?.action_intent) - hud_used.action_intent.update_appearance() + hud_used?.screen_objects[HUD_MOB_INTENTS]?.update_appearance() if(silent || !client?.prefs.read_preference(/datum/preference/toggle/sound_combatmode)) return if(combat_mode) diff --git a/code/modules/mob/living/living_fov.dm b/code/modules/mob/living/living_fov.dm index a16cf111133..8c6c0833fbf 100644 --- a/code/modules/mob/living/living_fov.dm +++ b/code/modules/mob/living/living_fov.dm @@ -131,3 +131,5 @@ mouse_opacity = MOUSE_OPACITY_TRANSPARENT plane = FIELD_OF_VISION_BLOCKER_PLANE screen_loc = "BOTTOM,LEFT" + hud_key = HUD_MOB_FOV_BLOCKER + hud_group_key = HUD_GROUP_SCREEN_OVERLAYS diff --git a/code/modules/mob/living/living_item_handling.dm b/code/modules/mob/living/living_item_handling.dm index 482e0099491..24b3e2692d1 100644 --- a/code/modules/mob/living/living_item_handling.dm +++ b/code/modules/mob/living/living_item_handling.dm @@ -17,7 +17,7 @@ return throw_mode = THROW_MODE_DISABLED if(hud_used) - hud_used.throw_icon.icon_state = "act_throw" + hud_used.screen_objects[HUD_MOB_THROW]?.icon_state = "act_throw" SEND_SIGNAL(src, COMSIG_LIVING_THROW_MODE_TOGGLE, throw_mode) @@ -26,7 +26,7 @@ return throw_mode = mode if(hud_used) - hud_used.throw_icon.icon_state = "act_throw_on" + hud_used.screen_objects[HUD_MOB_THROW]?.icon_state = "act_throw_on" SEND_SIGNAL(src, COMSIG_LIVING_THROW_MODE_TOGGLE, throw_mode) /mob/proc/throw_item(atom/target) diff --git a/code/modules/mob/living/silicon/death.dm b/code/modules/mob/living/silicon/death.dm index 8aff9b59278..1522555af70 100644 --- a/code/modules/mob/living/silicon/death.dm +++ b/code/modules/mob/living/silicon/death.dm @@ -8,12 +8,10 @@ /mob/living/silicon/set_stat(new_stat) . = ..() - if(. != DEAD) + if(. != DEAD || !hud_used) return // Clean up hud element used for the death sequence - for(var/atom/movable/screen/cyborg_death/deathhud in hud_used?.always_visible_inventory) - hud_used.always_visible_inventory -= deathhud - qdel(deathhud) + hud_used.remove_screen_object(HUD_CYBORG_DEATH) /mob/living/silicon/death(gibbed) diag_hud_set_status() @@ -38,10 +36,8 @@ if(get_oxy_loss() > 100) cause_of_death = "Critically low power." - var/atom/movable/screen/cyborg_death/deathhud = new(null, hud_used, cause_of_death) - hud_used.always_visible_inventory += deathhud - hud_used.show_hud(hud_used.hud_version) - deathhud.run_animation() + var/atom/movable/screen/cyborg_death/deathhud = hud_used.add_screen_object(/atom/movable/screen/cyborg_death, HUD_CYBORG_DEATH, HUD_GROUP_SCREEN_OVERLAYS, update_screen = TRUE) + deathhud.run_animation(cause_of_death) #define WARNING_ROBOT(text) ("" + text + "") #define DANGER_ROBOT(text) ("" + text + "") @@ -88,13 +84,10 @@ WARNING_ROBOT("WARNI-"), ) -/atom/movable/screen/cyborg_death/Initialize(mapload, datum/hud/hud_owner, cause_of_death = "Unidentified kernel error.") - . = ..() - messages.Insert(1, WARNING_ROBOT("WARNING: [cause_of_death]")) - -/atom/movable/screen/cyborg_death/proc/run_animation() +/atom/movable/screen/cyborg_death/proc/run_animation(cause_of_death = "Unidentified kernel error.") set waitfor = FALSE + messages.Insert(1, WARNING_ROBOT("WARNING: [cause_of_death]")) if(prob(1)) messages[length(messages)] = SENTIENT_ROBOT(pick("I don't want to go.", "I don't feel good.", "I don't want to die.")) diff --git a/code/modules/mob/living/silicon/robot/inventory.dm b/code/modules/mob/living/silicon/robot/inventory.dm index d7a320c6e67..30790c176b5 100644 --- a/code/modules/mob/living/silicon/robot/inventory.dm +++ b/code/modules/mob/living/silicon/robot/inventory.dm @@ -77,16 +77,17 @@ . = ..() if(isnull(client) || isnull(hud_used) || hud_used.hud_version == HUD_STYLE_NOHUD) return - var/turf/our_turf = get_turf(src) - for(var/obj/item/held in held_items) + var/turf/our_turf = get_turf(src) + for (var/held_index in 1 to length(held_items)) + var/obj/item/held = held_items[held_index] + if (!held) + continue SET_PLANE(held, ABOVE_HUD_PLANE, our_turf) - if(held_items[BORG_CHOOSE_MODULE_ONE] == held) - held.screen_loc = inv1.screen_loc - else if(held_items[BORG_CHOOSE_MODULE_TWO] == held) - held.screen_loc = inv2.screen_loc - else if(held_items[BORG_CHOOSE_MODULE_THREE] == held) - held.screen_loc = inv3.screen_loc + var/atom/movable/screen/robot/module_slot/slot = hud_used.screen_objects[HUD_KEY_CYBORG_MODULE(held_index)] + if (!slot) //?? + continue + held.screen_loc = slot.screen_loc client.screen |= held /mob/living/silicon/robot/put_in_hand_check(obj/item/item_equipping) @@ -111,7 +112,6 @@ if(disabled_modules & BORG_MODULE_ALL_DISABLED) return FALSE - inv1.icon_state = "[initial(inv1.icon_state)] +b" disabled_modules |= BORG_MODULE_ALL_DISABLED playsound(src, 'sound/machines/warning-buzzer.ogg', 75, TRUE, TRUE) @@ -127,7 +127,6 @@ if(disabled_modules & BORG_MODULE_TWO_DISABLED) return FALSE - inv2.icon_state = "[initial(inv2.icon_state)] +b" disabled_modules |= BORG_MODULE_TWO_DISABLED playsound(src, 'sound/machines/warning-buzzer.ogg', 60, TRUE, TRUE) @@ -138,13 +137,15 @@ if(disabled_modules & BORG_MODULE_THREE_DISABLED) return FALSE - inv3.icon_state = "[initial(inv3.icon_state)] +b" disabled_modules |= BORG_MODULE_THREE_DISABLED playsound(src, 'sound/machines/warning-buzzer.ogg', 50, TRUE, TRUE) audible_message(span_warning("[src] sounds an alarm! \"SYSTEM ERROR: Module [module_num] OFFLINE.\"")) to_chat(src, span_userdanger("SYSTEM ERROR: Module [module_num] OFFLINE.")) + var/atom/movable/screen/robot/module_slot/module = hud_used?.screen_objects[HUD_KEY_CYBORG_MODULE(module_num)] + if(module) + module.icon_state = "[module.base_icon_state] +b" return TRUE /** @@ -169,26 +170,27 @@ if(!(disabled_modules & BORG_MODULE_ALL_DISABLED)) return FALSE - inv1.icon_state = initial(inv1.icon_state) disabled_modules &= ~BORG_MODULE_ALL_DISABLED if(builtInCamera) builtInCamera.camera_enabled = TRUE to_chat(src, span_notice("You hear your built in security camera focus adjust as it comes back online!")) + if(BORG_CHOOSE_MODULE_TWO) if(!(disabled_modules & BORG_MODULE_TWO_DISABLED)) return FALSE - inv2.icon_state = initial(inv2.icon_state) disabled_modules &= ~BORG_MODULE_TWO_DISABLED + if(BORG_CHOOSE_MODULE_THREE) if(!(disabled_modules & BORG_MODULE_THREE_DISABLED)) return FALSE - inv3.icon_state = initial(inv3.icon_state) disabled_modules &= ~BORG_MODULE_THREE_DISABLED to_chat(src, span_notice("ERROR CLEARED: Module [module_num] back online.")) - + var/atom/movable/screen/robot/module_slot/module = hud_used?.screen_objects[HUD_KEY_CYBORG_MODULE(module_num)] + if(module) + module.icon_state = module.base_icon_state return TRUE /** @@ -268,16 +270,9 @@ if(is_invalid_module_number(module_num) || !held_items[module_num]) //If the slot number is invalid, or there's nothing there, we have nothing to equip return FALSE - switch(module_num) - if(BORG_CHOOSE_MODULE_ONE) - if(module_active != held_items[module_num]) - inv1.icon_state = "[initial(inv1.icon_state)] +a" - if(BORG_CHOOSE_MODULE_TWO) - if(module_active != held_items[module_num]) - inv2.icon_state = "[initial(inv2.icon_state)] +a" - if(BORG_CHOOSE_MODULE_THREE) - if(module_active != held_items[module_num]) - inv3.icon_state = "[initial(inv3.icon_state)] +a" + var/atom/movable/screen/robot/module_slot/module = hud_used?.screen_objects[HUD_KEY_CYBORG_MODULE(module_num)] + if(module && module_active != held_items[module_num]) + module.icon_state = "[module.base_icon_state] +a" module_active = held_items[module_num] return TRUE @@ -287,13 +282,9 @@ * * module_num - the slot number being de-selected */ /mob/living/silicon/robot/proc/deselect_module(module_num) - switch(module_num) - if(BORG_CHOOSE_MODULE_ONE) - inv1.icon_state = initial(inv1.icon_state) - if(BORG_CHOOSE_MODULE_TWO) - inv2.icon_state = initial(inv2.icon_state) - if(BORG_CHOOSE_MODULE_THREE) - inv3.icon_state = initial(inv3.icon_state) + var/atom/movable/screen/robot/module_slot/module = hud_used?.screen_objects[HUD_KEY_CYBORG_MODULE(module_num)] + if(module) + module.icon_state = module.base_icon_state module_active = null return TRUE diff --git a/code/modules/mob/living/silicon/robot/life.dm b/code/modules/mob/living/silicon/robot/life.dm index d428c275171..a4da3bd1c80 100644 --- a/code/modules/mob/living/silicon/robot/life.dm +++ b/code/modules/mob/living/silicon/robot/life.dm @@ -37,22 +37,27 @@ /mob/living/silicon/robot/update_health_hud() if(!client || !hud_used) return - if(hud_used.healths) - if(stat != DEAD) - if(health >= maxHealth) - hud_used.healths.icon_state = "health0" - else if(health > maxHealth*0.6) - hud_used.healths.icon_state = "health2" - else if(health > maxHealth*0.2) - hud_used.healths.icon_state = "health3" - else if(health > -maxHealth*0.2) - hud_used.healths.icon_state = "health4" - else if(health > -maxHealth*0.6) - hud_used.healths.icon_state = "health5" - else - hud_used.healths.icon_state = "health6" - else - hud_used.healths.icon_state = "health7" + + var/atom/movable/screen/healths/healths = hud_used.screen_objects[HUD_MOB_HEALTH] + if(!healths) + return + + if(stat == DEAD) + healths.icon_state = "health7" + return + + if(health >= maxHealth) + healths.icon_state = "health0" + else if(health > maxHealth*0.6) + healths.icon_state = "health2" + else if(health > maxHealth*0.2) + healths.icon_state = "health3" + else if(health > -maxHealth*0.2) + healths.icon_state = "health4" + else if(health > -maxHealth*0.6) + healths.icon_state = "health5" + else + healths.icon_state = "health6" /mob/living/silicon/robot/proc/update_cell_hud_icon() if(cell) diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm index b132ce92987..429b66c1a34 100644 --- a/code/modules/mob/living/silicon/robot/robot.dm +++ b/code/modules/mob/living/silicon/robot/robot.dm @@ -20,10 +20,6 @@ RegisterSignal(src, COMSIG_LIGHT_EATER_ACT, PROC_REF(on_light_eater)) RegisterSignal(src, SIGNAL_ADDTRAIT(TRAIT_GOT_DAMPENED), PROC_REF(on_dampen)) - inv1 = new /atom/movable/screen/robot/module1() - inv2 = new /atom/movable/screen/robot/module2() - inv3 = new /atom/movable/screen/robot/module3() - previous_health = health if(ispath(cell)) @@ -131,10 +127,6 @@ QDEL_NULL(model) QDEL_NULL(eye_lights) QDEL_NULL(hat_overlay) - QDEL_NULL(inv1) - QDEL_NULL(inv2) - QDEL_NULL(inv3) - QDEL_NULL(hands) QDEL_NULL(spark_system) QDEL_NULL(alert_control) QDEL_LIST(upgrades) @@ -513,19 +505,21 @@ if(!COOLDOWN_FINISHED(src, disabled_time)) balloon_alert(src, "disrupted!") return FALSE + if(!(update_color && lamp_enabled) && (turn_off || lamp_enabled || update_color || !lamp_functional || stat || low_power_mode)) set_light_on(lamp_functional && stat != DEAD && lamp_doom) //If the lamp isn't broken and borg isn't dead, doomsday borgs cannot disable their light fully. set_light_color(COLOR_RED) //This should only matter for doomsday borgs, as any other time the lamp will be off and the color not seen set_light_range(1) //Again, like above, this only takes effect when the light is forced on by doomsday mode. lamp_enabled = FALSE - lampButton?.update_appearance() + hud_used?.screen_objects[HUD_CYBORG_LAMP]?.update_appearance() update_icons() return + set_light_range(max(MINIMUM_USEFUL_LIGHT_RANGE, lamp_intensity)) set_light_color(lamp_doom ? COLOR_RED : lamp_color) //Red for doomsday killborgs, borg's choice otherwise set_light_on(TRUE) lamp_enabled = TRUE - lampButton?.update_appearance() + hud_used?.screen_objects[HUD_CYBORG_LAMP]?.update_appearance() update_icons() ///Completely deconstructs the borg, dropping the MMI/posibrain, removing applied upgrades and stripping the exoskeleton of all limbs, @@ -762,18 +756,15 @@ /mob/living/silicon/robot/proc/update_module_innate() designation = model.name - if(hands) - hands.icon_state = model.model_select_icon + hud_used?.screen_objects[HUD_CYBORG_HANDS]?.icon_state = model.model_select_icon REMOVE_TRAITS_IN(src, MODEL_TRAIT) if(length(model.model_traits)) add_traits(model.model_traits, MODEL_TRAIT) hat_offset = model.hat_offset - INVOKE_ASYNC(src, PROC_REF(updatename)) - /mob/living/silicon/robot/proc/place_on_head(obj/item/new_hat) if(hat) hat.forceMove(get_turf(src)) diff --git a/code/modules/mob/living/silicon/robot/robot_defines.dm b/code/modules/mob/living/silicon/robot/robot_defines.dm index 2cf30e5a5d9..c4cf75317d9 100644 --- a/code/modules/mob/living/silicon/robot/robot_defines.dm +++ b/code/modules/mob/living/silicon/robot/robot_defines.dm @@ -69,30 +69,15 @@ // Overlay for borg hat var/mutable_appearance/hat_overlay - - // Hud - var/atom/movable/screen/inv1 = null - var/atom/movable/screen/inv2 = null - var/atom/movable/screen/inv3 = null - var/atom/movable/screen/hands = null - - ///Lamp button reference - var/atom/movable/screen/robot/lamp/lampButton - - ///The reference to the built-in tablet that borgs carry. - var/atom/movable/screen/robot/modpc/interfaceButton - var/sight_mode = 0 hud_possible = list(ANTAG_HUD, DIAG_STAT_HUD, DIAG_HUD, DIAG_BATT_HUD, DIAG_TRACK_HUD) - // Modules (tool slots) var/obj/item/module_active = null ///For checking which modules are disabled or not. var/disabled_modules - // Status var/mob/living/silicon/ai/connected_ai = null diff --git a/code/modules/mob/living/simple_animal/hostile/ooze.dm b/code/modules/mob/living/simple_animal/hostile/ooze.dm index aec9457ecae..4bb2858bce1 100644 --- a/code/modules/mob/living/simple_animal/hostile/ooze.dm +++ b/code/modules/mob/living/simple_animal/hostile/ooze.dm @@ -85,7 +85,9 @@ ///Does ooze_nutrition + supplied amount and clamps it within 0 and 500 /mob/living/simple_animal/hostile/ooze/proc/adjust_ooze_nutrition(amount) ooze_nutrition = clamp(ooze_nutrition + amount, 0, 500) - updateNutritionDisplay() + hud_used?.screen_objects[HUD_OOZE_NUTRITION_DISPLAY]?.maptext = MAPTEXT( \ + "
[round(ooze_nutrition)]
" \ + ) ///Tries to transfer the atoms reagents then delete it /mob/living/simple_animal/hostile/ooze/proc/eat_atom(atom/eat_target, silent) @@ -98,12 +100,6 @@ to_chat(src, span_warning("[eat_target] cannot be eaten!")) return FALSE -///Updates the display that shows the mobs nutrition -/mob/living/simple_animal/hostile/ooze/proc/updateNutritionDisplay() - if(hud_used) //clientless oozes - hud_used.alien_plasma_display.maptext = MAPTEXT("
[round(ooze_nutrition)]
") - - ///* Gelatinious Ooze code below *\\\\ diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index 4a8c75c0b11..dfdce3c3292 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -766,13 +766,13 @@ ///Update the pulling hud icon /mob/proc/update_pull_hud_icon() - hud_used?.pull_icon?.update_appearance() + hud_used?.screen_objects[HUD_MOB_PULL]?.update_appearance() ///Update the resting hud icon /mob/proc/update_rest_hud_icon() if(!hud_used) return FALSE - hud_used.rest_icon?.update_appearance() + hud_used.screen_objects[HUD_MOB_REST]?.update_appearance() return TRUE /** @@ -943,10 +943,10 @@ active_hand_index = held_index if(hud_used) var/atom/movable/screen/inventory/hand/held_location - held_location = hud_used.hand_slots["[previous_index]"] + held_location = hud_used.hand_slots[previous_index] if(!isnull(held_location)) held_location.update_appearance() - held_location = hud_used.hand_slots["[held_index]"] + held_location = hud_used.hand_slots[held_index] if(!isnull(held_location)) held_location.update_appearance() return TRUE @@ -1501,7 +1501,9 @@ /// Updates nutrition related effects /mob/living/proc/update_nutrition() mob_mood?.update_nutrition_moodlets() - hud_used?.hunger?.update_hunger_bar() + var/atom/movable/screen/hunger/hunger_bar = hud_used?.screen_objects[HUD_MOB_HUNGER] + if (hunger_bar) + hunger_bar.update_hunger_bar() SEND_SIGNAL(src, COMSIG_LIVING_UPDATE_NUTRITION) /// Apply a proper movespeed modifier based on items we have equipped diff --git a/code/modules/mob/mob_movement.dm b/code/modules/mob/mob_movement.dm index d461d9458cb..f0e07051a14 100644 --- a/code/modules/mob/mob_movement.dm +++ b/code/modules/mob/mob_movement.dm @@ -398,7 +398,7 @@ ///Validate the client's mob has a valid zone selected /client/proc/check_has_body_select() - return mob && mob.hud_used && mob.hud_used.zone_select && istype(mob.hud_used.zone_select, /atom/movable/screen/zone_sel) + return istype(mob?.hud_used?.screen_objects[HUD_MOB_ZONE_SELECTOR], /atom/movable/screen/zone_sel) /** * Hidden verbs to set desired body target zone @@ -423,7 +423,7 @@ else next_in_line = BODY_ZONE_HEAD - var/atom/movable/screen/zone_sel/selector = mob.hud_used.zone_select + var/atom/movable/screen/zone_sel/selector = mob.hud_used.screen_objects[HUD_MOB_ZONE_SELECTOR] selector.set_selected_zone(next_in_line, mob) ///Hidden verb to target the head, unbound by default. @@ -434,7 +434,7 @@ if(!check_has_body_select()) return - var/atom/movable/screen/zone_sel/selector = mob.hud_used.zone_select + var/atom/movable/screen/zone_sel/selector = mob.hud_used.screen_objects[HUD_MOB_ZONE_SELECTOR] selector.set_selected_zone(BODY_ZONE_HEAD, mob) ///Hidden verb to target the eyes, bound to 7 @@ -445,7 +445,7 @@ if(!check_has_body_select()) return - var/atom/movable/screen/zone_sel/selector = mob.hud_used.zone_select + var/atom/movable/screen/zone_sel/selector = mob.hud_used.screen_objects[HUD_MOB_ZONE_SELECTOR] selector.set_selected_zone(BODY_ZONE_PRECISE_EYES, mob) ///Hidden verb to target the mouth, bound to 9 @@ -456,7 +456,7 @@ if(!check_has_body_select()) return - var/atom/movable/screen/zone_sel/selector = mob.hud_used.zone_select + var/atom/movable/screen/zone_sel/selector = mob.hud_used.screen_objects[HUD_MOB_ZONE_SELECTOR] selector.set_selected_zone(BODY_ZONE_PRECISE_MOUTH, mob) ///Hidden verb to target the right arm, bound to 4 @@ -467,7 +467,7 @@ if(!check_has_body_select()) return - var/atom/movable/screen/zone_sel/selector = mob.hud_used.zone_select + var/atom/movable/screen/zone_sel/selector = mob.hud_used.screen_objects[HUD_MOB_ZONE_SELECTOR] selector.set_selected_zone(BODY_ZONE_R_ARM, mob) ///Hidden verb to target the chest, bound to 5 @@ -478,7 +478,7 @@ if(!check_has_body_select()) return - var/atom/movable/screen/zone_sel/selector = mob.hud_used.zone_select + var/atom/movable/screen/zone_sel/selector = mob.hud_used.screen_objects[HUD_MOB_ZONE_SELECTOR] selector.set_selected_zone(BODY_ZONE_CHEST, mob) ///Hidden verb to target the left arm, bound to 6 @@ -489,7 +489,7 @@ if(!check_has_body_select()) return - var/atom/movable/screen/zone_sel/selector = mob.hud_used.zone_select + var/atom/movable/screen/zone_sel/selector = mob.hud_used.screen_objects[HUD_MOB_ZONE_SELECTOR] selector.set_selected_zone(BODY_ZONE_L_ARM, mob) ///Hidden verb to target the right leg, bound to 1 @@ -500,7 +500,7 @@ if(!check_has_body_select()) return - var/atom/movable/screen/zone_sel/selector = mob.hud_used.zone_select + var/atom/movable/screen/zone_sel/selector = mob.hud_used.screen_objects[HUD_MOB_ZONE_SELECTOR] selector.set_selected_zone(BODY_ZONE_R_LEG, mob) ///Hidden verb to target the groin, bound to 2 @@ -511,7 +511,7 @@ if(!check_has_body_select()) return - var/atom/movable/screen/zone_sel/selector = mob.hud_used.zone_select + var/atom/movable/screen/zone_sel/selector = mob.hud_used.screen_objects[HUD_MOB_ZONE_SELECTOR] selector.set_selected_zone(BODY_ZONE_PRECISE_GROIN, mob) ///Hidden verb to target the left leg, bound to 3 @@ -522,7 +522,7 @@ if(!check_has_body_select()) return - var/atom/movable/screen/zone_sel/selector = mob.hud_used.zone_select + var/atom/movable/screen/zone_sel/selector = mob.hud_used.screen_objects[HUD_MOB_ZONE_SELECTOR] selector.set_selected_zone(BODY_ZONE_L_LEG, mob) ///Verb to toggle the walk or run status @@ -544,11 +544,9 @@ move_intent = MOVE_INTENT_WALK else move_intent = MOVE_INTENT_RUN - if(hud_used?.static_inventory) - for(var/atom/movable/screen/mov_intent/selector in hud_used.static_inventory) - selector.update_appearance() - update_move_intent_slowdown() + hud_used?.screen_objects[HUD_MOB_MOVE_INTENT]?.update_appearance() + update_move_intent_slowdown() SEND_SIGNAL(src, COMSIG_MOVE_INTENT_TOGGLED) ///Moves a mob upwards in z level diff --git a/code/modules/mod/mod_control.dm b/code/modules/mod/mod_control.dm index e9e1f1a05fe..7f6fff2e89e 100644 --- a/code/modules/mod/mod_control.dm +++ b/code/modules/mod/mod_control.dm @@ -524,7 +524,9 @@ module.on_unequip() UnregisterSignal(wearer, list(COMSIG_ATOM_EXITED, COMSIG_SPECIES_GAIN, COMSIG_MOB_CLICKON)) SEND_SIGNAL(src, COMSIG_MOD_WEARER_UNSET, wearer) - wearer.hud_used?.spacesuit_hud.update_spacesuit_hud_icon() + var/atom/movable/screen/spacesuit/spacesuit_hud = wearer.hud_used?.screen_objects[HUD_MOB_SPACESUIT] + if (spacesuit_hud) + spacesuit_hud.update_spacesuit_hud_icon() wearer = null /obj/item/mod/control/proc/get_sealed_slots(list/parts) @@ -725,7 +727,9 @@ else state_to_use = core.get_charge_icon_state() - wearer.hud_used.spacesuit_hud.update_spacesuit_hud_icon(state_to_use || SPACESUIT_NO_ICON) + var/atom/movable/screen/spacesuit/spacesuit_hud = wearer.hud_used?.screen_objects[HUD_MOB_SPACESUIT] + if (spacesuit_hud) + spacesuit_hud.update_spacesuit_hud_icon(state_to_use || SPACESUIT_NO_ICON) /obj/item/mod/control/proc/update_speed() var/total_slowdown = 0 diff --git a/code/modules/reagents/reagent_containers/cups/_cup.dm b/code/modules/reagents/reagent_containers/cups/_cup.dm index 953fb3d248a..e19880d6a66 100644 --- a/code/modules/reagents/reagent_containers/cups/_cup.dm +++ b/code/modules/reagents/reagent_containers/cups/_cup.dm @@ -138,7 +138,9 @@ SEND_SIGNAL(src, COMSIG_GLASS_DRANK, target_mob, user) var/fraction = min(gulp_size / reagents.total_volume, 1) reagents.trans_to(target_mob, gulp_size, transferred_by = user, methods = reagent_consumption_method) - user.hud_used?.hunger?.update_hunger_bar() + var/atom/movable/screen/hunger/hunger_bar = user.hud_used?.screen_objects[HUD_MOB_HUNGER] + if (istype(hunger_bar)) + hunger_bar.update_hunger_bar() checkLiked(fraction, target_mob) playsound(target_mob, consumption_sound, rand(10, 50), TRUE) var/list/datum/disease/diseases_to_add diff --git a/code/modules/research/xenobiology/xenobio_camera.dm b/code/modules/research/xenobiology/xenobio_camera.dm index 65fcb3ffc38..b26e759c218 100644 --- a/code/modules/research/xenobiology/xenobio_camera.dm +++ b/code/modules/research/xenobiology/xenobio_camera.dm @@ -46,8 +46,6 @@ var/max_slimes = 5 /// The amount of monkey cubes inside this machine. var/stored_monkeys = 0 - /// The HUD for this console. - var/atom/movable/screen/xenobio_console/xeno_hud /obj/machinery/computer/camera_advanced/xenobio/Initialize(mapload) . = ..() @@ -60,8 +58,6 @@ actions += new /datum/action/innate/hotkey_help(src) stored_slimes = list() - xeno_hud = new(null, src) - xeno_hud.on_update_hud(LAZYLEN(stored_slimes), stored_monkeys, max_slimes) register_context() /obj/machinery/computer/camera_advanced/xenobio/post_machine_initialize() @@ -77,7 +73,6 @@ var/mob/living/basic/slime/stored_slime = thing stored_slime.forceMove(drop_location()) stored_slimes.Cut() - QDEL_NULL(xeno_hud) return ..() /obj/machinery/computer/camera_advanced/xenobio/add_context(atom/source, list/context, obj/item/held_item, mob/living/user) @@ -115,8 +110,8 @@ RegisterSignal(user, COMSIG_CLICK_SHIFT, PROC_REF(user_shift_click)) if(!user.hud_used) return - user.hud_used.static_inventory += xeno_hud - user.hud_used.show_hud(user.hud_used.hud_version) + var/atom/movable/screen/xenobio_console/xeno_hud = user.hud_used.add_screen_object(/atom/movable/screen/xenobio_console, HUD_XENOBIO_CONSOLE, update_screen = TRUE) + xeno_hud.on_update_hud(LAZYLEN(stored_slimes), stored_monkeys, max_slimes) /obj/machinery/computer/camera_advanced/xenobio/remove_eye_control(mob/living/user) UnregisterSignal(user, list( @@ -124,10 +119,7 @@ COMSIG_MOB_ALTCLICKON, COMSIG_CLICK_SHIFT, )) - if(user.hud_used) - if(xeno_hud) - user.hud_used.static_inventory -= xeno_hud - user.hud_used.show_hud(user.hud_used.hud_version) + user.hud_used?.remove_screen_object(HUD_XENOBIO_CONSOLE) return ..() /obj/machinery/computer/camera_advanced/xenobio/item_interaction(mob/living/user, obj/item/tool, list/modifiers) @@ -156,14 +148,18 @@ balloon_alert(user, "inserted") current_potion = used_potion - xeno_hud.update_potion(current_potion) + var/atom/movable/screen/xenobio_console/xeno_hud = user.hud_used?.screen_objects[HUD_XENOBIO_CONSOLE] + if(xeno_hud) + xeno_hud.update_potion(current_potion) return ITEM_INTERACT_SUCCESS /// Handles inserting a monkey cube into the console. /obj/machinery/computer/camera_advanced/xenobio/proc/monkeycube_act(mob/living/user, obj/item/food/monkeycube/used_cube) stored_monkeys += 1 balloon_alert(user, "[stored_monkeys] cube\s stored") - xeno_hud.on_update_hud(LAZYLEN(stored_slimes), stored_monkeys, max_slimes) + var/atom/movable/screen/xenobio_console/xeno_hud = user.hud_used?.screen_objects[HUD_XENOBIO_CONSOLE] + if(xeno_hud) + xeno_hud.on_update_hud(LAZYLEN(stored_slimes), stored_monkeys, max_slimes) qdel(used_cube) return ITEM_INTERACT_SUCCESS @@ -180,7 +176,9 @@ return ITEM_INTERACT_BLOCKING balloon_alert(user, "[stored_monkeys] cube\s stored") - xeno_hud.on_update_hud(LAZYLEN(stored_slimes), stored_monkeys, max_slimes) + var/atom/movable/screen/xenobio_console/xeno_hud = user.hud_used?.screen_objects[HUD_XENOBIO_CONSOLE] + if(xeno_hud) + xeno_hud.on_update_hud(LAZYLEN(stored_slimes), stored_monkeys, max_slimes) return ITEM_INTERACT_SUCCESS /obj/machinery/computer/camera_advanced/xenobio/multitool_act(mob/living/user, obj/item/multitool/tool) @@ -212,19 +210,24 @@ return TRUE ///Places every slime in storage on target turf -/obj/machinery/computer/camera_advanced/xenobio/proc/slime_place(turf/open/target_turf) +/obj/machinery/computer/camera_advanced/xenobio/proc/slime_place(turf/open/target_turf, mob/living/user) spit_out(stored_slimes, target_turf) if(stored_slimes.len <= 0) return + if(stored_slimes.len == 1) target_turf.visible_message(span_notice("The slime is spat out!")) else target_turf.visible_message(span_notice("[stored_slimes.len] slimes are spat out!")) + for(var/mob/living/basic/slime/stored_slime in stored_slimes) stored_slime.forceMove(target_turf) REMOVE_TRAIT(stored_slime, TRAIT_STASIS, XENOBIO_CONSOLE_TRAIT) stored_slime.handle_slime_stasis() - xeno_hud.on_update_hud(LAZYLEN(stored_slimes), stored_monkeys, max_slimes) + + var/atom/movable/screen/xenobio_console/xeno_hud = user.hud_used?.screen_objects[HUD_XENOBIO_CONSOLE] + if(xeno_hud) + xeno_hud.on_update_hud(LAZYLEN(stored_slimes), stored_monkeys, max_slimes) ///Places every slime not controlled by a player into the internal storage, respecting its limits ///Returns TRUE to signal it hitting the limit, in case its being called from a loop and we want it to stop @@ -233,13 +236,16 @@ // It's possible for this proc to be called on a slime that's already being picked up, // so we need to check whether we already have to avoid duplicate entries. return FALSE + if(stored_slimes.len >= max_slimes) to_chat(user, span_warning("Slime storage is full.")) target_slime.balloon_alert(user, "storage full") return TRUE + if(target_slime.ckey) to_chat(user, span_warning("The slime wiggled free!")) return FALSE + if(target_slime.buckled) target_slime.stop_feeding(silent = TRUE) target_slime.visible_message(span_notice("The slime gets sucked up!")) @@ -247,8 +253,10 @@ target_slime.forceMove(src) stored_slimes += target_slime ADD_TRAIT(target_slime, TRAIT_STASIS, XENOBIO_CONSOLE_TRAIT) - xeno_hud.on_update_hud(LAZYLEN(stored_slimes), stored_monkeys, max_slimes) + var/atom/movable/screen/xenobio_console/xeno_hud = user.hud_used?.screen_objects[HUD_XENOBIO_CONSOLE] + if(xeno_hud) + xeno_hud.on_update_hud(LAZYLEN(stored_slimes), stored_monkeys, max_slimes) return FALSE ///Places one monkey, if possible @@ -261,13 +269,16 @@ var/mob/living/carbon/human/species/monkey/food = new /mob/living/carbon/human/species/monkey(target_turf, TRUE, user) if (QDELETED(food)) return + food.apply_status_effect(/datum/status_effect/slime_food, user) ADD_TRAIT(food, TRAIT_SPAWNED_MOB, INNATE_TRAIT) - stored_monkeys-- stored_monkeys = round(stored_monkeys, 0.1) //Prevents rounding errors spit_out(food, target_turf) - xeno_hud.on_update_hud(LAZYLEN(stored_slimes), stored_monkeys, max_slimes) + + var/atom/movable/screen/xenobio_console/xeno_hud = user.hud_used?.screen_objects[HUD_XENOBIO_CONSOLE] + if(xeno_hud) + xeno_hud.on_update_hud(LAZYLEN(stored_slimes), stored_monkeys, max_slimes) /// Check whether we can recycle monkeys at all. Optionally, displays a balloon alert over a target atom for feedback. /obj/machinery/computer/camera_advanced/xenobio/proc/can_recycle_monkeys(mob/living/user, atom/target_atom) @@ -302,7 +313,7 @@ for(var/mob/living/carbon/human/target_human in target_turf) if(!can_recycle_target_monkey(target_human)) continue - recycle_monkey(target_human) + recycle_monkey(target_human, user) monkey_found = TRUE return monkey_found @@ -314,11 +325,11 @@ if(!can_recycle_monkeys(user, target_human)) return FALSE - recycle_monkey(target_human) + recycle_monkey(target_human, user) return TRUE /// Recycles a given monkey. -/obj/machinery/computer/camera_advanced/xenobio/proc/recycle_monkey(mob/living/carbon/human/target_monkey) +/obj/machinery/computer/camera_advanced/xenobio/proc/recycle_monkey(mob/living/carbon/human/target_monkey, mob/living/user) var/obj/machinery/monkey_recycler/connected_recycler = connected_recycler_ref?.resolve() if(isnull(connected_recycler)) return @@ -328,7 +339,9 @@ connected_recycler.use_energy(500 JOULES) stored_monkeys += connected_recycler.cube_production stored_monkeys = round(stored_monkeys, 0.1) //Prevents rounding errors - xeno_hud.on_update_hud(LAZYLEN(stored_slimes), stored_monkeys, max_slimes) + var/atom/movable/screen/xenobio_console/xeno_hud = user.hud_used?.screen_objects[HUD_XENOBIO_CONSOLE] + if(xeno_hud) + xeno_hud.on_update_hud(LAZYLEN(stored_slimes), stored_monkeys, max_slimes) qdel(target_monkey) /datum/action/innate/slime_place @@ -346,7 +359,7 @@ if(!xeno_console.validate_turf(owner, eye_turf)) return - xeno_console.slime_place(eye_turf) + xeno_console.slime_place(eye_turf, owner) /datum/action/innate/slime_pick_up name = "Pick up Slime" @@ -443,7 +456,9 @@ for(var/mob/living/basic/slime/potioned_slime in eye_turf) xeno_console.spit_atom(xeno_console.current_potion, eye_turf) xeno_console.current_potion.interact_with_slime(potioned_slime, living_owner) - xeno_console.xeno_hud.update_potion(xeno_console.current_potion) + var/atom/movable/screen/xenobio_console/xeno_hud = owner.hud_used?.screen_objects[HUD_XENOBIO_CONSOLE] + if(xeno_hud) + xeno_hud.update_potion(xeno_console.current_potion) break /datum/action/innate/hotkey_help @@ -485,7 +500,9 @@ spit_atom(current_potion, slime_turf) INVOKE_ASYNC(current_potion, TYPE_PROC_REF(/obj/item/slimepotion/slime, attack), target_slime, user) - xeno_hud.update_potion(current_potion) + var/atom/movable/screen/xenobio_console/xeno_hud = user.hud_used?.screen_objects[HUD_XENOBIO_CONSOLE] + if(xeno_hud) + xeno_hud.update_potion(current_potion) /// Handles console user shift-clicking, forwards to other procs based on target type. /obj/machinery/computer/camera_advanced/xenobio/proc/user_shift_click(mob/living/user, atom/target) diff --git a/code/modules/surgery/bodyparts/dismemberment.dm b/code/modules/surgery/bodyparts/dismemberment.dm index 72108859d3e..d0a3d18cfa2 100644 --- a/code/modules/surgery/bodyparts/dismemberment.dm +++ b/code/modules/surgery/bodyparts/dismemberment.dm @@ -204,7 +204,7 @@ arm_owner.set_handcuffed(null) arm_owner.dropItemToGround(lost_cuffs, force = TRUE) if(arm_owner.hud_used) - var/atom/movable/screen/inventory/hand/associated_hand = arm_owner.hud_used.hand_slots["[held_index]"] + var/atom/movable/screen/inventory/hand/associated_hand = arm_owner.hud_used.hand_slots[held_index] associated_hand?.update_appearance() if(arm_owner.num_hands == 0) arm_owner.dropItemToGround(arm_owner.gloves, force = TRUE) diff --git a/code/modules/surgery/bodyparts/parts.dm b/code/modules/surgery/bodyparts/parts.dm index 7c112950265..9b0f56c6a58 100644 --- a/code/modules/surgery/bodyparts/parts.dm +++ b/code/modules/surgery/bodyparts/parts.dm @@ -211,7 +211,7 @@ if(!old_owner.hud_used) return - var/atom/movable/screen/inventory/hand/hand = old_owner.hud_used.hand_slots["[held_index]"] + var/atom/movable/screen/inventory/hand/hand = old_owner.hud_used.hand_slots[held_index] hand?.update_appearance() /// We need to add hand hud items and appearance, so do that here @@ -230,7 +230,7 @@ if(!new_owner.hud_used) return - var/atom/movable/screen/inventory/hand/hand = new_owner.hud_used.hand_slots["[held_index]"] + var/atom/movable/screen/inventory/hand/hand = new_owner.hud_used.hand_slots[held_index] hand?.update_appearance() /obj/item/bodypart/arm/set_disabled(new_disabled) @@ -249,7 +249,7 @@ owner.set_usable_hands(owner.usable_hands + 1) if(owner.hud_used) - var/atom/movable/screen/inventory/hand/hand_screen_object = owner.hud_used.hand_slots["[held_index]"] + var/atom/movable/screen/inventory/hand/hand_screen_object = owner.hud_used.hand_slots[held_index] hand_screen_object?.update_appearance() /datum/status_effect/arm_speed_penalty diff --git a/code/modules/surgery/organs/internal/stomach/_stomach.dm b/code/modules/surgery/organs/internal/stomach/_stomach.dm index f8cb50193d5..7429f072f53 100644 --- a/code/modules/surgery/organs/internal/stomach/_stomach.dm +++ b/code/modules/surgery/organs/internal/stomach/_stomach.dm @@ -388,7 +388,9 @@ /obj/item/organ/stomach/on_mob_insert(mob/living/carbon/receiver, special, movement_flags) . = ..() - receiver.hud_used?.hunger?.update_hunger_bar() + var/atom/movable/screen/hunger/hunger_bar = receiver.hud_used?.screen_objects[HUD_MOB_HUNGER] + if(hunger_bar) + hunger_bar.update_hunger_bar() RegisterSignal(receiver, COMSIG_CARBON_VOMITED, PROC_REF(on_vomit)) RegisterSignal(receiver, COMSIG_HUMAN_GOT_PUNCHED, PROC_REF(on_punched)) @@ -397,7 +399,9 @@ var/mob/living/carbon/human/human_owner = stomach_owner human_owner.clear_alert(ALERT_DISGUST) human_owner.clear_mood_event("disgust") - stomach_owner.hud_used?.hunger?.update_hunger_bar() + var/atom/movable/screen/hunger/hunger_bar = stomach_owner.hud_used?.screen_objects[HUD_MOB_HUNGER] + if(hunger_bar) + hunger_bar.update_hunger_bar() UnregisterSignal(stomach_owner, list(COMSIG_CARBON_VOMITED, COMSIG_HUMAN_GOT_PUNCHED)) return ..() diff --git a/code/modules/unit_tests/unequip_defib.dm b/code/modules/unit_tests/unequip_defib.dm index e2db399f2de..910cf599af2 100644 --- a/code/modules/unit_tests/unequip_defib.dm +++ b/code/modules/unit_tests/unequip_defib.dm @@ -12,7 +12,7 @@ usr = dummy // mouse drop still uses usr - defib.MouseDrop(dummy.hud_used.hand_slots["1"]) + defib.MouseDrop(dummy.hud_used.hand_slots[1]) if(!dummy.is_holding(defib)) TEST_FAIL("The dummy failed to remove the defib from their back via mouse drop.") diff --git a/code/modules/unit_tests/unit_test.dm b/code/modules/unit_tests/unit_test.dm index 74f14ecea49..289bfc097bc 100644 --- a/code/modules/unit_tests/unit_test.dm +++ b/code/modules/unit_tests/unit_test.dm @@ -351,13 +351,12 @@ GLOBAL_VAR_INIT(focused_tests, focused_tests()) returnable_list += typesof(/obj/structure/transport/linear) // Runtimes if the associated machinery does not exist, but not the base type returnable_list += subtypesof(/obj/machinery/airlock_controller) - // Always ought to have an associated escape menu. Any references it could possibly hold would need one regardless. - returnable_list += subtypesof(/atom/movable/screen/escape_menu) // Can't spawn openspace above nothing, it'll get pissy at me returnable_list += typesof(/turf/open/space/openspace) returnable_list += typesof(/turf/open/openspace) returnable_list += typesof(/obj/item/robot_model) // These should never be spawned outside of a robot. - + //A lot of these depend on a hud datum to function and should not be created in a vacuum + returnable_list += typesof(/atom/movable/screen) return returnable_list /proc/RunUnitTests() diff --git a/icons/hud/screen_changeling.dmi b/icons/hud/screen_changeling.dmi index c3bab062ac497d18ace3cdca24db46e1291f0c8e..30c3df2994825731c7c2ab28459d1c489e4c4e6d 100644 GIT binary patch literal 7108 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 literal 6755 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 FV1iZXBzOP- diff --git a/icons/mob/actions/actions_changeling.dmi b/icons/mob/actions/actions_changeling.dmi index a721505a8c07d8f20c1182cc6270ee7ce8c5b75b..aae88cd0b5ccb9e1cafc6b0640c8e7631c51a08e 100644 GIT binary patch literal 11025 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 MsyYu#l&wPl4@GMfcmMzZ diff --git a/tgstation.dme b/tgstation.dme index 233b01bea38..ca737cae21b 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -619,37 +619,26 @@ #include "code\_onclick\other_mobs.dm" #include "code\_onclick\overmind.dm" #include "code\_onclick\telekinesis.dm" -#include "code\_onclick\hud\action_button.dm" +#include "code\_onclick\hud\action_group.dm" #include "code\_onclick\hud\ai.dm" -#include "code\_onclick\hud\alert.dm" #include "code\_onclick\hud\alien.dm" #include "code\_onclick\hud\alien_larva.dm" #include "code\_onclick\hud\blob_overmind.dm" -#include "code\_onclick\hud\credits.dm" #include "code\_onclick\hud\drones.dm" -#include "code\_onclick\hud\fullscreen.dm" #include "code\_onclick\hud\generic_dextrous.dm" #include "code\_onclick\hud\ghost.dm" #include "code\_onclick\hud\guardian.dm" #include "code\_onclick\hud\hud.dm" #include "code\_onclick\hud\human.dm" +#include "code\_onclick\hud\inventory_slot.dm" #include "code\_onclick\hud\living.dm" -#include "code\_onclick\hud\map_popups.dm" -#include "code\_onclick\hud\map_view.dm" -#include "code\_onclick\hud\movable_screen_objects.dm" #include "code\_onclick\hud\new_player.dm" #include "code\_onclick\hud\ooze.dm" -#include "code\_onclick\hud\perks.dm" -#include "code\_onclick\hud\picture_in_picture.dm" -#include "code\_onclick\hud\radial.dm" -#include "code\_onclick\hud\radial_persistent.dm" +#include "code\_onclick\hud\pai.dm" #include "code\_onclick\hud\revenanthud.dm" #include "code\_onclick\hud\robot.dm" -#include "code\_onclick\hud\screen_object_holder.dm" -#include "code\_onclick\hud\screen_objects.dm" -#include "code\_onclick\hud\screentip.dm" #include "code\_onclick\hud\soulscythe.dm" -#include "code\_onclick\hud\voidwalkerhud.dm" +#include "code\_onclick\hud\voidwalker.dm" #include "code\_onclick\hud\parallax\parallax.dm" #include "code\_onclick\hud\parallax\random_layer.dm" #include "code\_onclick\hud\rendering\plane_master_controller.dm" @@ -657,6 +646,30 @@ #include "code\_onclick\hud\rendering\render_plate.dm" #include "code\_onclick\hud\rendering\plane_masters\_plane_master.dm" #include "code\_onclick\hud\rendering\plane_masters\plane_master_subtypes.dm" +#include "code\_onclick\hud\screen_objects\action_button.dm" +#include "code\_onclick\hud\screen_objects\ai.dm" +#include "code\_onclick\hud\screen_objects\alert.dm" +#include "code\_onclick\hud\screen_objects\alien.dm" +#include "code\_onclick\hud\screen_objects\blob.dm" +#include "code\_onclick\hud\screen_objects\credits.dm" +#include "code\_onclick\hud\screen_objects\fullscreen.dm" +#include "code\_onclick\hud\screen_objects\ghost.dm" +#include "code\_onclick\hud\screen_objects\guardian.dm" +#include "code\_onclick\hud\screen_objects\human.dm" +#include "code\_onclick\hud\screen_objects\map_popups.dm" +#include "code\_onclick\hud\screen_objects\map_view.dm" +#include "code\_onclick\hud\screen_objects\movable_screen_objects.dm" +#include "code\_onclick\hud\screen_objects\new_player.dm" +#include "code\_onclick\hud\screen_objects\pai.dm" +#include "code\_onclick\hud\screen_objects\perks.dm" +#include "code\_onclick\hud\screen_objects\picture_in_picture.dm" +#include "code\_onclick\hud\screen_objects\radial.dm" +#include "code\_onclick\hud\screen_objects\radial_persistent.dm" +#include "code\_onclick\hud\screen_objects\robot.dm" +#include "code\_onclick\hud\screen_objects\screen_object_holder.dm" +#include "code\_onclick\hud\screen_objects\screen_objects.dm" +#include "code\_onclick\hud\screen_objects\screentip.dm" +#include "code\_onclick\hud\screen_objects\voidwalker.dm" #include "code\controllers\admin.dm" #include "code\controllers\controller.dm" #include "code\controllers\failsafe.dm" @@ -4320,7 +4333,6 @@ #include "code\modules\economy\poker_chips.dm" #include "code\modules\emoji\emoji_parse.dm" #include "code\modules\emote_panel\emote_panel.dm" -#include "code\modules\engineering\tools\multitool.dm" #include "code\modules\error_handler\error_handler.dm" #include "code\modules\error_handler\error_viewer.dm" #include "code\modules\escape_menu\details.dm" @@ -5815,7 +5827,6 @@ #include "code\modules\pai\debug.dm" #include "code\modules\pai\defense.dm" #include "code\modules\pai\door_jack.dm" -#include "code\modules\pai\hud.dm" #include "code\modules\pai\login.dm" #include "code\modules\pai\pai.dm" #include "code\modules\pai\personality.dm"