diff --git a/code/datums/wires/robot.dm b/code/datums/wires/robot.dm
index f65ee6be50..73555f3889 100644
--- a/code/datums/wires/robot.dm
+++ b/code/datums/wires/robot.dm
@@ -51,36 +51,17 @@ var/const/BORG_WIRE_CAMERA = 16
/datum/wires/robot/UpdatePulsed(var/index)
-
var/mob/living/silicon/robot/R = holder
switch(index)
if (BORG_WIRE_AI_CONTROL) //pulse the AI wire to make the borg reselect an AI
if(!R.emagged)
- var/new_ai = select_active_ai(R)
+ var/mob/living/silicon/ai/new_ai = select_active_ai(R)
if(new_ai && (new_ai != R.connected_ai))
+ R.connected_ai.connected_robots -= src
R.connected_ai = new_ai
+ new_ai.connected_robots += src
R.notify_ai(1)
- var/numberer = 1 // Send images the Cyborg has taken to the AI's album upon sync.
- for(var/datum/picture/z in R.aiCamera.aipictures)
- if(R.connected_ai.aiCamera.aipictures.len == 0)
- var/datum/picture/p = new/datum/picture()
- p = z
- p.fields["name"] = "Uploaded Image [numberer] (synced from [R.name])"
- R.connected_ai.aiCamera.aipictures += p
- numberer++
- continue
- for(var/datum/picture/t in R.connected_ai.aiCamera.aipictures) //Hopefully to prevent someone spamming images to silicons, by spamming this wire
- if((z.fields["pixel_y"] != t.fields["pixel_y"]) && (z.fields["pixel_x"] != t.fields["pixel_x"])) //~2.26 out of 1000 chance this will stop something it shouldn't
- var/datum/picture/p = new/datum/picture()
- p = z
- p.fields["name"] = "Uploaded Image [numberer] (synced from [R.name])"
- R.connected_ai.aiCamera.aipictures += p
- else
- continue
- numberer++
- if(R.aiCamera.aipictures.len > 0)
- R << "Locally saved images synced with AI. Images were retained in local database in case of loss of connection with the AI."
-
+ R.sync()
if (BORG_WIRE_CAMERA)
if(!isnull(R.camera) && R.camera.can_use() && !R.scrambledcodes)
R.camera.kick_viewers() // Kick anyone watching the Cyborg's camera
diff --git a/code/game/machinery/computer/security.dm b/code/game/machinery/computer/security.dm
index 5aed27cc56..76c9790c5d 100644
--- a/code/game/machinery/computer/security.dm
+++ b/code/game/machinery/computer/security.dm
@@ -576,9 +576,9 @@ What a mess.*/
return photo.img
if(istype(user, /mob/living/silicon))
var/mob/living/silicon/tempAI = usr
- var/datum/picture/selection = tempAI.GetPicture()
+ var/obj/item/weapon/photo/selection = tempAI.GetPicture()
if (selection)
- return selection.fields["img"]
+ return selection.img
/obj/machinery/computer/secure_data/emp_act(severity)
if(stat & (BROKEN|NOPOWER))
diff --git a/code/modules/mob/living/silicon/robot/photos.dm b/code/modules/mob/living/silicon/robot/photos.dm
index fbcc3bf484..7c52bd0f85 100644
--- a/code/modules/mob/living/silicon/robot/photos.dm
+++ b/code/modules/mob/living/silicon/robot/photos.dm
@@ -1,13 +1,20 @@
-/mob/living/silicon/robot/proc/photosync()
- var/obj/item/device/camera/siliconcam/master_cam = connected_ai ? connected_ai.aiCamera : null
- if (!master_cam)
- return
-
- var/synced
- synced = 0
- for(var/datum/picture/z in aiCamera.aipictures)
- if (!(master_cam.aipictures.Find(z)))
- aiCamera.printpicture(null, z)
- synced = 1
- if(synced)
- src << "Locally saved images synced with AI. Images were retained in local database in case of loss of connection with the AI."
+/mob/living/silicon/robot/proc/photosync()
+ var/obj/item/device/camera/siliconcam/master_cam = connected_ai ? connected_ai.aiCamera : null
+ if (!master_cam)
+ return
+
+ var/synced = 0
+ // Sync borg images to the master AI.
+ // We don't care about syncing the other way around
+ for(var/obj/item/weapon/photo/borg_photo in aiCamera.aipictures)
+ var/copied = 0
+ for(var/obj/item/weapon/photo/ai_photo in master_cam.aipictures)
+ if(borg_photo.id == ai_photo.id)
+ copied = 1
+ break
+ if(!copied)
+ master_cam.injectaialbum(borg_photo.copy(1), " (synced from [name])")
+ synced = 1
+
+ if(synced)
+ src << "Images synced with AI. Local images will be retained in the case of loss of connection with the AI."
diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm
index 17dd5e4d79..3f755bbb90 100644
--- a/code/modules/mob/living/silicon/robot/robot.dm
+++ b/code/modules/mob/living/silicon/robot/robot.dm
@@ -159,9 +159,8 @@ var/list/robot_verbs_default = list(
connected_ai = select_active_ai_with_fewest_borgs()
if(connected_ai)
connected_ai.connected_robots += src
- lawsync()
- photosync()
lawupdate = 1
+ sync()
else
lawupdate = 0
@@ -178,6 +177,10 @@ var/list/robot_verbs_default = list(
playsound(loc, 'sound/mecha/nominalsyndi.ogg', 75, 0)
+/mob/living/silicon/robot/proc/sync()
+ if(lawupdate && connected_ai)
+ lawsync()
+ photosync()
/mob/living/silicon/robot/drain_power(var/drain_check)
diff --git a/code/modules/paperwork/photocopier.dm b/code/modules/paperwork/photocopier.dm
index 41e59884c7..83b27b7a2b 100644
--- a/code/modules/paperwork/photocopier.dm
+++ b/code/modules/paperwork/photocopier.dm
@@ -43,11 +43,11 @@
if(href_list["copy"])
if(stat & (BROKEN|NOPOWER))
return
-
+
for(var/i = 0, i < copies, i++)
if(toner <= 0)
break
-
+
if (istype(copyitem, /obj/item/weapon/paper))
copy(copyitem)
sleep(15)
@@ -60,7 +60,7 @@
else
usr << "\The [copyitem] can't be copied by \the [src]."
break
-
+
use_power(active_power_usage)
updateUsrDialog()
else if(href_list["remove"])
@@ -81,19 +81,18 @@
else if(href_list["aipic"])
if(!istype(usr,/mob/living/silicon)) return
if(stat & (BROKEN|NOPOWER)) return
-
+
if(toner >= 5)
var/mob/living/silicon/tempAI = usr
var/obj/item/device/camera/siliconcam/camera = tempAI.aiCamera
if(!camera)
return
- var/datum/picture/selection = camera.selectpicture()
+ var/obj/item/weapon/photo/selection = camera.selectpicture()
if (!selection)
return
- var/obj/item/weapon/photo/p = new /obj/item/weapon/photo (src.loc)
- p.construct(selection)
+ var/obj/item/weapon/photo/p = photocopy(selection)
if (p.desc == "")
p.desc += "Copied by [tempAI.name]"
else
@@ -195,6 +194,7 @@
/obj/machinery/photocopier/proc/photocopy(var/obj/item/weapon/photo/photocopy)
var/obj/item/weapon/photo/p = photocopy.copy()
+ p.loc = src.loc
var/icon/I = icon(photocopy.icon, photocopy.icon_state)
if(toner > 10) //plenty of toner, go straight greyscale
@@ -210,6 +210,7 @@
if(toner < 0)
toner = 0
visible_message("A red light on \the [src] flashes, indicating that it is out of toner.")
+
return p
//If need_toner is 0, the copies will still be lightened when low on toner, however it will not be prevented from printing. TODO: Implement print queues for fax machines and get rid of need_toner
@@ -220,7 +221,7 @@
toner = 0
visible_message("A red light on \the [src] flashes, indicating that it is out of toner.")
break
-
+
if(istype(W, /obj/item/weapon/paper))
W = copy(W)
else if(istype(W, /obj/item/weapon/photo))
diff --git a/code/modules/paperwork/photography.dm b/code/modules/paperwork/photography.dm
index 5fc3733451..1a93e87539 100644
--- a/code/modules/paperwork/photography.dm
+++ b/code/modules/paperwork/photography.dm
@@ -21,17 +21,23 @@
/********
* photo *
********/
+var/global/photo_count = 0
+
/obj/item/weapon/photo
name = "photo"
icon = 'icons/obj/items.dmi'
icon_state = "photo"
item_state = "paper"
w_class = 2.0
+ var/id
var/icon/img //Big photo image
var/scribble //Scribble on the back.
var/icon/tiny
var/photo_size = 3
+/obj/item/weapon/photo/New()
+ id = photo_count++
+
/obj/item/weapon/photo/attack_self(mob/user as mob)
user.examinate(src)
@@ -270,8 +276,8 @@
y_c--
x_c = x_c - size
- var/datum/picture/P = createpicture(target, user, turfs, mobs, flag)
- printpicture(user, P)
+ var/obj/item/weapon/photo/p = createpicture(target, user, turfs, mobs, flag)
+ printpicture(user, p)
/obj/item/device/camera/proc/createpicture(atom/target, mob/user, list/turfs, mobs, flag)
var/icon/photoimage = get_icon(turfs, target)
@@ -285,43 +291,37 @@
ic.Blend(small_img,ICON_OVERLAY, 10, 13)
pc.Blend(tiny_img,ICON_OVERLAY, 12, 19)
- var/datum/picture/P = new()
- P.fields["name"] = "photo"
- P.fields["icon"] = ic
- P.fields["tiny"] = pc
- P.fields["img"] = photoimage
- P.fields["desc"] = mobs
- P.fields["pixel_x"] = rand(-10, 10)
- P.fields["pixel_y"] = rand(-10, 10)
- P.fields["size"] = size
-
- return P
-
-/obj/item/device/camera/proc/printpicture(mob/user, var/datum/picture/P)
- var/obj/item/weapon/photo/Photo = new/obj/item/weapon/photo()
- Photo.loc = user.loc
- if(!user.get_inactive_hand())
- user.put_in_inactive_hand(Photo)
- Photo.construct(P)
-
-/obj/item/weapon/photo/proc/construct(var/datum/picture/P)
- name = P.fields["name"]
- icon = P.fields["icon"]
- tiny = P.fields["tiny"]
- img = P.fields["img"]
- desc = P.fields["desc"]
- pixel_x = P.fields["pixel_x"]
- pixel_y = P.fields["pixel_y"]
- photo_size = P.fields["size"]
-
-/obj/item/weapon/photo/proc/copy()
- var/obj/item/weapon/photo/p = new/obj/item/weapon/photo()
-
- p.icon = icon(icon, icon_state)
- p.img = icon(img)
- p.tiny = icon(tiny)
- p.name = name
- p.desc = desc
- p.scribble = scribble
+ var/obj/item/weapon/photo/p = new()
+ p.name = "photo"
+ p.icon = ic
+ p.tiny = pc
+ p.img = photoimage
+ p.desc = mobs
+ p.pixel_x = rand(-10, 10)
+ p.pixel_y = rand(-10, 10)
+ p.photo_size = size
+
+ return p
+
+/obj/item/device/camera/proc/printpicture(mob/user, obj/item/weapon/photo/p)
+ p.loc = user.loc
+ if(!user.get_inactive_hand())
+ user.put_in_inactive_hand(p)
+
+/obj/item/weapon/photo/proc/copy(var/copy_id = 0)
+ var/obj/item/weapon/photo/p = new/obj/item/weapon/photo()
+
+ p.name = name
+ p.icon = icon
+ p.tiny = tiny
+ p.img = img
+ p.desc = desc
+ p.pixel_x = pixel_x
+ p.pixel_y = pixel_y
+ p.photo_size = photo_size
+ p.scribble = scribble
+
+ if(copy_id)
+ p.id = id
return p
diff --git a/code/modules/paperwork/silicon_photography.dm b/code/modules/paperwork/silicon_photography.dm
index fb321ae603..c754909c4c 100644
--- a/code/modules/paperwork/silicon_photography.dm
+++ b/code/modules/paperwork/silicon_photography.dm
@@ -1,10 +1,6 @@
/**************
* AI-specific *
**************/
-/datum/picture
- var/name = "image"
- var/list/fields = list()
-
/obj/item/device/camera/siliconcam
var/in_camera_mode = 0
var/photos_taken = 0
@@ -19,23 +15,22 @@
/obj/item/device/camera/siliconcam/drone_camera //currently doesn't offer the verbs, thus cannot be used
name = "Drone photo camera"
-/obj/item/device/camera/siliconcam/proc/injectaialbum(var/datum/picture/P, var/sufix = "") //stores image information to a list similar to that of the datacore
+/obj/item/device/camera/siliconcam/proc/injectaialbum(obj/item/weapon/photo/p, var/sufix = "") //stores image information to a list similar to that of the datacore
+ p.loc = src
photos_taken++
- P.fields["name"] = "Image [photos_taken][sufix]"
- var/obj/item/weapon/photo/photo = new
- photo.construct(P)
- aipictures += photo
+ p.name = "Image [photos_taken][sufix]"
+ aipictures += p
-/obj/item/device/camera/siliconcam/proc/injectmasteralbum(var/datum/picture/P) //stores image information to a list similar to that of the datacore
- var/mob/living/silicon/robot/C = src.loc
+/obj/item/device/camera/siliconcam/proc/injectmasteralbum(obj/item/weapon/photo/p) //stores image information to a list similar to that of the datacore
+ var/mob/living/silicon/robot/C = usr
if(C.connected_ai)
- var/mob/A = P.fields["author"]
- C.connected_ai.aiCamera.injectaialbum(P, " (taken by [A.name])")
- C.connected_ai << "Image recorded and saved by [name]"
- usr << "Image recorded and saved to remote database" //feedback to the Cyborg player that the picture was taken
+ C.connected_ai.aiCamera.injectaialbum(p.copy(1), " (synced from [C.name])")
+ C.connected_ai << "Image uploaded by [C.name]"
+ usr << "Image synced to remote database" //feedback to the Cyborg player that the picture was taken
else
- injectaialbum(P)
usr << "Image recorded"
+ // Always save locally
+ injectaialbum(p)
/obj/item/device/camera/siliconcam/proc/selectpicture(obj/item/device/camera/siliconcam/cam)
if(!cam)
@@ -65,14 +60,14 @@
selection.show(usr)
usr << selection.desc
-/obj/item/device/camera/siliconcam/proc/deletepicture()
- var/selection = selectpicture()
+/obj/item/device/camera/siliconcam/proc/deletepicture(obj/item/device/camera/siliconcam/cam)
+ var/selection = selectpicture(cam)
if(!selection)
return
aipictures -= selection
- usr << "Image deleted"
+ usr << "Local image deleted"
/obj/item/device/camera/siliconcam/ai_camera/can_capture_turf(turf/T, mob/user)
var/mob/living/silicon/ai = user
@@ -92,12 +87,12 @@
src.in_camera_mode = 1
usr << "Camera Mode activated"
-/obj/item/device/camera/siliconcam/ai_camera/printpicture(mob/user, datum/picture/P)
- injectaialbum(P)
+/obj/item/device/camera/siliconcam/ai_camera/printpicture(mob/user, obj/item/weapon/photo/p)
+ injectaialbum(p)
usr << "Image recorded"
-/obj/item/device/camera/siliconcam/robot_camera/printpicture(mob/user, datum/picture/P)
- injectmasteralbum(P)
+/obj/item/device/camera/siliconcam/robot_camera/printpicture(mob/user, obj/item/weapon/photo/p)
+ injectmasteralbum(p)
/obj/item/device/camera/siliconcam/ai_camera/verb/take_image()
set category = "AI Commands"
@@ -145,19 +140,13 @@
set desc = "Delete a local image"
set src in usr
- // Explicitly only allow deletion from the local camera
- var/mob/living/silicon/robot/C = src.loc
- if(C.connected_ai)
- C << "Not allowed to delete from the remote database."
- return
-
- deletepicture()
+ deletepicture(src)
obj/item/device/camera/siliconcam/proc/getsource()
if(istype(src.loc, /mob/living/silicon/ai))
return src
- var/mob/living/silicon/robot/C = src.loc
+ var/mob/living/silicon/robot/C = usr
var/obj/item/device/camera/siliconcam/Cinfo
if(C.connected_ai)
Cinfo = C.connected_ai.aiCamera