Files
Bubberstation/code/game/objects/structures/ai_core.dm
Watermelon914 375a20e49b Refactors most spans into span procs (#59645)
Converts most spans into span procs. Mostly used regex for this and sorted out any compile time errors afterwards so there could be some bugs.
Was initially going to do defines, but ninja said to make it into a proc, and if there's any overhead, they can easily be changed to defines.

Makes it easier to control the formatting and prevents typos when creating spans as it'll runtime if you misspell instead of silently failing.
Reduces the code you need to write when writing spans, as you don't need to close the span as that's automatically handled by the proc.

(Note from Lemon: This should be converted to defines once we update the minimum version to 514. Didn't do it now because byond pain and such)
2021-06-14 13:03:53 -07:00

331 lines
11 KiB
Plaintext

/obj/structure/ai_core
density = TRUE
anchored = FALSE
name = "\improper AI core"
icon = 'icons/mob/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/brain
var/can_deconstruct = TRUE
/obj/structure/ai_core/Initialize()
. = ..()
laws = new
laws.set_laws_config()
/obj/structure/ai_core/handle_atom_del(atom/A)
if(A == circuit)
circuit = null
if((state != GLASS_CORE) && (state != AI_READY_CORE))
state = EMPTY_CORE
update_appearance()
if(A == brain)
brain = null
return ..()
/obj/structure/ai_core/Destroy()
QDEL_NULL(circuit)
QDEL_NULL(brain)
QDEL_NULL(laws)
return ..()
/obj/structure/ai_core/deactivated
name = "inactive AI"
icon_state = "ai-empty"
anchored = TRUE
state = AI_READY_CORE
/obj/structure/ai_core/deactivated/Initialize()
. = ..()
circuit = new(src)
/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."
can_deconstruct = FALSE
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()
. = ..()
circuit = new(src)
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(!istype(T, /turf/open/floor))
return FALSE
return TRUE
/obj/structure/ai_core/latejoin_inactive/attackby(obj/item/P, mob/user, params)
if(P.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/attackby(obj/item/P, mob/user, params)
if(P.tool_behaviour == TOOL_WRENCH)
return default_unfasten_wrench(user, P, 20)
if(!anchored)
if(P.tool_behaviour == TOOL_WELDER && can_deconstruct)
if(state != EMPTY_CORE)
to_chat(user, span_warning("The core must be empty to deconstruct it!"))
return
if(!P.tool_start_check(user, amount=0))
return
to_chat(user, span_notice("You start to deconstruct the frame..."))
if(P.use_tool(src, user, 20, volume=50) && state == EMPTY_CORE)
to_chat(user, span_notice("You deconstruct the frame."))
deconstruct(TRUE)
return
else
switch(state)
if(EMPTY_CORE)
if(istype(P, /obj/item/circuitboard/aicore))
if(!user.transferItemToLoc(P, src))
return
playsound(loc, 'sound/items/deconstruct.ogg', 50, TRUE)
to_chat(user, span_notice("You place the circuit board inside the frame."))
update_appearance()
state = CIRCUIT_CORE
circuit = P
return
if(CIRCUIT_CORE)
if(P.tool_behaviour == TOOL_SCREWDRIVER)
P.play_tool_sound(src)
to_chat(user, span_notice("You screw the circuit board into place."))
state = SCREWED_CORE
update_appearance()
return
if(P.tool_behaviour == TOOL_CROWBAR)
P.play_tool_sound(src)
to_chat(user, span_notice("You remove the circuit board."))
state = EMPTY_CORE
update_appearance()
circuit.forceMove(loc)
circuit = null
return
if(SCREWED_CORE)
if(P.tool_behaviour == TOOL_SCREWDRIVER && circuit)
P.play_tool_sound(src)
to_chat(user, span_notice("You unfasten the circuit board."))
state = CIRCUIT_CORE
update_appearance()
return
if(istype(P, /obj/item/stack/cable_coil))
var/obj/item/stack/cable_coil/C = P
if(C.get_amount() >= 5)
playsound(loc, 'sound/items/deconstruct.ogg', 50, TRUE)
to_chat(user, span_notice("You start to add cables to the frame..."))
if(do_after(user, 20, target = src) && state == SCREWED_CORE && C.use(5))
to_chat(user, span_notice("You add cables to the frame."))
state = CABLED_CORE
update_appearance()
else
to_chat(user, span_warning("You need five lengths of cable to wire the AI core!"))
return
if(CABLED_CORE)
if(P.tool_behaviour == TOOL_WIRECUTTER)
if(brain)
to_chat(user, span_warning("Get that [brain.name] out of there first!"))
else
P.play_tool_sound(src)
to_chat(user, span_notice("You remove the cables."))
state = SCREWED_CORE
update_appearance()
new /obj/item/stack/cable_coil(drop_location(), 5)
return
if(istype(P, /obj/item/stack/sheet/rglass))
var/obj/item/stack/sheet/rglass/G = P
if(G.get_amount() >= 2)
playsound(loc, 'sound/items/deconstruct.ogg', 50, TRUE)
to_chat(user, span_notice("You start to put in the glass panel..."))
if(do_after(user, 20, target = src) && state == CABLED_CORE && G.use(2))
to_chat(user, span_notice("You put in the glass panel."))
state = GLASS_CORE
update_appearance()
else
to_chat(user, span_warning("You need two sheets of reinforced glass to insert them into the AI core!"))
return
if(istype(P, /obj/item/ai_module))
if(brain && brain.laws.id != DEFAULT_AI_LAWID)
to_chat(user, span_warning("The installed [brain.name] already has set laws!"))
return
var/obj/item/ai_module/module = P
module.install(laws, user)
return
if(istype(P, /obj/item/mmi) && !brain)
var/obj/item/mmi/M = P
if(!M.brain_check(user))
return
var/mob/living/brain/B = M.brainmob
if(!CONFIG_GET(flag/allow_ai) || (is_banned_from(B.ckey, "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
brain = M
to_chat(user, span_notice("You add [M.name] to the frame."))
update_appearance()
return
if(P.tool_behaviour == TOOL_CROWBAR && brain)
P.play_tool_sound(src)
to_chat(user, span_notice("You remove the brain."))
brain.forceMove(loc)
brain = null
update_appearance()
return
if(GLASS_CORE)
if(P.tool_behaviour == TOOL_CROWBAR)
P.play_tool_sound(src)
to_chat(user, span_notice("You remove the glass panel."))
state = CABLED_CORE
update_appearance()
new /obj/item/stack/sheet/rglass(loc, 2)
return
if(P.tool_behaviour == TOOL_SCREWDRIVER)
P.play_tool_sound(src)
to_chat(user, span_notice("You connect the monitor."))
if(brain)
var/mob/living/brain/B = brain.brainmob
B.mind?.remove_antags_for_borging()
var/mob/living/silicon/ai/A = null
if (brain.overrides_aicore_laws)
A = new /mob/living/silicon/ai(loc, brain.laws, B)
brain.laws = null //Brain's law datum is being donated, so we need the brain to let it go or the GC will eat it
else
A = new /mob/living/silicon/ai(loc, laws, B)
laws = null //we're giving the new AI this datum, so let's not delete it when we qdel(src) 5 lines from now
if(brain.force_replace_ai_name)
A.fully_replace_character_name(A.name, brain.replacement_ai_name())
SSblackbox.record_feedback("amount", "ais_created", 1)
deadchat_broadcast(" has been brought online at <b>[get_area_name(A, TRUE)]</b>.", span_name("[A]"), follow_target=A, message_type=DEADCHAT_ANNOUNCEMENT)
qdel(src)
else
state = AI_READY_CORE
update_appearance()
return
if(AI_READY_CORE)
if(istype(P, /obj/item/aicard))
return //handled by /obj/structure/ai_core/transfer_ai()
if(P.tool_behaviour == TOOL_SCREWDRIVER)
P.play_tool_sound(src)
to_chat(user, span_notice("You disconnect the monitor."))
state = GLASS_CORE
update_appearance()
return
return ..()
/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(brain)
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/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)
qdel(src)
/*
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)
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
//Transferring a carded AI to a core.
if(interaction == AI_TRANS_FROM_CARD)
AI.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
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