From 5342a3058e0fad449e7b70210a49c22ea535f1ff Mon Sep 17 00:00:00 2001 From: MrMelbert Date: Sun, 21 Jun 2026 23:24:39 -0500 Subject: [PATCH 01/10] Postround stuff --- _maps/map_files/OmegaStation/OmegaStation.dmm | 402 +++++++++++++----- code/datums/elements/rust.dm | 8 +- code/datums/mood.dm | 13 +- .../effects/decals/cleanable/humans.dm | 7 + code/modules/clothing/masks/bandana.dm | 17 +- code/modules/forensics/forensics_helpers.dm | 2 +- .../code/modules/mob/living/blood.dm | 16 +- .../human/species_types/synth/android.dm | 8 +- 8 files changed, 330 insertions(+), 143 deletions(-) diff --git a/_maps/map_files/OmegaStation/OmegaStation.dmm b/_maps/map_files/OmegaStation/OmegaStation.dmm index 6964f67be16d..77730ecad780 100644 --- a/_maps/map_files/OmegaStation/OmegaStation.dmm +++ b/_maps/map_files/OmegaStation/OmegaStation.dmm @@ -576,6 +576,7 @@ dir = 2 }, /obj/machinery/meter/layer4, +/obj/structure/cable, /turf/open/floor/plating, /area/station/maintenance/solars/port/fore) "abU" = ( @@ -2288,11 +2289,18 @@ /area/station/command/heads_quarters/hop) "agr" = ( /obj/structure/table/wood, -/obj/item/paper_bin, +/obj/item/paper_bin{ + pixel_y = 2; + pixel_x = 2 + }, /obj/item/pen, /obj/item/stamp/head/hop, /obj/effect/mapping_helpers/broken_floor, /obj/structure/cable, +/obj/item/ashtray{ + pixel_y = -5; + pixel_x = -8 + }, /turf/open/floor/wood, /area/station/command/heads_quarters/hop) "ags" = ( @@ -2492,6 +2500,10 @@ /obj/item/folder/blue, /obj/item/melee/chainofcommand, /obj/item/stamp/head/captain, +/obj/item/ashtray{ + pixel_y = 12; + pixel_x = -6 + }, /turf/open/floor/carpet/royalblue, /area/station/command/heads_quarters/captain/private) "agR" = ( @@ -2786,6 +2798,10 @@ /obj/structure/table/wood, /obj/item/folder/red, /obj/item/stamp/head/hos, +/obj/item/ashtray{ + pixel_y = 12; + pixel_x = -6 + }, /turf/open/floor/carpet/red, /area/station/command/heads_quarters/hos) "ahF" = ( @@ -3699,6 +3715,10 @@ dir = 8 }, /obj/machinery/newscaster/directional/east, +/obj/item/ashtray{ + pixel_y = 6; + pixel_x = -7 + }, /turf/open/floor/iron/dark, /area/station/hallway/primary/fore) "ajW" = ( @@ -4701,6 +4721,10 @@ c_tag = "Engineering - Chief Engineer's Office"; network = list("ss13","engine","heads") }, +/obj/item/ashtray{ + pixel_y = -5; + pixel_x = -8 + }, /turf/open/floor/iron/dark, /area/station/command/heads_quarters/ce) "amG" = ( @@ -5610,6 +5634,10 @@ }, /obj/item/gavelhammer, /obj/machinery/airalarm/directional/south, +/obj/item/ashtray{ + pixel_y = -4; + pixel_x = -2 + }, /turf/open/floor/carpet/green, /area/station/service/lawoffice) "aoE" = ( @@ -5840,13 +5868,6 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/iron, /area/station/cargo/miningdock) -"apn" = ( -/obj/effect/turf_decal/stripes/line, -/obj/effect/turf_decal/stripes/line{ - dir = 1 - }, -/turf/open/floor/iron, -/area/station/cargo/miningdock) "apo" = ( /obj/effect/turf_decal/stripes/line{ dir = 6 @@ -7418,7 +7439,7 @@ /obj/effect/decal/cleanable/dirt, /obj/effect/mapping_helpers/broken_floor, /obj/structure/table/wood, -/obj/item/stack/medical/gauze/improvised, +/obj/item/stack/medical/wrap/gauze/improvised, /obj/item/restraints/handcuffs/cable, /turf/open/floor/wood, /area/station/maintenance/department/science) @@ -8038,6 +8059,10 @@ /obj/effect/turf_decal/siding/wood{ dir = 8 }, +/obj/item/ashtray{ + pixel_y = 6; + pixel_x = 5 + }, /turf/open/floor/iron/dark/side{ dir = 8 }, @@ -8504,6 +8529,7 @@ "awX" = ( /obj/structure/table/reinforced, /obj/effect/turf_decal/tile/neutral, +/obj/item/ashtray/random_contents, /turf/open/floor/iron/dark/side{ dir = 4 }, @@ -9178,6 +9204,10 @@ /obj/effect/turf_decal/siding/wood{ dir = 8 }, +/obj/item/ashtray{ + pixel_y = -4; + pixel_x = 5 + }, /turf/open/floor/iron/dark/side{ dir = 8 }, @@ -9877,6 +9907,10 @@ /obj/structure/table/reinforced, /obj/item/folder/red, /obj/effect/turf_decal/stripes/line, +/obj/item/ashtray{ + pixel_y = -3; + pixel_x = -8 + }, /turf/open/floor/iron, /area/station/hallway/secondary/exit/departure_lounge) "aBg" = ( @@ -10843,6 +10877,7 @@ "aEa" = ( /obj/structure/table, /obj/effect/turf_decal/delivery, +/obj/item/storage/medkit/emergency, /turf/open/floor/iron/dark/side{ dir = 4 }, @@ -11168,6 +11203,10 @@ name = "Station Intercom"; pixel_y = -26 }, +/obj/item/ashtray{ + pixel_y = 6; + pixel_x = 5 + }, /turf/open/floor/iron/dark/side, /area/station/service/theater) "aEU" = ( @@ -11423,9 +11462,8 @@ /obj/effect/turf_decal/stripes/line{ dir = 8 }, -/obj/machinery/atmospherics/components/unary/airlock_pump/unbolt_only{ - dir = 8 - }, +/obj/machinery/atmospherics/pipe/smart/manifold4w/cyan/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/iron, /area/station/maintenance/department/cargo) "aFC" = ( @@ -11486,7 +11524,6 @@ /obj/structure/extinguisher_cabinet{ pixel_x = -26 }, -/obj/item/kirbyplants/organic/plant22, /obj/machinery/camera/directional/west{ c_tag = "Cafeteria - Aft"; network = list("ss13","service") @@ -11535,6 +11572,10 @@ /obj/item/storage/fancy/donut_box{ pixel_y = 15 }, +/obj/item/ashtray{ + pixel_y = 3; + pixel_x = -4 + }, /turf/open/floor/iron, /area/station/service/kitchen) "aFR" = ( @@ -12273,6 +12314,7 @@ }, /obj/machinery/status_display/ai/directional/east, /obj/machinery/light/directional/east, +/obj/item/kirbyplants/organic/plant21, /turf/open/floor/iron, /area/station/service/cafeteria) "aHW" = ( @@ -12654,6 +12696,7 @@ }, /obj/effect/turf_decal/tile/red/opposingcorners, /obj/machinery/newscaster/directional/east, +/obj/machinery/restaurant_portal/restaurant, /turf/open/floor/iron, /area/station/service/cafeteria) "aIR" = ( @@ -12766,6 +12809,10 @@ pixel_y = 7; pixel_x = 7 }, +/obj/item/ashtray{ + pixel_y = 6; + pixel_x = -8 + }, /turf/open/floor/iron/dark, /area/station/command/heads_quarters/cmo) "aJg" = ( @@ -13105,9 +13152,9 @@ dir = 8 }, /obj/effect/turf_decal/tile/red/opposingcorners, -/obj/item/kirbyplants/organic/plant21, /obj/structure/sign/poster/official/random/directional/east, /obj/effect/landmark/start/hangover, +/obj/structure/closet/crate/bin, /turf/open/floor/iron, /area/station/service/cafeteria) "aJY" = ( @@ -13174,6 +13221,10 @@ req_access = list("cargo") }, /obj/effect/turf_decal/delivery, +/obj/item/ashtray{ + pixel_y = 6; + pixel_x = -8 + }, /turf/open/floor/iron, /area/station/hallway/secondary/exit/departure_lounge) "aKj" = ( @@ -13193,6 +13244,7 @@ dir = 1 }, /obj/effect/landmark/event_spawn, +/mob/living/basic/bot/cleanbot/medbay, /turf/open/floor/iron/white, /area/station/medical/treatment_center) "aKm" = ( @@ -13636,7 +13688,7 @@ /turf/open/floor/iron, /area/station/service/cafeteria) "aLg" = ( -/obj/machinery/restaurant_portal/restaurant, +/obj/machinery/vending/coffee, /turf/open/floor/iron/dark/side{ dir = 4 }, @@ -13990,6 +14042,7 @@ dir = 4 }, /obj/structure/table/reinforced, +/obj/item/storage/medkit/emergency, /turf/open/floor/iron, /area/station/engineering/main) "aMe" = ( @@ -15045,7 +15098,7 @@ /area/station/science/lab) "aOY" = ( /obj/structure/table/reinforced, -/obj/item/stack/medical/gauze{ +/obj/item/stack/medical/wrap/gauze{ pixel_x = 8 }, /obj/item/stack/medical/suture, @@ -15069,7 +15122,6 @@ }, /obj/machinery/airalarm/directional/east, /obj/machinery/camera/autoname/directional/east, -/obj/machinery/light/small/directional/east, /turf/open/floor/iron/white, /area/station/commons/long_term_storage) "aPc" = ( @@ -16616,6 +16668,10 @@ }, /obj/structure/table/reinforced, /obj/structure/sign/poster/official/ue_no/directional/north, +/obj/item/ashtray{ + pixel_y = 6; + pixel_x = -8 + }, /turf/open/floor/iron, /area/station/command/heads_quarters/rd) "aTp" = ( @@ -16691,11 +16747,15 @@ /area/station/science/ordnance/testlab) "aTy" = ( /obj/structure/table/wood, -/obj/item/flashlight/lamp, +/obj/item/flashlight/lamp{ + pixel_y = 5; + pixel_x = -3 + }, /obj/machinery/status_display/evac/directional/north, /obj/effect/turf_decal/siding/thinplating{ dir = 8 }, +/obj/item/stack/medical/wrap/gauze, /turf/open/floor/iron/grimy, /area/station/hallway/primary/aft) "aTz" = ( @@ -16795,19 +16855,6 @@ /obj/effect/spawner/structure/window/reinforced, /turf/open/floor/plating, /area/station/science/lab) -"aTM" = ( -/obj/machinery/door/airlock/external{ - name = "External Docking Port" - }, -/obj/effect/turf_decal/stripes/line{ - dir = 8 - }, -/obj/effect/mapping_helpers/airlock/cyclelink_helper{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/turf/open/floor/iron, -/area/station/hallway/secondary/exit/departure_lounge) "aTO" = ( /obj/machinery/door/airlock/maintenance_hatch{ name = "Science Maintenance" @@ -16822,6 +16869,9 @@ "aTS" = ( /obj/effect/landmark/blobstart, /obj/effect/mapping_helpers/burnt_floor, +/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ + dir = 8 + }, /turf/open/floor/plating, /area/station/maintenance/department/science) "aTU" = ( @@ -17125,6 +17175,9 @@ /obj/effect/turf_decal/stripes/line{ dir = 4 }, +/obj/effect/mapping_helpers/cycling_airlock_old/marker/inner_door{ + dir = 2 + }, /turf/open/floor/iron, /area/station/medical/virology) "aUL" = ( @@ -17493,6 +17546,10 @@ "aVP" = ( /obj/structure/table/wood, /obj/item/flashlight/lamp, +/obj/item/ashtray{ + pixel_y = 6; + pixel_x = -8 + }, /turf/open/floor/iron/dark/side{ dir = 10 }, @@ -17862,6 +17919,10 @@ /obj/machinery/camera/directional/east{ c_tag = "Library - Starboard" }, +/obj/item/ashtray{ + pixel_y = -2; + pixel_x = -8 + }, /turf/open/floor/iron/dark, /area/station/service/library) "aWH" = ( @@ -17899,6 +17960,9 @@ /obj/structure/cable, /obj/machinery/airalarm/directional/north, /obj/machinery/light/small/directional/north, +/obj/effect/mapping_helpers/cycling_airlock_old{ + access = list("virology") + }, /turf/open/floor/iron/white, /area/station/medical/virology) "aWL" = ( @@ -17906,7 +17970,9 @@ dir = 8 }, /obj/machinery/duct, -/obj/machinery/firealarm/directional/east, +/obj/machinery/firealarm/directional/east{ + pixel_y = -6 + }, /obj/effect/turf_decal/stripes/line{ dir = 4 }, @@ -17980,6 +18046,10 @@ /obj/effect/turf_decal/siding/thinplating{ dir = 4 }, +/obj/item/ashtray{ + pixel_y = 3; + pixel_x = -4 + }, /turf/open/floor/iron/grimy, /area/station/hallway/primary/aft) "aWU" = ( @@ -18049,6 +18119,9 @@ /obj/effect/turf_decal/stripes/line{ dir = 8 }, +/obj/effect/mapping_helpers/cycling_airlock_old/marker/outer_door{ + dir = 2 + }, /turf/open/floor/iron/white, /area/station/maintenance/department/medical) "aXe" = ( @@ -18310,7 +18383,6 @@ /obj/structure/sign/warning/secure_area/directional/west{ pixel_y = -32 }, -/obj/structure/sign/departments/virology/directional/west, /turf/open/floor/plating, /area/station/maintenance/department/medical) "aXP" = ( @@ -18355,7 +18427,7 @@ /area/station/medical/treatment_center) "aXT" = ( /obj/structure/table/reinforced, -/obj/item/stack/medical/gauze{ +/obj/item/stack/medical/wrap/gauze{ pixel_x = 8 }, /obj/item/stack/medical/mesh, @@ -18553,6 +18625,9 @@ c_tag = "Medical - Virology Airlock"; network = list("ss13","medbay","viro") }, +/obj/machinery/firealarm/directional/west{ + pixel_y = -6 + }, /turf/open/floor/iron/white, /area/station/medical/virology) "aYA" = ( @@ -20106,6 +20181,9 @@ /obj/effect/turf_decal/caution{ dir = 8 }, +/obj/machinery/atmospherics/components/unary/airlock_pump/unbolt_only{ + dir = 8 + }, /turf/open/floor/iron, /area/station/maintenance/department/cargo) "bcL" = ( @@ -21327,11 +21405,11 @@ /obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ dir = 8 }, -/obj/item/radio/intercom/directional/south, /obj/effect/turf_decal/siding/green, /obj/effect/turf_decal/trimline/green/end{ dir = 1 }, +/obj/structure/sign/departments/virology/directional/south, /turf/open/floor/iron/white, /area/station/medical/virology) "bfN" = ( @@ -21775,7 +21853,8 @@ "bhp" = ( /obj/machinery/door/morgue{ name = "Relic Closet"; - req_one_access = list("chapel_office", "crematorium") + req_one_access = list("chapel_office", "crematorium"); + dir = 1 }, /obj/effect/turf_decal/tile/neutral{ dir = 1 @@ -22584,6 +22663,7 @@ /obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ dir = 4 }, +/mob/living/basic/bot/medbot/autopatrol, /turf/open/floor/iron, /area/station/medical/treatment_center) "bkt" = ( @@ -23722,7 +23802,6 @@ /turf/open/floor/iron, /area/station/hallway/primary/fore) "bNe" = ( -/obj/structure/closet/crate/bin, /obj/effect/landmark/start/hangover, /turf/open/floor/iron/dark/side{ dir = 8 @@ -23966,18 +24045,14 @@ }, /area/station/hallway/secondary/service) "cgi" = ( -/obj/effect/turf_decal/caution{ - dir = 8 - }, -/obj/effect/turf_decal/stripes/line{ - dir = 4 - }, /obj/effect/turf_decal/stripes/line{ dir = 8 }, -/obj/machinery/atmospherics/components/unary/airlock_pump{ +/obj/effect/turf_decal/caution{ dir = 8 }, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/iron, /area/station/maintenance/department/science) "cgO" = ( @@ -24118,8 +24193,15 @@ /turf/open/floor/iron, /area/station/service/hydroponics) "cpo" = ( -/obj/machinery/vending/coffee, /obj/structure/sign/warning/doors/directional/south, +/obj/structure/table, +/obj/effect/spawner/random/trash/food_packaging, +/obj/effect/spawner/random/trash/cigbutt, +/obj/effect/spawner/random/trash/cigbutt, +/obj/item/ashtray{ + pixel_y = 3; + pixel_x = -4 + }, /turf/open/floor/iron/dark/side{ dir = 10 }, @@ -25744,7 +25826,6 @@ /area/station/science/ordnance/testlab) "fcU" = ( /obj/item/cigbutt, -/obj/structure/sign/warning/secure_area/directional/south, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -25872,6 +25953,7 @@ /obj/structure/sign/nanotrasen{ pixel_y = -32 }, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/iron{ heat_capacity = 1e+006 }, @@ -29773,6 +29855,15 @@ }, /turf/open/floor/iron, /area/station/security/prison) +"mdS" = ( +/obj/effect/turf_decal/stripes/line{ + dir = 4 + }, +/obj/machinery/atmospherics/components/unary/airlock_pump{ + dir = 8 + }, +/turf/open/floor/iron, +/area/station/maintenance/department/science) "meo" = ( /obj/machinery/navbeacon{ codes_txt = "patrol;next_patrol=5.2-Cargo"; @@ -29878,6 +29969,9 @@ dir = 1 }, /area/station/hallway/secondary/entry) +"mlz" = ( +/turf/closed/wall/r_wall/rust, +/area/station/maintenance/department/medical) "mmf" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -29892,6 +29986,7 @@ dir = 1 }, /obj/effect/turf_decal/tile/neutral/anticorner/contrasted, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/iron, /area/station/hallway/primary/aft) "mmW" = ( @@ -30026,6 +30121,12 @@ /obj/item/inspector, /turf/open/floor/iron, /area/station/security/brig) +"mtl" = ( +/obj/structure/table/wood, +/obj/effect/turf_decal/tile/neutral/fourcorners, +/obj/item/ashtray/random_contents, +/turf/open/floor/iron, +/area/station/service/cafeteria) "mvj" = ( /obj/machinery/atmospherics/pipe/smart/simple/supply/hidden{ dir = 9 @@ -30462,9 +30563,6 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/cyan/hidden/layer5, /turf/open/floor/iron, /area/station/hallway/primary/starboard) -"nhh" = ( -/turf/closed/wall, -/area/space) "nhB" = ( /obj/structure/cable, /obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2, @@ -31211,6 +31309,7 @@ dir = 1 }, /obj/effect/turf_decal/tile/neutral/anticorner/contrasted, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/iron, /area/station/hallway/primary/aft) "oCy" = ( @@ -32539,6 +32638,15 @@ }, /turf/open/floor/iron/dark/corner, /area/station/cargo/bitrunning/den) +"qQo" = ( +/obj/effect/turf_decal/stripes/line, +/obj/effect/turf_decal/stripes/line{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/smart/manifold4w/cyan/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/turf/open/floor/iron, +/area/station/cargo/miningdock) "qQO" = ( /obj/machinery/door/firedoor, /obj/structure/sign/departments/medbay/alt/directional/south, @@ -33022,6 +33130,7 @@ /area/space/nearstation) "rFA" = ( /obj/structure/table, +/obj/item/storage/medkit/emergency, /turf/open/floor/iron, /area/station/commons/dorms) "rIZ" = ( @@ -33070,6 +33179,21 @@ /obj/structure/cable, /turf/open/floor/iron, /area/station/engineering/supermatter/room) +"rMs" = ( +/obj/effect/turf_decal/tile/red{ + dir = 1 + }, +/obj/effect/turf_decal/tile/red, +/obj/effect/turf_decal/tile/yellow{ + dir = 4 + }, +/obj/effect/turf_decal/tile/yellow{ + dir = 8 + }, +/obj/effect/landmark/start/hangover, +/obj/item/kirbyplants/organic/plant21, +/turf/open/floor/iron, +/area/station/service/cafeteria) "rOb" = ( /obj/machinery/atmospherics/pipe/smart/simple/orange/hidden{ dir = 4 @@ -33753,6 +33877,7 @@ /obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ dir = 4 }, +/obj/machinery/light/cold/dim/directional/south, /turf/open/floor/iron/white, /area/station/commons/long_term_storage) "sHz" = ( @@ -34417,6 +34542,10 @@ pixel_x = 7; pixel_y = 2 }, +/obj/item/ashtray{ + pixel_y = -5; + pixel_x = -8 + }, /turf/open/floor/iron, /area/station/command/heads_quarters/qm) "sMe" = ( @@ -35208,6 +35337,12 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/cyan/hidden/layer5, /turf/open/floor/iron/white/corner, /area/station/hallway/primary/starboard) +"tbZ" = ( +/obj/effect/turf_decal/delivery, +/obj/machinery/atmospherics/pipe/smart/manifold4w/cyan/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/turf/open/floor/iron, +/area/station/hallway/secondary/entry) "tdz" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/structure/table, @@ -35267,6 +35402,10 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/effect/turf_decal/tile/neutral/fourcorners, +/obj/item/ashtray{ + pixel_y = 6; + pixel_x = 2 + }, /turf/open/floor/iron, /area/station/service/cafeteria) "tin" = ( @@ -35328,6 +35467,7 @@ /obj/effect/mapping_helpers/airlock/unres{ dir = 4 }, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/plating, /area/station/maintenance/department/science) "tlg" = ( @@ -35344,6 +35484,7 @@ dir = 1 }, /obj/effect/turf_decal/tile/neutral, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/iron/white/corner{ dir = 8 }, @@ -35666,6 +35807,13 @@ /obj/effect/landmark/start/station_engineer, /turf/open/floor/iron, /area/station/engineering/main) +"tVj" = ( +/obj/effect/turf_decal/tile/neutral{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/turf/open/floor/iron, +/area/station/hallway/primary/aft) "tVp" = ( /obj/machinery/power/apc/auto_name/directional/east, /obj/structure/cable, @@ -35690,7 +35838,8 @@ }, /obj/machinery/door/morgue{ name = "Curator's Study"; - req_access = list("library") + req_access = list("library"); + dir = 1 }, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/iron/dark, @@ -36091,6 +36240,7 @@ /obj/effect/turf_decal/tile/neutral/anticorner/contrasted{ dir = 1 }, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/iron{ heat_capacity = 1e+006 }, @@ -36148,6 +36298,12 @@ /obj/machinery/iv_drip, /turf/open/floor/iron, /area/station/medical/treatment_center) +"uAP" = ( +/obj/effect/turf_decal/delivery, +/obj/machinery/atmospherics/pipe/smart/manifold4w/cyan/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/turf/open/floor/iron, +/area/station/hallway/secondary/exit/departure_lounge) "uBJ" = ( /obj/machinery/computer/security{ dir = 1 @@ -36892,6 +37048,7 @@ /area/station/science/breakroom) "wdt" = ( /obj/effect/turf_decal/bot, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/iron/dark/side{ dir = 4 }, @@ -37172,6 +37329,13 @@ /obj/structure/cable, /turf/open/floor/iron, /area/station/cargo/storage) +"wAa" = ( +/obj/effect/turf_decal/stripes/line{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/turf/open/floor/plating, +/area/station/maintenance/department/science) "wAw" = ( /turf/open/space, /area/space) @@ -37994,6 +38158,10 @@ /obj/effect/turf_decal/siding/wood{ dir = 1 }, +/obj/item/ashtray{ + pixel_y = -2; + pixel_x = -8 + }, /turf/open/floor/iron/dark, /area/station/service/library) "xSs" = ( @@ -38067,7 +38235,6 @@ /turf/open/floor/iron/dark, /area/station/science/ordnance/storage) "xZz" = ( -/obj/item/kirbyplants/organic/plant22, /obj/effect/turf_decal/tile/red, /obj/effect/turf_decal/tile/yellow{ dir = 4 @@ -38079,6 +38246,7 @@ dir = 1 }, /obj/effect/landmark/start/hangover, +/obj/structure/tank_holder/extinguisher, /turf/open/floor/iron, /area/station/service/cafeteria) "xZL" = ( @@ -38295,10 +38463,10 @@ dir = 6 }, /obj/structure/closet/l3closet/virology, -/obj/machinery/firealarm/directional/south, /obj/effect/turf_decal/siding/green{ dir = 6 }, +/obj/item/radio/intercom/directional/south, /turf/open/floor/iron/white, /area/station/medical/virology) "ylH" = ( @@ -63922,7 +64090,7 @@ aSs aUl aKm ayM -bea +mlz aWJ bfM bea @@ -64179,7 +64347,7 @@ aTb aUp aTU jXv -aKV +bxN aWM ylF aKV @@ -68307,7 +68475,7 @@ aaa aaa aaa aaa -aaa +bwz aaa aaa aaa @@ -68563,15 +68731,15 @@ aaa aaa aaa aaa -aaa -bwz -aaa -aaa -aaa -aaa +bgU +bkj +bgU aaa aaa aaa +bgU +bkj +bgU aaa aaa aaa @@ -68821,13 +68989,13 @@ aaa aaa aaa bgU -bkj +eIU bgU sdX sdX sdX bgU -bkj +eIU bgU aaa aaa @@ -69078,13 +69246,13 @@ aae aae aae bgU -eIU +tbZ bgU bgP bgU bgP bgU -eIU +tbZ bgU aae aae @@ -70363,13 +70531,13 @@ aae aae aae bgU -bki +tbZ bgU bgP bgU bgP bgU -bki +tbZ bgU aae aae @@ -70620,13 +70788,13 @@ aaa aaa aaa bgU -btl +bki bgU sdX sdX sdX bgU -btl +bki bgU aaa aaa @@ -70876,15 +71044,15 @@ aaa aaa aaa aaa +bgU +btl +bgU aaa aaa aaa -aaa -aaa -aaa -aaa -aaa -aaa +bgU +btl +bgU aaa aaa aaa @@ -71401,7 +71569,7 @@ aaa aaa aaa aaa -lUq +aaa aaa aaa aaa @@ -71658,7 +71826,7 @@ aaa aaa aaa aaa -aaa +lUq aaa aaa aaa @@ -71850,7 +72018,7 @@ auc pcN avg awl -aBZ +mtl gpG rdB eZj @@ -71861,7 +72029,7 @@ eZj oTd aFO kcP -aBZ +mtl sAA pcN auc @@ -72379,7 +72547,7 @@ vPL vPL asg hDi -ubG +rMs arb aOq aPn @@ -72658,7 +72826,7 @@ bcq bfJ aDE bfJ -aDE +tVj qks rJx bhH @@ -73686,7 +73854,7 @@ bcu bdm beh sKP -xKp +wAa sJL pej hrd @@ -79295,7 +79463,7 @@ aaa aae amD aol -gtS +qQo aqu amD aae @@ -79552,7 +79720,7 @@ aaa aae ant aom -apn +gtS aqv nzE aae @@ -79862,7 +80030,7 @@ eBJ aiQ pMh pMh -sKH +mdS pMh uTo aaa @@ -80118,8 +80286,9 @@ aiQ aiQ aiQ aiQ -aiQ -bvg +pMh +sKH +pMh uTo aaa aaa @@ -80210,7 +80379,6 @@ aaa aaa aaa aaa -aaa "} (164,1,1) = {" aaa @@ -80376,6 +80544,7 @@ aiQ aiQ aiQ aiQ +bvg uTo aaa aaa @@ -80467,7 +80636,6 @@ aaa aaa aaa aaa -aaa "} (165,1,1) = {" aaa @@ -80632,7 +80800,7 @@ aiQ aiQ aiQ aiQ -aaa +aiQ aaa aaa aaa @@ -80887,8 +81055,8 @@ aDw imR ozW aHq -aaa -aaa +aiQ +uTo aaa aaa aaa @@ -82130,7 +82298,7 @@ aaa aaa aaf aae -nhh +aKh sDP azb azb @@ -82142,7 +82310,7 @@ aKh aGc aKh azb -aTM +aBh aCn aBh azb @@ -82391,17 +82559,17 @@ rel aae aae azb -aDh +uAP azb -aDh +uAP azb aae aae aae azb -aDh +uAP azb -aDh +uAP azb aae rel @@ -82648,17 +82816,17 @@ aaa aaa aaa azb -fWz +aDh azb -fWz +aDh azb -aaa -aaa -aaa +aae +aae +aae azb -fWz +aDh azb -fWz +aDh azb aaa aaa @@ -82671,7 +82839,7 @@ aaa aaa aaa aaa -jYq +aae uTo xUx uTo @@ -82904,19 +83072,19 @@ aaa aaa aaa aaa +azb +fWz +azb +fWz +azb aaa aaa aaa -fsl -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa +azb +fWz +azb +fWz +azb aaa aaa aaa @@ -83164,7 +83332,7 @@ aaa aaa aaa aaa -aaa +fsl aaa aaa aaa diff --git a/code/datums/elements/rust.dm b/code/datums/elements/rust.dm index 135f45b7c2f3..e94e3703ad77 100644 --- a/code/datums/elements/rust.dm +++ b/code/datums/elements/rust.dm @@ -51,12 +51,10 @@ /datum/element/rust/proc/handle_tool_use(atom/source, mob/user, obj/item/item) switch(item.tool_behaviour) if(TOOL_WELDER) - if(!item.tool_start_check(user, amount=1)) + if(!item.tool_start_check(user, amount = 1)) return - user.balloon_alert(user, "burning off rust...") - - if(!item.use_tool(source, user, 5 SECONDS)) + if(!item.use_tool(source, user, 5 SECONDS, amount = 1, volume = 50)) return user.balloon_alert(user, "burned off rust") Detach(source) @@ -67,7 +65,7 @@ if(!item.tool_start_check(user)) return user.balloon_alert(user, "scraping off rust...") - if(!item.use_tool(source, user, 2 SECONDS)) + if(!item.use_tool(source, user, 2 SECONDS, volume = 50)) return user.balloon_alert(user, "scraped off rust") Detach(source) diff --git a/code/datums/mood.dm b/code/datums/mood.dm index 890b5bf022ce..f37d116ead8c 100644 --- a/code/datums/mood.dm +++ b/code/datums/mood.dm @@ -798,20 +798,23 @@ switch(esanity) if (0 to 10) new_screen = mob_parent.overlay_fullscreen("sanity", /atom/movable/screen/fullscreen/sanity, 4) - mob_parent.add_client_colour(/datum/client_colour/sanity/tier4, "sanity") + mob_parent.add_client_colour(/datum/client_colour/sanity/tier4) if (10 to 20) new_screen = mob_parent.overlay_fullscreen("sanity", /atom/movable/screen/fullscreen/sanity, 3) - mob_parent.add_client_colour(/datum/client_colour/sanity/tier3, "sanity") + mob_parent.add_client_colour(/datum/client_colour/sanity/tier3) if (20 to 30) new_screen = mob_parent.overlay_fullscreen("sanity", /atom/movable/screen/fullscreen/sanity, 2) - mob_parent.add_client_colour(/datum/client_colour/sanity/tier2, "sanity") + mob_parent.add_client_colour(/datum/client_colour/sanity/tier2) if (30 to 40) new_screen = mob_parent.overlay_fullscreen("sanity", /atom/movable/screen/fullscreen/sanity, 1) - mob_parent.add_client_colour(/datum/client_colour/sanity/tier1, "sanity") + mob_parent.add_client_colour(/datum/client_colour/sanity/tier1) else mob_parent.clear_fullscreen("sanity") mob_parent.clear_fullscreen("sanity_static") - mob_parent.remove_client_colour("sanity") + mob_parent.remove_client_colour(/datum/client_colour/sanity/tier4) + mob_parent.remove_client_colour(/datum/client_colour/sanity/tier3) + mob_parent.remove_client_colour(/datum/client_colour/sanity/tier2) + mob_parent.remove_client_colour(/datum/client_colour/sanity/tier1) if(new_screen && old_state != new_screen.icon_state) // updating static effect for new sanity level diff --git a/code/game/objects/effects/decals/cleanable/humans.dm b/code/game/objects/effects/decals/cleanable/humans.dm index 8e168b25f082..9985f87dacf3 100644 --- a/code/game/objects/effects/decals/cleanable/humans.dm +++ b/code/game/objects/effects/decals/cleanable/humans.dm @@ -16,6 +16,8 @@ var/can_dry = TRUE /// Is this blood dried out? var/dried = FALSE + /// Do we delete ourselves when we dry out? + var/qdel_on_dry = FALSE /// How much our blood glows, up to 255 (it's the alpha of the EM overlay). 0 = no glow var/emissive_alpha = 0 @@ -43,6 +45,9 @@ if(mapload || starting_dna) init_dna(starting_dna) if(dried) + if(qdel_on_dry) + stack_trace("Blood decal set to dry on init but qdel on dry, you probably don't want that?") + qdel_on_dry = FALSE dry() else if(can_dry) START_PROCESSING(SSblood_drying, src) @@ -159,6 +164,8 @@ update_atom_colour() STOP_PROCESSING(SSblood_drying, src) clear_smells() + if(qdel_on_dry) + qdel(src) return TRUE /obj/effect/decal/cleanable/blood/adjust_bloodiness(by_amount) diff --git a/code/modules/clothing/masks/bandana.dm b/code/modules/clothing/masks/bandana.dm index b5f7b7bf3710..758cb1ddb9a1 100644 --- a/code/modules/clothing/masks/bandana.dm +++ b/code/modules/clothing/masks/bandana.dm @@ -72,12 +72,17 @@ widen.Scale(1.25, 1) transform = widen user.visible_message(span_notice("[user] ties [src] up like a neckerchief."), span_notice("You tie [src] up like a neckerchief.")) - else - undyeable = initial(undyeable) - slot_flags = initial(slot_flags) - worn_y_offset = initial(worn_y_offset) - transform = initial(transform) - user.visible_message(span_notice("[user] unties the neckercheif."), span_notice("You untie the neckercheif.")) + flags_inv = NONE + flags_cover = NONE + return CLICK_ACTION_SUCCESS + + undyeable = initial(undyeable) + slot_flags = initial(slot_flags) + worn_y_offset = initial(worn_y_offset) + transform = initial(transform) + user.visible_message(span_notice("[user] unties the neckercheif."), span_notice("You untie the neckercheif.")) + flags_inv = initial(flags_inv) + flags_cover = initial(flags_cover) return CLICK_ACTION_SUCCESS /obj/item/clothing/mask/bandana/red diff --git a/code/modules/forensics/forensics_helpers.dm b/code/modules/forensics/forensics_helpers.dm index f02d9e2450a2..da22fc1c8bd0 100644 --- a/code/modules/forensics/forensics_helpers.dm +++ b/code/modules/forensics/forensics_helpers.dm @@ -135,7 +135,7 @@ if(unique_blood[blood_type]) continue var/datum/blood_type/blood = find_blood_type(blood_type) - blood.set_up_blood(src, first_dna == 0) + blood.set_up_blood(src, first_dna == 0, only_dna = length(blood_DNA_to_add) == 1) unique_blood[blood_type] = TRUE // handle smells refresh_smells() diff --git a/maplestation_modules/code/modules/mob/living/blood.dm b/maplestation_modules/code/modules/mob/living/blood.dm index 866b6ccfcfe9..7aeab63d3c62 100644 --- a/maplestation_modules/code/modules/mob/living/blood.dm +++ b/maplestation_modules/code/modules/mob/living/blood.dm @@ -118,8 +118,9 @@ PROCESSING_SUBSYSTEM_DEF(blood_drying) * Arguments * * blood - the blood being set up * * new_splat - whether this is a newly instantiated blood decal, or an existing one this blood is being added to + * * only_type - whether this blood decal is only of this blood type, or if it has other blood types mixed in */ -/datum/blood_type/proc/set_up_blood(obj/effect/decal/cleanable/blood/blood, new_splat = FALSE) +/datum/blood_type/proc/set_up_blood(obj/effect/decal/cleanable/blood/blood, new_splat = FALSE, only_type = TRUE) return /** @@ -301,7 +302,7 @@ PROCESSING_SUBSYSTEM_DEF(blood_drying) restoration_chem = /datum/reagent/silver scent_text = null -/datum/blood_type/silver/set_up_blood(obj/effect/decal/cleanable/blood/blood, new_splat) +/datum/blood_type/silver/set_up_blood(obj/effect/decal/cleanable/blood/blood, new_splat, only_type) blood.can_dry = FALSE blood.emissive_alpha = max(blood.emissive_alpha, new_splat ? 125 : 63) @@ -323,7 +324,7 @@ PROCESSING_SUBSYSTEM_DEF(blood_drying) salgu_compatible = TRUE scent_text = null -/datum/blood_type/crew/ethereal/set_up_blood(obj/effect/decal/cleanable/blood/blood, new_splat) +/datum/blood_type/crew/ethereal/set_up_blood(obj/effect/decal/cleanable/blood/blood, new_splat, only_type) blood.emissive_alpha = max(blood.emissive_alpha, new_splat ? 188 : 125) if(!new_splat) return @@ -357,7 +358,7 @@ PROCESSING_SUBSYSTEM_DEF(blood_drying) restoration_chem = /datum/reagent/fuel/oil scent_text = /datum/smell/oil -/datum/blood_type/oil/set_up_blood(obj/effect/decal/cleanable/blood/blood, new_splat) +/datum/blood_type/oil/set_up_blood(obj/effect/decal/cleanable/blood/blood, new_splat, only_type) if(!new_splat) return // Oil blood will never dry and can be ignited with fire @@ -402,6 +403,11 @@ PROCESSING_SUBSYSTEM_DEF(blood_drying) salgu_compatible = TRUE scent_text = null +/datum/blood_type/water/set_up_blood(obj/effect/decal/cleanable/blood/blood, new_splat, only_type) + if(!new_splat || !only_type) + return + blood.qdel_on_dry = TRUE + /// Snails have Lube for blood, for some reason? /datum/blood_type/snail name = "Lube" @@ -410,7 +416,7 @@ PROCESSING_SUBSYSTEM_DEF(blood_drying) scent_text = /obj/effect/abstract/smell/reagent/lube::name scent_category = /obj/effect/abstract/smell/reagent/lube::category -/datum/blood_type/snail/set_up_blood(obj/effect/decal/cleanable/blood/blood, new_splat) +/datum/blood_type/snail/set_up_blood(obj/effect/decal/cleanable/blood/blood, new_splat, only_type) if(blood.bloodiness < BLOOD_AMOUNT_PER_DECAL) return var/slip_amt = new_splat ? 4 SECONDS : 1 SECONDS diff --git a/maplestation_modules/code/modules/mob/living/carbon/human/species_types/synth/android.dm b/maplestation_modules/code/modules/mob/living/carbon/human/species_types/synth/android.dm index b7bfaf46fd3b..e8a9bc8feb3c 100644 --- a/maplestation_modules/code/modules/mob/living/carbon/human/species_types/synth/android.dm +++ b/maplestation_modules/code/modules/mob/living/carbon/human/species_types/synth/android.dm @@ -432,7 +432,7 @@ /datum/species/android/proc/update_heat_modifiers(mob/living/carbon/human/source) var/obj/item/organ/lungs = source.get_organ_slot(ORGAN_SLOT_LUNGS) if(HAS_TRAIT_NOT_FROM_LUNGS(source, TRAIT_RESISTHEAT, lungs)) - remove_heat_modifiers() + remove_heat_modifiers(source) return if(source.body_temperature > source.bodytemp_heat_damage_limit * 2) @@ -461,12 +461,12 @@ else // ?? if(is_overheating != 0) - remove_heat_modifiers() + remove_heat_modifiers(source) /datum/species/android/proc/update_cold_modifiers(mob/living/carbon/human/source) var/obj/item/organ/lungs = source.get_organ_slot(ORGAN_SLOT_LUNGS) if(HAS_TRAIT_NOT_FROM_LUNGS(source, TRAIT_RESISTCOLD, lungs)) - remove_cold_modifiers() + remove_cold_modifiers(source) return if(source.body_temperature < source.bodytemp_cold_damage_limit * 2) @@ -495,7 +495,7 @@ else // ?? if(is_overcooled != 0) - remove_cold_modifiers() + remove_cold_modifiers(source) #undef HAS_TRAIT_NOT_FROM_LUNGS From e06532be2fb4dea972a8a3d1ffcd399ffe52ad6f Mon Sep 17 00:00:00 2001 From: OrionTheFox <76465278+OrionTheFox@users.noreply.github.com> Date: Wed, 29 Jan 2025 13:03:34 -0700 Subject: [PATCH 02/10] Resprites Extinguisher Cabinets (#89240) ## About The Pull Request Resprites the Extinguisher Cabinet wallmounts Additionally changes the door to an overlay rather than having an open/close state for each extinguisher type ![image](https://github.com/user-attachments/assets/79166f28-618a-4a4d-b052-93f540f42dcd) ![image](https://github.com/user-attachments/assets/fd2762f1-ee59-4f54-b420-6e50d5b866ae)
Here's some examples of them around the station: ![image](https://github.com/user-attachments/assets/6497c857-5f4d-44d8-9005-a3f4806b1882) ![image](https://github.com/user-attachments/assets/6c30bee9-087c-4bfd-88c1-ca15a2701682) ![image](https://github.com/user-attachments/assets/9771e391-cd51-4c65-90da-216a7b88552c)
## Why It's Good For The Game Extinguisher cabinets ~~are really showing their age~~ aren't actually that old compared to most sprites. However, some of the practices in the old one (mainly the perspective and hard outline) make it stick out a lot compared to other wallmounts. My hope with this is that they blend in better with the other wall fixtures, as opposed to appearing to be thin objects flat against walls. ![image](https://github.com/user-attachments/assets/30111618-47ef-41e3-b59e-cd18a74cb226) ## Changelog :cl: image: resprited Extinguisher Cabinets (did you know there's craftable Extinguishers? "Improvised cooling spray"? I didn't. Now I do though, and so do you!) /:cl: --- code/game/objects/structures/extinguisher.dm | 11 ++++++----- icons/obj/wallmounts.dmi | Bin 14929 -> 13074 bytes 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/code/game/objects/structures/extinguisher.dm b/code/game/objects/structures/extinguisher.dm index 93040121f0fd..c4176048e4dc 100644 --- a/code/game/objects/structures/extinguisher.dm +++ b/code/game/objects/structures/extinguisher.dm @@ -2,7 +2,7 @@ name = "extinguisher cabinet" desc = "A small wall mounted cabinet designed to hold a fire extinguisher." icon = 'icons/obj/wallmounts.dmi' - icon_state = "extinguisher_closed" + icon_state = "extinguisher" anchored = TRUE density = FALSE max_integrity = 200 @@ -153,11 +153,12 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/extinguisher_cabinet, 29) else if(istype(stored_extinguisher, /obj/item/extinguisher)) icon_state += "_default" - if(!opened) - icon_state += "_closed" - return ..() +/obj/structure/extinguisher_cabinet/update_overlays() + . = ..() + . += mutable_appearance(icon, opened ? "door_open" : "door") + /obj/structure/extinguisher_cabinet/atom_break(damage_flag) . = ..() if(!broken) @@ -182,6 +183,6 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/extinguisher_cabinet, 29) name = "extinguisher cabinet frame" desc = "Used for building wall-mounted extinguisher cabinets." icon = 'icons/obj/wallmounts.dmi' - icon_state = "extinguisher_assembly" + icon_state = "extinguisher" //Reuses wallmount icon, but no door overlay result_path = /obj/structure/extinguisher_cabinet pixel_shift = 29 diff --git a/icons/obj/wallmounts.dmi b/icons/obj/wallmounts.dmi index e70024a9edb23df81c12ff6b0b218d7a0a3c2894..2e7cb6b0f6232a3bbe230f78343564b658baa1d2 100644 GIT binary patch literal 13074 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 literal 14929 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 Date: Tue, 9 Dec 2025 14:52:03 -0600 Subject: [PATCH 03/10] Fix closets, crates, and drawers missing material tags (#94273) --- code/game/objects/structures/crates_lockers/closets.dm | 2 +- .../objects/structures/crates_lockers/closets/cardboardbox.dm | 3 +++ code/game/objects/structures/crates_lockers/closets/gimmick.dm | 3 +++ .../structures/crates_lockers/closets/secure/personal.dm | 2 ++ code/game/objects/structures/crates_lockers/crates/wooden.dm | 1 + 5 files changed, 10 insertions(+), 1 deletion(-) diff --git a/code/game/objects/structures/crates_lockers/closets.dm b/code/game/objects/structures/crates_lockers/closets.dm index 523d8f6d79b0..b50753449122 100644 --- a/code/game/objects/structures/crates_lockers/closets.dm +++ b/code/game/objects/structures/crates_lockers/closets.dm @@ -20,7 +20,7 @@ GLOBAL_LIST_EMPTY(roundstart_station_closets) /// How insulated the thing is, for the purposes of calculating body temperature. Must be between 0 and 1! contents_thermal_insulation = 0 pass_flags_self = PASSSTRUCTURE | LETPASSCLICKS - + custom_materials = list(/datum/material/iron = SHEET_MATERIAL_AMOUNT * 2) /// The overlay for the closet's door var/obj/effect/overlay/closet_door/door_obj /// Whether or not this door is being animated diff --git a/code/game/objects/structures/crates_lockers/closets/cardboardbox.dm b/code/game/objects/structures/crates_lockers/closets/cardboardbox.dm index b398731e7d8a..b532fa9b2d89 100644 --- a/code/game/objects/structures/crates_lockers/closets/cardboardbox.dm +++ b/code/game/objects/structures/crates_lockers/closets/cardboardbox.dm @@ -9,6 +9,8 @@ can_weld_shut = 0 cutting_tool = /obj/item/wirecutters material_drop = /obj/item/stack/sheet/cardboard + material_drop_amount = 4 + custom_materials = list(/datum/material/cardboard = SHEET_MATERIAL_AMOUNT * 4) delivery_icon = "deliverybox" anchorable = FALSE open_sound = 'sound/machines/cardboard_box.ogg' @@ -117,4 +119,5 @@ close_sound = 'sound/machines/crate_close.ogg' open_sound_volume = 35 close_sound_volume = 50 + custom_materials = list(/datum/material/alloy/plasteel = SHEET_MATERIAL_AMOUNT * 4) material_drop = /obj/item/stack/sheet/plasteel diff --git a/code/game/objects/structures/crates_lockers/closets/gimmick.dm b/code/game/objects/structures/crates_lockers/closets/gimmick.dm index 2ee4f780ff3c..73c2eee5321b 100644 --- a/code/game/objects/structures/crates_lockers/closets/gimmick.dm +++ b/code/game/objects/structures/crates_lockers/closets/gimmick.dm @@ -9,12 +9,15 @@ close_sound_volume = 50 max_integrity = 70 door_anim_time = 0 // no animation + material_drop = /obj/item/stack/sheet/mineral/wood + custom_materials = list(/datum/material/wood = SHEET_MATERIAL_AMOUNT * 2) /obj/structure/closet/acloset name = "strange closet" desc = "It looks alien!" icon_state = "alien" material_drop = /obj/item/stack/sheet/mineral/abductor + custom_materials = list(/datum/material/alloy/alien = SHEET_MATERIAL_AMOUNT * 2) /obj/structure/closet/gimmick name = "administrative supply closet" diff --git a/code/game/objects/structures/crates_lockers/closets/secure/personal.dm b/code/game/objects/structures/crates_lockers/closets/secure/personal.dm index d0487198d4c7..5b5676c26e47 100644 --- a/code/game/objects/structures/crates_lockers/closets/secure/personal.dm +++ b/code/game/objects/structures/crates_lockers/closets/secure/personal.dm @@ -45,6 +45,8 @@ open_sound_volume = 25 close_sound_volume = 50 door_anim_time = 0 // no animation + custom_materials = list(/datum/material/wood = SHEET_MATERIAL_AMOUNT * 2) + material_drop = /obj/item/stack/sheet/mineral/wood /obj/structure/closet/secure_closet/personal/cabinet/PopulateContents() new /obj/item/storage/backpack/satchel/leather/withwallet( src ) diff --git a/code/game/objects/structures/crates_lockers/crates/wooden.dm b/code/game/objects/structures/crates_lockers/crates/wooden.dm index a5e0b78cadb6..b98ee5c1601c 100644 --- a/code/game/objects/structures/crates_lockers/crates/wooden.dm +++ b/code/game/objects/structures/crates_lockers/crates/wooden.dm @@ -1,6 +1,7 @@ /obj/structure/closet/crate/wooden name = "wooden crate" desc = "Works just as well as a metal one." + custom_materials = list(/datum/material/wood = SHEET_MATERIAL_AMOUNT * 6) material_drop = /obj/item/stack/sheet/mineral/wood material_drop_amount = 6 icon_state = "wooden" From b320f67828a8ca5359a32b4a2e0c7edc1f422f24 Mon Sep 17 00:00:00 2001 From: Tim Date: Sun, 21 Dec 2025 07:00:19 -0600 Subject: [PATCH 04/10] Add recipes for flare, washer machine, lamp, lantern, cabinet, alien closet, and large metal box (#94283) --- code/datums/components/crafting/furniture.dm | 37 +++++++++++++++++++ code/datums/components/crafting/tools.dm | 12 ++++++ code/game/machinery/washing_machine.dm | 27 ++++++++++++-- .../machines/machine_circuitboards.dm | 20 ++++++++++ code/game/objects/items/devices/flashlight.dm | 32 +++++++++++++++- code/game/objects/items/food/burgers.dm | 6 +++ .../objects/items/stacks/sheets/mineral.dm | 1 + .../items/stacks/sheets/sheet_types.dm | 2 + .../autolathe/multi-department_designs.dm | 15 ++++++++ .../research/designs/machine_designs.dm | 30 +++++++++++++++ .../research/techweb/nodes/service_nodes.dm | 2 + 11 files changed, 178 insertions(+), 6 deletions(-) diff --git a/code/datums/components/crafting/furniture.dm b/code/datums/components/crafting/furniture.dm index 39f5a25a19f8..742d060bd017 100644 --- a/code/datums/components/crafting/furniture.dm +++ b/code/datums/components/crafting/furniture.dm @@ -71,3 +71,40 @@ tool_behaviors = list(TOOL_SCREWDRIVER) category = CAT_FURNITURE time = 10 SECONDS + +/datum/crafting_recipe/lamp + name = "Desk Lamp" + result = /obj/item/flashlight/lamp + reqs = list( + /obj/item/flashlight = 1, + /obj/item/stack/rods = 1, + /obj/item/light/bulb = 1, + ) + crafting_flags = CRAFT_SKIP_MATERIALS_PARITY + tool_behaviors = list(TOOL_SCREWDRIVER) + category = CAT_FURNITURE + +/datum/crafting_recipe/lamp/New() + . = ..() + blacklist += subtypesof(/obj/item/flashlight) + +/datum/crafting_recipe/lamp/green + name = "Green Desk Lamp" + result = /obj/item/flashlight/lamp/green + +/datum/crafting_recipe/banana_lamp + name = "Banana Lamp" + result = /obj/item/flashlight/lamp/bananalamp + reqs = list( + /obj/item/flashlight/lamp = 1, + /obj/item/grown/bananapeel = 1, + ) + blacklist = list( + /obj/item/flashlight/lamp/bananalamp, + /obj/item/flashlight/lamp/space_bubble, + ) + requirements_mats_blacklist = list(/obj/item/grown/bananapeel) + tool_behaviors = list(TOOL_SCREWDRIVER) + category = CAT_FURNITURE + + diff --git a/code/datums/components/crafting/tools.dm b/code/datums/components/crafting/tools.dm index 46faafa75613..d1a20b6b2017 100644 --- a/code/datums/components/crafting/tools.dm +++ b/code/datums/components/crafting/tools.dm @@ -90,3 +90,15 @@ // crafting_flags = CRAFT_SKIP_MATERIALS_PARITY tool_behaviors = list(TOOL_SCREWDRIVER) category = CAT_TOOLS + +/datum/crafting_recipe/lantern + name = "Lantern" + result = /obj/item/flashlight/lantern + reqs = list( + /obj/item/flashlight/flare/candle = 1, + /obj/item/stack/rods = 1, + /obj/item/stack/sheet/glass = 1, + ) + crafting_flags = CRAFT_SKIP_MATERIALS_PARITY + tool_behaviors = list(TOOL_SCREWDRIVER) + category = CAT_TOOLS diff --git a/code/game/machinery/washing_machine.dm b/code/game/machinery/washing_machine.dm index 3da43c1294f3..f4c7010fc97b 100644 --- a/code/game/machinery/washing_machine.dm +++ b/code/game/machinery/washing_machine.dm @@ -179,16 +179,33 @@ GLOBAL_LIST_INIT(dye_registry, list( icon_state = "wm_1_0" density = TRUE state_open = TRUE + custom_materials = list(/datum/material/iron = SHEET_MATERIAL_AMOUNT * 5, /datum/material/glass = SHEET_MATERIAL_AMOUNT) + circuit = /obj/item/circuitboard/machine/washing_machine var/busy = FALSE var/bloody_mess = FALSE var/obj/item/color_source - var/max_wash_capacity = 5 + /// The max amount of items that can be washed per load + var/max_wash_capacity + /// The time it takes to wash a load of laundry + var/time_to_wash + /// The current number of items inserted + var/total_load = 0 /obj/machinery/washing_machine/examine(mob/user) . = ..() if(!busy) . += span_notice("Right-click with an empty hand to start a wash cycle.") +/obj/machinery/washing_machine/RefreshParts() + . = ..() + var/total_volume = 0 + for(var/obj/item/reagent_containers/cup/beaker/beaker in component_parts) + total_volume += beaker.reagents.maximum_volume + max_wash_capacity = floor(total_volume/20) + + for(var/datum/stock_part/servo/servo in component_parts) + time_to_wash = 20 SECONDS / servo.tier + /obj/machinery/washing_machine/process(seconds_per_tick) if(!busy) animate(src, transform=matrix(), time=2) @@ -320,7 +337,7 @@ GLOBAL_LIST_INIT(dye_registry, list( icon_state = "wm_[state_open]_blood" return ..() - var/full = contents.len ? 1 : 0 + var/full = total_load ? 1 : 0 icon_state = "wm_[state_open]_[full]" return ..() @@ -352,7 +369,7 @@ GLOBAL_LIST_INIT(dye_registry, list( if(bloody_mess) to_chat(user, span_warning("[src] must be cleaned up first!")) return ITEM_INTERACT_BLOCKING - if(contents.len >= max_wash_capacity) + if(total_load >= max_wash_capacity) to_chat(user, span_warning("The washing machine is full!")) return ITEM_INTERACT_BLOCKING if(!user.transferItemToLoc(item, src)) @@ -360,6 +377,7 @@ GLOBAL_LIST_INIT(dye_registry, list( return ITEM_INTERACT_BLOCKING if(item.dye_color) color_source = item + total_load++ update_appearance() return ITEM_INTERACT_SUCCESS @@ -408,7 +426,7 @@ GLOBAL_LIST_INIT(dye_registry, list( if(HAS_TRAIT(user, TRAIT_BRAINWASHING)) ADD_TRAIT(src, TRAIT_BRAINWASHING, SKILLCHIP_TRAIT) update_appearance() - addtimer(CALLBACK(src, PROC_REF(wash_cycle)), 20 SECONDS) + addtimer(CALLBACK(src, PROC_REF(wash_cycle), user), time_to_wash) START_PROCESSING(SSfastprocess, src) return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN @@ -422,3 +440,4 @@ GLOBAL_LIST_INIT(dye_registry, list( . = ..() set_density(TRUE) //because machinery/open_machine() sets it to FALSE color_source = null + total_load = 0 diff --git a/code/game/objects/items/circuitboards/machines/machine_circuitboards.dm b/code/game/objects/items/circuitboards/machines/machine_circuitboards.dm index 260e1e87a592..82f564b33140 100644 --- a/code/game/objects/items/circuitboards/machines/machine_circuitboards.dm +++ b/code/game/objects/items/circuitboards/machines/machine_circuitboards.dm @@ -1651,3 +1651,23 @@ /datum/stock_part/capacitor = 2, /datum/stock_part/micro_laser = 2, /obj/item/stack/sheet/glass = 1) + +// /obj/item/circuitboard/machine/atmos_shield_gen +// name = /obj/machinery/atmos_shield_gen::name +// greyscale_colors = CIRCUIT_COLOR_ENGINEERING +// build_path = /obj/machinery/atmos_shield_gen +// req_components = list( +// /datum/stock_part/micro_laser = 1, +// /datum/stock_part/capacitor = 1, +// ) + +/obj/item/circuitboard/machine/washing_machine + name = "Washing Machine" + greyscale_colors = CIRCUIT_COLOR_SERVICE + build_path = /obj/machinery/washing_machine + req_components = list( + /obj/item/stack/sheet/glass = 1, + /obj/item/reagent_containers/cup/beaker = 2, + /datum/stock_part/water_recycler = 1, + /datum/stock_part/servo = 1, + ) diff --git a/code/game/objects/items/devices/flashlight.dm b/code/game/objects/items/devices/flashlight.dm index c0ea987aaca4..fa2d8ada6435 100644 --- a/code/game/objects/items/devices/flashlight.dm +++ b/code/game/objects/items/devices/flashlight.dm @@ -17,7 +17,10 @@ w_class = WEIGHT_CLASS_SMALL obj_flags = CONDUCTS_ELECTRICITY slot_flags = ITEM_SLOT_BELT - custom_materials = list(/datum/material/iron= SMALL_MATERIAL_AMOUNT * 0.5, /datum/material/glass= SMALL_MATERIAL_AMOUNT * 0.2) + custom_materials = list( + /datum/material/iron = SMALL_MATERIAL_AMOUNT * 0.5, + /datum/material/glass = SMALL_MATERIAL_AMOUNT * 0.2, + ) actions_types = list(/datum/action/item_action/toggle_light) action_slots = ALL light_system = OVERLAY_LIGHT_DIRECTIONAL @@ -435,7 +438,11 @@ var/trash_type = /obj/item/trash/flare /// If the light source can be extinguished var/can_be_extinguished = FALSE - custom_materials = list(/datum/material/plastic= SMALL_MATERIAL_AMOUNT * 0.5) + custom_materials = list( + /datum/material/iron = SMALL_MATERIAL_AMOUNT * 0.5, + /datum/material/plasma = SMALL_MATERIAL_AMOUNT * 0.5, + /datum/material/plastic = SMALL_MATERIAL_AMOUNT * 0.5, + ) /obj/item/flashlight/flare/Initialize(mapload) . = ..() @@ -693,6 +700,26 @@ slot_flags = null trash_type = /obj/effect/decal/cleanable/ash can_be_extinguished = TRUE + custom_materials = list(/datum/material/wood = SMALL_MATERIAL_AMOUNT*0.5) + +/obj/item/flashlight/flare/torch/on + start_on = TRUE + +/obj/item/flashlight/flare/torch/everburning + name = "everburning torch" + desc = "A torch which burns continuously, even in the vacuum of space" + can_be_extinguished = FALSE + fuel = INFINITY + randomize_fuel = FALSE + start_on = TRUE + custom_materials = null + +/obj/item/flashlight/flare/torch/red + color = "#ff0000" + light_range = 2 + +/obj/item/flashlight/flare/torch/red/on + start_on = TRUE /obj/item/flashlight/lantern name = "lantern" @@ -817,6 +844,7 @@ /// How many seconds of fuel we have left var/fuel = 0 ignore_base_color = TRUE + custom_materials = null /obj/item/flashlight/glowstick/Initialize(mapload) fuel = rand(50 MINUTES, 60 MINUTES) diff --git a/code/game/objects/items/food/burgers.dm b/code/game/objects/items/food/burgers.dm index 95b40f03d32a..0daa1bccdc34 100644 --- a/code/game/objects/items/food/burgers.dm +++ b/code/game/objects/items/food/burgers.dm @@ -659,6 +659,12 @@ tastes = list("bun" = 2, "beef patty" = 4, "cheese" = 2, "beef soaked in chili" = 3, "a smoking flare" = 2) foodtypes = GRAIN | MEAT | DAIRY | VEGETABLES crafting_complexity = FOOD_COMPLEXITY_4 + custom_materials = list( + /datum/material/meat = MEATDISH_MATERIAL_AMOUNT * 2, + /datum/material/iron = SMALL_MATERIAL_AMOUNT * 0.5, + /datum/material/plasma = SMALL_MATERIAL_AMOUNT * 0.5, + /datum/material/plastic = SMALL_MATERIAL_AMOUNT * 0.5, + ) /obj/item/food/burger/crazy/Initialize(mapload) . = ..() diff --git a/code/game/objects/items/stacks/sheets/mineral.dm b/code/game/objects/items/stacks/sheets/mineral.dm index 7a137cde9a4b..cf78ac563bab 100644 --- a/code/game/objects/items/stacks/sheets/mineral.dm +++ b/code/game/objects/items/stacks/sheets/mineral.dm @@ -437,6 +437,7 @@ GLOBAL_LIST_INIT(adamantine_recipes, list( GLOBAL_LIST_INIT(abductor_recipes, list ( \ new/datum/stack_recipe("alien bed", /obj/structure/bed/abductor, 2, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \ new/datum/stack_recipe("alien locker", /obj/structure/closet/abductor, 2, time = 2 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \ + new/datum/stack_recipe("strange closet", /obj/structure/closet/acloset, 2, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_CONTAINERS), \ new/datum/stack_recipe("alien table frame", /obj/structure/table_frame/abductor, 1, time = 2 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \ new/datum/stack_recipe("alien airlock assembly", /obj/structure/door_assembly/door_assembly_abductor, 4, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_DOORS), \ null, \ diff --git a/code/game/objects/items/stacks/sheets/sheet_types.dm b/code/game/objects/items/stacks/sheets/sheet_types.dm index 908cc0d4f7b8..d507c41e6652 100644 --- a/code/game/objects/items/stacks/sheets/sheet_types.dm +++ b/code/game/objects/items/stacks/sheets/sheet_types.dm @@ -272,6 +272,7 @@ GLOBAL_LIST_INIT(plasteel_recipes, list ( \ new/datum/stack_recipe("bomb assembly", /obj/machinery/syndicatebomb/empty, 10, time = 5 SECONDS, crafting_flags = NONE, category = CAT_CHEMISTRY), new/datum/stack_recipe("Large Gas Tank", /obj/structure/tank_frame, 4, time=1 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF, category = CAT_ATMOSPHERIC), new/datum/stack_recipe("shutter assembly", /obj/machinery/door/poddoor/shutters/preopen/deconstructed, 5, time = 5 SECONDS, crafting_flags = CRAFT_ONE_PER_TURF, category = CAT_DOORS), + new/datum/stack_recipe("large metal box", /obj/structure/closet/cardboard/metal, 4, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_CONTAINERS), null, new /datum/stack_recipe_list("airlock assemblies", list( \ new/datum/stack_recipe("high security airlock assembly", /obj/structure/door_assembly/door_assembly_highsecurity, 4, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_DOORS), @@ -336,6 +337,7 @@ GLOBAL_LIST_INIT(wood_recipes, list ( \ new/datum/stack_recipe("wooden barrel", /obj/structure/fermenting_barrel, 8, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_CONTAINERS), \ new/datum/stack_recipe("dog bed", /obj/structure/bed/dogbed, 10, time = 1 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \ new/datum/stack_recipe("dresser", /obj/structure/dresser, 10, time = 1.5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \ + new/datum/stack_recipe("cabinet", /obj/structure/closet/cabinet, 2, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_CONTAINERS), \ new/datum/stack_recipe("picture frame", /obj/item/wallframe/picture, 1, time = 1 SECONDS, crafting_flags = NONE, category = CAT_ENTERTAINMENT),\ new/datum/stack_recipe("painting frame", /obj/item/wallframe/painting, 1, time = 1 SECONDS, crafting_flags = NONE, category = CAT_ENTERTAINMENT),\ new/datum/stack_recipe("display case chassis", /obj/structure/displaycase_chassis, 5, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \ diff --git a/code/modules/research/designs/autolathe/multi-department_designs.dm b/code/modules/research/designs/autolathe/multi-department_designs.dm index b6cc72951134..8e88f505b603 100644 --- a/code/modules/research/designs/autolathe/multi-department_designs.dm +++ b/code/modules/research/designs/autolathe/multi-department_designs.dm @@ -9,6 +9,21 @@ RND_CATEGORY_TOOLS + RND_SUBCATEGORY_TOOLS_MISC, ) +/datum/design/flare + name = "Flare" + id = "flare" + build_type = AUTOLATHE | PROTOLATHE | AWAY_LATHE + materials = list( + /datum/material/iron = SMALL_MATERIAL_AMOUNT * 0.5, + /datum/material/plasma = SMALL_MATERIAL_AMOUNT * 0.5, + /datum/material/plastic = SMALL_MATERIAL_AMOUNT * 0.5, + ) + build_path = /obj/item/flashlight/flare + category = list( + RND_CATEGORY_INITIAL, + RND_CATEGORY_TOOLS + RND_SUBCATEGORY_TOOLS_MISC, + ) + /datum/design/crowbar name = "Pocket Crowbar" id = "crowbar" diff --git a/code/modules/research/designs/machine_designs.dm b/code/modules/research/designs/machine_designs.dm index 74df51e520c2..1d9f38bbb9d4 100644 --- a/code/modules/research/designs/machine_designs.dm +++ b/code/modules/research/designs/machine_designs.dm @@ -1202,3 +1202,33 @@ RND_CATEGORY_MACHINE + RND_SUBCATEGORY_MACHINE_CARGO ) departmental_flags = DEPARTMENT_BITFLAG_CARGO | DEPARTMENT_BITFLAG_ENGINEERING + +// /datum/design/board/photopcopier +// name = "Photocopier" +// desc = "The circuit for a photocopier." +// id = "photocopier" +// build_path = /obj/item/circuitboard/machine/photocopier +// category = list( +// RND_CATEGORY_MACHINE + RND_SUBCATEGORY_MACHINE_SERVICE +// ) +// departmental_flags = DEPARTMENT_BITFLAG_CARGO | DEPARTMENT_BITFLAG_SERVICE + +// /datum/design/board/atmosshieldgen +// name = "Atmospherics Shield Generator Board" +// desc = "The circuit board for an atmospherics shield generator." +// id = "atmosshieldgen" +// build_path = /obj/item/circuitboard/machine/atmos_shield_gen +// category = list( +// RND_CATEGORY_MACHINE + RND_SUBCATEGORY_MACHINE_ATMOS +// ) +// departmental_flags = DEPARTMENT_BITFLAG_SCIENCE | DEPARTMENT_BITFLAG_ENGINEERING + +/datum/design/board/washing_machine + name = "Washing Machine" + desc = "The circuit board to build a washing machine." + id = "washing_machine" + build_path = /obj/item/circuitboard/machine/washing_machine + category = list( + RND_CATEGORY_MACHINE + RND_SUBCATEGORY_MACHINE_SERVICE + ) + departmental_flags = DEPARTMENT_BITFLAG_SERVICE diff --git a/code/modules/research/techweb/nodes/service_nodes.dm b/code/modules/research/techweb/nodes/service_nodes.dm index 125b3fef0563..22729bd1777e 100644 --- a/code/modules/research/techweb/nodes/service_nodes.dm +++ b/code/modules/research/techweb/nodes/service_nodes.dm @@ -33,6 +33,7 @@ "normtrash", "wirebrush", "flashlight", + "flare", "water_balloon", "ticket_machine", "radio_entertainment", @@ -52,6 +53,7 @@ "beartrap", "buffer", "vacuum", + "washing_machine", ) research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_2_POINTS) discount_experiments = list(/datum/experiment/scanning/random/janitor_trash = TECHWEB_TIER_2_POINTS) From d75c645ed61a2a5d197632bbe7996c1055301c8d Mon Sep 17 00:00:00 2001 From: Tim Date: Sun, 8 Jun 2025 11:09:56 -0500 Subject: [PATCH 05/10] Photocopier Improvements (#91258) --- .../lavaland_surface_syndicate_base1.dmm | 2 +- .../SpaceRuins/allamericandiner.dmm | 2 +- .../SpaceRuins/derelict_sulaco.dmm | 2 +- _maps/RandomRuins/SpaceRuins/hellfactory.dmm | 2 +- .../SpaceRuins/hilbertresearchfacility.dmm | 2 +- _maps/RandomRuins/SpaceRuins/meatderelict.dmm | 2 +- .../SpaceRuins/originalcontent.dmm | 2 +- _maps/RandomRuins/SpaceRuins/waystation.dmm | 4 +- .../map_files/Deltastation/DeltaStation2.dmm | 46 +- .../map_files/IceBoxStation/IceBoxStation.dmm | 20 +- _maps/map_files/KiloStation/KiloStation.dmm | 20 +- _maps/map_files/LimaStation/LimaStation.dmm | 22 +- _maps/map_files/MetaStation/MetaStation.dmm | 22 +- .../map_files/NebulaStation/NebulaStation.dmm | 40 +- _maps/map_files/NorthStar/north_star.dmm | 20 +- _maps/map_files/OmegaStation/OmegaStation.dmm | 20 +- _maps/map_files/PubbyStation/PubbyStation.dmm | 20 +- _maps/map_files/generic/CentCom.dmm | 6 +- .../secbarupper_attachment_a_1.dmm | 2 +- _maps/map_files/tramstation/tramstation.dmm | 14 +- _maps/shuttles/emergency_monastery.dmm | 2 +- _maps/shuttles/pirate_irs.dmm | 2 +- _maps/templates/lazy_templates/ninja_den.dmm | 2 +- _maps/virtual_domains/meta_central.dmm | 2 +- .../machines/machine_circuitboards.dm | 10 + code/modules/paperwork/paper.dm | 5 + code/modules/paperwork/photocopier.dm | 437 +++++++++++++----- tgui/packages/tgui/interfaces/Photocopier.tsx | 38 +- .../Scripts/90685_buildable_photocopiers.txt | 1 + 29 files changed, 525 insertions(+), 244 deletions(-) create mode 100644 tools/UpdatePaths/Scripts/90685_buildable_photocopiers.txt diff --git a/_maps/RandomRuins/LavaRuins/lavaland_surface_syndicate_base1.dmm b/_maps/RandomRuins/LavaRuins/lavaland_surface_syndicate_base1.dmm index 6c58eaa8c8fb..32e76893cd9d 100644 --- a/_maps/RandomRuins/LavaRuins/lavaland_surface_syndicate_base1.dmm +++ b/_maps/RandomRuins/LavaRuins/lavaland_surface_syndicate_base1.dmm @@ -1305,7 +1305,7 @@ /obj/effect/turf_decal/tile/brown{ dir = 1 }, -/obj/machinery/photocopier/gratis, +/obj/machinery/photocopier/gratis/prebuilt, /turf/open/floor/iron, /area/ruin/syndicate_lava_base/cargo) "gQ" = ( diff --git a/_maps/RandomRuins/SpaceRuins/allamericandiner.dmm b/_maps/RandomRuins/SpaceRuins/allamericandiner.dmm index c0125ed5398d..c9da64d2e8c3 100644 --- a/_maps/RandomRuins/SpaceRuins/allamericandiner.dmm +++ b/_maps/RandomRuins/SpaceRuins/allamericandiner.dmm @@ -371,7 +371,7 @@ /turf/open/floor/iron, /area/ruin/space/has_grav/allamericandiner) "tg" = ( -/obj/machinery/photocopier/gratis, +/obj/machinery/photocopier/gratis/prebuilt, /obj/structure/sign/flag/ssc/directional/north, /obj/effect/decal/cleanable/dirt, /turf/open/floor/iron/grimy, diff --git a/_maps/RandomRuins/SpaceRuins/derelict_sulaco.dmm b/_maps/RandomRuins/SpaceRuins/derelict_sulaco.dmm index 995a736c620e..498a13896021 100644 --- a/_maps/RandomRuins/SpaceRuins/derelict_sulaco.dmm +++ b/_maps/RandomRuins/SpaceRuins/derelict_sulaco.dmm @@ -589,7 +589,7 @@ /turf/open/floor/iron/showroomfloor, /area/ruin/space/has_grav/derelictsulaco) "tp" = ( -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/pod/light, diff --git a/_maps/RandomRuins/SpaceRuins/hellfactory.dmm b/_maps/RandomRuins/SpaceRuins/hellfactory.dmm index 5e2038ac70a1..aa9b462d2c6d 100644 --- a/_maps/RandomRuins/SpaceRuins/hellfactory.dmm +++ b/_maps/RandomRuins/SpaceRuins/hellfactory.dmm @@ -182,7 +182,7 @@ /turf/open/floor/plastic, /area/ruin/space/has_grav/hellfactory) "aE" = ( -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /turf/open/floor/iron/grimy, /area/ruin/space/has_grav/hellfactoryoffice) "aF" = ( diff --git a/_maps/RandomRuins/SpaceRuins/hilbertresearchfacility.dmm b/_maps/RandomRuins/SpaceRuins/hilbertresearchfacility.dmm index c338834ad7c3..e83499a74091 100644 --- a/_maps/RandomRuins/SpaceRuins/hilbertresearchfacility.dmm +++ b/_maps/RandomRuins/SpaceRuins/hilbertresearchfacility.dmm @@ -1635,7 +1635,7 @@ /turf/open/floor/engine, /area/ruin/space/has_grav/powered/hilbertresearchfacility) "Lr" = ( -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /turf/open/floor/wood, /area/ruin/space/has_grav/powered/hilbertresearchfacility) "Lw" = ( diff --git a/_maps/RandomRuins/SpaceRuins/meatderelict.dmm b/_maps/RandomRuins/SpaceRuins/meatderelict.dmm index 3e4bece11e8e..7e1fcc4803b3 100644 --- a/_maps/RandomRuins/SpaceRuins/meatderelict.dmm +++ b/_maps/RandomRuins/SpaceRuins/meatderelict.dmm @@ -2324,7 +2324,7 @@ /turf/open/indestructible/meat, /area/ruin/space/has_grav/powered/biooutpost/vault) "Ue" = ( -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /obj/effect/turf_decal/tile/purple/opposingcorners, /turf/open/indestructible/white, /area/ruin/space/has_grav/powered/biooutpost) diff --git a/_maps/RandomRuins/SpaceRuins/originalcontent.dmm b/_maps/RandomRuins/SpaceRuins/originalcontent.dmm index ea2ca46c0921..d2cf049c0a57 100644 --- a/_maps/RandomRuins/SpaceRuins/originalcontent.dmm +++ b/_maps/RandomRuins/SpaceRuins/originalcontent.dmm @@ -840,7 +840,7 @@ /obj/structure/fluff/paper{ dir = 10 }, -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /turf/open/indestructible/paper, /area/ruin/space/has_grav/powered) "cq" = ( diff --git a/_maps/RandomRuins/SpaceRuins/waystation.dmm b/_maps/RandomRuins/SpaceRuins/waystation.dmm index 5642e9b85c3c..022e4889c46e 100644 --- a/_maps/RandomRuins/SpaceRuins/waystation.dmm +++ b/_maps/RandomRuins/SpaceRuins/waystation.dmm @@ -218,7 +218,7 @@ /area/ruin/space/has_grav/waystation/cargobay) "ea" = ( /obj/effect/turf_decal/tile/brown/half/contrasted, -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /obj/effect/decal/cleanable/dirt, /turf/open/floor/iron, /area/ruin/space/has_grav/waystation/cargooffice) @@ -946,7 +946,7 @@ /turf/open/floor/iron, /area/ruin/space/has_grav/waystation/dorms) "pl" = ( -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /turf/open/floor/iron/grimy, /area/ruin/space/has_grav/waystation/qm) "pm" = ( diff --git a/_maps/map_files/Deltastation/DeltaStation2.dmm b/_maps/map_files/Deltastation/DeltaStation2.dmm index 6a77ae8388d7..8d69c91deff6 100644 --- a/_maps/map_files/Deltastation/DeltaStation2.dmm +++ b/_maps/map_files/Deltastation/DeltaStation2.dmm @@ -1586,7 +1586,7 @@ /area/station/security/checkpoint/arrivals) "amx" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /obj/machinery/button/door/directional/east{ id = "left_arrivals_shutters"; name = "Left Arrivals Hallway Shutters"; @@ -8531,7 +8531,7 @@ /turf/open/floor/iron/dark, /area/station/security/detectives_office) "bJm" = ( -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /obj/machinery/status_display/ai/directional/north, /obj/structure/reagent_dispensers/wall/peppertank/directional/east, /obj/effect/turf_decal/bot_white, @@ -17527,7 +17527,7 @@ dir = 8 }, /obj/machinery/airalarm/directional/south, -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /turf/open/floor/iron/white, /area/station/science/research) "ddW" = ( @@ -18773,7 +18773,7 @@ name = "medbay camera"; network = list("ss13","medbay") }, -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /turf/open/floor/iron/white, /area/station/medical/medbay) "dlO" = ( @@ -28526,7 +28526,7 @@ /turf/open/floor/iron, /area/station/hallway/primary/central/aft) "ffd" = ( -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /obj/machinery/requests_console/directional/north{ department = "Head of Security's Desk"; name = "Head of Security's Requests Console" @@ -32609,7 +32609,7 @@ /area/station/ai_monitored/turret_protected/aisat_interior) "goP" = ( /obj/item/radio/intercom/directional/north, -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /turf/open/floor/iron/checker, /area/station/hallway/secondary/service) "goR" = ( @@ -41737,7 +41737,7 @@ /turf/open/floor/iron, /area/station/hallway/secondary/entry) "iKf" = ( -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /obj/item/radio/intercom/directional/east, /turf/open/floor/carpet/royalblack, /area/station/service/chapel/office) @@ -45268,7 +45268,7 @@ /turf/open/floor/iron/dark, /area/station/command/heads_quarters/ce) "jNF" = ( -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /obj/effect/turf_decal/bot_white, /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron/dark, @@ -50708,7 +50708,7 @@ /obj/effect/decal/cleanable/cobweb, /obj/effect/decal/cleanable/dirt, /obj/effect/decal/cleanable/dirt, -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /obj/item/newspaper{ pixel_x = 3; pixel_y = 3 @@ -51895,7 +51895,7 @@ /turf/open/floor/iron, /area/station/commons/storage/tools) "lEN" = ( -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /obj/machinery/computer/security/telescreen/entertainment/directional/west, /turf/open/floor/wood, /area/station/command/heads_quarters/captain/private) @@ -52695,7 +52695,7 @@ /turf/open/floor/plating, /area/station/maintenance/department/security) "lSF" = ( -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /obj/machinery/computer/security/telescreen/entertainment/directional/north, /turf/open/floor/wood/large, /area/station/service/library) @@ -56419,7 +56419,7 @@ /turf/open/floor/iron, /area/station/engineering/main) "mUF" = ( -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /obj/machinery/power/apc/auto_name/directional/north, /obj/structure/cable, /obj/effect/turf_decal/bot_white, @@ -56697,7 +56697,7 @@ /area/station/command/heads_quarters/rd) "mYI" = ( /obj/machinery/light_switch/directional/north, -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /obj/machinery/light/directional/north, /turf/open/floor/wood, /area/station/command/heads_quarters/captain) @@ -60653,7 +60653,7 @@ /turf/open/floor/iron/dark, /area/station/science/robotics/lab) "ocD" = ( -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /obj/structure/sign/poster/official/work_for_a_future/directional/east, /turf/open/floor/wood, /area/station/command/heads_quarters/hop) @@ -70156,7 +70156,7 @@ /area/station/maintenance/department/science) "qKC" = ( /obj/effect/turf_decal/stripes/white/line, -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /turf/open/floor/wood, /area/station/engineering/break_room) "qKF" = ( @@ -73946,7 +73946,7 @@ /turf/open/floor/iron, /area/station/engineering/atmos) "rPg" = ( -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /obj/effect/decal/cleanable/dirt, /obj/machinery/light/small/broken/directional/south, /turf/open/floor/plating, @@ -77136,7 +77136,7 @@ /area/station/service/kitchen/abandoned) "sKa" = ( /obj/structure/cable, -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /turf/open/floor/wood, /area/station/command/meeting_room/council) "sKd" = ( @@ -78639,7 +78639,7 @@ /area/station/hallway/primary/central/fore) "tiI" = ( /obj/machinery/newscaster/directional/east, -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /obj/effect/turf_decal/bot_white, /obj/machinery/light/small/directional/east, /obj/effect/turf_decal/tile/neutral/fourcorners, @@ -80010,7 +80010,7 @@ /turf/open/floor/iron, /area/station/cargo/storage) "tEy" = ( -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /obj/machinery/status_display/evac/directional/east, /obj/machinery/camera/directional/east{ c_tag = "Lawyer's Office" @@ -80606,7 +80606,7 @@ /turf/open/floor/iron/dark, /area/station/science/genetics) "tMm" = ( -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /obj/item/radio/intercom/directional/south, /obj/effect/turf_decal/box/white, /obj/effect/turf_decal/tile/neutral/fourcorners, @@ -83196,7 +83196,7 @@ /obj/effect/turf_decal/siding/wood{ dir = 4 }, -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /turf/open/floor/iron/grimy, /area/station/commons/vacant_room/office) "uyF" = ( @@ -84305,7 +84305,7 @@ /turf/open/floor/iron/dark, /area/station/engineering/main) "uOw" = ( -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /obj/effect/turf_decal/tile/brown/half/contrasted{ dir = 8 }, @@ -91781,7 +91781,7 @@ /turf/open/floor/iron/dark, /area/station/security/courtroom) "wPU" = ( -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /obj/effect/turf_decal/tile/brown/half/contrasted{ dir = 1 }, diff --git a/_maps/map_files/IceBoxStation/IceBoxStation.dmm b/_maps/map_files/IceBoxStation/IceBoxStation.dmm index 3f2cd29fc509..8fdff6e0d46e 100644 --- a/_maps/map_files/IceBoxStation/IceBoxStation.dmm +++ b/_maps/map_files/IceBoxStation/IceBoxStation.dmm @@ -193,7 +193,7 @@ /area/station/science/xenobiology) "adZ" = ( /obj/effect/turf_decal/tile/brown/fourcorners, -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /turf/open/floor/iron/dark, /area/station/engineering/lobby) "aee" = ( @@ -17599,7 +17599,7 @@ /turf/open/floor/iron, /area/station/hallway/primary/starboard) "fgm" = ( -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /obj/structure/sign/poster/official/random/directional/east, /turf/open/floor/wood, /area/station/service/library) @@ -23772,7 +23772,7 @@ /turf/open/floor/iron, /area/station/hallway/primary/starboard) "hbp" = ( -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /turf/open/floor/wood, /area/station/command/meeting_room) "hbt" = ( @@ -24476,7 +24476,7 @@ /turf/open/openspace, /area/station/science/xenobiology) "hnP" = ( -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /turf/open/floor/iron/cafeteria{ dir = 8 }, @@ -25303,7 +25303,7 @@ }, /area/station/science/research) "hAo" = ( -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /obj/effect/turf_decal/siding/wood/corner, /obj/structure/sign/calendar/directional/west, /turf/open/floor/wood, @@ -28536,7 +28536,7 @@ /obj/structure/disposalpipe/segment{ dir = 5 }, -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /turf/open/floor/iron/white, /area/station/medical/medbay/aft) "iyL" = ( @@ -33506,7 +33506,7 @@ /turf/open/floor/iron, /area/station/hallway/primary/starboard) "kaw" = ( -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /obj/item/radio/intercom/directional/north, /turf/open/floor/iron, /area/station/cargo/office) @@ -61156,7 +61156,7 @@ /area/station/science/ordnance) "sbi" = ( /obj/machinery/newscaster/directional/north, -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /turf/open/floor/iron, /area/station/command/heads_quarters/hop) "sbv" = ( @@ -73360,7 +73360,7 @@ /turf/open/floor/plating, /area/station/maintenance/aft/greater) "vLt" = ( -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /obj/effect/turf_decal/tile/red/half/contrasted{ dir = 8 }, @@ -73954,7 +73954,7 @@ /obj/machinery/light_switch/directional/west{ pixel_y = 5 }, -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /obj/machinery/airalarm/directional/north, /turf/open/floor/wood, /area/station/hallway/secondary/service) diff --git a/_maps/map_files/KiloStation/KiloStation.dmm b/_maps/map_files/KiloStation/KiloStation.dmm index ee1cdc76a9d0..bb4f167d9440 100644 --- a/_maps/map_files/KiloStation/KiloStation.dmm +++ b/_maps/map_files/KiloStation/KiloStation.dmm @@ -831,7 +831,7 @@ /turf/open/floor/plating/airless, /area/space/nearstation) "aeM" = ( -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /obj/effect/turf_decal/tile/neutral{ dir = 4 }, @@ -13162,7 +13162,7 @@ /obj/effect/turf_decal/tile/neutral{ dir = 1 }, -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /obj/effect/turf_decal/bot, /turf/open/floor/iron/dark, /area/station/security/detectives_office) @@ -28199,7 +28199,7 @@ /obj/effect/turf_decal/tile/neutral{ dir = 1 }, -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /obj/effect/turf_decal/tile/blue{ dir = 1 }, @@ -39173,7 +39173,7 @@ /area/station/maintenance/starboard/aft) "imu" = ( /obj/machinery/light/small/directional/west, -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /obj/effect/turf_decal/tile/neutral, /obj/effect/turf_decal/tile/neutral{ dir = 1 @@ -52088,7 +52088,7 @@ /area/station/security/prison/safe) "mAS" = ( /obj/effect/turf_decal/tile/red, -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /obj/structure/sign/poster/official/space_cops/directional/south, /turf/open/floor/iron, /area/station/security/office) @@ -54435,7 +54435,7 @@ /obj/structure/sign/painting/library{ pixel_x = 32 }, -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /obj/item/radio/intercom/directional/south, /obj/effect/turf_decal/box/white, /turf/open/floor/iron/dark, @@ -58767,7 +58767,7 @@ /turf/open/floor/iron, /area/station/cargo/storage) "oMj" = ( -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /obj/effect/turf_decal/tile/neutral{ dir = 4 }, @@ -76110,7 +76110,7 @@ "uou" = ( /obj/machinery/power/apc/auto_name/directional/east, /obj/structure/cable, -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /obj/effect/turf_decal/tile/neutral{ dir = 1 }, @@ -78254,7 +78254,7 @@ /area/station/cargo/warehouse) "vaK" = ( /obj/effect/decal/cleanable/cobweb/cobweb2, -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /obj/item/newspaper{ pixel_x = 4; pixel_y = 4 @@ -86702,7 +86702,7 @@ }, /obj/structure/cable, /obj/machinery/power/apc/auto_name/directional/north, -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /turf/open/floor/iron/dark, /area/station/command/heads_quarters/hos) "xJP" = ( diff --git a/_maps/map_files/LimaStation/LimaStation.dmm b/_maps/map_files/LimaStation/LimaStation.dmm index 2b0f7a1c944e..6a3d4b8040f0 100644 --- a/_maps/map_files/LimaStation/LimaStation.dmm +++ b/_maps/map_files/LimaStation/LimaStation.dmm @@ -5752,7 +5752,7 @@ /area/station/security/lockers) "bTN" = ( /obj/machinery/firealarm/directional/east, -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /turf/open/floor/iron/dark/side{ dir = 4 }, @@ -6917,7 +6917,7 @@ /turf/open/floor/wood, /area/station/service/library) "cra" = ( -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /turf/open/floor/wood, /area/station/service/library) "crf" = ( @@ -10831,7 +10831,7 @@ /obj/structure/secure_safe{ pixel_x = -23 }, -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /turf/open/floor/wood, /area/station/commons/vacant_room/office) "dEN" = ( @@ -17654,7 +17654,7 @@ /turf/open/floor/iron/dark, /area/station/engineering/atmos/experiment_room) "fQB" = ( -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /obj/machinery/newscaster/directional/south, /obj/effect/turf_decal/bot_white, /obj/effect/turf_decal/siding/wood{ @@ -29553,7 +29553,7 @@ /turf/open/floor/iron/grimy, /area/station/service/library) "jEc" = ( -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /obj/machinery/status_display/evac/directional/west, /obj/machinery/firealarm/directional/south, /turf/open/floor/iron/grimy, @@ -39365,7 +39365,7 @@ }, /area/station/service/bar) "mHl" = ( -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /obj/effect/turf_decal/siding/wood{ dir = 1 }, @@ -55167,7 +55167,7 @@ /turf/open/floor/iron/sepia, /area/station/hallway/secondary/service) "rvi" = ( -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /obj/machinery/status_display/supply{ pixel_y = 30 }, @@ -66132,7 +66132,7 @@ /area/station/hallway/secondary/exit) "uMU" = ( /obj/machinery/status_display/ai/directional/west, -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /obj/structure/cable, /obj/effect/turf_decal/bot_white, /turf/open/floor/iron/dark/telecomms, @@ -68714,7 +68714,7 @@ /turf/closed/wall/r_wall, /area/station/medical/abandoned) "vHB" = ( -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /obj/effect/turf_decal/siding/wood{ dir = 4 }, @@ -69387,7 +69387,7 @@ /obj/structure/secure_safe/hos{ pixel_y = 34 }, -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /turf/open/floor/iron/dark, /area/station/command/heads_quarters/hos) "vTG" = ( @@ -73258,7 +73258,7 @@ /turf/open/floor/engine, /area/station/engineering/supermatter) "xfM" = ( -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /obj/effect/turf_decal/trimline/red/filled/line{ dir = 8 }, diff --git a/_maps/map_files/MetaStation/MetaStation.dmm b/_maps/map_files/MetaStation/MetaStation.dmm index fa683179a155..5fbbe49938c2 100644 --- a/_maps/map_files/MetaStation/MetaStation.dmm +++ b/_maps/map_files/MetaStation/MetaStation.dmm @@ -13216,7 +13216,7 @@ /obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ dir = 1 }, -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /obj/item/radio/intercom/directional/south, /turf/open/floor/carpet, /area/station/command/heads_quarters/hos) @@ -17780,7 +17780,7 @@ "eJb" = ( /obj/machinery/airalarm/directional/south, /obj/effect/turf_decal/stripes/corner, -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /obj/effect/turf_decal/tile/yellow/half/contrasted, /turf/open/floor/iron, /area/station/engineering/break_room) @@ -20446,7 +20446,7 @@ /area/station/science/xenobiology) "fFD" = ( /obj/structure/cable, -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /turf/open/floor/carpet, /area/station/command/heads_quarters/hop) "fFJ" = ( @@ -21688,7 +21688,7 @@ /turf/open/floor/carpet, /area/station/service/theater) "gdY" = ( -/obj/machinery/photocopier{ +/obj/machinery/photocopier/prebuilt{ pixel_y = 3 }, /turf/open/floor/wood, @@ -27647,7 +27647,7 @@ /turf/open/floor/iron, /area/station/engineering/atmos) "isH" = ( -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /turf/open/floor/iron/white, /area/station/science/research) "isK" = ( @@ -32142,7 +32142,7 @@ /area/station/maintenance/port/fore) "kjv" = ( /obj/effect/decal/cleanable/cobweb, -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /turf/open/floor/wood, /area/station/service/library) "kjG" = ( @@ -32872,7 +32872,7 @@ /turf/open/floor/iron, /area/station/commons/locker) "kyN" = ( -/obj/machinery/photocopier{ +/obj/machinery/photocopier/prebuilt{ pixel_y = 3 }, /turf/open/floor/iron/dark, @@ -34266,7 +34266,7 @@ /obj/effect/turf_decal/trimline/blue/filled/line{ dir = 5 }, -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /turf/open/floor/iron/white, /area/station/medical/office) "lcd" = ( @@ -54456,7 +54456,7 @@ /turf/open/floor/plating, /area/station/maintenance/port/aft) "sJV" = ( -/obj/machinery/photocopier{ +/obj/machinery/photocopier/prebuilt{ pixel_y = 3 }, /obj/effect/turf_decal/tile/red/half/contrasted{ @@ -54635,7 +54635,7 @@ /turf/open/floor/iron/dark, /area/station/service/chapel) "sOr" = ( -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /obj/machinery/camera/directional/east{ c_tag = "Law Office" }, @@ -64771,7 +64771,7 @@ /turf/open/floor/carpet, /area/station/command/heads_quarters/hop) "wNe" = ( -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /obj/effect/turf_decal/tile/brown/anticorner/contrasted{ dir = 8 }, diff --git a/_maps/map_files/NebulaStation/NebulaStation.dmm b/_maps/map_files/NebulaStation/NebulaStation.dmm index a503bca5c450..2f537e54506e 100644 --- a/_maps/map_files/NebulaStation/NebulaStation.dmm +++ b/_maps/map_files/NebulaStation/NebulaStation.dmm @@ -4764,7 +4764,7 @@ /turf/open/floor/iron/dark, /area/station/medical/morgue) "aKP" = ( -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /obj/effect/turf_decal/bot, /obj/structure/sign/calendar/directional/north, /turf/open/floor/iron/dark/textured_large, @@ -7074,7 +7074,7 @@ }, /area/station/engineering/atmos/storage) "bcE" = ( -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /obj/effect/turf_decal/bot_white, /turf/open/floor/iron/dark/textured, /area/station/security/office) @@ -7575,7 +7575,7 @@ dir = 1 }, /obj/effect/turf_decal/siding/wood, -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /obj/item/radio/intercom/directional/north, /turf/open/floor/wood/large, /area/station/security/detectives_office) @@ -28968,7 +28968,7 @@ /obj/effect/turf_decal/siding/wood{ dir = 4 }, -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /obj/machinery/camera/autoname/directional/east, /turf/open/floor/wood/large, /area/station/service/lawoffice) @@ -29263,7 +29263,7 @@ /obj/effect/turf_decal/siding/wood/corner{ dir = 8 }, -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /turf/open/floor/wood/large, /area/station/service/library) "eqr" = ( @@ -32849,7 +32849,7 @@ /turf/open/floor/iron/dark, /area/station/cargo/storage) "eSx" = ( -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /obj/machinery/power/apc/auto_name/directional/north, /obj/structure/cable, /turf/open/floor/iron/dark, @@ -34560,7 +34560,7 @@ /area/station/maintenance/port/aft) "ffC" = ( /obj/effect/turf_decal/siding/wood/end, -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /turf/open/floor/wood/large, /area/station/service/chapel/office) "ffE" = ( @@ -45004,7 +45004,7 @@ /turf/open/floor/iron/dark/textured, /area/station/commons/fitness/recreation) "gIo" = ( -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /obj/effect/turf_decal/siding/wood{ dir = 5 }, @@ -50104,7 +50104,7 @@ dir = 10 }, /obj/machinery/firealarm/directional/south, -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /turf/open/floor/iron/dark, /area/station/cargo/office) "hvR" = ( @@ -70321,7 +70321,7 @@ /turf/open/floor/iron/dark, /area/station/hallway/primary/port) "ksS" = ( -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /obj/structure/sign/flag/ssc/directional/south, /turf/open/floor/iron/dark, /area/station/command/meeting_room) @@ -75122,7 +75122,7 @@ dir = 4 }, /obj/machinery/light_switch/directional/west, -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /turf/open/floor/iron/dark, /area/station/command) "lfg" = ( @@ -82169,7 +82169,7 @@ /obj/effect/turf_decal/siding/wood{ dir = 6 }, -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /turf/open/floor/wood/large, /area/station/command/heads_quarters/ce) "mkx" = ( @@ -84746,7 +84746,7 @@ /obj/effect/turf_decal/siding/thinplating_new/dark/corner{ dir = 4 }, -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /obj/machinery/camera/autoname/directional/south, /turf/open/floor/iron/dark/diagonal, /area/station/engineering/lobby) @@ -99845,7 +99845,7 @@ /obj/effect/turf_decal/siding/wood/corner{ dir = 4 }, -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /turf/open/floor/wood/large, /area/station/service/library/upper) "oQA" = ( @@ -123360,7 +123360,7 @@ /obj/effect/turf_decal/siding/wood{ dir = 9 }, -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /obj/item/toy/figure/hos{ pixel_y = 12; pixel_x = 3 @@ -140328,7 +140328,7 @@ /turf/open/floor/iron/dark, /area/station/hallway/secondary/service) "uVy" = ( -/obj/machinery/photocopier{ +/obj/machinery/photocopier/prebuilt{ pixel_y = 4 }, /obj/effect/turf_decal/siding/wood{ @@ -142364,7 +142364,7 @@ }, /obj/effect/turf_decal/trimline/white/line, /obj/structure/table/reinforced/rglass, -/obj/machinery/photocopier{ +/obj/machinery/photocopier/prebuilt{ pixel_y = 4 }, /turf/open/floor/iron/dark/textured_large, @@ -150554,7 +150554,7 @@ /turf/open/floor/plating, /area/station/maintenance/department/science) "wwD" = ( -/obj/machinery/photocopier{ +/obj/machinery/photocopier/prebuilt{ pixel_y = 3 }, /obj/machinery/newscaster/directional/north, @@ -151376,7 +151376,7 @@ /turf/open/misc/asteroid/airless, /area/space/nearstation) "wCZ" = ( -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /obj/effect/turf_decal/siding/wood{ dir = 6 }, @@ -157183,7 +157183,7 @@ }, /obj/machinery/airalarm/directional/east, /obj/structure/table/glass, -/obj/machinery/photocopier{ +/obj/machinery/photocopier/prebuilt{ pixel_y = 5 }, /turf/open/floor/iron/white, diff --git a/_maps/map_files/NorthStar/north_star.dmm b/_maps/map_files/NorthStar/north_star.dmm index 8aca9bf29ad1..bb83ed43d2c0 100644 --- a/_maps/map_files/NorthStar/north_star.dmm +++ b/_maps/map_files/NorthStar/north_star.dmm @@ -9869,7 +9869,7 @@ /turf/open/floor/iron/white, /area/station/medical/office) "cuK" = ( -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /turf/open/floor/iron/dark, /area/station/command/heads_quarters/hop) "cuL" = ( @@ -41052,7 +41052,7 @@ /turf/open/floor/engine, /area/station/maintenance/floor4/starboard/aft) "kFJ" = ( -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /obj/machinery/camera/autoname/directional/north, /obj/machinery/light_switch/directional/north, /turf/open/floor/wood/tile, @@ -50770,7 +50770,7 @@ }, /area/station/commons/fitness/recreation) "naI" = ( -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /obj/effect/turf_decal/tile/purple/opposingcorners, /turf/open/floor/iron/white, /area/station/science/circuits) @@ -53740,7 +53740,7 @@ /turf/open/floor/iron/dark, /area/station/hallway/floor4/aft) "nMD" = ( -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /turf/open/floor/iron/half{ dir = 1 }, @@ -54640,7 +54640,7 @@ /turf/open/floor/iron, /area/station/hallway/floor3/aft) "nXJ" = ( -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /turf/open/floor/iron/white, /area/station/science/lower) "nXO" = ( @@ -55727,7 +55727,7 @@ "omG" = ( /obj/effect/turf_decal/bot, /obj/effect/turf_decal/bot, -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /turf/open/floor/iron/dark/textured_large, /area/station/service/library/printer) "omK" = ( @@ -57408,7 +57408,7 @@ /turf/open/floor/iron/dark/smooth_large, /area/station/engineering/storage/tech) "oKD" = ( -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /obj/machinery/requests_console/directional/west{ department = "Detective"; name = "Detective Requests Console" @@ -58506,7 +58506,7 @@ "oYL" = ( /obj/machinery/power/apc/auto_name/directional/north, /obj/structure/cable, -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /turf/open/floor/carpet, /area/station/command/heads_quarters/captain) "oYT" = ( @@ -61804,7 +61804,7 @@ }, /obj/structure/window/reinforced/spawner/directional/west, /obj/machinery/status_display/ai/directional/south, -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /turf/open/floor/iron/dark/side{ dir = 8 }, @@ -70343,7 +70343,7 @@ /turf/open/floor/plating, /area/station/maintenance/floor4/port/aft) "sfR" = ( -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /obj/effect/decal/cleanable/dirt, /turf/open/floor/wood/parquet, /area/station/service/lawoffice) diff --git a/_maps/map_files/OmegaStation/OmegaStation.dmm b/_maps/map_files/OmegaStation/OmegaStation.dmm index 77730ecad780..181d04a347bb 100644 --- a/_maps/map_files/OmegaStation/OmegaStation.dmm +++ b/_maps/map_files/OmegaStation/OmegaStation.dmm @@ -360,7 +360,7 @@ /obj/effect/turf_decal/tile/neutral/half/contrasted{ dir = 8 }, -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /turf/open/floor/iron/dark, /area/station/command/bridge) "abn" = ( @@ -1621,7 +1621,7 @@ /turf/open/floor/iron/dark/side, /area/station/command/heads_quarters/hop) "aeL" = ( -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/iron/dark/side, /area/station/command/heads_quarters/hop) @@ -2853,7 +2853,7 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/machinery/newscaster/directional/south, -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /turf/open/floor/iron/grimy, /area/station/command/heads_quarters/captain/private) "ahM" = ( @@ -3630,7 +3630,7 @@ /obj/effect/turf_decal/tile/brown{ dir = 4 }, -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /turf/open/floor/iron, /area/station/cargo/storage) "ajO" = ( @@ -3646,7 +3646,7 @@ /turf/open/floor/plating, /area/station/security/prison) "ajR" = ( -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /obj/machinery/firealarm/directional/west{ pixel_y = -5 }, @@ -7503,7 +7503,7 @@ "atC" = ( /obj/effect/decal/cleanable/cobweb, /obj/effect/mapping_helpers/broken_floor, -/obj/machinery/photocopier/gratis, +/obj/machinery/photocopier/gratis/prebuilt, /obj/machinery/airalarm/directional/west, /turf/open/floor/wood, /area/station/maintenance/department/science) @@ -16940,7 +16940,7 @@ /turf/closed/wall/rust, /area/station/maintenance/department/engine) "aUj" = ( -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /obj/effect/turf_decal/siding/wood{ dir = 8 }, @@ -22521,7 +22521,7 @@ /turf/open/floor/circuit/telecomms, /area/station/science/xenobiology) "bjJ" = ( -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /obj/item/radio/intercom/directional/west, /obj/machinery/computer/security/telescreen/entertainment/directional/south, /turf/open/floor/iron/grimy, @@ -24003,7 +24003,7 @@ /obj/effect/turf_decal/siding/wood{ dir = 4 }, -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /obj/item/newspaper{ pixel_x = 3; pixel_y = 3 @@ -32663,7 +32663,7 @@ /turf/open/floor/iron, /area/station/hallway/primary/central) "qRz" = ( -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /obj/machinery/newscaster/directional/east, /turf/open/floor/carpet/green, /area/station/service/lawoffice) diff --git a/_maps/map_files/PubbyStation/PubbyStation.dmm b/_maps/map_files/PubbyStation/PubbyStation.dmm index 501ef891da57..3091f52612ab 100644 --- a/_maps/map_files/PubbyStation/PubbyStation.dmm +++ b/_maps/map_files/PubbyStation/PubbyStation.dmm @@ -2685,7 +2685,7 @@ /turf/open/floor/iron/large, /area/station/security) "ajp" = ( -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /obj/machinery/computer/security/telescreen/entertainment/directional/north, /turf/open/floor/iron/large, /area/station/security) @@ -7981,7 +7981,7 @@ /turf/open/floor/wood, /area/station/command/heads_quarters/hop) "aBC" = ( -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /obj/machinery/airalarm/directional/north, /turf/open/floor/wood, /area/station/command/heads_quarters/hop) @@ -10460,7 +10460,7 @@ /turf/open/floor/iron, /area/station/commons/storage/art) "aLz" = ( -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /obj/effect/turf_decal/tile/red{ dir = 1 }, @@ -21119,7 +21119,7 @@ /obj/machinery/light_switch/directional/east{ name = "Light Switch" }, -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /turf/open/floor/iron/white, /area/station/command/heads_quarters/cmo) "bDy" = ( @@ -28283,7 +28283,7 @@ /turf/open/floor/plating, /area/station/maintenance/department/chapel/monastery) "ckl" = ( -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /obj/machinery/light/small/directional/west, /turf/open/floor/iron/dark/smooth_large, /area/station/service/library/lounge) @@ -33008,7 +33008,7 @@ /obj/effect/turf_decal/trimline/brown/filled/line, /obj/machinery/power/apc/auto_name/directional/north, /obj/structure/cable, -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /turf/open/floor/iron/dark, /area/station/cargo/sorting) "dWk" = ( @@ -40117,7 +40117,7 @@ /area/station/cargo/storage) "jdj" = ( /obj/structure/disposalpipe/segment, -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /obj/effect/turf_decal/siding/wood/corner{ dir = 8 }, @@ -42600,7 +42600,7 @@ /obj/effect/turf_decal/tile/yellow/half{ dir = 4 }, -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /turf/open/floor/iron/edge{ dir = 4 }, @@ -42979,7 +42979,7 @@ /turf/open/floor/plating, /area/station/maintenance/department/cargo) "lui" = ( -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /turf/open/floor/iron/grimy, /area/station/security/detectives_office) "luA" = ( @@ -59405,7 +59405,7 @@ /turf/open/floor/iron/dark/smooth_edge, /area/station/command/heads_quarters/rd) "wrU" = ( -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /obj/machinery/power/apc/auto_name/directional/west, /obj/structure/cable, /turf/open/floor/wood, diff --git a/_maps/map_files/generic/CentCom.dmm b/_maps/map_files/generic/CentCom.dmm index f0d3d9663262..3930eb7343ea 100644 --- a/_maps/map_files/generic/CentCom.dmm +++ b/_maps/map_files/generic/CentCom.dmm @@ -909,7 +909,7 @@ /turf/open/floor/grass, /area/centcom/central_command_areas/control) "hx" = ( -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /turf/open/floor/iron/grimy, /area/centcom/central_command_areas/briefing) "hz" = ( @@ -2872,7 +2872,7 @@ /turf/open/floor/iron, /area/centcom/central_command_areas/supply) "ou" = ( -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /obj/effect/turf_decal/stripes/line{ dir = 6 }, @@ -4641,7 +4641,7 @@ /turf/open/floor/iron/dark, /area/centcom/central_command_areas/control) "vJ" = ( -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /obj/machinery/button/door/indestructible{ id = "XCCFerry"; name = "Hanger Bay Shutters"; diff --git a/_maps/map_files/tramstation/maintenance_modules/secbarupper_attachment_a_1.dmm b/_maps/map_files/tramstation/maintenance_modules/secbarupper_attachment_a_1.dmm index c709ff932851..e4c4505d62e2 100644 --- a/_maps/map_files/tramstation/maintenance_modules/secbarupper_attachment_a_1.dmm +++ b/_maps/map_files/tramstation/maintenance_modules/secbarupper_attachment_a_1.dmm @@ -85,7 +85,7 @@ /area/station/maintenance/department/security) "Q" = ( /obj/effect/decal/cleanable/dirt, -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /turf/open/floor/iron/smooth, /area/station/maintenance/department/security) "T" = ( diff --git a/_maps/map_files/tramstation/tramstation.dmm b/_maps/map_files/tramstation/tramstation.dmm index 697c14b8f9a8..f38086a022e1 100644 --- a/_maps/map_files/tramstation/tramstation.dmm +++ b/_maps/map_files/tramstation/tramstation.dmm @@ -6241,7 +6241,7 @@ /turf/open/floor/iron/white, /area/station/medical/medbay/central) "bbM" = ( -/obj/machinery/photocopier{ +/obj/machinery/photocopier/prebuilt{ pixel_y = 3 }, /obj/structure/sign/clock/directional/west, @@ -6721,7 +6721,7 @@ /area/station/engineering/atmos/pumproom) "bnh" = ( /obj/item/radio/intercom/directional/north, -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /turf/open/floor/wood, /area/station/service/lawoffice) "bnY" = ( @@ -19880,7 +19880,7 @@ /obj/effect/turf_decal/trimline/purple/filled/line{ dir = 8 }, -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /turf/open/floor/iron/white, /area/station/science/lower) "gbp" = ( @@ -39022,7 +39022,7 @@ /turf/open/floor/iron, /area/station/cargo/sorting) "mNV" = ( -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /turf/open/floor/iron/grimy, /area/station/service/library/lounge) "mOi" = ( @@ -51979,7 +51979,7 @@ /turf/open/floor/iron, /area/station/commons/dorms) "rxN" = ( -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /obj/structure/extinguisher_cabinet/directional/north, /turf/open/floor/wood, /area/station/command/heads_quarters/hop) @@ -61265,7 +61265,7 @@ /area/station/cargo/miningdock) "uHb" = ( /obj/machinery/airalarm/directional/north, -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /obj/effect/turf_decal/tile/brown/fourcorners, /turf/open/floor/iron, /area/station/cargo/sorting) @@ -66266,7 +66266,7 @@ /obj/effect/turf_decal/trimline/dark_green/filled/corner{ dir = 1 }, -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /obj/effect/turf_decal/tile/purple/fourcorners, /turf/open/floor/iron/white, /area/station/science/research) diff --git a/_maps/shuttles/emergency_monastery.dmm b/_maps/shuttles/emergency_monastery.dmm index 07a9ef7acdc6..5f89a426c1a3 100644 --- a/_maps/shuttles/emergency_monastery.dmm +++ b/_maps/shuttles/emergency_monastery.dmm @@ -556,7 +556,7 @@ /area/shuttle/escape) "iB" = ( /obj/machinery/light/small/directional/west, -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /turf/open/floor/iron/dark, /area/shuttle/escape) "iE" = ( diff --git a/_maps/shuttles/pirate_irs.dmm b/_maps/shuttles/pirate_irs.dmm index 82c0ac6185b6..838b0080347b 100644 --- a/_maps/shuttles/pirate_irs.dmm +++ b/_maps/shuttles/pirate_irs.dmm @@ -1721,7 +1721,7 @@ /turf/open/floor/iron, /area/shuttle/pirate) "SQ" = ( -/obj/machinery/photocopier/gratis, +/obj/machinery/photocopier/gratis/prebuilt, /obj/machinery/firealarm/directional/south, /turf/open/floor/iron/white, /area/shuttle/pirate) diff --git a/_maps/templates/lazy_templates/ninja_den.dmm b/_maps/templates/lazy_templates/ninja_den.dmm index 1713ec116bb3..b16e571cc687 100644 --- a/_maps/templates/lazy_templates/ninja_den.dmm +++ b/_maps/templates/lazy_templates/ninja_den.dmm @@ -34,7 +34,7 @@ /turf/open/floor/bamboo/tatami/purple, /area/centcom/central_command_areas/holding) "bH" = ( -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /turf/open/floor/catwalk_floor, /area/centcom/central_command_areas/holding) "bP" = ( diff --git a/_maps/virtual_domains/meta_central.dmm b/_maps/virtual_domains/meta_central.dmm index 024799dcc897..750d22e34700 100644 --- a/_maps/virtual_domains/meta_central.dmm +++ b/_maps/virtual_domains/meta_central.dmm @@ -2174,7 +2174,7 @@ /turf/open/floor/wood, /area/virtual_domain) "rX" = ( -/obj/machinery/photocopier, +/obj/machinery/photocopier/prebuilt, /turf/open/floor/carpet, /area/virtual_domain) "sa" = ( diff --git a/code/game/objects/items/circuitboards/machines/machine_circuitboards.dm b/code/game/objects/items/circuitboards/machines/machine_circuitboards.dm index 82f564b33140..7f290b93178d 100644 --- a/code/game/objects/items/circuitboards/machines/machine_circuitboards.dm +++ b/code/game/objects/items/circuitboards/machines/machine_circuitboards.dm @@ -725,6 +725,16 @@ /datum/stock_part/scanning_module = 1, ) +/obj/item/circuitboard/machine/photocopier + name = "Photocopier" + greyscale_colors = CIRCUIT_COLOR_GENERIC + build_path = /obj/machinery/photocopier + req_components = list( + /datum/stock_part/scanning_module = 1, + /datum/stock_part/micro_laser = 1, + /datum/stock_part/matter_bin = 1 + ) + //Medical /obj/item/circuitboard/machine/chem_dispenser diff --git a/code/modules/paperwork/paper.dm b/code/modules/paperwork/paper.dm index 62f4b8581089..9828633fc2e5 100644 --- a/code/modules/paperwork/paper.dm +++ b/code/modules/paperwork/paper.dm @@ -910,12 +910,17 @@ ) /obj/item/paper/construction + name = "construction paper" + icon = 'icons/effects/random_spawners.dmi' /obj/item/paper/construction/Initialize(mapload) . = ..() + icon = 'icons/obj/service/bureaucracy.dmi' color = pick(COLOR_RED, COLOR_LIME, COLOR_LIGHT_ORANGE, COLOR_DARK_PURPLE, COLOR_FADED_PINK, COLOR_BLUE_LIGHT) + update_appearance() /obj/item/paper/natural + name = "natural paper" color = COLOR_OFF_WHITE /obj/item/paper/crumpled diff --git a/code/modules/paperwork/photocopier.dm b/code/modules/paperwork/photocopier.dm index 56f302acbdc1..b9c6abcab50c 100644 --- a/code/modules/paperwork/photocopier.dm +++ b/code/modules/paperwork/photocopier.dm @@ -32,8 +32,8 @@ /// How much paper is used for making a copy of paperwork. #define PAPERWORK_PAPER_USE 10 -/// Maximum capacity of a photocopier -#define MAX_PAPER_CAPACITY 60 +/// Paper capacity of a matter bin +#define MATTER_BIN_PAPER_CAPACITY 30 /// The maximum amount of copies you can make with one press of the copy button. #define MAX_COPIES_AT_ONCE 10 @@ -62,41 +62,94 @@ GLOBAL_LIST_INIT(paper_blanks, init_paper_blanks()) desc = "Used to copy important documents and anatomy studies." icon = 'icons/obj/service/library.dmi' icon_state = "photocopier" + base_icon_state = "photocopier" density = TRUE power_channel = AREA_USAGE_EQUIP max_integrity = 300 integrity_failure = 0.33 interaction_flags_mouse_drop = NEED_DEXTERITY | ALLOW_RESTING - + circuit = /obj/item/circuitboard/machine/photocopier + + /// The max paper capacity this photocopier can store + var/max_paper_capacity + /// How long it takes to print something in seconds + var/time_to_print + /// How efficent our toner is when printing + var/toner_efficiency /// A reference to a mob on top of the photocopier trying to copy their ass. Null if there is no mob. var/mob/living/ass /// A reference to the toner cartridge that's inserted into the copier. Null if there is no cartridge. var/obj/item/toner/toner_cartridge + /// Type path of toner this photocopier should starts with. Null if he should start without it. + var/obj/item/toner/starting_toner /// How many copies will be printed with one click of the "copy" button. var/num_copies = 1 /// Used with photos. Determines if the copied photo will be in greyscale or color. var/color_mode = PHOTO_COLOR /// Indicates whether the printer is currently busy copying or not. var/busy = FALSE + /// How much does it cost to use this photocopier. + var/usage_cost = PHOTOCOPIER_FEE /// Variable that holds a reference to any object supported for photocopying inside the photocopier var/obj/object_copy /// Variable for the UI telling us how many copies are in the queue. var/copies_left = 0 /// The amount of paper this photocoper starts with. - var/starting_paper = 30 - /// A stack for all the empty paper we have newly inserted (LIFO) + var/starting_paper = 0 + /// The paper loaded into the machine var/list/paper_stack = list() - + /// Type path to the paper that's created when we're initalized + var/created_paper = /obj/item/paper + /// Typecache of objects that can be inserted and scanned into the photocopier for copying + var/static/list/whitelist_scannable_objects = typecacheof(list( + /obj/item/paper, + /obj/item/photo, + /obj/item/documents, + /obj/item/paperwork + )) + /// List of paper types that can be inserted as blank paper + var/static/list/valid_paper_types = list( + /obj/item/paper, + /obj/item/paper/carbon, + /obj/item/paper/construction, + /obj/item/paper/natural, + ) + +/obj/machinery/photocopier/prebuilt + starting_toner = /obj/item/toner + starting_paper = 30 + +/obj/machinery/photocopier/get_save_vars() + . = ..() + . += NAMEOF(src, paper_stack) + return . /obj/machinery/photocopier/Initialize(mapload) . = ..() - toner_cartridge = new(src) setup_components() AddElement(/datum/element/elevation, pixel_shift = 8) //enough to look like your bums are on the machine. + if(starting_paper) + paper_stack[created_paper] = starting_paper + if(starting_toner) + toner_cartridge = new starting_toner(src) /// Simply adds the necessary components for this to function. /obj/machinery/photocopier/proc/setup_components() - AddComponent(/datum/component/payment, PHOTOCOPIER_FEE, SSeconomy.get_dep_account(ACCOUNT_CIV), PAYMENT_CLINICAL) + AddComponent(/datum/component/payment, usage_cost, SSeconomy.get_dep_account(ACCOUNT_CIV), PAYMENT_CLINICAL) + +/obj/machinery/photocopier/RefreshParts() + . = ..() + max_paper_capacity = 0 + for(var/datum/stock_part/matter_bin/matter_bin in component_parts) + max_paper_capacity += MATTER_BIN_PAPER_CAPACITY * matter_bin.tier + + toner_efficiency = 1 + for(var/datum/stock_part/micro_laser/micro_laser in component_parts) + toner_efficiency += micro_laser.tier + + time_to_print = 5 SECONDS + for(var/datum/stock_part/scanning_module/scanning_module in component_parts) + time_to_print -= (scanning_module.tier SECONDS) /obj/machinery/photocopier/Exited(atom/movable/gone, direction) . = ..() @@ -104,20 +157,45 @@ GLOBAL_LIST_INIT(paper_blanks, init_paper_blanks()) object_copy = null if(gone == toner_cartridge) toner_cartridge = null - if(gone in paper_stack) - paper_stack -= gone + +/obj/machinery/photocopier/dump_contents() + var/dump_location = drop_location() + + // object_copy can be a traitor objective, don't qdel + object_copy?.forceMove(dump_location) + toner_cartridge?.forceMove(dump_location) + + for(var/paper_path in paper_stack) + var/paper_amount = paper_stack[paper_path] + if(paper_amount <= 0) + stack_trace("Detected zero or negative [paper_path] amount inside photocopier. There should be at least 1 or more of paper amount inside the list") + continue + + for(var/i in 1 to paper_amount) + var/obj/item/paper/new_paper = new paper_path(dump_location) + if(!new_paper.pixel_y) + new_paper.pixel_y = rand(-3,3) + if(!new_paper.pixel_x) + new_paper.pixel_x = rand(-3,3) + + paper_stack.Remove(paper_path) + + update_appearance() /obj/machinery/photocopier/Destroy() // object_copy can be a traitor objective, don't qdel - if(object_copy) - object_copy.forceMove(drop_location()) + object_copy?.forceMove(drop_location()) QDEL_NULL(toner_cartridge) - QDEL_LIST(paper_stack) - + paper_stack = null ass = null //the mob isn't actually contained and just referenced, no need to delete it. return ..() +/obj/machinery/photocopier/on_deconstruction(disassembled) + if(disassembled) + dump_contents() + return ..() + /obj/machinery/photocopier/examine(mob/user) . = ..() if(object_copy) @@ -147,7 +225,7 @@ GLOBAL_LIST_INIT(paper_blanks, init_paper_blanks()) static_data["blanks"] = blank_infos static_data["categories"] = category_names - static_data["max_paper_count"] = MAX_PAPER_CAPACITY + static_data["max_paper_count"] = max_paper_capacity static_data["max_copies"] = MAX_COPIES_AT_ONCE return static_data @@ -162,9 +240,9 @@ GLOBAL_LIST_INIT(paper_blanks, init_paper_blanks()) data["is_photo"] = TRUE data["color_mode"] = color_mode - if(isAI(user)) + if(HAS_AI_ACCESS(user)) data["isAI"] = TRUE - data["can_AI_print"] = toner_cartridge && (toner_cartridge.charges >= PHOTO_TONER_USE) && (get_paper_count() >= PHOTO_PAPER_USE) + data["can_AI_print"] = toner_cartridge && (toner_cartridge.charges >= PHOTO_TONER_USE) && (get_paper_count(created_paper) >= PHOTO_PAPER_USE) else data["isAI"] = FALSE @@ -175,11 +253,24 @@ GLOBAL_LIST_INIT(paper_blanks, init_paper_blanks()) else data["has_toner"] = FALSE + data["created_paper"] = created_paper + data["paper_stack"] = paper_stack data["paper_count"] = get_paper_count() + var/list/paper_types = list() + for(var/obj/item/paper/paper as anything in valid_paper_types) + paper_types += list(list( + name = paper::name, + icon = paper::icon, + icon_state = paper::icon_state, + amount = paper_stack[paper::type] || 0, + type = paper::type, + )) + data["paper_types"] = paper_types + return data -/obj/machinery/photocopier/ui_act(action, list/params) +/obj/machinery/photocopier/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) . = ..() if(.) return @@ -224,7 +315,7 @@ GLOBAL_LIST_INIT(paper_blanks, init_paper_blanks()) // Remove the paper/photo/document from the photocopier. if("remove") if(object_copy) - remove_photocopy(object_copy, usr) + remove_photocopy(usr, object_copy) object_copy = null else if(check_ass()) to_chat(ass, span_notice("You feel a slight pressure on your ass.")) @@ -272,6 +363,20 @@ GLOBAL_LIST_INIT(paper_blanks, init_paper_blanks()) var/list/blank = GLOB.paper_blanks[params["code"]] do_copies(CALLBACK(src, PROC_REF(make_blank_print), blank), usr, PAPER_PAPER_USE, PAPER_TONER_USE, num_copies) return TRUE + if("select_paper_type") + if(check_busy(usr)) + return FALSE + + var/paper_path = text2path(params["created_paper"]) + + if(!ispath(paper_path, /obj/item/paper)) + return FALSE + + if(!paper_stack[paper_path]) + return FALSE + + created_paper = paper_path + return TRUE /// Returns the color used for the printing operation. If the color is below TONER_LOW_PERCENTAGE, it returns a gray color. /obj/machinery/photocopier/proc/get_toner_color() @@ -286,28 +391,38 @@ GLOBAL_LIST_INIT(paper_blanks, init_paper_blanks()) busy = TRUE update_use_power(ACTIVE_POWER_USE) // fucking god proc - INVOKE_ASYNC(src, PROC_REF(do_copy_loop), copy_cb, user, paper_use, toner_use, copies_amount) + INVOKE_ASYNC(src, PROC_REF(do_copy_loop), user, copy_cb, paper_use, toner_use, copies_amount) + +/obj/machinery/photocopier/emag_act(mob/user, obj/item/card/emag/emag_card) + if(obj_flags & EMAGGED) + return FALSE + obj_flags |= EMAGGED + + playsound(src, SFX_SPARKS, 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) + visible_message(span_warning("Sparks fly out of [src]!")) + balloon_alert(user, "payment system shorted") + return TRUE /** * Will invoke the passed in `copy_cb` callback in 4 second intervals, and charge the user 5 credits for each copy made. * * Arguments: - * * copy_cb - a callback for which proc to call. Should only be one of the `make_x_copy()` procs, such as `make_paper_copy()`. * * user - the mob who clicked copy. + * * copy_cb - a callback for which proc to call. Should only be one of the `make_x_copy()` procs, such as `make_paper_copy()`. * * paper_use - the amount of paper used in this operation * * toner_use - the amount of toner used in this operation * * copies_amount - the amount of copies we should make */ -/obj/machinery/photocopier/proc/do_copy_loop(datum/callback/copy_cb, mob/user, paper_use, toner_use, copies_amount) +/obj/machinery/photocopier/proc/do_copy_loop(mob/user, datum/callback/copy_cb, paper_use, toner_use, copies_amount) var/error_message = null if(!toner_cartridge) copies_amount = 0 error_message = span_warning("An error message flashes across \the [src]'s screen: \"No toner cartridge found. Aborting.\"") - else if(toner_cartridge.charges < toner_use * copies_amount) - copies_amount = FLOOR(toner_cartridge.charges / toner_use, 1) + else if(toner_cartridge.charges < (toner_use / toner_efficiency) * copies_amount) + copies_amount = FLOOR(toner_cartridge.charges / (toner_use / toner_efficiency), 1) error_message = span_warning("An error message flashes across \the [src]'s screen: \"Not enough toner to perform [copies_amount >= 1 ? "full " : ""]operation.\"") - if(get_paper_count() < paper_use * copies_amount) - copies_amount = FLOOR(get_paper_count() / paper_use, 1) + if(get_paper_count(created_paper) < paper_use * copies_amount) + copies_amount = FLOOR(get_paper_count(created_paper) / paper_use, 1) error_message = span_warning("An error message flashes across \the [src]'s screen: \"Not enough paper to perform [copies_amount >= 1 ? "full " : ""]operation.\"") copies_left = copies_amount @@ -317,14 +432,11 @@ GLOBAL_LIST_INIT(paper_blanks, init_paper_blanks()) reset_busy() return - if(attempt_charge(src, user, (copies_amount - 1) * PHOTOCOPIER_FEE) & COMPONENT_OBJ_CANCEL_CHARGE) - reset_busy() - return - if(error_message) to_chat(user, error_message) // if you managed to cancel the copy operation, tough luck. you aren't getting your money back. + var/list/copies_made = list() for(var/i in 1 to copies_amount) if(machine_stat & (BROKEN|NOPOWER)) break @@ -338,13 +450,25 @@ GLOBAL_LIST_INIT(paper_blanks, init_paper_blanks()) break playsound(src, 'sound/machines/printer.ogg', 50, vary = FALSE) - sleep(4 SECONDS) + sleep(time_to_print) // reveal our copied item - copied_obj.forceMove(drop_location()) - give_pixel_offset(copied_obj) + if(!QDELETED(copied_obj)) + copied_obj.forceMove(drop_location()) + give_pixel_offset(copied_obj) + copies_made += copied_obj copies_left-- + if(copies_made.len) + if(!(obj_flags & EMAGGED) && attempt_charge(src, user, (copies_made.len - 1) * usage_cost) & COMPONENT_OBJ_CANCEL_CHARGE) + visible_message( + span_warning("An error message flashes across \the [src]'s screen."), \ + span_warning("Failed to charge bank account. Scrapping copies.") \ + ) + QDEL_LIST(copies_made) + else + to_chat(user, span_warning("Failed to copy object!")) + copies_left = 0 reset_busy() @@ -372,19 +496,36 @@ GLOBAL_LIST_INIT(paper_blanks, init_paper_blanks()) copied_item.pixel_x = copied_item.base_pixel_x + rand(-10, 10) copied_item.pixel_y = copied_item.base_pixel_y + rand(-10, 10) -/// Gets the total amount of paper this printer has stored. -/obj/machinery/photocopier/proc/get_paper_count() - return length(paper_stack) + starting_paper +/** + * Gets the total amount of paper this printer has stored + * + * Returns the amount of paper stored in the photocopier if passed with no args + * If paper_type is supplied will only return the amount of that paper type + * + * Arguments: + * * paper_type - The paper type to check to see quantity stored + */ +/obj/machinery/photocopier/proc/get_paper_count(paper_type) + if(paper_type) + return paper_stack[paper_type] || 0 + + var/total_amount = 0 + for(var/paper_path in paper_stack) + var/paper_amount = paper_stack[paper_path] + if(paper_amount <= 0) + stack_trace("Detected zero or negative [paper_path] amount inside photocopier. There should be at least 1 or more of paper amount inside the list") + continue + + total_amount += paper_amount + + return total_amount /** * Returns an empty paper, used for blanks and paper copies. * Prioritizes `paper_stack`, creates new paper in case `paper_stack` is empty. */ -/obj/machinery/photocopier/proc/get_empty_paper() - var/obj/item/paper/new_paper = pop(paper_stack) - if(new_paper == null && starting_paper > 0) - new_paper = new /obj/item/paper - starting_paper-- +/obj/machinery/photocopier/proc/get_empty_paper(paper_type) + var/obj/item/paper/new_paper = new paper_type() return new_paper /** @@ -392,14 +533,12 @@ GLOBAL_LIST_INIT(paper_blanks, init_paper_blanks()) * This lets us pretend we actually consumed paper when we were actually printing something that wasn't paper. */ /obj/machinery/photocopier/proc/delete_paper(number) - if(number > get_paper_count()) + if(!paper_stack[created_paper] || (number > paper_stack[created_paper])) CRASH("Trying to delete more paper than is stored in the photocopier") - for(var/i in 1 to number) - var/to_delete = pop(paper_stack) - if(to_delete) - qdel(to_delete) - else - starting_paper-- + + paper_stack[created_paper] -= number + if(paper_stack[created_paper] <= 0) + paper_stack.Remove(created_paper) /** * Handles the copying of paper. Transfers all the text, stamps and so on from the old paper, to the copy. @@ -410,8 +549,9 @@ GLOBAL_LIST_INIT(paper_blanks, init_paper_blanks()) if(isnull(paper_copy)) return null - var/obj/item/paper/empty_paper = get_empty_paper() - toner_cartridge.charges -= PAPER_TONER_USE + var/obj/item/paper/empty_paper = get_empty_paper(created_paper) + delete_paper(PAPER_PAPER_USE) + use_toner(PAPER_TONER_USE) var/copy_colour = get_toner_color() @@ -429,7 +569,7 @@ GLOBAL_LIST_INIT(paper_blanks, init_paper_blanks()) return null var/obj/item/photo/copied_pic = new(src, photo.Copy(photo_color == PHOTO_GREYSCALE ? TRUE : FALSE)) delete_paper(PHOTO_PAPER_USE) - toner_cartridge.charges -= PHOTO_TONER_USE + use_toner(PHOTO_TONER_USE) return copied_pic /** @@ -442,7 +582,7 @@ GLOBAL_LIST_INIT(paper_blanks, init_paper_blanks()) return null var/obj/item/documents/photocopy/copied_doc = new(src, document_copy) delete_paper(DOCUMENT_PAPER_USE) - toner_cartridge.charges -= DOCUMENT_TONER_USE + use_toner(DOCUMENT_TONER_USE) return copied_doc /** @@ -460,13 +600,13 @@ GLOBAL_LIST_INIT(paper_blanks, init_paper_blanks()) copied_paperwork.stamp_icon = "paper_stamp-pc" //Override with the photocopy overlay sprite copied_paperwork.add_stamp() delete_paper(PAPERWORK_PAPER_USE) - toner_cartridge.charges -= PAPERWORK_TONER_USE + use_toner(PAPERWORK_TONER_USE) return copied_paperwork /// Handles the copying of blanks. No mutating state, so this should not fail. /obj/machinery/photocopier/proc/make_blank_print(list/blank) var/copy_colour = get_toner_color() - var/obj/item/paper/printblank = get_empty_paper() + var/obj/item/paper/printblank = get_empty_paper(created_paper) var/printname = blank["name"] var/list/printinfo @@ -476,8 +616,7 @@ GLOBAL_LIST_INIT(paper_blanks, init_paper_blanks()) printblank.name = "paper - '[printname]'" printblank.add_raw_text(printinfo, color = copy_colour) printblank.update_appearance() - - toner_cartridge.charges -= PAPER_TONER_USE + use_toner(PAPER_TONER_USE) return printblank /** @@ -489,17 +628,16 @@ GLOBAL_LIST_INIT(paper_blanks, init_paper_blanks()) /obj/machinery/photocopier/proc/make_ass_copy() if(!check_ass()) return null - var/butt_icon_state = ass.get_butt_sprite() - if(isnull(butt_icon_state)) + var/icon/temp_img = ass.get_butt_sprite() + if(isnull(temp_img)) return null - var/icon/temp_img = icon('icons/mob/butts.dmi', butt_icon_state) var/obj/item/photo/copied_ass = new /obj/item/photo(src) var/datum/picture/toEmbed = new(name = "[ass]'s Ass", desc = "You see [ass]'s ass on the photo.", image = temp_img) toEmbed.psize_x = 128 toEmbed.psize_y = 128 copied_ass.set_picture(toEmbed, TRUE, TRUE) delete_paper(ASS_PAPER_USE) - toner_cartridge.charges -= ASS_TONER_USE + use_toner(ASS_TONER_USE) return copied_ass /** @@ -512,60 +650,133 @@ GLOBAL_LIST_INIT(paper_blanks, init_paper_blanks()) * * object - the item we're trying to remove. * * user - the user removing the item. */ -/obj/machinery/photocopier/proc/remove_photocopy(obj/item/object, mob/user) +/obj/machinery/photocopier/proc/remove_photocopy(mob/user, obj/item/object) if(issilicon(user)) object.forceMove(drop_location()) return - try_put_in_hand(object, user) + object.forceMove(user.loc) + user.put_in_hands(object) to_chat(user, span_notice("You take [object] out of [src]. [busy ? "The [src] comes to a halt." : ""]")) +/obj/machinery/photocopier/update_icon_state() + . = ..() + icon_state = panel_open ? "[base_icon_state]2" : base_icon_state + +/obj/machinery/photocopier/screwdriver_act(mob/living/user, obj/item/tool) + return default_deconstruction_screwdriver(user, tool) + +/obj/machinery/photocopier/crowbar_act(mob/living/user, obj/item/tool) + return default_deconstruction_crowbar(user, tool) + /obj/machinery/photocopier/wrench_act(mob/living/user, obj/item/tool) . = ..() default_unfasten_wrench(user, tool) return ITEM_INTERACT_SUCCESS -/obj/machinery/photocopier/attackby(obj/item/object, mob/user, params) - if(istype(object, /obj/item/paper) || istype(object, /obj/item/photo) || istype(object, /obj/item/documents)) - if(istype(object, /obj/item/paper)) - var/obj/item/paper/paper = object - if(paper.is_empty()) - insert_empty_paper(paper, user) - return - insert_copy_object(object, user) +/obj/machinery/photocopier/item_interaction(mob/living/user, obj/item/tool, list/modifiers) + // No infinite paper chain. You need the original paperwork to make more copies. + if(istype(tool, /obj/item/paperwork/photocopy)) + balloon_alert(user, "too blurry!") + to_chat(user, span_warning("The [tool] is far too messy to produce a good copy!")) + return ITEM_INTERACT_FAILURE + + if(istype(tool, /obj/item/paper/paperslip)) + balloon_alert(user, "too small!") + return ITEM_INTERACT_FAILURE + + if(istype(tool, /obj/item/blueprints)) + balloon_alert(user, "too large!") + to_chat(user, span_warning("\The [tool] is too large to put into the copier. You need to find something else to record the document.")) + return ITEM_INTERACT_FAILURE - else if(istype(object, /obj/item/toner)) + if(istype(tool, /obj/item/toner)) if(toner_cartridge) balloon_alert(user, "another cartridge inside!") - return - object.forceMove(src) - toner_cartridge = object - balloon_alert(user, "cartridge inserted") + return ITEM_INTERACT_FAILURE - else if(istype(object, /obj/item/blueprints)) - to_chat(user, span_warning("\The [object] is too large to put into the copier. You need to find something else to record the document.")) - - else if(istype(object, /obj/item/paperwork)) - if(istype(object, /obj/item/paperwork/photocopy)) //No infinite paper chain. You need the original paperwork to make more copies. - to_chat(user, span_warning("The [object] is far too messy to produce a good copy!")) - else - insert_copy_object(object, user) + tool.forceMove(src) + toner_cartridge = tool + balloon_alert(user, "cartridge inserted") + return ITEM_INTERACT_SUCCESS + + if(istype(tool, /obj/item/paperplane)) + balloon_alert(user, "flatten paper first!") + return ITEM_INTERACT_FAILURE + + if(istype(tool, /obj/item/paper)) + var/obj/item/paper/paper = tool + + if(paper.resistance_flags & ON_FIRE) + balloon_alert(user, "paper on fire!") + return ITEM_INTERACT_FAILURE + + if(paper.is_empty()) // if not empty it gets inserted as an object to be copied + if(!has_room_for_paper()) + balloon_alert(user, "cannot hold more paper!") + return ITEM_INTERACT_FAILURE + + insert_empty_paper(user, paper.type) + qdel(paper) + return ITEM_INTERACT_SUCCESS + + if(istype(tool, /obj/item/paper_bin)) + var/obj/item/paper_bin/paper_bin = tool + + if(!paper_bin.total_paper) + balloon_alert(user, "paper bin empty!") + return ITEM_INTERACT_FAILURE + + var/paper_inserted = 0 + for(var/obj/item/paper/stacked_paper in paper_bin.paper_stack) // insert all paper that is already initialized + var/is_empty = stacked_paper.is_empty() + var/is_room = has_room_for_paper() + if(!is_empty || !is_room) + continue + + insert_empty_paper(user, stacked_paper.type, silent=TRUE) + paper_bin.paper_stack -= stacked_paper + paper_bin.total_paper -= 1 + paper_inserted++ + qdel(stacked_paper) + + if(paper_bin.total_paper) // then insert non-initialized paper that is always considered empty paper + var/noninitialized_paper_total = paper_bin.total_paper - length(paper_bin.paper_stack) + var/paper_to_take = min(max_paper_capacity - get_paper_count(), noninitialized_paper_total) + if(paper_to_take) + insert_empty_paper(user, paper_bin.papertype, paper_to_take, silent=TRUE) + paper_inserted += paper_to_take + paper_bin.total_paper -= (paper_to_take) + + if(!paper_inserted && !has_room_for_paper()) // no paper was inserted because it was full + balloon_alert(user, "cannot hold more paper!") + return ITEM_INTERACT_FAILURE + + paper_bin.update_appearance() + // we use silent for insert_empty_paper() so that we don't spam balloon_alerts and instead condense them into one alert here + balloon_alert(user, "[paper_inserted] paper inserted") + return ITEM_INTERACT_SUCCESS + + if(is_type_in_typecache(tool, whitelist_scannable_objects)) + insert_copy_object(user, tool) + return ITEM_INTERACT_SUCCESS + + return NONE + +/// Check if there is enough room to insert paper +/obj/machinery/photocopier/proc/has_room_for_paper(mob/user, amount = 1) + return get_paper_count() < max_paper_capacity /// Proc that handles insertion of empty paper, useful for copying later. -/obj/machinery/photocopier/proc/insert_empty_paper(obj/item/paper/paper, mob/user) - if(istype(paper, /obj/item/paper/paperslip)) - return - if(get_paper_count() >= MAX_PAPER_CAPACITY) - balloon_alert(user, "cannot hold more paper!") - return - if(!user.temporarilyRemoveItemFromInventory(paper)) - return - paper_stack += paper - paper.forceMove(src) - balloon_alert(user, "paper inserted") - -/obj/machinery/photocopier/proc/insert_copy_object(obj/item/object, mob/user) +/obj/machinery/photocopier/proc/insert_empty_paper(mob/user, paper_type, amount = 1, silent = FALSE) + if(!paper_stack[paper_type]) + paper_stack[paper_type] = 0 + paper_stack[paper_type] += amount + if(!silent) + balloon_alert(user, "paper inserted") + +/obj/machinery/photocopier/proc/insert_copy_object(mob/user, obj/item/object) if(!copier_empty()) balloon_alert(user, "scanner tray occupied!") return @@ -578,8 +789,8 @@ GLOBAL_LIST_INIT(paper_blanks, init_paper_blanks()) /obj/machinery/photocopier/atom_break(damage_flag) . = ..() - if(. && toner_cartridge.charges) - new /obj/effect/decal/cleanable/oil(get_turf(src)) + if(. && toner_cartridge?.charges) + new /obj/effect/decal/cleanable/blood/oil(get_turf(src)) toner_cartridge.charges = 0 /obj/machinery/photocopier/mouse_drop_receive(mob/target, mob/user, params) @@ -636,6 +847,12 @@ GLOBAL_LIST_INIT(paper_blanks, init_paper_blanks()) return TRUE return FALSE +/** + * Removes a certain amount of toner that is affected by the efficiency of stock parts + */ +/obj/machinery/photocopier/proc/use_toner(amount) + toner_cartridge.charges -= (amount / toner_efficiency) + /** * Checks if there is an item inserted into the copier or a mob sitting on top of it. * @@ -650,10 +867,11 @@ GLOBAL_LIST_INIT(paper_blanks, init_paper_blanks()) /// Subtype of photocopier that is free to use. /obj/machinery/photocopier/gratis desc = "Does the same important paperwork, but it's free to use! The best type of free." + usage_cost = 0 // it's free! no charge! very cool and gratis-pilled. -/obj/machinery/photocopier/gratis/setup_components() - // it's free! no charge! very cool and gratis-pilled. - AddComponent(/datum/component/payment, 0, SSeconomy.get_dep_account(ACCOUNT_CIV), PAYMENT_CLINICAL) +/obj/machinery/photocopier/gratis/prebuilt + starting_toner = /obj/item/toner + starting_paper = 30 /* * Toner cartridge @@ -663,10 +881,13 @@ GLOBAL_LIST_INIT(paper_blanks, init_paper_blanks()) desc = "A small, lightweight cartridge of Nanotrasen ValueBrand toner. Fits photocopiers and autopainters alike." icon = 'icons/obj/service/bureaucracy.dmi' icon_state = "tonercartridge" - grind_results = list(/datum/reagent/iodine = 40, /datum/reagent/iron = 10) + w_class = WEIGHT_CLASS_SMALL var/charges = 5 var/max_charges = 5 +/obj/item/toner/grind_results() + return list(/datum/reagent/iodine = 40, /datum/reagent/iron = 10) + /obj/item/toner/examine(mob/user) . = ..() . += span_notice("The ink level gauge on the side reads [round(charges / max_charges * 100)]%") @@ -674,16 +895,24 @@ GLOBAL_LIST_INIT(paper_blanks, init_paper_blanks()) /obj/item/toner/large name = "large toner cartridge" desc = "A hefty cartridge of Nanotrasen ValueBrand toner. Fits photocopiers and autopainters alike." - grind_results = list(/datum/reagent/iodine = 90, /datum/reagent/iron = 10) charges = 25 max_charges = 25 +/obj/item/toner/large/grind_results() + return list(/datum/reagent/iodine = 90, /datum/reagent/iron = 10) + /obj/item/toner/extreme name = "extremely large toner cartridge" desc = "Why would ANYONE need THIS MUCH TONER?" charges = 200 max_charges = 200 +/obj/item/toner/infinite + name = "infinite toner cartridge" + desc = "...are you satisfied now?" + charges = INFINITY + max_charges = INFINITY + #undef PHOTOCOPIER_FEE #undef BLANKS_FILE_NAME #undef PAPER_PAPER_USE @@ -691,7 +920,7 @@ GLOBAL_LIST_INIT(paper_blanks, init_paper_blanks()) #undef DOCUMENT_PAPER_USE #undef ASS_PAPER_USE #undef PAPERWORK_PAPER_USE -#undef MAX_PAPER_CAPACITY +#undef MATTER_BIN_PAPER_CAPACITY #undef TONER_CHARGE_LOW_AMOUNT #undef PHOTO_GREYSCALE #undef PHOTO_COLOR diff --git a/tgui/packages/tgui/interfaces/Photocopier.tsx b/tgui/packages/tgui/interfaces/Photocopier.tsx index 40ae11f5dba7..cc8984844639 100644 --- a/tgui/packages/tgui/interfaces/Photocopier.tsx +++ b/tgui/packages/tgui/interfaces/Photocopier.tsx @@ -1,6 +1,7 @@ import { useState } from 'react'; import { Button, + ImageButton, Input, LabeledList, ProgressBar, @@ -30,6 +31,16 @@ type Data = { paper_count: number; max_paper_count: number; blanks: Blank[]; + paper_types: Paper[]; + created_paper: string; +}; + +type Paper = { + name: string; + icon: string; + icon_state: string; + amount: number; + type: string; }; type Blank = { @@ -45,7 +56,7 @@ export const Photocopier = (props) => { return ( @@ -100,6 +111,8 @@ const Status = (props: StatusProps) => { max_toner, paper_count, max_paper_count, + paper_types, + created_paper, } = data; const average_toner = max_toner * 0.66; @@ -166,6 +179,29 @@ const Status = (props: StatusProps) => { {selectedBlank ? selectedBlank : 'Not Selected'} + + + + {paper_types.map((paper) => ( + + + act('select_paper_type', { + created_paper: paper.type, + }) + } + /> + + ))} + + ); diff --git a/tools/UpdatePaths/Scripts/90685_buildable_photocopiers.txt b/tools/UpdatePaths/Scripts/90685_buildable_photocopiers.txt new file mode 100644 index 000000000000..da25320533f7 --- /dev/null +++ b/tools/UpdatePaths/Scripts/90685_buildable_photocopiers.txt @@ -0,0 +1 @@ +/obj/machinery/photocopier : /obj/machinery/photocopier/prebuilt{@OLD} \ No newline at end of file From 13a744ac7b6d0c42139588ba4a6e2ad25bcdbaea Mon Sep 17 00:00:00 2001 From: Ghom <42542238+Ghommie@users.noreply.github.com> Date: Fri, 5 Jun 2026 17:56:23 +0200 Subject: [PATCH 06/10] Personality can now be re-viewed from the mood hud icon (#96341) --- code/datums/mood.dm | 3 ++ code/datums/quirks/_quirk.dm | 42 -------------------- code/game/objects/structures/janitor.dm | 1 + code/modules/mob/living/status_procs.dm | 53 +++++++++++++++++++++++++ 4 files changed, 57 insertions(+), 42 deletions(-) diff --git a/code/datums/mood.dm b/code/datums/mood.dm index f37d116ead8c..206b25a7ab0d 100644 --- a/code/datums/mood.dm +++ b/code/datums/mood.dm @@ -610,6 +610,9 @@ else msg += "• [span_grey("I don't have much of a reaction to anything right now.")]
" + if(LAZYLEN(mob_parent.personalities)) + msg += span_notice("You know yourself to be [mob_parent.get_parsonality_string()].
") + if(LAZYLEN(mob_parent.quirks)) msg += span_notice("You have these quirks: [mob_parent.get_quirk_string(FALSE, CAT_QUIRK_ALL)].") diff --git a/code/datums/quirks/_quirk.dm b/code/datums/quirks/_quirk.dm index 36363d46ab1e..2098400b217c 100644 --- a/code/datums/quirks/_quirk.dm +++ b/code/datums/quirks/_quirk.dm @@ -198,45 +198,3 @@ to_chat(quirk_holder, chat_string) where_items_spawned = null - -/** - * get_quirk_string() is used to get a printable string of all the quirk traits someone has for certain criteria - * - * Arguments: - * * Medical- If we want the long, fancy descriptions that show up in medical records, or if not, just the name - * * Category- Which types of quirks we want to print out. Defaults to everything - * * from_scan- If the source of this call is like a health analyzer or HUD, in which case QUIRK_HIDE_FROM_MEDICAL hides the quirk. - */ -/mob/living/proc/get_quirk_string(medical = FALSE, category = CAT_QUIRK_ALL, from_scan = FALSE, none_text) - var/list/dat = list() - for(var/datum/quirk/candidate as anything in quirks) - if(from_scan && (candidate.quirk_flags & QUIRK_HIDE_FROM_SCAN)) - continue - if(medical && !candidate.medical_record_text) - continue - switch(category) - if(CAT_QUIRK_MAJOR_DISABILITY) - if(candidate.value >= -4) - continue - if(CAT_QUIRK_MINOR_DISABILITY) - if(!ISINRANGE(candidate.value, -4, -1)) - continue - if(CAT_QUIRK_NOTES) - if(candidate.value < 0) - continue - dat += medical ? candidate.medical_record_text : candidate.name - - if(!dat.len) - return isnull(none_text) ? (medical ? "No issues have been declared." : "None") : none_text - return medical ? dat.Join("
") : dat.Join(", ") - -/mob/living/proc/cleanse_quirk_datums() //removes all trait datums - QDEL_LAZYLIST(quirks) - -/mob/living/proc/transfer_quirk_datums(mob/living/to_mob) - // We could be done before the client was moved or after the client was moved - var/datum/preferences/to_pass = client || to_mob.client - - for(var/datum/quirk/quirk as anything in quirks) - quirk.remove_from_current_holder(quirk_transfer = TRUE) - quirk.add_to_holder(to_mob, quirk_transfer = TRUE, client_source = to_pass) diff --git a/code/game/objects/structures/janitor.dm b/code/game/objects/structures/janitor.dm index 4f5bdf281273..0413bcac5398 100644 --- a/code/game/objects/structures/janitor.dm +++ b/code/game/objects/structures/janitor.dm @@ -73,6 +73,7 @@ /obj/structure/mop_bucket/janitorialcart/Initialize(mapload) . = ..() + reagents.maximum_volume *= 2.5 GLOB.janitor_devices += src /obj/structure/mop_bucket/janitorialcart/Destroy() diff --git a/code/modules/mob/living/status_procs.dm b/code/modules/mob/living/status_procs.dm index bdb7ff67c520..4a8dd0b04c9c 100644 --- a/code/modules/mob/living/status_procs.dm +++ b/code/modules/mob/living/status_procs.dm @@ -495,6 +495,51 @@ return quirk return null +/** + * get_quirk_string() is used to get a printable string of all the quirk traits someone has for certain criteria + * + * Arguments: + * * Medical- If we want the long, fancy descriptions that show up in medical records, or if not, just the name + * * Category- Which types of quirks we want to print out. Defaults to everything + * * from_scan- If the source of this call is like a health analyzer or HUD, in which case QUIRK_HIDE_FROM_MEDICAL hides the quirk. + */ +/mob/living/proc/get_quirk_string(medical = FALSE, category = CAT_QUIRK_ALL, from_scan = FALSE, none_text) + var/list/dat = list() + for(var/datum/quirk/candidate as anything in quirks) + if(from_scan && (candidate.quirk_flags & QUIRK_HIDE_FROM_SCAN)) + continue + if(medical && !candidate.medical_record_text) + continue + switch(category) + if(CAT_QUIRK_MAJOR_DISABILITY) + if(candidate.value >= -4) + continue + if(CAT_QUIRK_MINOR_DISABILITY) + if(!ISINRANGE(candidate.value, -4, -1)) + continue + if(CAT_QUIRK_NOTES) + if(candidate.value < 0) + continue + dat += medical ? candidate.medical_record_text : candidate.name + + if(!dat.len) + return isnull(none_text) ? (medical ? "No issues have been declared." : "None") : none_text + return medical ? dat.Join("
") : dat.Join(", ") + +/mob/living/proc/cleanse_quirk_datums() //removes all trait datums + QDEL_LAZYLIST(quirks) + +/mob/living/proc/transfer_quirk_datums(mob/living/to_mob) + // We could be done before the client was moved or after the client was moved + var/datum/preferences/to_pass = client || to_mob.client + + for(var/datum/quirk/quirk as anything in quirks) + if(quirk.quirk_flags & QUIRK_NO_TRANSFER) + continue + quirk.remove_from_current_holder(quirk_transfer = TRUE) + quirk.add_to_holder(to_mob, quirk_transfer = TRUE, client_source = to_pass) + + /// Helper to easily add a personality by a typepath /mob/living/proc/add_personality(personality_type) var/datum/personality/personality = SSpersonalities.personalities_by_type[personality_type] @@ -515,6 +560,14 @@ for(var/personality_type in personalities) remove_personality(personality_type) +/// Returns a string with the names of the personalities of this mob, and their description as tooltip +/mob/living/proc/get_parsonality_string() + var/list/return_list = list() + for(var/personality_type in personalities) + var/datum/personality/personality = SSpersonalities.personalities_by_type[personality_type] + return_list += span_tooltip(personality.desc, personality.name) + return english_list(return_list) + /mob/living/proc/cure_husk(source) REMOVE_TRAIT(src, TRAIT_HUSK, source) if(HAS_TRAIT(src, TRAIT_HUSK)) From ce4ad923d10fbc61931f8c0fc8e68d8e6b428435 Mon Sep 17 00:00:00 2001 From: MrMelbert Date: Mon, 15 Jun 2026 01:21:44 -0500 Subject: [PATCH 07/10] Slight rework to cursed effects --- .../signals_atom/signals_atom_lighting.dm | 15 + code/__DEFINES/dcs/signals/signals_object.dm | 29 ++ code/datums/components/omen.dm | 411 ++++++++++-------- code/datums/quirks/negative_quirks/cursed.dm | 23 +- code/game/machinery/doors/airlock.dm | 5 + code/modules/admin/smites/bad_luck.dm | 13 +- code/modules/power/lighting/light.dm | 11 +- code/modules/vending/_vending.dm | 4 +- 8 files changed, 324 insertions(+), 187 deletions(-) diff --git a/code/__DEFINES/dcs/signals/signals_atom/signals_atom_lighting.dm b/code/__DEFINES/dcs/signals/signals_atom/signals_atom_lighting.dm index 391ed0112ac9..5446ab83fcc2 100644 --- a/code/__DEFINES/dcs/signals/signals_atom/signals_atom_lighting.dm +++ b/code/__DEFINES/dcs/signals/signals_atom/signals_atom_lighting.dm @@ -42,3 +42,18 @@ ///Called when an atom has a light template applied to it. Frombase of [/datum/light_template/proc/mirror_onto]: () #define COMSIG_ATOM_LIGHT_TEMPLATE_MIRRORED "atom_light_template_mirrored" + +///Called when an atom's overlay component applies visuals, from base of [/datum/component/overlay_lighting/proc/show_to_holder]: (image/mask, image/cone, atom/movable/light_holder) +#define COMSIG_ATOM_OVERLAY_LIGHT_APPLIED "atom_overlay_light_applied" +///Above, but send to the holder of the light instead of the light source itself: (image/mask, image/cone, atom/movable/light_source) +#define COMSIG_ATOM_HOLDER_OVERLAY_LIGHT_APPLIED "atom_holder_overlay_light_applied" + +///Called when an atom's overlay component hides its visuals, from base of [/datum/component/overlay_lighting/proc/hide_from_holder]: (atom/movable/light_holder) +#define COMSIG_ATOM_OVERLAY_LIGHT_REMOVED "atom_overlay_light_removed" +///Above, but send to the holder of the light instead of the light source itself: (atom/movable/light_source) +#define COMSIG_ATOM_HOLDER_OVERLAY_LIGHT_REMOVED "atom_holder_overlay_light_removed" + +/// Called when a light fixture is broken, from base of [/obj/machinery/light/break_light_tube]: (was_ok) +#define COMSIG_LIGHT_FIXTURE_BROKEN "light_fixture_broken" +/// Called when a light fixture is toggled on or off, from base of [/obj/machinery/light/toggle_light]: (new_status) +#define COMSIG_LIGHT_FIXTURE_TOGGLED "light_fixture_toggled" diff --git a/code/__DEFINES/dcs/signals/signals_object.dm b/code/__DEFINES/dcs/signals/signals_object.dm index 986e5290186b..ed3ba0553bf9 100644 --- a/code/__DEFINES/dcs/signals/signals_object.dm +++ b/code/__DEFINES/dcs/signals/signals_object.dm @@ -595,3 +595,32 @@ /// Sent from /obj/effect/rune/convert/try_sacrifice_item(obj/effect/rune/convert/rune) #define COMSIG_ITEM_CULT_SACRIFICE "item_cult_sacrifice" #define COMPONENT_SACRIFICE_SUCCESSFUL (1<<0) + +/// Send to items that have been unwrapped from a gift +#define COMSIG_ITEM_OPENED_FROM_GIFT "gift_opened" + +/// From /obj/machinery/vending/ui_interact(): (mob/user, datum/vending_ui/ui) +#define COMSIG_VENDING_UI_INTERACT "vending_ui_interact" + #define VENDING_DENIED (1<<0) + +/// From /obj/machinery/vending/dispense(): (obj/item/vended_item) +#define COMSIG_VENDING_DISPENSED "vending_dispensed" + +/// From /obj/machinery/vending/vend(): (mob/user, obj/machinery/vending_machine, obj/item/vended_item) +#define COMSIG_MOB_VENDING_PURCHASE "mob_vending_purchase" + /// Stops the mob from picking up whatevr they just purchased (it just goes to the floor) + #define VENDING_NO_PICKUP (1<<0) + +/// Sent from /datum/component/reflection when the reflection is updated to the mob reflecting: (atom/movable/reflecting_in, obj/effect/abstract/reflection) +#define COMSIG_REFLECTION_UPDATED "reflection_updated" + +/// Sent from /datum/component/reflection when the reflection is updated to the component parent: (obj/effect/abstract/reflection) +#define COMSIG_REFLECTED_IMAGE_UPDATED "reflected_image_updated" + +/// From /datum/element/weapon_description: (list/readout) +#define COMSIG_ITEM_WEAPON_LABEL_READOUT "item_weapon_label_readout" + +/// Sent from /obj/machinery/door/airlock/close, to a movable blocking it from closing: (obj/machinery/door/being_blocked, force_close, force_crush) +#define COMSIG_MOVABLE_BLOCKING_AIRLOCK "movable_blocking_airlock" + /// Forces the airlock to crush whatever's blocking it even if it normally wouldn't + #define AIRLOCK_BLOCK_FORCE_CRUSH (1<<0) diff --git a/code/datums/components/omen.dm b/code/datums/components/omen.dm index 75cce3ee3d4a..885db5f2714c 100644 --- a/code/datums/components/omen.dm +++ b/code/datums/components/omen.dm @@ -16,22 +16,28 @@ var/luck_mod = 1 /// Base damage from negative events. Cursed take 25% of this damage. var/damage_mod = 1 - -/datum/component/omen/Initialize(obj/vessel, incidents_left, luck_mod, damage_mod) + /// If TRUE being blessed by the chaplain can remove the omen + var/bless_fixable = TRUE + /// Callback invoked on death + var/datum/callback/on_death + /// List of light fixtures nearby - we track their state to see if they break or toggle + VAR_FINAL/list/tracked_lights = list() + +/datum/component/omen/Initialize(obj/vessel, incidents_left = INFINITY, luck_mod = 1, damage_mod = 1, bless_fixable = TRUE, datum/callback/on_death) if(!isliving(parent)) return COMPONENT_INCOMPATIBLE if(istype(vessel)) src.vessel = vessel RegisterSignal(vessel, COMSIG_QDELETING, PROC_REF(vessel_qdeleting)) - if(!isnull(incidents_left)) - src.incidents_left = incidents_left - if(!isnull(luck_mod)) - src.luck_mod = luck_mod - if(!isnull(damage_mod)) - src.damage_mod = damage_mod - ADD_TRAIT(parent, TRAIT_CURSED, SMITE_TRAIT) + src.incidents_left = incidents_left + src.luck_mod = luck_mod + src.damage_mod = damage_mod + src.bless_fixable = bless_fixable + src.on_death = on_death + + ADD_TRAIT(parent, TRAIT_CURSED, REF(src)) /** * This is a omen eat omen world! The stronger omen survives. @@ -52,7 +58,8 @@ /datum/component/omen/Destroy(force) var/mob/living/person = parent - REMOVE_TRAIT(person, TRAIT_CURSED, SMITE_TRAIT) + REMOVE_TRAIT(person, TRAIT_CURSED, REF(src)) + REMOVE_TRAIT(person, TRAIT_NO_MIRROR_REFLECTION, REF(src)) to_chat(person, span_nicegreen("You feel a horrible omen lifted off your shoulders!")) if(vessel) @@ -61,6 +68,9 @@ vessel.burn() vessel = null + for(var/obj/machinery/light/to_untrack as anything in tracked_lights) + untrack_light(to_untrack) + return ..() /datum/component/omen/RegisterWithParent() @@ -68,164 +78,251 @@ RegisterSignal(parent, COMSIG_ON_CARBON_SLIP, PROC_REF(check_slip)) RegisterSignal(parent, COMSIG_CARBON_MOOD_UPDATE, PROC_REF(check_bless)) RegisterSignal(parent, COMSIG_LIVING_DEATH, PROC_REF(check_death)) + RegisterSignal(parent, COMSIG_MOVABLE_BLOCKING_AIRLOCK, PROC_REF(check_airlock_crush)) + RegisterSignal(parent, COMSIG_MOB_VENDING_PURCHASE, PROC_REF(check_vending)) + RegisterSignal(parent, COMSIG_LIVING_LIFE, PROC_REF(on_life)) /datum/component/omen/UnregisterFromParent() - UnregisterSignal(parent, list(COMSIG_ON_CARBON_SLIP, COMSIG_MOVABLE_MOVED, COMSIG_CARBON_MOOD_UPDATE, COMSIG_LIVING_DEATH)) + UnregisterSignal(parent, list( + COMSIG_ON_CARBON_SLIP, + COMSIG_MOVABLE_MOVED, + COMSIG_LIVING_BLESSED, + COMSIG_LIVING_DEATH, + COMSIG_MOVABLE_BLOCKING_AIRLOCK, + COMSIG_MOB_VENDING_PURCHASE, + COMSIG_LIVING_LIFE, + )) /datum/component/omen/proc/consume_omen() + if(incidents_left == INFINITY) + return + incidents_left-- if(incidents_left < 1) qdel(src) -/** - * check_accident() is called each step we take - * - * While we're walking around, roll to see if there's any environmental hazards on one of the adjacent tiles we can trigger. - * We do the prob() at the beginning to A. add some tension for /when/ it will strike, and B. (more importantly) ameliorate the fact that we're checking up to 5 turfs's contents each time - */ -/datum/component/omen/proc/check_accident(atom/movable/our_guy) +/// Roll an accident happening, factoring in a few things, based on some base change. +/datum/component/omen/proc/roll_for_accident(base_chance = 4) + var/chance = base_chance * luck_mod + for(var/mob/viewer in viewers(parent)) + if(!viewer.client?.is_afk()) + chance *= 2 + break + + return prob(chance) + +/// When we obstruct an airlock, there's a chance it will crush us instead of stopping like it should +/datum/component/omen/proc/check_airlock_crush(mob/living/source, obj/machinery/door/airlock/darth_airlock, forced, force_crush) SIGNAL_HANDLER - if(!isliving(our_guy)) + if(force_crush || !roll_for_accident(25)) + return NONE + + consume_omen() + to_chat(parent, span_warning("As you stand in [darth_airlock], it doesn't stop closing like it should...")) + return AIRLOCK_BLOCK_FORCE_CRUSH + +/// When we vend an item from a vending machine, there's a chance the machine will tip +/datum/component/omen/proc/check_vending(mob/living/source, obj/machinery/vending/darth_vendor, obj/item/vended_item) + SIGNAL_HANDLER + + if(!source.Adjacent(darth_vendor) || !roll_for_accident(10)) + return NONE + + consume_omen() + to_chat(source, span_warning("As you grab [vended_item] from the slot, [darth_vendor] wobbles ominously...")) + INVOKE_ASYNC(darth_vendor, TYPE_PROC_REF(/obj/machinery/vending, tilt), source) + return VENDING_NO_PICKUP + +/// On life tick, run a few generic checks for accidents, and track nearby lights +/datum/component/omen/proc/on_life(mob/living/source) + SIGNAL_HANDLER + + if(source.stat == DEAD || HAS_TRAIT(source, TRAIT_STASIS)) return - var/mob/living/living_guy = our_guy + if(roll_for_accident(0.001)) + spontaneous_combustion(source) + return - if(prob(0.001) && (living_guy.stat != DEAD)) // You hit the lottery! Kinda. - living_guy.visible_message(span_danger("[living_guy] suddenly bursts into flames!"), span_danger("You suddenly burst into flames!")) - INVOKE_ASYNC(living_guy, TYPE_PROC_REF(/mob, emote), "scream") - living_guy.adjust_fire_stacks(20) - living_guy.ignite_mob(silent = TRUE) - consume_omen() + if(HAS_TRAIT(source, TRAIT_SHOCKIMMUNE)) + for(var/obj/machinery/light/to_untrack as anything in tracked_lights) + untrack_light(to_untrack) return - var/effective_luck = luck_mod + var/list/light_list = list() + for(var/obj/machinery/light/evil_light in view(2, source)) + if(evil_light.status == LIGHT_OK) + light_list += evil_light + for(var/obj/machinery/light/to_track as anything in light_list - tracked_lights) + track_light(to_track) + for(var/obj/machinery/light/to_untrack as anything in tracked_lights - light_list) + untrack_light(to_untrack) + +/// Start tracking a light, because it's near us and could be a threat +/datum/component/omen/proc/track_light(obj/machinery/light/evil_light) + tracked_lights += evil_light + RegisterSignal(evil_light, COMSIG_LIGHT_FIXTURE_BROKEN, PROC_REF(check_break_zap)) + RegisterSignal(evil_light, COMSIG_LIGHT_FIXTURE_TOGGLED, PROC_REF(check_toggle_zap)) + RegisterSignal(evil_light, COMSIG_QDELETING, PROC_REF(untrack_light)) + +/// Stop tracking a light, either because it broke or we moved away from it +/datum/component/omen/proc/untrack_light(obj/machinery/light/evil_light) + SIGNAL_HANDLER - // If there's nobody to witness the misfortune, make it less likely. - // This way, we allow for people to be able to get into hilarious situations without making the game nigh unplayable most of the time. + tracked_lights -= evil_light + UnregisterSignal(evil_light, list(COMSIG_LIGHT_FIXTURE_BROKEN, COMSIG_LIGHT_FIXTURE_TOGGLED, COMSIG_QDELETING)) - var/has_watchers = FALSE - for(var/mob/viewer in viewers(our_guy, world.view)) - if(viewer.client) - has_watchers = TRUE - break - if(!has_watchers) - effective_luck *= 0.5 +/// When a light we track breaks, there's a chance of zapping us +/datum/component/omen/proc/check_break_zap(obj/machinery/light/evil_light, was_ok) + SIGNAL_HANDLER + + if(was_ok && !HAS_TRAIT(parent, TRAIT_SHOCKIMMUNE) && roll_for_accident(10)) + evil_light.visible_message(span_boldwarning("A bolt of electricity jumps from [evil_light] to [parent] as it breaks!")) + light_zap(evil_light) + consume_omen() + // always untrack because it's broken now + untrack_light(evil_light) - if(!prob(8 * effective_luck)) +/// When a light we track is toggled on or off, there's a chance of zapping us +/datum/component/omen/proc/check_toggle_zap(obj/machinery/light/evil_light, new_status) + SIGNAL_HANDLER + + if(HAS_TRAIT(parent, TRAIT_SHOCKIMMUNE) || !roll_for_accident(20)) return - var/our_guy_pos = get_turf(living_guy) - for(var/obj/machinery/door/airlock/darth_airlock in our_guy_pos) - if(darth_airlock.locked || !darth_airlock.hasPower()) - continue + evil_light.visible_message(span_boldwarning("A bolt of electricity jumps from [evil_light] to [parent] as it turns [new_status ? "on" : "off"]!")) + light_zap(evil_light) + consume_omen() + // we're about to break it, so untrack to avoid a double zap + untrack_light(evil_light) + // and then actually break the thing + evil_light.break_light_tube() + +/// Zap the target with electricity from a light fixture +/datum/component/omen/proc/light_zap(obj/machinery/light/evil_light) + PRIVATE_PROC(TRUE) + + var/mob/living/target = parent + evil_light.Beam(target, icon_state = "lightning[rand(1, 12)]", time = 0.5 SECONDS) + target.electrocute_act(35 * damage_mod, evil_light, flags = SHOCK_NOGLOVES) + INVOKE_ASYNC(target, TYPE_PROC_REF(/mob, emote), "scream") + consume_omen() + +/// Randomly burst into flames +/datum/component/omen/proc/spontaneous_combustion() + var/mob/living/target = parent + target.adjust_fire_stacks(20) + if(!target.ignite_mob(silent = TRUE)) + return FALSE + + target.visible_message( + span_danger("[target] suddenly bursts into flames!"), + span_userdanger("You suddenly burst into flames!"), + ) + INVOKE_ASYNC(target, TYPE_PROC_REF(/mob, emote), "scream") + consume_omen() + return TRUE + +/// Every time we move we need to check a few things for potential incidents +/datum/component/omen/proc/check_accident(mob/living/source) + SIGNAL_HANDLER + + if(mirror_interaction()) + return - to_chat(living_guy, span_warning("A malevolent force launches your body to the floor...")) - living_guy.Paralyze(1 SECONDS, ignore_canstun = TRUE) - INVOKE_ASYNC(src, PROC_REF(slam_airlock), darth_airlock) + if(fall_down()) return - for(var/turf/the_turf as anything in get_adjacent_open_turfs(living_guy)) - if(istype(the_turf, /turf/open/floor/glass/reinforced/tram)) // don't fall off the tram bridge, we want to hit you instead - return - if(living_guy.can_z_move(DOWN, the_turf, z_move_flags = ZMOVE_FALL_FLAGS)) - to_chat(living_guy, span_warning("A malevolent force guides you towards the edge...")) - living_guy.throw_at(the_turf, 1, 10, force = MOVE_FORCE_EXTREMELY_STRONG) - consume_omen() - return - - for(var/obj/machinery/vending/darth_vendor in the_turf) - if(!darth_vendor.tiltable || darth_vendor.tilted) - continue - to_chat(living_guy, span_warning("A malevolent force tugs at the [darth_vendor]...")) - INVOKE_ASYNC(darth_vendor, TYPE_PROC_REF(/obj/machinery/vending, tilt), living_guy) - consume_omen() - return - - for(var/obj/machinery/light/evil_light in the_turf) - if((evil_light.status == LIGHT_BURNED || evil_light.status == LIGHT_BROKEN) || (HAS_TRAIT(living_guy, TRAIT_SHOCKIMMUNE))) // we cant do anything :( // Why in the world is there no get_siemens_coeff proc??? - to_chat(living_guy, span_warning("[evil_light] sparks weakly for a second.")) - do_sparks(2, FALSE, evil_light) // hey maybe it'll ignite them - return - - to_chat(living_guy, span_warning("[evil_light] glows ominously...")) // omenously - evil_light.visible_message(span_boldwarning("[evil_light] suddenly flares brightly and sparks!")) - evil_light.break_light_tube(skip_sound_and_sparks = FALSE) - do_sparks(number = 4, cardinal_only = FALSE, source = evil_light) - evil_light.Beam(living_guy, icon_state = "lightning[rand(1,12)]", time = 0.5 SECONDS) - living_guy.electrocute_act(35 * (damage_mod * 0.5), evil_light, flags = SHOCK_NOGLOVES) - INVOKE_ASYNC(living_guy, TYPE_PROC_REF(/mob, emote), "scream") - consume_omen() - - for(var/obj/structure/mirror/evil_mirror in the_turf) - to_chat(living_guy, span_warning("You pass by the mirror and glance at it...")) - if(evil_mirror.broken) - to_chat(living_guy, span_notice("You feel lucky, somehow.")) - return - switch(rand(1, 5)) - if(1) - to_chat(living_guy, span_warning("The mirror explodes into a million pieces! Wait, does that mean you're even more unlucky?")) - evil_mirror.take_damage(evil_mirror.max_integrity, BRUTE, MELEE, FALSE) - if(prob(50 * effective_luck)) // sometimes - luck_mod += 0.25 - damage_mod += 0.25 - if(2 to 3) - to_chat(living_guy, span_big(span_hypnophrase("Oh god, you can't see your reflection!!"))) - if(HAS_TRAIT(living_guy, TRAIT_NO_MIRROR_REFLECTION)) // not so living i suppose - to_chat(living_guy, span_green("Well, obviously.")) - return - INVOKE_ASYNC(living_guy, TYPE_PROC_REF(/mob, emote), "scream") - - if(4 to 5) - if(HAS_TRAIT(living_guy, TRAIT_NO_MIRROR_REFLECTION)) - to_chat(living_guy, span_warning("You don't see anything of notice. Huh.")) - return - to_chat(living_guy, span_userdanger("You see your reflection, but it is grinning malevolently and staring directly at you!")) - INVOKE_ASYNC(living_guy, TYPE_PROC_REF(/mob, emote), "scream") - - living_guy.set_jitter_if_lower(25 SECONDS) - if(prob(7 * effective_luck)) - to_chat(living_guy, span_warning("You are completely shocked by this turn of events!")) - to_chat(living_guy, span_userdanger("You clutch at your heart!")) - var/mob/living/carbon/carbon_guy = living_guy - if(istype(carbon_guy)) - carbon_guy.set_heartattack(status = TRUE) - - consume_omen() - -/datum/component/omen/proc/slam_airlock(obj/machinery/door/airlock/darth_airlock) - . = darth_airlock.close(force_crush = TRUE) - if(.) +/// Attempts to throw us down a nearby open space +/datum/component/omen/proc/fall_down() + var/mob/living/our_guy = parent + var/turf/open/mob_turf = get_turf(our_guy) + if(isgroundlessturf(mob_turf) || istype(mob_turf, /turf/open/floor/glass/reinforced/tram)) // snowflake check is to increase likelihood of being hit with the tram + return FALSE + + for(var/turf/adjacent_turf as anything in get_adjacent_open_turfs(mob_turf)) + if(!our_guy.can_z_move(DOWN, adjacent_turf, z_move_flags = ZMOVE_FALL_FLAGS)) + continue + if(!roll_for_accident(4)) + return FALSE + + var/obj/structure/railing/rail = locate() in mob_turf + to_chat(our_guy, span_warning("As you step on [mob_turf], you lose footing and fall[rail ? " over the railing and" : ""] off the edge!")) + our_guy.throw_at(adjacent_turf, 1, 10, force = MOVE_FORCE_EXTREMELY_STRONG) consume_omen() + return TRUE + + return FALSE + +/// Gaze into a mirror and see if something bad happens +/datum/component/omen/proc/mirror_interaction() + var/mob/living/our_guy = parent + var/obj/structure/mirror/evil_mirror = locate() in get_turf(our_guy) + if(isnull(evil_mirror) || !roll_for_accident(10)) + REMOVE_TRAIT(our_guy, TRAIT_NO_MIRROR_REFLECTION, REF(src)) + return FALSE + + to_chat(our_guy, span_warning("You pass by the mirror and glance at it...")) + if(evil_mirror.broken) + to_chat(our_guy, span_notice("...You feel lucky, somehow.")) + return TRUE + + switch(rand(1, 5)) + if(1) + to_chat(our_guy, span_warning("...The mirror explodes into a million pieces! Wait, does that mean you're even more unlucky?")) + evil_mirror.take_damage(evil_mirror.max_integrity, BRUTE, MELEE, FALSE) + if(roll_for_accident(20)) + luck_mod += 0.25 + damage_mod += 0.25 + + if(2 to 3) + if(HAS_TRAIT(our_guy, TRAIT_NO_MIRROR_REFLECTION)) // not so living i suppose + to_chat(our_guy, span_green("...Oh god, you can't see your reflection - wait, that's normal.")) + return TRUE + to_chat(our_guy, span_big(span_hypnophrase("...Oh god, you can't see your reflection!!"))) + INVOKE_ASYNC(our_guy, TYPE_PROC_REF(/mob, emote), "scream") + ADD_TRAIT(our_guy, TRAIT_NO_MIRROR_REFLECTION, REF(src)) + + if(4 to 5) + if(HAS_TRAIT(our_guy, TRAIT_NO_MIRROR_REFLECTION)) + to_chat(our_guy, span_warning("...but you don't see anything of notice.")) + return TRUE + to_chat(our_guy, span_userdanger("You see your reflection, but it is grinning malevolently and staring directly at you!")) + INVOKE_ASYNC(our_guy, TYPE_PROC_REF(/mob, emote), "scream") + + our_guy.set_jitter_if_lower(25 SECONDS) + if(roll_for_accident(2)) + to_chat(our_guy, span_warning("You are completely shocked by this turn of events!")) + to_chat(our_guy, span_userdanger("You clutch at your heart!")) + if(iscarbon(our_guy)) + var/mob/living/carbon/carbon_guy = our_guy + carbon_guy.set_heartattack(status = TRUE) + + consume_omen() + return TRUE /// If we get knocked down, see if we have a really bad slip and bash our head hard /datum/component/omen/proc/check_slip(mob/living/our_guy, amount) SIGNAL_HANDLER - if(prob(30)) // AAAA - INVOKE_ASYNC(our_guy, TYPE_PROC_REF(/mob, emote), "scream") - to_chat(our_guy, span_warning("What a horrible night... To have a curse!")) - - if(prob(30 * luck_mod)) /// Bonk! - var/obj/item/bodypart/the_head = our_guy.get_bodypart(BODY_ZONE_HEAD) - if(!the_head) - return - playsound(our_guy, 'sound/effects/tableheadsmash.ogg', 90, TRUE) - our_guy.visible_message(span_danger("[our_guy] hits [our_guy.p_their()] head really badly falling down!"), span_userdanger("You hit your head really badly falling down!")) - our_guy.apply_damage(75 * damage_mod, BRUTE, the_head, attacking_item = "slipping") - our_guy.adjustOrganLoss(ORGAN_SLOT_BRAIN, 100 * damage_mod) - consume_omen() + if(!our_guy.get_bodypart(BODY_ZONE_HEAD) || !roll_for_accident(15)) // Bonk! + return - return + playsound(our_guy, 'sound/effects/tableheadsmash.ogg', 90, TRUE) + our_guy.visible_message( + span_danger("[our_guy] hits [our_guy.p_their()] head really badly falling down!"), + span_userdanger("You hit your head really badly falling down!"), + ) + our_guy.apply_damage(75 * damage_mod, BRUTE, BODY_ZONE_HEAD, attacking_item = "slipping") + our_guy.apply_damage(100 * damage_mod, BRAIN) + consume_omen() /// Hijack the mood system to see if we get the blessing mood event to cancel the omen /datum/component/omen/proc/check_bless(mob/living/our_guy, category) SIGNAL_HANDLER - if(incidents_left == INFINITY) - return - - if(!("blessing" in our_guy.mob_mood.mood_events)) + if(incidents_left == INFINITY || bless_result != BLESSING_SUCCESS || !bless_fixable) return playsound(our_guy, 'sound/effects/pray_chaplain.ogg', 40, TRUE) @@ -237,6 +334,7 @@ /datum/component/omen/proc/check_death(mob/living/our_guy) SIGNAL_HANDLER + on_death?.Invoke(src) if(incidents_left == INFINITY) return @@ -256,53 +354,6 @@ UnregisterSignal(vessel, COMSIG_QDELETING) vessel = null -/** - * The smite omen. Permanent. - */ -/datum/component/omen/smite - -/datum/component/omen/smite/check_death(mob/living/our_guy) - if(incidents_left == INFINITY) - return ..() - - death_explode(our_guy) - our_guy.gib(DROP_ALL_REMAINS) - -/** - * The quirk omen. Permanent. - * Has only a 50% chance of bad things happening, and takes only 25% of normal damage. - */ -/datum/component/omen/quirk - incidents_left = INFINITY - luck_mod = 0.3 // 30% chance of bad things happening - damage_mod = 0.25 // 25% of normal damage - -/datum/component/omen/quirk/RegisterWithParent() - RegisterSignal(parent, COMSIG_MOVABLE_MOVED, PROC_REF(check_accident)) - RegisterSignal(parent, COMSIG_ON_CARBON_SLIP, PROC_REF(check_slip)) - RegisterSignal(parent, COMSIG_LIVING_DEATH, PROC_REF(check_death)) - -/datum/component/omen/quirk/UnregisterFromParent() - UnregisterSignal(parent, list(COMSIG_ON_CARBON_SLIP, COMSIG_MOVABLE_MOVED, COMSIG_LIVING_DEATH)) - -/datum/component/omen/quirk/check_death(mob/living/our_guy) - if(!iscarbon(our_guy)) - our_guy.gib(DROP_ALL_REMAINS) - return - - // Don't explode if buckled to a stasis bed - if(our_guy.buckled) - var/obj/machinery/stasis/stasis_bed = our_guy.buckled - if(istype(stasis_bed)) - return - - death_explode(our_guy) - var/mob/living/carbon/player = our_guy - player.spread_bodyparts() - player.spawn_gibs() - - return - /** * The bible omen. * While it lasts, parent gets a cursed aura filter. diff --git a/code/datums/quirks/negative_quirks/cursed.dm b/code/datums/quirks/negative_quirks/cursed.dm index f58d31be28e4..6063d15dccb9 100644 --- a/code/datums/quirks/negative_quirks/cursed.dm +++ b/code/datums/quirks/negative_quirks/cursed.dm @@ -10,4 +10,25 @@ hardcore_value = 8 /datum/quirk/cursed/add(client/client_source) - quirk_holder.AddComponent(/datum/component/omen/quirk) + quirk_holder.AddComponent( \ + /datum/component/omen, \ + incidents_left = INFINITY, \ + luck_mod = 0.3, \ + damage_mod = 0.25, \ + bless_fixable = FALSE, \ + on_death = CALLBACK(src, PROC_REF(on_death)), \ + ) + +/datum/quirk/cursed/proc/on_death(datum/component/omen/omen) + var/mob/living/carbon/cursed = omen.parent + if(!iscarbon(cursed)) + cursed.gib(DROP_ALL_REMAINS) + return + + // Don't explode if buckled to a stasis bed + if(istype(cursed.buckled, /obj/machinery/stasis)) + return + + omen.death_explode(cursed) + cursed.spread_bodyparts() + cursed.spawn_gibs() diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm index e8584049e681..a83454b681e4 100644 --- a/code/game/machinery/doors/airlock.dm +++ b/code/game/machinery/doors/airlock.dm @@ -1310,6 +1310,11 @@ if(!dangerous_close) for(var/turf/checked_turf in locs) for(var/atom/movable/blocking in checked_turf) + var/sigreturn = SEND_SIGNAL(blocking, COMSIG_MOVABLE_BLOCKING_AIRLOCK, src, forced, force_crush) + if(sigreturn & AIRLOCK_BLOCK_FORCE_CRUSH) + dangerous_close = TRUE + continue + if(blocking.density && blocking != src) autoclose_in(DOOR_CLOSE_WAIT) return FALSE diff --git a/code/modules/admin/smites/bad_luck.dm b/code/modules/admin/smites/bad_luck.dm index 34592dd200d4..4ea884fd2267 100644 --- a/code/modules/admin/smites/bad_luck.dm +++ b/code/modules/admin/smites/bad_luck.dm @@ -18,11 +18,18 @@ . = ..() //if permanent, replace any existing omen if(incidents == INFINITY) - var/existing_component = target.GetComponent(/datum/component/omen) - qdel(existing_component) - target.AddComponent(/datum/component/omen/smite, incidents_left = incidents) + qdel(target.GetComponent(/datum/component/omen)) + target.AddComponent(/datum/component/omen/smite, incidents_left = incidents, on_death = CALLBACK(src, PROC_REF(on_death))) if(silent) return to_chat(target, span_warning("You get a bad feeling...")) if(incidents == INFINITY) to_chat(target, span_warning("A very bad feeling... As if malevolent forces are watching you...")) + +/datum/smite/bad_luck/proc/on_death(datum/component/omen/omen) + if(omen.incidents_left == INFINITY) + return + + var/mob/living/our_guy = omen.parent + omen.death_explode(our_guy) + our_guy.gib(DROP_ALL_REMAINS) diff --git a/code/modules/power/lighting/light.dm b/code/modules/power/lighting/light.dm index ad398c2b599e..bf624e02c360 100644 --- a/code/modules/power/lighting/light.dm +++ b/code/modules/power/lighting/light.dm @@ -313,7 +313,11 @@ // attempt to set the light's on/off status // will not switch on if broken/burned/empty /obj/machinery/light/proc/set_on(turn_on) + var/was_on = on on = (turn_on && status == LIGHT_OK) + if(on == was_on) + return + SEND_SIGNAL(src, COMSIG_LIGHT_FIXTURE_TOGGLED, on) update() /obj/machinery/light/get_cell() @@ -629,12 +633,15 @@ if(status == LIGHT_EMPTY || status == LIGHT_BROKEN) return + var/was_ok = (status == LIGHT_OK || status == LIGHT_BURNED) + status = LIGHT_BROKEN + + SEND_SIGNAL(src, COMSIG_LIGHT_FIXTURE_BROKEN, was_ok) if(!skip_sound_and_sparks) - if(status == LIGHT_OK || status == LIGHT_BURNED) + if(was_ok) playsound(loc, 'sound/effects/glasshit.ogg', 75, TRUE) if(on) do_sparks(3, TRUE, src) - status = LIGHT_BROKEN update() /obj/machinery/light/proc/fix() diff --git a/code/modules/vending/_vending.dm b/code/modules/vending/_vending.dm index e7093ece0393..7ac1f9e84a46 100644 --- a/code/modules/vending/_vending.dm +++ b/code/modules/vending/_vending.dm @@ -1451,8 +1451,10 @@ GLOBAL_LIST_EMPTY(vending_machines_to_restock) if(greyscale_colors) vended_item.set_greyscale(colors=greyscale_colors) item_record.amount-- - if(usr.CanReach(src) && try_put_in_hand(vended_item, usr)) + var/sigreturn = SEND_SIGNAL(user, COMSIG_MOB_VENDING_PURCHASE, src, vended_item) + if(!(sigreturn & VENDING_NO_PICKUP) && usr.CanReach(src) && try_put_in_hand(vended_item, usr)) to_chat(usr, span_notice("You take [item_record.name] out of the slot.")) + vended_item.do_pickup_animation(user, src) else to_chat(usr, span_warning("[capitalize(format_text(item_record.name))] falls onto the floor!")) SSblackbox.record_feedback("nested tally", "vending_machine_usage", 1, list("[type]", "[item_record.product_path]")) From 2e9456501905b90473763754ccdc03a2c8a0e7ce Mon Sep 17 00:00:00 2001 From: MrMelbert Date: Mon, 22 Jun 2026 14:21:07 -0500 Subject: [PATCH 08/10] Copier stuff --- .../dcs/signals/signals_mob/signals_mob_living.dm | 3 +++ code/datums/components/crafting/furniture.dm | 7 ++----- code/datums/components/crafting/tools.dm | 2 +- code/datums/components/omen.dm | 4 ++-- code/game/objects/items/food/burgers.dm | 12 ++++++------ code/modules/admin/smites/bad_luck.dm | 7 ++++++- code/modules/forensics/forensics_helpers.dm | 2 +- code/modules/library/bibles.dm | 3 ++- code/modules/mob/living/status_procs.dm | 2 -- code/modules/paperwork/photocopier.dm | 12 ++++-------- code/modules/vending/_vending.dm | 3 +-- 11 files changed, 28 insertions(+), 29 deletions(-) diff --git a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm index a1303046e1f6..e8dbddc50827 100644 --- a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm +++ b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm @@ -310,6 +310,9 @@ #define COMSIG_LIVING_PERCEIVE_EXAMINE_NAME "living_perceive_examine_name" #define COMPONENT_EXAMINE_NAME_OVERRIDEN (1<<0) +/// From /obj/item/book/bible/attack() : (mob/living/user, obj/item/book/bible/bible, bless_result) +#define COMSIG_LIVING_BLESSED "living_blessed" + /// From /datum/element/death_drops/on_death(mob/living/target, gibbed) : (list/loot, gibbed) #define COMSIG_LIVING_DROP_LOOT "living_drop_loot" /// Prevent loot from being dropped diff --git a/code/datums/components/crafting/furniture.dm b/code/datums/components/crafting/furniture.dm index 742d060bd017..c03e1d0fc286 100644 --- a/code/datums/components/crafting/furniture.dm +++ b/code/datums/components/crafting/furniture.dm @@ -80,7 +80,7 @@ /obj/item/stack/rods = 1, /obj/item/light/bulb = 1, ) - crafting_flags = CRAFT_SKIP_MATERIALS_PARITY + // crafting_flags = CRAFT_SKIP_MATERIALS_PARITY tool_behaviors = list(TOOL_SCREWDRIVER) category = CAT_FURNITURE @@ -101,10 +101,7 @@ ) blacklist = list( /obj/item/flashlight/lamp/bananalamp, - /obj/item/flashlight/lamp/space_bubble, ) - requirements_mats_blacklist = list(/obj/item/grown/bananapeel) + // requirements_mats_blacklist = list(/obj/item/grown/bananapeel) tool_behaviors = list(TOOL_SCREWDRIVER) category = CAT_FURNITURE - - diff --git a/code/datums/components/crafting/tools.dm b/code/datums/components/crafting/tools.dm index d1a20b6b2017..32b9976c88ca 100644 --- a/code/datums/components/crafting/tools.dm +++ b/code/datums/components/crafting/tools.dm @@ -99,6 +99,6 @@ /obj/item/stack/rods = 1, /obj/item/stack/sheet/glass = 1, ) - crafting_flags = CRAFT_SKIP_MATERIALS_PARITY + // crafting_flags = CRAFT_SKIP_MATERIALS_PARITY tool_behaviors = list(TOOL_SCREWDRIVER) category = CAT_TOOLS diff --git a/code/datums/components/omen.dm b/code/datums/components/omen.dm index 885db5f2714c..f6aa7ce76689 100644 --- a/code/datums/components/omen.dm +++ b/code/datums/components/omen.dm @@ -319,10 +319,10 @@ consume_omen() /// Hijack the mood system to see if we get the blessing mood event to cancel the omen -/datum/component/omen/proc/check_bless(mob/living/our_guy, category) +/datum/component/omen/proc/check_bless(mob/living/our_guy, mob/blesser, obj/item/bible, bless_result) SIGNAL_HANDLER - if(incidents_left == INFINITY || bless_result != BLESSING_SUCCESS || !bless_fixable) + if(incidents_left == INFINITY || !bless_result/* != BLESSING_SUCCESS*/ || !bless_fixable) return playsound(our_guy, 'sound/effects/pray_chaplain.ogg', 40, TRUE) diff --git a/code/game/objects/items/food/burgers.dm b/code/game/objects/items/food/burgers.dm index 0daa1bccdc34..ec00d39899bc 100644 --- a/code/game/objects/items/food/burgers.dm +++ b/code/game/objects/items/food/burgers.dm @@ -659,12 +659,12 @@ tastes = list("bun" = 2, "beef patty" = 4, "cheese" = 2, "beef soaked in chili" = 3, "a smoking flare" = 2) foodtypes = GRAIN | MEAT | DAIRY | VEGETABLES crafting_complexity = FOOD_COMPLEXITY_4 - custom_materials = list( - /datum/material/meat = MEATDISH_MATERIAL_AMOUNT * 2, - /datum/material/iron = SMALL_MATERIAL_AMOUNT * 0.5, - /datum/material/plasma = SMALL_MATERIAL_AMOUNT * 0.5, - /datum/material/plastic = SMALL_MATERIAL_AMOUNT * 0.5, - ) + // custom_materials = list( + // /datum/material/meat = MEATDISH_MATERIAL_AMOUNT * 2, + // /datum/material/iron = SMALL_MATERIAL_AMOUNT * 0.5, + // /datum/material/plasma = SMALL_MATERIAL_AMOUNT * 0.5, + // /datum/material/plastic = SMALL_MATERIAL_AMOUNT * 0.5, + // ) /obj/item/food/burger/crazy/Initialize(mapload) . = ..() diff --git a/code/modules/admin/smites/bad_luck.dm b/code/modules/admin/smites/bad_luck.dm index 4ea884fd2267..82551955a534 100644 --- a/code/modules/admin/smites/bad_luck.dm +++ b/code/modules/admin/smites/bad_luck.dm @@ -19,7 +19,12 @@ //if permanent, replace any existing omen if(incidents == INFINITY) qdel(target.GetComponent(/datum/component/omen)) - target.AddComponent(/datum/component/omen/smite, incidents_left = incidents, on_death = CALLBACK(src, PROC_REF(on_death))) + target.AddComponent( \ + /datum/component/omen, \ + incidents_left = incidents, \ + on_death = CALLBACK(src, PROC_REF(on_death)), \ + bless_fixable = incidents != INFINITY, \ + ) if(silent) return to_chat(target, span_warning("You get a bad feeling...")) diff --git a/code/modules/forensics/forensics_helpers.dm b/code/modules/forensics/forensics_helpers.dm index da22fc1c8bd0..f5e704b668fb 100644 --- a/code/modules/forensics/forensics_helpers.dm +++ b/code/modules/forensics/forensics_helpers.dm @@ -135,7 +135,7 @@ if(unique_blood[blood_type]) continue var/datum/blood_type/blood = find_blood_type(blood_type) - blood.set_up_blood(src, first_dna == 0, only_dna = length(blood_DNA_to_add) == 1) + blood.set_up_blood(src, first_dna == 0, only_type = length(blood_DNA_to_add) == 1) unique_blood[blood_type] = TRUE // handle smells refresh_smells() diff --git a/code/modules/library/bibles.dm b/code/modules/library/bibles.dm index d43fdfa85800..48c0b24d6179 100644 --- a/code/modules/library/bibles.dm +++ b/code/modules/library/bibles.dm @@ -212,7 +212,7 @@ GLOBAL_LIST_INIT(bibleitemstates, list( if(GLOB.religious_sect) return GLOB.religious_sect.sect_bless(blessed,user) if(!ishuman(blessed)) - return + return FALSE var/mob/living/carbon/human/built_in_his_image = blessed for(var/obj/item/bodypart/bodypart as anything in built_in_his_image.get_bodyparts()) if(!IS_ORGANIC_LIMB(bodypart)) @@ -265,6 +265,7 @@ GLOBAL_LIST_INIT(bibleitemstates, list( smack_chance = GLOB.religious_sect.smack_chance var/success = !prob(smack_chance) && bless(target_mob, user) if(success) + SEND_SIGNAL(target_mob, COMSIG_LIVING_BLESSED, user, src, success) return if(iscarbon(target_mob)) var/mob/living/carbon/carbon_target = target_mob diff --git a/code/modules/mob/living/status_procs.dm b/code/modules/mob/living/status_procs.dm index 4a8dd0b04c9c..f373c21fa07a 100644 --- a/code/modules/mob/living/status_procs.dm +++ b/code/modules/mob/living/status_procs.dm @@ -534,8 +534,6 @@ var/datum/preferences/to_pass = client || to_mob.client for(var/datum/quirk/quirk as anything in quirks) - if(quirk.quirk_flags & QUIRK_NO_TRANSFER) - continue quirk.remove_from_current_holder(quirk_transfer = TRUE) quirk.add_to_holder(to_mob, quirk_transfer = TRUE, client_source = to_pass) diff --git a/code/modules/paperwork/photocopier.dm b/code/modules/paperwork/photocopier.dm index b9c6abcab50c..88e2c27e13f9 100644 --- a/code/modules/paperwork/photocopier.dm +++ b/code/modules/paperwork/photocopier.dm @@ -240,7 +240,7 @@ GLOBAL_LIST_INIT(paper_blanks, init_paper_blanks()) data["is_photo"] = TRUE data["color_mode"] = color_mode - if(HAS_AI_ACCESS(user)) + if(isAI(user) || isAdminGhostAI(user)) data["isAI"] = TRUE data["can_AI_print"] = toner_cartridge && (toner_cartridge.charges >= PHOTO_TONER_USE) && (get_paper_count(created_paper) >= PHOTO_PAPER_USE) else @@ -790,7 +790,7 @@ GLOBAL_LIST_INIT(paper_blanks, init_paper_blanks()) /obj/machinery/photocopier/atom_break(damage_flag) . = ..() if(. && toner_cartridge?.charges) - new /obj/effect/decal/cleanable/blood/oil(get_turf(src)) + new /obj/effect/decal/cleanable/oil(get_turf(src)) toner_cartridge.charges = 0 /obj/machinery/photocopier/mouse_drop_receive(mob/target, mob/user, params) @@ -882,12 +882,10 @@ GLOBAL_LIST_INIT(paper_blanks, init_paper_blanks()) icon = 'icons/obj/service/bureaucracy.dmi' icon_state = "tonercartridge" w_class = WEIGHT_CLASS_SMALL + grind_results = list(/datum/reagent/iodine = 40, /datum/reagent/iron = 10) var/charges = 5 var/max_charges = 5 -/obj/item/toner/grind_results() - return list(/datum/reagent/iodine = 40, /datum/reagent/iron = 10) - /obj/item/toner/examine(mob/user) . = ..() . += span_notice("The ink level gauge on the side reads [round(charges / max_charges * 100)]%") @@ -897,9 +895,7 @@ GLOBAL_LIST_INIT(paper_blanks, init_paper_blanks()) desc = "A hefty cartridge of Nanotrasen ValueBrand toner. Fits photocopiers and autopainters alike." charges = 25 max_charges = 25 - -/obj/item/toner/large/grind_results() - return list(/datum/reagent/iodine = 90, /datum/reagent/iron = 10) + grind_results = list(/datum/reagent/iodine = 90, /datum/reagent/iron = 10) /obj/item/toner/extreme name = "extremely large toner cartridge" diff --git a/code/modules/vending/_vending.dm b/code/modules/vending/_vending.dm index 7ac1f9e84a46..d4ca5ce02a5d 100644 --- a/code/modules/vending/_vending.dm +++ b/code/modules/vending/_vending.dm @@ -1451,10 +1451,9 @@ GLOBAL_LIST_EMPTY(vending_machines_to_restock) if(greyscale_colors) vended_item.set_greyscale(colors=greyscale_colors) item_record.amount-- - var/sigreturn = SEND_SIGNAL(user, COMSIG_MOB_VENDING_PURCHASE, src, vended_item) + var/sigreturn = SEND_SIGNAL(usr, COMSIG_MOB_VENDING_PURCHASE, src, vended_item) if(!(sigreturn & VENDING_NO_PICKUP) && usr.CanReach(src) && try_put_in_hand(vended_item, usr)) to_chat(usr, span_notice("You take [item_record.name] out of the slot.")) - vended_item.do_pickup_animation(user, src) else to_chat(usr, span_warning("[capitalize(format_text(item_record.name))] falls onto the floor!")) SSblackbox.record_feedback("nested tally", "vending_machine_usage", 1, list("[type]", "[item_record.product_path]")) From 9b30524afcbfcb43c01643e70f7e31bad27f1863 Mon Sep 17 00:00:00 2001 From: MrMelbert Date: Mon, 22 Jun 2026 14:35:42 -0500 Subject: [PATCH 09/10] Printable --- .../research/designs/machine_designs.dm | 18 +++++++++--------- .../research/techweb/nodes/service_nodes.dm | 1 + 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/code/modules/research/designs/machine_designs.dm b/code/modules/research/designs/machine_designs.dm index 1d9f38bbb9d4..4c206c4be3f1 100644 --- a/code/modules/research/designs/machine_designs.dm +++ b/code/modules/research/designs/machine_designs.dm @@ -1203,15 +1203,15 @@ ) departmental_flags = DEPARTMENT_BITFLAG_CARGO | DEPARTMENT_BITFLAG_ENGINEERING -// /datum/design/board/photopcopier -// name = "Photocopier" -// desc = "The circuit for a photocopier." -// id = "photocopier" -// build_path = /obj/item/circuitboard/machine/photocopier -// category = list( -// RND_CATEGORY_MACHINE + RND_SUBCATEGORY_MACHINE_SERVICE -// ) -// departmental_flags = DEPARTMENT_BITFLAG_CARGO | DEPARTMENT_BITFLAG_SERVICE +/datum/design/board/photopcopier + name = "Photocopier" + desc = "The circuit for a photocopier." + id = "photocopier" + build_path = /obj/item/circuitboard/machine/photocopier + category = list( + RND_CATEGORY_MACHINE + RND_SUBCATEGORY_MACHINE_SERVICE + ) + departmental_flags = DEPARTMENT_BITFLAG_CARGO | DEPARTMENT_BITFLAG_SERVICE // /datum/design/board/atmosshieldgen // name = "Atmospherics Shield Generator Board" diff --git a/code/modules/research/techweb/nodes/service_nodes.dm b/code/modules/research/techweb/nodes/service_nodes.dm index 22729bd1777e..6d5f5a434970 100644 --- a/code/modules/research/techweb/nodes/service_nodes.dm +++ b/code/modules/research/techweb/nodes/service_nodes.dm @@ -38,6 +38,7 @@ "ticket_machine", "radio_entertainment", "barber_scissors", + "photocopier", ) /datum/techweb_node/sanitation From 503549961bc97297656d06c6af607c38c7bd6a7e Mon Sep 17 00:00:00 2001 From: MrMelbert Date: Mon, 22 Jun 2026 14:38:31 -0500 Subject: [PATCH 10/10] Tweak --- tgui/packages/tgui/interfaces/Photocopier.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tgui/packages/tgui/interfaces/Photocopier.tsx b/tgui/packages/tgui/interfaces/Photocopier.tsx index cc8984844639..d4f4ebe98bd3 100644 --- a/tgui/packages/tgui/interfaces/Photocopier.tsx +++ b/tgui/packages/tgui/interfaces/Photocopier.tsx @@ -188,7 +188,7 @@ const Status = (props: StatusProps) => { fluid dmIcon={paper.icon} dmIconState={paper.icon_state} - tooltip={paper.name + ' amount is ' + paper.amount} + tooltip={`${paper.name} amount is ${paper.amount}`} imageSize={32} disabled={!paper.amount} selected={created_paper === paper.type && paper.amount}