Photography Update

This commit is contained in:
kevinz000
2018-07-20 15:26:13 -07:00
parent 141edb25e8
commit 2a6e4fce59
49 changed files with 1455 additions and 811 deletions
+221
View File
@@ -0,0 +1,221 @@
#define CAMERA_PICTURE_SIZE_HARD_LIMIT 21
/obj/item/camera
name = "camera"
icon = 'icons/obj/items_and_weapons.dmi'
desc = "A polaroid camera."
icon_state = "camera"
item_state = "electropack"
lefthand_file = 'icons/mob/inhands/misc/devices_lefthand.dmi'
righthand_file = 'icons/mob/inhands/misc/devices_righthand.dmi'
w_class = WEIGHT_CLASS_SMALL
flags_1 = CONDUCT_1
slot_flags = ITEM_SLOT_BELT
materials = list(MAT_METAL = 50, MAT_GLASS = 150)
var/state_on = "camera"
var/state_off = "camera_off"
var/pictures_max = 10
var/pictures_left = 10
var/on = TRUE
var/cooldown = 64
var/blending = FALSE //lets not take pictures while the previous is still processing!
var/see_ghosts = CAMERA_NO_GHOSTS //for the spoop of it
var/obj/item/disk/holodisk/disk
var/sound/custom_sound
var/silent = FALSE
var/picture_size_x = 1
var/picture_size_y = 1
var/picture_size_x_min = 0
var/picture_size_y_min = 0
var/picture_size_x_max = 3
var/picture_size_y_max = 3
/obj/item/camera/CheckParts(list/parts_list)
..()
var/obj/item/camera/C = locate(/obj/item/camera) in contents
if(C)
pictures_max = C.pictures_max
pictures_left = C.pictures_left
visible_message("[C] has been imbued with godlike power!")
qdel(C)
/obj/item/camera/attack_self(mob/user)
if(!disk)
return
to_chat(user, "<span class='notice'>You eject [disk] out the back of [src].</span>")
user.put_in_hands(disk)
disk = null
/obj/item/camera/AltClick(mob/user)
var/desired_x = input(user, "How high do you want the camera to shoot, between [picture_size_x_min] and [picture_size_x_max]?", "Zoom", picture_size_x) as num
var/desired_y = input(user, "How wide do you want the camera to shoot, between [picture_size_y_min] and [picture_size_y_max]?", "Zoom", picture_size_y) as num
desired_x = min(CLAMP(desired_x, picture_size_x_min, picture_size_x_max), CAMERA_PICTURE_SIZE_HARD_LIMIT)
desired_y = min(CLAMP(desired_y, picture_size_y_min, picture_size_y_max), CAMERA_PICTURE_SIZE_HARD_LIMIT)
if(user.canUseTopic(src))
picture_size_x = desired_x
picture_size_y = desired_y
/obj/item/camera/attack(mob/living/carbon/human/M, mob/user)
return
/obj/item/camera/attackby(obj/item/I, mob/user, params)
if(istype(I, /obj/item/camera_film))
if(pictures_left)
to_chat(user, "<span class='notice'>[src] still has some film in it!</span>")
return
if(!user.temporarilyRemoveItemFromInventory(I))
return
to_chat(user, "<span class='notice'>You insert [I] into [src].</span>")
qdel(I)
pictures_left = pictures_max
return
if(istype(I, /obj/item/disk/holodisk))
if (!disk)
if(!user.transferItemToLoc(I, src))
to_chat(user, "<span class='warning'>[I] is stuck to your hand!</span>")
return TRUE
to_chat(user, "<span class='notice'>You slide [I] into the back of [src].</span>")
disk = I
else
to_chat(user, "<span class='warning'>There's already a disk inside [src].</span>")
return TRUE //no afterattack
..()
/obj/item/camera/examine(mob/user)
..()
to_chat(user, "It has [pictures_left] photos left.")
/obj/item/camera/proc/can_target(atom/target, mob/user, prox_flag)
if(!on || blending || !pictures_left || (!isturf(target) && !isturf(target.loc)) || !((isAI(user) && GLOB.cameranet.checkTurfVis(get_turf(target))) || ((user.client && (get_turf(target) in get_hear(user.client.view, user)) || (get_turf(target) in get_hear(world.view, user))))))
return FALSE
return TRUE
/obj/item/camera/afterattack(atom/target, mob/user, flag)
if (disk)
if(ismob(target))
if (disk.record)
QDEL_NULL(disk.record)
disk.record = new
var/mob/M = target
disk.record.caller_name = M.name
disk.record.set_caller_image(M)
else
to_chat(user, "<span class='warning'>Invalid holodisk target.</span>")
return
if(!can_target(target, user, flag))
return
on = FALSE
addtimer(CALLBACK(src, .proc/cooldown), cooldown)
icon_state = state_off
INVOKE_ASYNC(src, .proc/captureimage, target, user, flag, picture_size_x, picture_size_y)
/obj/item/camera/proc/cooldown()
UNTIL(!blending)
icon_state = state_on
on = TRUE
/obj/item/camera/proc/show_picture(mob/user, datum/picture/selection)
var/obj/item/photo/P = new(src, selection)
P.show(user)
to_chat(user, P.desc)
qdel(P)
/obj/item/camera/proc/captureimage(atom/target, mob/user, flag, size_x = 1, size_y = 1)
blending = TRUE
var/turf/target_turf = get_turf(target)
if(!isturf(target_turf))
blending = FALSE
return FALSE
size_x = CLAMP(size_x, 0, CAMERA_PICTURE_SIZE_HARD_LIMIT)
size_y = CLAMP(size_y, 0, CAMERA_PICTURE_SIZE_HARD_LIMIT)
var/list/desc = list()
var/ai_user = isAI(user)
var/list/seen
var/list/viewlist = (user && user.client)? getviewsize(user.client.view) : getviewsize(world.view)
var/viewr = max(viewlist[1], viewlist[2]) + max(size_x, size_y)
var/viewc = user.client? user.client.eye : target
seen = get_hear(viewr, viewc)
var/list/turfs = list()
var/list/mobs = list()
var/blueprints = FALSE
var/clone_area = SSmapping.RequestBlockReservation(size_x * 2 + 1, size_y * 2 + 1)
for(var/turf/T in block(locate(target_turf.x - size_x, target_turf.y - size_y, target_turf.z), locate(target_turf.x + size_x, target_turf.y + size_y, target_turf.z)))
if((ai_user && GLOB.cameranet.checkTurfVis(T)) || T in seen)
turfs += T
for(var/mob/M in T)
mobs += M
if(locate(/obj/item/areaeditor/blueprints) in T)
blueprints = TRUE
CHECK_TICK
for(var/i in mobs)
desc += camera_get_mobdesc(i)
var/psize_x = (size_x * 2 + 1) * world.icon_size
var/psize_y = (size_y * 2 + 1) * world.icon_size
var/get_icon = camera_get_icon(turfs, target_turf, psize_x, psize_y, clone_area, size_x, size_y, (size_x * 2 + 1), (size_y * 2 + 1))
qdel(clone_area)
var/icon/temp = icon('icons/effects/96x96.dmi',"")
temp.Blend("#000", ICON_OVERLAY)
temp.Scale(psize_x, psize_y)
temp.Blend(get_icon, ICON_OVERLAY)
var/datum/picture/P = new("picture", desc.Join(""), temp, null, psize_x, psize_y, blueprints)
after_picture(user, P, flag)
blending = FALSE
/obj/item/camera/proc/camera_get_mobdesc(mob/M)
var/list/mob_details = list()
if(M.invisibility)
if(see_ghosts && isobserver(M))
mob_details += "You can also see a g-g-g-g-ghooooost! "
else
return mob_details
var/list/holding = list()
if(isliving(M))
var/mob/living/L = M
var/len = length(L.held_items)
if(len)
for(var/obj/item/I in L.held_items)
if(!holding.len)
holding += "They are holding \a [I]"
else if(L.held_items.Find(I) == len)
holding += ", and \a [I]."
else
holding += ", \a [I]"
holding += "."
holding = holding.Join("")
mob_details += "You can also see [L] on the photo[L.health < (L.maxHealth * 0.75) ? ", looking a bit hurt":""][holding ? ". [holding]":"."]."
return mob_details.Join("")
/obj/item/camera/proc/after_picture(mob/user, datum/picture/picture, proximity_flag)
printpicture(user, picture)
/obj/item/camera/proc/printpicture(mob/user, datum/picture/picture) //Normal camera proc for creating photos
var/obj/item/photo/p = new(get_turf(src), picture)
if(in_range(src, user)) //needed because of TK
user.put_in_hands(p)
pictures_left--
to_chat(user, "<span class='notice'>[pictures_left] photos left.</span>")
var/customize = alert(user, "Do you want to customize the photo?", "Customization", "Yes", "No")
if(customize == "Yes")
var/name1 = input(user, "Set a name for this photo, or leave blank. 32 characters max.", "Name") as text|null
var/desc1 = input(user, "Set a description to add to photo, or leave blank. 128 characters max.", "Caption") as text|null
var/caption = input(user, "Set a caption for this photo, or leave blank. 256 characters max.", "Caption") as text|null
if(name1)
name1 = copytext(name1, 1, 33)
picture.picture_name = name1
if(desc1)
desc1 = copytext(desc1, 1, 129)
picture.picture_desc = "[desc1] - [picture.picture_desc]"
if(caption)
caption = copytext(caption, 1, 257)
picture.caption = caption
p.set_picture(picture)
if(CONFIG_GET(flag/picture_logging_camera))
picture.log_to_file()
@@ -0,0 +1,88 @@
/obj/effect/appearance_clone
/obj/effect/appearance_clone/New(loc, atom/A) //Intentionally not Initialize().
if(istype(A))
appearance = A.appearance
dir = A.dir
if(ismovableatom(A))
var/atom/movable/AM = A
step_x = AM.step_x
step_y = AM.step_y
. = ..()
/obj/item/camera/proc/camera_get_icon(list/turfs, turf/center, psize_x = 96, psize_y = 96, datum/turf_reservation/clone_area, size_x, size_y, total_x, total_y)
var/list/atoms = list()
var/skip_normal = FALSE
var/wipe_atoms = FALSE
if(istype(clone_area) && total_x == clone_area.width && total_y == clone_area.height && size_x >= 0 && size_y > 0)
var/cloned_center_x = round(clone_area.bottom_left_coords[1] + ((total_x - 1) / 2))
var/cloned_center_y = round(clone_area.bottom_left_coords[2] + ((total_y - 1) / 2))
for(var/t in turfs)
var/turf/T = t
var/offset_x = T.x - center.x
var/offset_y = T.y - center.y
var/turf/newT = locate(cloned_center_x + offset_x, cloned_center_y + offset_y, clone_area.bottom_left_coords[3])
if(!(newT in clone_area.reserved_turfs)) //sanity check so we don't overwrite other areas somehow
continue
atoms += new /obj/effect/appearance_clone(newT, T)
if(T.loc.icon_state)
atoms += new /obj/effect/appearance_clone(newT, T.loc)
for(var/i in T.contents)
var/atom/A = i
if(!A.invisibility || (see_ghosts && isobserver(A)))
atoms += new /obj/effect/appearance_clone(newT, A)
skip_normal = TRUE
wipe_atoms = TRUE
center = locate(cloned_center_x, cloned_center_y, clone_area.bottom_left_coords[3])
if(!skip_normal)
for(var/i in turfs)
var/turf/T = i
atoms += T
for(var/atom/movable/A in T)
if(A.invisibility)
if(!(see_ghosts && isobserver(A)))
continue
atoms += A
CHECK_TICK
var/icon/res = icon('icons/effects/96x96.dmi', "")
res.Scale(psize_x, psize_y)
var/list/sorted = list()
var/j
for(var/i in 1 to atoms.len)
var/atom/c = atoms[i]
for(j = sorted.len, j > 0, --j)
var/atom/c2 = sorted[j]
if(c2.layer <= c.layer)
break
sorted.Insert(j+1, c)
CHECK_TICK
var/xcomp = FLOOR(psize_x / 2, 1) - 15
var/ycomp = FLOOR(psize_y / 2, 1) - 15
for(var/atom/A in sorted)
var/xo = (A.x - center.x) * world.icon_size + A.pixel_x + xcomp
var/yo = (A.y - center.y) * world.icon_size + A.pixel_y + ycomp
if(ismovableatom(A))
var/atom/movable/AM = A
xo += AM.step_x
yo += AM.step_y
var/icon/img = getFlatIcon(A)
res.Blend(img, blendMode2iconMode(A.blend_mode), xo, yo)
CHECK_TICK
if(!silent)
if(istype(custom_sound)) //This is where the camera actually finishes its exposure.
playsound(loc, custom_sound, 75, 1, -3)
else
playsound(loc, pick('sound/items/polaroid1.ogg', 'sound/items/polaroid2.ogg'), 75, 1, -3)
if(wipe_atoms)
QDEL_LIST(atoms)
return res
+14
View File
@@ -0,0 +1,14 @@
/*
* Film
*/
/obj/item/camera_film
name = "film cartridge"
icon = 'icons/obj/items_and_weapons.dmi'
desc = "A camera film cartridge. Insert it into a camera to reload it."
icon_state = "film"
item_state = "electropack"
lefthand_file = 'icons/mob/inhands/misc/devices_lefthand.dmi'
righthand_file = 'icons/mob/inhands/misc/devices_righthand.dmi'
w_class = WEIGHT_CLASS_TINY
resistance_flags = FLAMMABLE
materials = list(MAT_METAL = 10, MAT_GLASS = 10)
+14
View File
@@ -0,0 +1,14 @@
/obj/item/camera/spooky
name = "camera obscura"
desc = "A polaroid camera, some say it can see ghosts!"
see_ghosts = CAMERA_SEE_GHOSTS_BASIC
/obj/item/camera/spooky/badmin
desc = "A polaroid camera, some say it can see ghosts! It seems to have an extra magnifier on the end."
see_ghosts = CAMERA_SEE_GHOSTS_ORBIT
/obj/item/camera/detective
name = "Detective's camera"
desc = "A polaroid camera with extra capacity for crime investigations."
pictures_max = 30
pictures_left = 30
@@ -0,0 +1,145 @@
// Picture frames
/obj/item/wallframe/picture
name = "picture frame"
desc = "The perfect showcase for your favorite deathtrap memories."
icon = 'icons/obj/decals.dmi'
materials = list()
flags_1 = 0
icon_state = "frame-empty"
result_path = /obj/structure/sign/picture_frame
var/obj/item/photo/displayed
/obj/item/wallframe/picture/attackby(obj/item/I, mob/user)
if(istype(I, /obj/item/photo))
if(!displayed)
if(!user.transferItemToLoc(I, src))
return
displayed = I
update_icon()
else
to_chat(user, "<span class=notice>\The [src] already contains a photo.</span>")
..()
//ATTACK HAND IGNORING PARENT RETURN VALUE
/obj/item/wallframe/picture/attack_hand(mob/user)
if(user.get_inactive_held_item() != src)
..()
return
if(contents.len)
var/obj/item/I = pick(contents)
user.put_in_hands(I)
to_chat(user, "<span class='notice'>You carefully remove the photo from \the [src].</span>")
displayed = null
update_icon()
return ..()
/obj/item/wallframe/picture/attack_self(mob/user)
user.examinate(src)
/obj/item/wallframe/picture/examine(mob/user)
if(user.is_holding(src) && displayed)
displayed.show(user)
else
..()
/obj/item/wallframe/picture/update_icon()
cut_overlays()
if(displayed)
add_overlay(getFlatIcon(displayed))
/obj/item/wallframe/picture/after_attach(obj/O)
..()
var/obj/structure/sign/picture_frame/PF = O
PF.copy_overlays(src)
if(displayed)
PF.framed = displayed
if(contents.len)
var/obj/item/I = pick(contents)
I.forceMove(PF)
/obj/structure/sign/picture_frame
name = "picture frame"
desc = "Every time you look it makes you laugh."
icon = 'icons/obj/decals.dmi'
icon_state = "frame-empty"
var/obj/item/photo/framed
var/persistence_id
/obj/structure/sign/picture_frame/Initialize(mapload, dir, building)
. = ..()
LAZYADD(SSpersistence.photo_frames, src)
if(dir)
setDir(dir)
if(building)
pixel_x = (dir & 3)? 0 : (dir == 4 ? -30 : 30)
pixel_y = (dir & 3)? (dir ==1 ? -30 : 30) : 0
/obj/structure/sign/picture_frame/Destroy()
LAZYREMOVE(SSpersistence.photo_frames, src)
return ..()
/obj/structure/sign/picture_frame/proc/get_photo_id()
if(istype(framed) && istype(framed.picture))
return framed.picture.id
/obj/structure/sign/picture_frame/proc/load_from_id(id)
var/obj/item/photo/P = load_photo_from_disk(id)
if(istype(P))
if(istype(framed))
framed.forceMove(drop_location())
else
qdel(framed)
framed = P
update_icon()
/obj/structure/sign/picture_frame/examine(mob/user)
if(in_range(src, user) && framed)
framed.show(user)
else
..()
/obj/structure/sign/picture_frame/attackby(obj/item/I, mob/user, params)
if(istype(I, /obj/item/screwdriver) || istype(I, /obj/item/wrench))
to_chat(user, "<span class='notice'>You start unsecuring [name]...</span>")
if(I.use_tool(src, user, 30, volume=50))
playsound(loc, 'sound/items/deconstruct.ogg', 50, 1)
to_chat(user, "<span class='notice'>You unsecure [name].</span>")
deconstruct()
return
else if(istype(I, /obj/item/photo))
if(!framed)
var/obj/item/photo/P = I
if(!user.transferItemToLoc(P, src))
return
framed = P
update_icon()
else
to_chat(user, "<span class=notice>\The [src] already contains a photo.</span>")
..()
/obj/structure/sign/picture_frame/attack_hand(mob/user)
. = ..()
if(.)
return
if(framed)
framed.show(user)
/obj/structure/sign/picture_frame/update_icon()
cut_overlays()
if(framed)
add_overlay(getFlatIcon(framed))
/obj/structure/sign/picture_frame/deconstruct(disassembled = TRUE)
if(!(flags_1 & NODECONSTRUCT_1))
var/obj/item/wallframe/picture/F = new /obj/item/wallframe/picture(loc)
if(framed)
F.displayed = framed
framed = null
if(contents.len)
var/obj/item/I = pick(contents)
I.forceMove(F)
F.update_icon()
qdel(src)
@@ -0,0 +1,98 @@
/obj/item/camera/siliconcam
name = "silicon photo camera"
var/in_camera_mode = FALSE
var/list/datum/picture/stored = list()
/obj/item/camera/siliconcam/ai_camera
name = "AI photo camera"
/obj/item/camera/siliconcam/proc/toggle_camera_mode(mob/user)
if(in_camera_mode)
camera_mode_off(user)
else
camera_mode_on(user)
/obj/item/camera/siliconcam/proc/camera_mode_off(mob/user)
in_camera_mode = FALSE
to_chat(user, "<B>Camera Mode deactivated</B>")
/obj/item/camera/siliconcam/proc/camera_mode_on(mob/user)
in_camera_mode = TRUE
to_chat(user, "<B>Camera Mode activated</B>")
/obj/item/camera/siliconcam/proc/selectpicture(mob/user)
var/list/nametemp = list()
var/find
if(!stored.len)
to_chat(usr, "<span class='boldannounce'>No images saved</span>")
return
var/list/temp = list()
for(var/i in stored)
var/datum/picture/p = i
nametemp += p.picture_name
temp[p.picture_name] = p
find = input(user, "Select image") in nametemp|null
if(!find)
return
return temp[find]
/obj/item/camera/siliconcam/proc/viewpictures(mob/user)
var/datum/picture/selection = selectpicture(user)
if(istype(selection))
show_picture(user, selection)
/obj/item/camera/siliconcam/ai_camera/after_picture(mob/user, datum/picture/picture, proximity_flag)
var/number = stored.len
picture.picture_name = "Image [number] (taken by [loc.name])"
stored[picture] = TRUE
to_chat(usr, "<span class='unconscious'>Image recorded</span>")
/obj/item/camera/siliconcam/robot_camera
name = "Cyborg photo camera"
var/printcost = 2
/obj/item/camera/siliconcam/robot_camera/after_picture(mob/user, datum/picture/picture, proximity_flag)
var/mob/living/silicon/robot/C = loc
if(istype(C) && istype(C.connected_ai))
var/number = C.connected_ai.aicamera.stored.len
picture.picture_name = "Image [number] (taken by [loc.name])"
C.connected_ai.aicamera.stored[picture] = TRUE
to_chat(usr, "<span class='unconscious'>Image recorded and saved to remote database</span>")
else
var/number = stored.len
picture.picture_name = "Image [number] (taken by [loc.name])"
stored[picture] = TRUE
to_chat(usr, "<span class='unconscious'>Image recorded and saved to local storage. Upload will happen automatically if unit is lawsynced.</span>")
/obj/item/camera/siliconcam/robot_camera/selectpicture(mob/user)
var/mob/living/silicon/robot/R = loc
if(istype(R) && R.connected_ai)
R.picturesync()
return R.connected_ai.aicamera.selectpicture(user)
else
return ..()
/obj/item/camera/siliconcam/robot_camera/verb/borgprinting()
set category ="Robot Commands"
set name = "Print Image"
set src in usr
if(usr.stat == DEAD)
return
borgprint(usr)
/obj/item/camera/siliconcam/robot_camera/proc/borgprint(mob/user)
var/mob/living/silicon/robot/C = loc
if(!istype(C) || C.toner < 20)
to_chat(user, "<span class='warning'>Insufficent toner to print image.</span>")
return
var/datum/picture/selection = selectpicture(user)
if(!istype(selection))
to_chat(user, "<span class='warning'>Invalid Image.</span>")
return
var/obj/item/photo/p = new /obj/item/photo(C.loc, selection)
p.pixel_x = rand(-10, 10)
p.pixel_y = rand(-10, 10)
C.toner -= printcost //All fun allowed.
visible_message("[C.name] spits out a photograph from a narrow slot on its chassis.")
to_chat(usr, "<span class='notice'>You print a photograph.</span>")