From 3e0a36e0382198bd25b47aceca250ca11fccfdcb Mon Sep 17 00:00:00 2001 From: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Date: Wed, 9 Aug 2023 00:24:17 +0200 Subject: [PATCH] [MIRROR] pAIs can be inserted into a MODsuit [MDB IGNORE] (#22852) * pAIs can be inserted into a MODsuit * Update MODsuit.tsx * Update objective_items.dm * Update mod_actions.dm * Update mod_activation.dm * Update mod_control.dm * Update mod_ui.dm * Update MODsuit.tsx * Update modules_ninja.dm * prettier * Update mod_control.dm * This is torture * Removes most of the overrides for pAIs in MODsuits, to use the procs from upstream (and reduce the amount of clutter/duplication) * Damnit keyboard * Good catch Vinyl! Co-authored-by: Bloop <13398309+vinylspiders@users.noreply.github.com> --------- Co-authored-by: Jacquerel Co-authored-by: Bloop <13398309+vinylspiders@users.noreply.github.com> Co-authored-by: GoldenAlpharex Co-authored-by: GoldenAlpharex <58045821+GoldenAlpharex@users.noreply.github.com> --- code/game/gamemodes/objective_items.dm | 3 +- code/game/objects/items.dm | 14 +- code/modules/mod/mod_actions.dm | 45 +++--- code/modules/mod/mod_activation.dm | 15 +- code/modules/mod/mod_ai.dm | 120 +++++++++++--- code/modules/mod/mod_control.dm | 54 +++---- code/modules/mod/mod_ui.dm | 26 +-- code/modules/mod/modules/modules_ninja.dm | 6 +- .../modules/modsuit_pai/code/mod_pai.dm | 150 +----------------- tgui/packages/tgui/interfaces/MODsuit.tsx | 37 ++--- 10 files changed, 196 insertions(+), 274 deletions(-) diff --git a/code/game/gamemodes/objective_items.dm b/code/game/gamemodes/objective_items.dm index 8a9945d1d1d..8325c2460ad 100644 --- a/code/game/gamemodes/objective_items.dm +++ b/code/game/gamemodes/objective_items.dm @@ -365,7 +365,8 @@ // SKYRAT REMOVAL START - MOD PAI /*else if(istype(potential_storage, /obj/item/mod/control)) var/obj/item/mod/control/suit = potential_storage - being = suit.ai + if(isAI(suit.ai_assistant)) + being = suit.ai_assistant */ // SKYRAT REMOVAL END else stack_trace("check_special_completion() called on [src] with [potential_storage] ([potential_storage.type])! That's not supposed to happen!") diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index 767f215cbf6..0ca75c35850 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -302,14 +302,16 @@ LAZYADD(actions, action) RegisterSignal(action, COMSIG_QDELETING, PROC_REF(on_action_deleted)) - if(ismob(loc)) - // We're being held or are equipped by someone while adding an action? - // Then they should also probably be granted the action, given it's in a correct slot - var/mob/holder = loc - give_item_action(action, holder, holder.get_slot_by_item(src)) - + grant_action_to_bearer(action) return action +/// Grant the action to anyone who has this item equipped to an appropriate slot +/obj/item/proc/grant_action_to_bearer(datum/action/action) + if(!ismob(loc)) + return + var/mob/holder = loc + give_item_action(action, holder, holder.get_slot_by_item(src)) + /// Removes an instance of an action from our list of item actions. /obj/item/proc/remove_item_action(datum/action/action) if(!action) diff --git a/code/modules/mod/mod_actions.dm b/code/modules/mod/mod_actions.dm index eca29c8293e..d82912055e2 100644 --- a/code/modules/mod/mod_actions.dm +++ b/code/modules/mod/mod_actions.dm @@ -11,24 +11,22 @@ if(!istype(Target, /obj/item/mod/control)) qdel(src) return - // SKYRAT EDIT START - pAIs in MODsuits - if(pai_action) - background_icon_state = "bg_tech" - // SKYRAT EDIT END + if(ai_action) + background_icon_state = ACTION_BUTTON_DEFAULT_BACKGROUND /datum/action/item_action/mod/Grant(mob/user) var/obj/item/mod/control/mod = target - if(pai_action && user != mod.mod_pai) // SKYRAT EDIT - pAIs in MODsuits + if(ai_action && user != mod.ai_assistant) return - else if(!pai_action && user == mod.mod_pai) // SKYRAT EDIT - pAIs in MODsuits + else if(!ai_action && user == mod.ai_assistant) return return ..() /datum/action/item_action/mod/Remove(mob/user) var/obj/item/mod/control/mod = target - if(pai_action && user != mod.mod_pai) // SKYRAT EDIT - pAIs in MODsuits + if(ai_action && user != mod.ai_assistant) return - else if(!pai_action && user == mod.mod_pai) // SKYRAT EDIT - pAIs in MODsuits + else if(!ai_action && user == mod.ai_assistant) return return ..() @@ -125,40 +123,36 @@ var/override = FALSE /// Module we are linked to. var/obj/item/mod/module/module - /// A ref to the mob we are pinned to. - var/pinner_ref + /// A reference to the mob we are pinned to. + var/mob/pinner /datum/action/item_action/mod/pinned_module/New(Target, obj/item/mod/module/linked_module, mob/user) - // SKYRAT EDIT START - pAIs in MODsuits - var/obj/item/mod/control/mod = Target // We have to do this otherwise it's going to runtime - if(user == mod.mod_pai) - pai_action = TRUE - // SKYRAT EDIT END - if(isAI(user)) + var/obj/item/mod/control/mod = Target + if(user == mod.ai_assistant) ai_action = TRUE button_icon = linked_module.icon button_icon_state = linked_module.icon_state - ..() + . = ..() module = linked_module + pinner = user + module.pinned_to[REF(user)] = src if(linked_module.allow_flags & MODULE_ALLOW_INCAPACITATED) // clears check hands and check conscious check_flags = NONE name = "Activate [capitalize(linked_module.name)]" desc = "Quickly activate [linked_module]." RegisterSignals(linked_module, list(COMSIG_MODULE_ACTIVATED, COMSIG_MODULE_DEACTIVATED, COMSIG_MODULE_USED), PROC_REF(module_interacted_with)) + RegisterSignal(user, COMSIG_QDELETING, PROC_REF(pinner_deleted)) /datum/action/item_action/mod/pinned_module/Destroy() UnregisterSignal(module, list(COMSIG_MODULE_ACTIVATED, COMSIG_MODULE_DEACTIVATED, COMSIG_MODULE_USED)) - module.pinned_to -= pinner_ref + module.pinned_to -= REF(pinner) module = null + pinner = null return ..() /datum/action/item_action/mod/pinned_module/Grant(mob/user) - var/user_ref = REF(user) - if(!pinner_ref) - pinner_ref = user_ref - module.pinned_to[pinner_ref] = src - else if(pinner_ref != user_ref) + if(pinner != user) return return ..() @@ -168,6 +162,11 @@ return module.on_select() +/// If the guy whose UI we are pinned to got deleted +/datum/action/item_action/mod/pinned_module/proc/pinner_deleted() + pinner = null + qdel(src) + /datum/action/item_action/mod/pinned_module/apply_button_overlay(atom/movable/screen/movable/action_button/current_button, force) current_button.cut_overlays() if(override) diff --git a/code/modules/mod/mod_activation.dm b/code/modules/mod/mod_activation.dm index a9c24669a4c..37083aeb2c1 100644 --- a/code/modules/mod/mod_activation.dm +++ b/code/modules/mod/mod_activation.dm @@ -70,6 +70,9 @@ /// Deploys a part of the suit onto the user. /obj/item/mod/control/proc/deploy(mob/user, obj/item/part) + if(!wearer) + playsound(src, 'sound/machines/scanbuzz.ogg', 25, TRUE, SILENCED_SOUND_EXTRARANGE) + return FALSE // pAI is trying to deploy it from your hands if(part.loc != src) if(!user) return FALSE @@ -162,11 +165,9 @@ module.on_deactivation(display_message = FALSE) activating = TRUE to_chat(wearer, span_notice("MODsuit [active ? "shutting down" : "starting up"].")) - // SKYRAT EDIT START - pAIs in MODsuits - if(mod_pai) - to_chat(mod_pai, span_notice("MODsuit [active ? "shutting down" : "starting up"].")) - // SKYRAT EDIT END + if (ai_assistant) + to_chat(ai_assistant, span_notice("MODsuit [active ? "shutting down" : "starting up"].")) if(do_after(wearer, activation_step_time, wearer, MOD_ACTIVATION_STEP_FLAGS, extra_checks = CALLBACK(src, PROC_REF(has_wearer)))) to_chat(wearer, span_notice("[boots] [active ? "relax their grip on your legs" : "seal around your feet"].")) playsound(src, 'sound/mecha/mechmove03.ogg', 25, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) @@ -185,10 +186,8 @@ seal_part(helmet, seal = !active) if(do_after(wearer, activation_step_time, wearer, MOD_ACTIVATION_STEP_FLAGS, extra_checks = CALLBACK(src, PROC_REF(has_wearer)))) to_chat(wearer, span_notice("Systems [active ? "shut down. Parts unsealed. Goodbye" : "started up. Parts sealed. Welcome"], [wearer].")) - // SKYRAT EDIT START - pAIs in MODsuits - if(mod_pai) - to_chat(mod_pai, span_notice("SYSTEMS [active ? "DEACTIVATED. GOODBYE" : "ACTIVATED. WELCOME"]: \"[mod_pai]\"")) - // SKYRAT EDIT END + if(ai_assistant) + to_chat(ai_assistant, span_notice("SYSTEMS [active ? "DEACTIVATED. GOODBYE" : "ACTIVATED. WELCOME"]: \"[ai_assistant]\"")) finish_activation(on = !active) if(active) playsound(src, 'sound/machines/synth_yes.ogg', 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE, frequency = 6000) diff --git a/code/modules/mod/mod_ai.dm b/code/modules/mod/mod_ai.dm index 97fdcd364ee..fb83518c562 100644 --- a/code/modules/mod/mod_ai.dm +++ b/code/modules/mod/mod_ai.dm @@ -1,43 +1,35 @@ -/* SKYRAT EDIT REMOVAL - pAIs in MODsuits /obj/item/mod/control/transfer_ai(interaction, mob/user, mob/living/silicon/ai/intAI, obj/item/aicard/card) . = ..() if(!.) return + // SKYRAT EDIT ADDITION START - No AIs in MODsuits + if(!allow_ai) + return + // SKYRAT EDIT END if(!open) //mod must be open balloon_alert(user, "suit must be open to transfer!") return switch(interaction) if(AI_TRANS_TO_CARD) - if(!ai) + if(!ai_assistant) balloon_alert(user, "no ai in suit!") return balloon_alert(user, "transferring to card...") if(!do_after(user, 5 SECONDS, target = src)) balloon_alert(user, "interrupted!") return - if(!ai) + if(!ai_assistant) + balloon_alert(user, "no ai in suit!") return - intAI = ai - intAI.ai_restore_power()//So the AI initially has power. - intAI.control_disabled = TRUE - intAI.radio_enabled = FALSE - intAI.disconnect_shell() - intAI.forceMove(card) - card.AI = intAI - for(var/datum/action/action as anything in actions) - action.Remove(intAI) - intAI.controlled_equipment = null - intAI.remote_control = null - balloon_alert(intAI, "transferred to a card") balloon_alert(user, "ai transferred to card") - ai = null + ai_exit_mod(card) if(AI_TRANS_FROM_CARD) //Using an AI card to upload to the suit. intAI = card.AI if(!intAI) balloon_alert(user, "no ai in card!") return - if(ai) + if(ai_assistant) balloon_alert(user, "already has ai!") return if(intAI.deployed_shell) //Recall AI if shelled so it can be checked for a client @@ -49,12 +41,13 @@ if(!do_after(user, 5 SECONDS, target = src)) balloon_alert(user, "interrupted!") return - if(ai) + if(ai_assistant) return balloon_alert(user, "ai transferred to suit") ai_enter_mod(intAI) card.AI = null +/// Place an AI in control of your suit functions /obj/item/mod/control/proc/ai_enter_mod(mob/living/silicon/ai/new_ai) new_ai.control_disabled = FALSE new_ai.radio_enabled = TRUE @@ -63,10 +56,84 @@ new_ai.controlled_equipment = src new_ai.remote_control = src new_ai.forceMove(src) - ai = new_ai - balloon_alert(new_ai, "transferred to a suit") + on_gained_assistant(new_ai) + +/// Remove an AI's control of your suit functions +/obj/item/mod/control/proc/ai_exit_mod(obj/item/aicard/card) + var/mob/living/silicon/ai/old_ai = ai_assistant + old_ai.ai_restore_power()//So the AI initially has power. + old_ai.control_disabled = TRUE + old_ai.radio_enabled = FALSE + old_ai.disconnect_shell() + old_ai.forceMove(card) + card.AI = old_ai + old_ai.controlled_equipment = null + on_removed_assistant(old_ai) + +/// Place a pAI in control of your suit functions +/obj/item/mod/control/proc/insert_pai(mob/user, obj/item/pai_card/card) + if (!isnull(ai_assistant)) + balloon_alert(user, "slot occupied!") + return FALSE + if (isnull(card.pai?.mind)) + balloon_alert(user, "pAI unresponsive!") + return FALSE + balloon_alert(user, "transferring to suit...") + if (!do_after(user, 5 SECONDS, target = src)) + balloon_alert(user, "interrupted!") + return FALSE + if (!user.transferItemToLoc(card, src)) + balloon_alert(user, "transfer failed!") + return FALSE + balloon_alert(user, "pAI transferred to suit") + var/mob/living/silicon/pai/pai_assistant = card.pai + pai_assistant.can_transmit = TRUE + pai_assistant.can_receive = TRUE + pai_assistant.can_holo = FALSE + if (pai_assistant.holoform) + pai_assistant.fold_in() + // SKYRAT EDIT ADDITION START - pAIs in MODsuits + if(can_pai_move_suit) + pai_assistant.remote_control = src + // SKYRAT EDIT END + SStgui.close_uis(card) + on_gained_assistant(card.pai) + return TRUE + +/// Removes pAI control from a modsuit +/obj/item/mod/control/proc/remove_pai(mob/user, forced = FALSE) + if (isnull(ai_assistant)) + balloon_alert(user, "no pAI!") + return FALSE + if (!forced) + if (!open) + balloon_alert(user, "suit panel closed!") + return FALSE + balloon_alert(user, "uninstalling card...") + if (!do_after(user, 5 SECONDS, target = src)) + balloon_alert(user, "interrupted!") + return FALSE + + balloon_alert(user, "pAI removed from suit") + var/mob/living/silicon/pai/pai_helper = ai_assistant + pai_helper.can_holo = TRUE + pai_helper.card.forceMove(get_turf(src)) + on_removed_assistant() + +/// Called when a new ai assistant is inserted +/obj/item/mod/control/proc/on_gained_assistant(mob/living/silicon/new_helper) + ai_assistant = new_helper + balloon_alert(new_helper, "transferred to a suit") for(var/datum/action/action as anything in actions) - action.Grant(new_ai) + action.Grant(new_helper) + +/// Called when an existing ai assistant is removed +/obj/item/mod/control/proc/on_removed_assistant() + for(var/datum/action/action as anything in actions) + action.Remove(ai_assistant) + ai_assistant.remote_control = null + balloon_alert(ai_assistant, "transferred to a card") + ai_assistant = null #define MOVE_DELAY 2 #define WEARER_DELAY 1 @@ -75,8 +142,12 @@ #define AI_FALL_TIME (1 SECONDS) /obj/item/mod/control/relaymove(mob/user, direction) - if((!active && wearer) || get_charge() < CHARGE_PER_STEP || user != ai || !COOLDOWN_FINISHED(src, cooldown_mod_move) || (wearer?.pulledby?.grab_state > GRAB_PASSIVE)) + if((!active && wearer) || get_charge() < CHARGE_PER_STEP || user != ai_assistant || !COOLDOWN_FINISHED(src, cooldown_mod_move) || (wearer?.pulledby?.grab_state > GRAB_PASSIVE)) return FALSE + // SKYRAT EDIT START - pAIs in MODsuits with a bit more functionalities + if(active && !can_pai_move_suit && ispAI(ai_assistant)) + return FALSE + // SKYRAT EDIT END var/timemodifier = MOVE_DELAY * (ISDIAGONALDIR(direction) ? sqrt(2) : 1) * (wearer ? WEARER_DELAY : LONE_DELAY) if(wearer && !wearer.Process_Spacemove(direction)) return FALSE @@ -112,8 +183,10 @@ /obj/item/mod/ai_minicard/Initialize(mapload, mob/living/silicon/ai/ai) . = ..() - if(!ai) + if(isnull(ai)) return + ai.controlled_equipment = null + ai.remote_control = null ai.apply_damage(150, BURN) INVOKE_ASYNC(ai, TYPE_PROC_REF(/mob/living/silicon/ai, death)) ai.forceMove(src) @@ -149,4 +222,3 @@ balloon_alert(user, "ai transferred to card") stored_ai = null #undef AI_FALL_TIME -*/ diff --git a/code/modules/mod/mod_control.dm b/code/modules/mod/mod_control.dm index bdc4ce75cf6..5cce89f1511 100644 --- a/code/modules/mod/mod_control.dm +++ b/code/modules/mod/mod_control.dm @@ -21,10 +21,10 @@ /datum/action/item_action/mod/sprite_accessories, // SKYRAT EDIT - Hide mutant parts action /datum/action/item_action/mod/panel, /datum/action/item_action/mod/module, - /datum/action/item_action/mod/deploy/pai, // SKYRAT EDIT - pAIs in MODsuits - /datum/action/item_action/mod/activate/pai, // SKYRAT EDIT - pAIs in MODsuits - /datum/action/item_action/mod/panel/pai, // SKYRAT EDIT - pAIs in MODsuits - /datum/action/item_action/mod/module/pai, // SKYRAT EDIT - pAIs in MODsuits + /datum/action/item_action/mod/deploy/ai, + /datum/action/item_action/mod/activate/ai, + /datum/action/item_action/mod/panel/ai, + /datum/action/item_action/mod/module/ai, ) resistance_flags = NONE max_heat_protection_temperature = SPACE_SUIT_MAX_TEMP_PROTECT @@ -83,10 +83,8 @@ var/list/modules = list() /// Currently used module. var/obj/item/mod/module/selected_module - /* SKYRAT EDIT REMOVAL - MODsuit pAIs - /// AI mob inhabiting the MOD. - var/mob/living/silicon/ai/ai - */ // SKYRAT EDIT END + /// AI or pAI mob inhabiting the MOD. + var/mob/living/silicon/ai_assistant /// Delay between moves as AI. var/static/movedelay = 0 /// Cooldown for AI moves. @@ -189,7 +187,14 @@ var/obj/item/overslot = overslotting_parts[part] overslot.forceMove(drop_location()) overslotting_parts[part] = null - remove_pai() // SKYRAT EDIT - pAIs in MODsuits + if(ai_assistant) + if(ispAI(ai_assistant)) + INVOKE_ASYNC(src, PROC_REF(remove_pai), /* user = */ null, /* forced = */ TRUE) // async to appease spaceman DMM because the branch we don't run has a do_after + else + for(var/datum/action/action as anything in actions) + if(action.owner == ai_assistant) + action.Remove(ai_assistant) + new /obj/item/mod/ai_minicard(drop_location(), ai_assistant) return ..() /obj/item/mod/control/examine(mob/user) @@ -211,12 +216,10 @@ . += span_notice("You could remove [core] with a wrench.") else . += span_notice("You could use a MOD core on it to install one.") - if(!mod_pai) // SKYRAT EDIT BEGIN - PAI in Modsuits - . += span_notice("You could install a pAI with a pAI card.") -/* if(ai) - . += span_notice("You could remove [ai] with an intellicard.") - else - . += span_notice("You could install an AI with an intellicard.") SKYRAT EDIT END */ + if(isnull(ai_assistant)) + . += span_notice("You could install a pAI with a pAI card.") // SKYRAT EDIT CHANGE - ORIGINAL: . += span_notice("You could install an AI or pAI using their storage card.") + else if(isAI(ai_assistant)) + . += span_notice("You could remove [ai_assistant] with an intellicard.") . += span_notice("You could examine it more thoroughly...") /obj/item/mod/control/examine_more(mob/user) @@ -256,6 +259,13 @@ if(slot & slot_flags) return TRUE +// Grant pinned actions to pin owners, gives AI pinned actions to the AI and not the wearer +/obj/item/mod/control/grant_action_to_bearer(datum/action/action) + if (!istype(action, /datum/action/item_action/mod/pinned_module)) + return ..() + var/datum/action/item_action/mod/pinned_module/pinned = action + give_item_action(action, pinned.pinner, slot_flags) + /obj/item/mod/control/Moved(atom/old_loc, movement_dir, forced, list/old_locs, momentum_change = TRUE) . = ..() if(!wearer || old_loc != wearer || loc == wearer) @@ -317,10 +327,8 @@ return ..() /obj/item/mod/control/screwdriver_act(mob/living/user, obj/item/screwdriver) - // SKYRAT EDIT START - pAIs in MODsuits . = ..() if(.) - // SKYRAT EDIT END return TRUE if(active || activating || ai_controller) balloon_alert(user, "deactivate suit first!") @@ -370,14 +378,12 @@ return FALSE /obj/item/mod/control/attackby(obj/item/attacking_item, mob/living/user, params) - // SKYRAT EDIT START - pAIs in MODsuits if(istype(attacking_item, /obj/item/pai_card)) - if(!open) //mod must be open - balloon_alert(user, "suit must be open to transfer!") + if(!open) + balloon_alert(user, "open the cover first!") return FALSE insert_pai(user, attacking_item) return TRUE - // SKYRAT EDIT END if(istype(attacking_item, /obj/item/mod/module)) if(!open) balloon_alert(user, "open the cover first!") @@ -576,12 +582,6 @@ new_module.on_equip() if(active) new_module.on_suit_activation() - // SKYRAT EDIT START - pAIs in MODsuits - if(mod_pai) - var/datum/action/item_action/mod/pinned_module/action = new_module.pinned_to[ref(mod_pai)] - if(action) - action.Grant(mod_pai) - // SKYRAT EDIT END if(user) balloon_alert(user, "[new_module] added") playsound(src, 'sound/machines/click.ogg', 50, TRUE, SILENCED_SOUND_EXTRARANGE) diff --git a/code/modules/mod/mod_ui.dm b/code/modules/mod/mod_ui.dm index 5c4e3328868..cbf30fe1611 100644 --- a/code/modules/mod/mod_ui.dm +++ b/code/modules/mod/mod_ui.dm @@ -12,7 +12,9 @@ "cell_charge_current" = get_charge(), "cell_charge_max" = get_max_charge(), "active" = active, - //"ai_name" = ai?.name, // SKYRAT EDIT REMOVAL - pAIs in MODsuits + "ai_name" = ai_assistant?.name, + "has_pai" = ispAI(ai_assistant), + "is_ai" = ai_assistant && ai_assistant == user, // Wires "open" = open, "seconds_electrified" = seconds_electrified, @@ -21,10 +23,6 @@ "interface_break" = interface_break, // Modules "complexity" = complexity, - // SKYRAT EDIT START - pAIs in MODsuits - "pAI" = mod_pai?.name, - "ispAI" = mod_pai ? mod_pai == user : FALSE, - // SKYRAT EDIT END ) data["suit_status"] = suit_status // User information @@ -69,12 +67,16 @@ data["boots"] = boots?.name return data +/obj/item/mod/control/ui_state(mob/user) + if(user == ai_assistant) + return GLOB.contained_state + return ..() + /obj/item/mod/control/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) . = ..() if(.) return - // allowed() doesn't allow for pAIs - if(((locked && !ispAI(usr)) && !allowed(usr))) // SKYRAT EDIT CHANGE - ORIGINAL: if(locked && !allowed(usr)) + if(locked && (!allowed(usr) || !ispAI(usr))) // pAIs automatically fail out of allowed() balloon_alert(usr, "insufficient access!") playsound(src, 'sound/machines/scanbuzz.ogg', 25, TRUE, SILENCED_SOUND_EXTRARANGE) return @@ -102,10 +104,8 @@ if(!module) return module.pin(usr) - // SKYRAT EDIT START - pAIs in MODsuits - if("remove_pai") - if(ishuman(usr)) // Only the MODsuit's wearer should be removing the pAI. - var/mob/user = usr - extract_pai(user) - // SKYRAT EDIT END + if("eject_pai") + if (!ishuman(usr)) + return + remove_pai(usr) return TRUE diff --git a/code/modules/mod/modules/modules_ninja.dm b/code/modules/mod/modules/modules_ninja.dm index 0b9a804dc52..9f6fd3b702d 100644 --- a/code/modules/mod/modules/modules_ninja.dm +++ b/code/modules/mod/modules/modules_ninja.dm @@ -257,11 +257,9 @@ . = ..() if(. != MOD_CANCEL_ACTIVATE || !isliving(user)) return - // SKYRAT EDIT CHANGE BEGIN - pAIs in MODsuits - `ai` replaced with `mod_pai` - if(mod.mod_pai == user) - to_chat(mod.mod_pai, span_danger("fATaL EERRoR: 381200-*#00CODE BLUE\nAI INTErFERenCE DEtECted\nACTi0N DISrEGArdED")) + if(mod.ai_assistant == user) + to_chat(mod.ai_assistant, span_danger("fATaL EERRoR: 381200-*#00CODE BLUE\nAI INTErFERenCE DEtECted\nACTi0N DISrEGArdED")) return - // SKYRAT EDIT CHANGE END var/mob/living/living_user = user to_chat(living_user, span_danger("fATaL EERRoR: 382200-*#00CODE RED\nUNAUTHORIZED USE DETECteD\nCoMMENCING SUB-R0UTIN3 13...\nTERMInATING U-U-USER...")) living_user.investigate_log("has been gibbed by using a MODsuit equipped with [src].", INVESTIGATE_DEATHS) diff --git a/modular_skyrat/modules/modsuit_pai/code/mod_pai.dm b/modular_skyrat/modules/modsuit_pai/code/mod_pai.dm index 0732d1dd459..521fe7ebcc7 100644 --- a/modular_skyrat/modules/modsuit_pai/code/mod_pai.dm +++ b/modular_skyrat/modules/modsuit_pai/code/mod_pai.dm @@ -1,154 +1,8 @@ -/** - * Simple proc to insert the pAI into the MODsuit. - * - * user - The person trying to put the pAI into the MODsuit. - * card - The pAI card we're slotting in the MODsuit. - */ - -/obj/item/mod/control/proc/insert_pai(mob/user, obj/item/pai_card/card) - if(mod_pai) - balloon_alert(user, "pAI already installed!") - return - if(!card.pai || !card.pai.mind) - balloon_alert(user, "pAI unresponsive!") - return - balloon_alert(user, "transferring to suit...") - if(!do_after(user, 5 SECONDS, target = src)) - balloon_alert(user, "interrupted!") - return FALSE - if(!user.transferItemToLoc(card, src)) - return - - mod_pai = card.pai - balloon_alert(user, "pAI transferred to suit") - balloon_alert(mod_pai, "transferred to a suit") - mod_pai.can_transmit = TRUE - mod_pai.can_receive = TRUE - mod_pai.can_holo = FALSE - mod_pai.remote_control = src - for(var/datum/action/action as anything in actions) - action.Grant(mod_pai) - return TRUE - -/** - * Simple proc to extract the pAI from the MODsuit. It's the proc to call if you want to take it out, - * remove_pai() is there so atom_destruction() doesn't have any risk of sleeping. - * - * user - The person trying to take out the pAI from the MODsuit. - * forced - Whether or not we skip the checks and just eject the pAI. Defaults to FALSE. - * feedback - Whether to give feedback via balloon alerts or not. Defaults to TRUE. - */ -/obj/item/mod/control/proc/extract_pai(mob/user, forced = FALSE, feedback = TRUE) - if(!mod_pai) - if(user && feedback) - balloon_alert(user, "no pAI to remove!") - return - if(!forced) - if(!open) - if(user && feedback) - balloon_alert(user, "open the suit panel!") - return FALSE - if(!do_after(user, 5 SECONDS, target = src)) - if(user && feedback) - balloon_alert(user, "interrupted!") - return FALSE - - remove_pai(feedback) - - if(feedback && user) - balloon_alert(user, "pAI removed from the suit") - -/** - * Simple proc that handles the safe removal of the pAI from a MOD control unit. - * - * Arguments: - * * feedback - Whether or not we want to give balloon alert feedback to the mod_pai. Defaults to FALSE. - */ -/obj/item/mod/control/proc/remove_pai(feedback = FALSE) - var/turf/drop_off = get_turf(src) - if(drop_off) // In case there's no drop_off, the pAI will simply get deleted. - mod_pai.card.forceMove(drop_off) - - for(var/datum/action/action as anything in actions) - if(action.owner == mod_pai) - action.Remove(mod_pai) - - if(feedback) - balloon_alert(mod_pai, "removed from a suit") - mod_pai.remote_control = null - mod_pai.can_holo = TRUE - mod_pai = null - - -#define MOVE_DELAY 2 -#define WEARER_DELAY 1 -#define LONE_DELAY 5 -#define CELL_PER_STEP (DEFAULT_CHARGE_DRAIN * 2.5) -#define PAI_FALL_TIME (1 SECONDS) - -/obj/item/mod/control/relaymove(mob/user, direction) - if((!active && wearer) || (active && !can_pai_move_suit) || !core.charge_source() || core.charge_amount() < CELL_PER_STEP || user != mod_pai || !COOLDOWN_FINISHED(src, cooldown_mod_move)) - return FALSE - if(wearer && (wearer.pulledby?.grab_state || wearer.incapacitated() || wearer.stat)) - return FALSE - var/timemodifier = MOVE_DELAY * (ISDIAGONALDIR(direction) ? sqrt(2) : 1) * (wearer ? WEARER_DELAY : LONE_DELAY) - COOLDOWN_START(src, cooldown_mod_move, movedelay * timemodifier + slowdown) - playsound(src, 'sound/mecha/mechmove01.ogg', 25, TRUE) - core.subtract_charge(CELL_PER_STEP) - if(wearer) - ADD_TRAIT(wearer, TRAIT_FORCED_STANDING, MOD_TRAIT) - addtimer(CALLBACK(src, PROC_REF(pai_fall)), PAI_FALL_TIME, TIMER_UNIQUE | TIMER_OVERRIDE) - if(ismovable(wearer?.loc)) - return wearer.loc.relaymove(wearer, direction) - if(wearer && !wearer.Process_Spacemove(direction)) - return FALSE - var/atom/movable/mover = wearer || src - return mover.try_step_multiz(direction) - -#undef MOVE_DELAY -#undef WEARER_DELAY -#undef LONE_DELAY -#undef CELL_PER_STEP -#undef PAI_FALL_TIME - -/// Simple proc adding the falling of the MODsuit when it's no longer moving, for corpses and unconscious wearers. -/obj/item/mod/control/proc/pai_fall() - if(!wearer) - return - REMOVE_TRAIT(wearer, TRAIT_FORCED_STANDING, MOD_TRAIT) - /** * Misc stuff to avoid having files with three lines in them. */ /obj/item/mod/control - /// pAI mob inhabiting the MOD. - var/mob/living/silicon/pai/mod_pai /// Whether or not an on-board pAI can move the suit. FALSE by default, intended to be modified either via VV or via a possible future pAI program. var/can_pai_move_suit = FALSE - - -/datum/action/item_action/mod - /// Whether this action is intended for the inserted pAI. Stuff breaks a lot if this is done differently. - var/pai_action = FALSE - - -/datum/action/item_action/mod/deploy/pai - pai_action = TRUE - - -/datum/action/item_action/mod/panel/pai - pai_action = TRUE - - -/datum/action/item_action/mod/module/pai - pai_action = TRUE - - -/datum/action/item_action/mod/activate/pai - pai_action = TRUE - - -/obj/item/mod/control/ui_state(mob/user) - if(user == mod_pai) - return GLOB.contained_state - return ..() + /// Whether or not this MODsuit can hold AIs, or if it's restricted to just pAIs. + var/allow_ai = FALSE diff --git a/tgui/packages/tgui/interfaces/MODsuit.tsx b/tgui/packages/tgui/interfaces/MODsuit.tsx index ab3f69c1eda..6e737792447 100644 --- a/tgui/packages/tgui/interfaces/MODsuit.tsx +++ b/tgui/packages/tgui/interfaces/MODsuit.tsx @@ -33,8 +33,8 @@ type SuitStatus = { complexity: number; selected_module: string; ai_name: string; - pAI: string; // SKYRAT EDIT ADDITION - pAIs in MODsuits - ispAI: BooleanLike; // SKYRAT EDIT ADDITION - pAIs in MODsuits + has_pai: boolean; + is_ai: boolean; }; type UserStatus = { @@ -315,8 +315,8 @@ const SuitStatusSection = (props, context) => { malfunctioning, locked, ai_name, - pAI, - ispAI, + has_pai, + is_ai, } = data.suit_status; const { display_time, shift_time, shift_id } = data.module_custom_status; const status = malfunctioning @@ -388,20 +388,17 @@ const SuitStatusSection = (props, context) => { )} {!!ai_name && ( - {ai_name} + + {has_pai && ( +