From 90eab441aac63673211e480632e3873cba9d12f1 Mon Sep 17 00:00:00 2001 From: SandPoot Date: Mon, 9 May 2022 18:50:17 -0300 Subject: [PATCH] Upload files --- code/__DEFINES/mobs.dm | 22 + .../game/machinery/computer/communications.dm | 6 +- code/game/machinery/status_display.dm | 490 +++++++++++++----- code/modules/mob/living/silicon/ai/death.dm | 10 +- code/modules/mob/living/silicon/ai/emote.dm | 101 ++++ code/modules/mob/living/silicon/ai/login.dm | 6 - code/modules/mob/living/silicon/ai/logout.dm | 4 - .../autolathe_designs_construction.dm | 8 + icons/obj/wallframe.dmi | Bin 1059 -> 1126 bytes tgstation.dme | 1 + 10 files changed, 495 insertions(+), 153 deletions(-) create mode 100644 code/modules/mob/living/silicon/ai/emote.dm diff --git a/code/__DEFINES/mobs.dm b/code/__DEFINES/mobs.dm index 3ce91f4332..07ffbc568d 100644 --- a/code/__DEFINES/mobs.dm +++ b/code/__DEFINES/mobs.dm @@ -344,6 +344,28 @@ ///Define for spawning megafauna instead of a mob for cave gen #define SPAWN_MEGAFAUNA "bluh bluh huge boss" +/* + * Defines for "AI emotions", allowing the AI to expression emotions + * with status displays via emotes. + */ + +#define AI_EMOTION_VERY_HAPPY "Very Happy" +#define AI_EMOTION_HAPPY "Happy" +#define AI_EMOTION_NEUTRAL "Neutral" +#define AI_EMOTION_UNSURE "Unsure" +#define AI_EMOTION_CONFUSED "Confused" +#define AI_EMOTION_SAD "Sad" +#define AI_EMOTION_BSOD "BSOD" +#define AI_EMOTION_BLANK "Blank" +#define AI_EMOTION_PROBLEMS "Problems?" +#define AI_EMOTION_AWESOME "Awesome" +#define AI_EMOTION_FACEPALM "Facepalm" +#define AI_EMOTION_THINKING "Thinking" +#define AI_EMOTION_FRIEND_COMPUTER "Friend Computer" +#define AI_EMOTION_DORFY "Dorfy" +#define AI_EMOTION_BLUE_GLOW "Blue Glow" +#define AI_EMOTION_RED_GLOW "Red Glow" + // / Breathing types. Lungs can access either by these or by a string, which will be considered a gas ID. #define BREATH_OXY /datum/breathing_class/oxygen #define BREATH_PLASMA /datum/breathing_class/plasma diff --git a/code/game/machinery/computer/communications.dm b/code/game/machinery/computer/communications.dm index 2f394fcb4d..7c22846ece 100755 --- a/code/game/machinery/computer/communications.dm +++ b/code/game/machinery/computer/communications.dm @@ -89,6 +89,7 @@ /obj/machinery/computer/communications/ui_act(action, list/params) var/static/list/approved_states = list(STATE_BUYING_SHUTTLE, STATE_CHANGING_STATUS, STATE_MAIN, STATE_MESSAGES) var/static/list/approved_status_pictures = list("biohazard", "blank", "default", "lockdown", "redalert", "shuttle") + var/static/list/state_status_pictures = list("blank", "shuttle") . = ..() if (.) @@ -307,7 +308,10 @@ var/picture = params["picture"] if (!(picture in approved_status_pictures)) return - post_status("alert", picture) + if(picture in state_status_pictures) + post_status(picture) + else + post_status("alert", picture) playsound(src, "terminal_type", 50, FALSE) if ("toggleAuthentication") // Log out if we're logged in diff --git a/code/game/machinery/status_display.dm b/code/game/machinery/status_display.dm index 8627a79772..2438a6b66b 100644 --- a/code/game/machinery/status_display.dm +++ b/code/game/machinery/status_display.dm @@ -4,102 +4,182 @@ #define CHARS_PER_LINE 5 #define FONT_SIZE "5pt" #define FONT_COLOR "#09f" -#define FONT_STYLE "Arial Black" -#define SCROLL_SPEED 2 +#define FONT_STYLE "Small Fonts" +#define SCROLL_RATE (0.04 SECONDS) // time per pixel +#define LINE1_Y -8 +#define LINE2_Y -15 #define SD_BLANK 0 // 0 = Blank #define SD_EMERGENCY 1 // 1 = Emergency Shuttle timer #define SD_MESSAGE 2 // 2 = Arbitrary message(s) #define SD_PICTURE 3 // 3 = alert picture -#define SD_AI_EMOTE 1 // 1 = AI emoticon -#define SD_AI_BSOD 2 // 2 = Blue screen of death - -/// Status display which can show images and scrolling text. !!!USE /obj/machinery/status_display/evac NOT THIS!!! +/// Status display which can show images and scrolling text. /obj/machinery/status_display name = "status display" desc = null icon = 'icons/obj/status_display.dmi' icon_state = "frame" - plane = ABOVE_WALL_PLANE + base_icon_state = "unanchoredstatusdisplay" + verb_say = "beeps" + verb_ask = "beeps" + verb_exclaim = "beeps" density = FALSE - use_power = IDLE_POWER_USE - idle_power_usage = 10 + layer = ABOVE_WINDOW_LAYER - maptext_height = 26 - maptext_width = 32 + var/obj/effect/overlay/status_display_text/message1_overlay + var/obj/effect/overlay/status_display_text/message2_overlay + var/current_picture = "" + var/current_mode = SD_BLANK + var/message1 = "" + var/message2 = "" - var/message1 = "" // message line 1 - var/message2 = "" // message line 2 - var/index1 // display index for scrolling messages or 0 if non-scrolling - var/index2 +/obj/item/wallframe/status_display + name = "status display frame" + desc = "Used to build status displays, just secure to the wall." + icon_state = "unanchoredstatusdisplay" + custom_materials = list(/datum/material/iron=14000, /datum/material/glass=8000) + result_path = /obj/machinery/status_display/evac + pixel_shift = -32 -/// Immediately blank the display. -/obj/machinery/status_display/proc/remove_display() - cut_overlays() - if(maptext) - maptext = "" +/obj/machinery/status_display/wrench_act(mob/living/user, obj/item/tool) + . = ..() + balloon_alert(user, "[anchored ? "un" : ""]securing...") + tool.play_tool_sound(src) + if(tool.use_tool(src, user, 6 SECONDS)) + playsound(loc, 'sound/items/deconstruct.ogg', 50, TRUE) + balloon_alert(user, "[anchored ? "un" : ""]secured") + deconstruct() + return TRUE + +/obj/machinery/status_display/welder_act(mob/living/user, obj/item/tool) + if(user.a_intent == INTENT_HARM) + return + if(obj_integrity >= max_integrity) + balloon_alert(user, "it doesn't need repairs!") + return TRUE + user.balloon_alert_to_viewers("repairing display...", "repairing...") + if(!tool.use_tool(src, user, 4 SECONDS, amount = 0, volume=50)) + return TRUE + balloon_alert(user, "repaired") + obj_integrity = max_integrity + set_machine_stat(stat & ~BROKEN) + update_appearance() + return TRUE + +/obj/machinery/status_display/deconstruct(disassembled = TRUE) + if(flags_1 & NODECONSTRUCT_1) + return + if(!disassembled) + new /obj/item/stack/sheet/metal(drop_location(), 2) + new /obj/item/shard(drop_location()) + new /obj/item/shard(drop_location()) + else + new /obj/item/wallframe/status_display(drop_location()) + qdel(src) /// Immediately change the display to the given picture. /obj/machinery/status_display/proc/set_picture(state) - remove_display() - add_overlay(state) + if(state != current_picture) + current_picture = state + + update_appearance() /// Immediately change the display to the given two lines. -/obj/machinery/status_display/proc/update_display(line1, line2) - var/new_text = {"
[line1]
[line2]
"} - if(maptext != new_text) - maptext = new_text +/obj/machinery/status_display/proc/set_messages(line1, line2) + line1 = uppertext(line1) + line2 = uppertext(line2) -/// Prepare the display to marquee the given two lines. -/// -/// Call with no arguments to disable. -/obj/machinery/status_display/proc/set_message(m1, m2) - if(m1) - index1 = (length_char(m1) > CHARS_PER_LINE) - message1 = m1 - else - message1 = "" - index1 = 0 + if(line1 != message1) + message1 = line1 - if(m2) - index2 = (length_char(m2) > CHARS_PER_LINE) - message2 = m2 - else - message2 = "" - index2 = 0 + if(line2 != message2) + message2 = line2 -// Timed process - performs default marquee action if so needed. + update_appearance() + +/** + * Remove both message objs and null the fields. + * Don't call this in subclasses. + */ +/obj/machinery/status_display/proc/remove_messages() + if(message1_overlay) + QDEL_NULL(message1_overlay) + if(message2_overlay) + QDEL_NULL(message2_overlay) + +/** + * Create/update message overlay. + * They must be handled as real objects for the animation to run. + * Don't call this in subclasses. + * Arguments: + * * overlay - the current /obj/effect/overlay/status_display_text instance + * * line_y - The Y offset to render the text. + * * message - the new message text. + * Returns new /obj/effect/overlay/status_display_text or null if unchanged. + */ +/obj/machinery/status_display/proc/update_message(obj/effect/overlay/status_display_text/overlay, line_y, message) + if(overlay && message == overlay.message) + return null + + if(overlay) + qdel(overlay) + + var/obj/effect/overlay/status_display_text/new_status_display_text = new(src, line_y, message) + vis_contents += new_status_display_text + return new_status_display_text + +/obj/machinery/status_display/update_appearance(updates=ALL) + . = ..() + if( \ + (stat & (NOPOWER|BROKEN)) || \ + (current_mode == SD_BLANK) || \ + (current_mode != SD_PICTURE && message1 == "" && message2 == "") \ + ) + set_light(0) + return + set_light(1.4, 0.7, LIGHT_COLOR_BLUE) // blue light + +/obj/machinery/status_display/update_overlays() + . = ..() + + if(stat & (NOPOWER|BROKEN)) + remove_messages() + return + + switch(current_mode) + if(SD_BLANK) + remove_messages() + // Turn off backlight. + return + if(SD_PICTURE) + remove_messages() + . += mutable_appearance(icon, current_picture) + else + var/overlay = update_message(message1_overlay, LINE1_Y, message1) + if(overlay) + message1_overlay = overlay + overlay = update_message(message2_overlay, LINE2_Y, message2) + if(overlay) + message2_overlay = overlay + + // Turn off backlight if message is blank + if(message1 == "" && message2 == "") + return + + . += emissive_appearance(icon, "outline", alpha = src.alpha) + +// Timed process - performs nothing in the base class /obj/machinery/status_display/process() if(stat & NOPOWER) // No power, no processing. - remove_display() - return PROCESS_KILL + update_appearance() - var/line1 = message1 - if(index1) - line1 = copytext_char("[message1]|[message1]", index1, index1+CHARS_PER_LINE) - var/message1_len = length_char(message1) - index1 += SCROLL_SPEED - if(index1 > message1_len + 1) - index1 -= (message1_len + 1) - - var/line2 = message2 - if(index2) - line2 = copytext_char("[message2]|[message2]", index2, index2+CHARS_PER_LINE) - var/message2_len = length(message2) - index2 += SCROLL_SPEED - if(index2 > message2_len + 1) - index2 -= (message2_len + 1) - - update_display(line1, line2) - if (!index1 && !index2) - // No marquee, no processing. - return PROCESS_KILL + return PROCESS_KILL /// Update the display and, if necessary, re-enable processing. /obj/machinery/status_display/proc/update() - if (process() != PROCESS_KILL) + if (process(SSMACHINES_DT) != PROCESS_KILL) START_PROCESSING(SSmachines, src) /obj/machinery/status_display/power_change() @@ -110,22 +190,23 @@ . = ..() if(stat & (NOPOWER|BROKEN) || . & EMP_PROTECT_SELF) return + current_mode = SD_PICTURE set_picture("ai_bsod") /obj/machinery/status_display/examine(mob/user) . = ..() - if (message1 || message2) + if (current_mode == SD_MESSAGE && (message1_overlay?.message || message2_overlay?.message)) . += "The display says:" - if (message1) - . += "\t[html_encode(message1)]" - if (message2) - . += "\t[html_encode(message2)]" + if (message1_overlay.message) + . += "\t[html_encode(message1_overlay.message)]" + if (message2_overlay.message) + . += "\t[html_encode(message2_overlay.message)]" // Helper procs for child display types. /obj/machinery/status_display/proc/display_shuttle_status(obj/docking_port/mobile/shuttle) if(!shuttle) // the shuttle is missing - no processing - update_display("shutl?","") + set_messages("shutl?","") return PROCESS_KILL else if(shuttle.timer) var/line1 = "-[shuttle.getModeStr()]-" @@ -133,10 +214,10 @@ if(length_char(line2) > CHARS_PER_LINE) line2 = "error" - update_display(line1, line2) + set_messages(line1, line2) else // don't kill processing, the timer might turn back on - remove_display() + set_messages("", "") /obj/machinery/status_display/proc/examine_shuttle(mob/user, obj/docking_port/mobile/shuttle) if (shuttle) @@ -150,18 +231,75 @@ else return "The display says:
\tShuttle missing!" +/obj/machinery/status_display/Destroy() + remove_messages() + return ..() + +/** + * Nice overlay to make text smoothly scroll with no client updates after setup. + */ +/obj/effect/overlay/status_display_text + icon = 'icons/obj/status_display.dmi' + vis_flags = VIS_INHERIT_LAYER | VIS_INHERIT_PLANE | VIS_INHERIT_ID + + var/message + +/obj/effect/overlay/status_display_text/Initialize(mapload, yoffset, line) + . = ..() + + maptext_y = yoffset + message = line + + var/line_length = length_char(line) + + if(line_length > CHARS_PER_LINE) + // Marquee text + var/marquee_message = "[line] • [line] • [line]" + var/marquee_length = line_length * 3 + 6 + maptext = generate_text(marquee_message, center = FALSE) + maptext_width = 6 * marquee_length + maptext_x = 32 + + // Mask off to fit in screen. + add_filter("mask", 1, alpha_mask_filter(icon = icon(icon, "outline"))) + + // Scroll. + var/width = 4 * marquee_length + var/time = (width + 32) * SCROLL_RATE + animate(src, maptext_x = -width, time = time, loop = -1) + animate(maptext_x = 32, time = 0) + else + // Centered text + maptext = generate_text(line, center = TRUE) + maptext_x = 0 + +/obj/effect/overlay/status_display_text/proc/generate_text(text, center) + return {"
[text]
"} /// Evac display which shows shuttle timer or message set by Command. /obj/machinery/status_display/evac + current_mode = SD_EMERGENCY var/frequency = FREQ_STATUS_DISPLAYS - var/mode = SD_EMERGENCY var/friendc = FALSE // track if Friend Computer mode var/last_picture // For when Friend Computer mode is undone +// MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/status_display/evac, 32) + +//makes it go on the wall when built +/obj/machinery/status_display/Initialize(mapload, ndir, building) + . = ..() + update_appearance() + /obj/machinery/status_display/evac/Initialize(mapload) . = ..() // register for radio system SSradio.add_object(src, frequency) + // Circuit USB + /* + AddComponent(/datum/component/usb_port, list( + /obj/item/circuit_component/status_display, + )) + */ /obj/machinery/status_display/evac/Destroy() SSradio.remove_object(src,frequency) @@ -170,23 +308,23 @@ /obj/machinery/status_display/evac/process() if(stat & NOPOWER) // No power, no processing. - remove_display() + update_appearance() return PROCESS_KILL if(friendc) //Makes all status displays except supply shuttle timer display the eye -- Urist + current_mode = SD_PICTURE set_picture("ai_friend") return PROCESS_KILL - switch(mode) + switch(current_mode) if(SD_BLANK) - remove_display() return PROCESS_KILL if(SD_EMERGENCY) return display_shuttle_status(SSshuttle.emergency) if(SD_MESSAGE) - return ..() + return PROCESS_KILL if(SD_PICTURE) set_picture(last_picture) @@ -194,7 +332,7 @@ /obj/machinery/status_display/evac/examine(mob/user) . = ..() - if(mode == SD_EMERGENCY) + if(current_mode == SD_EMERGENCY) . += examine_shuttle(user, SSshuttle.emergency) else if(!message1 && !message2) . += "The display is blank." @@ -202,16 +340,16 @@ /obj/machinery/status_display/evac/receive_signal(datum/signal/signal) switch(signal.data["command"]) if("blank") - mode = SD_BLANK - set_message(null, null) + current_mode = SD_BLANK + update_appearance() if("shuttle") - mode = SD_EMERGENCY - set_message(null, null) + current_mode = SD_EMERGENCY + set_messages("", "") if("message") - mode = SD_MESSAGE - set_message(signal.data["msg1"], signal.data["msg2"]) + current_mode = SD_MESSAGE + set_messages(signal.data["msg1"] || "", signal.data["msg2"] || "") if("alert") - mode = SD_PICTURE + current_mode = SD_PICTURE last_picture = signal.data["picture_state"] set_picture(last_picture) if("friendcomputer") @@ -222,11 +360,12 @@ /// Supply display which shows the status of the supply shuttle. /obj/machinery/status_display/supply name = "supply display" + current_mode = SD_MESSAGE /obj/machinery/status_display/supply/process() if(stat & NOPOWER) // No power, no processing. - remove_display() + update_appearance() return PROCESS_KILL var/line1 @@ -240,12 +379,15 @@ if(is_station_level(SSshuttle.supply.z)) line1 = "CARGO" line2 = "Docked" + else + line1 = "" + line2 = "" else line1 = "CARGO" line2 = SSshuttle.supply.getTimerStr() if(length_char(line2) > CHARS_PER_LINE) line2 = "Error" - update_display(line1, line2) + set_messages(line1, line2) /obj/machinery/status_display/supply/examine(mob/user) . = ..() @@ -265,12 +407,13 @@ /// General-purpose shuttle status display. /obj/machinery/status_display/shuttle name = "shuttle display" + current_mode = SD_MESSAGE var/shuttle_id /obj/machinery/status_display/shuttle/process() if(!shuttle_id || (stat & NOPOWER)) // No power, no processing. - remove_display() + update_appearance() return PROCESS_KILL return display_shuttle_status(SSshuttle.getShuttle(shuttle_id)) @@ -291,7 +434,7 @@ update() /obj/machinery/status_display/shuttle/connect_to_shuttle(obj/docking_port/mobile/port, obj/docking_port/stationary/dock, idnum, override) - if (port && (shuttle_id == initial(shuttle_id) || override)) + if(port && (shuttle_id == initial(shuttle_id) || override)) shuttle_id = port.id update() @@ -300,9 +443,32 @@ /obj/machinery/status_display/ai name = "\improper AI display" desc = "A small screen which the AI can use to present itself." + current_mode = SD_PICTURE - var/mode = SD_BLANK - var/emotion = "Neutral" + var/emotion = AI_EMOTION_BLANK + + /// A mapping between AI_EMOTION_* string constants, which also double as user readable descriptions, and the name of the iconfile. + var/static/list/emotion_map = list( + AI_EMOTION_BLANK = "ai_off", + AI_EMOTION_VERY_HAPPY = "ai_veryhappy", + AI_EMOTION_HAPPY = "ai_happy", + AI_EMOTION_NEUTRAL = "ai_neutral", + AI_EMOTION_UNSURE = "ai_unsure", + AI_EMOTION_CONFUSED = "ai_confused", + AI_EMOTION_SAD = "ai_sad", + AI_EMOTION_BSOD = "ai_bsod", + AI_EMOTION_PROBLEMS = "ai_trollface", + AI_EMOTION_AWESOME = "ai_awesome", + AI_EMOTION_DORFY = "ai_urist", + AI_EMOTION_THINKING = "ai_thinking", + AI_EMOTION_FACEPALM = "ai_facepalm", + AI_EMOTION_FRIEND_COMPUTER = "ai_friend", + AI_EMOTION_BLUE_GLOW = "ai_sal", + AI_EMOTION_RED_GLOW = "ai_hal", + ) + + +// MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/status_display/ai, 32) /obj/machinery/status_display/ai/Initialize(mapload) . = ..() @@ -313,57 +479,109 @@ . = ..() /obj/machinery/status_display/ai/attack_ai(mob/living/silicon/ai/user) - if(isAI(user)) - user.ai_statuschange() + if(!isAI(user)) + return + var/list/choices = list() + for(var/emotion_const in emotion_map) + var/icon_state = emotion_map[emotion_const] + choices[emotion_const] = image(icon = 'icons/obj/status_display.dmi', icon_state = icon_state) + + var/emotion_result = show_radial_menu(user, src, choices, tooltips = TRUE) + for(var/_emote in typesof(/datum/emote/ai/emotion_display)) + var/datum/emote/ai/emotion_display/emote = _emote + if(initial(emote.emotion) == emotion_result) + user.emote(initial(emote.key)) + break /obj/machinery/status_display/ai/process() - if(mode == SD_BLANK || (stat & NOPOWER)) - remove_display() + if(stat & NOPOWER) + update_appearance() return PROCESS_KILL - if(mode == SD_AI_EMOTE) - switch(emotion) - if("Very Happy") - set_picture("ai_veryhappy") - if("Happy") - set_picture("ai_happy") - if("Neutral") - set_picture("ai_neutral") - if("Unsure") - set_picture("ai_unsure") - if("Confused") - set_picture("ai_confused") - if("Sad") - set_picture("ai_sad") - if("BSOD") - set_picture("ai_bsod") - if("Blank") - set_picture("ai_off") - if("Problems?") - set_picture("ai_trollface") - if("Awesome") - set_picture("ai_awesome") - if("Dorfy") - set_picture("ai_urist") - if("Thinking") - set_picture("ai_thinking") - if("Facepalm") - set_picture("ai_facepalm") - if("Friend Computer") - set_picture("ai_friend") - if("Blue Glow") - set_picture("ai_sal") - if("Red Glow") - set_picture("ai_hal") - return PROCESS_KILL + set_picture(emotion_map[emotion]) + return PROCESS_KILL - if(mode == SD_AI_BSOD) - set_picture("ai_bsod") - return PROCESS_KILL +/* +/obj/item/circuit_component/status_display + display_name = "Status Display" + desc = "Output text and pictures to a status display." + circuit_flags = CIRCUIT_FLAG_INPUT_SIGNAL|CIRCUIT_FLAG_OUTPUT_SIGNAL + var/datum/port/input/option/command + var/datum/port/input/option/picture + var/datum/port/input/message1 + var/datum/port/input/message2 + + var/obj/machinery/status_display/connected_display + + var/list/command_map + var/list/picture_map + +/obj/item/circuit_component/status_display/populate_ports() + message1 = add_input_port("Message 1", PORT_TYPE_STRING) + message2 = add_input_port("Message 2", PORT_TYPE_STRING) + +/obj/item/circuit_component/status_display/populate_options() + var/static/list/command_options = list( + "Blank" = "blank", + "Shuttle" = "shuttle", + "Message" = "message", + "Alert" = "alert" + ) + + var/static/list/picture_options = list( + "Default" = "default", + "Red Alert" = "redalert", + "Biohazard" = "biohazard", + "Lockdown" = "lockdown", + "Happy" = "ai_happy", + "Neutral" = "ai_neutral", + "Very Happy" = "ai_veryhappy", + "Sad" = "ai_sad", + "Unsure" = "ai_unsure", + "Confused" = "ai_confused", + "Surprised" = "ai_surprised", + "BSOD" = "ai_bsod" + ) + + command = add_option_port("Command", command_options) + command_map = command_options + + picture = add_option_port("Picture", picture_options) + picture_map = picture_options + +/obj/item/circuit_component/status_display/register_usb_parent(atom/movable/shell) + . = ..() + if(istype(shell, /obj/machinery/status_display)) + connected_display = shell + +/obj/item/circuit_component/status_display/unregister_usb_parent(atom/movable/parent) + connected_display = null + return ..() + +/obj/item/circuit_component/status_display/input_received(datum/port/input/port) + // Just use command handling built into status display. + // The option inputs thankfully sanitize command and picture for us. + + if(!connected_display) + return + + var/command_value = command_map[command.value] + var/datum/signal/status_signal = new(list("command" = command_value)) + switch(command_value) + if("message") + status_signal.data["msg1"] = message1.value + status_signal.data["msg2"] = message2.value + if("alert") + status_signal.data["picture_state"] = picture_map[picture.value] + + connected_display.receive_signal(status_signal) +*/ #undef CHARS_PER_LINE #undef FONT_SIZE #undef FONT_COLOR #undef FONT_STYLE -#undef SCROLL_SPEED +#undef SCROLL_RATE +#undef LINE1_Y +#undef LINE2_Y diff --git a/code/modules/mob/living/silicon/ai/death.dm b/code/modules/mob/living/silicon/ai/death.dm index afabafd929..14f9490481 100644 --- a/code/modules/mob/living/silicon/ai/death.dm +++ b/code/modules/mob/living/silicon/ai/death.dm @@ -2,6 +2,10 @@ if(stat == DEAD) return + if(!gibbed) + // Will update all AI status displays with a blue screen of death + INVOKE_ASYNC(src, .proc/emote, "bsod") + . = ..() var/old_icon = icon_state @@ -29,12 +33,6 @@ spawn(10) explosion(src.loc, 3, 6, 12, 15) - if(src.key) - for(var/each in GLOB.ai_status_displays) //change status - var/obj/machinery/status_display/ai/O = each - O.mode = 2 - O.update() - if(istype(loc, /obj/item/aicard/aitater)) loc.icon_state = "aitater-404" else if(istype(loc, /obj/item/aicard/aispook)) diff --git a/code/modules/mob/living/silicon/ai/emote.dm b/code/modules/mob/living/silicon/ai/emote.dm new file mode 100644 index 0000000000..c48fefbe1f --- /dev/null +++ b/code/modules/mob/living/silicon/ai/emote.dm @@ -0,0 +1,101 @@ +/datum/emote/ai + mob_type_allowed_typecache = /mob/living/silicon/ai + mob_type_blacklist_typecache = list() + + +/datum/emote/ai/emotion_display + key = "blank" + var/emotion = AI_EMOTION_BLANK + +/datum/emote/ai/emotion_display/run_emote(mob/user, params, type_override, intentional) + . = ..() + if(!.) + return + var/mob/living/silicon/ai/ai = user + var/turf/ai_turf = get_turf(ai) + + for(var/_display in GLOB.ai_status_displays) + var/obj/machinery/status_display/ai/ai_display = _display + var/turf/display_turf = get_turf(ai_display) + + // Derelict AIs can't affect station displays. + // TODO does this need to be made multiZ aware? + if(ai_turf.z != display_turf.z) + continue + + ai_display.emotion = emotion + ai_display.update() + +/datum/emote/ai/emotion_display/very_happy + key = "veryhappy" + emotion = AI_EMOTION_VERY_HAPPY + +/datum/emote/ai/emotion_display/happy + key = "happy" + emotion = AI_EMOTION_HAPPY + +/datum/emote/ai/emotion_display/neutral + key = "neutral" + emotion = AI_EMOTION_NEUTRAL + +/datum/emote/ai/emotion_display/unsure + key = "unsure" + emotion = AI_EMOTION_UNSURE + +/datum/emote/ai/emotion_display/confused + key = "confused" + emotion = AI_EMOTION_CONFUSED + +/datum/emote/ai/emotion_display/sad + key = "sad" + emotion = AI_EMOTION_SAD + +/datum/emote/ai/emotion_display/bsod + key = "bsod" + emotion = AI_EMOTION_BSOD + +/datum/emote/ai/emotion_display/trollface + key = "trollface" + emotion = AI_EMOTION_PROBLEMS + +/datum/emote/ai/emotion_display/awesome + key = "awesome" + emotion = AI_EMOTION_AWESOME + +/datum/emote/ai/emotion_display/dorfy + key = "dorfy" + emotion = AI_EMOTION_DORFY + +/datum/emote/ai/emotion_display/thinking + key = "thinking" + emotion = AI_EMOTION_THINKING + +/datum/emote/ai/emotion_display/facepalm + key = "facepalm" + key_third_person = "facepalms" + emotion = AI_EMOTION_FACEPALM + +/datum/emote/ai/emotion_display/friend_computer + key = "friendcomputer" + emotion = AI_EMOTION_FRIEND_COMPUTER + +/datum/emote/ai/emotion_display/friend_computer/run_emote(mob/user, params, type_override, intentional) + . = ..() + if(!.) + return + + var/datum/radio_frequency/frequency = SSradio.return_frequency(FREQ_STATUS_DISPLAYS) + + if(!frequency) + return + + var/datum/signal/status_signal = new(list("command" = "friendcomputer")) + frequency.post_signal(src, status_signal) + +/datum/emote/ai/emotion_display/blue_glow + key = "blueglow" + emotion = AI_EMOTION_BLUE_GLOW + +/datum/emote/ai/emotion_display/red_glow + key = "redglow" + emotion = AI_EMOTION_RED_GLOW diff --git a/code/modules/mob/living/silicon/ai/login.dm b/code/modules/mob/living/silicon/ai/login.dm index 36e87a8e16..a1826c38af 100644 --- a/code/modules/mob/living/silicon/ai/login.dm +++ b/code/modules/mob/living/silicon/ai/login.dm @@ -1,11 +1,5 @@ /mob/living/silicon/ai/Login() ..() - if(stat != DEAD) - for(var/each in GLOB.ai_status_displays) //change status - var/obj/machinery/status_display/ai/O = each - O.mode = 1 - O.emotion = emote_display - O.update() set_eyeobj_visible(TRUE) if(multicam_on) end_multicam() diff --git a/code/modules/mob/living/silicon/ai/logout.dm b/code/modules/mob/living/silicon/ai/logout.dm index 73161f12d5..a027871716 100644 --- a/code/modules/mob/living/silicon/ai/logout.dm +++ b/code/modules/mob/living/silicon/ai/logout.dm @@ -1,8 +1,4 @@ /mob/living/silicon/ai/Logout() ..() - for(var/each in GLOB.ai_status_displays) //change status - var/obj/machinery/status_display/ai/O = each - O.mode = 0 - O.update() set_eyeobj_visible(FALSE) view_core() diff --git a/code/modules/research/designs/autolathe_desings/autolathe_designs_construction.dm b/code/modules/research/designs/autolathe_desings/autolathe_designs_construction.dm index f8cf5c1d84..0fdef4819e 100644 --- a/code/modules/research/designs/autolathe_desings/autolathe_designs_construction.dm +++ b/code/modules/research/designs/autolathe_desings/autolathe_designs_construction.dm @@ -75,6 +75,14 @@ build_path = /obj/item/wallframe/newscaster category = list("initial", "Construction") +/datum/design/status_display_frame + name = "Status Display Frame" + id = "status_display_frame" + build_type = AUTOLATHE + materials = list(/datum/material/iron = 14000, /datum/material/glass = 8000) + build_path = /obj/item/wallframe/status_display + category = list("initial", "Construction") + /datum/design/turret_control_frame name = "Turret Control Frame" id = "turret_control" diff --git a/icons/obj/wallframe.dmi b/icons/obj/wallframe.dmi index 70149901e33acdf8a077fe7f7b4b2850bc183d0c..c447263db585214ee75ae9e0148778e0e05256b9 100644 GIT binary patch delta 916 zcmV;F18e-F2<8ZovmO9503aYBCM6^|I5{sbYu1?Fm$3Lt%T*`rhJN9otjatLEIvJ4C|Z)j{o7Ybj>5>~h&{ zrEq|QuU)O$zWF@u1+yDQMI>Rl1!{D&A4_$0rjt_D+-hU5{M$#OOq1x4P)Sc3I&~90S|@|pbkJiH4%L?pje=O$rW(J zQNWO^k49EjFpe0|6XXaq4GSidiDh8{A;EYWQXse`Px4(Lu&h8pN-+I;Kby^r2f9Gb z6Wn2e6$wrg493%Y%RtZtih4_G5r#eohB2O^>V*juVuBh6tPyp86(M}V8411-1%hSq zAl_u4j=oL>4*_|CM?{{0Cz1KjAcibxW5J`Ms)RYfJwnGQ2;a#QbOE*(e?t!HBZERp zfO;edTy$t#=n@zOtq@5f@AXt~M(AQZvYQE*Zmg)NsQ9OtF;}W@#9YOI>PG=s4Q38m zfoVSZAOn-YOk_`gk};sFPa!0Moh5mvL3;jdALs%b&K+pGt_v|}bnWDwrhdXn9|{C> zXYSa~5H2tfJ}*-OUH_f|8Q28Q%30YV9A)7Iw3$Mo0)XCBum qg10{WIjlX_`XwIZI`u0mO7a&02gh-2%)#sc0000`6 delta 849 zcmV-X1Frn$2%`v)vmU^}zyLDVa2==PC zwMzx67~mb!;1UlwRcs26->694D!QFt`j%7LYkg}vTeS_mFbPGr7kl3A!OYZa$ZJJ5QYP|C@7IqTdhT@t0s+UPFyi+ z@e*xq`~Uw@XSqeq0EI$7^zh(u{UGz4cV=0xuKpW@OY#K(w=KEVihtVPh2R1;6ud_T?RHz}d^n|ZCh)gmw~KAUQ^B?V5t#u9 zWLfB(b0+ATX3za33Yw9B0+I9sNQIEf*&w=>N3uZw6e$q;1CPE?84T#9U>MMgPY@w6 z3@#XrMwD^^l3+OYNf6xNL%#I{lzIXz!T9stWHK@D;{|$@;Fb$$Ab6diHyqzl6NndR z`VH11PW%i^b2x_Ti3v0`!IePhAa)l4uHX+6d_e^gr6LI*GE#wmuh)Wmk0`+d5G4>X zF80bO*)vFH%4NCw$k|ZHGv?*LtNpZm~K`^s_XZG}ou?2^*r)Ay(du6YtOSbsRS+Hg937|etu;2!WkR^eUoM1ll zTQtiu1Ls9xAVaoSe>>#$CQiWF`a5)+X`h}793;VRw|m~X?D@*l3l6b@{kQM?=l$_$ zACIv9__@zpz+1m%9`2fRi}E-s9LqOskRj)QWvs1@i{%t3B7g|a`ta+pb_%Lr{42Ah bBqP581SE_f9Ixn#00000NkvXXu0mjfubg~C diff --git a/tgstation.dme b/tgstation.dme index f3d34ee6bd..f17fa4a25d 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -2726,6 +2726,7 @@ #include "code\modules\mob\living\silicon\ai\ai_defense.dm" #include "code\modules\mob\living\silicon\ai\ai_portrait_picker.dm" #include "code\modules\mob\living\silicon\ai\death.dm" +#include "code\modules\mob\living\silicon\ai\emote.dm" #include "code\modules\mob\living\silicon\ai\examine.dm" #include "code\modules\mob\living\silicon\ai\laws.dm" #include "code\modules\mob\living\silicon\ai\life.dm"