From dc83eff4ef0788ecd6226e26e76b65e3d68ec5e2 Mon Sep 17 00:00:00 2001 From: MrMelbert <51863163+MrMelbert@users.noreply.github.com> Date: Sun, 16 Jul 2023 14:38:42 -0500 Subject: [PATCH] Signalizes an AI card thing (#76869) ## About The Pull Request Changes this code to be signalized on AI cards https://github.com/tgstation/tgstation/blob/76bddbd90306829291896e9b90e6e8071933e6fa/code/modules/mob/living/silicon/ai/death.dm#L44-L49 Minor code improvements as well (Moving the sleep out from flushing into its own async proc) ## Why It's Good For The Game Cringe code ## Changelog :cl: Melbert code: AI cards should react more snap-ily to having their occupant perish /:cl: --- code/game/objects/items/devices/aicard.dm | 94 +++++++++++++++------ code/game/objects/structures/ai_core.dm | 1 + code/modules/mob/living/silicon/ai/death.dm | 7 -- code/modules/power/apc/apc_malf.dm | 27 +++--- 4 files changed, 82 insertions(+), 47 deletions(-) diff --git a/code/game/objects/items/devices/aicard.dm b/code/game/objects/items/devices/aicard.dm index e99811e4bfa..71b6080f6ce 100644 --- a/code/game/objects/items/devices/aicard.dm +++ b/code/game/objects/items/devices/aicard.dm @@ -3,6 +3,7 @@ desc = "A storage device for AIs. Patent pending." icon = 'icons/obj/aicards.dmi' icon_state = "aicard" // aicard-full + base_icon_state = "aicard" inhand_icon_state = "electronic" worn_icon_state = "electronic" lefthand_file = 'icons/mob/inhands/items/devices_lefthand.dmi' @@ -15,7 +16,6 @@ /obj/item/aicard/Destroy(force) if(AI) - AI.death() AI.ghostize(can_reenter_corpse = FALSE) QDEL_NULL(AI) @@ -25,47 +25,80 @@ name = "intelliTater" desc = "A stylish upgrade (?) to the intelliCard." icon_state = "aitater" + base_icon_state = "aitater" /obj/item/aicard/aispook name = "intelliLantern" desc = "A spoOoOoky upgrade to the intelliCard." icon_state = "aispook" + base_icon_state = "aispook" /obj/item/aicard/suicide_act(mob/living/user) user.visible_message(span_suicide("[user] is trying to upload [user.p_them()]self into [src]! That's not going to work out well!")) return BRUTELOSS /obj/item/aicard/pre_attack(atom/target, mob/living/user, params) - if(AI) //AI is on the card, implies user wants to upload it. - var/our_ai = AI - target.transfer_ai(AI_TRANS_FROM_CARD, user, AI, src) - if(!AI) - log_combat(user, our_ai, "uploaded", src, "to [target].") - update_appearance() + . = ..() + if(.) + return + + if(AI) + if(upload_ai(target, user)) return TRUE - else //No AI on the card, therefore the user wants to download one. - target.transfer_ai(AI_TRANS_TO_CARD, user, null, src) - if(AI) - log_silicon("[key_name(user)] carded [key_name(AI)]", src) - update_appearance() + else + if(capture_ai(target, user)) return TRUE - return ..() + +/// Tries to get an AI from the atom clicked +/obj/item/aicard/proc/capture_ai(atom/from_what, mob/living/user) + from_what.transfer_ai(AI_TRANS_TO_CARD, user, null, src) + if(isnull(AI)) + return FALSE + + log_silicon("[key_name(user)] carded [key_name(AI)]", src) + update_appearance() + AI.cancel_camera() + RegisterSignal(AI, COMSIG_MOB_STATCHANGE, PROC_REF(on_ai_stat_change)) + return TRUE + +/// Tries to upload the AI we have captured to the atom clicked +/obj/item/aicard/proc/upload_ai(atom/to_what, mob/living/user) + var/mob/living/silicon/ai/old_ai = AI + to_what.transfer_ai(AI_TRANS_FROM_CARD, user, AI, src) + if(!isnull(AI)) + return FALSE + + log_combat(user, old_ai, "uploaded", src, "to [to_what].") + update_appearance() + old_ai.cancel_camera() + UnregisterSignal(old_ai, COMSIG_MOB_STATCHANGE) + return TRUE + +/obj/item/aicard/proc/on_ai_stat_change(datum/source, new_stat, old_stat) + SIGNAL_HANDLER + + if(new_stat == DEAD || old_stat == DEAD) + update_appearance() + +/obj/item/aicard/update_name(updates) + . = ..() + if(AI) + name = "[initial(name)] - [AI.name]" + else + name = initial(name) /obj/item/aicard/update_icon_state() - if(!AI) - name = initial(name) - icon_state = initial(icon_state) - return ..() - name = "[initial(name)] - [AI.name]" - icon_state = "[initial(icon_state)][AI.stat == DEAD ? "-404" : "-full"]" - AI.cancel_camera() + if(AI) + icon_state = "[base_icon_state][AI.stat == DEAD ? "-404" : "-full"]" + else + icon_state = base_icon_state return ..() /obj/item/aicard/update_overlays() . = ..() if(!AI?.control_disabled) return - . += "[initial(icon_state)]-on" + . += "[base_icon_state]-on" /obj/item/aicard/ui_state(mob/user) return GLOB.hands_state @@ -101,13 +134,7 @@ var/confirm = tgui_alert(usr, "Are you sure you want to wipe this card's memory?", name, list("Yes", "No")) if(confirm == "Yes" && !..()) flush = TRUE - if(AI && AI.loc == src) - to_chat(AI, span_userdanger("Your core files are being wiped!")) - while(AI.stat != DEAD && flush) - AI.adjustOxyLoss(5) - AI.updatehealth() - sleep(0.5 SECONDS) - flush = FALSE + wipe_ai() . = TRUE if("wireless") AI.control_disabled = !AI.control_disabled @@ -122,3 +149,14 @@ to_chat(AI, span_warning("Your Subspace Transceiver has been [AI.radio_enabled ? "enabled" : "disabled"]!")) . = TRUE update_appearance() + +/obj/item/aicard/proc/wipe_ai() + set waitfor = FALSE + + if(AI && AI.loc == src) + to_chat(AI, span_userdanger("Your core files are being wiped!")) + while(AI.stat != DEAD && flush) + AI.adjustOxyLoss(5) + AI.updatehealth() + sleep(0.5 SECONDS) + flush = FALSE diff --git a/code/game/objects/structures/ai_core.dm b/code/game/objects/structures/ai_core.dm index 4ed67e3b3c6..690a4e35a8b 100644 --- a/code/game/objects/structures/ai_core.dm +++ b/code/game/objects/structures/ai_core.dm @@ -409,6 +409,7 @@ That prevents a few funky behaviors. /atom/proc/transfer_ai(interaction, mob/user, mob/living/silicon/ai/AI, obj/item/aicard/card) + SHOULD_CALL_PARENT(TRUE) if(istype(card)) if(card.flush) to_chat(user, span_alert("ERROR: AI flush is in progress, cannot execute transfer protocol.")) diff --git a/code/modules/mob/living/silicon/ai/death.dm b/code/modules/mob/living/silicon/ai/death.dm index 52546c6109f..7a7e238b296 100644 --- a/code/modules/mob/living/silicon/ai/death.dm +++ b/code/modules/mob/living/silicon/ai/death.dm @@ -41,13 +41,6 @@ if(explosive) addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(explosion), loc, 3, 6, 12, null, 15), 1 SECONDS) - if(istype(loc, /obj/item/aicard/aitater)) - loc.icon_state = "aitater-404" - else if(istype(loc, /obj/item/aicard/aispook)) - loc.icon_state = "aispook-404" - else if(istype(loc, /obj/item/aicard)) - loc.icon_state = "aicard-404" - /mob/living/silicon/ai/proc/ShutOffDoomsdayDevice() if(nuking) nuking = FALSE diff --git a/code/modules/power/apc/apc_malf.dm b/code/modules/power/apc/apc_malf.dm index 77dfc3f5a0e..f13b588842a 100644 --- a/code/modules/power/apc/apc_malf.dm +++ b/code/modules/power/apc/apc_malf.dm @@ -77,26 +77,29 @@ disk_pinpointers.alert = FALSE /obj/machinery/power/apc/transfer_ai(interaction, mob/user, mob/living/silicon/ai/AI, obj/item/aicard/card) + . = ..() + if(!.) + return if(card.AI) to_chat(user, span_warning("[card] is already occupied!")) - return + return FALSE if(!occupier) to_chat(user, span_warning("There's nothing in [src] to transfer!")) - return + return FALSE if(!occupier.mind || !occupier.client) to_chat(user, span_warning("[occupier] is either inactive or destroyed!")) - return + return FALSE if(!occupier.parent.stat) to_chat(user, span_warning("[occupier] is refusing all attempts at transfer!") ) - return + return FALSE if(transfer_in_progress) to_chat(user, span_warning("There's already a transfer in progress!")) - return + return FALSE if(interaction != AI_TRANS_TO_CARD || occupier.stat) - return + return FALSE var/turf/user_turf = get_turf(user) if(!user_turf) - return + return FALSE transfer_in_progress = TRUE user.visible_message(span_notice("[user] slots [card] into [src]..."), span_notice("Transfer process initiated. Sending request for AI approval...")) playsound(src, 'sound/machines/click.ogg', 50, TRUE) @@ -105,21 +108,21 @@ to_chat(user, span_danger("AI denied transfer request. Process terminated.")) playsound(src, 'sound/machines/buzz-sigh.ogg', 50, TRUE) transfer_in_progress = FALSE - return + return FALSE if(user.loc != user_turf) to_chat(user, span_danger("Location changed. Process terminated.")) to_chat(occupier, span_warning("[user] moved away! Transfer canceled.")) transfer_in_progress = FALSE - return + return FALSE to_chat(user, span_notice("AI accepted request. Transferring stored intelligence to [card]...")) to_chat(occupier, span_notice("Transfer starting. You will be moved to [card] shortly.")) if(!do_after(user, 50, target = src)) to_chat(occupier, span_warning("[user] was interrupted! Transfer canceled.")) transfer_in_progress = FALSE - return + return FALSE if(!occupier || !card) transfer_in_progress = FALSE - return + return FALSE user.visible_message(span_notice("[user] transfers [occupier] to [card]!"), span_notice("Transfer complete! [occupier] is now stored in [card].")) to_chat(occupier, span_notice("Transfer complete! You've been stored in [user]'s [card.name].")) occupier.forceMove(card) @@ -128,4 +131,4 @@ occupier.cancel_camera() occupier = null transfer_in_progress = FALSE - return + return TRUE