diff --git a/code/game/machinery/newscaster/newscaster_machine.dm b/code/game/machinery/newscaster/newscaster_machine.dm
index ad08823981b..98cce390010 100644
--- a/code/game/machinery/newscaster/newscaster_machine.dm
+++ b/code/game/machinery/newscaster/newscaster_machine.dm
@@ -578,7 +578,8 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/newscaster, 30)
targetcam = R.aicamera
else if(ispAI(user))
var/mob/living/silicon/pai/R = user
- targetcam = R.camera
+ if(R.aicamera)
+ targetcam = R.aicamera
else if(iscyborg(user))
var/mob/living/silicon/robot/R = user
if(R.connected_ai)
diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm
index 5fda090dd9f..5cb45e8b089 100644
--- a/code/modules/mob/living/living.dm
+++ b/code/modules/mob/living/living.dm
@@ -1252,7 +1252,7 @@
to_chat(src, span_warning("You don't have the physical ability to do this!"))
return FALSE
- if(!Adjacent(target) && (target.loc != src))
+ if(!Adjacent(target) && (target.loc != src) && !recursive_loc_check(src, target))
if(issilicon(src) && !ispAI(src))
if(!(action_bitflags & ALLOW_SILICON_REACH)) // silicons can ignore range checks (except pAIs)
to_chat(src, span_warning("You are too far away!"))
diff --git a/code/modules/modular_computers/computers/item/computer.dm b/code/modules/modular_computers/computers/item/computer.dm
index 18a17311c3f..da83445a641 100644
--- a/code/modules/modular_computers/computers/item/computer.dm
+++ b/code/modules/modular_computers/computers/item/computer.dm
@@ -200,10 +200,7 @@
return TRUE
if(istype(inserted_pai)) // Remove pAI
- user.put_in_hands(inserted_pai)
- balloon_alert(user, "removed pAI")
- inserted_pai = null
- update_appearance(UPDATE_ICON)
+ remove_pai(user)
return TRUE
// Gets IDs/access levels from card slot. Would be useful when/if PDAs would become modular PCs. //guess what
@@ -414,7 +411,7 @@
var/mob/living/carbon/human/human_wearer = loc
human_wearer.sec_hud_set_ID()
if(inserted_pai == gone)
- inserted_pai = null
+ update_appearance(UPDATE_ICON)
if(inserted_disk == gone)
inserted_disk = null
update_appearance(UPDATE_ICON)
@@ -713,12 +710,7 @@
return
// Inserting a pAI
- if(istype(attacking_item, /obj/item/pai_card) && !inserted_pai)
- if(!user.transferItemToLoc(attacking_item, src))
- return
- inserted_pai = attacking_item
- balloon_alert(user, "inserted pai")
- update_appearance(UPDATE_ICON)
+ if(istype(attacking_item, /obj/item/pai_card) && insert_pai(user, attacking_item))
return
if(istype(attacking_item, /obj/item/stock_parts/cell))
@@ -792,7 +784,7 @@
internal_cell?.forceMove(drop_location())
computer_id_slot?.forceMove(drop_location())
inserted_disk?.forceMove(drop_location())
- inserted_pai?.forceMove(drop_location())
+ remove_pai()
new /obj/item/stack/sheet/iron(get_turf(loc), steel_sheet_cost)
user.balloon_alert(user, "disassembled")
relay_qdel()
@@ -840,3 +832,30 @@
///Returns a string of what to send at the end of messenger's messages.
/obj/item/modular_computer/proc/get_messenger_ending()
return "Sent from my PDA"
+
+/obj/item/modular_computer/proc/insert_pai(mob/user, obj/item/pai_card/card)
+ if(inserted_pai)
+ return FALSE
+ if(!user.transferItemToLoc(card, src))
+ return FALSE
+ inserted_pai = card
+ balloon_alert(user, "inserted pai")
+ var/datum/action/innate/pai/messenger/messenger_ability = new(inserted_pai.pai)
+ messenger_ability.Grant(inserted_pai.pai)
+ update_appearance(UPDATE_ICON)
+ return TRUE
+
+/obj/item/modular_computer/proc/remove_pai(mob/user)
+ if(!inserted_pai)
+ return FALSE
+ var/datum/action/innate/pai/messenger/messenger_ability = locate() in inserted_pai.pai.actions
+ messenger_ability.Remove(inserted_pai.pai)
+ qdel(messenger_ability)
+ if(user)
+ user.put_in_hands(inserted_pai)
+ balloon_alert(user, "removed pAI")
+ else
+ inserted_pai.forceMove(drop_location())
+ inserted_pai = null
+ update_appearance(UPDATE_ICON)
+ return TRUE
diff --git a/code/modules/modular_computers/computers/item/computer_ui.dm b/code/modules/modular_computers/computers/item/computer_ui.dm
index 11c12ea0c47..d5dcf98c623 100644
--- a/code/modules/modular_computers/computers/item/computer_ui.dm
+++ b/code/modules/modular_computers/computers/item/computer_ui.dm
@@ -20,15 +20,21 @@
active_ui = new(user, src, "NtosMain")
return active_ui.open()
- if(active_program)
- active_ui.interface = active_program.tgui_id
- active_ui.title = active_program.filedesc
- active_program.ui_interact(user, active_ui)
- else
- active_ui.interface = "NtosMain"
+ for (var/datum/tgui/window as anything in open_uis)
+ if(active_program)
+ window.interface = active_program.tgui_id
+ window.title = active_program.filedesc
+ active_program.ui_interact(user, window)
+ else
+ window.interface = "NtosMain"
+ window.send_assets()
+ update_static_data_for_all_viewers()
- update_static_data(user, active_ui)
- active_ui.send_assets()
+
+/obj/item/modular_computer/ui_state(mob/user)
+ if(inserted_pai && (user == inserted_pai.pai))
+ return GLOB.contained_state
+ return ..()
/obj/item/modular_computer/interact(mob/user)
if(enabled)
@@ -206,10 +212,9 @@
if("PC_Pai_Interact")
switch(params["option"])
if("eject")
- usr.put_in_hands(inserted_pai)
- to_chat(usr, span_notice("You remove [inserted_pai] from the [name]."))
- inserted_pai = null
- update_appearance(UPDATE_ICON)
+ if(!ishuman(usr))
+ return
+ remove_pai(usr)
if("interact")
inserted_pai.attack_self(usr)
return TRUE
diff --git a/code/modules/modular_computers/computers/item/pda.dm b/code/modules/modular_computers/computers/item/pda.dm
index 9728e8c6f7f..1a766c3de7d 100644
--- a/code/modules/modular_computers/computers/item/pda.dm
+++ b/code/modules/modular_computers/computers/item/pda.dm
@@ -83,7 +83,7 @@
/obj/item/modular_computer/pda/interact(mob/user)
. = ..()
if(HAS_TRAIT(src, TRAIT_PDA_MESSAGE_MENU_RIGGED))
- explode(usr, from_message_menu = TRUE)
+ explode(user, from_message_menu = TRUE)
/obj/item/modular_computer/pda/attack_self(mob/user)
// bypass literacy checks to access syndicate uplink
diff --git a/code/modules/modular_computers/file_system/program.dm b/code/modules/modular_computers/file_system/program.dm
index 59ef183f6d6..1f36713380d 100644
--- a/code/modules/modular_computers/file_system/program.dm
+++ b/code/modules/modular_computers/file_system/program.dm
@@ -120,7 +120,7 @@
*access can contain a list of access numbers to check against. If access is not empty, it will be used istead of checking any inserted ID.
*/
/datum/computer_file/program/proc/can_run(mob/user, loud = FALSE, access_to_check, transfer = FALSE, list/access)
- if(issilicon(user))
+ if(issilicon(user) && !ispAI(user))
return TRUE
if(isAdminGhostAI(user))
diff --git a/code/modules/modular_computers/file_system/programs/messenger/messenger_program.dm b/code/modules/modular_computers/file_system/programs/messenger/messenger_program.dm
index e77e876c648..423f9c32dec 100644
--- a/code/modules/modular_computers/file_system/programs/messenger/messenger_program.dm
+++ b/code/modules/modular_computers/file_system/programs/messenger/messenger_program.dm
@@ -651,17 +651,17 @@
if(!isnull(viewing_messages_of) && viewing_messages_of == sender_ref)
viewing_messages_of = REF(chat)
- var/mob/living/receiver_mob = null
- //Check our immediate loc
- if(isliving(computer.loc))
- receiver_mob = computer.loc
- //Maybe they are a silicon!
- else
- receiver_mob = get(computer, /mob/living/silicon)
+ var/list/mob/living/receievers = list()
+ if(computer.inserted_pai)
+ receievers += computer.inserted_pai.pai
+ if(computer.loc && isliving(computer.loc))
+ receievers += computer.loc
- var/should_ring = !alert_silenced || is_rigged
-
- if(should_ring && istype(receiver_mob) && receiver_mob.is_literate() && (receiver_mob.stat == CONSCIOUS || receiver_mob.stat == SOFT_CRIT))
+ for(var/mob/living/messaged_mob as anything in receievers)
+ if(messaged_mob.stat >= UNCONSCIOUS)
+ continue
+ if(!messaged_mob.is_literate())
+ continue
var/reply_href = signal.data["rigged"] ? "explode" : "message"
var/photo_href = signal.data["rigged"] ? "explode" : "open"
var/reply
@@ -676,16 +676,16 @@
var/sender_title = is_fake_user ? STRINGIFY_PDA_TARGET(fake_name, fake_job) : get_messenger_name(sender_messenger)
var/sender_name = is_fake_user ? fake_name : sender_messenger.computer.saved_identification
- if (isAI(receiver_mob))
- sender_title = "[sender_title]"
+ if (isAI(messaged_mob))
+ sender_title = "[sender_title]"
var/inbound_message = "[signal.format_message()]"
inbound_message = emoji_parse(inbound_message)
var/photo_message = signal.data["photo"] ? " (Photo Attached)" : ""
- to_chat(receiver_mob, span_infoplain("[icon2html(computer, receiver_mob)] PDA message from [sender_title], \"[inbound_message]\"[photo_message] [reply]"))
+ to_chat(messaged_mob, span_infoplain("[icon2html(computer, messaged_mob)] PDA message from [sender_title], \"[inbound_message]\"[photo_message] [reply]"))
- if (alert_able && should_ring)
+ if (alert_able && (!alert_silenced || is_rigged))
computer.ring(ringtone)
SStgui.update_uis(computer)
diff --git a/code/modules/pai/actions.dm b/code/modules/pai/actions.dm
index 0d22d828382..e067cca01e9 100644
--- a/code/modules/pai/actions.dm
+++ b/code/modules/pai/actions.dm
@@ -61,3 +61,18 @@
/datum/action/innate/pai/light/Trigger(trigger_flags)
..()
pai_owner.toggle_integrated_light()
+
+/datum/action/innate/pai/messenger
+ name = "Interact with PDA"
+ button_icon_state = "pda"
+ background_icon_state = "bg_tech"
+ overlay_icon_state = "bg_tech_border"
+
+/datum/action/innate/pai/messenger/Trigger(trigger_flags)
+ . = ..()
+ var/obj/item/pai_card/pai_holder = owner.loc
+ if(!istype(pai_holder.loc, /obj/item/modular_computer))
+ owner.balloon_alert(owner, "not in a pda!")
+ return
+ var/obj/item/modular_computer/computer_host = pai_holder.loc
+ computer_host.interact(owner)
diff --git a/code/modules/pai/camera.dm b/code/modules/pai/camera.dm
index 30b1918651e..a091b208638 100644
--- a/code/modules/pai/camera.dm
+++ b/code/modules/pai/camera.dm
@@ -1,10 +1,8 @@
/mob/living/silicon/pai/ClickOn(atom/target, params)
- ..()
- if(!camera?.in_camera_mode)
- return FALSE
- //pAI picture taking
- camera.toggle_camera_mode(sound = FALSE)
- camera.captureimage(target, usr, camera.picture_size_x - 1, camera.picture_size_y - 1)
+ . = ..()
+ if(aicamera && aicamera.in_camera_mode)
+ aicamera.toggle_camera_mode(sound = FALSE)
+ aicamera.captureimage(target, usr)
return TRUE
/obj/item/camera/siliconcam/pai_camera
@@ -46,13 +44,14 @@
* @returns {boolean} - TRUE if the camera worked.
*/
/mob/living/silicon/pai/proc/use_camera(mob/user, mode)
- if(!camera || isnull(mode))
+ if(!aicamera || isnull(mode))
return FALSE
switch(mode)
if(PAI_PHOTO_MODE_CAMERA)
- camera.toggle_camera_mode(user)
+ aicamera.toggle_camera_mode(user)
if(PAI_PHOTO_MODE_PRINTER)
- camera.pai_print(user)
+ var/obj/item/camera/siliconcam/pai_camera/paicam = aicamera
+ paicam.pai_print(user)
if(PAI_PHOTO_MODE_ZOOM)
- camera.adjust_zoom(user)
+ aicamera.adjust_zoom(user)
return TRUE
diff --git a/code/modules/pai/hud.dm b/code/modules/pai/hud.dm
index 057a199cdad..530780758d2 100644
--- a/code/modules/pai/hud.dm
+++ b/code/modules/pai/hud.dm
@@ -150,7 +150,7 @@
if(!..())
return
var/mob/living/silicon/pai/pAI = usr
- pAI.camera.toggle_camera_mode(usr)
+ pAI.aicamera.toggle_camera_mode(usr)
/atom/movable/screen/pai/image_view
name = "View Images"
@@ -161,7 +161,7 @@
if(!..())
return
var/mob/living/silicon/pai/pAI = usr
- pAI.camera.viewpictures(usr)
+ pAI.aicamera.viewpictures(usr)
/atom/movable/screen/pai/radio
name = "radio"
@@ -177,7 +177,6 @@
/datum/hud/pai/New(mob/living/silicon/pai/owner)
..()
var/atom/movable/screen/using
- var/mob/living/silicon/pai/mypai = mymob
// Software menu
using = new /atom/movable/screen/pai/software(null, src)
@@ -238,9 +237,8 @@
using = new /atom/movable/screen/pai/modpc(null, src)
using.screen_loc = ui_pai_mod_int
static_inventory += using
- mypai.pda_button = using
var/atom/movable/screen/pai/modpc/tablet_button = using
- tablet_button.pAI = mypai
+ tablet_button.pAI = mymob
// Internal GPS
using = new /atom/movable/screen/pai/internal_gps(null, src)
diff --git a/code/modules/pai/pai.dm b/code/modules/pai/pai.dm
index f8476339468..490e614b51f 100644
--- a/code/modules/pai/pai.dm
+++ b/code/modules/pai/pai.dm
@@ -79,10 +79,6 @@
var/obj/item/instrument/piano_synth/instrument
/// Newscaster
var/obj/machinery/newscaster/pai/newscaster
- /// PDA
- var/atom/movable/screen/ai/modpc/pda_button
- /// Photography module
- var/obj/item/camera/siliconcam/pai_camera/camera
/// Remote signaler
var/obj/item/assembly/signaler/internal/signaler
@@ -155,7 +151,6 @@
/mob/living/silicon/pai/Destroy()
QDEL_NULL(atmos_analyzer)
- QDEL_NULL(camera)
QDEL_NULL(hacking_cable)
QDEL_NULL(host_scan)
QDEL_NULL(instrument)
@@ -195,8 +190,8 @@
/mob/living/silicon/pai/Exited(atom/movable/gone, direction)
if(gone == atmos_analyzer)
atmos_analyzer = null
- else if(gone == camera)
- camera = null
+ else if(gone == aicamera)
+ aicamera = null
else if(gone == host_scan)
host_scan = null
else if(gone == internal_gps)
diff --git a/code/modules/pai/software.dm b/code/modules/pai/software.dm
index 85f952c43eb..103056a5535 100644
--- a/code/modules/pai/software.dm
+++ b/code/modules/pai/software.dm
@@ -125,7 +125,7 @@
if("Newscaster")
newscaster = new(src)
if("Photography Module")
- camera = new(src)
+ aicamera = new /obj/item/camera/siliconcam/pai_camera(src)
if("Remote Signaler")
signaler = new(src)
return TRUE
diff --git a/icons/mob/actions/actions_silicon.dmi b/icons/mob/actions/actions_silicon.dmi
index 7be634e9f6c..9c4b7ec7fbe 100644
Binary files a/icons/mob/actions/actions_silicon.dmi and b/icons/mob/actions/actions_silicon.dmi differ