mirror of
https://github.com/yogstation13/Yogstation.git
synced 2025-02-26 09:04:50 +00:00
Revival of "Allows AIs to deploy to borgs" by Shadowlight213 (#25184)
The AI may now deploy to cyborgs prepared as AI shells. The module to do this may be research in the exosuit fabricator. Simply slot the module into a completed cyborg frame as with an MMI, or into a playerless (with no ckey) cyborg.
This commit is contained in:
@@ -34,3 +34,9 @@
|
||||
#define FLOOR_BOT 4 // Floorbots
|
||||
#define CLEAN_BOT 8 // Cleanbots
|
||||
#define MED_BOT 16 // Medibots
|
||||
|
||||
//AI notification defines
|
||||
#define NEW_BORG 1
|
||||
#define NEW_MODULE 2
|
||||
#define RENAME 3
|
||||
#define AI_SHELL 4
|
||||
@@ -232,7 +232,7 @@ Turf and target are seperate in case you want to teleport some distance from a t
|
||||
/proc/active_free_borgs()
|
||||
. = list()
|
||||
for(var/mob/living/silicon/robot/R in living_mob_list)
|
||||
if(R.connected_ai)
|
||||
if(R.connected_ai || R.shell)
|
||||
continue
|
||||
if(R.stat == DEAD)
|
||||
continue
|
||||
|
||||
@@ -13,4 +13,5 @@ var/global/list/living_mob_list = list() //all alive mobs, including clientles
|
||||
var/global/list/dead_mob_list = list() //all dead mobs, including clientless. Excludes /mob/dead/new_player
|
||||
var/global/list/joined_player_list = list() //all clients that have joined the game at round-start or as a latejoin.
|
||||
var/global/list/silicon_mobs = list() //all silicon mobs
|
||||
var/global/list/pai_list = list()
|
||||
var/global/list/pai_list = list()
|
||||
var/global/list/available_ai_shells = list()
|
||||
@@ -18,6 +18,14 @@
|
||||
. = is_eligible_servant(new_body)
|
||||
|
||||
/datum/antagonist/clockcultist/give_to_body(mob/living/new_body)
|
||||
if(iscyborg(new_body))
|
||||
var/mob/living/silicon/robot/R = new_body
|
||||
if(R.deployed)
|
||||
var/mob/living/silicon/ai/AI = R.mainframe
|
||||
R.undeploy()
|
||||
var/converted = add_servant_of_ratvar(AI, silent_update)
|
||||
to_chat(AI, "<span class='userdanger'>Anomaly Detected. Returned to core!</span>") //The AI needs to be in its core to properly be converted
|
||||
return converted
|
||||
if(!silent_update)
|
||||
if(issilicon(new_body))
|
||||
to_chat(new_body, "<span class='heavy_brass'>You are unable to compute this truth. Your vision glows a brilliant yellow, and all at once it comes to you. Ratvar, the Clockwork Justiciar, \
|
||||
@@ -69,7 +77,8 @@
|
||||
var/mob/living/silicon/S = owner
|
||||
if(iscyborg(S))
|
||||
var/mob/living/silicon/robot/R = S
|
||||
R.UnlinkSelf()
|
||||
if(!R.shell)
|
||||
R.UnlinkSelf()
|
||||
R.module.rebuild_modules()
|
||||
else if(isAI(S))
|
||||
var/mob/living/silicon/ai/A = S
|
||||
|
||||
@@ -34,7 +34,11 @@
|
||||
var/new_ai = select_active_ai(R)
|
||||
if(new_ai && (new_ai != R.connected_ai))
|
||||
R.connected_ai = new_ai
|
||||
R.notify_ai(TRUE)
|
||||
if(R.shell)
|
||||
R.undeploy() //If this borg is an AI shell, disconnect the controlling AI and assign ti to a new AI
|
||||
R.notify_ai(AI_SHELL)
|
||||
else
|
||||
R.notify_ai(TRUE)
|
||||
if(WIRE_CAMERA) // Pulse to disable the camera.
|
||||
if(!isnull(R.camera) && !R.scrambledcodes)
|
||||
R.camera.toggle_cam(usr, 0)
|
||||
@@ -56,11 +60,12 @@
|
||||
if(WIRE_AI) // Cut the AI wire to reset AI control.
|
||||
if(!mend)
|
||||
R.connected_ai = null
|
||||
R.undeploy() //Forced disconnect of an AI should this body be a shell.
|
||||
if(WIRE_LAWSYNC) // Cut the law wire, and the borg will no longer receive law updates from its AI. Repair and it will re-sync.
|
||||
if(mend)
|
||||
if(!R.emagged)
|
||||
R.lawupdate = TRUE
|
||||
else
|
||||
else if(!R.deployed) //AI shells must always have the same laws as the AI
|
||||
R.lawupdate = FALSE
|
||||
if (WIRE_CAMERA) // Disable the camera.
|
||||
if(!isnull(R.camera) && !R.scrambledcodes)
|
||||
|
||||
@@ -297,6 +297,28 @@
|
||||
else
|
||||
holder.icon_state = "hudnobatt"
|
||||
|
||||
//borg-AI shell tracking
|
||||
/mob/living/silicon/robot/proc/diag_hud_set_aishell() //Shows tracking beacons on the mech
|
||||
var/image/holder = hud_list[DIAG_TRACK_HUD]
|
||||
var/icon/I = icon(icon, icon_state, dir)
|
||||
holder.pixel_y = I.Height() - world.icon_size
|
||||
if(!shell) //Not an AI shell
|
||||
holder.icon_state = null
|
||||
else if(deployed) //AI shell in use by an AI
|
||||
holder.icon_state = "hudtrackingai"
|
||||
else //Empty AI shell
|
||||
holder.icon_state = "hudtracking"
|
||||
|
||||
//AI side tracking of AI shell control
|
||||
/mob/living/silicon/ai/proc/diag_hud_set_deployed() //Shows tracking beacons on the mech
|
||||
var/image/holder = hud_list[DIAG_TRACK_HUD]
|
||||
var/icon/I = icon(icon, icon_state, dir)
|
||||
holder.pixel_y = I.Height() - world.icon_size
|
||||
if(!deployed_shell)
|
||||
holder.icon_state = null
|
||||
else //AI is currently controlling a shell
|
||||
holder.icon_state = "hudtrackingai"
|
||||
|
||||
/*~~~~~~~~~~~~~~~~~~~~
|
||||
BIG STOMPY MECHS
|
||||
~~~~~~~~~~~~~~~~~~~~~*/
|
||||
|
||||
@@ -110,7 +110,7 @@
|
||||
sleep(30)
|
||||
if(R)
|
||||
R.SetLockdown(0)
|
||||
R.notify_ai(1)
|
||||
R.notify_ai(NEW_BORG)
|
||||
|
||||
/obj/machinery/transformer/conveyor/New()
|
||||
..()
|
||||
|
||||
@@ -206,7 +206,7 @@
|
||||
lawsync = 0
|
||||
O.connected_ai = null
|
||||
else
|
||||
O.notify_ai(1)
|
||||
O.notify_ai(NEW_BORG)
|
||||
if(forced_ai)
|
||||
O.connected_ai = forced_ai
|
||||
if(!lawsync)
|
||||
@@ -248,6 +248,41 @@
|
||||
else
|
||||
to_chat(user, "<span class='warning'>The MMI must go in after everything else!</span>")
|
||||
|
||||
else if(istype(W, /obj/item/borg/upgrade/ai))
|
||||
var/obj/item/borg/upgrade/ai/M = W
|
||||
if(check_completion())
|
||||
if(!isturf(loc))
|
||||
to_chat(user, "<span class='warning'>You cannot install[M], the frame has to be standing on the ground to be perfectly precise!</span>")
|
||||
return
|
||||
if(!user.drop_item())
|
||||
to_chat(user, "<span class='warning'>[M] is stuck to your hand!</span>")
|
||||
return
|
||||
qdel(M)
|
||||
var/mob/living/silicon/robot/O = new /mob/living/silicon/robot/shell(get_turf(src))
|
||||
|
||||
if(!aisync)
|
||||
lawsync = FALSE
|
||||
O.connected_ai = null
|
||||
else
|
||||
if(forced_ai)
|
||||
O.connected_ai = forced_ai
|
||||
O.notify_ai(AI_SHELL)
|
||||
if(!lawsync)
|
||||
O.lawupdate = FALSE
|
||||
O.make_laws()
|
||||
|
||||
|
||||
O.cell = chest.cell
|
||||
chest.cell.loc = O
|
||||
chest.cell = null
|
||||
O.locked = panel_locked
|
||||
O.job = "Cyborg"
|
||||
forceMove(O)
|
||||
O.robot_suit = src
|
||||
if(!locomotion)
|
||||
O.lockcharge = TRUE
|
||||
O.update_canmove()
|
||||
|
||||
else if(istype(W,/obj/item/weapon/pen))
|
||||
to_chat(user, "<span class='warning'>You need to use a multitool to name [src]!</span>")
|
||||
else
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
R.custom_name = heldname
|
||||
R.updatename()
|
||||
if(oldname == R.real_name)
|
||||
R.notify_ai(3, oldname, R.real_name)
|
||||
R.notify_ai(RENAME, oldname, R.real_name)
|
||||
|
||||
return 1
|
||||
|
||||
@@ -381,3 +381,22 @@
|
||||
R.module.add_module(S, FALSE, TRUE)
|
||||
|
||||
return 1
|
||||
|
||||
/obj/item/borg/upgrade/ai
|
||||
name = "B.O.R.I.S. module"
|
||||
desc = "Bluespace Optimized Remote Intelligence Synchronization. An uplink device which takes the place of an MMI in cyborg endoskeletons, creating a robotic shell controlled by an AI."
|
||||
icon_state = "boris"
|
||||
origin_tech = "engineering=4;magnets=4;programming=4"
|
||||
|
||||
/obj/item/borg/upgrade/ai/action(mob/living/silicon/robot/R)
|
||||
if(..())
|
||||
return
|
||||
if(R.shell)
|
||||
to_chat(usr, "<span class='warning'>This unit is already an AI shell!</span>")
|
||||
return
|
||||
if(R.key) //You cannot replace a player unless the key is completely removed.
|
||||
to_chat(usr, "<span class='warning'>Intelligence patterns detected in this [R.braintype]. Aborting.</span>")
|
||||
return
|
||||
|
||||
R.make_shell(src)
|
||||
return TRUE
|
||||
@@ -84,6 +84,9 @@ var/list/ai_list = list()
|
||||
var/obj/machinery/camera/portable/builtInCamera
|
||||
|
||||
var/obj/structure/AIcore/deactivated/linked_core //For exosuit control
|
||||
var/mob/living/silicon/robot/deployed_shell = null //For shell control
|
||||
var/datum/action/innate/deploy_shell/deploy_action = new
|
||||
var/datum/action/innate/deploy_last_shell/redeploy_action = new
|
||||
|
||||
/mob/living/silicon/ai/Initialize(mapload, datum/ai_laws/L, mob/target_ai)
|
||||
..()
|
||||
@@ -138,6 +141,8 @@ var/list/ai_list = list()
|
||||
radio = new /obj/item/device/radio/headset/ai(src)
|
||||
aicamera = new/obj/item/device/camera/siliconcam/ai_camera(src)
|
||||
|
||||
deploy_action.Grant(src)
|
||||
|
||||
if(isturf(loc))
|
||||
verbs.Add(/mob/living/silicon/ai/proc/ai_network_change, \
|
||||
/mob/living/silicon/ai/proc/ai_statuschange, /mob/living/silicon/ai/proc/ai_hologram_change, \
|
||||
@@ -247,13 +252,16 @@ var/list/ai_list = list()
|
||||
for(var/mob/living/silicon/robot/R in connected_robots)
|
||||
borg_area = get_area(R)
|
||||
var/robot_status = "Nominal"
|
||||
if(R.stat || !R.client)
|
||||
if(R.shell)
|
||||
robot_status = "AI SHELL"
|
||||
else if(R.stat || !R.client)
|
||||
robot_status = "OFFLINE"
|
||||
else if(!R.cell || R.cell.charge <= 0)
|
||||
robot_status = "DEPOWERED"
|
||||
//Name, Health, Battery, Module, Area, and Status! Everything an AI wants to know about its borgies!
|
||||
stat(null, text("[R.name] | S.Integrity: [R.health]% | Cell: [R.cell ? "[R.cell.charge]/[R.cell.maxcharge]" : "Empty"] | \
|
||||
Module: [R.designation] | Loc: [borg_area.name] | Status: [robot_status]"))
|
||||
Module: [R.designation] | Loc: [borg_area.name] | Status: [robot_status]"))
|
||||
stat(null, text("AI shell beacons detected: [LAZYLEN(available_ai_shells)]")) //Count of total AI shells
|
||||
else
|
||||
stat(null, text("Systems nonfunctional"))
|
||||
|
||||
@@ -791,12 +799,13 @@ var/list/ai_list = list()
|
||||
if(!..())
|
||||
return
|
||||
if(interaction == AI_TRANS_TO_CARD)//The only possible interaction. Upload AI mob to a card.
|
||||
if(!mind)
|
||||
to_chat(user, "<span class='warning'>No intelligence patterns detected.</span>" )
|
||||
return
|
||||
if(!can_be_carded)
|
||||
to_chat(user, "<span class='boldwarning'>Transfer failed.</span>")
|
||||
return
|
||||
disconnect_shell() //If the AI is controlling a borg, force the player back to core!
|
||||
if(!mind)
|
||||
to_chat(user, "<span class='warning'>No intelligence patterns detected.</span>" )
|
||||
return
|
||||
ShutOffDoomsdayDevice()
|
||||
new /obj/structure/AIcore/deactivated(loc)//Spawns a deactivated terminal at AI location.
|
||||
ai_restore_power()//So the AI initially has power.
|
||||
@@ -907,10 +916,73 @@ var/list/ai_list = list()
|
||||
to_chat(src, "Hack complete. \The [apc] is now under your exclusive control.")
|
||||
apc.update_icon()
|
||||
|
||||
/mob/living/silicon/ai/verb/deploy_to_shell(var/mob/living/silicon/robot/target)
|
||||
set category = "AI Commands"
|
||||
set name = "Deploy to Shell"
|
||||
|
||||
if(stat || lacks_power() || control_disabled)
|
||||
to_chat(src, "<span class='danger'>Wireless networking module is offline.</span>")
|
||||
return
|
||||
|
||||
var/list/possible = list()
|
||||
|
||||
for(var/borgie in available_ai_shells)
|
||||
var/mob/living/silicon/robot/R = borgie
|
||||
if(R.shell && !R.deployed && (R.stat != DEAD) && (!R.connected_ai ||(R.connected_ai == src)))
|
||||
possible += R
|
||||
|
||||
if(!LAZYLEN(possible))
|
||||
to_chat(src, "No usable AI shell beacons detected.")
|
||||
|
||||
if(!target || !(target in possible)) //If the AI is looking for a new shell, or its pre-selected shell is no longer valid
|
||||
target = input(src, "Which body to control?") as null|anything in possible
|
||||
|
||||
if (!target || target.stat == DEAD || target.deployed || !(!target.connected_ai ||(target.connected_ai == src)))
|
||||
return
|
||||
|
||||
else if(mind)
|
||||
soullink(/datum/soullink/sharedbody, src, target)
|
||||
deployed_shell = target
|
||||
target.deploy_init(src)
|
||||
mind.transfer_to(target)
|
||||
diag_hud_set_deployed()
|
||||
|
||||
/datum/action/innate/deploy_shell
|
||||
name = "Deploy to AI Shell"
|
||||
desc = "Wirelessly control a specialized cyborg shell."
|
||||
button_icon_state = "ai_shell"
|
||||
|
||||
/datum/action/innate/deploy_shell/Trigger()
|
||||
var/mob/living/silicon/ai/AI = owner
|
||||
if(!AI)
|
||||
return
|
||||
AI.deploy_to_shell()
|
||||
|
||||
/datum/action/innate/deploy_last_shell
|
||||
name = "Reconnect to shell"
|
||||
desc = "Reconnect to the most recently used AI shell."
|
||||
button_icon_state = "ai_last_shell"
|
||||
var/mob/living/silicon/robot/last_used_shell
|
||||
|
||||
/datum/action/innate/deploy_last_shell/Trigger()
|
||||
if(!owner)
|
||||
return
|
||||
if(last_used_shell)
|
||||
var/mob/living/silicon/ai/AI = owner
|
||||
AI.deploy_to_shell(last_used_shell)
|
||||
else
|
||||
Remove(owner) //If the last shell is blown, destroy it.
|
||||
|
||||
/mob/living/silicon/ai/proc/disconnect_shell()
|
||||
if(deployed_shell) //Forcibly call back AI in event of things such as damage, EMP or power loss.
|
||||
to_chat(src, "<span class='danger'>Your remote connection has been reset!</span>")
|
||||
deployed_shell.undeploy()
|
||||
diag_hud_set_deployed()
|
||||
|
||||
/mob/living/silicon/ai/resist()
|
||||
return
|
||||
|
||||
/mob/living/silicon/ai/spawned/Initialize(mapload, datum/ai_laws/L, mob/target_ai)
|
||||
if(!target_ai)
|
||||
target_ai = src //cheat! just give... ourselves as the spawned AI, because that's technically correct
|
||||
..()
|
||||
..()
|
||||
@@ -22,6 +22,7 @@
|
||||
return 0
|
||||
|
||||
/mob/living/silicon/ai/emp_act(severity)
|
||||
disconnect_shell()
|
||||
if (prob(30))
|
||||
switch(pick(1,2))
|
||||
if(1)
|
||||
|
||||
@@ -1,21 +1,23 @@
|
||||
/mob/living/silicon/ai/examine(mob/user)
|
||||
var/msg = "<span class='info'>*---------*\nThis is \icon[src] <EM>[src]</EM>!\n"
|
||||
if (src.stat == DEAD)
|
||||
if (stat == DEAD)
|
||||
msg += "<span class='deadsay'>It appears to be powered-down.</span>\n"
|
||||
else
|
||||
msg += "<span class='warning'>"
|
||||
if (src.getBruteLoss())
|
||||
if (src.getBruteLoss() < 30)
|
||||
if (getBruteLoss())
|
||||
if (getBruteLoss() < 30)
|
||||
msg += "It looks slightly dented.\n"
|
||||
else
|
||||
msg += "<B>It looks severely dented!</B>\n"
|
||||
if (src.getFireLoss())
|
||||
if (src.getFireLoss() < 30)
|
||||
if (getFireLoss())
|
||||
if (getFireLoss() < 30)
|
||||
msg += "It looks slightly charred.\n"
|
||||
else
|
||||
msg += "<B>Its casing is melted and heat-warped!</B>\n"
|
||||
msg += "</span>"
|
||||
if (shunted == 0 && !src.client)
|
||||
if(deployed_shell)
|
||||
msg += "The wireless networking light is blinking.\n"
|
||||
else if (!shunted && !client)
|
||||
msg += "[src]Core.exe has stopped responding! NTOS is searching for a solution to the problem...\n"
|
||||
msg += "*---------*</span>"
|
||||
|
||||
|
||||
@@ -65,6 +65,7 @@
|
||||
health = maxHealth - getOxyLoss() - getToxLoss() - getBruteLoss() - getFireLoss()
|
||||
update_stat()
|
||||
diag_hud_set_health()
|
||||
disconnect_shell()
|
||||
|
||||
/mob/living/silicon/ai/update_stat()
|
||||
if(status_flags & GODMODE)
|
||||
@@ -163,6 +164,7 @@
|
||||
update_sight()
|
||||
|
||||
/mob/living/silicon/ai/proc/ai_lose_power()
|
||||
disconnect_shell()
|
||||
aiRestorePowerRoutine = POWER_RESTORATION_START
|
||||
blind_eyes(1)
|
||||
update_sight()
|
||||
|
||||
@@ -36,9 +36,11 @@
|
||||
if(is_servant_of_ratvar(src) && user.Adjacent(src) && !stat) //To counter pseudo-stealth by using headlamps
|
||||
msg += "<span class='warning'>Its eyes are glowing a blazing yellow!</span>\n"
|
||||
|
||||
switch(src.stat)
|
||||
switch(stat)
|
||||
if(CONSCIOUS)
|
||||
if(!src.client)
|
||||
if(shell)
|
||||
msg += "It appears to be an [deployed ? "active" : "empty"] AI shell.\n"
|
||||
else if(!client)
|
||||
msg += "It appears to be in stand-by mode.\n" //afk
|
||||
if(UNCONSCIOUS)
|
||||
msg += "<span class='warning'>It doesn't seem to be responding.</span>\n"
|
||||
|
||||
@@ -32,7 +32,9 @@
|
||||
|
||||
to_chat(who, "<b>Obey these laws:</b>")
|
||||
laws.show_laws(who)
|
||||
if (is_special_character(src) && connected_ai)
|
||||
if (shell) //AI shell
|
||||
to_chat(who, "<b>Remember, you are an AI remotely controlling your shell, other AIs can be ignored.</b>")
|
||||
else if (is_special_character(src) && connected_ai)
|
||||
to_chat(who, "<b>Remember, [connected_ai.name] is technically your master, but your objective comes first.</b>")
|
||||
else if (connected_ai)
|
||||
to_chat(who, "<b>Remember, [connected_ai.name] is your master, other AIs can be ignored.</b>")
|
||||
|
||||
@@ -16,6 +16,10 @@
|
||||
var/obj/item/robot_suit/robot_suit = null //Used for deconstruction to remember what the borg was constructed out of..
|
||||
var/obj/item/device/mmi/mmi = null
|
||||
|
||||
var/shell = FALSE
|
||||
var/deployed = FALSE
|
||||
var/mob/living/silicon/ai/mainframe = null
|
||||
var/datum/action/innate/undeployment/undeployment_action = new
|
||||
|
||||
//Hud stuff
|
||||
|
||||
@@ -73,7 +77,7 @@
|
||||
|
||||
var/sight_mode = 0
|
||||
var/updating = 0 //portable camera camerachunk update
|
||||
hud_possible = list(ANTAG_HUD, DIAG_STAT_HUD, DIAG_HUD, DIAG_BATT_HUD)
|
||||
hud_possible = list(ANTAG_HUD, DIAG_STAT_HUD, DIAG_HUD, DIAG_BATT_HUD, DIAG_TRACK_HUD)
|
||||
|
||||
var/list/upgrades = list()
|
||||
|
||||
@@ -129,8 +133,12 @@
|
||||
update_icons()
|
||||
..()
|
||||
|
||||
//If this body is meant to be a borg controlled by the AI player
|
||||
if(shell)
|
||||
make_shell()
|
||||
|
||||
//MMI stuff. Held togheter by magic. ~Miauw
|
||||
if(!mmi || !mmi.brainmob)
|
||||
else if(!mmi || !mmi.brainmob)
|
||||
mmi = new (src)
|
||||
mmi.brain = new /obj/item/organ/brain(mmi)
|
||||
mmi.brain.name = "[real_name]'s brain"
|
||||
@@ -170,6 +178,8 @@
|
||||
mmi = null
|
||||
if(connected_ai)
|
||||
connected_ai.connected_robots -= src
|
||||
if(shell)
|
||||
available_ai_shells -= src
|
||||
qdel(wires)
|
||||
qdel(module)
|
||||
qdel(eye_lights)
|
||||
@@ -204,6 +214,8 @@
|
||||
|
||||
|
||||
/mob/living/silicon/robot/proc/updatename()
|
||||
if(shell)
|
||||
return
|
||||
var/changed_name = ""
|
||||
if(custom_name)
|
||||
changed_name = custom_name
|
||||
@@ -424,7 +436,9 @@
|
||||
update_icons()
|
||||
|
||||
else if(istype(W, /obj/item/weapon/screwdriver) && opened && cell) // radio
|
||||
if(radio)
|
||||
if(shell)
|
||||
to_chat(user, "You cannot seem to open the radio compartment") //Prevent AI radio key theft
|
||||
else if(radio)
|
||||
radio.attackby(W,user)//Push it to the radio to let it handle everything
|
||||
else
|
||||
to_chat(user, "<span class='warning'>Unable to locate a radio!</span>")
|
||||
@@ -453,6 +467,9 @@
|
||||
if(!cell)
|
||||
to_chat(user, "<span class='warning'>You need to install a power cell to do that!</span>")
|
||||
return
|
||||
if(shell) //AI shells always have the laws of the AI
|
||||
to_chat(user, "<span class='warning'>[src] is controlled remotely! You cannot upload new laws this way!</span>")
|
||||
return
|
||||
if(emagged || (connected_ai && lawupdate)) //Can't be sure which, metagamers
|
||||
emote("buzz-[user.name]")
|
||||
return
|
||||
@@ -813,12 +830,14 @@
|
||||
if(!connected_ai)
|
||||
return
|
||||
switch(notifytype)
|
||||
if(1) //New Cyborg
|
||||
if(NEW_BORG) //New Cyborg
|
||||
to_chat(connected_ai, "<br><br><span class='notice'>NOTICE - New cyborg connection detected: <a href='?src=\ref[connected_ai];track=[html_encode(name)]'>[name]</a></span><br>")
|
||||
if(2) //New Module
|
||||
if(NEW_MODULE) //New Module
|
||||
to_chat(connected_ai, "<br><br><span class='notice'>NOTICE - Cyborg module change detected: [name] has loaded the [designation] module.</span><br>")
|
||||
if(3) //New Name
|
||||
if(RENAME) //New Name
|
||||
to_chat(connected_ai, "<br><br><span class='notice'>NOTICE - Cyborg reclassification detected: [oldname] is now designated as [newname].</span><br>")
|
||||
if(AI_SHELL) //New Shell
|
||||
to_chat(connected_ai, "<br><br><span class='notice'>NOTICE - New cyborg shell detected: <a href='?src=\ref[connected_ai];track=[html_encode(name)]'>[name]</a></span><br>")
|
||||
|
||||
/mob/living/silicon/robot/canUseTopic(atom/movable/M, be_close = 0)
|
||||
if(stat || lockcharge || low_power_mode)
|
||||
@@ -901,6 +920,7 @@
|
||||
update_headlamp()
|
||||
diag_hud_set_status()
|
||||
diag_hud_set_health()
|
||||
diag_hud_set_aishell()
|
||||
update_health_hud()
|
||||
|
||||
/mob/living/silicon/robot/revive(full_heal = 0, admin_revive = 0)
|
||||
@@ -910,13 +930,13 @@
|
||||
update_headlamp()
|
||||
if(admin_revive)
|
||||
locked = 1
|
||||
notify_ai(1)
|
||||
notify_ai(NEW_BORG)
|
||||
. = 1
|
||||
|
||||
/mob/living/silicon/robot/fully_replace_character_name(oldname, newname)
|
||||
..()
|
||||
if(oldname != real_name)
|
||||
notify_ai(3, oldname, newname)
|
||||
notify_ai(RENAME, oldname, newname)
|
||||
if(camera)
|
||||
camera.c_tag = real_name
|
||||
custom_name = newname
|
||||
@@ -937,6 +957,7 @@
|
||||
|
||||
speed = 0
|
||||
ionpulse = FALSE
|
||||
revert_shell()
|
||||
|
||||
return 1
|
||||
|
||||
@@ -973,6 +994,97 @@
|
||||
new_hat.forceMove(src)
|
||||
update_icons()
|
||||
|
||||
/mob/living/silicon/robot/proc/make_shell(var/obj/item/borg/upgrade/ai/board)
|
||||
if(!board)
|
||||
upgrades |= new /obj/item/borg/upgrade/ai(src)
|
||||
shell = TRUE
|
||||
braintype = "AI Shell"
|
||||
name = "[designation] AI Shell [rand(100,999)]"
|
||||
real_name = name
|
||||
available_ai_shells |= src
|
||||
if(camera)
|
||||
camera.c_tag = real_name //update the camera name too
|
||||
diag_hud_set_aishell()
|
||||
notify_ai(AI_SHELL)
|
||||
|
||||
/mob/living/silicon/robot/proc/revert_shell()
|
||||
if(!shell)
|
||||
return
|
||||
undeploy()
|
||||
for(var/obj/item/borg/upgrade/ai/boris in src)
|
||||
//A player forced reset of a borg would drop the module before this is called, so this is for catching edge cases
|
||||
qdel(boris)
|
||||
shell = FALSE
|
||||
available_ai_shells -= src
|
||||
name = "Unformatted Cyborg [rand(100,999)]"
|
||||
real_name = name
|
||||
if(camera)
|
||||
camera.c_tag = real_name
|
||||
diag_hud_set_aishell()
|
||||
|
||||
/mob/living/silicon/robot/proc/deploy_init(var/mob/living/silicon/ai/AI)
|
||||
real_name = "[AI.real_name] shell [rand(100, 999)] - [designation]" //Randomizing the name so it shows up seperately in the shells list
|
||||
name = real_name
|
||||
if(camera)
|
||||
camera.c_tag = real_name //update the camera name too
|
||||
mainframe = AI
|
||||
deployed = TRUE
|
||||
connected_ai = mainframe
|
||||
mainframe.connected_robots |= src
|
||||
lawupdate = TRUE
|
||||
lawsync()
|
||||
if(radio && AI.radio) //AI keeps all channels, including Syndie if it is a Traitor
|
||||
if(AI.radio.syndie)
|
||||
radio.make_syndie()
|
||||
radio.subspace_transmission = TRUE
|
||||
radio.channels = AI.radio.channels
|
||||
for(var/chan in radio.channels)
|
||||
radio.secure_radio_connections[chan] = add_radio(radio, radiochannels[chan])
|
||||
|
||||
diag_hud_set_aishell()
|
||||
undeployment_action.Grant(src)
|
||||
|
||||
/datum/action/innate/undeployment
|
||||
name = "Disconnect from shell"
|
||||
desc = "Stop controlling your shell and resume normal core operations."
|
||||
button_icon_state = "ai_core"
|
||||
|
||||
/datum/action/innate/undeployment/Trigger()
|
||||
if(!..())
|
||||
return FALSE
|
||||
var/mob/living/silicon/robot/R = owner
|
||||
|
||||
R.undeploy()
|
||||
return TRUE
|
||||
|
||||
|
||||
/mob/living/silicon/robot/proc/undeploy()
|
||||
|
||||
if(!deployed || !mainframe)
|
||||
return
|
||||
mainframe.redeploy_action.Grant(mainframe)
|
||||
mainframe.redeploy_action.last_used_shell = src
|
||||
mind.transfer_to(mainframe)
|
||||
deployed = FALSE
|
||||
mainframe.deployed_shell = null
|
||||
undeployment_action.Remove(src)
|
||||
if(radio) //Return radio to normal
|
||||
radio.recalculateChannels()
|
||||
if(camera)
|
||||
camera.c_tag = real_name //update the camera name too
|
||||
diag_hud_set_aishell()
|
||||
mainframe.diag_hud_set_deployed()
|
||||
mainframe.show_laws() //Always remind the AI when switching
|
||||
mainframe = null
|
||||
|
||||
/mob/living/silicon/robot/attack_ai(mob/user)
|
||||
if(shell && (!connected_ai || connected_ai == user))
|
||||
var/mob/living/silicon/ai/AI = user
|
||||
AI.deploy_to_shell(src)
|
||||
|
||||
/mob/living/silicon/robot/shell
|
||||
shell = TRUE
|
||||
|
||||
/mob/living/silicon/robot/MouseDrop_T(mob/living/M, mob/living/user)
|
||||
. = ..()
|
||||
if(!(M in buckled_mobs) && isliving(M))
|
||||
|
||||
@@ -92,6 +92,8 @@
|
||||
if(locked)
|
||||
to_chat(user, "<span class='notice'>You emag the cover lock.</span>")
|
||||
locked = 0
|
||||
if(shell) //A warning to Traitors who may not know that emagging AI shells does not slave them.
|
||||
to_chat(user, "<span class='boldwarning'>[src] seems to be controlled remotely! Emagging the interface may not work as expected.</span>")
|
||||
else
|
||||
to_chat(user, "<span class='warning'>The cover is already unlocked!</span>")
|
||||
return
|
||||
@@ -125,6 +127,12 @@
|
||||
log_game("[key_name(user)] attempted to emag cyborg [key_name(src)], but they were slaved to traitor AI [connected_ai].")
|
||||
return
|
||||
|
||||
if(shell) //AI shells cannot be emagged, so we try to make it look like a standard reset. Smart players may see through this, however.
|
||||
to_chat(user, "<span class='danger'>[src] is remotely controlled! Your emag attempt has triggered a system reset instead!</span>")
|
||||
log_game("[key_name(user)] attempted to emag an AI shell belonging to [key_name(src) ? key_name(src) : connected_ai]. The shell has been reset as a result.")
|
||||
ResetModule()
|
||||
return
|
||||
|
||||
SetEmagged(1)
|
||||
SetStunned(3) //Borgs were getting into trouble because they would attack the emagger before the new laws were shown
|
||||
lawupdate = 0
|
||||
|
||||
@@ -218,7 +218,7 @@
|
||||
R.SetLockdown(0)
|
||||
R.anchored = FALSE
|
||||
R.notransform = FALSE
|
||||
R.notify_ai(2)
|
||||
R.notify_ai(NEW_MODULE)
|
||||
if(R.hud_used)
|
||||
R.hud_used.update_robot_modules_display()
|
||||
if(feedback_key && !did_feedback)
|
||||
|
||||
@@ -21,8 +21,7 @@
|
||||
var/designation = ""
|
||||
var/radiomod = "" //Radio character used before state laws/arrivals announce to allow department transmissions, default, or none at all.
|
||||
var/obj/item/device/camera/siliconcam/aicamera = null //photography
|
||||
//hud_possible = list(DIAG_STAT_HUD, DIAG_HUD, ANTAG_HUD)
|
||||
hud_possible = list(ANTAG_HUD, DIAG_STAT_HUD, DIAG_HUD)
|
||||
hud_possible = list(ANTAG_HUD, DIAG_STAT_HUD, DIAG_HUD, DIAG_TRACK_HUD)
|
||||
|
||||
var/obj/item/device/radio/borg/radio = null //AIs dont use this but this is at the silicon level to advoid copypasta in say()
|
||||
|
||||
|
||||
@@ -385,7 +385,7 @@
|
||||
|
||||
R.loc = loc
|
||||
R.job = "Cyborg"
|
||||
R.notify_ai(1)
|
||||
R.notify_ai(NEW_BORG)
|
||||
|
||||
. = R
|
||||
qdel(src)
|
||||
|
||||
@@ -122,7 +122,7 @@
|
||||
var/mob/living/silicon/robot/Robot = M
|
||||
if(Robot.mmi)
|
||||
qdel(Robot.mmi)
|
||||
Robot.notify_ai(1)
|
||||
Robot.notify_ai(NEW_BORG)
|
||||
else
|
||||
for(var/obj/item/W in contents)
|
||||
if(!M.dropItemToGround(W))
|
||||
|
||||
@@ -718,6 +718,16 @@
|
||||
construction_time = 120
|
||||
category = list("Cyborg Upgrade Modules")
|
||||
|
||||
/datum/design/boris_ai_controller
|
||||
name = "B.O.R.I.S. AI-Cyborg Remote Control Module"
|
||||
id = "borg_ai_control"
|
||||
build_type = MECHFAB
|
||||
build_path = /obj/item/borg/upgrade/ai
|
||||
materials = list(MAT_METAL = 1200, MAT_GLASS = 1500, MAT_GOLD = 200)
|
||||
req_tech = list("programming" = 4, "magnets" = 4, "engineering" = 4)
|
||||
construction_time = 50
|
||||
category = list("Misc")
|
||||
|
||||
//Misc
|
||||
/datum/design/mecha_tracking
|
||||
name = "Exosuit Tracking Beacon"
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 180 KiB After Width: | Height: | Size: 182 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
Reference in New Issue
Block a user