diff --git a/code/game/machinery/camera/camera.dm b/code/game/machinery/camera/camera.dm
index 2ae4de8d754..8f590d77a4e 100644
--- a/code/game/machinery/camera/camera.dm
+++ b/code/game/machinery/camera/camera.dm
@@ -347,11 +347,6 @@
bug.bugged_cameras[src.c_tag] = src
return
- else if(istype(I, /obj/item/pai_cable))
- var/obj/item/pai_cable/cable = I
- cable.plugin(src, user)
- return
-
return ..()
diff --git a/code/game/objects/items/devices/aicard.dm b/code/game/objects/items/devices/aicard.dm
index a938d618b1a..68cf8d961f3 100644
--- a/code/game/objects/items/devices/aicard.dm
+++ b/code/game/objects/items/devices/aicard.dm
@@ -40,20 +40,20 @@
log_combat(user, AI, "carded", src)
update_icon() //Whatever happened, update the card's state (icon, name) to match.
-/obj/item/aicard/update_icon()
- cut_overlays()
- if(AI)
- name = "[initial(name)] - [AI.name]"
- if(AI.stat == DEAD)
- icon_state = "[initial(icon_state)]-404"
- else
- icon_state = "[initial(icon_state)]-full"
- if(!AI.control_disabled)
- add_overlay("[initial(icon_state)]-on")
- AI.cancel_camera()
- else
+/obj/item/aicard/update_icon_state()
+ if(!AI)
name = initial(name)
icon_state = initial(icon_state)
+ return
+ name = "[initial(name)] - [AI.name]"
+ icon_state = "[initial(icon_state)][AI.stat == DEAD ? "-404" : "-full"]"
+ AI.cancel_camera()
+
+/obj/item/aicard/update_overlays()
+ . = ..()
+ if(!AI || AI.control_disabled)
+ return
+ . += "[initial(icon_state)]-on"
/obj/item/aicard/ui_state(mob/user)
return GLOB.hands_state
diff --git a/code/game/objects/items/devices/paicard.dm b/code/game/objects/items/devices/paicard.dm
index cde3702087e..283f3637758 100644
--- a/code/game/objects/items/devices/paicard.dm
+++ b/code/game/objects/items/devices/paicard.dm
@@ -9,6 +9,7 @@
w_class = WEIGHT_CLASS_SMALL
slot_flags = ITEM_SLOT_BELT
var/mob/living/silicon/pai/pai
+ var/emotion_icon = "off" ///what emotion icon we have. handled in /mob/living/silicon/pai/Topic()
resistance_flags = FIRE_PROOF | ACID_PROOF | INDESTRUCTIBLE
/obj/item/paicard/suicide_act(mob/living/user)
@@ -17,13 +18,31 @@
/obj/item/paicard/Initialize()
SSpai.pai_card_list += src
- add_overlay("pai-off")
+ . = ..()
+ update_icon()
+
+/obj/item/paicard/vv_edit_var(vname, vval)
+ . = ..()
+ if(vname == NAMEOF(src, emotion_icon))
+ update_icon()
+
+/obj/item/paicard/handle_atom_del(atom/A)
+ if(A == pai) //double check /mob/living/silicon/pai/Destroy() if you change these.
+ pai = null
+ emotion_icon = initial(emotion_icon)
+ update_icon()
return ..()
+/obj/item/paicard/update_overlays()
+ . = ..()
+ . += "pai-[emotion_icon]"
+ if(pai?.hacking_cable)
+ . += "[initial(icon_state)]-connector"
+
/obj/item/paicard/Destroy()
//Will stop people throwing friend pAIs into the singularity so they can respawn
SSpai.pai_card_list -= src
- if (!QDELETED(pai))
+ if(!QDELETED(pai))
QDEL_NULL(pai)
return ..()
@@ -130,39 +149,13 @@
// WIRE_TRANSMIT = 4
/obj/item/paicard/proc/setPersonality(mob/living/silicon/pai/personality)
- src.pai = personality
- src.add_overlay("pai-null")
+ pai = personality
+ emotion_icon = "null"
+ update_icon()
playsound(loc, 'sound/effects/pai_boot.ogg', 50, TRUE, -1)
audible_message("\The [src] plays a cheerful startup noise!")
-/obj/item/paicard/proc/setEmotion(emotion)
- if(pai)
- src.cut_overlays()
- switch(emotion)
- if(1)
- src.add_overlay("pai-happy")
- if(2)
- src.add_overlay("pai-cat")
- if(3)
- src.add_overlay("pai-extremely-happy")
- if(4)
- src.add_overlay("pai-face")
- if(5)
- src.add_overlay("pai-laugh")
- if(6)
- src.add_overlay("pai-off")
- if(7)
- src.add_overlay("pai-sad")
- if(8)
- src.add_overlay("pai-angry")
- if(9)
- src.add_overlay("pai-what")
- if(10)
- src.add_overlay("pai-null")
- if(11)
- src.add_overlay("pai-sunglasses")
-
/obj/item/paicard/proc/alertUpdate()
audible_message("[src] flashes a message across its screen, \"Additional personalities available for download.\"", "[src] vibrates with an alert.")
diff --git a/code/game/objects/items/paiwire.dm b/code/game/objects/items/paiwire.dm
index 0dbf23e937f..1e14be9a385 100644
--- a/code/game/objects/items/paiwire.dm
+++ b/code/game/objects/items/paiwire.dm
@@ -4,7 +4,12 @@
icon = 'icons/obj/power.dmi'
icon_state = "wire1"
item_flags = NOBLUDGEON
- var/obj/machinery/machine
+ var/obj/machinery/machine //what machine we're currently hacking.
+
+/obj/item/pai_cable/machine/Destroy()
+ machine = null
+ return ..()
+
/obj/item/pai_cable/proc/plugin(obj/machinery/M, mob/living/user)
if(!user.transferItemToLoc(src, M))
diff --git a/code/game/objects/structures/ai_core.dm b/code/game/objects/structures/ai_core.dm
index 3dc69b1a592..cd6c285cebf 100644
--- a/code/game/objects/structures/ai_core.dm
+++ b/code/game/objects/structures/ai_core.dm
@@ -244,8 +244,7 @@
if(AI_READY_CORE)
if(istype(P, /obj/item/aicard))
- P.transfer_ai("INACTIVE", "AICARD", src, user)
- return
+ return //handled by /obj/structure/ai_core/transfer_ai()
if(P.tool_behaviour == TOOL_SCREWDRIVER)
P.play_tool_sound(src)
diff --git a/code/modules/mob/living/silicon/pai/pai.dm b/code/modules/mob/living/silicon/pai/pai.dm
index 4baf74fa5e1..4485e86e6a2 100644
--- a/code/modules/mob/living/silicon/pai/pai.dm
+++ b/code/modules/mob/living/silicon/pai/pai.dm
@@ -13,6 +13,9 @@
maxHealth = 500
layer = BELOW_MOB_LAYER
can_be_held = TRUE
+ move_force = 0
+ pull_force = 0
+ move_resist = 0
worn_slot_flags = ITEM_SLOT_HEAD
held_lh = 'icons/mob/pai_item_lh.dmi'
held_rh = 'icons/mob/pai_item_rh.dmi'
@@ -32,7 +35,7 @@
var/speakDoubleExclamation = "alarms"
var/speakQuery = "queries"
- var/obj/item/pai_cable/cable // The cable we produce and use when door or camera jacking
+ var/obj/item/pai_cable/hacking_cable // The cable we produce when hacking a door
var/master // Name of the one who commands us
var/master_dna // DNA string for owner verification
@@ -66,7 +69,6 @@
var/canholo = TRUE
var/can_transmit = TRUE
var/can_receive = TRUE
- var/obj/item/card/id/access_card = null
var/chassis = "repairbot"
var/list/possible_chassis = list("cat" = TRUE, "mouse" = TRUE, "monkey" = TRUE, "corgi" = FALSE, "fox" = FALSE, "repairbot" = TRUE, "rabbit" = TRUE, "bat" = FALSE, "butterfly" = FALSE, "hawk" = FALSE, "lizard" = FALSE, "duffel" = TRUE) //assoc value is whether it can be picked up.
@@ -92,15 +94,32 @@
/mob/living/silicon/pai/add_sensors() //pAIs have to buy their HUDs
return
+/mob/living/silicon/pai/handle_atom_del(atom/A)
+ if(A == hacking_cable)
+ hacking_cable = null
+ if(!QDELETED(card))
+ card.update_icon()
+ if(A == internal_instrument)
+ internal_instrument = null
+ if(A == newscaster)
+ newscaster = null
+ if(A == signaler)
+ signaler = null
+ if(A == hostscan)
+ hostscan = null
+ return ..()
+
/mob/living/silicon/pai/Destroy()
QDEL_NULL(internal_instrument)
- if(cable)
- QDEL_NULL(cable)
- if (loc != card)
+ QDEL_NULL(hacking_cable)
+ QDEL_NULL(newscaster)
+ QDEL_NULL(signaler)
+ QDEL_NULL(hostscan)
+ if(!QDELETED(card) && loc != card)
card.forceMove(drop_location())
- card.pai = null
- card.cut_overlays()
- card.add_overlay("pai-off")
+ card.pai = null //these are otherwise handled by paicard/handle_atom_del()
+ card.emotion_icon = initial(card.emotion_icon)
+ card.update_icon()
GLOB.pai_list -= src
return ..()
@@ -138,19 +157,24 @@
aiPDA.name = real_name + " (" + aiPDA.ownjob + ")"
/mob/living/silicon/pai/proc/process_hack()
- if(cable && cable.machine && istype(cable.machine, /obj/machinery/door) && cable.machine == hackdoor && get_dist(src, hackdoor) <= 1)
+
+
+ if(hacking_cable && hacking_cable.machine && istype(hacking_cable.machine, /obj/machinery/door) && hacking_cable.machine == hackdoor && get_dist(src, hackdoor) <= 1)
hackprogress = clamp(hackprogress + 4, 0, 100)
else
temp = "Door Jack: Connection to airlock has been lost. Hack aborted."
hackprogress = 0
hacking = FALSE
hackdoor = null
+ QDEL_NULL(hacking_cable)
+ if(!QDELETED(card))
+ card.update_icon()
return
if(screen == "doorjack" && subscreen == 0) // Update our view, if appropriate
paiInterface()
if(hackprogress >= 100)
hackprogress = 0
- var/obj/machinery/door/D = cable.machine
+ var/obj/machinery/door/D = hacking_cable.machine
D.open()
hacking = FALSE
@@ -272,13 +296,15 @@
. = ..()
if(QDELETED(src) || stat == DEAD)
return
- if(cable)
- if(get_dist(src, cable) > 1)
+ if(hacking_cable)
+ if(get_dist(src, hacking_cable) > 1)
var/turf/T = get_turf(src)
- T.visible_message("[cable] rapidly retracts back into its spool.", "You hear a click and the sound of wire spooling rapidly.")
- QDEL_NULL(cable)
- if(hacking)
- process_hack()
+ T.visible_message("[hacking_cable] rapidly retracts back into its spool.", "You hear a click and the sound of wire spooling rapidly.")
+ QDEL_NULL(hacking_cable)
+ if(!QDELETED(card))
+ card.update_icon()
+ else if(hacking)
+ process_hack()
silent = max(silent - 1, 0)
/mob/living/silicon/pai/updatehealth()
@@ -291,12 +317,12 @@
emitterhealth = clamp((emitterhealth + emitterregen), -50, emittermaxhealth)
/obj/item/paicard/attackby(obj/item/W, mob/user, params)
- ..()
- user.set_machine(src)
- if(pai && pai.encryptmod == TRUE)
- if(W.tool_behaviour == TOOL_SCREWDRIVER)
- pai.radio.attackby(W, user, params)
- else if(istype(W, /obj/item/encryptionkey))
- pai.radio.attackby(W, user, params)
- else
- to_chat(user, "Encryption Key ports not configured.")
+ if(pai && (istype(W, /obj/item/encryptionkey) || W.tool_behaviour == TOOL_SCREWDRIVER))
+ if(!pai.encryptmod)
+ to_chat(user, "Encryption Key ports not configured.")
+ return
+ user.set_machine(src)
+ pai.radio.attackby(W, user, params)
+ return
+
+ return ..()
diff --git a/code/modules/mob/living/silicon/pai/software.dm b/code/modules/mob/living/silicon/pai/software.dm
index a90b330c590..a2c4d999039 100644
--- a/code/modules/mob/living/silicon/pai/software.dm
+++ b/code/modules/mob/living/silicon/pai/software.dm
@@ -1,8 +1,6 @@
// TODO:
// - Potentially roll HUDs and Records into one
// - Shock collar/lock system for prisoner pAIs?
-// - Put cable in user's hand instead of on the ground
-// - Camera jack
/mob/living/silicon/pai/var/list/available_software = list(
@@ -20,9 +18,6 @@
"security records" = 10,
"camera zoom" = 10,
"host scan" = 10,
- //"camera jack" = 10,
- //"heartbeat sensor" = 10,
- //"projection array" = 15,
"medical HUD" = 20,
"security HUD" = 20,
"loudness booster" = 20,
@@ -72,8 +67,6 @@
left_part = medicalAnalysis()
if("doorjack")
left_part = softwareDoor()
- if("camerajack")
- left_part = softwareCamera()
if("signaller")
left_part = softwareSignal()
if("loudness")
@@ -158,32 +151,14 @@
if("image") // Set pAI card display face
var/newImage = input("Select your new display image.", "Display Image", "Happy") in sortList(list("Happy", "Cat", "Extremely Happy", "Face", "Laugh", "Off", "Sad", "Angry", "What", "Sunglasses"))
- var/pID = 1
-
switch(newImage)
- if("Happy")
- pID = 1
- if("Cat")
- pID = 2
+ if(null)
+ card.emotion_icon = "null"
if("Extremely Happy")
- pID = 3
- if("Face")
- pID = 4
- if("Laugh")
- pID = 5
- if("Off")
- pID = 6
- if("Sad")
- pID = 7
- if("Angry")
- pID = 8
- if("What")
- pID = 9
- if("Null")
- pID = 10
- if("Sunglasses")
- pID = 11
- card.setEmotion(pID)
+ card.emotion_icon = "extremely-happy"
+ else
+ card.emotion_icon = "[lowertext(newImage)]"
+ card.update_icon()
if("news")
newscaster.ui_interact(src)
@@ -285,15 +260,25 @@
if("doorjack")
if(href_list["jack"])
- if(cable && cable.machine)
- hackdoor = cable.machine
+ if(hacking_cable?.machine)
+ hackdoor = hacking_cable.machine
hackloop()
if(href_list["cancel"])
hackdoor = null
if(href_list["cable"])
- var/turf/T = get_turf(loc)
- cable = new /obj/item/pai_cable(T)
- T.visible_message("A port on [src] opens to reveal [cable], which promptly falls to the floor.", "You hear the soft click of something light and hard falling to the ground.")
+ qdel(hacking_cable) //clear any old cables
+ hacking_cable = new
+ var/transfered_to_mob
+ if(isliving(card.loc))
+ var/mob/living/L = card.loc
+ if(L.put_in_hands(hacking_cable))
+ transfered_to_mob = TRUE
+ L.visible_message("A port on [src] opens to reveal \a [hacking_cable], which you quickly grab hold of.", "You hear the soft click of something light and manage to catch hold of [hacking_cable].")
+ if(!transfered_to_mob)
+ hacking_cable.forceMove(drop_location())
+ hacking_cable.visible_message("A port on [src] opens to reveal \a [hacking_cable], which promptly falls to the floor.", "You hear the soft click of something light and hard falling to the ground.")
+
+
if("loudness")
if(subscreen == 1) // Open Instrument
@@ -329,8 +314,6 @@
dat += "Medical Records
"
if(s == "security records")
dat += "Security Records
"
- if(s == "camera")
- dat += "Camera Jack
"
if(s == "remote signaller")
dat += "Remote Signaller
"
if(s == "loudness booster")
@@ -344,8 +327,6 @@
dat += "Adjust Camera Zoom
"
if(s == "atmosphere sensor")
dat += "Atmospheric Sensor
"
- if(s == "heartbeat sensor")
- dat += "Heartbeat Sensor
"
if(s == "security HUD")
dat += "Facial Recognition Suite[(secHUD) ? " On" : " Off"]
"
if(s == "medical HUD")
@@ -355,10 +336,6 @@
if(s == "universal translator")
var/datum/language_holder/H = get_language_holder()
dat += "Universal Translator[H.omnitongue ? " On" : " Off"]
"
- if(s == "projection array")
- dat += "Projection Array
"
- if(s == "camera jack")
- dat += "Camera Jack
"
if(s == "door jack")
dat += "Door Jack
"
dat += "
"
@@ -576,41 +553,20 @@
dat += "Refresh Reading
"
dat += "
"
return dat
-
-// Camera Jack - Clearly not finished
-/mob/living/silicon/pai/proc/softwareCamera()
- var/dat = "