diff --git a/baystation12.dme b/baystation12.dme
index a820faad30..98fc485a45 100644
--- a/baystation12.dme
+++ b/baystation12.dme
@@ -1037,6 +1037,7 @@
#include "code\modules\mob\living\silicon\robot\laws.dm"
#include "code\modules\mob\living\silicon\robot\life.dm"
#include "code\modules\mob\living\silicon\robot\login.dm"
+#include "code\modules\mob\living\silicon\robot\photos.dm"
#include "code\modules\mob\living\silicon\robot\robot.dm"
#include "code\modules\mob\living\silicon\robot\robot_damage.dm"
#include "code\modules\mob\living\silicon\robot\robot_items.dm"
@@ -1114,6 +1115,7 @@
#include "code\modules\paperwork\pen.dm"
#include "code\modules\paperwork\photocopier.dm"
#include "code\modules\paperwork\photography.dm"
+#include "code\modules\paperwork\silicon_photography.dm"
#include "code\modules\paperwork\stamps.dm"
#include "code\modules\power\apc.dm"
#include "code\modules\power\batteryrack.dm"
diff --git a/code/_onclick/ai.dm b/code/_onclick/ai.dm
index 204f39e69c..c6078c10ac 100644
--- a/code/_onclick/ai.dm
+++ b/code/_onclick/ai.dm
@@ -53,6 +53,11 @@
return
next_move = world.time + 9
+ if(aiCamera.in_camera_mode)
+ aiCamera.camera_mode_off()
+ aiCamera.captureimage(A, usr)
+ return
+
/*
AI restrained() currently does nothing
if(restrained())
diff --git a/code/_onclick/cyborg.dm b/code/_onclick/cyborg.dm
index d86faacbd1..04682c76ad 100644
--- a/code/_onclick/cyborg.dm
+++ b/code/_onclick/cyborg.dm
@@ -37,6 +37,14 @@
face_atom(A) // change direction to face what you clicked on
+ if(aiCamera.in_camera_mode)
+ aiCamera.camera_mode_off()
+ if(is_component_functioning("camera"))
+ aiCamera.captureimage(A, usr)
+ else
+ src << "Your camera isn't functional."
+ return
+
/*
cyborg restrained() currently does nothing
if(restrained())
diff --git a/code/game/machinery/newscaster.dm b/code/game/machinery/newscaster.dm
index b1783b1707..fba4927947 100644
--- a/code/game/machinery/newscaster.dm
+++ b/code/game/machinery/newscaster.dm
@@ -748,16 +748,27 @@ var/list/obj/machinery/newscaster/allCasters = list() //Global list that will co
/obj/machinery/newscaster/proc/AttachPhoto(mob/user as mob)
if(photo)
- photo.loc = src.loc
- user.put_in_inactive_hand(photo)
+ if(!issilicon(user))
+ photo.loc = src.loc
+ user.put_in_inactive_hand(photo)
photo = null
if(istype(user.get_active_hand(), /obj/item/weapon/photo))
photo = user.get_active_hand()
user.drop_item()
photo.loc = src
+ else if(istype(user,/mob/living/silicon))
+ var/mob/living/silicon/tempAI = user
+ var/obj/item/device/camera/siliconcam/camera = tempAI.aiCamera
+ if(!camera)
+ return
+ var/datum/picture/selection = camera.selectpicture()
+ if (!selection)
+ return
-
+ var/obj/item/weapon/photo/P = new/obj/item/weapon/photo()
+ P.construct(selection)
+ photo = P
//########################################################################################################################
diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm
index a2b375d3be..0fe0ddc93d 100644
--- a/code/modules/mob/living/silicon/ai/ai.dm
+++ b/code/modules/mob/living/silicon/ai/ai.dm
@@ -91,6 +91,7 @@ var/list/ai_list = list()
aiMulti = new(src)
aiRadio = new(src)
aiRadio.myAi = src
+ aiCamera = new/obj/item/device/camera/siliconcam/ai_camera(src)
if (istype(loc, /turf))
verbs.Add(/mob/living/silicon/ai/proc/ai_call_shuttle,/mob/living/silicon/ai/proc/ai_camera_track, \
@@ -756,4 +757,4 @@ var/list/ai_list = list()
src << "Accessing Subspace Transceiver control..."
if (src.aiRadio)
- src.aiRadio.interact(src)
+ src.aiRadio.interact(src)
diff --git a/code/modules/mob/living/silicon/robot/drone/drone.dm b/code/modules/mob/living/silicon/robot/drone/drone.dm
index 0ab4e42028..cd0cbc9e2c 100644
--- a/code/modules/mob/living/silicon/robot/drone/drone.dm
+++ b/code/modules/mob/living/silicon/robot/drone/drone.dm
@@ -61,6 +61,10 @@
flavor_text = "It's a tiny little repair drone. The casing is stamped with an NT logo and the subscript: 'NanoTrasen Recursive Repair Systems: Fixing Tomorrow's Problem, Today!'"
updateicon()
+/mob/living/silicon/robot/drone/init()
+ new/obj/item/device/camera/siliconcam/drone_camera(src)
+ playsound(src.loc, 'sound/machines/twobeep.ogg', 50, 0)
+
//Redefining some robot procs...
/mob/living/silicon/robot/drone/updatename()
real_name = "maintenance drone ([rand(100,999)])"
diff --git a/code/modules/mob/living/silicon/robot/laws.dm b/code/modules/mob/living/silicon/robot/laws.dm
index bff875a0d6..2d6a12e966 100644
--- a/code/modules/mob/living/silicon/robot/laws.dm
+++ b/code/modules/mob/living/silicon/robot/laws.dm
@@ -18,6 +18,7 @@
else
lawsync()
+ photosync()
src << "Laws synced with AI, be sure to note any changes."
if(mind && mind.special_role == "traitor" && mind.original == src)
src << "Remember, your AI does NOT share or know about your law 0."
diff --git a/code/modules/mob/living/silicon/robot/photos.dm b/code/modules/mob/living/silicon/robot/photos.dm
new file mode 100644
index 0000000000..fbcc3bf484
--- /dev/null
+++ b/code/modules/mob/living/silicon/robot/photos.dm
@@ -0,0 +1,13 @@
+/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."
diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm
index 273df70dd9..4daa0f5cf8 100644
--- a/code/modules/mob/living/silicon/robot/robot.dm
+++ b/code/modules/mob/living/silicon/robot/robot.dm
@@ -97,6 +97,7 @@
if(connected_ai)
connected_ai.connected_robots += src
lawsync()
+ photosync()
lawupdate = 1
else
lawupdate = 0
@@ -137,12 +138,11 @@
hud_list[IMPCHEM_HUD] = image('icons/mob/hud.dmi', src, "hudblank")
hud_list[IMPTRACK_HUD] = image('icons/mob/hud.dmi', src, "hudblank")
hud_list[SPECIALROLE_HUD] = image('icons/mob/hud.dmi', src, "hudblank")
+ init()
-
- if(istype(src,/mob/living/silicon/robot/drone))
- playsound(src.loc, 'sound/machines/twobeep.ogg', 50, 0)
- else
- playsound(loc, 'sound/voice/liveagain.ogg', 75, 1)
+/mob/living/silicon/robot/proc/init()
+ new/obj/item/device/camera/siliconcam/robot_camera(src)
+ playsound(loc, 'sound/voice/liveagain.ogg', 75, 1)
// setup the PDA and its name
/mob/living/silicon/robot/proc/setup_PDA()
diff --git a/code/modules/mob/living/silicon/robot/wires.dm b/code/modules/mob/living/silicon/robot/wires.dm
index 10b6832fe4..9ed4320c84 100644
--- a/code/modules/mob/living/silicon/robot/wires.dm
+++ b/code/modules/mob/living/silicon/robot/wires.dm
@@ -74,6 +74,7 @@
if(BORG_WIRE_LAWCHECK) //Forces a law update if the borg is set to receive them. Since an update would happen when the borg checks its laws anyway, not much use, but eh
if (src.lawupdate)
src.lawsync()
+ src.photosync()
if (BORG_WIRE_AI_CONTROL) //pulse the AI wire to make the borg reselect an AI
if(!src.emagged)
diff --git a/code/modules/mob/living/silicon/silicon.dm b/code/modules/mob/living/silicon/silicon.dm
index 99adb65ed0..d730bd9b5f 100644
--- a/code/modules/mob/living/silicon/silicon.dm
+++ b/code/modules/mob/living/silicon/silicon.dm
@@ -13,6 +13,8 @@
var/speak_exclamation = "declares"
var/speak_query = "queries"
+ var/obj/item/device/camera/siliconcam/aiCamera = null //photography
+
/mob/living/silicon/proc/show_laws()
return
diff --git a/code/modules/paperwork/photocopier.dm b/code/modules/paperwork/photocopier.dm
index 7f006325e6..6963fe2f75 100644
--- a/code/modules/paperwork/photocopier.dm
+++ b/code/modules/paperwork/photocopier.dm
@@ -34,6 +34,8 @@
dat += "+
"
else if(toner)
dat += "Please insert paper to copy.
"
+ if(istype(user,/mob/living/silicon))
+ dat += "Print photo from database
"
dat += "Current toner level: [toner]"
if(!toner)
dat +="
Please insert a new toner cartridge!"
@@ -112,6 +114,27 @@
if(copies < maxcopies)
copies++
updateUsrDialog()
+ else if(href_list["aipic"])
+ if(!istype(usr,/mob/living/silicon)) 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()
+ if (!selection)
+ return
+
+ var/obj/item/weapon/photo/p = new /obj/item/weapon/photo (src.loc)
+ p.construct(selection)
+ if (p.desc == "")
+ p.desc += "Copied by [tempAI.name]"
+ else
+ p.desc += " - Copied by [tempAI.name]"
+ toner -= 5
+ sleep(15)
+ updateUsrDialog()
attackby(obj/item/O as obj, mob/user as mob)
if(istype(O, /obj/item/weapon/paper))
diff --git a/code/modules/paperwork/photography.dm b/code/modules/paperwork/photography.dm
index cbc119eaf5..fe2326c21b 100644
--- a/code/modules/paperwork/photography.dm
+++ b/code/modules/paperwork/photography.dm
@@ -219,10 +219,33 @@
mob_detail += "You can also see [A] on the photo[A:health < 75 ? " - [A] looks hurt":""].[holding ? " [holding]":"."]."
return mob_detail
-
/obj/item/device/camera/afterattack(atom/target as mob|obj|turf|area, mob/user as mob, flag)
if(!on || !pictures_left || ismob(target.loc)) return
+ captureimage(target, user, flag)
+ playsound(loc, pick('sound/items/polaroid1.ogg', 'sound/items/polaroid2.ogg'), 75, 1, -3)
+
+ pictures_left--
+ desc = "A polaroid camera. It has [pictures_left] photos left."
+ user << "[pictures_left] photos left."
+ icon_state = icon_off
+ on = 0
+ spawn(64)
+ icon_state = icon_on
+ on = 1
+
+/obj/item/device/camera/proc/can_capture_turf(turf/T, mob/user)
+ var/mob/dummy = new(T) //Go go visibility check dummy
+ var/viewer = user
+ if(user.client) //To make shooting through security cameras possible
+ viewer = user.client.eye
+ var/can_see = (dummy in viewers(world.view, viewer)) != null
+
+ dummy.loc = null
+ dummy = null //Alas, nameless creature //garbage collect it instead
+ return can_see
+
+/obj/item/device/camera/proc/captureimage(atom/target, mob/user, flag)
var/x_c = target.x - 1
var/y_c = target.y + 1
var/z_c = target.z
@@ -233,25 +256,19 @@
for(var/i = 1; i <= 3; i++)
for(var/j = 1; j <= 3; j++)
var/turf/T = locate(x_c, y_c, z_c)
- var/mob/dummy = new(T) //Go go visibility check dummy
- var/viewer = user
- if(user.client) //To make shooting through security cameras possible
- viewer = user.client.eye
- if(dummy in viewers(world.view, viewer))
+ if(can_capture_turf(T, user))
turfs.Add(T)
- mobs += get_mobs(T)
- dummy.loc = null
- dummy = null //Alas, nameless creature //garbage collect it instead
+ mobs += get_mobs(T)
x_c++
y_c--
x_c = x_c - 3
+ var/datum/picture/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)
- var/obj/item/weapon/photo/P = new/obj/item/weapon/photo()
- P.loc = user.loc
- if(!user.get_inactive_hand())
- user.put_in_inactive_hand(P)
var/icon/small_img = icon(photoimage)
var/icon/tiny_img = icon(photoimage)
var/icon/ic = icon('icons/obj/items.dmi',"photo")
@@ -260,19 +277,29 @@
tiny_img.Scale(4, 4)
ic.Blend(small_img,ICON_OVERLAY, 10, 13)
pc.Blend(tiny_img,ICON_OVERLAY, 12, 19)
- P.icon = ic
- P.tiny = pc
- P.img = photoimage
- P.desc = mobs
- P.pixel_x = rand(-10, 10)
- P.pixel_y = rand(-10, 10)
- playsound(loc, pick('sound/items/polaroid1.ogg', 'sound/items/polaroid2.ogg'), 75, 1, -3)
- pictures_left--
- desc = "A polaroid camera. It has [pictures_left] photos left."
- user << "[pictures_left] photos left."
- icon_state = icon_off
- on = 0
- spawn(64)
- icon_state = icon_on
- on = 1
\ No newline at end of file
+ var/datum/picture/P = new()
+ P.fields["author"] = user
+ 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)
+
+ 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)
+ 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"]
diff --git a/code/modules/paperwork/silicon_photography.dm b/code/modules/paperwork/silicon_photography.dm
new file mode 100644
index 0000000000..4fbe953d72
--- /dev/null
+++ b/code/modules/paperwork/silicon_photography.dm
@@ -0,0 +1,162 @@
+/**************
+* 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
+ var/list/aipictures = list()
+
+/obj/item/device/camera/siliconcam/ai_camera //camera AI can take pictures with
+ name = "AI photo camera"
+
+/obj/item/device/camera/siliconcam/robot_camera //camera cyborgs can take pictures with
+ name = "Cyborg photo camera"
+
+/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
+ photos_taken++
+ P.fields["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
+ 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
+ else
+ injectaialbum(P)
+ usr << "Image recorded"
+
+/obj/item/device/camera/siliconcam/proc/selectpicture(obj/item/device/camera/siliconcam/cam)
+ if(!cam)
+ cam = getsource()
+
+ var/list/nametemp = list()
+ var/find
+ if(cam.aipictures.len == 0)
+ usr << "No images saved"
+ return
+ for(var/datum/picture/t in cam.aipictures)
+ nametemp += t.fields["name"]
+ find = input("Select image (numbered in order taken)") in nametemp
+
+ for(var/datum/picture/q in cam.aipictures)
+ if(q.fields["name"] == find)
+ return q
+
+/obj/item/device/camera/siliconcam/proc/viewpictures()
+ var/datum/picture/selection = selectpicture()
+
+ if(!selection)
+ return
+
+ var/obj/item/weapon/photo/P = new/obj/item/weapon/photo()
+ P.construct(selection)
+ P.show(usr)
+ usr << P.desc
+
+ // TG uses a special garbage collector.. qdel(P)
+ del(P) //so 10 thousand pictures items are not left in memory should an AI take them and then view them all.
+
+/obj/item/device/camera/siliconcam/proc/deletepicture(obj/item/device/camera/siliconcam/cam)
+ var/datum/picture/selection = selectpicture(cam)
+
+ if(!selection)
+ return
+
+ cam.aipictures -= selection
+ usr << "Image deleted"
+
+/obj/item/device/camera/siliconcam/ai_camera/can_capture_turf(turf/T, mob/user)
+ var/mob/living/silicon/ai = user
+ return ai.TurfAdjacent(T)
+
+/obj/item/device/camera/siliconcam/proc/toggle_camera_mode()
+ if(in_camera_mode)
+ camera_mode_off()
+ else
+ camera_mode_on()
+
+/obj/item/device/camera/siliconcam/proc/camera_mode_off()
+ src.in_camera_mode = 0
+ usr << "Camera Mode deactivated"
+
+/obj/item/device/camera/siliconcam/proc/camera_mode_on()
+ src.in_camera_mode = 1
+ usr << "Camera Mode activated"
+
+/obj/item/device/camera/siliconcam/ai_camera/printpicture(mob/user, datum/picture/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/ai_camera/verb/take_image()
+ set category = "AI Commands"
+ set name = "Take Image"
+ set desc = "Takes an image"
+ set src in usr
+
+ toggle_camera_mode()
+
+/obj/item/device/camera/siliconcam/ai_camera/verb/view_images()
+ set category = "AI Commands"
+ set name = "View Images"
+ set desc = "View images"
+ set src in usr
+
+ viewpictures()
+
+/obj/item/device/camera/siliconcam/ai_camera/verb/delete_images()
+ set category = "AI Commands"
+ set name = "Delete Image"
+ set desc = "Delete image"
+ set src in usr
+
+ deletepicture()
+
+/obj/item/device/camera/siliconcam/robot_camera/verb/take_image()
+ set category ="Robot Commands"
+ set name = "Take Image"
+ set desc = "Takes an image"
+ set src in usr
+
+ toggle_camera_mode()
+
+/obj/item/device/camera/siliconcam/robot_camera/verb/view_images()
+ set category ="Robot Commands"
+ set name = "View Images"
+ set desc = "View images"
+ set src in usr
+
+ viewpictures()
+
+/obj/item/device/camera/siliconcam/robot_camera/verb/delete_images()
+ set category = "Robot Commands"
+ set name = "Delete Image"
+ set desc = "Delete a local image"
+ set src in usr
+
+ // Explicitly only allow deletion from the local camera
+ 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/obj/item/device/camera/siliconcam/Cinfo
+ if(C.connected_ai)
+ Cinfo = C.connected_ai.aiCamera
+ else
+ Cinfo = src
+ return Cinfo