mirror of
https://github.com/Aurorastation/Aurora.3.git
synced 2026-08-21 12:02:31 +01:00
Commune can now send snapshot popups of paper & photo contents to targets, similar to how Show-Held-Item can let others see the items' contents. This was originally planned for the initial PR and only didn't make it in because I didn't know how to get the functionality. There's more unique psi-sensitivity interactions in this. There is a 45% chance for psi-deaf targets to even get the photo popup. Photo scribbles fittingly appear scrambled to the psi-deaf. <img width="969" height="232" alt="image" src="https://github.com/user-attachments/assets/84105c37-6c1d-4da2-83bb-738ce6651977" /> On the chance psi-deaf even get the photo popup, there is a 60% chance the photo will be in greyscale. <img width="476" height="195" alt="image" src="https://github.com/user-attachments/assets/030407b7-ce51-4b20-a1e2-6eb93fb21be7" /> Psi-sensitive targets receiving a paper popup will have it translated based on what the sender understands. This is a fun form of translation because it's possible for the target to _not_ understand a written language they actually know simply because the sender doesn't. <img width="1411" height="656" alt="image" src="https://github.com/user-attachments/assets/9d4fe196-2593-4535-b062-bbdfa8e1e819" /> There is also a QoL adjacency check for writing scribbles on photos now because it bugged me I needed to use both hands while testing. NEW: If a psi-deaf target doesn't get it in greyscale, they may also get photos with randomized colors <img width="443" height="444" alt="image" src="https://github.com/user-attachments/assets/f9a1f1c0-a6af-4d1e-95e3-260231d57643" /> This can seriously reframe some photos. Lots of fun with possible misunderstandings. Both the above and below are the same photo with Skrell blood, but the above looks like vaurca blood while the below one doesn't look to even have blood at first glance. <img width="444" height="447" alt="image" src="https://github.com/user-attachments/assets/166b40f2-6ed7-49af-95e1-989ffbb69e60" /> --------- Signed-off-by: runecap <43975590+runecap@users.noreply.github.com> Co-authored-by: VMSolidus <evilexecutive@gmail.com>
331 lines
9.1 KiB
Plaintext
331 lines
9.1 KiB
Plaintext
/* Photography!
|
|
* Contains:
|
|
* * Camera
|
|
* * Camera Film
|
|
* * Photos
|
|
* * Photo Albums
|
|
*/
|
|
|
|
/*******
|
|
* film *
|
|
*******/
|
|
/obj/item/camera_film
|
|
name = "film cartridge"
|
|
icon = 'icons/obj/bureaucracy.dmi'
|
|
desc = "A camera film cartridge. Insert it into a camera to reload it."
|
|
icon_state = "film"
|
|
item_state = "electropack"
|
|
w_class = WEIGHT_CLASS_TINY
|
|
|
|
/obj/item/camera_film/taj_film
|
|
name = "film canister"
|
|
icon = 'icons/obj/tajara_items.dmi'
|
|
desc = "A rolle of 35mm film intended for cameras of Tajaran make."
|
|
icon_state = "taj_film"
|
|
|
|
/********
|
|
* photo *
|
|
********/
|
|
GLOBAL_VAR_INIT(photo_count, 0)
|
|
|
|
/obj/item/photo
|
|
name = "photo"
|
|
desc = "An archaic means of visual preservation, kept alive as kitschy memorabilia by paparazzi, conspiracy theorists and teenage girls."
|
|
icon = 'icons/obj/bureaucracy.dmi'
|
|
icon_state = "photo"
|
|
item_state = "paper"
|
|
w_class = WEIGHT_CLASS_TINY
|
|
var/picture_desc // Who and/or what's in the picture.
|
|
var/id
|
|
var/icon/img //Big photo image
|
|
var/scribble //Scribble on the back.
|
|
var/icon/tiny
|
|
var/photo_size = 3
|
|
|
|
drop_sound = 'sound/items/drop/paper.ogg'
|
|
pickup_sound = 'sound/items/pickup/paper.ogg'
|
|
|
|
/obj/item/photo/feedback_hints(mob/user, distance, is_adjacent)
|
|
. += ..()
|
|
if(distance <= 1 || in_slide_projector(user))
|
|
show(user)
|
|
. += SPAN_NOTICE("[picture_desc]")
|
|
else
|
|
. += SPAN_NOTICE("You are too far away to discern its contents.")
|
|
|
|
/obj/item/photo/New()
|
|
. = ..()
|
|
id = GLOB.photo_count++
|
|
|
|
/obj/item/photo/attack_self(mob/user as mob)
|
|
examinate(user, src)
|
|
|
|
/obj/item/photo/attackby(obj/item/attacking_item, mob/user)
|
|
if(attacking_item.tool_behaviour == TOOL_PEN)
|
|
var/txt = sanitize( tgui_input_text(user, "What would you like to write on the back?", "Photo Writing", max_length = 128), 128 )
|
|
if((loc == user || Adjacent(user)) && user.stat == 0)
|
|
scribble = txt
|
|
..()
|
|
|
|
/obj/item/photo/proc/show(mob/user as mob)
|
|
send_rsc(user, img, "tmp_photo_[id].png")
|
|
var/dat = "<html><head><title>[name]</title></head>" \
|
|
+ "<body style='overflow:hidden;margin:0;text-align:center'>" \
|
|
+ "<img src='tmp_photo_[id].png' width='[64*photo_size]' style='-ms-interpolation-mode:nearest-neighbor' />" \
|
|
+ "[scribble ? "<br>Written on the back:<br><i>[scribble]</i>" : ""]" \
|
|
+ "</body></html>"
|
|
show_browser(user, HTML_SKELETON(dat), "window=book;size=[64*photo_size]x[scribble ? 400 : 64*photo_size]")
|
|
onclose(user, "[name]")
|
|
return
|
|
|
|
/obj/item/photo/verb/rename()
|
|
set name = "Rename Photo"
|
|
set category = "Object"
|
|
set src in usr
|
|
|
|
if(use_check_and_message(usr, USE_ALLOW_NON_ADJACENT))
|
|
return
|
|
|
|
var/n_name = sanitizeSafe(input(usr, "What would you like to label the photo?", "Photo Labelling", null) as text, MAX_NAME_LEN)
|
|
|
|
if(use_check_and_message(usr, USE_ALLOW_NON_ADJACENT))
|
|
return
|
|
|
|
var/atom/surface_atom = recursive_loc_turf_check(src, 3, usr)
|
|
if(surface_atom == usr || surface_atom.Adjacent(usr))
|
|
if(n_name)
|
|
name = "[initial(name)] ([n_name])"
|
|
else
|
|
name = initial(name)
|
|
add_fingerprint(usr)
|
|
|
|
|
|
/**************
|
|
* photo album *
|
|
**************/
|
|
/obj/item/storage/photo_album
|
|
name = "photo album"
|
|
icon = 'icons/obj/bureaucracy.dmi'
|
|
icon_state = "album"
|
|
item_state = "briefcase"
|
|
can_hold = list(/obj/item/photo)
|
|
|
|
/obj/item/storage/photo_album/mouse_drop_dragged(atom/over, mob/user, src_location, over_location, params)
|
|
|
|
if((istype(user, /mob/living/carbon/human)))
|
|
var/mob/M = user
|
|
if(!( istype(over, /atom/movable/screen) ))
|
|
return ..()
|
|
playsound(loc, SFX_RUSTLE, 50, 1, -5)
|
|
if((!( M.restrained() ) && !( M.stat ) && M.back == src))
|
|
switch(over.name)
|
|
if("right hand")
|
|
M.u_equip(src)
|
|
M.equip_to_slot_if_possible(src, slot_r_hand)
|
|
if("left hand")
|
|
M.u_equip(src)
|
|
M.equip_to_slot_if_possible(src, slot_l_hand)
|
|
add_fingerprint(user)
|
|
return
|
|
if(over == user && in_range(src, user) || user.contents.Find(src))
|
|
if(user.s_active)
|
|
user.s_active.close(user)
|
|
show_to(user)
|
|
return
|
|
return
|
|
|
|
/*********
|
|
* camera *
|
|
*********/
|
|
/obj/item/camera
|
|
name = "camera"
|
|
icon = 'icons/obj/bureaucracy.dmi'
|
|
desc = "A polaroid camera."
|
|
icon_state = "camera"
|
|
item_state = "electropack"
|
|
w_class = WEIGHT_CLASS_SMALL
|
|
obj_flags = OBJ_FLAG_CONDUCTABLE
|
|
slot_flags = SLOT_BELT
|
|
matter = list(DEFAULT_WALL_MATERIAL = 2000)
|
|
var/black_white = FALSE
|
|
var/pictures_max = 10
|
|
var/pictures_left = 10
|
|
var/on = 1
|
|
var/icon_on = "camera"
|
|
var/icon_off = "camera_off"
|
|
var/size = 3
|
|
|
|
/obj/item/camera/feedback_hints(mob/user, distance, is_adjacent)
|
|
. += ..()
|
|
if(is_adjacent)
|
|
. += SPAN_NOTICE("It has <b>[pictures_left] photos</b> left.")
|
|
|
|
/obj/item/camera/verb/change_size()
|
|
set name = "Set Photo Focus"
|
|
set category = "Object"
|
|
set src in usr
|
|
|
|
var/nsize = input("Photo Size","Pick a size of resulting photo.") as null|anything in list(1,3,5,7)
|
|
if(nsize)
|
|
size = nsize
|
|
to_chat(usr, SPAN_NOTICE("Camera will now take [size]x[size] photos."))
|
|
|
|
/obj/item/camera/attack(mob/living/target_mob, mob/living/user, target_zone)
|
|
return
|
|
|
|
/obj/item/camera/attack_self(mob/user as mob)
|
|
on = !on
|
|
if(on)
|
|
src.icon_state = icon_on
|
|
else
|
|
src.icon_state = icon_off
|
|
to_chat(user, "You switch the camera [on ? "on" : "off"].")
|
|
return
|
|
|
|
/obj/item/camera/attackby(obj/item/attacking_item, mob/user)
|
|
if(istype(attacking_item, /obj/item/camera_film))
|
|
if(pictures_left)
|
|
to_chat(user, SPAN_NOTICE("[src] still has some film in it!"))
|
|
return TRUE
|
|
to_chat(user, SPAN_NOTICE("You insert [attacking_item] into [src]."))
|
|
user.drop_from_inventory(attacking_item, get_turf(src))
|
|
qdel(attacking_item)
|
|
pictures_left = pictures_max
|
|
return TRUE
|
|
return ..()
|
|
|
|
/obj/item/camera/AltClick(var/mob/user)
|
|
change_size()
|
|
|
|
/obj/item/camera/proc/get_mobs(turf/the_turf as turf)
|
|
var/mob_detail
|
|
for(var/mob/living/carbon/A in the_turf)
|
|
if(A.invisibility) continue
|
|
var/holding = null
|
|
if(A.l_hand || A.r_hand)
|
|
if(A.l_hand) holding = "They are holding \a [A.l_hand]"
|
|
if(A.r_hand)
|
|
if(holding)
|
|
holding += " and \a [A.r_hand]"
|
|
else
|
|
holding = "They are holding \a [A.r_hand]"
|
|
|
|
if(!mob_detail)
|
|
mob_detail = "You can see [A] in the photo[A.health < 75 ? " - [A] looks hurt":""].[holding ? " [holding]":"."]. "
|
|
else
|
|
mob_detail += "You can also see [A] in the photo[A.health < 75 ? " - [A] looks hurt":""].[holding ? " [holding]":"."]."
|
|
return mob_detail
|
|
|
|
/obj/item/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)
|
|
|
|
do_photo_sound()
|
|
|
|
pictures_left--
|
|
to_chat(user, SPAN_NOTICE("[pictures_left] photos left."))
|
|
icon_state = icon_off
|
|
on = 0
|
|
spawn(64)
|
|
icon_state = icon_on
|
|
on = 1
|
|
|
|
/obj/item/camera/proc/do_photo_sound()
|
|
playsound(loc, SFX_PRINT, 75, 1, -3)
|
|
|
|
/obj/item/camera/detective
|
|
name = "detectives camera"
|
|
desc = "A one use - polaroid camera."
|
|
pictures_left = 30
|
|
|
|
//Proc for capturing check
|
|
/mob/living/proc/can_capture_turf(turf/T)
|
|
return TRUE // DVIEW will do sanity checks, we've got no special checks.
|
|
|
|
/obj/item/camera/proc/captureimage(atom/target, mob/living/user, flag)
|
|
var/obj/item/photo/p = createpicture(get_turf(target), user, flag)
|
|
printpicture(user, p)
|
|
|
|
/obj/item/camera/proc/createpicture(atom/target, mob/living/user, flag)
|
|
var/mobs = ""
|
|
var/list/turfs = list()
|
|
|
|
FOR_DVIEW(var/turf/T, size, target, INVISIBILITY_LIGHTING)
|
|
if (user.can_capture_turf(T))
|
|
mobs += get_mobs(T)
|
|
turfs += T
|
|
|
|
END_FOR_DVIEW
|
|
|
|
var/x_c = target.x - (size-1)/2
|
|
var/y_c = target.y - (size-1)/2
|
|
var/z_c = target.z
|
|
|
|
var/turf/topleft = locate(x_c, y_c, z_c)
|
|
if (!topleft)
|
|
return null
|
|
|
|
var/icon/photoimage = generate_image_from_turfs(topleft, turfs, size, CAPTURE_MODE_REGULAR, user)
|
|
|
|
var/icon/small_img = icon(photoimage)
|
|
var/icon/tiny_img = icon(photoimage)
|
|
var/icon/ic = icon('icons/obj/bureaucracy.dmi',"photo")
|
|
var/icon/pc = icon('icons/obj/bureaucracy.dmi', "photo")
|
|
small_img.Scale(8, 8)
|
|
tiny_img.Scale(4, 4)
|
|
ic.Blend(small_img,ICON_OVERLAY, 10, 13)
|
|
pc.Blend(tiny_img,ICON_OVERLAY, 12, 19)
|
|
|
|
var/obj/item/photo/p = new()
|
|
p.name = "photo"
|
|
p.icon = ic
|
|
p.tiny = pc
|
|
p.img = photoimage
|
|
if(black_white)
|
|
p.img.MapColors(rgb(77,77,77), rgb(150,150,150), rgb(28,28,28), rgb(0,0,0))
|
|
p.tiny.MapColors(rgb(77,77,77), rgb(150,150,150), rgb(28,28,28), rgb(0,0,0))
|
|
p.picture_desc = mobs
|
|
p.pixel_x = rand(-10, 10)
|
|
p.pixel_y = rand(-10, 10)
|
|
p.photo_size = size
|
|
|
|
return p
|
|
|
|
/obj/item/camera/proc/printpicture(mob/user, obj/item/photo/p)
|
|
p.forceMove(user.loc)
|
|
if(!user.get_inactive_hand())
|
|
user.put_in_inactive_hand(p)
|
|
|
|
/obj/item/photo/proc/copy(var/copy_id = 0)
|
|
var/obj/item/photo/p = new/obj/item/photo()
|
|
|
|
p.name = name
|
|
p.icon = icon(icon, icon_state)
|
|
p.tiny = icon(tiny)
|
|
p.img = icon(img)
|
|
p.picture_desc = picture_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
|
|
|
|
/obj/item/camera/adhomai
|
|
name = "adhomian camera"
|
|
icon = 'icons/obj/tajara_items.dmi'
|
|
desc = "A slightly antiquated camera with a large flash bulb. Still popular with Tajara all over Adhomai."
|
|
icon_state = "taj_camera_on"
|
|
item_state = "taj_camera"
|
|
slot_flags = SLOT_MASK
|
|
black_white = TRUE
|
|
icon_on = "taj_camera_on"
|
|
icon_off = "taj_camera_off"
|
|
|
|
/obj/item/camera/adhomai/do_photo_sound()
|
|
flick("taj_camera_flash", src)
|
|
playsound(loc, 'sound/items/camerabulb.ogg', 75, 1, -3)
|