mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-24 21:48:39 +01:00
[MDB IGNORE] Cleans up AI core structure, un-spaghettis some AI code (#93873)
## About The Pull Request The AI core structure now fully integrates item/tool interactions and no longer uses attackby/take_damage overrides. Construction behaviour has been isolated into its own file. All handling relating to the AI core's status when shunted has been turned into signals. For this reason, helper procs for managing core link state have been made and integrated into the relevant users (APC shunting, mech takeover). The AI core no longer references the remote AI mob. /obj/structure/ai_core/deactivated has been removed from code since it had no function after refactoring. There was only a single instance of it being used in a map, which has been replaced with a var edit. There may be more things I changed, but I'm h
This commit is contained in:
@@ -288,7 +288,9 @@
|
||||
/turf/open/floor/iron,
|
||||
/area/ruin/space/ancientstation/charlie/bridge)
|
||||
"bA" = (
|
||||
/obj/structure/ai_core/deactivated,
|
||||
/obj/structure/ai_core{
|
||||
state = 5
|
||||
},
|
||||
/turf/open/floor/iron/dark,
|
||||
/area/ruin/space/ancientstation/delta/ai)
|
||||
"bC" = (
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
//Defines for construction states
|
||||
|
||||
//ai core defines
|
||||
#define EMPTY_CORE 0
|
||||
#define CIRCUIT_CORE 1
|
||||
#define SCREWED_CORE 2
|
||||
#define CABLED_CORE 3
|
||||
#define GLASS_CORE 4
|
||||
#define AI_READY_CORE 5
|
||||
#define CORE_STATE_EMPTY 0
|
||||
#define CORE_STATE_CIRCUIT 1
|
||||
#define CORE_STATE_SCREWED 2
|
||||
#define CORE_STATE_CABLED 3
|
||||
#define CORE_STATE_GLASSED 4
|
||||
#define CORE_STATE_FINISHED 5
|
||||
|
||||
//girder construction states
|
||||
#define GIRDER_NORMAL 0
|
||||
|
||||
@@ -8,10 +8,6 @@
|
||||
#define COMSIG_BORG_HUG_HANDLED 1
|
||||
///called from /mob/living/silicon/attack_hand proc
|
||||
#define COMSIG_MOB_PAT_BORG "mob_pat_borg"
|
||||
///called when someone is inquiring about an AI's linked core
|
||||
#define COMSIG_SILICON_AI_CORE_STATUS "AI_core_status"
|
||||
#define COMPONENT_CORE_ALL_GOOD (1<<0)
|
||||
#define COMPONENT_CORE_DISCONNECTED (1<<1)
|
||||
///called when an AI (malf or perhaps combat upgraded or some other circumstance that has them inhabit
|
||||
///an APC) enters an APC
|
||||
#define COMSIG_SILICON_AI_OCCUPY_APC "AI_occupy_apc"
|
||||
|
||||
@@ -0,0 +1,247 @@
|
||||
#define AI_CORE_BRAIN(X) X.braintype == "Android" ? "brain" : "MMI"
|
||||
|
||||
/obj/structure/ai_core
|
||||
name = "\improper AI core"
|
||||
desc = "The framework for an artificial intelligence core."
|
||||
icon = 'icons/mob/silicon/ai.dmi'
|
||||
icon_state = "build_0"
|
||||
base_icon_state = "build_"
|
||||
density = TRUE
|
||||
anchored = FALSE
|
||||
max_integrity = 500
|
||||
var/state = CORE_STATE_EMPTY
|
||||
var/datum/ai_laws/laws
|
||||
var/obj/item/circuitboard/aicore/circuit
|
||||
var/obj/item/mmi/core_mmi
|
||||
|
||||
/obj/structure/ai_core/Initialize(mapload, state = src.state, obj/item/mmi/core_mmi = null)
|
||||
. = ..()
|
||||
laws = new
|
||||
laws.set_laws_config()
|
||||
|
||||
if(core_mmi && state < CORE_STATE_CABLED)
|
||||
stack_trace("supplied a core_mmi as constructor argument, but core state wouldn't have accepted it!")
|
||||
state = CORE_STATE_FINISHED // just in case...
|
||||
src.state = state
|
||||
if(state >= CORE_STATE_CIRCUIT)
|
||||
circuit = new(src)
|
||||
if(state >= CORE_STATE_CABLED)
|
||||
if(!core_mmi)
|
||||
core_mmi = new /obj/item/mmi(src)
|
||||
core_mmi.brain = new(core_mmi)
|
||||
core_mmi.brain.organ_flags |= ORGAN_FROZEN
|
||||
core_mmi.set_brainmob(new /mob/living/brain())
|
||||
core_mmi.brainmob.container = core_mmi
|
||||
core_mmi.update_appearance()
|
||||
core_mmi.forceMove(src)
|
||||
src.core_mmi = core_mmi
|
||||
set_anchored(TRUE)
|
||||
|
||||
update_appearance(UPDATE_ICON_STATE)
|
||||
|
||||
/obj/structure/ai_core/update_icon_state()
|
||||
if(state != CORE_STATE_FINISHED)
|
||||
icon_state = "[base_icon_state][state]"
|
||||
if(state == CORE_STATE_CABLED && core_mmi)
|
||||
icon_state += "b"
|
||||
else
|
||||
icon_state = "ai-empty"
|
||||
return ..()
|
||||
|
||||
/obj/structure/ai_core/Exited(atom/movable/gone, direction)
|
||||
. = ..()
|
||||
if(gone == circuit)
|
||||
circuit = null
|
||||
if((state != CORE_STATE_GLASSED) && (state != CORE_STATE_FINISHED))
|
||||
state = CORE_STATE_EMPTY
|
||||
update_appearance()
|
||||
if(gone == core_mmi)
|
||||
core_mmi = null
|
||||
update_appearance()
|
||||
|
||||
/obj/structure/ai_core/atom_deconstruct(disassembled = TRUE)
|
||||
if(state >= CORE_STATE_GLASSED)
|
||||
new /obj/item/stack/sheet/rglass(drop_location(), 2)
|
||||
if(state >= CORE_STATE_CABLED)
|
||||
new /obj/item/stack/cable_coil(drop_location(), 5)
|
||||
core_mmi?.forceMove(drop_location())
|
||||
circuit?.forceMove(drop_location())
|
||||
new /obj/item/stack/sheet/plasteel(drop_location(), 4)
|
||||
|
||||
/obj/structure/ai_core/Destroy()
|
||||
QDEL_NULL(circuit)
|
||||
QDEL_NULL(core_mmi)
|
||||
QDEL_NULL(laws)
|
||||
return ..()
|
||||
|
||||
/obj/structure/ai_core/examine(mob/user)
|
||||
. = ..()
|
||||
. += span_notice("It has some <b>bolts</b> that look [anchored ? "tightened" : "loosened"].")
|
||||
|
||||
switch(state)
|
||||
if(CORE_STATE_EMPTY)
|
||||
. += span_notice("There is a <b>slot</b> for a circuit board, the frame can be <b>melted</b> down.")
|
||||
if(CORE_STATE_CIRCUIT)
|
||||
. += span_notice("The circuit board can be <b>screwed</b> into place or <b>pried</b> out.")
|
||||
if(CORE_STATE_SCREWED)
|
||||
. += span_notice("The frame can be <b>wired</b>, the circuit board can be <b>unfastened</b>.")
|
||||
if(CORE_STATE_CABLED)
|
||||
if(!core_mmi)
|
||||
. += span_notice("There are wires which could be hooked up to an <b>MMI or positronic brain</b>, or <b>cut</b>.")
|
||||
else
|
||||
var/accept_laws = TRUE
|
||||
if(core_mmi.laws.id != DEFAULT_AI_LAWID || !core_mmi.brainmob || !core_mmi.brainmob?.mind)
|
||||
accept_laws = FALSE
|
||||
. += span_notice("There is a <b>slot</b> for a reinforced glass panel, the [AI_CORE_BRAIN(core_mmi)] could be <b>pried</b> out.[accept_laws ? " A law module can be <b>swiped</b> across." : ""]")
|
||||
if(CORE_STATE_GLASSED)
|
||||
. += span_notice("The monitor [core_mmi?.brainmob?.mind && !suicide_check() ? "and neural interface " : ""]can be <b>screwed</b> in, the panel can be <b>pried</b> out.")
|
||||
if(CORE_STATE_FINISHED)
|
||||
. += span_notice("The monitor's connection can be <b>cut</b>[core_mmi?.brainmob?.mind && !suicide_check() ? " the neural interface can be <b>screwed</b> in." : "."]")
|
||||
|
||||
/obj/structure/ai_core/item_interaction(mob/living/user, obj/item/tool, list/modifiers)
|
||||
if(state < CORE_STATE_FINISHED)
|
||||
return construction_item_interaction(user, tool, modifiers)
|
||||
|
||||
return NONE
|
||||
|
||||
/// Exists to be used for callbacks.
|
||||
/obj/structure/ai_core/proc/check_state(state_to_check)
|
||||
return (state == state_to_check)
|
||||
|
||||
/obj/structure/ai_core/latejoin_inactive
|
||||
name = "networked AI core"
|
||||
desc = "This AI core is connected by bluespace transmitters to NTNet, allowing for an AI personality to be downloaded to it on the fly mid-shift."
|
||||
anchored = TRUE
|
||||
state = CORE_STATE_FINISHED
|
||||
var/available = TRUE
|
||||
var/safety_checks = TRUE
|
||||
var/active = TRUE
|
||||
|
||||
/obj/structure/ai_core/latejoin_inactive/Initialize(mapload, state, posibrain)
|
||||
. = ..()
|
||||
GLOB.latejoin_ai_cores += src
|
||||
|
||||
/obj/structure/ai_core/latejoin_inactive/Destroy()
|
||||
GLOB.latejoin_ai_cores -= src
|
||||
return ..()
|
||||
|
||||
/obj/structure/ai_core/latejoin_inactive/examine(mob/user)
|
||||
. = ..()
|
||||
. += "Its transmitter seems to be <b>[active? "on" : "off"]</b>."
|
||||
. += span_notice("You could [active? "deactivate" : "activate"] it with a multitool.")
|
||||
|
||||
/obj/structure/ai_core/latejoin_inactive/proc/is_available() //If people still manage to use this feature to spawn-kill AI latejoins ahelp them.
|
||||
if(!available)
|
||||
return FALSE
|
||||
if(!safety_checks)
|
||||
return TRUE
|
||||
if(!active)
|
||||
return FALSE
|
||||
var/turf/T = get_turf(src)
|
||||
var/area/A = get_area(src)
|
||||
if(!(A.area_flags & BLOBS_ALLOWED))
|
||||
return FALSE
|
||||
if(!A.power_equip)
|
||||
return FALSE
|
||||
if(!SSmapping.level_trait(T.z,ZTRAIT_STATION))
|
||||
return FALSE
|
||||
if(!isfloorturf(T))
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/obj/structure/ai_core/latejoin_inactive/multitool_act(mob/living/user, obj/item/tool)
|
||||
if(user.combat_mode)
|
||||
return NONE
|
||||
|
||||
if(!tool.use_tool(src, user, 0 SECONDS, 0, 50))
|
||||
return ITEM_INTERACT_BLOCKING
|
||||
|
||||
active = !active
|
||||
balloon_alert(user, "[active ? "activated" : "deactivated"] transmitters")
|
||||
return ITEM_INTERACT_SUCCESS
|
||||
|
||||
/obj/structure/ai_core/proc/ai_structure_to_mob()
|
||||
var/mob/living/brain/the_brainmob = core_mmi.brainmob
|
||||
if(!the_brainmob.mind || suicide_check())
|
||||
return FALSE
|
||||
the_brainmob.mind.remove_antags_for_borging()
|
||||
if(!the_brainmob.mind.has_ever_been_ai)
|
||||
SSblackbox.record_feedback("amount", "ais_created", 1)
|
||||
var/mob/living/silicon/ai/ai_mob = null
|
||||
|
||||
if(core_mmi.overrides_aicore_laws)
|
||||
ai_mob = new /mob/living/silicon/ai(loc, core_mmi.laws, the_brainmob)
|
||||
core_mmi.laws = null //MMI's law datum is being donated, so we need the MMI to let it go or the GC will eat it
|
||||
else
|
||||
ai_mob = new /mob/living/silicon/ai(loc, laws, the_brainmob)
|
||||
laws = null //we're giving the new AI this datum, so let's not delete it when we qdel(src) 5 lines from now
|
||||
|
||||
var/datum/antagonist/malf_ai/malf_datum = IS_MALF_AI(ai_mob)
|
||||
if(malf_datum)
|
||||
malf_datum.add_law_zero()
|
||||
|
||||
if(!isnull(the_brainmob.client))
|
||||
ai_mob.set_gender(the_brainmob.client)
|
||||
if(core_mmi.force_replace_ai_name)
|
||||
ai_mob.fully_replace_character_name(ai_mob.name, core_mmi.replacement_ai_name())
|
||||
ai_mob.posibrain_inside = core_mmi.braintype == "Android"
|
||||
deadchat_broadcast(" has been brought online at <b>[get_area_name(ai_mob, format_text = TRUE)]</b>.", span_name("[ai_mob]"), follow_target = ai_mob, message_type = DEADCHAT_ANNOUNCEMENT)
|
||||
qdel(src)
|
||||
return ai_mob
|
||||
|
||||
/// Quick proc to call to see if the brainmob inside of us has suicided. Returns TRUE if we have, FALSE in any other scenario.
|
||||
/obj/structure/ai_core/proc/suicide_check()
|
||||
if(isnull(core_mmi) || isnull(core_mmi.brainmob))
|
||||
return FALSE
|
||||
return HAS_TRAIT(core_mmi.brainmob, TRAIT_SUICIDED)
|
||||
|
||||
/*
|
||||
This is a good place for AI-related object verbs so I'm sticking it here.
|
||||
If adding stuff to this, don't forget that an AI need to cancel_camera() whenever it physically moves to a different location.
|
||||
That prevents a few funky behaviors.
|
||||
*/
|
||||
//The type of interaction, the player performing the operation, the AI itself, and the card object, if any.
|
||||
|
||||
|
||||
/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."))
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/obj/structure/ai_core/transfer_ai(interaction, mob/user, mob/living/silicon/ai/AI, obj/item/aicard/card)
|
||||
if(state != CORE_STATE_FINISHED || !..())
|
||||
return
|
||||
if(core_mmi && core_mmi.brainmob)
|
||||
if(core_mmi.brainmob.mind)
|
||||
to_chat(user, span_warning("[src] already contains an active mind!"))
|
||||
return
|
||||
else if(suicide_check())
|
||||
to_chat(user, span_warning("[AI_CORE_BRAIN(core_mmi)] installed in [src] is completely useless!"))
|
||||
return
|
||||
//Transferring a carded AI to a core.
|
||||
if(interaction == AI_TRANS_FROM_CARD)
|
||||
AI.set_control_disabled(FALSE)
|
||||
AI.radio_enabled = TRUE
|
||||
AI.forceMove(loc) // to replace the terminal.
|
||||
to_chat(AI, span_notice("You have been uploaded to a stationary terminal. Remote device connection restored."))
|
||||
to_chat(user, "[span_boldnotice("Transfer successful")]: [AI.name] ([rand(1000,9999)].exe) installed and executed successfully. Local copy has been removed.")
|
||||
card.AI = null
|
||||
AI.battery = circuit.battery
|
||||
AI.posibrain_inside = isnull(core_mmi) || core_mmi.braintype == "Android"
|
||||
qdel(src)
|
||||
else //If for some reason you use an empty card on an empty AI terminal.
|
||||
to_chat(user, span_alert("There is no AI loaded on this terminal."))
|
||||
|
||||
/obj/item/circuitboard/aicore
|
||||
name = "AI core (AI Core Board)" //Well, duh, but best to be consistent
|
||||
var/battery = 200 //backup battery for when the AI loses power. Copied to/from AI mobs when carding, and placed here to avoid recharge via deconning the core
|
||||
|
||||
/obj/item/circuitboard/aicore/Initialize(mapload)
|
||||
. = ..()
|
||||
if(mapload && HAS_TRAIT(SSstation, STATION_TRAIT_HUMAN_AI))
|
||||
return INITIALIZE_HINT_QDEL
|
||||
|
||||
#undef AI_CORE_BRAIN
|
||||
@@ -0,0 +1,253 @@
|
||||
#define AI_CORE_BRAIN(X) X.braintype == "Android" ? "brain" : "MMI"
|
||||
#define UPDATE_STATE(new_state) state = new_state; update_appearance(UPDATE_ICON_STATE)
|
||||
#define CHECK_STATE_CALLBACK(maintained_state) CALLBACK(src, PROC_REF(check_state), maintained_state)
|
||||
|
||||
/obj/structure/ai_core/welder_act(mob/living/user, obj/item/tool)
|
||||
if(state != CORE_STATE_EMPTY)
|
||||
balloon_alert(user, "frame has to be empty!")
|
||||
return ITEM_INTERACT_BLOCKING
|
||||
|
||||
if(!tool.tool_start_check(user, 1))
|
||||
return ITEM_INTERACT_BLOCKING
|
||||
|
||||
if(!tool.use_tool(src, user, 2 SECONDS, 1, 50, CHECK_STATE_CALLBACK(CORE_STATE_EMPTY)))
|
||||
return ITEM_INTERACT_BLOCKING
|
||||
|
||||
deconstruct(TRUE)
|
||||
return ITEM_INTERACT_SUCCESS
|
||||
|
||||
/obj/structure/ai_core/wrench_act(mob/living/user, obj/item/tool)
|
||||
if(state >= CORE_STATE_FINISHED)
|
||||
set_anchored(TRUE) //teehee
|
||||
balloon_alert(user, "can't unanchor!")
|
||||
return ITEM_INTERACT_BLOCKING
|
||||
|
||||
default_unfasten_wrench(user, tool)
|
||||
return ITEM_INTERACT_SUCCESS
|
||||
|
||||
/obj/structure/ai_core/screwdriver_act(mob/living/user, obj/item/tool)
|
||||
switch(state)
|
||||
if(CORE_STATE_EMPTY)
|
||||
balloon_alert(user, "nothing to screw in there!")
|
||||
return ITEM_INTERACT_BLOCKING
|
||||
if(CORE_STATE_CIRCUIT)
|
||||
if(!tool.use_tool(src, user, 0 SECONDS, 0, 50, CHECK_STATE_CALLBACK(CORE_STATE_CIRCUIT)))
|
||||
return ITEM_INTERACT_BLOCKING
|
||||
balloon_alert(user, "board secured")
|
||||
UPDATE_STATE(CORE_STATE_SCREWED)
|
||||
return ITEM_INTERACT_SUCCESS
|
||||
if(CORE_STATE_SCREWED)
|
||||
if(!tool.use_tool(src, user, 0 SECONDS, 0, 50, CHECK_STATE_CALLBACK(CORE_STATE_SCREWED)))
|
||||
return ITEM_INTERACT_BLOCKING
|
||||
balloon_alert(user, "board unsecured")
|
||||
UPDATE_STATE(CORE_STATE_CIRCUIT)
|
||||
return ITEM_INTERACT_SUCCESS
|
||||
if(CORE_STATE_CABLED)
|
||||
balloon_alert(user, "can't reach the board!")
|
||||
return ITEM_INTERACT_BLOCKING
|
||||
if(CORE_STATE_GLASSED)
|
||||
if(!anchored)
|
||||
balloon_alert(user, "isn't anchored!")
|
||||
return ITEM_INTERACT_BLOCKING
|
||||
if(!tool.use_tool(src, user, 0 SECONDS, 0, 50, CHECK_STATE_CALLBACK(CORE_STATE_GLASSED)))
|
||||
return ITEM_INTERACT_BLOCKING
|
||||
if(suicide_check())
|
||||
balloon_alert(user, "processor is completely useless!")
|
||||
return ITEM_INTERACT_BLOCKING
|
||||
|
||||
var/atom/movable/alert_source = src
|
||||
if(core_mmi.brainmob?.mind)
|
||||
alert_source = ai_structure_to_mob() || alert_source
|
||||
else
|
||||
UPDATE_STATE(CORE_STATE_FINISHED)
|
||||
alert_source.balloon_alert(user, "connected monitor[core_mmi?.brainmob?.mind ? " and neural network" : ""]")
|
||||
return ITEM_INTERACT_SUCCESS
|
||||
if(CORE_STATE_FINISHED)
|
||||
if(!core_mmi?.brainmob?.mind || suicide_check())
|
||||
balloon_alert(user, "processor is inactive!")
|
||||
return ITEM_INTERACT_BLOCKING
|
||||
|
||||
if(!anchored)
|
||||
balloon_alert(user, "anchor it first!")
|
||||
return ITEM_INTERACT_BLOCKING
|
||||
|
||||
balloon_alert(user, "connecting neural network...")
|
||||
if(!tool.use_tool(src, user, 10 SECONDS, 0, 50, CHECK_STATE_CALLBACK(CORE_STATE_FINISHED)))
|
||||
return ITEM_INTERACT_BLOCKING
|
||||
|
||||
var/atom/movable/alert_source = ai_structure_to_mob()
|
||||
if(!alert_source)
|
||||
balloon_alert(user, "processor is inactive!")
|
||||
return ITEM_INTERACT_BLOCKING
|
||||
|
||||
alert_source.balloon_alert(user, "connected neural network")
|
||||
return ITEM_INTERACT_SUCCESS
|
||||
|
||||
/obj/structure/ai_core/crowbar_act(mob/living/user, obj/item/tool)
|
||||
switch(state)
|
||||
if(CORE_STATE_EMPTY)
|
||||
balloon_alert(user, "nothing to pry out!")
|
||||
return ITEM_INTERACT_BLOCKING
|
||||
if(CORE_STATE_CIRCUIT)
|
||||
if(!tool.use_tool(src, user, 0 SECONDS, 0, 50, CHECK_STATE_CALLBACK(CORE_STATE_CIRCUIT)))
|
||||
return ITEM_INTERACT_BLOCKING
|
||||
|
||||
circuit.forceMove(drop_location())
|
||||
UPDATE_STATE(CORE_STATE_EMPTY)
|
||||
return ITEM_INTERACT_SUCCESS
|
||||
if(CORE_STATE_SCREWED)
|
||||
balloon_alert(user, "won't budge!")
|
||||
return ITEM_INTERACT_BLOCKING
|
||||
if(CORE_STATE_CABLED)
|
||||
if(!core_mmi)
|
||||
balloon_alert(user, "nothing to pry out!")
|
||||
return ITEM_INTERACT_BLOCKING
|
||||
if(!tool.use_tool(src, user, 0 SECONDS, 0, 50, CHECK_STATE_CALLBACK(CORE_STATE_CABLED)) || !core_mmi)
|
||||
return ITEM_INTERACT_BLOCKING
|
||||
|
||||
core_mmi.forceMove(drop_location())
|
||||
UPDATE_STATE(CORE_STATE_CABLED)
|
||||
return ITEM_INTERACT_SUCCESS
|
||||
if(CORE_STATE_GLASSED)
|
||||
if(!tool.use_tool(src, user, 0 SECONDS, 0, 50, CHECK_STATE_CALLBACK(CORE_STATE_GLASSED)))
|
||||
return ITEM_INTERACT_BLOCKING
|
||||
|
||||
new /obj/item/stack/sheet/rglass(drop_location(), 2)
|
||||
UPDATE_STATE(CORE_STATE_CABLED)
|
||||
return ITEM_INTERACT_SUCCESS
|
||||
if(CORE_STATE_FINISHED)
|
||||
balloon_alert(user, "display is on!")
|
||||
return ITEM_INTERACT_SUCCESS
|
||||
|
||||
/obj/structure/ai_core/wirecutter_act(mob/living/user, obj/item/tool)
|
||||
switch(state)
|
||||
if(CORE_STATE_EMPTY to CORE_STATE_CIRCUIT)
|
||||
balloon_alert(user, "nothing to cut!")
|
||||
return ITEM_INTERACT_BLOCKING
|
||||
if(CORE_STATE_CABLED)
|
||||
if(core_mmi)
|
||||
balloon_alert(user, "[AI_CORE_BRAIN(core_mmi)] in the way!")
|
||||
return ITEM_INTERACT_BLOCKING
|
||||
|
||||
if(!tool.use_tool(src, user, 0 SECONDS, 0, 50, CHECK_STATE_CALLBACK(CORE_STATE_CABLED)) || core_mmi)
|
||||
return ITEM_INTERACT_BLOCKING
|
||||
|
||||
new /obj/item/stack/cable_coil(drop_location(), 5)
|
||||
UPDATE_STATE(CORE_STATE_SCREWED)
|
||||
return ITEM_INTERACT_SUCCESS
|
||||
if(CORE_STATE_GLASSED)
|
||||
balloon_alert(user, "nothing left to cut!")
|
||||
return ITEM_INTERACT_BLOCKING
|
||||
if(CORE_STATE_FINISHED)
|
||||
if(!tool.use_tool(src, user, 0 SECONDS, 0, 50, CHECK_STATE_CALLBACK(CORE_STATE_FINISHED)))
|
||||
return ITEM_INTERACT_BLOCKING
|
||||
|
||||
UPDATE_STATE(CORE_STATE_GLASSED)
|
||||
return ITEM_INTERACT_SUCCESS
|
||||
|
||||
/// Handles the interaction chain the same as item_interaction. Exists to isolate construction behaviour from other item behaviour.
|
||||
/obj/structure/ai_core/proc/construction_item_interaction(mob/living/user, obj/item/tool, list/modifiers)
|
||||
if(istype(tool, /obj/item/circuitboard/aicore))
|
||||
return install_board(user, tool) ? ITEM_INTERACT_SUCCESS : ITEM_INTERACT_BLOCKING
|
||||
|
||||
if(istype(tool, /obj/item/stack/cable_coil))
|
||||
return add_cabling(user, tool) ? ITEM_INTERACT_SUCCESS : ITEM_INTERACT_BLOCKING
|
||||
|
||||
if(istype(tool, /obj/item/mmi))
|
||||
return install_mmi(user, tool) ? ITEM_INTERACT_SUCCESS : ITEM_INTERACT_BLOCKING
|
||||
if(istype(tool, /obj/item/ai_module))
|
||||
return update_laws(user, tool) ? ITEM_INTERACT_SUCCESS : ITEM_INTERACT_BLOCKING
|
||||
if(istype(tool, /obj/item/stack/sheet/rglass))
|
||||
return install_glass(user, tool) ? ITEM_INTERACT_SUCCESS : ITEM_INTERACT_BLOCKING
|
||||
|
||||
return NONE
|
||||
|
||||
/obj/structure/ai_core/proc/install_board(mob/living/user, obj/item/circuitboard/aicore/circuit)
|
||||
if(state != CORE_STATE_EMPTY)
|
||||
return FALSE
|
||||
if(!user.transferItemToLoc(circuit, src))
|
||||
return FALSE
|
||||
|
||||
playsound(src, 'sound/items/deconstruct.ogg', 50, TRUE)
|
||||
src.circuit = circuit
|
||||
UPDATE_STATE(CORE_STATE_CIRCUIT)
|
||||
return TRUE
|
||||
|
||||
/obj/structure/ai_core/proc/add_cabling(mob/living/user, obj/item/stack/cable_coil/cable)
|
||||
if(state != CORE_STATE_SCREWED)
|
||||
return FALSE
|
||||
|
||||
if(cable.get_amount() < 5)
|
||||
balloon_alert(user, "not enough [cable::name]!")
|
||||
return FALSE
|
||||
|
||||
balloon_alert(user, "adding cable...")
|
||||
if(!cable.use_tool(src, user, 2 SECONDS, 5, 50, CHECK_STATE_CALLBACK(CORE_STATE_SCREWED)))
|
||||
return FALSE
|
||||
|
||||
UPDATE_STATE(CORE_STATE_CABLED)
|
||||
return TRUE
|
||||
|
||||
/obj/structure/ai_core/proc/install_mmi(mob/living/user, obj/item/mmi/mmi)
|
||||
if(state != CORE_STATE_CABLED)
|
||||
return FALSE
|
||||
|
||||
if(!mmi.brain_check(user))
|
||||
var/wants_install = (tgui_alert(user, "This [AI_CORE_BRAIN(mmi)] is inactive, would you like to make an inactive AI?", "Installing AI [AI_CORE_BRAIN(mmi)]", list("Yes", "No")) == "Yes")
|
||||
if(!wants_install)
|
||||
return FALSE
|
||||
if(QDELETED(src) || QDELETED(user) || QDELETED(mmi) || !user.is_holding(mmi) || !Adjacent(user))
|
||||
return FALSE
|
||||
if(mmi.brainmob && HAS_TRAIT(mmi.brainmob, TRAIT_SUICIDED))
|
||||
balloon_alert(user, "[AI_CORE_BRAIN(mmi)] is useless!")
|
||||
return FALSE
|
||||
else
|
||||
var/mob/living/brain/mmi_brainmob = mmi.brainmob
|
||||
if(!CONFIG_GET(flag/allow_ai) || (mmi_brainmob && is_banned_from(mmi_brainmob.ckey, JOB_AI)))
|
||||
if(!QDELETED(src) && !QDELETED(user) && !QDELETED(mmi) && user.is_holding(mmi) && Adjacent(user))
|
||||
balloon_alert(user, "[mmi] won't fit!")
|
||||
return FALSE
|
||||
|
||||
if(state != CORE_STATE_CABLED)
|
||||
return FALSE
|
||||
if(!user.transferItemToLoc(mmi, src))
|
||||
return FALSE
|
||||
|
||||
core_mmi = mmi
|
||||
UPDATE_STATE(CORE_STATE_CABLED)
|
||||
return TRUE
|
||||
|
||||
/obj/structure/ai_core/proc/update_laws(mob/living/user, obj/item/ai_module/module)
|
||||
if(!core_mmi)
|
||||
balloon_alert(user, "no brain installed!")
|
||||
return FALSE
|
||||
if(!core_mmi.brainmob || !core_mmi.brainmob?.mind || suicide_check())
|
||||
balloon_alert(user, "[AI_CORE_BRAIN(core_mmi)] is inactive!")
|
||||
return FALSE
|
||||
if(core_mmi.laws.id != DEFAULT_AI_LAWID)
|
||||
balloon_alert(user, "[AI_CORE_BRAIN(core_mmi)] already has set laws!")
|
||||
return FALSE
|
||||
|
||||
module.install(laws, user)
|
||||
return TRUE
|
||||
|
||||
/obj/structure/ai_core/proc/install_glass(mob/living/user, obj/item/stack/sheet/rglass/glass)
|
||||
if(state != CORE_STATE_CABLED)
|
||||
return FALSE
|
||||
|
||||
if(!core_mmi)
|
||||
balloon_alert(user, "needs a processor!")
|
||||
return FALSE
|
||||
if(glass.get_amount() < 2)
|
||||
balloon_alert(user, "not enough [glass::name]!")
|
||||
return FALSE
|
||||
|
||||
if(!glass.use_tool(src, user, 2 SECONDS, 2, 50, CHECK_STATE_CALLBACK(CORE_STATE_CABLED)) || !core_mmi)
|
||||
return FALSE
|
||||
|
||||
UPDATE_STATE(CORE_STATE_GLASSED)
|
||||
return TRUE
|
||||
|
||||
#undef CHECK_STATE_CALLBACK
|
||||
#undef UPDATE_STATE
|
||||
#undef AI_CORE_BRAIN
|
||||
@@ -69,7 +69,7 @@
|
||||
|
||||
// Transfer the AI from the core we created into the card, then delete the core
|
||||
capture_ai(new_ai, user)
|
||||
var/obj/structure/ai_core/deactivated/detritus = locate() in get_turf(src)
|
||||
var/obj/structure/ai_core/detritus = locate() in get_turf(src)
|
||||
qdel(detritus)
|
||||
AI.set_control_disabled(FALSE)
|
||||
AI.radio_enabled = TRUE
|
||||
|
||||
@@ -1,484 +0,0 @@
|
||||
#define AI_CORE_BRAIN(X) X.braintype == "Android" ? "brain" : "MMI"
|
||||
|
||||
/obj/structure/ai_core
|
||||
density = TRUE
|
||||
anchored = FALSE
|
||||
name = "\improper AI core"
|
||||
icon = 'icons/mob/silicon/ai.dmi'
|
||||
icon_state = "0"
|
||||
desc = "The framework for an artificial intelligence core."
|
||||
max_integrity = 500
|
||||
var/state = EMPTY_CORE
|
||||
var/datum/ai_laws/laws
|
||||
var/obj/item/circuitboard/aicore/circuit
|
||||
var/obj/item/mmi/core_mmi
|
||||
/// only used in cases of AIs piloting mechs or shunted malf AIs, possible later use cases
|
||||
var/mob/living/silicon/ai/remote_ai = null
|
||||
|
||||
/obj/structure/ai_core/Initialize(mapload)
|
||||
. = ..()
|
||||
laws = new
|
||||
laws.set_laws_config()
|
||||
|
||||
/obj/structure/ai_core/examine(mob/user)
|
||||
. = ..()
|
||||
if(!anchored)
|
||||
if(state != EMPTY_CORE)
|
||||
. += span_notice("It has some <b>bolts</b> that could be tightened.")
|
||||
else
|
||||
. += span_notice("It has some <b>bolts</b> that could be tightened. The frame can be <b>melted</b> down.")
|
||||
else
|
||||
switch(state)
|
||||
if(EMPTY_CORE)
|
||||
. += span_notice("There is a <b>slot</b> for a circuit board, its <b>bolts</b> can be loosened.")
|
||||
if(CIRCUIT_CORE)
|
||||
. += span_notice("The circuit board can be <b>screwed</b> into place or <b>pried</b> out.")
|
||||
if(SCREWED_CORE)
|
||||
. += span_notice("The frame can be <b>wired</b>, the circuit board can be <b>unfastened</b>.")
|
||||
if(CABLED_CORE)
|
||||
if(!core_mmi)
|
||||
. += span_notice("There are wires which could be hooked up to an <b>MMI or positronic brain</b>, or <b>cut</b>.")
|
||||
else
|
||||
var/accept_laws = TRUE
|
||||
if(core_mmi.laws.id != DEFAULT_AI_LAWID || !core_mmi.brainmob || !core_mmi.brainmob?.mind)
|
||||
accept_laws = FALSE
|
||||
. += span_notice("There is a <b>slot</b> for a reinforced glass panel, the [AI_CORE_BRAIN(core_mmi)] could be <b>pried</b> out.[accept_laws ? " A law module can be <b>swiped</b> across." : ""]")
|
||||
if(GLASS_CORE)
|
||||
. += span_notice("The monitor [core_mmi?.brainmob?.mind && !suicide_check() ? "and neural interface " : ""]can be <b>screwed</b> in, the panel can be <b>pried</b> out.")
|
||||
if(AI_READY_CORE)
|
||||
. += span_notice("The monitor's connection can be <b>cut</b>[core_mmi?.brainmob?.mind && !suicide_check() ? " the neural interface can be <b>screwed</b> in." : "."]")
|
||||
|
||||
/obj/structure/ai_core/Exited(atom/movable/gone, direction)
|
||||
. = ..()
|
||||
if(gone == circuit)
|
||||
circuit = null
|
||||
if((state != GLASS_CORE) && (state != AI_READY_CORE))
|
||||
state = EMPTY_CORE
|
||||
update_appearance()
|
||||
if(gone == core_mmi)
|
||||
core_mmi = null
|
||||
update_appearance()
|
||||
|
||||
/obj/structure/ai_core/Destroy()
|
||||
if(istype(remote_ai))
|
||||
remote_ai = null
|
||||
QDEL_NULL(circuit)
|
||||
QDEL_NULL(core_mmi)
|
||||
QDEL_NULL(laws)
|
||||
return ..()
|
||||
|
||||
/obj/structure/ai_core/take_damage(damage_amount, damage_type, damage_flag, sound_effect, attack_dir, armour_penetration)
|
||||
. = ..()
|
||||
if(. > 0 && istype(remote_ai))
|
||||
to_chat(remote_ai, span_danger("Your core is under attack!"))
|
||||
|
||||
|
||||
/obj/structure/ai_core/deactivated
|
||||
icon_state = "ai-empty"
|
||||
anchored = TRUE
|
||||
state = AI_READY_CORE
|
||||
var/mob/living/silicon/ai/attached_ai
|
||||
|
||||
/obj/structure/ai_core/deactivated/Initialize(mapload, skip_mmi_creation = FALSE, posibrain = FALSE, linked_ai)
|
||||
. = ..()
|
||||
circuit = new(src)
|
||||
if(linked_ai)
|
||||
attached_ai = linked_ai
|
||||
if(skip_mmi_creation)
|
||||
return
|
||||
if(posibrain)
|
||||
core_mmi = new/obj/item/mmi/posibrain(src, /* autoping = */ FALSE)
|
||||
else
|
||||
core_mmi = new(src)
|
||||
core_mmi.brain = new(core_mmi)
|
||||
core_mmi.update_appearance()
|
||||
|
||||
/obj/structure/ai_core/deactivated/Destroy()
|
||||
if(attached_ai)
|
||||
attached_ai.linked_core = null
|
||||
attached_ai = null
|
||||
. = ..()
|
||||
|
||||
/obj/structure/ai_core/deactivated/proc/disable_doomsday(datum/source)
|
||||
SIGNAL_HANDLER
|
||||
attached_ai.ShutOffDoomsdayDevice()
|
||||
|
||||
/obj/structure/ai_core/latejoin_inactive
|
||||
name = "networked AI core"
|
||||
desc = "This AI core is connected by bluespace transmitters to NTNet, allowing for an AI personality to be downloaded to it on the fly mid-shift."
|
||||
icon_state = "ai-empty"
|
||||
anchored = TRUE
|
||||
state = AI_READY_CORE
|
||||
var/available = TRUE
|
||||
var/safety_checks = TRUE
|
||||
var/active = TRUE
|
||||
|
||||
/obj/structure/ai_core/latejoin_inactive/Initialize(mapload)
|
||||
. = ..()
|
||||
circuit = new(src)
|
||||
core_mmi = new(src)
|
||||
core_mmi.brain = new(core_mmi)
|
||||
core_mmi.update_appearance()
|
||||
GLOB.latejoin_ai_cores += src
|
||||
|
||||
/obj/structure/ai_core/latejoin_inactive/Destroy()
|
||||
GLOB.latejoin_ai_cores -= src
|
||||
return ..()
|
||||
|
||||
/obj/structure/ai_core/latejoin_inactive/examine(mob/user)
|
||||
. = ..()
|
||||
. += "Its transmitter seems to be <b>[active? "on" : "off"]</b>."
|
||||
. += span_notice("You could [active? "deactivate" : "activate"] it with a multitool.")
|
||||
|
||||
/obj/structure/ai_core/latejoin_inactive/proc/is_available() //If people still manage to use this feature to spawn-kill AI latejoins ahelp them.
|
||||
if(!available)
|
||||
return FALSE
|
||||
if(!safety_checks)
|
||||
return TRUE
|
||||
if(!active)
|
||||
return FALSE
|
||||
var/turf/T = get_turf(src)
|
||||
var/area/A = get_area(src)
|
||||
if(!(A.area_flags & BLOBS_ALLOWED))
|
||||
return FALSE
|
||||
if(!A.power_equip)
|
||||
return FALSE
|
||||
if(!SSmapping.level_trait(T.z,ZTRAIT_STATION))
|
||||
return FALSE
|
||||
if(!isfloorturf(T))
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/obj/structure/ai_core/latejoin_inactive/attackby(obj/item/tool, mob/user, list/modifiers, list/attack_modifiers)
|
||||
if(tool.tool_behaviour == TOOL_MULTITOOL)
|
||||
active = !active
|
||||
to_chat(user, span_notice("You [active? "activate" : "deactivate"] \the [src]'s transmitters."))
|
||||
return
|
||||
return ..()
|
||||
|
||||
/obj/structure/ai_core/wrench_act(mob/living/user, obj/item/tool)
|
||||
. = ..()
|
||||
default_unfasten_wrench(user, tool)
|
||||
return ITEM_INTERACT_SUCCESS
|
||||
|
||||
/obj/structure/ai_core/screwdriver_act(mob/living/user, obj/item/tool)
|
||||
. = ..()
|
||||
if(state == AI_READY_CORE)
|
||||
if(!core_mmi)
|
||||
balloon_alert(user, "no brain installed!")
|
||||
return ITEM_INTERACT_SUCCESS
|
||||
else if(!core_mmi.brainmob?.mind || suicide_check())
|
||||
balloon_alert(user, "brain is inactive!")
|
||||
return ITEM_INTERACT_SUCCESS
|
||||
else
|
||||
balloon_alert(user, "connecting neural network...")
|
||||
if(!tool.use_tool(src, user, 10 SECONDS))
|
||||
return ITEM_INTERACT_SUCCESS
|
||||
if(!ai_structure_to_mob())
|
||||
return ITEM_INTERACT_SUCCESS
|
||||
balloon_alert(user, "connected neural network")
|
||||
return ITEM_INTERACT_SUCCESS
|
||||
|
||||
/obj/structure/ai_core/attackby(obj/item/tool, mob/living/user, list/modifiers, list/attack_modifiers)
|
||||
if(remote_ai)
|
||||
to_chat(remote_ai, span_danger("CORE TAMPERING DETECTED!"))
|
||||
if(!anchored)
|
||||
if(tool.tool_behaviour == TOOL_WELDER)
|
||||
if(state != EMPTY_CORE)
|
||||
balloon_alert(user, "core must be empty to deconstruct it!")
|
||||
return
|
||||
|
||||
if(!tool.tool_start_check(user, amount=1))
|
||||
return
|
||||
|
||||
balloon_alert(user, "deconstructing frame...")
|
||||
if(tool.use_tool(src, user, 20, volume=50) && state == EMPTY_CORE)
|
||||
balloon_alert(user, "deconstructed frame")
|
||||
deconstruct(TRUE)
|
||||
return
|
||||
else
|
||||
if(!user.combat_mode)
|
||||
balloon_alert(user, "bolt it down first!")
|
||||
return
|
||||
else
|
||||
return ..()
|
||||
else
|
||||
switch(state)
|
||||
if(EMPTY_CORE)
|
||||
if(istype(tool, /obj/item/circuitboard/aicore))
|
||||
if(!user.transferItemToLoc(tool, src))
|
||||
return
|
||||
playsound(loc, 'sound/items/deconstruct.ogg', 50, TRUE)
|
||||
balloon_alert(user, "circuit board inserted")
|
||||
update_appearance()
|
||||
state = CIRCUIT_CORE
|
||||
circuit = tool
|
||||
return
|
||||
if(CIRCUIT_CORE)
|
||||
if(tool.tool_behaviour == TOOL_SCREWDRIVER)
|
||||
tool.play_tool_sound(src)
|
||||
balloon_alert(user, "board screwed into place")
|
||||
state = SCREWED_CORE
|
||||
update_appearance()
|
||||
return
|
||||
if(tool.tool_behaviour == TOOL_CROWBAR)
|
||||
tool.play_tool_sound(src)
|
||||
balloon_alert(user, "circuit board removed")
|
||||
state = EMPTY_CORE
|
||||
circuit.forceMove(loc)
|
||||
return
|
||||
if(SCREWED_CORE)
|
||||
if(tool.tool_behaviour == TOOL_SCREWDRIVER && circuit)
|
||||
tool.play_tool_sound(src)
|
||||
balloon_alert(user, "circuit board unfastened")
|
||||
state = CIRCUIT_CORE
|
||||
update_appearance()
|
||||
return
|
||||
if(istype(tool, /obj/item/stack/cable_coil))
|
||||
var/obj/item/stack/cable_coil/C = tool
|
||||
if(C.get_amount() >= 5)
|
||||
playsound(loc, 'sound/items/deconstruct.ogg', 50, TRUE)
|
||||
balloon_alert(user, "adding cables to frame...")
|
||||
if(do_after(user, 2 SECONDS, target = src) && state == SCREWED_CORE && C.use(5))
|
||||
balloon_alert(user, "added cables to frame.")
|
||||
state = CABLED_CORE
|
||||
update_appearance()
|
||||
else
|
||||
balloon_alert(user, "need five lengths of cable!")
|
||||
return
|
||||
if(CABLED_CORE)
|
||||
if(tool.tool_behaviour == TOOL_WIRECUTTER)
|
||||
if(core_mmi)
|
||||
balloon_alert(user, "remove the [AI_CORE_BRAIN(core_mmi)] first!")
|
||||
else
|
||||
tool.play_tool_sound(src)
|
||||
balloon_alert(user, "cables removed")
|
||||
state = SCREWED_CORE
|
||||
update_appearance()
|
||||
new /obj/item/stack/cable_coil(drop_location(), 5)
|
||||
return
|
||||
|
||||
if(istype(tool, /obj/item/stack/sheet/rglass))
|
||||
if(!core_mmi)
|
||||
balloon_alert(user, "add a brain first!")
|
||||
return
|
||||
var/obj/item/stack/sheet/rglass/G = tool
|
||||
if(G.get_amount() >= 2)
|
||||
playsound(loc, 'sound/items/deconstruct.ogg', 50, TRUE)
|
||||
balloon_alert(user, "adding glass panel...")
|
||||
if(do_after(user, 2 SECONDS, target = src) && state == CABLED_CORE && G.use(2))
|
||||
balloon_alert(user, "added glass panel")
|
||||
state = GLASS_CORE
|
||||
update_appearance()
|
||||
else
|
||||
balloon_alert(user, "need two sheets of reinforced glass!")
|
||||
return
|
||||
|
||||
if(istype(tool, /obj/item/ai_module))
|
||||
if(!core_mmi)
|
||||
balloon_alert(user, "no brain installed!")
|
||||
return
|
||||
if(!core_mmi.brainmob || !core_mmi.brainmob?.mind || suicide_check())
|
||||
balloon_alert(user, "[AI_CORE_BRAIN(core_mmi)] is inactive!")
|
||||
return
|
||||
if(core_mmi.laws.id != DEFAULT_AI_LAWID)
|
||||
balloon_alert(user, "[AI_CORE_BRAIN(core_mmi)] already has set laws!")
|
||||
return
|
||||
var/obj/item/ai_module/module = tool
|
||||
module.install(laws, user)
|
||||
return
|
||||
|
||||
if(istype(tool, /obj/item/mmi) && !core_mmi)
|
||||
var/obj/item/mmi/M = tool
|
||||
if(!M.brain_check(user))
|
||||
var/install = tgui_alert(user, "This [AI_CORE_BRAIN(M)] is inactive, would you like to make an inactive AI?", "Installing AI [AI_CORE_BRAIN(M)]", list("Yes", "No"))
|
||||
if(install != "Yes")
|
||||
return
|
||||
if(M.brainmob && HAS_TRAIT(M.brainmob, TRAIT_SUICIDED))
|
||||
to_chat(user, span_warning("[M.name] is completely useless!"))
|
||||
return
|
||||
if(!user.transferItemToLoc(M, src))
|
||||
return
|
||||
core_mmi = M
|
||||
balloon_alert(user, "added [AI_CORE_BRAIN(core_mmi)] to frame")
|
||||
update_appearance()
|
||||
return
|
||||
|
||||
var/mob/living/brain/B = M.brainmob
|
||||
if(!CONFIG_GET(flag/allow_ai) || (is_banned_from(B.ckey, JOB_AI) && !QDELETED(src) && !QDELETED(user) && !QDELETED(M) && !QDELETED(user) && Adjacent(user)))
|
||||
if(!QDELETED(M))
|
||||
to_chat(user, span_warning("This [M.name] does not seem to fit!"))
|
||||
return
|
||||
if(!user.transferItemToLoc(M,src))
|
||||
return
|
||||
|
||||
core_mmi = M
|
||||
balloon_alert(user, "added [AI_CORE_BRAIN(core_mmi)] to frame")
|
||||
update_appearance()
|
||||
return
|
||||
|
||||
if(tool.tool_behaviour == TOOL_CROWBAR && core_mmi)
|
||||
tool.play_tool_sound(src)
|
||||
balloon_alert(user, "removed [AI_CORE_BRAIN(core_mmi)]")
|
||||
if(remote_ai)
|
||||
var/mob/living/silicon/ai/remoted_ai = remote_ai
|
||||
remoted_ai.break_core_link()
|
||||
if(!IS_MALF_AI(remoted_ai))
|
||||
//don't pull back shunted malf AIs
|
||||
remoted_ai.death(gibbed = TRUE, drop_mmi = FALSE)
|
||||
///the drop_mmi param determines whether the MMI is dropped at their current location
|
||||
///which in this case would be somewhere else, so we drop their MMI at the core instead
|
||||
remoted_ai.make_mmi_drop_and_transfer(core_mmi, src)
|
||||
core_mmi.forceMove(loc) //if they're malf, just drops a blank MMI, or if it's an incomplete shell
|
||||
return //it drops the mmi that was put in before it was finished
|
||||
|
||||
if(GLASS_CORE)
|
||||
if(tool.tool_behaviour == TOOL_CROWBAR)
|
||||
tool.play_tool_sound(src)
|
||||
balloon_alert(user, "removed glass panel")
|
||||
state = CABLED_CORE
|
||||
update_appearance()
|
||||
new /obj/item/stack/sheet/rglass(loc, 2)
|
||||
return
|
||||
|
||||
if(tool.tool_behaviour == TOOL_SCREWDRIVER)
|
||||
if(suicide_check())
|
||||
to_chat(user, span_warning("The brain installed is completely useless."))
|
||||
return
|
||||
tool.play_tool_sound(src)
|
||||
|
||||
var/atom/alert_source = src
|
||||
if(core_mmi.brainmob?.mind)
|
||||
alert_source = ai_structure_to_mob() || alert_source
|
||||
else
|
||||
state = AI_READY_CORE
|
||||
update_appearance()
|
||||
alert_source.balloon_alert(user, "connected monitor[core_mmi?.brainmob?.mind ? " and neural network" : ""]")
|
||||
return
|
||||
|
||||
if(AI_READY_CORE)
|
||||
if(istype(tool, /obj/item/aicard))
|
||||
return //handled by /obj/structure/ai_core/transfer_ai()
|
||||
|
||||
if(tool.tool_behaviour == TOOL_WIRECUTTER)
|
||||
tool.play_tool_sound(src)
|
||||
balloon_alert(user, "disconnected monitor")
|
||||
state = GLASS_CORE
|
||||
update_appearance()
|
||||
return
|
||||
return ..()
|
||||
|
||||
/obj/structure/ai_core/proc/ai_structure_to_mob()
|
||||
var/mob/living/brain/the_brainmob = core_mmi.brainmob
|
||||
if(!the_brainmob.mind || suicide_check())
|
||||
return FALSE
|
||||
the_brainmob.mind.remove_antags_for_borging()
|
||||
if(!the_brainmob.mind.has_ever_been_ai)
|
||||
SSblackbox.record_feedback("amount", "ais_created", 1)
|
||||
var/mob/living/silicon/ai/ai_mob = null
|
||||
|
||||
if(core_mmi.overrides_aicore_laws)
|
||||
ai_mob = new /mob/living/silicon/ai(loc, core_mmi.laws, the_brainmob)
|
||||
core_mmi.laws = null //MMI's law datum is being donated, so we need the MMI to let it go or the GC will eat it
|
||||
else
|
||||
ai_mob = new /mob/living/silicon/ai(loc, laws, the_brainmob)
|
||||
laws = null //we're giving the new AI this datum, so let's not delete it when we qdel(src) 5 lines from now
|
||||
|
||||
var/datum/antagonist/malf_ai/malf_datum = IS_MALF_AI(ai_mob)
|
||||
if(malf_datum)
|
||||
malf_datum.add_law_zero()
|
||||
|
||||
if(!isnull(the_brainmob.client))
|
||||
ai_mob.set_gender(the_brainmob.client)
|
||||
if(core_mmi.force_replace_ai_name)
|
||||
ai_mob.fully_replace_character_name(ai_mob.name, core_mmi.replacement_ai_name())
|
||||
ai_mob.posibrain_inside = core_mmi.braintype == "Android"
|
||||
deadchat_broadcast(" has been brought online at <b>[get_area_name(ai_mob, format_text = TRUE)]</b>.", span_name("[ai_mob]"), follow_target = ai_mob, message_type = DEADCHAT_ANNOUNCEMENT)
|
||||
qdel(src)
|
||||
return ai_mob
|
||||
|
||||
/obj/structure/ai_core/update_icon_state()
|
||||
switch(state)
|
||||
if(EMPTY_CORE)
|
||||
icon_state = "0"
|
||||
if(CIRCUIT_CORE)
|
||||
icon_state = "1"
|
||||
if(SCREWED_CORE)
|
||||
icon_state = "2"
|
||||
if(CABLED_CORE)
|
||||
if(core_mmi)
|
||||
icon_state = "3b"
|
||||
else
|
||||
icon_state = "3"
|
||||
if(GLASS_CORE)
|
||||
icon_state = "4"
|
||||
if(AI_READY_CORE)
|
||||
icon_state = "ai-empty"
|
||||
return ..()
|
||||
|
||||
/obj/structure/ai_core/atom_deconstruct(disassembled = TRUE)
|
||||
if(state >= GLASS_CORE)
|
||||
new /obj/item/stack/sheet/rglass(loc, 2)
|
||||
if(state >= CABLED_CORE)
|
||||
new /obj/item/stack/cable_coil(loc, 5)
|
||||
if(circuit)
|
||||
circuit.forceMove(loc)
|
||||
circuit = null
|
||||
new /obj/item/stack/sheet/plasteel(loc, 4)
|
||||
|
||||
/// Quick proc to call to see if the brainmob inside of us has suicided. Returns TRUE if we have, FALSE in any other scenario.
|
||||
/obj/structure/ai_core/proc/suicide_check()
|
||||
if(isnull(core_mmi) || isnull(core_mmi.brainmob))
|
||||
return FALSE
|
||||
return HAS_TRAIT(core_mmi.brainmob, TRAIT_SUICIDED)
|
||||
|
||||
/*
|
||||
This is a good place for AI-related object verbs so I'm sticking it here.
|
||||
If adding stuff to this, don't forget that an AI need to cancel_camera() whenever it physically moves to a different location.
|
||||
That prevents a few funky behaviors.
|
||||
*/
|
||||
//The type of interaction, the player performing the operation, the AI itself, and the card object, if any.
|
||||
|
||||
|
||||
/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."))
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/obj/structure/ai_core/transfer_ai(interaction, mob/user, mob/living/silicon/ai/AI, obj/item/aicard/card)
|
||||
if(state != AI_READY_CORE || !..())
|
||||
return
|
||||
if(core_mmi && core_mmi.brainmob)
|
||||
if(core_mmi.brainmob.mind)
|
||||
to_chat(user, span_warning("[src] already contains an active mind!"))
|
||||
return
|
||||
else if(suicide_check())
|
||||
to_chat(user, span_warning("[AI_CORE_BRAIN(core_mmi)] installed in [src] is completely useless!"))
|
||||
return
|
||||
//Transferring a carded AI to a core.
|
||||
if(interaction == AI_TRANS_FROM_CARD)
|
||||
AI.set_control_disabled(FALSE)
|
||||
AI.radio_enabled = TRUE
|
||||
AI.forceMove(loc) // to replace the terminal.
|
||||
to_chat(AI, span_notice("You have been uploaded to a stationary terminal. Remote device connection restored."))
|
||||
to_chat(user, "[span_boldnotice("Transfer successful")]: [AI.name] ([rand(1000,9999)].exe) installed and executed successfully. Local copy has been removed.")
|
||||
card.AI = null
|
||||
AI.battery = circuit.battery
|
||||
AI.posibrain_inside = isnull(core_mmi) || core_mmi.braintype == "Android"
|
||||
qdel(src)
|
||||
else //If for some reason you use an empty card on an empty AI terminal.
|
||||
to_chat(user, span_alert("There is no AI loaded on this terminal."))
|
||||
|
||||
/obj/item/circuitboard/aicore
|
||||
name = "AI core (AI Core Board)" //Well, duh, but best to be consistent
|
||||
var/battery = 200 //backup battery for when the AI loses power. Copied to/from AI mobs when carding, and placed here to avoid recharge via deconning the core
|
||||
|
||||
/obj/item/circuitboard/aicore/Initialize(mapload)
|
||||
. = ..()
|
||||
if(mapload && HAS_TRAIT(SSstation, STATION_TRAIT_HUMAN_AI))
|
||||
return INITIALIZE_HINT_QDEL
|
||||
|
||||
#undef AI_CORE_BRAIN
|
||||
@@ -40,7 +40,6 @@
|
||||
malfunction_flavor = strings(MALFUNCTION_FLAVOR_FILE, employer)
|
||||
|
||||
add_law_zero()
|
||||
RegisterSignal(owner.current, COMSIG_SILICON_AI_CORE_STATUS, PROC_REF(core_status))
|
||||
if(malf_sound)
|
||||
owner.current.playsound_local(get_turf(owner.current), malf_sound, 100, FALSE, pressure_affected = FALSE, use_reverb = FALSE)
|
||||
owner.current.grant_language(/datum/language/codespeak, source = LANGUAGE_MALF)
|
||||
@@ -57,7 +56,6 @@
|
||||
malf_ai.remove_malf_abilities()
|
||||
QDEL_NULL(malf_ai.malf_picker)
|
||||
|
||||
UnregisterSignal(owner, COMSIG_SILICON_AI_CORE_STATUS)
|
||||
return ..()
|
||||
|
||||
/// Generates a complete set of malf AI objectives up to the traitor objective limit.
|
||||
@@ -271,14 +269,6 @@
|
||||
|
||||
return malf_ai_icon
|
||||
|
||||
/datum/antagonist/malf_ai/proc/core_status(datum/source)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
var/mob/living/silicon/ai/malf_owner = owner.current
|
||||
if(malf_owner?.linked_core)
|
||||
return COMPONENT_CORE_ALL_GOOD
|
||||
return COMPONENT_CORE_DISCONNECTED
|
||||
|
||||
//Subtype of Malf AI datum, used for one of the traitor final objectives
|
||||
/datum/antagonist/malf_ai/infected
|
||||
name = "Infected AI"
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
/mob/living/silicon/ai/Initialize(mapload, datum/ai_laws/L, mob/target_ai)
|
||||
. = ..()
|
||||
if(!target_ai) //If there is no player/brain inside.
|
||||
new/obj/structure/ai_core/deactivated(loc) //New empty terminal.
|
||||
new/obj/structure/ai_core(loc, CORE_STATE_FINISHED) //New empty terminal.
|
||||
return INITIALIZE_HINT_QDEL //Delete AI.
|
||||
|
||||
ADD_TRAIT(src, TRAIT_NO_TELEPORT, AI_ANCHOR_TRAIT)
|
||||
@@ -152,7 +152,7 @@
|
||||
current = null
|
||||
bot_ref = null
|
||||
controlled_equipment = null
|
||||
linked_core = null
|
||||
break_core_link()
|
||||
apc_override = null
|
||||
if(ai_voicechanger)
|
||||
ai_voicechanger.owner = null
|
||||
@@ -363,53 +363,45 @@
|
||||
status_flags &= ~CANPUSH //we dont want the core to be push-able when anchored
|
||||
ADD_TRAIT(src, TRAIT_NO_TELEPORT, AI_ANCHOR_TRAIT)
|
||||
|
||||
/// Creates an MMI of the AI based on its configuration.
|
||||
/mob/living/silicon/ai/proc/make_mmi(atom/destination) as /obj/item/mmi
|
||||
RETURN_TYPE(/obj/item/mmi)
|
||||
//FIXME: this code is really bad, we shouldn't be doing most of this ourselves. MMI code needs a good refactoring....
|
||||
var/obj/item/mmi/copied_mmi
|
||||
if(posibrain_inside)
|
||||
copied_mmi = new /obj/item/mmi/posibrain(destination, FALSE)
|
||||
copied_mmi.name = "[initial(copied_mmi.name)] ([real_name])"
|
||||
else
|
||||
copied_mmi = new /obj/item/mmi(destination)
|
||||
copied_mmi.name = "[initial(copied_mmi.name)]: [real_name]"
|
||||
copied_mmi.brain = new /obj/item/organ/brain(copied_mmi)
|
||||
copied_mmi.brain.organ_flags |= ORGAN_FROZEN
|
||||
copied_mmi.brain.name = "[real_name]'s brain"
|
||||
copied_mmi.set_brainmob(new /mob/living/brain(copied_mmi))
|
||||
copied_mmi.brainmob.container = copied_mmi
|
||||
|
||||
copied_mmi.brainmob.name = real_name
|
||||
copied_mmi.brainmob.real_name = real_name
|
||||
copied_mmi.brainmob.gender = gender
|
||||
|
||||
var/suicided = HAS_TRAIT(src, TRAIT_SUICIDED)
|
||||
copied_mmi.brainmob.set_suicide(suicided)
|
||||
copied_mmi.brain?.suicided = suicided // we can't guarantee that the MMI has a brain... sigh
|
||||
|
||||
if(copied_mmi.brainmob.stat == DEAD && !suicided)
|
||||
copied_mmi.brainmob.set_stat(CONSCIOUS)
|
||||
|
||||
copied_mmi.update_appearance()
|
||||
return copied_mmi
|
||||
|
||||
/mob/living/silicon/ai/proc/ai_mob_to_structure()
|
||||
disconnect_shell()
|
||||
ShutOffDoomsdayDevice()
|
||||
var/obj/structure/ai_core/deactivated/ai_core = new(get_turf(src), /* skip_mmi_creation = */ TRUE)
|
||||
if(make_mmi_drop_and_transfer(ai_core.core_mmi, the_core = ai_core))
|
||||
qdel(src)
|
||||
var/obj/structure/ai_core/ai_core = new(get_turf(src), CORE_STATE_FINISHED, make_mmi())
|
||||
mind?.transfer_to(ai_core.core_mmi.brainmob)
|
||||
qdel(src)
|
||||
return ai_core
|
||||
|
||||
/mob/living/silicon/ai/proc/break_core_link()
|
||||
to_chat(src, span_danger("Your core has been destroyed!"))
|
||||
linked_core = null
|
||||
|
||||
/mob/living/silicon/ai/proc/make_mmi_drop_and_transfer(obj/item/mmi/the_mmi, the_core)
|
||||
var/mmi_type
|
||||
if(posibrain_inside)
|
||||
mmi_type = new/obj/item/mmi/posibrain(src, /* autoping = */ FALSE)
|
||||
else
|
||||
mmi_type = new/obj/item/mmi(src)
|
||||
if(hack_software)
|
||||
new/obj/item/malf_upgrade(get_turf(src))
|
||||
the_mmi = mmi_type
|
||||
the_mmi.brain = new /obj/item/organ/brain(the_mmi)
|
||||
the_mmi.brain.organ_flags |= ORGAN_FROZEN
|
||||
the_mmi.brain.name = "[real_name]'s brain"
|
||||
the_mmi.name = "[initial(the_mmi.name)]: [real_name]"
|
||||
the_mmi.set_brainmob(new /mob/living/brain(the_mmi))
|
||||
the_mmi.brainmob.name = src.real_name
|
||||
the_mmi.brainmob.real_name = src.real_name
|
||||
the_mmi.brainmob.container = the_mmi
|
||||
the_mmi.brainmob.gender = src.gender
|
||||
|
||||
var/has_suicided_trait = HAS_TRAIT(src, TRAIT_SUICIDED)
|
||||
the_mmi.brainmob.set_suicide(has_suicided_trait)
|
||||
the_mmi.brain.suicided = has_suicided_trait
|
||||
if(the_core)
|
||||
var/obj/structure/ai_core/core = the_core
|
||||
core.core_mmi = the_mmi
|
||||
the_mmi.forceMove(the_core)
|
||||
else
|
||||
the_mmi.forceMove(get_turf(src))
|
||||
if(the_mmi.brainmob.stat == DEAD && !has_suicided_trait)
|
||||
the_mmi.brainmob.set_stat(CONSCIOUS)
|
||||
if(mind)
|
||||
mind.transfer_to(the_mmi.brainmob)
|
||||
the_mmi.update_appearance()
|
||||
return TRUE
|
||||
|
||||
/mob/living/silicon/ai/Topic(href, href_list)
|
||||
..()
|
||||
if(usr != src)
|
||||
@@ -702,7 +694,7 @@
|
||||
if(!istype(apc))
|
||||
to_chat(owner, span_notice("You are already in your Main Core."))
|
||||
return
|
||||
if(SEND_SIGNAL(owner, COMSIG_SILICON_AI_CORE_STATUS) & COMPONENT_CORE_ALL_GOOD)
|
||||
if(astype(owner, /mob/living/silicon/ai)?.linked_core)
|
||||
apc.malfvacate()
|
||||
else
|
||||
to_chat(owner, span_danger("Linked core not detected!"))
|
||||
@@ -786,7 +778,7 @@
|
||||
balloon_alert(user, "no intelligence detected!") // average tg coder am i right
|
||||
return
|
||||
ShutOffDoomsdayDevice()
|
||||
var/obj/structure/ai_core/new_core = new /obj/structure/ai_core/deactivated(loc, posibrain_inside)//Spawns a deactivated terminal at AI location.
|
||||
var/obj/structure/ai_core/new_core = new /obj/structure/ai_core(loc, CORE_STATE_FINISHED, make_mmi())
|
||||
new_core.circuit.battery = battery
|
||||
ai_restore_power()//So the AI initially has power.
|
||||
set_control_disabled(TRUE) //Can't control things remotely if you're stuck in a card!
|
||||
@@ -1109,6 +1101,99 @@
|
||||
SEND_SIGNAL(src, COMSIG_SILICON_AI_SET_CONTROL_DISABLED, control_disabled)
|
||||
src.control_disabled = control_disabled
|
||||
|
||||
|
||||
/// Establishes a "core link" with a supplied core structure.
|
||||
/// This will register multiple signals and give the AI a strong reference to it.
|
||||
/// See [proc/resolve_core_link] or [proc/break_core_link] for ways to end the connection.
|
||||
/mob/living/silicon/ai/proc/create_core_link(obj/structure/ai_core/core)
|
||||
if(linked_core) //uh oh
|
||||
break_core_link(linked_core)
|
||||
linked_core = core
|
||||
|
||||
//this block is kind of sketchy, but I don't think this should cause any problems
|
||||
qdel(core.core_mmi)
|
||||
core.core_mmi = make_mmi(core)
|
||||
|
||||
RegisterSignals(linked_core, list(COMSIG_ATOM_DESTRUCTION, COMSIG_QDELETING), PROC_REF(on_core_destroyed))
|
||||
RegisterSignals(linked_core, list(
|
||||
COMSIG_ATOM_ITEM_INTERACTION,
|
||||
COMSIG_ATOM_TOOL_ACT(TOOL_CROWBAR),
|
||||
COMSIG_ATOM_TOOL_ACT(TOOL_WRENCH),
|
||||
COMSIG_ATOM_TOOL_ACT(TOOL_WELDER),
|
||||
COMSIG_ATOM_TOOL_ACT(TOOL_WIRECUTTER),
|
||||
COMSIG_ATOM_TOOL_ACT(TOOL_SCREWDRIVER),
|
||||
), PROC_REF(on_core_item_interaction))
|
||||
RegisterSignal(linked_core, COMSIG_ATOM_TAKE_DAMAGE, PROC_REF(on_core_take_damage))
|
||||
RegisterSignal(linked_core, COMSIG_ATOM_EXITED, PROC_REF(on_core_exited))
|
||||
|
||||
/// Elegantly closes the AI's link to a core structure,
|
||||
/// moving them to its location and cleaning it up. This is generally what you want to call.
|
||||
/// Prefer calling [proc/break_core_link] directly if the connection is meant to be suddenly severed.
|
||||
/mob/living/silicon/ai/proc/resolve_core_link()
|
||||
if(!linked_core) //oh no bro
|
||||
CRASH("tried to resolve a core link with no core!!!!")
|
||||
|
||||
forceMove(linked_core.loc)
|
||||
var/obj/structure/ai_core/unlinked_core = linked_core
|
||||
break_core_link()
|
||||
qdel(unlinked_core)
|
||||
cancel_camera()
|
||||
|
||||
/// Handles unregistering the AI from its core. The core itself will not be cleaned up.
|
||||
/// Prefer calling [proc/resolve_core_link] if the connection is being closed elegantly.
|
||||
/mob/living/silicon/ai/proc/break_core_link()
|
||||
if(!linked_core)
|
||||
return
|
||||
|
||||
UnregisterSignal(linked_core, list(
|
||||
COMSIG_QDELETING, COMSIG_ATOM_DESTRUCTION, //on_core_destroyed
|
||||
//on_core_item_interaction
|
||||
COMSIG_ATOM_ITEM_INTERACTION,
|
||||
COMSIG_ATOM_TOOL_ACT(TOOL_CROWBAR),
|
||||
COMSIG_ATOM_TOOL_ACT(TOOL_WRENCH),
|
||||
COMSIG_ATOM_TOOL_ACT(TOOL_WELDER),
|
||||
COMSIG_ATOM_TOOL_ACT(TOOL_WIRECUTTER),
|
||||
COMSIG_ATOM_TOOL_ACT(TOOL_SCREWDRIVER),
|
||||
COMSIG_ATOM_TAKE_DAMAGE, //on_core_take_damage
|
||||
COMSIG_ATOM_EXITED, //on_core_exited
|
||||
))
|
||||
linked_core = null
|
||||
|
||||
/mob/living/silicon/ai/proc/on_core_item_interaction(datum/source, mob/living/user, obj/item/tool, list/processing_recipes)
|
||||
SIGNAL_HANDLER
|
||||
if(user.combat_mode)
|
||||
return NONE
|
||||
|
||||
to_chat(src, span_danger("CORE TAMPERING DETECTED!"))
|
||||
return NONE
|
||||
|
||||
/mob/living/silicon/ai/proc/on_core_take_damage(datum/source, damage_taken, ...)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(damage_taken > 0)
|
||||
to_chat(src, span_danger("CORE DAMAGE DETECTED!"))
|
||||
return NONE
|
||||
|
||||
/mob/living/silicon/ai/proc/on_core_destroyed(datum/source, damage_flag)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
to_chat(src, span_danger("Your core has been destroyed!"))
|
||||
ShutOffDoomsdayDevice()
|
||||
break_core_link()
|
||||
|
||||
/mob/living/silicon/ai/proc/on_core_exited(datum/source, atom/movable/gone, direction)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(istype(gone, /obj/item/mmi))
|
||||
var/obj/item/mmi/mmi_gone = gone
|
||||
on_core_destroyed(source, NONE)
|
||||
if(!IS_MALF_AI(src)) //don't pull back shunted malf AIs
|
||||
death(gibbed = TRUE, drop_mmi = FALSE)
|
||||
///the drop_mmi param determines whether the MMI is dropped at their current location
|
||||
///which in this case would be somewhere else, so we drop their MMI at the core instead
|
||||
mind?.transfer_to(mmi_gone.brainmob)
|
||||
qdel(src)
|
||||
|
||||
#undef HOLOGRAM_CHOICE_CHARACTER
|
||||
#undef CHARACTER_TYPE_SELF
|
||||
#undef CHARACTER_TYPE_CREWMEMBER
|
||||
|
||||
@@ -122,8 +122,8 @@
|
||||
/* REMOTE CONTROL */
|
||||
/// Equipment that the AI is controlling remotely, to determine whether to relaymove or use the AI eye
|
||||
VAR_FINAL/obj/controlled_equipment
|
||||
/// AI core that this AI is linked to, used when put into an exosuit
|
||||
VAR_FINAL/obj/structure/ai_core/deactivated/linked_core
|
||||
/// AI core that this AI is linked to. See [proc/create_core_link] [proc/resolve_core_link] [proc/break_core_link]
|
||||
VAR_FINAL/obj/structure/ai_core/linked_core
|
||||
/// Robot that this AI is currently using
|
||||
VAR_FINAL/mob/living/silicon/robot/deployed_shell
|
||||
/// Action to deploy to a shell from a list of options
|
||||
|
||||
@@ -34,7 +34,8 @@
|
||||
ShutOffDoomsdayDevice()
|
||||
|
||||
if(gibbed && drop_mmi)
|
||||
make_mmi_drop_and_transfer()
|
||||
var/obj/item/mmi/loose_cpu = make_mmi(get_turf(src))
|
||||
mind?.transfer_to(loose_cpu.brainmob)
|
||||
|
||||
if(explodes_on_death)
|
||||
addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(explosion), loc, 3, 6, 12, null, 15), 1 SECONDS)
|
||||
@@ -42,7 +43,5 @@
|
||||
SSblackbox.ReportDeath(src)
|
||||
|
||||
/mob/living/silicon/ai/proc/ShutOffDoomsdayDevice()
|
||||
if(nuking)
|
||||
nuking = FALSE
|
||||
if(doomsday_device)
|
||||
qdel(doomsday_device)
|
||||
nuking = FALSE
|
||||
QDEL_NULL(doomsday_device)
|
||||
|
||||
@@ -45,8 +45,7 @@
|
||||
malf.ShutOffDoomsdayDevice()
|
||||
occupier = malf
|
||||
if (isturf(malf.loc)) // create a deactivated AI core if the AI isn't coming from an emergency mech shunt
|
||||
malf.linked_core = new /obj/structure/ai_core/deactivated(malf.loc)
|
||||
malf.linked_core.remote_ai = malf // note that we do not set the deactivated core's core_mmi.brainmob
|
||||
malf.create_core_link(new /obj/structure/ai_core(malf.loc, CORE_STATE_FINISHED, malf.make_mmi()))
|
||||
malf.forceMove(src) // move INTO the APC, not to its tile
|
||||
if(!findtext(occupier.name, "APC Copy"))
|
||||
occupier.name = "[malf.name] APC Copy"
|
||||
@@ -74,9 +73,7 @@
|
||||
return
|
||||
if(occupier.linked_core)
|
||||
occupier.shunted = FALSE
|
||||
occupier.forceMove(occupier.linked_core.loc)
|
||||
qdel(occupier.linked_core)
|
||||
occupier.cancel_camera()
|
||||
occupier.resolve_core_link()
|
||||
occupier = null
|
||||
else
|
||||
stack_trace("An AI: [occupier] has vacated an APC with no linked core and without being gibbed.")
|
||||
|
||||
@@ -332,6 +332,7 @@
|
||||
var/mob/living/silicon/ai/unlucky_ai
|
||||
for(var/mob/living/occupant as anything in occupants)
|
||||
if(isAI(occupant))
|
||||
//FIXME: Nothiing about this block works
|
||||
var/mob/living/silicon/ai/ai = occupant
|
||||
if(!ai.linked_core && !ai.can_shunt) // we probably shouldnt gib AIs with a core or shunting abilities
|
||||
unlucky_ai = occupant
|
||||
|
||||
@@ -78,10 +78,7 @@
|
||||
return
|
||||
|
||||
if(AI_MECH_HACK) //Called by AIs on the mech
|
||||
var/obj/structure/ai_core/deactivated/deactivated_core = new(AI.loc, FALSE, FALSE, AI)
|
||||
AI.linked_core = deactivated_core
|
||||
AI.linked_core.RegisterSignal(deactivated_core, COMSIG_ATOM_DESTRUCTION, TYPE_PROC_REF(/obj/structure/ai_core/deactivated, disable_doomsday)) //Protect that core! The structure goes bye-bye when we re-shunt back in so no need for cleanup.
|
||||
AI.linked_core.remote_ai = AI
|
||||
AI.create_core_link(new /obj/structure/ai_core(AI.loc, CORE_STATE_FINISHED, AI.make_mmi()))
|
||||
if(AI.can_dominate_mechs && LAZYLEN(occupants)) //Oh, I am sorry, were you using that?
|
||||
to_chat(AI, span_warning("Occupants detected! Forced ejection initiated!"))
|
||||
to_chat(occupants, span_danger("You have been forcibly ejected!"))
|
||||
|
||||
@@ -111,7 +111,9 @@
|
||||
brain_mob.log_message("was put into [src] by [key_name(user)]", LOG_GAME, log_globally = FALSE)
|
||||
return TRUE
|
||||
|
||||
|
||||
/obj/vehicle/sealed/mecha/mob_exit(mob/M, silent = FALSE, randomstep = FALSE, forced = FALSE)
|
||||
// FIXME: this code is really bad (shocker). Needs a refactor
|
||||
var/atom/movable/mob_container
|
||||
var/turf/newloc = get_turf(src)
|
||||
if(ishuman(M))
|
||||
@@ -147,9 +149,7 @@
|
||||
if(!forced && !silent)
|
||||
to_chat(AI, span_notice("Returning to core..."))
|
||||
mecha_flags &= ~SILICON_PILOT
|
||||
newloc = get_turf(AI.linked_core)
|
||||
qdel(AI.linked_core)
|
||||
AI.forceMove(newloc)
|
||||
AI.resolve_core_link()
|
||||
if(forced)
|
||||
to_chat(AI, span_danger("ZZUZULU.ERR--ERRR-NEUROLOG-- PERCEP--- DIST-B**@"))
|
||||
for(var/count in 1 to 5)
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 410 KiB After Width: | Height: | Size: 410 KiB |
+2
-1
@@ -2251,6 +2251,8 @@
|
||||
#include "code\game\machinery\wall_healer.dm"
|
||||
#include "code\game\machinery\washing_machine.dm"
|
||||
#include "code\game\machinery\wishgranter.dm"
|
||||
#include "code\game\machinery\ai_core\_core.dm"
|
||||
#include "code\game\machinery\ai_core\core_construction.dm"
|
||||
#include "code\game\machinery\camera\camera.dm"
|
||||
#include "code\game\machinery\camera\camera_construction.dm"
|
||||
#include "code\game\machinery\camera\motion.dm"
|
||||
@@ -2869,7 +2871,6 @@
|
||||
#include "code\game\objects\items\tools\painter\airlock_painter.dm"
|
||||
#include "code\game\objects\items\tools\painter\decal_painter.dm"
|
||||
#include "code\game\objects\items\tools\painter\paintable_decals.dm"
|
||||
#include "code\game\objects\structures\ai_core.dm"
|
||||
#include "code\game\objects\structures\aliens.dm"
|
||||
#include "code\game\objects\structures\bedsheet_bin.dm"
|
||||
#include "code\game\objects\structures\billboard.dm"
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
/obj/structure/ai_core/deactivated/@SUBTYPES : /obj/structure/ai_core/@SUBTYPES{@OLD;state=5}
|
||||
Reference in New Issue
Block a user