mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2025-12-12 10:42:37 +00:00
<!-- Write **BELOW** The Headers and **ABOVE** The comments else it may not be viewable. --> <!-- You can view Contributing.MD for a detailed description of the pull request process. --> ## About The Pull Request Renames - `/mob/proc/notify_ghost_cloning` to `/mob/proc/notify_revival` - `/mob/dead/observer/proc/notify_cloning` to `/mob/dead/observer/proc/send_revival_notification` - `/atom/movable/screen/alert/notify_cloning` to `/atom/movable/screen/alert/revival`. I could have found a way to merge both procs together but default parameters keep me up at night. <!-- Describe The Pull Request. Please be sure every change is documented or this can delay review and even discourage maintainers from merging your PR! --> ## Why It's Good For The Game Conciseness, code that is named after a removed feature is silly. <!-- Argue for the merits of your changes and how they benefit the game, especially if they are controversial and/or far reaching. If you can't actually explain WHY what you are doing will improve the game, then it probably isn't good for the game in the first place. --> ## Changelog <!-- If your PR modifies aspects of the game that can be concretely observed by players or admins you should add a changelog. If your change does NOT meet this description, remove this section. Be sure to properly mark your PRs to prevent unnecessary GBP loss. You can read up on GBP and it's effects on PRs in the tgstation guides for contributors. Please note that maintainers freely reserve the right to remove and add tags should they deem it appropriate. You can attempt to finagle the system all you want, but it's best to shoot for clear communication right off the bat. --> nothing playerfacing <!-- Both 🆑's are required for the changelog to work! You can put your name to the right of the first 🆑 if you want to overwrite your GitHub username as author ingame. --> <!-- You can use multiple of the same prefix (they're only used for the icon ingame) and delete the unneeded ones. Despite some of the tags, changelogs should generally represent how a player might be affected by the changes rather than a summary of the PR's contents. -->
214 lines
6.8 KiB
Plaintext
214 lines
6.8 KiB
Plaintext
/obj/item/mod/control/transfer_ai(interaction, mob/user, mob/living/silicon/ai/intAI, obj/item/aicard/card)
|
|
. = ..()
|
|
if(!.)
|
|
return
|
|
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_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_assistant)
|
|
balloon_alert(user, "no ai in suit!")
|
|
return
|
|
balloon_alert(user, "ai transferred to card")
|
|
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_assistant)
|
|
balloon_alert(user, "already has ai!")
|
|
return
|
|
if(intAI.deployed_shell) //Recall AI if shelled so it can be checked for a client
|
|
intAI.disconnect_shell()
|
|
if(intAI.stat || !intAI.client)
|
|
balloon_alert(user, "ai unresponsive!")
|
|
return
|
|
balloon_alert(user, "transferring to suit...")
|
|
if(!do_after(user, 5 SECONDS, target = src))
|
|
balloon_alert(user, "interrupted!")
|
|
return
|
|
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
|
|
new_ai.ai_restore_power()
|
|
new_ai.cancel_camera()
|
|
new_ai.controlled_equipment = src
|
|
new_ai.remote_control = src
|
|
new_ai.forceMove(src)
|
|
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()
|
|
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_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
|
|
#define LONE_DELAY 5
|
|
#define CHARGE_PER_STEP (DEFAULT_CHARGE_DRAIN * 2.5)
|
|
#define AI_FALL_TIME (1 SECONDS)
|
|
|
|
/obj/item/mod/control/relaymove(mob/user, direction)
|
|
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
|
|
var/timemodifier = MOVE_DELAY * (ISDIAGONALDIR(direction) ? sqrt(2) : 1) * (wearer ? WEARER_DELAY : LONE_DELAY)
|
|
if(wearer && !wearer.Process_Spacemove(direction))
|
|
return FALSE
|
|
else if(!wearer && (!has_gravity() || !isturf(loc)))
|
|
return FALSE
|
|
COOLDOWN_START(src, cooldown_mod_move, movedelay * timemodifier + slowdown_active)
|
|
subtract_charge(CHARGE_PER_STEP)
|
|
playsound(src, 'sound/mecha/mechmove01.ogg', 25, TRUE)
|
|
if(ismovable(wearer?.loc))
|
|
return wearer.loc.relaymove(wearer, direction)
|
|
else if(wearer)
|
|
ADD_TRAIT(wearer, TRAIT_FORCED_STANDING, MOD_TRAIT)
|
|
addtimer(CALLBACK(src, PROC_REF(ai_fall)), AI_FALL_TIME, TIMER_UNIQUE | TIMER_OVERRIDE)
|
|
var/atom/movable/mover = wearer || src
|
|
return mover.try_step_multiz(direction)
|
|
|
|
#undef MOVE_DELAY
|
|
#undef WEARER_DELAY
|
|
#undef LONE_DELAY
|
|
#undef CHARGE_PER_STEP
|
|
|
|
/obj/item/mod/control/proc/ai_fall()
|
|
if(!wearer)
|
|
return
|
|
REMOVE_TRAIT(wearer, TRAIT_FORCED_STANDING, MOD_TRAIT)
|
|
|
|
/obj/item/mod/ai_minicard
|
|
name = "AI mini-card"
|
|
desc = "A small card designed to eject dead AIs. You could use an intellicard to recover it."
|
|
icon = 'icons/obj/aicards.dmi'
|
|
icon_state = "minicard"
|
|
var/datum/weakref/stored_ai
|
|
|
|
/obj/item/mod/ai_minicard/Initialize(mapload, mob/living/silicon/ai/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)
|
|
stored_ai = WEAKREF(ai)
|
|
icon_state = "minicard-filled"
|
|
|
|
/obj/item/mod/ai_minicard/Destroy()
|
|
QDEL_NULL(stored_ai)
|
|
return ..()
|
|
|
|
/obj/item/mod/ai_minicard/examine(mob/user)
|
|
. = ..()
|
|
. += span_notice("You see [stored_ai.resolve() || "no AI"] stored inside.")
|
|
|
|
/obj/item/mod/ai_minicard/transfer_ai(interaction, mob/user, mob/living/silicon/ai/intAI, obj/item/aicard/card)
|
|
. = ..()
|
|
if(!.)
|
|
return
|
|
if(interaction != AI_TRANS_TO_CARD)
|
|
return
|
|
var/mob/living/silicon/ai/ai = stored_ai.resolve()
|
|
if(!ai)
|
|
balloon_alert(user, "no ai!")
|
|
return
|
|
balloon_alert(user, "transferring to card...")
|
|
if(!do_after(user, 5 SECONDS, target = src) || !ai)
|
|
balloon_alert(user, "interrupted!")
|
|
return
|
|
icon_state = "minicard"
|
|
ai.forceMove(card)
|
|
card.AI = ai
|
|
ai.notify_revival("You have been recovered from the wreckage!", source = card)
|
|
balloon_alert(user, "ai transferred to card")
|
|
stored_ai = null
|
|
|
|
#undef AI_FALL_TIME
|