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