diff --git a/_maps/map_files/Birdshot/birdshot.dmm b/_maps/map_files/Birdshot/birdshot.dmm index 7b7fd7a2eb3..dfdc0d2a761 100644 --- a/_maps/map_files/Birdshot/birdshot.dmm +++ b/_maps/map_files/Birdshot/birdshot.dmm @@ -21117,6 +21117,9 @@ /obj/machinery/door/window/left/directional/west{ name = "Reception Window" }, +/obj/structure/desk_bell{ + pixel_x = 7 + }, /turf/open/floor/iron/textured_large, /area/station/command/heads_quarters/hop) "hBA" = ( @@ -22368,20 +22371,9 @@ /turf/open/floor/iron/dark, /area/station/medical/medbay/aft) "ibq" = ( -/obj/structure/table/wood, -/obj/structure/desk_bell{ - pixel_x = 7 - }, -/obj/item/paper_bin{ - pixel_x = -4; - pixel_y = 4 - }, -/obj/item/pen{ - pixel_x = -4; - pixel_y = 3 - }, /obj/machinery/bluespace_vendor/directional/north, /obj/machinery/light/small/directional/west, +/obj/machinery/photobooth, /turf/open/floor/iron/textured_large, /area/station/hallway/primary/central/fore) "ibv" = ( @@ -26278,8 +26270,12 @@ }, /obj/machinery/button/flasher{ id = "hopflash"; - pixel_x = -23; - pixel_y = 11 + pixel_x = -24; + pixel_y = 6 + }, +/obj/machinery/button/photobooth{ + pixel_y = -6; + pixel_x = -24 }, /turf/open/floor/iron/dark/textured_corner, /area/station/command/heads_quarters/hop) @@ -39342,6 +39338,7 @@ dir = 4 }, /obj/effect/decal/cleanable/dirt, +/obj/effect/turf_decal/delivery, /turf/open/floor/iron/half, /area/station/hallway/primary/central/fore) "nZh" = ( @@ -65647,15 +65644,13 @@ /obj/effect/turf_decal/tile/dark_red/half/contrasted{ dir = 8 }, -/obj/structure/chair{ - pixel_y = -2 - }, /obj/machinery/computer/security/telescreen/interrogation{ dir = 8; name = "isolation room monitor"; network = list("isolation"); pixel_x = 30 }, +/obj/machinery/photobooth/security, /turf/open/floor/iron, /area/station/security/execution/transfer) "wvn" = ( diff --git a/_maps/map_files/Deltastation/DeltaStation2.dmm b/_maps/map_files/Deltastation/DeltaStation2.dmm index 56237c8fea2..d38200e7a71 100644 --- a/_maps/map_files/Deltastation/DeltaStation2.dmm +++ b/_maps/map_files/Deltastation/DeltaStation2.dmm @@ -19010,7 +19010,9 @@ /obj/effect/turf_decal/stripes/line{ dir = 8 }, -/obj/item/folder/blue, +/obj/structure/desk_bell{ + pixel_x = 7 + }, /turf/open/floor/iron, /area/station/command/heads_quarters/hop) "eIy" = ( @@ -49305,10 +49307,8 @@ req_access = list("kitchen") }, /obj/machinery/button/ticket_machine{ - pixel_y = 22 - }, -/obj/item/radio/intercom/directional/north{ - pixel_y = 30 + pixel_y = 22; + pixel_x = -6 }, /obj/machinery/button/door/directional/west{ id = "hopblast"; @@ -49323,6 +49323,10 @@ req_access = list("hop") }, /obj/effect/turf_decal/tile/neutral/fourcorners, +/obj/machinery/button/photobooth{ + pixel_y = 22; + pixel_x = 6 + }, /turf/open/floor/iron/dark, /area/station/command/heads_quarters/hop) "mlW" = ( @@ -59837,6 +59841,7 @@ /obj/structure/table/wood, /obj/item/papercutter, /obj/item/paper/fluff/ids_for_dummies, +/obj/item/radio/intercom/directional/east, /turf/open/floor/wood, /area/station/command/heads_quarters/hop) "paQ" = ( @@ -66038,11 +66043,9 @@ /turf/open/floor/iron, /area/station/engineering/main) "qyK" = ( -/obj/structure/table/reinforced, -/obj/item/paper_bin, -/obj/item/pen, /obj/machinery/light/small/directional/west, /obj/effect/turf_decal/tile/neutral/fourcorners, +/obj/machinery/photobooth/security, /turf/open/floor/iron/dark, /area/station/security/execution/transfer) "qyX" = ( @@ -67100,24 +67103,13 @@ /turf/open/floor/iron/dark, /area/station/security/courtroom) "qLa" = ( -/obj/structure/table, -/obj/item/paper_bin{ - pixel_x = -6; - pixel_y = 5 - }, -/obj/item/pen{ - pixel_x = -6; - pixel_y = 5 - }, /obj/machinery/flasher/directional/east{ id = "hopflash"; pixel_x = 0; pixel_y = 26 }, -/obj/structure/desk_bell{ - pixel_x = 7 - }, /obj/effect/turf_decal/tile/neutral/fourcorners, +/obj/machinery/photobooth, /turf/open/floor/iron/dark, /area/station/hallway/primary/central/fore) "qLg" = ( diff --git a/_maps/map_files/IceBoxStation/IceBoxStation.dmm b/_maps/map_files/IceBoxStation/IceBoxStation.dmm index 35700dbf5ea..00f1dbce54c 100644 --- a/_maps/map_files/IceBoxStation/IceBoxStation.dmm +++ b/_maps/map_files/IceBoxStation/IceBoxStation.dmm @@ -20624,6 +20624,10 @@ dir = 8 }, /obj/machinery/light/small/directional/west, +/obj/machinery/requests_console/directional/west, +/obj/effect/mapping_helpers/requests_console/assistance, +/obj/effect/mapping_helpers/requests_console/announcement, +/obj/effect/mapping_helpers/requests_console/information, /turf/open/floor/iron, /area/station/command/heads_quarters/hop) "gnL" = ( @@ -25917,7 +25921,6 @@ /turf/open/floor/plating/snowed/icemoon, /area/icemoon/underground/explored) "hYW" = ( -/obj/machinery/door/firedoor, /obj/effect/turf_decal/tile/red{ dir = 4 }, @@ -25980,11 +25983,12 @@ /turf/open/floor/iron, /area/station/cargo/storage) "iaS" = ( -/obj/machinery/modular_computer/preset/id, -/obj/item/paper/fluff/ids_for_dummies, /obj/effect/turf_decal/tile/blue/half/contrasted{ dir = 8 }, +/obj/structure/chair/office{ + dir = 8 + }, /turf/open/floor/iron, /area/station/command/heads_quarters/hop) "iaT" = ( @@ -59014,9 +59018,6 @@ /turf/open/floor/iron/dark/smooth_large, /area/station/security/processing) "rYk" = ( -/obj/structure/chair/office{ - dir = 8 - }, /obj/machinery/button/flasher{ id = "hopflash"; pixel_x = 8; @@ -59041,6 +59042,10 @@ /obj/effect/turf_decal/tile/blue/anticorner/contrasted{ dir = 8 }, +/obj/machinery/modular_computer/preset/id{ + dir = 1 + }, +/obj/item/paper/fluff/ids_for_dummies, /turf/open/floor/iron, /area/station/command/heads_quarters/hop) "rYq" = ( @@ -69573,13 +69578,9 @@ /turf/open/floor/iron, /area/station/security/courtroom) "vry" = ( -/obj/machinery/requests_console/directional/south{ - department = "Head of Personnel's Desk"; - name = "Head of Personnel's Requests Console" +/obj/machinery/button/photobooth{ + pixel_y = -26 }, -/obj/effect/mapping_helpers/requests_console/announcement, -/obj/effect/mapping_helpers/requests_console/information, -/obj/effect/mapping_helpers/requests_console/assistance, /turf/open/floor/iron, /area/station/command/heads_quarters/hop) "vrC" = ( @@ -70882,6 +70883,10 @@ /obj/machinery/holopad, /turf/open/floor/iron/kitchen/diagonal, /area/station/service/kitchen) +"vMz" = ( +/obj/machinery/photobooth, +/turf/open/floor/iron, +/area/station/hallway/primary/central) "vMA" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -75533,10 +75538,7 @@ req_access = list("brig"); specialfunctions = 4 }, -/obj/item/paper/crumpled{ - default_raw_text = "Remember! Corporate spent a lot of money to create this state of the art fashion show. If we EVER even so much as HEAR a rumor that a news crew or corporate rep is coming by, this place needs to be in TIP TOP condition. It's all of our asses (and our pensions) if it's not."; - name = "Crumpled Memo" - }, +/obj/machinery/photobooth/security, /turf/open/floor/iron/smooth, /area/station/security/execution/transfer) "xgg" = ( @@ -169937,10 +169939,10 @@ thA thA thA thA -xMq psb scw psb +iDt thA thA xMq @@ -170194,10 +170196,10 @@ thA thA thA iDt -iDt scw iDt scw +iDt thA thA thA @@ -170451,10 +170453,10 @@ thA thA iDt iDt -iDt psb scw psb +iDt thA thA thA @@ -235216,10 +235218,10 @@ qrJ uLC xzh dnq -dnq qcu bDR hYW +mpy bep ylU dnq @@ -235474,9 +235476,9 @@ nqU rcE rcE rcE -rcE hVc jII +jII dnq ylU dnq @@ -235731,8 +235733,8 @@ ydT iIA fSC iIA -iIA cvg +vMz jII okb ylU @@ -235988,8 +235990,8 @@ cpm cpm cpm egY -egY wwn +jfc cpm pzb cRF diff --git a/_maps/map_files/MetaStation/MetaStation.dmm b/_maps/map_files/MetaStation/MetaStation.dmm index 2192d36a613..053d7dc0cbc 100644 --- a/_maps/map_files/MetaStation/MetaStation.dmm +++ b/_maps/map_files/MetaStation/MetaStation.dmm @@ -561,12 +561,6 @@ /area/station/ai_monitored/turret_protected/ai_upload) "akT" = ( /obj/structure/table, -/obj/item/storage/box/bodybags{ - pixel_x = 4; - pixel_y = 2 - }, -/obj/item/pen, -/obj/item/storage/box/prisoner, /obj/effect/turf_decal/trimline/red/filled/line{ dir = 9 }, @@ -575,6 +569,10 @@ network = list("ss13","prison") }, /obj/machinery/light/directional/south, +/obj/item/storage/box/prisoner{ + pixel_y = 8 + }, +/obj/item/storage/box/prisoner, /turf/open/floor/iron, /area/station/security/execution/transfer) "akZ" = ( @@ -4111,12 +4109,29 @@ /area/station/maintenance/aft/lesser) "buw" = ( /obj/structure/table, -/obj/item/clothing/gloves/color/orange, -/obj/item/restraints/handcuffs, -/obj/item/reagent_containers/spray/pepper, /obj/effect/turf_decal/tile/red/half/contrasted{ dir = 4 }, +/obj/item/clothing/under/rank/prisoner{ + pixel_x = 8; + pixel_y = 5 + }, +/obj/item/clothing/shoes/sneakers/orange{ + pixel_x = -6; + pixel_y = 10 + }, +/obj/item/clothing/shoes/sneakers/orange{ + pixel_x = -6; + pixel_y = 4 + }, +/obj/item/clothing/shoes/sneakers/orange{ + pixel_x = -6; + pixel_y = -2 + }, +/obj/item/clothing/shoes/sneakers/orange{ + pixel_x = -6; + pixel_y = -8 + }, /turf/open/floor/iron, /area/station/security/execution/transfer) "buE" = ( @@ -23906,29 +23921,12 @@ "iJx" = ( /obj/structure/cable, /obj/structure/table, -/obj/item/clothing/shoes/sneakers/orange{ - pixel_x = -6; - pixel_y = 10 - }, -/obj/item/clothing/shoes/sneakers/orange{ - pixel_x = -6; - pixel_y = -2 - }, -/obj/item/clothing/shoes/sneakers/orange{ - pixel_x = -6; - pixel_y = 4 - }, -/obj/item/clothing/shoes/sneakers/orange{ - pixel_x = -6; - pixel_y = -8 - }, -/obj/item/clothing/under/rank/prisoner{ - pixel_x = 8; - pixel_y = 5 - }, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/effect/turf_decal/tile/red/anticorner/contrasted, +/obj/item/clothing/gloves/color/orange, +/obj/item/restraints/handcuffs, +/obj/item/reagent_containers/spray/pepper, /turf/open/floor/iron, /area/station/security/execution/transfer) "iJC" = ( @@ -30248,14 +30246,22 @@ /turf/open/floor/iron, /area/station/hallway/primary/central) "kQz" = ( -/obj/structure/table, -/obj/item/storage/box/prisoner{ - pixel_y = 8 - }, -/obj/item/storage/box/prisoner, /obj/effect/turf_decal/tile/red/half/contrasted{ dir = 4 }, +/obj/structure/table, +/obj/item/clothing/under/rank/prisoner/skirt{ + pixel_x = 9; + pixel_y = 5 + }, +/obj/item/clothing/under/rank/prisoner{ + pixel_x = -2; + pixel_y = 5 + }, +/obj/item/clothing/under/rank/prisoner/skirt{ + pixel_x = -13; + pixel_y = 5 + }, /turf/open/floor/iron, /area/station/security/execution/transfer) "kQP" = ( @@ -44736,7 +44742,7 @@ "qaN" = ( /obj/structure/table/wood, /obj/machinery/button/ticket_machine{ - pixel_x = 32 + pixel_x = 38 }, /obj/machinery/light_switch/directional/south{ pixel_x = 6; @@ -44763,6 +44769,13 @@ pixel_y = -34; req_access = list("hop") }, +/obj/item/pen{ + pixel_x = -4; + pixel_y = 3 + }, +/obj/machinery/button/photobooth{ + pixel_x = 26 + }, /turf/open/floor/wood, /area/station/command/heads_quarters/hop) "qaP" = ( @@ -55075,6 +55088,9 @@ name = "Privacy Shutters" }, /obj/structure/cable, +/obj/structure/desk_bell{ + pixel_x = 7 + }, /turf/open/floor/iron, /area/station/command/heads_quarters/hop) "tIx" = ( @@ -57418,20 +57434,9 @@ /turf/open/floor/iron, /area/station/engineering/break_room) "uwC" = ( -/obj/structure/table, -/obj/item/paper_bin{ - pixel_x = -4; - pixel_y = 4 - }, -/obj/item/pen{ - pixel_x = -4; - pixel_y = 3 - }, /obj/effect/turf_decal/delivery, /obj/machinery/bluespace_vendor/directional/east, -/obj/structure/desk_bell{ - pixel_x = 7 - }, +/obj/machinery/photobooth, /turf/open/floor/iron, /area/station/hallway/secondary/command) "uwK" = ( @@ -57909,25 +57914,13 @@ /turf/open/floor/iron, /area/station/engineering/break_room) "uFK" = ( -/obj/structure/table, -/obj/item/clothing/under/rank/prisoner/skirt{ - pixel_x = -13; - pixel_y = 5 - }, -/obj/item/clothing/under/rank/prisoner/skirt{ - pixel_x = 9; - pixel_y = 5 - }, -/obj/item/clothing/under/rank/prisoner{ - pixel_x = -2; - pixel_y = 5 - }, /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/effect/turf_decal/tile/red/anticorner/contrasted{ dir = 8 }, +/obj/machinery/photobooth/security, /turf/open/floor/iron, /area/station/security/execution/transfer) "uFQ" = ( diff --git a/_maps/map_files/NorthStar/north_star.dmm b/_maps/map_files/NorthStar/north_star.dmm index 9af6d5baf06..16d9d96dec3 100644 --- a/_maps/map_files/NorthStar/north_star.dmm +++ b/_maps/map_files/NorthStar/north_star.dmm @@ -14966,9 +14966,8 @@ /turf/open/floor/engine, /area/station/maintenance/floor1/port/aft) "dNU" = ( -/obj/structure/table, -/obj/item/paper_bin, -/obj/item/pen, +/obj/machinery/photobooth, +/obj/effect/turf_decal/delivery, /turf/open/floor/iron/dark, /area/station/hallway/floor4/fore) "dOa" = ( @@ -54431,6 +54430,14 @@ }, /turf/open/floor/iron/dark, /area/station/service/hydroponics) +"nVN" = ( +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/effect/turf_decal/tile/red/diagonal_edge, +/obj/structure/cable, +/obj/machinery/photobooth/security, +/turf/open/floor/iron/dark, +/area/station/security/prison/visit) "nVP" = ( /obj/structure/cable/multilayer/multiz, /turf/open/floor/plating, @@ -78876,7 +78883,8 @@ "uqF" = ( /obj/structure/table, /obj/machinery/button/ticket_machine{ - pixel_x = -32 + pixel_x = -24; + pixel_y = -6 }, /obj/item/stamp/head/hop{ pixel_x = 8; @@ -78886,6 +78894,10 @@ pixel_x = -4; pixel_y = 3 }, +/obj/machinery/button/photobooth{ + pixel_y = 6; + pixel_x = -24 + }, /turf/open/floor/iron/dark, /area/station/command/heads_quarters/hop) "uqT" = ( @@ -326677,7 +326689,7 @@ gDx iIb ftZ tBk -qTA +nVN wKi akt rbr diff --git a/_maps/map_files/tramstation/tramstation.dmm b/_maps/map_files/tramstation/tramstation.dmm index 03f46d2d840..cac4e19df12 100644 --- a/_maps/map_files/tramstation/tramstation.dmm +++ b/_maps/map_files/tramstation/tramstation.dmm @@ -604,6 +604,7 @@ /obj/effect/turf_decal/trimline/red/filled/line{ dir = 4 }, +/obj/machinery/photobooth/security, /turf/open/floor/iron, /area/station/security/execution/transfer) "acj" = ( @@ -38858,6 +38859,7 @@ /area/station/command/heads_quarters/hop) "mHZ" = ( /obj/item/radio/intercom/directional/east, +/obj/machinery/photobooth, /turf/open/floor/iron/grimy, /area/station/service/library/lounge) "mId" = ( diff --git a/code/controllers/subsystem/ticker.dm b/code/controllers/subsystem/ticker.dm index e3d9be937e2..45085c0a6f8 100644 --- a/code/controllers/subsystem/ticker.dm +++ b/code/controllers/subsystem/ticker.dm @@ -464,8 +464,7 @@ SUBSYSTEM_DEF(ticker) /datum/controller/subsystem/ticker/proc/transfer_characters() var/list/livings = list() - for(var/i in GLOB.new_player_list) - var/mob/dead/new_player/player = i + for(var/mob/dead/new_player/player as anything in GLOB.new_player_list) var/mob/living = player.transfer_character() if(living) qdel(player) diff --git a/code/datums/records/manifest.dm b/code/datums/records/manifest.dm index 146f0b85845..fc2bb30ce8d 100644 --- a/code/datums/records/manifest.dm +++ b/code/datums/records/manifest.dm @@ -154,8 +154,6 @@ GLOBAL_DATUM_INIT(manifest, /datum/manifest, new) quirk_notes = person.get_quirk_string(TRUE, CAT_QUIRK_NOTES), ) - return - /// Edits the rank and trim of the found record. /datum/manifest/proc/modify(name, assignment, trim) var/datum/record/crew/target = find_record(name) @@ -165,6 +163,22 @@ GLOBAL_DATUM_INIT(manifest, /datum/manifest, new) target.rank = assignment target.trim = trim +/** + * Using the name to find the record, and person in reference to the body, we recreate photos for the manifest (and records). + * Args: + * - name - The name of the record we're looking for, which should be the name of the person. + * - person - The mob we're taking pictures of to update the records. + * - add_height_chart - If we should add a height chart to the background of the photo. + */ +/datum/manifest/proc/change_pictures(name, mob/living/person, add_height_chart = FALSE) + var/datum/record/crew/target = find_record(name) + if(!target) + return FALSE + + target.character_appearance = new(person.appearance) + target.recreate_manifest_photos(add_height_chart) + return TRUE + /datum/manifest/ui_state(mob/user) return GLOB.always_state diff --git a/code/datums/records/record.dm b/code/datums/records/record.dm index 167f227fc3a..4c40a85d5fc 100644 --- a/code/datums/records/record.dm +++ b/code/datums/records/record.dm @@ -84,6 +84,9 @@ /// Current arrest status var/wanted_status = WANTED_NONE + ///Photo used for records, which we store here so we don't have to constantly make more of. + var/list/obj/item/photo/record_photos + /datum/record/crew/New( age = 18, blood_type = "?", @@ -120,6 +123,7 @@ /datum/record/crew/Destroy() GLOB.manifest.general -= src + QDEL_LAZYLIST(record_photos) return ..() /** @@ -170,6 +174,20 @@ /datum/record/crew/proc/get_side_photo() return get_photo("photo_side", WEST) +/// A helper proc to recreate all photos of a character from the record. +/datum/record/crew/proc/recreate_manifest_photos(add_height_chart) + delete_photos("photo_front") + make_photo("photo_front", SOUTH, add_height_chart) + delete_photos("photo_side") + make_photo("photo_side", WEST, add_height_chart) + +///Deletes the existing photo for field_name +/datum/record/crew/proc/delete_photos(field_name) + var/obj/item/photo/existing_photo = LAZYACCESS(record_photos, field_name) + if(existing_photo) + qdel(existing_photo) + LAZYREMOVE(record_photos, field_name) + /** * You shouldn't be calling this directly, use `get_front_photo()` or `get_side_photo()` * instead. @@ -188,18 +206,29 @@ * Returns an empty `/icon` if there was no `character_appearance` entry in the `fields` list, * returns the generated/cached photo otherwise. */ -/datum/record/crew/proc/get_photo(field_name, orientation) +/datum/record/crew/proc/get_photo(field_name, orientation = SOUTH) if(!field_name) return - if(!character_appearance) return new /icon() + var/obj/item/photo/existing_photo = LAZYACCESS(record_photos, field_name) + if(!existing_photo) + existing_photo = make_photo(field_name, orientation) + return existing_photo +/** + * make_photo + * + * Called if the person doesn't already have a photo, this will make a photo of the person, + * then make a picture out of it, then finally create a new photo. + */ +/datum/record/crew/proc/make_photo(field_name, orientation, add_height_chart) var/icon/picture_image if(!isicon(character_appearance)) var/mutable_appearance/appearance = character_appearance appearance.setDir(orientation) - + if(add_height_chart) + appearance.underlays += mutable_appearance('icons/obj/machines/photobooth.dmi', "height_chart", alpha = 125, appearance_flags = RESET_ALPHA|RESET_COLOR|RESET_TRANSFORM) picture_image = getFlatIcon(appearance) else picture_image = character_appearance @@ -209,9 +238,10 @@ picture.picture_desc = "This is [name]." picture.picture_image = picture_image - var/obj/item/photo/photo = new(null, picture) - field_name = photo - return photo + var/obj/item/photo/new_photo = new(null, picture) + + LAZYSET(record_photos, field_name, new_photo) + return new_photo /// Returns a paper printout of the current record's crime data. /datum/record/crew/proc/get_rapsheet(alias, header = "Rapsheet", description = "No further details.") diff --git a/code/game/machinery/buttons.dm b/code/game/machinery/buttons.dm index 552afbb4ed8..32e56e2fca9 100644 --- a/code/game/machinery/buttons.dm +++ b/code/game/machinery/buttons.dm @@ -4,17 +4,7 @@ icon = 'icons/obj/machines/wallmounts.dmi' base_icon_state = "button" icon_state = "button" - ///Icon suffix for the skin of the front pannel that is added to base_icon_state - var/skin = "" - ///Whether it is possible to change the panel skin - var/can_alter_skin = TRUE power_channel = AREA_USAGE_ENVIRON - var/obj/item/assembly/device - var/obj/item/electronics/airlock/board - var/device_type = null - var/id = null - var/initialized_button = 0 - var/silicon_access_disabled = FALSE light_power = 0.5 // Minimums, we want the button to glow if it has a mask, not light an area light_range = 1.5 light_color = LIGHT_COLOR_VIVID_GREEN @@ -22,6 +12,17 @@ idle_power_usage = BASE_MACHINE_IDLE_CONSUMPTION * 0.02 resistance_flags = LAVA_PROOF | FIRE_PROOF interaction_flags_machine = parent_type::interaction_flags_machine | INTERACT_MACHINE_OPEN + ///Icon suffix for the skin of the front pannel that is added to base_icon_state + var/skin = "" + ///Whether it is possible to change the panel skin + var/can_alter_skin = TRUE + + var/obj/item/assembly/device + var/obj/item/electronics/airlock/board + var/device_type = null + var/id = null + var/initialized_button = 0 + var/silicon_access_disabled = FALSE /obj/machinery/button/indestructible resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF diff --git a/code/game/machinery/computer/records/records.dm b/code/game/machinery/computer/records/records.dm index c3aba60e4c6..f0b360ff1c8 100644 --- a/code/game/machinery/computer/records/records.dm +++ b/code/game/machinery/computer/records/records.dm @@ -28,6 +28,7 @@ . = ..() if(.) return + var/mob/user = ui.user var/datum/record/crew/target if(params["crew_ref"]) @@ -41,7 +42,7 @@ return FALSE var/value = trim(params["value"], MAX_BROADCAST_LEN) - investigate_log("[key_name(usr)] changed the field: \"[field]\" with value: \"[target.vars[field]]\" to new value: \"[value || "Unknown"]\"", INVESTIGATE_RECORDS) + investigate_log("[key_name(user)] changed the field: \"[field]\" with value: \"[target.vars[field]]\" to new value: \"[value || "Unknown"]\"", INVESTIGATE_RECORDS) target.vars[field] = value || "Unknown" return TRUE @@ -51,23 +52,23 @@ return FALSE // Don't let people off station futz with the station network. if(!is_station_level(z)) - balloon_alert(usr, "out of range!") + balloon_alert(user, "out of range!") return TRUE expunge_record_info(target) - balloon_alert(usr, "record expunged") + balloon_alert(user, "record expunged") playsound(src, 'sound/machines/terminal_eject.ogg', 70, TRUE) - investigate_log("[key_name(usr)] expunged the record of [target.name].", INVESTIGATE_RECORDS) + investigate_log("[key_name(user)] expunged the record of [target.name].", INVESTIGATE_RECORDS) return TRUE if("login") - authenticated = secure_login(usr) - investigate_log("[key_name(usr)] [authenticated ? "successfully logged" : "failed to log"] into the [src].", INVESTIGATE_RECORDS) + authenticated = secure_login(user) + investigate_log("[key_name(user)] [authenticated ? "successfully logged" : "failed to log"] into the [src].", INVESTIGATE_RECORDS) return TRUE if("logout") - balloon_alert(usr, "logged out") + balloon_alert(user, "logged out") playsound(src, 'sound/machines/terminal_off.ogg', 70, TRUE) authenticated = FALSE @@ -76,22 +77,22 @@ if("purge_records") // Don't let people off station futz with the station network. if(!is_station_level(z)) - balloon_alert(usr, "out of range!") + balloon_alert(user, "out of range!") return TRUE ui.close() - balloon_alert(usr, "purging records...") + balloon_alert(user, "purging records...") playsound(src, 'sound/machines/terminal_alert.ogg', 70, TRUE) - if(do_after(usr, 5 SECONDS)) + if(do_after(user, 5 SECONDS)) for(var/datum/record/crew/entry in GLOB.manifest.general) expunge_record_info(entry) - balloon_alert(usr, "records purged") + balloon_alert(user, "records purged") playsound(src, 'sound/machines/terminal_off.ogg', 70, TRUE) - investigate_log("[key_name(usr)] purged all records.", INVESTIGATE_RECORDS) + investigate_log("[key_name(user)] purged all records.", INVESTIGATE_RECORDS) else - balloon_alert(usr, "interrupted!") + balloon_alert(user, "interrupted!") return TRUE @@ -100,7 +101,7 @@ return FALSE playsound(src, "sound/machines/terminal_button0[rand(1, 8)].ogg", 50, TRUE) - update_preview(usr, params["assigned_view"], target) + update_preview(user, params["assigned_view"], target) return TRUE return FALSE diff --git a/code/game/machinery/computer/records/security.dm b/code/game/machinery/computer/records/security.dm index 6e44d112b4b..0797b4d1890 100644 --- a/code/game/machinery/computer/records/security.dm +++ b/code/game/machinery/computer/records/security.dm @@ -147,6 +147,8 @@ if(.) return + var/mob/user = ui.user + var/datum/record/crew/target if(params["crew_ref"]) target = locate(params["crew_ref"]) in GLOB.manifest.general @@ -155,29 +157,29 @@ switch(action) if("add_crime") - add_crime(usr, target, params) + add_crime(user, target, params) return TRUE if("delete_record") - investigate_log("[usr] deleted record: \"[target]\".", INVESTIGATE_RECORDS) + investigate_log("[user] deleted record: \"[target]\".", INVESTIGATE_RECORDS) qdel(target) return TRUE if("edit_crime") - edit_crime(usr, target, params) + edit_crime(user, target, params) return TRUE if("invalidate_crime") - invalidate_crime(usr, target, params) + invalidate_crime(user, target, params) return TRUE if("print_record") - print_record(usr, target, params) + print_record(user, target, params) return TRUE if("set_note") var/note = trim(params["note"], MAX_MESSAGE_LEN) - investigate_log("[usr] has changed the security note of record: \"[target]\" from \"[target.security_note]\" to \"[note]\".") + investigate_log("[user] has changed the security note of record: \"[target]\" from \"[target.security_note]\" to \"[note]\".") target.security_note = note return TRUE @@ -318,7 +320,7 @@ /// Handles printing records via UI. Takes the params from UI_act. /obj/machinery/computer/records/security/proc/print_record(mob/user, datum/record/crew/target, list/params) if(printing) - balloon_alert(usr, "printer busy") + balloon_alert(user, "printer busy") playsound(src, 'sound/machines/terminal_error.ogg', 100, TRUE) return FALSE diff --git a/code/game/machinery/photobooth.dm b/code/game/machinery/photobooth.dm new file mode 100644 index 00000000000..d7775974269 --- /dev/null +++ b/code/game/machinery/photobooth.dm @@ -0,0 +1,228 @@ +/** + * Photobooth + * A machine used to change occupant's security record photos, working similarly to a + * camera, but doesn't give any physical photo to the user. + * Links to buttons for remote control. + */ +/obj/machinery/photobooth + name = "photobooth" + desc = "A machine with some drapes and a camera, used to update security record photos. Requires Law Office access to use." + icon = 'icons/obj/machines/photobooth.dmi' + icon_state = "booth_open" + base_icon_state = "booth" + state_open = TRUE + circuit = /obj/item/circuitboard/machine/photobooth + light_system = OVERLAY_LIGHT_DIRECTIONAL //Used as a flash here. + light_range = 6 + light_color = COLOR_WHITE + light_power = FLASH_LIGHT_POWER + light_on = FALSE + interaction_flags_atom = INTERACT_ATOM_ATTACK_HAND + req_one_access = list(ACCESS_LAWYER, ACCESS_SECURITY) + ///Boolean on whether we should add a height chart to the underlays of the people we take photos of. + var/add_height_chart = FALSE + ///Boolean on whether the machine is currently busy taking someone's pictures, so you can't start taking pictures while it's working. + var/taking_pictures = FALSE + ///The ID of the photobooth, used to connect it to a button. + var/button_id = "photobooth_machine_default" + +/** + * Security photobooth + * Adds a height chart in the background, used for people you want to evidently stick out as prisoners. + * Good for people you plan on putting in the permabrig. + */ +/obj/machinery/photobooth/security + name = "security photobooth" + desc = "A machine with some drapes and a camera, used to update security record photos. Requires Security access to use, and adds a height chart to the person." + circuit = /obj/item/circuitboard/machine/photobooth/security + req_one_access = list(ACCESS_SECURITY) + color = COLOR_LIGHT_GRAYISH_RED + add_height_chart = TRUE + +/obj/machinery/photobooth/Initialize(mapload) + . = ..() + register_context() + +/obj/machinery/photobooth/interact(mob/living/user, list/modifiers) + . = ..() + if(taking_pictures) + balloon_alert(user, "machine busy!") + return + if(state_open) + close_machine() + else + open_machine() + +/obj/machinery/photobooth/attack_hand_secondary(mob/user, list/modifiers) + if(taking_pictures) + balloon_alert(user, "machine busy!") + return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN + if(occupant) + if(allowed(user)) + start_taking_pictures() + else + balloon_alert(user, "access denied!") + return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN + return ..() + +/obj/machinery/photobooth/add_context(atom/source, list/context, obj/item/held_item, mob/user) + if(machine_stat & (BROKEN|NOPOWER) || !isnull(held_item)) + return NONE + + context[SCREENTIP_CONTEXT_LMB] = "[state_open ? "Close" : "Open"] Machine" + if(occupant) + context[SCREENTIP_CONTEXT_RMB] = "Take Pictures" + + return CONTEXTUAL_SCREENTIP_SET + +/obj/machinery/photobooth/close_machine(mob/user, density_to_set = TRUE) + if(panel_open) + balloon_alert(user, "close panel first!") + return + playsound(src, 'sound/effects/curtain.ogg', 50, TRUE) + return ..() + +/obj/machinery/photobooth/open_machine(drop = TRUE, density_to_set = FALSE) + playsound(src, 'sound/effects/curtain.ogg', 50, TRUE) + return ..() + +/obj/machinery/photobooth/update_icon_state() + . = ..() + if(machine_stat & (BROKEN|NOPOWER)) + icon_state = "[base_icon_state]_off" + else if(state_open) + icon_state = "[base_icon_state]_open" + else + icon_state = "[base_icon_state]_closed" + +/obj/machinery/photobooth/update_overlays() + . = ..() + if((machine_stat & MAINT) || panel_open) + . += "[base_icon_state]_panel" + +/obj/machinery/photobooth/screwdriver_act(mob/living/user, obj/item/tool) + if(!has_buckled_mobs() && default_deconstruction_screwdriver(user, icon_state, icon_state, tool)) + update_appearance(UPDATE_ICON) + return ITEM_INTERACT_SUCCESS + return ..() + +/obj/machinery/photobooth/crowbar_act(mob/living/user, obj/item/tool) + if(default_deconstruction_crowbar(tool)) + return ITEM_INTERACT_SUCCESS + return ..() + +/obj/machinery/photobooth/emag_act(mob/user, obj/item/card/emag/emag_card) + if(obj_flags & EMAGGED) + return FALSE + req_access = list() //in case someone sets this to something + req_one_access = list() + balloon_alert(user, "beeps softly") + obj_flags |= EMAGGED + return TRUE + +/** + * Handles the effects of taking pictures of the user, calling finish_taking_pictures + * to actually update the records. + */ +/obj/machinery/photobooth/proc/start_taking_pictures() + taking_pictures = TRUE + if(obj_flags & EMAGGED) + var/mob/living/carbon/carbon_occupant = occupant + for(var/i in 1 to 5) //play a ton of sounds to mimic it blinding you + playsound(src, pick('sound/items/polaroid1.ogg', 'sound/items/polaroid2.ogg'), 75, TRUE) + if(carbon_occupant) + carbon_occupant.flash_act(5) + sleep(0.2 SECONDS) + if(carbon_occupant) + carbon_occupant.emote("scream") + finish_taking_pictures() + return + if(!do_after(occupant, 2 SECONDS, src, timed_action_flags = IGNORE_HELD_ITEM)) //gives them time to put their hand items away. + taking_pictures = FALSE + return + playsound(src, 'sound/items/polaroid1.ogg', 75, TRUE) + flash() + if(!do_after(occupant, 3 SECONDS, src, timed_action_flags = IGNORE_HELD_ITEM)) + taking_pictures = FALSE + return + playsound(src, 'sound/items/polaroid2.ogg', 75, TRUE) + flash() + if(!do_after(occupant, 2 SECONDS, src, timed_action_flags = IGNORE_HELD_ITEM)) + taking_pictures = FALSE + return + finish_taking_pictures() + +///Updates the records (if possible), giving feedback, and spitting the user out if all's well. +/obj/machinery/photobooth/proc/finish_taking_pictures() + taking_pictures = FALSE + if(!GLOB.manifest.change_pictures(occupant.name, occupant, add_height_chart = add_height_chart)) + balloon_alert(occupant, "record not found!") + return + balloon_alert(occupant, "records updated") + open_machine() + +///Mimicing the camera, gives a flash effect by turning the light on and calling flash_end. +/obj/machinery/photobooth/proc/flash() + set_light_on(TRUE) + addtimer(CALLBACK(src, PROC_REF(flash_end)), FLASH_LIGHT_DURATION, TIMER_OVERRIDE|TIMER_UNIQUE) + +///Called by a timer to turn the light off to end the flash effect. +/obj/machinery/photobooth/proc/flash_end() + set_light_on(FALSE) + + +/obj/machinery/button/photobooth + name = "photobooth control button" + desc = "Operates the photobooth from a distance, allowing people to update their security record photos." + device_type = /obj/item/assembly/control/photobooth_control + req_one_access = list(ACCESS_SECURITY, ACCESS_LAWYER) + id = "photobooth_machine_default" + +/obj/machinery/button/photobooth/Initialize(mapload) + . = ..() + if(device) + var/obj/item/assembly/control/photobooth_control/ours = device + ours.id = id + +/obj/machinery/button/photobooth/multitool_act(mob/living/user, obj/item/multitool/tool) + . = ..() + if(tool.buffer && !istype(tool.buffer, /obj/machinery/photobooth)) + return + var/obj/item/assembly/control/photobooth_control/controller = device + controller.booth_machine_ref = WEAKREF(tool.buffer) + id = null + controller.id = null + balloon_alert(user, "linked to [tool.buffer]") + +/obj/item/assembly/control/photobooth_control + name = "photobooth controller" + desc = "A remote controller for the HoP's photobooth." + ///Weakref to the photobooth we're connected to. + var/datum/weakref/booth_machine_ref + +/obj/item/assembly/control/photobooth_control/Initialize(mapload) + ..() + return INITIALIZE_HINT_LATELOAD + +/obj/item/assembly/control/photobooth_control/LateInitialize() + find_machine() + +/// Locate the photobooth we're linked via ID +/obj/item/assembly/control/photobooth_control/proc/find_machine() + for(var/obj/machinery/photobooth/booth as anything in SSmachines.get_machines_by_type_and_subtypes(/obj/machinery/photobooth)) + if(booth.button_id == id) + booth_machine_ref = WEAKREF(booth) + if(booth_machine_ref) + return TRUE + return FALSE + +/obj/item/assembly/control/photobooth_control/activate(mob/activator) + if(!booth_machine_ref) + return + var/obj/machinery/photobooth/machine = booth_machine_ref.resolve() + if(!machine) + return + if(machine.taking_pictures) + balloon_alert(activator, "machine busy!") + return + machine.start_taking_pictures() diff --git a/code/game/objects/items/circuitboards/machines/machine_circuitboards.dm b/code/game/objects/items/circuitboards/machines/machine_circuitboards.dm index 2be7daca2bd..addfbc233ef 100644 --- a/code/game/objects/items/circuitboards/machines/machine_circuitboards.dm +++ b/code/game/objects/items/circuitboards/machines/machine_circuitboards.dm @@ -79,7 +79,6 @@ req_components = list(/datum/stock_part/capacitor = 1) needs_anchored = FALSE - /obj/item/circuitboard/machine/telecomms/broadcaster name = "Subspace Broadcaster" greyscale_colors = CIRCUIT_COLOR_ENGINEERING @@ -1113,6 +1112,19 @@ build_path = /obj/machinery/rnd/production/techfab/department/security //Service +/obj/item/circuitboard/machine/photobooth + name = "Photobooth" + greyscale_colors = CIRCUIT_COLOR_SERVICE + build_path = /obj/machinery/photobooth + req_components = list( + /datum/stock_part/matter_bin = 1, + /datum/stock_part/servo = 1, + ) + +/obj/item/circuitboard/machine/photobooth/security + name = "Security Photobooth" + greyscale_colors = CIRCUIT_COLOR_SECURITY + build_path = /obj/machinery/photobooth/security /obj/item/circuitboard/machine/biogenerator name = "Biogenerator" diff --git a/code/modules/jobs/access.dm b/code/modules/jobs/access.dm index 859f83bf35a..2055080710e 100644 --- a/code/modules/jobs/access.dm +++ b/code/modules/jobs/access.dm @@ -32,7 +32,7 @@ else if(SEND_SIGNAL(accessor, COMSIG_MOB_TRIED_ACCESS, src) & ACCESS_ALLOWED) return TRUE //If the mob is holding a valid ID, we let them in. get_active_held_item() is on the mob level, so no need to copypasta everywhere. - else if(check_access(accessor.get_active_held_item())) + else if(check_access(accessor.get_active_held_item()) || check_access(accessor.get_inactive_held_item())) return TRUE else if(ishuman(accessor)) var/mob/living/carbon/human/human_accessor = accessor diff --git a/code/modules/jobs/job_types/prisoner.dm b/code/modules/jobs/job_types/prisoner.dm index 28b697a794f..fd6f0f939d6 100644 --- a/code/modules/jobs/job_types/prisoner.dm +++ b/code/modules/jobs/job_types/prisoner.dm @@ -27,23 +27,25 @@ /datum/job/prisoner/New() . = ..() - RegisterSignal(SSdcs, COMSIG_GLOB_CREWMEMBER_JOINED, PROC_REF(add_pref_crime)) + RegisterSignal(SSdcs, COMSIG_GLOB_CREWMEMBER_JOINED, PROC_REF(handle_prisoner_joining)) -/datum/job/prisoner/proc/add_pref_crime(datum/source, mob/living/crewmember, rank) +/datum/job/prisoner/proc/handle_prisoner_joining(datum/source, mob/living/crewmember, rank) SIGNAL_HANDLER if(rank != title) return //not a prisoner var/crime_name = crewmember.client?.prefs?.read_preference(/datum/preference/choiced/prisoner_crime) if(!crime_name) - return - if(crime_name == "Random") + stack_trace("[crewmember] joined as a Prisoner without having a prisoner crime set.") + crime_name = pick(assoc_to_keys(GLOB.prisoner_crimes)) + else if(crime_name == "Random") crime_name = pick(assoc_to_keys(GLOB.prisoner_crimes)) var/datum/prisoner_crime/crime = GLOB.prisoner_crimes[crime_name] - var/datum/record/crew/target_record = find_record(crewmember.real_name) var/datum/crime/past_crime = new(crime.name, crime.desc, "Central Command", "Indefinite.") + var/datum/record/crew/target_record = find_record(crewmember.real_name) target_record.crimes += past_crime + target_record.recreate_manifest_photos(add_height_chart = TRUE) to_chat(crewmember, span_warning("You are imprisoned for \"[crime_name]\".")) crewmember.add_mob_memory(/datum/memory/key/permabrig_crimes, crimes = crime_name) diff --git a/code/modules/mob/inventory.dm b/code/modules/mob/inventory.dm index 15f45694c29..bc44e651868 100644 --- a/code/modules/mob/inventory.dm +++ b/code/modules/mob/inventory.dm @@ -1,4 +1,4 @@ -//These procs handle putting s tuff in your hands +//These procs handle putting stuff in your hands //as they handle all relevant stuff like adding it to the player's screen and updating their overlays. ///Returns the thing we're currently holding diff --git a/code/modules/research/designs/machine_designs.dm b/code/modules/research/designs/machine_designs.dm index a73b4459333..65dd75142a2 100644 --- a/code/modules/research/designs/machine_designs.dm +++ b/code/modules/research/designs/machine_designs.dm @@ -318,6 +318,26 @@ ) departmental_flags = DEPARTMENT_BITFLAG_SECURITY +/datum/design/board/photobooth + name = "Photobooth Board" + desc = "The circuit board for a photobooth." + id = "photobooth" + build_path = /obj/item/circuitboard/machine/photobooth + category = list( + RND_CATEGORY_MACHINE + RND_SUBCATEGORY_MACHINE_SERVICE + ) + departmental_flags = DEPARTMENT_BITFLAG_SERVICE + +/datum/design/board/security_photobooth + name = "Security Photobooth Board" + desc = "The circuit board for a security photobooth." + id = "security_photobooth" + build_path = /obj/item/circuitboard/machine/photobooth/security + category = list( + RND_CATEGORY_MACHINE + RND_SUBCATEGORY_MACHINE_SECURITY + ) + departmental_flags = DEPARTMENT_BITFLAG_SECURITY + /datum/design/board/biogenerator name = "Biogenerator Board" desc = "The circuit board for a biogenerator." diff --git a/code/modules/research/techweb/all_nodes.dm b/code/modules/research/techweb/all_nodes.dm index 76e5085c525..8e0fdc95a74 100644 --- a/code/modules/research/techweb/all_nodes.dm +++ b/code/modules/research/techweb/all_nodes.dm @@ -1204,8 +1204,10 @@ "idcard", "libraryconsole", "mining", + "photobooth", "rdcamera", "seccamera", + "security_photobooth", ) research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2000) diff --git a/icons/obj/machines/photobooth.dmi b/icons/obj/machines/photobooth.dmi new file mode 100644 index 00000000000..c4e812bdf47 Binary files /dev/null and b/icons/obj/machines/photobooth.dmi differ diff --git a/tgstation.dme b/tgstation.dme index 8552083073a..0bb4356e926 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -1977,6 +1977,7 @@ #include "code\game\machinery\navbeacon.dm" #include "code\game\machinery\nebula_shielding.dm" #include "code\game\machinery\PDApainter.dm" +#include "code\game\machinery\photobooth.dm" #include "code\game\machinery\prisongate.dm" #include "code\game\machinery\prisonlabor.dm" #include "code\game\machinery\quantum_pad.dm"