diff --git a/_maps/RandomRuins/SpaceRuins/hilbertresearchfacility.dmm b/_maps/RandomRuins/SpaceRuins/hilbertresearchfacility.dmm index 3d03f4acd18..01009e41349 100644 --- a/_maps/RandomRuins/SpaceRuins/hilbertresearchfacility.dmm +++ b/_maps/RandomRuins/SpaceRuins/hilbertresearchfacility.dmm @@ -197,8 +197,8 @@ /area/ruin/space/has_grav/powered/hilbertresearchfacility) "gv" = ( /obj/structure/fluff/tram_rail, -/obj/machinery/door/window/tram/hilbert, -/obj/structure/industrial_lift/tram/purple, +/obj/structure/transport/linear/tram, +/obj/structure/thermoplastic/light, /turf/open/floor/engine, /area/ruin/space/has_grav/powered/hilbertresearchfacility) "gx" = ( @@ -328,9 +328,10 @@ bulb_colour = "#deefff"; bulb_power = 0.6 }, -/obj/structure/industrial_lift/tram/purple, -/obj/effect/landmark/tram/platform/hilbert/middle, -/obj/effect/landmark/tram/nav/hilbert, +/obj/structure/transport/linear/tram, +/obj/structure/thermoplastic/light, +/obj/effect/landmark/transport/nav_beacon/tram/platform/hilbert/middle, +/obj/effect/landmark/transport/nav_beacon/tram/nav/hilbert, /turf/open/floor/engine, /area/ruin/space/has_grav/powered/hilbertresearchfacility) "iY" = ( @@ -405,9 +406,11 @@ /obj/structure/fluff/tram_rail{ dir = 1 }, -/obj/structure/industrial_lift/tram/purple, /obj/structure/window/reinforced/survival_pod/spawner/directional/west, /obj/structure/window/reinforced/survival_pod/spawner/directional/north, +/obj/structure/transport/linear/tram, +/obj/structure/thermoplastic/light, +/obj/effect/landmark/transport/transport_id/hilbert, /turf/open/floor/engine, /area/ruin/space/has_grav/powered/hilbertresearchfacility) "kw" = ( @@ -513,6 +516,10 @@ /obj/effect/spawner/random/vending/snackvend, /turf/open/floor/wood, /area/ruin/space/has_grav/powered/hilbertresearchfacility) +"mV" = ( +/obj/machinery/transport/tram_controller/hilbert, +/turf/closed/indestructible/riveted/plastinum/nodiagonal, +/area/ruin/space/has_grav/powered/hilbertresearchfacility) "ng" = ( /obj/machinery/atmospherics/components/unary/portables_connector/visible{ dir = 4 @@ -777,9 +784,10 @@ /area/ruin/space/has_grav/powered/hilbertresearchfacility) "uc" = ( /obj/structure/fluff/tram_rail, -/obj/structure/industrial_lift/tram/purple, /obj/structure/window/reinforced/survival_pod/spawner/directional/east, /obj/structure/window/reinforced/survival_pod/spawner/directional/south, +/obj/structure/transport/linear/tram, +/obj/structure/thermoplastic/light, /turf/open/floor/engine, /area/ruin/space/has_grav/powered/hilbertresearchfacility) "uf" = ( @@ -938,7 +946,7 @@ /turf/open/floor/mineral/titanium/tiled/white, /area/ruin/space/has_grav/powered/hilbertresearchfacility) "yf" = ( -/obj/effect/landmark/tram/nav/immovable_rod, +/obj/effect/landmark/transport/nav_beacon/tram/nav/immovable_rod, /turf/closed/indestructible/riveted/plastinum, /area/ruin/space/has_grav/powered/hilbertresearchfacility) "yi" = ( @@ -1039,12 +1047,12 @@ dir = 1 }, /obj/structure/sign/departments/cargo/directional/north, -/obj/machinery/button/tram{ +/obj/structure/table/reinforced/plastitaniumglass, +/obj/machinery/button/transport/tram{ + specific_transport_id = "hilb_1"; id = 2; - pixel_y = 9; - lift_id = "tram_hilbert" + pixel_y = 9 }, -/obj/structure/table/reinforced/plastitaniumglass, /turf/open/floor/mineral/plastitanium, /area/ruin/space/has_grav/powered/hilbertresearchfacility) "zw" = ( @@ -1161,7 +1169,7 @@ /obj/machinery/door/airlock/science{ name = "Hilbert's Office" }, -/obj/effect/landmark/tram/nav/immovable_rod, +/obj/effect/landmark/transport/nav_beacon/tram/nav/immovable_rod, /turf/open/floor/wood, /area/ruin/space/has_grav/powered/hilbertresearchfacility) "BF" = ( @@ -1362,14 +1370,15 @@ /turf/open/floor/mineral/plastitanium, /area/ruin/space/has_grav/powered/hilbertresearchfacility) "Fo" = ( -/obj/machinery/button/tram{ - pixel_y = 9; - lift_id = "tram_hilbert" - }, /obj/structure/table/reinforced/rglass, /obj/effect/turf_decal/stripes/red/line{ dir = 4 }, +/obj/machinery/button/transport/tram{ + specific_transport_id = "hilb_1"; + id = 1; + pixel_y = 9 + }, /turf/open/floor/mineral/titanium/tiled/white, /area/ruin/space/has_grav/powered/hilbertresearchfacility) "Fv" = ( @@ -1389,7 +1398,7 @@ /turf/open/floor/mineral/plastitanium, /area/ruin/space/has_grav/powered/hilbertresearchfacility) "Gf" = ( -/obj/effect/landmark/tram/platform/hilbert/right, +/obj/effect/landmark/transport/nav_beacon/tram/platform/hilbert/right, /turf/open/floor/engine, /area/ruin/space/has_grav/powered/hilbertresearchfacility) "Gi" = ( @@ -1408,10 +1417,10 @@ dir = 8 }, /obj/structure/table/reinforced/rglass, -/obj/machinery/button/tram{ +/obj/machinery/button/transport/tram{ + specific_transport_id = "hilb_1"; id = 3; - pixel_y = 9; - lift_id = "tram_hilbert" + pixel_y = 9 }, /turf/open/floor/mineral/titanium/tiled/white, /area/ruin/space/has_grav/powered/hilbertresearchfacility) @@ -1462,8 +1471,8 @@ /area/ruin/space/has_grav/powered/hilbertresearchfacility) "HN" = ( /obj/structure/window/reinforced/survival_pod/spawner/directional/east, -/obj/structure/industrial_lift/tram/purple, -/obj/effect/landmark/lift_id/hilbert, +/obj/structure/transport/linear/tram, +/obj/structure/thermoplastic/light, /turf/open/floor/engine, /area/ruin/space/has_grav/powered/hilbertresearchfacility) "Ic" = ( @@ -1483,7 +1492,7 @@ /turf/open/floor/grass/fairy, /area/ruin/space/has_grav/powered/hilbertresearchfacility) "It" = ( -/obj/effect/landmark/tram/platform/hilbert/left, +/obj/effect/landmark/transport/nav_beacon/tram/platform/hilbert/left, /turf/open/floor/engine, /area/ruin/space/has_grav/powered/hilbertresearchfacility) "Iv" = ( @@ -1776,10 +1785,8 @@ /obj/structure/fluff/tram_rail{ dir = 1 }, -/obj/machinery/door/window/tram/hilbert{ - dir = 1 - }, -/obj/structure/industrial_lift/tram/purple, +/obj/structure/transport/linear/tram, +/obj/structure/thermoplastic/light, /turf/open/floor/engine, /area/ruin/space/has_grav/powered/hilbertresearchfacility) "Px" = ( @@ -1842,13 +1849,14 @@ /area/ruin/space) "QS" = ( /obj/structure/window/reinforced/survival_pod/spawner/directional/west, -/obj/structure/industrial_lift/tram/purple, /obj/machinery/computer/tram_controls{ dir = 8; - specific_lift_id = "tram_hilbert"; icon_state = "tram_alt_controls"; - density = 0 + density = 0; + specific_transport_id = "hilb_1" }, +/obj/structure/transport/linear/tram, +/obj/structure/thermoplastic/light, /turf/open/floor/engine, /area/ruin/space/has_grav/powered/hilbertresearchfacility) "QV" = ( @@ -1907,9 +1915,10 @@ /obj/structure/fluff/tram_rail{ dir = 1 }, -/obj/structure/industrial_lift/tram/purple, /obj/structure/window/reinforced/survival_pod/spawner/directional/east, /obj/structure/window/reinforced/survival_pod/spawner/directional/north, +/obj/structure/transport/linear/tram, +/obj/structure/thermoplastic/light, /turf/open/floor/engine, /area/ruin/space/has_grav/powered/hilbertresearchfacility) "RV" = ( @@ -2189,9 +2198,10 @@ /area/ruin/space/has_grav/powered/hilbertresearchfacility) "WQ" = ( /obj/structure/fluff/tram_rail, -/obj/structure/industrial_lift/tram/purple, /obj/structure/window/reinforced/survival_pod/spawner/directional/west, /obj/structure/window/reinforced/survival_pod/spawner/directional/south, +/obj/structure/transport/linear/tram, +/obj/structure/thermoplastic/light, /turf/open/floor/engine, /area/ruin/space/has_grav/powered/hilbertresearchfacility) "WV" = ( @@ -3668,12 +3678,12 @@ ZV YV Ok Bo -Ok -BI +mV +Xi hk KC Xw -YG +MD Ok Bo Bo @@ -3825,11 +3835,11 @@ Jq Ok Bo Ok -Xi +BI hk KC Xw -MD +YG Ok Bo Bo diff --git a/_maps/map_files/Birdshot/birdshot.dmm b/_maps/map_files/Birdshot/birdshot.dmm index cb2ffc90188..22dea003430 100644 --- a/_maps/map_files/Birdshot/birdshot.dmm +++ b/_maps/map_files/Birdshot/birdshot.dmm @@ -85,14 +85,6 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/plating, /area/station/engineering/atmos/project) -"acO" = ( -/obj/effect/turf_decal/stripes/white/line{ - dir = 4 - }, -/obj/effect/spawner/random/maintenance, -/obj/effect/spawner/random/structure/girder, -/turf/open/floor/noslip/tram_platform, -/area/station/security/tram) "acS" = ( /obj/structure/disposalpipe/segment{ dir = 4 @@ -905,6 +897,13 @@ }, /turf/open/floor/iron/kitchen/small, /area/station/maintenance/aft) +"ase" = ( +/obj/effect/turf_decal/stripes/white/line{ + dir = 1 + }, +/obj/effect/turf_decal/stripes/white/line, +/turf/open/floor/tram, +/area/station/maintenance/department/medical/central) "asf" = ( /obj/effect/turf_decal/stripes{ dir = 9 @@ -1196,9 +1195,11 @@ /turf/open/floor/iron, /area/station/hallway/primary/fore) "ays" = ( -/obj/effect/turf_decal/stripes/white/line, -/obj/structure/frame/machine, -/turf/open/floor/noslip/tram_platform, +/obj/effect/turf_decal/stripes/white/line{ + dir = 9 + }, +/obj/item/stack/sheet/mineral/titanium, +/turf/open/floor/tram, /area/station/security/tram) "ayu" = ( /obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ @@ -1937,12 +1938,11 @@ /turf/open/floor/plating/rust, /area/station/engineering/atmos/project) "aPe" = ( -/obj/effect/turf_decal/stripes/white/line{ - dir = 8 - }, -/obj/structure/window/reinforced/tram/directional/west, -/obj/structure/industrial_lift/tram/white, -/turf/open/floor/noslip/tram_platform, +/obj/structure/transport/linear/tram, +/obj/structure/thermoplastic, +/obj/effect/landmark/transport/nav_beacon/tram/platform/birdshot/sec_wing, +/obj/effect/landmark/transport/nav_beacon/tram/nav/birdshot/prison, +/turf/open/floor/tram, /area/station/security/tram) "aPh" = ( /obj/structure/window/reinforced/plasma/spawner/directional/north, @@ -2404,6 +2404,13 @@ /obj/machinery/light/small/directional/west, /turf/open/floor/grass, /area/station/service/hydroponics/garden/monastery) +"aWy" = ( +/obj/effect/turf_decal/stripes/white/line{ + dir = 8 + }, +/obj/item/stack/sheet/mineral/titanium, +/turf/open/floor/tram, +/area/station/security/tram) "aWC" = ( /obj/machinery/computer/department_orders/engineering{ dir = 8 @@ -2463,15 +2470,6 @@ dir = 8 }, /area/station/command/corporate_showroom) -"aYO" = ( -/obj/effect/turf_decal/stripes/white/corner{ - dir = 1 - }, -/obj/effect/turf_decal/stripes/white/corner{ - dir = 4 - }, -/turf/open/floor/noslip/tram_platform, -/area/station/security/tram) "aYR" = ( /obj/structure/broken_flooring/singular/directional/east, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -4223,10 +4221,11 @@ /turf/open/floor/circuit, /area/station/tcommsat/server) "bFG" = ( -/obj/effect/turf_decal/stripes/white/line, -/obj/item/stack/sheet/mineral/titanium, -/obj/machinery/light/small/directional/south, -/turf/open/floor/noslip/tram_platform, +/obj/effect/turf_decal/stripes/white/line{ + dir = 1 + }, +/obj/structure/frame/machine, +/turf/open/floor/tram, /area/station/maintenance/department/medical/central) "bFM" = ( /obj/effect/turf_decal/tile/yellow{ @@ -4275,6 +4274,12 @@ /obj/structure/mannequin/skeleton, /turf/open/floor/iron/small, /area/station/medical/morgue) +"bGm" = ( +/obj/effect/turf_decal/stripes/white/line{ + dir = 8 + }, +/turf/open/floor/tram, +/area/station/maintenance/department/medical/central) "bGn" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/turf_decal/stripes/line{ @@ -4655,6 +4660,14 @@ /obj/machinery/door/airlock/external/glass, /turf/open/floor/plating, /area/station/maintenance/department/engine) +"bOQ" = ( +/obj/effect/turf_decal/stripes/white/line{ + dir = 8 + }, +/obj/structure/transport/linear/tram, +/obj/structure/tram, +/turf/open/floor/tram, +/area/station/security/tram) "bOR" = ( /obj/machinery/light/small/directional/west, /obj/structure/flora/bush/flowers_yw, @@ -4703,13 +4716,6 @@ /obj/machinery/computer/records/security, /turf/open/floor/wood/tile, /area/station/command/bridge) -"bQz" = ( -/obj/effect/turf_decal/stripes/white/line{ - dir = 4 - }, -/obj/effect/spawner/random/maintenance, -/turf/open/floor/noslip/tram_platform, -/area/station/security/tram) "bQU" = ( /obj/structure/cable, /obj/structure/disposalpipe/segment{ @@ -4865,7 +4871,7 @@ /obj/effect/turf_decal/stripes/white/line{ dir = 9 }, -/turf/open/floor/noslip/tram_platform, +/turf/open/floor/tram, /area/station/security/tram) "bUr" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -4972,6 +4978,11 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/iron, /area/station/security/tram) +"bVC" = ( +/obj/effect/turf_decal/stripes/white/line, +/obj/effect/spawner/random/maintenance, +/turf/open/floor/tram, +/area/station/maintenance/department/medical/central) "bVD" = ( /obj/effect/turf_decal/stripes/line{ dir = 1 @@ -5197,13 +5208,9 @@ /area/station/ai_monitored/turret_protected/ai) "caE" = ( /obj/effect/decal/cleanable/dirt, -/obj/machinery/button/tram{ - lift_id = "maint_tram"; - pixel_y = -32 - }, -/obj/machinery/destination_sign/indicator{ - pixel_y = -32; - tram_id = "maint_tram" +/obj/machinery/button/transport/tram/directional/south{ + specific_transport_id = "bird_2"; + id = 1 }, /turf/open/floor/iron, /area/station/maintenance/port/aft) @@ -5867,7 +5874,7 @@ name = "forgotten exosuit fabricator" }, /obj/machinery/light/small/broken/directional/west, -/turf/open/floor/iron, +/turf/open/floor/plating, /area/station/maintenance/port/aft) "coJ" = ( /obj/structure/chair/stool/directional/east, @@ -6035,13 +6042,6 @@ }, /turf/open/floor/engine, /area/station/maintenance/disposal/incinerator) -"crr" = ( -/obj/effect/turf_decal/stripes/white/line{ - dir = 6 - }, -/obj/effect/spawner/random/structure/girder, -/turf/open/floor/noslip/tram_platform, -/area/station/maintenance/department/medical/central) "crE" = ( /obj/structure/window/spawner/directional/north, /turf/open/space/basic, @@ -6052,6 +6052,15 @@ }, /turf/open/floor/iron/small, /area/station/security/brig) +"crV" = ( +/obj/structure/transport/linear/tram, +/obj/structure/fluff/tram_rail/floor{ + dir = 1 + }, +/obj/structure/thermoplastic, +/obj/structure/rack, +/turf/open/floor/tram, +/area/station/maintenance/port/aft) "csl" = ( /obj/structure/cable, /obj/structure/disposalpipe/segment, @@ -6152,13 +6161,14 @@ /obj/machinery/light/cold/directional/north, /turf/open/floor/iron, /area/station/security/prison/rec) -"cuG" = ( +"cum" = ( /obj/effect/turf_decal/stripes/white/line{ - dir = 8 + dir = 6 }, -/obj/effect/spawner/random/structure/girder, -/turf/open/floor/noslip/tram_platform, -/area/station/maintenance/department/medical/central) +/obj/structure/transport/linear/tram, +/obj/structure/tram, +/turf/open/floor/tram, +/area/station/security/tram) "cuS" = ( /obj/effect/mapping_helpers/broken_floor, /obj/effect/decal/cleanable/dirt, @@ -6896,6 +6906,17 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/iron/dark/small, /area/station/ai_monitored/security/armory) +"cHt" = ( +/obj/structure/transport/linear/tram, +/obj/structure/fluff/tram_rail/floor{ + dir = 1 + }, +/obj/structure/thermoplastic, +/obj/structure/chair/sofa/bench/tram/left{ + dir = 1 + }, +/turf/open/floor/tram, +/area/station/maintenance/port/aft) "cHC" = ( /obj/structure/chair{ pixel_y = -2 @@ -6950,8 +6971,9 @@ /obj/effect/turf_decal/stripes/white/line{ dir = 4 }, -/obj/structure/industrial_lift/tram/white, -/turf/open/floor/noslip/tram_platform, +/obj/structure/transport/linear/tram, +/obj/structure/thermoplastic, +/turf/open/floor/tram, /area/station/security/tram) "cIE" = ( /obj/structure/cable, @@ -6976,11 +6998,8 @@ /turf/open/floor/iron/small, /area/station/maintenance/department/engine) "cJu" = ( -/obj/effect/turf_decal/stripes/white/line{ - dir = 8 - }, -/obj/effect/spawner/random/maintenance, -/turf/open/floor/noslip/tram_platform, +/obj/item/stack/sheet/mineral/titanium, +/turf/open/floor/tram, /area/station/security/tram) "cJz" = ( /obj/structure/cable, @@ -7459,11 +7478,10 @@ /turf/closed/wall, /area/station/commons/vacant_room/office) "cSD" = ( -/obj/structure/industrial_lift/tram, -/obj/effect/landmark/lift_id{ - specific_lift_id = "maint_tram" - }, -/turf/open/floor/noslip/tram_plate, +/obj/structure/transport/linear/tram, +/obj/structure/fluff/tram_rail/floor, +/obj/structure/thermoplastic/light, +/turf/open/floor/tram, /area/station/maintenance/port/aft) "cSR" = ( /obj/structure/chair{ @@ -7632,6 +7650,17 @@ }, /turf/open/floor/plating, /area/station/maintenance/department/engine) +"cWb" = ( +/obj/structure/transport/linear/tram, +/obj/effect/turf_decal/stripes/white/line{ + dir = 8 + }, +/obj/structure/fluff/tram_rail/floor{ + dir = 1 + }, +/obj/structure/tram, +/turf/open/floor/tram, +/area/station/maintenance/port/aft) "cWh" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -7884,10 +7913,13 @@ /turf/open/floor/plating/rust, /area/station/ai_monitored/turret_protected/aisat/maint) "dbO" = ( -/obj/effect/turf_decal/stripes/white/line, -/obj/effect/spawner/random/maintenance, -/obj/effect/spawner/random/structure/girder, -/turf/open/floor/noslip/tram_platform, +/obj/effect/turf_decal/stripes/white/line{ + dir = 1 + }, +/obj/structure/frame/computer{ + dir = 1 + }, +/turf/open/floor/tram, /area/station/maintenance/department/medical/central) "dbR" = ( /obj/structure/disposalpipe/segment{ @@ -8122,6 +8154,10 @@ /obj/machinery/light/small/directional/south, /turf/open/floor/wood/parquet, /area/station/service/library) +"dgg" = ( +/obj/effect/turf_decal/stripes/white/line, +/turf/open/floor/tram, +/area/station/security/tram) "dgn" = ( /obj/structure/cable, /obj/structure/disposalpipe/segment{ @@ -8195,8 +8231,11 @@ /turf/open/floor/plating, /area/station/maintenance/department/engine) "dhX" = ( -/obj/item/stack/sheet/mineral/titanium, -/turf/open/floor/noslip/tram_platform, +/obj/effect/turf_decal/stripes/white/line{ + dir = 4 + }, +/obj/effect/spawner/random/maintenance, +/turf/open/floor/tram, /area/station/security/tram) "dim" = ( /obj/structure/disposalpipe/segment{ @@ -9743,13 +9782,6 @@ dir = 1 }, /area/station/maintenance/disposal/incinerator) -"dLd" = ( -/obj/effect/turf_decal/stripes/white/line{ - dir = 10 - }, -/obj/item/stack/sheet/mineral/titanium, -/turf/open/floor/noslip/tram_platform, -/area/station/maintenance/department/medical/central) "dLf" = ( /obj/effect/turf_decal/tile/yellow/opposingcorners, /obj/structure/table/reinforced/titaniumglass, @@ -10833,10 +10865,6 @@ /obj/machinery/status_display/ai/directional/north, /turf/open/floor/iron/smooth, /area/station/ai_monitored/turret_protected/aisat_interior) -"edW" = ( -/obj/effect/spawner/random/structure/girder, -/turf/open/floor/noslip/tram_platform, -/area/station/maintenance/department/medical/central) "eeb" = ( /obj/structure/disposalpipe/segment{ dir = 4 @@ -12189,6 +12217,12 @@ /obj/effect/landmark/event_spawn, /turf/open/floor/iron/white, /area/station/medical/paramedic) +"eBv" = ( +/obj/structure/chair/comfy/shuttle, +/obj/structure/transport/linear/tram, +/obj/structure/thermoplastic, +/turf/open/floor/tram, +/area/station/security/tram) "eBH" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -12350,13 +12384,9 @@ /turf/open/floor/carpet/red, /area/station/command/heads_quarters/hos) "eEl" = ( -/obj/effect/turf_decal/stripes/white/line, -/obj/structure/industrial_lift/tram/white, -/obj/structure/window/reinforced/tram/directional/south, -/obj/structure/chair/sofa/bench/left{ - dir = 1 - }, -/turf/open/floor/noslip/tram_platform, +/obj/structure/transport/linear/tram, +/obj/structure/thermoplastic/light, +/turf/open/floor/tram, /area/station/maintenance/port/aft) "eEq" = ( /obj/effect/turf_decal/bot_white, @@ -12379,10 +12409,6 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/iron/smooth, /area/station/ai_monitored/turret_protected/aisat/equipment) -"eFi" = ( -/obj/structure/frame/machine, -/turf/open/floor/noslip/tram_platform, -/area/station/maintenance/department/medical/central) "eFk" = ( /obj/structure/cable/layer3, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -12632,6 +12658,13 @@ /obj/effect/turf_decal/tile/neutral, /turf/open/floor/iron, /area/station/hallway/primary/central/fore) +"eIN" = ( +/obj/effect/turf_decal/stripes/white/line{ + dir = 8 + }, +/obj/effect/spawner/random/maintenance, +/turf/open/floor/tram, +/area/station/security/tram) "eJe" = ( /obj/effect/turf_decal/tile/dark_red/half/contrasted, /turf/open/floor/iron/smooth, @@ -13189,15 +13222,6 @@ /obj/effect/landmark/start/roboticist, /turf/open/floor/iron/grimy, /area/station/science/cubicle) -"eTq" = ( -/obj/effect/turf_decal/stripes/white/line{ - dir = 4 - }, -/obj/structure/window/reinforced/tram/directional/east, -/obj/structure/chair/comfy/shuttle, -/obj/structure/industrial_lift/tram, -/turf/open/floor/noslip/tram_platform, -/area/station/security/tram) "eTr" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -13320,11 +13344,9 @@ /obj/effect/turf_decal/stripes/white/line{ dir = 6 }, -/obj/structure/industrial_lift/tram/subfloor, -/obj/structure/window/reinforced/tram/front{ - icon_state = "tram_window-2" - }, -/turf/open/floor/noslip/tram_platform, +/obj/structure/transport/linear/tram, +/obj/structure/tram, +/turf/open/floor/tram, /area/station/maintenance/port/aft) "eVu" = ( /obj/effect/mapping_helpers/broken_floor, @@ -13514,9 +13536,6 @@ /obj/machinery/portable_atmospherics/pump, /turf/open/floor/iron/dark, /area/station/engineering/atmos) -"fay" = ( -/turf/open/floor/noslip/tram_platform, -/area/station/security/tram) "faB" = ( /obj/structure/table/wood, /obj/item/book/bible, @@ -14017,6 +14036,20 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/iron/dark, /area/station/science/ordnance) +"fkN" = ( +/obj/effect/turf_decal/stripes/corner, +/obj/effect/turf_decal/stripes/corner{ + dir = 8 + }, +/obj/effect/turf_decal/stripes/corner{ + dir = 1 + }, +/obj/effect/turf_decal/stripes/corner{ + dir = 4 + }, +/obj/structure/holosign/barrier/atmos/tram, +/turf/open/floor/tram, +/area/station/security/tram) "fkT" = ( /obj/effect/turf_decal/sand/plating, /obj/structure/alien/weeds, @@ -14216,7 +14249,10 @@ /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/turf/open/floor/noslip/tram_platform, +/obj/structure/fluff/tram_rail/end{ + dir = 8 + }, +/turf/open/floor/plating, /area/station/maintenance/port/aft) "fov" = ( /obj/effect/turf_decal/tile/dark_red/opposingcorners, @@ -14337,15 +14373,6 @@ }, /turf/open/floor/iron, /area/station/hallway/primary/central/fore) -"fqT" = ( -/obj/effect/turf_decal/stripes/white/corner{ - dir = 1 - }, -/obj/effect/turf_decal/stripes/white/corner{ - dir = 8 - }, -/turf/open/floor/noslip/tram_plate, -/area/station/maintenance/department/medical/central) "frf" = ( /obj/structure/table/glass, /obj/item/defibrillator/loaded{ @@ -14390,14 +14417,9 @@ /turf/open/floor/catwalk_floor/iron_smooth, /area/station/command/heads_quarters/ce) "frB" = ( -/obj/machinery/button/tram{ - id = 2; - lift_id = "maint_tram"; - pixel_y = -32 - }, -/obj/machinery/destination_sign/indicator{ - pixel_y = -32; - tram_id = "maint_tram" +/obj/machinery/button/transport/tram/directional/south{ + specific_transport_id = "bird_2"; + id = 2 }, /turf/open/floor/iron, /area/station/maintenance/department/medical/central) @@ -14596,18 +14618,6 @@ /obj/machinery/light/small/directional/south, /turf/open/floor/stone, /area/station/command/heads_quarters/hos) -"fuk" = ( -/obj/structure/flora/bush/flowers_br/style_random, -/obj/structure/flora/rock/pile/style_random, -/obj/structure/window/reinforced/spawner/directional/west, -/obj/effect/turf_decal/siding/wideplating{ - dir = 4 - }, -/obj/machinery/light/floor{ - pixel_x = 32 - }, -/turf/open/misc/sandy_dirt, -/area/station/security/tram) "fun" = ( /obj/structure/cable/layer3, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -15353,6 +15363,12 @@ "fEC" = ( /turf/closed/wall, /area/station/maintenance/port/lesser) +"fEL" = ( +/obj/effect/turf_decal/stripes/white/line{ + dir = 8 + }, +/turf/open/floor/tram, +/area/station/security/tram) "fEV" = ( /obj/machinery/porta_turret/ai, /obj/machinery/computer/security/telescreen/minisat{ @@ -16302,6 +16318,15 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/iron/cafeteria, /area/station/science/circuits) +"fVC" = ( +/obj/effect/turf_decal/stripes/white/line{ + dir = 8 + }, +/obj/effect/turf_decal/stripes/white/line{ + dir = 4 + }, +/turf/open/floor/tram, +/area/station/security/tram) "fVG" = ( /obj/structure/cable, /turf/open/floor/iron/smooth, @@ -16395,6 +16420,13 @@ }, /turf/open/floor/iron/smooth, /area/station/ai_monitored/turret_protected/aisat/foyer) +"fXt" = ( +/obj/effect/turf_decal/stripes/white/line{ + dir = 1 + }, +/obj/effect/spawner/random/structure/girder, +/turf/open/floor/tram, +/area/station/maintenance/department/medical/central) "fXJ" = ( /obj/structure/cable, /obj/structure/disposalpipe/segment, @@ -16995,10 +17027,11 @@ /turf/open/space/basic, /area/space/nearstation) "gjr" = ( -/obj/effect/turf_decal/stripes/white/line, -/obj/effect/spawner/random/structure/girder, -/obj/machinery/light/small/directional/south, -/turf/open/floor/noslip/tram_platform, +/obj/effect/turf_decal/stripes/white/line{ + dir = 1 + }, +/obj/item/stack/sheet/mineral/titanium, +/turf/open/floor/tram, /area/station/maintenance/department/medical/central) "gjL" = ( /obj/structure/cable, @@ -17055,13 +17088,10 @@ /turf/open/floor/iron, /area/station/hallway/primary/fore) "gkO" = ( -/obj/effect/turf_decal/stripes/white/line{ - dir = 8 - }, -/obj/structure/window/reinforced/tram/directional/west, -/obj/structure/chair/comfy/shuttle, -/obj/structure/industrial_lift/tram, -/turf/open/floor/noslip/tram_platform, +/obj/structure/rack, +/obj/structure/transport/linear/tram, +/obj/structure/thermoplastic, +/turf/open/floor/tram, /area/station/security/tram) "glb" = ( /obj/structure/cable, @@ -17616,12 +17646,6 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/orange/hidden/layer1, /turf/open/floor/iron/dark, /area/station/engineering/atmos) -"gwh" = ( -/obj/effect/turf_decal/stripes/white/line{ - dir = 4 - }, -/turf/open/floor/noslip/tram_platform, -/area/station/maintenance/department/medical/central) "gwo" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/simple/purple/visible{ @@ -18945,19 +18969,10 @@ /obj/effect/turf_decal/stripes/white/line{ dir = 1 }, -/obj/structure/industrial_lift/tram, -/obj/machinery/door/window/tram/right/directional/north{ - pixel_y = -25; - associated_lift = "maint_tram" - }, -/turf/open/floor/noslip/tram_platform, +/obj/structure/transport/linear/tram, +/obj/structure/thermoplastic/light, +/turf/open/floor/tram, /area/station/maintenance/port/aft) -"gTC" = ( -/obj/effect/turf_decal/stripes/white/line{ - dir = 6 - }, -/turf/open/floor/noslip/tram_platform, -/area/station/security/tram) "gTH" = ( /obj/structure/cable, /obj/structure/disposalpipe/segment{ @@ -19199,9 +19214,9 @@ /obj/effect/turf_decal/stripes/white/line{ dir = 9 }, -/obj/structure/window/reinforced/tram/front, -/obj/structure/industrial_lift/tram/subfloor, -/turf/open/floor/noslip/tram_platform, +/obj/structure/transport/linear/tram, +/obj/structure/tram, +/turf/open/floor/tram, /area/station/security/tram) "gXf" = ( /obj/effect/turf_decal/sand/plating, @@ -20923,7 +20938,6 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/machinery/firealarm/directional/east, -/obj/effect/landmark/tram/nav/immovable_rod, /turf/open/floor/iron, /area/station/hallway/secondary/entry) "hzK" = ( @@ -21274,6 +21288,12 @@ /obj/effect/spawner/random/structure/crate_abandoned, /turf/open/floor/plating, /area/station/maintenance/fore/lesser) +"hFM" = ( +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/effect/landmark/transport/nav_beacon/tram/nav/immovable_rod, +/turf/open/floor/iron, +/area/station/hallway/secondary/entry) "hFO" = ( /obj/structure/broken_flooring/corner/directional/south, /obj/structure/extinguisher_cabinet/directional/west, @@ -21960,21 +21980,18 @@ /obj/item/radio/off, /turf/open/floor/iron/smooth, /area/station/command/gateway) +"hUO" = ( +/obj/effect/turf_decal/stripes/white/line, +/obj/item/stack/sheet/mineral/titanium, +/obj/machinery/light/small/directional/south, +/turf/open/floor/tram, +/area/station/maintenance/department/medical/central) "hUP" = ( /obj/structure/sink/directional/east, /obj/structure/mirror/directional/west, /obj/effect/decal/cleanable/dirt, /turf/open/floor/iron/showroomfloor, /area/station/commons/toilet/restrooms) -"hUT" = ( -/obj/effect/turf_decal/stripes/white/line, -/obj/structure/industrial_lift/tram/white, -/obj/structure/window/reinforced/tram/directional/south, -/obj/structure/chair/sofa/bench/right{ - dir = 1 - }, -/turf/open/floor/noslip/tram_platform, -/area/station/maintenance/port/aft) "hVb" = ( /obj/machinery/plate_press, /obj/effect/turf_decal/stripes/line, @@ -22184,12 +22201,10 @@ /turf/open/floor/engine, /area/station/engineering/gravity_generator) "hYz" = ( -/obj/effect/turf_decal/stripes/white/line{ - dir = 6 - }, -/obj/structure/window/reinforced/tram/front, -/obj/structure/industrial_lift/tram/subfloor, -/turf/open/floor/noslip/tram_platform, +/obj/structure/transport/linear/tram, +/obj/machinery/transport/tram_controller, +/obj/structure/tram, +/turf/open/floor/tram, /area/station/security/tram) "hYC" = ( /turf/closed/wall, @@ -22336,13 +22351,12 @@ /obj/effect/turf_decal/stripes/white/line{ dir = 1 }, -/obj/structure/industrial_lift/tram, -/obj/machinery/door/window/tram/left/directional/north{ - pixel_x = -32; - pixel_y = -25; - associated_lift = "maint_tram" +/obj/structure/transport/linear/tram, +/obj/structure/thermoplastic/light, +/obj/machinery/door/airlock/tram{ + transport_linked_id = "bird_2" }, -/turf/open/floor/noslip/tram_platform, +/turf/open/floor/tram, /area/station/maintenance/port/aft) "ibe" = ( /obj/effect/turf_decal/bot_white, @@ -22512,24 +22526,6 @@ dir = 1 }, /area/station/security/tram) -"idv" = ( -/obj/effect/turf_decal/stripes/corner, -/obj/effect/turf_decal/stripes/corner{ - dir = 8 - }, -/obj/effect/turf_decal/stripes/corner{ - dir = 4 - }, -/obj/effect/turf_decal/stripes/corner{ - dir = 1 - }, -/obj/structure/holosign/barrier/atmos/tram, -/obj/effect/turf_decal/stripes/white/line{ - dir = 1 - }, -/obj/effect/turf_decal/stripes/white/line, -/turf/open/floor/noslip/tram_plate, -/area/station/maintenance/department/medical/central) "idz" = ( /obj/structure/disposalpipe/segment{ dir = 5 @@ -23080,13 +23076,6 @@ }, /turf/open/floor/iron/dark/smooth_large, /area/station/command/meeting_room) -"ipn" = ( -/obj/effect/turf_decal/stripes/white/corner, -/obj/effect/turf_decal/stripes/white/corner{ - dir = 8 - }, -/turf/open/floor/noslip/tram_platform, -/area/station/security/tram) "ips" = ( /obj/structure/cable, /obj/structure/disposalpipe/segment{ @@ -23266,15 +23255,13 @@ /obj/effect/turf_decal/stripes/white/corner{ dir = 4 }, -/obj/effect/turf_decal/stripes/white/corner, -/obj/structure/industrial_lift/tram/subfloor, -/obj/structure/window/reinforced/tram/front{ - icon_state = "tram_window-3" - }, -/obj/machinery/computer/tram_controls/directional/east{ - specific_lift_id = "maint_tram" +/obj/structure/transport/linear/tram, +/obj/effect/turf_decal/stripes/white/line{ + dir = 4 }, -/turf/open/floor/noslip/tram_plate, +/obj/structure/fluff/tram_rail/floor, +/obj/structure/tram, +/turf/open/floor/tram, /area/station/maintenance/port/aft) "isi" = ( /obj/structure/table, @@ -23423,20 +23410,6 @@ /obj/machinery/power/apc/worn_out/directional/east, /turf/open/floor/plating, /area/station/maintenance/hallway/abandoned_command) -"ius" = ( -/obj/structure/flora/bush/large/style_random{ - pixel_y = -3 - }, -/obj/structure/flora/bush/flowers_br/style_random, -/obj/structure/window/reinforced/spawner/directional/west, -/obj/effect/turf_decal/siding/wideplating{ - dir = 4 - }, -/obj/machinery/light/floor{ - pixel_x = 32 - }, -/turf/open/misc/sandy_dirt, -/area/station/security/tram) "iut" = ( /obj/structure/disposalpipe/segment{ dir = 4 @@ -23672,9 +23645,13 @@ /turf/open/floor/plating, /area/station/security/brig/entrance) "iyk" = ( -/obj/effect/spawner/random/maintenance, -/obj/effect/spawner/random/structure/girder, -/turf/open/floor/noslip/tram_platform, +/obj/effect/turf_decal/stripes/white/line{ + dir = 4 + }, +/obj/structure/frame/computer{ + dir = 4 + }, +/turf/open/floor/tram, /area/station/security/tram) "iyq" = ( /obj/machinery/atmospherics/pipe/smart/simple/green/hidden{ @@ -23820,13 +23797,6 @@ /obj/structure/cable, /turf/open/floor/wood/tile, /area/station/maintenance/port/lesser) -"iBV" = ( -/obj/effect/turf_decal/stripes/white/line{ - dir = 1 - }, -/obj/effect/turf_decal/stripes/white/line, -/turf/open/floor/noslip/tram_plate, -/area/station/maintenance/port/aft) "iBZ" = ( /obj/structure/disposalpipe/segment{ dir = 5 @@ -24556,6 +24526,12 @@ /obj/structure/cable, /turf/open/floor/circuit/green, /area/station/ai_monitored/command/nuke_storage) +"iPw" = ( +/obj/effect/turf_decal/stripes/white/line, +/obj/effect/spawner/random/structure/girder, +/obj/machinery/light/small/directional/south, +/turf/open/floor/tram, +/area/station/maintenance/department/medical/central) "iPF" = ( /obj/structure/cable, /obj/effect/spawner/structure/window/reinforced, @@ -24615,11 +24591,6 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/iron/dark/small, /area/station/service/chapel/storage) -"iRp" = ( -/obj/structure/industrial_lift/tram/white, -/obj/machinery/light/small/directional/east, -/turf/open/floor/noslip/tram_plate, -/area/station/maintenance/port/aft) "iRv" = ( /obj/structure/cable, /obj/effect/decal/cleanable/dirt, @@ -25423,10 +25394,10 @@ /area/station/maintenance/fore/greater) "jfX" = ( /obj/effect/turf_decal/stripes/white/line{ - dir = 6 + dir = 1 }, /obj/effect/spawner/random/structure/girder, -/turf/open/floor/noslip/tram_platform, +/turf/open/floor/tram, /area/station/security/tram) "jfZ" = ( /obj/structure/cable, @@ -25615,6 +25586,14 @@ /obj/effect/mapping_helpers/broken_floor, /turf/open/floor/iron, /area/station/commons) +"jku" = ( +/obj/structure/transport/linear/tram, +/obj/structure/chair{ + dir = 1 + }, +/obj/structure/thermoplastic, +/turf/open/floor/tram, +/area/station/security/tram) "jkw" = ( /obj/effect/mapping_helpers/broken_floor, /obj/structure/table/greyscale, @@ -25899,21 +25878,6 @@ /obj/effect/spawner/random/maintenance/three, /turf/open/floor/plating, /area/station/maintenance/port/fore) -"jqs" = ( -/obj/structure/flora/bush/large/style_random{ - pixel_x = -18; - pixel_y = -9 - }, -/obj/structure/flora/bush/flowers_yw/style_random, -/obj/structure/window/reinforced/spawner/directional/west, -/obj/effect/turf_decal/siding/wideplating{ - dir = 4 - }, -/obj/machinery/light/floor{ - pixel_x = 32 - }, -/turf/open/misc/sandy_dirt, -/area/station/security/tram) "jqu" = ( /obj/structure/disposalpipe/segment{ dir = 5 @@ -26207,11 +26171,10 @@ /turf/open/floor/plating, /area/station/maintenance/starboard/aft) "jwC" = ( -/obj/effect/turf_decal/stripes/white/line, -/obj/structure/industrial_lift/tram, -/obj/structure/window/reinforced/tram/directional/south, -/obj/structure/rack, -/turf/open/floor/noslip/tram_platform, +/obj/structure/transport/linear/tram, +/obj/effect/landmark/transport/transport_id/birdshot/line_2, +/obj/structure/thermoplastic/light, +/turf/open/floor/tram, /area/station/maintenance/port/aft) "jxd" = ( /obj/machinery/atmospherics/pipe/smart/simple/purple/visible/layer2{ @@ -26738,15 +26701,9 @@ /turf/open/floor/iron, /area/station/cargo/office) "jEX" = ( -/obj/effect/turf_decal/stripes/white/line{ - dir = 8 - }, -/obj/structure/window/reinforced/tram/directional/west, -/obj/structure/chair{ - dir = 1 - }, -/obj/structure/industrial_lift/tram, -/turf/open/floor/noslip/tram_platform, +/obj/structure/transport/linear/tram, +/obj/structure/thermoplastic, +/turf/open/floor/tram, /area/station/security/tram) "jEZ" = ( /obj/structure/hedge, @@ -26795,6 +26752,10 @@ dir = 1 }, /area/station/hallway/primary/aft) +"jFz" = ( +/obj/effect/turf_decal/stripes/white/line, +/turf/open/floor/tram, +/area/station/maintenance/department/medical/central) "jFB" = ( /obj/structure/cable, /obj/structure/disposalpipe/segment{ @@ -27248,12 +27209,6 @@ /obj/item/radio/intercom/directional/south, /turf/open/floor/iron/smooth, /area/station/engineering/supermatter/room) -"jMv" = ( -/obj/structure/industrial_lift/tram, -/obj/effect/landmark/tram/nav/birdshot/maint, -/obj/effect/landmark/tram/platform/birdshot/maint_left, -/turf/open/floor/noslip/tram_plate, -/area/station/maintenance/port/aft) "jMC" = ( /obj/machinery/atmospherics/components/unary/outlet_injector/on{ dir = 8 @@ -27650,13 +27605,17 @@ /obj/item/instrument/harmonica, /turf/open/floor/iron, /area/station/security/prison/rec) +"jUC" = ( +/obj/structure/frame/machine, +/turf/open/floor/tram, +/area/station/maintenance/department/medical/central) "jUN" = ( -/obj/effect/turf_decal/stripes/white/line{ - dir = 5 +/obj/structure/transport/linear/tram, +/obj/structure/tram, +/obj/machinery/computer/tram_controls{ + specific_transport_id = "bird_1" }, -/obj/structure/window/reinforced/tram/front, -/obj/structure/industrial_lift/tram/subfloor, -/turf/open/floor/noslip/tram_platform, +/turf/open/floor/tram, /area/station/security/tram) "jVe" = ( /obj/structure/cable, @@ -27842,10 +27801,7 @@ /turf/open/floor/plating, /area/station/maintenance/starboard/greater) "jYd" = ( -/obj/effect/turf_decal/stripes/white/line{ - dir = 5 - }, -/turf/open/floor/noslip/tram_platform, +/turf/open/floor/tram, /area/station/security/tram) "jYr" = ( /obj/effect/turf_decal/tile/neutral/fourcorners, @@ -28161,11 +28117,9 @@ /turf/open/floor/iron, /area/station/cargo/storage) "kef" = ( -/obj/effect/turf_decal/stripes/white/line{ - dir = 5 - }, -/obj/effect/spawner/random/structure/girder, -/turf/open/floor/noslip/tram_platform, +/obj/effect/turf_decal/stripes/white/line, +/obj/structure/frame/machine, +/turf/open/floor/tram, /area/station/security/tram) "kel" = ( /obj/machinery/light/cold/directional/south, @@ -28407,20 +28361,6 @@ /obj/effect/spawner/random/structure/grille, /turf/open/floor/plating, /area/station/maintenance/fore/lesser) -"kjn" = ( -/obj/effect/turf_decal/stripes/corner, -/obj/effect/turf_decal/stripes/corner{ - dir = 8 - }, -/obj/effect/turf_decal/stripes/corner{ - dir = 1 - }, -/obj/effect/turf_decal/stripes/corner{ - dir = 4 - }, -/obj/structure/holosign/barrier/atmos/tram, -/turf/open/floor/noslip/tram_platform, -/area/station/security/tram) "kjw" = ( /obj/effect/turf_decal/tile/blue, /obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ @@ -28858,10 +28798,13 @@ /turf/closed/wall, /area/station/ai_monitored/aisat/exterior) "kqZ" = ( -/obj/effect/turf_decal/stripes/white/line{ - dir = 5 +/obj/effect/turf_decal/stripes/white/corner{ + dir = 1 + }, +/obj/effect/turf_decal/stripes/white/corner{ + dir = 8 }, -/turf/open/floor/noslip/tram_platform, +/turf/open/floor/tram, /area/station/maintenance/department/medical/central) "krc" = ( /obj/structure/disposalpipe/segment{ @@ -29000,10 +28943,10 @@ /area/station/engineering/gravity_generator) "ksL" = ( /obj/effect/turf_decal/stripes/white/line{ - dir = 5 + dir = 6 }, -/obj/item/stack/sheet/mineral/titanium, -/turf/open/floor/noslip/tram_platform, +/obj/effect/spawner/random/structure/girder, +/turf/open/floor/tram, /area/station/maintenance/department/medical/central) "ksN" = ( /obj/structure/transit_tube/station/dispenser, @@ -29117,12 +29060,6 @@ /obj/effect/turf_decal/trimline/neutral/line, /turf/open/floor/iron, /area/station/hallway/primary/central/fore) -"kvb" = ( -/obj/structure/industrial_lift/tram/white, -/obj/effect/landmark/tram/nav/birdshot/prison, -/obj/effect/landmark/tram/platform/birdshot/sec_wing, -/turf/open/floor/noslip/tram_platform, -/area/station/security/tram) "kvf" = ( /obj/effect/decal/cleanable/dirt, /turf/open/floor/iron, @@ -29149,6 +29086,13 @@ }, /turf/open/space/basic, /area/space) +"kvN" = ( +/obj/effect/turf_decal/stripes/white/line{ + dir = 8 + }, +/obj/effect/spawner/random/structure/girder, +/turf/open/floor/tram, +/area/station/maintenance/department/medical/central) "kvO" = ( /obj/machinery/light/small/directional/north, /obj/machinery/camera/directional/east{ @@ -29254,6 +29198,10 @@ /obj/structure/window/spawner/directional/east, /turf/open/floor/plating/rust, /area/station/maintenance/fore/lesser) +"kyk" = ( +/obj/item/stack/sheet/mineral/titanium, +/turf/open/floor/tram, +/area/station/maintenance/department/medical/central) "kyr" = ( /obj/structure/window/reinforced/spawner/directional/south, /obj/machinery/airalarm/directional/west, @@ -29292,15 +29240,10 @@ /area/station/hallway/primary/central/fore) "kyS" = ( /obj/effect/turf_decal/stripes/white/corner, -/obj/effect/turf_decal/stripes/white/corner{ - dir = 8 - }, -/obj/structure/window/reinforced/tram/front, -/obj/machinery/computer/tram_controls/directional/south{ - specific_lift_id = "prison_tram" - }, -/obj/structure/industrial_lift/tram/subfloor, -/turf/open/floor/noslip/tram_platform, +/obj/effect/turf_decal/stripes/white/line, +/obj/structure/transport/linear/tram, +/obj/structure/tram, +/turf/open/floor/tram, /area/station/security/tram) "kyT" = ( /obj/effect/decal/cleanable/dirt, @@ -29522,6 +29465,12 @@ }, /turf/open/floor/iron, /area/station/engineering/gravity_generator) +"kDa" = ( +/obj/effect/turf_decal/stripes/white/line, +/obj/structure/transport/linear/tram, +/obj/structure/tram, +/turf/open/floor/tram, +/area/station/maintenance/port/aft) "kDg" = ( /obj/effect/decal/cleanable/dirt, /turf/open/floor/iron/smooth, @@ -29953,11 +29902,8 @@ /turf/open/floor/iron/dark/side, /area/station/science/xenobiology) "kKy" = ( -/obj/effect/turf_decal/stripes/white/line{ - dir = 8 - }, -/obj/effect/spawner/random/structure/girder, -/turf/open/floor/noslip/tram_platform, +/obj/structure/frame/machine, +/turf/open/floor/tram, /area/station/security/tram) "kKB" = ( /obj/structure/window/spawner/directional/west, @@ -30023,7 +29969,7 @@ /obj/effect/turf_decal/stripes/white/line{ dir = 4 }, -/turf/open/floor/noslip/tram_platform, +/turf/open/floor/tram, /area/station/security/tram) "kLS" = ( /turf/open/floor/iron/stairs{ @@ -30072,15 +30018,6 @@ /obj/structure/closet/emcloset, /turf/open/floor/iron/small, /area/station/maintenance/department/medical/central) -"kNA" = ( -/obj/effect/turf_decal/stripes/white/line{ - dir = 8 - }, -/obj/effect/turf_decal/stripes/white/line{ - dir = 4 - }, -/turf/open/floor/noslip/tram_platform, -/area/station/security/tram) "kND" = ( /turf/closed/wall/r_wall, /area/station/security/prison) @@ -30327,9 +30264,9 @@ /obj/structure/chair{ dir = 1 }, -/obj/machinery/light/small/directional/south, -/obj/structure/industrial_lift/tram, -/turf/open/floor/noslip/tram_platform, +/obj/structure/transport/linear/tram, +/obj/structure/thermoplastic, +/turf/open/floor/tram, /area/station/security/tram) "kSr" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -31406,7 +31343,7 @@ /obj/effect/turf_decal/stripes/white/line{ dir = 6 }, -/turf/open/floor/noslip/tram_platform, +/turf/open/floor/tram, /area/station/maintenance/department/medical/central) "ljk" = ( /obj/effect/turf_decal/stripes/line{ @@ -32052,7 +31989,6 @@ name = "Prison Garden" }, /obj/machinery/door/firedoor, -/obj/effect/landmark/tram/nav/immovable_rod, /turf/open/floor/iron/textured_half{ dir = 8 }, @@ -32420,6 +32356,15 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/iron/smooth, /area/station/maintenance/solars/starboard/aft) +"lBa" = ( +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/structure/fluff/tram_rail/end{ + dir = 4 + }, +/turf/open/floor/plating, +/area/station/maintenance/port/aft) "lBf" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/turf_decal/siding/wood{ @@ -32497,6 +32442,12 @@ /obj/machinery/light/small/directional/south, /turf/open/floor/iron/cafeteria, /area/station/science/circuits) +"lCi" = ( +/obj/effect/turf_decal/stripes/white/line{ + dir = 5 + }, +/turf/open/floor/tram, +/area/station/security/tram) "lCt" = ( /obj/effect/turf_decal/siding/red{ dir = 1 @@ -32655,6 +32606,15 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/iron, /area/station/cargo/storage) +"lFH" = ( +/obj/effect/turf_decal/stripes/white/line{ + dir = 4 + }, +/obj/effect/turf_decal/stripes/white/line{ + dir = 8 + }, +/turf/open/floor/tram, +/area/station/security/tram) "lGe" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -33502,11 +33462,6 @@ /obj/structure/reagent_dispensers/watertank, /turf/open/floor/plating, /area/station/maintenance/department/science/xenobiology) -"lTs" = ( -/obj/effect/decal/cleanable/dirt, -/obj/machinery/light/cold/directional/west, -/turf/open/floor/plating, -/area/station/security/tram) "lTt" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -33562,6 +33517,13 @@ }, /turf/open/floor/iron/dark, /area/station/cargo/storage) +"lUA" = ( +/obj/effect/turf_decal/stripes/white/line{ + dir = 1 + }, +/obj/effect/turf_decal/stripes/white/line, +/turf/open/floor/tram, +/area/station/maintenance/port/aft) "lUE" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -35593,6 +35555,15 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/plating, /area/station/maintenance/port/fore) +"mFD" = ( +/obj/structure/flora/bush/flowers_br/style_random, +/obj/structure/flora/rock/pile/style_random, +/obj/structure/window/reinforced/spawner/directional/west, +/obj/effect/turf_decal/siding/wideplating{ + dir = 4 + }, +/turf/open/misc/sandy_dirt, +/area/station/security/tram) "mFG" = ( /obj/machinery/telecomms/processor/preset_four, /obj/effect/decal/cleanable/dirt, @@ -35647,13 +35618,6 @@ /obj/structure/sink/directional/west, /turf/open/floor/iron/white/small, /area/station/medical/storage) -"mGQ" = ( -/obj/effect/turf_decal/stripes/white/line{ - dir = 1 - }, -/obj/structure/frame/machine, -/turf/open/floor/noslip/tram_platform, -/area/station/maintenance/department/medical/central) "mGT" = ( /obj/structure/cable, /obj/machinery/door/airlock{ @@ -35704,15 +35668,11 @@ /area/station/medical/virology) "mId" = ( /obj/structure/window/reinforced/spawner/directional/west, -/obj/machinery/button/tram{ - id = 2; - lift_id = "prison_tram"; - pixel_y = 32 - }, -/obj/machinery/destination_sign/indicator{ - pixel_y = 32; - tram_id = "prison_tram" +/obj/machinery/button/transport/tram/directional/north{ + specific_transport_id = "bird_1"; + id = 2 }, +/obj/machinery/transport/destination_sign/indicator/directional/north, /turf/open/floor/noslip, /area/station/security/tram) "mIg" = ( @@ -36146,10 +36106,6 @@ /obj/effect/landmark/generic_maintenance_landmark, /turf/open/floor/light/colour_cycle/dancefloor_b, /area/station/maintenance/starboard/central) -"mOP" = ( -/obj/effect/landmark/tram/platform/birdshot/prison_wing, -/turf/open/floor/noslip/tram_platform, -/area/station/security/tram) "mOT" = ( /obj/structure/disposalpipe/segment, /obj/effect/mapping_helpers/broken_floor, @@ -36294,6 +36250,17 @@ /obj/effect/spawner/random/maintenance, /turf/open/floor/plating, /area/station/maintenance/starboard/central) +"mSM" = ( +/obj/structure/transport/linear/tram, +/obj/structure/fluff/tram_rail/floor{ + dir = 1 + }, +/obj/structure/thermoplastic, +/obj/structure/chair/sofa/bench/tram/right{ + dir = 1 + }, +/turf/open/floor/tram, +/area/station/maintenance/port/aft) "mTd" = ( /obj/structure/closet/crate{ name = "Starups Clothing Crate" @@ -36502,6 +36469,12 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/iron, /area/station/science/lower) +"mWh" = ( +/obj/effect/turf_decal/stripes/white/line{ + dir = 1 + }, +/turf/open/floor/tram, +/area/station/security/tram) "mWk" = ( /obj/structure/cable, /obj/item/storage/bag/trash, @@ -36845,10 +36818,10 @@ /area/station/maintenance/central/greater) "ndA" = ( /obj/effect/turf_decal/stripes/white/line{ - dir = 1 + dir = 10 }, -/obj/effect/spawner/random/structure/girder, -/turf/open/floor/noslip/tram_platform, +/obj/item/stack/sheet/mineral/titanium, +/turf/open/floor/tram, /area/station/security/tram) "ndM" = ( /obj/structure/tank_dispenser/oxygen, @@ -36883,6 +36856,10 @@ }, /turf/open/floor/wood/tile, /area/station/commons/vacant_room/commissary) +"neN" = ( +/obj/effect/landmark/transport/nav_beacon/tram/nav/immovable_rod, +/turf/closed/wall, +/area/station/maintenance/port/aft) "neZ" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -37370,6 +37347,12 @@ /obj/effect/turf_decal/tile/neutral/opposingcorners, /turf/open/floor/iron, /area/station/hallway/secondary/spacebridge) +"nnW" = ( +/obj/effect/turf_decal/stripes/white/line, +/obj/structure/transport/linear/tram, +/obj/structure/tram, +/turf/open/floor/tram, +/area/station/security/tram) "noe" = ( /obj/structure/cable, /obj/structure/disposalpipe/segment, @@ -37835,6 +37818,12 @@ /obj/structure/cable, /turf/open/floor/iron, /area/station/commons/dorms) +"nwf" = ( +/obj/effect/turf_decal/stripes/white/line{ + dir = 6 + }, +/turf/open/floor/tram, +/area/station/security/tram) "nwg" = ( /obj/structure/disposalpipe/segment{ dir = 9 @@ -38639,13 +38628,6 @@ /obj/structure/cable, /turf/open/floor/iron/small, /area/station/maintenance/solars/starboard/fore) -"nJm" = ( -/obj/effect/turf_decal/stripes/white/line{ - dir = 1 - }, -/obj/effect/spawner/random/maintenance, -/turf/open/floor/noslip/tram_platform, -/area/station/maintenance/department/medical/central) "nJx" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -38762,6 +38744,13 @@ /obj/effect/spawner/random/structure/grille, /turf/open/floor/plating, /area/station/maintenance/central/greater) +"nLg" = ( +/obj/effect/turf_decal/stripes/white/line{ + dir = 6 + }, +/obj/effect/spawner/random/structure/girder, +/turf/open/floor/tram, +/area/station/security/tram) "nLN" = ( /obj/structure/cable, /obj/structure/disposalpipe/segment, @@ -39527,13 +39516,6 @@ "ocb" = ( /turf/open/floor/iron/white/small, /area/station/science/cubicle) -"ocg" = ( -/obj/effect/turf_decal/stripes/white/line{ - dir = 1 - }, -/obj/item/stack/sheet/mineral/titanium, -/turf/open/floor/noslip/tram_platform, -/area/station/maintenance/department/medical/central) "ocs" = ( /obj/structure/cable, /obj/structure/disposalpipe/segment{ @@ -40292,10 +40274,6 @@ /obj/item/kirbyplants/random, /turf/open/floor/iron, /area/station/hallway/secondary/dock) -"oqS" = ( -/obj/effect/landmark/tram/platform/birdshot/maint_right, -/turf/open/floor/noslip/tram_plate, -/area/station/maintenance/department/medical/central) "oqT" = ( /obj/structure/disposalpipe/segment{ dir = 4 @@ -40840,17 +40818,6 @@ /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron, /area/station/hallway/primary/port) -"oBo" = ( -/obj/structure/flora/bush/lavendergrass/style_random, -/obj/structure/window/reinforced/spawner/directional/west, -/obj/effect/turf_decal/siding/wideplating{ - dir = 4 - }, -/obj/machinery/light/floor{ - pixel_x = 32 - }, -/turf/open/misc/sandy_dirt, -/area/station/security/tram) "oBA" = ( /obj/structure/cable, /obj/structure/disposalpipe/segment, @@ -41131,14 +41098,13 @@ /turf/open/floor/plating, /area/station/maintenance/starboard/greater) "oGS" = ( -/obj/effect/turf_decal/stripes/white/line{ - dir = 9 - }, -/obj/structure/industrial_lift/tram/subfloor, -/obj/structure/window/reinforced/tram/front{ - icon_state = "tram_window-5" +/obj/structure/transport/linear/tram, +/obj/effect/turf_decal/stripes/white/corner, +/obj/effect/turf_decal/stripes/white/corner{ + dir = 4 }, -/turf/open/floor/noslip/tram_platform, +/obj/structure/tram, +/turf/open/floor/tram, /area/station/maintenance/port/aft) "oHa" = ( /obj/structure/table, @@ -41386,6 +41352,14 @@ /obj/machinery/airalarm/directional/south, /turf/open/floor/iron/white/small, /area/station/service/hydroponics) +"oMD" = ( +/obj/effect/turf_decal/stripes/white/line{ + dir = 9 + }, +/obj/structure/transport/linear/tram, +/obj/structure/tram, +/turf/open/floor/tram, +/area/station/maintenance/port/aft) "oMF" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/effect/turf_decal/tile/neutral, @@ -41402,6 +41376,12 @@ /obj/effect/landmark/event_spawn, /turf/open/floor/iron/white/small, /area/station/medical/storage) +"oNk" = ( +/obj/effect/turf_decal/stripes/white/line{ + dir = 9 + }, +/turf/open/floor/tram, +/area/station/maintenance/department/medical/central) "oNn" = ( /obj/machinery/atmospherics/pipe/heat_exchanging/junction{ dir = 8 @@ -41434,10 +41414,12 @@ /obj/effect/turf_decal/stripes/white/line{ dir = 1 }, -/obj/structure/industrial_lift/tram/white, -/obj/structure/window/reinforced/tram/directional/north, -/obj/structure/chair/sofa/bench/left, -/turf/open/floor/noslip/tram_platform, +/obj/structure/transport/linear/tram, +/obj/machinery/transport/tram_controller{ + configured_transport_id = "bird_2" + }, +/obj/structure/tram, +/turf/open/floor/tram, /area/station/maintenance/port/aft) "oNX" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -41516,6 +41498,13 @@ /obj/machinery/portable_atmospherics/canister, /turf/open/floor/iron, /area/station/maintenance/port/fore) +"oPa" = ( +/obj/effect/turf_decal/stripes/white/line{ + dir = 5 + }, +/obj/item/stack/sheet/mineral/titanium, +/turf/open/floor/tram, +/area/station/maintenance/department/medical/central) "oPc" = ( /obj/structure/window/reinforced/spawner/directional/west, /obj/machinery/computer/upload/borg{ @@ -41941,12 +41930,9 @@ /obj/effect/turf_decal/stripes/white/line{ dir = 4 }, -/obj/structure/window/reinforced/tram/directional/east, -/obj/structure/chair{ - dir = 1 - }, -/obj/structure/industrial_lift/tram, -/turf/open/floor/noslip/tram_platform, +/obj/structure/transport/linear/tram, +/obj/structure/tram, +/turf/open/floor/tram, /area/station/security/tram) "oXs" = ( /obj/effect/decal/cleanable/dirt, @@ -42186,12 +42172,6 @@ /obj/machinery/light/small/directional/east, /turf/open/floor/iron/smooth, /area/station/service/greenroom) -"pca" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/effect/turf_decal/tile/neutral, -/obj/effect/landmark/tram/nav/immovable_rod, -/turf/open/floor/iron, -/area/station/hallway/primary/port) "pcb" = ( /obj/effect/turf_decal/tile/dark_red{ dir = 4 @@ -42643,6 +42623,12 @@ }, /turf/open/floor/iron, /area/station/hallway/primary/central/fore) +"pjI" = ( +/obj/effect/turf_decal/stripes/white/line{ + dir = 4 + }, +/turf/open/floor/tram, +/area/station/maintenance/department/medical/central) "pjL" = ( /obj/structure/disposalpipe/segment, /obj/effect/turf_decal/trimline/blue/filled/line{ @@ -43032,9 +43018,6 @@ /obj/structure/window/reinforced/spawner/directional/east, /turf/open/space/basic, /area/space) -"pqf" = ( -/turf/open/floor/noslip/tram_platform, -/area/station/maintenance/department/medical/central) "pqm" = ( /turf/closed/wall/r_wall, /area/station/engineering/storage/tcomms) @@ -43113,9 +43096,12 @@ /turf/open/floor/iron/cafeteria, /area/station/service/kitchen) "prT" = ( -/obj/effect/turf_decal/stripes/white/line, +/obj/effect/turf_decal/stripes/white/line{ + dir = 1 + }, /obj/effect/spawner/random/maintenance, -/turf/open/floor/noslip/tram_platform, +/obj/effect/spawner/random/structure/girder, +/turf/open/floor/tram, /area/station/maintenance/department/medical/central) "prW" = ( /obj/effect/turf_decal/stripes/red/line{ @@ -43429,13 +43415,6 @@ }, /turf/open/floor/iron/white/side, /area/station/science/research) -"pwG" = ( -/obj/effect/landmark/lift_id{ - specific_lift_id = "prison_tram" - }, -/obj/structure/industrial_lift/tram/white, -/turf/open/floor/noslip/tram_platform, -/area/station/security/tram) "pwJ" = ( /obj/structure/disposalpipe/segment{ dir = 4 @@ -43469,20 +43448,13 @@ /turf/open/floor/iron, /area/station/service/hydroponics) "pxs" = ( -/obj/effect/turf_decal/stripes/white/corner{ - dir = 1 - }, -/obj/effect/turf_decal/stripes/white/corner{ +/obj/structure/transport/linear/tram, +/obj/effect/turf_decal/stripes/white/line{ dir = 8 }, -/obj/structure/industrial_lift/tram/subfloor, -/obj/structure/window/reinforced/tram/front{ - icon_state = "tram_window-3" - }, -/obj/machinery/computer/tram_controls/directional/west{ - specific_lift_id = "maint_tram" - }, -/turf/open/floor/noslip/tram_plate, +/obj/structure/fluff/tram_rail/floor, +/obj/structure/tram, +/turf/open/floor/tram, /area/station/maintenance/port/aft) "pxw" = ( /obj/structure/cable, @@ -43892,15 +43864,6 @@ }, /turf/open/floor/wood/tile, /area/station/service/lawoffice) -"pDG" = ( -/obj/effect/turf_decal/stripes/white/line{ - dir = 1 - }, -/obj/structure/frame/computer{ - dir = 1 - }, -/turf/open/floor/noslip/tram_platform, -/area/station/maintenance/department/medical/central) "pDQ" = ( /obj/structure/cable, /obj/structure/table/glass, @@ -44485,13 +44448,6 @@ }, /turf/open/floor/wood/tile, /area/station/command/corporate_showroom) -"pNm" = ( -/obj/effect/turf_decal/stripes/white/line{ - dir = 1 - }, -/obj/effect/spawner/random/structure/girder, -/turf/open/floor/noslip/tram_platform, -/area/station/maintenance/department/medical/central) "pNy" = ( /obj/structure/disposalpipe/segment{ dir = 9 @@ -44527,6 +44483,13 @@ /obj/machinery/duct, /turf/open/floor/plating, /area/station/maintenance/port/greater) +"pOe" = ( +/obj/effect/turf_decal/stripes/white/line{ + dir = 8 + }, +/obj/machinery/light/cold/directional/west, +/turf/open/floor/tram, +/area/station/security/tram) "pOg" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -46302,6 +46265,13 @@ /obj/machinery/airalarm/directional/east, /turf/open/floor/iron/white/small, /area/station/science/ordnance/storage) +"qnK" = ( +/obj/effect/turf_decal/stripes/white/line{ + dir = 1 + }, +/obj/effect/spawner/random/maintenance, +/turf/open/floor/tram, +/area/station/maintenance/department/medical/central) "qnL" = ( /obj/structure/cable, /obj/structure/disposalpipe/segment, @@ -46646,15 +46616,6 @@ /obj/machinery/light/small/directional/south, /turf/open/floor/grass, /area/station/service/hydroponics/garden/monastery) -"quQ" = ( -/obj/effect/turf_decal/stripes/white/line{ - dir = 4 - }, -/obj/effect/turf_decal/stripes/white/line{ - dir = 8 - }, -/turf/open/floor/noslip/tram_platform, -/area/station/security/tram) "quS" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -46883,6 +46844,10 @@ /obj/structure/reagent_dispensers/watertank, /turf/open/floor/plating/rust, /area/station/maintenance/fore/lesser) +"qyI" = ( +/obj/effect/spawner/random/structure/girder, +/turf/open/floor/tram, +/area/station/maintenance/department/medical/central) "qyN" = ( /obj/structure/railing, /turf/open/space/basic, @@ -47235,7 +47200,7 @@ /obj/effect/turf_decal/stripes/white/line{ dir = 1 }, -/turf/open/floor/noslip/tram_platform, +/turf/open/floor/tram, /area/station/maintenance/department/medical/central) "qDK" = ( /obj/machinery/light_switch/directional/west, @@ -47614,6 +47579,14 @@ /obj/effect/spawner/structure/window, /turf/open/floor/plating, /area/station/service/cafeteria) +"qKH" = ( +/obj/effect/turf_decal/stripes/white/line{ + dir = 5 + }, +/obj/structure/transport/linear/tram, +/obj/structure/tram, +/turf/open/floor/tram, +/area/station/security/tram) "qKI" = ( /obj/machinery/portable_atmospherics/pump, /turf/open/floor/iron/small, @@ -47819,8 +47792,10 @@ /turf/open/floor/iron, /area/station/hallway/primary/port) "qOv" = ( -/obj/structure/industrial_lift/tram/white, -/turf/open/floor/noslip/tram_plate, +/obj/structure/transport/linear/tram, +/obj/structure/fluff/tram_rail/floor, +/obj/structure/thermoplastic, +/turf/open/floor/tram, /area/station/maintenance/port/aft) "qOG" = ( /obj/structure/cable, @@ -47855,10 +47830,6 @@ }, /turf/open/floor/iron/smooth, /area/station/cargo/drone_bay) -"qOO" = ( -/obj/item/stack/sheet/mineral/titanium, -/turf/open/floor/noslip/tram_platform, -/area/station/maintenance/department/medical/central) "qPc" = ( /obj/effect/turf_decal/tile/green/opposingcorners{ dir = 1 @@ -47869,6 +47840,12 @@ "qPN" = ( /turf/closed/wall/r_wall, /area/station/security/prison/safe) +"qQd" = ( +/obj/effect/turf_decal/stripes/white/line{ + dir = 5 + }, +/turf/open/floor/tram, +/area/station/maintenance/department/medical/central) "qQg" = ( /obj/structure/cable, /obj/structure/disposalpipe/segment{ @@ -48264,10 +48241,9 @@ /obj/effect/turf_decal/stripes/white/line{ dir = 1 }, -/obj/structure/industrial_lift/tram/white, -/obj/structure/window/reinforced/tram/directional/north, -/obj/structure/chair/sofa/bench/right, -/turf/open/floor/noslip/tram_platform, +/obj/structure/transport/linear/tram, +/obj/structure/tram, +/turf/open/floor/tram, /area/station/maintenance/port/aft) "qVK" = ( /obj/machinery/firealarm/directional/west, @@ -48293,8 +48269,12 @@ /turf/open/floor/wood, /area/station/cargo/boutique) "qWd" = ( -/obj/structure/frame/machine, -/turf/open/floor/noslip/tram_platform, +/obj/effect/turf_decal/stripes/white/line{ + dir = 4 + }, +/obj/effect/spawner/random/maintenance, +/obj/effect/spawner/random/structure/girder, +/turf/open/floor/tram, /area/station/security/tram) "qWh" = ( /obj/structure/cable, @@ -49275,15 +49255,6 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/wood, /area/station/cargo/boutique) -"rlV" = ( -/obj/effect/turf_decal/stripes/white/line{ - dir = 4 - }, -/obj/structure/frame/computer{ - dir = 4 - }, -/turf/open/floor/noslip/tram_platform, -/area/station/security/tram) "rma" = ( /obj/machinery/atmospherics/pipe/smart/simple/general/visible{ dir = 6 @@ -49748,6 +49719,14 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/iron, /area/station/science/lower) +"rup" = ( +/obj/effect/turf_decal/stripes/white/line{ + dir = 5 + }, +/obj/structure/transport/linear/tram, +/obj/structure/tram, +/turf/open/floor/tram, +/area/station/maintenance/port/aft) "ruC" = ( /obj/structure/window/reinforced/spawner/directional/east, /obj/effect/turf_decal/tile/green/anticorner/contrasted, @@ -49981,9 +49960,9 @@ /obj/effect/turf_decal/stripes/white/line{ dir = 10 }, -/obj/structure/window/reinforced/tram/front, -/obj/structure/industrial_lift/tram/subfloor, -/turf/open/floor/noslip/tram_platform, +/obj/structure/transport/linear/tram, +/obj/structure/tram, +/turf/open/floor/tram, /area/station/security/tram) "ryk" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -51489,7 +51468,7 @@ /obj/effect/turf_decal/stripes/white/line{ dir = 10 }, -/turf/open/floor/noslip/tram_platform, +/turf/open/floor/tram, /area/station/security/tram) "rVH" = ( /obj/effect/turf_decal/tile/blue/fourcorners, @@ -51730,12 +51709,6 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/catwalk_floor/flat_white, /area/station/science/robotics/augments) -"rZk" = ( -/obj/structure/rack, -/obj/machinery/light/small/directional/north, -/obj/structure/industrial_lift/tram, -/turf/open/floor/noslip/tram_platform, -/area/station/security/tram) "rZn" = ( /obj/structure/cable, /obj/structure/disposalpipe/segment, @@ -52009,9 +51982,11 @@ /turf/open/floor/plating, /area/station/maintenance/department/medical/central) "sdC" = ( -/obj/structure/industrial_lift/tram/white, -/obj/machinery/light/small/directional/west, -/turf/open/floor/noslip/tram_plate, +/obj/structure/transport/linear/tram, +/obj/structure/fluff/tram_rail/floor, +/obj/structure/thermoplastic, +/obj/structure/chair/sofa/bench/tram/solo, +/turf/open/floor/tram, /area/station/maintenance/port/aft) "sdQ" = ( /obj/structure/cable, @@ -52551,6 +52526,20 @@ }, /turf/open/floor/iron, /area/station/security/courtroom) +"smM" = ( +/obj/effect/turf_decal/stripes/corner{ + dir = 4 + }, +/obj/effect/turf_decal/stripes/corner{ + dir = 1 + }, +/obj/effect/turf_decal/stripes/corner{ + dir = 8 + }, +/obj/effect/turf_decal/stripes/corner, +/obj/structure/holosign/barrier/atmos/tram, +/turf/open/floor/tram, +/area/station/security/tram) "smV" = ( /obj/structure/chair{ dir = 4 @@ -52924,6 +52913,12 @@ /obj/item/stock_parts/subspace/filter, /turf/open/floor/iron/dark, /area/station/engineering/storage/tcomms) +"ssK" = ( +/obj/structure/transport/linear/tram, +/obj/effect/landmark/transport/transport_id/birdshot/line_1, +/obj/structure/thermoplastic, +/turf/open/floor/tram, +/area/station/security/tram) "ssY" = ( /obj/structure/cable, /turf/open/floor/wood, @@ -57621,6 +57616,13 @@ /obj/machinery/atmospherics/components/unary/vent_pump/on/layer4, /turf/open/floor/iron/cafeteria, /area/station/science/breakroom) +"tWJ" = ( +/obj/effect/turf_decal/stripes/white/line{ + dir = 5 + }, +/obj/effect/spawner/random/structure/girder, +/turf/open/floor/tram, +/area/station/security/tram) "tWL" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/effect/turf_decal/tile/blue{ @@ -58087,14 +58089,6 @@ }, /turf/open/floor/iron/textured_large, /area/station/security/brig/entrance) -"udE" = ( -/obj/effect/turf_decal/stripes/white/line{ - dir = 1 - }, -/obj/effect/spawner/random/maintenance, -/obj/effect/spawner/random/structure/girder, -/turf/open/floor/noslip/tram_platform, -/area/station/maintenance/department/medical/central) "udI" = ( /obj/structure/closet{ name = "Evidence Closet 3" @@ -58229,6 +58223,7 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/effect/decal/cleanable/dirt, +/obj/effect/landmark/transport/nav_beacon/tram/nav/immovable_rod, /turf/open/floor/iron, /area/station/security/prison/garden) "ugb" = ( @@ -58307,7 +58302,7 @@ /obj/effect/turf_decal/stripes/white/line{ dir = 10 }, -/turf/open/floor/noslip/tram_platform, +/turf/open/floor/tram, /area/station/maintenance/department/medical/central) "uhe" = ( /obj/effect/turf_decal/tile/neutral/fourcorners, @@ -58785,14 +58780,9 @@ }, /area/station/science/research) "upR" = ( -/obj/effect/turf_decal/stripes/white/line{ - dir = 5 - }, -/obj/structure/industrial_lift/tram/subfloor, -/obj/structure/window/reinforced/tram/front{ - icon_state = "tram_window-1" - }, -/turf/open/floor/noslip/tram_platform, +/obj/structure/transport/linear/tram, +/obj/structure/tram, +/turf/open/floor/tram, /area/station/maintenance/port/aft) "uqc" = ( /obj/structure/cable, @@ -58914,6 +58904,17 @@ /obj/machinery/firealarm/directional/west, /turf/open/floor/iron/dark/small, /area/station/hallway/secondary/dock) +"urI" = ( +/obj/effect/turf_decal/stripes/white/line{ + dir = 1 + }, +/obj/structure/transport/linear/tram, +/obj/structure/tram, +/obj/machinery/computer/tram_controls{ + specific_transport_id = "bird_2" + }, +/turf/open/floor/tram, +/area/station/maintenance/port/aft) "urM" = ( /obj/effect/turf_decal/tile/dark_red/fourcorners, /obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ @@ -58959,6 +58960,7 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/effect/turf_decal/tile/neutral, /obj/effect/landmark/navigate_destination/chapel, +/obj/effect/landmark/transport/nav_beacon/tram/nav/immovable_rod, /turf/open/floor/iron, /area/station/hallway/primary/port) "uth" = ( @@ -60315,11 +60317,9 @@ /turf/open/floor/iron/smooth, /area/station/maintenance/solars/port/aft) "uRp" = ( -/obj/effect/turf_decal/stripes/white/line{ - dir = 8 - }, -/obj/item/stack/sheet/mineral/titanium, -/turf/open/floor/noslip/tram_platform, +/obj/effect/spawner/random/maintenance, +/obj/effect/spawner/random/structure/girder, +/turf/open/floor/tram, /area/station/security/tram) "uRF" = ( /obj/effect/spawner/structure/window/reinforced, @@ -60414,6 +60414,16 @@ }, /turf/open/floor/iron/textured_half, /area/station/commons/storage/art) +"uTd" = ( +/obj/effect/turf_decal/stripes/line{ + dir = 8 + }, +/obj/effect/turf_decal/stripes/line{ + dir = 4 + }, +/obj/structure/holosign/barrier/atmos/tram, +/turf/open/floor/tram, +/area/station/maintenance/department/medical/central) "uTh" = ( /obj/structure/cable, /obj/effect/turf_decal/tile/green/opposingcorners, @@ -60623,20 +60633,6 @@ "uWo" = ( /turf/closed/wall, /area/station/medical/paramedic) -"uWu" = ( -/obj/effect/turf_decal/stripes/corner{ - dir = 4 - }, -/obj/effect/turf_decal/stripes/corner{ - dir = 1 - }, -/obj/effect/turf_decal/stripes/corner{ - dir = 8 - }, -/obj/effect/turf_decal/stripes/corner, -/obj/structure/holosign/barrier/atmos/tram, -/turf/open/floor/noslip/tram_platform, -/area/station/security/tram) "uWv" = ( /obj/structure/window/reinforced/spawner/directional/east, /obj/structure/flora/bush/flowers_pp/style_random, @@ -61112,11 +61108,9 @@ /obj/effect/turf_decal/stripes/white/line{ dir = 10 }, -/obj/structure/industrial_lift/tram/subfloor, -/obj/structure/window/reinforced/tram/front{ - icon_state = "tram_window-6" - }, -/turf/open/floor/noslip/tram_platform, +/obj/structure/transport/linear/tram, +/obj/structure/tram, +/turf/open/floor/tram, /area/station/maintenance/port/aft) "veA" = ( /obj/machinery/atmospherics/pipe/smart/simple/green/visible, @@ -61179,6 +61173,13 @@ /obj/machinery/light/small/directional/south, /turf/open/floor/iron/smooth_large, /area/station/science/robotics/mechbay) +"vfJ" = ( +/obj/structure/transport/linear/tram, +/obj/effect/landmark/transport/nav_beacon/tram/nav/birdshot/maint, +/obj/effect/landmark/transport/nav_beacon/tram/platform/birdshot/maint_left, +/obj/structure/thermoplastic/light, +/turf/open/floor/tram, +/area/station/maintenance/port/aft) "vfK" = ( /obj/structure/cable, /obj/structure/disposalpipe/segment{ @@ -63372,18 +63373,15 @@ /turf/open/floor/plating, /area/station/maintenance/central/greater) "vNj" = ( -/obj/effect/turf_decal/stripes/white/corner{ - dir = 1 - }, /obj/effect/turf_decal/stripes/white/corner{ dir = 4 }, -/obj/structure/window/reinforced/tram/front, -/obj/machinery/computer/tram_controls/directional/north{ - specific_lift_id = "prison_tram" +/obj/effect/turf_decal/stripes/white/line{ + dir = 1 }, -/obj/structure/industrial_lift/tram/subfloor, -/turf/open/floor/noslip/tram_platform, +/obj/structure/transport/linear/tram, +/obj/structure/tram, +/turf/open/floor/tram, /area/station/security/tram) "vNo" = ( /obj/effect/decal/cleanable/dirt, @@ -63613,24 +63611,6 @@ /obj/effect/mapping_helpers/airlock/access/all/engineering/general, /turf/open/floor/catwalk_floor/iron_smooth, /area/station/maintenance/department/engine) -"vSq" = ( -/obj/effect/turf_decal/stripes/corner, -/obj/effect/turf_decal/stripes/corner{ - dir = 8 - }, -/obj/effect/turf_decal/stripes/corner{ - dir = 4 - }, -/obj/effect/turf_decal/stripes/corner{ - dir = 1 - }, -/obj/structure/holosign/barrier/atmos/tram, -/obj/effect/turf_decal/stripes/white/line{ - dir = 1 - }, -/obj/effect/turf_decal/stripes/white/line, -/turf/open/floor/noslip/tram_plate, -/area/station/maintenance/port/aft) "vSu" = ( /obj/structure/chair{ dir = 8 @@ -63870,6 +63850,12 @@ /obj/machinery/airalarm/directional/south, /turf/open/floor/iron/smooth, /area/station/security/checkpoint/escape) +"vVp" = ( +/obj/effect/turf_decal/stripes/white/line, +/obj/effect/spawner/random/maintenance, +/obj/effect/spawner/random/structure/girder, +/turf/open/floor/tram, +/area/station/maintenance/department/medical/central) "vVw" = ( /obj/effect/turf_decal/tile/red/opposingcorners{ dir = 1 @@ -64434,10 +64420,8 @@ /turf/open/floor/iron, /area/station/construction/mining/aux_base) "weV" = ( -/obj/effect/turf_decal/stripes/white/line{ - dir = 8 - }, -/turf/open/floor/noslip/tram_platform, +/obj/effect/landmark/transport/nav_beacon/tram/platform/birdshot/prison_wing, +/turf/open/floor/tram, /area/station/security/tram) "wfa" = ( /obj/structure/cable, @@ -64490,9 +64474,10 @@ /area/station/science/research) "wfH" = ( /obj/effect/turf_decal/stripes/white/line{ - dir = 9 + dir = 10 }, -/turf/open/floor/noslip/tram_platform, +/obj/item/stack/sheet/mineral/titanium, +/turf/open/floor/tram, /area/station/maintenance/department/medical/central) "wfP" = ( /obj/machinery/door/firedoor, @@ -65991,8 +65976,8 @@ /turf/open/floor/iron/white, /area/station/medical/medbay/central) "wDu" = ( -/obj/effect/turf_decal/stripes/white/line, -/turf/open/floor/noslip/tram_platform, +/obj/effect/landmark/transport/nav_beacon/tram/platform/birdshot/maint_right, +/turf/open/floor/tram, /area/station/maintenance/department/medical/central) "wDA" = ( /obj/effect/turf_decal/tile/neutral/fourcorners, @@ -66230,13 +66215,6 @@ /obj/effect/turf_decal/tile/neutral/opposingcorners, /turf/open/floor/iron, /area/station/hallway/secondary/spacebridge) -"wHY" = ( -/obj/effect/turf_decal/stripes/white/line{ - dir = 9 - }, -/obj/item/stack/sheet/mineral/titanium, -/turf/open/floor/noslip/tram_platform, -/area/station/security/tram) "wIc" = ( /obj/structure/window/spawner/directional/west, /obj/structure/flora/rock/pile/jungle/style_random, @@ -67147,6 +67125,17 @@ }, /turf/open/floor/iron, /area/station/security) +"wUf" = ( +/obj/structure/transport/linear/tram, +/obj/effect/turf_decal/stripes/white/line{ + dir = 4 + }, +/obj/structure/fluff/tram_rail/floor{ + dir = 1 + }, +/obj/structure/tram, +/turf/open/floor/tram, +/area/station/maintenance/port/aft) "wUZ" = ( /obj/structure/cable, /obj/structure/disposalpipe/segment{ @@ -68545,9 +68534,6 @@ /obj/effect/mapping_helpers/airalarm/mixingchamber_access, /turf/open/floor/iron/dark, /area/station/science/ordnance/burnchamber) -"xnU" = ( -/turf/open/floor/noslip/tram_plate, -/area/station/maintenance/department/medical/central) "xoa" = ( /obj/structure/disposalpipe/segment{ dir = 4 @@ -68780,14 +68766,11 @@ /area/station/hallway/primary/starboard) "xrh" = ( /obj/structure/window/reinforced/spawner/directional/west, -/obj/machinery/button/tram{ - lift_id = "prison_tram"; - pixel_y = 32 - }, -/obj/machinery/destination_sign/indicator{ - pixel_y = 32; - tram_id = "prison_tram" +/obj/machinery/button/transport/tram/directional/north{ + specific_transport_id = "bird_1"; + id = 1 }, +/obj/machinery/transport/destination_sign/indicator/directional/north, /turf/open/floor/noslip, /area/station/security/tram) "xrk" = ( @@ -69214,6 +69197,13 @@ /obj/structure/barricade/wooden/crude, /turf/open/floor/plating, /area/station/maintenance/starboard/central) +"xwP" = ( +/obj/effect/turf_decal/stripes/white/line{ + dir = 8 + }, +/obj/effect/spawner/random/structure/girder, +/turf/open/floor/tram, +/area/station/security/tram) "xwQ" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/turf_decal/stripes/white/line{ @@ -69686,13 +69676,6 @@ }, /turf/open/floor/iron/small, /area/station/hallway/primary/starboard) -"xDM" = ( -/obj/effect/turf_decal/stripes/white/line{ - dir = 10 - }, -/obj/item/stack/sheet/mineral/titanium, -/turf/open/floor/noslip/tram_platform, -/area/station/security/tram) "xDW" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -70240,6 +70223,14 @@ dir = 4 }, /area/station/science/xenobiology) +"xKZ" = ( +/obj/effect/turf_decal/stripes/white/line{ + dir = 1 + }, +/obj/structure/transport/linear/tram, +/obj/structure/tram, +/turf/open/floor/tram, +/area/station/security/tram) "xLc" = ( /obj/effect/spawner/structure/window, /obj/machinery/door/poddoor/shutters/preopen{ @@ -70418,13 +70409,6 @@ /obj/machinery/door/firedoor, /turf/open/floor/catwalk_floor/flat_white, /area/station/science/auxlab/firing_range) -"xNW" = ( -/obj/effect/turf_decal/stripes/white/corner{ - dir = 4 - }, -/obj/effect/turf_decal/stripes/white/corner, -/turf/open/floor/noslip/tram_plate, -/area/station/maintenance/department/medical/central) "xNZ" = ( /obj/structure/disposalpipe/sorting/mail/flip{ dir = 4 @@ -70843,6 +70827,18 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/iron/white, /area/station/hallway/primary/starboard) +"xSL" = ( +/obj/structure/flora/bush/large/style_random{ + pixel_x = -18; + pixel_y = -9 + }, +/obj/structure/flora/bush/flowers_yw/style_random, +/obj/structure/window/reinforced/spawner/directional/west, +/obj/effect/turf_decal/siding/wideplating{ + dir = 4 + }, +/turf/open/misc/sandy_dirt, +/area/station/security/tram) "xSO" = ( /obj/effect/spawner/structure/window/reinforced, /turf/open/floor/plating, @@ -71582,13 +71578,6 @@ }, /turf/open/floor/iron/white, /area/station/science/research) -"ycv" = ( -/obj/effect/turf_decal/stripes/white/line{ - dir = 1 - }, -/obj/effect/turf_decal/stripes/white/line, -/turf/open/floor/noslip/tram_plate, -/area/station/maintenance/department/medical/central) "ycC" = ( /turf/closed/wall/r_wall, /area/station/command/bridge) @@ -71898,6 +71887,9 @@ /obj/effect/spawner/random/engineering/atmospherics_portable, /turf/open/floor/plating, /area/station/maintenance/central/greater) +"ygs" = ( +/turf/open/floor/tram, +/area/station/maintenance/department/medical/central) "ygu" = ( /turf/open/floor/iron/white, /area/station/hallway/primary/starboard) @@ -72011,10 +72003,6 @@ /obj/structure/window/spawner/directional/north, /turf/open/floor/plating, /area/station/maintenance/department/engine) -"yhE" = ( -/obj/effect/landmark/tram/nav/immovable_rod, -/turf/closed/wall, -/area/station/maintenance/port/aft) "yhF" = ( /obj/machinery/door/firedoor, /turf/open/floor/iron, @@ -84069,7 +84057,7 @@ cGj cGj cGj cGj -aJq +rtQ aJq aJq aJq @@ -84327,14 +84315,14 @@ vUM sbW cGj rtQ -aJq -aJq -aJq -aJq -aJq -aJq -aJq -aJq +rtQ +rtQ +rtQ +rtQ +rtQ +rtQ +rtQ +rtQ aJq aJq aJq @@ -84583,14 +84571,14 @@ lce vKU lPO vfc -rtQ -rtQ -rtQ -rtQ -rtQ -rtQ -rtQ -rtQ +lzM +nLg +eIN +xwP +eIN +aWy +tWJ +ieZ rtQ aJq aJq @@ -84842,7 +84830,7 @@ dLn rxu lzM jfX -cJu +kKy kKy cJu uRp @@ -85100,7 +85088,7 @@ rcg lzM ndA qWd -qWd +kLG dhX iyk ays @@ -85355,30 +85343,31 @@ uRW kxO lwc lzM -xDM -acO -kLG -bQz -rlV -wHY +ieZ +ieZ +ieZ +ieZ +ieZ +ieZ ieZ rtQ +lzM aJq -aJq -aJq -tYT -tYT -tYT vmL vmL -tYT -tYT vmL vmL -tYT +vmL +vmL +vmL +vmL +vmL +vmL +aJq aJq aJq aJq +gcs aJq aJq aJq @@ -85387,8 +85376,7 @@ aJq aJq aJq aJq -rMm -vqH +blb uPX uPX uPX @@ -85612,43 +85600,43 @@ pxj hAC cVC lzM -ieZ -ieZ -ieZ -ieZ -ieZ -ieZ -ieZ +hsZ +hsZ +hsZ +hsZ +hsZ +hsZ +lzM rtQ -aJq -aJq -aJq -vmL -tYT -vmL -tYT -tYT -vmL -vmL -vmL -tYT -aJq -aJq -aJq -aJq -aJq -aJq -aJq -aJq -aJq -aJq -aJq -aJq -aJq -blb -dDB -dDB -dDB +kaI +dRk +nlV +toT +kaI +tlI +mFD +uEI +gxx +gxx +xSL +jYv +nlV +sGp +tij +qQo +uEI +lzM +lzM +lzM +lzM +lzM +lzM +lzM +lzM +lzM +xAG +xAG +tDn jZJ iTP jZJ @@ -85868,43 +85856,43 @@ cGj mZc hXU hXU -lzM -hsZ -hsZ -hsZ -hsZ -hsZ -hsZ -lzM -rtQ -lzM -aJq -vmL -vmL -vmL -vmL -vmL -vmL -vmL -vmL -vmL -vmL -aJq -aJq -aJq -aJq -lzM -lzM -lzM -lzM -lzM -lzM -lzM -lzM -lzM -lzM -xAG +aFR +cum +bOQ +bOQ +bOQ +bOQ +qKH +aFR +kGC +qBi +qBi +qBi +qBi +qBi +qBi +qBi +qBi +qBi +qBi +qBi +qBi +qBi +qBi +qBi +qBi +qBi +ltp +qBi +nwf +fEL +pOe +fEL +fEL +lCi +qBi xAG +pGR tDn jZJ npp @@ -86126,40 +86114,40 @@ ccD yap lzM ezE +xKZ +eBv +jEX +jEX +jku +nnW aFR -aFR -aFR -aFR -aFR -aFR -aFR -rtQ -ius -dRk -nlV -toT -kaI -tlI -fuk -uEI -gxx -gxx -jqs -jYv -nlV -sGp -tij -qQo -oBo -lzM +kGC +qBi +qBi +qBi +qBi +qBi +qBi +qBi +qBi qBi qBi qBi -lTs qBi qBi qBi qBi +qBi +qBi +ltp +qBi +mWh +jYd +jYd +jYd +jYd +dgg +qBi xAG pGR tDn @@ -86385,37 +86373,37 @@ lzM aFR hYz gkO -aPe +ssK aPe jEX jUN -aFR -kGC -qBi -qBi -qBi -qBi -qBi -qBi -qBi -qBi -qBi -qBi -qBi -qBi -qBi -qBi -qBi -qBi -qBi -ltp -aFR -gTC -weV -weV -weV +fVC +smM +fVC +fVC +fVC +fVC +fVC +fVC +fVC +fVC +fVC +fVC +fVC +fVC +fVC +fVC +fVC +fVC +fVC +fkN +lFH +jYd +jYd +jYd weV jYd +jYd qBi iJt pGR @@ -86599,7 +86587,7 @@ tdg wBm wXk bVv -pca +xOS rQC von vRe @@ -86641,38 +86629,38 @@ eWB lzM aFR vNj -rZk -pwG -kvb +eBv +jEX +jEX kSo kyS -kNA -uWu -kNA -kNA -kNA -kNA -kNA -kNA -kNA -kNA -kNA -kNA -kNA -kNA -kNA -kNA -kNA -kNA -kNA -kjn -quQ -aYO -fay -fay -mOP -fay -ipn +aFR +kGC +qBi +qBi +qBi +qBi +qBi +qBi +qBi +qBi +qBi +qBi +qBi +qBi +qBi +qBi +qBi +qBi +qBi +ltp +qBi +mWh +jYd +jYd +jYd +jYd +dgg qBi xAG pSd @@ -86898,7 +86886,7 @@ vzY lzM aFR ryj -eTq +oXh cID cID oXh @@ -88710,13 +88698,13 @@ trp trp trp trp -yhE +trp +neN +trp trp trp trp trp -dDB -dDB dDB dDB dDB @@ -88969,6 +88957,8 @@ hQE xAR fos xAR +lBa +xAR xAR xAR trp @@ -88976,8 +88966,6 @@ dDB dDB dDB dDB -dDB -dDB wum wum ohu @@ -89226,6 +89214,8 @@ trp eVe pxs upR +cWb +rup vJH xAR trp @@ -89233,8 +89223,6 @@ dDB dDB dDB dDB -dDB -dDB oCq vnq wmS @@ -89483,6 +89471,8 @@ trp qVz sdC eEl +cHt +kDa vJH xAR trp @@ -89490,8 +89480,6 @@ dDB dDB dDB dDB -dDB -dDB oCq gUG fwJ @@ -89739,7 +89727,9 @@ knJ fAr oNM qOv -hUT +eEl +mSM +kDa vJH xAR trp @@ -89747,8 +89737,6 @@ dDB dDB dDB dDB -dDB -dDB oCq iAZ rPT @@ -89997,6 +89985,8 @@ mxM iaZ cSD jwC +crV +kDa vJH xAR trp @@ -90004,8 +89994,6 @@ dDB dDB dDB dDB -dDB -dDB wum wum ygU @@ -90252,8 +90240,10 @@ knJ nFu mxM gTk -jMv -jwC +cSD +vfJ +crV +kDa vJH xAR trp @@ -90262,8 +90252,6 @@ dDB dDB dDB dDB -dDB -dDB wum wum wum @@ -90508,9 +90496,11 @@ gEe bbU knJ fAr -qVz +urI qOv eEl +cHt +kDa vJH xAR trp @@ -90519,8 +90509,6 @@ dDB dDB dDB dDB -dDB -dDB dbY kgu wOl @@ -90765,9 +90753,11 @@ vUf vAU caE trp -oNM -iRp -hUT +qVz +sdC +eEl +mSM +kDa vJH xAR trp @@ -90776,8 +90766,6 @@ dDB dDB dDB dDB -dDB -dDB eeq hhZ fSf @@ -91025,6 +91013,8 @@ trp vez isf oGS +wUf +oMD trp vfi trp @@ -91035,8 +91025,6 @@ dDB dDB dDB dDB -dDB -dDB kND vEW tHK @@ -91280,12 +91268,14 @@ xqd xul trp vJH -iBV +vJH +lUA +vJH vJH trp xAR trp -dDB +bSo wCc dDB dDB @@ -91293,8 +91283,6 @@ dDB dDB dDB dDB -dDB -dDB vEW xwf cSs @@ -91537,12 +91525,14 @@ trp trp trp eHy -vSq +eHy +eHy +eHy eHy trp iMl trp -dDB +bSo wCc dDB dDB @@ -91550,8 +91540,6 @@ dDB dDB dDB dDB -dDB -dDB vEW mEU qYD @@ -91794,9 +91782,11 @@ dDB blb dDB dDB +dDB wte dDB -qyN +dDB +bSo jcE wgv dDB @@ -91807,8 +91797,6 @@ dDB dDB dDB dDB -dDB -dDB vEW vEW vEW @@ -92051,9 +92039,11 @@ dDB blb dDB dDB +dDB wte dDB -qyN +dDB +bSo jcE wgv dDB @@ -92067,8 +92057,6 @@ dDB dDB dDB dDB -dDB -dDB vEW vEW vEW @@ -92306,11 +92294,13 @@ dDB dDB dDB blb -blb -blb +dDB +dDB +dDB wte dDB -qyN +dDB +bSo jcE wgv dDB @@ -92332,8 +92322,6 @@ dDB dDB dDB dDB -dDB -dDB qPN qPN qPN @@ -92565,9 +92553,11 @@ dDB blb dDB dDB +dDB wte dDB -qyN +dDB +bSo jcE wgv dDB @@ -92592,8 +92582,6 @@ dDB dDB dDB dDB -dDB -dDB blb dDB dDB @@ -92822,9 +92810,11 @@ dDB blb dDB dDB +dDB wte dDB -qyN +dDB +bSo jcE wgv dDB @@ -92849,8 +92839,6 @@ dDB dDB dDB dDB -dDB -dDB blb dDB dDB @@ -93077,11 +93065,13 @@ dDB dDB dDB blb -dDB -dDB +blb +blb +blb wte blb -lBy +blb +blb jcE vCm blb @@ -93105,8 +93095,6 @@ dDB dDB dDB dDB -dDB -dDB wCc wCc wCc @@ -93336,9 +93324,11 @@ dDB blb dDB dDB +dDB wte dDB -qyN +dDB +bSo jcE wgv dDB @@ -93403,8 +93393,6 @@ dDB dDB dDB dDB -dDB -dDB "} (83,1,1) = {" dDB @@ -93593,9 +93581,11 @@ dDB blb dDB dDB +dDB wte dDB -qyN +dDB +bSo jcE wgv dDB @@ -93660,8 +93650,6 @@ dDB dDB dDB dDB -dDB -dDB "} (84,1,1) = {" dDB @@ -93848,11 +93836,13 @@ dDB dDB dDB blb -blb -blb +dDB +dDB +dDB wte dDB -qyN +dDB +bSo jcE wgv dDB @@ -93917,8 +93907,6 @@ dDB dDB dDB dDB -dDB -dDB "} (85,1,1) = {" dDB @@ -94107,9 +94095,11 @@ dDB blb dDB dDB +dDB wte dDB -qyN +dDB +bSo jcE wgv dDB @@ -94174,8 +94164,6 @@ dDB dDB dDB dDB -dDB -dDB "} (86,1,1) = {" dDB @@ -94364,9 +94352,11 @@ dDB blb dDB dDB +dDB wte dDB -qyN +dDB +bSo jcE wgv dDB @@ -94431,8 +94421,6 @@ dDB dDB dDB dDB -dDB -dDB "} (87,1,1) = {" dDB @@ -94619,11 +94607,13 @@ dDB dDB dDB blb -dDB -dDB +blb +blb +blb wte blb -lBy +blb +blb jcE vCm blb @@ -94688,8 +94678,6 @@ dDB dDB dDB dDB -dDB -dDB "} (88,1,1) = {" dDB @@ -94878,9 +94866,11 @@ dDB blb dDB dDB +dDB wte dDB -qyN +dDB +bSo jcE wgv dDB @@ -94945,8 +94935,6 @@ dDB dDB dDB dDB -dDB -dDB "} (89,1,1) = {" dDB @@ -95135,9 +95123,11 @@ dDB blb dDB dDB +dDB wte dDB -qyN +dDB +bSo jcE wgv dDB @@ -95151,8 +95141,6 @@ dDB dDB dDB dDB -dDB -dDB aan dDB dDB @@ -95390,11 +95378,13 @@ dDB dDB dDB blb -blb -blb +dDB +dDB +dDB wte dDB -qyN +dDB +bSo jcE wgv dDB @@ -95459,8 +95449,6 @@ dDB dDB dDB dDB -dDB -dDB "} (91,1,1) = {" dDB @@ -95649,9 +95637,11 @@ dDB blb dDB dDB +dDB wte dDB -qyN +dDB +bSo jcE wgv dDB @@ -95716,8 +95706,6 @@ dDB dDB dDB dDB -dDB -dDB "} (92,1,1) = {" dDB @@ -95906,9 +95894,11 @@ dDB blb dDB dDB +dDB wte dDB -qyN +dDB +bSo jcE wgv dDB @@ -95947,8 +95937,6 @@ dDB dDB dDB dDB -dDB -dDB aan dDB dDB @@ -96161,11 +96149,13 @@ dDB dDB dDB blb -dDB -dDB +blb +blb +blb wte blb -lBy +blb +blb jcE vCm blb @@ -96230,8 +96220,6 @@ dDB dDB dDB dDB -dDB -dDB "} (94,1,1) = {" dDB @@ -96420,9 +96408,11 @@ dDB blb dDB dDB +dDB wte dDB -qyN +dDB +bSo jcE wgv dDB @@ -96487,8 +96477,6 @@ dDB dDB dDB dDB -dDB -dDB "} (95,1,1) = {" dDB @@ -96677,9 +96665,11 @@ dDB blb dDB dDB +dDB wte dDB -qyN +dDB +bSo jcE wgv dDB @@ -96744,8 +96734,6 @@ dDB dDB dDB dDB -dDB -dDB "} (96,1,1) = {" dDB @@ -96932,11 +96920,13 @@ dDB dDB dDB blb -blb -blb +dDB +dDB +dDB wte dDB -qyN +dDB +bSo jcE wgv dDB @@ -97001,8 +96991,6 @@ dDB dDB dDB dDB -dDB -dDB "} (97,1,1) = {" dDB @@ -97191,9 +97179,11 @@ dDB blb dDB dDB +dDB wte dDB -qyN +dDB +bSo jcE wgv dDB @@ -97218,8 +97208,6 @@ dDB dDB dDB dDB -dDB -dDB aan dDB dDB @@ -97446,11 +97434,13 @@ dDB dDB dDB blb -dDB -dDB +blb +blb +blb wte blb -lBy +blb +blb jcE vCm blb @@ -97515,8 +97505,6 @@ dDB dDB dDB dDB -dDB -dDB "} (99,1,1) = {" dDB @@ -97705,9 +97693,11 @@ dDB blb dDB dDB +dDB wte dDB -qyN +dDB +bSo jcE wgv dDB @@ -97716,8 +97706,6 @@ dDB dDB dDB dDB -dDB -dDB aan dDB dDB @@ -97962,9 +97950,11 @@ sSQ blb dDB dDB +dDB wte dDB -qyN +dDB +bSo jcE wgv dDB @@ -98029,8 +98019,6 @@ dDB dDB dDB dDB -dDB -dDB "} (101,1,1) = {" dDB @@ -98219,9 +98207,11 @@ sSQ blb dDB dDB +dDB wte dDB -qyN +dDB +bSo jcE wgv dDB @@ -98286,8 +98276,6 @@ dDB dDB dDB dDB -dDB -dDB "} (102,1,1) = {" dDB @@ -98476,7 +98464,9 @@ sSQ blb sSQ lMF -idv +lMF +uTd +lMF lMF sSQ bno @@ -98525,8 +98515,6 @@ dDB dDB dDB dDB -dDB -dDB aan dDB dDB @@ -98733,7 +98721,9 @@ sSQ sSQ sSQ ulO -ycv +ulO +ase +ulO ulO sSQ gpu @@ -98800,8 +98790,6 @@ dDB dDB dDB dDB -dDB -dDB "} (104,1,1) = {" dDB @@ -98990,8 +98978,10 @@ sqV nFy sSQ liU -fqT +bGm kqZ +bGm +qQd sSQ rwq sSQ @@ -99057,8 +99047,6 @@ dDB dDB dDB dDB -dDB -dDB "} (105,1,1) = {" dDB @@ -99247,8 +99235,10 @@ aTc frB sSQ qDD -xnU -wDu +ygs +ygs +ygs +jFz ulO gpu sSQ @@ -99314,8 +99304,6 @@ dDB dDB dDB dDB -dDB -dDB "} (106,1,1) = {" dDB @@ -99504,15 +99492,17 @@ liH uOw eBQ qDD -xnU -wDu +ygs +ygs +ygs +jFz ulO gpu sOj vTG -crr -cuG ksL +kvN +oPa sSQ dDB dDB @@ -99571,8 +99561,6 @@ dDB dDB dDB dDB -dDB -dDB "} (107,1,1) = {" dDB @@ -99761,15 +99749,17 @@ ewW aTc cku qDD -xnU -wDu +ygs +ygs +ygs +jFz ulO gpu sOj vTG -ocg -pqf gjr +ygs +iPw sSQ dDB dDB @@ -99828,8 +99818,6 @@ dDB dDB dDB dDB -dDB -dDB "} (108,1,1) = {" dDB @@ -100018,15 +100006,17 @@ oZY aTc cku qDD -oqS +ygs wDu +ygs +jFz ulO gpu sOj vTG -udE -edW prT +qyI +bVC sSQ dDB dDB @@ -100034,8 +100024,6 @@ dDB dDB dDB dDB -dDB -dDB wCc wCc wCc @@ -100275,15 +100263,17 @@ hia ggl eBQ qDD -xnU -wDu +ygs +ygs +ygs +jFz ulO gpu sOj vTG -pDG -qOO dbO +kyk +vVp sSQ dDB dDB @@ -100294,8 +100284,6 @@ dDB dDB dDB dDB -dDB -dDB blb dDB dDB @@ -100532,15 +100520,17 @@ fWW idW sSQ qDD -xnU -wDu +ygs +ygs +ygs +jFz ulO gpu sOj vTG -pNm -eFi -prT +fXt +jUC +bVC sSQ dDB dDB @@ -100551,8 +100541,6 @@ dDB dDB dDB dDB -dDB -dDB blb dDB dDB @@ -100789,15 +100777,17 @@ lQZ sSQ sSQ ugY -xNW -wfH +pjI +pjI +pjI +oNk ulO gpu sOj vTG -nJm -pqf -prT +qnK +ygs +bVC sSQ dDB dDB @@ -100808,8 +100798,6 @@ dDB dDB dDB dDB -dDB -dDB blb dDB dDB @@ -101046,21 +101034,21 @@ jmW ibE sSQ ulO -pqf +ulO +ulO +ulO ulO ulO gpu sOj vTG -mGQ -edW bFG +qyI +hUO sSQ dDB dDB dDB -dDB -dDB vdg wdB wdB @@ -101306,18 +101294,18 @@ ulO ulO ulO ulO +ulO +ulO gpu sOj vTG -dLd -gwh wfH +pjI +oNk sSQ blb blb blb -blb -blb vav iLR iLR @@ -101563,6 +101551,8 @@ sSQ sSQ sSQ sSQ +sSQ +sSQ nln sSQ vTG @@ -101571,8 +101561,6 @@ vTG vTG sSQ dDB -dDB -dDB blb dDB rMm @@ -101821,15 +101809,15 @@ sSQ qNj qNj kVb -sSQ +kVb +kVb hAu sSQ sSQ sSQ sSQ -vdg -wdB -sxv +sSQ +dDB tCq blb tCq @@ -107729,7 +107717,7 @@ vbR vbR vbR hzI -vbR +hFM vbR vbR fnz diff --git a/_maps/map_files/IceBoxStation/IceBoxStation.dmm b/_maps/map_files/IceBoxStation/IceBoxStation.dmm index 21ce5c6368c..6f2a792489b 100644 --- a/_maps/map_files/IceBoxStation/IceBoxStation.dmm +++ b/_maps/map_files/IceBoxStation/IceBoxStation.dmm @@ -3550,7 +3550,7 @@ /obj/effect/turf_decal/stripes/line{ dir = 5 }, -/obj/structure/industrial_lift{ +/obj/structure/transport/linear{ radial_travel = 0 }, /obj/structure/railing{ @@ -7408,7 +7408,7 @@ /obj/effect/turf_decal/stripes/line{ dir = 8 }, -/obj/structure/industrial_lift{ +/obj/structure/transport/linear{ radial_travel = 0 }, /turf/open/floor/plating/elevatorshaft, @@ -7945,7 +7945,7 @@ /obj/effect/turf_decal/stripes/line{ dir = 9 }, -/obj/structure/industrial_lift{ +/obj/structure/transport/linear{ radial_travel = 0 }, /obj/structure/railing{ @@ -32897,8 +32897,8 @@ id = "publicElevator" }, /obj/machinery/door/window/elevator/left/directional/west{ - elevator_linked_id = "publicElevator"; - elevator_mode = 1 + elevator_mode = 1; + transport_linked_id = "publicElevator" }, /obj/machinery/lift_indicator/directional/north{ linked_elevator_id = "publicElevator" @@ -33498,11 +33498,11 @@ /obj/effect/turf_decal/stripes/line{ dir = 4 }, -/obj/structure/industrial_lift{ +/obj/structure/transport/linear{ radial_travel = 0 }, -/obj/effect/landmark/lift_id{ - specific_lift_id = "publicElevator" +/obj/effect/landmark/transport/transport_id{ + specific_transport_id = "publicElevator" }, /obj/machinery/light/floor, /obj/effect/abstract/elevator_music_zone{ @@ -46934,9 +46934,9 @@ linked_elevator_id = "publicElevator" }, /obj/machinery/door/window/elevator/left/directional/west{ - elevator_linked_id = "publicElevator"; elevator_mode = 1; - req_access = null + req_access = null; + transport_linked_id = "publicElevator" }, /turf/open/floor/iron/dark, /area/mine/storage) @@ -67271,7 +67271,7 @@ /obj/effect/turf_decal/stripes/line{ dir = 6 }, -/obj/structure/industrial_lift{ +/obj/structure/transport/linear{ radial_travel = 0 }, /obj/structure/railing{ @@ -73888,7 +73888,7 @@ /obj/effect/turf_decal/stripes/line{ dir = 10 }, -/obj/structure/industrial_lift{ +/obj/structure/transport/linear{ radial_travel = 0 }, /obj/structure/railing{ diff --git a/_maps/map_files/NorthStar/north_star.dmm b/_maps/map_files/NorthStar/north_star.dmm index 58a80c3942f..656792317cc 100644 --- a/_maps/map_files/NorthStar/north_star.dmm +++ b/_maps/map_files/NorthStar/north_star.dmm @@ -1454,7 +1454,7 @@ /turf/open/floor/iron/dark/side, /area/station/hallway/floor1/fore) "asI" = ( -/obj/structure/industrial_lift/public, +/obj/structure/transport/linear/public, /turf/open/floor/plating/elevatorshaft, /area/station/hallway/floor1/fore) "asL" = ( @@ -3017,8 +3017,8 @@ "aOQ" = ( /obj/machinery/door/firedoor, /obj/machinery/door/poddoor{ - elevator_linked_id = "aft_vator"; - elevator_mode = 1 + elevator_mode = 1; + transport_linked_id = "aft_vator" }, /turf/open/floor/iron/dark, /area/station/hallway/floor3/aft) @@ -3827,9 +3827,9 @@ /turf/open/floor/iron/dark/side, /area/station/hallway/floor3/aft) "aYk" = ( -/obj/structure/industrial_lift/public, -/obj/effect/landmark/lift_id{ - specific_lift_id = "aft_vator" +/obj/structure/transport/linear/public, +/obj/effect/landmark/transport/transport_id{ + specific_transport_id = "aft_vator" }, /obj/effect/abstract/elevator_music_zone{ linked_elevator_id = "aft_vator"; @@ -9212,9 +9212,9 @@ /turf/open/floor/iron/dark/textured, /area/station/commons/fitness) "cni" = ( -/obj/structure/industrial_lift/public, -/obj/effect/landmark/lift_id{ - specific_lift_id = "fore_vator" +/obj/structure/transport/linear/public, +/obj/effect/landmark/transport/transport_id{ + specific_transport_id = "fore_vator" }, /obj/effect/abstract/elevator_music_zone{ linked_elevator_id = "fore_vator"; @@ -9718,8 +9718,8 @@ /obj/effect/turf_decal/delivery, /obj/machinery/door/firedoor/heavy, /obj/machinery/door/poddoor/preopen{ - elevator_linked_id = "com_vator"; - elevator_mode = 1 + elevator_mode = 1; + transport_linked_id = "com_vator" }, /obj/effect/turf_decal/trimline/blue/line{ dir = 4 @@ -16264,7 +16264,7 @@ /turf/open/floor/iron/dark/textured_large, /area/station/security/checkpoint/escape) "ehT" = ( -/obj/structure/industrial_lift/public, +/obj/structure/transport/linear/public, /obj/machinery/elevator_control_panel/directional/west{ linked_elevator_id = "fore_vator"; pixel_x = -24; @@ -16524,8 +16524,8 @@ /obj/effect/turf_decal/delivery, /obj/machinery/door/firedoor/heavy, /obj/machinery/door/poddoor{ - elevator_linked_id = "com_vator"; - elevator_mode = 1 + elevator_mode = 1; + transport_linked_id = "com_vator" }, /turf/open/floor/iron/dark, /area/station/hallway/floor4/aft) @@ -23711,7 +23711,7 @@ /turf/open/floor/iron, /area/station/engineering/atmos) "gmz" = ( -/obj/structure/industrial_lift/public, +/obj/structure/transport/linear/public, /obj/machinery/lift_indicator/directional/east{ linked_elevator_id = "com_vator"; pixel_x = 38; @@ -27709,8 +27709,8 @@ "hoc" = ( /obj/machinery/door/firedoor, /obj/machinery/door/poddoor/preopen{ - elevator_linked_id = "aft_vator"; - elevator_mode = 1 + elevator_mode = 1; + transport_linked_id = "aft_vator" }, /turf/open/floor/iron/dark, /area/station/hallway/floor1/aft) @@ -27785,8 +27785,8 @@ "hpd" = ( /obj/machinery/door/firedoor, /obj/machinery/door/poddoor{ - elevator_linked_id = "fore_vator"; - elevator_mode = 1 + elevator_mode = 1; + transport_linked_id = "fore_vator" }, /turf/open/floor/iron/dark, /area/station/hallway/floor3/fore) @@ -30889,8 +30889,8 @@ /obj/effect/turf_decal/delivery, /obj/machinery/door/firedoor/heavy, /obj/machinery/door/poddoor{ - elevator_linked_id = "com_vator"; - elevator_mode = 1 + elevator_mode = 1; + transport_linked_id = "com_vator" }, /turf/open/floor/iron/dark, /area/station/hallway/floor3/fore) @@ -35618,8 +35618,8 @@ /obj/machinery/door/firedoor/heavy, /obj/effect/turf_decal/delivery, /obj/machinery/door/poddoor{ - elevator_linked_id = "com_vator"; - elevator_mode = 1 + elevator_mode = 1; + transport_linked_id = "com_vator" }, /turf/open/floor/iron/dark, /area/station/hallway/floor4/aft) @@ -48679,8 +48679,8 @@ "mIA" = ( /obj/machinery/door/firedoor, /obj/machinery/door/poddoor{ - elevator_linked_id = "aft_vator"; - elevator_mode = 1 + elevator_mode = 1; + transport_linked_id = "aft_vator" }, /turf/open/floor/iron/dark, /area/station/hallway/floor2/aft) @@ -51985,7 +51985,7 @@ /turf/open/floor/engine/air, /area/station/engineering/atmos) "nyn" = ( -/obj/structure/industrial_lift/public, +/obj/structure/transport/linear/public, /obj/machinery/light/directional/south, /turf/open/floor/plating/elevatorshaft, /area/station/hallway/floor2/fore) @@ -53633,7 +53633,7 @@ /turf/open/floor/carpet/purple, /area/station/commons/dorms/apartment1) "nUI" = ( -/obj/structure/industrial_lift/public, +/obj/structure/transport/linear/public, /obj/machinery/lift_indicator/directional/east{ linked_elevator_id = "aft_vator"; pixel_x = 38; @@ -55719,7 +55719,7 @@ /turf/open/floor/iron/white, /area/station/hallway/floor2/fore) "oxs" = ( -/obj/structure/industrial_lift/public, +/obj/structure/transport/linear/public, /turf/open/floor/plating/elevatorshaft, /area/station/hallway/floor2/fore) "oxz" = ( @@ -57087,8 +57087,8 @@ "oQx" = ( /obj/machinery/door/firedoor, /obj/machinery/door/poddoor/preopen{ - elevator_linked_id = "fore_vator"; - elevator_mode = 1 + elevator_mode = 1; + transport_linked_id = "fore_vator" }, /turf/open/floor/catwalk_floor, /area/station/hallway/floor1/fore) @@ -81725,8 +81725,8 @@ /obj/effect/turf_decal/delivery, /obj/machinery/door/firedoor/heavy, /obj/machinery/door/poddoor/preopen{ - elevator_linked_id = "com_vator"; - elevator_mode = 1 + elevator_mode = 1; + transport_linked_id = "com_vator" }, /turf/open/floor/iron/dark, /area/station/hallway/floor2/fore) @@ -82265,8 +82265,8 @@ /obj/machinery/door/firedoor/heavy, /obj/effect/turf_decal/delivery, /obj/machinery/door/poddoor{ - elevator_linked_id = "com_vator"; - elevator_mode = 1 + elevator_mode = 1; + transport_linked_id = "com_vator" }, /turf/open/floor/iron/dark, /area/station/hallway/floor3/fore) @@ -82539,9 +82539,9 @@ }, /area/station/hallway/secondary/exit) "vCf" = ( -/obj/structure/industrial_lift/public, -/obj/effect/landmark/lift_id{ - specific_lift_id = "com_vator" +/obj/structure/transport/linear/public, +/obj/effect/landmark/transport/transport_id{ + specific_transport_id = "com_vator" }, /obj/effect/abstract/elevator_music_zone{ linked_elevator_id = "com_vator"; @@ -85444,8 +85444,8 @@ "woV" = ( /obj/machinery/door/firedoor, /obj/machinery/door/poddoor{ - elevator_linked_id = "fore_vator"; - elevator_mode = 1 + elevator_mode = 1; + transport_linked_id = "fore_vator" }, /turf/open/floor/iron/dark, /area/station/hallway/floor2/fore) @@ -90210,7 +90210,7 @@ /turf/open/floor/iron/dark/side, /area/station/hallway/floor1/aft) "xzL" = ( -/obj/structure/industrial_lift/public, +/obj/structure/transport/linear/public, /turf/open/floor/plating/elevatorshaft, /area/station/hallway/floor1/aft) "xzP" = ( diff --git a/_maps/map_files/debug/multiz.dmm b/_maps/map_files/debug/multiz.dmm index c1b5b0e2c3f..d545b0cc7b8 100644 --- a/_maps/map_files/debug/multiz.dmm +++ b/_maps/map_files/debug/multiz.dmm @@ -137,7 +137,7 @@ /turf/open/floor/plating, /area/station/engineering/main) "aW" = ( -/obj/structure/industrial_lift/public, +/obj/structure/transport/linear/public, /obj/effect/turf_decal/siding/white{ dir = 1 }, @@ -683,9 +683,9 @@ dir = 4 }, /obj/machinery/door/poddoor/preopen{ - elevator_linked_id = "test_vator"; elevator_mode = 1; - name = "Industrial Lift" + name = "Industrial Lift"; + transport_linked_id = "test_vator" }, /obj/effect/turf_decal/stripes/line{ dir = 8 @@ -1054,7 +1054,7 @@ /turf/open/floor/iron, /area/station/hallway/secondary/service) "lT" = ( -/obj/structure/industrial_lift/public, +/obj/structure/transport/linear/public, /obj/effect/turf_decal/siding/white{ dir = 6 }, @@ -1079,7 +1079,7 @@ }, /area/station/hallway/secondary/entry) "mG" = ( -/obj/structure/industrial_lift/public, +/obj/structure/transport/linear/public, /obj/effect/turf_decal/siding/white{ dir = 8 }, @@ -1108,7 +1108,7 @@ /turf/open/floor/plating, /area/station/hallway/secondary/service) "nS" = ( -/obj/structure/industrial_lift/public, +/obj/structure/transport/linear/public, /obj/effect/turf_decal/siding/white, /turf/open/floor/plating/elevatorshaft, /area/station/commons/storage/primary) @@ -1166,9 +1166,9 @@ dir = 8 }, /obj/machinery/door/poddoor{ - elevator_linked_id = "test_vator"; elevator_mode = 1; - name = "Industrial Lift" + name = "Industrial Lift"; + transport_linked_id = "test_vator" }, /turf/open/floor/iron/edge{ dir = 4 @@ -1333,7 +1333,7 @@ /turf/open/floor/iron, /area/station/hallway/secondary/service) "xK" = ( -/obj/structure/industrial_lift/public, +/obj/structure/transport/linear/public, /obj/effect/turf_decal/siding/white{ dir = 10 }, @@ -1358,18 +1358,18 @@ preset_destination_names = list("2"="Bottom Floor","3"="Middle Floor","4"="Top Floor"); linked_elevator_id = "test_vator" }, -/obj/structure/industrial_lift/public, +/obj/structure/transport/linear/public, /obj/effect/turf_decal/siding/white{ dir = 5 }, /turf/open/floor/plating/elevatorshaft, /area/station/commons/storage/primary) "yX" = ( -/obj/effect/landmark/lift_id{ - specific_lift_id = "test_vator" +/obj/effect/landmark/transport/transport_id{ + specific_transport_id = "test_vator" }, /obj/machinery/light/floor, -/obj/structure/industrial_lift/public, +/obj/structure/transport/linear/public, /turf/open/floor/plating/elevatorshaft, /area/station/commons/storage/primary) "zb" = ( @@ -1417,7 +1417,7 @@ /area/station/engineering/storage) "Bm" = ( /obj/structure/sign/warning/directional/east, -/obj/structure/industrial_lift/public, +/obj/structure/transport/linear/public, /obj/effect/turf_decal/siding/white{ dir = 4 }, @@ -1881,9 +1881,9 @@ /area/station/engineering/storage) "Vo" = ( /obj/machinery/door/poddoor/preopen{ - elevator_linked_id = "test_vator"; elevator_mode = 1; - name = "Industrial Lift" + name = "Industrial Lift"; + transport_linked_id = "test_vator" }, /obj/effect/turf_decal/stripes/line{ dir = 8 @@ -1929,9 +1929,9 @@ dir = 4 }, /obj/machinery/door/poddoor{ - elevator_linked_id = "test_vator"; elevator_mode = 1; - name = "Industrial Lift" + name = "Industrial Lift"; + transport_linked_id = "test_vator" }, /obj/effect/turf_decal/stripes/line{ dir = 8 @@ -1996,7 +1996,7 @@ /turf/open/floor/plating, /area/station/hallway/secondary/service) "Zk" = ( -/obj/structure/industrial_lift/public, +/obj/structure/transport/linear/public, /obj/effect/turf_decal/siding/white{ dir = 9 }, diff --git a/_maps/map_files/tramstation/tramstation.dmm b/_maps/map_files/tramstation/tramstation.dmm index 9bfe7ed759e..bc0520c8149 100644 --- a/_maps/map_files/tramstation/tramstation.dmm +++ b/_maps/map_files/tramstation/tramstation.dmm @@ -121,6 +121,17 @@ /obj/item/stack/ore/glass, /turf/open/misc/asteroid/airless, /area/station/asteroid) +"aay" = ( +/obj/structure/fluff/tram_rail/electric{ + dir = 1 + }, +/obj/structure/transport/linear/tram, +/obj/structure/thermoplastic, +/obj/structure/chair/sofa/bench/tram/right{ + dir = 1 + }, +/turf/open/openspace, +/area/station/hallway/primary/tram/center) "aaz" = ( /obj/effect/turf_decal/trimline/red/filled/line{ dir = 4 @@ -1799,26 +1810,22 @@ /turf/open/openspace, /area/station/asteroid) "afP" = ( -/obj/structure/fluff/tram_rail, +/obj/structure/fluff/tram_rail/electric/anchor, +/obj/structure/lattice, /turf/open/openspace, -/area/station/asteroid) +/area/station/hallway/primary/tram/left) "afQ" = ( /obj/effect/turf_decal/delivery/white, /obj/structure/fluff/tram_rail/floor, /obj/structure/holosign/barrier/atmos/tram, /obj/structure/disposalpipe/segment, -/turf/open/floor/noslip/tram_platform, +/turf/open/floor/tram, /area/station/hallway/primary/tram/center) "afR" = ( /obj/machinery/computer/order_console/mining, /obj/effect/turf_decal/tile/brown/fourcorners, /turf/open/floor/iron, /area/station/cargo/miningdock) -"afS" = ( -/obj/structure/lattice, -/obj/structure/fluff/tram_rail, -/turf/open/openspace, -/area/station/asteroid) "afT" = ( /obj/effect/turf_decal/trimline/neutral/filled/line{ dir = 8 @@ -1837,31 +1844,13 @@ }, /turf/open/floor/iron, /area/station/hallway/secondary/service) -"afV" = ( -/obj/structure/fluff/tram_rail, -/obj/structure/lattice, -/turf/open/openspace, -/area/station/asteroid) "afX" = ( -/obj/structure/fluff/tram_rail{ - dir = 1 - }, -/turf/open/openspace, -/area/station/asteroid) -"afY" = ( -/obj/structure/lattice, -/obj/structure/fluff/tram_rail{ - dir = 1 - }, -/turf/open/openspace, -/area/station/asteroid) -"aga" = ( -/obj/structure/fluff/tram_rail{ +/obj/structure/fluff/tram_rail/electric/anchor{ dir = 1 }, /obj/structure/lattice, /turf/open/openspace, -/area/station/asteroid) +/area/station/hallway/primary/tram/left) "agb" = ( /obj/structure/lattice, /obj/structure/railing/corner, @@ -2622,7 +2611,7 @@ /turf/open/floor/iron, /area/station/engineering/atmos) "akC" = ( -/obj/structure/industrial_lift/public, +/obj/structure/transport/linear/public, /obj/effect/turf_decal/caution/stand_clear/red, /turf/open/floor/plating/elevatorshaft, /area/station/science/xenobiology) @@ -4476,11 +4465,12 @@ /turf/open/floor/iron, /area/station/hallway/primary/tram/center) "aEq" = ( -/obj/structure/industrial_lift/tram, -/obj/structure/fluff/tram_rail{ +/obj/structure/fluff/tram_rail/electric{ dir = 1 }, -/obj/structure/chair/sofa/bench/tram/left{ +/obj/structure/transport/linear/tram, +/obj/structure/thermoplastic, +/obj/structure/chair/sofa/bench/tram/right{ dir = 4 }, /turf/open/openspace, @@ -4607,19 +4597,13 @@ /turf/open/floor/engine, /area/station/science/explab) "aFm" = ( -/obj/machinery/crossing_signal/northeast{ - inbound = 1; - outbound = 2 - }, /obj/effect/turf_decal/stripes/white/line, +/obj/machinery/transport/crossing_signal/northeast, /turf/open/floor/iron, /area/station/hallway/primary/tram/left) "aFp" = ( -/obj/machinery/crossing_signal/northeast{ - inbound = 2; - outbound = 3 - }, /obj/effect/turf_decal/stripes/white/line, +/obj/machinery/transport/crossing_signal/northeast, /turf/open/floor/iron, /area/station/hallway/primary/tram/center) "aFs" = ( @@ -4809,11 +4793,9 @@ /turf/open/floor/catwalk_floor, /area/station/hallway/primary/tram/center) "aGO" = ( -/obj/structure/industrial_lift/tram/white, -/obj/machinery/door/window/tram/left/directional/south{ - pixel_x = -32; - pixel_y = -7 - }, +/obj/structure/transport/linear/tram, +/obj/structure/thermoplastic/light, +/obj/machinery/door/airlock/tram, /turf/open/openspace, /area/station/hallway/primary/tram/center) "aGY" = ( @@ -5073,10 +5055,6 @@ }, /turf/open/floor/iron, /area/station/security/checkpoint/medical) -"aII" = ( -/obj/machinery/destination_sign/indicator, -/turf/closed/wall, -/area/station/hallway/primary/tram/left) "aIJ" = ( /obj/machinery/flasher/directional/east{ id = "medcell" @@ -5457,12 +5435,6 @@ }, /turf/open/floor/iron, /area/station/hallway/secondary/service) -"aMD" = ( -/obj/machinery/destination_sign/indicator{ - dir = 1 - }, -/turf/closed/wall, -/area/station/hallway/primary/tram/left) "aME" = ( /obj/structure/lattice/catwalk, /obj/structure/railing/corner{ @@ -6256,7 +6228,7 @@ /obj/effect/turf_decal/caution/stand_clear/red{ dir = 4 }, -/obj/structure/industrial_lift/public, +/obj/structure/transport/linear/public, /turf/open/floor/plating/elevatorshaft, /area/station/cargo/miningdock) "aXD" = ( @@ -6310,6 +6282,10 @@ /obj/structure/sign/clock/directional/north, /turf/open/floor/iron, /area/station/service/janitor) +"aYl" = ( +/obj/effect/turf_decal/tile/neutral/tram, +/turf/open/indestructible/tram/plate, +/area/station/hallway/primary/tram/center) "aYn" = ( /obj/structure/disposalpipe/segment{ dir = 4 @@ -6430,7 +6406,7 @@ /obj/effect/turf_decal/trimline/dark_red/warning{ dir = 4 }, -/obj/structure/industrial_lift/public, +/obj/structure/transport/linear/public, /obj/structure/railing{ dir = 4 }, @@ -6631,7 +6607,7 @@ /obj/effect/turf_decal/siding/thinplating{ dir = 4 }, -/obj/structure/industrial_lift/public, +/obj/structure/transport/linear/public, /obj/effect/turf_decal/caution/stand_clear/red{ dir = 4 }, @@ -6986,12 +6962,12 @@ /obj/effect/turf_decal/trimline/dark_red/warning{ dir = 10 }, -/obj/structure/industrial_lift/public, +/obj/structure/transport/linear/public, /obj/structure/railing{ dir = 10 }, -/obj/effect/landmark/lift_id{ - specific_lift_id = "tram_sci_lift" +/obj/effect/landmark/transport/transport_id{ + specific_transport_id = "tram_sci_lift" }, /obj/effect/abstract/elevator_music_zone{ linked_elevator_id = "tram_sci_lift" @@ -7277,6 +7253,10 @@ /obj/machinery/vending/cigarette, /turf/open/floor/iron, /area/station/commons/storage/tools) +"bup" = ( +/obj/effect/landmark/transport/transport_id/tramstation/line_1, +/turf/closed/wall, +/area/station/hallway/primary/tram/center) "buv" = ( /obj/machinery/atmospherics/components/unary/vent_pump/on/layer4, /turf/open/floor/iron/freezer, @@ -7739,7 +7719,7 @@ }, /area/station/command/teleporter) "bEt" = ( -/obj/structure/fluff/tram_rail/anchor, +/obj/structure/fluff/tram_rail/electric/anchor, /turf/open/openspace, /area/station/hallway/primary/tram/left) "bEz" = ( @@ -8010,13 +7990,10 @@ /turf/open/floor/iron/white, /area/station/science/research) "bJu" = ( -/obj/machinery/crossing_signal/southeast{ - inbound = 1; - outbound = 2 - }, /obj/effect/turf_decal/stripes/white/line{ dir = 1 }, +/obj/machinery/transport/crossing_signal/southeast, /turf/open/floor/iron, /area/station/hallway/primary/tram/left) "bJP" = ( @@ -8549,6 +8526,17 @@ /obj/effect/landmark/event_spawn, /turf/open/floor/iron, /area/station/engineering/atmos) +"bQV" = ( +/obj/effect/turf_decal/tile/neutral/tram, +/obj/effect/turf_decal/stripes/white/line{ + dir = 1 + }, +/obj/effect/turf_decal/stripes/white/line, +/turf/open/floor/tram/plate/energized{ + inbound = 1; + outbound = 2 + }, +/area/station/hallway/primary/tram/center) "bRE" = ( /obj/structure/lattice/catwalk, /turf/open/floor/plating/airless, @@ -8615,12 +8603,6 @@ }, /turf/open/floor/iron, /area/station/commons/dorms) -"bTT" = ( -/obj/structure/fluff/tram_rail/anchor{ - dir = 1 - }, -/turf/open/openspace, -/area/station/hallway/primary/tram/right) "bUh" = ( /obj/machinery/door/firedoor, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -8771,6 +8753,15 @@ /obj/machinery/keycard_auth/directional/east, /turf/open/floor/carpet, /area/station/command/heads_quarters/hos) +"bWe" = ( +/obj/effect/turf_decal/tile/neutral/tram, +/obj/structure/transport/linear/tram, +/obj/structure/thermoplastic, +/obj/structure/chair/sofa/bench/tram/left{ + dir = 8 + }, +/turf/open/indestructible/tram/plate, +/area/station/hallway/primary/tram/center) "bWi" = ( /obj/structure/lattice/catwalk, /obj/structure/cable, @@ -9842,7 +9833,7 @@ /obj/effect/turf_decal/trimline/dark_red/warning{ dir = 6 }, -/obj/structure/industrial_lift/public, +/obj/structure/transport/linear/public, /obj/structure/railing{ dir = 6 }, @@ -10139,7 +10130,7 @@ /obj/effect/turf_decal/trimline/dark_red/warning{ dir = 1 }, -/obj/structure/industrial_lift/public, +/obj/structure/transport/linear/public, /turf/open/floor/plating/elevatorshaft, /area/station/maintenance/tram/mid) "cuM" = ( @@ -11159,6 +11150,12 @@ }, /turf/open/floor/iron/dark, /area/station/command/bridge) +"cMd" = ( +/obj/structure/fluff/tram_rail/electric/anchor{ + dir = 1 + }, +/turf/open/openspace, +/area/station/hallway/primary/tram/right) "cMB" = ( /obj/effect/turf_decal/trimline/neutral/filled/line, /obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ @@ -11229,9 +11226,9 @@ /turf/open/floor/iron, /area/station/commons/dorms) "cNT" = ( -/obj/structure/industrial_lift/tram/subfloor/window, -/obj/structure/window/reinforced/tram/front{ - icon_state = "tram_window-5" +/obj/structure/transport/linear/tram/corner/southeast, +/obj/structure/tram/spoiler{ + dir = 4 }, /turf/open/openspace, /area/station/hallway/primary/tram/center) @@ -11561,8 +11558,8 @@ dir = 4 }, /obj/machinery/door/window/elevator/left/directional/west{ - elevator_linked_id = "tram_cargo_lift"; - elevator_mode = 1 + elevator_mode = 1; + transport_linked_id = "tram_cargo_lift" }, /turf/open/floor/iron, /area/station/cargo/storage) @@ -11663,8 +11660,8 @@ dir = 1 }, /obj/machinery/door/window/elevator/left/directional/south{ - elevator_linked_id = "tram_perma_lift"; - elevator_mode = 1 + elevator_mode = 1; + transport_linked_id = "tram_perma_lift" }, /turf/open/floor/iron, /area/station/security/brig) @@ -11928,7 +11925,7 @@ }, /obj/effect/turf_decal/stripes/white/line, /obj/effect/turf_decal/tile/neutral/tram, -/turf/open/floor/noslip/tram_plate/energized{ +/turf/open/floor/tram/plate/energized{ inbound = 1; outbound = 2 }, @@ -13025,11 +13022,9 @@ /turf/open/floor/iron/white/side, /area/station/science/lobby) "dtY" = ( -/obj/structure/industrial_lift/tram, -/obj/structure/window/reinforced/tram/directional/south, -/obj/structure/chair/sofa/bench/tram/right{ - dir = 4 - }, +/obj/structure/transport/linear/tram, +/obj/structure/tram/split, +/obj/machinery/transport/destination_sign/split/south, /turf/open/openspace, /area/station/hallway/primary/tram/center) "dur" = ( @@ -13343,6 +13338,10 @@ /obj/structure/lattice/catwalk, /turf/open/space/openspace, /area/space/nearstation) +"dAt" = ( +/obj/effect/turf_decal/tile/neutral/tram, +/turf/open/indestructible/tram/plate, +/area/station/hallway/primary/tram/right) "dAx" = ( /obj/effect/turf_decal/trimline/brown/filled/line{ dir = 8 @@ -13401,10 +13400,6 @@ }, /turf/open/floor/iron, /area/station/hallway/primary/tram/center) -"dCf" = ( -/obj/machinery/destination_sign/indicator, -/turf/closed/wall, -/area/station/hallway/primary/tram/right) "dCk" = ( /obj/structure/table/wood, /obj/machinery/recharger{ @@ -13622,7 +13617,7 @@ /obj/effect/turf_decal/trimline/dark_red/warning{ dir = 1 }, -/obj/structure/industrial_lift/public, +/obj/structure/transport/linear/public, /obj/structure/railing{ dir = 1 }, @@ -13714,7 +13709,7 @@ /obj/effect/turf_decal/caution/stand_clear/red{ dir = 1 }, -/obj/structure/industrial_lift/public, +/obj/structure/transport/linear/public, /obj/structure/railing{ dir = 4 }, @@ -13805,10 +13800,10 @@ dir = 1 }, /obj/machinery/door/window/elevator/left/directional/north{ - elevator_linked_id = "dumbwaiter_lift"; elevator_mode = 1; name = "Dumbwaiter"; - req_access = null + req_access = null; + transport_linked_id = "dumbwaiter_lift" }, /turf/open/floor/iron/cafeteria, /area/station/service/kitchen) @@ -15530,7 +15525,10 @@ }, /obj/effect/turf_decal/trimline/tram/filled/line, /obj/effect/turf_decal/trimline/tram/filled/warning, -/obj/machinery/button/tram/directional/south, +/obj/machinery/button/transport/tram/directional/south{ + id = 1 + }, +/obj/machinery/transport/destination_sign/indicator/directional/south, /turf/open/floor/iron, /area/station/hallway/primary/tram/left) "esc" = ( @@ -15814,7 +15812,7 @@ /obj/effect/turf_decal/caution/stand_clear/white{ dir = 4 }, -/turf/open/floor/noslip/tram_platform, +/turf/open/indestructible/tram, /area/station/hallway/primary/tram/right) "exF" = ( /obj/effect/turf_decal/trimline/brown/filled/line{ @@ -16815,7 +16813,7 @@ /turf/closed/wall, /area/station/service/kitchen) "eSy" = ( -/obj/effect/landmark/tram/nav/immovable_rod, +/obj/effect/landmark/transport/nav_beacon/tram/nav/immovable_rod, /turf/open/floor/carpet, /area/station/hallway/secondary/entry) "eSz" = ( @@ -17451,11 +17449,10 @@ /turf/open/floor/iron/dark, /area/station/security/courtroom/holding) "ffU" = ( -/obj/structure/industrial_lift/tram, -/obj/structure/fluff/tram_rail, -/obj/structure/chair/sofa/bench/tram/left{ - dir = 8 - }, +/obj/structure/fluff/tram_rail/electric, +/obj/structure/transport/linear/tram, +/obj/structure/thermoplastic, +/obj/structure/chair/sofa/bench/tram/right, /turf/open/openspace, /area/station/hallway/primary/tram/center) "fgi" = ( @@ -17749,10 +17746,6 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/wood/parquet, /area/station/medical/psychology) -"fld" = ( -/obj/machinery/destination_sign/indicator, -/turf/closed/wall, -/area/station/hallway/primary/tram/center) "flf" = ( /obj/machinery/door/airlock/security{ name = "Interrogation" @@ -17942,7 +17935,7 @@ /obj/structure/railing{ dir = 4 }, -/obj/structure/industrial_lift/public, +/obj/structure/transport/linear/public, /turf/open/floor/plating/elevatorshaft, /area/station/maintenance/tram/mid) "foy" = ( @@ -18072,14 +18065,6 @@ }, /turf/open/floor/iron/dark, /area/station/security/execution/transfer) -"fqv" = ( -/obj/structure/industrial_lift/tram/white, -/obj/machinery/door/window/tram/left/directional/north{ - pixel_x = -32; - pixel_y = -25 - }, -/turf/open/openspace, -/area/station/hallway/primary/tram/center) "fqM" = ( /obj/structure/disposaloutlet{ dir = 8 @@ -18514,6 +18499,10 @@ }, /turf/open/floor/engine/hull, /area/station/solars/port) +"fxX" = ( +/obj/structure/fluff/tram_rail/electric, +/turf/open/openspace, +/area/station/hallway/primary/tram/right) "fyc" = ( /obj/effect/turf_decal/trimline/purple/filled/corner, /turf/open/floor/iron, @@ -18584,7 +18573,7 @@ /obj/effect/turf_decal/trimline/dark_red/warning{ dir = 5 }, -/obj/structure/industrial_lift/public, +/obj/structure/transport/linear/public, /obj/structure/railing{ dir = 5 }, @@ -19231,7 +19220,7 @@ dir = 2 }, /obj/effect/turf_decal/tile/neutral/tram, -/turf/open/floor/noslip/tram_plate, +/turf/open/floor/tram/plate, /area/station/hallway/primary/tram/right) "fMQ" = ( /obj/machinery/air_sensor/ordnance_burn_chamber, @@ -19273,11 +19262,9 @@ /turf/open/floor/iron, /area/station/cargo/sorting) "fNs" = ( -/obj/structure/industrial_lift/tram/subfloor/window, -/obj/structure/fluff/tram_rail, -/obj/structure/window/reinforced/tram/front{ - icon_state = "tram_window-3" - }, +/obj/structure/fluff/tram_rail/electric, +/obj/structure/transport/linear/tram, +/obj/structure/tram, /turf/open/openspace, /area/station/hallway/primary/tram/center) "fNx" = ( @@ -20076,7 +20063,7 @@ /obj/structure/holosign/barrier/atmos/tram, /obj/structure/disposalpipe/segment, /obj/effect/turf_decal/tile/neutral/tram, -/turf/open/floor/noslip/tram_plate, +/turf/open/floor/tram/plate, /area/station/hallway/primary/tram/center) "geX" = ( /obj/effect/turf_decal/trimline/neutral/filled/corner{ @@ -20116,7 +20103,7 @@ "gfP" = ( /obj/structure/holosign/barrier/atmos/tram, /obj/effect/turf_decal/tile/neutral/tram, -/turf/open/floor/noslip/tram_plate, +/turf/open/floor/tram/plate, /area/station/hallway/primary/tram/left) "gfV" = ( /obj/structure/table/wood/fancy/green, @@ -20265,17 +20252,17 @@ /turf/open/floor/iron, /area/station/hallway/primary/tram/right) "giW" = ( +/obj/structure/transport/linear/public, +/obj/machinery/elevator_control_panel/directional/west{ + linked_elevator_id = "tram_sci_lift"; + preset_destination_names = list("2"="Lower Deck","3"="Upper Deck") + }, /obj/effect/turf_decal/trimline/dark_red/warning{ dir = 9 }, -/obj/structure/industrial_lift/public, /obj/structure/railing{ dir = 9 }, -/obj/machinery/elevator_control_panel/directional/west{ - linked_elevator_id = "tram_sci_lift"; - preset_destination_names = list("2"="Lower Deck","3"="Upper Deck") - }, /turf/open/floor/plating/elevatorshaft, /area/station/science/lower) "giZ" = ( @@ -20360,9 +20347,9 @@ /turf/open/floor/wood/large, /area/station/service/library) "gjM" = ( -/obj/structure/industrial_lift/tram/subfloor/window, -/obj/structure/window/reinforced/tram/front{ - icon_state = "tram_window-6" +/obj/structure/transport/linear/tram/corner/northeast, +/obj/structure/tram/spoiler{ + dir = 1 }, /turf/open/openspace, /area/station/hallway/primary/tram/center) @@ -20523,9 +20510,9 @@ /turf/open/floor/iron, /area/station/commons/dorms) "glZ" = ( -/obj/structure/industrial_lift/public, -/obj/effect/landmark/lift_id{ - specific_lift_id = "tram_lower_center_lift" +/obj/structure/transport/linear/public, +/obj/effect/landmark/transport/transport_id{ + specific_transport_id = "tram_lower_center_lift" }, /obj/effect/abstract/elevator_music_zone{ linked_elevator_id = "tram_lower_center_lift" @@ -21200,8 +21187,8 @@ }, /obj/effect/turf_decal/stripes/white/line, /obj/machinery/door/window/elevator/right/directional/south{ - elevator_linked_id = "tram_lower_center_lift"; - elevator_mode = 1 + elevator_mode = 1; + transport_linked_id = "tram_lower_center_lift" }, /turf/open/floor/iron, /area/station/hallway/primary/tram/center) @@ -21708,10 +21695,11 @@ /turf/open/floor/iron/dark, /area/station/science/ordnance/storage) "gIm" = ( -/obj/structure/industrial_lift/tram/white, -/obj/effect/landmark/lift_id, /obj/effect/turf_decal/tile/neutral/tram, -/turf/open/floor/noslip/tram_plate, +/obj/effect/landmark/transport/transport_id/tramstation/line_1, +/obj/structure/transport/linear/tram, +/obj/structure/thermoplastic/light, +/turf/open/indestructible/tram/plate, /area/station/hallway/primary/tram/center) "gIu" = ( /obj/structure/table, @@ -22289,7 +22277,7 @@ /obj/effect/turf_decal/trimline/dark_red/warning{ dir = 10 }, -/obj/structure/industrial_lift/public, +/obj/structure/transport/linear/public, /obj/structure/railing{ dir = 10 }, @@ -22349,10 +22337,11 @@ /turf/open/floor/plating, /area/station/engineering/engine_smes) "gUF" = ( -/obj/structure/industrial_lift/tram/white, -/obj/structure/fluff/tram_rail{ +/obj/structure/fluff/tram_rail/electric{ dir = 1 }, +/obj/structure/transport/linear/tram, +/obj/structure/thermoplastic/light, /turf/open/openspace, /area/station/hallway/primary/tram/center) "gUH" = ( @@ -22398,6 +22387,10 @@ /obj/effect/spawner/structure/window/reinforced, /turf/open/floor/plating, /area/station/medical/break_room) +"gVV" = ( +/obj/structure/fluff/tram_rail/electric, +/turf/open/openspace, +/area/station/hallway/primary/tram/left) "gVW" = ( /obj/effect/turf_decal/stripes/white/corner{ dir = 1 @@ -22995,12 +22988,11 @@ /turf/closed/wall/rock, /area/station/engineering/atmos) "hio" = ( -/obj/structure/industrial_lift/tram, -/obj/structure/fluff/tram_rail, -/obj/effect/landmark/start/hangover, -/obj/structure/chair/sofa/bench/tram/left{ - dir = 8 - }, +/obj/structure/fluff/tram_rail/electric, +/obj/structure/transport/linear/tram, +/obj/structure/thermoplastic, +/obj/structure/chair/sofa/bench/tram/left, +/obj/machinery/computer/tram_controls/split/directional/north, /turf/open/openspace, /area/station/hallway/primary/tram/center) "hiq" = ( @@ -23902,13 +23894,11 @@ /turf/open/floor/iron/checker, /area/station/commons/lounge) "hCt" = ( -/obj/structure/industrial_lift/tram/subfloor/window, -/obj/structure/fluff/tram_rail{ +/obj/structure/fluff/tram_rail/electric{ dir = 1 }, -/obj/structure/window/reinforced/tram/front{ - icon_state = "tram_window-3" - }, +/obj/structure/transport/linear/tram, +/obj/structure/tram, /turf/open/openspace, /area/station/hallway/primary/tram/center) "hCv" = ( @@ -24113,8 +24103,8 @@ dir = 1 }, /obj/machinery/door/window/elevator/left/directional/north{ - elevator_linked_id = "tram_xeno_lift"; - elevator_mode = 1 + elevator_mode = 1; + transport_linked_id = "tram_xeno_lift" }, /turf/open/floor/iron/white, /area/station/science/xenobiology) @@ -24941,7 +24931,7 @@ /obj/structure/railing{ dir = 8 }, -/obj/structure/industrial_lift/public, +/obj/structure/transport/linear/public, /turf/open/floor/plating/elevatorshaft, /area/station/maintenance/tram/mid) "hWI" = ( @@ -25017,11 +25007,8 @@ /turf/open/floor/iron, /area/station/security/office) "hYv" = ( -/obj/machinery/crossing_signal/northwest{ - inbound = 2; - outbound = 3 - }, /obj/effect/turf_decal/stripes/white/line, +/obj/machinery/transport/crossing_signal/northwest, /turf/open/floor/iron, /area/station/hallway/primary/tram/right) "hYK" = ( @@ -25222,7 +25209,7 @@ /obj/effect/turf_decal/trimline/dark_red/warning{ dir = 6 }, -/obj/structure/industrial_lift/public, +/obj/structure/transport/linear/public, /turf/open/floor/plating/elevatorshaft, /area/station/maintenance/tram/mid) "ibs" = ( @@ -25872,8 +25859,8 @@ dir = 8 }, /obj/machinery/door/window/elevator/left/directional/east{ - elevator_linked_id = "tram_dorm_lift"; - elevator_mode = 1 + elevator_mode = 1; + transport_linked_id = "tram_dorm_lift" }, /turf/open/floor/iron, /area/station/hallway/primary/tram/left) @@ -25987,9 +25974,9 @@ /turf/open/floor/iron/dark, /area/station/cargo/miningdock/oresilo) "irw" = ( -/obj/structure/industrial_lift/tram/subfloor/window, -/obj/structure/window/reinforced/tram/front{ - icon_state = "tram_window-2" +/obj/structure/transport/linear/tram/corner/northwest, +/obj/structure/tram/spoiler{ + dir = 8 }, /turf/open/openspace, /area/station/hallway/primary/tram/center) @@ -26809,7 +26796,7 @@ /obj/structure/cable, /obj/structure/disposalpipe/segment, /obj/effect/turf_decal/tile/neutral/tram, -/turf/open/floor/noslip/tram_plate, +/turf/open/floor/tram/plate, /area/station/hallway/primary/tram/center) "iIH" = ( /obj/machinery/power/terminal{ @@ -26857,7 +26844,7 @@ /obj/effect/turf_decal/caution/stand_clear/red{ dir = 8 }, -/obj/structure/industrial_lift/public, +/obj/structure/transport/linear/public, /turf/open/floor/plating/elevatorshaft, /area/station/maintenance/tram/left) "iJn" = ( @@ -27068,10 +27055,6 @@ }, /turf/open/floor/iron/white, /area/station/medical/treatment_center) -"iOd" = ( -/obj/structure/fluff/tram_rail, -/turf/open/openspace, -/area/station/hallway/primary/tram/right) "iOh" = ( /obj/machinery/door/firedoor/border_only{ dir = 8 @@ -27617,8 +27600,8 @@ dir = 1 }, /obj/machinery/door/window/elevator/right/directional/south{ - elevator_linked_id = "tram_perma_lift"; - elevator_mode = 1 + elevator_mode = 1; + transport_linked_id = "tram_perma_lift" }, /turf/open/floor/iron, /area/station/security/execution/transfer) @@ -27920,7 +27903,7 @@ "jcr" = ( /obj/effect/turf_decal/delivery/white, /obj/structure/holosign/barrier/atmos/tram, -/turf/open/floor/noslip/tram_platform, +/turf/open/floor/tram, /area/station/hallway/primary/tram/left) "jcI" = ( /obj/machinery/firealarm/directional/west, @@ -28016,7 +27999,7 @@ /obj/effect/turf_decal/trimline/dark_red/warning{ dir = 9 }, -/obj/structure/industrial_lift/public, +/obj/structure/transport/linear/public, /obj/structure/railing{ dir = 9 }, @@ -28450,7 +28433,7 @@ /obj/effect/turf_decal/trimline/dark_red/warning{ dir = 5 }, -/obj/structure/industrial_lift/public, +/obj/structure/transport/linear/public, /turf/open/floor/plating/elevatorshaft, /area/station/maintenance/tram/mid) "jkM" = ( @@ -28773,7 +28756,7 @@ /obj/effect/turf_decal/trimline/dark_red/warning{ dir = 6 }, -/obj/structure/industrial_lift/public, +/obj/structure/transport/linear/public, /obj/structure/railing, /turf/open/floor/plating/elevatorshaft, /area/station/science/lower) @@ -29001,10 +28984,13 @@ /turf/open/floor/iron/dark, /area/station/ai_monitored/turret_protected/ai) "juu" = ( -/obj/structure/industrial_lift/tram, -/obj/structure/sign/plaques/tram, /obj/effect/turf_decal/tile/neutral/tram, -/turf/open/floor/noslip/tram_plate, +/obj/structure/transport/linear/tram, +/obj/structure/thermoplastic, +/obj/structure/chair/sofa/bench/tram/left{ + dir = 4 + }, +/turf/open/indestructible/tram/plate, /area/station/hallway/primary/tram/center) "juw" = ( /obj/effect/turf_decal/trimline/neutral/filled/line{ @@ -29135,24 +29121,24 @@ /turf/open/floor/iron/showroomfloor, /area/station/security/lockers) "jwP" = ( -/obj/effect/landmark/lift_id{ - specific_lift_id = "tram_cargo_lift" - }, -/obj/structure/railing{ - dir = 8 +/obj/effect/landmark/transport/transport_id{ + specific_transport_id = "tram_cargo_lift" }, /obj/effect/turf_decal/trimline/dark_red/warning{ dir = 8 }, -/obj/structure/industrial_lift/public, +/obj/structure/transport/linear/public, /obj/machinery/elevator_control_panel/directional/west{ linked_elevator_id = "tram_cargo_lift"; - preset_destination_names = list("2"="Lower Deck","3"="Upper Deck"); + preset_destination_names = list("2"="Lower Deck","3"="Upper Deck"); req_access = list("mining") }, /obj/effect/abstract/elevator_music_zone{ linked_elevator_id = "tram_cargo_lift" }, +/obj/structure/railing{ + dir = 8 + }, /turf/open/floor/plating/elevatorshaft, /area/station/cargo/miningdock) "jwT" = ( @@ -29559,6 +29545,12 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/iron/checker, /area/station/commons/lounge) +"jDp" = ( +/obj/structure/lattice, +/obj/machinery/light/cold/dim/directional/east, +/obj/machinery/transport/guideway_sensor, +/turf/open/openspace, +/area/station/asteroid) "jDx" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/visible, /obj/effect/turf_decal/stripes/line, @@ -29644,12 +29636,6 @@ /obj/effect/landmark/start/hangover, /turf/open/floor/iron/dark, /area/station/commons/lounge) -"jEO" = ( -/obj/machinery/destination_sign/indicator{ - dir = 1 - }, -/turf/closed/wall, -/area/station/hallway/primary/tram/center) "jFh" = ( /obj/effect/turf_decal/trimline/red/filled/line{ dir = 4 @@ -29810,9 +29796,10 @@ /obj/effect/turf_decal/trimline/tram/filled/warning{ dir = 1 }, -/obj/machinery/button/tram/directional/north{ +/obj/machinery/button/transport/tram/directional/north{ id = 2 }, +/obj/machinery/transport/destination_sign/indicator/directional/north, /turf/open/floor/iron, /area/station/hallway/primary/tram/center) "jHX" = ( @@ -29852,6 +29839,12 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/catwalk_floor, /area/station/maintenance/central/greater) +"jJb" = ( +/obj/structure/fluff/tram_rail, +/obj/structure/transport/linear/tram, +/obj/structure/thermoplastic/light, +/turf/open/openspace, +/area/station/hallway/primary/tram/center) "jJd" = ( /obj/effect/turf_decal/trimline/brown/filled/line{ dir = 1 @@ -29960,8 +29953,8 @@ dir = 4 }, /obj/machinery/door/window/elevator/left/directional/west{ - elevator_linked_id = "tram_sci_lift"; - elevator_mode = 1 + elevator_mode = 1; + transport_linked_id = "tram_sci_lift" }, /obj/effect/turf_decal/tile/purple/fourcorners, /turf/open/floor/iron/white, @@ -30359,9 +30352,9 @@ /turf/open/floor/plating, /area/station/maintenance/department/cargo) "jSV" = ( -/obj/structure/industrial_lift/public, -/obj/effect/landmark/lift_id{ - specific_lift_id = "tram_upper_center_lift" +/obj/structure/transport/linear/public, +/obj/effect/landmark/transport/transport_id{ + specific_transport_id = "tram_upper_center_lift" }, /obj/effect/abstract/elevator_music_zone{ linked_elevator_id = "tram_upper_center_lift" @@ -30369,8 +30362,8 @@ /turf/open/floor/plating/elevatorshaft, /area/station/maintenance/tram/mid) "jSX" = ( -/obj/structure/industrial_lift/tram, -/obj/structure/window/reinforced/tram/directional/south, +/obj/structure/transport/linear/tram, +/obj/structure/tram/split, /turf/open/openspace, /area/station/hallway/primary/tram/center) "jTf" = ( @@ -30413,26 +30406,16 @@ }, /turf/open/floor/iron/white, /area/station/science/research) -"jUi" = ( -/obj/structure/industrial_lift/tram, -/obj/machinery/destination_sign/north{ - pixel_y = 10 - }, -/obj/structure/window/reinforced/tram/directional/north, -/obj/structure/chair/sofa/bench/tram/right{ - dir = 8 - }, -/turf/open/openspace, -/area/station/hallway/primary/tram/center) "jUw" = ( -/obj/structure/industrial_lift/tram, -/obj/structure/fluff/tram_rail{ +/obj/structure/fluff/tram_rail/electric{ dir = 1 }, -/obj/effect/landmark/start/hangover, +/obj/structure/transport/linear/tram, +/obj/structure/thermoplastic, /obj/structure/chair/sofa/bench/tram/left{ - dir = 4 + dir = 1 }, +/obj/machinery/computer/tram_controls/split/directional/south, /turf/open/openspace, /area/station/hallway/primary/tram/center) "jUz" = ( @@ -30552,7 +30535,7 @@ loot = list(/obj/effect/decal/cleanable/oil/slippery=10,/obj/effect/decal/cleanable/oil=90); name = "funny slipper :)" }, -/turf/open/floor/noslip/tram_plate, +/turf/open/floor/tram/plate, /area/station/hallway/primary/tram/left) "jXc" = ( /obj/effect/turf_decal/trimline/yellow/filled/corner{ @@ -30902,6 +30885,13 @@ /obj/machinery/light/directional/east, /turf/open/floor/iron, /area/station/hallway/primary/tram/center) +"kby" = ( +/obj/structure/fluff/tram_rail/electric/anchor{ + dir = 1 + }, +/obj/structure/lattice, +/turf/open/openspace, +/area/station/hallway/primary/tram/right) "kbz" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -30961,7 +30951,7 @@ }, /obj/effect/turf_decal/stripes/white/line, /obj/effect/turf_decal/tile/neutral/tram, -/turf/open/floor/noslip/tram_plate/energized{ +/turf/open/floor/tram/plate/energized{ inbound = 2; outbound = 3 }, @@ -32121,7 +32111,7 @@ }, /obj/structure/holosign/barrier/atmos/tram, /obj/structure/disposalpipe/segment, -/turf/open/floor/noslip/tram_platform, +/turf/open/floor/tram, /area/station/hallway/primary/tram/center) "kwG" = ( /obj/effect/turf_decal/trimline/red/filled/line, @@ -32333,6 +32323,12 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/iron/dark, /area/station/engineering/gravity_generator) +"kCf" = ( +/obj/structure/fluff/tram_rail/electric/anchor{ + dir = 1 + }, +/turf/open/openspace, +/area/station/hallway/primary/tram/center) "kCm" = ( /obj/effect/turf_decal/trimline/red/filled/line, /obj/structure/table, @@ -32492,6 +32488,12 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/iron, /area/station/security/brig) +"kFn" = ( +/obj/structure/lattice, +/obj/machinery/light/cold/dim/directional/west, +/obj/machinery/transport/guideway_sensor, +/turf/open/openspace, +/area/station/asteroid) "kFp" = ( /obj/effect/decal/cleanable/dirt, /turf/open/floor/plating, @@ -33878,7 +33880,7 @@ /obj/structure/disposalpipe/segment, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/effect/landmark/tram/nav/immovable_rod, +/obj/effect/landmark/transport/nav_beacon/tram/nav/immovable_rod, /turf/open/floor/iron, /area/station/hallway/secondary/exit/departure_lounge) "lax" = ( @@ -35008,17 +35010,17 @@ /turf/open/floor/iron/dark, /area/station/security/office) "lvz" = ( +/obj/structure/transport/linear/public, +/obj/machinery/elevator_control_panel/directional/west{ + linked_elevator_id = "tram_perma_lift"; + preset_destination_names = list("2"="Lower Deck","3"="Upper Deck") + }, /obj/effect/turf_decal/caution/stand_clear/red{ dir = 1 }, -/obj/structure/industrial_lift/public, /obj/structure/railing{ dir = 8 }, -/obj/machinery/elevator_control_panel/directional/west{ - linked_elevator_id = "tram_perma_lift"; - preset_destination_names = list("2"="Lower Deck","3"="Upper Deck") - }, /turf/open/floor/plating/elevatorshaft, /area/station/security/execution/transfer) "lvH" = ( @@ -35273,7 +35275,7 @@ /area/station/service/hydroponics) "lzu" = ( /obj/effect/turf_decal/tile/neutral/tram, -/turf/open/floor/noslip/tram_plate, +/turf/open/floor/tram/plate, /area/station/hallway/primary/tram/left) "lzJ" = ( /obj/structure/sign/warning/pods/directional/west, @@ -35974,7 +35976,7 @@ /area/station/solars/port) "lMF" = ( /obj/effect/turf_decal/tile/neutral/tram, -/turf/open/floor/noslip/tram_plate, +/turf/open/floor/tram/plate, /area/station/hallway/primary/tram/right) "lMJ" = ( /obj/effect/turf_decal/sand/plating, @@ -36524,8 +36526,8 @@ /area/station/science/ordnance/burnchamber) "lUP" = ( /obj/effect/turf_decal/tile/neutral/tram, -/obj/effect/landmark/tram/platform/tramstation/west, -/turf/open/floor/noslip/tram_plate, +/obj/effect/landmark/transport/nav_beacon/tram/platform/tramstation/west, +/turf/open/indestructible/tram/plate, /area/station/hallway/primary/tram/left) "lUZ" = ( /obj/machinery/navbeacon{ @@ -36605,6 +36607,12 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/iron/dark, /area/station/security/interrogation) +"lWi" = ( +/obj/structure/fluff/tram_rail/electric{ + dir = 1 + }, +/turf/open/openspace, +/area/station/hallway/primary/tram/center) "lWj" = ( /obj/effect/turf_decal/trimline/neutral/filled/line{ dir = 4 @@ -37857,7 +37865,7 @@ dir = 1 }, /obj/structure/holosign/barrier/atmos/tram, -/turf/open/floor/noslip/tram_platform, +/turf/open/floor/tram, /area/station/hallway/primary/tram/left) "mtU" = ( /obj/effect/turf_decal/trimline/neutral/filled/line{ @@ -37946,7 +37954,7 @@ /obj/structure/holosign/barrier/atmos/tram, /obj/structure/cable, /obj/structure/disposalpipe/segment, -/turf/open/floor/noslip/tram_platform, +/turf/open/floor/tram, /area/station/hallway/primary/tram/center) "mwd" = ( /obj/effect/turf_decal/siding/thinplating{ @@ -38214,7 +38222,7 @@ /turf/closed/wall/r_wall, /area/station/maintenance/department/crew_quarters/dorms) "mBB" = ( -/obj/structure/industrial_lift/public, +/obj/structure/transport/linear/public, /obj/effect/turf_decal/trimline/dark_red/warning{ dir = 9 }, @@ -38433,6 +38441,13 @@ }, /turf/open/floor/iron/dark, /area/station/security/courtroom/holding) +"mFL" = ( +/obj/structure/fluff/tram_rail/electric/anchor{ + dir = 1 + }, +/obj/structure/lattice, +/turf/open/openspace, +/area/station/hallway/primary/tram/center) "mFV" = ( /obj/effect/turf_decal/trimline/blue/filled/corner{ dir = 1 @@ -38981,8 +38996,8 @@ /area/station/security/courtroom/holding) "mQE" = ( /obj/effect/turf_decal/tile/neutral/tram, -/obj/effect/landmark/tram/platform/tramstation/east, -/turf/open/floor/noslip/tram_plate, +/obj/effect/landmark/transport/nav_beacon/tram/platform/tramstation/east, +/turf/open/indestructible/tram/plate, /area/station/hallway/primary/tram/right) "mQS" = ( /obj/structure/chair/comfy/beige, @@ -39019,7 +39034,7 @@ /obj/structure/disposalpipe/segment{ dir = 2 }, -/turf/open/floor/noslip/tram_platform, +/turf/open/floor/tram, /area/station/hallway/primary/tram/right) "mRY" = ( /obj/machinery/computer/scan_consolenew{ @@ -39107,12 +39122,12 @@ }, /obj/machinery/elevator_control_panel/directional/north{ linked_elevator_id = "tram_upper_center_lift"; - preset_destination_names = list("2"="Lower Deck","3"="Upper Deck") + preset_destination_names = list("2"="Lower Deck","3"="Upper Deck") }, /obj/effect/turf_decal/trimline/dark_red/warning{ dir = 1 }, -/obj/structure/industrial_lift/public, +/obj/structure/transport/linear/public, /turf/open/floor/plating/elevatorshaft, /area/station/maintenance/tram/mid) "mUd" = ( @@ -39576,13 +39591,11 @@ /turf/open/floor/catwalk_floor, /area/station/command/gateway) "ndX" = ( -/obj/structure/fluff/tram_rail{ +/obj/structure/fluff/tram_rail/electric{ dir = 1 }, -/obj/structure/industrial_lift/tram, -/obj/structure/chair/sofa/bench/tram/right{ - dir = 8 - }, +/obj/structure/transport/linear/tram, +/obj/structure/thermoplastic, /turf/open/openspace, /area/station/hallway/primary/tram/center) "nel" = ( @@ -39711,6 +39724,11 @@ "ngp" = ( /turf/closed/wall, /area/station/tcommsat/computer) +"ngr" = ( +/obj/structure/fluff/tram_rail/electric/anchor, +/obj/structure/lattice, +/turf/open/openspace, +/area/station/hallway/primary/tram/right) "ngv" = ( /obj/structure/cable, /obj/structure/disposalpipe/segment, @@ -40017,6 +40035,10 @@ /obj/effect/turf_decal/tile/blue/fourcorners, /turf/open/floor/iron/dark, /area/station/command/heads_quarters/cmo) +"nkn" = ( +/obj/structure/lattice, +/turf/open/openspace, +/area/station/hallway/primary/tram/center) "nkt" = ( /obj/structure/window/reinforced/spawner/directional/west, /obj/structure/window/reinforced/spawner/directional/south, @@ -40404,9 +40426,10 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/effect/turf_decal/trimline/tram/filled/line, /obj/effect/turf_decal/trimline/tram/filled/warning, -/obj/machinery/button/tram/directional/south{ +/obj/machinery/button/transport/tram/directional/south{ id = 3 }, +/obj/machinery/transport/destination_sign/indicator/directional/south, /turf/open/floor/iron, /area/station/hallway/primary/tram/right) "nqB" = ( @@ -40743,17 +40766,9 @@ }, /turf/open/floor/iron/white, /area/station/science/ordnance) -"nwQ" = ( -/obj/machinery/destination_sign/indicator{ - dir = 1 - }, -/turf/closed/wall, -/area/station/hallway/primary/tram/right) "nxf" = ( -/obj/structure/industrial_lift/tram/subfloor/window, -/obj/structure/window/reinforced/tram/front{ - icon_state = "tram_window-1" - }, +/obj/structure/transport/linear/tram/corner/southwest, +/obj/structure/tram/spoiler, /turf/open/openspace, /area/station/hallway/primary/tram/center) "nxq" = ( @@ -40843,6 +40858,10 @@ /obj/effect/spawner/structure/window, /turf/open/floor/plating, /area/station/hallway/primary/tram/left) +"nyP" = ( +/obj/structure/fluff/tram_rail/electric/anchor, +/turf/open/openspace, +/area/station/hallway/primary/tram/right) "nyV" = ( /obj/effect/turf_decal/siding/thinplating{ dir = 1 @@ -42978,8 +42997,9 @@ /turf/open/floor/iron/white, /area/station/medical/medbay/lobby) "olw" = ( -/obj/structure/industrial_lift/tram/white, -/obj/structure/fluff/tram_rail, +/obj/structure/fluff/tram_rail/electric, +/obj/structure/transport/linear/tram, +/obj/structure/thermoplastic/light, /turf/open/openspace, /area/station/hallway/primary/tram/center) "olG" = ( @@ -43634,7 +43654,7 @@ /turf/open/floor/iron/freezer, /area/station/security/prison) "oAf" = ( -/obj/structure/industrial_lift/public, +/obj/structure/transport/linear/public, /obj/effect/turf_decal/trimline/dark_red/warning{ dir = 5 }, @@ -43708,6 +43728,10 @@ /obj/effect/turf_decal/tile/bar/opposingcorners, /turf/open/floor/iron, /area/station/cargo/miningdock/cafeteria) +"oCg" = ( +/obj/structure/fluff/tram_rail/electric/anchor, +/turf/open/openspace, +/area/station/hallway/primary/tram/center) "oCj" = ( /obj/effect/turf_decal/trimline/neutral/filled/line{ dir = 4 @@ -43761,7 +43785,7 @@ /obj/effect/turf_decal/trimline/dark_red/warning{ dir = 5 }, -/obj/structure/industrial_lift/public, +/obj/structure/transport/linear/public, /obj/structure/railing{ dir = 1 }, @@ -43939,13 +43963,6 @@ /obj/structure/bookcase/random/nonfiction, /turf/open/floor/wood/large, /area/station/service/library) -"oHq" = ( -/obj/effect/turf_decal/tile/neutral/tram, -/turf/open/floor/noslip/tram_plate/energized{ - inbound = 2; - outbound = 3 - }, -/area/station/hallway/primary/tram/right) "oHC" = ( /obj/structure/table, /obj/effect/turf_decal/trimline/yellow/filled/line{ @@ -44680,7 +44697,7 @@ /turf/open/floor/iron, /area/station/engineering/atmos/pumproom) "oYQ" = ( -/obj/structure/industrial_lift/public, +/obj/structure/transport/linear/public, /obj/effect/turf_decal/trimline/dark_red/warning{ dir = 10 }, @@ -44733,11 +44750,12 @@ /turf/open/floor/iron, /area/station/security/brig) "oZC" = ( -/obj/structure/industrial_lift/tram/white, /obj/effect/turf_decal/tile/neutral/tram, -/obj/effect/landmark/tram/nav/tramstation/main, -/obj/effect/landmark/tram/platform/tramstation/central, -/turf/open/floor/noslip/tram_plate, +/obj/structure/transport/linear/tram, +/obj/effect/landmark/transport/nav_beacon/tram/nav/tramstation/main, +/obj/effect/landmark/transport/nav_beacon/tram/platform/tramstation/central, +/obj/structure/thermoplastic/light, +/turf/open/indestructible/tram/plate, /area/station/hallway/primary/tram/center) "pal" = ( /obj/structure/disposalpipe/segment{ @@ -45224,8 +45242,8 @@ dir = 4 }, /obj/machinery/door/window/elevator/left/directional/west{ - elevator_linked_id = "tram_upper_center_lift"; - elevator_mode = 1 + elevator_mode = 1; + transport_linked_id = "tram_upper_center_lift" }, /turf/open/floor/iron, /area/station/maintenance/tram/mid) @@ -45472,7 +45490,7 @@ /obj/effect/turf_decal/trimline/dark_red/warning{ dir = 9 }, -/obj/structure/industrial_lift/public, +/obj/structure/transport/linear/public, /turf/open/floor/plating/elevatorshaft, /area/station/maintenance/tram/mid) "pmG" = ( @@ -45593,23 +45611,11 @@ }, /turf/open/floor/iron, /area/station/hallway/primary/tram/left) -"poE" = ( -/obj/structure/industrial_lift/tram/subfloor/window, -/obj/structure/window/reinforced/tram/front{ - icon_state = "tram_window-3" - }, -/obj/machinery/computer/tram_controls/directional/east, -/obj/effect/turf_decal/tile/neutral/tram, -/turf/open/floor/noslip/tram_plate, -/area/station/hallway/primary/tram/center) "poG" = ( -/obj/machinery/crossing_signal/southwest{ - inbound = 1; - outbound = 2 - }, /obj/effect/turf_decal/stripes/white/line{ dir = 1 }, +/obj/machinery/transport/crossing_signal/southwest, /turf/open/floor/iron, /area/station/hallway/primary/tram/center) "poM" = ( @@ -45788,7 +45794,7 @@ /obj/effect/turf_decal/trimline/dark_red/warning{ dir = 9 }, -/obj/structure/industrial_lift/public, +/obj/structure/transport/linear/public, /obj/structure/railing{ dir = 1 }, @@ -45900,13 +45906,10 @@ /turf/open/floor/carpet, /area/station/command/heads_quarters/hos) "ptB" = ( -/obj/machinery/crossing_signal/southwest{ - inbound = 2; - outbound = 3 - }, /obj/effect/turf_decal/stripes/white/line{ dir = 1 }, +/obj/machinery/transport/crossing_signal/southwest, /turf/open/floor/iron, /area/station/hallway/primary/tram/right) "ptD" = ( @@ -46008,10 +46011,6 @@ }, /turf/open/floor/iron/white, /area/station/science/lower) -"puY" = ( -/obj/structure/fluff/tram_rail/anchor, -/turf/open/openspace, -/area/station/hallway/primary/tram/right) "puZ" = ( /obj/effect/turf_decal/trimline/yellow/filled/line{ dir = 1 @@ -46659,7 +46658,7 @@ /obj/effect/turf_decal/trimline/dark_red/warning{ dir = 6 }, -/obj/structure/industrial_lift/public, +/obj/structure/transport/linear/public, /obj/structure/railing, /turf/open/floor/plating/elevatorshaft, /area/station/cargo/miningdock) @@ -47054,7 +47053,7 @@ /obj/effect/turf_decal/stripes/white/line{ dir = 4 }, -/turf/open/floor/noslip/tram_platform, +/turf/open/indestructible/tram, /area/station/hallway/primary/tram/left) "pLO" = ( /obj/effect/turf_decal/siding/thinplating{ @@ -47252,7 +47251,7 @@ /obj/effect/turf_decal/trimline/dark_red/warning{ dir = 10 }, -/obj/structure/industrial_lift/public, +/obj/structure/transport/linear/public, /obj/structure/railing, /turf/open/floor/plating/elevatorshaft, /area/station/maintenance/tram/left) @@ -47528,6 +47527,10 @@ /obj/structure/cable/layer1, /turf/open/floor/engine, /area/station/engineering/supermatter/room) +"pVi" = ( +/obj/structure/lattice, +/turf/open/openspace, +/area/station/hallway/primary/tram/right) "pVk" = ( /obj/machinery/duct, /obj/structure/cable, @@ -48668,6 +48671,10 @@ /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron/dark, /area/station/commons/vacant_room/commissary) +"qrv" = ( +/obj/structure/lattice, +/turf/open/openspace, +/area/station/hallway/primary/tram/left) "qrW" = ( /obj/effect/turf_decal/trimline/blue/filled/line{ dir = 1 @@ -50053,8 +50060,8 @@ dir = 8 }, /obj/machinery/door/window/elevator/left/directional/east{ - elevator_linked_id = "tram_dorm_lift"; - elevator_mode = 1 + elevator_mode = 1; + transport_linked_id = "tram_dorm_lift" }, /turf/open/floor/iron, /area/station/maintenance/tram/left) @@ -50568,15 +50575,9 @@ /turf/open/floor/iron, /area/station/security/brig) "ray" = ( -/obj/structure/industrial_lift/tram, -/obj/machinery/destination_sign/south{ - pixel_y = -11 - }, -/obj/structure/window/reinforced/tram/directional/south, -/obj/effect/landmark/start/hangover, -/obj/structure/chair/sofa/bench/tram/left{ - dir = 8 - }, +/obj/structure/transport/linear/tram, +/obj/structure/tram, +/obj/structure/plaque/static_plaque/tram, /turf/open/openspace, /area/station/hallway/primary/tram/center) "raD" = ( @@ -50584,8 +50585,8 @@ dir = 4 }, /obj/machinery/door/window/elevator/left/directional/west{ - elevator_linked_id = "tram_sci_lift"; - elevator_mode = 1 + elevator_mode = 1; + transport_linked_id = "tram_sci_lift" }, /obj/effect/turf_decal/tile/purple/fourcorners, /turf/open/floor/iron/white, @@ -50754,8 +50755,8 @@ dir = 4 }, /obj/machinery/door/window/elevator/left/directional/west{ - elevator_linked_id = "tram_upper_center_lift"; - elevator_mode = 1 + elevator_mode = 1; + transport_linked_id = "tram_upper_center_lift" }, /turf/open/floor/iron, /area/station/hallway/primary/tram/center) @@ -50882,7 +50883,7 @@ /obj/effect/turf_decal/trimline/dark_red/warning{ dir = 10 }, -/obj/structure/industrial_lift/public, +/obj/structure/transport/linear/public, /obj/structure/railing{ dir = 10 }, @@ -50980,7 +50981,7 @@ /turf/closed/wall, /area/station/medical/treatment_center) "rhn" = ( -/obj/structure/industrial_lift/public, +/obj/structure/transport/linear/public, /obj/effect/turf_decal/trimline/dark_red/warning{ dir = 6 }, @@ -51026,7 +51027,7 @@ /turf/open/floor/iron, /area/station/commons/dorms) "rib" = ( -/obj/structure/fluff/tram_rail/anchor{ +/obj/structure/fluff/tram_rail/electric/anchor{ dir = 1 }, /turf/open/openspace, @@ -51249,10 +51250,8 @@ /turf/open/floor/plating, /area/station/construction/mining/aux_base) "rlO" = ( -/obj/structure/industrial_lift/tram/white, -/obj/machinery/door/window/tram/right/directional/south{ - pixel_y = -7 - }, +/obj/structure/transport/linear/tram, +/obj/structure/thermoplastic/light, /turf/open/openspace, /area/station/hallway/primary/tram/center) "rlU" = ( @@ -51450,7 +51449,10 @@ /obj/effect/turf_decal/trimline/tram/filled/warning{ dir = 1 }, -/obj/machinery/button/tram/directional/north, +/obj/machinery/button/transport/tram/directional/north{ + id = 1 + }, +/obj/machinery/transport/destination_sign/indicator/directional/north, /turf/open/floor/iron, /area/station/hallway/primary/tram/left) "roz" = ( @@ -51563,11 +51565,8 @@ /turf/open/floor/iron, /area/station/cargo/office) "rqG" = ( -/obj/machinery/crossing_signal/northwest{ - inbound = 1; - outbound = 2 - }, /obj/effect/turf_decal/stripes/white/line, +/obj/machinery/transport/crossing_signal/northwest, /turf/open/floor/iron, /area/station/hallway/primary/tram/center) "rre" = ( @@ -51577,14 +51576,9 @@ /turf/open/floor/iron, /area/station/hallway/secondary/construction/engineering) "rrg" = ( -/obj/structure/industrial_lift/tram, -/obj/structure/window/reinforced/tram/directional/north, -/obj/machinery/destination_sign/north{ - pixel_y = 10 - }, -/obj/structure/chair/sofa/bench/tram/left{ - dir = 4 - }, +/obj/structure/transport/linear/tram, +/obj/structure/tram, +/obj/machinery/transport/tram_controller, /turf/open/openspace, /area/station/hallway/primary/tram/center) "rrk" = ( @@ -51731,7 +51725,7 @@ }, /obj/effect/turf_decal/stripes/white/line, /obj/effect/turf_decal/tile/neutral/tram, -/turf/open/floor/noslip/tram_plate/energized{ +/turf/open/floor/tram/plate/energized{ inbound = 2; outbound = 3 }, @@ -52131,6 +52125,11 @@ }, /turf/open/floor/iron, /area/station/hallway/secondary/entry) +"rDE" = ( +/obj/structure/fluff/tram_rail/electric/anchor, +/obj/structure/lattice, +/turf/open/openspace, +/area/station/hallway/primary/tram/center) "rDI" = ( /obj/effect/turf_decal/trimline/white/line{ dir = 1 @@ -52211,7 +52210,7 @@ /obj/structure/holosign/barrier/atmos/tram, /obj/structure/cable, /obj/structure/disposalpipe/segment, -/turf/open/floor/noslip/tram_platform, +/turf/open/floor/tram, /area/station/hallway/primary/tram/center) "rGj" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -52686,9 +52685,10 @@ /turf/open/floor/iron, /area/station/engineering/atmospherics_engine) "rPq" = ( -/obj/structure/industrial_lift/tram/white, /obj/effect/turf_decal/tile/neutral/tram, -/turf/open/floor/noslip/tram_plate, +/obj/structure/transport/linear/tram, +/obj/structure/thermoplastic/light, +/turf/open/indestructible/tram/plate, /area/station/hallway/primary/tram/center) "rPs" = ( /obj/machinery/power/apc/auto_name/directional/west, @@ -53303,6 +53303,17 @@ "saZ" = ( /turf/open/floor/iron, /area/station/maintenance/tram/mid) +"sbb" = ( +/obj/effect/turf_decal/tile/neutral/tram, +/obj/effect/turf_decal/stripes/white/line, +/obj/effect/turf_decal/stripes/white/line{ + dir = 1 + }, +/turf/open/floor/tram/plate/energized{ + inbound = 1; + outbound = 2 + }, +/area/station/hallway/primary/tram/left) "sbe" = ( /obj/structure/table/wood, /obj/structure/window/reinforced/spawner/directional/west{ @@ -54675,7 +54686,7 @@ }, /obj/effect/turf_decal/stripes/white/line, /obj/effect/turf_decal/tile/neutral/tram, -/turf/open/floor/noslip/tram_plate/energized{ +/turf/open/floor/tram/plate/energized{ inbound = 1; outbound = 2 }, @@ -55261,8 +55272,8 @@ }, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/machinery/door/window/elevator/right/directional/south{ - elevator_linked_id = "tram_xeno_lift"; - elevator_mode = 1 + elevator_mode = 1; + transport_linked_id = "tram_xeno_lift" }, /turf/open/floor/iron/white, /area/station/science/xenobiology) @@ -55376,7 +55387,7 @@ /obj/structure/railing{ dir = 4 }, -/obj/structure/industrial_lift/public, +/obj/structure/transport/linear/public, /turf/open/floor/plating/elevatorshaft, /area/station/maintenance/tram/mid) "sNr" = ( @@ -55821,7 +55832,7 @@ /obj/structure/holosign/barrier/atmos/tram, /obj/structure/cable, /obj/structure/disposalpipe/segment, -/turf/open/floor/noslip/tram_platform, +/turf/open/floor/tram, /area/station/hallway/primary/tram/center) "sUD" = ( /obj/structure/chair, @@ -55961,13 +55972,10 @@ /turf/open/floor/iron, /area/station/security/execution/transfer) "sXj" = ( -/obj/structure/industrial_lift/tram/subfloor/window, -/obj/structure/window/reinforced/tram/front{ - icon_state = "tram_window-3" - }, -/obj/machinery/computer/tram_controls/directional/west, /obj/effect/turf_decal/tile/neutral/tram, -/turf/open/floor/noslip/tram_plate, +/obj/structure/transport/linear/tram, +/obj/structure/tram, +/turf/open/indestructible/tram/plate, /area/station/hallway/primary/tram/center) "sXm" = ( /obj/effect/turf_decal/trimline/brown/filled/line{ @@ -56030,9 +56038,9 @@ /turf/open/floor/iron, /area/station/security/checkpoint/engineering) "sXX" = ( -/obj/structure/industrial_lift/public, -/obj/effect/landmark/lift_id{ - specific_lift_id = "tram_xeno_lift" +/obj/structure/transport/linear/public, +/obj/effect/landmark/transport/transport_id{ + specific_transport_id = "tram_xeno_lift" }, /obj/effect/turf_decal/trimline/dark_red/warning{ dir = 1 @@ -56308,15 +56316,8 @@ /turf/open/floor/catwalk_floor, /area/station/hallway/primary/tram/left) "tdv" = ( -/obj/structure/industrial_lift/tram, -/obj/structure/window/reinforced/tram/directional/south, -/obj/machinery/destination_sign/south{ - pixel_y = -11 - }, -/obj/effect/landmark/start/hangover, -/obj/structure/chair/sofa/bench/tram/right{ - dir = 4 - }, +/obj/structure/transport/linear/tram, +/obj/structure/tram, /turf/open/openspace, /area/station/hallway/primary/tram/center) "tdx" = ( @@ -56368,12 +56369,13 @@ /obj/effect/turf_decal/trimline/tram/filled/warning{ dir = 1 }, -/obj/machinery/button/tram/directional/north{ - id = 3 - }, /obj/effect/turf_decal/trimline/tram/filled/line{ dir = 1 }, +/obj/machinery/button/transport/tram/directional/north{ + id = 3 + }, +/obj/machinery/transport/destination_sign/indicator/directional/north, /turf/open/floor/iron, /area/station/hallway/primary/tram/right) "tel" = ( @@ -57142,11 +57144,6 @@ }, /turf/open/floor/iron/dark, /area/station/ai_monitored/turret_protected/aisat_interior) -"tsf" = ( -/obj/structure/industrial_lift/tram, -/obj/structure/window/reinforced/tram/directional/north, -/turf/open/openspace, -/area/station/hallway/primary/tram/center) "tsg" = ( /obj/effect/turf_decal/trimline/purple/filled/corner{ dir = 8 @@ -57285,13 +57282,13 @@ /turf/open/floor/iron/dark, /area/station/engineering/storage/tech) "tuU" = ( -/obj/structure/industrial_lift/public, -/obj/effect/landmark/lift_id{ - specific_lift_id = "tram_dorm_lift" - }, +/obj/structure/transport/linear/public, /obj/effect/abstract/elevator_music_zone{ linked_elevator_id = "tram_dorm_lift" }, +/obj/effect/landmark/transport/transport_id{ + specific_transport_id = "tram_dorm_lift" + }, /turf/open/floor/plating/elevatorshaft, /area/station/maintenance/tram/left) "tvP" = ( @@ -57350,10 +57347,10 @@ /obj/effect/turf_decal/trimline/green/filled/line, /obj/effect/turf_decal/trimline/yellow/warning, /obj/machinery/door/window/elevator/right/directional/south{ - elevator_linked_id = "dumbwaiter_lift"; elevator_mode = 1; name = "Dumbwaiter"; - req_access = null + req_access = null; + transport_linked_id = "dumbwaiter_lift" }, /turf/open/floor/iron/dark, /area/station/service/hydroponics) @@ -57788,16 +57785,9 @@ "tCi" = ( /turf/open/floor/iron/dark, /area/station/service/chapel/monastery) -"tCl" = ( -/obj/structure/fluff/tram_rail, -/turf/open/openspace, -/area/station/hallway/primary/tram/center) "tCo" = ( /obj/effect/turf_decal/tile/neutral/tram, -/turf/open/floor/noslip/tram_plate/energized{ - inbound = 1; - outbound = 2 - }, +/turf/open/indestructible/tram/plate, /area/station/hallway/primary/tram/left) "tCw" = ( /obj/structure/lattice/catwalk, @@ -58721,11 +58711,9 @@ /turf/open/floor/iron, /area/station/engineering/atmos) "tUk" = ( -/obj/structure/industrial_lift/tram, -/obj/structure/window/reinforced/tram/directional/north, -/obj/structure/chair/sofa/bench/tram/right{ - dir = 8 - }, +/obj/structure/transport/linear/tram, +/obj/structure/tram/split, +/obj/machinery/transport/destination_sign/split/north, /turf/open/openspace, /area/station/hallway/primary/tram/center) "tUy" = ( @@ -58794,16 +58782,20 @@ /obj/machinery/light/directional/south, /turf/open/floor/grass, /area/station/service/hydroponics/garden) +"tVS" = ( +/obj/structure/fluff/tram_rail/electric, +/turf/open/openspace, +/area/station/hallway/primary/tram/center) "tVZ" = ( /obj/effect/turf_decal/trimline/dark_red/warning{ dir = 6 }, -/obj/structure/industrial_lift/public, +/obj/structure/transport/linear/public, /obj/structure/railing{ dir = 6 }, -/obj/effect/landmark/lift_id{ - specific_lift_id = "tram_perma_lift" +/obj/effect/landmark/transport/transport_id{ + specific_transport_id = "tram_perma_lift" }, /obj/effect/abstract/elevator_music_zone{ linked_elevator_id = "tram_perma_lift" @@ -59068,6 +59060,17 @@ "uax" = ( /turf/open/floor/iron, /area/station/cargo/storage) +"uaE" = ( +/obj/effect/turf_decal/tile/neutral/tram, +/obj/effect/turf_decal/stripes/white/line, +/obj/effect/turf_decal/stripes/white/line{ + dir = 1 + }, +/turf/open/floor/tram/plate/energized{ + inbound = 1; + outbound = 2 + }, +/area/station/hallway/primary/tram/center) "uaJ" = ( /obj/machinery/computer/mechpad, /turf/open/floor/iron, @@ -59360,6 +59363,9 @@ "ufe" = ( /obj/structure/lattice, /obj/machinery/light/cold/dim/directional/west, +/obj/machinery/transport/guideway_sensor{ + dir = 1 + }, /turf/open/openspace, /area/station/asteroid) "ufh" = ( @@ -59539,12 +59545,9 @@ /turf/closed/wall, /area/station/science/robotics/lab) "ujf" = ( -/obj/structure/fluff/tram_rail, -/obj/effect/landmark/start/hangover, -/obj/structure/industrial_lift/tram, -/obj/structure/chair/sofa/bench/tram/right{ - dir = 4 - }, +/obj/structure/fluff/tram_rail/electric, +/obj/structure/transport/linear/tram, +/obj/structure/thermoplastic, /turf/open/openspace, /area/station/hallway/primary/tram/center) "ujm" = ( @@ -60276,10 +60279,10 @@ /obj/structure/railing{ dir = 4 }, -/obj/structure/industrial_lift/public, +/obj/structure/transport/linear/public, /obj/machinery/elevator_control_panel/directional/east{ linked_elevator_id = "tram_lower_center_lift"; - preset_destination_names = list("2"="Lower Deck","3"="Upper Deck") + preset_destination_names = list("2"="Lower Deck","3"="Upper Deck") }, /turf/open/floor/plating/elevatorshaft, /area/station/maintenance/tram/mid) @@ -60319,7 +60322,7 @@ "uuD" = ( /obj/structure/railing, /obj/effect/turf_decal/trimline/dark_red/warning, -/obj/structure/industrial_lift/public, +/obj/structure/transport/linear/public, /turf/open/floor/plating/elevatorshaft, /area/station/maintenance/tram/mid) "uuR" = ( @@ -60648,10 +60651,11 @@ /turf/open/floor/iron, /area/station/commons/storage/primary) "uAE" = ( -/obj/structure/industrial_lift/tram/white, /obj/effect/landmark/start/hangover, /obj/effect/turf_decal/tile/neutral/tram, -/turf/open/floor/noslip/tram_plate, +/obj/structure/transport/linear/tram, +/obj/structure/thermoplastic/light, +/turf/open/indestructible/tram/plate, /area/station/hallway/primary/tram/center) "uAF" = ( /obj/effect/spawner/structure/window/reinforced, @@ -60921,7 +60925,7 @@ loot = list(/obj/effect/decal/cleanable/oil/slippery=10,/obj/effect/decal/cleanable/oil=90); name = "funny slipper :)" }, -/turf/open/floor/noslip/tram_plate, +/turf/open/floor/tram/plate, /area/station/hallway/primary/tram/right) "uEw" = ( /obj/machinery/button/door/directional/east{ @@ -61137,7 +61141,7 @@ /obj/effect/turf_decal/trimline/dark_red/warning{ dir = 5 }, -/obj/structure/industrial_lift/public, +/obj/structure/transport/linear/public, /obj/structure/railing{ dir = 1 }, @@ -61661,13 +61665,6 @@ /obj/effect/turf_decal/trimline/white/warning, /turf/open/floor/iron, /area/station/maintenance/tram/right) -"uOL" = ( -/obj/structure/industrial_lift/tram/white, -/obj/machinery/door/window/tram/right/directional/north{ - pixel_y = -25 - }, -/turf/open/openspace, -/area/station/hallway/primary/tram/center) "uOQ" = ( /obj/machinery/biogenerator, /obj/effect/turf_decal/trimline/neutral/filled/line{ @@ -61793,20 +61790,20 @@ /turf/open/floor/iron, /area/station/security/checkpoint/arrivals) "uSl" = ( +/obj/structure/transport/linear/public, +/obj/structure/railing, /obj/effect/turf_decal/trimline/dark_red/warning, -/obj/structure/industrial_lift/public, /obj/machinery/elevator_control_panel/directional/south{ linked_elevator_id = "tram_dorm_lift"; preset_destination_names = list("2"="Lower Deck","3"="Upper Deck") }, -/obj/structure/railing, /turf/open/floor/plating/elevatorshaft, /area/station/maintenance/tram/left) "uSL" = ( /obj/effect/turf_decal/delivery/white, /obj/structure/fluff/tram_rail/floor, /obj/structure/holosign/barrier/atmos/tram, -/turf/open/floor/noslip/tram_platform, +/turf/open/floor/tram, /area/station/hallway/primary/tram/left) "uSP" = ( /obj/structure/cable, @@ -61980,8 +61977,8 @@ dir = 1 }, /obj/machinery/door/window/elevator/right/directional/south{ - elevator_linked_id = "tram_perma_lift"; - elevator_mode = 1 + elevator_mode = 1; + transport_linked_id = "tram_perma_lift" }, /turf/open/floor/iron, /area/station/security/brig) @@ -63358,10 +63355,10 @@ /turf/open/floor/iron/freezer, /area/station/science/lower) "vtP" = ( -/obj/structure/fluff/tram_rail, -/obj/structure/industrial_lift/tram, -/obj/effect/landmark/start/hangover, -/obj/structure/chair/sofa/bench/tram/left{ +/obj/structure/fluff/tram_rail/electric, +/obj/structure/transport/linear/tram, +/obj/structure/thermoplastic, +/obj/structure/chair/sofa/bench/tram/right{ dir = 8 }, /turf/open/openspace, @@ -63526,7 +63523,7 @@ /obj/effect/turf_decal/trimline/dark_red/warning{ dir = 10 }, -/obj/structure/industrial_lift/public, +/obj/structure/transport/linear/public, /turf/open/floor/plating/elevatorshaft, /area/station/maintenance/tram/mid) "vyo" = ( @@ -63795,7 +63792,7 @@ /obj/structure/disposalpipe/segment{ dir = 2 }, -/turf/open/floor/noslip/tram_platform, +/turf/open/floor/tram, /area/station/hallway/primary/tram/right) "vCt" = ( /obj/effect/turf_decal/trimline/green/filled/corner{ @@ -64016,7 +64013,7 @@ /obj/structure/railing{ dir = 8 }, -/obj/structure/industrial_lift/public, +/obj/structure/transport/linear/public, /turf/open/floor/plating/elevatorshaft, /area/station/maintenance/tram/mid) "vFC" = ( @@ -64297,8 +64294,8 @@ dir = 4 }, /obj/machinery/door/window/elevator/right/directional/west{ - elevator_linked_id = "tram_cargo_lift"; - elevator_mode = 1 + elevator_mode = 1; + transport_linked_id = "tram_cargo_lift" }, /turf/open/floor/iron, /area/station/cargo/miningdock) @@ -64521,12 +64518,6 @@ }, /turf/open/floor/iron, /area/station/hallway/secondary/entry) -"vPi" = ( -/obj/structure/fluff/tram_rail{ - dir = 1 - }, -/turf/open/openspace, -/area/station/hallway/primary/tram/right) "vPw" = ( /obj/effect/decal/cleanable/cobweb, /obj/effect/turf_decal/trimline/yellow/filled/corner{ @@ -64851,7 +64842,7 @@ /turf/open/floor/plating, /area/station/service/lawoffice) "vVY" = ( -/obj/structure/fluff/tram_rail{ +/obj/structure/fluff/tram_rail/electric{ dir = 1 }, /turf/open/openspace, @@ -65753,7 +65744,7 @@ /turf/open/floor/iron/dark, /area/station/service/chapel/monastery) "wop" = ( -/obj/structure/industrial_lift/public, +/obj/structure/transport/linear/public, /obj/effect/turf_decal/caution/stand_clear/red, /turf/open/floor/plating/elevatorshaft, /area/station/maintenance/tram/mid) @@ -65762,8 +65753,8 @@ dir = 10 }, /obj/machinery/door/window/elevator/left/directional/south{ - elevator_linked_id = "tram_perma_lift"; - elevator_mode = 1 + elevator_mode = 1; + transport_linked_id = "tram_perma_lift" }, /turf/open/floor/iron, /area/station/security/execution/transfer) @@ -65780,6 +65771,17 @@ }, /turf/open/floor/iron/cafeteria, /area/station/commons/dorms/laundry) +"woM" = ( +/obj/effect/turf_decal/tile/neutral/tram, +/obj/effect/turf_decal/stripes/white/line, +/obj/effect/turf_decal/stripes/white/line{ + dir = 1 + }, +/turf/open/floor/tram/plate/energized{ + inbound = 1; + outbound = 2 + }, +/area/station/hallway/primary/tram/right) "woR" = ( /obj/effect/turf_decal/bot, /obj/machinery/portable_atmospherics/pump, @@ -65866,8 +65868,8 @@ "wqk" = ( /obj/effect/turf_decal/caution/stand_clear/white, /obj/machinery/door/window/elevator/left/directional/north{ - elevator_linked_id = "tram_lower_center_lift"; - elevator_mode = 1 + elevator_mode = 1; + transport_linked_id = "tram_lower_center_lift" }, /turf/open/floor/iron, /area/station/maintenance/tram/mid) @@ -66107,12 +66109,6 @@ /obj/structure/cable, /turf/open/floor/circuit, /area/station/ai_monitored/turret_protected/aisat_interior) -"wvE" = ( -/obj/structure/fluff/tram_rail{ - dir = 1 - }, -/turf/open/openspace, -/area/station/hallway/primary/tram/center) "wvG" = ( /obj/effect/turf_decal/trimline/red/filled/corner{ dir = 1 @@ -66515,9 +66511,10 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/effect/turf_decal/trimline/tram/filled/line, /obj/effect/turf_decal/trimline/tram/filled/warning, -/obj/machinery/button/tram/directional/south{ +/obj/machinery/button/transport/tram/directional/south{ id = 2 }, +/obj/machinery/transport/destination_sign/indicator/directional/south, /turf/open/floor/iron, /area/station/hallway/primary/tram/center) "wCn" = ( @@ -66894,7 +66891,7 @@ /area/station/commons/dorms) "wJq" = ( /obj/effect/turf_decal/tile/neutral/tram, -/turf/open/floor/noslip/tram_plate, +/turf/open/floor/tram/plate, /area/station/hallway/primary/tram/center) "wJt" = ( /obj/machinery/door/poddoor{ @@ -67351,7 +67348,7 @@ /obj/effect/turf_decal/delivery/white, /obj/structure/holosign/barrier/atmos/tram, /obj/structure/disposalpipe/segment, -/turf/open/floor/noslip/tram_platform, +/turf/open/floor/tram, /area/station/hallway/primary/tram/center) "wVV" = ( /obj/effect/turf_decal/trimline/red/filled/line{ @@ -69034,7 +69031,7 @@ /obj/effect/turf_decal/trimline/dark_red/warning{ dir = 8 }, -/obj/structure/industrial_lift/public, +/obj/structure/transport/linear/public, /turf/open/floor/plating/elevatorshaft, /area/station/maintenance/tram/mid) "xEo" = ( @@ -69476,6 +69473,12 @@ /obj/item/lighter, /turf/open/floor/carpet, /area/station/security/detectives_office) +"xNA" = ( +/obj/structure/fluff/tram_rail/electric{ + dir = 1 + }, +/turf/open/openspace, +/area/station/hallway/primary/tram/right) "xNH" = ( /obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ dir = 8 @@ -69557,7 +69560,7 @@ /obj/structure/disposalpipe/segment{ dir = 2 }, -/turf/open/floor/noslip/tram_platform, +/turf/open/floor/tram, /area/station/hallway/primary/tram/right) "xPg" = ( /obj/effect/turf_decal/trimline/brown/filled/line, @@ -69950,13 +69953,10 @@ /turf/closed/wall, /area/station/hallway/secondary/exit/departure_lounge) "xXb" = ( -/obj/machinery/crossing_signal/southeast{ - inbound = 2; - outbound = 3 - }, /obj/effect/turf_decal/stripes/white/line{ dir = 1 }, +/obj/machinery/transport/crossing_signal/southeast, /turf/open/floor/iron, /area/station/hallway/primary/tram/center) "xXe" = ( @@ -69998,8 +69998,10 @@ /turf/open/floor/iron, /area/station/hallway/primary/tram/center) "xXU" = ( -/obj/structure/fluff/tram_rail, -/obj/structure/industrial_lift/tram, +/obj/structure/fluff/tram_rail/electric/anchor, +/obj/structure/transport/linear/tram, +/obj/structure/thermoplastic, +/obj/structure/chair/sofa/bench/tram, /turf/open/openspace, /area/station/hallway/primary/tram/center) "xXZ" = ( @@ -70268,10 +70270,14 @@ /turf/open/floor/iron, /area/station/security/courtroom) "ycE" = ( -/obj/structure/fluff/tram_rail{ +/obj/structure/fluff/tram_rail/electric/anchor{ + dir = 1 + }, +/obj/structure/transport/linear/tram, +/obj/structure/thermoplastic, +/obj/structure/chair/sofa/bench/tram{ dir = 1 }, -/obj/structure/industrial_lift/tram, /turf/open/openspace, /area/station/hallway/primary/tram/center) "ycI" = ( @@ -70293,6 +70299,9 @@ "ydd" = ( /obj/structure/lattice, /obj/machinery/light/cold/dim/directional/east, +/obj/machinery/transport/guideway_sensor{ + dir = 1 + }, /turf/open/openspace, /area/station/asteroid) "ydh" = ( @@ -70722,11 +70731,11 @@ /area/station/security/courtroom) "yka" = ( /obj/machinery/smartfridge, -/obj/effect/landmark/lift_id{ - specific_lift_id = "dumbwaiter_lift" +/obj/effect/landmark/transport/transport_id{ + specific_transport_id = "dumbwaiter_lift" }, /obj/effect/turf_decal/delivery/red, -/obj/structure/industrial_lift/public, +/obj/structure/transport/linear/public, /obj/effect/turf_decal/tile/green/fourcorners, /turf/open/floor/iron/dark, /area/station/service/hydroponics) @@ -153459,7 +153468,7 @@ qhM nYq yiM cFs -lNP +gVV tCo vVY cFs @@ -153716,8 +153725,8 @@ esd kiU kTz cFs -lNP -lzu +gVV +tCo vVY cFs mCu @@ -153973,8 +153982,8 @@ eaT kiU aQm cFs -lNP -lzu +gVV +tCo vVY cFs aQm @@ -154230,8 +154239,8 @@ eaT vfr aQm cFs -lNP -lzu +gVV +tCo vVY cFs aQm @@ -154487,8 +154496,8 @@ eaT kiU aQm cFs -lNP -lzu +gVV +tCo vVY cFs aQm @@ -154742,13 +154751,13 @@ jfp lPY xFl erO -aII +yiM cFs bEt lUP rib cFs -aMD +yiM rov cbe aEa @@ -155001,8 +155010,8 @@ eaT kiU aQm cFs -lNP -lzu +gVV +tCo vVY cFs aQm @@ -155258,8 +155267,8 @@ eaT kiU aQm cFs -lNP -lzu +gVV +tCo vVY cFs aQm @@ -155515,8 +155524,8 @@ eaT kiU aQm cFs -lNP -lzu +gVV +tCo vVY cFs aQm @@ -155772,8 +155781,8 @@ gBN kiU nlS cFs -lNP -lzu +gVV +tCo vVY cFs cPI @@ -156029,8 +156038,8 @@ qhM nKo yiM cFs -lNP -lzu +gVV +tCo vVY cFs yiM @@ -156286,8 +156295,8 @@ hja kGF tJe cFs -lNP -lzu +gVV +tCo vVY cFs nBo @@ -157057,7 +157066,7 @@ yiM wmo yiM cFs -lNP +gVV lzu vVY cFs @@ -157570,11 +157579,11 @@ yiM tkv qUg yiM -afy -afP +cFs +gVV lzu -afX -afy +vVY +cFs yiM rnR tkv @@ -157827,11 +157836,11 @@ yiM yiM lIQ yiM -afy -afP +cFs +gVV lzu -afX -afy +vVY +cFs yiM aGL yiM @@ -158084,11 +158093,11 @@ yiM iYd ifS yiM -afy -afP +cFs +gVV lzu -afX -afy +vVY +cFs yiM aEP qSQ @@ -158341,11 +158350,11 @@ yiM tdu ojT iPy -afy -afP +cFs +lNP lzu -afX -afy +vVY +cFs iPy ojT aHe @@ -158598,11 +158607,11 @@ yiM aEh iPy yiM -afz -afS +cFs +gVV lzu -afY -afz +vVY +cFs yiM iPy tBu @@ -158854,12 +158863,12 @@ aaS afz afA afz -ufe -afy +kFn +qrv afP -lzu +sbb afX -afy +qrv ufe afz age @@ -159112,11 +159121,11 @@ afy afA afy afy -afy -afP +cFs +gVV lzu -afX -afy +vVY +cFs afy afy age @@ -159369,11 +159378,11 @@ afy afA afy afy -afy -afP +cFs +gVV lzu -afX -afy +vVY +cFs afy afy age @@ -159626,11 +159635,11 @@ afy afA afy afy -afy -afP +cFs +gVV lzu -afX -afy +vVY +cFs afy afy age @@ -159883,11 +159892,11 @@ afy afA afy afy -afy -afP +cFs +gVV lzu -afX -afy +vVY +cFs afy afy age @@ -160140,11 +160149,11 @@ afy afA afy afy -afy -afP +cFs +gVV lzu -afX -afy +vVY +cFs afy afy age @@ -160397,11 +160406,11 @@ afy afB afE afJ -afy -afP +cFs +gVV lzu -afX -afy +vVY +cFs agb afE agf @@ -160654,11 +160663,11 @@ afz afC vFt oNG -afy -afP +cFs +bEt jWQ -afX -afy +rib +cFs lgK yiM agg @@ -160911,11 +160920,11 @@ afy afD afG afM -afy -afP +cFs +gVV lzu -afX -afy +vVY +cFs agd afG agh @@ -161168,11 +161177,11 @@ afy afA afy afy -afy -afP +cFs +gVV lzu -afX -afy +vVY +cFs afy afy age @@ -161425,11 +161434,11 @@ afy afA afy afy -afy -afP +cFs +gVV lzu -afX -afy +vVY +cFs afy afy age @@ -161682,11 +161691,11 @@ afy afA afy afy -afy -afP +eSz +tVS wJq -afX -afy +lWi +eSz afy afy age @@ -161939,11 +161948,11 @@ afy afA afy afy -afy -afP +eSz +tVS wJq -afX -afy +lWi +eSz afy afy age @@ -162196,11 +162205,11 @@ afy afB afE afJ -afy -afP +eSz +tVS wJq -afX -afy +lWi +eSz agb afE agf @@ -162453,11 +162462,11 @@ afz afC izU oNG -afy -afP +eSz +oCg wJq -afX -afy +kCf +eSz lgK qas agg @@ -162710,11 +162719,11 @@ afy afD afG afN -afy -afP +eSz +tVS wJq -afX -afy +lWi +eSz agd afG agh @@ -162967,11 +162976,11 @@ afy afA afy afy -afy -afP +eSz +tVS wJq -afX -afy +lWi +eSz afy afy age @@ -163224,11 +163233,11 @@ afy afA afy afy -afy -afP +eSz +tVS wJq -afX -afy +lWi +eSz afy afy age @@ -163481,11 +163490,11 @@ afy afA afy afy -afy -afP +eSz +tVS wJq -afX -afy +lWi +eSz afy afy age @@ -163738,11 +163747,11 @@ afy afA afy afy -afy -afP +eSz +tVS wJq -afX -afy +lWi +eSz afy afy age @@ -163995,11 +164004,11 @@ afy afA afy afy -afy -afP +eSz +tVS wJq -afX -afy +lWi +eSz afy afy age @@ -164251,12 +164260,12 @@ afv afz afA afz -ydd -afy -afP -wJq -afX -afy +jDp +nkn +rDE +uaE +mFL +nkn ydd afz age @@ -164509,11 +164518,11 @@ izU vMI nEl izU -afz -afV +eSz +tVS wJq -aga -afz +lWi +eSz izU nEl dnp @@ -164766,11 +164775,11 @@ izU wWn wYw nEl -afy -afP +eSz +tVS wJq -afX -afy +lWi +eSz nEl wYw aHf @@ -165023,11 +165032,11 @@ izU nOj gGI izU -afy -afP +eSz +tVS wJq -afX -afy +lWi +eSz izU ghg xlZ @@ -165280,11 +165289,11 @@ izU izU dXc izU -afy -afP +eSz +tVS wJq -afX -afy +lWi +eSz izU aGM izU @@ -165537,11 +165546,11 @@ izU seG vYA izU -afy -afP +eSz +tVS wJq -afX -afy +lWi +eSz izU pby seG @@ -166052,9 +166061,9 @@ izU dno ago eSz -tCl +tVS wJq -wvE +lWi eSz ago blP @@ -166823,9 +166832,9 @@ aEl wQW cFS eSz -tCl -wJq -wvE +tVS +aYl +lWi eSz kbq ooV @@ -167075,7 +167084,7 @@ izU izU izU izU -izU +bup tAL sOD izU @@ -167593,7 +167602,7 @@ aEj rOu mYI ykP -fqv +aGO olw rPq gUF @@ -167850,7 +167859,7 @@ eyK obC kjY ykP -uOL +rlO olw uAE gUF @@ -168107,7 +168116,7 @@ aEl rOu umT ykP -tUk +jSX ffU gIm jUw @@ -168363,13 +168372,13 @@ vyH iNr rOu wCl -fld -tsf +izU +jSX xXU oZC ycE jSX -jEO +izU jHR dWi bPh @@ -168624,8 +168633,8 @@ ykP tUk hio rPq -aEq -dtY +aay +jSX ykP lej pxC @@ -168878,8 +168887,8 @@ iZV tQy cHj ykP -fqv -olw +aGO +jJb uAE gUF aGO @@ -169135,7 +169144,7 @@ aEj rOu mpa ykP -uOL +rlO olw rPq gUF @@ -169392,9 +169401,9 @@ moU aEl mpa aiH -jUi +tdv vtP -juu +bWe ndX ray dhI @@ -169651,7 +169660,7 @@ gnK izU gjM fNs -poE +sXj hCt cNT izU @@ -169907,9 +169916,9 @@ aEn gfk bbu eSz -tCl -wJq -wvE +tVS +aYl +lWi eSz dTx sIM @@ -170678,9 +170687,9 @@ izU lQe iRT eSz -tCl +tVS wJq -wvE +lWi eSz iRT dPB @@ -171191,11 +171200,11 @@ abE seG vYA izU -afy -afP +eSz +tVS wJq -afX -afy +lWi +eSz izU ghg seG @@ -171448,11 +171457,11 @@ abE izU suw izU -afy -afP +eSz +tVS wJq -afX -afy +lWi +eSz izU aHk izU @@ -171705,11 +171714,11 @@ abE kMs qtS izU -afy -afP +eSz +tVS wJq -afX -afy +lWi +eSz izU ghg xlZ @@ -171962,11 +171971,11 @@ abE gEC wYw nEl -afy -afP +eSz +tVS wJq -afX -afy +lWi +eSz nEl wYw aHl @@ -172219,11 +172228,11 @@ izU eqK nEl izU -afz -afS +eSz +tVS wJq -afY -afz +lWi +eSz izU nEl mhE @@ -172475,12 +172484,12 @@ afv afz afA afz -ufe -afy -afP -wJq -afX -afy +kFn +nkn +rDE +bQV +mFL +nkn ufe afz age @@ -172733,11 +172742,11 @@ afy afA afy afy -afy -afP +eSz +tVS wJq -afX -afy +lWi +eSz afy afy age @@ -172990,11 +172999,11 @@ afy afA afy afy -afy -afP +eSz +tVS wJq -afX -afy +lWi +eSz afy afy age @@ -173247,11 +173256,11 @@ afy afA afy afy -afy -afP +eSz +tVS wJq -afX -afy +lWi +eSz afy afy age @@ -173504,11 +173513,11 @@ afy afA afy afy -afy -afP +eSz +tVS wJq -afX -afy +lWi +eSz afy afy age @@ -173761,11 +173770,11 @@ afy afA afy afy -afy -afP +eSz +tVS wJq -afX -afy +lWi +eSz afy afy age @@ -174018,11 +174027,11 @@ afy afB afE afJ -afy -afP +eSz +tVS wJq -afX -afy +lWi +eSz agb afE agf @@ -174275,11 +174284,11 @@ afz afC qas oNG -afy -afP +eSz +oCg wJq -afX -afy +kCf +eSz lgK izU agg @@ -174532,11 +174541,11 @@ afy afD afG afN -afy -afP +eSz +tVS wJq -afX -afy +lWi +eSz agd afG agh @@ -174789,11 +174798,11 @@ afy afA afy afy -afy -afP +eSz +tVS wJq -afX -afy +lWi +eSz afy afy age @@ -175046,11 +175055,11 @@ afy afA afy afy -afy -afP +eSz +tVS wJq -afX -afy +lWi +eSz afy afy age @@ -175303,11 +175312,11 @@ afy afA afy afy -afy -afP +brm +fxX lMF -afX -afy +xNA +brm afy afy age @@ -175560,11 +175569,11 @@ afy afA afy afy -afy -afP +brm +fxX lMF -afX -afy +xNA +brm afy afy age @@ -175817,11 +175826,11 @@ afy afB afE afJ -afy -afP +brm +fxX lMF -afX -afy +xNA +brm agb afE agf @@ -176074,11 +176083,11 @@ afz afC bMb oNG -afy -afP +brm +nyP lMF -afX -afy +cMd +brm lgK bMb agg @@ -176331,11 +176340,11 @@ afy afD afG afN -afy -afP +brm +fxX lMF -afX -afy +xNA +brm agd afG agh @@ -176588,11 +176597,11 @@ afy afA afy afy -afy -afP +brm +fxX uEo -afX -afy +xNA +brm afy afy age @@ -176845,11 +176854,11 @@ afy afA afy afy -afy -afP +brm +fxX lMF -afX -afy +xNA +brm afy afy age @@ -177102,11 +177111,11 @@ afy afA afy afy -afy -afP +brm +fxX lMF -afX -afy +xNA +brm afy afy age @@ -177359,11 +177368,11 @@ afy afA afy afy -afy -afP +brm +fxX lMF -afX -afy +xNA +brm afy afy age @@ -177616,11 +177625,11 @@ afy afA afy afy -afy -afP +brm +fxX lMF -afX -afy +xNA +brm afy afy age @@ -177872,12 +177881,12 @@ afv afz afA afz -ydd -afy -afP -lMF -afX -afy +jDp +pVi +ngr +woM +kby +pVi ydd afz age @@ -178130,11 +178139,11 @@ bMb lyt ghV bMb -afz -afS +brm +fxX lMF -afY -afz +xNA +brm bMb ghV bXG @@ -178387,11 +178396,11 @@ lZW kYk rxO ghV -afy -afP +brm +fxX lMF -afX -afy +xNA +brm ghV rxO aHn @@ -178644,11 +178653,11 @@ lZW qIt mzf bMb -afy -afP +brm +fxX lMF -afX -afy +xNA +brm bMb gaH bly @@ -178901,11 +178910,11 @@ lZW bMb qHo bMb -afy -afP +brm +fxX lMF -afX -afy +xNA +brm bMb aHo bMb @@ -179158,11 +179167,11 @@ skT lRs lVe bMb -afy -afP +brm +fxX lMF -afX -afy +xNA +brm bMb aEv lRs @@ -179673,9 +179682,9 @@ bMb car pxO brm -iOd +fxX lMF -vPi +xNA brm pxO aEx @@ -180444,9 +180453,9 @@ aEz xkX fSf brm -iOd -lMF -vPi +fxX +dAt +xNA brm mEd kuq @@ -180701,9 +180710,9 @@ rEB glv bMb brm -iOd -lMF -vPi +fxX +dAt +xNA brm bMb oiv @@ -180958,9 +180967,9 @@ rEB oPw rlZ brm -iOd -lMF -vPi +fxX +dAt +xNA brm tjl bNW @@ -181215,9 +181224,9 @@ aEA pne dfx brm -iOd -lMF -vPi +fxX +dAt +xNA brm dfx blg @@ -181472,9 +181481,9 @@ rEB oPw dfx brm -iOd -lMF -vPi +fxX +dAt +xNA brm dfx qVk @@ -181729,9 +181738,9 @@ lHu nbv dfx brm -iOd -lMF -vPi +fxX +dAt +xNA brm dfx wTU @@ -181984,13 +181993,13 @@ wgQ iMj dlg nqj -dCf +bMb brm -puY +nyP mQE -bTT +cMd brm -nwQ +bMb tef iPD ptV @@ -182243,9 +182252,9 @@ vyN ncT dfx brm -iOd -lMF -vPi +fxX +dAt +xNA brm dfx xZQ @@ -182500,9 +182509,9 @@ rEB rMl dfx brm -iOd -lMF -vPi +fxX +dAt +xNA brm dfx xZQ @@ -182757,9 +182766,9 @@ cXX eOw dfx brm -iOd -lMF -vPi +fxX +dAt +xNA brm dfx cey @@ -183014,9 +183023,9 @@ giR rMl qnL brm -iOd -lMF -vPi +fxX +dAt +xNA brm idI xZQ @@ -183271,9 +183280,9 @@ qtF iIS bMb brm -iOd -oHq -vPi +fxX +dAt +xNA brm bMb pvI diff --git a/code/__DEFINES/ai/ai.dm b/code/__DEFINES/ai/ai.dm index 83d7e7f6a5f..53cbf117af4 100644 --- a/code/__DEFINES/ai/ai.dm +++ b/code/__DEFINES/ai/ai.dm @@ -48,3 +48,14 @@ #define SHOULD_RESIST(source) (source.on_fire || source.buckled || HAS_TRAIT(source, TRAIT_RESTRAINED) || (source.pulledby && source.pulledby.grab_state > GRAB_PASSIVE)) ///macro for whether the pawn can act, used generally to prevent some horrifying ai disasters #define IS_DEAD_OR_INCAP(source) (source.incapacitated() || source.stat) + +GLOBAL_LIST_INIT(all_radial_directions, list( + "NORTH" = image(icon = 'icons/testing/turf_analysis.dmi', icon_state = "red_arrow", dir = NORTH), + "NORTHEAST" = image(icon = 'icons/testing/turf_analysis.dmi', icon_state = "red_arrow", dir = NORTHEAST), + "EAST" = image(icon = 'icons/testing/turf_analysis.dmi', icon_state = "red_arrow", dir = EAST), + "SOUTHEAST" = image(icon = 'icons/testing/turf_analysis.dmi', icon_state = "red_arrow", dir = SOUTHEAST), + "SOUTH" = image(icon = 'icons/testing/turf_analysis.dmi', icon_state = "red_arrow", dir = SOUTH), + "SOUTHWEST" = image(icon = 'icons/testing/turf_analysis.dmi', icon_state = "red_arrow", dir = SOUTHWEST), + "WEST" = image(icon = 'icons/testing/turf_analysis.dmi', icon_state = "red_arrow", dir = WEST), + "NORTHWEST" = image(icon = 'icons/testing/turf_analysis.dmi', icon_state = "red_arrow", dir = NORTHWEST) +)) diff --git a/code/__DEFINES/airlock.dm b/code/__DEFINES/airlock.dm index f53b144d4a6..dd3ee6a8ecb 100644 --- a/code/__DEFINES/airlock.dm +++ b/code/__DEFINES/airlock.dm @@ -4,3 +4,11 @@ #define AIRLOCK_LIGHT_DENIED "denied" #define AIRLOCK_LIGHT_CLOSING "closing" #define AIRLOCK_LIGHT_OPENING "opening" + +// Airlock physical states +#define AIRLOCK_CLOSED 1 +#define AIRLOCK_CLOSING 2 +#define AIRLOCK_OPEN 3 +#define AIRLOCK_OPENING 4 +#define AIRLOCK_DENY 5 +#define AIRLOCK_EMAG 6 diff --git a/code/__DEFINES/colors.dm b/code/__DEFINES/colors.dm index 2b253c90aad..b23df993432 100644 --- a/code/__DEFINES/colors.dm +++ b/code/__DEFINES/colors.dm @@ -78,6 +78,8 @@ #define COLOR_COMMAND_BLUE "#1B67A5" #define COLOR_MEDICAL_BLUE "#5B97BC" #define COLOR_MODERATE_BLUE "#555CC2" +#define COLOR_TRAM_BLUE "#6160A8" +#define COLOR_TRAM_LIGHT_BLUE "#A8A7DA" #define COLOR_AMETHYST "#822BFF" #define COLOR_BLUE_LIGHT "#33CCFF" #define COLOR_NAVY "#000080" @@ -219,6 +221,8 @@ #define LIGHT_COLOR_BLUEGREEN "#7DE1AF" /// Diluted cyan. rgb(125, 225, 225) #define LIGHT_COLOR_CYAN "#7DE1E1" +/// Faint cyan. rgb(200, 240, 255) +#define LIGHT_COLOR_FAINT_CYAN "#CAF0FF" /// Baby Blue rgb(0, 170, 220) #define LIGHT_COLOR_BABY_BLUE "#00AADC" /// Electric cyan rgb(0, 255, 255) @@ -280,6 +284,15 @@ #define COLOR_PRIDE_BLUE "#42FFF2" #define COLOR_PRIDE_PURPLE "#5D5DFC" +/// Colors for status/tram/incident displays +#define COLOR_DISPLAY_RED "#BE3455" +#define COLOR_DISPLAY_ORANGE "#FF9900" +#define COLOR_DISPLAY_YELLOW "#FFF743" +#define COLOR_DISPLAY_GREEN "#3CF046" +#define COLOR_DISPLAY_CYAN "#22FFCC" +#define COLOR_DISPLAY_BLUE "#22CCFF" +#define COLOR_DISPLAY_PURPLE "#5D5DFC" + /// The default color for admin say, used as a fallback when the preference is not enabled #define DEFAULT_ASAY_COLOR COLOR_MOSTLY_PURE_RED diff --git a/code/__DEFINES/construction/structures.dm b/code/__DEFINES/construction/structures.dm index cda5b920a42..32368f421cd 100644 --- a/code/__DEFINES/construction/structures.dm +++ b/code/__DEFINES/construction/structures.dm @@ -38,6 +38,11 @@ #define RWINDOW_BOLTS_HEATED 7 #define RWINDOW_SECURE 8 +//tram structure construction states +#define TRAM_OUT_OF_FRAME 0 +#define TRAM_IN_FRAME 1 +#define TRAM_SCREWED_TO_FRAME 2 + //airlock assembly construction states #define AIRLOCK_ASSEMBLY_NEEDS_WIRES 0 #define AIRLOCK_ASSEMBLY_NEEDS_ELECTRONICS 1 @@ -60,3 +65,4 @@ // Stationary gas tanks #define TANK_FRAME 0 #define TANK_PLATING_UNSECURED 1 + diff --git a/code/__DEFINES/dcs/signals/signals_lift.dm b/code/__DEFINES/dcs/signals/signals_lift.dm index 26eef6b9e17..b2ecbf07004 100644 --- a/code/__DEFINES/dcs/signals/signals_lift.dm +++ b/code/__DEFINES/dcs/signals/signals_lift.dm @@ -1,2 +1,2 @@ -/// Sent from /datum/lift_master when a normal lift starts or stops going up or down. (direction if started or 0 if stopped) +/// Sent from /datum/transport_controller when a normal lift starts or stops going up or down. (direction if started or 0 if stopped) #define COMSIG_LIFT_SET_DIRECTION "lift_set_direction" diff --git a/code/__DEFINES/dcs/signals/signals_tram.dm b/code/__DEFINES/dcs/signals/signals_tram.dm deleted file mode 100644 index 8788a646749..00000000000 --- a/code/__DEFINES/dcs/signals/signals_tram.dm +++ /dev/null @@ -1,8 +0,0 @@ -/// Sent from /obj/structure/industrial_lift/tram when its travelling status updates. (travelling) -#define COMSIG_TRAM_SET_TRAVELLING "tram_set_travelling" - -/// Sent from /obj/structure/industrial_lift/tram when it begins to travel. (obj/effect/landmark/tram/idle_platform, obj/effect/landmark/tram/to_where) -#define COMSIG_TRAM_TRAVEL "tram_travel" - -/// Sent from /obj/structure/industrial_lift/tram when it hits someone: () -#define COMSIG_TRAM_COLLISION "tram_collided" diff --git a/code/__DEFINES/dcs/signals/signals_transport.dm b/code/__DEFINES/dcs/signals/signals_transport.dm new file mode 100644 index 00000000000..6e3dc6f39b2 --- /dev/null +++ b/code/__DEFINES/dcs/signals/signals_transport.dm @@ -0,0 +1,17 @@ +/// Sent from /obj/structure/transport/linear/tram when it begins to travel. (obj/effect/landmark/tram/idle_platform, obj/effect/landmark/tram/to_where) +#define COMSIG_TRAM_TRAVEL "tram_travel" + +/// Sent from /obj/structure/transport/linear/tram when it hits someone: () +#define COMSIG_TRAM_COLLISION "tram_collided" + +// Sent to and from SStransport for control between various components +/// Requesting transport move to a destination +#define COMSIG_TRANSPORT_REQUEST "!REQ" +/// Response to a COMSIG_TRANSPORT_REQUEST request signal +#define COMSIG_TRANSPORT_RESPONSE "!RESP" +/// Transport controller 'active' (busy) status +#define COMSIG_TRANSPORT_ACTIVE "!ACTV" +/// Transport controller destination change signal +#define COMSIG_TRANSPORT_DESTINATION "!DEST" +/// Transport controller communication status (tram malfunction event) +#define COMSIG_COMMS_STATUS "!COMM" diff --git a/code/__DEFINES/dcs/signals/signals_turf.dm b/code/__DEFINES/dcs/signals/signals_turf.dm index 4c20b5f9dd7..65709f4e446 100644 --- a/code/__DEFINES/dcs/signals/signals_turf.dm +++ b/code/__DEFINES/dcs/signals/signals_turf.dm @@ -20,7 +20,7 @@ #define COMSIG_TURF_EXPOSE "turf_expose" ///from /turf/proc/immediate_calculate_adjacent_turfs() #define COMSIG_TURF_CALCULATED_ADJACENT_ATMOS "turf_calculated_adjacent_atmos" -///called when an industrial lift enters this turf +///called when an elevator enters this turf #define COMSIG_TURF_INDUSTRIAL_LIFT_ENTER "turf_industrial_life_enter" ///from /datum/element/decal/Detach(): (description, cleanable, directional, mutable_appearance/pic) diff --git a/code/__DEFINES/icon_smoothing.dm b/code/__DEFINES/icon_smoothing.dm index 830daef563d..55d25fd5e45 100644 --- a/code/__DEFINES/icon_smoothing.dm +++ b/code/__DEFINES/icon_smoothing.dm @@ -174,13 +174,16 @@ DEFINE_BITFIELD(smoothing_junction, list( #define SMOOTH_GROUP_WINDOW_FULLTILE_PLASTITANIUM S_OBJ(24) ///turf/closed/indestructible/opsglass, /obj/structure/window/reinforced/plasma/plastitanium #define SMOOTH_GROUP_WINDOW_FULLTILE_SHUTTLE S_OBJ(25) ///obj/structure/window/reinforced/shuttle -#define SMOOTH_GROUP_WINDOW_DIRECTIONAL_TRAM S_OBJ(26) ///obj/structure/window/reinforced/tram +#define SMOOTH_GROUP_WINDOW_DIRECTIONAL_TRAM S_OBJ(26) ///obj/structure/tram #define SMOOTH_GROUP_LATTICE S_OBJ(31) ///obj/structure/lattice #define SMOOTH_GROUP_CATWALK S_OBJ(32) ///obj/structure/lattice/catwalk #define SMOOTH_GROUP_AIRLOCK S_OBJ(41) ///obj/machinery/door/airlock +#define SMOOTH_GROUP_INDUSTRIAL_LIFT S_OBJ(46) ///obj/structure/transport/linear +#define SMOOTH_GROUP_TRAM_STRUCTURE S_OBJ(47) //obj/structure/tram + #define SMOOTH_GROUP_TABLES S_OBJ(51) ///obj/structure/table #define SMOOTH_GROUP_WOOD_TABLES S_OBJ(52) ///obj/structure/table/wood #define SMOOTH_GROUP_FANCY_WOOD_TABLES S_OBJ(53) ///obj/structure/table/wood/fancy @@ -202,8 +205,6 @@ DEFINE_BITFIELD(smoothing_junction, list( #define SMOOTH_GROUP_CLEANABLE_DIRT S_OBJ(68) ///obj/effect/decal/cleanable/dirt -#define SMOOTH_GROUP_INDUSTRIAL_LIFT S_OBJ(71) ///obj/structure/industrial_lift - #define SMOOTH_GROUP_GAS_TANK S_OBJ(72) //SKYRAT EDIT ADDITION diff --git a/code/__DEFINES/industrial_lift.dm b/code/__DEFINES/industrial_lift.dm deleted file mode 100644 index 5ab2406229d..00000000000 --- a/code/__DEFINES/industrial_lift.dm +++ /dev/null @@ -1,41 +0,0 @@ -//Booleans in arguments are confusing, so I made them defines. -///the lift's controls are currently locked from user input -#define LIFT_PLATFORM_LOCKED 1 -///the lift's controls are currently unlocked so user's can direct it -#define LIFT_PLATFORM_UNLOCKED 0 - -//lift_id's -///basic lift_id, goes up and down -#define BASIC_LIFT_ID "base" -///tram lift_id, goes left and right or north and south. maybe one day be able to turn and go up/down as well -#define TRAM_LIFT_ID "tram" -///debug lift_id -#define DEBUG_LIFT_ID "debug" - -///used for navigation aids that aren't actual platforms -#define TRAM_NAV_BEACONS "tram_nav" -#define IMMOVABLE_ROD_DESTINATIONS "immovable_rod" - -//specific_lift_id's -///the specific_lift_id of the main station tram landmark for tramstation that spawns roundstart. -#define MAIN_STATION_TRAM "main station tram" -///the specific_lift_id of the tram on the hilbert research station -#define HILBERT_TRAM "tram_hilbert" -///the specific_lift_id of the trams on birdshot station -#define PRISON_TRAM "prison_tram" -#define MAINTENANCE_TRAM "maint_tram" - -// Defines for update_lift_doors -#define OPEN_DOORS "open" -#define CLOSE_DOORS "close" - -// Defines for the state of tram destination signs -#define DESTINATION_WEST_ACTIVE "west_active" -#define DESTINATION_WEST_IDLE "west_idle" -#define DESTINATION_CENTRAL_EASTBOUND_ACTIVE "central_eb_active" -#define DESTINATION_CENTRAL_WESTBOUND_ACTIVE "central_wb_active" -#define DESTINATION_CENTRAL_IDLE "central_idle" -#define DESTINATION_EAST_ACTIVE "east_active" -#define DESTINATION_EAST_IDLE "east_idle" -#define DESTINATION_NOT_IN_SERVICE "NIS" -#define DESTINATION_OFF "off" diff --git a/code/__DEFINES/is_helpers.dm b/code/__DEFINES/is_helpers.dm index 23d941585e6..f8f91ebaa47 100644 --- a/code/__DEFINES/is_helpers.dm +++ b/code/__DEFINES/is_helpers.dm @@ -232,7 +232,7 @@ GLOBAL_LIST_INIT(turfs_pass_meteor, typecacheof(list( #define ismachinery(A) (istype(A, /obj/machinery)) -#define istramwall(A) (istype(A, /obj/structure/window/reinforced/tram/front)) +#define istramwall(A) (istype(A, /obj/structure/tram)) #define isvendor(A) (istype(A, /obj/machinery/vending)) diff --git a/code/__DEFINES/layers.dm b/code/__DEFINES/layers.dm index b9af1fd64ba..0cdad4f7241 100644 --- a/code/__DEFINES/layers.dm +++ b/code/__DEFINES/layers.dm @@ -134,7 +134,6 @@ #define WIRE_LAYER 2.044 #define GLASS_FLOOR_LAYER 2.046 #define TRAM_RAIL_LAYER 2.047 -#define TRAM_FLOOR_LAYER 2.048 #define ABOVE_OPEN_TURF_LAYER 2.049 //WALL_PLANE layers @@ -161,6 +160,9 @@ // Anything above this layer is not "on" a turf for the purposes of washing // I hate this life of ours #define FLOOR_CLEAN_LAYER 2.55 +#define TRAM_STRUCTURE_LAYER 2.57 +#define TRAM_FLOOR_LAYER 2.58 +#define TRAM_WALL_LAYER 2.59 #define BELOW_OPEN_DOOR_LAYER 2.6 ///Anything below this layer is to be considered completely (visually) under water by the immerse layer. @@ -201,6 +203,7 @@ // GAME_PLANE_UPPER layers #define ABOVE_MOB_LAYER 4.1 #define WALL_OBJ_LAYER 4.25 +#define TRAM_SIGNAL_LAYER 4.26 // WALL_PLANE_UPPER layers #define EDGED_TURF_LAYER 4.3 #define ON_EDGED_TURF_LAYER 4.35 diff --git a/code/__DEFINES/logging.dm b/code/__DEFINES/logging.dm index 8c21879fb64..0a4424b0d73 100644 --- a/code/__DEFINES/logging.dm +++ b/code/__DEFINES/logging.dm @@ -22,6 +22,7 @@ #define INVESTIGATE_RADIATION "radiation" #define INVESTIGATE_RECORDS "records" #define INVESTIGATE_RESEARCH "research" +#define INVESTIGATE_TRANSPORT "transport" #define INVESTIGATE_WIRES "wires" // Logging types for log_message() @@ -47,6 +48,7 @@ #define LOG_VICTIM (1 << 19) #define LOG_RADIO_EMOTE (1 << 20) #define LOG_SPEECH_INDICATORS (1 << 21) +#define LOG_TRANSPORT (1 << 22) //Individual logging panel pages #define INDIVIDUAL_GAME_LOG (LOG_GAME) @@ -107,6 +109,7 @@ #define LOG_CATEGORY_TARGET_ZONE_SWITCH "target-zone-switch" #define LOG_CATEGORY_TELECOMMS "telecomms" #define LOG_CATEGORY_TOOL "tool" +#define LOG_CATEGORY_TRANSPORT "transport" #define LOG_CATEGORY_VIRUS "virus" // Admin categories diff --git a/code/__DEFINES/stack.dm b/code/__DEFINES/stack.dm new file mode 100644 index 00000000000..5e43561b838 --- /dev/null +++ b/code/__DEFINES/stack.dm @@ -0,0 +1,4 @@ +/// Checks if this is banned from being built on the tram +#define STACK_CHECK_TRAM_FORBIDDEN (1<<2) +/// Checks if this can only built on the tram +#define STACK_CHECK_TRAM_EXCLUSIVE (1<<3) diff --git a/code/__DEFINES/tram.dm b/code/__DEFINES/tram.dm deleted file mode 100644 index a88086b36a5..00000000000 --- a/code/__DEFINES/tram.dm +++ /dev/null @@ -1,32 +0,0 @@ -/// Tram crossing light logic -#define XING_STATE_GREEN 0 -#define XING_STATE_AMBER 1 -#define XING_STATE_RED 2 -#define XING_STATE_MALF 3 - -#define XING_DISTANCE_AMBER 70 -#define XING_DISTANCE_RED 40 - -#define XING_SIGNAL_DIRECTION_WEST "west-" -#define XING_SIGNAL_DIRECTION_EAST "east-" - -#define XING_DEFAULT_TRAM_LENGTH 10 - -/// Tram destinations/platforms -#define TRAMSTATION_WEST 1 -#define TRAMSTATION_CENTRAL 2 -#define TRAMSTATION_EAST 3 - -#define HILBERT_PORT 1 -#define HILBERT_CENTRAL 2 -#define HILBERT_STARBOARD 3 - -#define BIRDSHOT_PRISON_WING 1 -#define BIRDSHOT_SECURITY_WING 2 - -#define BIRDSHOT_MAINTENANCE_LEFT 1 -#define BRIDSHOT_MAINTENANCE_RIGHT 2 - -/// Tram navigation directions -#define OUTBOUND 1 -#define INBOUND -1 diff --git a/code/__DEFINES/transport.dm b/code/__DEFINES/transport.dm new file mode 100644 index 00000000000..452ba285354 --- /dev/null +++ b/code/__DEFINES/transport.dm @@ -0,0 +1,115 @@ +#define SEND_TRANSPORT_SIGNAL(sigtype, arguments...) ( SEND_SIGNAL(SStransport, sigtype, ##arguments) ) + +// Transport directions +#define INBOUND -1 +#define OUTBOUND 1 + +// Status response codes +#define REQUEST_FAIL "!FAIL" +#define REQUEST_SUCCESS "!ACK" +#define NOT_IN_SERVICE "!NIS" +#define TRANSPORT_IN_USE "!BUSY" +#define INVALID_PLATFORM "!NDEST" +#define NO_CALL_REQUIRED "!NCR" +#define INTERNAL_ERROR "!ERR" +#define BROKEN_BEYOND_REPAIR "!DEAD" + +// Tram lines +#define TRAMSTATION_LINE_1 "tram_1" +#define HILBERT_LINE_1 "hilb_1" +#define BIRDSHOT_LINE_1 "bird_1" +#define BIRDSHOT_LINE_2 "bird_2" + +// Destinations/platforms +#define TRAMSTATION_WEST 1 +#define TRAMSTATION_CENTRAL 2 +#define TRAMSTATION_EAST 3 + +#define HILBERT_PORT 1 +#define HILBERT_CENTRAL 2 +#define HILBERT_STARBOARD 3 + +#define BIRDSHOT_PRISON_WING 1 +#define BIRDSHOT_SECURITY_WING 2 + +#define BIRDSHOT_MAINTENANCE_LEFT 1 +#define BRIDSHOT_MAINTENANCE_RIGHT 2 + +// Tram Navigation aids +#define TRAM_NAV_BEACONS "tram_nav" +#define IMMOVABLE_ROD_DESTINATIONS "immovable_rod" + +// The lift's controls are currently locked from user input +#define LIFT_PLATFORM_LOCKED 1 +// The lift's controls are currently unlocked so user's can direct it +#define LIFT_PLATFORM_UNLOCKED 0 + +// Flags for the Tram VOBC (vehicle on-board computer) +#define SYSTEM_FAULT (1<<0) +#define COMM_ERROR (1<<1) +#define EMERGENCY_STOP (1<<2) +#define PRE_DEPARTURE (1<<3) +#define DOORS_READY (1<<4) +#define CONTROLS_LOCKED (1<<5) +#define BYPASS_SENSORS (1<<6) +#define RAPID_MODE (1<<7) + +DEFINE_BITFIELD(controller_status, list( + "SYSTEM_FAULT" = SYSTEM_FAULT, + "COMM_ERROR" = COMM_ERROR, + "EMERGENCY_STOP" = EMERGENCY_STOP, + "PRE_DEPARTURE" = PRE_DEPARTURE, + "DOORS_READY" = DOORS_READY, + "CONTROLS_LOCKED" = CONTROLS_LOCKED, + "BYPASS_SENSORS" = BYPASS_SENSORS, +)) + +#define TRANSPORT_FLAGS list( \ + "SYSTEM_FAULT", \ + "COMM_ERROR", \ + "EMERGENCY_STOP", \ + "PRE_DEPARTURE", \ + "DOORS_READY", \ + "CONTROLS_LOCKED", \ + "BYPASS_SENSORS", \ +) + +DEFINE_BITFIELD(request_flags, list( + "RAPID_MODE" = RAPID_MODE, + "BYPASS_SENSORS" = BYPASS_SENSORS, +)) + +// Logging +#define SUB_TS_STATUS "TS-[english_list(bitfield_to_list(transport_controller.controller_status, TRANSPORT_FLAGS))]" +#define TC_TS_STATUS "TS-[english_list(bitfield_to_list(controller_status, TRANSPORT_FLAGS))]" +#define TC_TA_INFO "TA-[transport_controller.controller_active ? "PROCESSING" : "READY"]" + +// Landmarks +#define TRANSPORT_TYPE_ELEVATOR "icts_elev" +#define TRANSPORT_TYPE_TRAM "icts_tram" +#define TRANSPORT_TYPE_DEBUG "icts_debug" + +// Tram door cycles +#define CYCLE_OPEN "open" +#define CYCLE_CLOSED "close" + +// Crossing signals +#define XING_STATE_GREEN 0 +#define XING_STATE_AMBER 1 +#define XING_STATE_RED 2 +#define XING_STATE_MALF 3 + +#define AMBER_THRESHOLD_NORMAL 45 +#define RED_THRESHOLD_NORMAL 20 +#define AMBER_THRESHOLD_DEGRADED 30 +#define RED_THRESHOLD_DEGRADED 15 + +#define DEFAULT_TRAM_LENGTH 10 + +// Tram machinery subtype +#define TRANSPORT_SYSTEM_NORMAL 0 +#define TRANSPORT_REMOTE_WARNING 1 +#define TRANSPORT_LOCAL_WARNING 2 +#define TRANSPORT_REMOTE_FAULT 3 +#define TRANSPORT_LOCAL_FAULT 4 +#define TRANSPORT_BREAKDOWN_RATE 0.0175 diff --git a/code/__DEFINES/~skyrat_defines/airlock.dm b/code/__DEFINES/~skyrat_defines/airlock.dm new file mode 100644 index 00000000000..8f0a05e3e61 --- /dev/null +++ b/code/__DEFINES/~skyrat_defines/airlock.dm @@ -0,0 +1,35 @@ +#define AIRLOCK_FRAME_CLOSED "closed" +#define AIRLOCK_FRAME_CLOSING "closing" +#define AIRLOCK_FRAME_OPEN "open" +#define AIRLOCK_FRAME_OPENING "opening" + +#define AIRLOCK_SECURITY_NONE 0 //Normal airlock //Wires are not secured +#define AIRLOCK_SECURITY_IRON 1 //Medium security airlock //There is a simple iron plate over wires (use welder) +#define AIRLOCK_SECURITY_PLASTEEL_I_S 2 //Sliced inner plating (use crowbar), jumps to 0 +#define AIRLOCK_SECURITY_PLASTEEL_I 3 //Removed outer plating, second layer here (use welder) +#define AIRLOCK_SECURITY_PLASTEEL_O_S 4 //Sliced outer plating (use crowbar) +#define AIRLOCK_SECURITY_PLASTEEL_O 5 //There is first layer of plasteel (use welder) +#define AIRLOCK_SECURITY_PLASTEEL 6 //Max security airlock //Fully secured wires (use wirecutters to remove grille, that is electrified) + +#define AIRLOCK_INTEGRITY_N 300 // Normal airlock integrity +#define AIRLOCK_INTEGRITY_MULTIPLIER 1.5 // How much reinforced doors health increases +/// How much extra health airlocks get when braced with a seal +#define AIRLOCK_SEAL_MULTIPLIER 2 +#define AIRLOCK_DAMAGE_DEFLECTION_N 21 // Normal airlock damage deflection +#define AIRLOCK_DAMAGE_DEFLECTION_R 30 // Reinforced airlock damage deflection + +#define AIRLOCK_DENY_ANIMATION_TIME (0.6 SECONDS) /// The amount of time for the airlock deny animation to show + +#define DOOR_CLOSE_WAIT 60 /// Time before a door closes, if not overridden + +#define DOOR_VISION_DISTANCE 11 ///The maximum distance a door will see out to + +#define AIRLOCK_LIGHT_POWER 0.5 +#define AIRLOCK_LIGHT_RANGE 2 +#define AIRLOCK_LIGHT_ENGINEERING "engineering" +#define AIRLOCK_POWERON_LIGHT_COLOR "#3aa7c2" +#define AIRLOCK_BOLTS_LIGHT_COLOR "#c22323" +#define AIRLOCK_ACCESS_LIGHT_COLOR "#57e69c" +#define AIRLOCK_EMERGENCY_LIGHT_COLOR "#d1d11d" +#define AIRLOCK_ENGINEERING_LIGHT_COLOR "#fd8719" +#define AIRLOCK_DENY_LIGHT_COLOR "#c22323" diff --git a/code/__HELPERS/logging/_logging.dm b/code/__HELPERS/logging/_logging.dm index 66de82d5240..e6085c0cdc1 100644 --- a/code/__HELPERS/logging/_logging.dm +++ b/code/__HELPERS/logging/_logging.dm @@ -145,6 +145,8 @@ GLOBAL_LIST_INIT(testing_global_profiler, list("_PROFILE_NAME" = "Global")) log_comment(log_text) if(LOG_TELECOMMS) log_telecomms(log_text) + if(LOG_TRANSPORT) + log_transport(log_text) if(LOG_ECON) log_econ(log_text) if(LOG_OOC) diff --git a/code/__HELPERS/logging/transport.dm b/code/__HELPERS/logging/transport.dm new file mode 100644 index 00000000000..f2145632023 --- /dev/null +++ b/code/__HELPERS/logging/transport.dm @@ -0,0 +1,3 @@ +/// Logging for transport (tram/elevator) actions +/proc/log_transport(text, list/data) + logger.Log(LOG_CATEGORY_TRANSPORT, text, data) diff --git a/code/controllers/subsystem/persistence.dm b/code/controllers/subsystem/persistence.dm index 56e4b5abb8c..ce3c1f7619b 100644 --- a/code/controllers/subsystem/persistence.dm +++ b/code/controllers/subsystem/persistence.dm @@ -55,7 +55,9 @@ SUBSYSTEM_DEF(persistence) save_modular_persistence() // SKYRAT EDIT ADDITION - MODULAR_PERSISTENCE save_custom_outfits() save_delamination_counter() - if(SStramprocess.can_fire) + if(SStransport.can_fire) + for(var/datum/transport_controller/linear/tram/transport as anything in SStransport.transports_by_type[TRANSPORT_TYPE_TRAM]) + save_tram_history(transport.specific_transport_id) save_tram_counter() save_panic_bunker() //SKYRAT EDIT ADDITION - PANICBUNKER @@ -569,8 +571,61 @@ SUBSYSTEM_DEF(persistence) /datum/controller/subsystem/persistence/proc/save_tram_counter() rustg_file_write("[tram_hits_this_round]", TRAM_COUNT_FILEPATH) +#define MAX_TRAM_SAVES 4 + +// Loads historical tram data +/datum/controller/subsystem/persistence/proc/load_tram_history(specific_transport_id) + var/list/raw_saved_trams = list() + var/json_file = file("data/tram_data/[specific_transport_id].json") + if(!fexists(json_file)) + return + var/list/json = json_decode(file2text(json_file)) + if(!json) + return + raw_saved_trams = json["data"] + + var/list/previous_tram_data = list() + for(var/raw_json in raw_saved_trams) + var/datum/tram_mfg_info/parsed_tram_data = new + parsed_tram_data.load_from_json(raw_json) + previous_tram_data += parsed_tram_data + return previous_tram_data + +// Saves historical tram data +/datum/controller/subsystem/persistence/proc/save_tram_history(specific_transport_id) + var/list/packaged_tram_data = list() + for(var/datum/transport_controller/linear/tram/transport as anything in SStransport.transports_by_type[TRANSPORT_TYPE_TRAM]) + if(transport.specific_transport_id == specific_transport_id) + packaged_tram_data = package_tram_data(transport) + break + + var/json_file = file("data/tram_data/[specific_transport_id].json") + var/list/file_data = list() + var/list/converted_data = list() + + for(var/datum/tram_mfg_info/data in packaged_tram_data) + converted_data += list(data.export_to_json()) + + file_data["data"] = converted_data + fdel(json_file) + WRITE_FILE(json_file, json_encode(file_data)) + +/datum/controller/subsystem/persistence/proc/package_tram_data(datum/transport_controller/linear/tram/tram_controller) + var/list/packaged_data = list() + var/list/tram_list = tram_controller.tram_history + if(!isnull(tram_list)) + while(tram_list.len > MAX_TRAM_SAVES) + tram_list.Cut(1,2) + + for(var/datum/tram_mfg_info/data as anything in tram_list) + packaged_data += data + + packaged_data += tram_controller.tram_registration + return packaged_data + #undef DELAMINATION_COUNT_FILEPATH #undef DELAMINATION_HIGHSCORE_FILEPATH #undef TRAM_COUNT_FILEPATH #undef FILE_RECENT_MAPS #undef KEEP_ROUNDS_MAP +#undef MAX_TRAM_SAVES diff --git a/code/controllers/subsystem/processing/tramprocess.dm b/code/controllers/subsystem/processing/tramprocess.dm deleted file mode 100644 index b497cce8b8c..00000000000 --- a/code/controllers/subsystem/processing/tramprocess.dm +++ /dev/null @@ -1,15 +0,0 @@ -PROCESSING_SUBSYSTEM_DEF(tramprocess) - name = "Tram Process" - wait = 0.5 - /// only used on maps with trams, so only enabled by such. - can_fire = FALSE - - ///how much time a tram can take per movement before we notify admins and slow down the tram. in milliseconds - var/max_time = 15 - - ///how many times the tram can move costing over max_time milliseconds before it gets slowed down - var/max_exceeding_moves = 5 - - ///how many times the tram can move costing less than half max_time milliseconds before we speed it back up again. - ///is only used if the tram has been slowed down for exceeding max_time - var/max_cheap_moves = 5 diff --git a/code/controllers/subsystem/transport.dm b/code/controllers/subsystem/transport.dm new file mode 100644 index 00000000000..db8d19fa060 --- /dev/null +++ b/code/controllers/subsystem/transport.dm @@ -0,0 +1,236 @@ +PROCESSING_SUBSYSTEM_DEF(transport) + name = "Transport" + wait = 0.05 SECONDS + /// only used on maps with trams, so only enabled by such. + can_fire = FALSE + + ///associative list of the form: list(lift_id = list(all transport_controller datums attached to lifts of that type)) + var/list/transports_by_type = list() + var/list/nav_beacons = list() + var/list/crossing_signals = list() + var/list/sensors = list() + var/list/doors = list() + var/list/displays = list() + ///how much time a tram can take per movement before we notify admins and slow down the tram. in milliseconds + var/max_time = 15 + ///how many times the tram can move costing over max_time milliseconds before it gets slowed down + var/max_exceeding_moves = 5 + ///how many times the tram can move costing less than half max_time milliseconds before we speed it back up again. + ///is only used if the tram has been slowed down for exceeding max_time + var/max_cheap_moves = 5 + +/** + * Registers the subsystem to listen for incoming requests from paired devices + * + * When a new device (such as a button, tram, signal etc) comes online + * it calls this proc with the subsystem enabling two-way communication using + * signals. + * + * Arguments: new_unit: the starting point to find a beacon + * unit_name: the friendly name of this device + * id_tag: a unique identifier for this device, set on init + */ +/datum/controller/subsystem/processing/transport/proc/hello(atom/new_unit, unit_name, id_tag) + RegisterSignal(new_unit, COMSIG_TRANSPORT_REQUEST, PROC_REF(incoming_request)) + log_transport("Sub: Registered new transport component [unit_name] [id_tag].") + +/datum/controller/subsystem/processing/transport/Recover() + _listen_lookup = SStransport._listen_lookup + +/** + * Performs the request received from a registered transport device + * + * Currently the only supported request type is tram dispatch + * so there's no var for what type of request it is + * + * The subsystem will validate and process, then send a success + * or fail response to the device that made the request, + * with info relevant to the request such as destination + * or error details (if the request is rejected/fails) + * + * Arguments: source: the device sending the request + * transport_id: the transport this request is for, such as tram line 1 or 2 + * platform: the requested destination to dispatch the tram + * options: additional flags for the request (ie: bypass doors, emagged request) + */ +/datum/controller/subsystem/processing/transport/proc/incoming_request(obj/source, transport_id, platform, options) + SIGNAL_HANDLER + + log_transport("Sub: Received request from [source.name] [source.id_tag]. Contents: [transport_id] [platform] [options]") + var/relevant + var/request_flags = options + var/datum/transport_controller/linear/tram/transport_controller + var/obj/effect/landmark/transport/nav_beacon/tram/platform/destination + for(var/datum/transport_controller/linear/tram/candidate_controller as anything in transports_by_type[TRANSPORT_TYPE_TRAM]) + if(candidate_controller.specific_transport_id == transport_id) + transport_controller = candidate_controller + break + + // We make a list of relevant devices (that should act/respond to this request) for when we send the signal at the end + LAZYADD(relevant, source) + + // Check for various failure states + // The transport controller datum is qdel'd + if(isnull(transport_controller)) + log_transport("Sub: Transport [transport_id] has no controller datum! Someone deleted it or something catastrophic happened.") + SEND_TRANSPORT_SIGNAL(COMSIG_TRANSPORT_RESPONSE, relevant, REQUEST_FAIL, BROKEN_BEYOND_REPAIR) + log_transport("Sub: Sending response to [source.id_tag]. Contents: [REQUEST_FAIL] [INTERNAL_ERROR]. Info: [SUB_TS_STATUS].") + return + + // Non operational (such as power loss) or the controls cabinet is missing/destroyed + if(!transport_controller.controller_operational || !transport_controller.paired_cabinet) + SEND_TRANSPORT_SIGNAL(COMSIG_TRANSPORT_RESPONSE, relevant, REQUEST_FAIL, NOT_IN_SERVICE) + log_transport("Sub: Sending response to [source.id_tag]. Contents: [REQUEST_FAIL] [NOT_IN_SERVICE]. Info: TC-[!transport_controller][!transport_controller.controller_operational][!transport_controller.paired_cabinet].") + return + + // Someone emergency stopped the tram, or something went wrong and it needs to reset its landmarks. + if(transport_controller.controller_status & SYSTEM_FAULT || transport_controller.controller_status & EMERGENCY_STOP) + SEND_TRANSPORT_SIGNAL(COMSIG_TRANSPORT_RESPONSE, relevant, REQUEST_FAIL, INTERNAL_ERROR) + log_transport("Sub: Sending response to [source.id_tag]. Contents: [REQUEST_FAIL] [INTERNAL_ERROR]. Info: [SUB_TS_STATUS].") + return + + // Controller is 'active' (not accepting requests right now) someone already pushed button, hit by a rod, etc. + if(transport_controller.controller_active) + SEND_TRANSPORT_SIGNAL(COMSIG_TRANSPORT_RESPONSE, relevant, REQUEST_FAIL, TRANSPORT_IN_USE) + log_transport("Sub: Sending response to [source.id_tag]. Contents: [REQUEST_FAIL] [TRANSPORT_IN_USE]. Info: [TC_TA_INFO].") + return + + // We've made it this far, tram is physically fine so let's trip plan + // This is based on the destination nav beacon, the logical location + // If Something Happens and the location the controller thinks it's at + // gets out of sync with it's actual physical location, it can be reset + + // Since players can set the platform ID themselves, make sure it's a valid platform we're aware of + var/network = LAZYACCESS(nav_beacons, transport_id) + for(var/obj/effect/landmark/transport/nav_beacon/tram/platform/potential_destination in network) + if(potential_destination.platform_code == platform) + destination = potential_destination + break + + // The platform in the request doesn't exist (ie: Can't send a tram to East Wing when the map is Birdshot) + if(!destination) + SEND_TRANSPORT_SIGNAL(COMSIG_TRANSPORT_RESPONSE, relevant, REQUEST_FAIL, INVALID_PLATFORM) + log_transport("Sub: Sending response to [source.id_tag]. Contents: [REQUEST_FAIL] [INVALID_PLATFORM]. Info: RD0.") + return + + // The controller thinks the tram is already there + if(transport_controller.idle_platform == destination) //did you even look? + SEND_TRANSPORT_SIGNAL(COMSIG_TRANSPORT_RESPONSE, relevant, REQUEST_FAIL, NO_CALL_REQUIRED) + log_transport("Sub: Sending response to [source.id_tag]. Contents: [REQUEST_FAIL] [NO_CALL_REQUIRED]. Info: RD1.") + return + + // Calculate the trip data, which will be stored on the controller datum, passed to the transport modules making up the tram + // If for some reason the controller can't determine the distance/direction it needs to go, send a failure message + if(!transport_controller.calculate_route(destination)) + SEND_TRANSPORT_SIGNAL(COMSIG_TRANSPORT_RESPONSE, relevant, REQUEST_FAIL, INTERNAL_ERROR) + log_transport("Sub: Sending response to [source.id_tag]. Contents: [REQUEST_FAIL] [INTERNAL_ERROR]. Info: NV0.") + return + + // At this point we're sending the tram somewhere, so send a success response to the devices + SEND_TRANSPORT_SIGNAL(COMSIG_TRANSPORT_RESPONSE, relevant, REQUEST_SUCCESS, destination.name) + log_transport("Sub: Sending response to [source.id_tag]. Contents: [REQUEST_SUCCESS] [destination.name].") + + // Since this is a signal and we're done with the request, do the rest async + INVOKE_ASYNC(src, PROC_REF(dispatch_transport), transport_controller, request_flags) + +/** + * Dispatches the transport on a validated trip + * + * The subsystem at this point has confirmed a valid trip + * Start the transport, wake up machinery running on + * the subsystem (signals, etc.) + * + * Make tram go, basically. + * + * Arguments: transport_controller: the transport controller datum we're giving orders to + * destination: destination we're sending it to + * request_flags: additional flags for the request (ie: bypass doors, emagged request) + */ +/datum/controller/subsystem/processing/transport/proc/dispatch_transport(datum/transport_controller/linear/tram/transport_controller, destination, request_flags) + log_transport("Sub: Sending dispatch request to [transport_controller.specific_transport_id]. [request_flags ? "Contents: [request_flags]." : "No request flags."]") + + // This will generally be caught in the request validation, however an admin may try to force move the tram, or other actions bypassing the request process. + if(transport_controller.idle_platform == transport_controller.destination_platform) + log_transport("Sub: [transport_controller.specific_transport_id] dispatch failed. Info: DE-1 Transport Controller idle and destination are the same.") + return + + // Set active, so no more requests will be accepted until we're in a safe state to change destination. + transport_controller.set_active(TRUE) + pre_departure(transport_controller, request_flags) + +/** + * Pre-departure checks for the tram + * + * We do things slighly different based on the request_flags such as + * door crushing, emag related things + * + * Arguments: transport_controller: the transport controller datum we're giving orders to + * request_flags: additional flags for the request (ie: bypass doors, emagged request) + */ +/datum/controller/subsystem/processing/transport/proc/pre_departure(datum/transport_controller/linear/tram/transport_controller, request_flags) + log_transport("Sub: [transport_controller.specific_transport_id] start pre-departure. Info: [SUB_TS_STATUS]") + + // Tram Malfunction event + if(transport_controller.controller_status & COMM_ERROR) + request_flags |= BYPASS_SENSORS + + // Lock the physical controls of the tram + transport_controller.set_status_code(PRE_DEPARTURE, TRUE) + transport_controller.set_status_code(CONTROLS_LOCKED, TRUE) + + // Tram door actions + log_transport("Sub: [transport_controller.specific_transport_id] requested door close. Info: [SUB_TS_STATUS].") + if(request_flags & RAPID_MODE || request_flags & BYPASS_SENSORS || transport_controller.controller_status & BYPASS_SENSORS) // bypass for unsafe, rapid departure + transport_controller.cycle_doors(CYCLE_CLOSED, BYPASS_DOOR_CHECKS) + if(request_flags & RAPID_MODE) + log_transport("Sub: [transport_controller.specific_transport_id] rapid mode enabled, bypassing validation.") + transport_controller.dispatch_transport() + return + else + transport_controller.set_status_code(DOORS_READY, FALSE) + transport_controller.cycle_doors(CYCLE_CLOSED) + + addtimer(CALLBACK(src, PROC_REF(validate_and_dispatch), transport_controller), 3 SECONDS) + +/** + * Operational checks, then start moving + * + * Some check failures aren't worth halting the tram for, like no blocking the doors forever + * Crush them instead! + * + * Arguments: transport_controller: the transport controller datum we're giving orders to + * attempt: how many attempts to start moving we've made + */ +/datum/controller/subsystem/processing/transport/proc/validate_and_dispatch(datum/transport_controller/linear/tram/transport_controller, attempt) + log_transport("Sub: [transport_controller.specific_transport_id] start pre-departure validation. Attempts: [attempt ? attempt : 0].") + var/current_attempt + if(attempt) + current_attempt = attempt + else + current_attempt = 0 + + if(current_attempt >= 4) + log_transport("Sub: [transport_controller.specific_transport_id] pre-departure validation failed, but dispatching tram anyways. Info: [SUB_TS_STATUS].") + transport_controller.dispatch_transport() + return + + current_attempt++ + + transport_controller.update_status() + if(!(transport_controller.controller_status & DOORS_READY)) + addtimer(CALLBACK(src, PROC_REF(validate_and_dispatch), transport_controller, current_attempt), 3 SECONDS) + return + else + + transport_controller.dispatch_transport() + log_transport("Sub: [transport_controller.specific_transport_id] pre-departure passed.") + +/// Give a list of destinations to the tram controls +/datum/controller/subsystem/processing/transport/proc/detailed_destination_list(specific_transport_id) + . = list() + for(var/obj/effect/landmark/transport/nav_beacon/tram/platform/destination as anything in SStransport.nav_beacons[specific_transport_id]) + var/list/this_destination = list() + this_destination["name"] = destination.name + this_destination["dest_icons"] = destination.tgui_icons + this_destination["id"] = destination.platform_code + . += list(this_destination) diff --git a/code/datums/components/energized.dm b/code/datums/components/energized.dm new file mode 100644 index 00000000000..64adeb5e9be --- /dev/null +++ b/code/datums/components/energized.dm @@ -0,0 +1,114 @@ +/datum/component/energized + can_transfer = FALSE + ///what we give to connect_loc by default, makes slippable mobs moving over us slip + var/static/list/default_connections = list( + COMSIG_ATOM_ENTERED = PROC_REF(toast), + ) + /// Inbound station + var/inbound + /// Outbound station + var/outbound + /// Transport ID of the tram + var/specific_transport_id = TRAMSTATION_LINE_1 + /// Weakref to the tram + var/datum/weakref/transport_ref + +/datum/component/energized/Initialize(plate_inbound, plate_outbound, plate_transport_id) + . = ..() + + if(isnull(plate_inbound)) + return + + inbound = plate_inbound + if(isnull(plate_outbound)) + return + + outbound = plate_outbound + if(isnull(plate_transport_id)) + return + + specific_transport_id = plate_transport_id + find_tram() + +/datum/component/energized/proc/find_tram() + for(var/datum/transport_controller/linear/transport as anything in SStransport.transports_by_type[TRANSPORT_TYPE_TRAM]) + if(transport.specific_transport_id == specific_transport_id) + transport_ref = WEAKREF(transport) + break + +/datum/component/energized/RegisterWithParent() + . = ..() + RegisterSignal(parent, COMSIG_ATOM_ENTERED, PROC_REF(toast)) + +/datum/component/energized/UnregisterFromParent() + UnregisterSignal(parent, COMSIG_ATOM_ENTERED) + return ..() + + +/datum/component/energized/proc/toast(turf/open/floor/source, atom/movable/arrived, atom/old_loc, list/atom/old_locs) + SIGNAL_HANDLER + + if(!source.broken && !source.burnt) + return + + if(!isliving(arrived)) + return + + if(prob(85)) + if(prob(25)) + do_sparks(1, FALSE, source) + playsound(src, SFX_SPARKS, 40, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) + source.audible_message(span_danger("[parent] makes an electric crackle...")) + return + + var/mob/living/future_tram_victim = arrived + var/datum/transport_controller/linear/tram/tram = transport_ref?.resolve() + + // Check for stopped states. + if(isnull(tram) || !tram.controller_operational || !inbound || !outbound) + return FALSE + + var/obj/structure/transport/linear/tram/tram_part = tram.return_closest_platform_to(parent) + + if(QDELETED(tram_part)) + return FALSE + + if(isnull(source)) + return FALSE + + // Everything will be based on position and travel direction + var/plate_pos + var/tram_pos + var/tram_velocity_sign // 1 for positive axis movement, -1 for negative + // Try to be agnostic about N-S vs E-W movement + if(tram.travel_direction & (NORTH|SOUTH)) + plate_pos = source.y + tram_pos = source.y + tram_velocity_sign = tram.travel_direction & NORTH ? 1 : -1 + else + plate_pos = source.x + tram_pos = source.x + tram_velocity_sign = tram.travel_direction & EAST ? 1 : -1 + + // How far away are we? negative if already passed. + var/approach_distance = tram_velocity_sign * (plate_pos - (tram_pos + (DEFAULT_TRAM_LENGTH * 0.5))) + + // Check if our victim is in the active path of the tram. + if(!tram.controller_active) + return FALSE + if(approach_distance < 0) + return FALSE + if((tram.travel_direction & WEST) && inbound < tram.destination_platform.platform_code) + return FALSE + if((tram.travel_direction & EAST) && outbound > tram.destination_platform.platform_code) + return FALSE + if(approach_distance >= AMBER_THRESHOLD_NORMAL) + return FALSE + + // Finally the interesting part where they ACTUALLY get hit! + notify_ghosts("[future_tram_victim] has fallen in the path of an oncoming tram!", source = future_tram_victim, action = NOTIFY_ORBIT, header = "Electrifying!") + playsound(src, SFX_SPARKS, 75, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) + source.audible_message(span_danger("[parent] makes a loud electric crackle!")) + to_chat(future_tram_victim, span_userdanger("You hear a loud electric crackle!")) + future_tram_victim.electrocute_act(15, src, 1) + return TRUE diff --git a/code/datums/components/omen.dm b/code/datums/components/omen.dm index f499d22968d..56bf4cc9e20 100644 --- a/code/datums/components/omen.dm +++ b/code/datums/components/omen.dm @@ -88,13 +88,6 @@ INVOKE_ASYNC(src, PROC_REF(slam_airlock), darth_airlock) return - if(istype(our_guy_pos, /turf/open/floor/noslip/tram_plate/energized)) - var/turf/open/floor/noslip/tram_plate/energized/future_tram_victim = our_guy_pos - if(future_tram_victim.toast(living_guy)) - if(!permanent) - qdel(src) - 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 diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm index 4c50950ba91..1aba12fe6e2 100644 --- a/code/game/machinery/doors/airlock.dm +++ b/code/game/machinery/doors/airlock.dm @@ -54,14 +54,8 @@ // "Would this be better with a global var" // Wires for the airlock are located in the datum folder, inside the wires datum folder. - -#define AIRLOCK_CLOSED 1 -#define AIRLOCK_CLOSING 2 -#define AIRLOCK_OPEN 3 -#define AIRLOCK_OPENING 4 -#define AIRLOCK_DENY 5 -#define AIRLOCK_EMAG 6 - +// SKYRAT EDIT REMOVAL START - moved to code/__DEFINES/~skyrat_defines/airlock.dm +/* #define AIRLOCK_FRAME_CLOSED "closed" #define AIRLOCK_FRAME_CLOSING "closing" #define AIRLOCK_FRAME_OPEN "open" @@ -87,6 +81,8 @@ #define DOOR_CLOSE_WAIT 60 /// Time before a door closes, if not overridden #define DOOR_VISION_DISTANCE 11 ///The maximum distance a door will see out to +*/ +// SKYRAT EDIT REMOVAL END - moved to code/__DEFINES/~skyrat_defines/airlock.dm /obj/machinery/door/airlock name = "Airlock" @@ -1329,9 +1325,6 @@ if(multi_tile) filler.density = TRUE flags_1 |= PREVENT_CLICK_UNDER_1 - //SKYRAT EDIT ADDITION BEGIN - LARGE_DOOR - if(multi_tile) - filler.density = TRUE air_update_turf(TRUE, TRUE) sleep(0.1 SECONDS) if(!air_tight) @@ -1339,10 +1332,6 @@ if(multi_tile) filler.density = TRUE flags_1 |= PREVENT_CLICK_UNDER_1 - //SKYRAT EDIT ADDITION BEGIN - LARGE_DOOR - if(multi_tile) - filler.density = TRUE - //SKYRAT EDIT END air_update_turf(TRUE, TRUE) sleep(0.4 SECONDS) if(dangerous_close) @@ -2493,15 +2482,8 @@ set_density(TRUE) operating = FALSE return TRUE - - -#undef AIRLOCK_CLOSED -#undef AIRLOCK_CLOSING -#undef AIRLOCK_OPEN -#undef AIRLOCK_OPENING -#undef AIRLOCK_DENY -#undef AIRLOCK_EMAG - +// SKYRAT EDIT REMOVAL START - moved to code/__DEFINES/~skyrat_defines/airlock.dm +/* #undef AIRLOCK_SECURITY_NONE #undef AIRLOCK_SECURITY_IRON #undef AIRLOCK_SECURITY_PLASTEEL_I_S @@ -2526,3 +2508,5 @@ #undef AIRLOCK_FRAME_CLOSING #undef AIRLOCK_FRAME_OPEN #undef AIRLOCK_FRAME_OPENING +*/ +// SKYRAT EDIT REMOVAL END - moved to code/__DEFINES/~skyrat_defines/airlock.dm diff --git a/code/game/machinery/doors/door.dm b/code/game/machinery/doors/door.dm index 78223b813b3..8d53b0e8727 100644 --- a/code/game/machinery/doors/door.dm +++ b/code/game/machinery/doors/door.dm @@ -1,4 +1,4 @@ -#define DOOR_CLOSE_WAIT 60 ///Default wait until doors autoclose +// #define DOOR_CLOSE_WAIT 60 ///Default wait until doors autoclose // SKYRAT EDIT REMOVAL - moved to code/__DEFINES/~skyrat_defines/airlock.dm /obj/machinery/door name = "door" desc = "It opens and closes." @@ -55,7 +55,7 @@ /// Current elevator status for processing var/elevator_status /// What specific lift ID do we link with? - var/elevator_linked_id + var/transport_linked_id /datum/armor/machinery_door melee = 30 @@ -78,7 +78,7 @@ air_update_turf(TRUE, TRUE) register_context() if(elevator_mode) - if(elevator_linked_id) + if(transport_linked_id) elevator_status = LIFT_PLATFORM_LOCKED GLOB.elevator_doors += src else @@ -600,4 +600,4 @@ return ..() return ..(0) -#undef DOOR_CLOSE_WAIT +// #undef DOOR_CLOSE_WAIT // SKYRAT EDIT REMOVAL - moved to code/__DEFINES/~skyrat_defines/airlock.dm diff --git a/code/game/machinery/incident_display.dm b/code/game/machinery/incident_display.dm index 5ec7c50ecfd..97557c5611c 100644 --- a/code/game/machinery/incident_display.dm +++ b/code/game/machinery/incident_display.dm @@ -84,8 +84,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/incident_display/tram, 32) . = ..() GLOB.map_delamination_counters += src update_delam_count(SSpersistence.rounds_since_engine_exploded, SSpersistence.delam_highscore) - for(var/obj/structure/industrial_lift/tram/tram as anything in GLOB.lifts) - RegisterSignal(tram, COMSIG_TRAM_COLLISION, PROC_REF(update_tram_count)) + RegisterSignal(SStransport, COMSIG_TRAM_COLLISION, PROC_REF(update_tram_count)) update_appearance() @@ -190,22 +189,19 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/incident_display/tram, 32) . = ..() if(machine_stat & NOPOWER) icon_state = "stat_display_blank" - set_light(0) + set_light(l_on = FALSE) return if(machine_stat & BROKEN) icon_state = "stat_display_broken" - set_light(l_range = 1.7, l_power = 1.5, l_color = LIGHT_COLOR_DARK_BLUE) - return - - if(sign_features == (DISPLAY_DELAM + DISPLAY_TRAM)) + else if(sign_features == (DISPLAY_DELAM + DISPLAY_TRAM)) icon_state = "stat_display_dual" else if(sign_features == DISPLAY_DELAM) icon_state = "stat_display_delam" else if(sign_features == DISPLAY_TRAM) icon_state = "stat_display_tram" - set_light(l_range = 1.7, l_power = 1.5, l_color = LIGHT_COLOR_FAINT_BLUE) + set_light(l_range = 1.7, l_power = 1.5, l_color = LIGHT_COLOR_FAINT_CYAN, l_on = TRUE) /obj/machinery/incident_display/update_overlays() . = ..() @@ -220,9 +216,9 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/incident_display/tram, 32) var/delam_display_color . += delam_base_emissive if(!last_delam) - delam_display_color = LIGHT_COLOR_INTENSE_RED + delam_display_color = COLOR_DISPLAY_RED else - delam_display_color = LIGHT_COLOR_HOLY_MAGIC + delam_display_color = COLOR_DISPLAY_YELLOW var/delam_pos1 = last_delam % 10 var/mutable_appearance/delam_pos1_overlay = mutable_appearance(icon, "num_[delam_pos1]") @@ -255,7 +251,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/incident_display/tram, 32) if(last_delam == delam_record) var/mutable_appearance/delam_trend_overlay = mutable_appearance(icon, TREND_RISING) var/mutable_appearance/delam_trend_emissive = emissive_appearance(icon, "[TREND_RISING]_e", src, alpha = src.alpha) - delam_trend_overlay.color = LIGHT_COLOR_VIVID_GREEN + delam_trend_overlay.color = COLOR_DISPLAY_GREEN delam_trend_overlay.pixel_w = 1 delam_trend_emissive.pixel_w = 1 delam_trend_overlay.pixel_z = 6 @@ -265,7 +261,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/incident_display/tram, 32) else var/mutable_appearance/delam_trend_overlay = mutable_appearance(icon, TREND_FALLING) var/mutable_appearance/delam_trend_emissive = emissive_appearance(icon, "[TREND_FALLING]_e", src, alpha = src.alpha) - delam_trend_overlay.color = LIGHT_COLOR_INTENSE_RED + delam_trend_overlay.color = COLOR_DISPLAY_RED delam_trend_overlay.pixel_w = 1 delam_trend_emissive.pixel_w = 1 delam_trend_overlay.pixel_z = 6 @@ -275,7 +271,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/incident_display/tram, 32) if(sign_features & DISPLAY_TRAM) var/mutable_appearance/tram_base_emissive = emissive_appearance(icon, "tram_base_emissive", src, alpha = src.alpha) - var/tram_display_color = LIGHT_COLOR_BABY_BLUE + var/tram_display_color = COLOR_DISPLAY_BLUE var/tram_pos1 = hit_count % 10 var/mutable_appearance/tram_pos1_overlay = mutable_appearance(icon, "num_[tram_pos1]") @@ -309,7 +305,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/incident_display/tram, 32) if(hit_count > SSpersistence.tram_hits_last_round) var/mutable_appearance/tram_trend_overlay = mutable_appearance(icon, TREND_RISING) var/mutable_appearance/tram_trend_emissive = emissive_appearance(icon, "[TREND_RISING]_e", src, alpha = src.alpha) - tram_trend_overlay.color = LIGHT_COLOR_INTENSE_RED + tram_trend_overlay.color = COLOR_DISPLAY_RED tram_trend_overlay.pixel_w = 1 tram_trend_emissive.pixel_w = 1 tram_trend_overlay.pixel_z = -4 @@ -319,7 +315,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/incident_display/tram, 32) else var/mutable_appearance/tram_trend_overlay = mutable_appearance(icon, TREND_FALLING) var/mutable_appearance/tram_trend_emissive = emissive_appearance(icon, "[TREND_FALLING]_e", src, alpha = src.alpha) - tram_trend_overlay.color = LIGHT_COLOR_VIVID_GREEN + tram_trend_overlay.color = COLOR_DISPLAY_GREEN tram_trend_overlay.pixel_w = 1 tram_trend_emissive.pixel_w = 1 tram_trend_overlay.pixel_z = -4 diff --git a/code/game/machinery/status_display.dm b/code/game/machinery/status_display.dm index 76c82dd39dd..3f905965495 100644 --- a/code/game/machinery/status_display.dm +++ b/code/game/machinery/status_display.dm @@ -30,9 +30,9 @@ var/message2 = "" /// Normal text color - var/text_color = "#09F" + var/text_color = COLOR_DISPLAY_BLUE /// Color for headers, eg. "- ETA -" - var/header_text_color = "#2CF" + var/header_text_color = COLOR_DISPLAY_PURPLE /obj/item/wallframe/status_display name = "status display frame" @@ -151,7 +151,7 @@ ) set_light(0) return - set_light(1.5, 0.7, LIGHT_COLOR_BLUE) // blue light + set_light(1.5, 0.7, LIGHT_COLOR_FAINT_CYAN) // blue light /obj/machinery/status_display/update_overlays(updates) . = ..() @@ -374,8 +374,8 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/status_display/evac, 32) /obj/machinery/status_display/supply name = "supply display" current_mode = SD_MESSAGE - text_color = "#F90" - header_text_color = "#FC2" + text_color = COLOR_DISPLAY_ORANGE + header_text_color = COLOR_DISPLAY_YELLOW /obj/machinery/status_display/supply/process() if(machine_stat & NOPOWER) @@ -409,8 +409,8 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/status_display/evac, 32) current_mode = SD_MESSAGE var/shuttle_id - text_color = "#0F5" - header_text_color = "#2FC" + text_color = COLOR_DISPLAY_GREEN + header_text_color = COLOR_DISPLAY_CYAN /obj/machinery/status_display/shuttle/process() if(!shuttle_id || (machine_stat & NOPOWER)) diff --git a/code/game/objects/items/circuitboards/computer_circuitboards.dm b/code/game/objects/items/circuitboards/computer_circuitboards.dm index 79efe62a225..2eca8339590 100644 --- a/code/game/objects/items/circuitboards/computer_circuitboards.dm +++ b/code/game/objects/items/circuitboards/computer_circuitboards.dm @@ -331,6 +331,20 @@ /obj/item/circuitboard/computer/tram_controls name = "Tram Controls" build_path = /obj/machinery/computer/tram_controls + var/split_mode = FALSE + +/obj/item/circuitboard/computer/tram_controls/split + split_mode = TRUE + +/obj/item/circuitboard/computer/tram_controls/examine(mob/user) + . = ..() + . += span_info("The board is configured for [split_mode ? "split window" : "normal window"].") + . += span_notice("The board mode can be changed with a [EXAMINE_HINT("multitool")].") + +/obj/item/circuitboard/computer/tram_controls/multitool_act(mob/living/user) + split_mode = !split_mode + to_chat(user, span_notice("[src] positioning set to [split_mode ? "split window" : "normal window"].")) + return TRUE /obj/item/circuitboard/computer/terminal name = "Terminal" diff --git a/code/game/objects/items/circuitboards/machines/machine_circuitboards.dm b/code/game/objects/items/circuitboards/machines/machine_circuitboards.dm index f41cb62c9de..2fd3714342c 100644 --- a/code/game/objects/items/circuitboards/machines/machine_circuitboards.dm +++ b/code/game/objects/items/circuitboards/machines/machine_circuitboards.dm @@ -1387,6 +1387,21 @@ /datum/stock_part/scanning_module = 1, /datum/stock_part/card_reader = 1) +//Tram +/obj/item/circuitboard/machine/crossing_signal + name = "Crossing Signal" + build_path = /obj/machinery/transport/crossing_signal + req_components = list( + /datum/stock_part/micro_laser = 1, + ) + +/obj/item/circuitboard/machine/guideway_sensor + name = "Guideway Sensor" + build_path = /obj/machinery/transport/guideway_sensor + req_components = list( + /obj/item/assembly/prox_sensor = 1, + ) + //Misc /obj/item/circuitboard/machine/sheetifier name = "Sheet-meister 2000" diff --git a/code/game/objects/items/emags.dm b/code/game/objects/items/emags.dm index 25ad7321bd8..58e0ad881a4 100644 --- a/code/game/objects/items/emags.dm +++ b/code/game/objects/items/emags.dm @@ -58,7 +58,7 @@ /obj/item/card/emag/Initialize(mapload) . = ..() - type_blacklist = list(typesof(/obj/machinery/door/airlock) + typesof(/obj/machinery/door/window/) + typesof(/obj/machinery/door/firedoor) - typesof(/obj/machinery/door/window/tram/)) //list of all typepaths that require a specialized emag to hack. + type_blacklist = list(typesof(/obj/machinery/door/airlock) + typesof(/obj/machinery/door/window/) + typesof(/obj/machinery/door/firedoor) - typesof(/obj/machinery/door/airlock/tram)) //list of all typepaths that require a specialized emag to hack. /obj/item/card/emag/attack() return diff --git a/code/game/objects/items/stacks/sheets/mineral.dm b/code/game/objects/items/stacks/sheets/mineral.dm index 3ad762153e2..a28247ea471 100644 --- a/code/game/objects/items/stacks/sheets/mineral.dm +++ b/code/game/objects/items/stacks/sheets/mineral.dm @@ -305,8 +305,8 @@ GLOBAL_LIST_INIT(bananium_recipes, list ( \ walltype = /turf/closed/wall/mineral/titanium GLOBAL_LIST_INIT(titanium_recipes, list ( \ - new/datum/stack_recipe("titanium tile", /obj/item/stack/tile/mineral/titanium, 1, 4, 20, check_density = FALSE, category = CAT_TILES), \ - new/datum/stack_recipe("shuttle seat", /obj/structure/chair/comfy/shuttle, 2, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \ + new/datum/stack_recipe("Titanium tile", /obj/item/stack/tile/mineral/titanium, 1, 4, 20, check_density = FALSE, category = CAT_TILES), \ + new/datum/stack_recipe("Shuttle seat", /obj/structure/chair/comfy/shuttle, 2, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \ )) /obj/item/stack/sheet/mineral/titanium/get_main_recipes() diff --git a/code/game/objects/items/stacks/sheets/sheet_types.dm b/code/game/objects/items/stacks/sheets/sheet_types.dm index e9da67e9cc2..182666862eb 100644 --- a/code/game/objects/items/stacks/sheets/sheet_types.dm +++ b/code/game/objects/items/stacks/sheets/sheet_types.dm @@ -78,9 +78,8 @@ GLOBAL_LIST_INIT(metal_recipes, list ( \ new/datum/stack_recipe("floor tile", /obj/item/stack/tile/iron/base, 1, 4, 20, category = CAT_TILES), \ new/datum/stack_recipe("iron rod", /obj/item/stack/rods, 1, 2, 60, category = CAT_MISC), \ null, \ - new/datum/stack_recipe("wall girders (anchored)", /obj/structure/girder, 2, time = 4 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, trait_booster = TRAIT_QUICK_BUILD, trait_modifier = 0.75, category = CAT_STRUCTURE), \ + new/datum/stack_recipe("wall girders (anchored)", /obj/structure/girder, 2, time = 4 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, placement_checks = STACK_CHECK_TRAM_FORBIDDEN, trait_booster = TRAIT_QUICK_BUILD, trait_modifier = 0.75, category = CAT_STRUCTURE), \ null, \ - new/datum/stack_recipe("tram wall girders (anchored)", /obj/structure/girder/tram, 2, time = 4 SECONDS, one_per_turf = TRUE, on_solid_ground = FALSE, check_density = FALSE, on_tram = TRUE, trait_booster = TRAIT_QUICK_BUILD, trait_modifier = 0.75, category = CAT_STRUCTURE), \ null, \ new/datum/stack_recipe("computer frame", /obj/structure/frame/computer, 5, time = 2.5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_EQUIPMENT), \ new/datum/stack_recipe("modular console", /obj/machinery/modular_computer, 10, time = 2.5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_EQUIPMENT), \ @@ -762,7 +761,8 @@ GLOBAL_LIST_INIT(bronze_recipes, list ( \ material_type = /datum/material/bone GLOBAL_LIST_INIT(plastic_recipes, list( - new /datum/stack_recipe("plastic floor tile", /obj/item/stack/tile/plastic, 1, 4, 20, check_density = FALSE, category = CAT_TILES), \ + new /datum/stack_recipe("plastic floor tile", /obj/item/stack/tile/plastic, 1, 4, time = 2 SECONDS, check_density = FALSE, category = CAT_TILES), \ + new /datum/stack_recipe("thermoplastic tram tile", /obj/item/stack/thermoplastic, 1, 2, time = 4 SECONDS, check_density = FALSE, placement_checks = STACK_CHECK_TRAM_EXCLUSIVE, category = CAT_TILES), \ new /datum/stack_recipe("folding plastic chair", /obj/structure/chair/plastic, 2, check_density = FALSE, category = CAT_FURNITURE), \ new /datum/stack_recipe("plastic flaps", /obj/structure/plasticflaps, 5, one_per_turf = TRUE, on_solid_ground = TRUE, time = 4 SECONDS, category = CAT_FURNITURE), \ new /datum/stack_recipe("water bottle", /obj/item/reagent_containers/cup/glass/waterbottle/empty, check_density = FALSE, category = CAT_CONTAINERS), \ diff --git a/code/game/objects/items/stacks/stack.dm b/code/game/objects/items/stacks/stack.dm index 7050309268c..7f789eaa514 100644 --- a/code/game/objects/items/stacks/stack.dm +++ b/code/game/objects/items/stacks/stack.dm @@ -493,19 +493,15 @@ builder.balloon_alert(builder, "won't fit here!") return FALSE - if(recipe.on_tram) - if(!locate(/obj/structure/industrial_lift/tram) in dest_turf) - builder.balloon_alert(builder, "must be made on a tram!") - return FALSE - if(recipe.on_solid_ground) if(isclosedturf(dest_turf)) builder.balloon_alert(builder, "cannot be made on a wall!") return FALSE if(is_type_in_typecache(dest_turf, GLOB.turfs_without_ground)) - builder.balloon_alert(builder, "must be made on solid ground!") - return FALSE + if(!locate(/obj/structure/thermoplastic) in dest_turf) // for tram construction + builder.balloon_alert(builder, "must be made on solid ground!") + return FALSE if(recipe.check_density) for(var/obj/object in dest_turf) @@ -527,6 +523,16 @@ builder.balloon_alert(builder, "can't be near another!") return FALSE + if(recipe.placement_checks & STACK_CHECK_TRAM_FORBIDDEN) + if(locate(/obj/structure/transport/linear/tram) in dest_turf || locate(/obj/structure/thermoplastic) in dest_turf) + builder.balloon_alert(builder, "can't be on tram!") + return FALSE + + if(recipe.placement_checks & STACK_CHECK_TRAM_EXCLUSIVE) + if(!locate(/obj/structure/transport/linear/tram) in dest_turf) + builder.balloon_alert(builder, "must be made on a tram!") + return FALSE + return TRUE /obj/item/stack/use(used, transfer = FALSE, check = TRUE) // return 0 = borked; return 1 = had enough diff --git a/code/game/objects/items/stacks/stack_recipe.dm b/code/game/objects/items/stacks/stack_recipe.dm index a065a4916b3..bfdc3c8ca57 100644 --- a/code/game/objects/items/stacks/stack_recipe.dm +++ b/code/game/objects/items/stacks/stack_recipe.dm @@ -24,11 +24,9 @@ var/check_direction = FALSE /// If the atom requires a floor below var/on_solid_ground = FALSE - /// If the atom requires a tram floor below - var/on_tram = FALSE /// If the atom checks that there are objects with density in the same turf when being built. TRUE by default var/check_density = TRUE - /// Bitflag of additional placement checks required to place. (STACK_CHECK_CARDINALS|STACK_CHECK_ADJACENT) + /// Bitflag of additional placement checks required to place. (STACK_CHECK_CARDINALS|STACK_CHECK_ADJACENT|STACK_CHECK_TRAM_FORBIDDEN|STACK_CHECK_TRAM_EXCLUSIVE) var/placement_checks = NONE /// If TRUE, the created atom will gain custom mat datums var/applies_mats = FALSE @@ -48,7 +46,6 @@ time = 0, one_per_turf = FALSE, on_solid_ground = FALSE, - on_tram = FALSE, is_fulltile = FALSE, check_direction = FALSE, check_density = TRUE, @@ -67,7 +64,6 @@ src.time = time src.one_per_turf = one_per_turf src.on_solid_ground = on_solid_ground - src.on_tram = on_tram src.is_fulltile = is_fulltile src.check_direction = check_direction || is_fulltile src.check_density = check_density @@ -90,7 +86,6 @@ time = 0, one_per_turf = FALSE, on_solid_ground = FALSE, - on_tram = FALSE, window_checks = FALSE, placement_checks = NONE, applies_mats = FALSE, diff --git a/code/game/objects/items/stacks/tiles/tile_types.dm b/code/game/objects/items/stacks/tiles/tile_types.dm index d15396e0bb5..ef19367d42a 100644 --- a/code/game/objects/items/stacks/tiles/tile_types.dm +++ b/code/game/objects/items/stacks/tiles/tile_types.dm @@ -48,21 +48,21 @@ if(tile_reskin_types || tile_rotate_dirs) . += span_notice("Use while in your hand to change what type of [src] you want.") if(throwforce && !is_cyborg) //do not want to divide by zero or show the message to borgs who can't throw - var/verb + var/damage_value switch(CEILING(MAX_LIVING_HEALTH / throwforce, 1)) //throws to crit a human if(1 to 3) - verb = "superb" + damage_value = "superb" if(4 to 6) - verb = "great" + damage_value = "great" if(7 to 9) - verb = "good" + damage_value = "good" if(10 to 12) - verb = "fairly decent" + damage_value = "fairly decent" if(13 to 15) - verb = "mediocre" - if(!verb) + damage_value = "mediocre" + if(!damage_value) return - . += span_notice("Those could work as a [verb] throwing weapon.") + . += span_notice("Those could work as a [damage_value] throwing weapon.") /** * Place our tile on a plating, or replace it. @@ -1035,23 +1035,23 @@ turf_type = /turf/open/floor/noslip/tram merge_type = /obj/item/stack/tile/noslip/tram -/obj/item/stack/tile/noslip/tram_platform +/obj/item/stack/tile/tram name = "tram platform tiles" singular_name = "tram platform" desc = "A tile used for tram platforms." icon_state = "darkiron_catwalk" inhand_icon_state = "tile-neon" - turf_type = /turf/open/floor/noslip/tram_platform - merge_type = /obj/item/stack/tile/noslip/tram_platform + turf_type = /turf/open/floor/tram + merge_type = /obj/item/stack/tile/tram -/obj/item/stack/tile/noslip/tram_plate - name = "high-traction platform tile" - singular_name = "high-traction platform tile" - desc = "A high-traction tile used for tram platforms." +/obj/item/stack/tile/tram/plate + name = "linear induction tram tiles" + singular_name = "linear induction tram tile tile" + desc = "A tile with an aluminium plate for tram propulsion." icon_state = "darkiron_plate" inhand_icon_state = "tile-neon" - turf_type = /turf/open/floor/noslip/tram_plate - merge_type = /obj/item/stack/tile/noslip/tram_plate + turf_type = /turf/open/floor/tram/plate + merge_type = /obj/item/stack/tile/tram/plate //Circuit /obj/item/stack/tile/circuit diff --git a/code/game/objects/structures/fluff.dm b/code/game/objects/structures/fluff.dm index 15298367bc0..57207cf7aba 100644 --- a/code/game/objects/structures/fluff.dm +++ b/code/game/objects/structures/fluff.dm @@ -269,22 +269,35 @@ /obj/structure/fluff/tram_rail name = "tram rail" desc = "Great for trams, not so great for skating." - icon = 'icons/obj/fluff/tram_rails.dmi' + icon = 'icons/obj/tram/tram_rails.dmi' icon_state = "rail" layer = TRAM_RAIL_LAYER plane = FLOOR_PLANE - deconstructible = TRUE + resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF + deconstructible = FALSE /obj/structure/fluff/tram_rail/floor + name = "tram rail protective cover" icon_state = "rail_floor" /obj/structure/fluff/tram_rail/end icon_state = "railend" +/obj/structure/fluff/tram_rail/electric + desc = "Great for trams, not so great for skating. This one is a power rail." + /obj/structure/fluff/tram_rail/anchor name = "tram rail anchor" icon_state = "anchor" +/obj/structure/fluff/tram_rail/electric/anchor + name = "tram rail anchor" + icon_state = "anchor" + +/obj/structure/fluff/tram_rail/electric/attack_hand(mob/living/user, list/modifiers) + if(user.electrocute_act(75, src)) + do_sparks(5, TRUE, src) + /obj/structure/fluff/broken_canister_frame name = "broken canister frame" desc = "A torn apart canister. It looks like some metal can be salvaged with a wrench." diff --git a/code/game/objects/structures/girders.dm b/code/game/objects/structures/girders.dm index 42246e8fcfa..63a040d6dfe 100644 --- a/code/game/objects/structures/girders.dm +++ b/code/game/objects/structures/girders.dm @@ -17,6 +17,7 @@ /obj/item/stack/sheet/plasteel = 2, /obj/item/stack/sheet/bronze = 2, /obj/item/stack/sheet/runed_metal = 1, + /obj/item/stack/sheet/titaniumglass = 2, exotic_material = 2 // this needs to be refactored properly ) @@ -49,9 +50,14 @@ if(istype(W, /obj/item/gun/energy/plasmacutter)) balloon_alert(user, "slicing apart...") if(W.use_tool(src, user, 40, volume=100)) - var/obj/item/stack/sheet/iron/M = new (loc, 2) - if (!QDELETED(M)) - M.add_fingerprint(user) + if(state == GIRDER_TRAM) + var/obj/item/stack/sheet/mineral/titanium/M = new (user.loc, 2) + if(!QDELETED(M)) + M.add_fingerprint(user) + else + var/obj/item/stack/sheet/iron/M = new (loc, 2) + if(!QDELETED(M)) + M.add_fingerprint(user) qdel(src) return @@ -63,7 +69,7 @@ balloon_alert(user, "need floor!") return if(state == GIRDER_TRAM) - if(!locate(/obj/structure/industrial_lift/tram) in src.loc.contents) + if(!locate(/obj/structure/transport/linear/tram) in src.loc.contents) balloon_alert(user, "need tram floors!") return @@ -128,8 +134,8 @@ if (do_after(user, 4 SECONDS, target = src)) if(sheets.get_amount() < amount) return - sheets.use(2) - var/obj/structure/tramwall/tram_wall = new(loc) + sheets.use(amount) + var/obj/structure/tram/alt/iron/tram_wall = new(loc) transfer_fingerprints_to(tram_wall) qdel(src) return @@ -148,6 +154,21 @@ qdel(src) return + if(istype(sheets, /obj/item/stack/sheet/titaniumglass) && state == GIRDER_TRAM) + var/amount = construction_cost[/obj/item/stack/sheet/titaniumglass] + if(sheets.get_amount() < amount) + balloon_alert(user, "need [amount] sheets!") + return + balloon_alert(user, "adding panel...") + if (do_after(user, 2 SECONDS, target = src)) + if(sheets.get_amount() < amount) + return + sheets.use(amount) + var/obj/structure/tram/tram_wall = new(loc) + transfer_fingerprints_to(tram_wall) + qdel(src) + return + if(istype(sheets, /obj/item/stack/sheet/plasteel)) var/amount = construction_cost[/obj/item/stack/sheet/plasteel] if(state == GIRDER_DISPLACED) @@ -201,22 +222,17 @@ if(sheets.get_amount() < amount) balloon_alert(user, "need [amount] sheets!") return + var/tram_wall_type = text2path("/obj/structure/tram/alt/[M]") + if(!tram_wall_type) + balloon_alert(user, "need titanium glass or mineral!") + return balloon_alert(user, "adding plating...") if (do_after(user, 4 SECONDS, target = src)) if(sheets.get_amount() < amount) return + var/obj/structure/tram/tram_wall + tram_wall = new tram_wall_type(loc) sheets.use(amount) - var/obj/structure/tramwall/tram_wall - var/tram_wall_type = text2path("/obj/structure/tramwall/[M]") - if(tram_wall_type) - tram_wall = new tram_wall_type(loc) - else - var/obj/structure/tramwall/material/mat_tram_wall = new(loc) - var/list/material_list = list() - material_list[GET_MATERIAL_REF(sheets.material_type)] = SHEET_MATERIAL_AMOUNT * 2 - if(material_list) - mat_tram_wall.set_custom_materials(material_list) - tram_wall = mat_tram_wall transfer_fingerprints_to(tram_wall) qdel(src) return @@ -289,9 +305,9 @@ if(state != GIRDER_TRAM) return state = GIRDER_DISASSEMBLED - var/obj/item/stack/sheet/iron/M = new (loc, 2) - if (!QDELETED(M)) - M.add_fingerprint(user) + var/obj/item/stack/sheet/mineral/titanium/material = new (user.loc, 2) + if (!QDELETED(material)) + material.add_fingerprint(user) qdel(src) return TRUE @@ -391,8 +407,15 @@ max_integrity = 350 /obj/structure/girder/tram - name = "tram girder" + name = "tram frame" + desc = "Titanium framework to construct tram walls. Can be plated with titanium glass or other wall materials." + icon_state = "tram" state = GIRDER_TRAM + density = FALSE + obj_flags = CAN_BE_HIT | BLOCK_Z_OUT_DOWN + +/obj/structure/girder/tram/corner + name = "tram frame corner" //////////////////////////////////////////// cult girder ////////////////////////////////////////////// diff --git a/code/game/objects/structures/plaques/static_plaques.dm b/code/game/objects/structures/plaques/static_plaques.dm index c37ddc4ff67..06538ea2ef1 100644 --- a/code/game/objects/structures/plaques/static_plaques.dm +++ b/code/game/objects/structures/plaques/static_plaques.dm @@ -19,6 +19,84 @@ /obj/structure/plaque/static_plaque/golden/captain name = "The Most Robust Captain Award for Robustness" +/obj/structure/plaque/static_plaque/tram + /// The tram we have info about + var/specific_transport_id = TRAMSTATION_LINE_1 + /// Weakref to the tram we have info about + var/datum/weakref/transport_ref + /// Serial number of the tram + var/tram_serial + name = "\improper tram information plate" + icon_state = "commission_tram" + custom_materials = list(/datum/material/titanium = SHEET_MATERIAL_AMOUNT) + layer = SIGN_LAYER + +/obj/structure/plaque/static_plaque/tram/Initialize(mapload) + . = ..() + return INITIALIZE_HINT_LATELOAD + +/obj/structure/plaque/static_plaque/tram/LateInitialize(mapload) + . = ..() + link_tram() + set_tram_serial() + +/obj/structure/plaque/static_plaque/tram/add_context(atom/source, list/context, obj/item/held_item, mob/user) + . = ..() + if(isnull(held_item)) + context[SCREENTIP_CONTEXT_LMB] = "View details" + return CONTEXTUAL_SCREENTIP_SET + +/obj/structure/plaque/static_plaque/tram/proc/link_tram() + for(var/datum/transport_controller/linear/tram/tram as anything in SStransport.transports_by_type[TRANSPORT_TYPE_TRAM]) + if(tram.specific_transport_id == specific_transport_id) + transport_ref = WEAKREF(tram) + break + +/obj/structure/plaque/static_plaque/tram/proc/set_tram_serial() + var/datum/transport_controller/linear/tram/tram = transport_ref?.resolve() + if(isnull(tram) || isnull(tram.tram_registration)) + return + + tram_serial = tram.tram_registration.serial_number + desc = "A plate showing details from the manufacturer about this Nakamura Engineering SkyyTram Mk VI, serial number [tram_serial].

We are not responsible for any injuries or fatalities caused by usage of the tram. \ + Using the tram carries inherent risks, and we cannot guarantee the safety of all passengers. By using the tram, you assume, acknowledge, and accept all the risks and responsibilities.

\ + Please be aware that riding the tram can cause a variety of injuries, including but not limited to: slips, trips, and falls; collisions with other passengers or objects; strains, sprains, and other musculoskeletal injuries; \ + cuts, bruises, and lacerations; and more severe injuries such as head trauma, spinal cord injuries, and even death. These injuries can be caused by a variety of factors, including the movements of the tram, the behaviour \ + of other passengers, and unforeseen circumstances such as foul play or mechanical issues.

\ + By entering the tram, guideway, or crossings you agree Nanotrasen is not liable for any injuries, damages, or losses that may occur. If you do not agree to these terms, please do not use the tram.
" + +/obj/structure/plaque/static_plaque/tram/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "TramPlaque") + ui.autoupdate = FALSE + ui.open() + +/obj/structure/plaque/static_plaque/tram/ui_static_data(mob/user) + var/datum/transport_controller/linear/tram/tram = transport_ref?.resolve() + var/list/data = list() + var/list/current_tram = list() + var/list/previous_trams = list() + + current_tram += list(list( + "serialNumber" = tram.tram_registration.serial_number, + "mfgDate" = tram.tram_registration.mfg_date, + "distanceTravelled" = tram.tram_registration.distance_travelled, + "tramCollisions" = tram.tram_registration.collisions, + )) + + for(var/datum/tram_mfg_info/previous_tram as anything in tram.tram_history) + previous_trams += list(list( + "serialNumber" = previous_tram.serial_number, + "mfgDate" = previous_tram.mfg_date, + "distanceTravelled" = previous_tram.distance_travelled, + "tramCollisions" = previous_tram.collisions, + )) + + data["currentTram"] = current_tram + data["previousTrams"] = previous_trams + return data + // Commission plaques, to give a little backstory to the stations. Commission dates are date of merge (or best approximation, in the case of Meta) + 540 years to convert to SS13 dates. // Where PRs are available, I've linked them. Where they are unavailable, a git hash is provided instead for the direct commit that added/removed the map. // Please enjoy this trip through SS13's history. @@ -149,15 +227,3 @@ /obj/structure/sign/plaques/kiddie/gameoflife name = "\improper Conway's The Game Of Life plaque" desc = "A plaque detailing the historical significance of The Game Of Life in the field of computer science, and that the mural underfoot is a representation of the game in action." - -/obj/structure/sign/plaques/tram - name = "\improper tram information plate" - desc = "A plate showing details from the manufacturer about this Nakamura Engineering SkyyTram Mk IV, serial number LT304TG2563.

We are not responsible for any injuries or fatalities caused by usage of the tram. \ - Using the tram carries inherent risks, and we cannot guarantee the safety of all passengers. By using the tram, you assume, acknowledge, and accept all the risks and responsibilities.

\ - Please be aware that riding the tram can cause a variety of injuries, including but not limited to: slips, trips, and falls; collisions with other passengers or objects; strains, sprains, and other musculoskeletal injuries; \ - cuts, bruises, and lacerations; and more severe injuries such as head trauma, spinal cord injuries, and even death. These injuries can be caused by a variety of factors, including the movements of the tram, the behaviour \ - of other passengers, and unforeseen circumstances such as foul play or mechanical issues.

\ - By entering the tram, guideway, or crossings you agree Nanotrasen is not liable for any injuries, damages, or losses that may occur. If you do not agree to these terms, please do not use the tram.
" - icon_state = "commission_tram" - custom_materials = list(/datum/material/titanium =SHEET_MATERIAL_AMOUNT) - plane = FLOOR_PLANE diff --git a/code/game/turfs/open/_open.dm b/code/game/turfs/open/_open.dm index 24c4c4914ec..7abd965e4e0 100644 --- a/code/game/turfs/open/_open.dm +++ b/code/game/turfs/open/_open.dm @@ -399,3 +399,31 @@ if(istype(get_step(src, direction), /turf/open/floor)) return TRUE return FALSE + +/// Very similar to build_with_rods, this exists to allow consistent behavior between different types in terms of how +/// Building floors works +/turf/open/proc/build_with_transport_tiles(obj/item/stack/thermoplastic/used_tiles, user) + var/obj/structure/transport/linear/platform = locate(/obj/structure/transport/linear, src) + if(!platform) + balloon_alert(user, "no tram base!") + return + if(!used_tiles.use(1)) + balloon_alert(user, "no tile!") + return + + playsound(src, 'sound/weapons/genhit.ogg', 50, TRUE) + new used_tiles.tile_type(src) + +/// Very similar to build_with_rods, this exists to allow building transport/tram girders on openspace +/turf/open/proc/build_with_titanium(obj/item/stack/sheet/mineral/titanium/used_stack, user) + var/obj/structure/transport/linear/platform = locate(/obj/structure/transport/linear, src) + if(!platform) + to_chat(user, span_warning("There is no transport frame to attach the anchor!")) + return + if(!used_stack.use(2)) + balloon_alert(user, "not enough titanium!") + return + + playsound(src, 'sound/weapons/genhit.ogg', 50, TRUE) + new /obj/structure/girder/tram(src) + diff --git a/code/game/turfs/open/openspace.dm b/code/game/turfs/open/openspace.dm index 77a2259763a..309bda83c0e 100644 --- a/code/game/turfs/open/openspace.dm +++ b/code/game/turfs/open/openspace.dm @@ -122,6 +122,10 @@ build_with_rods(C, user) else if(istype(C, /obj/item/stack/tile/iron)) build_with_floor_tiles(C, user) + else if(istype(C, /obj/item/stack/thermoplastic)) + build_with_transport_tiles(C, user) + else if(istype(C, /obj/item/stack/sheet/mineral/titanium)) + build_with_titanium(C, user) /turf/open/openspace/build_with_floor_tiles(obj/item/stack/tile/iron/used_tiles) if(!CanCoverUp()) diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm index b80516c6fe0..15297383a7b 100644 --- a/code/modules/admin/admin_verbs.dm +++ b/code/modules/admin/admin_verbs.dm @@ -51,6 +51,7 @@ GLOBAL_PROTECT(admin_verbs_admin) /datum/admins/proc/view_all_circuits, /datum/verbs/menu/Admin/verb/playerpanel, /* It isn't /datum/admin but it fits no less */ /datum/admins/proc/change_shuttle_events, //allows us to change the shuttle events + /datum/admins/proc/reset_tram, //tram related admin actions // Client procs /client/proc/admin_call_shuttle, /*allows us to call the emergency shuttle*/ /client/proc/admin_cancel_shuttle, /*allows us to cancel the emergency shuttle, sending it back to centcom*/ diff --git a/code/modules/antagonists/ninja/ninjaDrainAct.dm b/code/modules/antagonists/ninja/ninjaDrainAct.dm index 9230aaf913d..4d21ab89185 100644 --- a/code/modules/antagonists/ninja/ninjaDrainAct.dm +++ b/code/modules/antagonists/ninja/ninjaDrainAct.dm @@ -443,7 +443,7 @@ balloon_alert(ninja, "tram is already malfunctioning!") return COMPONENT_CANCEL_ATTACK_CHAIN - if(specific_lift_id != MAIN_STATION_TRAM) + if(specific_transport_id != TRAMSTATION_LINE_1) balloon_alert(ninja, "cannot hack this tram!") return COMPONENT_CANCEL_ATTACK_CHAIN @@ -454,7 +454,11 @@ force_event(/datum/round_event_control/tram_malfunction, "ninja interference") malfunction_event = locate(/datum/round_event/tram_malfunction) in SSevents.running - malfunction_event.end_when *= 3 + malfunction_event.end_when *= 2 + for(var/obj/machinery/transport/guideway_sensor/sensor as anything in SStransport.sensors) + // Since faults are now used instead of straight event end_when var, we make a few of them malfunction + if(prob(rand(15, 30))) + sensor.local_fault() return COMPONENT_CANCEL_ATTACK_CHAIN diff --git a/code/modules/assembly/doorcontrol.dm b/code/modules/assembly/doorcontrol.dm index 8ca5fd8b10e..f5f33afa83c 100644 --- a/code/modules/assembly/doorcontrol.dm +++ b/code/modules/assembly/doorcontrol.dm @@ -179,65 +179,3 @@ C.cremate(usr) addtimer(VARSET_CALLBACK(src, cooldown, FALSE), 50) - -/obj/item/assembly/control/tram - name = "tram call button" - desc = "A small device used to bring trams to you." - ///for finding the landmark initially - should be the exact same as the landmark's destination id. - var/initial_id - ///ID to link to allow us to link to one specific tram in the world - var/specific_lift_id = MAIN_STATION_TRAM - ///this is our destination's landmark, so we only have to find it the first time. - var/datum/weakref/destination_platform - -/obj/item/assembly/control/tram/Initialize(mapload) - ..() - return INITIALIZE_HINT_LATELOAD - -/obj/item/assembly/control/tram/LateInitialize() - . = ..() - //find where the tram needs to go to (our destination). only needs to happen the first time - for(var/obj/effect/landmark/tram/our_destination as anything in GLOB.tram_landmarks[specific_lift_id]) - if(our_destination.platform_code == initial_id) - destination_platform = WEAKREF(our_destination) - break - -/obj/item/assembly/control/tram/Destroy() - destination_platform = null - return ..() - -/obj/item/assembly/control/tram/activate() - if(cooldown) - return - cooldown = TRUE - addtimer(VARSET_CALLBACK(src, cooldown, FALSE), 2 SECONDS) - - var/datum/lift_master/tram/tram - for(var/datum/lift_master/tram/possible_match as anything in GLOB.active_lifts_by_type[TRAM_LIFT_ID]) - if(possible_match.specific_lift_id == specific_lift_id) - tram = possible_match - break - - if(!tram || !tram.is_operational) //tram is QDEL or has no power - say("The tram is not in service. Please send a technician to repair the internals of the tram.") - return - if(tram.travelling) //already on its way - say("The tram is already travelling to [tram.idle_platform].") - return - if(tram.controls_locked) //attempting a dispatch or on cooldown - say("The tram controller is busy. Try again in a moment.") - return - if(!destination_platform) - return - var/obj/effect/landmark/tram/current_location = destination_platform.resolve() - if(!current_location) - return - if(tram.idle_platform == current_location) //already here - say("The tram is already here. Please board the tram and select a destination.") - return - - if(tram.tram_travel(current_location)) - say("The tram has been called to [current_location.name]. Please wait for its arrival.") - return - else - say("The tram controller has encountered an error. Try again in a moment.") diff --git a/code/modules/events/immovable_rod/immovable_rod.dm b/code/modules/events/immovable_rod/immovable_rod.dm index 1280eb1faa7..a4cc4d4d683 100644 --- a/code/modules/events/immovable_rod/immovable_rod.dm +++ b/code/modules/events/immovable_rod/immovable_rod.dm @@ -185,7 +185,7 @@ // If we Bump into the tram front or back, push the tram. Otherwise smash the object as usual. if(isobj(clong)) if(istramwall(clong) && !special_target) - rod_vs_tram_battle(clong) + rod_vs_tram_battle() return ..() var/obj/clong_obj = clong @@ -301,17 +301,17 @@ * while flying parallel. */ /obj/effect/immovablerod/proc/rod_vs_tram_battle() - var/obj/structure/industrial_lift/tram/industrial_lift = locate() in src.loc + var/obj/structure/transport/linear/tram/transport_module = locate() in src.loc - if(isnull(industrial_lift)) + if(isnull(transport_module)) return - var/datum/lift_master/tram/lift_master = industrial_lift.lift_master_datum + var/datum/transport_controller/linear/tram/tram_controller = transport_module.transport_controller_datum - if(isnull(lift_master)) + if(isnull(tram_controller)) return - var/push_target = lift_master.rod_collision(src) + var/push_target = tram_controller.rod_collision(src) if(!push_target) return diff --git a/code/modules/events/tram_malfunction.dm b/code/modules/events/tram_malfunction.dm index b5130a8c693..26e0f2feefa 100644 --- a/code/modules/events/tram_malfunction.dm +++ b/code/modules/events/tram_malfunction.dm @@ -18,9 +18,9 @@ if (!.) return FALSE - for(var/tram_id in GLOB.active_lifts_by_type) - var/datum/lift_master/tram_ref = GLOB.active_lifts_by_type[tram_id][1] - if(tram_ref.specific_lift_id == MAIN_STATION_TRAM) + for(var/tram_id in SStransport.transports_by_type) + var/datum/transport_controller/linear/tram/tram_ref = SStransport.transports_by_type[tram_id][1] + if(tram_ref.specific_transport_id == TRAMSTATION_LINE_1) return . return FALSE @@ -28,43 +28,27 @@ /datum/round_event/tram_malfunction announce_when = 1 end_when = TRAM_MALFUNCTION_TIME_LOWER - var/specific_lift_id = MAIN_STATION_TRAM - var/original_lethality + /// The ID of the tram we're going to malfunction + var/specific_transport_id = TRAMSTATION_LINE_1 /datum/round_event/tram_malfunction/setup() end_when = rand(TRAM_MALFUNCTION_TIME_LOWER, TRAM_MALFUNCTION_TIME_UPPER) /datum/round_event/tram_malfunction/announce() - priority_announce("Our automated control system has lost contact with the tram's on board computer. Please take extra care while we diagnose and resolve the issue. Signals and emergency braking may not be available during this time.", "CentCom Engineering Division") + priority_announce("Our automated control system has lost contact with the tram's onboard computer. Please take extra care while engineers diagnose and resolve the issue.", "CentCom Engineering Division") /datum/round_event/tram_malfunction/start() - for(var/obj/machinery/crossing_signal/signal as anything in GLOB.tram_signals) - signal.start_malfunction() - - for(var/obj/machinery/door/window/tram/door as anything in GLOB.tram_doors) - door.start_malfunction() - - for(var/obj/machinery/destination_sign/sign as anything in GLOB.tram_signs) - sign.malfunctioning = TRUE - - for(var/obj/structure/industrial_lift/tram as anything in GLOB.lifts) - original_lethality = tram.collision_lethality - tram.collision_lethality = original_lethality * 1.25 + for(var/datum/transport_controller/linear/tram/malfunctioning_controller as anything in SStransport.transports_by_type[TRANSPORT_TYPE_TRAM]) + if(malfunctioning_controller.specific_transport_id == specific_transport_id) + malfunctioning_controller.start_malf_event() + return /datum/round_event/tram_malfunction/end() - for(var/obj/machinery/crossing_signal/signal as anything in GLOB.tram_signals) - signal.end_malfunction() - - for(var/obj/machinery/door/window/tram/door as anything in GLOB.tram_doors) - door.end_malfunction() - - for(var/obj/machinery/destination_sign/sign as anything in GLOB.tram_signs) - sign.malfunctioning = FALSE - - for(var/obj/structure/industrial_lift/tram as anything in GLOB.lifts) - tram.collision_lethality = original_lethality - - priority_announce("We've successfully reset the software on the tram, normal operations are now resuming. Sorry for any inconvienence this may have caused.", "CentCom Engineering Division") + for(var/datum/transport_controller/linear/tram/malfunctioning_controller as anything in SStransport.transports_by_type[TRANSPORT_TYPE_TRAM]) + if(malfunctioning_controller.specific_transport_id == specific_transport_id && malfunctioning_controller.controller_status & COMM_ERROR) + malfunctioning_controller.end_malf_event() + priority_announce("The software on the tram has been reset, normal operations are now resuming. Sorry for any inconvienence this may have caused.", "CentCom Engineering Division") + return #undef TRAM_MALFUNCTION_TIME_UPPER #undef TRAM_MALFUNCTION_TIME_LOWER diff --git a/code/modules/industrial_lift/lift_master.dm b/code/modules/industrial_lift/lift_master.dm deleted file mode 100644 index 207e8b7fd74..00000000000 --- a/code/modules/industrial_lift/lift_master.dm +++ /dev/null @@ -1,634 +0,0 @@ -///associative list of the form: list(lift_id = list(all lift_master datums attached to lifts of that type)) -GLOBAL_LIST_EMPTY(active_lifts_by_type) - -///coordinate and control movement across linked industrial_lift's. allows moving large single multitile platforms and many 1 tile platforms. -///also is capable of linking platforms across linked z levels -/datum/lift_master - ///the lift platforms we consider as part of this lift. ordered in order of lowest z level to highest z level after init. - ///(the sorting algorithm sucks btw) - var/list/obj/structure/industrial_lift/lift_platforms - - /// Typepath list of what to ignore smashing through, controls all lifts - var/static/list/ignored_smashthroughs = list( - /obj/machinery/power/supermatter_crystal, - /obj/structure/holosign, - /obj/machinery/field, - ) - - ///whether the lift handled by this lift_master datum is multitile as opposed to nxm platforms per z level - var/multitile_platform = FALSE - - ///taken from our lift platforms. if true we go through each z level of platforms and attempt to make the lowest left corner platform - ///into one giant multitile object the size of all other platforms on that z level. - var/create_multitile_platform = FALSE - - ///lift platforms have already been sorted in order of z level. - var/z_sorted = FALSE - - ///lift_id taken from our base lift platform, used to put us into GLOB.active_lifts_by_type - var/lift_id = BASIC_LIFT_ID - - ///overridable ID string to link control units to this specific lift_master datum. created by placing a lift id landmark object - ///somewhere on the tram, if its anywhere on the tram we'll find it in init and set this to whatever it specifies - var/specific_lift_id - - ///if true, the lift cannot be manually moved. - var/controls_locked = FALSE - -/datum/lift_master/New(obj/structure/industrial_lift/lift_platform) - lift_id = lift_platform.lift_id - create_multitile_platform = lift_platform.create_multitile_platform - - Rebuild_lift_plaform(lift_platform) - ignored_smashthroughs = typecacheof(ignored_smashthroughs) - - LAZYADDASSOCLIST(GLOB.active_lifts_by_type, lift_id, src) - - for(var/obj/structure/industrial_lift/lift as anything in lift_platforms) - lift.add_initial_contents() - -/datum/lift_master/Destroy() - for(var/obj/structure/industrial_lift/lift_platform as anything in lift_platforms) - lift_platform.lift_master_datum = null - lift_platforms = null - - LAZYREMOVEASSOC(GLOB.active_lifts_by_type, lift_id, src) - if(isnull(GLOB.active_lifts_by_type)) - GLOB.active_lifts_by_type = list()//im lazy - - return ..() - -/datum/lift_master/proc/add_lift_platforms(obj/structure/industrial_lift/new_lift_platform) - if(new_lift_platform in lift_platforms) - return - for(var/obj/structure/industrial_lift/other_platform in new_lift_platform.loc) - if(other_platform != new_lift_platform) - stack_trace("there is more than one lift platform on a tile when a lift_master adds it. this causes problems") - qdel(other_platform) - - new_lift_platform.lift_master_datum = src - LAZYADD(lift_platforms, new_lift_platform) - RegisterSignal(new_lift_platform, COMSIG_QDELETING, PROC_REF(remove_lift_platforms)) - - check_for_landmarks(new_lift_platform) - - if(z_sorted)//make sure we dont lose z ordering if we get additional platforms after init - order_platforms_by_z_level() - -/datum/lift_master/proc/remove_lift_platforms(obj/structure/industrial_lift/old_lift_platform) - SIGNAL_HANDLER - - if(!(old_lift_platform in lift_platforms)) - return - - old_lift_platform.lift_master_datum = null - LAZYREMOVE(lift_platforms, old_lift_platform) - UnregisterSignal(old_lift_platform, COMSIG_QDELETING) - if(!length(lift_platforms)) - qdel(src) - -///Collect all bordered platforms via a simple floodfill algorithm. allows multiz trams because its funny -/datum/lift_master/proc/Rebuild_lift_plaform(obj/structure/industrial_lift/base_lift_platform) - add_lift_platforms(base_lift_platform) - var/list/possible_expansions = list(base_lift_platform) - - while(possible_expansions.len) - for(var/obj/structure/industrial_lift/borderline as anything in possible_expansions) - var/list/result = borderline.lift_platform_expansion(src) - if(length(result)) - for(var/obj/structure/industrial_lift/lift_platform as anything in result) - if(lift_platforms.Find(lift_platform)) - continue - - add_lift_platforms(lift_platform) - possible_expansions |= lift_platform - - possible_expansions -= borderline - -///check for any landmarks placed inside the locs of the given lift_platform -/datum/lift_master/proc/check_for_landmarks(obj/structure/industrial_lift/new_lift_platform) - SHOULD_CALL_PARENT(TRUE) - - for(var/turf/platform_loc as anything in new_lift_platform.locs) - var/obj/effect/landmark/lift_id/id_giver = locate() in platform_loc - - if(id_giver) - set_info_from_id_landmark(id_giver) - -///set vars and such given an overriding lift_id landmark -/datum/lift_master/proc/set_info_from_id_landmark(obj/effect/landmark/lift_id/landmark) - SHOULD_CALL_PARENT(TRUE) - - if(!istype(landmark, /obj/effect/landmark/lift_id))//lift_master subtypes can want differnet id's than the base type wants - return - - if(landmark.specific_lift_id) - specific_lift_id = landmark.specific_lift_id - - qdel(landmark) - -///orders the lift platforms in order of lowest z level to highest z level. -/datum/lift_master/proc/order_platforms_by_z_level() - //contains nested lists for every z level in the world. why? because its really easy to sort - var/list/platforms_by_z = list() - platforms_by_z.len = world.maxz - - for(var/z in 1 to world.maxz) - platforms_by_z[z] = list() - - for(var/obj/structure/industrial_lift/lift_platform as anything in lift_platforms) - if(QDELETED(lift_platform) || !lift_platform.z) - lift_platforms -= lift_platform - continue - - platforms_by_z[lift_platform.z] += lift_platform - - if(create_multitile_platform) - for(var/list/z_list as anything in platforms_by_z) - if(!length(z_list)) - continue - - create_multitile_platform_for_z_level(z_list)//this will subtract all but one platform from the list - - var/list/output = list() - - for(var/list/z_list as anything in platforms_by_z) - output += z_list - - lift_platforms = output - - z_sorted = TRUE - -///goes through all platforms in the given list and finds the one in the lower left corner -/datum/lift_master/proc/create_multitile_platform_for_z_level(list/obj/structure/industrial_lift/platforms_in_z) - var/min_x = INFINITY - var/max_x = 0 - - var/min_y = INFINITY - var/max_y = 0 - - var/z = 0 - - for(var/obj/structure/industrial_lift/lift_to_sort as anything in platforms_in_z) - if(!z) - if(!lift_to_sort.z) - stack_trace("create_multitile_platform_for_z_level() was given a platform in nullspace or not on a turf!") - platforms_in_z -= lift_to_sort - continue - - z = lift_to_sort.z - - if(z != lift_to_sort.z) - stack_trace("create_multitile_platform_for_z_level() was given lifts on different z levels!") - platforms_in_z -= lift_to_sort - continue - - min_x = min(min_x, lift_to_sort.x) - max_x = max(max_x, lift_to_sort.x) - - min_y = min(min_y, lift_to_sort.y) - max_y = max(max_y, lift_to_sort.y) - - var/turf/lower_left_corner_loc = locate(min_x, min_y, z) - if(!lower_left_corner_loc) - CRASH("was unable to find a turf at the lower left corner of this z") - - var/obj/structure/industrial_lift/lower_left_corner_lift = locate() in lower_left_corner_loc - - if(!lower_left_corner_lift) - CRASH("there was no lift in the lower left corner of the given lifts") - - platforms_in_z.Cut() - platforms_in_z += lower_left_corner_lift//we want to change the list given to us not create a new one. so we do this - - lower_left_corner_lift.create_multitile_platform(min_x, min_y, max_x, max_y, z) - -///returns the closest lift to the specified atom, prioritizing lifts on the same z level. used for comparing distance -/datum/lift_master/proc/return_closest_platform_to(atom/comparison, allow_multiple_answers = FALSE) - if(!istype(comparison) || !comparison.z) - return FALSE - - var/list/obj/structure/industrial_lift/candidate_platforms = list() - - for(var/obj/structure/industrial_lift/platform as anything in lift_platforms) - if(platform.z == comparison.z) - candidate_platforms += platform - - var/obj/structure/industrial_lift/winner = candidate_platforms[1] - var/winner_distance = get_dist(comparison, winner) - - var/list/tied_winners = list(winner) - - for(var/obj/structure/industrial_lift/platform_to_sort as anything in candidate_platforms) - var/platform_distance = get_dist(comparison, platform_to_sort) - - if(platform_distance < winner_distance) - winner = platform_to_sort - winner_distance = platform_distance - - if(allow_multiple_answers) - tied_winners = list(winner) - - else if(platform_distance == winner_distance && allow_multiple_answers) - tied_winners += platform_to_sort - - if(allow_multiple_answers) - return tied_winners - - return winner - -/// Returns a lift platform on the z-level which is vertically closest to the passed target_z -/datum/lift_master/proc/return_closest_platform_to_z(target_z) - var/obj/structure/industrial_lift/found_platform - for(var/obj/structure/industrial_lift/lift as anything in lift_platforms) - // Already at the same Z-level, we can stop - if(lift.z == target_z) - found_platform = lift - break - - // Set up an initial lift to compare to - if(!found_platform) - found_platform = lift - continue - - // Same level, we can go with the one we currently have - if(lift.z == found_platform.z) - continue - - // If the difference between the current found platform and the target - // if less than the distance between the next lift and the target, - // our current platform is closer to the target than the next one, so we can skip it - if(abs(found_platform.z - target_z) < abs(lift.z - target_z)) - continue - - // The difference is smaller for this lift, so it's closer - found_platform = lift - - return found_platform - -/// Returns a list of all the z-levels our lift is currently on. -/datum/lift_master/proc/get_zs_we_are_on() - var/list/zs_we_are_present_on = list() - for(var/obj/structure/industrial_lift/lift as anything in lift_platforms) - zs_we_are_present_on |= lift.z - return zs_we_are_present_on - -///returns all industrial_lifts associated with this tram on the given z level or given atoms z level -/datum/lift_master/proc/get_platforms_on_level(atom/atom_reference_OR_z_level_number) - var/z = atom_reference_OR_z_level_number - if(isatom(atom_reference_OR_z_level_number)) - z = atom_reference_OR_z_level_number.z - - if(!isnum(z) || z < 0 || z > world.maxz) - return null - - var/list/platforms_in_z = list() - - for(var/obj/structure/industrial_lift/lift_to_check as anything in lift_platforms) - if(lift_to_check.z) - platforms_in_z += lift_to_check - - return platforms_in_z - -/** - * Moves the lift UP or DOWN, this is what users invoke with their hand. - * This is a SAFE proc, ensuring every part of the lift moves SANELY. - * - * Arguments: - * going - UP or DOWN directions, where the lift should go. Keep in mind by this point checks of whether it should go up or down have already been done. - * user - Whomever made the lift movement. - */ -/datum/lift_master/proc/move_lift_vertically(going, mob/user) - //lift_platforms are sorted in order of lowest z to highest z, so going upwards we need to move them in reverse order to not collide - if(going == UP) - var/obj/structure/industrial_lift/platform_to_move - var/current_index = length(lift_platforms) - - while(current_index > 0) - platform_to_move = lift_platforms[current_index] - current_index-- - - platform_to_move.travel(going) - - else if(going == DOWN) - for(var/obj/structure/industrial_lift/lift_platform as anything in lift_platforms) - lift_platform.travel(going) - -/** - * Moves the lift after a passed delay. - * - * This is a more "user friendly" or "realistic" lift move. - * It includes things like: - * - Allowing lift "travel time" - * - Shutting elevator safety doors - * - Sound effects while moving - * - Safety warnings for anyone below the lift (while it's moving downwards) - * - * Arguments: - * duration - required, how long do we wait to move the lift? - * door_duration - optional, how long should we wait to open the doors after arriving? If null, we won't open or close doors - * direction - which direction are we moving the lift? - * user - optional, who is moving the lift? - */ -/datum/lift_master/proc/move_after_delay(lift_move_duration, door_duration, direction, mob/user) - if(!isnum(lift_move_duration)) - CRASH("[type] move_after_delay called with invalid duration ([lift_move_duration]).") - if(lift_move_duration <= 0 SECONDS) - move_lift_vertically(direction, user) - return - - // Get the lowest or highest lift according to which direction we're moving - var/obj/structure/industrial_lift/prime_lift = return_closest_platform_to_z(direction == UP ? world.maxz : 0) - - // If anyone changes the hydraulic sound effect I sure hope they update this variable... - var/hydraulic_sfx_duration = 2 SECONDS - // ...because we use the duration of the sound effect to make it last for roughly the duration of the lift travel - playsound(prime_lift, 'sound/mecha/hydraulic.ogg', 25, vary = TRUE, frequency = clamp(hydraulic_sfx_duration / lift_move_duration, 0.33, 3)) - - // Move the lift after a timer - addtimer(CALLBACK(src, PROC_REF(move_lift_vertically), direction, user), lift_move_duration, TIMER_UNIQUE) - // Open doors after the set duration if supplied - if(isnum(door_duration)) - addtimer(CALLBACK(src, PROC_REF(open_lift_doors_callback)), door_duration, TIMER_UNIQUE) - - // Here on we only care about lifts going DOWN - if(direction != DOWN) - return - - // Okay we're going down, let's try to display some warnings to people below - var/list/turf/lift_locs = list() - for(var/obj/structure/industrial_lift/going_to_move as anything in lift_platforms) - // This lift has no warnings so we don't even need to worry about it - if(!going_to_move.warns_on_down_movement) - continue - // Collect all the turfs our lift is found at - lift_locs |= going_to_move.locs - - for(var/turf/moving in lift_locs) - // Find what's below the turf that's moving - var/turf/below_us = get_step_multiz(moving, DOWN) - // Hold up the turf below us is also in our locs list. Multi-z lift? Don't show a warning - if(below_us in lift_locs) - continue - // Display the warning for until we land - new /obj/effect/temp_visual/telegraphing/lift_travel(below_us, lift_move_duration) - -/** - * Simple wrapper for checking if we can move 1 zlevel, and if we can, do said move. - * Locks controls, closes all doors, then moves the lift and re-opens the doors afterwards. - * - * Arguments: - * direction - which direction are we moving? - * lift_move_duration - how long does the move take? can be 0 or null for instant move. - * door_duration - how long does it take for the doors to open after a move? - * user - optional, who moved it? - */ -/datum/lift_master/proc/simple_move_wrapper(direction, lift_move_duration, mob/user) - if(!Check_lift_move(direction)) - return FALSE - - // Lock controls, to prevent moving-while-moving memes - set_controls(LIFT_PLATFORM_LOCKED) - // Send out a signal that we're going - SEND_SIGNAL(src, COMSIG_LIFT_SET_DIRECTION, direction) - // Close all lift doors - update_lift_doors(action = CLOSE_DOORS) - - if(isnull(lift_move_duration) || lift_move_duration <= 0 SECONDS) - // Do an instant move - move_lift_vertically(direction, user) - // Open doors on the zs we arrive at - update_lift_doors(get_zs_we_are_on(), action = OPEN_DOORS) - // And unlock the controls after - set_controls(LIFT_PLATFORM_UNLOCKED) - return TRUE - - // Do a delayed move - move_after_delay( - lift_move_duration = lift_move_duration, - door_duration = lift_move_duration * 1.5, - direction = direction, - user = user, - ) - - addtimer(CALLBACK(src, PROC_REF(finish_simple_move_wrapper)), lift_move_duration * 1.5) - return TRUE - -/** - * Wrap everything up from simple_move_wrapper finishing its movement - */ -/datum/lift_master/proc/finish_simple_move_wrapper() - SEND_SIGNAL(src, COMSIG_LIFT_SET_DIRECTION, 0) - set_controls(LIFT_PLATFORM_UNLOCKED) - -/** - * Moves the lift to the passed z-level. - * - * Checks for validity of the move: Are we moving to the same z-level, can we actually move to that z-level? - * Does NOT check if the lift controls are currently locked. - * - * Moves to the passed z-level by calling move_after_delay repeatedly until the passed z-level is reached. - * This proc sleeps as it moves. - * - * Arguments: - * target_z - required, the Z we want to move to - * loop_callback - optional, an additional callback invoked during the l oop that allows the move to cancel. - * user - optional, who started the move - */ -/datum/lift_master/proc/move_to_zlevel(target_z, datum/callback/loop_callback, mob/user) - if(!isnum(target_z) || target_z <= 0) - CRASH("[type] move_to_zlevel was passed an invalid target_z ([target_z]).") - - var/obj/structure/industrial_lift/prime_lift = return_closest_platform_to_z(target_z) - var/lift_z = prime_lift.z - // We're already at the desired z-level! - if(target_z == lift_z) - return FALSE - - // The amount of z levels between the our and target_z - var/z_difference = abs(target_z - lift_z) - // Direction (up/down) needed to go to reach target_z - var/direction = lift_z < target_z ? UP : DOWN - - // We can't go that way anymore, or possibly ever - if(!Check_lift_move(direction)) - return FALSE - - // Okay we're ready to start moving now. - set_controls(LIFT_PLATFORM_LOCKED) - // Send out a signal that we're going - SEND_SIGNAL(src, COMSIG_LIFT_SET_DIRECTION, direction) - var/travel_speed = prime_lift.elevator_vertical_speed - - // Close all lift doors - update_lift_doors(action = CLOSE_DOORS) - // Approach the desired z-level one step at a time - for(var/i in 1 to z_difference) - if(!Check_lift_move(direction)) - break - if(loop_callback && !loop_callback.Invoke()) - break - // move_after_delay will set up a timer and cause us to move after a time - move_after_delay( - lift_move_duration = travel_speed, - direction = direction, - user = user, - ) - // and we don't want to send another request until the timer's done - stoplag(travel_speed + 0.1 SECONDS) - if(QDELETED(src) || QDELETED(prime_lift)) - return - - addtimer(CALLBACK(src, PROC_REF(open_lift_doors_callback)), 2 SECONDS) - SEND_SIGNAL(src, COMSIG_LIFT_SET_DIRECTION, 0) - set_controls(LIFT_PLATFORM_UNLOCKED) - return TRUE - -/** - * Updates all blast doors and shutters that share an ID with our lift. - * - * Arguments: - * on_z_level - optional, only open doors on this z-level or list of z-levels - * action - how do we update the doors? OPEN_DOORS to make them open, CLOSE_DOORS to make them shut - */ -/datum/lift_master/proc/update_lift_doors(on_z_level, action) - - if(!isnull(on_z_level) && !islist(on_z_level)) - on_z_level = list(on_z_level) - - var/played_ding = FALSE - for(var/obj/machinery/door/elevator_door as anything in GLOB.elevator_doors) - if(elevator_door.elevator_linked_id != specific_lift_id) - continue - if(on_z_level && !(elevator_door.z in on_z_level)) - continue - switch(action) - if(OPEN_DOORS) - elevator_door.elevator_status = LIFT_PLATFORM_UNLOCKED - if(!played_ding) - playsound(elevator_door, 'sound/machines/ping.ogg', 50, TRUE) - played_ding = TRUE - addtimer(CALLBACK(elevator_door, TYPE_PROC_REF(/obj/machinery/door, open)), 0.7 SECONDS) - if(CLOSE_DOORS) - elevator_door.elevator_status = LIFT_PLATFORM_LOCKED - INVOKE_ASYNC(elevator_door, TYPE_PROC_REF(/obj/machinery/door, close)) - else - stack_trace("Elevator lift update_lift_doors called with an improper action ([action]).") - -/// Helper used in callbacks to open all the doors our lift is on -/datum/lift_master/proc/open_lift_doors_callback() - update_lift_doors(get_zs_we_are_on(), action = OPEN_DOORS) - -/** - * Moves the lift, this is what users invoke with their hand. - * This is a SAFE proc, ensuring every part of the lift moves SANELY. - * It also locks controls for the (miniscule) duration of the movement, so the elevator cannot be broken by spamming. - */ -/datum/lift_master/proc/move_lift_horizontally(going) - set_controls(LIFT_PLATFORM_LOCKED) - - if(multitile_platform) - for(var/obj/structure/industrial_lift/platform_to_move as anything in lift_platforms) - platform_to_move.travel(going) - - set_controls(LIFT_PLATFORM_UNLOCKED) - return - - var/max_x = 0 - var/max_y = 0 - var/max_z = 0 - var/min_x = world.maxx - var/min_y = world.maxy - var/min_z = world.maxz - - for(var/obj/structure/industrial_lift/lift_platform as anything in lift_platforms) - max_z = max(max_z, lift_platform.z) - min_z = min(min_z, lift_platform.z) - - min_x = min(min_x, lift_platform.x) - max_x = max(max_x, lift_platform.x) - //this assumes that all z levels have identical horizontal bounding boxes - //but if youre still using a non multitile tram platform at this point - //then its your own problem. it wont runtime it will jsut be slower than it needs to be if this assumption isnt - //the case - - min_y = min(min_y, lift_platform.y) - max_y = max(max_y, lift_platform.y) - - for(var/z in min_z to max_z) - //This must be safe way to border tile to tile move of bordered platforms, that excludes platform overlapping. - if(going & WEST) - //Go along the X axis from min to max, from left to right - for(var/x in min_x to max_x) - if(going & NORTH) - //Go along the Y axis from max to min, from up to down - for(var/y in max_y to min_y step -1) - var/obj/structure/industrial_lift/lift_platform = locate(/obj/structure/industrial_lift, locate(x, y, z)) - lift_platform?.travel(going) - - else if(going & SOUTH) - //Go along the Y axis from min to max, from down to up - for(var/y in min_y to max_y) - var/obj/structure/industrial_lift/lift_platform = locate(/obj/structure/industrial_lift, locate(x, y, z)) - lift_platform?.travel(going) - - else - for(var/y in min_y to max_y) - var/obj/structure/industrial_lift/lift_platform = locate(/obj/structure/industrial_lift, locate(x, y, z)) - lift_platform?.travel(going) - else - //Go along the X axis from max to min, from right to left - for(var/x in max_x to min_x step -1) - if(going & NORTH) - //Go along the Y axis from max to min, from up to down - for(var/y in max_y to min_y step -1) - var/obj/structure/industrial_lift/lift_platform = locate(/obj/structure/industrial_lift, locate(x, y, z)) - lift_platform?.travel(going) - - else if (going & SOUTH) - for(var/y in min_y to max_y) - var/obj/structure/industrial_lift/lift_platform = locate(/obj/structure/industrial_lift, locate(x, y, z)) - lift_platform?.travel(going) - - else - //Go along the Y axis from min to max, from down to up - for(var/y in min_y to max_y) - var/obj/structure/industrial_lift/lift_platform = locate(/obj/structure/industrial_lift, locate(x, y, z)) - lift_platform?.travel(going) - - set_controls(LIFT_PLATFORM_UNLOCKED) - -///Check destination turfs -/datum/lift_master/proc/Check_lift_move(check_dir) - for(var/obj/structure/industrial_lift/lift_platform as anything in lift_platforms) - for(var/turf/bound_turf in lift_platform.locs) - var/turf/T = get_step_multiz(lift_platform, check_dir) - if(!T)//the edges of multi-z maps - return FALSE - if(check_dir == UP && !istype(T, /turf/open/openspace)) // We don't want to go through the ceiling! - return FALSE - if(check_dir == DOWN && !istype(get_turf(lift_platform), /turf/open/openspace)) // No going through the floor! - return FALSE - return TRUE - -/** - * Sets all lift parts's controls_locked variable. Used to prevent moving mid movement, or cooldowns. - */ -/datum/lift_master/proc/set_controls(state) - controls_locked = state - -/** - * resets the contents of all platforms to their original state in case someone put a bunch of shit onto the tram. - * intended to be called by admins. passes all arguments to reset_contents() for each of our platforms. - * - * Arguments: - * * consider_anything_past - number. if > 0 our platforms will only handle foreign contents that exceed this number in each of their locs - * * foreign_objects - bool. if true our platforms will consider /atom/movable's that arent mobs as part of foreign contents - * * foreign_non_player_mobs - bool. if true our platforms consider mobs that dont have a mind to be foreign - * * consider_player_mobs - bool. if true our platforms consider player mobs to be foreign. only works if foreign_non_player_mobs is true as well - */ -/datum/lift_master/proc/reset_lift_contents(consider_anything_past = 0, foreign_objects = TRUE, foreign_non_player_mobs = TRUE, consider_player_mobs = FALSE) - for(var/obj/structure/industrial_lift/lift_to_reset in lift_platforms) - lift_to_reset.reset_contents(consider_anything_past, foreign_objects, foreign_non_player_mobs, consider_player_mobs) - - return TRUE diff --git a/code/modules/industrial_lift/tram/tram_doors.dm b/code/modules/industrial_lift/tram/tram_doors.dm deleted file mode 100644 index f0253659eb6..00000000000 --- a/code/modules/industrial_lift/tram/tram_doors.dm +++ /dev/null @@ -1,135 +0,0 @@ -/obj/machinery/door/window/tram - name = "tram door" - desc = "Probably won't crush you if you try to rush them as they close. But we know you live on that danger, try and beat the tram!" - icon = 'icons/obj/doors/tramdoor.dmi' - req_access = list("tcomms") - multi_tile = TRUE - var/associated_lift = MAIN_STATION_TRAM - var/datum/weakref/tram_ref - /// Are the doors in a malfunctioning state (dangerous) - var/malfunctioning = FALSE - -/obj/machinery/door/window/tram/left - icon_state = "left" - base_state = "left" - -/obj/machinery/door/window/tram/left/directional/south - plane = WALL_PLANE_UPPER - -/obj/machinery/door/window/tram/right - icon_state = "right" - base_state = "right" - -/obj/machinery/door/window/tram/hilbert - icon = 'icons/obj/mining_zones/survival_pod.dmi' - associated_lift = HILBERT_TRAM - icon_state = "windoor" - base_state = "windoor" - -/obj/machinery/door/window/tram/emag_act(mob/user, obj/item/card/emag/emag_card) - if(obj_flags & EMAGGED) - return FALSE - balloon_alert(user, "disabled motion sensors") - obj_flags |= EMAGGED - return TRUE - -/// Random event called by code\modules\events\tram_malfunction.dm -/// Makes the doors malfunction -/obj/machinery/door/window/tram/proc/start_malfunction() - if(obj_flags & EMAGGED) - return - - malfunctioning = TRUE - process() - -/// Random event called by code\modules\events\tram_malfunction.dm -/// Returns doors to their original status -/obj/machinery/door/window/tram/proc/end_malfunction() - if(obj_flags & EMAGGED) - return - - malfunctioning = FALSE - process() - -/obj/machinery/door/window/tram/proc/cycle_doors(command, forced=FALSE) - if(command == "open" && icon_state == "[base_state]open") - if(!forced && !hasPower()) - return FALSE - return TRUE - if(command == "close" && icon_state == base_state) - return TRUE - switch(command) - if("open") - playsound(src, 'sound/machines/tramopen.ogg', vol = 75, vary = FALSE, extrarange = SHORT_RANGE_SOUND_EXTRARANGE) - do_animate("opening") - icon_state ="[base_state]open" - sleep(7 DECISECONDS) - set_density(FALSE) - air_update_turf(TRUE, FALSE) - if("close") - if((obj_flags & EMAGGED) || malfunctioning) - flick("[base_state]spark", src) - playsound(src, SFX_SPARKS, vol = 75, vary = FALSE, extrarange = SHORT_RANGE_SOUND_EXTRARANGE) - sleep(6 DECISECONDS) - playsound(src, 'sound/machines/tramclose.ogg', vol = 75, vary = FALSE, extrarange = SHORT_RANGE_SOUND_EXTRARANGE) - do_animate("closing") - icon_state = base_state - sleep(19 DECISECONDS) - if((obj_flags & EMAGGED) || malfunctioning) - if(malfunctioning && prob(85)) - return - for(var/i in 1 to 3) - for(var/mob/living/crushee in get_turf(src)) - crush() - sleep(2 DECISECONDS) - air_update_turf(TRUE, TRUE) - operating = FALSE - set_density(TRUE) - - update_freelook_sight() - return TRUE - -/obj/machinery/door/window/tram/right/directional/south - plane = WALL_PLANE_UPPER - -/obj/machinery/door/window/tram/proc/find_tram() - for(var/datum/lift_master/lift as anything in GLOB.active_lifts_by_type[TRAM_LIFT_ID]) - if(lift.specific_lift_id == associated_lift) - tram_ref = WEAKREF(lift) - -/obj/machinery/door/window/tram/Initialize(mapload, set_dir, unres_sides) - . = ..() - RemoveElement(/datum/element/atmos_sensitive, mapload) - if(filler) - filler.set_density(FALSE) // tram doors allow you to stand on the tile - INVOKE_ASYNC(src, PROC_REF(open)) - GLOB.tram_doors += src - find_tram() - -/obj/machinery/door/window/tram/Destroy() - GLOB.tram_doors -= src - return ..() - -/obj/machinery/door/window/tram/examine(mob/user) - . = ..() - . += span_notice("It has labels indicating that it has an emergency mechanism to open using just your hands in the event of an emergency.") - -/obj/machinery/door/window/tram/try_safety_unlock(mob/user) - if(!hasPower() && density) - balloon_alert(user, "pulling emergency exit...") - if(do_after(user, 7 SECONDS, target = src)) - try_to_crowbar(null, user, TRUE) - return TRUE - -/obj/machinery/door/window/tram/bumpopen(mob/user) - if(operating || !density) - return - var/datum/lift_master/tram/tram_part = tram_ref?.resolve() - add_fingerprint(user) - if(tram_part.travel_distance < XING_DEFAULT_TRAM_LENGTH || tram_part.travel_distance > tram_part.travel_trip_length - XING_DEFAULT_TRAM_LENGTH) - return // we're already animating, don't reset that - cycle_doors(OPEN_DOORS, TRUE) //making a daring exit midtravel? make sure the doors don't go in the wrong state on arrival. - return - -MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/door/window/tram/left, 0) -MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/door/window/tram/right, 0) diff --git a/code/modules/industrial_lift/tram/tram_floors.dm b/code/modules/industrial_lift/tram/tram_floors.dm deleted file mode 100644 index 3d4cff43ccb..00000000000 --- a/code/modules/industrial_lift/tram/tram_floors.dm +++ /dev/null @@ -1,96 +0,0 @@ -/turf/open/floor/noslip/tram - name = "high-traction platform" - icon_state = "noslip_tram" - base_icon_state = "noslip_tram" - floor_tile = /obj/item/stack/tile/noslip/tram - -/turf/open/floor/noslip/tram_plate - name = "linear induction plate" - desc = "The linear induction plate that powers the tram." - icon_state = "tram_plate" - base_icon_state = "tram_plate" - floor_tile = /obj/item/stack/tile/noslip/tram_plate - slowdown = 0 - flags_1 = NONE - -/turf/open/floor/noslip/tram_plate/energized - desc = "The linear induction plate that powers the tram. It is currently energized." - /// Inbound station - var/inbound - /// Outbound station - var/outbound - -/turf/open/floor/noslip/tram_platform - name = "tram platform" - icon_state = "tram_platform" - base_icon_state = "tram_platform" - floor_tile = /obj/item/stack/tile/noslip/tram_platform - slowdown = 0 - -/turf/open/floor/noslip/tram_plate/broken_states() - return list("tram_plate-damaged1","tram_plate-damaged2") - -/turf/open/floor/noslip/tram_plate/burnt_states() - return list("tram_plate-scorched1","tram_plate-scorched2") - -/turf/open/floor/noslip/tram_platform/broken_states() - return list("tram_platform-damaged1","tram_platform-damaged2") - -/turf/open/floor/noslip/tram_platform/burnt_states() - return list("tram_platform-scorched1","tram_platform-scorched2") - -/turf/open/floor/noslip/tram_plate/energized/proc/find_tram() - for(var/datum/lift_master/tram/tram as anything in GLOB.active_lifts_by_type[TRAM_LIFT_ID]) - if(tram.specific_lift_id != MAIN_STATION_TRAM) - continue - return tram - -/turf/open/floor/noslip/tram_plate/energized/proc/toast(mob/living/future_tram_victim) - var/datum/lift_master/tram/tram = find_tram() - - // Check for stopped states. - if(!tram || !tram.is_operational || !inbound || !outbound) - return FALSE - - var/obj/structure/industrial_lift/tram/tram_part = tram.return_closest_platform_to(src) - - if(QDELETED(tram_part)) - return FALSE - - // Everything will be based on position and travel direction - var/plate_pos - var/tram_pos - var/tram_velocity_sign // 1 for positive axis movement, -1 for negative - // Try to be agnostic about N-S vs E-W movement - if(tram.travel_direction & (NORTH|SOUTH)) - plate_pos = y - tram_pos = tram_part.y - tram_velocity_sign = tram.travel_direction & NORTH ? 1 : -1 - else - plate_pos = x - tram_pos = tram_part.x - tram_velocity_sign = tram.travel_direction & EAST ? 1 : -1 - - // How far away are we? negative if already passed. - var/approach_distance = tram_velocity_sign * (plate_pos - (tram_pos + (XING_DEFAULT_TRAM_LENGTH * 0.5))) - - // Check if our victim is in the active path of the tram. - if(!tram.travelling) - return FALSE - if(approach_distance < 0) - return FALSE - playsound(src, SFX_SPARKS, 75, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) - audible_message( - span_hear("You hear an electric crackle when you step on the plate...") - ) - if(tram.travel_direction & WEST && inbound < tram.idle_platform.platform_code) - return FALSE - if(tram.travel_direction & EAST && outbound > tram.idle_platform.platform_code) - return FALSE - if(approach_distance >= XING_DISTANCE_AMBER) - return FALSE - - // Finally the interesting part where they ACTUALLY get hit! - notify_ghosts("[future_tram_victim] has fallen in the path of an oncoming tram!", source = future_tram_victim, action = NOTIFY_ORBIT, header = "Electrifying!") - future_tram_victim.electrocute_act(15, src, 1) - return TRUE diff --git a/code/modules/industrial_lift/tram/tram_landmark.dm b/code/modules/industrial_lift/tram/tram_landmark.dm deleted file mode 100644 index 76341a7d064..00000000000 --- a/code/modules/industrial_lift/tram/tram_landmark.dm +++ /dev/null @@ -1,109 +0,0 @@ -GLOBAL_LIST_EMPTY(tram_landmarks) - -/obj/effect/landmark/tram - name = "tram destination" //the tram buttons will mention this. - icon_state = "tram" - - ///the id of the tram we're linked to. - var/specific_lift_id = MAIN_STATION_TRAM - /// The ID of that particular destination. - var/platform_code = null - /// Icons for the tgui console to list out for what is at this location - var/list/tgui_icons = list() - -/obj/effect/landmark/tram/Initialize(mapload) - . = ..() - LAZYADDASSOCLIST(GLOB.tram_landmarks, specific_lift_id, src) - -/obj/effect/landmark/tram/Destroy() - LAZYREMOVEASSOC(GLOB.tram_landmarks, specific_lift_id, src) - return ..() - -/obj/effect/landmark/tram/nav - name = "tram nav beacon" - invisibility = INVISIBILITY_MAXIMUM // nav aids can't be abstract since they stay with the tram - -/** - * lift_id landmarks. used to map in specific_lift_id to trams. when the trams lift_master encounters one on a trams tile - * it sets its specific_lift_id to that landmark. allows you to have multiple trams and multiple controls linking to their specific tram - */ -/obj/effect/landmark/lift_id - name = "lift id setter" - icon_state = "lift_id" - ///what specific id we give to the tram we're placed on, should explicitly set this if its a subtype, or weird things might happen - var/specific_lift_id = MAIN_STATION_TRAM - -//tramstation - -/obj/effect/landmark/tram/nav/tramstation/main - name = MAIN_STATION_TRAM - specific_lift_id = TRAM_NAV_BEACONS - dir = WEST - -/obj/effect/landmark/tram/platform/tramstation/west - name = "West Wing" - platform_code = TRAMSTATION_WEST - tgui_icons = list("Arrivals" = "plane-arrival", "Command" = "bullhorn", "Security" = "gavel") - -/obj/effect/landmark/tram/platform/tramstation/central - name = "Central Wing" - platform_code = TRAMSTATION_CENTRAL - tgui_icons = list("Service" = "cocktail", "Medical" = "plus", "Engineering" = "wrench") - -/obj/effect/landmark/tram/platform/tramstation/east - name = "East Wing" - platform_code = TRAMSTATION_EAST - tgui_icons = list("Departures" = "plane-departure", "Cargo" = "box", "Science" = "flask") - -//map-agnostic landmarks - -/obj/effect/landmark/tram/nav/immovable_rod - name = "DESTINATION/NOT/FOUND" - specific_lift_id = IMMOVABLE_ROD_DESTINATIONS - -/obj/effect/landmark/tram/nav/hilbert - name = HILBERT_TRAM - specific_lift_id = TRAM_NAV_BEACONS - dir = WEST - -//birdshot - -/obj/effect/landmark/lift_id/birdshot/prison - specific_lift_id = PRISON_TRAM - -/obj/effect/landmark/lift_id/birdshot/maint - specific_lift_id = MAINTENANCE_TRAM - -/obj/effect/landmark/tram/nav/birdshot/prison - name = PRISON_TRAM - specific_lift_id = TRAM_NAV_BEACONS - dir = NORTH - -/obj/effect/landmark/tram/nav/birdshot/maint - name = MAINTENANCE_TRAM - specific_lift_id = TRAM_NAV_BEACONS - dir = WEST - -/obj/effect/landmark/tram/platform/birdshot/sec_wing - name = "Security Wing" - specific_lift_id = PRISON_TRAM - platform_code = BIRDSHOT_SECURITY_WING - tgui_icons = list("Security" = "gavel") - -/obj/effect/landmark/tram/platform/birdshot/prison_wing - name = "Prison Wing" - specific_lift_id = PRISON_TRAM - platform_code = BIRDSHOT_PRISON_WING - tgui_icons = list("Prison" = "box") - -/obj/effect/landmark/tram/platform/birdshot/maint_left - name = "Port Platform" - specific_lift_id = MAINTENANCE_TRAM - platform_code = BIRDSHOT_MAINTENANCE_LEFT - tgui_icons = list("Port Platform" = "plane-departure") - -/obj/effect/landmark/tram/platform/birdshot/maint_right - name = "Starboard Platform" - specific_lift_id = MAINTENANCE_TRAM - platform_code = BRIDSHOT_MAINTENANCE_RIGHT - tgui_icons = list("Starboard Platform" = "plane-arrival") diff --git a/code/modules/industrial_lift/tram/tram_lift_master.dm b/code/modules/industrial_lift/tram/tram_lift_master.dm deleted file mode 100644 index e2d044dc5b2..00000000000 --- a/code/modules/industrial_lift/tram/tram_lift_master.dm +++ /dev/null @@ -1,330 +0,0 @@ -/datum/lift_master/tram - - ///whether this tram is traveling across vertical and/or horizontal axis for some distance. not all lifts use this - var/travelling = FALSE - ///if we're travelling, what direction are we going - var/travel_direction = NONE - ///if we're travelling, how far do we have to go - var/travel_distance = 0 - ///how far in total we'll be travelling - var/travel_trip_length = 0 - - ///multiplier on how much damage/force the tram imparts on things it hits - var/collision_lethality = 1 - - /// reference to the destination landmark we consider ourselves "at". since we potentially span multiple z levels we dont actually - /// know where on us this platform is. as long as we know THAT its on us we can just move the distance and direction between this - /// and the destination landmark. - var/obj/effect/landmark/tram/idle_platform - - /// a navigational landmark that we use to find the tram's location on the map at any time - var/obj/effect/landmark/tram/nav/nav_beacon - - ///decisecond delay between horizontal movement. cannot make the tram move faster than 1 movement per world.tick_lag. - ///this var is poorly named its actually horizontal movement delay but whatever. - var/horizontal_speed = 0.5 - - ///version of horizontal_speed that gets set in init and is considered our base speed if our lift gets slowed down - var/base_horizontal_speed = 0.5 - - ///the world.time we should next move at. in case our speed is set to less than 1 movement per tick - var/next_move = INFINITY - - ///whether we have been slowed down automatically - var/slowed_down = FALSE - - ///how many times we moved while costing more than SStramprocess.max_time milliseconds per movement. - ///if this exceeds SStramprocess.max_exceeding_moves - var/times_exceeded = 0 - - ///how many times we moved while costing less than 0.5 * SStramprocess.max_time milliseconds per movement - var/times_below = 0 - - var/is_operational = TRUE - -/datum/lift_master/tram/New(obj/structure/industrial_lift/tram/lift_platform) - . = ..() - horizontal_speed = lift_platform.horizontal_speed - base_horizontal_speed = lift_platform.horizontal_speed - - check_starting_landmark() - -/datum/lift_master/tram/vv_edit_var(var_name, var_value) - . = ..() - if(var_name == "base_horizontal_speed") - horizontal_speed = max(horizontal_speed, base_horizontal_speed) - -/datum/lift_master/tram/add_lift_platforms(obj/structure/industrial_lift/new_lift_platform) - . = ..() - RegisterSignal(new_lift_platform, COMSIG_MOVABLE_BUMP, PROC_REF(gracefully_break)) - -/datum/lift_master/tram/check_for_landmarks(obj/structure/industrial_lift/tram/new_lift_platform) - . = ..() - for(var/turf/platform_loc as anything in new_lift_platform.locs) - var/obj/effect/landmark/tram/platform/initial_destination = locate() in platform_loc - var/obj/effect/landmark/tram/nav/beacon = locate() in platform_loc - - if(initial_destination) - idle_platform = initial_destination - - if(beacon) - nav_beacon = beacon - -/datum/lift_master/tram/proc/check_starting_landmark() - if(!idle_platform || !nav_beacon) - CRASH("a tram lift_master was initialized without the required landmarks to give it direction!") - - SStramprocess.can_fire = TRUE - - return TRUE - -/** - * Signal for when the tram runs into a field of which it cannot go through. - * Stops the train's travel fully, sends a message, and destroys the train. - * Arguments: - * bumped_atom - The atom this tram bumped into - */ -/datum/lift_master/tram/proc/gracefully_break(atom/bumped_atom) - SIGNAL_HANDLER - - travel_distance = 0 - bumped_atom.visible_message(span_userdanger("The [bumped_atom.name] crashes into the field violently!")) - for(var/obj/structure/industrial_lift/tram/tram_part as anything in lift_platforms) - tram_part.set_travelling(FALSE) - for(var/tram_contents in tram_part.lift_load) - if(iseffect(tram_contents)) - continue - - if(isliving(tram_contents)) - explosion(tram_contents, devastation_range = rand(0, 1), heavy_impact_range = 2, light_impact_range = 3) //50% chance of gib - - else if(prob(9)) - explosion(tram_contents, devastation_range = 1, heavy_impact_range = 2, light_impact_range = 3) - - explosion(tram_part, devastation_range = 1, heavy_impact_range = 2, light_impact_range = 3) - qdel(tram_part) - - for(var/obj/machinery/destination_sign/desto as anything in GLOB.tram_signs) - desto.icon_state = "[desto.base_icon_state][DESTINATION_NOT_IN_SERVICE]" - - for(var/obj/machinery/crossing_signal/xing as anything in GLOB.tram_signals) - xing.set_signal_state(XING_STATE_MALF) - xing.update_appearance() - -/** - * Handles moving the tram - * - * Tells the individual tram parts where to actually go and has an extra safety checks - * incase multiple inputs get through, preventing conflicting directions and the tram - * literally ripping itself apart. all of the actual movement is handled by SStramprocess - * Arguments: destination platform, rapid (bypass some safety checks) - */ -/datum/lift_master/tram/proc/tram_travel(obj/effect/landmark/tram/destination_platform, rapid = FALSE) - if(destination_platform == idle_platform) - return FALSE - - travel_direction = get_dir(nav_beacon, destination_platform) - travel_distance = get_dist(nav_beacon, destination_platform) - travel_trip_length = travel_distance - idle_platform = destination_platform - set_travelling(TRUE) - set_controls(LIFT_PLATFORM_LOCKED) - if(rapid) // bypass for unsafe, rapid departure - dispatch_tram(destination_platform) - return TRUE - else - update_tram_doors(CLOSE_DOORS) - addtimer(CALLBACK(src, PROC_REF(dispatch_tram), destination_platform), 3 SECONDS) - return TRUE - -/datum/lift_master/tram/proc/dispatch_tram(obj/effect/landmark/tram/destination_platform) - SEND_SIGNAL(src, COMSIG_TRAM_TRAVEL, idle_platform, destination_platform) - - for(var/obj/structure/industrial_lift/tram/tram_part as anything in lift_platforms) //only thing everyone needs to know is the new location. - if(tram_part.travelling) //wee woo wee woo there was a double action queued. damn multi tile structs - return //we don't care to undo locked controls, though, as that will resolve itself - - tram_part.glide_size_override = DELAY_TO_GLIDE_SIZE(horizontal_speed) - tram_part.set_travelling(TRUE) - - next_move = world.time + horizontal_speed - - START_PROCESSING(SStramprocess, src) - -/datum/lift_master/tram/process(seconds_per_tick) - if(!travel_distance) - update_tram_doors(OPEN_DOORS) - addtimer(CALLBACK(src, PROC_REF(unlock_controls)), 2 SECONDS) - return PROCESS_KILL - else if(world.time >= next_move) - var/start_time = TICK_USAGE - travel_distance-- - - move_lift_horizontally(travel_direction) - - var/duration = TICK_USAGE_TO_MS(start_time) - if(slowed_down) - if(duration <= (SStramprocess.max_time / 2)) - times_below++ - else - times_below = 0 - - if(times_below >= SStramprocess.max_cheap_moves) - horizontal_speed = base_horizontal_speed - slowed_down = FALSE - times_below = 0 - - else if(duration > SStramprocess.max_time) - times_exceeded++ - - if(times_exceeded >= SStramprocess.max_exceeding_moves) - message_admins("The tram at [ADMIN_JMP(lift_platforms[1])] is taking more than [SStramprocess.max_time] milliseconds per movement, halving its movement speed. if this continues to be a problem you can call reset_lift_contents() on the trams lift_master_datum to reset it to its original state and clear added objects") - horizontal_speed = base_horizontal_speed * 2 //halves its speed - slowed_down = TRUE - times_exceeded = 0 - else - times_exceeded = max(times_exceeded - 1, 0) - - next_move = world.time + horizontal_speed - -/** - * Handles unlocking the tram controls for use after moving - * - * More safety checks to make sure the tram has actually docked properly - * at a location before users are allowed to interact with the tram console again. - * Tram finds its location at this point before fully unlocking controls to the user. - */ -/datum/lift_master/tram/proc/unlock_controls() - set_travelling(FALSE) - set_controls(LIFT_PLATFORM_UNLOCKED) - for(var/obj/structure/industrial_lift/tram/tram_part as anything in lift_platforms) //only thing everyone needs to know is the new location. - tram_part.set_travelling(FALSE) - - -/datum/lift_master/tram/proc/set_travelling(new_travelling) - if(travelling == new_travelling) - return - - travelling = new_travelling - SEND_SIGNAL(src, COMSIG_TRAM_SET_TRAVELLING, travelling) - -/** - * Controls the doors of the tram when it departs and arrives at stations. - * The tram doors are in a list of airlocks and we apply the proc on that list. - */ -/datum/lift_master/tram/proc/update_tram_doors(action) - for(var/obj/machinery/door/window/tram/tram_door as anything in SSmachines.get_machines_by_type_and_subtypes(/obj/machinery/door/window/tram)) - if(tram_door.associated_lift != specific_lift_id) - continue - set_door_state(tram_door, action) - -/datum/lift_master/tram/proc/set_door_state(tram_door, action) - switch(action) - if(OPEN_DOORS) - INVOKE_ASYNC(tram_door, TYPE_PROC_REF(/obj/machinery/door/window/tram, cycle_doors), action) - - if(CLOSE_DOORS) - INVOKE_ASYNC(tram_door, TYPE_PROC_REF(/obj/machinery/door/window/tram, cycle_doors), action) - - else - stack_trace("Tram doors update_tram_doors called with an improper action ([action]).") - -/datum/lift_master/tram/proc/set_operational(new_value) - if(is_operational != new_value) - is_operational = new_value - -/** - * Returns the closest tram nav beacon to an atom - * - * Creates a list of nav beacons in the requested direction - * and returns the closest to be passed to the industrial_lift - * - * Arguments: source: the starting point to find a beacon - * travel_dir: travel direction in tram form, INBOUND or OUTBOUND - * beacon_type: what list of beacons we pull from - */ -/datum/lift_master/tram/proc/closest_nav_in_travel_dir(atom/origin, travel_dir, beacon_type) - if(!istype(origin) || !origin.z) - return FALSE - - var/list/obj/effect/landmark/tram/nav/inbound_candidates = list() - var/list/obj/effect/landmark/tram/nav/outbound_candidates = list() - - for(var/obj/effect/landmark/tram/nav/candidate_beacon in GLOB.tram_landmarks[beacon_type]) - if(candidate_beacon.z != origin.z || candidate_beacon.z != nav_beacon.z) - continue - - switch(nav_beacon.dir) - if(EAST, WEST) - if(candidate_beacon.y != nav_beacon.y) - continue - else if(candidate_beacon.x < nav_beacon.x) - inbound_candidates += candidate_beacon - else - outbound_candidates += candidate_beacon - if(NORTH, SOUTH) - if(candidate_beacon.x != nav_beacon.x) - continue - else if(candidate_beacon.y < nav_beacon.y) - inbound_candidates += candidate_beacon - else - outbound_candidates += candidate_beacon - - switch(travel_dir) - if(INBOUND) - var/obj/effect/landmark/tram/nav/selected = get_closest_atom(/obj/effect/landmark/tram/nav, inbound_candidates, origin) - if(selected) - return selected - stack_trace("No inbound beacon candidate found for [origin]. Cancelling dispatch.") - return FALSE - - if(OUTBOUND) - var/obj/effect/landmark/tram/nav/selected = get_closest_atom(/obj/effect/landmark/tram/nav, outbound_candidates, origin) - if(selected) - return selected - stack_trace("No outbound beacon candidate found for [origin]. Cancelling dispatch.") - return FALSE - - else - stack_trace("Tram receieved invalid travel direction [travel_dir]. Cancelling dispatch.") - - return FALSE - -/** - * Moves the tram when hit by an immovable rod - * - * Tells the individual tram parts where to actually go and has an extra safety checks - * incase multiple inputs get through, preventing conflicting directions and the tram - * literally ripping itself apart. all of the actual movement is handled by SStramprocess - * - * Arguments: collided_rod (the immovable rod that hit the tram) - * Return: push_destination (the landmark /obj/effect/landmark/tram/nav that the tram is being pushed to due to the rod's trajectory) - */ -/datum/lift_master/tram/proc/rod_collision(obj/effect/immovablerod/collided_rod) - if(!is_operational) - return - var/rod_velocity_sign - // Determine inbound or outbound - if(collided_rod.dir & (NORTH|SOUTH)) - rod_velocity_sign = collided_rod.dir & NORTH ? OUTBOUND : INBOUND - else - rod_velocity_sign = collided_rod.dir & EAST ? OUTBOUND : INBOUND - - var/obj/effect/landmark/tram/nav/push_destination = closest_nav_in_travel_dir(origin = nav_beacon, travel_dir = rod_velocity_sign, beacon_type = IMMOVABLE_ROD_DESTINATIONS) - if(!push_destination) - return - travel_direction = get_dir(nav_beacon, push_destination) - travel_distance = get_dist(nav_beacon, push_destination) - travel_trip_length = travel_distance - idle_platform = push_destination - // Don't bother processing crossing signals, where this tram's going there are no signals - for(var/obj/machinery/crossing_signal/xing as anything in GLOB.tram_signals) - xing.temp_malfunction() - priority_announce("In a turn of rather peculiar events, it appears that [GLOB.station_name] has struck an immovable rod. (Don't ask us where it came from.) This has led to a station brakes failure on one of the tram platforms.\n\n\ - Our diligent team of engineers have been informed and they're rushing over - although not quite at the speed of our recently flying tram.\n\n\ - So while we all look in awe at the universe's mysterious sense of humour, please stand clear of the tracks and remember to stand behind the yellow line.", "Braking News") - set_travelling(TRUE) - set_controls(LIFT_PLATFORM_LOCKED) - dispatch_tram(destination_platform = push_destination) - set_operational(FALSE) - return push_destination diff --git a/code/modules/industrial_lift/tram/tram_machinery.dm b/code/modules/industrial_lift/tram/tram_machinery.dm deleted file mode 100644 index 2e4399cce70..00000000000 --- a/code/modules/industrial_lift/tram/tram_machinery.dm +++ /dev/null @@ -1,777 +0,0 @@ -GLOBAL_LIST_EMPTY(tram_signals) -GLOBAL_LIST_EMPTY(tram_signs) -GLOBAL_LIST_EMPTY(tram_doors) - -/obj/machinery/computer/tram_controls - name = "tram controls" - desc = "An interface for the tram that lets you tell the tram where to go and hopefully it makes it there. I'm here to describe the controls to you, not to inspire confidence." - icon_state = "tram_controls" - base_icon_state = "tram_" - icon_screen = "tram_Central Wing_idle" - icon_keyboard = null - layer = SIGN_LAYER - density = FALSE - circuit = /obj/item/circuitboard/computer/tram_controls - flags_1 = NODECONSTRUCT_1 | SUPERMATTER_IGNORES_1 - resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF - interaction_flags_machine = INTERACT_MACHINE_ALLOW_SILICON|INTERACT_MACHINE_SET_MACHINE - light_color = COLOR_BLUE_LIGHT - light_range = 0 //we dont want to spam SSlighting with source updates every movement - - ///Weakref to the tram piece we control - var/datum/weakref/tram_ref - - var/specific_lift_id = MAIN_STATION_TRAM - -/obj/machinery/computer/tram_controls/Initialize(mapload, obj/item/circuitboard/C) - . = ..() - AddComponent(/datum/component/usb_port, list(/obj/item/circuit_component/tram_controls)) - return INITIALIZE_HINT_LATELOAD - -/obj/machinery/computer/tram_controls/LateInitialize() - . = ..() - find_tram() - - var/datum/lift_master/tram/tram_part = tram_ref?.resolve() - if(tram_part) - RegisterSignal(tram_part, COMSIG_TRAM_SET_TRAVELLING, PROC_REF(update_tram_display)) - icon_screen = "[base_icon_state][tram_part.idle_platform.name]_idle" - update_appearance(UPDATE_ICON) - -/** - * Finds the tram from the console - * - * Locates tram parts in the lift global list after everything is done. - */ -/obj/machinery/computer/tram_controls/proc/find_tram() - for(var/datum/lift_master/lift as anything in GLOB.active_lifts_by_type[TRAM_LIFT_ID]) - if(lift.specific_lift_id == specific_lift_id) - tram_ref = WEAKREF(lift) - -/obj/machinery/computer/tram_controls/ui_state(mob/user) - return GLOB.not_incapacitated_state - -/obj/machinery/computer/tram_controls/ui_status(mob/user,/datum/tgui/ui) - var/datum/lift_master/tram/tram = tram_ref?.resolve() - - if(tram?.travelling) - return UI_CLOSE - if(!in_range(user, src) && !isobserver(user)) - return UI_CLOSE - return ..() - -/obj/machinery/computer/tram_controls/ui_interact(mob/user, datum/tgui/ui) - . = ..() - if(!user.can_read(src, reading_check_flags = READING_CHECK_LITERACY)) - try_illiterate_movement(user) - return - ui = SStgui.try_update_ui(user, src, ui) - if(!ui) - ui = new(user, src, "TramControl", name) - ui.open() - -/// Traverse to a random location after some time -/obj/machinery/computer/tram_controls/proc/try_illiterate_movement(mob/user) - var/datum/lift_master/tram/tram_lift = tram_ref?.resolve() - if (!tram_lift || tram_lift.travelling) - return - user.visible_message(span_notice("[user] starts mashing buttons at random!")) - if(!do_after(user, 5 SECONDS, target = src)) - return - if (!tram_lift || tram_lift.travelling) - to_chat(user, span_warning("The screen displays a flashing error message, but you can't comprehend it.")) - return // Broke or started moving during progress bar - var/list/all_destinations = GLOB.tram_landmarks[specific_lift_id] || list() - var/list/possible_destinations = all_destinations.Copy() - tram_lift.idle_platform - if (!length(possible_destinations)) - to_chat(user, span_warning("The screen displays a flashing error message, but you can't comprehend it.")) - return // No possible places to end up - try_send_tram(pick(possible_destinations)) - -/obj/machinery/computer/tram_controls/ui_data(mob/user) - var/datum/lift_master/tram/tram_lift = tram_ref?.resolve() - var/list/data = list() - data["moving"] = tram_lift?.travelling - data["broken"] = tram_lift ? FALSE : TRUE - var/obj/effect/landmark/tram/current_loc = tram_lift?.idle_platform - if(current_loc) - data["tram_location"] = current_loc.name - return data - -/obj/machinery/computer/tram_controls/ui_static_data(mob/user) - var/list/data = list() - data["destinations"] = get_destinations() - return data - -/** - * Finds the destinations for the tram console gui - * - * Pulls tram landmarks from the landmark gobal list - * and uses those to show the proper icons and destination - * names for the tram console gui. - */ -/obj/machinery/computer/tram_controls/proc/get_destinations() - . = list() - for(var/obj/effect/landmark/tram/destination as anything in GLOB.tram_landmarks[specific_lift_id]) - var/list/this_destination = list() - this_destination["name"] = destination.name - this_destination["dest_icons"] = destination.tgui_icons - this_destination["id"] = destination.platform_code - . += list(this_destination) - -/obj/machinery/computer/tram_controls/ui_act(action, params) - . = ..() - if (.) - return - - switch (action) - if ("send") - var/obj/effect/landmark/tram/destination_platform - for (var/obj/effect/landmark/tram/destination as anything in GLOB.tram_landmarks[specific_lift_id]) - if(destination.platform_code == params["destination"]) - destination_platform = destination - break - - if (!destination_platform) - return FALSE - - return try_send_tram(destination_platform) - -/// Attempts to sends the tram to the given destination -/obj/machinery/computer/tram_controls/proc/try_send_tram(obj/effect/landmark/tram/destination_platform) - var/datum/lift_master/tram/tram_part = tram_ref?.resolve() - if(!tram_part) - return FALSE - if(tram_part.controls_locked || tram_part.travelling) // someone else started already - return FALSE - if(!tram_part.tram_travel(destination_platform)) - return FALSE // lift_master failure - say("The next station is: [destination_platform.name]") - update_appearance() - return TRUE - -/obj/machinery/computer/tram_controls/proc/update_tram_display(obj/effect/landmark/tram/idle_platform, travelling) - SIGNAL_HANDLER - var/datum/lift_master/tram/tram_part = tram_ref?.resolve() - if(travelling) - icon_screen = "[base_icon_state][tram_part.idle_platform.name]_active" - else - icon_screen = "[base_icon_state][tram_part.idle_platform.name]_idle" - update_appearance(UPDATE_ICON) - return PROCESS_KILL - -/obj/machinery/computer/tram_controls/power_change() // Change tram operating status on power loss/recovery - . = ..() - var/datum/lift_master/tram/tram_part = tram_ref?.resolve() - update_operating() - if(tram_part) - if(!tram_part.travelling) - if(is_operational) - for(var/obj/machinery/crossing_signal/xing as anything in GLOB.tram_signals) - xing.set_signal_state(XING_STATE_MALF, TRUE) - for(var/obj/machinery/destination_sign/desto as anything in GLOB.tram_signs) - desto.icon_state = "[desto.base_icon_state][DESTINATION_OFF]" - desto.update_appearance() - else - for(var/obj/machinery/crossing_signal/xing as anything in GLOB.tram_signals) - xing.set_signal_state(XING_STATE_MALF, TRUE) - for(var/obj/machinery/destination_sign/desto as anything in GLOB.tram_signs) - desto.icon_state = "[desto.base_icon_state][DESTINATION_NOT_IN_SERVICE]" - desto.update_appearance() - -/obj/machinery/computer/tram_controls/proc/update_operating() // Pass the operating status from the controls to the lift_master - var/datum/lift_master/tram/tram_part = tram_ref?.resolve() - if(tram_part) - if(machine_stat & NOPOWER) - tram_part.is_operational = FALSE - else - tram_part.is_operational = TRUE - -/obj/item/circuit_component/tram_controls - display_name = "Tram Controls" - - /// The destination to go - var/datum/port/input/new_destination - - /// The trigger to send the tram - var/datum/port/input/trigger_move - - /// The current location - var/datum/port/output/location - - /// Whether or not the tram is moving - var/datum/port/output/travelling_output - - /// The tram controls computer (/obj/machinery/computer/tram_controls) - var/obj/machinery/computer/tram_controls/computer - -/obj/item/circuit_component/tram_controls/populate_ports() - new_destination = add_input_port("Destination", PORT_TYPE_STRING, trigger = null) - trigger_move = add_input_port("Send Tram", PORT_TYPE_SIGNAL) - - location = add_output_port("Location", PORT_TYPE_STRING) - travelling_output = add_output_port("Travelling", PORT_TYPE_NUMBER) - -/obj/item/circuit_component/tram_controls/register_usb_parent(atom/movable/shell) - . = ..() - if (istype(shell, /obj/machinery/computer/tram_controls)) - computer = shell - var/datum/lift_master/tram/tram_part = computer.tram_ref?.resolve() - RegisterSignal(tram_part, COMSIG_TRAM_SET_TRAVELLING, PROC_REF(on_tram_set_travelling)) - RegisterSignal(tram_part, COMSIG_TRAM_TRAVEL, PROC_REF(on_tram_travel)) - -/obj/item/circuit_component/tram_controls/unregister_usb_parent(atom/movable/shell) - var/datum/lift_master/tram/tram_part = computer.tram_ref?.resolve() - computer = null - UnregisterSignal(tram_part, list(COMSIG_TRAM_SET_TRAVELLING, COMSIG_TRAM_TRAVEL)) - return ..() - -/obj/item/circuit_component/tram_controls/input_received(datum/port/input/port) - if (!COMPONENT_TRIGGERED_BY(trigger_move, port)) - return - - if (isnull(computer)) - return - - if (!computer.powered()) - return - - var/destination - for(var/obj/effect/landmark/tram/possible_destination as anything in GLOB.tram_landmarks[computer.specific_lift_id]) - if(possible_destination.name == new_destination.value) - destination = possible_destination - break - - if (!destination) - return - - computer.try_send_tram(destination) - -/obj/item/circuit_component/tram_controls/proc/on_tram_set_travelling(datum/source, travelling) - SIGNAL_HANDLER - travelling_output.set_output(travelling) - -/obj/item/circuit_component/tram_controls/proc/on_tram_travel(datum/source, obj/effect/landmark/tram/idle_platform, obj/effect/landmark/tram/destination_platform) - SIGNAL_HANDLER - location.set_output(destination_platform.name) - -/// Pedestrian crossing signal for tram -/obj/machinery/crossing_signal - name = "crossing signal" - desc = "Indicates to pedestrians if it's safe to cross the tracks." - icon = 'icons/obj/machines/crossing_signal.dmi' - base_icon_state = "crossing-" - plane = GAME_PLANE_UPPER - max_integrity = 250 - integrity_failure = 0.25 - idle_power_usage = BASE_MACHINE_IDLE_CONSUMPTION * 2.4 - active_power_usage = BASE_MACHINE_ACTIVE_CONSUMPTION * 0.74 - anchored = TRUE - density = FALSE - // pointless if it only takes 2 seconds to cross but updates every 2 seconds - subsystem_type = /datum/controller/subsystem/processing/fastprocess - light_range = 1.5 - light_power = 3 - light_color = LIGHT_COLOR_BABY_BLUE - luminosity = 1 - - /// green, amber, or red for tram, blue if it's emag, tram missing, etc. - var/signal_state = XING_STATE_MALF - /// The ID of the tram we control - var/tram_id = MAIN_STATION_TRAM - /// Weakref to the tram piece we control - var/datum/weakref/tram_ref - - /** Proximity thresholds for crossing signal states - * - * The proc that checks the distance between the tram and crossing signal uses these vars to determine the distance between tram and signal to change - * colors. The numbers are specifically set for Tramstation. If we get another map with crossing signals we'll have to probably subtype it or something. - * If the value is set too high, it will cause the lights to turn red when the tram arrives at another station. You want to optimize the amount of - * warning without turning it red unnessecarily. - * - * Red: decent chance of getting hit, but if you're quick it's a decent gamble. - * Amber: slow people may be in danger. - */ - var/amber_distance_threshold = XING_DISTANCE_AMBER - var/red_distance_threshold = XING_DISTANCE_RED - /// If the signal is facing east or west - var/signal_direction - /// Inbound station - var/inbound - /// Outbound station - var/outbound - /// Is the signal malfunctioning? - var/malfunctioning = FALSE - -/** Crossing signal subtypes - * - * Each map will have a different amount of tiles between stations, so adjust the signals here based on the map. - * The distance is calculated from the bottom left corner of the tram, - * so signals on the east side have their distance reduced by the tram length, in this case 10 for Tramstation. -*/ -/obj/machinery/crossing_signal/northwest - icon_state = "crossing-base-right" - signal_direction = XING_SIGNAL_DIRECTION_WEST - pixel_x = -32 - pixel_y = -1 - -/obj/machinery/crossing_signal/northeast - icon_state = "crossing-base-left" - signal_direction = XING_SIGNAL_DIRECTION_EAST - pixel_x = -2 - pixel_y = -1 - -/obj/machinery/crossing_signal/southwest - icon_state = "crossing-base-right" - signal_direction = XING_SIGNAL_DIRECTION_WEST - pixel_x = -32 - pixel_y = 20 - -/obj/machinery/crossing_signal/southeast - icon_state = "crossing-base-left" - signal_direction = XING_SIGNAL_DIRECTION_EAST - pixel_x = -2 - pixel_y = 20 - -/obj/machinery/static_signal - name = "crossing signal" - desc = "Indicates to pedestrians if it's safe to cross the tracks." - icon = 'icons/obj/machines/crossing_signal.dmi' - icon_state = "static-left-on" - base_icon_state = "static-left-" - plane = GAME_PLANE_UPPER - max_integrity = 250 - integrity_failure = 0.25 - idle_power_usage = BASE_MACHINE_IDLE_CONSUMPTION * 2.4 - active_power_usage = BASE_MACHINE_ACTIVE_CONSUMPTION * 0.74 - anchored = TRUE - density = FALSE - light_range = 1.5 - light_power = 3 - light_color = COLOR_VIBRANT_LIME - luminosity = 1 - -/obj/machinery/static_signal/northwest - icon_state = "static-right-on" - base_icon_state = "static-right-" - pixel_x = -32 - pixel_y = -1 - -/obj/machinery/static_signal/northeast - pixel_x = -2 - pixel_y = -1 - -/obj/machinery/static_signal/southwest - icon_state = "static-right-on" - base_icon_state = "static-right-" - pixel_x = -32 - pixel_y = 20 - -/obj/machinery/static_signal/southeast - pixel_x = -2 - pixel_y = 20 - -/obj/machinery/crossing_signal/Initialize(mapload) - . = ..() - return INITIALIZE_HINT_LATELOAD - -/obj/machinery/crossing_signal/LateInitialize() - . = ..() - find_tram() - - var/datum/lift_master/tram/tram_part = tram_ref?.resolve() - if(tram_part) - RegisterSignal(tram_part, COMSIG_TRAM_SET_TRAVELLING, PROC_REF(on_tram_travelling)) - GLOB.tram_signals += src - -/obj/machinery/crossing_signal/Destroy() - GLOB.tram_signals -= src - . = ..() - - var/datum/lift_master/tram/tram_part = tram_ref?.resolve() - if(tram_part) - UnregisterSignal(tram_part, COMSIG_TRAM_SET_TRAVELLING) - -/obj/machinery/crossing_signal/emag_act(mob/user, obj/item/card/emag/emag_card) - if(obj_flags & EMAGGED) - return FALSE - balloon_alert(user, "disabled motion sensors") - if(signal_state != XING_STATE_MALF) - set_signal_state(XING_STATE_MALF) - obj_flags |= EMAGGED - return TRUE - -/obj/machinery/crossing_signal/proc/start_malfunction() - if(signal_state != XING_STATE_MALF) - malfunctioning = TRUE - set_signal_state(XING_STATE_MALF) - -/obj/machinery/crossing_signal/proc/end_malfunction() - if(obj_flags & EMAGGED) - return - - malfunctioning = FALSE - process() - -/obj/machinery/crossing_signal/proc/temp_malfunction() - start_malfunction() - addtimer(CALLBACK(src, PROC_REF(end_malfunction)), 15 SECONDS) - -/** - * Finds the tram, just like the tram computer - * - * Locates tram parts in the lift global list after everything is done. - */ -/obj/machinery/crossing_signal/proc/find_tram() - for(var/datum/lift_master/tram/tram as anything in GLOB.active_lifts_by_type[TRAM_LIFT_ID]) - if(tram.specific_lift_id != tram_id) - continue - tram_ref = WEAKREF(tram) - break - -/** - * Only process if the tram is actually moving - */ -/obj/machinery/crossing_signal/proc/on_tram_travelling(datum/source, travelling) - SIGNAL_HANDLER - - update_operating() - -/obj/machinery/crossing_signal/on_set_is_operational() - . = ..() - - update_operating() - -/** - * Update processing state. - * - * Returns whether we are still processing. - */ -/obj/machinery/crossing_signal/proc/update_operating() - - use_power(idle_power_usage) - - // Emagged crossing signals don't update - if(obj_flags & EMAGGED) - return - // Malfunctioning signals don't update - if(malfunctioning) - return - // Immediately process for snappy feedback - var/should_process = process() != PROCESS_KILL - if(should_process) - begin_processing() - return - end_processing() - -/obj/machinery/crossing_signal/process() - - var/datum/lift_master/tram/tram = tram_ref?.resolve() - - // Check for stopped states. - if(!tram || !is_operational || !tram.is_operational || !inbound || !outbound) - // Tram missing, we lost power, or something isn't right - // Throw the error message (blue) - set_signal_state(XING_STATE_MALF, force = !is_operational) - return PROCESS_KILL - - use_power(active_power_usage) - - var/obj/structure/industrial_lift/tram/tram_part = tram.return_closest_platform_to(src) - - if(QDELETED(tram_part)) - set_signal_state(XING_STATE_MALF, force = !is_operational) - return PROCESS_KILL - - // Everything will be based on position and travel direction - var/signal_pos - var/tram_pos - var/tram_velocity_sign // 1 for positive axis movement, -1 for negative - // Try to be agnostic about N-S vs E-W movement - if(tram.travel_direction & (NORTH|SOUTH)) - signal_pos = y - tram_pos = tram_part.y - tram_velocity_sign = tram.travel_direction & NORTH ? 1 : -1 - else - signal_pos = x - tram_pos = tram_part.x - tram_velocity_sign = tram.travel_direction & EAST ? 1 : -1 - - // How far away are we? negative if already passed. - var/approach_distance = tram_velocity_sign * (signal_pos - (tram_pos + (XING_DEFAULT_TRAM_LENGTH * 0.5))) - - // Check for stopped state. - // Will kill the process since tram starting up will restart process. - if(!tram.travelling) - set_signal_state(XING_STATE_GREEN) - return PROCESS_KILL - - // Check if tram is driving away from us. - if(approach_distance < 0) - // driving away. Green. In fact, in order to reverse, it'll have to stop, so let's go ahead and kill. - set_signal_state(XING_STATE_GREEN) - return PROCESS_KILL - - // Check the tram's terminus station. - // INBOUND 1 < 2 < 3 - // OUTBOUND 1 > 2 > 3 - if(tram.travel_direction & WEST && inbound < tram.idle_platform.platform_code) - set_signal_state(XING_STATE_GREEN) - return PROCESS_KILL - if(tram.travel_direction & EAST && outbound > tram.idle_platform.platform_code) - set_signal_state(XING_STATE_GREEN) - return PROCESS_KILL - - // Finally the interesting part where it's ACTUALLY approaching - if(approach_distance <= red_distance_threshold) - set_signal_state(XING_STATE_RED) - return - if(approach_distance <= amber_distance_threshold) - set_signal_state(XING_STATE_AMBER) - return - set_signal_state(XING_STATE_GREEN) - -/** - * Set the signal state and update appearance. - * - * Arguments: - * new_state - the new state (XING_STATE_RED, etc) - * force_update - force appearance to update even if state didn't change. - */ -/obj/machinery/crossing_signal/proc/set_signal_state(new_state, force = FALSE) - if(new_state == signal_state && !force) - return - - signal_state = new_state - update_appearance() - -/obj/machinery/crossing_signal/update_appearance(updates) - . = ..() - - if(!is_operational) - set_light(l_on = FALSE) - return - - var/new_color - switch(signal_state) - if(XING_STATE_MALF) - new_color = LIGHT_COLOR_BABY_BLUE - if(XING_STATE_GREEN) - new_color = LIGHT_COLOR_VIVID_GREEN - if(XING_STATE_AMBER) - new_color = LIGHT_COLOR_BRIGHT_YELLOW - else - new_color = LIGHT_COLOR_FLARE - - set_light(l_on = TRUE, l_color = new_color) - -/obj/machinery/crossing_signal/update_overlays() - . = ..() - - if(!is_operational) - return - - if(!signal_direction) //Base type doesnt have directions set - return - - var/lights_overlay = "[base_icon_state][signal_direction][signal_state]" - - . += mutable_appearance(icon, lights_overlay) - . += emissive_appearance(icon, "[lights_overlay]e", offset_spokesman = src, alpha = src.alpha) - -/obj/machinery/static_signal/power_change() - ..() - if(!is_operational) - icon_state = "[base_icon_state]off" - set_light(l_on = FALSE) - return - - icon_state = "[base_icon_state]on" - set_light(l_on = TRUE) - -/obj/machinery/destination_sign - name = "destination sign" - desc = "A display to show you what direction the tram is travelling." - icon = 'icons/obj/machines/tram_sign.dmi' - icon_state = "desto_off" - base_icon_state = "desto_" - idle_power_usage = BASE_MACHINE_IDLE_CONSUMPTION * 1.2 - active_power_usage = BASE_MACHINE_ACTIVE_CONSUMPTION * 0.47 - anchored = TRUE - density = FALSE - subsystem_type = /datum/controller/subsystem/processing/fastprocess - - /// The ID of the tram we're indicating - var/tram_id = MAIN_STATION_TRAM - /// Weakref to the tram piece we indicate - var/datum/weakref/tram_ref - /// The last destination we were at - var/previous_destination - /// The light mask overlay we use - var/light_mask - /// Is this sign malfunctioning? - var/malfunctioning = FALSE - /// A default list of possible sign states - var/static/list/sign_states = list() - -/obj/machinery/destination_sign/north - layer = BELOW_OBJ_LAYER - -/obj/machinery/destination_sign/south - plane = WALL_PLANE_UPPER - layer = BELOW_OBJ_LAYER - -/obj/machinery/destination_sign/indicator - icon_state = "indicator_off" - base_icon_state = "indicator_" - light_range = 1.5 - light_color = LIGHT_COLOR_DARK_BLUE - light_mask = "indicator_off_e" - -/obj/machinery/destination_sign/Initialize(mapload) - . = ..() - return INITIALIZE_HINT_LATELOAD - -/obj/machinery/destination_sign/LateInitialize() - . = ..() - find_tram() - - var/datum/lift_master/tram/tram_part = tram_ref?.resolve() - if(tram_part) - RegisterSignal(tram_part, COMSIG_TRAM_SET_TRAVELLING, PROC_REF(on_tram_travelling)) - GLOB.tram_signs += src - - sign_states = list( - "[DESTINATION_WEST_ACTIVE]", - "[DESTINATION_WEST_IDLE]", - "[DESTINATION_EAST_ACTIVE]", - "[DESTINATION_EAST_IDLE]", - "[DESTINATION_CENTRAL_IDLE]", - "[DESTINATION_CENTRAL_EASTBOUND_ACTIVE]", - "[DESTINATION_CENTRAL_WESTBOUND_ACTIVE]", - ) - -/obj/machinery/destination_sign/Destroy() - GLOB.tram_signs -= src - . = ..() - - var/datum/lift_master/tram/tram_part = tram_ref?.resolve() - if(tram_part) - UnregisterSignal(tram_part, COMSIG_TRAM_SET_TRAVELLING) - -/obj/machinery/destination_sign/proc/find_tram() - for(var/datum/lift_master/tram/tram as anything in GLOB.active_lifts_by_type[TRAM_LIFT_ID]) - if(tram.specific_lift_id != tram_id) - continue - tram_ref = WEAKREF(tram) - break - -/obj/machinery/destination_sign/proc/on_tram_travelling(datum/source, travelling) - SIGNAL_HANDLER - update_sign() - INVOKE_ASYNC(src, TYPE_PROC_REF(/datum, process)) - -/obj/machinery/destination_sign/proc/update_operating() - // Immediately process for snappy feedback - var/should_process = process() != PROCESS_KILL - if(should_process) - begin_processing() - return - end_processing() - -/obj/machinery/destination_sign/proc/update_sign() - var/datum/lift_master/tram/tram = tram_ref?.resolve() - - if(!tram || !tram.is_operational) - icon_state = "[base_icon_state][DESTINATION_NOT_IN_SERVICE]" - light_mask = "[base_icon_state][DESTINATION_NOT_IN_SERVICE]_e" - update_appearance() - return PROCESS_KILL - - use_power(active_power_usage) - - if(malfunctioning) - icon_state = "[base_icon_state][pick(sign_states)]" - light_mask = "[base_icon_state][pick(sign_states)]_e" - update_appearance() - return PROCESS_KILL - - if(!tram.travelling) - if(istype(tram.idle_platform, /obj/effect/landmark/tram/platform/tramstation/west)) - icon_state = "[base_icon_state][DESTINATION_WEST_IDLE]" - light_mask = "[base_icon_state][DESTINATION_WEST_IDLE]_e" - previous_destination = tram.idle_platform - update_appearance() - return PROCESS_KILL - - if(istype(tram.idle_platform, /obj/effect/landmark/tram/platform/tramstation/central)) - icon_state = "[base_icon_state][DESTINATION_CENTRAL_IDLE]" - light_mask = "[base_icon_state][DESTINATION_CENTRAL_IDLE]_e" - previous_destination = tram.idle_platform - update_appearance() - return PROCESS_KILL - - if(istype(tram.idle_platform, /obj/effect/landmark/tram/platform/tramstation/east)) - icon_state = "[base_icon_state][DESTINATION_EAST_IDLE]" - light_mask = "[base_icon_state][DESTINATION_EAST_IDLE]_e" - previous_destination = tram.idle_platform - update_appearance() - return PROCESS_KILL - - if(istype(tram.idle_platform, /obj/effect/landmark/tram/platform/tramstation/west)) - icon_state = "[base_icon_state][DESTINATION_WEST_ACTIVE]" - light_mask = "[base_icon_state][DESTINATION_WEST_ACTIVE]_e" - update_appearance() - return PROCESS_KILL - - if(istype(tram.idle_platform, /obj/effect/landmark/tram/platform/tramstation/central)) - if(istype(previous_destination, /obj/effect/landmark/tram/platform/tramstation/west)) - icon_state = "[base_icon_state][DESTINATION_CENTRAL_EASTBOUND_ACTIVE]" - light_mask = "[base_icon_state][DESTINATION_CENTRAL_EASTBOUND_ACTIVE]_e" - if(istype(previous_destination, /obj/effect/landmark/tram/platform/tramstation/east)) - icon_state = "[base_icon_state][DESTINATION_CENTRAL_WESTBOUND_ACTIVE]" - light_mask = "[base_icon_state][DESTINATION_CENTRAL_WESTBOUND_ACTIVE]_e" - update_appearance() - return PROCESS_KILL - - if(istype(tram.idle_platform, /obj/effect/landmark/tram/platform/tramstation/east)) - icon_state = "[base_icon_state][DESTINATION_EAST_ACTIVE]" - light_mask = "[base_icon_state][DESTINATION_EAST_ACTIVE]_e" - update_appearance() - return PROCESS_KILL - -/obj/machinery/destination_sign/update_overlays() - . = ..() - if(!light_mask) - return - - if(!(machine_stat & (NOPOWER|BROKEN)) && !panel_open) - . += emissive_appearance(icon, light_mask, src, alpha = alpha) - -/obj/machinery/button/tram - name = "tram request" - desc = "A button for calling the tram. It has a speakerbox in it with some internals." - base_icon_state = "tram" - icon_state = "tram" - light_color = LIGHT_COLOR_DARK_BLUE - can_alter_skin = FALSE - device_type = /obj/item/assembly/control/tram - req_access = list() - id = 1 - /// The specific lift id of the tram we're calling. - var/lift_id = MAIN_STATION_TRAM - -/obj/machinery/button/tram/setup_device() - var/obj/item/assembly/control/tram/tram_device = device - tram_device.initial_id = id - tram_device.specific_lift_id = lift_id - return ..() - -/obj/machinery/button/tram/examine(mob/user) - . = ..() - . += span_notice("There's a small inscription on the button...") - . += span_notice("THIS CALLS THE TRAM! IT DOES NOT OPERATE IT! The console on the tram tells it where to go!") - -MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/computer/tram_controls, 0) -MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/destination_sign/indicator, 32) -MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/button/tram, 32) diff --git a/code/modules/industrial_lift/tram/tram_override_objects.dm b/code/modules/industrial_lift/tram/tram_override_objects.dm deleted file mode 100644 index 57a0368d6bc..00000000000 --- a/code/modules/industrial_lift/tram/tram_override_objects.dm +++ /dev/null @@ -1,28 +0,0 @@ -/** - * the tram has a few objects mapped onto it at roundstart, by default many of those objects have unwanted properties - * for example grilles and windows have the atmos_sensitive element applied to them, which makes them register to - * themselves moving to re register signals onto the turf via connect_loc. this is bad and dumb since it makes the tram - * more expensive to move. - * - * if you map something on to the tram, make SURE if possible that it doesnt have anything reacting to its own movement - * it will make the tram more expensive to move and we dont want that because we dont want to return to the days where - * the tram took a third of the tick per movement when its just carrying its default mapped in objects - */ - -/obj/structure/grille/tram/Initialize(mapload) - . = ..() - RemoveElement(/datum/element/atmos_sensitive, mapload) - //atmos_sensitive applies connect_loc which 1. reacts to movement in order to 2. unregister and register signals to - //the old and new locs. we dont want that, pretend these grilles and windows are plastic or something idk - -/obj/structure/window/reinforced/tram/Initialize(mapload, direct) - . = ..() - RemoveElement(/datum/element/atmos_sensitive, mapload) - -/turf/open/floor/glass/reinforced/tram/Initialize(mapload) - . = ..() - RemoveElement(/datum/element/atmos_sensitive, mapload) - -/turf/open/floor/glass/reinforced/tram - name = "tram bridge" - desc = "It shakes a bit when you step, but lets you cross between sides quickly!" diff --git a/code/modules/industrial_lift/tram/tram_remote.dm b/code/modules/industrial_lift/tram/tram_remote.dm deleted file mode 100644 index abb3b430e18..00000000000 --- a/code/modules/industrial_lift/tram/tram_remote.dm +++ /dev/null @@ -1,150 +0,0 @@ -#define TRAMCTRL_FAST 1 -#define TRAMCTRL_SAFE 0 - -/obj/item/tram_remote - icon_state = "tramremote_nis" - inhand_icon_state = "electronic" - lefthand_file = 'icons/mob/inhands/items/devices_lefthand.dmi' - righthand_file = 'icons/mob/inhands/items/devices_righthand.dmi' - icon = 'icons/obj/device.dmi' - name = "tram remote" - desc = "A remote control that can be linked to a tram. This can only go well." - w_class = WEIGHT_CLASS_TINY - ///desired tram direction - var/direction = INBOUND - ///fast and fun, or safe and boring - var/mode = TRAMCTRL_FAST - ///weakref to the tram piece we control - var/datum/weakref/tram_ref - ///cooldown for the remote - COOLDOWN_DECLARE(tram_remote) - -/obj/item/tram_remote/Initialize(mapload) - . = ..() - register_context() - -/obj/item/tram_remote/add_context(atom/source, list/context, obj/item/held_item, mob/user) - if(!tram_ref) - context[SCREENTIP_CONTEXT_LMB] = "Link tram" - return CONTEXTUAL_SCREENTIP_SET - context[SCREENTIP_CONTEXT_LMB] = "Dispatch tram" - context[SCREENTIP_CONTEXT_RMB] = "Change direction" - context[SCREENTIP_CONTEXT_CTRL_LMB] = "Toggle door safeties" - return CONTEXTUAL_SCREENTIP_SET - -///set tram control direction -/obj/item/tram_remote/attack_self_secondary(mob/user) - switch(direction) - if(INBOUND) - direction = OUTBOUND - if(OUTBOUND) - direction = INBOUND - update_appearance() - balloon_alert(user, "[direction ? "< inbound" : "outbound >"]") - return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN - -///set safety bypass -/obj/item/tram_remote/CtrlClick(mob/user) - switch(mode) - if(TRAMCTRL_SAFE) - mode = TRAMCTRL_FAST - if(TRAMCTRL_FAST) - mode = TRAMCTRL_SAFE - update_appearance() - balloon_alert(user, "mode: [mode ? "fast" : "safe"]") - -/obj/item/tram_remote/examine(mob/user) - . = ..() - if(!tram_ref) - . += "There is an X showing on the display." - . += "Left-click a tram request button to link." - return - . += "The arrow on the display is pointing [direction ? "inbound" : "outbound"]." - . += "The rapid mode light is [mode ? "on" : "off"]." - if (!COOLDOWN_FINISHED(src, tram_remote)) - . += "The number on the display shows [DisplayTimeText(COOLDOWN_TIMELEFT(src, tram_remote), 1)]." - else - . += "The display indicates ready." - . += "Left-click to dispatch tram." - . += "Right-click to toggle direction." - . += "Ctrl-click to toggle safety bypass." - -/obj/item/tram_remote/update_icon_state() - . = ..() - if(!tram_ref) - icon_state = "tramremote_nis" - return - switch(direction) - if(INBOUND) - icon_state = "tramremote_ib" - if(OUTBOUND) - icon_state = "tramremote_ob" - -/obj/item/tram_remote/update_overlays() - . = ..() - if(mode == TRAMCTRL_FAST) - . += mutable_appearance(icon, "tramremote_emag") - -/obj/item/tram_remote/attack_self(mob/user) - if (!COOLDOWN_FINISHED(src, tram_remote)) - balloon_alert(user, "cooldown: [DisplayTimeText(COOLDOWN_TIMELEFT(src, tram_remote), 1)]") - return FALSE - if(try_force_tram(user)) - COOLDOWN_START(src, tram_remote, 2 MINUTES) - -///send our selected commands to the tram -/obj/item/tram_remote/proc/try_force_tram(mob/user) - var/datum/lift_master/tram/tram_part = tram_ref?.resolve() - if(!tram_part) - balloon_alert(user, "no tram linked!") - return FALSE - if(tram_part.controls_locked || tram_part.travelling) // someone else started already - balloon_alert(user, "tram busy!") - return FALSE - var/tram_id = tram_part.specific_lift_id - var/destination_platform = null - var/platform = 0 - switch(direction) - if(INBOUND) - platform = clamp(tram_part.idle_platform.platform_code - 1, 1, INFINITY) - if(OUTBOUND) - platform = clamp(tram_part.idle_platform.platform_code + 1, 1, INFINITY) - if(platform == tram_part.idle_platform.platform_code) - balloon_alert(user, "invalid command!") - return FALSE - for (var/obj/effect/landmark/tram/destination as anything in GLOB.tram_landmarks[tram_id]) - if(destination.platform_code == platform) - destination_platform = destination - break - if(!destination_platform) - balloon_alert(user, "invalid command!") - return FALSE - else - switch(mode) - if(TRAMCTRL_FAST) - tram_part.tram_travel(destination_platform, rapid = TRUE) - if(TRAMCTRL_SAFE) - tram_part.tram_travel(destination_platform, rapid = FALSE) - balloon_alert(user, "tram dispatched") - return TRUE - -/obj/item/tram_remote/afterattack(atom/target, mob/user) - link_tram(user, target) - -/obj/item/tram_remote/proc/link_tram(mob/user, atom/target) - var/obj/machinery/button/tram/smacked_device = target - if(!istype(smacked_device, /obj/machinery/button/tram)) - return - tram_ref = null - for(var/datum/lift_master/lift as anything in GLOB.active_lifts_by_type[TRAM_LIFT_ID]) - if(lift.specific_lift_id == smacked_device.lift_id) - tram_ref = WEAKREF(lift) - break - if(tram_ref) - balloon_alert(user, "tram linked") - else - balloon_alert(user, "link failed!") - update_appearance() - -#undef TRAMCTRL_FAST -#undef TRAMCTRL_SAFE diff --git a/code/modules/industrial_lift/tram/tram_structures.dm b/code/modules/industrial_lift/tram/tram_structures.dm deleted file mode 100644 index 81c80e135ae..00000000000 --- a/code/modules/industrial_lift/tram/tram_structures.dm +++ /dev/null @@ -1,22 +0,0 @@ -/obj/structure/chair/sofa/bench/tram - name = "bench" - desc = "Perfectly designed to be comfortable to sit on, and hellish to sleep on." - icon_state = "bench_middle" - greyscale_config = /datum/greyscale_config/bench_middle - greyscale_colors = "#00CCFF" - -/obj/structure/chair/sofa/bench/tram/left - icon_state = "bench_left" - greyscale_config = /datum/greyscale_config/bench_left - -/obj/structure/chair/sofa/bench/tram/right - icon_state = "bench_right" - greyscale_config = /datum/greyscale_config/bench_right - -/obj/structure/chair/sofa/bench/tram/corner - icon_state = "bench_corner" - greyscale_config = /datum/greyscale_config/bench_corner - -/obj/structure/chair/sofa/bench/tram/solo - icon_state = "bench_solo" - greyscale_config = /datum/greyscale_config/bench_solo diff --git a/code/modules/industrial_lift/tram/tram_walls.dm b/code/modules/industrial_lift/tram/tram_walls.dm deleted file mode 100644 index c8bf7e970b5..00000000000 --- a/code/modules/industrial_lift/tram/tram_walls.dm +++ /dev/null @@ -1,326 +0,0 @@ -/* - * Tram Walls - */ -/obj/structure/tramwall - name = "wall" - desc = "A huge chunk of metal used to separate rooms." - anchored = TRUE - icon = 'icons/turf/walls/wall.dmi' - icon_state = "wall-0" - base_icon_state = "wall" - layer = LOW_OBJ_LAYER - density = TRUE - opacity = FALSE - max_integrity = 100 - smoothing_flags = SMOOTH_BITMASK - smoothing_groups = SMOOTH_GROUP_WALLS + SMOOTH_GROUP_CLOSED_TURFS - canSmoothWith = SMOOTH_GROUP_WALLS - can_be_unanchored = FALSE - can_atmos_pass = ATMOS_PASS_DENSITY - rad_insulation = RAD_MEDIUM_INSULATION - material_flags = MATERIAL_EFFECTS - var/mineral = /obj/item/stack/sheet/iron - var/mineral_amount = 2 - var/tram_wall_type = /obj/structure/tramwall - var/girder_type = /obj/structure/girder/tram - var/slicing_duration = 100 - -/obj/structure/tramwall/Initialize(mapload) - AddElement(/datum/element/blocks_explosives) - . = ..() - var/obj/item/stack/initialized_mineral = new mineral - set_custom_materials(initialized_mineral.mats_per_unit, mineral_amount) - qdel(initialized_mineral) - air_update_turf(TRUE, TRUE) - -/obj/structure/tramwall/attackby(obj/item/welder, mob/user, params) - if(welder.tool_behaviour == TOOL_WELDER) - if(!welder.tool_start_check(user, amount=round(slicing_duration / 50))) - return FALSE - - to_chat(user, span_notice("You begin slicing through the outer plating...")) - if(welder.use_tool(src, user, slicing_duration, volume=100)) - to_chat(user, span_notice("You remove the outer plating.")) - dismantle(user, TRUE) - else - return ..() - -/obj/structure/tramwall/proc/dismantle(mob/user, disassembled=TRUE, obj/item/tool = null) - user.visible_message(span_notice("[user] dismantles the wall."), span_notice("You dismantle the wall.")) - if(tool) - tool.play_tool_sound(src, 100) - else - playsound(src, 'sound/items/welder.ogg', 100, TRUE) - deconstruct(disassembled) - -/obj/structure/tramwall/deconstruct(disassembled = TRUE) - if(!(flags_1 & NODECONSTRUCT_1)) - if(disassembled) - new girder_type(loc) - if(mineral_amount) - for(var/i in 1 to mineral_amount) - new mineral(loc) - qdel(src) - -/obj/structure/tramwall/get_dumping_location() - return null - -/obj/structure/tramwall/examine_status(mob/user) - to_chat(user, span_notice("The outer plating is welded firmly in place.")) - return null - - -/* - * Other misc tramwall types - */ - -/obj/structure/tramwall/titanium - name = "wall" - desc = "A light-weight titanium wall used in shuttles." - icon = 'icons/turf/walls/tram_wall.dmi' - icon_state = "shuttle_wall-0" - base_icon_state = "shuttle_wall" - mineral = /obj/item/stack/sheet/mineral/titanium - tram_wall_type = /obj/structure/tramwall/titanium - smoothing_flags = SMOOTH_BITMASK - smoothing_groups = SMOOTH_GROUP_TITANIUM_WALLS + SMOOTH_GROUP_WALLS - canSmoothWith = SMOOTH_GROUP_SHUTTLE_PARTS + SMOOTH_GROUP_AIRLOCK + SMOOTH_GROUP_TITANIUM_WALLS - -/obj/structure/tramwall/plastitanium - name = "wall" - desc = "An evil wall of plasma and titanium." - icon = 'icons/turf/walls/plastitanium_wall.dmi' - icon_state = "plastitanium_wall-0" - base_icon_state = "plastitanium_wall" - mineral = /obj/item/stack/sheet/mineral/plastitanium - tram_wall_type = /obj/structure/tramwall/plastitanium - smoothing_flags = SMOOTH_BITMASK - smoothing_groups = SMOOTH_GROUP_PLASTITANIUM_WALLS + SMOOTH_GROUP_WALLS - canSmoothWith = SMOOTH_GROUP_SHUTTLE_PARTS + SMOOTH_GROUP_AIRLOCK + SMOOTH_GROUP_PLASTITANIUM_WALLS - -/obj/structure/tramwall/gold - name = "gold wall" - desc = "A wall with gold plating. Swag!" - icon = 'icons/turf/walls/gold_wall.dmi' - icon_state = "gold_wall-0" - base_icon_state = "gold_wall" - mineral = /obj/item/stack/sheet/mineral/gold - tram_wall_type = /obj/structure/tramwall/gold - explosion_block = 0 //gold is a soft metal you dingus. - smoothing_groups = SMOOTH_GROUP_GOLD_WALLS + SMOOTH_GROUP_WALLS + SMOOTH_GROUP_CLOSED_TURFS - canSmoothWith = SMOOTH_GROUP_GOLD_WALLS - custom_materials = list(/datum/material/gold = SHEET_MATERIAL_AMOUNT*2) - -/obj/structure/tramwall/silver - name = "silver wall" - desc = "A wall with silver plating. Shiny!" - icon = 'icons/turf/walls/silver_wall.dmi' - icon_state = "silver_wall-0" - base_icon_state = "silver_wall" - mineral = /obj/item/stack/sheet/mineral/silver - tram_wall_type = /obj/structure/tramwall/silver - smoothing_flags = SMOOTH_BITMASK - smoothing_groups = SMOOTH_GROUP_SILVER_WALLS + SMOOTH_GROUP_WALLS + SMOOTH_GROUP_CLOSED_TURFS - canSmoothWith = SMOOTH_GROUP_SILVER_WALLS - custom_materials = list(/datum/material/silver = SHEET_MATERIAL_AMOUNT*2) - -/obj/structure/tramwall/diamond - name = "diamond wall" - desc = "A wall with diamond plating. You monster." - icon = 'icons/turf/walls/diamond_wall.dmi' - icon_state = "diamond_wall-0" - base_icon_state = "diamond_wall" - mineral = /obj/item/stack/sheet/mineral/diamond - tram_wall_type = /obj/structure/tramwall/diamond - slicing_duration = 200 //diamond wall takes twice as much time to slice - max_integrity = 800 - explosion_block = 3 - smoothing_flags = SMOOTH_BITMASK - smoothing_groups = SMOOTH_GROUP_DIAMOND_WALLS + SMOOTH_GROUP_WALLS + SMOOTH_GROUP_CLOSED_TURFS - canSmoothWith = SMOOTH_GROUP_DIAMOND_WALLS - custom_materials = list(/datum/material/diamond = SHEET_MATERIAL_AMOUNT*2) - -/obj/structure/tramwall/bananium - name = "bananium wall" - desc = "A wall with bananium plating. Honk!" - icon = 'icons/turf/walls/bananium_wall.dmi' - icon_state = "bananium_wall-0" - base_icon_state = "bananium_wall" - mineral = /obj/item/stack/sheet/mineral/bananium - tram_wall_type = /obj/structure/tramwall/bananium - smoothing_flags = SMOOTH_BITMASK - smoothing_groups = SMOOTH_GROUP_BANANIUM_WALLS + SMOOTH_GROUP_WALLS + SMOOTH_GROUP_CLOSED_TURFS - canSmoothWith = SMOOTH_GROUP_BANANIUM_WALLS - custom_materials = list(/datum/material/bananium = SHEET_MATERIAL_AMOUNT*2) - -/obj/structure/tramwall/sandstone - name = "sandstone wall" - desc = "A wall with sandstone plating. Rough." - icon = 'icons/turf/walls/sandstone_wall.dmi' - icon_state = "sandstone_wall-0" - base_icon_state = "sandstone_wall" - mineral = /obj/item/stack/sheet/mineral/sandstone - tram_wall_type = /obj/structure/tramwall/sandstone - explosion_block = 0 - smoothing_flags = SMOOTH_BITMASK - smoothing_groups = SMOOTH_GROUP_SANDSTONE_WALLS + SMOOTH_GROUP_WALLS + SMOOTH_GROUP_CLOSED_TURFS - canSmoothWith = SMOOTH_GROUP_SANDSTONE_WALLS - custom_materials = list(/datum/material/sandstone = SHEET_MATERIAL_AMOUNT*2) - -/obj/structure/tramwall/uranium - article = "a" - name = "uranium wall" - desc = "A wall with uranium plating. This is probably a bad idea." - icon = 'icons/turf/walls/uranium_wall.dmi' - icon_state = "uranium_wall-0" - base_icon_state = "uranium_wall" - mineral = /obj/item/stack/sheet/mineral/uranium - tram_wall_type = /obj/structure/tramwall/uranium - smoothing_flags = SMOOTH_BITMASK - smoothing_groups = SMOOTH_GROUP_URANIUM_WALLS + SMOOTH_GROUP_WALLS + SMOOTH_GROUP_CLOSED_TURFS - canSmoothWith = SMOOTH_GROUP_URANIUM_WALLS - custom_materials = list(/datum/material/uranium = SHEET_MATERIAL_AMOUNT*2) - - /// Mutex to prevent infinite recursion when propagating radiation pulses - var/active = null - - /// The last time a radiation pulse was performed - var/last_event = 0 - -/obj/structure/tramwall/uranium/attackby(obj/item/W, mob/user, params) - radiate() - return ..() - -/obj/structure/tramwall/uranium/attack_hand(mob/user, list/modifiers) - radiate() - return ..() - -/obj/structure/tramwall/uranium/proc/radiate() - SIGNAL_HANDLER - if(active) - return - if(world.time <= last_event + 1.5 SECONDS) - return - active = TRUE - radiation_pulse( - src, - max_range = 3, - threshold = RAD_LIGHT_INSULATION, - chance = URANIUM_IRRADIATION_CHANCE, - minimum_exposure_time = URANIUM_RADIATION_MINIMUM_EXPOSURE_TIME, - ) - propagate_radiation_pulse() - last_event = world.time - active = FALSE - -/obj/structure/tramwall/plasma - name = "plasma wall" - desc = "A wall with plasma plating. This is definitely a bad idea." - icon = 'icons/turf/walls/plasma_wall.dmi' - icon_state = "plasma_wall-0" - base_icon_state = "plasma_wall" - mineral = /obj/item/stack/sheet/mineral/plasma - tram_wall_type = /obj/structure/tramwall/plasma - smoothing_flags = SMOOTH_BITMASK - smoothing_groups = SMOOTH_GROUP_PLASMA_WALLS + SMOOTH_GROUP_WALLS + SMOOTH_GROUP_CLOSED_TURFS - canSmoothWith = SMOOTH_GROUP_PLASMA_WALLS - custom_materials = list(/datum/material/plasma = SHEET_MATERIAL_AMOUNT*2) - -/obj/structure/tramwall/wood - name = "wooden wall" - desc = "A wall with wooden plating. Stiff." - icon = 'icons/turf/walls/wood_wall.dmi' - icon_state = "wood_wall-0" - base_icon_state = "wood_wall" - mineral = /obj/item/stack/sheet/mineral/wood - tram_wall_type = /obj/structure/tramwall/wood - explosion_block = 0 - smoothing_flags = SMOOTH_BITMASK - smoothing_groups = SMOOTH_GROUP_WOOD_WALLS + SMOOTH_GROUP_WALLS + SMOOTH_GROUP_CLOSED_TURFS - canSmoothWith = SMOOTH_GROUP_WOOD_WALLS - custom_materials = list(/datum/material/wood = SHEET_MATERIAL_AMOUNT*2) - -/obj/structure/tramwall/wood/attackby(obj/item/W, mob/user) - if(W.get_sharpness() && W.force) - var/duration = ((4.8 SECONDS) / W.force) * 2 //In seconds, for now. - if(istype(W, /obj/item/hatchet) || istype(W, /obj/item/fireaxe)) - duration /= 4 //Much better with hatchets and axes. - if(do_after(user, duration * (1 SECONDS), target=src)) //Into deciseconds. - dismantle(user, disassembled = FALSE, tool = W) - return - return ..() - -/obj/structure/tramwall/bamboo - name = "bamboo wall" - desc = "A wall with a bamboo finish." - icon = 'icons/turf/walls/bamboo_wall.dmi' - smoothing_flags = SMOOTH_BITMASK - smoothing_groups = SMOOTH_GROUP_WALLS + SMOOTH_GROUP_BAMBOO_WALLS + SMOOTH_GROUP_CLOSED_TURFS - canSmoothWith = SMOOTH_GROUP_BAMBOO_WALLS - mineral = /obj/item/stack/sheet/mineral/bamboo - tram_wall_type = /obj/structure/tramwall/bamboo - -/obj/structure/tramwall/iron - name = "rough iron wall" - desc = "A wall with rough iron plating." - icon = 'icons/turf/walls/iron_wall.dmi' - icon_state = "iron_wall-0" - base_icon_state = "iron_wall" - mineral = /obj/item/stack/rods - mineral_amount = 5 - tram_wall_type = /obj/structure/tramwall/iron - smoothing_flags = SMOOTH_BITMASK - smoothing_groups = SMOOTH_GROUP_IRON_WALLS + SMOOTH_GROUP_WALLS + SMOOTH_GROUP_CLOSED_TURFS - canSmoothWith = SMOOTH_GROUP_IRON_WALLS - custom_materials = list(/datum/material/iron = SHEET_MATERIAL_AMOUNT * 2.5) - -/obj/structure/tramwall/abductor - name = "alien wall" - desc = "A wall with alien alloy plating." - icon = 'icons/turf/walls/abductor_wall.dmi' - icon_state = "abductor_wall-0" - base_icon_state = "abductor_wall" - mineral = /obj/item/stack/sheet/mineral/abductor - tram_wall_type = /obj/structure/tramwall/abductor - slicing_duration = 200 //alien wall takes twice as much time to slice - explosion_block = 3 - smoothing_flags = SMOOTH_BITMASK - smoothing_groups = SMOOTH_GROUP_ABDUCTOR_WALLS + SMOOTH_GROUP_WALLS + SMOOTH_GROUP_CLOSED_TURFS - canSmoothWith = SMOOTH_GROUP_ABDUCTOR_WALLS - custom_materials = list(/datum/material/alloy/alien = SHEET_MATERIAL_AMOUNT*2) - -/obj/structure/tramwall/material - name = "wall" - desc = "A huge chunk of material used to separate rooms." - icon = 'icons/turf/walls/materialwall.dmi' - icon_state = "materialwall-0" - base_icon_state = "materialwall" - smoothing_flags = SMOOTH_BITMASK - smoothing_groups = SMOOTH_GROUP_WALLS + SMOOTH_GROUP_CLOSED_TURFS + SMOOTH_GROUP_MATERIAL_WALLS - canSmoothWith = SMOOTH_GROUP_MATERIAL_WALLS - material_flags = MATERIAL_EFFECTS | MATERIAL_ADD_PREFIX | MATERIAL_COLOR | MATERIAL_AFFECT_STATISTICS - -/obj/structure/tramwall/material/deconstruct(disassembled = TRUE) - if(!(flags_1 & NODECONSTRUCT_1)) - if(disassembled) - new girder_type(loc) - for(var/material in custom_materials) - var/datum/material/material_datum = material - new material_datum.sheet_type(loc, FLOOR(custom_materials[material_datum] / SHEET_MATERIAL_AMOUNT, 1)) - qdel(src) - -/obj/structure/tramwall/material/mat_update_desc(mat) - desc = "A huge chunk of [mat] used to separate rooms." - -/obj/structure/tramwall/material/update_icon(updates) - . = ..() - for(var/datum/material/material in custom_materials) - if(material.alpha < 255) - update_transparency_underlays() - return - -/obj/structure/tramwall/material/proc/update_transparency_underlays() - underlays.Cut() - var/mutable_appearance/girder_underlay = mutable_appearance('icons/obj/structures.dmi', "girder", layer = LOW_OBJ_LAYER-0.01) - girder_underlay.appearance_flags = RESET_ALPHA | RESET_COLOR - underlays += girder_underlay diff --git a/code/modules/industrial_lift/tram/tram_windows.dm b/code/modules/industrial_lift/tram/tram_windows.dm deleted file mode 100644 index 55ec5aa283f..00000000000 --- a/code/modules/industrial_lift/tram/tram_windows.dm +++ /dev/null @@ -1,73 +0,0 @@ -/obj/structure/window/reinforced/tram - name = "tram window" - desc = "A window made out of a titanium-silicate alloy. It looks tough to break. Is that a challenge?" - icon = 'icons/obj/smooth_structures/tram_window.dmi' - icon_state = "tram_mid" - smoothing_flags = SMOOTH_BITMASK|SMOOTH_BORDER_OBJECT - canSmoothWith = SMOOTH_GROUP_WINDOW_DIRECTIONAL_TRAM - smoothing_groups = SMOOTH_GROUP_WINDOW_DIRECTIONAL_TRAM - reinf = TRUE - heat_resistance = 1600 - armor_type = /datum/armor/window_tram - max_integrity = 100 - explosion_block = 0 - glass_type = /obj/item/stack/sheet/titaniumglass - rad_insulation = RAD_MEDIUM_INSULATION - glass_material_datum = /datum/material/alloy/titaniumglass - -/obj/structure/window/reinforced/tram/Initialize(mapload, direct) - . = ..() - setDir(dir) - -/obj/structure/window/reinforced/tram/setDir(new_dir) - . = ..() - if(fulltile) - return - if(dir & NORTH) - layer = LOW_ITEM_LAYER - else - layer = BELOW_OBJ_LAYER - if(dir & SOUTH) - SET_PLANE_IMPLICIT(src, WALL_PLANE_UPPER) - else - SET_PLANE_IMPLICIT(src, GAME_PLANE) - -/obj/structure/window/reinforced/tram/set_smoothed_icon_state(new_junction) - if(fulltile) - return ..() - smoothing_junction = new_junction - var/go_off = reverse_ndir(smoothing_junction) - var/smooth_left = (go_off & turn(dir, 90)) - var/smooth_right = (go_off & turn(dir, -90)) - if(smooth_left && smooth_right) - icon_state = "tram_mid" - else if (smooth_left) - icon_state = "tram_left" - else if (smooth_right) - icon_state = "tram_right" - else - icon_state = "tram_mid" - -/obj/structure/window/reinforced/tram/front - name = "tram wall" - desc = "A lightweight titanium composite structure with a windscreen installed." - icon_state = "tram_window-0" - base_icon_state = "tram_window" - wtype = "shuttle" - fulltile = TRUE - smoothing_flags = NONE - canSmoothWith = null - smoothing_groups = SMOOTH_GROUP_WINDOW_DIRECTIONAL_TRAM - flags_1 = PREVENT_CLICK_UNDER_1 - explosion_block = 3 - glass_amount = 2 - receive_ricochet_chance_mod = 1.2 - -/datum/armor/window_tram - melee = 80 - bullet = 5 - bomb = 45 - fire = 99 - acid = 100 - -MAPPING_DIRECTIONAL_HELPERS(/obj/structure/window/reinforced/tram, 0) diff --git a/code/modules/logging/categories/log_category_misc.dm b/code/modules/logging/categories/log_category_misc.dm index e3a737d4328..2d200e63aa2 100644 --- a/code/modules/logging/categories/log_category_misc.dm +++ b/code/modules/logging/categories/log_category_misc.dm @@ -53,6 +53,9 @@ category = LOG_CATEGORY_TELECOMMS config_flag = /datum/config_entry/flag/log_telecomms +/datum/log_category/transport + category = LOG_CATEGORY_TRANSPORT + /datum/log_category/speech_indicator category = LOG_CATEGORY_SPEECH_INDICATOR config_flag = /datum/config_entry/flag/log_speech_indicators diff --git a/code/modules/mapfluff/ruins/spaceruin_code/hilbertshotel.dm b/code/modules/mapfluff/ruins/spaceruin_code/hilbertshotel.dm index af316034f93..1e39d248f50 100644 --- a/code/modules/mapfluff/ruins/spaceruin_code/hilbertshotel.dm +++ b/code/modules/mapfluff/ruins/spaceruin_code/hilbertshotel.dm @@ -553,28 +553,28 @@ GLOBAL_VAR_INIT(hhMysteryRoomNumber, rand(1, 999999)) to_chat(user, "No vacated rooms.") return . -/obj/effect/landmark/lift_id/hilbert - specific_lift_id = HILBERT_TRAM +/obj/effect/landmark/transport/transport_id/hilbert + specific_transport_id = HILBERT_LINE_1 -/obj/effect/landmark/tram/nav/hilbert - name = HILBERT_TRAM - specific_lift_id = TRAM_NAV_BEACONS +/obj/effect/landmark/transport/nav_beacon/tram/nav/hilbert + name = HILBERT_LINE_1 + specific_transport_id = TRAM_NAV_BEACONS -/obj/effect/landmark/tram/platform/hilbert/left +/obj/effect/landmark/transport/nav_beacon/tram/platform/hilbert/left name = "Port" - specific_lift_id = HILBERT_TRAM + specific_transport_id = HILBERT_LINE_1 platform_code = HILBERT_PORT tgui_icons = list("Reception" = "briefcase", "Botany" = "leaf", "Chemistry" = "flask") -/obj/effect/landmark/tram/platform/hilbert/middle +/obj/effect/landmark/transport/nav_beacon/tram/platform/hilbert/middle name = "Central" - specific_lift_id = HILBERT_TRAM + specific_transport_id = HILBERT_LINE_1 platform_code = HILBERT_CENTRAL tgui_icons = list("Processing" = "cogs", "Xenobiology" = "paw") -/obj/effect/landmark/tram/platform/hilbert/right +/obj/effect/landmark/transport/nav_beacon/tram/platform/hilbert/right name = "Starboard" - specific_lift_id = HILBERT_TRAM + specific_transport_id = HILBERT_LINE_1 platform_code = HILBERT_STARBOARD tgui_icons = list("Ordnance" = "bullseye", "Office" = "user", "Dormitories" = "bed") diff --git a/code/modules/research/designs/autolathe/engineering_designs.dm b/code/modules/research/designs/autolathe/engineering_designs.dm index 4d065ff1dda..6249f5c645a 100644 --- a/code/modules/research/designs/autolathe/engineering_designs.dm +++ b/code/modules/research/designs/autolathe/engineering_designs.dm @@ -392,3 +392,37 @@ RND_CATEGORY_CONSTRUCTION + RND_SUBCATEGORY_CONSTRUCTION_MOUNTS, ) departmental_flags = DEPARTMENT_BITFLAG_ENGINEERING + +/datum/design/tram_controller + name = "Tram Controller Cabinet" + id = "tram_controller" + build_type = PROTOLATHE + materials = list( + /datum/material/titanium = SHEET_MATERIAL_AMOUNT * 4, + /datum/material/iron = SHEET_MATERIAL_AMOUNT * 2, + /datum/material/gold = SHEET_MATERIAL_AMOUNT * 7, + /datum/material/silver = SHEET_MATERIAL_AMOUNT * 7, + /datum/material/diamond = SHEET_MATERIAL_AMOUNT * 4, + ) + build_path = /obj/item/wallframe/tram/controller + category = list( + RND_CATEGORY_INITIAL, + RND_CATEGORY_CONSTRUCTION + RND_SUBCATEGORY_CONSTRUCTION_MOUNTS, + ) + departmental_flags = DEPARTMENT_BITFLAG_ENGINEERING + +/datum/design/tram_display + name = "Tram Indicator Display" + id = "tram_display" + build_type = PROTOLATHE + materials = list( + /datum/material/titanium = SHEET_MATERIAL_AMOUNT * 4, + /datum/material/iron = SHEET_MATERIAL_AMOUNT * 1, + /datum/material/glass =SHEET_MATERIAL_AMOUNT * 2, + ) + build_path = /obj/item/wallframe/indicator_display + category = list( + RND_CATEGORY_INITIAL, + RND_CATEGORY_CONSTRUCTION + RND_SUBCATEGORY_CONSTRUCTION_MOUNTS, + ) + departmental_flags = DEPARTMENT_BITFLAG_ENGINEERING diff --git a/code/modules/research/designs/machine_designs.dm b/code/modules/research/designs/machine_designs.dm index 3b0bf62c267..a73745399e1 100644 --- a/code/modules/research/designs/machine_designs.dm +++ b/code/modules/research/designs/machine_designs.dm @@ -734,6 +734,26 @@ ) departmental_flags = DEPARTMENT_BITFLAG_ENGINEERING | DEPARTMENT_BITFLAG_SCIENCE +/datum/design/board/crossing_signal + name = "Crossing Signal Board" + desc = "The circuit board for a tram crossing signal." + id = "crossing_signal" + build_path = /obj/item/circuitboard/machine/crossing_signal + category = list( + RND_CATEGORY_MACHINE + RND_SUBCATEGORY_MACHINE_TELECOMMS + ) + departmental_flags = DEPARTMENT_BITFLAG_ENGINEERING + +/datum/design/board/guideway_sensor + name = "Guideway Sensor Board" + desc = "The circuit board for a tram proximity sensor." + id = "guideway_sensor" + build_path = /obj/item/circuitboard/machine/guideway_sensor + category = list( + RND_CATEGORY_MACHINE + RND_SUBCATEGORY_MACHINE_TELECOMMS + ) + departmental_flags = DEPARTMENT_BITFLAG_ENGINEERING + /datum/design/board/limbgrower name = "Limb Grower Board" desc = "The circuit board for a limb grower." diff --git a/code/modules/research/techweb/all_nodes.dm b/code/modules/research/techweb/all_nodes.dm index 441e6f0038b..20851acea68 100644 --- a/code/modules/research/techweb/all_nodes.dm +++ b/code/modules/research/techweb/all_nodes.dm @@ -1243,6 +1243,19 @@ "s_treatment", ) +/datum/techweb_node/tram + id = "tram" + display_name = "Tram Technology" + description = "Technology for linear induction transportation systems." + prereq_ids = list("telecomms") + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 1500) + design_ids = list( + "tram_controller", + "tram_display", + "crossing_signal", + "guideway_sensor", + ) + /datum/techweb_node/integrated_hud id = "integrated_HUDs" display_name = "Integrated HUDs" diff --git a/code/modules/transport/_transport_machinery.dm b/code/modules/transport/_transport_machinery.dm new file mode 100644 index 00000000000..33824d288a1 --- /dev/null +++ b/code/modules/transport/_transport_machinery.dm @@ -0,0 +1,198 @@ +/obj/machinery/transport + armor_type = /datum/armor/transport_machinery + max_integrity = 400 + integrity_failure = 0.1 + /// ID of the transport we're associated with for filtering commands + var/configured_transport_id = TRAMSTATION_LINE_1 + /// weakref of the transport we're associated with + var/datum/weakref/transport_ref + var/list/methods_to_fix = list() + var/list/repair_signals + var/static/list/how_do_we_fix_it = list( + "try turning it off and on again with a multitool" = TOOL_MULTITOOL, + "try forcing an unexpected reboot with a multitool" = TOOL_MULTITOOL, + "patch the system's call table with a multitool" = TOOL_MULTITOOL, + "gently reset the invalid memory with a crowbar" = TOOL_CROWBAR, + "secure its ground connection with a wrench" = TOOL_WRENCH, + "tighten some screws with a screwdriver" = TOOL_SCREWDRIVER, + "check its wire voltages with a multitool" = TOOL_MULTITOOL, + "cut some excess wires with wirecutters" = TOOL_WIRECUTTER, + ) + var/malfunctioning = FALSE + +/datum/armor/transport_machinery + melee = 40 + bullet = 10 + laser = 10 + bomb = 45 + fire = 90 + acid = 100 + +/obj/machinery/transport/Initialize(mapload) + . = ..() + if(!id_tag) + id_tag = assign_random_name() + +/obj/machinery/transport/add_context(atom/source, list/context, obj/item/held_item, mob/user) + if(held_item?.tool_behaviour == TOOL_SCREWDRIVER) + context[SCREENTIP_CONTEXT_RMB] = panel_open ? "close panel" : "open panel" + + if(panel_open) + if(malfunctioning || methods_to_fix.len) + context[SCREENTIP_CONTEXT_LMB] = "repair electronics" + if(held_item?.tool_behaviour == TOOL_CROWBAR) + context[SCREENTIP_CONTEXT_RMB] = "deconstruct" + + if(held_item?.tool_behaviour == TOOL_WELDER) + context[SCREENTIP_CONTEXT_LMB] = "repair frame" + + return CONTEXTUAL_SCREENTIP_SET + +/** + * Finds the tram + * + * Locates tram parts in the lift global list after everything is done. + */ +/obj/machinery/transport/proc/link_tram() + for(var/datum/transport_controller/linear/tram/tram as anything in SStransport.transports_by_type[TRANSPORT_TYPE_TRAM]) + if(tram.specific_transport_id != configured_transport_id) + continue + transport_ref = WEAKREF(tram) + log_transport("[id_tag]: Successfuly linked to transport ID [tram.specific_transport_id] [transport_ref]") + break + + if(isnull(transport_ref)) + log_transport("[id_tag]: Tried to find a transport with ID [configured_transport_id], but failed!") + +/obj/machinery/transport/proc/local_fault() + if(malfunctioning || !isnull(repair_signals)) + return + + generate_repair_signals() + malfunctioning = TRUE + set_is_operational(FALSE) + update_appearance() + +/** + * All subtypes have the same method of repair for consistency and predictability + * The key of this assoc list is the "method" of how they're fixing the thing (just flavor for examine), + * and the value is what tool they actually need to use on the thing to fix it + */ +/obj/machinery/transport/proc/generate_repair_signals() + + // Select a few methods of how to fix it + var/list/fix_it_keys = assoc_to_keys(how_do_we_fix_it) + methods_to_fix += pick_n_take(fix_it_keys) + + // Construct the signals + LAZYINITLIST(repair_signals) + for(var/tool_method as anything in methods_to_fix) + repair_signals += COMSIG_ATOM_TOOL_ACT(how_do_we_fix_it[tool_method]) + + // Register signals to make it fixable + if(length(repair_signals)) + RegisterSignals(src, repair_signals, PROC_REF(on_machine_tooled)) + +/obj/machinery/transport/proc/clear_repair_signals() + UnregisterSignal(src, repair_signals) + QDEL_LAZYLIST(repair_signals) + +/obj/machinery/transport/examine(mob/user) + . = ..() + if(methods_to_fix) + for(var/tool_method as anything in methods_to_fix) + . += span_warning("It needs someone to [EXAMINE_HINT(tool_method)].") + if(panel_open) + . += span_notice("It can be deconstructed with a [EXAMINE_HINT("crowbar.")]") + +/** + * Signal proc for [COMSIG_ATOM_TOOL_ACT], from a variety of signals, registered on the machinery. + * + * We allow for someone to stop the event early by using the proper tools, hinted at in examine, on the machine + */ +/obj/machinery/transport/proc/on_machine_tooled(obj/machinery/source, mob/living/user, obj/item/tool) + SIGNAL_HANDLER + + INVOKE_ASYNC(src, PROC_REF(try_fix_machine), source, user, tool) + return COMPONENT_BLOCK_TOOL_ATTACK + +/// Attempts a do_after, and if successful, stops the event +/obj/machinery/transport/proc/try_fix_machine(obj/machinery/transport/machine, mob/living/user, obj/item/tool) + SHOULD_CALL_PARENT(TRUE) + + machine.balloon_alert(user, "percussive maintenance...") + if(!tool.use_tool(machine, user, 7 SECONDS, volume = 50)) + machine.balloon_alert(user, "interrupted!") + return FALSE + + playsound(src, 'sound/machines/synth_yes.ogg', 75, use_reverb = TRUE) + machine.balloon_alert(user, "success!") + UnregisterSignal(src, repair_signals) + QDEL_LAZYLIST(repair_signals) + QDEL_LAZYLIST(methods_to_fix) + malfunctioning = FALSE + set_machine_stat(machine_stat & ~EMAGGED) + update_appearance() + return TRUE + +/obj/machinery/transport/welder_act(mob/living/user, obj/item/tool) + if(user.combat_mode) + return + if(atom_integrity >= max_integrity) + balloon_alert(user, "it doesn't need repairs!") + return TRUE + balloon_alert(user, "repairing...") + if(!tool.use_tool(src, user, 4 SECONDS, amount = 0, volume=50)) + return TRUE + balloon_alert(user, "repaired") + atom_integrity = max_integrity + set_machine_stat(machine_stat & ~BROKEN) + update_appearance() + return TRUE + +/obj/item/wallframe/tram/try_build(obj/structure/tram/on_tram, mob/user) + if(get_dist(on_tram,user) > 1) + balloon_alert(user, "you are too far!") + return + + var/floor_to_tram = get_dir(user, on_tram) + if(!(floor_to_tram in GLOB.cardinals)) + balloon_alert(user, "stand in line with tram wall!") + return + + var/turf/tram_turf = get_turf(user) + var/obj/structure/thermoplastic/tram_floor = locate() in tram_turf + if(!istype(tram_floor)) + balloon_alert(user, "needs tram!") + return + + if(check_wall_item(tram_turf, floor_to_tram, wall_external)) + balloon_alert(user, "already something here!") + return + + return TRUE + +/obj/item/wallframe/tram/attach(obj/structure/tram/on_tram, mob/user) + if(result_path) + playsound(src.loc, 'sound/machines/click.ogg', 75, TRUE) + user.visible_message(span_notice("[user.name] installs [src] on the tram."), + span_notice("You install [src] on the tram."), + span_hear("You hear clicking.")) + var/floor_to_tram = get_dir(user, on_tram) + + var/obj/cabinet = new result_path(get_turf(user), floor_to_tram, TRUE) + cabinet.setDir(floor_to_tram) + + if(pixel_shift) + switch(floor_to_tram) + if(NORTH) + cabinet.pixel_y = pixel_shift + if(SOUTH) + cabinet.pixel_y = -pixel_shift + if(EAST) + cabinet.pixel_x = pixel_shift + if(WEST) + cabinet.pixel_x = -pixel_shift + after_attach(cabinet) + + qdel(src) diff --git a/code/modules/transport/admin.dm b/code/modules/transport/admin.dm new file mode 100644 index 00000000000..9d68d967e60 --- /dev/null +++ b/code/modules/transport/admin.dm @@ -0,0 +1,85 @@ +/** + * Helper tool to try and resolve tram controller errors, or reset the contents if someone put a million chickens on the tram + * and now it's slow as hell and lagging things. + */ +/datum/admins/proc/reset_tram() + set name = "Reset Tram" + set category = "Debug" + var/static/list/debug_tram_list = list( + TRAMSTATION_LINE_1, + BIRDSHOT_LINE_1, + BIRDSHOT_LINE_2, + HILBERT_LINE_1, + ) + + if(!check_rights(R_DEBUG)) + return + + var/datum/transport_controller/linear/tram/broken_controller + var/selected_transport_id = tgui_input_list(usr, "Which tram?", "Off the rails", debug_tram_list) + var/reset_type = tgui_input_list(usr, "How hard of a reset?", "How bad is it screwed up", list("Clear Tram Contents", "Controller", "Controller and Contents", "Delete Datum", "Cancel")) + + if(isnull(reset_type) || reset_type == "Cancel") + return + + for(var/datum/transport_controller/linear/tram/transport as anything in SStransport.transports_by_type[TRANSPORT_TYPE_TRAM]) + if(transport.specific_transport_id == selected_transport_id) + broken_controller = transport + break + + if(isnull(broken_controller)) + to_chat(usr, span_warning("Couldn't find a transport controller datum with ID [selected_transport_id]!")) + return + + switch(reset_type) + if("Clear Tram Contents") + var/selection = tgui_alert(usr, "Include player mobs in the clearing?", "Contents reset [selected_transport_id]", list("Contents", "Contents and Players", "Cancel")) + switch(selection) + if("Contents") + broken_controller.reset_lift_contents(foreign_objects = TRUE, foreign_non_player_mobs = TRUE, consider_player_mobs = FALSE) + message_admins("[key_name_admin(usr)] performed a contents reset of tram ID [selected_transport_id].") + log_transport("TC: [selected_transport_id]: [key_name_admin(usr)] performed a contents reset.") + if("Contents and Players") + broken_controller.reset_lift_contents(foreign_objects = TRUE, foreign_non_player_mobs = TRUE, consider_player_mobs = TRUE) + message_admins("[key_name_admin(usr)] performed a contents and player mob reset of tram ID [selected_transport_id].") + log_transport("TC: [selected_transport_id]: [key_name_admin(usr)] performed a contents and player mob reset.") + else + return + + if("Controller") + log_transport("TC: [selected_transport_id]: [key_name_admin(usr)] performed a controller reset, force operational.") + message_admins("[key_name_admin(usr)] performed a controller reset of tram ID [selected_transport_id].") + broken_controller.set_operational(TRUE) + broken_controller.reset_position() + + if("Controller and Contents") + var/selection = tgui_alert(usr, "Include player mobs in the clearing?", "Contents reset [selected_transport_id]", list("Contents", "Contents and Players", "Cancel")) + switch(selection) + if("Contents") + message_admins("[key_name_admin(usr)] performed a contents and controller reset of tram ID [selected_transport_id].") + log_transport("TC: [selected_transport_id]: [key_name_admin(usr)] performed a contents reset. Controller reset, force operational.") + broken_controller.reset_lift_contents(foreign_objects = TRUE, foreign_non_player_mobs = TRUE, consider_player_mobs = FALSE) + if("Contents and Players") + message_admins("[key_name_admin(usr)] performed a contents/player/controller reset of tram ID [selected_transport_id].") + log_transport("TC: [selected_transport_id]: [key_name_admin(usr)] performed a contents and player mob reset. Controller reset, force operational.") + broken_controller.reset_lift_contents(foreign_objects = TRUE, foreign_non_player_mobs = TRUE, consider_player_mobs = TRUE) + else + return + + broken_controller.set_operational(TRUE) + broken_controller.reset_position() + + if("Delete Datum") + var/confirm = tgui_alert(usr, "Deleting [selected_transport_id] will make it unrecoverable this round. Are you sure?", "Delete tram ID [selected_transport_id]", list("Yes", "Cancel")) + if(confirm != "Yes") + return + + var/obj/machinery/transport/tram_controller/tram_cabinet = broken_controller.paired_cabinet + if(!isnull(tram_cabinet)) + tram_cabinet.controller_datum = null + tram_cabinet.update_appearance() + + broken_controller.cycle_doors(CYCLE_OPEN, BYPASS_DOOR_CHECKS) + broken_controller.estop() + qdel(broken_controller) + message_admins("[key_name_admin(usr)] performed a datum delete of tram ID [selected_transport_id].") diff --git a/code/modules/industrial_lift/elevator/elevator_controller.dm b/code/modules/transport/elevator/elev_controller.dm similarity index 81% rename from code/modules/industrial_lift/elevator/elevator_controller.dm rename to code/modules/transport/elevator/elev_controller.dm index 9d8a18ed798..aae79cfe0f1 100644 --- a/code/modules/industrial_lift/elevator/elevator_controller.dm +++ b/code/modules/transport/elevator/elev_controller.dm @@ -4,7 +4,7 @@ base_icon_state = "tram" icon_state = "tram" can_alter_skin = FALSE - light_color = LIGHT_COLOR_DARK_BLUE + light_color = COLOR_DISPLAY_BLUE device_type = /obj/item/assembly/control/elevator req_access = list() id = 1 @@ -19,7 +19,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/button/elevator, 32) /obj/item/assembly/control/elevator name = "elevator controller" desc = "A small device used to call elevators to the current floor." - /// A weakref to the lift_master datum we control + /// A weakref to the transport_controller datum we control var/datum/weakref/lift_weakref COOLDOWN_DECLARE(elevator_cooldown) @@ -29,16 +29,16 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/button/elevator, 32) if(mapload) return INITIALIZE_HINT_LATELOAD - var/datum/lift_master/lift = get_lift() + var/datum/transport_controller/linear/lift = get_lift() if(!lift) return lift_weakref = WEAKREF(lift) /obj/item/assembly/control/elevator/LateInitialize() - var/datum/lift_master/lift = get_lift() + var/datum/transport_controller/linear/lift = get_lift() if(!lift) - log_mapping("Elevator call button at [AREACOORD(src)] found no associated lift to link with, this may be a mapping error.") + log_mapping("Elevator call button at [AREACOORD(src)] found no associated elevator to link with, this may be a mapping error.") return lift_weakref = WEAKREF(lift) @@ -49,17 +49,17 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/button/elevator, 32) return FALSE obj_flags |= EMAGGED - var/datum/lift_master/lift = lift_weakref?.resolve() + var/datum/transport_controller/linear/lift = lift_weakref?.resolve() if(!lift) return FALSE - for(var/obj/structure/industrial_lift/lift_platform as anything in lift.lift_platforms) + for(var/obj/structure/transport/linear/lift_platform as anything in lift.transport_modules) lift_platform.violent_landing = TRUE lift_platform.warns_on_down_movement = FALSE lift_platform.elevator_vertical_speed = initial(lift_platform.elevator_vertical_speed) * 0.5 for(var/obj/machinery/door/elevator_door as anything in GLOB.elevator_doors) - if(elevator_door.elevator_linked_id != lift.lift_id) + if(elevator_door.transport_linked_id != lift.specific_transport_id) continue if(elevator_door.obj_flags & EMAGGED) continue @@ -78,17 +78,17 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/button/elevator, 32) if(!(obj_flags & EMAGGED)) return ..() - var/datum/lift_master/lift = lift_weakref?.resolve() + var/datum/transport_controller/linear/lift = lift_weakref?.resolve() if(isnull(lift)) return ..() - for(var/obj/structure/industrial_lift/lift_platform as anything in lift.lift_platforms) + for(var/obj/structure/transport/linear/lift_platform as anything in lift.transport_modules) lift_platform.violent_landing = initial(lift_platform.violent_landing) lift_platform.warns_on_down_movement = initial(lift_platform.warns_on_down_movement) lift_platform.elevator_vertical_speed = initial(lift_platform.elevator_vertical_speed) for(var/obj/machinery/door/elevator_door as anything in GLOB.elevator_doors) - if(elevator_door.elevator_linked_id != lift.lift_id) + if(elevator_door.transport_linked_id != lift.specific_transport_id) continue if(!(elevator_door.obj_flags & EMAGGED)) continue @@ -116,7 +116,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/button/elevator, 32) /// Returns TRUE if the move setup was a success, EVEN IF the move itself fails afterwards /obj/item/assembly/control/elevator/proc/call_elevator(mob/activator) // We can't call an elevator that doesn't exist - var/datum/lift_master/lift = lift_weakref?.resolve() + var/datum/transport_controller/linear/lift = lift_weakref?.resolve() if(!lift) loc.balloon_alert(activator, "no elevator connected!") return FALSE @@ -127,9 +127,9 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/button/elevator, 32) return FALSE // If the elevator is already here, open the doors. - var/obj/structure/industrial_lift/prime_lift = lift.return_closest_platform_to_z(loc.z) + var/obj/structure/transport/linear/prime_lift = lift.return_closest_platform_to_z(loc.z) if(prime_lift.z == loc.z) - INVOKE_ASYNC(lift, TYPE_PROC_REF(/datum/lift_master, open_lift_doors_callback)) + INVOKE_ASYNC(lift, TYPE_PROC_REF(/datum/transport_controller/linear, open_lift_doors_callback)) loc.balloon_alert(activator, "elevator is here!") return TRUE @@ -169,10 +169,10 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/button/elevator, 32) return FALSE return TRUE -/// Gets the lift associated with our assembly / button +/// Gets the elevator associated with our assembly / button /obj/item/assembly/control/elevator/proc/get_lift() - for(var/datum/lift_master/possible_match as anything in GLOB.active_lifts_by_type[BASIC_LIFT_ID]) - if(possible_match.specific_lift_id != id) + for(var/datum/transport_controller/linear/possible_match as anything in SStransport.transports_by_type[TRANSPORT_TYPE_ELEVATOR]) + if(possible_match.specific_transport_id != id) continue return possible_match diff --git a/code/modules/industrial_lift/elevator/elevator_doors.dm b/code/modules/transport/elevator/elev_doors.dm similarity index 100% rename from code/modules/industrial_lift/elevator/elevator_doors.dm rename to code/modules/transport/elevator/elev_doors.dm diff --git a/code/modules/industrial_lift/elevator/elevator_indicator.dm b/code/modules/transport/elevator/elev_indicator.dm similarity index 78% rename from code/modules/industrial_lift/elevator/elevator_indicator.dm rename to code/modules/transport/elevator/elev_indicator.dm index 77518a4bdc8..cf9fa46e963 100644 --- a/code/modules/industrial_lift/elevator/elevator_indicator.dm +++ b/code/modules/transport/elevator/elev_indicator.dm @@ -1,5 +1,5 @@ /** - * A lift indicator aka an elevator hall lantern w/ floor number + * An indicator display aka an elevator hall lantern w/ floor number */ /obj/machinery/lift_indicator name = "elevator indicator" @@ -16,7 +16,7 @@ light_range = 1 light_power = 1 - light_color = LIGHT_COLOR_DARK_BLUE + light_color = COLOR_DISPLAY_BLUE luminosity = 1 maptext_x = 18 @@ -24,17 +24,17 @@ maptext_width = 8 maptext_height = 16 - /// What specific_lift_id do we link with? + /// What specific_transport_id do we link with? var/linked_elevator_id /// 'Floors' for display purposes are by default offset by 1 from their actual z-levels var/lowest_floor_offset = 1 - /// Weakref to the lift. + /// Weakref to the transport. var/datum/weakref/lift_ref - /// The lowest floor number. Determined by lift init. + /// The lowest floor number. Determined by transport module init. var/lowest_floor_num = 1 /// Positive for going up, negative going down, 0 for stopped var/current_lift_direction = 0 - /// The lift's current floor relative to its lowest floor being 1 + /// The elevator's current floor relative to its lowest floor being 1 var/current_lift_floor = 1 /obj/machinery/lift_indicator/Initialize(mapload) @@ -44,8 +44,8 @@ /obj/machinery/lift_indicator/LateInitialize() . = ..() - for(var/datum/lift_master/possible_match as anything in GLOB.active_lifts_by_type[BASIC_LIFT_ID]) - if(possible_match.specific_lift_id != linked_elevator_id) + for(var/datum/transport_controller/linear/possible_match as anything in SStransport.transports_by_type[TRANSPORT_TYPE_ELEVATOR]) + if(possible_match.specific_transport_id != linked_elevator_id) continue lift_ref = WEAKREF(possible_match) @@ -70,12 +70,12 @@ . += span_notice("The elevator is at floor [current_lift_floor], [dirtext].") /** - * Update state, and only process if lift is moving. + * Update state, and only process if elevator is moving. */ /obj/machinery/lift_indicator/proc/on_lift_direction(datum/source, direction) SIGNAL_HANDLER - var/datum/lift_master/lift = lift_ref?.resolve() + var/datum/transport_controller/linear/lift = lift_ref?.resolve() if(!lift) return @@ -102,26 +102,26 @@ return FALSE /obj/machinery/lift_indicator/process() - var/datum/lift_master/lift = lift_ref?.resolve() + var/datum/transport_controller/linear/lift = lift_ref?.resolve() // Check for stopped states. if(!lift || !is_operational) - // Lift missing, or we lost power. + // elevator missing, or we lost power. set_lift_state(0, 0, force = !is_operational) return PROCESS_KILL use_power(active_power_usage) - var/obj/structure/industrial_lift/lift_part = lift.lift_platforms[1] + var/obj/structure/transport/linear/lift_part = lift.transport_modules[1] if(QDELETED(lift_part)) set_lift_state(0, 0, force = !is_operational) return PROCESS_KILL // Update - set_lift_state(current_lift_direction, lift.lift_platforms[1].z - lowest_floor_offset) + set_lift_state(current_lift_direction, lift.transport_modules[1].z - lowest_floor_offset) - // Lift's not moving, we're done; we just had to update the floor number one last time. + // elevator's not moving, we're done; we just had to update the floor number one last time. if(!current_lift_direction) return PROCESS_KILL @@ -150,7 +150,7 @@ return set_light(l_on = TRUE) - maptext = "
[current_lift_floor]
" + maptext = "
[current_lift_floor]
" /obj/machinery/lift_indicator/update_overlays() . = ..() diff --git a/code/modules/industrial_lift/elevator/elevator_music_zone.dm b/code/modules/transport/elevator/elev_music_zone.dm similarity index 98% rename from code/modules/industrial_lift/elevator/elevator_music_zone.dm rename to code/modules/transport/elevator/elev_music_zone.dm index 00d55751a5c..1f09a00a68b 100644 --- a/code/modules/industrial_lift/elevator/elevator_music_zone.dm +++ b/code/modules/transport/elevator/elev_music_zone.dm @@ -7,7 +7,7 @@ GLOBAL_LIST_EMPTY(elevator_music) invisibility = INVISIBILITY_MAXIMUM // Setting this to ABSTRACT means it isn't moved by the lift icon = 'icons/obj/art/musician.dmi' icon_state = "piano" - /// What specific_lift_id do we link with? + /// What specific_transport_id do we link with? var/linked_elevator_id = "" /// Radius around this map helper in which to play the sound var/range = 1 diff --git a/code/modules/industrial_lift/elevator/elevator_panel.dm b/code/modules/transport/elevator/elev_panel.dm similarity index 83% rename from code/modules/industrial_lift/elevator/elevator_panel.dm rename to code/modules/transport/elevator/elev_panel.dm index 8791c885a50..3e9e0e073c1 100644 --- a/code/modules/industrial_lift/elevator/elevator_panel.dm +++ b/code/modules/transport/elevator/elev_panel.dm @@ -5,9 +5,9 @@ * allowing users to enter a UI to move it up or down * * These can be placed in two methods: - * - You can place the control panel on the same turf as a lift. It will move up and down with the lift - * - You can place the control panel to the side of a lift, NOT attached to the lift. It will remain in position - * I don't recommend using both methods on the same elevator, as it might result in some jank, but it's functional. + * - You can place the control panel on the same turf as an elevator. It will move up and down with the elevator + * - You can place the control panel to the side of an elevator, NOT attached to the elevator. It will remain in position + * - I don't recommend using both methods on the same elevator, as it might result in some jank, but it's functional. */ /obj/machinery/elevator_control_panel name = "elevator panel" @@ -26,9 +26,9 @@ /// Were we instantiated at mapload? Used to determine when we should link / throw errors var/maploaded = FALSE - /// A weakref to the lift_master datum we control + /// A weakref to the transport_controller datum we control var/datum/weakref/lift_weakref - /// What specific_lift_id do we link with? + /// What specific_transport_id do we link with? var/linked_elevator_id /// A list of all possible destinations this elevator can travel. @@ -82,9 +82,9 @@ // and also so we can throw mapping errors to let people know if they messed up setup. link_with_lift(log_error = TRUE) -/// Link with associated lift objects, only log failure to find a lift in LateInit because those are mapped in +/// Link with associated transport controllers, only log failure to find a lift in LateInit because those are mapped in /obj/machinery/elevator_control_panel/proc/link_with_lift(log_error = FALSE) - var/datum/lift_master/lift = get_associated_lift() + var/datum/transport_controller/linear/lift = get_associated_lift() if(!lift) if (log_error) log_mapping("Elevator control panel at [AREACOORD(src)] found no associated lift to link with, this may be a mapping error.") @@ -102,17 +102,17 @@ obj_flags |= EMAGGED - var/datum/lift_master/lift = lift_weakref?.resolve() + var/datum/transport_controller/linear/lift = lift_weakref?.resolve() if(!lift) return FALSE - for(var/obj/structure/industrial_lift/lift_platform as anything in lift.lift_platforms) + for(var/obj/structure/transport/linear/lift_platform as anything in lift.transport_modules) lift_platform.violent_landing = TRUE lift_platform.warns_on_down_movement = FALSE lift_platform.elevator_vertical_speed = initial(lift_platform.elevator_vertical_speed) * 0.5 for(var/obj/machinery/door/elevator_door as anything in GLOB.elevator_doors) - if(elevator_door.elevator_linked_id != linked_elevator_id) + if(elevator_door.transport_linked_id != linked_elevator_id) continue if(elevator_door.obj_flags & EMAGGED) continue @@ -125,7 +125,7 @@ return TRUE /obj/machinery/elevator_control_panel/multitool_act(mob/living/user) - var/datum/lift_master/lift = lift_weakref?.resolve() + var/datum/transport_controller/linear/lift = lift_weakref?.resolve() if(!lift) return @@ -135,18 +135,18 @@ balloon_alert(user, "interrupted!") return TRUE - if(QDELETED(lift) || !length(lift.lift_platforms)) + if(QDELETED(lift) || !length(lift.transport_modules)) return // If we were emagged, reset us if(obj_flags & EMAGGED) - for(var/obj/structure/industrial_lift/lift_platform as anything in lift.lift_platforms) + for(var/obj/structure/transport/linear/lift_platform as anything in lift.transport_modules) lift_platform.violent_landing = initial(lift_platform.violent_landing) lift_platform.warns_on_down_movement = initial(lift_platform.warns_on_down_movement) lift_platform.elevator_vertical_speed = initial(lift_platform.elevator_vertical_speed) for(var/obj/machinery/door/elevator_door as anything in GLOB.elevator_doors) - if(elevator_door.elevator_linked_id != linked_elevator_id) + if(elevator_door.transport_linked_id != linked_elevator_id) continue if(!(elevator_door.obj_flags & EMAGGED)) continue @@ -168,8 +168,8 @@ /// Find the elevator associated with our lift button. /obj/machinery/elevator_control_panel/proc/get_associated_lift() - for(var/datum/lift_master/possible_match as anything in GLOB.active_lifts_by_type[BASIC_LIFT_ID]) - if(possible_match.specific_lift_id != linked_elevator_id) + for(var/datum/transport_controller/linear/possible_match as anything in SStransport.transports_by_type[TRANSPORT_TYPE_ELEVATOR]) + if(possible_match.specific_transport_id != linked_elevator_id) continue return possible_match @@ -177,13 +177,13 @@ return null /// Goes through and populates the linked_elevator_destination list with all possible destinations the lift can go. -/obj/machinery/elevator_control_panel/proc/populate_destinations_list(datum/lift_master/linked_lift) +/obj/machinery/elevator_control_panel/proc/populate_destinations_list(datum/transport_controller/linear/linked_lift) // This list will track all the raw z-levels which we found that we can travel to var/list/raw_destinations = list() // Get a list of all the starting locs our elevator starts at var/list/starting_locs = list() - for(var/obj/structure/industrial_lift/lift_piece as anything in linked_lift.lift_platforms) + for(var/obj/structure/transport/linear/lift_piece as anything in linked_lift.transport_modules) starting_locs |= lift_piece.locs // The raw destination list will start with all the z's we start at raw_destinations |= lift_piece.z @@ -242,7 +242,7 @@ // Add the Zs of all the found turfs as possible destinations for(var/turf/found as anything in checked_turfs) - // We check all turfs we found in case of multi-z lift memes. + // We check all turfs we found in case of multi-z memes. destinations |= found.z // And recursively call the proc with all the turfs we found on the next level @@ -255,7 +255,7 @@ ui.open() /obj/machinery/elevator_control_panel/ui_status(mob/user) - // We moved up a z-level, probably via the lift itself, so don't preserve the UI. + // We moved up a z-level, probably via the elevator itself, so don't preserve the UI. if(user.z != z) return UI_CLOSE @@ -277,12 +277,12 @@ data["is_emergency"] = SSsecurity_level.get_current_level_as_number() >= SEC_LEVEL_RED data["doors_open"] = !!door_reset_timerid - var/datum/lift_master/lift = lift_weakref?.resolve() + var/datum/transport_controller/linear/lift = lift_weakref?.resolve() if(lift) data["lift_exists"] = TRUE data["currently_moving"] = lift.controls_locked == LIFT_PLATFORM_LOCKED data["currently_moving_to_floor"] = last_move_target - data["current_floor"] = lift.lift_platforms[1].z + data["current_floor"] = lift.transport_modules[1].z else data["lift_exists"] = FALSE @@ -322,16 +322,16 @@ if(!(num2text(desired_z) in linked_elevator_destination)) return TRUE // Something is inaccurate, update UI - var/datum/lift_master/lift = lift_weakref?.resolve() + var/datum/transport_controller/linear/lift = lift_weakref?.resolve() if(!lift || lift.controls_locked == LIFT_PLATFORM_LOCKED) return TRUE // We shouldn't be moving anything, update UI - INVOKE_ASYNC(lift, TYPE_PROC_REF(/datum/lift_master, move_to_zlevel), desired_z, CALLBACK(src, PROC_REF(check_panel)), usr) + INVOKE_ASYNC(lift, TYPE_PROC_REF(/datum/transport_controller/linear, move_to_zlevel), desired_z, CALLBACK(src, PROC_REF(check_panel)), usr) last_move_target = desired_z return TRUE // Succcessfully initiated a move. Regardless of whether it actually works, update the UI if("emergency_door") - var/datum/lift_master/lift = lift_weakref?.resolve() + var/datum/transport_controller/linear/lift = lift_weakref?.resolve() if(!lift) return TRUE // Something is wrong, update UI @@ -340,8 +340,8 @@ if(SSsecurity_level.get_current_level_as_number() < SEC_LEVEL_RED) return TRUE // The security level might have been lowered since last update, so update UI - // Open all lift doors, it's an emergency dang it! - lift.update_lift_doors(action = OPEN_DOORS) + // Open all elevator doors, it's an emergency dang it! + lift.update_lift_doors(action = CYCLE_OPEN) door_reset_timerid = addtimer(CALLBACK(src, PROC_REF(reset_doors)), 3 MINUTES, TIMER_UNIQUE|TIMER_STOPPABLE) return TRUE // We opened up all the doors, update the UI so the emergency button is replaced correctly @@ -353,7 +353,7 @@ reset_doors() return TRUE // We closed all the doors, update the UI so the door button is replaced correctly -/// Callback for move_to_zlevel to ensure the lift can continue to move. +/// Callback for move_to_zlevel to ensure the elevator can continue to move. /obj/machinery/elevator_control_panel/proc/check_panel() if(QDELETED(src)) return FALSE @@ -363,9 +363,9 @@ return TRUE /// Helper proc to go through all of our desetinations and reset all elevator doors, -/// closing doors on z-levels the lift is away from, and opening doors on the z the lift is +/// closing doors on z-levels the elevator is away from, and opening doors on the z the elevator is /obj/machinery/elevator_control_panel/proc/reset_doors() - var/datum/lift_master/lift = lift_weakref?.resolve() + var/datum/transport_controller/linear/lift = lift_weakref?.resolve() if(!lift) return @@ -381,8 +381,8 @@ // Open all the doors on the zs we should be open on, // and close all doors we aren't on. Simple enough. - lift.update_lift_doors(zs_we_are_present_on, action = OPEN_DOORS) - lift.update_lift_doors(zs_we_are_absent, action = CLOSE_DOORS) + lift.update_lift_doors(zs_we_are_present_on, action = CYCLE_OPEN) + lift.update_lift_doors(zs_we_are_absent, action = CYCLE_CLOSED) door_reset_timerid = null diff --git a/code/modules/transport/linear_controller.dm b/code/modules/transport/linear_controller.dm new file mode 100644 index 00000000000..dd90562deb6 --- /dev/null +++ b/code/modules/transport/linear_controller.dm @@ -0,0 +1,635 @@ +///coordinate and control movement across linked transport_controllers. allows moving large single multitile platforms and many 1 tile platforms. +///also is capable of linking platforms across linked z levels +/datum/transport_controller/linear + ///the lift platforms we consider as part of this transport. ordered in order of lowest z level to highest z level after init. + ///(the sorting algorithm sucks btw) + var/list/obj/structure/transport/linear/transport_modules + + /// Typepath list of what to ignore smashing through, controls all lifts + var/static/list/ignored_smashthroughs = list( + /obj/machinery/power/supermatter_crystal, + /obj/structure/holosign, + /obj/machinery/field, + ) + + ///whether the lift handled by this transport_controller datum is multitile as opposed to nxm platforms per z level + var/modular_set = FALSE + + ///taken from our lift platforms. if true we go through each z level of platforms and attempt to make the lowest left corner platform + ///into one giant multitile object the size of all other platforms on that z level. + var/create_modular_set = FALSE + + ///lift platforms have already been sorted in order of z level. + var/z_sorted = FALSE + + ///transport_id taken from our base lift platform, used to put us into SStransport.transports_by_type + var/transport_id = TRANSPORT_TYPE_ELEVATOR + + ///overridable ID string to link control units to this specific transport_controller datum. created by placing a transport id landmark object + ///somewhere on the tram, if its anywhere on the tram we'll find it in init and set this to whatever it specifies + var/specific_transport_id + + ///bitfield of various transport states + var/controller_status = NONE + + ///if true, the platform cannot be manually moved. + var/controls_locked = FALSE + +/datum/transport_controller/linear/New(obj/structure/transport/linear/transport_module) + transport_id = transport_module.transport_id + create_modular_set = transport_module.create_modular_set + + link_transport_modules(transport_module) + ignored_smashthroughs = typecacheof(ignored_smashthroughs) + + LAZYADDASSOCLIST(SStransport.transports_by_type, transport_id, src) + + for(var/obj/structure/transport/linear/lift as anything in transport_modules) + lift.add_initial_contents() + +/datum/transport_controller/linear/Destroy() + for(var/obj/structure/transport/linear/transport_module as anything in transport_modules) + transport_module.transport_controller_datum = null + transport_modules = null + + LAZYREMOVEASSOC(SStransport.transports_by_type, transport_id, src) + if(isnull(SStransport.transports_by_type)) + SStransport.transports_by_type = list() + + return ..() + +/datum/transport_controller/linear/proc/add_transport_modules(obj/structure/transport/linear/new_transport_module) + if(new_transport_module in transport_modules) + return + for(var/obj/structure/transport/linear/other_module in new_transport_module.loc) + if(other_module != new_transport_module) + stack_trace("there is more than one transport module on a tile when a controller adds it. this causes problems") + qdel(other_module) + + new_transport_module.transport_controller_datum = src + LAZYADD(transport_modules, new_transport_module) + RegisterSignal(new_transport_module, COMSIG_QDELETING, PROC_REF(remove_transport_modules)) + + check_for_landmarks(new_transport_module) + + if(z_sorted)//make sure we dont lose z ordering if we get additional platforms after init + order_platforms_by_z_level() + +/datum/transport_controller/linear/proc/remove_transport_modules(obj/structure/transport/linear/old_transport_module) + SIGNAL_HANDLER + + if(!(old_transport_module in transport_modules)) + return + + old_transport_module.transport_controller_datum = null + LAZYREMOVE(transport_modules, old_transport_module) + UnregisterSignal(old_transport_module, COMSIG_QDELETING) + if(!length(transport_modules)) + qdel(src) + +///Collect all bordered platforms via a simple floodfill algorithm. allows multiz trams because its funny +/datum/transport_controller/linear/proc/link_transport_modules(obj/structure/transport/linear/base_transport_module) + add_transport_modules(base_transport_module) + var/list/possible_expansions = list(base_transport_module) + + while(possible_expansions.len) + for(var/obj/structure/transport/linear/borderline as anything in possible_expansions) + var/list/result = borderline.module_adjacency(src) + if(length(result)) + for(var/obj/structure/transport/linear/transport_module as anything in result) + if(transport_modules.Find(transport_module)) + continue + + add_transport_modules(transport_module) + possible_expansions |= transport_module + + possible_expansions -= borderline + +///check for any landmarks placed inside the locs of the given transport_module +/datum/transport_controller/linear/proc/check_for_landmarks(obj/structure/transport/linear/new_transport_module) + SHOULD_CALL_PARENT(TRUE) + + for(var/turf/platform_loc as anything in new_transport_module.locs) + var/obj/effect/landmark/transport/transport_id/id_giver = locate() in platform_loc + + if(id_giver) + set_info_from_id_landmark(id_giver) + +///set vars and such given an overriding transport_id landmark +/datum/transport_controller/linear/proc/set_info_from_id_landmark(obj/effect/landmark/transport/transport_id/landmark) + SHOULD_CALL_PARENT(TRUE) + + if(!istype(landmark, /obj/effect/landmark/transport/transport_id))//transport_controller subtypes can want differnet id's than the base type wants + return + + if(landmark.specific_transport_id) + specific_transport_id = landmark.specific_transport_id + + qdel(landmark) + +///orders the lift platforms in order of lowest z level to highest z level. +/datum/transport_controller/linear/proc/order_platforms_by_z_level() + //contains nested lists for every z level in the world. why? because its really easy to sort + var/list/platforms_by_z = list() + platforms_by_z.len = world.maxz + + for(var/z in 1 to world.maxz) + platforms_by_z[z] = list() + + for(var/obj/structure/transport/linear/transport_module as anything in transport_modules) + if(QDELETED(transport_module) || !transport_module.z) + transport_modules -= transport_module + continue + + platforms_by_z[transport_module.z] += transport_module + + if(create_modular_set) + for(var/list/z_list as anything in platforms_by_z) + if(!length(z_list)) + continue + + create_modular_set_for_z_level(z_list)//this will subtract all but one platform from the list + + var/list/output = list() + + for(var/list/z_list as anything in platforms_by_z) + output += z_list + + transport_modules = output + + z_sorted = TRUE + +///goes through all platforms in the given list and finds the one in the lower left corner +/datum/transport_controller/linear/proc/create_modular_set_for_z_level(list/obj/structure/transport/linear/platforms_in_z) + var/min_x = INFINITY + var/max_x = 0 + + var/min_y = INFINITY + var/max_y = 0 + + var/z = 0 + + for(var/obj/structure/transport/linear/module_to_sort as anything in platforms_in_z) + if(!z) + if(!module_to_sort.z) + stack_trace("create_modular_set_for_z_level() was given a platform in nullspace or not on a turf!") + platforms_in_z -= module_to_sort + continue + + z = module_to_sort.z + + if(z != module_to_sort.z) + stack_trace("create_modular_set_for_z_level() was given lifts on different z levels!") + platforms_in_z -= module_to_sort + continue + + min_x = min(min_x, module_to_sort.x) + max_x = max(max_x, module_to_sort.x) + + min_y = min(min_y, module_to_sort.y) + max_y = max(max_y, module_to_sort.y) + + var/turf/lower_left_corner_loc = locate(min_x, min_y, z) + if(!lower_left_corner_loc) + CRASH("was unable to find a turf at the lower left corner of this z") + + var/obj/structure/transport/linear/lower_left_corner_transport = locate() in lower_left_corner_loc + + if(!lower_left_corner_transport) + CRASH("there was no transport in the lower left corner of the given transport") + + platforms_in_z.Cut() + platforms_in_z += lower_left_corner_transport//we want to change the list given to us not create a new one. so we do this + + lower_left_corner_transport.create_modular_set(min_x, min_y, max_x, max_y, z) + +///returns the closest transport to the specified atom, prioritizing transports on the same z level. used for comparing distance +/datum/transport_controller/linear/proc/return_closest_platform_to(atom/comparison, allow_multiple_answers = FALSE) + if(!istype(comparison) || !comparison.z) + return FALSE + + var/list/obj/structure/transport/linear/candidate_platforms = list() + + for(var/obj/structure/transport/linear/platform as anything in transport_modules) + if(platform.z == comparison.z) + candidate_platforms += platform + + var/obj/structure/transport/linear/winner = candidate_platforms[1] + var/winner_distance = get_dist(comparison, winner) + + var/list/tied_winners = list(winner) + + for(var/obj/structure/transport/linear/platform_to_sort as anything in candidate_platforms) + var/platform_distance = get_dist(comparison, platform_to_sort) + + if(platform_distance < winner_distance) + winner = platform_to_sort + winner_distance = platform_distance + + if(allow_multiple_answers) + tied_winners = list(winner) + + else if(platform_distance == winner_distance && allow_multiple_answers) + tied_winners += platform_to_sort + + if(allow_multiple_answers) + return tied_winners + + return winner + +/// Returns a platform on the z-level which is vertically closest to the passed target_z +/datum/transport_controller/linear/proc/return_closest_platform_to_z(target_z) + var/obj/structure/transport/linear/found_platform + for(var/obj/structure/transport/linear/lift as anything in transport_modules) + // Already at the same Z-level, we can stop + if(lift.z == target_z) + found_platform = lift + break + + // Set up an initial lift to compare to + if(!found_platform) + found_platform = lift + continue + + // Same level, we can go with the one we currently have + if(lift.z == found_platform.z) + continue + + // If the difference between the current found platform and the target + // if less than the distance between the next lift and the target, + // our current platform is closer to the target than the next one, so we can skip it + if(abs(found_platform.z - target_z) < abs(lift.z - target_z)) + continue + + // The difference is smaller for this lift, so it's closer + found_platform = lift + + return found_platform + +/// Returns a list of all the z-levels our transport is currently on. +/datum/transport_controller/linear/proc/get_zs_we_are_on() + var/list/zs_we_are_present_on = list() + for(var/obj/structure/transport/linear/lift as anything in transport_modules) + zs_we_are_present_on |= lift.z + return zs_we_are_present_on + +///returns all transport modules associated with this transport on the given z level or given atoms z level +/datum/transport_controller/linear/proc/get_platforms_on_level(atom/atom_reference_OR_z_level_number) + var/z = atom_reference_OR_z_level_number + if(isatom(atom_reference_OR_z_level_number)) + z = atom_reference_OR_z_level_number.z + + if(!isnum(z) || z < 0 || z > world.maxz) + return null + + var/list/platforms_in_z = list() + + for(var/obj/structure/transport/linear/lift_to_check as anything in transport_modules) + if(lift_to_check.z) + platforms_in_z += lift_to_check + + return platforms_in_z + +/** + * Moves the platform UP or DOWN, this is what users invoke with their hand. + * This is a SAFE proc, ensuring every part of it moves SANELY. + * + * Arguments: + * going - UP or DOWN directions, where the platform should go. Keep in mind by this point checks of whether it should go up or down have already been done. + * user - Whomever made the movement. + */ +/datum/transport_controller/linear/proc/move_lift_vertically(going, mob/user) + //transport_modules are sorted in order of lowest z to highest z, so going upwards we need to move them in reverse order to not collide + if(going == UP) + var/obj/structure/transport/linear/platform_to_move + var/current_index = length(transport_modules) + + while(current_index > 0) + platform_to_move = transport_modules[current_index] + current_index-- + + platform_to_move.travel(going) + + else if(going == DOWN) + for(var/obj/structure/transport/linear/transport_module as anything in transport_modules) + transport_module.travel(going) + +/** + * Moves the platform after a passed delay. + * + * This is a more "user friendly" or "realistic" move. + * It includes things like: + * - Allowing platform "travel time" + * - Shutting elevator safety doors + * - Sound effects while moving + * - Safety warnings for anyone below the platform (while it's moving downwards) + * + * Arguments: + * duration - required, how long do we wait to move the platform? + * door_duration - optional, how long should we wait to open the doors after arriving? If null, we won't open or close doors + * direction - which direction are we moving the lift? + * user - optional, who is moving the lift? + */ +/datum/transport_controller/linear/proc/move_after_delay(lift_move_duration, door_duration, direction, mob/user) + if(!isnum(lift_move_duration)) + CRASH("[type] move_after_delay called with invalid duration ([lift_move_duration]).") + if(lift_move_duration <= 0 SECONDS) + move_lift_vertically(direction, user) + return + + // Get the lowest or highest platform according to which direction we're moving + var/obj/structure/transport/linear/prime_lift = return_closest_platform_to_z(direction == UP ? world.maxz : 0) + + // If anyone changes the hydraulic sound effect I sure hope they update this variable... + var/hydraulic_sfx_duration = 2 SECONDS + // ...because we use the duration of the sound effect to make it last for roughly the duration of the lift travel + playsound(prime_lift, 'sound/mecha/hydraulic.ogg', 25, vary = TRUE, frequency = clamp(hydraulic_sfx_duration / lift_move_duration, 0.33, 3)) + + // Move the platform after a timer + addtimer(CALLBACK(src, PROC_REF(move_lift_vertically), direction, user), lift_move_duration, TIMER_UNIQUE) + // Open doors after the set duration if supplied + if(isnum(door_duration)) + addtimer(CALLBACK(src, PROC_REF(open_lift_doors_callback)), door_duration, TIMER_UNIQUE) + + // Here on we only care about platforms going DOWN + if(direction != DOWN) + return + + // Okay we're going down, let's try to display some warnings to people below + var/list/turf/lift_locs = list() + for(var/obj/structure/transport/linear/going_to_move as anything in transport_modules) + // This platform has no warnings so we don't even need to worry about it + if(!going_to_move.warns_on_down_movement) + continue + // Collect all the turfs our platform is found at + lift_locs |= going_to_move.locs + + for(var/turf/moving in lift_locs) + // Find what's below the turf that's moving + var/turf/below_us = get_step_multiz(moving, DOWN) + // Hold up the turf below us is also in our locs list. Multi-z? Don't show a warning + if(below_us in lift_locs) + continue + // Display the warning for until we land + new /obj/effect/temp_visual/telegraphing/lift_travel(below_us, lift_move_duration) + +/** + * Simple wrapper for checking if we can move 1 zlevel, and if we can, do said move. + * Locks controls, closes all doors, then moves the platform and re-opens the doors afterwards. + * + * Arguments: + * direction - which direction are we moving? + * lift_move_duration - how long does the move take? can be 0 or null for instant move. + * door_duration - how long does it take for the doors to open after a move? + * user - optional, who moved it? + */ +/datum/transport_controller/linear/proc/simple_move_wrapper(direction, lift_move_duration, mob/user) + if(!Check_lift_move(direction)) + return FALSE + + // Lock controls, to prevent moving-while-moving memes + controls_lock(TRUE) + // Send out a signal that we're going + SEND_SIGNAL(src, COMSIG_LIFT_SET_DIRECTION, direction) + // Close all lift doors + update_lift_doors(action = CYCLE_CLOSED) + + if(isnull(lift_move_duration) || lift_move_duration <= 0 SECONDS) + // Do an instant move + move_lift_vertically(direction, user) + // Open doors on the zs we arrive at + update_lift_doors(get_zs_we_are_on(), action = CYCLE_OPEN) + // And unlock the controls after + controls_lock(FALSE) + return TRUE + + // Do a delayed move + move_after_delay( + lift_move_duration = lift_move_duration, + door_duration = lift_move_duration * 1.5, + direction = direction, + user = user, + ) + + addtimer(CALLBACK(src, PROC_REF(finish_simple_move_wrapper)), lift_move_duration * 1.5) + return TRUE + +/** + * Wrap everything up from simple_move_wrapper finishing its movement + */ +/datum/transport_controller/linear/proc/finish_simple_move_wrapper() + SEND_SIGNAL(src, COMSIG_LIFT_SET_DIRECTION, 0) + controls_lock(FALSE) + +/** + * Moves the platform to the passed z-level. + * + * Checks for validity of the move: Are we moving to the same z-level, can we actually move to that z-level? + * Does NOT check if the controls are currently locked. + * + * Moves to the passed z-level by calling move_after_delay repeatedly until the passed z-level is reached. + * This proc sleeps as it moves. + * + * Arguments: + * target_z - required, the Z we want to move to + * loop_callback - optional, an additional callback invoked during the loop that allows the move to cancel. + * user - optional, who started the move + */ +/datum/transport_controller/linear/proc/move_to_zlevel(target_z, datum/callback/loop_callback, mob/user) + if(!isnum(target_z) || target_z <= 0) + CRASH("[type] move_to_zlevel was passed an invalid target_z ([target_z]).") + + var/obj/structure/transport/linear/prime_lift = return_closest_platform_to_z(target_z) + var/lift_z = prime_lift.z + // We're already at the desired z-level! + if(target_z == lift_z) + return FALSE + + // The amount of z levels between the our and target_z + var/z_difference = abs(target_z - lift_z) + // Direction (up/down) needed to go to reach target_z + var/direction = lift_z < target_z ? UP : DOWN + + // We can't go that way anymore, or possibly ever + if(!Check_lift_move(direction)) + return FALSE + + // Okay we're ready to start moving now. + controls_lock(TRUE) + // Send out a signal that we're going + SEND_SIGNAL(src, COMSIG_LIFT_SET_DIRECTION, direction) + var/travel_speed = prime_lift.elevator_vertical_speed + + // Close all lift doors + update_lift_doors(action = CYCLE_CLOSED) + // Approach the desired z-level one step at a time + for(var/i in 1 to z_difference) + if(!Check_lift_move(direction)) + break + if(loop_callback && !loop_callback.Invoke()) + break + // move_after_delay will set up a timer and cause us to move after a time + move_after_delay( + lift_move_duration = travel_speed, + direction = direction, + user = user, + ) + // and we don't want to send another request until the timer's done + stoplag(travel_speed + 0.1 SECONDS) + if(QDELETED(src) || QDELETED(prime_lift)) + return + + addtimer(CALLBACK(src, PROC_REF(open_lift_doors_callback)), 2 SECONDS) + SEND_SIGNAL(src, COMSIG_LIFT_SET_DIRECTION, 0) + controls_lock(FALSE) + return TRUE + +/** + * Updates all blast doors and shutters that share an ID with our lift. + * + * Arguments: + * on_z_level - optional, only open doors on this z-level or list of z-levels + * action - how do we update the doors? CYCLE_OPEN to make them open, CYCLE_CLOSED to make them shut + */ +/datum/transport_controller/linear/proc/update_lift_doors(on_z_level, action) + + if(!isnull(on_z_level) && !islist(on_z_level)) + on_z_level = list(on_z_level) + + var/played_ding = FALSE + for(var/obj/machinery/door/elevator_door as anything in GLOB.elevator_doors) + if(elevator_door.transport_linked_id != specific_transport_id) + continue + if(on_z_level && !(elevator_door.z in on_z_level)) + continue + switch(action) + if(CYCLE_OPEN) + elevator_door.elevator_status = LIFT_PLATFORM_UNLOCKED + if(!played_ding) + playsound(elevator_door, 'sound/machines/ping.ogg', 50, TRUE) + played_ding = TRUE + addtimer(CALLBACK(elevator_door, TYPE_PROC_REF(/obj/machinery/door, open)), 0.7 SECONDS) + if(CYCLE_CLOSED) + elevator_door.elevator_status = LIFT_PLATFORM_LOCKED + INVOKE_ASYNC(elevator_door, TYPE_PROC_REF(/obj/machinery/door, close)) + else + stack_trace("Elevator lift update_lift_doors called with an improper action ([action]).") + +/// Helper used in callbacks to open all the doors our platform is on +/datum/transport_controller/linear/proc/open_lift_doors_callback() + update_lift_doors(get_zs_we_are_on(), action = CYCLE_OPEN) + +/** + * Moves the platform, this is what users invoke with their hand. + * This is a SAFE proc, ensuring every part of the lift moves SANELY. + * It also locks controls for the (miniscule) duration of the movement, so the elevator cannot be broken by spamming. + */ +/datum/transport_controller/linear/proc/move_transport_horizontally(going) + if(modular_set) + controls_lock(TRUE) + for(var/obj/structure/transport/linear/module_to_move as anything in transport_modules) + module_to_move.travel(going) + + controls_lock(FALSE) + return + + var/max_x = 0 + var/max_y = 0 + var/max_z = 0 + var/min_x = world.maxx + var/min_y = world.maxy + var/min_z = world.maxz + + for(var/obj/structure/transport/linear/transport_module as anything in transport_modules) + max_z = max(max_z, transport_module.z) + min_z = min(min_z, transport_module.z) + + min_x = min(min_x, transport_module.x) + max_x = max(max_x, transport_module.x) + //this assumes that all z levels have identical horizontal bounding boxes + //but if youre still using a non multitile platform at this point + //then its your own problem. it wont runtime it will just be slower than it needs to be if this assumption isnt + //the case + + min_y = min(min_y, transport_module.y) + max_y = max(max_y, transport_module.y) + + for(var/z in min_z to max_z) + //This must be safe way to border tile to tile move of bordered platforms, that excludes platform overlapping. + if(going & WEST) + //Go along the X axis from min to max, from left to right + for(var/x in min_x to max_x) + if(going & NORTH) + //Go along the Y axis from max to min, from up to down + for(var/y in max_y to min_y step -1) + var/obj/structure/transport/linear/transport_module = locate(/obj/structure/transport/linear, locate(x, y, z)) + transport_module?.travel(going) + + else if(going & SOUTH) + //Go along the Y axis from min to max, from down to up + for(var/y in min_y to max_y) + var/obj/structure/transport/linear/transport_module = locate(/obj/structure/transport/linear, locate(x, y, z)) + transport_module?.travel(going) + + else + for(var/y in min_y to max_y) + var/obj/structure/transport/linear/transport_module = locate(/obj/structure/transport/linear, locate(x, y, z)) + transport_module?.travel(going) + else + //Go along the X axis from max to min, from right to left + for(var/x in max_x to min_x step -1) + if(going & NORTH) + //Go along the Y axis from max to min, from up to down + for(var/y in max_y to min_y step -1) + var/obj/structure/transport/linear/transport_module = locate(/obj/structure/transport/linear, locate(x, y, z)) + transport_module?.travel(going) + + else if (going & SOUTH) + for(var/y in min_y to max_y) + var/obj/structure/transport/linear/transport_module = locate(/obj/structure/transport/linear, locate(x, y, z)) + transport_module?.travel(going) + + else + //Go along the Y axis from min to max, from down to up + for(var/y in min_y to max_y) + var/obj/structure/transport/linear/transport_module = locate(/obj/structure/transport/linear, locate(x, y, z)) + transport_module?.travel(going) + +///Check destination turfs +/datum/transport_controller/linear/proc/Check_lift_move(check_dir) + for(var/obj/structure/transport/linear/transport_module as anything in transport_modules) + for(var/turf/bound_turf in transport_module.locs) + var/turf/T = get_step_multiz(transport_module, check_dir) + if(!T)//the edges of multi-z maps + return FALSE + if(check_dir == UP && !istype(T, /turf/open/openspace)) // We don't want to go through the ceiling! + return FALSE + if(check_dir == DOWN && !istype(get_turf(transport_module), /turf/open/openspace)) // No going through the floor! + return FALSE + return TRUE + +/** + * Sets transport controls_locked state. Used to prevent moving mid movement, or cooldowns. + */ +/datum/transport_controller/linear/proc/controls_lock(state) + switch(state) + if(FALSE) + controller_status &= ~CONTROLS_LOCKED + else + controller_status |= CONTROLS_LOCKED + +/** + * resets the contents of all platforms to their original state in case someone put a bunch of shit onto the platform. + * intended to be called by admins. passes all arguments to reset_contents() for each of our platforms. + * + * Arguments: + * * consider_anything_past - number. if > 0 our platforms will only handle foreign contents that exceed this number in each of their locs + * * foreign_objects - bool. if true our platforms will consider /atom/movable's that arent mobs as part of foreign contents + * * foreign_non_player_mobs - bool. if true our platforms consider mobs that dont have a mind to be foreign + * * consider_player_mobs - bool. if true our platforms consider player mobs to be foreign. only works if foreign_non_player_mobs is true as well + */ +/datum/transport_controller/linear/proc/reset_lift_contents(consider_anything_past = 0, foreign_objects = TRUE, foreign_non_player_mobs = TRUE, consider_player_mobs = FALSE) + for(var/obj/structure/transport/linear/lift_to_reset in transport_modules) + lift_to_reset.reset_contents(consider_anything_past, foreign_objects, foreign_non_player_mobs, consider_player_mobs) + + return TRUE diff --git a/code/modules/transport/tram/tram_controller.dm b/code/modules/transport/tram/tram_controller.dm new file mode 100644 index 00000000000..e04e1bd26b6 --- /dev/null +++ b/code/modules/transport/tram/tram_controller.dm @@ -0,0 +1,1043 @@ +/** + * Tram specific variant of the generic linear transport controller. + * + * Hierarchy + * The sstransport subsystem manages a list of controllers, + * A controller manages a list of transport modules (individual tiles) which together make up a transport unit (in this case a tram) + */ +/datum/transport_controller/linear/tram + ///whether this controller is active (any state we don't accept new orders, not nessecarily moving) + var/controller_active = FALSE + ///whether all required parts of the tram are considered operational + var/controller_operational = TRUE + var/obj/machinery/transport/tram_controller/paired_cabinet + ///if we're travelling, what direction are we going + var/travel_direction = NONE + ///if we're travelling, how far do we have to go + var/travel_remaining = 0 + ///how far in total we'll be travelling + var/travel_trip_length = 0 + + ///multiplier on how much damage/force the tram imparts on things it hits + var/collision_lethality = 1 + var/obj/effect/landmark/transport/nav_beacon/tram/nav/nav_beacon + /// reference to the destination landmarks we consider ourselves "at" or travelling towards. since we potentially span multiple z levels we dont actually + /// know where on us this platform is. as long as we know THAT its on us we can just move the distance and direction between this + /// and the destination landmark. + var/obj/effect/landmark/transport/nav_beacon/tram/platform/idle_platform + /// reference to the destination landmarks we consider ourselves travelling towards. since we potentially span multiple z levels we dont actually + /// know where on us this platform is. as long as we know THAT its on us we can just move the distance and direction between this + /// and the destination landmark. + var/obj/effect/landmark/transport/nav_beacon/tram/platform/destination_platform + + var/current_speed = 0 + var/current_load = 0 + + ///decisecond delay between horizontal movement. cannot make the tram move faster than 1 movement per world.tick_lag. + var/speed_limiter = 0.5 + + ///version of speed_limiter that gets set in init and is considered our base speed if our lift gets slowed down + var/base_speed_limiter = 0.5 + + ///the world.time we should next move at. in case our speed is set to less than 1 movement per tick + var/scheduled_move = INFINITY + + ///whether we have been slowed down automatically + var/recovery_mode = FALSE + + ///how many times we moved while costing more than SStransport.max_time milliseconds per movement. + ///if this exceeds SStransport.max_exceeding_moves + var/recovery_activate_count = 0 + + ///how many times we moved while costing less than 0.5 * SStransport.max_time milliseconds per movement + var/recovery_clear_count = 0 + + var/datum/tram_mfg_info/tram_registration + + var/list/tram_history + +/datum/tram_mfg_info + var/serial_number + var/active = TRUE + var/mfg_date + var/install_location + var/distance_travelled = 0 + var/collisions = 0 + +/** + * Assign registration details to a new tram. + * + * When a new tram is created, we give it a builder's plate with the date it was created. + * We track a few stats about it, and keep a small historical record on the + * information plate inside the tram. + */ +/datum/tram_mfg_info/New(specific_transport_id) + if(GLOB.round_id) + serial_number = "LT306TG[add_leading(GLOB.round_id, 6, 0)]" + else + serial_number = "LT306TG[rand(000000, 999999)]" + + mfg_date = "[CURRENT_STATION_YEAR]-[time2text(world.timeofday, "MM-DD")]" + install_location = specific_transport_id + +/datum/tram_mfg_info/proc/load_from_json(list/json_data) + serial_number = json_data["serial_number"] + active = json_data["active"] + mfg_date = json_data["mfg_date"] + install_location = json_data["install_location"] + distance_travelled = json_data["distance_travelled"] + collisions = json_data["collisions"] + +/datum/tram_mfg_info/proc/export_to_json() + var/list/new_data = list() + new_data["serial_number"] = serial_number + new_data["active"] = active + new_data["mfg_date"] = mfg_date + new_data["install_location"] = install_location + new_data["distance_travelled"] = distance_travelled + new_data["collisions"] = collisions + return new_data + +/** + * Make sure all modules have matching speed limiter vars, pull save data from persistence + * + * We track a few stats about it, and keep a small historical record on the + * information plate inside the tram. + */ +/datum/transport_controller/linear/tram/New(obj/structure/transport/linear/tram/transport_module) + . = ..() + speed_limiter = transport_module.speed_limiter + base_speed_limiter = transport_module.speed_limiter + tram_history = SSpersistence.load_tram_history(specific_transport_id) + var/datum/tram_mfg_info/previous_tram = peek(tram_history) + if(!isnull(previous_tram) && previous_tram.active) + tram_registration = pop(tram_history) + else + tram_registration = new /datum/tram_mfg_info(specific_transport_id) + + check_starting_landmark() + +/** + * If someone VVs the base speed limiter of the tram, copy it to the current active speed limiter. + */ +/datum/transport_controller/linear/tram/vv_edit_var(var_name, var_value) + . = ..() + if(var_name == "base_speed_limiter") + speed_limiter = max(speed_limiter, base_speed_limiter) + +/datum/transport_controller/linear/tram/Destroy() + paired_cabinet = null + set_status_code(SYSTEM_FAULT, TRUE) + tram_registration.active = FALSE + SSblackbox.record_feedback("amount", "tram_destroyed", 1) + SSpersistence.save_tram_history(specific_transport_id) + ..() + +/** + * Register transport modules to the controller + * + * Spreads out searching neighbouring tiles for additional transport modules, to combine into one full tram. + * We register to every module's signal that it's collided with something, be it mob, structure, etc. + */ +/datum/transport_controller/linear/tram/add_transport_modules(obj/structure/transport/linear/new_transport_module) + . = ..() + RegisterSignal(new_transport_module, COMSIG_MOVABLE_BUMP, PROC_REF(gracefully_break)) + +/** + * The mapper should have placed the tram at one of the stations, the controller will search for a landmark within + * its control area and set it as its idle position. + */ +/datum/transport_controller/linear/tram/check_for_landmarks(obj/structure/transport/linear/tram/new_transport_module) + . = ..() + for(var/turf/platform_loc as anything in new_transport_module.locs) + var/obj/effect/landmark/transport/nav_beacon/tram/platform/initial_destination = locate() in platform_loc + var/obj/effect/landmark/transport/nav_beacon/tram/nav/beacon = locate() in platform_loc + + if(initial_destination) + idle_platform = initial_destination + destination_platform = initial_destination + + if(beacon) + nav_beacon = beacon + +/** + * Verify tram is in a valid starting location, start the subsystem. + * + * Throw an error if someone mapped a tram with no landmarks available for it to register. + * The processing subsystem starts off because not all maps have elevators/transports. + * Now that the tram is aware of its surroundings, we start the subsystem. + */ +/datum/transport_controller/linear/tram/proc/check_starting_landmark() + if(!idle_platform || !nav_beacon) + CRASH("a tram lift_master was initialized without the required landmarks to give it direction!") + + SStransport.can_fire = TRUE + + return TRUE + +/** + * The tram explodes if it hits a few types of objects. + * + * Signal for when the tram runs into a field of which it cannot go through. + * Stops the train's travel fully, sends a message, and destroys the train. + * Arguments: + * * bumped_atom - The atom this tram bumped into + */ +/datum/transport_controller/linear/tram/proc/gracefully_break(atom/bumped_atom) + SIGNAL_HANDLER + + travel_remaining = 0 + bumped_atom.visible_message(span_userdanger("The [bumped_atom.name] crashes into the field violently!")) + for(var/obj/structure/transport/linear/tram/transport_module as anything in transport_modules) + transport_module.set_travelling(FALSE) + for(var/explosive_target in transport_module.transport_contents) + if(iseffect(explosive_target)) + continue + + if(isliving(explosive_target)) + explosion(explosive_target, devastation_range = rand(0, 1), heavy_impact_range = 2, light_impact_range = 3) //50% chance of gib + + else if(prob(9)) + explosion(explosive_target, devastation_range = 1, heavy_impact_range = 2, light_impact_range = 3) + + explosion(transport_module, devastation_range = 1, heavy_impact_range = 2, light_impact_range = 3) + qdel(transport_module) + + send_transport_active_signal() + +/** + * Calculate the journey details to the requested platform + * + * These will eventually be passed to the transport modules as args telling them where to move. + * We do some sanity checking in case of discrepencany between where the subsystem thinks the + * tram is and where the tram actually is. (For example, moving the landmarks after round start.) + + */ +/datum/transport_controller/linear/tram/proc/calculate_route(obj/effect/landmark/transport/nav_beacon/tram/destination) + if(destination == idle_platform) + return FALSE + + destination_platform = destination + travel_direction = get_dir(nav_beacon, destination_platform) + travel_remaining = get_dist(nav_beacon, destination_platform) + travel_trip_length = travel_remaining + log_transport("TC: [specific_transport_id] trip calculation: src: [nav_beacon.x], [nav_beacon.y], [nav_beacon.z] dst: [destination_platform] [destination_platform.x], [destination_platform.y], [destination_platform.z] = Dir [travel_direction] Dist [travel_remaining].") + return TRUE + +/** + * Handles moving the tram + * + * Called by the subsystem, the controller tells the individual tram parts where to actually go and has extra safety checks + * incase multiple inputs get through, preventing conflicting directions and the tram literally ripping itself apart. + * All of the actual movement is handled by SStransport. + * + * If we're this far all the PRE_DEPARTURE checks should have passed, so we leave the PRE_DEPARTURE status and actually move. + * We send a signal to anything registered that cares about the physical movement of the tram. + * + * Arguments: + * * destination_platform - where the subsystem wants it to go + */ + +/datum/transport_controller/linear/tram/proc/dispatch_transport(obj/effect/landmark/transport/nav_beacon/tram/destination_platform) + log_transport("TC: [specific_transport_id] starting departure.") + set_status_code(PRE_DEPARTURE, FALSE) + if(controller_status & EMERGENCY_STOP) + set_status_code(EMERGENCY_STOP, FALSE) + playsound(paired_cabinet, 'sound/machines/synth_yes.ogg', 40, vary = FALSE, extrarange = SHORT_RANGE_SOUND_EXTRARANGE) + paired_cabinet.say("Controller reset.") + + SEND_SIGNAL(src, COMSIG_TRAM_TRAVEL, idle_platform, destination_platform) + + for(var/obj/structure/transport/linear/tram/transport_module as anything in transport_modules) //only thing everyone needs to know is the new location. + if(transport_module.travelling) //wee woo wee woo there was a double action queued. damn multi tile structs + return //we don't care to undo cover_locked controls, though, as that will resolve itself + transport_module.glide_size_override = DELAY_TO_GLIDE_SIZE(speed_limiter) + transport_module.set_travelling(TRUE) + + scheduled_move = world.time + speed_limiter + + START_PROCESSING(SStransport, src) + +/** + * Tram processing loop + * + * Moves the tram to its set destination. + * When it arrives at its destination perform callback to the post-arrival procs like controls and lights. + * We update the odometer and kill the process until we need to move again. + * + * If the status is EMERGENCY_STOP the tram should immediately come to a stop regardless of the travel_remaining. + * Some extra things happen in an emergency stop (throwing the passengers) and when reset will run a + * recovery procedure to head to the nearest platform and sync logical and physical location data + * (idle_platform and nav_beacon) once the issue is resolved. + */ +/datum/transport_controller/linear/tram/process(seconds_per_tick) + if(isnull(paired_cabinet)) + set_status_code(SYSTEM_FAULT, TRUE) + + if(controller_status & SYSTEM_FAULT || controller_status & EMERGENCY_STOP) + halt_and_catch_fire() + return PROCESS_KILL + + if(!travel_remaining) + if(!controller_operational) + degraded_stop() + return PROCESS_KILL + + normal_stop() + return PROCESS_KILL + + else if(world.time >= scheduled_move) + var/start_time = TICK_USAGE + travel_remaining-- + + move_transport_horizontally(travel_direction) + + var/duration = TICK_USAGE_TO_MS(start_time) + current_load = duration + current_speed = transport_modules[1].glide_size + if(recovery_mode) + if(duration <= (SStransport.max_time / 2)) + recovery_clear_count++ + else + recovery_clear_count = 0 + + if(recovery_clear_count >= SStransport.max_cheap_moves) + speed_limiter = base_speed_limiter + recovery_mode = FALSE + recovery_clear_count = 0 + log_transport("TC: [specific_transport_id] removing speed limiter, performance issue resolved. Last tick was [duration]ms.") + + else if(duration > SStransport.max_time) + recovery_activate_count++ + if(recovery_activate_count >= SStransport.max_exceeding_moves) + message_admins("The tram at [ADMIN_JMP(transport_modules[1])] is taking [duration] ms which is more than [SStransport.max_time] ms per movement for [recovery_activate_count] ticks. Reducing its movement speed until it recovers. If this continues to be a problem you can reset the tram contents to its original state, and clear added objects on the Debug tab.") + log_transport("TC: [specific_transport_id] activating speed limiter due to poor performance. Last tick was [duration]ms.") + speed_limiter = base_speed_limiter * 2 //halves its speed + recovery_mode = TRUE + recovery_activate_count = 0 + else + recovery_activate_count = max(recovery_activate_count - 1, 0) + + scheduled_move = world.time + speed_limiter + +/datum/transport_controller/linear/tram/proc/normal_stop() + cycle_doors(CYCLE_OPEN) + log_transport("TC: [specific_transport_id] trip completed. Info: nav_pos ([nav_beacon.x], [nav_beacon.y], [nav_beacon.z]) idle_pos ([destination_platform.x], [destination_platform.y], [destination_platform.z]).") + addtimer(CALLBACK(src, PROC_REF(unlock_controls)), 2 SECONDS) + if((controller_status & SYSTEM_FAULT) && (nav_beacon.loc == destination_platform.loc)) //position matches between controller and tram, we're back on track + set_status_code(SYSTEM_FAULT, FALSE) + playsound(paired_cabinet, 'sound/machines/synth_yes.ogg', 40, vary = FALSE, extrarange = SHORT_RANGE_SOUND_EXTRARANGE) + paired_cabinet.say("Controller reset.") + log_transport("TC: [specific_transport_id] position data successfully reset.") + speed_limiter = initial(speed_limiter) + idle_platform = destination_platform + tram_registration.distance_travelled += (travel_trip_length - travel_remaining) + travel_trip_length = 0 + current_speed = 0 + current_load = 0 + speed_limiter = initial(speed_limiter) + +/datum/transport_controller/linear/tram/proc/degraded_stop() + log_transport("TC: [specific_transport_id] trip completed with a degraded status. Info: [TC_TS_STATUS] nav_pos ([nav_beacon.x], [nav_beacon.y], [nav_beacon.z]) idle_pos ([destination_platform.x], [destination_platform.y], [destination_platform.z]).") + addtimer(CALLBACK(src, PROC_REF(unlock_controls)), 4 SECONDS) + if(controller_status & SYSTEM_FAULT) + set_status_code(SYSTEM_FAULT, FALSE) + playsound(paired_cabinet, 'sound/machines/synth_yes.ogg', 40, vary = FALSE, extrarange = SHORT_RANGE_SOUND_EXTRARANGE) + paired_cabinet.say("Controller reset.") + log_transport("TC: [specific_transport_id] position data successfully reset. ") + speed_limiter = initial(speed_limiter) + idle_platform = destination_platform + tram_registration.distance_travelled += (travel_trip_length - travel_remaining) + travel_trip_length = 0 + current_speed = 0 + current_load = 0 + speed_limiter = initial(speed_limiter) + var/throw_direction = travel_direction + for(var/obj/structure/transport/linear/tram/module in transport_modules) + module.estop_throw(throw_direction) + +/datum/transport_controller/linear/tram/proc/halt_and_catch_fire() + if(controller_status & SYSTEM_FAULT) + if(!isnull(paired_cabinet)) + playsound(paired_cabinet, 'sound/machines/buzz-sigh.ogg', 60, vary = FALSE, extrarange = SHORT_RANGE_SOUND_EXTRARANGE) + paired_cabinet.say("Controller error. Please contact your engineering department.") + log_transport("TC: [specific_transport_id] Transport Controller failed!") + + if(travel_remaining) + travel_remaining = 0 + var/throw_direction = travel_direction + for(var/obj/structure/transport/linear/tram/module in transport_modules) + module.estop_throw(throw_direction) + + addtimer(CALLBACK(src, PROC_REF(unlock_controls)), 4 SECONDS) + addtimer(CALLBACK(src, PROC_REF(cycle_doors), CYCLE_OPEN), 2 SECONDS) + idle_platform = null + log_transport("TC: [specific_transport_id] Transport Controller needs new position data from the tram.") + tram_registration.distance_travelled += (travel_trip_length - travel_remaining) + travel_trip_length = 0 + current_speed = 0 + current_load = 0 + +/datum/transport_controller/linear/tram/proc/reset_position() + if(idle_platform) + if(get_turf(idle_platform) == get_turf(nav_beacon)) + set_status_code(SYSTEM_FAULT, FALSE) + set_status_code(EMERGENCY_STOP, FALSE) + playsound(paired_cabinet, 'sound/machines/synth_yes.ogg', 40, vary = FALSE, extrarange = SHORT_RANGE_SOUND_EXTRARANGE) + paired_cabinet.say("Controller reset.") + log_transport("TC: [specific_transport_id] Transport Controller reset was requested, but the tram nav data seems correct. Info: nav_pos ([nav_beacon.x], [nav_beacon.y], [nav_beacon.z]) idle_pos ([idle_platform.x], [idle_platform.y], [idle_platform.z]).") + return + + log_transport("TC: [specific_transport_id] performing Transport Controller reset. Locating closest reset beacon to ([nav_beacon.x], [nav_beacon.y], [nav_beacon.z])") + var/tram_velocity_sign + if(travel_direction & (NORTH|SOUTH)) + tram_velocity_sign = travel_direction & NORTH ? OUTBOUND : INBOUND + else + tram_velocity_sign = travel_direction & EAST ? OUTBOUND : INBOUND + + var/reset_beacon = closest_nav_in_travel_dir(nav_beacon, tram_velocity_sign, specific_transport_id) + + if(!reset_beacon) + playsound(paired_cabinet, 'sound/machines/buzz-sigh.ogg', 60, vary = FALSE, extrarange = SHORT_RANGE_SOUND_EXTRARANGE) + paired_cabinet.say("Controller reset failed. Contact manufacturer.") // If you screwed up the tram this bad, I don't even + log_transport("TC: [specific_transport_id] non-recoverable error! Tram is at ([nav_beacon.x], [nav_beacon.y], [nav_beacon.z] [tram_velocity_sign ? "OUTBOUND" : "INBOUND"]) and can't find a reset beacon.") + message_admins("Tram ID [specific_transport_id] is in a non-recoverable error state at [ADMIN_JMP(nav_beacon)]. If it's causing problems, delete the controller datum from the 'Reset Tram' proc in the Debug tab.") + return + + travel_direction = get_dir(nav_beacon, reset_beacon) + travel_remaining = get_dist(nav_beacon, reset_beacon) + travel_trip_length = travel_remaining + destination_platform = reset_beacon + speed_limiter = 1.5 + playsound(paired_cabinet, 'sound/machines/ping.ogg', 40, vary = FALSE, extrarange = SHORT_RANGE_SOUND_EXTRARANGE) + paired_cabinet.say("Peforming controller reset... Navigating to reset point.") + log_transport("TC: [specific_transport_id] trip calculation: src: [nav_beacon.x], [nav_beacon.y], [nav_beacon.z] dst: [destination_platform] [destination_platform.x], [destination_platform.y], [destination_platform.z] = Dir [travel_direction] Dist [travel_remaining].") + cycle_doors(CYCLE_CLOSED) + set_active(TRUE) + set_status_code(CONTROLS_LOCKED, TRUE) + addtimer(CALLBACK(src, PROC_REF(dispatch_transport), reset_beacon), 3 SECONDS) + log_transport("TC: [specific_transport_id] trying to reset at [destination_platform].") + +/datum/transport_controller/linear/tram/proc/estop() + playsound(paired_cabinet, 'sound/machines/buzz-sigh.ogg', 60, vary = FALSE, extrarange = SHORT_RANGE_SOUND_EXTRARANGE) + paired_cabinet.say("Emergency stop activated!") + set_status_code(EMERGENCY_STOP, TRUE) + log_transport("TC: [specific_transport_id] requested emergency stop.") + +/** + * Handles unlocking the tram controls for use after moving + * + * More safety checks to make sure the tram has actually docked properly + * at a location before users are allowed to interact with the tram console again. + * Tram finds its location at this point before fully unlocking controls to the user. + */ +/datum/transport_controller/linear/tram/proc/unlock_controls() + controls_lock(FALSE) + for(var/obj/structure/transport/linear/tram/transport_module as anything in transport_modules) //only thing everyone needs to know is the new location. + transport_module.set_travelling(FALSE) + set_active(FALSE) + +/** + * Sets the active status for the controller and sends a signal to listeners. + * + * The main signal used by most components, it has the active status, the bitfield of the controller's status, its direction, and set destination. + * + * Arguments: + * new_status - The active status of the controller (whether it's busy doing something and not taking commands right now) + */ +/datum/transport_controller/linear/tram/proc/set_active(new_status) + if(controller_active == new_status) + return + + controller_active = new_status + send_transport_active_signal() + log_transport("TC: [specific_transport_id] controller state [controller_active ? "READY > PROCESSING" : "PROCESSING > READY"].") + +/** + * Sets the controller status bitfield + * + * This status var is used by various components like lights, crossing signals, signs + * Sent via signal the listening components will perform required actions based on + * the status codes. + * + * Arguments: + * * code - The status bitflag we're changing + * * value - boolean TRUE/FALSE to set the code + */ +/datum/transport_controller/linear/tram/proc/set_status_code(code, value) + if(code != DOORS_READY) + log_transport("TC: [specific_transport_id] status change [value ? "+" : "-"][english_list(bitfield_to_list(code, TRANSPORT_FLAGS))].") + switch(value) + if(TRUE) + controller_status |= code + if(FALSE) + controller_status &= ~code + else + stack_trace("Transport controller received invalid status code request [code]/[value]") + return + + send_transport_active_signal() + +/datum/transport_controller/linear/tram/proc/send_transport_active_signal() + SEND_SIGNAL(SStransport, COMSIG_TRANSPORT_ACTIVE, src, controller_active, controller_status, travel_direction, destination_platform) + +/** + * Part of the pre-departure list, checks the status of the doors on the tram + * + * Checks if all doors are closed, and updates the status code accordingly. + * + * TODO: this is probably better renamed check_door_status() + */ +/datum/transport_controller/linear/tram/proc/update_status() + for(var/obj/machinery/door/airlock/tram/door as anything in SStransport.doors) + if(door.transport_linked_id != specific_transport_id) + continue + if(door.crushing_in_progress) + log_transport("TC: [specific_transport_id] door [door.id_tag] failed crush status check.") + set_status_code(DOORS_READY, FALSE) + return + + set_status_code(DOORS_READY, TRUE) + +/** + * Cycle all the doors on the tram. + */ +/datum/transport_controller/linear/tram/proc/cycle_doors(door_status, rapid) + switch(door_status) + if(CYCLE_OPEN) + for(var/obj/machinery/door/airlock/tram/door as anything in SStransport.doors) + if(door.transport_linked_id == specific_transport_id) + INVOKE_ASYNC(door, TYPE_PROC_REF(/obj/machinery/door/airlock/tram, open), rapid) + + if(CYCLE_CLOSED) + for(var/obj/machinery/door/airlock/tram/door as anything in SStransport.doors) + if(door.transport_linked_id == specific_transport_id) + INVOKE_ASYNC(door, TYPE_PROC_REF(/obj/machinery/door/airlock/tram, close), rapid) + +/datum/transport_controller/linear/tram/proc/notify_controller(obj/machinery/transport/tram_controller/new_cabinet) + paired_cabinet = new_cabinet + RegisterSignal(new_cabinet, COMSIG_MACHINERY_POWER_LOST, PROC_REF(power_lost)) + RegisterSignal(new_cabinet, COMSIG_MACHINERY_POWER_RESTORED, PROC_REF(power_restored)) + RegisterSignal(new_cabinet, COMSIG_QDELETING, PROC_REF(on_cabinet_qdel)) + log_transport("TC: [specific_transport_id] is now paired with [new_cabinet].") + if(controller_status & SYSTEM_FAULT) + set_status_code(SYSTEM_FAULT, FALSE) + reset_position() + +/datum/transport_controller/linear/tram/proc/on_cabinet_qdel() + paired_cabinet = null + log_transport("TC: [specific_transport_id] received QDEL from controller cabinet.") + set_status_code(SYSTEM_FAULT, TRUE) + +/** + * Tram malfunction random event. Set comm error, increase tram lethality. + */ +/datum/transport_controller/linear/tram/proc/start_malf_event() + set_status_code(COMM_ERROR, TRUE) + SEND_TRANSPORT_SIGNAL(COMSIG_COMMS_STATUS, src, FALSE) + paired_cabinet.generate_repair_signals() + collision_lethality = 1.25 + log_transport("TC: [specific_transport_id] starting Tram Malfunction event.") + +/** + * Remove effects of tram malfunction event. + * + * If engineers didn't already repair the tram by the end of the event, + * automagically reset it remotely. + */ +/datum/transport_controller/linear/tram/proc/end_malf_event() + if(!(controller_status & COMM_ERROR)) + return + set_status_code(COMM_ERROR, FALSE) + paired_cabinet.clear_repair_signals() + collision_lethality = initial(collision_lethality) + SEND_TRANSPORT_SIGNAL(COMSIG_COMMS_STATUS, src, TRUE) + log_transport("TC: [specific_transport_id] ending Tram Malfunction event.") + +/datum/transport_controller/linear/tram/proc/register_collision() + tram_registration.collisions += 1 + SEND_TRANSPORT_SIGNAL(COMSIG_TRAM_COLLISION, SSpersistence.tram_hits_this_round) + +/datum/transport_controller/linear/tram/proc/power_lost() + set_operational(FALSE) + log_transport("TC: [specific_transport_id] power lost.") + send_transport_active_signal() + +/datum/transport_controller/linear/tram/proc/power_restored() + set_operational(TRUE) + log_transport("TC: [specific_transport_id] power restored.") + cycle_doors(CYCLE_OPEN) + send_transport_active_signal() + +/datum/transport_controller/linear/tram/proc/set_operational(new_value) + if(controller_operational != new_value) + controller_operational = new_value + +/** + * Returns the closest tram nav beacon to an atom + * + * Creates a list of nav beacons in the requested direction + * and returns the closest to be passed to the industrial_lift + * + * Arguments: source: the starting point to find a beacon + * travel_dir: travel direction in tram form, INBOUND or OUTBOUND + * beacon_type: what list of beacons we pull from + */ +/datum/transport_controller/linear/tram/proc/closest_nav_in_travel_dir(atom/origin, travel_dir, beacon_type) + if(!istype(origin) || !origin.z) + return FALSE + + var/list/obj/effect/landmark/transport/nav_beacon/tram/inbound_candidates = list() + var/list/obj/effect/landmark/transport/nav_beacon/tram/outbound_candidates = list() + + for(var/obj/effect/landmark/transport/nav_beacon/tram/candidate_beacon in SStransport.nav_beacons[beacon_type]) + if(candidate_beacon.z != origin.z || candidate_beacon.z != nav_beacon.z) + continue + + switch(nav_beacon.dir) + if(EAST, WEST) + if(candidate_beacon.y != nav_beacon.y) + continue + else if(candidate_beacon.x < nav_beacon.x) + inbound_candidates += candidate_beacon + else + outbound_candidates += candidate_beacon + if(NORTH, SOUTH) + if(candidate_beacon.x != nav_beacon.x) + continue + else if(candidate_beacon.y < nav_beacon.y) + inbound_candidates += candidate_beacon + else + outbound_candidates += candidate_beacon + + switch(travel_dir) + if(INBOUND) + var/obj/effect/landmark/transport/nav_beacon/tram/nav/selected = get_closest_atom(/obj/effect/landmark/transport/nav_beacon/tram, inbound_candidates, origin) + if(selected) + return selected + stack_trace("No inbound beacon candidate found for [origin]. Cancelling dispatch.") + return FALSE + + if(OUTBOUND) + var/obj/effect/landmark/transport/nav_beacon/tram/nav/selected = get_closest_atom(/obj/effect/landmark/transport/nav_beacon/tram, outbound_candidates, origin) + if(selected) + return selected + stack_trace("No outbound beacon candidate found for [origin]. Cancelling dispatch.") + return FALSE + + else + stack_trace("Tram receieved invalid travel direction [travel_dir]. Cancelling dispatch.") + + return FALSE + +/** + * Moves the tram when hit by an immovable rod + * + * Tells the individual tram parts where to actually go and has an extra safety checks + * incase multiple inputs get through, preventing conflicting directions and the tram + * literally ripping itself apart. all of the actual movement is handled by SStramprocess + * + * Arguments: collided_rod (the immovable rod that hit the tram) + * Return: push_destination (the landmark /obj/effect/landmark/tram/nav that the tram is being pushed to due to the rod's trajectory) + */ +/datum/transport_controller/linear/tram/proc/rod_collision(obj/effect/immovablerod/collided_rod) + log_transport("TC: [specific_transport_id] hit an immovable rod.") + if(!controller_operational) + return + var/rod_velocity_sign + // Determine inbound or outbound + if(collided_rod.dir & (NORTH|SOUTH)) + rod_velocity_sign = collided_rod.dir & NORTH ? OUTBOUND : INBOUND + else + rod_velocity_sign = collided_rod.dir & EAST ? OUTBOUND : INBOUND + + var/obj/effect/landmark/transport/nav_beacon/tram/nav/push_destination = closest_nav_in_travel_dir(origin = nav_beacon, travel_dir = rod_velocity_sign, beacon_type = IMMOVABLE_ROD_DESTINATIONS) + if(!push_destination) + return + travel_direction = get_dir(nav_beacon, push_destination) + travel_remaining = get_dist(nav_beacon, push_destination) + travel_trip_length = travel_remaining + destination_platform = push_destination + log_transport("TC: [specific_transport_id] collided at ([nav_beacon.x], [nav_beacon.y], [nav_beacon.z]) towards [push_destination] ([push_destination.x], [push_destination.y], [push_destination.z]) Dir [travel_direction] Dist [travel_remaining].") + // Don't bother processing crossing signals, where this tram's going there are no signals + //for(var/obj/machinery/transport/crossing_signal/xing as anything in SStransport.crossing_signals) + // xing.temp_malfunction() + priority_announce("In a turn of rather peculiar events, it appears that [GLOB.station_name] has struck an immovable rod. (Don't ask us where it came from.) This has led to a station brakes failure on one of the tram platforms.\n\n\ + Our diligent team of engineers have been informed and they're rushing over - although not quite at the speed of our recently flying tram.\n\n\ + So while we all look in awe at the universe's mysterious sense of humour, please stand clear of the tracks and remember to stand behind the yellow line.", "Braking News") + set_active(TRUE) + set_status_code(CONTROLS_LOCKED, TRUE) + dispatch_transport(destination_platform = push_destination) + return push_destination + +/** + * The physical cabinet on the tram. Acts as the interface between players and the controller datum. + */ +/obj/machinery/transport/tram_controller + name = "tram controller" + desc = "Makes the tram go, or something. Holds the tram's electronics, controls, and maintenance panel. A sticker above the card reader says 'Engineering access only.'" + icon = 'icons/obj/tram/tram_controllers.dmi' + icon_state = "controller-panel" + anchored = TRUE + density = FALSE + armor_type = /datum/armor/transport_module + resistance_flags = LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF + max_integrity = 750 + integrity_failure = 0.25 + layer = SIGN_LAYER + req_access = list(ACCESS_TCOMMS) + idle_power_usage = BASE_MACHINE_IDLE_CONSUMPTION * 4.8 + active_power_usage = BASE_MACHINE_ACTIVE_CONSUMPTION * 4.8 + var/datum/transport_controller/linear/tram/controller_datum + /// If the cover is open + var/cover_open = FALSE + /// If the cover is locked + var/cover_locked = TRUE + COOLDOWN_DECLARE(manual_command_cooldown) + +/obj/machinery/transport/tram_controller/hilbert + configured_transport_id = HILBERT_LINE_1 + flags_1 = NODECONSTRUCT_1 + +/obj/machinery/transport/tram_controller/Initialize(mapload) + . = ..() + register_context() + if(!id_tag) + id_tag = assign_random_name() + return INITIALIZE_HINT_LATELOAD + +/** + * Mapped or built tram cabinet isn't located on a transport module. + */ +/obj/machinery/transport/tram_controller/LateInitialize(mapload) + . = ..() + SStransport.hello(src, name, id_tag) + find_controller() + update_appearance() + +/obj/machinery/transport/tram_controller/atom_break() + set_machine_stat(machine_stat | BROKEN) + ..() + +/obj/machinery/transport/tram_controller/add_context(atom/source, list/context, obj/item/held_item, mob/user) + if(held_item?.tool_behaviour == TOOL_SCREWDRIVER) + context[SCREENTIP_CONTEXT_RMB] = panel_open ? "close panel" : "open panel" + + if(!held_item) + context[SCREENTIP_CONTEXT_RMB] = cover_open ? "close cabinet" : "open cabinet" + + if(istype(held_item, /obj/item/card/id/) && allowed(user) && !cover_open) + context[SCREENTIP_CONTEXT_LMB] = cover_locked ? "unlock cabinet" : "lock cabinet" + + if(panel_open) + if(held_item?.tool_behaviour == TOOL_WRENCH) + context[SCREENTIP_CONTEXT_RMB] = "unscrew cabinet" + if(malfunctioning || methods_to_fix.len) + context[SCREENTIP_CONTEXT_LMB] = "repair electronics" + + if(held_item?.tool_behaviour == TOOL_WELDER) + context[SCREENTIP_CONTEXT_LMB] = "repair frame" + + if(istype(held_item, /obj/item/card/emag) && !(obj_flags & EMAGGED)) + context[SCREENTIP_CONTEXT_LMB] = "emag controller" + + return CONTEXTUAL_SCREENTIP_SET + +/obj/machinery/transport/tram_controller/examine(mob/user) + . = ..() + . += span_notice("The door appears to be [cover_locked ? "locked. Swipe an ID card to unlock" : "unlocked. Swipe an ID card to lock"].") + if(panel_open) + . += span_notice("It is secured to the tram wall with [EXAMINE_HINT("bolts.")]") + else + . += span_notice("The maintenance panel can be opened with a [EXAMINE_HINT("screwdriver.")]") + + if(cover_open) + . += span_notice("The [EXAMINE_HINT("yellow reset button")] resets the tram controller if a problem occurs or needs to be restarted.") + . += span_notice("The [EXAMINE_HINT("red stop button")] immediately stops the tram, requiring a reset afterwards.") + . += span_notice("The cabinet can be closed with a [EXAMINE_HINT("Right-click.")]") + else + . += span_notice("The cabinet can be opened with a [EXAMINE_HINT("Right-click.")]") + + +/obj/machinery/transport/tram_controller/attackby(obj/item/weapon, mob/living/user, params) + if(!user.combat_mode) + if(weapon && istype(weapon, /obj/item/card/id) && !cover_open) + return try_toggle_lock(user) + + return ..() + +/obj/machinery/transport/tram_controller/wrench_act_secondary(mob/living/user, obj/item/tool) + . = ..() + if(panel_open) + balloon_alert(user, "unsecuring...") + tool.play_tool_sound(src) + if(tool.use_tool(src, user, 6 SECONDS)) + playsound(loc, 'sound/items/deconstruct.ogg', 50, vary = TRUE) + balloon_alert(user, "unsecured") + deconstruct() + +/obj/machinery/transport/tram_controller/deconstruct(disassembled = TRUE) + if(flags_1 & NODECONSTRUCT_1) + return + if(disassembled) + new /obj/item/wallframe/tram/controller(drop_location()) + else + new /obj/item/stack/sheet/mineral/titanium(drop_location(), 2) + new /obj/item/stack/sheet/iron(drop_location(), 1) + new /obj/item/shard(drop_location()) + qdel(src) + +/** + * Update the blinky lights based on the controller status, allowing to quickly check without opening up the cabinet. + */ +/obj/machinery/transport/tram_controller/update_overlays() + . = ..() + + if(!cover_open) + . += mutable_appearance(icon, "controller-closed") + if(cover_locked) + . += mutable_appearance(icon, "controller-locked") + + else + var/mutable_appearance/controller_door = mutable_appearance(icon, "controller-open") + controller_door.pixel_w = -3 + . += controller_door + + if(machine_stat & NOPOWER) + . += mutable_appearance(icon, "estop") + . += emissive_appearance(icon, "estop", src, alpha = src.alpha) + return + + . += mutable_appearance(icon, "power") + . += emissive_appearance(icon, "power", src, alpha = src.alpha) + + if(!controller_datum) + . += mutable_appearance(icon, "fatal") + . += emissive_appearance(icon, "fatal", src, alpha = src.alpha) + return + + if(controller_datum.controller_status & EMERGENCY_STOP) + . += mutable_appearance(icon, "estop") + . += emissive_appearance(icon, "estop", src, alpha = src.alpha) + return + + if(!(controller_datum.controller_status & DOORS_READY)) + . += mutable_appearance(icon, "doors") + . += emissive_appearance(icon, "doors", src, alpha = src.alpha) + + if(controller_datum.controller_active) + . += mutable_appearance(icon, "active") + . += emissive_appearance(icon, "active", src, alpha = src.alpha) + + if(controller_datum.controller_status & SYSTEM_FAULT) + . += mutable_appearance(icon, "fault") + . += emissive_appearance(icon, "fault", src, alpha = src.alpha) + + else if(controller_datum.controller_status & COMM_ERROR) + . += mutable_appearance(icon, "comms") + . += emissive_appearance(icon, "comms", src, alpha = src.alpha) + + else + . += mutable_appearance(icon, "normal") + . += emissive_appearance(icon, "normal", src, alpha = src.alpha) + +/** + * Find the controller associated with the transport module the cabinet is sitting on. + */ +/obj/machinery/transport/tram_controller/proc/find_controller() + var/obj/structure/transport/linear/tram/tram_structure = locate() in src.loc + if(!tram_structure) + return + + controller_datum = tram_structure.transport_controller_datum + if(!controller_datum) + return + + controller_datum.notify_controller(src) + RegisterSignal(SStransport, COMSIG_TRANSPORT_ACTIVE, PROC_REF(sync_controller)) + +/obj/machinery/transport/tram_controller/hilbert/find_controller() + for(var/datum/transport_controller/linear/tram/tram as anything in SStransport.transports_by_type[TRANSPORT_TYPE_TRAM]) + if(tram.specific_transport_id == configured_transport_id) + controller_datum = tram + break + + if(!controller_datum) + return + + controller_datum.notify_controller(src) + RegisterSignal(SStransport, COMSIG_TRANSPORT_ACTIVE, PROC_REF(sync_controller)) + +/** + * Since the machinery obj is a dumb terminal for the controller datum, sync the display with the status bitfield of the tram + */ +/obj/machinery/transport/tram_controller/proc/sync_controller(source, controller, controller_status, travel_direction, destination_platform) + use_power(active_power_usage) + if(controller != controller_datum) + return + update_appearance() + +/obj/machinery/transport/tram_controller/attack_hand(mob/living/user, params) + . = ..() + if(!cover_open && cover_locked) + balloon_alert(user, "it's locked! swipe ID!") + return + +/obj/machinery/transport/tram_controller/attack_hand_secondary(mob/living/user, params) + . = ..() + + if(!cover_open && cover_locked) + balloon_alert(user, "it's locked! swipe ID!") + return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN + + toggle_door() + return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN + +/obj/machinery/transport/tram_controller/proc/toggle_door() + if(!cover_open) + playsound(loc, 'sound/machines/closet_open.ogg', 35, TRUE, -3) + else + playsound(loc, 'sound/machines/closet_close.ogg', 50, TRUE, -3) + cover_open = !cover_open + update_appearance() + +/obj/machinery/transport/tram_controller/proc/try_toggle_lock(mob/living/user, item, params) + var/obj/item/card/id/id_card = user.get_idcard(TRUE) + if(obj_flags & EMAGGED) + balloon_alert(user, "access controller damaged!") + return FALSE + + else if(check_access(id_card)) + cover_locked = !cover_locked + balloon_alert(user, "controls [cover_locked ? "locked" : "unlocked"]") + update_appearance() + return TRUE + + else + balloon_alert(user, "access denied") + return FALSE + +/obj/machinery/transport/tram_controller/emag_act(mob/user, obj/item/card/emag/emag_card) + if(obj_flags & EMAGGED) + balloon_alert(user, "already fried!") + return FALSE + obj_flags |= EMAGGED + cover_locked = FALSE + playsound(src, SFX_SPARKS, 100, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) + balloon_alert(user, "access controller shorted") + return TRUE + +/** + * Check if the tram was malfunctioning due to the random event, and if so end the event on repair. + */ +/obj/machinery/transport/tram_controller/try_fix_machine(obj/machinery/transport/machine, mob/living/user, obj/item/tool) + . = ..() + + if(. == FALSE) + return + + if(!controller_datum) + return + + var/datum/round_event/tram_malfunction/malfunction_event = locate(/datum/round_event/tram_malfunction) in SSevents.running + if(malfunction_event) + malfunction_event.end() + + if(controller_datum.controller_status & COMM_ERROR) + controller_datum.set_status_code(COMM_ERROR, FALSE) + +/obj/machinery/transport/tram_controller/ui_interact(mob/user, datum/tgui/ui) + . = ..() + + if(!cover_open && !issiliconoradminghost(user) && !isobserver(user)) + return + + if(!is_operational) + return + + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "TramController") + ui.open() + +/obj/machinery/transport/tram_controller/ui_data(mob/user) + var/list/data = list() + + data = list( + "transportId" = controller_datum.specific_transport_id, + "controllerActive" = controller_datum.controller_active, + "controllerOperational" = controller_datum.controller_operational, + "travelDirection" = controller_datum.travel_direction, + "destinationPlatform" = controller_datum.destination_platform, + "idlePlatform" = controller_datum.idle_platform, + "recoveryMode" = controller_datum.recovery_mode, + "currentSpeed" = controller_datum.current_speed, + "currentLoad" = controller_datum.current_load, + "statusSF" = controller_datum.controller_status & SYSTEM_FAULT, + "statusCE" = controller_datum.controller_status & COMM_ERROR, + "statusES" = controller_datum.controller_status & EMERGENCY_STOP, + "statusPD" = controller_datum.controller_status & PRE_DEPARTURE, + "statusDR" = controller_datum.controller_status & DOORS_READY, + "statusCL" = controller_datum.controller_status & CONTROLS_LOCKED, + "statusBS" = controller_datum.controller_status & BYPASS_SENSORS, + ) + + return data + +/obj/machinery/transport/tram_controller/ui_static_data(mob/user) + var/list/data = list() + data["destinations"] = SStransport.detailed_destination_list(controller_datum.specific_transport_id) + + return data + +/obj/machinery/transport/tram_controller/ui_act(action, params) + . = ..() + if (.) + return + + if(!COOLDOWN_FINISHED(src, manual_command_cooldown)) + return + + switch(action) + + if("dispatch") + var/obj/effect/landmark/transport/nav_beacon/tram/platform/destination_platform + for (var/obj/effect/landmark/transport/nav_beacon/tram/platform/destination as anything in SStransport.nav_beacons[controller_datum.specific_transport_id]) + if(destination.name == params["tripDestination"]) + destination_platform = destination + break + + if(!destination_platform) + return FALSE + + SEND_SIGNAL(src, COMSIG_TRANSPORT_REQUEST, controller_datum.specific_transport_id, destination_platform.platform_code) + update_appearance() + + if("estop") + controller_datum.estop() + + if("reset") + controller_datum.reset_position() + + if("dclose") + controller_datum.cycle_doors(CYCLE_CLOSED) + + if("dopen") + controller_datum.cycle_doors(CYCLE_OPEN) + + if("togglesensors") + if(controller_datum.controller_status & BYPASS_SENSORS) + controller_datum.set_status_code(BYPASS_SENSORS, FALSE) + else + controller_datum.set_status_code(BYPASS_SENSORS, TRUE) + + COOLDOWN_START(src, manual_command_cooldown, 2 SECONDS) + +/obj/item/wallframe/tram/controller + name = "tram controller cabinet" + desc = "A box that contains the equipment to control a tram. Just secure to the tram wall." + icon = 'icons/obj/tram/tram_controllers.dmi' + icon_state = "controller-panel" + custom_materials = list(/datum/material/titanium = SHEET_MATERIAL_AMOUNT * 4, /datum/material/iron = SHEET_MATERIAL_AMOUNT * 2, /datum/material/glass = SHEET_MATERIAL_AMOUNT * 2) + result_path = /obj/machinery/transport/tram_controller + pixel_shift = 32 diff --git a/code/modules/transport/tram/tram_controls.dm b/code/modules/transport/tram/tram_controls.dm new file mode 100644 index 00000000000..e62943c6623 --- /dev/null +++ b/code/modules/transport/tram/tram_controls.dm @@ -0,0 +1,248 @@ +/obj/machinery/computer/tram_controls + name = "tram controls" + desc = "An interface for the tram that lets you tell the tram where to go and hopefully it makes it there. I'm here to describe the controls to you, not to inspire confidence." + icon_state = "tram_controls" + base_icon_state = "tram" + icon_screen = TRAMSTATION_LINE_1 + icon_keyboard = null + layer = SIGN_LAYER + density = FALSE + max_integrity = 400 + integrity_failure = 0.1 + armor_type = /datum/armor/transport_machinery + circuit = /obj/item/circuitboard/computer/tram_controls + light_color = COLOR_BLUE_LIGHT + light_range = 0 //we dont want to spam SSlighting with source updates every movement + brightness_on = 0 + /// What sign face prefixes we have icons for + var/static/list/available_faces = list() + /// The sign face we're displaying + var/sign_face + /// Weakref to the tram piece we control + var/datum/weakref/transport_ref + /// The ID of the tram we're controlling + var/specific_transport_id = TRAMSTATION_LINE_1 + /// If the sign is adjusted for split type tram windows + var/split_mode = FALSE + +/obj/machinery/computer/tram_controls/split + circuit = /obj/item/circuitboard/computer/tram_controls/split + split_mode = TRUE + +/obj/machinery/computer/tram_controls/split/directional/north + dir = SOUTH + pixel_x = -8 + pixel_y = 32 + +/obj/machinery/computer/tram_controls/split/directional/south + dir = NORTH + pixel_x = 8 + pixel_y = -32 + +/obj/machinery/computer/tram_controls/split/directional/east + dir = WEST + pixel_x = 32 + +/obj/machinery/computer/tram_controls/split/directional/west + dir = EAST + pixel_x = -32 + +/obj/machinery/computer/tram_controls/Initialize(mapload) + . = ..() + var/obj/item/circuitboard/computer/tram_controls/my_circuit = circuit + split_mode = my_circuit.split_mode + +/obj/machinery/computer/tram_controls/LateInitialize() + . = ..() + if(!id_tag) + id_tag = assign_random_name() + SStransport.hello(src, name, id_tag) + RegisterSignal(SStransport, COMSIG_TRANSPORT_RESPONSE, PROC_REF(call_response)) + find_tram() + + var/datum/transport_controller/linear/tram/tram = transport_ref?.resolve() + if(tram) + RegisterSignal(SStransport, COMSIG_TRANSPORT_ACTIVE, PROC_REF(update_display)) + +/** + * Finds the tram from the console + * + * Locates tram parts in the lift global list after everything is done. + */ +/obj/machinery/computer/tram_controls/proc/find_tram() + for(var/datum/transport_controller/linear/transport as anything in SStransport.transports_by_type[TRANSPORT_TYPE_TRAM]) + if(transport.specific_transport_id == specific_transport_id) + transport_ref = WEAKREF(transport) + return + +/obj/machinery/computer/tram_controls/ui_state(mob/user) + return GLOB.not_incapacitated_state + +/obj/machinery/computer/tram_controls/ui_status(mob/user,/datum/tgui/ui) + var/datum/transport_controller/linear/tram/tram = transport_ref?.resolve() + + if(tram?.controller_active) + return UI_CLOSE + if(!in_range(user, src) && !isobserver(user)) + return UI_CLOSE + return ..() + +/obj/machinery/computer/tram_controls/ui_interact(mob/user, datum/tgui/ui) + . = ..() + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "TramControl", name) + ui.open() + +/obj/machinery/computer/tram_controls/ui_data(mob/user) + var/datum/transport_controller/linear/tram/tram_controller = transport_ref?.resolve() + var/list/data = list() + data["moving"] = tram_controller?.controller_active + data["broken"] = (tram_controller ? FALSE : TRUE) || (tram_controller?.paired_cabinet ? FALSE : TRUE) + var/obj/effect/landmark/transport/nav_beacon/tram/platform/current_loc = tram_controller?.idle_platform + if(current_loc) + data["tram_location"] = current_loc.name + return data + +/obj/machinery/computer/tram_controls/ui_static_data(mob/user) + var/list/data = list() + data["destinations"] = get_destinations() + return data + +/** + * Finds the destinations for the tram console gui + * + * Pulls tram landmarks from the landmark gobal list + * and uses those to show the proper icons and destination + * names for the tram console gui. + */ +/obj/machinery/computer/tram_controls/proc/get_destinations() + . = list() + for(var/obj/effect/landmark/transport/nav_beacon/tram/platform/destination as anything in SStransport.nav_beacons[specific_transport_id]) + var/list/this_destination = list() + this_destination["name"] = destination.name + this_destination["dest_icons"] = destination.tgui_icons + this_destination["id"] = destination.platform_code + . += list(this_destination) + +/obj/machinery/computer/tram_controls/ui_act(action, params) + . = ..() + if(.) + return + + switch(action) + if("send") + var/obj/effect/landmark/transport/nav_beacon/tram/platform/destination_platform + for(var/obj/effect/landmark/transport/nav_beacon/tram/platform/destination as anything in SStransport.nav_beacons[specific_transport_id]) + if(destination.platform_code == params["destination"]) + destination_platform = destination + break + + if(isnull(destination_platform)) + return FALSE + + SStransport.incoming_request(src, specific_transport_id, destination_platform.platform_code) + update_appearance() + +/obj/machinery/computer/tram_controls/proc/update_display(datum/source, datum/transport_controller/linear/tram/controller, controller_active, controller_status, travel_direction, obj/effect/landmark/transport/nav_beacon/tram/platform/destination_platform) + SIGNAL_HANDLER + + if(machine_stat & (NOPOWER|BROKEN)) + icon_screen = null + update_appearance() + return + + if(isnull(controller) || !controller.controller_operational) + icon_screen = "[base_icon_state]_broken" + update_appearance() + return + + if(isnull(destination_platform)) + icon_screen = "[specific_transport_id]" + update_appearance() + return + + if(controller.controller_status & EMERGENCY_STOP || controller.controller_status & SYSTEM_FAULT) + icon_screen = "[base_icon_state]_NIS" + update_appearance() + return + + if(controller_active) + icon_screen = "[base_icon_state]_0[travel_direction]" + update_appearance() + return + + icon_screen = "" + icon_screen += "[controller.specific_transport_id]" + icon_screen += "[destination_platform.platform_code]" + + update_appearance() + +/obj/machinery/computer/tram_controls/on_construction(mob/user) + . = ..() + var/obj/item/circuitboard/computer/tram_controls/my_circuit = circuit + split_mode = my_circuit.split_mode + if(split_mode) + switch(dir) + if(NORTH) + pixel_x = 8 + pixel_y = -32 + if(SOUTH) + pixel_x = -8 + pixel_y = 32 + if(EAST) + pixel_x = -32 + pixel_y = -8 + if(WEST) + pixel_x = 32 + pixel_y = 8 + else + switch(dir) + if(NORTH) + pixel_y = -32 + if(SOUTH) + pixel_y = 32 + if(EAST) + pixel_x = -32 + if(WEST) + pixel_x = 32 + +/obj/machinery/computer/tram_controls/update_overlays() + . = ..() + + if(isnull(icon_screen)) + return + + . += emissive_appearance(icon, icon_screen, src, alpha = src.alpha) + +/obj/machinery/computer/tram_controls/power_change() + ..() + var/datum/transport_controller/linear/tram/tram = transport_ref?.resolve() + if(isnull(tram)) + icon_screen = "[base_icon_state]_broken" + update_appearance() + return + + update_display(src, tram, tram.controller_active, tram.controller_status, tram.travel_direction, tram.destination_platform) + +/obj/machinery/computer/tram_controls/proc/call_response(controller, list/relevant, response_code, response_info) + SIGNAL_HANDLER + switch(response_code) + if(REQUEST_SUCCESS) + say("The next station is: [response_info]") + + if(REQUEST_FAIL) + if(!LAZYFIND(relevant, src)) + return + + switch(response_info) + if(NOT_IN_SERVICE) + say("The tram is not in service. Please contact the nearest engineer.") + if(INVALID_PLATFORM) + say("Configuration error. Please contact the nearest engineer.") + if(INTERNAL_ERROR) + say("Tram controller error. Please contact the nearest engineer.") + else + return + +MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/computer/tram_controls, 32) diff --git a/code/modules/transport/tram/tram_displays.dm b/code/modules/transport/tram/tram_displays.dm new file mode 100644 index 00000000000..908651f3b11 --- /dev/null +++ b/code/modules/transport/tram/tram_displays.dm @@ -0,0 +1,166 @@ +/obj/machinery/transport/destination_sign + name = "destination sign" + desc = "A display to show you what direction the tram is travelling." + icon = 'icons/obj/tram/tram_display.dmi' + icon_state = "desto_blank" + base_icon_state = "desto" + use_power = NO_POWER_USE + idle_power_usage = BASE_MACHINE_IDLE_CONSUMPTION * 1.2 + active_power_usage = BASE_MACHINE_ACTIVE_CONSUMPTION * 0.47 + anchored = TRUE + density = FALSE + layer = SIGN_LAYER + light_range = 0 + /// What sign face prefixes we have icons for + var/static/list/available_faces = list() + /// The sign face we're displaying + var/sign_face + var/sign_color = COLOR_DISPLAY_BLUE + +/obj/machinery/transport/destination_sign/split/north + pixel_x = -8 + +/obj/machinery/transport/destination_sign/split/south + pixel_x = 8 + +/obj/machinery/transport/destination_sign/indicator + icon = 'icons/obj/tram/tram_indicator.dmi' + icon_state = "indi_blank" + base_icon_state = "indi" + use_power = IDLE_POWER_USE + max_integrity = 50 + light_range = 2 + light_power = 0.7 + light_angle = 115 + flags_1 = NONE + +/obj/item/wallframe/indicator_display + name = "indicator display frame" + desc = "Used to build tram indicator displays, just secure to the wall." + icon_state = "indi_blank" + icon = 'icons/obj/tram/tram_indicator.dmi' + custom_materials = list(/datum/material/titanium = SHEET_MATERIAL_AMOUNT * 4, /datum/material/iron = SHEET_MATERIAL_AMOUNT * 2, /datum/material/glass = SHEET_MATERIAL_AMOUNT * 2) + result_path = /obj/machinery/transport/destination_sign/indicator + pixel_shift = 32 + +/obj/machinery/transport/destination_sign/Initialize(mapload) + . = ..() + RegisterSignal(SStransport, COMSIG_TRANSPORT_ACTIVE, PROC_REF(update_sign)) + SStransport.displays += src + available_faces = list( + TRAMSTATION_LINE_1, + ) + set_light(l_dir = REVERSE_DIR(dir)) + return INITIALIZE_HINT_LATELOAD + +/obj/machinery/transport/destination_sign/Destroy() + SStransport.displays -= src + . = ..() + +/obj/machinery/transport/destination_sign/indicator/setDir(newdir) + . = ..() + set_light(l_dir = REVERSE_DIR(dir)) + +/obj/machinery/transport/destination_sign/indicator/LateInitialize(mapload) + . = ..() + link_tram() + +/obj/machinery/transport/destination_sign/indicator/add_context(atom/source, list/context, obj/item/held_item, mob/user) + . = ..() + if(held_item?.tool_behaviour == TOOL_WRENCH) + context[SCREENTIP_CONTEXT_RMB] = "unanchor" + if(held_item?.tool_behaviour == TOOL_WELDER) + context[SCREENTIP_CONTEXT_LMB] = "repair" + + return CONTEXTUAL_SCREENTIP_SET + + +/obj/machinery/transport/destination_sign/indicator/examine(mob/user) + . = ..() + + if(panel_open) + . += span_notice("It is secured to the tram wall with [EXAMINE_HINT("bolts.")]") + +/obj/machinery/transport/destination_sign/deconstruct(disassembled = TRUE) + if(flags_1 & NODECONSTRUCT_1) + return + if(disassembled) + new /obj/item/wallframe/indicator_display(drop_location()) + else + new /obj/item/stack/sheet/mineral/titanium(drop_location(), 2) + new /obj/item/stack/sheet/iron(drop_location(), 1) + new /obj/item/shard(drop_location()) + new /obj/item/shard(drop_location()) + qdel(src) + +/obj/machinery/transport/destination_sign/indicator/wrench_act_secondary(mob/living/user, obj/item/tool) + . = ..() + balloon_alert(user, "[anchored ? "un" : ""]securing...") + tool.play_tool_sound(src) + if(tool.use_tool(src, user, 6 SECONDS)) + playsound(loc, 'sound/items/deconstruct.ogg', 50, vary = TRUE) + balloon_alert(user, "[anchored ? "un" : ""]secured") + deconstruct() + return TRUE + +/obj/machinery/transport/destination_sign/proc/update_sign(datum/source, datum/transport_controller/linear/tram/controller, controller_active, controller_status, travel_direction, obj/effect/landmark/transport/nav_beacon/tram/platform/destination_platform) + SIGNAL_HANDLER + + if(machine_stat & (NOPOWER|BROKEN)) + sign_face = null + update_appearance() + return + + if(!controller || !controller.controller_operational || isnull(destination_platform)) + sign_face = "[base_icon_state]_NIS" + sign_color = COLOR_DISPLAY_RED + update_appearance() + return + + if(controller.controller_status & EMERGENCY_STOP || controller.controller_status & SYSTEM_FAULT) + sign_face = "[base_icon_state]_NIS" + sign_color = COLOR_DISPLAY_RED + update_appearance() + return + + sign_face = "" + sign_face += "[base_icon_state]_" + if(!LAZYFIND(available_faces, controller.specific_transport_id)) + sign_face += "[TRAMSTATION_LINE_1]" + else + sign_face += "[controller.specific_transport_id]" + + sign_face += "[controller_active]" + sign_face += "[destination_platform.platform_code]" + sign_face += "[travel_direction]" + sign_color = COLOR_DISPLAY_BLUE + + update_appearance() + +/obj/machinery/transport/destination_sign/update_icon_state() + . = ..() + if(isnull(sign_face)) + icon_state = "[base_icon_state]_blank" + return + else + icon_state = sign_face + +/obj/machinery/transport/destination_sign/update_overlays() + . = ..() + + if(isnull(sign_face)) + set_light(l_on = FALSE) + return + + set_light(l_on = TRUE, l_color = sign_color) + . += emissive_appearance(icon, "[sign_face]_e", src, alpha = src.alpha) + +/obj/machinery/transport/destination_sign/indicator/power_change() + ..() + var/datum/transport_controller/linear/tram/tram = transport_ref?.resolve() + if(!tram) + return + + update_sign(src, tram, tram.controller_active, tram.controller_status, tram.travel_direction, tram.destination_platform) + +MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/transport/destination_sign/indicator, 32) diff --git a/code/modules/transport/tram/tram_doors.dm b/code/modules/transport/tram/tram_doors.dm new file mode 100644 index 00000000000..d836685acf1 --- /dev/null +++ b/code/modules/transport/tram/tram_doors.dm @@ -0,0 +1,230 @@ +#define TRAM_DOOR_WARNING_TIME (1.4 SECONDS) +#define TRAM_DOOR_CYCLE_TIME (0.4 SECONDS) +#define TRAM_DOOR_CRUSH_TIME (0.7 SECONDS) +#define TRAM_DOOR_RECYCLE_TIME (3 SECONDS) + +/obj/machinery/door/airlock/tram + name = "tram door" + icon = 'icons/obj/doors/airlocks/tram/tram.dmi' + overlays_file = 'icons/obj/doors/airlocks/tram/tram-overlays.dmi' + multi_tile = TRUE + opacity = FALSE + assemblytype = null + airlock_material = "glass" + air_tight = TRUE + req_access = list(ACCESS_TCOMMS) + transport_linked_id = TRAMSTATION_LINE_1 + doorOpen = 'sound/machines/tramopen.ogg' + doorClose = 'sound/machines/tramclose.ogg' + autoclose = FALSE + /// Weakref to the tram we're attached + var/datum/weakref/transport_ref + var/retry_counter + var/crushing_in_progress = FALSE + bound_width = 64 + +/obj/machinery/door/airlock/tram/Initialize(mapload) + . = ..() + if(!id_tag) + id_tag = assign_random_name() + +/obj/machinery/door/airlock/tram/open(forced = DEFAULT_DOOR_CHECKS) + if(operating || welded || locked || seal) + return FALSE + + if(!density) + return TRUE + + if(forced == DEFAULT_DOOR_CHECKS && (!hasPower() || wires.is_cut(WIRE_OPEN))) + return FALSE + + SEND_SIGNAL(src, COMSIG_AIRLOCK_OPEN, FALSE) + operating = TRUE + update_icon(ALL, AIRLOCK_OPENING, TRUE) + + if(forced >= BYPASS_DOOR_CHECKS) + playsound(src, 'sound/machines/airlockforced.ogg', vol = 40, vary = FALSE) + sleep(TRAM_DOOR_CYCLE_TIME) + else + playsound(src, doorOpen, vol = 40, vary = FALSE) + sleep(TRAM_DOOR_WARNING_TIME) + + set_density(FALSE) + if(!isnull(filler)) + filler.set_density(FALSE) + update_freelook_sight() + flags_1 &= ~PREVENT_CLICK_UNDER_1 + air_update_turf(TRUE, FALSE) + sleep(TRAM_DOOR_CYCLE_TIME) + layer = OPEN_DOOR_LAYER + update_icon(ALL, AIRLOCK_OPEN, TRUE) + operating = FALSE + + return TRUE + +/obj/machinery/door/airlock/tram/close(forced = DEFAULT_DOOR_CHECKS, force_crush = FALSE) + retry_counter++ + if(retry_counter >= 4 || force_crush || forced == BYPASS_DOOR_CHECKS) + try_to_close(forced = BYPASS_DOOR_CHECKS) + return + + if(retry_counter == 1) + playsound(src, 'sound/machines/chime.ogg', 40, vary = FALSE, extrarange = SHORT_RANGE_SOUND_EXTRARANGE) + + addtimer(CALLBACK(src, PROC_REF(verify_status)), TRAM_DOOR_RECYCLE_TIME) + try_to_close() + +/** + * Perform a close attempt and report TRUE/FALSE if it worked + * + * Arguments: + * * rapid - boolean: if TRUE will skip safety checks and crush whatever is in the way + */ +/obj/machinery/door/airlock/tram/proc/try_to_close(forced = DEFAULT_DOOR_CHECKS) + if(operating || welded || locked || seal) + return FALSE + if(density) + return TRUE + crushing_in_progress = TRUE + var/hungry_door = (forced == BYPASS_DOOR_CHECKS || !safe) + if((obj_flags & EMAGGED) || !safe) + do_sparks(3, TRUE, src) + playsound(src, SFX_SPARKS, vol = 75, vary = FALSE, extrarange = SHORT_RANGE_SOUND_EXTRARANGE) + use_power(50) + playsound(src, doorClose, vol = 40, vary = FALSE) + operating = TRUE + layer = CLOSED_DOOR_LAYER + update_icon(ALL, AIRLOCK_CLOSING, 1) + sleep(TRAM_DOOR_WARNING_TIME) + if(!hungry_door) + for(var/turf/checked_turf in locs) + for(var/atom/movable/blocker in checked_turf) + if(blocker.density && blocker != src) //something is blocking the door + say("Please stand clear of the doors!") + playsound(src, 'sound/machines/buzz-sigh.ogg', 60, vary = FALSE, extrarange = SHORT_RANGE_SOUND_EXTRARANGE) + layer = OPEN_DOOR_LAYER + update_icon(ALL, AIRLOCK_OPEN, 1) + operating = FALSE + return FALSE + SEND_SIGNAL(src, COMSIG_AIRLOCK_CLOSE) + sleep(TRAM_DOOR_CRUSH_TIME) + set_density(TRUE) + if(!isnull(filler)) + filler.set_density(TRUE) + update_freelook_sight() + flags_1 |= PREVENT_CLICK_UNDER_1 + air_update_turf(TRUE, TRUE) + crush() + crushing_in_progress = FALSE + sleep(TRAM_DOOR_CYCLE_TIME) + update_icon(ALL, AIRLOCK_CLOSED, 1) + operating = FALSE + retry_counter = 0 + return TRUE + +/** + * Crush the jerk holding up the tram from moving + * + * Tram doors need their own crush proc because the normal one + * leaves you stunned far too long, leading to the doors crushing + * you over and over, no escape! + * + * While funny to watch, not ideal for the player. + */ +/obj/machinery/door/airlock/tram/crush() + for(var/turf/checked_turf in locs) + for(var/mob/living/future_pancake in checked_turf) + future_pancake.visible_message(span_warning("[src] beeps angrily and closes on [future_pancake]!"), span_userdanger("[src] beeps angrily and closes on you!")) + SEND_SIGNAL(future_pancake, COMSIG_LIVING_DOORCRUSHED, src) + if(ishuman(future_pancake) || ismonkey(future_pancake)) + future_pancake.emote("scream") + future_pancake.adjustBruteLoss(DOOR_CRUSH_DAMAGE * 2) + future_pancake.Paralyze(2 SECONDS) + + else //for simple_animals & borgs + future_pancake.adjustBruteLoss(DOOR_CRUSH_DAMAGE * 2) + var/turf/location = get_turf(src) + //add_blood doesn't work for borgs/xenos, but add_blood_floor does. + future_pancake.add_splatter_floor(location) + + log_combat(src, future_pancake, "crushed") + + for(var/obj/vehicle/sealed/mecha/mech in checked_turf) // Your fancy metal won't save you here! + mech.take_damage(DOOR_CRUSH_DAMAGE) + log_combat(src, mech, "crushed") + +/** + * Checks if the door close action was successful. Retries if it failed + * + * If some jerk is blocking the doors, they've had enough warning by attempt 3, + * take a chunk of skin, people have places to be! + */ +/obj/machinery/door/airlock/tram/proc/verify_status() + if(airlock_state == AIRLOCK_CLOSED) + return + + if(retry_counter < 3) + close() + return + + playsound(src, 'sound/machines/buzz-two.ogg', 60, vary = FALSE, extrarange = SHORT_RANGE_SOUND_EXTRARANGE) + say("YOU'RE HOLDING UP THE TRAM, ASSHOLE!") + close(forced = BYPASS_DOOR_CHECKS) + +/** + * Set the weakref for the tram we're attached to + */ +/obj/machinery/door/airlock/tram/proc/find_tram() + for(var/datum/transport_controller/linear/tram/tram as anything in SStransport.transports_by_type[TRANSPORT_TYPE_TRAM]) + if(tram.specific_transport_id == transport_linked_id) + transport_ref = WEAKREF(tram) + +/obj/machinery/door/airlock/tram/Initialize(mapload, set_dir, unres_sides) + . = ..() + RemoveElement(/datum/element/atmos_sensitive, mapload) + return INITIALIZE_HINT_LATELOAD + +/obj/machinery/door/airlock/tram/LateInitialize(mapload) + . = ..() + INVOKE_ASYNC(src, PROC_REF(open)) + SStransport.doors += src + find_tram() + +/obj/machinery/door/airlock/tram/Destroy() + SStransport.doors -= src + return ..() + +/** + * Tram doors can be opened with hands when unpowered + */ +/obj/machinery/door/airlock/tram/examine(mob/user) + . = ..() + . += span_notice("It has an emergency mechanism to open using [EXAMINE_HINT("just your hands")] in the event of an emergency.") + +/** + * Tram doors can be opened with hands when unpowered + */ +/obj/machinery/door/airlock/tram/try_safety_unlock(mob/user) + if(!hasPower() && density) + balloon_alert(user, "pulling emergency exit...") + if(do_after(user, 4 SECONDS, target = src)) + try_to_crowbar(null, user, TRUE) + return TRUE + +/** + * If you pry (bump) the doors open midtravel, open quickly so you can jump out and make a daring escape. + */ +/obj/machinery/door/airlock/tram/bumpopen(mob/user, forced = BYPASS_DOOR_CHECKS) + if(operating || !density) + return + var/datum/transport_controller/linear/tram/tram_part = transport_ref?.resolve() + add_fingerprint(user) + if((tram_part.travel_remaining < DEFAULT_TRAM_LENGTH || tram_part.travel_remaining > tram_part.travel_trip_length - DEFAULT_TRAM_LENGTH) && tram_part.controller_active) + return // we're already animating, don't reset that + open(forced = BYPASS_DOOR_CHECKS) + return + +#undef TRAM_DOOR_WARNING_TIME +#undef TRAM_DOOR_CYCLE_TIME +#undef TRAM_DOOR_CRUSH_TIME +#undef TRAM_DOOR_RECYCLE_TIME diff --git a/code/modules/transport/tram/tram_floors.dm b/code/modules/transport/tram/tram_floors.dm new file mode 100644 index 00000000000..2afb59f9b4a --- /dev/null +++ b/code/modules/transport/tram/tram_floors.dm @@ -0,0 +1,322 @@ +/turf/open/floor/noslip/tram + name = "high-traction tram platform" + icon = 'icons/turf/tram.dmi' + icon_state = "noslip_tram" + base_icon_state = "noslip_tram" + floor_tile = /obj/item/stack/tile/noslip/tram + +/turf/open/floor/tram + name = "tram guideway" + icon = 'icons/turf/tram.dmi' + icon_state = "tram_platform" + base_icon_state = "tram_platform" + floor_tile = /obj/item/stack/tile/tram + footstep = FOOTSTEP_CATWALK + barefootstep = FOOTSTEP_HARD_BAREFOOT + clawfootstep = FOOTSTEP_HARD_CLAW + heavyfootstep = FOOTSTEP_GENERIC_HEAVY + tiled_dirt = FALSE + rcd_proof = TRUE + +/turf/open/floor/tram/examine(mob/user) + . += ..() + . += span_notice("The reinforcement bolts are [EXAMINE_HINT("wrenched")] firmly in place. Use a [EXAMINE_HINT("wrench")] to remove the plate.") + +/turf/open/floor/tram/attackby(obj/item/object, mob/living/user, params) + . = ..() + if(istype(object, /obj/item/stack/thermoplastic)) + build_with_transport_tiles(object, user) + else if(istype(object, /obj/item/stack/sheet/mineral/titanium)) + build_with_titanium(object, user) + +/turf/open/floor/tram/make_plating(force = FALSE) + if(force) + return ..() + return //unplateable + +/turf/open/floor/tram/try_replace_tile(obj/item/stack/tile/replacement_tile, mob/user, params) + return + +/turf/open/floor/tram/crowbar_act(mob/living/user, obj/item/item) + return + +/turf/open/floor/tram/wrench_act(mob/living/user, obj/item/item) + ..() + to_chat(user, span_notice("You begin removing the plate...")) + if(item.use_tool(src, user, 30, volume=80)) + if(!istype(src, /turf/open/floor/tram)) + return TRUE + if(floor_tile) + new floor_tile(src, 2) + ScrapeAway(flags = CHANGETURF_INHERIT_AIR) + return TRUE + +/turf/open/floor/tram/ex_act(severity, target) + if(target == src) + ScrapeAway(flags = CHANGETURF_INHERIT_AIR) + return TRUE + if(severity < EXPLODE_DEVASTATE && is_shielded()) + return FALSE + + switch(severity) + if(EXPLODE_DEVASTATE) + if(prob(80)) + if(!ispath(baseturf_at_depth(2), /turf/open/floor)) + attempt_lattice_replacement() + else + ScrapeAway(2, flags = CHANGETURF_INHERIT_AIR) + else + break_tile() + if(EXPLODE_HEAVY) + if(prob(30)) + if(!ispath(baseturf_at_depth(2), /turf/open/floor)) + attempt_lattice_replacement() + else + ScrapeAway(2, flags = CHANGETURF_INHERIT_AIR) + else + break_tile() + if(EXPLODE_LIGHT) + if(prob(50)) + break_tile() + + return TRUE + +/turf/open/floor/tram/broken_states() + return list("tram_platform-damaged1","tram_platform-damaged2") + +/turf/open/floor/tram/tram_platform/burnt_states() + return list("tram_platform-scorched1","tram_platform-scorched2") + +/turf/open/floor/tram/plate + name = "linear induction plate" + desc = "The linear induction plate that powers the tram." + icon = 'icons/turf/tram.dmi' + icon_state = "tram_plate" + base_icon_state = "tram_plate" + flags_1 = NONE + +/turf/open/floor/tram/plate/broken_states() + return list("tram_plate-damaged1","tram_plate-damaged2") + +/turf/open/floor/tram/plate/burnt_states() + return list("tram_plate-scorched1","tram_plate-scorched2") + +/turf/open/floor/tram/plate/energized + desc = "The linear induction plate that powers the tram. It is currently energized." + /// Inbound station + var/inbound + /// Outbound station + var/outbound + /// Transport ID of the tram + var/specific_transport_id = TRAMSTATION_LINE_1 + +/turf/open/floor/tram/plate/energized/Initialize(mapload) + . = ..() + AddComponent(/datum/component/energized, inbound, outbound, specific_transport_id) + +/turf/open/floor/tram/plate/energized/examine(mob/user) + . = ..() + if(broken || burnt) + . += span_danger("It looks damaged and the electrical components exposed!") + . += span_notice("The plate can be repaired using a [EXAMINE_HINT("titanium sheet")].") + +/turf/open/floor/tram/plate/energized/broken_states() + return list("energized_plate_damaged") + +/turf/open/floor/tram/plate/energized/burnt_states() + return list("energized_plate_damaged") + +/turf/open/floor/tram/plate/energized/attackby(obj/item/attacking_item, mob/living/user, params) + if((broken || burnt) && istype(attacking_item, /obj/item/stack/sheet/mineral/titanium)) + if(attacking_item.use(1)) + broken = FALSE + update_appearance() + balloon_alert(user, "plate replaced") + return + return ..() + +// Resetting the tram contents to its original state needs the turf to be there +/turf/open/indestructible/tram + name = "tram guideway" + icon = 'icons/turf/tram.dmi' + icon_state = "tram_platform" + base_icon_state = "tram_platform" + footstep = FOOTSTEP_CATWALK + barefootstep = FOOTSTEP_HARD_BAREFOOT + clawfootstep = FOOTSTEP_HARD_CLAW + heavyfootstep = FOOTSTEP_GENERIC_HEAVY + +/turf/open/indestructible/tram/attackby(obj/item/object, mob/living/user, params) + . = ..() + if(istype(object, /obj/item/stack/thermoplastic)) + build_with_transport_tiles(object, user) + else if(istype(object, /obj/item/stack/sheet/mineral/titanium)) + build_with_titanium(object, user) + +/turf/open/indestructible/tram/plate + name = "linear induction plate" + desc = "The linear induction plate that powers the tram." + icon_state = "tram_plate" + base_icon_state = "tram_plate" + flags_1 = NONE + +/turf/open/floor/glass/reinforced/tram/Initialize(mapload) + . = ..() + RemoveElement(/datum/element/atmos_sensitive, mapload) + +/turf/open/floor/glass/reinforced/tram + name = "tram bridge" + desc = "It shakes a bit when you step, but lets you cross between sides quickly!" + +/obj/structure/thermoplastic + name = "tram floor" + desc = "A lightweight thermoplastic flooring." + icon = 'icons/turf/tram.dmi' + icon_state = "tram_dark" + base_icon_state = "tram_dark" + density = FALSE + anchored = TRUE + max_integrity = 150 + integrity_failure = 0.75 + armor_type = /datum/armor/tram_floor + layer = TRAM_FLOOR_LAYER + plane = FLOOR_PLANE + obj_flags = BLOCK_Z_OUT_DOWN | BLOCK_Z_OUT_UP + appearance_flags = PIXEL_SCALE|KEEP_TOGETHER + var/secured = TRUE + var/floor_tile = /obj/item/stack/thermoplastic + var/mutable_appearance/damage_overlay + +/datum/armor/tram_floor + melee = 40 + bullet = 10 + laser = 10 + bomb = 45 + fire = 90 + acid = 100 + +/obj/structure/thermoplastic/light + icon_state = "tram_light" + base_icon_state = "tram_light" + floor_tile = /obj/item/stack/thermoplastic/light + +/obj/structure/thermoplastic/examine(mob/user) + . = ..() + + if(secured) + . += span_notice("It is secured with a set of [EXAMINE_HINT("screws.")] To remove tile use a [EXAMINE_HINT("screwdriver.")]") + else + . += span_notice("You can [EXAMINE_HINT("crowbar")] to remove the tile.") + . += span_notice("It can be re-secured using a [EXAMINE_HINT("screwdriver.")]") + +/obj/structure/thermoplastic/take_damage(damage_amount, damage_type = BRUTE, damage_flag = "", sound_effect = TRUE, attack_dir, armour_penetration = 0) + . = ..() + if(.) //received damage + update_appearance() + +/obj/structure/thermoplastic/update_icon_state() + . = ..() + var/ratio = atom_integrity / max_integrity + ratio = CEILING(ratio * 4, 1) * 25 + if(ratio > 75) + icon_state = base_icon_state + return + + icon_state = "[base_icon_state]_damage[ratio]" + +/obj/structure/thermoplastic/screwdriver_act_secondary(mob/living/user, obj/item/tool) + . = ..() + if(secured) + user.visible_message(span_notice("[user] begins to unscrew the tile..."), + span_notice("You begin to unscrew the tile...")) + if(tool.use_tool(src, user, 1 SECONDS, volume = 50)) + secured = FALSE + to_chat(user, span_notice("The screws come out, and a gap forms around the edge of the tile.")) + else + user.visible_message(span_notice("[user] begins to fasten the tile..."), + span_notice("You begin to fasten the tile...")) + if(tool.use_tool(src, user, 1 SECONDS, volume = 50)) + secured = TRUE + to_chat(user, span_notice("The tile is securely screwed in place.")) + + return TOOL_ACT_TOOLTYPE_SUCCESS + +/obj/structure/thermoplastic/crowbar_act_secondary(mob/living/user, obj/item/tool) + . = ..() + if(secured) + to_chat(user, span_warning("The security screws need to be removed first!")) + return FALSE + + else + user.visible_message(span_notice("[user] wedges \the [tool] into the tile's gap in the edge and starts prying..."), + span_notice("You wedge \the [tool] into the tram panel's gap in the frame and start prying...")) + if(tool.use_tool(src, user, 1 SECONDS, volume = 50)) + to_chat(user, span_notice("The panel pops out of the frame.")) + var/obj/item/stack/thermoplastic/pulled_tile = new() + pulled_tile.update_integrity(atom_integrity) + user.put_in_hands(pulled_tile) + qdel(src) + + return TOOL_ACT_TOOLTYPE_SUCCESS + +/obj/structure/thermoplastic/welder_act(mob/living/user, obj/item/tool) + if(atom_integrity >= max_integrity) + to_chat(user, span_warning("[src] is already in good condition!")) + return TOOL_ACT_TOOLTYPE_SUCCESS + if(!tool.tool_start_check(user, amount = 0)) + return FALSE + to_chat(user, span_notice("You begin repairing [src]...")) + var/integrity_to_repair = max_integrity - atom_integrity + if(tool.use_tool(src, user, integrity_to_repair * 0.5, volume = 50)) + atom_integrity = max_integrity + to_chat(user, span_notice("You repair [src].")) + update_appearance() + return TOOL_ACT_TOOLTYPE_SUCCESS + +/obj/item/stack/thermoplastic + name = "thermoplastic tram tile" + singular_name = "thermoplastic tram tile" + desc = "A high-traction floor tile. It sparkles in the light." + icon = 'icons/obj/tiles.dmi' + lefthand_file = 'icons/mob/inhands/items/tiles_lefthand.dmi' + righthand_file = 'icons/mob/inhands/items/tiles_righthand.dmi' + icon_state = "tile_textured_white_large" + inhand_icon_state = "tile-neon-glow" + color = COLOR_TRAM_BLUE + w_class = WEIGHT_CLASS_NORMAL + force = 1 + throwforce = 1 + throw_speed = 3 + throw_range = 7 + max_amount = 60 + novariants = TRUE + merge_type = /obj/item/stack/thermoplastic + var/tile_type = /obj/structure/thermoplastic + +/obj/item/stack/thermoplastic/light + color = COLOR_TRAM_LIGHT_BLUE + tile_type = /obj/structure/thermoplastic/light + +/obj/item/stack/thermoplastic/Initialize(mapload, new_amount, merge = TRUE, list/mat_override=null, mat_amt=1) + . = ..() + pixel_x = rand(-3, 3) + pixel_y = rand(-3, 3) //randomize a little + +/obj/item/stack/thermoplastic/examine(mob/user) + . = ..() + if(throwforce && !is_cyborg) //do not want to divide by zero or show the message to borgs who can't throw + var/damage_value + switch(CEILING(MAX_LIVING_HEALTH / throwforce, 1)) //throws to crit a human + if(1 to 3) + damage_value = "superb" + if(4 to 6) + damage_value = "great" + if(7 to 9) + damage_value = "good" + if(10 to 12) + damage_value = "fairly decent" + if(13 to 15) + damage_value = "mediocre" + if(!damage_value) + return + . += span_notice("Those could work as a [damage_value] throwing weapon.") diff --git a/code/modules/transport/tram/tram_machinery.dm b/code/modules/transport/tram/tram_machinery.dm new file mode 100644 index 00000000000..32887dffec7 --- /dev/null +++ b/code/modules/transport/tram/tram_machinery.dm @@ -0,0 +1,106 @@ +/obj/item/assembly/control/transport + /// The ID of the tram we're linked to + var/specific_transport_id = TRAMSTATION_LINE_1 + /// Options to be passed with the requests to the transport subsystem + var/options = NONE + +/obj/item/assembly/control/transport/multitool_act(mob/living/user) + var/list/available_platforms = list() + for(var/obj/effect/landmark/transport/nav_beacon/tram/platform/platform as anything in SStransport.nav_beacons[specific_transport_id]) + LAZYADD(available_platforms, platform.name) + + var/selected_platform = tgui_input_list(user, "Set the platform ID", "Platform", available_platforms) + var/obj/effect/landmark/transport/nav_beacon/tram/platform/change_platform + for(var/obj/effect/landmark/transport/nav_beacon/tram/platform/destination as anything in SStransport.nav_beacons[specific_transport_id]) + if(destination.name == selected_platform) + change_platform = destination + break + + if(!change_platform || QDELETED(user) || QDELETED(src) || !user.can_perform_action(src, FORBID_TELEKINESIS_REACH)) + return + + if(get_dist(change_platform, src) > 15) + balloon_alert(user, "out of range!") + return + + id = change_platform.platform_code + balloon_alert(user, "platform changed") + to_chat(user, span_notice("You change the platform ID to [change_platform.name].")) + +/obj/item/assembly/control/transport/call_button + name = "tram call button" + desc = "A small device used to bring trams to you." + ///ID to link to allow us to link to one specific tram in the world + id = 0 + +/obj/item/assembly/control/transport/call_button/Initialize(mapload) + . = ..() + return INITIALIZE_HINT_LATELOAD + +/obj/item/assembly/control/transport/call_button/LateInitialize(mapload) + . = ..() + if(!id_tag) + id_tag = assign_random_name() + SStransport.hello(src, name, id_tag) + RegisterSignal(SStransport, COMSIG_TRANSPORT_RESPONSE, PROC_REF(call_response)) + +/obj/item/assembly/control/transport/proc/call_response(controller, list/relevant, response_code, response_info) + SIGNAL_HANDLER + if(!LAZYFIND(relevant, src)) + return + + switch(response_code) + if(REQUEST_SUCCESS) + say("The tram has been called to the platform.") + + if(REQUEST_FAIL) + switch(response_info) + if(BROKEN_BEYOND_REPAIR) + say("The tram has suffered a catastrophic failure. Please seek alternate modes of travel.") + if(NOT_IN_SERVICE) //tram has no power or other fault, but it's not broken forever + say("The tram is not in service. Please contact the nearest engineer.") + if(INVALID_PLATFORM) //engineer needs to fix button + say("Button configuration error. Please contact the nearest engineer.") + if(TRANSPORT_IN_USE) + say("The tram is tramversing the station, please wait.") + if(INTERNAL_ERROR) + say("Tram controller error. Please contact the nearest engineer.") + if(NO_CALL_REQUIRED) //already here + say("The tram is already here. Please board the tram and select a destination.") + else + say("Tram controller error. Please contact the nearest engineer.") + +/obj/item/assembly/control/transport/call_button/activate() + if(cooldown) + return + cooldown = TRUE + addtimer(VARSET_CALLBACK(src, cooldown, FALSE), 2 SECONDS) + + // INVOKE_ASYNC(SStransport, TYPE_PROC_REF(/datum/controller/subsystem/processing/transport, call_request), src, specific_transport_id, id) + SEND_SIGNAL(src, COMSIG_TRANSPORT_REQUEST, specific_transport_id, id) + +/obj/machinery/button/transport/tram + name = "tram request" + desc = "A button for calling the tram. It has a speakerbox in it with some internals." + base_icon_state = "tram" + icon_state = "tram" + light_color = COLOR_DISPLAY_BLUE + can_alter_skin = FALSE + device_type = /obj/item/assembly/control/transport/call_button + req_access = list() + id = 0 + /// The ID of the tram we're linked to + var/specific_transport_id = TRAMSTATION_LINE_1 + +/obj/machinery/button/transport/tram/setup_device() + var/obj/item/assembly/control/transport/call_button/tram_device = device + tram_device.id = id + tram_device.specific_transport_id = specific_transport_id + return ..() + +/obj/machinery/button/transport/tram/examine(mob/user) + . = ..() + . += span_notice("There's a small inscription on the button...") + . += span_notice("THIS CALLS THE TRAM! IT DOES NOT OPERATE IT! The console on the tram tells it where to go!") + +MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/button/transport/tram, 32) diff --git a/code/modules/transport/tram/tram_remote.dm b/code/modules/transport/tram/tram_remote.dm new file mode 100644 index 00000000000..08e127bc6b9 --- /dev/null +++ b/code/modules/transport/tram/tram_remote.dm @@ -0,0 +1,126 @@ +/obj/item/assembly/control/transport/remote + icon_state = "tramremote_nis" + inhand_icon_state = "electronic" + lefthand_file = 'icons/mob/inhands/items/devices_lefthand.dmi' + righthand_file = 'icons/mob/inhands/items/devices_righthand.dmi' + icon = 'icons/obj/device.dmi' + name = "tram remote" + desc = "A remote control that can be linked to a tram. This can only go well." + w_class = WEIGHT_CLASS_TINY + options = RAPID_MODE + ///desired tram destination + var/destination + COOLDOWN_DECLARE(tram_remote) + +/obj/item/assembly/control/transport/remote/Initialize(mapload) + . = ..() + if(!id_tag) + id_tag = assign_random_name() + SStransport.hello(src, name, id_tag) + register_context() + +/obj/item/assembly/control/transport/remote/add_context(atom/source, list/context, obj/item/held_item, mob/user) + if(!specific_transport_id) + context[SCREENTIP_CONTEXT_LMB] = "Link tram" + return CONTEXTUAL_SCREENTIP_SET + context[SCREENTIP_CONTEXT_LMB] = "Dispatch tram" + context[SCREENTIP_CONTEXT_RMB] = "Select destination" + context[SCREENTIP_CONTEXT_CTRL_LMB] = "Toggle door safeties" + context[SCREENTIP_CONTEXT_ALT_LMB] = "Change tram" + return CONTEXTUAL_SCREENTIP_SET + +//set tram destination +/obj/item/assembly/control/transport/remote/attack_self_secondary(mob/user) + var/list/available_platforms = list() + for(var/obj/effect/landmark/transport/nav_beacon/tram/platform/platform as anything in SStransport.nav_beacons[specific_transport_id]) + LAZYADD(available_platforms, platform.name) + + var/selected_platform = tgui_input_list(user, "Available destinations", "Where to?", available_platforms) + for(var/obj/effect/landmark/transport/nav_beacon/tram/platform/potential_platform as anything in SStransport.nav_beacons[specific_transport_id]) + if(potential_platform.name == selected_platform) + destination = potential_platform.platform_code + break + + balloon_alert(user, "set [selected_platform]") + to_chat(user, span_notice("You change the platform ID on [src] to [selected_platform].")) + +///set safety bypass +/obj/item/assembly/control/transport/remote/CtrlClick(mob/user) + switch(options) + if(!RAPID_MODE) + options |= RAPID_MODE + if(RAPID_MODE) + options &= ~RAPID_MODE + update_appearance() + balloon_alert(user, "mode: [options ? "fast" : "safe"]") + +/obj/item/assembly/control/transport/remote/examine(mob/user) + . = ..() + if(!specific_transport_id) + . += "There is an X showing on the display." + . += "Left-click to link to a tram." + return + . += "The rapid mode light is [options ? "on" : "off"]." + if(cooldown) + . += "The number on the display shows [DisplayTimeText(cooldown, 1)]." + else + . += "The display indicates ready." + . += "Left-click to dispatch tram." + . += "Right-click to set destination." + . += "Ctrl-click to toggle safety bypass." + . += "Alt-click to change configured tram." + +/obj/item/assembly/control/transport/remote/update_icon_state() + . = ..() + + if(!specific_transport_id) + icon_state = "tramremote_nis" + return + + icon_state = "tramremote_ob" + +/obj/item/assembly/control/transport/remote/update_overlays() + . = ..() + if(options & RAPID_MODE) + . += mutable_appearance(icon, "tramremote_emag") + +/obj/item/assembly/control/transport/remote/attack_self(mob/user) + if(!specific_transport_id) + link_tram(user) + return + + if(cooldown) + balloon_alert(user, "cooldown: [DisplayTimeText(cooldown, 1)]") + return + + activate(user) + COOLDOWN_START(src, tram_remote, 2 MINUTES) + +///send our selected commands to the tram +/obj/item/assembly/control/transport/remote/activate(mob/user) + if(!specific_transport_id) + balloon_alert(user, "no tram linked!") + return + if(!destination) + balloon_alert(user, "no destination!") + return + + SEND_SIGNAL(src, COMSIG_TRANSPORT_REQUEST, specific_transport_id, destination, options) + +/obj/item/assembly/control/transport/remote/AltClick(mob/user) + link_tram(user) + +/obj/item/assembly/control/transport/remote/proc/link_tram(mob/user) + specific_transport_id = null + var/list/transports_available + for(var/datum/transport_controller/linear/tram/tram as anything in SStransport.transports_by_type[TRANSPORT_TYPE_TRAM]) + LAZYADD(transports_available, tram.specific_transport_id) + + specific_transport_id = tgui_input_list(user, "Available transports", "Select a transport", transports_available) + + if(specific_transport_id) + balloon_alert(user, "tram linked") + else + balloon_alert(user, "link failed!") + + update_appearance() diff --git a/code/modules/transport/tram/tram_signals.dm b/code/modules/transport/tram/tram_signals.dm new file mode 100644 index 00000000000..57cb89f3629 --- /dev/null +++ b/code/modules/transport/tram/tram_signals.dm @@ -0,0 +1,731 @@ +/// Pedestrian crossing signal for tram +/obj/machinery/transport/crossing_signal + name = "crossing signal" + desc = "Indicates to pedestrians if it's safe to cross the tracks. Connects to sensors down the track." + icon = 'icons/obj/tram/crossing_signal.dmi' + icon_state = "crossing-inbound" + base_icon_state = "crossing-inbound" + plane = GAME_PLANE_UPPER + layer = TRAM_SIGNAL_LAYER + max_integrity = 250 + integrity_failure = 0.25 + light_range = 2 + light_power = 0.7 + idle_power_usage = BASE_MACHINE_IDLE_CONSUMPTION * 2.4 + active_power_usage = BASE_MACHINE_ACTIVE_CONSUMPTION * 0.48 + anchored = TRUE + density = FALSE + circuit = /obj/item/circuitboard/machine/crossing_signal + // pointless if it only takes 2 seconds to cross but updates every 2 seconds + subsystem_type = /datum/controller/subsystem/processing/transport + light_color = LIGHT_COLOR_BABY_BLUE + luminosity = 1 + /// green, amber, or red for tram, blue if it's emag, tram missing, etc. + var/signal_state = XING_STATE_MALF + /// the sensor we use + var/datum/weakref/sensor_ref + /// Inbound station + var/inbound + /// Outbound station + var/outbound + /// If us or anything else in the operation chain is broken + var/operating_status = TRANSPORT_SYSTEM_NORMAL + var/sign_dir = INBOUND + /** Proximity thresholds for crossing signal states + * + * The proc that checks the distance between the tram and crossing signal uses these vars to determine the distance between tram and signal to change + * colors. The numbers are specifically set for Tramstation. If we get another map with crossing signals we'll have to probably subtype it or something. + * If the value is set too high, it will cause the lights to turn red when the tram arrives at another station. You want to optimize the amount of + * warning without turning it red unnessecarily. + * + * Red: decent chance of getting hit, but if you're quick it's a decent gamble. + * Amber: slow people may be in danger. + */ + var/amber_distance_threshold = AMBER_THRESHOLD_NORMAL + var/red_distance_threshold = RED_THRESHOLD_NORMAL + +/** Crossing signal subtypes + * + * Each map will have a different amount of tiles between stations, so adjust the signals here based on the map. + * The distance is calculated from the bottom left corner of the tram, + * so signals on the east side have their distance reduced by the tram length, in this case 10 for Tramstation. +*/ +/obj/machinery/transport/crossing_signal/northwest + dir = NORTH + sign_dir = INBOUND + +/obj/machinery/transport/crossing_signal/northeast + dir = NORTH + sign_dir = OUTBOUND + +/obj/machinery/transport/crossing_signal/southwest + dir = SOUTH + sign_dir = INBOUND + pixel_y = 20 + +/obj/machinery/transport/crossing_signal/southeast + dir = SOUTH + sign_dir = OUTBOUND + pixel_y = 20 + +/obj/machinery/static_signal + name = "crossing signal" + desc = "Indicates to pedestrians if it's safe to cross the tracks." + icon = 'icons/obj/tram/crossing_signal.dmi' + icon_state = "crossing-inbound" + plane = GAME_PLANE_UPPER + max_integrity = 250 + integrity_failure = 0.25 + idle_power_usage = BASE_MACHINE_IDLE_CONSUMPTION * 2.4 + active_power_usage = BASE_MACHINE_ACTIVE_CONSUMPTION * 0.74 + anchored = TRUE + density = FALSE + light_range = 1.5 + light_power = 3 + light_color = COLOR_VIBRANT_LIME + luminosity = 1 + var/sign_dir = INBOUND + +/obj/machinery/static_signal/northwest + dir = NORTH + sign_dir = INBOUND + +/obj/machinery/static_signal/northeast + dir = NORTH + sign_dir = OUTBOUND + +/obj/machinery/static_signal/southwest + dir = SOUTH + sign_dir = INBOUND + pixel_y = 20 + +/obj/machinery/static_signal/southeast + dir = SOUTH + sign_dir = OUTBOUND + pixel_y = 20 + +/obj/machinery/transport/crossing_signal/Initialize(mapload) + . = ..() + RegisterSignal(SStransport, COMSIG_TRANSPORT_ACTIVE, PROC_REF(wake_up)) + RegisterSignal(SStransport, COMSIG_COMMS_STATUS, PROC_REF(comms_change)) + SStransport.crossing_signals += src + register_context() + return INITIALIZE_HINT_LATELOAD + +/obj/machinery/transport/crossing_signal/LateInitialize(mapload) + . = ..() + link_tram() + link_sensor() + find_uplink() + +/obj/machinery/transport/crossing_signal/Destroy() + SStransport.crossing_signals -= src + . = ..() + +/obj/machinery/transport/crossing_signal/attackby(obj/item/weapon, mob/living/user, params) + if(!user.combat_mode) + if(default_deconstruction_screwdriver(user, icon_state, icon_state, weapon)) + return + + if(default_deconstruction_crowbar(weapon)) + return + + return ..() + +/obj/machinery/transport/crossing_signal/add_context(atom/source, list/context, obj/item/held_item, mob/user) + . = ..() + if(panel_open) + if(held_item?.tool_behaviour == TOOL_WRENCH) + context[SCREENTIP_CONTEXT_ALT_LMB] = "rotate signal" + context[SCREENTIP_CONTEXT_RMB] = "flip signal" + + if(istype(held_item, /obj/item/card/emag) && !(obj_flags & EMAGGED)) + context[SCREENTIP_CONTEXT_LMB] = "disable sensors" + + return CONTEXTUAL_SCREENTIP_SET + +/obj/machinery/transport/crossing_signal/examine(mob/user) + . = ..() + . += span_notice("The maintenance panel is [panel_open ? "open" : "closed"].") + if(panel_open) + . += span_notice("It can be flipped or rotated with a [EXAMINE_HINT("wrench.")]") + switch(operating_status) + if(TRANSPORT_REMOTE_WARNING) + . += span_notice("The yellow [EXAMINE_HINT("remote warning")] light is on.") + . += span_notice("The status display reads: Check track sensor.") + if(TRANSPORT_REMOTE_FAULT) + . += span_notice("The blue [EXAMINE_HINT("remote fault")] light is on.") + . += span_notice("The status display reads: Check tram controller.") + if(TRANSPORT_LOCAL_FAULT) + . += span_notice("The red [EXAMINE_HINT("local fault")] light is on.") + . += span_notice("The status display reads: Repair required.") + switch(dir) + if(NORTH, SOUTH) + . += span_notice("The tram configuration display shows EAST/WEST.") + if(EAST, WEST) + . += span_notice("The tram configuration display shows NORTH/SOUTH.") + +/obj/machinery/transport/crossing_signal/emag_act(mob/living/user) + if(obj_flags & EMAGGED) + return FALSE + balloon_alert(user, "disabled motion sensors") + operating_status = TRANSPORT_LOCAL_FAULT + obj_flags |= EMAGGED + return TRUE + +/obj/machinery/transport/crossing_signal/AltClick(mob/living/user) + . = ..() + + var/obj/item/tool = user.get_active_held_item() + if(!panel_open || tool?.tool_behaviour != TOOL_WRENCH) + return FALSE + + tool.play_tool_sound(src, 50) + setDir(turn(dir,-90)) + to_chat(user, span_notice("You rotate [src].")) + find_uplink() + return TRUE + +/obj/machinery/transport/crossing_signal/attackby_secondary(obj/item/weapon, mob/user, params) + . = ..() + + if(weapon.tool_behaviour == TOOL_WRENCH && panel_open) + switch(sign_dir) + if(INBOUND) + sign_dir = OUTBOUND + if(OUTBOUND) + sign_dir = INBOUND + + to_chat(user, span_notice("You flip directions on [src].")) + update_appearance() + + return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN + +/obj/machinery/transport/crossing_signal/proc/link_sensor() + sensor_ref = WEAKREF(find_closest_valid_sensor()) + update_appearance() + +/obj/machinery/transport/crossing_signal/proc/unlink_sensor() + sensor_ref = null + if(operating_status < TRANSPORT_REMOTE_WARNING) + operating_status = TRANSPORT_REMOTE_WARNING + degraded_response() + update_appearance() + +/obj/machinery/transport/crossing_signal/proc/wake_sensor() + if(operating_status > TRANSPORT_REMOTE_WARNING) + degraded_response() + return + + var/obj/machinery/transport/guideway_sensor/linked_sensor = sensor_ref?.resolve() + if(isnull(linked_sensor)) + operating_status = TRANSPORT_REMOTE_WARNING + degraded_response() + + else if(linked_sensor.trigger_sensor()) + operating_status = TRANSPORT_SYSTEM_NORMAL + normal_response() + + else + operating_status = TRANSPORT_REMOTE_WARNING + degraded_response() + +/obj/machinery/transport/crossing_signal/proc/normal_response() + amber_distance_threshold = AMBER_THRESHOLD_NORMAL + red_distance_threshold = RED_THRESHOLD_NORMAL + +/obj/machinery/transport/crossing_signal/proc/degraded_response() + amber_distance_threshold = AMBER_THRESHOLD_DEGRADED + red_distance_threshold = RED_THRESHOLD_DEGRADED + +/obj/machinery/transport/crossing_signal/proc/clear_uplink() + inbound = null + outbound = null + update_appearance() + +/** + * Only process if the tram is actually moving + */ +/obj/machinery/transport/crossing_signal/proc/wake_up(datum/source, transport_controller, controller_active) + SIGNAL_HANDLER + + if(machine_stat & BROKEN || machine_stat & NOPOWER) + return + + if(prob(TRANSPORT_BREAKDOWN_RATE)) + local_fault() + return + + operating_status = TRANSPORT_SYSTEM_NORMAL + + var/datum/transport_controller/linear/tram/tram = transport_ref?.resolve() + var/obj/machinery/transport/guideway_sensor/linked_sensor = sensor_ref?.resolve() + + if(isnull(tram) || tram.controller_status & COMM_ERROR) + operating_status = TRANSPORT_REMOTE_FAULT + + if(isnull(linked_sensor)) + link_sensor() + wake_sensor() + update_operating() + +/obj/machinery/transport/crossing_signal/on_set_machine_stat() + . = ..() + if(machine_stat & BROKEN) + operating_status = TRANSPORT_REMOTE_FAULT + else + operating_status = TRANSPORT_SYSTEM_NORMAL + +/obj/machinery/transport/crossing_signal/on_set_is_operational() + . = ..() + + update_operating() + +/obj/machinery/transport/crossing_signal/proc/comms_change(source, controller, new_status) + SIGNAL_HANDLER + + var/datum/transport_controller/linear/tram/updated_controller = controller + + if(updated_controller.specific_transport_id != configured_transport_id) + return + + switch(new_status) + if(TRUE) + if(operating_status == TRANSPORT_REMOTE_FAULT) + operating_status = TRANSPORT_SYSTEM_NORMAL + if(FALSE) + if(operating_status == TRANSPORT_SYSTEM_NORMAL) + operating_status = TRANSPORT_REMOTE_FAULT + +/** + * Update processing state. + * + * Returns whether we are still processing. + */ +/obj/machinery/transport/crossing_signal/proc/update_operating() + use_power(idle_power_usage) + update_appearance() + // Immediately process for snappy feedback + var/should_process = process() != PROCESS_KILL + if(should_process) + begin_processing() + return + end_processing() + +/obj/machinery/transport/crossing_signal/process() + + var/datum/transport_controller/linear/tram/tram = transport_ref?.resolve() + + // Check for stopped states. + if(!tram || !tram.controller_operational || !is_operational || !inbound || !outbound) + // Tram missing, we lost power, or something isn't right + // Throw the error message (blue) + set_signal_state(XING_STATE_MALF, force = !is_operational) + return PROCESS_KILL + + use_power(active_power_usage) + + var/obj/structure/transport/linear/tram_part = tram.return_closest_platform_to(src) + + if(QDELETED(tram_part)) + set_signal_state(XING_STATE_MALF, force = !is_operational) + return PROCESS_KILL + + // Everything will be based on position and travel direction + var/signal_pos + var/tram_pos + var/tram_velocity_sign // 1 for positive axis movement, -1 for negative + // Try to be agnostic about N-S vs E-W movement + if(tram.travel_direction & (NORTH|SOUTH)) + signal_pos = y + tram_pos = tram_part.y + tram_velocity_sign = tram.travel_direction & NORTH ? 1 : -1 + else + signal_pos = x + tram_pos = tram_part.x + tram_velocity_sign = tram.travel_direction & EAST ? 1 : -1 + + // How far away are we? negative if already passed. + var/approach_distance = tram_velocity_sign * (signal_pos - (tram_pos + (DEFAULT_TRAM_LENGTH * 0.5))) + + // Check for stopped state. + // Will kill the process since tram starting up will restart process. + if(!tram.controller_active) + set_signal_state(XING_STATE_GREEN) + return PROCESS_KILL + + // Check if tram is driving away from us. + if(approach_distance < 0) + // driving away. Green. In fact, in order to reverse, it'll have to stop, so let's go ahead and kill. + set_signal_state(XING_STATE_GREEN) + return PROCESS_KILL + + // Check the tram's terminus station. + // INBOUND 1 < 2 < 3 + // OUTBOUND 1 > 2 > 3 + if(tram.travel_direction & WEST && inbound < tram.destination_platform.platform_code) + set_signal_state(XING_STATE_GREEN) + return PROCESS_KILL + if(tram.travel_direction & EAST && outbound > tram.destination_platform.platform_code) + set_signal_state(XING_STATE_GREEN) + return PROCESS_KILL + + // Finally the interesting part where it's ACTUALLY approaching + if(approach_distance <= red_distance_threshold) + if(operating_status != TRANSPORT_SYSTEM_NORMAL) + set_signal_state(XING_STATE_MALF) + else + set_signal_state(XING_STATE_RED) + return + if(approach_distance <= amber_distance_threshold) + set_signal_state(XING_STATE_AMBER) + return + set_signal_state(XING_STATE_GREEN) + +/** + * Set the signal state and update appearance. + * + * Arguments: + * new_state - the new state (XING_STATE_RED, etc) + * force_update - force appearance to update even if state didn't change. + */ +/obj/machinery/transport/crossing_signal/proc/set_signal_state(new_state, force = FALSE) + if(new_state == signal_state && !force) + return + + signal_state = new_state + flick_overlay() + update_appearance() + +/obj/machinery/transport/crossing_signal/update_icon_state() + switch(dir) + if(SOUTH, EAST) + pixel_y = 20 + if(NORTH, WEST) + pixel_y = 0 + + switch(sign_dir) + if(INBOUND) + icon_state = "crossing-inbound" + base_icon_state = "crossing-inbound" + if(OUTBOUND) + icon_state = "crossing-outbound" + base_icon_state = "crossing-outbound" + + return ..() + +/obj/machinery/static_signal/update_icon_state() + switch(dir) + if(SOUTH, EAST) + pixel_y = 20 + if(NORTH, WEST) + pixel_y = 0 + + switch(sign_dir) + if(INBOUND) + icon_state = "crossing-inbound" + base_icon_state = "crossing-inbound" + if(OUTBOUND) + icon_state = "crossing-outbound" + base_icon_state = "crossing-outbound" + + return ..() + +/obj/machinery/transport/crossing_signal/update_appearance(updates) + . = ..() + + if(machine_stat & NOPOWER) + set_light(l_on = FALSE) + return + + var/new_color + switch(signal_state) + if(XING_STATE_MALF) + new_color = LIGHT_COLOR_BABY_BLUE + if(XING_STATE_GREEN) + new_color = LIGHT_COLOR_VIVID_GREEN + if(XING_STATE_AMBER) + new_color = LIGHT_COLOR_BRIGHT_YELLOW + else + new_color = LIGHT_COLOR_FLARE + + set_light(l_on = TRUE, l_color = new_color) + +/obj/machinery/transport/crossing_signal/update_overlays() + . = ..() + + if(machine_stat & NOPOWER) + return + + if(machine_stat & BROKEN) + operating_status = TRANSPORT_LOCAL_FAULT + + var/lights_overlay = "[base_icon_state]-l[signal_state]" + var/status_overlay = "[base_icon_state]-s[operating_status]" + + . += mutable_appearance(icon, lights_overlay) + . += mutable_appearance(icon, status_overlay) + . += emissive_appearance(icon, lights_overlay, offset_spokesman = src, alpha = src.alpha) + . += emissive_appearance(icon, status_overlay, offset_spokesman = src, alpha = src.alpha) + +/obj/machinery/static_signal/power_change() + ..() + + if(!is_operational) + set_light(l_on = FALSE) + return + + set_light(l_on = TRUE) + +/obj/machinery/static_signal/update_overlays() + . = ..() + + if(!is_operational) + return + + . += mutable_appearance(icon, "[base_icon_state]-l0") + . += mutable_appearance(icon, "[base_icon_state]-s0") + . += emissive_appearance(icon, "[base_icon_state]-l0", offset_spokesman = src, alpha = src.alpha) + . += emissive_appearance(icon, "[base_icon_state]-s0", offset_spokesman = src, alpha = src.alpha) + +/obj/machinery/transport/guideway_sensor + name = "guideway sensor" + icon = 'icons/obj/tram/tram_sensor.dmi' + icon_state = "sensor-base" + desc = "Uses an infrared beam to detect passing trams. Works when paired with a sensor on the other side of the track." + layer = TRAM_RAIL_LAYER + use_power = 0 + circuit = /obj/item/circuitboard/machine/guideway_sensor + /// Sensors work in a married pair + var/datum/weakref/paired_sensor + /// If us or anything else in the operation chain is broken + var/operating_status = TRANSPORT_SYSTEM_NORMAL + +/obj/machinery/transport/guideway_sensor/Initialize(mapload) + . = ..() + SStransport.sensors += src + return INITIALIZE_HINT_LATELOAD + +/obj/machinery/transport/guideway_sensor/LateInitialize(mapload) + . = ..() + pair_sensor() + RegisterSignal(SStransport, COMSIG_TRANSPORT_ACTIVE, PROC_REF(wake_up)) + +/obj/machinery/transport/guideway_sensor/add_context(atom/source, list/context, obj/item/held_item, mob/user) + . = ..() + if(panel_open) + if(held_item?.tool_behaviour == TOOL_WRENCH) + context[SCREENTIP_CONTEXT_RMB] = "rotate sensor" + + if(istype(held_item, /obj/item/card/emag) && !(obj_flags & EMAGGED)) + context[SCREENTIP_CONTEXT_LMB] = "disable sensor" + + return CONTEXTUAL_SCREENTIP_SET + +/obj/machinery/transport/guideway_sensor/examine(mob/user) + . = ..() + . += span_notice("The maintenance panel is [panel_open ? "open" : "closed"].") + if(panel_open) + . += span_notice("It can be rotated with a [EXAMINE_HINT("wrench.")]") + switch(operating_status) + if(TRANSPORT_REMOTE_WARNING) + . += span_notice("The yellow [EXAMINE_HINT("remote warning")] light is on.") + . += span_notice("The status display reads: Check paired sensor.") + if(TRANSPORT_REMOTE_FAULT) + . += span_notice("The blue [EXAMINE_HINT("remote fault")] light is on.") + . += span_notice("The status display reads: Paired sensor not found.") + if(TRANSPORT_LOCAL_FAULT) + . += span_notice("The red [EXAMINE_HINT("local fault")] light is on.") + . += span_notice("The status display reads: Repair required.") + +/obj/machinery/transport/guideway_sensor/attackby(obj/item/weapon, mob/living/user, params) + if (!user.combat_mode) + if(default_deconstruction_screwdriver(user, icon_state, icon_state, weapon)) + return + + if(default_deconstruction_crowbar(weapon)) + return + + return ..() + +/obj/machinery/transport/guideway_sensor/proc/pair_sensor() + set_machine_stat(machine_stat | MAINT) + if(paired_sensor) + var/obj/machinery/transport/guideway_sensor/divorcee = paired_sensor?.resolve() + divorcee.set_machine_stat(machine_stat | MAINT) + divorcee.paired_sensor = null + divorcee.update_appearance() + paired_sensor = null + + for(var/obj/machinery/transport/guideway_sensor/potential_sensor in SStransport.sensors) + if(potential_sensor == src) + continue + switch(potential_sensor.dir) + if(NORTH, SOUTH) + if(potential_sensor.x == src.x) + paired_sensor = WEAKREF(potential_sensor) + set_machine_stat(machine_stat & ~MAINT) + break + if(EAST, WEST) + if(potential_sensor.y == src.y) + paired_sensor = WEAKREF(potential_sensor) + set_machine_stat(machine_stat & ~MAINT) + break + + update_appearance() + + var/obj/machinery/transport/guideway_sensor/new_partner = paired_sensor?.resolve() + if(isnull(new_partner)) + return + + new_partner.paired_sensor = WEAKREF(src) + new_partner.set_machine_stat(machine_stat & ~MAINT) + new_partner.update_appearance() + playsound(src, 'sound/machines/synth_yes.ogg', 75, vary = FALSE, use_reverb = TRUE) + +/obj/machinery/transport/guideway_sensor/Destroy() + SStransport.sensors -= src + if(paired_sensor) + var/obj/machinery/transport/guideway_sensor/divorcee = paired_sensor?.resolve() + divorcee.set_machine_stat(machine_stat & ~MAINT) + divorcee.paired_sensor = null + divorcee.update_appearance() + playsound(src, 'sound/machines/synth_no.ogg', 75, vary = FALSE, use_reverb = TRUE) + paired_sensor = null + . = ..() + +/obj/machinery/transport/guideway_sensor/wrench_act(mob/living/user, obj/item/tool) + . = ..() + + if(default_change_direction_wrench(user, tool)) + pair_sensor() + return TRUE + +/obj/machinery/transport/guideway_sensor/update_overlays() + . = ..() + if(machine_stat & NOPOWER) + return + + if(machine_stat & BROKEN) + operating_status = TRANSPORT_LOCAL_FAULT + . += mutable_appearance(icon, "sensor-[TRANSPORT_LOCAL_FAULT]") + . += emissive_appearance(icon, "sensor-[TRANSPORT_LOCAL_FAULT]", src, alpha = src.alpha) + return + + if(machine_stat & MAINT) + operating_status = TRANSPORT_REMOTE_FAULT + . += mutable_appearance(icon, "sensor-[TRANSPORT_REMOTE_FAULT]") + . += emissive_appearance(icon, "sensor-[TRANSPORT_REMOTE_FAULT]", src, alpha = src.alpha) + return + + var/obj/machinery/transport/guideway_sensor/buddy = paired_sensor?.resolve() + if(buddy) + if(!buddy.is_operational) + operating_status = TRANSPORT_REMOTE_WARNING + . += mutable_appearance(icon, "sensor-[TRANSPORT_REMOTE_WARNING]") + . += emissive_appearance(icon, "sensor-[TRANSPORT_REMOTE_WARNING]", src, alpha = src.alpha) + else + operating_status = TRANSPORT_SYSTEM_NORMAL + . += mutable_appearance(icon, "sensor-[TRANSPORT_SYSTEM_NORMAL]") + . += emissive_appearance(icon, "sensor-[TRANSPORT_SYSTEM_NORMAL]", src, alpha = src.alpha) + return + + else + operating_status = TRANSPORT_REMOTE_FAULT + . += mutable_appearance(icon, "sensor-[TRANSPORT_REMOTE_FAULT]") + . += emissive_appearance(icon, "sensor-[TRANSPORT_REMOTE_FAULT]", src, alpha = src.alpha) + +/obj/machinery/transport/guideway_sensor/proc/trigger_sensor() + var/obj/machinery/transport/guideway_sensor/buddy = paired_sensor?.resolve() + if(!buddy) + return FALSE + + if(!is_operational || !buddy.is_operational) + return FALSE + + return TRUE + +/obj/machinery/transport/guideway_sensor/proc/wake_up() + SIGNAL_HANDLER + + if(machine_stat & BROKEN) + return + + if(prob(TRANSPORT_BREAKDOWN_RATE)) + local_fault() + + var/obj/machinery/transport/guideway_sensor/buddy = paired_sensor?.resolve() + + if(buddy) + set_machine_stat(machine_stat & ~MAINT) + + update_appearance() + +/obj/machinery/transport/guideway_sensor/on_set_is_operational() + . = ..() + + var/obj/machinery/transport/guideway_sensor/buddy = paired_sensor?.resolve() + if(buddy) + buddy.update_appearance() + + update_appearance() + +/obj/machinery/transport/crossing_signal/proc/find_closest_valid_sensor() + if(!istype(src) || !src.z) + return FALSE + + var/list/obj/machinery/transport/guideway_sensor/sensor_candidates = list() + + for(var/obj/machinery/transport/guideway_sensor/sensor in SStransport.sensors) + if(sensor.z == src.z) + if((sensor.x == src.x && sensor.dir & NORTH|SOUTH) || (sensor.y == src.y && sensor.dir & EAST|WEST)) + sensor_candidates += sensor + + var/obj/machinery/transport/guideway_sensor/selected_sensor = get_closest_atom(/obj/machinery/transport/guideway_sensor, sensor_candidates, src) + var/sensor_distance = get_dist(src, selected_sensor) + if(sensor_distance <= DEFAULT_TRAM_LENGTH) + return selected_sensor + + return FALSE + +/obj/machinery/transport/crossing_signal/proc/find_uplink() + if(!istype(src) || !src.z) + return FALSE + + var/list/obj/effect/landmark/transport/nav_beacon/tram/platform/inbound_candidates = list() + var/list/obj/effect/landmark/transport/nav_beacon/tram/platform/outbound_candidates = list() + + inbound = null + outbound = null + + for(var/obj/effect/landmark/transport/nav_beacon/tram/platform/beacon in SStransport.nav_beacons[configured_transport_id]) + if(beacon.z != src.z) + continue + + switch(src.dir) + if(NORTH, SOUTH) + if(abs((beacon.y - src.y)) <= DEFAULT_TRAM_LENGTH) + if(beacon.x < src.x) + inbound_candidates += beacon + else + outbound_candidates += beacon + if(EAST, WEST) + if(abs((beacon.x - src.x)) <= DEFAULT_TRAM_LENGTH) + if(beacon.y < src.y) + inbound_candidates += beacon + else + outbound_candidates += beacon + + var/obj/effect/landmark/transport/nav_beacon/tram/platform/selected_inbound = get_closest_atom(/obj/effect/landmark/transport/nav_beacon/tram/platform, inbound_candidates, src) + if(isnull(selected_inbound)) + return FALSE + + inbound = selected_inbound.platform_code + + var/obj/effect/landmark/transport/nav_beacon/tram/platform/selected_outbound = get_closest_atom(/obj/effect/landmark/transport/nav_beacon/tram/platform, outbound_candidates, src) + if(isnull(selected_outbound)) + return FALSE + + outbound = selected_outbound.platform_code + + update_appearance() diff --git a/code/modules/transport/tram/tram_structures.dm b/code/modules/transport/tram/tram_structures.dm new file mode 100644 index 00000000000..03b36c1f528 --- /dev/null +++ b/code/modules/transport/tram/tram_structures.dm @@ -0,0 +1,574 @@ +/** + * the tram has a few objects mapped onto it at roundstart, by default many of those objects have unwanted properties + * for example grilles and windows have the atmos_sensitive element applied to them, which makes them register to + * themselves moving to re register signals onto the turf via connect_loc. this is bad and dumb since it makes the tram + * more expensive to move. + * + * if you map something on to the tram, make SURE if possible that it doesnt have anything reacting to its own movement + * it will make the tram more expensive to move and we dont want that because we dont want to return to the days where + * the tram took a third of the tick per movement when its just carrying its default mapped in objects + */ + +/obj/structure/grille/tram/Initialize(mapload) + . = ..() + RemoveElement(/datum/element/atmos_sensitive, mapload) + //atmos_sensitive applies connect_loc which 1. reacts to movement in order to 2. unregister and register signals to + //the old and new locs. we dont want that, pretend these grilles and windows are plastic or something idk + +/obj/structure/tram/Initialize(mapload, direct) + . = ..() + RemoveElement(/datum/element/atmos_sensitive, mapload) + +/obj/structure/tram + name = "tram wall" + desc = "A lightweight titanium composite structure with titanium silicate panels." + icon = 'icons/obj/tram/tram_structure.dmi' + icon_state = "tram-part-0" + base_icon_state = "tram-part" + max_integrity = 150 + layer = TRAM_WALL_LAYER + density = TRUE + opacity = FALSE + anchored = TRUE + flags_1 = PREVENT_CLICK_UNDER_1 + armor_type = /datum/armor/tram_structure + smoothing_flags = SMOOTH_BITMASK + smoothing_groups = SMOOTH_GROUP_TRAM_STRUCTURE + canSmoothWith = SMOOTH_GROUP_TRAM_STRUCTURE + can_be_unanchored = FALSE + can_atmos_pass = ATMOS_PASS_DENSITY + explosion_block = 3 + receive_ricochet_chance_mod = 1.2 + rad_insulation = RAD_MEDIUM_INSULATION + var/state = TRAM_SCREWED_TO_FRAME + var/mineral = /obj/item/stack/sheet/titaniumglass + var/mineral_amount = 2 + var/tram_wall_type = /obj/structure/tram + var/girder_type = /obj/structure/girder/tram + var/mutable_appearance/damage_overlay + var/break_sound = SFX_SHATTER + var/knock_sound = 'sound/effects/glassknock.ogg' + var/bash_sound = 'sound/effects/glassbash.ogg' + +/obj/structure/tram/split + base_icon_state = "tram-split" + +/datum/armor/tram_structure + melee = 40 + bullet = 10 + laser = 10 + bomb = 45 + fire = 90 + acid = 100 + +/obj/structure/tram/Initialize(mapload) + AddElement(/datum/element/blocks_explosives) + . = ..() + var/obj/item/stack/initialized_mineral = new mineral + set_custom_materials(initialized_mineral.mats_per_unit, mineral_amount) + qdel(initialized_mineral) + air_update_turf(TRUE, TRUE) + register_context() + +/obj/structure/tram/examine(mob/user) + . = ..() + switch(state) + if(TRAM_SCREWED_TO_FRAME) + . += span_notice("The panel is [EXAMINE_HINT("screwed")] to the frame. To dismantle use a [EXAMINE_HINT("screwdriver.")]") + if(TRAM_IN_FRAME) + . += span_notice("The panel is [EXAMINE_HINT("unscrewed,")] but [EXAMINE_HINT("pried")] into the frame. To dismantle use a [EXAMINE_HINT("crowbar.")]") + if(TRAM_OUT_OF_FRAME) + . += span_notice("The panel is [EXAMINE_HINT("pried")] out of the frame, but still[EXAMINE_HINT("wired.")] To dismantle use [EXAMINE_HINT("wirecutters.")]") + +/obj/structure/tram/add_context(atom/source, list/context, obj/item/held_item, mob/user) + if(held_item?.tool_behaviour == TOOL_WELDER && atom_integrity < max_integrity) + context[SCREENTIP_CONTEXT_LMB] = "repair" + if(held_item?.tool_behaviour == TOOL_SCREWDRIVER && state == TRAM_SCREWED_TO_FRAME) + context[SCREENTIP_CONTEXT_RMB] = "unscrew panel" + if(held_item?.tool_behaviour == TOOL_CROWBAR && state == TRAM_IN_FRAME) + context[SCREENTIP_CONTEXT_RMB] = "remove panel" + if(held_item?.tool_behaviour == TOOL_WIRECUTTER && state == TRAM_OUT_OF_FRAME) + context[SCREENTIP_CONTEXT_RMB] = "disconnect panel" + + return CONTEXTUAL_SCREENTIP_SET + +/obj/structure/tram/update_overlays(updates = ALL) + . = ..() + var/ratio = atom_integrity / max_integrity + ratio = CEILING(ratio * 4, 1) * 25 + cut_overlay(damage_overlay) + if(ratio > 75) + return + + damage_overlay = mutable_appearance('icons/obj/structures.dmi', "damage[ratio]", -(layer + 0.1)) + . += damage_overlay + +/obj/structure/tram/attack_hand(mob/living/user, list/modifiers) + . = ..() + + if(!user.combat_mode) + user.visible_message(span_notice("[user] knocks on [src]."), \ + span_notice("You knock on [src].")) + playsound(src, knock_sound, 50, TRUE) + else + user.visible_message(span_warning("[user] bashes [src]!"), \ + span_warning("You bash [src]!")) + playsound(src, bash_sound, 100, TRUE) + +/obj/structure/tram/rcd_vals(mob/user, obj/item/construction/rcd/the_rcd) + switch(the_rcd.mode) + if(RCD_DECONSTRUCT) + return list("mode" = RCD_DECONSTRUCT, "delay" = 3 SECONDS, "cost" = 10) + return FALSE + +/obj/structure/tram/rcd_act(mob/user, obj/item/construction/rcd/the_rcd) + switch(the_rcd.mode) + if(RCD_DECONSTRUCT) + qdel(src) + return TRUE + return FALSE + +/obj/structure/tram/take_damage(damage_amount, damage_type = BRUTE, damage_flag = "", sound_effect = TRUE, attack_dir, armour_penetration = 0) + . = ..() + if(.) //received damage + update_appearance() + +/obj/structure/tram/narsie_act() + add_atom_colour(NARSIE_WINDOW_COLOUR, FIXED_COLOUR_PRIORITY) + +/obj/structure/tram/singularity_pull(singulo, current_size) + ..() + + if(current_size >= STAGE_FIVE) + deconstruct(disassembled = FALSE) + +/obj/structure/tram/welder_act(mob/living/user, obj/item/tool) + if(atom_integrity >= max_integrity) + to_chat(user, span_warning("[src] is already in good condition!")) + return TOOL_ACT_TOOLTYPE_SUCCESS + if(!tool.tool_start_check(user, amount = 0)) + return FALSE + to_chat(user, span_notice("You begin repairing [src]...")) + if(tool.use_tool(src, user, 4 SECONDS, volume = 50)) + atom_integrity = max_integrity + to_chat(user, span_notice("You repair [src].")) + update_appearance() + return TOOL_ACT_TOOLTYPE_SUCCESS + +/obj/structure/tram/attackby_secondary(obj/item/tool, mob/user, params) + switch(state) + if(TRAM_SCREWED_TO_FRAME) + if(tool.tool_behaviour == TOOL_SCREWDRIVER) + user.visible_message(span_notice("[user] begins to unscrew the tram panel from the frame..."), + span_notice("You begin to unscrew the tram panel from the frame...")) + if(tool.use_tool(src, user, 1 SECONDS, volume = 50)) + state = TRAM_IN_FRAME + to_chat(user, span_notice("The screws come out, and a gap forms around the edge of the pane.")) + return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN + + if(tool.tool_behaviour) + to_chat(user, span_warning("The security screws need to be removed first!")) + + if(TRAM_IN_FRAME) + if(tool.tool_behaviour == TOOL_CROWBAR) + user.visible_message(span_notice("[user] wedges \the [tool] into the tram panel's gap in the frame and starts prying..."), + span_notice("You wedge \the [tool] into the tram panel's gap in the frame and start prying...")) + if(tool.use_tool(src, user, 1 SECONDS, volume = 50)) + state = TRAM_OUT_OF_FRAME + to_chat(user, span_notice("The panel pops out of the frame, exposing some cabling that look like they can be cut.")) + return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN + + if(tool.tool_behaviour == TOOL_SCREWDRIVER) + user.visible_message(span_notice("[user] resecures the tram panel to the frame..."), + span_notice("You resecure the tram panel to the frame...")) + state = TRAM_SCREWED_TO_FRAME + return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN + + if(TRAM_OUT_OF_FRAME) + if(tool.tool_behaviour == TOOL_WIRECUTTER) + user.visible_message(span_notice("[user] starts cutting the connective cabling on \the [src]..."), + span_notice("You start cutting the connective cabling on \the [src]")) + if(tool.use_tool(src, user, 1 SECONDS, volume = 50)) + to_chat(user, span_notice("The panels falls out of the way exposing the frame backing.")) + deconstruct(disassembled = TRUE) + + if(tool.tool_behaviour == TOOL_CROWBAR) + user.visible_message(span_notice("[user] snaps the tram panel into place."), + span_notice("You snap the tram panel into place...")) + state = TRAM_IN_FRAME + return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN + + if(tool.tool_behaviour) + to_chat(user, span_warning("The cabling need to be cut first!")) + + return ..() + +/obj/structure/tram/deconstruct(disassembled = TRUE) + if(!(flags_1 & NODECONSTRUCT_1)) + if(disassembled) + new girder_type(loc) + if(mineral_amount) + for(var/i in 1 to mineral_amount) + new mineral(loc) + qdel(src) + +/obj/structure/tram/attackby(obj/item/item, mob/user, params) + . = ..() + + if(istype(item, /obj/item/wallframe/tram)) + try_wallmount(item, user) + +/obj/structure/tram/proc/try_wallmount(obj/item/wallmount, mob/user) + if(!istype(wallmount, /obj/item/wallframe/tram)) + return + + var/obj/item/wallframe/frame = wallmount + if(frame.try_build(src, user)) + frame.attach(src, user) + + return + +/* + * Other misc tramwall types + */ + +/obj/structure/tram/alt + + +/obj/structure/tram/alt/titanium + name = "solid tram" + desc = "A lightweight titanium composite structure. There is further solid plating where the panels usually attach to the frame." + icon = 'icons/turf/walls/shuttle_wall.dmi' + icon_state = "shuttle_wall-0" + base_icon_state = "shuttle_wall" + mineral = /obj/item/stack/sheet/mineral/titanium + tram_wall_type = /obj/structure/tram/alt/titanium + smoothing_flags = SMOOTH_BITMASK + smoothing_groups = SMOOTH_GROUP_TITANIUM_WALLS + SMOOTH_GROUP_WALLS + canSmoothWith = SMOOTH_GROUP_SHUTTLE_PARTS + SMOOTH_GROUP_AIRLOCK + SMOOTH_GROUP_TITANIUM_WALLS + +/obj/structure/tram/alt/plastitanium + name = "reinforced tram" + desc = "An evil tram of plasma and titanium." + icon = 'icons/turf/walls/plastitanium_wall.dmi' + icon_state = "plastitanium_wall-0" + base_icon_state = "plastitanium_wall" + mineral = /obj/item/stack/sheet/mineral/plastitanium + tram_wall_type = /obj/structure/tram/alt/plastitanium + smoothing_flags = SMOOTH_BITMASK + smoothing_groups = SMOOTH_GROUP_PLASTITANIUM_WALLS + SMOOTH_GROUP_WALLS + canSmoothWith = SMOOTH_GROUP_SHUTTLE_PARTS + SMOOTH_GROUP_AIRLOCK + SMOOTH_GROUP_PLASTITANIUM_WALLS + +/obj/structure/tram/alt/gold + name = "gold tram" + desc = "A solid gold tram. Swag!" + icon = 'icons/turf/walls/gold_wall.dmi' + icon_state = "gold_wall-0" + base_icon_state = "gold_wall" + mineral = /obj/item/stack/sheet/mineral/gold + tram_wall_type = /obj/structure/tram/alt/gold + explosion_block = 0 //gold is a soft metal you dingus. + smoothing_groups = SMOOTH_GROUP_GOLD_WALLS + SMOOTH_GROUP_WALLS + SMOOTH_GROUP_CLOSED_TURFS + canSmoothWith = SMOOTH_GROUP_GOLD_WALLS + custom_materials = list(/datum/material/gold = SHEET_MATERIAL_AMOUNT * 2) + +/obj/structure/tram/alt/silver + name = "silver tram" + desc = "A solid silver tram. Shiny!" + icon = 'icons/turf/walls/silver_wall.dmi' + icon_state = "silver_wall-0" + base_icon_state = "silver_wall" + mineral = /obj/item/stack/sheet/mineral/silver + tram_wall_type = /obj/structure/tram/alt/silver + smoothing_flags = SMOOTH_BITMASK + smoothing_groups = SMOOTH_GROUP_SILVER_WALLS + SMOOTH_GROUP_WALLS + SMOOTH_GROUP_CLOSED_TURFS + canSmoothWith = SMOOTH_GROUP_SILVER_WALLS + custom_materials = list(/datum/material/silver = SHEET_MATERIAL_AMOUNT * 2) + +/obj/structure/tram/alt/diamond + name = "diamond tram" + desc = "A composite structure with diamond-plated panels. Looks awfully sharp..." + icon = 'icons/turf/walls/diamond_wall.dmi' + icon_state = "diamond_wall-0" + base_icon_state = "diamond_wall" + mineral = /obj/item/stack/sheet/mineral/diamond + tram_wall_type = /obj/structure/tram/alt/diamond //diamond wall takes twice as much time to slice + max_integrity = 800 + explosion_block = 3 + smoothing_flags = SMOOTH_BITMASK + smoothing_groups = SMOOTH_GROUP_DIAMOND_WALLS + SMOOTH_GROUP_WALLS + SMOOTH_GROUP_CLOSED_TURFS + canSmoothWith = SMOOTH_GROUP_DIAMOND_WALLS + custom_materials = list(/datum/material/diamond = SHEET_MATERIAL_AMOUNT * 2) + +/obj/structure/tram/alt/bananium + name = "bananium tram" + desc = "A composite structure with bananium plating. Honk!" + icon = 'icons/turf/walls/bananium_wall.dmi' + icon_state = "bananium_wall-0" + base_icon_state = "bananium_wall" + mineral = /obj/item/stack/sheet/mineral/bananium + tram_wall_type = /obj/structure/tram/alt/bananium + smoothing_flags = SMOOTH_BITMASK + smoothing_groups = SMOOTH_GROUP_BANANIUM_WALLS + SMOOTH_GROUP_WALLS + SMOOTH_GROUP_CLOSED_TURFS + canSmoothWith = SMOOTH_GROUP_BANANIUM_WALLS + custom_materials = list(/datum/material/bananium = SHEET_MATERIAL_AMOUNT*2) + +/obj/structure/tram/alt/sandstone + name = "sandstone tram" + desc = "A composite structure with sandstone plating. Rough." + icon = 'icons/turf/walls/sandstone_wall.dmi' + icon_state = "sandstone_wall-0" + base_icon_state = "sandstone_wall" + mineral = /obj/item/stack/sheet/mineral/sandstone + tram_wall_type = /obj/structure/tram/alt/sandstone + explosion_block = 0 + smoothing_flags = SMOOTH_BITMASK + smoothing_groups = SMOOTH_GROUP_SANDSTONE_WALLS + SMOOTH_GROUP_WALLS + SMOOTH_GROUP_CLOSED_TURFS + canSmoothWith = SMOOTH_GROUP_SANDSTONE_WALLS + custom_materials = list(/datum/material/sandstone = SHEET_MATERIAL_AMOUNT*2) + +/obj/structure/tram/alt/uranium + article = "a" + name = "uranium tram" + desc = "A composite structure with uranium plating. This is probably a bad idea." + icon = 'icons/turf/walls/uranium_wall.dmi' + icon_state = "uranium_wall-0" + base_icon_state = "uranium_wall" + mineral = /obj/item/stack/sheet/mineral/uranium + tram_wall_type = /obj/structure/tram/alt/uranium + smoothing_flags = SMOOTH_BITMASK + smoothing_groups = SMOOTH_GROUP_URANIUM_WALLS + SMOOTH_GROUP_WALLS + SMOOTH_GROUP_CLOSED_TURFS + canSmoothWith = SMOOTH_GROUP_URANIUM_WALLS + custom_materials = list(/datum/material/uranium = SHEET_MATERIAL_AMOUNT*2) + + /// Mutex to prevent infinite recursion when propagating radiation pulses + var/active = null + + /// The last time a radiation pulse was performed + var/last_event = 0 + +/obj/structure/tram/alt/uranium/attackby(obj/item/W, mob/user, params) + radiate() + return ..() + +/obj/structure/tram/alt/uranium/attack_hand(mob/user, list/modifiers) + radiate() + return ..() + +/obj/structure/tram/alt/uranium/proc/radiate() + SIGNAL_HANDLER + if(active) + return + if(world.time <= last_event + 1.5 SECONDS) + return + active = TRUE + radiation_pulse( + src, + max_range = 3, + threshold = RAD_LIGHT_INSULATION, + chance = URANIUM_IRRADIATION_CHANCE, + minimum_exposure_time = URANIUM_RADIATION_MINIMUM_EXPOSURE_TIME, + ) + propagate_radiation_pulse() + last_event = world.time + active = FALSE + +/obj/structure/tram/alt/plasma + name = "plasma tram" + desc = "A composite structure with plasma plating. This is definitely a bad idea." + icon = 'icons/turf/walls/plasma_wall.dmi' + icon_state = "plasma_wall-0" + base_icon_state = "plasma_wall" + mineral = /obj/item/stack/sheet/mineral/plasma + tram_wall_type = /obj/structure/tram/alt/plasma + smoothing_flags = SMOOTH_BITMASK + smoothing_groups = SMOOTH_GROUP_PLASMA_WALLS + SMOOTH_GROUP_WALLS + SMOOTH_GROUP_CLOSED_TURFS + canSmoothWith = SMOOTH_GROUP_PLASMA_WALLS + custom_materials = list(/datum/material/plasma = SHEET_MATERIAL_AMOUNT*2) + +/obj/structure/tram/alt/wood + name = "wooden tram" + desc = "A tram with wooden framing. Flammable. There's a reason we use metal now." + icon = 'icons/turf/walls/wood_wall.dmi' + icon_state = "wood_wall-0" + base_icon_state = "wood_wall" + mineral = /obj/item/stack/sheet/mineral/wood + tram_wall_type = /obj/structure/tram/alt/wood + explosion_block = 0 + smoothing_flags = SMOOTH_BITMASK + smoothing_groups = SMOOTH_GROUP_WOOD_WALLS + SMOOTH_GROUP_WALLS + SMOOTH_GROUP_CLOSED_TURFS + canSmoothWith = SMOOTH_GROUP_WOOD_WALLS + custom_materials = list(/datum/material/wood = SHEET_MATERIAL_AMOUNT*2) + +/obj/structure/tram/alt/wood/attackby(obj/item/W, mob/user) + if(W.get_sharpness() && W.force) + var/duration = ((4.8 SECONDS) / W.force) * 2 //In seconds, for now. + if(istype(W, /obj/item/hatchet) || istype(W, /obj/item/fireaxe)) + duration /= 4 //Much better with hatchets and axes. + if(do_after(user, duration * (1 SECONDS), target=src)) //Into deciseconds. + deconstruct(disassembled = FALSE) + return + return ..() + +/obj/structure/tram/alt/bamboo + name = "bamboo tram" + desc = "A tram with a bamboo framing." + icon = 'icons/turf/walls/bamboo_wall.dmi' + icon_state = "wall-0" + base_icon_state = "wall" + smoothing_flags = SMOOTH_BITMASK + smoothing_groups = SMOOTH_GROUP_WALLS + SMOOTH_GROUP_BAMBOO_WALLS + SMOOTH_GROUP_CLOSED_TURFS + canSmoothWith = SMOOTH_GROUP_BAMBOO_WALLS + mineral = /obj/item/stack/sheet/mineral/bamboo + tram_wall_type = /obj/structure/tram/alt/bamboo + +/obj/structure/tram/alt/iron + name = "rough iron tram" + desc = "A composite structure with rough iron plating." + icon = 'icons/turf/walls/iron_wall.dmi' + icon_state = "iron_wall-0" + base_icon_state = "iron_wall" + mineral = /obj/item/stack/rods + mineral_amount = 5 + tram_wall_type = /obj/structure/tram/alt/iron + smoothing_flags = SMOOTH_BITMASK + smoothing_groups = SMOOTH_GROUP_IRON_WALLS + SMOOTH_GROUP_WALLS + SMOOTH_GROUP_CLOSED_TURFS + canSmoothWith = SMOOTH_GROUP_IRON_WALLS + custom_materials = list(/datum/material/iron = SHEET_MATERIAL_AMOUNT * 2.5) + +/obj/structure/tram/alt/abductor + name = "alien tram" + desc = "A composite structure made of some kind of alien alloy." + icon = 'icons/turf/walls/abductor_wall.dmi' + icon_state = "abductor_wall-0" + base_icon_state = "abductor_wall" + mineral = /obj/item/stack/sheet/mineral/abductor + tram_wall_type = /obj/structure/tram/alt/abductor + explosion_block = 3 + smoothing_flags = SMOOTH_BITMASK + smoothing_groups = SMOOTH_GROUP_ABDUCTOR_WALLS + SMOOTH_GROUP_WALLS + SMOOTH_GROUP_CLOSED_TURFS + canSmoothWith = SMOOTH_GROUP_ABDUCTOR_WALLS + custom_materials = list(/datum/material/alloy/alien = SHEET_MATERIAL_AMOUNT*2) + +/obj/structure/tram/get_dumping_location() + return null + +/obj/structure/tram/spoiler + name = "tram spoiler" + icon = 'icons/obj/tram/tram_structure.dmi' + desc = "Nanotrasen bought the luxury package under the impression titanium spoilers make the tram go faster. They're just for looks, or potentially stabbing anybody who gets in the way." + icon_state = "tram-spoiler-retracted" + max_integrity = 400 + ///Position of the spoiler + var/deployed = FALSE + ///Weakref to the tram piece we control + var/datum/weakref/tram_ref + ///The tram we're attached to + var/tram_id = TRAMSTATION_LINE_1 + obj_flags = CAN_BE_HIT + mineral = /obj/item/stack/sheet/mineral/titanium + girder_type = /obj/structure/girder/tram/corner + smoothing_flags = NONE + smoothing_groups = null + canSmoothWith = null + +/obj/structure/tram/spoiler/Initialize(mapload) + . = ..() + return INITIALIZE_HINT_LATELOAD + +/obj/structure/tram/spoiler/LateInitialize() + . = ..() + RegisterSignal(SStransport, COMSIG_TRANSPORT_ACTIVE, PROC_REF(set_spoiler)) + +/obj/structure/tram/spoiler/add_context(atom/source, list/context, obj/item/held_item, mob/user) + . = ..() + if(held_item?.tool_behaviour == TOOL_MULTITOOL && (obj_flags & EMAGGED)) + context[SCREENTIP_CONTEXT_LMB] = "repair" + + return CONTEXTUAL_SCREENTIP_SET + +/obj/structure/tram/spoiler/proc/set_spoiler(source, controller, controller_active, controller_status, travel_direction) + SIGNAL_HANDLER + + var/spoiler_direction = travel_direction + if(obj_flags & EMAGGED || controller_status & COMM_ERROR) + if(!deployed) + // Bring out the blades + do_sparks(3, cardinal_only = FALSE, source = src) + deploy_spoiler() + return + + if(!controller_active) + return + + switch(spoiler_direction) + if(SOUTH, EAST) + switch(dir) + if(NORTH, EAST) + retract_spoiler() + if(SOUTH, WEST) + deploy_spoiler() + + if(NORTH, WEST) + switch(dir) + if(NORTH, EAST) + deploy_spoiler() + if(SOUTH, WEST) + retract_spoiler() + return + +/obj/structure/tram/spoiler/proc/deploy_spoiler() + if(deployed) + return + flick("tram-spoiler-deploying", src) + icon_state = "tram-spoiler-deployed" + deployed = TRUE + +/obj/structure/tram/spoiler/proc/retract_spoiler() + if(!deployed) + return + flick("tram-spoiler-retracting", src) + icon_state = "tram-spoiler-retracted" + deployed = FALSE + +/obj/structure/tram/spoiler/emag_act(mob/user) + if(obj_flags & EMAGGED) + return + to_chat(user, span_warning("You short-circuit the [src]'s locking mechanism!"), type = MESSAGE_TYPE_INFO) + playsound(src, SFX_SPARKS, 100, vary = TRUE, extrarange = SHORT_RANGE_SOUND_EXTRARANGE) + do_sparks(5, cardinal_only = FALSE, source = src) + obj_flags |= EMAGGED + +/obj/structure/tram/spoiler/multitool_act(mob/living/user, obj/item/tool) + if(user.combat_mode) + return FALSE + + if(obj_flags & EMAGGED) + balloon_alert(user, "electronics reset!") + obj_flags &= ~EMAGGED + return TRUE + + return FALSE + +/obj/structure/chair/sofa/bench/tram + name = "bench" + desc = "Perfectly designed to be comfortable to sit on, and hellish to sleep on." + icon_state = "bench_middle" + greyscale_config = /datum/greyscale_config/bench_middle + greyscale_colors = COLOR_TRAM_BLUE + +/obj/structure/chair/sofa/bench/tram/left + icon_state = "bench_left" + greyscale_config = /datum/greyscale_config/bench_left + +/obj/structure/chair/sofa/bench/tram/right + icon_state = "bench_right" + greyscale_config = /datum/greyscale_config/bench_right + +/obj/structure/chair/sofa/bench/tram/corner + icon_state = "bench_corner" + greyscale_config = /datum/greyscale_config/bench_corner + +/obj/structure/chair/sofa/bench/tram/solo + icon_state = "bench_solo" + greyscale_config = /datum/greyscale_config/bench_solo diff --git a/code/modules/industrial_lift/industrial_lift.dm b/code/modules/transport/transport_module.dm similarity index 58% rename from code/modules/industrial_lift/industrial_lift.dm rename to code/modules/transport/transport_module.dm index 0bcc2a49bc8..56aa52beebc 100644 --- a/code/modules/industrial_lift/industrial_lift.dm +++ b/code/modules/transport/transport_module.dm @@ -1,59 +1,55 @@ -GLOBAL_LIST_EMPTY(lifts) -GLOBAL_LIST_INIT(all_radial_directions, list( - "NORTH" = image(icon = 'icons/testing/turf_analysis.dmi', icon_state = "red_arrow", dir = NORTH), - "NORTHEAST" = image(icon = 'icons/testing/turf_analysis.dmi', icon_state = "red_arrow", dir = NORTHEAST), - "EAST" = image(icon = 'icons/testing/turf_analysis.dmi', icon_state = "red_arrow", dir = EAST), - "SOUTHEAST" = image(icon = 'icons/testing/turf_analysis.dmi', icon_state = "red_arrow", dir = SOUTHEAST), - "SOUTH" = image(icon = 'icons/testing/turf_analysis.dmi', icon_state = "red_arrow", dir = SOUTH), - "SOUTHWEST" = image(icon = 'icons/testing/turf_analysis.dmi', icon_state = "red_arrow", dir = SOUTHWEST), - "WEST" = image(icon = 'icons/testing/turf_analysis.dmi', icon_state = "red_arrow", dir = WEST), - "NORTHWEST" = image(icon = 'icons/testing/turf_analysis.dmi', icon_state = "red_arrow", dir = NORTHWEST) -)) - -/obj/structure/industrial_lift - name = "lift platform" - desc = "A lightweight lift platform. It moves up and down." +/** + * Base transport structure. A single tile that can form a modular set with neighbouring tiles + * This type holds elevators and trams + */ +/obj/structure/transport/linear + name = "linear transport module" + desc = "A lightweight lift platform. It moves." icon = 'icons/obj/smooth_structures/catwalk.dmi' icon_state = "catwalk-0" base_icon_state = "catwalk" density = FALSE anchored = TRUE - armor_type = /datum/armor/structure_industrial_lift + resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF + armor_type = /datum/armor/transport_module max_integrity = 50 - layer = LATTICE_LAYER //under pipes + layer = TRAM_FLOOR_LAYER plane = FLOOR_PLANE smoothing_flags = SMOOTH_BITMASK smoothing_groups = SMOOTH_GROUP_INDUSTRIAL_LIFT canSmoothWith = SMOOTH_GROUP_INDUSTRIAL_LIFT - obj_flags = CAN_BE_HIT | BLOCK_Z_OUT_DOWN + obj_flags = BLOCK_Z_OUT_DOWN appearance_flags = PIXEL_SCALE|KEEP_TOGETHER //no TILE_BOUND since we're potentially multitile // If we don't do this, we'll build our overlays early, and fuck up how we're rendered blocks_emissive = EMISSIVE_BLOCK_NONE - ///ID used to determine what lift types we can merge with - var/lift_id = BASIC_LIFT_ID + ///ID used to determine what transport types we can merge with + var/transport_id = TRANSPORT_TYPE_ELEVATOR ///if true, the elevator works through floors var/pass_through_floors = FALSE ///what movables on our platform that we are moving - var/list/atom/movable/lift_load = list() + var/list/atom/movable/transport_contents = list() ///weakrefs to the contents we have when we're first created. stored so that admins can clear the tram to its initial state ///if someone put a bunch of stuff onto it. var/list/datum/weakref/initial_contents = list() ///what glide_size we set our moving contents to. var/glide_size_override = 8 - ///movables inside lift_load who had their glide_size changed since our last movement. + ///movables inside transport_contents who had their glide_size changed since our last movement. ///used so that we dont have to change the glide_size of every object every movement, which scales to cost more than you'd think var/list/atom/movable/changed_gliders = list() - ///master datum that controls our movement. in general /industrial_lift subtypes control moving themselves, and - /// /datum/lift_master instances control moving the entire tram and any behavior associated with that. - var/datum/lift_master/lift_master_datum - ///what subtype of /datum/lift_master to create for itself if no other platform on this tram has created one yet. + ///decisecond delay between horizontal movements. cannot make the tram move faster than 1 movement per world.tick_lag. only used to give to the transport_controller + var/speed_limiter = 0.5 + + ///master datum that controls our movement. in general /transport/linear subtypes control moving themselves, and + /// /datum/transport_controller instances control moving the entire tram and any behavior associated with that. + var/datum/transport_controller/linear/transport_controller_datum + ///what subtype of /datum/transport_controller to create for itself if no other platform on this tram has created one yet. ///very important for some behaviors since - var/lift_master_type = /datum/lift_master + var/transport_controller_type = /datum/transport_controller/linear ///how many tiles this platform extends on the x axis var/width = 1 @@ -61,7 +57,7 @@ GLOBAL_LIST_INIT(all_radial_directions, list( var/height = 1 ///if TRUE, this platform will late initialize and then expand to become a multitile object across all other linked platforms on this z level - var/create_multitile_platform = FALSE + var/create_modular_set = FALSE /// Does our elevator warn people (with visual effects) when moving down? var/warns_on_down_movement = FALSE @@ -77,91 +73,91 @@ GLOBAL_LIST_INIT(all_radial_directions, list( /// A lazylist of REFs to all mobs which have a radial open currently var/list/current_operators -/datum/armor/structure_industrial_lift - melee = 50 - fire = 80 - acid = 50 +/datum/armor/transport_module + melee = 80 + bullet = 90 + bomb = 70 + fire = 100 + acid = 100 -/obj/structure/industrial_lift/Initialize(mapload) +/obj/structure/transport/linear/Initialize(mapload) . = ..() - GLOB.lifts.Add(src) - // Yes if it's VV'd it won't be accurate but it probably shouldn't ever be if(radial_travel) - AddElement(/datum/element/contextual_screentip_bare_hands, lmb_text = "Send Elevator") + AddElement(/datum/element/contextual_screentip_bare_hands, lmb_text = "Send Transport") set_movement_registrations() - //since lift_master datums find all connected platforms when an industrial lift first creates it and then - //sets those platforms' lift_master_datum to itself, this check will only evaluate to true once per tram platform - if(!lift_master_datum && lift_master_type) - lift_master_datum = new lift_master_type(src) + //since transport_controller datums find all connected platforms when a transport structure first creates it and then + //sets those platforms' transport_controller_datum to itself, this check will only evaluate to true once per tram platform + if(!transport_controller_datum && transport_controller_type) + transport_controller_datum = new transport_controller_type(src) return INITIALIZE_HINT_LATELOAD -/obj/structure/industrial_lift/LateInitialize() - //after everything is initialized the lift master can order everything - lift_master_datum.order_platforms_by_z_level() +/obj/structure/transport/linear/LateInitialize() + . = ..() + //after everything is initialized the transport controller can order everything + transport_controller_datum.order_platforms_by_z_level() -/obj/structure/industrial_lift/Destroy() - GLOB.lifts.Remove(src) - lift_master_datum = null +/obj/structure/transport/linear/Destroy() + transport_controller_datum = null return ..() ///set the movement registrations to our current turf(s) so contents moving out of our tile(s) are removed from our movement lists -/obj/structure/industrial_lift/proc/set_movement_registrations(list/turfs_to_set) +/obj/structure/transport/linear/proc/set_movement_registrations(list/turfs_to_set) for(var/turf/turf_loc as anything in turfs_to_set || locs) - RegisterSignal(turf_loc, COMSIG_ATOM_EXITED, PROC_REF(UncrossedRemoveItemFromLift)) - RegisterSignals(turf_loc, list(COMSIG_ATOM_ENTERED, COMSIG_ATOM_AFTER_SUCCESSFUL_INITIALIZED_ON), PROC_REF(AddItemOnLift)) + RegisterSignal(turf_loc, COMSIG_ATOM_EXITED, PROC_REF(uncrossed_remove_item_from_transport)) + RegisterSignals(turf_loc, list(COMSIG_ATOM_ENTERED,COMSIG_ATOM_AFTER_SUCCESSFUL_INITIALIZED_ON), PROC_REF(add_item_on_transport)) ///unset our movement registrations from turfs that no longer contain us (or every loc if turfs_to_unset is unspecified) -/obj/structure/industrial_lift/proc/unset_movement_registrations(list/turfs_to_unset) +/obj/structure/transport/linear/proc/unset_movement_registrations(list/turfs_to_unset) var/static/list/registrations = list(COMSIG_ATOM_ENTERED, COMSIG_ATOM_EXITED, COMSIG_ATOM_AFTER_SUCCESSFUL_INITIALIZED_ON) for(var/turf/turf_loc as anything in turfs_to_unset || locs) UnregisterSignal(turf_loc, registrations) -/obj/structure/industrial_lift/proc/UncrossedRemoveItemFromLift(datum/source, atom/movable/gone, direction) +/obj/structure/transport/linear/proc/uncrossed_remove_item_from_transport(datum/source, atom/movable/gone, direction) SIGNAL_HANDLER if(!(gone.loc in locs)) - RemoveItemFromLift(gone) + remove_item_from_transport(gone) -/obj/structure/industrial_lift/proc/RemoveItemFromLift(atom/movable/potential_rider) +/obj/structure/transport/linear/proc/remove_item_from_transport(atom/movable/potential_rider) SIGNAL_HANDLER - if(!(potential_rider in lift_load)) + if(!(potential_rider in transport_contents)) return if(isliving(potential_rider) && HAS_TRAIT(potential_rider, TRAIT_CANNOT_BE_UNBUCKLED)) REMOVE_TRAIT(potential_rider, TRAIT_CANNOT_BE_UNBUCKLED, BUCKLED_TRAIT) - lift_load -= potential_rider + transport_contents -= potential_rider changed_gliders -= potential_rider UnregisterSignal(potential_rider, list(COMSIG_QDELETING, COMSIG_MOVABLE_UPDATE_GLIDE_SIZE)) -/obj/structure/industrial_lift/proc/AddItemOnLift(datum/source, atom/movable/new_lift_contents) +/obj/structure/transport/linear/proc/add_item_on_transport(datum/source, atom/movable/new_transport_contents) SIGNAL_HANDLER - var/static/list/blacklisted_types = typecacheof(list(/obj/structure/fluff/tram_rail, /obj/effect/decal/cleanable, /obj/structure/industrial_lift, /mob/camera)) - if(is_type_in_typecache(new_lift_contents, blacklisted_types) || new_lift_contents.invisibility == INVISIBILITY_ABSTRACT) //prevents the tram from stealing things like landmarks + var/static/list/blacklisted_types = typecacheof(list(/obj/structure/fluff/tram_rail, /obj/effect/decal/cleanable, /obj/structure/transport/linear, /mob/camera)) + if(is_type_in_typecache(new_transport_contents, blacklisted_types) || new_transport_contents.invisibility == INVISIBILITY_ABSTRACT) //prevents the tram from stealing things like landmarks return FALSE - if(new_lift_contents in lift_load) + if(new_transport_contents in transport_contents) return FALSE - if(isliving(new_lift_contents) && !HAS_TRAIT(new_lift_contents, TRAIT_CANNOT_BE_UNBUCKLED)) - ADD_TRAIT(new_lift_contents, TRAIT_CANNOT_BE_UNBUCKLED, BUCKLED_TRAIT) + if(isliving(new_transport_contents) && !HAS_TRAIT(new_transport_contents, TRAIT_CANNOT_BE_UNBUCKLED)) + ADD_TRAIT(new_transport_contents, TRAIT_CANNOT_BE_UNBUCKLED, BUCKLED_TRAIT) - lift_load += new_lift_contents - RegisterSignal(new_lift_contents, COMSIG_QDELETING, PROC_REF(RemoveItemFromLift)) + transport_contents += new_transport_contents + RegisterSignal(new_transport_contents, COMSIG_QDELETING, PROC_REF(remove_item_from_transport)) return TRUE -///adds everything on our tile that can be added to our lift_load and initial_contents lists when we're created -/obj/structure/industrial_lift/proc/add_initial_contents() +///adds everything on our tile that can be added to our transport_contents and initial_contents lists when we're created +/obj/structure/transport/linear/proc/add_initial_contents() for(var/turf/turf_loc in locs) for(var/atom/movable/movable_contents as anything in turf_loc) if(movable_contents == src) continue - if(AddItemOnLift(src, movable_contents)) + if(add_item_on_transport(src, movable_contents)) var/datum/weakref/new_initial_contents = WEAKREF(movable_contents) if(!new_initial_contents) @@ -169,39 +165,39 @@ GLOBAL_LIST_INIT(all_radial_directions, list( initial_contents += new_initial_contents -///signal handler for COMSIG_MOVABLE_UPDATE_GLIDE_SIZE: when a movable in lift_load changes its glide_size independently. +///signal handler for COMSIG_MOVABLE_UPDATE_GLIDE_SIZE: when a movable in transport_contents changes its glide_size independently. ///adds that movable to a lazy list, movables in that list have their glide_size updated when the tram next moves -/obj/structure/industrial_lift/proc/on_changed_glide_size(atom/movable/moving_contents, new_glide_size) +/obj/structure/transport/linear/proc/on_changed_glide_size(atom/movable/moving_contents, new_glide_size) SIGNAL_HANDLER if(new_glide_size != glide_size_override) changed_gliders += moving_contents ///make this tram platform multitile, expanding to cover all the tram platforms adjacent to us and deleting them. makes movement more efficient. -///the platform becoming multitile should be in the bottom left corner since thats assumed to be the loc of multitile objects -/obj/structure/industrial_lift/proc/create_multitile_platform(min_x, min_y, max_x, max_y, z) +///the platform becoming multitile should be in the lower left corner since thats assumed to be the loc of multitile objects +/obj/structure/transport/linear/proc/create_modular_set(min_x, min_y, max_x, max_y, z) if(!(min_x && min_y && max_x && max_y && z)) - for(var/obj/structure/industrial_lift/other_lift as anything in lift_master_datum.lift_platforms) - if(other_lift.z != z) + for(var/obj/structure/transport/linear/other_transport as anything in transport_controller_datum.transport_modules) + if(other_transport.z != z) continue - min_x = min(min_x, other_lift.x) - max_x = max(max_x, other_lift.x) + min_x = min(min_x, other_transport.x) + max_x = max(max_x, other_transport.x) - min_y = min(min_y, other_lift.y) - max_y = max(max_y, other_lift.y) + min_y = min(min_y, other_transport.y) + max_y = max(max_y, other_transport.y) - var/turf/bottom_left_loc = locate(min_x, min_y, z) - var/obj/structure/industrial_lift/loc_corner_lift = locate() in bottom_left_loc + var/turf/lower_left_corner = locate(min_x, min_y, z) + var/obj/structure/transport/linear/primary_module = locate() in lower_left_corner - if(!loc_corner_lift) - stack_trace("no lift in the bottom left corner of a lift level!") + if(!primary_module) + stack_trace("no lift in the lower left corner of a lift level!") return FALSE - if(loc_corner_lift != src) + if(primary_module != src) //the loc of a multitile object must always be the lower left corner - return loc_corner_lift.create_multitile_platform() + return primary_module.create_modular_set() width = (max_x - min_x) + 1 height = (max_y - min_y) + 1 @@ -229,40 +225,40 @@ GLOBAL_LIST_INIT(all_radial_directions, list( var/x_pixel_offset = world.icon_size * x - var/turf/lift_turf = locate(x + min_x, y + min_y, z) + var/turf/set_turf = locate(x + min_x, y + min_y, z) - if(!lift_turf) + if(!set_turf) continue - if(lift_turf in locs_to_skip) + if(set_turf in locs_to_skip) continue - var/obj/structure/industrial_lift/other_lift = locate() in lift_turf + var/obj/structure/transport/linear/other_transport = locate() in set_turf - if(!other_lift) + if(!other_transport) continue - locs_to_skip += other_lift.locs.Copy()//make sure we never go over multitile platforms multiple times + locs_to_skip += other_transport.locs.Copy()//make sure we never go over multitile platforms multiple times - other_lift.pixel_x = x_pixel_offset - other_lift.pixel_y = y_pixel_offset + other_transport.pixel_x = x_pixel_offset + other_transport.pixel_y = y_pixel_offset - overlays += other_lift + overlays += other_transport //now we vore all the other lifts connected to us on our z level - for(var/obj/structure/industrial_lift/other_lift in lift_master_datum.lift_platforms) - if(other_lift == src || other_lift.z != z) + for(var/obj/structure/transport/linear/other_transport in transport_controller_datum.transport_modules) + if(other_transport == src || other_transport.z != z) continue - lift_master_datum.lift_platforms -= other_lift - if(other_lift.lift_load) - lift_load |= other_lift.lift_load - if(other_lift.initial_contents) - initial_contents |= other_lift.initial_contents + transport_controller_datum.transport_modules -= other_transport + if(other_transport.transport_contents) + transport_contents |= other_transport.transport_contents + if(other_transport.initial_contents) + initial_contents |= other_transport.initial_contents - qdel(other_lift) + qdel(other_transport) - lift_master_datum.multitile_platform = TRUE + transport_controller_datum.create_modular_set = TRUE var/turf/old_loc = loc @@ -272,44 +268,44 @@ GLOBAL_LIST_INIT(all_radial_directions, list( update_appearance() return TRUE -///returns an unordered list of all lift platforms adjacent to us. used so our lift_master_datum can control all connected platforms. -///includes platforms directly above or below us as well. only includes platforms with an identical lift_id to our own. -/obj/structure/industrial_lift/proc/lift_platform_expansion(datum/lift_master/lift_master_datum) +///returns an unordered list of all lift platforms adjacent to us. used so our transport_controller_datum can control all connected platforms. +///includes platforms directly above or below us as well. only includes platforms with an identical transport_id to our own. +/obj/structure/transport/linear/proc/module_adjacency(datum/transport_controller/transport_controller_datum) . = list() for(var/direction in GLOB.cardinals_multiz) - var/obj/structure/industrial_lift/neighbor = locate() in get_step_multiz(src, direction) - if(!neighbor || neighbor.lift_id != lift_id) + var/obj/structure/transport/linear/neighbor = locate() in get_step_multiz(src, direction) + if(!neighbor || neighbor.transport_id != transport_id) continue . += neighbor -///main proc for moving the lift in the direction [going]. handles horizontal and/or vertical movement for multi platformed lifts and multitile lifts. -/obj/structure/industrial_lift/proc/travel(going) - var/list/things_to_move = lift_load +///main proc for moving the lift in the direction [travel_direction]. handles horizontal and/or vertical movement for multi platformed lifts and multitile lifts. +/obj/structure/transport/linear/proc/travel(travel_direction) + var/list/things_to_move = transport_contents var/turf/destination - if(!isturf(going)) - destination = get_step_multiz(src, going) + if(!isturf(travel_direction)) + destination = get_step_multiz(src, travel_direction) else - destination = going - going = get_dir_multiz(loc, going) + destination = travel_direction + travel_direction = get_dir_multiz(loc, travel_direction) var/x_offset = ROUND_UP(bound_width / 32) - 1 //how many tiles our horizontally farthest edge is from us var/y_offset = ROUND_UP(bound_height / 32) - 1 //how many tiles our vertically farthest edge is from us //the x coordinate of the edge furthest from our future destination, which would be our right hand side var/back_edge_x = destination.x + x_offset//if we arent multitile this should just be destination.x - var/top_edge_y = destination.y + y_offset + var/upper_edge_y = destination.y + y_offset - var/turf/top_right_corner = locate(min(world.maxx, back_edge_x), min(world.maxy, top_edge_y), destination.z) + var/turf/upper_right_corner = locate(min(world.maxx, back_edge_x), min(world.maxy, upper_edge_y), destination.z) var/list/dest_locs = block( destination, - top_right_corner + upper_right_corner ) var/list/entering_locs = dest_locs - locs var/list/exited_locs = locs - dest_locs - if(going == DOWN) + if(travel_direction == DOWN) for(var/turf/dest_turf as anything in entering_locs) SEND_SIGNAL(dest_turf, COMSIG_TURF_INDUSTRIAL_LIFT_ENTER, things_to_move) @@ -337,7 +333,7 @@ GLOBAL_LIST_INIT(all_radial_directions, list( crushed.apply_damage(15, BRUTE, BODY_ZONE_L_ARM, wound_bonus = 15) crushed.apply_damage(15, BRUTE, BODY_ZONE_R_ARM, wound_bonus = 15) - else if(going == UP) + else if(travel_direction == UP) for(var/turf/dest_turf as anything in entering_locs) ///handles any special interactions objects could have with the lift/tram, handled on the item itself SEND_SIGNAL(dest_turf, COMSIG_TURF_INDUSTRIAL_LIFT_ENTER, things_to_move) @@ -376,7 +372,7 @@ GLOBAL_LIST_INIT(all_radial_directions, list( for(var/obj/structure/victim_structure in dest_turf.contents) if(QDELING(victim_structure)) continue - if(!is_type_in_typecache(victim_structure, lift_master_datum.ignored_smashthroughs) && victim_structure.layer >= LOW_OBJ_LAYER) + if(!is_type_in_typecache(victim_structure, transport_controller_datum.ignored_smashthroughs) && victim_structure.layer >= LOW_OBJ_LAYER) if(victim_structure.anchored && initial(victim_structure.anchored) == TRUE) visible_message(span_danger("[src] smashes through [victim_structure]!")) @@ -384,7 +380,7 @@ GLOBAL_LIST_INIT(all_radial_directions, list( else if(!throw_target) - throw_target = get_edge_target_turf(src, turn(going, pick(45, -45))) + throw_target = get_edge_target_turf(src, turn(travel_direction, pick(45, -45))) visible_message(span_danger("[src] violently rams [victim_structure] out of the way!")) victim_structure.anchored = FALSE victim_structure.take_damage(rand(20, 25) * collision_lethality) @@ -393,7 +389,7 @@ GLOBAL_LIST_INIT(all_radial_directions, list( for(var/obj/machinery/victim_machine in dest_turf.contents) if(QDELING(victim_machine)) continue - if(is_type_in_typecache(victim_machine, lift_master_datum.ignored_smashthroughs)) + if(is_type_in_typecache(victim_machine, transport_controller_datum.ignored_smashthroughs)) continue if(istype(victim_machine, /obj/machinery/field)) //graceful break handles this scenario continue @@ -402,45 +398,69 @@ GLOBAL_LIST_INIT(all_radial_directions, list( visible_message(span_danger("[src] smashes through [victim_machine]!")) qdel(victim_machine) - for(var/mob/living/collided in dest_turf.contents) - var/damage_multiplier = collided.maxHealth * 0.01 - if(lift_master_datum.ignored_smashthroughs[collided.type]) + for(var/mob/living/victim_living in dest_turf.contents) + var/damage_multiplier = victim_living.maxHealth * 0.01 + var/extra_ouch = FALSE // if emagged you're gonna have a really bad time + if(speed_limiter == 0.5) // slow trams don't cause extra damage + for(var/obj/structure/tram/spoiler/my_spoiler in transport_contents) + if(get_dist(my_spoiler, victim_living) != 1) + continue + + if(my_spoiler.deployed) + extra_ouch = TRUE + break + + if(transport_controller_datum.ignored_smashthroughs[victim_living.type]) continue - to_chat(collided, span_userdanger("[src] collides into you!")) + to_chat(victim_living, span_userdanger("[src] collides into you!")) playsound(src, 'sound/effects/splat.ogg', 50, TRUE) var/damage = 0 - if(prob(15)) //sorry buddy, luck wasn't on your side - damage = 29 * collision_lethality * damage_multiplier - else - damage = rand(7, 21) * collision_lethality * damage_multiplier - collided.apply_damage(2 * damage, BRUTE, BODY_ZONE_HEAD, wound_bonus = 7) - collided.apply_damage(3 * damage, BRUTE, BODY_ZONE_CHEST, wound_bonus = 21) - collided.apply_damage(0.5 * damage, BRUTE, BODY_ZONE_L_LEG, wound_bonus = 14) - collided.apply_damage(0.5 * damage, BRUTE, BODY_ZONE_R_LEG, wound_bonus = 14) - collided.apply_damage(0.5 * damage, BRUTE, BODY_ZONE_L_ARM, wound_bonus = 14) - collided.apply_damage(0.5 * damage, BRUTE, BODY_ZONE_R_ARM, wound_bonus = 14) - log_combat(src, collided, "collided with") - - if(QDELETED(collided)) //in case it was a mob that dels on death + switch(extra_ouch) + if(TRUE) + playsound(src, 'sound/effects/grillehit.ogg', 50, TRUE) + var/obj/item/bodypart/head/head = victim_living.get_bodypart("head") + if(head) + log_combat(src, victim_living, "beheaded") + head.dismember() + victim_living.regenerate_icons() + add_overlay(mutable_appearance(icon, "blood_overlay")) + + if(FALSE) + log_combat(src, victim_living, "collided with") + if(prob(15)) //sorry buddy, luck wasn't on your side + damage = 29 * collision_lethality * damage_multiplier + else + damage = rand(7, 21) * collision_lethality * damage_multiplier + victim_living.apply_damage(2 * damage, BRUTE, BODY_ZONE_HEAD, wound_bonus = 7) + victim_living.apply_damage(3 * damage, BRUTE, BODY_ZONE_CHEST, wound_bonus = 21) + victim_living.apply_damage(0.5 * damage, BRUTE, BODY_ZONE_L_LEG, wound_bonus = 14) + victim_living.apply_damage(0.5 * damage, BRUTE, BODY_ZONE_R_LEG, wound_bonus = 14) + victim_living.apply_damage(0.5 * damage, BRUTE, BODY_ZONE_L_ARM, wound_bonus = 14) + victim_living.apply_damage(0.5 * damage, BRUTE, BODY_ZONE_R_ARM, wound_bonus = 14) + + if(QDELETED(victim_living)) //in case it was a mob that dels on death continue if(!throw_target) - throw_target = get_edge_target_turf(src, turn(going, pick(45, -45))) + throw_target = get_edge_target_turf(src, turn(travel_direction, pick(45, -45))) - var/turf/T = get_turf(collided) - T.add_mob_blood(collided) + var/turf/turf_to_bloody = get_turf(victim_living) + turf_to_bloody.add_mob_blood(victim_living) - collided.throw_at() - //if going EAST, will turn to the NORTHEAST or SOUTHEAST and throw the ran over guy away - var/datum/callback/land_slam = new(collided, TYPE_PROC_REF(/mob/living/, tram_slam_land)) - collided.throw_at(throw_target, 200 * collision_lethality, 4 * collision_lethality, callback = land_slam) + victim_living.throw_at() + //if travel_direction EAST, will turn to the NORTHEAST or SOUTHEAST and throw the ran over guy away + var/datum/callback/land_slam = new(victim_living, TYPE_PROC_REF(/mob/living/, tram_slam_land)) + victim_living.throw_at(throw_target, 200 * collision_lethality, 4 * collision_lethality, callback = land_slam) - //increment the hit counter signs - if(ismob(collided) && collided.client) - SSpersistence.tram_hits_this_round++ - SEND_SIGNAL(src, COMSIG_TRAM_COLLISION, SSpersistence.tram_hits_this_round) + //increment the hit counters + if(ismob(victim_living) && victim_living.client) + if(istype(transport_controller_datum, /datum/transport_controller/linear/tram)) + SSpersistence.tram_hits_this_round++ + SSblackbox.record_feedback("amount", "tram_collision", 1) + var/datum/transport_controller/linear/tram/tram_controller = transport_controller_datum + tram_controller.register_collision() unset_movement_registrations(exited_locs) - group_move(things_to_move, going) + group_move(things_to_move, travel_direction) set_movement_registrations(entering_locs) ///move the movers list of movables on our tile to destination if we successfully move there first. @@ -449,9 +469,9 @@ GLOBAL_LIST_INIT(all_radial_directions, list( ///none of the movers are able to react to the movement of any other mover, saving a lot of needless processing cost ///and is more sensible. without this, if you and a banana are on the same platform, when that platform moves you will slip ///on the banana even if youre not moving relative to it. -/obj/structure/industrial_lift/proc/group_move(list/atom/movable/movers, movement_direction) +/obj/structure/transport/linear/proc/group_move(list/atom/movable/movers, movement_direction) if(movement_direction == NONE) - stack_trace("an industrial lift was told to move to somewhere it already is!") + stack_trace("a transport was told to move to somewhere it already is!") return FALSE var/turf/our_dest = get_step(src, movement_direction) @@ -509,7 +529,7 @@ GLOBAL_LIST_INIT(all_radial_directions, list( * reset the contents of this lift platform to its original state in case someone put too much shit on it. * everything that is considered foreign is deleted, you can configure what is considered foreign. * - * used by an admin via calling reset_lift_contents() on our lift_master_datum. + * used by an admin via calling reset_lift_contents() on our transport_controller_datum. * * Arguments: * * consider_anything_past - number. if > 0 this platform will only handle foreign contents that exceed this number on each of our locs @@ -517,17 +537,17 @@ GLOBAL_LIST_INIT(all_radial_directions, list( * * foreign_non_player_mobs - bool. if true we consider mobs that dont have a mind to be foreign * * consider_player_mobs - bool. if true we consider player mobs to be foreign. only works if foreign_non_player_mobs is true as well */ -/obj/structure/industrial_lift/proc/reset_contents(consider_anything_past = 0, foreign_objects = TRUE, foreign_non_player_mobs = TRUE, consider_player_mobs = FALSE) +/obj/structure/transport/linear/proc/reset_contents(consider_anything_past = 0, foreign_objects = TRUE, foreign_non_player_mobs = TRUE, consider_player_mobs = FALSE) if(!foreign_objects && !foreign_non_player_mobs && !consider_player_mobs) return FALSE consider_anything_past = isnum(consider_anything_past) ? max(consider_anything_past, 0) : 0 //just in case someone fucks up the arguments - if(consider_anything_past && length(lift_load) <= consider_anything_past) + if(consider_anything_past && length(transport_contents) <= consider_anything_past) return FALSE - ///list of resolve()'d initial_contents that are still in lift_load + ///list of resolve()'d initial_contents that are still in transport_contents var/list/atom/movable/original_contents = list(src) ///list of objects we consider foreign according to the given arguments @@ -543,7 +563,7 @@ GLOBAL_LIST_INIT(all_radial_directions, list( if(!resolved_contents) continue - if(!(resolved_contents in lift_load)) + if(!(resolved_contents in transport_contents)) continue original_contents += resolved_contents @@ -552,7 +572,7 @@ GLOBAL_LIST_INIT(all_radial_directions, list( var/list/atom/movable/foreign_contents_in_loc = list() for(var/atom/movable/foreign_movable as anything in (turf_loc.contents - original_contents)) - if(foreign_objects && ismovable(foreign_movable) && !ismob(foreign_movable) && !istype(foreign_movable, /obj/effect/landmark/tram)) + if(foreign_objects && ismovable(foreign_movable) && !ismob(foreign_movable) && !istype(foreign_movable, /obj/effect/landmark/transport/nav_beacon)) foreign_contents_in_loc += foreign_movable continue @@ -577,7 +597,7 @@ GLOBAL_LIST_INIT(all_radial_directions, list( return TRUE /// Callback / general proc to check if the lift is usable by the passed mob. -/obj/structure/industrial_lift/proc/can_open_lift_radial(mob/living/user, starting_position) +/obj/structure/transport/linear/proc/can_open_lift_radial(mob/living/user, starting_position) // Gotta be a living mob if(!isliving(user)) return FALSE @@ -597,25 +617,25 @@ GLOBAL_LIST_INIT(all_radial_directions, list( return TRUE /// Opens the radial for the lift, allowing the user to move it around. -/obj/structure/industrial_lift/proc/open_lift_radial(mob/living/user) +/obj/structure/transport/linear/proc/open_lift_radial(mob/living/user) var/starting_position = loc if(!can_open_lift_radial(user, starting_position)) return // One radial per person - for(var/obj/structure/industrial_lift/other_platform as anything in lift_master_datum.lift_platforms) + for(var/obj/structure/transport/linear/other_platform as anything in transport_controller_datum.transport_modules) if(REF(user) in other_platform.current_operators) return var/list/possible_directions = list() - if(lift_master_datum.Check_lift_move(UP)) + if(transport_controller_datum.Check_lift_move(UP)) var/static/image/up_arrow if(!up_arrow) up_arrow = image(icon = 'icons/testing/turf_analysis.dmi', icon_state = "red_arrow", dir = NORTH) possible_directions["Up"] = up_arrow - if(lift_master_datum.Check_lift_move(DOWN)) + if(transport_controller_datum.Check_lift_move(DOWN)) var/static/image/down_arrow if(!down_arrow) down_arrow = image(icon = 'icons/testing/turf_analysis.dmi', icon_state = "red_arrow", dir = SOUTH) @@ -640,7 +660,7 @@ GLOBAL_LIST_INIT(all_radial_directions, list( LAZYREMOVE(current_operators, REF(user)) if(!can_open_lift_radial(user, starting_position)) return //nice try - if(!isnull(result) && result != "Cancel" && lift_master_datum.controls_locked) + if(!isnull(result) && result != "Cancel" && transport_controller_datum.controller_status & CONTROLS_LOCKED) // Only show this message if they actually wanted to move balloon_alert(user, "elevator controls locked!") return @@ -648,14 +668,14 @@ GLOBAL_LIST_INIT(all_radial_directions, list( if("Up") // We have to make sure that they don't do illegal actions // by not having their radial menu refresh from someone else moving the lift. - if(!lift_master_datum.simple_move_wrapper(UP, elevator_vertical_speed, user)) + if(!transport_controller_datum.simple_move_wrapper(UP, elevator_vertical_speed, user)) return show_fluff_message(UP, user) open_lift_radial(user) if("Down") - if(!lift_master_datum.simple_move_wrapper(DOWN, elevator_vertical_speed, user)) + if(!transport_controller_datum.simple_move_wrapper(DOWN, elevator_vertical_speed, user)) return show_fluff_message(DOWN, user) @@ -673,12 +693,12 @@ GLOBAL_LIST_INIT(all_radial_directions, list( * Returns: * * boolean, FALSE if the menu should be closed, TRUE if the menu is clear to stay opened. */ -/obj/structure/industrial_lift/proc/check_menu(mob/user, starting_loc) +/obj/structure/transport/linear/proc/check_menu(mob/user, starting_loc) if(user.incapacitated() || !user.Adjacent(src) || starting_loc != src.loc) return FALSE return TRUE -/obj/structure/industrial_lift/attack_hand(mob/user, list/modifiers) +/obj/structure/transport/linear/attack_hand(mob/user, list/modifiers) . = ..() if(.) return @@ -688,7 +708,7 @@ GLOBAL_LIST_INIT(all_radial_directions, list( return open_lift_radial(user) //ai probably shouldn't get to use lifts but they sure are great for admins to crush people with -/obj/structure/industrial_lift/attack_ghost(mob/user) +/obj/structure/transport/linear/attack_ghost(mob/user) . = ..() if(.) return @@ -699,19 +719,19 @@ GLOBAL_LIST_INIT(all_radial_directions, list( return open_lift_radial(user) -/obj/structure/industrial_lift/attack_paw(mob/user, list/modifiers) +/obj/structure/transport/linear/attack_paw(mob/user, list/modifiers) if(!radial_travel) return ..() return open_lift_radial(user) -/obj/structure/industrial_lift/attackby(obj/item/attacking_item, mob/user, params) +/obj/structure/transport/linear/attackby(obj/item/attacking_item, mob/user, params) if(!radial_travel) return ..() return open_lift_radial(user) -/obj/structure/industrial_lift/attack_robot(mob/living/user) +/obj/structure/transport/linear/attack_robot(mob/living/user) if(!radial_travel) return ..() @@ -723,7 +743,7 @@ GLOBAL_LIST_INIT(all_radial_directions, list( * * direction - What direction are we going * * user - The mob that caused the lift to move, for the visible message. */ -/obj/structure/industrial_lift/proc/show_fluff_message(direction, mob/user) +/obj/structure/transport/linear/proc/show_fluff_message(direction, mob/user) if(direction == UP) user.visible_message(span_notice("[user] moves the lift upwards."), span_notice("You move the lift upwards.")) @@ -731,123 +751,123 @@ GLOBAL_LIST_INIT(all_radial_directions, list( user.visible_message(span_notice("[user] moves the lift downwards."), span_notice("You move the lift downwards.")) // A subtype intended for "public use" -/obj/structure/industrial_lift/public +/obj/structure/transport/linear/public icon = 'icons/turf/floors.dmi' icon_state = "rockvault" base_icon_state = null smoothing_flags = NONE smoothing_groups = null canSmoothWith = null - resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF warns_on_down_movement = TRUE violent_landing = FALSE elevator_vertical_speed = 3 SECONDS radial_travel = FALSE -/obj/structure/industrial_lift/debug +/obj/structure/transport/linear/debug name = "transport platform" desc = "A lightweight platform. It moves in any direction, except up and down." color = "#5286b9ff" - lift_id = DEBUG_LIFT_ID + transport_id = TRANSPORT_TYPE_DEBUG radial_travel = TRUE -/obj/structure/industrial_lift/debug/open_lift_radial(mob/living/user) +/obj/structure/transport/linear/debug/open_lift_radial(mob/living/user) var/starting_position = loc if (!can_open_lift_radial(user,starting_position)) return - - var/result = show_radial_menu(user, src, GLOB.all_radial_directions, custom_check = CALLBACK(src, PROC_REF(can_open_lift_radial), user, starting_position), require_near = TRUE, tooltips = FALSE) +//NORTH, SOUTH, EAST, WEST, NORTHEAST, NORTHWEST, SOUTHEAST, SOUTHWEST + var/static/list/tool_list = list( + "NORTH" = image(icon = 'icons/testing/turf_analysis.dmi', icon_state = "red_arrow", dir = NORTH), + "NORTHEAST" = image(icon = 'icons/testing/turf_analysis.dmi', icon_state = "red_arrow", dir = NORTH), + "EAST" = image(icon = 'icons/testing/turf_analysis.dmi', icon_state = "red_arrow", dir = EAST), + "SOUTHEAST" = image(icon = 'icons/testing/turf_analysis.dmi', icon_state = "red_arrow", dir = EAST), + "SOUTH" = image(icon = 'icons/testing/turf_analysis.dmi', icon_state = "red_arrow", dir = SOUTH), + "SOUTHWEST" = image(icon = 'icons/testing/turf_analysis.dmi', icon_state = "red_arrow", dir = SOUTH), + "WEST" = image(icon = 'icons/testing/turf_analysis.dmi', icon_state = "red_arrow", dir = WEST), + "NORTHWEST" = image(icon = 'icons/testing/turf_analysis.dmi', icon_state = "red_arrow", dir = WEST) + ) + + var/result = show_radial_menu(user, src, tool_list, custom_check = CALLBACK(src, PROC_REF(can_open_lift_radial), user, starting_position), require_near = TRUE, tooltips = FALSE) if (!can_open_lift_radial(user,starting_position)) return // nice try - if(!isnull(result) && result != "Cancel" && lift_master_datum.controls_locked) + if(!isnull(result) && result != "Cancel" && transport_controller_datum.controller_status & CONTROLS_LOCKED) // Only show this message if they actually wanted to move balloon_alert(user, "elevator controls locked!") return switch(result) if("NORTH") - lift_master_datum.move_lift_horizontally(NORTH) + transport_controller_datum.move_transport_horizontally(NORTH) open_lift_radial(user) if("NORTHEAST") - lift_master_datum.move_lift_horizontally(NORTHEAST) + transport_controller_datum.move_transport_horizontally(NORTHEAST) open_lift_radial(user) if("EAST") - lift_master_datum.move_lift_horizontally(EAST) + transport_controller_datum.move_transport_horizontally(EAST) open_lift_radial(user) if("SOUTHEAST") - lift_master_datum.move_lift_horizontally(SOUTHEAST) + transport_controller_datum.move_transport_horizontally(SOUTHEAST) open_lift_radial(user) if("SOUTH") - lift_master_datum.move_lift_horizontally(SOUTH) + transport_controller_datum.move_transport_horizontally(SOUTH) open_lift_radial(user) if("SOUTHWEST") - lift_master_datum.move_lift_horizontally(SOUTHWEST) + transport_controller_datum.move_transport_horizontally(SOUTHWEST) open_lift_radial(user) if("WEST") - lift_master_datum.move_lift_horizontally(WEST) + transport_controller_datum.move_transport_horizontally(WEST) open_lift_radial(user) if("NORTHWEST") - lift_master_datum.move_lift_horizontally(NORTHWEST) + transport_controller_datum.move_transport_horizontally(NORTHWEST) open_lift_radial(user) if("Cancel") return add_fingerprint(user) -/obj/structure/industrial_lift/tram - name = "tram" - desc = "A tram for tramversing the station." - icon = 'icons/turf/floors.dmi' - icon_state = "textured_large" - layer = TRAM_FLOOR_LAYER +/obj/structure/transport/linear/tram + name = "tram subfloor" + desc = "The subfloor lattice of the tram. You can build a tram wall frame by using titanium sheets, or place down thermoplastic tram floor tiles." + icon = 'icons/obj/tram/tram_structure.dmi' + icon_state = "subfloor" base_icon_state = null + density = FALSE + layer = TRAM_STRUCTURE_LAYER smoothing_flags = NONE smoothing_groups = null canSmoothWith = null - //kind of a centerpiece of the station, so pretty tough to destroy - resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF - - lift_id = TRAM_LIFT_ID - lift_master_type = /datum/lift_master/tram + //the modular structure is pain to work with, damage is done to the floor on top + transport_id = TRANSPORT_TYPE_TRAM + transport_controller_type = /datum/transport_controller/linear/tram radial_travel = FALSE - + obj_flags = NONE /// Set by the tram control console in late initialize var/travelling = FALSE - //the following are only used to give to the lift_master datum when it's first created - - ///decisecond delay between horizontal movements. cannot make the tram move faster than 1 movement per world.tick_lag. only used to give to the lift_master - var/horizontal_speed = 0.5 - - create_multitile_platform = TRUE + /// Do we want this transport to link with nearby modules to make a multi-tile platform + create_modular_set = TRUE -/obj/structure/industrial_lift/tram/white - icon_state = "textured_white_large" +/obj/structure/transport/linear/tram/corner/northwest + icon_state = "subfloor-corner-nw" -/obj/structure/industrial_lift/tram/purple - icon_state = "titanium_purple" +/obj/structure/transport/linear/tram/corner/southwest + icon_state = "subfloor-corner-sw" -/obj/structure/industrial_lift/tram/subfloor - icon_state = "tram_subfloor" +/obj/structure/transport/linear/tram/corner/northeast + icon_state = "subfloor-corner-ne" -/obj/structure/industrial_lift/tram/subfloor/window - icon_state = "tram_subfloor_window" +/obj/structure/transport/linear/tram/corner/southeast + icon_state = "subfloor-corner-se" -/datum/armor/structure_industrial_lift - melee = 50 - fire = 80 - acid = 50 - -/obj/structure/industrial_lift/tram/AddItemOnLift(datum/source, atom/movable/AM) +/obj/structure/transport/linear/tram/add_item_on_transport(datum/source, atom/movable/item) . = ..() if(travelling) - on_changed_glide_size(AM, AM.glide_size) + on_changed_glide_size(item, item.glide_size) -/obj/structure/industrial_lift/tram/proc/set_travelling(travelling) +/obj/structure/transport/linear/tram/proc/set_travelling(travelling) if (src.travelling == travelling) return - for(var/atom/movable/glider as anything in lift_load) + for(var/atom/movable/glider as anything in transport_contents) if(travelling) glider.set_glide_size(glide_size_override) RegisterSignal(glider, COMSIG_MOVABLE_UPDATE_GLIDE_SIZE, PROC_REF(on_changed_glide_size)) @@ -856,9 +876,9 @@ GLOBAL_LIST_INIT(all_radial_directions, list( UnregisterSignal(glider, COMSIG_MOVABLE_UPDATE_GLIDE_SIZE) src.travelling = travelling - SEND_SIGNAL(src, COMSIG_TRAM_SET_TRAVELLING, travelling) + SEND_SIGNAL(src, COMSIG_TRANSPORT_ACTIVE, travelling) -/obj/structure/industrial_lift/tram/set_currently_z_moving() +/obj/structure/transport/linear/tram/set_currently_z_moving() return FALSE //trams can never z fall and shouldnt waste any processing time trying to do so /** @@ -868,13 +888,13 @@ GLOBAL_LIST_INIT(all_radial_directions, list( * at a location before users are allowed to interact with the tram console again. * Tram finds its location at this point before fully unlocking controls to the user. */ -/obj/structure/industrial_lift/tram/proc/unlock_controls() - for(var/obj/structure/industrial_lift/tram/tram_part as anything in lift_master_datum.lift_platforms) //only thing everyone needs to know is the new location. +/obj/structure/transport/linear/tram/proc/unlock_controls() + for(var/obj/structure/transport/linear/tram/tram_part as anything in transport_controller_datum.transport_modules) //only thing everyone needs to know is the new location. tram_part.set_travelling(FALSE) - lift_master_datum.set_controls(LIFT_PLATFORM_UNLOCKED) + transport_controller_datum.controls_lock(FALSE) ///debug proc to highlight the locs of the tram platform -/obj/structure/industrial_lift/tram/proc/find_dimensions(iterations = 100) +/obj/structure/transport/linear/tram/proc/find_dimensions(iterations = 100) message_admins("num turfs: [length(locs)]") var/overlay = /obj/effect/overlay/ai_detect_hud @@ -886,7 +906,7 @@ GLOBAL_LIST_INIT(all_radial_directions, list( addtimer(CALLBACK(src, PROC_REF(clear_turfs), turfs, iterations), 1) -/obj/structure/industrial_lift/tram/proc/clear_turfs(list/turfs_to_clear, iterations) +/obj/structure/transport/linear/tram/proc/clear_turfs(list/turfs_to_clear, iterations) for(var/turf/our_old_turf as anything in turfs_to_clear) var/obj/effect/overlay/ai_detect_hud/hud = locate() in our_old_turf if(hud) @@ -905,3 +925,12 @@ GLOBAL_LIST_INIT(all_radial_directions, list( if(iterations) addtimer(CALLBACK(src, PROC_REF(clear_turfs), turfs, iterations), 1) + +/obj/structure/transport/linear/tram/proc/estop_throw(throw_direction) + if(prob(50)) + do_sparks(2, FALSE, src) + for(var/mob/living/passenger in transport_contents) + to_chat(passenger, span_userdanger("The tram comes to a sudden, grinding stop!")) + var/throw_target = get_edge_target_turf(src, throw_direction) + var/datum/callback/land_slam = new(passenger, TYPE_PROC_REF(/mob/living/, tram_slam_land)) + passenger.throw_at(throw_target, 400, 4, force = MOVE_FORCE_OVERPOWERING, callback = land_slam) diff --git a/code/modules/transport/transport_navigation.dm b/code/modules/transport/transport_navigation.dm new file mode 100644 index 00000000000..3b5c73b5de1 --- /dev/null +++ b/code/modules/transport/transport_navigation.dm @@ -0,0 +1,108 @@ +/** + * transport_controller landmarks. used to map specific destinations on the map. + */ +/obj/effect/landmark/transport/nav_beacon/tram + name = "tram destination" //the tram buttons will mention this. + icon_state = "tram" + + /// The ID of the tram we're linked to + var/specific_transport_id = TRAMSTATION_LINE_1 + /// The ID of that particular destination + var/platform_code = null + /// Icons for the tgui console to list out for what is at this location + var/list/tgui_icons = list() + +/obj/effect/landmark/transport/nav_beacon/tram/Initialize(mapload) + . = ..() + LAZYADDASSOCLIST(SStransport.nav_beacons, specific_transport_id, src) + +/obj/effect/landmark/transport/nav_beacon/tram/Destroy() + LAZYREMOVEASSOC(SStransport.nav_beacons, specific_transport_id, src) + return ..() + +/obj/effect/landmark/transport/nav_beacon/tram/nav + name = "tram nav beacon" + invisibility = INVISIBILITY_MAXIMUM // nav aids can't be abstract since they stay with the tram + +/** + * transport_controller landmarks. used to map in specific_transport_id to trams and elevators. when the transport_controller encounters one on a tile + * it sets its specific_transport_id to that landmark. allows you to have multiple trams and multiple objects linking to their specific tram + */ +/obj/effect/landmark/transport/transport_id + name = "transport init landmark" + icon_state = "lift_id" + ///what specific id we give to the tram we're placed on, should explicitely set this if its a subtype, or weird things might happen + var/specific_transport_id + +//tramstation + +/obj/effect/landmark/transport/transport_id/tramstation/line_1 + specific_transport_id = TRAMSTATION_LINE_1 + +/obj/effect/landmark/transport/nav_beacon/tram/nav/tramstation/main + name = TRAMSTATION_LINE_1 + specific_transport_id = TRAM_NAV_BEACONS + dir = WEST + +/obj/effect/landmark/transport/nav_beacon/tram/platform/tramstation/west + name = "West Wing" + platform_code = TRAMSTATION_WEST + tgui_icons = list("Arrivals" = "plane-arrival", "Command" = "bullhorn", "Security" = "gavel") + +/obj/effect/landmark/transport/nav_beacon/tram/platform/tramstation/central + name = "Central Wing" + platform_code = TRAMSTATION_CENTRAL + tgui_icons = list("Service" = "cocktail", "Medical" = "plus", "Engineering" = "wrench") + +/obj/effect/landmark/transport/nav_beacon/tram/platform/tramstation/east + name = "East Wing" + platform_code = TRAMSTATION_EAST + tgui_icons = list("Departures" = "plane-departure", "Cargo" = "box", "Science" = "flask") + +//birdshot + +/obj/effect/landmark/transport/transport_id/birdshot/line_1 + specific_transport_id = BIRDSHOT_LINE_1 + +/obj/effect/landmark/transport/transport_id/birdshot/line_2 + specific_transport_id = BIRDSHOT_LINE_2 + +/obj/effect/landmark/transport/nav_beacon/tram/nav/birdshot/prison + name = BIRDSHOT_LINE_1 + specific_transport_id = TRAM_NAV_BEACONS + dir = NORTH + +/obj/effect/landmark/transport/nav_beacon/tram/nav/birdshot/maint + name = BIRDSHOT_LINE_2 + specific_transport_id = TRAM_NAV_BEACONS + dir = WEST + +/obj/effect/landmark/transport/nav_beacon/tram/platform/birdshot/sec_wing + name = "Security Wing" + specific_transport_id = BIRDSHOT_LINE_1 + platform_code = BIRDSHOT_SECURITY_WING + tgui_icons = list("Security" = "gavel") + +/obj/effect/landmark/transport/nav_beacon/tram/platform/birdshot/prison_wing + name = "Prison Wing" + specific_transport_id = BIRDSHOT_LINE_1 + platform_code = BIRDSHOT_PRISON_WING + tgui_icons = list("Prison" = "box") + +/obj/effect/landmark/transport/nav_beacon/tram/platform/birdshot/maint_left + name = "Port Platform" + specific_transport_id = BIRDSHOT_LINE_2 + platform_code = BIRDSHOT_MAINTENANCE_LEFT + tgui_icons = list("Port Platform" = "plane-departure") + +/obj/effect/landmark/transport/nav_beacon/tram/platform/birdshot/maint_right + name = "Starboard Platform" + specific_transport_id = BIRDSHOT_LINE_2 + platform_code = BRIDSHOT_MAINTENANCE_RIGHT + tgui_icons = list("Starboard Platform" = "plane-arrival") + +//map-agnostic landmarks + +/obj/effect/landmark/transport/nav_beacon/tram/nav/immovable_rod + name = "DESTINATION/NOT/FOUND" + specific_transport_id = IMMOVABLE_ROD_DESTINATIONS diff --git a/code/modules/unit_tests/unit_test.dm b/code/modules/unit_tests/unit_test.dm index c552902775a..2ad1f182215 100644 --- a/code/modules/unit_tests/unit_test.dm +++ b/code/modules/unit_tests/unit_test.dm @@ -311,7 +311,7 @@ GLOBAL_VAR_INIT(focused_tests, focused_tests()) //Needs a holodeck area linked to it which is not guarenteed to exist and technically is supposed to have a 1:1 relationship with computer anyway. returnable_list += typesof(/obj/machinery/computer/holodeck) //runtimes if not paired with a landmark - returnable_list += typesof(/obj/structure/industrial_lift) + returnable_list += typesof(/obj/structure/transport/linear) // Runtimes if the associated machinery does not exist, but not the base type returnable_list += subtypesof(/obj/machinery/airlock_controller) // Always ought to have an associated escape menu. Any references it could possibly hold would need one regardless. diff --git a/code/modules/uplink/uplink_items/device_tools.dm b/code/modules/uplink/uplink_items/device_tools.dm index 8a83e7450c5..c698a46761b 100644 --- a/code/modules/uplink/uplink_items/device_tools.dm +++ b/code/modules/uplink/uplink_items/device_tools.dm @@ -46,7 +46,7 @@ desc = "When linked to a tram's on board computer systems, this device allows the user to manipulate the controls remotely. \ Includes direction toggle and a rapid mode to bypass door safety checks and crossing signals. \ Perfect for running someone over in the name of a tram malfunction!" - item = /obj/item/tram_remote + item = /obj/item/assembly/control/transport/remote cost = 2 /datum/uplink_item/device_tools/thermal diff --git a/icons/obj/doors/airlocks/tram/tram-overlays.dmi b/icons/obj/doors/airlocks/tram/tram-overlays.dmi new file mode 100644 index 00000000000..879c920686d Binary files /dev/null and b/icons/obj/doors/airlocks/tram/tram-overlays.dmi differ diff --git a/icons/obj/doors/airlocks/tram/tram.dmi b/icons/obj/doors/airlocks/tram/tram.dmi new file mode 100644 index 00000000000..43d30b58a6f Binary files /dev/null and b/icons/obj/doors/airlocks/tram/tram.dmi differ diff --git a/icons/obj/doors/tramdoor.dmi b/icons/obj/doors/tramdoor.dmi deleted file mode 100644 index 8ca8c9aee49..00000000000 Binary files a/icons/obj/doors/tramdoor.dmi and /dev/null differ diff --git a/icons/obj/fluff/tram_rails.dmi b/icons/obj/fluff/tram_rails.dmi deleted file mode 100644 index 359fc5f7838..00000000000 Binary files a/icons/obj/fluff/tram_rails.dmi and /dev/null differ diff --git a/icons/obj/machines/computer.dmi b/icons/obj/machines/computer.dmi index 5ffa3445db6..9cb0dda4967 100644 Binary files a/icons/obj/machines/computer.dmi and b/icons/obj/machines/computer.dmi differ diff --git a/icons/obj/machines/crossing_signal.dmi b/icons/obj/machines/crossing_signal.dmi deleted file mode 100644 index 4e31966f7e4..00000000000 Binary files a/icons/obj/machines/crossing_signal.dmi and /dev/null differ diff --git a/icons/obj/machines/lift_indicator.dmi b/icons/obj/machines/lift_indicator.dmi index 878606ae489..24983cf5dae 100644 Binary files a/icons/obj/machines/lift_indicator.dmi and b/icons/obj/machines/lift_indicator.dmi differ diff --git a/icons/obj/machines/tram_sign.dmi b/icons/obj/machines/tram_sign.dmi deleted file mode 100644 index 1043153c4e3..00000000000 Binary files a/icons/obj/machines/tram_sign.dmi and /dev/null differ diff --git a/icons/obj/machines/wallmounts.dmi b/icons/obj/machines/wallmounts.dmi index 39e4cc2476b..379668e3a1d 100644 Binary files a/icons/obj/machines/wallmounts.dmi and b/icons/obj/machines/wallmounts.dmi differ diff --git a/icons/obj/signs.dmi b/icons/obj/signs.dmi index 20531b0f8ea..9ece919c213 100644 Binary files a/icons/obj/signs.dmi and b/icons/obj/signs.dmi differ diff --git a/icons/obj/smooth_structures/tram_window.dmi b/icons/obj/smooth_structures/tram_window.dmi deleted file mode 100644 index 938ca3a0c0b..00000000000 Binary files a/icons/obj/smooth_structures/tram_window.dmi and /dev/null differ diff --git a/icons/obj/structures.dmi b/icons/obj/structures.dmi index 0289c9105be..5d6e1eb8a24 100644 Binary files a/icons/obj/structures.dmi and b/icons/obj/structures.dmi differ diff --git a/icons/obj/tram/crossing_signal.dmi b/icons/obj/tram/crossing_signal.dmi new file mode 100644 index 00000000000..b532ca1e175 Binary files /dev/null and b/icons/obj/tram/crossing_signal.dmi differ diff --git a/icons/obj/tram/tram_controllers.dmi b/icons/obj/tram/tram_controllers.dmi new file mode 100644 index 00000000000..93462e0b41e Binary files /dev/null and b/icons/obj/tram/tram_controllers.dmi differ diff --git a/icons/obj/tram/tram_display.dmi b/icons/obj/tram/tram_display.dmi new file mode 100644 index 00000000000..e28beef468f Binary files /dev/null and b/icons/obj/tram/tram_display.dmi differ diff --git a/icons/obj/tram/tram_indicator.dmi b/icons/obj/tram/tram_indicator.dmi new file mode 100644 index 00000000000..f1b0b412390 Binary files /dev/null and b/icons/obj/tram/tram_indicator.dmi differ diff --git a/icons/obj/tram/tram_rails.dmi b/icons/obj/tram/tram_rails.dmi new file mode 100644 index 00000000000..8e0316223b3 Binary files /dev/null and b/icons/obj/tram/tram_rails.dmi differ diff --git a/icons/obj/tram/tram_sensor.dmi b/icons/obj/tram/tram_sensor.dmi new file mode 100644 index 00000000000..de50b20e701 Binary files /dev/null and b/icons/obj/tram/tram_sensor.dmi differ diff --git a/icons/obj/tram/tram_structure.dmi b/icons/obj/tram/tram_structure.dmi new file mode 100644 index 00000000000..8840f3a4f2c Binary files /dev/null and b/icons/obj/tram/tram_structure.dmi differ diff --git a/icons/turf/walls/tram_wall.dmi b/icons/obj/tram/tram_wall.dmi similarity index 100% rename from icons/turf/walls/tram_wall.dmi rename to icons/obj/tram/tram_wall.dmi diff --git a/icons/turf/damaged.dmi b/icons/turf/damaged.dmi index d3d06d53e46..a81384d8be6 100644 Binary files a/icons/turf/damaged.dmi and b/icons/turf/damaged.dmi differ diff --git a/icons/turf/floors.dmi b/icons/turf/floors.dmi index 6ddc178b98c..682809fbf43 100644 Binary files a/icons/turf/floors.dmi and b/icons/turf/floors.dmi differ diff --git a/icons/turf/tram.dmi b/icons/turf/tram.dmi new file mode 100644 index 00000000000..d38802bd8de Binary files /dev/null and b/icons/turf/tram.dmi differ diff --git a/modular_skyrat/modules/aesthetics/airlock/code/airlock.dm b/modular_skyrat/modules/aesthetics/airlock/code/airlock.dm index 91f866fda6d..15c5d45ba8b 100644 --- a/modular_skyrat/modules/aesthetics/airlock/code/airlock.dm +++ b/modular_skyrat/modules/aesthetics/airlock/code/airlock.dm @@ -1,27 +1,3 @@ -//SKYRAT ADDITION BEGIN - AESTHETICS -#define AIRLOCK_LIGHT_POWER 0.5 -#define AIRLOCK_LIGHT_RANGE 2 -#define AIRLOCK_LIGHT_ENGINEERING "engineering" -#define AIRLOCK_POWERON_LIGHT_COLOR "#3aa7c2" -#define AIRLOCK_BOLTS_LIGHT_COLOR "#c22323" -#define AIRLOCK_ACCESS_LIGHT_COLOR "#57e69c" -#define AIRLOCK_EMERGENCY_LIGHT_COLOR "#d1d11d" -#define AIRLOCK_ENGINEERING_LIGHT_COLOR "#fd8719" -#define AIRLOCK_DENY_LIGHT_COLOR "#c22323" -//SKYRAT ADDITION END - -#define AIRLOCK_CLOSED 1 -#define AIRLOCK_CLOSING 2 -#define AIRLOCK_OPEN 3 -#define AIRLOCK_OPENING 4 -#define AIRLOCK_DENY 5 -#define AIRLOCK_EMAG 6 - -#define AIRLOCK_FRAME_CLOSED "closed" -#define AIRLOCK_FRAME_CLOSING "closing" -#define AIRLOCK_FRAME_OPEN "open" -#define AIRLOCK_FRAME_OPENING "opening" - /obj/machinery/door/airlock doorOpen = 'modular_skyrat/modules/aesthetics/airlock/sound/open.ogg' doorClose = 'modular_skyrat/modules/aesthetics/airlock/sound/close.ogg' @@ -388,7 +364,6 @@ /obj/machinery/door/airlock/multi_tile icon = 'modular_skyrat/modules/aesthetics/airlock/icons/airlocks/multi_tile/glass.dmi' overlays_file = 'modular_skyrat/modules/aesthetics/airlock/icons/airlocks/multi_tile/glass_overlays.dmi' - bound_width = 64 /obj/machinery/door/airlock/multi_tile/glass icon = 'modular_skyrat/modules/aesthetics/airlock/icons/airlocks/multi_tile/glass.dmi' @@ -398,6 +373,16 @@ icon = 'modular_skyrat/modules/aesthetics/airlock/icons/airlocks/multi_tile/metal.dmi' overlays_file = 'modular_skyrat/modules/aesthetics/airlock/icons/airlocks/multi_tile/metal_overlays.dmi' +//TRAM + +/obj/machinery/door/airlock/tram + name = "tram door" + icon = 'modular_skyrat/modules/aesthetics/airlock/icons/airlocks/tram/tram.dmi' + overlays_file = 'modular_skyrat/modules/aesthetics/airlock/icons/airlocks/tram/tram_overlays.dmi' + doorOpen = 'sound/machines/tramopen.ogg' + doorClose = 'sound/machines/tramclose.ogg' + has_environment_lights = FALSE + //ASSEMBLYS /obj/structure/door_assembly/door_assembly_public icon = 'modular_skyrat/modules/aesthetics/airlock/icons/airlocks/station2/glass.dmi' @@ -571,27 +556,3 @@ /obj/structure/door_assembly/ icon = 'modular_skyrat/modules/aesthetics/airlock/icons/airlocks/station/public.dmi' overlays_file = 'modular_skyrat/modules/aesthetics/airlock/icons/airlocks/station/overlays.dmi' - -//SKYRAT EDIT ADDITION BEGIN - AESTHETICS -#undef AIRLOCK_LIGHT_POWER -#undef AIRLOCK_LIGHT_RANGE -#undef AIRLOCK_LIGHT_ENGINEERING -#undef AIRLOCK_ENGINEERING_LIGHT_COLOR -#undef AIRLOCK_POWERON_LIGHT_COLOR -#undef AIRLOCK_BOLTS_LIGHT_COLOR -#undef AIRLOCK_ACCESS_LIGHT_COLOR -#undef AIRLOCK_EMERGENCY_LIGHT_COLOR -#undef AIRLOCK_DENY_LIGHT_COLOR -//SKYRAT EDIT END - -#undef AIRLOCK_CLOSED -#undef AIRLOCK_CLOSING -#undef AIRLOCK_OPEN -#undef AIRLOCK_OPENING -#undef AIRLOCK_DENY -#undef AIRLOCK_EMAG - -#undef AIRLOCK_FRAME_CLOSED -#undef AIRLOCK_FRAME_CLOSING -#undef AIRLOCK_FRAME_OPEN -#undef AIRLOCK_FRAME_OPENING diff --git a/modular_skyrat/modules/aesthetics/airlock/icons/airlocks/tram/tram.dmi b/modular_skyrat/modules/aesthetics/airlock/icons/airlocks/tram/tram.dmi new file mode 100644 index 00000000000..43d30b58a6f Binary files /dev/null and b/modular_skyrat/modules/aesthetics/airlock/icons/airlocks/tram/tram.dmi differ diff --git a/modular_skyrat/modules/aesthetics/airlock/icons/airlocks/tram/tram_overlays.dmi b/modular_skyrat/modules/aesthetics/airlock/icons/airlocks/tram/tram_overlays.dmi new file mode 100644 index 00000000000..e30dbeb2b98 Binary files /dev/null and b/modular_skyrat/modules/aesthetics/airlock/icons/airlocks/tram/tram_overlays.dmi differ diff --git a/modular_skyrat/modules/opposing_force/code/equipment/utility.dm b/modular_skyrat/modules/opposing_force/code/equipment/utility.dm index 17c7c6ed8ce..7bdc361280a 100644 --- a/modular_skyrat/modules/opposing_force/code/equipment/utility.dm +++ b/modular_skyrat/modules/opposing_force/code/equipment/utility.dm @@ -13,7 +13,7 @@ /datum/opposing_force_equipment/gear/tram_remote name = "Tram Remote Control" - item_type = /obj/item/tram_remote + item_type = /obj/item/assembly/control/transport/remote description = "When linked to a tram's on board computer systems, this device allows the user to manipulate the controls remotely. \ Includes direction toggle and a rapid mode to bypass door safety checks and crossing signals. \ Perfect for running someone over in the name of a tram malfunction!" diff --git a/tgstation.dme b/tgstation.dme index 56ac7fcc85f..378223bea5b 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -109,7 +109,6 @@ #include "code\__DEFINES\icon_smoothing.dm" #include "code\__DEFINES\id_cards.dm" #include "code\__DEFINES\important_recursive_contents.dm" -#include "code\__DEFINES\industrial_lift.dm" #include "code\__DEFINES\injection.dm" #include "code\__DEFINES\input.dm" #include "code\__DEFINES\instruments.dm" @@ -209,6 +208,7 @@ #include "code\__DEFINES\species_clothing_paths.dm" #include "code\__DEFINES\speech_channels.dm" #include "code\__DEFINES\sprite_accessories.dm" +#include "code\__DEFINES\stack.dm" #include "code\__DEFINES\stack_trace.dm" #include "code\__DEFINES\stat.dm" #include "code\__DEFINES\stat_tracking.dm" @@ -230,7 +230,7 @@ #include "code\__DEFINES\tools.dm" #include "code\__DEFINES\toys.dm" #include "code\__DEFINES\traits.dm" -#include "code\__DEFINES\tram.dm" +#include "code\__DEFINES\transport.dm" #include "code\__DEFINES\tts.dm" #include "code\__DEFINES\turbine_defines.dm" #include "code\__DEFINES\turfs.dm" @@ -339,8 +339,8 @@ #include "code\__DEFINES\dcs\signals\signals_techweb.dm" #include "code\__DEFINES\dcs\signals\signals_tools.dm" #include "code\__DEFINES\dcs\signals\signals_traitor.dm" -#include "code\__DEFINES\dcs\signals\signals_tram.dm" #include "code\__DEFINES\dcs\signals\signals_transform.dm" +#include "code\__DEFINES\dcs\signals\signals_transport.dm" #include "code\__DEFINES\dcs\signals\signals_turf.dm" #include "code\__DEFINES\dcs\signals\signals_twohand.dm" #include "code\__DEFINES\dcs\signals\signals_vehicle.dm" @@ -380,6 +380,7 @@ #include "code\__DEFINES\~skyrat_defines\access.dm" #include "code\__DEFINES\~skyrat_defines\actionspeed_modification.dm" #include "code\__DEFINES\~skyrat_defines\admin.dm" +#include "code\__DEFINES\~skyrat_defines\airlock.dm" #include "code\__DEFINES\~skyrat_defines\ammo_defines.dm" #include "code\__DEFINES\~skyrat_defines\antagonists.dm" #include "code\__DEFINES\~skyrat_defines\apc_defines.dm" @@ -565,6 +566,7 @@ #include "code\__HELPERS\logging\shuttle.dm" #include "code\__HELPERS\logging\talk.dm" #include "code\__HELPERS\logging\tool.dm" +#include "code\__HELPERS\logging\transport.dm" #include "code\__HELPERS\logging\ui.dm" #include "code\__HELPERS\logging\virus.dm" #include "code\__HELPERS\sorts\__main.dm" @@ -758,6 +760,7 @@ #include "code\controllers\subsystem\timer.dm" #include "code\controllers\subsystem\title.dm" #include "code\controllers\subsystem\traitor.dm" +#include "code\controllers\subsystem\transport.dm" #include "code\controllers\subsystem\tts.dm" #include "code\controllers\subsystem\tutorials.dm" #include "code\controllers\subsystem\verb_manager.dm" @@ -796,7 +799,6 @@ #include "code\controllers\subsystem\processing\singulo.dm" #include "code\controllers\subsystem\processing\station.dm" #include "code\controllers\subsystem\processing\supermatter_cascade.dm" -#include "code\controllers\subsystem\processing\tramprocess.dm" #include "code\controllers\subsystem\processing\wet_floors.dm" #include "code\datums\alarm.dm" #include "code\datums\beam.dm" @@ -1089,6 +1091,7 @@ #include "code\datums\components\egg_layer.dm" #include "code\datums\components\electrified_buckle.dm" #include "code\datums\components\embedded.dm" +#include "code\datums\components\energized.dm" #include "code\datums\components\engraved.dm" #include "code\datums\components\evolutionary_leap.dm" #include "code\datums\components\explodable.dm" @@ -4079,23 +4082,6 @@ #include "code\modules\hydroponics\grown\weeds\kudzu.dm" #include "code\modules\hydroponics\grown\weeds\nettle.dm" #include "code\modules\hydroponics\grown\weeds\starthistle.dm" -#include "code\modules\industrial_lift\industrial_lift.dm" -#include "code\modules\industrial_lift\lift_master.dm" -#include "code\modules\industrial_lift\elevator\elevator_controller.dm" -#include "code\modules\industrial_lift\elevator\elevator_doors.dm" -#include "code\modules\industrial_lift\elevator\elevator_indicator.dm" -#include "code\modules\industrial_lift\elevator\elevator_music_zone.dm" -#include "code\modules\industrial_lift\elevator\elevator_panel.dm" -#include "code\modules\industrial_lift\tram\tram_doors.dm" -#include "code\modules\industrial_lift\tram\tram_floors.dm" -#include "code\modules\industrial_lift\tram\tram_landmark.dm" -#include "code\modules\industrial_lift\tram\tram_lift_master.dm" -#include "code\modules\industrial_lift\tram\tram_machinery.dm" -#include "code\modules\industrial_lift\tram\tram_override_objects.dm" -#include "code\modules\industrial_lift\tram\tram_remote.dm" -#include "code\modules\industrial_lift\tram\tram_structures.dm" -#include "code\modules\industrial_lift\tram\tram_walls.dm" -#include "code\modules\industrial_lift\tram\tram_windows.dm" #include "code\modules\instruments\items.dm" #include "code\modules\instruments\piano_synth.dm" #include "code\modules\instruments\stationary.dm" @@ -5701,6 +5687,25 @@ #include "code\modules\tgui_panel\telemetry.dm" #include "code\modules\tgui_panel\tgui_panel.dm" #include "code\modules\tooltip\tooltip.dm" +#include "code\modules\transport\_transport_machinery.dm" +#include "code\modules\transport\admin.dm" +#include "code\modules\transport\linear_controller.dm" +#include "code\modules\transport\transport_module.dm" +#include "code\modules\transport\transport_navigation.dm" +#include "code\modules\transport\elevator\elev_controller.dm" +#include "code\modules\transport\elevator\elev_doors.dm" +#include "code\modules\transport\elevator\elev_indicator.dm" +#include "code\modules\transport\elevator\elev_music_zone.dm" +#include "code\modules\transport\elevator\elev_panel.dm" +#include "code\modules\transport\tram\tram_controller.dm" +#include "code\modules\transport\tram\tram_controls.dm" +#include "code\modules\transport\tram\tram_displays.dm" +#include "code\modules\transport\tram\tram_doors.dm" +#include "code\modules\transport\tram\tram_floors.dm" +#include "code\modules\transport\tram\tram_machinery.dm" +#include "code\modules\transport\tram\tram_remote.dm" +#include "code\modules\transport\tram\tram_signals.dm" +#include "code\modules\transport\tram\tram_structures.dm" #include "code\modules\tutorials\_tutorial.dm" #include "code\modules\tutorials\tutorial_instruction.dm" #include "code\modules\tutorials\tutorials\drop.dm" diff --git a/tgui/packages/tgui/interfaces/CrossingSignal.tsx b/tgui/packages/tgui/interfaces/CrossingSignal.tsx new file mode 100644 index 00000000000..6fbda68c452 --- /dev/null +++ b/tgui/packages/tgui/interfaces/CrossingSignal.tsx @@ -0,0 +1,49 @@ +import { BooleanLike } from 'common/react'; +import { useBackend } from '../backend'; +import { Section, LabeledList } from '../components'; +import { Window } from '../layouts'; + +type Data = { + sensorStatus: BooleanLike; + operatingStatus: number; + inboundPlatform: number; + outboundPlatform: number; +}; + +type Props = { + context: any; +}; + +export const CrossingSignal = (props, context) => { + const { act, data } = useBackend(context); + + const { sensorStatus, operatingStatus, inboundPlatform, outboundPlatform } = + data; + + return ( + + +
+ + + {operatingStatus ? 'Degraded' : 'Normal'} + + + {sensorStatus ? 'Connected' : 'Error'} + + + {inboundPlatform} + + + {outboundPlatform} + + +
+
+
+ ); +}; diff --git a/tgui/packages/tgui/interfaces/TramControl.js b/tgui/packages/tgui/interfaces/TramControl.js index 2d1f0beb24e..b9b8359da09 100644 --- a/tgui/packages/tgui/interfaces/TramControl.js +++ b/tgui/packages/tgui/interfaces/TramControl.js @@ -44,10 +44,10 @@ const BrokenTramDimmer = () => { - + - No Tram Detected! + Check Tram Controller! diff --git a/tgui/packages/tgui/interfaces/TramController.tsx b/tgui/packages/tgui/interfaces/TramController.tsx new file mode 100644 index 00000000000..dbe048fc329 --- /dev/null +++ b/tgui/packages/tgui/interfaces/TramController.tsx @@ -0,0 +1,279 @@ +import { useBackend, useLocalState } from '../backend'; +import { BooleanLike } from 'common/react'; +import { Stack, Section, LabeledList, ProgressBar, Button, NoticeBox, Dropdown } from '../components'; +import { toFixed } from 'common/math'; +import { Window } from '../layouts'; + +type Data = { + transportId: string; + controllerActive: number; + controllerOperational: BooleanLike; + travelDirection: number; + destinationPlatform: string; + idlePlatform: string; + recoveryMode: BooleanLike; + currentSpeed: number; + currentLoad: number; + statusSF: BooleanLike; + statusCE: BooleanLike; + statusES: BooleanLike; + statusPD: BooleanLike; + statusDR: BooleanLike; + statusCL: BooleanLike; + statusBS: BooleanLike; + destinations: TramDestination[]; +}; + +type TramDestination = { + name: string; + dest_icons: string[]; + id: number; +}; + +export const TramController = (props, context) => { + const { act, data } = useBackend(context); + + const { + transportId, + controllerActive, + controllerOperational, + travelDirection, + destinationPlatform, + idlePlatform, + recoveryMode, + currentSpeed, + currentLoad, + statusSF, + statusCE, + statusES, + statusPD, + statusDR, + statusCL, + statusBS, + destinations = [], + } = data; + + const [tripDestination, setTripDestination] = useLocalState( + context, + 'TramDestination', + '' + ); + + return ( + + + + +
+ + + {transportId} + + + {controllerActive ? 'Processing' : 'Ready'} + + + {controllerOperational ? 'Normal' : 'Fault'} + + + {recoveryMode ? 'Overload' : 'Normal'} + + + + + + + {toFixed(currentSpeed * 2.25, 0) + ' km/h'} + + + +
+
+ + + {travelDirection === 4 ? 'Outbound' : 'Inbound'} + + + {idlePlatform} + + + {destinationPlatform} + + +
+
+ +
+ + Nanotrasen is not responsible for any injuries or fatalities + caused by usage of the tram. + + + + + id.name)} + selected={tripDestination} + displayText={tripDestination || 'Pick a Destination'} + onSelected={(value) => setTripDestination(value)} + /> + + + +
+
+ + + + + + +
+
+
+
+
+ ); +}; diff --git a/tgui/packages/tgui/interfaces/TramPlaque.tsx b/tgui/packages/tgui/interfaces/TramPlaque.tsx new file mode 100644 index 00000000000..9a6e90d16d8 --- /dev/null +++ b/tgui/packages/tgui/interfaces/TramPlaque.tsx @@ -0,0 +1,86 @@ +import { useBackend } from '../backend'; +import { NoticeBox, Section, LabeledList, Stack } from '../components'; +import { Window } from '../layouts'; + +type Data = { + currentTram: Tram[]; + previousTrams: Tram[]; +}; + +type Tram = { + serialNumber: string; + mfgDate: string; + distanceTravelled: number; + tramCollisions: number; +}; + +export const TramPlaque = (props, context) => { + const { data } = useBackend(context); + const { currentTram = [], previousTrams = [] } = data; + + return ( + + + SkyyTram Mk VI by Nakamura Engineering +
serialNumber.serialNumber) + + ' - Constructed ' + + currentTram.map((serialNumber) => serialNumber.mfgDate) + }> + + + {currentTram.map( + (serialNumber) => serialNumber.distanceTravelled / 1000 + )}{' '} + km + + + {currentTram.map((serialNumber) => serialNumber.tramCollisions)} + + +
+
+ + + Serial + + + Constructed + + + Distance + + + Collisions + + + + {previousTrams.map((tram_entry) => ( + + + + {tram_entry.serialNumber} + + + {tram_entry.mfgDate} + + + {tram_entry.distanceTravelled / 1000} km + + + {tram_entry.tramCollisions} + + + + ))} + +
+
+
+ ); +}; diff --git a/tools/UpdatePaths/Scripts/77777_Tram_2023.txt b/tools/UpdatePaths/Scripts/77777_Tram_2023.txt new file mode 100644 index 00000000000..f3ac42e09f5 --- /dev/null +++ b/tools/UpdatePaths/Scripts/77777_Tram_2023.txt @@ -0,0 +1,11 @@ +#comment Repathing for Transport Subsystem + +/obj/structure/industrial_lift : /obj/structure/transport/linear{@OLD} +/obj/structure/industrial_lift/public : /obj/structure/transport/linear/public{@OLD} +/obj/structure/industrial_lift/debug : /obj/structure/transport/linear/debug{@OLD} +/obj/structure/industrial_lift/tram : /obj/structure/transport/linear/tram{@OLD} +/obj/effect/landmark/lift_id : /obj/effect/landmark/transport/transport_id{@OLD} +/obj/effect/landmark/tram/nav/immovable_rod : /obj/effect/landmark/transport/nav_beacon/tram/nav/immovable_rod{@OLD} +/turf/open/floor/noslip/tram_plate : /turf/open/floor/tram/plate{@OLD} +/turf/open/floor/noslip/tram_plate/energized : /turf/open/floor/tram/plate/energized{@OLD} +/turf/open/floor/noslip/tram_platform : /turf/open/floor/tram{@OLD} \ No newline at end of file