diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 817626d228..643b4d6e64 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -414,10 +414,17 @@ Regarding sprites & sounds, you must credit the artist and possibly the codebase Do not add any of the following in a Pull Request or risk getting the PR closed: * National Socialist Party of Germany content, National Socialist Party of Germany related content, or National Socialist Party of Germany references * Code where one line of code is split across mutiple lines (except for multiple, separate strings and comments; in those cases, existing longer lines must not be split up) -* Code adding, removing, or updating the availability of alien races/species/human mutants without prior approval. Pull requests attempting to add or remove features from said races/species/mutants require prior approval as well. Just because something isn't on this list doesn't mean that it's acceptable. Use common sense above all else. +## Content requiring prior approval +Certain types of changes may require prior approval from maintainers. This currently includes: + +* Code adding, removing, or updating the availability of alien races/species/human mutants. This includes pull requests attempting to add or remove features from said races/species/mutants. (Requires approval from at least one maintainer) +* Code adding, removing, or modifying the functionality of adult-oriented features (such as, but not limited to: vore, genitals, MKUltra, and more). This also includes pull requests attempting to add or remove these features outright. (Requires approval from at least half of the formal maintainer team) + +The above content requires approval from the specified amount of maintainers prior to PR creation. Seeking approval must be done via a @Maintainer ping in a relevant development/code or staff channel on the Discord, otherwise it will be considered insufficient. If a PR contains any of the above content, but the creator does not have sufficient approval prior to the PR's creation, then the PR may be closed by any maintainer, at any time, for any reason. + ## A word on Git Yes, we know that the files have a tonne of mixed Windows and Linux line endings. Attempts to fix this have been met with less than stellar success, and as such we have decided to give up caring until there comes a time when it matters. diff --git a/_maps/RandomRuins/AnywhereRuins/golem_ship.dmm b/_maps/RandomRuins/AnywhereRuins/golem_ship.dmm index d01e4f8da1..37a89ba2ff 100644 --- a/_maps/RandomRuins/AnywhereRuins/golem_ship.dmm +++ b/_maps/RandomRuins/AnywhereRuins/golem_ship.dmm @@ -18,9 +18,7 @@ /obj/item/mining_scanner, /obj/item/flashlight/lantern, /obj/item/card/id/mining, -/obj/item/gps/mining{ - tracking = 0 - }, +/obj/item/gps/mining, /turf/open/floor/plating, /area/ruin/powered/golem_ship) "d" = ( @@ -34,9 +32,7 @@ /obj/item/mining_scanner, /obj/item/flashlight/lantern, /obj/item/card/id/mining, -/obj/item/gps/mining{ - tracking = 0 - }, +/obj/item/gps/mining, /turf/open/floor/plating, /area/ruin/powered/golem_ship) "e" = ( @@ -156,9 +152,7 @@ "x" = ( /obj/structure/table/wood, /obj/machinery/reagentgrinder, -/obj/item/gps/mining{ - tracking = 0 - }, +/obj/item/gps/mining, /turf/open/floor/mineral/titanium/purple, /area/ruin/powered/golem_ship) "z" = ( diff --git a/_maps/RandomRuins/IceRuins/icemoon_surface_mining_site.dmm b/_maps/RandomRuins/IceRuins/icemoon_surface_mining_site.dmm index 969acdd871..23abc4b731 100644 --- a/_maps/RandomRuins/IceRuins/icemoon_surface_mining_site.dmm +++ b/_maps/RandomRuins/IceRuins/icemoon_surface_mining_site.dmm @@ -16,7 +16,7 @@ /turf/open/floor/wood, /area/ruin/unpowered) "d" = ( -/turf/open/openspace/icemoon, +/turf/open/transparent/openspace/icemoon, /area/icemoon/surface/outdoors) "e" = ( /obj/item/clothing/suit/hooded/explorer, diff --git a/_maps/RandomRuins/StationRuins/Box/Engine/engine_teg.dmm b/_maps/RandomRuins/StationRuins/Box/Engine/engine_teg.dmm index f8d701debe..2d66300953 100644 --- a/_maps/RandomRuins/StationRuins/Box/Engine/engine_teg.dmm +++ b/_maps/RandomRuins/StationRuins/Box/Engine/engine_teg.dmm @@ -71,8 +71,9 @@ /turf/closed/wall/r_wall, /area/engine/engineering) "di" = ( -/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, -/turf/closed/wall, +/obj/structure/reagent_dispensers/fueltank, +/obj/effect/turf_decal/delivery, +/turf/open/floor/plasteel, /area/engine/engineering) "dl" = ( /obj/structure/cable{ @@ -304,12 +305,6 @@ /obj/machinery/atmospherics/pipe/simple/supply/hidden{ dir = 4 }, -/obj/effect/turf_decal/tile/yellow{ - dir = 1 - }, -/obj/effect/turf_decal/tile/yellow{ - dir = 8 - }, /turf/open/floor/plasteel, /area/engine/engineering) "kH" = ( @@ -523,6 +518,9 @@ /obj/machinery/light{ dir = 4 }, +/obj/structure/sign/warning/enginesafety{ + pixel_x = 32 + }, /turf/open/floor/plasteel, /area/engine/engineering) "qv" = ( @@ -543,7 +541,13 @@ dir = 4 }, /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, -/turf/closed/wall, +/obj/effect/turf_decal/tile/yellow{ + dir = 1 + }, +/obj/effect/turf_decal/tile/yellow{ + dir = 8 + }, +/turf/open/floor/plasteel, /area/engine/engineering) "qN" = ( /obj/structure/table/reinforced, @@ -848,6 +852,10 @@ /obj/machinery/igniter{ id = "TEG_igniter" }, +/mob/living/carbon/monkey{ + name = "Mumkey Jones" + }, +/obj/item/clothing/head/hardhat/atmos, /turf/open/floor/engine/vacuum, /area/engine/engineering) "An" = ( @@ -882,14 +890,6 @@ /obj/machinery/atmospherics/pipe/simple/orange/visible{ dir = 1 }, -/obj/machinery/camera{ - c_tag = "TEG - North Center"; - dir = 8 - }, -/obj/effect/turf_decal/tile/yellow{ - dir = 4 - }, -/obj/effect/turf_decal/tile/yellow, /turf/open/floor/plasteel, /area/engine/engineering) "AX" = ( @@ -1042,12 +1042,6 @@ }, /turf/open/floor/plasteel, /area/engine/engineering) -"EI" = ( -/obj/effect/turf_decal/delivery, -/obj/structure/reagent_dispensers/fueltank, -/obj/machinery/atmospherics/pipe/simple/orange/visible, -/turf/open/floor/plasteel, -/area/engine/engineering) "EL" = ( /turf/closed/wall, /area/engine/engineering) @@ -1082,6 +1076,11 @@ /obj/structure/window/reinforced, /turf/open/floor/plasteel, /area/engine/engineering) +"Fs" = ( +/obj/structure/rack, +/obj/item/pipe_dispenser, +/turf/open/floor/plasteel, +/area/engine/engineering) "FG" = ( /obj/machinery/atmospherics/pipe/simple/orange/visible{ dir = 10 @@ -1218,11 +1217,6 @@ /turf/open/floor/plasteel, /area/engine/engineering) "Jd" = ( -/obj/machinery/light, -/obj/effect/turf_decal/tile/yellow{ - dir = 8 - }, -/obj/effect/turf_decal/tile/yellow, /obj/machinery/atmospherics/pipe/manifold/orange/visible, /turf/open/floor/plasteel, /area/engine/engineering) @@ -1312,15 +1306,6 @@ dir = 4 }, /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, -/obj/machinery/light{ - dir = 1 - }, -/obj/effect/turf_decal/tile/yellow{ - dir = 1 - }, -/obj/effect/turf_decal/tile/yellow{ - dir = 4 - }, /turf/open/floor/plasteel, /area/engine/engineering) "LD" = ( @@ -1372,6 +1357,7 @@ /obj/machinery/atmospherics/pipe/manifold/cyan/visible{ dir = 4 }, +/obj/machinery/meter, /turf/open/floor/plasteel, /area/engine/engineering) "Nz" = ( @@ -1429,12 +1415,10 @@ /obj/machinery/atmospherics/pipe/simple/scrubbers/visible{ dir = 4 }, -/obj/machinery/airalarm{ - dir = 1; - locked = 0; - pixel_y = -22 - }, /obj/machinery/light, +/obj/structure/sign/nanotrasen{ + pixel_y = -32 + }, /turf/open/floor/plasteel, /area/engine/engineering) "Pz" = ( @@ -1452,6 +1436,9 @@ /obj/machinery/light{ dir = 1 }, +/obj/structure/sign/warning/nosmoking{ + pixel_y = 30 + }, /turf/open/floor/plasteel, /area/engine/engineering) "PK" = ( @@ -1522,12 +1509,11 @@ /turf/open/space, /area/space/nearstation) "Rl" = ( -/obj/machinery/atmospherics/components/binary/pump{ - dir = 1 - }, /obj/effect/turf_decal/stripes/line{ dir = 1 }, +/obj/machinery/atmospherics/pipe/simple/cyan/visible, +/obj/machinery/meter, /turf/open/floor/plasteel, /area/engine/engineering) "Rz" = ( @@ -1602,7 +1588,13 @@ /turf/open/floor/plating, /area/engine/engineering) "TE" = ( -/obj/structure/closet/crate/internals, +/obj/structure/closet/crate{ + icon_state = "crateopen" + }, +/obj/effect/spawner/lootdrop/maintenance{ + lootcount = 2; + name = "2maintenance loot spawner" + }, /turf/open/floor/plasteel, /area/engine/engineering) "TH" = ( @@ -1648,6 +1640,10 @@ dir = 4 }, /obj/effect/turf_decal/tile/yellow, +/obj/machinery/camera{ + c_tag = "TEG - North Center"; + dir = 8 + }, /turf/open/floor/plasteel, /area/engine/engineering) "Uq" = ( @@ -1671,18 +1667,15 @@ /area/engine/engineering) "UT" = ( /obj/machinery/atmospherics/pipe/simple/orange/visible, -/obj/effect/turf_decal/tile/yellow{ - dir = 1 - }, -/obj/effect/turf_decal/tile/yellow{ - dir = 8 - }, /turf/open/floor/plasteel, /area/engine/engineering) "UY" = ( /obj/machinery/atmospherics/components/unary/vent_pump/on{ dir = 8 }, +/obj/machinery/airalarm{ + pixel_y = 23 + }, /turf/open/floor/plasteel, /area/engine/engineering) "Vi" = ( @@ -1811,10 +1804,6 @@ /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ dir = 5 }, -/obj/structure/extinguisher_cabinet{ - dir = 4; - pixel_y = -27 - }, /turf/open/floor/plasteel, /area/engine/engineering) "YC" = ( @@ -1837,9 +1826,10 @@ /turf/open/floor/plasteel, /area/engine/engineering) "YP" = ( -/obj/structure/rack, -/obj/machinery/atmospherics/pipe/simple/scrubbers/visible, -/obj/item/pipe_dispenser, +/obj/effect/turf_decal/tile/yellow{ + dir = 8 + }, +/obj/effect/turf_decal/tile/yellow, /turf/open/floor/plasteel, /area/engine/engineering) "YQ" = ( @@ -1878,7 +1868,9 @@ /turf/open/floor/plasteel, /area/engine/engineering) "Zu" = ( -/obj/machinery/atmospherics/pipe/manifold/cyan/visible, +/obj/machinery/atmospherics/pipe/simple/scrubbers/visible{ + dir = 6 + }, /obj/machinery/meter, /turf/open/floor/plasteel, /area/engine/engineering) @@ -1887,13 +1879,6 @@ dir = 4 }, /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, -/obj/structure/sign/warning/securearea{ - pixel_y = -32 - }, -/obj/effect/turf_decal/tile/yellow{ - dir = 8 - }, -/obj/effect/turf_decal/tile/yellow, /turf/open/floor/plasteel, /area/engine/engineering) "ZC" = ( @@ -2170,7 +2155,7 @@ iD MP MP MP -ij +MP yX qn qn @@ -2251,11 +2236,11 @@ ME QS uB Ok -Ok -Ok +di +di Ok Bz -Zu +lI Wc Ok zG @@ -2307,8 +2292,8 @@ iP wk go fF -EI -EI +UT +UT sn qc Nh @@ -2367,7 +2352,7 @@ KA KA Ok dZ -bO +Zu ev tl qb @@ -2477,7 +2462,7 @@ IP Zs sD Jd -EL +YP YG AX PK @@ -2505,7 +2490,7 @@ SX ou vG Zv -di +Xe qJ Lw Xe @@ -2595,7 +2580,7 @@ PK Dv Dv bO -YP +sH As yN yN @@ -2651,7 +2636,7 @@ eh zx XW ST -Ok +Fs MP tw tw diff --git a/_maps/map_files/BoxStation/BoxStation.dmm b/_maps/map_files/BoxStation/BoxStation.dmm index f9ff2a594c..c0b4e6a88a 100644 --- a/_maps/map_files/BoxStation/BoxStation.dmm +++ b/_maps/map_files/BoxStation/BoxStation.dmm @@ -1257,6 +1257,16 @@ /turf/open/floor/plating, /area/maintenance/fore/secondary) "acV" = ( +/obj/structure/cable{ + icon_state = "1-4" + }, +/obj/structure/cable{ + icon_state = "2-4" + }, +/obj/structure/lattice/catwalk, +/turf/open/space, +/area/solar/port/fore) +"acW" = ( /obj/structure/cable{ icon_state = "0-2" }, @@ -1266,11 +1276,6 @@ }, /turf/open/floor/plasteel/airless/solarpanel, /area/solar/port/fore) -"acW" = ( -/obj/structure/cable, -/obj/structure/lattice/catwalk, -/turf/open/space, -/area/solar/port/fore) "acX" = ( /obj/effect/spawner/structure/window/reinforced, /obj/machinery/atmospherics/pipe/simple/supply/hidden, @@ -1489,7 +1494,12 @@ /obj/structure/lattice/catwalk, /turf/open/space, /area/solar/starboard/fore) -"adu" = ( +"adw" = ( +/obj/structure/cable, +/obj/structure/lattice/catwalk, +/turf/open/space, +/area/solar/port/fore) +"adx" = ( /obj/structure/cable{ icon_state = "4-8" }, @@ -1502,56 +1512,17 @@ /obj/structure/lattice/catwalk, /turf/open/space, /area/solar/port/fore) -"adv" = ( -/obj/structure/cable{ - icon_state = "1-4" - }, -/obj/structure/cable{ - icon_state = "2-4" - }, -/obj/structure/lattice/catwalk, -/turf/open/space, -/area/solar/port/fore) -"adw" = ( -/obj/structure/cable{ - icon_state = "0-8" - }, -/obj/structure/lattice/catwalk, -/turf/open/space, -/area/solar/port/fore) -"adx" = ( -/obj/structure/cable{ - icon_state = "0-4" - }, -/obj/structure/lattice/catwalk, -/turf/open/space, -/area/solar/port/fore) "ady" = ( /obj/structure/lattice/catwalk, /turf/open/space, /area/solar/port/fore) -"adz" = ( -/obj/structure/cable{ - icon_state = "4-8" - }, -/obj/structure/cable{ - icon_state = "2-8" - }, -/obj/structure/cable{ - icon_state = "1-8" - }, -/obj/structure/lattice/catwalk, -/turf/open/space, -/area/solar/port/fore) "adA" = ( -/obj/structure/cable{ - icon_state = "2-8" +/obj/structure/cable, +/obj/machinery/power/solar{ + id = "auxsolareast"; + name = "Port Auxiliary Solar Array" }, -/obj/structure/cable{ - icon_state = "1-8" - }, -/obj/structure/lattice/catwalk, -/turf/open/space, +/turf/open/floor/plasteel/airless/solarpanel, /area/solar/port/fore) "adB" = ( /obj/structure/cable{ @@ -1817,12 +1788,11 @@ /turf/open/space, /area/solar/starboard/fore) "adZ" = ( -/obj/structure/cable, -/obj/machinery/power/solar{ - id = "auxsolareast"; - name = "Port Auxiliary Solar Array" +/obj/structure/cable{ + icon_state = "0-8" }, -/turf/open/floor/plasteel/airless/solarpanel, +/obj/structure/lattice/catwalk, +/turf/open/space, /area/solar/port/fore) "aea" = ( /obj/machinery/portable_atmospherics/canister/nitrous_oxide, @@ -4879,6 +4849,10 @@ dir = 4 }, /obj/machinery/holopad, +/obj/machinery/door/poddoor/shutters/preopen{ + id = "hopqueue"; + name = "HoP Queue Shutters" + }, /turf/open/floor/plasteel, /area/hallway/primary/central) "aiW" = ( @@ -5050,12 +5024,16 @@ /turf/open/floor/plasteel/dark, /area/security/courtroom) "ajq" = ( -/obj/structure/lattice/catwalk, +/obj/machinery/door/airlock/external{ + name = "Solar Maintenance"; + req_access_txt = "10; 13" + }, /obj/structure/cable{ icon_state = "1-2" }, -/turf/open/space, -/area/solar/port/fore) +/obj/effect/mapping_helpers/airlock/cyclelink_helper, +/turf/open/floor/plating, +/area/maintenance/solars/port/fore) "ajr" = ( /obj/structure/table/wood, /obj/machinery/atmospherics/pipe/simple/supply/hidden, @@ -5413,16 +5391,12 @@ /turf/open/floor/plating, /area/maintenance/solars/port/fore) "ajW" = ( -/obj/machinery/door/airlock/external{ - name = "Solar Maintenance"; - req_access_txt = "10; 13" - }, /obj/structure/cable{ - icon_state = "1-2" + icon_state = "0-4" }, -/obj/effect/mapping_helpers/airlock/cyclelink_helper, -/turf/open/floor/plating, -/area/maintenance/solars/port/fore) +/obj/structure/lattice/catwalk, +/turf/open/space, +/area/solar/port/fore) "ajX" = ( /obj/machinery/atmospherics/pipe/simple/supply/hidden{ dir = 4 @@ -6467,6 +6441,12 @@ }, /turf/open/floor/plasteel/white, /area/science/xenobiology) +"alX" = ( +/obj/structure/disposalpipe/segment{ + dir = 6 + }, +/turf/open/floor/plasteel/white, +/area/medical/chemistry) "alY" = ( /obj/structure/cable{ icon_state = "1-2" @@ -6658,15 +6638,17 @@ /area/security/courtroom) "amv" = ( /obj/structure/cable{ - icon_state = "1-2" + icon_state = "4-8" }, -/obj/effect/mapping_helpers/airlock/cyclelink_helper, -/obj/machinery/door/airlock/external{ - name = "Solar Maintenance"; - req_access_txt = "10; 13" +/obj/structure/cable{ + icon_state = "2-8" }, -/turf/open/floor/plating, -/area/maintenance/solars/starboard/fore) +/obj/structure/cable{ + icon_state = "1-8" + }, +/obj/structure/lattice/catwalk, +/turf/open/space, +/area/solar/port/fore) "amw" = ( /obj/effect/spawner/structure/window/reinforced, /turf/open/floor/plating, @@ -8069,6 +8051,13 @@ }, /turf/open/floor/plasteel/showroomfloor, /area/security/warden) +"apI" = ( +/obj/structure/disposalpipe/segment{ + dir = 6 + }, +/obj/structure/closet/secure_closet/medical1, +/turf/open/floor/plasteel/white, +/area/medical/medbay/central) "apJ" = ( /turf/closed/wall, /area/construction/mining/aux_base) @@ -8555,13 +8544,15 @@ /turf/open/floor/plasteel, /area/security/processing) "aqJ" = ( -/obj/effect/mapping_helpers/airlock/cyclelink_helper, -/obj/machinery/door/airlock/external{ - name = "External Access"; - req_access_txt = "13" +/obj/structure/cable{ + icon_state = "2-8" }, -/turf/open/floor/plating, -/area/maintenance/port/fore) +/obj/structure/cable{ + icon_state = "1-8" + }, +/obj/structure/lattice/catwalk, +/turf/open/space, +/area/solar/port/fore) "aqK" = ( /obj/structure/chair/stool, /turf/open/floor/plasteel, @@ -9381,6 +9372,13 @@ /obj/effect/spawner/structure/window/reinforced, /turf/open/floor/plating, /area/construction/mining/aux_base) +"asG" = ( +/obj/structure/disposalpipe/trunk{ + dir = 1 + }, +/obj/machinery/disposal/bin, +/turf/open/floor/plasteel/white, +/area/medical/medbay/central) "asH" = ( /obj/structure/closet/toolcloset, /obj/effect/turf_decal/tile/yellow{ @@ -9424,6 +9422,35 @@ }, /turf/open/floor/plating, /area/maintenance/port/fore) +"asL" = ( +/obj/machinery/light{ + dir = 8 + }, +/obj/machinery/firealarm{ + dir = 4; + pixel_x = -24 + }, +/obj/item/reagent_containers/spray/cleaner, +/obj/item/crowbar, +/obj/item/clothing/neck/stethoscope, +/obj/item/storage/box/gloves{ + pixel_x = 3; + pixel_y = 4 + }, +/obj/item/storage/box/masks, +/obj/structure/table, +/turf/open/floor/plasteel/white, +/area/medical/sleeper) +"asM" = ( +/obj/structure/table, +/obj/item/crowbar, +/obj/item/clothing/neck/stethoscope, +/obj/item/reagent_containers/spray/cleaner, +/obj/structure/sign/warning/nosmoking{ + pixel_y = 30 + }, +/turf/open/floor/plasteel/dark, +/area/medical/sleeper) "asN" = ( /obj/machinery/airalarm{ dir = 4; @@ -9453,12 +9480,66 @@ /obj/structure/closet/firecloset, /turf/open/floor/plating, /area/maintenance/fore) +"asT" = ( +/obj/machinery/atmospherics/pipe/simple/supply/hidden{ + dir = 4 + }, +/obj/effect/turf_decal/tile/blue, +/obj/effect/turf_decal/tile/blue{ + dir = 4 + }, +/turf/open/floor/plasteel, +/area/medical/medbay/central) +"asU" = ( +/obj/structure/sign/warning/nosmoking{ + pixel_y = 30 + }, +/obj/machinery/atmospherics/pipe/simple/supply/hidden{ + dir = 4 + }, +/obj/effect/turf_decal/tile/yellow{ + dir = 4 + }, +/obj/machinery/door/airlock/medical/glass{ + id_tag = "MedbayFoyer"; + name = "Medbay"; + req_access_txt = "5" + }, +/turf/open/floor/plasteel/white, +/area/medical/medbay/central) +"asV" = ( +/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ + dir = 4 + }, +/obj/effect/turf_decal/tile/blue, +/obj/effect/turf_decal/tile/blue{ + dir = 4 + }, +/turf/open/floor/plasteel, +/area/medical/medbay/central) "asW" = ( /obj/machinery/light/small{ dir = 8 }, /turf/open/floor/plasteel/grimy, /area/security/detectives_office) +"asX" = ( +/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ + dir = 4 + }, +/obj/machinery/door/airlock/medical/glass{ + id_tag = "MedbayFoyer"; + name = "Medbay"; + req_access_txt = "5" + }, +/turf/open/floor/plasteel/white, +/area/medical/medbay/central) +"asY" = ( +/obj/structure/sign/warning/nosmoking{ + pixel_y = 30 + }, +/turf/open/floor/plasteel, +/area/hallway/primary/central) "ata" = ( /turf/open/floor/wood, /area/lawoffice) @@ -24467,12 +24548,6 @@ /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, /turf/closed/wall/r_wall, /area/engine/gravity_generator) -"bgP" = ( -/obj/structure/disposalpipe/segment{ - dir = 6 - }, -/turf/open/floor/plasteel/white, -/area/medical/chemistry) "bgQ" = ( /obj/machinery/atmospherics/components/unary/vent_scrubber/on{ dir = 8 @@ -28210,12 +28285,6 @@ /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, /turf/open/floor/plasteel/white, /area/medical/medbay/central) -"bpy" = ( -/obj/structure/disposalpipe/segment{ - dir = 6 - }, -/turf/open/floor/plasteel/white, -/area/medical/medbay/central) "bpz" = ( /obj/machinery/atmospherics/components/unary/vent_scrubber/on{ dir = 8 @@ -28704,13 +28773,6 @@ /obj/structure/disposalpipe/segment, /turf/open/floor/plasteel, /area/hallway/primary/central) -"bqM" = ( -/obj/effect/spawner/structure/window/reinforced, -/obj/machinery/atmospherics/pipe/simple/supply/hidden{ - dir = 4 - }, -/turf/open/floor/plating, -/area/medical/medbay/central) "bqN" = ( /obj/machinery/atmospherics/pipe/simple/supply/hidden{ dir = 5 @@ -28743,22 +28805,6 @@ }, /turf/open/floor/plasteel/white, /area/medical/medbay/central) -"bqR" = ( -/obj/structure/table, -/obj/item/crowbar, -/obj/item/clothing/neck/stethoscope, -/obj/item/reagent_containers/spray/cleaner, -/obj/structure/sign/warning/nosmoking{ - pixel_y = 30 - }, -/obj/machinery/atmospherics/pipe/simple/supply/hidden{ - dir = 4 - }, -/obj/effect/turf_decal/tile/yellow{ - dir = 4 - }, -/turf/open/floor/plasteel/white, -/area/medical/medbay/central) "bqS" = ( /obj/structure/cable{ icon_state = "4-8" @@ -29261,13 +29307,6 @@ /obj/effect/spawner/structure/window/reinforced, /turf/open/floor/plating, /area/crew_quarters/heads/hop) -"brV" = ( -/obj/effect/spawner/structure/window/reinforced, -/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ - dir = 4 - }, -/turf/open/floor/plating, -/area/medical/medbay/central) "brW" = ( /obj/structure/cable{ icon_state = "4-8" @@ -29275,18 +29314,6 @@ /obj/machinery/vending/cart, /turf/open/floor/plasteel, /area/crew_quarters/heads/hop) -"brX" = ( -/obj/structure/table, -/obj/item/storage/box/masks, -/obj/item/storage/box/gloves{ - pixel_x = 3; - pixel_y = 4 - }, -/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ - dir = 4 - }, -/turf/open/floor/plasteel/white, -/area/medical/medbay/central) "brY" = ( /obj/structure/disposalpipe/segment{ dir = 6 @@ -31211,23 +31238,10 @@ /obj/effect/turf_decal/delivery, /turf/open/floor/plasteel, /area/medical/medbay/central) -"bwy" = ( -/obj/structure/disposalpipe/segment{ - dir = 5 - }, -/turf/open/floor/plasteel/white, -/area/medical/medbay/central) "bwz" = ( /obj/structure/disposalpipe/segment, /turf/open/floor/plasteel/white, /area/medical/medbay/central) -"bwA" = ( -/obj/machinery/disposal/bin, -/obj/structure/disposalpipe/trunk{ - dir = 8 - }, -/turf/open/floor/plasteel/white, -/area/medical/medbay/central) "bwB" = ( /obj/structure/chair, /obj/machinery/atmospherics/components/unary/vent_scrubber/on{ @@ -32967,17 +32981,6 @@ }, /turf/open/floor/plating, /area/maintenance/port/aft) -"bAp" = ( -/obj/structure/closet/secure_closet/medical1, -/obj/machinery/light{ - dir = 8 - }, -/obj/machinery/firealarm{ - dir = 4; - pixel_x = -24 - }, -/turf/open/floor/plasteel/white, -/area/medical/sleeper) "bAq" = ( /obj/machinery/sleeper{ dir = 8 @@ -42316,15 +42319,9 @@ /turf/open/floor/plasteel, /area/science/circuit) "bXv" = ( -/obj/effect/mapping_helpers/airlock/cyclelink_helper{ - dir = 4 - }, -/obj/machinery/door/airlock/external{ - name = "External Access"; - req_access_txt = "13" - }, -/turf/open/floor/plating, -/area/maintenance/port/aft) +/obj/item/stack/rods, +/turf/open/space, +/area/space) "bXw" = ( /obj/machinery/atmospherics/pipe/simple/scrubbers/visible, /turf/open/floor/plasteel, @@ -45038,7 +45035,7 @@ dir = 4 }, /turf/closed/wall/r_wall, -/area/engine/engineering) +/area/engine/atmos) "cez" = ( /obj/machinery/atmospherics/pipe/simple/cyan/visible, /turf/open/floor/plasteel, @@ -45492,9 +45489,12 @@ /turf/open/floor/plasteel, /area/engine/engineering) "cfK" = ( -/obj/structure/sign/warning/securearea, -/turf/closed/wall, -/area/engine/engineering) +/obj/structure/lattice/catwalk, +/obj/structure/cable{ + icon_state = "0-2" + }, +/turf/open/space, +/area/solar/port/fore) "cfL" = ( /obj/machinery/firealarm{ pixel_y = 24 @@ -46294,18 +46294,11 @@ /turf/open/floor/plating, /area/maintenance/solars/port/aft) "chO" = ( -/obj/structure/cable{ - icon_state = "4-8" - }, -/obj/effect/mapping_helpers/airlock/cyclelink_helper{ - dir = 4 - }, /obj/machinery/door/airlock/external{ - name = "Solar Maintenance"; - req_access_txt = "10; 13" + req_access_txt = "13" }, /turf/open/floor/plating, -/area/maintenance/solars/port/aft) +/area/maintenance/fore/secondary) "chP" = ( /obj/structure/cable{ icon_state = "4-8" @@ -49323,15 +49316,16 @@ /turf/open/space, /area/maintenance/aft) "csg" = ( -/obj/effect/mapping_helpers/airlock/cyclelink_helper{ - dir = 1 +/obj/structure/cable{ + icon_state = "1-2" }, +/obj/effect/mapping_helpers/airlock/cyclelink_helper, /obj/machinery/door/airlock/external{ - name = "Engineering External Access"; - req_access_txt = "10;13" + name = "Solar Maintenance"; + req_access_txt = "10; 13" }, /turf/open/floor/plating, -/area/engine/engineering) +/area/maintenance/solars/starboard/fore) "csi" = ( /obj/structure/transit_tube/curved/flipped{ dir = 1 @@ -51124,13 +51118,10 @@ /turf/open/floor/plasteel, /area/security/processing) "cxW" = ( -/obj/effect/mapping_helpers/airlock/cyclelink_helper, -/obj/machinery/door/airlock/external{ - name = "External Access"; - req_access_txt = "13" - }, -/turf/open/floor/plating, -/area/maintenance/starboard/fore) +/obj/structure/lattice, +/obj/structure/lattice/catwalk, +/turf/open/space, +/area/space/nearstation) "cxY" = ( /obj/machinery/camera{ c_tag = "Arrivals Escape Pod 1"; @@ -51229,14 +51220,13 @@ /turf/open/floor/plating, /area/hallway/secondary/entry) "cyC" = ( -/obj/effect/mapping_helpers/airlock/cyclelink_helper{ - dir = 8 - }, +/obj/effect/mapping_helpers/airlock/cyclelink_helper, /obj/machinery/door/airlock/external{ + name = "External Access"; req_access_txt = "13" }, /turf/open/floor/plating, -/area/maintenance/starboard) +/area/maintenance/port/fore) "cyD" = ( /obj/effect/mapping_helpers/airlock/cyclelink_helper{ dir = 8 @@ -51258,15 +51248,13 @@ /turf/open/floor/plating, /area/maintenance/port/aft) "cyG" = ( -/obj/effect/mapping_helpers/airlock/cyclelink_helper{ - dir = 8 - }, +/obj/effect/mapping_helpers/airlock/cyclelink_helper, /obj/machinery/door/airlock/external{ - name = "Atmospherics External Airlock"; - req_access_txt = "24" + name = "External Access"; + req_access_txt = "13" }, /turf/open/floor/plating, -/area/engine/atmos) +/area/maintenance/starboard/fore) "cyK" = ( /obj/structure/cable{ icon_state = "4-8" @@ -51312,18 +51300,14 @@ /turf/open/space/basic, /area/space) "cyU" = ( -/obj/structure/cable{ - icon_state = "1-2" - }, /obj/effect/mapping_helpers/airlock/cyclelink_helper{ - dir = 1 + dir = 8 }, /obj/machinery/door/airlock/external{ - name = "Solar Maintenance"; - req_access_txt = "10; 13" + req_access_txt = "13" }, /turf/open/floor/plating, -/area/maintenance/solars/starboard/aft) +/area/maintenance/starboard) "czg" = ( /obj/effect/mapping_helpers/airlock/cyclelink_helper{ dir = 8 @@ -52229,10 +52213,9 @@ /turf/open/space, /area/space/nearstation) "cCS" = ( -/obj/machinery/atmospherics/pipe/simple/orange/visible, /obj/structure/lattice, -/turf/open/space, -/area/space/nearstation) +/turf/closed/wall/r_wall, +/area/engine/atmos) "cCT" = ( /obj/machinery/atmospherics/components/unary/vent_pump/on{ dir = 4 @@ -52299,12 +52282,15 @@ /turf/closed/wall, /area/engine/engineering) "cDY" = ( -/obj/structure/lattice, -/obj/machinery/atmospherics/pipe/simple/orange/visible{ - dir = 9 +/obj/effect/mapping_helpers/airlock/cyclelink_helper{ + dir = 4 }, -/turf/open/space, -/area/space/nearstation) +/obj/machinery/door/airlock/external{ + name = "External Access"; + req_access_txt = "13" + }, +/turf/open/floor/plating, +/area/maintenance/port/aft) "cDZ" = ( /obj/structure/cable{ icon_state = "1-2" @@ -53583,6 +53569,11 @@ dir = 8 }, /area/crew_quarters/fitness/pool) +"dCt" = ( +/obj/machinery/atmospherics/pipe/simple/orange/visible, +/obj/structure/lattice, +/turf/open/space, +/area/space/nearstation) "dCV" = ( /obj/structure/cable{ icon_state = "1-4" @@ -54251,6 +54242,12 @@ }, /turf/open/floor/plasteel, /area/security/range) +"fty" = ( +/obj/structure/lattice, +/obj/machinery/atmospherics/pipe/simple/orange/visible, +/obj/structure/lattice, +/turf/open/space, +/area/space/nearstation) "ftE" = ( /obj/item/radio/intercom{ pixel_y = 25 @@ -54809,10 +54806,6 @@ dir = 8 }, /area/medical/sleeper) -"haL" = ( -/obj/structure/lattice, -/turf/open/space/basic, -/area/space) "haM" = ( /obj/item/radio/intercom{ name = "Station Intercom (General)"; @@ -55093,6 +55086,13 @@ }, /turf/open/floor/plasteel, /area/hallway/primary/starboard) +"imk" = ( +/obj/structure/lattice, +/obj/machinery/atmospherics/pipe/simple/orange/visible{ + dir = 9 + }, +/turf/open/space/basic, +/area/space/nearstation) "imH" = ( /obj/structure/falsewall, /turf/open/floor/plating, @@ -55388,6 +55388,10 @@ }, /turf/open/floor/wood, /area/crew_quarters/bar) +"jiK" = ( +/obj/structure/sign/warning/securearea, +/turf/closed/wall, +/area/engine/engineering) "jjC" = ( /obj/structure/table/wood, /obj/item/toy/cards/deck, @@ -55994,6 +55998,10 @@ }, /turf/open/floor/plasteel, /area/crew_quarters/theatre) +"kEm" = ( +/mob/living/simple_animal/opossum/poppy, +/turf/open/floor/plating, +/area/maintenance/port/aft) "kEY" = ( /obj/effect/landmark/stationroom/box/engine, /turf/open/space/basic, @@ -56556,7 +56564,6 @@ }, /area/maintenance/bar) "mqZ" = ( -/obj/structure/reagent_dispensers/keg/aphro/strong, /obj/item/reagent_containers/glass/beaker, /turf/open/floor/plating, /area/maintenance/bar) @@ -56697,6 +56704,19 @@ /obj/structure/table/wood, /turf/open/floor/wood, /area/maintenance/bar) +"mQp" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/effect/mapping_helpers/airlock/cyclelink_helper{ + dir = 1 + }, +/obj/machinery/door/airlock/external{ + name = "Solar Maintenance"; + req_access_txt = "10; 13" + }, +/turf/open/floor/plating, +/area/maintenance/solars/starboard/aft) "mQS" = ( /obj/machinery/light{ dir = 8; @@ -58122,6 +58142,10 @@ /obj/effect/decal/cleanable/blood/old, /turf/open/floor/plating, /area/maintenance/fore) +"rtU" = ( +/mob/living/simple_animal/opossum, +/turf/open/floor/plating, +/area/maintenance/starboard/fore) "ruo" = ( /obj/structure/cable{ icon_state = "4-8" @@ -58822,14 +58846,10 @@ /turf/open/floor/plasteel, /area/crew_quarters/fitness/pool) "tAH" = ( -/obj/machinery/door/airlock/external{ - req_access_txt = "13" - }, -/obj/effect/mapping_helpers/airlock/cyclelink_helper{ - dir = 8 - }, -/turf/open/floor/plating, -/area/maintenance/fore/secondary) +/obj/machinery/atmospherics/pipe/simple/orange/visible, +/obj/structure/lattice, +/turf/open/space/basic, +/area/space/nearstation) "tCa" = ( /obj/structure/table/wood, /obj/item/instrument/guitar{ @@ -58852,6 +58872,19 @@ }, /turf/open/floor/plasteel/white, /area/medical/medbay/central) +"tEK" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/effect/mapping_helpers/airlock/cyclelink_helper{ + dir = 4 + }, +/obj/machinery/door/airlock/external{ + name = "Solar Maintenance"; + req_access_txt = "10; 13" + }, +/turf/open/floor/plating, +/area/maintenance/solars/port/aft) "tHh" = ( /obj/machinery/disposal/bin, /obj/effect/turf_decal/tile/red, @@ -59222,7 +59255,7 @@ "uDO" = ( /obj/structure/lattice/catwalk, /obj/structure/cable{ - icon_state = "0-2" + icon_state = "1-2" }, /turf/open/space, /area/solar/port/fore) @@ -59966,6 +59999,16 @@ /obj/machinery/holopad, /turf/open/floor/plasteel/showroomfloor, /area/security/main) +"wmu" = ( +/obj/effect/mapping_helpers/airlock/cyclelink_helper{ + dir = 1 + }, +/obj/machinery/door/airlock/external{ + name = "Engineering External Access"; + req_access_txt = "10;13" + }, +/turf/open/floor/plating, +/area/engine/engineering) "woR" = ( /obj/machinery/cryopod{ dir = 1 @@ -60125,6 +60168,16 @@ /obj/item/hand_labeler, /turf/open/floor/plasteel, /area/hallway/secondary/service) +"wWi" = ( +/obj/effect/mapping_helpers/airlock/cyclelink_helper{ + dir = 8 + }, +/obj/machinery/door/airlock/external{ + name = "Atmospherics External Airlock"; + req_access_txt = "24" + }, +/turf/open/floor/plating, +/area/engine/atmos) "wWT" = ( /obj/effect/landmark/start/roboticist, /turf/open/floor/plasteel/white, @@ -67515,7 +67568,7 @@ gXs gXs gJi gJi -haL +gXs aag gJi aaa @@ -68269,7 +68322,7 @@ aaa aaa aaa aae -ktS +aaa gXs aaa aaa @@ -68526,7 +68579,7 @@ aaa aaa aaa aaa -ktS +aaa gXs aaa aaa @@ -68783,7 +68836,7 @@ aaa aaa aaa aaa -ktS +aaa gXs aaa aaa @@ -69040,7 +69093,7 @@ aaa aaa aaa aaa -ktS +aaa gXs aaa cqq @@ -69297,7 +69350,7 @@ aaf aaf aaf aaa -ktS +aaa arB asE cyb @@ -73659,11 +73712,11 @@ aaa aae aaa aaa -aaa aag alU alU alU +alU aCW amC asK @@ -73916,9 +73969,9 @@ aaa aaa aaa aaa -aaa aag -aqJ +cyC +amC amC gLH ase @@ -74173,7 +74226,7 @@ aaa aaa aaa aaa -aaa +gJi alU alU alU @@ -74922,7 +74975,6 @@ aaa aaa aaa aaa -aaa aaS aaS aaS @@ -74941,6 +74993,7 @@ aaS aaf aaf aaf +aaf aaa aaa aaa @@ -75179,7 +75232,6 @@ aaa aaa aaa aaa -aaa abY aaa aaf @@ -75192,7 +75244,7 @@ acy aaa aaf aaa -aiS +bXv aaa aaS aaa @@ -75201,6 +75253,7 @@ aaa aaa aaa aaa +aaa alU aoR apO @@ -75436,25 +75489,25 @@ aaa aaa aaa aaa -aaa abY aaa +acW acV -adv -adZ +adA aaa +acW acV -adv -adZ +adA aaa +acW acV -adv -adZ +adA aaa aaS aaf aaf aaf +aaf aaa aaa aaa @@ -75690,23 +75743,22 @@ aaa aaa aaa aaa -aaa aae aaa aaa abY aaf -acV -adu -adZ +acW +adx +adA aaa -acV -adu -adZ +acW +adx +adA aaa -acV -adu -adZ +acW +adx +adA aaf aaf aaa @@ -75715,6 +75767,7 @@ aaa aaa aaa aaa +aaa alU alU alU @@ -75950,20 +76003,19 @@ aaa aaa aaa aaa -aaa abY aaa -acV -adu -adZ +acW +adx +adA aaf -acV -adu -adZ +acW +adx +adA aaf -acV -adu -adZ +acW +adx +adA aaa aaf aaa @@ -75972,6 +76024,7 @@ aaa aaa aaa aaa +aaa aaf aaa ali @@ -76207,20 +76260,20 @@ aaa aaa aaa aaa -aaa aaf aaf -acV -adu -adZ +acW +adx +adA aaa -acV -adu -adZ +acW +adx +adA aaa -acV -adu -adZ +acW +adx +adA +aaf aaf aaf aaf @@ -76461,26 +76514,26 @@ aaa aaa aaa aaa -aaa aaS aaS aaS aaf aaa -acV -adu -adZ +acW +adx +adA aaa -acV -adu -adZ +acW +adx +adA aaa -acV -adu -adZ +acW +adx +adA aaa aaf aaa +aaa ajV alR alR @@ -76718,27 +76771,27 @@ aaa aaa aaa aaa -aaa aaS aaa aaf aaa aaa aaa -adw +adZ aaa aaa aaa -adw +adZ aaa aaa aaa -adw +adZ aaa aaa ajV ajV ajV +ajV alQ amy ang @@ -76975,13 +77028,12 @@ aaa aaa aaa aaa -aaa aaS aaf abs abZ abZ -acW +adw ady ady ady @@ -76991,9 +77043,10 @@ ady ady ady ady +cfK uDO ajq -ajW +akB akB alh alT @@ -77232,27 +77285,27 @@ aaa aaa aaa aaa -aaa aaS aaa aaf aaa aaa aaa -adx +ajW aaa aaa aaa -adx +ajW aaa aaa aaa -adx +ajW aaa aaa ajV ajV ajV +ajV alS amz anh @@ -77489,26 +77542,26 @@ aaa aaa aaa aaa -aaa aaS aba aaS aaf aaa -acV -adz -adZ +acW +amv +adA aaa -acV -adz -adZ +acW +amv +adA aaa -acV -adz -adZ +acW +amv +adA aaa aaf aaa +aaa ajV alR alR @@ -77749,22 +77802,22 @@ aaa aaa aaa aaa +aaf +aaf +acW +amv +adA aaa -aaf -aaf -acV -adz -adZ +acW +amv +adA aaa -acV -adz -adZ +acW +amv +adA +aaf +aaf aaa -acV -adz -adZ -aaf -aaf aaa aaa aaa @@ -78006,24 +78059,24 @@ aaa aaa aaa aaa -aaa aaS aaa -acV -adz -adZ +acW +amv +adA aaf -acV -adz -adZ +acW +amv +adA aaf -acV -adz -adZ +acW +amv +adA aaa aaf aaf aaf +aaf gXs alU alF @@ -78263,25 +78316,25 @@ aaa aaa aaa aaa -aaa aaS aaf -acV -adz -adZ +acW +amv +adA aaa -acV -adz -adZ +acW +amv +adA aaa -acV -adz -adZ +acW +amv +adA aaf aaf aaa aaa aaa +aaa alU alU ank @@ -78520,22 +78573,22 @@ aaa aaa aaa aaa +aaS +aaa +acW +aqJ +adA +aaa +acW +aqJ +adA +aaa +acW +aqJ +adA aaa aaS aaa -acV -adA -adZ -aaa -acV -adA -adZ -aaa -acV -adA -adZ -aaa -aaS aaa aaa aaa @@ -78622,9 +78675,9 @@ aaf aaa aaf aaa -aaa +aaf hrF -aaa +aaf aaa aaf aaa @@ -78777,7 +78830,6 @@ aaa aaa aaa aaa -aaa aaS aaa aaf @@ -78795,6 +78847,7 @@ aaa aaS aaf aaf +aaf gXs alU amC @@ -78879,9 +78932,9 @@ aaf aaf aaf aaf -aaf -hrF -aaf +cfx +tEK +cfx aaf aaf aaf @@ -79034,7 +79087,6 @@ aaa aaa aaa aaa -aaa aaS aaS aaS @@ -79053,6 +79105,7 @@ aaS aaa aaa aaa +aaa alU amE ann @@ -79137,7 +79190,7 @@ aaf aaa aaa cfx -chO +chN cfx aaa aaf @@ -79385,8 +79438,8 @@ caf aoV aag aaf -aaa -aaa +gXs +gXs aaf aaa aaa @@ -79639,9 +79692,9 @@ bLv bCq aoV cbj -aoV -aag -aaf +bLv +cDY +bLv aaf bCq bCq @@ -79897,7 +79950,7 @@ bCq bCq cbj bLv -bXv +bHE bLv aaf bCq @@ -79913,7 +79966,7 @@ ciQ cfw aaa aaa -aaa +gXs aaf aaf aaa @@ -80168,9 +80221,9 @@ cgC chR ciS cfw -aaa -aaa -aaa +aag +aag +aag aaa aaf aaf @@ -80425,9 +80478,9 @@ cgB chQ ciR cfw -aag -aag -aag +bCq +cDY +bCq aaa aaa aaf @@ -80683,7 +80736,7 @@ chS cfw cfw bCq -bXv +bHE bCq aaa aaa @@ -85306,7 +85359,7 @@ bVI bTA xgk bHE -bHE +kEm bHE bHE bHE @@ -90179,7 +90232,7 @@ bUE bWM bXJ bMK -bMK +bYH bYH bYH bVg @@ -92212,7 +92265,7 @@ btJ buV bws bqH -aJq +asY aJq byW bCv @@ -92495,10 +92548,10 @@ bWQ bWQ caD bWQ -ccw -ccw +bLK +bLK cey -ccw +bLK ccw ccw ccw @@ -92774,14 +92827,14 @@ ckF cpE cjR crW -csg +ciZ +wmu aag aaa aaa aaa aaa aaa -aaa ctv ctv ctv @@ -93031,14 +93084,14 @@ crw cjO ccw crX -cfK +ciZ +jiK aag aaa aaa aaa aaa aaa -aaa aaT aaT aaT @@ -93289,7 +93342,7 @@ cjm ccw ccw cig -aag +cig aag aag aag @@ -94263,8 +94316,8 @@ bfF bfF bfF bfF -bqM -brV +asT +asV bof bwv bvj @@ -94520,8 +94573,8 @@ bmF bob bnB bfF -bqR -brX +asU +asX bof bwx bvj @@ -94967,10 +95020,10 @@ aaa aaa aaa aaa -aaa acw abp abp +abp adR abp lJC @@ -95028,7 +95081,7 @@ aYV bfF bhc bip -bgP +alX bjL bkL bmT @@ -95223,10 +95276,10 @@ aaa aaa aaa aaa -aaa aaf aag acU +anF adr sXy aeC @@ -95294,7 +95347,7 @@ bpF bqS brY bwz -bwy +asG bvj bza bxb @@ -95481,12 +95534,12 @@ aaa aaa aaa aaa -aaa aag abp abp abp abp +abp mxn abp abp @@ -95550,10 +95603,10 @@ bpt bfF bqV bEe +bhh bBL -bwA bvj -bAl +asM bAl bvh bzS @@ -96009,7 +96062,7 @@ aaa ahn ahn ahn -tAH +anF ahn eMs anG @@ -96068,7 +96121,7 @@ bvh ajv bxN bze -bAp +asL bvh bCG bBd @@ -96265,8 +96318,8 @@ aaa aaa aaa aaa -gJi -gJi +ahn +chO ahn ahn khB @@ -96354,10 +96407,10 @@ bQA bPj bOh cCQ -bLK -cyG -bLK -aoV +cCS +chg +cCS +aaf aoV aoV aaf @@ -96522,8 +96575,8 @@ aaa aaa aaa aaa -aaa -aaa +gJi +gJi dFX wWW dqb @@ -96610,21 +96663,21 @@ cbI ccC cdD bOh -cCG +cCQ cCS +wWi cCS -cCI -cCI -cCI -cCI -cCI -cCI -cCI -cCI -cCI -cCI -cCI -cDY +aaa +aaa +aaa +gXs +aaa +aaa +aaa +aaa +aaa +aaa +cCQ aaf aaf aaf @@ -96867,21 +96920,21 @@ cbH ccB cbH bOh -aaf -aaa -aoV -aaf -aoV -aoV -aoV -aaf -aoV -aoV -aoV -aoV -aoV -aoV -gXs +cCG +tAH +dCt +fty +dCt +dCt +dCt +fty +dCt +dCt +dCt +dCt +dCt +dCt +imk aoV aaa aaa @@ -97125,11 +97178,11 @@ ccD cbH bOh aaf -aaf -aaf -aaf -aaf -aoV +aaa +aaa +aaa +aaa +aaa aoV aaf aoV @@ -98116,7 +98169,7 @@ bjX blp bmO bhi -bpy +apI bwz brg btZ @@ -100388,7 +100441,7 @@ aaa aaa aaa aaa -aaa +gXs aaf aaf alO @@ -100644,8 +100697,8 @@ aaa aaa aaa aaa -aaa -aag +gJi +alO alO arp alO @@ -100901,9 +100954,9 @@ aaa aaa aaa aaa -aaa -aag -cxW +gJi +cyG +anf anf aqv ayf @@ -101158,10 +101211,10 @@ aaf aaf aaf aaf -aaf -aag +cxW alO anf +anf alO mAH jaF @@ -101667,7 +101720,7 @@ aaa aaa aaf aaa -aaa +amw amw amw amw @@ -101924,8 +101977,8 @@ eaR jIs jIs jIs -acx -amv +csg +ane ane cxN aog @@ -102181,7 +102234,7 @@ aaa aaa aaf aaa -aaa +amw amw amw amw @@ -104251,7 +104304,7 @@ anf anf alP alP -anf +rtU alP alP alP @@ -110499,7 +110552,7 @@ cmw cnj cnj cnj -aaa +cnj aaa aaf aaa @@ -110706,7 +110759,7 @@ aaf aaf aaf bky -cyC +btp bns boF bqe @@ -110755,8 +110808,8 @@ clx cmv cnk cnK -cyU -cpi +cnK +mQp cpi cpi cqJ @@ -110961,9 +111014,9 @@ aQE aNa aaa aaf -aaa -aaf -aaa +gXs +bky +cyU bns boF bqe @@ -111013,7 +111066,7 @@ cmx cnj cnj cnj -aaa +cnj aaa aaf aaa @@ -111218,7 +111271,7 @@ afE aNa aaa aaa -aaa +gXs aaf aaa bns @@ -112800,7 +112853,7 @@ aaa aaa aaf cNW -cPI +cOe cNW aaf aaf @@ -113056,9 +113109,9 @@ aaa aaa aaa aaf -aag -aag -aag +cNW +cPI +cNW aaf aaa aaa @@ -113312,11 +113365,11 @@ aaa aaa aaa aaa -aaa -aaa +gXs aag -aaa -aaa +aag +aag +gXs aaa aaa aaa @@ -113571,7 +113624,7 @@ aaa aaa aaa aaa -aaf +aag aaa aaa aaa diff --git a/_maps/map_files/CogStation/CogStation.dmm b/_maps/map_files/CogStation/CogStation.dmm index 182f1a4f27..40a57135fd 100644 --- a/_maps/map_files/CogStation/CogStation.dmm +++ b/_maps/map_files/CogStation/CogStation.dmm @@ -242,13 +242,13 @@ pixel_x = 22 }, /obj/structure/rack, -/obj/item/gun/energy{ +/obj/item/gun/energy/e_gun{ pixel_y = -6 }, -/obj/item/gun/energy{ +/obj/item/gun/energy/e_gun{ pixel_y = -3 }, -/obj/item/gun/energy, +/obj/item/gun/energy/e_gun, /turf/open/floor/plasteel/dark, /area/ai_monitored/security/armory) "aaI" = ( @@ -1848,9 +1848,6 @@ dir = 8 }, /obj/effect/turf_decal/tile/neutral, -/obj/machinery/light_switch{ - pixel_y = -24 - }, /turf/open/floor/plasteel/dark, /area/crew_quarters/observatory) "aez" = ( @@ -2177,6 +2174,9 @@ dir = 4 }, /obj/effect/turf_decal/tile/neutral, +/obj/machinery/light_switch{ + pixel_x = 24 + }, /turf/open/floor/plasteel/dark, /area/crew_quarters/observatory) "afl" = ( @@ -2722,10 +2722,6 @@ dir = 1; pixel_y = -22 }, -/obj/machinery/camera{ - c_tag = "Observatory Viewing Area"; - dir = 4 - }, /obj/machinery/light/small{ dir = 8 }, @@ -3188,6 +3184,9 @@ /obj/machinery/atmospherics/pipe/manifold/cyan/hidden{ dir = 1 }, +/obj/structure/cable{ + icon_state = "4-8" + }, /turf/open/floor/plating, /area/maintenance/starboard/fore) "ahL" = ( @@ -3327,15 +3326,12 @@ /turf/open/floor/plasteel/dark, /area/crew_quarters/observatory) "aif" = ( -/obj/machinery/firealarm{ - pixel_y = 26 - }, -/obj/structure/cable{ - icon_state = "2-4" - }, /obj/machinery/atmospherics/pipe/simple/cyan/hidden{ dir = 4 }, +/obj/structure/cable{ + icon_state = "4-8" + }, /turf/open/floor/plating, /area/maintenance/starboard/fore) "aig" = ( @@ -4483,17 +4479,8 @@ /turf/open/floor/plasteel, /area/hallway/secondary/entry) "akN" = ( -/obj/structure/plasticflaps, -/obj/structure/fans/tiny, -/obj/machinery/door/poddoor/preopen{ - id = "secblock"; - name = "Security Router" - }, -/obj/machinery/conveyor/auto{ - id = "sec" - }, -/turf/open/floor/plating, -/area/router/sec) +/turf/open/space/basic, +/area/router/aux) "akO" = ( /obj/effect/turf_decal/stripes/line{ dir = 8 @@ -6200,12 +6187,20 @@ /turf/open/floor/grass, /area/hydroponics) "aoJ" = ( -/obj/machinery/atmospherics/pipe/simple/supply/visible, -/obj/machinery/space_heater, -/turf/open/floor/plasteel, -/area/engine/engineering{ - name = "Engine Room" - }) +/obj/machinery/firealarm{ + pixel_y = 26 + }, +/obj/structure/cable{ + icon_state = "2-4" + }, +/obj/machinery/atmospherics/pipe/simple/cyan/hidden{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/open/floor/plating, +/area/maintenance/starboard/fore) "aoK" = ( /turf/closed/wall/r_wall, /area/router/service) @@ -6300,7 +6295,7 @@ /obj/machinery/conveyor{ id = "serv_off" }, -/obj/machinery/door/poddoor/preopen{ +/obj/machinery/door/poddoor{ id = "servblock"; name = "Service Router" }, @@ -6309,7 +6304,7 @@ "aoT" = ( /obj/structure/plasticflaps, /obj/structure/fans/tiny, -/obj/machinery/door/poddoor/preopen{ +/obj/machinery/door/poddoor{ id = "servblock"; name = "Service Router" }, @@ -8607,7 +8602,7 @@ /obj/effect/turf_decal/tile/bar{ dir = 1 }, -/obj/item/storage/pill_bottle/dice, +/obj/item/storage/box/dice, /obj/item/toy/cards/deck, /turf/open/floor/plasteel, /area/crew_quarters/bar) @@ -15009,13 +15004,19 @@ /turf/open/floor/plasteel/stairs/medium, /area/hallway/secondary/entry) "aHa" = ( -/obj/structure/disposalpipe/junction/yjunction, -/obj/machinery/atmospherics/pipe/simple/supplymain/hidden{ - dir = 8 +/obj/structure/cable, +/obj/machinery/power/apc{ + areastring = "/area/crew_quarters/locker"; + dir = 8; + name = "Locker Room APC"; + pixel_x = -24 }, /obj/machinery/atmospherics/pipe/simple/orange/hidden, -/turf/open/floor/plasteel, -/area/hallway/primary/port/fore) +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/open/floor/plating, +/area/maintenance/fore) "aHb" = ( /obj/structure/chair, /obj/machinery/firealarm{ @@ -15163,12 +15164,12 @@ /turf/open/floor/plasteel, /area/tcommsat/computer) "aHp" = ( -/obj/structure/disposalpipe/segment{ - dir = 9 +/obj/machinery/atmospherics/pipe/simple/orange/hidden, +/obj/structure/cable{ + icon_state = "1-2" }, -/obj/machinery/atmospherics/pipe/manifold4w/supplymain/hidden, -/turf/open/floor/plasteel, -/area/hallway/primary/port/fore) +/turf/open/floor/plating, +/area/maintenance/fore) "aHq" = ( /obj/effect/turf_decal/bot, /obj/structure/disposalpipe/segment, @@ -15841,12 +15842,16 @@ /turf/open/floor/carpet/royalblue, /area/bridge) "aIJ" = ( -/obj/effect/turf_decal/tile/neutral, -/obj/effect/turf_decal/tile/neutral{ - dir = 8 +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/maintenance{ + name = "Fore Maintenance"; + req_one_access_txt = "12;46" }, -/obj/machinery/atmospherics/pipe/simple/supplymain/hidden, -/turf/open/floor/plasteel, +/obj/machinery/atmospherics/pipe/simple/orange/hidden, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/open/floor/plating, /area/hallway/primary/port/fore) "aIK" = ( /obj/structure/table/wood, @@ -16804,7 +16809,7 @@ /area/bridge) "aKw" = ( /obj/structure/table, -/obj/item/storage/pill_bottle/dice, +/obj/item/storage/box/dice, /obj/item/toy/cards/deck, /obj/structure/disposalpipe/segment{ dir = 4 @@ -17089,13 +17094,22 @@ /turf/open/floor/plating, /area/maintenance/fore) "aLc" = ( -/obj/machinery/door/firedoor, -/obj/machinery/door/airlock/maintenance{ - name = "Central Maintenance"; - req_one_access_txt = "12" +/obj/structure/disposalpipe/segment{ + dir = 4 }, -/obj/machinery/atmospherics/pipe/simple/supplymain/hidden, -/turf/open/floor/plating, +/obj/effect/turf_decal/tile/neutral{ + dir = 1 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/orange/hidden{ + dir = 8 + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/open/floor/plasteel, /area/hallway/primary/port/fore) "aLd" = ( /obj/machinery/atmospherics/pipe/simple/supplymain/hidden, @@ -17721,14 +17735,16 @@ /turf/closed/wall, /area/maintenance/department/chapel) "aMo" = ( -/obj/structure/disposalpipe/segment{ - dir = 6 +/obj/structure/disposalpipe/junction/yjunction, +/obj/machinery/atmospherics/pipe/simple/supplymain/hidden{ + dir = 8 }, +/obj/machinery/atmospherics/pipe/simple/orange/hidden, /obj/structure/cable{ - icon_state = "1-2" + icon_state = "1-4" }, -/turf/open/floor/plating, -/area/maintenance/starboard/central) +/turf/open/floor/plasteel, +/area/hallway/primary/port/fore) "aMp" = ( /obj/effect/landmark/event_spawn, /obj/machinery/atmospherics/pipe/simple/orange/hidden, @@ -17880,18 +17896,15 @@ }, /area/chapel/main) "aMG" = ( -/obj/structure/disposalpipe/segment, +/obj/structure/disposalpipe/segment{ + dir = 9 + }, +/obj/machinery/atmospherics/pipe/manifold4w/supplymain/hidden, /obj/structure/cable{ - icon_state = "1-2" + icon_state = "2-8" }, -/obj/machinery/camera{ - c_tag = "Central Starboard Maintenance"; - dir = 8; - pixel_y = -22 - }, -/mob/living/simple_animal/hostile/retaliate/bat, -/turf/open/floor/plating, -/area/maintenance/starboard/central) +/turf/open/floor/plasteel, +/area/hallway/primary/port/fore) "aMH" = ( /obj/structure/cable{ icon_state = "2-8" @@ -19880,9 +19893,16 @@ /turf/open/floor/plasteel/white, /area/crew_quarters/fitness/cogpool) "aQS" = ( +/obj/effect/turf_decal/tile/neutral, +/obj/effect/turf_decal/tile/neutral{ + dir = 8 + }, /obj/machinery/atmospherics/pipe/simple/supplymain/hidden, -/turf/open/floor/plating, -/area/maintenance/central) +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/open/floor/plasteel, +/area/hallway/primary/port/fore) "aQT" = ( /obj/machinery/door/airlock/engineering{ name = "Thermo-Electric Generator"; @@ -22384,6 +22404,18 @@ /obj/effect/spawner/lootdrop/maintenance, /turf/open/floor/plating, /area/maintenance/department/eva) +"aWr" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/maintenance{ + name = "Central Maintenance"; + req_one_access_txt = "12" + }, +/obj/machinery/atmospherics/pipe/simple/supplymain/hidden, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/open/floor/plating, +/area/hallway/primary/port/fore) "aWs" = ( /obj/machinery/light{ dir = 8; @@ -22411,16 +22443,10 @@ /turf/open/floor/plating, /area/maintenance/central) "aWu" = ( -/obj/structure/cable{ - icon_state = "0-2" - }, -/obj/machinery/power/apc{ - areastring = "/area/crew_quarters/fitness/cogpool"; - dir = 4; - name = "Pool APC"; - pixel_x = 24 - }, /obj/machinery/atmospherics/pipe/simple/supplymain/hidden, +/obj/structure/cable{ + icon_state = "1-2" + }, /turf/open/floor/plating, /area/maintenance/central) "aWv" = ( @@ -22787,9 +22813,9 @@ /turf/open/floor/carpet, /area/library) "aXg" = ( -/obj/structure/bookcase/random/reference, -/turf/open/floor/wood, -/area/library) +/obj/machinery/vending/coffee, +/turf/open/floor/plasteel, +/area/hallway/primary/central) "aXh" = ( /obj/machinery/atmospherics/pipe/simple/supply/visible{ dir = 6 @@ -22837,6 +22863,12 @@ }, /turf/open/floor/plasteel, /area/hallway/primary/central) +"aXm" = ( +/obj/machinery/atmospherics/pipe/manifold/cyan/hidden{ + dir = 1 + }, +/turf/closed/wall/r_wall, +/area/tcommsat/computer) "aXn" = ( /obj/effect/turf_decal/tile/bar, /obj/effect/turf_decal/tile/bar{ @@ -22876,6 +22908,15 @@ "aXr" = ( /turf/open/floor/plasteel, /area/ai_monitored/storage/eva) +"aXs" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/components/unary/vent_pump/on{ + dir = 1 + }, +/turf/open/floor/plating, +/area/tcommsat/computer) "aXt" = ( /obj/effect/spawner/structure/window/reinforced, /obj/structure/sign/warning/securearea, @@ -24424,10 +24465,12 @@ /turf/open/floor/plasteel/dark, /area/security/checkpoint/customs) "baE" = ( -/obj/structure/disposalpipe/segment{ - dir = 9 +/obj/structure/bookcase/random/reference, +/obj/effect/turf_decal/tile/neutral, +/obj/effect/turf_decal/tile/neutral{ + dir = 1 }, -/turf/open/floor/wood, +/turf/open/floor/plasteel/dark, /area/library) "baF" = ( /obj/structure/chair/office/dark{ @@ -24976,18 +25019,21 @@ /turf/open/floor/plating, /area/security/checkpoint/customs) "bbQ" = ( -/obj/structure/sign/warning/vacuum/external{ - pixel_x = -32; - pixel_y = 32 +/obj/structure/cable{ + icon_state = "0-2" }, +/obj/machinery/power/apc{ + areastring = "/area/crew_quarters/fitness/cogpool"; + dir = 4; + name = "Pool APC"; + pixel_x = 24 + }, +/obj/machinery/atmospherics/pipe/simple/supplymain/hidden, /obj/structure/cable{ icon_state = "1-2" }, -/obj/machinery/atmospherics/pipe/simple/supplymain/hidden, -/turf/open/floor/plasteel, -/area/engine/engineering{ - name = "Engine Room" - }) +/turf/open/floor/plating, +/area/maintenance/central) "bbR" = ( /obj/structure/closet/crate/hydroponics, /obj/effect/turf_decal/tile/green, @@ -27393,19 +27439,16 @@ /turf/open/floor/wood, /area/medical/medbay/lobby) "bhy" = ( -/obj/structure/closet/crate/science, -/obj/item/stack/sheet/metal/ten, -/obj/item/stack/sheet/glass/five, -/obj/item/stack/rods/twentyfive, -/obj/item/target/syndicate, -/obj/item/target/alien, -/obj/item/target, -/obj/item/target/clown, -/obj/machinery/atmospherics/pipe/simple/orange/hidden{ - dir = 10 +/obj/structure/plasticflaps, +/obj/structure/fans/tiny, +/obj/machinery/conveyor/auto{ + id = "sec" }, -/turf/open/floor/plasteel, -/area/science/mixing) +/obj/machinery/door/poddoor{ + name = "Security Router" + }, +/turf/open/floor/plating, +/area/router/sec) "bhz" = ( /obj/structure/disposalpipe/segment, /obj/machinery/atmospherics/pipe/simple/supplymain/hidden{ @@ -27774,8 +27817,15 @@ /turf/open/floor/plating, /area/quartermaster/storage) "bim" = ( -/turf/open/space/basic, -/area/space/nearstation) +/obj/effect/decal/cleanable/dirt, +/obj/machinery/button/massdriver{ + id = "router_in"; + name = "mass driver button (Router)"; + pixel_x = 24; + pixel_y = -8 + }, +/turf/open/floor/plating, +/area/maintenance/disposal) "bin" = ( /obj/machinery/computer/mecha{ dir = 4 @@ -30316,6 +30366,18 @@ }, /turf/open/floor/plasteel, /area/science/mixing) +"bnl" = ( +/obj/structure/cable{ + icon_state = "1-4" + }, +/obj/structure/cable{ + icon_state = "2-4" + }, +/obj/machinery/atmospherics/pipe/manifold/cyan/hidden{ + dir = 8 + }, +/turf/open/floor/plating, +/area/maintenance/starboard/central) "bnm" = ( /obj/machinery/atmospherics/pipe/manifold/orange/hidden{ dir = 4 @@ -31910,7 +31972,7 @@ /obj/effect/turf_decal/tile/green{ dir = 4 }, -/obj/item/storage/pill_bottle/dice, +/obj/item/storage/box/dice, /obj/item/toy/cards/deck, /turf/open/floor/plasteel/white/corner{ dir = 1 @@ -33867,9 +33929,18 @@ /area/janitor) "bvb" = ( /obj/structure/disposalpipe/segment, -/obj/effect/landmark/blobstart, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/door/airlock/engineering{ + name = "Electrical Substation"; + req_access_txt = "10" + }, +/obj/structure/fans/tiny, /turf/open/floor/plating, -/area/maintenance/starboard/central) +/area/engine/storage_shared{ + name = "Electrical Substation" + }) "bvc" = ( /obj/machinery/computer/cargo/request, /obj/machinery/airalarm{ @@ -34423,10 +34494,13 @@ /turf/open/floor/plating, /area/maintenance/starboard/central) "bwp" = ( -/obj/structure/disposalpipe/segment, -/obj/structure/cable{ - icon_state = "1-8" +/obj/structure/disposalpipe/segment{ + dir = 6 }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/cyan/hidden, /turf/open/floor/plating, /area/maintenance/starboard/central) "bwq" = ( @@ -34650,6 +34724,20 @@ }, /turf/open/floor/plating, /area/router) +"bwM" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/camera{ + c_tag = "Central Starboard Maintenance"; + dir = 8; + pixel_y = -22 + }, +/obj/machinery/atmospherics/pipe/simple/cyan/hidden, +/mob/living/simple_animal/hostile/retaliate/bat, +/turf/open/floor/plating, +/area/maintenance/starboard/central) "bwN" = ( /obj/machinery/atmospherics/pipe/simple/general/visible{ dir = 4 @@ -34921,11 +35009,16 @@ /turf/open/floor/plating, /area/maintenance/department/chapel) "bxq" = ( +/obj/structure/disposalpipe/segment, /obj/structure/cable{ - icon_state = "4-8" + icon_state = "1-2" }, +/obj/structure/cable{ + icon_state = "1-4" + }, +/obj/machinery/atmospherics/pipe/simple/cyan/hidden, /turf/open/floor/plating, -/area/tcommsat/computer) +/area/maintenance/starboard/central) "bxr" = ( /obj/structure/table, /obj/effect/turf_decal/tile/purple, @@ -35428,32 +35521,29 @@ /turf/open/floor/plasteel, /area/router/eva) "byt" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/cable{ + icon_state = "1-8" + }, +/obj/machinery/atmospherics/pipe/simple/cyan/hidden, +/turf/open/floor/plating, +/area/maintenance/starboard/central) +"byu" = ( +/obj/structure/disposalpipe/segment, +/obj/effect/landmark/blobstart, +/obj/machinery/atmospherics/pipe/simple/cyan/hidden, +/turf/open/floor/plating, +/area/maintenance/starboard/central) +"byv" = ( /obj/structure/disposalpipe/segment{ dir = 4 }, /obj/machinery/camera{ c_tag = "Central Starboard Exterior Access" }, -/turf/open/floor/plating, -/area/maintenance/starboard/central) -"byu" = ( -/obj/machinery/door/firedoor, -/obj/effect/mapping_helpers/airlock/cyclelink_helper{ - dir = 8 - }, -/obj/structure/disposalpipe/segment{ +/obj/machinery/atmospherics/components/unary/vent_pump/on{ dir = 4 }, -/obj/machinery/door/airlock/external{ - name = "Central Starboard Exterior Access"; - req_access_txt = "13" - }, -/turf/open/floor/plating, -/area/maintenance/starboard/central) -"byv" = ( -/obj/structure/disposalpipe/junction/flip{ - dir = 1 - }, /turf/open/floor/plating, /area/maintenance/starboard/central) "byw" = ( @@ -36136,14 +36226,19 @@ /turf/open/floor/plasteel, /area/gateway) "bAd" = ( -/obj/structure/cable{ - icon_state = "1-4" +/obj/machinery/door/firedoor, +/obj/effect/mapping_helpers/airlock/cyclelink_helper{ + dir = 8 }, -/obj/structure/cable{ - icon_state = "2-4" +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/door/airlock/external{ + name = "Central Starboard Exterior Access"; + req_access_txt = "13" }, /obj/machinery/atmospherics/pipe/simple/cyan/hidden{ - dir = 5 + dir = 4 }, /turf/open/floor/plating, /area/maintenance/starboard/central) @@ -36375,6 +36470,15 @@ /area/medical/medbay/zone2{ name = "Medbay Treatment Center" }) +"bAz" = ( +/obj/structure/disposalpipe/junction/flip{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/simple/cyan/hidden{ + dir = 9 + }, +/turf/open/floor/plating, +/area/maintenance/starboard/central) "bAA" = ( /obj/structure/lattice, /obj/structure/cable{ @@ -36532,6 +36636,19 @@ /area/medical/medbay/zone2{ name = "Medbay Treatment Center" }) +"bAN" = ( +/obj/structure/rack, +/obj/item/clothing/suit/space/fragile, +/obj/item/clothing/head/helmet/space/fragile, +/obj/item/tank/internals/air, +/obj/item/flashlight, +/obj/machinery/airalarm{ + dir = 1; + locked = 0; + pixel_y = -22 + }, +/turf/open/floor/plating, +/area/maintenance/starboard/central) "bAO" = ( /obj/machinery/atmospherics/pipe/simple/supplymain/hidden{ dir = 4 @@ -38158,16 +38275,20 @@ }, /area/crew_quarters/heads/captain) "bEr" = ( -/obj/structure/cable, -/obj/machinery/power/apc{ - areastring = "/area/crew_quarters/locker"; - dir = 8; - name = "Locker Room APC"; - pixel_x = -24 +/obj/structure/sign/warning/vacuum/external{ + pixel_x = -32; + pixel_y = 32 }, -/obj/machinery/atmospherics/pipe/simple/orange/hidden, -/turf/open/floor/plating, -/area/maintenance/fore) +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/manifold/supplymain/hidden{ + dir = 8 + }, +/turf/open/floor/plasteel, +/area/engine/engineering{ + name = "Engine Room" + }) "bEs" = ( /obj/machinery/portable_atmospherics/canister/oxygen, /obj/effect/turf_decal/tile/yellow{ @@ -38355,9 +38476,15 @@ /turf/open/floor/plasteel/dark, /area/crew_quarters/bar) "bEK" = ( -/obj/machinery/atmospherics/pipe/simple/orange/hidden, -/turf/open/floor/plating, -/area/maintenance/fore) +/obj/machinery/atmospherics/pipe/simple/supply/visible, +/obj/machinery/space_heater, +/obj/machinery/atmospherics/components/unary/vent_pump/on{ + dir = 8 + }, +/turf/open/floor/plasteel, +/area/engine/engineering{ + name = "Engine Room" + }) "bEL" = ( /obj/structure/disposalpipe/segment{ dir = 4 @@ -38591,9 +38718,19 @@ /turf/open/floor/plasteel, /area/ai_monitored/turret_protected/ai) "bFg" = ( -/obj/effect/turf_decal/tile/brown, +/obj/machinery/atmospherics/pipe/simple/scrubbers/visible, +/obj/machinery/suit_storage_unit/engine, +/obj/machinery/atmospherics/pipe/simple/supplymain/hidden{ + dir = 4 + }, +/obj/machinery/airalarm{ + dir = 4; + pixel_x = -23 + }, /turf/open/floor/plasteel, -/area/quartermaster/miningoffice) +/area/engine/engineering{ + name = "Engine Room" + }) "bFh" = ( /obj/effect/turf_decal/tile/brown, /obj/machinery/light, @@ -39247,14 +39384,15 @@ /turf/open/floor/plasteel, /area/hallway/primary/central) "bGu" = ( -/obj/machinery/door/firedoor, -/obj/machinery/door/airlock/maintenance{ - name = "Fore Maintenance"; - req_one_access_txt = "12;46" +/obj/structure/cable{ + icon_state = "1-4" }, -/obj/machinery/atmospherics/pipe/simple/orange/hidden, -/turf/open/floor/plating, -/area/hallway/primary/port/fore) +/obj/machinery/atmospherics/pipe/simple/supplymain/hidden, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/open/floor/plasteel/freezer, +/area/crew_quarters/toilet/restrooms) "bGv" = ( /obj/machinery/door/firedoor, /obj/machinery/door/airlock/public/glass{ @@ -39621,20 +39759,15 @@ /turf/open/floor/plasteel, /area/security/main) "bHi" = ( -/obj/structure/disposalpipe/segment{ - dir = 4 - }, -/obj/effect/turf_decal/tile/neutral{ +/obj/machinery/atmospherics/components/unary/vent_pump/on{ dir = 1 }, -/obj/effect/turf_decal/tile/neutral{ - dir = 4 +/obj/effect/landmark/event_spawn, +/obj/structure/cable{ + icon_state = "1-2" }, -/obj/machinery/atmospherics/pipe/manifold/orange/hidden{ - dir = 8 - }, -/turf/open/floor/plasteel, -/area/hallway/primary/port/fore) +/turf/open/floor/plasteel/freezer, +/area/crew_quarters/toilet/restrooms) "bHj" = ( /obj/structure/table, /obj/structure/bedsheetbin/towel, @@ -40740,7 +40873,11 @@ /obj/machinery/airalarm{ pixel_y = 24 }, -/turf/open/floor/wood, +/obj/effect/turf_decal/tile/neutral, +/obj/effect/turf_decal/tile/neutral{ + dir = 1 + }, +/turf/open/floor/plasteel/dark, /area/library) "bJD" = ( /obj/machinery/disposal/bin{ @@ -40891,15 +41028,11 @@ /turf/open/floor/plasteel/white, /area/science/mixing) "bJU" = ( -/obj/effect/turf_decal/tile/brown, -/obj/machinery/light{ - dir = 4 +/obj/structure/cable{ + icon_state = "1-2" }, -/obj/effect/turf_decal/tile/purple{ - dir = 4 - }, -/turf/open/floor/plasteel, -/area/quartermaster/miningoffice) +/turf/open/floor/plasteel/freezer, +/area/crew_quarters/toilet/restrooms) "bJV" = ( /obj/machinery/atmospherics/components/unary/thermomachine/freezer/on{ dir = 1; @@ -41361,7 +41494,11 @@ /area/science/robotics/lab) "bKR" = ( /obj/structure/bookcase/random/religion, -/turf/open/floor/wood, +/obj/effect/turf_decal/tile/neutral, +/obj/effect/turf_decal/tile/neutral{ + dir = 1 + }, +/turf/open/floor/plasteel/dark, /area/library) "bKS" = ( /obj/machinery/door/firedoor, @@ -42981,22 +43118,30 @@ /turf/open/floor/plasteel, /area/hallway/secondary/exit) "bOn" = ( -/obj/machinery/door/airlock/external/glass{ - name = "Shuttle Maintenance Access" +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/maintenance{ + name = "Bathroom Maintenance"; + req_access_txt = "12" }, -/turf/open/floor/plasteel, -/area/hallway/secondary/exit) +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/open/floor/plating, +/area/crew_quarters/toilet/restrooms) "bOo" = ( /obj/effect/spawner/structure/window/reinforced, /obj/structure/sign/warning/docking, /turf/open/floor/plating, /area/hallway/secondary/exit) "bOp" = ( -/obj/machinery/door/airlock/external/glass{ - name = "Departures Shuttle Dock" +/obj/structure/cable{ + icon_state = "2-8" }, -/turf/open/floor/plasteel, -/area/hallway/secondary/exit) +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/open/floor/plating, +/area/maintenance/aft) "bOq" = ( /obj/machinery/power/tracker, /obj/structure/cable, @@ -44925,8 +45070,12 @@ /turf/open/floor/plasteel/dark, /area/science/robotics/lab) "bRZ" = ( -/obj/structure/bookcase/random/fiction, -/turf/open/floor/wood, +/obj/structure/bookcase/random/nonfiction, +/obj/effect/turf_decal/tile/neutral, +/obj/effect/turf_decal/tile/neutral{ + dir = 1 + }, +/turf/open/floor/plasteel/dark, /area/library) "bSa" = ( /obj/structure/closet/secure_closet/medical3, @@ -46569,15 +46718,15 @@ /turf/open/floor/plasteel, /area/quartermaster/sorting) "bVt" = ( -/obj/structure/disposalpipe/segment, -/obj/structure/cable{ - icon_state = "1-2" +/obj/effect/turf_decal/tile/brown{ + dir = 1 }, -/obj/structure/cable{ - icon_state = "1-4" +/obj/effect/turf_decal/tile/purple{ + dir = 4 }, -/turf/open/floor/plating, -/area/maintenance/starboard/central) +/obj/machinery/atmospherics/pipe/simple/cyan/hidden, +/turf/open/floor/plasteel, +/area/quartermaster/miningoffice) "bVu" = ( /obj/effect/decal/cleanable/dirt, /obj/item/radio/intercom{ @@ -47901,11 +48050,9 @@ /turf/open/floor/plating, /area/router) "bXN" = ( -/obj/structure/cable{ - icon_state = "2-8" - }, -/turf/open/floor/plating, -/area/maintenance/aft) +/obj/machinery/smartfridge/organ/preloaded, +/turf/closed/wall, +/area/medical/morgue) "bXO" = ( /obj/structure/table/glass, /obj/machinery/reagentgrinder, @@ -47922,7 +48069,7 @@ /obj/structure/cable{ icon_state = "0-4" }, -/turf/open/floor/plating, +/turf/open/floor/plating/airless, /area/space/nearstation) "bXQ" = ( /obj/structure/closet/l3closet/scientist, @@ -47979,7 +48126,7 @@ /obj/structure/cable{ icon_state = "4-8" }, -/turf/open/floor/plating, +/turf/open/floor/plating/airless, /area/space/nearstation) "bXW" = ( /obj/structure/disposalpipe/segment{ @@ -48671,8 +48818,10 @@ /turf/open/floor/plasteel/freezer, /area/crew_quarters/toilet/restrooms) "bZo" = ( -/turf/open/floor/plasteel/freezer, -/area/crew_quarters/toilet/restrooms) +/obj/effect/turf_decal/tile/brown, +/obj/machinery/atmospherics/pipe/simple/cyan/hidden, +/turf/open/floor/plasteel, +/area/quartermaster/miningoffice) "bZp" = ( /obj/structure/lattice/catwalk, /obj/structure/cable{ @@ -48706,13 +48855,13 @@ /turf/open/floor/plating, /area/hallway/primary/central) "bZs" = ( -/obj/machinery/door/firedoor, -/obj/machinery/door/airlock/maintenance{ - name = "Bathroom Maintenance"; - req_access_txt = "12" +/obj/effect/turf_decal/tile/brown, +/obj/effect/turf_decal/tile/purple{ + dir = 4 }, -/turf/open/floor/plating, -/area/crew_quarters/toilet/restrooms) +/obj/machinery/atmospherics/pipe/simple/cyan/hidden, +/turf/open/floor/plasteel, +/area/quartermaster/miningoffice) "bZt" = ( /turf/closed/wall, /area/maintenance/starboard/aft) @@ -48859,8 +49008,11 @@ /turf/open/floor/carpet, /area/library) "bZK" = ( -/obj/structure/bookcase/random/nonfiction, -/turf/open/floor/wood, +/obj/effect/turf_decal/tile/neutral, +/obj/effect/turf_decal/tile/neutral{ + dir = 1 + }, +/turf/open/floor/plasteel/dark, /area/library) "bZL" = ( /obj/machinery/air_sensor/atmos/nitrous_tank, @@ -52612,9 +52764,8 @@ /turf/open/floor/plasteel, /area/engine/teg_hot) "chC" = ( -/obj/effect/decal/cleanable/dirt, -/turf/open/floor/plating, -/area/maintenance/disposal) +/turf/closed/wall/r_wall/rust, +/area/space/nearstation) "chD" = ( /obj/effect/turf_decal/stripes/line{ dir = 1 @@ -53089,6 +53240,17 @@ }, /turf/open/floor/plating, /area/maintenance/port/fore) +"ciA" = ( +/obj/effect/turf_decal/tile/brown, +/obj/machinery/light{ + dir = 4 + }, +/obj/effect/turf_decal/tile/purple{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/cyan/hidden, +/turf/open/floor/plasteel, +/area/quartermaster/miningoffice) "ciB" = ( /obj/structure/frame/computer, /obj/structure/disposalpipe/segment, @@ -54655,18 +54817,15 @@ /turf/open/floor/circuit/telecomms/mainframe, /area/tcommsat/server) "clO" = ( -/obj/structure/disposalpipe/segment, -/obj/structure/cable{ - icon_state = "1-2" +/obj/effect/turf_decal/tile/brown, +/obj/effect/turf_decal/tile/purple{ + dir = 4 }, -/obj/machinery/door/airlock/engineering{ - name = "Electrical Substation"; - req_access_txt = "10" +/obj/machinery/atmospherics/components/unary/vent_pump/on{ + dir = 1 }, -/turf/open/floor/plating, -/area/engine/storage_shared{ - name = "Electrical Substation" - }) +/turf/open/floor/plasteel, +/area/quartermaster/miningoffice) "clP" = ( /obj/structure/table, /obj/item/stock_parts/subspace/amplifier, @@ -55625,6 +55784,29 @@ icon_state = "panelscorched" }, /area/maintenance/port/fore) +"cnG" = ( +/obj/machinery/door/airlock/external/glass{ + name = "Shuttle Maintenance Access" + }, +/obj/structure/fans/tiny, +/turf/open/floor/plasteel, +/area/hallway/secondary/exit) +"cnH" = ( +/obj/machinery/door/airlock/external/glass{ + name = "Departures Shuttle Dock" + }, +/obj/structure/fans/tiny, +/turf/open/floor/plasteel, +/area/hallway/secondary/exit) +"cnI" = ( +/turf/open/floor/plating{ + icon_state = "platingdmg3" + }, +/area/space/nearstation) +"cnJ" = ( +/obj/structure/girder, +/turf/open/floor/plating/airless, +/area/space/nearstation) "cnK" = ( /obj/effect/turf_decal/stripes/line{ dir = 8 @@ -55634,10 +55816,47 @@ }, /turf/open/floor/plasteel, /area/engine/teg_hot) +"cnL" = ( +/obj/structure/closet/crate/science, +/obj/item/stack/sheet/metal/ten, +/obj/item/stack/sheet/glass/five, +/obj/item/stack/rods/twentyfive, +/obj/item/target/syndicate, +/obj/item/target/alien, +/obj/item/target, +/obj/item/target/clown, +/turf/open/floor/plasteel, +/area/science/mixing) +"cnM" = ( +/obj/machinery/mass_driver{ + dir = 8; + id = "pb_in"; + name = "Router Driver" + }, +/turf/open/floor/plating/airless, +/area/router/aux) +"cnN" = ( +/obj/structure/bookcase/random/fiction, +/obj/effect/turf_decal/tile/neutral, +/obj/effect/turf_decal/tile/neutral{ + dir = 1 + }, +/turf/open/floor/plasteel/dark, +/area/library) "cnO" = ( /obj/effect/landmark/event_spawn, /turf/open/floor/engine, /area/science/storage) +"cnP" = ( +/obj/structure/disposalpipe/segment{ + dir = 9 + }, +/obj/item/kirbyplants{ + icon_state = "plant-21"; + pixel_y = 3 + }, +/turf/open/floor/wood, +/area/library) "cnS" = ( /obj/structure/cable{ icon_state = "0-2" @@ -61156,18 +61375,6 @@ /obj/machinery/atmospherics/pipe/simple/cyan/hidden, /turf/open/floor/plasteel, /area/quartermaster/miningoffice) -"cyd" = ( -/obj/effect/turf_decal/tile/brown{ - dir = 1 - }, -/obj/effect/turf_decal/tile/purple{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/cyan/hidden{ - dir = 5 - }, -/turf/open/floor/plasteel, -/area/quartermaster/miningoffice) "cye" = ( /obj/structure/disposalpipe/segment{ dir = 5 @@ -67714,13 +67921,6 @@ /obj/machinery/atmospherics/pipe/simple/supplymain/hidden, /turf/open/floor/plasteel/freezer, /area/crew_quarters/toilet/restrooms) -"cJg" = ( -/obj/structure/cable{ - icon_state = "1-4" - }, -/obj/machinery/atmospherics/pipe/simple/supplymain/hidden, -/turf/open/floor/plasteel/freezer, -/area/crew_quarters/toilet/restrooms) "cJh" = ( /obj/structure/table, /obj/structure/bedsheetbin/towel, @@ -67819,16 +68019,6 @@ }, /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, /turf/closed/wall/r_wall, -/area/engine/engineering{ - name = "Engine Room" - }) -"cJq" = ( -/obj/machinery/atmospherics/pipe/simple/scrubbers/visible, -/obj/machinery/suit_storage_unit/engine, -/obj/machinery/atmospherics/pipe/simple/supplymain/hidden{ - dir = 4 - }, -/turf/open/floor/plasteel, /area/engine/engineering{ name = "Engine Room" }) @@ -69803,13 +69993,6 @@ "cNB" = ( /turf/open/floor/plating, /area/quartermaster/miningdock/airless) -"cNC" = ( -/obj/machinery/atmospherics/components/unary/vent_pump/on{ - dir = 1 - }, -/obj/effect/landmark/event_spawn, -/turf/open/floor/plasteel/freezer, -/area/crew_quarters/toilet/restrooms) "cND" = ( /obj/effect/landmark/event_spawn, /turf/open/floor/plasteel, @@ -85536,8 +85719,8 @@ aaU aaa aaU aEa -cMK -bxq +aXm +aXs bxC akI bxK @@ -92528,7 +92711,7 @@ aaa aaa aaa aaa -aaU +aaa bcy bed boJ @@ -93042,11 +93225,11 @@ aaa aaa aaa aaa -aaa +aaU +bQe +aaU aaU aaU -aaa -aaa bcw bdf bdf @@ -93299,13 +93482,13 @@ aaa aaa aaa aaa -aaa -bim +aaU +aye +aaU aaU aaU -aaa bcw -bhy +cnL bdf bpR bJw @@ -93557,10 +93740,10 @@ aaa aaa aaa aaU -aaa -aaa -aaU -aaU +chC +abp +abp +abp bcy biK bdf @@ -93814,10 +93997,10 @@ aaa aaa aaa aaU -aaa -aaa -aaa -aaU +brs +brs +brs +brs bcw biT bdf @@ -94071,8 +94254,8 @@ aaU aaU aaU aaU -aaa -aaa +cnI +cnJ bgW bgW bgW @@ -97834,16 +98017,16 @@ aaa aaa aaa aaa -aak -aak -aak +aaU +aaa +aaU aaa aaa aaa aaa aaa aaa -akN +bhy alq alq apn @@ -98169,7 +98352,7 @@ aZy aZy aZy aZy -beJ +aXg bfd bjg bUt @@ -98348,9 +98531,9 @@ aaa aaa aaa aaa -aWj -aWj -aWj +aaU +aaa +aaU aaa aaa aaa @@ -98598,16 +98781,16 @@ aaU aar abM ace -aWj -aWj -aWj -aWj -aWj -aWj -aWj -aWj +aaU +aaU +aaU +aaU +aaU +aaU +aaU +aaU abp -aWj +aaU aaU aaU aaU @@ -98855,16 +99038,16 @@ aaU aar abR ace -aWj +aaU aaa aaa aaa aaa aaa aaa -aWj -aWj -aWj +aaU +aaa +aaU aaa aaa aaa @@ -99112,7 +99295,7 @@ aaU aar abM acf -aWj +aaU aaa aaa aaa @@ -99368,8 +99551,8 @@ aaa aaU aaa acM -aWj -aWj +aaa +aaU aaa aaa aaa @@ -99454,8 +99637,8 @@ bWi aWh cmN aZy -aXg -bZK +baE +bRZ bZF csH bay @@ -99625,7 +99808,7 @@ aaa aaU aaa aaU -aWj +aaa aaU aaa aaa @@ -99712,7 +99895,7 @@ baS bbr aZy bJC -bZF +bZK bZF cjx bay @@ -99882,7 +100065,7 @@ aaa aaU aaa aaU -aWj +aaa aaU aaa aaa @@ -99969,10 +100152,10 @@ cdE bbs aZy bKR -bRZ +cnN bZF cCJ -baE +cnP bZS bZS bGI @@ -100139,7 +100322,7 @@ aaa aaU aaa aaU -aWj +aaa aaU add adC @@ -100396,7 +100579,7 @@ aaa aaU aaa aaU -aWj +aaa aaU adf aad @@ -100653,7 +100836,7 @@ aaa aaU aaa aaU -aWj +aaa aaU adf aad @@ -100910,7 +101093,7 @@ aaa aaU aaa aaU -aWj +aaa aaU adf aad @@ -101167,7 +101350,7 @@ aaa aaU aaa aaU -aWj +aaa aaU adf aad @@ -101424,7 +101607,7 @@ aaa aaU aaa aaU -aWj +aaa aaU adf aad @@ -101681,7 +101864,7 @@ aaa aaU aaa aaU -aWj +aaa aaU adh adC @@ -101938,7 +102121,7 @@ aaa aaU aaa aaU -aWj +aaa aaU aaa aaa @@ -102193,9 +102376,9 @@ aaa aaa aaa aaU -aar aaU -aWj +aaU +aaU aaU aaU aaU @@ -102450,9 +102633,9 @@ aaa aaa aaa abp -aar +akN aTd -aWj +aaa abp aaa aaU @@ -102707,9 +102890,9 @@ aaa aaa aaa aaU -aar aaU -aWj +aaU +aaU aaU aaU aaU @@ -102966,7 +103149,7 @@ aaa aaU aaa aaU -aWj +aaa aaU aaa aaa @@ -103223,7 +103406,7 @@ aaa aaa aaa aaU -aWj +aaa aaU aaa adj @@ -103480,7 +103663,7 @@ aaa aaa aaa aaU -aWj +aaa aaU adj adj @@ -103737,7 +103920,7 @@ aaa aaa aaa aaU -aWj +aaa aaU adj adF @@ -103994,7 +104177,7 @@ aaa aaa aaa aaU -aWj +aaa aaU adj adF @@ -104251,7 +104434,7 @@ aaa aaa aaa aaU -aWj +aaa aaU adj adF @@ -104285,12 +104468,12 @@ aJF aJF aJF aJF -bEr -bEK -bEK -bGu -bHi aHa +aHp +aHp +aIJ +aLc +aMo cBj cBw cBF @@ -104508,7 +104691,7 @@ aaa aaa aaa aaU -aWj +aaa aaU adj adF @@ -104547,15 +104730,15 @@ aim aim aEh aEq -aHp -aIJ -aLc -aQS -aQS -aQS -aQS +aMG aQS +aWr aWu +aWu +aWu +aWu +aWu +bbQ aWA aXd bre @@ -104765,7 +104948,7 @@ aaa aaa aaa aaU -aWj +aaa aaU adj adF @@ -105022,7 +105205,7 @@ aaa aaa aaa aaU -aWj +aaa aaU adj adj @@ -105279,7 +105462,7 @@ aaa aaa aaa aaU -aWj +aaa aaa aaU adj @@ -105536,7 +105719,7 @@ aaa aaa aaa aaU -aWj +aaa aaa aaa aaa @@ -105660,7 +105843,7 @@ cbm byQ bHK cGU -byQ +bXN bHK bIu bJh @@ -105793,7 +105976,7 @@ aaa aaa aaa aaU -aWj +aaa aaa aaa aaa @@ -106050,7 +106233,7 @@ aaa aaa aaa aaU -aWj +aaa aaa aaa aaa @@ -106307,7 +106490,7 @@ aaa aaa aaa aaU -aWj +aaa aaa aaa aaa @@ -106564,7 +106747,7 @@ aaa aaa aaa aaU -aWj +aaa aaa aaa aaa @@ -106821,7 +107004,7 @@ aaa aaa aaa aaU -aWj +aaa aaa aaa aaa @@ -107078,7 +107261,7 @@ aaa aaa aaa aaU -aWj +aaa aaa aaa aaa @@ -107191,11 +107374,11 @@ cIA cIP cIY cJf -cJg -cNC -bZo -bZs -bXN +bGu +bHi +bJU +bOn +bOp bJp bJp cyT @@ -107335,7 +107518,7 @@ aaa aaa aaa aaU -aWj +aaa aaa aaa aaa @@ -107592,7 +107775,7 @@ aaa aaa aaa aaU -aWj +aaa aaa aaa aaU @@ -107849,7 +108032,7 @@ aaa aaa aaa aaU -aWj +aaa aaa aaa aaa @@ -108104,9 +108287,9 @@ aaa aaa aaa aaU -aar +aaU aTd -aWj +aaU aaU aaU aaU @@ -108363,7 +108546,7 @@ aaa aaa aaa aaU -aWj +aaa aaa aaa aaa @@ -108620,7 +108803,7 @@ aaa aaa aaa aaU -aWj +aaa aaa aaa aaa @@ -108877,7 +109060,7 @@ aaa aaa aaa aaU -aWj +aaa aaa aaa aaa @@ -109013,7 +109196,7 @@ bme bme bme bme -bOn +cnG bme bOo aaa @@ -109134,7 +109317,7 @@ aaa aaa aaa aaU -aWj +aaa aaa aaa aaa @@ -109272,7 +109455,7 @@ bOe bOi cnd bOl -bOp +cnH aaa aaa aaa @@ -109391,7 +109574,7 @@ aaa aaa aaa aaU -aWj +aaa aaa aaa aaa @@ -109648,7 +109831,7 @@ aaa aaa aaa aaU -aWj +aaa aae aaa aaa @@ -109786,7 +109969,7 @@ bme bOh cne bOm -bOp +cnH aaa aaa aaa @@ -109905,7 +110088,7 @@ aaa aaa aaa aaU -aWj +aaa aaa aaa aaa @@ -110162,7 +110345,7 @@ aaa aaa aaa aaU -aWj +aaa aaa aaa aaa @@ -110242,7 +110425,7 @@ bsz aej agc agT -cJq +bFg apm aqS arP @@ -110419,7 +110602,7 @@ aaa aaa aaa aaU -aWj +aaa aaa aaa aaa @@ -110480,7 +110663,7 @@ bpH ang coh cfy -clO +bvb aRu aSv aSy @@ -110498,7 +110681,7 @@ cxa bPr sVC aNH -bbQ +bEr cJA aqO anE @@ -110676,7 +110859,7 @@ aaa aaa aaa aaU -aWj +aaa aaa aaa aaa @@ -110755,7 +110938,7 @@ cxb bsz aej agC -aoJ +bEK cJB apm aqT @@ -110933,7 +111116,7 @@ aaa aaa aaa aaU -aWj +aaa aaa aaa aaa @@ -111188,9 +111371,9 @@ aaa aaa aaa aaU -aav +aaU aTd -aWj +aaU aaU aaU aaU @@ -111328,7 +111511,7 @@ bme bOi bOj bOl -bOp +cnH cnE aaa aaa @@ -111447,7 +111630,7 @@ aaa aaa aaa aaU -aWj +aaa aaa aaa aaa @@ -111704,7 +111887,7 @@ aaa aaa aaa aaU -aWj +aaa aaa aaa aaU @@ -111842,7 +112025,7 @@ bOe bOh cnc bOm -bOp +cnH aaa aaa aaa @@ -111961,7 +112144,7 @@ aaa aaa aaa aaU -aWj +aaa aaa aaa aaa @@ -111982,7 +112165,7 @@ afm apT adS bEu -ahN +aif afa aha ahx @@ -112097,7 +112280,7 @@ bme bme bme bme -bOn +cnG bme bOo aaa @@ -112218,7 +112401,7 @@ aaa aaa aaa aaU -aWj +aaa aaa aaa aaa @@ -112239,7 +112422,7 @@ aiV anv aec axS -ahN +aif afK ahb ahx @@ -112288,7 +112471,7 @@ bxP arE aMI cgX -chC +bim cik bwW bsT @@ -112475,7 +112658,7 @@ aaa aaU aaa aaU -aWj +aaa aaU aaa aaa @@ -112496,7 +112679,7 @@ aja aoM aec agi -ahN +aif afK ahc ahx @@ -112730,9 +112913,9 @@ aaa aaa aaa aaU -aav aaU -aWj +aaU +aaU aaU aaU aaU @@ -112753,7 +112936,7 @@ bEp bEp bEp bEp -ahN +aif afK ahd ahx @@ -112798,8 +112981,8 @@ arE att cqr arE -byt -bzo +byv +bAN aMI cgZ cif @@ -112987,9 +113170,9 @@ aaa aaa aaa abp -aav +aaa aTd -aWj +aaa abp aaa aaa @@ -113010,7 +113193,7 @@ ajS aHj bvm ahP -ahN +aif afK afK ahT @@ -113055,7 +113238,7 @@ att btP bwo arE -byu +bAd arE aMI cha @@ -113244,19 +113427,19 @@ aaa aaa aaa aaU -aav aaU -aWj -aWj -aWj -aWj -aWj -aWj -aWj -aWj -aWj -aWj -aWj +aaU +aaU +aaU +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaU aaV aaU aaU @@ -113267,7 +113450,7 @@ ahP ahP bzp ahP -ahN +aif aiB afK ahU @@ -113306,13 +113489,13 @@ aYF beQ bjw bwu -bAd -aMo -aMG -bVt +bnl bwp -bvb -byv +bwM +bxq +byt +byu +bAz ceQ cgT chc @@ -113503,7 +113686,7 @@ aaa aaU aaa aaU -aWj +aaa aaU aaa aaa @@ -113524,7 +113707,7 @@ akn aJR bEg ahP -aif +aoJ ass afK afK @@ -113760,7 +113943,7 @@ aaa aaU aaa aaU -aWj +aaa aaU aaa aaa @@ -114017,7 +114200,7 @@ aaa aaU aaa aaU -aWj +aaa aaU aaa aaa @@ -114274,7 +114457,7 @@ aaa aaU aaa aaU -aWj +aaa aaU aaa aaa @@ -114531,7 +114714,7 @@ aaa aaU aaa aaU -aWj +aaa aaU aaa aaa @@ -114788,7 +114971,7 @@ aaa aaU aaa aaU -aWj +aaa aaU aaa aaa @@ -115045,7 +115228,7 @@ aaa aaU aaa aaU -aWj +aaa aaU aaa aaa @@ -115302,7 +115485,7 @@ aaa aaU aaa aaU -aWj +aaa aaU aaa aaa @@ -115559,7 +115742,7 @@ aaa aaU aaa aaU -aWj +aaa aaU aaa aaa @@ -115816,7 +115999,7 @@ aaa aaU aaa aaU -aWj +aaa aaU aaa aaa @@ -116073,7 +116256,7 @@ aaa aaU aaa aaU -aWj +aaa aaU aaa aaa @@ -116330,7 +116513,7 @@ aaa aaU aaa ahv -aWj +aaa aaU aaa aaa @@ -116585,7 +116768,7 @@ aaa aaa aaa aaU -aav +cnM abM acj aaU @@ -119537,13 +119720,13 @@ cjb cxV cyb cyc -cyd -bFg -bHR -bHR -bHR -bJU -bHR +bVt +bZo +bZs +bZs +bZs +ciA +clO bHR bLb boK diff --git a/_maps/map_files/Deltastation/DeltaStation2.dmm b/_maps/map_files/Deltastation/DeltaStation2.dmm index 61ecaddddc..53ca9a72b0 100644 --- a/_maps/map_files/Deltastation/DeltaStation2.dmm +++ b/_maps/map_files/Deltastation/DeltaStation2.dmm @@ -1464,19 +1464,7 @@ /obj/structure/cable{ icon_state = "4-8" }, -/obj/effect/mapping_helpers/airlock/cyclelink_helper{ - dir = 8 - }, -/obj/machinery/door/airlock/external{ - name = "External Solar Access"; - req_access_txt = "10; 13" - }, -/obj/effect/turf_decal/stripes/line{ - dir = 8 - }, -/obj/effect/turf_decal/stripes/line{ - dir = 4 - }, +/obj/effect/turf_decal/delivery, /turf/open/floor/plasteel, /area/maintenance/solars/starboard/fore) "acQ" = ( @@ -17256,19 +17244,7 @@ /obj/structure/cable{ icon_state = "4-8" }, -/obj/effect/mapping_helpers/airlock/cyclelink_helper{ - dir = 4 - }, -/obj/machinery/door/airlock/external{ - name = "External Solar Access"; - req_one_access_txt = "13; 24; 10" - }, -/obj/effect/turf_decal/stripes/line{ - dir = 8 - }, -/obj/effect/turf_decal/stripes/line{ - dir = 4 - }, +/obj/effect/turf_decal/delivery, /turf/open/floor/plasteel, /area/maintenance/solars/port/fore) "aIk" = ( @@ -25107,14 +25083,8 @@ /turf/open/floor/plasteel/dark, /area/security/execution/education) "aUK" = ( -/obj/effect/mapping_helpers/airlock/cyclelink_helper, -/obj/machinery/door/airlock/external{ - name = "Security External Airlock"; - req_access_txt = "63" - }, -/obj/effect/turf_decal/stripes/line, -/obj/effect/turf_decal/stripes/line{ - dir = 1 +/obj/structure/sign/warning/vacuum/external{ + pixel_x = 32 }, /turf/open/floor/plating, /area/security/prison) @@ -43327,21 +43297,16 @@ /turf/open/floor/plasteel/dark, /area/ai_monitored/turret_protected/ai) "bzd" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/cobweb, -/obj/structure/closet/emcloset/anchored, -/obj/effect/turf_decal/delivery, -/turf/open/floor/plasteel, -/area/engine/gravity_generator) +/obj/structure/lattice, +/turf/closed/wall, +/area/construction/mining/aux_base) "bze" = ( -/obj/effect/decal/cleanable/dirt, /obj/effect/turf_decal/bot, /turf/open/floor/plasteel, /area/engine/gravity_generator) "bzf" = ( -/obj/machinery/light/small{ - dir = 4 - }, +/obj/effect/decal/cleanable/dirt, +/obj/structure/closet/emcloset/anchored, /obj/effect/turf_decal/delivery, /turf/open/floor/plasteel, /area/engine/gravity_generator) @@ -44447,122 +44412,83 @@ /turf/open/floor/plasteel/dark, /area/engine/gravity_generator) "bAI" = ( -/obj/machinery/atmospherics/pipe/simple/supply/hidden{ - dir = 6 - }, -/obj/effect/turf_decal/tile/neutral{ - dir = 1 - }, -/obj/effect/turf_decal/tile/neutral, -/obj/effect/turf_decal/tile/neutral{ - dir = 4 - }, -/obj/effect/turf_decal/tile/neutral{ - dir = 8 - }, -/turf/open/floor/plasteel/dark, -/area/engine/gravity_generator) -"bAJ" = ( -/obj/structure/cable/white{ - icon_state = "0-2" - }, -/obj/effect/spawner/structure/window/reinforced, -/obj/structure/sign/warning/electricshock{ - pixel_y = 32 - }, -/obj/machinery/atmospherics/pipe/simple/supply/hidden{ - dir = 4 - }, -/turf/open/floor/plating, -/area/engine/gravity_generator) -"bAK" = ( -/obj/effect/decal/cleanable/dirt, -/obj/machinery/light{ - dir = 1 - }, -/obj/machinery/status_display/evac{ - pixel_y = 32 - }, -/obj/machinery/atmospherics/pipe/simple/supply/hidden{ - dir = 4 - }, -/obj/effect/turf_decal/stripes/line{ - dir = 9 - }, -/turf/open/floor/plasteel, -/area/engine/gravity_generator) -"bAL" = ( -/obj/machinery/power/apc/highcap/five_k{ - areastring = "/area/engine/gravity_generator"; - dir = 1; - name = "Gravity Generator APC"; - pixel_y = 24 - }, -/obj/machinery/atmospherics/pipe/simple/supply/hidden{ - dir = 4 - }, -/obj/structure/cable{ - icon_state = "0-2" - }, -/obj/effect/turf_decal/stripes/line{ - dir = 1 - }, -/turf/open/floor/plasteel, -/area/engine/gravity_generator) -"bAM" = ( -/obj/machinery/power/terminal{ - dir = 4 - }, -/obj/item/radio/intercom{ - name = "Station Intercom"; - pixel_y = 26 - }, -/obj/machinery/atmospherics/pipe/simple/supply/hidden{ - dir = 10 - }, -/obj/structure/cable/white{ - icon_state = "0-2" - }, -/obj/effect/turf_decal/stripes/line{ - dir = 5 - }, -/turf/open/floor/plasteel, -/area/engine/gravity_generator) -"bAN" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/cobweb/cobweb2, -/obj/machinery/power/smes{ - charge = 5e+006 - }, -/obj/structure/sign/nanotrasen{ - pixel_y = 32 - }, -/obj/structure/extinguisher_cabinet{ - pixel_x = 26 - }, -/obj/structure/cable{ - icon_state = "0-2" - }, +/obj/structure/closet/firecloset, /obj/effect/turf_decal/bot, /turf/open/floor/plasteel, -/area/engine/gravity_generator) -"bAO" = ( -/turf/closed/wall, -/area/engine/gravity_generator) -"bAP" = ( -/obj/machinery/door/firedoor, +/area/construction/mining/aux_base) +"bAJ" = ( +/obj/structure/reagent_dispensers/watertank, +/obj/effect/turf_decal/bot, +/turf/open/floor/plasteel, +/area/construction/mining/aux_base) +"bAK" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, /obj/effect/mapping_helpers/airlock/cyclelink_helper{ - dir = 1 + dir = 8 }, /obj/machinery/door/airlock/external{ - name = "External Airlock"; - req_access_txt = "13" + name = "External Solar Access"; + req_access_txt = "10; 13" + }, +/obj/effect/turf_decal/stripes/line{ + dir = 8 + }, +/obj/effect/turf_decal/stripes/line{ + dir = 4 + }, +/turf/open/floor/plasteel, +/area/maintenance/solars/starboard/fore) +"bAL" = ( +/obj/structure/lattice/catwalk, +/obj/structure/cable{ + icon_state = "0-4" + }, +/turf/open/space, +/area/solar/port/fore) +"bAM" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/effect/mapping_helpers/airlock/cyclelink_helper{ + dir = 4 + }, +/obj/machinery/door/airlock/external{ + name = "External Solar Access"; + req_one_access_txt = "13; 24; 10" + }, +/obj/effect/turf_decal/stripes/line{ + dir = 8 + }, +/obj/effect/turf_decal/stripes/line{ + dir = 4 + }, +/turf/open/floor/plasteel, +/area/maintenance/solars/port/fore) +"bAN" = ( +/obj/effect/mapping_helpers/airlock/cyclelink_helper, +/obj/machinery/door/airlock/external{ + name = "Security External Airlock"; + req_access_txt = "63" }, -/obj/effect/decal/cleanable/dirt, /obj/effect/turf_decal/stripes/line, /obj/effect/turf_decal/stripes/line{ dir = 1 }, +/turf/open/floor/plating, +/area/security/prison) +"bAO" = ( +/obj/machinery/light/small{ + dir = 4 + }, +/obj/effect/turf_decal/delivery, +/obj/structure/reagent_dispensers/fueltank, +/turf/open/floor/plasteel, +/area/engine/gravity_generator) +"bAP" = ( +/obj/effect/decal/cleanable/dirt, +/obj/effect/turf_decal/bot, /turf/open/floor/plasteel, /area/engine/gravity_generator) "bAQ" = ( @@ -45609,7 +45535,7 @@ }, /turf/open/floor/circuit/green, /area/ai_monitored/turret_protected/ai) -"bCw" = ( +"bCx" = ( /obj/effect/turf_decal/bot_white/right, /obj/effect/turf_decal/tile/neutral{ dir = 1 @@ -45623,37 +45549,9 @@ }, /turf/open/floor/plasteel/dark, /area/engine/gravity_generator) -"bCx" = ( -/obj/effect/turf_decal/bot_white, -/obj/effect/turf_decal/tile/neutral{ - dir = 1 - }, -/obj/effect/turf_decal/tile/neutral, -/obj/effect/turf_decal/tile/neutral{ - dir = 4 - }, -/obj/effect/turf_decal/tile/neutral{ - dir = 8 - }, -/turf/open/floor/plasteel/dark, -/area/engine/gravity_generator) -"bCy" = ( -/obj/effect/turf_decal/bot_white/left, -/obj/effect/turf_decal/tile/neutral{ - dir = 1 - }, -/obj/effect/turf_decal/tile/neutral, -/obj/effect/turf_decal/tile/neutral{ - dir = 4 - }, -/obj/effect/turf_decal/tile/neutral{ - dir = 8 - }, -/turf/open/floor/plasteel/dark, -/area/engine/gravity_generator) "bCz" = ( -/obj/machinery/atmospherics/components/unary/vent_pump/on{ - dir = 1 +/obj/machinery/atmospherics/pipe/simple/supply/hidden{ + dir = 6 }, /obj/effect/turf_decal/tile/neutral{ dir = 1 @@ -45668,26 +45566,91 @@ /turf/open/floor/plasteel/dark, /area/engine/gravity_generator) "bCA" = ( -/obj/structure/cable/white, /obj/structure/cable/white{ icon_state = "0-2" }, /obj/effect/spawner/structure/window/reinforced, +/obj/structure/sign/warning/electricshock{ + pixel_y = 32 + }, +/obj/machinery/atmospherics/pipe/simple/supply/hidden{ + dir = 4 + }, /turf/open/floor/plating, /area/engine/gravity_generator) "bCB" = ( +/obj/effect/decal/cleanable/dirt, +/obj/machinery/light{ + dir = 1 + }, +/obj/machinery/status_display/evac{ + pixel_y = 32 + }, +/obj/machinery/atmospherics/pipe/simple/supply/hidden{ + dir = 4 + }, /obj/effect/turf_decal/stripes/line{ - dir = 8 + dir = 9 }, /turf/open/floor/plasteel, /area/engine/gravity_generator) "bCC" = ( -/obj/machinery/atmospherics/components/unary/vent_pump/on{ +/obj/machinery/power/apc/highcap/five_k{ + areastring = "/area/engine/gravity_generator"; + dir = 1; + name = "Gravity Generator APC"; + pixel_y = 24 + }, +/obj/machinery/atmospherics/pipe/simple/supply/hidden{ dir = 4 }, /obj/structure/cable{ - icon_state = "1-4" + icon_state = "0-2" }, +/obj/effect/turf_decal/stripes/line{ + dir = 1 + }, +/turf/open/floor/plasteel, +/area/engine/gravity_generator) +"bCD" = ( +/obj/machinery/power/terminal{ + dir = 4 + }, +/obj/item/radio/intercom{ + name = "Station Intercom"; + pixel_y = 26 + }, +/obj/machinery/atmospherics/pipe/simple/supply/hidden{ + dir = 10 + }, +/obj/structure/cable/white{ + icon_state = "0-2" + }, +/obj/effect/turf_decal/stripes/line{ + dir = 5 + }, +/turf/open/floor/plasteel, +/area/engine/gravity_generator) +"bCE" = ( +/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/cobweb/cobweb2, +/obj/machinery/power/smes{ + charge = 5e+006 + }, +/obj/structure/sign/nanotrasen{ + pixel_y = 32 + }, +/obj/structure/extinguisher_cabinet{ + pixel_x = 26 + }, +/obj/structure/cable{ + icon_state = "0-2" + }, +/obj/effect/turf_decal/bot, +/turf/open/floor/plasteel, +/area/engine/gravity_generator) +"bCF" = ( +/obj/effect/turf_decal/bot_white/left, /obj/effect/turf_decal/tile/neutral{ dir = 1 }, @@ -45698,80 +45661,26 @@ /obj/effect/turf_decal/tile/neutral{ dir = 8 }, -/turf/open/floor/plasteel, -/area/engine/gravity_generator) -"bCD" = ( -/obj/effect/decal/cleanable/dirt, -/obj/machinery/atmospherics/pipe/manifold/supply/hidden, -/obj/structure/cable{ - icon_state = "4-8" - }, -/obj/structure/cable/white{ - icon_state = "1-2" - }, -/obj/effect/turf_decal/stripes/line{ - dir = 4 - }, -/turf/open/floor/plasteel, -/area/engine/gravity_generator) -"bCE" = ( -/obj/effect/decal/cleanable/dirt, -/obj/machinery/atmospherics/pipe/simple/supply/hidden{ - dir = 4 - }, -/obj/structure/cable{ - icon_state = "1-8" - }, -/obj/effect/turf_decal/bot, -/turf/open/floor/plasteel, -/area/engine/gravity_generator) -"bCF" = ( -/obj/structure/sign/warning/radiation, -/obj/machinery/atmospherics/pipe/simple/supply/hidden{ - dir = 4 - }, -/turf/closed/wall/r_wall, -/area/engine/gravity_generator) -"bCG" = ( -/obj/effect/decal/cleanable/dirt, -/obj/machinery/airalarm{ - pixel_y = 23 - }, -/obj/machinery/atmospherics/pipe/manifold/supply/hidden{ - dir = 1 - }, -/obj/machinery/camera{ - c_tag = "Engineering - Gravity Generator Foyer"; - dir = 4; - name = "engineering camera" - }, -/obj/effect/turf_decal/stripes/line{ - dir = 9 - }, -/turf/open/floor/plasteel, +/turf/open/floor/plasteel/dark, /area/engine/gravity_generator) "bCH" = ( -/obj/machinery/atmospherics/pipe/simple/supply/hidden{ - dir = 4 +/obj/machinery/door/firedoor, +/obj/effect/mapping_helpers/airlock/cyclelink_helper{ + dir = 1 + }, +/obj/machinery/door/airlock/external{ + name = "External Airlock"; + req_access_txt = "13" + }, +/obj/effect/decal/cleanable/dirt, +/obj/effect/turf_decal/stripes/line, +/obj/effect/turf_decal/stripes/line{ + dir = 1 }, -/obj/effect/turf_decal/delivery, /turf/open/floor/plasteel, /area/engine/gravity_generator) "bCI" = ( -/obj/structure/closet/radiation, -/obj/machinery/light/small{ - dir = 1 - }, -/obj/structure/extinguisher_cabinet{ - pixel_x = 26 - }, -/obj/machinery/atmospherics/pipe/simple/supply/hidden{ - dir = 4 - }, -/obj/effect/turf_decal/stripes/line{ - dir = 5 - }, -/turf/open/floor/plasteel, +/turf/closed/wall, /area/engine/gravity_generator) "bCJ" = ( /obj/machinery/atmospherics/pipe/simple/supply/hidden{ @@ -45784,9 +45693,6 @@ icon_state = "0-4" }, /obj/effect/spawner/structure/window/reinforced, -/obj/machinery/atmospherics/pipe/simple/supply/hidden{ - dir = 4 - }, /turf/open/floor/plating, /area/engine/break_room) "bCL" = ( @@ -45801,13 +45707,13 @@ /obj/structure/cable/white{ icon_state = "2-8" }, -/obj/machinery/atmospherics/pipe/manifold/supply/hidden{ - dir = 1 - }, /obj/effect/turf_decal/stripes/line, /obj/effect/turf_decal/stripes/line{ dir = 1 }, +/obj/machinery/atmospherics/pipe/simple/supply/hidden{ + dir = 6 + }, /turf/open/floor/plasteel, /area/engine/break_room) "bCM" = ( @@ -47193,11 +47099,8 @@ /turf/open/floor/circuit/green, /area/ai_monitored/turret_protected/ai) "bEn" = ( -/obj/machinery/light{ - dir = 8 - }, -/obj/structure/sign/warning/radiation{ - pixel_x = -32 +/obj/machinery/atmospherics/components/unary/vent_pump/on{ + dir = 1 }, /obj/effect/turf_decal/tile/neutral{ dir = 1 @@ -47212,112 +47115,124 @@ /turf/open/floor/plasteel/dark, /area/engine/gravity_generator) "bEo" = ( -/turf/open/floor/circuit/green, -/area/engine/gravity_generator) -"bEp" = ( -/obj/machinery/door/firedoor, -/obj/machinery/door/airlock/command/glass{ - name = "Gravity Generator Chamber"; - req_access_txt = "19; 61" +/obj/effect/turf_decal/bot_white, +/obj/effect/turf_decal/tile/neutral{ + dir = 1 }, -/obj/effect/turf_decal/stripes/line{ - dir = 8 - }, -/obj/effect/turf_decal/stripes/line{ +/obj/effect/turf_decal/tile/neutral, +/obj/effect/turf_decal/tile/neutral{ dir = 4 }, -/obj/structure/cable/white{ - icon_state = "1-4" +/obj/effect/turf_decal/tile/neutral{ + dir = 8 }, -/obj/structure/cable/white{ - icon_state = "2-4" - }, -/turf/open/floor/plasteel, +/turf/open/floor/plasteel/dark, /area/engine/gravity_generator) "bEq" = ( /obj/effect/turf_decal/stripes/line{ dir = 8 }, -/obj/structure/cable/white{ - icon_state = "4-8" - }, /turf/open/floor/plasteel, /area/engine/gravity_generator) "bEr" = ( -/obj/machinery/holopad, -/obj/effect/decal/cleanable/dirt, -/obj/effect/turf_decal/bot, -/obj/structure/cable/white{ - icon_state = "4-8" +/obj/machinery/atmospherics/components/unary/vent_pump/on{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "1-4" + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 1 + }, +/obj/effect/turf_decal/tile/neutral, +/obj/effect/turf_decal/tile/neutral{ + dir = 4 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 8 }, /turf/open/floor/plasteel, /area/engine/gravity_generator) "bEs" = ( +/obj/effect/decal/cleanable/dirt, +/obj/machinery/atmospherics/pipe/manifold/supply/hidden, +/obj/structure/cable{ + icon_state = "4-8" + }, /obj/structure/cable/white{ - icon_state = "1-4" + icon_state = "1-2" }, /obj/effect/turf_decal/stripes/line{ dir = 4 }, -/obj/structure/cable/white{ - icon_state = "1-8" - }, /turf/open/floor/plasteel, /area/engine/gravity_generator) "bEt" = ( /obj/effect/decal/cleanable/dirt, -/obj/structure/cable/white{ - icon_state = "4-8" - }, -/obj/effect/turf_decal/delivery, -/turf/open/floor/plasteel, -/area/engine/gravity_generator) -"bEu" = ( -/obj/machinery/door/firedoor, -/obj/machinery/door/airlock/highsecurity{ - name = "Gravity Generator Room"; - req_access_txt = "19;23" - }, -/obj/structure/cable/white{ - icon_state = "4-8" - }, -/obj/effect/turf_decal/stripes/line{ - dir = 8 - }, -/obj/effect/turf_decal/stripes/line{ +/obj/machinery/atmospherics/pipe/simple/supply/hidden{ dir = 4 }, -/turf/open/floor/plasteel, -/area/engine/gravity_generator) -"bEv" = ( -/obj/structure/cable/white{ - icon_state = "2-4" - }, -/obj/structure/cable/white{ - icon_state = "2-8" - }, -/obj/machinery/atmospherics/pipe/simple/supply/hidden, -/obj/effect/turf_decal/delivery, -/turf/open/floor/plasteel, -/area/engine/gravity_generator) -"bEw" = ( -/obj/machinery/holopad, -/obj/effect/decal/cleanable/dirt, -/obj/structure/cable/white{ - icon_state = "4-8" +/obj/structure/cable{ + icon_state = "1-8" }, /obj/effect/turf_decal/bot, /turf/open/floor/plasteel, /area/engine/gravity_generator) -"bEx" = ( +"bEu" = ( +/obj/structure/sign/warning/radiation, +/obj/machinery/atmospherics/pipe/simple/supply/hidden{ + dir = 4 + }, +/turf/closed/wall/r_wall, +/area/engine/gravity_generator) +"bEv" = ( +/obj/effect/decal/cleanable/dirt, +/obj/machinery/airalarm{ + pixel_y = 23 + }, +/obj/machinery/atmospherics/pipe/manifold/supply/hidden{ + dir = 1 + }, +/obj/machinery/camera{ + c_tag = "Engineering - Gravity Generator Foyer"; + dir = 4; + name = "engineering camera" + }, +/obj/effect/turf_decal/stripes/line{ + dir = 9 + }, +/obj/structure/cable/white{ + icon_state = "2-4" + }, +/turf/open/floor/plasteel, +/area/engine/gravity_generator) +"bEw" = ( +/obj/machinery/atmospherics/pipe/simple/supply/hidden{ + dir = 4 + }, +/obj/effect/turf_decal/delivery, /obj/structure/cable/white{ icon_state = "4-8" }, -/obj/effect/decal/cleanable/dirt, -/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ - dir = 6 +/turf/open/floor/plasteel, +/area/engine/gravity_generator) +"bEx" = ( +/obj/structure/closet/radiation, +/obj/machinery/light/small{ + dir = 1 + }, +/obj/structure/extinguisher_cabinet{ + pixel_x = 26 + }, +/obj/machinery/atmospherics/pipe/simple/supply/hidden{ + dir = 4 + }, +/obj/effect/turf_decal/stripes/line{ + dir = 5 + }, +/obj/structure/cable/white{ + icon_state = "4-8" }, -/obj/effect/turf_decal/delivery, /turf/open/floor/plasteel, /area/engine/gravity_generator) "bEy" = ( @@ -47330,9 +47245,6 @@ req_access_txt = "10" }, /obj/effect/decal/cleanable/dirt, -/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ - dir = 4 - }, /obj/effect/turf_decal/stripes/line{ dir = 8 }, @@ -47342,18 +47254,21 @@ /obj/effect/mapping_helpers/airlock/cyclelink_helper{ dir = 4 }, +/obj/machinery/atmospherics/pipe/simple/supply/hidden{ + dir = 4 + }, /turf/open/floor/plasteel, /area/engine/break_room) "bEz" = ( /obj/structure/cable/white{ icon_state = "4-8" }, -/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ - dir = 4 - }, /obj/effect/turf_decal/stripes/end{ dir = 8 }, +/obj/machinery/atmospherics/pipe/simple/supply/hidden{ + dir = 4 + }, /turf/open/floor/plasteel, /area/engine/break_room) "bEA" = ( @@ -47363,27 +47278,26 @@ /obj/structure/cable/white{ icon_state = "4-8" }, -/obj/machinery/atmospherics/pipe/simple/supply/hidden, -/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ - dir = 4 - }, /obj/effect/turf_decal/stripes/line, /obj/effect/turf_decal/stripes/line{ dir = 1 }, +/obj/machinery/atmospherics/pipe/manifold/supply/hidden{ + dir = 4 + }, /turf/open/floor/plasteel, /area/engine/break_room) "bEB" = ( /obj/structure/cable/white{ icon_state = "4-8" }, -/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ - dir = 4 - }, /obj/effect/turf_decal/stripes/line, /obj/effect/turf_decal/stripes/line{ dir = 1 }, +/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ + dir = 6 + }, /turf/open/floor/plasteel, /area/engine/break_room) "bEC" = ( @@ -47393,25 +47307,25 @@ /obj/structure/cable/white{ icon_state = "4-8" }, -/obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden{ - dir = 1 - }, /obj/effect/turf_decal/stripes/line, /obj/effect/turf_decal/stripes/line{ dir = 1 }, +/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ + dir = 4 + }, /turf/open/floor/plasteel, /area/engine/break_room) "bED" = ( +/obj/effect/turf_decal/stripes/end{ + dir = 4 + }, /obj/structure/cable/white{ icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ dir = 4 }, -/obj/effect/turf_decal/stripes/end{ - dir = 4 - }, /turf/open/floor/plasteel, /area/engine/break_room) "bEE" = ( @@ -48446,22 +48360,15 @@ /turf/open/floor/plasteel/dark, /area/aisat) "bFW" = ( -/obj/machinery/gravity_generator/main/station, -/obj/effect/turf_decal/bot_white, -/obj/effect/turf_decal/tile/neutral{ - dir = 1 - }, -/obj/effect/turf_decal/tile/neutral, -/obj/effect/turf_decal/tile/neutral{ - dir = 4 - }, -/obj/effect/turf_decal/tile/neutral{ - dir = 8 - }, -/turf/open/floor/plasteel/dark, +/turf/open/floor/circuit/green, /area/engine/gravity_generator) "bFX" = ( -/obj/machinery/atmospherics/components/unary/vent_scrubber/on, +/obj/machinery/light{ + dir = 8 + }, +/obj/structure/sign/warning/radiation{ + pixel_x = -32 + }, /obj/effect/turf_decal/tile/neutral{ dir = 1 }, @@ -48475,89 +48382,89 @@ /turf/open/floor/plasteel/dark, /area/engine/gravity_generator) "bFY" = ( -/obj/effect/decal/cleanable/dirt, /obj/effect/turf_decal/stripes/line{ dir = 8 }, +/obj/structure/cable/white{ + icon_state = "4-8" + }, /turf/open/floor/plasteel, /area/engine/gravity_generator) "bFZ" = ( -/obj/machinery/atmospherics/components/unary/vent_scrubber/on{ - dir = 4 - }, -/obj/effect/turf_decal/tile/neutral{ - dir = 1 - }, -/obj/effect/turf_decal/tile/neutral, -/obj/effect/turf_decal/tile/neutral{ - dir = 4 - }, -/obj/effect/turf_decal/tile/neutral{ - dir = 8 +/obj/machinery/holopad, +/obj/effect/decal/cleanable/dirt, +/obj/effect/turf_decal/bot, +/obj/structure/cable/white{ + icon_state = "4-8" }, /turf/open/floor/plasteel, /area/engine/gravity_generator) "bGa" = ( -/obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden{ - dir = 1 +/obj/structure/cable/white{ + icon_state = "1-4" }, /obj/effect/turf_decal/stripes/line{ dir = 4 }, +/obj/structure/cable/white{ + icon_state = "1-8" + }, /turf/open/floor/plasteel, /area/engine/gravity_generator) "bGb" = ( /obj/effect/decal/cleanable/dirt, -/obj/machinery/power/port_gen/pacman, -/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ - dir = 4 - }, -/obj/effect/turf_decal/bot, -/turf/open/floor/plasteel, -/area/engine/gravity_generator) -"bGc" = ( -/obj/structure/sign/warning/radiation, -/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ - dir = 4 - }, -/turf/closed/wall/r_wall, -/area/engine/gravity_generator) -"bGd" = ( /obj/structure/cable/white{ - icon_state = "1-2" - }, -/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/supply/hidden, -/obj/effect/turf_decal/stripes/line{ - dir = 10 - }, -/turf/open/floor/plasteel, -/area/engine/gravity_generator) -"bGe" = ( -/obj/machinery/status_display/evac{ - pixel_x = 32; - pixel_y = -32 - }, -/obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden{ - dir = 1 + icon_state = "4-8" }, /obj/effect/turf_decal/delivery, /turf/open/floor/plasteel, /area/engine/gravity_generator) -"bGf" = ( -/obj/structure/closet/radiation, -/obj/effect/decal/cleanable/dirt, -/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ - dir = 9 +"bGc" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/highsecurity{ + name = "Gravity Generator Room"; + req_access_txt = "19;23" + }, +/obj/structure/cable/white{ + icon_state = "4-8" }, -/obj/machinery/light/small, /obj/effect/turf_decal/stripes/line{ + dir = 8 + }, +/obj/effect/turf_decal/stripes/line{ + dir = 4 + }, +/turf/open/floor/plasteel, +/area/engine/gravity_generator) +"bGd" = ( +/obj/structure/cable/white{ + icon_state = "2-8" + }, +/obj/machinery/atmospherics/pipe/simple/supply/hidden, +/obj/effect/turf_decal/delivery, +/obj/structure/cable/white{ + icon_state = "1-8" + }, +/turf/open/floor/plasteel, +/area/engine/gravity_generator) +"bGe" = ( +/obj/machinery/holopad, +/obj/effect/decal/cleanable/dirt, +/obj/effect/turf_decal/bot, +/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ dir = 6 }, /turf/open/floor/plasteel, /area/engine/gravity_generator) +"bGf" = ( +/obj/effect/decal/cleanable/dirt, +/obj/effect/turf_decal/delivery, +/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ + dir = 4 + }, +/obj/machinery/light/small, +/turf/open/floor/plasteel, +/area/engine/gravity_generator) "bGg" = ( /obj/machinery/firealarm{ dir = 4; @@ -48565,6 +48472,9 @@ }, /obj/item/kirbyplants/random, /obj/effect/turf_decal/delivery, +/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ + dir = 4 + }, /turf/open/floor/plasteel, /area/engine/break_room) "bGh" = ( @@ -48579,6 +48489,9 @@ /obj/effect/turf_decal/tile/yellow{ dir = 8 }, +/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ + dir = 4 + }, /turf/open/floor/plasteel/dark/corner, /area/engine/break_room) "bGi" = ( @@ -48586,15 +48499,16 @@ /obj/effect/turf_decal/tile/yellow{ dir = 8 }, +/obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden, /turf/open/floor/plasteel/dark/corner, /area/engine/break_room) "bGj" = ( -/obj/machinery/atmospherics/components/unary/vent_scrubber/on{ - dir = 1 - }, /obj/effect/turf_decal/tile/yellow{ dir = 8 }, +/obj/machinery/atmospherics/components/unary/vent_scrubber/on{ + dir = 8 + }, /turf/open/floor/plasteel/dark/corner, /area/engine/break_room) "bGk" = ( @@ -49624,9 +49538,7 @@ /turf/open/floor/plasteel/dark, /area/ai_monitored/turret_protected/ai) "bHN" = ( -/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ - dir = 5 - }, +/obj/machinery/atmospherics/components/unary/vent_scrubber/on, /obj/effect/turf_decal/tile/neutral{ dir = 1 }, @@ -49641,68 +49553,50 @@ /area/engine/gravity_generator) "bHO" = ( /obj/structure/cable/white, +/obj/structure/cable/white{ + icon_state = "0-2" + }, /obj/effect/spawner/structure/window/reinforced, -/obj/structure/sign/warning/electricshock{ - pixel_y = -32 - }, -/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ - dir = 4 - }, /turf/open/floor/plating, /area/engine/gravity_generator) "bHP" = ( -/obj/machinery/light, -/obj/machinery/status_display/evac{ - pixel_y = -32 - }, -/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ - dir = 4 - }, -/obj/machinery/camera{ - c_tag = "Engineering - Gravity Generator"; - dir = 1; - name = "engineering camera" - }, +/obj/effect/decal/cleanable/dirt, /obj/effect/turf_decal/stripes/line{ - dir = 10 + dir = 8 }, /turf/open/floor/plasteel, /area/engine/gravity_generator) "bHQ" = ( -/obj/effect/decal/cleanable/dirt, -/obj/machinery/airalarm{ - dir = 1; - pixel_y = -22 - }, -/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ +/obj/machinery/atmospherics/components/unary/vent_scrubber/on{ dir = 4 }, -/obj/effect/turf_decal/stripes/line, +/obj/effect/turf_decal/tile/neutral{ + dir = 1 + }, +/obj/effect/turf_decal/tile/neutral, +/obj/effect/turf_decal/tile/neutral{ + dir = 4 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 8 + }, /turf/open/floor/plasteel, /area/engine/gravity_generator) "bHR" = ( -/obj/machinery/newscaster{ - pixel_y = -32 - }, -/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ - dir = 9 +/obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden{ + dir = 1 }, /obj/effect/turf_decal/stripes/line{ - dir = 6 + dir = 4 }, /turf/open/floor/plasteel, /area/engine/gravity_generator) "bHS" = ( -/obj/machinery/firealarm{ - dir = 8; - pixel_x = 24 +/obj/effect/decal/cleanable/dirt, +/obj/machinery/power/port_gen/pacman, +/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ + dir = 4 }, -/obj/machinery/light_switch{ - pixel_y = -26 - }, -/obj/structure/table/reinforced, -/obj/item/stack/sheet/plasteel/twenty, -/obj/item/wrench, /obj/effect/turf_decal/bot, /turf/open/floor/plasteel, /area/engine/gravity_generator) @@ -49710,27 +49604,23 @@ /obj/structure/cable/white{ icon_state = "1-2" }, -/obj/machinery/door/poddoor/preopen{ - id = "transitlock"; - name = "Transit Tube Lockdown Door" +/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ + dir = 4 }, /obj/machinery/atmospherics/pipe/simple/supply/hidden, -/obj/effect/turf_decal/stripes/line, /obj/effect/turf_decal/stripes/line{ - dir = 1 + dir = 10 }, /turf/open/floor/plasteel, /area/engine/gravity_generator) "bHU" = ( -/obj/effect/decal/cleanable/dirt, -/obj/machinery/door/poddoor/preopen{ - id = "transitlock"; - name = "Transit Tube Lockdown Door" +/obj/machinery/status_display/evac{ + pixel_x = 32; + pixel_y = -32 }, -/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, -/obj/effect/turf_decal/stripes/line, -/obj/effect/turf_decal/stripes/line{ - dir = 1 +/obj/effect/turf_decal/delivery, +/obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden{ + dir = 4 }, /turf/open/floor/plasteel, /area/engine/gravity_generator) @@ -51017,27 +50907,30 @@ /obj/structure/cable/white{ icon_state = "1-2" }, -/obj/machinery/door/airlock/hatch{ - name = "MiniSat Transit Tube Access"; - req_one_access_txt = "32;19" +/obj/machinery/door/poddoor/preopen{ + id = "transitlock"; + name = "Transit Tube Lockdown Door" }, /obj/machinery/atmospherics/pipe/simple/supply/hidden, -/obj/effect/turf_decal/tile/neutral{ +/obj/effect/turf_decal/stripes/line, +/obj/effect/turf_decal/stripes/line{ dir = 1 }, -/obj/effect/turf_decal/tile/neutral, -/obj/effect/turf_decal/tile/neutral{ - dir = 4 - }, -/obj/effect/turf_decal/tile/neutral{ - dir = 8 - }, -/turf/open/floor/plasteel/dark, -/area/engine/transit_tube) +/turf/open/floor/plasteel, +/area/engine/gravity_generator) "bJP" = ( +/obj/effect/decal/cleanable/dirt, +/obj/machinery/door/poddoor/preopen{ + id = "transitlock"; + name = "Transit Tube Lockdown Door" + }, /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, -/turf/closed/wall/r_wall, -/area/engine/transit_tube) +/obj/effect/turf_decal/stripes/line, +/obj/effect/turf_decal/stripes/line{ + dir = 1 + }, +/turf/open/floor/plasteel, +/area/engine/gravity_generator) "bJQ" = ( /obj/item/kirbyplants/random, /obj/effect/turf_decal/tile/neutral{ @@ -52186,50 +52079,54 @@ /turf/closed/wall/r_wall, /area/engine/transit_tube) "bLG" = ( -/obj/structure/closet/emcloset/anchored, -/obj/effect/turf_decal/tile/neutral{ - dir = 1 +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/command/glass{ + name = "Gravity Generator Chamber"; + req_access_txt = "19; 61" }, -/obj/effect/turf_decal/tile/neutral, -/obj/effect/turf_decal/tile/neutral{ - dir = 4 - }, -/obj/effect/turf_decal/tile/neutral{ +/obj/effect/turf_decal/stripes/line{ dir = 8 }, -/turf/open/floor/plasteel/dark, -/area/engine/transit_tube) -"bLH" = ( -/obj/machinery/status_display/evac, -/turf/closed/wall, -/area/engine/transit_tube) -"bLI" = ( -/obj/machinery/power/apc/highcap/five_k{ - areastring = "/area/engine/transit_tube"; - dir = 1; - name = "Transit Tube Access APC"; - pixel_y = 24 - }, -/obj/machinery/atmospherics/components/unary/vent_pump/on, -/obj/effect/turf_decal/tile/neutral{ - dir = 1 - }, -/obj/effect/turf_decal/tile/neutral, -/obj/effect/turf_decal/tile/neutral{ +/obj/effect/turf_decal/stripes/line{ dir = 4 }, -/obj/effect/turf_decal/tile/neutral{ - dir = 8 - }, /obj/structure/cable/white{ - icon_state = "0-4" + icon_state = "1-4" + }, +/obj/structure/cable/white{ + icon_state = "2-4" + }, +/turf/open/floor/plasteel, +/area/engine/gravity_generator) +"bLH" = ( +/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ + dir = 4 + }, +/turf/closed/wall, +/area/engine/break_room) +"bLI" = ( +/obj/machinery/gravity_generator/main/station, +/obj/effect/turf_decal/bot_white, +/obj/effect/turf_decal/tile/neutral{ + dir = 1 + }, +/obj/effect/turf_decal/tile/neutral, +/obj/effect/turf_decal/tile/neutral{ + dir = 4 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 8 }, /turf/open/floor/plasteel/dark, -/area/engine/transit_tube) +/area/engine/gravity_generator) "bLJ" = ( /obj/structure/cable/white{ icon_state = "1-2" }, +/obj/machinery/door/airlock/hatch{ + name = "MiniSat Transit Tube Access"; + req_one_access_txt = "32;19" + }, /obj/machinery/atmospherics/pipe/simple/supply/hidden, /obj/effect/turf_decal/tile/neutral{ dir = 1 @@ -52241,35 +52138,11 @@ /obj/effect/turf_decal/tile/neutral{ dir = 8 }, -/obj/structure/cable/white{ - icon_state = "1-8" - }, /turf/open/floor/plasteel/dark, /area/engine/transit_tube) "bLK" = ( -/obj/item/kirbyplants/random, -/obj/machinery/firealarm{ - dir = 8; - pixel_x = 24 - }, -/obj/machinery/button/door{ - id = "transitlock"; - name = "Transit Tube Lockdown Control"; - pixel_y = 26; - req_access_txt = "39; 19" - }, /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, -/obj/effect/turf_decal/tile/neutral{ - dir = 1 - }, -/obj/effect/turf_decal/tile/neutral, -/obj/effect/turf_decal/tile/neutral{ - dir = 4 - }, -/obj/effect/turf_decal/tile/neutral{ - dir = 8 - }, -/turf/open/floor/plasteel/dark, +/turf/closed/wall/r_wall, /area/engine/transit_tube) "bLL" = ( /obj/item/kirbyplants/random, @@ -53595,29 +53468,14 @@ /turf/open/space, /area/space/nearstation) "bNH" = ( -/obj/structure/lattice/catwalk, -/obj/structure/cable/white{ - icon_state = "2-4" +/obj/structure/sign/warning/radiation, +/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ + dir = 4 }, -/obj/machinery/atmospherics/pipe/simple/supply/hidden{ - dir = 6 - }, -/turf/open/space, -/area/space/nearstation) +/turf/closed/wall/r_wall, +/area/engine/gravity_generator) "bNI" = ( -/obj/structure/cable/white{ - icon_state = "4-8" - }, -/obj/effect/mapping_helpers/airlock/cyclelink_helper{ - dir = 4 - }, -/obj/machinery/door/airlock/hatch{ - name = "MiniSat Exterior Access"; - req_one_access_txt = "32;19" - }, -/obj/machinery/atmospherics/pipe/simple/supply/hidden{ - dir = 4 - }, +/obj/structure/closet/emcloset/anchored, /obj/effect/turf_decal/tile/neutral{ dir = 1 }, @@ -53631,12 +53489,6 @@ /turf/open/floor/plasteel/dark, /area/engine/transit_tube) "bNJ" = ( -/obj/structure/cable/white{ - icon_state = "4-8" - }, -/obj/machinery/atmospherics/pipe/simple/supply/hidden{ - dir = 4 - }, /obj/effect/turf_decal/tile/neutral{ dir = 1 }, @@ -53647,39 +53499,21 @@ /obj/effect/turf_decal/tile/neutral{ dir = 8 }, +/obj/structure/closet/firecloset, /turf/open/floor/plasteel/dark, /area/engine/transit_tube) "bNK" = ( -/obj/structure/cable/white{ - icon_state = "4-8" - }, -/obj/effect/mapping_helpers/airlock/cyclelink_helper{ - dir = 8 - }, -/obj/machinery/door/airlock/hatch{ - name = "MiniSat Exterior Access"; - req_one_access_txt = "32;19" - }, -/obj/machinery/atmospherics/pipe/simple/supply/hidden{ - dir = 4 - }, -/obj/effect/turf_decal/tile/neutral{ - dir = 1 - }, -/obj/effect/turf_decal/tile/neutral, -/obj/effect/turf_decal/tile/neutral{ - dir = 4 - }, -/obj/effect/turf_decal/tile/neutral{ - dir = 8 - }, -/turf/open/floor/plasteel/dark, +/obj/machinery/status_display/evac, +/turf/closed/wall, /area/engine/transit_tube) "bNL" = ( -/obj/structure/cable/white{ - icon_state = "4-8" +/obj/machinery/power/apc/highcap/five_k{ + areastring = "/area/engine/transit_tube"; + dir = 1; + name = "Transit Tube Access APC"; + pixel_y = 24 }, -/obj/machinery/atmospherics/pipe/manifold/supply/hidden, +/obj/machinery/atmospherics/components/unary/vent_pump/on, /obj/effect/turf_decal/tile/neutral{ dir = 1 }, @@ -53690,15 +53524,16 @@ /obj/effect/turf_decal/tile/neutral{ dir = 8 }, +/obj/structure/cable/white{ + icon_state = "0-4" + }, /turf/open/floor/plasteel/dark, /area/engine/transit_tube) "bNM" = ( /obj/structure/cable/white{ - icon_state = "1-8" - }, -/obj/machinery/atmospherics/pipe/simple/supply/hidden{ - dir = 9 + icon_state = "1-2" }, +/obj/machinery/atmospherics/pipe/simple/supply/hidden, /obj/effect/turf_decal/tile/neutral{ dir = 1 }, @@ -53709,11 +53544,22 @@ /obj/effect/turf_decal/tile/neutral{ dir = 8 }, +/obj/structure/cable/white{ + icon_state = "1-8" + }, /turf/open/floor/plasteel/dark, /area/engine/transit_tube) "bNN" = ( -/obj/machinery/light/small{ - dir = 4 +/obj/item/kirbyplants/random, +/obj/machinery/firealarm{ + dir = 8; + pixel_x = 24 + }, +/obj/machinery/button/door{ + id = "transitlock"; + name = "Transit Tube Lockdown Control"; + pixel_y = 26; + req_access_txt = "39; 19" }, /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, /obj/effect/turf_decal/tile/neutral{ @@ -54901,9 +54747,38 @@ /turf/open/space, /area/space/nearstation) "bPL" = ( +/obj/structure/cable/white{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/supply/hidden{ + dir = 4 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 1 + }, +/obj/effect/turf_decal/tile/neutral, +/obj/effect/turf_decal/tile/neutral{ + dir = 4 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 8 + }, /obj/machinery/light/small, -/obj/structure/sign/warning/vacuum{ - pixel_x = -32 +/turf/open/floor/plasteel/dark, +/area/engine/transit_tube) +"bPM" = ( +/obj/structure/cable/white{ + icon_state = "4-8" + }, +/obj/effect/mapping_helpers/airlock/cyclelink_helper{ + dir = 8 + }, +/obj/machinery/door/airlock/hatch{ + name = "MiniSat Exterior Access"; + req_one_access_txt = "32;19" + }, +/obj/machinery/atmospherics/pipe/simple/supply/hidden{ + dir = 4 }, /obj/effect/turf_decal/tile/neutral{ dir = 1 @@ -54917,20 +54792,11 @@ }, /turf/open/floor/plasteel/dark, /area/engine/transit_tube) -"bPM" = ( -/turf/closed/wall, -/area/engine/transit_tube) "bPN" = ( -/obj/item/kirbyplants/random, -/obj/machinery/airalarm{ - dir = 4; - pixel_x = -23 - }, -/obj/machinery/flasher{ - id = "AI"; - pixel_x = -26; - pixel_y = -26 +/obj/structure/cable/white{ + icon_state = "4-8" }, +/obj/machinery/atmospherics/pipe/manifold/supply/hidden, /obj/effect/turf_decal/tile/neutral{ dir = 1 }, @@ -54944,6 +54810,9 @@ /turf/open/floor/plasteel/dark, /area/engine/transit_tube) "bPO" = ( +/obj/structure/cable/white{ + icon_state = "1-8" + }, /obj/effect/turf_decal/tile/neutral{ dir = 1 }, @@ -54954,15 +54823,16 @@ /obj/effect/turf_decal/tile/neutral{ dir = 8 }, +/obj/machinery/atmospherics/pipe/manifold/supply/hidden{ + dir = 4 + }, /turf/open/floor/plasteel/dark, /area/engine/transit_tube) "bPP" = ( -/obj/item/kirbyplants/random, -/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, -/obj/machinery/light_switch{ - pixel_x = 22; - pixel_y = -10 +/obj/machinery/light/small{ + dir = 4 }, +/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, /obj/effect/turf_decal/tile/neutral{ dir = 1 }, @@ -56192,13 +56062,15 @@ /turf/open/space, /area/space/nearstation) "bRV" = ( -/obj/effect/spawner/structure/window/reinforced, -/turf/open/floor/plating, -/area/engine/transit_tube) -"bRW" = ( -/obj/machinery/door/airlock/hatch{ - name = "MiniSat Transit Tube Access"; - req_one_access_txt = "32;19" +/obj/item/kirbyplants/random, +/obj/machinery/airalarm{ + dir = 4; + pixel_x = -23 + }, +/obj/machinery/flasher{ + id = "AI"; + pixel_x = -26; + pixel_y = -26 }, /obj/effect/turf_decal/tile/neutral{ dir = 1 @@ -56212,10 +56084,38 @@ }, /turf/open/floor/plasteel/dark, /area/engine/transit_tube) +"bRW" = ( +/obj/effect/turf_decal/tile/neutral{ + dir = 1 + }, +/obj/effect/turf_decal/tile/neutral, +/obj/effect/turf_decal/tile/neutral{ + dir = 4 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/supply/hidden, +/turf/open/floor/plasteel/dark, +/area/engine/transit_tube) "bRX" = ( -/obj/effect/spawner/structure/window/reinforced, +/obj/item/kirbyplants/random, /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, -/turf/open/floor/plating, +/obj/machinery/light_switch{ + pixel_x = 22; + pixel_y = -10 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 1 + }, +/obj/effect/turf_decal/tile/neutral, +/obj/effect/turf_decal/tile/neutral{ + dir = 4 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 8 + }, +/turf/open/floor/plasteel/dark, /area/engine/transit_tube) "bRY" = ( /obj/machinery/keycard_auth{ @@ -57376,22 +57276,9 @@ /turf/open/space, /area/space/nearstation) "bTL" = ( -/obj/structure/window/reinforced{ - dir = 8 +/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ + dir = 5 }, -/obj/structure/table/reinforced, -/obj/machinery/light/small{ - dir = 1 - }, -/obj/machinery/camera{ - c_tag = "AI Satellite - Transit Tube"; - name = "ai camera"; - network = list("minisat"); - start_active = 1 - }, -/obj/item/clipboard, -/obj/item/folder/blue, -/obj/item/pen, /obj/effect/turf_decal/tile/neutral{ dir = 1 }, @@ -57403,30 +57290,16 @@ dir = 8 }, /turf/open/floor/plasteel/dark, -/area/engine/transit_tube) +/area/engine/gravity_generator) "bTM" = ( -/obj/structure/chair/office/dark{ - dir = 8 - }, -/obj/machinery/flasher{ - id = "AI"; - pixel_x = -26; - pixel_y = 26 - }, -/obj/effect/turf_decal/tile/neutral{ - dir = 1 - }, -/obj/effect/turf_decal/tile/neutral, -/obj/effect/turf_decal/tile/neutral{ - dir = 4 - }, -/obj/effect/turf_decal/tile/neutral{ - dir = 8 - }, -/turf/open/floor/plasteel/dark, +/obj/effect/spawner/structure/window/reinforced, +/turf/open/floor/plating, /area/engine/transit_tube) "bTN" = ( -/obj/machinery/atmospherics/components/unary/vent_scrubber/on, +/obj/machinery/door/airlock/hatch{ + name = "MiniSat Transit Tube Access"; + req_one_access_txt = "32;19" + }, /obj/effect/turf_decal/tile/neutral{ dir = 1 }, @@ -57437,22 +57310,13 @@ /obj/effect/turf_decal/tile/neutral{ dir = 8 }, +/obj/machinery/atmospherics/pipe/simple/supply/hidden, /turf/open/floor/plasteel/dark, /area/engine/transit_tube) "bTO" = ( -/obj/item/kirbyplants/random, +/obj/effect/spawner/structure/window/reinforced, /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, -/obj/effect/turf_decal/tile/neutral{ - dir = 1 - }, -/obj/effect/turf_decal/tile/neutral, -/obj/effect/turf_decal/tile/neutral{ - dir = 4 - }, -/obj/effect/turf_decal/tile/neutral{ - dir = 8 - }, -/turf/open/floor/plasteel/dark, +/turf/open/floor/plating, /area/engine/transit_tube) "bTP" = ( /obj/machinery/computer/station_alert{ @@ -59145,9 +59009,6 @@ /turf/open/floor/plasteel/dark, /area/engine/transit_tube) "bWc" = ( -/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ - dir = 4 - }, /obj/effect/turf_decal/tile/neutral{ dir = 1 }, @@ -59158,10 +59019,15 @@ /obj/effect/turf_decal/tile/neutral{ dir = 8 }, +/obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden{ + dir = 1 + }, +/obj/structure/chair/office/light{ + dir = 8 + }, /turf/open/floor/plasteel/dark, /area/engine/transit_tube) "bWd" = ( -/obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden, /obj/effect/turf_decal/tile/neutral{ dir = 1 }, @@ -59172,6 +59038,12 @@ /obj/effect/turf_decal/tile/neutral{ dir = 8 }, +/obj/machinery/atmospherics/components/unary/vent_pump/on{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ + dir = 4 + }, /turf/open/floor/plasteel/dark, /area/engine/transit_tube) "bWe" = ( @@ -60847,6 +60719,9 @@ /obj/effect/turf_decal/tile/neutral{ dir = 8 }, +/obj/machinery/atmospherics/components/unary/vent_scrubber/on{ + dir = 1 + }, /turf/open/floor/plasteel/dark, /area/engine/transit_tube) "bYp" = ( @@ -72264,7 +72139,7 @@ pixel_y = 32 }, /turf/open/space, -/area/space/nearstation) +/area/space) "crE" = ( /obj/structure/window/reinforced, /obj/structure/window/reinforced{ @@ -83035,22 +82910,16 @@ /turf/open/floor/plasteel, /area/crew_quarters/fitness/recreation) "cJI" = ( -/obj/effect/mapping_helpers/airlock/cyclelink_helper{ +/obj/structure/cable/white, +/obj/effect/spawner/structure/window/reinforced, +/obj/structure/sign/warning/electricshock{ + pixel_y = -32 + }, +/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ dir = 4 }, -/obj/machinery/door/airlock/external{ - name = "External Airlock"; - req_access_txt = "13" - }, -/obj/effect/decal/cleanable/dirt, -/obj/effect/turf_decal/stripes/line{ - dir = 8 - }, -/obj/effect/turf_decal/stripes/line{ - dir = 4 - }, -/turf/open/floor/plasteel, -/area/maintenance/port) +/turf/open/floor/plating, +/area/engine/gravity_generator) "cJJ" = ( /obj/effect/mapping_helpers/airlock/cyclelink_helper{ dir = 8 @@ -108364,19 +108233,7 @@ /obj/structure/cable{ icon_state = "4-8" }, -/obj/effect/mapping_helpers/airlock/cyclelink_helper{ - dir = 8 - }, -/obj/machinery/door/airlock/external{ - name = "External Solar Access"; - req_access_txt = "10; 13" - }, -/obj/effect/turf_decal/stripes/line{ - dir = 8 - }, -/obj/effect/turf_decal/stripes/line{ - dir = 4 - }, +/obj/effect/turf_decal/delivery, /turf/open/floor/plasteel, /area/maintenance/solars/starboard/aft) "dBN" = ( @@ -115581,6 +115438,10 @@ /turf/open/floor/plasteel, /area/maintenance/port/aft) "dOc" = ( +/obj/effect/decal/cleanable/dirt, +/turf/open/floor/plasteel, +/area/maintenance/port/aft) +"dOd" = ( /obj/effect/mapping_helpers/airlock/cyclelink_helper{ dir = 8 }, @@ -115597,11 +115458,6 @@ }, /turf/open/floor/plasteel, /area/maintenance/port/aft) -"dOd" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/turf_decal/delivery, -/turf/open/floor/plasteel, -/area/maintenance/port/aft) "dOe" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/turf_decal/tile/neutral{ @@ -115610,6 +115466,7 @@ /obj/effect/turf_decal/tile/neutral{ dir = 8 }, +/obj/effect/turf_decal/delivery, /turf/open/floor/plasteel{ heat_capacity = 1e+006 }, @@ -122648,19 +122505,7 @@ /obj/structure/cable{ icon_state = "4-8" }, -/obj/effect/mapping_helpers/airlock/cyclelink_helper{ - dir = 4 - }, -/obj/machinery/door/airlock/external{ - name = "External Solar Access"; - req_access_txt = "10; 13" - }, -/obj/effect/turf_decal/stripes/line{ - dir = 8 - }, -/obj/effect/turf_decal/stripes/line{ - dir = 4 - }, +/obj/effect/turf_decal/delivery, /turf/open/floor/plasteel, /area/maintenance/solars/port/aft) "ebE" = ( @@ -124004,14 +123849,16 @@ /turf/open/floor/plasteel/grimy, /area/chapel/office) "edX" = ( -/obj/machinery/door/airlock/maintenance_hatch{ - name = "Maintenance Hatch"; - req_access_txt = "12" - }, /obj/effect/turf_decal/stripes/line, /obj/effect/turf_decal/stripes/line{ dir = 1 }, +/obj/machinery/door/airlock/external{ + name = "External Airlock"; + req_access_txt = "13" + }, +/obj/effect/mapping_helpers/airlock/cyclelink_helper, +/obj/machinery/door/firedoor, /turf/open/floor/plasteel, /area/hallway/secondary/exit/departure_lounge) "edY" = ( @@ -124731,16 +124578,6 @@ /turf/open/floor/carpet, /area/chapel/office) "eft" = ( -/obj/machinery/door/firedoor, -/obj/effect/mapping_helpers/airlock/cyclelink_helper, -/obj/machinery/door/airlock/external{ - name = "External Airlock"; - req_access_txt = "13" - }, -/obj/effect/turf_decal/stripes/line, -/obj/effect/turf_decal/stripes/line{ - dir = 1 - }, /turf/open/floor/plasteel, /area/hallway/secondary/exit/departure_lounge) "efu" = ( @@ -125581,6 +125418,24 @@ /obj/machinery/chem_dispenser/apothecary, /turf/open/floor/plasteel/dark, /area/medical/medbay/central) +"eMb" = ( +/obj/effect/decal/cleanable/dirt, +/obj/structure/closet/crate{ + icon_state = "crateopen" + }, +/obj/item/flashlight, +/obj/effect/spawner/lootdrop/maintenance, +/obj/effect/turf_decal/tile/neutral{ + dir = 1 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 4 + }, +/obj/effect/turf_decal/bot, +/turf/open/floor/plasteel{ + heat_capacity = 1e+006 + }, +/area/maintenance/port) "eMD" = ( /obj/effect/decal/cleanable/dirt, /obj/structure/cable/white{ @@ -125733,6 +125588,9 @@ }, /turf/closed/wall/r_wall, /area/maintenance/disposal/incinerator) +"fMf" = ( +/turf/closed/wall, +/area/engine/transit_tube) "fRK" = ( /obj/effect/turf_decal/tile/neutral{ dir = 1 @@ -126013,10 +125871,27 @@ /turf/open/floor/plating, /area/chapel/office) "ijB" = ( -/obj/structure/reagent_dispensers/keg/aphro/strong, /obj/item/reagent_containers/glass/beaker, /turf/open/floor/plating, /area/crew_quarters/abandoned_gambling_den) +"ikq" = ( +/obj/machinery/light, +/obj/machinery/status_display/evac{ + pixel_y = -32 + }, +/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ + dir = 4 + }, +/obj/machinery/camera{ + c_tag = "Engineering - Gravity Generator"; + dir = 1; + name = "engineering camera" + }, +/obj/effect/turf_decal/stripes/line{ + dir = 10 + }, +/turf/open/floor/plasteel, +/area/engine/gravity_generator) "imI" = ( /obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden, /obj/effect/turf_decal/tile/neutral{ @@ -126144,6 +126019,25 @@ }, /turf/open/floor/plasteel/dark, /area/science/mixing) +"iUc" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/effect/mapping_helpers/airlock/cyclelink_helper{ + dir = 4 + }, +/obj/machinery/door/airlock/external{ + name = "External Solar Access"; + req_access_txt = "10; 13" + }, +/obj/effect/turf_decal/stripes/line{ + dir = 8 + }, +/obj/effect/turf_decal/stripes/line{ + dir = 4 + }, +/turf/open/floor/plasteel, +/area/maintenance/solars/port/aft) "jdx" = ( /obj/structure/lattice, /obj/structure/grille, @@ -126345,6 +126239,9 @@ /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, /turf/open/floor/plating, /area/science/mixing) +"jUu" = ( +/turf/closed/wall/r_wall, +/area/space/nearstation) "jYx" = ( /obj/effect/turf_decal/bot, /obj/machinery/portable_atmospherics/canister/carbon_dioxide, @@ -126385,6 +126282,13 @@ }, /turf/open/space, /area/engine/atmos) +"kqo" = ( +/obj/structure/cable/white{ + icon_state = "4-8" + }, +/mob/living/simple_animal/opossum, +/turf/open/floor/plating, +/area/maintenance/port/fore) "ktK" = ( /obj/effect/turf_decal/tile/neutral{ dir = 4 @@ -126730,6 +126634,20 @@ }, /turf/open/floor/plasteel/dark, /area/science/mixing) +"mte" = ( +/obj/machinery/firealarm{ + dir = 8; + pixel_x = 24 + }, +/obj/machinery/light_switch{ + pixel_y = -26 + }, +/obj/structure/table/reinforced, +/obj/item/stack/sheet/plasteel/twenty, +/obj/item/wrench, +/obj/effect/turf_decal/bot, +/turf/open/floor/plasteel, +/area/engine/gravity_generator) "mvm" = ( /obj/effect/decal/cleanable/dirt, /obj/structure/cable/white{ @@ -126871,6 +126789,18 @@ }, /turf/open/floor/plasteel, /area/maintenance/port/fore) +"nYv" = ( +/obj/machinery/newscaster{ + pixel_y = -32 + }, +/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ + dir = 9 + }, +/obj/effect/turf_decal/stripes/line{ + dir = 6 + }, +/turf/open/floor/plasteel, +/area/engine/gravity_generator) "odz" = ( /obj/machinery/atmospherics/pipe/manifold/supply/hidden{ dir = 1 @@ -127043,6 +126973,10 @@ dir = 1 }, /area/science/circuit) +"pok" = ( +/mob/living/simple_animal/opossum/poppy, +/turf/open/floor/plasteel/grimy, +/area/crew_quarters/theatre/abandoned) "poI" = ( /obj/structure/bed, /obj/item/tank/internals/anesthetic, @@ -127161,6 +127095,25 @@ dir = 9 }, /area/science/circuit) +"qhB" = ( +/obj/structure/cable/white{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/supply/hidden{ + dir = 4 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 1 + }, +/obj/effect/turf_decal/tile/neutral, +/obj/effect/turf_decal/tile/neutral{ + dir = 4 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 8 + }, +/turf/open/floor/plasteel/dark, +/area/engine/transit_tube) "qnx" = ( /obj/machinery/atmospherics/components/unary/outlet_injector/atmos/toxins_mixing_input, /turf/open/floor/engine/vacuum, @@ -127398,6 +127351,25 @@ }, /turf/open/floor/plasteel/grimy, /area/library) +"tML" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/effect/mapping_helpers/airlock/cyclelink_helper{ + dir = 8 + }, +/obj/machinery/door/airlock/external{ + name = "External Solar Access"; + req_access_txt = "10; 13" + }, +/obj/effect/turf_decal/stripes/line{ + dir = 8 + }, +/obj/effect/turf_decal/stripes/line{ + dir = 4 + }, +/turf/open/floor/plasteel, +/area/maintenance/solars/starboard/aft) "tNT" = ( /obj/effect/landmark/carpspawn, /turf/open/space, @@ -127643,6 +127615,32 @@ /obj/machinery/atmospherics/pipe/simple/green/visible, /turf/open/floor/plasteel/dark, /area/engine/atmos) +"vFT" = ( +/obj/structure/cable/white{ + icon_state = "4-8" + }, +/obj/effect/mapping_helpers/airlock/cyclelink_helper{ + dir = 4 + }, +/obj/machinery/door/airlock/hatch{ + name = "MiniSat Exterior Access"; + req_one_access_txt = "32;19" + }, +/obj/machinery/atmospherics/pipe/simple/supply/hidden{ + dir = 4 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 1 + }, +/obj/effect/turf_decal/tile/neutral, +/obj/effect/turf_decal/tile/neutral{ + dir = 4 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 8 + }, +/turf/open/floor/plasteel/dark, +/area/engine/transit_tube) "vHN" = ( /obj/machinery/atmospherics/pipe/simple/supply/hidden, /obj/effect/turf_decal/tile/neutral{ @@ -127678,6 +127676,18 @@ }, /turf/open/floor/plasteel, /area/maintenance/port/aft) +"vYo" = ( +/obj/effect/decal/cleanable/dirt, +/obj/machinery/airalarm{ + dir = 1; + pixel_y = -22 + }, +/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ + dir = 4 + }, +/obj/effect/turf_decal/stripes/line, +/turf/open/floor/plasteel, +/area/engine/gravity_generator) "wei" = ( /obj/effect/turf_decal/stripes/line, /turf/open/floor/plasteel, @@ -127740,6 +127750,16 @@ /obj/effect/turf_decal/tile/purple, /turf/open/floor/plasteel/white, /area/science/misc_lab) +"wFK" = ( +/obj/structure/lattice/catwalk, +/obj/structure/cable/white{ + icon_state = "2-4" + }, +/obj/machinery/atmospherics/pipe/simple/supply/hidden{ + dir = 6 + }, +/turf/open/space, +/area/space/nearstation) "wZT" = ( /obj/effect/turf_decal/tile/neutral{ dir = 8 @@ -127962,6 +127982,23 @@ }, /turf/open/floor/plating, /area/engine/atmos) +"yja" = ( +/obj/effect/mapping_helpers/airlock/cyclelink_helper{ + dir = 4 + }, +/obj/machinery/door/airlock/external{ + name = "External Airlock"; + req_access_txt = "13" + }, +/obj/effect/decal/cleanable/dirt, +/obj/effect/turf_decal/stripes/line{ + dir = 8 + }, +/obj/effect/turf_decal/stripes/line{ + dir = 4 + }, +/turf/open/floor/plasteel, +/area/maintenance/port) "yjc" = ( /obj/machinery/power/apc{ areastring = "/area/science/research/abandoned"; @@ -145304,12 +145341,12 @@ aaa aaa aaa aaa +aaa ajr ajr aad ajr ajr -ajr aad ajr ajr @@ -145561,11 +145598,11 @@ aaa aaa aaa aaa +aaa ajr aaa aaa aad -aaa aad aaa aad @@ -145818,11 +145855,11 @@ aaa aaa aaa aaa +aaa ajr aad ajr ajr -aad ajr ajr ajr @@ -146075,6 +146112,7 @@ aaa aaa aaa aaa +aaa ajr aaa ajr @@ -146086,7 +146124,6 @@ aad aad aad aad -aad ajr aaa bNF @@ -146332,6 +146369,7 @@ aaa aaa aaa aaa +aaa aad aaa ajr @@ -146342,12 +146380,11 @@ bxC bxC bxC bxC -bxC -aad +jUu aad aad bNF -aad +qgU bVZ aad aad @@ -146589,20 +146626,20 @@ aaa aaa aaa aaa -ajr -aad -ajr -aad -bxC -bAH -bAH -bEn -bAH -bAH -bxC -aad -ajr aaa +ajr +aad +ajr +aad +bxC +bAH +bAH +bFX +bAH +bAH +jUu +aad +ajr bNF aaa bVZ @@ -146846,20 +146883,20 @@ aaa aaa aaa aaa +aaa ajr aaa aad aad bxC bAH -bCw bCx -bCy +bEo +bCF bAH -bxC +jUu aad ajr -aaa bNF aaa bVZ @@ -146886,8 +146923,8 @@ cdB cdB cdB car -aad -abj +caE +yja caE caE cOj @@ -147080,7 +147117,7 @@ aAP aAP avY ask -ask +bAL aad abj abj @@ -147103,22 +147140,22 @@ aaa aaa aaa aaa +aaa ajr aad ajr aad bxC bAH -bCx bEo bFW +bLI bAH -bxC -aad +jUu aad aad bNF -aad +qgU bVY aad aad @@ -147143,8 +147180,8 @@ car car car car -caE -cJI +eMb +cqI caE cme cOk @@ -147336,9 +147373,9 @@ aad aad aad aad -aad -apK -aad +aFp +bAM +aFp aLb aad aaa @@ -147360,20 +147397,20 @@ aaa aaa aaa aaa +aaa aad aaa ajr aad bxC bAH -bCy +bCF +bEo bCx -bCw bAH -bxC +jUu aad ajr -aaa bNF aaa bVZ @@ -147618,19 +147655,19 @@ ajr ajr aad ajr +ajr aad ajr aad bxC -bAI bCz +bEn bAH -bFX bHN -bxC +bTL +jUu aad aad -aaa bNF aaa bVZ @@ -147878,18 +147915,18 @@ aad aaa aaa aad +aad bxC -bAJ -bCA -bEp bCA bHO -bxC +bLG +bHO +cJI +jUu aad -bNH -bPK +wFK bRU -aad +qgU bVZ aad car @@ -148135,18 +148172,18 @@ ajr ajr aad aad +aad bxC -bAK bCB bEq bFY bHP -bxC -aad -bNF -aad -aad -aad +ikq +bLF +bLF +vFT +bLF +qgU bVZ aad car @@ -148392,18 +148429,18 @@ aad aad aad aad +aad bxC -bAL bCC bEr bFZ bHQ -bxC +vYo bLF bNI +qhB bLF -bLF -aad +qgU bVZ aad car @@ -148649,18 +148686,18 @@ aRF aRF aad aad +aad bxC -bAM bCD bEs bGa bHR -bxC -bLG +nYv +bLF bNJ bPL bLF -bTK +qgU bWa bTK car @@ -148906,18 +148943,18 @@ bpO aRF aad aad +aad bxC -bAN bCE bEt bGb bHS -bxC -bLH +mte +bLF bNK bPM +fMf bLF -bTL bWb bYn car @@ -149162,15 +149199,15 @@ bpO btK aRF aad +qgU +qgU bxC bxC -bxC -bCF bEu bGc +bNH bxC -bxC -bLI +bLF bNL bPN bRV @@ -149420,9 +149457,9 @@ btL aRF abj bxC -bzd -bAO -bCG +bxC +bxC +bCI bEv bGd bHT @@ -150193,9 +150230,9 @@ aMG bxE bzg bzg -bCJ -bEy bzg +bEy +bLH bHV bJQ bLL @@ -154650,7 +154687,7 @@ aaa aad aad aad -ajr +qgU aad ebC aad @@ -154908,9 +154945,9 @@ ajr aad aad aad -aad -ebC -aad +eak +iUc +eak aad aaa aac @@ -164028,7 +164065,7 @@ aof aky aky aky -arD +kqo asZ aui avF @@ -169905,8 +169942,8 @@ aaa aaa aaa aad -aad abi +bAI abR abi acp @@ -170162,9 +170199,9 @@ aaa aaa aaa abj -abj abH abS +abS acd acq acH @@ -170418,9 +170455,9 @@ aaa aaa aaa aaa -aaa -aad +qgU abi +bAJ abT abi acr @@ -170674,9 +170711,9 @@ aaa aaa aaa aaa -aaa -aac +jdx aad +bzd abi abi ace @@ -170931,8 +170968,8 @@ aaa aaa aaa aaa -aaa -aac +jdx +aad aad aad aad @@ -171188,7 +171225,7 @@ aaa aaa aaa aaa -aaa +aac aac aac aad @@ -172479,9 +172516,9 @@ aac aaa aad aad -aad -acQ -aad +acf +bAK +acf aad aaa abi @@ -172735,7 +172772,7 @@ aaa aac aac aad -aac +aad aad aaj aad @@ -178787,7 +178824,7 @@ dCX dEj dFq dGJ -dGJ +pok dJy dGJ dGJ @@ -182636,9 +182673,9 @@ aaA aaa aaa aad -aaa -dBN -aad +dyV +tML +dyV aad aaa aad @@ -182892,9 +182929,9 @@ aci aaA aaa aaa -ajr -aad -dBO +qgU +qgU +dBN aad aaa dFy @@ -184863,7 +184900,7 @@ aaa ajr ajr ajr -aaa +qgU aKZ aKZ aKZ @@ -185120,9 +185157,9 @@ aaa aaa aaa aaa -aaa -aaa +qgU abj +bAN aUK aWs aXT @@ -185378,11 +185415,11 @@ aaa aaa aaa aaa -aaa aad aKV aKV aKV +aKV aZK bbt aNJ diff --git a/_maps/map_files/KiloStation/KiloStation.dmm b/_maps/map_files/KiloStation/KiloStation.dmm index fbe5b954ff..518fa4e81e 100644 --- a/_maps/map_files/KiloStation/KiloStation.dmm +++ b/_maps/map_files/KiloStation/KiloStation.dmm @@ -2134,14 +2134,11 @@ /turf/open/floor/plasteel/dark, /area/maintenance/port) "adM" = ( -/obj/machinery/door/airlock/external{ - name = "Abandoned External Airlock" - }, -/obj/effect/mapping_helpers/airlock/cyclelink_helper, /obj/structure/cable{ icon_state = "1-2" }, -/turf/open/floor/plasteel/dark, +/obj/effect/decal/cleanable/dirt, +/turf/open/floor/plasteel, /area/maintenance/fore) "adN" = ( /obj/effect/turf_decal/loading_area{ @@ -2160,11 +2157,16 @@ /turf/open/floor/engine, /area/ai_monitored/storage/satellite) "adO" = ( +/obj/machinery/door/airlock/external{ + name = "Satellite External Airlock"; + req_one_access_txt = "32;19" + }, +/obj/effect/mapping_helpers/airlock/cyclelink_helper, /obj/machinery/atmospherics/pipe/simple/supply/hidden, /obj/structure/cable{ icon_state = "1-2" }, -/turf/open/floor/engine, +/turf/open/floor/plasteel/dark, /area/ai_monitored/turret_protected/aisat/atmos) "adP" = ( /obj/machinery/status_display/ai, @@ -2513,6 +2515,9 @@ /turf/open/floor/plating, /area/security/execution/education) "aeD" = ( +/obj/structure/cable{ + icon_state = "2-8" + }, /obj/structure/disposalpipe/segment, /turf/open/floor/plating/airless, /area/space/nearstation) @@ -2598,13 +2603,20 @@ }, /obj/machinery/light/small, /turf/open/floor/plating/airless, -/area/maintenance/starboard/fore) +/area/space/nearstation) "aeL" = ( +/obj/machinery/door/airlock/external{ + name = "Abandoned External Airlock" + }, +/obj/effect/mapping_helpers/airlock/cyclelink_helper, /obj/structure/cable{ - icon_state = "2-8" + icon_state = "1-2" + }, +/obj/structure/cable{ + icon_state = "1-2" }, /obj/structure/disposalpipe/segment, -/turf/open/floor/plating/airless, +/turf/open/floor/plasteel/dark, /area/maintenance/starboard/fore) "aeM" = ( /obj/machinery/photocopier, @@ -5704,13 +5716,6 @@ /turf/open/floor/plasteel/dark, /area/security/courtroom) "ajI" = ( -/obj/machinery/door/airlock/external{ - name = "Abandoned External Airlock" - }, -/obj/effect/mapping_helpers/airlock/cyclelink_helper, -/obj/structure/cable{ - icon_state = "1-2" - }, /obj/structure/cable{ icon_state = "1-2" }, @@ -6935,7 +6940,6 @@ dir = 4 }, /obj/structure/closet/emcloset/anchored, -/obj/effect/decal/cleanable/cobweb, /obj/machinery/light/small{ dir = 8 }, @@ -9658,12 +9662,19 @@ /turf/open/floor/plasteel/showroomfloor, /area/medical/genetics) "aqp" = ( +/obj/machinery/door/airlock/external{ + name = "Solar Maintenance"; + req_access_txt = "10; 13" + }, /obj/structure/cable{ icon_state = "4-8" }, -/obj/structure/lattice/catwalk, -/turf/open/floor/plating/airless, -/area/solar/port/fore) +/obj/effect/mapping_helpers/airlock/cyclelink_helper{ + dir = 4 + }, +/obj/effect/decal/cleanable/dirt, +/turf/open/floor/plating, +/area/maintenance/solars/port/fore) "aqq" = ( /obj/machinery/status_display/ai{ pixel_x = -32 @@ -12462,12 +12473,18 @@ /turf/open/floor/plasteel, /area/bridge) "auN" = ( +/obj/machinery/door/airlock/external{ + name = "Solar Maintenance"; + req_access_txt = "10; 13" + }, /obj/structure/cable{ icon_state = "4-8" }, -/obj/structure/lattice/catwalk, -/turf/open/floor/plating/airless, -/area/solar/starboard/fore) +/obj/effect/mapping_helpers/airlock/cyclelink_helper{ + dir = 8 + }, +/turf/open/floor/plating, +/area/maintenance/solars/starboard/fore) "auO" = ( /obj/effect/decal/cleanable/dirt, /obj/structure/cable{ @@ -64779,11 +64796,15 @@ /turf/open/floor/plasteel/dark, /area/hallway/primary/starboard) "bZG" = ( -/obj/structure/sign/warning/vacuum/external{ - pixel_y = 32 +/obj/machinery/door/airlock/external{ + name = "Abandoned External Airlock" }, -/turf/open/floor/plating/airless, -/area/space/nearstation) +/obj/effect/mapping_helpers/airlock/cyclelink_helper, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/open/floor/plasteel/dark, +/area/maintenance/fore) "bZH" = ( /obj/effect/turf_decal/tile/neutral{ dir = 1 @@ -64902,9 +64923,18 @@ /turf/open/floor/plasteel, /area/hallway/primary/starboard) "bZP" = ( -/obj/structure/cable, -/turf/open/floor/plating/airless, -/area/space/nearstation) +/obj/machinery/door/airlock/external{ + name = "Prison External Airlock"; + req_access_txt = "2" + }, +/obj/effect/mapping_helpers/airlock/cyclelink_helper{ + dir = 1 + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/open/floor/plasteel/dark, +/area/security/prison) "bZQ" = ( /obj/structure/closet/l3closet/janitor, /obj/structure/window/reinforced, @@ -67690,11 +67720,6 @@ }, /area/ai_monitored/turret_protected/ai) "ceA" = ( -/obj/machinery/door/airlock/external{ - name = "Satellite External Airlock"; - req_one_access_txt = "32;19" - }, -/obj/effect/mapping_helpers/airlock/cyclelink_helper, /obj/machinery/atmospherics/pipe/simple/supply/hidden, /obj/structure/cable{ icon_state = "1-2" @@ -69610,15 +69635,12 @@ /turf/open/floor/plasteel, /area/engine/atmos) "chO" = ( -/obj/structure/sign/warning/vacuum/external, -/turf/closed/wall, +/obj/structure/reagent_dispensers/fueltank, +/turf/open/floor/plasteel/dark, /area/ai_monitored/turret_protected/aisat/atmos) "chP" = ( -/obj/structure/reagent_dispensers/watertank, -/obj/structure/reagent_dispensers/watertank, -/obj/effect/turf_decal/delivery, -/obj/machinery/light, -/turf/open/floor/plasteel/dark, +/obj/structure/sign/warning/vacuum/external, +/turf/closed/wall, /area/ai_monitored/turret_protected/aisat/atmos) "chQ" = ( /obj/machinery/atmospherics/pipe/simple/supply/hidden{ @@ -69697,12 +69719,19 @@ /turf/open/floor/plasteel, /area/engine/engineering) "chU" = ( +/obj/machinery/door/airlock/external{ + name = "Solar Maintenance"; + req_access_txt = "10; 13" + }, /obj/structure/cable{ icon_state = "4-8" }, -/obj/structure/lattice/catwalk, -/turf/open/floor/plating/airless, -/area/solar/port/aft) +/obj/effect/mapping_helpers/airlock/cyclelink_helper{ + dir = 4 + }, +/obj/effect/decal/cleanable/dirt, +/turf/open/floor/plating, +/area/maintenance/solars/port/aft) "chW" = ( /obj/machinery/door/firedoor, /obj/machinery/door/airlock/hatch{ @@ -71343,16 +71372,9 @@ /turf/open/floor/plating, /area/engine/engineering) "ckJ" = ( -/obj/machinery/door/airlock/external{ - name = "Solar Maintenance"; - req_access_txt = "10; 13" - }, /obj/structure/cable{ icon_state = "4-8" }, -/obj/effect/mapping_helpers/airlock/cyclelink_helper{ - dir = 8 - }, /turf/open/floor/plating, /area/maintenance/solars/starboard/aft) "ckK" = ( @@ -71763,16 +71785,9 @@ /turf/open/space/basic, /area/space/nearstation) "clx" = ( -/obj/machinery/door/airlock/external{ - name = "Solar Maintenance"; - req_access_txt = "10; 13" - }, /obj/structure/cable{ icon_state = "4-8" }, -/obj/effect/mapping_helpers/airlock/cyclelink_helper{ - dir = 4 - }, /obj/effect/decal/cleanable/dirt, /turf/open/floor/plating, /area/maintenance/solars/port/aft) @@ -74873,6 +74888,9 @@ dir = 8 }, /obj/effect/decal/cleanable/dirt, +/obj/structure/cable{ + icon_state = "1-4" + }, /turf/open/floor/plating{ icon_state = "platingdmg1" }, @@ -74942,6 +74960,9 @@ /obj/machinery/atmospherics/pipe/simple/supply/hidden{ dir = 4 }, +/obj/structure/cable{ + icon_state = "4-8" + }, /turf/open/floor/plasteel/dark, /area/maintenance/disposal) "crg" = ( @@ -76410,14 +76431,12 @@ /turf/open/floor/plating/airless, /area/solar/starboard/aft) "ctO" = ( -/obj/machinery/door/airlock/external{ - name = "External Airlock"; - req_access_txt = "13" - }, /obj/structure/cable{ icon_state = "1-2" }, -/turf/open/floor/plasteel/dark, +/turf/open/floor/plating{ + icon_state = "platingdmg1" + }, /area/maintenance/disposal) "ctP" = ( /obj/structure/cable{ @@ -76438,16 +76457,9 @@ /turf/open/floor/plating/airless, /area/solar/starboard/aft) "ctS" = ( -/obj/machinery/door/airlock/external{ - name = "Solar Maintenance"; - req_access_txt = "10; 13" - }, /obj/structure/cable{ icon_state = "4-8" }, -/obj/effect/mapping_helpers/airlock/cyclelink_helper{ - dir = 4 - }, /obj/effect/decal/cleanable/dirt, /turf/open/floor/plating, /area/maintenance/solars/port/fore) @@ -77673,12 +77685,18 @@ /turf/open/floor/plating, /area/maintenance/disposal) "cwb" = ( +/obj/machinery/door/airlock/external{ + name = "Solar Maintenance"; + req_access_txt = "10; 13" + }, /obj/structure/cable{ icon_state = "4-8" }, -/obj/structure/lattice/catwalk, -/turf/open/floor/plating/airless, -/area/solar/starboard/aft) +/obj/effect/mapping_helpers/airlock/cyclelink_helper{ + dir = 8 + }, +/turf/open/floor/plating, +/area/maintenance/solars/starboard/aft) "cwc" = ( /obj/machinery/atmospherics/components/binary/pump/on, /obj/machinery/airlock_sensor/incinerator_atmos{ @@ -77774,9 +77792,9 @@ /area/maintenance/starboard/aft) "cwk" = ( /obj/structure/cable{ - icon_state = "1-2" + icon_state = "2-8" }, -/turf/open/floor/plating/asteroid/airless, +/turf/open/floor/plating/airless, /area/space/nearstation) "cwl" = ( /obj/structure/cable{ @@ -77954,13 +77972,6 @@ /turf/open/floor/plating, /area/maintenance/starboard) "cwD" = ( -/obj/machinery/door/airlock/external{ - name = "External Airlock"; - req_access_txt = "13" - }, -/obj/effect/mapping_helpers/airlock/cyclelink_helper{ - dir = 8 - }, /turf/open/floor/plasteel/dark, /area/maintenance/starboard) "cwE" = ( @@ -78131,6 +78142,9 @@ icon_state = "1-8" }, /obj/effect/decal/cleanable/blood/old, +/obj/structure/cable{ + icon_state = "1-2" + }, /turf/open/floor/plating, /area/maintenance/disposal) "cwQ" = ( @@ -78244,6 +78258,9 @@ dir = 4 }, /obj/effect/decal/cleanable/dirt, +/obj/structure/cable{ + icon_state = "4-8" + }, /turf/open/floor/plating{ icon_state = "platingdmg3" }, @@ -78301,6 +78318,9 @@ }, /obj/effect/decal/cleanable/dirt, /obj/effect/decal/cleanable/blood/old, +/obj/structure/cable{ + icon_state = "2-8" + }, /turf/open/floor/plating, /area/maintenance/disposal) "cxh" = ( @@ -78340,6 +78360,9 @@ /area/maintenance/disposal) "cxj" = ( /obj/effect/decal/cleanable/dirt, +/obj/structure/cable{ + icon_state = "1-2" + }, /turf/open/floor/plating{ icon_state = "platingdmg3" }, @@ -78387,17 +78410,21 @@ }, /area/maintenance/port/fore) "cxp" = ( -/obj/structure/cable{ - icon_state = "1-4" +/obj/machinery/door/airlock/external{ + name = "External Airlock"; + req_access_txt = "13" }, -/turf/open/floor/plating/airless, -/area/space/nearstation) +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/open/floor/plasteel/dark, +/area/maintenance/disposal) "cxq" = ( -/obj/structure/cable{ - icon_state = "2-8" +/obj/effect/decal/cleanable/cobweb, +/turf/open/floor/plating{ + icon_state = "platingdmg1" }, -/turf/open/floor/plating/airless, -/area/space/nearstation) +/area/maintenance/fore) "cxr" = ( /obj/structure/sign/poster/contraband/clown, /turf/closed/wall/rust, @@ -78498,6 +78525,7 @@ icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/manifold/supply/hidden, +/mob/living/simple_animal/opossum/poppy, /turf/open/floor/plating{ icon_state = "platingdmg3" }, @@ -83809,16 +83837,9 @@ }, /area/maintenance/starboard) "cMH" = ( -/obj/machinery/door/airlock/external{ - name = "Solar Maintenance"; - req_access_txt = "10; 13" - }, /obj/structure/cable{ icon_state = "4-8" }, -/obj/effect/mapping_helpers/airlock/cyclelink_helper{ - dir = 8 - }, /turf/open/floor/plating, /area/maintenance/solars/starboard/fore) "cMI" = ( @@ -84486,13 +84507,6 @@ /turf/open/space/basic, /area/space/nearstation) "cUD" = ( -/obj/machinery/door/airlock/external{ - name = "Prison External Airlock"; - req_access_txt = "2" - }, -/obj/effect/mapping_helpers/airlock/cyclelink_helper{ - dir = 1 - }, /obj/structure/cable{ icon_state = "1-2" }, @@ -84510,6 +84524,10 @@ icon_state = "wood-broken" }, /area/security/vacantoffice) +"dky" = ( +/obj/structure/cable, +/turf/open/floor/plating/airless, +/area/space/nearstation) "dlg" = ( /obj/machinery/light, /turf/open/floor/wood, @@ -84661,6 +84679,12 @@ /obj/effect/decal/cleanable/cobweb/cobweb2, /turf/closed/mineral/random/labormineral, /area/space/nearstation) +"fAn" = ( +/obj/structure/sign/warning/vacuum/external{ + pixel_y = 32 + }, +/turf/open/floor/plating/airless, +/area/space/nearstation) "fXq" = ( /obj/effect/turf_decal/tile/neutral{ dir = 8 @@ -84902,6 +84926,11 @@ /obj/machinery/light, /turf/open/floor/plating/airless, /area/hallway/secondary/entry) +"jGN" = ( +/obj/effect/decal/cleanable/dirt, +/mob/living/simple_animal/opossum, +/turf/open/floor/plating, +/area/maintenance/starboard/aft) "jHJ" = ( /obj/machinery/atmospherics/pipe/simple/general/visible{ dir = 9 @@ -85108,6 +85137,16 @@ /obj/structure/sign/poster/ripped, /turf/closed/wall, /area/crew_quarters/fitness/recreation) +"lqz" = ( +/obj/machinery/door/airlock/external{ + name = "External Airlock"; + req_access_txt = "13" + }, +/obj/effect/mapping_helpers/airlock/cyclelink_helper{ + dir = 8 + }, +/turf/open/floor/plasteel/dark, +/area/maintenance/starboard) "lKu" = ( /obj/structure/table/wood, /obj/item/reagent_containers/food/drinks/soda_cans/thirteenloko, @@ -85165,6 +85204,9 @@ }, /turf/open/floor/plasteel/dark, /area/science/research) +"mKj" = ( +/turf/closed/wall/rust, +/area/security/execution/education) "mKp" = ( /obj/structure/cable{ icon_state = "1-2" @@ -85531,6 +85573,12 @@ icon_state = "wood-broken4" }, /area/maintenance/port/fore) +"yaV" = ( +/obj/structure/cable{ + icon_state = "1-4" + }, +/turf/open/floor/plating/airless, +/area/space/nearstation) "ydo" = ( /obj/structure/cable{ icon_state = "4-8" @@ -99344,9 +99392,9 @@ bTK bVs hNk bXG +abp cZm -bZG -aeU +fAn aeU aeU aeU @@ -99603,7 +99651,7 @@ cTF bXH cUD bZP -aeU +dky coy aeU aeU @@ -99856,19 +99904,19 @@ aaG aez cIj aeB -cZm +mKj +aez aez aez cko cko -cko -aeU aeU aeU aeU aeU +cnS chU -aeU +cnS aUz aeU aeu @@ -100311,9 +100359,9 @@ aeu aeU aeU aeU -aeU +ctH aqp -aeU +ctH aeu aeu aeu @@ -112385,7 +112433,7 @@ aaa aaa aeU aUz -aeu +adH adH adH adH @@ -112642,8 +112690,8 @@ aaa aaa acm aeU -aeU adQ +cxq alN chj aoc @@ -112899,7 +112947,7 @@ aeR aeR aes aes -aes +bZG adM alO amL @@ -113156,7 +113204,7 @@ aaa aaa acm aaa -aaa +adH adH adH adQ @@ -120597,9 +120645,9 @@ aaa aaa aaa aaa -aeU aeK baH +baH afb baH baH @@ -124306,9 +124354,9 @@ cpb crf cnu cnu +cnu cko aeu -aeu aaa aaa aaa @@ -124564,7 +124612,7 @@ cxg cxj ctO cxp -aeU +yaV ciQ aeU aaa @@ -124820,7 +124868,7 @@ cnu cnd cnu cnu -cxq +cnu cwk cxu aeU @@ -125028,7 +125076,7 @@ bAP bCf bhQ bhQ -bAM +jGN bGH bOc bHZ @@ -126354,9 +126402,9 @@ bzG bzG aeu aeu -aeU +ckz cwb -aeU +ckz aeU aUz aeU @@ -129376,9 +129424,9 @@ aaQ aeo aeo acm -acm -acK -acm +bkd +lqz +bkd aaa aaa aaa @@ -129611,9 +129659,9 @@ aeu aeu aeu aeu -aeU +cLM auN -aeU +cLM aeu aeu aeu diff --git a/_maps/map_files/LambdaStation/lambda.dmm b/_maps/map_files/LambdaStation/lambda.dmm index 4d2d8cb624..47d8dd9cb4 100644 --- a/_maps/map_files/LambdaStation/lambda.dmm +++ b/_maps/map_files/LambdaStation/lambda.dmm @@ -44383,7 +44383,6 @@ /turf/open/floor/plasteel/white, /area/hallway/primary/aft) "bFB" = ( -/obj/structure/reagent_dispensers/keg/aphro/strong, /obj/effect/decal/cleanable/dirt, /turf/open/floor/wood{ icon_state = "wood-broken5" @@ -80286,6 +80285,11 @@ }, /turf/open/space/basic, /area/engine/engineering) +"eCO" = ( +/obj/effect/decal/cleanable/dirt, +/mob/living/simple_animal/opossum/poppy, +/turf/open/floor/plasteel/dark, +/area/maintenance/starboard/aft) "eDP" = ( /obj/effect/turf_decal/trimline/blue/filled/corner{ dir = 8 @@ -82039,6 +82043,10 @@ }, /turf/open/floor/plasteel/cafeteria, /area/crew_quarters/kitchen) +"vDO" = ( +/mob/living/simple_animal/opossum, +/turf/open/floor/plating, +/area/maintenance/fore) "vDW" = ( /obj/structure/cable{ icon_state = "1-2" @@ -107579,7 +107587,7 @@ aaA abY ayy acw -acw +vDO acw acw aeG @@ -135198,7 +135206,7 @@ bPp ccJ clR bQh -clN +eCO bPp bQh bYx diff --git a/_maps/map_files/Mafia/mafia_ayylmao.dmm b/_maps/map_files/Mafia/mafia_ayylmao.dmm new file mode 100644 index 0000000000..5d6f2aec5f --- /dev/null +++ b/_maps/map_files/Mafia/mafia_ayylmao.dmm @@ -0,0 +1,768 @@ +//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE +"a" = ( +/turf/closed/indestructible/riveted, +/area/mafia) +"b" = ( +/turf/closed/indestructible{ + desc = "A wall with alien alloy plating."; + icon = 'icons/turf/walls/abductor_wall.dmi'; + icon_state = "abductor"; + name = "alien wall"; + smooth = 5 + }, +/area/mafia) +"g" = ( +/obj/mafia_game_board, +/turf/open/floor/plating{ + icon_state = "platingdmg3" + }, +/area/mafia) +"h" = ( +/obj/structure/grille/indestructable, +/turf/open/floor/plating, +/area/mafia) +"i" = ( +/turf/open/floor/fakespace, +/area/mafia) +"j" = ( +/turf/closed/indestructible/abductor{ + icon_state = "alien22" + }, +/area/mafia) +"k" = ( +/obj/mafia_game_board, +/turf/open/floor/plating, +/area/mafia) +"l" = ( +/obj/structure/closet/abductor, +/turf/open/floor/plating/abductor, +/area/mafia) +"m" = ( +/obj/effect/landmark/mafia, +/obj/structure/bed/abductor, +/turf/open/floor/plating/abductor, +/area/mafia) +"n" = ( +/obj/effect/landmark/mafia, +/obj/structure/bed/abductor, +/turf/open/floor/plating/abductor2, +/area/mafia) +"o" = ( +/obj/structure/closet/abductor, +/turf/open/floor/plating/abductor2, +/area/mafia) +"p" = ( +/obj/machinery/door/poddoor/preopen{ + desc = "When it's time to sleep, the lights will go out. Remember - no one in space can hear you scream."; + id = "mafia"; + max_integrity = 99999; + name = "Station Night Shutters" + }, +/turf/closed/indestructible/fakeglass, +/area/mafia) +"q" = ( +/turf/open/floor/plating/abductor, +/area/mafia) +"r" = ( +/turf/open/floor/plating/abductor2, +/area/mafia) +"t" = ( +/turf/open/floor/light/colour_cycle/dancefloor_a, +/area/mafia) +"u" = ( +/obj/effect/baseturf_helper/asteroid, +/obj/effect/landmark/mafia/town_center, +/turf/open/floor/light/colour_cycle/dancefloor_b, +/area/mafia) +"v" = ( +/obj/mafia_game_board, +/turf/open/floor/plating{ + icon_state = "panelscorched" + }, +/area/mafia) +"x" = ( +/obj/machinery/door/poddoor/preopen{ + desc = "When it's time to sleep, the lights will go out. Remember - no one in space can hear you scream."; + id = "mafia"; + max_integrity = 99999; + name = "Station Night Shutters" + }, +/obj/effect/spawner/structure/window/plastitanium, +/turf/open/floor/plating/abductor2, +/area/mafia) +"z" = ( +/obj/structure/grille/indestructable, +/turf/open/floor/fakespace, +/area/mafia) +"B" = ( +/turf/closed/indestructible/abductor{ + icon_state = "alien2" + }, +/area/mafia) +"D" = ( +/turf/closed/indestructible/abductor{ + icon_state = "alien15" + }, +/area/mafia) +"E" = ( +/turf/closed/indestructible/abductor{ + icon_state = "alien7" + }, +/area/mafia) +"F" = ( +/turf/closed/indestructible/abductor{ + icon_state = "alien12" + }, +/area/mafia) +"G" = ( +/turf/closed/indestructible/abductor{ + icon_state = "alien17" + }, +/area/mafia) +"H" = ( +/turf/open/space/basic, +/area/mafia) +"I" = ( +/turf/closed/indestructible/abductor{ + icon_state = "alien24" + }, +/area/mafia) +"J" = ( +/turf/closed/indestructible/abductor{ + icon_state = "alien18" + }, +/area/mafia) +"K" = ( +/turf/closed/indestructible/abductor{ + icon_state = "alien11" + }, +/area/mafia) +"L" = ( +/turf/closed/indestructible/abductor{ + icon_state = "alien14" + }, +/area/mafia) +"M" = ( +/turf/closed/indestructible/abductor{ + icon_state = "alien4" + }, +/area/mafia) +"N" = ( +/turf/closed/indestructible/abductor{ + icon_state = "alien21" + }, +/area/mafia) +"P" = ( +/turf/closed/indestructible/abductor, +/area/mafia) +"Q" = ( +/turf/closed/indestructible/abductor{ + icon_state = "alien5" + }, +/area/mafia) +"S" = ( +/turf/closed/indestructible/abductor{ + icon_state = "alien3" + }, +/area/mafia) +"U" = ( +/turf/closed/indestructible/abductor{ + icon_state = "alien23" + }, +/area/mafia) +"V" = ( +/turf/closed/indestructible/abductor{ + icon_state = "alien13" + }, +/area/mafia) +"W" = ( +/turf/closed/indestructible/abductor{ + icon_state = "alien20" + }, +/area/mafia) +"Y" = ( +/turf/closed/indestructible/abductor{ + icon_state = "alien8" + }, +/area/mafia) +"Z" = ( +/turf/closed/indestructible/abductor{ + icon_state = "alien10" + }, +/area/mafia) + +(1,1,1) = {" +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +"} +(2,1,1) = {" +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +"} +(3,1,1) = {" +a +b +i +i +i +i +i +i +i +i +i +i +i +i +i +i +i +i +i +i +i +b +a +"} +(4,1,1) = {" +a +b +i +i +g +z +i +i +i +i +i +i +i +i +i +H +i +z +k +i +i +b +a +"} +(5,1,1) = {" +a +b +i +i +z +i +i +i +W +L +F +F +F +Z +P +i +i +i +h +i +i +b +a +"} +(6,1,1) = {" +a +b +i +i +i +W +L +Z +G +l +q +b +r +o +E +L +Z +P +i +i +i +b +a +"} +(7,1,1) = {" +a +b +i +i +i +N +o +r +p +m +q +x +r +n +x +q +l +B +i +i +i +b +a +"} +(8,1,1) = {" +a +b +i +i +i +U +n +r +b +b +q +b +r +b +b +q +m +M +i +i +i +b +a +"} +(9,1,1) = {" +a +b +i +i +W +G +x +r +r +x +q +x +r +x +q +q +x +E +P +i +i +b +a +"} +(10,1,1) = {" +a +b +i +i +N +l +x +b +x +x +x +x +x +x +x +b +x +o +B +i +i +b +a +"} +(11,1,1) = {" +a +b +i +i +j +m +q +q +q +x +t +t +t +x +r +r +r +n +S +i +i +b +a +"} +(12,1,1) = {" +a +b +i +i +j +b +x +b +x +x +t +u +t +x +x +b +x +b +S +i +i +b +a +"} +(13,1,1) = {" +a +b +i +i +j +n +r +r +r +x +t +t +t +x +q +q +q +m +S +i +i +b +a +"} +(14,1,1) = {" +a +b +i +i +U +o +x +b +x +x +x +x +x +x +x +b +x +l +M +i +i +b +a +"} +(15,1,1) = {" +a +b +i +i +I +J +x +q +q +x +r +x +q +x +r +r +x +Y +Q +i +i +b +a +"} +(16,1,1) = {" +a +b +i +i +i +N +m +q +b +b +r +b +q +b +b +r +n +B +i +i +i +b +a +"} +(17,1,1) = {" +a +b +i +i +i +U +l +q +x +n +r +x +q +m +x +r +o +M +i +i +i +b +a +"} +(18,1,1) = {" +a +b +i +i +i +I +D +K +J +o +r +b +q +l +Y +D +K +Q +i +i +i +b +a +"} +(19,1,1) = {" +a +b +i +i +z +i +i +i +I +D +V +V +V +K +Q +i +i +i +z +i +i +b +a +"} +(20,1,1) = {" +a +b +i +i +k +z +i +i +i +i +i +i +i +i +i +i +i +z +v +i +i +b +a +"} +(21,1,1) = {" +a +b +i +i +i +i +i +i +i +i +i +i +i +i +i +i +i +i +i +i +i +b +a +"} +(22,1,1) = {" +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +"} +(23,1,1) = {" +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +"} diff --git a/_maps/map_files/Mafia/mafia_ball.dmm b/_maps/map_files/Mafia/mafia_ball.dmm new file mode 100644 index 0000000000..6ca955726b --- /dev/null +++ b/_maps/map_files/Mafia/mafia_ball.dmm @@ -0,0 +1,675 @@ +//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE +"a" = ( +/turf/closed/indestructible/riveted, +/area/mafia) +"c" = ( +/turf/closed/wall/rust, +/area/mafia) +"d" = ( +/turf/open/floor/plating, +/area/mafia) +"e" = ( +/turf/open/floor/plating{ + icon_state = "platingdmg3" + }, +/area/mafia) +"f" = ( +/turf/open/floor/plating{ + icon_state = "panelscorched" + }, +/area/mafia) +"g" = ( +/obj/mafia_game_board, +/turf/open/floor/plating{ + icon_state = "platingdmg3" + }, +/area/mafia) +"h" = ( +/obj/structure/grille/indestructable, +/turf/open/floor/plating, +/area/mafia) +"i" = ( +/turf/open/floor/plating{ + icon_state = "platingdmg1" + }, +/area/mafia) +"j" = ( +/obj/machinery/door/airlock/maintenance_hatch{ + max_integrity = 99999; + name = "Maintenance" + }, +/obj/effect/mapping_helpers/airlock/locked, +/turf/open/floor/plating, +/area/mafia) +"k" = ( +/obj/mafia_game_board, +/turf/open/floor/plating, +/area/mafia) +"l" = ( +/obj/structure/closet/cabinet{ + anchored = 1 + }, +/turf/open/floor/plasteel/dark, +/area/mafia) +"m" = ( +/obj/effect/landmark/mafia, +/turf/open/floor/plasteel/dark, +/area/mafia) +"n" = ( +/obj/effect/landmark/mafia, +/turf/open/floor/plasteel, +/area/mafia) +"o" = ( +/obj/structure/closet/cabinet{ + anchored = 1 + }, +/turf/open/floor/plasteel, +/area/mafia) +"p" = ( +/obj/machinery/door/poddoor/preopen{ + desc = "When it's time to sleep, the lights will go out. Remember - no one in space can hear you scream."; + id = "mafia"; + max_integrity = 99999; + name = "Station Night Shutters" + }, +/turf/closed/indestructible/fakeglass, +/area/mafia) +"q" = ( +/turf/open/floor/plasteel/dark, +/area/mafia) +"r" = ( +/turf/open/floor/plasteel, +/area/mafia) +"s" = ( +/turf/open/floor/fakespace, +/area/mafia) +"t" = ( +/turf/open/floor/plasteel/solarpanel, +/area/mafia) +"u" = ( +/obj/effect/baseturf_helper/asteroid, +/obj/effect/landmark/mafia/town_center, +/turf/open/floor/plasteel/solarpanel, +/area/mafia) +"v" = ( +/obj/mafia_game_board, +/turf/open/floor/plating{ + icon_state = "panelscorched" + }, +/area/mafia) + +(1,1,1) = {" +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +"} +(2,1,1) = {" +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +"} +(3,1,1) = {" +a +a +a +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +a +a +a +"} +(4,1,1) = {" +a +a +a +c +g +h +d +d +d +d +d +e +d +d +d +d +d +h +k +c +a +a +a +"} +(5,1,1) = {" +a +a +a +c +h +d +d +e +a +a +j +a +j +a +a +d +d +i +h +c +a +a +a +"} +(6,1,1) = {" +a +a +a +c +i +a +a +j +a +l +q +a +r +o +a +j +a +a +d +c +a +a +a +"} +(7,1,1) = {" +a +a +c +c +d +a +o +r +p +m +q +p +r +n +p +q +l +a +d +c +c +a +a +"} +(8,1,1) = {" +a +a +c +d +d +a +n +r +a +a +q +a +r +a +a +q +m +a +d +d +c +a +a +"} +(9,1,1) = {" +a +a +c +d +a +a +p +r +r +p +q +p +r +p +q +q +p +a +a +d +c +a +a +"} +(10,1,1) = {" +a +a +c +d +a +l +p +a +p +p +p +p +p +p +p +a +p +o +a +d +c +a +a +"} +(11,1,1) = {" +a +a +c +d +j +m +q +q +q +p +s +t +s +p +r +r +r +n +j +e +c +a +a +"} +(12,1,1) = {" +a +a +c +e +a +a +p +a +p +p +t +u +t +p +p +a +p +a +a +d +c +a +a +"} +(13,1,1) = {" +a +a +c +d +j +n +r +r +r +p +s +t +s +p +q +q +q +m +j +d +c +a +a +"} +(14,1,1) = {" +a +a +c +d +a +o +p +a +p +p +p +p +p +p +p +a +p +l +a +i +c +a +a +"} +(15,1,1) = {" +a +a +c +d +a +a +p +q +q +p +r +p +q +p +r +r +p +a +a +d +c +a +a +"} +(16,1,1) = {" +a +a +c +f +d +a +m +q +a +a +r +a +q +a +a +r +n +a +d +d +c +a +a +"} +(17,1,1) = {" +a +a +c +c +d +a +l +q +p +n +r +p +q +m +p +r +o +a +d +c +c +a +a +"} +(18,1,1) = {" +a +a +a +c +d +a +a +j +a +o +r +a +q +l +a +j +a +a +d +c +a +a +a +"} +(19,1,1) = {" +a +a +a +c +h +i +d +d +a +a +j +a +j +a +a +d +e +d +h +c +a +a +a +"} +(20,1,1) = {" +a +a +a +c +k +h +d +d +e +d +d +d +d +d +d +d +d +h +v +c +a +a +a +"} +(21,1,1) = {" +a +a +a +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +a +a +a +"} +(22,1,1) = {" +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +"} +(23,1,1) = {" +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +"} diff --git a/_maps/map_files/Mafia/mafia_gothic.dmm b/_maps/map_files/Mafia/mafia_gothic.dmm new file mode 100644 index 0000000000..a3c19fee85 --- /dev/null +++ b/_maps/map_files/Mafia/mafia_gothic.dmm @@ -0,0 +1,724 @@ +//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE +"a" = ( +/turf/closed/indestructible/riveted, +/area/mafia) +"b" = ( +/turf/closed/wall/mineral/iron, +/area/mafia) +"c" = ( +/turf/closed/wall/rust, +/area/mafia) +"d" = ( +/turf/open/floor/plating, +/area/mafia) +"e" = ( +/turf/open/floor/plating{ + icon_state = "platingdmg3" + }, +/area/mafia) +"f" = ( +/turf/open/floor/plating{ + icon_state = "panelscorched" + }, +/area/mafia) +"g" = ( +/obj/mafia_game_board, +/turf/open/floor/plating{ + icon_state = "platingdmg3" + }, +/area/mafia) +"h" = ( +/obj/structure/grille/indestructable, +/turf/open/floor/plating, +/area/mafia) +"i" = ( +/turf/open/floor/plating{ + icon_state = "platingdmg1" + }, +/area/mafia) +"j" = ( +/turf/closed/indestructible/fakedoor, +/area/mafia) +"k" = ( +/obj/mafia_game_board, +/turf/open/floor/plating, +/area/mafia) +"l" = ( +/obj/structure/closet/crate/coffin, +/turf/open/floor/carpet/red, +/area/mafia) +"m" = ( +/obj/effect/landmark/mafia, +/turf/open/floor/carpet/red, +/area/mafia) +"n" = ( +/obj/effect/landmark/mafia, +/turf/open/floor/plasteel/chapel{ + dir = 1 + }, +/area/mafia) +"o" = ( +/obj/structure/closet/crate/coffin, +/turf/open/floor/plasteel/chapel{ + dir = 4 + }, +/area/mafia) +"p" = ( +/obj/machinery/door/poddoor/preopen{ + desc = "When it's time to sleep, the lights will go out. Remember - no one in space can hear you scream."; + id = "mafia"; + max_integrity = 99999; + name = "Station Night Shutters" + }, +/obj/effect/spawner/structure/window/plastitanium, +/turf/open/space/basic, +/area/mafia) +"q" = ( +/turf/open/floor/carpet/red, +/area/mafia) +"r" = ( +/turf/open/floor/plasteel/chapel{ + dir = 8 + }, +/area/mafia) +"t" = ( +/turf/open/floor/carpet/royalblack, +/area/mafia) +"u" = ( +/obj/effect/baseturf_helper/asteroid, +/obj/effect/landmark/mafia/town_center, +/turf/open/floor/carpet/royalblack, +/area/mafia) +"v" = ( +/obj/mafia_game_board, +/turf/open/floor/plating{ + icon_state = "panelscorched" + }, +/area/mafia) +"D" = ( +/obj/effect/landmark/mafia, +/turf/open/floor/plasteel/chapel{ + dir = 4 + }, +/area/mafia) +"E" = ( +/turf/open/floor/plasteel/chapel{ + dir = 4 + }, +/area/mafia) +"H" = ( +/obj/structure/closet/cabinet{ + anchored = 1 + }, +/turf/open/floor/carpet/red, +/area/mafia) +"J" = ( +/obj/structure/closet/crate/coffin, +/turf/open/floor/plasteel/chapel{ + dir = 1 + }, +/area/mafia) +"M" = ( +/obj/effect/landmark/mafia, +/turf/open/floor/plasteel/chapel{ + dir = 8 + }, +/area/mafia) +"N" = ( +/obj/effect/landmark/mafia, +/turf/open/floor/plasteel/chapel, +/area/mafia) +"O" = ( +/turf/open/floor/plasteel/chapel, +/area/mafia) +"P" = ( +/obj/structure/closet/crate/coffin, +/turf/open/floor/plasteel/chapel, +/area/mafia) +"Q" = ( +/obj/structure/closet/crate/coffin, +/turf/open/floor/plasteel/chapel{ + dir = 8 + }, +/area/mafia) +"X" = ( +/turf/open/floor/plasteel/chapel{ + dir = 1 + }, +/area/mafia) + +(1,1,1) = {" +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +"} +(2,1,1) = {" +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +"} +(3,1,1) = {" +a +b +b +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +b +b +a +"} +(4,1,1) = {" +a +b +b +c +g +h +d +d +d +d +d +e +d +d +d +d +d +h +k +c +b +b +a +"} +(5,1,1) = {" +a +b +b +c +h +d +d +e +b +b +j +b +j +b +b +d +d +i +h +c +b +b +a +"} +(6,1,1) = {" +a +b +b +c +i +b +b +j +b +l +q +b +X +Q +b +j +b +b +d +c +b +b +a +"} +(7,1,1) = {" +a +b +c +c +d +b +J +r +p +m +q +p +E +N +p +q +l +b +d +c +c +b +a +"} +(8,1,1) = {" +a +b +c +d +d +b +D +O +b +b +q +b +r +b +b +q +m +b +d +d +c +b +a +"} +(9,1,1) = {" +a +b +c +d +b +b +p +X +r +p +q +p +O +p +q +q +p +b +b +d +c +b +a +"} +(10,1,1) = {" +a +b +c +d +b +l +p +b +p +p +p +p +p +p +p +b +p +Q +b +d +c +b +a +"} +(11,1,1) = {" +a +b +c +d +j +m +q +q +q +p +t +t +t +p +X +r +E +N +j +e +c +b +a +"} +(12,1,1) = {" +a +b +c +e +b +b +p +b +p +p +t +u +t +p +p +b +p +b +b +d +c +b +a +"} +(13,1,1) = {" +a +b +c +d +j +n +r +E +O +p +t +t +t +p +q +q +q +m +j +d +c +b +a +"} +(14,1,1) = {" +a +b +c +d +b +o +p +b +p +p +p +p +p +p +p +b +p +l +b +i +c +b +a +"} +(15,1,1) = {" +a +b +c +d +b +b +p +q +q +p +X +p +q +p +E +O +p +b +b +d +c +b +a +"} +(16,1,1) = {" +a +b +c +f +d +b +m +q +b +b +E +b +q +b +b +X +M +b +d +d +c +b +a +"} +(17,1,1) = {" +a +b +c +c +d +b +l +q +p +n +r +p +q +m +p +E +P +b +d +c +c +b +a +"} +(18,1,1) = {" +a +b +b +c +d +b +b +j +b +o +O +b +q +H +b +j +b +b +d +c +b +b +a +"} +(19,1,1) = {" +a +b +b +c +h +i +d +d +b +b +j +b +j +b +b +d +e +d +h +c +b +b +a +"} +(20,1,1) = {" +a +b +b +c +k +h +d +d +e +d +d +d +d +d +d +d +d +h +v +c +b +b +a +"} +(21,1,1) = {" +a +b +b +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +b +b +a +"} +(22,1,1) = {" +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +"} +(23,1,1) = {" +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +"} diff --git a/_maps/map_files/Mafia/mafia_lavaland.dmm b/_maps/map_files/Mafia/mafia_lavaland.dmm new file mode 100644 index 0000000000..8c58fb9054 --- /dev/null +++ b/_maps/map_files/Mafia/mafia_lavaland.dmm @@ -0,0 +1,976 @@ +//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE +"a" = ( +/turf/closed/indestructible/riveted, +/area/mafia) +"c" = ( +/turf/closed/wall/rust, +/area/mafia) +"d" = ( +/turf/open/floor/plating, +/area/mafia) +"e" = ( +/turf/open/floor/plating{ + icon_state = "platingdmg3" + }, +/area/mafia) +"f" = ( +/turf/open/floor/plating{ + icon_state = "panelscorched" + }, +/area/mafia) +"g" = ( +/obj/mafia_game_board, +/turf/open/floor/plating{ + icon_state = "platingdmg3" + }, +/area/mafia) +"h" = ( +/obj/structure/grille/indestructable, +/turf/open/floor/plating, +/area/mafia) +"i" = ( +/turf/open/floor/plating{ + icon_state = "platingdmg1" + }, +/area/mafia) +"j" = ( +/obj/machinery/door/airlock/external{ + max_integrity = 99999; + name = "Maintenance" + }, +/obj/effect/mapping_helpers/airlock/locked, +/turf/open/floor/plating, +/area/mafia) +"k" = ( +/obj/mafia_game_board, +/turf/open/floor/plating, +/area/mafia) +"l" = ( +/obj/structure/closet{ + desc = "It's a storage unit. For mining stuff. Y'know."; + icon_state = "mining"; + name = "miner equipment locker" + }, +/obj/item/clothing/under/rank/cargo/miner/lavaland, +/turf/open/floor/grass/fakebasalt, +/area/mafia) +"m" = ( +/obj/effect/landmark/mafia, +/turf/open/floor/grass/fakebasalt, +/area/mafia) +"n" = ( +/obj/effect/landmark/mafia, +/obj/effect/turf_decal/trimline/brown/filled/line{ + icon_state = "trimline_fill"; + dir = 9 + }, +/obj/effect/turf_decal/trimline/brown/filled/corner, +/turf/open/floor/plasteel, +/area/mafia) +"o" = ( +/obj/effect/turf_decal/trimline/brown/filled/end{ + icon_state = "trimline_end_fill"; + dir = 4 + }, +/obj/structure/closet{ + desc = "It's a storage unit. For mining stuff. Y'know."; + icon_state = "mining"; + name = "miner equipment locker" + }, +/obj/item/clothing/under/rank/cargo/miner/lavaland, +/turf/open/floor/plasteel, +/area/mafia) +"p" = ( +/obj/machinery/door/poddoor/preopen{ + desc = "When it's time to sleep, the lights will go out. Remember - no one in space can hear you scream."; + id = "mafia"; + max_integrity = 99999; + name = "Station Night Shutters" + }, +/turf/closed/indestructible/fakeglass, +/area/mafia) +"q" = ( +/turf/open/floor/grass/fakebasalt, +/area/mafia) +"r" = ( +/obj/effect/turf_decal/trimline/brown/filled/line{ + icon_state = "trimline_fill"; + dir = 9 + }, +/obj/structure/closet{ + desc = "It's a storage unit. For mining stuff. Y'know."; + icon_state = "mining"; + name = "miner equipment locker" + }, +/obj/item/clothing/under/rank/cargo/miner/lavaland, +/turf/open/floor/plasteel, +/area/mafia) +"s" = ( +/obj/effect/turf_decal/trimline/brown/filled/line{ + icon_state = "trimline_fill"; + dir = 9 + }, +/turf/open/floor/plasteel, +/area/mafia) +"t" = ( +/obj/effect/turf_decal/tile/red, +/obj/effect/turf_decal/tile/red{ + dir = 8 + }, +/turf/open/floor/plasteel/dark, +/area/mafia) +"u" = ( +/obj/effect/turf_decal/tile/red{ + dir = 4 + }, +/obj/effect/turf_decal/tile/red, +/turf/open/floor/plasteel/dark, +/area/mafia) +"v" = ( +/obj/mafia_game_board, +/turf/open/floor/plating{ + icon_state = "panelscorched" + }, +/area/mafia) +"w" = ( +/obj/effect/turf_decal/trimline/brown/filled/line{ + icon_state = "trimline_fill"; + dir = 1 + }, +/obj/effect/turf_decal/trimline/brown/filled/corner, +/turf/open/floor/plasteel, +/area/mafia) +"x" = ( +/obj/effect/turf_decal/trimline/brown/filled/line{ + icon_state = "trimline_fill"; + dir = 1 + }, +/obj/effect/turf_decal/trimline/brown/filled/line, +/turf/open/floor/plasteel, +/area/mafia) +"y" = ( +/obj/effect/turf_decal/trimline/brown/filled/end{ + icon_state = "trimline_end_fill"; + dir = 4 + }, +/turf/open/floor/plasteel, +/area/mafia) +"z" = ( +/obj/effect/turf_decal/trimline/brown/filled/line{ + icon_state = "trimline_fill"; + dir = 5 + }, +/obj/structure/closet{ + desc = "It's a storage unit. For mining stuff. Y'know."; + icon_state = "mining"; + name = "miner equipment locker" + }, +/obj/item/clothing/under/rank/cargo/miner/lavaland, +/turf/open/floor/plasteel, +/area/mafia) +"A" = ( +/obj/effect/landmark/mafia, +/obj/effect/turf_decal/trimline/brown/filled/line{ + icon_state = "trimline_fill"; + dir = 6 + }, +/turf/open/floor/plasteel, +/area/mafia) +"B" = ( +/obj/effect/turf_decal/trimline/brown/filled/end{ + icon_state = "trimline_end_fill"; + dir = 1 + }, +/turf/open/floor/plasteel, +/area/mafia) +"C" = ( +/obj/effect/turf_decal/trimline/brown/filled/line{ + icon_state = "trimline_fill"; + dir = 4 + }, +/obj/effect/turf_decal/trimline/brown/filled/line{ + icon_state = "trimline_fill"; + dir = 8 + }, +/turf/open/floor/plasteel, +/area/mafia) +"D" = ( +/obj/effect/turf_decal/trimline/brown/filled/line{ + icon_state = "trimline_fill"; + dir = 10 + }, +/obj/effect/turf_decal/trimline/brown/filled/corner{ + icon_state = "trimline_corner_fill"; + dir = 4 + }, +/turf/open/floor/plasteel, +/area/mafia) +"E" = ( +/obj/effect/turf_decal/trimline/brown/filled/line{ + icon_state = "trimline_fill"; + dir = 1 + }, +/obj/effect/turf_decal/trimline/brown/filled/corner{ + icon_state = "trimline_corner_fill"; + dir = 8 + }, +/turf/open/floor/plasteel, +/area/mafia) +"F" = ( +/obj/effect/turf_decal/trimline/brown/filled/line{ + icon_state = "trimline_fill"; + dir = 5 + }, +/turf/open/floor/plasteel, +/area/mafia) +"G" = ( +/obj/effect/landmark/mafia, +/obj/effect/turf_decal/trimline/brown/filled/line{ + icon_state = "trimline_fill"; + dir = 10 + }, +/turf/open/floor/plasteel, +/area/mafia) +"H" = ( +/obj/effect/turf_decal/trimline/brown/filled/line{ + icon_state = "trimline_fill"; + dir = 10 + }, +/obj/structure/closet{ + desc = "It's a storage unit. For mining stuff. Y'know."; + icon_state = "mining"; + name = "miner equipment locker" + }, +/obj/item/clothing/under/rank/cargo/miner/lavaland, +/turf/open/floor/plasteel, +/area/mafia) +"I" = ( +/obj/effect/turf_decal/trimline/brown/filled/line{ + icon_state = "trimline_fill"; + dir = 6 + }, +/obj/structure/closet{ + desc = "It's a storage unit. For mining stuff. Y'know."; + icon_state = "mining"; + name = "miner equipment locker" + }, +/obj/item/clothing/under/rank/cargo/miner/lavaland, +/turf/open/floor/plasteel, +/area/mafia) +"J" = ( +/obj/effect/landmark/mafia, +/obj/effect/turf_decal/trimline/brown/filled/line{ + icon_state = "trimline_fill"; + dir = 6 + }, +/obj/effect/turf_decal/trimline/brown/filled/corner{ + icon_state = "trimline_corner_fill"; + dir = 1 + }, +/turf/open/floor/plasteel, +/area/mafia) +"K" = ( +/obj/effect/turf_decal/trimline/brown/filled/end{ + icon_state = "trimline_end_fill"; + dir = 8 + }, +/obj/structure/closet{ + desc = "It's a storage unit. For mining stuff. Y'know."; + icon_state = "mining"; + name = "miner equipment locker" + }, +/obj/item/clothing/under/rank/cargo/miner/lavaland, +/turf/open/floor/plasteel, +/area/mafia) +"L" = ( +/obj/effect/landmark/mafia, +/obj/effect/turf_decal/trimline/brown/filled/line{ + icon_state = "trimline_fill"; + dir = 5 + }, +/turf/open/floor/plasteel, +/area/mafia) +"M" = ( +/obj/effect/turf_decal/trimline/brown/filled/line{ + icon_state = "trimline_fill"; + dir = 10 + }, +/turf/open/floor/plasteel, +/area/mafia) +"N" = ( +/obj/effect/turf_decal/trimline/brown/filled/line, +/obj/effect/turf_decal/trimline/brown/filled/corner{ + icon_state = "trimline_corner_fill"; + dir = 4 + }, +/turf/open/floor/plasteel, +/area/mafia) +"O" = ( +/obj/effect/turf_decal/trimline/brown/filled/corner{ + icon_state = "trimline_corner_fill"; + dir = 8 + }, +/obj/effect/turf_decal/trimline/brown/filled/line{ + icon_state = "trimline_fill"; + dir = 5 + }, +/turf/open/floor/plasteel, +/area/mafia) +"P" = ( +/obj/effect/turf_decal/trimline/brown/filled/end, +/turf/open/floor/plasteel, +/area/mafia) +"Q" = ( +/obj/effect/landmark/mafia, +/obj/effect/turf_decal/trimline/brown/filled/line{ + icon_state = "trimline_fill"; + dir = 9 + }, +/turf/open/floor/plasteel, +/area/mafia) +"R" = ( +/obj/effect/baseturf_helper/asteroid, +/obj/effect/landmark/mafia/town_center, +/obj/effect/turf_decal/tile/red, +/obj/effect/turf_decal/tile/red{ + dir = 1 + }, +/obj/effect/turf_decal/tile/red{ + dir = 8 + }, +/obj/effect/turf_decal/tile/red{ + dir = 4 + }, +/turf/open/floor/plasteel/dark, +/area/mafia) +"S" = ( +/obj/effect/turf_decal/trimline/brown/filled/end{ + icon_state = "trimline_end_fill"; + dir = 8 + }, +/turf/open/floor/plasteel, +/area/mafia) +"T" = ( +/obj/effect/turf_decal/trimline/brown/filled/line, +/obj/effect/turf_decal/trimline/brown/filled/line{ + icon_state = "trimline_fill"; + dir = 1 + }, +/turf/open/floor/plasteel, +/area/mafia) +"U" = ( +/obj/effect/turf_decal/trimline/brown/filled/line, +/obj/effect/turf_decal/trimline/brown/filled/corner{ + icon_state = "trimline_corner_fill"; + dir = 1 + }, +/turf/open/floor/plasteel, +/area/mafia) +"V" = ( +/obj/effect/turf_decal/trimline/brown/filled/line{ + icon_state = "trimline_fill"; + dir = 6 + }, +/turf/open/floor/plasteel, +/area/mafia) +"W" = ( +/obj/effect/turf_decal/tile/red{ + dir = 8 + }, +/obj/effect/turf_decal/tile/red{ + dir = 1 + }, +/turf/open/floor/plasteel/dark, +/area/mafia) +"X" = ( +/obj/effect/turf_decal/tile/red{ + dir = 1 + }, +/obj/effect/turf_decal/tile/red{ + dir = 4 + }, +/turf/open/floor/plasteel/dark, +/area/mafia) +"Y" = ( +/turf/closed/indestructible{ + icon = 'icons/turf/walls/reinforced_wall.dmi'; + icon_state = "r_wall"; + name = "reinforced wall" + }, +/area/mafia) + +(1,1,1) = {" +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +"} +(2,1,1) = {" +a +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +a +"} +(3,1,1) = {" +a +Y +Y +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +Y +Y +a +"} +(4,1,1) = {" +a +Y +Y +c +g +h +d +d +d +d +d +e +d +d +d +d +d +h +k +c +Y +Y +a +"} +(5,1,1) = {" +a +Y +Y +c +h +d +d +e +Y +Y +j +Y +j +Y +Y +d +d +i +h +c +Y +Y +a +"} +(6,1,1) = {" +a +Y +Y +c +i +Y +Y +j +Y +l +q +Y +s +H +Y +j +Y +Y +d +c +Y +Y +a +"} +(7,1,1) = {" +a +Y +c +c +d +Y +r +M +p +m +q +p +w +A +p +q +l +Y +d +c +c +Y +a +"} +(8,1,1) = {" +a +Y +c +d +d +Y +L +N +Y +Y +q +Y +x +Y +Y +q +m +Y +d +d +c +Y +a +"} +(9,1,1) = {" +a +Y +c +d +Y +Y +p +O +P +p +q +p +y +p +q +q +p +Y +Y +d +c +Y +a +"} +(10,1,1) = {" +a +Y +c +d +Y +l +p +Y +p +p +p +p +p +p +p +Y +p +K +Y +d +c +Y +a +"} +(11,1,1) = {" +a +Y +c +d +j +m +q +q +q +p +q +u +q +p +B +C +C +J +j +e +c +Y +a +"} +(12,1,1) = {" +a +Y +c +e +Y +Y +p +Y +p +p +t +R +X +p +p +Y +p +Y +Y +d +c +Y +a +"} +(13,1,1) = {" +a +Y +c +d +j +n +C +C +P +p +q +W +q +p +q +q +q +m +j +d +c +Y +a +"} +(14,1,1) = {" +a +Y +c +d +Y +o +p +Y +p +p +p +p +p +p +p +Y +p +l +Y +i +c +Y +a +"} +(15,1,1) = {" +a +Y +c +d +Y +Y +p +q +q +p +S +p +q +p +B +D +p +Y +Y +d +c +Y +a +"} +(16,1,1) = {" +a +Y +c +f +d +Y +m +q +Y +Y +T +Y +q +Y +Y +E +G +Y +d +d +c +Y +a +"} +(17,1,1) = {" +a +Y +c +c +d +Y +l +q +p +Q +U +p +q +m +p +F +I +Y +d +c +c +Y +a +"} +(18,1,1) = {" +a +Y +Y +c +d +Y +Y +j +Y +z +V +Y +q +l +Y +j +Y +Y +d +c +Y +Y +a +"} +(19,1,1) = {" +a +Y +Y +c +h +i +d +d +Y +Y +j +Y +j +Y +Y +d +e +d +h +c +Y +Y +a +"} +(20,1,1) = {" +a +Y +Y +c +k +h +d +d +e +d +d +d +d +d +d +d +d +h +v +c +Y +Y +a +"} +(21,1,1) = {" +a +Y +Y +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +Y +Y +a +"} +(22,1,1) = {" +a +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +a +"} +(23,1,1) = {" +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +"} diff --git a/_maps/map_files/Mafia/mafia_reebe.dmm b/_maps/map_files/Mafia/mafia_reebe.dmm new file mode 100644 index 0000000000..e82174ff93 --- /dev/null +++ b/_maps/map_files/Mafia/mafia_reebe.dmm @@ -0,0 +1,658 @@ +//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE +"a" = ( +/turf/closed/indestructible/riveted, +/area/mafia) +"b" = ( +/turf/open/indestructible/reebe_void, +/area/mafia) +"c" = ( +/turf/open/indestructible/reebe_void/spawning/lattices, +/area/mafia) +"d" = ( +/obj/mafia_game_board, +/turf/open/indestructible/reebe_void/spawning/lattices, +/area/mafia) +"e" = ( +/turf/closed/wall/clockwork, +/area/mafia) +"f" = ( +/turf/open/floor/clockwork/reebe, +/area/mafia) +"g" = ( +/obj/effect/landmark/mafia, +/turf/open/floor/clockwork/reebe, +/area/mafia) +"h" = ( +/obj/structure/window/reinforced/clockwork/fulltile, +/obj/structure/grille/ratvar, +/obj/machinery/door/poddoor/preopen{ + desc = "When it's time to sleep, the lights will go out. Remember - no one in space can hear you scream."; + id = "mafia"; + max_integrity = 99999; + name = "Station Night Shutters" + }, +/turf/open/floor/clockwork/reebe, +/area/mafia) +"i" = ( +/obj/structure/bed, +/obj/item/bedsheet/orange, +/turf/open/floor/clockwork/reebe, +/area/mafia) +"j" = ( +/obj/structure/chair/brass{ + dir = 4 + }, +/turf/open/floor/clockwork/reebe, +/area/mafia) +"k" = ( +/obj/structure/chair/brass, +/turf/open/floor/clockwork/reebe, +/area/mafia) +"l" = ( +/obj/structure/chair/brass{ + dir = 8 + }, +/turf/open/floor/clockwork/reebe, +/area/mafia) +"m" = ( +/obj/effect/baseturf_helper/asteroid, +/obj/effect/landmark/mafia/town_center, +/obj/structure/chair/brass, +/turf/open/floor/clockwork/reebe, +/area/mafia) +"n" = ( +/obj/structure/chair/brass{ + icon_state = "brass_chair"; + dir = 1 + }, +/turf/open/floor/clockwork/reebe, +/area/mafia) +"o" = ( +/obj/item/toy/plush/plushvar, +/turf/open/floor/clockwork/reebe, +/area/mafia) +"p" = ( +/obj/structure/window/reinforced/clockwork/fulltile, +/obj/structure/grille/ratvar, +/turf/open/floor/clockwork/reebe, +/area/mafia) +"q" = ( +/obj/item/toy/plush/plushvar, +/turf/open/indestructible/reebe_void/spawning/lattices, +/area/mafia) + +(1,1,1) = {" +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +"} +(2,1,1) = {" +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +"} +(3,1,1) = {" +a +b +b +c +c +c +b +b +b +b +b +b +b +b +b +b +b +c +c +c +b +b +a +"} +(4,1,1) = {" +a +b +b +c +d +c +b +b +b +b +b +b +b +b +b +b +b +q +d +c +b +b +a +"} +(5,1,1) = {" +a +b +b +c +c +c +c +b +e +e +p +e +p +e +e +b +b +c +c +c +b +b +a +"} +(6,1,1) = {" +a +b +b +b +b +p +p +e +e +i +f +e +f +i +e +e +p +p +c +b +b +b +a +"} +(7,1,1) = {" +a +b +b +b +b +p +i +f +h +g +f +h +f +g +h +f +i +p +b +b +b +b +a +"} +(8,1,1) = {" +a +b +b +b +b +e +g +f +e +e +f +e +f +e +e +f +g +e +b +b +b +b +a +"} +(9,1,1) = {" +a +b +b +b +e +e +h +f +j +h +j +h +j +h +j +f +h +e +e +b +b +b +a +"} +(10,1,1) = {" +a +b +b +b +e +i +h +e +h +h +h +h +h +h +h +e +h +i +e +b +b +b +a +"} +(11,1,1) = {" +a +b +b +b +p +g +f +f +k +h +f +f +o +h +n +f +f +g +p +b +b +b +a +"} +(12,1,1) = {" +a +b +b +b +e +e +h +e +h +h +f +m +f +h +h +e +h +e +e +b +b +b +a +"} +(13,1,1) = {" +a +b +b +b +p +g +f +f +k +h +f +f +f +h +n +f +f +g +p +b +b +b +a +"} +(14,1,1) = {" +a +b +b +b +e +i +h +e +h +h +h +h +h +h +h +e +h +i +e +b +b +b +a +"} +(15,1,1) = {" +a +b +b +b +e +e +h +f +l +h +l +h +l +h +l +f +h +e +e +b +b +b +a +"} +(16,1,1) = {" +a +b +b +b +b +e +g +f +e +e +f +e +f +e +e +f +g +e +b +b +b +b +a +"} +(17,1,1) = {" +a +b +b +b +b +p +i +f +h +g +f +h +f +g +h +f +i +p +b +b +b +b +a +"} +(18,1,1) = {" +a +b +b +b +b +p +p +e +e +f +i +e +i +f +e +e +p +p +c +b +b +b +a +"} +(19,1,1) = {" +a +b +b +c +c +c +c +b +e +e +p +e +p +e +e +b +b +c +c +c +b +b +a +"} +(20,1,1) = {" +a +b +b +c +d +c +b +b +b +b +b +b +b +b +b +b +b +c +d +c +b +b +a +"} +(21,1,1) = {" +a +b +b +c +c +c +b +b +b +b +b +b +b +b +b +b +b +c +c +c +b +b +a +"} +(22,1,1) = {" +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +"} +(23,1,1) = {" +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +"} diff --git a/_maps/map_files/Mafia/mafia_snow.dmm b/_maps/map_files/Mafia/mafia_snow.dmm new file mode 100644 index 0000000000..a47440f00e --- /dev/null +++ b/_maps/map_files/Mafia/mafia_snow.dmm @@ -0,0 +1,755 @@ +//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE +"a" = ( +/turf/closed/indestructible/riveted, +/area/mafia) +"d" = ( +/turf/open/floor/plating, +/area/mafia) +"e" = ( +/turf/open/floor/plating{ + icon_state = "platingdmg3" + }, +/area/mafia) +"f" = ( +/turf/open/floor/plating{ + icon_state = "panelscorched" + }, +/area/mafia) +"g" = ( +/obj/mafia_game_board, +/turf/open/floor/plating{ + icon_state = "platingdmg3" + }, +/area/mafia) +"h" = ( +/obj/structure/grille/indestructable, +/turf/open/floor/plating, +/area/mafia) +"i" = ( +/turf/open/floor/plating{ + icon_state = "platingdmg1" + }, +/area/mafia) +"j" = ( +/obj/machinery/door/airlock/maintenance_hatch{ + max_integrity = 99999; + name = "Maintenance" + }, +/obj/effect/mapping_helpers/airlock/locked, +/turf/open/floor/plating, +/area/mafia) +"k" = ( +/obj/mafia_game_board, +/turf/open/floor/plating, +/area/mafia) +"l" = ( +/obj/item/bedsheet/brown, +/obj/structure/bed, +/turf/open/floor/holofloor/wood, +/area/mafia) +"m" = ( +/obj/effect/landmark/mafia, +/turf/open/floor/holofloor/wood, +/area/mafia) +"n" = ( +/obj/item/bedsheet/green, +/obj/structure/bed, +/turf/open/floor/holofloor/wood, +/area/mafia) +"o" = ( +/obj/item/bedsheet/blue, +/obj/structure/bed, +/turf/open/floor/holofloor/wood, +/area/mafia) +"p" = ( +/obj/machinery/door/poddoor/preopen{ + desc = "When it's time to sleep, the lights will go out. Remember - no one in space can hear you scream."; + id = "mafia"; + max_integrity = 99999; + name = "Station Night Shutters" + }, +/turf/closed/indestructible/fakeglass, +/area/mafia) +"q" = ( +/turf/open/floor/plasteel/dark, +/area/mafia) +"r" = ( +/turf/open/floor/plasteel, +/area/mafia) +"s" = ( +/turf/closed/wall/ice, +/area/mafia) +"t" = ( +/turf/open/floor/holofloor/snow, +/area/mafia) +"u" = ( +/obj/structure/statue/plasma/scientist{ + anchored = 1 + }, +/turf/open/floor/holofloor/snow, +/area/mafia) +"v" = ( +/obj/effect/baseturf_helper/asteroid, +/obj/effect/landmark/mafia/town_center, +/turf/open/floor/holofloor/snow, +/area/mafia) +"w" = ( +/turf/open/lava/plasma, +/area/mafia) +"x" = ( +/obj/machinery/door/airlock/external{ + max_integrity = 9999; + opacity = 0 + }, +/obj/machinery/door/poddoor/preopen{ + desc = "When it's time to sleep, the lights will go out. Remember - no one in space can hear you scream."; + id = "mafia"; + max_integrity = 99999; + name = "Station Night Shutters" + }, +/obj/effect/mapping_helpers/airlock/locked, +/turf/open/floor/plasteel/dark, +/area/mafia) +"y" = ( +/obj/effect/landmark/mafia, +/turf/open/floor/holofloor/snow, +/area/mafia) +"z" = ( +/obj/structure/lattice/catwalk, +/turf/open/lava/plasma, +/area/mafia) +"A" = ( +/obj/machinery/door/airlock/external{ + max_integrity = 9999 + }, +/obj/machinery/door/poddoor/preopen{ + desc = "When it's time to sleep, the lights will go out. Remember - no one in space can hear you scream."; + id = "mafia"; + max_integrity = 99999; + name = "Station Night Shutters" + }, +/obj/effect/mapping_helpers/airlock/locked, +/turf/open/floor/plasteel, +/area/mafia) +"B" = ( +/obj/effect/landmark/mafia, +/obj/structure/lattice/catwalk, +/turf/open/lava/plasma, +/area/mafia) +"C" = ( +/obj/mafia_game_board, +/turf/open/floor/holofloor/snow, +/area/mafia) +"D" = ( +/obj/structure/closet/crate/science, +/obj/item/clothing/suit/hooded/wintercoat, +/obj/item/clothing/shoes/winterboots, +/turf/open/floor/holofloor/snow, +/area/mafia) +"E" = ( +/obj/structure/lattice/catwalk, +/obj/structure/closet/crate/critter, +/obj/item/clothing/suit/hooded/wintercoat/miner, +/obj/item/clothing/shoes/winterboots, +/turf/open/lava/plasma, +/area/mafia) +"F" = ( +/turf/open/floor/holofloor/wood, +/area/mafia) +"G" = ( +/obj/item/bedsheet/orange, +/obj/structure/bed, +/turf/open/floor/holofloor/wood, +/area/mafia) +"H" = ( +/obj/item/bedsheet/black, +/obj/structure/bed, +/turf/open/floor/holofloor/wood, +/area/mafia) +"I" = ( +/obj/item/bedsheet/red, +/obj/structure/bed, +/turf/open/floor/holofloor/wood, +/area/mafia) +"J" = ( +/turf/open/floor/plating/snowed/smoothed, +/area/mafia) +"K" = ( +/turf/closed/indestructible/rock/snow, +/area/mafia) + +(1,1,1) = {" +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +"} +(2,1,1) = {" +a +a +a +a +a +a +a +a +a +a +a +s +K +K +K +K +K +K +K +K +K +K +a +"} +(3,1,1) = {" +a +a +a +s +s +s +s +s +s +s +s +s +w +w +t +w +w +w +w +w +w +K +a +"} +(4,1,1) = {" +a +a +a +s +g +h +d +d +d +d +d +s +t +w +w +w +w +w +C +w +w +K +a +"} +(5,1,1) = {" +a +a +a +s +h +d +d +e +s +s +j +s +p +p +p +w +w +w +w +w +w +K +a +"} +(6,1,1) = {" +a +a +a +s +i +s +s +j +s +H +F +s +t +D +p +p +p +p +w +w +w +K +a +"} +(7,1,1) = {" +a +a +s +s +d +s +o +F +p +m +q +p +t +y +p +z +E +p +w +t +w +K +a +"} +(8,1,1) = {" +a +a +s +d +d +s +m +r +s +s +q +s +t +p +p +z +B +p +w +w +w +K +a +"} +(9,1,1) = {" +a +a +s +d +s +s +p +r +r +p +q +p +t +p +z +z +p +p +p +w +w +K +a +"} +(10,1,1) = {" +a +a +s +d +s +l +p +s +p +p +p +p +p +p +p +p +p +D +p +w +w +K +a +"} +(11,1,1) = {" +a +a +s +d +j +m +F +q +q +x +J +t +t +p +t +t +t +y +p +w +t +K +a +"} +(12,1,1) = {" +a +a +s +e +s +a +p +s +p +p +u +v +t +p +p +p +p +p +p +w +w +K +a +"} +(13,1,1) = {" +a +a +s +d +j +m +F +r +r +A +J +t +t +p +t +t +t +y +p +w +w +K +a +"} +(14,1,1) = {" +a +a +s +d +s +n +p +s +p +p +p +p +p +p +p +p +p +D +p +w +w +K +a +"} +(15,1,1) = {" +a +a +s +d +s +s +p +q +q +p +r +p +t +p +z +z +p +p +p +w +w +K +a +"} +(16,1,1) = {" +a +a +s +f +d +s +m +q +s +s +r +s +t +p +p +z +B +p +w +w +w +K +a +"} +(17,1,1) = {" +a +a +s +s +d +s +G +F +p +m +r +p +t +y +p +z +E +p +w +w +w +K +a +"} +(18,1,1) = {" +a +a +a +s +d +s +s +j +s +I +F +s +t +D +p +p +p +p +w +t +w +K +a +"} +(19,1,1) = {" +a +a +a +s +h +i +d +d +s +s +j +s +p +p +p +t +w +w +w +w +w +K +a +"} +(20,1,1) = {" +a +a +a +s +k +h +d +d +e +d +d +s +t +w +w +w +w +w +C +w +w +K +a +"} +(21,1,1) = {" +a +a +a +s +s +s +s +s +s +s +s +s +w +w +w +w +w +w +w +w +w +K +a +"} +(22,1,1) = {" +a +a +a +a +a +a +a +a +a +a +a +s +K +K +K +K +K +K +K +K +K +K +a +"} +(23,1,1) = {" +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +"} diff --git a/_maps/map_files/Mafia/mafia_spiderclan.dmm b/_maps/map_files/Mafia/mafia_spiderclan.dmm new file mode 100644 index 0000000000..89771212b8 --- /dev/null +++ b/_maps/map_files/Mafia/mafia_spiderclan.dmm @@ -0,0 +1,690 @@ +//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE +"a" = ( +/turf/closed/indestructible/riveted, +/area/mafia) +"b" = ( +/obj/structure/closet/cabinet{ + anchored = 1 + }, +/obj/item/reagent_containers/food/snacks/sashimi, +/turf/open/floor/carpet/black, +/area/mafia) +"c" = ( +/turf/closed/wall/rust, +/area/mafia) +"d" = ( +/turf/open/floor/plating, +/area/mafia) +"e" = ( +/turf/open/floor/plating{ + icon_state = "platingdmg3" + }, +/area/mafia) +"f" = ( +/turf/open/floor/plating{ + icon_state = "panelscorched" + }, +/area/mafia) +"g" = ( +/obj/mafia_game_board, +/turf/open/floor/plating{ + icon_state = "platingdmg3" + }, +/area/mafia) +"h" = ( +/obj/structure/grille/indestructable, +/turf/open/floor/plating, +/area/mafia) +"i" = ( +/turf/open/floor/plating{ + icon_state = "platingdmg1" + }, +/area/mafia) +"j" = ( +/turf/closed/wall/mineral/wood{ + desc = "A door that goes nowhere. How kafkaesque."; + icon = 'icons/obj/doors/mineral_doors.dmi'; + icon_state = "paperframe"; + name = "Door" + }, +/area/mafia) +"k" = ( +/obj/mafia_game_board, +/turf/open/floor/plating, +/area/mafia) +"m" = ( +/obj/effect/landmark/mafia, +/turf/open/floor/wood, +/area/mafia) +"n" = ( +/obj/effect/landmark/mafia, +/turf/open/floor/carpet/black, +/area/mafia) +"o" = ( +/obj/structure/closet/cabinet{ + anchored = 1 + }, +/obj/item/reagent_containers/food/snacks/sashimi, +/turf/open/floor/wood, +/area/mafia) +"p" = ( +/obj/machinery/door/poddoor/preopen{ + desc = "When it's time to sleep, the lights will go out. Remember - no one in space can hear you scream."; + id = "mafia"; + max_integrity = 99999; + name = "Station Night Shutters" + }, +/turf/closed/indestructible/fakeglass{ + icon = 'icons/obj/smooth_structures/paperframes.dmi'; + icon_state = "paper" + }, +/area/mafia) +"q" = ( +/turf/open/floor/wood, +/area/mafia) +"r" = ( +/turf/open/floor/carpet/black, +/area/mafia) +"t" = ( +/turf/open/floor/plating/beach/sand, +/area/mafia) +"u" = ( +/obj/effect/baseturf_helper/asteroid, +/obj/effect/landmark/mafia/town_center, +/turf/open/floor/plating/beach/sand, +/area/mafia) +"v" = ( +/obj/mafia_game_board, +/turf/open/floor/plating{ + icon_state = "panelscorched" + }, +/area/mafia) +"B" = ( +/obj/structure/showcase{ + density = 0; + desc = "Welp, only one way to recover your honour."; + icon = 'icons/obj/items_and_weapons.dmi'; + icon_state = "katana"; + name = "seppuku katana" + }, +/turf/open/floor/plating/beach/sand, +/area/mafia) +"S" = ( +/turf/closed/wall/mineral/wood, +/area/mafia) + +(1,1,1) = {" +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +"} +(2,1,1) = {" +a +S +S +S +S +S +S +S +S +S +S +S +S +S +S +S +S +S +S +S +S +S +a +"} +(3,1,1) = {" +a +S +S +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +S +S +a +"} +(4,1,1) = {" +a +S +S +c +g +h +d +d +d +d +d +e +d +d +d +d +d +h +k +c +S +S +a +"} +(5,1,1) = {" +a +S +S +c +h +d +d +e +S +S +j +S +j +S +S +d +d +i +h +c +S +S +a +"} +(6,1,1) = {" +a +S +S +c +i +S +S +j +S +o +q +S +r +b +S +j +S +S +d +c +S +S +a +"} +(7,1,1) = {" +a +S +c +c +d +S +b +r +p +m +q +p +r +n +p +q +o +S +d +c +c +S +a +"} +(8,1,1) = {" +a +S +c +d +d +S +n +r +S +S +q +S +r +S +S +q +m +S +d +d +c +S +a +"} +(9,1,1) = {" +a +S +c +d +S +S +p +r +r +p +q +p +r +p +q +q +p +S +S +d +c +S +a +"} +(10,1,1) = {" +a +S +c +d +S +o +p +S +p +p +p +p +p +p +p +S +p +b +S +d +c +S +a +"} +(11,1,1) = {" +a +S +c +d +j +m +q +q +q +p +t +t +t +p +r +r +r +n +j +e +c +S +a +"} +(12,1,1) = {" +a +S +c +e +S +S +p +S +p +p +t +u +B +p +p +S +p +S +S +d +c +S +a +"} +(13,1,1) = {" +a +S +c +d +j +n +r +r +r +p +t +t +t +p +q +q +q +m +j +d +c +S +a +"} +(14,1,1) = {" +a +S +c +d +S +b +p +S +p +p +p +p +p +p +p +S +p +o +S +i +c +S +a +"} +(15,1,1) = {" +a +S +c +d +S +S +p +q +q +p +r +p +q +p +r +r +p +S +S +d +c +S +a +"} +(16,1,1) = {" +a +S +c +f +d +S +m +q +S +S +r +S +q +S +S +r +n +S +d +d +c +S +a +"} +(17,1,1) = {" +a +S +c +c +d +S +o +q +p +n +r +p +q +m +p +r +b +S +d +c +c +S +a +"} +(18,1,1) = {" +a +S +S +c +d +S +S +j +S +b +r +S +q +o +S +j +S +S +d +c +S +S +a +"} +(19,1,1) = {" +a +S +S +c +h +i +d +d +S +S +j +S +j +S +S +d +e +d +h +c +S +S +a +"} +(20,1,1) = {" +a +S +S +c +k +h +d +d +e +d +d +d +d +d +d +d +d +h +v +c +S +S +a +"} +(21,1,1) = {" +a +S +S +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +S +S +a +"} +(22,1,1) = {" +a +S +S +S +S +S +S +S +S +S +S +S +S +S +S +S +S +S +S +S +S +S +a +"} +(23,1,1) = {" +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +"} diff --git a/_maps/map_files/Mafia/mafia_syndie.dmm b/_maps/map_files/Mafia/mafia_syndie.dmm new file mode 100644 index 0000000000..d56c3cc0c6 --- /dev/null +++ b/_maps/map_files/Mafia/mafia_syndie.dmm @@ -0,0 +1,869 @@ +//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE +"a" = ( +/turf/closed/indestructible/riveted, +/area/mafia) +"b" = ( +/obj/structure/closet/syndicate{ + desc = "A storage closet for syndicate conflict resolution operatives."; + name = "red closet" + }, +/obj/item/clothing/under/syndicate/tacticool, +/obj/item/clothing/under/syndicate/tacticool/skirt, +/turf/open/floor/mineral/plastitanium, +/area/mafia) +"c" = ( +/turf/closed/wall/rust, +/area/mafia) +"d" = ( +/turf/open/floor/plating, +/area/mafia) +"e" = ( +/turf/open/floor/plating{ + icon_state = "platingdmg3" + }, +/area/mafia) +"f" = ( +/turf/open/floor/plating{ + icon_state = "panelscorched" + }, +/area/mafia) +"g" = ( +/obj/mafia_game_board, +/turf/open/floor/plating{ + icon_state = "platingdmg3" + }, +/area/mafia) +"h" = ( +/obj/structure/grille/indestructable, +/turf/open/floor/plating, +/area/mafia) +"i" = ( +/turf/open/floor/plating{ + icon_state = "platingdmg1" + }, +/area/mafia) +"j" = ( +/obj/machinery/door/airlock/maintenance_hatch{ + max_integrity = 99999; + name = "Maintenance" + }, +/obj/effect/mapping_helpers/airlock/locked, +/turf/open/floor/plating, +/area/mafia) +"k" = ( +/obj/mafia_game_board, +/turf/open/floor/plating, +/area/mafia) +"l" = ( +/obj/structure/closet/syndicate{ + desc = "A storage closet for syndicate conflict resolution operatives."; + name = "red closet" + }, +/obj/item/clothing/under/syndicate/tacticool, +/obj/item/clothing/under/syndicate/tacticool/skirt, +/obj/effect/turf_decal/tile/red, +/obj/effect/turf_decal/tile/red{ + dir = 1 + }, +/obj/effect/turf_decal/tile/red{ + dir = 8 + }, +/obj/effect/turf_decal/tile/red{ + dir = 4 + }, +/turf/open/floor/plasteel/dark, +/area/mafia) +"m" = ( +/obj/structure/closet/syndicate{ + desc = "A storage closet for syndicate conflict resolution operatives."; + name = "red closet" + }, +/obj/item/clothing/under/syndicate/tacticool, +/obj/item/clothing/under/syndicate/tacticool/skirt, +/obj/effect/turf_decal/tile/red, +/obj/effect/turf_decal/tile/red{ + dir = 1 + }, +/obj/effect/turf_decal/tile/red{ + dir = 4 + }, +/obj/effect/turf_decal/tile/red{ + dir = 8 + }, +/turf/open/floor/plasteel/dark, +/area/mafia) +"n" = ( +/obj/effect/landmark/mafia, +/turf/open/floor/mineral/plastitanium, +/area/mafia) +"o" = ( +/obj/effect/turf_decal/tile/red, +/obj/effect/turf_decal/tile/red{ + dir = 4 + }, +/obj/effect/turf_decal/tile/red{ + dir = 8 + }, +/obj/effect/turf_decal/tile/red{ + dir = 1 + }, +/turf/open/floor/plasteel/dark, +/area/mafia) +"p" = ( +/obj/machinery/door/poddoor/preopen{ + desc = "When it's time to sleep, the lights will go out. Remember - no one in space can hear you scream."; + id = "mafia"; + max_integrity = 99999; + name = "Station Night Shutters" + }, +/obj/effect/spawner/structure/window/plastitanium, +/turf/open/space/basic, +/area/mafia) +"q" = ( +/obj/effect/turf_decal/tile/red, +/obj/effect/turf_decal/tile/red{ + dir = 4 + }, +/obj/effect/turf_decal/tile/red{ + dir = 8 + }, +/obj/effect/turf_decal/tile/red{ + dir = 1 + }, +/obj/structure/chair/office{ + dir = 1; + name = "tactical swivel chair" + }, +/turf/open/floor/plasteel/dark, +/area/mafia) +"r" = ( +/turf/open/floor/mineral/plastitanium, +/area/mafia) +"s" = ( +/turf/open/floor/mineral/plastitanium/red, +/area/mafia) +"t" = ( +/turf/open/floor/circuit/red, +/area/mafia) +"u" = ( +/obj/effect/baseturf_helper/asteroid, +/obj/effect/landmark/mafia/town_center, +/obj/structure/chair, +/turf/open/floor/circuit/red, +/area/mafia) +"v" = ( +/obj/mafia_game_board, +/turf/open/floor/plating{ + icon_state = "panelscorched" + }, +/area/mafia) +"w" = ( +/turf/closed/indestructible/syndicate, +/area/mafia) +"x" = ( +/obj/effect/turf_decal/tile/red, +/obj/effect/turf_decal/tile/red{ + dir = 4 + }, +/obj/effect/turf_decal/tile/red{ + dir = 8 + }, +/obj/effect/turf_decal/tile/red{ + dir = 1 + }, +/obj/structure/chair/office{ + dir = 4; + name = "tactical swivel chair" + }, +/turf/open/floor/plasteel/dark, +/area/mafia) +"y" = ( +/obj/structure/chair/office{ + dir = 2; + name = "tactical swivel chair" + }, +/turf/open/floor/mineral/plastitanium, +/area/mafia) +"z" = ( +/obj/effect/turf_decal/tile/red, +/obj/effect/turf_decal/tile/red{ + dir = 4 + }, +/obj/effect/turf_decal/tile/red{ + dir = 8 + }, +/obj/effect/turf_decal/tile/red{ + dir = 1 + }, +/obj/structure/chair/office{ + dir = 2; + name = "tactical swivel chair" + }, +/turf/open/floor/plasteel/dark, +/area/mafia) +"A" = ( +/obj/structure/chair/office{ + dir = 8; + name = "tactical swivel chair" + }, +/turf/open/floor/mineral/plastitanium, +/area/mafia) +"B" = ( +/obj/structure/chair/office{ + dir = 4; + name = "tactical swivel chair" + }, +/turf/open/floor/mineral/plastitanium, +/area/mafia) +"C" = ( +/obj/effect/turf_decal/tile/red, +/obj/effect/turf_decal/tile/red{ + dir = 4 + }, +/obj/effect/turf_decal/tile/red{ + dir = 8 + }, +/obj/effect/turf_decal/tile/red{ + dir = 1 + }, +/obj/structure/chair/office{ + dir = 8; + name = "tactical swivel chair" + }, +/turf/open/floor/plasteel/dark, +/area/mafia) +"E" = ( +/obj/structure/chair/office{ + dir = 1; + name = "tactical swivel chair" + }, +/turf/open/floor/mineral/plastitanium, +/area/mafia) +"F" = ( +/obj/effect/turf_decal/tile/red, +/obj/effect/turf_decal/tile/red{ + dir = 4 + }, +/obj/effect/turf_decal/tile/red{ + dir = 8 + }, +/obj/effect/turf_decal/tile/red{ + dir = 1 + }, +/obj/structure/closet/syndicate{ + desc = "A storage closet for syndicate conflict resolution operatives."; + name = "red closet" + }, +/obj/item/clothing/under/syndicate/tacticool, +/obj/item/clothing/under/syndicate/tacticool/skirt, +/turf/open/floor/plasteel/dark, +/area/mafia) +"G" = ( +/obj/effect/turf_decal/tile/red, +/obj/effect/turf_decal/tile/red{ + dir = 4 + }, +/obj/effect/turf_decal/tile/red{ + dir = 8 + }, +/obj/effect/turf_decal/tile/red{ + dir = 1 + }, +/obj/item/clothing/under/syndicate/tacticool, +/obj/structure/closet/syndicate{ + desc = "A storage closet for syndicate conflict resolution operatives."; + name = "red closet" + }, +/obj/item/clothing/under/syndicate/tacticool/skirt, +/turf/open/floor/plasteel/dark, +/area/mafia) +"H" = ( +/obj/effect/turf_decal/tile/red, +/obj/effect/turf_decal/tile/red{ + dir = 4 + }, +/obj/effect/turf_decal/tile/red{ + dir = 8 + }, +/obj/effect/turf_decal/tile/red{ + dir = 1 + }, +/obj/effect/landmark/mafia, +/turf/open/floor/plasteel/dark, +/area/mafia) + +(1,1,1) = {" +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +"} +(2,1,1) = {" +a +w +w +w +w +w +w +w +w +w +w +w +w +w +w +w +w +w +w +w +w +w +a +"} +(3,1,1) = {" +a +w +w +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +w +w +a +"} +(4,1,1) = {" +a +w +w +c +g +h +d +d +d +d +d +e +d +d +d +d +d +h +k +c +w +w +a +"} +(5,1,1) = {" +a +w +w +c +h +d +d +e +w +w +j +w +j +w +w +d +d +i +h +c +w +w +a +"} +(6,1,1) = {" +a +w +w +c +i +w +w +j +w +b +r +w +o +F +w +j +w +w +d +c +w +w +a +"} +(7,1,1) = {" +a +w +c +c +d +w +l +o +p +n +r +p +o +H +p +r +b +w +d +c +c +w +a +"} +(8,1,1) = {" +a +w +c +d +d +w +H +o +w +w +r +w +o +w +w +r +n +w +d +d +c +w +a +"} +(9,1,1) = {" +a +w +c +d +w +w +p +o +x +p +B +p +x +p +B +r +p +w +w +d +c +w +a +"} +(10,1,1) = {" +a +w +c +d +w +b +p +w +p +p +p +p +p +p +p +w +p +m +w +d +c +w +a +"} +(11,1,1) = {" +a +w +c +d +j +n +r +r +y +p +s +t +s +p +q +o +o +H +j +e +c +w +a +"} +(12,1,1) = {" +a +w +c +e +w +w +p +w +p +p +t +u +t +p +p +w +p +w +w +d +c +w +a +"} +(13,1,1) = {" +a +w +c +d +j +H +o +o +z +p +s +t +s +p +E +r +r +n +j +d +c +w +a +"} +(14,1,1) = {" +a +w +c +d +w +l +p +w +p +p +p +p +p +p +p +w +p +b +w +i +c +w +a +"} +(15,1,1) = {" +a +w +c +d +w +w +p +r +A +p +C +p +A +p +C +o +p +w +w +d +c +w +a +"} +(16,1,1) = {" +a +w +c +f +d +w +n +r +w +w +o +w +r +w +w +o +H +w +d +d +c +w +a +"} +(17,1,1) = {" +a +w +c +c +d +w +b +r +p +H +o +p +r +n +p +o +G +w +d +c +c +w +a +"} +(18,1,1) = {" +a +w +w +c +d +w +w +j +w +F +o +w +r +b +w +j +w +w +d +c +w +w +a +"} +(19,1,1) = {" +a +w +w +c +h +i +d +d +w +w +j +w +j +w +w +d +e +d +h +c +w +w +a +"} +(20,1,1) = {" +a +w +w +c +k +h +d +d +e +d +d +d +d +d +d +d +d +h +v +c +w +w +a +"} +(21,1,1) = {" +a +w +w +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +w +w +a +"} +(22,1,1) = {" +a +w +w +w +w +w +w +w +w +w +w +w +w +w +w +w +w +w +w +w +w +w +a +"} +(23,1,1) = {" +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +"} diff --git a/_maps/map_files/MetaStation/MetaStation.dmm b/_maps/map_files/MetaStation/MetaStation.dmm index 6415c984bf..6338213195 100644 --- a/_maps/map_files/MetaStation/MetaStation.dmm +++ b/_maps/map_files/MetaStation/MetaStation.dmm @@ -793,10 +793,16 @@ /turf/open/floor/plating, /area/security/prison) "abN" = ( -/turf/open/floor/plating{ - icon_state = "platingdmg3" +/obj/machinery/door/airlock/external{ + name = "Solar Maintenance"; + req_access_txt = "10; 13" }, -/area/security/prison) +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/effect/mapping_helpers/airlock/cyclelink_helper, +/turf/open/floor/plating, +/area/maintenance/solars/port/fore) "abO" = ( /obj/structure/cable{ icon_state = "1-4" @@ -954,6 +960,9 @@ /area/security/prison) "acg" = ( /obj/machinery/light/small, +/obj/effect/turf_decal/stripes/line{ + dir = 4 + }, /turf/open/floor/plating{ icon_state = "panelscorched" }, @@ -962,18 +971,22 @@ /obj/effect/turf_decal/stripes/line{ dir = 4 }, -/turf/open/floor/plating, -/area/security/prison) -"aci" = ( +/obj/effect/mapping_helpers/airlock/cyclelink_helper{ + dir = 4 + }, /obj/machinery/door/airlock/external{ name = "Security External Airlock"; req_access_txt = "1" }, -/obj/effect/mapping_helpers/airlock/cyclelink_helper{ - dir = 4 - }, /turf/open/floor/plating, /area/security/prison) +"aci" = ( +/obj/structure/lattice/catwalk, +/obj/machinery/door/airlock/external{ + req_one_access_txt = "13,8" + }, +/turf/open/space, +/area/maintenance/starboard/fore) "acj" = ( /obj/machinery/light/small{ dir = 1 @@ -2047,14 +2060,12 @@ /turf/open/floor/plating, /area/maintenance/solars/port/fore) "aef" = ( -/obj/machinery/door/airlock/external{ - name = "Solar Maintenance"; - req_access_txt = "10; 13" - }, /obj/structure/cable{ icon_state = "1-2" }, -/obj/effect/mapping_helpers/airlock/cyclelink_helper, +/obj/effect/turf_decal/stripes/line{ + dir = 1 + }, /turf/open/floor/plating, /area/maintenance/solars/port/fore) "aeg" = ( @@ -2310,9 +2321,6 @@ /obj/structure/cable{ icon_state = "1-2" }, -/obj/effect/turf_decal/stripes/line{ - dir = 1 - }, /turf/open/floor/plating, /area/maintenance/solars/port/fore) "aeH" = ( @@ -7007,14 +7015,8 @@ /turf/closed/wall, /area/crew_quarters/fitness/recreation) "amG" = ( -/obj/machinery/light/small{ - dir = 8 - }, -/obj/effect/turf_decal/stripes/line{ - dir = 6 - }, -/turf/open/floor/plating, -/area/maintenance/starboard/fore) +/turf/closed/wall, +/area/space) "amH" = ( /obj/machinery/door/airlock/external{ req_one_access_txt = "13,8" @@ -10324,6 +10326,7 @@ /turf/open/floor/carpet, /area/crew_quarters/dorms) "atd" = ( +/mob/living/simple_animal/opossum, /turf/open/floor/plating{ icon_state = "panelscorched" }, @@ -11552,19 +11555,15 @@ /turf/open/floor/plating/airless, /area/space/nearstation) "avJ" = ( -/obj/machinery/door/airlock/external, -/obj/effect/mapping_helpers/airlock/cyclelink_helper{ - dir = 4 +/obj/structure/sign/warning/vacuum/external{ + pixel_x = 32 }, /turf/open/floor/plating, -/area/maintenance/port/fore) +/area/maintenance/starboard/fore) "avK" = ( /obj/structure/sign/warning/vacuum/external{ pixel_y = 32 }, -/obj/effect/turf_decal/stripes/line{ - dir = 8 - }, /turf/open/floor/plating, /area/maintenance/port/fore) "avL" = ( @@ -37958,12 +37957,8 @@ /turf/open/floor/wood, /area/crew_quarters/heads/hop) "bwl" = ( -/obj/machinery/door/airlock/hatch{ - name = "MiniSat Space Access Airlock"; - req_one_access_txt = "32;19" - }, -/obj/effect/mapping_helpers/airlock/cyclelink_helper{ - dir = 8 +/obj/effect/turf_decal/stripes/line{ + dir = 4 }, /turf/open/floor/plasteel/dark, /area/engine/break_room) @@ -38523,9 +38518,6 @@ /obj/machinery/light/small{ dir = 1 }, -/obj/effect/turf_decal/stripes/line{ - dir = 4 - }, /turf/open/floor/plasteel/dark, /area/engine/break_room) "bxn" = ( @@ -44778,7 +44770,7 @@ dir = 8 }, /turf/open/space, -/area/aisat) +/area/space/nearstation) "bKR" = ( /obj/structure/window/reinforced{ dir = 8 @@ -46795,14 +46787,14 @@ /turf/open/floor/plasteel/showroomfloor, /area/crew_quarters/kitchen) "bOY" = ( -/obj/structure/sign/warning/vacuum/external{ - pixel_x = 32 +/obj/machinery/door/airlock/external{ + req_access_txt = "13" }, -/obj/effect/turf_decal/stripes/line{ - dir = 1 +/obj/effect/mapping_helpers/airlock/cyclelink_helper{ + dir = 8 }, /turf/open/floor/plating, -/area/maintenance/starboard/fore) +/area/space/nearstation) "bOZ" = ( /obj/machinery/chem_master/condimaster{ name = "CondiMaster Neo"; @@ -53608,9 +53600,6 @@ /obj/machinery/light/small{ dir = 1 }, -/obj/effect/turf_decal/stripes/line{ - dir = 4 - }, /turf/open/floor/plating, /area/engine/atmos) "ccY" = ( @@ -54893,17 +54882,12 @@ /turf/open/space, /area/solar/port/aft) "cfA" = ( -/obj/structure/cable/yellow{ - icon_state = "4-8" - }, -/obj/machinery/door/airlock/external{ - req_access_txt = "13" - }, +/obj/machinery/door/airlock/external, /obj/effect/mapping_helpers/airlock/cyclelink_helper{ dir = 4 }, /turf/open/floor/plating, -/area/maintenance/port/aft) +/area/maintenance/port/fore) "cfB" = ( /obj/machinery/atmospherics/pipe/simple/supply/hidden, /obj/structure/cable/yellow{ @@ -63172,12 +63156,9 @@ /turf/open/space, /area/solar/port/aft) "cvj" = ( -/obj/structure/closet/emcloset, -/obj/structure/sign/warning/vacuum/external{ - pixel_x = -32 - }, -/turf/open/floor/plating, -/area/maintenance/port/aft) +/obj/structure/lattice, +/turf/closed/wall/r_wall, +/area/engine/break_room) "cvk" = ( /obj/structure/closet/crate, /obj/item/crowbar/red, @@ -63663,7 +63644,10 @@ /turf/open/floor/plasteel, /area/science/circuit) "cwc" = ( -/obj/effect/turf_decal/stripes/line, +/obj/machinery/door/airlock/external{ + name = "Auxiliary Escape Airlock" + }, +/obj/effect/mapping_helpers/airlock/cyclelink_helper, /turf/open/floor/plating, /area/maintenance/aft) "cwd" = ( @@ -63692,9 +63676,14 @@ /obj/structure/cable/yellow{ icon_state = "4-8" }, -/obj/structure/lattice/catwalk, -/turf/open/space, -/area/space/nearstation) +/obj/machinery/door/airlock/external{ + req_access_txt = "13" + }, +/obj/effect/mapping_helpers/airlock/cyclelink_helper{ + dir = 4 + }, +/turf/open/floor/plating, +/area/maintenance/port/aft) "cwh" = ( /obj/structure/cable/yellow{ icon_state = "4-8" @@ -70268,7 +70257,7 @@ pixel_x = -32 }, /turf/open/space, -/area/space/nearstation) +/area/space) "cIz" = ( /obj/structure/disposalpipe/segment, /obj/machinery/atmospherics/pipe/simple/supply/hidden, @@ -70552,17 +70541,19 @@ /obj/structure/cable/yellow{ icon_state = "4-8" }, -/obj/effect/turf_decal/stripes/line{ - dir = 4 - }, /turf/open/floor/plating, /area/maintenance/starboard/aft) "cJf" = ( /obj/structure/cable/yellow{ - icon_state = "0-8" + icon_state = "4-8" }, -/obj/structure/lattice/catwalk, -/turf/open/space, +/obj/machinery/door/airlock/external{ + req_access_txt = "13" + }, +/obj/effect/mapping_helpers/airlock/cyclelink_helper{ + dir = 8 + }, +/turf/open/floor/plating, /area/space/nearstation) "cJg" = ( /obj/machinery/atmospherics/pipe/simple/supply/hidden, @@ -71812,6 +71803,7 @@ /obj/effect/turf_decal/stripes/line{ dir = 1 }, +/obj/effect/landmark/blobstart, /turf/open/floor/plating, /area/maintenance/aft) "cLA" = ( @@ -72156,15 +72148,12 @@ /turf/open/floor/plasteel, /area/hallway/secondary/exit/departure_lounge) "cMk" = ( -/obj/machinery/power/apc/highcap/five_k{ - areastring = "/area/maintenance/aft"; - name = "Aft Maintenance APC"; - pixel_y = -24 +/obj/structure/window/reinforced{ + dir = 1; + pixel_y = 1 }, -/obj/structure/cable/yellow, -/obj/effect/turf_decal/stripes/line, -/turf/open/floor/plating, -/area/maintenance/aft) +/turf/open/space, +/area/space) "cMl" = ( /obj/structure/table, /obj/item/stack/sheet/glass/fifty{ @@ -72749,10 +72738,6 @@ /turf/open/floor/plasteel, /area/hallway/secondary/exit/departure_lounge) "cNe" = ( -/obj/machinery/door/airlock/external{ - name = "Auxiliary Escape Airlock" - }, -/obj/effect/mapping_helpers/airlock/cyclelink_helper, /turf/open/floor/plating, /area/maintenance/aft) "cNf" = ( @@ -76630,9 +76615,6 @@ /obj/structure/cable{ icon_state = "4-8" }, -/obj/effect/turf_decal/stripes/line{ - dir = 4 - }, /turf/open/floor/plating, /area/maintenance/solars/starboard/aft) "dbR" = ( @@ -81312,6 +81294,19 @@ }, /turf/open/floor/plating, /area/maintenance/starboard/aft) +"gsT" = ( +/obj/machinery/door/airlock/external{ + name = "Solar Maintenance"; + req_access_txt = "10; 13" + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/effect/mapping_helpers/airlock/cyclelink_helper{ + dir = 8 + }, +/turf/open/floor/plating, +/area/solar/starboard/aft) "gEk" = ( /obj/structure/cable/yellow{ icon_state = "2-8" @@ -81349,9 +81344,7 @@ /turf/open/floor/plasteel, /area/science/misc_lab) "gNe" = ( -/obj/machinery/light/small{ - dir = 8 - }, +/obj/effect/turf_decal/stripes/line, /turf/open/floor/plating, /area/maintenance/aft) "gRS" = ( @@ -81392,6 +81385,10 @@ }, /turf/open/floor/plating, /area/maintenance/port/aft) +"hKW" = ( +/obj/structure/lattice, +/turf/open/space/basic, +/area/maintenance/aft) "ioI" = ( /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ dir = 4 @@ -81525,13 +81522,6 @@ /obj/structure/cable{ icon_state = "1-2" }, -/obj/machinery/door/airlock/external{ - name = "Solar Maintenance"; - req_access_txt = "10; 13" - }, -/obj/effect/mapping_helpers/airlock/cyclelink_helper{ - dir = 1 - }, /turf/open/floor/plating, /area/maintenance/solars/port/aft) "jAj" = ( @@ -81655,17 +81645,15 @@ /turf/open/floor/plasteel, /area/hallway/secondary/exit/departure_lounge) "kDM" = ( -/obj/structure/cable/yellow{ - icon_state = "4-8" - }, -/obj/machinery/door/airlock/external{ - req_access_txt = "13" +/obj/machinery/door/airlock/hatch{ + name = "MiniSat Space Access Airlock"; + req_one_access_txt = "32;19" }, /obj/effect/mapping_helpers/airlock/cyclelink_helper{ dir = 8 }, -/turf/open/floor/plating, -/area/maintenance/starboard/aft) +/turf/open/floor/plasteel/dark, +/area/engine/break_room) "kJW" = ( /obj/machinery/atmospherics/components/binary/pump{ dir = 1; @@ -81774,14 +81762,9 @@ /turf/open/space/basic, /area/space/nearstation) "lNZ" = ( -/obj/machinery/door/airlock/external{ - req_access_txt = "13" - }, -/obj/effect/mapping_helpers/airlock/cyclelink_helper{ - dir = 8 - }, -/turf/open/floor/plating, -/area/maintenance/starboard/fore) +/obj/structure/lattice/catwalk, +/turf/closed/wall/r_wall, +/area/engine/atmos) "lOi" = ( /obj/machinery/atmospherics/pipe/simple/supply/hidden{ dir = 4 @@ -81901,6 +81884,12 @@ }, /turf/open/floor/plating, /area/maintenance/port) +"mSd" = ( +/obj/structure/cable/yellow{ + icon_state = "4-8" + }, +/turf/open/floor/plating, +/area/maintenance/port/aft) "mWg" = ( /obj/structure/girder, /obj/structure/grille, @@ -82149,6 +82138,16 @@ /obj/structure/grille, /turf/open/floor/plating, /area/maintenance/port/aft) +"pbc" = ( +/obj/structure/light_construct/small{ + dir = 4 + }, +/obj/machinery/computer/security/telescreen/entertainment{ + pixel_x = 30 + }, +/mob/living/simple_animal/opossum/poppy, +/turf/open/floor/wood, +/area/maintenance/port/aft) "pbF" = ( /obj/machinery/portable_atmospherics/canister, /obj/machinery/atmospherics/components/unary/portables_connector/visible{ @@ -82466,8 +82465,9 @@ /turf/open/floor/plasteel, /area/science/circuit) "sdw" = ( -/turf/open/space/basic, -/area/space/nearstation) +/obj/structure/window/reinforced, +/turf/open/space, +/area/space) "siF" = ( /obj/structure/grille, /turf/open/floor/plating/airless, @@ -82565,6 +82565,12 @@ }, /turf/open/floor/plasteel/dark, /area/crew_quarters/cryopod) +"sUM" = ( +/obj/structure/sign/warning/vacuum/external{ + pixel_x = -32 + }, +/turf/open/floor/plating, +/area/maintenance/port/aft) "sZN" = ( /obj/structure/closet/firecloset, /turf/open/floor/plating, @@ -82651,6 +82657,13 @@ /obj/machinery/cryopod, /turf/open/floor/plasteel/dark, /area/crew_quarters/cryopod) +"uim" = ( +/obj/structure/cable/yellow{ + icon_state = "0-8" + }, +/obj/structure/lattice/catwalk, +/turf/open/space, +/area/space/nearstation) "uku" = ( /obj/machinery/atmospherics/pipe/manifold4w/general/visible, /turf/open/floor/plasteel, @@ -82821,6 +82834,10 @@ }, /turf/open/floor/plating, /area/security/prison) +"wkz" = ( +/obj/structure/lattice/catwalk, +/turf/open/space, +/area/space) "wlH" = ( /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ dir = 4 @@ -82842,12 +82859,8 @@ /turf/open/floor/plating, /area/maintenance/port/aft) "wxc" = ( -/obj/machinery/door/airlock/external{ - name = "Atmospherics External Airlock"; - req_access_txt = "24" - }, -/obj/effect/mapping_helpers/airlock/cyclelink_helper{ - dir = 8 +/obj/effect/turf_decal/stripes/line{ + dir = 4 }, /turf/open/floor/plating, /area/engine/atmos) @@ -82858,10 +82871,13 @@ /turf/open/floor/plating, /area/crew_quarters/cryopod) "wFH" = ( -/obj/structure/cable/yellow{ - icon_state = "1-2" +/obj/machinery/power/apc/highcap/five_k{ + areastring = "/area/maintenance/aft"; + name = "Aft Maintenance APC"; + pixel_y = -24 }, -/obj/effect/landmark/blobstart, +/obj/structure/cable/yellow, +/obj/effect/turf_decal/stripes/line, /turf/open/floor/plating, /area/maintenance/starboard/aft) "wKo" = ( @@ -82869,8 +82885,15 @@ /turf/closed/wall, /area/science/circuit) "wOE" = ( +/obj/machinery/door/airlock/external{ + name = "Atmospherics External Airlock"; + req_access_txt = "24" + }, +/obj/effect/mapping_helpers/airlock/cyclelink_helper{ + dir = 8 + }, /turf/open/floor/plating, -/area/maintenance/aft) +/area/engine/atmos) "wOY" = ( /obj/structure/fans/tiny/invisible, /turf/open/space/basic, @@ -82929,15 +82952,11 @@ /turf/open/floor/plasteel, /area/hallway/primary/port) "xse" = ( -/obj/machinery/door/airlock/external{ - name = "Solar Maintenance"; - req_access_txt = "10; 13" - }, /obj/structure/cable{ icon_state = "4-8" }, -/obj/effect/mapping_helpers/airlock/cyclelink_helper{ - dir = 8 +/obj/effect/turf_decal/stripes/line{ + dir = 4 }, /turf/open/floor/plating, /area/maintenance/solars/starboard/aft) @@ -83045,6 +83064,19 @@ }, /turf/open/floor/plating, /area/maintenance/port/aft) +"yfW" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/door/airlock/external{ + name = "Solar Maintenance"; + req_access_txt = "10; 13" + }, +/obj/effect/mapping_helpers/airlock/cyclelink_helper{ + dir = 1 + }, +/turf/open/floor/plating, +/area/maintenance/solars/port/aft) "ygk" = ( /obj/effect/turf_decal/stripes/line{ dir = 8 @@ -95227,9 +95259,9 @@ anS anS aaf aaf -aqB -anS -aaf +dne +cfA +dne aaf aaf aaf @@ -95485,7 +95517,7 @@ aaa aaa aaf dne -avJ +avL dne aaf aaa @@ -96570,7 +96602,7 @@ bXt bYC bYC bYC -aaa +bYC aaa aaf aaa @@ -96827,8 +96859,8 @@ bXu bYD bZN jyQ +yfW cda -cej cfz cED chY @@ -97084,7 +97116,7 @@ bXv bYC bYC bYC -aaa +bYC aaa aaf aaa @@ -99157,7 +99189,7 @@ ckN aaa aaf aaf -aaa +lMJ aaa aaf aaa @@ -99412,7 +99444,7 @@ ckQ cjt ckN aaf -aaf +ack cwf ack aaf @@ -99669,10 +99701,10 @@ cjt diJ dux dux -ack +dux cwg -ack -ack +dux +dux aaf aaa aaa @@ -99926,9 +99958,9 @@ crh dxv ctn dux -dux -cfA -dux +sUM +cwh +dyw dux aaf aaf @@ -100175,7 +100207,7 @@ csT dux cxQ ckS -cmi +pbc cnk ckP cmi @@ -100183,8 +100215,8 @@ dvt csf cto dux -cvj -cwh +cfF +mSd cxb dux aaa @@ -101636,7 +101668,7 @@ aaa aaa acT aaa -aaf +aee aee aee aee @@ -101893,7 +101925,7 @@ aaf aaf acU aak -aak +abN aef aeG afE @@ -102150,7 +102182,7 @@ aaa aaa aaf aaa -aaf +aee aee aee aee @@ -108569,7 +108601,7 @@ aaa aaa aaa wOY -abN +abe ach aax acN @@ -108827,7 +108859,7 @@ urv abe abe abe -aci +abL aax acO adh @@ -112795,7 +112827,7 @@ cFh cKH cLz wFH -cMk +bTs bTs bTs bTs @@ -113052,8 +113084,8 @@ cJN cCq cgN cMl -wOE bTs +hKW aaf aaf aaf @@ -113310,7 +113342,7 @@ cCq cLA bTs bTs -bTs +hKW aaf aaa aaa @@ -119474,7 +119506,7 @@ aaf aaa aaf dvY -kDM +cJd dvY aaa dbN @@ -119730,13 +119762,13 @@ cEA aaf aaa aaa -ack +blx cJf -ack -aaa -aaf -dbR +blx aaa +dbN +gsT +dbN aaa aaa aaa @@ -119882,7 +119914,7 @@ aaf aaa aaa aaa -sdw +aaa aaa acP acP @@ -119987,9 +120019,9 @@ blx aaa aaa aaa -aaa -aaf -aaa +wkz +uim +wkz aaa aaf dbR @@ -121512,7 +121544,7 @@ cpK ciL csc dvY -vLD +lMJ krD jyv ohj @@ -121769,7 +121801,7 @@ cpL crb csd dvY -vLD +lMJ krD krD noG @@ -123490,7 +123522,7 @@ aaa aaa aaf dni -amG +asB amH anN dnS @@ -123747,7 +123779,7 @@ aaf aaf aaf dnh -amH +avG dnh apd dnS @@ -124003,8 +124035,8 @@ aaa aaf aaa aaf -aaa -ack +dnh +aci dnh ape dnS @@ -127129,8 +127161,8 @@ aaa aaf bpw aaf -aaf -ack +cvj +kDM bxc bzg bAP @@ -127387,7 +127419,7 @@ aaf bpw aaa aaf -aaf +ack bxc bzh bAQ @@ -128179,9 +128211,9 @@ gJs bFZ bAR aaf -bxc +lNZ wxc -bxc +lNZ aaf aaa aaf @@ -128436,9 +128468,9 @@ bVN bXr bAR aaf -aMr -ccY -bBb +lNZ +wOE +lNZ aaf aaa aaf @@ -128693,7 +128725,7 @@ bVO bUJ bAR aaf -aMq +sdw ccY bgo aTQ @@ -129150,8 +129182,8 @@ aaa ack ack atn -bOY -avG +anN +dnS dqT aaf aaa @@ -129207,7 +129239,7 @@ bAR bAR bAR aaf -aMq +sdw ccY aVk aNC @@ -129407,8 +129439,8 @@ aaf aaf aaf dnh -dnh -lNZ +avJ +avG dqT aaf aaa @@ -129663,9 +129695,9 @@ aaa aaa aaf aaa -aaa -aaf -ack +amG +blx +bOY dqT aaf anT @@ -135867,7 +135899,7 @@ blA bnu bpH brU -aOV +cMk aaa aMq bzm @@ -136109,7 +136141,7 @@ aOU aOY aOY aOY -aTT +aNC aaa aaa aaa @@ -136127,7 +136159,7 @@ brV aRy aaa aaa -aTT +aNC aOY aOY aOY @@ -136366,7 +136398,7 @@ aOV aaa aaa aaa -aTU +aaf aaa aRy aRy @@ -136391,7 +136423,7 @@ aaa aaa aaa aaa -aTU +aaf aaa aaa aaa @@ -139450,7 +139482,7 @@ aOV aaa aaa aaa -aTU +aaf aaa aRy aRy @@ -139468,14 +139500,14 @@ bsh aRy bvt aaa -aTU +aaf aaa aaa aaa aaa aaa aaa -aTU +aaf aaa aaa aaa @@ -139707,7 +139739,7 @@ aOX aNw aNw aNw -aTY +bJl aaa aaa aaa @@ -139725,14 +139757,14 @@ bsi aRy aaa aaa -aTY +bJl aNw aNw aNw aNw aNw aNw -aTY +bJl aNw aNw aNw diff --git a/_maps/map_files/OmegaStation/OmegaStation.dmm b/_maps/map_files/OmegaStation/OmegaStation.dmm index f3b1b2afb6..db44dfb92a 100644 --- a/_maps/map_files/OmegaStation/OmegaStation.dmm +++ b/_maps/map_files/OmegaStation/OmegaStation.dmm @@ -1244,15 +1244,7 @@ /turf/closed/wall, /area/maintenance/starboard/fore) "abM" = ( -/obj/effect/turf_decal/stripes/line, -/obj/machinery/door/airlock/external{ - name = "External Airlock"; - req_access_txt = "13" - }, -/obj/effect/mapping_helpers/airlock/cyclelink_helper, -/obj/effect/turf_decal/stripes/line{ - dir = 1 - }, +/obj/effect/turf_decal/delivery, /turf/open/floor/plasteel, /area/maintenance/starboard/fore) "abN" = ( @@ -23608,22 +23600,9 @@ /turf/open/floor/engine, /area/engine/supermatter) "aKB" = ( -/obj/effect/turf_decal/stripes/line{ - dir = 8 - }, -/obj/effect/turf_decal/stripes/line{ - dir = 4 - }, /obj/machinery/atmospherics/pipe/simple/supply/hidden{ dir = 4 }, -/obj/machinery/door/airlock/external{ - name = "External Airlock"; - req_access_txt = "13" - }, -/obj/effect/mapping_helpers/airlock/cyclelink_helper{ - dir = 8 - }, /turf/open/floor/plasteel, /area/maintenance/port/aft) "aKC" = ( @@ -23645,14 +23624,23 @@ /turf/open/floor/plasteel/dark, /area/engine/engineering) "aKF" = ( +/obj/effect/turf_decal/stripes/line{ + dir = 8 + }, +/obj/effect/turf_decal/stripes/line{ + dir = 4 + }, /obj/machinery/atmospherics/pipe/simple/supply/hidden{ dir = 4 }, -/obj/structure/sign/warning/vacuum{ - pixel_x = -32; - pixel_y = 32 +/obj/machinery/door/airlock/external{ + name = "External Airlock"; + req_access_txt = "13" }, -/turf/open/floor/plating, +/obj/effect/mapping_helpers/airlock/cyclelink_helper{ + dir = 8 + }, +/turf/open/floor/plasteel, /area/maintenance/port/aft) "aKG" = ( /obj/structure/cable/white{ @@ -39608,9 +39596,17 @@ /turf/open/floor/plasteel, /area/engine/atmos) "edA" = ( -/obj/structure/lattice, -/turf/open/space/basic, -/area/space) +/obj/effect/turf_decal/stripes/line, +/obj/machinery/door/airlock/external{ + name = "External Airlock"; + req_access_txt = "13" + }, +/obj/effect/mapping_helpers/airlock/cyclelink_helper, +/obj/effect/turf_decal/stripes/line{ + dir = 1 + }, +/turf/open/floor/plasteel, +/area/maintenance/starboard/fore) "eew" = ( /obj/machinery/atmospherics/pipe/simple/supply/hidden, /obj/structure/cable{ @@ -41988,6 +41984,16 @@ }, /turf/open/floor/plasteel, /area/hydroponics) +"saI" = ( +/obj/structure/cable/white{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/supply/hidden{ + dir = 4 + }, +/mob/living/simple_animal/opossum, +/turf/open/floor/plating, +/area/maintenance/starboard) "scn" = ( /obj/structure/cable{ icon_state = "4-8" @@ -42866,9 +42872,6 @@ /obj/structure/sign/warning/securearea, /turf/closed/wall/rust, /area/maintenance/starboard) -"sIO" = ( -/turf/open/space/basic, -/area/space/nearstation) "sIP" = ( /obj/machinery/vending/cola/random, /obj/effect/turf_decal/bot, @@ -45205,6 +45208,10 @@ /obj/effect/landmark/carpspawn, /turf/open/space, /area/space/station_ruins) +"uXV" = ( +/mob/living/simple_animal/opossum/poppy, +/turf/open/floor/wood, +/area/maintenance/port/aft) "ver" = ( /obj/machinery/atmospherics/pipe/simple/scrubbers/visible{ dir = 10 @@ -71447,7 +71454,7 @@ aaa aaa aaa aaa -aaa +sdX uhz uhz oxn @@ -71704,7 +71711,7 @@ aac aac aac aac -aaa +sdX uhz iye mJP @@ -79446,7 +79453,7 @@ aFM aOH aOT aPV -aRm +uXV aSI aRC aKm @@ -91206,7 +91213,7 @@ aaa aae aaa aaa -aac +bxZ abL bxZ swz @@ -91463,7 +91470,7 @@ aaa aae aad aac -bvg +edA abM acu adt @@ -91720,7 +91727,7 @@ aad aah aad aad -aad +bxZ bxZ adq bxZ @@ -92526,7 +92533,7 @@ aSD aRz aRz aRz -sGY +saI aRz sIb bsD @@ -93045,7 +93052,7 @@ aRz sIc sIv sFs -sIO +aaa sIU sJe sIU @@ -98463,9 +98470,9 @@ aac aaa aaa aaa -edA +sdX aaa -edA +sdX aac aac aac @@ -98720,9 +98727,9 @@ aac aaa aaa aaa -edA +sdX aaa -edA +sdX aaa aac aaa @@ -98977,9 +98984,9 @@ aaa aaa aaa aaa -edA +sdX aaa -edA +sdX aaa aaa aaa @@ -99234,9 +99241,9 @@ aaa aaa aaa aaa -edA +sdX aaa -edA +sdX aaa aaa aaa @@ -99491,9 +99498,9 @@ aaa aaa aaa aaa -edA +sdX aaa -edA +sdX aaa aaa aaa @@ -99748,9 +99755,9 @@ aaa aaa aaa aaa -edA +sdX aaa -edA +sdX aaa aaa aaa @@ -100005,9 +100012,9 @@ jFP aaa aaa aaa -edA +sdX aaa -edA +sdX aaa aaa aaa @@ -100262,9 +100269,9 @@ jFP aaa aaa aaa -edA +sdX aaa -edA +sdX aaa aaa aaa @@ -100519,9 +100526,9 @@ jFP aaa aaa aaa -edA +sdX aaa -edA +sdX aaa aaa aaa @@ -100776,9 +100783,9 @@ jFP aaa aaa aaa -edA +sdX aaa -edA +sdX aaa aaa aaa @@ -101033,9 +101040,9 @@ jFP aaa aaa aaa -edA +sdX aaa -edA +sdX aaa aaa aaa @@ -101290,9 +101297,9 @@ jFP aaa aaa aaa -edA +sdX aaa -edA +sdX aaa aaa aaa @@ -101547,9 +101554,9 @@ jFP aaa aaa aaa -edA +sdX aaa -edA +sdX aaa aaa aaa @@ -101804,9 +101811,9 @@ jFP aaa aaa aaa -edA +sdX aaa -edA +sdX aaa aaa aaa @@ -102061,9 +102068,9 @@ jFP aaa aaa aaa -edA +sdX aaa -edA +sdX aaa aaa aaa @@ -102318,9 +102325,9 @@ jFP aaa aaa aaa -edA +sdX aaa -edA +sdX aaa aaa aaa @@ -102575,9 +102582,9 @@ jFP aaa aaa aaa -edA +sdX aaa -edA +sdX aaa aaa aaa @@ -102832,9 +102839,9 @@ jFP aaa aaa aaa -edA +sdX aaa -edA +sdX aaa aaa aaa @@ -103089,9 +103096,9 @@ jFP aaa aaa aaa -edA +sdX aaa -edA +sdX aaa aaa aaa @@ -103346,9 +103353,9 @@ jFP aaa aaa aaa -edA +sdX aaa -edA +sdX aaa aaa aaa @@ -103603,9 +103610,9 @@ jFP aaa aaa aaa -edA +sdX aaa -edA +sdX aaa aaa aaa @@ -103860,9 +103867,9 @@ jFP aaa aaa aaa -edA +sdX aaa -edA +sdX aaa aaa aaa @@ -104117,9 +104124,9 @@ jFP aaa aaa aaa -edA +sdX aaa -edA +sdX aaa aaa aaa @@ -104374,9 +104381,9 @@ jFP aaa aaa aaa -edA +sdX aaa -edA +sdX aaa aaa aaa @@ -104631,9 +104638,9 @@ jFP aaa aaa aaa -edA +sdX aaa -edA +sdX aaa aaa aaa @@ -104888,9 +104895,9 @@ aaa aaa aaa aaa -edA +sdX aaa -edA +sdX aaa aaa aaa @@ -105145,9 +105152,9 @@ aaa aaa aaa aaa -edA +sdX aaa -edA +sdX aaa aaa aaa @@ -105402,9 +105409,9 @@ aaa aaa aaa aaa -edA +sdX aaa -edA +sdX aaa aaa aaa diff --git a/_maps/map_files/PubbyStation/PubbyStation.dmm b/_maps/map_files/PubbyStation/PubbyStation.dmm index 29be428d66..846fe48604 100644 --- a/_maps/map_files/PubbyStation/PubbyStation.dmm +++ b/_maps/map_files/PubbyStation/PubbyStation.dmm @@ -1846,7 +1846,7 @@ network = list("minisat") }, /turf/open/space, -/area/ai_monitored/turret_protected/AIsatextAS) +/area/ai_monitored/turret_protected/AIsatextAP) "aeA" = ( /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ dir = 6 @@ -2622,9 +2622,6 @@ /obj/machinery/light/small{ dir = 8 }, -/obj/structure/sign/warning/vacuum/external{ - pixel_x = 32 - }, /obj/structure/sign/warning/vacuum/external{ pixel_x = -32 }, @@ -2744,12 +2741,8 @@ /turf/open/floor/plating, /area/security/main) "agR" = ( -/obj/effect/mapping_helpers/airlock/cyclelink_helper{ - dir = 1 - }, -/obj/machinery/door/airlock/external{ - name = "MiniSat External Access"; - req_access_txt = "65" +/obj/structure/sign/warning/vacuum/external{ + pixel_x = 32 }, /turf/open/floor/plating, /area/ai_monitored/turret_protected/aisat_interior) @@ -2821,11 +2814,14 @@ /turf/open/floor/plasteel/showroomfloor, /area/security/main) "ahh" = ( -/obj/structure/lattice/catwalk, -/obj/structure/showcase/cyborg/old{ - pixel_y = 20 +/obj/effect/mapping_helpers/airlock/cyclelink_helper{ + dir = 1 }, -/turf/open/space, +/obj/machinery/door/airlock/external{ + name = "MiniSat External Access"; + req_access_txt = "65" + }, +/turf/open/floor/plating, /area/space/nearstation) "ahi" = ( /obj/structure/lattice/catwalk, @@ -2927,13 +2923,8 @@ /turf/open/floor/plasteel/showroomfloor, /area/security/main) "ahr" = ( -/obj/structure/lattice, -/obj/machinery/camera/motion{ - c_tag = "MiniSat Entrance"; - network = list("minisat") - }, -/turf/open/space, -/area/space/nearstation) +/turf/closed/wall/r_wall, +/area/space) "ahs" = ( /obj/structure/lattice/catwalk, /obj/structure/transit_tube, @@ -4690,8 +4681,12 @@ /turf/open/space/basic, /area/space/nearstation) "alb" = ( -/turf/open/floor/wood, -/area/maintenance/department/crew_quarters/dorms) +/obj/structure/lattice/catwalk, +/obj/structure/showcase/cyborg/old{ + pixel_y = 20 + }, +/turf/open/space, +/area/space) "alc" = ( /obj/structure/table, /obj/item/storage/fancy/cigarettes/cigars, @@ -8703,13 +8698,9 @@ /turf/closed/wall, /area/bridge) "atZ" = ( -/obj/effect/mapping_helpers/airlock/cyclelink_helper, -/obj/machinery/door/airlock/external{ - name = "Bridge External Access"; - req_access_txt = "10;13" - }, -/turf/open/floor/plating, -/area/ai_monitored/turret_protected/aisat_interior) +/obj/structure/lattice/catwalk, +/turf/open/space, +/area/space) "aua" = ( /obj/structure/closet/secure_closet/freezer/money, /obj/item/reagent_containers/food/drinks/bottle/vodka/badminka, @@ -9124,9 +9115,6 @@ /obj/structure/sign/warning/vacuum/external{ pixel_x = -32 }, -/obj/machinery/light/small{ - dir = 1 - }, /turf/open/floor/plating, /area/bridge) "auV" = ( @@ -13689,14 +13677,13 @@ /turf/open/floor/plating, /area/maintenance/department/cargo) "aFj" = ( -/obj/effect/mapping_helpers/airlock/cyclelink_helper{ - dir = 8 +/obj/structure/lattice, +/obj/machinery/camera/motion{ + c_tag = "MiniSat Entrance"; + network = list("minisat") }, -/obj/machinery/door/airlock/external{ - req_access_txt = "13" - }, -/turf/open/floor/plating, -/area/maintenance/department/cargo) +/turf/open/space, +/area/space/nearstation) "aFk" = ( /obj/machinery/atmospherics/pipe/simple/supply/hidden, /obj/effect/spawner/lootdrop/minor/bowler_or_that, @@ -22864,11 +22851,13 @@ /turf/closed/wall, /area/maintenance/solars/starboard) "baH" = ( -/obj/structure/rack, -/obj/item/clothing/mask/gas, -/obj/item/multitool, +/obj/effect/mapping_helpers/airlock/cyclelink_helper, +/obj/machinery/door/airlock/external{ + name = "Bridge External Access"; + req_access_txt = "10;13" + }, /turf/open/floor/plating, -/area/maintenance/solars/starboard) +/area/ai_monitored/turret_protected/aisat_interior) "baI" = ( /obj/structure/cable{ icon_state = "0-8" @@ -23315,13 +23304,6 @@ /turf/open/floor/plasteel, /area/quartermaster/miningdock) "bbL" = ( -/obj/machinery/power/smes, -/obj/structure/cable{ - icon_state = "0-2" - }, -/turf/open/floor/plating, -/area/maintenance/solars/starboard) -"bbM" = ( /obj/machinery/power/terminal{ dir = 8 }, @@ -23333,17 +23315,10 @@ }, /turf/open/floor/plating, /area/maintenance/solars/starboard) -"bbO" = ( -/obj/structure/cable{ - icon_state = "4-8" - }, -/obj/effect/mapping_helpers/airlock/cyclelink_helper{ - dir = 4 - }, -/obj/machinery/door/airlock/external{ - name = "Solar Maintenance"; - req_access_txt = "10; 13" - }, +"bbM" = ( +/obj/structure/rack, +/obj/item/clothing/mask/gas, +/obj/item/multitool, /turf/open/floor/plating, /area/maintenance/solars/starboard) "bbP" = ( @@ -23757,16 +23732,6 @@ /turf/open/floor/plating, /area/maintenance/department/cargo) "bcJ" = ( -/obj/structure/cable{ - icon_state = "4-8" - }, -/obj/machinery/door/airlock/engineering{ - name = "Starboard Solar Access"; - req_access_txt = "10" - }, -/turf/open/floor/plating, -/area/maintenance/solars/starboard) -"bcK" = ( /obj/structure/cable{ icon_state = "1-2" }, @@ -23775,25 +23740,39 @@ }, /turf/open/floor/plating, /area/maintenance/solars/starboard) -"bcL" = ( +"bcK" = ( /obj/structure/cable{ icon_state = "1-4" }, /turf/open/floor/plating, /area/maintenance/solars/starboard) -"bcN" = ( -/obj/machinery/power/solar_control{ - dir = 8; - id = "starboardsolar"; - name = "Starboard Solar Control" +"bcL" = ( +/obj/structure/cable{ + icon_state = "2-4" + }, +/obj/structure/cable{ + icon_state = "4-8" }, -/obj/structure/cable, /turf/open/floor/plating, /area/maintenance/solars/starboard) +"bcN" = ( +/obj/machinery/light/small{ + dir = 1 + }, +/obj/effect/decal/cleanable/cobweb, +/turf/open/floor/plating, +/area/bridge) "bcO" = ( /obj/structure/cable{ icon_state = "4-8" }, +/obj/effect/mapping_helpers/airlock/cyclelink_helper{ + dir = 8 + }, +/obj/machinery/door/airlock/external{ + name = "Solar Maintenance"; + req_access_txt = "10; 13" + }, /turf/open/floor/plating, /area/maintenance/solars/starboard) "bcQ" = ( @@ -24156,17 +24135,17 @@ }, /area/maintenance/department/cargo) "bdR" = ( -/obj/structure/cable, -/obj/machinery/power/apc{ - dir = 8; - name = "Starboard Solar APC"; - pixel_x = -24 - }, +/obj/structure/chair/stool, +/obj/item/cigbutt/cigarbutt, /turf/open/floor/plating, /area/maintenance/solars/starboard) "bdS" = ( -/obj/structure/chair/stool, -/obj/item/cigbutt/cigarbutt, +/obj/machinery/power/solar_control{ + dir = 8; + id = "starboardsolar"; + name = "Starboard Solar Control" + }, +/obj/structure/cable, /turf/open/floor/plating, /area/maintenance/solars/starboard) "bdU" = ( @@ -27986,7 +27965,7 @@ dir = 8 }, /turf/open/floor/plasteel/white, -/area/storage/emergency/port) +/area/medical/medbay/zone3) "bny" = ( /obj/machinery/atmospherics/pipe/simple/supply/hidden, /obj/machinery/firealarm{ @@ -28005,7 +27984,7 @@ dir = 4 }, /turf/open/floor/plasteel/white, -/area/storage/emergency/port) +/area/medical/medbay/zone3) "bnz" = ( /obj/structure/table, /obj/item/folder/white, @@ -43266,7 +43245,7 @@ /obj/structure/closet/firecloset, /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, /turf/open/floor/plasteel, -/area/engine/atmos) +/area/engine/break_room) "bTR" = ( /obj/machinery/atmospherics/pipe/simple/yellow/visible{ dir = 4 @@ -43455,7 +43434,7 @@ /obj/effect/turf_decal/delivery, /obj/structure/closet/firecloset, /turf/open/floor/plasteel, -/area/engine/atmos) +/area/engine/break_room) "bUp" = ( /obj/machinery/atmospherics/pipe/simple/scrubbers/visible, /turf/open/floor/plasteel, @@ -43848,7 +43827,7 @@ /obj/effect/turf_decal/delivery, /obj/machinery/atmospherics/pipe/manifold4w/scrubbers, /turf/open/floor/plasteel, -/area/engine/atmos) +/area/engine/break_room) "bVd" = ( /obj/machinery/door/airlock/atmos{ name = "Atmospherics"; @@ -45016,10 +44995,6 @@ /turf/open/floor/plating, /area/chapel/asteroid/monastery) "bXN" = ( -/obj/effect/mapping_helpers/airlock/cyclelink_helper{ - dir = 8 - }, -/obj/machinery/door/airlock/external, /turf/open/floor/plating, /area/chapel/asteroid/monastery) "bXS" = ( @@ -45926,12 +45901,21 @@ /obj/machinery/atmospherics/components/unary/outlet_injector/atmos/incinerator_input{ dir = 8 }, +/obj/machinery/air_sensor/atmos/incinerator_tank{ + pixel_x = 32; + pixel_y = -32 + }, /turf/open/floor/engine, /area/maintenance/disposal/incinerator) "bZV" = ( -/obj/structure/sign/warning/fire, -/turf/closed/wall/r_wall, -/area/maintenance/disposal/incinerator) +/obj/effect/mapping_helpers/airlock/cyclelink_helper{ + dir = 8 + }, +/obj/machinery/door/airlock/external{ + req_access_txt = "13" + }, +/turf/open/floor/plating, +/area/maintenance/department/cargo) "bZY" = ( /turf/closed/wall, /area/chapel/office) @@ -46149,13 +46133,15 @@ icon_state = "4-8" }, /obj/machinery/igniter/incinerator_atmos, -/obj/machinery/air_sensor/atmos/incinerator_tank{ - pixel_x = 32; - pixel_y = -32 - }, /turf/open/floor/engine, /area/maintenance/disposal/incinerator) "caP" = ( +/obj/structure/cable/yellow{ + icon_state = "4-8" + }, +/turf/open/floor/engine, +/area/maintenance/disposal/incinerator) +"caQ" = ( /obj/structure/cable/yellow{ icon_state = "0-8" }, @@ -46167,13 +46153,9 @@ dir = 8; luminosity = 2 }, -/obj/machinery/camera{ - c_tag = "Turbine Chamber"; - network = list("turbine") - }, /turf/open/floor/engine, /area/maintenance/disposal/incinerator) -"caQ" = ( +"caR" = ( /obj/structure/cable/yellow{ icon_state = "0-8" }, @@ -46183,10 +46165,6 @@ }, /turf/open/floor/engine, /area/maintenance/disposal/incinerator) -"caR" = ( -/obj/machinery/door/poddoor/incinerator_atmos_main, -/turf/open/floor/engine/vacuum, -/area/maintenance/disposal/incinerator) "caS" = ( /turf/closed/wall, /area/chapel/asteroid/monastery) @@ -46611,9 +46589,9 @@ /turf/open/floor/plasteel/dark, /area/maintenance/disposal/incinerator) "ccs" = ( -/obj/machinery/door/poddoor/incinerator_atmos_aux, -/turf/open/floor/engine/vacuum, -/area/maintenance/disposal/incinerator) +/obj/structure/lattice, +/turf/closed/wall, +/area/maintenance/department/cargo) "ccu" = ( /obj/structure/flora/ausbushes/leafybush, /turf/open/floor/plating/asteroid, @@ -46786,13 +46764,6 @@ /turf/open/floor/plating, /area/maintenance/disposal/incinerator) "cdl" = ( -/obj/effect/mapping_helpers/airlock/cyclelink_helper{ - dir = 8 - }, -/obj/machinery/door/airlock/external{ - name = "Atmospherics External Access"; - req_access_txt = "24" - }, /turf/open/floor/plating, /area/maintenance/disposal/incinerator) "cdm" = ( @@ -47328,6 +47299,9 @@ /obj/structure/cable{ icon_state = "1-2" }, +/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ + dir = 4 + }, /turf/open/floor/plasteel/dark, /area/engine/engineering) "cfu" = ( @@ -47446,14 +47420,12 @@ /turf/open/floor/plasteel/dark, /area/engine/engineering) "cfQ" = ( -/obj/structure/chair{ - dir = 8 +/obj/machinery/power/smes, +/obj/structure/cable{ + icon_state = "0-2" }, -/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ - dir = 9 - }, -/turf/open/floor/plasteel/dark, -/area/engine/engineering) +/turf/open/floor/plating, +/area/maintenance/solars/starboard) "cfS" = ( /obj/structure/table/reinforced, /obj/item/tank/internals/emergency_oxygen/engi, @@ -47579,14 +47551,12 @@ /turf/open/floor/plating, /area/engine/engineering) "cgs" = ( -/obj/effect/mapping_helpers/airlock/cyclelink_helper, -/obj/machinery/door/airlock/external{ - name = "Engineering External Access"; - req_access_txt = "61" - }, /obj/structure/cable{ icon_state = "1-2" }, +/obj/machinery/light/small{ + dir = 8 + }, /turf/open/floor/plating, /area/engine/engineering) "cgu" = ( @@ -47678,9 +47648,6 @@ /turf/open/floor/plating/airless, /area/space/nearstation) "cgQ" = ( -/obj/machinery/light/small{ - dir = 8 - }, /obj/structure/sign/warning/vacuum/external{ pixel_x = -32 }, @@ -49453,7 +49420,7 @@ /obj/structure/lattice, /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, /turf/open/space/basic, -/area/ai_monitored/turret_protected/AIsatextAS) +/area/ai_monitored/turret_protected/AIsatextAP) "cnJ" = ( /obj/effect/turf_decal/delivery, /obj/machinery/vending/wardrobe/sec_wardrobe, @@ -50434,6 +50401,15 @@ /turf/open/floor/plating, /area/maintenance/department/engine) "crB" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/light/small{ + dir = 1 + }, +/turf/open/floor/plating, +/area/maintenance/department/engine) +"crC" = ( /obj/effect/mapping_helpers/airlock/cyclelink_helper{ dir = 8 }, @@ -50445,15 +50421,6 @@ }, /turf/open/floor/plating, /area/maintenance/department/engine) -"crC" = ( -/obj/machinery/light/small{ - dir = 1 - }, -/obj/structure/disposalpipe/segment{ - dir = 4 - }, -/turf/open/floor/plating, -/area/maintenance/department/engine) "crD" = ( /obj/structure/table/wood/fancy, /obj/item/storage/box/bodybags, @@ -53207,6 +53174,10 @@ }, /turf/open/floor/plasteel, /area/hallway/primary/aft) +"dhS" = ( +/obj/structure/window/reinforced, +/turf/open/space/basic, +/area/space) "dir" = ( /obj/machinery/atmospherics/pipe/simple/general/visible{ dir = 5 @@ -53580,13 +53551,15 @@ /turf/open/floor/plating, /area/maintenance/department/engine) "dWp" = ( -/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ - dir = 4 +/obj/effect/mapping_helpers/airlock/cyclelink_helper, +/obj/machinery/door/airlock/external{ + name = "Engineering External Access"; + req_access_txt = "61" }, /obj/structure/cable{ icon_state = "1-2" }, -/turf/open/floor/plasteel/dark, +/turf/open/floor/plating, /area/engine/engineering) "dYe" = ( /obj/structure/cable{ @@ -53959,6 +53932,9 @@ /obj/effect/turf_decal/arrows{ dir = 8 }, +/obj/machinery/atmospherics/components/unary/vent_scrubber/on{ + dir = 4 + }, /turf/open/floor/plasteel/dark, /area/engine/engineering) "eWi" = ( @@ -54046,6 +54022,20 @@ }, /turf/open/floor/plasteel, /area/construction/mining/aux_base) +"fgS" = ( +/obj/effect/turf_decal/tile/neutral{ + dir = 1 + }, +/obj/effect/turf_decal/tile/neutral, +/obj/effect/turf_decal/tile/neutral{ + dir = 4 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 8 + }, +/mob/living/simple_animal/opossum/poppy, +/turf/open/floor/plasteel/dark, +/area/maintenance/department/engine) "fhM" = ( /obj/item/storage/secure/safe{ pixel_x = -22 @@ -54346,6 +54336,9 @@ }, /turf/open/floor/plasteel, /area/engine/engineering) +"fRr" = ( +/turf/open/floor/engine/vacuum, +/area/maintenance/disposal/incinerator) "fRs" = ( /turf/closed/wall, /area/crew_quarters/heads/hor) @@ -54558,6 +54551,16 @@ }, /turf/open/floor/plasteel, /area/hallway/secondary/exit/departure_lounge) +"gmZ" = ( +/obj/effect/mapping_helpers/airlock/cyclelink_helper{ + dir = 8 + }, +/obj/machinery/door/airlock/external{ + name = "Atmospherics External Access"; + req_access_txt = "24" + }, +/turf/open/floor/plating, +/area/maintenance/disposal/incinerator) "gna" = ( /turf/open/floor/plasteel/stairs/medium, /area/maintenance/department/crew_quarters/dorms) @@ -54918,6 +54921,10 @@ /obj/effect/turf_decal/stripes/line, /turf/open/floor/plasteel, /area/engine/engineering) +"hbl" = ( +/obj/machinery/door/poddoor/incinerator_atmos_main, +/turf/open/floor/engine/vacuum, +/area/space) "heC" = ( /obj/machinery/power/apc/highcap/five_k{ dir = 8; @@ -55265,14 +55272,15 @@ /turf/open/floor/engine, /area/engine/engineering) "hSM" = ( -/obj/effect/mapping_helpers/airlock/cyclelink_helper{ - dir = 8 +/obj/structure/cable{ + icon_state = "4-8" }, -/obj/machinery/door/airlock/external{ - req_access_txt = "13" +/obj/machinery/door/airlock/engineering{ + name = "Starboard Solar Access"; + req_access_txt = "10" }, /turf/open/floor/plating, -/area/maintenance/department/science) +/area/maintenance/solars/starboard) "hTl" = ( /obj/structure/sink{ dir = 4; @@ -55381,6 +55389,13 @@ /obj/effect/turf_decal/stripes/line, /turf/open/floor/engine, /area/engine/engineering) +"igB" = ( +/obj/machinery/camera{ + c_tag = "Turbine Chamber"; + network = list("turbine") + }, +/turf/open/floor/engine, +/area/maintenance/disposal/incinerator) "igE" = ( /obj/structure/table/reinforced, /obj/machinery/button/door{ @@ -55653,7 +55668,7 @@ dir = 9 }, /turf/open/floor/plasteel/white, -/area/storage/emergency/port) +/area/medical/medbay/zone3) "iJi" = ( /obj/machinery/atmospherics/pipe/simple/supply/hidden{ dir = 5 @@ -57255,6 +57270,15 @@ }, /turf/open/floor/plasteel, /area/science/xenobiology) +"mvm" = ( +/obj/structure/cable, +/obj/machinery/power/apc{ + dir = 8; + name = "Starboard Solar APC"; + pixel_x = -24 + }, +/turf/open/floor/plating, +/area/maintenance/solars/starboard) "mwg" = ( /obj/structure/closet/crate{ icon_state = "crateopen" @@ -57445,6 +57469,10 @@ /obj/effect/landmark/start/paramedic, /turf/open/floor/plasteel/white, /area/medical/medbay/central) +"nbu" = ( +/obj/structure/sign/warning/fire, +/turf/closed/wall/r_wall, +/area/space) "ncm" = ( /obj/machinery/atmospherics/pipe/simple/cyan/visible{ dir = 4 @@ -58021,6 +58049,10 @@ }, /turf/open/floor/plasteel/dark, /area/tcommsat/computer) +"ore" = ( +/obj/structure/closet/firecloset, +/turf/open/floor/plating, +/area/engine/engineering) "ost" = ( /obj/structure/table/glass, /obj/item/paper_bin{ @@ -58132,13 +58164,6 @@ /obj/structure/cable{ icon_state = "4-8" }, -/obj/effect/mapping_helpers/airlock/cyclelink_helper{ - dir = 8 - }, -/obj/machinery/door/airlock/external{ - name = "Solar Maintenance"; - req_access_txt = "10; 13" - }, /turf/open/floor/plating, /area/maintenance/solars/starboard) "oDP" = ( @@ -58207,6 +58232,12 @@ /obj/item/stack/sheet/mineral/wood, /turf/open/floor/plasteel, /area/maintenance/department/engine) +"oGw" = ( +/obj/item/clothing/mask/gas, +/turf/open/floor/plating{ + icon_state = "platingdmg3" + }, +/area/maintenance/disposal/incinerator) "oHa" = ( /obj/machinery/power/emitter/anchored{ dir = 8; @@ -58645,6 +58676,10 @@ "pyw" = ( /turf/open/space/basic, /area/hallway/secondary/entry) +"pzF" = ( +/mob/living/simple_animal/opossum, +/turf/open/floor/wood, +/area/maintenance/department/crew_quarters/dorms) "pBD" = ( /obj/structure/cable{ icon_state = "0-8" @@ -59237,6 +59272,10 @@ }, /turf/open/floor/plasteel, /area/hallway/secondary/exit/departure_lounge) +"qVk" = ( +/obj/machinery/door/poddoor/incinerator_atmos_aux, +/turf/open/space/basic, +/area/maintenance/disposal/incinerator) "qVP" = ( /obj/machinery/door/firedoor, /obj/machinery/atmospherics/pipe/simple/supply/hidden{ @@ -59545,6 +59584,13 @@ icon_state = "panelscorched" }, /area/maintenance/department/engine) +"rzF" = ( +/obj/effect/mapping_helpers/airlock/cyclelink_helper{ + dir = 8 + }, +/obj/machinery/door/airlock/external, +/turf/open/floor/plating, +/area/space/nearstation) "rBh" = ( /obj/structure/mopbucket, /obj/item/mop, @@ -60049,7 +60095,6 @@ /turf/open/floor/plasteel/dark, /area/chapel/office) "tap" = ( -/obj/structure/reagent_dispensers/keg/aphro, /turf/open/floor/wood, /area/maintenance/department/crew_quarters/dorms) "taA" = ( @@ -60860,12 +60905,16 @@ /turf/open/floor/plasteel, /area/science/xenobiology) "uXH" = ( -/obj/structure/cable{ - icon_state = "2-4" - }, /obj/structure/cable{ icon_state = "4-8" }, +/obj/effect/mapping_helpers/airlock/cyclelink_helper{ + dir = 4 + }, +/obj/machinery/door/airlock/external{ + name = "Solar Maintenance"; + req_access_txt = "10; 13" + }, /turf/open/floor/plating, /area/maintenance/solars/starboard) "uZb" = ( @@ -61163,6 +61212,15 @@ }, /turf/open/floor/plating, /area/maintenance/department/engine) +"vHf" = ( +/obj/effect/mapping_helpers/airlock/cyclelink_helper{ + dir = 8 + }, +/obj/machinery/door/airlock/external{ + req_access_txt = "13" + }, +/turf/open/floor/plating, +/area/maintenance/department/science) "vIc" = ( /obj/structure/cable{ icon_state = "2-4" @@ -62228,7 +62286,9 @@ /obj/structure/chair{ dir = 8 }, -/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, +/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ + dir = 9 + }, /turf/open/floor/plasteel/dark, /area/engine/engineering) @@ -77483,9 +77543,9 @@ rLi tlc aiu aht -aaa -azH -aaa +axB +rKr +axB aaa aaa aaa @@ -77743,7 +77803,7 @@ axC axB rKr axB -axC +aaa aaa aaa aaa @@ -78000,7 +78060,7 @@ axC ayz azN axB -axC +aaa aaa aaa aaa @@ -81836,7 +81896,7 @@ ahB ahZ aiB ajc -agy +ajM akB alq alZ @@ -82093,7 +82153,7 @@ ahC aia aiC ajc -agy +ajM akC alr ama @@ -82350,7 +82410,7 @@ ahD aib aiD ajc -agy +ajM akD als amb @@ -82441,9 +82501,9 @@ aht aaa aaa abI -aaa -bSZ -ahi +dhS +cqS +rzF bNs bOw bOw @@ -82607,7 +82667,7 @@ ahB aic aiE agy -agy +ajM akE alt amc @@ -82699,7 +82759,7 @@ abI abI abI aaa -aht +bSZ ahi bNs bNs @@ -83455,7 +83515,7 @@ bHP bJb bJb bJb -bJb +fgS bJb bJb bPp @@ -84519,8 +84579,8 @@ aaa aaa aaa aaa -kSb -kSb +fon +fon aht aht nKo @@ -88103,7 +88163,7 @@ bDi bDi bDi bIZ -mZE +aaa aaa aaa aaa @@ -88360,8 +88420,8 @@ wNq bva gMO bBX -mZE -mZE +aaa +aaa aaa aaa aaa @@ -88618,7 +88678,7 @@ bBX fdS bBX bBX -mZE +aaa aaa aaa aaa @@ -90419,7 +90479,7 @@ gnq bXk ceU eVy -cfP +bXk bXk bXk bXk @@ -90933,8 +90993,8 @@ cdM bXq xmE ymb -cfQ bXk +ore qWG bXk paU @@ -94681,7 +94741,7 @@ ags adX adX adX -aaa +ahr aaa aaa aaa @@ -94937,8 +94997,8 @@ cnC adX adX adX -ahh -aaa +shH +alb aaa aaa aaa @@ -94953,9 +95013,9 @@ aaa aaa aaa aaa -aaa ahi atY +bcN auU atY lQQ @@ -95194,8 +95254,8 @@ bIK agt agD agR -ahi -aaa +ahh +atZ aaa aaa aaa @@ -95210,9 +95270,9 @@ aaa aaa aaa aaa -aaa ahi -atZ +baH +auV auV awc axg @@ -95451,8 +95511,8 @@ agg adX adX adX -ahh -aaa +shH +alb aaa aaa aaa @@ -95467,11 +95527,11 @@ aaa aaa aaa aaa -aaa ahi atY atY atY +atY axh axh axh @@ -95709,8 +95769,8 @@ ags adX adX adX -ahr -aht +shH +aFj aht aht aht @@ -98797,7 +98857,7 @@ iqc ngp cBr cBs -alb +tap gna klV xbJ @@ -99567,7 +99627,7 @@ aju ajt alQ mnG -alb +tap tap aiS anY @@ -99824,8 +99884,8 @@ akh alc alR amF -alb -alb +pzF +tap anm ajv ajv @@ -101723,7 +101783,7 @@ caN bZT bYw cdl -bYw +oGw bYw aaa mau @@ -101978,9 +102038,9 @@ bYw bZU caO cbF -ccs -cdm -cdm +bYw +gmZ +bYw bYw aht fon @@ -102232,13 +102292,13 @@ bVo bJP aht bYw -bYw +igB caP +fRr +qVk +cdm +cdm bYw -bYw -aaa -aaa -aaa aaa aaa aaa @@ -102488,11 +102548,11 @@ bWg bVo bJP aaa -aaa +bYw bYw caQ bYw -aaa +bYw aaa aaa aaa @@ -102745,10 +102805,10 @@ bJP bJP bJP abI -abI -bZV +aaa +bYw caR -bZV +bYw aaa aaa aaa @@ -103002,10 +103062,10 @@ aaa aaa abI aaa -aaa -aaa -aaa -aaa +abI +nbu +hbl +nbu aaa aaa aaa @@ -106805,7 +106865,7 @@ aEl aEj aEj aht -aht +ccs aEj aEl aEl @@ -107062,10 +107122,10 @@ aTu aUB aEl aaa -aaa -aEl +aEj aZv aUC +aUC bcH aUC aZw @@ -107320,8 +107380,8 @@ aGO aEj aEj aEj -aEj aTx +aFi aGO bcI aFi @@ -107557,10 +107617,10 @@ aaa aaa aaa aaa +aEl +aFi aEj -aFj -aEj -aEj +aaa aEj aEl aEj @@ -107577,12 +107637,12 @@ aUC aVE aUC aUC -aUC aZw -aFi -bcI -aFi -aFi +aEj +aEj +hSM +aEj +aEj kIo bfN aEj @@ -107814,9 +107874,9 @@ aaa aaa aaa aaa -ahi -ahi -ahi +aEj +bZV +aEj aaa aaa aaa @@ -107836,9 +107896,9 @@ aEj aEj aYC baG -baG +cfQ bcJ -baG +mvm baG aEj aEj @@ -108071,9 +108131,9 @@ aaa aaa aaa aaa -aaa -aaa -aaa +ahi +ahi +ahi aaa aaa aaa @@ -108607,9 +108667,9 @@ aFi aFi aYD baG -baH +rWE uXH -bcN +rWE baG eZA tDn @@ -108865,7 +108925,7 @@ aXC aYE baG rWE -bbO +oCX rWE baG vzT @@ -109885,7 +109945,7 @@ aaa aaa aaa aaa -mZE +aaa aaa aaa aaa @@ -112487,7 +112547,7 @@ qcH bnd nNN bwm -hSM +lWy bwm bwm aaa @@ -112743,10 +112803,10 @@ riW jtf bnd aht -ahi -ahi -ahi -aht +bwm +vHf +bwm +aaa aht aby aht @@ -113000,9 +113060,9 @@ cOp lGS bnd aaa -aaa -aaa -aaa +ahi +ahi +ahi aht aaa aed diff --git a/_maps/map_files/Snaxi/Snaxi.dmm b/_maps/map_files/Snaxi/Snaxi.dmm index 43e7915ca4..45e6e4dee0 100644 --- a/_maps/map_files/Snaxi/Snaxi.dmm +++ b/_maps/map_files/Snaxi/Snaxi.dmm @@ -210,7 +210,8 @@ "aap" = ( /obj/machinery/quantumpad{ map_pad_id = "5"; - map_pad_link_id = "6" + map_pad_link_id = "6"; + name = "South Sector Pad" }, /obj/structure/sign/directions/evac{ pixel_y = 40 @@ -221,6 +222,13 @@ /obj/structure/sign/directions/command{ pixel_y = 24 }, +/obj/structure/sign/directions/science{ + dir = 8; + icon_state = "pad_s"; + layer = 4.1; + name = "south sector"; + pixel_y = 13 + }, /turf/open/floor/plasteel, /area/hallway/primary/aft) "aaq" = ( @@ -519,7 +527,8 @@ /obj/machinery/atmospherics/components/unary/vent_pump/on, /obj/machinery/quantumpad{ map_pad_id = "1"; - map_pad_link_id = "2" + map_pad_link_id = "2"; + name = "Northwest Sector Pad" }, /obj/structure/sign/directions/medical{ dir = 8; @@ -531,6 +540,13 @@ icon_state = "direction_sci"; pixel_y = 28 }, +/obj/structure/sign/directions/science{ + dir = 8; + icon_state = "pad_nw"; + layer = 4.1; + name = "northwest sector"; + pixel_y = 13 + }, /turf/open/floor/plasteel, /area/quartermaster/miningdock) "aaO" = ( @@ -730,13 +746,12 @@ /obj/machinery/light{ dir = 4 }, -/obj/structure/reagent_dispensers/watertank, -/obj/item/radio/intercom{ - pixel_y = -26 - }, /obj/structure/sign/departments/xenobio{ pixel_x = 32 }, +/obj/structure/closet/bombcloset{ + anchored = 1 + }, /turf/open/floor/plasteel/white, /area/science/misc_lab) "abi" = ( @@ -1242,11 +1257,8 @@ /turf/open/floor/plasteel/dark, /area/security/main) "acb" = ( -/obj/structure/sign/poster/official/science{ - pixel_y = -32 - }, -/turf/open/floor/plasteel/white, -/area/science/mixing) +/turf/open/floor/plasteel/dark, +/area/hydroponics) "acc" = ( /obj/structure/sign/poster/contraband/lusty_xenomorph{ pixel_x = -32; @@ -1640,8 +1652,8 @@ "aiS" = ( /obj/structure/closet/secure_closet/CMO, /obj/machinery/keycard_auth{ - pixel_y = 4; - pixel_x = -24 + pixel_x = -24; + pixel_y = 4 }, /obj/effect/turf_decal/tile/blue{ dir = 4 @@ -3147,8 +3159,8 @@ dir = 4 }, /obj/machinery/conveyor{ - id = "packageSort2"; - dir = 1 + dir = 1; + id = "packageSort2" }, /obj/machinery/disposal/deliveryChute, /obj/structure/window/reinforced{ @@ -4061,9 +4073,9 @@ /area/crew_quarters/dorms) "aNS" = ( /obj/machinery/turnstile{ + dir = 4; name = "Genpop Entrance Turnstile"; - req_access_txt = "69"; - dir = 4 + req_access_txt = "69" }, /obj/machinery/door/poddoor/preopen{ id = "permacell1"; @@ -4554,9 +4566,9 @@ /area/maintenance/solars/port/fore) "bcc" = ( /obj/machinery/door/window/brigdoor/security/cell{ + dir = 1; id = "Cell 2"; - name = "Cell 2"; - dir = 1 + name = "Cell 2" }, /obj/effect/turf_decal/vg_decals/numbers/two, /obj/machinery/door/poddoor/preopen{ @@ -5031,9 +5043,9 @@ "brE" = ( /obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden, /obj/machinery/door/window/southleft{ + dir = 1; name = "Court Cell"; - req_access_txt = "2"; - dir = 1 + req_access_txt = "2" }, /obj/structure/window/reinforced{ dir = 8 @@ -5169,7 +5181,7 @@ /turf/open/floor/plasteel/dark, /area/hallway/secondary/exit/departure_lounge) "bum" = ( -/turf/open/openspace/icemoon, +/turf/open/transparent/openspace/icemoon, /area/icemoon/surface/outdoors) "buF" = ( /obj/machinery/light, @@ -5209,7 +5221,15 @@ "buO" = ( /obj/machinery/quantumpad{ map_pad_id = "3"; - map_pad_link_id = "4" + map_pad_link_id = "4"; + name = "Northeast Sector Pad" + }, +/obj/structure/sign/directions/science{ + dir = 8; + icon_state = "pad_ne"; + layer = 4.1; + name = "northeast sector"; + pixel_y = 13 }, /turf/open/floor/plasteel, /area/hallway/primary/port) @@ -5284,9 +5304,9 @@ dir = 1 }, /obj/machinery/turnstile{ + dir = 4; name = "Genpop Entrance Turnstile"; - req_access_txt = "69"; - dir = 4 + req_access_txt = "69" }, /turf/open/floor/plasteel/dark, /area/security/brig) @@ -6957,9 +6977,9 @@ name = "west facing firelock" }, /obj/machinery/door/window/southleft{ + dir = 8; name = "Test Chamber"; - req_access_txt = "55"; - dir = 8 + req_access_txt = "55" }, /obj/machinery/door/poddoor/preopen{ id = "xenobio2"; @@ -6975,9 +6995,9 @@ dir = 10 }, /obj/machinery/door/window/southleft{ + dir = 4; name = "Test Chamber"; - req_access_txt = "55"; - dir = 4 + req_access_txt = "55" }, /turf/open/floor/plasteel, /area/science/xenobiology) @@ -7072,9 +7092,9 @@ dir = 4 }, /obj/machinery/door/window/brigdoor{ + dir = 1; name = "Reception Desk"; - req_access_txt = "63"; - dir = 1 + req_access_txt = "63" }, /obj/machinery/door/window/brigdoor{ dir = 8; @@ -7186,9 +7206,6 @@ dir = 5 }, /obj/machinery/atmospherics/components/unary/portables_connector/visible, -/obj/machinery/firealarm{ - pixel_y = 24 - }, /turf/open/floor/plasteel, /area/science/mixing) "bKO" = ( @@ -7475,8 +7492,8 @@ }, /obj/structure/table/wood, /obj/machinery/recharger{ - pixel_y = 4; - pixel_x = -7 + pixel_x = -7; + pixel_y = 4 }, /obj/item/book/manual/wiki/security_space_law{ pixel_x = 6; @@ -8958,7 +8975,15 @@ "cpC" = ( /obj/machinery/quantumpad{ map_pad_id = "2"; - map_pad_link_id = "1" + map_pad_link_id = "1"; + name = "South Sector Pad" + }, +/obj/structure/sign/directions/science{ + dir = 8; + icon_state = "pad_s"; + layer = 4.1; + name = "south sector"; + pixel_y = 13 }, /turf/open/floor/plasteel, /area/hallway/primary/port) @@ -9296,8 +9321,8 @@ }, /obj/machinery/camera{ c_tag = "Medbay West"; - network = list("ss13","medbay"); - dir = 4 + dir = 4; + network = list("ss13","medbay") }, /turf/open/floor/plasteel/white, /area/medical/medbay/central) @@ -9414,9 +9439,9 @@ req_access_txt = "10" }, /obj/machinery/door/window/northright{ + dir = 4; name = "Engineering Delivery"; - req_access_txt = "10"; - dir = 4 + req_access_txt = "10" }, /obj/effect/turf_decal/delivery, /turf/open/floor/plasteel/dark, @@ -9818,7 +9843,15 @@ "cQa" = ( /obj/machinery/quantumpad{ map_pad_id = "6"; - map_pad_link_id = "5" + map_pad_link_id = "5"; + name = "Northeast Sector Pad" + }, +/obj/structure/sign/directions/science{ + dir = 8; + icon_state = "pad_ne"; + layer = 4.1; + name = "northeast sector"; + pixel_y = 13 }, /turf/open/floor/plasteel, /area/quartermaster/miningdock) @@ -10387,8 +10420,8 @@ dir = 4 }, /obj/machinery/shower{ - pixel_y = 20; - pixel_x = 11 + pixel_x = 11; + pixel_y = 20 }, /obj/structure/disposalpipe/segment{ dir = 4 @@ -10760,8 +10793,8 @@ /obj/structure/table/wood, /obj/item/book/manual/wiki/security_space_law, /obj/item/flashlight/lamp/green{ - pixel_y = 1; - pixel_x = -7 + pixel_x = -7; + pixel_y = 1 }, /turf/open/floor/wood, /area/security/courtroom) @@ -11054,6 +11087,13 @@ "dAV" = ( /turf/closed/wall/r_wall, /area/ai_monitored/turret_protected/ai_upload_foyer) +"dBA" = ( +/obj/machinery/portable_atmospherics/pump, +/obj/item/radio/intercom{ + pixel_y = -26 + }, +/turf/open/floor/plasteel/white, +/area/science/mixing) "dBL" = ( /obj/structure/closet/secure_closet/medical1, /obj/structure/extinguisher_cabinet{ @@ -11207,9 +11247,9 @@ dir = 4 }, /obj/machinery/turnstile{ + dir = 8; name = "Genpop Exit Turnstile"; - req_access_txt = "70"; - dir = 8 + req_access_txt = "70" }, /turf/open/floor/plasteel/dark, /area/security/brig) @@ -12173,8 +12213,8 @@ /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, /obj/machinery/button/flasher{ id = "PCell 1"; - pixel_y = 9; - pixel_x = -37 + pixel_x = -37; + pixel_y = 9 }, /turf/open/floor/plasteel/dark, /area/security/brig) @@ -12356,9 +12396,9 @@ dir = 4 }, /obj/machinery/turnstile{ + dir = 8; name = "Genpop Exit Turnstile"; - req_access_txt = "70"; - dir = 8 + req_access_txt = "70" }, /obj/effect/turf_decal/tile/red{ dir = 1 @@ -12388,7 +12428,7 @@ /turf/open/floor/plasteel, /area/hallway/primary/port) "esY" = ( -/turf/open/openspace/icemoon, +/turf/open/transparent/openspace/icemoon, /area/engine/atmos) "ets" = ( /obj/machinery/atmospherics/components/unary/vent_pump/on{ @@ -13510,9 +13550,9 @@ icon_state = "1-4" }, /obj/machinery/door/window/brigdoor/security/cell{ + dir = 8; id = "Cell 1"; - name = "Cell 1"; - dir = 8 + name = "Cell 1" }, /obj/effect/turf_decal/vg_decals/numbers/one, /obj/machinery/door/poddoor/preopen{ @@ -13766,7 +13806,6 @@ dir = 4; pixel_x = -24 }, -/obj/structure/closet/crate/bin, /turf/open/floor/plasteel/white, /area/science/misc_lab) "fjS" = ( @@ -14345,8 +14384,8 @@ name = "Door Bolt Control"; normaldoorcontrol = 1; pixel_x = 24; - specialfunctions = 4; - pixel_y = -5 + pixel_y = -5; + specialfunctions = 4 }, /obj/machinery/light/small{ dir = 8 @@ -14836,8 +14875,8 @@ /obj/structure/table/wood, /obj/item/book/manual/wiki/security_space_law, /obj/item/flashlight/lamp/green{ - pixel_y = 1; - pixel_x = -7 + pixel_x = -7; + pixel_y = 1 }, /turf/open/floor/wood, /area/security/courtroom) @@ -15167,7 +15206,15 @@ "gct" = ( /obj/machinery/quantumpad{ map_pad_id = "4"; - map_pad_link_id = "3" + map_pad_link_id = "3"; + name = "Northwest Sector Pad" + }, +/obj/structure/sign/directions/science{ + dir = 8; + icon_state = "pad_nw"; + layer = 4.1; + name = "northwest sector"; + pixel_y = 13 }, /turf/open/floor/plasteel, /area/hallway/primary/aft) @@ -15538,9 +15585,9 @@ /obj/machinery/button/door{ id = "Secure Gate"; name = "Cell Shutters"; + pixel_x = 3; pixel_y = 24; - req_access_txt = "2"; - pixel_x = 3 + req_access_txt = "2" }, /turf/open/floor/plasteel/dark, /area/security/brig) @@ -15934,8 +15981,6 @@ /obj/machinery/atmospherics/components/unary/vent_pump/on{ dir = 4 }, -/obj/machinery/portable_atmospherics/scrubber, -/obj/item/storage/firstaid/toxin, /obj/structure/disposalpipe/segment{ dir = 4 }, @@ -16444,6 +16489,9 @@ /area/storage/atmos) "gPE" = ( /obj/machinery/portable_atmospherics/pump, +/obj/machinery/firealarm{ + pixel_y = 24 + }, /turf/open/floor/plasteel/white, /area/science/mixing) "gPF" = ( @@ -16835,9 +16883,9 @@ /obj/machinery/button/door{ id = "kitchen"; name = "Kitchen Shutters Control"; - req_access_txt = "28"; pixel_x = 24; - pixel_y = -4 + pixel_y = -4; + req_access_txt = "28" }, /turf/open/floor/plasteel/cafeteria, /area/crew_quarters/kitchen) @@ -17096,8 +17144,8 @@ dir = 8 }, /obj/machinery/computer/monitor{ - name = "bridge power monitoring console"; - dir = 1 + dir = 1; + name = "bridge power monitoring console" }, /obj/structure/cable{ icon_state = "0-2" @@ -17235,8 +17283,8 @@ /obj/item/folder/blue, /obj/item/stamp/law, /obj/item/flashlight/lamp/green{ - pixel_y = 1; - pixel_x = -7 + pixel_x = -7; + pixel_y = 1 }, /turf/open/floor/plasteel/cult, /area/lawoffice) @@ -18346,9 +18394,8 @@ /turf/open/floor/carpet, /area/security/detectives_office) "hTL" = ( -/obj/effect/spawner/structure/window/plasma/reinforced, /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, -/turf/open/floor/plating, +/turf/open/floor/plasteel/white, /area/science/mixing) "hTO" = ( /obj/structure/cable{ @@ -18426,9 +18473,9 @@ /area/engine/engineering) "hVH" = ( /obj/machinery/atmospherics/components/unary/vent_pump/siphon/on{ + dir = 1; external_pressure_bound = 120; - name = "killroom vent"; - dir = 1 + name = "killroom vent" }, /turf/open/floor/circuit/telecomms, /area/science/xenobiology) @@ -18466,8 +18513,8 @@ }, /obj/machinery/camera{ c_tag = "Surgery Observation"; - network = list("ss13","medbay"); - dir = 8 + dir = 8; + network = list("ss13","medbay") }, /turf/open/floor/plasteel/dark, /area/medical/surgery) @@ -18616,8 +18663,8 @@ /area/security/main) "iam" = ( /obj/machinery/computer/slot_machine{ - pixel_y = 2; - pixel_x = -7 + pixel_x = -7; + pixel_y = 2 }, /turf/open/floor/wood, /area/maintenance/bar) @@ -18912,6 +18959,10 @@ }, /turf/open/floor/plasteel, /area/storage/primary) +"ihL" = ( +/mob/living/simple_animal/opossum, +/turf/open/floor/plating, +/area/maintenance/aft/secondary) "ihX" = ( /obj/structure/cable{ icon_state = "0-2" @@ -19807,8 +19858,8 @@ /obj/machinery/button/door{ id = "hos"; name = "HoS Office Shutters"; - pixel_y = -26; - pixel_x = -6 + pixel_x = -6; + pixel_y = -26 }, /turf/open/floor/carpet, /area/crew_quarters/heads/hos) @@ -21383,8 +21434,8 @@ pixel_y = -22 }, /obj/machinery/button/door/incinerator_vent_toxmix{ - pixel_y = -22; - pixel_x = 9 + pixel_x = 9; + pixel_y = -22 }, /obj/machinery/meter, /turf/open/floor/plasteel/white, @@ -22642,6 +22693,8 @@ c_tag = "Testing Lab East"; network = list("ss13","rd") }, +/obj/machinery/portable_atmospherics/scrubber, +/obj/item/storage/firstaid/toxin, /turf/open/floor/plasteel/white, /area/science/misc_lab) "kxI" = ( @@ -24053,6 +24106,10 @@ "luo" = ( /turf/open/floor/plasteel/white, /area/science/misc_lab) +"lwl" = ( +/mob/living/simple_animal/opossum/poppy, +/turf/open/floor/plating, +/area/engine/engineering) "lwH" = ( /obj/structure/cable{ icon_state = "1-4" @@ -24577,8 +24634,8 @@ "lMF" = ( /obj/machinery/camera{ c_tag = "Virology Module"; - network = list("ss13","medbay"); - dir = 1 + dir = 1; + network = list("ss13","medbay") }, /obj/structure/disposalpipe/segment{ dir = 4 @@ -26012,8 +26069,8 @@ /obj/machinery/button/door{ id = "engsm"; name = "Radiation Shutters Control"; - req_access_txt = "10"; - pixel_y = 25 + pixel_y = 25; + req_access_txt = "10" }, /obj/machinery/atmospherics/pipe/manifold/cyan/visible, /obj/effect/turf_decal/stripes/line{ @@ -26159,9 +26216,9 @@ dir = 4 }, /obj/machinery/turnstile{ + dir = 8; name = "Genpop Exit Turnstile"; - req_access_txt = "70"; - dir = 8 + req_access_txt = "70" }, /obj/structure/cable{ icon_state = "4-8" @@ -27616,8 +27673,8 @@ /area/bridge) "nFM" = ( /obj/machinery/atmospherics/components/binary/pump{ - name = "Port Mix to Engine"; - dir = 1 + dir = 1; + name = "Port Mix to Engine" }, /turf/open/floor/plasteel, /area/engine/atmos) @@ -27738,9 +27795,9 @@ "nJI" = ( /obj/structure/table/reinforced, /obj/machinery/door/window/southleft{ + dir = 4; name = "Reception Desk"; - req_access_txt = "63"; - dir = 4 + req_access_txt = "63" }, /obj/structure/cable{ icon_state = "1-2" @@ -27989,8 +28046,8 @@ /area/engine/engineering) "nSX" = ( /obj/machinery/atmospherics/components/binary/pump/on{ - name = "Gas to Cooling Loop"; - dir = 1 + dir = 1; + name = "Gas to Cooling Loop" }, /turf/open/floor/plating, /area/engine/atmospherics_engine) @@ -28291,6 +28348,12 @@ /obj/effect/landmark/event_spawn, /turf/open/floor/plasteel, /area/maintenance/starboard) +"odf" = ( +/obj/structure/closet/bombcloset{ + anchored = 1 + }, +/turf/open/floor/plasteel/white, +/area/science/mixing) "odg" = ( /obj/machinery/atmospherics/pipe/heat_exchanging/simple{ dir = 4 @@ -30136,8 +30199,8 @@ /area/quartermaster/storage) "pfb" = ( /obj/machinery/atmospherics/components/binary/pump/on{ - name = "Gas to Cooling Loop"; - dir = 1 + dir = 1; + name = "Gas to Cooling Loop" }, /obj/effect/turf_decal/stripes/line{ dir = 9 @@ -30845,10 +30908,10 @@ /area/ai_monitored/security/armory) "pvY" = ( /obj/machinery/atmospherics/components/unary/vent_pump/on{ + dir = 1; external_pressure_bound = 140; name = "killroom vent"; - pressure_checks = 0; - dir = 1 + pressure_checks = 0 }, /turf/open/floor/circuit/telecomms, /area/science/xenobiology) @@ -31385,9 +31448,9 @@ dir = 4 }, /obj/machinery/turnstile{ + dir = 8; name = "Genpop Exit Turnstile"; - req_access_txt = "70"; - dir = 8 + req_access_txt = "70" }, /obj/machinery/door/firedoor/border_only{ dir = 8; @@ -32565,8 +32628,8 @@ }, /obj/machinery/button/ignition{ id = "testigniter"; - pixel_y = -30; - pixel_x = -1 + pixel_x = -1; + pixel_y = -30 }, /obj/structure/disposalpipe/trunk{ dir = 1 @@ -32750,9 +32813,9 @@ /area/maintenance/bar) "qEz" = ( /obj/machinery/door/window/brigdoor/security/cell{ + dir = 1; id = "Cell 3"; - name = "Cell 3"; - dir = 1 + name = "Cell 3" }, /obj/effect/turf_decal/vg_decals/numbers/three, /obj/machinery/door/poddoor/preopen{ @@ -33684,8 +33747,8 @@ "rgQ" = ( /obj/machinery/camera{ c_tag = "Xenobiology Test Chamber"; - network = list("xeno","rd"); - dir = 4 + dir = 4; + network = list("xeno","rd") }, /turf/open/floor/engine, /area/science/xenobiology) @@ -34106,7 +34169,6 @@ /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ dir = 4 }, -/obj/structure/reagent_dispensers/fueltank, /turf/open/floor/plasteel/white, /area/science/misc_lab) "rqE" = ( @@ -34451,8 +34513,8 @@ }, /obj/machinery/camera{ c_tag = "AI Chamber - Core"; - network = list("aicore"); - dir = 4 + dir = 4; + network = list("aicore") }, /turf/open/floor/circuit/off, /area/ai_monitored/turret_protected/ai) @@ -34542,9 +34604,9 @@ dir = 4 }, /obj/machinery/turnstile{ + dir = 8; name = "Genpop Exit Turnstile"; - req_access_txt = "70"; - dir = 8 + req_access_txt = "70" }, /obj/machinery/door/firedoor/border_only{ dir = 4; @@ -34779,6 +34841,10 @@ }, /turf/open/floor/plasteel/white, /area/medical/medbay/central) +"rQB" = ( +/obj/structure/reagent_dispensers/fueltank, +/turf/open/floor/plasteel/white, +/area/science/mixing) "rQH" = ( /obj/effect/spawner/structure/window/reinforced, /obj/machinery/atmospherics/pipe/simple/supply/hidden, @@ -34883,7 +34949,7 @@ /turf/open/floor/plasteel, /area/engine/engineering) "rUd" = ( -/turf/open/openspace/icemoon, +/turf/open/transparent/openspace/icemoon, /area/science/mixing) "rUl" = ( /obj/structure/cable{ @@ -36330,7 +36396,7 @@ /turf/open/floor/plasteel/white, /area/medical/medbay/central) "sTq" = ( -/turf/open/openspace/icemoon, +/turf/open/transparent/openspace/icemoon, /area/engine/atmospherics_engine) "sTz" = ( /obj/effect/turf_decal/bot_white, @@ -37650,7 +37716,6 @@ /area/icemoon/surface/outdoors) "tDO" = ( /obj/machinery/atmospherics/components/unary/portables_connector/visible, -/obj/machinery/portable_atmospherics/canister/toxins, /obj/machinery/computer/security/telescreen{ name = "Test Chamber Monitor"; network = list("test"); @@ -37770,8 +37835,8 @@ }, /obj/machinery/camera{ c_tag = "Genetics Research"; - network = list("ss13","medbay"); - dir = 8 + dir = 8; + network = list("ss13","medbay") }, /turf/open/floor/plasteel/white, /area/medical/genetics) @@ -37932,9 +37997,9 @@ /obj/machinery/button/door{ id = "Secure Brig Control"; name = "Brig Control Shutters"; + pixel_x = -6; pixel_y = -3; - req_access_txt = "2"; - pixel_x = -6 + req_access_txt = "2" }, /turf/open/floor/plasteel/dark, /area/security/warden) @@ -39014,8 +39079,8 @@ "uuY" = ( /obj/machinery/camera{ c_tag = "Toxins Lab West"; - network = list("ss13","rd"); - dir = 4 + dir = 4; + network = list("ss13","rd") }, /obj/structure/table/reinforced, /obj/item/assembly/prox_sensor{ @@ -39406,9 +39471,9 @@ pixel_y = 23 }, /obj/machinery/door/window/southright{ + dir = 8; name = "Bar Door"; - req_one_access_txt = "25;28"; - dir = 8 + req_one_access_txt = "25;28" }, /obj/machinery/door/firedoor/border_only{ dir = 8; @@ -39560,8 +39625,8 @@ dir = 4 }, /obj/machinery/computer/security/telescreen/prison{ - pixel_x = 29; - dir = 8 + dir = 8; + pixel_x = 29 }, /turf/open/floor/plasteel/cult, /area/lawoffice) @@ -39968,8 +40033,8 @@ dir = 8 }, /obj/structure/chair{ - name = "Judge"; - dir = 4 + dir = 4; + name = "Judge" }, /turf/open/floor/wood, /area/security/courtroom) @@ -40683,8 +40748,8 @@ }, /obj/machinery/button/ignition{ id = "Incinerator"; - pixel_y = 35; - pixel_x = -1 + pixel_x = -1; + pixel_y = 35 }, /turf/open/floor/plasteel, /area/engine/atmospherics_engine) @@ -42591,8 +42656,8 @@ "wtt" = ( /obj/structure/table/wood, /obj/item/flashlight/lamp/green{ - pixel_y = 13; - pixel_x = -7 + pixel_x = -7; + pixel_y = 13 }, /obj/item/camera/detective, /obj/item/hand_labeler{ @@ -42600,8 +42665,8 @@ }, /obj/item/storage/briefcase, /obj/item/storage/secure/safe{ - pixel_y = 36; - pixel_x = 6 + pixel_x = 6; + pixel_y = 36 }, /turf/open/floor/carpet, /area/security/detectives_office) @@ -44647,8 +44712,8 @@ areastring = "/area/engine/engineering"; dir = 8; name = "Engineering APC"; - pixel_y = -1; - pixel_x = -27 + pixel_x = -27; + pixel_y = -1 }, /obj/machinery/firealarm{ dir = 1; @@ -45207,14 +45272,6 @@ /area/medical/medbay/central) "ykk" = ( /obj/machinery/atmospherics/pipe/simple/supply/hidden, -/obj/machinery/door/firedoor/border_only{ - dir = 1; - name = "north facing firelock" - }, -/obj/machinery/door/airlock/research{ - name = "Toxins Lab"; - req_access_txt = "7" - }, /obj/structure/disposalpipe/segment, /turf/open/floor/plasteel/white, /area/science/mixing) @@ -81146,7 +81203,7 @@ bDW bEl bDE bFK -bJC +rQB prL fiN hmX @@ -81403,7 +81460,7 @@ bDW bIn bQP wOK -bJC +fjU gzZ gSu ipY @@ -82174,7 +82231,7 @@ bDW mOv jOB lYy -bJC +fjU ihE fJO eex @@ -82431,7 +82488,7 @@ bDW gpp wbT nHi -bJC +fjU rDA fjU dvO @@ -82688,7 +82745,7 @@ bEa kxj aaw rqx -qJV +fjU bKL fJO jKT @@ -82945,10 +83002,10 @@ bEa pHl aaw abh -qJV +odf +fjU fjU fjU -acb qJV fuG qJV @@ -83205,7 +83262,7 @@ cBt tRe gPE syy -gPE +dBA qJV goM gxF @@ -83466,7 +83523,7 @@ tRe tRe tRe bWf -bVa +ihL kXG sqx owj @@ -86968,7 +87025,7 @@ now mKv sAh sAh -sAh +acb aar uEz uEz @@ -87225,7 +87282,7 @@ qss mKv sAh sAh -sAh +acb urI qkO uEz @@ -87739,7 +87796,7 @@ qss sYv sAh sAh -sAh +acb urI uoV uEz @@ -87996,7 +88053,7 @@ qss sYv sAh sAh -sAh +acb urI uoV uEz @@ -98024,7 +98081,7 @@ xUL xUL dKF ijZ -ijZ +lwl bnU oJa cNE @@ -100071,11 +100128,11 @@ xUL xUL xUL xUL -xUL -xUL -xUL rGc jls +rGc +cly +jls odg ucC gUL @@ -100327,12 +100384,12 @@ bum bum bum bum -bum -bum -bum rGc tdX tdX +tdX +cly +tdX jPj ucC gUL @@ -100584,12 +100641,12 @@ bum bum bum bum -bum -bum -bum dQW tdX tdX +tdX +cly +tdX jls ucC gUL @@ -100841,12 +100898,12 @@ bum bum bum bum -bum -bum -bum rGc tdX tdX +tdX +cly +tdX jPj ucC cfs @@ -101098,12 +101155,12 @@ bum bum bum bum -bum -bum -bum dQW tdX tdX +tdX +cly +tdX jls ucC cfs @@ -101355,11 +101412,11 @@ bum bum bum bum -bum -bum -bum -xUL +rGc +jPj dQW +jPj +rGc flw flw lFN @@ -101612,11 +101669,11 @@ bum bum bum bum -bum -bum -bum -xUL -xUL +dQW +cly +cly +cly +jPj dQW jPj bnU @@ -101869,9 +101926,9 @@ bum bum bum bum -bum -bum -bum +xUL +xUL +xUL bDA bYY bYY @@ -102126,9 +102183,9 @@ bum bum bum bum -bum -bum -bum +xUL +xUL +xUL gjW xUL xUL @@ -102383,9 +102440,9 @@ bum bum bum bum -bum -bum -bum +xUL +xUL +xUL xUL xUL bum @@ -102640,9 +102697,9 @@ bum bum bum bum -bum -bum -bum +xUL +xUL +xUL xUL xUL sTq diff --git a/_maps/map_files/debug/multiz.dmm b/_maps/map_files/debug/multiz.dmm index 4614829679..5a18682129 100644 --- a/_maps/map_files/debug/multiz.dmm +++ b/_maps/map_files/debug/multiz.dmm @@ -102,7 +102,7 @@ /turf/open/floor/plasteel, /area/engine/gravity_generator) "au" = ( -/turf/open/openspace, +/turf/open/transparent/openspace, /area/space) "av" = ( /obj/structure/stairs{ @@ -1407,7 +1407,7 @@ }, /area/hallway/secondary/service) "eC" = ( -/turf/open/openspace, +/turf/open/transparent/openspace, /area/maintenance/department/bridge) "eD" = ( /obj/effect/turf_decal/stripes/asteroid/line{ @@ -1542,7 +1542,7 @@ /turf/open/floor/plating, /area/space) "iu" = ( -/turf/open/openspace, +/turf/open/transparent/openspace, /area/hallway/secondary/service) "iK" = ( /turf/open/floor/plasteel{ @@ -1593,7 +1593,7 @@ }, /area/hallway/secondary/service) "nx" = ( -/turf/open/openspace, +/turf/open/transparent/openspace, /area/space/nearstation) "nz" = ( /obj/machinery/light{ @@ -1633,7 +1633,7 @@ /turf/open/floor/plating, /area/maintenance/department/bridge) "qo" = ( -/turf/open/openspace, +/turf/open/transparent/openspace, /area/engine/storage) "qR" = ( /obj/effect/turf_decal/stripes/white/line{ @@ -1646,7 +1646,7 @@ /obj/machinery/light{ dir = 8 }, -/turf/open/openspace, +/turf/open/transparent/openspace, /area/engine/storage) "sh" = ( /turf/open/floor/plasteel{ @@ -1746,7 +1746,7 @@ /area/construction) "Bk" = ( /obj/structure/grille, -/turf/open/openspace, +/turf/open/transparent/openspace, /area/space/nearstation) "Bm" = ( /obj/machinery/light{ @@ -1876,7 +1876,7 @@ "Ob" = ( /obj/structure/lattice, /obj/structure/grille, -/turf/open/openspace, +/turf/open/transparent/openspace, /area/space/nearstation) "Og" = ( /obj/machinery/airalarm/directional/north, diff --git a/_maps/map_files/generic/CentCom.dmm b/_maps/map_files/generic/CentCom.dmm index 5a14eb9041..020017c3fe 100644 --- a/_maps/map_files/generic/CentCom.dmm +++ b/_maps/map_files/generic/CentCom.dmm @@ -13490,6 +13490,9 @@ /obj/structure/table/wood, /obj/item/instrument/piano_synth, /obj/item/instrument/guitar, +/obj/structure/sign/painting{ + pixel_x = -32 + }, /turf/open/indestructible/hotelwood, /area/centcom/holding) "Fg" = ( @@ -13794,6 +13797,9 @@ /turf/open/indestructible/hotelwood, /area/centcom/holding) "FX" = ( +/obj/structure/sign/painting{ + pixel_x = 32 + }, /turf/open/floor/plasteel/stairs, /area/centcom/holding) "FZ" = ( @@ -14421,6 +14427,9 @@ dir = 8 }, /obj/structure/musician/piano, +/obj/structure/sign/painting{ + pixel_x = -32 + }, /turf/open/indestructible/hotelwood, /area/centcom/holding) "Hk" = ( @@ -16225,6 +16234,12 @@ dir = 1 }, /obj/structure/table/wood, +/obj/item/storage/crayons, +/obj/item/storage/crayons, +/obj/item/storage/crayons, +/obj/structure/sign/painting{ + pixel_x = -32 + }, /turf/open/indestructible/hotelwood, /area/centcom/holding) "KU" = ( @@ -16304,6 +16319,14 @@ /obj/item/storage/box/bodybags, /turf/open/floor/plasteel/white, /area/centcom/holding) +"Ll" = ( +/obj/structure/window/reinforced{ + dir = 1 + }, +/obj/structure/easel, +/obj/item/canvas/twentythreeXtwentythree, +/turf/open/indestructible/hotelwood, +/area/centcom/holding) "Lm" = ( /obj/machinery/shower{ dir = 4 @@ -16808,6 +16831,22 @@ }, /turf/open/floor/plasteel, /area/centcom/supplypod/loading/two) +"NA" = ( +/obj/structure/window/reinforced{ + dir = 1 + }, +/obj/structure/table/wood, +/obj/item/canvas/twentythreeXtwentythree, +/obj/item/canvas/twentythreeXtwentythree, +/obj/item/canvas/twentythreeXtwentythree, +/obj/item/canvas/twentythreeXnineteen, +/obj/item/canvas/twentythreeXnineteen, +/obj/item/canvas/twentythreeXnineteen, +/obj/item/canvas/nineteenXnineteen, +/obj/item/canvas/nineteenXnineteen, +/obj/item/canvas/nineteenXnineteen, +/turf/open/indestructible/hotelwood, +/area/centcom/holding) "NE" = ( /obj/machinery/light{ dir = 4 @@ -16924,6 +16963,12 @@ }, /turf/open/floor/plasteel, /area/centcom/supplypod/loading/three) +"On" = ( +/obj/structure/sign/painting{ + pixel_x = 32 + }, +/turf/open/indestructible/hotelwood, +/area/centcom/holding) "Op" = ( /obj/structure/sink{ dir = 8; @@ -17249,6 +17294,10 @@ }, /turf/open/floor/mineral/titanium, /area/centcom/evac) +"Qc" = ( +/obj/effect/landmark/mafia_game_area, +/turf/open/space/basic, +/area/space) "Qe" = ( /turf/open/ai_visible, /area/ai_multicam_room) @@ -17906,6 +17955,15 @@ /obj/machinery/light, /turf/open/floor/plasteel/freezer, /area/centcom/holding) +"TD" = ( +/obj/machinery/light{ + dir = 4 + }, +/obj/structure/sign/painting{ + pixel_x = 32 + }, +/turf/open/indestructible/hotelwood, +/area/centcom/holding) "TF" = ( /obj/effect/turf_decal/tile/red{ dir = 8 @@ -45453,8 +45511,8 @@ Nd AE CV Sd -KT -Sd +Ll +CV Sd Sd Sd @@ -45710,7 +45768,7 @@ Nd QJ Sd Sd -KT +NA Sd Sd Sd @@ -46222,8 +46280,8 @@ Fh Fh Wl Sd -MR -Sd +TD +On FX Sd Sd @@ -58911,7 +58969,7 @@ aa aa aa aa -aa +Qc aa aa aa diff --git a/_maps/multiz_debug.json b/_maps/multiz_debug.json index 7e39981e23..e916a77d1d 100644 --- a/_maps/multiz_debug.json +++ b/_maps/multiz_debug.json @@ -2,5 +2,5 @@ "map_name": "MultiZ Debug", "map_path": "map_files/debug", "map_file": "multiz.dmm", - "traits": [{"Up": 1}, {"Up": 1, "Down": -1}, {"Down": -1}] + "traits": [{"Up" : 1, "Linkage" : "Cross"}, {"Up" : 1, "Down" : -1, "Baseturf" : "/turf/open/transparent/openspace", "Linkage" : "Cross"}, {"Down" : -1, "Baseturf" : "/turf/open/transparent/openspace", "Linkage" : "Cross"}] } diff --git a/_maps/shuttles/emergency_discoinferno.dmm b/_maps/shuttles/emergency_discoinferno.dmm index e142208e12..92b515f17e 100644 --- a/_maps/shuttles/emergency_discoinferno.dmm +++ b/_maps/shuttles/emergency_discoinferno.dmm @@ -94,7 +94,7 @@ /turf/open/floor/light/colour_cycle, /area/shuttle/escape) "r" = ( -/turf/open/floor/mineral/plasma, +/turf/open/floor/mineral/plasma/disco, /area/shuttle/escape) "s" = ( /turf/open/floor/mineral/silver, @@ -112,7 +112,7 @@ resistance_flags = 2 }, /obj/structure/fans/tiny, -/turf/open/floor/mineral/plasma, +/turf/open/floor/mineral/plasma/disco, /area/shuttle/escape) "v" = ( /obj/machinery/jukebox/disco/indestructible, diff --git a/_maps/shuttles/whiteship_box.dmm b/_maps/shuttles/whiteship_box.dmm index 0404cede34..3ac1d18ac4 100644 --- a/_maps/shuttles/whiteship_box.dmm +++ b/_maps/shuttles/whiteship_box.dmm @@ -2690,7 +2690,7 @@ /obj/structure/rack, /obj/item/storage/box/zipties, /obj/item/assembly/flash/handheld, -/obj/item/melee/classic_baton/telescopic, +/obj/item/melee/classic_baton, /obj/machinery/light/small/built{ dir = 8 }, diff --git a/_maps/snaxi.json b/_maps/snaxi.json index cb1917b6f6..3fc8eba15d 100644 --- a/_maps/snaxi.json +++ b/_maps/snaxi.json @@ -33,7 +33,7 @@ "Linkage":null, "Gravity":true, "Ice Ruins Underground":true, - "Baseturf":"/turf/open/openspace/icemoon" + "Baseturf":"/turf/open/transparent/openspace/icemoon" }, { "Down":-1, diff --git a/byond-extools.dll b/byond-extools.dll index 4910fad01b..bd6b34c48e 100644 Binary files a/byond-extools.dll and b/byond-extools.dll differ diff --git a/code/__DEFINES/_flags/_flags.dm b/code/__DEFINES/_flags/_flags.dm index 0734feaa42..ffa3f1c751 100644 --- a/code/__DEFINES/_flags/_flags.dm +++ b/code/__DEFINES/_flags/_flags.dm @@ -98,7 +98,7 @@ GLOBAL_LIST_INIT(bitflags, list(1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 204 #define ZAP_MOB_DAMAGE (1<<3) #define ZAP_MOB_STUN (1<<4) -#define ZAP_DEFAULT_FLAGS ALL +#define ZAP_DEFAULT_FLAGS ZAP_MOB_STUN | ZAP_MOB_DAMAGE | ZAP_OBJ_DAMAGE #define ZAP_FUSION_FLAGS ZAP_OBJ_DAMAGE | ZAP_MOB_DAMAGE | ZAP_MOB_STUN #define ZAP_SUPERMATTER_FLAGS NONE diff --git a/code/__DEFINES/antagonists.dm b/code/__DEFINES/antagonists.dm index b883a54209..a3e5423753 100644 --- a/code/__DEFINES/antagonists.dm +++ b/code/__DEFINES/antagonists.dm @@ -63,6 +63,16 @@ #define CONTRACT_UPLINK_PAGE_CONTRACTS "CONTRACTS" #define CONTRACT_UPLINK_PAGE_HUB "HUB" + +///Heretics -- +#define IS_HERETIC(mob) (mob.mind?.has_antag_datum(/datum/antagonist/heretic)) + +#define PATH_SIDE "Side" + +#define PATH_ASH "Ash" +#define PATH_RUST "Rust" +#define PATH_FLESH "Flesh" + //Overthrow time to update heads obj #define OBJECTIVE_UPDATING_TIME 300 @@ -91,4 +101,4 @@ #define BLOB_REROLL_TIME 2400 // blob gets a free reroll every X time #define BLOB_SPREAD_COST 4 #define BLOB_ATTACK_REFUND 2 //blob refunds this much if it attacks and doesn't spread -#define BLOB_REFLECTOR_COST 15 \ No newline at end of file +#define BLOB_REFLECTOR_COST 15 diff --git a/code/__DEFINES/atom_hud.dm b/code/__DEFINES/atom_hud.dm index 01f14c748e..386473a3ae 100644 --- a/code/__DEFINES/atom_hud.dm +++ b/code/__DEFINES/atom_hud.dm @@ -60,6 +60,7 @@ #define ANTAG_HUD_BROTHER 23 #define ANTAG_HUD_BLOODSUCKER 24 #define ANTAG_HUD_FUGITIVE 25 +#define ANTAG_HUD_HERETIC 26 // Notification action types #define NOTIFY_JUMP "jump" diff --git a/code/__DEFINES/dcs/signals.dm b/code/__DEFINES/dcs/signals.dm index 7e1a83486d..65994dda5a 100644 --- a/code/__DEFINES/dcs/signals.dm +++ b/code/__DEFINES/dcs/signals.dm @@ -15,22 +15,31 @@ ////////////////////////////////////////////////////////////////// // /datum signals -#define COMSIG_COMPONENT_ADDED "component_added" //sent to the new datum parent when a component is added to them: (/datum/component) -#define COMSIG_COMPONENT_REMOVING "component_removing" //sent to the datum parent before a component is removed from them because of RemoveComponent: (/datum/component) -#define COMSIG_COMPONENT_UNREGISTER_PARENT "component_unregister_parent" //sent to the component itself when unregistered from a parent -#define COMSIG_COMPONENT_REGISTER_PARENT "component_register_parent" //sent to the component itself when registered to a parent -#define COMSIG_PARENT_PREQDELETED "parent_preqdeleted" //before a datum's Destroy() is called: (force), returning a nonzero value will cancel the qdel operation -#define COMSIG_PARENT_QDELETING "parent_qdeleting" //just before a datum's Destroy() is called: (force), at this point none of the other components chose to interrupt qdel and Destroy will be called - -/// Trait signals -#define COMPONENT_ADD_TRAIT (1<<0) -#define COMPONENT_REMOVE_TRAIT (1<<1) +/// when a component is added to a datum: (/datum/component) +#define COMSIG_COMPONENT_ADDED "component_added" +/// before a component is removed from a datum because of RemoveComponent: (/datum/component) +#define COMSIG_COMPONENT_REMOVING "component_removing" +/// before a datum's Destroy() is called: (force), returning a nonzero value will cancel the qdel operation +#define COMSIG_PARENT_PREQDELETED "parent_preqdeleted" +/// just before a datum's Destroy() is called: (force), at this point none of the other components chose to interrupt qdel and Destroy will be called +#define COMSIG_PARENT_QDELETING "parent_qdeleting" +/// generic topic handler (usr, href_list) +#define COMSIG_TOPIC "handle_topic" /// fires on the target datum when an element is attached to it (/datum/element) #define COMSIG_ELEMENT_ATTACH "element_attach" /// fires on the target datum when an element is attached to it (/datum/element) #define COMSIG_ELEMENT_DETACH "element_detach" +/// sent to the component itself when unregistered from a parent +#define COMSIG_COMPONENT_UNREGISTER_PARENT "component_unregister_parent" +/// sent to the component itself when registered to a parent +#define COMSIG_COMPONENT_REGISTER_PARENT "component_register_parent" + +/// Trait signals +#define COMPONENT_ADD_TRAIT (1<<0) +#define COMPONENT_REMOVE_TRAIT (1<<1) + // /atom signals //from base of atom/proc/Initialize(): sent any time a new atom is created #define COMSIG_ATOM_CREATED "atom_created" @@ -56,30 +65,54 @@ #define COMSIG_ATOM_EXIT "atom_exit" //from base of atom/Exit(): (/atom/movable/exiting, /atom/newloc) #define COMPONENT_ATOM_BLOCK_EXIT 1 #define COMSIG_ATOM_EXITED "atom_exited" //from base of atom/Exited(): (atom/movable/exiting, atom/newloc) -#define COMSIG_ATOM_EX_ACT "atom_ex_act" //from base of atom/ex_act(): (severity, target) -#define COMSIG_ATOM_EMP_ACT "atom_emp_act" //from base of atom/emp_act(): (severity) -#define COMSIG_ATOM_FIRE_ACT "atom_fire_act" //from base of atom/fire_act(): (exposed_temperature, exposed_volume) -#define COMSIG_ATOM_BULLET_ACT "atom_bullet_act" //from base of atom/bullet_act(): (/obj/item/projectile, def_zone) -#define COMSIG_ATOM_BLOB_ACT "atom_blob_act" //from base of atom/blob_act(): (/obj/structure/blob) -#define COMSIG_ATOM_ACID_ACT "atom_acid_act" //from base of atom/acid_act(): (acidpwr, acid_volume) -#define COMSIG_ATOM_EMAG_ACT "atom_emag_act" //from base of atom/emag_act(): () -#define COMSIG_ATOM_RAD_ACT "atom_rad_act" //from base of atom/rad_act(intensity) -#define COMSIG_ATOM_NARSIE_ACT "atom_narsie_act" //from base of atom/narsie_act(): () -#define COMSIG_ATOM_RATVAR_ACT "atom_ratvar_act" //from base of atom/ratvar_act(): () -#define COMSIG_ATOM_RCD_ACT "atom_rcd_act" //from base of atom/rcd_act(): (/mob, /obj/item/construction/rcd, passed_mode) -#define COMSIG_ATOM_SING_PULL "atom_sing_pull" //from base of atom/singularity_pull(): (S, current_size) -#define COMSIG_ATOM_SET_LIGHT "atom_set_light" //from base of atom/set_light(): (l_range, l_power, l_color) -#define COMSIG_ATOM_DIR_CHANGE "atom_dir_change" //from base of atom/setDir(): (old_dir, new_dir) -#define COMSIG_ATOM_CONTENTS_DEL "atom_contents_del" //from base of atom/handle_atom_del(): (atom/deleted) -#define COMSIG_ATOM_HAS_GRAVITY "atom_has_gravity" //from base of atom/has_gravity(): (turf/location, list/forced_gravities) -#define COMSIG_ATOM_RAD_PROBE "atom_rad_probe" //from proc/get_rad_contents(): () - #define COMPONENT_BLOCK_RADIATION 1 -#define COMSIG_ATOM_RAD_CONTAMINATING "atom_rad_contam" //from base of datum/radiation_wave/radiate(): (strength) - #define COMPONENT_BLOCK_CONTAMINATION 1 -#define COMSIG_ATOM_RAD_WAVE_PASSING "atom_rad_wave_pass" //from base of datum/radiation_wave/check_obstructions(): (datum/radiation_wave, width) - #define COMPONENT_RAD_WAVE_HANDLED 1 -#define COMSIG_ATOM_CANREACH "atom_can_reach" //from internal loop in atom/movable/proc/CanReach(): (list/next) - #define COMPONENT_BLOCK_REACH 1 +///from base of atom/ex_act(): (severity, target) +#define COMSIG_ATOM_EX_ACT "atom_ex_act" +///from base of atom/emp_act(): (severity) +#define COMSIG_ATOM_EMP_ACT "atom_emp_act" +///from base of atom/fire_act(): (exposed_temperature, exposed_volume) +#define COMSIG_ATOM_FIRE_ACT "atom_fire_act" +///from base of atom/bullet_act(): (/obj/projectile, def_zone) +#define COMSIG_ATOM_BULLET_ACT "atom_bullet_act" +///from base of atom/blob_act(): (/obj/structure/blob) +#define COMSIG_ATOM_BLOB_ACT "atom_blob_act" +///from base of atom/acid_act(): (acidpwr, acid_volume) +#define COMSIG_ATOM_ACID_ACT "atom_acid_act" +///from base of atom/emag_act(): (/mob/user) +#define COMSIG_ATOM_EMAG_ACT "atom_emag_act" +///from base of atom/rad_act(intensity) +#define COMSIG_ATOM_RAD_ACT "atom_rad_act" +///from base of atom/narsie_act(): () +#define COMSIG_ATOM_NARSIE_ACT "atom_narsie_act" +///from base of atom/ratvar_act(): () +#define COMSIG_ATOM_RATVAR_ACT "atom_ratvar_act" +///from base of atom/rcd_act(): (/mob, /obj/item/construction/rcd, passed_mode) +#define COMSIG_ATOM_RCD_ACT "atom_rcd_act" +///from base of atom/singularity_pull(): (S, current_size) +#define COMSIG_ATOM_SING_PULL "atom_sing_pull" +///from obj/machinery/bsa/full/proc/fire(): () +#define COMSIG_ATOM_BSA_BEAM "atom_bsa_beam_pass" + #define COMSIG_ATOM_BLOCKS_BSA_BEAM (1<<0) +///from base of atom/set_light(): (l_range, l_power, l_color) +#define COMSIG_ATOM_SET_LIGHT "atom_set_light" +///from base of atom/setDir(): (old_dir, new_dir). Called before the direction changes. +#define COMSIG_ATOM_DIR_CHANGE "atom_dir_change" +///from base of atom/handle_atom_del(): (atom/deleted) +#define COMSIG_ATOM_CONTENTS_DEL "atom_contents_del" +///from base of atom/has_gravity(): (turf/location, list/forced_gravities) +#define COMSIG_ATOM_HAS_GRAVITY "atom_has_gravity" +///from proc/get_rad_contents(): () +#define COMSIG_ATOM_RAD_PROBE "atom_rad_probe" + #define COMPONENT_BLOCK_RADIATION (1<<0) +///from base of datum/radiation_wave/radiate(): (strength) +#define COMSIG_ATOM_RAD_CONTAMINATING "atom_rad_contam" + #define COMPONENT_BLOCK_CONTAMINATION (1<<0) +///from base of datum/radiation_wave/check_obstructions(): (datum/radiation_wave, width) +#define COMSIG_ATOM_RAD_WAVE_PASSING "atom_rad_wave_pass" + #define COMPONENT_RAD_WAVE_HANDLED (1<<0) +///from internal loop in atom/movable/proc/CanReach(): (list/next) +#define COMSIG_ATOM_CANREACH "atom_can_reach" + #define COMPONENT_BLOCK_REACH (1<<0) + #define COMSIG_ATOM_SCREWDRIVER_ACT "atom_screwdriver_act" //from base of atom/screwdriver_act(): (mob/living/user, obj/item/I) #define COMSIG_ATOM_INTERCEPT_TELEPORT "intercept_teleport" //called when teleporting into a protected turf: (channel, turf/origin, turf/destination) #define COMPONENT_BLOCK_TELEPORT 1 @@ -209,6 +242,8 @@ #define COMSIG_MOB_SWAP_HANDS "mob_swap_hands" //from base of mob/swap_hand(): (obj/item) #define COMPONENT_BLOCK_SWAP 1 +#define COMSIG_PROCESS_BORGCHARGER_OCCUPANT "living_charge" + // /client signals #define COMSIG_MOB_CLIENT_LOGIN "mob_client_login" //sent when a mob/login() finishes: (client) #define COMSIG_MOB_CLIENT_LOGOUT "mob_client_logout" //sent when a mob/logout() starts: (client) @@ -277,6 +312,7 @@ #define COMSIG_OBJ_DECONSTRUCT "obj_deconstruct" //from base of obj/deconstruct(): (disassembled) #define COMSIG_OBJ_BREAK "obj_break" //from base of /obj/obj_break(): (damage_flag) #define COMSIG_OBJ_SETANCHORED "obj_setanchored" //called in /obj/structure/setAnchored(): (value) +#define COMSIG_OBJ_DEFAULT_UNFASTEN_WRENCH "obj_default_unfasten_wrench" //called exclusively in plumbing, for now #define COMSIG_OBJ_ATTACK_GENERIC "obj_attack_generic" //from base of atom/animal_attack(): (/mob/user) #define COMPONENT_STOP_GENERIC_ATTACK 1 @@ -452,6 +488,9 @@ #define COMPONENT_TWOHANDED_BLOCK_WIELD 1 #define COMSIG_TWOHANDED_UNWIELD "twohanded_unwield" //from base of datum/component/two_handed/proc/unwield(mob/living/carbon/user): (/mob/user) +// /datum/component/squeak signals +#define COMSIG_CROSS_SQUEAKED "cross_squeaked" // sent when a squeak component squeaks from crossing something, to delay anything else crossing that might squeak to prevent ear hurt. + // /datum/action signals #define COMSIG_ACTION_TRIGGER "action_trigger" //from base of datum/action/proc/Trigger(): (datum/action) #define COMPONENT_ACTION_BLOCK_TRIGGER 1 diff --git a/code/__DEFINES/exosuit_fabs.dm b/code/__DEFINES/exosuit_fabs.dm new file mode 100644 index 0000000000..d951a7bc28 --- /dev/null +++ b/code/__DEFINES/exosuit_fabs.dm @@ -0,0 +1,35 @@ +/// Module is compatible with Security Cyborg models +#define BORG_MODULE_SECURITY (1<<0) +/// Module is compatible with Miner Cyborg models +#define BORG_MODULE_MINER (1<<1) +/// Module is compatible with Janitor Cyborg models +#define BORG_MODULE_JANITOR (1<<2) +/// Module is compatible with Medical Cyborg models +#define BORG_MODULE_MEDICAL (1<<3) +/// Module is compatible with Engineering Cyborg models +#define BORG_MODULE_ENGINEERING (1<<4) + +/// Module is compatible with Ripley Exosuit models +#define EXOSUIT_MODULE_RIPLEY (1<<0) +/// Module is compatible with Odyseeus Exosuit models +#define EXOSUIT_MODULE_ODYSSEUS (1<<1) +/// Module is compatible with Clarke Exosuit models. Rebranded to firefighter because tg nerfed it to this. +#define EXOSUIT_MODULE_FIREFIGHTER (1<<2) +// #define EXOSUIT_MODULE_CLARKE (1<<2) +/// Module is compatible with Gygax Exosuit models +#define EXOSUIT_MODULE_GYGAX (1<<3) +/// Module is compatible with Durand Exosuit models +#define EXOSUIT_MODULE_DURAND (1<<4) +/// Module is compatible with H.O.N.K Exosuit models +#define EXOSUIT_MODULE_HONK (1<<5) +/// Module is compatible with Phazon Exosuit models +#define EXOSUIT_MODULE_PHAZON (1<<6) +/// Module is compatable with N models +#define EXOSUIT_MODULE_GYGAX_MED (1<<7) + +/// Module is compatible with "Working" Exosuit models - Ripley and Clarke +#define EXOSUIT_MODULE_WORKING EXOSUIT_MODULE_RIPLEY | EXOSUIT_MODULE_FIREFIGHTER // | EXOSUIT_MODULE_CLARKE +/// Module is compatible with "Combat" Exosuit models - Gygax, H.O.N.K, Durand and Phazon +#define EXOSUIT_MODULE_COMBAT EXOSUIT_MODULE_GYGAX | EXOSUIT_MODULE_HONK | EXOSUIT_MODULE_DURAND | EXOSUIT_MODULE_PHAZON +/// Module is compatible with "Medical" Exosuit modelsm - Odysseus +#define EXOSUIT_MODULE_MEDICAL EXOSUIT_MODULE_ODYSSEUS | EXOSUIT_MODULE_GYGAX_MED diff --git a/code/__DEFINES/footsteps.dm b/code/__DEFINES/footsteps.dm index 2dd66b9833..215e287adf 100644 --- a/code/__DEFINES/footsteps.dm +++ b/code/__DEFINES/footsteps.dm @@ -7,6 +7,8 @@ #define FOOTSTEP_WATER "water" #define FOOTSTEP_LAVA "lava" #define FOOTSTEP_MEAT "meat" +#define FOOTSTEP_RUST "rust" + //barefoot sounds #define FOOTSTEP_WOOD_BAREFOOT "woodbarefoot" #define FOOTSTEP_WOOD_CLAW "woodclaw" @@ -91,7 +93,9 @@ GLOBAL_LIST_INIT(footstep, list( 'sound/effects/footstep/lava2.ogg', 'sound/effects/footstep/lava3.ogg'), 100, 0), FOOTSTEP_MEAT = list(list( - 'sound/effects/meatslap.ogg'), 100, 0) + 'sound/effects/meatslap.ogg'), 100, 0), + FOOTSTEP_RUST = list(list( + 'sound/effects/footstep/rustystep1.ogg'), 100, 0) )) //bare footsteps lists @@ -135,7 +139,9 @@ GLOBAL_LIST_INIT(barefootstep, list( 'sound/effects/footstep/lava2.ogg', 'sound/effects/footstep/lava3.ogg'), 100, 0), FOOTSTEP_MEAT = list(list( - 'sound/effects/meatslap.ogg'), 100, 0) + 'sound/effects/meatslap.ogg'), 100, 0), + FOOTSTEP_RUST = list(list( + 'sound/effects/footstep/rustystep1.ogg'), 100, 0) )) //claw footsteps lists @@ -179,7 +185,9 @@ GLOBAL_LIST_INIT(clawfootstep, list( 'sound/effects/footstep/lava2.ogg', 'sound/effects/footstep/lava3.ogg'), 100, 0), FOOTSTEP_MEAT = list(list( - 'sound/effects/meatslap.ogg'), 100, 0) + 'sound/effects/meatslap.ogg'), 100, 0), + FOOTSTEP_RUST = list(list( + 'sound/effects/footstep/rustystep1.ogg'), 100, 0) )) //heavy footsteps list @@ -197,5 +205,7 @@ GLOBAL_LIST_INIT(heavyfootstep, list( 'sound/effects/footstep/lava2.ogg', 'sound/effects/footstep/lava3.ogg'), 100, 0), FOOTSTEP_MEAT = list(list( - 'sound/effects/meatslap.ogg'), 100, 0) + 'sound/effects/meatslap.ogg'), 100, 0), + FOOTSTEP_RUST = list(list( + 'sound/effects/footstep/rustystep1.ogg'), 150, 2) )) diff --git a/code/__DEFINES/is_helpers.dm b/code/__DEFINES/is_helpers.dm index 3aa5a07480..55be13834d 100644 --- a/code/__DEFINES/is_helpers.dm +++ b/code/__DEFINES/is_helpers.dm @@ -17,7 +17,7 @@ GLOBAL_LIST_INIT(turfs_without_ground, typecacheof(list( /turf/open/chasm, /turf/open/lava, /turf/open/water, - /turf/open/openspace + /turf/open/transparent/openspace ))) #define isgroundlessturf(A) (is_type_in_typecache(A, GLOB.turfs_without_ground)) @@ -44,6 +44,8 @@ GLOBAL_LIST_INIT(turfs_without_ground, typecacheof(list( #define isplatingturf(A) (istype(A, /turf/open/floor/plating)) +#define istransparentturf(A) (istype(A, /turf/open/transparent)) + //Mobs #define isliving(A) (istype(A, /mob/living)) @@ -74,6 +76,7 @@ GLOBAL_LIST_INIT(turfs_without_ground, typecacheof(list( #define ismush(A) (is_species(A, /datum/species/mush)) #define isshadow(A) (is_species(A, /datum/species/shadow)) #define isskeleton(A) (is_species(A, /datum/species/skeleton)) +#define isethereal(A) (is_species(A, /datum/species/ethereal)) // Citadel specific species #define isipcperson(A) (is_species(A, /datum/species/ipc)) diff --git a/code/__DEFINES/layers_planes.dm b/code/__DEFINES/layers_planes.dm index 6f33bb1a0e..9188efacfd 100644 --- a/code/__DEFINES/layers_planes.dm +++ b/code/__DEFINES/layers_planes.dm @@ -131,6 +131,8 @@ #define LIGHTING_LAYER 15 #define LIGHTING_RENDER_TARGET "LIGHT_PLANE" +#define RAD_TEXT_LAYER 15.1 + #define ABOVE_LIGHTING_PLANE 16 #define ABOVE_LIGHTING_LAYER 16 #define ABOVE_LIGHTING_RENDER_TARGET "ABOVE_LIGHTING_PLANE" diff --git a/code/__DEFINES/loadout.dm b/code/__DEFINES/loadout.dm index 332095e049..94059c0880 100644 --- a/code/__DEFINES/loadout.dm +++ b/code/__DEFINES/loadout.dm @@ -1,56 +1,56 @@ //defines for loadout categories //no category defines -#define NOCATEGORY list("NOCATEGORY") -#define NOSUBCATEGORY list("NOSUBCATEGORY") - +#define LOADOUT_CATEGORY_NONE "ERROR" +#define LOADOUT_SUBCATEGORY_NONE "Miscellaneous" +#define LOADOUT_SUBCATEGORIES_NONE list("Miscellaneous") //backpack -#define CATEGORY_BACKPACK "In backpack" -#define SUBCATEGORY_BACKPACK_GENERAL "General" //basically anything that there's not enough of to have its own subcategory -#define SUBCATEGORY_BACKPACK_TOYS "Toys" +#define LOADOUT_CATEGORY_BACKPACK "In backpack" +#define LOADOUT_SUBCATEGORY_BACKPACK_GENERAL "General" //basically anything that there's not enough of to have its own subcategory +#define LOADOUT_SUBCATEGORY_BACKPACK_TOYS "Toys" //neck -#define CATEGORY_NECK "Neck" -#define SUBCATEGORY_NECK_GENERAL "General" -#define SUBCATEGORY_NECK_TIE "Ties" -#define SUBCATEGORY_NECK_SCARVES "Scarves" +#define LOADOUT_CATEGORY_NECK "Neck" +#define LOADOUT_SUBCATEGORY_NECK_GENERAL "General" +#define LOADOUT_SUBCATEGORY_NECK_TIE "Ties" +#define LOADOUT_SUBCATEGORY_NECK_SCARVES "Scarves" //mask -#define CATEGORY_MASK "Mask" +#define LOADOUT_CATEGORY_MASK "Mask" //hands -#define CATEGORY_HANDS "Hands" +#define LOADOUT_CATEGORY_HANDS "Hands" //uniform -#define CATEGORY_UNIFORM "Uniform" //there's so many types of uniform it's best to have lots of categories -#define SUBCATEGORY_UNIFORM_GENERAL "General" -#define SUBCATEGORY_UNIFORM_JOBS "Jobs" -#define SUBCATEGORY_UNIFORM_SUITS "Suits" -#define SUBCATEGORY_UNIFORM_SKIRTS "Skirts" -#define SUBCATEGORY_UNIFORM_DRESSES "Dresses" -#define SUBCATEGORY_UNIFORM_SWEATERS "Sweaters" -#define SUBCATEGORY_UNIFORM_PANTS "Pants" -#define SUBCATEGORY_UNIFORM_SHORTS "Shorts" +#define LOADOUT_CATEGORY_UNIFORM "Uniform" //there's so many types of uniform it's best to have lots of categories +#define LOADOUT_SUBCATEGORY_UNIFORM_GENERAL "General" +#define LOADOUT_SUBCATEGORY_UNIFORM_JOBS "Jobs" +#define LOADOUT_SUBCATEGORY_UNIFORM_SUITS "Suits" +#define LOADOUT_SUBCATEGORY_UNIFORM_SKIRTS "Skirts" +#define LOADOUT_SUBCATEGORY_UNIFORM_DRESSES "Dresses" +#define LOADOUT_SUBCATEGORY_UNIFORM_SWEATERS "Sweaters" +#define LOADOUT_SUBCATEGORY_UNIFORM_PANTS "Pants" +#define LOADOUT_SUBCATEGORY_UNIFORM_SHORTS "Shorts" //suit -#define CATEGORY_SUIT "Suit" -#define SUBCATEGORY_SUIT_GENERAL "General" -#define SUBCATEGORY_SUIT_COATS "Coats" -#define SUBCATEGORY_SUIT_JACKETS "Jackets" -#define SUBCATEGORY_SUIT_JOBS "Jobs" +#define LOADOUT_CATEGORY_SUIT "Suit" +#define LOADOUT_SUBCATEGORY_SUIT_GENERAL "General" +#define LOADOUT_SUBCATEGORY_SUIT_COATS "Coats" +#define LOADOUT_SUBCATEGORY_SUIT_JACKETS "Jackets" +#define LOADOUT_SUBCATEGORY_SUIT_JOBS "Jobs" //head -#define CATEGORY_HEAD "Head" -#define SUBCATEGORY_HEAD_GENERAL "General" -#define SUBCATEGORY_HEAD_JOBS "Jobs" +#define LOADOUT_CATEGORY_HEAD "Head" +#define LOADOUT_SUBCATEGORY_HEAD_GENERAL "General" +#define LOADOUT_SUBCATEGORY_HEAD_JOBS "Jobs" //shoes -#define CATEGORY_SHOES "Shoes" +#define LOADOUT_CATEGORY_SHOES "Shoes" //gloves -#define CATEGORY_GLOVES "Gloves" +#define LOADOUT_CATEGORY_GLOVES "Gloves" //glasses -#define CATEGORY_GLASSES "Glasses" +#define LOADOUT_CATEGORY_GLASSES "Glasses" //donator items -#define CATEGORY_DONATOR "Donator" +#define LOADOUT_CATEGORY_DONATOR "Donator" diff --git a/code/__DEFINES/logging.dm b/code/__DEFINES/logging.dm index 71de692410..ecb58f1291 100644 --- a/code/__DEFINES/logging.dm +++ b/code/__DEFINES/logging.dm @@ -19,6 +19,7 @@ #define INVESTIGATE_FERMICHEM "fermichem" #define INVESTIGATE_RCD "rcd" #define INVESTIGATE_CRYOGENICS "cryogenics" +#define INVESTIGATE_GHOST "ghost" // Logging types for log_message() #define LOG_ATTACK (1 << 0) diff --git a/code/__DEFINES/maths.dm b/code/__DEFINES/maths.dm index 24726b8058..370f869c48 100644 --- a/code/__DEFINES/maths.dm +++ b/code/__DEFINES/maths.dm @@ -46,6 +46,8 @@ // Cosecant #define CSC(x) (1 / sin(x)) +#define ATAN2(x, y) ( !(x) && !(y) ? 0 : (y) >= 0 ? arccos((x) / sqrt((x)*(x) + (y)*(y))) : -arccos((x) / sqrt((x)*(x) + (y)*(y))) ) + // Greatest Common Divisor - Euclid's algorithm /proc/Gcd(a, b) return b ? Gcd(b, (a) % (b)) : a diff --git a/code/__DEFINES/misc.dm b/code/__DEFINES/misc.dm index d294c69972..927b661898 100644 --- a/code/__DEFINES/misc.dm +++ b/code/__DEFINES/misc.dm @@ -341,10 +341,11 @@ GLOBAL_LIST_INIT(pda_reskins, list(PDA_SKIN_CLASSIC = 'icons/obj/pda.dmi', PDA_S #define COLOUR_PRIORITY_AMOUNT 4 //how many priority levels there are. //Endgame Results -#define NUKE_MISS_STATION 1 -#define NUKE_SYNDICATE_BASE 2 -#define STATION_DESTROYED_NUKE 3 -#define STATION_EVACUATED 4 +#define NUKE_NEAR_MISS 1 +#define NUKE_MISS_STATION 2 +#define NUKE_SYNDICATE_BASE 3 +#define STATION_DESTROYED_NUKE 4 +#define STATION_EVACUATED 5 #define BLOB_WIN 8 #define BLOB_NUKE 9 #define BLOB_DESTROYED 10 diff --git a/code/__DEFINES/mobs.dm b/code/__DEFINES/mobs.dm index 52657e9104..6ddd269b4b 100644 --- a/code/__DEFINES/mobs.dm +++ b/code/__DEFINES/mobs.dm @@ -176,6 +176,15 @@ #define DISGUST_LEVEL_VERYGROSS 50 #define DISGUST_LEVEL_GROSS 25 +//Charge levels for Ethereals +#define ETHEREAL_CHARGE_NONE 0 +#define ETHEREAL_CHARGE_LOWPOWER 20 +#define ETHEREAL_CHARGE_NORMAL 50 +#define ETHEREAL_CHARGE_ALMOSTFULL 75 +#define ETHEREAL_CHARGE_FULL 100 +#define ETHEREAL_CHARGE_OVERLOAD 125 +#define ETHEREAL_CHARGE_DANGEROUS 150 + //Slime evolution threshold. Controls how fast slimes can split/grow #define SLIME_EVOLUTION_THRESHOLD 10 @@ -284,6 +293,7 @@ #define DOOR_CRUSH_DAMAGE 15 //the amount of damage that airlocks deal when they crush you #define HUNGER_FACTOR 0.1 //factor at which mob nutrition decreases +#define ETHEREAL_CHARGE_FACTOR 0.08 //factor at which ethereal's charge decreases #define REAGENTS_METABOLISM 0.4 //How many units of reagent are consumed per tick, by default. #define REAGENTS_EFFECT_MULTIPLIER (REAGENTS_METABOLISM / 0.4) // By defining the effect multiplier this way, it'll exactly adjust all effects according to how they originally were with the 0.4 metabolism @@ -322,3 +332,5 @@ /// If you examine the same atom twice in this timeframe, we call examine_more() instead of examine() #define EXAMINE_MORE_TIME 1 SECONDS + +#define SILENCE_RANGED_MESSAGE (1<<0) diff --git a/code/__DEFINES/plumbing.dm b/code/__DEFINES/plumbing.dm new file mode 100644 index 0000000000..5ea7c46b42 --- /dev/null +++ b/code/__DEFINES/plumbing.dm @@ -0,0 +1,9 @@ +#define FIRST_DUCT_LAYER 1 +#define SECOND_DUCT_LAYER 2 +#define THIRD_DUCT_LAYER 4 +#define FOURTH_DUCT_LAYER 8 +#define FIFTH_DUCT_LAYER 16 + +#define DUCT_LAYER_DEFAULT THIRD_DUCT_LAYER + +#define MACHINE_REAGENT_TRANSFER 10 diff --git a/code/__DEFINES/pool.dm b/code/__DEFINES/pool.dm index 1e66109dc7..1bf39dcb1d 100644 --- a/code/__DEFINES/pool.dm +++ b/code/__DEFINES/pool.dm @@ -8,6 +8,5 @@ GLOBAL_LIST_INIT(blacklisted_pool_reagents, list( /datum/reagent/toxin/plasma, /datum/reagent/oxygen, /datum/reagent/nitrous_oxide, /datum/reagent/nitrogen, //gases /datum/reagent/fermi, //blanket fermichem ban sorry. this also covers mkultra, genital enlargers, etc etc. - /datum/reagent/drug/aphrodisiac, /datum/reagent/drug/anaphrodisiac, /datum/reagent/drug/aphrodisiacplus, /datum/reagent/drug/anaphrodisiacplus, //literally asking for prefbreaks - /datum/reagent/consumable/femcum, /datum/reagent/consumable/semen //NO. + /datum/reagent/consumable/semen //NO. )) diff --git a/code/__DEFINES/qdel.dm b/code/__DEFINES/qdel.dm index 4296e3c2e9..63259774fa 100644 --- a/code/__DEFINES/qdel.dm +++ b/code/__DEFINES/qdel.dm @@ -6,10 +6,17 @@ #define QDEL_HINT_IWILLGC 2 //functionally the same as the above. qdel should assume the object will gc on its own, and not check it. #define QDEL_HINT_HARDDEL 3 //qdel should assume this object won't gc, and queue a hard delete using a hard reference. #define QDEL_HINT_HARDDEL_NOW 4 //qdel should assume this object won't gc, and hard del it post haste. -#define QDEL_HINT_FINDREFERENCE 5 //functionally identical to QDEL_HINT_QUEUE if TESTING is not enabled in _compiler_options.dm. - //if TESTING is enabled, qdel will call this object's find_references() verb. -#define QDEL_HINT_IFFAIL_FINDREFERENCE 6 //Above but only if gc fails. -//defines for the gc_destroyed var + +#ifdef LEGACY_REFERENCE_TRACKING +/** If LEGACY_REFERENCE_TRACKING is enabled, qdel will call this object's find_references() verb. + * + * Functionally identical to QDEL_HINT_QUEUE if GC_FAILURE_HARD_LOOKUP is not enabled in _compiler_options.dm. +*/ +#define QDEL_HINT_FINDREFERENCE 5 +/// Behavior as QDEL_HINT_FINDREFERENCE, but only if the GC fails and a hard delete is forced. +#define QDEL_HINT_IFFAIL_FINDREFERENCE 6 +#endif + #define GC_QUEUE_CHECK 1 #define GC_QUEUE_HARDDELETE 2 diff --git a/code/__DEFINES/reagents.dm b/code/__DEFINES/reagents.dm index f4beef7ee8..44e97ef345 100644 --- a/code/__DEFINES/reagents.dm +++ b/code/__DEFINES/reagents.dm @@ -57,6 +57,10 @@ #define ADD_REAGENT 2 // reagent added #define REM_REAGENT 3 // reagent removed (may still exist) + +#define PILL_STYLE_COUNT 22 //Update this if you add more pill icons or you die (literally, we'll toss a nuke at whever your ip turns up) +#define RANDOM_PILL_STYLE 22 //Dont change this one though + #define THRESHOLD_UNHUSK 50 // health threshold for synthflesh/rezadone to unhusk someone //reagent bitflags, used for altering how they works diff --git a/code/__DEFINES/role_preferences.dm b/code/__DEFINES/role_preferences.dm index 7fabb74157..d7487eb54b 100644 --- a/code/__DEFINES/role_preferences.dm +++ b/code/__DEFINES/role_preferences.dm @@ -17,6 +17,7 @@ #define ROLE_ALIEN "xenomorph" #define ROLE_PAI "pAI" #define ROLE_CULTIST "cultist" +#define ROLE_HERETIC "Heretic" #define ROLE_BLOB "blob" #define ROLE_NINJA "space ninja" #define ROLE_MONKEY "monkey" @@ -64,6 +65,7 @@ GLOBAL_LIST_INIT(special_roles, list( ROLE_INTERNAL_AFFAIRS = /datum/game_mode/traitor/internal_affairs, ROLE_SENTIENCE, ROLE_GANG = /datum/game_mode/gang, + ROLE_HERETIC = /datum/game_mode/heretics, ROLE_BLOODSUCKER = /datum/game_mode/bloodsucker //ROLE_MONSTERHUNTER Disabled for now )) diff --git a/code/__DEFINES/status_effects.dm b/code/__DEFINES/status_effects.dm index 9a3b5d55f4..bfff1dc629 100644 --- a/code/__DEFINES/status_effects.dm +++ b/code/__DEFINES/status_effects.dm @@ -111,6 +111,10 @@ #define STATUS_EFFECT_LIMP /datum/status_effect/limp //For when you have a busted leg (or two!) and want additional slowdown when walking on that leg +#define STATUS_EFFECT_AMOK /datum/status_effect/amok //Makes the target automatically strike out at adjecent non-heretics. + +#define STATUS_EFFECT_CLOUDSTRUCK /datum/status_effect/cloudstruck //blinds and applies an overlay. + /// shoves inflict this to indicate the next shove while this is in effect should disarm guns #define STATUS_EFFECT_OFF_BALANCE /datum/status_effect/off_balance diff --git a/code/__DEFINES/subsystems.dm b/code/__DEFINES/subsystems.dm index 7a188281d0..81b5c5620f 100644 --- a/code/__DEFINES/subsystems.dm +++ b/code/__DEFINES/subsystems.dm @@ -146,11 +146,11 @@ #define SSAIR_EQUALIZE 8 #define SSAIR_ACTIVETURFS 9 +// |= on overlays is not actually guaranteed to not add same appearances but we're optimistically using it anyway. #define COMPILE_OVERLAYS(A)\ if (TRUE) {\ var/list/ad = A.add_overlays;\ var/list/rm = A.remove_overlays;\ - var/list/po = A.priority_overlays;\ if(LAZYLEN(rm)){\ A.overlays -= rm;\ A.remove_overlays = null;\ @@ -159,11 +159,5 @@ A.overlays |= ad;\ A.add_overlays = null;\ }\ - if(LAZYLEN(po)){\ - A.overlays |= po;\ - }\ - else{\ - A.priority_overlays = null;\ - }\ A.flags_1 &= ~OVERLAY_QUEUED_1;\ } diff --git a/code/__DEFINES/tgui.dm b/code/__DEFINES/tgui.dm index 5ba0096d1b..f5adeadade 100644 --- a/code/__DEFINES/tgui.dm +++ b/code/__DEFINES/tgui.dm @@ -1,4 +1,28 @@ -#define UI_INTERACTIVE 2 // Green/Interactive -#define UI_UPDATE 1 // Orange/Updates Only -#define UI_DISABLED 0 // Red/Disabled -#define UI_CLOSE -1 // Closed \ No newline at end of file +/// Green eye; fully interactive +#define UI_INTERACTIVE 2 +/// Orange eye; updates but is not interactive +#define UI_UPDATE 1 +/// Red eye; disabled, does not update +#define UI_DISABLED 0 +/// UI Should close +#define UI_CLOSE -1 + +/// Maximum number of windows that can be suspended/reused +#define TGUI_WINDOW_SOFT_LIMIT 5 +/// Maximum number of open windows +#define TGUI_WINDOW_HARD_LIMIT 9 + +/// Maximum ping timeout allowed to detect zombie windows +#define TGUI_PING_TIMEOUT 4 SECONDS + +/// Window does not exist +#define TGUI_WINDOW_CLOSED 0 +/// Window was just opened, but is still not ready to be sent data +#define TGUI_WINDOW_LOADING 1 +/// Window is free and ready to receive data +#define TGUI_WINDOW_READY 2 + +/// Get a window id based on the provided pool index +#define TGUI_WINDOW_ID(index) "tgui-window-[index]" +/// Get a pool index of the provided window id +#define TGUI_WINDOW_INDEX(window_id) text2num(copytext(window_id, 13)) diff --git a/code/__DEFINES/traits.dm b/code/__DEFINES/traits.dm index 3e5b27d376..674cc16980 100644 --- a/code/__DEFINES/traits.dm +++ b/code/__DEFINES/traits.dm @@ -104,7 +104,9 @@ #define TRAIT_RESISTCOLD "resist_cold" #define TRAIT_RESISTHIGHPRESSURE "resist_high_pressure" #define TRAIT_RESISTLOWPRESSURE "resist_low_pressure" +#define TRAIT_BOMBIMMUNE "bomb_immunity" #define TRAIT_RADIMMUNE "rad_immunity" +#define TRAIT_GENELESS "geneless" #define TRAIT_VIRUSIMMUNE "virus_immunity" #define TRAIT_PIERCEIMMUNE "pierce_immunity" #define TRAIT_NODISMEMBER "dismember_immunity" @@ -178,6 +180,7 @@ #define TRAIT_FREERUNNING "freerunning" #define TRAIT_SKITTISH "skittish" #define TRAIT_POOR_AIM "poor_aim" +#define TRAIT_INSANE_AIM "insane_aim" //they don't miss. they never miss. it was all part of their immaculate plan. #define TRAIT_PROSOPAGNOSIA "prosopagnosia" #define TRAIT_DRUNK_HEALING "drunk_healing" #define TRAIT_TAGGER "tagger" @@ -202,7 +205,7 @@ #define TRAIT_NO_ALCOHOL "alcohol_intolerance" #define TRAIT_MUTATION_STASIS "mutation_stasis" //Prevents processed genetics mutations from processing. #define TRAIT_FAST_PUMP "fast_pump" -#define TRAIT_NICE_SHOT "nice_shot" //hnnnnnnnggggg..... you're pretty good.... +#define TRAIT_NICE_SHOT "nice_shot" //hnnnnnnnggggg..... you're pretty good... // mobility flag traits // IN THE FUTURE, IT WOULD BE NICE TO DO SOMETHING SIMILAR TO https://github.com/tgstation/tgstation/pull/48923/files (ofcourse not nearly the same because I have my.. thoughts on it) @@ -256,6 +259,7 @@ #define CURSED_ITEM_TRAIT "cursed-item" // The item is magically cursed #define ABSTRACT_ITEM_TRAIT "abstract-item" #define STATUS_EFFECT_TRAIT "status-effect" +#define CLOTHING_TRAIT "clothing" #define ROUNDSTART_TRAIT "roundstart" //cannot be removed without admin intervention #define GHOSTROLE_TRAIT "ghostrole" #define APHRO_TRAIT "aphro" @@ -310,4 +314,4 @@ #define ACTIVE_BLOCK_TRAIT "active_block" /// This trait is added by the parry system. #define ACTIVE_PARRY_TRAIT "active_parry" -#define STICKY_NODROP "sticky-nodrop" //sticky nodrop sounds like a bad soundcloud rapper's name \ No newline at end of file +#define STICKY_NODROP "sticky-nodrop" //sticky nodrop sounds like a bad soundcloud rapper's name diff --git a/code/__DEFINES/vv.dm b/code/__DEFINES/vv.dm index 101330cc8b..fe46fdc710 100644 --- a/code/__DEFINES/vv.dm +++ b/code/__DEFINES/vv.dm @@ -75,6 +75,7 @@ #define VV_HK_MARK "mark" #define VV_HK_ADDCOMPONENT "addcomponent" #define VV_HK_MODIFY_TRAITS "modtraits" +#define VV_HK_VIEW_REFERENCES "viewreferences" // /datum/gas_mixture #define VV_HK_SET_MOLES "set_moles" diff --git a/code/__HELPERS/_logging.dm b/code/__HELPERS/_logging.dm index 733cbcfd8d..62e6c4daf9 100644 --- a/code/__HELPERS/_logging.dm +++ b/code/__HELPERS/_logging.dm @@ -201,9 +201,18 @@ WRITE_LOG(log, "Starting up round ID [GLOB.round_id].\n-------------------------") /* ui logging */ - -/proc/log_tgui(text) - WRITE_LOG(GLOB.tgui_log, text) +/proc/log_tgui(user_or_client, text) + var/entry = "" + if(!user_or_client) + entry += "no user" + else if(istype(user_or_client, /mob)) + var/mob/user = user_or_client + entry += "[user.ckey] (as [user])" + else if(istype(user_or_client, /client)) + var/client/client = user_or_client + entry += "[client.ckey]" + entry += ":\n[text]" + WRITE_LOG(GLOB.tgui_log, entry) /* Close open log handles. This should be called as late as possible, and no logging should hapen after. */ /proc/shutdown_logging() diff --git a/code/__HELPERS/cmp.dm b/code/__HELPERS/cmp.dm index 0825e51ae4..4ee622961a 100644 --- a/code/__HELPERS/cmp.dm +++ b/code/__HELPERS/cmp.dm @@ -85,9 +85,6 @@ GLOBAL_VAR_INIT(cmp_field, "name") /proc/cmp_advdisease_resistance_asc(datum/disease/advance/A, datum/disease/advance/B) return A.totalResistance() - B.totalResistance() -/proc/cmp_job_display_asc(datum/job/A, datum/job/B) - return A.display_order - B.display_order - /proc/cmp_uplink_items_dsc(datum/uplink_item/A, datum/uplink_item/B) return sorttext(initial(B.name), initial(A.name)) @@ -97,9 +94,6 @@ GLOBAL_VAR_INIT(cmp_field, "name") /proc/cmp_numbered_displays_name_dsc(datum/numbered_display/A, datum/numbered_display/B) return sorttext(B.sample_object.name, A.sample_object.name) -/proc/cmp_reagents_asc(datum/reagent/a, datum/reagent/b) - return sorttext(initial(b.name),initial(a.name)) - /proc/cmp_quirk_asc(datum/quirk/A, datum/quirk/B) var/a_sign = num2sign(initial(A.value) * -1) var/b_sign = num2sign(initial(B.value) * -1) @@ -133,3 +127,16 @@ GLOBAL_VAR_INIT(cmp_field, "name") return A.required_temp - B.required_temp //return coldest else return B.required_temp - A.required_temp //return hottest + + +/proc/cmp_mob_realname_dsc(mob/A,mob/B) + return sorttext(A.real_name,B.real_name) + +/proc/cmp_job_display_asc(datum/job/A, datum/job/B) + return A.display_order - B.display_order + +/proc/cmp_reagents_asc(datum/reagent/a, datum/reagent/b) + return sorttext(initial(b.name),initial(a.name)) + +/proc/cmp_typepaths_asc(A, B) + return sorttext("[B]","[A]") diff --git a/code/__HELPERS/global_lists.dm b/code/__HELPERS/global_lists.dm index d66e83d651..1119ef44ed 100644 --- a/code/__HELPERS/global_lists.dm +++ b/code/__HELPERS/global_lists.dm @@ -37,10 +37,10 @@ //CIT CHANGES START HERE, ADDS SNOWFLAKE BODYPARTS AND MORE //mammal bodyparts (fucking furries) init_sprite_accessory_subtypes(/datum/sprite_accessory/mam_body_markings, GLOB.mam_body_markings_list) - init_sprite_accessory_subtypes(/datum/sprite_accessory/mam_tails, GLOB.mam_tails_list) - init_sprite_accessory_subtypes(/datum/sprite_accessory/mam_ears, GLOB.mam_ears_list) - init_sprite_accessory_subtypes(/datum/sprite_accessory/mam_snouts, GLOB.mam_snouts_list) - init_sprite_accessory_subtypes(/datum/sprite_accessory/mam_tails_animated, GLOB.mam_tails_animated_list) + init_sprite_accessory_subtypes(/datum/sprite_accessory/tails/mam_tails, GLOB.mam_tails_list) + init_sprite_accessory_subtypes(/datum/sprite_accessory/ears/mam_ears, GLOB.mam_ears_list) + init_sprite_accessory_subtypes(/datum/sprite_accessory/snouts/mam_snouts, GLOB.mam_snouts_list) + init_sprite_accessory_subtypes(/datum/sprite_accessory/tails_animated/mam_tails_animated, GLOB.mam_tails_animated_list) init_sprite_accessory_subtypes(/datum/sprite_accessory/taur, GLOB.taur_list) //xeno parts (hiss?) init_sprite_accessory_subtypes(/datum/sprite_accessory/xeno_head, GLOB.xeno_head_list) diff --git a/code/__HELPERS/mobs.dm b/code/__HELPERS/mobs.dm index ca12567b59..52e26b67e7 100644 --- a/code/__HELPERS/mobs.dm +++ b/code/__HELPERS/mobs.dm @@ -93,16 +93,16 @@ if(!GLOB.mam_body_markings_list.len) init_sprite_accessory_subtypes(/datum/sprite_accessory/mam_body_markings, GLOB.mam_body_markings_list) if(!GLOB.mam_tails_list.len) - init_sprite_accessory_subtypes(/datum/sprite_accessory/mam_tails, GLOB.mam_tails_list) + init_sprite_accessory_subtypes(/datum/sprite_accessory/tails/mam_tails, GLOB.mam_tails_list) if(!GLOB.mam_ears_list.len) - init_sprite_accessory_subtypes(/datum/sprite_accessory/mam_ears, GLOB.mam_ears_list) + init_sprite_accessory_subtypes(/datum/sprite_accessory/ears/mam_ears, GLOB.mam_ears_list) if(!GLOB.mam_snouts_list.len) - init_sprite_accessory_subtypes(/datum/sprite_accessory/mam_snouts, GLOB.mam_snouts_list) + init_sprite_accessory_subtypes(/datum/sprite_accessory/snouts/mam_snouts, GLOB.mam_snouts_list) //snowflake check so people's ckey features don't get randomly put on unmonkeys/spawns var/list/snowflake_mam_tails_list = list() for(var/mtpath in GLOB.mam_tails_list) - var/datum/sprite_accessory/mam_tails/instance = GLOB.mam_tails_list[mtpath] + var/datum/sprite_accessory/tails/mam_tails/instance = GLOB.mam_tails_list[mtpath] if(istype(instance, /datum/sprite_accessory)) var/datum/sprite_accessory/S = instance if(intendedspecies && S.recommended_species && !S.recommended_species.Find(intendedspecies)) @@ -120,7 +120,7 @@ snowflake_markings_list[S.name] = mmpath var/list/snowflake_ears_list = list() for(var/mepath in GLOB.mam_ears_list) - var/datum/sprite_accessory/mam_ears/instance = GLOB.mam_ears_list[mepath] + var/datum/sprite_accessory/ears/mam_ears/instance = GLOB.mam_ears_list[mepath] if(istype(instance, /datum/sprite_accessory)) var/datum/sprite_accessory/S = instance if(intendedspecies && S.recommended_species && !S.recommended_species.Find(intendedspecies)) @@ -129,7 +129,7 @@ snowflake_ears_list[S.name] = mepath var/list/snowflake_mam_snouts_list = list() for(var/mspath in GLOB.mam_snouts_list) - var/datum/sprite_accessory/mam_snouts/instance = GLOB.mam_snouts_list[mspath] + var/datum/sprite_accessory/snouts/mam_snouts/instance = GLOB.mam_snouts_list[mspath] if(istype(instance, /datum/sprite_accessory)) var/datum/sprite_accessory/S = instance if(intendedspecies && S.recommended_species && !S.recommended_species.Find(intendedspecies)) @@ -138,7 +138,7 @@ snowflake_mam_snouts_list[S.name] = mspath var/list/snowflake_ipc_antenna_list = list() for(var/mspath in GLOB.ipc_antennas_list) - var/datum/sprite_accessory/mam_snouts/instance = GLOB.ipc_antennas_list[mspath] + var/datum/sprite_accessory/snouts/mam_snouts/instance = GLOB.ipc_antennas_list[mspath] if(istype(instance, /datum/sprite_accessory)) var/datum/sprite_accessory/S = instance if(intendedspecies && S.recommended_species && !S.recommended_species.Find(intendedspecies)) @@ -264,6 +264,13 @@ if(!findname(.)) break +/proc/random_unique_ethereal_name(attempts_to_find_unique_name=10) + for(var/i in 1 to attempts_to_find_unique_name) + . = capitalize(ethereal_name()) + + if(!findname(.)) + break + /proc/random_unique_moth_name(attempts_to_find_unique_name=10) for(var/i in 1 to attempts_to_find_unique_name) . = capitalize(pick(GLOB.moth_first)) + " " + capitalize(pick(GLOB.moth_last)) diff --git a/code/__HELPERS/names.dm b/code/__HELPERS/names.dm index 8b699e3eee..e1848b21a2 100644 --- a/code/__HELPERS/names.dm +++ b/code/__HELPERS/names.dm @@ -4,6 +4,12 @@ else return "[pick(GLOB.lizard_names_female)]-[pick(GLOB.lizard_names_female)]" +/proc/ethereal_name() + var/tempname = "[pick(GLOB.ethereal_names)] [random_capital_letter()]" + if(prob(65)) + tempname += random_capital_letter() + return tempname + /proc/plasmaman_name() return "[pick(GLOB.plasmaman_names)] \Roman[rand(1,99)]" diff --git a/code/__HELPERS/text.dm b/code/__HELPERS/text.dm index 6dfb685331..7c251edd88 100644 --- a/code/__HELPERS/text.dm +++ b/code/__HELPERS/text.dm @@ -776,6 +776,10 @@ GLOBAL_LIST_INIT(binary, list("0","1")) else return "[number]\th" + +/proc/random_capital_letter() + return uppertext(pick(GLOB.alphabet)) + /proc/unintelligize(message) var/regex/word_boundaries = regex(@"\b[\S]+\b", "g") var/prefix = message[1] diff --git a/code/_compile_options.dm b/code/_compile_options.dm index 9a36c626ba..0e0bd4ffaa 100644 --- a/code/_compile_options.dm +++ b/code/_compile_options.dm @@ -11,15 +11,28 @@ #ifdef TESTING #define DATUMVAR_DEBUGGING_MODE -//#define GC_FAILURE_HARD_LOOKUP //makes paths that fail to GC call find_references before del'ing. - //implies FIND_REF_NO_CHECK_TICK +/* +* Enables extools-powered reference tracking system, letting you see what is referencing objects that refuse to hard delete. +* +* * Requires TESTING to be defined to work. +*/ +//#define REFERENCE_TRACKING -//#define FIND_REF_NO_CHECK_TICK //Sets world.loop_checks to false and prevents find references from sleeping +///Method of tracking references without using extools. Slower, kept to avoid over-reliance on extools. +//#define LEGACY_REFERENCE_TRACKING +#ifdef LEGACY_REFERENCE_TRACKING +///Use the legacy reference on things hard deleting by default. +//#define GC_FAILURE_HARD_LOOKUP +#ifdef GC_FAILURE_HARD_LOOKUP +#define FIND_REF_NO_CHECK_TICK +#endif //ifdef GC_FAILURE_HARD_LOOKUP + +#endif //ifdef LEGACY_REFERENCE_TRACKING //#define VISUALIZE_ACTIVE_TURFS //Highlights atmos active turfs in green -#endif +#endif //ifdef TESTING //#define UNIT_TESTS //Enables unit tests via TEST_RUN_PARAMETER #ifndef PRELOAD_RSC //set to: diff --git a/code/_globalvars/game_modes.dm b/code/_globalvars/game_modes.dm index 01a34c2ab7..960e1f8d59 100644 --- a/code/_globalvars/game_modes.dm +++ b/code/_globalvars/game_modes.dm @@ -9,4 +9,8 @@ GLOBAL_DATUM(start_state, /datum/station_state) // Used in round-end report //TODO clear this one up too -GLOBAL_DATUM(cult_narsie, /obj/singularity/narsie/large/cult) \ No newline at end of file +GLOBAL_DATUM(cult_narsie, /obj/singularity/narsie/large/cult) + + +///We want reality_smash_tracker to exist only once and be accesable from anywhere. +GLOBAL_DATUM_INIT(reality_smash_track, /datum/reality_smash_tracker, new) diff --git a/code/_globalvars/lists/flavor_misc.dm b/code/_globalvars/lists/flavor_misc.dm index a25381f266..8225725ffd 100644 --- a/code/_globalvars/lists/flavor_misc.dm +++ b/code/_globalvars/lists/flavor_misc.dm @@ -40,6 +40,46 @@ GLOBAL_LIST_EMPTY(insect_fluffs_list) GLOBAL_LIST_EMPTY(insect_markings_list) GLOBAL_LIST_EMPTY(caps_list) +//a way to index the right bodypart list given the type of bodypart +GLOBAL_LIST_INIT(mutant_reference_list, list( + "tail_lizard" = GLOB.tails_list_lizard, + "waggingtail_lizard" = GLOB.animated_tails_list_lizard, + "tail_human" = GLOB.tails_list_human, + "waggingtail_human" = GLOB.animated_tails_list_human, + "spines" = GLOB.spines_list, + "waggingspines" = GLOB.animated_spines_list, + "snout" = GLOB.snouts_list, + "frills" = GLOB.frills_list, + "horns" = GLOB.horns_list, + "ears" = GLOB.ears_list, + "body_markings" = GLOB.body_markings_list, + "wings" = GLOB.wings_list, + "wingsopen" = GLOB.wings_open_list, + "deco_wings" = GLOB.deco_wings_list, + "legs" = GLOB.legs_list, + "insect_wings" = GLOB.insect_wings_list, + "insect_fluff" = GLOB.insect_fluffs_list, + "insect_markings" = GLOB.insect_markings_list, + "caps" = GLOB.caps_list, + "ipc_screen" = GLOB.ipc_screens_list, + "ipc_antenna" = GLOB.ipc_antennas_list, + "mam_tail" = GLOB.mam_tails_list, + "mam_waggingtail" = GLOB.mam_tails_animated_list, + "mam_body_markings" = GLOB.mam_body_markings_list, + "mam_ears" = GLOB.mam_ears_list, + "mam_snouts" = GLOB.mam_snouts_list, + "taur" = GLOB.taur_list, + "xenodorsal" = GLOB.xeno_dorsal_list, + "xenohead" = GLOB.xeno_head_list, + "xenotail" = GLOB.xeno_tail_list)) + +//references wag types to regular types, wings open to wings, etc +GLOBAL_LIST_INIT(mutant_transform_list, list("wingsopen" = "wings", + "waggingtail_human" = "tail_human", + "waggingtail_lizard" = "tail_lizard", + "waggingspines" = "spines", + "mam_waggingtail" = "mam_tail")) + GLOBAL_LIST_INIT(ghost_forms_with_directions_list, list("ghost")) //stores the ghost forms that support directional sprites GLOBAL_LIST_INIT(ghost_forms_with_accessories_list, list("ghost")) //stores the ghost forms that support hair and other such things @@ -231,4 +271,10 @@ GLOBAL_LIST_INIT(speech_verbs, list("default","says","gibbers", "states", "chitt GLOBAL_LIST_INIT(roundstart_tongues, list("default","human tongue" = /obj/item/organ/tongue, "lizard tongue" = /obj/item/organ/tongue/lizard, "skeleton tongue" = /obj/item/organ/tongue/bone, "fly tongue" = /obj/item/organ/tongue/fly, "ipc tongue" = /obj/item/organ/tongue/robot/ipc)) - +//locked parts are those that your picked species requires to have +//unlocked parts are those that anyone can choose on customisation regardless +//parts not in unlocked, but in all, are thus locked +GLOBAL_LIST_INIT(all_mutant_parts, list("tail_lizard" = "Tail", "mam_tail" = "Tail", "tail_human" = "Tail", "snout" = "Snout", "frills" = "Frills", "spines" = "Spines", "body_markings" = "Body Markings", "mam_body_markings" = "Species Markings" , "mam_ears" = "Ears", "ears" = "Ears", "mam_snouts" = "Snout", "legs" = "Legs", "deco_wings" = "Decorative Wings", "insect_wings" = "Insect Wings", "insect_fluff" = "Insect Fluff", "taur" = "Tauric Body", "insect_markings" = "Insect Markings", "wings" = "Wings", "xenohead" = "Caste Head", "xenotail" = "Tail", "xenodorsal" = "Dorsal Spines", "ipc_screen" = "Screen", "ipc_antenna" = "Antenna", "meat_type" = "Meat Type", "horns" = "Horns")) +GLOBAL_LIST_INIT(unlocked_mutant_parts, list("horns", "insect_fluff")) +//parts in either of the above two lists that require a second option that allows them to be coloured +GLOBAL_LIST_INIT(colored_mutant_parts, list("insect_wings" = "wings_color", "deco_wings" = "wings_color", "horns" = "horns_color")) diff --git a/code/_globalvars/lists/loadout_categories.dm b/code/_globalvars/lists/loadout_categories.dm index 2a44bf60f4..0f0ac52214 100644 --- a/code/_globalvars/lists/loadout_categories.dm +++ b/code/_globalvars/lists/loadout_categories.dm @@ -1,13 +1,13 @@ GLOBAL_LIST_INIT(loadout_categories, list( - CATEGORY_BACKPACK = list(SUBCATEGORY_BACKPACK_GENERAL, SUBCATEGORY_BACKPACK_TOYS), - CATEGORY_NECK = list(SUBCATEGORY_NECK_GENERAL, SUBCATEGORY_NECK_TIE, SUBCATEGORY_NECK_SCARVES), - CATEGORY_MASK = NOSUBCATEGORY, - CATEGORY_HANDS = NOSUBCATEGORY, - CATEGORY_UNIFORM = list(SUBCATEGORY_UNIFORM_GENERAL, SUBCATEGORY_UNIFORM_JOBS, SUBCATEGORY_UNIFORM_SUITS, SUBCATEGORY_UNIFORM_SKIRTS, SUBCATEGORY_UNIFORM_DRESSES, SUBCATEGORY_UNIFORM_SWEATERS, SUBCATEGORY_UNIFORM_PANTS, SUBCATEGORY_UNIFORM_SHORTS), - CATEGORY_SUIT = list(SUBCATEGORY_SUIT_GENERAL, SUBCATEGORY_SUIT_COATS, SUBCATEGORY_SUIT_JACKETS, SUBCATEGORY_SUIT_JOBS), - CATEGORY_HEAD = list(SUBCATEGORY_HEAD_GENERAL, SUBCATEGORY_HEAD_JOBS), - CATEGORY_SHOES = NOSUBCATEGORY, - CATEGORY_GLOVES = NOSUBCATEGORY, - CATEGORY_GLASSES = NOSUBCATEGORY, - CATEGORY_DONATOR = NOSUBCATEGORY + LOADOUT_CATEGORY_BACKPACK = list(LOADOUT_SUBCATEGORY_BACKPACK_GENERAL, LOADOUT_SUBCATEGORY_BACKPACK_TOYS), + LOADOUT_CATEGORY_NECK = list(LOADOUT_SUBCATEGORY_NECK_GENERAL, LOADOUT_SUBCATEGORY_NECK_TIE, LOADOUT_SUBCATEGORY_NECK_SCARVES), + LOADOUT_CATEGORY_MASK = LOADOUT_SUBCATEGORIES_NONE, + LOADOUT_CATEGORY_HANDS = LOADOUT_SUBCATEGORIES_NONE, + LOADOUT_CATEGORY_UNIFORM = list(LOADOUT_SUBCATEGORY_UNIFORM_GENERAL, LOADOUT_SUBCATEGORY_UNIFORM_JOBS, LOADOUT_SUBCATEGORY_UNIFORM_SUITS, LOADOUT_SUBCATEGORY_UNIFORM_SKIRTS, LOADOUT_SUBCATEGORY_UNIFORM_DRESSES, LOADOUT_SUBCATEGORY_UNIFORM_SWEATERS, LOADOUT_SUBCATEGORY_UNIFORM_PANTS, LOADOUT_SUBCATEGORY_UNIFORM_SHORTS), + LOADOUT_CATEGORY_SUIT = list(LOADOUT_SUBCATEGORY_SUIT_GENERAL, LOADOUT_SUBCATEGORY_SUIT_COATS, LOADOUT_SUBCATEGORY_SUIT_JACKETS, LOADOUT_SUBCATEGORY_SUIT_JOBS), + LOADOUT_CATEGORY_HEAD = list(LOADOUT_SUBCATEGORY_HEAD_GENERAL, LOADOUT_SUBCATEGORY_HEAD_JOBS), + LOADOUT_CATEGORY_SHOES = LOADOUT_SUBCATEGORIES_NONE, + LOADOUT_CATEGORY_GLOVES = LOADOUT_SUBCATEGORIES_NONE, + LOADOUT_CATEGORY_GLASSES = LOADOUT_SUBCATEGORIES_NONE, + LOADOUT_CATEGORY_DONATOR = LOADOUT_SUBCATEGORIES_NONE )) diff --git a/code/_globalvars/lists/names.dm b/code/_globalvars/lists/names.dm index e334d08040..b80fcf0bbf 100644 --- a/code/_globalvars/lists/names.dm +++ b/code/_globalvars/lists/names.dm @@ -17,6 +17,7 @@ GLOBAL_LIST_INIT(golem_names, world.file2list("strings/names/golem.txt")) GLOBAL_LIST_INIT(moth_first, world.file2list("strings/names/moth_first.txt")) GLOBAL_LIST_INIT(moth_last, world.file2list("strings/names/moth_last.txt")) GLOBAL_LIST_INIT(plasmaman_names, world.file2list("strings/names/plasmaman.txt")) +GLOBAL_LIST_INIT(ethereal_names, world.file2list("strings/names/ethereal.txt")) GLOBAL_LIST_INIT(posibrain_names, world.file2list("strings/names/posibrain.txt")) GLOBAL_LIST_INIT(nightmare_names, world.file2list("strings/names/nightmare.txt")) GLOBAL_LIST_INIT(megacarp_first_names, world.file2list("strings/names/megacarp1.txt")) diff --git a/code/_globalvars/traits.dm b/code/_globalvars/traits.dm index 8d8b8820b2..605b20a4f3 100644 --- a/code/_globalvars/traits.dm +++ b/code/_globalvars/traits.dm @@ -37,7 +37,9 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_RESISTCOLD" = TRAIT_RESISTCOLD, "TRAIT_RESISTHIGHPRESSURE" = TRAIT_RESISTHIGHPRESSURE, "TRAIT_RESISTLOWPRESSURE" = TRAIT_RESISTLOWPRESSURE, + "TRAIT_BOMBIMMUNE" = TRAIT_BOMBIMMUNE, "TRAIT_RADIMMUNE" = TRAIT_RADIMMUNE, + "TRAIT_GENELESS" = TRAIT_GENELESS, "TRAIT_VIRUSIMMUNE" = TRAIT_VIRUSIMMUNE, "TRAIT_PIERCEIMMUNE" = TRAIT_PIERCEIMMUNE, "TRAIT_NODISMEMBER" = TRAIT_NODISMEMBER, diff --git a/code/_onclick/hud/alert.dm b/code/_onclick/hud/alert.dm index 8111680c41..6dc1433bc8 100644 --- a/code/_onclick/hud/alert.dm +++ b/code/_onclick/hud/alert.dm @@ -493,6 +493,16 @@ Recharging stations are available in robotics, the dormitory bathrooms, and the desc = "Unit's power cell is running low. Recharging stations are available in robotics, the dormitory bathrooms, and the AI satellite." icon_state = "lowcell" +/obj/screen/alert/etherealcharge + name = "Low Blood Charge" + desc = "Your blood's electric charge is running low, find a source of charge for your blood. Use a recharging station found in robotics or the dormitory bathrooms, or eat some Ethereal-friendly food." + icon_state = "etherealcharge" + +/obj/screen/alert/ethereal_overcharge + name = "Blood Overcharge" + desc = "Your blood's electric charge is becoming dangerously high, find an outlet for your energy. Use Grab Intent on an APC to channel your energy into it." + icon_state = "ethereal_overcharge" + //Need to cover all use cases - emag, illegal upgrade module, malf AI hack, traitor cyborg /obj/screen/alert/hacked name = "Hacked" diff --git a/code/_onclick/hud/screen_objects/storage.dm b/code/_onclick/hud/screen_objects/storage.dm index ce7bc96c96..72b2d035a3 100644 --- a/code/_onclick/hud/screen_objects/storage.dm +++ b/code/_onclick/hud/screen_objects/storage.dm @@ -122,13 +122,13 @@ if(pixel_size == pixels) return pixel_size = pixels - cut_overlays(TRUE) + cut_overlays() //our icon size is 32 pixels. transform = matrix((pixels - (VOLUMETRIC_STORAGE_BOX_BORDER_SIZE * 2)) / VOLUMETRIC_STORAGE_BOX_ICON_SIZE, 0, 0, 0, 1, 0) left.pixel_x = -((pixels - VOLUMETRIC_STORAGE_BOX_ICON_SIZE) * 0.5) - VOLUMETRIC_STORAGE_BOX_BORDER_SIZE right.pixel_x = ((pixels - VOLUMETRIC_STORAGE_BOX_ICON_SIZE) * 0.5) + VOLUMETRIC_STORAGE_BOX_BORDER_SIZE - add_overlay(left, TRUE) - add_overlay(right, TRUE) + add_overlay(left) + add_overlay(right) /obj/screen/storage/volumetric_edge layer = VOLUMETRIC_STORAGE_BOX_LAYER diff --git a/code/controllers/configuration/entries/game_options.dm b/code/controllers/configuration/entries/game_options.dm index 5765f291e9..2e3cb1ea46 100644 --- a/code/controllers/configuration/entries/game_options.dm +++ b/code/controllers/configuration/entries/game_options.dm @@ -98,6 +98,11 @@ config_entry_value = 6 min_val = 1 +/datum/config_entry/number/ecult_scaling_coeff //how much does the amount of players get divided by to determine e_cult + config_entry_value = 6 + integer = FALSE + min_val = 1 + /datum/config_entry/number/security_scaling_coeff //how much does the amount of players get divided by to determine open security officer positions config_entry_value = 8 min_val = 1 @@ -529,4 +534,4 @@ config_entry_value = 6 /datum/config_entry/number/max_shuttle_size - config_entry_value = 250 + config_entry_value = 500 diff --git a/code/controllers/subsystem/acid.dm b/code/controllers/subsystem/acid.dm index e3c415960b..7c9e7634ab 100644 --- a/code/controllers/subsystem/acid.dm +++ b/code/controllers/subsystem/acid.dm @@ -29,7 +29,7 @@ SUBSYSTEM_DEF(acid) if(O.acid_level && O.acid_processing()) else - O.cut_overlay(GLOB.acid_overlay, TRUE) + O.update_icon() processing -= O if (MC_TICK_CHECK) diff --git a/code/controllers/subsystem/fluid.dm b/code/controllers/subsystem/fluid.dm new file mode 100644 index 0000000000..c4fa13d693 --- /dev/null +++ b/code/controllers/subsystem/fluid.dm @@ -0,0 +1,5 @@ +PROCESSING_SUBSYSTEM_DEF(fluids) + name = "Fluids" + wait = 20 + stat_tag = "FD" //its actually Fluid Ducts + flags = SS_NO_INIT | SS_TICKER diff --git a/code/controllers/subsystem/garbage.dm b/code/controllers/subsystem/garbage.dm index 8a1c08bc35..b46e22c1fa 100644 --- a/code/controllers/subsystem/garbage.dm +++ b/code/controllers/subsystem/garbage.dm @@ -25,7 +25,7 @@ SUBSYSTEM_DEF(garbage) //Queue var/list/queues - #ifdef TESTING + #ifdef LEGACY_REFERENCE_TRACKING var/list/reference_find_on_fail = list() var/list/reference_find_on_fail_types = list() #endif @@ -134,7 +134,7 @@ SUBSYSTEM_DEF(garbage) ++gcedlasttick ++totalgcs pass_counts[level]++ - #ifdef TESTING + #ifdef LEGACY_REFERENCE_TRACKING reference_find_on_fail -= refID //It's deleted we don't care anymore. #endif if (MC_TICK_CHECK) @@ -145,7 +145,9 @@ SUBSYSTEM_DEF(garbage) fail_counts[level]++ switch (level) if (GC_QUEUE_CHECK) - #ifdef TESTING + #ifdef REFERENCE_TRACKING + D.find_references() + #elif defined(LEGACY_REFERENCE_TRACKING) if(reference_find_on_fail[refID]) D.find_references() #ifdef GC_FAILURE_HARD_LOOKUP @@ -156,7 +158,19 @@ SUBSYSTEM_DEF(garbage) #endif var/type = D.type var/datum/qdel_item/I = items[type] + #ifdef TESTING + log_world("## TESTING: GC: -- \ref[D] | [type] was unable to be GC'd --") + for(var/c in GLOB.admins) //Using testing() here would fill the logs with ADMIN_VV garbage + var/client/admin = c + if(!check_rights_for(admin, R_ADMIN)) + continue + to_chat(admin, "## TESTING: GC: -- [ADMIN_VV(D)] | [type] was unable to be GC'd --") testing("GC: -- \ref[src] | [type] was unable to be GC'd --") + #endif + #ifdef REFERENCE_TRACKING + GLOB.deletion_failures += D //It should no longer be bothered by the GC, manual deletion only. + continue + #endif I.failures++ if (GC_QUEUE_HARDDELETE) HardDelete(D) @@ -181,7 +195,7 @@ SUBSYSTEM_DEF(garbage) var/gctime = world.time var/refid = "\ref[D]" -#ifdef TESTING +#ifdef LEGACY_REFERENCE_TRACKING if(reference_find_on_fail_types[D.type]) reference_find_on_fail["\ref[D]"] = TRUE #endif @@ -193,7 +207,7 @@ SUBSYSTEM_DEF(garbage) queue[refid] = gctime -#ifdef TESTING +#ifdef LEGACY_REFERENCE_TRACKING /datum/controller/subsystem/garbage/proc/add_type_to_findref(type) if(!ispath(type)) return "NOT A VAILD PATH" @@ -260,12 +274,6 @@ SUBSYSTEM_DEF(garbage) /datum/qdel_item/New(mytype) name = "[mytype]" -#ifdef TESTING -/proc/qdel_and_find_ref_if_fail(datum/D, force = FALSE) - SSgarbage.reference_find_on_fail["\ref[D]"] = TRUE - qdel(D, force) -#endif - // Should be treated as a replacement for the 'del' keyword. // Datums passed to this will be given a chance to clean up references to allow the GC to collect them. /proc/qdel(datum/D, force=FALSE, ...) @@ -319,16 +327,13 @@ SUBSYSTEM_DEF(garbage) SSgarbage.Queue(D, GC_QUEUE_HARDDELETE) if (QDEL_HINT_HARDDEL_NOW) //qdel should assume this object won't gc, and hard del it post haste. SSgarbage.HardDelete(D) - if (QDEL_HINT_FINDREFERENCE)//qdel will, if TESTING is enabled, display all references to this object, then queue the object for deletion. + #ifdef LEGACY_REFERENCE_TRACKING + if (QDEL_HINT_FINDREFERENCE) //qdel will, if LEGACY_REFERENCE_TRACKING is enabled, display all references to this object, then queue the object for deletion. SSgarbage.Queue(D) - #ifdef TESTING - D.find_references() - #endif if (QDEL_HINT_IFFAIL_FINDREFERENCE) SSgarbage.Queue(D) - #ifdef TESTING SSgarbage.reference_find_on_fail["\ref[D]"] = TRUE - #endif + #endif else #ifdef TESTING if(!I.no_hint) @@ -339,119 +344,6 @@ SUBSYSTEM_DEF(garbage) else if(D.gc_destroyed == GC_CURRENTLY_BEING_QDELETED) CRASH("[D.type] destroy proc was called multiple times, likely due to a qdel loop in the Destroy logic") -#ifdef TESTING - -/datum/verb/find_refs() - set category = "Debug" - set name = "Find References" - set src in world - - find_references(FALSE) - -/datum/proc/find_references(skip_alert) - running_find_references = type - if(usr && usr.client) - if(usr.client.running_find_references) - testing("CANCELLED search for references to a [usr.client.running_find_references].") - usr.client.running_find_references = null - running_find_references = null - //restart the garbage collector - SSgarbage.can_fire = 1 - SSgarbage.next_fire = world.time + world.tick_lag - return - - if(!skip_alert) - if(alert("Running this will lock everything up for about 5 minutes. Would you like to begin the search?", "Find References", "Yes", "No") == "No") - running_find_references = null - return - - //this keeps the garbage collector from failing to collect objects being searched for in here - SSgarbage.can_fire = 0 - - if(usr && usr.client) - usr.client.running_find_references = type - - testing("Beginning search for references to a [type].") - last_find_references = world.time - - DoSearchVar(GLOB) //globals - for(var/datum/thing in world) //atoms (don't beleive it's lies) - DoSearchVar(thing, "World -> [thing]") - - for (var/datum/thing) //datums - DoSearchVar(thing, "World -> [thing]") - - for (var/client/thing) //clients - DoSearchVar(thing, "World -> [thing]") - - testing("Completed search for references to a [type].") - if(usr && usr.client) - usr.client.running_find_references = null - running_find_references = null - - //restart the garbage collector - SSgarbage.can_fire = 1 - SSgarbage.next_fire = world.time + world.tick_lag - -/datum/verb/qdel_then_find_references() - set category = "Debug" - set name = "qdel() then Find References" - set src in world - - qdel(src, TRUE) //Force. - if(!running_find_references) - find_references(TRUE) - -/datum/verb/qdel_then_if_fail_find_references() - set category = "Debug" - set name = "qdel() then Find References if GC failure" - set src in world - - qdel_and_find_ref_if_fail(src, TRUE) - -/datum/proc/DoSearchVar(X, Xname, recursive_limit = 64) - if(usr && usr.client && !usr.client.running_find_references) - return - if (!recursive_limit) - return - - if(istype(X, /datum)) - var/datum/D = X - if(D.last_find_references == last_find_references) - return - - D.last_find_references = last_find_references - var/list/L = D.vars - - for(var/varname in L) - if (varname == "vars") - continue - var/variable = L[varname] - - if(variable == src) - testing("Found [src.type] \ref[src] in [D.type]'s [varname] var. [Xname]") - - else if(islist(variable)) - DoSearchVar(variable, "[Xname] -> list", recursive_limit-1) - - else if(islist(X)) - var/normal = IS_NORMAL_LIST(X) - for(var/I in X) - if (I == src) - testing("Found [src.type] \ref[src] in list [Xname].") - - else if (I && !isnum(I) && normal && X[I] == src) - testing("Found [src.type] \ref[src] in list [Xname]\[[I]\]") - - else if (islist(I)) - DoSearchVar(I, "[Xname] -> list", recursive_limit-1) - -#ifndef FIND_REF_NO_CHECK_TICK - CHECK_TICK -#endif - -#endif - #ifdef TESTING /proc/writeDatumCount() var/list/datums = list() diff --git a/code/controllers/subsystem/mapping.dm b/code/controllers/subsystem/mapping.dm index 97addfa131..617004646a 100644 --- a/code/controllers/subsystem/mapping.dm +++ b/code/controllers/subsystem/mapping.dm @@ -113,7 +113,7 @@ SUBSYSTEM_DEF(mapping) // needs to be whitelisted for underground too so place_below ruins work seedRuins(ice_ruins, CONFIG_GET(number/icemoon_budget), list(/area/icemoon/surface/outdoors/unexplored, /area/icemoon/underground/unexplored), ice_ruins_templates) for (var/ice_z in ice_ruins) - spawn_rivers(ice_z, 4, /turf/open/openspace/icemoon, /area/icemoon/surface/outdoors/unexplored/rivers) + spawn_rivers(ice_z, 4, /turf/open/transparent/openspace/icemoon, /area/icemoon/surface/outdoors/unexplored/rivers) var/list/ice_ruins_underground = levels_by_trait(ZTRAIT_ICE_RUINS_UNDERGROUND) if (ice_ruins_underground.len) diff --git a/code/controllers/subsystem/overlays.dm b/code/controllers/subsystem/overlays.dm index 20eb2af001..ea0f82436c 100644 --- a/code/controllers/subsystem/overlays.dm +++ b/code/controllers/subsystem/overlays.dm @@ -114,67 +114,47 @@ SUBSYSTEM_DEF(overlays) #define NOT_QUEUED_ALREADY (!(flags_1 & OVERLAY_QUEUED_1)) #define QUEUE_FOR_COMPILE flags_1 |= OVERLAY_QUEUED_1; SSoverlays.queue += src; -/atom/proc/cut_overlays(priority = FALSE) - LAZYINITLIST(priority_overlays) +/atom/proc/cut_overlays() LAZYINITLIST(remove_overlays) LAZYINITLIST(add_overlays) remove_overlays = overlays.Copy() add_overlays.Cut() - if(priority) - priority_overlays.Cut() - //If not already queued for work and there are overlays to remove if(NOT_QUEUED_ALREADY && remove_overlays.len) QUEUE_FOR_COMPILE -/atom/proc/cut_overlay(list/overlays, priority) +/atom/proc/cut_overlay(list/overlays) if(!overlays) return overlays = build_appearance_list(overlays) LAZYINITLIST(add_overlays) //always initialized after this point - LAZYINITLIST(priority_overlays) LAZYINITLIST(remove_overlays) var/a_len = add_overlays.len var/r_len = remove_overlays.len - var/p_len = priority_overlays.len remove_overlays += overlays add_overlays -= overlays - - if(priority) - var/list/cached_priority = priority_overlays - LAZYREMOVE(cached_priority, overlays) - var/fa_len = add_overlays.len var/fr_len = remove_overlays.len - var/fp_len = priority_overlays.len //If not already queued and there is work to be done - if(NOT_QUEUED_ALREADY && (fa_len != a_len || fr_len != r_len || fp_len != p_len)) + if(NOT_QUEUED_ALREADY && (fa_len != a_len || fr_len != r_len)) QUEUE_FOR_COMPILE -/atom/proc/add_overlay(list/overlays, priority = FALSE) +/atom/proc/add_overlay(list/overlays) if(!overlays) return overlays = build_appearance_list(overlays) LAZYINITLIST(add_overlays) //always initialized after this point - LAZYINITLIST(priority_overlays) var/a_len = add_overlays.len - var/p_len = priority_overlays.len - if(priority) - priority_overlays += overlays //or in the image. Can we use [image] = image? - var/fp_len = priority_overlays.len - if(NOT_QUEUED_ALREADY && fp_len != p_len) - QUEUE_FOR_COMPILE - else - add_overlays += overlays - var/fa_len = add_overlays.len - if(NOT_QUEUED_ALREADY && fa_len != a_len) - QUEUE_FOR_COMPILE + add_overlays += overlays + var/fa_len = add_overlays.len + if(NOT_QUEUED_ALREADY && fa_len != a_len) + QUEUE_FOR_COMPILE /atom/proc/copy_overlays(atom/other, cut_old) //copys our_overlays from another atom if(!other) diff --git a/code/controllers/subsystem/shuttle.dm b/code/controllers/subsystem/shuttle.dm index 9bda1cd233..c802448536 100644 --- a/code/controllers/subsystem/shuttle.dm +++ b/code/controllers/subsystem/shuttle.dm @@ -775,12 +775,14 @@ SUBSYSTEM_DEF(shuttle) preview_shuttle = null -/datum/controller/subsystem/shuttle/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.admin_state) - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) - if(!ui) - ui = new(user, src, ui_key, "ShuttleManipulator", name, 800, 600, master_ui, state) - ui.open() +/datum/controller/subsystem/shuttle/ui_state(mob/user) + return GLOB.admin_state +/datum/controller/subsystem/shuttle/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "ShuttleManipulator") + ui.open() /datum/controller/subsystem/shuttle/ui_data(mob/user) var/list/data = list() diff --git a/code/controllers/subsystem/tgui.dm b/code/controllers/subsystem/tgui.dm index 58bc28fa2f..a5526d2c03 100644 --- a/code/controllers/subsystem/tgui.dm +++ b/code/controllers/subsystem/tgui.dm @@ -1,3 +1,12 @@ +/** + * tgui subsystem + * + * Contains all tgui state and subsystem code. + * + * Copyright (c) 2020 Aleksej Komarov + * SPDX-License-Identifier: MIT + */ + SUBSYSTEM_DEF(tgui) name = "tgui" wait = 9 @@ -5,33 +14,338 @@ SUBSYSTEM_DEF(tgui) priority = FIRE_PRIORITY_TGUI runlevels = RUNLEVEL_LOBBY | RUNLEVELS_DEFAULT - var/list/currentrun = list() - var/list/open_uis = list() // A list of open UIs, grouped by src_object and ui_key. - var/list/processing_uis = list() // A list of processing UIs, ungrouped. - var/basehtml // The HTML base used for all UIs. + /// A list of UIs scheduled to process + var/list/current_run = list() + /// A list of open UIs + var/list/open_uis = list() + /// A list of open UIs, grouped by src_object. + var/list/open_uis_by_src = list() + /// The HTML base used for all UIs. + var/basehtml /datum/controller/subsystem/tgui/PreInit() - basehtml = file2text('tgui/packages/tgui/public/tgui.html') + basehtml = file2text('tgui/packages/tgui/public/tgui.html') /datum/controller/subsystem/tgui/Shutdown() close_all_uis() /datum/controller/subsystem/tgui/stat_entry() - ..("P:[processing_uis.len]") + ..("P:[open_uis.len]") /datum/controller/subsystem/tgui/fire(resumed = 0) - if (!resumed) - src.currentrun = processing_uis.Copy() - //cache for sanic speed (lists are references anyways) - var/list/currentrun = src.currentrun - - while(currentrun.len) - var/datum/tgui/ui = currentrun[currentrun.len] - currentrun.len-- + if(!resumed) + src.current_run = open_uis.Copy() + // Cache for sanic speed (lists are references anyways) + var/list/current_run = src.current_run + while(current_run.len) + var/datum/tgui/ui = current_run[current_run.len] + current_run.len-- + // TODO: Move user/src_object check to process() if(ui && ui.user && ui.src_object) ui.process() else - processing_uis.Remove(ui) - if (MC_TICK_CHECK) + open_uis.Remove(ui) + if(MC_TICK_CHECK) return +/** + * public + * + * Requests a usable tgui window from the pool. + * Returns null if pool was exhausted. + * + * required user mob + * return datum/tgui + */ +/datum/controller/subsystem/tgui/proc/request_pooled_window(mob/user) + if(!user.client) + return null + var/list/windows = user.client.tgui_windows + var/window_id + var/datum/tgui_window/window + var/window_found = FALSE + // Find a usable window + for(var/i in 1 to TGUI_WINDOW_HARD_LIMIT) + window_id = TGUI_WINDOW_ID(i) + window = windows[window_id] + // As we are looping, create missing window datums + if(!window) + window = new(user.client, window_id, pooled = TRUE) + // Skip windows with acquired locks + if(window.locked) + continue + if(window.status == TGUI_WINDOW_READY) + return window + if(window.status == TGUI_WINDOW_CLOSED) + window.status = TGUI_WINDOW_LOADING + window_found = TRUE + break + if(!window_found) + log_tgui(user, "Error: Pool exhausted") + return null + return window + +/** + * public + * + * Force closes all tgui windows. + * + * required user mob + */ +/datum/controller/subsystem/tgui/proc/force_close_all_windows(mob/user) + log_tgui(user, "force_close_all_windows") + if(user.client) + user.client.tgui_windows = list() + for(var/i in 1 to TGUI_WINDOW_HARD_LIMIT) + var/window_id = TGUI_WINDOW_ID(i) + user << browse(null, "window=[window_id]") + +/** + * public + * + * Force closes the tgui window by window_id. + * + * required user mob + * required window_id string + */ +/datum/controller/subsystem/tgui/proc/force_close_window(mob/user, window_id) + log_tgui(user, "force_close_window") + // Close all tgui datums based on window_id. + for(var/datum/tgui/ui in user.tgui_open_uis) + if(ui.window && ui.window.id == window_id) + ui.close(can_be_suspended = FALSE) + // Unset machine just to be sure. + user.unset_machine() + // Close window directly just to be sure. + user << browse(null, "window=[window_id]") + +/** + * public + * + * Try to find an instance of a UI, and push an update to it. + * + * required user mob The mob who opened/is using the UI. + * required src_object datum The object/datum which owns the UI. + * optional ui datum/tgui The UI to be updated, if it exists. + * optional force_open bool If the UI should be re-opened instead of updated. + * + * return datum/tgui The found UI. + */ +/datum/controller/subsystem/tgui/proc/try_update_ui( + mob/user, + datum/src_object, + datum/tgui/ui) + // Look up a UI if it wasn't passed + if(isnull(ui)) + ui = get_open_ui(user, src_object) + // Couldn't find a UI. + if(isnull(ui)) + return null + ui.process_status() + // UI ended up with the closed status + // or is actively trying to close itself. + // FIXME: Doesn't actually fix the paper bug. + if(ui.status <= UI_CLOSE) + ui.close() + return null + ui.send_update() + return ui + +/** + * public + * + * Get a open UI given a user and src_object. + * + * required user mob The mob who opened/is using the UI. + * required src_object datum The object/datum which owns the UI. + * + * return datum/tgui The found UI. + */ +/datum/controller/subsystem/tgui/proc/get_open_ui(mob/user, datum/src_object) + var/key = "[REF(src_object)]" + // No UIs opened for this src_object + if(isnull(open_uis_by_src[key]) || !istype(open_uis_by_src[key], /list)) + return null + for(var/datum/tgui/ui in open_uis_by_src[key]) + // Make sure we have the right user + if(ui.user == user) + return ui + return null + +/** + * public + * + * Update all UIs attached to src_object. + * + * required src_object datum The object/datum which owns the UIs. + * + * return int The number of UIs updated. + */ +/datum/controller/subsystem/tgui/proc/update_uis(datum/src_object) + var/count = 0 + var/key = "[REF(src_object)]" + // No UIs opened for this src_object + if(isnull(open_uis_by_src[key]) || !istype(open_uis_by_src[key], /list)) + return count + for(var/datum/tgui/ui in open_uis_by_src[key]) + // Check if UI is valid. + if(ui && ui.src_object && ui.user && ui.src_object.ui_host(ui.user)) + ui.process(force = 1) + count++ + return count + +/** + * public + * + * Close all UIs attached to src_object. + * + * required src_object datum The object/datum which owns the UIs. + * + * return int The number of UIs closed. + */ +/datum/controller/subsystem/tgui/proc/close_uis(datum/src_object) + var/count = 0 + var/key = "[REF(src_object)]" + // No UIs opened for this src_object + if(isnull(open_uis_by_src[key]) || !istype(open_uis_by_src[key], /list)) + return count + for(var/datum/tgui/ui in open_uis_by_src[key]) + // Check if UI is valid. + if(ui && ui.src_object && ui.user && ui.src_object.ui_host(ui.user)) + ui.close() + count++ + return count + +/** + * public + * + * Close all UIs regardless of their attachment to src_object. + * + * return int The number of UIs closed. + */ +/datum/controller/subsystem/tgui/proc/close_all_uis() + var/count = 0 + for(var/key in open_uis_by_src) + for(var/datum/tgui/ui in open_uis_by_src[key]) + // Check if UI is valid. + if(ui && ui.src_object && ui.user && ui.src_object.ui_host(ui.user)) + ui.close() + count++ + return count + +/** + * public + * + * Update all UIs belonging to a user. + * + * required user mob The mob who opened/is using the UI. + * optional src_object datum If provided, only update UIs belonging this src_object. + * + * return int The number of UIs updated. + */ +/datum/controller/subsystem/tgui/proc/update_user_uis(mob/user, datum/src_object) + var/count = 0 + if(length(user?.tgui_open_uis) == 0) + return count + for(var/datum/tgui/ui in user.tgui_open_uis) + if(isnull(src_object) || ui.src_object == src_object) + ui.process(force = 1) + count++ + return count + +/** + * public + * + * Close all UIs belonging to a user. + * + * required user mob The mob who opened/is using the UI. + * optional src_object datum If provided, only close UIs belonging this src_object. + * + * return int The number of UIs closed. + */ +/datum/controller/subsystem/tgui/proc/close_user_uis(mob/user, datum/src_object) + var/count = 0 + if(length(user?.tgui_open_uis) == 0) + return count + for(var/datum/tgui/ui in user.tgui_open_uis) + if(isnull(src_object) || ui.src_object == src_object) + ui.close() + count++ + return count + +/** + * private + * + * Add a UI to the list of open UIs. + * + * required ui datum/tgui The UI to be added. + */ +/datum/controller/subsystem/tgui/proc/on_open(datum/tgui/ui) + var/key = "[REF(ui.src_object)]" + if(isnull(open_uis_by_src[key]) || !istype(open_uis_by_src[key], /list)) + open_uis_by_src[key] = list() + ui.user.tgui_open_uis |= ui + var/list/uis = open_uis_by_src[key] + uis |= ui + open_uis |= ui + +/** + * private + * + * Remove a UI from the list of open UIs. + * + * required ui datum/tgui The UI to be removed. + * + * return bool If the UI was removed or not. + */ +/datum/controller/subsystem/tgui/proc/on_close(datum/tgui/ui) + var/key = "[REF(ui.src_object)]" + if(isnull(open_uis_by_src[key]) || !istype(open_uis_by_src[key], /list)) + return FALSE + // Remove it from the list of processing UIs. + open_uis.Remove(ui) + // If the user exists, remove it from them too. + if(ui.user) + ui.user.tgui_open_uis.Remove(ui) + var/list/uis = open_uis_by_src[key] + uis.Remove(ui) + if(length(uis) == 0) + open_uis_by_src.Remove(key) + return TRUE + +/** + * private + * + * Handle client logout, by closing all their UIs. + * + * required user mob The mob which logged out. + * + * return int The number of UIs closed. + */ +/datum/controller/subsystem/tgui/proc/on_logout(mob/user) + close_user_uis(user) + +/** + * private + * + * Handle clients switching mobs, by transferring their UIs. + * + * required user source The client's original mob. + * required user target The client's new mob. + * + * return bool If the UIs were transferred. + */ +/datum/controller/subsystem/tgui/proc/on_transfer(mob/source, mob/target) + // The old mob had no open UIs. + if(length(source?.tgui_open_uis) == 0) + return FALSE + if(isnull(target.tgui_open_uis) || !istype(target.tgui_open_uis, /list)) + target.tgui_open_uis = list() + // Transfer all the UIs. + for(var/datum/tgui/ui in source.tgui_open_uis) + // Inform the UIs of their new owner. + ui.user = target + target.tgui_open_uis.Add(ui) + // Clear the old list. + source.tgui_open_uis.Cut() + return TRUE diff --git a/code/datums/action.dm b/code/datums/action.dm index 0033df09d7..fbf7487e4d 100644 --- a/code/datums/action.dm +++ b/code/datums/action.dm @@ -157,7 +157,7 @@ /datum/action/proc/ApplyIcon(obj/screen/movable/action_button/current_button, force = FALSE) if(icon_icon && button_icon_state && ((current_button.button_icon_state != button_icon_state) || force)) - current_button.cut_overlays(TRUE) + current_button.cut_overlays() current_button.add_overlay(mutable_appearance(icon_icon, button_icon_state)) current_button.button_icon_state = button_icon_state diff --git a/code/datums/ai_laws.dm b/code/datums/ai_laws.dm index 9c6bb2ebfd..15115b62c0 100644 --- a/code/datums/ai_laws.dm +++ b/code/datums/ai_laws.dm @@ -431,25 +431,31 @@ if(!owner) owner = M -/datum/ai_laws/proc/get_law_list(include_zeroth = 0, show_numbers = 1) +/** + * Generates a list of all laws on this datum, including rendered HTML tags if required + * + * Arguments: + * * include_zeroth - Operator that controls if law 0 or law 666 is returned in the set + * * show_numbers - Operator that controls if law numbers are prepended to the returned laws + * * render_html - Operator controlling if HTML tags are rendered on the returned laws + */ +/datum/ai_laws/proc/get_law_list(include_zeroth = FALSE, show_numbers = TRUE, render_html = TRUE) var/list/data = list() - if (include_zeroth && devillaws && devillaws.len) - for(var/i in devillaws) - data += "[show_numbers ? "666:" : ""] [i]" + if (include_zeroth && devillaws) + for(var/law in devillaws) + data += "[show_numbers ? "666:" : ""] [render_html ? "[law]" : law]" if (include_zeroth && zeroth) - data += "[show_numbers ? "0:" : ""] [zeroth]" + data += "[show_numbers ? "0:" : ""] [render_html ? "[zeroth]" : zeroth]" for(var/law in hacked) if (length(law) > 0) - var/num = ionnum() - data += "[show_numbers ? "[num]:" : ""] [law]" + data += "[show_numbers ? "[ionnum()]:" : ""] [render_html ? "[law]" : law]" for(var/law in ion) if (length(law) > 0) - var/num = ionnum() - data += "[show_numbers ? "[num]:" : ""] [law]" + data += "[show_numbers ? "[ionnum()]:" : ""] [render_html ? "[law]" : law]" var/number = 1 for(var/law in inherent) @@ -459,6 +465,7 @@ for(var/law in supplied) if (length(law) > 0) - data += "[show_numbers ? "[number]:" : ""] [law]" + data += "[show_numbers ? "[number]:" : ""] [render_html ? "[law]" : law]" number++ return data + diff --git a/code/datums/components/crafting/crafting.dm b/code/datums/components/crafting/crafting.dm index b9a1b5ec3b..1a9f4c0512 100644 --- a/code/datums/components/crafting/crafting.dm +++ b/code/datums/components/crafting/crafting.dm @@ -203,9 +203,9 @@ Set var amt to the value current cycle req is pointing to, its amount of type we need to delete Get var/surroundings list of things accessable to crafting by get_environment() Check the type of the current cycle req - If its reagent then do a while loop, inside it try to locate() reagent containers, inside such containers try to locate needed reagent, if there isnt remove thing from surroundings + If its reagent then do a while loop, inside it try to locate() reagent containers, inside such containers try to locate needed reagent, if there isn't remove thing from surroundings If there is enough reagent in the search result then delete the needed amount, create the same type of reagent with the same data var and put it into deletion list - If there isnt enough take all of that reagent from the container, put into deletion list, substract the amt var by the volume of reagent, remove the container from surroundings list and keep searching + If there isn't enough take all of that reagent from the container, put into deletion list, substract the amt var by the volume of reagent, remove the container from surroundings list and keep searching While doing above stuff check deletion list if it already has such reagnet, if yes merge instead of adding second one If its stack check if it has enough amount If yes create new stack with the needed amount and put in into deletion list, substract taken amount from the stack @@ -216,7 +216,7 @@ Then do a loop over parts var of the recipe Do similar stuff to what we have done above, but now in deletion list, until the parts conditions are satisfied keep taking from the deletion list and putting it into parts list for return - After its done loop over deletion list and delete all the shit that wasnt taken by parts loop + After its done loop over deletion list and delete all the shit that wasn't taken by parts loop del_reqs return the list of parts resulting object will receive as argument of CheckParts proc, on the atom level it will add them all to the contents, on all other levels it calls ..() and does whatever is needed afterwards but from contents list already */ @@ -323,9 +323,12 @@ if(user == parent) ui_interact(user) +/datum/component/personal_crafting/ui_state(mob/user) + return GLOB.not_incapacitated_turf_state + //For the UI related things we're going to assume the user is a mob rather than typesetting it to an atom as the UI isn't generated if the parent is an atom -/datum/component/personal_crafting/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.not_incapacitated_turf_state) - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) +/datum/component/personal_crafting/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) if(!ui) cur_category = categories[1] if(islist(categories[cur_category])) @@ -333,7 +336,7 @@ cur_subcategory = subcats[1] else cur_subcategory = CAT_NONE - ui = new(user, src, ui_key, "PersonalCrafting", "Crafting Menu", 700, 800, master_ui, state) + ui = new(user, src, "PersonalCrafting") ui.open() /datum/component/personal_crafting/ui_data(mob/user) @@ -413,13 +416,8 @@ display_compact = !display_compact . = TRUE if("set_category") - if(!isnull(params["category"])) - cur_category = params["category"] - if(!isnull(params["subcategory"])) - if(params["subcategory"] == "0") - cur_subcategory = "" - else - cur_subcategory = params["subcategory"] + cur_category = params["category"] + cur_subcategory = params["subcategory"] || "" . = TRUE /datum/component/personal_crafting/proc/build_recipe_data(datum/crafting_recipe/R) diff --git a/code/datums/components/crafting/recipes/recipes_clothing.dm b/code/datums/components/crafting/recipes/recipes_clothing.dm index 2a24c0b451..717e99e8b2 100644 --- a/code/datums/components/crafting/recipes/recipes_clothing.dm +++ b/code/datums/components/crafting/recipes/recipes_clothing.dm @@ -40,13 +40,23 @@ reqs = list(/obj/item/paper = 20) category = CAT_CLOTHING +/datum/crafting_recipe/balaclavabreath + name = "Breathaclava" + result = /obj/item/clothing/mask/balaclava/breath + time = 10 + reqs = list(/obj/item/clothing/mask/balaclava = 1, + /obj/item/clothing/mask/breath = 1) + category = CAT_CLOTHING + + + /datum/crafting_recipe/armwraps name = "Armwraps" result = /obj/item/clothing/gloves/fingerless/pugilist time = 60 tools = list(TOOL_WIRECUTTER) reqs = list(/obj/item/stack/sheet/cloth = 4, - /obj/item/stack/sheet/durathread = 2, + /obj/item/stack/sticky_tape = 2, /obj/item/stack/sheet/leather = 2) category = CAT_CLOTHING diff --git a/code/datums/components/crafting/recipes/recipes_misc.dm b/code/datums/components/crafting/recipes/recipes_misc.dm index 214c1b1427..f113be728d 100644 --- a/code/datums/components/crafting/recipes/recipes_misc.dm +++ b/code/datums/components/crafting/recipes/recipes_misc.dm @@ -2,6 +2,15 @@ //Large Objects// ///////////////// +/datum/crafting_recipe/plunger + name = "Plunger" + result = /obj/item/plunger + time = 1 + reqs = list(/obj/item/stack/sheet/plastic = 1, + /obj/item/stack/sheet/mineral/wood = 1) + category = CAT_MISC + subcategory = CAT_TOOL + /datum/crafting_recipe/showercurtain name = "Shower Curtains" reqs = list(/obj/item/stack/sheet/cloth = 2, @@ -126,7 +135,7 @@ /datum/crafting_recipe/brute_pack name = "Suture Pack" - result = /obj/item/stack/medical/suture/one + result = /obj/item/stack/medical/suture/five time = 1 reqs = list(/obj/item/stack/medical/gauze = 1, /datum/reagent/medicine/styptic_powder = 10) @@ -135,7 +144,7 @@ /datum/crafting_recipe/burn_pack name = "Regenerative Mesh" - result = /obj/item/stack/medical/mesh/one + result = /obj/item/stack/medical/mesh/five time = 1 reqs = list(/obj/item/stack/medical/gauze = 1, /datum/reagent/medicine/silver_sulfadiazine = 10) @@ -188,7 +197,7 @@ result = /obj/item/screwdriver/bronze reqs = list(/obj/item/screwdriver = 1, /obj/item/stack/cable_coil = 10, - /obj/item/stack/tile/bronze = 1, + /obj/item/stack/sheet/bronze = 1, /datum/reagent/water = 15) time = 40 subcategory = CAT_TOOL @@ -200,7 +209,7 @@ result = /obj/item/weldingtool/bronze reqs = list(/obj/item/weldingtool = 1, /obj/item/stack/cable_coil = 10, - /obj/item/stack/tile/bronze = 1, + /obj/item/stack/sheet/bronze = 1, /datum/reagent/water = 15) time = 40 subcategory = CAT_TOOL @@ -212,7 +221,7 @@ result = /obj/item/wirecutters/bronze reqs = list(/obj/item/wirecutters = 1, /obj/item/stack/cable_coil = 10, - /obj/item/stack/tile/bronze = 1, + /obj/item/stack/sheet/bronze = 1, /datum/reagent/water = 15) time = 40 subcategory = CAT_TOOL @@ -224,7 +233,7 @@ result = /obj/item/crowbar/bronze reqs = list(/obj/item/crowbar = 1, /obj/item/stack/cable_coil = 10, - /obj/item/stack/tile/bronze = 1, + /obj/item/stack/sheet/bronze = 1, /datum/reagent/water = 15) time = 40 subcategory = CAT_TOOL @@ -236,7 +245,7 @@ result = /obj/item/wrench/bronze reqs = list(/obj/item/wrench = 1, /obj/item/stack/cable_coil = 10, - /obj/item/stack/tile/bronze = 1, + /obj/item/stack/sheet/bronze = 1, /datum/reagent/water = 15) time = 40 subcategory = CAT_TOOL @@ -269,6 +278,19 @@ subcategory = CAT_TOOL category = CAT_MISC +/datum/crafting_recipe/heretic/codex + name = "Codex Cicatrix" + result = /obj/item/forbidden_book + tools = list(/obj/item/pen) + reqs = list(/obj/item/paper = 5, + /obj/item/organ/eyes = 1, + /obj/item/organ/heart = 1, + /obj/item/stack/sheet/animalhide/human = 1) + time = 150 + subcategory = CAT_MISCELLANEOUS + category = CAT_MISC + always_availible = FALSE + //////////// //Vehicles// //////////// @@ -324,7 +346,7 @@ result = /obj/item/toy/sword/cx subcategory = CAT_MISCELLANEOUS category = CAT_MISC - + /datum/crafting_recipe/catgirlplushie name = "Catgirl Plushie" reqs = list(/obj/item/toy/plush/hairball = 3) diff --git a/code/datums/components/embedded.dm b/code/datums/components/embedded.dm index 51098756d3..8c4e62979b 100644 --- a/code/datums/components/embedded.dm +++ b/code/datums/components/embedded.dm @@ -119,7 +119,7 @@ UnregisterSignal(weapon, list(COMSIG_MOVABLE_MOVED, COMSIG_PARENT_QDELETING)) if(overlay) var/atom/A = parent - A.cut_overlay(overlay, TRUE) + UnregisterSignal(A,COMSIG_ATOM_UPDATE_OVERLAYS) qdel(overlay) return ..() @@ -326,7 +326,8 @@ var/matrix/M = matrix() M.Translate(pixelX, pixelY) overlay.transform = M - hit.add_overlay(overlay, TRUE) + RegisterSignal(hit,COMSIG_ATOM_UPDATE_OVERLAYS,.proc/apply_overlay) + hit.update_icon() if(harmful) hit.visible_message("[weapon] embeds itself in [hit]!") @@ -339,6 +340,8 @@ else hit.visible_message("[weapon] sticks itself to [hit]!") +/datum/component/embedded/proc/apply_overlay(atom/source, list/overlay_list) + overlay_list += overlay /datum/component/embedded/proc/examineTurf(datum/source, mob/user, list/examine_list) if(harmful) diff --git a/code/datums/components/gps.dm b/code/datums/components/gps.dm index 200ec2b956..c2b3ad1f30 100644 --- a/code/datums/components/gps.dm +++ b/code/datums/components/gps.dm @@ -80,19 +80,15 @@ GLOBAL_LIST_EMPTY(GPS_list) to_chat(user, "[parent] is now tracking, and visible to other GPS devices.") tracking = TRUE -/datum/component/gps/item/ui_interact(mob/user, ui_key = "gps", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) // Remember to use the appropriate state. +/datum/component/gps/item/ui_interact(mob/user, datum/tgui/ui) if(emped) to_chat(user, "[parent] fizzles weakly.") return - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) + ui = SStgui.try_update_ui(user, src, ui) if(!ui) - // Variable window height, depending on how many GPS units there are - // to show, clamped to relatively safe range. - var/gps_window_height = clamp(325 + GLOB.GPS_list.len * 14, 325, 700) - ui = new(user, src, ui_key, "Gps", "Global Positioning System", 470, gps_window_height, master_ui, state) //width, height + ui = new(user, src, "Gps") ui.open() - - ui.set_autoupdate(state = updating) + ui.set_autoupdate(updating) /datum/component/gps/item/ui_data(mob/user) var/list/data = list() diff --git a/code/datums/components/mood.dm b/code/datums/components/mood.dm index 90fea9ec8a..87bc681651 100644 --- a/code/datums/components/mood.dm +++ b/code/datums/components/mood.dm @@ -307,6 +307,10 @@ /datum/component/mood/proc/HandleNutrition(mob/living/L) + if(isethereal(L)) + HandleCharge(L) + if(HAS_TRAIT(L, TRAIT_NOHUNGER)) + return FALSE //no mood events for nutrition switch(L.nutrition) if(NUTRITION_LEVEL_FULL to INFINITY) add_event(null, "nutrition", /datum/mood_event/fat) @@ -321,6 +325,22 @@ if(0 to NUTRITION_LEVEL_STARVING) add_event(null, "nutrition", /datum/mood_event/starving) +/datum/component/mood/proc/HandleCharge(mob/living/carbon/human/H) + var/datum/species/ethereal/E = H.dna.species + switch(E.get_charge(H)) + if(ETHEREAL_CHARGE_NONE to ETHEREAL_CHARGE_LOWPOWER) + add_event(null, "charge", /datum/mood_event/decharged) + if(ETHEREAL_CHARGE_LOWPOWER to ETHEREAL_CHARGE_NORMAL) + add_event(null, "charge", /datum/mood_event/lowpower) + if(ETHEREAL_CHARGE_NORMAL to ETHEREAL_CHARGE_ALMOSTFULL) + clear_event(null, "charge") + if(ETHEREAL_CHARGE_ALMOSTFULL to ETHEREAL_CHARGE_FULL) + add_event(null, "charge", /datum/mood_event/charged) + if(ETHEREAL_CHARGE_FULL to ETHEREAL_CHARGE_OVERLOAD) + add_event(null, "charge", /datum/mood_event/overcharged) + if(ETHEREAL_CHARGE_OVERLOAD to ETHEREAL_CHARGE_DANGEROUS) + add_event(null, "charge", /datum/mood_event/supercharged) + /datum/component/mood/proc/update_beauty(area/A) if(A.outdoors) //if we're outside, we don't care. clear_event(null, "area_beauty") diff --git a/code/datums/components/plumbing/_plumbing.dm b/code/datums/components/plumbing/_plumbing.dm new file mode 100644 index 0000000000..6592e41103 --- /dev/null +++ b/code/datums/components/plumbing/_plumbing.dm @@ -0,0 +1,215 @@ +/datum/component/plumbing + ///Index with "1" = /datum/ductnet/theductpointingnorth etc. "1" being the num2text from NORTH define + var/list/datum/ductnet/ducts = list() + ///shortcut to our parents' reagent holder + var/datum/reagents/reagents + ///TRUE if we wanna add proper pipe outless under our parent object. this is pretty good if i may so so myself + var/use_overlays = TRUE + ///We can't just cut all of the parents' overlays, so we'll track them here + var/list/image/ducterlays + ///directions in wich we act as a supplier + var/supply_connects + ///direction in wich we act as a demander + var/demand_connects + ///FALSE to pretty much just not exist in the plumbing world so we can be moved, TRUE to go plumbo mode + var/active = FALSE + ///if TRUE connects will spin with the parent object visually and codually, so you can have it work in any direction. FALSE if you want it to be static + var/turn_connects = TRUE + +/datum/component/plumbing/Initialize(start=TRUE, _turn_connects=TRUE) //turn_connects for wheter or not we spin with the object to change our pipes + if(parent && !istype(parent, /atom/movable)) + return COMPONENT_INCOMPATIBLE + var/atom/movable/AM = parent + if(!AM.reagents) + return COMPONENT_INCOMPATIBLE + reagents = AM.reagents + turn_connects = _turn_connects + + RegisterSignal(parent, list(COMSIG_MOVABLE_MOVED,COMSIG_PARENT_PREQDELETED), .proc/disable) + RegisterSignal(parent, list(COMSIG_OBJ_DEFAULT_UNFASTEN_WRENCH), .proc/toggle_active) + + if(start) + enable() + + if(use_overlays) + create_overlays() + +/datum/component/plumbing/process() + if(!demand_connects || !reagents) + STOP_PROCESSING(SSfluids, src) + return + if(reagents.total_volume < reagents.maximum_volume) + for(var/D in GLOB.cardinals) + if(D & demand_connects) + send_request(D) +///Can we be added to the ductnet? +/datum/component/plumbing/proc/can_add(datum/ductnet/D, dir) + if(!active) + return + if(!dir || !D) + return FALSE + if(num2text(dir) in ducts) + return FALSE + + return TRUE +///called from in process(). only calls process_request(), but can be overwritten for children with special behaviour +/datum/component/plumbing/proc/send_request(dir) + process_request(amount = MACHINE_REAGENT_TRANSFER, reagent = null, dir = dir) +///check who can give us what we want, and how many each of them will give us +/datum/component/plumbing/proc/process_request(amount, reagent, dir) + var/list/valid_suppliers = list() + var/datum/ductnet/net + if(!ducts.Find(num2text(dir))) + return + net = ducts[num2text(dir)] + for(var/A in net.suppliers) + var/datum/component/plumbing/supplier = A + if(supplier.can_give(amount, reagent, net)) + valid_suppliers += supplier + for(var/A in valid_suppliers) + var/datum/component/plumbing/give = A + give.transfer_to(src, amount / valid_suppliers.len, reagent, net) +///returns TRUE when they can give the specified amount and reagent. called by process request +/datum/component/plumbing/proc/can_give(amount, reagent, datum/ductnet/net) + if(amount <= 0) + return + + if(reagent) //only asked for one type of reagent + for(var/A in reagents.reagent_list) + var/datum/reagent/R = A + if(R.type == reagent) + return TRUE + else if(reagents.total_volume > 0) //take whatever + return TRUE +///this is where the reagent is actually transferred and is thus the finish point of our process() +/datum/component/plumbing/proc/transfer_to(datum/component/plumbing/target, amount, reagent, datum/ductnet/net) + if(!reagents || !target || !target.reagents) + return FALSE + if(reagent) + reagents.trans_id_to(target.parent, reagent, amount) + else + reagents.trans_to(target.parent, amount) +///We create our luxurious piping overlays/underlays, to indicate where we do what. only called once if use_overlays = TRUE in Initialize() +/datum/component/plumbing/proc/create_overlays() + var/atom/movable/AM = parent + for(var/image/I in ducterlays) + AM.overlays.Remove(I) + qdel(I) + ducterlays = list() + for(var/D in GLOB.cardinals) + var/color + var/direction + if(D & demand_connects) + color = "red" //red because red is mean and it takes + else if(D & supply_connects) + color = "blue" //blue is nice and gives + else + continue + var/image/I + if(turn_connects) + switch(D) + if(NORTH) + direction = "north" + if(SOUTH) + direction = "south" + if(EAST) + direction = "east" + if(WEST) + direction = "west" + I = image('icons/obj/plumbing/plumbers.dmi', "[direction]-[color]", layer = AM.layer - 1) + else + I = image('icons/obj/plumbing/plumbers.dmi', color, layer = AM.layer - 1) //color is not color as in the var, it's just the name + I.dir = D + AM.add_overlay(I) + ducterlays += I +///we stop acting like a plumbing thing and disconnect if we are, so we can safely be moved and stuff +/datum/component/plumbing/proc/disable() + if(!active) + return + STOP_PROCESSING(SSfluids, src) + for(var/A in ducts) + var/datum/ductnet/D = ducts[A] + D.remove_plumber(src) + active = FALSE + for(var/D in GLOB.cardinals) + if(D & (demand_connects | supply_connects)) + for(var/obj/machinery/duct/duct in get_step(parent, D)) + duct.attempt_connect() + +///settle wherever we are, and start behaving like a piece of plumbing +/datum/component/plumbing/proc/enable() + if(active) + return + update_dir() + active = TRUE + var/atom/movable/AM = parent + for(var/obj/machinery/duct/D in AM.loc) //Destroy any ducts under us. Ducts also self destruct if placed under a plumbing machine. machines disable when they get moved + if(D.anchored) //that should cover everything + D.disconnect_duct() + + if(demand_connects) + START_PROCESSING(SSfluids, src) + + for(var/D in GLOB.cardinals) + if(D & (demand_connects | supply_connects)) + for(var/atom/movable/A in get_step(parent, D)) + if(istype(A, /obj/machinery/duct)) + var/obj/machinery/duct/duct = A + duct.attempt_connect() + else + var/datum/component/plumbing/P = A.GetComponent(/datum/component/plumbing) + if(P) + direct_connect(P, D) + +/// Toggle our machinery on or off. This is called by a hook from default_unfasten_wrench with anchored as only param, so we dont have to copypaste this on every object that can move +/datum/component/plumbing/proc/toggle_active(obj/O, new_state) + if(new_state) + enable() + else + disable() +/** We update our connects only when we settle down by taking our current and original direction to find our new connects +* If someone wants it to fucking spin while connected to something go actually knock yourself out +*/ +/datum/component/plumbing/proc/update_dir() + if(!turn_connects) + return + var/atom/movable/AM = parent + var/new_demand_connects + var/new_supply_connects + var/new_dir = AM.dir + var/angle = 180 - dir2angle(new_dir) + if(new_dir == SOUTH) + demand_connects = initial(demand_connects) + supply_connects = initial(supply_connects) + else + for(var/D in GLOB.cardinals) + if(D & initial(demand_connects)) + new_demand_connects += turn(D, angle) + if(D & initial(supply_connects)) + new_supply_connects += turn(D, angle) + demand_connects = new_demand_connects + supply_connects = new_supply_connects +///Give the direction of a pipe, and it'll return wich direction it originally was when it's object pointed SOUTH +/datum/component/plumbing/proc/get_original_direction(dir) + var/atom/movable/AM = parent + return turn(dir, dir2angle(AM.dir) - 180) +//special case in-case we want to connect directly with another machine without a duct +/datum/component/plumbing/proc/direct_connect(datum/component/plumbing/P, dir) + if(!P.active) + return + var/opposite_dir = turn(dir, 180) + if(P.demand_connects & opposite_dir && supply_connects & dir || P.supply_connects & opposite_dir && demand_connects & dir) //make sure we arent connecting two supplies or demands + var/datum/ductnet/net = new() + net.add_plumber(src, dir) + net.add_plumber(P, opposite_dir) + +///has one pipe input that only takes, example is manual output pipe +/datum/component/plumbing/simple_demand + demand_connects = NORTH +///has one pipe output that only supplies. example is liquid pump and manual input pipe +/datum/component/plumbing/simple_supply + supply_connects = NORTH +///input and output, like a holding tank +/datum/component/plumbing/tank + demand_connects = WEST + supply_connects = EAST diff --git a/code/datums/components/plumbing/chemical_acclimator.dm b/code/datums/components/plumbing/chemical_acclimator.dm new file mode 100644 index 0000000000..1cbe6ff017 --- /dev/null +++ b/code/datums/components/plumbing/chemical_acclimator.dm @@ -0,0 +1,21 @@ +/datum/component/plumbing/acclimator + demand_connects = WEST + supply_connects = EAST + var/obj/machinery/plumbing/acclimator/AC + +/datum/component/plumbing/acclimator/Initialize(start=TRUE, _turn_connects=TRUE) + . = ..() + if(!istype(parent, /obj/machinery/plumbing/acclimator)) + return COMPONENT_INCOMPATIBLE + AC = parent + +/datum/component/plumbing/acclimator/can_give(amount, reagent) + . = ..() + if(. && AC.emptying) + return TRUE + return FALSE +///We're overriding process and not send_request, because all process does is do the requests, so we might aswell cut out the middle man and save some code from running +/datum/component/plumbing/acclimator/process() + if(AC.emptying) + return + . = ..() diff --git a/code/datums/components/plumbing/filter.dm b/code/datums/components/plumbing/filter.dm new file mode 100644 index 0000000000..76b76323c5 --- /dev/null +++ b/code/datums/components/plumbing/filter.dm @@ -0,0 +1,59 @@ +///The magical plumbing component used by the chemical filters. The different supply connects behave differently depending on the filters set on the chemical filter +/datum/component/plumbing/filter + demand_connects = NORTH + supply_connects = SOUTH | EAST | WEST //SOUTH is straight, EAST is left and WEST is right. We look from the perspective of the insert + +/datum/component/plumbing/filter/Initialize() + . = ..() + if(!istype(parent, /obj/machinery/plumbing/filter)) + return COMPONENT_INCOMPATIBLE + +/datum/component/plumbing/filter/can_give(amount, reagent, datum/ductnet/net) + . = ..() + if(.) + var/direction + for(var/A in ducts) + if(ducts[A] == net) + direction = get_original_direction(text2num(A)) //we need it relative to the direction, so filters don't change when we turn the filter + break + if(!direction) + return FALSE + if(reagent) + if(!can_give_in_direction(direction, reagent)) + return FALSE + +/datum/component/plumbing/filter/transfer_to(datum/component/plumbing/target, amount, reagent, datum/ductnet/net) + if(!reagents || !target || !target.reagents) + return FALSE + var/direction + for(var/A in ducts) + if(ducts[A] == net) + direction = get_original_direction(text2num(A)) + break + if(reagent) + reagents.trans_id_to(target.parent, reagent, amount) + else + for(var/A in reagents.reagent_list) + var/datum/reagent/R = A + if(!can_give_in_direction(direction, R.type)) + continue + var/new_amount + if(R.volume < amount) + new_amount = amount - R.volume + reagents.trans_id_to(target.parent, R.type, amount) + amount = new_amount + if(amount <= 0) + break +///We check if the direction and reagent are valid to give. Needed for filters since different outputs have different behaviours +/datum/component/plumbing/filter/proc/can_give_in_direction(dir, reagent) + var/obj/machinery/plumbing/filter/F = parent + switch(dir) + if(SOUTH) //straight + if(!F.left.Find(reagent) && !F.right.Find(reagent)) + return TRUE + if(WEST) //right + if(F.right.Find(reagent)) + return TRUE + if(EAST) //left + if(F.left.Find(reagent)) + return TRUE diff --git a/code/datums/components/plumbing/reaction_chamber.dm b/code/datums/components/plumbing/reaction_chamber.dm new file mode 100644 index 0000000000..90f4e621da --- /dev/null +++ b/code/datums/components/plumbing/reaction_chamber.dm @@ -0,0 +1,38 @@ +/datum/component/plumbing/reaction_chamber + demand_connects = WEST + supply_connects = EAST + +/datum/component/plumbing/reaction_chamber/Initialize(start=TRUE, _turn_connects=TRUE) + . = ..() + if(!istype(parent, /obj/machinery/plumbing/reaction_chamber)) + return COMPONENT_INCOMPATIBLE + +/datum/component/plumbing/reaction_chamber/can_give(amount, reagent, datum/ductnet/net) + . = ..() + var/obj/machinery/plumbing/reaction_chamber/RC = parent + if(!. || !RC.emptying) + return FALSE + +/datum/component/plumbing/reaction_chamber/send_request(dir) + var/obj/machinery/plumbing/reaction_chamber/RC = parent + if(RC.emptying || !LAZYLEN(RC.required_reagents)) + return + for(var/RT in RC.required_reagents) + var/has_reagent = FALSE + for(var/A in reagents.reagent_list) + var/datum/reagent/RD = A + if(RT == RD.type) + has_reagent = TRUE + if(RD.volume < RC.required_reagents[RT]) + process_request(min(RC.required_reagents[RT] - RD.volume, MACHINE_REAGENT_TRANSFER) , RT, dir) + return + if(!has_reagent) + process_request(min(RC.required_reagents[RT], MACHINE_REAGENT_TRANSFER), RT, dir) + return + + RC.reagent_flags &= ~NO_REACT + reagents.handle_reactions() + + RC.emptying = TRUE //If we move this up, it'll instantly get turned off since any reaction always sets the reagent_total to zero. Other option is make the reaction update + //everything for every chemical removed, wich isn't a good option either. + RC.on_reagent_change() //We need to check it now, because some reactions leave nothing left. diff --git a/code/datums/components/plumbing/splitter.dm b/code/datums/components/plumbing/splitter.dm new file mode 100644 index 0000000000..7194e8803b --- /dev/null +++ b/code/datums/components/plumbing/splitter.dm @@ -0,0 +1,45 @@ +/datum/component/plumbing/splitter + demand_connects = NORTH + supply_connects = SOUTH | EAST + +/datum/component/plumbing/splitter/Initialize() + . = ..() + if(. && !istype(parent, /obj/machinery/plumbing/splitter)) + return FALSE + +/datum/component/plumbing/splitter/can_give(amount, reagent, datum/ductnet/net) + . = ..() + if(!.) + return + . = FALSE + var/direction + for(var/A in ducts) + if(ducts[A] == net) + direction = get_original_direction(text2num(A)) + break + var/obj/machinery/plumbing/splitter/S = parent + switch(direction) + if(SOUTH) + if(S.turn_straight && S.transfer_straight <= amount) + S.turn_straight = FALSE + return TRUE + if(EAST) + if(!S.turn_straight && S.transfer_side <= amount) + S.turn_straight = TRUE + return TRUE + +/datum/component/plumbing/splitter/transfer_to(datum/component/plumbing/target, amount, reagent, datum/ductnet/net) + var/direction + for(var/A in ducts) + if(ducts[A] == net) + direction = get_original_direction(text2num(A)) + break + var/obj/machinery/plumbing/splitter/S = parent + switch(direction) + if(SOUTH) + if(amount >= S.transfer_straight) + amount = S.transfer_straight + if(EAST) + if(amount >= S.transfer_side) + amount = S.transfer_side + . = ..() diff --git a/code/datums/components/radioactive.dm b/code/datums/components/radioactive.dm index f12e8bf007..8afa4353b2 100644 --- a/code/datums/components/radioactive.dm +++ b/code/datums/components/radioactive.dm @@ -29,10 +29,18 @@ if(strength > RAD_MINIMUM_CONTAMINATION) SSradiation.warn(src) + //Let's make er glow + //This relies on parent not being a turf or something. IF YOU CHANGE THAT, CHANGE THIS + var/atom/movable/master = parent + master.add_filter("rad_glow", 2, list("type" = "outline", "color" = "#39ff1430", "size" = 2)) + addtimer(CALLBACK(src, .proc/glow_loop, master), rand(1,19))//Things should look uneven + START_PROCESSING(SSradiation, src) /datum/component/radioactive/Destroy() STOP_PROCESSING(SSradiation, src) + var/atom/movable/master = parent + master.remove_filter("rad_glow") return ..() /datum/component/radioactive/process() @@ -46,6 +54,13 @@ if(strength <= RAD_BACKGROUND_RADIATION) return PROCESS_KILL + +/datum/component/radioactive/proc/glow_loop(atom/movable/master) + var/filter = master.get_filter("rad_glow") + if(filter) + animate(filter, alpha = 110, time = 15, loop = -1) + animate(alpha = 40, time = 25) + /datum/component/radioactive/InheritComponent(datum/component/C, i_am_original, _strength, _source, _half_life, _can_contaminate) if(!i_am_original) return diff --git a/code/datums/components/shielded.dm b/code/datums/components/shielded.dm index 2052e57f49..3cf70e80ef 100644 --- a/code/datums/components/shielded.dm +++ b/code/datums/components/shielded.dm @@ -14,6 +14,7 @@ var/mob/living/holder //who is currently benefiting from the shield. var/dissipating = FALSE //Is this shield meant to dissipate over time instead of recharging. var/del_on_overload = FALSE //will delete itself once it has no charges left. + var/cached_vis_overlay //text identifier of the visual overlay. /datum/component/shielded/Initialize(current, max = 3, delay = 20 SECONDS, rate = 1, slots, state = "shield-old", broken, \ sound = 'sound/magic/charge.ogg', end_sound = 'sound/machines/ding.ogg', diss = FALSE, del_overload = FALSE) @@ -47,9 +48,8 @@ holder = L var/to_add = charges >= 1 ? shield_state : broken_state if(to_add) - var/mutable_appearance/M = mutable_appearance('icons/effects/effects.dmi', to_add) - M.layer = (L.layer > MOB_LAYER ? L.layer : MOB_LAYER) + 0.01 - holder.add_overlay(M, TRUE) + var/layer = (L.layer > MOB_LAYER ? L.layer : MOB_LAYER) + 0.01 + SSvis_overlays.add_vis_overlay(L, 'icons/effects/effects.dmi', to_add, layer, GAME_PLANE, L.dir) /datum/component/shielded/UnregisterFromParent() . = ..() @@ -57,9 +57,9 @@ UnregisterSignal(parent, list(COMSIG_ITEM_RUN_BLOCK,COMSIG_ITEM_CHECK_BLOCK,COMSIG_ITEM_EQUIPPED,COMSIG_ITEM_DROPPED)) if(holder) UnregisterSignal(holder, list(COMSIG_LIVING_RUN_BLOCK, COMSIG_LIVING_GET_BLOCKING_ITEMS)) - var/to_remove = charges >= 1 ? shield_state : broken_state - if(to_remove) - holder.cut_overlay(mutable_appearance('icons/effects/effects.dmi', to_remove), TRUE) + if(cached_vis_overlay) + SSvis_overlays.remove_vis_overlay(holder, cached_vis_overlay) + cached_vis_overlay = null holder = null /datum/component/shielded/process() @@ -80,7 +80,7 @@ holder.visible_message("[holder]'s shield overloads!") qdel(src) return - if(holder && (old_charges < 1 && charges >= 1) || (!del_on_overload && old_charges >= 1 && charges < 1)) + if(holder && ((old_charges < 1 && charges >= 1) || (!del_on_overload && old_charges >= 1 && charges < 1))) update_shield_overlay(charges < 1) /datum/component/shielded/proc/adjust_charges(amount) @@ -93,20 +93,19 @@ holder.visible_message("[holder]'s shield overloads!") qdel(src) return - if(holder && (old_charges < 1 && charges >= 1) || (!del_on_overload && old_charges >= 1 && charges < 1)) + if(holder && ((old_charges < 1 && charges >= 1) || (!del_on_overload && old_charges >= 1 && charges < 1))) update_shield_overlay(charges < 1) /datum/component/shielded/proc/update_shield_overlay(broken) if(!holder) return - var/to_remove = broken ? shield_state : broken_state var/to_add = broken ? broken_state : shield_state - if(to_remove) - holder.cut_overlay(mutable_appearance('icons/effects/effects.dmi', to_remove), TRUE) + if(cached_vis_overlay) + SSvis_overlays.remove_vis_overlay(holder, cached_vis_overlay) + cached_vis_overlay = null if(to_add) - var/mutable_appearance/M = mutable_appearance('icons/effects/effects.dmi', to_add) - M.layer = (holder.layer > MOB_LAYER ? holder.layer : MOB_LAYER) + 0.01 - holder.add_overlay(M, TRUE) + var/layer = (holder.layer > MOB_LAYER ? holder.layer : MOB_LAYER) + 0.01 + SSvis_overlays.add_vis_overlay(holder, 'icons/effects/effects.dmi', to_add, layer, GAME_PLANE, holder.dir) /datum/component/shielded/proc/on_equip(obj/item/source, mob/living/equipper, slot) if(!(accepted_slots & slotdefine2slotbit(slot))) @@ -117,17 +116,16 @@ RegisterSignal(equipper, COMSIG_LIVING_GET_BLOCKING_ITEMS, .proc/include_shield) var/to_add = charges >= 1 ? shield_state : broken_state if(to_add) - var/mutable_appearance/M = mutable_appearance('icons/effects/effects.dmi', to_add) - M.layer = (holder.layer > MOB_LAYER ? holder.layer : MOB_LAYER) + 0.01 - equipper.add_overlay(M, TRUE) + var/layer = (holder.layer > MOB_LAYER ? holder.layer : MOB_LAYER) + 0.01 + cached_vis_overlay = SSvis_overlays.add_vis_overlay(holder, 'icons/effects/effects.dmi', to_add, layer, GAME_PLANE, holder.dir) /datum/component/shielded/proc/on_drop(obj/item/source, mob/dropper) if(holder == dropper) UnregisterSignal(holder, COMSIG_LIVING_GET_BLOCKING_ITEMS) UnregisterSignal(parent, list(COMSIG_ITEM_RUN_BLOCK, COMSIG_ITEM_CHECK_BLOCK)) - var/to_remove = charges >= 1 ? shield_state : broken_state - if(to_remove) - holder.cut_overlay(mutable_appearance('icons/effects/effects.dmi', to_remove), TRUE) + if(cached_vis_overlay) + SSvis_overlays.remove_vis_overlay(holder, cached_vis_overlay) + cached_vis_overlay = null holder = null /datum/component/shielded/proc/include_shield(mob/source, list/items) diff --git a/code/datums/components/squeak.dm b/code/datums/components/squeak.dm index 792222b27b..df44aef4de 100644 --- a/code/datums/components/squeak.dm +++ b/code/datums/components/squeak.dm @@ -11,6 +11,13 @@ // This is to stop squeak spam from inhand usage var/last_use = 0 var/use_delay = 20 + + // squeak cooldowns + var/last_squeak = 0 + var/squeak_delay = 5 + + /// chance we'll be stopped from squeaking by cooldown when something crossing us squeaks + var/cross_squeak_delay_chance = 33 // about 3 things can squeak at a time /datum/component/squeak/Initialize(custom_sounds, volume_override, chance_override, step_delay_override, use_delay_override) if(!isatom(parent)) @@ -19,6 +26,7 @@ if(ismovable(parent)) RegisterSignal(parent, list(COMSIG_MOVABLE_BUMP, COMSIG_MOVABLE_IMPACT), .proc/play_squeak) RegisterSignal(parent, list(COMSIG_MOVABLE_CROSSED, COMSIG_ITEM_WEARERCROSSED), .proc/play_squeak_crossed) + RegisterSignal(parent, COMSIG_CROSS_SQUEAKED, .proc/delay_squeak) RegisterSignal(parent, COMSIG_MOVABLE_DISPOSING, .proc/disposing_react) if(isitem(parent)) RegisterSignal(parent, list(COMSIG_ITEM_ATTACK, COMSIG_ITEM_ATTACK_OBJ, COMSIG_ITEM_HIT_REACT), .proc/play_squeak) @@ -39,20 +47,28 @@ use_delay = use_delay_override /datum/component/squeak/proc/play_squeak() + do_play_squeak() + +/datum/component/squeak/proc/do_play_squeak(bypass_cooldown = FALSE) + if(!bypass_cooldown && ((last_squeak + squeak_delay) >= world.time)) + return FALSE if(prob(squeak_chance)) if(!override_squeak_sounds) playsound(parent, pickweight(default_squeak_sounds), volume, 1, -1) else playsound(parent, pickweight(override_squeak_sounds), volume, 1, -1) + last_squeak = world.time + return TRUE + return FALSE /datum/component/squeak/proc/step_squeak() if(steps > step_delay) - play_squeak() + do_play_squeak(TRUE) steps = 0 else steps++ -/datum/component/squeak/proc/play_squeak_crossed(atom/movable/AM) +/datum/component/squeak/proc/play_squeak_crossed(datum/source, atom/movable/AM) if(isitem(AM)) var/obj/item/I = AM if(I.item_flags & ABSTRACT) @@ -63,13 +79,18 @@ return var/atom/current_parent = parent if(isturf(current_parent.loc)) - play_squeak() + if(do_play_squeak()) + SEND_SIGNAL(AM, COMSIG_CROSS_SQUEAKED) /datum/component/squeak/proc/use_squeak() if(last_use + use_delay < world.time) last_use = world.time play_squeak() +/datum/component/squeak/proc/delay_squeak() + if(prob(cross_squeak_delay_chance)) + last_squeak = world.time + /datum/component/squeak/proc/on_equip(datum/source, mob/equipper, slot) RegisterSignal(equipper, COMSIG_MOVABLE_DISPOSING, .proc/disposing_react, TRUE) diff --git a/code/datums/components/twohanded.dm b/code/datums/components/twohanded.dm index 77a9a79bf4..bcbf979101 100644 --- a/code/datums/components/twohanded.dm +++ b/code/datums/components/twohanded.dm @@ -105,6 +105,8 @@ /// Triggered on attack self of the item containing the component /datum/component/two_handed/proc/on_attack_self(datum/source, mob/user) + if(!user.is_holding(parent)) + return //give no quarter to telekinesis powergaemrs (telekinetic wielding will desync the offhand and result in all sorts of bugs so no until someone codes it properly) if(wielded) unwield(user) else diff --git a/code/datums/components/uplink.dm b/code/datums/components/uplink.dm index c7bbe01b2f..4a9c558d39 100644 --- a/code/datums/components/uplink.dm +++ b/code/datums/components/uplink.dm @@ -29,8 +29,8 @@ GLOBAL_LIST_EMPTY(uplinks) var/saved_player_population = 0 var/list/filters = list() - -/datum/component/uplink/Initialize(_owner, _lockable = TRUE, _enabled = FALSE, datum/game_mode/_gamemode, starting_tc = 20, datum/ui_state/_checkstate, datum/traitor_class/traitor_class) + +/datum/component/uplink/Initialize(_owner, _lockable = TRUE, _enabled = FALSE, datum/game_mode/_gamemode, starting_tc = 20, datum/traitor_class/traitor_class) if(!isitem(parent)) return COMPONENT_INCOMPATIBLE @@ -143,23 +143,21 @@ GLOBAL_LIST_EMPTY(uplinks) // an unlocked uplink blocks also opening the PDA or headset menu return COMPONENT_NO_INTERACT -/datum/component/uplink/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ - datum/tgui/master_ui = null, datum/ui_state/state = GLOB.inventory_state) +/datum/component/uplink/ui_state(mob/user) + if(istype(parent, /obj/item/implant/uplink)) + return GLOB.not_incapacitated_state + return GLOB.inventory_state + +/datum/component/uplink/ui_interact(mob/user, datum/tgui/ui) active = TRUE - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) + ui = SStgui.try_update_ui(user, src, ui) if(!ui) - ui = new(user, src, ui_key, "Uplink", name, 620, 580, master_ui, state) + ui = new(user, src, "Uplink", name) // This UI is only ever opened by one person, // and never is updated outside of user input. ui.set_autoupdate(FALSE) ui.open() -/datum/component/uplink/ui_host(mob/user) - if(istype(parent, /obj/item/implant)) //implants are like organs, not really located inside mobs codewise. - var/obj/item/implant/I = parent - return I.imp_in - return ..() - /datum/component/uplink/ui_data(mob/user) if(!user.mind) return @@ -187,8 +185,18 @@ GLOBAL_LIST_EMPTY(uplinks) is_inaccessible = FALSE if(is_inaccessible) continue + /* + if(I.restricted_species) //catpeople specfic gloves. + if(ishuman(user)) + var/is_inaccessible = TRUE + var/mob/living/carbon/human/H = user + for(var/F in I.restricted_species) + if(F == H.dna.species.id || debug) + is_inaccessible = FALSE + break if(is_inaccessible) continue + */ cat["items"] += list(list( "name" = I.name, "cost" = I.cost, diff --git a/code/datums/datacore.dm b/code/datums/datacore.dm index cf942f077f..5aeb7626f6 100644 --- a/code/datums/datacore.dm +++ b/code/datums/datacore.dm @@ -1,13 +1,13 @@ - +//TODO: someone please get rid of this shit /datum/datacore - var/medical[] = list() + var/list/medical = list() var/medicalPrintCount = 0 - var/general[] = list() - var/security[] = list() + var/list/general = list() + var/list/security = list() var/securityPrintCount = 0 var/securityCrimeCounter = 0 - //This list tracks characters spawned in the world and cannot be modified in-game. Currently referenced by respawn_character(). - var/locked[] = list() + ///This list tracks characters spawned in the world and cannot be modified in-game. Currently referenced by respawn_character(). + var/list/locked = list() /datum/data var/name = "data" @@ -91,6 +91,42 @@ if(foundrecord) foundrecord.fields["rank"] = assignment +/datum/datacore/proc/get_manifest_tg() //copypasted from tg, renamed to avoid namespace conflicts + var/list/manifest_out = list() + var/list/departments = list( + "Command" = GLOB.command_positions, + "Security" = GLOB.security_positions, + "Engineering" = GLOB.engineering_positions, + "Medical" = GLOB.medical_positions, + "Science" = GLOB.science_positions, + "Supply" = GLOB.supply_positions, + "Service" = GLOB.civilian_positions, + "Silicon" = GLOB.nonhuman_positions + ) + for(var/datum/data/record/t in GLOB.data_core.general) + var/name = t.fields["name"] + var/rank = t.fields["rank"] + var/has_department = FALSE + for(var/department in departments) + var/list/jobs = departments[department] + if(rank in jobs) + if(!manifest_out[department]) + manifest_out[department] = list() + manifest_out[department] += list(list( + "name" = name, + "rank" = rank + )) + has_department = TRUE + break + if(!has_department) + if(!manifest_out["Misc"]) + manifest_out["Misc"] = list() + manifest_out["Misc"] += list(list( + "name" = name, + "rank" = rank + )) + return manifest_out + /datum/datacore/proc/get_manifest(monochrome, OOC) var/list/heads = list() var/list/sec = list() diff --git a/code/datums/datumvars.dm b/code/datums/datumvars.dm index 348f9e6778..a91549ab4c 100644 --- a/code/datums/datumvars.dm +++ b/code/datums/datumvars.dm @@ -31,6 +31,9 @@ VV_DROPDOWN_OPTION(VV_HK_EXPOSE, "Show VV To Player") VV_DROPDOWN_OPTION(VV_HK_ADDCOMPONENT, "Add Component/Element") VV_DROPDOWN_OPTION(VV_HK_MODIFY_TRAITS, "Modify Traits") + #ifdef REFERENCE_TRACKING + VV_DROPDOWN_OPTION(VV_HK_VIEW_REFERENCES, "View References") + #endif //This proc is only called if everything topic-wise is verified. The only verifications that should happen here is things like permission checks! //href_list is a reference, modifying it in these procs WILL change the rest of the proc in topic.dm of admin/view_variables! diff --git a/code/datums/diseases/advance/symptoms/species.dm b/code/datums/diseases/advance/symptoms/species.dm index 49a3cf8d07..2d5255842b 100644 --- a/code/datums/diseases/advance/symptoms/species.dm +++ b/code/datums/diseases/advance/symptoms/species.dm @@ -31,4 +31,3 @@ /datum/symptom/inorganic_adaptation/OnRemove(datum/disease/advance/A) A.infectable_biotypes &= ~MOB_MINERAL - diff --git a/code/datums/dna.dm b/code/datums/dna.dm index 8d80bc3f36..9486029fdd 100644 --- a/code/datums/dna.dm +++ b/code/datums/dna.dm @@ -50,6 +50,7 @@ destination.dna.skin_tone_override = skin_tone_override destination.dna.features = features.Copy() destination.set_species(species.type, icon_update=0) + destination.dna.species.say_mod = species.say_mod destination.dna.real_name = real_name destination.dna.nameless = nameless destination.dna.custom_species = custom_species @@ -74,6 +75,7 @@ new_dna.skin_tone_override = skin_tone_override new_dna.features = features.Copy() new_dna.species = new species.type + new_dna.species.say_mod = species.say_mod new_dna.real_name = real_name new_dna.nameless = nameless new_dna.custom_species = custom_species @@ -135,10 +137,10 @@ L[DNA_COLOR_TWO_BLOCK] = sanitize_hexcolor(features["mcolor2"], 6) L[DNA_COLOR_THREE_BLOCK] = sanitize_hexcolor(features["mcolor3"], 6) if(!GLOB.mam_tails_list.len) - init_sprite_accessory_subtypes(/datum/sprite_accessory/mam_tails, GLOB.mam_tails_list) + init_sprite_accessory_subtypes(/datum/sprite_accessory/tails/mam_tails, GLOB.mam_tails_list) L[DNA_MUTANTTAIL_BLOCK] = construct_block(GLOB.mam_tails_list.Find(features["mam_tail"]), GLOB.mam_tails_list.len) if(!GLOB.mam_ears_list.len) - init_sprite_accessory_subtypes(/datum/sprite_accessory/mam_ears, GLOB.mam_ears_list) + init_sprite_accessory_subtypes(/datum/sprite_accessory/ears/mam_ears, GLOB.mam_ears_list) L[DNA_MUTANTEAR_BLOCK] = construct_block(GLOB.mam_ears_list.Find(features["mam_ears"]), GLOB.mam_ears_list.len) if(!GLOB.mam_body_markings_list.len) init_sprite_accessory_subtypes(/datum/sprite_accessory/mam_body_markings, GLOB.mam_body_markings_list) diff --git a/code/datums/ductnet.dm b/code/datums/ductnet.dm new file mode 100644 index 0000000000..14a74a67c4 --- /dev/null +++ b/code/datums/ductnet.dm @@ -0,0 +1,65 @@ +///We handle the unity part of plumbing. We track who is connected to who. +/datum/ductnet + var/list/suppliers = list() + var/list/demanders = list() + var/list/obj/machinery/duct/ducts = list() + + var/capacity +///Add a duct to our network +/datum/ductnet/proc/add_duct(obj/machinery/duct/D) + if(!D || (D in ducts)) + return + ducts += D + D.duct = src +///Remove a duct from our network and commit suicide, because this is probably easier than to check who that duct was connected to and what part of us was lost +/datum/ductnet/proc/remove_duct(obj/machinery/duct/ducting) + destroy_network(FALSE) + for(var/obj/machinery/duct/D in ducting.neighbours) + addtimer(CALLBACK(D, /obj/machinery/duct/proc/reconnect), 0) //all needs to happen after the original duct that was destroyed finishes destroying itself + addtimer(CALLBACK(D, /obj/machinery/duct/proc/generate_connects), 0) + qdel(src) +///add a plumbing object to either demanders or suppliers +/datum/ductnet/proc/add_plumber(datum/component/plumbing/P, dir) + if(!P.can_add(src, dir)) + return FALSE + P.ducts[num2text(dir)] = src + if(dir & P.supply_connects) + suppliers += P + else if(dir & P.demand_connects) + demanders += P + return TRUE +///remove a plumber. we dont delete ourselves because ductnets dont persist through plumbing objects +/datum/ductnet/proc/remove_plumber(datum/component/plumbing/P) + suppliers.Remove(P) //we're probably only in one of these, but Remove() is inherently sane so this is fine + demanders.Remove(P) + + for(var/dir in P.ducts) + if(P.ducts[dir] == src) + P.ducts -= dir + if(!ducts.len) //there were no ducts, so it was a direct connection. we destroy ourselves since a ductnet with only one plumber and no ducts is worthless + destroy_network() +///we combine ductnets. this occurs when someone connects to seperate sets of fluid ducts +/datum/ductnet/proc/assimilate(datum/ductnet/D) + ducts.Add(D.ducts) + suppliers.Add(D.suppliers) + demanders.Add(D.demanders) + for(var/A in D.suppliers + D.demanders) + var/datum/component/plumbing/P = A + for(var/s in P.ducts) + if(P.ducts[s] != D) + continue + P.ducts[s] = src //all your ducts are belong to us + for(var/A in D.ducts) + var/obj/machinery/duct/M = A + M.duct = src //forget your old master + + destroy_network() +///destroy the network and tell all our ducts and plumbers we are gone +/datum/ductnet/proc/destroy_network(delete=TRUE) + for(var/A in suppliers + demanders) + remove_plumber(A) + for(var/A in ducts) + var/obj/machinery/duct/D = A + D.duct = null + if(delete) //I don't want code to run with qdeleted objects because that can never be good, so keep this in-case the ductnet has some business left to attend to before commiting suicide + qdel(src) diff --git a/code/datums/elements/bsa_blocker.dm b/code/datums/elements/bsa_blocker.dm new file mode 100644 index 0000000000..61140ad0ed --- /dev/null +++ b/code/datums/elements/bsa_blocker.dm @@ -0,0 +1,10 @@ +//blocks bluespace artillery beams that try to fly through +//look not all elements need to be fancy +/datum/element/bsa_blocker/Attach(datum/target) + if(!isatom(target)) + return ELEMENT_INCOMPATIBLE + RegisterSignal(target, COMSIG_ATOM_BSA_BEAM, .proc/block_bsa) + return ..() + +/datum/element/bsa_blocker/proc/block_bsa() + return COMSIG_ATOM_BLOCKS_BSA_BEAM diff --git a/code/datums/elements/decal.dm b/code/datums/elements/decal.dm index 4bd482915a..50519b08e7 100644 --- a/code/datums/elements/decal.dm +++ b/code/datums/elements/decal.dm @@ -33,39 +33,34 @@ if(description) RegisterSignal(A, COMSIG_PARENT_EXAMINE, .proc/examine) - apply(A, TRUE) - num_decals_per_atom[A]++ + apply(A) /datum/element/decal/Detach(datum/target) var/atom/A = target - remove(A, A.dir) - UnregisterSignal(A, list(COMSIG_ATOM_DIR_CHANGE, COMSIG_COMPONENT_CLEAN_ACT, COMSIG_PARENT_EXAMINE)) - LAZYREMOVE(num_decals_per_atom, A) + num_decals_per_atom[A]-- + apply(A, TRUE) + if(!num_decals_per_atom[A]) + UnregisterSignal(A, list(COMSIG_ATOM_DIR_CHANGE, COMSIG_COMPONENT_CLEAN_ACT, COMSIG_PARENT_EXAMINE, COMSIG_ATOM_UPDATE_OVERLAYS)) + LAZYREMOVE(num_decals_per_atom, A) return ..() -/datum/element/decal/proc/remove(atom/target, old_dir) - pic.dir = first_dir == NORTH ? target.dir : turn(first_dir, dir2angle(old_dir)) - for(var/i in 1 to num_decals_per_atom[target]) - target.cut_overlay(pic, TRUE) +/datum/element/decal/proc/apply(atom/target, removing = FALSE) + if(num_decals_per_atom[target] == 1 && !removing) + RegisterSignal(target, COMSIG_ATOM_UPDATE_OVERLAYS, .proc/apply_overlay, TRUE) + target.update_icon() if(isitem(target)) addtimer(CALLBACK(target, /obj/item/.proc/update_slot_icon), 0, TIMER_UNIQUE) -/datum/element/decal/proc/apply(atom/target, init = FALSE) - pic.dir = first_dir == NORTH ? target.dir : turn(first_dir, dir2angle(target.dir)) - if(init) - target.add_overlay(pic, TRUE) - else - for(var/i in 1 to num_decals_per_atom[target]) - target.add_overlay(pic, TRUE) - if(isitem(target)) - addtimer(CALLBACK(target, /obj/item/.proc/update_slot_icon), 0, TIMER_UNIQUE) +/datum/element/decal/proc/apply_overlay(atom/source, list/overlay_list) + pic.dir = first_dir == NORTH ? source.dir : turn(first_dir, dir2angle(source.dir)) + for(var/i in 1 to num_decals_per_atom[source]) + overlay_list += pic -/datum/element/decal/proc/rotate_react(datum/source, old_dir, new_dir) +/datum/element/decal/proc/rotate_react(atom/source, old_dir, new_dir) if(old_dir == new_dir) return - remove(source, old_dir) - apply(source) + source.update_icon() /datum/element/decal/proc/clean_react(datum/source, strength) if(strength >= cleanable) diff --git a/code/datums/holocall.dm b/code/datums/holocall.dm index 0f4f02ae2a..4bf02e8587 100644 --- a/code/datums/holocall.dm +++ b/code/datums/holocall.dm @@ -32,20 +32,29 @@ var/datum/action/innate/end_holocall/hangup //hangup action var/call_start_time + var/head_call = FALSE //calls from a head of staff autoconnect, if the receiving pad is not secure. //creates a holocall made by `caller` from `calling_pad` to `callees` -/datum/holocall/New(mob/living/caller, obj/machinery/holopad/calling_pad, list/callees) +/datum/holocall/New(mob/living/caller, obj/machinery/holopad/calling_pad, list/callees, elevated_access = FALSE) call_start_time = world.time user = caller calling_pad.outgoing_call = src calling_holopad = calling_pad + head_call = elevated_access dialed_holopads = list() for(var/I in callees) var/obj/machinery/holopad/H = I if(!QDELETED(H) && H.is_operational()) dialed_holopads += H - H.say("Incoming call.") + if(head_call) + if(H.secure) + calling_pad.say("Auto-connection refused, falling back to call mode.") + H.say("Incoming call.") + else + H.say("Incoming connection.") + else + H.say("Incoming call.") LAZYADD(H.holo_calls, src) if(!dialed_holopads.len) @@ -79,6 +88,7 @@ dialed_holopads.Cut() if(calling_holopad) + calling_holopad.calling = FALSE calling_holopad.outgoing_call = null calling_holopad.SetLightsAndPower() calling_holopad = null @@ -145,6 +155,7 @@ if(!Check()) return + calling_holopad.calling = FALSE hologram = H.activate_holo(user) hologram.HC = src @@ -160,6 +171,8 @@ hangup = new(eye, src) hangup.Grant(user) + playsound(H, 'sound/machines/ping.ogg', 100) + H.say("Connection established.") //Checks the validity of a holocall and qdels itself if it's not. Returns TRUE if valid, FALSE otherwise /datum/holocall/proc/Check() @@ -178,7 +191,6 @@ . = world.time < (call_start_time + HOLOPAD_MAX_DIAL_TIME) if(!.) calling_holopad.say("No answer received.") - calling_holopad.temp = "" if(!.) testing("Holocall Check fail") @@ -241,10 +253,10 @@ record.caller_image = holodiskOriginal.record.caller_image record.entries = holodiskOriginal.record.entries.Copy() record.language = holodiskOriginal.record.language - to_chat(user, "You copy the record from [holodiskOriginal] to [src] by connecting the ports!") + to_chat(user, "You copy the record from [holodiskOriginal] to [src] by connecting the ports!") name = holodiskOriginal.name else - to_chat(user, "[holodiskOriginal] has no record on it!") + to_chat(user, "[holodiskOriginal] has no record on it!") ..() /obj/item/disk/holodisk/proc/build_record() @@ -331,6 +343,21 @@ DELAY 20"} /datum/preset_holoimage/engineer + outfit_type = /datum/outfit/job/engineer + +/datum/preset_holoimage/engineer/rig + outfit_type = /datum/outfit/job/engineer/gloved/rig + +/datum/preset_holoimage/engineer/ce + outfit_type = /datum/outfit/job/ce + +/datum/preset_holoimage/engineer/ce/rig + outfit_type = /datum/outfit/job/engineer/gloved/rig + +/datum/preset_holoimage/engineer/atmos + outfit_type = /datum/outfit/job/atmos + +/datum/preset_holoimage/engineer/atmos/rig outfit_type = /datum/outfit/job/engineer/gloved/rig /datum/preset_holoimage/researcher @@ -350,3 +377,90 @@ /datum/preset_holoimage/clown outfit_type = /datum/outfit/job/clown + +/obj/item/disk/holodisk/donutstation/whiteship + name = "Blackbox Print-out #DS024" + desc = "A holodisk containing the last viable recording of DS024's blackbox." + preset_image_type = /datum/preset_holoimage/engineer/ce + preset_record_text = {" + NAME Geysr Shorthalt + SAY Engine renovations complete and the ships been loaded. We all ready? + DELAY 25 + PRESET /datum/preset_holoimage/engineer + NAME Jacob Ullman + SAY Lets blow this popsicle stand of a station. + DELAY 20 + PRESET /datum/preset_holoimage/engineer/atmos + NAME Lindsey Cuffler + SAY Uh, sir? Shouldn't we call for a secondary shuttle? The bluespace drive on this thing made an awfully weird noise when we jumped here.. + DELAY 30 + PRESET /datum/preset_holoimage/engineer/ce + NAME Geysr Shorthalt + SAY Pah! Ship techie at the dock said to give it a good few kicks if it started acting up, let me just.. + DELAY 25 + SOUND punch + SOUND sparks + DELAY 10 + SOUND punch + SOUND sparks + DELAY 10 + SOUND punch + SOUND sparks + SOUND warpspeed + DELAY 15 + PRESET /datum/preset_holoimage/engineer/atmos + NAME Lindsey Cuffler + SAY Uhh.. is it supposed to be doing that?? + DELAY 15 + PRESET /datum/preset_holoimage/engineer/ce + NAME Geysr Shorthalt + SAY See? Working as intended. Now, are we all ready? + DELAY 10 + PRESET /datum/preset_holoimage/engineer + NAME Jacob Ullman + SAY Is it supposed to be glowing like that? + DELAY 20 + SOUND explosion + + "} + +/obj/item/disk/holodisk/ruin/snowengieruin + name = "Blackbox Print-out #EB412" + desc = "A holodisk containing the last moments of EB412. There's a bloody fingerprint on it." + preset_image_type = /datum/preset_holoimage/engineer + preset_record_text = {" + NAME Dave Tundrale + SAY Maria, how's Build? + DELAY 10 + NAME Maria Dell + PRESET /datum/preset_holoimage/engineer/atmos + SAY It's fine, don't worry. I've got Plastic on it. And frankly, i'm kinda busy with, the, uhhm, incinerator. + DELAY 30 + NAME Dave Tundrale + PRESET /datum/preset_holoimage/engineer + SAY Aight, wonderful. The science mans been kinda shit though. No RCDs- + DELAY 20 + NAME Maria Dell + PRESET /datum/preset_holoimage/engineer/atmos + SAY Enough about your RCDs. They're not even that important, just bui- + DELAY 15 + SOUND explosion + DELAY 10 + SAY Oh, shit! + DELAY 10 + PRESET /datum/preset_holoimage/engineer/atmos/rig + LANGUAGE /datum/language/narsie + NAME Unknown + SAY RISE, MY LORD!! + DELAY 10 + LANGUAGE /datum/language/common + NAME Plastic + PRESET /datum/preset_holoimage/engineer/rig + SAY Fuck, fuck, fuck! + DELAY 20 + SAY It's loose! CALL THE FUCKING SHUTT- + DELAY 10 + PRESET /datum/preset_holoimage/corgi + NAME Blackbox Automated Message + SAY Connection lost. Dumping audio logs to disk. + DELAY 50"} diff --git a/code/datums/hud.dm b/code/datums/hud.dm index c1811fb9b3..1c23d5f2a0 100644 --- a/code/datums/hud.dm +++ b/code/datums/hud.dm @@ -28,7 +28,8 @@ GLOBAL_LIST_INIT(huds, list( ANTAG_HUD_CLOCKWORK = new/datum/atom_hud/antag(), ANTAG_HUD_BROTHER = new/datum/atom_hud/antag/hidden(), ANTAG_HUD_BLOODSUCKER = new/datum/atom_hud/antag/bloodsucker(), - ANTAG_HUD_FUGITIVE = new/datum/atom_hud/antag() + ANTAG_HUD_FUGITIVE = new/datum/atom_hud/antag(), + ANTAG_HUD_HERETIC = new/datum/atom_hud/antag/hidden() )) /datum/atom_hud diff --git a/code/datums/materials/basemats.dm b/code/datums/materials/basemats.dm index 721af65449..1469965b57 100644 --- a/code/datums/materials/basemats.dm +++ b/code/datums/materials/basemats.dm @@ -287,7 +287,7 @@ Unless you know what you're doing, only use the first three numbers. They're in desc = "Clock Cult? Never heard of it." color = "#92661A" categories = list(MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE) - sheet_type = /obj/item/stack/tile/bronze + sheet_type = /obj/item/stack/sheet/bronze value_per_unit = 0.025 armor_modifiers = list("melee" = 1, "bullet" = 1, "laser" = 1, "energy" = 1, "bomb" = 1, "bio" = 1, "rad" = 1.5, "fire" = 1.5, "acid" = 1.5) beauty_modifier = 0.2 diff --git a/code/datums/mood_events/generic_negative_events.dm b/code/datums/mood_events/generic_negative_events.dm index 787d6375a7..38b004a657 100644 --- a/code/datums/mood_events/generic_negative_events.dm +++ b/code/datums/mood_events/generic_negative_events.dm @@ -162,6 +162,11 @@ mood_change = -8 timeout = 3 MINUTES +/datum/mood_event/gates_of_mansus + description = "LIVING IN A PERFORMANCE IS WORSE THAN DEATH\n" + mood_change = -25 + timeout = 4 MINUTES + //These are unused so far but I want to remember them to use them later /datum/mood_event/cloned_corpse diff --git a/code/datums/mood_events/generic_positive_events.dm b/code/datums/mood_events/generic_positive_events.dm index 8f98917ed3..b73756c2b1 100644 --- a/code/datums/mood_events/generic_positive_events.dm +++ b/code/datums/mood_events/generic_positive_events.dm @@ -70,6 +70,11 @@ mood_change = 40 //maybe being a cultist isnt that bad after all hidden = TRUE +/datum/mood_event/heretics + description = "THE HIGHER I RISE, THE MORE I SEE.\n" + mood_change = 12 //maybe being a cultist isnt that bad after all + hidden = TRUE + /datum/mood_event/family_heirloom description = "My family heirloom is safe with me.\n" mood_change = 1 diff --git a/code/datums/mood_events/needs_events.dm b/code/datums/mood_events/needs_events.dm index 962681eb94..b307bcb0aa 100644 --- a/code/datums/mood_events/needs_events.dm +++ b/code/datums/mood_events/needs_events.dm @@ -19,6 +19,27 @@ description = "I'm starving!\n" mood_change = -15 +//charge +/datum/mood_event/supercharged + description = "I can't possibly keep all this power inside, I need to release some quick!\n" + mood_change = -10 + +/datum/mood_event/overcharged + description = "I feel dangerously overcharged, perhaps I should release some power.\n" + mood_change = -4 + +/datum/mood_event/charged + description = "I feel the power in my veins!\n" + mood_change = 6 + +/datum/mood_event/lowpower + description = "My power is running low, I should go charge up somewhere.\n" + mood_change = -6 + +/datum/mood_event/decharged + description = "I'm in desperate need of some electricity!\n" + mood_change = -10 + //Disgust /datum/mood_event/gross description = "I saw something gross.\n" diff --git a/code/datums/radiation_wave.dm b/code/datums/radiation_wave.dm index fe018a8761..8dc3b64e16 100644 --- a/code/datums/radiation_wave.dm +++ b/code/datums/radiation_wave.dm @@ -105,7 +105,6 @@ // modify the ignored_things list in __HELPERS/radiation.dm instead var/static/list/blacklisted = typecacheof(list( /turf, - /mob, /obj/structure/cable, /obj/machinery/atmospherics, /obj/item/ammo_casing, diff --git a/code/datums/ruins/space.dm b/code/datums/ruins/space.dm index 5d86290f8f..64b8692ccd 100644 --- a/code/datums/ruins/space.dm +++ b/code/datums/ruins/space.dm @@ -325,6 +325,12 @@ name = "Abductor Replication Lab" description = "Some scientists tried and almost succeeded to recreate abductor tools. Somewhat slower and a bit less modern than their originals, these tools are the best you can get if you aren't an alien." +/datum/map_template/ruin/space/spacediner + id = "spacediner" + suffix = "spacediner.dmm" + name = "Space Diner" + description = "Come, traveler of the bluespace planes. Sit, enjoy a drink and take one of the fair maidens for a night. The exit is the way you came in, via that teleporter thingy, but do remember to stay safe." + //Space ruins for the station z /datum/map_template/ruin/spacenearstation prefix = "_maps/RandomRuins/SpaceRuinsStation/" diff --git a/code/datums/skills/_check_skills.dm b/code/datums/skills/_check_skills.dm index 41939dbee3..91b36a123f 100644 --- a/code/datums/skills/_check_skills.dm +++ b/code/datums/skills/_check_skills.dm @@ -14,11 +14,14 @@ mind.skill_holder.ui_interact(src) -/datum/skill_holder/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.always_state) - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) +/datum/skill_holder/ui_state(mob/user) + return GLOB.always_state + +/datum/skill_holder/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) if(!ui) - ui = new(user, src, ui_key, "SkillPanel", "[owner.name]'s Skills", 620, 580, master_ui, state) - ui.set_autoupdate(FALSE) // This UI is only ever opened by one person, and never is updated outside of user input. + ui = new(user, src, "SkillPanel", "[owner.name]'s Skills") + ui.set_autoupdate(FALSE) ui.open() else if(need_static_data_update) update_static_data(user) diff --git a/code/datums/spawners_menu.dm b/code/datums/spawners_menu.dm index d66445b8a1..95a7d8e633 100644 --- a/code/datums/spawners_menu.dm +++ b/code/datums/spawners_menu.dm @@ -6,10 +6,13 @@ qdel(src) owner = new_owner -/datum/spawners_menu/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.observer_state) - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) +/datum/spawners_menu/ui_state(mob/user) + return GLOB.observer_state + +/datum/spawners_menu/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) if(!ui) - ui = new(user, src, ui_key, "SpawnersMenu", "Spawners Menu", 700, 600, master_ui, state) + ui = new(user, src, "SpawnersMenu") ui.open() /datum/spawners_menu/ui_data(mob/user) @@ -42,11 +45,15 @@ if(..()) return - var/spawner_ref = pick(GLOB.mob_spawners[params["name"]]) - var/obj/effect/mob_spawn/MS = locate(spawner_ref) in GLOB.poi_list - if(!MS) + var/group_name = params["name"] + if(!group_name || !(group_name in GLOB.mob_spawners)) + return + var/list/spawnerlist = GLOB.mob_spawners[group_name] + if(!spawnerlist.len) + return + var/obj/effect/mob_spawn/MS = pick(spawnerlist) + if(!istype(MS) || !(MS in GLOB.poi_list)) return - switch(action) if("jump") if(MS) @@ -55,4 +62,4 @@ if("spawn") if(MS) MS.attack_ghost(owner) - . = TRUE \ No newline at end of file + . = TRUE diff --git a/code/datums/status_effects/debuffs.dm b/code/datums/status_effects/debuffs.dm index 6e59d4fa2c..9cd47403d1 100644 --- a/code/datums/status_effects/debuffs.dm +++ b/code/datums/status_effects/debuffs.dm @@ -403,6 +403,197 @@ owner.underlays -= marked_underlay //if this is being called, we should have an owner at this point. ..() +/datum/status_effect/eldritch + duration = 15 SECONDS + status_type = STATUS_EFFECT_REPLACE + alert_type = null + on_remove_on_mob_delete = TRUE + ///underlay used to indicate that someone is marked + var/mutable_appearance/marked_underlay + ///path for the underlay + var/effect_sprite = "" + +/datum/status_effect/eldritch/on_creation(mob/living/new_owner, ...) + marked_underlay = mutable_appearance('icons/effects/effects.dmi', effect_sprite,BELOW_MOB_LAYER) + return ..() + +/datum/status_effect/eldritch/on_apply() + . = ..() + if(owner.mob_size >= MOB_SIZE_HUMAN) + RegisterSignal(owner,COMSIG_ATOM_UPDATE_OVERLAYS,.proc/update_owner_underlay) + owner.update_icon() + return TRUE + return FALSE + +/datum/status_effect/eldritch/on_remove() + UnregisterSignal(owner,COMSIG_ATOM_UPDATE_OVERLAYS) + owner.update_icon() + return ..() + +/datum/status_effect/eldritch/proc/update_owner_underlay(atom/source, list/overlays) + overlays += marked_underlay + +/datum/status_effect/eldritch/Destroy() + QDEL_NULL(marked_underlay) + return ..() + +/** + * What happens when this mark gets popped + * + * Adds actual functionality to each mark + */ +/datum/status_effect/eldritch/proc/on_effect() + playsound(owner, 'sound/magic/repulse.ogg', 75, TRUE) + qdel(src) //what happens when this is procced. + +//Each mark has diffrent effects when it is destroyed that combine with the mansus grasp effect. +/datum/status_effect/eldritch/flesh + id = "flesh_mark" + effect_sprite = "emark1" + +/datum/status_effect/eldritch/flesh/on_effect() + + if(ishuman(owner)) + var/mob/living/carbon/human/H = owner + var/obj/item/bodypart/bodypart = pick(H.bodyparts) + var/datum/wound/slash/severe/crit_wound = new + crit_wound.apply_wound(bodypart) + return ..() + +/datum/status_effect/eldritch/ash + id = "ash_mark" + effect_sprite = "emark2" + ///Dictates how much damage and stamina loss this mark will cause. + var/repetitions = 1 + +/datum/status_effect/eldritch/ash/on_creation(mob/living/new_owner, _repetition = 5) + . = ..() + repetitions = min(1,_repetition) + +/datum/status_effect/eldritch/ash/on_effect() + if(iscarbon(owner)) + var/mob/living/carbon/carbon_owner = owner + carbon_owner.adjustStaminaLoss(10 * repetitions) + carbon_owner.adjustFireLoss(5 * repetitions) + for(var/mob/living/carbon/victim in range(1,carbon_owner)) + if(IS_HERETIC(victim) || victim == carbon_owner) + continue + victim.apply_status_effect(type,repetitions-1) + break + return ..() + +/datum/status_effect/eldritch/rust + id = "rust_mark" + effect_sprite = "emark3" + +/datum/status_effect/eldritch/rust/on_effect() + if(!iscarbon(owner)) + return + var/mob/living/carbon/carbon_owner = owner + for(var/obj/item/I in carbon_owner.get_all_gear()) //Affects roughly 75% of items + if(!QDELETED(I) && prob(75)) //Just in case + I.take_damage(100) + return ..() + +/datum/status_effect/corrosion_curse + id = "corrosion_curse" + status_type = STATUS_EFFECT_REPLACE + alert_type = null + tick_interval = 1 SECONDS + +/datum/status_effect/corrosion_curse/on_creation(mob/living/new_owner, ...) + . = ..() + to_chat(owner, "Your feel your body starting to break apart...") + +/datum/status_effect/corrosion_curse/tick() + . = ..() + if(!ishuman(owner)) + return + var/mob/living/carbon/human/H = owner + var/chance = rand(0,100) + switch(chance) + if(0 to 19) + H.vomit() + if(20 to 29) + H.Dizzy(10) + if(30 to 39) + H.adjustOrganLoss(ORGAN_SLOT_LIVER,5) + if(40 to 49) + H.adjustOrganLoss(ORGAN_SLOT_HEART,5) + if(50 to 59) + H.adjustOrganLoss(ORGAN_SLOT_STOMACH,5) + if(60 to 69) + H.adjustOrganLoss(ORGAN_SLOT_EYES,10) + if(70 to 79) + H.adjustOrganLoss(ORGAN_SLOT_EARS,10) + if(80 to 89) + H.adjustOrganLoss(ORGAN_SLOT_LUNGS,10) + if(90 to 99) + H.adjustOrganLoss(ORGAN_SLOT_TONGUE,10) + if(100) + H.adjustOrganLoss(ORGAN_SLOT_BRAIN,20) + +/datum/status_effect/amok + id = "amok" + status_type = STATUS_EFFECT_REPLACE + alert_type = null + duration = 10 SECONDS + tick_interval = 1 SECONDS + +/datum/status_effect/amok/on_apply(mob/living/afflicted) + . = ..() + to_chat(owner, "Your feel filled with a rage that is not your own!") + +/datum/status_effect/amok/tick() + . = ..() + var/prev_intent = owner.a_intent + owner.a_intent = INTENT_HARM + + var/list/mob/living/targets = list() + for(var/mob/living/potential_target in oview(owner, 1)) + if(IS_HERETIC(potential_target) || potential_target.mind?.has_antag_datum(/datum/antagonist/heretic_monster)) + continue + targets += potential_target + if(LAZYLEN(targets)) + owner.log_message(" attacked someone due to the amok debuff.", LOG_ATTACK) //the following attack will log itself + owner.ClickOn(pick(targets)) + owner.a_intent = prev_intent + +/datum/status_effect/cloudstruck + id = "cloudstruck" + status_type = STATUS_EFFECT_REPLACE + duration = 3 SECONDS + on_remove_on_mob_delete = TRUE + ///This overlay is applied to the owner for the duration of the effect. + var/mutable_appearance/mob_overlay + +/datum/status_effect/cloudstruck/on_creation(mob/living/new_owner, set_duration) + if(isnum(set_duration)) + duration = set_duration + . = ..() + +/datum/status_effect/cloudstruck/on_apply() + . = ..() + mob_overlay = mutable_appearance('icons/effects/eldritch.dmi', "cloud_swirl", ABOVE_MOB_LAYER) + owner.overlays += mob_overlay + owner.update_icon() + ADD_TRAIT(owner, TRAIT_BLIND, "cloudstruck") + return TRUE + +/datum/status_effect/cloudstruck/on_remove() + . = ..() + if(QDELETED(owner)) + return + REMOVE_TRAIT(owner, TRAIT_BLIND, "cloudstruck") + if(owner) + owner.overlays -= mob_overlay + owner.update_icon() + +/datum/status_effect/cloudstruck/Destroy() + . = ..() + QDEL_NULL(mob_overlay) + + /datum/status_effect/stacking/saw_bleed id = "saw_bleed" tick_interval = 6 diff --git a/code/datums/wires/_wires.dm b/code/datums/wires/_wires.dm index 75bd4f5c17..04fbc4a590 100644 --- a/code/datums/wires/_wires.dm +++ b/code/datums/wires/_wires.dm @@ -97,6 +97,12 @@ /datum/wires/proc/get_wire(color) return colors[color] +/datum/wires/proc/get_color_of_wire(wire_type) + for(var/color in colors) + var/other_type = colors[color] + if(wire_type == other_type) + return color + /datum/wires/proc/get_attached(color) if(assemblies[color]) return assemblies[color] @@ -117,7 +123,7 @@ return TRUE /datum/wires/proc/is_dud(wire) - return findtext(wire, WIRE_DUD_PREFIX) + return findtext(wire, WIRE_DUD_PREFIX, 1, length(WIRE_DUD_PREFIX) + 1) /datum/wires/proc/is_dud_color(color) return is_dud(get_wire(color)) @@ -197,6 +203,7 @@ S.forceMove(holder.drop_location()) return S +/// Called from [/atom/proc/emp_act] /datum/wires/proc/emp_pulse() var/list/possible_wires = shuffle(wires) var/remaining_pulses = MAXIMUM_EMP_WIRES @@ -239,11 +246,13 @@ return ..() return UI_CLOSE -/datum/wires/ui_interact(mob/user, ui_key = "wires", datum/tgui/ui = null, force_open = FALSE, \ - datum/tgui/master_ui = null, datum/ui_state/state = GLOB.physical_state) - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) +/datum/wires/ui_state(mob/user) + return GLOB.physical_state + +/datum/wires/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) if (!ui) - ui = new(user, src, ui_key, "Wires", "[holder.name] Wires", 350, 150 + wires.len * 30, master_ui, state) + ui = new(user, src, "Wires", "[holder.name] Wires") ui.open() /datum/wires/ui_data(mob/user) diff --git a/code/datums/wires/airlock.dm b/code/datums/wires/airlock.dm index 2b13344cc6..6cef7ac50f 100644 --- a/code/datums/wires/airlock.dm +++ b/code/datums/wires/airlock.dm @@ -53,11 +53,10 @@ /datum/wires/airlock/interactable(mob/user) var/obj/machinery/door/airlock/A = holder - if(!A.panel_open) - return FALSE if(!A.hasSiliconAccessInArea(user) && A.isElectrified() && A.shock(user, 100)) return FALSE - return TRUE + if(A.panel_open) + return TRUE /datum/wires/airlock/get_status() var/obj/machinery/door/airlock/A = holder @@ -115,10 +114,7 @@ A.aiControlDisabled = -1 if(WIRE_SHOCK) // Pulse to shock the door for 10 ticks. if(!A.secondsElectrified) - A.set_electrified(30) - if(usr) - LAZYADD(A.shockedby, text("\[[TIME_STAMP("hh:mm:ss", FALSE)]\] [key_name(usr)]")) - log_combat(usr, A, "electrified") + A.set_electrified(30, usr) if(WIRE_SAFETY) A.safe = !A.safe if(!A.density) @@ -135,21 +131,17 @@ if(WIRE_POWER1, WIRE_POWER2) // Cut to loose power, repair all to gain power. if(mend && !is_cut(WIRE_POWER1) && !is_cut(WIRE_POWER2)) A.regainMainPower() - if(usr) - A.shock(usr, 50) else A.loseMainPower() - if(usr) - A.shock(usr, 50) + if(isliving(usr)) + A.shock(usr, 50) if(WIRE_BACKUP1, WIRE_BACKUP2) // Cut to loose backup power, repair all to gain backup power. if(mend && !is_cut(WIRE_BACKUP1) && !is_cut(WIRE_BACKUP2)) A.regainBackupPower() - if(usr) - A.shock(usr, 50) else A.loseBackupPower() - if(usr) - A.shock(usr, 50) + if(isliving(usr)) + A.shock(usr, 50) if(WIRE_BOLTS) // Cut to drop bolts, mend does nothing. if(!mend) A.bolt() @@ -170,10 +162,7 @@ A.set_electrified(0) else if(A.secondsElectrified != -1) - A.set_electrified(-1) - if(usr) - LAZYADD(A.shockedby, text("\[[TIME_STAMP("hh:mm:ss", FALSE)]\] [key_name(usr)]")) - log_combat(usr, A, "electrified") + A.set_electrified(-1, usr) if(WIRE_SAFETY) // Cut to disable safeties, mend to re-enable. A.safe = mend if(WIRE_TIMING) // Cut to disable auto-close, mend to re-enable. @@ -184,5 +173,5 @@ A.lights = mend A.update_icon() if(WIRE_ZAP1, WIRE_ZAP2) // Ouch. - if(usr) - A.shock(usr, 50) + if(isliving(usr)) + A.shock(usr, 50) \ No newline at end of file diff --git a/code/game/area/areas.dm b/code/game/area/areas.dm index f87f7a757c..672d5c096f 100644 --- a/code/game/area/areas.dm +++ b/code/game/area/areas.dm @@ -16,6 +16,8 @@ /// If it's valid territory for gangs/cults to summon var/valid_territory = TRUE + /// malf ais can hack this + var/valid_malf_hack = TRUE /// if blobs can spawn there and if it counts towards their score. var/blob_allowed = TRUE /// whether servants can warp into this area from Reebe @@ -572,6 +574,7 @@ GLOBAL_LIST_EMPTY(teleportlocs) power_environ = FALSE always_unpowered = FALSE valid_territory = FALSE + valid_malf_hack = FALSE blob_allowed = FALSE addSorted() diff --git a/code/game/atoms.dm b/code/game/atoms.dm index de9df3a23e..8a66394ecc 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -26,7 +26,6 @@ var/list/atom_colours //used to store the different colors on an atom //its inherent color, the colored paint applied on it, special color effect etc... - var/list/priority_overlays //overlays that should remain on top and not normally removed when using cut_overlay functions, like c4. var/list/remove_overlays // a very temporary list of overlays to remove var/list/add_overlays // a very temporary list of overlays to add @@ -145,7 +144,6 @@ qdel(reagents) LAZYCLEARLIST(overlays) - LAZYCLEARLIST(priority_overlays) for(var/i in targeted_by) var/mob/M = i @@ -962,15 +960,16 @@ if(source != target) target.log_talk(message, message_type, tag="[tag] from [key_name(source)]", log_globally=FALSE) -/* -Proc for attack log creation, because really why not -1 argument is the actor performing the action -2 argument is the target of the action -3 is a verb describing the action (e.g. punched, throwed, kicked, etc.) -4 is a tool with which the action was made (usually an item) -5 is any additional text, which will be appended to the rest of the log line -*/ - +/** + * Log a combat message in the attack log + * + * Arguments: + * * atom/user - argument is the actor performing the action + * * atom/target - argument is the target of the action + * * what_done - is a verb describing the action (e.g. punched, throwed, kicked, etc.) + * * atom/object - is a tool with which the action was made (usually an item) + * * addition - is any additional text, which will be appended to the rest of the log line + */ /proc/log_combat(atom/user, atom/target, what_done, atom/object=null, addition=null) var/ssource = key_name(user) var/starget = key_name(target) @@ -1120,3 +1119,11 @@ Proc for attack log creation, because really why not max_grav = max(G.setting,max_grav) return max_grav return SSmapping.level_trait(T.z, ZTRAIT_GRAVITY) + +/** + * Causes effects when the atom gets hit by a rust effect from heretics + * + * Override this if you want custom behaviour in whatever gets hit by the rust + */ +/atom/proc/rust_heretic_act() + return diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm index 0238529195..0a6c2b9eca 100644 --- a/code/game/atoms_movable.dm +++ b/code/game/atoms_movable.dm @@ -646,3 +646,10 @@ animate(I, alpha = 175, pixel_x = to_x, pixel_y = to_y, time = 3, transform = M, easing = CUBIC_EASING) sleep(1) animate(I, alpha = 0, transform = matrix(), time = 1) + +/atom/movable/proc/set_anchored(anchorvalue) //literally only for plumbing ran + SHOULD_CALL_PARENT(TRUE) + if(anchored == anchorvalue) + return + . = anchored + anchored = anchorvalue diff --git a/code/game/gamemodes/clock_cult/clock_cult.dm b/code/game/gamemodes/clock_cult/clock_cult.dm index 406e142a25..be8dee5bf8 100644 --- a/code/game/gamemodes/clock_cult/clock_cult.dm +++ b/code/game/gamemodes/clock_cult/clock_cult.dm @@ -224,8 +224,7 @@ Credit where due: qdel(S) if(S && !QDELETED(S)) to_chat(L, "[slot] is a clockwork slab, a multipurpose tool used to construct machines and invoke ancient words of power. If this is your first time \ - as a servant, you can find a concise tutorial in the Recollection category of its interface.") - to_chat(L, "If you want more information, you can read the wiki page to learn more.") + as a servant, you can read the wiki page to learn more.") return TRUE return FALSE diff --git a/code/game/gamemodes/dynamic/dynamic_rulesets_latejoin.dm b/code/game/gamemodes/dynamic/dynamic_rulesets_latejoin.dm index da33da5f43..63574c6475 100644 --- a/code/game/gamemodes/dynamic/dynamic_rulesets_latejoin.dm +++ b/code/game/gamemodes/dynamic/dynamic_rulesets_latejoin.dm @@ -191,6 +191,24 @@ SSticker.mode_result = "loss - rev heads killed" SSticker.news_report = REVS_LOSE +////////////////////////////////////////////// +// // +// HERETIC SMUGGLER // +// // +////////////////////////////////////////////// + +/datum/dynamic_ruleset/latejoin/heretic_smuggler + name = "Heretic Smuggler" + antag_datum = /datum/antagonist/heretic + antag_flag = ROLE_HERETIC + protected_roles = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Quartermaster") + restricted_roles = list("AI","Cyborg") + required_candidates = 1 + weight = 4 + cost = 10 + requirements = list(40,30,20,10,10,10,10,10,10,10) + repeatable = TRUE + ////////////////////////////////////////////// // // // BLOODSUCKERS // diff --git a/code/game/gamemodes/dynamic/dynamic_rulesets_roundstart.dm b/code/game/gamemodes/dynamic/dynamic_rulesets_roundstart.dm index edaadeae1c..766ddcefc7 100644 --- a/code/game/gamemodes/dynamic/dynamic_rulesets_roundstart.dm +++ b/code/game/gamemodes/dynamic/dynamic_rulesets_roundstart.dm @@ -143,6 +143,46 @@ changeling.add_antag_datum(new_antag) return TRUE +////////////////////////////////////////////// +// // +// ELDRITCH CULT // +// // +////////////////////////////////////////////// + +/datum/dynamic_ruleset/roundstart/heretics + name = "Heretics" + antag_flag = ROLE_HERETIC + antag_datum = /datum/antagonist/heretic + protected_roles = list("Prisoner","Security Officer", "Warden", "Detective", "Head of Security", "Captain") + restricted_roles = list("AI", "Cyborg") + required_candidates = 1 + weight = 3 + cost = 20 + scaling_cost = 15 + requirements = list(50,45,45,40,35,20,20,15,10,10) + antag_cap = list(1,1,1,1,2,2,2,2,3,3) + + +/datum/dynamic_ruleset/roundstart/heretics/pre_execute() + . = ..() + var/num_ecult = antag_cap[indice_pop] * (scaled_times + 1) + + for (var/i = 1 to num_ecult) + var/mob/picked_candidate = pick_n_take(candidates) + assigned += picked_candidate.mind + picked_candidate.mind.restricted_roles = restricted_roles + picked_candidate.mind.special_role = ROLE_HERETIC + return TRUE + +/datum/dynamic_ruleset/roundstart/heretics/execute() + + for(var/c in assigned) + var/datum/mind/cultie = c + var/datum/antagonist/heretic/new_antag = new antag_datum() + cultie.add_antag_datum(new_antag) + + return TRUE + ////////////////////////////////////////////// // // // WIZARDS // diff --git a/code/game/gamemodes/dynamic/dynamic_storytellers.dm b/code/game/gamemodes/dynamic/dynamic_storytellers.dm index 561b38fde1..148de9568a 100644 --- a/code/game/gamemodes/dynamic/dynamic_storytellers.dm +++ b/code/game/gamemodes/dynamic/dynamic_storytellers.dm @@ -50,10 +50,6 @@ Property weights are: for(var/r in SSevents.running) var/datum/round_event/R = r threat += R.threat() - for(var/mob/living/simple_animal/hostile/H in GLOB.mob_living_list) - var/turf/T = get_turf(H) - if(H.stat != DEAD && is_station_level(T.z) && !("Station" in H.faction)) - threat += H.threat() for(var/obj/item/phylactery/P in GLOB.poi_list) threat += 25 // can't be giving them too much of a break for (var/mob/M in mode.current_players[CURRENT_LIVING_PLAYERS]) @@ -91,6 +87,8 @@ Property weights are: mean += 2.5 if(CHAOS_MAX) mean += 5 + else + voters += 0.5 if(voters) GLOB.dynamic_curve_centre += (mean/voters) if(flags & USE_PREV_ROUND_WEIGHTS) @@ -128,7 +126,8 @@ Property weights are: for(var/property in property_weights) if(property in rule.property_weights) // just treat it as 0 if it's not in there property_weight += rule.property_weights[property] * property_weights[property] - drafted_rules[rule] = (rule.get_weight() * property_weight)*rule.weight_mult + if(property_weight > 0) + drafted_rules[rule] = rule.get_weight() * property_weight * rule.weight_mult return drafted_rules /datum/dynamic_storyteller/proc/midround_draft() @@ -140,25 +139,26 @@ Property weights are: if (GLOB.dynamic_classic_secret && !((rule.flags & TRAITOR_RULESET) || (rule.flags & MINOR_RULESET))) continue rule.trim_candidates() - var/threat_weight = 1 - if(!(rule.flags & MINOR_RULESET)) // makes the traitor rulesets always possible anyway - var/cost_difference = abs(rule.cost-(mode.threat_level-mode.threat)) - /* Basically, the closer the cost is to the current threat-level-away-from-threat, the more likely it is to - pick this particular ruleset. - Let's use a toy example: there's 60 threat level and 10 threat spent. - We want to pick a ruleset that's close to that, so we run the below equation, on two rulesets. - Ruleset 1 has 30 cost, ruleset 2 has 5 cost. - When we do the math, ruleset 1's threat_weight is 0.538, and ruleset 2's is 0.238, meaning ruleset 1 - is 2.26 times as likely to be picked, all other things considered. - Of course, we don't want it to GUARANTEE the closest, that's no fun, so it's just a weight. - */ - threat_weight = abs(1-abs(1-LOGISTIC_FUNCTION(2,0.05,cost_difference,0))) if (rule.ready()) var/property_weight = 0 for(var/property in property_weights) - if(property in rule.property_weights) + if(property in rule.property_weights) // just treat it as 0 if it's not in there property_weight += rule.property_weights[property] * property_weights[property] - drafted_rules[rule] = round(((rule.get_weight() * property_weight)*rule.weight_mult*threat_weight)*1000,1) + if(property_weight > 0) + var/threat_weight = 1 + if(!(rule.flags & TRAITOR_RULESET) || (rule.flags & MINOR_RULESET)) // makes the traitor rulesets always possible anyway + var/cost_difference = abs(rule.cost-(mode.threat_level-mode.threat)) + /* Basically, the closer the cost is to the current threat-level-away-from-threat, the more likely it is to + pick this particular ruleset. + Let's use a toy example: there's 60 threat level and 10 threat spent. + We want to pick a ruleset that's close to that, so we run the below equation, on two rulesets. + Ruleset 1 has 30 cost, ruleset 2 has 5 cost. + When we do the math, ruleset 1's threat_weight is 0.538, and ruleset 2's is 0.238, meaning ruleset 1 + is 2.26 times as likely to be picked, all other things considered. + Of course, we don't want it to GUARANTEE the closest, that's no fun, so it's just a weight. + */ + threat_weight = abs(1-abs(1-LOGISTIC_FUNCTION(2,0.05,cost_difference,0))) + drafted_rules[rule] = rule.get_weight() * property_weight * rule.weight_mult * threat_weight return drafted_rules /datum/dynamic_storyteller/proc/latejoin_draft(mob/living/carbon/human/newPlayer) @@ -175,28 +175,29 @@ Property weights are: rule.candidates = list(newPlayer) rule.trim_candidates() - var/threat_weight = 1 - if(!(rule.flags & MINOR_RULESET)) - var/cost_difference = abs(rule.cost-(mode.threat_level-mode.threat)) - threat_weight = 1-abs(1-(LOGISTIC_FUNCTION(2,0.05,cost_difference,0))) if (rule.ready()) var/property_weight = 0 for(var/property in property_weights) if(property in rule.property_weights) property_weight += rule.property_weights[property] * property_weights[property] - drafted_rules[rule] = round(((rule.get_weight() * property_weight)*rule.weight_mult*threat_weight)*1000,1) + if(property_weight > 0) + var/threat_weight = 1 + if(!(rule.flags & TRAITOR_RULESET) || (rule.flags & MINOR_RULESET)) + var/cost_difference = abs(rule.cost-(mode.threat_level-mode.threat)) + threat_weight = 1-abs(1-(LOGISTIC_FUNCTION(2,0.05,cost_difference,0))) + drafted_rules[rule] = rule.get_weight() * property_weight * rule.weight_mult * threat_weight return drafted_rules /datum/dynamic_storyteller/proc/event_draft() var/list/drafted_rules = list() for(var/datum/dynamic_ruleset/event/rule in mode.events) - if(rule.acceptable(mode.current_players[CURRENT_LIVING_PLAYERS].len, mode.threat_level) && (mode.threat_level - mode.threat) >= rule.cost) - if(rule.ready()) - var/property_weight = 0 - for(var/property in property_weights) - if(property in rule.property_weights) - property_weight += rule.property_weights[property] * property_weights[property] - drafted_rules[rule] = (rule.get_weight() + property_weight)*rule.weight_mult + if(rule.acceptable(mode.current_players[CURRENT_LIVING_PLAYERS].len, mode.threat_level) && (mode.threat_level + 20 - mode.threat) >= rule.cost && rule.ready()) + var/property_weight = 0 + for(var/property in property_weights) + if(property in rule.property_weights) + property_weight += rule.property_weights[property] * property_weights[property] + if(property_weight > 0) + drafted_rules[rule] = rule.get_weight() + property_weight * rule.weight_mult return drafted_rules @@ -313,9 +314,8 @@ Property weights are: /datum/dynamic_storyteller/random/event_draft() var/list/drafted_rules = list() for(var/datum/dynamic_ruleset/event/rule in mode.events) - if(rule.acceptable(mode.current_players[CURRENT_LIVING_PLAYERS].len, mode.threat_level)) - if(rule.ready()) - drafted_rules[rule] = 1 + if(rule.acceptable(mode.current_players[CURRENT_LIVING_PLAYERS].len, mode.threat_level) && rule.ready()) + drafted_rules[rule] = 1 return drafted_rules /datum/dynamic_storyteller/story @@ -330,7 +330,7 @@ Property weights are: /datum/dynamic_storyteller/story/calculate_threat() var/current_time = (world.time / SSautotransfer.targettime)*180 - mode.threat_level = round(mode.initial_threat_level*(sin(current_time)+0.25),0.1) + mode.threat_level = round((mode.initial_threat_level*(sin(current_time)/2)+0.75),0.1) return ..() /datum/dynamic_storyteller/classic diff --git a/code/game/gamemodes/eldritch_cult/eldritch_cult.dm b/code/game/gamemodes/eldritch_cult/eldritch_cult.dm new file mode 100644 index 0000000000..20a129a5a3 --- /dev/null +++ b/code/game/gamemodes/eldritch_cult/eldritch_cult.dm @@ -0,0 +1,67 @@ +/datum/game_mode/heretics + name = "heresy" + config_tag = "heresy" + antag_flag = ROLE_HERETIC + false_report_weight = 5 + restricted_jobs = list("AI", "Cyborg") + protected_jobs = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Quartermaster") //citadel change - adds HoP, CE, CMO, and RD to heretic role blacklist + required_players = 15 + required_enemies = 1 + recommended_enemies = 4 + reroll_friendly = 1 + enemy_minimum_age = 0 + round_ends_with_antag_death = 0 + + announce_span = "danger" + announce_text = "Heretics have been spotted on the station!\n\ + Heretics: Accomplish your objectives.\n\ + Crew: Do not let the madman succeed!" + + var/ecult_possible = 4 //hard limit on culties if scaling is turned off + var/num_ecult = 1 + var/list/culties = list() + +/datum/game_mode/heretics/pre_setup() + + if(CONFIG_GET(flag/protect_roles_from_antagonist)) + restricted_jobs += protected_jobs + + if(CONFIG_GET(flag/protect_assistant_from_antagonist)) + restricted_jobs += "Assistant" + + + var/esc = CONFIG_GET(number/ecult_scaling_coeff) + if(esc) + num_ecult = min(max(1, min(round(num_players() / (esc * 2)) + 2, round(num_players() / esc))),4) + else + num_ecult = max(1, min(num_players(), ecult_possible)) + + for(var/i in 1 to num_ecult) + if(!antag_candidates.len) + break + var/datum/mind/cultie = antag_pick(antag_candidates) + antag_candidates -= cultie + cultie.special_role = ROLE_HERETIC + cultie.restricted_roles = restricted_jobs + culties += cultie + + var/enough_heretics = culties.len > 0 + + if(!enough_heretics) + setup_error = "Not enough heretic candidates" + return FALSE + else + for(var/antag in culties) + return TRUE + +/datum/game_mode/heretics/post_setup() + for(var/c in culties) + var/datum/mind/cultie = c + log_game("[key_name(cultie)] has been selected as a heretic!") + var/datum/antagonist/heretic/new_antag = new() + cultie.add_antag_datum(new_antag) + return ..() + +/datum/game_mode/heretics/generate_report() + return "Cybersun Industries has announced that they have successfully raided a high-security library. The library contained a very dangerous book that was \ + shown to posses anomalous properties. We suspect that the book has been copied over, Stay vigilant!" diff --git a/code/game/machinery/Sleeper.dm b/code/game/machinery/Sleeper.dm index 55976d69c2..047e6c955f 100644 --- a/code/game/machinery/Sleeper.dm +++ b/code/game/machinery/Sleeper.dm @@ -12,9 +12,9 @@ density = FALSE state_open = TRUE circuit = /obj/item/circuitboard/machine/sleeper - req_access = list(ACCESS_CMO) //Used for reagent deletion and addition of non medicines + var/efficiency = 1 - var/min_health = 30 + var/min_health = -25 var/list/available_chems var/controls_inside = FALSE var/list/possible_chems = list( @@ -31,32 +31,13 @@ /obj/machinery/sleeper/Initialize() . = ..() - create_reagents(500, NO_REACT) + // if(mapload) + // component_parts -= circuit + // QDEL_NULL(circuit) occupant_typecache = GLOB.typecache_living update_icon() reset_chem_buttons() RefreshParts() - add_inital_chems() - new_occupant_dir = dir - -/obj/machinery/sleeper/setDir(newdir) - . = ..() - new_occupant_dir = dir - -/obj/machinery/sleeper/on_deconstruction() - var/obj/item/reagent_containers/sleeper_buffer/buffer = new (loc) - buffer.volume = reagents.maximum_volume - buffer.reagents.maximum_volume = reagents.maximum_volume - reagents.trans_to(buffer.reagents, reagents.total_volume) - -/obj/machinery/sleeper/proc/add_inital_chems() - for(var/i in available_chems) - var/datum/reagent/R = reagents.has_reagent(i) - if(!R) - reagents.add_reagent(i, (20)) - continue - if(R.volume < 20) - reagents.add_reagent(i, (20 - R.volume)) /obj/machinery/sleeper/RefreshParts() var/E @@ -73,15 +54,11 @@ available_chems |= possible_chems[i] reset_chem_buttons() - //Total container size 500 - 2000u - if(reagents) - reagents.maximum_volume = (500*E) - - /obj/machinery/sleeper/update_icon_state() - icon_state = initial(icon_state) if(state_open) - icon_state += "-open" + icon_state = "[initial(icon_state)]-open" + else + icon_state = initial(icon_state) /obj/machinery/sleeper/container_resist(mob/living/user) visible_message("[occupant] emerges from [src]!", @@ -98,10 +75,12 @@ /obj/machinery/sleeper/open_machine() if(!state_open && !panel_open) + // flick("[initial(icon_state)]-anim", src) ..() /obj/machinery/sleeper/close_machine(mob/user) if((isnull(user) || istype(user)) && state_open && !panel_open) + // flick("[initial(icon_state)]-anim", src) ..(user) var/mob/living/mob_occupant = occupant if(mob_occupant && mob_occupant.stat != DEAD) @@ -112,46 +91,23 @@ if (. & EMP_PROTECT_SELF) return if(is_operational() && occupant) - var/datum/reagent/R = pick(reagents.reagent_list) + var/datum/reagent/R = pick(reagents.reagent_list) //cit specific inject_chem(R.type, occupant) open_machine() - //Is this too much? + //Is this too much? Cit specific if(severity == EMP_HEAVY) var/chem = pick(available_chems) available_chems -= chem available_chems += get_random_reagent_id() reset_chem_buttons() -/obj/machinery/sleeper/attackby(obj/item/I, mob/user, params) - if(istype(I, /obj/item/reagent_containers/sleeper_buffer)) - var/obj/item/reagent_containers/sleeper_buffer/SB = I - if((SB.reagents.total_volume + reagents.total_volume) < reagents.maximum_volume) - SB.reagents.trans_to(reagents, SB.reagents.total_volume) - visible_message("[user] places the [SB] into the [src].") - qdel(SB) - return - else - SB.reagents.trans_to(reagents, SB.reagents.total_volume) - visible_message("[user] adds as much as they can to the [src] from the [SB].") - return - if(istype(I, /obj/item/reagent_containers)) - var/obj/item/reagent_containers/RC = I - if(RC.reagents.total_volume == 0) - to_chat(user, "The [I] is empty!") - for(var/datum/reagent/R in RC.reagents.reagent_list) - if((obj_flags & EMAGGED) || (allowed(usr))) - break - if(!istype(R, /datum/reagent/medicine)) - visible_message("The [src] gives out a hearty boop and rejects the [I]. The Sleeper's screen flashes with a pompous \"Medicines only, please.\"") - return - RC.reagents.trans_to(reagents, 1000) - visible_message("[user] adds as much as they can to the [src] from the [I].") - return - - /obj/machinery/sleeper/MouseDrop_T(mob/target, mob/user) - if(user.stat || user.lying || !Adjacent(user) || !user.Adjacent(target) || !iscarbon(target) || !user.IsAdvancedToolUser()) + if(user.stat || !Adjacent(user) || !user.Adjacent(target) || !iscarbon(target) || !user.IsAdvancedToolUser()) return + if(isliving(user)) + var/mob/living/L = user + if(!(L.mobility_flags & MOBILITY_STAND)) + return close_machine(target) /obj/machinery/sleeper/screwdriver_act(mob/living/user, obj/item/I) @@ -187,31 +143,29 @@ visible_message("[usr] pries open [src].", "You pry open [src].") open_machine() +/obj/machinery/sleeper/ui_state(mob/user) + if(controls_inside) + return GLOB.contained_state + return GLOB.default_state + +/obj/machinery/sleeper/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "Sleeper", name) + ui.open() + /obj/machinery/sleeper/AltClick(mob/user) - . = ..() - if(!user.canUseTopic(src, !hasSiliconAccessInArea(user))) + if(!user.canUseTopic(src, !issilicon(user))) return if(state_open) close_machine() else open_machine() - return TRUE /obj/machinery/sleeper/examine(mob/user) . = ..() . += "Alt-click [src] to [state_open ? "close" : "open"] it." -/obj/machinery/sleeper/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ - datum/tgui/master_ui = null, datum/ui_state/state = GLOB.notcontained_state) - - if(controls_inside && state == GLOB.notcontained_state) - state = GLOB.default_state // If it has a set of controls on the inside, make it actually controllable by the mob in it. - - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) - if(!ui) - ui = new(user, src, ui_key, "Sleeper", name, 550, 700, master_ui, state) - ui.open() - /obj/machinery/sleeper/process() ..() check_nap_violations() @@ -221,22 +175,13 @@ /obj/machinery/sleeper/ui_data() var/list/data = list() - var/chemical_list = list() - var/blood_percent = 0 - data["occupied"] = occupant ? 1 : 0 data["open"] = state_open - data["blood_levels"] = blood_percent - data["blood_status"] = "Patient either has no blood, or does not require it to function." - data["chemical_list"] = chemical_list data["chems"] = list() for(var/chem in available_chems) - var/datum/reagent/R = reagents.has_reagent(chem) - R = GLOB.chemical_reagents_list[chem] - data["synthchems"] += list(list("name" = R.name, "id" = R.type, "synth_allowed" = synth_allowed(chem))) - for(var/datum/reagent/R in reagents.reagent_list) - data["chems"] += list(list("name" = R.name, "id" = R.type, "vol" = R.volume, "purity" = R.purity, "allowed" = chem_allowed(R.type))) + var/datum/reagent/R = GLOB.chemical_reagents_list[chem] + data["chems"] += list(list("name" = R.name, "id" = R.type, "allowed" = chem_allowed(chem))) data["occupant"] = list() var/mob/living/mob_occupant = occupant @@ -264,40 +209,10 @@ data["occupant"]["fireLoss"] = mob_occupant.getFireLoss() data["occupant"]["cloneLoss"] = mob_occupant.getCloneLoss() data["occupant"]["brainLoss"] = mob_occupant.getOrganLoss(ORGAN_SLOT_BRAIN) - - if(mob_occupant.reagents.reagent_list.len) + data["occupant"]["reagents"] = list() + if(mob_occupant.reagents && mob_occupant.reagents.reagent_list.len) for(var/datum/reagent/R in mob_occupant.reagents.reagent_list) - chemical_list += list(list("name" = R.name, "volume" = R.volume)) - else - chemical_list = "Patient has no reagents." - - data["occupant"]["failing_organs"] = list() - var/mob/living/carbon/C = mob_occupant - if(C) - for(var/obj/item/organ/Or in C.getFailingOrgans()) - if(istype(Or, /obj/item/organ/brain)) - continue - data["occupant"]["failing_organs"] += list(list("name" = Or.name)) - - if(istype(C)) //Non-carbons shouldn't be able to enter sleepers, but this is to prevent runtimes if something ever breaks - if(mob_occupant.has_dna()) // Blood-stuff is mostly a copy-paste from the healthscanner. - blood_percent = round((C.blood_volume / BLOOD_VOLUME_NORMAL)*100) - var/blood_id = C.get_blood_id() - var/blood_warning = "" - if(blood_percent < 80) - blood_warning = "Patient has low blood levels." - if(blood_percent < 60) - blood_warning = "Patient has DANGEROUSLY low blood levels." - if(blood_id) - var/blood_type = C.dna.blood_type - if(!(blood_id in GLOB.blood_reagent_types)) // special blood substance - var/datum/reagent/R = GLOB.chemical_reagents_list[blood_id] - if(R) - blood_type = R.name - else - blood_type = blood_id - data["blood_status"] = "Patient has [blood_type] type blood. [blood_warning]" - data["blood_levels"] = blood_percent + data["occupant"]["reagents"] += list(list("name" = R.name, "volume" = R.volume)) return data /obj/machinery/sleeper/ui_act(action, params) @@ -314,37 +229,14 @@ . = TRUE if("inject") var/chem = text2path(params["chem"]) - var/amount = text2num(params["volume"]) if(!is_operational() || !mob_occupant || isnull(chem)) return if(mob_occupant.health < min_health && chem != /datum/reagent/medicine/epinephrine) return - if(inject_chem(chem, usr, amount)) + if(inject_chem(chem, usr)) . = TRUE if(scrambled_chems && prob(5)) to_chat(usr, "Chemical system re-route detected, results may not be as expected!") - if("synth") - var/chem = text2path(params["chem"]) - if(!is_operational()) - return - reagents.add_reagent(chem_buttons[chem], 10) //other_purity = 0.75 for when the mechanics are in - if("purge") - var/chem = text2path(params["chem"]) - if(allowed(usr)) - if(!is_operational()) - return - reagents.remove_reagent(chem, 1000) - return - if(chem in available_chems) - if(!is_operational()) - return - /*var/datum/reagent/R = reagents.has_reagent(chem) //For when purity effects are in - if(R.purity < 0.8)*/ - reagents.remove_reagent(chem, 1000) - else - visible_message("Access Denied.") - playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0) - /obj/machinery/sleeper/emag_act(mob/user) . = ..() @@ -353,10 +245,9 @@ to_chat(user, "You scramble the sleeper's user interface!") return TRUE -//trans to -/obj/machinery/sleeper/proc/inject_chem(chem, mob/user, volume = 10) - if(chem_allowed(chem)) - reagents.trans_id_to(occupant, chem, volume)//emag effect kicks in here so that the "intended" chem is used for all checks, for extra FUUU +/obj/machinery/sleeper/proc/inject_chem(chem, mob/user) + if((chem in available_chems) && chem_allowed(chem)) + occupant.reagents.add_reagent(chem_buttons[chem], 10) //emag effect kicks in here so that the "intended" chem is used for all checks, for extra FUUU if(user) log_combat(user, occupant, "injected [chem] into", addition = "via [src]") return TRUE @@ -369,14 +260,6 @@ var/occ_health = mob_occupant.health > min_health || chem == /datum/reagent/medicine/epinephrine return amount && occ_health -/obj/machinery/sleeper/proc/synth_allowed(chem) - var/datum/reagent/R = reagents.has_reagent(chem) - if(!R) - return TRUE - if(R.volume < 50) - return TRUE - return FALSE - /obj/machinery/sleeper/proc/reset_chem_buttons() scrambled_chems = FALSE LAZYINITLIST(chem_buttons) @@ -416,23 +299,6 @@ component_parts += new /obj/item/stack/cable_coil(null) RefreshParts() -/obj/machinery/sleeper/clockwork - name = "soothing sleeper" - desc = "A large cryogenics unit built from brass. Its surface is pleasantly cool the touch." - icon_state = "sleeper_clockwork" - enter_message = "You hear the gentle hum and click of machinery, and are lulled into a sense of peace." - possible_chems = list(list(/datum/reagent/medicine/epinephrine, /datum/reagent/medicine/salbutamol, /datum/reagent/medicine/bicaridine, - /datum/reagent/medicine/kelotane, /datum/reagent/medicine/oculine, /datum/reagent/medicine/inacusiate, /datum/reagent/medicine/mannitol)) - -/obj/machinery/sleeper/clockwork/process() - if(occupant && isliving(occupant)) - var/mob/living/L = occupant - if(GLOB.clockwork_vitality) //If there's Vitality, the sleeper has passive healing - GLOB.clockwork_vitality = max(0, GLOB.clockwork_vitality - 1) - L.adjustBruteLoss(-1) - L.adjustFireLoss(-1) - L.adjustOxyLoss(-5) - /obj/machinery/sleeper/old icon_state = "oldpod" @@ -443,8 +309,6 @@ idle_power_usage = 3000 circuit = /obj/item/circuitboard/machine/sleeper/party var/leddit = FALSE //Get it like reddit and lead alright fine - ui_x = 310 - ui_y = 400 controls_inside = TRUE possible_chems = list( @@ -477,3 +341,23 @@ /obj/machinery/sleeper/party/emag_act(mob/user) ..() leddit = TRUE + +/obj/machinery/sleeper/clockwork + name = "soothing sleeper" + desc = "A large cryogenics unit built from brass. Its surface is pleasantly cool the touch." + icon_state = "sleeper_clockwork" + enter_message = "You hear the gentle hum and click of machinery, and are lulled into a sense of peace." + possible_chems = list( + list(/datum/reagent/medicine/epinephrine, /datum/reagent/medicine/salbutamol, /datum/reagent/medicine/bicaridine, /datum/reagent/medicine/kelotane, /datum/reagent/medicine/oculine, /datum/reagent/medicine/inacusiate, /datum/reagent/medicine/mannitol) + ) //everything is available at start + fair_market_price = 0 //it's free + +/obj/machinery/sleeper/clockwork/process() + ..() + if(occupant && isliving(occupant)) + var/mob/living/L = occupant + if(GLOB.clockwork_vitality) //If there's Vitality, the sleeper has passive healing + GLOB.clockwork_vitality = max(0, GLOB.clockwork_vitality - 1) + L.adjustBruteLoss(-1) + L.adjustFireLoss(-1) + L.adjustOxyLoss(-5) diff --git a/code/game/machinery/_machinery.dm b/code/game/machinery/_machinery.dm index 3faf6d5727..2b7411d03f 100644 --- a/code/game/machinery/_machinery.dm +++ b/code/game/machinery/_machinery.dm @@ -92,6 +92,7 @@ Class Procs: pressure_resistance = 15 max_integrity = 200 layer = BELOW_OBJ_LAYER //keeps shit coming out of the machine from ending up underneath it. + flags_1 = DEFAULT_RICOCHET_1 flags_ricochet = RICOCHET_HARD ricochet_chance_mod = 0.3 @@ -116,6 +117,7 @@ Class Procs: var/new_occupant_dir = SOUTH //The direction the occupant will be set to look at when entering the machine. var/speed_process = FALSE // Process as fast as possible? var/obj/item/circuitboard/circuit // Circuit to be created and inserted when the machinery is created + var/wire_compatible = FALSE // For storing and overriding ui id and dimensions var/tgui_id // ID of TGUI interface var/ui_style // ID of custom TGUI style (optional) @@ -432,6 +434,7 @@ Class Procs: to_chat(user, "You [anchored ? "un" : ""]secure [src].") setAnchored(!anchored) playsound(src, 'sound/items/deconstruct.ogg', 50, 1) + SEND_SIGNAL(src, COMSIG_OBJ_DEFAULT_UNFASTEN_WRENCH, anchored) return SUCCESSFUL_UNFASTEN return FAILED_UNFASTEN return CANT_UNFASTEN @@ -546,3 +549,6 @@ Class Procs: . = . % 9 AM.pixel_x = -8 + ((.%3)*8) AM.pixel_y = -8 + (round( . / 3)*8) + +/obj/machinery/rust_heretic_act() + take_damage(500, BRUTE, "melee", 1) diff --git a/code/game/machinery/announcement_system.dm b/code/game/machinery/announcement_system.dm index 8db5ca1d17..b004746051 100644 --- a/code/game/machinery/announcement_system.dm +++ b/code/game/machinery/announcement_system.dm @@ -93,13 +93,10 @@ GLOBAL_LIST_EMPTY(announcement_systems) for(var/channel in channels) radio.talk_into(src, message, channel) -//config stuff - -/obj/machinery/announcement_system/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) - . = ..() - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) +/obj/machinery/announcement_system/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) if(!ui) - ui = new(user, src, ui_key, "AutomatedAnnouncement", "Automated Announcement System", 500, 225, master_ui, state) + ui = new(user, src, "AutomatedAnnouncement") ui.open() /obj/machinery/announcement_system/ui_data() diff --git a/code/game/machinery/bank_machine.dm b/code/game/machinery/bank_machine.dm index 8033f538ba..882d0b989c 100644 --- a/code/game/machinery/bank_machine.dm +++ b/code/game/machinery/bank_machine.dm @@ -3,6 +3,7 @@ desc = "A machine used to deposit and withdraw station funds." icon = 'goon/icons/obj/goon_terminals.dmi' idle_power_usage = 100 + var/siphoning = FALSE var/next_warning = 0 var/obj/item/radio/radio @@ -38,7 +39,6 @@ return return ..() - /obj/machinery/computer/bank_machine/process() ..() if(siphoning) @@ -51,7 +51,7 @@ end_syphon() return - playsound(src.loc, 'sound/items/poster_being_created.ogg', 100, 1) + playsound(src, 'sound/items/poster_being_created.ogg', 100, TRUE) syphoning_credits += 200 D.adjust_money(-200) if(next_warning < world.time && prob(15)) @@ -60,17 +60,20 @@ radio.talk_into(src, message, radio_channel) next_warning = world.time + minimum_time_between_warnings -/obj/machinery/computer/bank_machine/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ - datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) +/obj/machinery/computer/bank_machine/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) if(!ui) - ui = new(user, src, ui_key, "BankMachine", name, 320, 165, master_ui, state) + ui = new(user, src, "BankMachine", name) ui.open() /obj/machinery/computer/bank_machine/ui_data(mob/user) var/list/data = list() var/datum/bank_account/D = SSeconomy.get_dep_account(ACCOUNT_CAR) - data["current_balance"] = D.account_balance + + if(D) + data["current_balance"] = D.account_balance + else + data["current_balance"] = 0 data["siphoning"] = siphoning data["station_name"] = station_name() diff --git a/code/game/machinery/computer/Operating.dm b/code/game/machinery/computer/Operating.dm index c8efe319db..a2fdc2336f 100644 --- a/code/game/machinery/computer/Operating.dm +++ b/code/game/machinery/computer/Operating.dm @@ -43,10 +43,13 @@ table.computer = src break -/obj/machinery/computer/operating/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = 0, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.not_incapacitated_state) - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) +/obj/machinery/computer/operating/ui_state(mob/user) + return GLOB.not_incapacitated_state + +/obj/machinery/computer/operating/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) if(!ui) - ui = new(user, src, ui_key, "OperatingComputer", name, 350, 470, master_ui, state) + ui = new(user, src, "OperatingComputer", name) ui.open() /obj/machinery/computer/operating/ui_data(mob/user) @@ -153,6 +156,8 @@ )) return data + + /obj/machinery/computer/operating/ui_act(action, params) if(..()) return diff --git a/code/game/machinery/computer/aifixer.dm b/code/game/machinery/computer/aifixer.dm index d8553854b2..8ebb64097d 100644 --- a/code/game/machinery/computer/aifixer.dm +++ b/code/game/machinery/computer/aifixer.dm @@ -2,14 +2,13 @@ name = "\improper AI system integrity restorer" desc = "Used with intelliCards containing nonfunctional AIs to restore them to working order." req_access = list(ACCESS_CAPTAIN, ACCESS_ROBOTICS, ACCESS_HEADS) - var/mob/living/silicon/ai/occupier = null - var/active = 0 - circuit = /obj/item/circuitboard/computer/aifixer icon_keyboard = "tech_key" icon_screen = "ai-fixer" light_color = LIGHT_COLOR_PINK - ui_x = 370 - ui_y = 360 + circuit = /obj/item/circuitboard/computer/aifixer + + var/mob/living/silicon/ai/occupier = null + var/active = FALSE /obj/machinery/computer/aifixer/attackby(obj/I, mob/user, params) if(occupier && istype(I, /obj/item/screwdriver)) @@ -20,64 +19,45 @@ else return ..() -/obj/machinery/computer/aifixer/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ - datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) + +/obj/machinery/computer/aifixer/ui_interact(mob/user, datum/tgui/ui) //artur didn't port this correctly + ui = SStgui.try_update_ui(user, src, ui) if(!ui) - ui = new(user, src, ui_key, "AiRestorer", name, ui_x, ui_y, master_ui, state) + ui = new(user, src, "AiRestorer", name) ui.open() - var/dat = "" +/obj/machinery/computer/aifixer/ui_data(mob/user) + var/list/data = list() - if (src.occupier) - var/laws - dat += "

Stored AI: [src.occupier.name]

" - dat += "System integrity: [(src.occupier.health+100)/2]%
" + data["ejectable"] = FALSE + data["AI_present"] = FALSE + data["error"] = null + if(!occupier) + data["error"] = "Please transfer an AI unit." + else + data["AI_present"] = TRUE + data["name"] = occupier.name + data["restoring"] = active + data["health"] = (occupier.health + 100) / 2 + data["isDead"] = occupier.stat == DEAD + data["laws"] = occupier.laws.get_law_list(include_zeroth = TRUE, render_html = FALSE) - if (src.occupier.laws.zeroth) - laws += "0: [src.occupier.laws.zeroth]
" + return data - for (var/index = 1, index <= src.occupier.laws.hacked.len, index++) - var/law = src.occupier.laws.hacked[index] - if (length(law) > 0) - var/num = ionnum() - laws += "[num]: [law]
" +/obj/machinery/computer/aifixer/ui_act(action, params) + if(..()) + return + if(!occupier) + active = FALSE - for (var/index = 1, index <= src.occupier.laws.ion.len, index++) - var/law = src.occupier.laws.ion[index] - if (length(law) > 0) - var/num = ionnum() - laws += "[num]: [law]
" - - var/number = 1 - for (var/index = 1, index <= src.occupier.laws.inherent.len, index++) - var/law = src.occupier.laws.inherent[index] - if (length(law) > 0) - laws += "[number]: [law]
" - number++ - - for (var/index = 1, index <= src.occupier.laws.supplied.len, index++) - var/law = src.occupier.laws.supplied[index] - if (length(law) > 0) - laws += "[number]: [law]
" - number++ - - dat += "Laws:
[laws]
" - - if (src.occupier.stat == DEAD) - dat += "AI non-functional" - else - dat += "AI functional" - if (!src.active) - dat += {"

Begin Reconstruction"} - else - dat += "

Reconstruction in process, please wait.
" - dat += {"
Close"} - var/datum/browser/popup = new(user, "computer", "AI System Integrity Restorer", 400, 500) - popup.set_content(dat) - popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state)) - popup.open() - return + switch(action) + if("PRG_beginReconstruction") + if(occupier?.health < 100) + to_chat(usr, "Reconstruction in progress. This will take several minutes.") + playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 25, FALSE) + active = TRUE + occupier.notify_ghost_cloning("Your core files are being restored!", source = src) + . = TRUE /obj/machinery/computer/aifixer/proc/Fix() use_power(1000) @@ -97,17 +77,6 @@ active = Fix() if(oldstat != occupier.stat) update_icon() - updateDialog() - -/obj/machinery/computer/aifixer/Topic(href, href_list) - if(..()) - return - if(href_list["fix"]) - to_chat(usr, "Reconstruction in progress. This will take several minutes.") - playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 25, 0) - active = TRUE - add_fingerprint(usr) - updateUsrDialog() /obj/machinery/computer/aifixer/update_overlays() . = ..() diff --git a/code/game/machinery/computer/apc_control.dm b/code/game/machinery/computer/apc_control.dm index eae2d5fa5b..c14837b8e3 100644 --- a/code/game/machinery/computer/apc_control.dm +++ b/code/game/machinery/computer/apc_control.dm @@ -3,19 +3,19 @@ desc = "Used to remotely control the flow of power to different parts of the station." icon_screen = "solar" icon_keyboard = "power_key" - req_access = list(ACCESS_ENGINE) + req_access = list(ACCESS_CE) circuit = /obj/item/circuitboard/computer/apc_control light_color = LIGHT_COLOR_YELLOW var/mob/living/operator //Who's operating the computer right now var/obj/machinery/power/apc/active_apc //The APC we're using right now - var/list/result_filters //For sorting the results - var/checking_logs = 0 + var/should_log = TRUE + var/restoring = FALSE var/list/logs - var/auth_id = "\[NULL\]" + var/auth_id = "\[NULL\]:" -/obj/machinery/computer/apc_control/Initialize() +/obj/machinery/computer/apc_control/Initialize(mapload, obj/item/circuitboard/C) . = ..() - result_filters = list("Name" = null, "Charge Above" = null, "Charge Below" = null, "Responsive" = null) + logs = list() /obj/machinery/computer/apc_control/process() if(operator && (!operator.Adjacent(src) || stat)) @@ -23,8 +23,8 @@ if(active_apc) if(!active_apc.locked) active_apc.say("Remote access canceled. Interface locked.") - playsound(active_apc, 'sound/machines/boltsdown.ogg', 25, 0) - playsound(active_apc, 'sound/machines/terminal_alert.ogg', 50, 0) + playsound(active_apc, 'sound/machines/boltsdown.ogg', 25, FALSE) + playsound(active_apc, 'sound/machines/terminal_alert.ogg', 50, FALSE) active_apc.locked = TRUE active_apc.update_icon() active_apc.remote_control = null @@ -34,171 +34,163 @@ if(!IsAdminGhost(user)) to_chat(user,"[src] does not support AI control.") //You already have APC access, cheater! return - ..(user) + ..() /obj/machinery/computer/apc_control/proc/check_apc(obj/machinery/power/apc/APC) return APC.z == z && !APC.malfhack && !APC.aidisabled && !(APC.obj_flags & EMAGGED) && !APC.stat && !istype(APC.area, /area/ai_monitored) && !APC.area.outdoors -/obj/machinery/computer/apc_control/ui_interact(mob/living/user) - . = ..() - var/dat - if(authenticated) - if(!checking_logs) - dat += "Logged in as [auth_id].

" - dat += "Filters
" - dat += "Name: [result_filters["Name"] ? result_filters["Name"] : "None set"]
" - dat += "Charge: \>[result_filters["Charge Above"] ? result_filters["Charge Above"] : "NaN"]% and \<[result_filters["Charge Below"] ? result_filters["Charge Below"] : "NaN"]%
" - dat += "Accessible: [result_filters["Responsive"] ? "Non-Responsive Only" : "All"]

" - for(var/A in GLOB.apcs_list) - if(check_apc(A)) - var/obj/machinery/power/apc/APC = A - if(result_filters["Name"] && !findtext(APC.name, result_filters["Name"]) && !findtext(APC.area.name, result_filters["Name"])) - continue - if(result_filters["Charge Above"] && (!APC.cell || (APC.cell && (APC.cell.charge / APC.cell.maxcharge) < result_filters["Charge Above"] / 100))) - continue - if(result_filters["Charge Below"] && APC.cell && (APC.cell.charge / APC.cell.maxcharge) > result_filters["Charge Below"] / 100) - continue - if(result_filters["Responsive"] && !APC.aidisabled) - continue - dat += "[A]
\ - Charge: [APC.cell ? "[DisplayEnergy(APC.cell.charge)] / [DisplayEnergy(APC.cell.maxcharge)] ([round((APC.cell.charge / APC.cell.maxcharge) * 100)]%)" : "No Powercell Installed"]
\ - Area: [APC.area]
\ - [APC.aidisabled || APC.panel_open ? "APC does not respond to interface query." : "APC responds to interface query."]

" - dat += "Check Logs
" - dat += "Log Out
" - if(obj_flags & EMAGGED) - dat += "WARNING: Logging functionality partially disabled from outside source.
" - dat += "Restore logging functionality?
" - else - if(logs.len) - for(var/entry in logs) - dat += "[entry]
" - else - dat += "No activity has been recorded at this time.
" - if(obj_flags & EMAGGED) - dat += "@#%! CLEAR LOGS" - dat += "Return" - operator = user - else - dat = "Please swipe a valid ID to log in..." - var/datum/browser/popup = new(user, "apc_control", name, 600, 400) - popup.set_content(dat) - popup.set_title_image(user.browse_rsc_icon(icon, icon_state)) - popup.open() +/obj/machinery/computer/apc_control/ui_interact(mob/user, datum/tgui/ui) + operator = user + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "ApcControl") + ui.open() -/obj/machinery/computer/apc_control/Topic(href, href_list) +/obj/machinery/computer/apc_control/ui_data(mob/user) + var/list/data = list() + data["auth_id"] = auth_id + data["authenticated"] = authenticated + data["emagged"] = obj_flags & EMAGGED + data["logging"] = should_log + data["restoring"] = restoring + data["logs"] = list() + data["apcs"] = list() + + for(var/entry in logs) + data["logs"] += list(list("entry" = entry)) + + for(var/apc in GLOB.apcs_list) + if(check_apc(apc)) + var/obj/machinery/power/apc/A = apc + var/has_cell = (A.cell) ? TRUE : FALSE + data["apcs"] += list(list( + "name" = A.area.name, + "operating" = A.operating, + "charge" = (has_cell) ? A.cell.percent() : "NOCELL", + "load" = DisplayPower(A.lastused_total), + "charging" = A.charging, + "chargeMode" = A.chargemode, + "eqp" = A.equipment, + "lgt" = A.lighting, + "env" = A.environ, + "responds" = A.aidisabled || A.panel_open, + "ref" = REF(A) + ) + ) + return data + +/obj/machinery/computer/apc_control/ui_act(action, params) if(..()) return - if(!usr || !usr.canUseTopic(src) || stat || QDELETED(src)) - return - if(href_list["authenticate"]) - var/obj/item/card/id/ID = usr.get_idcard(TRUE) - if(ID && istype(ID)) - if(check_access(ID)) + switch(action) + if("log-in") + if(obj_flags & EMAGGED) authenticated = TRUE - auth_id = "[ID.registered_name] ([ID.assignment])" - log_activity("logged in") - if(href_list["log_out"]) - log_activity("logged out") - authenticated = FALSE - auth_id = "\[NULL\]" - if(href_list["restore_logging"]) - to_chat(usr, "[icon2html(src, usr)] Logging functionality restored from backup data.") - obj_flags &= ~EMAGGED - LAZYADD(logs, "-=- Logging restored to full functionality at this point -=-") - if(href_list["access_apc"]) - playsound(src, "terminal_type", 50, 0) - var/obj/machinery/power/apc/APC = locate(href_list["access_apc"]) in GLOB.apcs_list - if(!APC || APC.aidisabled || APC.panel_open || QDELETED(APC)) - to_chat(usr, "[icon2html(src, usr)] APC does not return interface request. Remote access may be disabled.") - return - if(active_apc) - to_chat(usr, "[icon2html(src, usr)] Disconnected from [active_apc].") - active_apc.say("Remote access canceled. Interface locked.") - playsound(active_apc, 'sound/machines/boltsdown.ogg', 25, 0) - playsound(active_apc, 'sound/machines/terminal_alert.ogg', 50, 0) - active_apc.locked = TRUE - active_apc.update_icon() - active_apc.remote_control = null - active_apc = null - to_chat(usr, "[icon2html(src, usr)] Connected to APC in [get_area_name(APC.area, TRUE)]. Interface request sent.") - log_activity("remotely accessed APC in [get_area_name(APC.area, TRUE)]") - APC.remote_control = src - APC.ui_interact(usr) - playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0) - message_admins("[ADMIN_LOOKUPFLW(usr)] remotely accessed [APC] from [src] at [AREACOORD(src)].") - log_game("[key_name(usr)] remotely accessed [APC] from [src] at [AREACOORD(src)].") - if(APC.locked) - APC.say("Remote access detected. Interface unlocked.") - playsound(APC, 'sound/machines/boltsup.ogg', 25, 0) - playsound(APC, 'sound/machines/terminal_alert.ogg', 50, 0) - APC.locked = FALSE - APC.update_icon() - active_apc = APC - if(href_list["name_filter"]) - playsound(src, 'sound/machines/terminal_prompt.ogg', 50, 0) - var/new_filter = stripped_input(usr, "What name are you looking for?", name) - if(!src || !usr || !usr.canUseTopic(src) || stat || QDELETED(src)) - return - log_activity("changed name filter to \"[new_filter]\"") - playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0) - result_filters["Name"] = new_filter - if(href_list["above_filter"]) - playsound(src, 'sound/machines/terminal_prompt.ogg', 50, 0) - var/new_filter = input(usr, "Enter a percentage from 1-100 to sort by (greater than).", name) as null|num - if(!src || !usr || !usr.canUseTopic(src) || stat || QDELETED(src)) - return - log_activity("changed greater than charge filter to \"[new_filter]\"") - if(new_filter) - new_filter = clamp(new_filter, 0, 100) - playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0) - result_filters["Charge Above"] = new_filter - if(href_list["below_filter"]) - playsound(src, 'sound/machines/terminal_prompt.ogg', 50, 0) - var/new_filter = input(usr, "Enter a percentage from 1-100 to sort by (lesser than).", name) as null|num - if(!src || !usr || !usr.canUseTopic(src) || stat || QDELETED(src)) - return - log_activity("changed lesser than charge filter to \"[new_filter]\"") - if(new_filter) - new_filter = clamp(new_filter, 0, 100) - playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0) - result_filters["Charge Below"] = new_filter - if(href_list["access_filter"]) - if(isnull(result_filters["Responsive"])) - result_filters["Responsive"] = 1 - log_activity("sorted by non-responsive APCs only") - else - result_filters["Responsive"] = !result_filters["Responsive"] - log_activity("sorted by all APCs") - playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0) - if(href_list["check_logs"]) - checking_logs = TRUE - log_activity("checked logs") - if(href_list["check_apcs"]) - checking_logs = FALSE - log_activity("checked APCs") - if(href_list["clear_logs"]) - logs = list() - ui_interact(usr) //Refresh the UI after a filter changes + auth_id = "Unknown (Unknown):" + log_activity("[auth_id] logged in to the terminal") + return + var/obj/item/card/id/ID = operator.get_idcard(TRUE) + if(ID && istype(ID)) + if(check_access(ID)) + authenticated = TRUE + auth_id = "[ID.registered_name] ([ID.assignment]):" + log_activity("[auth_id] logged in to the terminal") + playsound(src, 'sound/machines/terminal_on.ogg', 50, FALSE) + else + auth_id = "[ID.registered_name] ([ID.assignment]):" + log_activity("[auth_id] attempted to log into the terminal") + return + auth_id = "Unknown (Unknown):" + log_activity("[auth_id] attempted to log into the terminal") + if("log-out") + log_activity("[auth_id] logged out of the terminal") + playsound(src, 'sound/machines/terminal_off.ogg', 50, FALSE) + authenticated = FALSE + auth_id = "\[NULL\]" + if("toggle-logs") + should_log = !should_log + log_game("[key_name(operator)] set the logs of [src] in [AREACOORD(src)] [should_log ? "On" : "Off"]") + if("restore-console") + restoring = TRUE + addtimer(CALLBACK(src, .proc/restore_comp), rand(3,5) * 9) + if("access-apc") + var/ref = params["ref"] + playsound(src, "terminal_type", 50, FALSE) + var/obj/machinery/power/apc/APC = locate(ref) in GLOB.apcs_list + if(!APC) + return + if(active_apc) + to_chat(operator, "[icon2html(src, auth_id)] Disconnected from [active_apc].") + active_apc.say("Remote access canceled. Interface locked.") + playsound(active_apc, 'sound/machines/boltsdown.ogg', 25, FALSE) + playsound(active_apc, 'sound/machines/terminal_alert.ogg', 50, FALSE) + active_apc.locked = TRUE + active_apc.update_icon() + active_apc.remote_control = null + active_apc = null + APC.remote_control = src + APC.ui_interact(operator) + playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, FALSE) + log_game("[key_name(operator)] remotely accessed [APC] from [src] at [AREACOORD(src)].") + log_activity("[auth_id] remotely accessed APC in [get_area_name(APC.area, TRUE)]") + if(APC.locked) + APC.say("Remote access detected. Interface unlocked.") + playsound(APC, 'sound/machines/boltsup.ogg', 25, FALSE) + playsound(APC, 'sound/machines/terminal_alert.ogg', 50, FALSE) + APC.locked = FALSE + APC.update_icon() + active_apc = APC + if("check-logs") + log_activity("Checked Logs") + if("check-apcs") + log_activity("Checked APCs") + if("toggle-minor") + var/ref = params["ref"] + var/type = params["type"] + var/value = params["value"] + var/obj/machinery/power/apc/target = locate(ref) in GLOB.apcs_list + if(!target) + return + target.vars[type] = target.setsubsystem(text2num(value)) + target.update_icon() + target.update() + var/setTo = "" + switch(target.vars[type]) + if(0) + setTo = "Off" + if(1) + setTo = "Auto Off" + if(2) + setTo = "On" + if(3) + setTo = "Auto On" + log_activity("Set APC [target.area.name] [type] to [setTo]") + log_game("[key_name(operator)] Set APC [target.area.name] [type] to [setTo]]") + if("breaker") + var/ref = params["ref"] + var/obj/machinery/power/apc/target = locate(ref) in GLOB.apcs_list + target.toggle_breaker() + var/setTo = target.operating ? "On" : "Off" + log_activity("Turned APC [target.area.name]'s breaker [setTo]") /obj/machinery/computer/apc_control/emag_act(mob/user) - . = ..() - if(!authenticated) - to_chat(user, "You bypass [src]'s access requirements using your emag.") - authenticated = TRUE - log_activity("logged in") - else - if(obj_flags & EMAGGED) - return - user.visible_message("You emag [src], disabling precise logging and allowing you to clear logs.") - log_game("[key_name(user)] emagged [src] at [AREACOORD(src)], disabling operator tracking.") - obj_flags |= EMAGGED - playsound(src, "sparks", 50, 1) - return TRUE + if(obj_flags & EMAGGED) + return + obj_flags |= EMAGGED + log_game("[key_name(user)] emagged [src] at [AREACOORD(src)]") + playsound(src, "sparks", 50, TRUE) /obj/machinery/computer/apc_control/proc/log_activity(log_text) - var/op_string = operator && !(obj_flags & EMAGGED) ? operator : "\[NULL OPERATOR\]" - LAZYADD(logs, "([STATION_TIME_TIMESTAMP("hh:mm:ss", world.time)]) [op_string] [log_text]") + if(!should_log) + return + LAZYADD(logs, "([STATION_TIME_TIMESTAMP("hh:mm:ss", world.time)]): [auth_id] [log_text]") + +/obj/machinery/computer/apc_control/proc/restore_comp() + obj_flags &= ~EMAGGED + should_log = TRUE + log_game("[key_name(operator)] restored the logs of [src] in [AREACOORD(src)]") + log_activity("-=- Logging restored to full functionality at this point -=-") + restoring = FALSE /mob/proc/using_power_flow_console() for(var/obj/machinery/computer/apc_control/A in range(1, src)) diff --git a/code/game/machinery/computer/atmos_alert.dm b/code/game/machinery/computer/atmos_alert.dm index fbedf62734..50a6d10302 100644 --- a/code/game/machinery/computer/atmos_alert.dm +++ b/code/game/machinery/computer/atmos_alert.dm @@ -19,11 +19,10 @@ SSradio.remove_object(src, receive_frequency) return ..() -/obj/machinery/computer/atmos_alert/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ - datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) +/obj/machinery/computer/atmos_alert/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) if(!ui) - ui = new(user, src, ui_key, "AtmosAlertConsole", name, 350, 300, master_ui, state) + ui = new(user, src, "AtmosAlertConsole", name) ui.open() /obj/machinery/computer/atmos_alert/ui_data(mob/user) @@ -45,11 +44,11 @@ if("clear") var/zone = params["zone"] if(zone in priority_alarms) - to_chat(usr, "Priority alarm for [zone] cleared.") + to_chat(usr, "Priority alarm for [zone] cleared.") priority_alarms -= zone . = TRUE if(zone in minor_alarms) - to_chat(usr, "Minor alarm for [zone] cleared.") + to_chat(usr, "Minor alarm for [zone] cleared.") minor_alarms -= zone . = TRUE update_icon() diff --git a/code/game/machinery/computer/atmos_control.dm b/code/game/machinery/computer/atmos_control.dm index 6ee975b338..4ba8d9f3d3 100644 --- a/code/game/machinery/computer/atmos_control.dm +++ b/code/game/machinery/computer/atmos_control.dm @@ -91,8 +91,6 @@ GLOBAL_LIST_EMPTY(atmos_air_controllers) icon_screen = "tank" icon_keyboard = "atmos_key" circuit = /obj/item/circuitboard/computer/atmos_control - ui_x = 400 - ui_y = 925 var/frequency = FREQ_ATMOS_STORAGE var/list/sensors = list( @@ -123,11 +121,10 @@ GLOBAL_LIST_EMPTY(atmos_air_controllers) SSradio.remove_object(src, frequency) return ..() -/obj/machinery/computer/atmos_control/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ - datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) +/obj/machinery/computer/atmos_control/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) if(!ui) - ui = new(user, src, ui_key, "AtmosControlConsole", name, ui_x, ui_y, master_ui, state) + ui = new(user, src, "AtmosControlConsole", name) ui.open() /obj/machinery/computer/atmos_control/ui_data(mob/user) @@ -265,13 +262,6 @@ GLOBAL_LIST_EMPTY(atmos_air_controllers) for(var/obj/machinery/atmospherics/components/unary/vent_pump/U in devices) U.broadcast_status() -/obj/machinery/computer/atmos_control/tank/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ - datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) - if(!ui) - ui = new(user, src, ui_key, "AtmosControlConsole", name, ui_x, ui_y, master_ui, state) - ui.open() - /obj/machinery/computer/atmos_control/tank/ui_data(mob/user) var/list/data = ..() data["tank"] = TRUE diff --git a/code/game/machinery/computer/camera.dm b/code/game/machinery/computer/camera.dm index 2b3416e1c8..d42291cd3c 100644 --- a/code/game/machinery/computer/camera.dm +++ b/code/game/machinery/computer/camera.dm @@ -5,8 +5,6 @@ icon_keyboard = "security_key" circuit = /obj/item/circuitboard/computer/security light_color = LIGHT_COLOR_RED - ui_x = 870 - ui_y = 708 var/list/network = list("ss13") var/obj/machinery/camera/active_camera @@ -55,11 +53,9 @@ network -= i network += "[idnum][i]" -/obj/machinery/computer/security/ui_interact(\ - mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ - datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) +/obj/machinery/computer/security/ui_interact(mob/user, datum/tgui/ui) // Update UI - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) + ui = SStgui.try_update_ui(user, src, ui) // Show static if can't use the camera if(!active_camera?.can_use()) show_camera_static() @@ -76,10 +72,11 @@ use_power(active_power_usage) // Register map objects user.client.register_map_obj(cam_screen) - user.client.register_map_obj(cam_plane_master) + for(var/plane in cam_plane_master) + user.client.register_map_obj(plane) user.client.register_map_obj(cam_background) // Open UI - ui = new(user, src, ui_key, "CameraConsole", name, ui_x, ui_y, master_ui, state) + ui = new(user, src, "CameraConsole", name) ui.open() /obj/machinery/computer/security/ui_data() diff --git a/code/game/machinery/computer/crew.dm b/code/game/machinery/computer/crew.dm index cd8b5c1c59..19da4f75d8 100644 --- a/code/game/machinery/computer/crew.dm +++ b/code/game/machinery/computer/crew.dm @@ -76,11 +76,10 @@ GLOBAL_DATUM_INIT(crewmonitor, /datum/crewmonitor, new) /datum/crewmonitor/Destroy() return ..() -/datum/crewmonitor/ui_interact(mob/user, ui_key = "crew", datum/tgui/ui = null, force_open = FALSE, \ - datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) +/datum/crewmonitor/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) if (!ui) - ui = new(user, src, ui_key, "CrewConsole", "crew monitor", 800, 600 , master_ui, state) + ui = new(user, src, "CrewConsole") ui.open() /datum/crewmonitor/proc/show(mob/M, source) diff --git a/code/game/machinery/computer/dna_console.dm b/code/game/machinery/computer/dna_console.dm index 2dce50aa88..286c106788 100644 --- a/code/game/machinery/computer/dna_console.dm +++ b/code/game/machinery/computer/dna_console.dm @@ -220,9 +220,7 @@ /obj/machinery/computer/scan_consolenew/examine(mob/user) . = ..() -/obj/machinery/computer/scan_consolenew/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = 0, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) - . = ..() - +/obj/machinery/computer/scan_consolenew/ui_interact(mob/user, datum/tgui/ui) // Most of ui_interact is spent setting variables for passing to the tgui // interface. // We can also do some general state processing here too as it's a good @@ -264,10 +262,9 @@ time_to_pulse = round((rad_pulse_timer - world.time)/10) // Attempt to update tgui ui, open and update if needed. - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) - + ui = SStgui.try_update_ui(user, src, ui) if(!ui) - ui = new(user, src, ui_key, "DnaConsole", name, 539, 710, master_ui, state) + ui = new(user, src, "DnaConsole") ui.open() /obj/machinery/computer/scan_consolenew/ui_data(mob/user) diff --git a/code/game/machinery/computer/launchpad_control.dm b/code/game/machinery/computer/launchpad_control.dm index fdbe2f1060..b2f7ae73a1 100644 --- a/code/game/machinery/computer/launchpad_control.dm +++ b/code/game/machinery/computer/launchpad_control.dm @@ -53,10 +53,10 @@ var/obj/machinery/launchpad/pad = launchpads[number] return pad -/obj/machinery/computer/launchpad/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = 0, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) +/obj/machinery/computer/launchpad/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) if(!ui) - ui = new(user, src, ui_key, "LaunchpadConsole", name, ui_x, ui_y, master_ui, state) + ui = new(user, src, "LaunchpadConsole", name) ui.open() /obj/machinery/computer/launchpad/ui_data(mob/user) @@ -128,4 +128,4 @@ if("pull") teleport(usr, current_pad, FALSE) . = TRUE - . = TRUE \ No newline at end of file + . = TRUE diff --git a/code/game/machinery/computer/prisoner/gulag_teleporter.dm b/code/game/machinery/computer/prisoner/gulag_teleporter.dm index dd925fbe3b..13727b585b 100644 --- a/code/game/machinery/computer/prisoner/gulag_teleporter.dm +++ b/code/game/machinery/computer/prisoner/gulag_teleporter.dm @@ -6,8 +6,6 @@ icon_keyboard = "security_key" req_access = list(ACCESS_ARMORY) circuit = /obj/item/circuitboard/computer/gulag_teleporter_console - ui_x = 350 - ui_y = 295 var/default_goal = 200 var/obj/machinery/gulag_teleporter/teleporter = null @@ -21,11 +19,10 @@ . = ..() scan_machinery() -/obj/machinery/computer/prisoner/gulag_teleporter_computer/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ - datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) +/obj/machinery/computer/prisoner/gulag_teleporter_computer/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) if(!ui) - ui = new(user, src, ui_key, "GulagTeleporterConsole", name, ui_x, ui_y, master_ui, state) + ui = new(user, src, "GulagTeleporterConsole", name) ui.open() /obj/machinery/computer/prisoner/gulag_teleporter_computer/ui_data(mob/user) diff --git a/code/game/machinery/computer/robot.dm b/code/game/machinery/computer/robot.dm index 4fd9665b1d..401d05da12 100644 --- a/code/game/machinery/computer/robot.dm +++ b/code/game/machinery/computer/robot.dm @@ -23,11 +23,10 @@ return return TRUE -/obj/machinery/computer/robotics/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ - datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) +/obj/machinery/computer/robotics/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) if(!ui) - ui = new(user, src, ui_key, "RoboticsControlConsole", name, ui_x, ui_y, master_ui, state) + ui = new(user, src, "RoboticsControlConsole", name) ui.open() /obj/machinery/computer/robotics/ui_data(mob/user) @@ -123,5 +122,5 @@ var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread s.set_up(3, TRUE, D) s.start() - D.visible_message("\the [D] self destructs!") + D.visible_message("\the [D] self-destructs!") D.gib() diff --git a/code/game/machinery/computer/station_alert.dm b/code/game/machinery/computer/station_alert.dm index b4340b9350..7b2e6ab455 100644 --- a/code/game/machinery/computer/station_alert.dm +++ b/code/game/machinery/computer/station_alert.dm @@ -16,11 +16,10 @@ GLOB.alert_consoles -= src return ..() -/obj/machinery/computer/station_alert/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ - datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) +/obj/machinery/computer/station_alert/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) if(!ui) - ui = new(user, src, ui_key, "StationAlertConsole", name, 325, 500, master_ui, state) + ui = new(user, src, "StationAlertConsole", name) ui.open() /obj/machinery/computer/station_alert/ui_data(mob/user) @@ -31,6 +30,7 @@ data["alarms"][class] = list() for(var/area in alarms[class]) data["alarms"][class] += area + return data /obj/machinery/computer/station_alert/proc/triggerAlarm(class, area/A, O, obj/source) diff --git a/code/game/machinery/computer/teleporter.dm b/code/game/machinery/computer/teleporter.dm index e7957a5b75..3a8ff7bf19 100644 --- a/code/game/machinery/computer/teleporter.dm +++ b/code/game/machinery/computer/teleporter.dm @@ -34,11 +34,10 @@ break return power_station -obj/machinery/computer/teleporter/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ - datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) +/obj/machinery/computer/teleporter/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) if(!ui) - ui = new(user, src, ui_key, "Teleporter", name, ui_x, ui_y, master_ui, state) + ui = new(user, src, "Teleporter", name) ui.open() /obj/machinery/computer/teleporter/ui_data(mob/user) @@ -56,7 +55,6 @@ obj/machinery/computer/teleporter/ui_interact(mob/user, ui_key = "main", datum/t return data - /obj/machinery/computer/teleporter/ui_act(action, params) if(..()) return @@ -92,16 +90,18 @@ obj/machinery/computer/teleporter/ui_interact(mob/user, ui_key = "main", datum/t say("Processing hub calibration to target...") calibrating = TRUE power_station.update_icon() - spawn(50 * (3 - power_station.teleporter_hub.accuracy)) //Better parts mean faster calibration - calibrating = FALSE - if(check_hub_connection()) - power_station.teleporter_hub.calibrated = TRUE - say("Calibration complete.") - else - say("Error: Unable to detect hub.") - power_station.update_icon() + addtimer(CALLBACK(src, .proc/finish_calibration), 50 * (3 - power_station.teleporter_hub.accuracy)) //Better parts mean faster calibration . = TRUE +/obj/machinery/computer/teleporter/proc/finish_calibration() + calibrating = FALSE + if(check_hub_connection()) + power_station.teleporter_hub.calibrated = TRUE + say("Calibration complete.") + else + say("Error: Unable to detect hub.") + power_station.update_icon() + /obj/machinery/computer/teleporter/proc/check_hub_connection() if(!power_station) return FALSE diff --git a/code/game/machinery/dance_machine.dm b/code/game/machinery/dance_machine.dm index 9ecc19e40f..756f924cfa 100644 --- a/code/game/machinery/dance_machine.dm +++ b/code/game/machinery/dance_machine.dm @@ -9,6 +9,7 @@ var/active = FALSE var/list/rangers = list() var/stop = 0 + var/volume = 70 var/datum/track/selection = null /obj/machinery/jukebox/disco @@ -51,74 +52,91 @@ else icon_state = "[initial(icon_state)]" -/obj/machinery/jukebox/ui_interact(mob/user) - . = ..() - if(!user.canUseTopic(src, !hasSiliconAccessInArea(user))) - return - if (!anchored) +/obj/machinery/jukebox/ui_status(mob/user) + if(!anchored) to_chat(user,"This device must be anchored by a wrench!") - return - if(!allowed(user)) + return UI_CLOSE + if(!allowed(user) && !isobserver(user)) to_chat(user,"Error: Access Denied.") - user.playsound_local(src,'sound/misc/compiler-failure.ogg', 25, 1) - return - if(!SSjukeboxes.songs.len) + user.playsound_local(src, 'sound/misc/compiler-failure.ogg', 25, TRUE) + return UI_CLOSE + if(!SSjukeboxes.songs.len && !isobserver(user)) to_chat(user,"Error: No music tracks have been authorized for your station. Petition Central Command to resolve this issue.") - playsound(src,'sound/misc/compiler-failure.ogg', 25, 1) - return - var/list/dat = list() - dat +="
" - dat += "[!active ? "BREAK IT DOWN" : "SHUT IT DOWN"]
" - dat += "

" - dat += " Select Track
" - if(istype(selection)) - dat += "Track Selected: [selection.song_name]
" - dat += "Track Length: [DisplayTimeText(selection.song_length)]

" - else - dat += "Track Selected: None!

" - var/datum/browser/popup = new(user, "vending", "[name]", 400, 350) - popup.set_content(dat.Join()) - popup.open() + playsound(src, 'sound/misc/compiler-failure.ogg', 25, TRUE) + return UI_CLOSE + return ..() +/obj/machinery/jukebox/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "Jukebox", name) + ui.open() -/obj/machinery/jukebox/Topic(href, href_list) - if(..()) +/obj/machinery/jukebox/ui_data(mob/user) + var/list/data = list() + data["active"] = active + data["songs"] = list() + for(var/datum/track/S in SSjukeboxes.songs) + var/list/track_data = list( + name = S.song_name + ) + data["songs"] += list(track_data) + data["track_selected"] = null + data["track_length"] = null + data["track_beat"] = null + if(selection) + data["track_selected"] = selection.song_name + data["track_length"] = DisplayTimeText(selection.song_length) + data["track_beat"] = selection.song_beat + data["volume"] = volume + return data + +/obj/machinery/jukebox/ui_act(action, list/params) + . = ..() + if(.) return - add_fingerprint(usr) - switch(href_list["action"]) + + switch(action) if("toggle") - if (QDELETED(src)) + if(QDELETED(src)) return if(!active) if(stop > world.time) to_chat(usr, "Error: The device is still resetting from the last activation, it will be ready again in [DisplayTimeText(stop-world.time)].") - playsound(src, 'sound/misc/compiler-failure.ogg', 50, 1) + playsound(src, 'sound/misc/compiler-failure.ogg', 50, TRUE) return - if(!istype(selection)) - to_chat(usr, "Error: Severe user incompetence detected.") - playsound(src, 'sound/misc/compiler-failure.ogg', 50, 1) - return - if(!activate_music()) - to_chat(usr, "Error: Generic hardware failure.") - playsound(src, 'sound/misc/compiler-failure.ogg', 50, 1) - return - updateUsrDialog() - else if(active) + activate_music() + START_PROCESSING(SSobj, src) + return TRUE + else stop = 0 - updateUsrDialog() - if("select") + return TRUE + if("select_track") if(active) to_chat(usr, "Error: You cannot change the song until the current one is over.") return - var/list/available = list() for(var/datum/track/S in SSjukeboxes.songs) available[S.song_name] = S - var/selected = input(usr, "Choose your song", "Track:") as null|anything in available + var/selected = params["track"] if(QDELETED(src) || !selected || !istype(available[selected], /datum/track)) return selection = available[selected] - updateUsrDialog() + return TRUE + if("set_volume") + var/new_volume = params["volume"] + if(new_volume == "reset") + volume = initial(volume) + return TRUE + else if(new_volume == "min") + volume = 0 + return TRUE + else if(new_volume == "max") + volume = 100 + return TRUE + else if(text2num(new_volume) != null) + volume = text2num(new_volume) + return TRUE /obj/machinery/jukebox/proc/activate_music() var/jukeboxslottotake = SSjukeboxes.addjukebox(src, selection, 2) diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm index 4771e2eca7..515a4672a5 100644 --- a/code/game/machinery/doors/airlock.dm +++ b/code/game/machinery/doors/airlock.dm @@ -50,7 +50,7 @@ integrity_failure = 0.25 damage_deflection = AIRLOCK_DAMAGE_DEFLECTION_N autoclose = TRUE - secondsElectrified = 0 //How many seconds remain until the door is no longer electrified. -1 if it is permanently electrified until someone fixes it. + secondsElectrified = NOT_ELECTRIFIED //How many seconds remain until the door is no longer electrified. -1 if it is permanently electrified until someone fixes it. assemblytype = /obj/structure/door_assembly normalspeed = 1 explosion_block = 1 @@ -298,10 +298,10 @@ /obj/machinery/door/airlock/Destroy() QDEL_NULL(wires) + QDEL_NULL(electronics) if(charge) qdel(charge) charge = null - QDEL_NULL(electronics) if (cyclelinkedairlock) if (cyclelinkedairlock.cyclelinkedairlock == src) cyclelinkedairlock.cyclelinkedairlock = null @@ -309,7 +309,7 @@ if(id_tag) for(var/obj/machinery/doorButtons/D in GLOB.machines) D.removeMe(src) - qdel(note) + QDEL_NULL(note) for(var/datum/atom_hud/data/diagnostic/diag_hud in GLOB.huds) diag_hud.remove_from_hud(src) return ..() @@ -765,8 +765,8 @@ /obj/machinery/door/airlock/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) if(!(issilicon(user) || IsAdminGhost(user))) - if(src.isElectrified()) - if(src.shock(user, 100)) + if(isElectrified()) + if(shock(user, 100)) return if(ishuman(user) && prob(40) && src.density) @@ -790,15 +790,15 @@ return ..() /obj/machinery/door/airlock/proc/electrified_loop() - while (secondsElectrified > 0) + while (secondsElectrified > NOT_ELECTRIFIED) sleep(10) if(QDELETED(src)) return - secondsElectrified -= 1 + secondsElectrified-- updateDialog() // This is to protect against changing to permanent, mid loop. - if(secondsElectrified==0) + if(secondsElectrified == NOT_ELECTRIFIED) set_electrified(NOT_ELECTRIFIED) else set_electrified(ELECTRIFIED_PERMANENT) @@ -825,8 +825,8 @@ /obj/machinery/door/airlock/attackby(obj/item/C, mob/user, params) if(!issilicon(user) && !IsAdminGhost(user)) - if(src.isElectrified()) - if(src.shock(user, 75)) + if(isElectrified()) + if(shock(user, 75)) return add_fingerprint(user) @@ -839,7 +839,7 @@ to_chat(user, "You need at least 2 metal sheets to reinforce [src].") return to_chat(user, "You start reinforcing [src].") - if(do_after(user, 20, 1, target = src)) + if(do_after(user, 20, TRUE, target = src)) if(!panel_open || !S.use(2)) return user.visible_message("[user] reinforces \the [src] with metal.", @@ -1070,7 +1070,7 @@ INVOKE_ASYNC(src, (density ? .proc/open : .proc/close), 2) if(istype(I, /obj/item/crowbar/power)) - if(isElectrified()) + if(hasPower() && isElectrified()) shock(user,100)//it's like sticking a forck in a power socket return @@ -1090,12 +1090,11 @@ time_to_open = 50 playsound(src, 'sound/machines/airlock_alien_prying.ogg',100,1) //is it aliens or just the CE being a dick? prying_so_hard = TRUE - var/result = do_after(user, time_to_open,target = src) - prying_so_hard = FALSE - if(result) + if(do_after(user, time_to_open,target = src)) open(2) if(density && !open(2)) to_chat(user, "Despite your attempts, [src] refuses to open.") + prying_so_hard = FALSE /obj/machinery/door/airlock/open(forced=0) if( operating || welded || locked ) @@ -1359,12 +1358,25 @@ wires.cut_all() update_icon() -/obj/machinery/door/airlock/proc/set_electrified(seconds) +/obj/machinery/door/airlock/proc/set_electrified(seconds, mob/user) secondsElectrified = seconds diag_hud_set_electrified() - if(secondsElectrified > 0) + if(secondsElectrified > NOT_ELECTRIFIED) INVOKE_ASYNC(src, .proc/electrified_loop) + if(user) + var/message + switch(secondsElectrified) + if(ELECTRIFIED_PERMANENT) + message = "permanently shocked" + if(NOT_ELECTRIFIED) + message = "unshocked" + else + message = "temp shocked for [secondsElectrified] seconds" + LAZYADD(shockedby, text("\[[TIME_STAMP("hh:mm:ss", FALSE)]\] [key_name(user)] - ([uppertext(message)])")) + log_combat(user, src, message) + //add_hiddenprint(user) + /obj/machinery/door/airlock/take_damage(damage_amount, damage_type = BRUTE, damage_flag = 0, sound_effect = 1, attack_dir) . = ..() if(obj_integrity < (0.75 * max_integrity)) @@ -1438,11 +1450,10 @@ else if(istype(note, /obj/item/photo)) return "photo" -/obj/machinery/door/airlock/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ - datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) - SStgui.try_update_ui(user, src, ui_key, ui, force_open) +/obj/machinery/door/airlock/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) if(!ui) - ui = new(user, src, ui_key, "AiAirlock", name, 500, 390, master_ui, state) + ui = new(user, src, "AiAirlock", name) ui.open() return TRUE @@ -1450,13 +1461,13 @@ var/list/data = list() var/list/power = list() - power["main"] = src.secondsMainPowerLost ? 0 : 2 // boolean - power["main_timeleft"] = src.secondsMainPowerLost - power["backup"] = src.secondsBackupPowerLost ? 0 : 2 // boolean - power["backup_timeleft"] = src.secondsBackupPowerLost + power["main"] = secondsMainPowerLost ? 0 : 2 // boolean + power["main_timeleft"] = secondsMainPowerLost + power["backup"] = secondsBackupPowerLost ? 0 : 2 // boolean + power["backup_timeleft"] = secondsBackupPowerLost data["power"] = power - data["shock"] = secondsElectrified == 0 ? 2 : 0 + data["shock"] = secondsElectrified == NOT_ELECTRIFIED ? 2 : 0 data["shock_timeleft"] = secondsElectrified data["id_scanner"] = !aiDisabledIdScanner data["emergency"] = emergency // access @@ -1493,14 +1504,14 @@ loseMainPower() update_icon() else - to_chat(usr, "Main power is already offline.") + to_chat(usr, "Main power is already offline.") . = TRUE if("disrupt-backup") if(!secondsBackupPowerLost) loseBackupPower() update_icon() else - to_chat(usr, "Backup power is already offline.") + to_chat(usr, "Backup power is already offline.") . = TRUE if("shock-restore") shock_restore(usr) @@ -1529,7 +1540,6 @@ . = TRUE if("speed-toggle") normalspeed = !normalspeed - . = TRUE if("open-close") user_toggle_open(usr) diff --git a/code/game/machinery/doors/airlock_electronics.dm b/code/game/machinery/doors/airlock_electronics.dm index a0ce3954c3..ef2be8d744 100644 --- a/code/game/machinery/doors/airlock_electronics.dm +++ b/code/game/machinery/doors/airlock_electronics.dm @@ -15,11 +15,13 @@ . = ..() . += "Has a neat selection menu for modifying airlock access levels." -/obj/item/electronics/airlock/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ - datum/tgui/master_ui = null, datum/ui_state/state = GLOB.hands_state) - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) +/obj/item/electronics/airlock/ui_state(mob/user) + return GLOB.hands_state + +/obj/item/electronics/airlock/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) if(!ui) - ui = new(user, src, ui_key, "AirlockElectronics", name, 420, 485, master_ui, state) + ui = new(user, src, "AirlockElectronics", name) ui.open() /obj/item/electronics/airlock/ui_static_data(mob/user) diff --git a/code/game/machinery/doors/airlock_types.dm b/code/game/machinery/doors/airlock_types.dm index 530a287134..b34e97d374 100644 --- a/code/game/machinery/doors/airlock_types.dm +++ b/code/game/machinery/doors/airlock_types.dm @@ -310,6 +310,17 @@ opacity = 0 glass = TRUE +/obj/machinery/door/airlock/bronze + name = "bronze airlock" + icon = 'icons/obj/doors/airlocks/clockwork/pinion_airlock.dmi' + overlays_file = 'icons/obj/doors/airlocks/clockwork/overlays.dmi' + assemblytype = /obj/structure/door_assembly/door_assembly_bronze + +/obj/machinery/door/airlock/bronze/seethru + assemblytype = /obj/structure/door_assembly/door_assembly_bronze/seethru + opacity = 0 + glass = TRUE + ////////////////////////////////// /* Station2 Airlocks diff --git a/code/game/machinery/doors/brigdoors.dm b/code/game/machinery/doors/brigdoors.dm index 5a1ed7dd19..b2e0050819 100644 --- a/code/game/machinery/doors/brigdoors.dm +++ b/code/game/machinery/doors/brigdoors.dm @@ -140,11 +140,10 @@ . = new_time == timer_duration //return 1 on no change timer_duration = new_time -/obj/machinery/door_timer/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ - datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) +/obj/machinery/door_timer/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) if(!ui) - ui = new(user, src, ui_key, "BrigTimer", name, 300, 138, master_ui, state) + ui = new(user, src, "BrigTimer", name) ui.open() //icon update function @@ -235,7 +234,7 @@ preset_time = PRESET_LONG . = set_timer(preset_time) if(timing) - activation_time = REALTIMEOFDAY + activation_time = world.time else . = FALSE diff --git a/code/game/machinery/doors/door.dm b/code/game/machinery/doors/door.dm index 4248e1684f..d4ba70bb6c 100644 --- a/code/game/machinery/doors/door.dm +++ b/code/game/machinery/doors/door.dm @@ -11,7 +11,7 @@ max_integrity = 350 armor = list("melee" = 30, "bullet" = 30, "laser" = 20, "energy" = 20, "bomb" = 10, "bio" = 100, "rad" = 100, "fire" = 80, "acid" = 70) CanAtmosPass = ATMOS_PASS_DENSITY - flags_1 = PREVENT_CLICK_UNDER_1 + flags_1 = PREVENT_CLICK_UNDER_1|DEFAULT_RICOCHET_1 ricochet_chance_mod = 0.8 interaction_flags_atom = INTERACT_ATOM_UI_INTERACT diff --git a/code/game/machinery/doors/firedoor.dm b/code/game/machinery/doors/firedoor.dm index 2d41575e70..228c2e1f52 100644 --- a/code/game/machinery/doors/firedoor.dm +++ b/code/game/machinery/doors/firedoor.dm @@ -298,7 +298,7 @@ /obj/machinery/door/firedoor/border_only icon = 'icons/obj/doors/edge_Doorfire.dmi' - flags_1 = ON_BORDER_1 + flags_1 = ON_BORDER_1|DEFAULT_RICOCHET_1 CanAtmosPass = ATMOS_PASS_PROC /obj/machinery/door/firedoor/border_only/closed @@ -320,7 +320,7 @@ to_chat(M, "You pull [M.pulling] through [src] right as it closes") M.pulling.forceMove(T1) M.start_pulling(M2) - + for(var/mob/living/M in T2) if(M.stat == CONSCIOUS && M.pulling && M.pulling.loc == T1 && !M.pulling.anchored && M.pulling.move_resist <= M.move_force) var/mob/living/M2 = M.pulling diff --git a/code/game/machinery/doors/windowdoor.dm b/code/game/machinery/doors/windowdoor.dm index c9c577231e..22bacf6aa1 100644 --- a/code/game/machinery/doors/windowdoor.dm +++ b/code/game/machinery/doors/windowdoor.dm @@ -11,7 +11,7 @@ integrity_failure = 0 armor = list("melee" = 20, "bullet" = 50, "laser" = 50, "energy" = 50, "bomb" = 10, "bio" = 100, "rad" = 100, "fire" = 70, "acid" = 100) visible = FALSE - flags_1 = ON_BORDER_1 + flags_1 = ON_BORDER_1|DEFAULT_RICOCHET_1 opacity = 0 CanAtmosPass = ATMOS_PASS_PROC interaction_flags_machine = INTERACT_MACHINE_WIRES_IF_OPEN | INTERACT_MACHINE_ALLOW_SILICON | INTERACT_MACHINE_OPEN_SILICON | INTERACT_MACHINE_REQUIRES_SILICON | INTERACT_MACHINE_OPEN diff --git a/code/game/machinery/gulag_item_reclaimer.dm b/code/game/machinery/gulag_item_reclaimer.dm index 45484caa77..93c6e66867 100644 --- a/code/game/machinery/gulag_item_reclaimer.dm +++ b/code/game/machinery/gulag_item_reclaimer.dm @@ -20,18 +20,15 @@ return ..() /obj/machinery/gulag_item_reclaimer/emag_act(mob/user) - . = ..() if(obj_flags & EMAGGED) // emagging lets anyone reclaim all the items return req_access = list() obj_flags |= EMAGGED - return TRUE -/obj/machinery/gulag_item_reclaimer/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ - datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) +/obj/machinery/gulag_item_reclaimer/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) if(!ui) - ui = new(user, src, ui_key, "GulagItemReclaimer", name, 300, 400, master_ui, state) + ui = new(user, src, "GulagItemReclaimer", name) ui.open() /obj/machinery/gulag_item_reclaimer/ui_data(mob/user) @@ -60,20 +57,22 @@ mobs += list(mob_info) data["mobs"] = mobs - - data["can_reclaim"] = can_reclaim return data -/obj/machinery/gulag_item_reclaimer/ui_act(action, list/params) +/obj/machinery/gulag_item_reclaimer/ui_act(action, params) + if(..()) + return + switch(action) if("release_items") - var/mob/M = locate(params["mobref"]) - if(M == usr || allowed(usr)) - drop_items(M) - else - to_chat(usr, "Access denied.") + var/mob/living/carbon/human/H = locate(params["mobref"]) in stored_items + if(H != usr && !allowed(usr)) + to_chat(usr, "Access denied.") + return + drop_items(H) + . = TRUE /obj/machinery/gulag_item_reclaimer/proc/drop_items(mob/user) if(!stored_items[user]) diff --git a/code/game/machinery/hologram.dm b/code/game/machinery/hologram.dm index 25f4248d6d..4a576c5a6e 100644 --- a/code/game/machinery/hologram.dm +++ b/code/game/machinery/hologram.dm @@ -25,7 +25,6 @@ Possible to do for anyone motivated enough: */ GLOBAL_LIST_EMPTY(network_holopads) - #define HOLOPAD_PASSIVE_POWER_USAGE 1 #define HOLOGRAM_POWER_USAGE 2 @@ -34,34 +33,64 @@ GLOBAL_LIST_EMPTY(network_holopads) desc = "It's a floor-mounted device for projecting holographic images." icon_state = "holopad0" layer = LOW_OBJ_LAYER - plane = ABOVE_WALL_PLANE + plane = FLOOR_PLANE flags_1 = HEAR_1 + req_access = list(ACCESS_KEYCARD_AUTH) //Used to allow for forced connecting to other (not secure) holopads. Anyone can make a call, though. use_power = IDLE_POWER_USE idle_power_usage = 5 active_power_usage = 100 max_integrity = 300 armor = list("melee" = 50, "bullet" = 20, "laser" = 20, "energy" = 20, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 50, "acid" = 0) circuit = /obj/item/circuitboard/machine/holopad - var/list/masters //List of living mobs that use the holopad - var/list/holorays //Holoray-mob link. - var/last_request = 0 //to prevent request spam. ~Carn - var/holo_range = 5 // Change to change how far the AI can move away from the holopad before deactivating. - var/temp = "" - var/list/holo_calls //array of /datum/holocalls - var/datum/holocall/outgoing_call //do not modify the datums only check and call the public procs - var/obj/item/disk/holodisk/disk //Record disk - var/replay_mode = FALSE //currently replaying a recording - var/loop_mode = FALSE //currently looping a recording - var/record_mode = FALSE //currently recording - var/record_start = 0 //recording start time - var/record_user //user that inititiated the recording - var/obj/effect/overlay/holo_pad_hologram/replay_holo //replay hologram - var/static/force_answer_call = FALSE //Calls will be automatically answered after a couple rings, here for debugging + /// List of living mobs that use the holopad + var/list/masters + /// Holoray-mob link + var/list/holorays + /// To prevent request spam. ~Carn + var/last_request = 0 + /// Change to change how far the AI can move away from the holopad before deactivating + var/holo_range = 5 + /// Array of /datum/holocalls + var/list/holo_calls + /// Currently outgoing holocall, do not modify the datums only check and call the public procs + var/datum/holocall/outgoing_call + /// Record disk + var/obj/item/disk/holodisk/disk + /// Currently replaying a recording + var/replay_mode = FALSE + /// Currently looping a recording + var/loop_mode = FALSE + /// Currently recording + var/record_mode = FALSE + /// Recording start time + var/record_start = 0 + /// User that inititiated the recording + var/record_user + /// Replay hologram + var/obj/effect/overlay/holo_pad_hologram/replay_holo + /// Calls will be automatically answered after a couple rings, here for debugging + var/static/force_answer_call = FALSE + // var/static/list/holopads = list() var/obj/effect/overlay/holoray/ray var/ringing = FALSE var/offset = FALSE var/on_network = TRUE + /// For pads in secure areas; do not allow forced connecting + var/secure = FALSE + /// If we are currently calling another holopad + var/calling = FALSE +/* +/obj/machinery/holopad/secure + name = "secure holopad" + desc = "It's a floor-mounted device for projecting holographic images. This one will refuse to auto-connect incoming calls." + secure = TRUE +/obj/machinery/holopad/secure/Initialize() + . = ..() + var/obj/item/circuitboard/machine/holopad/board = circuit + board.secure = TRUE + board.build_path = /obj/machinery/holopad/secure +*/ /obj/machinery/holopad/tutorial resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF flags_1 = NODECONSTRUCT_1 @@ -121,10 +150,8 @@ GLOBAL_LIST_EMPTY(network_holopads) return ..() /obj/machinery/holopad/power_change() - if (powered()) - stat &= ~NOPOWER - else - stat |= NOPOWER + . = ..() + if (!powered()) if(replay_mode) replay_stop() if(record_mode) @@ -163,171 +190,150 @@ GLOBAL_LIST_EMPTY(network_holopads) if(istype(P,/obj/item/disk/holodisk)) if(disk) - to_chat(user,"There's already a disk inside [src]") + to_chat(user,"There's already a disk inside [src]!") return if (!user.transferItemToLoc(P,src)) return - to_chat(user,"You insert [P] into [src]") + to_chat(user,"You insert [P] into [src].") disk = P - updateDialog() return return ..() +/obj/machinery/holopad/ui_status(mob/user) + if(!is_operational()) + return UI_CLOSE + if(outgoing_call && !calling) + return UI_CLOSE + return ..() -/obj/machinery/holopad/ui_interact(mob/living/carbon/human/user) //Carn: Hologram requests. +/obj/machinery/holopad/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "Holopad", name) + ui.open() + +/obj/machinery/holopad/ui_data(mob/user) + var/list/data = list() + data["calling"] = calling + data["on_network"] = on_network + data["on_cooldown"] = last_request + 200 < world.time ? FALSE : TRUE + data["allowed"] = allowed(user) + data["disk"] = disk ? TRUE : FALSE + data["disk_record"] = disk?.record ? TRUE : FALSE + data["replay_mode"] = replay_mode + data["loop_mode"] = loop_mode + data["record_mode"] = record_mode + data["holo_calls"] = list() + for(var/I in holo_calls) + var/datum/holocall/HC = I + var/list/call_data = list( + caller = HC.user, + connected = HC.connected_holopad == src ? TRUE : FALSE, + ref = REF(HC) + ) + data["holo_calls"] += list(call_data) + return data + +/obj/machinery/holopad/ui_act(action, list/params) . = ..() - if(!istype(user)) + if(.) return - if(outgoing_call || user.incapacitated() || !is_operational()) - return - - user.set_machine(src) - var/dat - if(temp) - dat = temp - else - if(on_network) - dat += "Request an AI's presence
" - dat += "Call another holopad
" - if(disk) - if(disk.record) - //Replay - dat += "Replay disk recording
" - dat += "Loop disk recording
" - //Clear - dat += "Clear disk recording
" + switch(action) + if("AIrequest") + if(last_request + 200 < world.time) + last_request = world.time + to_chat(usr, "You requested an AI's presence.") + var/area/area = get_area(src) + for(var/mob/living/silicon/ai/AI in GLOB.silicon_mobs) + if(!AI.client) + continue + to_chat(AI, "Your presence is requested at \the [area].") + return TRUE else - //Record - dat += "Start new recording
" - //Eject - dat += "Eject disk
" + to_chat(usr, "A request for AI presence was already sent recently.") + return + if("holocall") + if(outgoing_call) + return + if(usr.loc == loc) + var/list/callnames = list() + for(var/I in GLOB.network_holopads) + var/area/A = get_area(I) + if(A) + LAZYADD(callnames[A], I) + callnames -= get_area(src) + var/result = input(usr, "Choose an area to call", "Holocall") as null|anything in sortNames(callnames) + if(QDELETED(usr) || !result || outgoing_call) + return + if(usr.loc == loc) + var/input = text2num(params["headcall"]) + var/headcall = input == 1 ? TRUE : FALSE + new /datum/holocall(usr, src, callnames[result], headcall) + calling = TRUE + return TRUE + else + to_chat(usr, "You must stand on the holopad to make a call!") + if("connectcall") + var/datum/holocall/call_to_connect = locate(params["holopad"]) in holo_calls + if(!QDELETED(call_to_connect)) + call_to_connect.Answer(src) + return TRUE + if("disconnectcall") + var/datum/holocall/call_to_disconnect = locate(params["holopad"]) in holo_calls + if(!QDELETED(call_to_disconnect)) + call_to_disconnect.Disconnect(src) + return TRUE + if("disk_eject") + if(disk && !replay_mode) + disk.forceMove(drop_location()) + disk = null + return TRUE + if("replay_mode") + if(replay_mode) + replay_stop() + return TRUE + else + replay_start() + return TRUE + if("loop_mode") + loop_mode = !loop_mode + return TRUE + if("record_mode") + if(record_mode) + record_stop() + return TRUE + else + record_start(usr) + return TRUE + if("record_clear") + record_clear() + return TRUE + if("offset") + offset++ + if(offset > 4) + offset = FALSE + var/turf/new_turf + if(!offset) + new_turf = get_turf(src) + else + new_turf = get_step(src, GLOB.cardinals[offset]) + replay_holo.forceMove(new_turf) + return TRUE + if("hang_up") + if(outgoing_call) + outgoing_call.Disconnect(src) + return TRUE - if(LAZYLEN(holo_calls)) - dat += "=====================================================
" - - if(on_network) - var/one_answered_call = FALSE - var/one_unanswered_call = FALSE - for(var/I in holo_calls) - var/datum/holocall/HC = I - if(HC.connected_holopad != src) - dat += "Answer call from [get_area(HC.calling_holopad)]
" - one_unanswered_call = TRUE - else - one_answered_call = TRUE - - if(one_answered_call && one_unanswered_call) - dat += "=====================================================
" - //we loop twice for formatting - for(var/I in holo_calls) - var/datum/holocall/HC = I - if(HC.connected_holopad == src) - dat += "Disconnect call from [HC.user]
" - - - var/datum/browser/popup = new(user, "holopad", name, 300, 175) - popup.set_content(dat) - popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state)) - popup.open() - -//Stop ringing the AI!! +/** + * hangup_all_calls: Disconnects all current holocalls from the holopad + */ /obj/machinery/holopad/proc/hangup_all_calls() for(var/I in holo_calls) var/datum/holocall/HC = I HC.Disconnect(src) -/obj/machinery/holopad/Topic(href, href_list) - if(..() || isAI(usr)) - return - add_fingerprint(usr) - if(!is_operational()) - return - if (href_list["AIrequest"]) - if(last_request + 200 < world.time) - last_request = world.time - temp = "You requested an AI's presence.
" - temp += "Main Menu" - var/area/area = get_area(src) - for(var/mob/living/silicon/ai/AI in GLOB.silicon_mobs) - if(!AI.client) - continue - to_chat(AI, "Your presence is requested at \the [area].") - else - temp = "A request for AI presence was already sent recently.
" - temp += "Main Menu" - - else if(href_list["Holocall"]) - if(outgoing_call) - return - - temp = "You must stand on the holopad to make a call!
" - temp += "Main Menu" - if(usr.loc == loc) - var/list/callnames = list() - for(var/I in GLOB.network_holopads) - var/area/A = get_area(I) - if(A) - LAZYADD(callnames[A], I) - callnames -= get_area(src) - - var/result = input(usr, "Choose an area to call", "Holocall") as null|anything in callnames - if(QDELETED(usr) || !result || outgoing_call) - return - - if(usr.loc == loc) - temp = "Dialing...
" - temp += "Main Menu" - new /datum/holocall(usr, src, callnames[result]) - - else if(href_list["connectcall"]) - var/datum/holocall/call_to_connect = locate(href_list["connectcall"]) - if(!QDELETED(call_to_connect)) - call_to_connect.Answer(src) - temp = "" - - else if(href_list["disconnectcall"]) - var/datum/holocall/call_to_disconnect = locate(href_list["disconnectcall"]) - if(!QDELETED(call_to_disconnect)) - call_to_disconnect.Disconnect(src) - temp = "" - - else if(href_list["mainmenu"]) - temp = "" - if(outgoing_call) - outgoing_call.Disconnect() - - else if(href_list["disk_eject"]) - if(disk && !replay_mode) - disk.forceMove(drop_location()) - disk = null - - else if(href_list["replay_stop"]) - replay_stop() - else if(href_list["replay_start"]) - replay_start() - else if(href_list["loop_start"]) - loop_mode = TRUE - replay_start() - else if(href_list["record_start"]) - record_start(usr) - else if(href_list["record_stop"]) - record_stop() - else if(href_list["record_clear"]) - record_clear() - else if(href_list["offset"]) - offset++ - if (offset > 4) - offset = FALSE - var/turf/new_turf - if (!offset) - new_turf = get_turf(src) - else - new_turf = get_step(src, GLOB.cardinals[offset]) - replay_holo.forceMove(new_turf) - updateDialog() - //do not allow AIs to answer calls or people will use it to meta the AI sattelite /obj/machinery/holopad/attack_ai(mob/living/silicon/ai/user) if (!istype(user)) @@ -366,6 +372,9 @@ GLOBAL_LIST_EMPTY(network_holopads) if(force_answer_call && world.time > (HC.call_start_time + (HOLOPAD_MAX_DIAL_TIME / 2))) HC.Answer(src) break + if(!secure) //HC.head_call && + HC.Answer(src) + break if(outgoing_call) HC.Disconnect(src)//can't answer calls while calling else @@ -412,17 +421,17 @@ GLOBAL_LIST_EMPTY(network_holopads) /*This is the proc for special two-way communication between AI and holopad/people talking near holopad. For the other part of the code, check silicon say.dm. Particularly robot talk.*/ -/obj/machinery/holopad/Hear(message, atom/movable/speaker, datum/language/message_language, raw_message, radio_freq, list/spans, message_mode, atom/movable/source) +/obj/machinery/holopad/Hear(message, atom/movable/speaker, datum/language/message_language, raw_message, radio_freq, list/spans, list/message_mods = list()) . = ..() if(speaker && LAZYLEN(masters) && !radio_freq)//Master is mostly a safety in case lag hits or something. Radio_freq so AIs dont hear holopad stuff through radios. for(var/mob/living/silicon/ai/master in masters) if(masters[master] && speaker != master) - master.relay_speech(message, speaker, message_language, raw_message, radio_freq, spans, message_mode) + master.relay_speech(message, speaker, message_language, raw_message, radio_freq, spans, message_mods) for(var/I in holo_calls) var/datum/holocall/HC = I if(HC.connected_holopad == src && speaker != HC.hologram) - HC.user.Hear(message, speaker, message_language, raw_message, radio_freq, spans, message_mode, source) + HC.user.Hear(message, speaker, message_language, raw_message, radio_freq, spans, message_mods) if(outgoing_call && speaker == outgoing_call.user) outgoing_call.hologram.say(raw_message) @@ -449,7 +458,7 @@ For the other part of the code, check silicon say.dm. Particularly robot talk.*/ else icon_state = "holopad0" -/obj/machinery/holopad/proc/set_holo(mob/living/user, var/obj/effect/overlay/holo_pad_hologram/h) +/obj/machinery/holopad/proc/set_holo(mob/living/user, obj/effect/overlay/holo_pad_hologram/h) LAZYSET(masters, user, h) LAZYSET(holorays, user, new /obj/effect/overlay/holoray(loc)) var/mob/living/silicon/ai/AI = user @@ -504,7 +513,7 @@ For the other part of the code, check silicon say.dm. Particularly robot talk.*/ else return FALSE -/obj/machinery/holopad/proc/move_hologram(mob/living/user, turf/new_turf, direction) +/obj/machinery/holopad/proc/move_hologram(mob/living/user, turf/new_turf) if(LAZYLEN(masters) && masters[user]) var/obj/effect/overlay/holo_pad_hologram/holo = masters[user] var/transfered = FALSE @@ -516,8 +525,6 @@ For the other part of the code, check silicon say.dm. Particularly robot talk.*/ transfered = TRUE //All is good. holo.forceMove(new_turf) - if(direction) - holo.setDir(direction) if(!transfered) update_holoray(user,new_turf) return TRUE @@ -568,22 +575,15 @@ For the other part of the code, check silicon say.dm. Particularly robot talk.*/ if(!replay_mode) replay_mode = TRUE replay_holo = setup_replay_holo(disk.record) - temp = "Replaying...
" - temp += "Change offset
" - temp += "End replay" SetLightsAndPower() replay_entry(1) - return /obj/machinery/holopad/proc/replay_stop() if(replay_mode) replay_mode = FALSE - loop_mode = FALSE offset = FALSE - temp = null QDEL_NULL(replay_holo) SetLightsAndPower() - updateDialog() /obj/machinery/holopad/proc/record_start(mob/living/user) if(!user || !disk || disk.record) @@ -593,8 +593,6 @@ For the other part of the code, check silicon say.dm. Particularly robot talk.*/ record_start = world.time record_user = user disk.record.set_caller_image(user) - temp = "Recording...
" - temp += "End recording." /obj/machinery/holopad/proc/record_message(mob/living/speaker,message,language) if(!record_mode) @@ -641,7 +639,7 @@ For the other part of the code, check silicon say.dm. Particularly robot talk.*/ if(replay_holo) replay_holo.say(message) if(HOLORECORD_SOUND) - playsound(src,entry[2],50,1) + playsound(src,entry[2],50,TRUE) if(HOLORECORD_DELAY) addtimer(CALLBACK(src,.proc/replay_entry,entry_number+1),entry[2]) return @@ -660,14 +658,11 @@ For the other part of the code, check silicon say.dm. Particularly robot talk.*/ /obj/machinery/holopad/proc/record_stop() if(record_mode) record_mode = FALSE - temp = null record_user = null - updateDialog() /obj/machinery/holopad/proc/record_clear() if(disk && disk.record) QDEL_NULL(disk.record) - updateDialog() /obj/effect/overlay/holo_pad_hologram initial_language_holder = /datum/language_holder/universal diff --git a/code/game/machinery/hypnochair.dm b/code/game/machinery/hypnochair.dm index 16b464ced6..41f420204e 100644 --- a/code/game/machinery/hypnochair.dm +++ b/code/game/machinery/hypnochair.dm @@ -6,14 +6,12 @@ circuit = /obj/item/circuitboard/machine/hypnochair density = TRUE opacity = 0 - ui_x = 375 - ui_y = 480 + var/mob/living/carbon/victim = null ///Keeps track of the victim to apply effects if it teleports away var/interrogating = FALSE ///Is the device currently interrogating someone? var/start_time = 0 ///Time when the interrogation was started, to calculate effect in case of interruption var/trigger_phrase = "" ///Trigger phrase to implant var/timerid = 0 ///Timer ID for interrogations - var/message_cooldown = 0 ///Cooldown for breakout message /obj/machinery/hypnochair/Initialize() @@ -25,24 +23,24 @@ if(!occupant && default_deconstruction_screwdriver(user, icon_state, icon_state, I)) update_icon() return - if(default_pry_open(I)) return - if(default_deconstruction_crowbar(I)) return - return ..() -/obj/machinery/hypnochair/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.notcontained_state) - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) +/obj/machinery/hypnochair/ui_state(mob/user) + return GLOB.notcontained_state + +/obj/machinery/hypnochair/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) if(!ui) - ui = new(user, src, ui_key, "HypnoChair", name, ui_x, ui_y, master_ui, state) + ui = new(user, src, "HypnoChair", name) ui.open() /obj/machinery/hypnochair/ui_data() var/list/data = list() - data["occupied"] = occupant ? TRUE : FALSE + data["occupied"] = occupant ? 1 : 0 data["open"] = state_open data["interrogating"] = interrogating @@ -201,3 +199,4 @@ if(!(L.mobility_flags & MOBILITY_STAND)) return close_machine(target) + diff --git a/code/game/machinery/launch_pad.dm b/code/game/machinery/launch_pad.dm index 63ef40e045..e3df79e291 100644 --- a/code/game/machinery/launch_pad.dm +++ b/code/game/machinery/launch_pad.dm @@ -282,12 +282,14 @@ ui_interact(user) to_chat(user, "[src] projects a display onto your retina.") -/obj/item/launchpad_remote/ui_interact(mob/user, ui_key = "launchpad_remote", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) - if(!ui) - ui = new(user, src, ui_key, "LaunchpadRemote", "Briefcase Launchpad Remote", 300, 240, master_ui, state) //width, height - ui.open() +/obj/item/launchpad_remote/ui_state(mob/user) + return GLOB.inventory_state +/obj/item/launchpad_remote/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "LaunchpadRemote") + ui.open() ui.set_autoupdate(TRUE) /obj/item/launchpad_remote/ui_data(mob/user) diff --git a/code/game/machinery/porta_turret/portable_turret.dm b/code/game/machinery/porta_turret/portable_turret.dm index f69a722473..54d320e93b 100644 --- a/code/game/machinery/porta_turret/portable_turret.dm +++ b/code/game/machinery/porta_turret/portable_turret.dm @@ -4,6 +4,15 @@ #define POPUP_ANIM_TIME 5 #define POPDOWN_ANIM_TIME 5 //Be sure to change the icon animation at the same time or it'll look bad +#define TURRET_FLAG_SHOOT_ALL_REACT (1<<0) // The turret gets pissed off and shoots at people nearby (unless they have sec access!) +#define TURRET_FLAG_AUTH_WEAPONS (1<<1) // Checks if it can shoot people that have a weapon they aren't authorized to have +#define TURRET_FLAG_SHOOT_CRIMINALS (1<<2) // Checks if it can shoot people that are wanted +#define TURRET_FLAG_SHOOT_ALL (1<<3) // The turret gets pissed off and shoots at people nearby (unless they have sec access!) +#define TURRET_FLAG_SHOOT_ANOMALOUS (1<<4) // Checks if it can shoot at unidentified lifeforms (ie xenos) +#define TURRET_FLAG_SHOOT_UNSHIELDED (1<<5) // Checks if it can shoot people that aren't mindshielded and who arent heads +#define TURRET_FLAG_SHOOT_BORGS (1<<6) // checks if it can shoot cyborgs +#define TURRET_FLAG_SHOOT_HEADS (1<<7) // checks if it can shoot at heads of staff + /obj/machinery/porta_turret name = "turret" icon = 'icons/obj/turrets.dmi' @@ -15,70 +24,79 @@ use_power = IDLE_POWER_USE //this turret uses and requires power idle_power_usage = 50 //when inactive, this turret takes up constant 50 Equipment power active_power_usage = 300 //when active, this turret takes up constant 300 Equipment power - req_access = list(ACCESS_SEC_DOORS) + req_access = list(ACCESS_SECURITY) /// Only people with Security access power_channel = EQUIP //drains power from the EQUIPMENT channel - speed_process = TRUE - - var/base_icon_state = "standard" - var/scan_range = 7 - var/atom/base = null //for turrets inside other objects - - var/raised = 0 //if the turret cover is "open" and the turret is raised - var/raising= 0 //if the turret is currently opening or closing its cover - max_integrity = 160 //the turret's health integrity_failure = 0.5 armor = list("melee" = 50, "bullet" = 30, "laser" = 30, "energy" = 30, "bomb" = 30, "bio" = 0, "rad" = 0, "fire" = 90, "acid" = 90) - - var/locked = TRUE //if the turret's behaviour control access is locked - var/controllock = FALSE //if the turret responds to control panels - - var/installation = /obj/item/gun/energy/e_gun/turret //the type of weapon installed by default + /// Base turret icon state + var/base_icon_state = "standard" + /// Scan range of the turret for locating targets + var/scan_range = 7 + /// For turrets inside other objects + var/atom/base = null + /// If the turret cover is "open" and the turret is raised + var/raised = FALSE + /// If the turret is currently opening or closing its cover + var/raising = FALSE + /// If the turret's behaviour control access is locked + var/locked = TRUE + /// If the turret responds to control panels + var/controllock = FALSE + /// The type of weapon installed by default + var/installation = /obj/item/gun/energy/e_gun/turret + /// What stored gun is in the turret var/obj/item/gun/stored_gun = null - var/gun_charge = 0 //the charge of the gun when retrieved from wreckage - + /// The charge of the gun when retrieved from wreckage + var/gun_charge = 0 + /// In which mode is turret in, stun or lethal var/mode = TURRET_STUN - - var/stun_projectile = null //stun mode projectile type + /// Stun mode projectile type + var/stun_projectile = null + /// Sound of stun projectile var/stun_projectile_sound - var/nonlethal_projectile //projectile to use in stun mode when the target is resting, if any + /// Projectile to use in stun mode when the target is resting, if any + var/nonlethal_projectile + /// Sound of stun projectile wen the target is resting, optional var/nonlethal_projectile_sound - var/lethal_projectile = null //lethal mode projectile type + /// Lethal mode projectile type + var/lethal_projectile = null + /// Sound of lethal projectile var/lethal_projectile_sound - - var/reqpower = 500 //power needed per shot - var/always_up = 0 //Will stay active - var/has_cover = 1 //Hides the cover - - var/obj/machinery/porta_turret_cover/cover = null //the cover that is covering this turret - - var/last_fired = 0 //world.time the turret last fired - var/shot_delay = 15 //ticks until next shot (1.5 ?) - var/shot_stagger = 0 // sleep() shots to stagger attacks - - var/check_records = 1 //checks if it can use the security records - var/criminals = 1 //checks if it can shoot people on arrest - var/auth_weapons = 0 //checks if it can shoot people that have a weapon they aren't authorized to have - var/stun_all = 0 //if this is active, the turret shoots everything that isn't security or head of staff - var/check_anomalies = 1 //checks if it can shoot at unidentified lifeforms (ie xenos) - var/shoot_unloyal = 0 //checks if it can shoot people that aren't loyalty implantd - - var/attacked = 0 //if set to 1, the turret gets pissed off and shoots at people nearby (unless they have sec access!) - - var/on = TRUE //determines if the turret is on - - var/list/faction = list("turret") // Same faction mobs will never be shot at, no matter the other settings - - var/datum/effect_system/spark_spread/spark_system //the spark system, used for generating... sparks? - + /// Power needed per shot + var/reqpower = 500 + /// Will stay active + var/always_up = FALSE + /// Hides the cover + var/has_cover = TRUE + /// The cover that is covering this turret + var/obj/machinery/porta_turret_cover/cover = null + /// World.time the turret last fired + var/last_fired = 0 + /// Ticks until next shot (1.5 ?) + var/shot_delay = 15 + /// Turret flags about who is turret allowed to shoot + var/turret_flags = TURRET_FLAG_SHOOT_CRIMINALS | TURRET_FLAG_SHOOT_ANOMALOUS + /// Determines if the turret is on + var/on = TRUE + /// Same faction mobs will never be shot at, no matter the other settings + var/list/faction = list("turret") + /// The spark system, used for generating... sparks? + var/datum/effect_system/spark_spread/spark_system + /// Linked turret control panel of the turret var/obj/machinery/turretid/cp = null - - var/wall_turret_direction //The turret will try to shoot from a turf in that direction when in a wall - - var/manual_control = FALSE // + /// The turret will try to shoot from a turf in that direction when in a wall + var/wall_turret_direction + /// If the turret is manually controlled + var/manual_control = FALSE + /// Action button holder for quitting manual control var/datum/action/turret_quit/quit_action + /// Action button holder for switching between turret modes when manually controlling var/datum/action/turret_toggle/toggle_action + /// Mob that is remotely controlling the turret var/mob/remote_controller + /// MISSING: + var/shot_stagger = 0 /obj/machinery/porta_turret/Initialize() . = ..() @@ -100,6 +118,27 @@ if(!has_cover) INVOKE_ASYNC(src, .proc/popUp) +/obj/machinery/porta_turret/proc/toggle_on(var/set_to) + var/current = on + if (!isnull(set_to)) + on = set_to + else + on = !on + if (current != on) + check_should_process() + if (!on) + popDown() + +/obj/machinery/porta_turret/proc/check_should_process() + if (datum_flags & DF_ISPROCESSING) + if (!on || !anchored || (stat & BROKEN) || !powered()) + //end_processing() + STOP_PROCESSING(SSmachines, src) + else + if (on && anchored && !(stat & BROKEN) && powered()) + START_PROCESSING(SSmachines, src) + //begin_processing() + /obj/machinery/porta_turret/update_icon_state() if(!anchored) icon_state = "turretCover" @@ -119,7 +158,6 @@ else icon_state = "[base_icon_state]_unpowered" - /obj/machinery/porta_turret/proc/setup(obj/item/gun/turret_gun) if(stored_gun) qdel(stored_gun) @@ -160,83 +198,88 @@ remove_control() return ..() -/obj/machinery/porta_turret/ui_interact(mob/user) - . = ..() - var/dat - dat += "Status: [on ? "On" : "Off"]
" - dat += "Behaviour controls are [locked ? "locked" : "unlocked"]
" +/obj/machinery/porta_turret/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "PortableTurret", name) + ui.open() - if(!locked) - dat += "Check for Weapon Authorization: [auth_weapons ? "Yes" : "No"]
" - dat += "Check Security Records: [check_records ? "Yes" : "No"]
" - dat += "Neutralize Identified Criminals: [criminals ? "Yes" : "No"]
" - dat += "Neutralize All Non-Security and Non-Command Personnel: [stun_all ? "Yes" : "No"]
" - dat += "Neutralize All Unidentified Life Signs: [check_anomalies ? "Yes" : "No"]
" - dat += "Neutralize All Non-Loyalty Implanted Personnel: [shoot_unloyal ? "Yes" : "No"]
" +/obj/machinery/porta_turret/ui_data(mob/user) + var/list/data = list( + "locked" = locked, + "on" = on, + "check_weapons" = turret_flags & TURRET_FLAG_AUTH_WEAPONS, + "neutralize_criminals" = turret_flags & TURRET_FLAG_SHOOT_CRIMINALS, + "neutralize_all" = turret_flags & TURRET_FLAG_SHOOT_ALL, + "neutralize_unidentified" = turret_flags & TURRET_FLAG_SHOOT_ANOMALOUS, + "neutralize_nonmindshielded" = turret_flags & TURRET_FLAG_SHOOT_UNSHIELDED, + "neutralize_cyborgs" = turret_flags & TURRET_FLAG_SHOOT_BORGS, + "ignore_heads" = turret_flags & TURRET_FLAG_SHOOT_HEADS, + "manual_control" = manual_control, + "silicon_user" = FALSE, + "allow_manual_control" = FALSE, + "lasertag_turret" = istype(src, /obj/machinery/porta_turret/lasertag), + ) if(issilicon(user)) + data["silicon_user"] = TRUE if(!manual_control) var/mob/living/silicon/S = user if(S.hack_software) - dat += "Assume direct control : Manual Control
" - else - dat += "Warning! Remote control protocol enabled.
" + data["allow_manual_control"] = TRUE + return data - - var/datum/browser/popup = new(user, "autosec", "Automatic Portable Turret Installation", 300, 300) - popup.set_content(dat) - popup.open() - -/obj/machinery/porta_turret/Topic(href, href_list) - if(..()) - return - usr.set_machine(src) - add_fingerprint(usr) - - if(href_list["power"] && !locked) - if(anchored) //you can't turn a turret on/off if it's not anchored/secured - on = !on //toggle on/off - else - to_chat(usr, "It has to be secured first!") - interact(usr) +/obj/machinery/porta_turret/ui_act(action, list/params) + . = ..() + if(.) return - if(href_list["operation"]) - switch(href_list["operation"]) //toggles customizable behavioural protocols - if("authweapon") - auth_weapons = !auth_weapons - if("checkrecords") - check_records = !check_records - if("shootcrooks") - criminals = !criminals - if("shootall") - stun_all = !stun_all - if("checkxenos") - check_anomalies = !check_anomalies - if("checkloyal") - shoot_unloyal = !shoot_unloyal - if("manual") - if(issilicon(usr) && !manual_control) - give_control(usr) - interact(usr) + switch(action) + if("power") + if(anchored) + toggle_on() + return TRUE + else + to_chat(usr, "It has to be secured first!") + if("authweapon") + turret_flags ^= TURRET_FLAG_AUTH_WEAPONS + return TRUE + if("shootcriminals") + turret_flags ^= TURRET_FLAG_SHOOT_CRIMINALS + return TRUE + if("shootall") + turret_flags ^= TURRET_FLAG_SHOOT_ALL + return TRUE + if("checkxenos") + turret_flags ^= TURRET_FLAG_SHOOT_ANOMALOUS + return TRUE + if("checkloyal") + turret_flags ^= TURRET_FLAG_SHOOT_UNSHIELDED + return TRUE + if("shootborgs") + turret_flags ^= TURRET_FLAG_SHOOT_BORGS + return TRUE + if("shootheads") + turret_flags ^= TURRET_FLAG_SHOOT_HEADS + return TRUE + if("manual") + if(!issilicon(usr)) + return + give_control(usr) + return TRUE + +/obj/machinery/porta_turret/ui_host(mob/user) + if(has_cover && cover) + return cover + if(base) + return base + return src /obj/machinery/porta_turret/power_change() - if(!anchored) + . = ..() + if(!anchored || (stat & BROKEN) || !powered()) update_icon() remove_control() - return - if(stat & BROKEN) - update_icon() - remove_control() - else - if( powered() ) - stat &= ~NOPOWER - update_icon() - else - spawn(rand(0, 15)) - stat |= NOPOWER - remove_control() - update_icon() - + check_should_process() /obj/machinery/porta_turret/attackby(obj/item/I, mob/user, params) if(stat & BROKEN) @@ -284,8 +327,10 @@ locked = !locked to_chat(user, "Controls are now [locked ? "locked" : "unlocked"].") else - to_chat(user, "Access denied.") + to_chat(user, "Access denied.") else if(istype(I, /obj/item/multitool) && !locked) + if(!multitool_check_buffer(user, I)) + return var/obj/item/multitool/M = I M.buffer = src to_chat(user, "You add [src] to multitool buffer.") @@ -293,19 +338,17 @@ return ..() /obj/machinery/porta_turret/emag_act(mob/user) - . = ..() if(obj_flags & EMAGGED) return to_chat(user, "You short out [src]'s threat assessment circuits.") - visible_message("[src] hums oddly...") + audible_message("[src] hums oddly...") obj_flags |= EMAGGED controllock = TRUE - on = FALSE //turns off the turret temporarily + toggle_on(FALSE) //turns off the turret temporarily update_icon() - sleep(60) //6 seconds for the traitor to gtfo of the area before the turret decides to ruin his shit - on = TRUE //turns it back on. The cover popUp() popDown() are automatically called in process(), no need to define it here - return TRUE - + //6 seconds for the traitor to gtfo of the area before the turret decides to ruin his shit + addtimer(CALLBACK(src, .proc/toggle_on, TRUE), 6 SECONDS) + //turns it back on. The cover popUp() popDown() are automatically called in process(), no need to define it here /obj/machinery/porta_turret/emp_act(severity) . = ..() @@ -314,63 +357,41 @@ if(on) //if the turret is on, the EMP no matter how severe disables the turret for a while //and scrambles its settings, with a slight chance of having an emag effect - check_records = pick(0, 1) - criminals = pick(0, 1) - auth_weapons = pick(0, 1) - stun_all = pick(0, 0, 0, 0, 1) //stun_all is a pretty big deal, so it's least likely to get turned on + if(prob(50)) + turret_flags |= TURRET_FLAG_SHOOT_CRIMINALS + if(prob(50)) + turret_flags |= TURRET_FLAG_AUTH_WEAPONS + if(prob(20)) + turret_flags |= TURRET_FLAG_SHOOT_ALL // Shooting everyone is a pretty big deal, so it's least likely to get turned on - on = FALSE + toggle_on(FALSE) remove_control() - spawn(rand(60,600)) - if(!on) - on = TRUE + addtimer(CALLBACK(src, .proc/toggle_on, TRUE), rand(60,600)) /obj/machinery/porta_turret/take_damage(damage, damage_type = BRUTE, damage_flag = 0, sound_effect = 1) . = ..() - if(.) //damage received + if(. && obj_integrity > 0) //damage received if(prob(30)) spark_system.start() - if(on && !attacked && !(obj_flags & EMAGGED)) - attacked = TRUE + if(on && !(turret_flags & TURRET_FLAG_SHOOT_ALL_REACT) && !(obj_flags & EMAGGED)) + turret_flags |= TURRET_FLAG_SHOOT_ALL_REACT addtimer(CALLBACK(src, .proc/reset_attacked), 60) /obj/machinery/porta_turret/proc/reset_attacked() - attacked = FALSE + turret_flags &= ~TURRET_FLAG_SHOOT_ALL_REACT /obj/machinery/porta_turret/deconstruct(disassembled = TRUE) qdel(src) /obj/machinery/porta_turret/obj_break(damage_flag) - if(!(flags_1 & NODECONSTRUCT_1) && !(stat & BROKEN)) - stat |= BROKEN //enables the BROKEN bit + . = ..() + if(.) power_change() invisibility = 0 spark_system.start() //creates some sparks because they look cool qdel(cover) //deletes the cover - no need on keeping it there! -//turret healing -/obj/machinery/porta_turret/examine(mob/user) - . = ..() - if(obj_integrity < max_integrity) - . += "Use a welder to fix it." - -/obj/machinery/porta_turret/welder_act(mob/living/user, obj/item/I) - . = TRUE - if(obj_integrity < max_integrity) - if(!I.tool_start_check(user, amount=0)) - return - user.visible_message("[user] is welding the turret.", \ - "You begin repairing the turret...", \ - "You hear welding.") - if(I.use_tool(src, user, 40, volume=50)) - obj_integrity = max_integrity - user.visible_message("[user.name] has repaired [src].", \ - "You finish repairing the turret.") - else - to_chat(user, "The turret doesn't need repairing.") - - /obj/machinery/porta_turret/process() //the main machinery process if(cover == null && anchored) //if it has no cover and is anchored @@ -382,35 +403,43 @@ cover.parent_turret = src //assign the cover its parent_turret, which would be this (src) if(!on || (stat & (NOPOWER|BROKEN)) || manual_control) - return + return PROCESS_KILL var/list/targets = list() for(var/mob/A in view(scan_range, base)) if(A.invisibility > SEE_INVISIBLE_LIVING) continue - if(check_anomalies)//if it's set to check for simple animals + if(turret_flags & TURRET_FLAG_SHOOT_ANOMALOUS)//if it's set to check for simple animals if(isanimal(A)) var/mob/living/simple_animal/SA = A if(SA.stat || in_faction(SA)) //don't target if dead or in faction continue targets += SA - if(issilicon(A)) - var/mob/living/silicon/sillycone = A - if(sillycone.stat || in_faction(sillycone)) + continue + + if(issilicon(A)) + var/mob/living/silicon/sillycone = A + + if(ispAI(A)) + continue + + if((turret_flags & TURRET_FLAG_SHOOT_BORGS) && sillycone.stat != DEAD && iscyborg(sillycone)) + targets += sillycone + continue + + if(sillycone.stat || in_faction(sillycone)) + continue + + if(iscyborg(sillycone)) + var/mob/living/silicon/robot/sillyconerobot = A + if(LAZYLEN(faction) && (ROLE_SYNDICATE in faction) && sillyconerobot.emagged == TRUE) continue - if(iscyborg(sillycone)) - var/mob/living/silicon/robot/sillyconerobot = A - if(LAZYLEN(faction) && (ROLE_SYNDICATE in faction) && sillyconerobot.emagged == TRUE) - continue - - targets += sillycone - - if(iscarbon(A)) + else if(iscarbon(A)) var/mob/living/carbon/C = A - //If not emagged, only target non downed carbons - if(mode != TURRET_LETHAL && (C.stat || C.handcuffed || (C.combat_flags & COMBAT_FLAG_HARD_STAMCRIT)))//CIT CHANGE - replaces check for lying with check for recoveringstam + //If not emagged, only target carbons that can use items + if(mode != TURRET_LETHAL && (C.stat || C.handcuffed || !(C.mobility_flags & MOBILITY_USE))) continue //If emagged, target all but dead carbons @@ -419,12 +448,13 @@ //if the target is a human and not in our faction, analyze threat level if(ishuman(C) && !in_faction(C)) + if(assess_perp(C) >= 4) targets += C - - else if(check_anomalies) //non humans who are not simple animals (xenos etc) + else if(turret_flags & TURRET_FLAG_SHOOT_ANOMALOUS) //non humans who are not simple animals (xenos etc) if(!in_faction(C)) targets += C + for(var/A in GLOB.mechas_list) if((get_dist(A, base) < scan_range) && can_see(base, A, scan_range)) var/obj/mecha/Mech = A @@ -432,6 +462,10 @@ if(assess_perp(Mech.occupant) >= 4) targets += Mech + if((turret_flags & TURRET_FLAG_SHOOT_ANOMALOUS) && GLOB.blobs.len && (mode == TURRET_LETHAL)) + for(var/obj/structure/blob/B in view(scan_range, base)) + targets += B + if(targets.len) tryToShootAt(targets) else if(!always_up) @@ -488,36 +522,37 @@ if(obj_flags & EMAGGED) return 10 //if emagged, always return 10. - if((stun_all || attacked) && !allowed(perp)) + if((turret_flags & (TURRET_FLAG_SHOOT_ALL | TURRET_FLAG_SHOOT_ALL_REACT)) && !allowed(perp)) //if the turret has been attacked or is angry, target all non-sec people if(!allowed(perp)) return 10 - if(auth_weapons) //check for weapon authorization + if(turret_flags & TURRET_FLAG_AUTH_WEAPONS) //check for weapon authorization if(isnull(perp.wear_id) || istype(perp.wear_id.GetID(), /obj/item/card/id/syndicate)) if(allowed(perp)) //if the perp has security access, return 0 return 0 - if(perp.is_holding_item_of_type(/obj/item/gun) || perp.is_holding_item_of_type(/obj/item/melee/baton)) threatcount += 4 if(istype(perp.belt, /obj/item/gun) || istype(perp.belt, /obj/item/melee/baton)) threatcount += 2 - if(check_records) //if the turret can check the records, check if they are set to *Arrest* on records + if(turret_flags & TURRET_FLAG_SHOOT_CRIMINALS) //if the turret can check the records, check if they are set to *Arrest* on records var/perpname = perp.get_face_name(perp.get_id_name()) var/datum/data/record/R = find_record("name", perpname, GLOB.data_core.security) if(!R || (R.fields["criminal"] == "*Arrest*")) threatcount += 4 - if(shoot_unloyal) - if (!HAS_TRAIT(perp, TRAIT_MINDSHIELD)) - threatcount += 4 + if((turret_flags & TURRET_FLAG_SHOOT_UNSHIELDED) && (!HAS_TRAIT(perp, TRAIT_MINDSHIELD))) + threatcount += 4 + + // If we aren't shooting heads then return a threatcount of 0 + if (!(turret_flags & TURRET_FLAG_SHOOT_HEADS) && (perp.get_assignment() in GLOB.command_positions)) + return 0 return threatcount - /obj/machinery/porta_turret/proc/in_faction(mob/target) for(var/faction1 in faction) if(faction1 in target.faction) @@ -563,15 +598,14 @@ T = closer break - var/mob/living/carbon/C - if(iscarbon(target)) - C = target - update_icon() var/obj/item/projectile/A //any emagged turrets drains 2x power and uses a different projectile? if(mode == TURRET_STUN) - if(nonlethal_projectile && C && C.resting) + var/mob/living/carbon/C = null + if(iscarbon(target)) + C = target + if(nonlethal_projectile && C?.resting) use_power(reqpower*0.5) A = new nonlethal_projectile(T) playsound(loc, nonlethal_projectile_sound, 75, 1) @@ -582,7 +616,7 @@ else use_power(reqpower * 2) A = new lethal_projectile(T) - playsound(loc, lethal_projectile_sound, 75, 1) + playsound(loc, lethal_projectile_sound, 75, TRUE) //Shooting Code: @@ -592,16 +626,15 @@ A.fire() return A -/obj/machinery/porta_turret/proc/setState(on, mode) +/obj/machinery/porta_turret/proc/setState(on, mode, shoot_cyborgs) if(controllock) return - src.on = on - if(!on) - popDown() + + shoot_cyborgs ? (turret_flags |= TURRET_FLAG_SHOOT_BORGS) : (turret_flags &= ~TURRET_FLAG_SHOOT_BORGS) + toggle_on(on) src.mode = mode power_change() - /datum/action/turret_toggle name = "Toggle Mode" icon_icon = 'icons/mob/actions/actions_mecha.dmi' @@ -685,7 +718,15 @@ /obj/machinery/porta_turret/syndicate/ComponentInitialize() . = ..() - AddElement(/datum/element/empprotection, EMP_PROTECT_SELF | EMP_PROTECT_WIRES) + // AddComponent(/datum/component/empprotection, EMP_PROTECT_SELF | EMP_PROTECT_WIRES) + AddElement(/datum/element/empprotection, EMP_PROTECT_SELF | EMP_PROTECT_WIRES) //this one or ^ one? + + +/obj/machinery/porta_turret/syndicate/setup() + return + +/obj/machinery/porta_turret/syndicate/assess_perp(mob/living/carbon/human/perp) + return 10 //Syndicate turrets shoot everything not in their faction /obj/machinery/porta_turret/syndicate/energy icon_state = "standard_stun" @@ -698,7 +739,6 @@ lethal_projectile_sound = 'sound/weapons/laser.ogg' desc = "An energy blaster auto-turret." - /obj/machinery/porta_turret/syndicate/energy/heavy icon_state = "standard_stun" base_icon_state = "standard" @@ -715,14 +755,13 @@ integrity_failure = 0.08 armor = list("melee" = 50, "bullet" = 30, "laser" = 30, "energy" = 30, "bomb" = 50, "bio" = 0, "rad" = 0, "fire" = 90, "acid" = 90) - -/obj/machinery/porta_turret/syndicate/setup() - return - -/obj/machinery/porta_turret/syndicate/assess_perp(mob/living/carbon/human/perp) - return 10 //Syndicate turrets shoot everything not in their faction +/obj/machinery/porta_turret/syndicate/energy/raven + stun_projectile = /obj/item/projectile/beam/laser + stun_projectile_sound = 'sound/weapons/laser.ogg' + faction = list("neutral","silicon","turret") /obj/machinery/porta_turret/syndicate/pod + integrity_failure = 0.5 max_integrity = 40 stun_projectile = /obj/item/projectile/bullet/syndicate_turret lethal_projectile = /obj/item/projectile/bullet/syndicate_turret @@ -749,6 +788,7 @@ faction = list("silicon") nonlethal_projectile = /obj/item/projectile/beam/disabler nonlethal_projectile_sound = 'sound/weapons/taser2.ogg' + turret_flags = TURRET_FLAG_SHOOT_CRIMINALS | TURRET_FLAG_SHOOT_ANOMALOUS | TURRET_FLAG_SHOOT_HEADS /obj/machinery/porta_turret/ai/assess_perp(mob/living/carbon/human/perp) return 10 //AI turrets shoot at everything not in their faction @@ -804,6 +844,7 @@ /obj/machinery/porta_turret/centcom_shuttle/weak max_integrity = 120 + integrity_failure = 0.5 name = "Old Laser Turret" desc = "A turret built with substandard parts and run down further with age. Still capable of delivering lethal lasers to the odd space carp, but not much else." stun_projectile = /obj/item/projectile/beam/weak/penetrator @@ -817,7 +858,6 @@ stun_projectile_sound = 'sound/weapons/gunshot.ogg' desc = "A ballistic machine gun auto-turret." - //////////////////////// //Turret Control Panel// //////////////////////// @@ -828,14 +868,22 @@ icon = 'icons/obj/machines/turret_control.dmi' icon_state = "control_standby" density = FALSE - var/enabled = 1 - var/lethal = 0 - var/locked = TRUE - var/control_area = null //can be area name, path or nothing. - var/ailock = 0 // AI cannot use this req_access = list(ACCESS_AI_UPLOAD) - var/list/obj/machinery/porta_turret/turrets = list() resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF + /// Variable dictating if linked turrets are active and will shoot targets + var/enabled = TRUE + /// Variable dictating if linked turrets will shoot lethal projectiles + var/lethal = FALSE + /// Variable dictating if the panel is locked, preventing changes to turret settings + var/locked = TRUE + /// An area in which linked turrets are located, it can be an area name, path or nothing + var/control_area = null + /// AI is unable to use this machine if set to TRUE + var/ailock = FALSE + /// Variable dictating if linked turrets will shoot cyborgs + var/shoot_cyborgs = FALSE + /// List of all linked turrets + var/list/turrets = list() /obj/machinery/turretid/Initialize(mapload, ndir = 0, built = 0) . = ..() @@ -868,112 +916,111 @@ T.cp = src /obj/machinery/turretid/examine(mob/user) - . = ..() - if(hasSiliconAccessInArea(user) && (!stat & BROKEN)) - . += "Ctrl-click [src] to [ enabled ? "disable" : "enable"] turrets." - . += "Alt-click [src] to set turrets to [ lethal ? "stun" : "kill"]." + . += ..() + if(issilicon(user) && !(stat & BROKEN)) + . += {"Ctrl-click [src] to [ enabled ? "disable" : "enable"] turrets. + Alt-click [src] to set turrets to [ lethal ? "stun" : "kill"]."} /obj/machinery/turretid/attackby(obj/item/I, mob/user, params) if(stat & BROKEN) return if (istype(I, /obj/item/multitool)) + if(!multitool_check_buffer(user, I)) + return var/obj/item/multitool/M = I if(M.buffer && istype(M.buffer, /obj/machinery/porta_turret)) turrets |= M.buffer - to_chat(user, "You link \the [M.buffer] with \the [src]") + to_chat(user, "You link \the [M.buffer] with \the [src].") return - if (hasSiliconAccessInArea(user)) + if (issilicon(user)) return attack_hand(user) if ( get_dist(src, user) == 0 ) // trying to unlock the interface if (allowed(usr)) if(obj_flags & EMAGGED) - to_chat(user, "The turret control is unresponsive.") + to_chat(user, "The turret control is unresponsive!") return locked = !locked to_chat(user, "You [ locked ? "lock" : "unlock"] the panel.") - if (locked) - if (user.machine==src) - user.unset_machine() - user << browse(null, "window=turretid") - else - if (user.machine==src) - attack_hand(user) else - to_chat(user, "Access denied.") + to_chat(user, "Access denied.") /obj/machinery/turretid/emag_act(mob/user) - . = ..() if(obj_flags & EMAGGED) return - to_chat(user, "You short out the turret controls' access analysis module.") + to_chat(user, "You short out the turret controls' access analysis module.") obj_flags |= EMAGGED locked = FALSE - if(user && user.machine == src) - attack_hand(user) - return TRUE /obj/machinery/turretid/attack_ai(mob/user) if(!ailock || IsAdminGhost(user)) return attack_hand(user) else - to_chat(user, "There seems to be a firewall preventing you from accessing this device.") + to_chat(user, "There seems to be a firewall preventing you from accessing this device!") -/obj/machinery/turretid/ui_interact(mob/user) +/obj/machinery/turretid/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "TurretControl", name) + ui.open() + +/obj/machinery/turretid/ui_data(mob/user) + var/list/data = list() + data["locked"] = locked + data["siliconUser"] = hasSiliconAccessInArea(user) || IsAdminGhost(user) + data["enabled"] = enabled + data["lethal"] = lethal + data["shootCyborgs"] = shoot_cyborgs + return data + +/obj/machinery/turretid/ui_act(action, list/params) . = ..() - if ( get_dist(src, user) > 0 ) - if ( !(hasSiliconAccessInArea(user) || IsAdminGhost(user)) ) - to_chat(user, "You are too far away.") - user.unset_machine() - user << browse(null, "window=turretid") - return - - var/t = "" - - if(locked && !(hasSiliconAccessInArea(user) || IsAdminGhost(user))) - t += "
Swipe ID card to unlock interface
" - else - if(!hasSiliconAccessInArea(user) && !IsAdminGhost(user)) - t += "
Swipe ID card to lock interface
" - t += "Turrets [enabled?"activated":"deactivated"] - [enabled?"Disable":"Enable"]?
" - t += "Currently set for [lethal?"lethal":"stun repeatedly"] - Change to [lethal?"Stun repeatedly":"Lethal"]?
" - - var/datum/browser/popup = new(user, "turretid", "Turret Control Panel ([get_area_name(src, TRUE)])") - popup.set_content(t) - popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state)) - popup.open() - -/obj/machinery/turretid/Topic(href, href_list) - if(..()) + if(.) return - if (locked) - if(!(hasSiliconAccessInArea(usr) || IsAdminGhost(usr))) - to_chat(usr, "Control panel is locked!") - return - if (href_list["toggleOn"]) - toggle_on() - else if (href_list["toggleLethal"]) - toggle_lethal() - attack_hand(usr) -/obj/machinery/turretid/proc/toggle_lethal() + switch(action) + if("lock") + if(!hasSiliconAccessInArea(usr) || IsAdminGhost(usr)) + return + if((obj_flags & EMAGGED) || (stat & BROKEN)) + to_chat(usr, "The turret control is unresponsive!") + return + locked = !locked + return TRUE + if("power") + toggle_on(usr) + return TRUE + if("mode") + toggle_lethal(usr) + return TRUE + if("shoot_silicons") + shoot_silicons(usr) + return TRUE + +/obj/machinery/turretid/proc/toggle_lethal(mob/user) lethal = !lethal + add_hiddenprint(user) + log_combat(user, src, "[lethal ? "enabled" : "disabled"] lethals on") updateTurrets() -/obj/machinery/turretid/proc/toggle_on() +/obj/machinery/turretid/proc/toggle_on(mob/user) enabled = !enabled + add_hiddenprint(user) + log_combat(user, src, "[enabled ? "enabled" : "disabled"]") + updateTurrets() + +/obj/machinery/turretid/proc/shoot_silicons(mob/user) + shoot_cyborgs = !shoot_cyborgs + add_hiddenprint(user) + log_combat(user, src, "[shoot_cyborgs ? "Shooting Borgs" : "Not Shooting Borgs"]") updateTurrets() /obj/machinery/turretid/proc/updateTurrets() for (var/obj/machinery/porta_turret/aTurret in turrets) - aTurret.setState(enabled, lethal) - update_icon() - -/obj/machinery/turretid/power_change() - ..() + aTurret.setState(enabled, lethal, shoot_cyborgs) update_icon() /obj/machinery/turretid/update_icon_state() @@ -1051,11 +1098,7 @@ /obj/machinery/porta_turret/lasertag req_access = list(ACCESS_MAINT_TUNNELS, ACCESS_THEATRE) - check_records = 0 - criminals = 0 - auth_weapons = 1 - stun_all = 0 - check_anomalies = 0 + turret_flags = TURRET_FLAG_AUTH_WEAPONS var/team_color /obj/machinery/porta_turret/lasertag/assess_perp(mob/living/carbon/human/perp) @@ -1083,20 +1126,14 @@ if(properties["team_color"]) team_color = properties["team_color"] -/obj/machinery/porta_turret/lasertag/ui_interact(mob/user) - . = ..() +/obj/machinery/porta_turret/lasertag/ui_status(mob/user) if(ishuman(user)) var/mob/living/carbon/human/H = user if(team_color == "blue" && istype(H.wear_suit, /obj/item/clothing/suit/redtag)) - return + return UI_CLOSE if(team_color == "red" && istype(H.wear_suit, /obj/item/clothing/suit/bluetag)) - return - - var/dat = "Status: [on ? "On" : "Off"]" - - var/datum/browser/popup = new(user, "autosec", "Automatic Portable Turret Installation", 300, 300) - popup.set_content(dat) - popup.open() + return UI_CLOSE + return ..() //lasertag presets /obj/machinery/porta_turret/lasertag/red @@ -1112,11 +1149,9 @@ if(on) if(team_color == "blue") if(istype(P, /obj/item/projectile/beam/lasertag/redtag)) - on = FALSE - spawn(100) - on = TRUE + toggle_on(FALSE) + addtimer(CALLBACK(src, .proc/toggle_on, TRUE), 10 SECONDS) else if(team_color == "red") if(istype(P, /obj/item/projectile/beam/lasertag/bluetag)) - on = FALSE - spawn(100) - on = TRUE + toggle_on(FALSE) + addtimer(CALLBACK(src, .proc/toggle_on, TRUE), 10 SECONDS) diff --git a/code/game/machinery/rechargestation.dm b/code/game/machinery/rechargestation.dm index bbafe99006..0accd0994c 100644 --- a/code/game/machinery/rechargestation.dm +++ b/code/game/machinery/rechargestation.dm @@ -126,17 +126,6 @@ update_icon() /obj/machinery/recharge_station/proc/process_occupant() - if(occupant && iscyborg(occupant)) - var/mob/living/silicon/robot/R = occupant - restock_modules() - if(repairs) - R.heal_bodypart_damage(repairs, repairs - 1) - if(R.cell) - R.cell.charge = min(R.cell.charge + recharge_speed, R.cell.maxcharge) - -/obj/machinery/recharge_station/proc/restock_modules() - if(occupant) - var/mob/living/silicon/robot/R = occupant - if(R && R.module) - var/coeff = recharge_speed * 0.005 - R.module.respawn_consumable(R, coeff) + if(!occupant) + return + SEND_SIGNAL(occupant, COMSIG_PROCESS_BORGCHARGER_OCCUPANT, recharge_speed, repairs) diff --git a/code/game/machinery/spaceheater.dm b/code/game/machinery/spaceheater.dm index e6137c08c2..c6484b051c 100644 --- a/code/game/machinery/spaceheater.dm +++ b/code/game/machinery/spaceheater.dm @@ -170,12 +170,10 @@ ..() default_unfasten_wrench(user, I, 5) return TRUE - -/obj/machinery/space_heater/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ - datum/tgui/master_ui = null, datum/ui_state/state = GLOB.physical_state) - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) +/obj/machinery/space_heater/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) if(!ui) - ui = new(user, src, ui_key, "SpaceHeater", name, 400, 305, master_ui, state) + ui = new(user, src, "SpaceHeater", name) ui.open() /obj/machinery/space_heater/ui_data() @@ -210,7 +208,7 @@ if("power") on = !on mode = HEATER_MODE_STANDBY - usr.visible_message("[usr] switches [on ? "on" : "off"] \the [src].", "You switch [on ? "on" : "off"] \the [src].") + usr.visible_message("[usr] switches [on ? "on" : "off"] \the [src].", "You switch [on ? "on" : "off"] \the [src].") update_icon() if (on) START_PROCESSING(SSmachines, src) @@ -222,16 +220,7 @@ if(!panel_open) return var/target = params["target"] - var/adjust = text2num(params["adjust"]) - if(target == "input") - target = input("New target temperature:", name, round(targetTemperature - T0C, 1)) as num|null - if(!isnull(target) && !..()) - target += T0C - . = TRUE - else if(adjust) - target = targetTemperature + adjust - . = TRUE - else if(text2num(target) != null) + if(text2num(target) != null) target= text2num(target) + T0C . = TRUE if(.) diff --git a/code/game/machinery/suit_storage_unit.dm b/code/game/machinery/suit_storage_unit.dm index 75772786fc..cecf351ea9 100644 --- a/code/game/machinery/suit_storage_unit.dm +++ b/code/game/machinery/suit_storage_unit.dm @@ -377,11 +377,13 @@ return ..() -/obj/machinery/suit_storage_unit/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ - datum/tgui/master_ui = null, datum/ui_state/state = GLOB.notcontained_state) - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) +/obj/machinery/suit_storage_unit/ui_state(mob/user) + return GLOB.notcontained_state + +/obj/machinery/suit_storage_unit/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) if(!ui) - ui = new(user, src, ui_key, "SuitStorageUnit", name, 400, 305, master_ui, state) + ui = new(user, src, "SuitStorageUnit", name) ui.open() /obj/machinery/suit_storage_unit/ui_data() diff --git a/code/game/machinery/telecomms/computers/logbrowser.dm b/code/game/machinery/telecomms/computers/logbrowser.dm index 9867a1c133..ca04009e3b 100644 --- a/code/game/machinery/telecomms/computers/logbrowser.dm +++ b/code/game/machinery/telecomms/computers/logbrowser.dm @@ -17,11 +17,10 @@ var/notice = "" var/universal_translate = FALSE // set to TRUE(1) if it can translate nonhuman speech -/obj/machinery/computer/telecomms/server/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ - datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) +/obj/machinery/computer/telecomms/server/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) if(!ui) - ui = new(user, src, ui_key, "TelecommsLogBrowser", "Telecomms Server Monitor", 575, 400, master_ui, state) + ui = new(user, src, "TelecommsLogBrowser", "Telecomms Server Monitor") ui.open() /obj/machinery/computer/telecomms/server/ui_data(mob/user) diff --git a/code/game/machinery/telecomms/computers/message.dm b/code/game/machinery/telecomms/computers/message.dm index 11d50a2858..539025e4d5 100644 --- a/code/game/machinery/telecomms/computers/message.dm +++ b/code/game/machinery/telecomms/computers/message.dm @@ -36,12 +36,11 @@ light_color = LIGHT_COLOR_GREEN -/obj/machinery/computer/message_monitor/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE,\ - datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) +/obj/machinery/computer/message_monitor/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) if(!ui) - ui = new(user, src, ui_key, "TelecommsPDALog", name, 727, 510, master_ui, state) + ui = new(user, src, "TelecommsPDALog", name) ui.open() /obj/machinery/computer/message_monitor/ui_static_data(mob/user) diff --git a/code/game/machinery/telecomms/computers/telemonitor.dm b/code/game/machinery/telecomms/computers/telemonitor.dm index 11312fcfaf..b711b9fa40 100644 --- a/code/game/machinery/telecomms/computers/telemonitor.dm +++ b/code/game/machinery/telecomms/computers/telemonitor.dm @@ -17,12 +17,11 @@ circuit = /obj/item/circuitboard/computer/comm_monitor -/obj/machinery/computer/telecomms/monitor/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE,\ - datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) +/obj/machinery/computer/telecomms/monitor/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) if(!ui) - ui = new(user, src, ui_key, "TelecommsMonitor", name, 575, 400, master_ui, state) + ui = new(user, src, "TelecommsMonitor", name) ui.open() /obj/machinery/computer/telecomms/monitor/ui_data(mob/user) diff --git a/code/game/machinery/telecomms/machine_interactions.dm b/code/game/machinery/telecomms/machine_interactions.dm index 86aa7905d5..cc8784c5b8 100644 --- a/code/game/machinery/telecomms/machine_interactions.dm +++ b/code/game/machinery/telecomms/machine_interactions.dm @@ -27,16 +27,15 @@ else return ..() -/obj/machinery/telecomms/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE,\ - datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) +/obj/machinery/telecomms/ui_interact(mob/user, datum/tgui/ui) if(!canInteract(user)) if(ui) ui.close() //haha no. return - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) + ui = SStgui.try_update_ui(user, src, ui) if(!ui) - ui = new(user, src, ui_key, "TelecommsInteraction", "[name] Access", 520, 500, master_ui, state) + ui = new(user, src, "TelecommsInteraction", "[name] Access") ui.open() /obj/machinery/telecomms/ui_data(mob/user) diff --git a/code/game/mecha/equipment/mecha_equipment.dm b/code/game/mecha/equipment/mecha_equipment.dm index 86cdd87505..ef1565502e 100644 --- a/code/game/mecha/equipment/mecha_equipment.dm +++ b/code/game/mecha/equipment/mecha_equipment.dm @@ -11,10 +11,15 @@ var/equip_ready = 1 //whether the equipment is ready for use. (or deactivated/activated for static stuff) var/energy_drain = 0 var/obj/mecha/chassis = null - var/range = MELEE //bitFflags + /// Bitflag. Determines the range of the equipment. + var/range = MELEE + /// Bitflag. Used by exosuit fabricator to assign sub-categories based on which exosuits can equip this. + var/mech_flags = NONE var/salvageable = 1 + //var/detachable = TRUE // Set to FALSE for built-in equipment that cannot be removed var/selectable = 1 // Set to 0 for passive equipment such as mining scanner or armor plates var/harmful = FALSE //Controls if equipment can be used to attack by a pacifist. + //var/destroy_sound = 'sound/mecha/critdestr.ogg' /obj/item/mecha_parts/mecha_equipment/proc/update_chassis_page() if(chassis) @@ -35,9 +40,14 @@ if(chassis.selected == src) chassis.selected = null src.update_chassis_page() - chassis.occupant_message("[src] is destroyed!") + //log_message("[src] is destroyed.", LOG_MECHA) chassis.log_append_to_last("[src] is destroyed.",1) - SEND_SOUND(chassis.occupant, sound(istype(src, /obj/item/mecha_parts/mecha_equipment/weapon) ? 'sound/mecha/weapdestr.ogg' : 'sound/mecha/critdestr.ogg', volume=50)) + if(chassis.occupant) + chassis.occupant_message("[src] is destroyed!") + SEND_SOUND(chassis.occupant, sound(istype(src, /obj/item/mecha_parts/mecha_equipment/weapon) ? 'sound/mecha/weapdestr.ogg' : 'sound/mecha/critdestr.ogg', volume=50)) + //chassis.occupant.playsound_local(chassis, destroy_sound, 50) + //if(!detachable) //If we're a built-in nondetachable equipment, let's lock up the slot that we were in. + // chassis.max_equip-- chassis = null return ..() @@ -59,7 +69,7 @@ return txt /obj/item/mecha_parts/mecha_equipment/proc/is_ranged()//add a distance restricted equipment. Why not? - return range&RANGED + return range&RANGED //rename to MECHA_RANGE and MECHA_MELEE /obj/item/mecha_parts/mecha_equipment/proc/is_melee() return range&MELEE @@ -72,10 +82,10 @@ return 0 if(!equip_ready) return 0 - if(crit_fail) - return 0 if(energy_drain && !chassis.has_charge(energy_drain)) return 0 + if(crit_fail) + return 0 if(chassis.equipment_disabled) to_chat(chassis.occupant, "Error -- Equipment control unit is unresponsive.") return 0 @@ -117,8 +127,6 @@ chassis = M forceMove(M) M.mecha_log_message("[src] initialized.") - if(!M.selected && selectable) - M.selected = src src.update_chassis_page() return @@ -150,7 +158,7 @@ chassis.occupant_message("[icon2html(src, chassis.occupant)] [message]") return -/obj/item/mecha_parts/mecha_equipment/proc/mecha_log_message(message, color) +/obj/item/mecha_parts/mecha_equipment/proc/mecha_log_message(message, color) //on tg this just overrides log_message log_message(message, LOG_GAME, color) //pass to default admin logging too if(chassis) chassis.mecha_log_message(message, color) //and pass to our chassis diff --git a/code/game/mecha/equipment/tools/medical_tools.dm b/code/game/mecha/equipment/tools/medical_tools.dm index 4a4d58ea73..1435f78718 100644 --- a/code/game/mecha/equipment/tools/medical_tools.dm +++ b/code/game/mecha/equipment/tools/medical_tools.dm @@ -1,6 +1,7 @@ // Sleeper, Medical Beam, and Syringe gun /obj/item/mecha_parts/mecha_equipment/medical + mech_flags = EXOSUIT_MODULE_MEDICAL /obj/item/mecha_parts/mecha_equipment/medical/Initialize() . = ..() diff --git a/code/game/mecha/equipment/tools/mining_tools.dm b/code/game/mecha/equipment/tools/mining_tools.dm index d4a29f639d..7c7c6be2bc 100644 --- a/code/game/mecha/equipment/tools/mining_tools.dm +++ b/code/game/mecha/equipment/tools/mining_tools.dm @@ -17,6 +17,7 @@ toolspeed = 0.9 var/drill_delay = 7 var/drill_level = DRILL_BASIC + mech_flags = EXOSUIT_MODULE_WORKING | EXOSUIT_MODULE_COMBAT /obj/item/mecha_parts/mecha_equipment/drill/Initialize() . = ..() @@ -153,6 +154,7 @@ selectable = 0 equip_cooldown = 15 var/scanning_time = 0 + mech_flags = EXOSUIT_MODULE_WORKING /obj/item/mecha_parts/mecha_equipment/mining_scanner/Initialize() . = ..() diff --git a/code/game/mecha/equipment/tools/work_tools.dm b/code/game/mecha/equipment/tools/work_tools.dm index 759fcd996d..1c4586205a 100644 --- a/code/game/mecha/equipment/tools/work_tools.dm +++ b/code/game/mecha/equipment/tools/work_tools.dm @@ -8,11 +8,12 @@ icon_state = "mecha_clamp" equip_cooldown = 15 energy_drain = 10 + tool_behaviour = TOOL_RETRACTOR + toolspeed = 0.8 var/dam_force = 20 var/obj/mecha/working/ripley/cargo_holder harmful = TRUE - tool_behaviour = TOOL_RETRACTOR - toolspeed = 0.8 + mech_flags = EXOSUIT_MODULE_RIPLEY /obj/item/mecha_parts/mecha_equipment/hydraulic_clamp/can_attach(obj/mecha/working/ripley/M as obj) if(..()) @@ -180,6 +181,7 @@ equip_cooldown = 5 energy_drain = 0 range = MELEE|RANGED + mech_flags = EXOSUIT_MODULE_WORKING /obj/item/mecha_parts/mecha_equipment/extinguisher/Initialize() . = ..() diff --git a/code/game/mecha/equipment/weapons/weapons.dm b/code/game/mecha/equipment/weapons/weapons.dm index 65aa001fe1..f2bced4aa8 100644 --- a/code/game/mecha/equipment/weapons/weapons.dm +++ b/code/game/mecha/equipment/weapons/weapons.dm @@ -9,6 +9,7 @@ var/projectile_delay = 0 var/firing_effect_type = /obj/effect/temp_visual/dir_setting/firing_effect //the visual effect appearing when the weapon is fired. var/kickback = TRUE //Will using this weapon in no grav push mecha back. + mech_flags = EXOSUIT_MODULE_COMBAT /obj/item/mecha_parts/mecha_equipment/weapon/can_attach(obj/mecha/combat/M) if(..()) diff --git a/code/game/mecha/mech_bay.dm b/code/game/mecha/mech_bay.dm index dcd8a12b38..e9f682e929 100644 --- a/code/game/mecha/mech_bay.dm +++ b/code/game/mecha/mech_bay.dm @@ -81,10 +81,10 @@ var/obj/machinery/mech_bay_recharge_port/recharge_port light_color = LIGHT_COLOR_PINK -/obj/machinery/computer/mech_bay_power_console/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) +/obj/machinery/computer/mech_bay_power_console/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) if(!ui) - ui = new(user, src, ui_key, "MechBayPowerConsole", "Mech Bay Power Control Console", 400, 200, master_ui, state) + ui = new(user, src, "MechBayPowerConsole", name) ui.open() /obj/machinery/computer/mech_bay_power_console/ui_act(action, params) @@ -104,7 +104,6 @@ data["recharge_port"]["mech"] = list("health" = recharge_port.recharging_mech.obj_integrity, "maxhealth" = recharge_port.recharging_mech.max_integrity, "cell" = null, "name" = recharge_port.recharging_mech.name,) if(recharge_port.recharging_mech.cell && !QDELETED(recharge_port.recharging_mech.cell)) data["recharge_port"]["mech"]["cell"] = list( - "critfail" = recharge_port.recharging_mech.cell.crit_fail, "charge" = recharge_port.recharging_mech.cell.charge, "maxcharge" = recharge_port.recharging_mech.cell.maxcharge ) diff --git a/code/game/mecha/mech_fabricator.dm b/code/game/mecha/mech_fabricator.dm index ca481f0d80..002753c5d4 100644 --- a/code/game/mecha/mech_fabricator.dm +++ b/code/game/mecha/mech_fabricator.dm @@ -9,17 +9,41 @@ active_power_usage = 5000 req_access = list(ACCESS_ROBOTICS) circuit = /obj/item/circuitboard/machine/mechfab - var/time_coeff = 1 - var/component_coeff = 1 - var/datum/techweb/specialized/autounlocking/exofab/stored_research - var/sync = 0 - var/part_set - var/datum/design/being_built + // processing_flags = START_PROCESSING_MANUALLY + + // subsystem_type = /datum/controller/subsystem/processing/fastprocess + + /// Current items in the build queue. var/list/queue = list() - var/processing_queue = 0 - var/screen = "main" - var/temp - var/offstation_security_levels = TRUE + /// Whether or not the machine is building the entire queue automagically. + var/process_queue = FALSE + + /// The current design datum that the machine is building. + var/datum/design/being_built + /// World time when the build will finish. + var/build_finish = 0 + /// World time when the build started. + var/build_start = 0 + /// Reference to all materials used in the creation of the item being_built. + var/list/build_materials + /// Part currently stored in the Exofab. + var/obj/item/stored_part + + /// Coefficient for the speed of item building. Based on the installed parts. + var/time_coeff = 1 + /// Coefficient for the efficiency of material usage in item building. Based on the installed parts. + var/component_coeff = 1 + + /// Copy of the currently synced techweb. + var/datum/techweb/specialized/autounlocking/exofab/stored_research + + /// Whether the Exofab links to the ore silo on init. Special derelict or maintanance variants should set this to FALSE. + var/link_on_init = TRUE + + /// Reference to a remote material inventory, such as an ore silo. + var/datum/component/remote_materials/rmat + + /// A list of categories that valid MECHFAB design datums will broadly categorise themselves under. var/list/part_sets = list( "Cyborg", "Ripley", @@ -33,25 +57,17 @@ "Exosuit Equipment", "Exosuit Ammunition", "Cyborg Upgrade Modules", + "Cybernetics", + "Implants", + "Control Interfaces", "Misc" ) -/obj/machinery/mecha_part_fabricator/Initialize() - var/static/list/allowed_types = list( - /datum/material/iron, - /datum/material/glass, - /datum/material/silver, - /datum/material/gold, - /datum/material/diamond, - /datum/material/plasma, - /datum/material/uranium, - /datum/material/bananium, - /datum/material/titanium, - /datum/material/bluespace - ) - var/datum/component/material_container/materials = AddComponent(/datum/component/material_container, allowed_types, 0, TRUE, /obj/item/stack, CALLBACK(src, .proc/is_insertion_ready), CALLBACK(src, .proc/AfterMaterialInsert)) - materials.precise_insertion = TRUE +/obj/machinery/mecha_part_fabricator/Initialize(mapload) stored_research = new + rmat = AddComponent(/datum/component/remote_materials, "mechfab", mapload && link_on_init) + + RefreshParts() //Recalculating local material sizes if the fab isn't linked return ..() /obj/machinery/mecha_part_fabricator/RefreshParts() @@ -60,8 +76,7 @@ //maximum stocking amount (default 300000, 600000 at T4) for(var/obj/item/stock_parts/matter_bin/M in component_parts) T += M.rating - var/datum/component/material_container/materials = GetComponent(/datum/component/material_container) - materials.max_amount = (200000 + (T*50000)) + rmat.set_local_size((200000 + (T*50000))) //resources adjustment coefficient (1 -> 0.85 -> 0.7 -> 0.55) T = 1.15 @@ -74,89 +89,157 @@ for(var/obj/item/stock_parts/manipulator/Ml in component_parts) T += Ml.rating time_coeff = round(initial(time_coeff) - (initial(time_coeff)*(T))/5,0.01) - var/obj/item/circuitboard/machine/mechfab/C = circuit - offstation_security_levels = C.offstation_security_levels + + // Adjust the build time of any item currently being built. + if(being_built) + var/last_const_time = build_finish - build_start + var/new_const_time = get_construction_time_w_coeff(initial(being_built.construction_time)) + var/const_time_left = build_finish - world.time + var/new_build_time = (new_const_time / last_const_time) * const_time_left + build_finish = world.time + new_build_time + + update_static_data(usr) /obj/machinery/mecha_part_fabricator/examine(mob/user) . = ..() - var/datum/component/material_container/materials = GetComponent(/datum/component/material_container) if(in_range(user, src) || isobserver(user)) - . += "The status display reads: Storing up to [materials.max_amount] material units.
Material consumption at [component_coeff*100]%.
Build time reduced by [100-time_coeff*100]%.
" + . += "The status display reads: Storing up to [rmat.local_size] material units.
Material consumption at [component_coeff*100]%.
Build time reduced by [100-time_coeff*100]%.
" -/obj/machinery/mecha_part_fabricator/emag_act() - . = ..() - if(obj_flags & EMAGGED) - return - obj_flags |= EMAGGED - req_access = list() - INVOKE_ASYNC(src, .proc/error_action_sucessful) - return TRUE - -/obj/machinery/mecha_part_fabricator/proc/error_action_sucessful() - say("DB error \[Code 0x00F1\]") - sleep(10) - say("Attempting auto-repair...") - sleep(15) - say("User DB corrupted \[Code 0x00FA\]. Truncating data structure...") - sleep(30) - say("User DB truncated. Please contact your Nanotrasen system operator for future assistance.") - - -/obj/machinery/mecha_part_fabricator/proc/output_parts_list(set_name) - var/output = "" - for(var/v in stored_research.researched_designs) - var/datum/design/D = SSresearch.techweb_design_by_id(v) - if(D.build_type & MECHFAB) - if(!(set_name in D.category)) - continue - output += "
[output_part_info(D)]
\[" - if(check_clearance(D) && check_resources(D)) - output += "Build | " - output += "Add to queue\]\[?\]
" - return output - -/obj/machinery/mecha_part_fabricator/proc/check_clearance(datum/design/D) - if(!(obj_flags & EMAGGED) && (offstation_security_levels || is_station_level(z)) && !ISINRANGE(GLOB.security_level, D.min_security_level, D.max_security_level)) - return FALSE - return TRUE - -/obj/machinery/mecha_part_fabricator/proc/output_part_info(datum/design/D) - var/clearance = !(obj_flags & EMAGGED) && (offstation_security_levels || is_station_level(z)) - var/sec_text = "" - if(clearance && (D.min_security_level > SEC_LEVEL_GREEN || D.max_security_level < SEC_LEVEL_DELTA)) - sec_text = " (Allowed security levels: " - for(var/n in D.min_security_level to D.max_security_level) - sec_text += NUM2SECLEVEL(n) - if(n + 1 <= D.max_security_level) - sec_text += ", " - sec_text += ") " - var/output = "[initial(D.name)] (Cost: [output_part_cost(D)]) [sec_text][get_construction_time_w_coeff(D)/10]sec" - return output - -/obj/machinery/mecha_part_fabricator/proc/output_part_cost(datum/design/D) - var/i = 0 - var/output +/** + * Generates an info list for a given part. + * + * Returns a list of part information. + * * D - Design datum to get information on. + * * categories - Boolean, whether or not to parse snowflake categories into the part information list. + */ +/obj/machinery/mecha_part_fabricator/proc/output_part_info(datum/design/D, categories = FALSE) + var/cost = list() for(var/c in D.materials) var/datum/material/M = c - output += "[i?" | ":null][get_resource_cost_w_coeff(D, M)] [M.name]" - i++ - return output + cost[M.name] = get_resource_cost_w_coeff(D, M) + var/obj/built_item = D.build_path + + var/list/category_override = null + var/list/sub_category = null + + if(categories) + // Handle some special cases to build up sub-categories for the fab interface. + // Start with checking if this design builds a cyborg module. + if(built_item in typesof(/obj/item/borg/upgrade)) + var/obj/item/borg/upgrade/U = built_item + var/module_types = initial(U.module_flags) + sub_category = list() + if(module_types) + if(module_types & BORG_MODULE_SECURITY) + sub_category += "Security" + if(module_types & BORG_MODULE_MINER) + sub_category += "Mining" + if(module_types & BORG_MODULE_JANITOR) + sub_category += "Janitor" + if(module_types & BORG_MODULE_MEDICAL) + sub_category += "Medical" + if(module_types & BORG_MODULE_ENGINEERING) + sub_category += "Engineering" + else + sub_category += "All Cyborgs" + // Else check if this design builds a piece of exosuit equipment. + else if(built_item in typesof(/obj/item/mecha_parts/mecha_equipment)) + var/obj/item/mecha_parts/mecha_equipment/E = built_item + var/mech_types = initial(E.mech_flags) + sub_category = "Equipment" + if(mech_types) + category_override = list() + if(mech_types & EXOSUIT_MODULE_RIPLEY) + category_override += "Ripley" + if(mech_types & EXOSUIT_MODULE_FIREFIGHTER) + category_override += "Firefighter" + if(mech_types & EXOSUIT_MODULE_ODYSSEUS) + category_override += "Odysseus" + // if(mech_types & EXOSUIT_MODULE_CLARKE) + // category_override += "Clarke" + if(mech_types & EXOSUIT_MODULE_GYGAX_MED) + category_override += "Medical-Spec Gygax" + if(mech_types & EXOSUIT_MODULE_GYGAX) + category_override += "Gygax" + if(mech_types & EXOSUIT_MODULE_DURAND) + category_override += "Durand" + if(mech_types & EXOSUIT_MODULE_HONK) + category_override += "H.O.N.K" + if(mech_types & EXOSUIT_MODULE_PHAZON) + category_override += "Phazon" + + + var/list/part = list( + "name" = D.name, + "desc" = initial(built_item.desc), + "printTime" = get_construction_time_w_coeff(initial(D.construction_time))/10, + "cost" = cost, + "id" = D.id, + "subCategory" = sub_category, + "categoryOverride" = category_override, + "searchMeta" = "UNKNOWN"//D.search_metadata + ) + + return part + +/** + * Generates a list of resources / materials available to this Exosuit Fab + * + * Returns null if there is no material container available. + * List format is list(material_name = list(amount = ..., ref = ..., etc.)) + */ /obj/machinery/mecha_part_fabricator/proc/output_available_resources() - var/output - var/datum/component/material_container/materials = GetComponent(/datum/component/material_container) - for(var/mat_id in materials.materials) - var/datum/material/M = mat_id - var/amount = materials.materials[mat_id] - output += "[M.name]: [amount] cm³" - if(amount >= MINERAL_MATERIAL_AMOUNT) - output += "- Remove \[1\]" - if(amount >= (MINERAL_MATERIAL_AMOUNT * 10)) - output += " | \[10\]" - output += " | \[All\]" - output += "
" - return output + var/datum/component/material_container/materials = rmat.mat_container + var/list/material_data = list() + + if(materials) + for(var/mat_id in materials.materials) + var/datum/material/M = mat_id + var/list/material_info = list() + var/amount = materials.materials[mat_id] + + material_info = list( + "name" = M.name, + "ref" = REF(M), + "amount" = amount, + "sheets" = round(amount / MINERAL_MATERIAL_AMOUNT), + "removable" = amount >= MINERAL_MATERIAL_AMOUNT + ) + + material_data += list(material_info) + + return material_data + + return null + +/** + * Intended to be called when an item starts printing. + * + * Adds the overlay to show the fab working and sets active power usage settings. + */ +/obj/machinery/mecha_part_fabricator/proc/on_start_printing() + add_overlay("fab-active") + use_power = ACTIVE_POWER_USE + +/** + * Intended to be called when the exofab has stopped working and is no longer printing items. + * + * Removes the overlay to show the fab working and sets idle power usage settings. Additionally resets the description and turns off queue processing. + */ +/obj/machinery/mecha_part_fabricator/proc/on_finish_printing() + cut_overlay("fab-active") + use_power = IDLE_POWER_USE + desc = initial(desc) + process_queue = FALSE + +/** + * Calculates resource/material costs for printing an item based on the machine's resource coefficient. + * + * Returns a list of k,v resources with their amounts. + * * D - Design datum to calculate the modified resource cost of. + */ /obj/machinery/mecha_part_fabricator/proc/get_resources_w_coeff(datum/design/D) var/list/resources = list() for(var/R in D.materials) @@ -164,294 +247,419 @@ resources[M] = get_resource_cost_w_coeff(D, M) return resources +/** + * Checks if the Exofab has enough resources to print a given item. + * + * Returns FALSE if the design has no reagents used in its construction (?) or if there are insufficient resources. + * Returns TRUE if there are sufficient resources to print the item. + * * D - Design datum to calculate the modified resource cost of. + */ /obj/machinery/mecha_part_fabricator/proc/check_resources(datum/design/D) - if(D.reagents_list.len) // No reagents storage - no reagent designs. + if(length(D.reagents_list)) // No reagents storage - no reagent designs. return FALSE - var/datum/component/material_container/materials = GetComponent(/datum/component/material_container) + var/datum/component/material_container/materials = rmat.mat_container if(materials.has_materials(get_resources_w_coeff(D))) return TRUE return FALSE -/obj/machinery/mecha_part_fabricator/proc/build_part(datum/design/D) +/** + * Attempts to build the next item in the build queue. + * + * Returns FALSE if either there are no more parts to build or the next part is not buildable. + * Returns TRUE if the next part has started building. + * * verbose - Whether the machine should use say() procs. Set to FALSE to disable the machine saying reasons for failure to build. + */ +/obj/machinery/mecha_part_fabricator/proc/build_next_in_queue(verbose = TRUE) + if(!length(queue)) + return FALSE + + var/datum/design/D = queue[1] + if(build_part(D, verbose)) + remove_from_queue(1) + return TRUE + + return FALSE + +/** + * Starts the build process for a given design datum. + * + * Returns FALSE if the procedure fails. Returns TRUE when being_built is set. + * Uses materials. + * * D - Design datum to attempt to print. + * * verbose - Whether the machine should use say() procs. Set to FALSE to disable the machine saying reasons for failure to build. + */ +/obj/machinery/mecha_part_fabricator/proc/build_part(datum/design/D, verbose = TRUE) + if(!D) + return FALSE + + var/datum/component/material_container/materials = rmat.mat_container + if (!materials) + if(verbose) + say("No access to material storage, please contact the quartermaster.") + return FALSE + if (rmat.on_hold()) + if(verbose) + say("Mineral access is on hold, please contact the quartermaster.") + return FALSE + if(!check_resources(D)) + if(verbose) + say("Not enough resources. Processing stopped.") + return FALSE + + build_materials = get_resources_w_coeff(D) + + materials.use_materials(build_materials) being_built = D - desc = "It's building \a [initial(D.name)]." - var/list/res_coef = get_resources_w_coeff(D) + build_finish = world.time + get_construction_time_w_coeff(initial(D.construction_time)) + build_start = world.time + desc = "It's building \a [D.name]." - var/datum/component/material_container/materials = GetComponent(/datum/component/material_container) - materials.use_materials(res_coef) - add_overlay("fab-active") - use_power = ACTIVE_POWER_USE - updateUsrDialog() - sleep(get_construction_time_w_coeff(D)) - use_power = IDLE_POWER_USE - cut_overlay("fab-active") - desc = initial(desc) + rmat.silo_log(src, "built", -1, "[D.name]", build_materials) - var/location = get_step(src,(dir)) - var/obj/item/I = new D.build_path(location) - I.set_custom_materials(res_coef) - say("\The [I] is complete.") - being_built = null - - updateUsrDialog() return TRUE -/obj/machinery/mecha_part_fabricator/proc/update_queue_on_page() - send_byjax(usr,"mecha_fabricator.browser","queue",list_queue()) - return +/obj/machinery/mecha_part_fabricator/process() + // If there's a stored part to dispense due to an obstruction, try to dispense it. + if(stored_part) + var/turf/exit = get_step(src,(dir)) + if(exit.density) + return TRUE -/obj/machinery/mecha_part_fabricator/proc/add_part_set_to_queue(set_name) - if(set_name in part_sets) - for(var/v in stored_research.researched_designs) - var/datum/design/D = SSresearch.techweb_design_by_id(v) - if(D.build_type & MECHFAB) - if(set_name in D.category) - add_to_queue(D) + say("Obstruction cleared. \The [stored_part] is complete.") + stored_part.forceMove(exit) + stored_part = null -/obj/machinery/mecha_part_fabricator/proc/add_to_queue(D) + // If there's nothing being built, try to build something + if(!being_built) + // If we're not processing the queue anymore or there's nothing to build, end processing. + if(!process_queue || !build_next_in_queue()) + on_finish_printing() + STOP_PROCESSING(SSfastprocess, src) + //end_processing() + return TRUE + on_start_printing() + + // If there's an item being built, check if it is complete. + if(being_built && (build_finish < world.time)) + // Then attempt to dispense it and if appropriate build the next item. + dispense_built_part(being_built) + if(process_queue) + build_next_in_queue(FALSE) + return TRUE + +/** + * Dispenses a part to the tile infront of the Exosuit Fab. + * + * Returns FALSE is the machine cannot dispense the part on the appropriate turf. + * Return TRUE if the part was successfully dispensed. + * * D - Design datum to attempt to dispense. + */ +/obj/machinery/mecha_part_fabricator/proc/dispense_built_part(datum/design/D) + var/obj/item/I = new D.build_path(src) + // I.material_flags |= MATERIAL_NO_EFFECTS //Find a better way to do this. + I.set_custom_materials(build_materials) + + being_built = null + + var/turf/exit = get_step(src,(dir)) + if(exit.density) + say("Error! Part outlet is obstructed.") + desc = "It's trying to dispense \a [D.name], but the part outlet is obstructed." + stored_part = I + return FALSE + + say("\The [I] is complete.") + I.forceMove(exit) + return TRUE + +/** + * Adds a list of datum designs to the build queue. + * + * Will only add designs that are in this machine's stored techweb. + * Does final checks for datum IDs and makes sure this machine can build the designs. + * * part_list - List of datum design ids for designs to add to the queue. + */ +/obj/machinery/mecha_part_fabricator/proc/add_part_set_to_queue(list/part_list) + for(var/v in stored_research.researched_designs) + var/datum/design/D = SSresearch.techweb_design_by_id(v) + if((D.build_type & MECHFAB) && (D.id in part_list)) + add_to_queue(D) + +/** + * Adds a datum design to the build queue. + * + * Returns TRUE if successful and FALSE if the design was not added to the queue. + * * D - Datum design to add to the queue. + */ +/obj/machinery/mecha_part_fabricator/proc/add_to_queue(datum/design/D) if(!istype(queue)) queue = list() if(D) queue[++queue.len] = D - return queue.len + return TRUE + return FALSE +/** + * Removes datum design from the build queue based on index. + * + * Returns TRUE if successful and FALSE if a design was not removed from the queue. + * * index - Index in the build queue of the element to remove. + */ /obj/machinery/mecha_part_fabricator/proc/remove_from_queue(index) - if(!isnum(index) || !ISINTEGER(index) || !istype(queue) || (index<1 || index>queue.len)) + if(!isnum(index) || !ISINTEGER(index) || !istype(queue) || (index<1 || index>length(queue))) return FALSE queue.Cut(index,++index) return TRUE -/obj/machinery/mecha_part_fabricator/proc/process_queue() - var/datum/design/D = queue[1] - if(!D) - remove_from_queue(1) - if(queue.len) - return process_queue() - else - return - temp = null - while(D) - if(stat&(NOPOWER|BROKEN)) - return FALSE - if(!check_clearance(D)) - say("Security level not met. Queue processing stopped.") - temp = {"Security level not met to build next part.
- Try again | Return"} - return FALSE - if(!check_resources(D)) - say("Not enough resources. Queue processing stopped.") - temp = {"Not enough resources to build next part.
-
Try again | Return"} - return FALSE - remove_from_queue(1) - build_part(D) - D = listgetindex(queue, 1) - say("Queue processing finished successfully.") - +/** + * Generates a list of parts formatted for tgui based on the current build queue. + * + * Returns a formatted list of lists containing formatted part information for every part in the build queue. + */ /obj/machinery/mecha_part_fabricator/proc/list_queue() - var/output = "Queue contains:" - if(!istype(queue) || !queue.len) - output += "
Nothing" - else - output += "
    " - var/i = 0 - for(var/datum/design/D in queue) - i++ - var/obj/part = D.build_path - output += "" - output += initial(part.name) + " - " - output += "[i>1?"":null] " - output += "[i↓":null] " - output += "Remove" + if(!istype(queue) || !length(queue)) + return null - output += "
" - output += "\[Process queue | Clear queue\]" - return output + var/list/queued_parts = list() + for(var/datum/design/D in queue) + var/list/part = output_part_info(D) + queued_parts += list(part) + return queued_parts +/** + * Syncs machine with R&D servers. + * + * Requires an R&D Console visible within 7 tiles. Copies techweb research. Updates tgui's state data. + */ /obj/machinery/mecha_part_fabricator/proc/sync() - temp = "Updating local R&D database..." - updateUsrDialog() - sleep(30) //only sleep if called by user - - for(var/obj/machinery/computer/rdconsole/RDC in oview(7,src)) + for(var/obj/machinery/computer/rdconsole/RDC in orange(7,src)) RDC.stored_research.copy_research_to(stored_research) - temp = "Processed equipment designs.
" - //check if the tech coefficients have changed - temp += "Return" - - updateUsrDialog() + update_static_data(usr) say("Successfully synchronized with R&D server.") return - temp = "Unable to connect to local R&D Database.
Please check your connections and try again.
Return" - updateUsrDialog() + say("Unable to connect to local R&D server.") return +/** + * Calculates the coefficient-modified resource cost of a single material component of a design's recipe. + * + * Returns coefficient-modified resource cost for the given material component. + * * D - Design datum to pull the resource cost from. + * * resource - Material datum reference to the resource to calculate the cost of. + * * roundto - Rounding value for round() proc + */ /obj/machinery/mecha_part_fabricator/proc/get_resource_cost_w_coeff(datum/design/D, var/datum/material/resource, roundto = 1) return round(D.materials[resource]*component_coeff, roundto) -/obj/machinery/mecha_part_fabricator/proc/get_construction_time_w_coeff(datum/design/D, roundto = 1) //aran - return round(initial(D.construction_time)*time_coeff, roundto) +/** + * Calculates the coefficient-modified build time of a design. + * + * Returns coefficient-modified build time of a given design. + * * D - Design datum to calculate the modified build time of. + * * roundto - Rounding value for round() proc + */ +/obj/machinery/mecha_part_fabricator/proc/get_construction_time_w_coeff(construction_time, roundto = 1) //aran + return round(construction_time*time_coeff, roundto) -/obj/machinery/mecha_part_fabricator/ui_interact(mob/user as mob) - . = ..() - var/dat, left_part - user.set_machine(src) - var/turf/exit = get_step(src,(dir)) - if(exit.density) - say("Error! Part outlet is obstructed.") - return - if(temp) - left_part = temp - else if(being_built) - var/obj/I = being_built.build_path - left_part = {"Building [initial(I.name)].
- Please wait until completion...
"} +/obj/machinery/mecha_part_fabricator/ui_assets(mob/user) + return list( + get_asset_datum(/datum/asset/spritesheet/sheetmaterials) + ) + +/obj/machinery/mecha_part_fabricator/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "ExosuitFabricator") + ui.open() + +/obj/machinery/mecha_part_fabricator/ui_static_data(mob/user) + var/list/data = list() + + var/list/final_sets = list() + var/list/buildable_parts = list() + + for(var/part_set in part_sets) + final_sets += part_set + + for(var/v in stored_research.researched_designs) + var/datum/design/D = SSresearch.techweb_design_by_id(v) + if(D.build_type & MECHFAB) + // This is for us. + var/list/part = output_part_info(D, TRUE) + + if(part["category_override"]) + for(var/cat in part["category_override"]) + buildable_parts[cat] += list(part) + if(!(cat in part_sets)) + final_sets += cat + continue + + for(var/cat in part_sets) + // Find all matching categories. + if(!(cat in D.category)) + continue + + buildable_parts[cat] += list(part) + + data["partSets"] = final_sets + data["buildableParts"] = buildable_parts + + return data + +/obj/machinery/mecha_part_fabricator/ui_data(mob/user) + var/list/data = list() + + data["materials"] = output_available_resources() + + if(being_built) + var/list/part = list( + "name" = being_built.name, + "duration" = build_finish - world.time, + "printTime" = get_construction_time_w_coeff(initial(being_built.construction_time)) + ) + data["buildingPart"] = part else - switch(screen) - if("main") - left_part = output_available_resources()+"
" - left_part += "Sync with R&D servers
" - for(var/part_set in part_sets) - left_part += "[part_set] - \[Add all parts to queue\]
" - if("parts") - left_part += output_parts_list(part_set) - left_part += "
Return" - dat = {" - - - [name] data - - - - - - - - - -
- [left_part] - - [list_queue()] -
- - "} - user << browse(dat, "window=mecha_fabricator;size=1000x430") - onclose(user, "mecha_fabricator") - return + data["buildingPart"] = null -/obj/machinery/mecha_part_fabricator/Topic(href, href_list) + data["queue"] = list_queue() + + if(stored_part) + data["storedPart"] = stored_part.name + else + data["storedPart"] = null + + data["isProcessingQueue"] = process_queue + + return data + +/obj/machinery/mecha_part_fabricator/ui_act(action, var/list/params) if(..()) - return - if(href_list["part_set"]) - var/tpart_set = href_list["part_set"] - if(tpart_set) - if(tpart_set=="clear") - part_set = null - else - part_set = tpart_set - screen = "parts" - if(href_list["part"]) - var/T = href_list["part"] - for(var/v in stored_research.researched_designs) - var/datum/design/D = SSresearch.techweb_design_by_id(v) - if(D.build_type & MECHFAB) - if(D.id == T) - if(!processing_queue) - build_part(D) - else - add_to_queue(D) - break - if(href_list["add_to_queue"]) - var/T = href_list["add_to_queue"] - for(var/v in stored_research.researched_designs) - var/datum/design/D = SSresearch.techweb_design_by_id(v) - if(D.build_type & MECHFAB) - if(D.id == T) + return TRUE + + . = TRUE + + add_fingerprint(usr) + usr.set_machine(src) + + switch(action) + if("sync_rnd") + // Sync with R&D Servers + sync() + return + if("add_queue_set") + // Add all parts of a set to queue + var/part_list = params["part_list"] + add_part_set_to_queue(part_list) + return + if("add_queue_part") + // Add a specific part to queue + var/T = params["id"] + for(var/v in stored_research.researched_designs) + var/datum/design/D = SSresearch.techweb_design_by_id(v) + if((D.build_type & MECHFAB) && (D.id == T)) add_to_queue(D) break - return update_queue_on_page() - if(href_list["remove_from_queue"]) - remove_from_queue(text2num(href_list["remove_from_queue"])) - return update_queue_on_page() - if(href_list["partset_to_queue"]) - add_part_set_to_queue(href_list["partset_to_queue"]) - return update_queue_on_page() - if(href_list["process_queue"]) - spawn(0) - if(processing_queue || being_built) - return FALSE - processing_queue = 1 - process_queue() - processing_queue = 0 - if(href_list["clear_temp"]) - temp = null - if(href_list["screen"]) - screen = href_list["screen"] - if(href_list["queue_move"] && href_list["index"]) - var/index = text2num(href_list["index"]) - var/new_index = index + text2num(href_list["queue_move"]) - if(isnum(index) && isnum(new_index) && ISINTEGER(index) && ISINTEGER(new_index)) - if(ISINRANGE(new_index,1,queue.len)) - queue.Swap(index,new_index) - return update_queue_on_page() - if(href_list["clear_queue"]) - queue = list() - return update_queue_on_page() - if(href_list["sync"]) - sync() - if(href_list["part_desc"]) - var/T = href_list["part_desc"] - for(var/v in stored_research.researched_designs) - var/datum/design/D = SSresearch.techweb_design_by_id(v) - if(D.build_type & MECHFAB) - if(D.id == T) - var/obj/part = D.build_path - temp = {"

[initial(part.name)] description:

- [initial(part.desc)]
- Return - "} - break + return + if("del_queue_part") + // Delete a specific from from the queue + var/index = text2num(params["index"]) + remove_from_queue(index) + return + if("clear_queue") + // Delete everything from queue + queue.Cut() + return + if("build_queue") + // Build everything in queue + if(process_queue) + return + process_queue = TRUE - if(href_list["remove_mat"] && href_list["material"]) - var/datum/component/material_container/materials = GetComponent(/datum/component/material_container) - var/datum/material/Mat = locate(href_list["material"]) - materials.retrieve_sheets(text2num(href_list["remove_mat"]), Mat) + if(!being_built) + START_PROCESSING(SSfastprocess, src) + //begin_processing() + return + if("stop_queue") + // Pause queue building. Also known as stop. + process_queue = FALSE + return + if("build_part") + // Build a single part + if(being_built || process_queue) + return - updateUsrDialog() - return + var/id = params["id"] + var/datum/design/D = SSresearch.techweb_design_by_id(id) -/obj/machinery/mecha_part_fabricator/on_deconstruction() - var/datum/component/material_container/materials = GetComponent(/datum/component/material_container) - materials.retrieve_all() - ..() + if(!(D.build_type & MECHFAB) || !(D.id == id)) + return + + if(build_part(D)) + on_start_printing() + START_PROCESSING(SSfastprocess, src) + //begin_processing() teege has this as a helper proc. please port it! + + return + if("move_queue_part") + // Moves a part up or down in the queue. + var/index = text2num(params["index"]) + var/new_index = index + text2num(params["newindex"]) + if(isnum(index) && isnum(new_index) && ISINTEGER(index) && ISINTEGER(new_index)) + if(ISINRANGE(new_index,1,length(queue))) + queue.Swap(index,new_index) + return + if("remove_mat") + // Remove a material from the fab + var/mat_ref = params["ref"] + var/amount = text2num(params["amount"]) + var/datum/material/mat = locate(mat_ref) + eject_sheets(mat, amount) + return + + return FALSE + +/** + * Eject material sheets. + * + * Returns the number of sheets successfully ejected. + * eject_sheet - Byond REF of the material to eject. + * eject_amt - Number of sheets to attempt to eject. + */ +/obj/machinery/mecha_part_fabricator/proc/eject_sheets(eject_sheet, eject_amt) + var/datum/component/material_container/mat_container = rmat.mat_container + if (!mat_container) + say("No access to material storage, please contact the quartermaster.") + return 0 + if (rmat.on_hold()) + say("Mineral access is on hold, please contact the quartermaster.") + return 0 + var/count = mat_container.retrieve_sheets(text2num(eject_amt), eject_sheet, drop_location()) + var/list/matlist = list() + matlist[eject_sheet] = text2num(eject_amt) + rmat.silo_log(src, "ejected", -count, "sheets", matlist) + return count /obj/machinery/mecha_part_fabricator/proc/AfterMaterialInsert(item_inserted, id_inserted, amount_inserted) var/datum/material/M = id_inserted add_overlay("fab-load-[M.name]") addtimer(CALLBACK(src, /atom/proc/cut_overlay, "fab-load-[M.name]"), 10) - updateUsrDialog() -/obj/machinery/mecha_part_fabricator/attackby(obj/item/W, mob/user, params) - if(default_deconstruction_screwdriver(user, "fab-o", "fab-idle", W)) +/obj/machinery/mecha_part_fabricator/screwdriver_act(mob/living/user, obj/item/I) + if(..()) return TRUE + if(being_built) + to_chat(user, "\The [src] is currently processing! Please wait until completion.") + return FALSE + return default_deconstruction_screwdriver(user, "fab-o", "fab-idle", I) - if(default_deconstruction_crowbar(W)) +/obj/machinery/mecha_part_fabricator/crowbar_act(mob/living/user, obj/item/I) + if(..()) return TRUE - - return ..() + if(being_built) + to_chat(user, "\The [src] is currently processing! Please wait until completion.") + return FALSE + return default_deconstruction_crowbar(I) /obj/machinery/mecha_part_fabricator/proc/is_insertion_ready(mob/user) if(panel_open) @@ -463,6 +671,9 @@ return TRUE +/obj/machinery/mecha_part_fabricator/maint + link_on_init = FALSE + /obj/machinery/mecha_part_fabricator/offstation - offstation_security_levels = FALSE + link_on_init = FALSE circuit = /obj/item/circuitboard/machine/mechfab/offstation diff --git a/code/game/mecha/mecha.dm b/code/game/mecha/mecha.dm index 5b691607db..f16a5f9292 100644 --- a/code/game/mecha/mecha.dm +++ b/code/game/mecha/mecha.dm @@ -153,6 +153,9 @@ /obj/mecha/get_cell() return cell +/obj/mecha/rust_heretic_act() + take_damage(500, BRUTE) + /obj/mecha/Destroy() go_out() var/mob/living/silicon/ai/AI diff --git a/code/game/mecha/mecha_control_console.dm b/code/game/mecha/mecha_control_console.dm index c7db051331..50d18c6fda 100644 --- a/code/game/mecha/mecha_control_console.dm +++ b/code/game/mecha/mecha_control_console.dm @@ -5,14 +5,11 @@ icon_keyboard = "tech_key" req_access = list(ACCESS_ROBOTICS) circuit = /obj/item/circuitboard/computer/mecha_control - ui_x = 500 - ui_y = 500 -/obj/machinery/computer/mecha/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ - datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) +/obj/machinery/computer/mecha/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) if(!ui) - ui = new(user, src, ui_key, "ExosuitControlConsole", name, ui_x, ui_y, master_ui, state) + ui = new(user, src, "ExosuitControlConsole", name) ui.open() /obj/machinery/computer/mecha/ui_data(mob/user) diff --git a/code/game/objects/effects/anomalies.dm b/code/game/objects/effects/anomalies.dm index e75a18dca8..41270bb09e 100644 --- a/code/game/objects/effects/anomalies.dm +++ b/code/game/objects/effects/anomalies.dm @@ -8,7 +8,7 @@ anchored = TRUE light_range = 3 var/movechance = 70 - var/obj/item/assembly/signaler/anomaly/aSignal + var/obj/item/assembly/signaler/anomaly/aSignal = /obj/item/assembly/signaler/anomaly var/area/impact_area var/lifespan = 990 @@ -23,8 +23,10 @@ START_PROCESSING(SSobj, src) impact_area = get_area(src) - aSignal = new(src) - aSignal.name = "[name] core" + if (!impact_area) + return INITIALIZE_HINT_QDEL + + aSignal = new aSignal(src) aSignal.code = rand(1,100) aSignal.anomaly_type = type @@ -75,7 +77,7 @@ /obj/effect/anomaly/attackby(obj/item/I, mob/user, params) - if(istype(I, /obj/item/analyzer)) + if(I.tool_behaviour == TOOL_ANALYZER) //revert if runtimed to_chat(user, "Analyzing... [src]'s unstable field is fluctuating along frequency [format_frequency(aSignal.frequency)], code [aSignal.code].") /////////////////////// @@ -85,6 +87,7 @@ icon_state = "shield2" density = FALSE var/boing = 0 + aSignal = /obj/item/assembly/signaler/anomaly/grav /obj/effect/anomaly/grav/anomalyEffect() ..() @@ -95,17 +98,23 @@ for(var/mob/living/M in range(0, src)) gravShock(M) for(var/mob/living/M in orange(4, src)) - step_towards(M,src) + if(!M.mob_negates_gravity()) //delete when runtimed + step_towards(M,src) for(var/obj/O in range(0,src)) if(!O.anchored) + //if(isturf(O.loc)) + // var/turf/T = O.loc + // if(T.intact && HAS_TRAIT(O, TRAIT_T_RAY_VISIBLE)) + // continue var/mob/living/target = locate() in view(4,src) if(target && !target.stat) O.throw_at(target, 5, 10) -/obj/effect/anomaly/grav/Crossed(mob/A) - gravShock(A) +/obj/effect/anomaly/grav/Crossed(atom/movable/AM) + . = ..() + gravShock(AM) -/obj/effect/anomaly/grav/Bump(mob/A) +/obj/effect/anomaly/grav/Bump(atom/A) gravShock(A) /obj/effect/anomaly/grav/Bumped(atom/movable/AM) @@ -138,6 +147,7 @@ name = "flux wave anomaly" icon_state = "electricity2" density = TRUE + aSignal = /obj/item/assembly/signaler/anomaly/flux var/canshock = FALSE var/shockdamage = 20 var/explosive = TRUE @@ -148,11 +158,12 @@ for(var/mob/living/M in range(0, src)) mobShock(M) -/obj/effect/anomaly/flux/Crossed(mob/living/M) - mobShock(M) +/obj/effect/anomaly/flux/Crossed(atom/movable/AM) + . = ..() + mobShock(AM) -/obj/effect/anomaly/flux/Bump(mob/living/M) - mobShock(M) +/obj/effect/anomaly/flux/Bump(atom/A) + mobShock(A) /obj/effect/anomaly/flux/Bumped(atom/movable/AM) mobShock(AM) @@ -160,7 +171,7 @@ /obj/effect/anomaly/flux/proc/mobShock(mob/living/M) if(canshock && istype(M)) canshock = FALSE //Just so you don't instakill yourself if you slam into the anomaly five times in a second. - M.electrocute_act(shockdamage, "[name]", flags = SHOCK_NOGLOVES) + M.electrocute_act(shockdamage, name, flags = SHOCK_NOGLOVES) /obj/effect/anomaly/flux/detonate() if(explosive) @@ -176,6 +187,7 @@ icon = 'icons/obj/projectiles.dmi' icon_state = "bluespace" density = TRUE + aSignal = /obj/item/assembly/signaler/anomaly/bluespace /obj/effect/anomaly/bluespace/anomalyEffect() ..() @@ -187,7 +199,7 @@ do_teleport(AM, locate(AM.x, AM.y, AM.z), 8, channel = TELEPORT_CHANNEL_BLUESPACE) /obj/effect/anomaly/bluespace/detonate() - var/turf/T = safepick(get_area_turfs(impact_area)) + var/turf/T = pick(get_area_turfs(impact_area)) if(T) // Calculate new position (searches through beacons in world) var/obj/item/beacon/chosen @@ -224,21 +236,23 @@ if(!A.Move(newloc) && newloc) // if the atom, for some reason, can't move, FORCE them to move! :) We try Move() first to invoke any movement-related checks the atom needs to perform after moving A.forceMove(newloc) - spawn() - if(ismob(A) && !(A in flashers)) // don't flash if we're already doing an effect - var/mob/M = A - if(M.client) - var/obj/blueeffect = new /obj(src) - blueeffect.screen_loc = "WEST,SOUTH to EAST,NORTH" - blueeffect.icon = 'icons/effects/effects.dmi' - blueeffect.icon_state = "shieldsparkles" - blueeffect.layer = FLASH_LAYER - blueeffect.plane = FULLSCREEN_PLANE - blueeffect.mouse_opacity = MOUSE_OPACITY_TRANSPARENT - M.client.screen += blueeffect - sleep(20) - M.client.screen -= blueeffect - qdel(blueeffect) + if(ismob(A) && !(A in flashers)) // don't flash if we're already doing an effect + var/mob/M = A + if(M.client) + INVOKE_ASYNC(src, .proc/blue_effect, M) + +/obj/effect/anomaly/bluespace/proc/blue_effect(mob/M) + var/obj/blueeffect = new /obj(src) + blueeffect.screen_loc = "WEST,SOUTH to EAST,NORTH" + blueeffect.icon = 'icons/effects/effects.dmi' + blueeffect.icon_state = "shieldsparkles" + blueeffect.layer = FLASH_LAYER + blueeffect.plane = FULLSCREEN_PLANE + blueeffect.mouse_opacity = MOUSE_OPACITY_TRANSPARENT + M.client.screen += blueeffect + sleep(20) + M.client.screen -= blueeffect + qdel(blueeffect) ///////////////////// @@ -246,6 +260,7 @@ name = "pyroclastic anomaly" icon_state = "mustard" var/ticks = 0 + aSignal = /obj/item/assembly/signaler/anomaly/pyro /obj/effect/anomaly/pyro/anomalyEffect() ..() @@ -278,6 +293,7 @@ name = "vortex anomaly" icon_state = "bhole3" desc = "That's a nice station you have there. It'd be a shame if something happened to it." + aSignal = /obj/item/assembly/signaler/anomaly/vortex /obj/effect/anomaly/bhole/anomalyEffect() ..() diff --git a/code/game/objects/effects/portals.dm b/code/game/objects/effects/portals.dm index 0b227be247..a7b5091522 100644 --- a/code/game/objects/effects/portals.dm +++ b/code/game/objects/effects/portals.dm @@ -1,10 +1,10 @@ -/proc/create_portal_pair(turf/source, turf/destination, _creator = null, _lifespan = 300, accuracy = 0, newtype = /obj/effect/portal, atmos_link_override) +/proc/create_portal_pair(turf/source, turf/destination, _lifespan = 300, accuracy = 0, newtype = /obj/effect/portal, atmos_link_override) if(!istype(source) || !istype(destination)) return var/turf/actual_destination = get_teleport_turf(destination, accuracy) - var/obj/effect/portal/P1 = new newtype(source, _creator, _lifespan, null, FALSE, null, atmos_link_override) - var/obj/effect/portal/P2 = new newtype(actual_destination, _creator, _lifespan, P1, TRUE, null, atmos_link_override) + var/obj/effect/portal/P1 = new newtype(source, _lifespan, null, FALSE, null, atmos_link_override) + var/obj/effect/portal/P2 = new newtype(actual_destination, _lifespan, P1, TRUE, null, atmos_link_override) if(!istype(P1)||!istype(P2)) return P1.link_portal(P2) @@ -21,7 +21,6 @@ var/obj/effect/portal/linked var/hardlinked = TRUE //Requires a linked portal at all times. Destroy if there's no linked portal, if there is destroy it when this one is deleted. var/teleport_channel = TELEPORT_CHANNEL_BLUESPACE - var/creator var/turf/hard_target //For when a portal needs a hard target and isn't to be linked. var/atmos_link = FALSE //Link source/destination atmos. var/turf/open/atmos_source //Atmos link source @@ -35,6 +34,7 @@ name = "wormhole" icon = 'icons/obj/objects.dmi' icon_state = "anom" + layer = RIPPLE_LAYER mech_sized = TRUE teleport_channel = TELEPORT_CHANNEL_WORMHOLE @@ -49,7 +49,9 @@ user.forceMove(get_turf(src)) return TRUE -/obj/effect/portal/Crossed(atom/movable/AM, oldloc) +/obj/effect/portal/Crossed(atom/movable/AM, oldloc, force_stop = 0) + if(force_stop) + return ..() if(isobserver(AM)) return ..() if(linked && (get_turf(oldloc) == get_turf(linked))) @@ -66,7 +68,7 @@ if(Adjacent(user)) user.forceMove(get_turf(src)) -/obj/effect/portal/Initialize(mapload, _creator, _lifespan = 0, obj/effect/portal/_linked, automatic_link = FALSE, turf/hard_target_override, atmos_link_override) +/obj/effect/portal/Initialize(mapload, _lifespan = 0, obj/effect/portal/_linked, automatic_link = FALSE, turf/hard_target_override, atmos_link_override) . = ..() GLOB.portals += src if(!istype(_linked) && automatic_link) @@ -78,7 +80,6 @@ atmos_link = atmos_link_override link_portal(_linked) hardlinked = automatic_link - creator = _creator if(isturf(hard_target_override)) hard_target = hard_target_override @@ -129,10 +130,7 @@ LAZYREMOVE(atmos_destination.atmos_adjacent_turfs, atmos_source) atmos_destination = null -/obj/effect/portal/Destroy() //Calls on_portal_destroy(destroyed portal, location of destroyed portal) on creator if creator has such call. - if(creator && hascall(creator, "on_portal_destroy")) - call(creator, "on_portal_destroy")(src, src.loc) - creator = null +/obj/effect/portal/Destroy() GLOB.portals -= src unlink_atmos() if(hardlinked && !QDELETED(linked)) @@ -153,8 +151,6 @@ return FALSE if(!force && (!ismecha(M) && !istype(M, /obj/item/projectile) && M.anchored && !allow_anchored)) return - if(ismegafauna(M)) - message_admins("[M] has used a portal at [ADMIN_VERBOSEJMP(src)] made by [usr].") var/no_effect = FALSE if(last_effect == world.time) no_effect = TRUE diff --git a/code/game/objects/effects/spawners/bundle.dm b/code/game/objects/effects/spawners/bundle.dm index 3f2701c03f..b75df644eb 100644 --- a/code/game/objects/effects/spawners/bundle.dm +++ b/code/game/objects/effects/spawners/bundle.dm @@ -168,3 +168,26 @@ items = list( /obj/item/clothing/mask/gas/sexymime, /obj/item/clothing/under/rank/civilian/mime/sexy) + +/obj/effect/spawner/bundle/crate/Initialize(mapload) + if(items && items.len) + var/turf/T = get_turf(src) + var/obj/structure/closet/LC = locate(/obj/structure/closet) in T + if(LC) + for(var/path in items) + new path(LC) + return INITIALIZE_HINT_QDEL + +/obj/effect/spawner/bundle/crate/mosin + name = "Mosin-Nagant spawner" + items = list( + /obj/item/gun/ballistic/shotgun/boltaction, + /obj/item/ammo_box/a762 + ) + +/obj/effect/spawner/bundle/crate/surplusrifle + name = "surplus rifle spawner" + items = list( + /obj/item/gun/ballistic/automatic/surplus, + /obj/item/ammo_box/magazine/m10mm/rifle + ) diff --git a/code/game/objects/effects/spawners/lootdrop.dm b/code/game/objects/effects/spawners/lootdrop.dm index 8944b55cc4..6564a83729 100644 --- a/code/game/objects/effects/spawners/lootdrop.dm +++ b/code/game/objects/effects/spawners/lootdrop.dm @@ -380,8 +380,6 @@ name = "random keg spawner" lootcount = 1 loot = list(/obj/structure/reagent_dispensers/keg/mead = 5, - /obj/structure/reagent_dispensers/keg/aphro = 2, - /obj/structure/reagent_dispensers/keg/aphro/strong = 2, /obj/structure/reagent_dispensers/keg/gargle = 1) /obj/effect/spawner/lootdrop/coin diff --git a/code/game/objects/effects/temporary_visuals/miscellaneous.dm b/code/game/objects/effects/temporary_visuals/miscellaneous.dm index 396f463136..8d5458333c 100644 --- a/code/game/objects/effects/temporary_visuals/miscellaneous.dm +++ b/code/game/objects/effects/temporary_visuals/miscellaneous.dm @@ -139,6 +139,23 @@ /obj/effect/temp_visual/dir_setting/curse/hand icon_state = "cursehand" +/obj/effect/temp_visual/bsa_splash + name = "\improper Bluespace energy wave" + desc = "A massive, rippling wave of bluepace energy, all rapidly exhausting itself the moment it leaves the concentrated beam of light." + icon = 'icons/effects/beam_splash.dmi' + icon_state = "beam_splash_l" + layer = ABOVE_ALL_MOB_LAYER + pixel_y = -16 + duration = 50 + +/obj/effect/temp_visual/bsa_splash/Initialize(mapload, dir) + . = ..() + switch(dir) + if(WEST) + icon_state = "beam_splash_w" + if(EAST) + icon_state = "beam_splash_e" + /obj/effect/temp_visual/wizard name = "water" icon = 'icons/mob/mob.dmi' diff --git a/code/game/objects/items/RCD.dm b/code/game/objects/items/RCD.dm index 2fbb45173b..c89e318714 100644 --- a/code/game/objects/items/RCD.dm +++ b/code/game/objects/items/RCD.dm @@ -135,6 +135,14 @@ RLD flick("[icon_state]_empty", src) //somewhat hacky thing to make RCDs with ammo counters actually have a blinking yellow light return . + +/obj/item/construction/proc/check_menu(mob/living/user) + if(!istype(user)) + return FALSE + if(user.incapacitated() || !user.Adjacent(src)) + return FALSE + return TRUE + /obj/item/construction/proc/range_check(atom/A, mob/user) if(!(A in range(custom_range, get_turf(user)))) to_chat(user, "The \'Out of Range\' light on [src] blinks red.") @@ -276,13 +284,6 @@ RLD //Not scaling these down to button size because they look horrible then, instead just bumping up radius. return MA -/obj/item/construction/rcd/proc/check_menu(mob/living/user) - if(!istype(user)) - return FALSE - if(user.incapacitated() || !user.Adjacent(src)) - return FALSE - return TRUE - /obj/item/construction/rcd/proc/change_computer_dir(mob/user) if(!user) return @@ -856,6 +857,82 @@ RLD desc = "It contains the design for firelock, air alarm, fire alarm, apc circuits and crap power cells." upgrade = RCD_UPGRADE_SIMPLE_CIRCUITS +/obj/item/construction/plumbing + name = "Plumbing Constructor" + desc = "An expertly modified RCD outfitted to construct plumbing machinery. Reload with compressed matter cartridges." + icon = 'icons/obj/tools.dmi' + icon_state = "arcd" + item_state = "oldrcd" + has_ammobar = FALSE + matter = 200 + max_matter = 200 + + ///type of the plumbing machine + var/blueprint = null + ///index, used in the attack self to get the type. stored here since it doesnt change + var/list/choices = list() + ///index, used in the attack self to get the type. stored here since it doesnt change + var/list/name_to_type = list() + /// + var/list/machinery_data = list("cost" = list(), "delay" = list()) + +/obj/item/construction/plumbing/attack_self(mob/user) + ..() + if(!choices.len) + for(var/A in subtypesof(/obj/machinery/plumbing)) + var/obj/machinery/plumbing/M = A + if(initial(M.rcd_constructable)) + choices += list(initial(M.name) = image(icon = initial(M.icon), icon_state = initial(M.icon_state))) + name_to_type[initial(M.name)] = M + machinery_data["cost"][A] = initial(M.rcd_cost) + machinery_data["delay"][A] = initial(M.rcd_delay) + + var/choice = show_radial_menu(user, src, choices, custom_check = CALLBACK(src, .proc/check_menu, user), require_near = TRUE, tooltips = TRUE) + if(!check_menu(user)) + return + + blueprint = name_to_type[choice] + playsound(src, 'sound/effects/pop.ogg', 50, FALSE) + to_chat(user, "You change [name]s blueprint to '[choice]'.") + +///pretty much rcd_create, but named differently to make myself feel less bad for copypasting from a sibling-type +/obj/item/construction/plumbing/proc/create_machine(atom/A, mob/user) + if(!machinery_data || !isopenturf(A)) + return FALSE + + if(checkResource(machinery_data["cost"][blueprint], user) && blueprint) + if(do_after(user, machinery_data["delay"][blueprint], target = A)) + if(checkResource(machinery_data["cost"][blueprint], user) && canPlace(A)) + useResource(machinery_data["cost"][blueprint], user) + activate() + playsound(src.loc, 'sound/machines/click.ogg', 50, TRUE) + new blueprint (A, FALSE, FALSE) + return TRUE + +/obj/item/construction/plumbing/proc/canPlace(turf/T) + if(!isopenturf(T)) + return FALSE + . = TRUE + for(var/obj/O in T.contents) + if(O.density) //let's not built ontop of dense stuff, like big machines and other obstacles, it kills my immershion + return FALSE + +/obj/item/construction/plumbing/afterattack(atom/A, mob/user) + . = ..() + if(!range_check(A, user)) + return + if(istype(A, /obj/machinery/plumbing)) + var/obj/machinery/plumbing/P = A + if(P.anchored) + to_chat(user, "The [P.name] needs to be unanchored!") + return + if(do_after(user, 20, target = P)) + P.deconstruct() //Let's not substract matter + playsound(get_turf(src), 'sound/machines/click.ogg', 50, TRUE) //this is just such a great sound effect + else + create_machine(A, user) + + #undef GLOW_MODE #undef LIGHT_MODE #undef REMOVE_MODE diff --git a/code/game/objects/items/RPD.dm b/code/game/objects/items/RPD.dm index 93d73b2b5f..70e4441c66 100644 --- a/code/game/objects/items/RPD.dm +++ b/code/game/objects/items/RPD.dm @@ -6,6 +6,7 @@ RPD #define ATMOS_CATEGORY 0 #define DISPOSALS_CATEGORY 1 #define TRANSIT_CATEGORY 2 +#define PLUMBING_CATEGORY 3 #define BUILD_MODE (1<<0) #define WRENCH_MODE (1<<1) @@ -75,6 +76,13 @@ GLOBAL_LIST_INIT(transit_tube_recipes, list( ) )) +GLOBAL_LIST_INIT(fluid_duct_recipes, list( + "Fluid Ducts" = list( + new /datum/pipe_info/plumbing("Duct", /obj/machinery/duct, PIPE_ONEDIR), + new /datum/pipe_info/plumbing/multilayer("Duct Layer-Manifold",/obj/machinery/duct/multilayered, PIPE_STRAIGHT) + ) +)) + /datum/pipe_info var/name var/icon_state @@ -175,6 +183,15 @@ GLOBAL_LIST_INIT(transit_tube_recipes, list( if(dt == PIPE_UNARY_FLIPPABLE) icon_state = "[icon_state]_preview" +/datum/pipe_info/plumbing/New(label, obj/path, dt=PIPE_UNARY) + name = label + id = path + icon_state = initial(path.icon_state) + dirtype = dt + +/datum/pipe_info/plumbing/multilayer //exists as identifier so we can see the difference between multi_layer and just ducts properly later on + + /obj/item/pipe_dispenser name = "Rapid Piping Device (RPD)" desc = "A device used to rapidly pipe things." @@ -200,15 +217,19 @@ GLOBAL_LIST_INIT(transit_tube_recipes, list( var/atmos_build_speed = 5 //deciseconds (500ms) var/disposal_build_speed = 5 var/transit_build_speed = 5 + var/plumbing_build_speed = 5 var/destroy_speed = 5 var/paint_speed = 5 var/category = ATMOS_CATEGORY var/piping_layer = PIPING_LAYER_DEFAULT + var/ducting_layer = DUCT_LAYER_DEFAULT var/datum/pipe_info/recipe var/static/datum/pipe_info/first_atmos var/static/datum/pipe_info/first_disposal var/static/datum/pipe_info/first_transit var/mode = BUILD_MODE | DESTROY_MODE | WRENCH_MODE + var/static/datum/pipe_info/first_plumbing + var/locked = FALSE //wheter we can change categories. Useful for the plumber /obj/item/pipe_dispenser/New() . = ..() @@ -238,29 +259,30 @@ GLOBAL_LIST_INIT(transit_tube_recipes, list( playsound(get_turf(user), 'sound/items/deconstruct.ogg', 50, 1) return(BRUTELOSS) -/obj/item/pipe_dispenser/ui_base_html(html) - var/datum/asset/spritesheet/assets = get_asset_datum(/datum/asset/spritesheet/pipes) - . = replacetext(html, "", assets.css_tag()) +/obj/item/pipe_dispenser/ui_assets(mob/user) + return list( + get_asset_datum(/datum/asset/spritesheet/pipes), + ) -/obj/item/pipe_dispenser/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ - datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) +/obj/item/pipe_dispenser/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) if(!ui) - var/datum/asset/assets = get_asset_datum(/datum/asset/spritesheet/pipes) - assets.send(user) - - ui = new(user, src, ui_key, "RapidPipeDispenser", name, 425, 515, master_ui, state) + ui = new(user, src, "RapidPipeDispenser", name) ui.open() /obj/item/pipe_dispenser/ui_data(mob/user) var/list/data = list( "category" = category, "piping_layer" = piping_layer, + + "ducting_layer" = ducting_layer, + "preview_rows" = recipe.get_preview(p_dir), "categories" = list(), "selected_color" = paint_color, "paint_colors" = GLOB.pipe_paint_colors, - "mode" = mode + "mode" = mode, + "locked" = locked ) var/list/recipes @@ -271,6 +293,8 @@ GLOBAL_LIST_INIT(transit_tube_recipes, list( recipes = GLOB.disposal_pipe_recipes if(TRANSIT_CATEGORY) recipes = GLOB.transit_tube_recipes + if(PLUMBING_CATEGORY) + recipes = GLOB.fluid_duct_recipes for(var/c in recipes) var/list/cat = recipes[c] var/list/r = list() @@ -284,7 +308,7 @@ GLOBAL_LIST_INIT(transit_tube_recipes, list( /obj/item/pipe_dispenser/ui_act(action, params) if(..()) return - if(!usr.canUseTopic(src)) + if(!usr.canUseTopic(src, BE_CLOSE)) return var/playeffect = TRUE switch(action) @@ -299,11 +323,16 @@ GLOBAL_LIST_INIT(transit_tube_recipes, list( recipe = first_atmos if(TRANSIT_CATEGORY) recipe = first_transit + if(PLUMBING_CATEGORY) + recipe = first_plumbing p_dir = NORTH playeffect = FALSE if("piping_layer") piping_layer = text2num(params["piping_layer"]) playeffect = FALSE + // if("ducting_layer") + // ducting_layer = text2num(params["ducting_layer"]) + // playeffect = FALSE if("pipe_type") var/static/list/recipes if(!recipes) @@ -320,11 +349,9 @@ GLOBAL_LIST_INIT(transit_tube_recipes, list( mode &= ~n else mode |= n - - if(playeffect && world.time >= effectcooldown) + if(playeffect) spark_system.start() - effectcooldown = world.time + 100 - playsound(get_turf(src), 'sound/effects/pop.ogg', 50, 0) + playsound(get_turf(src), 'sound/effects/pop.ogg', 50, FALSE) return TRUE /obj/item/pipe_dispenser/pre_attack(atom/A, mob/user) @@ -469,16 +496,56 @@ GLOBAL_LIST_INIT(transit_tube_recipes, list( if(mode & WRENCH_MODE) tube.wrench_act(user, src) return - + if(PLUMBING_CATEGORY) //Plumbing. + if(!can_make_pipe) + return ..() + A = get_turf(A) + if(isclosedturf(A)) + to_chat(user, "[src]'s error light flickers; there's something in the way!") + return + to_chat(user, "You start building a fluid duct...") + playsound(get_turf(src), 'sound/machines/click.ogg', 50, 1) + if(do_after(user, plumbing_build_speed, target = A)) + var/obj/machinery/duct/D + if(recipe.type == /datum/pipe_info/plumbing/multilayer) + var/temp_connects = NORTH + SOUTH + if(queued_p_dir == EAST) + temp_connects = EAST + WEST + D = new queued_p_type (A, TRUE, GLOB.pipe_paint_colors[paint_color], ducting_layer, temp_connects) + else + D = new queued_p_type (A, TRUE, GLOB.pipe_paint_colors[paint_color], ducting_layer) + D.add_fingerprint(usr) + if(mode & WRENCH_MODE) + D.wrench_act(user, src) else return ..() /obj/item/pipe_dispenser/proc/activate() playsound(get_turf(src), 'sound/items/deconstruct.ogg', 50, 1) +/* unneeded, you can craft ducts from plastic +/obj/item/pipe_dispenser/plumbing + name = "Plumberinator" + desc = "A crude device to rapidly plumb things." + icon_state = "plumberer" + category = PLUMBING_CATEGORY + locked = TRUE + +/obj/item/pipe_dispenser/plumbing/Initialize() + . = ..() + spark_system = new + spark_system.set_up(5, 0, src) + spark_system.attach(src) + if(!first_plumbing) + first_plumbing = GLOB.fluid_duct_recipes[GLOB.fluid_duct_recipes[1]][1] + + recipe = first_plumbing + +*/ #undef ATMOS_CATEGORY #undef DISPOSALS_CATEGORY #undef TRANSIT_CATEGORY +#undef PLUMBING_CATEGORY #undef BUILD_MODE #undef DESTROY_MODE diff --git a/code/game/objects/items/airlock_painter.dm b/code/game/objects/items/airlock_painter.dm index 4f3761f899..b28de437ed 100644 --- a/code/game/objects/items/airlock_painter.dm +++ b/code/game/objects/items/airlock_painter.dm @@ -180,10 +180,10 @@ stored_decal_total = "[stored_decal][yellow_fix][stored_color]" return -/obj/item/airlock_painter/decal/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = 0, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) +/obj/item/airlock_painter/decal/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) if(!ui) - ui = new(user, src, ui_key, "DecalPainter", name, 500, 400, master_ui, state) + ui = new(user, src, "DecalPainter", name) ui.open() /obj/item/airlock_painter/decal/ui_data(mob/user) diff --git a/code/game/objects/items/circuitboards/machine_circuitboards.dm b/code/game/objects/items/circuitboards/machine_circuitboards.dm index 56eb25f953..37d19783b5 100644 --- a/code/game/objects/items/circuitboards/machine_circuitboards.dm +++ b/code/game/objects/items/circuitboards/machine_circuitboards.dm @@ -48,6 +48,13 @@ /obj/item/stack/cable_coil = 5, /obj/item/stack/sheet/glass = 1) +/obj/item/circuitboard/machine/medipen_refiller + name = "Medipen Refiller (Machine Board)" + icon_state = "medical" + build_path = /obj/machinery/medipen_refiller + req_components = list( + /obj/item/stock_parts/matter_bin = 1) + /obj/item/circuitboard/machine/clonepod name = "Clone Pod (Machine Board)" build_path = /obj/machinery/clonepod @@ -512,6 +519,10 @@ /obj/item/stack/sheet/glass = 1) needs_anchored = FALSE +/obj/item/circuitboard/machine/hydroponics/automagic + name = "Automatic Hydroponics Tray (Machine Board)" + build_path = /obj/machinery/hydroponics/constructable/automagic + /obj/item/circuitboard/machine/seed_extractor name = "Seed Extractor (Machine Board)" build_path = /obj/machinery/seed_extractor diff --git a/code/game/objects/items/crayons.dm b/code/game/objects/items/crayons.dm index a366a2ef88..7f8b720509 100644 --- a/code/game/objects/items/crayons.dm +++ b/code/game/objects/items/crayons.dm @@ -147,23 +147,23 @@ to_chat(user, "There is not enough of [src] left!") . = TRUE -/obj/item/toy/crayon/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.hands_state) - // tgui is a plague upon this codebase +/obj/item/toy/crayon/ui_state(mob/user) + return GLOB.hands_state - SStgui.try_update_ui(user, src, ui_key, ui, force_open) +/obj/item/toy/crayon/ui_interact(mob/user, datum/tgui/ui) + // tgui is a plague upon this codebase + // no u + ui = SStgui.try_update_ui(user, src, ui) if(!ui) - ui = new(user, src, ui_key, "Crayon", name, 600, 600, - master_ui, state) + ui = new(user, src, "Crayon", name) ui.open() /obj/item/toy/crayon/spraycan/AltClick(mob/user) - . = ..() if(user.canUseTopic(src, BE_CLOSE, ismonkey(user))) if(has_cap) is_capped = !is_capped to_chat(user, "The cap on [src] is now [is_capped ? "on" : "off"].") update_icon() - return TRUE /obj/item/toy/crayon/CtrlClick(mob/user) if(can_change_colour && !isturf(loc) && user.canUseTopic(src, BE_CLOSE, ismonkey(user))) diff --git a/code/game/objects/items/devices/PDA/PDA.dm b/code/game/objects/items/devices/PDA/PDA.dm index d706f5468a..ec68cdb40c 100644 --- a/code/game/objects/items/devices/PDA/PDA.dm +++ b/code/game/objects/items/devices/PDA/PDA.dm @@ -1027,6 +1027,7 @@ GLOBAL_LIST_EMPTY(PDAs) else if(is_type_in_list(C, contained_item)) //Checks if there is a pen if(inserted_item) to_chat(user, "There is already \a [inserted_item] in \the [src]!") + return ..() else if(!user.transferItemToLoc(C, src)) return diff --git a/code/game/objects/items/devices/aicard.dm b/code/game/objects/items/devices/aicard.dm index bfb9348d97..503e2a9473 100644 --- a/code/game/objects/items/devices/aicard.dm +++ b/code/game/objects/items/devices/aicard.dm @@ -54,18 +54,20 @@ name = initial(name) icon_state = initial(icon_state) -/obj/item/aicard/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ - datum/tgui/master_ui = null, datum/ui_state/state = GLOB.hands_state) - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) +/obj/item/aicard/ui_state(mob/user) + return GLOB.hands_state + +/obj/item/aicard/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) if(!ui) - ui = new(user, src, ui_key, "Intellicard", name, 500, 500, master_ui, state) + ui = new(user, src, "Intellicard", name) ui.open() /obj/item/aicard/ui_data() var/list/data = list() if(AI) data["name"] = AI.name - data["laws"] = AI.laws.get_law_list(include_zeroth = 1) + data["laws"] = AI.laws.get_law_list(include_zeroth = TRUE, render_html = FALSE) data["health"] = (AI.health + 100) / 2 data["wireless"] = !AI.control_disabled //todo disabled->enabled data["radio"] = AI.radio_enabled @@ -86,19 +88,19 @@ if(confirm == "Yes" && !..()) flush = TRUE if(AI && AI.loc == src) - to_chat(AI, "Your core files are being wiped!") + to_chat(AI, "Your core files are being wiped!") while(AI.stat != DEAD && flush) - AI.adjustOxyLoss(1) + AI.adjustOxyLoss(5) AI.updatehealth() sleep(5) flush = FALSE . = TRUE if("wireless") AI.control_disabled = !AI.control_disabled - to_chat(AI, "[src]'s wireless port has been [AI.control_disabled ? "disabled" : "enabled"]!") + to_chat(AI, "[src]'s wireless port has been [AI.control_disabled ? "disabled" : "enabled"]!") . = TRUE if("radio") AI.radio_enabled = !AI.radio_enabled - to_chat(AI, "Your Subspace Transceiver has been [AI.radio_enabled ? "enabled" : "disabled"]!") + to_chat(AI, "Your Subspace Transceiver has been [AI.radio_enabled ? "enabled" : "disabled"]!") . = TRUE update_icon() diff --git a/code/game/objects/items/devices/dogborg_sleeper.dm b/code/game/objects/items/devices/dogborg_sleeper.dm index d8abccb336..1f91196b24 100644 --- a/code/game/objects/items/devices/dogborg_sleeper.dm +++ b/code/game/objects/items/devices/dogborg_sleeper.dm @@ -163,12 +163,13 @@ return ui_interact(user) -/obj/item/dogborg/sleeper/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ - datum/tgui/master_ui = null, datum/ui_state/state = GLOB.notcontained_state) +/obj/item/dogborg/sleeper/ui_state(mob/user) + return GLOB.notcontained_state - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) +/obj/item/dogborg/sleeper/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) if(!ui) - ui = new(user, src, ui_key, "dogborg_sleeper", name, 375, 550, master_ui, state) + ui = new(user, src, "dogborg_sleeper", name, 375, 550) //UI DOES NOT EXIST ui.open() /obj/item/dogborg/sleeper/ui_data() diff --git a/code/game/objects/items/devices/gps.dm b/code/game/objects/items/devices/gps.dm index ee26d81a0d..bb46577702 100644 --- a/code/game/objects/items/devices/gps.dm +++ b/code/game/objects/items/devices/gps.dm @@ -1,4 +1,4 @@ -GLOBAL_LIST_EMPTY(GPS_list) + /obj/item/gps name = "global positioning system" desc = "Helping lost spacemen find their way through the planets since 2016." @@ -8,138 +8,10 @@ GLOBAL_LIST_EMPTY(GPS_list) slot_flags = ITEM_SLOT_BELT obj_flags = UNIQUE_RENAME var/gpstag = "COM0" - var/emped = FALSE - var/tracking = TRUE - var/updating = TRUE //Automatic updating of GPS list. Can be set to manual by user. - var/global_mode = TRUE //If disabled, only GPS signals of the same Z level are shown - -/obj/item/gps/examine(mob/user) - . = ..() - var/turf/curr = get_turf(src) - . += "The screen says: [get_area_name(curr, TRUE)] ([curr.x], [curr.y], [curr.z])" - . += "Alt-click to switch it [tracking ? "off":"on"]." /obj/item/gps/Initialize() . = ..() - GLOB.GPS_list += src - name = "global positioning system ([gpstag])" - add_overlay("working") - -/obj/item/gps/Destroy() - GLOB.GPS_list -= src - return ..() - -/obj/item/gps/emp_act(severity) - . = ..() - if (. & EMP_PROTECT_SELF) - return - emped = TRUE - cut_overlay("working") - add_overlay("emp") - addtimer(CALLBACK(src, .proc/reboot), 300, TIMER_UNIQUE|TIMER_OVERRIDE) //if a new EMP happens, remove the old timer so it doesn't reactivate early - SStgui.close_uis(src) //Close the UI control if it is open. - -/obj/item/gps/proc/reboot() - emped = FALSE - cut_overlay("emp") - add_overlay("working") - -/obj/item/gps/AltClick(mob/user) - . = ..() - if(!user.canUseTopic(src, BE_CLOSE)) - return - toggletracking(user) - return TRUE - -/obj/item/gps/proc/toggletracking(mob/user) - if(!user.canUseTopic(src, BE_CLOSE)) - return //user not valid to use gps - if(emped) - to_chat(user, "It's busted!") - return - if(tracking) - cut_overlay("working") - to_chat(user, "[src] is no longer tracking, or visible to other GPS devices.") - tracking = FALSE - else - add_overlay("working") - to_chat(user, "[src] is now tracking, and visible to other GPS devices.") - tracking = TRUE - - -/obj/item/gps/ui_interact(mob/user, ui_key = "gps", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) // Remember to use the appropriate state. - if(emped) - to_chat(user, "[src] fizzles weakly.") - return - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) - if(!ui) - // Variable window height, depending on how many GPS units there are - // to show, clamped to relatively safe range. - var/gps_window_height = clamp(325 + GLOB.GPS_list.len * 14, 325, 700) - ui = new(user, src, ui_key, "Gps", "Global Positioning System", 470, gps_window_height, master_ui, state) //width, height - ui.open() - - ui.set_autoupdate(state = updating) - - -/obj/item/gps/ui_data(mob/user) - var/list/data = list() - data["power"] = tracking - data["tag"] = gpstag - data["updating"] = updating - data["globalmode"] = global_mode - if(!tracking || emped) //Do not bother scanning if the GPS is off or EMPed - return data - - var/turf/curr = get_turf(src) - data["current"] = "[get_area_name(curr, TRUE)] ([curr.x], [curr.y], [curr.z])" - data["currentArea"] = "[get_area_name(curr, TRUE)]" - data["currentCoords"] = "[curr.x], [curr.y], [curr.z]" - - var/list/signals = list() - data["signals"] = list() - - for(var/gps in GLOB.GPS_list) - var/obj/item/gps/G = gps - if(G.emped || !G.tracking || G == src) - continue - var/turf/pos = get_turf(G) - if(!global_mode && pos.z != curr.z) - continue - var/list/signal = list() - signal["entrytag"] = G.gpstag //Name or 'tag' of the GPS - signal["coords"] = "[pos.x], [pos.y], [pos.z]" - if(pos.z == curr.z) //Distance/Direction calculations for same z-level only - signal["dist"] = max(get_dist(curr, pos), 0) //Distance between the src and remote GPS turfs - signal["degrees"] = round(Get_Angle(curr, pos)) //0-360 degree directional bearing, for more precision. - - signals += list(signal) //Add this signal to the list of signals - data["signals"] = signals - return data - - - -/obj/item/gps/ui_act(action, params) - if(..()) - return - switch(action) - if("rename") - var/a = input("Please enter desired tag.", name, gpstag) as text - a = copytext(sanitize(a), 1, 20) - gpstag = a - . = TRUE - name = "global positioning system ([gpstag])" - - if("power") - toggletracking(usr) - . = TRUE - if("updating") - updating = !updating - . = TRUE - if("globalmode") - global_mode = !global_mode - . = TRUE - + AddComponent(/datum/component/gps/item, gpstag) /obj/item/gps/science icon_state = "gps-s" diff --git a/code/game/objects/items/devices/radio/electropack.dm b/code/game/objects/items/devices/radio/electropack.dm index 0cf7ceb55b..e65325587c 100644 --- a/code/game/objects/items/devices/radio/electropack.dm +++ b/code/game/objects/items/devices/radio/electropack.dm @@ -29,7 +29,7 @@ /obj/item/electropack/Destroy() SSradio.remove_object(src, frequency) - . = ..() + return ..() /obj/item/electropack/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) if(iscarbon(user)) @@ -39,7 +39,7 @@ return return ..() -/obj/item/electropack/attackby(obj/item/W, mob/living/user, params) +/obj/item/electropack/attackby(obj/item/W, mob/user, params) if(istype(W, /obj/item/clothing/head/helmet)) var/obj/item/assembly/shock_kit/A = new /obj/item/assembly/shock_kit(user) A.icon = 'icons/obj/assemblies.dmi' @@ -59,56 +59,12 @@ else return ..() -/obj/item/electropack/Topic(href, href_list) - var/mob/living/carbon/C = usr - if(usr.stat || usr.restrained() || C.back == src) - return - - if(!usr.canUseTopic(src, BE_CLOSE)) - usr << browse(null, "window=radio") - onclose(usr, "radio") - return - - if(href_list["set"]) - if(href_list["set"] == "freq") - var/new_freq = input(usr, "Input a new receiving frequency", "Electropack Frequency", format_frequency(frequency)) as num|null - if(!usr.canUseTopic(src, BE_CLOSE)) - return - new_freq = unformat_frequency(new_freq) - new_freq = sanitize_frequency(new_freq, TRUE) - set_frequency(new_freq) - - if(href_list["set"] == "code") - var/new_code = input(usr, "Input a new receiving code", "Electropack Code", code) as num|null - if(!usr.canUseTopic(src, BE_CLOSE)) - return - new_code = round(new_code) - new_code = clamp(new_code, 1, 100) - code = new_code - - if(href_list["set"] == "power") - if(!usr.canUseTopic(src, BE_CLOSE)) - return - on = !(on) - icon_state = "electropack[on]" - - if(usr) - attack_self(usr) - - return - -/obj/item/electropack/proc/set_frequency(new_frequency) - SSradio.remove_object(src, frequency) - frequency = new_frequency - SSradio.add_object(src, frequency, RADIO_SIGNALER) - return - /obj/item/electropack/receive_signal(datum/signal/signal) if(!signal || signal.data["code"] != code) return if(isliving(loc) && on) - if(shock_cooldown == TRUE) + if(shock_cooldown) return shock_cooldown = TRUE addtimer(VARSET_CALLBACK(src, shock_cooldown, FALSE), 100) @@ -124,18 +80,59 @@ if(master) master.receive_signal() - return -/obj/item/electropack/ui_interact(mob/user) - if(!ishuman(user)) +/obj/item/electropack/proc/set_frequency(new_frequency) + SSradio.remove_object(src, frequency) + frequency = new_frequency + SSradio.add_object(src, frequency, RADIO_SIGNALER) + +/obj/item/electropack/ui_state(mob/user) + return GLOB.hands_state + +/obj/item/electropack/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "Electropack", name) + ui.open() + +/obj/item/electropack/ui_data(mob/user) + var/list/data = list() + data["power"] = on + data["frequency"] = frequency + data["code"] = code + data["minFrequency"] = MIN_FREE_FREQ + data["maxFrequency"] = MAX_FREE_FREQ + return data + +/obj/item/electropack/ui_act(action, params) + if(..()) return -/obj/item/electropack/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ - datum/tgui/master_ui = null, datum/ui_state/state = GLOB.hands_state) - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) - if(!ui) - ui = new(user, src, ui_key, "Electropack", name, ui_x, ui_y, master_ui, state) - ui.open() + switch(action) + if("power") + on = !on + icon_state = "electropack[on]" + . = TRUE + if("freq") + var/value = unformat_frequency(params["freq"]) + if(value) + frequency = sanitize_frequency(value, TRUE) + set_frequency(frequency) + . = TRUE + if("code") + var/value = text2num(params["code"]) + if(value) + value = round(value) + code = clamp(value, 1, 100) + . = TRUE + if("reset") + if(params["reset"] == "freq") + frequency = initial(frequency) + . = TRUE + else if(params["reset"] == "code") + code = initial(code) + . = TRUE + /obj/item/electropack/shockcollar name = "shock collar" @@ -145,7 +142,7 @@ icon_state = "shockcollar" item_state = "shockcollar" body_parts_covered = NECK - slot_flags = ITEM_SLOT_NECK | ITEM_SLOT_DENYPOCKET //no more pocket shockers + slot_flags = ITEM_SLOT_NECK //no more pocket shockers. Now done without lazyness w_class = WEIGHT_CLASS_SMALL strip_delay = 60 equip_delay_other = 60 @@ -167,16 +164,18 @@ return return ..() -/obj/item/electropack/shockcollar/receive_signal(datum/signal/signal) +/obj/item/electropack/shockcollar/receive_signal(datum/signal/signal) //we have to override this because of text if(!signal || signal.data["code"] != code) return - if(isliving(loc) && on) + if(isliving(loc) && on) //the "on" arg is currently useless + var/mob/living/L = loc + if(!L.get_item_by_slot(SLOT_NECK)) //**properly** stops pocket shockers + return if(shock_cooldown == TRUE) return shock_cooldown = TRUE addtimer(VARSET_CALLBACK(src, shock_cooldown, FALSE), 100) - var/mob/living/L = loc step(L, pick(GLOB.cardinals)) to_chat(L, "You feel a sharp shock from the collar!") @@ -196,10 +195,13 @@ if(t) tagname = t name = "[initial(name)] - [t]" + return + if(istype(W, /obj/item/clothing/head/helmet)) //lazy method of denying this + return else return ..() -/obj/item/electropack/shockcollar/ui_interact(mob/user) //on_click calls this +/obj/item/electropack/shockcollar/ui_interact(mob/user) //note to src: use tgooey var/dat = {" Frequency/Code for shock collar:
diff --git a/code/game/objects/items/devices/radio/radio.dm b/code/game/objects/items/devices/radio/radio.dm index e26b29289a..4623a405de 100644 --- a/code/game/objects/items/devices/radio/radio.dm +++ b/code/game/objects/items/devices/radio/radio.dm @@ -107,19 +107,15 @@ else ..() -/obj/item/radio/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ - datum/tgui/master_ui = null, datum/ui_state/state = GLOB.inventory_state) - . = ..() - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) +/obj/item/radio/ui_state(mob/user) + return GLOB.inventory_state + +/obj/item/radio/ui_interact(mob/user, datum/tgui/ui, datum/ui_state/state) + ui = SStgui.try_update_ui(user, src, ui) if(!ui) - var/ui_width = 360 - var/ui_height = 106 - if(subspace_transmission) - if(channels.len > 0) - ui_height += 6 + channels.len * 21 - else - ui_height += 24 - ui = new(user, src, ui_key, "Radio", name, ui_width, ui_height, master_ui, state) + ui = new(user, src, "Radio", name) + if(state) + ui.set_state(state) ui.open() /obj/item/radio/ui_data(mob/user) diff --git a/code/game/objects/items/devices/traitordevices.dm b/code/game/objects/items/devices/traitordevices.dm index 4d255fd339..eb444cdb12 100644 --- a/code/game/objects/items/devices/traitordevices.dm +++ b/code/game/objects/items/devices/traitordevices.dm @@ -86,98 +86,102 @@ effective or pretty fucking useless. return if(!used) log_combat(user, M, "irradiated", src) - var/cooldown = GetCooldown() - used = 1 + var/cooldown = get_cooldown() + used = TRUE icon_state = "health1" - handle_cooldown(cooldown) // splits off to handle the cooldown while handling wavelength + addtimer(VARSET_CALLBACK(src, used, FALSE), cooldown) + addtimer(VARSET_CALLBACK(src, icon_state, "health"), cooldown) to_chat(user, "Successfully irradiated [M].") - spawn((wavelength+(intensity*4))*5) - if(M) - if(intensity >= 5) - M.apply_effect(round(intensity/0.075), EFFECT_UNCONSCIOUS) - M.rad_act(intensity*10) + addtimer(CALLBACK(src, .proc/radiation_aftereffect, M), (wavelength+(intensity*4))*5) else to_chat(user, "The radioactive microlaser is still recharging.") -/obj/item/healthanalyzer/rad_laser/proc/handle_cooldown(cooldown) - spawn(cooldown) - used = 0 - icon_state = "health" +/obj/item/healthanalyzer/rad_laser/proc/radiation_aftereffect(mob/living/M) + if(QDELETED(M)) + return + if(intensity >= 5) + M.apply_effect(round(intensity/0.075), EFFECT_UNCONSCIOUS) + M.rad_act(intensity*10) + +/obj/item/healthanalyzer/rad_laser/proc/get_cooldown() + return round(max(10, (stealth*30 + intensity*5 - wavelength/4))) /obj/item/healthanalyzer/rad_laser/attack_self(mob/user) interact(user) -/obj/item/healthanalyzer/rad_laser/proc/GetCooldown() - return round(max(10, (stealth*30 + intensity*5 - wavelength/4))) - /obj/item/healthanalyzer/rad_laser/interact(mob/user) ui_interact(user) -/obj/item/healthanalyzer/rad_laser/ui_interact(mob/user) -/obj/item/healthanalyzer/rad_laser/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ - datum/tgui/master_ui = null, datum/ui_state/state = GLOB.hands_state) - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) +/obj/item/healthanalyzer/rad_laser/ui_state(mob/user) + return GLOB.hands_state + +/obj/item/healthanalyzer/rad_laser/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) if(!ui) - ui = new(user, src, ui_key, "RadioactiveMicrolaser", "Radioactive Microlaser", ui_x, ui_y, master_ui, state) + ui = new(user, src, "RadioactiveMicrolaser") ui.open() - var/dat = "Irradiation: [irradiate ? "On" : "Off"]
" - dat += "Stealth Mode (NOTE: Deactivates automatically while Irradiation is off): [stealth ? "On" : "Off"]
" - dat += "Scan Mode: " - if(!scanmode) - dat += "Scan Health" - else if(scanmode == 1) - dat += "Scan Reagents" - else - dat += "Disabled" - dat += "

" +/obj/item/healthanalyzer/rad_laser/ui_data(mob/user) + var/list/data = list() + data["irradiate"] = irradiate + data["stealth"] = stealth + data["scanmode"] = scanmode + data["intensity"] = intensity + data["wavelength"] = wavelength + data["on_cooldown"] = used + data["cooldown"] = DisplayTimeText(get_cooldown()) + return data - dat += {" - Radiation Intensity: - -- - [intensity] - ++
+/obj/item/healthanalyzer/rad_laser/ui_act(action, params) + if(..()) + return - Radiation Wavelength: - -- - [(wavelength+(intensity*4))] - ++
- Laser Cooldown: [DisplayTimeText(GetCooldown())]
- "} - - var/datum/browser/popup = new(user, "radlaser", "Radioactive Microlaser Interface", 400, 240) - popup.set_content(dat) - popup.open() - -/obj/item/healthanalyzer/rad_laser/Topic(href, href_list) - if(!usr.canUseTopic(src)) - return 1 - - usr.set_machine(src) - if(href_list["rad"]) - irradiate = !irradiate - - else if(href_list["stealthy"]) - stealth = !stealth - - else if(href_list["mode"]) - scanmode += 1 - if(scanmode > 2) - scanmode = 0 - - else if(href_list["radint"]) - var/amount = text2num(href_list["radint"]) - amount += intensity - intensity = max(1,(min(20,amount))) - - else if(href_list["radwav"]) - var/amount = text2num(href_list["radwav"]) - amount += wavelength - wavelength = max(0,(min(120,amount))) - - attack_self(usr) - add_fingerprint(usr) - return + switch(action) + if("irradiate") + irradiate = !irradiate + . = TRUE + if("stealth") + stealth = !stealth + . = TRUE + if("scanmode") + scanmode = !scanmode + . = TRUE + if("radintensity") + var/target = params["target"] + var/adjust = text2num(params["adjust"]) + if(target == "min") + target = 1 + . = TRUE + else if(target == "max") + target = 20 + . = TRUE + else if(adjust) + target = intensity + adjust + . = TRUE + else if(text2num(target) != null) + target = text2num(target) + . = TRUE + if(.) + target = round(target) + intensity = clamp(target, 1, 20) + if("radwavelength") + var/target = params["target"] + var/adjust = text2num(params["adjust"]) + if(target == "min") + target = 0 + . = TRUE + else if(target == "max") + target = 120 + . = TRUE + else if(adjust) + target = wavelength + adjust + . = TRUE + else if(text2num(target) != null) + target = text2num(target) + . = TRUE + if(.) + target = round(target) + wavelength = clamp(target, 0, 120) /obj/item/shadowcloak name = "cloaker belt" diff --git a/code/game/objects/items/devices/transfer_valve.dm b/code/game/objects/items/devices/transfer_valve.dm index c791b7e323..32d9c02a27 100644 --- a/code/game/objects/items/devices/transfer_valve.dm +++ b/code/game/objects/items/devices/transfer_valve.dm @@ -188,11 +188,10 @@ tank_one.air_contents.merge(temp) tank_two.air_contents.set_volume(tank_two.air_contents.return_volume() - tank_one.air_contents.return_volume()) - /* +/* Exadv1: I know this isn't how it's going to work, but this was just to check it explodes properly when it gets a signal (and it does). - */ - +*/ /obj/item/transfer_valve/proc/toggle_valve() if(!valve_open && tank_one && tank_two) valve_open = TRUE @@ -233,16 +232,20 @@ valve_open = FALSE update_icon() -// this doesn't do anything but the timer etc. expects it to be here -// eventually maybe have it update icon to show state (timer, prox etc.) like old bombs +/* + This doesn't do anything but the timer etc. expects it to be here + eventually maybe have it update icon to show state (timer, prox etc.) like old bombs +*/ /obj/item/transfer_valve/proc/c_state() return -/obj/item/transfer_valve/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ - datum/tgui/master_ui = null, datum/ui_state/state = GLOB.hands_state) - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) +/obj/item/transfer_valve/ui_state(mob/user) + return GLOB.hands_state + +/obj/item/transfer_valve/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) if(!ui) - ui = new(user, src, ui_key, "TransferValve", name, ui_x, ui_y, master_ui, state) + ui = new(user, src, "TransferValve", name) ui.open() /obj/item/transfer_valve/ui_data(mob/user) diff --git a/code/game/objects/items/dualsaber.dm b/code/game/objects/items/dualsaber.dm index 9db9449fcb..cf5c3d4fc5 100644 --- a/code/game/objects/items/dualsaber.dm +++ b/code/game/objects/items/dualsaber.dm @@ -51,6 +51,10 @@ // no attacking while blocking block_lock_attacking = TRUE block_projectile_mitigation = 75 + // more efficient vs projectiles + block_stamina_efficiency_override = list( + TEXT_ATTACK_TYPE_PROJECTILE = 4 + ) parry_time_windup = 0 parry_time_active = 8 @@ -65,14 +69,20 @@ parry_imperfect_falloff_percent = 10 parry_efficiency_to_counterattack = 100 parry_efficiency_considered_successful = 25 // VERY generous - parry_efficiency_perfect = 90 parry_failed_stagger_duration = 3 SECONDS parry_failed_clickcd_duration = CLICK_CD_MELEE - // more efficient vs projectiles - block_stamina_efficiency_override = list( - TEXT_ATTACK_TYPE_PROJECTILE = 4 - ) +/obj/item/dualsaber/active_block(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return, override_direction) + if((attack_type & ATTACK_TYPE_PROJECTILE) && is_energy_reflectable_projectile(object)) + block_return[BLOCK_RETURN_REDIRECT_METHOD] = REDIRECT_METHOD_RETURN_TO_SENDER + return BLOCK_SUCCESS | BLOCK_REDIRECTED | BLOCK_SHOULD_REDIRECT + return ..() + +/obj/item/dualsaber/on_active_parry(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, list/block_return, parry_efficiency, parry_time) + . = ..() + if(parry_efficiency >= 90) // perfect parry + block_return[BLOCK_RETURN_REDIRECT_METHOD] = REDIRECT_METHOD_RETURN_TO_SENDER + . |= BLOCK_SHOULD_REDIRECT /obj/item/dualsaber/Initialize() . = ..() @@ -342,12 +352,30 @@ name = "divine lightblade" desc = "A giant blade of bright and holy light, said to cut down the wicked with ease." force = 5 - block_chance = 50 armour_penetration = 0 + block_parry_data = /datum/block_parry_data/chaplain var/chaplain_spawnable = TRUE can_reflect = FALSE obj_flags = UNIQUE_RENAME +/datum/block_parry_data/chaplain + parry_stamina_cost = 12 + parry_time_windup = 2 + parry_time_active = 5 + parry_time_spindown = 3 + // parry_flags = PARRY_DEFAULT_HANDLE_FEEDBACK + parry_time_perfect = 1 + parry_time_perfect_leeway = 1 + parry_imperfect_falloff_percent = 7.5 + parry_efficiency_to_counterattack = 100 + parry_efficiency_considered_successful = 80 + parry_efficiency_perfect = 120 + parry_efficiency_perfect_override = list( + TEXT_ATTACK_TYPE_PROJECTILE = 30, + ) + parry_failed_stagger_duration = 3 SECONDS + parry_failed_clickcd_duration = 2 SECONDS + /obj/item/dualsaber/hypereutactic/chaplain/ComponentInitialize() . = ..() AddComponent(/datum/component/two_handed, force_unwielded=5, force_wielded=20, \ diff --git a/code/game/objects/items/eightball.dm b/code/game/objects/items/eightball.dm index dbc4c297ca..0d5c9a22aa 100644 --- a/code/game/objects/items/eightball.dm +++ b/code/game/objects/items/eightball.dm @@ -192,11 +192,13 @@ return top_vote -/obj/item/toy/eightball/haunted/ui_interact(mob/user, ui_key="main", datum/tgui/ui=null, force_open=0, datum/tgui/master_ui=null, datum/ui_state/state = GLOB.always_state) +/obj/item/toy/eightball/haunted/ui_state(mob/user) + return GLOB.observer_state - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) +/obj/item/toy/eightball/haunted/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) if(!ui) - ui = new(user, src, ui_key, "EightBallVote", name, 400, 600, master_ui, state) + ui = new(user, src, "EightBallVote", name) ui.open() /obj/item/toy/eightball/haunted/ui_data(mob/user) diff --git a/code/game/objects/items/granters.dm b/code/game/objects/items/granters.dm index 609cc3b719..979fa7e958 100644 --- a/code/game/objects/items/granters.dm +++ b/code/game/objects/items/granters.dm @@ -253,7 +253,7 @@ user.set_nutrition(NUTRITION_LEVEL_STARVING + 50) /obj/item/book/granter/spell/blind - spell = /obj/effect/proc_holder/spell/targeted/trigger/blind + spell = /obj/effect/proc_holder/spell/pointed/trigger/blind spellname = "blind" icon_state ="bookblind" desc = "This book looks blurry, no matter how you look at it." @@ -265,7 +265,7 @@ user.blind_eyes(10) /obj/item/book/granter/spell/mindswap - spell = /obj/effect/proc_holder/spell/targeted/mind_transfer + spell = /obj/effect/proc_holder/spell/pointed/mind_transfer spellname = "mindswap" icon_state ="bookmindswap" desc = "This book's cover is pristine, though its pages look ragged and torn." @@ -289,7 +289,7 @@ if(stored_swap == user) to_chat(user,"You stare at the book some more, but there doesn't seem to be anything else to learn...") return - var/obj/effect/proc_holder/spell/targeted/mind_transfer/swapper = new + var/obj/effect/proc_holder/spell/pointed/mind_transfer/swapper = new if(swapper.cast(list(stored_swap), user, TRUE, TRUE)) to_chat(user,"You're suddenly somewhere else... and someone else?!") to_chat(stored_swap,"Suddenly you're staring at [src] again... where are you, who are you?!") @@ -324,7 +324,7 @@ user.DefaultCombatKnockdown(40) /obj/item/book/granter/spell/barnyard - spell = /obj/effect/proc_holder/spell/targeted/barnyardcurse + spell = /obj/effect/proc_holder/spell/pointed/barnyardcurse spellname = "barnyard" icon_state ="bookhorses" desc = "This book is more horse than your mind has room for." diff --git a/code/game/objects/items/grenades/plastic.dm b/code/game/objects/items/grenades/plastic.dm index a2b0e3edd4..014487332c 100644 --- a/code/game/objects/items/grenades/plastic.dm +++ b/code/game/objects/items/grenades/plastic.dm @@ -60,7 +60,8 @@ if(target) if(!QDELETED(target)) location = get_turf(target) - target.cut_overlay(plastic_overlay, TRUE) + target.cut_overlay(plastic_overlay) + UnregisterSignal(target, COMSIG_ATOM_UPDATE_OVERLAYS, .proc/add_plastic_overlay) if(!ismob(target) || full_damage_on_mobs) target.ex_act(EXPLODE_HEAVY, target) else @@ -126,13 +127,17 @@ I.embedding["embed_chance"] = 0 I.updateEmbedding() - target.add_overlay(plastic_overlay, TRUE) + RegisterSignal(target, COMSIG_ATOM_UPDATE_OVERLAYS, .proc/add_plastic_overlay) + target.update_icon() if(!nadeassembly) to_chat(user, "You plant the bomb. Timer counting down from [det_time].") addtimer(CALLBACK(src, .proc/prime), det_time*10) else qdel(src) //How? +/obj/item/grenade/plastic/proc/add_plastic_overlay(atom/source, list/overlay_list) + overlay_list += plastic_overlay + /obj/item/grenade/plastic/proc/shout_syndicate_crap(mob/M) if(!M) return diff --git a/code/game/objects/items/implants/implant_misc.dm b/code/game/objects/items/implants/implant_misc.dm index 897cb9b750..08d6a586c8 100644 --- a/code/game/objects/items/implants/implant_misc.dm +++ b/code/game/objects/items/implants/implant_misc.dm @@ -47,7 +47,7 @@ /obj/item/implant/warp/activate() . = ..() uses-- - imp_in.do_adrenaline(150, TRUE, 0, 0, TRUE, list(/datum/reagent/fermi/eigenstate = 1.2), "You feel an internal prick as as the bluespace starts ramping up!") + imp_in.do_adrenaline(20, TRUE, 0, 0, TRUE, list(/datum/reagent/fermi/eigenstate = 1.2), "You feel an internal prick as as the bluespace starts ramping up!") to_chat(imp_in, "You feel an internal prick as as the bluespace starts ramping up!") if(!uses) qdel(src) @@ -86,4 +86,4 @@ healthstring = "Oxygen Deprivation Damage => [round(L.getOxyLoss())]
Fire Damage => [round(L.getFireLoss())]
Toxin Damage => [round(L.getToxLoss())]
Brute Force Damage => [round(L.getBruteLoss())]
" if (!healthstring) healthstring = "ERROR" - return healthstring \ No newline at end of file + return healthstring diff --git a/code/game/objects/items/implants/implant_radio.dm b/code/game/objects/items/implants/implant_radio.dm index 5d3d579a4e..6f42547004 100644 --- a/code/game/objects/items/implants/implant_radio.dm +++ b/code/game/objects/items/implants/implant_radio.dm @@ -10,7 +10,7 @@ /obj/item/implant/radio/activate() . = ..() // needs to be GLOB.deep_inventory_state otherwise it won't open - radio.ui_interact(usr, "main", null, FALSE, null, GLOB.deep_inventory_state) + radio.ui_interact(usr, state = GLOB.deep_inventory_state) /obj/item/implant/radio/implant(mob/living/target, mob/user, silent = FALSE) . = ..() diff --git a/code/game/objects/items/implants/implant_uplink.dm b/code/game/objects/items/implants/implant_uplink.dm index 9895c1e34c..0cac8f838a 100644 --- a/code/game/objects/items/implants/implant_uplink.dm +++ b/code/game/objects/items/implants/implant_uplink.dm @@ -9,7 +9,7 @@ /obj/item/implant/uplink/Initialize(mapload, _owner) . = ..() - AddComponent(/datum/component/uplink, _owner, TRUE, FALSE, null, starting_tc, GLOB.not_incapacitated_state) + AddComponent(/datum/component/uplink, _owner, TRUE, FALSE, null, starting_tc) /obj/item/implanter/uplink name = "implanter (uplink)" diff --git a/code/game/objects/items/implants/implantchair.dm b/code/game/objects/items/implants/implantchair.dm index b3c1f79e94..7b05cf302e 100644 --- a/code/game/objects/items/implants/implantchair.dm +++ b/code/game/objects/items/implants/implantchair.dm @@ -26,14 +26,15 @@ open_machine() update_icon() +/obj/machinery/implantchair/ui_state(mob/user) + return GLOB.notcontained_state -/obj/machinery/implantchair/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.notcontained_state) - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) +/obj/machinery/implantchair/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) if(!ui) - ui = new(user, src, ui_key, "implantchair", name, 375, 280, master_ui, state) + ui = new(user, src, "ImplantChair", name) ui.open() - /obj/machinery/implantchair/ui_data() var/list/data = list() data["occupied"] = occupant ? 1 : 0 diff --git a/code/game/objects/items/pet_carrier.dm b/code/game/objects/items/pet_carrier.dm index c6b5a7e224..a4b12dd629 100644 --- a/code/game/objects/items/pet_carrier.dm +++ b/code/game/objects/items/pet_carrier.dm @@ -240,7 +240,31 @@ custom_materials = list(/datum/material/glass = 1000, /datum/material/bluespace = 600) escape_time = 200 //equal to the time of a bluespace bodybag alternate_escape_time = 100 + + ///gas supply for simplemobs so they don't die var/datum/gas_mixture/occupant_gas_supply + ///level until the reagent gets INGEST ed instead of TOUCH + var/sipping_level = 150 + ///prob50 level of sipping + var/sipping_probably = 99 + ///chem transfer rate / second + var/transfer_rate = 5 + +/obj/item/pet_carrier/bluespace/Initialize() + . = ..() + create_reagents(300, OPENCONTAINER, DEFAULT_REAGENTS_VALUE) //equivalent of bsbeakers + +/obj/item/pet_carrier/bluespace/Destroy() + STOP_PROCESSING(SSobj, src) + return ..() + +/obj/item/pet_carrier/bluespace/attack_self(mob/living/user) + ..() + if(reagents) + if(open) + reagents.reagents_holder_flags = OPENCONTAINER + else + reagents.reagents_holder_flags = NONE /obj/item/pet_carrier/bluespace/update_icon_state() if(open) @@ -248,11 +272,28 @@ else icon_state = "bluespace_jar" -/obj/item/pet_carrier/bluespace/throw_impact() +/obj/item/pet_carrier/bluespace/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum) . = ..() //delete the item upon impact, releasing the creature inside (this is handled by its deletion) if(occupants.len) loc.visible_message("The bluespace jar smashes, releasing [occupants[1]]!") + + if(reagents?.total_volume && ismob(hit_atom) && hit_atom.reagents) + reagents.total_volume *= rand(5,10) * 0.1 //Not all of it makes contact with the target + var/mob/M = hit_atom + var/R = reagents.log_list() + hit_atom.visible_message("[M] has been splashed with something!", \ + "[M] has been splashed with something!") + var/turf/TT = get_turf(hit_atom) + var/throwerstring + if(thrownby) + log_combat(thrownby, M, "splashed", R) + var/turf/AT = get_turf(thrownby) + throwerstring = " THROWN BY [key_name(thrownby)] at [AT] (AREACOORD(AT)]" + log_reagent("SPLASH: [src] mob throw_impact() onto [key_name(hit_atom)] at [TT] ([AREACOORD(TT)])[throwerstring] - [R]") + reagents.reaction(hit_atom, TOUCH) + reagents.clear_reagents() + playsound(src, "shatter", 70, 1) qdel(src) @@ -260,21 +301,24 @@ . = ..() if(!occupant_gas_supply) occupant_gas_supply = new + if(isanimal(occupant)) var/mob/living/simple_animal/animal = occupant occupant_gas_supply[/datum/gas/oxygen] = 0.0064 //make sure it has some gas in so it isn't depressurized occupant_gas_supply.set_temperature(animal.minbodytemp) //simple animals only care about temperature/pressure when their turf isnt a location - else - if(ishuman(occupant)) //humans require resistance to cold/heat and living in no air while inside, and lose this when outside - ADD_TRAIT(occupant, TRAIT_RESISTCOLD, "bluespace_container_cold_resist") - ADD_TRAIT(occupant, TRAIT_RESISTHEAT, "bluespace_container_heat_resist") - ADD_TRAIT(occupant, TRAIT_NOBREATH, "bluespace_container_no_breath") - ADD_TRAIT(occupant, TRAIT_RESISTHIGHPRESSURE, "bluespace_container_resist_high_pressure") - ADD_TRAIT(occupant, TRAIT_RESISTLOWPRESSURE, "bluespace_container_resist_low_pressure") + + if(ishuman(occupant)) //humans require resistance to cold/heat and living in no air while inside, and lose this when outside + START_PROCESSING(SSobj, src) + ADD_TRAIT(occupant, TRAIT_RESISTCOLD, "bluespace_container_cold_resist") + ADD_TRAIT(occupant, TRAIT_RESISTHEAT, "bluespace_container_heat_resist") + ADD_TRAIT(occupant, TRAIT_NOBREATH, "bluespace_container_no_breath") + ADD_TRAIT(occupant, TRAIT_RESISTHIGHPRESSURE, "bluespace_container_resist_high_pressure") + ADD_TRAIT(occupant, TRAIT_RESISTLOWPRESSURE, "bluespace_container_resist_low_pressure") /obj/item/pet_carrier/bluespace/remove_occupant(mob/living/occupant) . = ..() if(ishuman(occupant)) + STOP_PROCESSING(SSobj, src) REMOVE_TRAIT(occupant, TRAIT_RESISTCOLD, "bluespace_container_cold_resist") REMOVE_TRAIT(occupant, TRAIT_RESISTHEAT, "bluespace_container_heat_resist") REMOVE_TRAIT(occupant, TRAIT_NOBREATH, "bluespace_container_no_breath") @@ -287,6 +331,18 @@ occupant_gas_supply = new return occupant_gas_supply +/obj/item/pet_carrier/bluespace/process() + if(!reagents) + return + for(var/mob/living/L in occupants) + if(!ishuman(L)) + continue + if((reagents.total_volume >= sipping_level) || ((reagents.total_volume >= sipping_probably) && prob(50))) //sipp + reagents.reaction(L, INGEST) //consume + reagents.trans_to(L, transfer_rate) + else + reagents.reaction(L, TOUCH, show_message = FALSE) + /obj/item/pet_carrier/bluespace/load_occupant(mob/living/user, mob/living/target) if(..()) name = "[initial(name)] ([target])" diff --git a/code/game/objects/items/plushes.dm b/code/game/objects/items/plushes.dm index 44205f4884..a3da49ed89 100644 --- a/code/game/objects/items/plushes.dm +++ b/code/game/objects/items/plushes.dm @@ -688,6 +688,18 @@ GLOBAL_LIST_INIT(valid_plushie_paths, valid_plushie_paths()) icon_state = "scrubpuppy" item_state = "scrubpuppy" +/obj/item/toy/plush/borgplushie/meddrake + name = "MediDrake Plushie" + desc = "An adorable stuffed toy of a Medidrake." + icon_state = "meddrake" + item_state = "meddrake" + +/obj/item/toy/plush/borgplushie/secdrake + name = "SecDrake Plushie" + desc = "An adorable stuffed toy of a Secdrake." + icon_state = "secdrake" + item_state = "secdrake" + /obj/item/toy/plush/aiplush name = "AI plushie" desc = "A little stuffed toy AI core... it appears to be malfunctioning." diff --git a/code/game/objects/items/robot/robot_upgrades.dm b/code/game/objects/items/robot/robot_upgrades.dm index c50dc6e316..80fd177d84 100644 --- a/code/game/objects/items/robot/robot_upgrades.dm +++ b/code/game/objects/items/robot/robot_upgrades.dm @@ -6,21 +6,24 @@ desc = "Protected by FRM." icon = 'icons/obj/module.dmi' icon_state = "cyborg_upgrade" + w_class = WEIGHT_CLASS_SMALL var/locked = FALSE var/installed = 0 var/require_module = 0 var/list/module_type + /// Bitflags listing module compatibility. Used in the exosuit fabricator for creating sub-categories. + var/module_flags = NONE // if true, is not stored in the robot to be ejected // if module is reset var/one_use = FALSE /obj/item/borg/upgrade/proc/action(mob/living/silicon/robot/R, user = usr) if(R.stat == DEAD) - to_chat(user, "[src] will not function on a deceased cyborg.") + to_chat(user, "[src] will not function on a deceased cyborg.") return FALSE if(module_type && !is_type_in_list(R.module, module_type)) - to_chat(R, "Upgrade mounting error! No suitable hardpoint detected!") - to_chat(user, "There's no mounting point for the module!") + to_chat(R, "Upgrade mounting error! No suitable hardpoint detected.") + to_chat(user, "There's no mounting point for the module!") return FALSE return TRUE @@ -37,7 +40,7 @@ one_use = TRUE /obj/item/borg/upgrade/rename/attack_self(mob/user) - heldname = stripped_input(user, "Enter new robot name", "Cyborg Reclassification", heldname, MAX_NAME_LEN) + heldname = sanitize_name(stripped_input(user, "Enter new robot name", "Cyborg Reclassification", heldname, MAX_NAME_LEN)) /obj/item/borg/upgrade/rename/action(mob/living/silicon/robot/R) . = ..() @@ -95,6 +98,7 @@ desc = "Used to cool a mounted energy-based firearm, increasing the potential current in it and thus its recharge rate." icon_state = "cyborg_upgrade3" require_module = 1 + module_flags = BORG_MODULE_SECURITY /obj/item/borg/upgrade/disablercooler/action(mob/living/silicon/robot/R, user = usr) . = ..() @@ -147,6 +151,7 @@ icon_state = "cyborg_upgrade3" require_module = 1 module_type = list(/obj/item/robot_module/miner) + module_flags = BORG_MODULE_MINER /obj/item/borg/upgrade/ddrill/action(mob/living/silicon/robot/R, user = usr) . = ..() @@ -207,6 +212,7 @@ icon_state = "cyborg_upgrade3" require_module = 1 module_type = list(/obj/item/robot_module/butler) + module_flags = BORG_MODULE_JANITOR /obj/item/borg/upgrade/tboh/action(mob/living/silicon/robot/R) . = ..() @@ -234,6 +240,7 @@ icon_state = "cyborg_upgrade3" require_module = 1 module_type = list(/obj/item/robot_module/butler) + module_flags = BORG_MODULE_JANITOR /obj/item/borg/upgrade/amop/action(mob/living/silicon/robot/R) . = ..() @@ -283,6 +290,7 @@ resistance_flags = LAVA_PROOF | FIRE_PROOF require_module = 1 module_type = list(/obj/item/robot_module/miner) + module_flags = BORG_MODULE_MINER /obj/item/borg/upgrade/lavaproof/action(mob/living/silicon/robot/R, user = usr) . = ..() @@ -402,6 +410,7 @@ module_type = list(/obj/item/robot_module/medical, /obj/item/robot_module/syndicate_medical) var/list/additional_reagents = list() + module_flags = BORG_MODULE_MEDICAL /obj/item/borg/upgrade/hypospray/action(mob/living/silicon/robot/R, user = usr) . = ..() @@ -471,6 +480,7 @@ require_module = 1 module_type = list(/obj/item/robot_module/medical, /obj/item/robot_module/syndicate_medical) + module_flags = BORG_MODULE_MEDICAL /obj/item/borg/upgrade/processor/action(mob/living/silicon/robot/R, user = usr) . = ..() @@ -578,6 +588,7 @@ icon_state = "borg_BS_RPED" require_module = TRUE module_type = list(/obj/item/robot_module/engineering, /obj/item/robot_module/saboteur) + module_flags = BORG_MODULE_ENGINEERING /obj/item/borg/upgrade/rped/action(mob/living/silicon/robot/R, user = usr) . = ..() @@ -612,8 +623,8 @@ icon = 'icons/obj/device.dmi' icon_state = "pinpointer_crew" require_module = TRUE - module_type = list(/obj/item/robot_module/medical, - /obj/item/robot_module/syndicate_medical) + module_type = list(/obj/item/robot_module/medical, /obj/item/robot_module/syndicate_medical) + module_flags = BORG_MODULE_MEDICAL /obj/item/borg/upgrade/pinpointer/action(mob/living/silicon/robot/R, user = usr) . = ..() diff --git a/code/game/objects/items/stacks/medical.dm b/code/game/objects/items/stacks/medical.dm index 6b6e9d7d65..7ba2196184 100644 --- a/code/game/objects/items/stacks/medical.dm +++ b/code/game/objects/items/stacks/medical.dm @@ -115,18 +115,20 @@ /obj/item/stack/medical/gauze name = "medical gauze" - desc = "A roll of elastic cloth, perfect for stabilizing all kinds of wounds, from cuts and burns, to broken bones. " + desc = "A roll of elastic cloth, perfect for stabilizing all kinds of wounds, from cuts and burns to broken bones." gender = PLURAL singular_name = "medical gauze" icon_state = "gauze" heal_brute = 5 self_delay = 50 other_delay = 20 - amount = 6 + amount = 10 + max_amount = 10 absorption_rate = 0.25 absorption_capacity = 5 splint_factor = 0.35 custom_price = PRICE_REALLY_CHEAP + grind_results = list(/datum/reagent/cellulose = 2) // gauze is only relevant for wounds, which are handled in the wounds themselves /obj/item/stack/medical/gauze/try_heal(mob/living/M, mob/user, silent) @@ -170,6 +172,14 @@ "You cut [src] into pieces of cloth with [I].", \ "You hear cutting.") use(2) + else if(I.is_drainable() && I.reagents.has_reagent(/datum/reagent/space_cleaner/sterilizine)) + if(!I.reagents.has_reagent(/datum/reagent/space_cleaner/sterilizine, 10)) + to_chat(user, "There's not enough sterilizine in [I] to sterilize [src]!") + return + user.visible_message("[user] pours the contents of [I] onto [src], sterilizing it.", "You pour the contents of [I] onto [src], sterilizing it.") + I.reagents.remove_reagent(/datum/reagent/space_cleaner/sterilizine, 10) + new /obj/item/stack/medical/gauze/adv/one(user.drop_location()) + use(1) else return ..() @@ -181,7 +191,7 @@ name = "improvised gauze" singular_name = "improvised gauze" heal_brute = 0 - desc = "A roll of cloth roughly cut from something that does a decent job of stabilizing wounds, but less efficiently so than real medical gauze." + desc = "A roll of cloth roughly cut from something that does a decent job of stabilizing wounds, but less efficiently than real medical gauze." self_delay = 60 other_delay = 30 absorption_rate = 0.15 @@ -189,9 +199,13 @@ /obj/item/stack/medical/gauze/adv name = "sterilized medical gauze" - desc = "A roll of elastic sterilized cloth that is extremely effective at stopping bleeding, heals minor wounds and cleans them." singular_name = "sterilized medical gauze" - self_delay = 5 + desc = "A roll of elastic sterilized cloth that is extremely effective at stopping bleeding and covering burns." + heal_brute = 6 + self_delay = 45 + other_delay = 15 + absorption_rate = 0.4 + absorption_capacity = 6 /obj/item/stack/medical/gauze/adv/one amount = 1 @@ -209,8 +223,8 @@ icon_state = "suture" self_delay = 30 other_delay = 10 - amount = 10 - max_amount = 10 + amount = 15 + max_amount = 15 repeating = TRUE heal_brute = 10 stop_bleeding = 0.6 @@ -226,6 +240,9 @@ /obj/item/stack/medical/suture/one amount = 1 +/obj/item/stack/medical/suture/five + amount = 5 + /obj/item/stack/medical/suture/medicated name = "medicated suture" icon_state = "suture_purp" @@ -264,8 +281,8 @@ icon_state = "ointment" lefthand_file = 'icons/mob/inhands/equipment/medical_lefthand.dmi' righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi' - amount = 10 - max_amount = 10 + amount = 12 + max_amount = 12 self_delay = 40 other_delay = 20 @@ -295,8 +312,8 @@ self_delay = 30 other_delay = 10 amount = 15 - heal_burn = 10 max_amount = 15 + heal_burn = 10 repeating = TRUE sanitization = 0.75 flesh_regeneration = 3 @@ -306,6 +323,9 @@ /obj/item/stack/medical/mesh/one amount = 1 +/obj/item/stack/medical/mesh/five + amount = 5 + /obj/item/stack/medical/mesh/advanced name = "advanced regenerative mesh" desc = "An advanced mesh made with aloe extracts and sterilizing chemicals, used to treat burns." diff --git a/code/game/objects/items/stacks/sheets/sheet_types.dm b/code/game/objects/items/stacks/sheets/sheet_types.dm index 5f6341ea21..645051b7c2 100644 --- a/code/game/objects/items/stacks/sheets/sheet_types.dm +++ b/code/game/objects/items/stacks/sheets/sheet_types.dm @@ -412,6 +412,7 @@ GLOBAL_LIST_INIT(cloth_recipes, list ( \ force = 0 throwforce = 0 merge_type = /obj/item/stack/sheet/cloth + grind_results = list(/datum/reagent/cellulose = 2) /obj/item/stack/sheet/cloth/get_main_recipes() . = ..() @@ -672,6 +673,10 @@ GLOBAL_LIST_INIT(brass_recipes, list ( \ GLOBAL_LIST_INIT(bronze_recipes, list ( \ new/datum/stack_recipe("wall gear", /obj/structure/girder/bronze, 2, time = 20, one_per_turf = TRUE, on_floor = TRUE), \ null, + new/datum/stack_recipe("directional bronze window", /obj/structure/window/bronze/unanchored, time = 0, on_floor = TRUE, window_checks = TRUE), \ + new/datum/stack_recipe("fulltile bronze window", /obj/structure/window/bronze/fulltile/unanchored, 2, time = 0, on_floor = TRUE, window_checks = TRUE), \ + new/datum/stack_recipe("pinion airlock assembly", /obj/structure/door_assembly/door_assembly_bronze, 4, time = 50, one_per_turf = TRUE, on_floor = TRUE), \ + new/datum/stack_recipe("bronze pinion airlock assembly", /obj/structure/door_assembly/door_assembly_bronze/seethru, 4, time = 50, one_per_turf = TRUE, on_floor = TRUE), \ new/datum/stack_recipe("bronze hat", /obj/item/clothing/head/bronze), \ new/datum/stack_recipe("bronze suit", /obj/item/clothing/suit/bronze), \ new/datum/stack_recipe("bronze boots", /obj/item/clothing/shoes/bronze), \ @@ -679,9 +684,10 @@ GLOBAL_LIST_INIT(bronze_recipes, list ( \ new/datum/stack_recipe("bronze chair", /obj/structure/chair/bronze, 1, time = 0, one_per_turf = TRUE, on_floor = TRUE), \ new/datum/stack_recipe("bronze bar stool", /obj/structure/chair/stool/bar/bronze, 1, time = 0, one_per_turf = TRUE, on_floor = TRUE), \ new/datum/stack_recipe("bronze stool", /obj/structure/chair/stool/bronze, 1, time = 0, one_per_turf = TRUE, on_floor = TRUE), \ + new /datum/stack_recipe("bronze floor tiles", /obj/item/stack/tile/bronze, 1, 4, 20), \ )) -/obj/item/stack/tile/bronze +/obj/item/stack/sheet/bronze name = "brass" desc = "On closer inspection, what appears to be wholly-unsuitable-for-building brass is actually more structurally stable bronze." singular_name = "bronze sheet" @@ -690,27 +696,21 @@ GLOBAL_LIST_INIT(bronze_recipes, list ( \ icon = 'icons/obj/stack_objects.dmi' custom_materials = list(/datum/material/bronze = MINERAL_MATERIAL_AMOUNT) resistance_flags = FIRE_PROOF | ACID_PROOF - throwforce = 10 - max_amount = 50 - throw_speed = 1 - throw_range = 3 - turf_type = /turf/open/floor/bronze - novariants = FALSE grind_results = list(/datum/reagent/iron = 5, /datum/reagent/copper = 3) //we have no "tin" reagent so this is the closest thing - merge_type = /obj/item/stack/tile/bronze + merge_type = /obj/item/stack/sheet/bronze tableVariant = /obj/structure/table/bronze material_type = /datum/material/bronze -/obj/item/stack/tile/bronze/attack_self(mob/living/user) +/obj/item/stack/sheet/bronze/attack_self(mob/living/user) if(is_servant_of_ratvar(user)) //still lets them build with it, just gives a message to_chat(user, "Wha... what is this cheap imitation crap? This isn't brass at all!") ..() -/obj/item/stack/tile/bronze/get_main_recipes() +/obj/item/stack/sheet/bronze/get_main_recipes() . = ..() . += GLOB.bronze_recipes -/obj/item/stack/tile/bronze/thirty +/obj/item/stack/sheet/bronze/thirty amount = 30 /* @@ -774,6 +774,7 @@ GLOBAL_LIST_INIT(plastic_recipes, list( new /datum/stack_recipe("water bottle", /obj/item/reagent_containers/glass/beaker/waterbottle/empty), \ new /datum/stack_recipe("large water bottle", /obj/item/reagent_containers/glass/beaker/waterbottle/large/empty,3), \ new /datum/stack_recipe("shower curtain", /obj/structure/curtain, 10, time = 10, one_per_turf = 1, on_floor = 1), \ + new /datum/stack_recipe("duct", /obj/item/stack/ducts,1), \ new /datum/stack_recipe("laser pointer case", /obj/item/glasswork/glass_base/laserpointer_shell, 30), \ new /datum/stack_recipe("wet floor sign", /obj/item/caution, 2))) @@ -842,6 +843,7 @@ new /datum/stack_recipe("paper frame door", /obj/structure/mineral_door/paperfra merge_type = /obj/item/stack/sheet/cotton var/pull_effort = 30 var/loom_result = /obj/item/stack/sheet/cloth + grind_results = list(/datum/reagent/cellulose = 5) /obj/item/stack/sheet/cotton/ten amount = 10 @@ -857,6 +859,7 @@ new /datum/stack_recipe("paper frame door", /obj/structure/mineral_door/paperfra merge_type = /obj/item/stack/sheet/cotton/durathread pull_effort = 70 loom_result = /obj/item/stack/sheet/durathread + grind_results = list(/datum/reagent/cellulose = 10) /obj/item/stack/sheet/meat name = "meat sheets" diff --git a/code/game/objects/items/stacks/tiles/tile_types.dm b/code/game/objects/items/stacks/tiles/tile_types.dm index 13fca1e8fe..0d85e897d2 100644 --- a/code/game/objects/items/stacks/tiles/tile_types.dm +++ b/code/game/objects/items/stacks/tiles/tile_types.dm @@ -513,3 +513,12 @@ icon_state = "material_tile" turf_type = /turf/open/floor/material material_flags = MATERIAL_ADD_PREFIX | MATERIAL_COLOR | MATERIAL_AFFECT_STATISTICS + +/obj/item/stack/tile/bronze + name = "bronze tile" + singular_name = "bronze floor tile" + desc = "A tile made out of bronze. Looks like clockwork." + icon_state = "material_tile" + color = "#92661A" + turf_type = /turf/open/floor/bronze + custom_materials = list(/datum/material/bronze = 250) diff --git a/code/game/objects/items/storage/belt.dm b/code/game/objects/items/storage/belt.dm index 3c554aa58e..0001494fdd 100755 --- a/code/game/objects/items/storage/belt.dm +++ b/code/game/objects/items/storage/belt.dm @@ -478,7 +478,7 @@ /obj/item/assembly/signaler, /obj/item/lightreplacer, /obj/item/rcd_ammo, - /obj/item/construction/rcd, + /obj/item/construction, /obj/item/pipe_dispenser, /obj/item/stack/rods, /obj/item/stack/tile/plasteel, @@ -492,7 +492,7 @@ icon_state = "grenadebeltnew" item_state = "security" rad_flags = RAD_PROTECT_CONTENTS | RAD_NO_CONTAMINATE - + /obj/item/storage/belt/grenade/ComponentInitialize() . = ..() var/datum/component/storage/STR = GetComponent(/datum/component/storage) diff --git a/code/game/objects/items/storage/book.dm b/code/game/objects/items/storage/book.dm index 7532aacbfa..28850e79a2 100644 --- a/code/game/objects/items/storage/book.dm +++ b/code/game/objects/items/storage/book.dm @@ -47,41 +47,58 @@ GLOBAL_LIST_INIT(bibleitemstates, list("bible", "koran", "scrapbook", "bible", user.visible_message("[user] is offering [user.p_them()]self to [deity_name]! It looks like [user.p_theyre()] trying to commit suicide!") return (BRUTELOSS) -/obj/item/storage/book/bible/attack_self(mob/living/carbon/human/H) - if(!istype(H)) +/obj/item/storage/book/bible/attack_self(mob/living/carbon/human/user) + if(!istype(user)) return - // If H is the Chaplain, we can set the icon_state of the bible (but only once!) - if(!GLOB.bible_icon_state && H.job == "Chaplain") - var/dat = "Pick Bible Style

Pick a bible style

" - for(var/i in 1 to GLOB.biblestates.len) - var/icon/bibleicon = icon('icons/obj/storage.dmi', GLOB.biblestates[i]) - var/nicename = GLOB.biblenames[i] - H << browse_rsc(bibleicon, nicename) - dat += {""} - dat += "
[nicename]
" - H << browse(dat, "window=editicon;can_close=0;can_minimize=0;size=250x650") + if(GLOB.bible_icon_state) // if there is already a bible icon return FALSE + return FALSE + if(user.job != "Chaplain") // if the user is not the chaplain, return FALSE + return FALSE -/obj/item/storage/book/bible/Topic(href, href_list) - if(!usr.canUseTopic(src)) - return - if(href_list["seticon"] && GLOB && !GLOB.bible_icon_state) - var/iconi = text2num(href_list["seticon"]) - var/biblename = GLOB.biblenames[iconi] - var/obj/item/storage/book/bible/B = locate(href_list["src"]) - B.icon_state = GLOB.biblestates[iconi] - B.item_state = GLOB.bibleitemstates[iconi] + var/list/skins = list() + for(var/i in 1 to GLOB.biblestates.len) + var/image/bible_image = image(icon = 'icons/obj/storage.dmi', icon_state = GLOB.biblestates[i]) + skins += list("[GLOB.biblenames[i]]" = bible_image) - if(B.icon_state == "honk1" || B.icon_state == "honk2") - var/mob/living/carbon/human/H = usr - H.dna.add_mutation(CLOWNMUT) - H.dna.add_mutation(SMILE) - H.equip_to_slot_or_del(new /obj/item/clothing/mask/gas/clown_hat(H), SLOT_WEAR_MASK) + var/choice = show_radial_menu(user, src, skins, custom_check = CALLBACK(src, .proc/check_menu, user), radius = 40, require_near = TRUE) + if(!choice) + return FALSE + var/bible_index = GLOB.biblenames.Find(choice) + if(!bible_index) + return FALSE + icon_state = GLOB.biblestates[bible_index] + item_state = GLOB.bibleitemstates[bible_index] - GLOB.bible_icon_state = B.icon_state - GLOB.bible_item_state = B.item_state + if(icon_state == "honk1" || icon_state == "honk2") + var/mob/living/carbon/human/H = usr + H.dna.add_mutation(CLOWNMUT) + H.dna.add_mutation(SMILE) + H.equip_to_slot_or_del(new /obj/item/clothing/mask/gas/clown_hat(H), SLOT_WEAR_MASK) - SSblackbox.record_feedback("text", "religion_book", 1, "[biblename]") - usr << browse(null, "window=editicon") + GLOB.bible_icon_state = icon_state + GLOB.bibleitemstates = item_state + SSblackbox.record_feedback("text", "religion_book", 1, "[choice]") + +/** + * Checks if we are allowed to interact with the radial + * + * Arguements: user The mob interacting with the menu + */ + +/obj/item/storage/book/bible/proc/check_menu(mob/living/carbon/human/user) + if(GLOB.bible_icon_state) + return FALSE + if(!istype(user)) + return FALSE + if(!user.is_holding(src)) + return FALSE + if(!user.can_read(src)) + return FALSE + if(user.incapacitated()) + return FALSE + if(user.job != "Chaplain") + return FALSE + return TRUE /obj/item/storage/book/bible/proc/bless(mob/living/carbon/human/H, mob/living/user) for(var/X in H.bodyparts) diff --git a/code/game/objects/items/storage/toolbox.dm b/code/game/objects/items/storage/toolbox.dm index ed0ee8ad07..a6b34c59e3 100644 --- a/code/game/objects/items/storage/toolbox.dm +++ b/code/game/objects/items/storage/toolbox.dm @@ -245,19 +245,20 @@ GLOBAL_LIST_EMPTY(rubber_toolbox_icons) new /obj/item/stack/cable_coil/white(src) /obj/item/storage/toolbox/ammo - name = "ammo box" - desc = "It contains a few clips." + name = "ammunition case (7.62mm stripper clips)" + desc = "It contains a few 7.62 stripper clips." icon_state = "ammobox" item_state = "ammobox" + var/ammotype = /obj/item/ammo_box/a762 // make sure this is a typepath thanks /obj/item/storage/toolbox/ammo/PopulateContents() - new /obj/item/ammo_box/a762(src) - new /obj/item/ammo_box/a762(src) - new /obj/item/ammo_box/a762(src) - new /obj/item/ammo_box/a762(src) - new /obj/item/ammo_box/a762(src) - new /obj/item/ammo_box/a762(src) - new /obj/item/ammo_box/a762(src) + for (var/i = 0, i < 7, i++) + new ammotype(src) + +/obj/item/storage/toolbox/ammo/surplus + name = "ammunition case (10mm rifle magazines)" + desc = "It contains a few 10mm rifle magazines." + ammotype = /obj/item/ammo_box/magazine/m10mm/rifle /obj/item/storage/toolbox/infiltrator name = "insidious case" diff --git a/code/game/objects/items/storage/uplink_kits.dm b/code/game/objects/items/storage/uplink_kits.dm index 4f65a4597e..442228ef31 100644 --- a/code/game/objects/items/storage/uplink_kits.dm +++ b/code/game/objects/items/storage/uplink_kits.dm @@ -335,6 +335,7 @@ new /obj/item/reagent_containers/glass/bottle/romerol(src) new /obj/item/reagent_containers/syringe(src) new /obj/item/reagent_containers/dropper(src) + new /obj/item/paper/guides/antag/romerol_instructions(src) /obj/item/storage/box/syndie_kit/ez_clean/PopulateContents() for(var/i in 1 to 3) diff --git a/code/game/objects/items/tanks/tanks.dm b/code/game/objects/items/tanks/tanks.dm index 2de5860794..08b91332ef 100644 --- a/code/game/objects/items/tanks/tanks.dm +++ b/code/game/objects/items/tanks/tanks.dm @@ -164,11 +164,13 @@ else . = ..() -/obj/item/tank/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ - datum/tgui/master_ui = null, datum/ui_state/state = GLOB.hands_state) - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) +/obj/item/tank/ui_state(mob/user) + return GLOB.hands_state + +/obj/item/tank/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) if(!ui) - ui = new(user, src, ui_key, "Tank", name, 400, 120, master_ui, state) + ui = new(user, src, "Tank", name) ui.open() /obj/item/tank/ui_data(mob/user) @@ -205,10 +207,6 @@ else if(pressure == "max") pressure = TANK_MAX_RELEASE_PRESSURE . = TRUE - else if(pressure == "input") - pressure = input("New release pressure ([TANK_MIN_RELEASE_PRESSURE]-[TANK_MAX_RELEASE_PRESSURE] kPa):", name, distribute_pressure) as num|null - if(!isnull(pressure) && !..()) - . = TRUE else if(text2num(pressure) != null) pressure = text2num(pressure) . = TRUE diff --git a/code/game/objects/items/teleportation.dm b/code/game/objects/items/teleportation.dm index 881e4d5f1a..f9ede407ca 100644 --- a/code/game/objects/items/teleportation.dm +++ b/code/game/objects/items/teleportation.dm @@ -1,4 +1,3 @@ - #define SOURCE_PORTAL 1 #define DESTINATION_PORTAL 2 @@ -25,90 +24,72 @@ throw_speed = 3 throw_range = 7 custom_materials = list(/datum/material/iron=400) + var/tracking_range = 20 -/obj/item/locator/attack_self(mob/user) - user.set_machine(src) - var/dat - if (temp) - dat = "[temp]

Clear" - else - dat = {" -Persistent Signal Locator
-Refresh"} - user << browse(dat, "window=radio") - onclose(user, "radio") - return +/obj/item/locator/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "BluespaceLocator", name) + ui.open() -/obj/item/locator/Topic(href, href_list) - ..() - if (usr.stat || usr.restrained()) - return - var/turf/current_location = get_turf(usr)//What turf is the user on? - if(!current_location || is_centcom_level(current_location.z))//If turf was not found or they're on CentCom - to_chat(usr, "[src] is malfunctioning.") - return - if(usr.contents.Find(src) || (in_range(src, usr) && isturf(loc))) - usr.set_machine(src) - if (href_list["refresh"]) - temp = "Persistent Signal Locator
" - var/turf/sr = get_turf(src) +/obj/item/locator/ui_data(mob/user) + var/list/data = list() - if (sr) - temp += "Beacon Signals:
" - for(var/obj/item/beacon/W in GLOB.teleportbeacons) - if (!W.renamed) - continue - var/turf/tr = get_turf(W) - if (tr.z == sr.z && tr) - var/direct = max(abs(tr.x - sr.x), abs(tr.y - sr.y)) - if (direct < 5) - direct = "very strong" - else - if (direct < 10) - direct = "strong" - else - if (direct < 20) - direct = "weak" - else - direct = "very weak" - temp += "[W.name]-[dir2text(get_dir(sr, tr))]-[direct]
" + data["trackingrange"] = tracking_range - temp += "Implant Signals:
" - for (var/obj/item/implant/tracking/W in GLOB.tracked_implants) - if (!isliving(W.imp_in)) - continue - var/mob/living/M = W.imp_in - if (M.stat == DEAD) - if (M.timeofdeath + W.lifespan_postmortem < world.time) - continue + // Get our current turf location. + var/turf/sr = get_turf(src) - var/turf/tr = get_turf(M) - if (tr.z == sr.z && tr) - var/direct = max(abs(tr.x - sr.x), abs(tr.y - sr.y)) - if (direct < 20) - if (direct < 5) - direct = "very strong" - else - if (direct < 10) - direct = "strong" - else - direct = "weak" - temp += "[W.imp_in.name]-[dir2text(get_dir(sr, tr))]-[direct]
" + if (sr) + // Check every teleport beacon. + var/list/tele_beacons = list() + for(var/obj/item/beacon/W in GLOB.teleportbeacons) - temp += "You are at \[[sr.x],[sr.y],[sr.z]\] in orbital coordinates.

Refresh
" + // Get the tracking beacon's turf location. + var/turf/tr = get_turf(W) + + // Make sure it's on a turf and that its Z-level matches the tracker's Z-level + if (tr && tr.z == sr.z) + // Get the distance between the beacon's turf and our turf + var/distance = max(abs(tr.x - sr.x), abs(tr.y - sr.y)) + + // If the target is too far away, skip over this beacon. + if(distance > tracking_range) + continue + + var/beacon_name + + if(W.renamed) + beacon_name = W.name + else + var/area/A = get_area(W) + beacon_name = A.name + + var/D = dir2text(get_dir(sr, tr)) + tele_beacons += list(list(name = beacon_name, direction = D, distance = distance)) + + data["telebeacons"] = tele_beacons + + var/list/track_implants = list() + + for (var/obj/item/implant/tracking/W in GLOB.tracked_implants) + if (!W.imp_in || !isliving(W.loc)) + continue else - temp += "Processing Error: Unable to locate orbital position.
" - else - if (href_list["temp"]) - temp = null - if (ismob(src.loc)) - attack_self(src.loc) - else - for(var/mob/M in fov_viewers(1, src)) - if (M.client) - src.attack_self(M) - return + var/mob/living/M = W.loc + if (M.stat == DEAD) + if (M.timeofdeath + W.lifespan_postmortem < world.time) + continue + var/turf/tr = get_turf(W) + var/distance = max(abs(tr.x - sr.x), abs(tr.y - sr.y)) + if(distance > tracking_range) + continue + + var/D = dir2text(get_dir(sr, tr)) + track_implants += list(list(name = W.imp_in.name, direction = D, distance = distance)) + data["trackimplants"] = track_implants + return data /* * Hand-tele @@ -190,13 +171,8 @@ user.show_message("\The [src] is recharging!") return var/atom/T = L[t1] - var/implantcheckmate = FALSE - if(isliving(T)) - var/mob/living/M = T - if(!locate(/obj/item/implant/tracking) in M.implants) //The user was too slow and let the target mob's tracking implant expire or get removed. - implantcheckmate = TRUE var/area/A = get_area(T) - if(A.noteleport || implantcheckmate) + if(A.noteleport) to_chat(user, "\The [src] is malfunctioning.") return current_location = get_turf(user) //Recheck. @@ -205,10 +181,12 @@ to_chat(user, "\The [src] is malfunctioning.") return user.show_message("Locked In.", MSG_AUDIBLE) - var/list/obj/effect/portal/created = create_portal_pair(current_location, get_teleport_turf(get_turf(T)), src, 300, 1, null, atmos_link_override) + var/list/obj/effect/portal/created = create_portal_pair(current_location, get_teleport_turf(get_turf(T)), 300, 1, null, atmos_link_override) if(!(LAZYLEN(created) == 2)) return - try_move_adjacent(created[1]) + RegisterSignal(created[1], COMSIG_PARENT_QDELETING, .proc/on_portal_destroy) //Gosh darn it kevinz. + RegisterSignal(created[2], COMSIG_PARENT_QDELETING, .proc/on_portal_destroy) + try_move_adjacent(created[1], user.dir) active_portal_pairs[created[1]] = created[2] var/obj/effect/portal/c1 = created[1] var/obj/effect/portal/c2 = created[2] diff --git a/code/game/objects/items/trash.dm b/code/game/objects/items/trash.dm index 4c6bcc08b4..2109d1038e 100644 --- a/code/game/objects/items/trash.dm +++ b/code/game/objects/items/trash.dm @@ -35,6 +35,10 @@ name = "syndi-cakes" icon_state = "syndi_cakes" +/obj/item/trash/energybar + name = "energybar wrapper" + icon_state = "energybar" + /obj/item/trash/waffles name = "waffles tray" icon_state = "waffles" diff --git a/code/game/objects/items/weaponry.dm b/code/game/objects/items/weaponry.dm index 0ab1f1b4fd..f462050789 100644 --- a/code/game/objects/items/weaponry.dm +++ b/code/game/objects/items/weaponry.dm @@ -249,6 +249,39 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301 playsound(src, 'sound/weapons/bladeslice.ogg', 50, 1) return(BRUTELOSS) +/obj/item/katana/timestop + name = "temporal katana" + desc = "Delicately balanced, this finely-crafted blade hums with barely-restrained potential." + icon_state = "temporalkatana" + item_state = "temporalkatana" + lefthand_file = 'icons/mob/inhands/weapons/swords_lefthand.dmi' + righthand_file = 'icons/mob/inhands/weapons/swords_righthand.dmi' + block_chance = 0 // oops + force = 27.5 // oops + item_flags = ITEM_CAN_PARRY + block_parry_data = /datum/block_parry_data/bokken/quick_parry/proj + +/obj/item/katana/timestop/on_active_parry(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, list/block_return, parry_efficiency, parry_time) + if(ishuman(owner)) + var/mob/living/carbon/human/flynn = owner + flynn.emote("smirk") + new /obj/effect/timestop/magic(get_turf(owner), 1, 50, list(owner)) // null roddies counter + +/obj/item/katana/timestop/suicide_act(mob/living/user) // stolen from hierophant staff + new /obj/effect/timestop/magic(get_turf(user), 1, 50, list(user)) // free usage for dying + user.visible_message("[user] poses menacingly with the [src]! It looks like [user.p_theyre()] trying to teleport behind someone!") + user.say("Heh.. Nothing personnel, kid..", forced = "temporal katana suicide") + sleep(20) + if(!user) + return + user.visible_message("[user] vanishes into a cloud of falling dust and burning embers, likely off to style on some poor sod in the distance!") + playsound(user,'sound/magic/blink.ogg', 75, TRUE) + for(var/obj/item/I in user) + if(I != src) + user.dropItemToGround(I) + user.dropItemToGround(src) //Drop us last, so it goes on top of their stuff + qdel(user) + /obj/item/melee/bokken // parrying stick name = "bokken" desc = "A space-Japanese training sword made of wood and shaped like a katana." @@ -283,24 +316,29 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301 parry_time_perfect = 1.5 parry_time_perfect_leeway = 1 parry_imperfect_falloff_percent = 7.5 - parry_efficiency_to_counterattack = 100 + parry_efficiency_to_counterattack = 120 parry_efficiency_considered_successful = 65 // VERY generous parry_efficiency_perfect = 120 parry_efficiency_perfect_override = list( TEXT_ATTACK_TYPE_PROJECTILE = 30, ) parry_failed_stagger_duration = 3 SECONDS - parry_data = list(PARRY_COUNTERATTACK_MELEE_ATTACK_CHAIN = 2.5) // 7*2.5 = 17.5, 8*2.5 = 20, 9*2.5 = 22.5, 10*2.5 = 25 + parry_data = list( + PARRY_COUNTERATTACK_MELEE_ATTACK_CHAIN = 2.5, // 7*2.5 = 17.5, 8*2.5 = 20, 9*2.5 = 22.5, 10*2.5 = 25 + ) /datum/block_parry_data/bokken/quick_parry // emphasizing REALLY SHORT PARRIES parry_stamina_cost = 6 // still more costly than most parries, but less than a full bokken parry parry_time_active = 5 // REALLY small parry window parry_time_perfect = 2.5 // however... - parry_time_perfect_leeway = 2.5 // the entire time, the parry is perfect + parry_time_perfect_leeway = 2 // the entire time, the parry is perfect parry_failed_stagger_duration = 1 SECONDS parry_failed_clickcd_duration = 1 SECONDS // more forgiving punishments for missed parries // still, don't fucking miss your parries or you're down stamina and staggered to shit +/datum/block_parry_data/bokken/quick_parry/proj + parry_efficiency_perfect_override = list() + /obj/item/melee/bokken/Initialize() . = ..() AddElement(/datum/element/sword_point) @@ -364,6 +402,40 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301 if(burnt) . += " Burned into the \"blade\" is [burned_in]." +/obj/item/melee/bokken/debug + name = "funny debug parrying stick" + desc = "if you see this you've fucked up somewhere my good man" + block_parry_data = /datum/block_parry_data/bokken/debug + +/obj/item/melee/bokken/debug/AltClick(mob/user) + quick_parry = !quick_parry + if(quick_parry) + block_parry_data = /datum/block_parry_data/bokken/quick_parry/debug + else + block_parry_data = /datum/block_parry_data/bokken/debug + to_chat(user, "[src] is now [quick_parry ? "emphasizing shorter parries, forcing you to riposte or be staggered" : "emphasizing longer parries, with a shorter window to riposte but more forgiving parries"].") + +/datum/block_parry_data/bokken/debug + parry_efficiency_perfect_override = list() + parry_data = list( + PARRY_COUNTERATTACK_MELEE_ATTACK_CHAIN = 2.5, // 7*2.5 = 17.5, 8*2.5 = 20, 9*2.5 = 22.5, 10*2.5 = 25 + PARRY_DISARM_ATTACKER = TRUE, + PARRY_KNOCKDOWN_ATTACKER = 10, + PARRY_STAGGER_ATTACKER = 10, + PARRY_DAZE_ATTACKER = 10, + ) + +/datum/block_parry_data/bokken/quick_parry/debug + parry_efficiency_perfect_override = list() + parry_data = list( + PARRY_COUNTERATTACK_MELEE_ATTACK_CHAIN = 2.5, // 7*2.5 = 17.5, 8*2.5 = 20, 9*2.5 = 22.5, 10*2.5 = 25 + PARRY_DISARM_ATTACKER = TRUE, + PARRY_KNOCKDOWN_ATTACKER = 10, + PARRY_STAGGER_ATTACKER = 10, + PARRY_DAZE_ATTACKER = 10, + ) + + /obj/item/wirerod name = "wired rod" desc = "A rod with some wire wrapped around the top. It'd be easy to attach something to the top bit." diff --git a/code/game/objects/obj_defense.dm b/code/game/objects/obj_defense.dm index 14017ffb2d..f5003e035b 100644 --- a/code/game/objects/obj_defense.dm +++ b/code/game/objects/obj_defense.dm @@ -186,7 +186,7 @@ GLOBAL_DATUM_INIT(acid_overlay, /mutable_appearance, mutable_appearance('icons/e if(!acid_level) SSacid.processing[src] = src - add_overlay(GLOB.acid_overlay, TRUE) + update_icon() var/acid_cap = acidpwr * 300 //so we cannot use huge amounts of weak acids to do as well as strong acids. if(acid_level < acid_cap) acid_level = min(acid_level + acidpwr * acid_volume, acid_cap) @@ -224,7 +224,7 @@ GLOBAL_DATUM_INIT(acid_overlay, /mutable_appearance, mutable_appearance('icons/e if(!(resistance_flags & ON_FIRE) && (resistance_flags & FLAMMABLE)) resistance_flags |= ON_FIRE SSfire_burning.processing[src] = src - add_overlay(GLOB.fire_overlay, TRUE) + update_icon() return 1 //called when the obj is destroyed by fire @@ -236,7 +236,7 @@ GLOBAL_DATUM_INIT(acid_overlay, /mutable_appearance, mutable_appearance('icons/e /obj/proc/extinguish() if(resistance_flags & ON_FIRE) resistance_flags &= ~ON_FIRE - cut_overlay(GLOB.fire_overlay, TRUE) + update_icon() SSfire_burning.processing -= src /obj/zap_act(power, zap_flags, shocked_targets) diff --git a/code/game/objects/objs.dm b/code/game/objects/objs.dm index 79dd13b0ae..99b302e9ce 100644 --- a/code/game/objects/objs.dm +++ b/code/game/objects/objs.dm @@ -317,6 +317,13 @@ icon_state = unique_reskin[choice] to_chat(M, "[src] is now skinned as '[choice]'.") +/obj/update_overlays() + . = ..() + if(acid_level) + . += GLOB.acid_overlay + if(resistance_flags & ON_FIRE) + . += GLOB.fire_overlay + //Called when the object is constructed by an autolathe //Has a reference to the autolathe so you can do !!FUN!! things with hacked lathes /obj/proc/autolathe_crafted(obj/machinery/autolathe/A) @@ -329,3 +336,6 @@ . = ..() if(. && ricochet_damage_mod) take_damage(P.damage * ricochet_damage_mod, P.damage_type, P.flag, 0, turn(P.dir, 180), P.armour_penetration) // pass along ricochet_damage_mod damage to the structure for the ricochet + +/obj/proc/plunger_act(obj/item/plunger/P, mob/living/user, reinforced) + return diff --git a/code/game/objects/structures.dm b/code/game/objects/structures.dm index 39f2d276a1..52036427c8 100644 --- a/code/game/objects/structures.dm +++ b/code/game/objects/structures.dm @@ -9,8 +9,10 @@ var/mob/living/structureclimber var/broken = 0 //similar to machinery's stat BROKEN layer = BELOW_OBJ_LAYER - flags_ricochet = RICOCHET_HARD - ricochet_chance_mod = 0.5 + //ricochets on structures commented out for now because there's a lot of structures that /shouldnt/ be ricocheting and those need to be reviewed first + //flags_1 = DEFAULT_RICOCHET_1 + //flags_ricochet = RICOCHET_HARD + //ricochet_chance_mod = 0.5 /obj/structure/Initialize() if (!armor) @@ -110,3 +112,6 @@ if(0 to 25) if(!broken) return "It's falling apart!" + +/obj/structure/rust_heretic_act() + take_damage(500, BRUTE, "melee", 1) diff --git a/code/game/objects/structures/artstuff.dm b/code/game/objects/structures/artstuff.dm index 827e9a7b0a..47584a1775 100644 --- a/code/game/objects/structures/artstuff.dm +++ b/code/game/objects/structures/artstuff.dm @@ -45,8 +45,6 @@ var/height = 11 var/list/grid var/canvas_color = "#ffffff" //empty canvas color - var/ui_x = 400 - var/ui_y = 400 var/used = FALSE var/painting_name //Painting name, this is set after framing. var/finalized = FALSE //Blocks edits @@ -75,12 +73,16 @@ . = ..() ui_interact(user) -/obj/item/canvas/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ - datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) +/obj/item/canvas/ui_state(mob/user) + if(finalized) + return GLOB.physical_obscured_state + else + return GLOB.default_state - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) +/obj/item/canvas/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) if(!ui) - ui = new(user, src, ui_key, "Canvas", name, ui_x, ui_y, master_ui, state) + ui = new(user, src, "Canvas", name) ui.set_autoupdate(FALSE) ui.open() @@ -190,8 +192,6 @@ icon_state = "19x19" width = 19 height = 19 - ui_x = 600 - ui_y = 600 pixel_x = 6 pixel_y = 9 framed_offset_x = 8 @@ -201,8 +201,6 @@ icon_state = "23x19" width = 23 height = 19 - ui_x = 800 - ui_y = 600 pixel_x = 4 pixel_y = 10 framed_offset_x = 6 @@ -212,8 +210,6 @@ icon_state = "23x23" width = 23 height = 23 - ui_x = 800 - ui_y = 800 pixel_x = 5 pixel_y = 9 framed_offset_x = 5 @@ -262,7 +258,7 @@ /obj/structure/sign/painting/examine(mob/user) . = ..() if(C) - C.ui_interact(user,state = GLOB.physical_obscured_state) + C.ui_interact(user) /obj/structure/sign/painting/wirecutter_act(mob/living/user, obj/item/I) . = ..() diff --git a/code/game/objects/structures/beds_chairs/chair.dm b/code/game/objects/structures/beds_chairs/chair.dm index 299ba7b659..39bef1a9c0 100644 --- a/code/game/objects/structures/beds_chairs/chair.dm +++ b/code/game/objects/structures/beds_chairs/chair.dm @@ -319,10 +319,43 @@ throwforce = 10 throw_range = 3 hitsound = 'sound/items/trayhit1.ogg' - block_chance = 50 custom_materials = list(/datum/material/iron = 2000) var/break_chance = 5 //Likely hood of smashing the chair. var/obj/structure/chair/origin_type = /obj/structure/chair + item_flags = ITEM_CAN_PARRY | ITEM_CAN_BLOCK + block_parry_data = /datum/block_parry_data/chair + +/obj/item/chair/ComponentInitialize() + . = ..() + AddComponent(/datum/component/two_handed, require_twohands = TRUE) + +/datum/block_parry_data/chair + block_damage_multiplier = 0.7 + block_stamina_efficiency = 2 + block_stamina_cost_per_second = 1.5 + block_slowdown = 0.5 + block_lock_attacking = FALSE + block_lock_sprinting = TRUE + block_start_delay = 1.5 + block_damage_absorption = 7 + block_damage_limit = 20 + block_resting_stamina_penalty_multiplier = 2 + block_projectile_mitigation = 20 + parry_stamina_cost = 5 + parry_time_windup = 1 + parry_time_active = 11 + parry_time_spindown = 2 + parry_time_perfect = 1.5 + parry_time_perfect_leeway = 1 + parry_imperfect_falloff_percent = 7.5 + parry_efficiency_to_counterattack = 100 + parry_efficiency_considered_successful = 50 + parry_efficiency_perfect = 120 + parry_efficiency_perfect_override = list( + TEXT_ATTACK_TYPE_PROJECTILE = 30, + ) + parry_failed_stagger_duration = 3.5 SECONDS + parry_data = list(PARRY_COUNTERATTACK_MELEE_ATTACK_CHAIN = 2.5) /obj/item/chair/suicide_act(mob/living/carbon/user) user.visible_message("[user] begins hitting [user.p_them()]self with \the [src]! It looks like [user.p_theyre()] trying to commit suicide!") @@ -454,7 +487,7 @@ desc = "A bronze bar stool with red silk for a pillow." icon_state = "barbrass" item_chair = /obj/item/chair/stool/bar/bronze - buildstacktype = /obj/item/stack/tile/bronze + buildstacktype = /obj/item/stack/sheet/bronze buildstackamount = 1 /obj/structure/chair/stool/brass @@ -470,7 +503,7 @@ desc = "A bronze stool with a silk top for comfort." icon_state = "stoolbrass" item_chair = /obj/item/chair/stool/bronze - buildstacktype = /obj/item/stack/tile/bronze + buildstacktype = /obj/item/stack/sheet/bronze buildstackamount = 1 /obj/item/chair/stool/brass @@ -536,7 +569,6 @@ buildstacktype = /obj/item/stack/tile/brass buildstackamount = 1 item_chair = null - var/turns = 0 /obj/structure/chair/brass/ComponentInitialize() return //it spins with the power of ratvar, not components. @@ -548,16 +580,12 @@ /obj/structure/chair/brass/process() setDir(turn(dir,-90)) playsound(src, 'sound/effects/servostep.ogg', 50, FALSE) - turns++ - if(turns >= 8) - STOP_PROCESSING(SSfastprocess, src) /obj/structure/chair/brass/ratvar_act() return /obj/structure/chair/brass/AltClick(mob/living/user) . = ..() - turns = 0 if(!istype(user) || !user.canUseTopic(src, BE_CLOSE, ismonkey(user))) return if(!(datum_flags & DF_ISPROCESSING)) @@ -575,7 +603,7 @@ desc = "A spinny chair made of bronze. It has little cogs for wheels!" anchored = FALSE icon_state = "brass_chair" - buildstacktype = /obj/item/stack/tile/bronze + buildstacktype = /obj/item/stack/sheet/bronze buildstackamount = 1 item_chair = null diff --git a/code/game/objects/structures/crates_lockers/closets.dm b/code/game/objects/structures/crates_lockers/closets.dm index 043232e9e3..5c5b2bb132 100644 --- a/code/game/objects/structures/crates_lockers/closets.dm +++ b/code/game/objects/structures/crates_lockers/closets.dm @@ -111,6 +111,9 @@ var/mob/living/L = user if(HAS_TRAIT(L, TRAIT_SKITTISH)) . += "Ctrl-Shift-click [src] to jump inside." + if(isobserver(user)) + . += "It contains: [english_list(contents)]." + investigate_log("had its contents examined by [user] as a ghost.", INVESTIGATE_GHOST) /obj/structure/closet/CanPass(atom/movable/mover, turf/target) if(wall_mounted) diff --git a/code/game/objects/structures/displaycase.dm b/code/game/objects/structures/displaycase.dm index f0384ca96a..19c0f0aed1 100644 --- a/code/game/objects/structures/displaycase.dm +++ b/code/game/objects/structures/displaycase.dm @@ -345,3 +345,212 @@ name = initial(I.name) icon = initial(I.icon) icon_state = initial(I.icon_state) +/* Selling people in jars is currently disabled. +/obj/structure/displaycase/forsale + name = "vend-a-tray" + icon = 'icons/obj/stationobjs.dmi' + icon_state = "laserbox0" + desc = "A display case with an ID-card swiper. Use your ID to purchase the contents." + density = FALSE + max_integrity = 100 + req_access = null + showpiece_type = /obj/item/reagent_containers/food + alert = FALSE //No, we're not calling the fire department because someone stole your cookie. + glass_fix = FALSE //Fixable with tools instead. + ///The price of the item being sold. Altered by grab intent ID use. + var/sale_price = 20 + ///The Account which will receive payment for purchases. Set by the first ID to swipe the tray. + var/datum/bank_account/payments_acc = null + ///We're using the same trick as paper does in order to cache the image, and only load the UI when messed with. + var/list/viewing_ui = list() + +/obj/structure/displaycase/forsale/update_icon() //remind me to fix my shitcode later + var/icon/I + if(open) + I = icon('icons/obj/stationobjs.dmi',"laserboxb0") + else + I = icon('icons/obj/stationobjs.dmi',"laserbox0") + if(!showpiece && !open) + I = icon('icons/obj/stationobjs.dmi',"laserbox_open") + if(broken) + I = icon('icons/obj/stationobjs.dmi',"laserbox_broken") + if(showpiece) + var/icon/S = getFlatIcon(showpiece) + S.Scale(17,17) + I.Blend(S,ICON_UNDERLAY,8,12) + src.icon = I + return + +/obj/structure/displaycase/forsale/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "Vendatray", name) + ui.set_autoupdate(FALSE) + viewing_ui[user] = ui + ui.open() + +/obj/structure/displaycase/forsale/ui_data(mob/user) + var/list/data = list() + var/register = FALSE + if(payments_acc) + register = TRUE + data["owner_name"] = payments_acc.account_holder + if(showpiece) + data["product_name"] = capitalize(showpiece.name) + var/base64 = icon2base64(icon(showpiece.icon, showpiece.icon_state)) + data["product_icon"] = base64 + data["registered"] = register + data["product_cost"] = sale_price + data["tray_open"] = open + return data + +/obj/structure/displaycase/forsale/ui_act(action, params) + if(..()) + return + var/obj/item/card/id/potential_acc = usr.get_idcard(hand_first = TRUE) + switch(action) + if("Buy") + if(!showpiece) + to_chat(usr, "There's nothing for sale.") + return TRUE + if(broken) + to_chat(usr, "[src] appears to be broken.") + return TRUE + if(!payments_acc) + to_chat(usr, "[src] hasn't been registered yet.") + return TRUE + if(!usr.canUseTopic(src, BE_CLOSE, FALSE, NO_TK)) + return TRUE + if(!potential_acc) + to_chat(usr, "No ID card detected.") + return + var/datum/bank_account/account = potential_acc.registered_account + if(!account) + to_chat(usr, "[potential_acc] has no account registered!") + return + if(!account.has_money(sale_price)) + to_chat(usr, "You do not possess the funds to purchase this.") + return TRUE + else + account.adjust_money(-sale_price) + if(payments_acc) + payments_acc.adjust_money(sale_price) + usr.put_in_hands(showpiece) + to_chat(usr, "You purchase [showpiece] for [sale_price] credits.") + playsound(src, 'sound/effects/cashregister.ogg', 40, TRUE) + icon = 'icons/obj/stationobjs.dmi' + flick("laserbox_vend", src) + showpiece = null + update_icon() + SStgui.update_uis(src) + return TRUE + if("Open") + if(!payments_acc) + to_chat(usr, "[src] hasn't been registered yet.") + return TRUE + if(!potential_acc || !potential_acc.registered_account) + return + if(!check_access(potential_acc)) + playsound(src, 'sound/machines/buzz-sigh.ogg', 50, TRUE) + return + toggle_lock() + SStgui.update_uis(src) + if("Register") + if(payments_acc) + return + if(!potential_acc || !potential_acc.registered_account) + return + if(!check_access(potential_acc)) + playsound(src, 'sound/machines/buzz-sigh.ogg', 50, TRUE) + return + payments_acc = potential_acc.registered_account + playsound(src, 'sound/machines/click.ogg', 20, TRUE) + if("Adjust") + if(!check_access(potential_acc) || potential_acc.registered_account != payments_acc) + playsound(src, 'sound/machines/buzz-sigh.ogg', 50, TRUE) + return + + var/new_price_input = input(usr,"Set the sale price for this vend-a-tray.","new price",0) as num|null + if(isnull(new_price_input) || (payments_acc != potential_acc.registered_account)) + to_chat(usr, "[src] rejects your new price.") + return + if(!usr.canUseTopic(src, BE_CLOSE, FALSE, NO_TK) ) + to_chat(usr, "You need to get closer!") + return + new_price_input = clamp(round(new_price_input, 1), 10, 1000) + sale_price = new_price_input + to_chat(usr, "The cost is now set to [sale_price].") + SStgui.update_uis(src) + return TRUE + . = TRUE +/obj/structure/displaycase/forsale/attackby(obj/item/I, mob/living/user, params) + if(isidcard(I)) + //Card Registration + var/obj/item/card/id/potential_acc = I + if(!potential_acc.registered_account) + to_chat(user, "This ID card has no account registered!") + return + if(payments_acc == potential_acc.registered_account) + playsound(src, 'sound/machines/click.ogg', 20, TRUE) + toggle_lock() + return + if(istype(I, /obj/item/pda)) + return TRUE + SStgui.update_uis(src) + . = ..() + + +/obj/structure/displaycase/forsale/multitool_act(mob/living/user, obj/item/I) + . = ..() + if(obj_integrity <= (integrity_failure * max_integrity)) + to_chat(user, "You start recalibrating [src]'s hover field...") + if(do_after(user, 20, target = src)) + broken = 0 + obj_integrity = max_integrity + update_icon() + return TRUE + +/obj/structure/displaycase/forsale/wrench_act(mob/living/user, obj/item/I) + . = ..() + if(open && user.a_intent == INTENT_HELP ) + if(anchored) + to_chat(user, "You start unsecuring [src]...") + else + to_chat(user, "You start securing [src]...") + if(I.use_tool(src, user, 16, volume=50)) + if(QDELETED(I)) + return + if(anchored) + to_chat(user, "You unsecure [src].") + else + to_chat(user, "You secure [src].") + anchored = !anchored + return + else if(!open && user.a_intent == INTENT_HELP) + to_chat(user, "[src] must be open to move it.") + return + +/obj/structure/displaycase/forsale/emag_act(mob/user) + . = ..() + payments_acc = null + req_access = list() + to_chat(user, "[src]'s card reader fizzles and smokes, and the account owner is reset.") + +/obj/structure/displaycase/forsale/examine(mob/user) + . = ..() + if(showpiece && !open) + . += "[showpiece] is for sale for [sale_price] credits." + if(broken) + . += "[src] is sparking and the hover field generator seems to be overloaded. Use a multitool to fix it." + +/obj/structure/displaycase/forsale/obj_break(damage_flag) + if(!broken && !(flags_1 & NODECONSTRUCT_1)) + broken = TRUE + playsound(src, "shatter", 70, TRUE) + update_icon() + trigger_alarm() //In case it's given an alarm anyway. + +/obj/structure/displaycase/forsale/kitchen + desc = "A display case with an ID-card swiper. Use your ID to purchase the contents. Meant for the bartender and chef." + req_one_access = list(ACCESS_KITCHEN, ACCESS_BAR) +*/ \ No newline at end of file diff --git a/code/game/objects/structures/door_assembly_types.dm b/code/game/objects/structures/door_assembly_types.dm index fe9c4e7bbc..5fb454b5bc 100644 --- a/code/game/objects/structures/door_assembly_types.dm +++ b/code/game/objects/structures/door_assembly_types.dm @@ -240,3 +240,14 @@ airlock_type = /obj/machinery/door/airlock/wood mineral = "wood" glass_type = /obj/machinery/door/airlock/wood/glass + +/obj/structure/door_assembly/door_assembly_bronze + name = "bronze airlock assembly" + icon = 'icons/obj/doors/airlocks/clockwork/pinion_airlock.dmi' + base_name = "bronze airlock" + airlock_type = /obj/machinery/door/airlock/bronze + noglass = TRUE + material_type = /obj/item/stack/tile/bronze + +/obj/structure/door_assembly/door_assembly_bronze/seethru + airlock_type = /obj/machinery/door/airlock/bronze/seethru diff --git a/code/game/objects/structures/girders.dm b/code/game/objects/structures/girders.dm index ff62b9cc48..87cfbb56e0 100644 --- a/code/game/objects/structures/girders.dm +++ b/code/game/objects/structures/girders.dm @@ -442,19 +442,19 @@ to_chat(user, "You start slicing apart [src]...") if(W.use_tool(src, user, 40, volume=50)) to_chat(user, "You slice apart [src].") - var/obj/item/stack/tile/bronze/B = new(drop_location(), 2) + var/obj/item/stack/sheet/bronze/B = new(drop_location(), 2) transfer_fingerprints_to(B) qdel(src) else if(istype(W, /obj/item/pickaxe/drill/jackhammer)) to_chat(user, "Your jackhammer smashes through the girder!") - var/obj/item/stack/tile/bronze/B = new(drop_location(), 2) + var/obj/item/stack/sheet/bronze/B = new(drop_location(), 2) transfer_fingerprints_to(B) W.play_tool_sound(src) qdel(src) - else if(istype(W, /obj/item/stack/tile/bronze)) - var/obj/item/stack/tile/bronze/B = W + else if(istype(W, /obj/item/stack/sheet/bronze)) + var/obj/item/stack/sheet/bronze/B = W if(B.get_amount() < 2) to_chat(user, "You need at least two bronze sheets to build a bronze wall!") return 0 diff --git a/code/game/objects/structures/lavaland/geyser.dm b/code/game/objects/structures/lavaland/geyser.dm index 4f6256e9c4..263b47aab2 100644 --- a/code/game/objects/structures/lavaland/geyser.dm +++ b/code/game/objects/structures/lavaland/geyser.dm @@ -9,7 +9,7 @@ var/erupting_state = null //set to null to get it greyscaled from "[icon_state]_soup". Not very usable with the whole random thing, but more types can be added if you change the spawn prob var/activated = FALSE //whether we are active and generating chems - var/reagent_id = /datum/reagent/fuel/oil + var/reagent_id = /datum/reagent/oil var/potency = 2 //how much reagents we add every process (2 seconds) var/max_volume = 500 var/start_volume = 50 @@ -77,10 +77,10 @@ /obj/item/plunger/reinforced name = "reinforced plunger" - desc = "It's an M. 7 Reinforced Plunger© for heavy duty plunging." + desc = "It's an M. 7 Reinforced Plunger� for heavy duty plunging." icon_state = "reinforced_plunger" reinforced = TRUE plunge_mod = 0.8 - custom_premium_price = 1200 + custom_premium_price = 600 diff --git a/code/game/objects/structures/stairs.dm b/code/game/objects/structures/stairs.dm index d1a2a6f9f6..1358b2e296 100644 --- a/code/game/objects/structures/stairs.dm +++ b/code/game/objects/structures/stairs.dm @@ -3,7 +3,7 @@ #define STAIR_TERMINATOR_YES 2 // dir determines the direction of travel to go upwards (due to lack of sprites, currently only 1 and 2 make sense) -// stairs require /turf/open/openspace as the tile above them to work +// stairs require /turf/open/transparent/openspace as the tile above them to work // multiple stair objects can be chained together; the Z level transition will happen on the final stair object in the chain /obj/structure/stairs @@ -12,7 +12,7 @@ icon_state = "stairs" anchored = TRUE - var/force_open_above = FALSE // replaces the turf above this stair obj with /turf/open/openspace + var/force_open_above = FALSE // replaces the turf above this stair obj with /turf/open/transparent/openspace var/terminator_mode = STAIR_TERMINATOR_AUTOMATIC var/turf/listeningTo @@ -95,20 +95,20 @@ /obj/structure/stairs/proc/build_signal_listener() if(listeningTo) UnregisterSignal(listeningTo, COMSIG_TURF_MULTIZ_NEW) - var/turf/open/openspace/T = get_step_multiz(get_turf(src), UP) + var/turf/open/transparent/openspace/T = get_step_multiz(get_turf(src), UP) RegisterSignal(T, COMSIG_TURF_MULTIZ_NEW, .proc/on_multiz_new) listeningTo = T /obj/structure/stairs/proc/force_open_above() - var/turf/open/openspace/T = get_step_multiz(get_turf(src), UP) + var/turf/open/transparent/openspace/T = get_step_multiz(get_turf(src), UP) if(T && !istype(T)) - T.ChangeTurf(/turf/open/openspace, flags = CHANGETURF_INHERIT_AIR) + T.ChangeTurf(/turf/open/transparent/openspace, flags = CHANGETURF_INHERIT_AIR) /obj/structure/stairs/proc/on_multiz_new(turf/source, dir) if(dir == UP) - var/turf/open/openspace/T = get_step_multiz(get_turf(src), UP) + var/turf/open/transparent/openspace/T = get_step_multiz(get_turf(src), UP) if(T && !istype(T)) - T.ChangeTurf(/turf/open/openspace, flags = CHANGETURF_INHERIT_AIR) + T.ChangeTurf(/turf/open/transparent/openspace, flags = CHANGETURF_INHERIT_AIR) /obj/structure/stairs/intercept_zImpact(atom/movable/AM, levels = 1) . = ..() diff --git a/code/game/objects/structures/tables_racks.dm b/code/game/objects/structures/tables_racks.dm index a553e63b0f..9f91d2c5e0 100644 --- a/code/game/objects/structures/tables_racks.dm +++ b/code/game/objects/structures/tables_racks.dm @@ -597,7 +597,7 @@ icon = 'icons/obj/smooth_structures/brass_table.dmi' icon_state = "brass_table" resistance_flags = FIRE_PROOF | ACID_PROOF - buildstack = /obj/item/stack/tile/bronze + buildstack = /obj/item/stack/sheet/bronze canSmoothWith = list(/obj/structure/table/reinforced/brass, /obj/structure/table/bronze) /obj/structure/table/bronze/tablelimbsmash(mob/living/user, mob/living/pushed_mob) diff --git a/code/game/objects/structures/tank_dispenser.dm b/code/game/objects/structures/tank_dispenser.dm index e2298ac6c5..2a441ff0f2 100644 --- a/code/game/objects/structures/tank_dispenser.dm +++ b/code/game/objects/structures/tank_dispenser.dm @@ -67,15 +67,14 @@ to_chat(user, "You put [I] in [src].") update_icon() -/obj/structure/tank_dispenser/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ - datum/tgui/master_ui = null, datum/ui_state/state = GLOB.physical_state) - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) - if(!ui) - ui = new(user, src, ui_key, "TankDispenser", name, 275, 103, master_ui, state) - ui.open() +/obj/structure/tank_dispenser/ui_state(mob/user) + return GLOB.physical_state -/obj/structure/tank_dispenser/attack_robot(mob/user) - ui_interact(user) +/obj/structure/tank_dispenser/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "TankDispenser", name) + ui.open() /obj/structure/tank_dispenser/ui_data(mob/user) var/list/data = list() diff --git a/code/game/objects/structures/window.dm b/code/game/objects/structures/window.dm index 6aae4955f1..74f006296f 100644 --- a/code/game/objects/structures/window.dm +++ b/code/game/objects/structures/window.dm @@ -17,7 +17,6 @@ GLOBAL_LIST_EMPTY(electrochromatic_window_lookup) layer = ABOVE_OBJ_LAYER //Just above doors pressure_resistance = 4*ONE_ATMOSPHERE anchored = TRUE //initially is 0 for tile smoothing - flags_1 = ON_BORDER_1 max_integrity = 25 var/ini_dir = null var/state = WINDOW_OUT_OF_FRAME @@ -38,7 +37,8 @@ GLOBAL_LIST_EMPTY(electrochromatic_window_lookup) var/hitsound = 'sound/effects/Glasshit.ogg' rad_insulation = RAD_VERY_LIGHT_INSULATION rad_flags = RAD_PROTECT_CONTENTS - flags_ricochet = RICOCHET_HARD + flags_1 = ON_BORDER_1|DEFAULT_RICOCHET_1 + flags_ricochet = RICOCHET_HARD ricochet_chance_mod = 0.4 attack_hand_speed = CLICK_CD_MELEE attack_hand_is_action = TRUE @@ -875,3 +875,26 @@ GLOBAL_LIST_EMPTY(electrochromatic_window_lookup) return ..() update_icon() + +/obj/structure/window/bronze + name = "brass window" + desc = "A paper-thin pane of translucent yet reinforced brass. Nevermind, this is just weak bronze!" + icon = 'icons/obj/smooth_structures/clockwork_window.dmi' + icon_state = "clockwork_window_single" + glass_type = /obj/item/stack/tile/bronze + +/obj/structure/window/bronze/unanchored + anchored = FALSE + +/obj/structure/window/bronze/fulltile + icon_state = "clockwork_window" + canSmoothWith = null + smooth = SMOOTH_TRUE + fulltile = TRUE + flags_1 = PREVENT_CLICK_UNDER_1 + dir = FULLTILE_WINDOW_DIR + max_integrity = 50 + glass_amount = 2 + +/obj/structure/window/bronze/fulltile/unanchored + anchored = FALSE diff --git a/code/game/sound.dm b/code/game/sound.dm index 577b058178..0feb01c223 100644 --- a/code/game/sound.dm +++ b/code/game/sound.dm @@ -226,5 +226,9 @@ soundin = pick('sound/effects/clangsmall1.ogg', 'sound/effects/clangsmall2.ogg') if("slosh") soundin = pick('sound/effects/slosh1.ogg', 'sound/effects/slosh2.ogg') + if("smcalm") + soundin = pick('sound/machines/sm/accent/normal/1.ogg', 'sound/machines/sm/accent/normal/2.ogg', 'sound/machines/sm/accent/normal/3.ogg', 'sound/machines/sm/accent/normal/4.ogg', 'sound/machines/sm/accent/normal/5.ogg', 'sound/machines/sm/accent/normal/6.ogg', 'sound/machines/sm/accent/normal/7.ogg', 'sound/machines/sm/accent/normal/8.ogg', 'sound/machines/sm/accent/normal/9.ogg', 'sound/machines/sm/accent/normal/10.ogg', 'sound/machines/sm/accent/normal/11.ogg', 'sound/machines/sm/accent/normal/12.ogg', 'sound/machines/sm/accent/normal/13.ogg', 'sound/machines/sm/accent/normal/14.ogg', 'sound/machines/sm/accent/normal/15.ogg', 'sound/machines/sm/accent/normal/16.ogg', 'sound/machines/sm/accent/normal/17.ogg', 'sound/machines/sm/accent/normal/18.ogg', 'sound/machines/sm/accent/normal/19.ogg', 'sound/machines/sm/accent/normal/20.ogg', 'sound/machines/sm/accent/normal/21.ogg', 'sound/machines/sm/accent/normal/22.ogg', 'sound/machines/sm/accent/normal/23.ogg', 'sound/machines/sm/accent/normal/24.ogg', 'sound/machines/sm/accent/normal/25.ogg', 'sound/machines/sm/accent/normal/26.ogg', 'sound/machines/sm/accent/normal/27.ogg', 'sound/machines/sm/accent/normal/28.ogg', 'sound/machines/sm/accent/normal/29.ogg', 'sound/machines/sm/accent/normal/30.ogg', 'sound/machines/sm/accent/normal/31.ogg', 'sound/machines/sm/accent/normal/32.ogg', 'sound/machines/sm/accent/normal/33.ogg') + if("smdelam") + soundin = pick('sound/machines/sm/accent/delam/1.ogg', 'sound/machines/sm/accent/normal/2.ogg', 'sound/machines/sm/accent/normal/3.ogg', 'sound/machines/sm/accent/normal/4.ogg', 'sound/machines/sm/accent/normal/5.ogg', 'sound/machines/sm/accent/normal/6.ogg', 'sound/machines/sm/accent/normal/7.ogg', 'sound/machines/sm/accent/normal/8.ogg', 'sound/machines/sm/accent/normal/9.ogg', 'sound/machines/sm/accent/normal/10.ogg', 'sound/machines/sm/accent/normal/11.ogg', 'sound/machines/sm/accent/normal/12.ogg', 'sound/machines/sm/accent/normal/13.ogg', 'sound/machines/sm/accent/normal/14.ogg', 'sound/machines/sm/accent/normal/15.ogg', 'sound/machines/sm/accent/normal/16.ogg', 'sound/machines/sm/accent/normal/17.ogg', 'sound/machines/sm/accent/normal/18.ogg', 'sound/machines/sm/accent/normal/19.ogg', 'sound/machines/sm/accent/normal/20.ogg', 'sound/machines/sm/accent/normal/21.ogg', 'sound/machines/sm/accent/normal/22.ogg', 'sound/machines/sm/accent/normal/23.ogg', 'sound/machines/sm/accent/normal/24.ogg', 'sound/machines/sm/accent/normal/25.ogg', 'sound/machines/sm/accent/normal/26.ogg', 'sound/machines/sm/accent/normal/27.ogg', 'sound/machines/sm/accent/normal/28.ogg', 'sound/machines/sm/accent/normal/29.ogg', 'sound/machines/sm/accent/normal/30.ogg', 'sound/machines/sm/accent/normal/31.ogg', 'sound/machines/sm/accent/normal/32.ogg', 'sound/machines/sm/accent/normal/33.ogg') //END OF CIT CHANGES return soundin diff --git a/code/game/turfs/closed.dm b/code/game/turfs/closed.dm index b78826b23b..be0c444541 100644 --- a/code/game/turfs/closed.dm +++ b/code/game/turfs/closed.dm @@ -29,6 +29,9 @@ icon = 'icons/turf/walls.dmi' explosion_block = 50 +/turf/closed/indestructible/rust_heretic_act() + return + /turf/closed/indestructible/TerraformTurf(path, new_baseturf, flags, defer_change = FALSE, ignore_air = FALSE) return @@ -198,13 +201,13 @@ /turf/closed/indestructible/rock/glacierrock name = "unaturally hard ice wall" - desc = "Ice, hardened over thousands of years, you're not breaking through this." + desc = "Ice, hardened over thousands of years, you're not breaking through this." icon = 'icons/turf/walls.dmi' icon_state = "snow_rock" /turf/closed/indestructible/rock/glacierrock/blue name = "blue ice wall" - desc = "The incredible compressive forces that formed this sturdy ice wall gave it a blue color." + desc = "The incredible compressive forces that formed this sturdy ice wall gave it a blue color." icon = 'icons/turf/walls.dmi' icon_state = "ice" canSmoothWith = list(/turf/closed/indestructible/rock/glacierrock/blue) diff --git a/code/game/turfs/openspace/openspace.dm b/code/game/turfs/openspace/openspace.dm index 90fab29611..ea539ce5b5 100644 --- a/code/game/turfs/openspace/openspace.dm +++ b/code/game/turfs/openspace/openspace.dm @@ -11,66 +11,47 @@ GLOBAL_DATUM_INIT(openspace_backdrop_one_for_all, /atom/movable/openspace_backdr mouse_opacity = MOUSE_OPACITY_TRANSPARENT layer = SPLASHSCREEN_LAYER -/turf/open/openspace +/turf/open/transparent/openspace name = "open space" desc = "Watch your step!" icon_state = "transparent" - baseturfs = /turf/open/openspace + baseturfs = /turf/open/transparent/openspace CanAtmosPassVertical = ATMOS_PASS_YES //mouse_opacity = MOUSE_OPACITY_TRANSPARENT var/can_cover_up = TRUE var/can_build_on = TRUE -/turf/open/openspace/debug/update_multiz() +/turf/open/transparent/openspace/airless + initial_gas_mix = AIRLESS_ATMOS + +/turf/open/transparent/openspace/debug/update_multiz() ..() return TRUE -/turf/open/openspace/Initialize() // handle plane and layer here so that they don't cover other obs/turfs in Dream Maker +///No bottom level for openspace. +/turf/open/transparent/openspace/show_bottom_level() + return FALSE + +/turf/open/transparent/openspace/Initialize() // handle plane and layer here so that they don't cover other obs/turfs in Dream Maker . = ..() - plane = OPENSPACE_PLANE - layer = OPENSPACE_LAYER + vis_contents += GLOB.openspace_backdrop_one_for_all //Special grey square for projecting backdrop darkness filter on it. - return INITIALIZE_HINT_LATELOAD -/turf/open/openspace/LateInitialize() - update_multiz(TRUE, TRUE) +/turf/open/transparent/openspace/can_have_cabling() + if(locate(/obj/structure/lattice/catwalk, src)) + return TRUE + return FALSE -/turf/open/openspace/Destroy() - vis_contents.len = 0 - return ..() - -/turf/open/openspace/update_multiz(prune_on_fail = FALSE, init = FALSE) - . = ..() - var/turf/T = below() - if(!T) - vis_contents.len = 0 - if(prune_on_fail) - ChangeTurf(/turf/open/floor/plating) - return FALSE - if(init) - vis_contents += T +/turf/open/transparent/openspace/zAirIn() return TRUE -/turf/open/openspace/multiz_turf_del(turf/T, dir) - if(dir != DOWN) - return - update_multiz() - -/turf/open/openspace/multiz_turf_new(turf/T, dir) - if(dir != DOWN) - return - update_multiz() - -/turf/open/openspace/zAirIn() +/turf/open/transparent/openspace/zAirOut() return TRUE -/turf/open/openspace/zAirOut() +/turf/open/transparent/openspace/zPassIn(atom/movable/A, direction, turf/source) return TRUE -/turf/open/openspace/zPassIn(atom/movable/A, direction, turf/source) - return TRUE - -/turf/open/openspace/zPassOut(atom/movable/A, direction, turf/destination) +/turf/open/transparent/openspace/zPassOut(atom/movable/A, direction, turf/destination) if(A.anchored) return FALSE for(var/obj/O in contents) @@ -78,13 +59,13 @@ GLOBAL_DATUM_INIT(openspace_backdrop_one_for_all, /atom/movable/openspace_backdr return FALSE return TRUE -/turf/open/openspace/proc/CanCoverUp() +/turf/open/transparent/openspace/proc/CanCoverUp() return can_cover_up -/turf/open/openspace/proc/CanBuildHere() +/turf/open/transparent/openspace/proc/CanBuildHere() return can_build_on -/turf/open/openspace/attackby(obj/item/C, mob/user, params) +/turf/open/transparent/openspace/attackby(obj/item/C, mob/user, params) ..() if(!CanBuildHere()) return @@ -98,14 +79,14 @@ GLOBAL_DATUM_INIT(openspace_backdrop_one_for_all, /atom/movable/openspace_backdr if(L) if(R.use(1)) to_chat(user, "You construct a catwalk.") - playsound(src, 'sound/weapons/genhit.ogg', 50, 1) + playsound(src, 'sound/weapons/genhit.ogg', 50, TRUE) new/obj/structure/lattice/catwalk(src) else to_chat(user, "You need two rods to build a catwalk!") return if(R.use(1)) to_chat(user, "You construct a lattice.") - playsound(src, 'sound/weapons/genhit.ogg', 50, 1) + playsound(src, 'sound/weapons/genhit.ogg', 50, TRUE) ReplaceWithLattice() else to_chat(user, "You need one rod to build a lattice.") @@ -118,7 +99,7 @@ GLOBAL_DATUM_INIT(openspace_backdrop_one_for_all, /atom/movable/openspace_backdr var/obj/item/stack/tile/plasteel/S = C if(S.use(1)) qdel(L) - playsound(src, 'sound/weapons/genhit.ogg', 50, 1) + playsound(src, 'sound/weapons/genhit.ogg', 50, TRUE) to_chat(user, "You build a floor.") PlaceOnTop(/turf/open/floor/plating, flags = CHANGETURF_INHERIT_AIR) else @@ -126,7 +107,7 @@ GLOBAL_DATUM_INIT(openspace_backdrop_one_for_all, /atom/movable/openspace_backdr else to_chat(user, "The plating is going to need some support! Place metal rods first.") -/turf/open/openspace/rcd_vals(mob/user, obj/item/construction/rcd/the_rcd) +/turf/open/transparent/openspace/rcd_vals(mob/user, obj/item/construction/rcd/the_rcd) if(!CanBuildHere()) return FALSE @@ -139,7 +120,7 @@ GLOBAL_DATUM_INIT(openspace_backdrop_one_for_all, /atom/movable/openspace_backdr return list("mode" = RCD_FLOORWALL, "delay" = 0, "cost" = 3) return FALSE -/turf/open/openspace/rcd_act(mob/user, obj/item/construction/rcd/the_rcd, passed_mode) +/turf/open/transparent/openspace/rcd_act(mob/user, obj/item/construction/rcd/the_rcd, passed_mode) switch(passed_mode) if(RCD_FLOORWALL) to_chat(user, "You build a floor.") @@ -147,12 +128,12 @@ GLOBAL_DATUM_INIT(openspace_backdrop_one_for_all, /atom/movable/openspace_backdr return TRUE return FALSE -/turf/open/openspace/icemoon +/turf/open/transparent/openspace/icemoon name = "ice chasm" - baseturfs = /turf/open/openspace/icemoon - can_cover_up = FALSE - can_build_on = FALSE + baseturfs = /turf/open/transparent/openspace/icemoon + can_cover_up = TRUE + can_build_on = TRUE initial_gas_mix = ICEMOON_DEFAULT_ATMOS -/turf/open/openspace/icemoon/can_zFall(atom/movable/A, levels = 1, turf/target) +/turf/open/transparent/openspace/icemoon/can_zFall(atom/movable/A, levels = 1, turf/target) return TRUE diff --git a/code/game/turfs/openspace/transparent.dm b/code/game/turfs/openspace/transparent.dm new file mode 100644 index 0000000000..8efc60a15b --- /dev/null +++ b/code/game/turfs/openspace/transparent.dm @@ -0,0 +1,95 @@ +/turf/open/transparent + baseturfs = /turf/open/transparent/openspace + intact = FALSE //this means wires go on top + +/turf/open/transparent/Initialize() // handle plane and layer here so that they don't cover other obs/turfs in Dream Maker + . = ..() + plane = OPENSPACE_PLANE + layer = OPENSPACE_LAYER + + return INITIALIZE_HINT_LATELOAD + +/turf/open/transparent/LateInitialize() + update_multiz(TRUE, TRUE) + +/turf/open/transparent/Destroy() + vis_contents.len = 0 + return ..() + +/turf/open/transparent/update_multiz(prune_on_fail = FALSE, init = FALSE) + . = ..() + var/turf/T = below() + if(!T) + vis_contents.len = 0 + if(!show_bottom_level() && prune_on_fail) //If we cant show whats below, and we prune on fail, change the turf to plating as a fallback + ChangeTurf(/turf/open/floor/plating, flags = CHANGETURF_INHERIT_AIR) + return FALSE + if(init) + vis_contents += T + return TRUE + +/turf/open/transparent/multiz_turf_del(turf/T, dir) + if(dir != DOWN) + return + update_multiz() + +/turf/open/transparent/multiz_turf_new(turf/T, dir) + if(dir != DOWN) + return + update_multiz() + +///Called when there is no real turf below this turf +/turf/open/transparent/proc/show_bottom_level() + var/turf/path = SSmapping.level_trait(z, ZTRAIT_BASETURF) || /turf/open/space + if(!ispath(path)) + path = text2path(path) + if(!ispath(path)) + warning("Z-level [z] has invalid baseturf '[SSmapping.level_trait(z, ZTRAIT_BASETURF)]'") + path = /turf/open/space + var/mutable_appearance/underlay_appearance = mutable_appearance(initial(path.icon), initial(path.icon_state), layer = TURF_LAYER, plane = PLANE_SPACE) + underlays += underlay_appearance + return TRUE + + +/turf/open/transparent/glass + name = "Glass floor" + desc = "Dont jump on it, or do, I'm not your mom." + icon = 'icons/turf/floors/glass.dmi' + icon_state = "floor_glass" + smooth = SMOOTH_MORE + var/floor_tile = /obj/item/stack/sheet/glass + canSmoothWith = list(/turf/open/transparent/glass, /turf/open/transparent/glass/reinforced) + footstep = FOOTSTEP_PLATING + barefootstep = FOOTSTEP_HARD_BAREFOOT + clawfootstep = FOOTSTEP_HARD_CLAW + heavyfootstep = FOOTSTEP_GENERIC_HEAVY + +/turf/open/transparent/glass/Initialize() + icon_state = "" //Prevent the normal icon from appearing behind the smooth overlays + return ..() + +/turf/open/transparent/glass/wrench_act(mob/living/user, obj/item/I) + to_chat(user, "You begin removing glass...") + if(I.use_tool(src, user, 30, volume=80)) + if(!istype(src, /turf/open/transparent/glass)) + return TRUE + if(floor_tile) + new floor_tile(src, 2) + ScrapeAway(flags = CHANGETURF_INHERIT_AIR) + return TRUE + +/turf/open/transparent/glass/reinforced + name = "Reinforced glass floor" + desc = "Do jump on it, it can take it." + icon = 'icons/turf/floors/reinf_glass.dmi' + floor_tile = /obj/item/stack/sheet/rglass + +/turf/open/transparent/glass/reinforced/wrench_act(mob/living/user, obj/item/I) + to_chat(user, "You begin removing reinforced glass...") + if(I.use_tool(src, user, 30, volume=80)) + if(!istype(src, /turf/open/transparent/glass/reinforced)) + return TRUE + if(floor_tile) + new floor_tile(src, 2) + ScrapeAway(flags = CHANGETURF_INHERIT_AIR) + return TRUE diff --git a/code/game/turfs/simulated/floor/fancy_floor.dm b/code/game/turfs/simulated/floor/fancy_floor.dm index f940761ff8..5024a4bada 100644 --- a/code/game/turfs/simulated/floor/fancy_floor.dm +++ b/code/game/turfs/simulated/floor/fancy_floor.dm @@ -26,7 +26,8 @@ /turf/open/floor/wood/screwdriver_act(mob/living/user, obj/item/I) if(..()) return TRUE - return pry_tile(I, user) + . = STOP_ATTACK_PROC_CHAIN + pry_tile(I, user) /turf/open/floor/wood/try_replace_tile(obj/item/stack/tile/T, mob/user, params) if(T.turf_type == type) @@ -62,6 +63,11 @@ to_chat(user, "You forcefully pry off the planks, destroying them in the process.") return make_plating() +/turf/open/floor/wood/rust_heretic_act() + if(prob(70)) + new /obj/effect/temp_visual/glowing_rune(src) + ChangeTurf(/turf/open/floor/plating/rust) + /turf/open/floor/wood/cold temperature = 255.37 diff --git a/code/game/turfs/simulated/floor/mineral_floor.dm b/code/game/turfs/simulated/floor/mineral_floor.dm index 8e0230a2b0..fe6ed2da9b 100644 --- a/code/game/turfs/simulated/floor/mineral_floor.dm +++ b/code/game/turfs/simulated/floor/mineral_floor.dm @@ -58,6 +58,12 @@ if(exposed_temperature > 300) PlasmaBurn(exposed_temperature) +// Plasma floor that can't be removed, for disco + +/turf/open/floor/mineral/plasma/disco + name = "disco floor" +/turf/open/floor/mineral/plasma/disco/crowbar_act(mob/living/user, obj/item/I) + return //GOLD diff --git a/code/game/turfs/simulated/floor/misc_floor.dm b/code/game/turfs/simulated/floor/misc_floor.dm index f6e70f8ef5..c70332eacb 100644 --- a/code/game/turfs/simulated/floor/misc_floor.dm +++ b/code/game/turfs/simulated/floor/misc_floor.dm @@ -259,7 +259,7 @@ desc = "Some heavy bronze tiles." icon = 'icons/obj/clockwork_objects.dmi' icon_state = "clockwork_floor" - floor_tile = /obj/item/stack/tile/bronze + floor_tile = /obj/item/stack/sheet/bronze /turf/open/floor/padded name = "padded floor" @@ -267,3 +267,15 @@ icon = 'icons/turf/floors.dmi' icon_state = "floor_padded" floor_tile = /obj/item/stack/tile/padded + +/turf/open/floor/plating/rust + name = "rusted plating" + desc = "Corrupted steel." + icon_state = "plating_rust" + footstep = FOOTSTEP_RUST + barefootstep = FOOTSTEP_RUST + clawfootstep = FOOTSTEP_RUST + heavyfootstep = FOOTSTEP_RUST + +/turf/open/floor/plating/rust/rust_heretic_act() + return diff --git a/code/game/turfs/simulated/floor/plasteel_floor.dm b/code/game/turfs/simulated/floor/plasteel_floor.dm index af48160ef1..614c63a14c 100644 --- a/code/game/turfs/simulated/floor/plasteel_floor.dm +++ b/code/game/turfs/simulated/floor/plasteel_floor.dm @@ -8,6 +8,11 @@ . = ..() . += "There's a small crack on the edge of it." +/turf/open/floor/plasteel/rust_heretic_act() + if(prob(70)) + new /obj/effect/temp_visual/glowing_rune(src) + ChangeTurf(/turf/open/floor/plating/rust) + /turf/open/floor/plasteel/update_icon() if(!..()) return 0 diff --git a/code/game/turfs/simulated/floor/plating.dm b/code/game/turfs/simulated/floor/plating.dm index ac80bddd00..35ee06a584 100644 --- a/code/game/turfs/simulated/floor/plating.dm +++ b/code/game/turfs/simulated/floor/plating.dm @@ -66,6 +66,40 @@ R.use(2) to_chat(user, "You reinforce the floor.") return + if(istype(C, /obj/item/stack/sheet/glass)) + if(broken || burnt) + to_chat(user, "Repair the plating first!") + return + var/obj/item/stack/sheet/glass/G = C + if (G.get_amount() < 2) + to_chat(user, "You need two glass sheets to make a glass floor!") + return + else + to_chat(user, "You begin adding glass to the floor...") + if(do_after(user, 5, target = src)) + if (G.get_amount() >= 2 && !istype(src, /turf/open/transparent/glass)) + PlaceOnTop(/turf/open/transparent/glass, flags = CHANGETURF_INHERIT_AIR) + playsound(src, 'sound/items/deconstruct.ogg', 80, 1) + G.use(2) + to_chat(user, "You add glass to the floor.") + return + if(istype(C, /obj/item/stack/sheet/rglass)) + if(broken || burnt) + to_chat(user, "Repair the plating first!") + return + var/obj/item/stack/sheet/rglass/RG = C + if (RG.get_amount() < 2) + to_chat(user, "You need two reinforced glass sheets to make a reinforced glass floor!") + return + else + to_chat(user, "You begin adding reinforced glass to the floor...") + if(do_after(user, 10, target = src)) + if (RG.get_amount() >= 2 && !istype(src, /turf/open/transparent/glass/reinforced)) + PlaceOnTop(/turf/open/transparent/glass/reinforced, flags = CHANGETURF_INHERIT_AIR) + playsound(src, 'sound/items/deconstruct.ogg', 80, 1) + RG.use(2) + to_chat(user, "You add reinforced glass to the floor.") + return else if(istype(C, /obj/item/stack/tile)) if(!broken && !burnt) for(var/obj/O in src) @@ -98,6 +132,11 @@ return TRUE +/turf/open/floor/plating/rust_heretic_act() + if(prob(70)) + new /obj/effect/temp_visual/glowing_rune(src) + ChangeTurf(/turf/open/floor/plating/rust) + /turf/open/floor/plating/make_plating() return diff --git a/code/game/turfs/simulated/floor/plating/asteroid.dm b/code/game/turfs/simulated/floor/plating/asteroid.dm index 1fbeee7523..6e7dbaf904 100644 --- a/code/game/turfs/simulated/floor/plating/asteroid.dm +++ b/code/game/turfs/simulated/floor/plating/asteroid.dm @@ -149,6 +149,8 @@ var/list/megafauna_spawn_list /// Flora that can spawn in the tunnel, weighted list var/list/flora_spawn_list + //terrain to spawn weighted list + var/list/terrain_spawn_list /// Turf type to choose when spawning in tunnel at 1% chance, weighted list var/list/choose_turf_type /// if the tunnel should keep being created @@ -230,7 +232,8 @@ megafauna_spawn_list = list(/mob/living/simple_animal/hostile/megafauna/dragon = 4, /mob/living/simple_animal/hostile/megafauna/colossus = 2, /mob/living/simple_animal/hostile/megafauna/bubblegum = SPAWN_BUBBLEGUM) if (!flora_spawn_list) flora_spawn_list = list(/obj/structure/flora/ash/leaf_shroom = 2 , /obj/structure/flora/ash/cap_shroom = 2 , /obj/structure/flora/ash/stem_shroom = 2 , /obj/structure/flora/ash/cacti = 1, /obj/structure/flora/ash/tall_shroom = 2) - + if(!terrain_spawn_list) + terrain_spawn_list = list(/obj/structure/geyser/random = 1) . = ..() if(!has_data) produce_tunnel_from_data() @@ -334,8 +337,19 @@ spawned_flora = SpawnFlora(T) if(!spawned_flora) // no rocks beneath mob spawners / mobs. SpawnMonster(T) + SpawnTerrain(T) T.ChangeTurf(turf_type, null, CHANGETURF_IGNORE_AIR) +/turf/open/floor/plating/asteroid/airless/cave/proc/SpawnTerrain(turf/T) + if(prob(1)) + if(istype(loc, /area/mine/explored) || istype(loc, /area/lavaland/surface/outdoors/explored)) + return + var/randumb = pickweight(terrain_spawn_list) + for(var/obj/structure/geyser/F in range(7, T)) + if(istype(F, randumb)) + return + new randumb(T) + /// Spawns a random mob or megafauna in the tunnel /turf/open/floor/plating/asteroid/airless/cave/proc/SpawnMonster(turf/T) if(!isarea(loc)) diff --git a/code/game/turfs/simulated/wall/mineral_walls.dm b/code/game/turfs/simulated/wall/mineral_walls.dm index 4466511acd..ed48c24462 100644 --- a/code/game/turfs/simulated/wall/mineral_walls.dm +++ b/code/game/turfs/simulated/wall/mineral_walls.dm @@ -192,6 +192,7 @@ icon_state = "map-shuttle" explosion_block = 3 flags_1 = CAN_BE_DIRTY_1 | DEFAULT_RICOCHET_1 + flags_ricochet = RICOCHET_SHINY | RICOCHET_HARD sheet_type = /obj/item/stack/sheet/mineral/titanium smooth = SMOOTH_MORE|SMOOTH_DIAGONAL canSmoothWith = list(/turf/closed/wall/mineral/titanium, /obj/machinery/door/airlock/shuttle, /obj/machinery/door/airlock, /obj/structure/window/shuttle, /obj/structure/shuttle/engine/heater, /obj/structure/falsewall/titanium) diff --git a/code/game/turfs/simulated/wall/misc_walls.dm b/code/game/turfs/simulated/wall/misc_walls.dm index d445be91cb..e4d991a082 100644 --- a/code/game/turfs/simulated/wall/misc_walls.dm +++ b/code/game/turfs/simulated/wall/misc_walls.dm @@ -188,17 +188,25 @@ icon = 'icons/turf/walls/rusty_wall.dmi' hardness = 45 +/turf/closed/wall/rust/rust_heretic_act() + ScrapeAway() + /turf/closed/wall/r_wall/rust name = "rusted reinforced wall" desc = "A huge chunk of rusted reinforced metal." icon = 'icons/turf/walls/rusty_reinforced_wall.dmi' hardness = 15 +/turf/closed/wall/r_wall/rust/rust_heretic_act() + if(prob(50)) + return + ScrapeAway() + /turf/closed/wall/mineral/bronze name = "clockwork wall" desc = "A huge chunk of bronze, decorated like gears and cogs." icon = 'icons/turf/walls/clockwork_wall.dmi' icon_state = "clockwork_wall" - sheet_type = /obj/item/stack/tile/bronze + sheet_type = /obj/item/stack/sheet/bronze sheet_amount = 2 girder_type = /obj/structure/girder/bronze diff --git a/code/game/turfs/simulated/wall/reinf_walls.dm b/code/game/turfs/simulated/wall/reinf_walls.dm index 6b41f41763..5e60f65ccc 100644 --- a/code/game/turfs/simulated/wall/reinf_walls.dm +++ b/code/game/turfs/simulated/wall/reinf_walls.dm @@ -235,6 +235,13 @@ if(the_rcd.canRturf) return ..() +/turf/closed/wall/r_wall/rust_heretic_act() + if(prob(50)) + return + if(prob(70)) + new /obj/effect/temp_visual/glowing_rune(src) + ChangeTurf(/turf/closed/wall/r_wall/rust) + /turf/closed/wall/r_wall/syndicate name = "hull" desc = "The armored hull of an ominous looking ship." diff --git a/code/game/turfs/simulated/walls.dm b/code/game/turfs/simulated/walls.dm index 0623f2b9d2..9ff4f668a4 100644 --- a/code/game/turfs/simulated/walls.dm +++ b/code/game/turfs/simulated/walls.dm @@ -6,7 +6,8 @@ icon = 'icons/turf/walls/wall.dmi' icon_state = "wall" explosion_block = 1 - + flags_1 = DEFAULT_RICOCHET_1 + flags_ricochet = RICOCHET_HARD thermal_conductivity = WALL_HEAT_TRANSFER_COEFFICIENT heat_capacity = 312500 //a little over 5 cm thick , 312500 for 1 m by 2.5 m by 0.25 m plasteel wall attack_hand_speed = 8 @@ -324,4 +325,9 @@ add_overlay(dent_decals) +/turf/closed/wall/rust_heretic_act() + if(prob(70)) + new /obj/effect/temp_visual/glowing_rune(src) + ChangeTurf(/turf/closed/wall/rust) + #undef MAX_DENT_DECALS diff --git a/code/game/world.dm b/code/game/world.dm index 55333fb3e6..a342200b3d 100644 --- a/code/game/world.dm +++ b/code/game/world.dm @@ -12,6 +12,9 @@ GLOBAL_LIST(topic_status_cache) if (fexists(EXTOOLS)) call(EXTOOLS, "maptick_initialize")() enable_debugger() +#ifdef REFERENCE_TRACKING + enable_reference_tracking() +#endif world.Profile(PROFILE_START) diff --git a/code/modules/NTNet/relays.dm b/code/modules/NTNet/relays.dm index c64e2332cc..8c33dd1eba 100644 --- a/code/modules/NTNet/relays.dm +++ b/code/modules/NTNet/relays.dm @@ -9,8 +9,6 @@ icon_state = "bus" density = TRUE circuit = /obj/item/circuitboard/machine/ntnet_relay - ui_x = 400 - ui_y = 300 var/datum/ntnet/NTNet = null // This is mostly for backwards reference and to allow varedit modifications from ingame. var/enabled = 1 // Set to 0 if the relay was turned off @@ -64,15 +62,12 @@ SSnetworks.station_network.add_log("Quantum relay switched from overload recovery mode to normal operation mode.") ..() -/obj/machinery/ntnet_relay/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) - - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) - +/obj/machinery/ntnet_relay/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) if(!ui) - ui = new(user, src, ui_key, "NtnetRelay", "NTNet Quantum Relay", ui_x, ui_y, master_ui, state) + ui = new(user, src, "NtnetRelay") ui.open() - /obj/machinery/ntnet_relay/ui_data(mob/user) var/list/data = list() data["enabled"] = enabled @@ -81,7 +76,6 @@ data["dos_crashed"] = dos_failure return data - /obj/machinery/ntnet_relay/ui_act(action, params) if(..()) return diff --git a/code/modules/VR/vr_sleeper.dm b/code/modules/VR/vr_sleeper.dm index 9953fe4bc5..cc59fe10ab 100644 --- a/code/modules/VR/vr_sleeper.dm +++ b/code/modules/VR/vr_sleeper.dm @@ -78,10 +78,15 @@ close_machine(target) ui_interact(user) -/obj/machinery/vr_sleeper/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_contained_state) - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) +/obj/machinery/vr_sleeper/ui_state(mob/user) + if(user == occupant) + return GLOB.contained_state + return GLOB.default_state + +/obj/machinery/vr_sleeper/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) if(!ui) - ui = new(user, src, ui_key, "VrSleeper", "VR Sleeper", 475, 340, master_ui, state) + ui = new(user, src, "VrSleeper", "VR Sleeper") ui.open() /obj/machinery/vr_sleeper/ui_act(action, params) diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm index 718f9d4246..e9abb7db87 100644 --- a/code/modules/admin/admin_verbs.dm +++ b/code/modules/admin/admin_verbs.dm @@ -171,7 +171,11 @@ GLOBAL_LIST_INIT(admin_verbs_debug, world.AVerbsDebug()) /client/proc/cmd_display_overlay_log, /client/proc/reload_configuration, /datum/admins/proc/create_or_modify_area, - /client/proc/generate_wikichem_list //DO NOT PRESS UNLESS YOU WANT SUPERLAG +#ifdef REFERENCE_TRACKING + /datum/admins/proc/view_refs, + /datum/admins/proc/view_del_failures, +#endif + /client/proc/generate_wikichem_list, //DO NOT PRESS UNLESS YOU WANT SUPERLAG ) GLOBAL_PROTECT(admin_verbs_debug) GLOBAL_LIST_INIT(admin_verbs_possess, list(/proc/possess, /proc/release)) diff --git a/code/modules/admin/chat_commands.dm b/code/modules/admin/chat_commands.dm index 7664d85b7d..bab74300f5 100644 --- a/code/modules/admin/chat_commands.dm +++ b/code/modules/admin/chat_commands.dm @@ -150,7 +150,7 @@ GLOBAL_LIST(round_end_notifiees) /datum/tgs_chat_command/wheelofsalt/Run(datum/tgs_chat_user/sender, params) var/saltresult = "The wheel of salt [pick("clatters","screams","vibrates","clanks","resonates","groans","moans","squeaks","emits a[pick(" god-forsaken"," lewd"," creepy"," generic","n orgasmic"," demonic")] [pick("airhorn","bike horn","trumpet","clown","latex","vore","dog","laughing")] noise")] as it spins violently... And it seems the salt of the day is the " - var/saltprimarysubject = "[pick("combat","medical","grab","furry","wall","orgasm","cat","ERP","lizard","dog","latex","vision cone","atmospherics","table","chem","vore","dogborg","Skylar Lineman","Mekhi Anderson","Peppermint","rework","cum","dick","cockvore","Medihound","sleeper","belly sleeper","door wires","flightsuit","coder privilege","Developer abuse","ban reason","github self merge","red panda","beret","male catgirl","powergame","hexacrocin","Discord server","Clitadel","Cargonia","Solarian Republic","Main and RP merger","bluespace","salt","chem dispenser theft","Botany","moth","BWOINK","anal vore","stamina","Mason Jakops","mining","noodle","milf","Lavaland","Necropolis","Ashwalker","Chase Redtail","Drew Mint","Pavel Marsk","Joker Amari","Durgit","chaplain","Antag","nanite","Syndicate","Nar-Sie","Ratvar","Cult","maint","Foam-Force","AI","cyborg","ghost","clockwork","cyberpunk","vaporwave","Clown","Leon Beech","Mime","security","research","Megafauna","Bubblegum","Ash Drake","Legion","Colossus","White Shuttle","Changeling","Cowboy","Space Ninja","Poly","Revolutionary","Skyrim","forbidden fruits","xenomorph","blob","Nuclear Operative","crossdressing")]" + var/saltprimarysubject = "[pick("combat","medical","grab","furry","wall","orgasm","cat","ERP","lizard","dog","latex","vision cone","atmospherics","table","chem","vore","dogborg","Skylar Lineman","Mekhi Anderson","Peppermint","rework","cum","dick","cockvore","Medihound","sleeper","belly sleeper","door wires","flightsuit","coder privilege","Developer abuse","ban reason","github self merge","red panda","beret","male catgirl","powergame","hexacrocin removal","Discord server","Clitadel","Cargonia","Solarian Republic","Main and RP merger","bluespace","salt","chem dispenser theft","Botany","moth","BWOINK","anal vore","stamina","Mason Jakops","mining","noodle","milf","Lavaland","Necropolis","Ashwalker","Chase Redtail","Drew Mint","Pavel Marsk","Joker Amari","Durgit","chaplain","Antag","nanite","Syndicate","Nar-Sie","Ratvar","Cult","maint","Foam-Force","AI","cyborg","ghost","clockwork","cyberpunk","vaporwave","Clown","Leon Beech","Mime","security","research","Megafauna","Bubblegum","Ash Drake","Legion","Colossus","White Shuttle","Changeling","Cowboy","Space Ninja","Poly","Revolutionary","Skyrim","forbidden fruits","xenomorph","blob","Nuclear Operative","crossdressing")]" var/saltsecondarysubject = "[pick("rework","changes","r34","ban","removal","addition","leak","proposal","fanart","introduction","tabling","ERP","bikeshedding","crossdressing","sprites","semen keg","argument","theft","nerf","screeching","salt","creampie","lewding","murder","kissing","marriage","replacement","fucking","ship","netflix adaptation","dance","remaster","system","voyeur","decoration","pre-order","bukkake","seduction","worship","gangbang","handholding")]" if(prob(10)) saltresult += "@here for your salt, all day every day" diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm index 41c3fe5105..13e8877440 100644 --- a/code/modules/admin/topic.dm +++ b/code/modules/admin/topic.dm @@ -2184,8 +2184,18 @@ if(!ishuman(H)) to_chat(usr, "This can only be used on instances of type /mob/living/carbon/human.") return - - var/obj/item/reagent_containers/food/snacks/cookie/cookie = new(H) + //let's keep it simple + //milk to plasmemes and skeletons, meat to lizards, electricity bars to ethereals, cookies to everyone else + var/cookiealt = /obj/item/reagent_containers/food/snacks/cookie + if(isskeleton(H)) + cookiealt = /obj/item/reagent_containers/food/condiment/milk + else if(isplasmaman(H)) + cookiealt = /obj/item/reagent_containers/food/condiment/milk + else if(isethereal(H)) + cookiealt = /obj/item/reagent_containers/food/snacks/energybar + else if(islizard(H)) + cookiealt = /obj/item/reagent_containers/food/snacks/meat/slab + var/obj/item/cookie = new cookiealt(H) if(H.put_in_hands(cookie)) H.update_inv_hands() else diff --git a/code/modules/admin/verbs/adminhelp.dm b/code/modules/admin/verbs/adminhelp.dm index 14cf0d7ee2..edf95dc47e 100644 --- a/code/modules/admin/verbs/adminhelp.dm +++ b/code/modules/admin/verbs/adminhelp.dm @@ -254,6 +254,7 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new) //message from the initiator without a target, all admins will see this //won't bug irc /datum/admin_help/proc/MessageNoRecipient(msg) + msg = sanitize(copytext_char(msg, 1, MAX_MESSAGE_LEN)) var/ref_src = "[REF(src)]" //Message to be sent to all admins var/admin_msg = "Ticket [TicketHref("#[id]", ref_src)]: [LinkedReplyName(ref_src)] [FullMonty(ref_src)]: [keywords_lookup(msg)]" @@ -371,8 +372,7 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new) return var/msg = "- AdminHelp marked as IC issue by [usr?.client?.holder?.fakekey? usr.client.holder.fakekey : "an administrator"]! -
" - msg += "Losing is part of the game!
" - msg += "It is also possible that your ahelp is unable to be answered properly, due to events occurring in the round." + msg += "Your ahelp is unable to be answered properly due to events occurring in the round. Your question probably has an IC answer, which means you should deal with it IC!" if(initiator) to_chat(initiator, msg) diff --git a/code/modules/admin/verbs/adminpm.dm b/code/modules/admin/verbs/adminpm.dm index 68b9a8e341..b7f05740a3 100644 --- a/code/modules/admin/verbs/adminpm.dm +++ b/code/modules/admin/verbs/adminpm.dm @@ -55,7 +55,7 @@ if(AH) message_admins("[key_name_admin(src)] has started replying to [key_name(C, 0, 0)]'s admin help.") - var/msg = stripped_multiline_input(src,"Message:", "Private message to [key_name(C, 0, 0)]") + var/msg = input(src,"Message:", "Private message to [C.holder?.fakekey ? "an Administrator" : key_name(C, 0, 0)].") as message|null if (!msg) message_admins("[key_name_admin(src)] has cancelled their reply to [key_name(C, 0, 0)]'s admin help.") return @@ -90,7 +90,7 @@ if(!ircreplyamount) //to prevent people from spamming irc/discord return if(!msg) - msg = stripped_multiline_input(src,"Message:", "Private message to Administrator") + msg = input(src,"Message:", "Private message to Administrator") as message|null if(!msg) return @@ -112,7 +112,7 @@ //get message text, limit it's length.and clean/escape html if(!msg) - msg = stripped_multiline_input(src,"Message:", "Private message to [key_name(recipient, 0, 0)]") + msg = input(src,"Message:", "Private message to [recipient.holder?.fakekey ? "an Administrator" : key_name(recipient, 0, 0)].") as message|null msg = trim(msg) if(!msg) return @@ -133,7 +133,7 @@ //clean the message if it's not sent by a high-rank admin if(!check_rights(R_SERVER|R_DEBUG,0)||irc)//no sending html to the poor bots - msg = trim(sanitize(msg), MAX_MESSAGE_LEN) + msg = sanitize(copytext_char(msg, 1, MAX_MESSAGE_LEN)) if(!msg) return @@ -188,10 +188,10 @@ //AdminPM popup for ApocStation and anybody else who wants to use it. Set it with POPUP_ADMIN_PM in config.txt ~Carn if(CONFIG_GET(flag/popup_admin_pm)) - spawn() //so we don't hold the caller proc up + spawn() //so we don't hold the caller proc up. Please functionalize this var/sender = src var/sendername = key - var/reply = stripped_multiline_input(recipient, msg,"Admin PM from-[sendername]", "") //show message and await a reply + var/reply = input(recipient, msg,"Admin PM from-[sendername]", "") as message|null //show message and await a reply if(recipient && reply) if(sender) recipient.cmd_admin_pm(sender,reply) //sender is still about, let's reply to them diff --git a/code/modules/admin/view_variables/reference_tracking.dm b/code/modules/admin/view_variables/reference_tracking.dm new file mode 100644 index 0000000000..70aac2f107 --- /dev/null +++ b/code/modules/admin/view_variables/reference_tracking.dm @@ -0,0 +1,225 @@ +#ifdef REFERENCE_TRACKING + +GLOBAL_LIST_EMPTY(deletion_failures) + +/world/proc/enable_reference_tracking() + if (fexists(EXTOOLS)) + call(EXTOOLS, "ref_tracking_initialize")() + +/proc/get_back_references(datum/D) + CRASH("/proc/get_back_references not hooked by extools, reference tracking will not function!") + +/proc/get_forward_references(datum/D) + CRASH("/proc/get_forward_references not hooked by extools, reference tracking will not function!") + +/proc/clear_references(datum/D) + return + +/datum/admins/proc/view_refs(atom/D in world) //it actually supports datums as well but byond no likey + set category = "Debug" + set name = "View References" + + if(!check_rights(R_DEBUG) || !D) + return + + var/list/backrefs = get_back_references(D) + if(isnull(backrefs)) + var/datum/browser/popup = new(usr, "ref_view", "
Error
") + popup.set_content("Reference tracking not enabled") + popup.open(FALSE) + return + + var/list/frontrefs = get_forward_references(D) + var/list/dat = list() + dat += "

References of \ref[D] - [D]


\[Refresh\]
" + dat += "

Back references - these things hold references to this object.

" + dat += "" + dat += "" + for(var/ref in backrefs) + var/datum/backreference = ref + if(isnull(backreference)) + dat += "" + if(istype(backreference)) + dat += "" + else if(islist(backreference)) + dat += "" + else + dat += "" + dat += "
RefTypeVariable NameFollow
GC'd Reference
[REF(backreference)][backreference.type][backrefs[backreference]]\[Follow\]
[REF(backreference)]list[backrefs[backreference]]\[Follow\]
Weird reference type. Add more debugging checks.

" + dat += "

Forward references - this object is referencing those things.

" + dat += "" + dat += "" + for(var/ref in frontrefs) + var/datum/backreference = frontrefs[ref] + dat += "" + dat += "
Variable nameRefTypeFollow
[ref][REF(backreference)][backreference.type]\[Follow\]

" + dat = dat.Join() + + var/datum/browser/popup = new(usr, "ref_view", "
References of \ref[D]
") + popup.set_content(dat) + popup.open(FALSE) + + +/datum/admins/proc/view_del_failures() + set category = "Debug" + set name = "View Deletion Failures" + + if(!check_rights(R_DEBUG)) + return + + var/list/dat = list("") + for(var/t in GLOB.deletion_failures) + if(isnull(t)) + dat += "" + continue + var/datum/thing = t + dat += "" + dat += "
GC'd Reference | Clear Nulls
\ref[thing] | [thing.type][thing.gc_destroyed ? " (destroyed)" : ""] [ADMIN_VV(thing)]

" + dat = dat.Join() + + var/datum/browser/popup = new(usr, "del_failures", "
Deletion Failures
") + popup.set_content(dat) + popup.open(FALSE) + + +/datum/proc/find_references() + testing("Beginning search for references to a [type].") + var/list/backrefs = get_back_references(src) + for(var/ref in backrefs) + if(isnull(ref)) + log_world("## TESTING: Datum reference found, but gone now.") + continue + if(islist(ref)) + log_world("## TESTING: Found [type] \ref[src] in list.") + continue + var/datum/datum_ref = ref + if(!istype(datum_ref)) + log_world("## TESTING: Found [type] \ref[src] in unknown type reference: [datum_ref].") + return + log_world("## TESTING: Found [type] \ref[src] in [datum_ref.type][datum_ref.gc_destroyed ? " (destroyed)" : ""]") + message_admins("Found [type] \ref[src] [ADMIN_VV(src)] in [datum_ref.type][datum_ref.gc_destroyed ? " (destroyed)" : ""] [ADMIN_VV(datum_ref)]") + testing("Completed search for references to a [type].") + +#endif + +#ifdef LEGACY_REFERENCE_TRACKING + +/datum/verb/legacy_find_refs() + set category = "Debug" + set name = "Find References" + set src in world + + find_references(FALSE) + + +/datum/proc/find_references_legacy(skip_alert) + running_find_references = type + if(usr?.client) + if(usr.client.running_find_references) + testing("CANCELLED search for references to a [usr.client.running_find_references].") + usr.client.running_find_references = null + running_find_references = null + //restart the garbage collector + SSgarbage.can_fire = TRUE + SSgarbage.next_fire = world.time + world.tick_lag + return + + if(!skip_alert && alert("Running this will lock everything up for about 5 minutes. Would you like to begin the search?", "Find References", "Yes", "No") != "Yes") + running_find_references = null + return + + //this keeps the garbage collector from failing to collect objects being searched for in here + SSgarbage.can_fire = FALSE + + if(usr?.client) + usr.client.running_find_references = type + + testing("Beginning search for references to a [type].") + last_find_references = world.time + + DoSearchVar(GLOB) //globals + for(var/datum/thing in world) //atoms (don't beleive its lies) + DoSearchVar(thing, "World -> [thing]") + + for(var/datum/thing) //datums + DoSearchVar(thing, "World -> [thing]") + + for(var/client/thing) //clients + DoSearchVar(thing, "World -> [thing]") + + testing("Completed search for references to a [type].") + if(usr?.client) + usr.client.running_find_references = null + running_find_references = null + + //restart the garbage collector + SSgarbage.can_fire = TRUE + SSgarbage.next_fire = world.time + world.tick_lag + + +/datum/verb/qdel_then_find_references() + set category = "Debug" + set name = "qdel() then Find References" + set src in world + + qdel(src, TRUE) //force a qdel + if(!running_find_references) + find_references(TRUE) + + +/datum/verb/qdel_then_if_fail_find_references() + set category = "Debug" + set name = "qdel() then Find References if GC failure" + set src in world + + qdel_and_find_ref_if_fail(src, TRUE) + + +/datum/proc/DoSearchVar(potential_container, container_name, recursive_limit = 64) + if(usr?.client && !usr.client.running_find_references) + return + + if(!recursive_limit) + return + + if(istype(potential_container, /datum)) + var/datum/datum_container = potential_container + if(datum_container.last_find_references == last_find_references) + return + + datum_container.last_find_references = last_find_references + var/list/vars_list = datum_container.vars + + for(var/varname in vars_list) + if (varname == "vars") + continue + var/variable = vars_list[varname] + + if(variable == src) + testing("Found [type] \ref[src] in [datum_container.type]'s [varname] var. [container_name]") + + else if(islist(variable)) + DoSearchVar(variable, "[container_name] -> list", recursive_limit - 1) + + else if(islist(potential_container)) + var/normal = IS_NORMAL_LIST(potential_container) + for(var/element_in_list in potential_container) + if(element_in_list == src) + testing("Found [type] \ref[src] in list [container_name].") + + else if(element_in_list && !isnum(element_in_list) && normal && potential_container[element_in_list] == src) + testing("Found [type] \ref[src] in list [container_name]\[[element_in_list]\]") + + else if(islist(element_in_list)) + DoSearchVar(element_in_list, "[container_name] -> list", recursive_limit - 1) + + #ifndef FIND_REF_NO_CHECK_TICK + CHECK_TICK + #endif + + +/proc/qdel_and_find_ref_if_fail(datum/thing_to_del, force = FALSE) + SSgarbage.reference_find_on_fail[REF(thing_to_del)] = TRUE + qdel(thing_to_del, force) + +#endif diff --git a/code/modules/admin/view_variables/topic_basic.dm b/code/modules/admin/view_variables/topic_basic.dm index d6e4c2b944..9ee7103562 100644 --- a/code/modules/admin/view_variables/topic_basic.dm +++ b/code/modules/admin/view_variables/topic_basic.dm @@ -45,6 +45,16 @@ usr.client.admin_delete(target) if (isturf(src)) // show the turf that took its place usr.client.debug_variables(src) + return + #ifdef REFERENCE_TRACKING + if(href_list[VV_HK_VIEW_REFERENCES]) + var/datum/D = locate(href_list[VV_HK_TARGET]) + if(!D) + to_chat(usr, "Unable to locate item.") + return + usr.client.holder.view_refs(target) + return + #endif if(href_list[VV_HK_MARK]) usr.client.mark_datum(target) if(href_list[VV_HK_ADDCOMPONENT]) diff --git a/code/modules/admin/view_variables/view_variables.dm b/code/modules/admin/view_variables/view_variables.dm index abe445589f..a4dff725f7 100644 --- a/code/modules/admin/view_variables/view_variables.dm +++ b/code/modules/admin/view_variables/view_variables.dm @@ -61,6 +61,7 @@ "Set len" = VV_HREF_TARGETREF_INTERNAL(refid, VV_HK_LIST_SET_LENGTH), "Shuffle" = VV_HREF_TARGETREF_INTERNAL(refid, VV_HK_LIST_SHUFFLE), "Show VV To Player" = VV_HREF_TARGETREF_INTERNAL(refid, VV_HK_EXPOSE), + "View References" = VV_HREF_TARGETREF_INTERNAL(refid, VV_HK_VIEW_REFERENCES), "---" ) for(var/i in 1 to length(dropdownoptions)) diff --git a/code/modules/antagonists/_common/antag_datum.dm b/code/modules/antagonists/_common/antag_datum.dm index 8bff37ab03..14f7b34309 100644 --- a/code/modules/antagonists/_common/antag_datum.dm +++ b/code/modules/antagonists/_common/antag_datum.dm @@ -14,6 +14,8 @@ GLOBAL_LIST_EMPTY(antagonists) var/list/objectives = list() var/antag_memory = ""//These will be removed with antag datum var/antag_moodlet //typepath of moodlet that the mob will gain with their status + var/antag_hud_type + var/antag_hud_name /// If above 0, this is the multiplier for the speed at which we hijack the shuttle. Do not directly read, use hijack_speed(). var/hijack_speed = 0 @@ -77,6 +79,17 @@ GLOBAL_LIST_EMPTY(antagonists) hud.leave_hud(mob_override) set_antag_hud(mob_override, null) +// Handles adding and removing the clumsy mutation from clown antags. Gets called in apply/remove_innate_effects +/datum/antagonist/proc/handle_clown_mutation(mob/living/mob_override, message, removing = TRUE) + var/mob/living/carbon/human/H = mob_override + if(H && istype(H) && owner.assigned_role == "Clown") + if(removing) // They're a clown becoming an antag, remove clumsy + H.dna.remove_mutation(CLOWNMUT) + if(!silent && message) + to_chat(H, "[message]") + else + H.dna.add_mutation(CLOWNMUT) // We're removing their antag status, add back clumsy + //Assign default team and creates one for one of a kind team antagonists /datum/antagonist/proc/create_team(datum/team/team) return @@ -268,7 +281,6 @@ GLOBAL_LIST_EMPTY(antagonists) . = CONFIG_GET(keyed_list/antag_threat)[lowertext(name)] if(. == null) return threat - return threat //This one is created by admin tools for custom objectives /datum/antagonist/custom diff --git a/code/modules/antagonists/abductor/equipment/orderable_gear.dm b/code/modules/antagonists/abductor/equipment/orderable_gear.dm new file mode 100644 index 0000000000..f21294b041 --- /dev/null +++ b/code/modules/antagonists/abductor/equipment/orderable_gear.dm @@ -0,0 +1,79 @@ +GLOBAL_LIST_INIT(abductor_gear, subtypesof(/datum/abductor_gear)) + +/datum/abductor_gear + /// Name of the gear + var/name = "Generic Abductor Gear" + /// Description of the gear + var/description = "Generic description." + /// Unique ID of the gear + var/id = "abductor_generic" + /// Credit cost of the gear + var/cost = 1 + /// Build path of the gear itself + var/build_path = null + /// Category of the gear + var/category = "Basic Gear" + +/datum/abductor_gear/agent_helmet + name = "Agent Helmet" + description = "Abduct with style - spiky style. Prevents digital tracking." + id = "agent_helmet" + build_path = /obj/item/clothing/head/helmet/abductor + +/datum/abductor_gear/agent_vest + name = "Agent Vest" + description = "A vest outfitted with advanced stealth technology. It has two modes - combat and stealth." + id = "agent_vest" + build_path = /obj/item/clothing/suit/armor/abductor/vest + +/datum/abductor_gear/radio_silencer + name = "Radio Silencer" + description = "A compact device used to shut down communications equipment." + id = "radio_silencer" + build_path = /obj/item/abductor/silencer + +/datum/abductor_gear/science_tool + name = "Science Tool" + description = "A dual-mode tool for retrieving specimens and scanning appearances. Scanning can be done through cameras." + id = "science_tool" + build_path = /obj/item/abductor/gizmo + +/datum/abductor_gear/advanced_baton + name = "Advanced Baton" + description = "A quad-mode baton used for incapacitation and restraining of specimens." + id = "advanced_baton" + cost = 2 + build_path = /obj/item/abductor/baton //does not exist? + +/datum/abductor_gear/superlingual_matrix + name = "Superlingual Matrix" + description = "A mysterious structure that allows for instant communication between users. Pretty impressive until you need to eat something." + id = "superlingual_matrix" + build_path = /obj/item/organ/tongue/abductor + category = "Advanced Gear" + +/datum/abductor_gear/mental_interface + name = "Mental Interface Device" + description = "A dual-mode tool for directly communicating with sentient brains. It can be used to send a direct message to a target, \ + or to send a command to a test subject with a charged gland." + id = "mental_interface" + cost = 2 + build_path = /obj/item/abductor/mind_device + category = "Advanced Gear" + +/datum/abductor_gear/reagent_synthesizer + name = "Reagent Synthesizer" + description = "Synthesizes a variety of reagents using proto-matter." + id = "reagent_synthesizer" + cost = 2 + build_path = /obj/item/abductor_machine_beacon/chem_dispenser + category = "Advanced Gear" + +/datum/abductor_gear/shrink_ray + name = "Shrink Ray Blaster" + description = "This is a piece of frightening alien tech that enhances the magnetic pull of atoms in a localized space to temporarily make an object shrink. \ + That or it's just space magic. Either way, it shrinks stuff." + id = "shrink_ray" + cost = 2 + build_path = /obj/item/gun/energy/shrink_ray + category = "Advanced Gear" diff --git a/code/modules/antagonists/abductor/machinery/console.dm b/code/modules/antagonists/abductor/machinery/console.dm index 6a981b36dc..2e244fa272 100644 --- a/code/modules/antagonists/abductor/machinery/console.dm +++ b/code/modules/antagonists/abductor/machinery/console.dm @@ -23,99 +23,121 @@ var/obj/machinery/abductor/pad/pad var/obj/machinery/computer/camera_advanced/abductor/camera var/list/datum/icon_snapshot/disguises = list() + /// Currently selected gear category + var/selected_cat + /// Dictates if the compact mode of the interface is on or off + var/compact_mode = FALSE + /// Possible gear to be dispensed + var/list/possible_gear + +/obj/machinery/abductor/console/Initialize(mapload) + . = ..() + possible_gear = get_abductor_gear() + +/** + * get_abductor_gear: Returns a list of a filtered abductor gear sorted by categories + */ +/obj/machinery/abductor/console/proc/get_abductor_gear() + var/list/filtered_modules = list() + for(var/path in GLOB.abductor_gear) + var/datum/abductor_gear/AG = new path + if(!filtered_modules[AG.category]) + filtered_modules[AG.category] = list() + filtered_modules[AG.category][AG] = AG + return filtered_modules /obj/machinery/abductor/console/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) if(!HAS_TRAIT(user, TRAIT_ABDUCTOR_TRAINING) && !HAS_TRAIT(user.mind, TRAIT_ABDUCTOR_TRAINING)) to_chat(user, "You start mashing alien buttons at random!") if(do_after(user,100, target = src)) TeleporterSend() - return - user.set_machine(src) - var/dat = "" - dat += "

Abductsoft 3000

" +/obj/machinery/abductor/console/ui_status(mob/user) + if(!isabductor(user) && !isobserver(user)) + return UI_CLOSE + return ..() + +/obj/machinery/abductor/console/ui_state(mob/user) + return GLOB.physical_state + +/obj/machinery/abductor/console/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "AbductorConsole", name) + ui.open() + +/obj/machinery/abductor/console/ui_static_data(mob/user) + var/list/data = list() + data["categories"] = list() + for(var/category in possible_gear) + var/list/cat = list( + "name" = category, + "items" = (category == selected_cat ? list() : null)) + for(var/gear in possible_gear[category]) + var/datum/abductor_gear/AG = possible_gear[category][gear] + cat["items"] += list(list( + "name" = AG.name, + "cost" = AG.cost, + "desc" = AG.description, + )) + data["categories"] += list(cat) + return data + +/obj/machinery/abductor/console/ui_data(mob/user) + var/list/data = list() + data["compactMode"] = compact_mode + data["experiment"] = experiment ? TRUE : FALSE if(experiment) - var/points = experiment.points - var/credits = experiment.credits - dat += "Collected Samples : [points]
" - dat += "Gear Credits: [credits]
" - dat += "Transfer data in exchange for supplies:
" - dat += "Advanced Baton (2 Credits)
" - dat += "Mental Interface Device (2 Credits)
" - dat += "Reagent Synthesizer (2 Credits)
" - dat += "Agent Helmet (1 Credit)
" - dat += "Agent Vest (1 Credit)
" - dat += "Radio Silencer (1 Credit)
" - dat += "Science Tool (1 Credit)
" - dat += "Superlingual Matrix (1 Credit)
" - else - dat += "NO EXPERIMENT MACHINE DETECTED
" - + data["points"] = experiment.points + data["credits"] = experiment.credits + data["pad"] = pad ? TRUE : FALSE if(pad) - dat += "Emergency Teleporter System." - dat += "Consider using primary observation console first." - dat += "Activate Teleporter
" - if(gizmo && gizmo.marked) - dat += "Retrieve Mark
" - else - dat += "Retrieve Mark
" - else - dat += "NO TELEPAD DETECTED
" - + data["gizmo"] = gizmo && gizmo.marked ? TRUE : FALSE + data["vest"] = vest ? TRUE : FALSE if(vest) - dat += "

Agent Vest Mode


" - var/mode = vest.mode - if(mode == VEST_STEALTH) - dat += "Combat" - dat += "Stealth" - else - dat += "Combat" - dat += "Stealth" + data["vest_mode"] = vest.mode + data["vest_lock"] = HAS_TRAIT_FROM(vest, TRAIT_NODROP, ABDUCTOR_VEST_TRAIT) + return data - dat+="
" - dat += "Select Agent Vest Disguise
" - dat += "[HAS_TRAIT_FROM(vest, TRAIT_NODROP, ABDUCTOR_VEST_TRAIT) ? "Unlock" : "Lock"] Vest
" - else - dat += "NO AGENT VEST DETECTED" - var/datum/browser/popup = new(user, "computer", "Abductor Console", 400, 500) - popup.set_content(dat) - popup.open() - -/obj/machinery/abductor/console/Topic(href, href_list) - if(..()) +/obj/machinery/abductor/console/ui_act(action, list/params) + . = ..() + if(.) return - usr.set_machine(src) - if(href_list["teleporter_send"]) - TeleporterSend() - else if(href_list["teleporter_retrieve"]) - TeleporterRetrieve() - else if(href_list["flip_vest"]) - FlipVest() - else if(href_list["toggle_vest"]) - if(vest) + switch(action) + if("buy") + var/item_name = params["name"] + var/list/buyable_items = list() + for(var/category in possible_gear) + buyable_items += possible_gear[category] + for(var/key in buyable_items) + var/datum/abductor_gear/AG = buyable_items[key] + if(AG.name == item_name) + Dispense(AG.build_path, AG.cost) + return TRUE + if("teleporter_send") + TeleporterSend() + return TRUE + if("teleporter_retrieve") + TeleporterRetrieve() + return TRUE + if("flip_vest") + FlipVest() + return TRUE + if("toggle_vest") + if(!vest) + return vest.toggle_nodrop() - else if(href_list["select_disguise"]) - SelectDisguise() - else if(href_list["dispense"]) - switch(href_list["dispense"]) - if("baton") - Dispense(/obj/item/abductor/baton,cost=2) - if("helmet") - Dispense(/obj/item/clothing/head/helmet/abductor) - if("silencer") - Dispense(/obj/item/abductor/silencer) - if("tool") - Dispense(/obj/item/abductor/gizmo) - if("vest") - Dispense(/obj/item/clothing/suit/armor/abductor/vest) - if("mind_device") - Dispense(/obj/item/abductor/mind_device,cost=2) - if("chem_dispenser") - Dispense(/obj/item/abductor_machine_beacon/chem_dispenser,cost=2) - if("tongue") - Dispense(/obj/item/organ/tongue/abductor) - updateUsrDialog() + return TRUE + if("select_disguise") + SelectDisguise() + return TRUE + if("select") + selected_cat = params["category"] + return TRUE + if("compact_toggle") + compact_mode = !compact_mode + return TRUE /obj/machinery/abductor/console/proc/TeleporterRetrieve() if(pad && gizmo && gizmo.marked) @@ -156,7 +178,6 @@ pad.teleport_target = location to_chat(user, "Location marked as test subject release point.") - /obj/machinery/abductor/console/Initialize(mapload) ..() return INITIALIZE_HINT_LATELOAD diff --git a/code/modules/antagonists/abductor/machinery/dispenser.dm b/code/modules/antagonists/abductor/machinery/dispenser.dm index 90dcf6626f..f5bc0946e6 100644 --- a/code/modules/antagonists/abductor/machinery/dispenser.dm +++ b/code/modules/antagonists/abductor/machinery/dispenser.dm @@ -22,38 +22,44 @@ gland_colors[i] = random_color() amounts[i] = rand(1,5) -/obj/machinery/abductor/gland_dispenser/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) - if(!isabductor(user)) +/obj/machinery/abductor/gland_dispenser/ui_status(mob/user) + if(!isabductor(user) && !isobserver(user)) + return UI_CLOSE + return ..() + +/obj/machinery/abductor/gland_dispenser/ui_state(mob/user) + return GLOB.physical_state + +/obj/machinery/abductor/gland_dispenser/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "GlandDispenser", name) + ui.open() + +/obj/machinery/abductor/gland_dispenser/ui_data(mob/user) + var/list/data = list() + data["glands"] = list() + for(var/gland_number=1,gland_number<=gland_colors.len,gland_number++) + var/list/gland_information = list( + "color" = gland_colors[gland_number], + "amount" = amounts[gland_number], + "id" = gland_number, + ) + data["glands"] += list(gland_information) + return data + +/obj/machinery/abductor/gland_dispenser/ui_act(action, list/params) + . = ..() + if(.) return - user.set_machine(src) - var/box_css = {" - "} - var/dat = "" - var/item_count = 0 - for(var/i=1,i<=gland_colors.len,i++) - item_count++ - var/g_color = gland_colors[i] - var/amount = amounts[i] - dat += "[amount]" - if(item_count == 4) // Four boxes per line - dat +="

" - item_count = 0 - var/datum/browser/popup = new(user, "glands", "Gland Dispenser", 200, 200) - popup.add_head_content(box_css) - popup.set_content(dat) - popup.open() - return + + switch(action) + if("dispense") + var/gland_id = text2num(params["gland_id"]) + if(!gland_id) + return + Dispense(gland_id) + return TRUE /obj/machinery/abductor/gland_dispenser/attackby(obj/item/W, mob/user, params) if(istype(W, /obj/item/organ/heart/gland)) @@ -65,15 +71,6 @@ else return ..() -/obj/machinery/abductor/gland_dispenser/Topic(href, href_list) - if(..()) - return - usr.set_machine(src) - - if(href_list["dispense"]) - Dispense(text2num(href_list["dispense"])) - updateUsrDialog() - /obj/machinery/abductor/gland_dispenser/proc/Dispense(count) if(amounts[count]>0) amounts[count]-- diff --git a/code/modules/antagonists/abductor/machinery/experiment.dm b/code/modules/antagonists/abductor/machinery/experiment.dm index bc58cf45f0..604730cff2 100644 --- a/code/modules/antagonists/abductor/machinery/experiment.dm +++ b/code/modules/antagonists/abductor/machinery/experiment.dm @@ -15,16 +15,13 @@ var/breakout_time = 450 /obj/machinery/abductor/experiment/MouseDrop_T(mob/target, mob/user) - if(user.stat || user.lying || !Adjacent(user) || !target.Adjacent(user) || !ishuman(target)) + var/mob/living/L = user + if(user.stat || (isliving(user) && (!(L.mobility_flags & MOBILITY_STAND) || !(L.mobility_flags & MOBILITY_UI))) || !Adjacent(user) || !target.Adjacent(user) || !ishuman(target)) return if(isabductor(target)) return close_machine(target) -/obj/machinery/abductor/experiment/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) - - experimentUI(user) - /obj/machinery/abductor/experiment/open_machine() if(!state_open && !panel_open) ..() @@ -46,7 +43,7 @@ /obj/machinery/abductor/experiment/container_resist(mob/living/user) user.visible_message("You see [user] kicking against the door of [src]!", \ "You lean on the back of [src] and start pushing the door open... (this will take about [DisplayTimeText(breakout_time)].)", \ - "You hear a metallic creaking from [src].") + "You hear a metallic creaking from [src].") if(do_after(user,(breakout_time), target = src)) if(!user || user.stat != CONSCIOUS || user.loc != src || state_open) return @@ -54,122 +51,84 @@ "You successfully break out of [src]!") open_machine() -/obj/machinery/abductor/experiment/proc/dissection_icon(mob/living/carbon/human/H) - var/icon/photo = null - var/g = (H.dna.features["body_model"] == FEMALE) ? "f" : "m" - if(H.dna.species.use_skintones) - photo = icon("icon" = 'icons/mob/human.dmi', "icon_state" = "[H.skin_tone]_[g]") - else - photo = icon("icon" = 'icons/mob/human.dmi', "icon_state" = "[H.dna.species.id]_[g]") - photo.Blend("#[H.dna.features["mcolor"]]", ICON_MULTIPLY) +/obj/machinery/abductor/experiment/ui_status(mob/user) + if(user == occupant) + return UI_CLOSE + return ..() - var/icon/eyes - if(EYECOLOR in H.dna.species.species_traits) - eyes = icon("icon" = 'icons/mob/human_face.dmi', "icon_state" = "eyes") - eyes.Blend("#[H.eye_color]", ICON_MULTIPLY) +/obj/machinery/abductor/experiment/ui_state(mob/user) + return GLOB.physical_state - var/datum/sprite_accessory/S - S = GLOB.hair_styles_list[H.hair_style] - if(S && (HAIR in H.dna.species.species_traits)) - var/icon/hair = icon("icon" = S.icon, "icon_state" = "[S.icon_state]") - hair.Blend("#[H.hair_color]", ICON_MULTIPLY) - eyes.Blend(hair, ICON_OVERLAY) +/obj/machinery/abductor/experiment/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "ProbingConsole", name) + ui.open() - S = GLOB.facial_hair_styles_list[H.facial_hair_style] - if(S && (FACEHAIR in H.dna.species.species_traits)) - var/icon/facial = icon("icon" = S.icon, "icon_state" = "[S.icon_state]") - facial.Blend("#[H.facial_hair_color]", ICON_MULTIPLY) - eyes.Blend(facial, ICON_OVERLAY) - - if(eyes) - photo.Blend(eyes, ICON_OVERLAY) - - var/icon/splat = icon("icon" = 'icons/mob/dam_mob.dmi',"icon_state" = "chest30") - photo.Blend(splat,ICON_OVERLAY) - - return photo - -/obj/machinery/abductor/experiment/proc/experimentUI(mob/user) - var/dat - dat += "

Experiment

" - if(occupant) - var/obj/item/photo/P = new - P.picture = new - P.picture.picture_image = icon(dissection_icon(occupant), dir = SOUTH) - user << browse_rsc(P.picture.picture_image, "dissection_img") - dat += "
" - dat += "" //Avert your eyes - dat += "" - dat += "Probe
" - dat += "Dissect
" - dat += "Analyze
" - dat += "
" - else - dat += "Experiment " - - if(!occupant) - dat += "

Machine Unoccupied

" - else - dat += "

Subject Status :

" - dat += "[occupant.name] => " - var/mob/living/mob_occupant = occupant - switch(mob_occupant.stat) - if(CONSCIOUS) - dat += "Conscious" - if(UNCONSCIOUS) - dat += "Unconscious" - else // DEAD - dat += "Deceased" - dat += "
" - dat += "[flash]" - dat += "
" - dat += "Scan" - dat += "Close" : "open=1'>Open"]" - var/datum/browser/popup = new(user, "experiment", "Probing Console", 300, 300) - popup.set_title_image(user.browse_rsc_icon(icon, icon_state)) - popup.set_content(dat) - popup.open() - -/obj/machinery/abductor/experiment/Topic(href, href_list) - if(..() || usr == occupant) - return - usr.set_machine(src) - if(href_list["refresh"]) - updateUsrDialog() - return - if(href_list["open"]) - open_machine() - return - if(href_list["close"]) - close_machine() - return +/obj/machinery/abductor/experiment/ui_data(mob/user) + var/list/data = list() + data["open"] = state_open + data["feedback"] = flash + data["occupant"] = occupant ? TRUE : FALSE + data["occupant_name"] = null + data["occupant_status"] = null if(occupant) var/mob/living/mob_occupant = occupant - if(mob_occupant.stat != DEAD) - if(href_list["experiment"]) - flash = Experiment(occupant,href_list["experiment"],usr) - updateUsrDialog() - add_fingerprint(usr) + data["occupant_name"] = mob_occupant.name + data["occupant_status"] = mob_occupant.stat + return data -/obj/machinery/abductor/experiment/proc/Experiment(mob/occupant,type,mob/user) +/obj/machinery/abductor/experiment/ui_act(action, list/params) + . = ..() + if(.) + return + + switch(action) + if("door") + if(state_open) + close_machine() + return TRUE + else + open_machine() + return TRUE + if("experiment") + if(!occupant) + return + var/mob/living/mob_occupant = occupant + if(mob_occupant.stat == DEAD) + return + flash = experiment(occupant, params["experiment_type"], usr) + return TRUE + +/** + * experiment: Performs selected experiment on occupant mob, resulting in a point reward on success + * + * Arguments: + * * occupant The mob inside the machine + * * type The type of experiment to be performed + * * user The mob starting the experiment + */ +/obj/machinery/abductor/experiment/proc/experiment(mob/occupant, type, mob/user) LAZYINITLIST(history) var/mob/living/carbon/human/H = occupant var/datum/antagonist/abductor/user_abductor = user.mind.has_antag_datum(/datum/antagonist/abductor) if(!user_abductor) - return "Authorization failure. Contact mothership immidiately." + return "Authorization failure. Contact mothership immediately." var/point_reward = 0 + if(!H) + return "Invalid or missing specimen." if(H in history) - return "Specimen already in database." + return "Specimen already in database." if(H.stat == DEAD) say("Specimen deceased - please provide fresh sample.") - return "Specimen deceased." + return "Specimen deceased." var/obj/item/organ/heart/gland/GlandTest = locate() in H.internal_organs if(!GlandTest) say("Experimental dissection not detected!") - return "No glands detected!" - if(H.mind != null && (H.voluntary_ghosted || (H.ckey != null))) + return "No glands detected!" + if(H.mind != null && H.ckey != null) LAZYINITLIST(abductee_minds) LAZYADD(history, H) LAZYADD(abductee_minds, H.mind) @@ -191,22 +150,27 @@ point_reward++ if(point_reward > 0) open_machine() - SendBack(H) - playsound(src.loc, 'sound/machines/ding.ogg', 50, 1) + send_back(H) + playsound(src.loc, 'sound/machines/ding.ogg', 50, TRUE) points += point_reward credits += point_reward - return "Experiment successful! [point_reward] new data-points collected." + return "Experiment successful! [point_reward] new data-points collected." else - playsound(src.loc, 'sound/machines/buzz-sigh.ogg', 50, 1) - return "Experiment failed! No replacement organ detected." + playsound(src.loc, 'sound/machines/buzz-sigh.ogg', 50, TRUE) + return "Experiment failed! No replacement organ detected." else say("Brain activity nonexistent - disposing sample...") open_machine() - SendBack(H) - return "Specimen braindead - disposed." + send_back(H) + return "Specimen braindead - disposed." - -/obj/machinery/abductor/experiment/proc/SendBack(mob/living/carbon/human/H) +/** + * send_back: Sends a mob back to a selected teleport location if safe + * + * Arguments: + * * H The human mob to be sent back + */ +/obj/machinery/abductor/experiment/proc/send_back(mob/living/carbon/human/H) H.Sleeping(160) H.uncuff() if(console && console.pad && console.pad.teleport_target) @@ -216,7 +180,6 @@ SSjob.SendToLateJoin(H, FALSE) return - /obj/machinery/abductor/experiment/update_icon_state() if(state_open) icon_state = "experiment-open" diff --git a/code/modules/antagonists/blob/blob.dm b/code/modules/antagonists/blob/blob.dm index 9a82bb546b..c449bd3012 100644 --- a/code/modules/antagonists/blob/blob.dm +++ b/code/modules/antagonists/blob/blob.dm @@ -4,11 +4,17 @@ antagpanel_category = "Blob" show_to_ghosts = TRUE job_rank = ROLE_BLOB - threat = 20 + threat = 50 var/datum/action/innate/blobpop/pop_action var/starting_points_human_blob = 60 var/point_rate_human_blob = 2 +/datum/antagonist/blob/threat() + . = ..() + if(isovermind(owner.current)) + var/mob/camera/blob/overmind = owner.current + . *= (overmind.blobs_legit.len / overmind.max_count) + /datum/antagonist/blob/roundend_report() var/basic_report = ..() //Display max blobpoints for blebs that lost diff --git a/code/modules/antagonists/blob/blob/blobs/blob_mobs.dm b/code/modules/antagonists/blob/blob/blobs/blob_mobs.dm index ba2363ecc0..f9763b92fd 100644 --- a/code/modules/antagonists/blob/blob/blobs/blob_mobs.dm +++ b/code/modules/antagonists/blob/blob/blobs/blob_mobs.dm @@ -75,7 +75,6 @@ desc = "A floating, fragile spore." icon_state = "blobpod" icon_living = "blobpod" - threat = 0.2 health = 30 maxHealth = 30 verb_say = "psychically pulses" diff --git a/code/modules/antagonists/blob/blob/blobs/shield.dm b/code/modules/antagonists/blob/blob/blobs/shield.dm index a2a6ce94d3..a3a1403e58 100644 --- a/code/modules/antagonists/blob/blob/blobs/shield.dm +++ b/code/modules/antagonists/blob/blob/blobs/shield.dm @@ -45,11 +45,8 @@ desc = "A solid wall of slightly twitching tendrils with a reflective glow." damaged_desc = "A wall of twitching tendrils with a reflective glow." icon_state = "blob_glow" + flags_ricochet = RICOCHET_SHINY point_return = 8 max_integrity = 100 brute_resist = 1 explosion_block = 2 - -/obj/structure/blob/shield/reflective/check_projectile_ricochet(obj/item/projectile/P) - return PROJECTILE_RICOCHET_FORCE - diff --git a/code/modules/antagonists/bloodsucker/bloodsucker_life.dm b/code/modules/antagonists/bloodsucker/bloodsucker_life.dm index a81f702a75..4117fc2b36 100644 --- a/code/modules/antagonists/bloodsucker/bloodsucker_life.dm +++ b/code/modules/antagonists/bloodsucker/bloodsucker_life.dm @@ -28,7 +28,6 @@ if(istype(owner.current.loc, /obj/structure/closet/crate/coffin)) Torpor_Begin() // Wait before next pass - FreeAllVassals() // Free my Vassals! (if I haven't yet) ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -308,6 +307,7 @@ + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // HUMAN FOOD diff --git a/code/modules/antagonists/bloodsucker/powers/fortitude.dm b/code/modules/antagonists/bloodsucker/powers/fortitude.dm index 76f3cc77a4..24cad2a188 100644 --- a/code/modules/antagonists/bloodsucker/powers/fortitude.dm +++ b/code/modules/antagonists/bloodsucker/powers/fortitude.dm @@ -23,6 +23,7 @@ ADD_TRAIT(user, TRAIT_PIERCEIMMUNE, "fortitude") ADD_TRAIT(user, TRAIT_NODISMEMBER, "fortitude") ADD_TRAIT(user, TRAIT_STUNIMMUNE, "fortitude") + ADD_TRAIT(user, TRAIT_NORUNNING, "fortitude") if(ishuman(owner)) var/mob/living/carbon/human/H = owner fortitude_resist = max(0.3, 0.7 - level_current * 0.1) @@ -53,6 +54,7 @@ REMOVE_TRAIT(user, TRAIT_PIERCEIMMUNE, "fortitude") REMOVE_TRAIT(user, TRAIT_NODISMEMBER, "fortitude") REMOVE_TRAIT(user, TRAIT_STUNIMMUNE, "fortitude") + REMOVE_TRAIT(user, TRAIT_STUNIMMUNE, "fortitude") if(!ishuman(owner)) return var/mob/living/carbon/human/H = owner diff --git a/code/modules/antagonists/changeling/cellular_emporium.dm b/code/modules/antagonists/changeling/cellular_emporium.dm index 6abefeefe7..2538394db7 100644 --- a/code/modules/antagonists/changeling/cellular_emporium.dm +++ b/code/modules/antagonists/changeling/cellular_emporium.dm @@ -13,10 +13,13 @@ changeling = null . = ..() -/datum/cellular_emporium/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.always_state) - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) +/datum/cellular_emporium/ui_state(mob/user) + return GLOB.always_state + +/datum/cellular_emporium/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) if(!ui) - ui = new(user, src, ui_key, "CellularEmporium", name, 900, 480, master_ui, state) + ui = new(user, src, "CellularEmporium", name) ui.open() /datum/cellular_emporium/ui_data(mob/user) diff --git a/code/modules/antagonists/clockcult/clock_items/clockwork_slab.dm b/code/modules/antagonists/clockcult/clock_items/clockwork_slab.dm index 04a8e92bb7..0bae7d3539 100644 --- a/code/modules/antagonists/clockcult/clock_items/clockwork_slab.dm +++ b/code/modules/antagonists/clockcult/clock_items/clockwork_slab.dm @@ -25,9 +25,6 @@ /datum/clockwork_scripture/ranged_ability/kindle, /datum/clockwork_scripture/ranged_ability/hateful_manacles) //quickbound scripture, accessed by index var/maximum_quickbound = 5 //how many quickbound scriptures we can have - var/ui_x = 800 - var/ui_z = 420 - var/obj/structure/destructible/clockwork/trap/linking //If we're linking traps together, which ones we're doing /obj/item/clockwork/slab/internal //an internal motor for mobs running scripture @@ -39,6 +36,11 @@ speed_multiplier = 0 no_cost = TRUE +/obj/item/clockwork/slab/debug/on_attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags) + if(!is_servant_of_ratvar(user)) + add_servant_of_ratvar(user) + return ..() + /obj/item/clockwork/slab/traitor var/spent = FALSE @@ -57,11 +59,6 @@ to_chat(user, "[src] falls dark. It appears you weren't worthy.") return ..() -/obj/item/clockwork/slab/debug/on_attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags) - if(!is_servant_of_ratvar(user)) - add_servant_of_ratvar(user) - return ..() - /obj/item/clockwork/slab/cyborg //three scriptures, plus a spear and fabricator clockwork_desc = "A divine link to the Celestial Derelict, allowing for limited recital of scripture." quickbound = list(/datum/clockwork_scripture/ranged_ability/judicial_marker, /datum/clockwork_scripture/ranged_ability/linked_vanguard, \ @@ -145,14 +142,15 @@ /obj/item/clockwork/slab/examine(mob/user) . = ..() - if(is_servant_of_ratvar(user) || isobserver(user)) - if(LAZYLEN(quickbound)) - for(var/i in 1 to quickbound.len) - if(!quickbound[i]) - continue - var/datum/clockwork_scripture/quickbind_slot = quickbound[i] - . += "Quickbind button: [initial(quickbind_slot.name)]." - . += "Available power: [DisplayPower(get_clockwork_power())]." + if(!is_servant_of_ratvar(user) || !isobserver(user)) + return + if(LAZYLEN(quickbound)) + for(var/i in 1 to quickbound.len) + if(!quickbound[i]) + continue + var/datum/clockwork_scripture/quickbind_slot = quickbound[i] + . += "Quickbind button: [initial(quickbind_slot.name)]." + . += "Available power: [DisplayPower(get_clockwork_power())]." //Slab actions; Hierophant, Quickbind /obj/item/clockwork/slab/ui_action_click(mob/user, action) @@ -198,12 +196,6 @@ ui_interact(user) return TRUE -/obj/item/clockwork/slab/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.inventory_state) - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) - if(!ui) - ui = new(user, src, ui_key, "ClockworkSlab", name, ui_x, ui_z, master_ui, state) - ui.open() - /obj/item/clockwork/slab/proc/recite_scripture(datum/clockwork_scripture/scripture, mob/living/user) if(!scripture || !user || !user.canUseTopic(src) || (!no_cost && !can_recite_scripture(user))) return FALSE @@ -223,27 +215,62 @@ scripture_to_recite.run_scripture() return TRUE +/* + * Gets text for a certain section. "Default" is used for when you first open Recollection. + * Current sections (make sure to update this if you add one: + * Basics + * Terminology + * Components + * Scripture + * Power + * Conversion + * * what - What section? + */ +/obj/item/clockwork/slab/proc/get_recollection(what) //Now DMDOC compliant!* + . = list() + switch(what) //need someone to rewrite info for this. + if("Default") + .["title"] = "Default" + .["info"] = "Hello servant! Currently these categories dosen't work!" + /* + if("Basics") + .["title"] = "Basics" + .["info"] = "# MARKDOWN WITH HTML?" + if("Terminology") + .["title"] = "Terminology" + .["info"] = "# MARKDOWN WITH HTML?" + if("Components") + .["title"] = "Default" + .["info"] = "# MARKDOWN WITH HTML?" + if("Scripture") + .["title"] = "Default" + .["info"] = "# MARKDOWN WITH HTML?" + if("Power") + .["title"] = "Power" + .["info"] = "# MARKDOWN WITH HTML?" + if("Conversion") + .["title"] = "Conversion" + .["info"] = "# MARKDOWN WITH HTML?" + */ + else + return null //error text handled tgui side. should not cause BSOD -//Gets text for a certain section. "Default" is used for when you first open Recollection. -//Current sections (make sure to update this if you add one: -//- Basics -//- Terminology -//- Components -//- Scripture -//- Power -//- Conversion +/obj/item/clockwork/slab/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "ClockworkSlab", name) + ui.open() /obj/item/clockwork/slab/ui_data(mob/user) //we display a lot of data via TGUI . = list() .["recollection"] = recollecting .["power"] = DisplayPower(get_clockwork_power()) .["power_unformatted"] = get_clockwork_power() - // .["rec_text"] = recollection() handled TGUI side .["HONOR_RATVAR"] = GLOB.ratvar_awakens .["scripture"] = list() - for(var/s in GLOB.all_scripture) + for(var/s in GLOB.all_scripture) //don't block this, even when ratvar spawns for roundend griff. var/datum/clockwork_scripture/S = GLOB.all_scripture[s] - if(S.tier == SCRIPTURE_PERIPHERAL) //yes, tiers are the tabs. + if(S.tier == SCRIPTURE_PERIPHERAL) // This tier is skiped because this contains basetype stuff continue var/list/data = list() @@ -253,7 +280,7 @@ data["required"] = "([DisplayPower(S.power_cost)][S.special_power_text ? "+ [replacetext(S.special_power_text, "POWERCOST", "[DisplayPower(S.special_power_cost)]")]" : ""])" data["required_unformatted"] = S.power_cost data["type"] = "[S.type]" - data["quickbind"] = S.quickbind //this is if it cant quickbind + data["quickbind"] = S.quickbind //this is if it cant quickbind (bool) data["fontcolor"] = get_component_color_bright(S.primary_component) data["important"] = S.important //italic! @@ -265,10 +292,8 @@ .["rec_binds"] = list() for(var/i in 1 to maximum_quickbound) - if(GLOB.ratvar_awakens) - return if(LAZYLEN(quickbound) < i || !quickbound[i]) - .["rec_binds"] += list(list()) + .["rec_binds"] += list(list()) //a blank json. else var/datum/clockwork_scripture/quickbind_slot = quickbound[i] .["rec_binds"] += list(list( @@ -280,7 +305,11 @@ /obj/item/clockwork/slab/ui_static_data(mob/user) . = list() - .["tier_infos"] = list() + .["tier_infos"] = list() //HEY!! WHEN ADDING NEW TIER, ADD IT HERE + .["tier_infos"][SCRIPTURE_PERIPHERAL] = list( + "requirement" = "Breaking the code DM side. Report to coggerbus if this appears!!", + "ready" = FALSE //just in case. Should NOT exist at all + ) .["tier_infos"][SCRIPTURE_DRIVER] = list( "requirement" = "None, this is already unlocked", "ready" = TRUE //to bold it on JS side, and to say "These scriptures are permanently unlocked." @@ -297,10 +326,10 @@ "requirement" = "Unlock powerful equipment and structures by converting five servants or if [DisplayPower(JUDGEMENT_UNLOCK_THRESHOLD)] of power is reached..", "ready" = SSticker.scripture_states[SCRIPTURE_JUDGEMENT] ) - - // .["selected"] = selected_scripture - generate_all_scripture() - .["recollection_categories"] = GLOB.ratvar_awakens ? list() : list( + .["recollection_categories"] = list() + if(GLOB.ratvar_awakens) + return + .["recollection_categories"] = list( list("name" = "Getting Started", "desc" = "First-time servant? Read this first."), list("name" = "Basics", "desc" = "A primer on how to play as a servant."), list("name" = "Terminology", "desc" = "Common acronyms, words, and terms."), @@ -309,8 +338,9 @@ list("name" = "Power", "desc" = "The power system that certain objects use to function."), list("name" = "Conversion", "desc" = "Converting the crew, cyborgs, and very walls to your cause.") ) - // .["rec_section"]["title"] //this is here if ever we decided to return these back. - // .["rec_section"]["info"]// wall of info for the thing + .["rec_section"] = get_recollection(recollection_category) + generate_all_scripture() + //needs a new place to live, preferably when clockcult unlocks/downgrades a tier. Smart enough to earlyreturn. /obj/item/clockwork/slab/ui_act(action, params) switch(action) @@ -369,4 +399,4 @@ Q.button_icon_state = quickbind_slot.name Q.UpdateButtonIcon() if(isliving(loc)) - Q.Grant(loc) \ No newline at end of file + Q.Grant(loc) diff --git a/code/modules/antagonists/clockcult/clock_items/construct_chassis.dm b/code/modules/antagonists/clockcult/clock_items/construct_chassis.dm index 19c29762bf..daee9f5c2c 100644 --- a/code/modules/antagonists/clockcult/clock_items/construct_chassis.dm +++ b/code/modules/antagonists/clockcult/clock_items/construct_chassis.dm @@ -89,17 +89,17 @@ creation_message = "The cogscarab clicks and whirrs as it hops up and springs to life!" construct_type = /mob/living/simple_animal/drone/cogscarab w_class = WEIGHT_CLASS_SMALL - var/infinite_resources = TRUE + var/infinite_resources = FALSE //No. var/static/obj/item/seasonal_hat //Share it with all other scarabs, since we're from the same cult! /obj/item/clockwork/construct_chassis/cogscarab/Initialize() . = ..() if(GLOB.servants_active) - infinite_resources = FALSE //For any that are somehow spawned in late + infinite_resources = FALSE //This check is relatively irrelevant until *someone* makes the infinite resources var default to true again, so, leaving it in. /obj/item/clockwork/construct_chassis/cogscarab/pre_spawn() if(infinite_resources) - //During rounds where they can't interact with the station, let them experiment with builds + //During rounds where they can't interact with the station, let them experiment with builds, if an admin allows them to. construct_type = /mob/living/simple_animal/drone/cogscarab/ratvar if(!seasonal_hat) var/obj/item/drone_shell/D = locate() in GLOB.poi_list diff --git a/code/modules/antagonists/clockcult/clock_mobs.dm b/code/modules/antagonists/clockcult/clock_mobs.dm index 87466d65f2..2f00fd4e4a 100644 --- a/code/modules/antagonists/clockcult/clock_mobs.dm +++ b/code/modules/antagonists/clockcult/clock_mobs.dm @@ -6,7 +6,6 @@ unique_name = 1 minbodytemp = 0 unsuitable_atmos_damage = 0 - threat = 1 atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0) //Robotic damage_coeff = list(BRUTE = 1, BURN = 1, TOX = 0, CLONE = 0, STAMINA = 0, OXY = 0) healable = FALSE diff --git a/code/modules/antagonists/clockcult/clock_mobs/clockwork_marauder.dm b/code/modules/antagonists/clockcult/clock_mobs/clockwork_marauder.dm index 79b919b1e9..76c9db7231 100644 --- a/code/modules/antagonists/clockcult/clock_mobs/clockwork_marauder.dm +++ b/code/modules/antagonists/clockcult/clock_mobs/clockwork_marauder.dm @@ -9,7 +9,6 @@ desc = "The stalwart apparition of a soldier, blazing with crimson flames. It's armed with a gladius and shield." icon_state = "clockwork_marauder" mob_biotypes = MOB_HUMANOID - threat = 3 health = 120 maxHealth = 120 force_threshold = 8 diff --git a/code/modules/antagonists/clockcult/clock_scriptures/scripture_drivers.dm b/code/modules/antagonists/clockcult/clock_scriptures/scripture_drivers.dm index 00c4d73428..b7c94d56df 100644 --- a/code/modules/antagonists/clockcult/clock_scriptures/scripture_drivers.dm +++ b/code/modules/antagonists/clockcult/clock_scriptures/scripture_drivers.dm @@ -97,7 +97,7 @@ desc = "Charges your slab with divine energy, allowing you to overwhelm a target with Ratvar's light." invocations = list("Divinity, show them your light!") whispered = TRUE - channel_time = 15 // I think making kindle channel a third of the time less is a good make up for the fact that it silences people for such a little amount of time. + channel_time = 25 //2.5 seconds should be a okay compromise between being able to use it when needed, and not being able to just pause in combat for a second and hardstunning your enemy power_cost = 125 usage_tip = "The light can be used from up to two tiles away. Damage taken will GREATLY REDUCE the stun's duration." tier = SCRIPTURE_DRIVER @@ -137,6 +137,30 @@ quickbind_desc = "Applies handcuffs to a struck target." +//Belligerent: Channeled for up to fifteen times over thirty seconds. Forces non-servants that can hear the chant to walk, doing minor damage. Nar-Sian cultists are burned. +/datum/clockwork_scripture/channeled/belligerent + descname = "Channeled, Area Slowdown" + name = "Belligerent" + desc = "Forces all nearby non-servants to walk rather than run, doing minor damage. Chanted every two seconds for up to thirty seconds." + chant_invocations = list("Punish their blindness!", "Take time, make slow!", "Kneel before The Justiciar!", "Halt their charges!", "Cease the tides!") + chant_amount = 15 + chant_interval = 20 + channel_time = 20 + power_cost = 300 + usage_tip = "Useful for crowd control in a populated area and disrupting mass movement." + tier = SCRIPTURE_DRIVER + primary_component = BELLIGERENT_EYE + sort_priority = 7 + quickbind = TRUE + quickbind_desc = "Forces nearby non-Servants to walk, doing minor damage with each chant.
Maximum 15 chants." + +/datum/clockwork_scripture/channeled/belligerent/chant_effects(chant_number) + for(var/mob/living/carbon/C in hearers(7, invoker)) + C.apply_status_effect(STATUS_EFFECT_BELLIGERENT) + new /obj/effect/temp_visual/ratvar/belligerent(get_turf(invoker)) + return TRUE + + //Vanguard: Provides twenty seconds of greatly increased stamina regeneration and stun immunity. At the end of the twenty seconds, 25% of all stuns absorbed aswell as 50% of healed stamloss are applied to the invoker. /datum/clockwork_scripture/vanguard descname = "Self Stun Immunity" @@ -149,7 +173,7 @@ usage_tip = "You cannot reactivate Vanguard while still shielded by it." tier = SCRIPTURE_DRIVER primary_component = VANGUARD_COGWHEEL - sort_priority = 7 + sort_priority = 8 quickbind = TRUE quickbind_desc = "Allows you to temporarily have quickly regenerating stamina and absorb stuns. Part of the stuns absorbed and staminaloss healed will affect you when disabled." @@ -181,7 +205,7 @@ usage_tip = "The Compromise is very fast to invoke, and will remove holy water from the target Servant." tier = SCRIPTURE_DRIVER primary_component = VANGUARD_COGWHEEL - sort_priority = 8 + sort_priority = 9 quickbind = TRUE quickbind_desc = "Allows you to convert a Servant's brute, burn, and oxygen damage to half toxin damage.
Click your slab to disable." slab_overlay = "compromise" @@ -255,7 +279,7 @@ tier = SCRIPTURE_DRIVER space_allowed = TRUE primary_component = GEIS_CAPACITOR - sort_priority = 10 + sort_priority = 11 important = TRUE quickbind = TRUE quickbind_desc = "Creates a new Clockwork Slab." @@ -276,7 +300,7 @@ tier = SCRIPTURE_DRIVER space_allowed = TRUE primary_component = GEIS_CAPACITOR - sort_priority = 11 + sort_priority = 12 quickbind = TRUE quickbind_desc = "Creates a pair of Wraith Spectacles, which grant true sight but cause gradual vision loss." @@ -295,7 +319,7 @@ usage_tip = "This gateway is strictly one-way and will only allow things through the invoker's portal." tier = SCRIPTURE_DRIVER primary_component = GEIS_CAPACITOR - sort_priority = 9 + sort_priority = 10 quickbind = TRUE quickbind_desc = "Allows you to create a one-way Spatial Gateway to a living Servant or Clockwork Obelisk." diff --git a/code/modules/antagonists/clockcult/clock_scriptures/scripture_scripts.dm b/code/modules/antagonists/clockcult/clock_scriptures/scripture_scripts.dm index 8819544928..eaec652f68 100644 --- a/code/modules/antagonists/clockcult/clock_scriptures/scripture_scripts.dm +++ b/code/modules/antagonists/clockcult/clock_scriptures/scripture_scripts.dm @@ -459,26 +459,3 @@ invoker.light_range = 0 invoker.update_light() return ..() - -//Belligerent: Channeled for up to fifteen times over thirty seconds. Forces non-servants that can hear the chant to walk, doing minor damage. Nar-Sian cultists are burned. -/datum/clockwork_scripture/channeled/belligerent - descname = "Channeled, Area Slowdown" - name = "Belligerent" - desc = "Forces all nearby non-servants to walk rather than run, doing minor damage. Chanted every two seconds for up to thirty seconds." - chant_invocations = list("Punish their blindness!", "Take time, make slow!", "Kneel before The Justiciar!", "Halt their charges!", "Cease the tides!") - chant_amount = 15 - chant_interval = 20 - channel_time = 20 - power_cost = 300 - usage_tip = "Useful for crowd control in a populated area and disrupting mass movement." - tier = SCRIPTURE_DRIVER - primary_component = BELLIGERENT_EYE - sort_priority = 1 - quickbind = TRUE - quickbind_desc = "Forces nearby non-Servants to walk, doing minor damage with each chant.
Maximum 15 chants." - -/datum/clockwork_scripture/channeled/belligerent/chant_effects(chant_number) - for(var/mob/living/carbon/C in hearers(7, invoker)) - C.apply_status_effect(STATUS_EFFECT_BELLIGERENT) - new /obj/effect/temp_visual/ratvar/belligerent(get_turf(invoker)) - return TRUE diff --git a/code/modules/antagonists/eldritch_cult/eldritch_antag.dm b/code/modules/antagonists/eldritch_cult/eldritch_antag.dm new file mode 100644 index 0000000000..367710b110 --- /dev/null +++ b/code/modules/antagonists/eldritch_cult/eldritch_antag.dm @@ -0,0 +1,229 @@ +/datum/antagonist/heretic + name = "Heretic" + roundend_category = "Heretics" + antagpanel_category = "Heretic" + antag_moodlet = /datum/mood_event/heretics + job_rank = ROLE_HERETIC + antag_hud_type = ANTAG_HUD_HERETIC + antag_hud_name = "heretic" + var/give_equipment = TRUE + var/list/researched_knowledge = list() + var/total_sacrifices = 0 + var/ascended = FALSE + +/datum/antagonist/heretic/admin_add(datum/mind/new_owner,mob/admin) + give_equipment = TRUE + new_owner.add_antag_datum(src) + message_admins("[key_name_admin(admin)] has heresized [key_name_admin(new_owner)].") + log_admin("[key_name(admin)] has heresized [key_name(new_owner)].") + +/datum/antagonist/heretic/greet() + owner.current.playsound_local(get_turf(owner.current), 'sound/ambience/antag/ecult_op.ogg', 100, FALSE, pressure_affected = FALSE)//subject to change + to_chat(owner, "You are the Heretic!
\ + The old ones gave you these tasks to fulfill:") + owner.announce_objectives() + to_chat(owner, "The book whispers, the forbidden knowledge walks once again!
\ + Your book allows you to research abilities, but be careful, you cannot undo what has been done.
\ + You gain charges by either collecting influences or sacrificing people tracked by the living heart
\ + You can find a basic guide at : https://tgstation13.org/wiki/Heresy_101
") + +/datum/antagonist/heretic/on_gain() + var/mob/living/current = owner.current + if(ishuman(current)) + forge_primary_objectives() + gain_knowledge(/datum/eldritch_knowledge/spell/basic) + gain_knowledge(/datum/eldritch_knowledge/living_heart) + gain_knowledge(/datum/eldritch_knowledge/codex_cicatrix) + gain_knowledge(/datum/eldritch_knowledge/eldritch_blade) + current.log_message("has been converted to the cult of the forgotten ones!", LOG_ATTACK, color="#960000") + GLOB.reality_smash_track.AddMind(owner) + START_PROCESSING(SSprocessing,src) + if(give_equipment) + equip_cultist() + owner.teach_crafting_recipe(/datum/crafting_recipe/heretic/codex) + return ..() + +/datum/antagonist/heretic/on_removal() + + for(var/X in researched_knowledge) + var/datum/eldritch_knowledge/EK = researched_knowledge[X] + EK.on_lose(owner.current) + + if(!silent) + to_chat(owner.current, "Your mind begins to flare as the otherwordly knowledge escapes your grasp!") + owner.current.log_message("has renounced the cult of the old ones!", LOG_ATTACK, color="#960000") + GLOB.reality_smash_track.RemoveMind(owner) + STOP_PROCESSING(SSprocessing,src) + + return ..() + + +/datum/antagonist/heretic/proc/equip_cultist() + var/mob/living/carbon/H = owner.current + if(!istype(H)) + return + . += ecult_give_item(/obj/item/forbidden_book, H) + . += ecult_give_item(/obj/item/living_heart, H) + +/datum/antagonist/heretic/proc/ecult_give_item(obj/item/item_path, mob/living/carbon/human/H) + var/list/slots = list( + "backpack" = SLOT_IN_BACKPACK, + "left pocket" = SLOT_L_STORE, + "right pocket" = SLOT_R_STORE + ) + + var/T = new item_path(H) + var/item_name = initial(item_path.name) + var/where = H.equip_in_one_of_slots(T, slots) + if(!where) + to_chat(H, "Unfortunately, you weren't able to get a [item_name]. This is very bad and you should adminhelp immediately (press F1).") + return FALSE + else + to_chat(H, "You have a [item_name] in your [where].") + if(where == "backpack") + SEND_SIGNAL(H.back, COMSIG_TRY_STORAGE_SHOW, H) + return TRUE + +/datum/antagonist/heretic/process() + + for(var/X in researched_knowledge) + var/datum/eldritch_knowledge/EK = researched_knowledge[X] + EK.on_life(owner.current) + +/datum/antagonist/heretic/proc/forge_primary_objectives() + var/list/assasination = list() + var/list/protection = list() + for(var/i in 1 to 2) + var/pck = pick("assasinate","protect") + switch(pck) + if("assasinate") + var/datum/objective/assassinate/A = new + A.owner = owner + var/list/owners = A.get_owners() + A.find_target(owners,protection) + assasination += A.target + objectives += A + if("protect") + var/datum/objective/protect/P = new + P.owner = owner + var/list/owners = P.get_owners() + P.find_target(owners,assasination) + protection += P.target + objectives += P + + + var/datum/objective/sacrifice_ecult/SE = new + SE.owner = owner + SE.update_explanation_text() + objectives += SE + + var/datum/objective/escape/escape_objective = new + escape_objective.owner = owner + objectives += escape_objective + +/datum/antagonist/heretic/apply_innate_effects(mob/living/mob_override) + . = ..() + var/mob/living/current = owner.current + if(mob_override) + current = mob_override + add_antag_hud(antag_hud_type, antag_hud_name, current) + handle_clown_mutation(current, mob_override ? null : "Knowledge described in the book allowed you to overcome your clownish nature, allowing you to use complex items effectively.") + current.faction |= "heretics" + +/datum/antagonist/heretic/remove_innate_effects(mob/living/mob_override) + . = ..() + var/mob/living/current = owner.current + if(mob_override) + current = mob_override + remove_antag_hud(antag_hud_type, current) + handle_clown_mutation(current, removing = FALSE) + current.faction -= "heretics" + +/datum/antagonist/heretic/get_admin_commands() + . = ..() + .["Equip"] = CALLBACK(src,.proc/equip_cultist) + +/datum/antagonist/heretic/roundend_report() + var/list/parts = list() + + var/cultiewin = TRUE + + parts += printplayer(owner) + parts += "Sacrifices Made: [total_sacrifices]" + + if(length(objectives)) + var/count = 1 + for(var/o in objectives) + var/datum/objective/objective = o + if(objective.check_completion()) + parts += "Objective #[count]: [objective.explanation_text] Success!
" + else + parts += "Objective #[count]: [objective.explanation_text] Fail." + cultiewin = FALSE + count++ + if(ascended) + parts += "HERETIC HAS ASCENDED!" + else + if(cultiewin) + parts += "The heretic was successful!" + else + parts += "The heretic has failed." + + parts += "Knowledge Researched: " + + var/list/knowledge_message = list() + var/list/knowledge = get_all_knowledge() + for(var/X in knowledge) + var/datum/eldritch_knowledge/EK = knowledge[X] + knowledge_message += "[EK.name]" + parts += knowledge_message.Join(", ") + + return parts.Join("
") +//////////////// +// Knowledge // +//////////////// + +/datum/antagonist/heretic/proc/gain_knowledge(datum/eldritch_knowledge/EK) + if(get_knowledge(EK)) + return FALSE + var/datum/eldritch_knowledge/initialized_knowledge = new EK + researched_knowledge[initialized_knowledge.type] = initialized_knowledge + initialized_knowledge.on_gain(owner.current) + return TRUE + +/datum/antagonist/heretic/proc/get_researchable_knowledge() + var/list/researchable_knowledge = list() + var/list/banned_knowledge = list() + for(var/X in researched_knowledge) + var/datum/eldritch_knowledge/EK = researched_knowledge[X] + researchable_knowledge |= EK.next_knowledge + banned_knowledge |= EK.banned_knowledge + banned_knowledge |= EK.type + researchable_knowledge -= banned_knowledge + return researchable_knowledge + +/datum/antagonist/heretic/proc/get_knowledge(wanted) + return researched_knowledge[wanted] + +/datum/antagonist/heretic/proc/get_all_knowledge() + return researched_knowledge + +//////////////// +// Objectives // +//////////////// + +/datum/objective/sacrifice_ecult + name = "sacrifice" + +/datum/objective/sacrifice_ecult/update_explanation_text() + . = ..() + target_amount = rand(2,4) + explanation_text = "Sacrifice at least [target_amount] people." + +/datum/objective/sacrifice_ecult/check_completion() + if(!owner) + return FALSE + var/datum/antagonist/heretic/cultie = owner.has_antag_datum(/datum/antagonist/heretic) + if(!cultie) + return FALSE + return cultie.total_sacrifices >= target_amount diff --git a/code/modules/antagonists/eldritch_cult/eldritch_book.dm b/code/modules/antagonists/eldritch_cult/eldritch_book.dm new file mode 100644 index 0000000000..839150d37d --- /dev/null +++ b/code/modules/antagonists/eldritch_cult/eldritch_book.dm @@ -0,0 +1,145 @@ +/obj/item/forbidden_book + name = "Codex Cicatrix" + desc = "Book describing the secrets of the veil." + icon = 'icons/obj/eldritch.dmi' + icon_state = "book" + item_state = "book" + w_class = WEIGHT_CLASS_SMALL + ///Last person that touched this + var/mob/living/last_user + ///how many charges do we have? + var/charge = 0 + ///Where we cannot create the rune? + var/static/list/blacklisted_turfs = typecacheof(list(/turf/closed,/turf/open/space,/turf/open/lava)) + +/obj/item/forbidden_book/Destroy() + last_user = null + . = ..() + + +/obj/item/forbidden_book/examine(mob/user) + . = ..() + if(!IS_HERETIC(user)) + return + . += "The Tome holds [charge] charges." + . += "Use it on the floor to create a transmutation rune, used to perform rituals." + . += "Hit an influence in the black part with it to gain a charge." + . += "Hit a transmutation rune to destroy it." + +/obj/item/forbidden_book/afterattack(atom/target, mob/user, proximity_flag, click_parameters) + . = ..() + if(!proximity_flag || !IS_HERETIC(user)) + return + if(istype(target,/obj/effect/eldritch)) + remove_rune(target,user) + if(istype(target,/obj/effect/reality_smash)) + get_power_from_influence(target,user) + if(istype(target,/turf/open)) + draw_rune(target,user) + +///Gives you a charge and destroys a corresponding influence +/obj/item/forbidden_book/proc/get_power_from_influence(atom/target, mob/user) + var/obj/effect/reality_smash/RS = target + to_chat(target, "You start drawing power from influence...") + if(do_after(user,10 SECONDS,TRUE,RS)) + qdel(RS) + charge += 1 + +///Draws a rune on a selected turf +/obj/item/forbidden_book/proc/draw_rune(atom/target,mob/user) + + for(var/turf/T in range(1,target)) + if(is_type_in_typecache(T, blacklisted_turfs)) + to_chat(target, "The terrain doesn't support runes!") + return + var/A = get_turf(target) + to_chat(user, "You start drawing a rune...") + + if(do_after(user,30 SECONDS,FALSE, user)) + + new /obj/effect/eldritch/big(A) + +///Removes runes from the selected turf +/obj/item/forbidden_book/proc/remove_rune(atom/target,mob/user) + + to_chat(user, "You start removing a rune...") + if(do_after(user,2 SECONDS,FALSE, user)) + qdel(target) + +/obj/item/forbidden_book/ui_interact(mob/user, datum/tgui/ui = null) + if(!IS_HERETIC(user)) + return FALSE + last_user = user + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + icon_state = "book_open" + flick("book_opening", src) + ui = new(user, src, "ForbiddenLore", name) + ui.open() + +/obj/item/forbidden_book/ui_data(mob/user) + var/datum/antagonist/heretic/cultie = user.mind.has_antag_datum(/datum/antagonist/heretic) + var/list/to_know = list() + for(var/Y in cultie.get_researchable_knowledge()) + to_know += new Y + var/list/known = cultie.get_all_knowledge() + var/list/data = list() + var/list/lore = list() + + data["charges"] = charge + + for(var/X in to_know) + lore = list() + var/datum/eldritch_knowledge/EK = X + lore["type"] = EK.type + lore["name"] = EK.name + lore["cost"] = EK.cost + lore["disabled"] = EK.cost <= charge ? FALSE : TRUE + lore["path"] = EK.route + lore["state"] = "Research" + lore["flavour"] = EK.gain_text + lore["desc"] = EK.desc + data["to_know"] += list(lore) + + for(var/X in known) + lore = list() + var/datum/eldritch_knowledge/EK = known[X] + lore["name"] = EK.name + lore["cost"] = EK.cost + lore["disabled"] = TRUE + lore["path"] = EK.route + lore["state"] = "Researched" + lore["flavour"] = EK.gain_text + lore["desc"] = EK.desc + data["to_know"] += list(lore) + + if(!length(data["to_know"])) + data["to_know"] = null + + return data + +/obj/item/forbidden_book/ui_act(action, params) + . = ..() + if(.) + return + switch(action) + if("research") + var/datum/antagonist/heretic/cultie = last_user.mind.has_antag_datum(/datum/antagonist/heretic) + var/ekname = params["name"] + for(var/X in cultie.get_researchable_knowledge()) + var/datum/eldritch_knowledge/EK = X + if(initial(EK.name) != ekname) + continue + if(cultie.gain_knowledge(EK)) + charge -= text2num(params["cost"]) + return TRUE + + update_icon() // Not applicable to all objects. + +/obj/item/forbidden_book/ui_close(mob/user) + flick("book_closing",src) + icon_state = initial(icon_state) + return ..() + +/obj/item/forbidden_book/debug + charge = 100 diff --git a/code/modules/antagonists/eldritch_cult/eldritch_effects.dm b/code/modules/antagonists/eldritch_cult/eldritch_effects.dm new file mode 100644 index 0000000000..899e588bda --- /dev/null +++ b/code/modules/antagonists/eldritch_cult/eldritch_effects.dm @@ -0,0 +1,289 @@ +/obj/effect/eldritch + name = "Generic rune" + desc = "Weird combination of shapes and symbols etched into the floor itself. The indentation is filled with thick black tar-like fluid." + anchored = TRUE + icon_state = "" + resistance_flags = FIRE_PROOF | UNACIDABLE | ACID_PROOF + layer = SIGIL_LAYER + ///Used mainly for summoning ritual to prevent spamming the rune to create millions of monsters. + var/is_in_use = FALSE + +/obj/effect/eldritch/attack_hand(mob/living/user) + . = ..() + if(.) + return + try_activate(user) + +/obj/effect/eldritch/proc/try_activate(mob/living/user) + if(!IS_HERETIC(user)) + return + if(!is_in_use) + INVOKE_ASYNC(src, .proc/activate , user) + +/obj/effect/eldritch/attacked_by(obj/item/I, mob/living/user) + . = ..() + if(istype(I,/obj/item/nullrod)) + qdel(src) + +/obj/effect/eldritch/proc/activate(mob/living/user) + is_in_use = TRUE + // Have fun trying to read this proc. + var/datum/antagonist/heretic/cultie = user.mind.has_antag_datum(/datum/antagonist/heretic) + var/list/knowledge = cultie.get_all_knowledge() + var/list/atoms_in_range = list() + + for(var/A in range(1, src)) + var/atom/atom_in_range = A + if(istype(atom_in_range,/area)) + continue + if(istype(atom_in_range,/turf)) // we dont want turfs + continue + if(istype(atom_in_range,/mob/living)) + var/mob/living/living_in_range = atom_in_range + if(living_in_range.stat != DEAD || living_in_range == user) // we only accept corpses, no living beings allowed. + continue + atoms_in_range += atom_in_range + for(var/X in knowledge) + var/datum/eldritch_knowledge/current_eldritch_knowledge = knowledge[X] + + //has to be done so that we can freely edit the local_required_atoms without fucking up the eldritch knowledge + var/list/local_required_atoms = list() + + if(!current_eldritch_knowledge.required_atoms || current_eldritch_knowledge.required_atoms.len == 0) + continue + + local_required_atoms += current_eldritch_knowledge.required_atoms + + var/list/selected_atoms = list() + + if(!current_eldritch_knowledge.recipe_snowflake_check(atoms_in_range,drop_location(),selected_atoms)) + continue + + for(var/LR in local_required_atoms) + var/list/local_required_atom_list = LR + + for(var/LAIR in atoms_in_range) + var/atom/local_atom_in_range = LAIR + if(is_type_in_list(local_atom_in_range,local_required_atom_list)) + selected_atoms |= local_atom_in_range + local_required_atoms -= list(local_required_atom_list) + + if(length(local_required_atoms) > 0) + continue + + flick("[icon_state]_active",src) + playsound(user, 'sound/magic/castsummon.ogg', 75, TRUE) + //we are doing this since some on_finished_recipe subtract the atoms from selected_atoms making them invisible permanently. + var/list/atoms_to_disappear = selected_atoms.Copy() + for(var/to_disappear in atoms_to_disappear) + var/atom/atom_to_disappear = to_disappear + //temporary so we dont have to deal with the bs of someone picking those up when they may be deleted + atom_to_disappear.invisibility = INVISIBILITY_ABSTRACT + if(current_eldritch_knowledge.on_finished_recipe(user,selected_atoms,loc)) + current_eldritch_knowledge.cleanup_atoms(selected_atoms) + is_in_use = FALSE + + for(var/to_appear in atoms_to_disappear) + var/atom/atom_to_appear = to_appear + //we need to reappear the item just in case the ritual didnt consume everything... or something. + atom_to_appear.invisibility = initial(atom_to_appear.invisibility) + + return + is_in_use = FALSE + to_chat(user,"Your ritual failed! You used either wrong components or are missing something important!") + +/obj/effect/eldritch/big + name = "transmutation circle" + icon = 'icons/effects/96x96.dmi' + icon_state = "eldritch_rune1" + pixel_x = -32 //So the big ol' 96x96 sprite shows up right + pixel_y = -32 + +/** + * #Reality smash tracker + * + * Stupid fucking list holder, DONT create new ones, it will break the game, this is automnatically created whenever eldritch cultists are created. + * + * Tracks relevant data, generates relevant data, useful tool + */ +/datum/reality_smash_tracker + ///list of tracked reality smashes + var/list/smashes = list() + ///List of mobs with ability to see the smashes + var/list/targets = list() + +/datum/reality_smash_tracker/Destroy(force, ...) + if(GLOB.reality_smash_track == src) + stack_trace("/datum/reality_smash_tracker was deleted. Heretics may no longer access any influences. Fix it or call coder support") + QDEL_LIST(smashes) + targets.Cut() + return ..() + +/** + * Automatically fixes the target and smash network + * + * Fixes any bugs that are caused by late Generate() or exchanging clients + */ +/datum/reality_smash_tracker/proc/ReworkNetwork() + listclearnulls(smashes) + for(var/mind in targets) + if(isnull(mind)) + stack_trace("A null somehow landed in a list of minds") + continue + for(var/X in smashes) + var/obj/effect/reality_smash/reality_smash = X + reality_smash.AddMind(mind) + +/** + * Generates a set amount of reality smashes based on the N value + * + * Automatically creates more reality smashes + */ +/datum/reality_smash_tracker/proc/_Generate() + var/targ_len = length(targets) + var/smash_len = length(smashes) + var/number = targ_len * 6 - smash_len + + for(var/i in 0 to number) + + var/turf/chosen_location = get_safe_random_station_turf() + //we also dont want them close to each other, at least 1 tile of seperation + var/obj/effect/reality_smash/what_if_i_have_one = locate() in range(1, chosen_location) + var/obj/effect/broken_illusion/what_if_i_had_one_but_got_used = locate() in range(1, chosen_location) + if(what_if_i_have_one || what_if_i_had_one_but_got_used) //we dont want to spawn + continue + var/obj/effect/reality_smash/RS = new/obj/effect/reality_smash(chosen_location) + smashes += RS + ReworkNetwork() + + +/** + * Adds a mind to the list of people that can see the reality smashes + * + * Use this whenever you want to add someone to the list + */ +/datum/reality_smash_tracker/proc/AddMind(var/datum/mind/M) + RegisterSignal(M.current,COMSIG_MOB_CLIENT_LOGIN,.proc/ReworkNetwork) + targets |= M + _Generate() + for(var/X in smashes) + var/obj/effect/reality_smash/reality_smash = X + reality_smash.AddMind(M) + + +/** + * Removes a mind from the list of people that can see the reality smashes + * + * Use this whenever you want to remove someone from the list + */ +/datum/reality_smash_tracker/proc/RemoveMind(var/datum/mind/M) + UnregisterSignal(M.current,COMSIG_MOB_CLIENT_LOGIN) + targets -= M + for(var/obj/effect/reality_smash/RS in smashes) + RS.RemoveMind(M) + +/obj/effect/broken_illusion + name = "pierced reality" + icon = 'icons/effects/eldritch.dmi' + icon_state = "pierced_illusion" + anchored = TRUE + resistance_flags = FIRE_PROOF | UNACIDABLE | ACID_PROOF + +/obj/effect/broken_illusion/attack_hand(mob/living/user) + if(!ishuman(user)) + return ..() + var/mob/living/carbon/human/human_user = user + if(IS_HERETIC(human_user)) + to_chat(human_user,"You know better than to tempt forces out of your control.") + else + var/obj/item/bodypart/arm = human_user.get_active_hand() + if(prob(25)) + to_chat(human_user,"An otherwordly presence tears your arm apart into atoms as you try to touch the hole in the very fabric of reality!") + arm.dismember() + qdel(arm) + else + to_chat(human_user,"You pull your hand away from the hole as eldritch energy flails out, trying to latch onto existence itself!") + +/obj/effect/broken_illusion/attack_tk(mob/user) + if(!ishuman(user)) + return + var/mob/living/carbon/human/human_user = user + if(IS_HERETIC(human_user)) + to_chat(human_user,"You know better than to tempt forces out of your control.") + else + //a very elaborate way to suicide + to_chat(human_user,"Eldritch energy lashes out, piercing your fragile mind, tearing it to pieces!") + human_user.ghostize() + var/obj/item/bodypart/head/head = locate() in human_user.bodyparts + if(head) + head.dismember() + qdel(head) + else + human_user.gib() + + var/datum/effect_system/reagents_explosion/explosion = new() + explosion.set_up(1, get_turf(human_user), 1, 0) + explosion.start() + +/obj/effect/broken_illusion/examine(mob/user) + if(!IS_HERETIC(user) && ishuman(user)) + var/mob/living/carbon/human/human_user = user + to_chat(human_user,"Your brain hurts when you look at this!") + human_user.adjustOrganLoss(ORGAN_SLOT_BRAIN,30) + . = ..() + +/obj/effect/reality_smash + name = "/improper reality smash" + icon = 'icons/effects/eldritch.dmi' + anchored = TRUE + resistance_flags = FIRE_PROOF | UNACIDABLE | ACID_PROOF + ///We cannot use icon_state since this is invisible, functions the same way but with custom behaviour. + var/image_state = "reality_smash" + ///Who can see us? + var/list/minds = list() + ///Tracked image + var/image/img + +/obj/effect/reality_smash/Initialize() + . = ..() + img = image(icon, src, image_state, OBJ_LAYER) + generate_name() + +/obj/effect/reality_smash/Destroy() + on_destroy() + return ..() + +///Custom effect that happens on destruction +/obj/effect/reality_smash/proc/on_destroy() + for(var/cm in minds) + var/datum/mind/cultie = cm + if(cultie.current?.client) + cultie.current.client.images -= img + //clear the list + minds -= cultie + GLOB.reality_smash_track.smashes -= src + img = null + new /obj/effect/broken_illusion(drop_location()) + +///Makes the mind able to see this effect +/obj/effect/reality_smash/proc/AddMind(var/datum/mind/cultie) + minds |= cultie + if(cultie.current.client) + cultie.current.client.images |= img + + + +///Makes the mind not able to see this effect +/obj/effect/reality_smash/proc/RemoveMind(var/datum/mind/cultie) + minds -= cultie + if(cultie.current.client) + cultie.current.client.images -= img + + + +///Generates random name +/obj/effect/reality_smash/proc/generate_name() + var/static/list/prefix = list("Omniscient","Thundering","Enlightening","Intrusive","Rejectful","Atomized","Subtle","Rising","Lowering","Fleeting","Towering","Blissful","Arrogant","Threatening","Peaceful","Aggressive") + var/static/list/postfix = list("Flaw","Presence","Crack","Heat","Cold","Memory","Reminder","Breeze","Grasp","Sight","Whisper","Flow","Touch","Veil","Thought","Imperfection","Blemish","Blush") + + name = pick(prefix) + " " + pick(postfix) diff --git a/code/modules/antagonists/eldritch_cult/eldritch_items.dm b/code/modules/antagonists/eldritch_cult/eldritch_items.dm new file mode 100644 index 0000000000..4dab6d789d --- /dev/null +++ b/code/modules/antagonists/eldritch_cult/eldritch_items.dm @@ -0,0 +1,142 @@ +/obj/item/living_heart + name = "living heart" + desc = "Link to the worlds beyond." + icon = 'icons/obj/eldritch.dmi' + icon_state = "living_heart" + w_class = WEIGHT_CLASS_SMALL + ///Target + var/mob/living/carbon/human/target + +/obj/item/living_heart/attack_self(mob/user) + . = ..() + if(!IS_HERETIC(user)) + return + if(!target) + to_chat(user,"No target could be found. Put the living heart on the rune and use the rune to recieve a target.") + return + var/dist = get_dist(user.loc,target.loc) + var/dir = get_dir(user.loc,target.loc) + + switch(dist) + if(0 to 15) + to_chat(user,"[target.real_name] is near you. They are to the [dir2text(dir)] of you!") + if(16 to 31) + to_chat(user,"[target.real_name] is somewhere in your vicinty. They are to the [dir2text(dir)] of you!") + if(32 to 127) + to_chat(user,"[target.real_name] is far away from you. They are to the [dir2text(dir)] of you!") + else + to_chat(user,"[target.real_name] is beyond our reach.") + + if(target.stat == DEAD) + to_chat(user,"[target.real_name] is dead. Bring them onto a transmutation rune!") + +/obj/item/melee/sickly_blade + name = "eldritch blade" + desc = "A sickly green crescent blade, decorated with an ornamental eye. You feel like you're being watched..." + icon = 'icons/obj/eldritch.dmi' + icon_state = "eldritch_blade" + item_state = "eldritch_blade" + lefthand_file = 'icons/mob/inhands/64x64_lefthand.dmi' + righthand_file = 'icons/mob/inhands/64x64_righthand.dmi' + inhand_x_dimension = 64 + inhand_y_dimension = 64 + flags_1 = CONDUCT_1 + sharpness = SHARP_EDGED + w_class = WEIGHT_CLASS_NORMAL + force = 17 + throwforce = 10 + hitsound = 'sound/weapons/bladeslice.ogg' + attack_verb = list("attacked", "slashed", "stabbed", "sliced", "tore", "lacerated", "ripped", "diced", "rended") + +/obj/item/melee/sickly_blade/attack(mob/living/M, mob/living/user) + if(!IS_HERETIC(user)) + to_chat(user,"You feel a pulse of some alien intellect lash out at your mind!") + var/mob/living/carbon/human/human_user = user + human_user.AdjustParalyzed(5 SECONDS) + return FALSE + return ..() + +/obj/item/melee/sickly_blade/afterattack(atom/target, mob/user, proximity_flag, click_parameters) + . = ..() + var/datum/antagonist/heretic/cultie = user.mind.has_antag_datum(/datum/antagonist/heretic) + if(!cultie || !proximity_flag) + return + var/list/knowledge = cultie.get_all_knowledge() + for(var/X in knowledge) + var/datum/eldritch_knowledge/eldritch_knowledge_datum = knowledge[X] + eldritch_knowledge_datum.on_eldritch_blade(target,user,proximity_flag,click_parameters) + +/obj/item/melee/sickly_blade/rust + name = "rusted blade" + desc = "This crescent blade is decrepit, wasting to dust. Yet still it bites, catching flesh with jagged, rotten teeth." + icon_state = "rust_blade" + item_state = "rust_blade" + embedding = list("pain_mult" = 4, "embed_chance" = 75, "fall_chance" = 10, "ignore_throwspeed_threshold" = TRUE) + throwforce = 17 + +/obj/item/melee/sickly_blade/ash + name = "ashen blade" + desc = "Molten and unwrought, a hunk of metal warped to cinders and slag. Unmade, it aspires to be more than it is, and shears soot-filled wounds with a blunt edge." + icon_state = "ash_blade" + item_state = "ash_blade" + force = 20 + +/obj/item/melee/sickly_blade/flesh + name = "flesh blade" + desc = "A crescent blade born from a fleshwarped creature. Keenly aware, it seeks to spread to others the excruciations it has endured from dead origins." + icon_state = "flesh_blade" + item_state = "flesh_blade" + wound_bonus = 5 + bare_wound_bonus = 15 + +/obj/item/clothing/neck/eldritch_amulet + name = "warm eldritch medallion" + desc = "A strange medallion. Peering through the crystalline surface, the world around you melts away. You see your own beating heart, and the pulse of a thousand others." + icon = 'icons/obj/eldritch.dmi' + icon_state = "eye_medalion" + w_class = WEIGHT_CLASS_SMALL + ///What trait do we want to add upon equipiing + var/trait = TRAIT_THERMAL_VISION + +/obj/item/clothing/neck/eldritch_amulet/equipped(mob/user, slot) + . = ..() + if(ishuman(user) && user.mind && slot == SLOT_NECK && IS_HERETIC(user)) + ADD_TRAIT(user, trait, CLOTHING_TRAIT) + user.update_sight() + +/obj/item/clothing/neck/eldritch_amulet/dropped(mob/user) + . = ..() + REMOVE_TRAIT(user, trait, CLOTHING_TRAIT) + user.update_sight() + +/obj/item/clothing/neck/eldritch_amulet/piercing + name = "piercing eldritch medallion" + desc = "A strange medallion. Peering through the crystalline surface, the light refracts into new and terrifying spectrums of color. You see yourself, reflected off cascading mirrors, warped into improbable shapes." + trait = TRAIT_XRAY_VISION + +/obj/item/clothing/head/hooded/cult_hoodie/eldritch + name = "ominous hood" + icon_state = "eldritch" + desc = "A torn, dust-caked hood. Strange eyes line the inside." + flags_inv = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDEFACIALHAIR + flags_cover = HEADCOVERSEYES | HEADCOVERSMOUTH + flash_protect = 2 + +/obj/item/clothing/suit/hooded/cultrobes/eldritch + name = "ominous armor" + desc = "A ragged, dusty set of robes. Strange eyes line the inside." + icon_state = "eldritch_armor" + item_state = "eldritch_armor" + flags_inv = HIDESHOES|HIDEJUMPSUIT + body_parts_covered = CHEST|GROIN|LEGS|FEET|ARMS + allowed = list(/obj/item/melee/sickly_blade, /obj/item/forbidden_book) + hoodtype = /obj/item/clothing/head/hooded/cult_hoodie/eldritch + // slightly better than normal cult robes + armor = list("melee" = 50, "bullet" = 50, "laser" = 50,"energy" = 50, "bomb" = 35, "bio" = 20, "rad" = 0, "fire" = 20, "acid" = 20) + +/obj/item/reagent_containers/glass/beaker/eldritch + name = "flask of eldritch essence" + desc = "Toxic to the close minded. Healing to those with knowledge of the beyond." + icon = 'icons/obj/eldritch.dmi' + icon_state = "eldrich_flask" + list_reagents = list(/datum/reagent/eldritch = 50) diff --git a/code/modules/antagonists/eldritch_cult/eldritch_knowledge.dm b/code/modules/antagonists/eldritch_cult/eldritch_knowledge.dm new file mode 100644 index 0000000000..065844bedf --- /dev/null +++ b/code/modules/antagonists/eldritch_cult/eldritch_knowledge.dm @@ -0,0 +1,303 @@ + +/** + * #Eldritch Knwoledge + * + * Datum that makes eldritch cultist interesting. + * + * Eldritch knowledge aren't instantiated anywhere roundstart, and are initalized and destroyed as the round goes on. + */ +/datum/eldritch_knowledge + ///Name of the knowledge + var/name = "Basic knowledge" + ///Description of the knowledge + var/desc = "Basic knowledge of forbidden arts." + ///What shows up + var/gain_text = "" + ///Cost of knowledge in souls + var/cost = 0 + ///Next knowledge in the research tree + var/list/next_knowledge = list() + ///What knowledge is incompatible with this. This will simply make it impossible to research knowledges that are in banned_knowledge once this gets researched. + var/list/banned_knowledge = list() + ///Used with rituals, how many items this needs + var/list/required_atoms = list() + ///What do we get out of this + var/list/result_atoms = list() + ///What path is this on defaults to "Side" + var/route = PATH_SIDE + +/datum/eldritch_knowledge/New() + . = ..() + var/list/temp_list + for(var/X in required_atoms) + var/atom/A = X + temp_list += list(typesof(A)) + required_atoms = temp_list + +/** + * What happens when this is assigned to an antag datum + * + * This proc is called whenever a new eldritch knowledge is added to an antag datum + */ +/datum/eldritch_knowledge/proc/on_gain(mob/user) + to_chat(user, "[gain_text]") + return +/** + * What happens when you loose this + * + * This proc is called whenever antagonist looses his antag datum, put cleanup code in here + */ +/datum/eldritch_knowledge/proc/on_lose(mob/user) + return +/** + * What happens every tick + * + * This proc is called on SSprocess in eldritch cultist antag datum. SSprocess happens roughly every second + */ +/datum/eldritch_knowledge/proc/on_life(mob/user) + return + +/** + * Special check for recipes + * + * If you are adding a more complex summoning or something that requires a special check that parses through all the atoms in an area override this. + */ +/datum/eldritch_knowledge/proc/recipe_snowflake_check(list/atoms,loc) + return TRUE + +/** + * What happens once the recipe is succesfully finished + * + * By default this proc creates atoms from result_atoms list. Override this is you want something else to happen. + */ +/datum/eldritch_knowledge/proc/on_finished_recipe(mob/living/user,list/atoms,loc) + if(result_atoms.len == 0) + return FALSE + + for(var/A in result_atoms) + new A(loc) + + return TRUE + +/** + * Used atom cleanup + * + * Overide this proc if you dont want ALL ATOMS to be destroyed. useful in many situations. + */ +/datum/eldritch_knowledge/proc/cleanup_atoms(list/atoms) + for(var/X in atoms) + var/atom/A = X + if(!isliving(A)) + atoms -= A + qdel(A) + return + +/** + * Mansus grasp act + * + * Gives addtional effects to mansus grasp spell + */ +/datum/eldritch_knowledge/proc/on_mansus_grasp(atom/target, mob/user, proximity_flag, click_parameters) + return FALSE + + +/** + * Sickly blade act + * + * Gives addtional effects to sickly blade weapon + */ +/datum/eldritch_knowledge/proc/on_eldritch_blade(target,user,proximity_flag,click_parameters) + return + +////////////// +///Subtypes/// +////////////// + +/datum/eldritch_knowledge/spell + var/obj/effect/proc_holder/spell/spell_to_add + +/datum/eldritch_knowledge/spell/on_gain(mob/user) + var/obj/effect/proc_holder/S = new spell_to_add + user.mind.AddSpell(S) + return ..() + +/datum/eldritch_knowledge/spell/on_lose(mob/user) + user.mind.RemoveSpell(spell_to_add) + return ..() + +/datum/eldritch_knowledge/curse + var/timer = 5 MINUTES + var/list/fingerprints = list() + +/datum/eldritch_knowledge/curse/recipe_snowflake_check(list/atoms, loc) + fingerprints = list() + for(var/X in atoms) + var/atom/A = X + fingerprints |= A.fingerprints + listclearnulls(fingerprints) + if(fingerprints.len == 0) + return FALSE + return TRUE + +/datum/eldritch_knowledge/curse/on_finished_recipe(mob/living/user,list/atoms,loc) + + var/list/compiled_list = list() + + for(var/H in GLOB.human_list) + var/mob/living/carbon/human/human_to_check = H + if(fingerprints[md5(human_to_check.dna.uni_identity)]) + compiled_list |= human_to_check.real_name + compiled_list[human_to_check.real_name] = human_to_check + + if(compiled_list.len == 0) + to_chat(user, "The items don't posses required fingerprints.") + return FALSE + + var/chosen_mob = input("Select the person you wish to curse","Your target") as null|anything in sortList(compiled_list, /proc/cmp_mob_realname_dsc) + if(!chosen_mob) + return FALSE + curse(compiled_list[chosen_mob]) + addtimer(CALLBACK(src, .proc/uncurse, compiled_list[chosen_mob]),timer) + return TRUE + +/datum/eldritch_knowledge/curse/proc/curse(mob/living/chosen_mob) + return + +/datum/eldritch_knowledge/curse/proc/uncurse(mob/living/chosen_mob) + return + +/datum/eldritch_knowledge/summon + //Mob to summon + var/mob/living/mob_to_summon + + +/datum/eldritch_knowledge/summon/on_finished_recipe(mob/living/user,list/atoms,loc) + //we need to spawn the mob first so that we can use it in pollCandidatesForMob, we will move it from nullspace down the code + var/mob/living/summoned = new mob_to_summon(loc) + message_admins("[summoned.name] is being summoned by [user.real_name] in [loc]") + var/list/mob/dead/observer/candidates = pollCandidatesForMob("Do you want to play as [summoned.name]", ROLE_HERETIC, null, FALSE, 100, summoned) + if(!LAZYLEN(candidates)) + to_chat(user,"No ghost could be found...") + qdel(summoned) + return FALSE + var/mob/dead/observer/C = pick(candidates) + log_game("[key_name_admin(C)] has taken control of ([key_name_admin(summoned)]), their master is [user.real_name]") + summoned.ghostize(FALSE) + summoned.key = C.key + summoned.mind.add_antag_datum(/datum/antagonist/heretic_monster) + var/datum/antagonist/heretic_monster/heretic_monster = summoned.mind.has_antag_datum(/datum/antagonist/heretic_monster) + var/datum/antagonist/heretic/master = user.mind.has_antag_datum(/datum/antagonist/heretic) + heretic_monster.set_owner(master) + return TRUE + +//Ascension knowledge +/datum/eldritch_knowledge/final + var/finished = FALSE + +/datum/eldritch_knowledge/final/recipe_snowflake_check(list/atoms, loc,selected_atoms) + if(finished) + return FALSE + var/counter = 0 + for(var/mob/living/carbon/human/H in atoms) + selected_atoms |= H + counter++ + if(counter == 3) + return TRUE + return FALSE + +/datum/eldritch_knowledge/final/on_finished_recipe( mob/living/user, list/atoms, loc) + finished = TRUE + return TRUE + +/datum/eldritch_knowledge/final/cleanup_atoms(list/atoms) + . = ..() + for(var/mob/living/carbon/human/H in atoms) + atoms -= H + H.gib() + + +/////////////// +///Base lore/// +/////////////// + +/datum/eldritch_knowledge/spell/basic + name = "Break of Dawn" + desc = "Starts your journey in the mansus. Allows you to select a target using a living heart on a transmutation rune." + gain_text = "Gates of Mansus open up to your mind." + next_knowledge = list(/datum/eldritch_knowledge/base_rust,/datum/eldritch_knowledge/base_ash,/datum/eldritch_knowledge/base_flesh) + cost = 0 + spell_to_add = /obj/effect/proc_holder/spell/targeted/touch/mansus_grasp + required_atoms = list(/obj/item/living_heart) + route = "Start" + +/datum/eldritch_knowledge/spell/basic/recipe_snowflake_check(list/atoms, loc) + . = ..() + for(var/obj/item/living_heart/LH in atoms) + if(!LH.target) + return TRUE + if(LH.target in atoms) + return TRUE + return FALSE + +/datum/eldritch_knowledge/spell/basic/on_finished_recipe(mob/living/user, list/atoms, loc) + . = TRUE + var/mob/living/carbon/carbon_user = user + for(var/obj/item/living_heart/LH in atoms) + + if(LH.target && LH.target.stat == DEAD) + to_chat(carbon_user,"Your patrons accepts your offer...") + var/mob/living/carbon/human/H = LH.target + H.become_husk() + LH.target = null + var/datum/antagonist/heretic/EC = carbon_user.mind.has_antag_datum(/datum/antagonist/heretic) + + EC.total_sacrifices++ + for(var/X in carbon_user.get_all_gear()) + if(!istype(X,/obj/item/forbidden_book)) + continue + var/obj/item/forbidden_book/FB = X + FB.charge++ + FB.charge++ + break + + if(!LH.target) + var/datum/objective/A = new + A.owner = user.mind + var/datum/mind/targeted = A.find_target()//easy way, i dont feel like copy pasting that entire block of code + LH.target = targeted.current + qdel(A) + if(LH.target) + to_chat(user,"Your new target has been selected, go and sacrifice [LH.target.real_name]!") + + else + to_chat(user,"target could not be found for living heart.") + +/datum/eldritch_knowledge/spell/basic/cleanup_atoms(list/atoms) + return + +/datum/eldritch_knowledge/living_heart + name = "Living Heart" + desc = "Allows you to create additional living hearts, using a heart, a pool of blood and a poppy. Living hearts when used on a transmutation rune will grant you a person to hunt and sacrifice on the rune. Every sacrifice gives you an additional charge in the book." + gain_text = "Disconnected, yet it still beats." + cost = 0 + required_atoms = list(/obj/item/organ/heart,/obj/effect/decal/cleanable/blood,/obj/item/reagent_containers/food/snacks/grown/poppy) + result_atoms = list(/obj/item/living_heart) + route = "Start" + +/datum/eldritch_knowledge/codex_cicatrix + name = "Codex Cicatrix" + desc = "Allows you to create a spare Codex Cicatrix if you have lost one, using a bible, human skin, a pen and a pair of eyes." + gain_text = "Their hands are at your throat, yet you see them not." + cost = 0 + required_atoms = list(/obj/item/organ/eyes,/obj/item/stack/sheet/animalhide/human,/obj/item/storage/book/bible,/obj/item/pen) + result_atoms = list(/obj/item/forbidden_book) + route = "Start" + +/datum/eldritch_knowledge/eldritch_blade + name = "Eldritch Blade" + desc = "Allows you to create a sickly, eldritch blade by transmuting a glass shard and a metal rod atop a transmutation rune." + gain_text = "The first step starts with sacrifice." + cost = 0 + required_atoms = list(/obj/item/shard,/obj/item/stack/rods) + result_atoms = list(/obj/item/melee/sickly_blade) + route = "Start" diff --git a/code/modules/antagonists/eldritch_cult/eldritch_magic.dm b/code/modules/antagonists/eldritch_cult/eldritch_magic.dm new file mode 100644 index 0000000000..d84a997e28 --- /dev/null +++ b/code/modules/antagonists/eldritch_cult/eldritch_magic.dm @@ -0,0 +1,668 @@ +/obj/effect/proc_holder/spell/targeted/ethereal_jaunt/shift/ash + name = "Ashen Passage" + desc = "Low range spell allowing you to pass through a few walls." + school = "transmutation" + invocation = "DULK'ES PRE'ZIMAS" + invocation_type = "whisper" + charge_max = 150 + range = -1 + action_icon = 'icons/mob/actions/actions_ecult.dmi' + action_icon_state = "ash_shift" + action_background_icon_state = "bg_ecult" + jaunt_in_time = 13 + jaunt_duration = 10 + jaunt_in_type = /obj/effect/temp_visual/dir_setting/ash_shift + jaunt_out_type = /obj/effect/temp_visual/dir_setting/ash_shift/out + +/obj/effect/proc_holder/spell/targeted/ethereal_jaunt/shift/ash/long + jaunt_duration = 50 + +/obj/effect/proc_holder/spell/targeted/ethereal_jaunt/shift/ash/play_sound() + return + +/obj/effect/temp_visual/dir_setting/ash_shift + name = "ash_shift" + icon = 'icons/mob/mob.dmi' + icon_state = "ash_shift2" + duration = 13 + +/obj/effect/temp_visual/dir_setting/ash_shift/out + icon_state = "ash_shift" + +/obj/effect/proc_holder/spell/targeted/touch/mansus_grasp + name = "Mansus Grasp" + desc = "Touch spell that allows you to channel the power of the Old Gods through you." + hand_path = /obj/item/melee/touch_attack/mansus_fist + school = "evocation" + charge_max = 150 + clothes_req = FALSE + action_icon = 'icons/mob/actions/actions_ecult.dmi' + action_icon_state = "mansus_grasp" + action_background_icon_state = "bg_ecult" + +/obj/item/melee/touch_attack/mansus_fist + name = "Mansus Grasp" + desc = "A sinister looking aura that distorts the flow of reality around it. Causes knockdown, major stamina damage aswell as some Brute. It gains additional beneficial effects with certain knowledges you can research." + icon_state = "disintegrate" + item_state = "disintegrate" + catchphrase = "T'IESA SIE'KTI VISATA" + +/obj/item/melee/touch_attack/mansus_fist/afterattack(atom/target, mob/user, proximity_flag, click_parameters) + + if(!proximity_flag || target == user) + return + playsound(user, 'sound/items/welder.ogg', 75, TRUE) + if(ishuman(target)) + var/mob/living/carbon/human/tar = target + if(tar.anti_magic_check()) + tar.visible_message("Spell bounces off of [target]!","The spell bounces off of you!") + return ..() + var/datum/mind/M = user.mind + var/datum/antagonist/heretic/cultie = M.has_antag_datum(/datum/antagonist/heretic) + + var/use_charge = FALSE + if(iscarbon(target)) + use_charge = TRUE + var/mob/living/carbon/C = target + C.adjustBruteLoss(15) + C.DefaultCombatKnockdown(50, override_stamdmg = 0) + C.adjustStaminaLoss(60) + var/list/knowledge = cultie.get_all_knowledge() + + for(var/X in knowledge) + var/datum/eldritch_knowledge/EK = knowledge[X] + if(EK.on_mansus_grasp(target, user, proximity_flag, click_parameters)) + use_charge = TRUE + if(use_charge) + return ..() + +/obj/effect/proc_holder/spell/aoe_turf/rust_conversion + name = "Aggressive Spread" + desc = "Spreads rust onto nearby turfs." + school = "transmutation" + charge_max = 300 //twice as long as mansus grasp + clothes_req = FALSE + invocation = "PLI'STI MINO DOMI'KA" + invocation_type = "whisper" + range = 3 + action_icon = 'icons/mob/actions/actions_ecult.dmi' + action_icon_state = "corrode" + action_background_icon_state = "bg_ecult" + +/obj/effect/proc_holder/spell/aoe_turf/rust_conversion/cast(list/targets, mob/user = usr) + playsound(user, 'sound/items/welder.ogg', 75, TRUE) + for(var/turf/T in targets) + ///What we want is the 3 tiles around the user and the tile under him to be rusted, so min(dist,1)-1 causes us to get 0 for these tiles, rest of the tiles are based on chance + var/chance = 100 - (max(get_dist(T,user),1)-1)*100/(range+1) + if(!prob(chance)) + continue + T.rust_heretic_act() + +/obj/effect/proc_holder/spell/aoe_turf/rust_conversion/small + name = "Rust Conversion" + desc = "Spreads rust onto nearby turfs." + range = 2 + +/obj/effect/proc_holder/spell/targeted/touch/blood_siphon + name = "Blood Siphon" + desc = "Touch spell that heals you while damaging the enemy, has a chance to transfer wounds between you and your enemy." + hand_path = /obj/item/melee/touch_attack/blood_siphon + school = "evocation" + charge_max = 150 + clothes_req = FALSE + invocation_type = "none" + action_icon = 'icons/mob/actions/actions_ecult.dmi' + action_icon_state = "blood_siphon" + action_background_icon_state = "bg_ecult" + +/obj/item/melee/touch_attack/blood_siphon + name = "Blood Siphon" + desc = "A sinister looking aura that distorts the flow of reality around it." + icon_state = "disintegrate" + item_state = "disintegrate" + catchphrase = "SUN'AI'KINI'MAS" + +/obj/item/melee/touch_attack/blood_siphon/afterattack(atom/target, mob/user, proximity_flag, proximity) + if(!proximity_flag) + return + playsound(user, 'sound/effects/curseattack.ogg', 75, TRUE) + if(ishuman(target)) + var/mob/living/carbon/human/tar = target + if(tar.anti_magic_check()) + tar.visible_message("Spell bounces off of [target]!","The spell bounces off of you!") + return ..() + var/mob/living/carbon/C2 = user + if(isliving(target)) + var/mob/living/L = target + L.adjustBruteLoss(20) + C2.adjustBruteLoss(-20) + if(iscarbon(target)) + var/mob/living/carbon/C1 = target + for(var/obj/item/bodypart/bodypart in C2.bodyparts) + for(var/i in bodypart.wounds) + var/datum/wound/iter_wound = i + if(prob(50)) + continue + var/obj/item/bodypart/target_bodypart = locate(bodypart.type) in C1.bodyparts + if(!target_bodypart) + continue + iter_wound.remove_wound() + iter_wound.apply_wound(target_bodypart) + + C1.blood_volume -= 20 + if(C2.blood_volume < BLOOD_VOLUME_MAXIMUM) //we dont want to explode after all + C2.blood_volume += 20 + return ..() + +/obj/effect/proc_holder/spell/aimed/rust_wave + name = "Patron's Reach" + desc = "Channels energy into your gauntlet - firing it results in a wave of rust being created in it's wake." + projectile_type = /obj/item/projectile/magic/spell/rust_wave + charge_max = 350 + clothes_req = FALSE + action_icon = 'icons/mob/actions/actions_ecult.dmi' + base_icon_state = "rust_wave" + action_icon_state = "rust_wave" + action_background_icon_state = "bg_ecult" + sound = 'sound/effects/curse5.ogg' + active_msg = "You extend your hand out, preparing to send out a wave of rust." + deactive_msg = "You extinguish that energy, for now..." + invocation = "RUD'ZI VAR'ZTAS" + invocation_type = "whisper" + +/obj/item/projectile/magic/spell/rust_wave + name = "rust bolt" + icon_state = "eldritch_projectile" + alpha = 180 + damage = 30 + damage_type = TOX + nodamage = 0 + hitsound = 'sound/effects/curseattack.ogg' + range = 15 + +/obj/item/projectile/magic/spell/rust_wave/Moved(atom/OldLoc, Dir) + . = ..() + playsound(src, 'sound/items/welder.ogg', 75, TRUE) + var/list/turflist = list() + var/turf/T1 + turflist += get_turf(src) + T1 = get_step(src,turn(dir,90)) + turflist += T1 + turflist += get_step(T1,turn(dir,90)) + T1 = get_step(src,turn(dir,-90)) + turflist += T1 + turflist += get_step(T1,turn(dir,-90)) + for(var/X in turflist) + if(!X || prob(25)) + continue + var/turf/T = X + T.rust_heretic_act() + +/obj/effect/proc_holder/spell/aimed/rust_wave/short + name = "Small Patron's Reach" + projectile_type = /obj/item/projectile/magic/spell/rust_wave/short + +/obj/item/projectile/magic/spell/rust_wave/short + range = 7 + +/obj/effect/proc_holder/spell/pointed/cleave + name = "Cleave" + desc = "Causes severe bleeding on a target and people around them" + school = "transmutation" + charge_max = 350 + clothes_req = FALSE + invocation = "PLES'TI VI'RIBUS" + invocation_type = "whisper" + range = 9 + action_icon = 'icons/mob/actions/actions_ecult.dmi' + action_icon_state = "cleave" + action_background_icon_state = "bg_ecult" + +/obj/effect/proc_holder/spell/pointed/cleave/cast(list/targets, mob/user) + if(!targets.len) + to_chat(user, "No target found in range!") + return FALSE + if(!can_target(targets[1], user)) + return FALSE + + for(var/mob/living/carbon/human/C in range(1,targets[1])) + targets |= C + + + for(var/X in targets) + var/mob/living/carbon/human/target = X + if(target == user) + continue + if(target.anti_magic_check()) + to_chat(user, "The spell had no effect!") + target.visible_message("[target]'s veins flash with fire, but their magic protection repulses the blaze!", \ + "Your veins flash with fire, but your magic protection repels the blaze!") + continue + + target.visible_message("[target]'s veins are shredded from within as an unholy blaze erupts from their blood!", \ + "Your veins burst from within and unholy flame erupts from your blood!") + var/obj/item/bodypart/bodypart = pick(target.bodyparts) + var/datum/wound/slash/critical/crit_wound = new + crit_wound.apply_wound(bodypart) + target.adjustFireLoss(20) + new /obj/effect/temp_visual/cleave(target.drop_location()) + +/obj/effect/proc_holder/spell/pointed/cleave/can_target(atom/target, mob/user, silent) + . = ..() + if(!.) + return FALSE + if(!istype(target,/mob/living/carbon/human)) + if(!silent) + to_chat(user, "You are unable to cleave [target]!") + return FALSE + return TRUE + +/obj/effect/proc_holder/spell/pointed/cleave/long + charge_max = 650 + +/obj/effect/proc_holder/spell/pointed/touch/mad_touch + name = "Touch of Madness" + desc = "Touch spell that drains your enemies sanity." + school = "transmutation" + charge_max = 150 + clothes_req = FALSE + invocation_type = "none" + range = 2 + action_icon = 'icons/mob/actions/actions_ecult.dmi' + action_icon_state = "mad_touch" + action_background_icon_state = "bg_ecult" + +/obj/effect/proc_holder/spell/pointed/touch/mad_touch/can_target(atom/target, mob/user, silent) + . = ..() + if(!.) + return FALSE + if(!istype(target,/mob/living/carbon/human)) + if(!silent) + to_chat(user, "You are unable to touch [target]!") + return FALSE + return TRUE + +/obj/effect/proc_holder/spell/pointed/touch/mad_touch/cast(list/targets, mob/user) + . = ..() + for(var/mob/living/carbon/target in targets) + if(ishuman(targets)) + var/mob/living/carbon/human/tar = target + if(tar.anti_magic_check()) + tar.visible_message("Spell bounces off of [target]!","The spell bounces off of you!") + return + if(target.mind && !target.mind.has_antag_datum(/datum/antagonist/heretic)) + to_chat(user,"[target.name] has been cursed!") + SEND_SIGNAL(target, COMSIG_ADD_MOOD_EVENT, "gates_of_mansus", /datum/mood_event/gates_of_mansus) + +/obj/effect/proc_holder/spell/pointed/ash_final + name = "Nightwatcher's Rite" + desc = "Powerful spell that releases 5 streams of fire away from you." + school = "transmutation" + invocation = "IGNIS'INTI" + invocation_type = "whisper" + charge_max = 300 + range = 15 + clothes_req = FALSE + action_icon = 'icons/mob/actions/actions_ecult.dmi' + action_icon_state = "flames" + action_background_icon_state = "bg_ecult" + +/obj/effect/proc_holder/spell/pointed/ash_final/cast(list/targets, mob/user) + for(var/X in targets) + var/T + T = line_target(-25, range, X, user) + INVOKE_ASYNC(src, .proc/fire_line, user,T) + T = line_target(10, range, X, user) + INVOKE_ASYNC(src, .proc/fire_line, user,T) + T = line_target(0, range, X, user) + INVOKE_ASYNC(src, .proc/fire_line, user,T) + T = line_target(-10, range, X, user) + INVOKE_ASYNC(src, .proc/fire_line, user,T) + T = line_target(25, range, X, user) + INVOKE_ASYNC(src, .proc/fire_line, user,T) + return ..() + +/obj/effect/proc_holder/spell/pointed/ash_final/proc/line_target(offset, range, atom/at , atom/user) + if(!at) + return + var/angle = ATAN2(at.x - user.x, at.y - user.y) + offset + var/turf/T = get_turf(user) + for(var/i in 1 to range) + var/turf/check = locate(user.x + cos(angle) * i, user.y + sin(angle) * i, user.z) + if(!check) + break + T = check + return (getline(user, T) - get_turf(user)) + +/obj/effect/proc_holder/spell/pointed/ash_final/proc/fire_line(atom/source, list/turfs) + var/list/hit_list = list() + for(var/turf/T in turfs) + if(istype(T, /turf/closed)) + break + + for(var/mob/living/L in T.contents) + if(L.anti_magic_check()) + L.visible_message("Spell bounces off of [L]!","The spell bounces off of you!") + continue + if(L in hit_list || L == source) + continue + hit_list += L + L.adjustFireLoss(20) + to_chat(L, "You're hit by [source]'s fire breath!") + + new /obj/effect/hotspot(T) + T.hotspot_expose(700,50,1) + // deals damage to mechs + for(var/obj/mecha/M in T.contents) + if(M in hit_list) + continue + hit_list += M + M.take_damage(45, BURN, "melee", 1) + sleep(1.5) + +/obj/effect/proc_holder/spell/targeted/shapeshift/eldritch + invocation_type = "none" + clothes_req = FALSE + action_background_icon_state = "bg_ecult" + sound = 'sound/magic/enter_blood.ogg' + possible_shapes = list(/mob/living/simple_animal/mouse,\ + /mob/living/simple_animal/pet/dog/corgi,\ + /mob/living/simple_animal/hostile/carp,\ + /mob/living/simple_animal/bot/secbot, \ + /mob/living/simple_animal/pet/fox,\ + /mob/living/simple_animal/pet/cat ) + +/obj/effect/proc_holder/spell/targeted/emplosion/eldritch + name = "Energetic Pulse" + invocation_type = "none" + clothes_req = FALSE + action_background_icon_state = "bg_ecult" + range = -1 + include_user = TRUE + charge_max = 300 + emp_heavy = 6 + emp_light = 10 + sound = 'sound/effects/lingscreech.ogg' + +/obj/effect/proc_holder/spell/aoe_turf/fire_cascade + name = "Fire Cascade" + desc = "creates hot turfs around you." + school = "transmutation" + charge_max = 300 //twice as long as mansus grasp + clothes_req = FALSE + invocation = "IGNIS'SAVARIN" + invocation_type = "whisper" + range = 4 + action_icon = 'icons/mob/actions/actions_ecult.dmi' + action_icon_state = "fire_ring" + action_background_icon_state = "bg_ecult" + +/obj/effect/proc_holder/spell/aoe_turf/fire_cascade/cast(list/targets, mob/user = usr) + INVOKE_ASYNC(src, .proc/fire_cascade, user,range) + +/obj/effect/proc_holder/spell/aoe_turf/fire_cascade/proc/fire_cascade(atom/centre,max_range) + playsound(get_turf(centre), 'sound/items/welder.ogg', 75, TRUE) + var/_range = 1 + for(var/i = 0, i <= max_range,i++) + for(var/turf/T in spiral_range_turfs(_range,centre)) + new /obj/effect/hotspot(T) + T.hotspot_expose(700,50,1) + for(var/mob/living/livies in T.contents - centre) + livies.adjustFireLoss(10) + _range++ + sleep(3) + +/obj/effect/proc_holder/spell/aoe_turf/fire_cascade/big + range = 6 + +/obj/effect/proc_holder/spell/targeted/telepathy/eldritch + invocation = "" + invocation_type = "whisper" + clothes_req = FALSE + action_background_icon_state = "bg_ecult" + +/obj/effect/proc_holder/spell/targeted/fire_sworn + name = "Oath of Fire" + desc = "For a minute you will passively create a ring of fire around you." + invocation = "IGNIS'AISTRA'LISTRE" + invocation_type = "whisper" + clothes_req = FALSE + action_background_icon_state = "bg_ecult" + range = -1 + include_user = TRUE + charge_max = 700 + action_icon = 'icons/mob/actions/actions_ecult.dmi' + action_icon_state = "fire_ring" + ///how long it lasts + var/duration = 1 MINUTES + ///who casted it right now + var/mob/current_user + ///Determines if you get the fire ring effect + var/has_fire_ring = FALSE + +/obj/effect/proc_holder/spell/targeted/fire_sworn/cast(list/targets, mob/user) + . = ..() + current_user = user + has_fire_ring = TRUE + addtimer(CALLBACK(src, .proc/remove, user), duration, TIMER_OVERRIDE|TIMER_UNIQUE) + +/obj/effect/proc_holder/spell/targeted/fire_sworn/proc/remove() + has_fire_ring = FALSE + +/obj/effect/proc_holder/spell/targeted/fire_sworn/process() + . = ..() + if(!has_fire_ring) + return + for(var/turf/T in range(1,current_user)) + new /obj/effect/hotspot(T) + T.hotspot_expose(700,50,1) + for(var/mob/living/livies in T.contents - current_user) + livies.adjustFireLoss(5) + + +/obj/effect/proc_holder/spell/targeted/worm_contract + name = "Force Contract" + desc = "Forces all the worm parts to collapse onto a single turf" + invocation_type = "none" + clothes_req = FALSE + action_background_icon_state = "bg_ecult" + range = -1 + include_user = TRUE + charge_max = 300 + action_icon = 'icons/mob/actions/actions_ecult.dmi' + action_icon_state = "worm_contract" + +/obj/effect/proc_holder/spell/targeted/worm_contract/cast(list/targets, mob/user) + . = ..() + if(!istype(user,/mob/living/simple_animal/hostile/eldritch/armsy)) + to_chat(user, "You try to contract your muscles but nothing happens...") + var/mob/living/simple_animal/hostile/eldritch/armsy/armsy = user + armsy.contract_next_chain_into_single_tile() + +/obj/effect/temp_visual/cleave + icon = 'icons/effects/eldritch.dmi' + icon_state = "cleave" + duration = 6 + +/obj/effect/temp_visual/eldritch_smoke + icon = 'icons/effects/eldritch.dmi' + icon_state = "smoke" + duration = 10 + +/obj/effect/proc_holder/spell/targeted/fiery_rebirth + name = "Nightwatcher's Rebirth" + desc = "Drains nearby alive people that are engulfed in flames. It heals 10 of each damage type per person. If a person is in critical condition it finishes them off." + invocation = "PETHRO'MINO'IGNI" + invocation_type = "whisper" + clothes_req = FALSE + action_background_icon_state = "bg_ecult" + range = -1 + include_user = TRUE + charge_max = 600 + action_icon = 'icons/mob/actions/actions_ecult.dmi' + action_icon_state = "smoke" + +/obj/effect/proc_holder/spell/targeted/fiery_rebirth/cast(list/targets, mob/user) + if(!ishuman(user)) + return + var/mob/living/carbon/human/human_user = user + for(var/mob/living/carbon/target in view(7,user)) + if(target.stat == DEAD || !target.on_fire) + continue + //This is essentially a death mark, use this to finish your opponent quicker. + if(target.InCritical()) + target.death() + target.adjustFireLoss(20) + new /obj/effect/temp_visual/eldritch_smoke(target.drop_location()) + human_user.ExtinguishMob() + human_user.adjustBruteLoss(-10, FALSE) + human_user.adjustFireLoss(-10, FALSE) + human_user.adjustStaminaLoss(-10, FALSE) + human_user.adjustToxLoss(-10, FALSE) + human_user.adjustOxyLoss(-10) + +/obj/effect/proc_holder/spell/pointed/manse_link + name = "Mansus Link" + desc = "Piercing through reality, connecting minds. This spell allows you to add people to a mansus net, allowing them to communicate with eachother" + school = "transmutation" + charge_max = 300 + clothes_req = FALSE + invocation = "SUSEI' METO MIN'TIS" + invocation_type = "whisper" + range = 10 + action_icon = 'icons/mob/actions/actions_ecult.dmi' + action_icon_state = "mansus_link" + action_background_icon_state = "bg_ecult" + +/obj/effect/proc_holder/spell/pointed/manse_link/can_target(atom/target, mob/user, silent) + if(!isliving(target)) + return FALSE + return TRUE + +/obj/effect/proc_holder/spell/pointed/manse_link/cast(list/targets, mob/user) + var/mob/living/simple_animal/hostile/eldritch/raw_prophet/originator = user + + var/mob/living/target = targets[1] + + to_chat(originator, "You begin linking [target]'s mind to yours...") + to_chat(target, "You feel your mind being pulled... connected... intertwined with the very fabric of reality...") + if(!do_after(originator, 6 SECONDS, target)) + return + if(!originator.link_mob(target)) + to_chat(originator, "You can't seem to link [target]'s mind...") + to_chat(target, "The foreign presence leaves your mind.") + return + to_chat(originator, "You connect [target]'s mind to your mansus link!") + + +/datum/action/innate/mansus_speech + name = "Mansus Link" + desc = "Send a psychic message to everyone connected to your mansus link." + button_icon_state = "link_speech" + icon_icon = 'icons/mob/actions/actions_slime.dmi' + background_icon_state = "bg_ecult" + var/mob/living/simple_animal/hostile/eldritch/raw_prophet/originator + +/datum/action/innate/mansus_speech/New(_originator) + . = ..() + originator = _originator + +/datum/action/innate/mansus_speech/Activate() + var/mob/living/living_owner = owner + if(!originator?.linked_mobs[living_owner]) + CRASH("Uh oh the mansus link got somehow activated without it being linked to a raw prophet or the mob not being in a list of mobs that should be able to do it.") + + var/message = sanitize(input("Message:", "Telepathy from the Manse") as text|null) + + if(QDELETED(living_owner)) + return + + if(!originator?.linked_mobs[living_owner]) + to_chat(living_owner, "The link seems to have been severed...") + Remove(living_owner) + return + if(message) + var/msg = "\[Mansus Link\] [living_owner]: [message]" + log_directed_talk(living_owner, originator, msg, LOG_SAY, "Mansus Link") + to_chat(originator.linked_mobs, msg) + + for(var/dead_mob in GLOB.dead_mob_list) + var/link = FOLLOW_LINK(dead_mob, living_owner) + to_chat(dead_mob, "[link] [msg]") + +/obj/effect/proc_holder/spell/pointed/trigger/blind/eldritch + range = 10 + invocation = "AK'LIS" + action_background_icon_state = "bg_ecult" + +/obj/effect/temp_visual/dir_setting/entropic + icon = 'icons/effects/160x160.dmi' + icon_state = "entropic_plume" + duration = 3 SECONDS + +/obj/effect/temp_visual/dir_setting/entropic/setDir(dir) + . = ..() + switch(dir) + if(NORTH) + pixel_x = -64 + if(SOUTH) + pixel_x = -64 + pixel_y = -128 + if(EAST) + pixel_y = -64 + if(WEST) + pixel_y = -64 + pixel_x = -128 + +/obj/effect/temp_visual/glowing_rune + icon = 'icons/effects/eldritch.dmi' + icon_state = "small_rune_1" + duration = 1 MINUTES + layer = LOW_SIGIL_LAYER + +/obj/effect/temp_visual/glowing_rune/Initialize() + . = ..() + pixel_y = rand(-6,6) + pixel_x = rand(-6,6) + icon_state = "small_rune_[rand(12)]" + update_icon() + +/obj/effect/proc_holder/spell/cone/staggered/entropic_plume + name = "Entropic Plume" + desc = "Spews forth a disorienting plume that causes enemies to strike each other, briefly blinds them(increasing with range) and poisons them(decreasing with range). Also spreads rust in the path of the plume." + school = "illusion" + invocation = "RU'KAS NU'DYTI" + invocation_type = "whisper" + clothes_req = FALSE + action_background_icon_state = "bg_ecult" + action_icon = 'icons/mob/actions/actions_ecult.dmi' + action_icon_state = "entropic_plume" + charge_max = 300 + cone_levels = 5 + respect_density = TRUE + +/obj/effect/proc_holder/spell/cone/staggered/entropic_plume/cast(list/targets,mob/user = usr) + . = ..() + new /obj/effect/temp_visual/dir_setting/entropic(get_step(user,user.dir), user.dir) + +/obj/effect/proc_holder/spell/cone/staggered/entropic_plume/do_turf_cone_effect(turf/target_turf, level) + . = ..() + target_turf.rust_heretic_act() + +/obj/effect/proc_holder/spell/cone/staggered/entropic_plume/do_mob_cone_effect(mob/living/victim, level) + . = ..() + if(victim.anti_magic_check() || IS_HERETIC(victim) || victim.mind?.has_antag_datum(/datum/antagonist/heretic_monster)) + return + victim.apply_status_effect(STATUS_EFFECT_AMOK) + victim.apply_status_effect(STATUS_EFFECT_CLOUDSTRUCK, (level*10)) + if(iscarbon(victim)) + var/mob/living/carbon/carbon_victim = victim + carbon_victim.reagents.add_reagent(/datum/reagent/eldritch, min(1, 6-level)) + +/obj/effect/proc_holder/spell/cone/staggered/entropic_plume/calculate_cone_shape(current_level) + if(current_level == cone_levels) + return 5 + else if(current_level == cone_levels-1) + return 3 + else + return 2 diff --git a/code/modules/antagonists/eldritch_cult/eldritch_monster_antag.dm b/code/modules/antagonists/eldritch_cult/eldritch_monster_antag.dm new file mode 100644 index 0000000000..529128fc0a --- /dev/null +++ b/code/modules/antagonists/eldritch_cult/eldritch_monster_antag.dm @@ -0,0 +1,43 @@ +///Tracking reasons +/datum/antagonist/heretic_monster + name = "Eldritch Horror" + roundend_category = "Heretics" + antagpanel_category = "Heretic Beast" + antag_moodlet = /datum/mood_event/heretics + job_rank = ROLE_HERETIC + antag_hud_type = ANTAG_HUD_HERETIC + antag_hud_name = "heretic_beast" + var/datum/antagonist/master + +/datum/antagonist/heretic_monster/admin_add(datum/mind/new_owner,mob/admin) + new_owner.add_antag_datum(src) + message_admins("[key_name_admin(admin)] has heresized [key_name_admin(new_owner)].") + log_admin("[key_name(admin)] has heresized [key_name(new_owner)].") + +/datum/antagonist/heretic_monster/greet() + owner.current.playsound_local(get_turf(owner.current), 'sound/ambience/antag/ecult_op.ogg', 100, FALSE, pressure_affected = FALSE)//subject to change + to_chat(owner, "You became an Eldritch Horror!") + +/datum/antagonist/heretic_monster/on_removal() + if(owner) + to_chat(owner, "Your master is no longer [master.owner.current.real_name]") + owner = null + return ..() + +/datum/antagonist/heretic_monster/proc/set_owner(datum/antagonist/_master) + master = _master + var/datum/objective/master_obj = new + master_obj.owner = src + master_obj.explanation_text = "Assist your master in any way you can!" + objectives += master_obj + owner.announce_objectives() + to_chat(owner, "Your master is [master.owner.current.real_name]") + return + +/datum/antagonist/heretic_monster/apply_innate_effects(mob/living/mob_override) + . = ..() + add_antag_hud(antag_hud_type, antag_hud_name, owner.current) + +/datum/antagonist/heretic_monster/remove_innate_effects(mob/living/mob_override) + . = ..() + remove_antag_hud(antag_hud_type, owner.current) diff --git a/code/modules/antagonists/eldritch_cult/knowledge/ash_lore.dm b/code/modules/antagonists/eldritch_cult/knowledge/ash_lore.dm new file mode 100644 index 0000000000..8efd9837a9 --- /dev/null +++ b/code/modules/antagonists/eldritch_cult/knowledge/ash_lore.dm @@ -0,0 +1,183 @@ +/datum/eldritch_knowledge/base_ash + name = "Nightwatcher's Secret" + desc = "Inducts you into the Path of Ash. Allows you to transmute a match with an eldritch blade into an ashen blade." + gain_text = "The City guard knows their watch. If you ask them at night they may tell you about the ashy lantern." + banned_knowledge = list(/datum/eldritch_knowledge/base_rust,/datum/eldritch_knowledge/base_flesh,/datum/eldritch_knowledge/final/rust_final,/datum/eldritch_knowledge/final/flesh_final) + next_knowledge = list(/datum/eldritch_knowledge/ashen_grasp) + required_atoms = list(/obj/item/melee/sickly_blade,/obj/item/match) + result_atoms = list(/obj/item/melee/sickly_blade/ash) + cost = 1 + route = PATH_ASH + +/datum/eldritch_knowledge/spell/ashen_shift + name = "Ashen Shift" + gain_text = "Ash is all the same, how can one man master it all?" + desc = "A short range jaunt that will enable you to escape from danger." + cost = 1 + spell_to_add = /obj/effect/proc_holder/spell/targeted/ethereal_jaunt/shift/ash + next_knowledge = list(/datum/eldritch_knowledge/ash_mark,/datum/eldritch_knowledge/essence,/datum/eldritch_knowledge/ashen_eyes) + route = PATH_ASH + +/datum/eldritch_knowledge/ashen_grasp + name = "Grasp of Ash" + gain_text = "Gates have opened, minds have flooded, yet I remain." + desc = "Empowers your mansus grasp to knock enemies down and throw them away." + cost = 1 + next_knowledge = list(/datum/eldritch_knowledge/spell/ashen_shift) + route = PATH_ASH + +/datum/eldritch_knowledge/ashen_grasp/on_mansus_grasp(atom/target, mob/user, proximity_flag, click_parameters) + . = ..() + if(!iscarbon(target)) + return + + var/mob/living/carbon/C = target + var/datum/status_effect/eldritch/E = C.has_status_effect(/datum/status_effect/eldritch/rust) || C.has_status_effect(/datum/status_effect/eldritch/ash) || C.has_status_effect(/datum/status_effect/eldritch/flesh) + if(E) + . = TRUE + E.on_effect() + for(var/X in user.mind.spell_list) + if(!istype(X,/obj/effect/proc_holder/spell/targeted/touch/mansus_grasp)) + continue + var/obj/effect/proc_holder/spell/targeted/touch/mansus_grasp/MG = X + MG.charge_counter = min(round(MG.charge_counter + MG.charge_max * 0.75),MG.charge_max) // refunds 75% of charge. + var/atom/throw_target = get_edge_target_turf(C, user.dir) + if(!C.anchored) + . = TRUE + C.throw_at(throw_target, rand(4,8), 14, user) + return + +/datum/eldritch_knowledge/ashen_eyes + name = "Ashen Eyes" + gain_text = "Piercing eyes may guide me through the mundane." + desc = "Allows you to craft thermal vision amulet by transmutating eyes with a glass shard." + cost = 1 + next_knowledge = list(/datum/eldritch_knowledge/spell/ashen_shift,/datum/eldritch_knowledge/flesh_ghoul) + required_atoms = list(/obj/item/organ/eyes,/obj/item/shard) + result_atoms = list(/obj/item/clothing/neck/eldritch_amulet) + +/datum/eldritch_knowledge/ash_mark + name = "Mark of Ash" + gain_text = "Spread the famine." + desc = "Your sickly blade now applies ash mark on hit. Use your mansus grasp to proc the mark. Mark of Ash causes stamina damage, and fire loss, and spreads to a nearby carbon. Damage decreases with how many times the mark has spread." + cost = 2 + next_knowledge = list(/datum/eldritch_knowledge/curse/blindness) + banned_knowledge = list(/datum/eldritch_knowledge/rust_mark,/datum/eldritch_knowledge/flesh_mark) + route = PATH_ASH + +/datum/eldritch_knowledge/ash_mark/on_eldritch_blade(target,user,proximity_flag,click_parameters) + . = ..() + if(isliving(target)) + var/mob/living/living_target = target + living_target.apply_status_effect(/datum/status_effect/eldritch/ash,5) + +/datum/eldritch_knowledge/curse/blindness + name = "Curse of Blindness" + gain_text = "The blind man walks through the world, unnoticed by the masses." + desc = "Curse someone with 2 minutes of complete blindness by sacrificing a pair of eyes, a screwdriver and a pool of blood, with an object that the victim has touched with their bare hands." + cost = 1 + required_atoms = list(/obj/item/organ/eyes,/obj/item/screwdriver,/obj/effect/decal/cleanable/blood) + next_knowledge = list(/datum/eldritch_knowledge/curse/corrosion,/datum/eldritch_knowledge/ash_blade_upgrade,/datum/eldritch_knowledge/curse/paralysis) + timer = 2 MINUTES + route = PATH_ASH + +/datum/eldritch_knowledge/curse/blindness/curse(mob/living/chosen_mob) + . = ..() + chosen_mob.become_blind(MAGIC_TRAIT) + +/datum/eldritch_knowledge/curse/blindness/uncurse(mob/living/chosen_mob) + . = ..() + chosen_mob.cure_blind(MAGIC_TRAIT) + +/datum/eldritch_knowledge/spell/flame_birth + name = "Fiery Rebirth" + gain_text = "Nightwatcher was a man of principles, and yet he arose from the chaos he vowed to protect from." + desc = "Drains nearby alive people that are engulfed in flames. It heals 10 of each damage type per person. If a person is in critical condition it finishes them off." + cost = 1 + spell_to_add = /obj/effect/proc_holder/spell/targeted/fiery_rebirth + next_knowledge = list(/datum/eldritch_knowledge/spell/cleave,/datum/eldritch_knowledge/summon/ashy,/datum/eldritch_knowledge/final/ash_final) + route = PATH_ASH + +/datum/eldritch_knowledge/ash_blade_upgrade + name = "Blazing Steel" + gain_text = "May the sun burn the heretics." + desc = "Your blade of choice will now add firestacks." + cost = 2 + next_knowledge = list(/datum/eldritch_knowledge/spell/flame_birth) + banned_knowledge = list(/datum/eldritch_knowledge/rust_blade_upgrade,/datum/eldritch_knowledge/flesh_blade_upgrade) + route = PATH_ASH + +/datum/eldritch_knowledge/ash_blade_upgrade/on_eldritch_blade(target,user,proximity_flag,click_parameters) + . = ..() + if(iscarbon(target)) + var/mob/living/carbon/C = target + C.adjust_fire_stacks(1) + C.IgniteMob() + +/datum/eldritch_knowledge/curse/corrosion + name = "Curse of Corrosion" + gain_text = "Cursed land, cursed man, cursed mind." + desc = "Curse someone for 2 minutes of vomiting and major organ damage. Using a wirecutter, a spill of blood, a heart, left arm and a right arm, and an item that the victim touched with their bare hands." + cost = 1 + required_atoms = list(/obj/item/wirecutters,/obj/effect/decal/cleanable/blood,/obj/item/organ/heart,/obj/item/bodypart/l_arm,/obj/item/bodypart/r_arm) + next_knowledge = list(/datum/eldritch_knowledge/curse/blindness,/datum/eldritch_knowledge/spell/area_conversion) + timer = 2 MINUTES + +/datum/eldritch_knowledge/curse/corrosion/curse(mob/living/chosen_mob) + . = ..() + chosen_mob.apply_status_effect(/datum/status_effect/corrosion_curse) + +/datum/eldritch_knowledge/curse/corrosion/uncurse(mob/living/chosen_mob) + . = ..() + chosen_mob.remove_status_effect(/datum/status_effect/corrosion_curse) + +/datum/eldritch_knowledge/curse/paralysis + name = "Curse of Paralysis" + gain_text = "Corrupt their flesh, make them bleed." + desc = "Curse someone for 5 minutes of inability to walk. Using a knife, pool of blood, left leg, right leg, a hatchet and an item that the victim touched with their bare hands. " + cost = 1 + required_atoms = list(/obj/item/kitchen/knife,/obj/effect/decal/cleanable/blood,/obj/item/bodypart/l_leg,/obj/item/bodypart/r_leg,/obj/item/hatchet) + next_knowledge = list(/datum/eldritch_knowledge/curse/blindness,/datum/eldritch_knowledge/summon/raw_prophet) + timer = 5 MINUTES + +/datum/eldritch_knowledge/curse/paralysis/curse(mob/living/chosen_mob) + . = ..() + ADD_TRAIT(chosen_mob,TRAIT_PARALYSIS_L_LEG,MAGIC_TRAIT) + ADD_TRAIT(chosen_mob,TRAIT_PARALYSIS_R_LEG,MAGIC_TRAIT) + chosen_mob.update_mobility() + +/datum/eldritch_knowledge/curse/paralysis/uncurse(mob/living/chosen_mob) + . = ..() + REMOVE_TRAIT(chosen_mob,TRAIT_PARALYSIS_L_LEG,MAGIC_TRAIT) + REMOVE_TRAIT(chosen_mob,TRAIT_PARALYSIS_R_LEG,MAGIC_TRAIT) + chosen_mob.update_mobility() + +/datum/eldritch_knowledge/spell/cleave + name = "Blood Cleave" + gain_text = "At first I was unfamiliar with these instruments of war, but the priest told me how to use them." + desc = "Grants a spell that will inflict wounds and bleeding upon the target, as well as in a short radius around them." + cost = 1 + spell_to_add = /obj/effect/proc_holder/spell/pointed/cleave + next_knowledge = list(/datum/eldritch_knowledge/spell/entropic_plume,/datum/eldritch_knowledge/spell/flame_birth) + +/datum/eldritch_knowledge/final/ash_final + name = "Ashlord's Rite" + gain_text = "The forgotten lords have spoken! The Lord of Ash has come! Fear the flame!" + desc = "Bring three corpses onto a transmutation rune, after ascending you will become immune to fire, space, temperature and other environmental hazards. You will develop resistance to all other damages. You will be granted two spells, one which can bring forth a cascade of massive fire, and another which will surround your body in precious flames for a minute." + required_atoms = list(/mob/living/carbon/human) + cost = 5 + route = PATH_ASH + var/list/trait_list = list(TRAIT_RESISTHEAT,TRAIT_NOBREATH,TRAIT_RESISTCOLD,TRAIT_RESISTHIGHPRESSURE,TRAIT_RESISTLOWPRESSURE,TRAIT_NOFIRE,TRAIT_RADIMMUNE,TRAIT_GENELESS,TRAIT_PIERCEIMMUNE,TRAIT_NODISMEMBER,TRAIT_BOMBIMMUNE) + +/datum/eldritch_knowledge/final/ash_final/on_finished_recipe(mob/living/user, list/atoms, loc) + priority_announce("$^@&#*$^@(#&$(@&#^$&#^@# Fear the blaze, for Ashbringer [user.real_name] has come! $^@&#*$^@(#&$(@&#^$&#^@#","#$^@&#*$^@(#&$(@&#^$&#^@#", 'sound/announcer/classic/spanomalies.ogg') + user.mind.AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/fire_cascade/big) + user.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/fire_sworn) + var/mob/living/carbon/human/H = user + H.physiology.brute_mod *= 0.5 + H.physiology.burn_mod *= 0.5 + var/datum/antagonist/heretic/ascension = H.mind.has_antag_datum(/datum/antagonist/heretic) + ascension.ascended = TRUE + for(var/X in trait_list) + ADD_TRAIT(user,X,MAGIC_TRAIT) + return ..() diff --git a/code/modules/antagonists/eldritch_cult/knowledge/flesh_lore.dm b/code/modules/antagonists/eldritch_cult/knowledge/flesh_lore.dm new file mode 100644 index 0000000000..9684e1fa0c --- /dev/null +++ b/code/modules/antagonists/eldritch_cult/knowledge/flesh_lore.dm @@ -0,0 +1,252 @@ +/datum/eldritch_knowledge/base_flesh + name = "Principle of Hunger" + desc = "Inducts you into the Path of Flesh. Allows you to transmute a pool of blood with your eldritch blade into a Blade of Flesh." + gain_text = "Hundred's of us starved, but I.. I found the strength in my greed." + banned_knowledge = list(/datum/eldritch_knowledge/base_ash,/datum/eldritch_knowledge/base_rust,/datum/eldritch_knowledge/final/ash_final,/datum/eldritch_knowledge/final/rust_final) + next_knowledge = list(/datum/eldritch_knowledge/flesh_grasp) + required_atoms = list(/obj/item/melee/sickly_blade,/obj/effect/decal/cleanable/blood) + result_atoms = list(/obj/item/melee/sickly_blade/flesh) + cost = 1 + route = PATH_FLESH + +/datum/eldritch_knowledge/flesh_ghoul + name = "Imperfect Ritual" + desc = "Allows you to resurrect the dead as voiceless dead by sacrificing them on the transmutation rune with a poppy. Voiceless dead are mute and have 50 HP. You can only have 2 at a time." + gain_text = "I found notes... notes of a ritual, scraps, unfinished, and yet... I still did it." + cost = 1 + required_atoms = list(/mob/living/carbon/human,/obj/item/reagent_containers/food/snacks/grown/poppy) + next_knowledge = list(/datum/eldritch_knowledge/flesh_mark,/datum/eldritch_knowledge/armor,/datum/eldritch_knowledge/ashen_eyes) + route = PATH_FLESH + var/max_amt = 2 + var/current_amt = 0 + var/list/ghouls = list() + +/datum/eldritch_knowledge/flesh_ghoul/on_finished_recipe(mob/living/user,list/atoms,loc) + var/mob/living/carbon/human/humie = locate() in atoms + if(QDELETED(humie) || humie.stat != DEAD) + return + + if(length(ghouls) >= max_amt) + return + + if(HAS_TRAIT(humie,TRAIT_HUSK)) + return + + humie.grab_ghost() + + if(!humie.mind || !humie.client) + var/list/mob/dead/observer/candidates = pollCandidatesForMob("Do you want to play as a [humie.real_name], a voiceless dead.", ROLE_HERETIC, null, ROLE_HERETIC, 50,humie) + if(!LAZYLEN(candidates)) + return + var/mob/dead/observer/C = pick(candidates) + message_admins("[key_name_admin(C)] has taken control of ([key_name_admin(humie)]) to replace an AFK player.") + humie.ghostize(0) + humie.key = C.key + + ADD_TRAIT(humie,TRAIT_MUTE,MAGIC_TRAIT) + log_game("[key_name_admin(humie)] has become a voiceless dead, their master is [user.real_name]") + humie.revive(full_heal = TRUE, admin_revive = TRUE) + humie.setMaxHealth(75) + humie.health = 75 // Voiceless dead are much tougher than ghouls + humie.become_husk() + humie.faction |= "heretics" + + var/datum/antagonist/heretic_monster/heretic_monster = humie.mind.add_antag_datum(/datum/antagonist/heretic_monster) + var/datum/antagonist/heretic/master = user.mind.has_antag_datum(/datum/antagonist/heretic) + heretic_monster.set_owner(master) + atoms -= humie + RegisterSignal(humie,COMSIG_MOB_DEATH,.proc/remove_ghoul) + ghouls += humie + +/datum/eldritch_knowledge/flesh_ghoul/proc/remove_ghoul(datum/source) + var/mob/living/carbon/human/humie = source + ghouls -= humie + humie.mind.remove_antag_datum(/datum/antagonist/heretic_monster) + UnregisterSignal(source,COMSIG_MOB_DEATH) + +/datum/eldritch_knowledge/flesh_grasp + name = "Grasp of Flesh" + gain_text = "'My newfound desire, it drove me to do great things,' The Priest said." + desc = "Empowers your Mansus Grasp to be able to create a single ghoul out of a dead player. You cannot raise the same person twice. Ghouls have only 50 HP and look like husks." + cost = 1 + next_knowledge = list(/datum/eldritch_knowledge/flesh_ghoul) + var/ghoul_amt = 6 + var/list/spooky_scaries + route = PATH_FLESH + +/datum/eldritch_knowledge/flesh_grasp/on_mansus_grasp(atom/target, mob/user, proximity_flag, click_parameters) + . = ..() + if(!ishuman(target) || target == user) + return + var/mob/living/carbon/human/human_target = target + var/datum/status_effect/eldritch/eldritch_effect = human_target.has_status_effect(/datum/status_effect/eldritch/rust) || human_target.has_status_effect(/datum/status_effect/eldritch/ash) || human_target.has_status_effect(/datum/status_effect/eldritch/flesh) + if(eldritch_effect) + . = TRUE + eldritch_effect.on_effect() + if(iscarbon(target)) + var/mob/living/carbon/carbon_target = target + var/obj/item/bodypart/bodypart = pick(carbon_target.bodyparts) + var/datum/wound/slash/severe/crit_wound = new + crit_wound.apply_wound(bodypart) + + if(QDELETED(human_target) || human_target.stat != DEAD) + return + + human_target.grab_ghost() + + if(!human_target.mind || !human_target.client) + to_chat(user, "There is no soul connected to this body...") + return + + if(HAS_TRAIT(human_target, TRAIT_HUSK)) + to_chat(user, "You cannot revive a dead ghoul!") + return + + if(LAZYLEN(spooky_scaries) >= ghoul_amt) + to_chat(user, "Your patron cannot support more ghouls on this plane!") + return + + LAZYADD(spooky_scaries, human_target) + log_game("[key_name_admin(human_target)] has become a ghoul, their master is [user.real_name]") + //we change it to true only after we know they passed all the checks + . = TRUE + RegisterSignal(human_target,COMSIG_MOB_DEATH,.proc/remove_ghoul) + human_target.revive(full_heal = TRUE, admin_revive = TRUE) + human_target.setMaxHealth(40) + human_target.health = 40 + human_target.become_husk() + human_target.faction |= "heretics" + var/datum/antagonist/heretic_monster/heretic_monster = human_target.mind.add_antag_datum(/datum/antagonist/heretic_monster) + var/datum/antagonist/heretic/master = user.mind.has_antag_datum(/datum/antagonist/heretic) + heretic_monster.set_owner(master) + return + + +/datum/eldritch_knowledge/flesh_grasp/proc/remove_ghoul(datum/source) + var/mob/living/carbon/human/humie = source + spooky_scaries -= humie + humie.mind.remove_antag_datum(/datum/antagonist/heretic_monster) + UnregisterSignal(source, COMSIG_MOB_DEATH) + +/datum/eldritch_knowledge/flesh_mark + name = "Mark of Flesh" + gain_text = "I saw them, the marked ones. The screams... the silence." + desc = "Your sickly blade now applies a mark of flesh to those cut by it. Once marked, using your Mansus Grasp upon them will cause additional bleeding from the target." + cost = 2 + next_knowledge = list(/datum/eldritch_knowledge/summon/raw_prophet) + banned_knowledge = list(/datum/eldritch_knowledge/rust_mark,/datum/eldritch_knowledge/ash_mark) + route = PATH_FLESH + +/datum/eldritch_knowledge/flesh_mark/on_eldritch_blade(target,user,proximity_flag,click_parameters) + . = ..() + if(isliving(target)) + var/mob/living/living_target = target + living_target.apply_status_effect(/datum/status_effect/eldritch/flesh) + +/datum/eldritch_knowledge/flesh_blade_upgrade + name = "Bleeding Steel" + gain_text = "It rained blood, that's when I understood the gravekeeper's advice." + desc = "Your blade will now cause additional bleeding to those hit by it." + cost = 2 + next_knowledge = list(/datum/eldritch_knowledge/summon/stalker) + banned_knowledge = list(/datum/eldritch_knowledge/ash_blade_upgrade,/datum/eldritch_knowledge/rust_blade_upgrade) + route = PATH_FLESH + +/datum/eldritch_knowledge/flesh_blade_upgrade/on_eldritch_blade(target,user,proximity_flag,click_parameters) + . = ..() + if(iscarbon(target)) + var/mob/living/carbon/carbon_target = target + var/obj/item/bodypart/bodypart = pick(carbon_target.bodyparts) + var/datum/wound/slash/severe/crit_wound = new + crit_wound.apply_wound(bodypart) + +/datum/eldritch_knowledge/summon/raw_prophet + name = "Raw Ritual" + gain_text = "The uncanny man walks alone in the valley, I was able to call his aid." + desc = "You can now summon a Raw Prophet using eyes, a left arm, right arm and a pool of blood using a transmutation circle. Raw prophets have increased seeing range, and can see through walls. They can jaunt long distances, though they are fragile." + cost = 1 + required_atoms = list(/obj/item/organ/eyes,/obj/item/bodypart/l_arm,/obj/item/bodypart/r_arm,/obj/effect/decal/cleanable/blood) + mob_to_summon = /mob/living/simple_animal/hostile/eldritch/raw_prophet + next_knowledge = list(/datum/eldritch_knowledge/flesh_blade_upgrade,/datum/eldritch_knowledge/spell/blood_siphon,/datum/eldritch_knowledge/curse/paralysis) + route = PATH_FLESH + +/datum/eldritch_knowledge/summon/stalker + name = "Lonely Ritual" + gain_text = "I was able to combine my greed and desires to summon an eldritch beast I have not seen before." + desc = "You can now summon a Stalker using a knife, a flower, a pen and a piece of paper using a transmutation circle. Stalkers possess the ability to shapeshift into various forms while assuming the vigor and powers of that form." + cost = 1 + required_atoms = list(/obj/item/kitchen/knife,/obj/item/reagent_containers/food/snacks/grown/poppy,/obj/item/pen,/obj/item/paper) + mob_to_summon = /mob/living/simple_animal/hostile/eldritch/stalker + next_knowledge = list(/datum/eldritch_knowledge/summon/ashy,/datum/eldritch_knowledge/summon/rusty,/datum/eldritch_knowledge/final/flesh_final) + route = PATH_FLESH + +/datum/eldritch_knowledge/summon/ashy + name = "Ashen Ritual" + gain_text = "I combined principle of hunger with desire of destruction. The eyeful lords have noticed me." + desc = "You can now summon an Ashen One by transmuting a pile of ash, a head and a book using a transmutation circle. They possess the ability to jaunt short distances and create a cascade of flames." + cost = 1 + required_atoms = list(/obj/effect/decal/cleanable/ash,/obj/item/bodypart/head,/obj/item/book) + mob_to_summon = /mob/living/simple_animal/hostile/eldritch/ash_spirit + next_knowledge = list(/datum/eldritch_knowledge/summon/stalker,/datum/eldritch_knowledge/spell/flame_birth) + +/datum/eldritch_knowledge/summon/rusty + name = "Rusted Ritual" + gain_text = "I combined principle of hunger with desire of corruption. The rusted hills call my name." + desc = "You can now summon a Rust Walker transmuting a vomit pool, a head, and a book using a transmutation circle. Rust Walkers possess the ability to spread rust and can fire bolts of rust to further corrode the area." + cost = 1 + required_atoms = list(/obj/effect/decal/cleanable/vomit,/obj/item/bodypart/head,/obj/item/book) + mob_to_summon = /mob/living/simple_animal/hostile/eldritch/rust_spirit + next_knowledge = list(/datum/eldritch_knowledge/summon/stalker,/datum/eldritch_knowledge/spell/entropic_plume) + +/datum/eldritch_knowledge/spell/blood_siphon + name = "Blood Siphon" + gain_text = "Our blood is all the same after all, the owl told me." + desc = "You are granted a spell that drains some of the targets health, and returns it to you. It also has a chance to transfer any wounds you possess onto the target." + cost = 1 + spell_to_add = /obj/effect/proc_holder/spell/targeted/touch/blood_siphon + next_knowledge = list(/datum/eldritch_knowledge/summon/raw_prophet,/datum/eldritch_knowledge/spell/area_conversion) + +/datum/eldritch_knowledge/final/flesh_final + name = "Priest's Final Hymn" + gain_text = "Man of this world. Hear me! For the time of the lord of arms has come!" + desc = "Bring three corpses to a transmutation rune to either ascend as The Lord of the Night or summon a single Terror of the Night, however you cannot ascend more than once." + required_atoms = list(/mob/living/carbon/human) + cost = 5 + route = PATH_FLESH + +/datum/eldritch_knowledge/final/flesh_final/on_finished_recipe(mob/living/user, list/atoms, loc) + var/alert_ = alert(user,"Do you want to ascend as the lord of the night or just summon a terror of the night?","...","Yes","No") + user.SetImmobilized(10 HOURS) // no way someone will stand 10 hours in a spot, just so he can move while the alert is still showing. + switch(alert_) + if("No") + var/mob/living/summoned = new /mob/living/simple_animal/hostile/eldritch/armsy(loc) + message_admins("[summoned.name] is being summoned by [user.real_name] in [loc]") + var/list/mob/dead/observer/candidates = pollCandidatesForMob("Do you want to play as a [summoned.real_name]", ROLE_HERETIC, null, ROLE_HERETIC, 100,summoned) + user.SetImmobilized(0) + if(LAZYLEN(candidates) == 0) + to_chat(user,"No ghost could be found...") + qdel(summoned) + return FALSE + var/mob/dead/observer/ghost_candidate = pick(candidates) + priority_announce("$^@&#*$^@(#&$(@&#^$&#^@# Fear the dark, for vassal of arms has ascended! Terror of the night has come! $^@&#*$^@(#&$(@&#^$&#^@#","#$^@&#*$^@(#&$(@&#^$&#^@#", 'sound/announcer/classic/spanomalies.ogg') + log_game("[key_name_admin(ghost_candidate)] has taken control of ([key_name_admin(summoned)]).") + summoned.ghostize(FALSE) + summoned.key = ghost_candidate.key + summoned.mind.add_antag_datum(/datum/antagonist/heretic_monster) + var/datum/antagonist/heretic_monster/monster = summoned.mind.has_antag_datum(/datum/antagonist/heretic_monster) + var/datum/antagonist/heretic/master = user.mind.has_antag_datum(/datum/antagonist/heretic) + monster.set_owner(master) + master.ascended = TRUE + if("Yes") + var/mob/living/summoned = new /mob/living/simple_animal/hostile/eldritch/armsy/prime(loc,TRUE,10) + summoned.ghostize(0) + user.SetImmobilized(0) + priority_announce("$^@&#*$^@(#&$(@&#^$&#^@# Fear the dark, for king of arms has ascended! Lord of the night has come! $^@&#*$^@(#&$(@&#^$&#^@#","#$^@&#*$^@(#&$(@&#^$&#^@#", 'sound/announcer/classic/spanomalies.ogg') + log_game("[user.real_name] ascended as [summoned.real_name]") + var/mob/living/carbon/carbon_user = user + var/datum/antagonist/heretic/ascension = carbon_user.mind.has_antag_datum(/datum/antagonist/heretic) + ascension.ascended = TRUE + carbon_user.mind.transfer_to(summoned, TRUE) + carbon_user.gib() + + return ..() diff --git a/code/modules/antagonists/eldritch_cult/knowledge/rust_lore.dm b/code/modules/antagonists/eldritch_cult/knowledge/rust_lore.dm new file mode 100644 index 0000000000..74b3753b69 --- /dev/null +++ b/code/modules/antagonists/eldritch_cult/knowledge/rust_lore.dm @@ -0,0 +1,209 @@ +/datum/eldritch_knowledge/base_rust + name = "Blacksmith's Tale" + desc = "Inducts you into the Path of Rust. Allows you to transmute an eldritch blade with any trash item into a Blade of Rust." + gain_text = "'Let me tell you a story,' The Blacksmith said as he gazed into his rusty blade." + banned_knowledge = list(/datum/eldritch_knowledge/base_ash,/datum/eldritch_knowledge/base_flesh,/datum/eldritch_knowledge/final/ash_final,/datum/eldritch_knowledge/final/flesh_final) + next_knowledge = list(/datum/eldritch_knowledge/rust_fist) + required_atoms = list(/obj/item/melee/sickly_blade,/obj/item/trash) + result_atoms = list(/obj/item/melee/sickly_blade/rust) + cost = 1 + route = PATH_RUST + +/datum/eldritch_knowledge/rust_fist + name = "Grasp of Rust" + desc = "Empowers your Mansus Grasp to deal 500 damage to non-living matter and rust any structure it touches. Destroys already rusted structures." + gain_text = "Rust grows on the ceiling of the mansus." + cost = 1 + next_knowledge = list(/datum/eldritch_knowledge/rust_regen) + var/rust_force = 500 + var/static/list/blacklisted_turfs = typecacheof(list(/turf/closed,/turf/open/space,/turf/open/lava,/turf/open/chasm,/turf/open/floor/plating/rust)) + route = PATH_RUST + +/datum/eldritch_knowledge/rust_fist/on_mansus_grasp(atom/target, mob/user, proximity_flag, click_parameters) + . = ..() + if(ishuman(target)) + var/mob/living/carbon/human/H = target + var/datum/status_effect/eldritch/E = H.has_status_effect(/datum/status_effect/eldritch/rust) || H.has_status_effect(/datum/status_effect/eldritch/ash) || H.has_status_effect(/datum/status_effect/eldritch/flesh) + if(E) + E.on_effect() + H.adjustOrganLoss(pick(ORGAN_SLOT_BRAIN,ORGAN_SLOT_EARS,ORGAN_SLOT_EYES,ORGAN_SLOT_LIVER,ORGAN_SLOT_LUNGS,ORGAN_SLOT_STOMACH,ORGAN_SLOT_HEART),25) + target.rust_heretic_act() + target.emp_act(EMP_HEAVY) + return TRUE + +/datum/eldritch_knowledge/spell/area_conversion + name = "Aggressive Spread" + desc = "Spreads rust to nearby turfs. Destroys already rusted walls." + gain_text = "All wise men know not to touch the bound king." + cost = 1 + spell_to_add = /obj/effect/proc_holder/spell/aoe_turf/rust_conversion + next_knowledge = list(/datum/eldritch_knowledge/rust_blade_upgrade,/datum/eldritch_knowledge/curse/corrosion,/datum/eldritch_knowledge/spell/blood_siphon,/datum/eldritch_knowledge/spell/rust_wave) + route = PATH_RUST + +/datum/eldritch_knowledge/spell/rust_wave + name = "Patron's Reach" + desc = "You can now send a bolt of rust that corrupts the immediate area, and poisons the first target hit." + gain_text = "Messengers of hope fear the rustbringer." + cost = 1 + spell_to_add = /obj/effect/proc_holder/spell/aimed/rust_wave + route = PATH_RUST + +/datum/eldritch_knowledge/rust_regen + name = "Leeching Walk" + desc = "Passively heals you when you are on rusted tiles." + gain_text = "'The strength was unparalleled, unnatural.' The Blacksmith was smiling." + cost = 1 + next_knowledge = list(/datum/eldritch_knowledge/rust_mark,/datum/eldritch_knowledge/armor,/datum/eldritch_knowledge/essence) + route = PATH_RUST + +/datum/eldritch_knowledge/rust_regen/on_life(mob/user) + . = ..() + var/turf/user_loc_turf = get_turf(user) + if(!istype(user_loc_turf, /turf/open/floor/plating/rust) || !isliving(user)) + return + var/mob/living/living_user = user + living_user.adjustBruteLoss(-3, FALSE) + living_user.adjustFireLoss(-3, FALSE) + living_user.adjustToxLoss(-3, FALSE) + living_user.adjustOxyLoss(-1, FALSE) + living_user.adjustStaminaLoss(-6) + +/datum/eldritch_knowledge/rust_mark + name = "Mark of Rust" + desc = "Your eldritch blade now applies a rust mark. Rust marks have a chance to deal between 0 to 200 damage to 75% of enemies items. To activate the mark use your Mansus Grasp on it." + gain_text = "Lords of the depths help those in dire need at a cost." + cost = 2 + next_knowledge = list(/datum/eldritch_knowledge/spell/area_conversion) + banned_knowledge = list(/datum/eldritch_knowledge/ash_mark,/datum/eldritch_knowledge/flesh_mark) + route = PATH_RUST + +/datum/eldritch_knowledge/rust_mark/on_eldritch_blade(target,user,proximity_flag,click_parameters) + . = ..() + if(isliving(target)) + var/mob/living/living_target = target + living_target.apply_status_effect(/datum/status_effect/eldritch/rust) + +/datum/eldritch_knowledge/rust_blade_upgrade + name = "Toxic Steel" + gain_text = "Let the blade guide you through the flesh." + desc = "Your blade of choice will now add toxin to enemies bloodstream." + cost = 2 + next_knowledge = list(/datum/eldritch_knowledge/spell/entropic_plume) + banned_knowledge = list(/datum/eldritch_knowledge/ash_blade_upgrade,/datum/eldritch_knowledge/flesh_blade_upgrade) + route = PATH_RUST + +/datum/eldritch_knowledge/rust_blade_upgrade/on_eldritch_blade(target,user,proximity_flag,click_parameters) + . = ..() + if(iscarbon(target)) + var/mob/living/carbon/carbon_target = target + carbon_target.reagents.add_reagent(/datum/reagent/eldritch, 5) + +/datum/eldritch_knowledge/spell/entropic_plume + name = "Entropic Plume" + desc = "You can now send a befuddling plume that blinds, poisons and makes enemies strike each other, while also converting the immediate area into rust." + gain_text = "Messengers of hope fear the rustbringer." + cost = 1 + spell_to_add = /obj/effect/proc_holder/spell/cone/staggered/entropic_plume + next_knowledge = list(/datum/eldritch_knowledge/final/rust_final,/datum/eldritch_knowledge/spell/cleave,/datum/eldritch_knowledge/summon/rusty) + route = PATH_RUST + +/datum/eldritch_knowledge/armor + name = "Armorer's Ritual" + desc = "You can now create eldritch armor using a built table and a gas mask on top of a transmutation rune." + gain_text = "For I am the heir to the throne of doom." + cost = 1 + next_knowledge = list(/datum/eldritch_knowledge/rust_regen,/datum/eldritch_knowledge/flesh_ghoul) + required_atoms = list(/obj/structure/table,/obj/item/clothing/mask/gas) + result_atoms = list(/obj/item/clothing/suit/hooded/cultrobes/eldritch) + +/datum/eldritch_knowledge/essence + name = "Priest's Ritual" + desc = "You can now transmute a tank of water into a bottle of eldritch fluid." + gain_text = "This is an old recipe, i got it from an owl." + cost = 1 + next_knowledge = list(/datum/eldritch_knowledge/rust_regen,/datum/eldritch_knowledge/spell/ashen_shift) + required_atoms = list(/obj/structure/reagent_dispensers/watertank) + result_atoms = list(/obj/item/reagent_containers/glass/beaker/eldritch) + +/datum/eldritch_knowledge/final/rust_final + name = "Rustbringer's Oath" + desc = "Bring three corpses onto a transmutation rune. After you finish the ritual, rust will now automatically spread from the rune. Your healing on rust is also tripled, while you become more resilient overall." + gain_text = "Champion of rust. Corruptor of steel. Fear the dark for Rustbringer has come!" + cost = 5 + required_atoms = list(/mob/living/carbon/human) + route = PATH_RUST + +/datum/eldritch_knowledge/final/rust_final/on_finished_recipe(mob/living/user, list/atoms, loc) + var/mob/living/carbon/human/H = user + H.physiology.brute_mod *= 0.5 + H.physiology.burn_mod *= 0.5 + priority_announce("$^@&#*$^@(#&$(@&#^$&#^@# Fear the decay, for Rustbringer [user.real_name] has come! $^@&#*$^@(#&$(@&#^$&#^@#","#$^@&#*$^@(#&$(@&#^$&#^@#", 'sound/announcer/classic/spanomalies.ogg') + new /datum/rust_spread(loc) + var/datum/antagonist/heretic/ascension = H.mind.has_antag_datum(/datum/antagonist/heretic) + ascension.ascended = TRUE + return ..() + + +/datum/eldritch_knowledge/final/rust_final/on_life(mob/user) + . = ..() + if(!finished) + return + var/mob/living/carbon/human/human_user = user + human_user.adjustBruteLoss(-6, FALSE) + human_user.adjustFireLoss(-6, FALSE) + human_user.adjustToxLoss(-6, FALSE) + human_user.adjustOxyLoss(-6, FALSE) + human_user.adjustStaminaLoss(-20) + + +/** + * #Rust spread datum + * + * Simple datum that automatically spreads rust around it + * + * Simple implementation of automatically growing entity + */ +/datum/rust_spread + var/list/edge_turfs = list() + var/list/turfs = list() + var/static/list/blacklisted_turfs = typecacheof(list(/turf/open/indestructible,/turf/closed/indestructible,/turf/open/space,/turf/open/lava,/turf/open/chasm)) + var/spread_per_tick = 6 + + +/datum/rust_spread/New(loc) + . = ..() + var/turf/turf_loc = get_turf(loc) + turf_loc.rust_heretic_act() + turfs += turf_loc + START_PROCESSING(SSprocessing,src) + + +/datum/rust_spread/Destroy(force, ...) + STOP_PROCESSING(SSprocessing,src) + return ..() + +/datum/rust_spread/process() + compile_turfs() + var/turf/T + for(var/i in 0 to spread_per_tick) + T = pick(edge_turfs) + T.rust_heretic_act() + turfs += get_turf(T) + +/** + * Compile turfs + * + * Recreates all edge_turfs as well as normal turfs. + */ +/datum/rust_spread/proc/compile_turfs() + edge_turfs = list() + for(var/X in turfs) + if(!istype(X,/turf/closed/wall/rust) && !istype(X,/turf/closed/wall/r_wall/rust) && !istype(X,/turf/open/floor/plating/rust)) + turfs -=X + continue + for(var/turf/T in range(1,X)) + if(T in turfs) + continue + if(is_type_in_typecache(T,blacklisted_turfs)) + continue + edge_turfs += T diff --git a/code/modules/antagonists/nukeop/equipment/nuclearbomb.dm b/code/modules/antagonists/nukeop/equipment/nuclearbomb.dm index 5c011b6318..a18906b70b 100644 --- a/code/modules/antagonists/nukeop/equipment/nuclearbomb.dm +++ b/code/modules/antagonists/nukeop/equipment/nuclearbomb.dm @@ -7,17 +7,13 @@ density = TRUE resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF - ui_x = 350 - ui_y = 442 - var/timer_set = 90 - var/default_timer_set = 90 var/minimum_timer_set = 90 var/maximum_timer_set = 3600 - ui_style = "nanotrasen" var/numeric_input = "" var/ui_mode = NUKEUI_AWAIT_DISK + var/timing = FALSE var/exploding = FALSE var/exploded = FALSE @@ -34,7 +30,6 @@ var/interior = "" var/proper_bomb = TRUE //Please var/obj/effect/countdown/nuclearbomb/countdown - var/nuclear_cooldown //used to stop global spam. /obj/machinery/nuclearbomb/Initialize() . = ..() @@ -77,15 +72,16 @@ /obj/machinery/nuclearbomb/syndicate/get_cinematic_type(off_station) var/datum/game_mode/nuclear/NM = SSticker.mode switch(off_station) - if(FALSE) + if(0) if(istype(NM) && !NM.nuke_team.syndies_escaped()) return CINEMATIC_ANNIHILATION else return CINEMATIC_NUKE_WIN - if(NUKE_MISS_STATION) + if(1) return CINEMATIC_NUKE_MISS - else + if(2) return CINEMATIC_NUKE_FAR + return CINEMATIC_NUKE_FAR /obj/machinery/nuclearbomb/proc/disk_check(obj/item/disk/nuclear/D) if(D.fake) @@ -194,7 +190,7 @@ icon_state = "nuclearbomb_exploding" /obj/machinery/nuclearbomb/update_overlays() - . = ..() + . += ..() update_icon_interior() update_icon_lights() @@ -236,7 +232,7 @@ explode() else var/volume = (get_time_left() <= 20 ? 30 : 5) - playsound(loc, 'sound/items/timer.ogg', volume, 0) + playsound(loc, 'sound/items/timer.ogg', volume, FALSE) /obj/machinery/nuclearbomb/proc/update_ui_mode() if(exploded) @@ -261,17 +257,18 @@ ui_mode = NUKEUI_AWAIT_TIMER - -/obj/machinery/nuclearbomb/ui_interact(mob/user, ui_key="main", datum/tgui/ui=null, force_open=0, datum/tgui/master_ui=null, datum/ui_state/state=GLOB.default_state) - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) +/obj/machinery/nuclearbomb/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) if(!ui) - ui = new(user, src, ui_key, "NuclearBomb", name, ui_x, ui_y, master_ui, state) + ui = new(user, src, "NuclearBomb", name) ui.open() /obj/machinery/nuclearbomb/ui_data(mob/user) var/list/data = list() data["disk_present"] = auth + var/hidden_code = (ui_mode == NUKEUI_AWAIT_CODE && numeric_input != "ERROR") + var/current_code = "" if(hidden_code) while(length(current_code) < length(numeric_input)) @@ -388,14 +385,13 @@ if("anchor") if(auth && yes_code) playsound(src, 'sound/machines/nuke/general_beep.ogg', 50, FALSE) - set_anchor(usr) + set_anchor() else playsound(src, 'sound/machines/nuke/angry_beep.ogg', 50, FALSE) - -/obj/machinery/nuclearbomb/proc/set_anchor(mob/user) - if((istype(get_area(src), /area/space) || isinspace()) && !anchored) - to_chat(user, "This is not a suitable platform for anchoring [src]!") +/obj/machinery/nuclearbomb/proc/set_anchor() + if(isinspace() && !anchored) + to_chat(usr, "There is nothing to anchor to!") else anchored = !anchored @@ -416,9 +412,6 @@ if(safety) to_chat(usr, "The safety is still on.") return - if(!timing && nuclear_cooldown > world.time) - to_chat(usr, "[src]'s timer protocols are currently on cooldown, please stand by.") - return timing = !timing if(timing) previous_level = NUM2SECLEVEL(GLOB.security_level) @@ -427,12 +420,6 @@ S.switch_mode_to(TRACK_INFILTRATOR) countdown.start() set_security_level("delta") - nuclear_cooldown = world.time + 15 SECONDS - - if(GLOB.war_declared) - var/area/A = get_area(src) - priority_announce("Alert: Unexpected increase in radiation levels near [A.name] ([src.x],[src.y],[src.z]). Please send an authorized radiation specialist to investigate.", "Sensory Nuclear Indexer Telemetry Calculation Helper") - else detonation_timer = null set_security_level(previous_level) @@ -483,12 +470,19 @@ var/off_station = FALSE var/turf/bomb_location = get_turf(src) - if(!bomb_location || !is_station_level(bomb_location.z)) - off_station = NUKE_MISS_STATION + var/area/A = get_area(bomb_location) + + if(bomb_location && is_station_level(bomb_location.z)) + if(istype(A, /area/space)) + off_station = NUKE_NEAR_MISS + if((bomb_location.x < (128-NUKERANGE)) || (bomb_location.x > (128+NUKERANGE)) || (bomb_location.y < (128-NUKERANGE)) || (bomb_location.y > (128+NUKERANGE))) + off_station = NUKE_NEAR_MISS else if(bomb_location.onSyndieBase()) off_station = NUKE_SYNDICATE_BASE + else + off_station = NUKE_MISS_STATION - if(!off_station) + if(off_station < 2) //can only launch when nuke is on syndie base or space SSshuttle.registerHostileEnvironment(src) SSshuttle.lockdown = TRUE @@ -502,13 +496,13 @@ INVOKE_ASYNC(GLOBAL_PROC,.proc/KillEveryoneOnZLevel, z) /obj/machinery/nuclearbomb/proc/get_cinematic_type(off_station) - if(!off_station) + if(off_station < 2) return CINEMATIC_SELFDESTRUCT else return CINEMATIC_SELFDESTRUCT_MISS /obj/machinery/nuclearbomb/beer - name = "Nanotrasen-brand nuclear fission explosive" + name = "\improper Nanotrasen-brand nuclear fission explosive" desc = "One of the more successful achievements of the Nanotrasen Corporate Warfare Division, their nuclear fission explosives are renowned for being cheap to produce and devastatingly effective. Signs explain that though this particular device has been decommissioned, every Nanotrasen station is equipped with an equivalent one, just in case. All Captains carefully guard the disk needed to detonate them - at least, the sign says they do. There seems to be a tap on the back." proper_bomb = FALSE var/obj/structure/reagent_dispensers/beerkeg/keg @@ -521,9 +515,9 @@ /obj/machinery/nuclearbomb/beer/examine(mob/user) . = ..() if(keg.reagents.total_volume) - . += "It has [keg.reagents.total_volume] unit\s left." + to_chat(user, "It has [keg.reagents.total_volume] unit\s left.") else - . += "It's empty." + to_chat(user, "It's empty.") /obj/machinery/nuclearbomb/beer/attackby(obj/item/W, mob/user, params) if(W.is_refillable()) @@ -535,6 +529,8 @@ return ..() /obj/machinery/nuclearbomb/beer/actually_explode() + //Unblock roundend, we're not actually exploding. + SSticker.roundend_check_paused = FALSE var/turf/bomb_location = get_turf(src) if(!bomb_location) disarm() @@ -583,7 +579,7 @@ This is here to make the tiles around the station mininuke change when it's armed. */ -/obj/machinery/nuclearbomb/selfdestruct/set_anchor(mob/user) +/obj/machinery/nuclearbomb/selfdestruct/set_anchor() return /obj/machinery/nuclearbomb/selfdestruct/set_active() @@ -641,18 +637,19 @@ This is here to make the tiles around the station mininuke change when it's arme if(newturf && lastlocation == newturf) if(last_disk_move < world.time - 5000 && prob((world.time - 5000 - last_disk_move)*0.0001)) var/datum/round_event_control/operative/loneop = locate(/datum/round_event_control/operative) in SSevents.control - if(istype(loneop)) + if(istype(loneop) && loneop.occurrences < loneop.max_occurrences) loneop.weight += 1 - if(loneop.weight % 5 == 0) + if(loneop.weight % 5 == 0 && SSticker.totalPlayers > 1) //players count now message_admins("[src] is stationary in [ADMIN_VERBOSEJMP(newturf)]. The weight of Lone Operative is now [loneop.weight].") log_game("[src] is stationary for too long in [loc_name(newturf)], and has increased the weight of the Lone Operative event to [loneop.weight].") + else lastlocation = newturf last_disk_move = world.time var/datum/round_event_control/operative/loneop = locate(/datum/round_event_control/operative) in SSevents.control - if(istype(loneop) && prob(loneop.weight)) + if(istype(loneop) && loneop.occurrences < loneop.max_occurrences && prob(loneop.weight)) loneop.weight = max(loneop.weight - 1, 0) - if(loneop.weight % 5 == 0) + if(loneop.weight % 5 == 0 && SSticker.totalPlayers > 1) message_admins("[src] is on the move (currently in [ADMIN_VERBOSEJMP(newturf)]). The weight of Lone Operative is now [loneop.weight].") log_game("[src] being on the move has reduced the weight of the Lone Operative event to [loneop.weight].") @@ -661,9 +658,19 @@ This is here to make the tiles around the station mininuke change when it's arme if(!fake) return - if(isobserver(user) || HAS_TRAIT(user, TRAIT_DISK_VERIFIER) || (user.mind && HAS_TRAIT(user.mind, TRAIT_DISK_VERIFIER))) + if(isobserver(user) || HAS_TRAIT(user.mind, TRAIT_DISK_VERIFIER)) . += "The serial numbers on [src] are incorrect." +/* + * You can't accidentally eat the nuke disk, bro + */ + /* +/obj/item/disk/nuclear/on_accidental_consumption(mob/living/carbon/M, mob/living/carbon/user, obj/item/source_item, discover_after = TRUE) + M.visible_message("[M] looks like [M.p_theyve()] just bitten into something important.", \ + "Wait, is this the nuke disk?") + + return discover_after +*/ /obj/item/disk/nuclear/attackby(obj/item/I, mob/living/user, params) if(istype(I, /obj/item/claymore/highlander) && !fake) var/obj/item/claymore/highlander/H = I @@ -686,7 +693,7 @@ This is here to make the tiles around the station mininuke change when it's arme /obj/item/disk/nuclear/suicide_act(mob/user) user.visible_message("[user] is going delta! It looks like [user.p_theyre()] trying to commit suicide!") - playsound(src, 'sound/machines/alarm.ogg', 50, -1, 1) + playsound(src, 'sound/machines/alarm.ogg', 50, -1, TRUE) for(var/i in 1 to 100) addtimer(CALLBACK(user, /atom/proc/add_atom_colour, (i % 2)? "#00FF00" : "#FF0000", ADMIN_COLOUR_PRIORITY), i) addtimer(CALLBACK(src, .proc/manual_suicide, user), 101) @@ -694,7 +701,7 @@ This is here to make the tiles around the station mininuke change when it's arme /obj/item/disk/nuclear/proc/manual_suicide(mob/living/user) user.remove_atom_colour(ADMIN_COLOUR_PRIORITY) - user.visible_message("[user] was destroyed by the nuclear blast!") + user.visible_message("[user] is destroyed by the nuclear blast!") user.adjustOxyLoss(200) user.death(0) diff --git a/code/modules/antagonists/revenant/revenant.dm b/code/modules/antagonists/revenant/revenant.dm index 21ccd425a3..848fe124be 100644 --- a/code/modules/antagonists/revenant/revenant.dm +++ b/code/modules/antagonists/revenant/revenant.dm @@ -28,6 +28,7 @@ throwforce = 0 blood_volume = 0 has_field_of_vision = FALSE //we are a spoopy ghost + rad_flags = RAD_NO_CONTAMINATE | RAD_PROTECT_CONTENTS see_in_dark = 8 lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE diff --git a/code/modules/antagonists/slaughter/slaughter.dm b/code/modules/antagonists/slaughter/slaughter.dm index 3ae9cfcfb0..d1db363b04 100644 --- a/code/modules/antagonists/slaughter/slaughter.dm +++ b/code/modules/antagonists/slaughter/slaughter.dm @@ -16,6 +16,7 @@ icon_state = "daemon" icon_living = "daemon" mob_biotypes = MOB_ORGANIC|MOB_HUMANOID + mob_size = MOB_SIZE_LARGE speed = 1 a_intent = INTENT_HARM stop_automated_movement = 1 diff --git a/code/modules/antagonists/swarmer/swarmer.dm b/code/modules/antagonists/swarmer/swarmer.dm index b7503f4b22..305c4fadb7 100644 --- a/code/modules/antagonists/swarmer/swarmer.dm +++ b/code/modules/antagonists/swarmer/swarmer.dm @@ -70,7 +70,6 @@ icon_living = "swarmer" icon_dead = "swarmer_unactivated" icon_gib = null - threat = 0.5 wander = 0 harm_intent_damage = 5 minbodytemp = 0 diff --git a/code/modules/antagonists/wizard/equipment/spellbook.dm b/code/modules/antagonists/wizard/equipment/spellbook.dm index 4c29c53a2e..1e98b2f753 100644 --- a/code/modules/antagonists/wizard/equipment/spellbook.dm +++ b/code/modules/antagonists/wizard/equipment/spellbook.dm @@ -161,12 +161,12 @@ /datum/spellbook_entry/blind name = "Blind" - spell_type = /obj/effect/proc_holder/spell/targeted/trigger/blind + spell_type = /obj/effect/proc_holder/spell/pointed/trigger/blind cost = 1 /datum/spellbook_entry/mindswap name = "Mindswap" - spell_type = /obj/effect/proc_holder/spell/targeted/mind_transfer + spell_type = /obj/effect/proc_holder/spell/pointed/mind_transfer category = "Mobility" /datum/spellbook_entry/forcewall @@ -246,7 +246,7 @@ /datum/spellbook_entry/barnyard name = "Barnyard Curse" - spell_type = /obj/effect/proc_holder/spell/targeted/barnyardcurse + spell_type = /obj/effect/proc_holder/spell/pointed/barnyardcurse /datum/spellbook_entry/charge name = "Charge" @@ -294,6 +294,11 @@ dat += "[surplus] left.
" return dat +/datum/spellbook_entry/item/timestop_katana + name = "Temporal Katana" + desc = "An oddly-weighted katana, reinforced to allow parrying, with a temporal anomaly magically shoved into it. Successful ripostes prove devastating to those unprepared." + item_path = /obj/item/katana/timestop + /datum/spellbook_entry/item/staffchange name = "Staff of Change" desc = "An artefact that spits bolts of coruscating energy which cause the target's very form to reshape itself." diff --git a/code/modules/antagonists/wizard/wizard.dm b/code/modules/antagonists/wizard/wizard.dm index 7263793f7f..42954c3542 100644 --- a/code/modules/antagonists/wizard/wizard.dm +++ b/code/modules/antagonists/wizard/wizard.dm @@ -177,7 +177,7 @@ to_chat(owner, "Your service has not gone unrewarded, however. Studying under [master.current.real_name], you have learned livesaving survival spells. You are able to cast charge and forcewall.") if(APPRENTICE_ROBELESS) owner.AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/knock(null)) - owner.AddSpell(new /obj/effect/proc_holder/spell/targeted/mind_transfer(null)) + owner.AddSpell(new /obj/effect/proc_holder/spell/pointed/mind_transfer(null)) to_chat(owner, "Your service has not gone unrewarded, however. Studying under [master.current.real_name], you have learned stealthy, robeless spells. You are able to cast knock and mindswap.") if(APPRENTICE_MARTIAL) owner.AddSpell(new /obj/effect/proc_holder/spell/targeted/touch/nuclear_fist(null)) diff --git a/code/modules/antagonists/xeno/xeno.dm b/code/modules/antagonists/xeno/xeno.dm index 2cc8e34b99..f10506a0d9 100644 --- a/code/modules/antagonists/xeno/xeno.dm +++ b/code/modules/antagonists/xeno/xeno.dm @@ -16,6 +16,18 @@ var/datum/team/xeno/xeno_team threat = 3 +/datum/antagonist/xeno/threat() + . = 1 + if(isalienhunter(owner)) + . = 2 + else if(isaliensentinel(owner)) + . = 4 + else if(isalienroyal(owner)) + if(isalienqueen(owner)) + . = 8 + else + . = 6 + /datum/antagonist/xeno/create_team(datum/team/xeno/new_team) if(!new_team) for(var/datum/antagonist/xeno/X in GLOB.antagonists) diff --git a/code/modules/arousal/genitals.dm b/code/modules/arousal/genitals.dm index 4d2e5e6fef..8f88076af9 100644 --- a/code/modules/arousal/genitals.dm +++ b/code/modules/arousal/genitals.dm @@ -232,23 +232,6 @@ /obj/item/organ/genital/proc/get_features(mob/living/carbon/human/H) return - -//procs to handle sprite overlays being applied to humans - -/mob/living/carbon/human/equip_to_slot(obj/item/I, slot) - . = ..() - if(!. && I && slot && !(slot in GLOB.no_genitals_update_slots)) //the item was successfully equipped, and the chosen slot wasn't merely storage, hands or cuffs. - update_genitals() - -/mob/living/carbon/human/doUnEquip(obj/item/I, force, newloc, no_move, invdrop = TRUE) - var/no_update = FALSE - if(!I || I == l_store || I == r_store || I == s_store || I == handcuffed || I == legcuffed || get_held_index_of_item(I)) //stops storages, cuffs and held items from triggering it. - no_update = TRUE - . = ..() - if(!. || no_update) - return - update_genitals() - /mob/living/carbon/human/proc/update_genitals() if(QDELETED(src)) return diff --git a/code/modules/arousal/organs/womb.dm b/code/modules/arousal/organs/womb.dm index 386f407a26..e89d4329aa 100644 --- a/code/modules/arousal/organs/womb.dm +++ b/code/modules/arousal/organs/womb.dm @@ -6,5 +6,5 @@ zone = BODY_ZONE_PRECISE_GROIN slot = ORGAN_SLOT_WOMB genital_flags = GENITAL_INTERNAL|GENITAL_FUID_PRODUCTION - fluid_id = /datum/reagent/consumable/femcum + fluid_id = /datum/reagent/consumable/semen/femcum linked_organ_slot = ORGAN_SLOT_VAGINA diff --git a/code/modules/arousal/toys/dildos.dm b/code/modules/arousal/toys/dildos.dm index 5cb6d47118..3f6fa9bb45 100644 --- a/code/modules/arousal/toys/dildos.dm +++ b/code/modules/arousal/toys/dildos.dm @@ -122,6 +122,7 @@ obj/item/dildo/flared/huge name = "literal horse cock" desc = "THIS THING IS HUGE!" dildo_size = 4 + force = 10 obj/item/dildo/custom name = "customizable dildo" diff --git a/code/modules/assembly/infrared.dm b/code/modules/assembly/infrared.dm index 6e8e2846a2..899eb12511 100644 --- a/code/modules/assembly/infrared.dm +++ b/code/modules/assembly/infrared.dm @@ -4,8 +4,6 @@ icon_state = "infrared" custom_materials = list(/datum/material/iron=1000, /datum/material/glass=500) is_position_sensitive = TRUE - var/ui_x = 225 - var/ui_y = 110 var/on = FALSE var/visible = FALSE var/maxlength = 8 @@ -134,7 +132,7 @@ . = ..() setDir(t) -/obj/item/assembly/infra/throw_at(atom/target, range, speed, mob/thrower, spin=1, diagonals_first = 0, datum/callback/callback, force, gentle = FALSE) +/obj/item/assembly/infra/throw_at(atom/target, range, speed, mob/thrower, spin=1, diagonals_first = 0, datum/callback/callback, force, gentle = FALSE, quickstart = TRUE) . = ..() olddir = dir @@ -186,11 +184,10 @@ return ..() return UI_CLOSE -/obj/item/assembly/infra/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ - datum/tgui/master_ui = null, datum/ui_state/state = GLOB.hands_state) - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) +/obj/item/assembly/infra/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) if(!ui) - ui = new(user, src, ui_key, "InfraredEmitter", name, ui_x, ui_y, master_ui, state) + ui = new(user, src, "InfraredEmitter", name) ui.open() /obj/item/assembly/infra/ui_data(mob/user) diff --git a/code/modules/assembly/proximity.dm b/code/modules/assembly/proximity.dm index f0d8f28688..60de1b3e87 100644 --- a/code/modules/assembly/proximity.dm +++ b/code/modules/assembly/proximity.dm @@ -4,8 +4,6 @@ icon_state = "prox" custom_materials = list(/datum/material/iron=800, /datum/material/glass=200) attachable = TRUE - var/ui_x = 250 - var/ui_y = 185 var/scanning = FALSE var/timing = FALSE var/time = 10 @@ -113,11 +111,10 @@ return ..() return UI_CLOSE -/obj/item/assembly/prox_sensor/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ - datum/tgui/master_ui = null, datum/ui_state/state = GLOB.hands_state) - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) +/obj/item/assembly/prox_sensor/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) if(!ui) - ui = new(user, src, ui_key, "ProximitySensor", name, ui_x, ui_y, master_ui, state) + ui = new(user, src, "ProximitySensor", name) ui.open() /obj/item/assembly/prox_sensor/ui_data(mob/user) diff --git a/code/modules/assembly/signaler.dm b/code/modules/assembly/signaler.dm index fe548d662d..e586f97a28 100644 --- a/code/modules/assembly/signaler.dm +++ b/code/modules/assembly/signaler.dm @@ -8,33 +8,46 @@ custom_materials = list(/datum/material/iron=400, /datum/material/glass=120) wires = WIRE_RECEIVE | WIRE_PULSE | WIRE_RADIO_PULSE | WIRE_RADIO_RECEIVE attachable = TRUE - var/ui_x = 280 - var/ui_y = 132 + var/code = DEFAULT_SIGNALER_CODE var/frequency = FREQ_SIGNALER var/datum/radio_frequency/radio_connection - var/suicider = null + ///Holds the mind that commited suicide. + var/datum/mind/suicider + ///Holds a reference string to the mob, decides how much of a gamer you are. + var/suicide_mob var/hearing_range = 1 /obj/item/assembly/signaler/suicide_act(mob/living/carbon/user) user.visible_message("[user] eats \the [src]! If it is signaled, [user.p_they()] will die!") playsound(src, 'sound/items/eatfood.ogg', 50, TRUE) - user.transferItemToLoc(src, user, TRUE) - suicider = user + moveToNullspace() + suicider = user.mind + suicide_mob = REF(user) return MANUAL_SUICIDE -/obj/item/assembly/signaler/proc/manual_suicide(mob/living/carbon/user) - user.visible_message("[user]'s \the [src] receives a signal, killing [user.p_them()] instantly!") +/obj/item/assembly/signaler/proc/manual_suicide(datum/mind/suicidee) + var/mob/living/user = suicidee.current + if(!istype(user)) + return + if(suicide_mob == REF(user)) + user.visible_message("[user]'s [src] receives a signal, killing [user.p_them()] instantly!") + else + user.visible_message("[user]'s [src] receives a signal and [user.p_they()] die[user.p_s()] like a gamer!") user.adjustOxyLoss(200)//it sends an electrical pulse to their heart, killing them. or something. user.death(0) + //user.set_suicide(TRUE) + user.suicide_log() + playsound(user, 'sound/machines/triple_beep.ogg', ASSEMBLY_BEEP_VOLUME, TRUE) + qdel(src) /obj/item/assembly/signaler/Initialize() . = ..() set_frequency(frequency) - /obj/item/assembly/signaler/Destroy() SSradio.remove_object(src,frequency) + suicider = null . = ..() /obj/item/assembly/signaler/activate() @@ -53,11 +66,10 @@ return ..() return UI_CLOSE -/obj/item/assembly/signaler/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ - datum/tgui/master_ui = null, datum/ui_state/state = GLOB.hands_state) - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) +/obj/item/assembly/signaler/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) if(!ui) - ui = new(user, src, ui_key, "Signaler", name, ui_x, ui_y, master_ui, state) + ui = new(user, src, "Signaler", name) ui.open() /obj/item/assembly/signaler/ui_data(mob/user) @@ -66,12 +78,12 @@ data["code"] = code data["minFrequency"] = MIN_FREE_FREQ data["maxFrequency"] = MAX_FREE_FREQ - return data /obj/item/assembly/signaler/ui_act(action, params) if(..()) return + switch(action) if("signal") INVOKE_ASYNC(src, .proc/signal) @@ -115,9 +127,6 @@ if(usr) GLOB.lastsignalers.Add("[time] : [usr.key] used [src] @ location ([T.x],[T.y],[T.z]) : [format_frequency(frequency)]/[code]") - - return - /obj/item/assembly/signaler/receive_signal(datum/signal/signal) . = FALSE if(!signal) @@ -128,6 +137,7 @@ return if(suicider) manual_suicide(suicider) + return pulse(TRUE) audible_message("[icon2html(src, hearers(src))] *beep* *beep* *beep*", null, hearing_range) for(var/CHM in get_hearers_in_view(hearing_range, src)) @@ -136,7 +146,6 @@ LM.playsound_local(get_turf(src), 'sound/machines/triple_beep.ogg', ASSEMBLY_BEEP_VOLUME, TRUE) return TRUE - /obj/item/assembly/signaler/proc/set_frequency(new_frequency) SSradio.remove_object(src, frequency) frequency = new_frequency @@ -165,69 +174,8 @@ return return ..(signal) -// Embedded signaller used in anomalies. -/obj/item/assembly/signaler/anomaly - name = "anomaly core" - desc = "The neutralized core of an anomaly. It'd probably be valuable for research." - icon_state = "anomaly core" - item_state = "electronic" - lefthand_file = 'icons/mob/inhands/misc/devices_lefthand.dmi' - righthand_file = 'icons/mob/inhands/misc/devices_righthand.dmi' - resistance_flags = FIRE_PROOF - var/anomaly_type = /obj/effect/anomaly - -/obj/item/assembly/signaler/anomaly/receive_signal(datum/signal/signal) - if(!signal) - return FALSE - if(signal.data["code"] != code) - return FALSE - if(suicider) - manual_suicide(suicider) - for(var/obj/effect/anomaly/A in get_turf(src)) - A.anomalyNeutralize() - return TRUE - -/obj/item/assembly/signaler/anomaly/manual_suicide(mob/living/carbon/user) - user.visible_message("[user]'s [src] is reacting to the radio signal, warping [user.p_their()] body!") - user.suiciding = TRUE - user.suicide_log() - user.gib() - -/obj/item/assembly/signaler/anomaly/attackby(obj/item/I, mob/user, params) - if(I.tool_behaviour == TOOL_ANALYZER) - to_chat(user, "Analyzing... [src]'s stabilized field is fluctuating along frequency [format_frequency(frequency)], code [code].") - ..() - -//Anomaly cores -/obj/item/assembly/signaler/anomaly/pyro - name = "\improper pyroclastic anomaly core" - desc = "The neutralized core of a pyroclastic anomaly. It feels warm to the touch. It'd probably be valuable for research." - icon_state = "pyro core" - anomaly_type = /obj/effect/anomaly/pyro - -/obj/item/assembly/signaler/anomaly/grav - name = "\improper gravitational anomaly core" - desc = "The neutralized core of a gravitational anomaly. It feels much heavier than it looks. It'd probably be valuable for research." - icon_state = "grav core" - anomaly_type = /obj/effect/anomaly/grav - -/obj/item/assembly/signaler/anomaly/flux - name = "\improper flux anomaly core" - desc = "The neutralized core of a flux anomaly. Touching it makes your skin tingle. It'd probably be valuable for research." - icon_state = "flux core" - anomaly_type = /obj/effect/anomaly/flux - -/obj/item/assembly/signaler/anomaly/bluespace - name = "\improper bluespace anomaly core" - desc = "The neutralized core of a bluespace anomaly. It keeps phasing in and out of view. It'd probably be valuable for research." - icon_state = "anomaly core" - anomaly_type = /obj/effect/anomaly/bluespace - -/obj/item/assembly/signaler/anomaly/vortex - name = "\improper vortex anomaly core" - desc = "The neutralized core of a vortex anomaly. It won't sit still, as if some invisible force is acting on it. It'd probably be valuable for research." - icon_state = "vortex core" - anomaly_type = /obj/effect/anomaly/bhole +/obj/item/assembly/signaler/anomaly/attack_self() + return /obj/item/assembly/signaler/cyborg diff --git a/code/modules/assembly/timer.dm b/code/modules/assembly/timer.dm index d0f0e1e593..e06bb22b0b 100644 --- a/code/modules/assembly/timer.dm +++ b/code/modules/assembly/timer.dm @@ -4,8 +4,7 @@ icon_state = "timer" custom_materials = list(/datum/material/iron=500, /datum/material/glass=50) attachable = TRUE - var/ui_x = 275 - var/ui_y = 115 + var/timing = FALSE var/time = 5 var/saved_time = 5 @@ -88,11 +87,10 @@ return ..() return UI_CLOSE -/obj/item/assembly/timer/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ - datum/tgui/master_ui = null, datum/ui_state/state = GLOB.hands_state) - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) +/obj/item/assembly/timer/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) if(!ui) - ui = new(user, src, ui_key, "Timer", name, ui_x, ui_y, master_ui, state) + ui = new(user, src, "Timer", name) ui.open() /obj/item/assembly/timer/ui_data(mob/user) diff --git a/code/modules/asset_cache/asset_cache.dm b/code/modules/asset_cache/asset_cache.dm index f702bf714e..53a30d4299 100644 --- a/code/modules/asset_cache/asset_cache.dm +++ b/code/modules/asset_cache/asset_cache.dm @@ -94,6 +94,13 @@ Note: If your code uses output() with assets you will need to call asset_flush o var/list/stacktrace = gib_stack_trace() log_asset("WARNING: dupe asset added to the asset cache: [asset_name] existing asset md5: [OACI.md5] new asset md5:[ACI.md5]\n[stacktrace.Join("\n")]") SSassets.cache[asset_name] = ACI + return ACI + +/// Returns the url of the asset, currently this is just its name, here to allow further work cdn'ing assets. +/// Can be given an asset as well, this is just a work around for buggy edge cases where two assets may have the same name, doesn't matter now, but it will when the cdn comes. +/proc/get_asset_url(asset_name, asset = null) + var/datum/asset_cache_item/ACI = SSassets.cache[asset_name] + return ACI?.url //Generated names do not include file extention. //Used mainly for code that deals with assets in a generic way diff --git a/code/modules/asset_cache/asset_cache_item.dm b/code/modules/asset_cache/asset_cache_item.dm index 0e7d44a7ac..e74293c65e 100644 --- a/code/modules/asset_cache/asset_cache_item.dm +++ b/code/modules/asset_cache/asset_cache_item.dm @@ -5,6 +5,7 @@ **/ /datum/asset_cache_item var/name + var/url var/md5 var/resource @@ -18,4 +19,5 @@ CRASH("invalid asset sent to asset cache") debug_world_log("asset cache unexpected success of second fcopy_rsc") src.name = name + url = name resource = file diff --git a/code/modules/asset_cache/asset_list.dm b/code/modules/asset_cache/asset_list.dm index 2e5881c67f..4ce9dcf6fc 100644 --- a/code/modules/asset_cache/asset_list.dm +++ b/code/modules/asset_cache/asset_list.dm @@ -16,6 +16,9 @@ GLOBAL_LIST_EMPTY(asset_datums) GLOB.asset_datums[type] = src register() +/datum/asset/proc/get_url_mappings() + return list() + /datum/asset/proc/register() return @@ -30,11 +33,19 @@ GLOBAL_LIST_EMPTY(asset_datums) /datum/asset/simple/register() for(var/asset_name in assets) - register_asset(asset_name, assets[asset_name]) + assets[asset_name] = register_asset(asset_name, assets[asset_name]) /datum/asset/simple/send(client) . = send_asset_list(client, assets) +/datum/asset/simple/get_url_mappings() + . = list() + for (var/asset_name in assets) + var/datum/asset_cache_item/ACI = assets[asset_name] + if (!ACI) + continue + .[asset_name] = ACI.url + // For registering or sending multiple others at once /datum/asset/group @@ -50,6 +61,11 @@ GLOBAL_LIST_EMPTY(asset_datums) var/datum/asset/A = get_asset_datum(type) . = A.send(C) || . +/datum/asset/group/get_url_mappings() + . = list() + for(var/type in children) + var/datum/asset/A = get_asset_datum(type) + . += A.get_url_mappings() // spritesheet implementation - coalesces various icons into a single .png file // and uses CSS to select icons out of that file - saves on transferring some @@ -70,7 +86,9 @@ GLOBAL_LIST_EMPTY(asset_datums) if (!name) CRASH("spritesheet [type] cannot register without a name") ensure_stripped() - + for(var/size_id in sizes) + var/size = sizes[size_id] + register_asset("[name]_[size_id].png", size[SPRSZ_STRIPPED]) var/res_name = "spritesheet_[name].css" var/fname = "data/spritesheets/[res_name]" fdel(fname) @@ -78,10 +96,6 @@ GLOBAL_LIST_EMPTY(asset_datums) register_asset(res_name, fcopy_rsc(fname)) fdel(fname) - for(var/size_id in sizes) - var/size = sizes[size_id] - register_asset("[name]_[size_id].png", size[SPRSZ_STRIPPED]) - /datum/asset/spritesheet/send(client/C) if (!name) return @@ -90,6 +104,15 @@ GLOBAL_LIST_EMPTY(asset_datums) all += "[name]_[size_id].png" . = send_asset_list(C, all) +/datum/asset/spritesheet/get_url_mappings() + if (!name) + return + . = list("spritesheet_[name].css" = get_asset_url("spritesheet_[name].css")) + for(var/size_id in sizes) + .["[name]_[size_id].png"] = get_asset_url("[name]_[size_id].png") + + + /datum/asset/spritesheet/proc/ensure_stripped(sizes_to_strip = sizes) for(var/size_id in sizes_to_strip) var/size = sizes[size_id] @@ -111,7 +134,7 @@ GLOBAL_LIST_EMPTY(asset_datums) for (var/size_id in sizes) var/size = sizes[size_id] var/icon/tiny = size[SPRSZ_ICON] - out += ".[name][size_id]{display:inline-block;width:[tiny.Width()]px;height:[tiny.Height()]px;background:url('[name]_[size_id].png') no-repeat;}" + out += ".[name][size_id]{display:inline-block;width:[tiny.Width()]px;height:[tiny.Height()]px;background:url('[get_asset_url("[name]_[size_id].png")]') no-repeat;}" for (var/sprite_id in sprites) var/sprite = sprites[sprite_id] @@ -162,7 +185,10 @@ GLOBAL_LIST_EMPTY(asset_datums) Insert("[prefix][prefix2][icon_state_name]", I, icon_state=icon_state_name, dir=direction) /datum/asset/spritesheet/proc/css_tag() - return {""} + return {""} + +/datum/asset/spritesheet/proc/css_filename() + return get_asset_url("spritesheet_[name].css") /datum/asset/spritesheet/proc/icon_tag(sprite_name) var/sprite = sprites[sprite_name] diff --git a/code/modules/asset_cache/asset_list_items.dm b/code/modules/asset_cache/asset_list_items.dm index 57d8e55e07..18e3281e4b 100644 --- a/code/modules/asset_cache/asset_list_items.dm +++ b/code/modules/asset_cache/asset_list_items.dm @@ -6,12 +6,6 @@ "tgui.bundle.css" = 'tgui/packages/tgui/public/tgui.bundle.css', ) -/datum/asset/group/tgui - children = list( - /datum/asset/simple/tgui, - /datum/asset/simple/fontawesome - ) - /datum/asset/simple/headers assets = list( "alarm_green.gif" = 'icons/program_icons/alarm_green.gif', @@ -78,6 +72,7 @@ "refresh" = 'icons/pda_icons/pda_refresh.png', "scanner" = 'icons/pda_icons/pda_scanner.png', "signaler" = 'icons/pda_icons/pda_signaler.png', + // "skills" = 'icons/pda_icons/pda_skills.png', "status" = 'icons/pda_icons/pda_status.png', "dronephone" = 'icons/pda_icons/pda_dronephone.png', "emoji" = 'icons/pda_icons/pda_emoji.png' @@ -97,6 +92,10 @@ "stamp-cap" = 'icons/stamp_icons/large_stamp-cap.png', "stamp-qm" = 'icons/stamp_icons/large_stamp-qm.png', "stamp-law" = 'icons/stamp_icons/large_stamp-law.png' + // "stamp-chap" = 'icons/stamp_icons/large_stamp-chap.png' + // "stamp-mime" = 'icons/stamp_icons/large_stamp-mime.png', + // "stamp-centcom" = 'icons/stamp_icons/large_stamp-centcom.png', + // "stamp-syndicate" = 'icons/stamp_icons/large_stamp-syndicate.png' ) @@ -147,7 +146,6 @@ "jquery.min.js" = 'code/modules/goonchat/browserassets/js/jquery.min.js', ) - /datum/asset/simple/goonchat assets = list( "json2.min.js" = 'code/modules/goonchat/browserassets/js/json2.min.js', @@ -266,7 +264,7 @@ name = "pipes" /datum/asset/spritesheet/pipes/register() - for (var/each in list('icons/obj/atmospherics/pipes/pipe_item.dmi', 'icons/obj/atmospherics/pipes/disposal.dmi')) + for (var/each in list('icons/obj/atmospherics/pipes/pipe_item.dmi', 'icons/obj/atmospherics/pipes/disposal.dmi', 'icons/obj/atmospherics/pipes/transit_tube.dmi', 'icons/obj/plumbing/fluid_ducts.dmi')) InsertAll("", each, GLOB.alldirs) ..() @@ -375,7 +373,26 @@ "ghost.png" = 'html/ghost.png' ) +/datum/asset/simple/vv assets = list( - "ghost.png" = 'html/ghost.png' + "view_variables.css" = 'html/admin/view_variables.css' ) +/datum/asset/spritesheet/sheetmaterials + name = "sheetmaterials" + +/datum/asset/spritesheet/sheetmaterials/register() + InsertAll("", 'icons/obj/stack_objects.dmi') + + // Special case to handle Bluespace Crystals + Insert("polycrystal", 'icons/obj/telescience.dmi', "polycrystal") + ..() + + +/datum/asset/spritesheet/mafia + name = "mafia" + +/datum/asset/spritesheet/mafia/register() + InsertAll("", 'icons/obj/mafia.dmi') + ..() + diff --git a/code/modules/atmospherics/machinery/airalarm.dm b/code/modules/atmospherics/machinery/airalarm.dm index 6b89deeb80..8316b29a24 100644 --- a/code/modules/atmospherics/machinery/airalarm.dm +++ b/code/modules/atmospherics/machinery/airalarm.dm @@ -237,11 +237,10 @@ return ..() return UI_CLOSE -/obj/machinery/airalarm/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ - datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) +/obj/machinery/airalarm/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) if(!ui) - ui = new(user, src, ui_key, "AirAlarm", name, 440, 650, master_ui, state) + ui = new(user, src, "AirAlarm", name) ui.open() /obj/machinery/airalarm/ui_data(mob/user) diff --git a/code/modules/atmospherics/machinery/components/binary_devices/passive_gate.dm b/code/modules/atmospherics/machinery/components/binary_devices/passive_gate.dm index 9e1908a500..00a085c31b 100644 --- a/code/modules/atmospherics/machinery/components/binary_devices/passive_gate.dm +++ b/code/modules/atmospherics/machinery/components/binary_devices/passive_gate.dm @@ -26,9 +26,6 @@ Passive gate is similar to the regular pump except: construction_type = /obj/item/pipe/directional pipe_state = "passivegate" - ui_x = 335 - ui_y = 115 - /obj/machinery/atmospherics/components/binary/passive_gate/CtrlClick(mob/user) if(can_interact(user)) on = !on @@ -102,11 +99,10 @@ Passive gate is similar to the regular pump except: )) radio_connection.post_signal(src, signal, filter = RADIO_ATMOSIA) -/obj/machinery/atmospherics/components/binary/passive_gate/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ - datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) +/obj/machinery/atmospherics/components/binary/passive_gate/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) if(!ui) - ui = new(user, src, ui_key, "AtmosPump", name, ui_x, ui_y, master_ui, state) + ui = new(user, src, "AtmosPump", name) ui.open() /obj/machinery/atmospherics/components/binary/passive_gate/ui_data() diff --git a/code/modules/atmospherics/machinery/components/binary_devices/pump.dm b/code/modules/atmospherics/machinery/components/binary_devices/pump.dm index d41df83e12..eb00e432b7 100644 --- a/code/modules/atmospherics/machinery/components/binary_devices/pump.dm +++ b/code/modules/atmospherics/machinery/components/binary_devices/pump.dm @@ -107,11 +107,10 @@ )) radio_connection.post_signal(src, signal, filter = RADIO_ATMOSIA) -/obj/machinery/atmospherics/components/binary/pump/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ - datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) +/obj/machinery/atmospherics/components/binary/pump/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) if(!ui) - ui = new(user, src, ui_key, "AtmosPump", name, 335, 115, master_ui, state) + ui = new(user, src, "AtmosPump", name) ui.open() /obj/machinery/atmospherics/components/binary/pump/ui_data() diff --git a/code/modules/atmospherics/machinery/components/binary_devices/relief_valve.dm b/code/modules/atmospherics/machinery/components/binary_devices/relief_valve.dm index 7bdd22cbd1..d0b663e4ad 100644 --- a/code/modules/atmospherics/machinery/components/binary_devices/relief_valve.dm +++ b/code/modules/atmospherics/machinery/components/binary_devices/relief_valve.dm @@ -60,15 +60,14 @@ else if(!opened && our_pressure >= open_pressure) open() -/obj/machinery/atmospherics/components/binary/relief_valve/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ - datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) +/obj/machinery/atmospherics/components/binary/relief_valve/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) if(!ui) - ui = new(user, src, ui_key, "atmos_relief", name, 335, 115, master_ui, state) + ui = new(user, src, "AtmosRelief", name) ui.open() /obj/machinery/atmospherics/components/binary/relief_valve/ui_data() - var/data = list() + var/list/data = list() data["open_pressure"] = round(open_pressure) data["close_pressure"] = round(close_pressure) data["max_pressure"] = round(50*ONE_ATMOSPHERE) @@ -79,11 +78,11 @@ return switch(action) if("open_pressure") - var/pressure = params["open_pressure"] + var/pressure = params["pressure"] if(pressure == "max") pressure = 50*ONE_ATMOSPHERE . = TRUE - else if(pressure == "input") + else if(pressure == "input") // The manual expirience. pressure = input("New output pressure ([close_pressure]-[50*ONE_ATMOSPHERE] kPa):", name, open_pressure) as num|null if(!isnull(pressure) && !..()) . = TRUE @@ -94,7 +93,7 @@ open_pressure = clamp(pressure, close_pressure, 50*ONE_ATMOSPHERE) investigate_log("open pressure was set to [open_pressure] kPa by [key_name(usr)]", INVESTIGATE_ATMOS) if("close_pressure") - var/pressure = params["close_pressure"] + var/pressure = params["pressure"] if(pressure == "max") pressure = open_pressure . = TRUE diff --git a/code/modules/atmospherics/machinery/components/binary_devices/volume_pump.dm b/code/modules/atmospherics/machinery/components/binary_devices/volume_pump.dm index d95e4ec123..1b049322a1 100644 --- a/code/modules/atmospherics/machinery/components/binary_devices/volume_pump.dm +++ b/code/modules/atmospherics/machinery/components/binary_devices/volume_pump.dm @@ -92,11 +92,10 @@ )) radio_connection.post_signal(src, signal) -/obj/machinery/atmospherics/components/binary/volume_pump/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ - datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) +/obj/machinery/atmospherics/components/binary/volume_pump/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) if(!ui) - ui = new(user, src, ui_key, "AtmosPump", name, 310, 115, master_ui, state) + ui = new(user, src, "AtmosPump", name) ui.open() /obj/machinery/atmospherics/components/binary/volume_pump/ui_data() diff --git a/code/modules/atmospherics/machinery/components/trinary_devices/filter.dm b/code/modules/atmospherics/machinery/components/trinary_devices/filter.dm index dd6952dfc6..ffab6a885c 100644 --- a/code/modules/atmospherics/machinery/components/trinary_devices/filter.dm +++ b/code/modules/atmospherics/machinery/components/trinary_devices/filter.dm @@ -133,11 +133,10 @@ set_frequency(frequency) return ..() -/obj/machinery/atmospherics/components/trinary/filter/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ - datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) +/obj/machinery/atmospherics/components/trinary/filter/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) if(!ui) - ui = new(user, src, ui_key, "AtmosFilter", name, 475, 185, master_ui, state) + ui = new(user, src, "AtmosFilter", name) ui.open() /obj/machinery/atmospherics/components/trinary/filter/ui_data() diff --git a/code/modules/atmospherics/machinery/components/trinary_devices/mixer.dm b/code/modules/atmospherics/machinery/components/trinary_devices/mixer.dm index 758d27ab61..7dac6d540e 100644 --- a/code/modules/atmospherics/machinery/components/trinary_devices/mixer.dm +++ b/code/modules/atmospherics/machinery/components/trinary_devices/mixer.dm @@ -14,9 +14,6 @@ construction_type = /obj/item/pipe/trinary/flippable pipe_state = "mixer" - ui_x = 370 - ui_y = 165 - //node 3 is the outlet, nodes 1 & 2 are intakes /obj/machinery/atmospherics/components/trinary/mixer/CtrlClick(mob/user) @@ -127,11 +124,10 @@ var/datum/pipeline/parent3 = parents[3] parent3.update = TRUE -/obj/machinery/atmospherics/components/trinary/mixer/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ - datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) +/obj/machinery/atmospherics/components/trinary/mixer/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) if(!ui) - ui = new(user, src, ui_key, "AtmosMixer", name, ui_x, ui_y, master_ui, state) + ui = new(user, src, "AtmosMixer", name) ui.open() /obj/machinery/atmospherics/components/trinary/mixer/ui_data() diff --git a/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm b/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm index 0f849af0e3..c08eaf2e8a 100644 --- a/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm +++ b/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm @@ -332,11 +332,13 @@ return return ..() -/obj/machinery/atmospherics/components/unary/cryo_cell/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ - datum/tgui/master_ui = null, datum/ui_state/state = GLOB.notcontained_state) - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) +/obj/machinery/atmospherics/components/unary/cryo_cell/ui_state(mob/user) + return GLOB.notcontained_state + +/obj/machinery/atmospherics/components/unary/cryo_cell/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) if(!ui) - ui = new(user, src, ui_key, "Cryo", name, 400, 550, master_ui, state) + ui = new(user, src, "Cryo", name) ui.open() /obj/machinery/atmospherics/components/unary/cryo_cell/ui_data() diff --git a/code/modules/atmospherics/machinery/components/unary_devices/outlet_injector.dm b/code/modules/atmospherics/machinery/components/unary_devices/outlet_injector.dm index 70672418a1..a07f131d62 100644 --- a/code/modules/atmospherics/machinery/components/unary_devices/outlet_injector.dm +++ b/code/modules/atmospherics/machinery/components/unary_devices/outlet_injector.dm @@ -20,9 +20,6 @@ pipe_state = "injector" - ui_x = 310 - ui_y = 115 - /obj/machinery/atmospherics/components/unary/outlet_injector/CtrlClick(mob/user) if(can_interact(user)) on = !on @@ -132,7 +129,7 @@ on = !on if("inject" in signal.data) - spawn inject() + INVOKE_ASYNC(src, .proc/inject) return if("set_volume_rate" in signal.data) @@ -140,22 +137,16 @@ var/datum/gas_mixture/air_contents = airs[1] volume_rate = clamp(number, 0, air_contents.return_volume()) - if("status" in signal.data) - spawn(2) - broadcast_status() - return //do not update_icon + addtimer(CALLBACK(src, .proc/broadcast_status), 2) - spawn(2) - broadcast_status() - - update_icon() + if(!("status" in signal.data)) //do not update_icon + update_icon() -/obj/machinery/atmospherics/components/unary/outlet_injector/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ - datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) +/obj/machinery/atmospherics/components/unary/outlet_injector/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) if(!ui) - ui = new(user, src, ui_key, "AtmosPump", name, ui_x, ui_y, master_ui, state) + ui = new(user, src, "AtmosPump", name) ui.open() /obj/machinery/atmospherics/components/unary/outlet_injector/ui_data() diff --git a/code/modules/atmospherics/machinery/components/unary_devices/relief_valve.dm b/code/modules/atmospherics/machinery/components/unary_devices/relief_valve.dm index 0893d2b9e6..f0d0d1d856 100644 --- a/code/modules/atmospherics/machinery/components/unary_devices/relief_valve.dm +++ b/code/modules/atmospherics/machinery/components/unary_devices/relief_valve.dm @@ -61,15 +61,14 @@ update_parents() -/obj/machinery/atmospherics/components/unary/relief_valve/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ - datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) +/obj/machinery/atmospherics/components/unary/relief_valve/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) if(!ui) - ui = new(user, src, ui_key, "atmos_relief", name, 335, 115, master_ui, state) + ui = new(user, src, "AtmosRelief", name) ui.open() /obj/machinery/atmospherics/components/unary/relief_valve/ui_data() - var/data = list() + var/list/data = list() data["open_pressure"] = round(open_pressure) data["close_pressure"] = round(close_pressure) data["max_pressure"] = round(50*ONE_ATMOSPHERE) @@ -80,7 +79,7 @@ return switch(action) if("open_pressure") - var/pressure = params["open_pressure"] + var/pressure = params["pressure"] if(pressure == "max") pressure = 50*ONE_ATMOSPHERE . = TRUE @@ -95,7 +94,7 @@ open_pressure = clamp(pressure, close_pressure, 50*ONE_ATMOSPHERE) investigate_log("open pressure was set to [open_pressure] kPa by [key_name(usr)]", INVESTIGATE_ATMOS) if("close_pressure") - var/pressure = params["close_pressure"] + var/pressure = params["pressure"] if(pressure == "max") pressure = open_pressure . = TRUE diff --git a/code/modules/atmospherics/machinery/components/unary_devices/thermomachine.dm b/code/modules/atmospherics/machinery/components/unary_devices/thermomachine.dm index c6168a6c9c..8456c0b346 100644 --- a/code/modules/atmospherics/machinery/components/unary_devices/thermomachine.dm +++ b/code/modules/atmospherics/machinery/components/unary_devices/thermomachine.dm @@ -11,8 +11,6 @@ layer = OBJ_LAYER plane = GAME_PLANE circuit = /obj/item/circuitboard/machine/thermomachine - ui_x = 300 - ui_y = 230 pipe_flags = PIPING_ONE_PER_TURF @@ -125,11 +123,10 @@ return ..() return UI_CLOSE -/obj/machinery/atmospherics/components/unary/thermomachine/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ - datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) +/obj/machinery/atmospherics/components/unary/thermomachine/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) if(!ui) - ui = new(user, src, ui_key, "ThermoMachine", name, ui_x, ui_y, master_ui, state) + ui = new(user, src, "ThermoMachine", name) ui.open() /obj/machinery/atmospherics/components/unary/thermomachine/ui_data(mob/user) diff --git a/code/modules/atmospherics/machinery/portable/canister.dm b/code/modules/atmospherics/machinery/portable/canister.dm index 12ba7e79b9..c66aabd57f 100644 --- a/code/modules/atmospherics/machinery/portable/canister.dm +++ b/code/modules/atmospherics/machinery/portable/canister.dm @@ -5,8 +5,6 @@ desc = "A canister for the storage of gas." icon_state = "yellow" density = TRUE - ui_x = 300 - ui_y = 232 var/valve_open = FALSE var/obj/machinery/atmospherics/components/binary/passive_gate/pump @@ -319,11 +317,13 @@ obj/machinery/portable_atmospherics/canister/welder_act(mob/living/user, obj/ite air_update_turf() // Update the environment if needed. update_icon() -/obj/machinery/portable_atmospherics/canister/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ - datum/tgui/master_ui = null, datum/ui_state/state = GLOB.physical_state) - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) +/obj/machinery/portable_atmospherics/canister/ui_state(mob/user) + return GLOB.physical_state + +/obj/machinery/portable_atmospherics/canister/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) if(!ui) - ui = new(user, src, ui_key, "Canister", name, ui_x, ui_y, master_ui, state) + ui = new(user, src, "Canister", name) ui.open() /obj/machinery/portable_atmospherics/canister/ui_data() diff --git a/code/modules/atmospherics/machinery/portable/pump.dm b/code/modules/atmospherics/machinery/portable/pump.dm index 7f1dc4d20f..bdde8f0f22 100644 --- a/code/modules/atmospherics/machinery/portable/pump.dm +++ b/code/modules/atmospherics/machinery/portable/pump.dm @@ -8,8 +8,6 @@ name = "portable air pump" icon_state = "psiphon:0" density = TRUE - ui_x = 300 - ui_y = 315 var/on = FALSE var/direction = PUMP_OUT @@ -83,11 +81,10 @@ investigate_log("[key_name(user)] started a transfer into [holding].", INVESTIGATE_ATMOS) -/obj/machinery/portable_atmospherics/pump/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ - datum/tgui/master_ui = null, datum/ui_state/state = GLOB.physical_state) - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) +/obj/machinery/portable_atmospherics/pump/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) if(!ui) - ui = new(user, src, ui_key, "PortablePump", name, ui_x, ui_y, master_ui, state) + ui = new(user, src, "PortablePump", name) ui.open() /obj/machinery/portable_atmospherics/pump/ui_data() diff --git a/code/modules/atmospherics/machinery/portable/scrubber.dm b/code/modules/atmospherics/machinery/portable/scrubber.dm index bc703b8bbd..7976ba641a 100644 --- a/code/modules/atmospherics/machinery/portable/scrubber.dm +++ b/code/modules/atmospherics/machinery/portable/scrubber.dm @@ -62,11 +62,10 @@ on = !on update_icon() -/obj/machinery/portable_atmospherics/scrubber/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ - datum/tgui/master_ui = null, datum/ui_state/state = GLOB.physical_state) - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) +/obj/machinery/portable_atmospherics/scrubber/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) if(!ui) - ui = new(user, src, ui_key, "PortableScrubber", name, ui_x, ui_y, master_ui, state) + ui = new(user, src, "PortableScrubber", name) ui.open() /obj/machinery/portable_atmospherics/scrubber/ui_data() diff --git a/code/modules/awaymissions/gateway.dm b/code/modules/awaymissions/gateway.dm index 157fdb7bc7..8476090f75 100644 --- a/code/modules/awaymissions/gateway.dm +++ b/code/modules/awaymissions/gateway.dm @@ -277,11 +277,10 @@ GLOBAL_LIST_EMPTY(gateway_destinations) . = ..() try_to_linkup() -/obj/machinery/computer/gateway_control/ui_interact(mob/user, ui_key = "main", datum/tgui/ui, force_open, datum/tgui/master_ui, datum/ui_state/state = GLOB.default_state) - . = ..() - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) +/obj/machinery/computer/gateway_control/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) if(!ui) - ui = new(user, src, ui_key, "Gateway", name, ui_x, ui_y, master_ui, state) + ui = new(user, src, "Gateway", name) ui.open() /obj/machinery/computer/gateway_control/ui_data(mob/user) diff --git a/code/modules/cargo/bounty_console.dm b/code/modules/cargo/bounty_console.dm index f499c38090..8a29715016 100644 --- a/code/modules/cargo/bounty_console.dm +++ b/code/modules/cargo/bounty_console.dm @@ -1,18 +1,18 @@ #define PRINTER_TIMEOUT 10 - - /obj/machinery/computer/bounty - name = "Nanotrasen bounty console" + name = "\improper Nanotrasen bounty console" desc = "Used to check and claim bounties offered by Nanotrasen" icon_screen = "bounty" circuit = /obj/item/circuitboard/computer/bounty light_color = "#E2853D"//orange var/printer_ready = 0 //cooldown var + var/static/datum/bank_account/cargocash /obj/machinery/computer/bounty/Initialize() . = ..() printer_ready = world.time + PRINTER_TIMEOUT + cargocash = SSeconomy.get_dep_account(ACCOUNT_CAR) /obj/machinery/computer/bounty/proc/print_paper() new /obj/item/paper/bounty_printout(loc) @@ -23,70 +23,43 @@ /obj/item/paper/bounty_printout/Initialize() . = ..() info = "

Nanotrasen Cargo Bounties


" + update_icon() + for(var/datum/bounty/B in GLOB.bounties_list) if(B.claimed) continue info += {"

[B.name]

-
  • Reward: [B.reward_string()]
  • -
  • Completed: [B.completion_string()]
"} - -/obj/machinery/computer/bounty/ui_interact(mob/user) - . = ..() +
  • Reward: [B.reward_string()]
  • +
  • Completed: [B.completion_string()]
"} +/obj/machinery/computer/bounty/ui_interact(mob/user, datum/tgui/ui) if(!GLOB.bounties_list.len) setup_bounties() - var/datum/bank_account/D = SSeconomy.get_dep_account(ACCOUNT_CAR) - var/list/dat = list({"Refresh - Print Paper -

Credits: [D.account_balance]

- - "}) - for(var/datum/bounty/B in GLOB.bounties_list) - if(B.claimed) - dat += "" - else if(B.can_claim()) - dat += "" - else - dat += "" - if(B.high_priority) - dat += {" - - "} - else - dat += {" - - "} - dat += "" - if(B.claimed) - dat += "" - else if(B.can_claim()) - dat += "" - else - dat += "" - dat += "" - dat += "
NameDescriptionRewardCompletionStatus
[B.name]High Priority: [B.description][B.reward_string()][B.name][B.description][B.reward_string()][B.completion_string()]ClaimedClaimUnclaimed
" - dat = dat.Join() - var/datum/browser/popup = new(user, "bounties", "Nanotrasen Bounties", 700, 600) - popup.set_content(dat) - popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state)) - popup.open() + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "CargoBountyConsole", name) + ui.open() -/obj/machinery/computer/bounty/Topic(href, href_list) +/obj/machinery/computer/bounty/ui_data(mob/user) + var/list/data = list() + var/list/bountyinfo = list() + for(var/datum/bounty/B in GLOB.bounties_list) + bountyinfo += list(list("name" = B.name, "description" = B.description, "reward_string" = B.reward_string(), "completion_string" = B.completion_string() , "claimed" = B.claimed, "can_claim" = B.can_claim(), "priority" = B.high_priority, "bounty_ref" = REF(B))) + data["stored_cash"] = cargocash.account_balance + data["bountydata"] = bountyinfo + return data + +/obj/machinery/computer/bounty/ui_act(action,params) if(..()) return - - switch(href_list["choice"]) + switch(action) + if("ClaimBounty") + var/datum/bounty/cashmoney = locate(params["bounty"]) in GLOB.bounties_list + if(cashmoney) + cashmoney.claim() + return TRUE if("Print") if(printer_ready < world.time) printer_ready = world.time + PRINTER_TIMEOUT print_paper() - - if("Claim") - var/datum/bounty/B = locate(href_list["d_rec"]) - if(B in GLOB.bounties_list) - B.claim() - - if(href_list["refresh"]) - playsound(src, "terminal_type", 25, 0) - - updateUsrDialog() + return diff --git a/code/modules/cargo/centcom_podlauncher.dm b/code/modules/cargo/centcom_podlauncher.dm index f33ea7059b..b7eac1e591 100644 --- a/code/modules/cargo/centcom_podlauncher.dm +++ b/code/modules/cargo/centcom_podlauncher.dm @@ -11,7 +11,7 @@ /client/proc/centcom_podlauncher() //Creates a verb for admins to open up the ui set name = "Config/Launch Supplypod" - set desc = "Configure and launch a Centcom supplypod full of whatever your heart desires!" + set desc = "Configure and launch a CentCom supplypod full of whatever your heart desires!" set category = "Admin" var/datum/centcom_podlauncher/plaunch = new(usr)//create the datum plaunch.ui_interact(usr)//datum has a tgui component, here we open the window @@ -23,7 +23,10 @@ var/turf/oldTurf //Keeps track of where the user was at if they use the "teleport to centcom" button, so they can go back var/client/holder //client of whoever is using this datum var/area/bay //What bay we're using to launch shit from. + var/turf/dropoff_turf //If we're reversing, where the reverse pods go + var/picking_dropoff_turf var/launchClone = FALSE //If true, then we don't actually launch the thing in the bay. Instead we call duplicateObject() and send the result + var/launchRandomItem = FALSE //If true, lauches a single random item instead of everything on a turf. var/launchChoice = 1 //Determines if we launch all at once (0) , in order (1), or at random(2) var/explosionChoice = 0 //Determines if there is no explosion (0), custom explosion (1), or just do a maxcap (2) var/damageChoice = 0 //Determines if we do no damage (0), custom amnt of damage (1), or gib + 5000dmg (2) @@ -50,20 +53,25 @@ temp_pod = new(locate(/area/centcom/supplypod/podStorage) in GLOB.sortedAreas) //Create a new temp_pod in the podStorage area on centcom (so users are free to look at it and change other variables if needed) orderedArea = createOrderedArea(bay) //Order all the turfs in the selected bay (top left to bottom right) to a single list. Used for the "ordered" mode (launchChoice = 1) -/datum/centcom_podlauncher/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, \ -force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.admin_state)//ui_interact is called when the client verb is called. +/datum/centcom_podlauncher/ui_state(mob/user) + return GLOB.admin_state - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) +/datum/centcom_podlauncher/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) if(!ui) - ui = new(user, src, ui_key, "CentcomPodLauncher", "Config/Launch Supplypod", 700, 700, master_ui, state) + ui = new(user, src, "CentcomPodLauncher") ui.open() /datum/centcom_podlauncher/ui_data(mob/user) //Sends info about the pod to the UI. var/list/data = list() //*****NOTE*****: Many of these comments are similarly described in supplypod.dm. If you change them here, please consider doing so in the supplypod code as well! - var/B = (istype(bay, /area/centcom/supplypod/loading/one)) ? 1 : (istype(bay, /area/centcom/supplypod/loading/two)) ? 2 : (istype(bay, /area/centcom/supplypod/loading/three)) ? 3 : (istype(bay, /area/centcom/supplypod/loading/four)) ? 4 : 0 //top ten THICCEST FUCKING TERNARY CONDITIONALS OF 2036 - data["bay"] = B //Holds the current bay the user is launching objects from. Bays are specific rooms on the centcom map. + var/B = (istype(bay, /area/centcom/supplypod/loading/one)) ? 1 : (istype(bay, /area/centcom/supplypod/loading/two)) ? 2 : (istype(bay, /area/centcom/supplypod/loading/three)) ? 3 : (istype(bay, /area/centcom/supplypod/loading/four)) ? 4 : 0 //(istype(bay, /area/centcom/supplypod/loading/ert)) ? 5 : 0 //top ten THICCEST FUCKING TERNARY CONDITIONALS OF 2036 + data["bay"] = bay //Holds the current bay the user is launching objects from. Bays are specific rooms on the centcom map. + data["bayNumber"] = B //Holds the bay as a number. Useful for comparisons in centcom_podlauncher.ract data["oldArea"] = (oldTurf ? get_area(oldTurf) : null) //Holds the name of the area that the user was in before using the teleportCentcom action + data["picking_dropoff_turf"] = picking_dropoff_turf //If we're picking or have picked a dropoff turf. Only works when pod is in reverse mode + data["dropoff_turf"] = dropoff_turf //The turf that reverse pods will drop their newly acquired cargo off at data["launchClone"] = launchClone //Do we launch the actual items in the bay or just launch clones of them? + data["launchRandomItem"] = launchRandomItem //Do we launch a single random item instead of everything on the turf? data["launchChoice"] = launchChoice //Launch turfs all at once (0), ordered (1), or randomly(1) data["explosionChoice"] = explosionChoice //An explosion that occurs when landing. Can be no explosion (0), custom explosion (1), or maxcap (2) data["damageChoice"] = damageChoice //Damage that occurs to any mob under the pod when it lands. Can be no damage (0), custom damage (1), or gib+5000dmg (2) @@ -72,11 +80,12 @@ force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.adm data["openingDelay"] = temp_pod.openingDelay //How long the pod takes to open after landing data["departureDelay"] = temp_pod.departureDelay //How long the pod takes to leave after opening (if bluespace=true, it deletes. if reversing=true, it flies back to centcom) data["styleChoice"] = temp_pod.style //Style is a variable that keeps track of what the pod is supposed to look like. It acts as an index to the POD_STYLES list in cargo.dm defines to get the proper icon/name/desc for the pod. + data["effectShrapnel"] = FALSE //temp_pod.effectShrapnel //If true, creates a cloud of shrapnel of a decided type and magnitude on landing data["effectStun"] = temp_pod.effectStun //If true, stuns anyone under the pod when it launches until it lands, forcing them to get hit by the pod. Devilish! data["effectLimb"] = temp_pod.effectLimb //If true, pops off a limb (if applicable) from anyone caught under the pod when it lands data["effectOrgans"] = temp_pod.effectOrgans //If true, yeets the organs out of any bodies caught under the pod when it lands data["effectBluespace"] = temp_pod.bluespace //If true, the pod deletes (in a shower of sparks) after landing - data["effectStealth"] = temp_pod.effectStealth //If true, a target icon isnt displayed on the turf where the pod will land + data["effectStealth"] = temp_pod.effectStealth //If true, a target icon isn't displayed on the turf where the pod will land data["effectQuiet"] = temp_pod.effectQuiet //The female sniper. If true, the pod makes no noise (including related explosions, opening sounds, etc) data["effectMissile"] = temp_pod.effectMissile //If true, the pod deletes the second it lands. If you give it an explosion, it will act like a missile exploding as it hits the ground data["effectCircle"] = temp_pod.effectCircle //If true, allows the pod to come in at any angle. Bit of a weird feature but whatever its here @@ -115,20 +124,41 @@ force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.adm bay = locate(/area/centcom/supplypod/loading/four) in GLOB.sortedAreas refreshBay() . = TRUE + if("bay5") + to_chat(usr, "LetterN is lazy and didin't bother porting this new cc area!") + return + // bay = locate(/area/centcom/supplypod/loading/ert) in GLOB.sortedAreas + // refreshBay() + // . = TRUE + if("pickDropoffTurf") //Enters a mode that lets you pick the dropoff location for reverse pods + if (picking_dropoff_turf) + picking_dropoff_turf = FALSE + updateCursor(FALSE, FALSE) //Update the cursor of the user to a cool looking target icon + return + if (launcherActivated) + launcherActivated = FALSE //We don't want to have launch mode enabled while we're picking a turf + picking_dropoff_turf = TRUE + updateCursor(FALSE, TRUE) //Update the cursor of the user to a cool looking target icon + . = TRUE + if("clearDropoffTurf") + picking_dropoff_turf = FALSE + dropoff_turf = null + updateCursor(FALSE, FALSE) + . = TRUE if("teleportCentcom") //Teleports the user to the centcom supply loading facility. var/mob/M = holder.mob //We teleport whatever mob the client is attached to at the point of clicking oldTurf = get_turf(M) //Used for the "teleportBack" action - var/area/A = locate(/area/centcom/supplypod/loading) in GLOB.sortedAreas + var/area/A = locate(bay) in GLOB.sortedAreas var/list/turfs = list() for(var/turf/T in A) turfs.Add(T) //Fill a list with turfs in the area - var/turf/T = safepick(turfs) //Only teleport if the list isn't empty - if(!T) //If the list is empty, error and cancel + if (!length(turfs)) //If the list is empty, error and cancel to_chat(M, "Nowhere to jump to!") - return + return //Only teleport if the list isn't empty + var/turf/T = pick(turfs) M.forceMove(T) //Perform the actual teleport - log_admin("[key_name(usr)] jumped to [AREACOORD(A)]") - message_admins("[key_name_admin(usr)] jumped to [AREACOORD(A)]") + log_admin("[key_name(usr)] jumped to [AREACOORD(T)]") + message_admins("[key_name_admin(usr)] jumped to [AREACOORD(T)]") . = TRUE if("teleportBack") //After teleporting to centcom, this button allows the user to teleport to the last spot they were at. var/mob/M = holder.mob @@ -144,6 +174,9 @@ force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.adm if("launchClone") //Toggles the launchClone var. See variable declarations above for what this specifically means launchClone = !launchClone . = TRUE + if("launchRandomItem") //Pick random turfs from the supplypod bay at centcom to launch + launchRandomItem = !launchRandomItem + . = TRUE if("launchOrdered") //Launch turfs (from the orderedArea list) one at a time in order, from the supplypod bay at centcom if (launchChoice == 1) //launchChoice 1 represents ordered. If we push "ordered" and it already is, then we go to default value launchChoice = 0 @@ -152,7 +185,7 @@ force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.adm launchChoice = 1 updateSelector() . = TRUE - if("launchRandom") //Pick random turfs from the supplypod bay at centcom to launch + if("launchRandomTurf") //Pick random turfs from the supplypod bay at centcom to launch if (launchChoice == 2) launchChoice = 0 updateSelector() @@ -170,11 +203,11 @@ force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.adm var/list/expNames = list("Devastation", "Heavy Damage", "Light Damage", "Flame") //Explosions have a range of different types of damage var/list/boomInput = list() for (var/i=1 to expNames.len) //Gather input from the user for the value of each type of damage - boomInput.Add(input("[expNames[i]] Range", "Enter the [expNames[i]] range of the explosion. WARNING: This ignores the bomb cap!", 0) as null|num) + boomInput.Add(input("Enter the [expNames[i]] range of the explosion. WARNING: This ignores the bomb cap!", "[expNames[i]] Range", 0) as null|num) if (isnull(boomInput[i])) return if (!isnum(boomInput[i])) //If the user doesn't input a number, set that specific explosion value to zero - alert(usr, "That wasnt a number! Value set to default (zero) instead.") + alert(usr, "That wasn't a number! Value set to default (zero) instead.") boomInput = 0 explosionChoice = 1 temp_pod.explosionSize = boomInput @@ -192,11 +225,11 @@ force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.adm damageChoice = 0 temp_pod.damage = 0 return - var/damageInput = input("How much damage to deal", "Enter the amount of brute damage dealt by getting hit", 0) as null|num + var/damageInput = input("Enter the amount of brute damage dealt by getting hit","How much damage to deal", 0) as null|num if (isnull(damageInput)) return if (!isnum(damageInput)) //Sanitize the input for damage to deal.s - alert(usr, "That wasnt a number! Value set to default (zero) instead.") + alert(usr, "That wasn't a number! Value set to default (zero) instead.") damageInput = 0 damageChoice = 1 temp_pod.damage = damageInput @@ -226,13 +259,32 @@ force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.adm temp_pod.desc = descInput temp_pod.adminNamed = TRUE //This variable is checked in the supplypod/setStyle() proc . = TRUE + /* + if("effectShrapnel") //Creates a cloud of shrapnel on landing + if (temp_pod.effectShrapnel == TRUE) //If already doing custom damage, set back to default (no shrapnel) + temp_pod.effectShrapnel = FALSE + return + var/shrapnelInput = input("Please enter the type of pellet cloud you'd like to create on landing (Can be any projectile!)", "Projectile Typepath", 0) in sortList(subtypesof(/obj/item/projectile), /proc/cmp_typepaths_asc) + if (isnull(shrapnelInput)) + return + var/shrapnelMagnitude = input("Enter the magnitude of the pellet cloud. This is usually a value around 1-5. Please note that Ryll-Ryll has asked me to tell you that if you go too crazy with the projectiles you might crash the server. So uh, be gentle!", "Shrapnel Magnitude", 0) as null|num + if (isnull(shrapnelMagnitude)) + return + if (!isnum(shrapnelMagnitude)) + alert(usr, "That wasn't a number! Value set to 3 instead.") + shrapnelMagnitude = 3 + temp_pod.shrapnel_type = shrapnelInput + temp_pod.shrapnel_magnitude = shrapnelMagnitude + temp_pod.effectShrapnel = TRUE + . = TRUE + */ if("effectStun") //Toggle: Any mob under the pod is stunned (cant move) until the pod lands, hitting them! temp_pod.effectStun = !temp_pod.effectStun . = TRUE if("effectLimb") //Toggle: Anyone carbon mob under the pod loses a limb when it lands temp_pod.effectLimb = !temp_pod.effectLimb . = TRUE - if("effectOrgans") //Toggle: Any carbon mob under the pod loses every limb and organ + if("effectOrgans") //Toggle: Anyone carbon mob under the pod loses a limb when it lands temp_pod.effectOrgans = !temp_pod.effectOrgans . = TRUE if("effectBluespace") //Toggle: Deletes the pod after landing @@ -253,7 +305,7 @@ force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.adm if("effectBurst") //Toggle: Launch 5 pods (with a very slight delay between) in a 3x3 area centered around the target effectBurst = !effectBurst . = TRUE - if("effectAnnounce") //Toggle: Sends a ghost announcement. + if("effectAnnounce") //Toggle: Launch 5 pods (with a very slight delay between) in a 3x3 area centered around the target effectAnnounce = !effectAnnounce . = TRUE if("effectReverse") //Toggle: Don't send any items. Instead, after landing, close (taking any objects inside) and go back to the centcom bay it came from @@ -272,15 +324,15 @@ force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.adm . = TRUE ////////////////////////////TIMER DELAYS////////////////// - if("fallDuration") //Change the falling animation duration - if (temp_pod.fallDuration != initial(temp_pod.fallDuration)) //If the fall duration has already been changed when we push the "change value" button, then set it to default + if("fallDuration") //Change the time it takes the pod to land, after firing + if (temp_pod.fallDuration != initial(temp_pod.fallDuration)) //If the landing delay has already been changed when we push the "change value" button, then set it to default temp_pod.fallDuration = initial(temp_pod.fallDuration) return - var/timeInput = input("Enter the duration of the pod's falling animation, in seconds", "Delay Time", initial(temp_pod.fallDuration) * 0.1) as null|num + var/timeInput = input("Enter the duration of the pod's falling animation, in seconds", "Delay Time", initial(temp_pod.fallDuration) * 0.1) as null|num if (isnull(timeInput)) return if (!isnum(timeInput)) //Sanitize input, if it doesnt check out, error and set to default - alert(usr, "That wasnt a number! Value set to default ([initial(temp_pod.fallDuration)*0.1]) instead.") + alert(usr, "That wasn't a number! Value set to default ([initial(temp_pod.fallDuration)*0.1]) instead.") timeInput = initial(temp_pod.fallDuration) temp_pod.fallDuration = 10 * timeInput . = TRUE @@ -292,7 +344,7 @@ force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.adm if (isnull(timeInput)) return if (!isnum(timeInput)) //Sanitize input, if it doesnt check out, error and set to default - alert(usr, "That wasnt a number! Value set to default ([initial(temp_pod.landingDelay)*0.1]) instead.") + alert(usr, "That wasn't a number! Value set to default ([initial(temp_pod.landingDelay)*0.1]) instead.") timeInput = initial(temp_pod.landingDelay) temp_pod.landingDelay = 10 * timeInput . = TRUE @@ -304,7 +356,7 @@ force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.adm if (isnull(timeInput)) return if (!isnum(timeInput)) //Sanitize input - alert(usr, "That wasnt a number! Value set to default ([initial(temp_pod.openingDelay)*0.1]) instead.") + alert(usr, "That wasn't a number! Value set to default ([initial(temp_pod.openingDelay)*0.1]) instead.") timeInput = initial(temp_pod.openingDelay) temp_pod.openingDelay = 10 * timeInput . = TRUE @@ -316,13 +368,13 @@ force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.adm if (isnull(timeInput)) return if (!isnum(timeInput)) - alert(usr, "That wasnt a number! Value set to default ([initial(temp_pod.departureDelay)*0.1]) instead.") + alert(usr, "That wasn't a number! Value set to default ([initial(temp_pod.departureDelay)*0.1]) instead.") timeInput = initial(temp_pod.departureDelay) temp_pod.departureDelay = 10 * timeInput . = TRUE ////////////////////////////ADMIN SOUNDS////////////////// - if("fallingSound") //Admin sound from a local file that plays when the pod falls + if("fallSound") //Admin sound from a local file that plays when the pod lands if ((temp_pod.fallingSound) != initial(temp_pod.fallingSound)) temp_pod.fallingSound = initial(temp_pod.fallingSound) temp_pod.fallingSoundLength = initial(temp_pod.fallingSoundLength) @@ -334,7 +386,7 @@ force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.adm if (isnull(timeInput)) return if (!isnum(timeInput)) - alert(usr, "That wasnt a number! Value set to default ([initial(temp_pod.fallingSoundLength)*0.1]) instead.") + alert(usr, "That wasn't a number! Value set to default ([initial(temp_pod.fallingSoundLength)*0.1]) instead.") temp_pod.fallingSound = soundInput temp_pod.fallingSoundLength = 10 * timeInput . = TRUE @@ -369,7 +421,7 @@ force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.adm if (temp_pod.soundVolume != initial(temp_pod.soundVolume)) temp_pod.soundVolume = initial(temp_pod.soundVolume) return - var/soundInput = input(holder, "Please pick a volume. Default is between 1 and 100 with 80 being average, but pick whatever. I'm a notification, not a cop. If you still cant hear your sound, consider turning on the Quiet effect. It will silence all pod sounds except for the custom admin ones set by the previous three buttons.", "Pick Admin Sound Volume") as null|num + var/soundInput = input(holder, "Please pick a volume. Default is between 1 and 100 with 50 being average, but pick whatever. I'm a notification, not a cop. If you still cant hear your sound, consider turning on the Quiet effect. It will silence all pod sounds except for the custom admin ones set by the previous three buttons.", "Pick Admin Sound Volume") as null|num if (isnull(soundInput)) return temp_pod.soundVolume = soundInput @@ -421,26 +473,36 @@ force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.adm . = TRUE if("giveLauncher") //Enters the "Launch Mode". When the launcher is activated, temp_pod is cloned, and the result it filled and launched anywhere the user clicks (unless specificTarget is true) launcherActivated = !launcherActivated - updateCursor(launcherActivated) //Update the cursor of the user to a cool looking target icon + updateCursor(launcherActivated, FALSE) //Update the cursor of the user to a cool looking target icon + . = TRUE + if("clearBay") //Delete all mobs and objs in the selected bay + if(alert(usr, "This will delete all objs and mobs in [bay]. Are you sure?", "Confirmation", "Delete that shit", "No") == "Delete that shit") + clearBay() + refreshBay() . = TRUE /datum/centcom_podlauncher/ui_close() //Uses the destroy() proc. When the user closes the UI, we clean up the temp_pod and supplypod_selector variables. qdel(src) -/datum/centcom_podlauncher/proc/updateCursor(var/launching) //Update the moues of the user - if (holder) //Check to see if we have a client - if (launching) //If the launching param is true, we give the user new mouse icons. - holder.mouse_up_icon = 'icons/effects/supplypod_target.dmi' //Icon for when mouse is released - holder.mouse_down_icon = 'icons/effects/supplypod_down_target.dmi' //Icon for when mouse is pressed - holder.mouse_pointer_icon = holder.mouse_up_icon //Icon for idle mouse (same as icon for when released) - holder.click_intercept = src //Create a click_intercept so we know where the user is clicking - else - var/mob/M = holder.mob - holder.mouse_up_icon = null - holder.mouse_down_icon = null - holder.click_intercept = null - if (M) - M.update_mouse_pointer() //set the moues icons to null, then call update_moues_pointer() which resets them to the correct values based on what the mob is doing (in a mech, holding a spell, etc)() +/datum/centcom_podlauncher/proc/updateCursor(var/launching, var/turf_picking) //Update the mouse of the user + if (!holder) //Can't update the mouse icon if the client doesnt exist! + return + if (launching || turf_picking) //If the launching param is true, we give the user new mouse icons. + if(launching) + holder.mouse_up_icon = 'icons/effects/mouse_pointers/supplypod_target.dmi' //Icon for when mouse is released + holder.mouse_down_icon = 'icons/effects/mouse_pointers/supplypod_down_target.dmi' //Icon for when mouse is pressed + if(turf_picking) + holder.mouse_up_icon = 'icons/effects/mouse_pointers/supplypod_pickturf.dmi' //Icon for when mouse is released + holder.mouse_down_icon = 'icons/effects/mouse_pointers/supplypod_pickturf_down.dmi' //Icon for when mouse is pressed + holder.mouse_pointer_icon = holder.mouse_up_icon //Icon for idle mouse (same as icon for when released) + holder.click_intercept = src //Create a click_intercept so we know where the user is clicking + else + var/mob/M = holder.mob + holder.mouse_up_icon = null + holder.mouse_down_icon = null + holder.click_intercept = null + if (M) + M.update_mouse_pointer() //set the moues icons to null, then call update_moues_pointer() which resets them to the correct values based on what the mob is doing (in a mech, holding a spell, etc)() /datum/centcom_podlauncher/proc/InterceptClickOn(user,params,atom/target) //Click Intercept so we know where to send pods where the user clicks var/list/pa = params2list(params) @@ -461,7 +523,7 @@ force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.adm else return //if target is null and we don't have a specific target, cancel if (effectAnnounce) - deadchat_broadcast("A special package is being launched at the station!", turf_target = target) + deadchat_broadcast("A special package is being launched at the station!", turf_target = target) //, message_type=DEADCHAT_ANNOUNCEMENT) var/list/bouttaDie = list() for (var/mob/living/M in target) bouttaDie.Add(M) @@ -479,6 +541,15 @@ force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.adm else launch(target) //If we couldn't locate an adjacent turf, just launch at the normal target sleep(rand()*2) //looks cooler than them all appearing at once. Gives the impression of burst fire. + else if (picking_dropoff_turf) + //Clicking on UI elements shouldn't pick a dropoff turf + if(istype(target,/obj/screen)) + return FALSE + + . = TRUE + if(left_click) //When we left click: + dropoff_turf = get_turf(target) + to_chat(user, " You've selected [dropoff_turf] at [COORD(dropoff_turf)] as your dropoff location.") /datum/centcom_podlauncher/proc/refreshBay() //Called whenever the bay is switched, as well as wheneber a pod is launched orderedArea = createOrderedArea(bay) //Create an ordered list full of turfs form the bay @@ -489,7 +560,7 @@ force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.adm to_chat(holder.mob, "No /area/centcom/supplypod/loading/one (or /two or /three or /four) in the world! You can make one yourself (then refresh) for now, but yell at a mapper to fix this, today!") CRASH("No /area/centcom/supplypod/loading/one (or /two or /three or /four) has been mapped into the centcom z-level!") orderedArea = list() - if (!isemptylist(A.contents)) //Go through the area passed into the proc, and figure out the top left and bottom right corners by calculating max and min values + if (length(A.contents)) //Go through the area passed into the proc, and figure out the top left and bottom right corners by calculating max and min values var/startX = A.contents[1].x //Create the four values (we do it off a.contents[1] so they have some sort of arbitrary initial value. They should be overwritten in a few moments) var/endX = A.contents[1].x var/startY = A.contents[1].y @@ -512,12 +583,12 @@ force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.adm numTurfs = 0 //Counts the number of turfs that can be launched (remember, supplypods either launch all at once or one turf-worth of items at a time) acceptableTurfs = list() for (var/turf/T in orderedArea) //Go through the orderedArea list - if (typecache_filter_list_reverse(T.contents, ignored_atoms).len != 0) //if there is something in this turf that isnt in the blacklist, we consider this turf "acceptable" and add it to the acceptableTurfs list + if (typecache_filter_list_reverse(T.contents, ignored_atoms).len != 0) //if there is something in this turf that isn't in the blacklist, we consider this turf "acceptable" and add it to the acceptableTurfs list acceptableTurfs.Add(T) //Because orderedArea was an ordered linear list, acceptableTurfs will be as well. numTurfs ++ launchList = list() //Anything in launchList will go into the supplypod when it is launched - if (!isemptylist(acceptableTurfs) && !temp_pod.reversing && !temp_pod.effectMissile) //We dont fill the supplypod if acceptableTurfs is empty, if the pod is going in reverse (effectReverse=true), or if the pod is acitng like a missile (effectMissile=true) + if (length(acceptableTurfs) && !temp_pod.reversing && !temp_pod.effectMissile) //We dont fill the supplypod if acceptableTurfs is empty, if the pod is going in reverse (effectReverse=true), or if the pod is acitng like a missile (effectMissile=true) switch(launchChoice) if(0) //If we are launching all the turfs at once for (var/turf/T in acceptableTurfs) @@ -536,22 +607,36 @@ force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.adm if (isnull(A)) return var/obj/structure/closet/supplypod/centcompod/toLaunch = DuplicateObject(temp_pod) //Duplicate the temp_pod (which we have been varediting or configuring with the UI) and store the result - toLaunch.bay = bay //Bay is currently a nonstatic expression, so it cant go into toLaunch using DuplicateObject - toLaunch.update_icon()//we update_icon() here so that the door doesnt "flicker on" right after it lands - if (launchClone) //We arent launching the actual items from the bay, rather we are creating clones and launching those - for (var/atom/movable/O in launchList) - DuplicateObject(O).forceMove(toLaunch) //Duplicate each atom/movable in launchList and forceMove them into the supplypod - new /obj/effect/abstract/DPtarget(A, toLaunch) //Create the DPTarget, which will eventually forceMove the temp_pod to it's location + /* + if(dropoff_turf) + toLaunch.reverse_dropoff_turf = dropoff_turf else - for (var/atom/movable/O in launchList) //If we aren't cloning the objects, just go through the launchList + toLaunch.reverse_dropoff_turf = bay //Bay is currently a nonstatic expression, so it cant go into toLaunch using DuplicateObject + */ + toLaunch.update_icon()//we update_icon() here so that the door doesnt "flicker on" right after it lands + // var/shippingLane = GLOB.areas_by_type[/area/centcom/supplypod/fly_me_to_the_moon] + // toLaunch.forceMove(shippingLane) The shipping lane is temporarily closed due to ratvarian blockades + if (launchClone) //We arent launching the actual items from the bay, rather we are creating clones and launching those + if(launchRandomItem) + var/atom/movable/O = pick_n_take(launchList) + DuplicateObject(O).forceMove(toLaunch) //Duplicate a single atom/movable from launchList and forceMove it into the supplypod + else + for (var/atom/movable/O in launchList) + DuplicateObject(O).forceMove(toLaunch) //Duplicate each atom/movable in launchList and forceMove them into the supplypod + else + if(launchRandomItem) + var/atom/movable/O = pick_n_take(launchList) O.forceMove(toLaunch) //and forceMove any atom/moveable into the supplypod - new /obj/effect/abstract/DPtarget(A, toLaunch) //Then, create the DPTarget effect, which will eventually forceMove the temp_pod to it's location + else + for (var/atom/movable/O in launchList) //If we aren't cloning the objects, just go through the launchList + O.forceMove(toLaunch) //and forceMove any atom/moveable into the supplypod + new /obj/effect/abstract/DPtarget(A, toLaunch) //Then, create the DPTarget effect, which will eventually forceMove the temp_pod to it's location if (launchClone) launchCounter++ //We only need to increment launchCounter if we are cloning objects. //If we aren't cloning objects, taking and removing the first item each time from the acceptableTurfs list will inherently iterate through the list in order /datum/centcom_podlauncher/proc/updateSelector() //Ensures that the selector effect will showcase the next item if needed - if (launchChoice == 1 && !isemptylist(acceptableTurfs) && !temp_pod.reversing && !temp_pod.effectMissile) //We only show the selector if we are taking items from the bay + if (launchChoice == 1 && length(acceptableTurfs) && !temp_pod.reversing && !temp_pod.effectMissile) //We only show the selector if we are taking items from the bay var/index = launchCounter + 1 //launchCounter acts as an index to the ordered acceptableTurfs list, so adding one will show the next item in the list if (index > acceptableTurfs.len) //out of bounds check index = 1 @@ -559,8 +644,14 @@ force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.adm else selector.moveToNullspace() //Otherwise, we move the selector to nullspace until it is needed again +/datum/centcom_podlauncher/proc/clearBay() //Clear all objs and mobs from the selected bay + for (var/obj/O in bay.GetAllContents()) + qdel(O) + for (var/mob/M in bay.GetAllContents()) + qdel(M) + /datum/centcom_podlauncher/Destroy() //The Destroy() proc. This is called by ui_close proc, or whenever the user leaves the game - updateCursor(FALSE) //Make sure our moues cursor resets to default. False means we are not in launch mode + updateCursor(FALSE, FALSE) //Make sure our moues cursor resets to default. False means we are not in launch mode qdel(temp_pod) //Delete the temp_pod qdel(selector) //Delete the selector effect . = ..() @@ -581,8 +672,8 @@ force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.adm for (var/X in temp_pod.explosionSize) explosionString += "[X]|" - var/msg = "launched [podString][whomString].[delayString][damageString][explosionString]]" - message_admins("[key_name_admin(usr)] [msg] in [AREACOORD(specificTarget)].") - if (!isemptylist(whoDyin)) + var/msg = "launched [podString] towards [whomString] [delayString][damageString][explosionString]" + message_admins("[key_name_admin(usr)] [msg] in [ADMIN_VERBOSEJMP(specificTarget)].") + if (length(whoDyin)) for (var/mob/living/M in whoDyin) admin_ticket_log(M, "[key_name_admin(usr)] [msg]") diff --git a/code/modules/cargo/console.dm b/code/modules/cargo/console.dm index 8a438a1342..f5a8d21278 100644 --- a/code/modules/cargo/console.dm +++ b/code/modules/cargo/console.dm @@ -3,9 +3,6 @@ desc = "Used to order supplies, approve requests, and control the shuttle." icon_screen = "supply" circuit = /obj/item/circuitboard/computer/cargo - req_access = list(ACCESS_CARGO) - ui_x = 780 - ui_y = 750 var/requestonly = FALSE var/contraband = FALSE @@ -27,7 +24,6 @@ desc = "Used to request supplies from cargo." icon_screen = "request" circuit = /obj/item/circuitboard/computer/cargo/request - req_access = list() requestonly = TRUE /obj/machinery/computer/cargo/Initialize() @@ -66,15 +62,12 @@ var/obj/item/circuitboard/computer/cargo/board = circuit board.contraband = TRUE board.obj_flags |= EMAGGED - req_access = list() update_static_data(user) - return ..() -/obj/machinery/computer/cargo/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ - datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) +/obj/machinery/computer/cargo/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) if(!ui) - ui = new(user, src, ui_key, "Cargo", name, ui_x, ui_y, master_ui, state) + ui = new(user, src, "Cargo", name) ui.open() /obj/machinery/computer/cargo/ui_data() @@ -120,7 +113,6 @@ var/list/data = list() data["requestonly"] = requestonly data["supplies"] = list() - data["emagged"] = obj_flags & EMAGGED for(var/pack in SSshuttle.supply_packs) var/datum/supply_pack/P = SSshuttle.supply_packs[pack] if(!data["supplies"][P.group]) @@ -135,8 +127,8 @@ "cost" = P.cost, "id" = pack, "desc" = P.desc || P.name, // If there is a description, use it. Otherwise use the pack's name. + "goody" = P.goody, "private_goody" = P.goody == PACK_GOODY_PRIVATE, - "goody" = P.goody == PACK_GOODY_PUBLIC, "access" = P.access, "can_private_buy" = P.can_private_buy )) @@ -145,9 +137,6 @@ /obj/machinery/computer/cargo/ui_act(action, params, datum/tgui/ui) if(..()) return - if(!allowed(usr)) - to_chat(usr, "Access denied.") - return switch(action) if("send") if(!SSshuttle.supply.canMove()) @@ -179,6 +168,8 @@ else SSshuttle.shuttle_loan.loan_shuttle() say("The supply shuttle has been loaned to CentCom.") + investigate_log("[key_name(usr)] accepted a shuttle loan event.", INVESTIGATE_CARGO) + log_game("[key_name(usr)] accepted a shuttle loan event.") . = TRUE if("add") var/id = text2path(params["id"]) @@ -200,13 +191,15 @@ rank = "Silicon" var/datum/bank_account/account - if(self_paid) - if(!pack.can_private_buy && !(obj_flags & EMAGGED)) - return - var/obj/item/card/id/id_card = usr.get_idcard(TRUE) + if(self_paid && ishuman(usr)) + var/mob/living/carbon/human/H = usr + var/obj/item/card/id/id_card = H.get_idcard(TRUE) if(!istype(id_card)) say("No ID card detected.") return + if(istype(id_card, /obj/item/card/id/departmental_budget)) + say("The [src] rejects [id_card].") + return account = id_card.registered_account if(!istype(account)) say("Invalid bank account.") @@ -241,6 +234,9 @@ SSshuttle.shoppinglist += SO if(self_paid) say("Order processed. The price will be charged to [account.account_holder]'s bank account on delivery.") + if(requestonly && message_cooldown < world.time) + radio.talk_into(src, "A new order has been requested.", RADIO_CHANNEL_SUPPLY) + message_cooldown = world.time + 30 SECONDS . = TRUE if("remove") var/id = text2num(params["id"]) diff --git a/code/modules/cargo/exports/gear.dm b/code/modules/cargo/exports/gear.dm index 646e1c6e47..678948128f 100644 --- a/code/modules/cargo/exports/gear.dm +++ b/code/modules/cargo/exports/gear.dm @@ -310,7 +310,7 @@ /datum/export/gear/combatgloves cost = 80 unit_name = "combat gloves" - export_types = list(/obj/item/clothing/gloves/tackler/combat, /obj/item/clothing/gloves/tackler/dolphin, /obj/item/clothing/gloves/fingerless/pugilist/rapid, /obj/item/clothing/gloves/krav_maga) + export_types = list(/obj/item/clothing/gloves/tackler/combat, /obj/item/clothing/gloves/tackler/dolphin, /obj/item/clothing/gloves/krav_maga) include_subtypes = TRUE /datum/export/gear/bonegloves diff --git a/code/modules/cargo/exports/organs_robotics.dm b/code/modules/cargo/exports/organs_robotics.dm index 7f54e675ca..b65cf28949 100644 --- a/code/modules/cargo/exports/organs_robotics.dm +++ b/code/modules/cargo/exports/organs_robotics.dm @@ -2,11 +2,11 @@ /datum/export/robotics include_subtypes = FALSE - k_elasticity = 1/50 + k_elasticity = 1/200 /datum/export/implant include_subtypes = FALSE - k_elasticity = 1/50 + k_elasticity = 1/200 /datum/export/organs include_subtypes = TRUE @@ -34,8 +34,8 @@ export_types = list(/obj/item/organ/cyberimp/brain/anti_stun) /datum/export/implant/breathtube - cost = 150 - k_elasticity = 300/20 //Large before depleating + cost = 175 + k_elasticity = 1/350 //Large before depleating unit_name = "breath implant" export_types = list(/obj/item/organ/cyberimp/mouth/breathing_tube) @@ -71,35 +71,35 @@ export_types = list(/obj/item/organ/cyberimp/arm/gun/laser, /obj/item/organ/cyberimp/arm/gun/taser, /obj/item/organ/cyberimp/arm/esword, /obj/item/organ/cyberimp/arm/medibeam, /obj/item/organ/cyberimp/arm/combat, /obj/item/organ/cyberimp/arm/flash, /obj/item/organ/cyberimp/arm/baton) include_subtypes = TRUE -/datum/export/orgains/heart +/datum/export/organs/heart cost = 250 unit_name = "heart" export_types = list(/obj/item/organ/heart) exclude_types = list(/obj/item/organ/heart/cursed, /obj/item/organ/heart/cybernetic) -/datum/export/orgains/tongue +/datum/export/organs/tongue cost = 75 unit_name = "tongue" export_types = list(/obj/item/organ/tongue) -/datum/export/orgains/eyes +/datum/export/organs/eyes cost = 50 //So many things take your eyes out anyways unit_name = "eyes" export_types = list(/obj/item/organ/eyes) exclude_types = list(/obj/item/organ/eyes/robotic) -/datum/export/orgains/stomach +/datum/export/organs/stomach cost = 50 //can be replaced unit_name = "stomach" export_types = list(/obj/item/organ/stomach) -/datum/export/orgains/lungs +/datum/export/organs/lungs cost = 150 unit_name = "lungs" export_types = list(/obj/item/organ/lungs) exclude_types = list(/obj/item/organ/lungs/cybernetic, /obj/item/organ/lungs/cybernetic/upgraded) -/datum/export/orgains/liver +/datum/export/organs/liver cost = 175 unit_name = "liver" export_types = list(/obj/item/organ/liver) @@ -116,33 +116,33 @@ unit_name = "upgraded cybernetic organ" export_types = list(/obj/item/organ/lungs/cybernetic/upgraded, /obj/item/organ/liver/cybernetic/upgraded) -/datum/export/organs/tail //Shhh +/datum/export/organs/tail // yeah have fun pulling this off someone without catching a bwoink cost = 500 - unit_name = "error shipment failer" + unit_name = "organic tail" export_types = list(/obj/item/organ/tail) -/datum/export/orgains/vocal_cords +/datum/export/organs/vocal_cords cost = 500 unit_name = "vocal cords" export_types = list(/obj/item/organ/vocal_cords) //These are gotten via different races -/datum/export/robotics/lims - cost = 30 - unit_name = "robotic lim replacement" +/datum/export/robotics/limbs + cost = 60 + unit_name = "robotic limb replacement" export_types = list(/obj/item/bodypart/l_arm/robot, /obj/item/bodypart/r_arm/robot, /obj/item/bodypart/l_leg/robot, /obj/item/bodypart/r_leg/robot, /obj/item/bodypart/chest/robot, /obj/item/bodypart/head/robot) /datum/export/robotics/surpluse - cost = 40 - unit_name = "robotic lim replacement" + cost = 50 + unit_name = "robotic limb replacement" export_types = list(/obj/item/bodypart/l_arm/robot/surplus, /obj/item/bodypart/r_arm/robot/surplus, /obj/item/bodypart/l_leg/robot/surplus, /obj/item/bodypart/r_leg/robot/surplus) /datum/export/robotics/surplus_upgraded - cost = 50 - unit_name = "upgraded robotic lim replacement" + cost = 80 + unit_name = "upgraded robotic limb replacement" export_types = list(/obj/item/bodypart/l_arm/robot/surplus_upgraded, /obj/item/bodypart/r_arm/robot/surplus_upgraded, /obj/item/bodypart/l_leg/robot/surplus_upgraded, /obj/item/bodypart/r_leg/robot/surplus_upgraded) /datum/export/robotics/surgery_gear_basic - cost = 10 + cost = 50 unit_name = "surgery tool" export_types = list(/obj/item/retractor, /obj/item/hemostat, /obj/item/cautery, /obj/item/surgicaldrill, /obj/item/scalpel, /obj/item/circular_saw, /obj/item/bonesetter, /obj/item/surgical_drapes) diff --git a/code/modules/cargo/exports/parts.dm b/code/modules/cargo/exports/parts.dm index da3c0cf31d..3e52780d44 100644 --- a/code/modules/cargo/exports/parts.dm +++ b/code/modules/cargo/exports/parts.dm @@ -102,6 +102,7 @@ export_types = list(/obj/item/stock_parts/cell/high/slime/hypercharged) //Glass working stuff +// i'd just like to say how i despise the previous coder's fetish for their funny glasswork /datum/export/glasswork_dish cost = 300 diff --git a/code/modules/cargo/exports/sheets.dm b/code/modules/cargo/exports/sheets.dm index a562210164..b0676fbde2 100644 --- a/code/modules/cargo/exports/sheets.dm +++ b/code/modules/cargo/exports/sheets.dm @@ -138,11 +138,11 @@ message = "of bones" export_types = list(/obj/item/stack/sheet/bone) -/datum/export/stack/bronze +/datum/export/stack/sheet/bronze unit_name = "tiles" cost = 5 message = "of brozne" - export_types = list(/obj/item/stack/tile/bronze) + export_types = list(/obj/item/stack/sheet/bronze) /datum/export/stack/brass unit_name = "tiles" diff --git a/code/modules/cargo/exports/weapons.dm b/code/modules/cargo/exports/weapons.dm index 983348a358..dc2703c146 100644 --- a/code/modules/cargo/exports/weapons.dm +++ b/code/modules/cargo/exports/weapons.dm @@ -5,7 +5,7 @@ /datum/export/weapon/makeshift_shield cost = 30 - unit_name = "unknown shield" + unit_name = "nonstandard shield" export_types = list(/obj/item/shield/riot, /obj/item/shield/riot/roman, /obj/item/shield/riot/buckler, /obj/item/shield/makeshift) /datum/export/weapon/riot_shield @@ -37,7 +37,7 @@ /datum/export/weapon/taser cost = 200 - unit_name = "advanced taser" + unit_name = "hybrid taser" export_types = list(/obj/item/gun/energy/e_gun/advtaser) /datum/export/weapon/laser @@ -104,12 +104,12 @@ /datum/export/weapon/aeg cost = 200 //Endless power - unit_name = "advance engery gun" + unit_name = "advanced energy gun" export_types = list(/obj/item/gun/energy/e_gun/nuclear) /datum/export/weapon/deconer cost = 600 - unit_name = "deconer" + unit_name = "decloner" export_types = list(/obj/item/gun/energy/decloner) /datum/export/weapon/ntsniper @@ -123,9 +123,8 @@ export_types = list(/obj/item/gun/syringe/rapidsyringe) /datum/export/weapon/temp_gun - cost = 175 //Its just smaller + cost = 175 unit_name = "small temperature gun" - k_elasticity = 1/30 //Its just a smaller temperature gun, easy to mass make export_types = list(/obj/item/gun/energy/temperature) /datum/export/weapon/flowergun @@ -139,8 +138,7 @@ export_types = list(/obj/item/gun/energy/xray) /datum/export/weapon/ioncarbine - cost = 200 - k_elasticity = 1/30 //Its just a smaller temperature gun, easy to mass make + cost = 200 unit_name = "ion carbine" export_types = list(/obj/item/gun/energy/ionrifle/carbine) @@ -194,7 +192,7 @@ export_types = list(/obj/item/firing_pin/test_range) /datum/export/weapon/techslug - cost = 25 + cost = 30 k_elasticity = 0 unit_name = "advanced shotgun shell" export_types = list(/obj/item/ammo_casing/shotgun/dragonsbreath, /obj/item/ammo_casing/shotgun/meteorslug, /obj/item/ammo_casing/shotgun/pulseslug, /obj/item/ammo_casing/shotgun/frag12, /obj/item/ammo_casing/shotgun/ion, /obj/item/ammo_casing/shotgun/laserslug) @@ -215,7 +213,7 @@ /datum/export/weapon/bow_teaching cost = 500 - unit_name = "stone tablets" + unit_name = "bowyery tablet" export_types = list(/obj/item/book/granter/crafting_recipe/bone_bow) /datum/export/weapon/quiver @@ -230,48 +228,48 @@ /datum/export/weapon/pistol cost = 120 - unit_name = "illegal firearm" + unit_name = "nonstandard sidearm" export_types = list(/obj/item/gun/ballistic/automatic/pistol) /datum/export/weapon/revolver cost = 200 - unit_name = "large handgun" + unit_name = "large-caliber revolver" export_types = list(/obj/item/gun/ballistic/revolver) exclude_types = list(/obj/item/gun/ballistic/revolver/russian, /obj/item/gun/ballistic/revolver/doublebarrel) /datum/export/weapon/rocketlauncher cost = 1000 - unit_name = "rocketlauncher" + unit_name = "PML-9 rocket-propelled grenade launcher" export_types = list(/obj/item/gun/ballistic/rocketlauncher) /datum/export/weapon/antitank cost = 300 - unit_name = "hand cannon" + unit_name = "anti-tank pistol" export_types = list(/obj/item/gun/ballistic/automatic/pistol/antitank/syndicate) /datum/export/weapon/clownstuff cost = 500 - unit_name = "clown war tech" - export_types = list(/obj/item/pneumatic_cannon/pie/selfcharge, /obj/item/shield/energy/bananium, /obj/item/melee/transforming/energy/sword/bananium, ) + unit_name = "clown combat equipment" + export_types = list(/obj/item/pneumatic_cannon/pie/selfcharge, /obj/item/shield/energy/bananium, /obj/item/melee/transforming/energy/sword/bananium) /datum/export/weapon/bulldog cost = 400 - unit_name = "drum loaded shotgun" + unit_name = "drum-fed compact combat shotgun" export_types = list(/obj/item/gun/ballistic/automatic/shotgun/bulldog) /datum/export/weapon/smg cost = 350 - unit_name = "automatic c-20r" + unit_name = "C-20r sub-machine gun" export_types = list(/obj/item/gun/ballistic/automatic/c20r) /datum/export/weapon/duelsaber - cost = 360 //Get it? - unit_name = "energy saber" + cost = 360 + unit_name = "double-bladed energy saber" export_types = list(/obj/item/dualsaber) /datum/export/weapon/esword cost = 130 - unit_name = "energy sword" + unit_name = "energy saber" export_types = list(/obj/item/melee/transforming/energy/sword/cx/traitor, /obj/item/melee/transforming/energy/sword/saber) /datum/export/weapon/rapier @@ -286,32 +284,32 @@ /datum/export/weapon/gloves cost = 90 - unit_name = "star struck gloves" + unit_name = "anomalous armwraps" export_types = list(/obj/item/clothing/gloves/fingerless/pugilist/rapid) /datum/export/weapon/l6 cost = 500 - unit_name = "law 6 saw" + unit_name = "Aussec Armory L6 SAW" export_types = list(/obj/item/gun/ballistic/automatic/l6_saw) /datum/export/weapon/m90 cost = 400 - unit_name = "assault class weapon" + unit_name = "M90-gl carbine" export_types = list(/obj/item/gun/ballistic/automatic/m90) /datum/export/weapon/powerglove cost = 100 - unit_name = "hydraulic glove" + unit_name = "pneumatic gauntlet" export_types = list(/obj/item/melee/powerfist) /datum/export/weapon/sniper cost = 750 - unit_name = ".50 sniper" + unit_name = "anti-materiel rifle" export_types = list(/obj/item/gun/ballistic/automatic/sniper_rifle/syndicate) /datum/export/weapon/ebow cost = 600 - unit_name = "mini crossbow" + unit_name = "compact energy crossbow" export_types = list(/obj/item/gun/energy/kinetic_accelerator/crossbow) /datum/export/weapon/m10mm @@ -333,12 +331,12 @@ /datum/export/weapon/smg_mag cost = 45 - unit_name = "smg magazine" + unit_name = "SMG/carbine magazine" export_types = list(/obj/item/ammo_box/magazine/smgm45, /obj/item/ammo_box/magazine/m556) /datum/export/weapon/l6sawammo cost = 60 - unit_name = "law 6 saw ammo box" + unit_name = "L6 SAW ammo box" export_types = list(/obj/item/ammo_box/magazine/mm195x129) include_subtypes = TRUE @@ -355,13 +353,13 @@ /datum/export/weapon/fletcher_ammo cost = 60 - unit_name = "illegal ammo magazines" + unit_name = "flechette launcher magazine" export_types = list(/obj/item/ammo_box/magazine/flechette) include_subtypes = TRUE /datum/export/weapon/dj_a_pizzabomb cost = -6000 - unit_name = "Repair Costs" + unit_name = "undeclared ordinance and subsequent repair costs" export_types = list(/obj/item/pizzabox/bomb, /obj/item/sbeacondrop/bomb) /datum/export/weapon/real_toolbox @@ -371,12 +369,12 @@ /datum/export/weapon/melee cost = 50 - unit_name = "unlisted weapon" + unit_name = "any other melee weapon" export_types = list(/obj/item/melee) include_subtypes = TRUE /datum/export/weapon/gun cost = 50 - unit_name = "unlisted weapon" + unit_name = "any other weapon" export_types = list(/obj/item/gun) include_subtypes = TRUE diff --git a/code/modules/cargo/expressconsole.dm b/code/modules/cargo/expressconsole.dm index dc7e4b5a06..4ca97a13a5 100644 --- a/code/modules/cargo/expressconsole.dm +++ b/code/modules/cargo/expressconsole.dm @@ -1,5 +1,5 @@ #define MAX_EMAG_ROCKETS 8 -#define BEACON_COST 5000 +#define BEACON_COST 500 #define SP_LINKED 1 #define SP_READY 2 #define SP_LAUNCH 3 @@ -13,10 +13,9 @@ All sales are near instantaneous - please choose carefully" icon_screen = "supply_express" circuit = /obj/item/circuitboard/computer/cargo/express - ui_x = 600 - ui_y = 700 blockade_warning = "Bluespace instability detected. Delivery impossible." req_access = list(ACCESS_QM) + var/message var/printed_beacons = 0 //number of beacons printed. Used to determine beacon names. var/list/meme_pack_data @@ -42,7 +41,7 @@ to_chat(user, "You [locked ? "lock" : "unlock"] the interface.") return else if(istype(W, /obj/item/disk/cargo/bluespace_pod)) - podType = /obj/structure/closet/supplypod/bluespacepod + podType = /obj/structure/closet/supplypod/bluespacepod //doesnt effect circuit board, making reversal possible to_chat(user, "You insert the disk into [src], allowing for advanced supply delivery vehicles.") qdel(W) return TRUE @@ -52,22 +51,20 @@ sb.link_console(src, user) return TRUE else - to_chat(user, "[src] is already linked to [sb].") + to_chat(user, "[src] is already linked to [sb].") ..() /obj/machinery/computer/cargo/express/emag_act(mob/living/user) - . = SEND_SIGNAL(src, COMSIG_ATOM_EMAG_ACT) if(obj_flags & EMAGGED) return - user.visible_message("[user] swipes a suspicious card through [src]!", - "You change the routing protocols, allowing the Supply Pod to land anywhere on the station.") + if(user) + user.visible_message("[user] swipes a suspicious card through [src]!", + "You change the routing protocols, allowing the Supply Pod to land anywhere on the station.") obj_flags |= EMAGGED // This also sets this on the circuit board var/obj/item/circuitboard/computer/cargo/board = circuit board.obj_flags |= EMAGGED packin_up() - req_access = list() - return TRUE /obj/machinery/computer/cargo/express/proc/packin_up() // oh shit, I'm sorry meme_pack_data = list() // sorry for what? @@ -89,10 +86,10 @@ "desc" = P.desc || P.name // If there is a description, use it. Otherwise use the pack's name. )) -/obj/machinery/computer/cargo/express/ui_interact(mob/living/user, ui_key = "main", datum/tgui/ui = null, force_open = 0, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) // Remember to use the appropriate state. - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) +/obj/machinery/computer/cargo/express/ui_interact(mob/living/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) if(!ui) - ui = new(user, src, ui_key, "CargoExpress", name, ui_x, ui_y, master_ui, state) + ui = new(user, src, "CargoExpress", name) ui.open() /obj/machinery/computer/cargo/express/ui_data(mob/user) @@ -131,9 +128,6 @@ return data /obj/machinery/computer/cargo/express/ui_act(action, params, datum/tgui/ui) - if(!allowed(usr)) - to_chat(usr, "Access denied.") - return switch(action) if("LZCargo") usingBeacon = FALSE @@ -153,6 +147,7 @@ printed_beacons++//printed_beacons starts at 0, so the first one out will be called beacon # 1 beacon.name = "Supply Pod Beacon #[printed_beacons]" + if("add")//Generate Supply Order first var/id = text2path(params["id"]) var/datum/supply_pack/pack = SSshuttle.supply_packs[id] @@ -195,7 +190,6 @@ LZ = pick(empty_turfs) if (SO.pack.cost <= points_to_check && LZ)//we need to call the cost check again because of the CHECK_TICK call D.adjust_money(-SO.pack.cost) - SSblackbox.record_feedback("nested tally", "cargo_imports", 1, list("[SO.pack.cost]", "[SO.pack.name]")) new /obj/effect/abstract/DPtarget(LZ, podType, SO) . = TRUE update_icon() @@ -209,7 +203,7 @@ CHECK_TICK if(empty_turfs && empty_turfs.len) D.adjust_money(-(SO.pack.cost * (0.72*MAX_EMAG_ROCKETS))) - SSblackbox.record_feedback("nested tally", "cargo_imports", MAX_EMAG_ROCKETS, list("[SO.pack.cost * 0.72]", "[SO.pack.name]")) + SO.generateRequisition(get_turf(src)) for(var/i in 1 to MAX_EMAG_ROCKETS) var/LZ = pick(empty_turfs) diff --git a/code/modules/cargo/packs/armory.dm b/code/modules/cargo/packs/armory.dm index 835457536f..9f8bb2f25f 100644 --- a/code/modules/cargo/packs/armory.dm +++ b/code/modules/cargo/packs/armory.dm @@ -158,11 +158,10 @@ /datum/supply_pack/security/armory/russian name = "Russian Surplus Crate" - desc = "Hello Comrade, we have the most modern russian military equipment the black market can offer, for the right price of course. Sadly we couldnt remove the lock so it requires Armory access to open." + desc = "Hello Comrade, we have the most modern Russian military equipment the black market can offer, for the right price of course. Sadly we couldn't remove the lock so it requires Armory access to open." cost = 7500 contraband = TRUE contains = list(/obj/item/reagent_containers/food/snacks/rationpack, - /obj/item/ammo_box/magazine/m10mm/rifle, /obj/item/clothing/suit/armor/vest/russian, /obj/item/clothing/head/helmet/rus_helmet, /obj/item/clothing/shoes/russian, @@ -172,7 +171,10 @@ /obj/item/clothing/mask/russian_balaclava, /obj/item/clothing/head/helmet/rus_ushanka, /obj/item/clothing/suit/armor/vest/russian_coat, - /obj/item/gun/ballistic/automatic/surplus) + /obj/effect/spawner/bundle/crate/mosin, + /obj/item/storage/toolbox/ammo, + /obj/effect/spawner/bundle/crate/surplusrifle, + /obj/item/storage/toolbox/ammo/surplus) crate_name = "surplus military crate" /datum/supply_pack/security/armory/russian/fill(obj/structure/closet/crate/C) @@ -223,3 +225,10 @@ /obj/item/ammo_box/magazine/wt550m9/wtrubber, /obj/item/ammo_box/magazine/wt550m9/wtrubber) crate_name = "auto rifle ammo crate" + +/datum/supply_pack/security/armory/hell_single + name = "Hellgun Single-Pack" + crate_name = "hellgun crate" + desc = "Contains one hellgun, an old pattern of laser gun infamous for its ability to horribly disfigure targets with burns. Technically violates the Space Geneva Convention when used on humanoids." + cost = 1500 + contains = list(/obj/item/gun/energy/laser/hellgun) diff --git a/code/modules/cargo/packs/goodies.dm b/code/modules/cargo/packs/goodies.dm index 86a7c73a34..5d07e85bac 100644 --- a/code/modules/cargo/packs/goodies.dm +++ b/code/modules/cargo/packs/goodies.dm @@ -76,12 +76,6 @@ cost = 200 contains = list(/obj/item/toy/beach_ball) -/datum/supply_pack/goody/hell_single - name = "Hellgun Single-Pack" - desc = "Contains one hellgun, an old pattern of laser gun infamous for its ability to horribly disfigure targets with burns. Technically violates the Space Geneva Convention when used on humanoids." - cost = 1500 - contains = list(/obj/item/gun/energy/laser/hellgun) - /datum/supply_pack/goody/medipen_twopak name = "Medipen Two-Pak" desc = "Contains one standard epinephrine medipen and one standard emergency first-aid kit medipen. For when you want to prepare for the worst." diff --git a/code/modules/cargo/packs/misc.dm b/code/modules/cargo/packs/misc.dm index a84e22f6f9..c6728831eb 100644 --- a/code/modules/cargo/packs/misc.dm +++ b/code/modules/cargo/packs/misc.dm @@ -194,9 +194,9 @@ /datum/supply_pack/misc/dirtymags name = "Dirty Magazines" - desc = "Get your mind out of the gutter operative, you have work to do. Three items per order. Possible Results: .357 Speedloaders, Kitchen Gun Mags, Stetchkin Mags." + desc = "Get your mind out of the gutter operative, you have work to do. Three items per order. Possible Results: .357 Speedloaders, Kitchen Gun patented magazines, or Stetchkin magazines." hidden = TRUE - cost = 12000 + cost = 4000 var/num_contained = 3 contains = list(/obj/item/ammo_box/a357, /obj/item/ammo_box/magazine/pistolm9mm, @@ -415,21 +415,10 @@ /obj/item/restraints/handcuffs/fake/kinky, /obj/item/clothing/head/kitty/genuine, // Why its illegal /obj/item/clothing/head/kitty/genuine, - /obj/item/storage/pill_bottle/penis_enlargement, - /obj/structure/reagent_dispensers/keg/aphro) + /obj/item/storage/pill_bottle/penis_enlargement) crate_name = "lewd kit" crate_type = /obj/structure/closet/crate -/datum/supply_pack/misc/lewdkeg - name = "Lewd Deluxe Keg" - desc = "That other stuff not getting you ready? Well I have a Chemslut making tons of the good stuff." - cost = 7500 //It can be a weapon - contraband = TRUE - contains = list(/obj/structure/reagent_dispensers/keg/aphro/strong) - crate_name = "deluxe keg" - crate_type = /obj/structure/closet/crate - - ///Special supply crate that generates random syndicate gear up to a determined TC value /datum/supply_pack/misc/syndicate @@ -466,4 +455,4 @@ if(crate_value < I.cost) continue crate_value -= I.cost - new I.item(C) \ No newline at end of file + new I.item(C) diff --git a/code/modules/cargo/packs/security.dm b/code/modules/cargo/packs/security.dm index 738eb03fbf..cf9cc5e0d1 100644 --- a/code/modules/cargo/packs/security.dm +++ b/code/modules/cargo/packs/security.dm @@ -100,7 +100,7 @@ crate_name = "surplus russian clothing" crate_type = /obj/structure/closet/crate/internals -/datum/supply_pack/security/russianmosin +/datum/supply_pack/security/russian_partisan name = "Russian Partisan Gear" desc = "An old russian partisan equipment crate, comes with a full russian outfit, a loaded surplus rifle and a second magazine." contraband = TRUE @@ -112,12 +112,17 @@ /obj/item/clothing/suit/armor/bulletproof, /obj/item/clothing/head/helmet/alt, /obj/item/clothing/gloves/tackler/combat/insulated, - /obj/item/clothing/mask/gas, - /obj/item/ammo_box/magazine/m10mm/rifle, - /obj/item/gun/ballistic/automatic/surplus) + /obj/item/clothing/mask/gas) crate_name = "surplus russian gear" crate_type = /obj/structure/closet/crate/internals +/datum/supply_pack/security/russian_partisan/fill(obj/structure/closet/crate/C) + ..() + if(prob(20)) + new /obj/effect/spawner/bundle/crate/mosin(C) + else + new /obj/effect/spawner/bundle/crate/surplusrifle(C) + /datum/supply_pack/security/sechardsuit name = "Sec Hardsuit" desc = "One Sec Hardsuit with a small air tank and mask." diff --git a/code/modules/client/client_procs.dm b/code/modules/client/client_procs.dm index 5c9b1eec2e..e7aa447840 100644 --- a/code/modules/client/client_procs.dm +++ b/code/modules/client/client_procs.dm @@ -41,6 +41,7 @@ GLOBAL_LIST_INIT(blacklisted_builds, list( if(!asset_cache_job) return + // Rate limiting var/mtl = CONFIG_GET(number/minute_topic_limit) if (!holder && mtl) var/minute = round(world.time, 600) @@ -98,6 +99,10 @@ GLOBAL_LIST_INIT(blacklisted_builds, list( keyUp(keycode) return + // Tgui Topic middleware + if(!tgui_Topic(href_list)) + return + // Admin PM if(href_list["priv_msg"]) cmd_admin_pm(href_list["priv_msg"],null) @@ -988,3 +993,6 @@ GLOBAL_LIST_EMPTY(external_rsc_urls) screen -= S qdel(S) char_render_holders = null + +/client/proc/can_have_part(part_name) + return prefs.pref_species.mutant_bodyparts[part_name] || (part_name in GLOB.unlocked_mutant_parts) diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm index 3c9697c03a..480ebda4f8 100644 --- a/code/modules/client/preferences.dm +++ b/code/modules/client/preferences.dm @@ -229,7 +229,8 @@ GLOBAL_LIST_EMPTY(preferences_datums) var/gear_points = 10 var/list/gear_categories var/list/chosen_gear = list() - var/gear_tab + var/gear_category + var/gear_subcategory var/screenshake = 100 var/damagescreenshake = 2 @@ -506,310 +507,19 @@ GLOBAL_LIST_EMPTY(preferences_datums) dat += "" mutant_category = 0 - if(pref_species.mutant_bodyparts["tail_lizard"]) - if(!mutant_category) - dat += APPEARANCE_CATEGORY_COLUMN - - dat += "

Tail

" - - dat += "[features["tail_lizard"]]" - - mutant_category++ - if(mutant_category >= MAX_MUTANT_ROWS) - dat += "" - mutant_category = 0 - - if(pref_species.mutant_bodyparts["mam_tail"]) - if(!mutant_category) - dat += APPEARANCE_CATEGORY_COLUMN - - dat += "

Tail

" - - dat += "[features["mam_tail"]]" - - mutant_category++ - if(mutant_category >= MAX_MUTANT_ROWS) - dat += "" - mutant_category = 0 - if(pref_species.mutant_bodyparts["tail_human"]) - if(!mutant_category) - dat += APPEARANCE_CATEGORY_COLUMN - - dat += "

Tail

" - - dat += "[features["tail_human"]]" - - mutant_category++ - if(mutant_category >= MAX_MUTANT_ROWS) - dat += "" - mutant_category = 0 - - if(pref_species.mutant_bodyparts["meat_type"]) - if(!mutant_category) - dat += APPEARANCE_CATEGORY_COLUMN - - dat += "

Meat Type

" - - dat += "[features["meat_type"]]" - - mutant_category++ - if(mutant_category >= MAX_MUTANT_ROWS) - dat += "" - mutant_category = 0 - if(pref_species.mutant_bodyparts["snout"]) - if(!mutant_category) - dat += APPEARANCE_CATEGORY_COLUMN - - dat += "

Snout

" - - dat += "[features["snout"]]" - - mutant_category++ - if(mutant_category >= MAX_MUTANT_ROWS) - dat += "" - mutant_category = 0 - if(pref_species.mutant_bodyparts["horns"]) - if(!mutant_category) - dat += APPEARANCE_CATEGORY_COLUMN - - dat += "

Horns

" - - dat += "[features["horns"]]" - dat += "    Change
" - - - mutant_category++ - if(mutant_category >= MAX_MUTANT_ROWS) - dat += "" - if(pref_species.mutant_bodyparts["frills"]) - if(!mutant_category) - dat += APPEARANCE_CATEGORY_COLUMN - - dat += "

Frills

" - - dat += "[features["frills"]]" - - mutant_category++ - if(mutant_category >= MAX_MUTANT_ROWS) - dat += "" - mutant_category = 0 - - if(pref_species.mutant_bodyparts["spines"]) - if(!mutant_category) - dat += APPEARANCE_CATEGORY_COLUMN - - dat += "

Spines

" - - dat += "[features["spines"]]" - - mutant_category++ - if(mutant_category >= MAX_MUTANT_ROWS) - dat += "" - mutant_category = 0 - - if(pref_species.mutant_bodyparts["body_markings"]) - if(!mutant_category) - dat += APPEARANCE_CATEGORY_COLUMN - - dat += "

Body Markings

" - - dat += "[features["body_markings"]]" - - mutant_category++ - if(mutant_category >= MAX_MUTANT_ROWS) - dat += "" - mutant_category = 0 - if(pref_species.mutant_bodyparts["mam_body_markings"]) - if(!mutant_category) - dat += APPEARANCE_CATEGORY_COLUMN - - dat += "

Species Markings

" - - dat += "[features["mam_body_markings"]]" - - mutant_category++ - if(mutant_category >= MAX_MUTANT_ROWS) - dat += "" - - if(pref_species.mutant_bodyparts["mam_ears"]) - if(!mutant_category) - dat += APPEARANCE_CATEGORY_COLUMN - - dat += "

Ears

" - - dat += "[features["mam_ears"]]" - - mutant_category++ - if(mutant_category >= MAX_MUTANT_ROWS) - dat += "" - mutant_category = 0 - - if(pref_species.mutant_bodyparts["ears"]) - if(!mutant_category) - dat += APPEARANCE_CATEGORY_COLUMN - - dat += "

Ears

" - - dat += "[features["ears"]]" - - mutant_category++ - if(mutant_category >= MAX_MUTANT_ROWS) - dat += "" - mutant_category = 0 - - if(pref_species.mutant_bodyparts["mam_snouts"]) - if(!mutant_category) - dat += APPEARANCE_CATEGORY_COLUMN - - dat += "

Snout

" - - dat += "[features["mam_snouts"]]" - - mutant_category++ - if(mutant_category >= MAX_MUTANT_ROWS) - dat += "" - mutant_category = 0 - if(pref_species.mutant_bodyparts["legs"]) - if(!mutant_category) - dat += APPEARANCE_CATEGORY_COLUMN - - dat += "

Legs

" - - dat += "[features["legs"]]" - - mutant_category++ - if(mutant_category >= MAX_MUTANT_ROWS) - dat += "" - mutant_category = 0 - if(pref_species.mutant_bodyparts["deco_wings"]) - if(!mutant_category) - dat += APPEARANCE_CATEGORY_COLUMN - - dat += "

Decorative wings

" - - dat += "[features["deco_wings"]]" - dat += "    Change
" - - if(pref_species.mutant_bodyparts["insect_wings"]) - if(!mutant_category) - dat += APPEARANCE_CATEGORY_COLUMN - - dat += "

Insect wings

" - - dat += "[features["insect_wings"]]" - dat += "    Change
" - mutant_category++ - if(mutant_category >= MAX_MUTANT_ROWS) - dat += "" - mutant_category = 0 - if(pref_species.mutant_bodyparts["insect_fluff"]) - if(!mutant_category) - dat += APPEARANCE_CATEGORY_COLUMN - - dat += "

Insect Fluff

" - - dat += "[features["insect_fluff"]]" - mutant_category++ - if(mutant_category >= MAX_MUTANT_ROWS) - dat += "" - mutant_category = 0 - if(pref_species.mutant_bodyparts["taur"]) - if(!mutant_category) - dat += APPEARANCE_CATEGORY_COLUMN - - dat += "

Tauric Body

" - - dat += "[features["taur"]]" - - if(pref_species.mutant_bodyparts["insect_markings"]) - if(!mutant_category) - dat += APPEARANCE_CATEGORY_COLUMN - - dat += "

Insect markings

" - - dat += "[features["insect_markings"]]
" - - mutant_category++ - if(mutant_category >= MAX_MUTANT_ROWS) - dat += "" - mutant_category = 0 - - mutant_category++ - if(mutant_category >= MAX_MUTANT_ROWS) - dat += "" - mutant_category = 0 - if(pref_species.mutant_bodyparts["wings"] && GLOB.r_wings_list.len >1) - if(!mutant_category) - dat += APPEARANCE_CATEGORY_COLUMN - - dat += "

Wings

" - - dat += "[features["wings"]]" - - mutant_category++ - if(mutant_category >= MAX_MUTANT_ROWS) - dat += "" - mutant_category = 0 - if(pref_species.mutant_bodyparts["xenohead"]) - if(!mutant_category) - dat += APPEARANCE_CATEGORY_COLUMN - - dat += "

Caste Head

" - - dat += "[features["xenohead"]]" - - mutant_category++ - if(mutant_category >= MAX_MUTANT_ROWS) - dat += "" - mutant_category = 0 - if(pref_species.mutant_bodyparts["xenotail"]) - if(!mutant_category) - dat += APPEARANCE_CATEGORY_COLUMN - - dat += "

Tail

" - - dat += "[features["xenotail"]]" - - mutant_category++ - if(mutant_category >= MAX_MUTANT_ROWS) - dat += "" - mutant_category = 0 - if(pref_species.mutant_bodyparts["xenodorsal"]) - if(!mutant_category) - dat += APPEARANCE_CATEGORY_COLUMN - - dat += "

Dorsal Spines

" - - dat += "[features["xenodorsal"]]" - - mutant_category++ - if(mutant_category >= MAX_MUTANT_ROWS) - dat += "" - mutant_category = 0 - if(pref_species.mutant_bodyparts["ipc_screen"]) - if(!mutant_category) - dat += APPEARANCE_CATEGORY_COLUMN - - dat += "

Screen

" - - dat += "[features["ipc_screen"]]" - - mutant_category++ - if(mutant_category >= MAX_MUTANT_ROWS) - dat += "" - mutant_category = 0 - if(pref_species.mutant_bodyparts["ipc_antenna"]) - if(!mutant_category) - dat += APPEARANCE_CATEGORY_COLUMN - - dat += "

Antenna

" - - dat += "[features["ipc_antenna"]]" - - mutant_category++ - if(mutant_category >= MAX_MUTANT_ROWS) - dat += "" - mutant_category = 0 + for(var/mutant_part in GLOB.all_mutant_parts) + if(parent.can_have_part(mutant_part)) + if(!mutant_category) + dat += APPEARANCE_CATEGORY_COLUMN + dat += "

[GLOB.all_mutant_parts[mutant_part]]

" + dat += "[features[mutant_part]]" + var/color_type = GLOB.colored_mutant_parts[mutant_part] //if it can be coloured, show the appropriate button + if(color_type) + dat += "    Change
" + mutant_category++ + if(mutant_category >= MAX_MUTANT_ROWS) + dat += "" + mutant_category = 0 if(mutant_category) dat += "" @@ -855,7 +565,7 @@ GLOBAL_LIST_EMPTY(preferences_datums) var/tauric_shape = FALSE if(features["cock_taur"]) var/datum/sprite_accessory/penis/P = GLOB.cock_shapes_list[features["cock_shape"]] - if(P.taur_icon && pref_species.mutant_bodyparts["taur"]) + if(P.taur_icon && parent.can_have_part("taur")) var/datum/sprite_accessory/taur/T = GLOB.taur_list[features["taur"]] if(T.taur_mode & P.accepted_taurs) tauric_shape = TRUE @@ -1058,60 +768,83 @@ GLOBAL_LIST_EMPTY(preferences_datums) dat += "
" if(3) - if(!gear_tab) - gear_tab = GLOB.loadout_items[1] dat += "" dat += "" dat += "" dat += "" - dat += "" - dat += "" - dat += "" - dat += "" - dat += "" - dat += "" - dat += "" - for(var/j in GLOB.loadout_items[gear_tab]) - var/datum/gear/gear = GLOB.loadout_items[gear_tab][j] - var/donoritem = gear.donoritem - if(donoritem && !gear.donator_ckey_check(user.ckey)) - continue - var/class_link = "" - if(gear.type in chosen_gear) - class_link = "style='white-space:normal;' class='linkOn' href='?_src_=prefs;preference=gear;toggle_gear_path=[html_encode(j)];toggle_gear=0'" - else if(gear_points <= 0) - class_link = "style='white-space:normal;' class='linkOff'" - else if(donoritem) - class_link = "style='white-space:normal;background:#ebc42e;' href='?_src_=prefs;preference=gear;toggle_gear_path=[html_encode(j)];toggle_gear=1'" + dat += "" + dat += "" + + dat += "" - dat += "" - dat += "
[gear_points] loadout points remaining. \[Clear Loadout\]
You can only choose one item per category, unless it's an item that spawns in your backpack or hands.
" - var/firstcat = TRUE - for(var/i in GLOB.loadout_items) - if(firstcat) - firstcat = FALSE - else - dat += " |" - if(i == gear_tab) - dat += " [i] " - else - dat += " [i] " + if(!length(GLOB.loadout_items)) + dat += "
ERROR: No loadout categories - something is horribly wrong!" + else + if(!GLOB.loadout_categories[gear_category]) + gear_category = GLOB.loadout_categories[1] + var/firstcat = TRUE + for(var/category in GLOB.loadout_categories) + if(firstcat) + firstcat = FALSE + else + dat += " |" + if(category == gear_category) + dat += " [category] " + else + dat += " [category] " - dat += "

[gear_tab]

NameCostRestrictionsDescription

" + + if(!length(GLOB.loadout_categories[gear_category])) + dat += "No subcategories detected. Something is horribly wrong!" else - class_link = "style='white-space:normal;' href='?_src_=prefs;preference=gear;toggle_gear_path=[html_encode(j)];toggle_gear=1'" - dat += "
[j][gear.cost]" - if(islist(gear.restricted_roles)) - if(gear.restricted_roles.len) - if(gear.restricted_desc) - dat += "" - dat += gear.restricted_desc - dat += "" + var/list/subcategories = GLOB.loadout_categories[gear_category] + if(!subcategories.Find(gear_subcategory)) + gear_subcategory = subcategories[1] + + var/firstsubcat = FALSE + for(var/subcategory in subcategories) + if(firstsubcat) + firstsubcat = FALSE else - dat += "" - dat += gear.restricted_roles.Join(";") - dat += "" - dat += "[gear.description]
" + dat += " |" + if(gear_subcategory == subcategory) + dat += " [subcategory] " + else + dat += " [subcategory] " + dat += "
" + + dat += "Name" + dat += "Cost" + dat += "Restrictions" + dat += "Description" + for(var/name in GLOB.loadout_items[gear_category][gear_subcategory]) + var/datum/gear/gear = GLOB.loadout_items[gear_category][gear_subcategory][name] + var/donoritem = gear.donoritem + if(donoritem && !gear.donator_ckey_check(user.ckey)) + continue + var/class_link = "" + if(gear.type in chosen_gear) + class_link = "style='white-space:normal;' class='linkOn' href='?_src_=prefs;preference=gear;toggle_gear_path=[html_encode(name)];toggle_gear=0'" + else if(gear_points <= 0) + class_link = "style='white-space:normal;' class='linkOff'" + else if(donoritem) + class_link = "style='white-space:normal;background:#ebc42e;' href='?_src_=prefs;preference=gear;toggle_gear_path=[html_encode(name)];toggle_gear=1'" + else + class_link = "style='white-space:normal;' href='?_src_=prefs;preference=gear;toggle_gear_path=[html_encode(name)];toggle_gear=1'" + dat += "[name]" + dat += "[gear.cost]" + if(islist(gear.restricted_roles)) + if(gear.restricted_roles.len) + if(gear.restricted_desc) + dat += "" + dat += gear.restricted_desc + dat += "" + else + dat += "" + dat += gear.restricted_roles.Join(";") + dat += "" + dat += "[gear.description]" + dat += "" if(4) // Content preferences dat += "
" dat += "

Fetish content prefs

" @@ -1129,7 +862,6 @@ GLOBAL_LIST_EMPTY(preferences_datums) dat += "Breast Enlargement: [(cit_toggles & BREAST_ENLARGEMENT) ? "Allowed" : "Disallowed"]
" dat += "Penis Enlargement: [(cit_toggles & PENIS_ENLARGEMENT) ? "Allowed" : "Disallowed"]
" dat += "Hypno: [(cit_toggles & NEVER_HYPNO) ? "Disallowed" : "Allowed"]
" - dat += "Aphrodisiacs: [(cit_toggles & NO_APHRO) ? "Disallowed" : "Allowed"]
" dat += "Ass Slapping: [(cit_toggles & NO_ASS_SLAP) ? "Disallowed" : "Allowed"]
" dat += "Automatic Wagging: [(cit_toggles & NO_AUTO_WAG) ? "Disabled" : "Enabled"]
" dat += "
" @@ -1785,14 +1517,14 @@ GLOBAL_LIST_EMPTY(preferences_datums) pref_species = new newtype() //let's ensure that no weird shit happens on species swapping. custom_species = null - if(!pref_species.mutant_bodyparts["body_markings"]) + if(!parent.can_have_part("body_markings")) features["body_markings"] = "None" - if(!pref_species.mutant_bodyparts["mam_body_markings"]) + if(!parent.can_have_part("mam_body_markings")) features["mam_body_markings"] = "None" - if(pref_species.mutant_bodyparts["mam_body_markings"]) + if(parent.can_have_part("mam_body_markings")) if(features["mam_body_markings"] == "None") features["mam_body_markings"] = "Plain" - if(pref_species.mutant_bodyparts["tail_lizard"]) + if(parent.can_have_part("tail_lizard")) features["tail_lizard"] = "Smooth" if(pref_species.id == "felinid") features["mam_tail"] = "Cat" @@ -1904,7 +1636,7 @@ GLOBAL_LIST_EMPTY(preferences_datums) if("mam_tail") var/list/snowflake_tails_list = list() for(var/path in GLOB.mam_tails_list) - var/datum/sprite_accessory/mam_tails/instance = GLOB.mam_tails_list[path] + var/datum/sprite_accessory/tails/mam_tails/instance = GLOB.mam_tails_list[path] if(istype(instance, /datum/sprite_accessory)) var/datum/sprite_accessory/S = instance if(!show_mismatched_markings && S.recommended_species && !S.recommended_species.Find(pref_species.id)) @@ -1920,7 +1652,7 @@ GLOBAL_LIST_EMPTY(preferences_datums) features["tail_human"] = "None" features["tail_lizard"] = "None" - if("meats") + if("meat_type") var/new_meat new_meat = input(user, "Choose your character's meat type:", "Character Preference") as null|anything in GLOB.meat_types if(new_meat) @@ -1929,7 +1661,7 @@ GLOBAL_LIST_EMPTY(preferences_datums) if("snout") var/list/snowflake_snouts_list = list() for(var/path in GLOB.snouts_list) - var/datum/sprite_accessory/mam_snouts/instance = GLOB.snouts_list[path] + var/datum/sprite_accessory/snouts/mam_snouts/instance = GLOB.snouts_list[path] if(istype(instance, /datum/sprite_accessory)) var/datum/sprite_accessory/S = instance if(!show_mismatched_markings && S.recommended_species && !S.recommended_species.Find(pref_species.id)) @@ -1946,7 +1678,7 @@ GLOBAL_LIST_EMPTY(preferences_datums) if("mam_snouts") var/list/snowflake_mam_snouts_list = list() for(var/path in GLOB.mam_snouts_list) - var/datum/sprite_accessory/mam_snouts/instance = GLOB.mam_snouts_list[path] + var/datum/sprite_accessory/snouts/mam_snouts/instance = GLOB.mam_snouts_list[path] if(istype(instance, /datum/sprite_accessory)) var/datum/sprite_accessory/S = instance if(!show_mismatched_markings && S.recommended_species && !S.recommended_species.Find(pref_species.id)) @@ -2025,7 +1757,7 @@ GLOBAL_LIST_EMPTY(preferences_datums) if(new_deco_wings) features["deco_wings"] = new_deco_wings - if("insect_fluffs") + if("insect_fluff") var/new_insect_fluff new_insect_fluff = input(user, "Choose your character's wings:", "Character Preference") as null|anything in GLOB.insect_fluffs_list if(new_insect_fluff) @@ -2095,7 +1827,7 @@ GLOBAL_LIST_EMPTY(preferences_datums) if("mam_ears") var/list/snowflake_ears_list = list() for(var/path in GLOB.mam_ears_list) - var/datum/sprite_accessory/mam_ears/instance = GLOB.mam_ears_list[path] + var/datum/sprite_accessory/ears/mam_ears/instance = GLOB.mam_ears_list[path] if(istype(instance, /datum/sprite_accessory)) var/datum/sprite_accessory/S = instance if(!show_mismatched_markings && S.recommended_species && !S.recommended_species.Find(pref_species.id)) @@ -2173,7 +1905,7 @@ GLOBAL_LIST_EMPTY(preferences_datums) if("cock_shape") var/new_shape var/list/hockeys = list() - if(pref_species.mutant_bodyparts["taur"]) + if(parent.can_have_part("taur")) var/datum/sprite_accessory/taur/T = GLOB.taur_list[features["taur"]] for(var/A in GLOB.cock_shapes_list) var/datum/sprite_accessory/penis/P = GLOB.cock_shapes_list[A] @@ -2692,11 +2424,13 @@ GLOBAL_LIST_EMPTY(preferences_datums) gear_points = CONFIG_GET(number/initial_gear_points) save_preferences() if(href_list["select_category"]) - for(var/i in GLOB.loadout_items) - if(i == href_list["select_category"]) - gear_tab = i + gear_category = html_decode(href_list["select_category"]) + gear_subcategory = GLOB.loadout_categories[gear_category][1] + if(href_list["select_subcategory"]) + gear_subcategory = html_decode(href_list["select_subcategory"]) if(href_list["toggle_gear_path"]) - var/datum/gear/G = GLOB.loadout_items[gear_tab][html_decode(href_list["toggle_gear_path"])] + var/name = html_decode(href_list["toggle_gear_path"]) + var/datum/gear/G = GLOB.loadout_items[gear_category][gear_subcategory][name] if(!G) return var/toggle = text2num(href_list["toggle_gear"]) @@ -2780,10 +2514,10 @@ GLOBAL_LIST_EMPTY(preferences_datums) character.dna.nameless = character.nameless character.dna.custom_species = character.custom_species - if(pref_species.mutant_bodyparts["meat_type"]) + if((parent && parent.can_have_part("meat_type")) || pref_species.mutant_bodyparts["meat_type"]) character.type_of_meat = GLOB.meat_types[features["meat_type"]] - if(character.dna.species.mutant_bodyparts["legs"] && (character.dna.features["legs"] == "Digitigrade" || character.dna.features["legs"] == "Avian")) + if(((parent && parent.can_have_part("legs")) || pref_species.mutant_bodyparts["legs"]) && (character.dna.features["legs"] == "Digitigrade" || character.dna.features["legs"] == "Avian")) pref_species.species_traits |= DIGITIGRADE else pref_species.species_traits -= DIGITIGRADE @@ -2876,17 +2610,17 @@ GLOBAL_LIST_EMPTY(preferences_datums) LAZYINITLIST(L) for(var/i in chosen_gear) var/datum/gear/G = i - var/occupied_slots = L[slot_to_string(initial(G.category))] ? L[slot_to_string(initial(G.category))] + 1 : 1 - LAZYSET(L, slot_to_string(initial(G.category)), occupied_slots) + var/occupied_slots = L[initial(G.category)] ? L[initial(G.category)] + 1 : 1 + LAZYSET(L, initial(G.category), occupied_slots) switch(slot) if(SLOT_IN_BACKPACK) - if(L[slot_to_string(SLOT_IN_BACKPACK)] < BACKPACK_SLOT_AMT) + if(L[LOADOUT_CATEGORY_BACKPACK] < BACKPACK_SLOT_AMT) return TRUE if(SLOT_HANDS) - if(L[slot_to_string(SLOT_HANDS)] < HANDS_SLOT_AMT) + if(L[LOADOUT_CATEGORY_HANDS] < HANDS_SLOT_AMT) return TRUE else - if(L[slot_to_string(slot)] < DEFAULT_SLOT_AMT) + if(L[slot] < DEFAULT_SLOT_AMT) return TRUE #undef DEFAULT_SLOT_AMT diff --git a/code/modules/client/preferences_savefile.dm b/code/modules/client/preferences_savefile.dm index dffab645a4..a8183e4940 100644 --- a/code/modules/client/preferences_savefile.dm +++ b/code/modules/client/preferences_savefile.dm @@ -5,7 +5,7 @@ // You do not need to raise this if you are adding new values that have sane defaults. // Only raise this value when changing the meaning/format/name/layout of an existing value // where you would want the updater procs below to run -#define SAVEFILE_VERSION_MAX 33 +#define SAVEFILE_VERSION_MAX 35 /* SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Carn @@ -200,6 +200,10 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car features["silicon_flavor_text"] = html_encode(features["silicon_flavor_text"]) features["ooc_notes"] = html_encode(features["ooc_notes"]) + if(current_version < 35) + if(S["species"] == "lizard") + features["mam_snouts"] = features["snout"] + /datum/preferences/proc/load_path(ckey,filename="preferences.sav") if(!ckey) return diff --git a/code/modules/clothing/clothing.dm b/code/modules/clothing/clothing.dm index d540336b86..2fbe738acb 100644 --- a/code/modules/clothing/clothing.dm +++ b/code/modules/clothing/clothing.dm @@ -118,8 +118,7 @@ // Set the clothing's integrity back to 100%, remove all damage to bodyparts, and generally fix it up /obj/item/clothing/proc/repair(mob/user, params) - damaged_clothes = CLOTHING_PRISTINE - update_clothes_damaged_state(FALSE) + update_clothes_damaged_state(CLOTHING_PRISTINE) obj_integrity = max_integrity name = initial(name) // remove "tattered" or "shredded" if there's a prefix body_parts_covered = initial(body_parts_covered) @@ -196,7 +195,7 @@ if(3 to INFINITY) // take better care of your shit, dude name = "tattered [initial(name)]" - update_clothes_damaged_state() + update_clothes_damaged_state(CLOTHING_DAMAGED) /obj/item/clothing/Destroy() user_vars_remembered = null //Oh god somebody put REFERENCES in here? not to worry, we'll clean it up @@ -257,7 +256,7 @@ how_cool_are_your_threads += "Adding or removing items from [src] makes no noise.\n" how_cool_are_your_threads += "" . += how_cool_are_your_threads.Join() - + if(LAZYLEN(armor_list)) armor_list.Cut() if(armor.bio) @@ -346,10 +345,16 @@ var/mob/M = loc to_chat(M, "Your [name] starts to fall apart!") -/obj/item/clothing/proc/update_clothes_damaged_state(damaging = TRUE) - var/index = "[REF(initial(icon))]-[initial(icon_state)]" - var/static/list/damaged_clothes_icons = list() - if(damaging) +//This mostly exists so subtypes can call appriopriate update icon calls on the wearer. +/obj/item/clothing/proc/update_clothes_damaged_state(damaged_state = CLOTHING_DAMAGED) + damaged_clothes = damaged_state + update_icon() + +/obj/item/clothing/update_overlays() + . = ..() + if(damaged_clothes) + var/index = "[REF(initial(icon))]-[initial(icon_state)]" + var/static/list/damaged_clothes_icons = list() var/icon/damaged_clothes_icon = damaged_clothes_icons[index] if(!damaged_clothes_icon) damaged_clothes_icon = icon(initial(icon), initial(icon_state), , 1) //we only want to apply damaged effect to the initial icon_state for each object @@ -357,9 +362,7 @@ damaged_clothes_icon.Blend(icon('icons/effects/item_damage.dmi', "itemdamaged"), ICON_MULTIPLY) //adds damage effect and the remaining white areas become transparant damaged_clothes_icon = fcopy_rsc(damaged_clothes_icon) damaged_clothes_icons[index] = damaged_clothes_icon - add_overlay(damaged_clothes_icon, TRUE) - else - cut_overlay(damaged_clothes_icons[index], TRUE) + . += damaged_clothes_icon /* SEE_SELF // can see self, no matter what diff --git a/code/modules/clothing/glasses/_glasses.dm b/code/modules/clothing/glasses/_glasses.dm index 350a577fb1..3f6d21bcd2 100644 --- a/code/modules/clothing/glasses/_glasses.dm +++ b/code/modules/clothing/glasses/_glasses.dm @@ -149,6 +149,30 @@ icon_state = "eyepatch" item_state = "eyepatch" +/obj/item/clothing/glasses/eyepatch/syndicate + name = "cybernetic eyepatch" + desc = "An eyepatch used to enhance one's aim with guns." + icon_state = "syndicatepatch" + item_state = "syndicatepatch" + resistance_flags = ACID_PROOF + +/obj/item/clothing/glasses/eyepatch/syndicate/equipped(mob/living/carbon/human/user, slot) + . = ..() + if(slot == SLOT_GLASSES) + user.visible_message("Circuitry from the eyepatch links itself to your brain as you put on the eyepatch.") + if(HAS_TRAIT(user, TRAIT_POOR_AIM)) + user.visible_message("You hear a fizzing noise from the circuit. That can't be good.") + ADD_TRAIT(user, TRAIT_INSANE_AIM, "SYNDICATE_EYEPATCH_AIM") + ADD_TRAIT(src, TRAIT_NODROP, "SYNDICATE_EYEPATCH_NODROP") + +/obj/item/clothing/glasses/eyepatch/syndicate/dropped(mob/living/carbon/human/user) + . = ..() + REMOVE_TRAIT(user, TRAIT_INSANE_AIM, "SYNDICATE_EYEPATCH_AIM") + var/obj/item/organ/eyes/eyes = user.getorganslot(ORGAN_SLOT_EYES) + if(eyes) + eyes.applyOrganDamage(30) + user.visible_message("Your eye stings as the circuitry is removed from your eye!") + /obj/item/clothing/glasses/monocle name = "monocle" desc = "Such a dapper eyepiece!" diff --git a/code/modules/clothing/glasses/engine_goggles.dm b/code/modules/clothing/glasses/engine_goggles.dm index 2a64445776..d7e7ae3669 100644 --- a/code/modules/clothing/glasses/engine_goggles.dm +++ b/code/modules/clothing/glasses/engine_goggles.dm @@ -97,14 +97,14 @@ if(get_dist(user, place) >= range*8) //Rads are easier to see than wires under the floor continue var/strength = round(rad_places[i] / 1000, 0.1) - var/image/pic = new(loc = place) + var/image/pic = image(loc = place) var/mutable_appearance/MA = new() - MA.alpha = 180 - MA.maptext = "[strength]k" - MA.color = "#64C864" - MA.layer = FLY_LAYER + MA.maptext = "[strength]k" + MA.color = "#04e604" + MA.layer = RAD_TEXT_LAYER + MA.plane = GAME_PLANE pic.appearance = MA - flick_overlay(pic, list(user.client), 8) + flick_overlay(pic, list(user.client), 10) /obj/item/clothing/glasses/meson/engine/proc/show_shuttle() var/mob/living/carbon/human/user = loc diff --git a/code/modules/clothing/gloves/ring.dm b/code/modules/clothing/gloves/ring.dm index 8354f13bd2..daca843c45 100644 --- a/code/modules/clothing/gloves/ring.dm +++ b/code/modules/clothing/gloves/ring.dm @@ -21,7 +21,7 @@ desc = "An expensive ring, studded with a diamond. Cultures have used these rings in courtship for a millenia." icon_state = "ringdiamond" item_state = "dring" - + /obj/item/clothing/gloves/ring/diamond/attack_self(mob/user) user.visible_message("\The [user] gets down on one knee, presenting \the [src].","You get down on one knee, presenting \the [src].") @@ -30,3 +30,12 @@ desc = "A tiny silver ring, sized to wrap around a finger." icon_state = "ringsilver" item_state = "sring" + +/obj/item/clothing/gloves/ring/custom + name = "ring" + desc = "A ring." + gender = NEUTER + w_class = WEIGHT_CLASS_TINY + obj_flags = UNIQUE_RENAME + icon_state = "ringsilver" + item_state = "sring" diff --git a/code/modules/clothing/masks/boxing.dm b/code/modules/clothing/masks/boxing.dm index f11c89d00c..6701b53c10 100644 --- a/code/modules/clothing/masks/boxing.dm +++ b/code/modules/clothing/masks/boxing.dm @@ -12,6 +12,10 @@ /obj/item/clothing/mask/balaclava/attack_self(mob/user) adjustmask(user) +/obj/item/clothing/mask/balaclava/breath + name = "breathaclava" + clothing_flags = ALLOWINTERNALS + /obj/item/clothing/mask/infiltrator name = "insidious balaclava" desc = "An incredibly suspicious balaclava made with Syndicate nanofibers to absorb impacts slightly while obfuscating the voice and face using a garbled vocoder." diff --git a/code/modules/clothing/spacesuits/hardsuit.dm b/code/modules/clothing/spacesuits/hardsuit.dm index 40797b97ed..12829ed0e7 100644 --- a/code/modules/clothing/spacesuits/hardsuit.dm +++ b/code/modules/clothing/spacesuits/hardsuit.dm @@ -214,7 +214,7 @@ name = "advanced hardsuit" desc = "An advanced suit that protects against hazardous, low pressure environments. Shines with a high polish." item_state = "ce_hardsuit" - armor = list("melee" = 40, "bullet" = 5, "laser" = 10, "energy" = 5, "bomb" = 50, "bio" = 100, "rad" = 95, "fire" = 100, "acid" = 90, "wound" = 10) + armor = list("melee" = 40, "bullet" = 5, "laser" = 10, "energy" = 5, "bomb" = 50, "bio" = 100, "rad" = 100, "fire" = 100, "acid" = 90, "wound" = 10) heat_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT helmettype = /obj/item/clothing/head/helmet/space/hardsuit/engine/elite diff --git a/code/modules/clothing/suits/miscellaneous.dm b/code/modules/clothing/suits/miscellaneous.dm index 607a8ecb55..6364a9a1c1 100644 --- a/code/modules/clothing/suits/miscellaneous.dm +++ b/code/modules/clothing/suits/miscellaneous.dm @@ -543,6 +543,7 @@ cold_protection = HEAD min_cold_protection_temperature = FIRE_SUIT_MIN_TEMP_PROTECT flags_inv = HIDEHAIR|HIDEEARS + rad_flags = RAD_NO_CONTAMINATE /obj/item/clothing/suit/hooded/wintercoat/centcom name = "centcom winter coat" @@ -1062,4 +1063,4 @@ name = "Samurai outfit" desc = "An outfit used by traditional japanese warriors." icon_state = "samurai" - item_state = "samurai" \ No newline at end of file + item_state = "samurai" diff --git a/code/modules/clothing/under/accessories.dm b/code/modules/clothing/under/accessories.dm index cb173f3bde..ee7e4c48e1 100644 --- a/code/modules/clothing/under/accessories.dm +++ b/code/modules/clothing/under/accessories.dm @@ -369,3 +369,12 @@ icon_state = "plastics" armor = list("melee" = 0, "bullet" = 0, "laser" = 20, "energy" = 10, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 20, "acid" = -40) flags_inv = HIDEACCESSORY + +//necklace +/obj/item/clothing/accessory/necklace + name = "necklace" + desc = "A necklace." + icon_state = "locket" + obj_flags = UNIQUE_RENAME + custom_materials = list(/datum/material/iron=100) + resistance_flags = FIRE_PROOF diff --git a/code/modules/emoji/emoji_parse.dm b/code/modules/emoji/emoji_parse.dm index 33d32227e1..3fd83899c9 100644 --- a/code/modules/emoji/emoji_parse.dm +++ b/code/modules/emoji/emoji_parse.dm @@ -16,11 +16,16 @@ search = findtext(text, ":", pos + length(text[pos])) if(search) emoji = lowertext(copytext(text, pos + length(text[pos]), search)) + var/isthisapath = (emoji[1] == "/") && text2path(emoji) var/datum/asset/spritesheet/sheet = get_asset_datum(/datum/asset/spritesheet/goonchat) var/tag = sheet.icon_tag("emoji-[emoji]") if(tag) parsed += "[tag]" //evil way of enforcing 16x16 pos = search + length(text[pos]) + else if(ispath(isthisapath, /atom)) //path + var/atom/thisisanatom = isthisapath + parsed += "[icon2html(initial(thisisanatom.icon), world, initial(thisisanatom.icon_state))]" + pos = search + length(text[pos]) else parsed += copytext(text, pos, search) pos = search diff --git a/code/modules/events/alien_infestation.dm b/code/modules/events/alien_infestation.dm index 69e9a974eb..993577cb30 100644 --- a/code/modules/events/alien_infestation.dm +++ b/code/modules/events/alien_infestation.dm @@ -3,7 +3,7 @@ typepath = /datum/round_event/ghost_role/alien_infestation weight = 5 gamemode_blacklist = list("dynamic") - min_players = 10 + min_players = 25 max_occurrences = 1 /datum/round_event/ghost_role/alien_infestation diff --git a/code/modules/events/brand_intelligence.dm b/code/modules/events/brand_intelligence.dm index da5b4c0cb2..1c88e68377 100644 --- a/code/modules/events/brand_intelligence.dm +++ b/code/modules/events/brand_intelligence.dm @@ -27,7 +27,6 @@ "How do I vore people?", "ERP?", "Not epic bros...") - threat = 5 /datum/round_event/brand_intelligence/announce(fake) diff --git a/code/modules/events/immovable_rod.dm b/code/modules/events/immovable_rod.dm index 89511a7b15..06318df4f5 100644 --- a/code/modules/events/immovable_rod.dm +++ b/code/modules/events/immovable_rod.dm @@ -42,6 +42,7 @@ In my current plan for it, 'solid' will be defined as anything with density == 1 name = "immovable rod" desc = "What the fuck is that?" icon = 'icons/obj/objects.dmi' + movement_type = FLOATING icon_state = "immrod" throwforce = 100 move_force = INFINITY diff --git a/code/modules/events/pirates.dm b/code/modules/events/pirates.dm index f1803b03ee..9ab5e8d517 100644 --- a/code/modules/events/pirates.dm +++ b/code/modules/events/pirates.dm @@ -25,7 +25,7 @@ ship_name = pick(strings(PIRATE_NAMES_FILE, "ship_names")) /datum/round_event/pirates/announce(fake) - priority_announce("A report has been downloaded and printed out at all communications consoles.", "Incoming Classified Message", "commandreport") // CITADEL EDIT metabreak + priority_announce("A business proposition has been downloaded and printed out at all communication consoles.", "Incoming Business Proposition", "commandreport") if(fake) return threat_message = new @@ -49,6 +49,7 @@ else priority_announce("Trying to cheat us? You'll regret this!",sender_override = ship_name) if(!shuttle_spawned) + priority_announce("You won't listen to reason? Then we'll take what's yours or die trying!",sender_override = ship_name) spawn_shuttle() /datum/round_event/pirates/start() @@ -83,8 +84,7 @@ announce_to_ghosts(M) else announce_to_ghosts(spawner) - - priority_announce("A report has been downloaded and printed out at all communications consoles.", "Incoming Classified Message", "commandreport") //CITADEL EDIT also metabreak here too + priority_announce("Unidentified ship detected near the station.") //Shuttle equipment @@ -95,14 +95,11 @@ icon_state = "dominator" density = TRUE var/active = FALSE - var/obj/item/gps/gps var/credits_stored = 0 var/siphon_per_tick = 5 /obj/machinery/shuttle_scrambler/Initialize(mapload) . = ..() - gps = new/obj/item/gps/internal/pirate(src) - gps.tracking = FALSE update_icon() /obj/machinery/shuttle_scrambler/process() @@ -112,6 +109,7 @@ if(D) var/siphoned = min(D.account_balance,siphon_per_tick) D.adjust_money(-siphoned) + credits_stored += siphoned interrupt_research() else return @@ -120,7 +118,7 @@ /obj/machinery/shuttle_scrambler/proc/toggle_on(mob/user) SSshuttle.registerTradeBlockade(src) - gps.tracking = TRUE + AddComponent(/datum/component/gps, "Nautical Signal") active = TRUE to_chat(user,"You toggle [src] [active ? "on":"off"].") to_chat(user,"The scrambling signal can be now tracked by GPS.") @@ -130,7 +128,7 @@ if(!active) if(alert(user, "Turning the scrambler on will make the shuttle trackable by GPS. Are you sure you want to do it?", "Scrambler", "Yes", "Cancel") == "Cancel") return - if(active || !user.canUseTopic(src)) + if(active || !user.canUseTopic(src, BE_CLOSE)) return toggle_on(user) update_icon() @@ -147,35 +145,31 @@ new /obj/effect/temp_visual/emp(get_turf(S)) /obj/machinery/shuttle_scrambler/proc/dump_loot(mob/user) - new /obj/item/holochip(drop_location(), credits_stored) - to_chat(user,"You retrieve the siphoned credits!") - credits_stored = 0 + if(credits_stored) // Prevents spamming empty holochips + new /obj/item/holochip(drop_location(), credits_stored) + to_chat(user,"You retrieve the siphoned credits!") + credits_stored = 0 + else + to_chat(user,"There's nothing to withdraw.") /obj/machinery/shuttle_scrambler/proc/send_notification() priority_announce("Data theft signal detected, source registered on local gps units.") /obj/machinery/shuttle_scrambler/proc/toggle_off(mob/user) SSshuttle.clearTradeBlockade(src) - gps.tracking = FALSE active = FALSE STOP_PROCESSING(SSobj,src) -/obj/machinery/shuttle_scrambler/update_overlays() - . = ..() +/obj/machinery/shuttle_scrambler/update_icon_state() if(active) - var/mutable_appearance/M = mutable_appearance(icon, "dominator-overlay") - M.color = "#00FFFF" - . += M + icon_state = "dominator-blue" + else + icon_state = "dominator" /obj/machinery/shuttle_scrambler/Destroy() toggle_off() - QDEL_NULL(gps) return ..() -/obj/item/gps/internal/pirate - gpstag = "Nautical Signal" - desc = "You can hear shanties over the static." - /obj/machinery/computer/shuttle/pirate name = "pirate shuttle console" shuttleId = "pirateship" @@ -312,11 +306,10 @@ else pad = locate() in range(4,src) -/obj/machinery/computer/piratepad_control/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ - datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) +/obj/machinery/computer/piratepad_control/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) if(!ui) - ui = new(user, src, ui_key, "CargoHoldTerminal", name, ui_x, ui_y, master_ui, state) + ui = new(user, src, "CargoHoldTerminal", name) ui.open() /obj/machinery/computer/piratepad_control/ui_data(mob/user) diff --git a/code/modules/events/wizard/magicarp.dm b/code/modules/events/wizard/magicarp.dm index 4d2e8e624c..57e2a2a051 100644 --- a/code/modules/events/wizard/magicarp.dm +++ b/code/modules/events/wizard/magicarp.dm @@ -30,7 +30,6 @@ icon_dead = "magicarp_dead" icon_gib = "magicarp_gib" ranged = 1 - threat = 4 retreat_distance = 2 minimum_distance = 0 //Between shots they can and will close in to nash projectiletype = /obj/item/projectile/magic @@ -52,7 +51,6 @@ color = "#00FFFF" maxHealth = 75 health = 75 - threat = 7 /mob/living/simple_animal/hostile/carp/ranged/chaos/Shoot() projectiletype = pick(allowed_projectile_types) diff --git a/code/modules/events/wizard/shuffle.dm b/code/modules/events/wizard/shuffle.dm index 3b5ea6b20a..18b8c8e21c 100644 --- a/code/modules/events/wizard/shuffle.dm +++ b/code/modules/events/wizard/shuffle.dm @@ -94,7 +94,7 @@ shuffle_inplace(mobs) - var/obj/effect/proc_holder/spell/targeted/mind_transfer/swapper = new /obj/effect/proc_holder/spell/targeted/mind_transfer + var/obj/effect/proc_holder/spell/pointed/mind_transfer/swapper = new /obj/effect/proc_holder/spell/pointed/mind_transfer while(mobs.len > 1) var/mob/living/carbon/human/H = pick(mobs) mobs -= H diff --git a/code/modules/food_and_drinks/food/snacks/meat.dm b/code/modules/food_and_drinks/food/snacks/meat.dm index fe70739ab5..4d287fdb86 100644 --- a/code/modules/food_and_drinks/food/snacks/meat.dm +++ b/code/modules/food_and_drinks/food/snacks/meat.dm @@ -162,6 +162,14 @@ tastes = list("brains" = 1, "meat" = 1) foodtype = RAW | MEAT | TOXIC +/obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/ethereal + icon_state = "etherealmeat" + desc = "So shiny you feel like ingesting it might make you shine too" + filling_color = "#97ee63" + list_reagents = list(/datum/reagent/consumable/liquidelectricity = 3) + tastes = list("pure electricity" = 2, "meat" = 1) + foodtype = RAW | MEAT | TOXIC + /obj/item/reagent_containers/food/snacks/carpmeat/aquatic name = "fillet" desc = "A fillet of one of the local water dwelling species." diff --git a/code/modules/food_and_drinks/food/snacks_meat.dm b/code/modules/food_and_drinks/food/snacks_meat.dm index 2a4139dbb9..05a0da2793 100644 --- a/code/modules/food_and_drinks/food/snacks_meat.dm +++ b/code/modules/food_and_drinks/food/snacks_meat.dm @@ -139,11 +139,22 @@ tastes = list("meat" = 1, "salmon" = 1) foodtype = MEAT | ALCOHOL +/obj/item/reagent_containers/food/snacks/rawmeatball + name = "raw meatball" + desc = "Raw mushy meat. Better cook this!" + icon_state = "rawmeatball" + cooked_type = /obj/item/reagent_containers/food/snacks/meatball + list_reagents = list(/datum/reagent/consumable/nutriment = 3) + filling_color = "#bd2020" + tastes = list("meat" = 1, "slime" = 1) + foodtype = MEAT | RAW + /obj/item/reagent_containers/food/snacks/meatball name = "meatball" desc = "MAMA MIA DAS A SPICY" icon_state = "meatball" list_reagents = list(/datum/reagent/consumable/nutriment = 4, /datum/reagent/consumable/nutriment/vitamin = 1) + bonus_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/nutriment/vitamin = 1) filling_color = "#800000" tastes = list("meat" = 1) foodtype = MEAT diff --git a/code/modules/food_and_drinks/food/snacks_pie.dm b/code/modules/food_and_drinks/food/snacks_pie.dm index 03f4640718..81805f5529 100644 --- a/code/modules/food_and_drinks/food/snacks_pie.dm +++ b/code/modules/food_and_drinks/food/snacks_pie.dm @@ -113,6 +113,27 @@ tastes = list("pie" = 1, "meat" = 1) foodtype = GRAIN | MEAT +/obj/item/reagent_containers/food/snacks/pie/burek + name = "Burek" + icon = 'icons/obj/food/piecake.dmi' + icon_state = "burek" + desc = "If you know, you know." + slice_path = /obj/item/reagent_containers/food/snacks/pie/burekslice + slices_num = 4 + bonus_reagents = list(/datum/reagent/consumable/nutriment = 4, /datum/reagent/consumable/nutriment/vitamin = 6) + list_reagents = list(/datum/reagent/consumable/nutriment= 20, /datum/reagent/consumable/nutriment/vitamin = 6) + bitesize = 12 + tastes = list("meat" = 1, "oil" = 1) + foodtype = GRAIN | MEAT + +/obj/item/reagent_containers/food/snacks/pie/burekslice + name = "Burek Slice" + icon = 'icons/obj/food/piecake.dmi' + icon_state = "burekslice" + desc = "A slice of Burek, watch out for oil stains!" + tastes = list("meat" = 1, "oil" = 1) + foodtype = GRAIN | MEAT + /obj/item/reagent_containers/food/snacks/pie/tofupie name = "tofu-pie" diff --git a/code/modules/food_and_drinks/food/snacks_vend.dm b/code/modules/food_and_drinks/food/snacks_vend.dm index 38f7ecf5b1..b4c7c89b74 100644 --- a/code/modules/food_and_drinks/food/snacks_vend.dm +++ b/code/modules/food_and_drinks/food/snacks_vend.dm @@ -91,3 +91,13 @@ tastes = list("sweetness" = 3, "cake" = 1) foodtype = GRAIN | FRUIT | VEGETABLES custom_price = PRICE_CHEAP + +/obj/item/reagent_containers/food/snacks/energybar + name = "High-power energy bars" + icon_state = "energybar" + desc = "An energy bar with a lot of punch, you probably shouldn't eat this if you're not an Ethereal." + trash = /obj/item/trash/energybar + list_reagents = list(/datum/reagent/consumable/nutriment = 3, /datum/reagent/consumable/liquidelectricity = 3) + filling_color = "#97ee63" + tastes = list("pure electricity" = 3, "fitness" = 2) + foodtype = TOXIC diff --git a/code/modules/food_and_drinks/kitchen_machinery/smartfridge.dm b/code/modules/food_and_drinks/kitchen_machinery/smartfridge.dm index 36e3b64487..35fa40e15d 100644 --- a/code/modules/food_and_drinks/kitchen_machinery/smartfridge.dm +++ b/code/modules/food_and_drinks/kitchen_machinery/smartfridge.dm @@ -12,6 +12,7 @@ idle_power_usage = 5 active_power_usage = 100 circuit = /obj/item/circuitboard/machine/smartfridge + var/max_n_of_items = 1500 var/allow_ai_retrieve = FALSE var/list/initial_contents @@ -38,12 +39,10 @@ if(in_range(user, src) || isobserver(user)) . += "The status display reads: This unit can hold a maximum of [max_n_of_items] items." -/obj/machinery/smartfridge/power_change() - ..() - update_icon() - /obj/machinery/smartfridge/update_icon_state() + SSvis_overlays.remove_vis_overlay(src, managed_vis_overlays) if(!stat) + SSvis_overlays.add_vis_overlay(src, icon, "smartfridge-light-mask", EMISSIVE_LAYER, EMISSIVE_PLANE, dir, alpha) if(visible_contents) switch(contents.len) if(0) @@ -66,9 +65,6 @@ ********************/ /obj/machinery/smartfridge/attackby(obj/item/O, mob/user, params) - if(user.a_intent == INTENT_HARM) - return ..() - if(default_deconstruction_screwdriver(user, icon_state, icon_state, O)) cut_overlays() if(panel_open) @@ -87,46 +83,53 @@ updateUsrDialog() return - if(stat) - updateUsrDialog() - return FALSE + if(!stat) - if(contents.len >= max_n_of_items) - to_chat(user, "\The [src] is full!") - return FALSE - - if(accept_check(O)) - load(O) - user.visible_message("[user] has added \the [O] to \the [src].", "You add \the [O] to \the [src].") - updateUsrDialog() - if (visible_contents) - update_icon() - return TRUE - - if(istype(O, /obj/item/storage/bag)) - var/obj/item/storage/P = O - var/loaded = 0 - for(var/obj/G in P.contents) - if(contents.len >= max_n_of_items) - break - if(accept_check(G)) - load(G) - loaded++ - updateUsrDialog() - - if(loaded) - user.visible_message("[user] loads \the [src] with \the [O].", \ - "You [contents.len >= max_n_of_items ? "fill" : "load"] \the [src] with \the [O].") - if(O.contents.len > 0) - to_chat(user, "Some items are refused.") - return TRUE - else - to_chat(user, "There is nothing in [O] to put in [src]!") + if(contents.len >= max_n_of_items) + to_chat(user, "\The [src] is full!") return FALSE - to_chat(user, "\The [src] smartly refuses [O].") - updateUsrDialog() - return FALSE + if(accept_check(O)) + load(O) + user.visible_message("[user] adds \the [O] to \the [src].", "You add \the [O] to \the [src].") + updateUsrDialog() + if (visible_contents) + update_icon() + return TRUE + + if(istype(O, /obj/item/storage/bag)) + var/obj/item/storage/P = O + var/loaded = 0 + for(var/obj/G in P.contents) + if(contents.len >= max_n_of_items) + break + if(accept_check(G)) + load(G) + loaded++ + updateUsrDialog() + + if(loaded) + if(contents.len >= max_n_of_items) + user.visible_message("[user] loads \the [src] with \the [O].", \ + "You fill \the [src] with \the [O].") + else + user.visible_message("[user] loads \the [src] with \the [O].", \ + "You load \the [src] with \the [O].") + if(O.contents.len > 0) + to_chat(user, "Some items are refused.") + if (visible_contents) + update_icon() + return TRUE + else + to_chat(user, "There is nothing in [O] to put in [src]!") + return FALSE + + if(user.a_intent != INTENT_HARM) + to_chat(user, "\The [src] smartly refuses [O].") + updateUsrDialog() + return FALSE + else + return ..() @@ -151,16 +154,16 @@ return TRUE ///Really simple proc, just moves the object "O" into the hands of mob "M" if able, done so I could modify the proc a little for the organ fridge -/obj/machinery/smartfridge/proc/dispense(obj/item/O, var/mob/M) +/obj/machinery/smartfridge/proc/dispense(obj/item/O, mob/M) if(!M.put_in_hands(O)) O.forceMove(drop_location()) adjust_item_drop_location(O) -/obj/machinery/smartfridge/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) +/obj/machinery/smartfridge/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) if(!ui) - ui = new(user, src, ui_key, "SmartVend", name, 440, 550, master_ui, state) + ui = new(user, src, "SmartVend", name) ui.set_autoupdate(FALSE) ui.open() @@ -232,7 +235,7 @@ // ---------------------------- /obj/machinery/smartfridge/drying_rack name = "drying rack" - desc = "A wooden contraption, used to dry plant products, food and leather." + desc = "A wooden contraption, used to dry plant products, food and hide." icon = 'icons/obj/hydroponics/equipment.dmi' icon_state = "drying_rack" use_power = IDLE_POWER_USE @@ -277,6 +280,11 @@ return TRUE return FALSE +// /obj/machinery/smartfridge/drying_rack/powered() do we have this? no. +// if(!anchored) +// return FALSE +// return ..() + /obj/machinery/smartfridge/drying_rack/power_change() if(powered() && anchored) stat &= ~NOPOWER @@ -285,6 +293,10 @@ toggle_drying(TRUE) update_icon() + // . = ..() + // if(!powered()) + // toggle_drying(TRUE) + /obj/machinery/smartfridge/drying_rack/load() //For updating the filled overlay ..() update_icon() @@ -308,7 +320,7 @@ var/obj/item/reagent_containers/food/snacks/S = O if(S.dried_type) return TRUE - if(istype(O, /obj/item/stack/sheet/wetleather/)) + if(istype(O, /obj/item/stack/sheet/wetleather/)) //no wethide return TRUE return FALSE @@ -386,19 +398,19 @@ /obj/machinery/smartfridge/extract/preloaded initial_contents = list(/obj/item/slime_scanner = 2) -// ------------------------- You think you're better than Chem, huh? +// ------------------------- // Organ Surgery Smartfridge -// ------------------------- Just wait till Tamiorgans +// ------------------------- /obj/machinery/smartfridge/organ name = "smart organ storage" desc = "A refrigerated storage unit for organ storage." - max_n_of_items = 25 //vastly lower to prevent processing too long + max_n_of_items = 20 //vastly lower to prevent processing too long var/repair_rate = 0 /obj/machinery/smartfridge/organ/accept_check(obj/item/O) - if(istype(O, /obj/item/organ)) + if(isorgan(O) || isbodypart(O)) return TRUE - if(istype(O, /obj/item/reagent_containers/syringe)) + if(istype(O, /obj/item/reagent_containers/syringe)) //other medical things. return TRUE if(istype(O, /obj/item/reagent_containers/glass/bottle)) return TRUE @@ -410,7 +422,7 @@ . = ..() if(!.) //if the item loads, clear can_decompose return - if(istype(O, /obj/item/organ)) + if(isorgan(O)) var/obj/item/organ/organ = O organ.organ_flags |= ORGAN_FROZEN @@ -426,12 +438,13 @@ return O.applyOrganDamage(-repair_rate) -/obj/machinery/smartfridge/organ/Exited(obj/item/organ/AM, atom/newLoc) +/obj/machinery/smartfridge/organ/Exited(atom/movable/AM, atom/newLoc) . = ..() - if(istype(AM)) - AM.organ_flags &= ~ORGAN_FROZEN + if(isorgan(AM)) + var/obj/item/organ/O = AM + O.organ_flags &= ~ORGAN_FROZEN -/obj/machinery/smartfridge/organ/preloaded +/obj/machinery/smartfridge/organ/preloaded //cit specific?????? initial_contents = list( /obj/item/reagent_containers/medspray/synthtissue = 1, /obj/item/reagent_containers/medspray/sterilizine = 1) @@ -450,6 +463,15 @@ desc = "A refrigerated storage unit for medicine storage." /obj/machinery/smartfridge/chemistry/accept_check(obj/item/O) + var/static/list/chemfridge_typecache = typecacheof(list( + /obj/item/reagent_containers/syringe, + /obj/item/reagent_containers/glass/bottle, + /obj/item/reagent_containers/glass/beaker, + /obj/item/reagent_containers/spray, + // /obj/item/reagent_containers/medigel, + /obj/item/reagent_containers/chem_pack + )) + if(istype(O, /obj/item/storage/pill_bottle)) if(O.contents.len) for(var/obj/item/I in O) @@ -463,7 +485,7 @@ return TRUE if(!O.reagents || !O.reagents.reagent_list.len) // other empty containers not accepted return FALSE - if(istype(O, /obj/item/reagent_containers/syringe) || istype(O, /obj/item/reagent_containers/glass/bottle) || istype(O, /obj/item/reagent_containers/glass/beaker) || istype(O, /obj/item/reagent_containers/spray) || istype(O, /obj/item/reagent_containers/medspray) || istype(O, /obj/item/reagent_containers/chem_pack)) + if(is_type_in_typecache(O, chemfridge_typecache)) return TRUE return FALSE @@ -487,6 +509,7 @@ /obj/item/reagent_containers/glass/bottle/cold = 1, /obj/item/reagent_containers/glass/bottle/flu_virion = 1, /obj/item/reagent_containers/glass/bottle/mutagen = 1, + /obj/item/reagent_containers/glass/bottle/sugar = 1, /obj/item/reagent_containers/glass/bottle/plasma = 1, /obj/item/reagent_containers/glass/bottle/synaptizine = 1, /obj/item/reagent_containers/glass/bottle/formaldehyde = 1) @@ -498,8 +521,8 @@ name = "disk compartmentalizer" desc = "A machine capable of storing a variety of disks. Denoted by most as the DSU (disk storage unit)." icon_state = "disktoaster" - visible_contents = FALSE pass_flags = PASSTABLE + visible_contents = FALSE /obj/machinery/smartfridge/disks/accept_check(obj/item/O) if(istype(O, /obj/item/disk/)) diff --git a/code/modules/food_and_drinks/recipes/processor_recipes.dm b/code/modules/food_and_drinks/recipes/processor_recipes.dm index 1e3afd1cf5..f75cf6ef3a 100644 --- a/code/modules/food_and_drinks/recipes/processor_recipes.dm +++ b/code/modules/food_and_drinks/recipes/processor_recipes.dm @@ -6,7 +6,7 @@ /datum/food_processor_process/meat input = /obj/item/reagent_containers/food/snacks/meat/slab - output = /obj/item/reagent_containers/food/snacks/meatball + output = /obj/item/reagent_containers/food/snacks/rawmeatball /datum/food_processor_process/bacon input = /obj/item/reagent_containers/food/snacks/meat/rawcutlet diff --git a/code/modules/food_and_drinks/recipes/tablecraft/recipes_pies_sweets.dm b/code/modules/food_and_drinks/recipes/tablecraft/recipes_pies_sweets.dm index 52becf81df..289c698b9a 100644 --- a/code/modules/food_and_drinks/recipes/tablecraft/recipes_pies_sweets.dm +++ b/code/modules/food_and_drinks/recipes/tablecraft/recipes_pies_sweets.dm @@ -130,6 +130,18 @@ result = /obj/item/reagent_containers/food/snacks/pie/dulcedebatata subcategory = CAT_PIE +/datum/crafting_recipe/food/burek + name = "Burek" + reqs = list( + /datum/reagent/consumable/blackpepper = 3, + /datum/reagent/consumable/sodiumchloride = 3, + /obj/item/reagent_containers/food/snacks/pizzabread = 2, + /obj/item/reagent_containers/food/snacks/meat/cutlet/plain = 6, + /obj/item/reagent_containers/food/snacks/butter = 1, + ) + result = /obj/item/reagent_containers/food/snacks/pie/burek + subcategory = CAT_PIE + /datum/crafting_recipe/food/meatpie name = "Meat pie" reqs = list( @@ -302,4 +314,4 @@ /obj/item/reagent_containers/food/snacks/spiderling = 1 ) result = /obj/item/reagent_containers/food/snacks/spiderlollipop - subcategory = CAT_PIE \ No newline at end of file + subcategory = CAT_PIE diff --git a/code/modules/holiday/halloween/halloween.dm b/code/modules/holiday/halloween/halloween.dm index 6c9e527f38..d3b9b92b4f 100644 --- a/code/modules/holiday/halloween/halloween.dm +++ b/code/modules/holiday/halloween/halloween.dm @@ -190,7 +190,6 @@ icon_dead = "scary_clown" icon_gib = "scary_clown" speak = list("...", ". . .") - threat = 3 maxHealth = 120 health = 120 emote_see = list("silently stares") diff --git a/code/modules/holodeck/computer.dm b/code/modules/holodeck/computer.dm index d72e1b1fc8..e5cd36cad6 100644 --- a/code/modules/holodeck/computer.dm +++ b/code/modules/holodeck/computer.dm @@ -2,10 +2,7 @@ Holodeck Update The on-station holodeck area is of type [holodeck_type]. - All types found in GLOB.holodeck_areas_per_comp_type[src.type], generated on make_datum_references_lists(), - are loaded into the program cache or emag programs list. - Paths with their abstract_type variable equal to themselves will be skipped. - + All subtypes of [program_type] are loaded into the program cache or emag programs list. If init_program is null, a random program will be loaded on startup. If you don't wish this, set it to the offline program or another of your choosing. @@ -15,6 +12,7 @@ 3) Create a new control console that uses those areas Non-mapped areas should be skipped but you should probably comment them out anyway. + The base of program_type will always be ignored; only subtypes will be loaded. */ #define HOLODECK_CD 25 @@ -26,18 +24,20 @@ icon_screen = "holocontrol" idle_power_usage = 10 active_power_usage = 50 + var/area/holodeck/linked var/area/holodeck/program var/area/holodeck/last_program var/area/offline_program = /area/holodeck/rec_center/offline - // Splitting this up allows two holodecks of the same size - // to use the same source patterns. Y'know, if you want to. - var/holodeck_type = /area/holodeck/rec_center - var/list/program_cache var/list/emag_programs + // Splitting this up allows two holodecks of the same size + // to use the same source patterns. Y'know, if you want to. + var/holodeck_type = /area/holodeck/rec_center // locate(this) to get the target holodeck + var/program_type = /area/holodeck/rec_center // subtypes of this (but not this itself) are loadable programs + var/active = FALSE var/damaged = FALSE var/list/spawned = list() @@ -49,41 +49,47 @@ return INITIALIZE_HINT_LATELOAD /obj/machinery/computer/holodeck/LateInitialize() - linked = SSholodeck.target_holodeck_area[type] - offline_program = SSholodeck.offline_programs[type] + if(ispath(holodeck_type, /area)) + linked = pop(get_areas(holodeck_type, FALSE)) + if(ispath(offline_program, /area)) + offline_program = pop(get_areas(offline_program), FALSE) + // the following is necessary for power reasons if(!linked || !offline_program) log_world("No matching holodeck area found") qdel(src) return - - program_cache = SSholodeck.program_cache[type] - emag_programs = SSholodeck.emag_program_cache[type] - - // the following is necessary for power reasons - var/area/AS = get_base_area(src) + var/area/AS = get_area(src) if(istype(AS, /area/holodeck)) log_mapping("Holodeck computer cannot be in a holodeck, This would cause circular power dependency.") qdel(src) return else linked.linked = src - + /* + var/area/my_area = get_area(src) + if(my_area) + linked.power_usage = my_area.power_usage + else + linked.power_usage = new /list(AREA_USAGE_LEN) + */ + generate_program_list() load_program(offline_program, FALSE, FALSE) /obj/machinery/computer/holodeck/Destroy() emergency_shutdown() if(linked) linked.linked = null + //linked.power_usage = new /list(AREA_USAGE_LEN) return ..() /obj/machinery/computer/holodeck/power_change() . = ..() toggle_power(!stat) -/obj/machinery/computer/holodeck/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) +/obj/machinery/computer/holodeck/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) if(!ui) - ui = new(user, src, ui_key, "Holodeck", name, 400, 500, master_ui, state) + ui = new(user, src, "Holodeck", name) ui.open() /obj/machinery/computer/holodeck/ui_data(mob/user) @@ -107,19 +113,27 @@ var/program_to_load = text2path(params["type"]) if(!ispath(program_to_load)) return FALSE + var/valid = FALSE + var/list/checked = program_cache.Copy() + if(obj_flags & EMAGGED) + checked |= emag_programs + for(var/prog in checked) + var/list/P = prog + if(P["type"] == program_to_load) + valid = TRUE + break + if(!valid) + return FALSE + var/area/A = locate(program_to_load) in GLOB.sortedAreas if(A) load_program(A) if("safety") - if(!hasSiliconAccessInArea(usr) && !IsAdminGhost(usr)) - var/msg = "[key_name(usr)] attempted to emag the holodeck using a href they shouldn't have!" - message_admins(msg) - log_admin(msg) - return - obj_flags ^= EMAGGED - if((obj_flags & EMAGGED) && program && emag_programs[program.name]) + if((obj_flags & EMAGGED) && program) emergency_shutdown() nerf(obj_flags & EMAGGED) + obj_flags ^= EMAGGED + say("Safeties restored. Restarting...") /obj/machinery/computer/holodeck/process() if(damaged && prob(10)) @@ -160,13 +174,12 @@ if(!LAZYLEN(emag_programs)) to_chat(user, "[src] does not seem to have a card swipe port. It must be an inferior model.") return - playsound(src, "sparks", 75, 1) + playsound(src, "sparks", 75, TRUE) obj_flags |= EMAGGED to_chat(user, "You vastly increase projector power and override the safety and security protocols.") - to_chat(user, "Warning. Automatic shutoff and derezing protocols have been corrupted. Please call Nanotrasen maintenance and do not use the simulator.") + say("Warning. Automatic shutoff and derezzing protocols have been corrupted. Please call Nanotrasen maintenance and do not use the simulator.") log_game("[key_name(user)] emagged the Holodeck Control Console") nerf(!(obj_flags & EMAGGED)) - return TRUE /obj/machinery/computer/holodeck/emp_act(severity) . = ..() @@ -182,6 +195,19 @@ emergency_shutdown() return ..() +/obj/machinery/computer/holodeck/proc/generate_program_list() + for(var/typekey in subtypesof(program_type)) + var/area/holodeck/A = GLOB.areas_by_type[typekey] + if(!A || !A.contents.len) + continue + var/list/info_this = list() + info_this["name"] = A.name + info_this["type"] = A.type + if(A.restricted) + LAZYADD(emag_programs, list(info_this)) + else + LAZYADD(program_cache, list(info_this)) + /obj/machinery/computer/holodeck/proc/toggle_power(toggleOn = FALSE) if(active == toggleOn) return @@ -281,7 +307,7 @@ silent = FALSE // otherwise make sure they are dropped if(!silent) - visible_message("[O] fades away!") + visible_message("[O] fades away!") qdel(O) #undef HOLODECK_CD diff --git a/code/modules/hydroponics/biogenerator.dm b/code/modules/hydroponics/biogenerator.dm index 06d2b3efda..b61d9451ef 100644 --- a/code/modules/hydroponics/biogenerator.dm +++ b/code/modules/hydroponics/biogenerator.dm @@ -10,13 +10,13 @@ var/processing = FALSE var/obj/item/reagent_containers/glass/beaker = null var/points = 0 - var/menustat = "menu" var/efficiency = 0 var/productivity = 0 var/max_items = 40 var/datum/techweb/stored_research var/list/show_categories = list("Food", "Botany Chemicals", "Organic Materials") - var/list/timesFiveCategories = list("Food", "Botany Chemicals") + /// Currently selected category in the UI + var/selected_cat /obj/machinery/biogenerator/Initialize() . = ..() @@ -37,22 +37,20 @@ if(A == beaker) beaker = null update_icon() - updateUsrDialog() /obj/machinery/biogenerator/RefreshParts() - var/E = 0.5 - var/P = 0.5 - var/max_storage = 20 + var/E = 0 + var/P = 0 + var/max_storage = 40 for(var/obj/item/stock_parts/matter_bin/B in component_parts) - P += B.rating * 0.5 - max_storage = max(20 * B.rating, max_storage) + P += B.rating + max_storage = 40 * B.rating for(var/obj/item/stock_parts/manipulator/M in component_parts) - E += M.rating * 0.5 + E += M.rating efficiency = E productivity = P max_items = max_storage - /obj/machinery/biogenerator/examine(mob/user) . = ..() if(in_range(user, src) || isobserver(user)) @@ -70,7 +68,6 @@ icon_state = "biogen-stand" else icon_state = "biogen-work" - return /obj/machinery/biogenerator/attackby(obj/item/O, mob/user, params) if(user.a_intent == INTENT_HARM) @@ -102,7 +99,6 @@ beaker = O to_chat(user, "You add the container to the machine.") update_icon() - updateUsrDialog() else to_chat(user, "Close the maintenance panel first.") return @@ -139,9 +135,9 @@ to_chat(user, "You put [O.name] in [src.name]") return TRUE //no afterattack else if (istype(O, /obj/item/disk/design_disk)) - user.visible_message("[user] begins to load \the [O] in \the [src]...", - "You begin to load a design from \the [O]...", - "You hear the chatter of a floppy drive.") + user.visible_message("[user] begins to load \the [O] in \the [src]...", + "You begin to load a design from \the [O]...", + "You hear the chatter of a floppy drive.") processing = TRUE var/obj/item/disk/design_disk/D = O if(do_after(user, 10, target = src)) @@ -153,106 +149,53 @@ else to_chat(user, "You cannot put this in [src.name]!") -/obj/machinery/biogenerator/ui_interact(mob/user) - if(stat & BROKEN || panel_open) - return - . = ..() - var/dat - if(processing) - dat += "
Biogenerator is processing! Please wait...

" - else - switch(menustat) - if("nopoints") - dat += "
You do not have enough biomass to create products.
Please, put growns into reactor and activate it.
" - menustat = "menu" - if("complete") - dat += "
Operation complete.
" - menustat = "menu" - if("void") - dat += "
Error: No growns inside.
Please, put growns into reactor.
" - menustat = "menu" - if("nobeakerspace") - dat += "
Not enough space left in container. Unable to create product.
" - menustat = "menu" - if(beaker) - var/categories = show_categories.Copy() - for(var/V in categories) - categories[V] = list() - for(var/V in stored_research.researched_designs) - var/datum/design/D = SSresearch.techweb_design_by_id(V) - for(var/C in categories) - if(C in D.category) - categories[C] += D - - dat += "
Biomass: [points] units.

" - dat += "ActivateDetach Container" - for(var/cat in categories) - dat += "

[cat]:

" - dat += "
" - for(var/V in categories[cat]) - var/datum/design/D = V - dat += "[D.name]: Make" - if(cat in timesFiveCategories) - dat += "x5" - if(ispath(D.build_path, /obj/item/stack)) - dat += "x10" - dat += "([CEILING(D.materials[SSmaterials.GetMaterialRef(/datum/material/biomass)]/efficiency, 1)])
" - dat += "
" - else - dat += "
No container inside, please insert container.
" - - var/datum/browser/popup = new(user, "biogen", name, 350, 520) - popup.set_content(dat) - popup.open() - /obj/machinery/biogenerator/AltClick(mob/living/user) . = ..() - if(istype(user) && user.canUseTopic(src, BE_CLOSE, FALSE, NO_TK)) + if(user.canUseTopic(src, BE_CLOSE, FALSE, NO_TK) && can_interact(user)) detach(user) -/obj/machinery/biogenerator/proc/activate() - if (usr.stat != CONSCIOUS) +/** + * activate: Activates biomass processing and converts all inserted grown products into biomass + * + * Arguments: + * * user The mob starting the biomass processing + */ +/obj/machinery/biogenerator/proc/activate(mob/user) + if(user.stat != CONSCIOUS) return - if (src.stat != NONE) //NOPOWER etc + if(stat != NONE) return if(processing) - to_chat(usr, "The biogenerator is in the process of working.") + to_chat(user, "The biogenerator is in the process of working.") return var/S = 0 - var/total = 0 for(var/obj/item/reagent_containers/food/snacks/grown/I in contents) S += 5 - var/nutri_amount = I.reagents.get_reagent_amount(/datum/reagent/consumable/nutriment) - if(nutri_amount < 0.1) - total += 1*productivity + if(I.reagents.get_reagent_amount(/datum/reagent/consumable/nutriment) < 0.1) + points += 1 * productivity else - total += nutri_amount*10*productivity + points += I.reagents.get_reagent_amount(/datum/reagent/consumable/nutriment) * 10 * productivity qdel(I) - points += round(total) if(S) processing = TRUE update_icon() - updateUsrDialog() - playsound(src.loc, 'sound/machines/blender.ogg', 50, 1) - use_power(S*30) - sleep(S+15/productivity) + playsound(loc, 'sound/machines/blender.ogg', 50, TRUE) + use_power(S * 30) + sleep(S + 15 / productivity) + if(QDELETED(src)) //let's not. + return processing = FALSE update_icon() - else - menustat = "void" /obj/machinery/biogenerator/proc/check_cost(list/materials, multiplier = 1, remove_points = TRUE) if(materials.len != 1 || materials[1] != SSmaterials.GetMaterialRef(/datum/material/biomass)) return FALSE - var/cost = CEILING(materials[SSmaterials.GetMaterialRef(/datum/material/biomass)]*multiplier/efficiency, 1) - if (cost > points) - menustat = "nopoints" + if (materials[SSmaterials.GetMaterialRef(/datum/material/biomass)]*multiplier/efficiency > points) return FALSE else if(remove_points) - points -= cost + points -= materials[SSmaterials.GetMaterialRef(/datum/material/biomass)]*multiplier/efficiency update_icon() - updateUsrDialog() return TRUE /obj/machinery/biogenerator/proc/check_container_volume(list/reagents, multiplier = 1) @@ -262,7 +205,6 @@ sum_reagents *= multiplier if(beaker.reagents.total_volume + sum_reagents > beaker.reagents.maximum_volume) - menustat = "nobeakerspace" return FALSE return TRUE @@ -284,6 +226,7 @@ var/i = amount while(i > 0) if(!check_container_volume(D.make_reagents)) + say("Warning: Attached container does not have enough free capacity!") return . if(!check_cost(D.materials)) return . @@ -293,51 +236,100 @@ beaker.reagents.add_reagent(R, D.make_reagents[R]) . = 1 --i - - menustat = "complete" update_icon() return . /obj/machinery/biogenerator/proc/detach(mob/living/user) if(beaker) - user.put_in_hands(beaker) + if(can_interact(user)) + user.put_in_hands(beaker) + else + beaker.drop_location(get_turf(src)) beaker = null update_icon() -/obj/machinery/biogenerator/Topic(href, href_list) - if(..() || panel_open) +/obj/machinery/biogenerator/ui_status(mob/user) + if(stat & BROKEN || panel_open) + return UI_CLOSE + return ..() + +/obj/machinery/biogenerator/ui_assets(mob/user) + return list( + get_asset_datum(/datum/asset/spritesheet/research_designs), + ) + +/obj/machinery/biogenerator/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "Biogenerator", name) + ui.open() + +/obj/machinery/biogenerator/ui_data(mob/user) + var/list/data = list() + data["beaker"] = beaker ? TRUE : FALSE + data["biomass"] = points + data["processing"] = processing + if(locate(/obj/item/reagent_containers/food/snacks/grown) in contents) + data["can_process"] = TRUE + else + data["can_process"] = FALSE + return data + +/obj/machinery/biogenerator/ui_static_data(mob/user) + var/list/data = list() + data["categories"] = list() + + var/categories = show_categories.Copy() + for(var/V in categories) + categories[V] = list() + for(var/V in stored_research.researched_designs) + var/datum/design/D = SSresearch.techweb_design_by_id(V) + for(var/C in categories) + if(C in D.category) + categories[C] += D + + for(var/category in categories) + var/list/cat = list( + "name" = category, + "items" = (category == selected_cat ? list() : null)) + for(var/item in categories[category]) + var/datum/design/D = item + cat["items"] += list(list( + "id" = D.id, + "name" = D.name, + "cost" = D.materials[SSmaterials.GetMaterialRef(/datum/material/biomass)]/efficiency, + )) + data["categories"] += list(cat) + + return data + +/obj/machinery/biogenerator/ui_act(action, list/params) + if(..()) return - usr.set_machine(src) - - if(href_list["activate"]) - activate() - updateUsrDialog() - - else if(href_list["detach"]) - detach(usr) - updateUsrDialog() - - else if(href_list["create"]) - var/amount = (text2num(href_list["amount"])) - //Can't be outside these (if you change this keep a sane limit) - amount = clamp(amount, 1, 50) - var/id = href_list["create"] - if(!stored_research.researched_designs.Find(id)) - //naughty naughty - stack_trace("ID did not map to a researched datum [id]") - return - - //Get design by id (or may return error design) - var/datum/design/D = SSresearch.techweb_design_by_id(id) - //Valid design datum, amount and the datum is not the error design, lets proceed - if(D && amount && !istype(D, /datum/design/error_design)) - create_product(D, amount) - //This shouldnt happen normally but href forgery is real - else - stack_trace("ID could not be turned into a valid techweb design datum [id]") - updateUsrDialog() - - else if(href_list["menu"]) - menustat = "menu" - updateUsrDialog() + switch(action) + if("activate") + activate(usr) + return TRUE + if("detach") + detach(usr) + return TRUE + if("create") + var/amount = text2num(params["amount"]) + amount = clamp(amount, 1, 10) + if(!amount) + return + var/id = params["id"] + if(!stored_research.researched_designs.Find(id)) + stack_trace("ID did not map to a researched datum [id]") + return + var/datum/design/D = SSresearch.techweb_design_by_id(id) + if(D && !istype(D, /datum/design/error_design)) + create_product(D, amount) + else + stack_trace("ID could not be turned into a valid techweb design datum [id]") + return + return TRUE + if("select") + selected_cat = params["category"] + return TRUE diff --git a/code/modules/hydroponics/gene_modder.dm b/code/modules/hydroponics/gene_modder.dm index 4e545c13ee..a0c273613f 100644 --- a/code/modules/hydroponics/gene_modder.dm +++ b/code/modules/hydroponics/gene_modder.dm @@ -3,9 +3,9 @@ desc = "An advanced device designed to manipulate plant genetic makeup." icon = 'icons/obj/hydroponics/equipment.dmi' icon_state = "dnamod" - density = TRUE circuit = /obj/item/circuitboard/machine/plantgenes - pass_flags = PASSTABLE + pass_flags = PASSTABLE | LETPASSTHROW + flags_1 = DEFAULT_RICOCHET_1 var/obj/item/seeds/seed var/obj/item/disk/plantgene/disk diff --git a/code/modules/hydroponics/grown/cannabis.dm b/code/modules/hydroponics/grown/cannabis.dm index 621e79fb77..6525ac42d4 100644 --- a/code/modules/hydroponics/grown/cannabis.dm +++ b/code/modules/hydroponics/grown/cannabis.dm @@ -14,9 +14,7 @@ icon_dead = "cannabis-dead" // Same for the dead icon genes = list(/datum/plant_gene/trait/repeated_harvest) mutatelist = list(/obj/item/seeds/cannabis/rainbow, - /obj/item/seeds/cannabis/death, - /obj/item/seeds/cannabis/white, - /obj/item/seeds/cannabis/ultimate) + /obj/item/seeds/cannabis/death) reagents_add = list(/datum/reagent/drug/space_drugs = 0.15, /datum/reagent/toxin/lipolicide = 0.35) // gives u the munchies @@ -27,7 +25,7 @@ species = "megacannabis" plantname = "Rainbow Weed" product = /obj/item/reagent_containers/food/snacks/grown/cannabis/rainbow - mutatelist = list() + mutatelist = list(/obj/item/seeds/cannabis/ultimate) reagents_add = list(/datum/reagent/toxin/mindbreaker = 0.15, /datum/reagent/toxin/lipolicide = 0.35) rarity = 40 @@ -38,7 +36,7 @@ species = "blackcannabis" plantname = "Deathweed" product = /obj/item/reagent_containers/food/snacks/grown/cannabis/death - mutatelist = list() + mutatelist = list(/obj/item/seeds/cannabis/white) reagents_add = list(/datum/reagent/toxin/cyanide = 0.35, /datum/reagent/drug/space_drugs = 0.15, /datum/reagent/toxin/lipolicide = 0.15) rarity = 40 diff --git a/code/modules/hydroponics/grown/citrus.dm b/code/modules/hydroponics/grown/citrus.dm index 6ac7bbcfcb..d130d50aa5 100644 --- a/code/modules/hydroponics/grown/citrus.dm +++ b/code/modules/hydroponics/grown/citrus.dm @@ -33,26 +33,6 @@ filling_color = "#00FF00" juice_results = list(/datum/reagent/consumable/limejuice = 0) -// Electric Lime -/obj/item/seeds/lime/electric - name = "pack of electric lime seeds" - desc = "Electrically sour seeds." - icon_state = "seed-electriclime" - species = "electric lime" - plantname = "Electric Lime Tree" - growing_icon = 'icons/obj/hydroponics/growing_fruits.dmi' - icon_grow = "lime-grow" - icon_dead = "lime-dead" - icon_harvest = "lime-harvest" - product = /obj/item/reagent_containers/food/snacks/grown/citrus/lime/electric - genes = list(/datum/plant_gene/trait/repeated_harvest, /datum/plant_gene/trait/cell_charge, /datum/plant_gene/trait/glow/green) - -/obj/item/reagent_containers/food/snacks/grown/citrus/lime/electric - seed = /obj/item/seeds/lime/electric - name = "electric lime" - desc = "It's so sour, you'll be shocked!" - icon_state = "electriclime" - // Orange /obj/item/seeds/orange name = "pack of orange seeds" diff --git a/code/modules/hydroponics/grown/garlic.dm b/code/modules/hydroponics/grown/garlic.dm index 4184b85008..2cc3f41860 100644 --- a/code/modules/hydroponics/grown/garlic.dm +++ b/code/modules/hydroponics/grown/garlic.dm @@ -9,6 +9,9 @@ potency = 25 growthstages = 3 growing_icon = 'icons/obj/hydroponics/growing_vegetables.dmi' + icon_grow = "garlic-grow" + icon_harvest = "garlic-harvest" + icon_dead = "garlic-dead" reagents_add = list(/datum/reagent/consumable/garlic = 0.15, /datum/reagent/consumable/nutriment = 0.1) /obj/item/reagent_containers/food/snacks/grown/garlic diff --git a/code/modules/hydroponics/grown/grass_carpet.dm b/code/modules/hydroponics/grown/grass_carpet.dm index 3b5159465c..a74850f3be 100644 --- a/code/modules/hydroponics/grown/grass_carpet.dm +++ b/code/modules/hydroponics/grown/grass_carpet.dm @@ -51,6 +51,7 @@ icon_grow = "fairygrass-grow" icon_dead = "fairygrass-dead" genes = list(/datum/plant_gene/trait/repeated_harvest, /datum/plant_gene/trait/glow/blue) + mutatelist = list (/obj/item/seeds/grass/carpet) reagents_add = list(/datum/reagent/consumable/nutriment = 0.02, /datum/reagent/hydrogen = 0.05, /datum/reagent/drug/space_drugs = 0.15) /obj/item/reagent_containers/food/snacks/grown/grass/fairy @@ -99,7 +100,7 @@ species = "carpet" plantname = "Carpet" product = /obj/item/reagent_containers/food/snacks/grown/grass/carpet - mutatelist = list() + mutatelist = list(/obj/item/seeds/grass/fairy) rarity = 10 /obj/item/reagent_containers/food/snacks/grown/grass/carpet diff --git a/code/modules/hydroponics/grown/tea_coffee.dm b/code/modules/hydroponics/grown/tea_coffee.dm index de27d1eed7..223b2c7bce 100644 --- a/code/modules/hydroponics/grown/tea_coffee.dm +++ b/code/modules/hydroponics/grown/tea_coffee.dm @@ -44,7 +44,7 @@ filling_color = "#4582B4" grind_results = list(/datum/reagent/toxin/teapowder = 0, /datum/reagent/medicine/salglu_solution = 0) -// Kitty drugs +// Catnip /obj/item/seeds/tea/catnip name = "pack of catnip seeds" icon_state = "seed-catnip" @@ -52,6 +52,9 @@ species = "catnip" plantname = "Catnip Plant" growthstages = 3 + icon_grow = "catnip-grow" + icon_harvest = "catnip-harvest" + icon_dead = "tea-dead" product = /obj/item/reagent_containers/food/snacks/grown/tea/catnip reagents_add = list(/datum/reagent/pax/catnip = 0.1, /datum/reagent/consumable/nutriment/vitamin = 0.06, /datum/reagent/toxin/teapowder = 0.3) rarity = 50 diff --git a/code/modules/hydroponics/hydroponics.dm b/code/modules/hydroponics/hydroponics.dm index 06179d1087..a208f2de3c 100644 --- a/code/modules/hydroponics/hydroponics.dm +++ b/code/modules/hydroponics/hydroponics.dm @@ -30,7 +30,7 @@ var/self_sufficiency_req = 20 //Required total dose to make a self-sufficient hydro tray. 1:1 with earthsblood. var/self_sufficiency_progress = 0 var/self_sustaining = FALSE //If the tray generates nutrients and water on its own - + var/canirrigate = TRUE //tin /obj/machinery/hydroponics/constructable name = "hydroponics tray" @@ -847,12 +847,13 @@ if (!anchored) to_chat(user, "Anchor the tray first!") return - using_irrigation = !using_irrigation - O.play_tool_sound(src) - user.visible_message("[user] [using_irrigation ? "" : "dis"]connects [src]'s irrigation hoses.", \ - "You [using_irrigation ? "" : "dis"]connect [src]'s irrigation hoses.") - for(var/obj/machinery/hydroponics/h in range(1,src)) - h.update_icon() + if(canirrigate) + using_irrigation = !using_irrigation + O.play_tool_sound(src) + user.visible_message("[user] [using_irrigation ? "" : "dis"]connects [src]'s irrigation hoses.", \ + "You [using_irrigation ? "" : "dis"]connect [src]'s irrigation hoses.") + for(var/obj/machinery/hydroponics/h in range(1,src)) + h.update_icon() else if(istype(O, /obj/item/shovel/spade)) if(!myseed && !weedlevel) @@ -910,11 +911,14 @@ harvest = 0 lastproduce = age if(istype(myseed, /obj/item/seeds/replicapod)) - to_chat(user, "You harvest from the [myseed.plantname].") + if(user)//runtimes + to_chat(user, "You harvest from the [myseed.plantname].") else if(myseed.getYield() <= 0) - to_chat(user, "You fail to harvest anything useful!") + if(user) + to_chat(user, "You fail to harvest anything useful!") else - to_chat(user, "You harvest [myseed.getYield()] items from the [myseed.plantname].") + if(user) + to_chat(user, "You harvest [myseed.getYield()] items from the [myseed.plantname].") if(!myseed.get_gene(/datum/plant_gene/trait/repeated_harvest)) qdel(myseed) myseed = null diff --git a/code/modules/hydroponics/seed_extractor.dm b/code/modules/hydroponics/seed_extractor.dm index 63b96632e6..71701d9637 100644 --- a/code/modules/hydroponics/seed_extractor.dm +++ b/code/modules/hydroponics/seed_extractor.dm @@ -1,3 +1,18 @@ +/** + * Finds and extracts seeds from an object + * + * Checks if the object is such that creates a seed when extracted. Used by seed + * extractors or posably anything that would create seeds in some way. The seeds + * are dropped either at the extractor, if it exists, or where the original object + * was and it qdel's the object + * + * Arguments: + * * O - Object containing the seed, can be the loc of the dumping of seeds + * * t_max - Amount of seed copies to dump, -1 is ranomized + * * extractor - Seed Extractor, used as the dumping loc for the seeds and seed multiplier + * * user - checks if we can remove the object from the inventory + * * + */ /proc/seedify(obj/item/O, t_max, obj/machinery/seed_extractor/extractor, mob/living/user) var/t_amount = 0 var/list/seeds = list() @@ -46,20 +61,22 @@ icon_state = "sextractor" density = TRUE circuit = /obj/item/circuitboard/machine/seed_extractor - var/piles = list() + /// Associated list of seeds, they are all weak refs. We check the len to see how many refs we have for each + // seed + var/list/piles = list() var/max_seeds = 1000 var/seed_multiplier = 1 /obj/machinery/seed_extractor/RefreshParts() for(var/obj/item/stock_parts/matter_bin/B in component_parts) - max_seeds = 1000 * B.rating + max_seeds = initial(max_seeds) * B.rating for(var/obj/item/stock_parts/manipulator/M in component_parts) - seed_multiplier = M.rating + seed_multiplier = initial(seed_multiplier) * M.rating /obj/machinery/seed_extractor/examine(mob/user) . = ..() if(in_range(user, src) || isobserver(user)) - . += "The status display reads: Extracting [seed_multiplier] seed(s) per piece of produce.
Machine can store up to [max_seeds] seeds.
" + . += "The status display reads: Extracting [seed_multiplier] seed(s) per piece of produce.
Machine can store up to [max_seeds]% seeds.
" /obj/machinery/seed_extractor/attackby(obj/item/O, mob/user, params) @@ -102,78 +119,26 @@ else return ..() -/datum/seed_pile - var/name = "" - var/lifespan = 0 //Saved stats - var/endurance = 0 - var/maturation = 0 - var/production = 0 - var/yield = 0 - var/potency = 0 - var/amount = 0 +/** + * Generate seed string + * + * Creates a string based of the traits of a seed. We use this string as a bucket for all + * seeds that match as well as the key the ui uses to get the seed. We also use the key + * for the data shown in the ui. Javascript parses this string to display + * + * Arguments: + * * O - seed to generate the string from + */ +/obj/machinery/seed_extractor/proc/generate_seed_string(obj/item/seeds/O) + return "name=[O.name];lifespan=[O.lifespan];endurance=[O.endurance];maturation=[O.maturation];production=[O.production];yield=[O.yield];potency=[O.potency];instability=0" -/datum/seed_pile/New(var/name, var/life, var/endur, var/matur, var/prod, var/yie, var/poten, var/am = 1) - src.name = name - src.lifespan = life - src.endurance = endur - src.maturation = matur - src.production = prod - src.yield = yie - src.potency = poten - src.amount = am - -/obj/machinery/seed_extractor/ui_interact(mob/user) - . = ..() - if (stat) - return FALSE - - var/dat = "Stored seeds:
" - - if (contents.len == 0) - dat += "No seeds" - else - dat += "" - for (var/datum/seed_pile/O in piles) - dat += "" - dat += "" - dat += "
NameLifespanEnduranceMaturationProductionYieldPotencyStock
[O.name][O.lifespan][O.endurance][O.maturation][O.production][O.yield][O.potency]" - dat += "Vend ([O.amount] left)
" - var/datum/browser/popup = new(user, "seed_ext", name, 700, 400) - popup.set_content(dat) - popup.open() - return - -/obj/machinery/seed_extractor/Topic(var/href, var/list/href_list) - if(..()) - return - usr.set_machine(src) - - href_list["li"] = text2num(href_list["li"]) - href_list["en"] = text2num(href_list["en"]) - href_list["ma"] = text2num(href_list["ma"]) - href_list["pr"] = text2num(href_list["pr"]) - href_list["yi"] = text2num(href_list["yi"]) - href_list["pot"] = text2num(href_list["pot"]) - - for (var/datum/seed_pile/N in piles)//Find the pile we need to reduce... - if (href_list["name"] == N.name && href_list["li"] == N.lifespan && href_list["en"] == N.endurance && href_list["ma"] == N.maturation && href_list["pr"] == N.production && href_list["yi"] == N.yield && href_list["pot"] == N.potency) - if(N.amount <= 0) - return - N.amount = max(N.amount - 1, 0) - if (N.amount <= 0) - piles -= N - qdel(N) - break - - for (var/obj/T in contents)//Now we find the seed we need to vend - var/obj/item/seeds/O = T - if (O.plantname == href_list["name"] && O.lifespan == href_list["li"] && O.endurance == href_list["en"] && O.maturation == href_list["ma"] && O.production == href_list["pr"] && O.yield == href_list["yi"] && O.potency == href_list["pot"]) - O.forceMove(drop_location()) - break - - src.updateUsrDialog() - return +/** Add Seeds Proc. + * + * Adds the seeds to the contents and to an associated list that pregenerates the data + * needed to go to the ui handler + * + **/ /obj/machinery/seed_extractor/proc/add_seed(obj/item/seeds/O) if(contents.len >= 999) to_chat(usr, "\The [src] is full.") @@ -188,10 +153,47 @@ if(!M.transferItemToLoc(O, src)) return FALSE - . = TRUE - for (var/datum/seed_pile/N in piles) - if (O.plantname == N.name && O.lifespan == N.lifespan && O.endurance == N.endurance && O.maturation == N.maturation && O.production == N.production && O.yield == N.yield && O.potency == N.potency) - ++N.amount - return + var/seed_string = generate_seed_string(O) + if(piles[seed_string]) + piles[seed_string] += WEAKREF(O) + else + piles[seed_string] = list(WEAKREF(O)) + + . = TRUE + +/obj/machinery/seed_extractor/ui_state(mob/user) + return GLOB.notcontained_state + +/obj/machinery/seed_extractor/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "SeedExtractor", name) + ui.open() + +/obj/machinery/seed_extractor/ui_data() + var/list/V = list() + for(var/key in piles) + if(piles[key]) + var/len = length(piles[key]) + if(len) + V[key] = len + + . = list() + .["seeds"] = V + +/obj/machinery/seed_extractor/ui_act(action, params) + if(..()) + return + + switch(action) + if("select") + var/item = params["item"] + if(piles[item] && length(piles[item]) > 0) + var/datum/weakref/WO = piles[item][1] + var/obj/item/seeds/O = WO.resolve() + if(O) + piles[item] -= WO + O.forceMove(drop_location()) + . = TRUE + //to_chat(usr, "[src] clanks to life briefly before vending [prize.equipment_name]!") - piles += new /datum/seed_pile(O.plantname, O.lifespan, O.endurance, O.maturation, O.production, O.yield, O.potency) diff --git a/code/modules/hydroponics/seeds.dm b/code/modules/hydroponics/seeds.dm index 5e49a32a23..c7314bf180 100644 --- a/code/modules/hydroponics/seeds.dm +++ b/code/modules/hydroponics/seeds.dm @@ -190,6 +190,31 @@ obj/item/seeds/proc/is_gene_forbidden(typepath) parent.update_tray(user) return result +/obj/item/seeds/proc/harvest_userless() + var/obj/machinery/hydroponics/parent = loc //for ease of access + var/t_amount = 0 + var/list/result = list() + var/output_loc = parent.loc + var/product_name + while(t_amount < getYield()) + var/obj/item/reagent_containers/food/snacks/grown/t_prod = new product(output_loc, src) + if(parent.myseed.plantname != initial(parent.myseed.plantname)) + t_prod.name = lowertext(parent.myseed.plantname) + if(productdesc) + t_prod.desc = productdesc + t_prod.seed.name = parent.myseed.name + t_prod.seed.desc = parent.myseed.desc + t_prod.seed.plantname = parent.myseed.plantname + result.Add(t_prod) // User gets a consumable + if(!t_prod) + return + t_amount++ + product_name = parent.myseed.plantname + if(getYield() >= 1) + SSblackbox.record_feedback("tally", "food_harvested", getYield(), product_name) + parent.investigate_log("autmoatic harvest of [getYield()] of [src], with seed traits [english_list(genes)] and reagents_add [english_list(reagents_add)] and potency [potency].", INVESTIGATE_BOTANY) + parent.update_tray() + return result /obj/item/seeds/proc/prepare_result(var/obj/item/reagent_containers/food/snacks/grown/T) if(!T.reagents) diff --git a/code/modules/jobs/job_types/_job.dm b/code/modules/jobs/job_types/_job.dm index bd36218211..1238b37919 100644 --- a/code/modules/jobs/job_types/_job.dm +++ b/code/modules/jobs/job_types/_job.dm @@ -46,6 +46,7 @@ var/minimal_player_age = 0 var/outfit = null + var/plasma_outfit = null //the outfit given to plasmamen var/exp_requirements = 0 diff --git a/code/modules/jobs/job_types/atmospheric_technician.dm b/code/modules/jobs/job_types/atmospheric_technician.dm index 1962b8e8a9..bff56d1d16 100644 --- a/code/modules/jobs/job_types/atmospheric_technician.dm +++ b/code/modules/jobs/job_types/atmospheric_technician.dm @@ -12,6 +12,7 @@ exp_type = EXP_TYPE_CREW outfit = /datum/outfit/job/atmos + plasma_outfit = /datum/outfit/plasmaman/atmospherics access = list(ACCESS_ENGINE, ACCESS_ENGINE_EQUIP, ACCESS_TECH_STORAGE, ACCESS_MAINT_TUNNELS, ACCESS_EXTERNAL_AIRLOCKS, ACCESS_CONSTRUCTION, ACCESS_ATMOSPHERICS, ACCESS_MINERAL_STOREROOM) diff --git a/code/modules/jobs/job_types/bartender.dm b/code/modules/jobs/job_types/bartender.dm index e5cd015460..8290adbbd7 100644 --- a/code/modules/jobs/job_types/bartender.dm +++ b/code/modules/jobs/job_types/bartender.dm @@ -11,6 +11,7 @@ exp_type_department = EXP_TYPE_SERVICE // This is so the jobs menu can work properly outfit = /datum/outfit/job/bartender + plasma_outfit = /datum/outfit/plasmaman/bar access = list(ACCESS_HYDROPONICS, ACCESS_BAR, ACCESS_KITCHEN, ACCESS_MORGUE, ACCESS_WEAPONS, ACCESS_MINERAL_STOREROOM) minimal_access = list(ACCESS_BAR, ACCESS_MINERAL_STOREROOM) diff --git a/code/modules/jobs/job_types/botanist.dm b/code/modules/jobs/job_types/botanist.dm index 65f3e7ca48..4c91f87791 100644 --- a/code/modules/jobs/job_types/botanist.dm +++ b/code/modules/jobs/job_types/botanist.dm @@ -10,6 +10,7 @@ selection_color = "#bbe291" outfit = /datum/outfit/job/botanist + plasma_outfit = /datum/outfit/plasmaman/botany access = list(ACCESS_HYDROPONICS, ACCESS_BAR, ACCESS_KITCHEN, ACCESS_MORGUE, ACCESS_MINERAL_STOREROOM) minimal_access = list(ACCESS_HYDROPONICS, ACCESS_MORGUE, ACCESS_MINERAL_STOREROOM) diff --git a/code/modules/jobs/job_types/captain.dm b/code/modules/jobs/job_types/captain.dm index 3733658c33..047a07062d 100644 --- a/code/modules/jobs/job_types/captain.dm +++ b/code/modules/jobs/job_types/captain.dm @@ -17,6 +17,7 @@ outfit = /datum/outfit/job/captain + plasma_outfit = /datum/outfit/plasmaman/captain access = list() //See get_access() minimal_access = list() //See get_access() diff --git a/code/modules/jobs/job_types/cargo_technician.dm b/code/modules/jobs/job_types/cargo_technician.dm index 840af56a0e..1f87a5265d 100644 --- a/code/modules/jobs/job_types/cargo_technician.dm +++ b/code/modules/jobs/job_types/cargo_technician.dm @@ -10,6 +10,7 @@ selection_color = "#ca8f55" outfit = /datum/outfit/job/cargo_tech + plasma_outfit = /datum/outfit/plasmaman/cargo access = list(ACCESS_MAINT_TUNNELS, ACCESS_MAILSORTING, ACCESS_CARGO, ACCESS_CARGO_BOT, ACCESS_MINING, ACCESS_MINING_STATION, ACCESS_MINERAL_STOREROOM) diff --git a/code/modules/jobs/job_types/chaplain.dm b/code/modules/jobs/job_types/chaplain.dm index 5f66519365..a9e891a303 100644 --- a/code/modules/jobs/job_types/chaplain.dm +++ b/code/modules/jobs/job_types/chaplain.dm @@ -10,6 +10,7 @@ selection_color = "#dddddd" outfit = /datum/outfit/job/chaplain + plasma_outfit = /datum/outfit/plasmaman/chaplain access = list(ACCESS_MORGUE, ACCESS_CHAPEL_OFFICE, ACCESS_CREMATORIUM, ACCESS_THEATRE) minimal_access = list(ACCESS_MORGUE, ACCESS_CHAPEL_OFFICE, ACCESS_CREMATORIUM, ACCESS_THEATRE) diff --git a/code/modules/jobs/job_types/chemist.dm b/code/modules/jobs/job_types/chemist.dm index b2699071e3..6d4204d041 100644 --- a/code/modules/jobs/job_types/chemist.dm +++ b/code/modules/jobs/job_types/chemist.dm @@ -12,6 +12,7 @@ exp_requirements = 60 outfit = /datum/outfit/job/chemist + plasma_outfit = /datum/outfit/plasmaman/chemist access = list(ACCESS_MEDICAL, ACCESS_MORGUE, ACCESS_SURGERY, ACCESS_CHEMISTRY, ACCESS_VIROLOGY, ACCESS_GENETICS, ACCESS_CLONING, ACCESS_MINERAL_STOREROOM) minimal_access = list(ACCESS_MEDICAL, ACCESS_MORGUE, ACCESS_CHEMISTRY, ACCESS_MINERAL_STOREROOM) diff --git a/code/modules/jobs/job_types/chief_engineer.dm b/code/modules/jobs/job_types/chief_engineer.dm index d8df767a9f..18be8c9835 100644 --- a/code/modules/jobs/job_types/chief_engineer.dm +++ b/code/modules/jobs/job_types/chief_engineer.dm @@ -17,6 +17,7 @@ exp_type_department = EXP_TYPE_ENGINEERING outfit = /datum/outfit/job/ce + plasma_outfit = /datum/outfit/plasmaman/ce access = list(ACCESS_ENGINE, ACCESS_ENGINE_EQUIP, ACCESS_TECH_STORAGE, ACCESS_MAINT_TUNNELS, ACCESS_EXTERNAL_AIRLOCKS, ACCESS_ATMOSPHERICS, ACCESS_EVA, diff --git a/code/modules/jobs/job_types/chief_medical_officer.dm b/code/modules/jobs/job_types/chief_medical_officer.dm index 9cbc15ca28..627a7a2ca1 100644 --- a/code/modules/jobs/job_types/chief_medical_officer.dm +++ b/code/modules/jobs/job_types/chief_medical_officer.dm @@ -17,6 +17,7 @@ exp_type_department = EXP_TYPE_MEDICAL outfit = /datum/outfit/job/cmo + plasma_outfit = /datum/outfit/plasmaman/cmo access = list(ACCESS_MEDICAL, ACCESS_MORGUE, ACCESS_GENETICS, ACCESS_CLONING, ACCESS_HEADS, ACCESS_MINERAL_STOREROOM, ACCESS_CHEMISTRY, ACCESS_VIROLOGY, ACCESS_CMO, ACCESS_SURGERY, ACCESS_RC_ANNOUNCE, diff --git a/code/modules/jobs/job_types/clown.dm b/code/modules/jobs/job_types/clown.dm index 7ad7148614..dc2f60434c 100644 --- a/code/modules/jobs/job_types/clown.dm +++ b/code/modules/jobs/job_types/clown.dm @@ -10,6 +10,7 @@ selection_color = "#dddddd" outfit = /datum/outfit/job/clown + plasma_outfit = /datum/outfit/plasmaman/clown access = list(ACCESS_THEATRE) minimal_access = list(ACCESS_THEATRE) diff --git a/code/modules/jobs/job_types/cook.dm b/code/modules/jobs/job_types/cook.dm index 5a5916cb7e..666ee8f036 100644 --- a/code/modules/jobs/job_types/cook.dm +++ b/code/modules/jobs/job_types/cook.dm @@ -11,6 +11,7 @@ var/cooks = 0 //Counts cooks amount outfit = /datum/outfit/job/cook + plasma_outfit = /datum/outfit/plasmaman/chef access = list(ACCESS_HYDROPONICS, ACCESS_BAR, ACCESS_KITCHEN, ACCESS_MORGUE, ACCESS_MINERAL_STOREROOM) minimal_access = list(ACCESS_KITCHEN, ACCESS_MORGUE, ACCESS_MINERAL_STOREROOM) diff --git a/code/modules/jobs/job_types/curator.dm b/code/modules/jobs/job_types/curator.dm index 47bfd4914a..254fc15bd4 100644 --- a/code/modules/jobs/job_types/curator.dm +++ b/code/modules/jobs/job_types/curator.dm @@ -10,6 +10,7 @@ selection_color = "#dddddd" outfit = /datum/outfit/job/curator + plasma_outfit = /datum/outfit/plasmaman/curator access = list(ACCESS_LIBRARY) minimal_access = list(ACCESS_LIBRARY, ACCESS_CONSTRUCTION, ACCESS_MINING_STATION) diff --git a/code/modules/jobs/job_types/detective.dm b/code/modules/jobs/job_types/detective.dm index 463113f14c..65724765e1 100644 --- a/code/modules/jobs/job_types/detective.dm +++ b/code/modules/jobs/job_types/detective.dm @@ -14,6 +14,7 @@ exp_type = EXP_TYPE_CREW outfit = /datum/outfit/job/detective + plasma_outfit = /datum/outfit/plasmaman/detective access = list(ACCESS_SEC_DOORS, ACCESS_FORENSICS_LOCKERS, ACCESS_MORGUE, ACCESS_MAINT_TUNNELS, ACCESS_COURT, ACCESS_BRIG, ACCESS_WEAPONS, ACCESS_MINERAL_STOREROOM) minimal_access = list(ACCESS_SEC_DOORS, ACCESS_FORENSICS_LOCKERS, ACCESS_MORGUE, ACCESS_MAINT_TUNNELS, ACCESS_COURT, ACCESS_BRIG, ACCESS_WEAPONS, ACCESS_MINERAL_STOREROOM) diff --git a/code/modules/jobs/job_types/geneticist.dm b/code/modules/jobs/job_types/geneticist.dm index a40ca0fca3..5ff1bebfbf 100644 --- a/code/modules/jobs/job_types/geneticist.dm +++ b/code/modules/jobs/job_types/geneticist.dm @@ -12,6 +12,7 @@ exp_requirements = 60 outfit = /datum/outfit/job/geneticist + plasma_outfit = /datum/outfit/plasmaman/genetics access = list(ACCESS_MEDICAL, ACCESS_MORGUE, ACCESS_CHEMISTRY, ACCESS_GENETICS, ACCESS_CLONING, ACCESS_RESEARCH, ACCESS_XENOBIOLOGY, ACCESS_ROBOTICS, ACCESS_MINERAL_STOREROOM, ACCESS_TECH_STORAGE) minimal_access = list(ACCESS_MEDICAL, ACCESS_MORGUE, ACCESS_GENETICS, ACCESS_CLONING, ACCESS_RESEARCH, ACCESS_MINERAL_STOREROOM) diff --git a/code/modules/jobs/job_types/head_of_personnel.dm b/code/modules/jobs/job_types/head_of_personnel.dm index 8015c19c36..41fb4b99da 100644 --- a/code/modules/jobs/job_types/head_of_personnel.dm +++ b/code/modules/jobs/job_types/head_of_personnel.dm @@ -17,6 +17,7 @@ exp_type_department = EXP_TYPE_SERVICE outfit = /datum/outfit/job/hop + plasma_outfit = /datum/outfit/plasmaman/hop access = list(ACCESS_SECURITY, ACCESS_SEC_DOORS, ACCESS_COURT, ACCESS_WEAPONS, ACCESS_MEDICAL, ACCESS_ENGINE, ACCESS_CHANGE_IDS, ACCESS_AI_UPLOAD, ACCESS_EVA, ACCESS_HEADS, diff --git a/code/modules/jobs/job_types/head_of_security.dm b/code/modules/jobs/job_types/head_of_security.dm index 3d7d07d894..cfd8d7f6c0 100644 --- a/code/modules/jobs/job_types/head_of_security.dm +++ b/code/modules/jobs/job_types/head_of_security.dm @@ -17,6 +17,8 @@ exp_type_department = EXP_TYPE_SECURITY outfit = /datum/outfit/job/hos + plasma_outfit = /datum/outfit/plasmaman/hos + mind_traits = list(TRAIT_LAW_ENFORCEMENT_METABOLISM) access = list(ACCESS_SECURITY, ACCESS_SEC_DOORS, ACCESS_BRIG, ACCESS_ARMORY, ACCESS_COURT, ACCESS_WEAPONS, ACCESS_ENTER_GENPOP, ACCESS_LEAVE_GENPOP, diff --git a/code/modules/jobs/job_types/janitor.dm b/code/modules/jobs/job_types/janitor.dm index 2f6d6f0e32..c62c2e5b26 100644 --- a/code/modules/jobs/job_types/janitor.dm +++ b/code/modules/jobs/job_types/janitor.dm @@ -10,6 +10,7 @@ selection_color = "#bbe291" outfit = /datum/outfit/job/janitor + plasma_outfit = /datum/outfit/plasmaman/janitor access = list(ACCESS_JANITOR, ACCESS_MAINT_TUNNELS, ACCESS_MINERAL_STOREROOM) minimal_access = list(ACCESS_JANITOR, ACCESS_MAINT_TUNNELS, ACCESS_MINERAL_STOREROOM) diff --git a/code/modules/jobs/job_types/lawyer.dm b/code/modules/jobs/job_types/lawyer.dm index 1a7499800b..17c376a5de 100644 --- a/code/modules/jobs/job_types/lawyer.dm +++ b/code/modules/jobs/job_types/lawyer.dm @@ -11,6 +11,7 @@ var/lawyers = 0 //Counts lawyer amount outfit = /datum/outfit/job/lawyer + plasma_outfit = /datum/outfit/plasmaman/bar //yes, this is correct, there's no 'lawyer' plasmeme outfit access = list(ACCESS_LAWYER, ACCESS_COURT, ACCESS_SEC_DOORS) minimal_access = list(ACCESS_LAWYER, ACCESS_COURT, ACCESS_SEC_DOORS) diff --git a/code/modules/jobs/job_types/medical_doctor.dm b/code/modules/jobs/job_types/medical_doctor.dm index 5ec4b83b2f..d6a763acfe 100644 --- a/code/modules/jobs/job_types/medical_doctor.dm +++ b/code/modules/jobs/job_types/medical_doctor.dm @@ -10,6 +10,7 @@ selection_color = "#74b5e0" outfit = /datum/outfit/job/doctor + plasma_outfit = /datum/outfit/plasmaman/medical access = list(ACCESS_MEDICAL, ACCESS_MORGUE, ACCESS_SURGERY, ACCESS_CHEMISTRY, ACCESS_GENETICS, ACCESS_CLONING, ACCESS_VIROLOGY, ACCESS_MINERAL_STOREROOM) minimal_access = list(ACCESS_MEDICAL, ACCESS_MORGUE, ACCESS_SURGERY, ACCESS_CLONING, ACCESS_MINERAL_STOREROOM) diff --git a/code/modules/jobs/job_types/mime.dm b/code/modules/jobs/job_types/mime.dm index 4ba2489ab2..e00b3a1e29 100644 --- a/code/modules/jobs/job_types/mime.dm +++ b/code/modules/jobs/job_types/mime.dm @@ -10,6 +10,7 @@ selection_color = "#dddddd" outfit = /datum/outfit/job/mime + plasma_outfit = /datum/outfit/plasmaman/mime access = list(ACCESS_THEATRE) minimal_access = list(ACCESS_THEATRE) diff --git a/code/modules/jobs/job_types/research_director.dm b/code/modules/jobs/job_types/research_director.dm index 7128fbe2c7..33f7df8260 100644 --- a/code/modules/jobs/job_types/research_director.dm +++ b/code/modules/jobs/job_types/research_director.dm @@ -17,6 +17,7 @@ exp_type = EXP_TYPE_CREW outfit = /datum/outfit/job/rd + plasma_outfit = /datum/outfit/plasmaman/rd access = list(ACCESS_RD, ACCESS_HEADS, ACCESS_TOX, ACCESS_GENETICS, ACCESS_MORGUE, ACCESS_TOX_STORAGE, ACCESS_TELEPORTER, ACCESS_SEC_DOORS, diff --git a/code/modules/jobs/job_types/roboticist.dm b/code/modules/jobs/job_types/roboticist.dm index f5ae93bb6a..aa52b353df 100644 --- a/code/modules/jobs/job_types/roboticist.dm +++ b/code/modules/jobs/job_types/roboticist.dm @@ -12,6 +12,7 @@ exp_type = EXP_TYPE_CREW outfit = /datum/outfit/job/roboticist + plasma_outfit = /datum/outfit/plasmaman/robotics access = list(ACCESS_ROBOTICS, ACCESS_TOX, ACCESS_TOX_STORAGE, ACCESS_TECH_STORAGE, ACCESS_MORGUE, ACCESS_RESEARCH, ACCESS_MINERAL_STOREROOM, ACCESS_XENOBIOLOGY, ACCESS_GENETICS) minimal_access = list(ACCESS_ROBOTICS, ACCESS_TECH_STORAGE, ACCESS_MORGUE, ACCESS_RESEARCH, ACCESS_MINERAL_STOREROOM) diff --git a/code/modules/jobs/job_types/scientist.dm b/code/modules/jobs/job_types/scientist.dm index 476f740b9d..a851b333fe 100644 --- a/code/modules/jobs/job_types/scientist.dm +++ b/code/modules/jobs/job_types/scientist.dm @@ -12,6 +12,7 @@ exp_type = EXP_TYPE_CREW outfit = /datum/outfit/job/scientist + plasma_outfit = /datum/outfit/plasmaman/science access = list(ACCESS_ROBOTICS, ACCESS_TOX, ACCESS_TOX_STORAGE, ACCESS_RESEARCH, ACCESS_XENOBIOLOGY, ACCESS_MINERAL_STOREROOM, ACCESS_TECH_STORAGE, ACCESS_GENETICS) minimal_access = list(ACCESS_TOX, ACCESS_TOX_STORAGE, ACCESS_RESEARCH, ACCESS_XENOBIOLOGY, ACCESS_MINERAL_STOREROOM) diff --git a/code/modules/jobs/job_types/security_officer.dm b/code/modules/jobs/job_types/security_officer.dm index 7e71b2d1f4..bc83eb752d 100644 --- a/code/modules/jobs/job_types/security_officer.dm +++ b/code/modules/jobs/job_types/security_officer.dm @@ -14,6 +14,7 @@ exp_type = EXP_TYPE_CREW outfit = /datum/outfit/job/security + plasma_outfit = /datum/outfit/plasmaman/security access = list(ACCESS_SECURITY, ACCESS_SEC_DOORS, ACCESS_BRIG, ACCESS_COURT, ACCESS_MAINT_TUNNELS, ACCESS_MORGUE, ACCESS_WEAPONS, ACCESS_ENTER_GENPOP, ACCESS_LEAVE_GENPOP, ACCESS_FORENSICS_LOCKERS, ACCESS_MINERAL_STOREROOM) minimal_access = list(ACCESS_SECURITY, ACCESS_SEC_DOORS, ACCESS_BRIG, ACCESS_COURT, ACCESS_WEAPONS, ACCESS_ENTER_GENPOP, ACCESS_LEAVE_GENPOP, ACCESS_MINERAL_STOREROOM) // See /datum/job/officer/get_access() diff --git a/code/modules/jobs/job_types/shaft_miner.dm b/code/modules/jobs/job_types/shaft_miner.dm index ebf7ba0f1f..04d3fb53b8 100644 --- a/code/modules/jobs/job_types/shaft_miner.dm +++ b/code/modules/jobs/job_types/shaft_miner.dm @@ -12,6 +12,7 @@ outfit = /datum/outfit/job/miner + plasma_outfit = /datum/outfit/plasmaman/mining access = list(ACCESS_MAINT_TUNNELS, ACCESS_MAILSORTING, ACCESS_CARGO, ACCESS_CARGO_BOT, ACCESS_MINING, ACCESS_MINING_STATION, ACCESS_MINERAL_STOREROOM) diff --git a/code/modules/jobs/job_types/station_engineer.dm b/code/modules/jobs/job_types/station_engineer.dm index d3f5db7dbb..2396728ad8 100644 --- a/code/modules/jobs/job_types/station_engineer.dm +++ b/code/modules/jobs/job_types/station_engineer.dm @@ -12,6 +12,7 @@ exp_type = EXP_TYPE_CREW outfit = /datum/outfit/job/engineer + plasma_outfit = /datum/outfit/plasmaman/engineering access = list(ACCESS_ENGINE, ACCESS_ENGINE_EQUIP, ACCESS_TECH_STORAGE, ACCESS_MAINT_TUNNELS, ACCESS_EXTERNAL_AIRLOCKS, ACCESS_CONSTRUCTION, ACCESS_ATMOSPHERICS, ACCESS_TCOMSAT, ACCESS_MINERAL_STOREROOM) diff --git a/code/modules/jobs/job_types/virologist.dm b/code/modules/jobs/job_types/virologist.dm index 790e828931..3e9b3ba06c 100644 --- a/code/modules/jobs/job_types/virologist.dm +++ b/code/modules/jobs/job_types/virologist.dm @@ -12,6 +12,7 @@ exp_requirements = 60 outfit = /datum/outfit/job/virologist + plasma_outfit = /datum/outfit/plasmaman/viro access = list(ACCESS_MEDICAL, ACCESS_MORGUE, ACCESS_SURGERY, ACCESS_CHEMISTRY, ACCESS_VIROLOGY, ACCESS_GENETICS, ACCESS_CLONING, ACCESS_MINERAL_STOREROOM) minimal_access = list(ACCESS_MEDICAL, ACCESS_VIROLOGY, ACCESS_MINERAL_STOREROOM) diff --git a/code/modules/jobs/job_types/warden.dm b/code/modules/jobs/job_types/warden.dm index 22e3f9b0f1..c909342d6f 100644 --- a/code/modules/jobs/job_types/warden.dm +++ b/code/modules/jobs/job_types/warden.dm @@ -14,6 +14,7 @@ exp_type = EXP_TYPE_CREW outfit = /datum/outfit/job/warden + plasma_outfit = /datum/outfit/plasmaman/warden access = list(ACCESS_SECURITY, ACCESS_SEC_DOORS, ACCESS_BRIG, ACCESS_ARMORY, ACCESS_COURT, ACCESS_MAINT_TUNNELS, ACCESS_MORGUE, ACCESS_WEAPONS, ACCESS_ENTER_GENPOP, ACCESS_LEAVE_GENPOP, ACCESS_FORENSICS_LOCKERS, ACCESS_MINERAL_STOREROOM) minimal_access = list(ACCESS_SECURITY, ACCESS_SEC_DOORS, ACCESS_BRIG, ACCESS_ARMORY, ACCESS_COURT, ACCESS_WEAPONS, ACCESS_ENTER_GENPOP, ACCESS_LEAVE_GENPOP, ACCESS_MINERAL_STOREROOM) // See /datum/job/warden/get_access() diff --git a/code/modules/language/language_holder.dm b/code/modules/language/language_holder.dm index 55e9352843..c1677117e9 100644 --- a/code/modules/language/language_holder.dm +++ b/code/modules/language/language_holder.dm @@ -324,6 +324,12 @@ Key procs /datum/language/sylvan = list(LANGUAGE_ATOM)) spoken_languages = list(/datum/language/sylvan = list(LANGUAGE_ATOM)) +/datum/language_holder/ethereal + understood_languages = list(/datum/language/common = list(LANGUAGE_ATOM), + /datum/language/voltaic = list(LANGUAGE_ATOM)) + spoken_languages = list(/datum/language/common = list(LANGUAGE_ATOM), + /datum/language/voltaic = list(LANGUAGE_ATOM)) + /datum/language_holder/empty understood_languages = list() spoken_languages = list() diff --git a/code/modules/language/language_menu.dm b/code/modules/language/language_menu.dm index 0df7c01fca..bffd3d59af 100644 --- a/code/modules/language/language_menu.dm +++ b/code/modules/language/language_menu.dm @@ -8,10 +8,13 @@ language_holder = null . = ..() -/datum/language_menu/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.language_menu_state) - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) +/datum/language_menu/ui_state(mob/user) + return GLOB.language_menu_state + +/datum/language_menu/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) if(!ui) - ui = new(user, src, ui_key, "LanguageMenu", "Language Menu", 700, 600, master_ui, state) + ui = new(user, src, "LanguageMenu") ui.open() /datum/language_menu/ui_data(mob/user) diff --git a/code/modules/language/voltaic.dm b/code/modules/language/voltaic.dm new file mode 100644 index 0000000000..ead7fe7c7f --- /dev/null +++ b/code/modules/language/voltaic.dm @@ -0,0 +1,14 @@ +// One of these languages will actually work, I'm certain of it. +/datum/language/voltaic + name = "Voltaic" + desc = "A sparky language made by manipulating electrical discharge." + key = "v" + space_chance = 20 + syllables = list( + "bzzt", "skrrt", "zzp", "mmm", "hzz", "tk", "shz", "k", "z", + "bzt", "zzt", "skzt", "skzz", "hmmt", "zrrt", "hzzt", "hz", + "vzt", "zt", "vz", "zip", "tzp", "lzzt", "dzzt", "zdt", "kzt", + "zzzz", "mzz" + ) + icon_state = "volt" + default_priority = 90 diff --git a/code/modules/library/lib_codex_gigas.dm b/code/modules/library/lib_codex_gigas.dm index 146c4221f8..26fa5b6f3d 100644 --- a/code/modules/library/lib_codex_gigas.dm +++ b/code/modules/library/lib_codex_gigas.dm @@ -34,13 +34,13 @@ if(U.check_acedia()) to_chat(user, "None of this matters, why are you reading this? You put [title] down.") return - user.visible_message("[user] opens [title] and begins reading intently.") + user.visible_message("[user] opens [title] and begins reading intently.") ask_name(user) /obj/item/book/codex_gigas/proc/perform_research(mob/user, devilName) if(!devilName) - user.visible_message("[user] closes [title] without looking anything up.") + user.visible_message("[user] closes [title] without looking anything up.") return inUse = TRUE var/speed = 300 @@ -50,7 +50,7 @@ if(U.job in list("Curator")) // the curator is both faster, and more accurate than normal crew members at research speed = 100 correctness = 100 - correctness -= U.getOrganLoss(ORGAN_SLOT_BRAIN) *0.5 //Brain damage makes researching hard. + correctness -= U.getOrganLoss(ORGAN_SLOT_BRAIN) * 0.5 //Brain damage makes researching hard. speed += U.getOrganLoss(ORGAN_SLOT_BRAIN) * 3 if(do_after(user, speed, 0, user)) var/usedName = devilName @@ -95,11 +95,10 @@ currentSection = SUFFIX return currentSection != oldSection -/obj/item/book/codex_gigas/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ - datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) +/obj/item/book/codex_gigas/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) if(!ui) - ui = new(user, src, ui_key, "CodexGigas", name, 450, 450, master_ui, state) + ui = new(user, src, "CodexGigas", name) ui.open() /obj/item/book/codex_gigas/ui_data(mob/user) diff --git a/code/modules/library/soapstone.dm b/code/modules/library/soapstone.dm index 50f984c44d..f17040a938 100644 --- a/code/modules/library/soapstone.dm +++ b/code/modules/library/soapstone.dm @@ -35,13 +35,13 @@ return if(existing_message) - user.visible_message("[user] starts erasing [existing_message].", "You start erasing [existing_message].", "You hear a chipping sound.") - playsound(loc, 'sound/items/gavel.ogg', 50, 1, -1) + user.visible_message("[user] starts erasing [existing_message].", "You start erasing [existing_message].", "You hear a chipping sound.") + playsound(loc, 'sound/items/gavel.ogg', 50, TRUE, -1) if(do_after(user, tool_speed, target = existing_message)) user.visible_message("[user] erases [existing_message].", "You erase [existing_message][existing_message.creator_key == user.ckey ? ", refunding a use" : ""].") existing_message.persists = FALSE qdel(existing_message) - playsound(loc, 'sound/items/gavel.ogg', 50, 1, -1) + playsound(loc, 'sound/items/gavel.ogg', 50, TRUE, -1) if(existing_message.creator_key == user.ckey) refund_use() return @@ -54,12 +54,12 @@ if(!target.Adjacent(user) && locate(/obj/structure/chisel_message) in T) to_chat(user, "Someone wrote here before you chose! Find another spot.") return - playsound(loc, 'sound/items/gavel.ogg', 50, 1, -1) - user.visible_message("[user] starts engraving a message into [T]...", "You start engraving a message into [T]...", "You hear a chipping sound.") + playsound(loc, 'sound/items/gavel.ogg', 50, TRUE, -1) + user.visible_message("[user] starts engraving a message into [T]...", "You start engraving a message into [T]...", "You hear a chipping sound.") if(can_use() && do_after(user, tool_speed, target = T) && can_use()) //This looks messy but it's actually really clever! if(!locate(/obj/structure/chisel_message) in T) - user.visible_message("[user] leaves a message for future spacemen!", "You engrave a message into [T]!", "You hear a chipping sound.") - playsound(loc, 'sound/items/gavel.ogg', 50, 1, -1) + user.visible_message("[user] leaves a message for future spacemen!", "You engrave a message into [T]!", "You hear a chipping sound.") + playsound(loc, 'sound/items/gavel.ogg', 50, TRUE, -1) var/obj/structure/chisel_message/M = new(T) M.register(user, message) remove_use() @@ -112,12 +112,10 @@ desc = "A message from a past traveler." icon = 'icons/obj/stationobjs.dmi' icon_state = "soapstone_message" - layer = HIGH_OBJ_LAYER + layer = LATTICE_LAYER density = FALSE anchored = TRUE max_integrity = 30 - layer = LATTICE_LAYER - light_power = 0.3 var/hidden_message var/creator_key @@ -206,10 +204,13 @@ /obj/structure/chisel_message/interact() return -/obj/structure/chisel_message/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.always_state) - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) +/obj/structure/chisel_message/ui_state(mob/user) + return GLOB.always_state + +/obj/structure/chisel_message/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) if(!ui) - ui = new(user, src, ui_key, "EngravedMessage", name, 600, 300, master_ui, state) + ui = new(user, src, "EngravedMessage", name) ui.open() /obj/structure/chisel_message/ui_data(mob/user) diff --git a/code/modules/mafia/_defines.dm b/code/modules/mafia/_defines.dm new file mode 100644 index 0000000000..194851beed --- /dev/null +++ b/code/modules/mafia/_defines.dm @@ -0,0 +1,65 @@ +///how many people can play mafia without issues (running out of spawns, procs not expecting more than this amount of people, etc) +#define MAFIA_MAX_PLAYER_COUNT 12 + +#define MAFIA_TEAM_TOWN "town" +#define MAFIA_TEAM_MAFIA "mafia" +#define MAFIA_TEAM_SOLO "solo" + +//types of town roles for random setup gen +/// assistants it's just assistants filling up the rest of the roles +#define TOWN_OVERFLOW "overflow" +/// roles that learn info about others in the game (chaplain, detective, psych) +#define TOWN_INVEST "invest" +/// roles that keep other roles safe (doctor, and weirdly enough lawyer counts) +#define TOWN_PROTECT "protect" +/// roles that don't fit into anything else (hop) +#define TOWN_MISC "misc" + +//other types (mafia team, neutrals) +/// normal vote kill changelings +#define MAFIA_REGULAR "regular" +/// every other changeling role that has extra abilities +#define MAFIA_SPECIAL "special" +/// role that wins solo that nobody likes +#define NEUTRAL_KILL "kill" +/// role that upsets the game aka obsessed, usually worse for town than mafia but they can vote against mafia +#define NEUTRAL_DISRUPT "disrupt" + +#define MAFIA_PHASE_SETUP 1 +#define MAFIA_PHASE_DAY 2 +#define MAFIA_PHASE_VOTING 3 +#define MAFIA_PHASE_JUDGEMENT 4 +#define MAFIA_PHASE_NIGHT 5 +#define MAFIA_PHASE_VICTORY_LAP 6 + +#define MAFIA_ALIVE 1 +#define MAFIA_DEAD 2 + +#define COMSIG_MAFIA_ON_KILL "mafia_onkill" +#define MAFIA_PREVENT_KILL 1 + +#define COMSIG_MAFIA_CAN_PERFORM_ACTION "mafia_can_perform_action" +#define MAFIA_PREVENT_ACTION 1 + +//in order of events + game end + +/// when the shutters fall, before the 45 second wait and night event resolution +#define COMSIG_MAFIA_SUNDOWN "sundown" +/// after the 45 second wait, for actions that must go first +#define COMSIG_MAFIA_NIGHT_START "night_start" +/// most night actions now resolve +#define COMSIG_MAFIA_NIGHT_ACTION_PHASE "night_actions" +/// now killing happens from the roles that do that. the reason this is post action phase is to ensure doctors can protect and lawyers can block +#define COMSIG_MAFIA_NIGHT_KILL_PHASE "night_kill" +/// now undoing states like protection, actions that must happen last, etc. right before shutters raise and the day begins +#define COMSIG_MAFIA_NIGHT_END "night_end" + +/// signal sent to roles when the game is confirmed ending +#define COMSIG_MAFIA_GAME_END "game_end" + +/// list of ghosts who want to play mafia, every time someone enters the list it checks to see if enough are in +GLOBAL_LIST_EMPTY(mafia_signup) +/// list of ghosts who want to play mafia that have since disconnected. They are kept in the lobby, but not counted for starting a game. +GLOBAL_LIST_EMPTY(mafia_bad_signup) +/// the current global mafia game running. +GLOBAL_VAR(mafia_game) diff --git a/code/modules/mafia/controller.dm b/code/modules/mafia/controller.dm new file mode 100644 index 0000000000..cd8c382f30 --- /dev/null +++ b/code/modules/mafia/controller.dm @@ -0,0 +1,971 @@ + + +/** + * The mafia controller handles the mafia minigame in progress. + * It is first created when the first ghost signs up to play. + */ +/datum/mafia_controller + ///list of observers that should get game updates. + var/list/spectators = list() + ///all roles in the game, dead or alive. check their game status if you only want living or dead. + var/list/all_roles = list() + ///exists to speed up role retrieval, it's a dict. player_role_lookup[player ckey] will give you the role they play + var/list/player_role_lookup = list() + ///what part of the game you're playing in. day phases, night phases, judgement phases, etc. + var/phase = MAFIA_PHASE_SETUP + ///how long the game has gone on for, changes with every sunrise. day one, night one, day two, etc. + var/turn = 0 + ///for debugging and testing a full game, or adminbuse. If this is not null, it will use this as a setup. clears when game is over + var/list/custom_setup = list() + ///first day has no voting, and thus is shorter + var/first_day_phase_period = 20 SECONDS + ///talk with others about the last night + var/day_phase_period = 1 MINUTES + ///vote someone to get put on trial + var/voting_phase_period = 30 SECONDS + ///defend yourself! don't get lynched! sometimes skipped if nobody votes. + var/judgement_phase_period = 30 SECONDS + ///guilty or innocent, we want a bit of time for players to process the outcome of the vote + var/judgement_lynch_period = 5 SECONDS + ///mafia talk at night and pick someone to kill, some town roles use their actions, etc etc. + var/night_phase_period = 45 SECONDS + ///like the lynch period, players need to see what the other players in the game's roles were + var/victory_lap_period = 20 SECONDS + + ///template picked when the game starts. used for the name and desc reading + var/datum/map_template/mafia/current_map + ///map generation tool that deletes the current map after the game finishes + var/datum/mapGenerator/massdelete/map_deleter + + ///Readable list of roles in current game, sent to the tgui panel for roles list > list("Psychologist x1", "Clown x2") + var/list/current_setup_text + + ///starting outfit for all mafia players. it's just a grey jumpsuit. + var/player_outfit = /datum/outfit/mafia + + ///spawn points for players, each one has a house + var/list/landmarks = list() + ///town center for when people get put on trial + var/town_center_landmark + + ///group voting on one person, like putting people to trial or choosing who to kill as mafia + var/list/votes = list() + ///and these (judgement_innocent_votes, judgement_abstain_votes and judgement_guilty_votes) are the judgement phase votes, aka people sorting themselves into guilty and innocent, and "eh, i don't really care" lists. whichever has more inno or guilty wins! + var/list/judgement_abstain_votes = list() + var/list/judgement_innocent_votes = list() + var/list/judgement_guilty_votes = list() + ///current role on trial for the judgement phase, will die if guilty is greater than innocent + var/datum/mafia_role/on_trial + + ///current timer for phase + var/next_phase_timer + + ///used for debugging in testing (doesn't put people out of the game, some other shit i forgot, who knows just don't set this in live) honestly kinda deprecated + var/debug = FALSE + + ///Max player count + var/max_player = MAFIA_MAX_PLAYER_COUNT + ///Required player count + var/required_player = 5 + ///Prioritizes clients to have cool antag roles + var/low_pop_mode = FALSE + +/datum/mafia_controller/New() + . = ..() + GLOB.mafia_game = src + map_deleter = new + +/datum/mafia_controller/Destroy(force, ...) + . = ..() + GLOB.mafia_game = null + end_game() + qdel(map_deleter) + +/** + * Triggers at beginning of the game when there is a confirmed list of valid, ready players. + * Creates a 100% ready game that has NOT started (no players in bodies) + * Followed by start game + * + * Does the following: + * * Picks map, and loads it + * * Grabs landmarks if it is the first time it's loading + * * Sets up the role list + * * Puts players in each role randomly + * Arguments: + * * setup_list: list of all the datum setups (fancy list of roles) that would work for the game + * * ready_players: list of filtered, sane players (so not playing or disconnected) for the game to put into roles + */ +/datum/mafia_controller/proc/prepare_game(setup_list, ready_players) + + var/list/possible_maps = subtypesof(/datum/map_template/mafia) + var/turf/spawn_area = get_turf(locate(/obj/effect/landmark/mafia_game_area) in GLOB.landmarks_list) + + current_map = pick(possible_maps) + current_map = new current_map + + if(!spawn_area) + CRASH("No spawn area detected for Mafia!") + var/list/bounds = current_map.load(spawn_area) + if(!bounds) + CRASH("Loading mafia map failed!") + map_deleter.defineRegion(spawn_area, locate(spawn_area.x + 23,spawn_area.y + 23,spawn_area.z), replace = TRUE) //so we're ready to mass delete when round ends + + if(!landmarks.len)//we grab town center when we grab landmarks, if there is none (the first game signed up for let's grab them post load) + for(var/obj/effect/landmark/mafia/possible_spawn in GLOB.landmarks_list) + if(istype(possible_spawn, /obj/effect/landmark/mafia/town_center)) + town_center_landmark = possible_spawn + else + landmarks += possible_spawn + + current_setup_text = list() + + var/list/boring_roles = list() + var/list/not_boring_roles = list() + + for(var/rtype in setup_list) + for(var/i in 1 to setup_list[rtype]) + var/datum/mafia_role/role = new rtype(src) + all_roles += role + if(role.role_type == TOWN_PROTECT || role.role_type == TOWN_INVEST || role.role_type == MAFIA_SPECIAL || role.role_type == MAFIA_REGULAR) + not_boring_roles += role + else + boring_roles += role + var/datum/mafia_role/rp = rtype + current_setup_text += "[initial(rp.name)] x[setup_list[rtype]]" + + var/list/spawnpoints = landmarks.Copy() + + if(length(ready_players) < 7 || low_pop_mode) + //do normal assign + for(var/datum/mafia_role/role in not_boring_roles) + role.assigned_landmark = pick_n_take(spawnpoints) + role.player_key = pick_n_take(ready_players) + //shame! + for(var/datum/mafia_role/role in boring_roles) + role.assigned_landmark = pick_n_take(spawnpoints) + role.player_key = pick_n_take(ready_players) + + else //go run the normal one + for(var/datum/mafia_role/role in all_roles) + role.assigned_landmark = pick_n_take(spawnpoints) + if(!debug) + role.player_key = pick_n_take(ready_players) + else + role.player_key = pop(ready_players) + +/datum/mafia_controller/proc/send_message(msg,team) + for(var/datum/mafia_role/R in all_roles) + if(team && R.team != team) + continue + to_chat(R.body,msg) + var/team_suffix = team ? "([uppertext(team)] CHAT)" : "" + for(var/M in GLOB.dead_mob_list) + var/mob/spectator = M + if(spectator.ckey in spectators) //was in current game, or spectatin' (won't send to living) + var/link = FOLLOW_LINK(M, town_center_landmark) + to_chat(M, "[link] MAFIA: [msg] [team_suffix]") + +/** + * The game by this point is now all set up, and so we can put people in their bodies and start the first phase. + * + * Does the following: + * * Creates bodies for all of the roles with the first proc + * * Starts the first day manually (so no timer) with the second proc + */ +/datum/mafia_controller/proc/start_game() + create_bodies() + start_day() + +/** + * How every day starts. + * + * What players do in this phase: + * * If day one, just a small starting period to see who is in the game and check role, leading to the night phase. + * * Otherwise, it's a longer period used to discuss events that happened during the night, leading to the voting phase. + */ +/datum/mafia_controller/proc/start_day() + turn += 1 + phase = MAFIA_PHASE_DAY + if(!check_victory()) + if(turn == 1) + send_message("The selected map is [current_map.name]!
[current_map.description]
") + send_message("Day [turn] started! There is no voting on the first day. Say hello to everybody!") + next_phase_timer = addtimer(CALLBACK(src,.proc/check_trial, FALSE),first_day_phase_period,TIMER_STOPPABLE) //no voting period = no votes = instant night + else + send_message("Day [turn] started! Voting will start in 1 minute.") + next_phase_timer = addtimer(CALLBACK(src,.proc/start_voting_phase),day_phase_period,TIMER_STOPPABLE) + + SStgui.update_uis(src) + +/** + * Players have finished the discussion period, and now must put up someone to the chopping block. + * + * What players do in this phase: + * * Vote on which player to put up for lynching, leading to the judgement phase. + * * If no votes are case, the judgement phase is skipped, leading to the night phase. + */ +/datum/mafia_controller/proc/start_voting_phase() + phase = MAFIA_PHASE_VOTING + next_phase_timer = addtimer(CALLBACK(src, .proc/check_trial, TRUE),voting_phase_period,TIMER_STOPPABLE) //be verbose! + send_message("Voting started! Vote for who you want to see on trial today.") + SStgui.update_uis(src) + +/** + * Players have voted someone up, and now the person must defend themselves while the town votes innocent or guilty. + * + * What players do in this phase: + * * Vote innocent or guilty, if they are not on trial. + * * Defend themselves and wait for judgement, if they are. + * * Leads to the lynch phase. + * Arguments: + * * verbose: boolean, announces whether there were votes or not. after judgement it goes back here with no voting period to end the day. + */ +/datum/mafia_controller/proc/check_trial(verbose = TRUE) + var/datum/mafia_role/loser = get_vote_winner("Day")//, majority_of_town = TRUE) + // var/loser_votes = get_vote_count(loser,"Day") + if(loser) + // if(loser_votes > 12) + // loser.body.client?.give_award(/datum/award/achievement/mafia/universally_hated, loser.body) + send_message("[loser.body.real_name] wins the day vote, Listen to their defense and vote \"INNOCENT\" or \"GUILTY\"!") + //refresh the lists + judgement_abstain_votes = list() + judgement_innocent_votes = list() + judgement_guilty_votes = list() + for(var/i in all_roles) + var/datum/mafia_role/abstainee = i + if(abstainee.game_status == MAFIA_ALIVE && abstainee != loser) + judgement_abstain_votes += abstainee + on_trial = loser + on_trial.body.forceMove(get_turf(town_center_landmark)) + phase = MAFIA_PHASE_JUDGEMENT + next_phase_timer = addtimer(CALLBACK(src, .proc/lynch),judgement_phase_period,TIMER_STOPPABLE) + reset_votes("Day") + else + if(verbose) + send_message("Not enough people have voted to put someone on trial, nobody will be lynched today.") + if(!check_victory()) + lockdown() + SStgui.update_uis(src) + +/** + * Players have voted innocent or guilty on the person on trial, and that person is now killed or returned home. + * + * What players do in this phase: + * * r/watchpeopledie + * * If the accused is killed, their true role is revealed to the rest of the players. + */ +/datum/mafia_controller/proc/lynch() + for(var/i in judgement_innocent_votes) + var/datum/mafia_role/role = i + send_message("[role.body.real_name] voted innocent.") + for(var/ii in judgement_abstain_votes) + var/datum/mafia_role/role = ii + send_message("[role.body.real_name] abstained.") + for(var/iii in judgement_guilty_votes) + var/datum/mafia_role/role = iii + send_message("[role.body.real_name] voted guilty.") + if(judgement_guilty_votes.len > judgement_innocent_votes.len) //strictly need majority guilty to lynch + send_message("Guilty wins majority, [on_trial.body.real_name] has been lynched.") + on_trial.kill(src, lynch = TRUE) + addtimer(CALLBACK(src, .proc/send_home, on_trial),judgement_lynch_period) + else + send_message("Innocent wins majority, [on_trial.body.real_name] has been spared.") + on_trial.body.forceMove(get_turf(on_trial.assigned_landmark)) + on_trial = null + //day votes are already cleared, so this will skip the trial and check victory/lockdown/whatever else + next_phase_timer = addtimer(CALLBACK(src, .proc/check_trial, FALSE),judgement_lynch_period,TIMER_STOPPABLE)// small pause to see the guy dead, no verbosity since we already did this + +/** + * Teenie helper proc to move players back to their home. + * Used in the above, but also used in the debug button "send all players home" + * Arguments: + * * role: mafia role that is getting sent back to the game. + */ +/datum/mafia_controller/proc/send_home(datum/mafia_role/role) + role.body.forceMove(get_turf(role.assigned_landmark)) + +/** + * Checks to see if a faction (or solo antagonist) has won. + * + * Calculates in this order: + * * counts up town, mafia, and solo + * * solos can count as town members for the purposes of mafia winning + * * sends the amount of living people to the solo antagonists, and see if they won OR block the victory of the teams + * * checks if solos won from above, then if town, then if mafia + * * starts the end of the game if a faction won + * * returns TRUE if someone won the game, halting other procs from continuing in the case of a victory + */ +/datum/mafia_controller/proc/check_victory() + //needed for achievements + var/list/total_town = list() + var/list/total_mafia = list() + + var/alive_town = 0 + var/alive_mafia = 0 + var/list/solos_to_ask = list() //need to ask after because first round is counting team sizes + var/list/total_victors = list() //if this list gets filled with anyone, they win. list because side antags can with with people + var/blocked_victory = FALSE //if a solo antagonist is stopping the town or mafia from finishing the game. + + ///PHASE ONE: TALLY UP ALL NUMBERS OF PEOPLE STILL ALIVE + + for(var/datum/mafia_role/R in all_roles) + switch(R.team) + if(MAFIA_TEAM_MAFIA) + total_mafia += R + if(R.game_status == MAFIA_ALIVE) + alive_mafia += R.vote_power + if(MAFIA_TEAM_TOWN) + total_town += R + if(R.game_status == MAFIA_ALIVE) + alive_town += R.vote_power + if(MAFIA_TEAM_SOLO) + if(R.game_status == MAFIA_ALIVE) + if(R.solo_counts_as_town) + alive_town += R.vote_power + solos_to_ask += R + + ///PHASE TWO: SEND STATS TO SOLO ANTAGS, SEE IF THEY WON OR TEAMS CANNOT WIN + + for(var/datum/mafia_role/solo in solos_to_ask) + if(solo.check_total_victory(alive_town, alive_mafia)) + total_victors += solo + if(solo.block_team_victory(alive_town, alive_mafia)) + blocked_victory = TRUE + + //solo victories! + var/solo_end = FALSE + for(var/datum/mafia_role/winner in total_victors) + send_message("!! [uppertext(winner.name)] VICTORY !!") + // var/client/winner_client = GLOB.directory[winner.player_key] + // winner_client?.give_award(winner.winner_award, winner.body) + solo_end = TRUE + if(solo_end) + start_the_end() + return TRUE + if(blocked_victory) + return FALSE + if(alive_mafia == 0) + // for(var/datum/mafia_role/townie in total_town) + // var/client/townie_client = GLOB.directory[townie.player_key] + // townie_client?.give_award(townie.winner_award, townie.body) + start_the_end("!! TOWN VICTORY !!") + return TRUE + else if(alive_mafia >= alive_town) //guess could change if town nightkill is added + start_the_end("!! MAFIA VICTORY !!") + // for(var/datum/mafia_role/changeling in total_mafia) + // var/client/changeling_client = GLOB.directory[changeling.player_key] + // changeling_client?.give_award(changeling.winner_award, changeling.body) + return TRUE + +/** + * The end of the game is in two procs, because we want a bit of time for players to see eachothers roles. + * Because of how check_victory works, the game is halted in other places by this point. + * + * What players do in this phase: + * * See everyone's role postgame + * * See who won the game + * Arguments: + * * message: string, if non-null it sends it to all players. used to announce team victories while solos are handled in check victory + */ +/datum/mafia_controller/proc/start_the_end(message) + SEND_SIGNAL(src,COMSIG_MAFIA_GAME_END) + if(message) + send_message(message) + for(var/datum/mafia_role/R in all_roles) + R.reveal_role(src) + phase = MAFIA_PHASE_VICTORY_LAP + next_phase_timer = addtimer(CALLBACK(src,.proc/end_game),victory_lap_period,TIMER_STOPPABLE) + +/** + * Cleans up the game, resetting variables back to the beginning and removing the map with the generator. + */ +/datum/mafia_controller/proc/end_game() + map_deleter.generate() //remove the map, it will be loaded at the start of the next one + QDEL_LIST(all_roles) + current_setup_text = null + custom_setup = list() + turn = 0 + votes = list() + //map gen does not deal with landmarks + QDEL_LIST(landmarks) + QDEL_NULL(town_center_landmark) + phase = MAFIA_PHASE_SETUP + +/** + * After the voting and judgement phases, the game goes to night shutting the windows and beginning night with a proc. + */ +/datum/mafia_controller/proc/lockdown() + toggle_night_curtains(close=TRUE) + start_night() + +/** + * Shuts poddoors attached to mafia. + * Arguments: + * * close: boolean, the state you want the curtains in. + */ +/datum/mafia_controller/proc/toggle_night_curtains(close) + for(var/obj/machinery/door/poddoor/D in GLOB.machines) //I really dislike pathing of these + if(D.id != "mafia") //so as to not trigger shutters on station, lol + continue + if(close) + INVOKE_ASYNC(D, /obj/machinery/door/poddoor.proc/close) + else + INVOKE_ASYNC(D, /obj/machinery/door/poddoor.proc/open) + +/** + * The actual start of night for players. Mostly info is given at the start of the night as the end of the night is when votes and actions are submitted and tried. + * + * What players do in this phase: + * * Mafia are told to begin voting on who to kill + * * Powers that are picked during the day announce themselves right now + */ +/datum/mafia_controller/proc/start_night() + phase = MAFIA_PHASE_NIGHT + send_message("Night [turn] started! Lockdown will end in 45 seconds.") + SEND_SIGNAL(src,COMSIG_MAFIA_SUNDOWN) + next_phase_timer = addtimer(CALLBACK(src, .proc/resolve_night),night_phase_period,TIMER_STOPPABLE) + SStgui.update_uis(src) + +/** + * The end of the night, and a series of signals for the order of events on a night. + * + * Order of events, and what they mean: + * * Start of resolve (NIGHT_START) is for activating night abilities that MUST go first + * * Action phase (NIGHT_ACTION_PHASE) is for non-lethal day abilities + * * Mafia then tallies votes and kills the highest voted person (note: one random voter visits that person for the purposes of roleblocking) + * * Killing phase (NIGHT_KILL_PHASE) is for lethal night abilities + * * End of resolve (NIGHT_END) is for cleaning up abilities that went off and i guess doing some that must go last + * * Finally opens the curtains and calls the start of day phase, completing the cycle until check victory returns TRUE + */ +/datum/mafia_controller/proc/resolve_night() + SEND_SIGNAL(src,COMSIG_MAFIA_NIGHT_START) + SEND_SIGNAL(src,COMSIG_MAFIA_NIGHT_ACTION_PHASE) + //resolve mafia kill, todo unsnowflake this + var/datum/mafia_role/R = get_vote_winner("Mafia") + if(R) + var/datum/mafia_role/killer = get_random_voter("Mafia") + if(SEND_SIGNAL(killer,COMSIG_MAFIA_CAN_PERFORM_ACTION,src,"mafia killing",R) & MAFIA_PREVENT_ACTION) + send_message("[killer.body.real_name] was unable to attack [R.body.real_name] tonight!",MAFIA_TEAM_MAFIA) + else + send_message("[killer.body.real_name] has attacked [R.body.real_name]!",MAFIA_TEAM_MAFIA) + R.kill(src) + reset_votes("Mafia") + SEND_SIGNAL(src,COMSIG_MAFIA_NIGHT_KILL_PHASE) + SEND_SIGNAL(src,COMSIG_MAFIA_NIGHT_END) + toggle_night_curtains(close=FALSE) + start_day() + SStgui.update_uis(src) + +/** + * Proc that goes off when players vote for something with their mafia panel. + * + * If teams, it hides the tally overlay and only sends the vote messages to the team that is voting + * Arguments: + * * voter: the mafia role that is trying to vote for... + * * target: the mafia role that is getting voted for + * * vote_type: type of vote submitted (is this the day vote? is this the mafia night vote?) + * * teams: see mafia team defines for what to put in, makes the messages only send to a specific team (so mafia night votes only sending messages to mafia at night) + */ +/datum/mafia_controller/proc/vote_for(datum/mafia_role/voter,datum/mafia_role/target,vote_type, teams) + if(!votes[vote_type]) + votes[vote_type] = list() + var/old_vote = votes[vote_type][voter] + if(old_vote && old_vote == target) + votes[vote_type] -= voter + else + votes[vote_type][voter] = target + if(old_vote && old_vote == target) + send_message("[voter.body.real_name] retracts their vote for [target.body.real_name]!", team = teams) + else + send_message("[voter.body.real_name] voted for [target.body.real_name]!",team = teams) + if(!teams) + target.body.update_icon() //Update the vote display if it's a public vote + var/datum/mafia_role/old = old_vote + if(old) + old.body.update_icon() + +/** + * Clears out the votes of a certain type (day votes, mafia kill votes) while leaving others untouched + */ +/datum/mafia_controller/proc/reset_votes(vote_type) + var/list/bodies_to_update = list() + for(var/vote in votes[vote_type]) + var/datum/mafia_role/R = votes[vote_type][vote] + bodies_to_update += R.body + votes[vote_type] = list() + for(var/mob/M in bodies_to_update) + M.update_icon() + +/** + * Returns how many people voted for the role, in whatever vote (day vote, night kill vote) + * Arguments: + * * role: the mafia role the proc tries to get the amount of votes for + * * vote_type: the vote type (getting how many day votes were for the role, or mafia night votes for the role) + */ +/datum/mafia_controller/proc/get_vote_count(role,vote_type) + . = 0 + for(var/v in votes[vote_type]) + var/datum/mafia_role/votee = v + if(votes[vote_type][votee] == role) + . += votee.vote_power + +/** + * Returns whichever role got the most votes, in whatever vote (day vote, night kill vote) + * returns null if no votes + * Arguments: + * * vote_type: the vote type (getting the role that got the most day votes, or the role that got the most mafia votes) + */ +/datum/mafia_controller/proc/get_vote_winner(vote_type) + var/list/tally = list() + for(var/votee in votes[vote_type]) + if(!tally[votes[vote_type][votee]]) + tally[votes[vote_type][votee]] = 1 + else + tally[votes[vote_type][votee]] += 1 + sortTim(tally,/proc/cmp_numeric_dsc,associative=TRUE) + return length(tally) ? tally[1] : null + +/** + * Returns a random person who voted for whatever vote (day vote, night kill vote) + * Arguments: + * * vote_type: vote type (getting a random day voter, or mafia night voter) + */ +/datum/mafia_controller/proc/get_random_voter(vote_type) + if(length(votes[vote_type])) + return pick(votes[vote_type]) + +/** + * Adds mutable appearances to people who get publicly voted on (so not night votes) showing how many people are picking them + * Arguments: + * * source: the body of the role getting the overlays + * * overlay_list: signal var passing the overlay list of the mob + */ +/datum/mafia_controller/proc/display_votes(atom/source, list/overlay_list) + if(phase != MAFIA_PHASE_VOTING) + return + var/v = get_vote_count(player_role_lookup[source],"Day") + var/mutable_appearance/MA = mutable_appearance('icons/obj/mafia.dmi',"vote_[v > 12 ? "over_12" : v]") + overlay_list += MA + +/** + * Called when the game is setting up, AFTER map is loaded but BEFORE the phase timers start. Creates and places each role's body and gives the correct player key + * + * Notably: + * * Toggles godmode so the mafia players cannot kill themselves + * * Adds signals for voting overlays, see display_votes proc + * * gives mafia panel + * * sends the greeting text (goals, role name, etc) + */ +/datum/mafia_controller/proc/create_bodies() + for(var/datum/mafia_role/role in all_roles) + var/mob/living/carbon/human/H = new(get_turf(role.assigned_landmark)) + H.equipOutfit(player_outfit) + H.status_flags |= GODMODE + RegisterSignal(H,COMSIG_ATOM_UPDATE_OVERLAYS,.proc/display_votes) + var/datum/action/innate/mafia_panel/mafia_panel = new(null,src) + mafia_panel.Grant(H) + var/client/player_client = GLOB.directory[role.player_key] + if(player_client) + player_client.prefs.copy_to(H) + if(H.dna.species.outfit_important_for_life) //plasmamen + H.set_species(/datum/species/human) + role.body = H + player_role_lookup[H] = role + H.key = role.player_key + role.greet() + +/datum/mafia_controller/ui_data(mob/user) + . = ..() + switch(phase) + if(MAFIA_PHASE_DAY,MAFIA_PHASE_VOTING,MAFIA_PHASE_JUDGEMENT) + .["phase"] = "Day [turn]" + if(MAFIA_PHASE_NIGHT) + .["phase"] = "Night [turn]" + else + .["phase"] = "No Game" + if(user.client?.holder) + .["admin_controls"] = TRUE //show admin buttons to start/setup/stop + if(phase == MAFIA_PHASE_JUDGEMENT) + .["judgement_phase"] = TRUE //show judgement section + else + .["judgement_phase"] = FALSE + var/datum/mafia_role/user_role = player_role_lookup[user] + if(user_role) + .["roleinfo"] = list("role" = user_role.name,"desc" = user_role.desc, "action_log" = user_role.role_notes, "hud_icon" = user_role.hud_icon, "revealed_icon" = user_role.revealed_icon) + var/actions = list() + for(var/action in user_role.actions) + if(user_role.validate_action_target(src,action,null)) + actions += action + .["actions"] = actions + .["role_theme"] = user_role.special_theme + else + var/list/lobby_data = list() + for(var/key in GLOB.mafia_signup + GLOB.mafia_bad_signup) + var/list/lobby_member = list() + lobby_member["name"] = key + lobby_member["status"] = "Ready" + if(key in GLOB.mafia_bad_signup) + lobby_member["status"] = "Disconnected" + lobby_member["spectating"] = "Ghost" + if(key in spectators) + lobby_member["spectating"] = "Spectator" + lobby_data += list(lobby_member) + .["lobbydata"] = lobby_data + var/list/player_data = list() + for(var/datum/mafia_role/R in all_roles) + var/list/player_info = list() + var/list/actions = list() + if(user_role) //not observer + for(var/action in user_role.targeted_actions) + if(user_role.validate_action_target(src,action,R)) + actions += action + //Awful snowflake, could use generalizing + if(phase == MAFIA_PHASE_VOTING) + player_info["votes"] = get_vote_count(R,"Day") + if(R.game_status == MAFIA_ALIVE && R != user_role) + actions += "Vote" + if(phase == MAFIA_PHASE_NIGHT && user_role.team == MAFIA_TEAM_MAFIA && R.game_status == MAFIA_ALIVE && R.team != MAFIA_TEAM_MAFIA) + actions += "Kill Vote" + player_info["name"] = R.body.real_name + player_info["ref"] = REF(R) + player_info["actions"] = actions + player_info["alive"] = R.game_status == MAFIA_ALIVE + player_data += list(player_info) + .["players"] = player_data + .["timeleft"] = next_phase_timer ? timeleft(next_phase_timer) : 0 + + //Not sure on this, should this info be visible + .["all_roles"] = current_setup_text + +/datum/mafia_controller/ui_assets(mob/user) + return list( + get_asset_datum(/datum/asset/spritesheet/mafia), + ) + +/datum/mafia_controller/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) + . = ..() + if(.) + return + var/datum/mafia_role/user_role = player_role_lookup[usr] + //Admin actions + if(usr.client?.holder) + switch(action) + if("new_game") + end_game() + basic_setup() + if("nuke") + end_game() + qdel(src) + if("next_phase") + var/datum/timedevent/timer = SStimer.timer_id_dict[next_phase_timer] + if(!timer.spent) + var/datum/callback/tc = timer.callBack + deltimer(next_phase_timer) + tc.InvokeAsync() + return TRUE + if("players_home") + var/list/failed = list() + for(var/datum/mafia_role/player in all_roles) + if(!player.body) + failed += player + continue + player.body.forceMove(get_turf(player.assigned_landmark)) + if(failed.len) + to_chat(usr, "List of players who no longer had a body (if you see this, the game is runtiming anyway so just hit \"New Game\" to end it)") + for(var/i in failed) + var/datum/mafia_role/fail = i + to_chat(usr, fail.player_key) + if("debug_setup") + var/list/debug_setup = list() + var/list/rolelist_dict = list() + var/done = FALSE + for(var/p in typesof(/datum/mafia_role)) + var/datum/mafia_role/path = p + rolelist_dict[initial(path.name) + " ([uppertext(initial(path.team))])"] = path + rolelist_dict = list("CANCEL", "FINISH") + rolelist_dict + while(!done) + to_chat(usr, "You have a total player count of [assoc_value_sum(debug_setup)] in this setup.") + var/chosen_role_name = input(usr,"Select a role!","Custom Setup Creation",rolelist_dict[1]) as null|anything in rolelist_dict + if(chosen_role_name == "CANCEL") + return + if(chosen_role_name == "FINISH") + break + var/found_path = rolelist_dict[chosen_role_name] + var/role_count = input(usr,"How many? Zero to cancel.","Custom Setup Creation",0) as null|num + if(role_count > 0) + debug_setup[found_path] = role_count + custom_setup = debug_setup + if("cancel_setup") + custom_setup = list() + switch(action) //both living and dead + if("mf_lookup") + var/role_lookup = params["atype"] + var/datum/mafia_role/helper + for(var/datum/mafia_role/role in all_roles) + if(role_lookup == role.name) + helper = role + break + helper.show_help(usr) + if(!user_role)//just the dead + var/client/C = ui.user.client + switch(action) + if("mf_signup") + if(!SSticker.HasRoundStarted()) + to_chat(usr, "Wait for the round to start.") + return + if(GLOB.mafia_signup[C.ckey]) + GLOB.mafia_signup -= C.ckey + to_chat(usr, "You unregister from Mafia.") + return + else + GLOB.mafia_signup[C.ckey] = C + to_chat(usr, "You sign up for Mafia.") + if(phase == MAFIA_PHASE_SETUP) + check_signups() + try_autostart() + if("mf_spectate") + if(C.ckey in spectators) + to_chat(usr, "You will no longer get messages from the game.") + spectators -= C.ckey + else + to_chat(usr, "You will now get messages from the game.") + spectators += C.ckey + if(user_role.game_status == MAFIA_DEAD) + return + //User actions (just living) + switch(action) + if("mf_action") + if(!user_role.actions.Find(params["atype"])) + return + user_role.handle_action(src,params["atype"],null) + return TRUE //vals for self-ui update + if("mf_targ_action") + var/datum/mafia_role/target = locate(params["target"]) in all_roles + if(!istype(target)) + return + switch(params["atype"]) + if("Vote") + if(phase != MAFIA_PHASE_VOTING) + return + vote_for(user_role,target,vote_type="Day") + if("Kill Vote") + if(phase != MAFIA_PHASE_NIGHT || user_role.team != MAFIA_TEAM_MAFIA) + return + vote_for(user_role,target,"Mafia", MAFIA_TEAM_MAFIA) + to_chat(user_role.body,"You will vote for [target.body.real_name] for tonights killing.") + else + if(!user_role.targeted_actions.Find(params["atype"])) + return + if(!user_role.validate_action_target(src,params["atype"],target)) + return + user_role.handle_action(src,params["atype"],target) + return TRUE + if(user_role != on_trial) + switch(action) + if("vote_abstain") + if(phase != MAFIA_PHASE_JUDGEMENT || (user_role in judgement_abstain_votes)) + return + to_chat(user_role.body,"You have decided to abstain.") + judgement_innocent_votes -= user_role + judgement_guilty_votes -= user_role + judgement_abstain_votes += user_role + if("vote_innocent") + if(phase != MAFIA_PHASE_JUDGEMENT || (user_role in judgement_innocent_votes)) + return + to_chat(user_role.body,"Your vote on [on_trial.body.real_name] submitted as INNOCENT!") + judgement_abstain_votes -= user_role//no fakers, and... + judgement_guilty_votes -= user_role//no radical centrism + judgement_innocent_votes += user_role + if("vote_guilty") + if(phase != MAFIA_PHASE_JUDGEMENT || (user_role in judgement_guilty_votes)) + return + to_chat(user_role.body,"Your vote on [on_trial.body.real_name] submitted as GUILTY!") + judgement_abstain_votes -= user_role//no fakers, and... + judgement_innocent_votes -= user_role//no radical centrism + judgement_guilty_votes += user_role + +/datum/mafia_controller/ui_state(mob/user) + return GLOB.always_state + +/datum/mafia_controller/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, null) + if(!ui) + ui = new(user, src, "MafiaPanel") + ui.set_autoupdate(FALSE) + ui.open() + +/proc/assoc_value_sum(list/L) + . = 0 + for(var/key in L) + . += L[key] + +/** + * Returns a semirandom setup, with... + * Town, Two invest roles, one protect role, sometimes a misc role, and the rest assistants for town. + * Mafia, 2 normal mafia and one special. + * Neutral, two disruption roles, sometimes one is a killing. + * + * See _defines.dm in the mafia folder for a rundown on what these groups of roles include. + */ +/datum/mafia_controller/proc/generate_random_setup() + var/invests_left = 2 + var/protects_left = 1 + var/miscs_left = prob(35) + var/mafiareg_left = 2 + var/mafiaspe_left = 1 + var/killing_role = prob(50) + var/disruptors = killing_role ? 1 : 2 //still required to calculate overflow + var/overflow_left = max_player - (invests_left + protects_left + miscs_left + mafiareg_left + mafiaspe_left + killing_role + disruptors) + + var/list/random_setup = list() + for(var/i in 1 to max_player) //should match the number of roles to add + if(overflow_left) + add_setup_role(random_setup, TOWN_OVERFLOW) + overflow_left-- + else if(invests_left) + add_setup_role(random_setup, TOWN_INVEST) + invests_left-- + else if(protects_left) + add_setup_role(random_setup, TOWN_PROTECT) + protects_left-- + else if(miscs_left) + add_setup_role(random_setup, TOWN_MISC) + miscs_left-- + else if(mafiareg_left) + add_setup_role(random_setup, MAFIA_REGULAR) + mafiareg_left-- + else if(mafiaspe_left) + add_setup_role(random_setup, MAFIA_SPECIAL) + mafiaspe_left-- + else if(killing_role) + add_setup_role(random_setup, NEUTRAL_KILL) + killing_role-- + else + add_setup_role(random_setup, NEUTRAL_DISRUPT) + return random_setup + +/** + * Helper proc that adds a random role of a type to a setup. if it doesn't exist in the setup, it adds the path to the list and otherwise bumps the path in the list up one + */ +/datum/mafia_controller/proc/add_setup_role(setup_list, wanted_role_type) + var/list/role_type_paths = list() + for(var/path in typesof(/datum/mafia_role)) + var/datum/mafia_role/instance = path + if(initial(instance.role_type) == wanted_role_type) + role_type_paths += instance + + var/mafia_path = pick(role_type_paths) + var/datum/mafia_role/mafia_path_type = mafia_path + var/found_role + for(var/searched_path in setup_list) + var/datum/mafia_role/searched_path_type = searched_path + if(initial(mafia_path_type.name) == initial(searched_path_type.name)) + found_role = searched_path + break + if(found_role) + setup_list[found_role] += 1 + return + setup_list[mafia_path] = 1 + +/** + * Called when enough players have signed up to fill a setup. DOESN'T NECESSARILY MEAN THE GAME WILL START. + * + * Checks for a custom setup, if so gets the required players from that and if not it sets the player requirement to required_player(max_player) and generates one IF basic setup starts a game. + * Checks if everyone signed up is an observer, and is still connected. If people aren't, they're removed from the list. + * If there aren't enough players post sanity, it aborts. otherwise, it selects enough people for the game and starts preparing the game for real. + */ +/datum/mafia_controller/proc/basic_setup() + var/req_players + var/list/setup = custom_setup + if(!setup.len) + req_players = required_player //max_player + else + req_players = assoc_value_sum(setup) + + //final list for all the players who will be in this game + var/list/filtered_keys = list() + //cuts invalid players from signups (disconnected/not a ghost) + var/list/possible_keys = list() + for(var/key in GLOB.mafia_signup) + if(GLOB.directory[key]) + var/client/C = GLOB.directory[key] + if(isobserver(C.mob)) + possible_keys += key + continue + GLOB.mafia_signup -= key //not valid to play when we checked so remove them from signups + + //if there were not enough players, don't start. we already trimmed the list to now hold only valid signups + if(length(possible_keys) < req_players) + return + else //hacky implementation of max players + req_players = clamp(length(possible_keys), 1, max_player) + + //if there were too many players, still start but only make filtered keys as big as it needs to be (cut excess) + //also removes people who do get into final player list from the signup so they have to sign up again when game ends + for(var/i in 1 to req_players) + var/chosen_key = pick_n_take(possible_keys) + filtered_keys += chosen_key + GLOB.mafia_signup -= chosen_key + //small message about not getting into this game for clarity on why they didn't get in + for(var/unpicked in possible_keys) + var/client/unpicked_client = GLOB.directory[unpicked] + to_chat(unpicked_client, "Sorry, the starting mafia game has too many players and you were not picked.") + to_chat(unpicked_client, "You're still signed up, getting messages from the current round, and have another chance to join when the one starting now finishes.") + + if(!setup.len) //don't actually have one yet, so generate a max player random setup. it's good to do this here instead of above so it doesn't generate one every time a game could possibly start. + setup = generate_random_setup() + prepare_game(setup,filtered_keys) + start_game() + +/** + * Called when someone signs up, and sees if there are enough people in the signup list to begin. + * + * Only checks if everyone is actually valid to start (still connected and an observer) if there are enough players (basic_setup) + */ +/datum/mafia_controller/proc/try_autostart() + if(phase != MAFIA_PHASE_SETUP) // || !(GLOB.ghost_role_flags & GHOSTROLE_MINIGAME)) + return + if(GLOB.mafia_signup.len >= max_player || GLOB.mafia_signup.len >= required_player|| custom_setup.len)//enough people to try and make something (or debug mode) + basic_setup() + +/** + * Filters inactive player into a different list until they reconnect, and removes players who are no longer ghosts. + * + * If a disconnected player gets a non-ghost mob and reconnects, they will be first put back into mafia_signup then filtered by that. + */ +/datum/mafia_controller/proc/check_signups() + for(var/bad_key in GLOB.mafia_bad_signup) + if(GLOB.directory[bad_key])//they have reconnected if we can search their key and get a client + GLOB.mafia_bad_signup -= bad_key + GLOB.mafia_signup += bad_key + for(var/key in GLOB.mafia_signup) + var/client/C = GLOB.directory[key] + if(!C)//vice versa but in a variable we use later + GLOB.mafia_signup -= key + GLOB.mafia_bad_signup += key + if(!isobserver(C.mob)) + //they are back to playing the game, remove them from the signups + GLOB.mafia_signup -= key + +/datum/action/innate/mafia_panel + name = "Mafia Panel" + desc = "Use this to play." + icon_icon = 'icons/obj/mafia.dmi' + button_icon_state = "board" + var/datum/mafia_controller/parent + +/datum/action/innate/mafia_panel/New(Target,mf) + . = ..() + parent = mf + +/datum/action/innate/mafia_panel/Activate() + parent.ui_interact(owner) + +/** + * Creates the global datum for playing mafia games, destroys the last if that's required and returns the new. + */ +/proc/create_mafia_game() + if(GLOB.mafia_game) + QDEL_NULL(GLOB.mafia_game) + var/datum/mafia_controller/MF = new() + return MF diff --git a/code/modules/mafia/map_pieces.dm b/code/modules/mafia/map_pieces.dm new file mode 100644 index 0000000000..3339c596b4 --- /dev/null +++ b/code/modules/mafia/map_pieces.dm @@ -0,0 +1,79 @@ +/obj/effect/landmark/mafia_game_area //locations where mafia will be loaded by the datum + name = "Mafia Area Spawn" + var/game_id = "mafia" + +/obj/effect/landmark/mafia + name = "Mafia Player Spawn" + var/game_id = "mafia" + +/obj/effect/landmark/mafia/town_center + name = "Mafia Town Center" + +//for ghosts/admins +/obj/mafia_game_board + name = "Mafia Game Board" + icon = 'icons/obj/mafia.dmi' + icon_state = "board" + anchored = TRUE + var/game_id = "mafia" + var/datum/mafia_controller/MF + +/obj/mafia_game_board/attack_ghost(mob/user) + . = ..() + if(!MF) + MF = GLOB.mafia_game + if(!MF) + MF = create_mafia_game() + MF.ui_interact(user) + +/area/mafia + name = "Mafia Minigame" + icon_state = "mafia" + dynamic_lighting = DYNAMIC_LIGHTING_DISABLED + requires_power = FALSE + has_gravity = STANDARD_GRAVITY + flags_1 = NONE + // block_suicide = TRUE + +/datum/map_template/mafia + var/description = "" + +/datum/map_template/mafia/summerball + name = "Summerball 2020" + description = "The original, the OG. The 2020 Summer ball was where mafia came from, with this map." + mappath = "_maps/map_files/Mafia/mafia_ball.dmm" + +/datum/map_template/mafia/syndicate + name = "Syndicate Megastation" + description = "Yes, it's a very confusing day at the Megastation. Will the syndicate conflict resolution operatives succeed?" + mappath = "_maps/map_files/Mafia/mafia_syndie.dmm" + +/datum/map_template/mafia/lavaland + name = "Lavaland Excursion" + description = "The station has no idea what's going down on lavaland right now, we got changelings... traitors, and worst of all... lawyers roleblocking you every night." + mappath = "_maps/map_files/Mafia/mafia_lavaland.dmm" + +/datum/map_template/mafia/ufo + name = "Alien Mothership" + description = "The haunted ghost UFO tour has gone south and now it's up to our fine townies and scare seekers to kill the actual real alien changelings..." + mappath = "_maps/map_files/Mafia/mafia_ayylmao.dmm" + +/datum/map_template/mafia/spider_clan + name = "Spider Clan Kidnapping" + description = "New and improved spider clan kidnappings are a lot less boring and have a lot more lynching. Damn westaboos!" + mappath = "_maps/map_files/Mafia/mafia_spiderclan.dmm" + +/datum/map_template/mafia/snowy + name = "Snowdin" + description = "Based off of the icey moon map of the same name, the guy who reworked it pretty much did it for nothing since away missions are disabled but at least he'll get this...?" + mappath = "_maps/map_files/Mafia/mafia_snow.dmm" + +/datum/map_template/mafia/gothic + name = "Vampire's Castle" + description = "Vampires and changelings clash to find out who's the superior bloodsucking monster in this creepy castle map." + mappath = "_maps/map_files/Mafia/mafia_gothic.dmm" + +/datum/map_template/mafia/reebe + name = "Reebe" + description = "Trouble in Reebe station! Copypaste guranteed by ClockCo™" + mappath = "_maps/map_files/Mafia/mafia_reebe.dmm" diff --git a/code/modules/mafia/outfits.dm b/code/modules/mafia/outfits.dm new file mode 100644 index 0000000000..bbc72bd120 --- /dev/null +++ b/code/modules/mafia/outfits.dm @@ -0,0 +1,108 @@ + +//what people wear unrevealed + +/datum/outfit/mafia + name = "Mafia Game Outfit" + uniform = /obj/item/clothing/under/color/grey + shoes = /obj/item/clothing/shoes/sneakers/black + +//town + +/datum/outfit/mafia/assistant + name = "Mafia Assistant" + + uniform = /obj/item/clothing/under/color/rainbow + +/datum/outfit/mafia/detective + name = "Mafia Detective" + + uniform = /obj/item/clothing/under/rank/security/detective + // neck = /obj/item/clothing/neck/tie/detective + shoes = /obj/item/clothing/shoes/sneakers/brown + suit = /obj/item/clothing/suit/det_suit + gloves = /obj/item/clothing/gloves/color/black + head = /obj/item/clothing/head/fedora/det_hat + mask = /obj/item/clothing/mask/cigarette + +/datum/outfit/mafia/psychologist + name = "Mafia Psychologist" + + uniform = /obj/item/clothing/under/suit/black + shoes = /obj/item/clothing/shoes/laceup + +/datum/outfit/mafia/md + name = "Mafia Medical Doctor" + + uniform = /obj/item/clothing/under/rank/medical/doctor + shoes = /obj/item/clothing/shoes/sneakers/white + suit = /obj/item/clothing/suit/toggle/labcoat + +/datum/outfit/mafia/chaplain + name = "Mafia Chaplain" + + uniform = /obj/item/clothing/under/rank/civilian/chaplain + +/datum/outfit/mafia/lawyer + name = "Mafia Lawyer" + + uniform = /obj/item/clothing/under/rank/civilian/lawyer/bluesuit + suit = /obj/item/clothing/suit/toggle/lawyer + shoes = /obj/item/clothing/shoes/laceup + +/datum/outfit/mafia/hop + name = "Mafia Head of Personnel" + + uniform = /obj/item/clothing/under/rank/civilian/head_of_personnel + suit = /obj/item/clothing/suit/armor/vest/alt + shoes = /obj/item/clothing/shoes/sneakers/brown + head = /obj/item/clothing/head/hopcap + glasses = /obj/item/clothing/glasses/sunglasses + +//mafia + +/datum/outfit/mafia/changeling + name = "Mafia Changeling" + + head = /obj/item/clothing/head/helmet/changeling + suit = /obj/item/clothing/suit/armor/changeling + +//solo + +/datum/outfit/mafia/fugitive + name = "Mafia Fugitive" + + uniform = /obj/item/clothing/under/rank/prisoner + shoes = /obj/item/clothing/shoes/sneakers/orange + +/datum/outfit/mafia/obsessed + name = "Mafia Obsessed" + uniform = /obj/item/clothing/under/misc/overalls + shoes = /obj/item/clothing/shoes/sneakers/white + gloves = /obj/item/clothing/gloves/color/latex + mask = /obj/item/clothing/mask/surgical + suit = /obj/item/clothing/suit/apron + +/datum/outfit/mafia/obsessed/post_equip(mob/living/carbon/human/H) + for(var/obj/item/carried_item in H.get_equipped_items(TRUE)) + carried_item.add_mob_blood(H)//Oh yes, there will be blood... + H.regenerate_icons() + +/datum/outfit/mafia/clown + name = "Mafia Clown" + + uniform = /obj/item/clothing/under/rank/civilian/clown + shoes = /obj/item/clothing/shoes/clown_shoes + mask = /obj/item/clothing/mask/gas/clown_hat + +/datum/outfit/mafia/traitor + name = "Mafia Traitor" + + mask = /obj/item/clothing/mask/gas/syndicate + uniform = /obj/item/clothing/under/syndicate/tacticool + shoes = /obj/item/clothing/shoes/jackboots + +/datum/outfit/mafia/nightmare + name = "Mafia Nightmare" + + uniform = null + shoes = null diff --git a/code/modules/mafia/roles.dm b/code/modules/mafia/roles.dm new file mode 100644 index 0000000000..2461a93976 --- /dev/null +++ b/code/modules/mafia/roles.dm @@ -0,0 +1,705 @@ +/datum/mafia_role + var/name = "Assistant" + var/desc = "You are a crewmember without any special abilities." + var/win_condition = "kill all mafia and solo killing roles." + var/team = MAFIA_TEAM_TOWN + ///how the random setup chooses which roles get put in + var/role_type = TOWN_OVERFLOW + + var/player_key + var/mob/living/carbon/human/body + var/obj/effect/landmark/mafia/assigned_landmark + + ///how many votes submitted when you vote. + var/vote_power = 1 + var/detect_immune = FALSE + var/revealed = FALSE + var/datum/outfit/revealed_outfit = /datum/outfit/mafia/assistant //the assistants need a special path to call out they were in fact assistant, everything else can just use job equipment + //action = uses + var/list/actions = list() + var/list/targeted_actions = list() + //what the role gets when it wins a game + // var/winner_award = /datum/award/achievement/mafia/assistant + + //so mafia have to also kill them to have a majority + var/solo_counts_as_town = FALSE //(don't set this for town) + var/game_status = MAFIA_ALIVE + + ///icon state in the mafia dmi of the hud of the role, used in the mafia ui + var/hud_icon = "hudassistant" + ///icon state in the mafia dmi of the hud of the role, used in the mafia ui + var/revealed_icon = "assistant" + ///set this to something cool for antagonists and their window will look different + var/special_theme + + var/list/role_notes = list() + + +/datum/mafia_role/New(datum/mafia_controller/game) + . = ..() + +/datum/mafia_role/proc/kill(datum/mafia_controller/game,lynch=FALSE) + if(SEND_SIGNAL(src,COMSIG_MAFIA_ON_KILL,game,lynch) & MAFIA_PREVENT_KILL) + return FALSE + game_status = MAFIA_DEAD + body.death() + if(lynch) + reveal_role(game, verbose = TRUE) + if(!(player_key in game.spectators)) //people who played will want to see the end of the game more often than not + game.spectators += player_key + return TRUE + +/datum/mafia_role/Destroy(force, ...) + QDEL_NULL(body) + . = ..() + +/datum/mafia_role/proc/greet() + SEND_SOUND(body, 'sound/ambience/ambifailure.ogg') + to_chat(body,"You are the [name].") + to_chat(body,"[desc]") + switch(team) + if(MAFIA_TEAM_MAFIA) + to_chat(body,"You and your co-conspirators win if you outnumber crewmembers.") + if(MAFIA_TEAM_TOWN) + to_chat(body,"You are a crewmember. Find out and lynch the changelings!") + if(MAFIA_TEAM_SOLO) + to_chat(body,"You are not aligned to town or mafia. Accomplish your own objectives!") + to_chat(body, "Be sure to read the wiki page to learn more, if you have no idea what's going on.") + +/datum/mafia_role/proc/reveal_role(datum/mafia_controller/game, verbose = FALSE) + if(revealed) + return + if(verbose) + game.send_message("It is revealed that the true role of [body] [game_status == MAFIA_ALIVE ? "is" : "was"] [name]!") + var/list/oldoutfit = body.get_equipped_items() + for(var/thing in oldoutfit) + qdel(thing) + special_reveal_equip(game) + body.equipOutfit(revealed_outfit) + revealed = TRUE + +/datum/mafia_role/proc/special_reveal_equip(datum/mafia_controller/game) + return + +/datum/mafia_role/proc/handle_action(datum/mafia_controller/game,action,datum/mafia_role/target) + return + +/datum/mafia_role/proc/validate_action_target(datum/mafia_controller/game,action,datum/mafia_role/target) + if(SEND_SIGNAL(src,COMSIG_MAFIA_CAN_PERFORM_ACTION,game,action,target) & MAFIA_PREVENT_ACTION) + return FALSE + return TRUE + +/datum/mafia_role/proc/add_note(note) + role_notes += note + +/datum/mafia_role/proc/check_total_victory(alive_town, alive_mafia) //solo antags can win... solo. + return FALSE + +/datum/mafia_role/proc/block_team_victory(alive_town, alive_mafia) //solo antags can also block team wins. + return FALSE + +/datum/mafia_role/proc/show_help(clueless) + var/list/result = list() + var/team_desc = "" + var/team_span = "" + var/the = TRUE + switch(team) + if(MAFIA_TEAM_TOWN) + team_desc = "Town" + team_span = "nicegreen" + if(MAFIA_TEAM_MAFIA) + team_desc = "Mafia" + team_span = "red" + if(MAFIA_TEAM_SOLO) + team_desc = "Nobody" + team_span = "comradio" + the = FALSE + result += "The [name] is aligned with [the ? "the " : ""][team_desc]" + result += "\"[desc]\"" + result += "[name] wins when they [win_condition]" + to_chat(clueless, result.Join("
")) + +/datum/mafia_role/detective + name = "Detective" + desc = "You can investigate a single person each night to learn their team." + revealed_outfit = /datum/outfit/mafia/detective + role_type = TOWN_INVEST + // winner_award = /datum/award/achievement/mafia/detective + + hud_icon = "huddetective" + revealed_icon = "detective" + + targeted_actions = list("Investigate") + + var/datum/mafia_role/current_investigation + +/datum/mafia_role/detective/New(datum/mafia_controller/game) + . = ..() + RegisterSignal(game,COMSIG_MAFIA_NIGHT_ACTION_PHASE,.proc/investigate) + +/datum/mafia_role/detective/validate_action_target(datum/mafia_controller/game,action,datum/mafia_role/target) + . = ..() + if(!.) + return + return game.phase == MAFIA_PHASE_NIGHT && target.game_status == MAFIA_ALIVE && target != src + +/datum/mafia_role/detective/handle_action(datum/mafia_controller/game,action,datum/mafia_role/target) + if(!target || target.game_status != MAFIA_ALIVE) + to_chat(body,"You can only investigate alive people.") + return + to_chat(body,"You will investigate [target.body.real_name] tonight.") + current_investigation = target + +/datum/mafia_role/detective/proc/investigate(datum/mafia_controller/game) + var/datum/mafia_role/target = current_investigation + if(target) + if(target.detect_immune) + to_chat(body,"Your investigations reveal that [target.body.real_name] is a true member of the station.") + add_note("N[game.turn] - [target.body.real_name] - Town") + else + var/team_text + var/fluff + switch(target.team) + if(MAFIA_TEAM_TOWN) + team_text = "Town" + fluff = "a true member of the station." + if(MAFIA_TEAM_MAFIA) + team_text = "Mafia" + fluff = "an unfeeling, hideous changeling!" + if(MAFIA_TEAM_SOLO) + team_text = "Solo" + fluff = "a rogue, with their own objectives..." + to_chat(body,"Your investigations reveal that [target.body.real_name] is [fluff]") + add_note("N[game.turn] - [target.body.real_name] - [team_text]") + current_investigation = null + +/datum/mafia_role/psychologist + name = "Psychologist" + desc = "You can visit someone ONCE PER GAME to reveal their true role in the morning!" + revealed_outfit = /datum/outfit/mafia/psychologist + role_type = TOWN_INVEST + // winner_award = /datum/award/achievement/mafia/psychologist + + hud_icon = "hudpsychologist" + revealed_icon = "psychologist" + + targeted_actions = list("Reveal") + var/datum/mafia_role/current_target + var/can_use = TRUE + +/datum/mafia_role/psychologist/New(datum/mafia_controller/game) + . = ..() + RegisterSignal(game,COMSIG_MAFIA_NIGHT_END,.proc/therapy_reveal) + +/datum/mafia_role/psychologist/validate_action_target(datum/mafia_controller/game, action, datum/mafia_role/target) + . = ..() + if(!. || !can_use || game.phase == MAFIA_PHASE_NIGHT || target.game_status != MAFIA_ALIVE || target.revealed || target == src) + return FALSE + +/datum/mafia_role/psychologist/handle_action(datum/mafia_controller/game, action, datum/mafia_role/target) + . = ..() + to_chat(body,"You will reveal [target.body.real_name] tonight.") + current_target = target + +/datum/mafia_role/psychologist/proc/therapy_reveal(datum/mafia_controller/game) + if(SEND_SIGNAL(src,COMSIG_MAFIA_CAN_PERFORM_ACTION,game,"reveal",current_target) & MAFIA_PREVENT_ACTION || game_status != MAFIA_ALIVE) //Got lynched or roleblocked by a lawyer. + current_target = null + if(current_target) + add_note("N[game.turn] - [current_target.body.real_name] - Revealed true identity") + to_chat(body,"You have revealed the true nature of the [current_target]!") + current_target.reveal_role(game, verbose = TRUE) + current_target = null + can_use = FALSE + +/datum/mafia_role/chaplain + name = "Chaplain" + desc = "You can communicate with spirits of the dead each night to discover dead crewmember roles." + revealed_outfit = /datum/outfit/mafia/chaplain + role_type = TOWN_INVEST + hud_icon = "hudchaplain" + revealed_icon = "chaplain" + // winner_award = /datum/award/achievement/mafia/chaplain + + targeted_actions = list("Pray") + var/current_target + +/datum/mafia_role/chaplain/New(datum/mafia_controller/game) + . = ..() + RegisterSignal(game,COMSIG_MAFIA_NIGHT_ACTION_PHASE,.proc/commune) + +/datum/mafia_role/chaplain/validate_action_target(datum/mafia_controller/game, action, datum/mafia_role/target) + . = ..() + if(!.) + return + return game.phase == MAFIA_PHASE_NIGHT && target.game_status == MAFIA_DEAD && target != src && !target.revealed + +/datum/mafia_role/chaplain/handle_action(datum/mafia_controller/game, action, datum/mafia_role/target) + to_chat(body,"You will commune with the spirit of [target.body.real_name] tonight.") + current_target = target + +/datum/mafia_role/chaplain/proc/commune(datum/mafia_controller/game) + var/datum/mafia_role/target = current_target + if(target) + to_chat(body,"You invoke spirit of [target.body.real_name] and learn their role was [target.name].") + add_note("N[game.turn] - [target.body.real_name] - [target.name]") + current_target = null + +/datum/mafia_role/md + name = "Medical Doctor" + desc = "You can protect a single person each night from killing." + revealed_outfit = /datum/outfit/mafia/md // /mafia <- outfit must be readded (just make a new mafia outfits file for all of these) + role_type = TOWN_PROTECT + hud_icon = "hudmedicaldoctor" + revealed_icon = "medicaldoctor" + // winner_award = /datum/award/achievement/mafia/md + + targeted_actions = list("Protect") + var/datum/mafia_role/current_protected + +/datum/mafia_role/md/New(datum/mafia_controller/game) + . = ..() + RegisterSignal(game,COMSIG_MAFIA_NIGHT_ACTION_PHASE,.proc/protect) + RegisterSignal(game,COMSIG_MAFIA_NIGHT_END,.proc/end_protection) + +/datum/mafia_role/md/validate_action_target(datum/mafia_controller/game,action,datum/mafia_role/target) + . = ..() + if(!.) + return + if(target.name == "Head of Personnel" && target.revealed) + return FALSE + return game.phase == MAFIA_PHASE_NIGHT && target.game_status == MAFIA_ALIVE && target != src + +/datum/mafia_role/md/handle_action(datum/mafia_controller/game,action,datum/mafia_role/target) + if(!target || target.game_status != MAFIA_ALIVE) + to_chat(body,"You can only protect alive people.") + return + to_chat(body,"You will protect [target.body.real_name] tonight.") + current_protected = target + +/datum/mafia_role/md/proc/protect(datum/mafia_controller/game) + if(current_protected) + RegisterSignal(current_protected,COMSIG_MAFIA_ON_KILL,.proc/prevent_kill) + add_note("N[game.turn] - Protected [current_protected.body.real_name]") + +/datum/mafia_role/md/proc/prevent_kill(datum/source) + to_chat(body,"The person you protected tonight was attacked!") + to_chat(current_protected.body,"You were attacked last night, but someone nursed you back to life!") + return MAFIA_PREVENT_KILL + +/datum/mafia_role/md/proc/end_protection(datum/mafia_controller/game) + if(current_protected) + UnregisterSignal(current_protected,COMSIG_MAFIA_ON_KILL) + current_protected = null + +/datum/mafia_role/lawyer + name = "Lawyer" + desc = "You can choose a person during the day to provide extensive legal advice to during the night, preventing night actions." + revealed_outfit = /datum/outfit/mafia/lawyer + role_type = TOWN_PROTECT + hud_icon = "hudlawyer" + revealed_icon = "lawyer" + // winner_award = /datum/award/achievement/mafia/lawyer + + targeted_actions = list("Advise") + var/datum/mafia_role/current_target + +/datum/mafia_role/lawyer/New(datum/mafia_controller/game) + . = ..() + RegisterSignal(game,COMSIG_MAFIA_SUNDOWN,.proc/roleblock_text) + RegisterSignal(game,COMSIG_MAFIA_NIGHT_START,.proc/try_to_roleblock) + RegisterSignal(game,COMSIG_MAFIA_NIGHT_END,.proc/release) + +/datum/mafia_role/lawyer/proc/roleblock_text(datum/mafia_controller/game) + if(SEND_SIGNAL(src,COMSIG_MAFIA_CAN_PERFORM_ACTION,game,"roleblock",current_target) & MAFIA_PREVENT_ACTION || game_status != MAFIA_ALIVE) //Got lynched or roleblocked by another lawyer. + current_target = null + if(current_target) + to_chat(current_target.body,"YOU HAVE BEEN BLOCKED! YOU CANNOT PERFORM ANY ACTIONS TONIGHT.") + add_note("N[game.turn] - [current_target.body.real_name] - Blocked") + +/datum/mafia_role/lawyer/validate_action_target(datum/mafia_controller/game, action, datum/mafia_role/target) + . = ..() + if(!.) + return FALSE + if(game.phase == MAFIA_PHASE_NIGHT) + return FALSE + if(target.game_status != MAFIA_ALIVE) + return FALSE + +/datum/mafia_role/lawyer/handle_action(datum/mafia_controller/game, action, datum/mafia_role/target) + . = ..() + if(target == current_target) + current_target = null + to_chat(body,"You have decided against blocking anyone tonight.") + else + current_target = target + to_chat(body,"You will block [target.body.real_name] tonight.") + +/datum/mafia_role/lawyer/proc/try_to_roleblock(datum/mafia_controller/game) + if(current_target) + RegisterSignal(current_target,COMSIG_MAFIA_CAN_PERFORM_ACTION, .proc/prevent_action) + +/datum/mafia_role/lawyer/proc/release(datum/mafia_controller/game) + . = ..() + if(current_target) + UnregisterSignal(current_target, COMSIG_MAFIA_CAN_PERFORM_ACTION) + current_target = null + +/datum/mafia_role/lawyer/proc/prevent_action(datum/source) + if(game_status == MAFIA_ALIVE) //in case we got killed while imprisoning sk - bad luck edge + return MAFIA_PREVENT_ACTION + +/datum/mafia_role/hop + name = "Head of Personnel" + desc = "You can reveal yourself once per game, tripling your vote power but becoming unable to be protected!" + revealed_outfit = /datum/outfit/mafia/hop + role_type = TOWN_MISC + hud_icon = "hudheadofpersonnel" + revealed_icon = "headofpersonnel" + // winner_award = /datum/award/achievement/mafia/hop + + targeted_actions = list("Reveal") + +/datum/mafia_role/hop/validate_action_target(datum/mafia_controller/game, action, datum/mafia_role/target) + . = ..() + if(!. || game.phase == MAFIA_PHASE_NIGHT || game.turn == 1 || target.game_status != MAFIA_ALIVE || target != src || revealed) + return FALSE + +/datum/mafia_role/hop/handle_action(datum/mafia_controller/game, action, datum/mafia_role/target) + . = ..() + reveal_role(game, TRUE) + vote_power = 2 + +///MAFIA ROLES/// only one until i rework this to allow more, they're the "anti-town" working to kill off townies to win + +/datum/mafia_role/mafia + name = "Changeling" + desc = "You're a member of the changeling hive. Use ':j' talk prefix to talk to your fellow lings." + team = MAFIA_TEAM_MAFIA + role_type = MAFIA_REGULAR + hud_icon = "hudchangeling" + revealed_icon = "changeling" + // winner_award = /datum/award/achievement/mafia/changeling + + revealed_outfit = /datum/outfit/mafia/changeling + special_theme = "syndicate" + win_condition = "become majority over the town and no solo killing role can stop them." + +/datum/mafia_role/mafia/New(datum/mafia_controller/game) + . = ..() + RegisterSignal(game,COMSIG_MAFIA_SUNDOWN,.proc/mafia_text) + +/datum/mafia_role/mafia/proc/mafia_text(datum/mafia_controller/source) + to_chat(body,"Vote for who to kill tonight. The killer will be chosen randomly from voters.") + +//better detective for mafia +/datum/mafia_role/mafia/thoughtfeeder + name = "Thoughtfeeder" + desc = "You're a changeling variant that feeds on the memories of others. Use ':j' talk prefix to talk to your fellow lings, and visit people at night to learn their role." + role_type = MAFIA_SPECIAL + hud_icon = "hudthoughtfeeder" + revealed_icon = "thoughtfeeder" + // winner_award = /datum/award/achievement/mafia/thoughtfeeder + + targeted_actions = list("Learn Role") + var/datum/mafia_role/current_investigation + +/datum/mafia_role/mafia/thoughtfeeder/New(datum/mafia_controller/game) + . = ..() + RegisterSignal(game,COMSIG_MAFIA_NIGHT_ACTION_PHASE,.proc/investigate) + +/datum/mafia_role/mafia/thoughtfeeder/validate_action_target(datum/mafia_controller/game,action,datum/mafia_role/target) + . = ..() + if(!.) + return + return game.phase == MAFIA_PHASE_NIGHT && target.game_status == MAFIA_ALIVE && target != src + +/datum/mafia_role/mafia/thoughtfeeder/handle_action(datum/mafia_controller/game,action,datum/mafia_role/target) + to_chat(body,"You will feast on the memories of [target.body.real_name] tonight.") + current_investigation = target + +/datum/mafia_role/mafia/thoughtfeeder/proc/investigate(datum/mafia_controller/game) + var/datum/mafia_role/target = current_investigation + current_investigation = null + if(SEND_SIGNAL(src,COMSIG_MAFIA_CAN_PERFORM_ACTION,game,"thoughtfeed",target) & MAFIA_PREVENT_ACTION) + to_chat(body,"You were unable to investigate [target.body.real_name].") + add_note("N[game.turn] - [target.body.real_name] - Unable to investigate") + return + if(target) + if(target.detect_immune) + to_chat(body,"[target.body.real_name]'s memories reveal that they are the Assistant.") + add_note("N[game.turn] - [target.body.real_name] - Assistant") + else + to_chat(body,"[target.body.real_name]'s memories reveal that they are the [target.name].") + add_note("N[game.turn] - [target.body.real_name] - [target.name]") + + +///SOLO ROLES/// they range from anomalous factors to deranged killers that try to win alone. + +/datum/mafia_role/traitor + name = "Traitor" + desc = "You're a solo traitor. You are immune to night kills, can kill every night and you win by outnumbering everyone else." + win_condition = "kill everyone." + team = MAFIA_TEAM_SOLO + role_type = NEUTRAL_KILL + // winner_award = /datum/award/achievement/mafia/traitor + + targeted_actions = list("Night Kill") + revealed_outfit = /datum/outfit/mafia/traitor + + hud_icon = "hudtraitor" + revealed_icon = "traitor" + special_theme = "neutral" + + var/datum/mafia_role/current_victim + +/datum/mafia_role/traitor/New(datum/mafia_controller/game) + . = ..() + RegisterSignal(src,COMSIG_MAFIA_ON_KILL,.proc/nightkill_immunity) + RegisterSignal(game,COMSIG_MAFIA_NIGHT_KILL_PHASE,.proc/try_to_kill) + +/datum/mafia_role/traitor/check_total_victory(alive_town, alive_mafia) //serial killers just want teams dead + return alive_town + alive_mafia <= 1 + +/datum/mafia_role/traitor/block_team_victory(alive_town, alive_mafia) //no team can win until they're dead + return TRUE //while alive, town AND mafia cannot win (though since mafia know who is who it's pretty easy to win from that point) + +/datum/mafia_role/traitor/proc/nightkill_immunity(datum/source,datum/mafia_controller/game,lynch) + if(game.phase == MAFIA_PHASE_NIGHT && !lynch) + to_chat(body,"You were attacked, but they'll have to try harder than that to put you down.") + return MAFIA_PREVENT_KILL + +/datum/mafia_role/traitor/validate_action_target(datum/mafia_controller/game, action, datum/mafia_role/target) + . = ..() + if(!.) + return FALSE + if(game.phase != MAFIA_PHASE_NIGHT || target.game_status != MAFIA_ALIVE || target == src) + return FALSE + +/datum/mafia_role/traitor/handle_action(datum/mafia_controller/game, action, datum/mafia_role/target) + . = ..() + current_victim = target + to_chat(body,"You will attempt to kill [target.body.real_name] tonight.") + +/datum/mafia_role/traitor/proc/try_to_kill(datum/mafia_controller/source) + var/datum/mafia_role/target = current_victim + current_victim = null + if(SEND_SIGNAL(src,COMSIG_MAFIA_CAN_PERFORM_ACTION,source,"traitor kill",target) & MAFIA_PREVENT_ACTION) + return + if(game_status == MAFIA_ALIVE && target && target.game_status == MAFIA_ALIVE) + if(!target.kill(source)) + to_chat(body,"Your attempt at killing [target.body] was prevented!") + +/datum/mafia_role/nightmare + name = "Nightmare" + desc = "You're a solo monster that cannot be detected by detective roles. You can flicker lights of another room each night. You can instead decide to hunt, killing everyone in a flickering room. Kill everyone to win." + win_condition = "kill everyone." + revealed_outfit = /datum/outfit/mafia/nightmare + detect_immune = TRUE + team = MAFIA_TEAM_SOLO + role_type = NEUTRAL_KILL + special_theme = "neutral" + hud_icon = "hudnightmare" + revealed_icon = "nightmare" + // winner_award = /datum/award/achievement/mafia/nightmare + + targeted_actions = list("Flicker", "Hunt") + var/list/flickering = list() + var/datum/mafia_role/flicker_target + +/datum/mafia_role/nightmare/New(datum/mafia_controller/game) + . = ..() + RegisterSignal(game,COMSIG_MAFIA_NIGHT_KILL_PHASE,.proc/flicker_or_hunt) + +/datum/mafia_role/nightmare/check_total_victory(alive_town, alive_mafia) //nightmares just want teams dead + return alive_town + alive_mafia <= 1 + +/datum/mafia_role/nightmare/block_team_victory(alive_town, alive_mafia) //no team can win until they're dead + return TRUE //while alive, town AND mafia cannot win (though since mafia know who is who it's pretty easy to win from that point) + +/datum/mafia_role/nightmare/special_reveal_equip() + body.underwear = "Nude" + body.undershirt = "Nude" + body.socks = "Nude" + body.set_species(/datum/species/shadow) + body.update_body() + +/datum/mafia_role/nightmare/validate_action_target(datum/mafia_controller/game, action, datum/mafia_role/target) + . = ..() + if(!. || game.phase != MAFIA_PHASE_NIGHT || target.game_status != MAFIA_ALIVE) + return FALSE + if(action == "Flicker") + return target != src && !(target in flickering) + return target == src + +/datum/mafia_role/nightmare/handle_action(datum/mafia_controller/game, action, datum/mafia_role/target) + . = ..() + if(target == flicker_target) + to_chat(body,"You will do nothing tonight.") + flicker_target = null + flicker_target = target + if(action == "Flicker") + to_chat(body,"You will attempt to flicker [target.body.real_name]'s room tonight.") + else + to_chat(body,"You will hunt everyone in a flickering room down tonight.") + +/datum/mafia_role/nightmare/proc/flicker_or_hunt(datum/mafia_controller/source) + if(game_status != MAFIA_ALIVE || !flicker_target) + return + if(SEND_SIGNAL(src,COMSIG_MAFIA_CAN_PERFORM_ACTION,source,"nightmare actions",flicker_target) & MAFIA_PREVENT_ACTION) + to_chat(flicker_target.body, "Your actions were prevented!") + return + var/datum/mafia_role/target = flicker_target + flicker_target = null + if(target != src) //flicker instead of hunt + to_chat(target.body, "The lights begin to flicker and dim. You're in danger.") + flickering += target + return + for(var/r in flickering) + var/datum/mafia_role/role = r + if(role && role.game_status == MAFIA_ALIVE) + to_chat(role.body, "A shadowy monster appears out of the darkness!") + role.kill(source) + flickering -= role + +//just helps read better +#define FUGITIVE_NOT_PRESERVING 0//will not become night immune tonight +#define FUGITIVE_WILL_PRESERVE 1 //will become night immune tonight + +/datum/mafia_role/fugitive + name = "Fugitive" + desc = "You're on the run. You can become immune to night kills exactly twice, and you win by surviving to the end of the game with anyone." + win_condition = "survive to the end of the game, with anyone" + solo_counts_as_town = TRUE //should not count towards mafia victory, they should have the option to work with town + revealed_outfit = /datum/outfit/mafia/fugitive + team = MAFIA_TEAM_SOLO + role_type = NEUTRAL_DISRUPT + special_theme = "neutral" + hud_icon = "hudfugitive" + revealed_icon = "fugitive" + // winner_award = /datum/award/achievement/mafia/fugitive + + actions = list("Self Preservation") + var/charges = 2 + var/protection_status = FUGITIVE_NOT_PRESERVING + + +/datum/mafia_role/fugitive/New(datum/mafia_controller/game) + . = ..() + RegisterSignal(game,COMSIG_MAFIA_SUNDOWN,.proc/night_start) + RegisterSignal(game,COMSIG_MAFIA_NIGHT_END,.proc/night_end) + RegisterSignal(game,COMSIG_MAFIA_GAME_END,.proc/survived) + +/datum/mafia_role/fugitive/handle_action(datum/mafia_controller/game, action, datum/mafia_role/target) + . = ..() + if(!charges) + to_chat(body,"You're out of supplies and cannot protect yourself anymore.") + return + if(game.phase == MAFIA_PHASE_NIGHT) + to_chat(body,"You don't have time to prepare, night has already arrived.") + return + if(protection_status == FUGITIVE_WILL_PRESERVE) + to_chat(body,"You decide to not prepare tonight.") + else + to_chat(body,"You decide to prepare for a horrible night.") + protection_status = !protection_status + +/datum/mafia_role/fugitive/proc/night_start(datum/mafia_controller/game) + if(protection_status == FUGITIVE_WILL_PRESERVE) + to_chat(body,"Your preparations are complete. Nothing could kill you tonight!") + RegisterSignal(src,COMSIG_MAFIA_ON_KILL,.proc/prevent_death) + +/datum/mafia_role/fugitive/proc/night_end(datum/mafia_controller/game) + if(protection_status == FUGITIVE_WILL_PRESERVE) + charges-- + UnregisterSignal(src,COMSIG_MAFIA_ON_KILL) + to_chat(body,"You are no longer protected. You have [charges] use[charges == 1 ? "" : "s"] left of your power.") + protection_status = FUGITIVE_NOT_PRESERVING + +/datum/mafia_role/fugitive/proc/prevent_death(datum/mafia_controller/game) + to_chat(body,"You were attacked! Luckily, you were ready for this!") + return MAFIA_PREVENT_KILL + +/datum/mafia_role/fugitive/proc/survived(datum/mafia_controller/game) + if(game_status == MAFIA_ALIVE) + // var/client/winner_client = GLOB.directory[player_key] + // winner_client?.give_award(winner_award, body) + game.send_message("!! FUGITIVE VICTORY !!") + +#undef FUGITIVE_NOT_PRESERVING +#undef FUGITIVE_WILL_PRESERVE + +/datum/mafia_role/obsessed + name = "Obsessed" + desc = "You're completely lost in your own mind. You win by lynching your obsession before you get killed in this mess. Obsession assigned on the first night!" + win_condition = "lynch their obsession." + revealed_outfit = /datum/outfit/mafia/obsessed // /mafia <- outfit must be readded (just make a new mafia outfits file for all of these) + solo_counts_as_town = TRUE //after winning or whatever, can side with whoever. they've already done their objective! + team = MAFIA_TEAM_SOLO + role_type = NEUTRAL_DISRUPT + special_theme = "neutral" + hud_icon = "hudobsessed" + revealed_icon = "obsessed" + + // winner_award = /datum/award/achievement/mafia/obsessed + + revealed_outfit = /datum/outfit/mafia/obsessed // /mafia <- outfit must be readded (just make a new mafia outfits file for all of these) + solo_counts_as_town = TRUE //after winning or whatever, can side with whoever. they've already done their objective! + var/datum/mafia_role/obsession + var/lynched_target = FALSE + +/datum/mafia_role/obsessed/New(datum/mafia_controller/game) //note: obsession is always a townie + . = ..() + RegisterSignal(game,COMSIG_MAFIA_SUNDOWN,.proc/find_obsession) + +/datum/mafia_role/obsessed/proc/find_obsession(datum/mafia_controller/game) + var/list/all_roles_shuffle = shuffle(game.all_roles) + for(var/role in all_roles_shuffle) + var/datum/mafia_role/possible = role + if(possible.team == MAFIA_TEAM_TOWN && possible.game_status != MAFIA_DEAD) + obsession = possible + break + if(!obsession) + obsession = pick(all_roles_shuffle) //okay no town just pick anyone here + //if you still don't have an obsession you're playing a single player game like i can't help your dumb ass + to_chat(body, "Your obsession is [obsession.body.real_name]! Get them lynched to win!") + add_note("N[game.turn] - I vowed to watch my obsession, [obsession.body.real_name], hang!") //it'll always be N1 but whatever + RegisterSignal(obsession,COMSIG_MAFIA_ON_KILL,.proc/check_victory) + UnregisterSignal(game,COMSIG_MAFIA_SUNDOWN) + +/datum/mafia_role/obsessed/proc/check_victory(datum/source,datum/mafia_controller/game,lynch) + UnregisterSignal(source,COMSIG_MAFIA_ON_KILL) + if(game_status == MAFIA_DEAD) + return + if(lynch) + game.send_message("!! OBSESSED VICTORY !!") + // var/client/winner_client = GLOB.directory[player_key] + // winner_client?.give_award(winner_award, body) + reveal_role(game, FALSE) + else + to_chat(body, "You have failed your objective to lynch [obsession.body]!") + +/datum/mafia_role/clown + name = "Clown" + desc = "If you are lynched you take down one of your voters (guilty or abstain) with you and win. HONK!" + win_condition = "get themselves lynched!" + revealed_outfit = /datum/outfit/mafia/clown + solo_counts_as_town = TRUE + team = MAFIA_TEAM_SOLO + role_type = NEUTRAL_DISRUPT + special_theme = "neutral" + hud_icon = "hudclown" + revealed_icon = "clown" + // winner_award = /datum/award/achievement/mafia/clown + +/datum/mafia_role/clown/New(datum/mafia_controller/game) + . = ..() + RegisterSignal(src,COMSIG_MAFIA_ON_KILL,.proc/prank) + +/datum/mafia_role/clown/proc/prank(datum/source,datum/mafia_controller/game,lynch) + if(lynch) + var/datum/mafia_role/victim = pick(game.judgement_guilty_votes + game.judgement_abstain_votes) + game.send_message("[body.real_name] WAS A CLOWN! HONK! They take down [victim.body.real_name] with their last prank.") + game.send_message("!! CLOWN VICTORY !!") + // var/client/winner_client = GLOB.directory[player_key] + // winner_client?.give_award(winner_award, body) + victim.kill(game,FALSE) diff --git a/code/modules/mapping/map_config.dm b/code/modules/mapping/map_config.dm index efa2655325..c03ef65f43 100644 --- a/code/modules/mapping/map_config.dm +++ b/code/modules/mapping/map_config.dm @@ -20,7 +20,7 @@ var/map_file = "BoxStation.dmm" var/traits = null - var/space_ruin_levels = 2 + var/space_ruin_levels = 4 var/space_empty_levels = 1 var/station_ruin_budget = -1 // can be set to manually override the station ruins budget on maps that don't support station ruins, stopping the error from being unable to place the ruins. diff --git a/code/modules/mining/equipment/kinetic_crusher.dm b/code/modules/mining/equipment/kinetic_crusher.dm index 7a755265dc..a6f456ce6f 100644 --- a/code/modules/mining/equipment/kinetic_crusher.dm +++ b/code/modules/mining/equipment/kinetic_crusher.dm @@ -183,9 +183,49 @@ attack_verb = list("stabbed", "diced", "sliced", "cleaved", "chopped", "lacerated", "cut", "jabbed", "punctured") icon_state = "crusher-glaive" item_state = "crusher0-glaive" + block_parry_data = /datum/block_parry_data/crusherglaive //ideas: altclick that lets you pummel people with the handguard/handle? //parrying functionality? +/datum/block_parry_data/crusherglaive // small perfect window, active for a fair while, time it right or use the Forbidden Technique + parry_time_windup = 0 + parry_time_active = 8 + parry_time_spindown = 0 + parry_time_perfect = 1 + parry_time_perfect_leeway = 2 + parry_imperfect_falloff_percent = 20 + parry_efficiency_to_counterattack = 100 // perfect parry or you're cringe + parry_failed_stagger_duration = 1.5 SECONDS // a good time to reconsider your actions... + parry_failed_clickcd_duration = 1.5 SECONDS // or your failures + +/obj/item/kinetic_crusher/glaive/on_active_parry(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, list/block_return, parry_efficiency, parry_time) // if you're dumb enough to go for a parry... + var/turf/proj_turf = owner.loc // destabilizer bolt, ignoring cooldown + if(!isturf(proj_turf)) + return + var/obj/item/projectile/destabilizer/D = new /obj/item/projectile/destabilizer(proj_turf) + for(var/t in trophies) + var/obj/item/crusher_trophy/T = t + T.on_projectile_fire(D, owner) + D.preparePixelProjectile(attacker, owner) + D.firer = owner + D.hammer_synced = src + playsound(owner, 'sound/weapons/plasma_cutter.ogg', 100, 1) + D.fire() + +/obj/item/kinetic_crusher/glaive/active_parry_reflex_counter(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, list/return_list, parry_efficiency, list/effect_text) + if(owner.Adjacent(attacker) && (!attacker.anchored || ismegafauna(attacker))) // free backstab, if you perfect parry + attacker.dir = get_dir(owner,attacker) + +/// triggered on wield of two handed item +/obj/item/kinetic_crusher/glaive/on_wield(obj/item/source, mob/user) + wielded = TRUE + item_flags |= (ITEM_CAN_PARRY) + +/// triggered on unwield of two handed item +/obj/item/kinetic_crusher/glaive/on_unwield(obj/item/source, mob/user) + wielded = FALSE + item_flags &= ~(ITEM_CAN_PARRY) + /obj/item/kinetic_crusher/glaive/update_icon_state() item_state = "crusher[wielded]-glaive" // this is not icon_state and not supported by 2hcomponent diff --git a/code/modules/mining/laborcamp/laborstacker.dm b/code/modules/mining/laborcamp/laborstacker.dm index 4d0b7dff21..429dc98e8a 100644 --- a/code/modules/mining/laborcamp/laborstacker.dm +++ b/code/modules/mining/laborcamp/laborstacker.dm @@ -8,8 +8,6 @@ GLOBAL_LIST(labor_sheet_values) icon = 'icons/obj/machines/mining_machines.dmi' icon_state = "console" density = FALSE - ui_x = 315 - ui_y = 430 var/obj/machinery/mineral/stacking_machine/laborstacker/stacking_machine = null var/machinedir = SOUTH @@ -35,11 +33,10 @@ GLOBAL_LIST(labor_sheet_values) /proc/cmp_sheet_list(list/a, list/b) return a["value"] - b["value"] -/obj/machinery/mineral/labor_claim_console/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ - datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) +/obj/machinery/mineral/labor_claim_console/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) if(!ui) - ui = new(user, src, ui_key, "LaborClaimConsole", name, ui_x, ui_y, master_ui, state) + ui = new(user, src, "LaborClaimConsole", name) ui.open() /obj/machinery/mineral/labor_claim_console/ui_data(mob/user) @@ -121,7 +118,7 @@ GLOBAL_LIST(labor_sheet_values) /obj/machinery/mineral/stacking_machine/laborstacker force_connect = TRUE var/points = 0 //The unclaimed value of ore stacked. - + //damage_deflection = 21 /obj/machinery/mineral/stacking_machine/laborstacker/process_sheet(obj/item/stack/sheet/inp) points += inp.point_value * inp.amount ..() diff --git a/code/modules/mining/machine_redemption.dm b/code/modules/mining/machine_redemption.dm index bae0e94032..0268d32a6b 100644 --- a/code/modules/mining/machine_redemption.dm +++ b/code/modules/mining/machine_redemption.dm @@ -195,10 +195,10 @@ to_chat(user, "You change [src]'s I/O settings, setting the input to [dir2text(input_dir)] and the output to [dir2text(output_dir)].") return TRUE -/obj/machinery/mineral/ore_redemption/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) +/obj/machinery/mineral/ore_redemption/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) if(!ui) - ui = new(user, src, ui_key, "OreRedemptionMachine", "Ore Redemption Machine", 440, 550, master_ui, state) + ui = new(user, src, "OreRedemptionMachine") ui.open() /obj/machinery/mineral/ore_redemption/ui_data(mob/user) diff --git a/code/modules/mining/machine_vending.dm b/code/modules/mining/machine_vending.dm index 564d554319..2cbb965ef5 100644 --- a/code/modules/mining/machine_vending.dm +++ b/code/modules/mining/machine_vending.dm @@ -7,8 +7,6 @@ icon_state = "mining" density = TRUE circuit = /obj/item/circuitboard/machine/mining_equipment_vendor - ui_x = 425 - ui_y = 600 var/icon_deny = "mining-deny" var/obj/item/card/id/inserted_id var/list/prize_list = list( //if you add something to this, please, for the love of god, sort it by price/type. use tabs and not spaces. @@ -68,13 +66,13 @@ new /datum/data/mining_equipment("KA Adjustable Tracer Rounds", /obj/item/borg/upgrade/modkit/tracer/adjustable, 150), new /datum/data/mining_equipment("KA Super Chassis", /obj/item/borg/upgrade/modkit/chassis_mod, 250), new /datum/data/mining_equipment("KA Hyper Chassis", /obj/item/borg/upgrade/modkit/chassis_mod/orange, 300), - new /datum/data/mining_equipment("Kinetic Glaive", /obj/item/kinetic_crusher/glaive, 1500), new /datum/data/mining_equipment("KA Range Increase", /obj/item/borg/upgrade/modkit/range, 1000), new /datum/data/mining_equipment("KA Damage Increase", /obj/item/borg/upgrade/modkit/damage, 1000), new /datum/data/mining_equipment("KA Cooldown Decrease", /obj/item/borg/upgrade/modkit/cooldown, 1000), new /datum/data/mining_equipment("KA AoE Damage", /obj/item/borg/upgrade/modkit/aoe/mobs, 2000), new /datum/data/mining_equipment("Miner Full Replacement", /obj/item/storage/backpack/duffelbag/mining_cloned, 3000), - new /datum/data/mining_equipment("Premium Accelerator", /obj/item/gun/energy/kinetic_accelerator/premiumka, 8000) + new /datum/data/mining_equipment("Premium Accelerator", /obj/item/gun/energy/kinetic_accelerator/premiumka, 8000), + new /datum/data/mining_equipment("Kinetic Glaive", /obj/item/kinetic_crusher/glaive, 2250), ) /datum/data/mining_equipment @@ -102,17 +100,15 @@ else icon_state = "[initial(icon_state)]-off" -/obj/machinery/mineral/equipment_vendor/ui_base_html(html) - var/datum/asset/spritesheet/assets = get_asset_datum(/datum/asset/spritesheet/vending) - . = replacetext(html, "", assets.css_tag()) +/obj/machinery/mineral/equipment_vendor/ui_assets(mob/user) + return list( + get_asset_datum(/datum/asset/spritesheet/vending), + ) -/obj/machinery/mineral/equipment_vendor/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ - datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) +/obj/machinery/mineral/equipment_vendor/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) if(!ui) - var/datum/asset/assets = get_asset_datum(/datum/asset/spritesheet/vending) - assets.send(user) - ui = new(user, src, ui_key, "MiningVendor", name, ui_x, ui_y, master_ui, state) + ui = new(user, src, "MiningVendor", name) ui.open() /obj/machinery/mineral/equipment_vendor/ui_static_data(mob/user) @@ -137,10 +133,12 @@ if(C) .["user"] = list() .["user"]["points"] = C.mining_points - if(C.assignment) - .["user"]["job"] = C.assignment - else - .["user"]["job"] = "No Job" + if(C.registered_account) + .["user"]["name"] = C.registered_account.account_holder + if(C.registered_account.account_job) + .["user"]["job"] = C.registered_account.account_job.title + else + .["user"]["job"] = "No Job" /obj/machinery/mineral/equipment_vendor/ui_act(action, params) if(..()) diff --git a/code/modules/mining/satchel_ore_boxdm.dm b/code/modules/mining/satchel_ore_boxdm.dm index ae42ca4745..36da9d5db9 100644 --- a/code/modules/mining/satchel_ore_boxdm.dm +++ b/code/modules/mining/satchel_ore_boxdm.dm @@ -9,9 +9,6 @@ density = TRUE pressure_resistance = 5*ONE_ATMOSPHERE - var/ui_x = 335 - var/ui_y = 415 - /obj/structure/ore_box/attackby(obj/item/W, mob/user, params) if (istype(W, /obj/item/stack/ore)) user.transferItemToLoc(W, src) @@ -58,11 +55,10 @@ stoplag() drop = drop_location() -/obj/structure/ore_box/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ - datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) +/obj/structure/ore_box/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) if(!ui) - ui = new(user, src, ui_key, "OreBox", name, ui_x, ui_y, master_ui, state) + ui = new(user, src, "OreBox", name) ui.open() /obj/structure/ore_box/ui_data() diff --git a/code/modules/mob/dead/new_player/sprite_accessories/Citadel_Snowflake.dm b/code/modules/mob/dead/new_player/sprite_accessories/Citadel_Snowflake.dm index 020776a75f..3c2c850e3c 100644 --- a/code/modules/mob/dead/new_player/sprite_accessories/Citadel_Snowflake.dm +++ b/code/modules/mob/dead/new_player/sprite_accessories/Citadel_Snowflake.dm @@ -1,9 +1,9 @@ -/datum/sprite_accessory/mam_tails/shark/datashark +/datum/sprite_accessory/tails/mam_tails/shark/datashark name = "DataShark" icon_state = "datashark" ckeys_allowed = list("rubyflamewing") -/datum/sprite_accessory/mam_tails_animated/shark/datashark +/datum/sprite_accessory/tails_animated/mam_tails_animated/shark/datashark name = "DataShark" icon_state = "datashark" ckeys_allowed = list("rubyflamewing") @@ -14,19 +14,19 @@ ckeys_allowed = list("rubyflamewing") //Sabresune -/datum/sprite_accessory/mam_ears/sabresune +/datum/sprite_accessory/ears/mam_ears/sabresune name = "Sabresune" icon_state = "sabresune" ckeys_allowed = list("poojawa") extra = TRUE extra_color_src = MUTCOLORS3 -/datum/sprite_accessory/mam_tails/sabresune +/datum/sprite_accessory/tails/mam_tails/sabresune name = "Sabresune" icon_state = "sabresune" ckeys_allowed = list("poojawa") -/datum/sprite_accessory/mam_tails_animated/sabresune +/datum/sprite_accessory/tails_animated/mam_tails_animated/sabresune name = "Sabresune" icon_state = "sabresune" ckeys_allowed = list("poojawa") @@ -37,17 +37,17 @@ ckeys_allowed = list("poojawa") //Lunasune -/datum/sprite_accessory/mam_ears/lunasune +/datum/sprite_accessory/ears/mam_ears/lunasune name = "lunasune" icon_state = "lunasune" ckeys_allowed = list("invader4352") -/datum/sprite_accessory/mam_tails/lunasune +/datum/sprite_accessory/tails/mam_tails/lunasune name = "lunasune" icon_state = "lunasune" ckeys_allowed = list("invader4352") -/datum/sprite_accessory/mam_tails_animated/lunasune +/datum/sprite_accessory/tails_animated/mam_tails_animated/lunasune name = "lunasune" icon_state = "lunasune" ckeys_allowed = list("invader4352") diff --git a/code/modules/mob/dead/new_player/sprite_accessories/_sprite_accessories.dm b/code/modules/mob/dead/new_player/sprite_accessories/_sprite_accessories.dm index 6514cb4f80..4cb8d080ff 100644 --- a/code/modules/mob/dead/new_player/sprite_accessories/_sprite_accessories.dm +++ b/code/modules/mob/dead/new_player/sprite_accessories/_sprite_accessories.dm @@ -76,6 +76,9 @@ //For soft-restricting markings to species IDs var/list/recommended_species +/datum/sprite_accessory/proc/is_not_visible(var/mob/living/carbon/human/H, var/tauric) //return if the accessory shouldn't be shown + return FALSE + /datum/sprite_accessory/underwear icon = 'icons/mob/clothing/underwear.dmi' var/has_color = FALSE diff --git a/code/modules/mob/dead/new_player/sprite_accessories/alienpeople.dm b/code/modules/mob/dead/new_player/sprite_accessories/alienpeople.dm index c8e7aca26d..899bf91081 100644 --- a/code/modules/mob/dead/new_player/sprite_accessories/alienpeople.dm +++ b/code/modules/mob/dead/new_player/sprite_accessories/alienpeople.dm @@ -7,6 +7,9 @@ mutant_part_string = "xenodorsal" relevant_layers = list(BODY_BEHIND_LAYER, BODY_FRONT_LAYER) +/datum/sprite_accessory/xeno_dorsal/is_not_visible(var/mob/living/carbon/human/H, var/tauric) + return (!H.dna.features["xenodorsal"] || H.dna.features["xenodorsal"] == "None" || (H.wear_suit && (H.wear_suit.flags_inv & HIDEJUMPSUIT))) + /datum/sprite_accessory/xeno_dorsal/standard name = "Standard" icon_state = "standard" @@ -27,6 +30,9 @@ mutant_part_string = "tail" relevant_layers = list(BODY_BEHIND_LAYER, BODY_FRONT_LAYER) +/datum/sprite_accessory/xeno_tail/is_not_visible(var/mob/living/carbon/human/H, var/tauric) + return (!H.dna.features["xenotail"] || H.dna.features["xenotail"] == "None" || H.wear_suit && (H.wear_suit.flags_inv & HIDEJUMPSUIT)) + /datum/sprite_accessory/xeno_tail/none name = "None" relevant_layers = null @@ -43,6 +49,10 @@ mutant_part_string = "xhead" relevant_layers = list(BODY_ADJ_LAYER) +/datum/sprite_accessory/xeno_head/is_not_visible(var/mob/living/carbon/human/H, var/tauric) + var/obj/item/bodypart/head/HD = H.get_bodypart(BODY_ZONE_HEAD) + return (!H.dna.features["xenohead"] || H.dna.features["xenohead"] == "None" || H.head && (H.head.flags_inv & HIDEHAIR) || (H.wear_mask && (H.wear_mask.flags_inv & HIDEHAIR)) || !HD || HD.status == BODYPART_ROBOTIC) + /datum/sprite_accessory/xeno_head/standard name = "Standard" icon_state = "standard" diff --git a/code/modules/mob/dead/new_player/sprite_accessories/body_markings.dm b/code/modules/mob/dead/new_player/sprite_accessories/body_markings.dm index 9950f0d76a..a04838a360 100644 --- a/code/modules/mob/dead/new_player/sprite_accessories/body_markings.dm +++ b/code/modules/mob/dead/new_player/sprite_accessories/body_markings.dm @@ -224,6 +224,9 @@ color_src = 0 relevant_layers = list(BODY_FRONT_LAYER) +/datum/sprite_accessory/insect_fluff/is_not_visible(var/mob/living/carbon/human/H, var/tauric) + return (!H.dna.features["insect_fluff"] || H.dna.features["insect_fluff"] == "None" || H.wear_suit && (H.wear_suit.flags_inv & HIDEJUMPSUIT)) + /datum/sprite_accessory/insect_fluff/none name = "None" icon_state = "none" diff --git a/code/modules/mob/dead/new_player/sprite_accessories/ears.dm b/code/modules/mob/dead/new_player/sprite_accessories/ears.dm index bc269ccf62..1e6c797364 100644 --- a/code/modules/mob/dead/new_player/sprite_accessories/ears.dm +++ b/code/modules/mob/dead/new_player/sprite_accessories/ears.dm @@ -3,6 +3,10 @@ mutant_part_string = "ears" relevant_layers = list(BODY_BEHIND_LAYER, BODY_ADJ_LAYER, BODY_FRONT_LAYER) +/datum/sprite_accessory/ears/is_not_visible(var/mob/living/carbon/human/H, var/tauric) + var/obj/item/bodypart/head/HD = H.get_bodypart(BODY_ZONE_HEAD) + return (!H.dna.features["ears"] || H.dna.features["ears"] == "None" || H.head && (H.head.flags_inv & HIDEEARS) || (H.wear_mask && (H.wear_mask.flags_inv & HIDEEARS)) || !HD || HD.status == BODYPART_ROBOTIC) + /datum/sprite_accessory/ears/none name = "None" icon_state = "none" @@ -175,50 +179,54 @@ *************** Furry Ears **************** *******************************************/ -/datum/sprite_accessory/mam_ears +/datum/sprite_accessory/ears/mam_ears icon = 'modular_citadel/icons/mob/mam_ears.dmi' color_src = MATRIXED mutant_part_string = "ears" relevant_layers = list(BODY_BEHIND_LAYER, BODY_ADJ_LAYER, BODY_FRONT_LAYER) -/datum/sprite_accessory/mam_ears/none +/datum/sprite_accessory/ears/mam_ears/is_not_visible(var/mob/living/carbon/human/H, var/tauric) + var/obj/item/bodypart/head/HD = H.get_bodypart(BODY_ZONE_HEAD) + return (!H.dna.features["mam_ears"] || H.dna.features["mam_ears"] == "None" || H.head && (H.head.flags_inv & HIDEEARS) || (H.wear_mask && (H.wear_mask.flags_inv & HIDEEARS)) || !HD || HD.status == BODYPART_ROBOTIC) + +/datum/sprite_accessory/ears/mam_ears/none name = "None" icon_state = "none" relevant_layers = null -/datum/sprite_accessory/mam_ears/axolotl +/datum/sprite_accessory/ears/mam_ears/axolotl name = "Axolotl" icon_state = "axolotl" -/datum/sprite_accessory/mam_ears/bat +/datum/sprite_accessory/ears/mam_ears/bat name = "Bat" icon_state = "bat" -/datum/sprite_accessory/mam_ears/bear +/datum/sprite_accessory/ears/mam_ears/bear name = "Bear" icon_state = "bear" -/datum/sprite_accessory/mam_ears/bigwolf +/datum/sprite_accessory/ears/mam_ears/bigwolf name = "Big Wolf" icon_state = "bigwolf" -/datum/sprite_accessory/mam_ears/bigwolfinner +/datum/sprite_accessory/ears/mam_ears/bigwolfinner name = "Big Wolf (ALT)" icon_state = "bigwolfinner" extra = TRUE extra_color_src = NONE -/datum/sprite_accessory/mam_ears/bigwolfdark +/datum/sprite_accessory/ears/mam_ears/bigwolfdark name = "Dark Big Wolf" icon_state = "bigwolfdark" -/datum/sprite_accessory/mam_ears/bigwolfinnerdark +/datum/sprite_accessory/ears/mam_ears/bigwolfinnerdark name = "Dark Big Wolf (ALT)" icon_state = "bigwolfinnerdark" extra = TRUE extra_color_src = NONE -/datum/sprite_accessory/mam_ears/cat +/datum/sprite_accessory/ears/mam_ears/cat name = "Cat" icon_state = "cat" icon = 'icons/mob/mutant_bodyparts.dmi' @@ -226,100 +234,100 @@ extra = TRUE extra_color_src = NONE -/datum/sprite_accessory/mam_ears/catbig +/datum/sprite_accessory/ears/mam_ears/catbig name = "Cat, Big" icon_state = "catbig" -/datum/sprite_accessory/mam_ears/cow +/datum/sprite_accessory/ears/mam_ears/cow name = "Cow" icon_state = "cow" -/datum/sprite_accessory/mam_ears/curled +/datum/sprite_accessory/ears/mam_ears/curled name = "Curled Horn" icon_state = "horn1" color_src = MUTCOLORS3 -/datum/sprite_accessory/mam_ears/deer +/datum/sprite_accessory/ears/mam_ears/deer name = "Deer" icon_state = "deer" color_src = MUTCOLORS3 -/datum/sprite_accessory/mam_ears/eevee +/datum/sprite_accessory/ears/mam_ears/eevee name = "Eevee" icon_state = "eevee" -/datum/sprite_accessory/mam_ears/elf +/datum/sprite_accessory/ears/mam_ears/elf name = "Elf" icon_state = "elf" color_src = MUTCOLORS3 -/datum/sprite_accessory/mam_ears/elephant +/datum/sprite_accessory/ears/mam_ears/elephant name = "Elephant" icon_state = "elephant" -/datum/sprite_accessory/mam_ears/fennec +/datum/sprite_accessory/ears/mam_ears/fennec name = "Fennec" icon_state = "fennec" -/datum/sprite_accessory/mam_ears/fish +/datum/sprite_accessory/ears/mam_ears/fish name = "Fish" icon_state = "fish" -/datum/sprite_accessory/mam_ears/fox +/datum/sprite_accessory/ears/mam_ears/fox name = "Fox" icon_state = "fox" -/datum/sprite_accessory/mam_ears/husky +/datum/sprite_accessory/ears/mam_ears/husky name = "Husky" icon_state = "wolf" -/datum/sprite_accessory/mam_ears/kangaroo +/datum/sprite_accessory/ears/mam_ears/kangaroo name = "kangaroo" icon_state = "kangaroo" -/datum/sprite_accessory/mam_ears/jellyfish +/datum/sprite_accessory/ears/mam_ears/jellyfish name = "Jellyfish" icon_state = "jellyfish" color_src = HAIR -/datum/sprite_accessory/mam_ears/lab +/datum/sprite_accessory/ears/mam_ears/lab name = "Dog, Long" icon_state = "lab" -/datum/sprite_accessory/mam_ears/murid +/datum/sprite_accessory/ears/mam_ears/murid name = "Murid" icon_state = "murid" -/datum/sprite_accessory/mam_ears/otie +/datum/sprite_accessory/ears/mam_ears/otie name = "Otusian" icon_state = "otie" -/datum/sprite_accessory/mam_ears/squirrel +/datum/sprite_accessory/ears/mam_ears/squirrel name = "Squirrel" icon_state = "squirrel" -/datum/sprite_accessory/mam_ears/pede +/datum/sprite_accessory/ears/mam_ears/pede name = "Scolipede" icon_state = "pede" -/datum/sprite_accessory/mam_ears/rabbit +/datum/sprite_accessory/ears/mam_ears/rabbit name = "Rabbit" icon_state = "rabbit" -/datum/sprite_accessory/mam_ears/sergal +/datum/sprite_accessory/ears/mam_ears/sergal name = "Sergal" icon_state = "sergal" -/datum/sprite_accessory/mam_ears/skunk +/datum/sprite_accessory/ears/mam_ears/skunk name = "skunk" icon_state = "skunk" -/datum/sprite_accessory/mam_ears/wolf +/datum/sprite_accessory/ears/mam_ears/wolf name = "Wolf" icon_state = "wolf" -/datum/sprite_accessory/mam_ears/bunny +/datum/sprite_accessory/ears/mam_ears/bunny name = "Bunny" icon_state = "bunny" diff --git a/code/modules/mob/dead/new_player/sprite_accessories/frills.dm b/code/modules/mob/dead/new_player/sprite_accessories/frills.dm index 0aaec309a4..18a76df116 100644 --- a/code/modules/mob/dead/new_player/sprite_accessories/frills.dm +++ b/code/modules/mob/dead/new_player/sprite_accessories/frills.dm @@ -2,6 +2,10 @@ icon = 'icons/mob/mutant_bodyparts.dmi' relevant_layers = list(BODY_ADJ_LAYER) +/datum/sprite_accessory/frills/is_not_visible(var/mob/living/carbon/human/H, var/tauric) + var/obj/item/bodypart/head/HD = H.get_bodypart(BODY_ZONE_HEAD) + return (!H.dna.features["frills"] || H.dna.features["frills"] == "None" || H.head && (H.head.flags_inv & HIDEEARS) || !HD || HD.status == BODYPART_ROBOTIC) + /datum/sprite_accessory/frills/none name = "None" icon_state = "none" diff --git a/code/modules/mob/dead/new_player/sprite_accessories/hair_head.dm b/code/modules/mob/dead/new_player/sprite_accessories/hair_head.dm index 89f2dd5370..138704067d 100644 --- a/code/modules/mob/dead/new_player/sprite_accessories/hair_head.dm +++ b/code/modules/mob/dead/new_player/sprite_accessories/hair_head.dm @@ -791,6 +791,10 @@ name = "Volaju" icon_state = "hair_volaju" +/datum/sprite_accessory/hair/volajupompless + name = "Volaju (Alt)" + icon_state = "hair_volajupompless" + /datum/sprite_accessory/hair/wisp name = "Wisp" icon_state = "hair_wisp" diff --git a/code/modules/mob/dead/new_player/sprite_accessories/horns.dm b/code/modules/mob/dead/new_player/sprite_accessories/horns.dm index b39f48f858..3a65eaebfa 100644 --- a/code/modules/mob/dead/new_player/sprite_accessories/horns.dm +++ b/code/modules/mob/dead/new_player/sprite_accessories/horns.dm @@ -3,6 +3,10 @@ color_src = HORNCOLOR relevant_layers = list(HORNS_LAYER) +/datum/sprite_accessory/horns/is_not_visible(var/mob/living/carbon/human/H, var/tauric) + var/obj/item/bodypart/head/HD = H.get_bodypart(BODY_ZONE_HEAD) + return (!H.dna.features["horns"] || H.dna.features["horns"] == "None" || H.head && (H.head.flags_inv & HIDEHAIR) || (H.wear_mask && (H.wear_mask.flags_inv & HIDEHAIR)) || !HD || HD.status == BODYPART_ROBOTIC) + /datum/sprite_accessory/horns/none name = "None" icon_state = "none" diff --git a/code/modules/mob/dead/new_player/sprite_accessories/legs_and_taurs.dm b/code/modules/mob/dead/new_player/sprite_accessories/legs_and_taurs.dm index 2ec6da2da8..d41f5ace22 100644 --- a/code/modules/mob/dead/new_player/sprite_accessories/legs_and_taurs.dm +++ b/code/modules/mob/dead/new_player/sprite_accessories/legs_and_taurs.dm @@ -30,6 +30,9 @@ var/alt_taur_mode = NONE //Same as above. var/hide_legs = USE_QUADRUPED_CLIP_MASK +/datum/sprite_accessory/taur/is_not_visible(var/mob/living/carbon/human/H, var/tauric) + return (!tauric || (H.wear_suit && (H.wear_suit.flags_inv & HIDETAUR))) + /datum/sprite_accessory/taur/New() switch(hide_legs) if(USE_QUADRUPED_CLIP_MASK) diff --git a/code/modules/mob/dead/new_player/sprite_accessories/snouts.dm b/code/modules/mob/dead/new_player/sprite_accessories/snouts.dm index 60e8ed1007..f514ef54db 100644 --- a/code/modules/mob/dead/new_player/sprite_accessories/snouts.dm +++ b/code/modules/mob/dead/new_player/sprite_accessories/snouts.dm @@ -3,6 +3,10 @@ mutant_part_string = "snout" relevant_layers = list(BODY_ADJ_LAYER, BODY_FRONT_LAYER) +/datum/sprite_accessory/snouts/is_not_visible(var/mob/living/carbon/human/H, var/tauric) + var/obj/item/bodypart/head/HD = H.get_bodypart(BODY_ZONE_HEAD) + return ((H.wear_mask && (H.wear_mask.flags_inv & HIDESNOUT)) || (H.head && (H.head.flags_inv & HIDESNOUT)) || !HD || HD.status == BODYPART_ROBOTIC) + /datum/sprite_accessory/snouts/sharp name = "Sharp" icon_state = "sharp" @@ -150,130 +154,140 @@ ************** Mammal Snouts ************** *******************************************/ -/datum/sprite_accessory/mam_snouts +/datum/sprite_accessory/snouts/mam_snouts color_src = MATRIXED icon = 'modular_citadel/icons/mob/mam_snouts.dmi' - recommended_species = list("mammal", "slimeperson", "insect", "podweak") + recommended_species = list("mammal", "slimeperson", "insect", "podweak", "lizard") mutant_part_string = "snout" relevant_layers = list(BODY_ADJ_LAYER, BODY_FRONT_LAYER) -/datum/sprite_accessory/mam_snouts/none +/datum/sprite_accessory/snouts/mam_snouts/is_not_visible(var/mob/living/carbon/human/H, var/tauric) + var/obj/item/bodypart/head/HD = H.get_bodypart(BODY_ZONE_HEAD) + return ((H.wear_mask && (H.wear_mask.flags_inv & HIDESNOUT)) || (H.head && (H.head.flags_inv & HIDESNOUT)) || !HD || HD.status == BODYPART_ROBOTIC) + +/datum/sprite_accessory/snouts/mam_snouts/none name = "None" icon_state = "none" recommended_species = null relevant_layers = null -/datum/sprite_accessory/mam_snouts/bird +/datum/sprite_accessory/snouts/mam_snouts/bird name = "Beak" icon_state = "bird" -/datum/sprite_accessory/mam_snouts/bigbeak +/datum/sprite_accessory/snouts/mam_snouts/bigbeak name = "Big Beak" icon_state = "bigbeak" -/datum/sprite_accessory/mam_snouts/bug +/datum/sprite_accessory/snouts/mam_snouts/bug name = "Bug" icon_state = "bug" color_src = MUTCOLORS extra2 = TRUE extra2_color_src = MUTCOLORS3 -/datum/sprite_accessory/mam_snouts/elephant +/datum/sprite_accessory/snouts/mam_snouts/elephant name = "Elephant" icon_state = "elephant" extra = TRUE extra_color_src = MUTCOLORS3 -/datum/sprite_accessory/mam_snouts/lcanid +/datum/sprite_accessory/snouts/mam_snouts/skulldog + name = "Skulldog" + icon_state = "skulldog" + extra = TRUE + extra_color_src = MATRIXED + +/datum/sprite_accessory/snouts/mam_snouts/lcanid name = "Mammal, Long" icon_state = "lcanid" -/datum/sprite_accessory/mam_snouts/lcanidalt +/datum/sprite_accessory/snouts/mam_snouts/lcanidalt name = "Mammal, Long ALT" icon_state = "lcanidalt" -/datum/sprite_accessory/mam_snouts/scanid +/datum/sprite_accessory/snouts/mam_snouts/scanid name = "Mammal, Short" icon_state = "scanid" -/datum/sprite_accessory/mam_snouts/scanidalt +/datum/sprite_accessory/snouts/mam_snouts/scanidalt name = "Mammal, Short ALT" icon_state = "scanidalt" -/datum/sprite_accessory/mam_snouts/scanidalt2 +/datum/sprite_accessory/snouts/mam_snouts/scanidalt2 name = "Mammal, Short ALT 2" icon_state = "scanidalt2" -/datum/sprite_accessory/mam_snouts/wolf +/datum/sprite_accessory/snouts/mam_snouts/wolf name = "Mammal, Thick" icon_state = "wolf" -/datum/sprite_accessory/mam_snouts/wolfalt +/datum/sprite_accessory/snouts/mam_snouts/wolfalt name = "Mammal, Thick ALT" icon_state = "wolfalt" -/datum/sprite_accessory/mam_snouts/redpanda +/datum/sprite_accessory/snouts/mam_snouts/redpanda name = "WahCoon" icon_state = "wah" -/datum/sprite_accessory/mam_snouts/redpandaalt +/datum/sprite_accessory/snouts/mam_snouts/redpandaalt name = "WahCoon ALT" icon_state = "wahalt" -/datum/sprite_accessory/mam_snouts/rhino +/datum/sprite_accessory/snouts/mam_snouts/rhino name = "Horn" icon_state = "rhino" extra = TRUE extra = MUTCOLORS3 -/datum/sprite_accessory/mam_snouts/rodent +/datum/sprite_accessory/snouts/mam_snouts/rodent name = "Rodent" icon_state = "rodent" -/datum/sprite_accessory/mam_snouts/husky +/datum/sprite_accessory/snouts/mam_snouts/husky name = "Husky" icon_state = "husky" -/datum/sprite_accessory/mam_snouts/otie +/datum/sprite_accessory/snouts/mam_snouts/otie name = "Otie" icon_state = "otie" -/datum/sprite_accessory/mam_snouts/pede +/datum/sprite_accessory/snouts/mam_snouts/pede name = "Scolipede" icon_state = "pede" -/datum/sprite_accessory/mam_snouts/sergal +/datum/sprite_accessory/snouts/mam_snouts/sergal name = "Sergal" icon_state = "sergal" -/datum/sprite_accessory/mam_snouts/shark +/datum/sprite_accessory/snouts/mam_snouts/shark name = "Shark" icon_state = "shark" -/datum/sprite_accessory/mam_snouts/hshark +/datum/sprite_accessory/snouts/mam_snouts/hshark name = "hShark" icon_state = "hshark" -/datum/sprite_accessory/mam_snouts/toucan +/datum/sprite_accessory/snouts/mam_snouts/toucan name = "Toucan" icon_state = "toucan" -/datum/sprite_accessory/mam_snouts/sharp +/datum/sprite_accessory/snouts/mam_snouts/sharp name = "Sharp" icon_state = "sharp" color_src = MUTCOLORS -/datum/sprite_accessory/mam_snouts/round +/datum/sprite_accessory/snouts/mam_snouts/round name = "Round" icon_state = "round" color_src = MUTCOLORS -/datum/sprite_accessory/mam_snouts/sharplight +/datum/sprite_accessory/snouts/mam_snouts/sharplight name = "Sharp + Light" icon_state = "sharplight" color_src = MUTCOLORS -/datum/sprite_accessory/mam_snouts/roundlight +/datum/sprite_accessory/snouts/mam_snouts/roundlight name = "Round + Light" icon_state = "roundlight" color_src = MUTCOLORS @@ -283,109 +297,109 @@ **************** Snouts ******************* *************but higher up*****************/ -/datum/sprite_accessory/mam_snouts/fbird +/datum/sprite_accessory/snouts/mam_snouts/fbird name = "Beak (Top)" icon_state = "fbird" -/datum/sprite_accessory/mam_snouts/fbigbeak +/datum/sprite_accessory/snouts/mam_snouts/fbigbeak name = "Big Beak (Top)" icon_state = "fbigbeak" -/datum/sprite_accessory/mam_snouts/fbug +/datum/sprite_accessory/snouts/mam_snouts/fbug name = "Bug (Top)" icon_state = "fbug" color_src = MUTCOLORS extra2 = TRUE extra2_color_src = MUTCOLORS3 -/datum/sprite_accessory/mam_snouts/felephant +/datum/sprite_accessory/snouts/mam_snouts/felephant name = "Elephant (Top)" icon_state = "felephant" extra = TRUE extra_color_src = MUTCOLORS3 -/datum/sprite_accessory/mam_snouts/flcanid +/datum/sprite_accessory/snouts/mam_snouts/flcanid name = "Mammal, Long (Top)" icon_state = "flcanid" -/datum/sprite_accessory/mam_snouts/flcanidalt +/datum/sprite_accessory/snouts/mam_snouts/flcanidalt name = "Mammal, Long ALT (Top)" icon_state = "flcanidalt" -/datum/sprite_accessory/mam_snouts/fscanid +/datum/sprite_accessory/snouts/mam_snouts/fscanid name = "Mammal, Short (Top)" icon_state = "fscanid" -/datum/sprite_accessory/mam_snouts/fscanidalt +/datum/sprite_accessory/snouts/mam_snouts/fscanidalt name = "Mammal, Short ALT (Top)" icon_state = "fscanidalt" -/datum/sprite_accessory/mam_snouts/fscanidalt2 +/datum/sprite_accessory/snouts/mam_snouts/fscanidalt2 name = "Mammal, Short ALT 2 (Top)" icon_state = "fscanidalt2" -/datum/sprite_accessory/mam_snouts/fwolf +/datum/sprite_accessory/snouts/mam_snouts/fwolf name = "Mammal, Thick (Top)" icon_state = "fwolf" -/datum/sprite_accessory/mam_snouts/fwolfalt +/datum/sprite_accessory/snouts/mam_snouts/fwolfalt name = "Mammal, Thick ALT (Top)" icon_state = "fwolfalt" -/datum/sprite_accessory/mam_snouts/fredpanda +/datum/sprite_accessory/snouts/mam_snouts/fredpanda name = "WahCoon (Top)" icon_state = "fwah" -/datum/sprite_accessory/mam_snouts/frhino +/datum/sprite_accessory/snouts/mam_snouts/frhino name = "Horn (Top)" icon_state = "frhino" extra = TRUE extra = MUTCOLORS3 -/datum/sprite_accessory/mam_snouts/frodent +/datum/sprite_accessory/snouts/mam_snouts/frodent name = "Rodent (Top)" icon_state = "frodent" -/datum/sprite_accessory/mam_snouts/fhusky +/datum/sprite_accessory/snouts/mam_snouts/fhusky name = "Husky (Top)" icon_state = "fhusky" -/datum/sprite_accessory/mam_snouts/fotie +/datum/sprite_accessory/snouts/mam_snouts/fotie name = "Otie (Top)" icon_state = "fotie" -/datum/sprite_accessory/mam_snouts/fpede +/datum/sprite_accessory/snouts/mam_snouts/fpede name = "Scolipede (Top)" icon_state = "fpede" -/datum/sprite_accessory/mam_snouts/fsergal +/datum/sprite_accessory/snouts/mam_snouts/fsergal name = "Sergal (Top)" icon_state = "fsergal" -/datum/sprite_accessory/mam_snouts/fshark +/datum/sprite_accessory/snouts/mam_snouts/fshark name = "Shark (Top)" icon_state = "fshark" -/datum/sprite_accessory/mam_snouts/ftoucan +/datum/sprite_accessory/snouts/mam_snouts/ftoucan name = "Toucan (Top)" icon_state = "ftoucan" -/datum/sprite_accessory/mam_snouts/fsharp +/datum/sprite_accessory/snouts/mam_snouts/fsharp name = "Sharp (Top)" icon_state = "fsharp" color_src = MUTCOLORS -/datum/sprite_accessory/mam_snouts/fround +/datum/sprite_accessory/snouts/mam_snouts/fround name = "Round (Top)" icon_state = "fround" color_src = MUTCOLORS -/datum/sprite_accessory/mam_snouts/fsharplight +/datum/sprite_accessory/snouts/mam_snouts/fsharplight name = "Sharp + Light (Top)" icon_state = "fsharplight" color_src = MUTCOLORS -/datum/sprite_accessory/mam_snouts/froundlight +/datum/sprite_accessory/snouts/mam_snouts/froundlight name = "Round + Light (Top)" icon_state = "froundlight" color_src = MUTCOLORS diff --git a/code/modules/mob/dead/new_player/sprite_accessories/spines.dm b/code/modules/mob/dead/new_player/sprite_accessories/spines.dm index 54749d5ea9..83415ed375 100644 --- a/code/modules/mob/dead/new_player/sprite_accessories/spines.dm +++ b/code/modules/mob/dead/new_player/sprite_accessories/spines.dm @@ -2,10 +2,16 @@ icon = 'icons/mob/mutant_bodyparts.dmi' relevant_layers = list(BODY_BEHIND_LAYER, BODY_ADJ_LAYER) +/datum/sprite_accessory/spines/is_not_visible(var/mob/living/carbon/human/H, var/tauric) + return (!H.dna.features["spines"] || H.dna.features["spines"] == "None" || H.wear_suit && (H.wear_suit.flags_inv & HIDETAUR)) + /datum/sprite_accessory/spines_animated icon = 'icons/mob/mutant_bodyparts.dmi' relevant_layers = list(BODY_BEHIND_LAYER, BODY_ADJ_LAYER) +/datum/sprite_accessory/spines_animated/is_not_visible(var/mob/living/carbon/human/H, var/tauric) + return ((!H.dna.features["spines"] || H.dna.features["spines"] == "None" || H.wear_suit && (H.wear_suit.flags_inv & HIDETAUR)) || H.dna.species.mutant_bodyparts["tail"]) + /datum/sprite_accessory/spines/none name = "None" icon_state = "none" diff --git a/code/modules/mob/dead/new_player/sprite_accessories/synthliz.dm b/code/modules/mob/dead/new_player/sprite_accessories/synthliz.dm index a2884ab944..16531d8f06 100644 --- a/code/modules/mob/dead/new_player/sprite_accessories/synthliz.dm +++ b/code/modules/mob/dead/new_player/sprite_accessories/synthliz.dm @@ -1,24 +1,24 @@ //Synth snouts (This is the most important part) -/datum/sprite_accessory/mam_snouts/synthliz +/datum/sprite_accessory/snouts/mam_snouts/synthliz recommended_species = list("synthliz") icon = 'modular_citadel/icons/mob/synthliz_snouts.dmi' color_src = MUTCOLORS name = "Synthetic Lizard - Snout" icon_state = "synthliz_basic" -/datum/sprite_accessory/mam_snouts/synthliz/synthliz_under +/datum/sprite_accessory/snouts/mam_snouts/synthliz/synthliz_under icon = 'modular_citadel/icons/mob/synthliz_snouts.dmi' color_src = MATRIXED name = "Synthetic Lizard - Snout Under" icon_state = "synthliz_under" -/datum/sprite_accessory/mam_snouts/synthliz/synthliz_tert +/datum/sprite_accessory/snouts/mam_snouts/synthliz/synthliz_tert icon = 'modular_citadel/icons/mob/synthliz_snouts.dmi' color_src = MATRIXED name = "Synthetic Lizard - Snout Tertiary" icon_state = "synthliz_tert" -/datum/sprite_accessory/mam_snouts/synthliz/synthliz_tertunder +/datum/sprite_accessory/snouts/mam_snouts/synthliz/synthliz_tertunder icon = 'modular_citadel/icons/mob/synthliz_snouts.dmi' color_src = MATRIXED name = "Synthetic Lizard - Snout Tertiary Under" @@ -42,14 +42,14 @@ icon_state = "synthlizpecslight" //Synth tails -/datum/sprite_accessory/mam_tails/synthliz +/datum/sprite_accessory/tails/mam_tails/synthliz recommended_species = list("synthliz") icon = 'modular_citadel/icons/mob/synthliz_tails.dmi' color_src = MUTCOLORS name = "Synthetic Lizard" icon_state = "synthliz" -/datum/sprite_accessory/mam_tails_animated/synthliz +/datum/sprite_accessory/tails_animated/mam_tails_animated/synthliz recommended_species = list("synthliz") icon = 'modular_citadel/icons/mob/synthliz_tails.dmi' color_src = MUTCOLORS diff --git a/code/modules/mob/dead/new_player/sprite_accessories/tails.dm b/code/modules/mob/dead/new_player/sprite_accessories/tails.dm index 33dbd7059f..812e0c052c 100644 --- a/code/modules/mob/dead/new_player/sprite_accessories/tails.dm +++ b/code/modules/mob/dead/new_player/sprite_accessories/tails.dm @@ -3,6 +3,9 @@ mutant_part_string = "tail" relevant_layers = list(BODY_BEHIND_LAYER, BODY_FRONT_LAYER) +/datum/sprite_accessory/tails/is_not_visible(var/mob/living/carbon/human/H, var/tauric) + return ((H.wear_suit && (H.wear_suit.flags_inv & HIDETAUR)) || tauric) + /datum/sprite_accessory/tails_animated icon = 'icons/mob/mutant_bodyparts.dmi' mutant_part_string = "tailwag" @@ -12,6 +15,9 @@ ************* Lizard Tails **************** *******************************************/ +/datum/sprite_accessory/tails_animated/lizard/is_not_visible(var/mob/living/carbon/human/H, var/tauric) + return (((H.wear_suit && (H.wear_suit.flags_inv & HIDETAUR)) || tauric) || H.dna.species.mutant_bodyparts["tail_lizard"]) + /datum/sprite_accessory/tails/lizard/smooth name = "Smooth" icon_state = "smooth" @@ -98,6 +104,9 @@ icon_state = "none" relevant_layers = null +/datum/sprite_accessory/tails_animated/human/is_not_visible(var/mob/living/carbon/human/H, var/tauric) + return (((H.wear_suit && (H.wear_suit.flags_inv & HIDETAUR)) || tauric)|| H.dna.species.mutant_bodyparts["tail_human"]) + /datum/sprite_accessory/tails/human/ailurus name = "Red Panda" icon_state = "wah" @@ -122,22 +131,22 @@ icon = 'modular_citadel/icons/mob/mam_tails.dmi' color_src = MATRIXED -/datum/sprite_accessory/mam_tails/batl +/datum/sprite_accessory/tails/mam_tails/batl name = "Bat (Long)" icon = 'modular_citadel/icons/mob/mam_tails.dmi' icon_state = "batl" -/datum/sprite_accessory/mam_tails_animated/batl +/datum/sprite_accessory/tails_animated/mam_tails_animated/batl name = "Bat (Long)" icon = 'modular_citadel/icons/mob/mam_tails.dmi' icon_state = "batl" -/datum/sprite_accessory/mam_tails/bats +/datum/sprite_accessory/tails/mam_tails/bats name = "Bat (Short)" icon = 'modular_citadel/icons/mob/mam_tails.dmi' icon_state = "bats" -/datum/sprite_accessory/mam_tails_animated/bats +/datum/sprite_accessory/tails_animated/mam_tails_animated/bats name = "Bat (Short)" icon = 'modular_citadel/icons/mob/mam_tails.dmi' icon_state = "bats" @@ -518,368 +527,371 @@ ************** Furry Tails **************** *******************************************/ -/datum/sprite_accessory/mam_tails +/datum/sprite_accessory/tails/mam_tails color_src = MATRIXED icon = 'modular_citadel/icons/mob/mam_tails.dmi' recommended_species = list("mammal", "slimeperson", "podweak", "felinid", "insect") mutant_part_string = "tail" relevant_layers = list(BODY_BEHIND_LAYER, BODY_FRONT_LAYER) -/datum/sprite_accessory/mam_tails/none +/datum/sprite_accessory/tails/mam_tails/none name = "None" icon_state = "none" recommended_species = null relevant_layers = null -/datum/sprite_accessory/mam_tails_animated +/datum/sprite_accessory/tails_animated/mam_tails_animated color_src = MATRIXED icon = 'modular_citadel/icons/mob/mam_tails.dmi' mutant_part_string = "tailwag" relevant_layers = list(BODY_BEHIND_LAYER, BODY_FRONT_LAYER) -/datum/sprite_accessory/mam_tails_animated/none +/datum/sprite_accessory/tails_animated/mam_tails_animated/is_not_visible(var/mob/living/carbon/human/H, var/tauric) + return (((H.wear_suit && (H.wear_suit.flags_inv & HIDETAUR)) || tauric) || H.dna.species.mutant_bodyparts["mam_tail"]) + +/datum/sprite_accessory/tails_animated/mam_tails_animated/none name = "None" icon_state = "none" relevant_layers = null -/datum/sprite_accessory/mam_tails/ailurus +/datum/sprite_accessory/tails/mam_tails/ailurus name = "Red Panda" icon_state = "wah" extra = TRUE -/datum/sprite_accessory/mam_tails_animated/ailurus +/datum/sprite_accessory/tails_animated/mam_tails_animated/ailurus name = "Red Panda" icon_state = "wah" extra = TRUE -/datum/sprite_accessory/mam_tails/axolotl +/datum/sprite_accessory/tails/mam_tails/axolotl name = "Axolotl" icon_state = "axolotl" -/datum/sprite_accessory/mam_tails_animated/axolotl +/datum/sprite_accessory/tails_animated/mam_tails_animated/axolotl name = "Axolotl" icon_state = "axolotl" -/datum/sprite_accessory/mam_tails/batl +/datum/sprite_accessory/tails/mam_tails/batl name = "Bat (Long)" icon_state = "batl" -/datum/sprite_accessory/mam_tails_animated/batl +/datum/sprite_accessory/tails_animated/mam_tails_animated/batl name = "Bat (Long)" icon_state = "batl" -/datum/sprite_accessory/mam_tails/bats +/datum/sprite_accessory/tails/mam_tails/bats name = "Bat (Short)" icon_state = "bats" -/datum/sprite_accessory/mam_tails_animated/bats +/datum/sprite_accessory/tails_animated/mam_tails_animated/bats name = "Bat (Short)" icon_state = "bats" -/datum/sprite_accessory/mam_tails/bee +/datum/sprite_accessory/tails/mam_tails/bee name = "Bee" icon_state = "bee" -/datum/sprite_accessory/mam_tails_animated/bee +/datum/sprite_accessory/tails_animated/mam_tails_animated/bee name = "Bee" icon_state = "bee" -/datum/sprite_accessory/mam_tails/cat +/datum/sprite_accessory/tails/mam_tails/cat name = "Cat" icon_state = "cat" color_src = HAIR -/datum/sprite_accessory/mam_tails_animated/cat +/datum/sprite_accessory/tails_animated/mam_tails_animated/cat name = "Cat" icon_state = "cat" color_src = HAIR -/datum/sprite_accessory/mam_tails/catbig +/datum/sprite_accessory/tails/mam_tails/catbig name = "Cat, Big" icon_state = "catbig" -/datum/sprite_accessory/mam_tails_animated/catbig +/datum/sprite_accessory/tails_animated/mam_tails_animated/catbig name = "Cat, Big" icon_state = "catbig" -/datum/sprite_accessory/mam_tails/twocat +/datum/sprite_accessory/tails/mam_tails/twocat name = "Cat, Double" icon_state = "twocat" -/datum/sprite_accessory/mam_tails_animated/twocat +/datum/sprite_accessory/tails_animated/mam_tails_animated/twocat name = "Cat, Double" icon_state = "twocat" -/datum/sprite_accessory/mam_tails/corvid +/datum/sprite_accessory/tails/mam_tails/corvid name = "Corvid" icon_state = "crow" -/datum/sprite_accessory/mam_tails_animated/corvid +/datum/sprite_accessory/tails_animated/mam_tails_animated/corvid name = "Corvid" icon_state = "crow" -/datum/sprite_accessory/mam_tail/cow +/datum/sprite_accessory/tails/mam_tail/cow name = "Cow" icon_state = "cow" -/datum/sprite_accessory/mam_tails_animated/cow +/datum/sprite_accessory/tails_animated/mam_tails_animated/cow name = "Cow" icon_state = "cow" -/datum/sprite_accessory/mam_tails/eevee +/datum/sprite_accessory/tails/mam_tails/eevee name = "Eevee" icon_state = "eevee" -/datum/sprite_accessory/mam_tails_animated/eevee +/datum/sprite_accessory/tails_animated/mam_tails_animated/eevee name = "Eevee" icon_state = "eevee" -/datum/sprite_accessory/mam_tails/fennec +/datum/sprite_accessory/tails/mam_tails/fennec name = "Fennec" icon_state = "fennec" -/datum/sprite_accessory/mam_tails_animated/fennec +/datum/sprite_accessory/tails_animated/mam_tails_animated/fennec name = "Fennec" icon_state = "fennec" -/datum/sprite_accessory/mam_tails/human/fish +/datum/sprite_accessory/tails/mam_tails/human/fish name = "Fish" icon_state = "fish" -/datum/sprite_accessory/mam_tails_animated/human/fish +/datum/sprite_accessory/tails_animated/mam_tails_animated/human/fish name = "Fish" icon_state = "fish" -/datum/sprite_accessory/mam_tails/fox +/datum/sprite_accessory/tails/mam_tails/fox name = "Fox" icon_state = "fox" -/datum/sprite_accessory/mam_tails_animated/fox +/datum/sprite_accessory/tails_animated/mam_tails_animated/fox name = "Fox" icon_state = "fox" -/datum/sprite_accessory/mam_tails/hawk +/datum/sprite_accessory/tails/mam_tails/hawk name = "Hawk" icon_state = "hawk" -/datum/sprite_accessory/mam_tails_animated/hawk +/datum/sprite_accessory/tails_animated/mam_tails_animated/hawk name = "Hawk" icon_state = "hawk" -/datum/sprite_accessory/mam_tails/horse +/datum/sprite_accessory/tails/mam_tails/horse name = "Horse" icon_state = "horse" color_src = HAIR -/datum/sprite_accessory/mam_tails_animated/horse +/datum/sprite_accessory/tails_animated/mam_tails_animated/horse name = "Horse" icon_state = "horse" color_src = HAIR -/datum/sprite_accessory/mam_tails/husky +/datum/sprite_accessory/tails/mam_tails/husky name = "Husky" icon_state = "husky" -/datum/sprite_accessory/mam_tails_animated/husky +/datum/sprite_accessory/tails_animated/mam_tails_animated/husky name = "Husky" icon_state = "husky" -datum/sprite_accessory/mam_tails/insect +datum/sprite_accessory/tails/mam_tails/insect name = "Insect" icon_state = "insect" -/datum/sprite_accessory/mam_tails_animated/insect +/datum/sprite_accessory/tails_animated/mam_tails_animated/insect name = "Insect" icon_state = "insect" -/datum/sprite_accessory/mam_tails/kangaroo +/datum/sprite_accessory/tails/mam_tails/kangaroo name = "kangaroo" icon_state = "kangaroo" -/datum/sprite_accessory/mam_tails_animated/kangaroo +/datum/sprite_accessory/tails_animated/mam_tails_animated/kangaroo name = "kangaroo" icon_state = "kangaroo" -/datum/sprite_accessory/mam_tails/kitsune +/datum/sprite_accessory/tails/mam_tails/kitsune name = "Kitsune" icon_state = "kitsune" -/datum/sprite_accessory/mam_tails_animated/kitsune +/datum/sprite_accessory/tails_animated/mam_tails_animated/kitsune name = "Kitsune" icon_state = "kitsune" -/datum/sprite_accessory/mam_tails/lab +/datum/sprite_accessory/tails/mam_tails/lab name = "Lab" icon_state = "lab" -/datum/sprite_accessory/mam_tails_animated/lab +/datum/sprite_accessory/tails_animated/mam_tails_animated/lab name = "Lab" icon_state = "lab" -/datum/sprite_accessory/mam_tails/murid +/datum/sprite_accessory/tails/mam_tails/murid name = "Murid" icon_state = "murid" -/datum/sprite_accessory/mam_tails_animated/murid +/datum/sprite_accessory/tails_animated/mam_tails_animated/murid name = "Murid" icon_state = "murid" -/datum/sprite_accessory/mam_tails/otie +/datum/sprite_accessory/tails/mam_tails/otie name = "Otusian" icon_state = "otie" -/datum/sprite_accessory/mam_tails_animated/otie +/datum/sprite_accessory/tails_animated/mam_tails_animated/otie name = "Otusian" icon_state = "otie" -/datum/sprite_accessory/mam_tails/orca +/datum/sprite_accessory/tails/mam_tails/orca name = "Orca" icon_state = "orca" -/datum/sprite_accessory/mam_tails_animated/orca +/datum/sprite_accessory/tails_animated/mam_tails_animated/orca name = "Orca" icon_state = "orca" -/datum/sprite_accessory/mam_tails/pede +/datum/sprite_accessory/tails/mam_tails/pede name = "Scolipede" icon_state = "pede" -/datum/sprite_accessory/mam_tails_animated/pede +/datum/sprite_accessory/tails_animated/mam_tails_animated/pede name = "Scolipede" icon_state = "pede" -/datum/sprite_accessory/mam_tails/rabbit +/datum/sprite_accessory/tails/mam_tails/rabbit name = "Rabbit" icon_state = "rabbit" -/datum/sprite_accessory/mam_tails_animated/rabbit +/datum/sprite_accessory/tails_animated/mam_tails_animated/rabbit name = "Rabbit" icon_state = "rabbit" -/datum/sprite_accessory/mam_tails/sergal +/datum/sprite_accessory/tails/mam_tails/sergal name = "Sergal" icon_state = "sergal" -/datum/sprite_accessory/mam_tails_animated/sergal +/datum/sprite_accessory/tails_animated/mam_tails_animated/sergal name = "Sergal" icon_state = "sergal" -/datum/sprite_accessory/mam_tails/skunk +/datum/sprite_accessory/tails/mam_tails/skunk name = "Skunk" icon_state = "skunk" -/datum/sprite_accessory/mam_tails_animated/skunk +/datum/sprite_accessory/tails_animated/mam_tails_animated/skunk name = "Skunk" icon_state = "skunk" -/datum/sprite_accessory/mam_tails/smooth +/datum/sprite_accessory/tails/mam_tails/smooth name = "Smooth" icon_state = "smooth" color_src = MUTCOLORS icon = 'icons/mob/mutant_bodyparts.dmi' -/datum/sprite_accessory/mam_tails_animated/smooth +/datum/sprite_accessory/tails_animated/mam_tails_animated/smooth name = "Smooth" icon_state = "smooth" color_src = MUTCOLORS icon = 'icons/mob/mutant_bodyparts.dmi' -/datum/sprite_accessory/mam_tails_animated/spikes +/datum/sprite_accessory/tails_animated/mam_tails_animated/spikes name = "Spikes" icon_state = "spikes" color_src = MUTCOLORS icon = 'icons/mob/mutant_bodyparts.dmi' -/datum/sprite_accessory/mam_tails/spikes +/datum/sprite_accessory/tails/mam_tails/spikes name = "Spikes" icon_state = "spikes" color_src = MUTCOLORS icon = 'icons/mob/mutant_bodyparts.dmi' -/datum/sprite_accessory/mam_tails/shark +/datum/sprite_accessory/tails/mam_tails/shark name = "Shark" icon_state = "shark" -/datum/sprite_accessory/mam_tails_animated/shark +/datum/sprite_accessory/tails_animated/mam_tails_animated/shark name = "Shark" icon_state = "shark" -/datum/sprite_accessory/mam_tails/shepherd +/datum/sprite_accessory/tails/mam_tails/shepherd name = "Shepherd" icon_state = "shepherd" -/datum/sprite_accessory/mam_tails_animated/shepherd +/datum/sprite_accessory/tails_animated/mam_tails_animated/shepherd name = "Shepherd" icon_state = "shepherd" -/datum/sprite_accessory/mam_tails/straighttail +/datum/sprite_accessory/tails/mam_tails/straighttail name = "Straight Tail" icon_state = "straighttail" -/datum/sprite_accessory/mam_tails_animated/straighttail +/datum/sprite_accessory/tails_animated/mam_tails_animated/straighttail name = "Straight Tail" icon_state = "straighttail" -/datum/sprite_accessory/mam_tails/squirrel +/datum/sprite_accessory/tails/mam_tails/squirrel name = "Squirrel" icon_state = "squirrel" -/datum/sprite_accessory/mam_tails_animated/squirrel +/datum/sprite_accessory/tails_animated/mam_tails_animated/squirrel name = "Squirrel" icon_state = "squirrel" -/datum/sprite_accessory/mam_tails/tamamo_kitsune +/datum/sprite_accessory/tails/mam_tails/tamamo_kitsune name = "Tamamo Kitsune Tails" icon_state = "9sune" -/datum/sprite_accessory/mam_tails_animated/tamamo_kitsune +/datum/sprite_accessory/tails_animated/mam_tails_animated/tamamo_kitsune name = "Tamamo Kitsune Tails" icon_state = "9sune" -/datum/sprite_accessory/mam_tails/tentacle +/datum/sprite_accessory/tails/mam_tails/tentacle name = "Tentacle" icon_state = "tentacle" -/datum/sprite_accessory/mam_tails_animated/tentacle +/datum/sprite_accessory/tails_animated/mam_tails_animated/tentacle name = "Tentacle" icon_state = "tentacle" -/datum/sprite_accessory/mam_tails/tiger +/datum/sprite_accessory/tails/mam_tails/tiger name = "Tiger" icon_state = "tiger" -/datum/sprite_accessory/mam_tails_animated/tiger +/datum/sprite_accessory/tails_animated/mam_tails_animated/tiger name = "Tiger" icon_state = "tiger" -/datum/sprite_accessory/mam_tails/dtiger +/datum/sprite_accessory/tails/mam_tails/dtiger name = "Dark Tiger" icon_state = "dtiger" color_src = MUTCOLORS icon = 'icons/mob/mutant_bodyparts.dmi' -/datum/sprite_accessory/mam_tails_animated/dtiger +/datum/sprite_accessory/tails_animated/mam_tails_animated/dtiger name = "Dark Tiger" icon_state = "dtiger" color_src = MUTCOLORS icon = 'icons/mob/mutant_bodyparts.dmi' -/datum/sprite_accessory/mam_tails/ltiger +/datum/sprite_accessory/tails/mam_tails/ltiger name = "Light Tiger" icon_state = "ltiger" color_src = MUTCOLORS icon = 'icons/mob/mutant_bodyparts.dmi' -/datum/sprite_accessory/mam_tails_animated/ltiger +/datum/sprite_accessory/tails_animated/mam_tails_animated/ltiger name = "Light Tiger" icon_state = "ltiger" color_src = MUTCOLORS icon = 'icons/mob/mutant_bodyparts.dmi' -/datum/sprite_accessory/mam_tails/wolf +/datum/sprite_accessory/tails/mam_tails/wolf name = "Wolf" icon_state = "wolf" -/datum/sprite_accessory/mam_tails_animated/wolf +/datum/sprite_accessory/tails_animated/mam_tails_animated/wolf name = "Wolf" icon_state = "wolf" diff --git a/code/modules/mob/dead/new_player/sprite_accessories/undershirt.dm b/code/modules/mob/dead/new_player/sprite_accessories/undershirt.dm index 73233f3e09..b8282931d2 100644 --- a/code/modules/mob/dead/new_player/sprite_accessories/undershirt.dm +++ b/code/modules/mob/dead/new_player/sprite_accessories/undershirt.dm @@ -348,6 +348,12 @@ name = "Cowboy Shirt Shortsleeved Red" icon_state = "cowboyshirt_reds" +/datum/sprite_accessory/underwear/top/bra_binder + name = "Bra (binder)" + icon_state = "bra_binder" + has_color = TRUE - - +/datum/sprite_accessory/underwear/top/bra_binder_strapless + name = "Bra (binder, strapless)" + icon_state = "bra_binder_strapless" + has_color = TRUE diff --git a/code/modules/mob/dead/new_player/sprite_accessories/wings.dm b/code/modules/mob/dead/new_player/sprite_accessories/wings.dm index 34767a10f1..fb03df88a1 100644 --- a/code/modules/mob/dead/new_player/sprite_accessories/wings.dm +++ b/code/modules/mob/dead/new_player/sprite_accessories/wings.dm @@ -5,10 +5,16 @@ icon_state = "none" relevant_layers = null +/datum/sprite_accessory/wings/is_not_visible(var/mob/living/carbon/human/H, var/tauric) + return (!H.dna.features["wings"] || H.dna.features["wings"] == "None" || (H.wear_suit && (H.wear_suit.flags_inv & HIDEJUMPSUIT) && (!H.wear_suit.species_exception || !is_type_in_list(src, H.wear_suit.species_exception)))) + /datum/sprite_accessory/wings_open icon = 'icons/mob/wings.dmi' relevant_layers = list(BODY_BEHIND_LAYER, BODY_ADJ_LAYER, BODY_FRONT_LAYER) +/datum/sprite_accessory/wings_open/is_not_visible(var/mob/living/carbon/human/H, var/tauric) + return (H.wear_suit && (H.wear_suit.flags_inv & HIDEJUMPSUIT) && (!H.wear_suit.species_exception || !is_type_in_list(src, H.wear_suit.species_exception)) || H.dna.species.mutant_bodyparts["wings"]) + /datum/sprite_accessory/wings_open/angel name = "Angel" icon_state = "angel" diff --git a/code/modules/mob/dead/observer/notificationprefs.dm b/code/modules/mob/dead/observer/notificationprefs.dm index 160abd57e1..524ff80d5d 100644 --- a/code/modules/mob/dead/observer/notificationprefs.dm +++ b/code/modules/mob/dead/observer/notificationprefs.dm @@ -3,12 +3,10 @@ set name = "Notification preferences" set desc = "Notification preferences" - var/datum/notificationpanel/panel = new(usr) + var/datum/notificationpanel/panel = new(usr) panel.ui_interact(usr) - - /datum/notificationpanel var/client/user @@ -21,10 +19,13 @@ else src.user = user -/datum/notificationpanel/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.observer_state) - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) +/datum/notificationpanel/ui_state(mob/user) + return GLOB.observer_state + +/datum/notificationpanel/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) if(!ui) - ui = new(user, src, ui_key, "NotificationPreferences", "Notification Preferences", 270, 360, master_ui, state) + ui = new(user, src, "NotificationPreferences") ui.open() /datum/notificationpanel/ui_data(mob/user) @@ -35,8 +36,7 @@ "key" = key, "enabled" = (user.ckey in GLOB.poll_ignore[key]), "desc" = GLOB.poll_ignore_desc[key] - )) - + )) /datum/notificationpanel/ui_act(action, params) if(..()) diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm index bb39639ec1..a0df1ee938 100644 --- a/code/modules/mob/dead/observer/observer.dm +++ b/code/modules/mob/dead/observer/observer.dm @@ -905,6 +905,22 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp else to_chat(usr, "Can't become a pAI candidate while not dead!") +/mob/dead/observer/verb/mafia_game_signup() + set category = "Ghost" + set name = "Signup for Mafia" + set desc = "Sign up for a game of Mafia to pass the time while dead." + mafia_signup() +/mob/dead/observer/proc/mafia_signup() + if(!client) + return + if(!isobserver(src)) + to_chat(usr, "You must be a ghost to join mafia!") + return + var/datum/mafia_controller/game = GLOB.mafia_game //this needs to change if you want multiple mafia games up at once. + if(!game) + game = create_mafia_game("mafia") + game.ui_interact(usr) + /mob/dead/observer/CtrlShiftClick(mob/user) if(isobserver(user) && check_rights(R_SPAWN)) change_mob_type( /mob/living/carbon/human , null, null, TRUE) //always delmob, ghosts shouldn't be left lingering diff --git a/code/modules/mob/dead/observer/orbit.dm b/code/modules/mob/dead/observer/orbit.dm index eb23a5fb67..b81172afad 100644 --- a/code/modules/mob/dead/observer/orbit.dm +++ b/code/modules/mob/dead/observer/orbit.dm @@ -6,9 +6,12 @@ qdel(src) owner = new_owner -/datum/orbit_menu/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.observer_state) +/datum/orbit_menu/ui_state(mob/user) + return GLOB.observer_state + +/datum/orbit_menu/ui_interact(mob/user, datum/tgui/ui) if (!ui) - ui = new(user, src, ui_key, "Orbit", "Orbit", 350, 700, master_ui, state) + ui = new(user, src, "Orbit") ui.open() /datum/orbit_menu/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) @@ -16,11 +19,10 @@ return if (action == "orbit") - var/list/pois = getpois(skip_mindless = 1) - var/atom/movable/poi = pois[params["name"]] + var/ref = params["ref"] + var/atom/movable/poi = (locate(ref) in GLOB.mob_list) || (locate(ref) in GLOB.poi_list) if (poi != null) owner.ManualFollow(poi) - ui.close() /datum/orbit_menu/ui_data(mob/user) var/list/data = list() @@ -39,6 +41,8 @@ var/poi = pois[name] + serialized["ref"] = REF(poi) + var/mob/M = poi if (istype(M)) if (isobserver(M)) diff --git a/code/modules/mob/inventory.dm b/code/modules/mob/inventory.dm index caebb9cf10..9ac270bf34 100644 --- a/code/modules/mob/inventory.dm +++ b/code/modules/mob/inventory.dm @@ -382,10 +382,20 @@ return 0 -//Outdated but still in use apparently. This should at least be a human proc. -//Daily reminder to murder this - Remie. +/** + * Used to return a list of equipped items on a mob; does not include held items (use get_all_gear) + * + * Argument(s): + * * Optional - include_pockets (TRUE/FALSE), whether or not to include the pockets and suit storage in the returned list + */ + /mob/living/proc/get_equipped_items(include_pockets = FALSE) - return + var/list/items = list() + for(var/obj/item/I in contents) + if(I.item_flags & IN_INVENTORY) + items += I + items -= held_items + return items /mob/living/proc/unequip_everything() var/list/items = list() @@ -476,5 +486,19 @@ hand_bodyparts[i] = BP ..() //Don't redraw hands until we have organs for them + +//GetAllContents that is reasonable and not stupid +/mob/living/carbon/proc/get_all_gear() + var/list/processing_list = get_equipped_items(include_pockets = TRUE) + held_items + listclearnulls(processing_list) // handles empty hands + var/i = 0 + while(i < length(processing_list) ) + var/atom/A = processing_list[++i] + if(SEND_SIGNAL(A, COMSIG_CONTAINS_STORAGE)) + var/list/item_stuff = list() + SEND_SIGNAL(A, COMSIG_TRY_STORAGE_RETURN_INVENTORY, item_stuff) + processing_list += item_stuff + return processing_list + /mob/canReachInto(atom/user, atom/target, list/next, view_only, obj/item/tool) return ..() && (user == src) diff --git a/code/modules/mob/living/carbon/human/dummy.dm b/code/modules/mob/living/carbon/human/dummy.dm index 1e2a375b39..2f5c94b784 100644 --- a/code/modules/mob/living/carbon/human/dummy.dm +++ b/code/modules/mob/living/carbon/human/dummy.dm @@ -21,7 +21,7 @@ INITIALIZE_IMMEDIATE(/mob/living/carbon/human/dummy) /mob/living/carbon/human/dummy/proc/wipe_state() delete_equipment() icon_render_key = null - cut_overlays(TRUE) + cut_overlays() //Inefficient pooling/caching way. GLOBAL_LIST_EMPTY(human_dummy_list) diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index b402260611..38b420aaba 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -1042,7 +1042,7 @@ /mob/living/carbon/human/updatehealth() . = ..() - + dna?.species.spec_updatehealth(src) if(HAS_TRAIT(src, TRAIT_IGNORESLOWDOWN)) //if we want to ignore slowdown from damage and equipment remove_movespeed_modifier(/datum/movespeed_modifier/damage_slowdown) remove_movespeed_modifier(/datum/movespeed_modifier/damage_slowdown_flying) @@ -1199,6 +1199,9 @@ /mob/living/carbon/human/species/lizard race = /datum/species/lizard +/mob/living/carbon/human/species/ethereal + race = /datum/species/ethereal + /mob/living/carbon/human/species/lizard/ashwalker race = /datum/species/lizard/ashwalker diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm index 1673c57a80..18501b4ca2 100644 --- a/code/modules/mob/living/carbon/human/human_defense.dm +++ b/code/modules/mob/living/carbon/human/human_defense.dm @@ -299,10 +299,10 @@ /mob/living/carbon/human/ex_act(severity, target, origin) - if(origin && istype(origin, /datum/spacevine_mutation) && isvineimmune(src)) + if(TRAIT_BOMBIMMUNE in dna.species.species_traits) return ..() - if (!severity) + if (!severity || QDELETED(src)) return var/brute_loss = 0 var/burn_loss = 0 @@ -336,7 +336,8 @@ if (!istype(ears, /obj/item/clothing/ears/earmuffs)) adjustEarDamage(30, 120) Unconscious(20) //short amount of time for follow up attacks against elusive enemies like wizards - Knockdown(200 - (bomb_armor * 1.6)) //between ~4 and ~20 seconds of knockdown depending on bomb armor + Knockdown((200 - (bomb_armor * 1.6)) / 4) //between ~1 and ~5 seconds of knockdown depending on bomb armor + adjustStaminaLoss(brute_loss) if(EXPLODE_LIGHT) brute_loss = 30 @@ -345,7 +346,8 @@ damage_clothes(max(50 - bomb_armor, 0), BRUTE, "bomb") if (!istype(ears, /obj/item/clothing/ears/earmuffs)) adjustEarDamage(15,60) - Knockdown(160 - (bomb_armor * 1.6)) //100 bomb armor will prevent knockdown altogether + Knockdown((160 - (bomb_armor * 1.6)) / 4) //100 bomb armor will prevent knockdown altogether + adjustStaminaLoss(brute_loss) take_overall_damage(brute_loss,burn_loss) diff --git a/code/modules/mob/living/carbon/human/inventory.dm b/code/modules/mob/living/carbon/human/inventory.dm index a7593ca0cb..523369d10a 100644 --- a/code/modules/mob/living/carbon/human/inventory.dm +++ b/code/modules/mob/living/carbon/human/inventory.dm @@ -1,31 +1,17 @@ /mob/living/carbon/human/can_equip(obj/item/I, slot, disable_warning = FALSE, bypass_equip_delay_self = FALSE, clothing_check = FALSE, list/return_warning) return dna.species.can_equip(I, slot, disable_warning, src, bypass_equip_delay_self, clothing_check, return_warning) +/** + * Used to return a list of equipped items on a human mob; does not include held items (use get_all_gear) + * + * Argument(s): + * * Optional - include_pockets (TRUE/FALSE), whether or not to include the pockets and suit storage in the returned list + */ + /mob/living/carbon/human/get_equipped_items(include_pockets = FALSE) var/list/items = ..() - if(belt) - items += belt - if(ears) - items += ears - if(glasses) - items += glasses - if(gloves) - items += gloves - if(shoes) - items += shoes - if(wear_id) - items += wear_id - if(wear_suit) - items += wear_suit - if(w_uniform) - items += w_uniform - if(include_pockets) - if(l_store) - items += l_store - if(r_store) - items += r_store - if(s_store) - items += s_store + if(!include_pockets) + items -= list(l_store, r_store, s_store) return items // Return the item currently in the slot ID @@ -169,7 +155,7 @@ //Item is handled and in slot, valid to call callback, for this proc should always be true if(!not_handled) I.equipped(src, slot) - + update_genitals() return not_handled //For future deeper overrides /mob/living/carbon/human/equipped_speed_mods() @@ -257,6 +243,7 @@ s_store = null if(!QDELETED(src)) update_inv_s_store() + update_genitals() /mob/living/carbon/human/wear_mask_update(obj/item/clothing/C, toggle_off = 1) if((C.flags_inv & (HIDEHAIR|HIDEFACIALHAIR)) || (initial(C.flags_inv) & (HIDEHAIR|HIDEFACIALHAIR))) diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm index dc7fe86aca..230a634e0e 100644 --- a/code/modules/mob/living/carbon/human/species.dm +++ b/code/modules/mob/living/carbon/human/species.dm @@ -56,6 +56,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) var/list/mutant_organs = list() //Internal organs that are unique to this race. var/speedmod = 0 // this affects the race's speed. positive numbers make it move slower, negative numbers make it move faster var/armor = 0 // overall defense for the race... or less defense, if it's negative. + var/attack_type = BRUTE // the type of damage unarmed attacks from this species do var/brutemod = 1 // multiplier for brute damage var/burnmod = 1 // multiplier for burn damage var/coldmod = 1 // multiplier for cold damage @@ -123,6 +124,9 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) limbs_id = id ..() + //update our mutant bodyparts to include unlocked ones + mutant_bodyparts += GLOB.unlocked_mutant_parts + /proc/generate_selectable_species(clear = FALSE) if(clear) GLOB.roundstart_races = list() @@ -638,106 +642,19 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) if(!mutant_bodyparts) return - var/obj/item/bodypart/head/HD = H.get_bodypart(BODY_ZONE_HEAD) var/tauric = mutant_bodyparts["taur"] && H.dna.features["taur"] && H.dna.features["taur"] != "None" - if(mutant_bodyparts["tail_lizard"]) - if((H.wear_suit && (H.wear_suit.flags_inv & HIDETAUR)) || tauric) - bodyparts_to_add -= "tail_lizard" - - if(mutant_bodyparts["waggingtail_lizard"]) - if((H.wear_suit && (H.wear_suit.flags_inv & HIDETAUR)) || tauric) - bodyparts_to_add -= "waggingtail_lizard" - else if (mutant_bodyparts["tail_lizard"]) - bodyparts_to_add -= "waggingtail_lizard" - - if(mutant_bodyparts["tail_human"]) - if((H.wear_suit && (H.wear_suit.flags_inv & HIDETAUR)) || tauric) - bodyparts_to_add -= "tail_human" - - if(mutant_bodyparts["waggingtail_human"]) - if((H.wear_suit && (H.wear_suit.flags_inv & HIDETAUR)) || tauric) - bodyparts_to_add -= "waggingtail_human" - else if (mutant_bodyparts["tail_human"]) - bodyparts_to_add -= "waggingtail_human" - - if(mutant_bodyparts["spines"]) - if(!H.dna.features["spines"] || H.dna.features["spines"] == "None" || H.wear_suit && (H.wear_suit.flags_inv & HIDETAUR)) - bodyparts_to_add -= "spines" - - if(mutant_bodyparts["waggingspines"]) - if(!H.dna.features["spines"] || H.dna.features["spines"] == "None" || H.wear_suit && (H.wear_suit.flags_inv & HIDETAUR)) - bodyparts_to_add -= "waggingspines" - else if (mutant_bodyparts["tail"]) - bodyparts_to_add -= "waggingspines" - - if(mutant_bodyparts["snout"]) //Take a closer look at that snout! - if((H.wear_mask && (H.wear_mask.flags_inv & HIDESNOUT)) || (H.head && (H.head.flags_inv & HIDESNOUT)) || !HD || HD.status == BODYPART_ROBOTIC) - bodyparts_to_add -= "snout" - - if(mutant_bodyparts["frills"]) - if(!H.dna.features["frills"] || H.dna.features["frills"] == "None" || H.head && (H.head.flags_inv & HIDEEARS) || !HD || HD.status == BODYPART_ROBOTIC) - bodyparts_to_add -= "frills" - - if(mutant_bodyparts["horns"]) - if(!H.dna.features["horns"] || H.dna.features["horns"] == "None" || H.head && (H.head.flags_inv & HIDEHAIR) || (H.wear_mask && (H.wear_mask.flags_inv & HIDEHAIR)) || !HD || HD.status == BODYPART_ROBOTIC) - bodyparts_to_add -= "horns" - - if(mutant_bodyparts["ears"]) - if(!H.dna.features["ears"] || H.dna.features["ears"] == "None" || H.head && (H.head.flags_inv & HIDEEARS) || (H.wear_mask && (H.wear_mask.flags_inv & HIDEEARS)) || !HD || HD.status == BODYPART_ROBOTIC) - bodyparts_to_add -= "ears" - - if(mutant_bodyparts["wings"]) - if(!H.dna.features["wings"] || H.dna.features["wings"] == "None" || (H.wear_suit && (H.wear_suit.flags_inv & HIDEJUMPSUIT) && (!H.wear_suit.species_exception || !is_type_in_list(src, H.wear_suit.species_exception)))) - bodyparts_to_add -= "wings" - - if(mutant_bodyparts["wings_open"]) - if(H.wear_suit && (H.wear_suit.flags_inv & HIDEJUMPSUIT) && (!H.wear_suit.species_exception || !is_type_in_list(src, H.wear_suit.species_exception))) - bodyparts_to_add -= "wings_open" - else if (mutant_bodyparts["wings"]) - bodyparts_to_add -= "wings_open" - - if(mutant_bodyparts["insect_fluff"]) - if(!H.dna.features["insect_fluff"] || H.dna.features["insect_fluff"] == "None" || H.wear_suit && (H.wear_suit.flags_inv & HIDEJUMPSUIT)) - bodyparts_to_add -= "insect_fluff" - -//CITADEL EDIT - //Race specific bodyparts: - //Xenos - if(mutant_bodyparts["xenodorsal"]) - if(!H.dna.features["xenodorsal"] || H.dna.features["xenodorsal"] == "None" || (H.wear_suit && (H.wear_suit.flags_inv & HIDEJUMPSUIT))) - bodyparts_to_add -= "xenodorsal" - if(mutant_bodyparts["xenohead"])//This is an overlay for different castes using different head crests - if(!H.dna.features["xenohead"] || H.dna.features["xenohead"] == "None" || H.head && (H.head.flags_inv & HIDEHAIR) || (H.wear_mask && (H.wear_mask.flags_inv & HIDEHAIR)) || !HD || HD.status == BODYPART_ROBOTIC) - bodyparts_to_add -= "xenohead" - if(mutant_bodyparts["xenotail"]) - if(!H.dna.features["xenotail"] || H.dna.features["xenotail"] == "None" || H.wear_suit && (H.wear_suit.flags_inv & HIDEJUMPSUIT)) - bodyparts_to_add -= "xenotail" - - //Other Races - if(mutant_bodyparts["mam_tail"]) - if((H.wear_suit && (H.wear_suit.flags_inv & HIDETAUR)) || tauric) - bodyparts_to_add -= "mam_tail" - - if(mutant_bodyparts["mam_waggingtail"]) - if((H.wear_suit && (H.wear_suit.flags_inv & HIDETAUR)) || tauric) - bodyparts_to_add -= "mam_waggingtail" - else if (mutant_bodyparts["mam_tail"]) - bodyparts_to_add -= "mam_waggingtail" - - if(mutant_bodyparts["mam_ears"]) - if(!H.dna.features["mam_ears"] || H.dna.features["mam_ears"] == "None" || H.head && (H.head.flags_inv & HIDEEARS) || (H.wear_mask && (H.wear_mask.flags_inv & HIDEEARS)) || !HD || HD.status == BODYPART_ROBOTIC) - bodyparts_to_add -= "mam_ears" - - if(mutant_bodyparts["mam_snouts"]) //Take a closer look at that snout! - if((H.wear_mask && (H.wear_mask.flags_inv & HIDESNOUT)) || (H.head && (H.head.flags_inv & HIDESNOUT)) || !HD || HD.status == BODYPART_ROBOTIC) - bodyparts_to_add -= "mam_snouts" - - if(mutant_bodyparts["taur"]) - if(!tauric || (H.wear_suit && (H.wear_suit.flags_inv & HIDETAUR))) - bodyparts_to_add -= "taur" - -//END EDIT + for(var/mutant_part in mutant_bodyparts) + var/reference_list = GLOB.mutant_reference_list[mutant_part] + if(reference_list) + var/datum/sprite_accessory/S + var/transformed_part = GLOB.mutant_transform_list[mutant_part] + if(transformed_part) + S = reference_list[H.dna.features[transformed_part]] + else + S = reference_list[H.dna.features[mutant_part]] + if(!S || S.is_not_visible(H, tauric)) + bodyparts_to_add -= mutant_part //Digitigrade legs are stuck in the phantom zone between true limbs and mutant bodyparts. Mainly it just needs more agressive updating than most limbs. var/update_needed = FALSE @@ -774,76 +691,22 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) var/list/dna_feature_as_text_string = list() for(var/bodypart in bodyparts_to_add) - var/datum/sprite_accessory/S - switch(bodypart) - if("tail_lizard") - S = GLOB.tails_list_lizard[H.dna.features["tail_lizard"]] - if("waggingtail_lizard") - S = GLOB.animated_tails_list_lizard[H.dna.features["tail_lizard"]] - if("tail_human") - S = GLOB.tails_list_human[H.dna.features["tail_human"]] - if("waggingtail_human") - S = GLOB.animated_tails_list_human[H.dna.features["tail_human"]] - if("spines") - S = GLOB.spines_list[H.dna.features["spines"]] - if("waggingspines") - S = GLOB.animated_spines_list[H.dna.features["spines"]] - if("snout") - S = GLOB.snouts_list[H.dna.features["snout"]] - if("frills") - S = GLOB.frills_list[H.dna.features["frills"]] - if("horns") - S = GLOB.horns_list[H.dna.features["horns"]] - if("ears") - S = GLOB.ears_list[H.dna.features["ears"]] - if("body_markings") - S = GLOB.body_markings_list[H.dna.features["body_markings"]] - if("wings") - S = GLOB.wings_list[H.dna.features["wings"]] - if("wingsopen") - S = GLOB.wings_open_list[H.dna.features["wings"]] - if("deco_wings") - S = GLOB.deco_wings_list[H.dna.features["deco_wings"]] - if("legs") - S = GLOB.legs_list[H.dna.features["legs"]] - if("insect_wings") - S = GLOB.insect_wings_list[H.dna.features["insect_wings"]] - if("insect_fluff") - S = GLOB.insect_fluffs_list[H.dna.features["insect_fluff"]] - if("insect_markings") - S = GLOB.insect_markings_list[H.dna.features["insect_markings"]] - if("caps") - S = GLOB.caps_list[H.dna.features["caps"]] - if("ipc_screen") - S = GLOB.ipc_screens_list[H.dna.features["ipc_screen"]] - if("ipc_antenna") - S = GLOB.ipc_antennas_list[H.dna.features["ipc_antenna"]] - if("mam_tail") - S = GLOB.mam_tails_list[H.dna.features["mam_tail"]] - if("mam_waggingtail") - S = GLOB.mam_tails_animated_list[H.dna.features["mam_tail"]] - if("mam_body_markings") - S = GLOB.mam_body_markings_list[H.dna.features["mam_body_markings"]] - if("mam_ears") - S = GLOB.mam_ears_list[H.dna.features["mam_ears"]] - if("mam_snouts") - S = GLOB.mam_snouts_list[H.dna.features["mam_snouts"]] - if("taur") - S = GLOB.taur_list[H.dna.features["taur"]] - if("xenodorsal") - S = GLOB.xeno_dorsal_list[H.dna.features["xenodorsal"]] - if("xenohead") - S = GLOB.xeno_head_list[H.dna.features["xenohead"]] - if("xenotail") - S = GLOB.xeno_tail_list[H.dna.features["xenotail"]] + var/reference_list = GLOB.mutant_reference_list[bodypart] + if(reference_list) + var/datum/sprite_accessory/S + var/transformed_part = GLOB.mutant_transform_list[bodypart] + if(transformed_part) + S = reference_list[H.dna.features[transformed_part]] + else + S = reference_list[H.dna.features[bodypart]] - if(!S || S.icon_state == "none") - continue + if(!S || S.icon_state == "none") + continue - for(var/L in S.relevant_layers) - LAZYADD(relevant_layers["[L]"], S) - if(!S.mutant_part_string) - dna_feature_as_text_string[S] = bodypart + for(var/L in S.relevant_layers) + LAZYADD(relevant_layers["[L]"], S) + if(!S.mutant_part_string) + dna_feature_as_text_string[S] = bodypart var/static/list/layer_text = list( "[BODY_BEHIND_LAYER]" = "BEHIND", @@ -1364,6 +1227,10 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) var/hungry = (500 - H.nutrition) / 5 //So overeat would be 100 and default level would be 80 if(hungry >= 70) H.add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/hunger, multiplicative_slowdown = (hungry / 50)) + else if(isethereal(H)) + var/datum/species/ethereal/E = H.dna.species + if(E.get_charge(H) <= ETHEREAL_CHARGE_NORMAL) + H.add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/hunger, multiplicative_slowdown = (1.5 * (1 - E.get_charge(H) / 100))) else H.remove_movespeed_modifier(/datum/movespeed_modifier/hunger) @@ -1420,6 +1287,12 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) // ATTACK PROCS // ////////////////// +/datum/species/proc/spec_updatehealth(mob/living/carbon/human/H) + return + +/datum/species/proc/spec_fully_heal(mob/living/carbon/human/H) + return + /datum/species/proc/help(mob/living/carbon/human/user, mob/living/carbon/human/target, datum/martial_art/attacker_style) if(target.health >= 0 && !HAS_TRAIT(target, TRAIT_FAKEDEATH)) target.help_shake_act(user) @@ -1538,11 +1411,11 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) target.dismembering_strike(user, affecting.body_zone) if(atk_verb == ATTACK_EFFECT_KICK)//kicks deal 1.5x raw damage + 0.5x stamina damage - target.apply_damage(damage*1.5, BRUTE, affecting, armor_block) + target.apply_damage(damage*1.5, attack_type, affecting, armor_block) target.apply_damage(damage*0.5, STAMINA, affecting, armor_block) log_combat(user, target, "kicked") else//other attacks deal full raw damage + 2x in stamina damage - target.apply_damage(damage, BRUTE, affecting, armor_block) + target.apply_damage(damage, attack_type, affecting, armor_block) target.apply_damage(damage*2, STAMINA, affecting, armor_block) log_combat(user, target, "punched") @@ -2032,17 +1905,8 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) return /** - - - * The human species version of [/mob/living/carbon/proc/get_biological_state]. Depends on the HAS_FLESH and HAS_BONE species traits, having bones lets you have bone wounds, having flesh lets you have burn, slash, and piercing wounds - - - */ - - - /datum/species/proc/get_biological_state(mob/living/carbon/human/H) . = BIO_INORGANIC if(HAS_FLESH in species_traits) @@ -2058,7 +1922,6 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) if(HAS_TRAIT(H, TRAIT_NOBREATH)) return TRUE - /datum/species/proc/handle_environment(datum/gas_mixture/environment, mob/living/carbon/human/H) if(!environment) return @@ -2250,7 +2113,6 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) /datum/species/proc/spec_stun(mob/living/carbon/human/H,amount) if(H) stop_wagging_tail(H) - . = stunmod * H.physiology.stun_mod * amount ////////////// diff --git a/code/modules/mob/living/carbon/human/species_types/ethereal.dm b/code/modules/mob/living/carbon/human/species_types/ethereal.dm new file mode 100644 index 0000000000..cd9b3b80c7 --- /dev/null +++ b/code/modules/mob/living/carbon/human/species_types/ethereal.dm @@ -0,0 +1,182 @@ +#define ETHEREAL_COLORS list("#00ffff", "#ffc0cb", "#9400D3", "#4B0082", "#0000FF", "#00FF00", "#FFFF00", "#FF7F00", "#FF0000") + +/datum/species/ethereal + name = "Ethereal" + id = "ethereal" + attack_verb = "burn" + attack_sound = 'sound/weapons/etherealhit.ogg' + miss_sound = 'sound/weapons/etherealmiss.ogg' + meat = /obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/ethereal + mutantstomach = /obj/item/organ/stomach/ethereal + mutanttongue = /obj/item/organ/tongue/ethereal + exotic_blood = /datum/reagent/consumable/liquidelectricity //Liquid Electricity. fuck you think of something better gamer + siemens_coeff = 0.5 //They thrive on energy + brutemod = 1.25 //They're weak to punches + attack_type = BURN //burn bish + damage_overlay_type = "" //We are too cool for regular damage overlays + species_traits = list(MUTCOLORS, HAIR, HAS_FLESH, HAS_BONE) // i mean i guess they have blood so they can have wounds too + species_language_holder = /datum/language_holder/ethereal + inherent_traits = list(TRAIT_NOHUNGER) + sexes = FALSE + toxic_food = NONE + /* + citadel doesn't have per-species temperatures, yet + // Body temperature for ethereals is much higher then humans as they like hotter environments + bodytemp_normal = (BODYTEMP_NORMAL + 50) + bodytemp_heat_damage_limit = FIRE_MINIMUM_TEMPERATURE_TO_SPREAD // about 150C + // Cold temperatures hurt faster as it is harder to move with out the heat energy + bodytemp_cold_damage_limit = (T20C - 10) // about 10c + */ + hair_color = "mutcolor" + hair_alpha = 140 + var/current_color + var/EMPeffect = FALSE + var/emageffect = FALSE + var/r1 + var/g1 + var/b1 + var/static/r2 = 237 + var/static/g2 = 164 + var/static/b2 = 149 + //this is shit but how do i fix it? no clue. + var/drain_time = 0 //used to keep ethereals from spam draining power sources + +/datum/species/ethereal/on_species_gain(mob/living/carbon/C, datum/species/old_species, pref_load) + .=..() + if(ishuman(C)) + var/mob/living/carbon/human/H = C + default_color = "#" + H.dna.features["mcolor"] + r1 = GETREDPART(default_color) + g1 = GETGREENPART(default_color) + b1 = GETBLUEPART(default_color) + spec_updatehealth(H) + RegisterSignal(C, COMSIG_ATOM_EMAG_ACT, .proc/on_emag_act) + RegisterSignal(C, COMSIG_ATOM_EMP_ACT, .proc/on_emp_act) + +/datum/species/ethereal/on_species_loss(mob/living/carbon/human/C, datum/species/new_species, pref_load) + .=..() + C.set_light(0) + UnregisterSignal(C, COMSIG_ATOM_EMAG_ACT) + UnregisterSignal(C, COMSIG_ATOM_EMP_ACT) + +/datum/species/ethereal/random_name(gender,unique,lastname) + if(unique) + return random_unique_ethereal_name() + + var/randname = ethereal_name() + + return randname + +/datum/species/ethereal/spec_updatehealth(mob/living/carbon/human/H) + .=..() + if(H.stat != DEAD && !EMPeffect) + var/healthpercent = max(H.health, 0) / 100 + if(!emageffect) + current_color = rgb(r2 + ((r1-r2)*healthpercent), g2 + ((g1-g2)*healthpercent), b2 + ((b1-b2)*healthpercent)) + H.set_light(1 + (2 * healthpercent), 1 + (1 * healthpercent), current_color) + fixed_mut_color = copytext_char(current_color, 2) + else + H.set_light(0) + fixed_mut_color = rgb(128,128,128) + H.update_body() + +/datum/species/ethereal/proc/on_emp_act(mob/living/carbon/human/H, severity) + EMPeffect = TRUE + spec_updatehealth(H) + to_chat(H, "You feel the light of your body leave you.") + switch(severity) + if(EMP_LIGHT) + addtimer(CALLBACK(src, .proc/stop_emp, H), 10 SECONDS, TIMER_UNIQUE|TIMER_OVERRIDE) //We're out for 10 seconds + if(EMP_HEAVY) + addtimer(CALLBACK(src, .proc/stop_emp, H), 20 SECONDS, TIMER_UNIQUE|TIMER_OVERRIDE) //We're out for 20 seconds + +/datum/species/ethereal/proc/on_emag_act(mob/living/carbon/human/H, mob/user) + if(emageffect) + return + emageffect = TRUE + if(user) + to_chat(user, "You tap [H] on the back with your card.") + H.visible_message("[H] starts flickering in an array of colors!") + handle_emag(H) + addtimer(CALLBACK(src, .proc/stop_emag, H), 30 SECONDS) //Disco mode for 30 seconds! This doesn't affect the ethereal at all besides either annoying some players, or making someone look badass. + + +/datum/species/ethereal/spec_life(mob/living/carbon/human/H) + .=..() + handle_charge(H) + + +/datum/species/ethereal/proc/stop_emp(mob/living/carbon/human/H) + EMPeffect = FALSE + spec_updatehealth(H) + to_chat(H, "You feel more energized as your shine comes back.") + + +/datum/species/ethereal/proc/handle_emag(mob/living/carbon/human/H) + if(!emageffect) + return + current_color = pick(ETHEREAL_COLORS) + spec_updatehealth(H) + addtimer(CALLBACK(src, .proc/handle_emag, H), 5) //Call ourselves every 0.5 seconds to change color + +/datum/species/ethereal/proc/stop_emag(mob/living/carbon/human/H) + emageffect = FALSE + spec_updatehealth(H) + H.visible_message("[H] stops flickering and goes back to their normal state!") + +/datum/species/ethereal/proc/handle_charge(mob/living/carbon/human/H) + brutemod = 1.25 + switch(get_charge(H)) + if(ETHEREAL_CHARGE_NONE) + H.throw_alert("ethereal_charge", /obj/screen/alert/etherealcharge, 3) + if(ETHEREAL_CHARGE_NONE to ETHEREAL_CHARGE_LOWPOWER) + H.throw_alert("ethereal_charge", /obj/screen/alert/etherealcharge, 2) + if(H.health > 10.5) + apply_damage(0.65, TOX, null, null, H) + brutemod = 1.75 + if(ETHEREAL_CHARGE_LOWPOWER to ETHEREAL_CHARGE_NORMAL) + H.throw_alert("ethereal_charge", /obj/screen/alert/etherealcharge, 1) + brutemod = 1.5 + if(ETHEREAL_CHARGE_FULL to ETHEREAL_CHARGE_OVERLOAD) + H.throw_alert("ethereal_overcharge", /obj/screen/alert/ethereal_overcharge, 1) + apply_damage(0.2, TOX, null, null, H) + brutemod = 1.5 + if(ETHEREAL_CHARGE_OVERLOAD to ETHEREAL_CHARGE_DANGEROUS) + H.throw_alert("ethereal_overcharge", /obj/screen/alert/ethereal_overcharge, 2) + apply_damage(0.65, TOX, null, null, H) + brutemod = 1.75 + if(prob(10)) //10% each tick for ethereals to explosively release excess energy if it reaches dangerous levels + discharge_process(H) + else + H.clear_alert("ethereal_charge") + H.clear_alert("ethereal_overcharge") + +/datum/species/ethereal/proc/discharge_process(mob/living/carbon/human/H) + to_chat(H, "You begin to lose control over your charge!") + H.visible_message("[H] begins to spark violently!") + var/static/mutable_appearance/overcharge //shameless copycode from lightning spell + overcharge = overcharge || mutable_appearance('icons/effects/effects.dmi', "electricity", EFFECTS_LAYER) + H.add_overlay(overcharge) + if(do_mob(H, H, 50, 1)) + H.flash_lighting_fx(5, 7, current_color) + var/obj/item/organ/stomach/ethereal/stomach = H.getorganslot(ORGAN_SLOT_STOMACH) + playsound(H, 'sound/magic/lightningshock.ogg', 100, TRUE, extrarange = 5) + H.cut_overlay(overcharge) + tesla_zap(H, 2, stomach.crystal_charge*50, ZAP_OBJ_DAMAGE | ZAP_ALLOW_DUPLICATES) + if(istype(stomach)) + stomach.adjust_charge(100 - stomach.crystal_charge) + to_chat(H, "You violently discharge energy!") + H.visible_message("[H] violently discharges energy!") + if(prob(10)) //chance of developing heart disease to dissuade overcharging oneself + var/datum/disease/D = new /datum/disease/heart_failure + H.ForceContractDisease(D) + to_chat(H, "You're pretty sure you just felt your heart stop for a second there..") + H.playsound_local(H, 'sound/effects/singlebeat.ogg', 100, 0) + H.Paralyze(100) + return + +/datum/species/ethereal/proc/get_charge(mob/living/carbon/H) //this feels like it should be somewhere else. Eh? + var/obj/item/organ/stomach/ethereal/stomach = H.getorganslot(ORGAN_SLOT_STOMACH) + if(istype(stomach)) + return stomach.crystal_charge + return ETHEREAL_CHARGE_NONE diff --git a/code/modules/mob/living/carbon/human/species_types/jellypeople.dm b/code/modules/mob/living/carbon/human/species_types/jellypeople.dm index 9d7f99c14e..49c55f70b3 100644 --- a/code/modules/mob/living/carbon/human/species_types/jellypeople.dm +++ b/code/modules/mob/living/carbon/human/species_types/jellypeople.dm @@ -287,11 +287,16 @@ else ui_interact(owner) -/datum/action/innate/swap_body/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.always_state) +/datum/action/innate/swap_body/ui_host(mob/user) + return owner - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) +/datum/action/innate/swap_body/ui_state(mob/user) + return GLOB.not_incapacitated_state + +/datum/action/innate/swap_body/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) if(!ui) - ui = new(user, src, ui_key, "SlimeBodySwapper", name, 400, 400, master_ui, state) + ui = new(user, src, "SlimeBodySwapper", name) ui.open() /datum/action/innate/swap_body/ui_data(mob/user) @@ -361,7 +366,8 @@ return switch(action) if("swap") - var/mob/living/carbon/human/selected = locate(params["ref"]) + var/datum/species/jelly/slime/SS = H.dna.species + var/mob/living/carbon/human/selected = locate(params["ref"]) in SS.bodies if(!can_swap(selected)) return SStgui.close_uis(src) @@ -498,7 +504,7 @@ else if (select_alteration == "Ears") var/list/snowflake_ears_list = list("Normal" = null) for(var/path in GLOB.mam_ears_list) - var/datum/sprite_accessory/mam_ears/instance = GLOB.mam_ears_list[path] + var/datum/sprite_accessory/ears/mam_ears/instance = GLOB.mam_ears_list[path] if(istype(instance, /datum/sprite_accessory)) var/datum/sprite_accessory/S = instance if((!S.ckeys_allowed) || (S.ckeys_allowed.Find(H.client.ckey))) @@ -512,7 +518,7 @@ else if (select_alteration == "Snout") var/list/snowflake_snouts_list = list("Normal" = null) for(var/path in GLOB.mam_snouts_list) - var/datum/sprite_accessory/mam_snouts/instance = GLOB.mam_snouts_list[path] + var/datum/sprite_accessory/snouts/mam_snouts/instance = GLOB.mam_snouts_list[path] if(istype(instance, /datum/sprite_accessory)) var/datum/sprite_accessory/S = instance if((!S.ckeys_allowed) || (S.ckeys_allowed.Find(H.client.ckey))) @@ -543,7 +549,7 @@ else if (select_alteration == "Tail") var/list/snowflake_tails_list = list("Normal" = null) for(var/path in GLOB.mam_tails_list) - var/datum/sprite_accessory/mam_tails/instance = GLOB.mam_tails_list[path] + var/datum/sprite_accessory/tails/mam_tails/instance = GLOB.mam_tails_list[path] if(istype(instance, /datum/sprite_accessory)) var/datum/sprite_accessory/S = instance if((!S.ckeys_allowed) || (S.ckeys_allowed.Find(H.client.ckey))) diff --git a/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm b/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm index d768788e87..a8e3f89957 100644 --- a/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm +++ b/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm @@ -5,13 +5,12 @@ say_mod = "hisses" default_color = "00FF00" species_traits = list(MUTCOLORS,EYECOLOR,HAIR,FACEHAIR,LIPS,HORNCOLOR,WINGCOLOR,HAS_FLESH,HAS_BONE) - mutant_bodyparts = list("tail_lizard", "snout", "spines", "horns", "frills", "body_markings", "legs", "taur", "deco_wings") inherent_biotypes = MOB_ORGANIC|MOB_HUMANOID|MOB_REPTILE mutanttongue = /obj/item/organ/tongue/lizard mutanttail = /obj/item/organ/tail/lizard coldmod = 1.5 heatmod = 0.67 - mutant_bodyparts = list("mcolor" = "0F0", "mcolor2" = "0F0", "mcolor3" = "0F0", "tail_lizard" = "Smooth", "snout" = "Round", + mutant_bodyparts = list("mcolor" = "0F0", "mcolor2" = "0F0", "mcolor3" = "0F0", "tail_lizard" = "Smooth", "mam_snouts" = "Round", "horns" = "None", "frills" = "None", "spines" = "None", "body_markings" = "None", "legs" = "Digitigrade", "taur" = "None", "deco_wings" = "None") attack_verb = "slash" @@ -52,6 +51,7 @@ species_traits = list(MUTCOLORS,EYECOLOR,LIPS,DIGITIGRADE) inherent_traits = list(TRAIT_CHUNKYFINGERS) mutantlungs = /obj/item/organ/lungs/ashwalker + mutanteyes = /obj/item/organ/eyes/night_vision burnmod = 0.9 brutemod = 0.9 species_language_holder = /datum/language_holder/lizard/ash diff --git a/code/modules/mob/living/carbon/human/species_types/plasmamen.dm b/code/modules/mob/living/carbon/human/species_types/plasmamen.dm index b61e29b685..8c30adb8f9 100644 --- a/code/modules/mob/living/carbon/human/species_types/plasmamen.dm +++ b/code/modules/mob/living/carbon/human/species_types/plasmamen.dm @@ -57,89 +57,10 @@ ..() /datum/species/plasmaman/before_equip_job(datum/job/J, mob/living/carbon/human/H, visualsOnly = FALSE) - var/current_job = J?.title var/datum/outfit/plasmaman/O = new /datum/outfit/plasmaman - switch(current_job) - if("Chaplain") - O = new /datum/outfit/plasmaman/chaplain - - if("Curator") - O = new /datum/outfit/plasmaman/curator - - if("Janitor") - O = new /datum/outfit/plasmaman/janitor - - if("Botanist") - O = new /datum/outfit/plasmaman/botany - - if("Bartender", "Lawyer") - O = new /datum/outfit/plasmaman/bar - - if("Cook") - O = new /datum/outfit/plasmaman/chef - - if("Security Officer") - O = new /datum/outfit/plasmaman/security - - if("Detective") - O = new /datum/outfit/plasmaman/detective - - if("Warden") - O = new /datum/outfit/plasmaman/warden - - if("Cargo Technician", "Quartermaster") - O = new /datum/outfit/plasmaman/cargo - - if("Shaft Miner") - O = new /datum/outfit/plasmaman/mining - - if("Medical Doctor") - O = new /datum/outfit/plasmaman/medical - - if("Chemist") - O = new /datum/outfit/plasmaman/chemist - - if("Geneticist") - O = new /datum/outfit/plasmaman/genetics - - if("Roboticist") - O = new /datum/outfit/plasmaman/robotics - - if("Virologist") - O = new /datum/outfit/plasmaman/viro - - if("Scientist") - O = new /datum/outfit/plasmaman/science - - if("Station Engineer") - O = new /datum/outfit/plasmaman/engineering - - if("Atmospheric Technician") - O = new /datum/outfit/plasmaman/atmospherics - - if("Captain") - O = new /datum/outfit/plasmaman/captain - - if("Head of Personnel") - O = new /datum/outfit/plasmaman/hop - - if("Head of Security") - O = new /datum/outfit/plasmaman/hos - - if("Chief Engineer") - O = new /datum/outfit/plasmaman/ce - - if("Chief Medical Officer") - O = new /datum/outfit/plasmaman/cmo - - if("Research Director") - O = new /datum/outfit/plasmaman/rd - - if("Mime") - O = new /datum/outfit/plasmaman/mime - - if("Clown") - O = new /datum/outfit/plasmaman/clown + if(J) + if(J.plasma_outfit) + O = new J.plasma_outfit H.equipOutfit(O, visualsOnly) H.internal = H.get_item_for_held_index(2) diff --git a/code/modules/mob/living/carbon/human/species_types/shadowpeople.dm b/code/modules/mob/living/carbon/human/species_types/shadowpeople.dm index b9864bce16..228a69c30f 100644 --- a/code/modules/mob/living/carbon/human/species_types/shadowpeople.dm +++ b/code/modules/mob/living/carbon/human/species_types/shadowpeople.dm @@ -82,13 +82,11 @@ M.AddSpell(SW) shadowwalk = SW - /obj/item/organ/brain/nightmare/Remove(special = FALSE) if(shadowwalk && owner) owner.RemoveSpell(shadowwalk) return ..() - /obj/item/organ/heart/nightmare name = "heart of darkness" desc = "An alien organ that twists and writhes when exposed to light." @@ -185,6 +183,8 @@ T.ScrapeAway(flags = CHANGETURF_INHERIT_AIR) else if(isliving(AM)) var/mob/living/L = AM + if(isethereal(AM)) + AM.emp_act(EMP_LIGHT) if(iscyborg(AM)) var/mob/living/silicon/robot/borg = AM if(borg.lamp_intensity) diff --git a/code/modules/mob/living/carbon/human/species_types/skeletons.dm b/code/modules/mob/living/carbon/human/species_types/skeletons.dm index 51d81bd4d3..1b6bef9dc6 100644 --- a/code/modules/mob/living/carbon/human/species_types/skeletons.dm +++ b/code/modules/mob/living/carbon/human/species_types/skeletons.dm @@ -5,8 +5,8 @@ blacklisted = 0 sexes = 0 meat = /obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/skeleton - species_traits = list(NOBLOOD,NOGENITALS,NOAROUSAL,HAS_BONE) - inherent_traits = list(TRAIT_NOBREATH,TRAIT_RADIMMUNE,TRAIT_PIERCEIMMUNE,TRAIT_NOHUNGER,TRAIT_EASYDISMEMBER,TRAIT_LIMBATTACHMENT,TRAIT_FAKEDEATH, TRAIT_CALCIUM_HEALER) + species_traits = list(NOBLOOD,NOGENITALS,NOAROUSAL,HAS_BONE,NOTRANSSTING) + inherent_traits = list(TRAIT_EASYDISMEMBER,TRAIT_LIMBATTACHMENT,TRAIT_CALCIUM_HEALER) inherent_biotypes = MOB_UNDEAD|MOB_HUMANOID mutanttongue = /obj/item/organ/tongue/bone damage_overlay_type = ""//let's not show bloody wounds or burns over bones. @@ -19,12 +19,12 @@ /datum/species/skeleton/New() if(SSevents.holidays && SSevents.holidays[HALLOWEEN]) //skeletons are stronger during the spooky season! - inherent_traits |= list(TRAIT_RESISTHEAT,TRAIT_RESISTCOLD) + inherent_traits |= list(TRAIT_RESISTHEAT, TRAIT_NOBREATH, TRAIT_PIERCEIMMUNE, TRAIT_FAKEDEATH, TRAIT_RESISTCOLD, TRAIT_RADIMMUNE) brutemod = 1 burnmod = 1 ..() -/datum/species/skeleton/greater/check_roundstart_eligible() +/datum/species/skeleton/check_roundstart_eligible() if(SSevents.holidays && SSevents.holidays[HALLOWEEN]) return TRUE return ..() diff --git a/code/modules/mob/living/carbon/human/species_types/synthliz.dm b/code/modules/mob/living/carbon/human/species_types/synthliz.dm index 5ed806b302..173411eaa1 100644 --- a/code/modules/mob/living/carbon/human/species_types/synthliz.dm +++ b/code/modules/mob/living/carbon/human/species_types/synthliz.dm @@ -22,4 +22,4 @@ tail_type = "mam_tail" wagging_type = "mam_waggingtail" - species_type = "robotic" \ No newline at end of file + species_type = "robotic" diff --git a/code/modules/mob/living/carbon/human/species_types/synths.dm b/code/modules/mob/living/carbon/human/species_types/synths.dm index a1a2a33c54..c10521dfd9 100644 --- a/code/modules/mob/living/carbon/human/species_types/synths.dm +++ b/code/modules/mob/living/carbon/human/species_types/synths.dm @@ -100,14 +100,12 @@ else return ..() - /datum/species/synth/handle_body(mob/living/carbon/human/H) if(fake_species) fake_species.handle_body(H) else return ..() - /datum/species/synth/handle_mutant_bodyparts(mob/living/carbon/human/H, forced_colour) if(fake_species) fake_species.handle_body(H,forced_colour) diff --git a/code/modules/mob/living/carbon/human/species_types/zombies.dm b/code/modules/mob/living/carbon/human/species_types/zombies.dm index 81a7f6e2e7..8d86ad2fa9 100644 --- a/code/modules/mob/living/carbon/human/species_types/zombies.dm +++ b/code/modules/mob/living/carbon/human/species_types/zombies.dm @@ -32,6 +32,7 @@ name = "Infectious Zombie" id = "memezombies" limbs_id = "zombie" + inherent_traits = list(TRAIT_RESISTCOLD,TRAIT_RESISTHIGHPRESSURE,TRAIT_RESISTLOWPRESSURE,TRAIT_RADIMMUNE,TRAIT_EASYDISMEMBER,TRAIT_LIMBATTACHMENT,TRAIT_NOBREATH,TRAIT_NODEATH,TRAIT_NOSOFTCRIT, TRAIT_FAKEDEATH) mutanthands = /obj/item/zombie_hand armor = 20 // 120 damage to KO a zombie, which kills it speedmod = 1.6 // they're very slow @@ -89,8 +90,8 @@ infection = new() infection.Insert(C) - //make their bodyparts stamina-resistant - var/incoming_stam_mult = 0.7 + //make their bodyparts stamina-immune, its a corpse. + var/incoming_stam_mult = 0 for(var/obj/item/bodypart/part in C.bodyparts) part.incoming_stam_mult = incoming_stam_mult //todo: add negative wound resistance to all parts when wounds is merged (zombies are physically weak in terms of limbs) diff --git a/code/modules/mob/living/carbon/inventory.dm b/code/modules/mob/living/carbon/inventory.dm index cc837a490c..50801e1c0d 100644 --- a/code/modules/mob/living/carbon/inventory.dm +++ b/code/modules/mob/living/carbon/inventory.dm @@ -117,18 +117,6 @@ if(!QDELETED(src)) update_inv_legcuffed() -/mob/living/carbon/get_equipped_items(include_pockets = FALSE) - var/list/items = list() - if(back) - items += back - if(head) - items += head - if(wear_mask) - items += wear_mask - if(wear_neck) - items += wear_neck - return items - //handle stuff to update when a mob equips/unequips a mask. /mob/living/proc/wear_mask_update(obj/item/clothing/C, toggle_off = 1) update_inv_wear_mask() diff --git a/code/modules/mob/living/emote.dm b/code/modules/mob/living/emote.dm index bae2d2106b..97de8bfd6c 100644 --- a/code/modules/mob/living/emote.dm +++ b/code/modules/mob/living/emote.dm @@ -326,6 +326,11 @@ key_third_person = "smiles" message = "smiles." +/datum/emote/living/smirk + key = "smirk" + key_third_person = "smirks" + message = "smirks." + /datum/emote/living/sneeze key = "sneeze" key_third_person = "sneezes" diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index 0f55d5c408..2a461b5921 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -57,7 +57,7 @@ /mob/living/Bump(atom/A) if(..()) //we are thrown onto something return - if (buckled || now_pushing) + if(buckled || now_pushing) return if(ismob(A)) var/mob/M = A diff --git a/code/modules/mob/living/living_active_block.dm b/code/modules/mob/living/living_active_block.dm index 729e7d3d7a..2493509e16 100644 --- a/code/modules/mob/living/living_active_block.dm +++ b/code/modules/mob/living/living_active_block.dm @@ -13,7 +13,7 @@ DelayNextAction(data.block_end_click_cd_add) return TRUE -/mob/living/proc/ACTIVE_BLOCK_START(obj/item/I) +/mob/living/proc/active_block_start(obj/item/I) if(combat_flags & (COMBAT_FLAG_ACTIVE_BLOCK_STARTING | COMBAT_FLAG_ACTIVE_BLOCKING)) return FALSE if(!(I in held_items)) @@ -109,7 +109,7 @@ animate(src, pixel_x = get_standard_pixel_x_offset(), pixel_y = get_standard_pixel_y_offset(), time = 2.5, FALSE, SINE_EASING | EASE_IN, ANIMATION_END_NOW) return combat_flags &= ~(COMBAT_FLAG_ACTIVE_BLOCK_STARTING) - ACTIVE_BLOCK_START(I) + active_block_start(I) /** * Gets the first item we can that can block, but if that fails, default to active held item.COMSIG_ENABLE_COMBAT_MODE @@ -180,6 +180,12 @@ /// Apply the stamina damage to our user, notice how damage argument is stamina_amount. /obj/item/proc/active_block_do_stamina_damage(mob/living/owner, atom/object, stamina_amount, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return) + if(istype(object, /obj/item/projectile)) + var/obj/item/projectile/P = object + if(P.stamina) + var/blocked = active_block_calculate_final_damage(owner, object, P.stamina, attack_text, attack_type, armour_penetration, attacker, def_zone, final_block_chance, block_return) + var/stam = active_block_stamina_cost(owner, object, blocked, attack_text, ATTACK_TYPE_PROJECTILE, armour_penetration, attacker, def_zone, final_block_chance, block_return) + stamina_amount += stam var/datum/block_parry_data/data = get_block_parry_data() if(iscarbon(owner)) var/mob/living/carbon/C = owner diff --git a/code/modules/mob/living/living_active_parry.dm b/code/modules/mob/living/living_active_parry.dm index 4a9c4e6311..b6706d0548 100644 --- a/code/modules/mob/living/living_active_parry.dm +++ b/code/modules/mob/living/living_active_parry.dm @@ -245,7 +245,7 @@ . |= BLOCK_SUCCESS var/list/effect_text if(efficiency >= data.parry_efficiency_to_counterattack) - run_parry_countereffects(object, damage, attack_text, attack_type, armour_penetration, attacker, def_zone, return_list, efficiency) + effect_text = run_parry_countereffects(object, damage, attack_text, attack_type, armour_penetration, attacker, def_zone, return_list, efficiency) if(data.parry_flags & PARRY_DEFAULT_HANDLE_FEEDBACK) handle_parry_feedback(object, damage, attack_text, attack_type, armour_penetration, attacker, def_zone, return_list, efficiency, effect_text) successful_parries += efficiency @@ -254,9 +254,12 @@ /mob/living/proc/handle_parry_feedback(atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, list/return_list = list(), parry_efficiency, list/effect_text) var/datum/block_parry_data/data = get_parry_data() + var/knockdown_check = FALSE + if(data.parry_data[PARRY_KNOCKDOWN_ATTACKER] && parry_efficiency >= data.parry_efficiency_to_counterattack) + knockdown_check = TRUE if(data.parry_sounds) playsound(src, pick(data.parry_sounds), 75) - visible_message("[src] parries [attack_text][length(effect_text)? ", [english_list(effect_text)] [attacker]" : ""]!") + visible_message("[src] parries [attack_text][length(effect_text)? ", [english_list(effect_text)] [attacker]" : ""][length(effect_text) && knockdown_check? " and" : ""][knockdown_check? " knocking them to the ground" : ""]!") /// Run counterattack if any /mob/living/proc/run_parry_countereffects(atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, list/return_list = list(), parry_efficiency) @@ -288,15 +291,15 @@ if(data.parry_data[PARRY_DISARM_ATTACKER]) L.drop_all_held_items() effect_text += "disarming" - if(data.parry_data[PARRY_KNOCKDOWN_ATTACKER]) - L.DefaultCombatKnockdown(data.parry_data[PARRY_KNOCKDOWN_ATTACKER]) - effect_text += "knocking them to the ground" if(data.parry_data[PARRY_STAGGER_ATTACKER]) L.Stagger(data.parry_data[PARRY_STAGGER_ATTACKER]) effect_text += "staggering" if(data.parry_data[PARRY_DAZE_ATTACKER]) L.Daze(data.parry_data[PARRY_DAZE_ATTACKER]) effect_text += "dazing" + if(data.parry_data[PARRY_KNOCKDOWN_ATTACKER]) + L.DefaultCombatKnockdown(data.parry_data[PARRY_KNOCKDOWN_ATTACKER]) + // effect_text += "knocking them to the ground" - snowflaked above return effect_text /// Gets the datum/block_parry_data we're going to use to parry. diff --git a/code/modules/mob/living/silicon/ai/life.dm b/code/modules/mob/living/silicon/ai/life.dm index 4f2332e99d..2cbd1f35ca 100644 --- a/code/modules/mob/living/silicon/ai/life.dm +++ b/code/modules/mob/living/silicon/ai/life.dm @@ -151,7 +151,7 @@ to_chat(src, "Receiving control information from APC.") sleep(2) apc_override = 1 - theAPC.ui_interact(src, state = GLOB.conscious_state) + theAPC.ui_interact(src) apc_override = 0 aiRestorePowerRoutine = POWER_RESTORATION_APC_FOUND sleep(50) diff --git a/code/modules/mob/living/silicon/ai/robot_control.dm b/code/modules/mob/living/silicon/ai/robot_control.dm index 0eaea103f2..bbfb7604ba 100644 --- a/code/modules/mob/living/silicon/ai/robot_control.dm +++ b/code/modules/mob/living/silicon/ai/robot_control.dm @@ -19,11 +19,13 @@ return ..() return UI_CLOSE -/datum/robot_control/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ - datum/tgui/master_ui = null, datum/ui_state/state = GLOB.always_state) - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) +/datum/robot_control/ui_state(mob/user) + return GLOB.always_state + +/datum/robot_control/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) if(!ui) - ui = new(user, src, ui_key, "RemoteRobotControl", "Remote Robot Control", 500, 500, master_ui, state) + ui = new(user, src, "RemoteRobotControl") ui.open() /datum/robot_control/ui_data(mob/user) diff --git a/code/modules/mob/living/silicon/robot/inventory.dm b/code/modules/mob/living/silicon/robot/inventory.dm index a063d090db..9b964ef188 100644 --- a/code/modules/mob/living/silicon/robot/inventory.dm +++ b/code/modules/mob/living/silicon/robot/inventory.dm @@ -79,15 +79,15 @@ if(activated(O)) to_chat(src, "That module is already activated.") return - if(!held_items[1]) + if(!held_items[1] && health >= -maxHealth*0.5) held_items[1] = O O.screen_loc = inv1.screen_loc . = TRUE - else if(!held_items[2]) + else if(!held_items[2] && health >= 0) held_items[2] = O O.screen_loc = inv2.screen_loc . = TRUE - else if(!held_items[3]) + else if(!held_items[3] && health >= maxHealth*0.5) held_items[3] = O O.screen_loc = inv3.screen_loc . = TRUE diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm index 4fcd6d1dbd..9018c49b2c 100644 --- a/code/modules/mob/living/silicon/robot/robot.dm +++ b/code/modules/mob/living/silicon/robot/robot.dm @@ -16,6 +16,8 @@ wires = new /datum/wires/robot(src) AddElement(/datum/element/empprotection, EMP_PROTECT_WIRES) + RegisterSignal(src, COMSIG_PROCESS_BORGCHARGER_OCCUPANT, .proc/charge) + robot_modules_background = new() robot_modules_background.icon_state = "block" robot_modules_background.layer = HUD_LAYER //Objects that appear on screen are on layer ABOVE_HUD_LAYER, UI should be just below it. @@ -1097,6 +1099,15 @@ for(var/i in connected_ai.aicamera.stored) aicamera.stored[i] = TRUE +/mob/living/silicon/robot/proc/charge(datum/source, amount, repairs) + if(module) + var/coeff = amount * 0.005 + module.respawn_consumable(src, coeff) + if(repairs) + heal_bodypart_damage(repairs, repairs - 1) + if(cell) + cell.charge = min(cell.charge + amount, cell.maxcharge) + /mob/living/silicon/robot/proc/rest_style() set name = "Switch Rest Style" set category = "Robot Commands" diff --git a/code/modules/mob/living/silicon/robot/robot_modules.dm b/code/modules/mob/living/silicon/robot/robot_modules.dm index 7c4125fbc6..6b58988c31 100644 --- a/code/modules/mob/living/silicon/robot/robot_modules.dm +++ b/code/modules/mob/living/silicon/robot/robot_modules.dm @@ -361,7 +361,8 @@ "Sleek" = image(icon = 'modular_citadel/icons/mob/robots.dmi', icon_state = "sleekmed"), "Marina" = image(icon = 'modular_citadel/icons/mob/robots.dmi', icon_state = "marinamed"), "Eyebot" = image(icon = 'modular_citadel/icons/mob/robots.dmi', icon_state = "eyebotmed"), - "Heavy" = image(icon = 'modular_citadel/icons/mob/robots.dmi', icon_state = "heavymed") + "Heavy" = image(icon = 'modular_citadel/icons/mob/robots.dmi', icon_state = "heavymed"), + "Drake" = image(icon = 'icons/mob/cyborg/drakemech.dmi', icon_state = "drakemedbox") ) var/list/L = list("Medihound" = "medihound", "Medihound Dark" = "medihounddark", "Vale" = "valemed") for(var/a in L) @@ -422,6 +423,13 @@ moduleselect_icon = "medihound" moduleselect_alternate_icon = 'modular_citadel/icons/ui/screen_cyborg.dmi' dogborg = TRUE + if("Drake") + cyborg_base_icon = "drakemed" + cyborg_icon_override = 'icons/mob/cyborg/drakemech.dmi' + sleeper_overlay = "drakemedsleeper" + moduleselect_icon = "medihound" + moduleselect_alternate_icon = 'modular_citadel/icons/ui/screen_cyborg.dmi' + dogborg = TRUE else return FALSE return ..() @@ -478,7 +486,8 @@ "Can" = image(icon = 'modular_citadel/icons/mob/robots.dmi', icon_state = "caneng"), "Marina" = image(icon = 'modular_citadel/icons/mob/robots.dmi', icon_state = "marinaeng"), "Spider" = image(icon = 'modular_citadel/icons/mob/robots.dmi', icon_state = "spidereng"), - "Heavy" = image(icon = 'modular_citadel/icons/mob/robots.dmi', icon_state = "heavyeng") + "Heavy" = image(icon = 'modular_citadel/icons/mob/robots.dmi', icon_state = "heavyeng"), + "Drake" = image(icon = 'icons/mob/cyborg/drakemech.dmi', icon_state = "drakeengbox") ) var/list/L = list("Pup Dozer" = "pupdozer", "Vale" = "valeeng") for(var/a in L) @@ -536,6 +545,11 @@ cyborg_icon_override = 'modular_citadel/icons/mob/widerobot.dmi' sleeper_overlay = "alinasleeper" dogborg = TRUE + if("Drake") + cyborg_base_icon = "drakeeng" + cyborg_icon_override = 'icons/mob/cyborg/drakemech.dmi' + sleeper_overlay = "drakesecsleeper" + dogborg = TRUE else return FALSE return ..() @@ -574,7 +588,8 @@ "Can" = image(icon = 'modular_citadel/icons/mob/robots.dmi', icon_state = "cansec"), "Marina" = image(icon = 'modular_citadel/icons/mob/robots.dmi', icon_state = "marinasec"), "Spider" = image(icon = 'modular_citadel/icons/mob/robots.dmi', icon_state = "spidersec"), - "Heavy" = image(icon = 'modular_citadel/icons/mob/robots.dmi', icon_state = "heavysec") + "Heavy" = image(icon = 'modular_citadel/icons/mob/robots.dmi', icon_state = "heavysec"), + "Drake" = image(icon = 'icons/mob/cyborg/drakemech.dmi', icon_state = "drakesecbox") ) var/list/L = list("K9" = "k9", "Vale" = "valesec", "K9 Dark" = "k9dark") for(var/a in L) @@ -630,6 +645,11 @@ sleeper_overlay = "valesecsleeper" cyborg_icon_override = 'modular_citadel/icons/mob/widerobot.dmi' dogborg = TRUE + if("Drake") + cyborg_base_icon = "drakesec" + cyborg_icon_override = 'icons/mob/cyborg/drakemech.dmi' + sleeper_overlay = "drakesecsleeper" + dogborg = TRUE else return FALSE return ..() @@ -673,7 +693,8 @@ var/static/list/peace_icons = sortList(list( "Default" = image(icon = 'icons/mob/robots.dmi', icon_state = "peace"), "Borgi" = image(icon = 'modular_citadel/icons/mob/robots.dmi', icon_state = "borgi"), - "Spider" = image(icon = 'modular_citadel/icons/mob/robots.dmi', icon_state = "whitespider") + "Spider" = image(icon = 'modular_citadel/icons/mob/robots.dmi', icon_state = "whitespider"), + "Drake" = image(icon = 'icons/mob/cyborg/drakemech.dmi', icon_state = "drakepeacebox") )) var/peace_borg_icon = show_radial_menu(R, R , peace_icons, custom_check = CALLBACK(src, .proc/check_menu, R), radius = 42, require_near = TRUE) switch(peace_borg_icon) @@ -689,6 +710,11 @@ hat_offset = INFINITY cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi' has_snowflake_deadsprite = TRUE + if("Drake") + cyborg_base_icon = "drakepeace" + cyborg_icon_override = 'icons/mob/cyborg/drakemech.dmi' + sleeper_overlay = "drakepeacesleeper" + dogborg = TRUE else return FALSE return ..() @@ -827,7 +853,8 @@ "(Janitor) Marina" = image(icon = 'modular_citadel/icons/mob/robots.dmi', icon_state = "marinajan"), "(Janitor) Sleek" = image(icon = 'modular_citadel/icons/mob/robots.dmi', icon_state = "sleekjan"), "(Janitor) Can" = image(icon = 'modular_citadel/icons/mob/robots.dmi', icon_state = "canjan"), - "(Janitor) Heavy" = image(icon = 'modular_citadel/icons/mob/robots.dmi', icon_state = "heavyjan") + "(Janitor) Heavy" = image(icon = 'modular_citadel/icons/mob/robots.dmi', icon_state = "heavyjan"), + "(Janitor) Drake" = image(icon = 'icons/mob/cyborg/drakemech.dmi', icon_state = "drakejanitbox") ) var/list/L = list("(Service) DarkK9" = "k50", "(Service) Vale" = "valeserv", "(Service) ValeDark" = "valeservdark", "(Janitor) Scrubpuppy" = "scrubpup") @@ -899,6 +926,11 @@ cyborg_icon_override = 'modular_citadel/icons/mob/widerobot.dmi' sleeper_overlay = "jsleeper" dogborg = TRUE + if("(Janitor) Drake") + cyborg_base_icon = "drakejanit" + cyborg_icon_override = 'icons/mob/cyborg/drakemech.dmi' + sleeper_overlay = "drakesecsleeper" + dogborg = TRUE else return FALSE return ..() @@ -944,7 +976,8 @@ "Sleek" = image(icon = 'modular_citadel/icons/mob/robots.dmi', icon_state = "sleekmin"), "Marina" = image(icon = 'modular_citadel/icons/mob/robots.dmi', icon_state = "marinamin"), "Can" = image(icon = 'modular_citadel/icons/mob/robots.dmi', icon_state = "canmin"), - "Heavy" = image(icon = 'modular_citadel/icons/mob/robots.dmi', icon_state = "heavymin") + "Heavy" = image(icon = 'modular_citadel/icons/mob/robots.dmi', icon_state = "heavymin"), + "Drake" = image(icon = 'icons/mob/cyborg/drakemech.dmi', icon_state = "drakeminebox") ) var/list/L = list("Blade" = "blade", "Vale" = "valemine") for(var/a in L) @@ -988,6 +1021,11 @@ cyborg_icon_override = 'modular_citadel/icons/mob/widerobot.dmi' sleeper_overlay = "valeminesleeper" dogborg = TRUE + if("Drake") + cyborg_base_icon = "drakemine" + cyborg_icon_override = 'icons/mob/cyborg/drakemech.dmi' + sleeper_overlay = "drakeminesleeper" + dogborg = TRUE else return FALSE return ..() diff --git a/code/modules/mob/living/silicon/silicon.dm b/code/modules/mob/living/silicon/silicon.dm index 7a9610fb53..c6aee397e4 100644 --- a/code/modules/mob/living/silicon/silicon.dm +++ b/code/modules/mob/living/silicon/silicon.dm @@ -430,3 +430,6 @@ /mob/living/silicon/handle_high_gravity(gravity) return + +/mob/living/silicon/rust_heretic_act() + adjustBruteLoss(500) diff --git a/code/modules/mob/living/simple_animal/bot/bot.dm b/code/modules/mob/living/simple_animal/bot/bot.dm index fe6792b5c2..a1772d9281 100644 --- a/code/modules/mob/living/simple_animal/bot/bot.dm +++ b/code/modules/mob/living/simple_animal/bot/bot.dm @@ -1058,3 +1058,6 @@ Pass a positive integer as an argument to override a bot's default speed. if(I) I.icon_state = null path.Cut(1, 2) + +/mob/living/silicon/rust_heretic_act() + adjustBruteLoss(500) diff --git a/code/modules/mob/living/simple_animal/bot/cleanbot.dm b/code/modules/mob/living/simple_animal/bot/cleanbot.dm index 5c83482bde..e7c5644e26 100644 --- a/code/modules/mob/living/simple_animal/bot/cleanbot.dm +++ b/code/modules/mob/living/simple_animal/bot/cleanbot.dm @@ -313,7 +313,7 @@ /obj/effect/decal/cleanable/dirt, /obj/effect/decal/cleanable/insectguts, /obj/effect/decal/cleanable/semen, - /obj/effect/decal/cleanable/femcum, + /obj/effect/decal/cleanable/semen/femcum, /obj/effect/decal/cleanable/generic, /obj/effect/decal/cleanable/glass,, /obj/effect/decal/cleanable/cobweb, diff --git a/code/modules/mob/living/simple_animal/bot/mulebot.dm b/code/modules/mob/living/simple_animal/bot/mulebot.dm index 5e96818766..d9bf8cc553 100644 --- a/code/modules/mob/living/simple_animal/bot/mulebot.dm +++ b/code/modules/mob/living/simple_animal/bot/mulebot.dm @@ -29,9 +29,6 @@ model = "MULE" bot_core_type = /obj/machinery/bot_core/mulebot - var/ui_x = 350 - var/ui_y = 425 - var/id path_image_color = "#7F5200" @@ -170,11 +167,10 @@ return ui_interact(user) -/mob/living/simple_animal/bot/mulebot/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ - datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) +/mob/living/simple_animal/bot/mulebot/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) if(!ui) - ui = new(user, src, ui_key, "Mule", name, ui_x, ui_y, master_ui, state) + ui = new(user, src, "Mule", name) ui.open() /mob/living/simple_animal/bot/mulebot/ui_data(mob/user) @@ -191,8 +187,7 @@ data["modeStatus"] = "average" if(BOT_NO_ROUTE) data["modeStatus"] = "bad" - else - data["load"] = load ? load.name : null + data["load"] = load ? load.name : null //IF YOU CHANGE THE NAME OF THIS, UPDATE MULEBOT/PARANORMAL/UI_DATA. data["destination"] = destination ? destination : null data["home"] = home_destination data["destinations"] = GLOB.deliverybeacontags @@ -206,18 +201,20 @@ return data /mob/living/simple_animal/bot/mulebot/ui_act(action, params) - var/silicon_access = hasSiliconAccessInArea(usr) - if(..() || (locked && silicon_access)) + if(..() || (locked && hasSiliconAccessInArea(usr))) return switch(action) if("lock") - if(silicon_access) + if(hasSiliconAccessInArea(usr)) locked = !locked . = TRUE if("power") if(on) turn_off() - else if(cell && !open) + else if(open) + to_chat(usr, "[name]'s maintenance panel is open!") + return + else if(cell) if(!turn_on()) to_chat(usr, "You can't switch on [src]!") return diff --git a/code/modules/mob/living/simple_animal/constructs.dm b/code/modules/mob/living/simple_animal/constructs.dm index 354bc9ed0f..95bd8d8991 100644 --- a/code/modules/mob/living/simple_animal/constructs.dm +++ b/code/modules/mob/living/simple_animal/constructs.dm @@ -11,7 +11,6 @@ response_disarm_simple = "flail at" response_harm_continuous = "punches" response_harm_simple = "punch" - threat = 1 speak_chance = 1 icon = 'icons/mob/mob.dmi' speed = 0 @@ -122,7 +121,6 @@ desc = "A massive, armored construct built to spearhead attacks and soak up enemy fire." icon_state = "behemoth" icon_living = "behemoth" - threat = 3 maxHealth = 150 health = 150 response_harm_continuous = "harmlessly punches" @@ -187,7 +185,6 @@ desc = "A wicked, clawed shell constructed to assassinate enemies and sow chaos behind enemy lines." icon_state = "floating" icon_living = "floating" - threat = 3 maxHealth = 65 health = 65 melee_damage_lower = 20 diff --git a/code/modules/mob/living/simple_animal/eldritch_demons.dm b/code/modules/mob/living/simple_animal/eldritch_demons.dm new file mode 100644 index 0000000000..dbf62be16d --- /dev/null +++ b/code/modules/mob/living/simple_animal/eldritch_demons.dm @@ -0,0 +1,386 @@ +/mob/living/simple_animal/hostile/eldritch + name = "Demon" + real_name = "Demon" + desc = "" + gender = NEUTER + mob_biotypes = NONE + speak_emote = list("screams") + response_help_continuous = "thinks better of touching" + response_help_simple = "think better of touching" + response_disarm_continuous = "flails at" + response_disarm_simple = "flail at" + response_harm_continuous = "reaps" + response_harm_simple = "tears" + speak_chance = 1 + icon = 'icons/mob/eldritch_mobs.dmi' + speed = 0 + a_intent = INTENT_HARM + stop_automated_movement = 1 + AIStatus = AI_OFF + attack_sound = 'sound/weapons/punch1.ogg' + see_in_dark = 7 + lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE + damage_coeff = list(BRUTE = 1, BURN = 1, TOX = 0, CLONE = 0, STAMINA = 0, OXY = 0) + atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0) + minbodytemp = 0 + maxbodytemp = INFINITY + healable = 0 + movement_type = GROUND + pressure_resistance = 100 + del_on_death = TRUE + deathmessage = "implodes into itself" + faction = list("heretics") + simple_mob_flags = SILENCE_RANGED_MESSAGE + ///Innate spells that are supposed to be added when a beast is created + var/list/spells_to_add + +/mob/living/simple_animal/hostile/eldritch/Initialize() + . = ..() + add_spells() + +/** + * Add_spells + * + * Goes through spells_to_add and adds each spell to the mind. + */ +/mob/living/simple_animal/hostile/eldritch/proc/add_spells() + for(var/spell in spells_to_add) + AddSpell(new spell()) + +/mob/living/simple_animal/hostile/eldritch/raw_prophet + name = "Raw Prophet" + real_name = "Raw Prophet" + desc = "Abomination made from severed limbs." + icon_state = "raw_prophet" + status_flags = CANPUSH + icon_living = "raw_prophet" + melee_damage_lower = 5 + melee_damage_upper = 10 + maxHealth = 50 + health = 50 + sight = SEE_MOBS|SEE_OBJS|SEE_TURFS + spells_to_add = list(/obj/effect/proc_holder/spell/targeted/ethereal_jaunt/shift/ash/long,/obj/effect/proc_holder/spell/pointed/manse_link,/obj/effect/proc_holder/spell/targeted/telepathy/eldritch,/obj/effect/proc_holder/spell/pointed/trigger/blind/eldritch) + + var/list/linked_mobs = list() + +/mob/living/simple_animal/hostile/eldritch/raw_prophet/Initialize() + . = ..() + link_mob(src) + +/mob/living/simple_animal/hostile/eldritch/raw_prophet/Login() + . = ..() + client.change_view(10) + +/mob/living/simple_animal/hostile/eldritch/raw_prophet/proc/link_mob(mob/living/mob_linked) + if(QDELETED(mob_linked) || mob_linked.stat == DEAD) + return FALSE + if(HAS_TRAIT(mob_linked, TRAIT_MINDSHIELD)) //mindshield implant, no dice + return FALSE + if(mob_linked.anti_magic_check(FALSE, FALSE, TRUE, 0)) + return FALSE + if(linked_mobs[mob_linked]) + return FALSE + + to_chat(mob_linked, "You feel something new enter your sphere of mind, you hear whispers of people far away, screeches of horror and a humming of welcome to [src]'s Mansus Link.") + var/datum/action/innate/mansus_speech/action = new(src) + linked_mobs[mob_linked] = action + action.Grant(mob_linked) + RegisterSignal(mob_linked, list(COMSIG_MOB_DEATH, COMSIG_PARENT_QDELETING) , .proc/unlink_mob) + return TRUE + +/mob/living/simple_animal/hostile/eldritch/raw_prophet/proc/unlink_mob(mob/living/mob_linked) + if(!linked_mobs[mob_linked]) + return + UnregisterSignal(mob_linked, list(COMSIG_MOB_DEATH, COMSIG_PARENT_QDELETING)) + var/datum/action/innate/mansus_speech/action = linked_mobs[mob_linked] + action.Remove(mob_linked) + qdel(action) + to_chat(mob_linked, "Your mind shatters as the [src]'s Mansus Link leaves your mind.") + mob_linked.emote("Scream") + //micro stun + mob_linked.AdjustParalyzed(0.5 SECONDS) + linked_mobs -= mob_linked + +/mob/living/simple_animal/hostile/eldritch/raw_prophet/death(gibbed) + for(var/linked_mob in linked_mobs) + unlink_mob(linked_mob) + return ..() + +/mob/living/simple_animal/hostile/eldritch/armsy + name = "Terror of the Night" + real_name = "Armsy" + desc = "Abomination made from severed limbs." + icon_state = "armsy_start" + icon_living = "armsy_start" + maxHealth = 200 + health = 200 + obj_damage = 80 + melee_damage_lower = 10 + melee_damage_upper = 15 + move_resist = MOVE_FORCE_OVERPOWERING+1 + movement_type = GROUND + environment_smash = ENVIRONMENT_SMASH_RWALLS + sight = SEE_MOBS + spells_to_add = list(/obj/effect/proc_holder/spell/targeted/worm_contract) + ranged = TRUE + ///Previous segment in the chain + var/mob/living/simple_animal/hostile/eldritch/armsy/back + ///Next segment in the chain + var/mob/living/simple_animal/hostile/eldritch/armsy/front + ///Your old location + var/oldloc + ///Allow / disallow pulling + var/allow_pulling = FALSE + ///How many arms do we have to eat to expand? + var/stacks_to_grow = 2 + ///Currently eaten arms + var/current_stacks = 0 + +//I tried Initalize but it didnt work, like at all. This proc just wouldnt fire if it was Initalize instead of New +/mob/living/simple_animal/hostile/eldritch/armsy/Initialize(mapload,spawn_more = TRUE,len = 6) + . = ..() + if(len < 3) + stack_trace("Eldritch Armsy created with invalid len ([len]). Reverting to 3.") + len = 3 //code breaks below 3, let's just not allow it. + oldloc = loc + RegisterSignal(src,COMSIG_MOVABLE_MOVED,.proc/update_chain_links) + if(!spawn_more) + return + allow_pulling = TRUE + ///next link + var/mob/living/simple_animal/hostile/eldritch/armsy/next + ///previous link + var/mob/living/simple_animal/hostile/eldritch/armsy/prev + ///current link + var/mob/living/simple_animal/hostile/eldritch/armsy/current + for(var/i in 0 to len) + prev = current + //i tried using switch, but byond is really fucky and it didnt work as intended. Im sorry + if(i == 0) + current = new type(drop_location(),FALSE) + current.icon_state = "armsy_mid" + current.icon_living = "armsy_mid" + current.front = src + current.AIStatus = AI_OFF + back = current + else if(i < len) + current = new type(drop_location(),FALSE) + prev.back = current + prev.icon_state = "armsy_mid" + prev.icon_living = "armsy_mid" + prev.front = next + prev.AIStatus = AI_OFF + else + prev.icon_state = "armsy_end" + prev.icon_living = "armsy_end" + prev.front = next + prev.AIStatus = AI_OFF + next = prev + +//we are literally a vessel of otherworldly destruction, we bring our own gravity unto this plane +/mob/living/simple_animal/hostile/eldritch/armsy/has_gravity(turf/T) + return TRUE + + +/mob/living/simple_animal/hostile/eldritch/armsy/can_be_pulled() + return FALSE + +///Updates chain links to force move onto a single tile +/mob/living/simple_animal/hostile/eldritch/armsy/proc/contract_next_chain_into_single_tile() + if(back) + back.forceMove(loc) + back.contract_next_chain_into_single_tile() + return + +///Updates the next mob in the chain to move to our last location, fixed the worm if somehow broken. +/mob/living/simple_animal/hostile/eldritch/armsy/proc/update_chain_links() + gib_trail() + if(back && back.loc != oldloc) + back.Move(oldloc) + // self fixing properties if somehow broken + if(front && loc != front.oldloc) + forceMove(front.oldloc) + oldloc = loc + +/mob/living/simple_animal/hostile/eldritch/armsy/proc/gib_trail() + if(front) // head makes gibs + return + var/chosen_decal = pick(typesof(/obj/effect/decal/cleanable/blood/tracks)) + var/obj/effect/decal/cleanable/blood/gibs/decal = new chosen_decal(drop_location()) + decal.setDir(dir) + +/mob/living/simple_animal/hostile/eldritch/armsy/Destroy() + if(front) + front.icon_state = "armsy_end" + front.icon_living = "armsy_end" + front.back = null + if(back) + QDEL_NULL(back) // chain destruction baby + return ..() + +/mob/living/simple_animal/hostile/eldritch/armsy/BiologicalLife(seconds, times_fired) + adjustBruteLoss(-2) + +/mob/living/simple_animal/hostile/eldritch/armsy/proc/heal() + if(health == maxHealth) + if(back) + back.heal() + return + else + current_stacks++ + if(current_stacks >= stacks_to_grow) + var/mob/living/simple_animal/hostile/eldritch/armsy/prev = new type(drop_location(),spawn_more = FALSE) + icon_state = "armsy_mid" + icon_living = "armsy_mid" + back = prev + prev.icon_state = "armsy_end" + prev.icon_living = "armsy_end" + prev.front = src + prev.AIStatus = AI_OFF + current_stacks = 0 + + adjustBruteLoss(-maxHealth * 0.5, FALSE) + adjustFireLoss(-maxHealth * 0.5 ,FALSE) + + +/mob/living/simple_animal/hostile/eldritch/armsy/Shoot(atom/targeted_atom) + target = targeted_atom + AttackingTarget() + + +/mob/living/simple_animal/hostile/eldritch/armsy/AttackingTarget() + if(istype(target,/obj/item/bodypart/r_arm) || istype(target,/obj/item/bodypart/l_arm)) + qdel(target) + heal() + return + if(target == back || target == front) + return + if(back) + back.target = target + back.AttackingTarget() + if(!Adjacent(target)) + return + do_attack_animation(target) + //have fun + //if(istype(target,/turf/closed/wall)) + //var/turf/closed/wall = target + //wall.ScrapeAway() + + + if(iscarbon(target)) + var/mob/living/carbon/C = target + if(HAS_TRAIT(C, TRAIT_NODISMEMBER)) + return + var/list/parts = list() + for(var/X in C.bodyparts) + var/obj/item/bodypart/bodypart = X + if(bodypart.body_part != HEAD && bodypart.body_part != CHEST) + if(bodypart.dismemberable) + parts += bodypart + if(length(parts) && prob(10)) + var/obj/item/bodypart/bodypart = pick(parts) + bodypart.dismember() + + return ..() + +/mob/living/simple_animal/hostile/eldritch/armsy/prime + name = "Lord of the Night" + real_name = "Master of Decay" + maxHealth = 400 + health = 400 + melee_damage_lower = 20 + melee_damage_upper = 25 + +/mob/living/simple_animal/hostile/eldritch/armsy/prime/Initialize(mapload,spawn_more = TRUE,len = 9) + . = ..() + var/matrix/matrix_transformation = matrix() + matrix_transformation.Scale(1.4,1.4) + transform = matrix_transformation + +/mob/living/simple_animal/hostile/eldritch/armsy/primeproc/heal() + if(health == maxHealth) + if(back) + back.heal() + return + else + current_stacks++ + if(current_stacks >= stacks_to_grow) + var/mob/living/simple_animal/hostile/eldritch/armsy/prev = new type(drop_location(),spawn_more = FALSE) + icon_state = "armsy_mid" + icon_living = "armsy_mid" + back = prev + prev.icon_state = "armsy_end" + prev.icon_living = "armsy_end" + prev.front = src + prev.AIStatus = AI_OFF + current_stacks = 0 + var/matrix/matrix_transformation = matrix() + matrix_transformation.Scale(1.4,1.4) + transform = matrix_transformation + + adjustBruteLoss(-maxHealth * 0.5, FALSE) + adjustFireLoss(-maxHealth * 0.5 ,FALSE) + + +/mob/living/simple_animal/hostile/eldritch/rust_spirit + name = "Rust Walker" + real_name = "Rusty" + desc = "Incomprehensible abomination actively seeping life out of it's surrounding." + icon_state = "rust_walker_s" + status_flags = CANPUSH + icon_living = "rust_walker_s" + maxHealth = 75 + health = 75 + melee_damage_lower = 15 + melee_damage_upper = 20 + sight = SEE_TURFS + spells_to_add = list(/obj/effect/proc_holder/spell/aoe_turf/rust_conversion/small,/obj/effect/proc_holder/spell/aimed/rust_wave/short) + +/mob/living/simple_animal/hostile/eldritch/rust_spirit/setDir(newdir, ismousemovement) + . = ..() + if(newdir == NORTH) + icon_state = "rust_walker_n" + else if(newdir == SOUTH) + icon_state = "rust_walker_s" + update_icon() + +/mob/living/simple_animal/hostile/eldritch/rust_spirit/Moved() + . = ..() + playsound(src, 'sound/effects/footstep/rustystep1.ogg', 100, TRUE) + +/mob/living/simple_animal/hostile/eldritch/rust_spirit/Life() + if(stat == DEAD) + return ..() + var/turf/T = get_turf(src) + if(istype(T,/turf/open/floor/plating/rust)) + adjustBruteLoss(-3, FALSE) + adjustFireLoss(-3, FALSE) + return ..() + +/mob/living/simple_animal/hostile/eldritch/ash_spirit + name = "Ash Man" + real_name = "Ashy" + desc = "Incomprehensible abomination actively seeping life out of it's surrounding." + icon_state = "ash_walker" + status_flags = CANPUSH + icon_living = "ash_walker" + maxHealth = 75 + health = 75 + melee_damage_lower = 15 + melee_damage_upper = 20 + sight = SEE_TURFS + spells_to_add = list(/obj/effect/proc_holder/spell/targeted/ethereal_jaunt/shift/ash,/obj/effect/proc_holder/spell/pointed/cleave/long,/obj/effect/proc_holder/spell/aoe_turf/fire_cascade) + +/mob/living/simple_animal/hostile/eldritch/stalker + name = "Flesh Stalker" + real_name = "Flesh Stalker" + desc = "Abomination made from severed limbs." + icon_state = "stalker" + status_flags = CANPUSH + icon_living = "stalker" + maxHealth = 150 + health = 150 + melee_damage_lower = 15 + melee_damage_upper = 20 + sight = SEE_MOBS + spells_to_add = list(/obj/effect/proc_holder/spell/targeted/ethereal_jaunt/shift/ash,/obj/effect/proc_holder/spell/targeted/shapeshift/eldritch,/obj/effect/proc_holder/spell/targeted/emplosion/eldritch) diff --git a/code/modules/mob/living/simple_animal/friendly/gondola.dm b/code/modules/mob/living/simple_animal/friendly/gondola.dm index 0cfea3548b..e29cbb8062 100644 --- a/code/modules/mob/living/simple_animal/friendly/gondola.dm +++ b/code/modules/mob/living/simple_animal/friendly/gondola.dm @@ -58,7 +58,7 @@ eyes_overlay.pixel_y = -8 moustache_overlay.pixel_y = -8 - cut_overlays(TRUE) + cut_overlays() add_overlay(body_overlay) add_overlay(eyes_overlay) add_overlay(moustache_overlay) diff --git a/code/modules/mob/living/simple_animal/friendly/possum.dm b/code/modules/mob/living/simple_animal/friendly/possum.dm new file mode 100644 index 0000000000..71fdbd1465 --- /dev/null +++ b/code/modules/mob/living/simple_animal/friendly/possum.dm @@ -0,0 +1,37 @@ +/mob/living/simple_animal/opossum + name = "opossum" + desc = "It's an opossum, a small scavenging marsupial." + icon_state = "possum" + icon_living = "possum" + icon_dead = "possum_dead" + speak = list("Hiss!","HISS!","Hissss?") + speak_emote = list("hisses") + emote_hear = list("hisses.") + emote_see = list("runs in a circle.", "shakes.") + speak_chance = 1 + turns_per_move = 3 + blood_volume = 250 + see_in_dark = 5 + maxHealth = 15 + health = 15 + butcher_results = list(/obj/item/reagent_containers/food/snacks/meat/slab = 1) + response_help_continuous = "pets" + response_help_simple = "pet" + response_disarm_continuous = "gently pushes aside" + response_disarm_simple = "gently push aside" + response_harm_continuous = "stamps on" + response_harm_simple = "stamp" + density = FALSE + ventcrawler = VENTCRAWLER_ALWAYS + pass_flags = PASSTABLE | PASSMOB + mob_size = MOB_SIZE_TINY + mob_biotypes = MOB_ORGANIC|MOB_BEAST + gold_core_spawnable = FRIENDLY_SPAWN + +/mob/living/simple_animal/opossum/poppy + name = "Poppy the Safety Possum" + desc = "Safety first!" + icon_state = "poppypossum" + icon_living = "poppypossum" + icon_dead = "poppypossum_dead" + butcher_results = list(/obj/item/clothing/head/hardhat = 1) diff --git a/code/modules/mob/living/simple_animal/guardian/guardian.dm b/code/modules/mob/living/simple_animal/guardian/guardian.dm index fb24b0fc09..7abecc7c81 100644 --- a/code/modules/mob/living/simple_animal/guardian/guardian.dm +++ b/code/modules/mob/living/simple_animal/guardian/guardian.dm @@ -8,7 +8,6 @@ GLOBAL_LIST_EMPTY(parasites) //all currently existing/living guardians name = "Guardian Spirit" real_name = "Guardian Spirit" desc = "A mysterious being that stands by its charge, ever vigilant." - threat = 5 speak_emote = list("hisses") gender = NEUTER mob_biotypes = NONE diff --git a/code/modules/mob/living/simple_animal/hostile/alien.dm b/code/modules/mob/living/simple_animal/hostile/alien.dm index 7120ab6d0a..86467624b5 100644 --- a/code/modules/mob/living/simple_animal/hostile/alien.dm +++ b/code/modules/mob/living/simple_animal/hostile/alien.dm @@ -7,7 +7,6 @@ icon_dead = "alienh_dead" icon_gib = "syndicate_gib" gender = FEMALE - threat = 1 response_help_continuous = "pokes" response_help_simple = "poke" response_disarm_continuous = "shoves" @@ -69,7 +68,6 @@ icon_state = "aliens" icon_living = "aliens" icon_dead = "aliens_dead" - threat = 3 health = 150 maxHealth = 150 melee_damage_lower = 15 @@ -87,7 +85,6 @@ icon_living = "alienq" icon_dead = "alienq_dead" pixel_x = -16 - threat = 8 health = 250 maxHealth = 250 melee_damage_lower = 15 @@ -167,7 +164,6 @@ name = "lusty xenomorph maid" melee_damage_lower = 0 melee_damage_upper = 0 - threat = -1 a_intent = INTENT_HELP friendly_verb_continuous = "caresses" friendly_verb_simple = "caress" diff --git a/code/modules/mob/living/simple_animal/hostile/bear.dm b/code/modules/mob/living/simple_animal/hostile/bear.dm index da16ec581b..1be90a07f8 100644 --- a/code/modules/mob/living/simple_animal/hostile/bear.dm +++ b/code/modules/mob/living/simple_animal/hostile/bear.dm @@ -2,7 +2,6 @@ /mob/living/simple_animal/hostile/bear name = "space bear" desc = "You don't need to be faster than a space bear, you just need to outrun your crewmates." - threat = 1 icon_state = "bear" icon_living = "bear" icon_dead = "bear_dead" diff --git a/code/modules/mob/living/simple_animal/hostile/bees.dm b/code/modules/mob/living/simple_animal/hostile/bees.dm index 5f3d4f11c1..0a3cde3ef8 100644 --- a/code/modules/mob/living/simple_animal/hostile/bees.dm +++ b/code/modules/mob/living/simple_animal/hostile/bees.dm @@ -16,7 +16,6 @@ icon_state = "" icon_living = "" icon = 'icons/mob/bees.dmi' - threat = 0.3 gender = FEMALE speak_emote = list("buzzes") emote_hear = list("buzzes") diff --git a/code/modules/mob/living/simple_animal/hostile/bosses/boss.dm b/code/modules/mob/living/simple_animal/hostile/bosses/boss.dm index cde63adffd..b4d60af198 100644 --- a/code/modules/mob/living/simple_animal/hostile/bosses/boss.dm +++ b/code/modules/mob/living/simple_animal/hostile/bosses/boss.dm @@ -1,7 +1,6 @@ /mob/living/simple_animal/hostile/boss name = "A Perfectly Generic Boss Placeholder" desc = "" - threat = 10 robust_searching = TRUE stat_attack = UNCONSCIOUS status_flags = NONE diff --git a/code/modules/mob/living/simple_animal/hostile/carp.dm b/code/modules/mob/living/simple_animal/hostile/carp.dm index f775d6600c..51a646f668 100644 --- a/code/modules/mob/living/simple_animal/hostile/carp.dm +++ b/code/modules/mob/living/simple_animal/hostile/carp.dm @@ -7,7 +7,6 @@ icon_living = "carp" icon_dead = "carp_dead" icon_gib = "carp_gib" - threat = 0.1 mob_biotypes = MOB_ORGANIC|MOB_BEAST speak_chance = 0 turns_per_move = 5 @@ -74,7 +73,6 @@ icon_living = "megacarp" icon_dead = "megacarp_dead" icon_gib = "megacarp_gib" - threat = 3 regen_amount = 6 maxHealth = 30 @@ -98,7 +96,6 @@ name = "Cayenne" desc = "A failed Syndicate experiment in weaponized space carp technology, it now serves as a lovable mascot." gender = FEMALE - threat = 5 regen_amount = 8 speak_emote = list("squeaks") diff --git a/code/modules/mob/living/simple_animal/hostile/dark_wizard.dm b/code/modules/mob/living/simple_animal/hostile/dark_wizard.dm index 48266e3e76..9b50587b3d 100644 --- a/code/modules/mob/living/simple_animal/hostile/dark_wizard.dm +++ b/code/modules/mob/living/simple_animal/hostile/dark_wizard.dm @@ -1,7 +1,6 @@ /mob/living/simple_animal/hostile/dark_wizard name = "Dark Wizard" desc = "Killing amateurs since the dawn of times." - threat = 3 icon = 'icons/mob/simple_human.dmi' icon_state = "dark_wizard" icon_living = "dark_wizard" diff --git a/code/modules/mob/living/simple_animal/hostile/faithless.dm b/code/modules/mob/living/simple_animal/hostile/faithless.dm index 4f8d2fef6c..b44a2502ef 100644 --- a/code/modules/mob/living/simple_animal/hostile/faithless.dm +++ b/code/modules/mob/living/simple_animal/hostile/faithless.dm @@ -4,7 +4,6 @@ icon_state = "faithless" icon_living = "faithless" icon_dead = "faithless_dead" - threat = 1 mob_biotypes = MOB_ORGANIC|MOB_HUMANOID gender = MALE speak_chance = 0 diff --git a/code/modules/mob/living/simple_animal/hostile/giant_spider.dm b/code/modules/mob/living/simple_animal/hostile/giant_spider.dm index a253ecfd96..a8799f4e8c 100644 --- a/code/modules/mob/living/simple_animal/hostile/giant_spider.dm +++ b/code/modules/mob/living/simple_animal/hostile/giant_spider.dm @@ -17,7 +17,6 @@ //basic spider mob, these generally guard nests /mob/living/simple_animal/hostile/poison/giant_spider - threat = 1 name = "giant spider" desc = "Furry and black, it makes you shudder to look at it. This one has deep red eyes." icon_state = "guard" diff --git a/code/modules/mob/living/simple_animal/hostile/gorilla/gorilla.dm b/code/modules/mob/living/simple_animal/hostile/gorilla/gorilla.dm index f48eef083b..ec0b7acd07 100644 --- a/code/modules/mob/living/simple_animal/hostile/gorilla/gorilla.dm +++ b/code/modules/mob/living/simple_animal/hostile/gorilla/gorilla.dm @@ -9,7 +9,6 @@ icon_state = "crawling" icon_living = "crawling" icon_dead = "dead" - threat = 0.5 mob_biotypes = MOB_ORGANIC|MOB_HUMANOID speak_chance = 80 maxHealth = 220 diff --git a/code/modules/mob/living/simple_animal/hostile/headcrab.dm b/code/modules/mob/living/simple_animal/hostile/headcrab.dm index 501534237a..ac53ff794b 100644 --- a/code/modules/mob/living/simple_animal/hostile/headcrab.dm +++ b/code/modules/mob/living/simple_animal/hostile/headcrab.dm @@ -6,7 +6,6 @@ icon_state = "headcrab" icon_living = "headcrab" icon_dead = "headcrab_dead" - threat = 1 gender = NEUTER health = 50 maxHealth = 50 diff --git a/code/modules/mob/living/simple_animal/hostile/hostile.dm b/code/modules/mob/living/simple_animal/hostile/hostile.dm index 5ed3cd0cdd..186fe36a10 100644 --- a/code/modules/mob/living/simple_animal/hostile/hostile.dm +++ b/code/modules/mob/living/simple_animal/hostile/hostile.dm @@ -3,7 +3,6 @@ stop_automated_movement_when_pulled = 0 obj_damage = 40 environment_smash = ENVIRONMENT_SMASH_STRUCTURES //Bitflags. Set to ENVIRONMENT_SMASH_STRUCTURES to break closets,tables,racks, etc; ENVIRONMENT_SMASH_WALLS for walls; ENVIRONMENT_SMASH_RWALLS for rwalls - var/threat = 0 // for dynamic var/atom/target var/ranged = FALSE var/rapid = 0 //How many shots per volley. @@ -600,6 +599,3 @@ mob/living/simple_animal/hostile/proc/DestroySurroundings() // for use with mega . += M else if (M.loc.type in hostile_machines) . += M.loc - -/mob/living/simple_animal/hostile/proc/threat() - return threat diff --git a/code/modules/mob/living/simple_animal/hostile/jungle/leaper.dm b/code/modules/mob/living/simple_animal/hostile/jungle/leaper.dm index 55046d6555..362432b2af 100644 --- a/code/modules/mob/living/simple_animal/hostile/jungle/leaper.dm +++ b/code/modules/mob/living/simple_animal/hostile/jungle/leaper.dm @@ -11,7 +11,6 @@ icon_living = "leaper" icon_dead = "leaper_dead" mob_biotypes = MOB_ORGANIC|MOB_BEAST - threat = 2 maxHealth = 300 health = 300 ranged = TRUE diff --git a/code/modules/mob/living/simple_animal/hostile/jungle/mega_arachnid.dm b/code/modules/mob/living/simple_animal/hostile/jungle/mega_arachnid.dm index 99349168f0..31303bd7f1 100644 --- a/code/modules/mob/living/simple_animal/hostile/jungle/mega_arachnid.dm +++ b/code/modules/mob/living/simple_animal/hostile/jungle/mega_arachnid.dm @@ -8,7 +8,6 @@ icon_living = "arachnid" icon_dead = "arachnid_dead" mob_biotypes = MOB_ORGANIC|MOB_BUG - threat = 2 melee_damage_lower = 30 melee_damage_upper = 30 maxHealth = 300 diff --git a/code/modules/mob/living/simple_animal/hostile/jungle/mook.dm b/code/modules/mob/living/simple_animal/hostile/jungle/mook.dm index 6efa0cf468..2d964f5721 100644 --- a/code/modules/mob/living/simple_animal/hostile/jungle/mook.dm +++ b/code/modules/mob/living/simple_animal/hostile/jungle/mook.dm @@ -14,7 +14,6 @@ icon_living = "mook" icon_dead = "mook_dead" mob_biotypes = MOB_ORGANIC|MOB_HUMANOID - threat = 0.5 pixel_x = -16 maxHealth = 45 health = 45 diff --git a/code/modules/mob/living/simple_animal/hostile/jungle/seedling.dm b/code/modules/mob/living/simple_animal/hostile/jungle/seedling.dm index 0521afa9e9..7565a686bf 100644 --- a/code/modules/mob/living/simple_animal/hostile/jungle/seedling.dm +++ b/code/modules/mob/living/simple_animal/hostile/jungle/seedling.dm @@ -13,7 +13,6 @@ icon_state = "seedling" icon_living = "seedling" icon_dead = "seedling_dead" - threat = 0.5 maxHealth = 100 health = 100 melee_damage_lower = 30 diff --git a/code/modules/mob/living/simple_animal/hostile/killertomato.dm b/code/modules/mob/living/simple_animal/hostile/killertomato.dm index 9cb65d7c30..b86d5d87fc 100644 --- a/code/modules/mob/living/simple_animal/hostile/killertomato.dm +++ b/code/modules/mob/living/simple_animal/hostile/killertomato.dm @@ -5,7 +5,6 @@ icon_living = "tomato" icon_dead = "tomato_dead" gender = NEUTER - threat = 0.3 speak_chance = 0 turns_per_move = 5 maxHealth = 30 diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner.dm index 5c1229c130..2a5f279386 100644 --- a/code/modules/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner.dm +++ b/code/modules/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner.dm @@ -23,7 +23,6 @@ Difficulty: Medium /mob/living/simple_animal/hostile/megafauna/blood_drunk_miner name = "blood-drunk miner" desc = "A miner destined to wander forever, engaged in an endless hunt." - threat = 15 health = 900 maxHealth = 900 icon_state = "miner" diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm index b191eaf3fb..519d6402e6 100644 --- a/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm +++ b/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm @@ -26,7 +26,6 @@ Difficulty: Hard /mob/living/simple_animal/hostile/megafauna/bubblegum name = "bubblegum" desc = "In what passes for a hierarchy among slaughter demons, this one is king." - threat = 35 health = 2500 maxHealth = 2500 attack_verb_continuous = "rends" diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm index 18abb019d3..883ad39261 100644 --- a/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm +++ b/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm @@ -24,7 +24,6 @@ Difficulty: Very Hard /mob/living/simple_animal/hostile/megafauna/colossus name = "colossus" desc = "A monstrous creature protected by heavy shielding." - threat = 40 health = 2500 maxHealth = 2500 attack_verb_continuous = "judges" @@ -603,7 +602,6 @@ Difficulty: Very Hard icon_state = "lightgeist" icon_living = "lightgeist" icon_dead = "butterfly_dead" - threat = -0.7 turns_per_move = 1 response_help_continuous = "waves away" response_help_simple = "wave away" diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/drake.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/drake.dm index a1ecde40b8..4dfd4561d6 100644 --- a/code/modules/mob/living/simple_animal/hostile/megafauna/drake.dm +++ b/code/modules/mob/living/simple_animal/hostile/megafauna/drake.dm @@ -38,7 +38,6 @@ Difficulty: Medium /mob/living/simple_animal/hostile/megafauna/dragon name = "ash drake" desc = "Guardians of the necropolis." - threat = 30 health = 2500 maxHealth = 2500 spacewalk = TRUE diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/hierophant.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/hierophant.dm index c00d7c3130..525388fa61 100644 --- a/code/modules/mob/living/simple_animal/hostile/megafauna/hierophant.dm +++ b/code/modules/mob/living/simple_animal/hostile/megafauna/hierophant.dm @@ -37,7 +37,6 @@ Difficulty: Normal /mob/living/simple_animal/hostile/megafauna/hierophant name = "hierophant" desc = "A massive metal club that hangs in the air as though waiting. It'll make you dance to its beat." - threat = 30 health = 2500 maxHealth = 2500 attack_verb_continuous = "clubs" diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/legion.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/legion.dm index 78c02fb7a7..795184bad5 100644 --- a/code/modules/mob/living/simple_animal/hostile/megafauna/legion.dm +++ b/code/modules/mob/living/simple_animal/hostile/megafauna/legion.dm @@ -18,7 +18,6 @@ Difficulty: Medium /mob/living/simple_animal/hostile/megafauna/legion name = "Legion" - threat = 30 health = 800 maxHealth = 800 spacewalk = TRUE diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/basilisk.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/basilisk.dm index 13738b20e1..61be1f6287 100644 --- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/basilisk.dm +++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/basilisk.dm @@ -8,7 +8,6 @@ icon_aggro = "Basilisk_alert" icon_dead = "Basilisk_dead" icon_gib = "syndicate_gib" - threat = 4 mob_biotypes = MOB_ORGANIC|MOB_BEAST move_to_delay = 20 projectiletype = /obj/item/projectile/temp/basilisk diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/curse_blob.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/curse_blob.dm index 11cc0fe67e..ed056c2ad9 100644 --- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/curse_blob.dm +++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/curse_blob.dm @@ -10,7 +10,6 @@ move_to_delay = 5 vision_range = 20 aggro_vision_range = 20 - threat = 1 maxHealth = 40 //easy to kill, but oh, will you be seeing a lot of them. health = 40 melee_damage_lower = 10 diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/elite.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/elite.dm index 87ec79abcf..e3edd171c0 100644 --- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/elite.dm +++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/elite.dm @@ -11,7 +11,6 @@ robust_searching = TRUE ranged_ignores_vision = TRUE ranged = TRUE - threat = 5 obj_damage = 5 vision_range = 6 aggro_vision_range = 18 diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/goliath_broodmother.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/goliath_broodmother.dm index 80489e0e40..d9f3cfba3d 100644 --- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/goliath_broodmother.dm +++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/goliath_broodmother.dm @@ -25,7 +25,6 @@ icon_aggro = "broodmother" icon_dead = "egg_sac" icon_gib = "syndicate_gib" - threat = 10 maxHealth = 800 health = 800 melee_damage_lower = 30 diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/herald.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/herald.dm index 78b24acfb0..fce5b636e4 100644 --- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/herald.dm +++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/herald.dm @@ -24,7 +24,6 @@ icon_aggro = "herald" icon_dead = "herald_dying" icon_gib = "syndicate_gib" - threat = 10 maxHealth = 800 health = 800 melee_damage_lower = 20 diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/legionnaire.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/legionnaire.dm index 31f925fb2b..15ed0135fe 100644 --- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/legionnaire.dm +++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/legionnaire.dm @@ -24,7 +24,6 @@ icon_aggro = "legionnaire" icon_dead = "legionnaire_dead" icon_gib = "syndicate_gib" - threat = 10 maxHealth = 800 health = 800 melee_damage_lower = 30 diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/pandora.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/pandora.dm index cdef0c50d3..7995e4d20f 100644 --- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/pandora.dm +++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/pandora.dm @@ -24,7 +24,6 @@ icon_aggro = "pandora" icon_dead = "pandora_dead" icon_gib = "syndicate_gib" - threat = 10 maxHealth = 800 health = 800 melee_damage_lower = 15 diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/goldgrub.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/goldgrub.dm index 4a3497055a..3845c6f406 100644 --- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/goldgrub.dm +++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/goldgrub.dm @@ -8,7 +8,6 @@ icon_aggro = "Goldgrub_alert" icon_dead = "Goldgrub_dead" icon_gib = "syndicate_gib" - threat = 0.2 mob_biotypes = MOB_ORGANIC|MOB_BEAST vision_range = 2 aggro_vision_range = 9 diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/goliath.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/goliath.dm index 5f6c21bbbd..12f0b41d4e 100644 --- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/goliath.dm +++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/goliath.dm @@ -10,7 +10,6 @@ icon_gib = "syndicate_gib" mob_biotypes = MOB_ORGANIC|MOB_BEAST mouse_opacity = MOUSE_OPACITY_OPAQUE - threat = 2 move_to_delay = 10 ranged = 1 ranged_cooldown_time = 60 diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/hivelord.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/hivelord.dm index 16f892bbff..11ce4f9214 100644 --- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/hivelord.dm +++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/hivelord.dm @@ -9,7 +9,6 @@ icon_gib = "syndicate_gib" mob_biotypes = MOB_ORGANIC mouse_opacity = MOUSE_OPACITY_OPAQUE - threat = 4 move_to_delay = 14 ranged = 1 vision_range = 4 @@ -241,7 +240,6 @@ icon_state = "legion" icon_living = "legion" icon_dead = "legion" - threat = 5 health = 450 maxHealth = 450 melee_damage_lower = 20 diff --git a/code/modules/mob/living/simple_animal/hostile/netherworld.dm b/code/modules/mob/living/simple_animal/hostile/netherworld.dm index e21e3e0693..92f331071a 100644 --- a/code/modules/mob/living/simple_animal/hostile/netherworld.dm +++ b/code/modules/mob/living/simple_animal/hostile/netherworld.dm @@ -10,7 +10,6 @@ obj_damage = 100 melee_damage_lower = 25 melee_damage_upper = 50 - threat = 2 attack_verb_continuous = "slashes" attack_verb_simple = "slash" attack_sound = 'sound/weapons/bladeslice.ogg' diff --git a/code/modules/mob/living/simple_animal/hostile/pirate.dm b/code/modules/mob/living/simple_animal/hostile/pirate.dm index 0544ddc676..74e37bea21 100644 --- a/code/modules/mob/living/simple_animal/hostile/pirate.dm +++ b/code/modules/mob/living/simple_animal/hostile/pirate.dm @@ -10,7 +10,6 @@ turns_per_move = 5 response_help_continuous = "pushes" response_help_simple = "push" - threat = 3 speed = 0 maxHealth = 115 health = 115 diff --git a/code/modules/mob/living/simple_animal/hostile/regalrat.dm b/code/modules/mob/living/simple_animal/hostile/regalrat.dm index e21514b37e..77b2d4268a 100644 --- a/code/modules/mob/living/simple_animal/hostile/regalrat.dm +++ b/code/modules/mob/living/simple_animal/hostile/regalrat.dm @@ -184,6 +184,7 @@ /mob/living/simple_animal/hostile/rat/Initialize() . = ..() SSmobs.cheeserats += src + AddComponent(/datum/component/swarming) /mob/living/simple_animal/hostile/rat/Destroy() SSmobs.cheeserats -= src diff --git a/code/modules/mob/living/simple_animal/hostile/russian.dm b/code/modules/mob/living/simple_animal/hostile/russian.dm index f7a46658c4..e9879f38ec 100644 --- a/code/modules/mob/living/simple_animal/hostile/russian.dm +++ b/code/modules/mob/living/simple_animal/hostile/russian.dm @@ -10,7 +10,6 @@ speak_chance = 0 turns_per_move = 5 speed = 0 - threat = 1 maxHealth = 100 health = 100 harm_intent_damage = 5 diff --git a/code/modules/mob/living/simple_animal/hostile/sharks.dm b/code/modules/mob/living/simple_animal/hostile/sharks.dm index 1263a23d26..af61149130 100644 --- a/code/modules/mob/living/simple_animal/hostile/sharks.dm +++ b/code/modules/mob/living/simple_animal/hostile/sharks.dm @@ -19,7 +19,6 @@ response_harm_continuous = "kicks" response_harm_simple = "kick" speed = 0 - threat = 1 maxHealth = 75 health = 75 harm_intent_damage = 18 diff --git a/code/modules/mob/living/simple_animal/hostile/skeleton.dm b/code/modules/mob/living/simple_animal/hostile/skeleton.dm index 3091949552..ebacf1edef 100644 --- a/code/modules/mob/living/simple_animal/hostile/skeleton.dm +++ b/code/modules/mob/living/simple_animal/hostile/skeleton.dm @@ -11,7 +11,6 @@ speak_emote = list("rattles") emote_see = list("rattles") a_intent = INTENT_HARM - threat = 0.5 maxHealth = 40 blood_volume = 0 health = 40 @@ -64,7 +63,6 @@ icon_state = "templar" icon_living = "templar" icon_dead = "templar_dead" - threat = 1.5 maxHealth = 150 health = 150 weather_immunities = list("snow") @@ -98,7 +96,6 @@ icon_state = "plasma_miner" icon_living = "plasma_miner" icon_dead = "plasma_miner" - threat = 2 maxHealth = 150 health = 150 harm_intent_damage = 10 @@ -116,7 +113,6 @@ icon_state = "plasma_miner_tool" icon_living = "plasma_miner_tool" icon_dead = "plasma_miner_tool" - threat = 3 maxHealth = 185 health = 185 harm_intent_damage = 15 diff --git a/code/modules/mob/living/simple_animal/hostile/statue.dm b/code/modules/mob/living/simple_animal/hostile/statue.dm index 3490d757a1..600d60eb4d 100644 --- a/code/modules/mob/living/simple_animal/hostile/statue.dm +++ b/code/modules/mob/living/simple_animal/hostile/statue.dm @@ -10,7 +10,6 @@ gender = NEUTER a_intent = INTENT_HARM mob_biotypes = MOB_HUMANOID - threat = 3 response_help_continuous = "touches" response_help_simple = "touch" response_disarm_continuous = "pushes" diff --git a/code/modules/mob/living/simple_animal/hostile/stickman.dm b/code/modules/mob/living/simple_animal/hostile/stickman.dm index 226af952b1..6eeeabc877 100644 --- a/code/modules/mob/living/simple_animal/hostile/stickman.dm +++ b/code/modules/mob/living/simple_animal/hostile/stickman.dm @@ -5,7 +5,6 @@ icon_living = "stickman" icon_dead = "stickman_dead" icon_gib = "syndicate_gib" - threat = 0.5 mob_biotypes = MOB_HUMANOID gender = MALE speak_chance = 0 diff --git a/code/modules/mob/living/simple_animal/hostile/syndicate.dm b/code/modules/mob/living/simple_animal/hostile/syndicate.dm index fd37bb26aa..103868e1d3 100644 --- a/code/modules/mob/living/simple_animal/hostile/syndicate.dm +++ b/code/modules/mob/living/simple_animal/hostile/syndicate.dm @@ -25,7 +25,6 @@ mob_biotypes = MOB_ORGANIC|MOB_HUMANOID speak_chance = 0 turns_per_move = 5 - threat = 1 speed = 0 stat_attack = UNCONSCIOUS robust_searching = 1 diff --git a/code/modules/mob/living/simple_animal/hostile/tree.dm b/code/modules/mob/living/simple_animal/hostile/tree.dm index 2b9f4eea35..46a5a8ec68 100644 --- a/code/modules/mob/living/simple_animal/hostile/tree.dm +++ b/code/modules/mob/living/simple_animal/hostile/tree.dm @@ -7,7 +7,6 @@ icon_dead = "pine_1" icon_gib = "pine_1" gender = NEUTER - threat = 1 speak_chance = 0 turns_per_move = 5 response_help_continuous = "brushes" diff --git a/code/modules/mob/living/simple_animal/hostile/wizard.dm b/code/modules/mob/living/simple_animal/hostile/wizard.dm index 57fb6f829d..b3523fc42c 100644 --- a/code/modules/mob/living/simple_animal/hostile/wizard.dm +++ b/code/modules/mob/living/simple_animal/hostile/wizard.dm @@ -8,7 +8,6 @@ mob_biotypes = MOB_ORGANIC|MOB_HUMANOID speak_chance = 0 turns_per_move = 3 - threat = 3 speed = 0 maxHealth = 100 health = 100 diff --git a/code/modules/mob/living/simple_animal/hostile/wumborian_fugu.dm b/code/modules/mob/living/simple_animal/hostile/wumborian_fugu.dm index dc6154c05e..bce1a01c8a 100644 --- a/code/modules/mob/living/simple_animal/hostile/wumborian_fugu.dm +++ b/code/modules/mob/living/simple_animal/hostile/wumborian_fugu.dm @@ -11,7 +11,6 @@ mob_biotypes = MOB_ORGANIC|MOB_BEAST mouse_opacity = MOUSE_OPACITY_ICON move_to_delay = 5 - threat = 1 friendly_verb_continuous = "floats near" friendly_verb_simple = "float near" speak_emote = list("puffs") diff --git a/code/modules/mob/living/simple_animal/hostile/zombie.dm b/code/modules/mob/living/simple_animal/hostile/zombie.dm index 6e4cbac022..1217084ce3 100644 --- a/code/modules/mob/living/simple_animal/hostile/zombie.dm +++ b/code/modules/mob/living/simple_animal/hostile/zombie.dm @@ -7,7 +7,6 @@ mob_biotypes = MOB_ORGANIC|MOB_HUMANOID speak_chance = 0 stat_attack = UNCONSCIOUS //braains - threat = 1 maxHealth = 100 health = 100 harm_intent_damage = 5 diff --git a/code/modules/mob/living/simple_animal/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm index 706bcc46f5..be0338a60e 100644 --- a/code/modules/mob/living/simple_animal/simple_animal.dm +++ b/code/modules/mob/living/simple_animal/simple_animal.dm @@ -146,6 +146,8 @@ var/bare_wound_bonus = 0 //If the attacks from this are sharp var/sharpness = SHARP_NONE + //Generic flags + var/simple_mob_flags = NONE /mob/living/simple_animal/Initialize() . = ..() diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index d454f85d1c..358eff7a47 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -649,8 +649,6 @@ GLOBAL_VAR_INIT(exploit_warn_spam_prevention, 0) continue if(overrides.len && (A in overrides)) continue - if(A.IsObscured()) - continue statpanel(listed_turf.name, null, A) if(mind) add_spells_to_statpanel(mind.spell_list) diff --git a/code/modules/modular_computers/NTNet/NTNRC/conversation.dm b/code/modules/modular_computers/NTNet/NTNRC/conversation.dm index eeb5212aeb..b5f3bae53d 100644 --- a/code/modules/modular_computers/NTNet/NTNRC/conversation.dm +++ b/code/modules/modular_computers/NTNet/NTNRC/conversation.dm @@ -73,4 +73,4 @@ add_status_message("[client.username] has changed channel title from [title] to [newtitle]") title = newtitle -#undef MAX_CHANNELS \ No newline at end of file +#undef MAX_CHANNELS diff --git a/code/modules/modular_computers/computers/_modular_computer_shared.dm b/code/modules/modular_computers/computers/_modular_computer_shared.dm new file mode 100644 index 0000000000..8ca93e8347 --- /dev/null +++ b/code/modules/modular_computers/computers/_modular_computer_shared.dm @@ -0,0 +1,64 @@ + +/obj/proc/is_modular_computer() + return + +/obj/proc/get_modular_computer_part(part_type) + return null + +/obj/item/modular_computer/is_modular_computer() + return TRUE + +/obj/item/modular_computer/get_modular_computer_part(part_type) + if(!part_type) + stack_trace("get_modular_computer_part() called without a valid part_type") + return null + return all_components[part_type] + + +/obj/machinery/modular_computer/is_modular_computer() + return TRUE + +/obj/machinery/modular_computer/get_modular_computer_part(part_type) + if(!part_type) + stack_trace("get_modular_computer_part() called without a valid part_type") + return null + return cpu?.all_components[part_type] + + +/obj/proc/get_modular_computer_parts_examine(mob/user) + . = list() + if(!is_modular_computer()) + return + + var/user_is_adjacent = Adjacent(user) //don't reveal full details unless they're close enough to see it on the screen anyway. + + var/obj/item/computer_hardware/ai_slot/ai_slot = get_modular_computer_part(MC_AI) + if(ai_slot) + if(ai_slot.stored_card) + if(user_is_adjacent) + . += "It has a slot installed for an intelliCard which contains: [ai_slot.stored_card.name]" + else + . += "It has a slot installed for an intelliCard, which appears to be occupied." + . += "Alt-click to eject the intelliCard." + else + . += "It has a slot installed for an intelliCard." + + var/obj/item/computer_hardware/card_slot/card_slot = get_modular_computer_part(MC_CARD) + if(card_slot) + if(card_slot.stored_card || card_slot.stored_card2) + var/obj/item/card/id/first_ID = card_slot.stored_card + var/obj/item/card/id/second_ID = card_slot.stored_card2 + var/multiple_cards = istype(first_ID) && istype(second_ID) + if(user_is_adjacent) + . += "It has two slots for identification cards installed[multiple_cards ? " which contain [first_ID] and [second_ID]" : ", one of which contains [first_ID ? first_ID : second_ID]"]." + else + . += "It has two slots for identification cards installed, [multiple_cards ? "both of which appear" : "and one of them appears"] to be occupied." + . += "Alt-click [src] to eject the identification card[multiple_cards ? "s":""]." + else + . += "It has two slots installed for identification cards." + + var/obj/item/computer_hardware/printer/printer_slot = get_modular_computer_part(MC_PRINT) + if(printer_slot) + . += "It has a printer installed." + if(user_is_adjacent) + . += "The printer's paper levels are at: [printer_slot.stored_paper]/[printer_slot.max_paper].
]" diff --git a/code/modules/modular_computers/computers/item/computer.dm b/code/modules/modular_computers/computers/item/computer.dm index d722197bd9..67c04de13f 100644 --- a/code/modules/modular_computers/computers/item/computer.dm +++ b/code/modules/modular_computers/computers/item/computer.dm @@ -7,6 +7,7 @@ var/enabled = 0 // Whether the computer is turned on. var/screen_on = 1 // Whether the computer is active/opened/it's screen is on. + var/device_theme = "ntos" // Sets the theme for the main menu, hardware config, and file browser apps. Overridden by certain non-NT devices. var/datum/computer_file/program/active_program = null // A currently active program running on the computer. var/hardware_flag = 0 // A flag that describes this device type var/last_power_usage = 0 @@ -98,7 +99,7 @@ if(issilicon(usr)) return var/obj/item/computer_hardware/card_slot/card_slot = all_components[MC_CARD] - if(usr.canUseTopic(src)) + if(usr.canUseTopic(src, BE_CLOSE)) card_slot.try_eject(null, usr) // Eject ID card from computer, if it has ID slot with card inside. @@ -109,7 +110,7 @@ if(issilicon(usr)) return var/obj/item/computer_hardware/ai_slot/ai_slot = all_components[MC_AI] - if(usr.canUseTopic(src)) + if(usr.canUseTopic(src, BE_CLOSE)) ai_slot.try_eject(null, usr,1) @@ -121,17 +122,17 @@ if(issilicon(usr)) return - if(usr.canUseTopic(src)) + if(usr.canUseTopic(src, BE_CLOSE)) var/obj/item/computer_hardware/hard_drive/portable/portable_drive = all_components[MC_SDD] if(uninstall_component(portable_drive, usr)) portable_drive.verb_pickup() /obj/item/modular_computer/AltClick(mob/user) - . = ..() + ..() if(issilicon(user)) return - if(user.canUseTopic(src)) + if(user.canUseTopic(src, BE_CLOSE)) var/obj/item/computer_hardware/card_slot/card_slot = all_components[MC_CARD] var/obj/item/computer_hardware/ai_slot/ai_slot = all_components[MC_AI] var/obj/item/computer_hardware/hard_drive/portable/portable_drive = all_components[MC_SDD] @@ -143,7 +144,7 @@ return if(ai_slot) ai_slot.try_eject(null, user) - return TRUE + // Gets IDs/access levels from card slot. Would be useful when/if PDAs would become modular PCs. /obj/item/modular_computer/GetAccess() @@ -175,7 +176,7 @@ /obj/item/modular_computer/MouseDrop(obj/over_object, src_location, over_location) var/mob/M = usr - if((!istype(over_object, /obj/screen)) && usr.canUseTopic(src)) + if((!istype(over_object, /obj/screen)) && usr.canUseTopic(src, BE_CLOSE)) return attack_self(M) return ..() @@ -195,12 +196,22 @@ /obj/item/modular_computer/emag_act(mob/user) . = ..() - if(obj_flags & EMAGGED) - to_chat(user, "\The [src] was already emagged.") - return - obj_flags |= EMAGGED - to_chat(user, "You emag \the [src]. It's screen briefly shows a \"OVERRIDE ACCEPTED: New software downloads available.\" message.") - return TRUE + if(!enabled) + to_chat(user, "You'd need to turn the [src] on first.") + return FALSE + obj_flags |= EMAGGED //Mostly for consistancy purposes; the programs will do their own emag handling + var/newemag = FALSE + var/obj/item/computer_hardware/hard_drive/drive = all_components[MC_HDD] + for(var/datum/computer_file/program/app in drive.stored_files) + if(!istype(app)) + continue + if(app.run_emag()) + newemag = TRUE + if(newemag) + to_chat(user, "You swipe \the [src]. A console window momentarily fills the screen, with white text rapidly scrolling past.") + return TRUE + to_chat(user, "You swipe \the [src]. A console window fills the screen, but it quickly closes itself after only a few lines are written to it.") + return FALSE /obj/item/modular_computer/examine(mob/user) . = ..() @@ -209,13 +220,14 @@ else if(obj_integrity < max_integrity) . += "It is damaged." + . += get_modular_computer_parts_examine(user) + /obj/item/modular_computer/update_icon_state() if(!enabled) icon_state = icon_state_unpowered else icon_state = icon_state_powered - /obj/item/modular_computer/update_overlays() . = ..() if(!display_overlays) @@ -306,6 +318,8 @@ /obj/item/modular_computer/proc/get_header_data() var/list/data = list() + data["PC_device_theme"] = device_theme + var/obj/item/computer_hardware/battery/battery_module = all_components[MC_CELL] var/obj/item/computer_hardware/recharger/recharger = all_components[MC_CHARGE] @@ -407,17 +421,17 @@ if(install_component(W, user)) return - if(istype(W, /obj/item/wrench)) + if(W.tool_behaviour == TOOL_WRENCH) if(all_components.len) to_chat(user, "Remove all components from \the [src] before disassembling it.") return new /obj/item/stack/sheet/metal( get_turf(src.loc), steel_sheet_cost ) - physical.visible_message("\The [src] has been disassembled by [user].") + physical.visible_message("\The [src] is disassembled by [user].") relay_qdel() qdel(src) return - if(istype(W, /obj/item/weldingtool)) + if(W.tool_behaviour == TOOL_WELDER) if(obj_integrity == max_integrity) to_chat(user, "\The [src] does not require repairs.") return @@ -431,7 +445,7 @@ to_chat(user, "You repair \the [src].") return - if(istype(W, /obj/item/screwdriver)) + if(W.tool_behaviour == TOOL_SCREWDRIVER) if(!all_components.len) to_chat(user, "This device doesn't have any components installed.") return @@ -440,7 +454,7 @@ var/obj/item/computer_hardware/H = all_components[h] component_names.Add(H.name) - var/choice = input(user, "Which component do you want to uninstall?", "Computer maintenance", null) as null|anything in component_names + var/choice = input(user, "Which component do you want to uninstall?", "Computer maintenance", null) as null|anything in sortList(component_names) if(!choice) return diff --git a/code/modules/modular_computers/computers/item/computer_damage.dm b/code/modules/modular_computers/computers/item/computer_damage.dm index 6664b449bd..b510f8aded 100644 --- a/code/modules/modular_computers/computers/item/computer_damage.dm +++ b/code/modules/modular_computers/computers/item/computer_damage.dm @@ -18,13 +18,13 @@ /obj/item/modular_computer/proc/break_apart() if(!(flags_1 & NODECONSTRUCT_1)) - physical.visible_message("\The [src] breaks apart!") + physical.visible_message("\The [src] breaks apart!") var/turf/newloc = get_turf(src) new /obj/item/stack/sheet/metal(newloc, round(steel_sheet_cost/2)) for(var/C in all_components) var/obj/item/computer_hardware/H = all_components[C] if(QDELETED(H)) - return + continue uninstall_component(H) H.forceMove(newloc) if(prob(25)) diff --git a/code/modules/modular_computers/computers/item/computer_power.dm b/code/modules/modular_computers/computers/item/computer_power.dm index d3c65f86ec..b5188f43d9 100644 --- a/code/modules/modular_computers/computers/item/computer_power.dm +++ b/code/modules/modular_computers/computers/item/computer_power.dm @@ -28,8 +28,7 @@ /obj/item/modular_computer/get_cell() var/obj/item/computer_hardware/battery/battery_module = all_components[MC_CELL] - if(battery_module && battery_module.battery) - return battery_module.battery + return battery_module?.get_cell() // Used in following function to reduce copypaste /obj/item/modular_computer/proc/power_failure() diff --git a/code/modules/modular_computers/computers/item/computer_ui.dm b/code/modules/modular_computers/computers/item/computer_ui.dm index 6266daad2b..fd017e2b0f 100644 --- a/code/modules/modular_computers/computers/item/computer_ui.dm +++ b/code/modules/modular_computers/computers/item/computer_ui.dm @@ -3,7 +3,7 @@ ui_interact(user) // Operates TGUI -/obj/item/modular_computer/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) +/obj/item/modular_computer/ui_interact(mob/user, datum/tgui/ui) if(!enabled) if(ui) ui.close() @@ -14,7 +14,7 @@ return 0 // Robots don't really need to see the screen, their wireless connection works as long as computer is on. - if(!screen_on && !hasSiliconAccessInArea(user)) + if(!screen_on && !issilicon(user)) if(ui) ui.close() return 0 @@ -33,19 +33,17 @@ to_chat(user, "\The [src] beeps three times, it's screen displaying a \"DISK ERROR\" warning.") return // No HDD, No HDD files list or no stored files. Something is very broken. - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) + ui = SStgui.try_update_ui(user, src, ui) if (!ui) - var/datum/asset/assets = get_asset_datum(/datum/asset/simple/headers) - assets.send(user) - assets = get_asset_datum(/datum/asset/simple/arcade) - assets.send(user) - ui = new(user, src, ui_key, "NtosMain", "NtOS Main menu", 400, 500, master_ui, state) + ui = new(user, src, "NtosMain") + ui.set_autoupdate(TRUE) ui.open() - ui.set_autoupdate(state = 1) + ui.send_asset(get_asset_datum(/datum/asset/simple/headers)) /obj/item/modular_computer/ui_data(mob/user) var/list/data = get_header_data() + data["device_theme"] = device_theme data["programs"] = list() var/obj/item/computer_hardware/hard_drive/hard_drive = all_components[MC_HDD] for(var/datum/computer_file/program/P in hard_drive.stored_files) @@ -143,6 +141,7 @@ set_light(comp_light_luminosity, 1, comp_light_color) else set_light(0) + return TRUE if("PC_light_color") var/mob/user = usr diff --git a/code/modules/modular_computers/computers/item/laptop.dm b/code/modules/modular_computers/computers/item/laptop.dm index 4781cbd8bc..5927d57a0b 100644 --- a/code/modules/modular_computers/computers/item/laptop.dm +++ b/code/modules/modular_computers/computers/item/laptop.dm @@ -7,6 +7,7 @@ icon_state_powered = "laptop" icon_state_unpowered = "laptop-off" icon_state_menu = "menu" + display_overlays = FALSE hardware_flag = PROGRAM_LAPTOP max_hardware_size = 2 @@ -18,8 +19,8 @@ screen_on = 0 // Starts closed var/start_open = TRUE // unless this var is set to 1 var/icon_state_closed = "laptop-closed" - display_overlays = FALSE var/w_class_open = WEIGHT_CLASS_BULKY + var/slowdown_open = TRUE /obj/item/modular_computer/laptop/examine(mob/user) . = ..() @@ -38,6 +39,13 @@ else . = ..() +/obj/item/modular_computer/laptop/update_overlays() + if(screen_on) + return ..() + else + cut_overlays() + icon_state = icon_state_closed + /obj/item/modular_computer/laptop/attack_self(mob/user) if(!screen_on) try_toggle_open(user) @@ -65,6 +73,7 @@ M.put_in_hand(src, H.held_index) /obj/item/modular_computer/laptop/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) + . = ..() if(screen_on && isturf(loc)) return attack_self(user) @@ -73,7 +82,7 @@ return if(!isturf(loc) && !ismob(loc)) // No opening it in backpack. return - if(!user.canUseTopic(src)) + if(!user.canUseTopic(src, BE_CLOSE)) return toggle_open(user) @@ -82,15 +91,17 @@ /obj/item/modular_computer/laptop/AltClick(mob/user) if(screen_on) // Close it. try_toggle_open(user) - return TRUE - return ..() + else + return ..() /obj/item/modular_computer/laptop/proc/toggle_open(mob/living/user=null) if(screen_on) to_chat(user, "You close \the [src].") + slowdown = initial(slowdown) w_class = initial(w_class) else to_chat(user, "You open \the [src].") + slowdown = slowdown_open w_class = w_class_open screen_on = !screen_on diff --git a/code/modules/modular_computers/computers/item/laptop_presets.dm b/code/modules/modular_computers/computers/item/laptop_presets.dm index e50392e3b3..6bc2919bea 100644 --- a/code/modules/modular_computers/computers/item/laptop_presets.dm +++ b/code/modules/modular_computers/computers/item/laptop_presets.dm @@ -20,4 +20,3 @@ /obj/item/modular_computer/laptop/preset/civilian/install_programs() var/obj/item/computer_hardware/hard_drive/hard_drive = all_components[MC_HDD] hard_drive.store_file(new/datum/computer_file/program/chatclient()) - hard_drive.store_file(new/datum/computer_file/program/nttransfer()) diff --git a/code/modules/modular_computers/computers/item/processor.dm b/code/modules/modular_computers/computers/item/processor.dm index 81e2cb95e6..c79d7a9361 100644 --- a/code/modules/modular_computers/computers/item/processor.dm +++ b/code/modules/modular_computers/computers/item/processor.dm @@ -1,4 +1,5 @@ // Held by /obj/machinery/modular_computer to reduce amount of copy-pasted code. +//TODO: REFACTOR THIS SPAGHETTI CODE, MAKE IT A COMPUTER_HARDWARE COMPONENT OR REMOVE IT /obj/item/modular_computer/processor name = "processing unit" desc = "You shouldn't see this. If you do, report it." @@ -11,19 +12,22 @@ var/obj/machinery/modular_computer/machinery_computer = null /obj/item/modular_computer/processor/Destroy() - . = ..() if(machinery_computer && (machinery_computer.cpu == src)) machinery_computer.cpu = null + machinery_computer.UnregisterSignal(src, COMSIG_ATOM_UPDATED_ICON) machinery_computer = null - -/obj/item/modular_computer/processor/Initialize(mapload) . = ..() - if(!loc || !istype(loc, /obj/machinery/modular_computer)) + +/obj/item/modular_computer/processor/New(comp) //intentional new probably + ..() + STOP_PROCESSING(SSobj, src) // Processed by its machine + + if(!comp || !istype(comp, /obj/machinery/modular_computer)) CRASH("Inapropriate type passed to obj/item/modular_computer/processor/New()! Aborting.") // Obtain reference to machinery computer all_components = list() idle_threads = list() - machinery_computer = loc + machinery_computer = comp machinery_computer.cpu = src hardware_flag = machinery_computer.hardware_flag max_hardware_size = machinery_computer.max_hardware_size @@ -39,7 +43,7 @@ qdel(machinery_computer) // This thing is not meant to be used on it's own, get topic data from our machinery owner. -//obj/item/modular_computer/processor/canUseTopic(atom/movable/M, be_close=FALSE, no_dextery=FALSE, no_tk=FALSE) +//obj/item/modular_computer/processor/canUseTopic(atom/movable/M, be_close=FALSE, no_dexterity=FALSE, no_tk=FALSE) // if(!machinery_computer) // return 0 @@ -69,3 +73,6 @@ machinery_computer.verbs -= /obj/machinery/modular_computer/proc/eject_disk if(MC_AI) machinery_computer.verbs -= /obj/machinery/modular_computer/proc/eject_card + +/obj/item/modular_computer/processor/attack_ghost(mob/user) + ui_interact(user) diff --git a/code/modules/modular_computers/computers/item/tablet.dm b/code/modules/modular_computers/computers/item/tablet.dm index a371e97ec6..41a256467f 100644 --- a/code/modules/modular_computers/computers/item/tablet.dm +++ b/code/modules/modular_computers/computers/item/tablet.dm @@ -5,6 +5,7 @@ icon_state_unpowered = "tablet" icon_state_powered = "tablet" icon_state_menu = "menu" + //worn_icon_state = "tablet" hardware_flag = PROGRAM_TABLET max_hardware_size = 1 w_class = WEIGHT_CLASS_SMALL @@ -32,3 +33,17 @@ slot_flags = ITEM_SLOT_ID | ITEM_SLOT_BELT comp_light_luminosity = 6.3 has_variants = FALSE + +/// Given to Nuke Ops members. +/obj/item/modular_computer/tablet/nukeops + icon_state = "tablet-syndicate" + comp_light_luminosity = 6.3 + has_variants = FALSE + device_theme = "syndicate" + +/obj/item/modular_computer/tablet/nukeops/emag_act(mob/user) + if(!enabled) + to_chat(user, "You'd need to turn the [src] on first.") + return FALSE + to_chat(user, "You swipe \the [src]. It's screen briefly shows a message reading \"MEMORY CODE INJECTION DETECTED AND SUCCESSFULLY QUARANTINED\".") + return FALSE diff --git a/code/modules/modular_computers/computers/item/tablet_presets.dm b/code/modules/modular_computers/computers/item/tablet_presets.dm index f516d3802f..7cca8ea5b4 100644 --- a/code/modules/modular_computers/computers/item/tablet_presets.dm +++ b/code/modules/modular_computers/computers/item/tablet_presets.dm @@ -22,23 +22,38 @@ /obj/item/modular_computer/tablet/preset/cargo/Initialize() . = ..() + var/obj/item/computer_hardware/hard_drive/small/hard_drive = new install_component(new /obj/item/computer_hardware/processor_unit/small) install_component(new /obj/item/computer_hardware/battery(src, /obj/item/stock_parts/cell/computer)) - install_component(new /obj/item/computer_hardware/hard_drive/small) + install_component(hard_drive) install_component(new /obj/item/computer_hardware/network_card) install_component(new /obj/item/computer_hardware/printer/mini) + hard_drive.store_file(new /datum/computer_file/program/bounty) + //hard_drive.store_file(new /datum/computer_file/program/shipping) -/obj/item/modular_computer/tablet/syndicate_contract_uplink/preset/uplink/Initialize() // Given by the syndicate as part of the contract uplink bundle - loads in the Contractor Uplink. +/// Given by the syndicate as part of the contract uplink bundle - loads in the Contractor Uplink. +/obj/item/modular_computer/tablet/syndicate_contract_uplink/preset/uplink/Initialize() . = ..() var/obj/item/computer_hardware/hard_drive/small/syndicate/hard_drive = new var/datum/computer_file/program/contract_uplink/uplink = new + active_program = uplink uplink.program_state = PROGRAM_STATE_ACTIVE uplink.computer = src + hard_drive.store_file(uplink) + install_component(new /obj/item/computer_hardware/processor_unit/small) install_component(new /obj/item/computer_hardware/battery(src, /obj/item/stock_parts/cell/computer)) install_component(hard_drive) install_component(new /obj/item/computer_hardware/network_card) install_component(new /obj/item/computer_hardware/card_slot) - install_component(new /obj/item/computer_hardware/printer/mini) \ No newline at end of file + install_component(new /obj/item/computer_hardware/printer/mini) + +/// Given to Nuke Ops members. +/obj/item/modular_computer/tablet/nukeops/Initialize() + . = ..() + install_component(new /obj/item/computer_hardware/processor_unit/small) + install_component(new /obj/item/computer_hardware/battery(src, /obj/item/stock_parts/cell/computer)) + install_component(new /obj/item/computer_hardware/hard_drive/small/nukeops) + install_component(new /obj/item/computer_hardware/network_card) diff --git a/code/modules/modular_computers/computers/machinery/console_presets.dm b/code/modules/modular_computers/computers/machinery/console_presets.dm index 066f1fb98b..9d29b23e76 100644 --- a/code/modules/modular_computers/computers/machinery/console_presets.dm +++ b/code/modules/modular_computers/computers/machinery/console_presets.dm @@ -46,16 +46,12 @@ desc = "A stationary computer. This one comes preloaded with research programs." _has_ai = TRUE -/obj/machinery/modular_computer/console/preset/research/examine(mob/user) - . = ..() - . += "Alt-click to eject the intelliCard." - /obj/machinery/modular_computer/console/preset/research/install_programs() var/obj/item/computer_hardware/hard_drive/hard_drive = cpu.all_components[MC_HDD] hard_drive.store_file(new/datum/computer_file/program/ntnetmonitor()) - hard_drive.store_file(new/datum/computer_file/program/nttransfer()) hard_drive.store_file(new/datum/computer_file/program/chatclient()) hard_drive.store_file(new/datum/computer_file/program/aidiag()) + hard_drive.store_file(new/datum/computer_file/program/robocontrol()) // ===== COMMAND CONSOLE ===== @@ -66,15 +62,27 @@ _has_id_slot = TRUE _has_printer = TRUE -/obj/machinery/modular_computer/console/preset/command/examine(mob/user) - . = ..() - . += "Alt-click [src] to eject the identification card." - /obj/machinery/modular_computer/console/preset/command/install_programs() var/obj/item/computer_hardware/hard_drive/hard_drive = cpu.all_components[MC_HDD] hard_drive.store_file(new/datum/computer_file/program/chatclient()) hard_drive.store_file(new/datum/computer_file/program/card_mod()) + +// ===== IDENTIFICATION CONSOLE ===== +/obj/machinery/modular_computer/console/preset/id + console_department = "Identification" + name = "identification console" + desc = "A stationary computer. This one comes preloaded with identification modification programs." + _has_id_slot = TRUE + _has_printer = TRUE + +/obj/machinery/modular_computer/console/preset/id/install_programs() + var/obj/item/computer_hardware/hard_drive/hard_drive = cpu.all_components[MC_HDD] + hard_drive.store_file(new/datum/computer_file/program/chatclient()) + hard_drive.store_file(new/datum/computer_file/program/card_mod()) + hard_drive.store_file(new/datum/computer_file/program/job_management()) + hard_drive.store_file(new/datum/computer_file/program/crew_manifest()) + // ===== CIVILIAN CONSOLE ===== /obj/machinery/modular_computer/console/preset/civilian console_department = "Civilian" @@ -84,5 +92,4 @@ /obj/machinery/modular_computer/console/preset/civilian/install_programs() var/obj/item/computer_hardware/hard_drive/hard_drive = cpu.all_components[MC_HDD] hard_drive.store_file(new/datum/computer_file/program/chatclient()) - hard_drive.store_file(new/datum/computer_file/program/nttransfer()) hard_drive.store_file(new/datum/computer_file/program/arcade()) diff --git a/code/modules/modular_computers/computers/machinery/modular_computer.dm b/code/modules/modular_computers/computers/machinery/modular_computer.dm index 7e384c3ddd..6f016ad147 100644 --- a/code/modules/modular_computers/computers/machinery/modular_computer.dm +++ b/code/modules/modular_computers/computers/machinery/modular_computer.dm @@ -36,6 +36,10 @@ QDEL_NULL(cpu) return ..() +/obj/machinery/modular_computer/examine(mob/user) + . = ..() + . += get_modular_computer_parts_examine(user) + /obj/machinery/modular_computer/attack_ghost(mob/dead/observer/user) . = ..() if(.) @@ -45,31 +49,31 @@ /obj/machinery/modular_computer/emag_act(mob/user) . = ..() - if(cpu) - . |= cpu.emag_act(user) + if(!cpu) + to_chat(user, "You'd need to turn the [src] on first.") + return FALSE + return (cpu.emag_act(user)) -/obj/machinery/modular_computer/update_icon_state() - if(cpu?.enabled) - icon_state = icon_state_powered - else if(stat & NOPOWER || !(cpu?.use_power())) - icon_state = icon_state_unpowered +/obj/machinery/modular_computer/update_icon() + cut_overlays() + icon_state = icon_state_powered -/obj/machinery/modular_computer/update_overlays() - . = ..() if(!cpu || !cpu.enabled) if (!(stat & NOPOWER) && (cpu && cpu.use_power())) - . += screen_icon_screensaver + add_overlay(screen_icon_screensaver) + else + icon_state = icon_state_unpowered set_light(0) else set_light(light_strength) if(cpu.active_program) - . += cpu.active_program.program_icon_state ? cpu.active_program.program_icon_state : screen_icon_state_menu + add_overlay(cpu.active_program.program_icon_state ? cpu.active_program.program_icon_state : screen_icon_state_menu) else - . += screen_icon_state_menu + add_overlay(screen_icon_state_menu) if(cpu && cpu.obj_integrity <= cpu.integrity_failure * cpu.max_integrity) - . += "bsod" - . += "broken" + add_overlay("bsod") + add_overlay("broken") // Eject ID card from computer, if it has ID slot with card inside. /obj/machinery/modular_computer/proc/eject_id() @@ -96,10 +100,10 @@ cpu.eject_card() /obj/machinery/modular_computer/AltClick(mob/user) - . = ..() if(cpu) - return cpu.AltClick(user) + cpu.AltClick(user) +//ATTACK HAND IGNORING PARENT RETURN VALUE // On-click handling. Turns on the computer if it's off and opens the GUI. /obj/machinery/modular_computer/interact(mob/user) if(cpu) @@ -130,8 +134,7 @@ stat &= ~NOPOWER update_icon() return - ..() - update_icon() + . = ..() /obj/machinery/modular_computer/attackby(var/obj/item/W as obj, mob/user) if(cpu && !(flags_1 & NODECONSTRUCT_1)) @@ -144,6 +147,13 @@ /obj/machinery/modular_computer/ex_act(severity) if(cpu) cpu.ex_act(severity) + // switch(severity) + // if(EXPLODE_DEVASTATE) + // SSexplosions.highobj += cpu + // if(EXPLODE_HEAVY) + // SSexplosions.medobj += cpu + // if(EXPLODE_LIGHT) + // SSexplosions.lowobj += cpu ..() // EMPs are similar to explosions, but don't cause physical damage to the casing. Instead they screw up the components diff --git a/code/modules/modular_computers/computers/machinery/modular_console.dm b/code/modules/modular_computers/computers/machinery/modular_console.dm index 3d4ec22e89..5d596f98e4 100644 --- a/code/modules/modular_computers/computers/machinery/modular_console.dm +++ b/code/modules/modular_computers/computers/machinery/modular_console.dm @@ -52,4 +52,4 @@ network_card.identification_string = "Unknown Console" if(cpu) cpu.screen_on = 1 - update_icon() \ No newline at end of file + update_icon() diff --git a/code/modules/modular_computers/documentation.md b/code/modules/modular_computers/documentation.md index 246da7c3d9..88d059da7a 100644 --- a/code/modules/modular_computers/documentation.md +++ b/code/modules/modular_computers/documentation.md @@ -1,5 +1,7 @@ # Modular computer programs +How module computer programs work + Ok. so a quick rundown on how to make a program. This is kind of a shitty documentation, but oh well I was asked to. ## Base setup diff --git a/code/modules/modular_computers/file_system/computer_file.dm b/code/modules/modular_computers/file_system/computer_file.dm index 7776fc04d0..4e862c4ae3 100644 --- a/code/modules/modular_computers/file_system/computer_file.dm +++ b/code/modules/modular_computers/file_system/computer_file.dm @@ -3,8 +3,8 @@ var/filetype = "XXX" // File full names are [filename].[filetype] so like NewFile.XXX in this case var/size = 1 // File size in GQ. Integers only! var/obj/item/computer_hardware/hard_drive/holder // Holder that contains this file. - var/unsendable = 0 // Whether the file may be sent to someone via NTNet transfer or other means. - var/undeletable = 0 // Whether the file may be deleted. Setting to 1 prevents deletion/renaming/etc. + var/unsendable = FALSE // Whether the file may be sent to someone via NTNet transfer or other means. + var/undeletable = FALSE // Whether the file may be deleted. Setting to TRUE prevents deletion/renaming/etc. var/uid // UID of this file var/static/file_uid = 0 @@ -24,7 +24,7 @@ return ..() // Returns independent copy of this file. -/datum/computer_file/proc/clone(rename = 0) +/datum/computer_file/proc/clone(rename = FALSE) var/datum/computer_file/temp = new type temp.unsendable = unsendable temp.undeletable = undeletable @@ -34,4 +34,4 @@ else temp.filename = filename temp.filetype = filetype - return temp \ No newline at end of file + return temp diff --git a/code/modules/modular_computers/file_system/program.dm b/code/modules/modular_computers/file_system/program.dm index 6b5390fc60..12e5ef6e95 100644 --- a/code/modules/modular_computers/file_system/program.dm +++ b/code/modules/modular_computers/file_system/program.dm @@ -31,15 +31,10 @@ var/available_on_ntnet = 1 /// Whether the program can be downloaded from SyndiNet (accessible via emagging the computer). Set to 1 to enable. var/available_on_syndinet = 0 - /// ID of TGUI interface + /// Name of the tgui interface var/tgui_id - /// Default size of TGUI window, in pixels - var/ui_x = 575 - var/ui_y = 700 /// Example: "something.gif" - a header image that will be rendered in computer's UI when this program is running at background. Images are taken from /icons/program_icons. Be careful not to use too large images! var/ui_header = null - ///Assets specific to programs - var/list/special_assets = list() /datum/computer_file/program/New(obj/item/modular_computer/comp = null) ..() @@ -69,23 +64,23 @@ /datum/computer_file/program/proc/generate_network_log(text) if(computer) return computer.add_log(text) - return FALSE + return 0 /datum/computer_file/program/proc/is_supported_by_hardware(hardware_flag = 0, loud = 0, mob/user = null) if(!(hardware_flag & usage_flags)) if(loud && computer && user) - to_chat(user, "\The [computer] flashes an \"Hardware Error - Incompatible software\" warning.") - return FALSE - return TRUE + to_chat(user, "\The [computer] flashes a \"Hardware Error - Incompatible software\" warning.") + return 0 + return 1 /datum/computer_file/program/proc/get_signal(specific_action = 0) if(computer) return computer.get_ntnet_status(specific_action) - return FALSE + return 0 // Called by Process() on device that runs us, once every tick. /datum/computer_file/program/proc/process_tick() - return TRUE + return 1 // Check if the user can run program. Only humans can operate computer. Automatically called in run_program() // User has to wear their ID for ID Scan to work. @@ -131,7 +126,7 @@ return TRUE if(loud) to_chat(user, "\The [computer] flashes an \"Access Denied\" warning.") - return FALSE + return 0 // This attempts to retrieve header data for UIs. If implementing completely new device of different type than existing ones // always include the device here in this proc. This proc basically relays the request to whatever is running the program. @@ -143,11 +138,25 @@ // This is performed on program startup. May be overridden to add extra logic. Remember to include ..() call. Return 1 on success, 0 on failure. // When implementing new program based device, use this to run the program. /datum/computer_file/program/proc/run_program(mob/living/user) - if(can_run(user, TRUE)) + if(can_run(user, 1)) if(requires_ntnet && network_destination) generate_network_log("Connection opened to [network_destination].") program_state = PROGRAM_STATE_ACTIVE - return TRUE + return 1 + return 0 + +/** + * + *Called by the device when it is emagged. + * + *Emagging the device allows certain programs to unlock new functions. However, the program will + *need to be downloaded first, and then handle the unlock on their own in their run_emag() proc. + *The device will allow an emag to be run multiple times, so the user can re-emag to run the + *override again, should they download something new. The run_emag() proc should return TRUE if + *the emagging affected anything, and FALSE if no change was made (already emagged, or has no + *emag functions). +**/ +/datum/computer_file/program/proc/run_emag() return FALSE // Use this proc to kill the program. Designed to be implemented by each program if it requires on-quit logic, such as the NTNRC client. @@ -155,20 +164,14 @@ program_state = PROGRAM_STATE_KILLED if(network_destination) generate_network_log("Connection to [network_destination] closed.") - return TRUE + return 1 - -/datum/computer_file/program/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) +/datum/computer_file/program/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) if(!ui && tgui_id) - var/datum/asset/assets = get_asset_datum(/datum/asset/simple/headers) - assets.send(user) - for(var/i in special_assets) - assets = get_asset_datum(i) - assets.send(user) - - ui = new(user, src, ui_key, tgui_id, filedesc, ui_x, ui_y, state = state) + ui = new(user, src, tgui_id, filedesc) ui.open() + ui.send_asset(get_asset_datum(/datum/asset/simple/headers)) // CONVENTIONS, READ THIS WHEN CREATING NEW PROGRAM AND OVERRIDING THIS PROC: // Topic calls are automagically forwarded from NanoModule this program contains. @@ -177,17 +180,17 @@ // ALWAYS INCLUDE PARENT CALL ..() OR DIE IN FIRE. /datum/computer_file/program/ui_act(action,list/params,datum/tgui/ui) if(..()) - return TRUE + return 1 if(computer) switch(action) if("PC_exit") computer.kill_program() ui.close() - return TRUE + return 1 if("PC_shutdown") computer.shutdown_computer() ui.close() - return TRUE + return 1 if("PC_minimize") var/mob/user = usr if(!computer.active_program || !computer.all_components[MC_CPU]) diff --git a/code/modules/modular_computers/file_system/program_events.dm b/code/modules/modular_computers/file_system/program_events.dm index 279d646cfd..3c1daa5af3 100644 --- a/code/modules/modular_computers/file_system/program_events.dm +++ b/code/modules/modular_computers/file_system/program_events.dm @@ -13,6 +13,6 @@ /datum/computer_file/program/proc/event_networkfailure(background) kill_program(forced = TRUE) if(background) - computer.visible_message("\The [computer]'s screen displays an \"Process [filename].[filetype] (PID [rand(100,999)]) terminated - Network Error\" error") + computer.visible_message("\The [computer]'s screen displays a \"Process [filename].[filetype] (PID [rand(100,999)]) terminated - Network Error\" error") else computer.visible_message("\The [computer]'s screen briefly freezes and then shows \"NETWORK ERROR - NTNet connection lost. Please retry. If problem persists contact your system administrator.\" error.") diff --git a/code/modules/modular_computers/file_system/programs/airestorer.dm b/code/modules/modular_computers/file_system/programs/airestorer.dm index 4e9cd85577..364ad79737 100644 --- a/code/modules/modular_computers/file_system/programs/airestorer.dm +++ b/code/modules/modular_computers/file_system/programs/airestorer.dm @@ -9,8 +9,6 @@ transfer_access = ACCESS_HEADS available_on_ntnet = TRUE tgui_id = "NtosAiRestorer" - ui_x = 370 - ui_y = 400 /// Variable dictating if we are in the process of restoring the AI in the inserted intellicard var/restoring = FALSE @@ -74,8 +72,8 @@ restoring = FALSE return ai_slot.locked =TRUE - A.adjustOxyLoss(-5, 0) - A.adjustFireLoss(-5, 0) + A.adjustOxyLoss(-5, 0)//, FALSE) + A.adjustFireLoss(-5, 0)//, FALSE) A.adjustToxLoss(-5, 0) A.adjustBruteLoss(-5, 0) A.updatehealth() @@ -113,7 +111,7 @@ data["restoring"] = restoring data["health"] = (AI.health + 100) / 2 data["isDead"] = AI.stat == DEAD - data["laws"] = AI.laws.get_law_list(include_zeroth = 1) + data["laws"] = AI.laws.get_law_list(include_zeroth = TRUE, render_html = FALSE) return data diff --git a/code/modules/modular_computers/file_system/programs/alarm.dm b/code/modules/modular_computers/file_system/programs/alarm.dm index 34daeff6ca..577fad83d0 100644 --- a/code/modules/modular_computers/file_system/programs/alarm.dm +++ b/code/modules/modular_computers/file_system/programs/alarm.dm @@ -8,9 +8,6 @@ network_destination = "alarm monitoring network" size = 5 tgui_id = "NtosStationAlertConsole" - ui_x = 315 - ui_y = 500 - var/has_alert = 0 var/alarms = list("Fire" = list(), "Atmosphere" = list(), "Power" = list()) diff --git a/code/modules/modular_computers/file_system/programs/antagonist/contract_uplink.dm b/code/modules/modular_computers/file_system/programs/antagonist/contract_uplink.dm index cf842f086f..3accb8e02d 100644 --- a/code/modules/modular_computers/file_system/programs/antagonist/contract_uplink.dm +++ b/code/modules/modular_computers/file_system/programs/antagonist/contract_uplink.dm @@ -1,6 +1,6 @@ /datum/computer_file/program/contract_uplink filename = "contractor uplink" - filedesc = "Syndicate Contract Uplink" + filedesc = "Syndicate Contractor Uplink" program_icon_state = "assign" extended_desc = "A standard, Syndicate issued system for handling important contracts while on the field." size = 10 @@ -9,8 +9,6 @@ unsendable = 1 undeletable = 1 tgui_id = "SyndContractor" - ui_x = 500 - ui_y = 600 var/error = "" var/info_screen = TRUE var/assigned = FALSE @@ -22,14 +20,18 @@ /datum/computer_file/program/contract_uplink/ui_act(action, params) if(..()) return TRUE + var/mob/living/user = usr var/obj/item/computer_hardware/hard_drive/small/syndicate/hard_drive = computer.all_components[MC_HDD] + switch(action) if("PRG_contract-accept") var/contract_id = text2num(params["contract_id"]) + // Set as the active contract hard_drive.traitor_data.contractor_hub.assigned_contracts[contract_id].status = CONTRACT_STATUS_ACTIVE hard_drive.traitor_data.contractor_hub.current_contract = hard_drive.traitor_data.contractor_hub.assigned_contracts[contract_id] + program_icon_state = "single_contract" return TRUE if("PRG_login") @@ -38,26 +40,30 @@ // Bake their data right into the hard drive, or we don't allow non-antags gaining access to an unused // contract system. // We also create their contracts at this point. - if(traitor_data) + if (traitor_data) // Only play greet sound, and handle contractor hub when assigning for the first time. - if(!traitor_data.contractor_hub) + if (!traitor_data.contractor_hub) user.playsound_local(user, 'sound/effects/contractstartup.ogg', 100, FALSE) traitor_data.contractor_hub = new traitor_data.contractor_hub.create_hub_items() + // Stops any topic exploits such as logging in multiple times on a single system. - if(!assigned) + if (!assigned) traitor_data.contractor_hub.create_contracts(traitor_data.owner) + hard_drive.traitor_data = traitor_data + program_icon_state = "contracts" assigned = TRUE else error = "UNAUTHORIZED USER" return TRUE if("PRG_call_extraction") - if(hard_drive.traitor_data.contractor_hub.current_contract.status != CONTRACT_STATUS_EXTRACTING) - if(hard_drive.traitor_data.contractor_hub.current_contract.handle_extraction(user)) + if (hard_drive.traitor_data.contractor_hub.current_contract.status != CONTRACT_STATUS_EXTRACTING) + if (hard_drive.traitor_data.contractor_hub.current_contract.handle_extraction(user)) user.playsound_local(user, 'sound/effects/confirmdropoff.ogg', 100, TRUE) hard_drive.traitor_data.contractor_hub.current_contract.status = CONTRACT_STATUS_EXTRACTING + program_icon_state = "extracted" else user.playsound_local(user, 'sound/machines/uplinkerror.ogg', 50) @@ -65,15 +71,19 @@ else user.playsound_local(user, 'sound/machines/uplinkerror.ogg', 50) error = "Already extracting... Place the target into the pod. If the pod was destroyed, this contract is no longer possible." + return TRUE if("PRG_contract_abort") var/contract_id = hard_drive.traitor_data.contractor_hub.current_contract.id + hard_drive.traitor_data.contractor_hub.current_contract = null hard_drive.traitor_data.contractor_hub.assigned_contracts[contract_id].status = CONTRACT_STATUS_ABORTED + program_icon_state = "contracts" + return TRUE if("PRG_redeem_TC") - if(hard_drive.traitor_data.contractor_hub.contract_TC_to_redeem) + if (hard_drive.traitor_data.contractor_hub.contract_TC_to_redeem) var/obj/item/stack/telecrystal/crystals = new /obj/item/stack/telecrystal(get_turf(user), hard_drive.traitor_data.contractor_hub.contract_TC_to_redeem) if(ishuman(user)) @@ -82,13 +92,14 @@ to_chat(H, "Your payment materializes into your hands!") else to_chat(user, "Your payment materializes onto the floor.") + hard_drive.traitor_data.contractor_hub.contract_TC_payed_out += hard_drive.traitor_data.contractor_hub.contract_TC_to_redeem hard_drive.traitor_data.contractor_hub.contract_TC_to_redeem = 0 return TRUE else user.playsound_local(user, 'sound/machines/uplinkerror.ogg', 50) return TRUE - if("PRG_clear_error") + if ("PRG_clear_error") error = "" return TRUE if("PRG_set_first_load_finished") @@ -97,10 +108,11 @@ if("PRG_toggle_info") info_screen = !info_screen return TRUE - if("buy_hub") - if(hard_drive.traitor_data.owner.current == user) + if ("buy_hub") + if (hard_drive.traitor_data.owner.current == user) var/item = params["item"] - for(var/datum/contractor_item/hub_item in hard_drive.traitor_data.contractor_hub.hub_items) + + for (var/datum/contractor_item/hub_item in hard_drive.traitor_data.contractor_hub.hub_items) if (hub_item.name == item) hub_item.handle_purchase(hard_drive.traitor_data.contractor_hub, user) else @@ -112,13 +124,15 @@ var/screen_to_be = null data["first_load"] = first_load - if(hard_drive && hard_drive.traitor_data != null) + + if (hard_drive && hard_drive.traitor_data != null) var/datum/antagonist/traitor/traitor_data = hard_drive.traitor_data data += get_header_data() - if(traitor_data.contractor_hub.current_contract) + + if (traitor_data.contractor_hub.current_contract) data["ongoing_contract"] = TRUE screen_to_be = "single_contract" - if(traitor_data.contractor_hub.current_contract.status == CONTRACT_STATUS_EXTRACTING) + if (traitor_data.contractor_hub.current_contract.status == CONTRACT_STATUS_EXTRACTING) data["extraction_enroute"] = TRUE screen_to_be = "extracted" else @@ -126,15 +140,19 @@ else data["ongoing_contract"] = FALSE data["extraction_enroute"] = FALSE + data["logged_in"] = TRUE data["station_name"] = GLOB.station_name data["redeemable_tc"] = traitor_data.contractor_hub.contract_TC_to_redeem data["earned_tc"] = traitor_data.contractor_hub.contract_TC_payed_out data["contracts_completed"] = traitor_data.contractor_hub.contracts_completed data["contract_rep"] = traitor_data.contractor_hub.contract_rep + data["info_screen"] = info_screen + data["error"] = error - for(var/datum/contractor_item/hub_item in traitor_data.contractor_hub.hub_items) + + for (var/datum/contractor_item/hub_item in traitor_data.contractor_hub.hub_items) data["contractor_hub_items"] += list(list( "name" = hub_item.name, "desc" = hub_item.desc, @@ -142,7 +160,8 @@ "limited" = hub_item.limited, "item_icon" = hub_item.item_icon )) - for(var/datum/syndicate_contract/contract in traitor_data.contractor_hub.assigned_contracts) + + for (var/datum/syndicate_contract/contract in traitor_data.contractor_hub.assigned_contracts) data["contracts"] += list(list( "target" = contract.contract.target, "target_rank" = contract.target_rank, @@ -155,23 +174,28 @@ )) var/direction - if(traitor_data.contractor_hub.current_contract) + if (traitor_data.contractor_hub.current_contract) var/turf/curr = get_turf(user) var/turf/dropoff_turf data["current_location"] = "[get_area_name(curr, TRUE)]" - for(var/turf/content in traitor_data.contractor_hub.current_contract.contract.dropoff.contents) - if(isturf(content)) + + for (var/turf/content in traitor_data.contractor_hub.current_contract.contract.dropoff.contents) + if (isturf(content)) dropoff_turf = content break + if(curr.z == dropoff_turf.z) //Direction calculations for same z-level only direction = uppertext(dir2text(get_dir(curr, dropoff_turf))) //Direction text (East, etc). Not as precise, but still helpful. if(get_area(user) == traitor_data.contractor_hub.current_contract.contract.dropoff) direction = "LOCATION CONFIRMED" else direction = "???" + data["dropoff_direction"] = direction + else data["logged_in"] = FALSE + program_icon_state = screen_to_be update_computer_icon() return data diff --git a/code/modules/modular_computers/file_system/programs/antagonist/dos.dm b/code/modules/modular_computers/file_system/programs/antagonist/dos.dm index 9dedc3810f..803dadc0a0 100644 --- a/code/modules/modular_computers/file_system/programs/antagonist/dos.dm +++ b/code/modules/modular_computers/file_system/programs/antagonist/dos.dm @@ -8,8 +8,6 @@ available_on_ntnet = FALSE available_on_syndinet = TRUE tgui_id = "NtosNetDos" - ui_x = 400 - ui_y = 250 var/obj/machinery/ntnet_relay/target = null var/dos_speed = 0 diff --git a/code/modules/modular_computers/file_system/programs/antagonist/revelation.dm b/code/modules/modular_computers/file_system/programs/antagonist/revelation.dm index a312815008..2ba3d69fe6 100644 --- a/code/modules/modular_computers/file_system/programs/antagonist/revelation.dm +++ b/code/modules/modular_computers/file_system/programs/antagonist/revelation.dm @@ -8,9 +8,6 @@ available_on_ntnet = FALSE available_on_syndinet = TRUE tgui_id = "NtosRevelation" - ui_x = 400 - ui_y = 250 - var/armed = 0 /datum/computer_file/program/revelation/run_program(var/mob/living/user) diff --git a/code/modules/modular_computers/file_system/programs/arcade.dm b/code/modules/modular_computers/file_system/programs/arcade.dm index 87debafd6b..2503073f9a 100644 --- a/code/modules/modular_computers/file_system/programs/arcade.dm +++ b/code/modules/modular_computers/file_system/programs/arcade.dm @@ -7,8 +7,6 @@ network_destination = "arcade network" size = 6 tgui_id = "NtosArcade" - ui_x = 450 - ui_y = 350 ///Returns TRUE if the game is being played. var/game_active = TRUE @@ -27,6 +25,7 @@ /datum/computer_file/program/arcade/proc/game_check(mob/user) sleep(5) + //user?.mind?.adjust_experience(/datum/skill/gaming, 1) No gaming(TM) Yet if(boss_hp <= 0) heads_up = "You have crushed [boss_name]! Rejoice!" playsound(computer.loc, 'sound/arcade/win.ogg', 50, TRUE, extrarange = -3, falloff = 10) @@ -35,6 +34,7 @@ if(istype(computer)) computer.update_icon() ticket_count += 1 + //user?.mind?.adjust_experience(/datum/skill/gaming, 50) sleep(10) else if(player_hp <= 0 || player_mp <= 0) heads_up = "You have been defeated... how will the station survive?" @@ -43,6 +43,7 @@ program_icon_state = "arcade_off" if(istype(computer)) computer.update_icon() + //user?.mind?.adjust_experience(/datum/skill/gaming, 10) sleep(10) /datum/computer_file/program/arcade/proc/enemy_check(mob/user) @@ -73,14 +74,13 @@ pause_state = FALSE game_check() -/datum/computer_file/program/arcade/ui_interact(mob/user, ui_key, datum/tgui/ui, force_open, datum/tgui/master_ui, datum/ui_state/state) - . = ..() - var/datum/asset/assets = get_asset_datum(/datum/asset/simple/arcade) - assets.send(user) +/datum/computer_file/program/arcade/ui_assets(mob/user) + return list( + get_asset_datum(/datum/asset/simple/arcade), + ) /datum/computer_file/program/arcade/ui_data(mob/user) var/list/data = get_header_data() - data["Hitpoints"] = boss_hp data["PlayerHitpoints"] = player_hp data["PlayerMP"] = player_mp @@ -98,11 +98,13 @@ if(computer) printer = computer.all_components[MC_PRINT] + //var/gamerSkillLevel = usr.mind?.get_skill_level(/datum/skill/gaming) + //var/gamerSkill = usr.mind?.get_skill_modifier(/datum/skill/gaming, SKILL_RANDS_MODIFIER) switch(action) if("Attack") var/attackamt = 0 //Spam prevention. if(pause_state == FALSE) - attackamt = rand(2,6) + attackamt = rand(2,6)// + rand(0, gamerSkill) pause_state = TRUE heads_up = "You attack for [attackamt] damage." playsound(computer.loc, 'sound/arcade/hit.ogg', 50, TRUE, extrarange = -3, falloff = 10) @@ -115,8 +117,10 @@ var/healamt = 0 //More Spam Prevention. var/healcost = 0 if(pause_state == FALSE) - healamt = rand(6,8) + healamt = rand(6,8)// + rand(0, gamerSkill) var/maxPointCost = 3 + //if(gamerSkillLevel >= SKILL_LEVEL_JOURNEYMAN) + // maxPointCost = 2 healcost = rand(1, maxPointCost) pause_state = TRUE heads_up = "You heal for [healamt] damage." @@ -130,7 +134,7 @@ if("Recharge_Power") var/rechargeamt = 0 //As above. if(pause_state == FALSE) - rechargeamt = rand(4, 7) + rechargeamt = rand(4,7)// + rand(0, gamerSkill) pause_state = TRUE heads_up = "You regain [rechargeamt] magic power." playsound(computer.loc, 'sound/arcade/mana.ogg', 50, TRUE, extrarange = -3, falloff = 10) diff --git a/code/modules/modular_computers/file_system/programs/atmosscan.dm b/code/modules/modular_computers/file_system/programs/atmosscan.dm index fe3833facd..2df751bebd 100644 --- a/code/modules/modular_computers/file_system/programs/atmosscan.dm +++ b/code/modules/modular_computers/file_system/programs/atmosscan.dm @@ -6,8 +6,6 @@ network_destination = "atmos scan" size = 4 tgui_id = "NtosAtmos" - ui_x = 300 - ui_y = 350 /datum/computer_file/program/atmosscan/ui_data(mob/user) var/list/data = get_header_data() @@ -15,16 +13,16 @@ var/turf/T = get_turf(ui_host()) if(T) var/datum/gas_mixture/environment = T.return_air() - var/list/env_gases = environment.gases + var/list/env_gases = environment.get_gases() var/pressure = environment.return_pressure() var/total_moles = environment.total_moles() data["AirPressure"] = round(pressure,0.1) - data["AirTemp"] = round(environment.temperature-T0C) + data["AirTemp"] = round(environment.return_temperature()-T0C) if (total_moles) for(var/id in env_gases) - var/gas_level = env_gases[id][MOLES]/total_moles + var/gas_level = environment.get_moles(id)/total_moles if(gas_level > 0) - airlist += list(list("name" = "[env_gases[id][GAS_META][META_GAS_NAME]]", "percentage" = round(gas_level*100, 0.01))) + airlist += list(list("name" = "[GLOB.meta_gas_names[id]]", "percentage" = round(gas_level*100, 0.01))) data["AirData"] = airlist return data diff --git a/code/modules/modular_computers/file_system/programs/borg_monitor.dm b/code/modules/modular_computers/file_system/programs/borg_monitor.dm index c493926c65..c2160a0e92 100644 --- a/code/modules/modular_computers/file_system/programs/borg_monitor.dm +++ b/code/modules/modular_computers/file_system/programs/borg_monitor.dm @@ -9,21 +9,17 @@ network_destination = "cyborg remote monitoring" size = 5 tgui_id = "NtosCyborgRemoteMonitor" - ui_x = 600 - ui_y = 800 /datum/computer_file/program/borg_monitor/ui_data(mob/user) var/list/data = get_header_data() data["card"] = FALSE - if(computer.GetID()) + if(checkID()) data["card"] = TRUE data["cyborgs"] = list() for(var/mob/living/silicon/robot/R in GLOB.silicon_mobs) - if((get_turf(computer)).z != (get_turf(R)).z) - continue - if(R.scrambledcodes) + if(!evaluate_borg(R)) continue var/list/upgrade @@ -36,7 +32,7 @@ var/list/cyborg_data = list( name = R.name, - locked_down = R.locked_down, + locked_down = R.lockcharge, status = R.stat, shell_discon = shell, charge = R.cell ? round(R.cell.percent()) : null, @@ -56,14 +52,53 @@ var/mob/living/silicon/robot/R = locate(params["ref"]) in GLOB.silicon_mobs if(!istype(R)) return - var/obj/item/card/id/ID = computer.GetID() + var/ID = checkID() if(!ID) return var/message = stripped_input(usr, message = "Enter message to be sent to remote cyborg.", title = "Send Message") if(!message) return - to_chat(R, "

Message from [ID.registered_name] -- \"[message]\"
") + to_chat(R, "

Message from [ID] -- \"[message]\"
") SEND_SOUND(R, 'sound/machines/twobeep_high.ogg') if(R.connected_ai) - to_chat(R.connected_ai, "

Message from [ID.registered_name] to [R] -- \"[message]\"
") + to_chat(R.connected_ai, "

Message from [ID] to [R] -- \"[message]\"
") SEND_SOUND(R.connected_ai, 'sound/machines/twobeep_high.ogg') + usr.log_talk(message, LOG_PDA, tag="Cyborg Monitor Program: ID name \"[ID]\" to [R]") + +///This proc is used to determin if a borg should be shown in the list (based on the borg's scrambledcodes var). Syndicate version overrides this to show only syndicate borgs. +/datum/computer_file/program/borg_monitor/proc/evaluate_borg(mob/living/silicon/robot/R) + if((get_turf(computer)).z != (get_turf(R)).z) + return FALSE + if(R.scrambledcodes) + return FALSE + return TRUE + +///Gets the ID's name, if one is inserted into the device. This is a seperate proc solely to be overridden by the syndicate version of the app. +/datum/computer_file/program/borg_monitor/proc/checkID() + var/obj/item/card/id/ID = computer.GetID() + if(!ID) + return FALSE + return ID.registered_name + +/datum/computer_file/program/borg_monitor/syndicate + filename = "scyborgmonitor" + filedesc = "Mission-Specific Cyborg Remote Monitoring" + ui_header = "borg_mon.gif" + program_icon_state = "generic" + extended_desc = "This program allows for remote monitoring of mission-assigned cyborgs." + requires_ntnet = FALSE + available_on_ntnet = FALSE + available_on_syndinet = TRUE + transfer_access = null + network_destination = "cyborg remote monitoring" + tgui_id = "NtosCyborgRemoteMonitorSyndicate" + +/datum/computer_file/program/borg_monitor/syndicate/evaluate_borg(mob/living/silicon/robot/R) + if((get_turf(computer)).z != (get_turf(R)).z) + return FALSE + if(!R.scrambledcodes) + return FALSE + return TRUE + +/datum/computer_file/program/borg_monitor/syndicate/checkID() + return "\[CLASSIFIED\]" //no ID is needed for the syndicate version's message function, and the borg will see "[CLASSIFIED]" as the message sender. diff --git a/code/modules/modular_computers/file_system/programs/bounty_board.dm b/code/modules/modular_computers/file_system/programs/bounty_board.dm new file mode 100644 index 0000000000..46fde84f65 --- /dev/null +++ b/code/modules/modular_computers/file_system/programs/bounty_board.dm @@ -0,0 +1,120 @@ +/datum/computer_file/program/bounty_board + filename = "bountyboard" + filedesc = "Bounty Board Request Network" + program_icon_state = "bountyboard" + extended_desc = "A multi-platform network for placing requests across the station, with payment across the network being possible.." + requires_ntnet = TRUE + network_destination = "bounty board interface" + size = 10 + tgui_id = "NtosRequestKiosk" + ///Reference to the currently logged in user. + var/datum/bank_account/current_user + ///The station request datum being affected by UI actions. + var/datum/station_request/active_request + ///Value of the currently bounty input + var/bounty_value = 1 + ///Text of the currently written bounty + var/bounty_text = "" + ///Has the app been added to the network yet? + var/networked = FALSE + +/datum/computer_file/program/bounty_board/ui_data(mob/user) + var/list/data = get_header_data() + var/list/formatted_requests = list() + var/list/formatted_applicants = list() + var/obj/item/computer_hardware/card_slot/card_slot = computer.all_components[MC_CARD] + if(!networked) + GLOB.allbountyboards += computer + networked = TRUE + if(card_slot && card_slot.stored_card && card_slot.stored_card.registered_account) + current_user = card_slot.stored_card.registered_account + for(var/i in GLOB.request_list) + if(!i) + continue + var/datum/station_request/request = i + formatted_requests += list(list("owner" = request.owner, "value" = request.value, "description" = request.description, "acc_number" = request.req_number)) + if(request.applicants) + for(var/datum/bank_account/j in request.applicants) + formatted_applicants += list(list("name" = j.account_holder, "request_id" = request.owner_account.account_id, "requestee_id" = j.account_id)) + if(current_user) + data["accountName"] = current_user.account_holder + data["requests"] = formatted_requests + data["applicants"] = formatted_applicants + data["bountyValue"] = bounty_value + data["bountyText"] = bounty_text + return data + +/datum/computer_file/program/bounty_board/ui_act(action, list/params) + if(..()) + return + var/current_ref_num = params["request"] + var/current_app_num = params["applicant"] + var/datum/bank_account/request_target + if(current_ref_num) + for(var/datum/station_request/i in GLOB.request_list) + if("[i.req_number]" == "[current_ref_num]") + active_request = i + break + if(active_request) + for(var/datum/bank_account/j in active_request.applicants) + if("[j.account_id]" == "[current_app_num]") + request_target = j + break + switch(action) + if("createBounty") + if(!current_user || !bounty_text) + playsound(src, 'sound/machines/buzz-sigh.ogg', 20, TRUE) + return TRUE + for(var/datum/station_request/i in GLOB.request_list) + if("[i.req_number]" == "[current_user.account_id]") + computer.say("Account already has active bounty.") + return + var/datum/station_request/curr_request = new /datum/station_request(current_user.account_holder, bounty_value,bounty_text,current_user.account_id, current_user) + GLOB.request_list += list(curr_request) + for(var/obj/i in GLOB.allbountyboards) + i.say("New bounty has been added!") + playsound(i.loc, 'sound/effects/cashregister.ogg', 30, TRUE) + return TRUE + if("apply") + if(!current_user) + computer.say("Please swipe a valid ID first.") + return TRUE + if(current_user.account_holder == active_request.owner) + playsound(computer, 'sound/machines/buzz-sigh.ogg', 20, TRUE) + return TRUE + active_request.applicants += list(current_user) + if("payApplicant") + if(!current_user) + return + if(!current_user.has_money(active_request.value) || (current_user.account_holder != active_request.owner)) + playsound(computer, 'sound/machines/buzz-sigh.ogg', 30, TRUE) + return + request_target.transfer_money(current_user, active_request.value) + computer.say("Paid out [active_request.value] credits.") + return TRUE + if("clear") + if(current_user) + current_user = null + computer.say("Account Reset.") + return TRUE + if("deleteRequest") + if(!current_user) + playsound(computer, 'sound/machines/buzz-sigh.ogg', 20, TRUE) + return TRUE + if(active_request.owner != current_user.account_holder) + playsound(computer, 'sound/machines/buzz-sigh.ogg', 20, TRUE) + return TRUE + computer.say("Deleted current request.") + GLOB.request_list.Remove(active_request) + return TRUE + if("bountyVal") + bounty_value = text2num(params["bountyval"]) + if(!bounty_value) + bounty_value = 1 + if("bountyText") + bounty_text = (params["bountytext"]) + . = TRUE + +/datum/computer_file/program/bounty_board/Destroy() + GLOB.allbountyboards -= computer + . = ..() diff --git a/code/modules/modular_computers/file_system/programs/card.dm b/code/modules/modular_computers/file_system/programs/card.dm index 07d39438d8..842d6e2588 100644 --- a/code/modules/modular_computers/file_system/programs/card.dm +++ b/code/modules/modular_computers/file_system/programs/card.dm @@ -15,8 +15,6 @@ requires_ntnet = 0 size = 8 tgui_id = "NtosCard" - ui_x = 450 - ui_y = 520 var/is_centcom = FALSE var/minor = FALSE @@ -275,7 +273,7 @@ departments = list("CentCom" = get_all_centcom_jobs()) else if(isnull(departments)) departments = list( - CARDCON_DEPARTMENT_COMMAND = list("Captain"), + CARDCON_DEPARTMENT_COMMAND = list("Captain"),//lol CARDCON_DEPARTMENT_ENGINEERING = GLOB.engineering_positions, CARDCON_DEPARTMENT_MEDICAL = GLOB.medical_positions, CARDCON_DEPARTMENT_SCIENCE = GLOB.science_positions, diff --git a/code/modules/modular_computers/file_system/programs/cargobounty.dm b/code/modules/modular_computers/file_system/programs/cargobounty.dm new file mode 100644 index 0000000000..d9bc65c98d --- /dev/null +++ b/code/modules/modular_computers/file_system/programs/cargobounty.dm @@ -0,0 +1,48 @@ +/datum/computer_file/program/bounty + filename = "bounty" + filedesc = "Nanotrasen Bounty Hunter" + program_icon_state = "bounty" + extended_desc = "A basic interface for supply personnel to check and claim bounties." + requires_ntnet = TRUE + transfer_access = ACCESS_CARGO + network_destination = "cargo claims interface" + size = 10 + tgui_id = "NtosBountyConsole" + ///cooldown var for printing paper sheets. + var/printer_ready = 0 + ///The cargo account for grabbing the cargo account's credits. + var/static/datum/bank_account/cargocash + +/datum/computer_file/program/bounty/proc/print_paper() + new /obj/item/paper/bounty_printout(get_turf(computer)) + +/datum/computer_file/program/bounty/ui_interact(mob/user, datum/tgui/ui) + if(!GLOB.bounties_list.len) + setup_bounties() + printer_ready = world.time + PRINTER_TIMEOUT + cargocash = SSeconomy.get_dep_account(ACCOUNT_CAR) + . = ..() + +/datum/computer_file/program/bounty/ui_data(mob/user) + var/list/data = get_header_data() + var/list/bountyinfo = list() + for(var/datum/bounty/B in GLOB.bounties_list) + bountyinfo += list(list("name" = B.name, "description" = B.description, "reward_string" = B.reward_string(), "completion_string" = B.completion_string() , "claimed" = B.claimed, "can_claim" = B.can_claim(), "priority" = B.high_priority, "bounty_ref" = REF(B))) + data["stored_cash"] = cargocash.account_balance + data["bountydata"] = bountyinfo + return data + +/datum/computer_file/program/bounty/ui_act(action,params) + if(..()) + return + switch(action) + if("ClaimBounty") + var/datum/bounty/cashmoney = locate(params["bounty"]) in GLOB.bounties_list + if(cashmoney) + cashmoney.claim() + return TRUE + if("Print") + if(printer_ready < world.time) + printer_ready = world.time + PRINTER_TIMEOUT + print_paper() + return diff --git a/code/modules/modular_computers/file_system/programs/cargoship.dm b/code/modules/modular_computers/file_system/programs/cargoship.dm index 39543adfa5..3ba08a3719 100644 --- a/code/modules/modular_computers/file_system/programs/cargoship.dm +++ b/code/modules/modular_computers/file_system/programs/cargoship.dm @@ -6,11 +6,9 @@ network_destination = "ship scanner" size = 6 tgui_id = "NtosShipping" - ui_x = 450 - ui_y = 350 ///Account used for creating barcodes. var/datum/bank_account/payments_acc - ///The amount which the tagger will recieve for the sale. + ///The amount which the tagger will receive for the sale. var/percent_cut = 20 /datum/computer_file/program/shipping/ui_data(mob/user) diff --git a/code/modules/modular_computers/file_system/programs/configurator.dm b/code/modules/modular_computers/file_system/programs/configurator.dm index 76da58ea11..fae06544d5 100644 --- a/code/modules/modular_computers/file_system/programs/configurator.dm +++ b/code/modules/modular_computers/file_system/programs/configurator.dm @@ -10,8 +10,6 @@ unsendable = 1 undeletable = 1 size = 4 - ui_x = 420 - ui_y = 630 available_on_ntnet = 0 requires_ntnet = 0 tgui_id = "NtosConfiguration" diff --git a/code/modules/modular_computers/file_system/programs/crewmanifest.dm b/code/modules/modular_computers/file_system/programs/crewmanifest.dm index 662c867a39..a1503ce3a8 100644 --- a/code/modules/modular_computers/file_system/programs/crewmanifest.dm +++ b/code/modules/modular_computers/file_system/programs/crewmanifest.dm @@ -7,12 +7,10 @@ requires_ntnet = FALSE size = 4 tgui_id = "NtosCrewManifest" - ui_x = 400 - ui_y = 480 /datum/computer_file/program/crew_manifest/ui_static_data(mob/user) var/list/data = list() - data["manifest"] = GLOB.data_core.get_manifest() + data["manifest"] = GLOB.data_core.get_manifest_tg() return data /datum/computer_file/program/crew_manifest/ui_data(mob/user) @@ -41,9 +39,9 @@ if(computer && printer) //This option should never be called if there is no printer var/contents = {"

Crew Manifest


- [GLOB.data_core ? GLOB.data_core.get_manifest_html(0) : ""] + [GLOB.data_core ? GLOB.data_core.get_manifest() : ""] "} - if(!printer.print_text(contents,text("crew manifest ([])", station_time_timestamp()))) + if(!printer.print_text(contents,text("crew manifest ([])", STATION_TIME_TIMESTAMP("hh:mm:ss", world.time)))) to_chat(usr, "Hardware error: Printer was unable to print the file. It may be out of paper.") return else diff --git a/code/modules/modular_computers/file_system/programs/jobmanagement.dm b/code/modules/modular_computers/file_system/programs/jobmanagement.dm index 7b847c123e..bccc6e4dbe 100644 --- a/code/modules/modular_computers/file_system/programs/jobmanagement.dm +++ b/code/modules/modular_computers/file_system/programs/jobmanagement.dm @@ -7,8 +7,6 @@ requires_ntnet = 0 size = 4 tgui_id = "NtosJobManager" - ui_x = 400 - ui_y = 620 var/change_position_cooldown = 30 //Jobs you cannot open new positions for diff --git a/code/modules/modular_computers/file_system/programs/ntdownloader.dm b/code/modules/modular_computers/file_system/programs/ntdownloader.dm index 352f13f305..6401d6207f 100644 --- a/code/modules/modular_computers/file_system/programs/ntdownloader.dm +++ b/code/modules/modular_computers/file_system/programs/ntdownloader.dm @@ -11,8 +11,6 @@ available_on_ntnet = 0 ui_header = "downloader_finished.gif" tgui_id = "NtosNetDownloader" - ui_x = 480 - ui_y = 735 var/datum/computer_file/program/downloaded_file = null var/hacked_download = 0 @@ -20,6 +18,21 @@ var/download_netspeed = 0 var/downloaderror = "" var/obj/item/modular_computer/my_computer = null + var/emagged = FALSE + var/list/main_repo + var/list/antag_repo + +/datum/computer_file/program/ntnetdownload/run_program() + . = ..() + main_repo = SSnetworks.station_network.available_station_software + antag_repo = SSnetworks.station_network.available_antag_software + +/datum/computer_file/program/ntnetdownload/run_emag() + if(emagged) + return FALSE + emagged = TRUE + return TRUE + /datum/computer_file/program/ntnetdownload/proc/begin_file_download(filename) if(downloaded_file) @@ -30,8 +43,8 @@ if(!PRG || !istype(PRG)) return 0 - // Attempting to download antag only program, but without having emagged computer. No. - if(PRG.available_on_syndinet && !(computer.obj_flags & EMAGGED)) + // Attempting to download antag only program, but without having emagged/syndicate computer. No. + if(PRG.available_on_syndinet && !emagged) return 0 var/obj/item/computer_hardware/hard_drive/hard_drive = computer.all_components[MC_HDD] @@ -41,10 +54,10 @@ ui_header = "downloader_running.gif" - if(PRG in SSnetworks.station_network.available_station_software) + if(PRG in main_repo) generate_network_log("Began downloading file [PRG.filename].[PRG.filetype] from NTNet Software Repository.") hacked_download = 0 - else if(PRG in SSnetworks.station_network.available_antag_software) + else if(PRG in antag_repo) generate_network_log("Began downloading file **ENCRYPTED**.[PRG.filetype] from unspecified server.") hacked_download = 1 else @@ -130,7 +143,7 @@ data["disk_size"] = hard_drive.max_capacity data["disk_used"] = hard_drive.used_capacity var/list/all_entries[0] - for(var/A in SSnetworks.station_network.available_station_software) + for(var/A in main_repo) var/datum/computer_file/program/P = A // Only those programs our user can run will show in the list if(!P.can_run(user,transfer = 1) || hard_drive.find_file_by_name(P.filename)) @@ -143,9 +156,9 @@ "size" = P.size, ))) data["hackedavailable"] = FALSE - if(computer.obj_flags & EMAGGED) // If we are running on emagged computer we have access to some "bonus" software + if(emagged) // If we are running on emagged computer we have access to some "bonus" software var/list/hacked_programs[0] - for(var/S in SSnetworks.station_network.available_antag_software) + for(var/S in antag_repo) var/datum/computer_file/program/P = S if(hard_drive.find_file_by_name(P.filename)) continue @@ -172,3 +185,24 @@ /datum/computer_file/program/ntnetdownload/kill_program(forced) abort_file_download() return ..(forced) + +//////////////////////// +//Syndicate Downloader// +//////////////////////// + +/// This app only lists programs normally found in the emagged section of the normal downloader app + +/datum/computer_file/program/ntnetdownload/syndicate + filename = "syndownloader" + filedesc = "Software Download Tool" + program_icon_state = "generic" + extended_desc = "This program allows downloads of software from shared Syndicate repositories" + requires_ntnet = 0 + ui_header = "downloader_finished.gif" + tgui_id = "NtosNetDownloader" + emagged = TRUE + +/datum/computer_file/program/ntnetdownload/syndicate/run_program() + . = ..() + main_repo = SSnetworks.station_network.available_antag_software + antag_repo = null diff --git a/code/modules/modular_computers/file_system/programs/ntnrc_client.dm b/code/modules/modular_computers/file_system/programs/ntnrc_client.dm index 4ae5bd326b..df9b02d8ec 100644 --- a/code/modules/modular_computers/file_system/programs/ntnrc_client.dm +++ b/code/modules/modular_computers/file_system/programs/ntnrc_client.dm @@ -10,9 +10,6 @@ ui_header = "ntnrc_idle.gif" available_on_ntnet = 1 tgui_id = "NtosNetChat" - ui_x = 900 - ui_y = 675 - var/last_message // Used to generate the toolbar icon var/username var/active_channel diff --git a/code/modules/modular_computers/file_system/programs/nttransfer.dm b/code/modules/modular_computers/file_system/programs/nttransfer.dm deleted file mode 100644 index 698e557941..0000000000 --- a/code/modules/modular_computers/file_system/programs/nttransfer.dm +++ /dev/null @@ -1,183 +0,0 @@ -/datum/computer_file/program/nttransfer - filename = "nttransfer" - filedesc = "P2P Transfer Client" - extended_desc = "This program allows for simple file transfer via direct peer to peer connection." - program_icon_state = "comm_logs" - size = 7 - requires_ntnet = 1 - requires_ntnet_feature = NTNET_PEERTOPEER - network_destination = "other device via P2P tunnel" - available_on_ntnet = 1 - tgui_id = "ntos_net_transfer" - - var/error = "" // Error screen - var/server_password = "" // Optional password to download the file. - var/datum/computer_file/provided_file = null // File which is provided to clients. - var/datum/computer_file/downloaded_file = null // File which is being downloaded - var/list/connected_clients = list() // List of connected clients. - var/datum/computer_file/program/nttransfer/remote // Client var, specifies who are we downloading from. - var/download_completion = 0 // Download progress in GQ - var/download_netspeed = 0 // Our connectivity speed in GQ/s - var/actual_netspeed = 0 // Displayed in the UI, this is the actual transfer speed. - var/unique_token // UID of this program - var/upload_menu = 0 // Whether we show the program list and upload menu - var/static/nttransfer_uid = 0 - -/datum/computer_file/program/nttransfer/New() - unique_token = nttransfer_uid++ - ..() - -/datum/computer_file/program/nttransfer/process_tick() - // Server mode - update_netspeed() - if(provided_file) - for(var/datum/computer_file/program/nttransfer/C in connected_clients) - // Transfer speed is limited by device which uses slower connectivity. - // We can have multiple clients downloading at same time, but let's assume we use some sort of multicast transfer - // so they can all run on same speed. - C.actual_netspeed = min(C.download_netspeed, download_netspeed) - C.download_completion += C.actual_netspeed - if(C.download_completion >= provided_file.size) - C.finish_download() - else if(downloaded_file) // Client mode - if(!remote) - crash_download("Connection to remote server lost") - -/datum/computer_file/program/nttransfer/kill_program(forced = FALSE) - if(downloaded_file) // Client mode, clean up variables for next use - finalize_download() - - if(provided_file) // Server mode, disconnect all clients - for(var/datum/computer_file/program/nttransfer/P in connected_clients) - P.crash_download("Connection terminated by remote server") - downloaded_file = null - ..(forced) - -/datum/computer_file/program/nttransfer/proc/update_netspeed() - download_netspeed = 0 - switch(ntnet_status) - if(1) - download_netspeed = NTNETSPEED_LOWSIGNAL - if(2) - download_netspeed = NTNETSPEED_HIGHSIGNAL - if(3) - download_netspeed = NTNETSPEED_ETHERNET - -// Finishes download and attempts to store the file on HDD -/datum/computer_file/program/nttransfer/proc/finish_download() - var/obj/item/computer_hardware/hard_drive/hard_drive = computer.all_components[MC_HDD] - if(!computer || !hard_drive || !hard_drive.store_file(downloaded_file)) - error = "I/O Error: Unable to save file. Check your hard drive and try again." - finalize_download() - -// Crashes the download and displays specific error message -/datum/computer_file/program/nttransfer/proc/crash_download(var/message) - error = message ? message : "An unknown error has occurred during download" - finalize_download() - -// Cleans up variables for next use -/datum/computer_file/program/nttransfer/proc/finalize_download() - if(remote) - remote.connected_clients.Remove(src) - downloaded_file = null - remote = null - download_completion = 0 - -/datum/computer_file/program/nttransfer/ui_act(action, params) - if(..()) - return 1 - switch(action) - if("PRG_downloadfile") - for(var/datum/computer_file/program/nttransfer/P in SSnetworks.station_network.fileservers) - if("[P.unique_token]" == params["id"]) - remote = P - break - if(!remote || !remote.provided_file) - return - if(remote.server_password) - var/pass = reject_bad_text(input(usr, "Code 401 Unauthorized. Please enter password:", "Password required")) - if(pass != remote.server_password) - error = "Incorrect Password" - return - downloaded_file = remote.provided_file.clone() - remote.connected_clients.Add(src) - return 1 - if("PRG_reset") - error = "" - upload_menu = 0 - finalize_download() - if(src in SSnetworks.station_network.fileservers) - SSnetworks.station_network.fileservers.Remove(src) - for(var/datum/computer_file/program/nttransfer/T in connected_clients) - T.crash_download("Remote server has forcibly closed the connection") - provided_file = null - return 1 - if("PRG_setpassword") - var/pass = reject_bad_text(input(usr, "Enter new server password. Leave blank to cancel, input 'none' to disable password.", "Server security", "none")) - if(!pass) - return - if(pass == "none") - server_password = "" - return - server_password = pass - return 1 - if("PRG_uploadfile") - var/obj/item/computer_hardware/hard_drive/hard_drive = computer.all_components[MC_HDD] - for(var/datum/computer_file/F in hard_drive.stored_files) - if("[F.uid]" == params["id"]) - if(F.unsendable) - error = "I/O Error: File locked." - return - if(istype(F, /datum/computer_file/program)) - var/datum/computer_file/program/P = F - if(!P.can_run(usr,transfer = 1)) - error = "Access Error: Insufficient rights to upload file." - provided_file = F - SSnetworks.station_network.fileservers.Add(src) - return - error = "I/O Error: Unable to locate file on hard drive." - return 1 - if("PRG_uploadmenu") - upload_menu = 1 - - -/datum/computer_file/program/nttransfer/ui_data(mob/user) - - var/list/data = get_header_data() - - if(error) - data["error"] = error - else if(downloaded_file) - data["downloading"] = 1 - data["download_size"] = downloaded_file.size - data["download_progress"] = download_completion - data["download_netspeed"] = actual_netspeed - data["download_name"] = "[downloaded_file.filename].[downloaded_file.filetype]" - else if (provided_file) - data["uploading"] = 1 - data["upload_uid"] = unique_token - data["upload_clients"] = connected_clients.len - data["upload_haspassword"] = server_password ? 1 : 0 - data["upload_filename"] = "[provided_file.filename].[provided_file.filetype]" - else if (upload_menu) - var/list/all_files[0] - var/obj/item/computer_hardware/hard_drive/hard_drive = computer.all_components[MC_HDD] - for(var/datum/computer_file/F in hard_drive.stored_files) - all_files.Add(list(list( - "uid" = F.uid, - "filename" = "[F.filename].[F.filetype]", - "size" = F.size - ))) - data["upload_filelist"] = all_files - else - var/list/all_servers[0] - for(var/datum/computer_file/program/nttransfer/P in SSnetworks.station_network.fileservers) - all_servers.Add(list(list( - "uid" = P.unique_token, - "filename" = "[P.provided_file.filename].[P.provided_file.filetype]", - "size" = P.provided_file.size, - "haspassword" = P.server_password ? 1 : 0 - ))) - data["servers"] = all_servers - - return data \ No newline at end of file diff --git a/code/modules/modular_computers/file_system/programs/powermonitor.dm b/code/modules/modular_computers/file_system/programs/powermonitor.dm index d2d57b1447..bd11474858 100644 --- a/code/modules/modular_computers/file_system/programs/powermonitor.dm +++ b/code/modules/modular_computers/file_system/programs/powermonitor.dm @@ -12,8 +12,6 @@ network_destination = "power monitoring system" size = 9 tgui_id = "NtosPowerMonitor" - ui_x = 550 - ui_y = 700 var/has_alert = 0 var/obj/structure/cable/attached_wire diff --git a/code/modules/modular_computers/file_system/programs/radar.dm b/code/modules/modular_computers/file_system/programs/radar.dm index 7a6e80267c..9b0e09ef99 100644 --- a/code/modules/modular_computers/file_system/programs/radar.dm +++ b/code/modules/modular_computers/file_system/programs/radar.dm @@ -2,31 +2,49 @@ filename = "genericfinder" filedesc = "debug_finder" ui_header = "borg_mon.gif" //DEBUG -- new icon before PR - program_icon_state = "generic" - extended_desc = "generic" + program_icon_state = "radarntos" requires_ntnet = TRUE transfer_access = null available_on_ntnet = FALSE + usage_flags = PROGRAM_LAPTOP | PROGRAM_TABLET network_destination = "tracking program" size = 5 tgui_id = "NtosRadar" - ui_x = 800 - ui_y = 600 - special_assets = list( - /datum/asset/simple/radar_assets, - ) ///List of trackable entities. Updated by the scan() proc. var/list/objects ///Ref of the last trackable object selected by the user in the tgui window. Updated in the ui_act() proc. var/atom/selected ///Used to store when the next scan is available. Updated by the scan() proc. var/next_scan = 0 + ///Used to keep track of the last value program_icon_state was set to, to prevent constant unnecessary update_icon() calls + var/last_icon_state = "" + ///Used by the tgui interface, themed NT or Syndicate. + var/arrowstyle = "ntosradarpointer.png" + ///Used by the tgui interface, themed for NT or Syndicate colors. + var/pointercolor = "green" + +/datum/computer_file/program/radar/run_program(mob/living/user) + . = ..() + if(.) + START_PROCESSING(SSfastprocess, src) + return + return FALSE /datum/computer_file/program/radar/kill_program(forced = FALSE) objects = list() selected = null + STOP_PROCESSING(SSfastprocess, src) return ..() +/datum/computer_file/program/radar/Destroy() + STOP_PROCESSING(SSfastprocess, src) + return ..() + +/datum/computer_file/program/radar/ui_assets(mob/user) + return list( + get_asset_datum(/datum/asset/simple/radar_assets), + ) + /datum/computer_file/program/radar/ui_data(mob/user) var/list/data = get_header_data() data["selected"] = selected @@ -65,7 +83,37 @@ * */ /datum/computer_file/program/radar/proc/track() - return + var/atom/movable/signal = find_atom() + if(!trackable(signal)) + return + + var/turf/here_turf = (get_turf(computer)) + var/turf/target_turf = (get_turf(signal)) + var/userot = FALSE + var/rot = 0 + var/pointer="crosshairs" + var/locx = (target_turf.x - here_turf.x) + 24 + var/locy = (here_turf.y - target_turf.y) + 24 + + if(get_dist_euclidian(here_turf, target_turf) > 24) + userot = TRUE + rot = round(Get_Angle(here_turf, target_turf)) + else + if(target_turf.z > here_turf.z) + pointer="caret-up" + else if(target_turf.z < here_turf.z) + pointer="caret-down" + + var/list/trackinfo = list( + "locx" = locx, + "locy" = locy, + "userot" = userot, + "rot" = rot, + "arrowstyle" = arrowstyle, + "color" = pointercolor, + "pointer" = pointer, + ) + return trackinfo /** * @@ -77,10 +125,12 @@ **arg1 is the atom being evaluated. */ /datum/computer_file/program/radar/proc/trackable(atom/movable/signal) - if(!signal) + if(!signal || !computer) return FALSE var/turf/here = get_turf(computer) var/turf/there = get_turf(signal) + if(!here || !there) + return FALSE //I was still getting a runtime even after the above check while scanning, so fuck it return (there.z == here.z) || (is_station_level(here.z) && is_station_level(there.z)) /** @@ -98,6 +148,59 @@ /datum/computer_file/program/radar/proc/scan() return +/** + * + *Finds the atom in the appropriate list that the `selected` var indicates + * + *The `selected` var holds a REF, which is a string. A mob REF may be + *something like "mob_209". In order to find the actual atom, we need + *to search the appropriate list for the REF string. This is dependant + *on the program (Lifeline uses GLOB.human_list, while Fission360 uses + *GLOB.poi_list), but the result will be the same; evaluate the string and + *return an atom reference. +*/ +/datum/computer_file/program/radar/proc/find_atom() + return + +//We use SSfastprocess for the program icon state because it runs faster than process_tick() does. +/datum/computer_file/program/radar/process() + if(computer.active_program != src) + STOP_PROCESSING(SSfastprocess, src) //We're not the active program, it's time to stop. + return + if(!selected) + return + + var/atom/movable/signal = find_atom() + if(!trackable(signal)) + program_icon_state = "[initial(program_icon_state)]lost" + if(last_icon_state != program_icon_state) + computer.update_icon() + last_icon_state = program_icon_state + return + + var/here_turf = get_turf(computer) + var/target_turf = get_turf(signal) + var/trackdistance = get_dist_euclidian(here_turf, target_turf) + switch(trackdistance) + if(0) + program_icon_state = "[initial(program_icon_state)]direct" + if(1 to 12) + program_icon_state = "[initial(program_icon_state)]close" + if(13 to 24) + program_icon_state = "[initial(program_icon_state)]medium" + if(25 to INFINITY) + program_icon_state = "[initial(program_icon_state)]far" + + if(last_icon_state != program_icon_state) + computer.update_icon() + last_icon_state = program_icon_state + computer.setDir(get_dir(here_turf, target_turf)) + +//We can use process_tick to restart fast processing, since the computer will be running this constantly either way. +/datum/computer_file/program/radar/process_tick() + if(computer.active_program == src) + START_PROCESSING(SSfastprocess, src) + /////////////////// //Suit Sensor App// /////////////////// @@ -106,44 +209,13 @@ /datum/computer_file/program/radar/lifeline filename = "Lifeline" filedesc = "Lifeline" - program_icon_state = "generic" extended_desc = "This program allows for tracking of crew members via their suit sensors." requires_ntnet = TRUE transfer_access = ACCESS_MEDICAL available_on_ntnet = TRUE -/datum/computer_file/program/radar/lifeline/track() - var/mob/living/carbon/human/humanoid = locate(selected) in GLOB.human_list - if(!istype(humanoid) || !trackable(humanoid)) - return - - var/turf/here_turf = (get_turf(computer)) - var/turf/target_turf = (get_turf(humanoid)) - var/userot = FALSE - var/rot = 0 - var/pointer="crosshairs" - var/locx = (target_turf.x - here_turf.x) - var/locy = (here_turf.y - target_turf.y) - if(get_dist_euclidian(here_turf, target_turf) > 24) //If they're too far away, we need the angle for the arrow along the edge of the radar display - userot = TRUE - rot = round(Get_Angle(here_turf, target_turf)) - else - locx = locx + 24 - locy = locy + 24 - if(target_turf.z > here_turf.z) - pointer="caret-up" - else if(target_turf.z < here_turf.z) - pointer="caret-down" - var/list/trackinfo = list( - locx = locx, - locy = locy, - userot = userot, - rot = rot, - arrowstyle = "ntosradarpointer.png", //For the rotation arrow, it's stupid I know - color = "green", - pointer = pointer, - ) - return trackinfo +/datum/computer_file/program/radar/lifeline/find_atom() + return locate(selected) in GLOB.human_list /datum/computer_file/program/radar/lifeline/scan() if(world.time < next_scan) @@ -184,46 +256,18 @@ /datum/computer_file/program/radar/fission360 filename = "Fission360" filedesc = "Fission360" - program_icon_state = "generic" + program_icon_state = "radarsyndicate" extended_desc = "This program allows for tracking of nuclear authorization disks and warheads." requires_ntnet = FALSE transfer_access = null available_on_ntnet = FALSE available_on_syndinet = TRUE tgui_id = "NtosRadarSyndicate" + arrowstyle = "ntosradarpointerS.png" + pointercolor = "red" -/datum/computer_file/program/radar/fission360/track() - var/obj/nuke = locate(selected) in GLOB.poi_list - if(!trackable(nuke)) - return - - var/turf/here_turf = (get_turf(computer)) - var/turf/target_turf = (get_turf(nuke)) - var/userot = FALSE - var/rot = 0 - var/pointer="crosshairs" - var/locx = (target_turf.x - here_turf.x) - var/locy = (here_turf.y - target_turf.y) - if(get_dist_euclidian(here_turf, target_turf) > 24) //If they're too far away, we need the angle for the arrow along the edge of the radar display - userot = TRUE - rot = round(Get_Angle(here_turf, target_turf)) - else - locx = locx + 24 - locy = locy + 24 - if(target_turf.z > here_turf.z) - pointer="caret-up" - else if(target_turf.z < here_turf.z) - pointer="caret-down" - var/list/trackinfo = list( - locx = locx, - locy = locy, - userot = userot, - rot = rot, - arrowstyle = "ntosradarpointerS.png", - color = "red", - pointer = pointer, - ) - return trackinfo +/datum/computer_file/program/radar/fission360/find_atom() + return locate(selected) in GLOB.poi_list /datum/computer_file/program/radar/fission360/scan() if(world.time < next_scan) diff --git a/code/modules/modular_computers/file_system/programs/robocontrol.dm b/code/modules/modular_computers/file_system/programs/robocontrol.dm index 910f923327..8644ce09b4 100644 --- a/code/modules/modular_computers/file_system/programs/robocontrol.dm +++ b/code/modules/modular_computers/file_system/programs/robocontrol.dm @@ -9,8 +9,6 @@ network_destination = "robotics control network" size = 12 tgui_id = "NtosRoboControl" - ui_x = 550 - ui_y = 550 ///Number of simple robots on-station. var/botcount = 0 ///Used to find the location of the user for the purposes of summoning robots. diff --git a/code/modules/modular_computers/file_system/programs/sm_monitor.dm b/code/modules/modular_computers/file_system/programs/sm_monitor.dm index 0a675a7abc..32ad102871 100644 --- a/code/modules/modular_computers/file_system/programs/sm_monitor.dm +++ b/code/modules/modular_computers/file_system/programs/sm_monitor.dm @@ -9,8 +9,6 @@ network_destination = "supermatter monitoring system" size = 5 tgui_id = "NtosSupermatterMonitor" - ui_x = 600 - ui_y = 350 var/last_status = SUPERMATTER_INACTIVE var/list/supermatters var/obj/machinery/power/supermatter_crystal/active // Currently selected supermatter crystal. diff --git a/code/modules/modular_computers/hardware/CPU.dm b/code/modules/modular_computers/hardware/CPU.dm index d08d65ff8b..f13081e1f3 100644 --- a/code/modules/modular_computers/hardware/CPU.dm +++ b/code/modules/modular_computers/hardware/CPU.dm @@ -37,4 +37,4 @@ icon_state = "cpu_super" w_class = WEIGHT_CLASS_TINY power_usage = 75 - max_idle_programs = 2 \ No newline at end of file + max_idle_programs = 2 diff --git a/code/modules/modular_computers/hardware/_hardware.dm b/code/modules/modular_computers/hardware/_hardware.dm index 37f3fc434e..b33442f99b 100644 --- a/code/modules/modular_computers/hardware/_hardware.dm +++ b/code/modules/modular_computers/hardware/_hardware.dm @@ -32,28 +32,29 @@ /obj/item/computer_hardware/attackby(obj/item/I, mob/living/user) - // Multitool. Runs diagnostics - if(istype(I, /obj/item/multitool)) - to_chat(user, "***** DIAGNOSTICS REPORT *****") - diagnostics(user) - to_chat(user, "******************************") - return 1 - // Cable coil. Works as repair method, but will probably require multiple applications and more cable. if(istype(I, /obj/item/stack/cable_coil)) + var/obj/item/stack/S = I if(obj_integrity == max_integrity) to_chat(user, "\The [src] doesn't seem to require repairs.") return 1 - if(I.use_tool(src, user, 0, 1)) + if(S.use(1)) to_chat(user, "You patch up \the [src] with a bit of \the [I].") obj_integrity = min(obj_integrity + 10, max_integrity) return 1 if(try_insert(I, user)) - return 1 + return TRUE return ..() +/obj/item/computer_hardware/multitool_act(mob/living/user, obj/item/I) + ..() + to_chat(user, "***** DIAGNOSTICS REPORT *****") + diagnostics(user) + to_chat(user, "******************************") + return TRUE + // Called on multitool click, prints diagnostic information to the user. /obj/item/computer_hardware/proc/diagnostics(var/mob/user) to_chat(user, "Hardware Integrity Test... (Corruption: [damage]/[max_damage]) [damage > damage_failure ? "FAIL" : damage > damage_malfunction ? "WARN" : "PASS"]") diff --git a/code/modules/modular_computers/hardware/ai_slot.dm b/code/modules/modular_computers/hardware/ai_slot.dm index 8428467a87..0ad157afcb 100644 --- a/code/modules/modular_computers/hardware/ai_slot.dm +++ b/code/modules/modular_computers/hardware/ai_slot.dm @@ -9,6 +9,10 @@ var/obj/item/aicard/stored_card = null var/locked = FALSE +/obj/item/computer_hardware/ai_slot/handle_atom_del(atom/A) + if(A == stored_card) + try_eject(0, null, TRUE) + . = ..() /obj/item/computer_hardware/ai_slot/examine(mob/user) . = ..() @@ -41,13 +45,6 @@ /obj/item/computer_hardware/ai_slot/try_eject(slot=0,mob/living/user = null,forced = 0) - if (get_dist(src,user) > 1) - if (iscarbon(user)) - var/mob/living/carbon/H = user - if (!(H.dna && H.dna.check_mutation(TK) && tkMaxRangeCheck(src,H))) - return FALSE - else - return FALSE if(!stored_card) to_chat(user, "There is no card in \the [src].") return FALSE @@ -57,19 +54,21 @@ return FALSE if(stored_card) - stored_card.forceMove(get_turf(src)) + to_chat(user, "You remove [stored_card] from [src].") locked = FALSE - stored_card.verb_pickup() + if(user) + user.put_in_hands(stored_card) + else + stored_card.forceMove(drop_location()) stored_card = null - to_chat(user, "You remove the card from \the [src].") return TRUE return FALSE /obj/item/computer_hardware/ai_slot/attackby(obj/item/I, mob/living/user) if(..()) return - if(istype(I, /obj/item/screwdriver)) + if(I.tool_behaviour == TOOL_SCREWDRIVER) to_chat(user, "You press down on the manual eject button with \the [I].") try_eject(,user,1) - return \ No newline at end of file + return diff --git a/code/modules/modular_computers/hardware/battery_module.dm b/code/modules/modular_computers/hardware/battery_module.dm index e03427cc9c..6e3193abfd 100644 --- a/code/modules/modular_computers/hardware/battery_module.dm +++ b/code/modules/modular_computers/hardware/battery_module.dm @@ -7,6 +7,9 @@ var/obj/item/stock_parts/cell/battery = null device_type = MC_CELL +/obj/item/computer_hardware/battery/get_cell() + return battery + /obj/item/computer_hardware/battery/New(loc, battery_type = null) if(battery_type) battery = new battery_type(src) @@ -16,6 +19,11 @@ . = ..() QDEL_NULL(battery) +/obj/item/computer_hardware/battery/handle_atom_del(atom/A) + if(A == battery) + try_eject(0, null, TRUE) + . = ..() + /obj/item/computer_hardware/battery/try_insert(obj/item/I, mob/living/user = null) if(!holder) return FALSE @@ -45,7 +53,10 @@ to_chat(user, "There is no power cell connected to \the [src].") return FALSE else - battery.forceMove(get_turf(src)) + if(user) + user.put_in_hands(battery) + else + battery.forceMove(drop_location()) to_chat(user, "You detach \the [battery] from \the [src].") battery = null diff --git a/code/modules/modular_computers/hardware/card_slot.dm b/code/modules/modular_computers/hardware/card_slot.dm index e4bc45dbc5..18b423a42e 100644 --- a/code/modules/modular_computers/hardware/card_slot.dm +++ b/code/modules/modular_computers/hardware/card_slot.dm @@ -9,6 +9,13 @@ var/obj/item/card/id/stored_card = null var/obj/item/card/id/stored_card2 = null +/obj/item/computer_hardware/card_slot/handle_atom_del(atom/A) + if(A == stored_card) + try_eject(1, null, TRUE) + if(A == stored_card2) + try_eject(2, null, TRUE) + . = ..() + /obj/item/computer_hardware/card_slot/Destroy() try_eject() return ..() @@ -67,19 +74,15 @@ else stored_card2 = I to_chat(user, "You insert \the [I] into \the [src].") - playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, 0) + playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, FALSE) + if(ishuman(user)) + var/mob/living/carbon/human/H = user + H.sec_hud_set_ID() return TRUE /obj/item/computer_hardware/card_slot/try_eject(slot=0, mob/living/user = null, forced = 0) - if (get_dist(src,user) > 1) - if (iscarbon(user)) - var/mob/living/carbon/H = user - if (!(H.dna && H.dna.check_mutation(TK) && tkMaxRangeCheck(src,H))) - return FALSE - else - return FALSE if(!stored_card && !stored_card2) to_chat(user, "There are no cards in \the [src].") return FALSE @@ -89,7 +92,7 @@ if(user) user.put_in_hands(stored_card) else - stored_card.forceMove(get_turf(src)) + stored_card.forceMove(drop_location()) stored_card = null ejected++ @@ -97,7 +100,7 @@ if(user) user.put_in_hands(stored_card2) else - stored_card2.forceMove(get_turf(src)) + stored_card2.forceMove(drop_location()) stored_card2 = null ejected++ @@ -109,16 +112,18 @@ for(var/I in holder.idle_threads) var/datum/computer_file/program/P = I P.event_idremoved(1, slot) - + if(ishuman(user)) + var/mob/living/carbon/human/H = user + H.sec_hud_set_ID() to_chat(user, "You remove the card[ejected>1 ? "s" : ""] from \the [src].") - playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, 0) + playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, FALSE) return TRUE return FALSE /obj/item/computer_hardware/card_slot/attackby(obj/item/I, mob/living/user) if(..()) return - if(istype(I, /obj/item/screwdriver)) + if(I.tool_behaviour == TOOL_SCREWDRIVER) to_chat(user, "You press down on the manual eject button with \the [I].") try_eject(0,user) return diff --git a/code/modules/modular_computers/hardware/hard_drive.dm b/code/modules/modular_computers/hardware/hard_drive.dm index e27eaa53ae..b8b9624388 100644 --- a/code/modules/modular_computers/hardware/hard_drive.dm +++ b/code/modules/modular_computers/hardware/hard_drive.dm @@ -157,18 +157,30 @@ max_capacity = 64 icon_state = "ssd_mini" w_class = WEIGHT_CLASS_TINY - custom_price = PRICE_ABOVE_NORMAL + custom_price = 150 -/obj/item/computer_hardware/hard_drive/small/syndicate // Syndicate variant - very slight better +// Syndicate variant - very slight better +/obj/item/computer_hardware/hard_drive/small/syndicate desc = "An efficient SSD for portable devices developed by a rival organisation." power_usage = 8 max_capacity = 70 var/datum/antagonist/traitor/traitor_data // Syndicate hard drive has the user's data baked directly into it on creation +/// For tablets given to nuke ops +/obj/item/computer_hardware/hard_drive/small/nukeops + power_usage = 8 + max_capacity = 70 + +/obj/item/computer_hardware/hard_drive/small/nukeops/install_default_programs() + store_file(new/datum/computer_file/program/computerconfig(src)) + store_file(new/datum/computer_file/program/ntnetdownload/syndicate(src)) // Syndicate version; automatic access to syndicate apps and no NT apps + store_file(new/datum/computer_file/program/filemanager(src)) + store_file(new/datum/computer_file/program/radar/fission360(src)) //I am legitimately afraid if I don't do this, Ops players will think they just don't get a pinpointer anymore. + /obj/item/computer_hardware/hard_drive/micro name = "micro solid state drive" desc = "A highly efficient SSD chip for portable devices." power_usage = 2 max_capacity = 32 icon_state = "ssd_micro" - w_class = WEIGHT_CLASS_TINY \ No newline at end of file + w_class = WEIGHT_CLASS_TINY diff --git a/code/modules/modular_computers/hardware/printer.dm b/code/modules/modular_computers/hardware/printer.dm index 36c666e5d6..ebe40c1922 100644 --- a/code/modules/modular_computers/hardware/printer.dm +++ b/code/modules/modular_computers/hardware/printer.dm @@ -10,14 +10,14 @@ /obj/item/computer_hardware/printer/diagnostics(mob/living/user) ..() - to_chat(user, "Paper level: [stored_paper]/[max_paper].") + to_chat(user, "Paper level: [stored_paper]/[max_paper].") /obj/item/computer_hardware/printer/examine(mob/user) . = ..() . += "Paper level: [stored_paper]/[max_paper]." -/obj/item/computer_hardware/printer/proc/print_text(var/text_to_print, var/paper_title = "") +/obj/item/computer_hardware/printer/proc/print_text(text_to_print, paper_title = "") if(!stored_paper) return FALSE if(!check_functionality()) @@ -27,11 +27,12 @@ // Damaged printer causes the resulting paper to be somewhat harder to read. if(damage > damage_malfunction) - P.setText(stars(text_to_print, 100-malfunction_probability)) + P.info = stars(text_to_print, 100-malfunction_probability) else - P.setText(text_to_print) + P.info = text_to_print if(paper_title) P.name = paper_title + P.update_icon() stored_paper-- P = null return TRUE diff --git a/code/modules/modular_computers/laptop_vendor.dm b/code/modules/modular_computers/laptop_vendor.dm index ee9def4191..a8d30bad21 100644 --- a/code/modules/modular_computers/laptop_vendor.dm +++ b/code/modules/modular_computers/laptop_vendor.dm @@ -27,9 +27,6 @@ var/dev_printer = 0 // 0: None, 1: Standard var/dev_card = 0 // 0: None, 1: Standard - ui_x = 500 - ui_y = 400 - // Removes all traces of old order and allows you to begin configuration from scratch. /obj/machinery/lapvend/proc/reset_order() state = 0 @@ -224,15 +221,15 @@ return TRUE return FALSE -/obj/machinery/lapvend/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) +/obj/machinery/lapvend/ui_interact(mob/user, datum/tgui/ui) if(stat & (BROKEN | NOPOWER | MAINT)) if(ui) ui.close() return FALSE - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) + ui = SStgui.try_update_ui(user, src, ui) if (!ui) - ui = new(user, src, ui_key, "ComputerFabricator", "Personal Computer Vendor", ui_x, ui_y, state = state) + ui = new(user, src, "ComputerFabricator") ui.open() /obj/machinery/lapvend/attackby(obj/item/I, mob/user) @@ -241,7 +238,7 @@ if(!user.temporarilyRemoveItemFromInventory(c)) return credits += c.value - visible_message("[user] inserts [c.value] credits into [src].") + visible_message("[user] inserts [c.value] cr into [src].") qdel(c) return else if(istype(I, /obj/item/holochip)) @@ -257,10 +254,10 @@ var/datum/bank_account/account = ID.registered_account var/target_credits = total_price - credits if(!account.adjust_money(-target_credits)) - say("Insufficient money on card to purchase!") + say("Insufficient credits on card to purchase!") return credits += target_credits - say("[target_credits] cr has been desposited from your account.") + say("[target_credits] cr has been deposited from your account.") return return ..() @@ -308,4 +305,4 @@ state = 3 addtimer(CALLBACK(src, .proc/reset_order), 100) return TRUE - return FALSE \ No newline at end of file + return FALSE diff --git a/code/modules/newscaster/ghostread.dm b/code/modules/newscaster/ghostread.dm index 77cb1a03c8..ff51f5268c 100644 --- a/code/modules/newscaster/ghostread.dm +++ b/code/modules/newscaster/ghostread.dm @@ -3,7 +3,7 @@ set desc = "Open a list of available news channels" set category = "Ghost" - var/datum/browser/B = new(src, "ghost_news_list", "Chanenl List", 450, 600) + var/datum/browser/B = new(src, "ghost_news_list", "Channel List", 450, 600) B.set_content(render_news_channel_list()) B.open() diff --git a/code/modules/paperwork/paper.dm b/code/modules/paperwork/paper.dm index 01c25b57f1..5d842ef11a 100644 --- a/code/modules/paperwork/paper.dm +++ b/code/modules/paperwork/paper.dm @@ -1,4 +1,4 @@ -/* +/** * Paper * also scraps of paper * @@ -11,12 +11,11 @@ #define MODE_WRITING 1 #define MODE_STAMPING 2 - /** - ** This is a custom ui state. All it really does is keep track of pen - ** being used and if they are editing it or not. This way we can keep - ** the data with the ui rather than on the paper - **/ + * This is a custom ui state. All it really does is keep track of pen + * being used and if they are editing it or not. This way we can keep + * the data with the ui rather than on the paper + */ /datum/ui_state/default/paper_state /// What edit mode we are in and who is /// writing on it right now @@ -33,7 +32,6 @@ var/stamp_name = "" var/stamp_class = "" - /datum/ui_state/default/paper_state/proc/copy_from(datum/ui_state/default/paper_state/from) switch(from.edit_mode) if(MODE_READING) @@ -49,12 +47,11 @@ stamp_class = from.stamp_class stamp_name = from.stamp_name - /** - ** Paper is now using markdown (like in github pull notes) for ALL rendering - ** so we do loose a bit of functionality but we gain in easy of use of - ** paper and getting rid of that crashing bug - **/ + * Paper is now using markdown (like in github pull notes) for ALL rendering + * so we do loose a bit of functionality but we gain in easy of use of + * paper and getting rid of that crashing bug + */ /obj/item/paper name = "paper" gender = NEUTER @@ -71,6 +68,8 @@ resistance_flags = FLAMMABLE max_integrity = 50 dog_fashion = /datum/dog_fashion/head + // drop_sound = 'sound/items/handling/paper_drop.ogg' + // pickup_sound = 'sound/items/handling/paper_pickup.ogg' grind_results = list(/datum/reagent/cellulose = 3) color = "white" /// What's actually written on the paper. @@ -89,9 +88,6 @@ var/contact_poison // Reagent ID to transfer on contact var/contact_poison_volume = 0 - // ui stuff - var/ui_x = 600 - var/ui_y = 800 // Ok, so WHY are we caching the ui's? // Since we are not using autoupdate we // need some way to update the ui's of @@ -103,7 +99,6 @@ // people look at it var/list/viewing_ui = list() - /// When the sheet can be "filled out" /// This is an associated list var/list/form_fields = list() @@ -116,10 +111,10 @@ . = ..() /** - ** This proc copies this sheet of paper to a new - ** sheet, Makes it nice and easy for carbon and - ** the copyer machine - **/ + * This proc copies this sheet of paper to a new + * sheet, Makes it nice and easy for carbon and + * the copyer machine + */ /obj/item/paper/proc/copy() var/obj/item/paper/N = new(arglist(args)) N.info = info @@ -133,10 +128,10 @@ return N /** - ** This proc sets the text of the paper and updates the - ** icons. You can modify the pen_color after if need - ** be. - **/ + * This proc sets the text of the paper and updates the + * icons. You can modify the pen_color after if need + * be. + */ /obj/item/paper/proc/setText(text) info = text form_fields = null @@ -152,30 +147,16 @@ contact_poison = null . = ..() - /obj/item/paper/Initialize() . = ..() pixel_y = rand(-8, 8) pixel_x = rand(-9, 9) update_icon() - /obj/item/paper/update_icon_state() if(info && show_written_words) icon_state = "[initial(icon_state)]_words" -/obj/item/paper/ui_base_html(html) - /// This might change in a future PR - var/datum/asset/spritesheet/assets = get_asset_datum(/datum/asset/spritesheet/simple/paper) - . = replacetext(html, "", assets.css_tag()) - - -/obj/item/paper/examine_more(mob/user) - ui_interact(user) - -/obj/item/paper/proc/show_content(mob/user) - user.examinate(src) - /obj/item/paper/verb/rename() set name = "Rename paper" set category = "Object" @@ -195,17 +176,14 @@ name = "paper[(n_name ? text("- '[n_name]'") : null)]" add_fingerprint(usr) - /obj/item/paper/suicide_act(mob/user) user.visible_message("[user] scratches a grid on [user.p_their()] wrist with the paper! It looks like [user.p_theyre()] trying to commit sudoku...") return (BRUTELOSS) - /// ONLY USED FOR APRIL FOOLS /obj/item/paper/proc/reset_spamflag() spam_flag = FALSE - /obj/item/paper/attack_self(mob/user) if(rigged && (SSevents.holidays && SSevents.holidays[APRIL_FOOLS])) if(!spam_flag) @@ -214,7 +192,6 @@ addtimer(CALLBACK(src, .proc/reset_spamflag), 20) . = ..() - /obj/item/paper/proc/clearpaper() info = "" stamps = null @@ -222,29 +199,28 @@ cut_overlays() update_icon_state() - -/obj/item/paper/examine(mob/user) +/obj/item/paper/examine_more(mob/user) ui_interact(user) - + return list("You try to read [src]...") /obj/item/paper/can_interact(mob/user) if(!..()) return FALSE - if(resistance_flags & ON_FIRE) // Are we on fire? Hard ot read if so + // Are we on fire? Hard ot read if so + if(resistance_flags & ON_FIRE) return FALSE - if(user.is_blind()) // Even harder to read if your blind...braile? humm + // Even harder to read if your blind...braile? humm + if(user.is_blind()) return FALSE - return user.can_read(src) // checks if the user can read. - + // checks if the user can read. + return user.can_read(src) /** - ** This creates the ui, since we are using a custom state but not much else - ** just makes it easyer to make it. Also we make a custom ui_key as I am - ** not sure how tgui handles many producers? -**/ + * This creates the ui, since we are using a custom state but not much else + * just makes it easyer to make it. + */ /obj/item/paper/proc/create_ui(mob/user, datum/ui_state/default/paper_state/state) - ui_interact(user, "main", null, FALSE, null, state) - + ui_interact(user, state = state) /obj/item/proc/burn_paper_product_attackby_check(obj/item/I, mob/living/user, bypass_clumsy) var/ignition_message = I.ignition_effect(src, user) @@ -320,24 +296,27 @@ if(.) info = "[stars(info)]" -/obj/item/paper/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/default/paper_state/state = new) - ui_key = "main-[REF(user)]" - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) +/obj/item/paper/ui_assets(mob/user) + return list( + get_asset_datum(/datum/asset/spritesheet/simple/paper), + ) + +/obj/item/paper/ui_interact(mob/user, datum/tgui/ui, + datum/ui_state/default/paper_state/state) + // Update the state + ui = ui || SStgui.get_open_ui(user, src) + if(ui && state) + var/datum/ui_state/default/paper_state/current_state = ui.state + current_state.copy_from(state) + // Update the UI + ui = SStgui.try_update_ui(user, src, ui) if(!ui) - var/datum/asset/assets = get_asset_datum(/datum/asset/spritesheet/simple/paper) - assets.send(user) - // The x size is because we double the width for the editor - ui = new(user, src, ui_key, "PaperSheet", name, ui_x, ui_y, master_ui, state) + ui = new(user, src, "PaperSheet", name) + state = new + ui.set_state(state) ui.set_autoupdate(FALSE) viewing_ui[user] = ui ui.open() - else - var/datum/ui_state/default/paper_state/last_state = ui.state - if(last_state) - last_state.copy_from(state) - else - ui.state = state - /obj/item/paper/ui_close(mob/user) /// close the editing window and change the mode @@ -347,7 +326,7 @@ // Again, we have to do this as autoupdate is off /obj/item/paper/proc/update_all_ui() for(var/datum/tgui/ui in viewing_ui) - ui.update() + ui.process(force = TRUE) // Again, we have to do this as autoupdate is off /obj/item/paper/proc/close_all_ui() @@ -383,7 +362,6 @@ return data - /obj/item/paper/ui_act(action, params, datum/tgui/ui, datum/ui_state/default/paper_state/state) if(..()) return @@ -445,21 +423,18 @@ . = TRUE - -/* +/** * Construction paper */ - /obj/item/paper/construction /obj/item/paper/construction/Initialize() . = ..() color = pick("FF0000", "#33cc33", "#ffb366", "#551A8B", "#ff80d5", "#4d94ff") -/* +/** * Natural paper */ - /obj/item/paper/natural/Initialize() . = ..() color = "#FFF5ED" diff --git a/code/modules/paperwork/pen.dm b/code/modules/paperwork/pen.dm index 997ada6b21..91b8a6719b 100644 --- a/code/modules/paperwork/pen.dm +++ b/code/modules/paperwork/pen.dm @@ -147,7 +147,7 @@ log_game("[user] [key_name(user)] has renamed [O] to [input]") if(penchoice == "Change description") - var/input = stripped_input(user,"Describe \the [O.name] here", ,"", 100) + var/input = stripped_input(user,"Describe \the [O.name] here", ,"", 2048) if(QDELETED(O) || !user.canUseTopic(O, BE_CLOSE)) return O.desc = input diff --git a/code/modules/plumbing/ducts.dm b/code/modules/plumbing/ducts.dm new file mode 100644 index 0000000000..8a27f2669c --- /dev/null +++ b/code/modules/plumbing/ducts.dm @@ -0,0 +1,433 @@ +/* +All the important duct code: +/code/datums/components/plumbing/plumbing.dm +/code/datums/ductnet.dm +*/ +/obj/machinery/duct + name = "fluid duct" + icon = 'icons/obj/plumbing/fluid_ducts.dmi' + icon_state = "nduct" + + ///bitfield with the directions we're connected in + var/connects + ///set to TRUE to disable smart duct behaviour + var/dumb = FALSE + ///wheter we allow our connects to be changed after initialization or not + var/lock_connects = FALSE + ///our ductnet, wich tracks what we're connected to + var/datum/ductnet/duct + ///amount we can transfer per process. note that the ductnet can carry as much as the lowest capacity duct + var/capacity = 10 + + ///the color of our duct + var/duct_color = null + ///TRUE to ignore colors, so yeah we also connect with other colors without issue + var/ignore_colors = FALSE + ///1,2,4,8,16 + var/duct_layer = DUCT_LAYER_DEFAULT + ///whether we allow our layers to be altered + var/lock_layers = FALSE + ///TRUE to let colors connect when forced with a wrench, false to just not do that at all + var/color_to_color_support = TRUE + ///wheter to even bother with plumbing code or not + var/active = TRUE + ///track ducts we're connected to. Mainly for ducts we connect to that we normally wouldn't, like different layers and colors, for when we regenerate the ducts + var/list/neighbours = list() + ///wheter we just unanchored or drop whatever is in the variable. either is safe + var/drop_on_wrench = /obj/item/stack/ducts + +/obj/machinery/duct/Initialize(mapload, no_anchor, color_of_duct = "#ffffff", layer_of_duct = DUCT_LAYER_DEFAULT, force_connects) + . = ..() + + if(no_anchor) + active = FALSE + set_anchored(FALSE) + else if(!can_anchor()) + qdel(src) + CRASH("Overlapping ducts detected") + + if(force_connects) + connects = force_connects //skip change_connects() because we're still initializing and we need to set our connects at one point + if(!lock_layers) + duct_layer = layer_of_duct + if(!ignore_colors) + duct_color = color_of_duct + if(duct_color) + add_atom_colour(duct_color, FIXED_COLOUR_PRIORITY) + + handle_layer() + + for(var/obj/machinery/duct/D in loc) + if(D == src) + continue + if(D.duct_layer & duct_layer) + disconnect_duct() + + if(active) + attempt_connect() + + +///start looking around us for stuff to connect to +/obj/machinery/duct/proc/attempt_connect() + + for(var/atom/movable/AM in loc) + var/datum/component/plumbing/P = AM.GetComponent(/datum/component/plumbing) + if(P?.active) + disconnect_duct() //let's not built under plumbing machinery + return + for(var/D in GLOB.cardinals) + if(dumb && !(D & connects)) + continue + for(var/atom/movable/AM in get_step(src, D)) + if(connect_network(AM, D)) + add_connects(D) + update_icon() + +///see if whatever we found can be connected to +/obj/machinery/duct/proc/connect_network(atom/movable/AM, direction, ignore_color) + if(istype(AM, /obj/machinery/duct)) + return connect_duct(AM, direction, ignore_color) + + var/plumber = AM.GetComponent(/datum/component/plumbing) + if(!plumber) + return + return connect_plumber(plumber, direction) + +///connect to a duct +/obj/machinery/duct/proc/connect_duct(obj/machinery/duct/D, direction, ignore_color) + var/opposite_dir = turn(direction, 180) + if(!active || !D.active) + return + + if(!dumb && D.dumb && !(opposite_dir & D.connects)) + return + if(dumb && D.dumb && !(connects & D.connects)) //we eliminated a few more scenarios in attempt connect + return + + if((duct == D.duct) && duct)//check if we're not just comparing two null values + add_neighbour(D, direction) + + D.add_connects(opposite_dir) + D.update_icon() + return TRUE //tell the current pipe to also update it's sprite + if(!(D in neighbours)) //we cool + if((duct_color != D.duct_color) && !(ignore_colors || D.ignore_colors)) + return + if(!(duct_layer & D.duct_layer)) + return + + if(D.duct) + if(duct) + duct.assimilate(D.duct) + else + D.duct.add_duct(src) + else + if(duct) + duct.add_duct(D) + else + create_duct() + duct.add_duct(D) + add_neighbour(D, direction) + //tell our buddy its time to pass on the torch of connecting to pipes. This shouldn't ever infinitely loop since it only works on pipes that havent been inductrinated + D.attempt_connect() + + return TRUE + +///connect to a plumbing object +/obj/machinery/duct/proc/connect_plumber(datum/component/plumbing/P, direction) + var/opposite_dir = turn(direction, 180) + if(duct_layer != DUCT_LAYER_DEFAULT) //plumbing devices don't support multilayering. 3 is the default layer so we only use that. We can change this later + return FALSE + + if(!P.active) + return + + var/comp_directions = P.supply_connects + P.demand_connects //they should never, ever have supply and demand connects overlap or catastrophic failure + if(opposite_dir & comp_directions) + if(!duct) + create_duct() + if(duct.add_plumber(P, opposite_dir)) + neighbours[P.parent] = direction + return TRUE + +///we disconnect ourself from our neighbours. we also destroy our ductnet and tell our neighbours to make a new one +/obj/machinery/duct/proc/disconnect_duct(skipanchor) + if(!skipanchor) //since set_anchored calls us too. + set_anchored(FALSE) + active = FALSE + if(duct) + duct.remove_duct(src) + lose_neighbours() + reset_connects(0) + update_icon() + if(ispath(drop_on_wrench) && !QDELING(src)) + new drop_on_wrench(drop_location()) + qdel(src) + +///''''''''''''''''optimized''''''''''''''''' proc for quickly reconnecting after a duct net was destroyed +/obj/machinery/duct/proc/reconnect() + if(neighbours.len && !duct) + create_duct() + for(var/atom/movable/AM in neighbours) + if(istype(AM, /obj/machinery/duct)) + var/obj/machinery/duct/D = AM + if(D.duct) + if(D.duct == duct) //we're already connected + continue + else + duct.assimilate(D.duct) + continue + else + duct.add_duct(D) + D.reconnect() + else + var/datum/component/plumbing/P = AM.GetComponent(/datum/component/plumbing) + if(AM in get_step(src, neighbours[AM])) //did we move? + if(P) + connect_plumber(P, neighbours[AM]) + else + neighbours -= AM //we moved + +///Special proc to draw a new connect frame based on neighbours. not the norm so we can support multiple duct kinds +/obj/machinery/duct/proc/generate_connects() + if(lock_connects) + return + connects = 0 + for(var/A in neighbours) + connects |= neighbours[A] + update_icon() + +///create a new duct datum +/obj/machinery/duct/proc/create_duct() + duct = new() + duct.add_duct(src) + +///add a duct as neighbour. this means we're connected and will connect again if we ever regenerate +/obj/machinery/duct/proc/add_neighbour(obj/machinery/duct/D, direction) + if(!(D in neighbours)) + neighbours[D] = direction + if(!(src in D.neighbours)) + D.neighbours[src] = turn(direction, 180) + +///remove all our neighbours, and remove us from our neighbours aswell +/obj/machinery/duct/proc/lose_neighbours() + for(var/obj/machinery/duct/D in neighbours) + D.neighbours.Remove(src) + neighbours = list() + +///add a connect direction +/obj/machinery/duct/proc/add_connects(new_connects) //make this a define to cut proc calls? + if(!lock_connects) + connects |= new_connects + +///remove a connect direction +/obj/machinery/duct/proc/remove_connects(dead_connects) + if(!lock_connects) + connects &= ~dead_connects + +///remove our connects +/obj/machinery/duct/proc/reset_connects() + if(!lock_connects) + connects = 0 + +///get a list of the ducts we can connect to if we are dumb +/obj/machinery/duct/proc/get_adjacent_ducts() + var/list/adjacents = list() + for(var/A in GLOB.cardinals) + if(A & connects) + for(var/obj/machinery/duct/D in get_step(src, A)) + if((turn(A, 180) & D.connects) && D.active) + adjacents += D + return adjacents + +/obj/machinery/duct/update_icon_state() + var/temp_icon = initial(icon_state) + for(var/D in GLOB.cardinals) + if(D & connects) + if(D == NORTH) + temp_icon += "_n" + if(D == SOUTH) + temp_icon += "_s" + if(D == EAST) + temp_icon += "_e" + if(D == WEST) + temp_icon += "_w" + icon_state = temp_icon + +///update the layer we are on +/obj/machinery/duct/proc/handle_layer() + var/offset + switch(duct_layer)//it's a bitfield, but it's fine because it only works when there's one layer, and multiple layers should be handled differently + if(FIRST_DUCT_LAYER) + offset = -10 + if(SECOND_DUCT_LAYER) + offset = -5 + if(THIRD_DUCT_LAYER) + offset = 0 + if(FOURTH_DUCT_LAYER) + offset = 5 + if(FIFTH_DUCT_LAYER) + offset = 10 + pixel_x = offset + pixel_y = offset + + +/obj/machinery/duct/set_anchored(anchorvalue) + . = ..() + if(isnull(.)) + return + if(anchorvalue) + active = TRUE + attempt_connect() + else + disconnect_duct(TRUE) + +/obj/machinery/duct/wrench_act(mob/living/user, obj/item/I) //I can also be the RPD + ..() + add_fingerprint(user) + I.play_tool_sound(src) + if(anchored || can_anchor()) + set_anchored(!anchored) + user.visible_message( \ + "[user] [anchored ? null : "un"]fastens \the [src].", \ + "You [anchored ? null : "un"]fasten \the [src].", \ + "You hear ratcheting.") + return TRUE +///collection of all the sanity checks to prevent us from stacking ducts that shouldn't be stacked +/obj/machinery/duct/proc/can_anchor(turf/T) + if(!T) + T = get_turf(src) + for(var/obj/machinery/duct/D in T) + if(!anchored || D == src) + continue + for(var/A in GLOB.cardinals) + if(A & connects && A & D.connects) + return FALSE + return TRUE + +/obj/machinery/duct/doMove(destination) + . = ..() + disconnect_duct() + anchored = FALSE + +/obj/machinery/duct/Destroy() + disconnect_duct() + return ..() + +/obj/machinery/duct/MouseDrop_T(atom/A, mob/living/user) + if(!istype(A, /obj/machinery/duct)) + return + var/obj/machinery/duct/D = A + var/obj/item/I = user.get_active_held_item() + if(I?.tool_behaviour != TOOL_WRENCH) + to_chat(user, "You need to be holding a wrench in your active hand to do that!") + return + if(get_dist(src, D) != 1) + return + var/direction = get_dir(src, D) + if(!(direction in GLOB.cardinals)) + return + if(duct_layer != D.duct_layer) + return + + add_connects(direction) //the connect of the other duct is handled in connect_network, but do this here for the parent duct because it's not necessary in normal cases + add_neighbour(D, direction) + connect_network(D, direction, TRUE) + update_icon() + +///has a total of 5 layers and doesnt give a shit about color. its also dumb so doesnt autoconnect. +/obj/machinery/duct/multilayered + name = "duct layer-manifold" + icon = 'icons/obj/2x2.dmi' + icon_state = "multiduct" + pixel_x = -15 + pixel_y = -15 + + color_to_color_support = FALSE + duct_layer = FIRST_DUCT_LAYER | SECOND_DUCT_LAYER | THIRD_DUCT_LAYER | FOURTH_DUCT_LAYER | FIFTH_DUCT_LAYER + drop_on_wrench = null + + lock_connects = TRUE + lock_layers = TRUE + ignore_colors = TRUE + dumb = TRUE + + active = FALSE + anchored = FALSE + +/obj/machinery/duct/multilayered/Initialize(mapload, no_anchor, color_of_duct, layer_of_duct = DUCT_LAYER_DEFAULT, force_connects) + . = ..() + update_connects() + +/obj/machinery/duct/multilayered/ComponentInitialize() + . = ..() + AddElement(/datum/element/update_icon_blocker) + +/obj/machinery/duct/multilayered/wrench_act(mob/living/user, obj/item/I) + . = ..() + update_connects() + +/obj/machinery/duct/multilayered/proc/update_connects() + if(dir & NORTH || dir & SOUTH) + connects = NORTH | SOUTH + else + connects = EAST | WEST + +///don't connect to other multilayered stuff because honestly it shouldn't be done and I dont wanna deal with it +/obj/machinery/duct/multilayered/connect_duct(obj/machinery/duct/D, direction, ignore_color) + if(istype(D, /obj/machinery/duct/multilayered)) + return + return ..() + +/obj/machinery/duct/multilayered/handle_layer() + return + +/obj/item/stack/ducts + name = "stack of duct" + desc = "A stack of fluid ducts." + singular_name = "duct" + icon = 'icons/obj/plumbing/fluid_ducts.dmi' + icon_state = "ducts" + custom_materials = list(/datum/material/iron=500) + w_class = WEIGHT_CLASS_TINY + novariants = FALSE + max_amount = 50 + item_flags = NOBLUDGEON + merge_type = /obj/item/stack/ducts + ///Color of our duct + var/duct_color = "grey" + ///Default layer of our duct + var/duct_layer = "Default Layer" + ///Assoc index with all the available layers. yes five might be a bit much. Colors uses a global by the way + var/list/layers = list("First Layer" = FIRST_DUCT_LAYER, "Second Layer" = SECOND_DUCT_LAYER, "Default Layer" = DUCT_LAYER_DEFAULT, + "Fourth Layer" = FOURTH_DUCT_LAYER, "Fifth Layer" = FIFTH_DUCT_LAYER) + +/obj/item/stack/ducts/examine(mob/user) + . = ..() + . += "It's current color and layer are [duct_color] and [duct_layer]. Use in-hand to change." + +/obj/item/stack/ducts/attack_self(mob/user) + var/new_layer = input("Select a layer", "Layer") as null|anything in layers + if(new_layer) + duct_layer = new_layer + var/new_color = input("Select a color", "Color") as null|anything in GLOB.pipe_paint_colors + if(new_color) + duct_color = new_color + add_atom_colour(GLOB.pipe_paint_colors[new_color], FIXED_COLOUR_PRIORITY) + +/obj/item/stack/ducts/afterattack(atom/A, user, proximity) + . = ..() + if(!proximity) + return + if(istype(A, /obj/machinery/duct)) + var/obj/machinery/duct/D = A + if(!D.anchored) + add(1) + qdel(D) + if(istype(A, /turf/open) && use(1)) + var/turf/open/OT = A + new /obj/machinery/duct(OT, FALSE, GLOB.pipe_paint_colors[duct_color], layers[duct_layer]) + playsound(get_turf(src), 'sound/machines/click.ogg', 50, TRUE) + +/obj/item/stack/ducts/fifty + amount = 50 diff --git a/code/modules/plumbing/plumbers/_plumb_machinery.dm b/code/modules/plumbing/plumbers/_plumb_machinery.dm new file mode 100644 index 0000000000..0566945e3b --- /dev/null +++ b/code/modules/plumbing/plumbers/_plumb_machinery.dm @@ -0,0 +1,98 @@ +/**Basic plumbing object. +* It doesn't really hold anything special, YET. +* Objects that are plumbing but not a subtype are as of writing liquid pumps and the reagent_dispenser tank +* Also please note that the plumbing component is toggled on and off by the component using a signal from default_unfasten_wrench, so dont worry about it +*/ +/obj/machinery/plumbing + name = "pipe thing" + icon = 'icons/obj/plumbing/plumbers.dmi' + icon_state = "pump" + density = TRUE + active_power_usage = 30 + use_power = ACTIVE_POWER_USE + resistance_flags = FIRE_PROOF | UNACIDABLE | ACID_PROOF + ///Plumbing machinery is always gonna need reagents, so we might aswell put it here + var/buffer = 50 + ///Flags for reagents, like INJECTABLE, TRANSPARENT bla bla everything thats in DEFINES/reagents.dm + var/reagent_flags = TRANSPARENT + ///wheter we partake in rcd construction or not + var/rcd_constructable = TRUE + ///cost of the plumbing rcd construction + var/rcd_cost = 15 + ///delay of constructing it throught the plumbing rcd + var/rcd_delay = 10 + +/obj/machinery/plumbing/Initialize(mapload, bolt = TRUE) + . = ..() + anchored = bolt + create_reagents(buffer, reagent_flags) + AddComponent(/datum/component/simple_rotation, ROTATION_ALTCLICK | ROTATION_CLOCKWISE | ROTATION_COUNTERCLOCKWISE | ROTATION_VERBS, null, CALLBACK(src, .proc/can_be_rotated)) + +/obj/machinery/plumbing/proc/can_be_rotated(mob/user,rotation_type) + return TRUE + + +/obj/machinery/plumbing/examine(mob/user) + . = ..() + . += "The maximum volume display reads: [reagents.maximum_volume] units." + +/obj/machinery/plumbing/wrench_act(mob/living/user, obj/item/I) + ..() + default_unfasten_wrench(user, I) + return TRUE + +/obj/machinery/plumbing/plunger_act(obj/item/plunger/P, mob/living/user, reinforced) + to_chat(user, "You start furiously plunging [name].") + if(do_after(user, 30, target = src)) + to_chat(user, "You finish plunging the [name].") + reagents.reaction(get_turf(src), TOUCH) //splash on the floor + reagents.clear_reagents() + +/obj/machinery/plumbing/welder_act(mob/living/user, obj/item/I) + . = ..() + if(anchored) + to_chat(user, "The [name] needs to be unbolted to do that!You start slicing the [name] apart.You slice the [name] apart. target_temperature && acclimate_state != COOLING) + acclimate_state = COOLING + update_icon() + if(!emptying) + if(reagents.chem_temp >= target_temperature && target_temperature + allowed_temperature_difference >= reagents.chem_temp) //cooling here + emptying = TRUE + if(reagents.chem_temp <= target_temperature && target_temperature - allowed_temperature_difference <= reagents.chem_temp) //heating here + emptying = TRUE + + reagents.adjust_thermal_energy((target_temperature - reagents.chem_temp) * heater_coefficient * SPECIFIC_HEAT_DEFAULT * reagents.total_volume) //keep constant with chem heater + reagents.handle_reactions() + +/obj/machinery/plumbing/acclimator/update_icon() + icon_state = initial(icon_state) + switch(acclimate_state) + if(COOLING) + icon_state += "_cold" + if(HEATING) + icon_state += "_hot" + +/obj/machinery/plumbing/acclimator/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "ChemAcclimator", name) + ui.open() + +/obj/machinery/plumbing/acclimator/ui_data(mob/user) + var/list/data = list() + + data["enabled"] = enabled + data["chem_temp"] = reagents.chem_temp + data["target_temperature"] = target_temperature + data["allowed_temperature_difference"] = allowed_temperature_difference + data["acclimate_state"] = acclimate_state + data["max_volume"] = reagents.maximum_volume + data["reagent_volume"] = reagents.total_volume + data["emptying"] = emptying + return data + +/obj/machinery/plumbing/acclimator/ui_act(action, params) + if(..()) + return + . = TRUE + switch(action) + if("set_target_temperature") + var/target = text2num(params["temperature"]) + target_temperature = clamp(target, 0, 1000) + if("set_allowed_temperature_difference") + var/target = text2num(params["temperature"]) + allowed_temperature_difference = clamp(target, 0, 1000) + if("toggle_power") + enabled = !enabled + if("change_volume") + var/target = text2num(params["volume"]) + reagents.maximum_volume = clamp(round(target), 1, buffer) + +#undef COOLING +#undef HEATING +#undef NEUTRAL diff --git a/code/modules/plumbing/plumbers/autohydro.dm b/code/modules/plumbing/plumbers/autohydro.dm new file mode 100644 index 0000000000..dbc70dfcf5 --- /dev/null +++ b/code/modules/plumbing/plumbers/autohydro.dm @@ -0,0 +1,65 @@ +/obj/machinery/hydroponics/constructable/automagic + name = "automated hydroponics system" + desc = "The bane of botanists everywhere. Accepts chemical reagents via plumbing, automatically harvests and removes dead plants." + obj_flags = CAN_BE_HIT | UNIQUE_RENAME + circuit = /obj/item/circuitboard/machine/hydroponics/automagic + self_sufficiency_req = 400 //automating hydroponics makes gaia sad so she needs more drugs to turn they tray godly. + canirrigate = FALSE + + +/obj/machinery/hydroponics/constructable/automagic/attackby(obj/item/O, mob/user, params) + if(istype(O, /obj/item/reagent_containers)) + return FALSE //avoid fucky wuckies + ..() + +/obj/machinery/hydroponics/constructable/automagic/default_unfasten_wrench(mob/user, obj/item/I, time = 20) + . = ..() + if(. == SUCCESSFUL_UNFASTEN) + user.visible_message("[user.name] [anchored ? "fasten" : "unfasten"] [src]", \ + "You [anchored ? "fasten" : "unfasten"] [src]") + var/datum/component/plumbing/CP = GetComponent(/datum/component/plumbing) + if(anchored) + CP.enable() + else + CP.disable() + +/obj/machinery/hydroponics/constructable/automagic/Destroy() + . = ..() + STOP_PROCESSING(SSobj, src) + +/obj/machinery/hydroponics/constructable/automagic/Initialize(mapload) + . = ..() + START_PROCESSING(SSobj, src) + create_reagents(100 , AMOUNT_VISIBLE) + +/obj/machinery/hydroponics/constructable/automagic/ComponentInitialize() + . = ..() + AddComponent(/datum/component/simple_rotation, ROTATION_ALTCLICK | ROTATION_CLOCKWISE | ROTATION_COUNTERCLOCKWISE | ROTATION_VERBS, null, CALLBACK(src, .proc/can_be_rotated)) + AddComponent(/datum/component/plumbing/simple_demand) + +/obj/machinery/hydroponics/constructable/proc/can_be_rotated(mob/user, rotation_type) + return !anchored + +/obj/machinery/hydroponics/constructable/automagic/process() + if(reagents) + applyChemicals(reagents) + reagents.clear_reagents() + if(dead) + dead = 0 + qdel(myseed) + myseed = null + update_icon() + name = initial(name) + desc = initial(desc) + if(harvest) + myseed.harvest_userless() + harvest = 0 + lastproduce = age + if(!myseed.get_gene(/datum/plant_gene/trait/repeated_harvest)) + qdel(myseed) + myseed = null + dead = 0 + name = initial(name) + desc = initial(desc) + update_icon() + ..() diff --git a/code/modules/plumbing/plumbers/bottler.dm b/code/modules/plumbing/plumbers/bottler.dm new file mode 100644 index 0000000000..396c7cac22 --- /dev/null +++ b/code/modules/plumbing/plumbers/bottler.dm @@ -0,0 +1,79 @@ +/obj/machinery/plumbing/bottler + name = "chemical bottler" + desc = "Puts reagents into containers, like bottles and beakers." + icon_state = "bottler" + layer = ABOVE_ALL_MOB_LAYER + reagent_flags = TRANSPARENT | DRAINABLE + rcd_cost = 50 + rcd_delay = 50 + buffer = 100 + ///how much do we fill + var/wanted_amount = 10 + ///where things are sent + var/turf/goodspot = null + ///where things are taken + var/turf/inputspot = null + ///where beakers that are already full will be sent + var/turf/badspot = null + +/obj/machinery/plumbing/bottler/Initialize(mapload, bolt) + . = ..() + AddComponent(/datum/component/plumbing/simple_demand, bolt) + setDir(dir) + +/obj/machinery/plumbing/bottler/can_be_rotated(mob/user, rotation_type) + if(anchored) + to_chat(user, "It is fastened to the floor!") + return FALSE + return TRUE + +///changes the tile array +/obj/machinery/plumbing/bottler/setDir(newdir) + . = ..() + switch(dir) + if(NORTH) + goodspot = get_step(get_turf(src), NORTH) + inputspot = get_step(get_turf(src), SOUTH) + badspot = get_step(get_turf(src), EAST) + if(SOUTH) + goodspot = get_step(get_turf(src), SOUTH) + inputspot = get_step(get_turf(src), NORTH) + badspot = get_step(get_turf(src), WEST) + if(WEST) + goodspot = get_step(get_turf(src), WEST) + inputspot = get_step(get_turf(src), EAST) + badspot = get_step(get_turf(src), NORTH) + if(EAST) + goodspot = get_step(get_turf(src), EAST) + inputspot = get_step(get_turf(src), WEST) + badspot = get_step(get_turf(src), SOUTH) + +///changing input ammount with a window +/obj/machinery/plumbing/bottler/interact(mob/user) + . = ..() + wanted_amount = clamp(round(input(user,"maximum is 100u","set ammount to fill with") as num|null, 1), 1, 100) + reagents.clear_reagents() + to_chat(user, " The [src] will now fill for [wanted_amount]u.") + +/obj/machinery/plumbing/bottler/process() + if(stat & NOPOWER) + return + ///see if machine has enough to fill + if(reagents.total_volume >= wanted_amount && anchored) + var/obj/AM = pick(inputspot.contents)///pick a reagent_container that could be used + if(istype(AM, /obj/item/reagent_containers) && (!istype(AM, /obj/item/reagent_containers/hypospray/medipen))) + var/obj/item/reagent_containers/B = AM + ///see if it would overflow else inject + if((B.reagents.total_volume + wanted_amount) <= B.reagents.maximum_volume) + reagents.trans_to(B, wanted_amount) + B.forceMove(goodspot) + return + ///glass was full so we move it away + AM.forceMove(badspot) + if(istype(AM, /obj/item/slime_extract)) ///slime extracts need inject + AM.forceMove(goodspot) + reagents.trans_to(AM, wanted_amount) + return + if(istype(AM, /obj/item/slimecross/industrial)) ///no need to move slimecross industrial things + reagents.trans_to(AM, wanted_amount) + return diff --git a/code/modules/plumbing/plumbers/destroyer.dm b/code/modules/plumbing/plumbers/destroyer.dm new file mode 100644 index 0000000000..b61383ea4a --- /dev/null +++ b/code/modules/plumbing/plumbers/destroyer.dm @@ -0,0 +1,21 @@ +/obj/machinery/plumbing/disposer + name = "chemical disposer" + desc = "Breaks down chemicals and annihilates them." + icon_state = "disposal" + ///we remove 10 reagents per second + var/disposal_rate = 10 + +/obj/machinery/plumbing/disposer/Initialize(mapload, bolt) + . = ..() + AddComponent(/datum/component/plumbing/simple_demand, bolt) + +/obj/machinery/plumbing/disposer/process() + if(stat & NOPOWER) + return + if(reagents.total_volume) + if(icon_state != initial(icon_state) + "_working") //threw it here instead of update icon since it only has two states + icon_state = initial(icon_state) + "_working" + reagents.remove_any(disposal_rate) + else + if(icon_state != initial(icon_state)) + icon_state = initial(icon_state) diff --git a/code/modules/plumbing/plumbers/fermenter.dm b/code/modules/plumbing/plumbers/fermenter.dm new file mode 100644 index 0000000000..b1e1e4b676 --- /dev/null +++ b/code/modules/plumbing/plumbers/fermenter.dm @@ -0,0 +1,59 @@ +/obj/machinery/plumbing/fermenter //FULLY AUTOMATIC BEER BREWING. TRULY, THE FUTURE. + name = "chemical fermenter" + desc = "Turns plants into various types of booze." + icon_state = "fermenter" + layer = ABOVE_ALL_MOB_LAYER + reagent_flags = TRANSPARENT | DRAINABLE + rcd_cost = 30 + rcd_delay = 30 + buffer = 400 + ///input dir + var/eat_dir = SOUTH + +/obj/machinery/plumbing/fermenter/Initialize(mapload, bolt) + . = ..() + AddComponent(/datum/component/plumbing/simple_supply, bolt) + +/obj/machinery/plumbing/fermenter/can_be_rotated(mob/user,rotation_type) + if(anchored) + to_chat(user, "It is fastened to the floor!") + return FALSE + switch(eat_dir) + if(WEST) + eat_dir = NORTH + return TRUE + if(EAST) + eat_dir = SOUTH + return TRUE + if(NORTH) + eat_dir = EAST + return TRUE + if(SOUTH) + eat_dir = WEST + return TRUE + +/obj/machinery/plumbing/fermenter/CanPass(atom/movable/AM) + . = ..() + if(!anchored) + return + var/move_dir = get_dir(loc, AM.loc) + if(move_dir == eat_dir) + return TRUE + +/obj/machinery/plumbing/fermenter/Crossed(atom/movable/AM) + . = ..() + ferment(AM) + +/obj/machinery/plumbing/fermenter/proc/ferment(atom/AM) + if(stat & NOPOWER) + return + if(reagents.holder_full()) + return + if(!isitem(AM)) + return + if(istype(AM, /obj/item/reagent_containers/food/snacks/grown)) + var/obj/item/reagent_containers/food/snacks/grown/G = AM + if(G.distill_reagent) + var/amount = G.seed.potency * 0.25 + reagents.add_reagent(G.distill_reagent, amount) + qdel(G) diff --git a/code/modules/plumbing/plumbers/filter.dm b/code/modules/plumbing/plumbers/filter.dm new file mode 100644 index 0000000000..1ffd170507 --- /dev/null +++ b/code/modules/plumbing/plumbers/filter.dm @@ -0,0 +1,65 @@ +///chemical plumbing filter. If it's not filtered by left and right, it goes straight. +/obj/machinery/plumbing/filter + name = "chemical filter" + desc = "A chemical filter for filtering chemicals. The left and right outputs appear to be from the perspective of the input port." + icon_state = "filter" + density = FALSE + + ///whitelist of chems id's that go to the left side. Empty to disable port + var/list/left = list() + ///whitelist of chem id's that go to the right side. Empty to disable port + var/list/right = list() + ///whitelist of chems but their name instead of path + var/list/english_left = list() + ///whitelist of chems but their name instead of path + var/list/english_right = list() + +/obj/machinery/plumbing/filter/Initialize(mapload, bolt) + . = ..() + AddComponent(/datum/component/plumbing/filter, bolt) + +/obj/machinery/plumbing/filter/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "ChemFilter", name) + ui.open() + +/obj/machinery/plumbing/filter/ui_data(mob/user) + var/list/data = list() + data["left"] = english_left + data["right"] = english_right + return data + +/obj/machinery/plumbing/filter/ui_act(action, params) + if(..()) + return + . = TRUE + switch(action) + if("add") + var/new_chem_name = params["name"] + var/chem_id = get_chem_id(new_chem_name) + if(chem_id) + switch(params["which"]) + if("left") + if(!left.Find(chem_id)) + english_left += new_chem_name + left += chem_id + if("right") + if(!right.Find(chem_id)) + english_right += new_chem_name + right += chem_id + else + to_chat(usr, "No such known reagent exists!") + + if("remove") + var/chem_name = params["reagent"] + var/chem_id = get_chem_id(chem_name) + switch(params["which"]) + if("left") + if(english_left.Find(chem_name)) + english_left -= chem_name + left -= chem_id + if("right") + if(english_right.Find(chem_name)) + english_right -= chem_name + right -= chem_id diff --git a/code/modules/plumbing/plumbers/grinder_chemical.dm b/code/modules/plumbing/plumbers/grinder_chemical.dm new file mode 100644 index 0000000000..f39c79f906 --- /dev/null +++ b/code/modules/plumbing/plumbers/grinder_chemical.dm @@ -0,0 +1,64 @@ +/obj/machinery/plumbing/grinder_chemical + name = "chemical grinder" + desc = "chemical grinder." + icon_state = "grinder_chemical" + layer = ABOVE_ALL_MOB_LAYER + reagent_flags = TRANSPARENT | DRAINABLE + rcd_cost = 30 + rcd_delay = 30 + buffer = 400 + var/eat_dir = NORTH + +/obj/machinery/plumbing/grinder_chemical/Initialize(mapload, bolt) + . = ..() + AddComponent(/datum/component/plumbing/simple_supply, bolt) + +/obj/machinery/plumbing/grinder_chemical/can_be_rotated(mob/user,rotation_type) + if(anchored) + to_chat(user, "It is fastened to the floor!") + return FALSE + switch(eat_dir) + if(WEST) + eat_dir = NORTH + return TRUE + if(EAST) + eat_dir = SOUTH + return TRUE + if(NORTH) + eat_dir = EAST + return TRUE + if(SOUTH) + eat_dir = WEST + return TRUE + +/obj/machinery/plumbing/grinder_chemical/CanPass(atom/movable/AM) + . = ..() + if(!anchored) + return + var/move_dir = get_dir(loc, AM.loc) + if(move_dir == eat_dir) + return TRUE + +/obj/machinery/plumbing/grinder_chemical/Crossed(atom/movable/AM) + . = ..() + grind(AM) + +/obj/machinery/plumbing/grinder_chemical/proc/grind(atom/AM) + if(stat & NOPOWER) + return + if(reagents.holder_full()) + return + if(!isitem(AM)) + return + var/obj/item/I = AM + if(I.juice_results || I.grind_results) + if(I.juice_results) + I.on_juice() + reagents.add_reagent_list(I.juice_results) + if(I.reagents) + I.reagents.trans_to(src, I.reagents.total_volume) + qdel(I) + return + I.on_grind() + reagents.add_reagent_list(I.grind_results) + qdel(I) diff --git a/code/modules/plumbing/plumbers/medipenrefill.dm b/code/modules/plumbing/plumbers/medipenrefill.dm new file mode 100644 index 0000000000..fb7553a4d5 --- /dev/null +++ b/code/modules/plumbing/plumbers/medipenrefill.dm @@ -0,0 +1,94 @@ +/obj/machinery/medipen_refiller + name = "Medipen Refiller" + desc = "A machine that refills used medipens with chemicals." + icon = 'icons/obj/machines/medipen_refiller.dmi' + icon_state = "medipen_refiller" + density = TRUE + circuit = /obj/item/circuitboard/machine/medipen_refiller + idle_power_usage = 100 + /// list of medipen subtypes it can refill + var/list/allowed = list(/obj/item/reagent_containers/hypospray/medipen = /datum/reagent/medicine/epinephrine, + /obj/item/reagent_containers/hypospray/medipen/ekit = /datum/reagent/medicine/epinephrine, + /obj/item/reagent_containers/hypospray/medipen/firelocker = /datum/reagent/medicine/oxandrolone, + /obj/item/reagent_containers/hypospray/medipen/stimpack = /datum/reagent/medicine/ephedrine, + /obj/item/reagent_containers/hypospray/medipen/blood_loss = /datum/reagent/medicine/coagulant/weak) + /// var to prevent glitches in the animation + var/busy = FALSE + +/obj/machinery/medipen_refiller/Initialize() + . = ..() + create_reagents(100, TRANSPARENT) + for(var/obj/item/stock_parts/matter_bin/B in component_parts) + reagents.maximum_volume += 100 * B.rating + AddComponent(/datum/component/plumbing/simple_demand) + + +/obj/machinery/medipen_refiller/RefreshParts() + var/new_volume = 100 + for(var/obj/item/stock_parts/matter_bin/B in component_parts) + new_volume += 100 * B.rating + if(!reagents) + create_reagents(new_volume, TRANSPARENT) + reagents.maximum_volume = new_volume + return TRUE + +/// handles the messages and animation, calls refill to end the animation +/obj/machinery/medipen_refiller/attackby(obj/item/I, mob/user, params) + if(busy) + to_chat(user, "The machine is busy.") + return + if(istype(I, /obj/item/reagent_containers) && I.is_open_container()) + var/obj/item/reagent_containers/RC = I + var/units = RC.reagents.trans_to(src, RC.amount_per_transfer_from_this) + if(units) + to_chat(user, "You transfer [units] units of the solution to the [name].") + return + else + to_chat(user, "The [name] is full.") + return + if(istype(I, /obj/item/reagent_containers/hypospray/medipen)) + var/obj/item/reagent_containers/hypospray/medipen/P = I + if(!(LAZYFIND(allowed, P.type))) + to_chat(user, "Error! Unknown schematics.") + return + if(P.reagents?.reagent_list.len) + to_chat(user, "The medipen is already filled.") + return + if(reagents.has_reagent(allowed[P.type], 10)) + busy = TRUE + add_overlay("active") + addtimer(CALLBACK(src, .proc/refill, P, user), 20) + qdel(P) + return + to_chat(user, "There aren't enough reagents to finish this operation.") + return + ..() + +/obj/machinery/medipen_refiller/plunger_act(obj/item/plunger/P, mob/living/user, reinforced) + to_chat(user, "You start furiously plunging [name].") + if(do_after(user, 30, target = src)) + to_chat(user, "You finish plunging the [name].") + reagents.clear_reagents() + +/obj/machinery/medipen_refiller/wrench_act(mob/living/user, obj/item/I) + ..() + default_unfasten_wrench(user, I) + return TRUE + +/obj/machinery/medipen_refiller/crowbar_act(mob/user, obj/item/I) + ..() + default_deconstruction_crowbar(I) + return TRUE + +/obj/machinery/medipen_refiller/screwdriver_act(mob/living/user, obj/item/I) + . = ..() + if(!.) + return default_deconstruction_screwdriver(user, "medipen_refiller_open", "medipen_refiller", I) + +/// refills the medipen +/obj/machinery/medipen_refiller/proc/refill(obj/item/reagent_containers/hypospray/medipen/P, mob/user) + new P.type(loc) + reagents.remove_reagent(allowed[P.type], 10) + cut_overlays() + busy = FALSE + to_chat(user, "Medipen refilled.") diff --git a/code/modules/plumbing/plumbers/pill_press.dm b/code/modules/plumbing/plumbers/pill_press.dm new file mode 100644 index 0000000000..56510fac87 --- /dev/null +++ b/code/modules/plumbing/plumbers/pill_press.dm @@ -0,0 +1,127 @@ +///We take a constant input of reagents, and produce a pill once a set volume is reached +/obj/machinery/plumbing/pill_press + name = "chemical press" + desc = "A press that makes pills, patches and bottles." + icon_state = "pill_press" + ///maximum size of a pill + var/max_pill_volume = 50 + ///maximum size of a patch + var/max_patch_volume = 40 + ///maximum size of a bottle + var/max_bottle_volume = 30 + ///current operating product (pills or patches) + var/product = "pill" + ///the minimum size a pill or patch can be + var/min_volume = 5 + ///the maximum size a pill or patch can be + var/max_volume = 50 + ///selected size of the product + var/current_volume = 10 + ///prefix for the product name + var/product_name = "factory" + ///the icon_state number for the pill. + var/pill_number = RANDOM_PILL_STYLE + ///list of id's and icons for the pill selection of the ui + var/list/pill_styles + ///list of products stored in the machine, so we dont have 610 pills on one tile + var/list/stored_products = list() + ///max amount of pills allowed on our tile before we start storing them instead + var/max_floor_products = 50 //haha massive pill piles + +/obj/machinery/plumbing/pill_press/examine(mob/user) + . = ..() + . += "The [name] currently has [stored_products.len] stored. There needs to be less than [max_floor_products ] on the floor to continue dispensing." + +/obj/machinery/plumbing/pill_press/Initialize(mapload, bolt) + . = ..() + AddComponent(/datum/component/plumbing/simple_demand, bolt) + + //expertly copypasted from chemmasters + var/datum/asset/spritesheet/simple/assets = get_asset_datum(/datum/asset/spritesheet/simple/pills) + pill_styles = list() + for (var/x in 1 to PILL_STYLE_COUNT) + var/list/SL = list() + SL["id"] = x + SL["htmltag"] = assets.icon_tag("pill[x]") + pill_styles += list(SL) + + +/obj/machinery/plumbing/pill_press/process() + if(stat & NOPOWER) + return + if(reagents.total_volume >= current_volume) + if (product == "pill") + var/obj/item/reagent_containers/pill/P = new(src) + reagents.trans_to(P, current_volume) + P.name = trim("[product_name] pill") + stored_products += P + if(pill_number == RANDOM_PILL_STYLE) + P.icon_state = "pill[rand(1,21)]" + else + P.icon_state = "pill[pill_number]" + if(P.icon_state == "pill4") //mirrored from chem masters + P.desc = "A tablet or capsule, but not just any, a red one, one taken by the ones not scared of knowledge, freedom, uncertainty and the brutal truths of reality." + else if (product == "patch") + var/obj/item/reagent_containers/pill/patch/P = new(src) + reagents.trans_to(P, current_volume) + P.name = trim("[product_name] patch") + stored_products += P + else if (product == "bottle") + var/obj/item/reagent_containers/glass/bottle/P = new(src) + reagents.trans_to(P, current_volume) + P.name = trim("[product_name] bottle") + stored_products += P + if(stored_products.len) + var/pill_amount = 0 + for(var/obj/item/reagent_containers/pill/P in loc) + pill_amount++ + if(pill_amount >= max_floor_products) //too much so just stop + break + if(pill_amount < max_floor_products) + var/atom/movable/AM = stored_products[1] //AM because forceMove is all we need + stored_products -= AM + AM.forceMove(drop_location()) + + +/obj/machinery/plumbing/pill_press/ui_assets(mob/user) + return list( + get_asset_datum(/datum/asset/spritesheet/simple/pills), + ) + +/obj/machinery/plumbing/pill_press/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "ChemPress", name) + ui.open() + +/obj/machinery/plumbing/pill_press/ui_data(mob/user) + var/list/data = list() + data["pill_style"] = pill_number + data["current_volume"] = current_volume + data["product_name"] = product_name + data["pill_styles"] = pill_styles + data["product"] = product + data["min_volume"] = min_volume + data["max_volume"] = max_volume + return data + +/obj/machinery/plumbing/pill_press/ui_act(action, params) + if(..()) + return + . = TRUE + switch(action) + if("change_pill_style") + pill_number = clamp(text2num(params["id"]), 1 , PILL_STYLE_COUNT) + if("change_current_volume") + current_volume = clamp(text2num(params["volume"]), min_volume, max_volume) + if("change_product_name") + product_name = html_encode(params["name"]) + if("change_product") + product = params["product"] + if (product == "pill") + max_volume = max_pill_volume + else if (product == "patch") + max_volume = max_patch_volume + else if (product == "bottle") + max_volume = max_bottle_volume + current_volume = clamp(current_volume, min_volume, max_volume) diff --git a/code/modules/plumbing/plumbers/pumps.dm b/code/modules/plumbing/plumbers/pumps.dm new file mode 100644 index 0000000000..c24e48098d --- /dev/null +++ b/code/modules/plumbing/plumbers/pumps.dm @@ -0,0 +1,64 @@ +///We pump liquids from activated(plungerated) geysers to a plumbing outlet. We don't need to be wired. +/obj/machinery/plumbing/liquid_pump + name = "liquid pump" + desc = "Pump up those sweet liquids from under the surface. Uses thermal energy from geysers to power itself." //better than placing 200 cables, because it wasnt fun + icon = 'icons/obj/plumbing/plumbers.dmi' + icon_state = "pump" + anchored = FALSE + density = TRUE + idle_power_usage = 10 + active_power_usage = 1000 + + rcd_cost = 30 + rcd_delay = 40 + + ///units we pump per process (2 seconds) + var/pump_power = 2 + ///set to true if the loop couldnt find a geyser in process, so it remembers and stops checking every loop until moved. more accurate name would be absolutely_no_geyser_under_me_so_dont_try + var/geyserless = FALSE + ///The geyser object + var/obj/structure/geyser/geyser + ///volume of our internal buffer + var/volume = 200 + +/obj/machinery/plumbing/liquid_pump/Initialize(mapload, bolt) + . = ..() + AddComponent(/datum/component/plumbing/simple_supply, bolt) + +///please note that the component has a hook in the parent call, wich handles activating and deactivating +/obj/machinery/plumbing/liquid_pump/default_unfasten_wrench(mob/user, obj/item/I, time = 20) + . = ..() + if(. == SUCCESSFUL_UNFASTEN) + geyser = null + update_icon() + geyserless = FALSE //we switched state, so lets just set this back aswell + +/obj/machinery/plumbing/liquid_pump/process() + if(!anchored || panel_open || geyserless) + return + + if(!geyser) + for(var/obj/structure/geyser/G in loc.contents) + geyser = G + update_icon() + if(!geyser) //we didnt find one, abort + geyserless = TRUE + visible_message("The [name] makes a sad beep!") + playsound(src, 'sound/machines/buzz-sigh.ogg', 50) + return + + pump() + +///pump up that sweet geyser nectar +/obj/machinery/plumbing/liquid_pump/proc/pump() + if(!geyser || !geyser.reagents) + return + geyser.reagents.trans_to(src, pump_power) + +/obj/machinery/plumbing/liquid_pump/update_icon_state() + if(geyser) + icon_state = initial(icon_state) + "-on" + else if(panel_open) + icon_state = initial(icon_state) + "-open" + else + icon_state = initial(icon_state) diff --git a/code/modules/plumbing/plumbers/reaction_chamber.dm b/code/modules/plumbing/plumbers/reaction_chamber.dm new file mode 100644 index 0000000000..949543c300 --- /dev/null +++ b/code/modules/plumbing/plumbers/reaction_chamber.dm @@ -0,0 +1,63 @@ +///a reaction chamber for plumbing. pretty much everything can react, but this one keeps the reagents seperated and only reacts under your given terms +/obj/machinery/plumbing/reaction_chamber + name = "reaction chamber" + desc = "Keeps chemicals seperated until given conditions are met." + icon_state = "reaction_chamber" + buffer = 200 + reagent_flags = TRANSPARENT | NO_REACT + + /**list of set reagents that the reaction_chamber allows in, and must all be present before mixing is enabled. + * example: list(/datum/reagent/water = 20, /datum/reagent/fuel/oil = 50) + */ + var/list/required_reagents = list() + ///our reagent goal has been reached, so now we lock our inputs and start emptying + var/emptying = FALSE + +/obj/machinery/plumbing/reaction_chamber/Initialize(mapload, bolt) + . = ..() + AddComponent(/datum/component/plumbing/reaction_chamber, bolt) + +/obj/machinery/plumbing/reaction_chamber/on_reagent_change() + if(reagents.total_volume == 0 && emptying) //we were emptying, but now we aren't + emptying = FALSE + reagent_flags |= NO_REACT + +/obj/machinery/plumbing/reaction_chamber/power_change() + . = ..() + if(use_power != NO_POWER_USE) + icon_state = initial(icon_state) + "_on" + else + icon_state = initial(icon_state) + +/obj/machinery/plumbing/reaction_chamber/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "ChemReactionChamber", name) + ui.open() + +/obj/machinery/plumbing/reaction_chamber/ui_data(mob/user) + var/list/data = list() + var/list/text_reagents = list() + for(var/A in required_reagents) //make a list where the key is text, because that looks alot better in the ui than a typepath + var/datum/reagent/R = A + text_reagents[initial(R.name)] = required_reagents[R] + + data["reagents"] = text_reagents + data["emptying"] = emptying + return data + +/obj/machinery/plumbing/reaction_chamber/ui_act(action, params) + if(..()) + return + . = TRUE + switch(action) + if("remove") + var/reagent = get_chem_id(params["chem"]) + if(reagent) + required_reagents.Remove(reagent) + if("add") + var/input_reagent = get_chem_id(params["chem"]) + if(input_reagent && !required_reagents.Find(input_reagent)) + var/input_amount = text2num(params["amount"]) + if(input_amount) + required_reagents[input_reagent] = input_amount diff --git a/code/modules/plumbing/plumbers/splitters.dm b/code/modules/plumbing/plumbers/splitters.dm new file mode 100644 index 0000000000..a26813486c --- /dev/null +++ b/code/modules/plumbing/plumbers/splitters.dm @@ -0,0 +1,50 @@ +///it splits the reagents however you want. So you can "every 60 units, 45 goes left and 15 goes straight". The side direction is EAST, you can change this in the component +/obj/machinery/plumbing/splitter + name = "Chemical Splitter" + desc = "A chemical splitter for smart chemical factorization. Waits till a set of conditions is met and then stops all input and splits the buffer evenly or other in two ducts." + icon_state = "splitter" + buffer = 100 + density = FALSE + + ///constantly switches between TRUE and FALSE. TRUE means the batch tick goes straight, FALSE means the next batch goes in the side duct. + var/turn_straight = TRUE + ///how much we must transfer straight. note input can be as high as 10 reagents per process, usually + var/transfer_straight = 5 + ///how much we must transfer to the side + var/transfer_side = 5 + //the maximum you can set the transfer to + var/max_transfer = 9 + + +/obj/machinery/plumbing/splitter/Initialize(mapload, bolt) + . = ..() + AddComponent(/datum/component/plumbing/splitter, bolt) + +/obj/machinery/plumbing/splitter/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "ChemSplitter", name) + ui.open() + +/obj/machinery/plumbing/splitter/ui_data(mob/user) + var/list/data = list() + data["straight"] = transfer_straight + data["side"] = transfer_side + data["max_transfer"] = max_transfer + return data + +/obj/machinery/plumbing/splitter/ui_act(action, params) + if(..()) + return + . = TRUE + switch(action) + if("set_amount") + var/direction = params["target"] + var/value = clamp(text2num(params["amount"]), 1, max_transfer) + switch(direction) + if("straight") + transfer_straight = value + if("side") + transfer_side = value + else + return FALSE diff --git a/code/modules/plumbing/plumbers/synthesizer.dm b/code/modules/plumbing/plumbers/synthesizer.dm new file mode 100644 index 0000000000..c2bc3439ff --- /dev/null +++ b/code/modules/plumbing/plumbers/synthesizer.dm @@ -0,0 +1,111 @@ +///A single machine that produces a single chem. Can be placed in unison with others through plumbing to create chemical factories +/obj/machinery/plumbing/synthesizer + name = "chemical synthesizer" + desc = "Produces a single chemical at a given volume. Must be plumbed. Most effective when working in unison with other chemical synthesizers, heaters and filters." + + icon_state = "synthesizer" + icon = 'icons/obj/plumbing/plumbers.dmi' + rcd_cost = 25 + rcd_delay = 15 + + ///Amount we produce for every process. Ideally keep under 5 since thats currently the standard duct capacity + var/amount = 1 + ///The maximum we can produce for every process + buffer = 5 + ///I track them here because I have no idea how I'd make tgui loop like that + var/static/list/possible_amounts = list(0,1,2,3,4,5) + ///The reagent we are producing. We are a typepath, but are also typecast because there's several occations where we need to use initial. + var/datum/reagent/reagent_id = null + ///straight up copied from chem dispenser. Being a subtype would be extremely tedious and making it global would restrict potential subtypes using different dispensable_reagents + var/list/dispensable_reagents = list( + /datum/reagent/aluminium, + /datum/reagent/bromine, + /datum/reagent/carbon, + /datum/reagent/chlorine, + /datum/reagent/copper, + /datum/reagent/consumable/ethanol, + /datum/reagent/fluorine, + /datum/reagent/hydrogen, + /datum/reagent/iodine, + /datum/reagent/iron, + /datum/reagent/lithium, + /datum/reagent/mercury, + /datum/reagent/nitrogen, + /datum/reagent/oxygen, + /datum/reagent/phosphorus, + /datum/reagent/potassium, + /datum/reagent/radium, + /datum/reagent/silicon, + /datum/reagent/silver, + /datum/reagent/sodium, + /datum/reagent/stable_plasma, + /datum/reagent/consumable/sugar, + /datum/reagent/sulfur, + /datum/reagent/toxin/acid, + /datum/reagent/water, + /datum/reagent/fuel, + ) + +/obj/machinery/plumbing/synthesizer/Initialize(mapload, bolt) + . = ..() + AddComponent(/datum/component/plumbing/simple_supply, bolt) + +/obj/machinery/plumbing/synthesizer/process() + if(stat & NOPOWER || !reagent_id || !amount) + return + if(reagents.total_volume >= amount) //otherwise we get leftovers, and we need this to be precise + return + reagents.add_reagent(reagent_id, amount) + +/obj/machinery/plumbing/synthesizer/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "ChemSynthesizer", name) + ui.open() + +/obj/machinery/plumbing/synthesizer/ui_data(mob/user) + var/list/data = list() + + var/is_hallucinating = user.hallucinating() + var/list/chemicals = list() + + for(var/A in dispensable_reagents) + var/datum/reagent/R = GLOB.chemical_reagents_list[A] + if(R) + var/chemname = R.name + if(is_hallucinating && prob(5)) + chemname = "[pick_list_replacements("hallucination.json", "chemicals")]" + chemicals.Add(list(list("title" = chemname, "id" = ckey(R.name)))) + data["chemicals"] = chemicals + data["amount"] = amount + data["possible_amounts"] = possible_amounts + + data["current_reagent"] = ckey(initial(reagent_id.name)) + return data + +/obj/machinery/plumbing/synthesizer/ui_act(action, params) + if(..()) + return + . = TRUE + switch(action) + if("amount") + var/new_amount = text2num(params["target"]) + if(new_amount in possible_amounts) + amount = new_amount + . = TRUE + if("select") + var/new_reagent = GLOB.name2reagent[params["reagent"]] + if(new_reagent in dispensable_reagents) + reagent_id = new_reagent + . = TRUE + update_icon() + reagents.clear_reagents() + +/obj/machinery/plumbing/synthesizer/update_overlays() + . = ..() + var/mutable_appearance/r_overlay = mutable_appearance(icon, "[icon_state]_overlay") + if(reagent_id) + r_overlay.color = initial(reagent_id.color) + else + r_overlay.color = "#FFFFFF" + . += r_overlay diff --git a/code/modules/power/apc.dm b/code/modules/power/apc.dm index ba51eb3bef..2480288484 100644 --- a/code/modules/power/apc.dm +++ b/code/modules/power/apc.dm @@ -838,6 +838,46 @@ // attack with hand - remove cell (if cover open) or interact with the APC /obj/machinery/power/apc/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) + if(isethereal(user)) + var/mob/living/carbon/human/H = user + if(H.a_intent == INTENT_HARM) + if(cell.charge <= (cell.maxcharge / 2)) // if charge is under 50% you shouldnt drain it + to_chat(H, "The APC doesn't have much power, you probably shouldn't drain any.") + return + var/obj/item/organ/stomach/ethereal/stomach = H.getorganslot(ORGAN_SLOT_STOMACH) + if(stomach.crystal_charge > 145) + to_chat(H, "Your charge is full!") + return + to_chat(H, "You start channeling some power through the APC into your body.") + if(do_after(user, 75, target = src)) + if(cell.charge <= (cell.maxcharge / 2) || (stomach.crystal_charge > 145)) + return + if(istype(stomach)) + to_chat(H, "You receive some charge from the APC.") + stomach.adjust_charge(10) + cell.charge -= 10 + else + to_chat(H, "You can't receive charge from the APC!") + return + if(H.a_intent == INTENT_GRAB) + if(cell.charge == cell.maxcharge) + to_chat(H, "The APC is full!") + return + var/obj/item/organ/stomach/ethereal/stomach = H.getorganslot(ORGAN_SLOT_STOMACH) + if(stomach.crystal_charge < 10) + to_chat(H, "Your charge is too low!") + return + to_chat(H, "You start channeling power through your body into the APC.") + if(do_after(user, 75, target = src)) + if(cell.charge == cell.maxcharge || (stomach.crystal_charge < 10)) + return + if(istype(stomach)) + to_chat(H, "You transfer some power to the APC.") + stomach.adjust_charge(-10) + cell.charge += 10 + else + to_chat(H, "You can't transfer power to the APC!") + return if(opened && (!issilicon(user))) if(cell) user.visible_message("[user] removes \the [cell] from [src]!","You remove \the [cell].") @@ -850,26 +890,19 @@ if((stat & MAINT) && !opened) //no board; no interface return -/obj/machinery/power/apc/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ - datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) - +/obj/machinery/power/apc/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) if(!ui) - ui = new(user, src, ui_key, "Apc", name, 480, 460, master_ui, state) + ui = new(user, src, "Apc", name) ui.open() /obj/machinery/power/apc/ui_data(mob/user) - var/obj/item/implant/hijack/H = user.getImplant(/obj/item/implant/hijack) - var/abilitiesavail = FALSE - if (H && !H.stealthmode && H.toggled) - abilitiesavail = TRUE var/list/data = list( "locked" = locked, - "lock_nightshift" = nightshift_requires_auth, "failTime" = failure_timer, "isOperating" = operating, "externalPower" = main_status, - "powerCellStatus" = (cell?.percent() || null), + "powerCellStatus" = cell ? cell.percent() : null, "chargeMode" = chargemode, "chargingStatus" = charging, "totalLoad" = DisplayPower(lastused_total), @@ -878,10 +911,7 @@ "malfStatus" = get_malf_status(user), "emergencyLights" = !emergency_lights, "nightshiftLights" = nightshift_lights, - "hijackable" = HAS_TRAIT(user,TRAIT_HIJACKER), - "hijacker" = hijacker == user ? TRUE : FALSE, - "drainavail" = cell && cell.percent() >= 85 && abilitiesavail, - "lockdownavail" = cell && cell.percent() >= 35 && abilitiesavail, + "powerChannels" = list( list( "title" = "Equipment", @@ -979,43 +1009,32 @@ . = UI_INTERACTIVE /obj/machinery/power/apc/ui_act(action, params) - if(..() || !can_use(usr, 1)) - return - if(failure_timer) - if(action == "reboot") - failure_timer = 0 - update_icon() - update() - if(action == "hijack" && can_use(usr, 1)) //don't need auth for hijack button - hijack(usr) - return - var/authorized = (!locked || area.hasSiliconAccessInArea(usr, PRIVILEDGES_SILICON|PRIVILEDGES_DRONE) || (integration_cog && (is_servant_of_ratvar(usr)))) - if((action == "toggle_nightshift") && (!nightshift_requires_auth || authorized)) - toggle_nightshift_lights() - return TRUE - if(!authorized) + if(..() || !can_use(usr, 1) || (locked && !area.hasSiliconAccessInArea(usr, PRIVILEDGES_SILICON|PRIVILEDGES_DRONE) && !failure_timer && action != "toggle_nightshift" && (!integration_cog || !(is_servant_of_ratvar(usr))))) return switch(action) if("lock") if(area.hasSiliconAccessInArea(usr)) if((obj_flags & EMAGGED) || (stat & (BROKEN|MAINT))) - to_chat(usr, "The APC does not respond to the command.") + to_chat(usr, "The APC does not respond to the command!") else locked = !locked update_icon() - return TRUE + . = TRUE if("cover") coverlocked = !coverlocked - return TRUE + . = TRUE if("breaker") - toggle_breaker() - return TRUE + toggle_breaker(usr) + . = TRUE + if("toggle_nightshift") + toggle_nightshift_lights() + . = TRUE if("charge") chargemode = !chargemode if(!chargemode) charging = APC_NOT_CHARGING update_icon() - return TRUE + . = TRUE if("channel") if(params["eqp"]) equipment = setsubsystem(text2num(params["eqp"])) @@ -1029,23 +1048,24 @@ environ = setsubsystem(text2num(params["env"])) update_icon() update() - return TRUE + . = TRUE if("overload") - if(area.hasSiliconAccessInArea(usr)) + if(area.hasSiliconAccessInArea(usr, PRIVILEDGES_SILICON|PRIVILEDGES_DRONE)) //usr.has_unlimited_silicon_privilege) overload_lighting() - return TRUE + . = TRUE if("hack") if(get_malf_status(usr)) malfhack(usr) - return TRUE if("occupy") if(get_malf_status(usr)) malfoccupy(usr) - return TRUE if("deoccupy") if(get_malf_status(usr)) malfvacate() - return TRUE + if("reboot") + failure_timer = 0 + update_icon() + update() if("emergency_lighting") emergency_lights = !emergency_lights for(var/obj/machinery/light/L in area) @@ -1053,31 +1073,14 @@ L.no_emergency = emergency_lights INVOKE_ASYNC(L, /obj/machinery/light/.proc/update, FALSE) CHECK_TICK - if("drain") - cell.use(cell.charge) - hijacker.toggleSiliconAccessArea(area) - hijacker = null - set_hijacked_lighting() - update_icon() - var/obj/item/implant/hijack/H = usr.getImplant(/obj/item/implant/hijack) - H.stealthcooldown = world.time + 2 MINUTES - energy_fail(30 SECONDS * (cell.charge / cell.maxcharge)) - if("lockdown") - var/celluse = rand(20,35) - celluse = celluse /100 - for (var/obj/machinery/door/D in GLOB.airlocks) - if (get_area(D) == area) - INVOKE_ASYNC(D,/obj/machinery/door.proc/hostile_lockdown,usr, FALSE) - addtimer(CALLBACK(D,/obj/machinery/door.proc/disable_lockdown, FALSE), 30 SECONDS) - cell.charge -= cell.maxcharge*celluse - var/obj/item/implant/hijack/H = usr.getImplant(/obj/item/implant/hijack) - H.stealthcooldown = world.time + 3 MINUTES return TRUE -/obj/machinery/power/apc/proc/toggle_breaker() +/obj/machinery/power/apc/proc/toggle_breaker(mob/user) if(!is_operational() || failure_timer) return operating = !operating + add_hiddenprint(user) //delete when runtime + log_game("[key_name(user)] turned [operating ? "on" : "off"] the [src] in [AREACOORD(src)]") update() update_icon() @@ -1122,6 +1125,10 @@ if(malf.malfhacking) to_chat(malf, "You are already hacking an APC.") return + var/area/ourarea = get_area(src) + if(!ourarea.valid_malf_hack) + to_chat(malf, "This APC is not well connected enough to the Exonet to provide any useful processing capabilities.") + return to_chat(malf, "Beginning override of APC systems. This takes some time, and you cannot perform other actions during the process.") malf.malfhack = src malf.malfhacking = addtimer(CALLBACK(malf, /mob/living/silicon/ai/.proc/malfhacked, src), 600, TIMER_STOPPABLE) diff --git a/code/modules/power/cell.dm b/code/modules/power/cell.dm index ba6311a94d..6425feac31 100644 --- a/code/modules/power/cell.dm +++ b/code/modules/power/cell.dm @@ -151,6 +151,27 @@ if(prob(25)) corrupt() +/obj/item/stock_parts/cell/attack_self(mob/user) + if(isethereal(user)) + var/mob/living/carbon/human/H = user + if(charge < 100) + to_chat(H, "The [src] doesn't have enough power!") + return + var/obj/item/organ/stomach/ethereal/stomach = H.getorganslot(ORGAN_SLOT_STOMACH) + if(stomach.crystal_charge > 146) + to_chat(H, "Your charge is full!") + return + to_chat(H, "You clumsily channel power through the [src] and into your body, wasting some in the process.") + if(do_after(user, 5, target = src)) + if((charge < 100) || (stomach.crystal_charge > 146)) + return + if(istype(stomach)) + to_chat(H, "You receive some charge from the [src].") + stomach.adjust_charge(3) + charge -= 100 //you waste way more than you receive, so that ethereals cant just steal one cell and forget about hunger + else + to_chat(H, "You can't receive charge from the [src]!") + return /obj/item/stock_parts/cell/blob_act(obj/structure/blob/B) ex_act(EXPLODE_DEVASTATE) diff --git a/code/modules/power/gravitygenerator.dm b/code/modules/power/gravitygenerator.dm index 30a7aa152b..e37ae56e71 100644 --- a/code/modules/power/gravitygenerator.dm +++ b/code/modules/power/gravitygenerator.dm @@ -116,8 +116,6 @@ GLOBAL_LIST_EMPTY(gravity_generators) // We will keep track of this by adding ne sprite_number = 8 use_power = IDLE_POWER_USE interaction_flags_machine = INTERACT_MACHINE_ALLOW_SILICON | INTERACT_MACHINE_OFFLINE - ui_x = 400 - ui_y = 165 var/on = TRUE var/breaker = TRUE var/list/parts = list() @@ -222,11 +220,10 @@ GLOBAL_LIST_EMPTY(gravity_generators) // We will keep track of this by adding ne return return ..() -/obj/machinery/gravity_generator/main/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ - datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) +/obj/machinery/gravity_generator/main/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) if(!ui) - ui = new(user, src, ui_key, "GravityGenerator", name, ui_x, ui_y, master_ui, state) + ui = new(user, src, "GravityGenerator", name) ui.open() /obj/machinery/gravity_generator/main/ui_data(mob/user) diff --git a/code/modules/power/lighting.dm b/code/modules/power/lighting.dm index 20f7ce099a..4c76c4b5b1 100644 --- a/code/modules/power/lighting.dm +++ b/code/modules/power/lighting.dm @@ -610,7 +610,18 @@ var/mob/living/carbon/human/H = user if(istype(H)) - + var/datum/species/ethereal/eth_species = H.dna?.species + if(istype(eth_species)) + to_chat(H, "You start channeling some power through the [fitting] into your body.") + if(do_after(user, 50, target = src)) + var/obj/item/organ/stomach/ethereal/stomach = H.getorganslot(ORGAN_SLOT_STOMACH) + if(istype(stomach)) + to_chat(H, "You receive some charge from the [fitting].") + stomach.adjust_charge(2) + else + to_chat(H, "You can't receive charge from the [fitting]!") + return + if(H.gloves) var/obj/item/clothing/gloves/G = H.gloves if(G.max_heat_protection_temperature) diff --git a/code/modules/power/monitor.dm b/code/modules/power/monitor.dm index 974fb1b9e2..393d403c4d 100644 --- a/code/modules/power/monitor.dm +++ b/code/modules/power/monitor.dm @@ -11,8 +11,6 @@ active_power_usage = 100 circuit = /obj/item/circuitboard/computer/powermonitor tgui_id = "PowerMonitor" - ui_x = 550 - ui_y = 700 var/obj/structure/cable/attached_wire var/obj/machinery/power/apc/local_apc @@ -84,11 +82,10 @@ if(demand.len > record_size) demand.Cut(1, 2) -/obj/machinery/computer/monitor/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ - datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) +/obj/machinery/computer/monitor/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) if(!ui) - ui = new(user, src, ui_key, "PowerMonitor", name, ui_x, ui_y, master_ui, state) + ui = new(user, src, "PowerMonitor", name) ui.open() /obj/machinery/computer/monitor/ui_data() diff --git a/code/modules/power/port_gen.dm b/code/modules/power/port_gen.dm index d4e0df8359..e2f8c4e58a 100644 --- a/code/modules/power/port_gen.dm +++ b/code/modules/power/port_gen.dm @@ -7,8 +7,6 @@ density = TRUE anchored = FALSE use_power = NO_POWER_USE - ui_x = 450 - ui_y = 340 var/active = FALSE var/power_gen = 5000 @@ -219,11 +217,10 @@ /obj/machinery/power/port_gen/pacman/attack_paw(mob/user) interact(user) -/obj/machinery/power/port_gen/pacman/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ - datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) +/obj/machinery/power/port_gen/pacman/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) if(!ui) - ui = new(user, src, ui_key, "PortableGenerator", name, ui_x, ui_y, master_ui, state) + ui = new(user, src, "PortableGenerator", name) ui.open() /obj/machinery/power/port_gen/pacman/ui_data() diff --git a/code/modules/power/singularity/particle_accelerator/particle_control.dm b/code/modules/power/singularity/particle_accelerator/particle_control.dm index 912fc0a72b..96c8d9a263 100644 --- a/code/modules/power/singularity/particle_accelerator/particle_control.dm +++ b/code/modules/power/singularity/particle_accelerator/particle_control.dm @@ -10,8 +10,6 @@ active_power_usage = 10000 dir = NORTH mouse_opacity = MOUSE_OPACITY_OPAQUE - ui_x = 350 - ui_y = 185 var/strength_upper_limit = 2 var/interface_control = TRUE var/list/obj/structure/particle_accelerator/connected_parts @@ -275,11 +273,10 @@ return ..() return UI_CLOSE -/obj/machinery/particle_accelerator/control_box/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ - datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) +/obj/machinery/particle_accelerator/control_box/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) if(!ui) - ui = new(user, src, ui_key, "ParticleAccelerator", name, ui_x, ui_y, master_ui, state) + ui = new(user, src, "ParticleAccelerator", name) ui.open() /obj/machinery/particle_accelerator/control_box/ui_data(mob/user) diff --git a/code/modules/power/smes.dm b/code/modules/power/smes.dm index fcc7faa29e..a4fc7d0641 100644 --- a/code/modules/power/smes.dm +++ b/code/modules/power/smes.dm @@ -21,8 +21,6 @@ density = TRUE use_power = NO_POWER_USE circuit = /obj/item/circuitboard/machine/smes - ui_x = 340 - ui_y = 350 var/capacity = 5e6 // maximum charge var/charge = 0 // actual charge @@ -202,7 +200,7 @@ /obj/machinery/power/smes/update_overlays() . = ..() - if((stat & BROKEN) || panel_open) + if(stat & BROKEN) return if(panel_open) @@ -318,11 +316,10 @@ return -/obj/machinery/power/smes/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ - datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) +/obj/machinery/power/smes/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) if(!ui) - ui = new(user, src, ui_key, "Smes", name, ui_x, ui_y, master_ui, state) + ui = new(user, src, "Smes", name) ui.open() /obj/machinery/power/smes/ui_data() diff --git a/code/modules/power/solar.dm b/code/modules/power/solar.dm index 2c258c1f49..cf526f083d 100644 --- a/code/modules/power/solar.dm +++ b/code/modules/power/solar.dm @@ -115,9 +115,6 @@ panel.icon_state = "solar_panel-b" else panel.icon_state = "solar_panel" -#if DM_VERSION <= 512 - . += new /mutable_appearance(panel) -#endif /obj/machinery/power/solar/proc/queue_turn(azimuth) needs_to_turn = TRUE @@ -346,11 +343,10 @@ else . += mutable_appearance(icon, icon_screen) -/obj/machinery/power/solar_control/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ - datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) +/obj/machinery/power/solar_control/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) if(!ui) - ui = new(user, src, ui_key, "SolarControl", name, 380, 230, master_ui, state) + ui = new(user, src, "SolarControl", name) ui.open() /obj/machinery/power/solar_control/ui_data() diff --git a/code/modules/power/supermatter/supermatter.dm b/code/modules/power/supermatter/supermatter.dm index 8559b8ba45..fd8f900552 100644 --- a/code/modules/power/supermatter/supermatter.dm +++ b/code/modules/power/supermatter/supermatter.dm @@ -2,34 +2,54 @@ //Please do not bother them with bugs from this port, however, as it has been modified quite a bit. //Modifications include removing the world-ending full supermatter variation, and leaving only the shard. +//Zap constants, speeds up targeting + +#define BIKE (COIL + 1) +#define COIL (ROD + 1) +#define ROD (LIVING + 1) +#define LIVING (MACHINERY + 1) +#define MACHINERY (OBJECT + 1) +#define OBJECT (LOWEST + 1) +#define LOWEST (1) + #define PLASMA_HEAT_PENALTY 15 // Higher == Bigger heat and waste penalty from having the crystal surrounded by this gas. Negative numbers reduce penalty. #define OXYGEN_HEAT_PENALTY 1 -#define CO2_HEAT_PENALTY 0.1 #define PLUOXIUM_HEAT_PENALTY -1 #define TRITIUM_HEAT_PENALTY 10 +#define CO2_HEAT_PENALTY 0.1 #define NITROGEN_HEAT_PENALTY -1.5 #define BZ_HEAT_PENALTY 5 +#define H2O_HEAT_PENALTY 8 +//#define FREON_HEAT_PENALTY -10 //very good heat absorbtion and less plasma and o2 generation +//#define HYDROGEN_HEAT_PENALTY 10 // similar heat penalty as tritium (dangerous) + +//All of these get divided by 10-bzcomp * 5 before having 1 added and being multiplied with power to determine rads +//Keep the negative values here above -10 and we won't get negative rads #define OXYGEN_TRANSMIT_MODIFIER 1.5 //Higher == Bigger bonus to power generation. #define PLASMA_TRANSMIT_MODIFIER 4 #define BZ_TRANSMIT_MODIFIER -2 +#define TRITIUM_TRANSMIT_MODIFIER 30 //We divide by 10, so this works out to 3 +#define PLUOXIUM_TRANSMIT_MODIFIER -5 //Should halve the power output +#define H2O_TRANSMIT_MODIFIER 2 +//#define HYDROGEN_TRANSMIT_MODIFIER 25 //increase the radiation emission, but less than the trit (2.5) -#define TRITIUM_RADIOACTIVITY_MODIFIER 3 //Higher == Crystal spews out more radiation -#define BZ_RADIOACTIVITY_MODIFIER 5 -#define PLUOXIUM_RADIOACTIVITY_MODIFIER -2 +#define BZ_RADIOACTIVITY_MODIFIER 5 //Improves the effect of transmit modifiers #define N2O_HEAT_RESISTANCE 6 //Higher == Gas makes the crystal more resistant against heat damage. #define PLUOXIUM_HEAT_RESISTANCE 3 +//#define HYDROGEN_HEAT_RESISTANCE 2 // just a bit of heat resistance to spice it up #define POWERLOSS_INHIBITION_GAS_THRESHOLD 0.20 //Higher == Higher percentage of inhibitor gas needed before the charge inertia chain reaction effect starts. #define POWERLOSS_INHIBITION_MOLE_THRESHOLD 20 //Higher == More moles of the gas are needed before the charge inertia chain reaction effect starts. //Scales powerloss inhibition down until this amount of moles is reached #define POWERLOSS_INHIBITION_MOLE_BOOST_THRESHOLD 500 //bonus powerloss inhibition boost if this amount of moles is reached -#define MOLE_PENALTY_THRESHOLD 1800 //Higher == Shard can absorb more moles before triggering the high mole penalties. +#define MOLE_PENALTY_THRESHOLD 1800 //Above this value we can get lord singulo and independent mol damage, below it we can heal damage #define MOLE_HEAT_PENALTY 350 //Heat damage scales around this. Too hot setups with this amount of moles do regular damage, anything above and below is scaled -#define POWER_PENALTY_THRESHOLD 5000 //Higher == Engine can generate more power before triggering the high power penalties. -#define SEVERE_POWER_PENALTY_THRESHOLD 7000 //Same as above, but causes more dangerous effects -#define CRITICAL_POWER_PENALTY_THRESHOLD 12000 //Even more dangerous effects, threshold for tesla delamination +//Along with damage_penalty_point, makes flux anomalies. +#define POWER_PENALTY_THRESHOLD 5000 //The cutoff on power properly doing damage, pulling shit around, and delamming into a tesla. Low chance of pyro anomalies, +2 bolts of electricity +#define SEVERE_POWER_PENALTY_THRESHOLD 7000 //+1 bolt of electricity, allows for gravitational anomalies, and higher chances of pyro anomalies +#define CRITICAL_POWER_PENALTY_THRESHOLD 9000 //+1 bolt of electricity. #define HEAT_PENALTY_THRESHOLD 40 //Higher == Crystal safe operational temperature is higher. #define DAMAGE_HARDCAP 0.002 #define DAMAGE_INCREASE_MULTIPLIER 0.25 @@ -66,6 +86,13 @@ #define SUPERMATTER_COUNTDOWN_TIME 30 SECONDS +///to prevent accent sounds from layering +#define SUPERMATTER_ACCENT_SOUND_MIN_COOLDOWN 2 SECONDS + +#define DEFAULT_ZAP_ICON_STATE "sm_arc" +#define SLIGHTLY_CHARGED_ZAP_ICON_STATE "sm_arc_supercharged" +#define OVER_9000_ZAP_ICON_STATE "sm_arc_dbz_referance" //Witty I know + GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal) /obj/machinery/power/supermatter_crystal @@ -76,89 +103,183 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal) density = TRUE anchored = TRUE flags_1 = PREVENT_CONTENTS_EXPLOSION_1 - var/uid = 1 - var/static/gl_uid = 1 light_range = 4 resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF | FREEZE_PROOF - critical_machine = TRUE + ///The id of our supermatter + var/uid = 1 + ///The amount of supermatters that have been created this round + var/static/gl_uid = 1 + ///Tracks the bolt color we are using + var/zap_icon = DEFAULT_ZAP_ICON_STATE + ///The portion of the gasmix we're on that we should remove var/gasefficency = 0.15 - + ///Used for changing icon states for diff base sprites var/base_icon_state = "darkmatter" + ///Are we exploding? var/final_countdown = FALSE + ///The amount of damage we have currently var/damage = 0 + ///The damage we had before this cycle. Used to limit the damage we can take each cycle, and for safe_alert var/damage_archived = 0 + ///Our "Shit is no longer fucked" message. We send it when damage is less then damage_archived var/safe_alert = "Crystalline hyperstructure returning to safe operating parameters." + ///The point at which we should start sending messeges about the damage to the engi channels. var/warning_point = 50 + ///The alert we send when we've reached warning_point var/warning_alert = "Danger! Crystal hyperstructure integrity faltering!" - var/damage_penalty_point = 550 + ///The point at which we start sending messages to the common channel var/emergency_point = 700 + ///The alert we send when we've reached emergency_point var/emergency_alert = "CRYSTAL DELAMINATION IMMINENT." + ///The point at which we delam var/explosion_point = 900 + ///When we pass this amount of damage we start shooting bolts + var/damage_penalty_point = 550 - var/emergency_issued = FALSE - + ///A scaling value that affects the severity of explosions. var/explosion_power = 35 - var/temp_factor = 30 - - var/lastwarning = 0 // Time in 1/10th of seconds since the last sent warning + ///Time in 1/10th of seconds since the last sent warning + var/lastwarning = 0 + ///Refered to as eer on the moniter. This value effects gas output, heat, damage, and radiation. var/power = 0 - - var/n2comp = 0 // raw composition of each gas in the chamber, ranges from 0 to 1 - - var/plasmacomp = 0 - var/o2comp = 0 - var/co2comp = 0 - var/n2ocomp = 0 - var/pluoxiumcomp = 0 - var/tritiumcomp = 0 - var/bzcomp = 0 - - var/pluoxiumbonus = 0 - + ///Determines the rate of positve change in gas comp values + var/gas_change_rate = 0.05 + ///The list of gases we will be interacting with in process_atoms() + var/list/gases_we_care_about = list( + /datum/gas/oxygen, + /datum/gas/water_vapor, + /datum/gas/plasma, + /datum/gas/carbon_dioxide, + /datum/gas/nitrous_oxide, + /datum/gas/nitrogen, + /datum/gas/pluoxium, + /datum/gas/tritium, + /datum/gas/bz, +// /datum/gas/freon, +// /datum/gas/hydrogen, + ) + ///The list of gases mapped against their current comp. We use this to calculate different values the supermatter uses, like power or heat resistance. It doesn't perfectly match the air around the sm, instead moving up at a rate determined by gas_change_rate per call. Ranges from 0 to 1 + var/list/gas_comp = list( + /datum/gas/oxygen = 0, + /datum/gas/water_vapor = 0, + /datum/gas/plasma = 0, + /datum/gas/carbon_dioxide = 0, + /datum/gas/nitrous_oxide = 0, + /datum/gas/nitrogen = 0, + /datum/gas/pluoxium = 0, + /datum/gas/tritium = 0, + /datum/gas/bz = 0, +// /datum/gas/freon = 0, +// /datum/gas/hydrogen = 0, + ) + ///The list of gases mapped against their transmit values. We use it to determine the effect different gases have on radiation + var/list/gas_trans = list( + /datum/gas/oxygen = OXYGEN_TRANSMIT_MODIFIER, + /datum/gas/water_vapor = H2O_TRANSMIT_MODIFIER, + /datum/gas/plasma = PLASMA_TRANSMIT_MODIFIER, + /datum/gas/pluoxium = PLUOXIUM_TRANSMIT_MODIFIER, + /datum/gas/tritium = TRITIUM_TRANSMIT_MODIFIER, + /datum/gas/bz = BZ_TRANSMIT_MODIFIER, +// /datum/gas/hydrogen = HYDROGEN_TRANSMIT_MODIFIER, + ) + ///The list of gases mapped against their heat penaltys. We use it to determin molar and heat output + var/list/gas_heat = list( + /datum/gas/oxygen = OXYGEN_HEAT_PENALTY, + /datum/gas/water_vapor = H2O_HEAT_PENALTY, + /datum/gas/plasma = PLASMA_HEAT_PENALTY, + /datum/gas/carbon_dioxide = CO2_HEAT_PENALTY, + /datum/gas/nitrogen = NITROGEN_HEAT_PENALTY, + /datum/gas/pluoxium = PLUOXIUM_HEAT_PENALTY, + /datum/gas/tritium = TRITIUM_HEAT_PENALTY, + /datum/gas/bz = BZ_HEAT_PENALTY, +// /datum/gas/freon = FREON_HEAT_PENALTY, +// /datum/gas/hydrogen = HYDROGEN_HEAT_PENALTY, + ) + ///The list of gases mapped against their heat resistance. We use it to moderate heat damage. + var/list/gas_resist = list( + /datum/gas/nitrous_oxide = N2O_HEAT_RESISTANCE, + /datum/gas/pluoxium = PLUOXIUM_HEAT_RESISTANCE, +// /datum/gas/hydrogen = HYDROGEN_HEAT_RESISTANCE, + ) + ///The list of gases mapped against their powermix ratio + var/list/gas_powermix = list( + /datum/gas/oxygen = 1, + /datum/gas/water_vapor = 1, + /datum/gas/plasma = 1, + /datum/gas/carbon_dioxide = 1, + /datum/gas/nitrogen = -1, + /datum/gas/pluoxium = -1, + /datum/gas/tritium = 1, + /datum/gas/bz = 1, +// /datum/gas/freon = -1, +// /datum/gas/hydrogen = 1, + ) + ///The last air sample's total molar count, will always be above or equal to 0 var/combined_gas = 0 + ///Affects the power gain the sm experiances from heat var/gasmix_power_ratio = 0 + ///Affects the amount of o2 and plasma the sm outputs, along with the heat it makes. var/dynamic_heat_modifier = 1 + ///Affects the amount of damage and minimum point at which the sm takes heat damage var/dynamic_heat_resistance = 1 + ///Uses powerloss_dynamic_scaling and combined_gas to lessen the effects of our powerloss functions var/powerloss_inhibitor = 1 + ///Based on co2 percentage, slowly moves between 0 and 1. We use it to calc the powerloss_inhibitor var/powerloss_dynamic_scaling= 0 + ///Affects the amount of radiation the sm makes. We multiply this with power to find the rads. var/power_transmission_bonus = 0 + ///Used to increase or lessen the amount of damage the sm takes from heat based on molar counts. var/mole_heat_penalty = 0 - - + ///Takes the energy throwing things into the sm generates and slowly turns it into actual power var/matter_power = 0 + ///The cutoff for a bolt jumping, grows with heat, lowers with higher mol count, + var/zap_cutoff = 1500 + ///How much the bullets damage should be multiplied by when it is added to the internal variables + var/bullet_energy = 2 + ///How much hallucination should we produce per unit of power? + var/hallucination_power = 0.1 - //Temporary values so that we can optimize this - //How much the bullets damage should be multiplied by when it is added to the internal variables - var/config_bullet_energy = 2 - //How much of the power is left after processing is finished? -// var/config_power_reduction_per_tick = 0.5 - //How much hallucination should it produce per unit of power? - var/config_hallucination_power = 0.1 - + ///Our internal radio var/obj/item/radio/radio + ///The key our internal radio uses var/radio_key = /obj/item/encryptionkey/headset_eng + ///The engineering channel var/engineering_channel = "Engineering" + ///The common channel var/common_channel = null - //for logging + ///Boolean used for logging if we've been powered var/has_been_powered = FALSE + ///Boolean used for logging if we've passed the emergency point var/has_reached_emergency = FALSE - // For making hugbox supermatter - var/takes_damage = TRUE - var/produces_gas = TRUE + ///An effect we show to admins and ghosts the percentage of delam we're at var/obj/effect/countdown/supermatter/countdown + ///Used along with a global var to track if we can give out the sm sliver stealing objective var/is_main_engine = FALSE - + ///Our soundloop var/datum/looping_sound/supermatter/soundloop - + ///Can it be moved? var/moveable = FALSE + ///cooldown tracker for accent sounds + var/last_accent_sound = 0 + + //For making hugbox supermatters + ///Disables all methods of taking damage + var/takes_damage = TRUE + ///Disables the production of gas, and pretty much any handling of it we do. + var/produces_gas = TRUE + ///Disables power changes + var/power_changes = TRUE + ///Disables the sm's proccessing totally. + var/processes = TRUE + /obj/machinery/power/supermatter_crystal/Initialize() . = ..() uid = gl_uid++ @@ -174,6 +295,9 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal) if(is_main_engine) GLOB.main_supermatter_engine = src + AddElement(/datum/element/bsa_blocker) + RegisterSignal(src, COMSIG_ATOM_BSA_BEAM, .proc/call_explode) + soundloop = new(list(src), TRUE) /obj/machinery/power/supermatter_crystal/Destroy() @@ -184,12 +308,11 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal) QDEL_NULL(countdown) if(is_main_engine && GLOB.main_supermatter_engine == src) GLOB.main_supermatter_engine = null - QDEL_NULL(soundloop) return ..() /obj/machinery/power/supermatter_crystal/examine(mob/user) . = ..() - if (iscarbon(user)) + if (istype(user, /mob/living/carbon)) var/mob/living/carbon/C = user if (!istype(C.glasses, /obj/item/clothing/glasses/meson) && (get_dist(user, src) < HALLUCINATION_RANGE(power))) . += "You get headaches just from looking at it." @@ -202,16 +325,17 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal) if(!air) return SUPERMATTER_ERROR - if(get_integrity() < SUPERMATTER_DELAM_PERCENT) + var/integrity = get_integrity() + if(integrity < SUPERMATTER_DELAM_PERCENT) return SUPERMATTER_DELAMINATING - if(get_integrity() < SUPERMATTER_EMERGENCY_PERCENT) + if(integrity < SUPERMATTER_EMERGENCY_PERCENT) return SUPERMATTER_EMERGENCY - if(get_integrity() < SUPERMATTER_DANGER_PERCENT) + if(integrity < SUPERMATTER_DANGER_PERCENT) return SUPERMATTER_DANGER - if((get_integrity() < SUPERMATTER_WARNING_PERCENT) || (air.return_temperature() > CRITICAL_TEMPERATURE)) + if((integrity < SUPERMATTER_WARNING_PERCENT) || (air.return_temperature() > CRITICAL_TEMPERATURE)) return SUPERMATTER_WARNING if(air.return_temperature() > (CRITICAL_TEMPERATURE * 0.8)) @@ -238,23 +362,26 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal) integrity = integrity < 0 ? 0 : integrity return integrity +/obj/machinery/power/supermatter_crystal/update_overlays() + . = ..() + if(final_countdown) + . += "casuality_field" + /obj/machinery/power/supermatter_crystal/proc/countdown() set waitfor = FALSE if(final_countdown) // We're already doing it go away return final_countdown = TRUE - - var/image/causality_field = image(icon, null, "causality_field") - add_overlay(causality_field, TRUE) + update_icon() var/speaking = "[emergency_alert] The supermatter has reached critical integrity failure. Emergency causality destabilization field has been activated." radio.talk_into(src, speaking, common_channel, language = get_selected_language()) for(var/i in SUPERMATTER_COUNTDOWN_TIME to 0 step -10) if(damage < explosion_point) // Cutting it a bit close there engineers radio.talk_into(src, "[safe_alert] Failsafe has been disengaged.", common_channel) - cut_overlay(causality_field, TRUE) final_countdown = FALSE + update_icon() return else if((i % 50) != 0 && i > 50) // A message once every 5 seconds until the final 5 seconds which count down individualy sleep(10) @@ -287,48 +414,65 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal) SEND_SIGNAL(M, COMSIG_ADD_MOOD_EVENT, "delam", /datum/mood_event/delam) if(combined_gas > MOLE_PENALTY_THRESHOLD) investigate_log("has collapsed into a singularity.", INVESTIGATE_SUPERMATTER) - if(T) + if(T) //If something fucks up we blow anyhow. This fix is 4 years old and none ever said why it's here. help. var/obj/singularity/S = new(T) S.energy = 800 S.consume(src) - else - investigate_log("has exploded.", INVESTIGATE_SUPERMATTER) - explosion(get_turf(T), explosion_power * max(gasmix_power_ratio, 0.205) * 0.5 , explosion_power * max(gasmix_power_ratio, 0.205) + 2, explosion_power * max(gasmix_power_ratio, 0.205) + 4 , explosion_power * max(gasmix_power_ratio, 0.205) + 6, 1, 1) - if(power > POWER_PENALTY_THRESHOLD) - investigate_log("has spawned additional energy balls.", INVESTIGATE_SUPERMATTER) + return //No boom for me sir + else if(power > POWER_PENALTY_THRESHOLD) + investigate_log("has spawned additional energy balls.", INVESTIGATE_SUPERMATTER) + if(T) var/obj/singularity/energy_ball/E = new(T) E.energy = power - qdel(src) + investigate_log("has exploded.", INVESTIGATE_SUPERMATTER) + //Dear mappers, balance the sm max explosion radius to 17.5, 37, 39, 41 + explosion(get_turf(T), explosion_power * max(gasmix_power_ratio, 0.205) * 0.5 , explosion_power * max(gasmix_power_ratio, 0.205) + 2, explosion_power * max(gasmix_power_ratio, 0.205) + 4 , explosion_power * max(gasmix_power_ratio, 0.205) + 6, 1, 1) + qdel(src) -/obj/machinery/power/supermatter_crystal/proc/consume_turf(turf/T) - var/oldtype = T.type - var/turf/newT = T.ScrapeAway() - if(newT.type == oldtype) - return - playsound(T, 'sound/effects/supermatter.ogg', 50, 1) - T.visible_message("[T] smacks into [src] and rapidly flashes to ash.",\ - "You hear a loud crack as you are washed with a wave of heat.") - CALCULATE_ADJACENT_TURFS(T) + +//this is here to eat arguments +/obj/machinery/power/supermatter_crystal/proc/call_explode() + explode() /obj/machinery/power/supermatter_crystal/process_atmos() + if(!processes) //Just fuck me up bro + return var/turf/T = loc - if(isnull(T)) // We have a null turf...something is wrong, stop processing this entity. + if(isnull(T))// We have a null turf...something is wrong, stop processing this entity. return PROCESS_KILL - if(!istype(T)) //We are in a crate or somewhere that isn't turf, if we return to turf resume processing but for now. + if(!istype(T))//We are in a crate or somewhere that isn't turf, if we return to turf resume processing but for now. return //Yeah just stop. - if(istype(T, /turf/closed)) - consume_turf(T) + if(isclosedturf(T)) + var/turf/did_it_melt = T.Melt() + if(!isclosedturf(did_it_melt)) //In case some joker finds way to place these on indestructible walls + visible_message("[src] melts through [T]!") + return + + //We vary volume by power, and handle OH FUCK FUSION IN COOLING LOOP noises. if(power) - soundloop.volume = min(40, (round(power/100)/50)+1) // 5 +1 volume per 20 power. 2500 power is max + soundloop.volume = clamp((50 + (power / 50)), 50, 100) + if(damage >= 300) + soundloop.mid_sounds = list('sound/machines/sm/loops/delamming.ogg' = 1) + else + soundloop.mid_sounds = list('sound/machines/sm/loops/calm.ogg' = 1) + + //We play delam/neutral sounds at a rate determined by power and damage + if(last_accent_sound < world.time && prob(20)) + var/aggression = min(((damage / 800) * (power / 2500)), 1.0) * 100 + if(damage >= 300) + playsound(src, "smdelam", max(50, aggression), FALSE, 10) + else + playsound(src, "smcalm", max(50, aggression), FALSE, 10) + var/next_sound = round((100 - aggression) * 5) + last_accent_sound = world.time + max(SUPERMATTER_ACCENT_SOUND_MIN_COOLDOWN, next_sound) //Ok, get the air from the turf var/datum/gas_mixture/env = T.return_air() var/datum/gas_mixture/removed - if(produces_gas) //Remove gas from surrounding area removed = env.remove(gasefficency * env.total_moles()) @@ -336,141 +480,240 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal) // Pass all the gas related code an empty gas container removed = new() damage_archived = damage + + /******** + EXPERIMENTAL, HUGBOXY AS HELL CITADEL CHANGES: Even in a vaccum, update gas composition and modifiers. + This means that the SM will usually have a very small explosion if it ends up being breached to space, + and CO2 tesla delaminations basically require multiple grounding rods to stabilize it long enough to not have it vent. + *********/ + if(!removed || !removed.total_moles() || isspaceturf(T)) //we're in space or there is no gas to process if(takes_damage) damage += max((power / 1000) * DAMAGE_INCREASE_MULTIPLIER, 0.1) // always does at least some damage + combined_gas = max(0, combined_gas - 0.5) // Slowly wear off. + for(var/gasID in gases_we_care_about) + gas_comp[gasID] = max(0, gas_comp[gasID] - 0.05) //slowly ramp down else if(takes_damage) //causing damage + //Due to DAMAGE_INCREASE_MULTIPLIER, we only deal one 4th of the damage the statements otherwise would cause + + //((((some value between 0.5 and 1 * temp - ((273.15 + 40) * some values between 1 and 10)) * some number between 0.25 and knock your socks off / 150) * 0.25 + //Heat and mols account for each other, a lot of hot mols are more damaging then a few + //Mols start to have a positive effect on damage after 350 damage = max(damage + (max(clamp(removed.total_moles() / 200, 0.5, 1) * removed.return_temperature() - ((T0C + HEAT_PENALTY_THRESHOLD)*dynamic_heat_resistance), 0) * mole_heat_penalty / 150 ) * DAMAGE_INCREASE_MULTIPLIER, 0) + //Power only starts affecting damage when it is above 5000 damage = max(damage + (max(power - POWER_PENALTY_THRESHOLD, 0)/500) * DAMAGE_INCREASE_MULTIPLIER, 0) + //Molar count only starts affecting damage when it is above 1800 damage = max(damage + (max(combined_gas - MOLE_PENALTY_THRESHOLD, 0)/80) * DAMAGE_INCREASE_MULTIPLIER, 0) + //There might be a way to integrate healing and hurting via heat //healing damage if(combined_gas < MOLE_PENALTY_THRESHOLD) - damage = max(damage + (min(removed.return_temperature() - (T0C + HEAT_PENALTY_THRESHOLD), 0) / 150 ), 0) + //Only has a net positive effect when the temp is below 313.15, heals up to 2 damage. Psycologists increase this temp min by up to 45 + damage = max(damage + (min(removed.return_temperature() - (T0C + HEAT_PENALTY_THRESHOLD), 0) / 150), 0) - //capping damage - damage = min(damage_archived + (DAMAGE_HARDCAP * explosion_point),damage) - if(damage > damage_archived && prob(10)) - playsound(get_turf(src), 'sound/effects/empulse.ogg', 50, 1) + //caps damage rate - //calculating gas related values - combined_gas = max(removed.total_moles(), 0) + //Takes the lower number between archived damage + (1.8) and damage + //This means we can only deal 1.8 damage per function call + damage = min(damage_archived + (DAMAGE_HARDCAP * explosion_point), damage) - plasmacomp = max(removed.get_moles(/datum/gas/plasma)/combined_gas, 0) - o2comp = max(removed.get_moles(/datum/gas/oxygen)/combined_gas, 0) - co2comp = max(removed.get_moles(/datum/gas/carbon_dioxide)/combined_gas, 0) - tritiumcomp = max(removed.get_moles(/datum/gas/tritium)/combined_gas, 0) - bzcomp = max(removed.get_moles(/datum/gas/bz)/combined_gas, 0) + //calculating gas related values + //Wanna know a secret? See that max() to zero? it's used for error checking. If we get a mol count in the negative, we'll get a divide by zero error + combined_gas = max(removed.total_moles(), 0) - pluoxiumcomp = max(removed.get_moles(/datum/gas/pluoxium)/combined_gas, 0) - n2ocomp = max(removed.get_moles(/datum/gas/nitrous_oxide)/combined_gas, 0) - n2comp = max(removed.get_moles(/datum/gas/nitrogen)/combined_gas, 0) + //This is more error prevention, according to all known laws of atmos, gas_mix.remove() should never make negative mol values. + //But this is tg - if(pluoxiumcomp >= 0.15) - pluoxiumbonus = 1 //makes pluoxium only work at 15%+ - else - pluoxiumbonus = 0 + //Lets get the proportions of the gasses in the mix and then slowly move our comp to that value + //Can cause an overestimation of mol count, should stabalize things though. + //Prevents huge bursts of gas/heat when a large amount of something is introduced + //They range between 0 and 1 + for(var/gasID in gases_we_care_about) + gas_comp[gasID] += clamp(max(removed.get_moles(gasID)/combined_gas, 0) - gas_comp[gasID], -1, gas_change_rate) - gasmix_power_ratio = min(max(plasmacomp + o2comp + co2comp + tritiumcomp + bzcomp - pluoxiumcomp - n2comp, 0), 1) + var/list/heat_mod = gases_we_care_about.Copy() + var/list/transit_mod = gases_we_care_about.Copy() + var/list/resistance_mod = gases_we_care_about.Copy() - dynamic_heat_modifier = max((plasmacomp * PLASMA_HEAT_PENALTY) + (o2comp * OXYGEN_HEAT_PENALTY) + (co2comp * CO2_HEAT_PENALTY) + (tritiumcomp * TRITIUM_HEAT_PENALTY) + ((pluoxiumcomp * PLUOXIUM_HEAT_PENALTY) * pluoxiumbonus) + (n2comp * NITROGEN_HEAT_PENALTY) + (bzcomp * BZ_HEAT_PENALTY), 0.5) - dynamic_heat_resistance = max((n2ocomp * N2O_HEAT_RESISTANCE) + ((pluoxiumcomp * PLUOXIUM_HEAT_RESISTANCE) * pluoxiumbonus), 1) + //We're concerned about pluoxium being too easy to abuse at low percents, so we make sure there's a substantial amount. + var/pluoxiumbonus = (gas_comp[/datum/gas/pluoxium] >= 0.15) //makes pluoxium only work at 15%+ + var/h2obonus = 1 - (gas_comp[/datum/gas/water_vapor] * 0.25)//At max this value should be 0.75 +// var/freonbonus = (gas_comp[/datum/gas/freon] <= 0.03) //Let's just yeet power output if this shit is high - power_transmission_bonus = max((plasmacomp * PLASMA_TRANSMIT_MODIFIER) + (o2comp * OXYGEN_TRANSMIT_MODIFIER) + (bzcomp * BZ_TRANSMIT_MODIFIER), 0) + heat_mod[/datum/gas/pluoxium] = pluoxiumbonus + transit_mod[/datum/gas/pluoxium] = pluoxiumbonus + resistance_mod[/datum/gas/pluoxium] = pluoxiumbonus - //more moles of gases are harder to heat than fewer, so let's scale heat damage around them - mole_heat_penalty = max(combined_gas / MOLE_HEAT_PENALTY, 0.25) + //No less then zero, and no greater then one, we use this to do explosions and heat to power transfer + //Be very careful with modifing this var by large amounts, and for the love of god do not push it past 1 + gasmix_power_ratio = 0 + for(var/gasID in gas_powermix) + gasmix_power_ratio += gas_comp[gasID] * gas_powermix[gasID] + gasmix_power_ratio = clamp(gasmix_power_ratio, 0, 1) - if (combined_gas > POWERLOSS_INHIBITION_MOLE_THRESHOLD && co2comp > POWERLOSS_INHIBITION_GAS_THRESHOLD) - powerloss_dynamic_scaling = clamp(powerloss_dynamic_scaling + clamp(co2comp - powerloss_dynamic_scaling, -0.02, 0.02), 0, 1) - else - powerloss_dynamic_scaling = clamp(powerloss_dynamic_scaling - 0.05,0, 1) - powerloss_inhibitor = clamp(1-(powerloss_dynamic_scaling * clamp(combined_gas/POWERLOSS_INHIBITION_MOLE_BOOST_THRESHOLD,1 ,1.5)),0 ,1) + //Minimum value of -10, maximum value of 23. Effects plasma and o2 output and the output heat + dynamic_heat_modifier = 0 + for(var/gasID in gas_heat) + dynamic_heat_modifier += gas_comp[gasID] * gas_heat[gasID] * (isnull(heat_mod[gasID]) ? 1 : heat_mod[gasID]) + dynamic_heat_modifier *= h2obonus + dynamic_heat_modifier = max(dynamic_heat_modifier, 0.5) - if(matter_power) - var/removed_matter = max(matter_power/MATTER_POWER_CONVERSION, 40) - power = max(power + removed_matter, 0) - matter_power = max(matter_power - removed_matter, 0) + //Value between 1 and 10. Effects the damage heat does to the crystal + dynamic_heat_resistance = 0 + for(var/gasID in gas_resist) + dynamic_heat_resistance += gas_comp[gasID] * gas_resist[gasID] * (isnull(resistance_mod[gasID]) ? 1 : resistance_mod[gasID]) + dynamic_heat_resistance = max(dynamic_heat_resistance, 1) - var/temp_factor = 50 + //Value between -5 and 30, used to determine radiation output as it concerns things like collectors. + power_transmission_bonus = 0 + for(var/gasID in gas_trans) + power_transmission_bonus += gas_comp[gasID] * gas_trans[gasID] * (isnull(transit_mod[gasID]) ? 1 : transit_mod[gasID]) + power_transmission_bonus *= h2obonus - if(gasmix_power_ratio > 0.8) - // with a perfect gas mix, make the power less based on heat - icon_state = "[base_icon_state]_glow" - else - // in normal mode, base the produced energy around the heat - temp_factor = 30 - icon_state = base_icon_state + //more moles of gases are harder to heat than fewer, so let's scale heat damage around them + mole_heat_penalty = max(combined_gas / MOLE_HEAT_PENALTY, 0.25) - power = max( (removed.return_temperature() * temp_factor / T0C) * gasmix_power_ratio + power, 0) //Total laser power plus an overload + //Ramps up or down in increments of 0.02 up to the proportion of co2 + //Given infinite time, powerloss_dynamic_scaling = co2comp + //Some value between 0 and 1 + if (combined_gas > POWERLOSS_INHIBITION_MOLE_THRESHOLD && gas_comp[/datum/gas/carbon_dioxide] > POWERLOSS_INHIBITION_GAS_THRESHOLD) //If there are more then 20 mols, and more then 20% co2 + powerloss_dynamic_scaling = clamp(powerloss_dynamic_scaling + clamp(gas_comp[/datum/gas/carbon_dioxide] - powerloss_dynamic_scaling, -0.02, 0.02), 0, 1) + else + powerloss_dynamic_scaling = clamp(powerloss_dynamic_scaling - 0.05, 0, 1) + //Ranges from 0 to 1(1-(value between 0 and 1 * ranges from 1 to 1.5(mol / 500))) + //We take the mol count, and scale it to be our inhibitor + powerloss_inhibitor = clamp(1-(powerloss_dynamic_scaling * clamp(combined_gas/POWERLOSS_INHIBITION_MOLE_BOOST_THRESHOLD, 1, 1.5)), 0, 1) - if(prob(50)) - radiation_pulse(src, power * (1 + (tritiumcomp * TRITIUM_RADIOACTIVITY_MODIFIER) + ((pluoxiumcomp * PLUOXIUM_RADIOACTIVITY_MODIFIER) * pluoxiumbonus) * (power_transmission_bonus/(10-(bzcomp * BZ_RADIOACTIVITY_MODIFIER))))) // Rad Modifiers BZ(500%), Tritium(300%), and Pluoxium(-200%) - if(bzcomp >= 0.4 && prob(30 * bzcomp)) - fire_nuclear_particle() // Start to emit radballs at a maximum of 30% chance per tick + //Releases stored power into the general pool + //We get this by consuming shit or being scalpeled + if(matter_power && power_changes) + //We base our removed power off one 10th of the matter_power. + var/removed_matter = max(matter_power/MATTER_POWER_CONVERSION, 40) + //Adds at least 40 power + power = max(power + removed_matter, 0) + //Removes at least 40 matter power + matter_power = max(matter_power - removed_matter, 0) - var/device_energy = power * REACTION_POWER_MODIFIER + var/temp_factor = 50 + if(gasmix_power_ratio > 0.8) + //with a perfect gas mix, make the power more based on heat + icon_state = "[base_icon_state]_glow" + else + //in normal mode, power is less effected by heat + temp_factor = 30 + icon_state = base_icon_state - //To figure out how much temperature to add each tick, consider that at one atmosphere's worth - //of pure oxygen, with all four lasers firing at standard energy and no N2 present, at room temperature - //that the device energy is around 2140. At that stage, we don't want too much heat to be put out - //Since the core is effectively "cold" + //if there is more pluox and n2 then anything else, we receive no power increase from heat + if(power_changes) + power = max((removed.return_temperature() * temp_factor / T0C) * gasmix_power_ratio + power, 0) - //Also keep in mind we are only adding this temperature to (efficiency)% of the one tile the rock - //is on. An increase of 4*C @ 25% efficiency here results in an increase of 1*C / (#tilesincore) overall. - removed.set_temperature(removed.return_temperature() + ((device_energy * dynamic_heat_modifier) / THERMAL_RELEASE_MODIFIER)) + if(prob(50)) + //(1 + (tritRad + pluoxDampen * bzDampen * o2Rad * plasmaRad / (10 - bzrads))) * freonbonus + radiation_pulse(src, power * max(0, (1 + (power_transmission_bonus/(10-(gas_comp[/datum/gas/bz] * BZ_RADIOACTIVITY_MODIFIER)))) * 1))//freonbonus))// RadModBZ(500%) + if(gas_comp[/datum/gas/bz] >= 0.4 && prob(30 * gas_comp[/datum/gas/bz])) + src.fire_nuclear_particle() // Start to emit radballs at a maximum of 30% chance per tick - removed.set_temperature(max(0, min(removed.return_temperature(), 2500 * dynamic_heat_modifier))) + //Power * 0.55 * a value between 1 and 0.8 + var/device_energy = power * REACTION_POWER_MODIFIER - //Calculate how much gas to release - removed.adjust_moles(/datum/gas/plasma, max((device_energy * dynamic_heat_modifier) / PLASMA_RELEASE_MODIFIER, 0)) + //To figure out how much temperature to add each tick, consider that at one atmosphere's worth + //of pure oxygen, with all four lasers firing at standard energy and no N2 present, at room temperature + //that the device energy is around 2140. At that stage, we don't want too much heat to be put out + //Since the core is effectively "cold" - removed.adjust_moles(/datum/gas/oxygen, max(((device_energy + removed.return_temperature() * dynamic_heat_modifier) - T0C) / OXYGEN_RELEASE_MODIFIER, 0)) + //Also keep in mind we are only adding this temperature to (efficiency)% of the one tile the rock + //is on. An increase of 4*C @ 25% efficiency here results in an increase of 1*C / (#tilesincore) overall. + //Power * 0.55 * (some value between 1.5 and 23) / 5 + removed.set_temperature(removed.return_temperature() + ((device_energy * dynamic_heat_modifier) / THERMAL_RELEASE_MODIFIER)) + //We can only emit so much heat, that being 57500 + removed.set_temperature(max(0, min(removed.return_temperature(), 2500 * dynamic_heat_modifier))) - if(produces_gas) - env.merge(removed) - air_update_turf() + //Calculate how much gas to release + //Varies based on power and gas content + removed.adjust_moles(/datum/gas/plasma, max((device_energy * dynamic_heat_modifier) / PLASMA_RELEASE_MODIFIER, 0)) + //Varies based on power, gas content, and heat + removed.adjust_moles(/datum/gas/oxygen, max(((device_energy + removed.return_temperature() * dynamic_heat_modifier) - T0C) / OXYGEN_RELEASE_MODIFIER, 0)) - for(var/mob/living/carbon/human/l in fov_viewers(HALLUCINATION_RANGE(power), src)) // If they can see it without mesons on. Bad on them. + if(produces_gas) + env.merge(removed) + air_update_turf() + + /********* + END CITADEL CHANGES + *********/ + + //Makes em go mad and accumulate rads. + for(var/mob/living/carbon/human/l in fov_viewers(src, HALLUCINATION_RANGE(power))) // If they can see it without mesons on. Bad on them. if(!istype(l.glasses, /obj/item/clothing/glasses/meson)) var/D = sqrt(1 / max(1, get_dist(l, src))) - l.hallucination += power * config_hallucination_power * D - l.hallucination = clamp(0, 200, l.hallucination) - + l.hallucination += power * hallucination_power * D + l.hallucination = clamp(l.hallucination, 0, 200) for(var/mob/living/l in range(src, round((power / 100) ** 0.25))) var/rads = (power / 10) * sqrt( 1 / max(get_dist(l, src),1) ) l.rad_act(rads) - power -= ((power/500)**3) * powerloss_inhibitor + //Transitions between one function and another, one we use for the fast inital startup, the other is used to prevent errors with fusion temperatures. + //Use of the second function improves the power gain imparted by using co2 + if(power_changes) + power = max(power - min(((power/500)**3) * powerloss_inhibitor, power * 0.83 * powerloss_inhibitor),0) + //After this point power is lowered + //This wraps around to the begining of the function + //Handle high power zaps/anomaly generation + if(power > POWER_PENALTY_THRESHOLD || damage > damage_penalty_point) //If the power is above 5000 or if the damage is above 550 + var/range = 4 + zap_cutoff = 1500 + if(removed && removed.return_pressure() > 0 && removed.return_temperature() > 0) + //You may be able to freeze the zapstate of the engine with good planning, we'll see + zap_cutoff = clamp(3000 - (power * (removed.total_moles()) / 10) / removed.return_temperature(), 350, 3000)//If the core is cold, it's easier to jump, ditto if there are a lot of mols + //We should always be able to zap our way out of the default enclosure + //See supermatter_zap() for more details + range = clamp(power / removed.return_pressure() * 10, 2, 7) + var/flags = ZAP_SUPERMATTER_FLAGS + var/zap_count = 0 + //Deal with power zaps + switch(power) + if(POWER_PENALTY_THRESHOLD to SEVERE_POWER_PENALTY_THRESHOLD) + zap_icon = DEFAULT_ZAP_ICON_STATE + zap_count = 2 + if(SEVERE_POWER_PENALTY_THRESHOLD to CRITICAL_POWER_PENALTY_THRESHOLD) + zap_icon = SLIGHTLY_CHARGED_ZAP_ICON_STATE + //Uncaps the zap damage, it's maxed by the input power + //Objects take damage now + flags |= (ZAP_MOB_DAMAGE | ZAP_OBJ_DAMAGE) + zap_count = 3 + if(CRITICAL_POWER_PENALTY_THRESHOLD to INFINITY) + zap_icon = OVER_9000_ZAP_ICON_STATE + //It'll stun more now, and damage will hit harder, gloves are no garentee. + //Machines go boom + flags |= (ZAP_MOB_STUN | ZAP_MACHINE_EXPLOSIVE | ZAP_MOB_DAMAGE | ZAP_OBJ_DAMAGE) + zap_count = 4 + //Now we deal with damage shit + if (damage > damage_penalty_point && prob(20)) + zap_count += 1 - if(power > POWER_PENALTY_THRESHOLD || damage > damage_penalty_point) + if(zap_count >= 1) + playsound(src.loc, 'sound/weapons/emitter2.ogg', 100, TRUE, extrarange = 10) + for(var/i in 1 to zap_count) + supermatter_zap(src, range, clamp(power*2, 4000, 20000), flags) - if(power > POWER_PENALTY_THRESHOLD) - playsound(src.loc, 'sound/weapons/emitter2.ogg', 100, 1, extrarange = 10) - supermatter_zap(src, 5, min(power*2, 20000)) - supermatter_zap(src, 5, min(power*2, 20000)) - if(power > SEVERE_POWER_PENALTY_THRESHOLD) - supermatter_zap(src, 5, min(power*2, 20000)) - if(power > CRITICAL_POWER_PENALTY_THRESHOLD) - supermatter_zap(src, 5, min(power*2, 20000)) - else if (damage > damage_penalty_point && prob(20)) - playsound(src.loc, 'sound/weapons/emitter2.ogg', 100, 1, extrarange = 10) - supermatter_zap(src, 5, clamp(power*2, 4000, 20000)) - - if(prob(15) && power > POWER_PENALTY_THRESHOLD) - supermatter_pull(src, power/750) if(prob(5)) supermatter_anomaly_gen(src, FLUX_ANOMALY, rand(5, 10)) if(power > SEVERE_POWER_PENALTY_THRESHOLD && prob(5) || prob(1)) supermatter_anomaly_gen(src, GRAVITATIONAL_ANOMALY, rand(5, 10)) - if(power > SEVERE_POWER_PENALTY_THRESHOLD && prob(2) || prob(0.3) && power > POWER_PENALTY_THRESHOLD) + if((power > SEVERE_POWER_PENALTY_THRESHOLD && prob(2)) || (prob(0.3) && power > POWER_PENALTY_THRESHOLD)) supermatter_anomaly_gen(src, PYRO_ANOMALY, rand(5, 10)) + + if(prob(15)) + supermatter_pull(loc, min(power/850, 3))//850, 1700, 2550 + + //Tells the engi team to get their butt in gear if(damage > warning_point) // while the core is still damaged and it's still worth noting its status if((REALTIMEOFDAY - lastwarning) / 10 >= WARNING_DELAY) alarm() + //Oh shit it's bad, time to freak out if(damage > emergency_point) radio.talk_into(src, "[emergency_alert] Integrity: [get_integrity()]%", common_channel) lastwarning = REALTIMEOFDAY @@ -493,7 +736,7 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal) if(combined_gas > MOLE_PENALTY_THRESHOLD) radio.talk_into(src, "Warning: Critical coolant mass reached.", engineering_channel) - + //Boom (Mind blown) if(damage > explosion_point) countdown() @@ -503,16 +746,17 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal) var/turf/L = loc if(!istype(L)) return FALSE - if(!istype(Proj.firer, /obj/machinery/power/emitter)) + if(!istype(Proj.firer, /obj/machinery/power/emitter) && power_changes) investigate_log("has been hit by [Proj] fired by [key_name(Proj.firer)]", INVESTIGATE_SUPERMATTER) if(Proj.flag != "bullet") - power += Proj.damage * config_bullet_energy - if(!has_been_powered) - investigate_log("has been powered for the first time.", INVESTIGATE_SUPERMATTER) - message_admins("[src] has been powered for the first time [ADMIN_JMP(src)].") - has_been_powered = TRUE + if(power_changes) //This needs to be here I swear + power += Proj.damage * bullet_energy + if(!has_been_powered) + investigate_log("has been powered for the first time.", INVESTIGATE_SUPERMATTER) + message_admins("[src] has been powered for the first time [ADMIN_JMP(src)].") + has_been_powered = TRUE else if(takes_damage) - matter_power += Proj.damage * config_bullet_energy + matter_power += Proj.damage * bullet_energy return BULLET_ACT_HIT /obj/machinery/power/supermatter_crystal/singularity_act() @@ -529,15 +773,15 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal) /obj/machinery/power/supermatter_crystal/blob_act(obj/structure/blob/B) if(B && !isspaceturf(loc)) //does nothing in space - playsound(get_turf(src), 'sound/effects/supermatter.ogg', 50, 1) + playsound(get_turf(src), 'sound/effects/supermatter.ogg', 50, TRUE) damage += B.obj_integrity * 0.5 //take damage equal to 50% of remaining blob health before it tried to eat us if(B.obj_integrity > 100) B.visible_message("\The [B] strikes at \the [src] and flinches away!",\ - "You hear a loud crack as you are washed with a wave of heat.") + "You hear a loud crack as you are washed with a wave of heat.") B.take_damage(100, BURN) else B.visible_message("\The [B] strikes at \the [src] and rapidly flashes to ash.",\ - "You hear a loud crack as you are washed with a wave of heat.") + "You hear a loud crack as you are washed with a wave of heat.") Consume(B) /obj/machinery/power/supermatter_crystal/attack_tk(mob/user) @@ -546,11 +790,10 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal) log_game("[key_name(C)] has been disintegrated by a telekenetic grab on a supermatter crystal.") to_chat(C, "That was a really dense idea.") C.visible_message("A bright flare of radiation is seen from [C]'s head, shortly before you hear a sickening sizzling!") + C.ghostize() var/obj/item/organ/brain/rip_u = locate(/obj/item/organ/brain) in C.internal_organs - rip_u.Remove() + rip_u.Remove(C) qdel(rip_u) - return - return ..() /obj/machinery/power/supermatter_crystal/attack_paw(mob/user) dust_mob(user, cause = "monkey attack") @@ -559,9 +802,14 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal) dust_mob(user, cause = "alien attack") /obj/machinery/power/supermatter_crystal/attack_animal(mob/living/simple_animal/S) + var/murder + if(!S.melee_damage_upper && !S.melee_damage_lower) + murder = S.friendly_verb_continuous + else + murder = S.attack_verb_continuous dust_mob(S, \ - "[S] unwisely [S.attack_verb_continuous] [src], and [S.p_their()] body burns brilliantly before flashing into ash!", \ - "You unwisely [S.attack_verb_simple] [src], and your vision glows brightly as your body crumbles to dust. Oops.", \ + "[S] unwisely [murder] [src], and [S.p_their()] body burns brilliantly before flashing into ash!", \ + "You unwisely touch [src], and your vision glows brightly as your body crumbles to dust. Oops.", \ "simple animal attack") /obj/machinery/power/supermatter_crystal/attack_robot(mob/user) @@ -571,65 +819,103 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal) /obj/machinery/power/supermatter_crystal/attack_ai(mob/user) return -/obj/machinery/power/supermatter_crystal/on_attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags) +/obj/machinery/power/supermatter_crystal/on_attack_hand(mob/living/user) . = ..() - if(.) - return dust_mob(user, cause = "hand") /obj/machinery/power/supermatter_crystal/proc/dust_mob(mob/living/nom, vis_msg, mob_msg, cause) - if(nom.incorporeal_move || nom.status_flags & GODMODE) + if(nom.incorporeal_move || nom.status_flags & GODMODE) //try to keep supermatter sliver's + hemostat's dust conditions in sync with this too return if(!vis_msg) - vis_msg = "[nom] reaches out and touches [src], inducing a resonance... [nom.p_their()] body starts to glow and bursts into flames before flashing into ash" + vis_msg = "[nom] reaches out and touches [src], inducing a resonance... [nom.p_their()] body starts to glow and burst into flames before flashing into dust!" if(!mob_msg) mob_msg = "You reach out and touch [src]. Everything starts burning and all you can hear is ringing. Your last thought is \"That was not a wise decision.\"" if(!cause) cause = "contact" - nom.visible_message(vis_msg, mob_msg, "You hear an unearthly noise as a wave of heat washes over you.") + nom.visible_message(vis_msg, mob_msg, "You hear an unearthly noise as a wave of heat washes over you.") investigate_log("has been attacked ([cause]) by [key_name(nom)]", INVESTIGATE_SUPERMATTER) - playsound(get_turf(src), 'sound/effects/supermatter.ogg', 50, 1) + playsound(get_turf(src), 'sound/effects/supermatter.ogg', 50, TRUE) Consume(nom) /obj/machinery/power/supermatter_crystal/attackby(obj/item/W, mob/living/user, params) if(!istype(W) || (W.item_flags & ABSTRACT) || !istype(user)) return - if (istype(W, /obj/item/melee/roastingstick)) + if(istype(W, /obj/item/melee/roastingstick)) return ..() + if(istype(W, /obj/item/clothing/mask/cigarette)) + var/obj/item/clothing/mask/cigarette/cig = W + var/clumsy = HAS_TRAIT(user, TRAIT_CLUMSY) + if(clumsy) + var/which_hand = BODY_ZONE_L_ARM + if(!(user.active_hand_index % 2)) + which_hand = BODY_ZONE_R_ARM + var/obj/item/bodypart/dust_arm = user.get_bodypart(which_hand) + dust_arm.dismember() + user.visible_message("The [W] flashes out of existence on contact with \the [src], resonating with a horrible sound...",\ + "Oops! The [W] flashes out of existence on contact with \the [src], taking your arm with it! That was clumsy of you!") + playsound(src, 'sound/effects/supermatter.ogg', 150, TRUE) + Consume(dust_arm) + qdel(W) + return + if(cig.lit || user.a_intent != INTENT_HELP) + user.visible_message("A hideous sound echoes as [W] is ashed out on contact with \the [src]. That didn't seem like a good idea...") + playsound(src, 'sound/effects/supermatter.ogg', 150, TRUE) + Consume(W) + radiation_pulse(src, 150, 4) + return ..() + else + cig.light() + user.visible_message("As [user] lights \their [W] on \the [src], silence fills the room...",\ + "Time seems to slow to a crawl as you touch \the [src] with \the [W].\n\The [W] flashes alight with an eerie energy as you nonchalantly lift your hand away from \the [src]. Damn.") + playsound(src, 'sound/effects/supermatter.ogg', 50, TRUE) + radiation_pulse(src, 50, 3) + return if(istype(W, /obj/item/scalpel/supermatter)) + var/obj/item/scalpel/supermatter/scalpel = W to_chat(user, "You carefully begin to scrape \the [src] with \the [W]...") if(W.use_tool(src, user, 60, volume=100)) - to_chat(user, "You extract a sliver from \the [src]. \The [src] begins to react violently!") - new /obj/item/nuke_core/supermatter_sliver(drop_location()) - matter_power += 200 + if (scalpel.usesLeft) + to_chat(user, "You extract a sliver from \the [src]. \The [src] begins to react violently!") + new /obj/item/nuke_core/supermatter_sliver(drop_location()) + matter_power += 800 + scalpel.usesLeft-- + if (!scalpel.usesLeft) + to_chat(user, "A tiny piece of \the [W] falls off, rendering it useless!") + else + to_chat(user, "You fail to extract a sliver from \The [src]! \the [W] isn't sharp enough anymore.") else if(user.dropItemToGround(W)) user.visible_message("As [user] touches \the [src] with \a [W], silence fills the room...",\ "You touch \the [src] with \the [W], and everything suddenly goes silent.\n\The [W] flashes into dust as you flinch away from \the [src].",\ - "Everything suddenly goes silent.") + "Everything suddenly goes silent.") investigate_log("has been attacked ([W]) by [key_name(user)]", INVESTIGATE_SUPERMATTER) Consume(W) - playsound(get_turf(src), 'sound/effects/supermatter.ogg', 50, 1) + playsound(get_turf(src), 'sound/effects/supermatter.ogg', 50, TRUE) radiation_pulse(src, 150, 4) + else if(Adjacent(user)) //if the item is stuck to the person, kill the person too instead of eating just the item. + var/vis_msg = "[user] reaches out and touches [src] with [W], inducing a resonance... [W] starts to glow briefly before the light continues up to [user]'s body. [user.p_they(TRUE)] bursts into flames before flashing into dust!" + var/mob_msg = "You reach out and touch [src] with [W]. Everything starts burning and all you can hear is ringing. Your last thought is \"That was not a wise decision.\"" + dust_mob(user, vis_msg, mob_msg) + /obj/machinery/power/supermatter_crystal/wrench_act(mob/user, obj/item/tool) + ..() if (moveable) default_unfasten_wrench(user, tool, time = 20) return TRUE /obj/machinery/power/supermatter_crystal/Bumped(atom/movable/AM) if(isliving(AM)) - AM.visible_message("\The [AM] slams into \the [src] inducing a resonance... [AM.p_their()] body starts to glow and catch flame before flashing into ash.",\ + AM.visible_message("\The [AM] slams into \the [src] inducing a resonance... [AM.p_their()] body starts to glow and burst into flames before flashing into dust!",\ "You slam into \the [src] as your ears are filled with unearthly ringing. Your last thought is \"Oh, fuck.\"",\ - "You hear an unearthly noise as a wave of heat washes over you.") + "You hear an unearthly noise as a wave of heat washes over you.") else if(isobj(AM) && !iseffect(AM)) AM.visible_message("\The [AM] smacks into \the [src] and rapidly flashes to ash.", null,\ - "You hear a loud crack as you are washed with a wave of heat.") + "You hear a loud crack as you are washed with a wave of heat.") else return - playsound(get_turf(src), 'sound/effects/supermatter.ogg', 50, 1) - + playsound(get_turf(src), 'sound/effects/supermatter.ogg', 50, TRUE) Consume(AM) /obj/machinery/power/supermatter_crystal/intercept_zImpact(atom/movable/AM, levels) @@ -645,7 +931,8 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal) message_admins("[src] has consumed [key_name_admin(user)] [ADMIN_JMP(src)].") investigate_log("has consumed [key_name(user)].", INVESTIGATE_SUPERMATTER) user.dust(force = TRUE) - matter_power += 200 + if(power_changes) + matter_power += 200 else if(istype(AM, /obj/singularity)) return else if(isobj(AM)) @@ -656,19 +943,29 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal) message_admins("[src] has consumed [AM], [suspicion] [ADMIN_JMP(src)].") investigate_log("has consumed [AM] - [suspicion].", INVESTIGATE_SUPERMATTER) qdel(AM) - if(!iseffect(AM)) + if(!iseffect(AM) && power_changes) matter_power += 200 //Some poor sod got eaten, go ahead and irradiate people nearby. radiation_pulse(src, 3000, 2, TRUE) - var/list/viewers = fov_viewers(world.view, src) for(var/mob/living/L in range(10)) investigate_log("has irradiated [key_name(L)] after consuming [AM].", INVESTIGATE_SUPERMATTER) + var/list/viewers = fov_viewers(world.view, src) if(L in viewers) L.show_message("As \the [src] slowly stops resonating, you find your skin covered in new radiation burns.", MSG_VISUAL,\ "The unearthly ringing subsides and you notice you have new radiation burns.", MSG_AUDIBLE) else - L.show_message("You hear an unearthly ringing and notice your skin is covered in fresh radiation burns.", MSG_AUDIBLE) + L.show_message("You hear an unearthly ringing and notice your skin is covered in fresh radiation burns.", MSG_AUDIBLE) + +/obj/machinery/power/supermatter_crystal/proc/consume_turf(turf/T) + var/oldtype = T.type + var/turf/newT = T.ScrapeAway() + if(newT.type == oldtype) + return + playsound(T, 'sound/effects/supermatter.ogg', 50, 1) + T.visible_message("[T] smacks into [src] and rapidly flashes to ash.",\ + "You hear a loud crack as you are washed with a wave of heat.") + CALCULATE_ADJACENT_TURFS(T) //Do not blow up our internal radio /obj/machinery/power/supermatter_crystal/contents_explosion(severity, target) @@ -685,6 +982,7 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal) anchored = FALSE gasefficency = 0.125 explosion_power = 12 + layer = ABOVE_MOB_LAYER moveable = TRUE /obj/machinery/power/supermatter_crystal/shard/engine @@ -699,6 +997,8 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal) name = "anchored supermatter shard" takes_damage = FALSE produces_gas = FALSE + power_changes = FALSE + processes = FALSE //SHUT IT DOWN moveable = FALSE anchored = TRUE @@ -707,101 +1007,183 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal) base_icon_state = "darkmatter" icon_state = "darkmatter" -/obj/machinery/power/supermatter_crystal/proc/supermatter_pull(turf/center, pull_range = 10) - playsound(src.loc, 'sound/weapons/marauder.ogg', 100, 1, extrarange = 7) - for(var/atom/P in orange(pull_range,center)) - if(ismovable(P)) - var/atom/movable/pulled_object = P - if(ishuman(P)) - var/mob/living/carbon/human/H = P - H.apply_effect(40, EFFECT_KNOCKDOWN, 0) - if(pulled_object && !pulled_object.anchored && !ishuman(P)) - step_towards(pulled_object,center) - step_towards(pulled_object,center) - step_towards(pulled_object,center) - step_towards(pulled_object,center) +/obj/machinery/power/supermatter_crystal/proc/supermatter_pull(turf/center, pull_range = 3) + playsound(center, 'sound/weapons/marauder.ogg', 100, TRUE, extrarange = pull_range - world.view) + for(var/atom/movable/P in orange(pull_range,center)) + if((P.anchored || P.move_resist >= MOVE_FORCE_EXTREMELY_STRONG)) //move resist memes. + if(istype(P, /obj/structure/closet)) + var/obj/structure/closet/toggle = P + toggle.open() + continue + if(ismob(P)) + var/mob/M = P + if(M.mob_negates_gravity()) + continue //You can't pull someone nailed to the deck + step_towards(P,center) /obj/machinery/power/supermatter_crystal/proc/supermatter_anomaly_gen(turf/anomalycenter, type = FLUX_ANOMALY, anomalyrange = 5) var/turf/L = pick(orange(anomalyrange, anomalycenter)) if(L) switch(type) if(FLUX_ANOMALY) - var/obj/effect/anomaly/flux/A = new(L, 300) + var/obj/effect/anomaly/flux/A = new(L, 300, FALSE) A.explosive = FALSE if(GRAVITATIONAL_ANOMALY) - new /obj/effect/anomaly/grav(L, 250) + new /obj/effect/anomaly/grav(L, 250, FALSE) if(PYRO_ANOMALY) - new /obj/effect/anomaly/pyro(L, 200) + new /obj/effect/anomaly/pyro(L, 200, FALSE) -/obj/machinery/power/supermatter_crystal/proc/supermatter_zap(atom/zapstart, range = 3, power) - . = zapstart.dir - if(power < 1000) +/obj/machinery/power/supermatter_crystal/proc/supermatter_zap(atom/zapstart = src, range = 5, zap_str = 4000, zap_flags = ZAP_SUPERMATTER_FLAGS, list/targets_hit = list()) + if(QDELETED(zapstart)) return + . = zapstart.dir + //If the strength of the zap decays past the cutoff, we stop + if(zap_str < zap_cutoff) + return + var/atom/target + var/target_type = LOWEST + var/list/arctargets = list() + //Making a new copy so additons further down the recursion do not mess with other arcs + //Lets put this ourself into the do not hit list, so we don't curve back to hit the same thing twice with one arc + for(var/test in oview(zapstart, range)) + if(!(zap_flags & ZAP_ALLOW_DUPLICATES) && LAZYACCESS(targets_hit, test)) + continue - var/target_atom - var/mob/living/target_mob - var/obj/machinery/target_machine - var/obj/structure/target_structure - var/list/arctargetsmob = list() - var/list/arctargetsmachine = list() - var/list/arctargetsstructure = list() + if(istype(test, /obj/vehicle/ridden/bicycle/)) + var/obj/vehicle/ridden/bicycle/bike = test + if(!(bike.obj_flags & BEING_SHOCKED) && bike.can_buckle)//God's not on our side cause he hates idiots. + if(target_type != BIKE) + arctargets = list() + arctargets += test + target_type = BIKE - if(prob(20)) //let's not hit all the engineers with every beam and/or segment of the arc - for(var/mob/living/Z in oview(zapstart, range+2)) - arctargetsmob += Z - if(arctargetsmob.len) - var/mob/living/H = pick(arctargetsmob) - var/atom/A = H - target_mob = H - target_atom = A + if(target_type > COIL) + continue - else - for(var/obj/machinery/X in oview(zapstart, range+2)) - arctargetsmachine += X - if(arctargetsmachine.len) - var/obj/machinery/M = pick(arctargetsmachine) - var/atom/A = M - target_machine = M - target_atom = A + if(istype(test, /obj/machinery/power/tesla_coil/)) + var/obj/machinery/power/tesla_coil/coil = test + if(coil.anchored && !(coil.obj_flags & BEING_SHOCKED) && !coil.panel_open && prob(70))//Diversity of death + if(target_type != COIL) + arctargets = list() + arctargets += test + target_type = COIL - else - for(var/obj/structure/Y in oview(zapstart, range+2)) - arctargetsstructure += Y - if(arctargetsstructure.len) - var/obj/structure/O = pick(arctargetsstructure) - var/atom/A = O - target_structure = O - target_atom = A + if(target_type > ROD) + continue - if(target_atom) - zapstart.Beam(target_atom, icon_state="nzcrentrs_power", time=5) - var/zapdir = get_dir(zapstart, target_atom) + if(istype(test, /obj/machinery/power/grounding_rod/)) + var/obj/machinery/power/grounding_rod/rod = test + //We're adding machine damaging effects, rods need to be surefire + if(rod.anchored && !rod.panel_open) + if(target_type != ROD) + arctargets = list() + arctargets += test + target_type = ROD + + if(target_type > LIVING) + continue + + if(istype(test, /mob/living/)) + var/mob/living/alive = test + if(!(HAS_TRAIT(alive, TRAIT_TESLA_SHOCKIMMUNE)) && !(alive.flags_1 & SHOCKED_1) && alive.stat != DEAD && prob(20))//let's not hit all the engineers with every beam and/or segment of the arc + if(target_type != LIVING) + arctargets = list() + arctargets += test + target_type = LIVING + + if(target_type > MACHINERY) + continue + + if(istype(test, /obj/machinery/)) + var/obj/machinery/machine = test + if(!(machine.obj_flags & BEING_SHOCKED) && prob(40)) + if(target_type != MACHINERY) + arctargets = list() + arctargets += test + target_type = MACHINERY + + if(target_type > OBJECT) + continue + + if(istype(test, /obj/)) + var/obj/object = test + if(!(object.obj_flags & BEING_SHOCKED)) + if(target_type != OBJECT) + arctargets = list() + arctargets += test + target_type = OBJECT + + if(arctargets.len)//Pick from our pool + target = pick(arctargets) + + if(!QDELETED(target))//If we found something + //Do the animation to zap to it from here + if(!(zap_flags & ZAP_ALLOW_DUPLICATES)) + LAZYSET(targets_hit, target, TRUE) + zapstart.Beam(target, icon_state=zap_icon, time=5) + var/zapdir = get_dir(zapstart, target) if(zapdir) . = zapdir - if(target_mob) - target_mob.electrocute_act(rand(5,10), "Supermatter Discharge Bolt", 1, SHOCK_NOSTUN) - if(prob(15)) - supermatter_zap(target_mob, 5, power / 2) - supermatter_zap(target_mob, 5, power / 2) - else - supermatter_zap(target_mob, 5, power / 1.5) + //Going boom should be rareish + if(prob(80)) + zap_flags &= ~ZAP_MACHINE_EXPLOSIVE + if(target_type == COIL) + //In the best situation we can expect this to grow up to 2120kw before a delam/IT'S GONE TOO FAR FRED SHUT IT DOWN + //The formula for power gen is zap_str * zap_mod / 2 * capacitor rating, between 1 and 4 + var/multi = 10 + switch(power)//Between 7k and 9k it's 20, above that it's 40 + if(SEVERE_POWER_PENALTY_THRESHOLD to CRITICAL_POWER_PENALTY_THRESHOLD) + multi = 20 + if(CRITICAL_POWER_PENALTY_THRESHOLD to INFINITY) + multi = 40 + target.zap_act(zap_str * multi, zap_flags, list()) + zap_str /= 3 //Coils should take a lot out of the power of the zap - else if(target_machine) - if(prob(15)) - supermatter_zap(target_machine, 5, power / 2) - supermatter_zap(target_machine, 5, power / 2) - else - supermatter_zap(target_machine, 5, power / 1.5) + else if(target_type == ROD) + //We can expect this to do very little, maybe shock the poor soul buckled to it, but that's all. + //This is one of our endpoints, if the bolt hits a grounding rod, it stops jumping + target.zap_act(zap_str, zap_flags, list()) + return + + else if(isliving(target))//If we got a fleshbag on our hands + var/mob/living/creature = target + creature.set_shocked() + addtimer(CALLBACK(creature, /mob/living/proc/reset_shocked), 10) + //3 shots a human with no resistance. 2 to crit, one to death. This is at at least 10000 power. + //There's no increase after that because the input power is effectivly capped at 10k + //Does 1.5 damage at the least + var/shock_damage = ((zap_flags & ZAP_MOB_DAMAGE) ? (power / 200) - 10 : rand(5,10)) + creature.electrocute_act(shock_damage, "Supermatter Discharge Bolt", 1, ((zap_flags & ZAP_MOB_STUN) ? SHOCK_TESLA : SHOCK_NOSTUN)) + zap_str /= 1.5 //Meatsacks are conductive, makes working in pairs more destructive - else if(target_structure) - if(prob(15)) - supermatter_zap(target_structure, 5, power / 2) - supermatter_zap(target_structure, 5, power / 2) else - supermatter_zap(target_structure, 5, power / 1.5) + target.zap_act(zap_str, zap_flags, list()) + zap_str /= 2 // worse then living things, better then coils + //This gotdamn variable is a boomer and keeps giving me problems + var/turf/T = get_turf(target) + var/pressure = 1 + if(T && T.return_air()) + pressure = max(1,T.return_air().return_pressure()) + //We get our range with the strength of the zap and the pressure, the higher the former and the lower the latter the better + var/new_range = clamp(zap_str / pressure * 10, 2, 7) + var/zap_count = 1 + if(prob(5)) + zap_str -= (zap_str/10) + zap_count += 1 + for(var/j in 1 to zap_count) + if(zap_count > 1) + targets_hit = targets_hit.Copy() //Pass by ref begone + supermatter_zap(target, new_range, zap_str, zap_flags, targets_hit) #undef HALLUCINATION_RANGE #undef GRAVITATIONAL_ANOMALY #undef FLUX_ANOMALY #undef PYRO_ANOMALY +#undef BIKE +#undef COIL +#undef ROD +#undef LIVING +#undef MACHINERY +#undef OBJECT +#undef LOWEST diff --git a/code/modules/power/turbine.dm b/code/modules/power/turbine.dm index e7a97c554f..a9acea719c 100644 --- a/code/modules/power/turbine.dm +++ b/code/modules/power/turbine.dm @@ -56,8 +56,6 @@ resistance_flags = FIRE_PROOF CanAtmosPass = ATMOS_PASS_DENSITY circuit = /obj/item/circuitboard/machine/power_turbine - ui_x = 310 - ui_y = 150 var/opened = 0 var/obj/machinery/power/compressor/compressor var/turf/outturf @@ -249,11 +247,10 @@ default_deconstruction_crowbar(I) -/obj/machinery/power/turbine/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ - datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) +/obj/machinery/power/turbine/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) if(!ui) - ui = new(user, src, ui_key, "TurbineComputer", name, ui_x, ui_y, master_ui, state) + ui = new(user, src, "TurbineComputer", name) ui.open() /obj/machinery/power/turbine/ui_data(mob/user) @@ -292,8 +289,6 @@ icon_screen = "turbinecomp" icon_keyboard = "tech_key" circuit = /obj/item/circuitboard/computer/turbine_computer - ui_x = 310 - ui_y = 150 var/obj/machinery/power/compressor/compressor var/id = 0 @@ -313,11 +308,10 @@ else compressor = locate(/obj/machinery/power/compressor) in range(7, src) -/obj/machinery/computer/turbine_computer/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ - datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) +/obj/machinery/computer/turbine_computer/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) if(!ui) - ui = new(user, src, ui_key, "TurbineComputer", name, ui_x, ui_y, master_ui, state) + ui = new(user, src, "TurbineComputer", name) ui.open() /obj/machinery/computer/turbine_computer/ui_data(mob/user) diff --git a/code/modules/procedural_mapping/mapGenerator.dm b/code/modules/procedural_mapping/mapGenerator.dm index f509c409ce..323f74d0ef 100644 --- a/code/modules/procedural_mapping/mapGenerator.dm +++ b/code/modules/procedural_mapping/mapGenerator.dm @@ -147,8 +147,16 @@ set category = "Debug" var/datum/mapGenerator/nature/N = new() - var/startInput = input(usr,"Start turf of Map, (X;Y;Z)", "Map Gen Settings", "1;1;1") as text - var/endInput = input(usr,"End turf of Map (X;Y;Z)", "Map Gen Settings", "[world.maxx];[world.maxy];[mob ? mob.z : 1]") as text + var/startInput = input(usr,"Start turf of Map, (X;Y;Z)", "Map Gen Settings", "1;1;1") as text|null + + if (isnull(startInput)) + return + + var/endInput = input(usr,"End turf of Map (X;Y;Z)", "Map Gen Settings", "[world.maxx];[world.maxy];[mob ? mob.z : 1]") as text|null + + if (isnull(endInput)) + return + //maxx maxy and current z so that if you fuck up, you only fuck up one entire z level instead of the entire universe if(!startInput || !endInput) to_chat(src, "Missing Input") diff --git a/code/modules/projectiles/ammunition/_firing.dm b/code/modules/projectiles/ammunition/_firing.dm index 0ef4c680aa..437b7dcc5a 100644 --- a/code/modules/projectiles/ammunition/_firing.dm +++ b/code/modules/projectiles/ammunition/_firing.dm @@ -36,6 +36,14 @@ if(isgun(fired_from)) var/obj/item/gun/G = fired_from BB.damage *= G.projectile_damage_multiplier + if(HAS_TRAIT(user, TRAIT_INSANE_AIM)) + BB.ricochets_max = max(BB.ricochets_max, 10) //bouncy! + BB.ricochet_chance = max(BB.ricochet_chance, 100) //it wont decay so we can leave it at 100 for always bouncing + BB.ricochet_auto_aim_range = max(BB.ricochet_auto_aim_range, 3) + BB.ricochet_auto_aim_angle = max(BB.ricochet_auto_aim_angle, 360) //it can turn full circle and shoot you in the face because our aim? is insane. + BB.ricochet_decay_chance = 0 + BB.ricochet_decay_damage = max(BB.ricochet_decay_damage, 0.1) + BB.ricochet_incidence_leeway = 0 if(reagents && BB.reagents) reagents.trans_to(BB, reagents.total_volume) //For chemical darts/bullets diff --git a/code/modules/projectiles/ammunition/ballistic/revolver.dm b/code/modules/projectiles/ammunition/ballistic/revolver.dm index 693b258e3d..c13a3c953d 100644 --- a/code/modules/projectiles/ammunition/ballistic/revolver.dm +++ b/code/modules/projectiles/ammunition/ballistic/revolver.dm @@ -14,9 +14,13 @@ /obj/item/ammo_casing/a357/match name = ".357 match bullet casing" desc = "A .357 bullet casing, manufactured to exceedingly high standards." - caliber = "357" projectile_type = /obj/item/projectile/bullet/a357/match +/obj/item/ammo_casing/a357/dumdum + name = ".357 DumDum bullet casing" + desc = "A .357 bullet casing. Usage of this ammunition will constitute a war crime in your area." + projectile_type = /obj/item/projectile/bullet/a357/dumdum + // 7.62x38mmR (Nagant Revolver) /obj/item/ammo_casing/n762 @@ -68,4 +72,4 @@ /obj/item/ammo_casing/c38/dumdum name = ".38 DumDum bullet casing" desc = "A .38 DumDum bullet casing." - projectile_type = /obj/item/projectile/bullet/c38/dumdum \ No newline at end of file + projectile_type = /obj/item/projectile/bullet/c38/dumdum diff --git a/code/modules/projectiles/boxes_magazines/_box_magazine.dm b/code/modules/projectiles/boxes_magazines/_box_magazine.dm index 9ea030da99..78ca6e9280 100644 --- a/code/modules/projectiles/boxes_magazines/_box_magazine.dm +++ b/code/modules/projectiles/boxes_magazines/_box_magazine.dm @@ -20,6 +20,7 @@ var/caliber var/multiload = 1 var/start_empty = 0 + var/load_delay = 0 //how long do we take to load (deciseconds) var/list/bullet_cost var/list/base_cost// override this one as well if you override bullet_cost @@ -75,12 +76,19 @@ return 1 /obj/item/ammo_box/attackby(obj/item/A, mob/user, params, silent = FALSE, replace_spent = 0) + if(INTERACTING_WITH(user, src) || INTERACTING_WITH(user, A)) + to_chat(user, "You're already doing that!") + return FALSE var/num_loaded = 0 if(!can_load(user)) return if(istype(A, /obj/item/ammo_box)) var/obj/item/ammo_box/AM = A for(var/obj/item/ammo_casing/AC in AM.stored_ammo) + if(load_delay || AM.load_delay) + var/loadtime = max(AM.load_delay, load_delay) + if(!do_after(user, loadtime, target = src)) + return FALSE var/did_load = give_round(AC, replace_spent) if(did_load) AM.stored_ammo -= AC diff --git a/code/modules/projectiles/boxes_magazines/ammo_boxes.dm b/code/modules/projectiles/boxes_magazines/ammo_boxes.dm index 987efc0404..0b00c89c02 100644 --- a/code/modules/projectiles/boxes_magazines/ammo_boxes.dm +++ b/code/modules/projectiles/boxes_magazines/ammo_boxes.dm @@ -16,6 +16,11 @@ name = "speed loader (.357 AP)" ammo_type = /obj/item/ammo_casing/a357/ap +/obj/item/ammo_box/a357/dumdum + name = "speed loader (.357 DumDum)" + desc = "Designed to quickly reload revolvers. Usage of these rounds will constitute a war crime in your area." + ammo_type = /obj/item/ammo_casing/a357/dumdum + /obj/item/ammo_box/c38 name = "speed loader (.38 rubber)" desc = "Designed to quickly reload revolvers." @@ -148,6 +153,8 @@ max_ammo = 4 var/pixeloffsetx = 4 start_empty = TRUE + multiload = FALSE + load_delay = 6 //6ds /obj/item/ammo_box/shotgun/update_overlays() . = ..() diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm index c3248bab2f..8cddd5d02f 100644 --- a/code/modules/projectiles/gun.dm +++ b/code/modules/projectiles/gun.dm @@ -29,7 +29,7 @@ trigger_guard = TRIGGER_GUARD_NORMAL //trigger guard on the weapon, hulks can't fire them with their big meaty fingers var/sawn_desc = null //description change if weapon is sawn-off var/sawn_off = FALSE - + /// can we be put into a turret var/can_turret = TRUE /// can we be put in a circuit @@ -62,7 +62,8 @@ var/no_pin_required = FALSE //whether the gun can be fired without a pin var/obj/item/flashlight/gun_light - var/can_flashlight = 0 + var/can_flashlight = FALSE + var/gunlight_state = "flight" var/obj/item/kitchen/knife/bayonet var/mutable_appearance/knife_overlay var/can_bayonet = FALSE @@ -310,8 +311,6 @@ randomized_gun_spread = rand(0, spread) else if(burst_size > 1 && burst_spread) randomized_gun_spread = rand(0, burst_spread) - if(HAS_TRAIT(user, TRAIT_POOR_AIM)) //nice shootin' tex - bonus_spread += 25 var/randomized_bonus_spread = rand(0, bonus_spread) if(burst_size > 1) @@ -419,14 +418,7 @@ return to_chat(user, "You attach \the [K] to the front of \the [src].") bayonet = K - var/state = "bayonet" //Generic state. - if(bayonet.icon_state in icon_states('icons/obj/guns/bayonets.dmi')) //Snowflake state? - state = bayonet.icon_state - var/icon/bayonet_icons = 'icons/obj/guns/bayonets.dmi' - knife_overlay = mutable_appearance(bayonet_icons, state) - knife_overlay.pixel_x = knife_x_offset - knife_overlay.pixel_y = knife_y_offset - add_overlay(knife_overlay, TRUE) + update_icon() else if(istype(I, /obj/item/screwdriver)) if(gun_light) var/obj/item/flashlight/seclite/S = gun_light @@ -441,8 +433,7 @@ var/obj/item/kitchen/knife/K = bayonet K.forceMove(get_turf(user)) bayonet = null - cut_overlay(knife_overlay, TRUE) - knife_overlay = null + update_icon() else return ..() @@ -470,22 +461,35 @@ set_light(gun_light.brightness_on, gun_light.flashlight_power, gun_light.light_color) else set_light(0) - cut_overlays(flashlight_overlay, TRUE) - var/state = "flight[gun_light.on? "_on":""]" //Generic state. + else + set_light(0) + update_icon() + for(var/X in actions) + var/datum/action/A = X + A.UpdateButtonIcon() + +/obj/item/gun/update_overlays() + . = ..() + if(gun_light) + var/mutable_appearance/flashlight_overlay + var/state = "[gunlight_state][gun_light.on? "_on":""]" //Generic state. if(gun_light.icon_state in icon_states('icons/obj/guns/flashlights.dmi')) //Snowflake state? state = gun_light.icon_state flashlight_overlay = mutable_appearance('icons/obj/guns/flashlights.dmi', state) flashlight_overlay.pixel_x = flight_x_offset flashlight_overlay.pixel_y = flight_y_offset - add_overlay(flashlight_overlay, TRUE) - else - set_light(0) - cut_overlays(flashlight_overlay, TRUE) - flashlight_overlay = null - update_icon(TRUE) - for(var/X in actions) - var/datum/action/A = X - A.UpdateButtonIcon() + . += flashlight_overlay + + if(bayonet) + var/mutable_appearance/knife_overlay + var/state = "bayonet" //Generic state. + if(bayonet.icon_state in icon_states('icons/obj/guns/bayonets.dmi')) //Snowflake state? + state = bayonet.icon_state + var/icon/bayonet_icons = 'icons/obj/guns/bayonets.dmi' + knife_overlay = mutable_appearance(bayonet_icons, state) + knife_overlay.pixel_x = knife_x_offset + knife_overlay.pixel_y = knife_y_offset + . += knife_overlay /obj/item/gun/item_action_slot_check(slot, mob/user, datum/action/A) if(istype(A, /datum/action/item_action/toggle_scope_zoom) && slot != SLOT_HANDS) @@ -603,10 +607,16 @@ var/penalty = (last_fire + GUN_AIMING_TIME + fire_delay) - world.time if(penalty > 0) //Yet we only penalize users firing it multiple times in a haste. fire_delay isn't necessarily cumbersomeness. aiming_delay = penalty - if(SEND_SIGNAL(user, COMSIG_COMBAT_MODE_CHECK, COMBAT_MODE_ACTIVE)) //To be removed in favor of something less tactless later. + if(SEND_SIGNAL(user, COMSIG_COMBAT_MODE_CHECK, COMBAT_MODE_ACTIVE) || HAS_TRAIT(user, TRAIT_INSANE_AIM)) //To be removed in favor of something less tactless later. base_inaccuracy /= 1.5 if(stamloss > STAMINA_NEAR_SOFTCRIT) //This can null out the above bonus. base_inaccuracy *= 1 + (stamloss - STAMINA_NEAR_SOFTCRIT)/(STAMINA_NEAR_CRIT - STAMINA_NEAR_SOFTCRIT)*0.5 + if(HAS_TRAIT(user, TRAIT_POOR_AIM)) //nice shootin' tex + if(!HAS_TRAIT(user, TRAIT_INSANE_AIM)) + bonus_spread += 25 + else + //you have both poor aim and insane aim, why? + bonus_spread += rand(0,50) var/mult = max((GUN_AIMING_TIME + aiming_delay + user.last_click_move - world.time)/GUN_AIMING_TIME, -0.5) //Yes, there is a bonus for taking time aiming. if(mult < 0) //accurate weapons should provide a proper bonus with negative inaccuracy. the opposite is true too. mult *= 1/inaccuracy_modifier diff --git a/code/modules/projectiles/guns/ballistic.dm b/code/modules/projectiles/guns/ballistic.dm index fa8099a257..1aefa51a51 100644 --- a/code/modules/projectiles/guns/ballistic.dm +++ b/code/modules/projectiles/guns/ballistic.dm @@ -53,6 +53,8 @@ ..() if (istype(A, /obj/item/ammo_box/magazine)) var/obj/item/ammo_box/magazine/AM = A + if(AM.load_delay && !do_after(user, AM.load_delay, target = src)) + return FALSE if (!magazine && istype(AM, mag_type)) if(user.transferItemToLoc(AM, src)) magazine = AM diff --git a/code/modules/projectiles/guns/ballistic/automatic.dm b/code/modules/projectiles/guns/ballistic/automatic.dm index b31fd2d1e0..9210e66f22 100644 --- a/code/modules/projectiles/guns/ballistic/automatic.dm +++ b/code/modules/projectiles/guns/ballistic/automatic.dm @@ -18,13 +18,15 @@ /obj/item/gun/ballistic/automatic/proto/unrestricted pin = /obj/item/firing_pin -/obj/item/gun/ballistic/automatic/update_icon() - ..() +/obj/item/gun/ballistic/automatic/update_overlays() + . = ..() if(automatic_burst_overlay) if(!select) - add_overlay("[initial(icon_state)]semi") + . += ("[initial(icon_state)]semi") if(select == 1) - add_overlay("[initial(icon_state)]burst") + . += "[initial(icon_state)]burst" + +/obj/item/gun/ballistic/automatic/update_icon_state() icon_state = "[initial(icon_state)][magazine ? "-[magazine.max_ammo]" : ""][chambered ? "" : "-e"][suppressed ? "-suppressed" : ""]" /obj/item/gun/ballistic/automatic/attackby(obj/item/A, mob/user, params) @@ -115,8 +117,7 @@ . = ..() empty_alarm() -/obj/item/gun/ballistic/automatic/c20r/update_icon() - ..() +/obj/item/gun/ballistic/automatic/c20r/update_icon_state() icon_state = "c20r[magazine ? "-[CEILING(get_ammo(0)/4, 1)*4]" : ""][chambered ? "" : "-e"][suppressed ? "-suppressed" : ""]" /obj/item/gun/ballistic/automatic/wt550 @@ -141,9 +142,8 @@ . = ..() spread = 0 -/obj/item/gun/ballistic/automatic/wt550/update_icon() - ..() - icon_state = "wt550[magazine ? "-[CEILING(( (get_ammo(FALSE) / magazine.max_ammo) * 20) /4, 1)*4]" : "-0"]" //Sprites only support up to 20. +/obj/item/gun/ballistic/automatic/wt550/update_icon_state() + icon_state = "wt550[magazine ? "-[CEILING(((get_ammo(FALSE) / magazine.max_ammo) * 20) /4, 1)*4]" : "-0"]" //Sprites only support up to 20. /obj/item/gun/ballistic/automatic/mini_uzi name = "\improper Type U3 Uzi" @@ -160,6 +160,7 @@ mag_type = /obj/item/ammo_box/magazine/m556 fire_sound = 'sound/weapons/gunshot_smg.ogg' can_suppress = FALSE + automatic_burst_overlay = FALSE var/obj/item/gun/ballistic/revolver/grenadelauncher/underbarrel burst_size = 3 burst_shot_delay = 2 @@ -191,18 +192,19 @@ underbarrel.attackby(A, user, params) else ..() -/obj/item/gun/ballistic/automatic/m90/update_icon() - ..() - cut_overlays() +/obj/item/gun/ballistic/automatic/m90/update_overlays() + . = ..() switch(select) if(0) - add_overlay("[initial(icon_state)]semi") + . += "[initial(icon_state)]semi" if(1) - add_overlay("[initial(icon_state)]burst") + . += "[initial(icon_state)]burst" if(2) - add_overlay("[initial(icon_state)]gren") + . += "[initial(icon_state)]gren" + +/obj/item/gun/ballistic/automatic/m90/update_icon_state() icon_state = "[initial(icon_state)][magazine ? "" : "-e"]" - return + /obj/item/gun/ballistic/automatic/m90/burst_select() var/mob/living/carbon/human/user = usr switch(select) @@ -257,6 +259,7 @@ weapon_weight = WEAPON_MEDIUM mag_type = /obj/item/ammo_box/magazine/m12g fire_sound = 'sound/weapons/gunshot.ogg' + automatic_burst_overlay = FALSE can_suppress = FALSE burst_size = 1 pin = /obj/item/firing_pin/implant/pindicate @@ -269,10 +272,13 @@ . = ..() update_icon() -/obj/item/gun/ballistic/automatic/shotgun/bulldog/update_icon() - cut_overlays() +/obj/item/gun/ballistic/automatic/shotgun/bulldog/update_icon_state() + return + +/obj/item/gun/ballistic/automatic/shotgun/bulldog/update_overlays() + . = ..() if(magazine) - add_overlay("[magazine.icon_state]") + . += "[magazine.icon_state]" icon_state = "bulldog[chambered ? "" : "-e"]" /obj/item/gun/ballistic/automatic/shotgun/bulldog/afterattack() @@ -298,6 +304,7 @@ burst_shot_delay = 1 spread = 7 pin = /obj/item/firing_pin/implant/pindicate + automatic_burst_overlay = FALSE /obj/item/gun/ballistic/automatic/l6_saw/unrestricted pin = /obj/item/firing_pin @@ -316,7 +323,7 @@ playsound(user, 'sound/weapons/sawclose.ogg', 60, 1) update_icon() -/obj/item/gun/ballistic/automatic/l6_saw/update_icon() +/obj/item/gun/ballistic/automatic/l6_saw/update_icon_state() icon_state = "l6[cover_open ? "open" : "closed"][magazine ? CEILING(get_ammo(0)/12.5, 1)*25 : "-empty"][suppressed ? "-suppressed" : ""]" item_state = "l6[cover_open ? "openmag" : "closedmag"]" @@ -369,9 +376,10 @@ zoom_amt = 10 //Long range, enough to see in front of you, but no tiles behind you. zoom_out_amt = 13 slot_flags = ITEM_SLOT_BACK + automatic_burst_overlay = FALSE actions_types = list() -/obj/item/gun/ballistic/automatic/sniper_rifle/update_icon() +/obj/item/gun/ballistic/automatic/sniper_rifle/update_icon_state() if(magazine) icon_state = "sniper-mag" else @@ -397,9 +405,10 @@ can_suppress = TRUE w_class = WEIGHT_CLASS_HUGE slot_flags = ITEM_SLOT_BACK + automatic_burst_overlay = FALSE actions_types = list() -/obj/item/gun/ballistic/automatic/surplus/update_icon() +/obj/item/gun/ballistic/automatic/surplus/update_icon_state() if(magazine) icon_state = "surplus" else @@ -413,6 +422,7 @@ icon_state = "oldrifle" item_state = "arg" mag_type = /obj/item/ammo_box/magazine/recharge + automatic_burst_overlay = FALSE fire_delay = 2 can_suppress = FALSE burst_size = 1 @@ -420,7 +430,5 @@ fire_sound = 'sound/weapons/laser.ogg' casing_ejector = FALSE -/obj/item/gun/ballistic/automatic/laser/update_icon() - ..() +/obj/item/gun/ballistic/automatic/laser/update_icon_state() icon_state = "oldrifle[magazine ? "-[CEILING(get_ammo(0)/4, 1)*4]" : ""]" - return diff --git a/code/modules/projectiles/guns/ballistic/launchers.dm b/code/modules/projectiles/guns/ballistic/launchers.dm index 004f78235a..9e03207888 100644 --- a/code/modules/projectiles/guns/ballistic/launchers.dm +++ b/code/modules/projectiles/guns/ballistic/launchers.dm @@ -42,8 +42,7 @@ actions_types = list() casing_ejector = FALSE -/obj/item/gun/ballistic/automatic/gyropistol/update_icon() - ..() +/obj/item/gun/ballistic/automatic/gyropistol/update_icon_state() icon_state = "[initial(icon_state)][magazine ? "loaded" : ""]" /obj/item/gun/ballistic/automatic/speargun @@ -54,6 +53,7 @@ w_class = WEIGHT_CLASS_BULKY force = 10 can_suppress = FALSE + automatic_burst_overlay = FALSE mag_type = /obj/item/ammo_box/magazine/internal/speargun fire_sound = 'sound/weapons/grenadelaunch.ogg' burst_size = 1 @@ -62,8 +62,9 @@ actions_types = list() casing_ejector = FALSE -/obj/item/gun/ballistic/automatic/speargun/update_icon() - return +/obj/item/gun/ballistic/automatic/speargun/ComponentInitialize() + . = ..() + AddElement(/datum/element/update_icon_blocker) /obj/item/gun/ballistic/automatic/speargun/attack_self() return @@ -137,7 +138,7 @@ chamber_round() update_icon() -/obj/item/gun/ballistic/rocketlauncher/update_icon() +/obj/item/gun/ballistic/rocketlauncher/update_icon_state() icon_state = "[initial(icon_state)]-[chambered ? "1" : "0"]" /obj/item/gun/ballistic/rocketlauncher/suicide_act(mob/living/user) diff --git a/code/modules/projectiles/guns/ballistic/magweapon.dm b/code/modules/projectiles/guns/ballistic/magweapon.dm index 74b8b210a7..4e27a73300 100644 --- a/code/modules/projectiles/guns/ballistic/magweapon.dm +++ b/code/modules/projectiles/guns/ballistic/magweapon.dm @@ -75,8 +75,7 @@ recoil = 2 weapon_weight = WEAPON_HEAVY -/obj/item/gun/ballistic/automatic/magrifle/hyperburst/update_icon() - ..() +/obj/item/gun/ballistic/automatic/magrifle/hyperburst/update_icon_state() icon_state = "hyperburst[magazine ? "-[get_ammo()]" : ""][chambered ? "" : "-e"]" ///magpistol/// @@ -92,12 +91,14 @@ fire_delay = 2 inaccuracy_modifier = 0.25 cell_type = /obj/item/stock_parts/cell/magnetic/pistol + automatic_burst_overlay = FALSE -/obj/item/gun/ballistic/automatic/magrifle/pistol/update_icon() - ..() - cut_overlays() +/obj/item/gun/ballistic/automatic/magrifle/pistol/update_overlays() + . = ..() if(magazine) - add_overlay("magpistol-magazine") + . += "magpistol-magazine" + +/obj/item/gun/ballistic/automatic/magrifle/pistol/update_icon_state() icon_state = "[initial(icon_state)][chambered ? "" : "-e"]" /obj/item/gun/ballistic/automatic/magrifle/pistol/nopin diff --git a/code/modules/projectiles/guns/ballistic/pistol.dm b/code/modules/projectiles/guns/ballistic/pistol.dm index cdaadb5c3b..e775fdc05a 100644 --- a/code/modules/projectiles/guns/ballistic/pistol.dm +++ b/code/modules/projectiles/guns/ballistic/pistol.dm @@ -8,12 +8,12 @@ burst_size = 1 fire_delay = 0 actions_types = list() + automatic_burst_overlay = FALSE /obj/item/gun/ballistic/automatic/pistol/no_mag spawnwithmagazine = FALSE -/obj/item/gun/ballistic/automatic/pistol/update_icon() - ..() +/obj/item/gun/ballistic/automatic/pistol/update_icon_state() icon_state = "[initial(icon_state)][chambered ? "" : "-e"][suppressed ? "-suppressed" : ""]" /obj/item/gun/ballistic/automatic/pistol/suppressed/Initialize(mapload) @@ -28,6 +28,7 @@ icon = 'modular_citadel/icons/obj/guns/cit_guns.dmi' icon_state = "cde" can_unsuppress = TRUE + automatic_burst_overlay = FALSE obj_flags = UNIQUE_RENAME unique_reskin = list("Default" = "cde", "N-99" = "n99", @@ -38,20 +39,18 @@ "PX4 Storm" = "px4" ) -/obj/item/gun/ballistic/automatic/pistol/modular/update_icon() - ..() +/obj/item/gun/ballistic/automatic/pistol/modular/update_icon_state() if(current_skin) icon_state = "[unique_reskin[current_skin]][chambered ? "" : "-e"][suppressed ? "-suppressed" : ""]" else icon_state = "[initial(icon_state)][chambered ? "" : "-e"][suppressed ? "-suppressed" : ""]" + +/obj/item/gun/ballistic/automatic/pistol/modular/update_overlays() + . = ..() if(magazine && suppressed) - cut_overlays() - add_overlay("[unique_reskin[current_skin]]-magazine-sup") //Yes, this means the default iconstate can't have a magazine overlay + . += "[unique_reskin[current_skin]]-magazine-sup" //Yes, this means the default iconstate can't have a magazine overlay else if (magazine) - cut_overlays() - add_overlay("[unique_reskin[current_skin]]-magazine") - else - cut_overlays() + . += "[unique_reskin[current_skin]]-magazine" /obj/item/gun/ballistic/automatic/pistol/m1911 name = "\improper M1911" @@ -77,14 +76,14 @@ force = 14 mag_type = /obj/item/ammo_box/magazine/m50 can_suppress = FALSE + automatic_burst_overlay = FALSE -/obj/item/gun/ballistic/automatic/pistol/deagle/update_icon() - ..() +/obj/item/gun/ballistic/automatic/pistol/deagle/update_overlays() + . = ..() if(magazine) - cut_overlays() - add_overlay("deagle_magazine") - else - cut_overlays() + . += "deagle_magazine" + +/obj/item/gun/ballistic/automatic/pistol/deagle/update_icon_state() icon_state = "[initial(icon_state)][chambered ? "" : "-e"]" /obj/item/gun/ballistic/automatic/pistol/deagle/gold @@ -142,14 +141,14 @@ actions_types = list() fire_sound = 'sound/weapons/blastcannon.ogg' spread = 20 //damn thing has no rifling. + automatic_burst_overlay = FALSE -/obj/item/gun/ballistic/automatic/pistol/antitank/update_icon() - ..() +/obj/item/gun/ballistic/automatic/pistol/antitank/update_overlays() + . = ..() if(magazine) - cut_overlays() - add_overlay("atp-mag") - else - cut_overlays() + . += "atp-mag" + +/obj/item/gun/ballistic/automatic/pistol/antitank/update_icon_state() icon_state = "[initial(icon_state)][chambered ? "" : "-e"]" /obj/item/gun/ballistic/automatic/pistol/antitank/syndicate diff --git a/code/modules/projectiles/guns/ballistic/revolver.dm b/code/modules/projectiles/guns/ballistic/revolver.dm index a5ed45dd48..6f1fb96af5 100644 --- a/code/modules/projectiles/guns/ballistic/revolver.dm +++ b/code/modules/projectiles/guns/ballistic/revolver.dm @@ -348,10 +348,10 @@ else to_chat(user, "You need at least ten lengths of cable if you want to make a sling!") -/obj/item/gun/ballistic/revolver/doublebarrel/improvised/update_icon() - ..() +/obj/item/gun/ballistic/revolver/doublebarrel/improvised/update_overlays() + . = ..() if(slung) - icon_state += "sling" + . += "[icon_state]sling" /obj/item/gun/ballistic/revolver/doublebarrel/improvised/sawoff(mob/user) . = ..() diff --git a/code/modules/projectiles/guns/ballistic/shotgun.dm b/code/modules/projectiles/guns/ballistic/shotgun.dm index 873b129c8f..ecf6e538b8 100644 --- a/code/modules/projectiles/guns/ballistic/shotgun.dm +++ b/code/modules/projectiles/guns/ballistic/shotgun.dm @@ -164,10 +164,10 @@ else to_chat(user, "You need at least ten lengths of cable if you want to make a sling!") -/obj/item/gun/ballistic/shotgun/boltaction/improvised/update_icon() - ..() +/obj/item/gun/ballistic/shotgun/boltaction/improvised/update_overlays() + . = ..() if(slung) - icon_state += "sling" + . += "[icon_state]sling" /obj/item/gun/ballistic/shotgun/boltaction/enchanted name = "enchanted bolt action rifle" @@ -272,7 +272,7 @@ spread = 2 update_icon() -/obj/item/gun/ballistic/shotgun/automatic/combat/compact/update_icon() +/obj/item/gun/ballistic/shotgun/automatic/combat/compact/update_icon_state() icon_state = "[current_skin ? unique_reskin[current_skin] : "cshotgun"][stock ? "" : "c"]" //Dual Feed Shotgun diff --git a/code/modules/projectiles/guns/ballistic/toy.dm b/code/modules/projectiles/guns/ballistic/toy.dm index 1f66cfdf8a..e7f26670d4 100644 --- a/code/modules/projectiles/guns/ballistic/toy.dm +++ b/code/modules/projectiles/guns/ballistic/toy.dm @@ -27,9 +27,9 @@ burst_size = 1 fire_delay = 0 actions_types = list() + automatic_burst_overlay = FALSE -/obj/item/gun/ballistic/automatic/toy/pistol/update_icon() - ..() +/obj/item/gun/ballistic/automatic/toy/pistol/update_icon_state() icon_state = "[initial(icon_state)][chambered ? "" : "-e"][suppressed ? "-suppressed" : ""]" /obj/item/gun/ballistic/automatic/toy/pistol/riot diff --git a/code/modules/projectiles/guns/energy.dm b/code/modules/projectiles/guns/energy.dm index c2b821dfcf..17dcfa96e6 100644 --- a/code/modules/projectiles/guns/energy.dm +++ b/code/modules/projectiles/guns/energy.dm @@ -29,7 +29,6 @@ var/charge_sections = 4 ammo_x_offset = 2 var/shaded_charge = FALSE //if this gun uses a stateful charge bar for more detail - var/old_ratio = 0 // stores the gun's previous ammo "ratio" to see if it needs an updated icon var/selfcharge = EGUN_NO_SELFCHARGE // EGUN_SELFCHARGE if true, EGUN_SELFCHARGE_BORG drains the cyborg's cell to recharge its own var/charge_tick = 0 var/charge_delay = 4 @@ -64,10 +63,20 @@ START_PROCESSING(SSobj, src) update_icon() +/obj/item/gun/energy/ComponentInitialize() + . = ..() + AddElement(/datum/element/update_icon_updates_onmob) + /obj/item/gun/energy/Destroy() STOP_PROCESSING(SSobj, src) return ..() +/obj/item/gun/energy/handle_atom_del(atom/A) + if(A == cell) + cell = null + update_icon() + return ..() + /obj/item/gun/energy/examine(mob/user) . = ..() if(!right_click_overridden) @@ -226,46 +235,47 @@ #undef DECREMENT_OR_WRAP #undef IS_VALID_INDEX -/obj/item/gun/energy/update_icon(force_update) - if(QDELETED(src)) +/obj/item/gun/energy/update_icon_state() + if(initial(item_state)) return ..() + var/ratio = get_charge_ratio() + var/new_item_state = "" + new_item_state = initial(icon_state) + if(modifystate) + var/obj/item/ammo_casing/energy/shot = ammo_type[current_firemode_index] + new_item_state += "[shot.select_name]" + new_item_state += "[ratio]" + item_state = new_item_state + +/obj/item/gun/energy/update_overlays() + . = ..() + if(QDELETED(src)) + return if(!automatic_charge_overlays) return - var/ratio = can_shoot() ? CEILING(clamp(cell.charge / cell.maxcharge, 0, 1) * charge_sections, 1) : 0 - // Sets the ratio to 0 if the gun doesn't have enough charge to fire, or if it's power cell is removed. - // TG issues #5361 & #47908 - if(ratio == old_ratio && !force_update) - return - old_ratio = ratio - cut_overlays() - var/iconState = "[icon_state]_charge" - var/itemState = null - if(!initial(item_state)) - itemState = icon_state + var/overlay_icon_state = "[icon_state]_charge" + var/ratio = get_charge_ratio() if (modifystate) var/obj/item/ammo_casing/energy/shot = ammo_type[current_firemode_index] - add_overlay("[icon_state]_[shot.select_name]") - iconState += "_[shot.select_name]" - if(itemState) - itemState += "[shot.select_name]" + . += "[icon_state]_[shot.select_name]" + overlay_icon_state += "_[shot.select_name]" if(ratio == 0) - add_overlay("[icon_state]_empty") + . += "[icon_state]_empty" else if(!shaded_charge) - var/mutable_appearance/charge_overlay = mutable_appearance(icon, iconState) + var/mutable_appearance/charge_overlay = mutable_appearance(icon, overlay_icon_state) for(var/i = ratio, i >= 1, i--) charge_overlay.pixel_x = ammo_x_offset * (i - 1) charge_overlay.pixel_y = ammo_y_offset * (i - 1) - add_overlay(charge_overlay) + . += charge_overlay else - add_overlay("[icon_state]_charge[ratio]") - if(itemState) - itemState += "[ratio]" - item_state = itemState - if(ismob(loc)) //forces inhands to update - var/mob/M = loc - M.update_inv_hands() + . += "[icon_state]_charge[ratio]" + +///Used by update_icon_state() and update_overlays() +/obj/item/gun/energy/proc/get_charge_ratio() + return can_shoot() ? CEILING(clamp(cell.charge / cell.maxcharge, 0, 1) * charge_sections, 1) : 0 + // Sets the ratio to 0 if the gun doesn't have enough charge to fire, or if its power cell is removed. /obj/item/gun/energy/suicide_act(mob/living/user) if (istype(user) && can_shoot() && can_trigger_gun(user) && user.get_bodypart(BODY_ZONE_HEAD)) diff --git a/code/modules/projectiles/guns/energy/dueling.dm b/code/modules/projectiles/guns/energy/dueling.dm index 80bb269b21..04eff5afa9 100644 --- a/code/modules/projectiles/guns/energy/dueling.dm +++ b/code/modules/projectiles/guns/energy/dueling.dm @@ -207,12 +207,11 @@ to_chat(user,"You switch [src] setting to [setting] mode.") update_icon() -/obj/item/gun/energy/dueling/update_icon(force_update) +/obj/item/gun/energy/dueling/update_overlays(force_update) . = ..() if(setting_overlay) - cut_overlay(setting_overlay) setting_overlay.icon_state = setting_iconstate() - add_overlay(setting_overlay) + . += setting_overlay /obj/item/gun/energy/dueling/Destroy() if(duel) @@ -363,8 +362,7 @@ STR.max_items = 2 STR.can_hold = typecacheof(/obj/item/gun/energy/dueling) -/obj/item/storage/lockbox/dueling/update_icon() - cut_overlays() +/obj/item/storage/lockbox/dueling/update_icon_state() var/locked = SEND_SIGNAL(src, COMSIG_IS_STORAGE_LOCKED) if(locked) icon_state = "medalbox+l" diff --git a/code/modules/projectiles/guns/energy/energy_gun.dm b/code/modules/projectiles/guns/energy/energy_gun.dm index 1b835d35a4..2c9794f391 100644 --- a/code/modules/projectiles/guns/energy/energy_gun.dm +++ b/code/modules/projectiles/guns/energy/energy_gun.dm @@ -19,17 +19,13 @@ cell_type = /obj/item/stock_parts/cell{charge = 600; maxcharge = 600} ammo_x_offset = 2 charge_sections = 3 + gunlight_state = "mini-light" can_flashlight = 0 // Can't attach or detach the flashlight, and override it's icon update /obj/item/gun/energy/e_gun/mini/Initialize() gun_light = new /obj/item/flashlight/seclite(src) return ..() -/obj/item/gun/energy/e_gun/mini/update_icon() - ..() - if(gun_light && gun_light.on) - add_overlay("mini-light") - /obj/item/gun/energy/e_gun/stun name = "tactical energy gun" desc = "Military issue energy gun, is able to fire stun rounds." @@ -138,15 +134,15 @@ return fail_chance = min(fail_chance + round(15/severity), 100) -/obj/item/gun/energy/e_gun/nuclear/update_icon() - ..() +/obj/item/gun/energy/e_gun/nuclear/update_overlays() + . = ..() if(crit_fail) - add_overlay("[icon_state]_fail_3") + . += "[icon_state]_fail_3" else switch(fail_tick) if(0) - add_overlay("[icon_state]_fail_0") + . += "[icon_state]_fail_0" if(1 to 150) - add_overlay("[icon_state]_fail_1") + . += "[icon_state]_fail_1" if(151 to INFINITY) - add_overlay("[icon_state]_fail_2") + . += "[icon_state]_fail_2" diff --git a/code/modules/projectiles/guns/energy/kinetic_accelerator.dm b/code/modules/projectiles/guns/energy/kinetic_accelerator.dm index 0c723199a1..c1f47ccd1a 100644 --- a/code/modules/projectiles/guns/energy/kinetic_accelerator.dm +++ b/code/modules/projectiles/guns/energy/kinetic_accelerator.dm @@ -46,13 +46,6 @@ range = 4 log_override = TRUE -/obj/item/gun/energy/kinetic_accelerator/premiumka/update_icon() - ..() - if(!can_shoot()) - add_overlay("[icon_state]_empty") - else - cut_overlays() - /obj/item/gun/energy/kinetic_accelerator/getinaccuracy(mob/living/user, bonus_spread, stamloss) var/old_fire_delay = fire_delay //It's pretty irrelevant tbh but whatever. fire_delay = overheat_time @@ -186,12 +179,10 @@ update_icon() overheat = FALSE -/obj/item/gun/energy/kinetic_accelerator/update_icon() - ..() +/obj/item/gun/energy/kinetic_accelerator/update_overlays() + . = ..() if(!can_shoot()) - add_overlay("[icon_state]_empty") - else - cut_overlays() + . += "[icon_state]_empty" //Casing /obj/item/ammo_casing/energy/kinetic diff --git a/code/modules/projectiles/guns/energy/special.dm b/code/modules/projectiles/guns/energy/special.dm index 20e847326e..19ca42022d 100644 --- a/code/modules/projectiles/guns/energy/special.dm +++ b/code/modules/projectiles/guns/energy/special.dm @@ -34,11 +34,11 @@ pin = null ammo_x_offset = 1 -/obj/item/gun/energy/decloner/update_icon() +/obj/item/gun/energy/decloner/update_overlays() ..() var/obj/item/ammo_casing/energy/shot = ammo_type[current_firemode_index] if(!QDELETED(cell) && (cell.charge > shot.e_cost)) - add_overlay("decloner_spin") + . += "decloner_spin" /obj/item/gun/energy/floragun name = "floral somatoray" @@ -134,9 +134,10 @@ tool_behaviour = TOOL_WELDER toolspeed = 0.7 //plasmacutters can be used as welders, and are faster than standard welders -/obj/item/gun/energy/plasmacutter/Initialize() +/obj/item/gun/energy/plasmacutter/ComponentInitialize() . = ..() AddComponent(/datum/component/butchering, 25, 105, 0, 'sound/weapons/plasma_cutter.ogg') + AddElement(/datum/element/update_icon_blocker) /obj/item/gun/energy/plasmacutter/examine(mob/user) . = ..() @@ -166,9 +167,6 @@ /obj/item/gun/energy/plasmacutter/use(amount) return cell.use(amount * 100) -/obj/item/gun/energy/plasmacutter/update_icon() - return - /obj/item/gun/energy/plasmacutter/adv name = "advanced plasma cutter" icon_state = "adv_plasmacutter" @@ -183,11 +181,12 @@ icon_state = "wormhole_projector" pin = null inaccuracy_modifier = 0.25 + automatic_charge_overlays = FALSE var/obj/effect/portal/p_blue var/obj/effect/portal/p_orange var/atmos_link = FALSE -/obj/item/gun/energy/wormhole_projector/update_icon() +/obj/item/gun/energy/wormhole_projector/update_icon_state() icon_state = "[initial(icon_state)][current_firemode_index]" item_state = icon_state @@ -256,8 +255,9 @@ can_charge = 0 use_cyborg_cell = 1 -/obj/item/gun/energy/printer/update_icon() - return +/obj/item/gun/energy/printer/ComponentInitialize() + . = ..() + AddElement(/datum/element/update_icon_blocker) /obj/item/gun/energy/printer/emp_act() return @@ -321,14 +321,14 @@ inaccuracy_modifier = 0.25 cell_type = /obj/item/stock_parts/cell/super ammo_type = list(/obj/item/ammo_casing/energy/emitter) + automatic_charge_overlays = FALSE -/obj/item/gun/energy/emitter/update_icon() - ..() +/obj/item/gun/energy/emitter/update_icon_state() var/obj/item/ammo_casing/energy/shot = ammo_type[current_firemode_index] if(!QDELETED(cell) && (cell.charge > shot.e_cost)) - add_overlay("emitter_carbine_empty") + icon_state = "emitter_carbine_empty" else - add_overlay("emitter_carbine") + icon_state = "emitter_carbine" //the pickle ray /obj/item/gun/energy/pickle_gun diff --git a/code/modules/projectiles/guns/misc/beam_rifle.dm b/code/modules/projectiles/guns/misc/beam_rifle.dm index fd09aa7f9d..5e250d44e2 100644 --- a/code/modules/projectiles/guns/misc/beam_rifle.dm +++ b/code/modules/projectiles/guns/misc/beam_rifle.dm @@ -35,6 +35,7 @@ slowdown = 1 item_flags = NO_MAT_REDEMPTION | SLOWS_WHILE_IN_HAND | NEEDS_PERMIT pin = null + automatic_charge_overlays = FALSE var/aiming = FALSE var/aiming_time = 14 var/aiming_time_fire_threshold = 5 @@ -152,13 +153,13 @@ current_zoom_x = 0 current_zoom_y = 0 -/obj/item/gun/energy/beam_rifle/update_icon() - cut_overlays() +/obj/item/gun/energy/beam_rifle/update_overlays() + . = ..() var/obj/item/ammo_casing/energy/primary_ammo = ammo_type[1] if(!QDELETED(cell) && (cell.charge > primary_ammo.e_cost)) - add_overlay(charged_overlay) + . += charged_overlay else - add_overlay(drained_overlay) + . += drained_overlay /obj/item/gun/energy/beam_rifle/attack_self(mob/user) if(!structure_piercing) diff --git a/code/modules/projectiles/guns/misc/blastcannon.dm b/code/modules/projectiles/guns/misc/blastcannon.dm index 1c8d519ba8..60b7565333 100644 --- a/code/modules/projectiles/guns/misc/blastcannon.dm +++ b/code/modules/projectiles/guns/misc/blastcannon.dm @@ -41,18 +41,16 @@ user.put_in_hands(bomb) user.visible_message("[user] detaches [bomb] from [src].") bomb = null + name = initial(name) + desc = initial(desc) update_icon() return ..() -/obj/item/gun/blastcannon/update_icon() +/obj/item/gun/blastcannon/update_icon_state() if(bomb) icon_state = icon_state_loaded - name = "blast cannon" - desc = "A makeshift device used to concentrate a bomb's blast energy to a narrow wave." else icon_state = initial(icon_state) - name = initial(name) - desc = initial(desc) /obj/item/gun/blastcannon/attackby(obj/O, mob/user) if(istype(O, /obj/item/transfer_valve)) @@ -65,6 +63,8 @@ return FALSE user.visible_message("[user] attaches [T] to [src]!") bomb = T + name = "blast cannon" + desc = "A makeshift device used to concentrate a bomb's blast energy to a narrow wave." update_icon() return TRUE return ..() diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm index 43384280d4..99a0bedc4d 100644 --- a/code/modules/projectiles/projectile.dm +++ b/code/modules/projectiles/projectile.dm @@ -327,16 +327,18 @@ if(!trajectory) return var/turf/T = get_turf(A) - if(check_ricochet(A) && A.handle_ricochet(src)) //if you can ricochet, attempt to ricochet off the object - on_ricochet(A) //if allowed, use autoaim to ricochet into someone, otherwise default to ricocheting off the object from above - var/datum/point/pcache = trajectory.copy_to() - if(hitscan) - store_hitscan_collision(pcache) - decayedRange = max(0, decayedRange - reflect_range_decrease) - ricochet_chance *= ricochet_decay_chance - damage *= ricochet_decay_damage - range = decayedRange - return TRUE + if(check_ricochet_flag(A) && check_ricochet(A)) //if you can ricochet, attempt to ricochet off the object + ricochets++ + if(A.handle_ricochet(src)) + on_ricochet(A) //if allowed, use autoaim to ricochet into someone, otherwise default to ricocheting off the object from above + var/datum/point/pcache = trajectory.copy_to() + if(hitscan) + store_hitscan_collision(pcache) + decayedRange = max(0, decayedRange - reflect_range_decrease) + ricochet_chance *= ricochet_decay_chance + damage *= ricochet_decay_damage + range = decayedRange + return TRUE var/distance = get_dist(T, starting) // Get the distance between the turf shot from and the mob we hit and use that for the calculations. if(def_zone && check_zone(def_zone) != BODY_ZONE_CHEST) @@ -680,7 +682,8 @@ if(!ignore_source_check && firer) var/mob/M = firer if((target == firer) || ((target == firer.loc) && ismecha(firer.loc)) || (target in firer.buckled_mobs) || (istype(M) && (M.buckled == target))) - return FALSE + if(!ricochets) //if it has ricocheted, it can hit the firer. + return FALSE if(!ignore_loc && (loc != target.loc)) return FALSE if(target in passthrough) diff --git a/code/modules/projectiles/projectile/bullets/revolver.dm b/code/modules/projectiles/projectile/bullets/revolver.dm index 95d43ba1ce..ec3cadc31a 100644 --- a/code/modules/projectiles/projectile/bullets/revolver.dm +++ b/code/modules/projectiles/projectile/bullets/revolver.dm @@ -126,4 +126,15 @@ ricochet_auto_aim_angle = 50 ricochet_auto_aim_range = 6 ricochet_incidence_leeway = 80 - ricochet_decay_chance = 1 \ No newline at end of file + ricochet_decay_chance = 1 + +/obj/item/projectile/bullet/a357/dumdum + name = ".357 DumDum bullet" // the warcrime bullet + damage = 40 + armour_penetration = -20 + wound_bonus = 45 + bare_wound_bonus = 45 + sharpness = SHARP_EDGED + embedding = list(embed_chance=90, fall_chance=2, jostle_chance=5, ignore_throwspeed_threshold=TRUE, pain_stam_pct=0.4, pain_mult=5, jostle_pain_mult=6, rip_time=10) + wound_falloff_tile = -1 + embed_falloff_tile = -5 diff --git a/code/modules/projectiles/projectile/special/plasma.dm b/code/modules/projectiles/projectile/special/plasma.dm index 33559fa92c..77509cb574 100644 --- a/code/modules/projectiles/projectile/special/plasma.dm +++ b/code/modules/projectiles/projectile/special/plasma.dm @@ -2,7 +2,7 @@ name = "plasma blast" icon_state = "plasmacutter" damage_type = BRUTE - damage = 20 + damage = 10 range = 4 dismemberment = 20 impact_effect_type = /obj/effect/temp_visual/impact_effect/purple_laser @@ -32,12 +32,12 @@ return BULLET_ACT_FORCE_PIERCE /obj/item/projectile/plasma/adv - damage = 28 + damage = 14 range = 5 mine_range = 5 /obj/item/projectile/plasma/adv/mech - damage = 40 + damage = 20 range = 9 mine_range = 3 @@ -52,4 +52,4 @@ dismemberment = 0 damage = 10 range = 4 - mine_range = 0 \ No newline at end of file + mine_range = 0 diff --git a/code/modules/reagents/chemistry/holder.dm b/code/modules/reagents/chemistry/holder.dm index c2662a8342..c489edf88e 100644 --- a/code/modules/reagents/chemistry/holder.dm +++ b/code/modules/reagents/chemistry/holder.dm @@ -1165,3 +1165,9 @@ random_reagents += R var/picked_reagent = pick(random_reagents) return picked_reagent + +/proc/get_chem_id(chem_name) + for(var/X in GLOB.chemical_reagents_list) + var/datum/reagent/R = GLOB.chemical_reagents_list[X] + if(ckey(chem_name) == ckey(lowertext(R.name))) + return X diff --git a/code/modules/reagents/chemistry/machinery/chem_dispenser.dm b/code/modules/reagents/chemistry/machinery/chem_dispenser.dm index da33f935da..db16a10d1d 100644 --- a/code/modules/reagents/chemistry/machinery/chem_dispenser.dm +++ b/code/modules/reagents/chemistry/machinery/chem_dispenser.dm @@ -177,11 +177,10 @@ beaker = null update_icon() -/obj/machinery/chem_dispenser/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ - datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) +/obj/machinery/chem_dispenser/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) if(!ui) - ui = new(user, src, ui_key, "ChemDispenser", name, 565, 550, master_ui, state) + ui = new(user, src, "ChemDispenser", name) if(user.hallucinating()) ui.set_autoupdate(FALSE) //to not ruin the immersion by constantly changing the fake chemicals ui.open() @@ -216,7 +215,7 @@ data["beakerTransferAmounts"] = null data["beakerCurrentpH"] = null - var/list/chemicals = list() + var/chemicals[0] var/is_hallucinating = FALSE if(user.hallucinating()) is_hallucinating = TRUE @@ -275,7 +274,7 @@ . = TRUE if("eject") replace_beaker(usr) - . = TRUE //no afterattack + . = TRUE if("dispense_recipe") if(!is_operational() || QDELETED(cell)) return @@ -326,9 +325,9 @@ for(var/reagent in recording_recipe) var/reagent_id = GLOB.name2reagent[translate_legacy_chem_id(reagent)] if(!dispensable_reagents.Find(reagent_id)) - visible_message("[src] buzzes.", "You hear a faint buzz.") + visible_message("[src] buzzes.", "You hear a faint buzz.") to_chat(usr, "[src] cannot find [reagent]!") - playsound(src, 'sound/machines/buzz-two.ogg', 50, 1) + playsound(src, 'sound/machines/buzz-two.ogg', 50, TRUE) return saved_recipes[name] = recording_recipe recording_recipe = null diff --git a/code/modules/reagents/chemistry/machinery/chem_heater.dm b/code/modules/reagents/chemistry/machinery/chem_heater.dm index 5697a2385c..28f0b2366a 100644 --- a/code/modules/reagents/chemistry/machinery/chem_heater.dm +++ b/code/modules/reagents/chemistry/machinery/chem_heater.dm @@ -7,6 +7,7 @@ idle_power_usage = 40 resistance_flags = FIRE_PROOF | ACID_PROOF circuit = /obj/item/circuitboard/machine/chem_heater + var/obj/item/reagent_containers/beaker = null var/target_temperature = 300 var/heater_coefficient = 0.1 @@ -30,22 +31,20 @@ /obj/machinery/chem_heater/AltClick(mob/living/user) . = ..() - if(!istype(user) || !user.canUseTopic(src, BE_CLOSE, FALSE, NO_TK)) + if(!can_interact(user) || !user.canUseTopic(src, BE_CLOSE, FALSE, NO_TK)) return replace_beaker(user) - return TRUE /obj/machinery/chem_heater/proc/replace_beaker(mob/living/user, obj/item/reagent_containers/new_beaker) + if(!user) + return FALSE if(beaker) - beaker.forceMove(drop_location()) - if(user && Adjacent(user) && user.can_hold_items()) - user.put_in_hands(beaker) + user.put_in_hands(beaker) + beaker = null if(new_beaker) beaker = new_beaker - else - beaker = null - update_icon() - return TRUE + update_icon() + return TRUE /obj/machinery/chem_heater/RefreshParts() heater_coefficient = 0.1 @@ -63,6 +62,7 @@ return if(on) if(beaker && beaker.reagents.total_volume) + //keep constant with the chemical acclimator please beaker.reagents.adjust_thermal_energy((target_temperature - beaker.reagents.chem_temp) * heater_coefficient * SPECIFIC_HEAT_DEFAULT * beaker.reagents.total_volume) beaker.reagents.handle_reactions() @@ -83,27 +83,16 @@ updateUsrDialog() update_icon() return - - if(beaker) - if(istype(I, /obj/item/reagent_containers/dropper)) - var/obj/item/reagent_containers/dropper/D = I - D.afterattack(beaker, user, 1) - - if(istype(I, /obj/item/reagent_containers/syringe)) - var/obj/item/reagent_containers/syringe/S = I - S.afterattack(beaker, user, 1) - return ..() /obj/machinery/chem_heater/on_deconstruction() replace_beaker() return ..() -/obj/machinery/chem_heater/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ - datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) +/obj/machinery/chem_heater/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) if(!ui) - ui = new(user, src, ui_key, "ChemHeater", name, 300, 400, master_ui, state) + ui = new(user, src, "ChemHeater", name) ui.open() /obj/machinery/chem_heater/ui_data() @@ -140,14 +129,7 @@ . = TRUE if("temperature") var/target = params["target"] - var/adjust = text2num(params["adjust"]) - if(target == "input") - target = input("New target temperature:", name, target_temperature) as num|null - if(!isnull(target) && !..()) - . = TRUE - else if(adjust) - target = target_temperature + adjust - else if(text2num(target) != null) + if(text2num(target) != null) target = text2num(target) . = TRUE if(.) diff --git a/code/modules/reagents/chemistry/machinery/chem_master.dm b/code/modules/reagents/chemistry/machinery/chem_master.dm index dd9dd7c0bf..32ac7cecba 100644 --- a/code/modules/reagents/chemistry/machinery/chem_master.dm +++ b/code/modules/reagents/chemistry/machinery/chem_master.dm @@ -1,5 +1,3 @@ -#define PILL_STYLE_COUNT 22 //Update this if you add more pill icons or you die -#define RANDOM_PILL_STYLE 22 //Dont change this one though /obj/machinery/chem_master name = "ChemMaster 3000" @@ -12,6 +10,7 @@ idle_power_usage = 20 resistance_flags = FIRE_PROOF | ACID_PROOF circuit = /obj/item/circuitboard/machine/chem_master + var/obj/item/reagent_containers/beaker = null var/obj/item/storage/pill_bottle/bottle = null var/mode = 1 @@ -154,19 +153,15 @@ bottle?.forceMove(A) return ..() -//Insert our custom spritesheet css link into the html -/obj/machinery/chem_master/ui_base_html(html) - var/datum/asset/spritesheet/assets = get_asset_datum(/datum/asset/spritesheet/simple/pills) - . = replacetext(html, "", assets.css_tag()) +/obj/machinery/chem_master/ui_assets(mob/user) + return list( + get_asset_datum(/datum/asset/spritesheet/simple/pills), + ) -/obj/machinery/chem_master/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ - datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) +/obj/machinery/chem_master/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) if(!ui) - var/datum/asset/assets = get_asset_datum(/datum/asset/spritesheet/simple/pills) - assets.send(user) - - ui = new(user, src, ui_key, "ChemMaster", name, 520, 550, master_ui, state) + ui = new(user, src, "ChemMaster", name) ui.open() /obj/machinery/chem_master/ui_data(mob/user) @@ -183,8 +178,8 @@ data["isPillBottleLoaded"] = bottle ? 1 : 0 if(bottle) var/datum/component/storage/STRB = bottle.GetComponent(/datum/component/storage) - data["pillBotContent"] = bottle.contents.len - data["pillBotMaxContent"] = STRB.max_items + data["pillBottleCurrentAmount"] = bottle.contents.len + data["pillBottleMaxAmount"] = STRB.max_items var/beakerContents[0] if(beaker) @@ -206,213 +201,219 @@ if(..()) return - switch(action) - if("eject") - replace_beaker(usr) - . = TRUE + if(action == "eject") + replace_beaker(usr) + return TRUE - if("ejectPillBottle") - replace_pillbottle(usr) - . = TRUE - - if("transfer") - if(!beaker) - return FALSE - var/reagent = GLOB.name2reagent[params["id"]] - var/amount = text2num(params["amount"]) - var/to_container = params["to"] - // Custom amount - if (amount == -1) - amount = text2num(input( - "Enter the amount you want to transfer:", - name, "")) - if (amount == null || amount <= 0) - return FALSE - if (to_container == "buffer") - end_fermi_reaction() - beaker.reagents.trans_id_to(src, reagent, amount) - return TRUE - if (to_container == "beaker" && mode) - end_fermi_reaction() - reagents.trans_id_to(beaker, reagent, amount) - return TRUE - if (to_container == "beaker" && !mode) - end_fermi_reaction() - reagents.remove_reagent(reagent, amount) - return TRUE + if(action == "ejectPillBottle") + if(!bottle) return FALSE + bottle.forceMove(drop_location()) + adjust_item_drop_location(bottle) + bottle = null + return TRUE - if("toggleMode") - mode = !mode - . = TRUE + if(action == "transfer") + if(!beaker) + return FALSE + var/reagent = GLOB.name2reagent[params["id"]] + var/amount = text2num(params["amount"]) + var/to_container = params["to"] + // Custom amount + if (amount == -1) + amount = text2num(input( + "Enter the amount you want to transfer:", + name, "")) + if (amount == null || amount <= 0) + return FALSE + if (to_container == "buffer") + end_fermi_reaction() + beaker.reagents.trans_id_to(src, reagent, amount) + return TRUE + if (to_container == "beaker" && mode) + end_fermi_reaction() + reagents.trans_id_to(beaker, reagent, amount) + return TRUE + if (to_container == "beaker" && !mode) + end_fermi_reaction() + reagents.remove_reagent(reagent, amount) + return TRUE + return FALSE - if("pillStyle") - var/id = text2num(params["id"]) - chosenPillStyle = id + if(action == "toggleMode") + mode = !mode + return TRUE + + if(action == "pillStyle") + var/id = text2num(params["id"]) + chosenPillStyle = id + return TRUE + + if(action == "create") + if(reagents.total_volume == 0) + return FALSE + var/item_type = params["type"] + // Get amount of items + var/amount = text2num(params["amount"]) + if(amount == null) + amount = text2num(input(usr, + "Max 10. Buffer content will be split evenly.", + "How many to make?", 1)) + amount = clamp(round(amount), 0, 10) + if (amount <= 0) + return FALSE + // Get units per item + var/vol_each = text2num(params["volume"]) + var/vol_each_text = params["volume"] + var/vol_each_max = reagents.total_volume / amount + if (item_type == "pill") + vol_each_max = min(50, vol_each_max) + else if (item_type == "patch") + vol_each_max = min(40, vol_each_max) + else if (item_type == "bottle") + vol_each_max = min(30, vol_each_max) + else if (item_type == "condimentPack") + vol_each_max = min(10, vol_each_max) + else if (item_type == "condimentBottle") + vol_each_max = min(50, vol_each_max) + else if (item_type == "hypoVial") + vol_each_max = min(60, vol_each_max) + else if (item_type == "smartDart") + vol_each_max = min(20, vol_each_max) + else + return FALSE + if(vol_each_text == "auto") + vol_each = vol_each_max + if(vol_each == null) + vol_each = text2num(input(usr, + "Maximum [vol_each_max] units per item.", + "How many units to fill?", + vol_each_max)) + vol_each = clamp(vol_each, 0, vol_each_max) + if(vol_each <= 0) + return FALSE + // Get item name + var/name = params["name"] + var/name_has_units = item_type == "pill" || item_type == "patch" + if(!name) + var/name_default = reagents.get_master_reagent_name() + if (name_has_units) + name_default += " ([vol_each]u)" + name = stripped_input(usr, + "Name:", + "Give it a name!", + name_default, + MAX_NAME_LEN) + if(!name || !reagents.total_volume || !src || QDELETED(src) || !usr.canUseTopic(src, !issilicon(usr))) + return FALSE + // Start filling + if(item_type == "pill") + var/obj/item/reagent_containers/pill/P + var/target_loc = drop_location() + var/drop_threshold = INFINITY + if(bottle) + var/datum/component/storage/STRB = bottle.GetComponent( + /datum/component/storage) + if(STRB) + drop_threshold = STRB.max_items - bottle.contents.len + for(var/i = 0; i < amount; i++) + if(i < drop_threshold) + P = new/obj/item/reagent_containers/pill(target_loc) + else + P = new/obj/item/reagent_containers/pill(drop_location()) + P.name = trim("[name] pill") + if(chosenPillStyle == RANDOM_PILL_STYLE) + P.icon_state ="pill[rand(1,21)]" + else + P.icon_state = "pill[chosenPillStyle]" + if(P.icon_state == "pill4") + P.desc = "A tablet or capsule, but not just any, a red one, one taken by the ones not scared of knowledge, freedom, uncertainty and the brutal truths of reality." + adjust_item_drop_location(P) + reagents.trans_to(P, vol_each)//, transfered_by = usr) + return TRUE + if(item_type == "patch") + var/obj/item/reagent_containers/pill/patch/P + for(var/i = 0; i < amount; i++) + P = new/obj/item/reagent_containers/pill/patch(drop_location()) + P.name = trim("[name] patch") + adjust_item_drop_location(P) + reagents.trans_to(P, vol_each)//, transfered_by = usr) + return TRUE + if(item_type == "bottle") + var/obj/item/reagent_containers/glass/bottle/P + for(var/i = 0; i < amount; i++) + P = new/obj/item/reagent_containers/glass/bottle(drop_location()) + P.name = trim("[name] bottle") + adjust_item_drop_location(P) + reagents.trans_to(P, vol_each)//, transfered_by = usr) + return TRUE + if(item_type == "condimentPack") + var/obj/item/reagent_containers/food/condiment/pack/P + for(var/i = 0; i < amount; i++) + P = new/obj/item/reagent_containers/food/condiment/pack(drop_location()) + P.originalname = name + P.name = trim("[name] pack") + P.desc = "A small condiment pack. The label says it contains [name]." + reagents.trans_to(P, vol_each)//, transfered_by = usr) + return TRUE + if(item_type == "condimentBottle") + var/obj/item/reagent_containers/food/condiment/P + for(var/i = 0; i < amount; i++) + P = new/obj/item/reagent_containers/food/condiment(drop_location()) + P.originalname = name + P.name = trim("[name] bottle") + reagents.trans_to(P, vol_each)//, transfered_by = usr) + return TRUE + if(item_type == "hypoVial") + var/obj/item/reagent_containers/glass/bottle/vial/small/P + for(var/i = 0; i < amount; i++) + P = new/obj/item/reagent_containers/glass/bottle/vial/small(drop_location()) + P.name = trim("[name] hypovial") + adjust_item_drop_location(P) + reagents.trans_to(P, vol_each)//, transfered_by = usr) + return TRUE + if(item_type == "smartDart") + var/obj/item/reagent_containers/syringe/dart/P + for(var/i = 0; i < amount; i++) + P = new /obj/item/reagent_containers/syringe/dart(drop_location()) + P.name = trim("[name] SmartDart") + adjust_item_drop_location(P) + reagents.trans_to(P, vol_each)//, transfered_by = usr) + P.mode=!mode + P.update_icon() + return TRUE + return FALSE + + if(action == "analyze") + // var/datum/reagent/R = GLOB.name2reagent[params["id"]] + var/reagent = GLOB.name2reagent[params["id"]] + var/datum/reagent/R = GLOB.chemical_reagents_list[reagent] + if(R) + var/state = "Unknown" + if(initial(R.reagent_state) == 1) + state = "Solid" + else if(initial(R.reagent_state) == 2) + state = "Liquid" + else if(initial(R.reagent_state) == 3) + state = "Gas" + var/const/P = 3 //The number of seconds between life ticks + var/T = initial(R.metabolization_rate) * (60 / P) + if(istype(R, /datum/reagent/fermi)) + fermianalyze = TRUE + var/datum/chemical_reaction/Rcr = get_chemical_reaction(reagent) + var/pHpeakCache = (Rcr.OptimalpHMin + Rcr.OptimalpHMax)/2 + analyzeVars = list("name" = initial(R.name), "state" = state, "color" = initial(R.color), "description" = initial(R.description), "metaRate" = T, "overD" = initial(R.overdose_threshold), "addicD" = initial(R.addiction_threshold), "purityF" = R.purity, "inverseRatioF" = initial(R.inverse_chem_val), "purityE" = initial(Rcr.PurityMin), "minTemp" = initial(Rcr.OptimalTempMin), "maxTemp" = initial(Rcr.OptimalTempMax), "eTemp" = initial(Rcr.ExplodeTemp), "pHpeak" = pHpeakCache) + else + fermianalyze = FALSE + analyzeVars = list("name" = initial(R.name), "state" = state, "color" = initial(R.color), "description" = initial(R.description), "metaRate" = T, "overD" = initial(R.overdose_threshold), "addicD" = initial(R.addiction_threshold)) + screen = "analyze" return TRUE - if("create") - if(reagents.total_volume == 0) - return FALSE - var/item_type = params["type"] - // Get amount of items - var/amount = text2num(params["amount"]) - if(amount == null) - amount = text2num(input(usr, - "Max 20. Buffer content will be split evenly.", - "How many to make?", 1)) - amount = clamp(round(amount), 0, 20) - if (amount <= 0) - return FALSE - // Get units per item - var/vol_each = text2num(params["volume"]) - var/vol_each_text = params["volume"] - var/vol_each_max = reagents.total_volume / amount - if (item_type == "pill") - vol_each_max = min(50, vol_each_max) - else if (item_type == "patch") - vol_each_max = min(40, vol_each_max) - else if (item_type == "bottle") - vol_each_max = min(30, vol_each_max) - else if (item_type == "condimentPack") - vol_each_max = min(10, vol_each_max) - else if (item_type == "condimentBottle") - vol_each_max = min(50, vol_each_max) - else if (item_type == "hypoVial") - vol_each_max = min(60, vol_each_max) - else if (item_type == "smartDart") - vol_each_max = min(20, vol_each_max) - else - return FALSE - if(vol_each_text == "auto") - vol_each = vol_each_max - if(vol_each == null) - vol_each = text2num(input(usr, - "Maximum [vol_each_max] units per item.", - "How many units to fill?", - vol_each_max)) - vol_each = clamp(vol_each, 0, vol_each_max) - if(vol_each <= 0) - return FALSE - // Get item name - var/name = params["name"] - var/name_has_units = item_type == "pill" || item_type == "patch" - if(!name) - var/name_default = reagents.get_master_reagent_name() - if (name_has_units) - name_default += " ([vol_each]u)" - name = stripped_input(usr, - "Name:", - "Give it a name!", - name_default, - MAX_NAME_LEN) - if(!name || !reagents.total_volume || !src || QDELETED(src) || !usr.canUseTopic(src, !issilicon(usr))) - return FALSE - // Start filling - if(item_type == "pill") - var/obj/item/reagent_containers/pill/P - var/target_loc = drop_location() - var/drop_threshold = INFINITY - if(bottle) - var/datum/component/storage/STRB = bottle.GetComponent( - /datum/component/storage) - if(STRB) - drop_threshold = STRB.max_items - bottle.contents.len - for(var/i = 0; i < amount; i++) - if(i < drop_threshold) - P = new/obj/item/reagent_containers/pill(target_loc) - else - P = new/obj/item/reagent_containers/pill(drop_location()) - P.name = trim("[name] pill") - if(chosenPillStyle == RANDOM_PILL_STYLE) - P.icon_state ="pill[rand(1,21)]" - else - P.icon_state = "pill[chosenPillStyle]" - if(P.icon_state == "pill4") - P.desc = "A tablet or capsule, but not just any, a red one, one taken by the ones not scared of knowledge, freedom, uncertainty and the brutal truths of reality." - adjust_item_drop_location(P) - reagents.trans_to(P, vol_each) - return TRUE - if(item_type == "patch") - var/obj/item/reagent_containers/pill/patch/P - for(var/i = 0; i < amount; i++) - P = new/obj/item/reagent_containers/pill/patch(drop_location()) - P.name = trim("[name] patch") - adjust_item_drop_location(P) - reagents.trans_to(P, vol_each) - return TRUE - if(item_type == "bottle") - var/obj/item/reagent_containers/glass/bottle/P - for(var/i = 0; i < amount; i++) - P = new/obj/item/reagent_containers/glass/bottle(drop_location()) - P.name = trim("[name] bottle") - adjust_item_drop_location(P) - reagents.trans_to(P, vol_each) - return TRUE - if(item_type == "condimentPack") - var/obj/item/reagent_containers/food/condiment/pack/P - for(var/i = 0; i < amount; i++) - P = new/obj/item/reagent_containers/food/condiment/pack(drop_location()) - P.originalname = name - P.name = trim("[name] pack") - P.desc = "A small condiment pack. The label says it contains [name]." - reagents.trans_to(P, vol_each) - return TRUE - if(item_type == "condimentBottle") - var/obj/item/reagent_containers/food/condiment/P - for(var/i = 0; i < amount; i++) - P = new/obj/item/reagent_containers/food/condiment(drop_location()) - P.originalname = name - P.name = trim("[name] bottle") - reagents.trans_to(P, vol_each) - return TRUE - if(item_type == "hypoVial") - var/obj/item/reagent_containers/glass/bottle/vial/small/P - for(var/i = 0; i < amount; i++) - P = new/obj/item/reagent_containers/glass/bottle/vial/small(drop_location()) - P.name = trim("[name] hypovial") - adjust_item_drop_location(P) - reagents.trans_to(P, vol_each) - return TRUE - if(item_type == "smartDart") - var/obj/item/reagent_containers/syringe/dart/P - for(var/i = 0; i < amount; i++) - P = new /obj/item/reagent_containers/syringe/dart(drop_location()) - P.name = trim("[name] SmartDart") - adjust_item_drop_location(P) - reagents.trans_to(P, vol_each) - P.mode=!mode - P.update_icon() - return TRUE - return FALSE + if(action == "goScreen") + screen = params["screen"] + return TRUE - if("analyze") - var/reagent = GLOB.name2reagent[params["id"]] - var/datum/reagent/R = GLOB.chemical_reagents_list[reagent] - if(R) - var/state = "Unknown" - if(initial(R.reagent_state) == 1) - state = "Solid" - else if(initial(R.reagent_state) == 2) - state = "Liquid" - else if(initial(R.reagent_state) == 3) - state = "Gas" - var/const/P = 3 //The number of seconds between life ticks - var/T = initial(R.metabolization_rate) * (60 / P) - if(istype(R, /datum/reagent/fermi)) - fermianalyze = TRUE - var/datum/chemical_reaction/Rcr = get_chemical_reaction(reagent) - var/pHpeakCache = (Rcr.OptimalpHMin + Rcr.OptimalpHMax)/2 - analyzeVars = list("name" = initial(R.name), "state" = state, "color" = initial(R.color), "description" = initial(R.description), "metaRate" = T, "overD" = initial(R.overdose_threshold), "addicD" = initial(R.addiction_threshold), "purityF" = R.purity, "inverseRatioF" = initial(R.inverse_chem_val), "purityE" = initial(Rcr.PurityMin), "minTemp" = initial(Rcr.OptimalTempMin), "maxTemp" = initial(Rcr.OptimalTempMax), "eTemp" = initial(Rcr.ExplodeTemp), "pHpeak" = pHpeakCache) - else - fermianalyze = FALSE - analyzeVars = list("name" = initial(R.name), "state" = state, "color" = initial(R.color), "description" = initial(R.description), "metaRate" = T, "overD" = initial(R.overdose_threshold), "addicD" = initial(R.addiction_threshold)) - screen = "analyze" - return TRUE - - if("goScreen") - screen = params["screen"] - . = TRUE + return FALSE diff --git a/code/modules/reagents/chemistry/machinery/chem_synthesizer.dm b/code/modules/reagents/chemistry/machinery/chem_synthesizer.dm index 66c2616972..489f9dd179 100644 --- a/code/modules/reagents/chemistry/machinery/chem_synthesizer.dm +++ b/code/modules/reagents/chemistry/machinery/chem_synthesizer.dm @@ -12,11 +12,10 @@ "tricord" = /datum/reagent/medicine/tricordrazine ) -/obj/machinery/chem_dispenser/chem_synthesizer/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ - datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) +/obj/machinery/chem_dispenser/chem_synthesizer/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) if(!ui) - ui = new(user, src, ui_key, "ChemDebugSynthesizer", name, 390, 330, master_ui, state) + ui = new(user, src, "ChemDebugSynthesizer", name) ui.open() /obj/machinery/chem_dispenser/chem_synthesizer/ui_act(action, params) @@ -31,7 +30,11 @@ beaker = null . = TRUE if("input") - var/input_reagent = replacetext(lowertext(input("Enter the name of any reagent", "Input") as text), " ", "") //95% of the time, the reagent types is a lowercase, no spaces / underscored version of the name + var/input_reagent = replacetext(lowertext(input("Enter the name of any reagent", "Input") as text|null), " ", "") //95% of the time, the reagent id is a lowercase/no spaces version of the name + + if (isnull(input_reagent)) + return + if(shortcuts[input_reagent]) input_reagent = shortcuts[input_reagent] else @@ -51,7 +54,7 @@ beaker = new /obj/item/reagent_containers/glass/beaker/bluespace(src) visible_message("[src] dispenses a bluespace beaker.") if("amount") - var/input = input("Units to dispense", "Units") as num|null + var/input = text2num(params["amount"]) if(input) amount = input update_icon() diff --git a/code/modules/reagents/chemistry/machinery/pandemic.dm b/code/modules/reagents/chemistry/machinery/pandemic.dm index 4a4bbdb546..36e102be72 100644 --- a/code/modules/reagents/chemistry/machinery/pandemic.dm +++ b/code/modules/reagents/chemistry/machinery/pandemic.dm @@ -7,10 +7,11 @@ density = TRUE icon = 'icons/obj/chemical.dmi' icon_state = "mixer0" - circuit = /obj/item/circuitboard/computer/pandemic use_power = TRUE idle_power_usage = 20 resistance_flags = ACID_PROOF + circuit = /obj/item/circuitboard/computer/pandemic + var/wait var/datum/symptom/selected_symptom var/obj/item/reagent_containers/beaker @@ -23,11 +24,27 @@ QDEL_NULL(beaker) return ..() -/obj/machinery/computer/pandemic/handle_atom_del(atom/A) +/obj/machinery/computer/pandemic/examine(mob/user) . = ..() + if(beaker) + var/is_close + if(Adjacent(user)) //don't reveal exactly what's inside unless they're close enough to see the UI anyway. + . += "It contains \a [beaker]." + is_close = TRUE + else + . += "It has a beaker inside it." + . += "Alt-click to eject [is_close ? beaker : "the beaker"]." + +/obj/machinery/computer/pandemic/AltClick(mob/user) + . = ..() + if(user.canUseTopic(src, BE_CLOSE)) + eject_beaker() + +/obj/machinery/computer/pandemic/handle_atom_del(atom/A) if(A == beaker) beaker = null update_icon() + return ..() /obj/machinery/computer/pandemic/proc/get_by_index(thing, index) if(!beaker || !beaker.reagents) @@ -107,7 +124,7 @@ /obj/machinery/computer/pandemic/proc/reset_replicator_cooldown() wait = FALSE update_icon() - playsound(loc, 'sound/machines/ping.ogg', 30, 1) + playsound(src, 'sound/machines/ping.ogg', 30, TRUE) /obj/machinery/computer/pandemic/update_icon_state() if(stat & BROKEN) @@ -117,13 +134,19 @@ /obj/machinery/computer/pandemic/update_overlays() . = ..() - if(!(stat & BROKEN) && wait) + if(wait) . += "waitlight" -/obj/machinery/computer/pandemic/ui_interact(mob/user, ui_key = "main", datum/tgui/ui, force_open = FALSE, datum/tgui/master_ui, datum/ui_state/state = GLOB.default_state) - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) +/obj/machinery/computer/pandemic/proc/eject_beaker() + if(beaker) + beaker.forceMove(drop_location()) + beaker = null + update_icon() + +/obj/machinery/computer/pandemic/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) if(!ui) - ui = new(user, src, ui_key, "Pandemic", name, 520, 550, master_ui, state) + ui = new(user, src, "Pandemic", name) ui.open() /obj/machinery/computer/pandemic/ui_data(mob/user) @@ -135,9 +158,9 @@ var/datum/reagent/blood/B = locate() in beaker.reagents.reagent_list if(B) data["has_blood"] = TRUE - data[/datum/reagent/blood] = list() - data[/datum/reagent/blood]["dna"] = B.data["blood_DNA"] || "none" - data[/datum/reagent/blood]["type"] = B.data["blood_type"] || "none" + data["blood"] = list() //wha why the fuck are we sending pathtypes to tgui frontend? + data["blood"]["dna"] = B.data["blood_DNA"] || "none" + data["blood"]["type"] = B.data["blood_type"] || "none" data["viruses"] = get_viruses_data(B) data["resistances"] = get_resistance_data(B) else @@ -153,7 +176,7 @@ return switch(action) if("eject_beaker") - replace_beaker(usr) + eject_beaker() . = TRUE if("empty_beaker") if(beaker) @@ -162,7 +185,7 @@ if("empty_eject_beaker") if(beaker) beaker.reagents.clear_reagents() - replace_beaker(usr) + eject_beaker() . = TRUE if("rename_disease") var/id = get_virus_id_by_index(text2num(params["index"])) @@ -170,75 +193,62 @@ if(!A.mutable) return if(A) - var/new_name = sanitize_name(html_encode(trim(params["name"], 50))) + var/new_name = sanitize_name(html_encode(trim(params["name"], 50)))//, allow_numbers = TRUE) if(!new_name || ..()) return A.AssignName(new_name) . = TRUE if("create_culture_bottle") + if (wait) + return var/id = get_virus_id_by_index(text2num(params["index"])) var/datum/disease/advance/A = SSdisease.archive_diseases[id] if(!istype(A) || !A.mutable) to_chat(usr, "ERROR: Cannot replicate virus strain.") return - wait = TRUE - addtimer(CALLBACK(src, .proc/reset_replicator_cooldown), 50) A = A.Copy() - var/list/data = list("blood_DNA" = "UNKNOWN DNA", "blood_type" = "SY", "viruses" = list(A)) + var/list/data = list("viruses" = list(A)) var/obj/item/reagent_containers/glass/bottle/B = new(drop_location()) B.name = "[A.name] culture bottle" B.desc = "A small bottle. Contains [A.agent] culture in synthblood medium." B.reagents.add_reagent(/datum/reagent/blood/synthetics, 10, data) + wait = TRUE update_icon() var/turf/source_turf = get_turf(src) log_virus("A culture bottle was printed for the virus [A.admin_details()] at [loc_name(source_turf)] by [key_name(usr)]") - + addtimer(CALLBACK(src, .proc/reset_replicator_cooldown), 50) . = TRUE if("create_vaccine_bottle") - wait = TRUE - addtimer(CALLBACK(src, .proc/reset_replicator_cooldown), 400) + if (wait) + return var/id = params["index"] var/datum/disease/D = SSdisease.archive_diseases[id] var/obj/item/reagent_containers/glass/bottle/B = new(drop_location()) B.name = "[D.name] vaccine bottle" B.reagents.add_reagent(/datum/reagent/vaccine, 15, list(id)) - + wait = TRUE update_icon() - + addtimer(CALLBACK(src, .proc/reset_replicator_cooldown), 200) . = TRUE + /obj/machinery/computer/pandemic/attackby(obj/item/I, mob/user, params) if(istype(I, /obj/item/reagent_containers) && !(I.item_flags & ABSTRACT) && I.is_open_container()) . = TRUE //no afterattack if(stat & (NOPOWER|BROKEN)) return - var/obj/item/reagent_containers/B = I - if(!user.transferItemToLoc(B, src)) + if(beaker) + to_chat(user, "A container is already loaded into [src]!") return - replace_beaker(user, B) + if(!user.transferItemToLoc(I, src)) + return + + beaker = I to_chat(user, "You insert [I] into [src].") + update_icon() else return ..() -/obj/machinery/computer/pandemic/AltClick(mob/living/user) - . = ..() - if(!istype(user) || !user.canUseTopic(src, BE_CLOSE, FALSE, NO_TK)) - return - replace_beaker(user) - return TRUE - -/obj/machinery/computer/pandemic/proc/replace_beaker(mob/living/user, obj/item/reagent_containers/new_beaker) - if(beaker) - if(user && Adjacent(user) && user.can_hold_items()) - if(!user.put_in_hands(beaker)) - beaker.forceMove(drop_location()) - if(new_beaker) - beaker = new_beaker - else - beaker = null - update_icon() - return TRUE - /obj/machinery/computer/pandemic/on_deconstruction() - replace_beaker(usr) + eject_beaker() . = ..() diff --git a/code/modules/reagents/chemistry/machinery/smoke_machine.dm b/code/modules/reagents/chemistry/machinery/smoke_machine.dm index cac90d1c14..d22523c4b8 100644 --- a/code/modules/reagents/chemistry/machinery/smoke_machine.dm +++ b/code/modules/reagents/chemistry/machinery/smoke_machine.dm @@ -7,6 +7,7 @@ icon_state = "smoke0" density = TRUE circuit = /obj/item/circuitboard/machine/smoke_machine + var/efficiency = 10 var/on = FALSE var/cooldown = 0 @@ -31,9 +32,18 @@ /obj/machinery/smoke_machine/Initialize() . = ..() create_reagents(REAGENTS_BASE_VOLUME) + // AddComponent(/datum/component/plumbing/simple_demand) for(var/obj/item/stock_parts/matter_bin/B in component_parts) reagents.maximum_volume += REAGENTS_BASE_VOLUME * B.rating +/obj/machinery/smoke_machine/ComponentInitialize() + . = ..() + AddComponent(/datum/component/simple_rotation, ROTATION_ALTCLICK | ROTATION_CLOCKWISE | ROTATION_COUNTERCLOCKWISE | ROTATION_VERBS, null, CALLBACK(src, .proc/can_be_rotated)) + AddComponent(/datum/component/plumbing/simple_demand) //this SURELY CANT' LEAD TO BAD THINGS HAPPENING. + +/obj/machinery/smoke_machine/proc/can_be_rotated(mob/user, rotation_type) + return !anchored + /obj/machinery/smoke_machine/update_icon_state() if((!is_operational()) || (!on) || (reagents.total_volume == 0)) if (panel_open) @@ -81,10 +91,9 @@ add_fingerprint(user) if(istype(I, /obj/item/reagent_containers) && I.is_open_container()) var/obj/item/reagent_containers/RC = I - var/units = RC.reagents.trans_to(src, RC.amount_per_transfer_from_this) + var/units = RC.reagents.trans_to(src, RC.amount_per_transfer_from_this) //, transfered_by = user) if(units) to_chat(user, "You transfer [units] units of the solution to [src].") - log_combat(usr, src, "has added [english_list(RC.reagents.reagent_list)] to [src]") return if(default_unfasten_wrench(user, I, 40)) on = FALSE @@ -100,11 +109,10 @@ reagents.clear_reagents() return ..() -/obj/machinery/smoke_machine/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ - datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) +/obj/machinery/smoke_machine/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) if(!ui) - ui = new(user, src, ui_key, "SmokeMachine", name, 350, 350, master_ui, state) + ui = new(user, src, "SmokeMachine", name) ui.open() /obj/machinery/smoke_machine/ui_data(mob/user) diff --git a/code/modules/reagents/chemistry/reagents.dm b/code/modules/reagents/chemistry/reagents.dm index a85ac8b085..672127cb11 100644 --- a/code/modules/reagents/chemistry/reagents.dm +++ b/code/modules/reagents/chemistry/reagents.dm @@ -8,6 +8,7 @@ GLOBAL_LIST_INIT(name2reagent, build_name2reagent()) if (length(initial(R.name))) .[ckey(initial(R.name))] = t + //Various reagents //Toxin & acid reagents //Hydroponics stuff @@ -52,6 +53,14 @@ GLOBAL_LIST_INIT(name2reagent, build_name2reagent()) var/metabolizing = FALSE var/chemical_flags // See fermi/readme.dm REAGENT_DEAD_PROCESS, REAGENT_DONOTSPLIT, REAGENT_ONLYINVERSE, REAGENT_ONMOBMERGE, REAGENT_INVISIBLE, REAGENT_FORCEONNEW, REAGENT_SNEAKYNAME var/value = REAGENT_VALUE_NONE //How much does it sell for in cargo? + var/datum/material/material //are we made of material? + +/datum/reagent/New() + . = ..() + + if(material) + material = SSmaterials.GetMaterialRef(material) + /datum/reagent/Destroy() // This should only be called by the holder, so it's already handled clearing its references . = ..() @@ -220,4 +229,3 @@ GLOBAL_LIST_INIT(name2reagent, build_name2reagent()) bloodsuckerdatum.handle_eat_human_food(disgust, blood_puke, force) if(blood_change) bloodsuckerdatum.AddBloodVolume(blood_change) - diff --git a/code/modules/reagents/chemistry/reagents/drink_reagents.dm b/code/modules/reagents/chemistry/reagents/drink_reagents.dm index 103061088e..e1433eb64e 100644 --- a/code/modules/reagents/chemistry/reagents/drink_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/drink_reagents.dm @@ -1044,12 +1044,6 @@ M.emote("nya") if(prob(20)) to_chat(M, "[pick("Headpats feel nice.", "Backrubs would be nice.", "Mew")]") - if(ishuman(M)) - var/mob/living/carbon/human/H = M - var/list/adjusted = H.adjust_arousal(5,aphro = TRUE) - for(var/g in adjusted) - var/obj/item/organ/genital/G = g - to_chat(M, "You feel like playing with your [G.name]!") ..() /datum/reagent/consumable/monkey_energy diff --git a/code/modules/reagents/chemistry/reagents/drug_reagents.dm b/code/modules/reagents/chemistry/reagents/drug_reagents.dm index 96f2c04598..44b6e85f47 100644 --- a/code/modules/reagents/chemistry/reagents/drug_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/drug_reagents.dm @@ -559,128 +559,3 @@ var/mob/living/carbon/C = M if(!C.undergoing_cardiac_arrest()) C.set_heartattack(TRUE) - -//aphrodisiac & anaphrodisiac - -/datum/reagent/drug/aphrodisiac - name = "Crocin" - description = "Naturally found in the crocus and gardenia flowers, this drug acts as a natural and safe aphrodisiac." - taste_description = "strawberries" - color = "#FFADFF"//PINK, rgb(255, 173, 255) - can_synth = FALSE - -/datum/reagent/drug/aphrodisiac/on_mob_life(mob/living/M) - if(M && M.client?.prefs.arousable && !(M.client?.prefs.cit_toggles & NO_APHRO)) - if((prob(min(current_cycle/2,5)))) - M.emote(pick("moan","blush")) - if(prob(min(current_cycle/4,10))) - var/aroused_message = pick("You feel frisky.", "You're having trouble suppressing your urges.", "You feel in the mood.") - to_chat(M, "[aroused_message]") - if(ishuman(M)) - var/mob/living/carbon/human/H = M - var/list/genits = H.adjust_arousal(current_cycle, aphro = TRUE) // redundant but should still be here - for(var/g in genits) - var/obj/item/organ/genital/G = g - to_chat(M, "[G.arousal_verb]!") - ..() - -/datum/reagent/drug/aphrodisiacplus - name = "Hexacrocin" - description = "Chemically condensed form of basic crocin. This aphrodisiac is extremely powerful and addictive in most animals.\ - Addiction withdrawals can cause brain damage and shortness of breath. Overdosage can lead to brain damage and a \ - permanent increase in libido (commonly referred to as 'bimbofication')." - taste_description = "liquid desire" - color = "#FF2BFF"//dark pink - addiction_threshold = 20 - overdose_threshold = 20 - can_synth = FALSE - -/datum/reagent/drug/aphrodisiacplus/on_mob_life(mob/living/M) - if(M && M.client?.prefs.arousable && !(M.client?.prefs.cit_toggles & NO_APHRO)) - if(prob(5)) - if(prob(current_cycle)) - M.say(pick("Hnnnnngghh...", "Ohh...", "Mmnnn...")) - else - M.emote(pick("moan","blush")) - if(prob(5)) - var/aroused_message - if(current_cycle>25) - aroused_message = pick("You need to fuck someone!", "You're bursting with sexual tension!", "You can't get sex off your mind!") - else - aroused_message = pick("You feel a bit hot.", "You feel strong sexual urges.", "You feel in the mood.", "You're ready to go down on someone.") - to_chat(M, "[aroused_message]") - REMOVE_TRAIT(M,TRAIT_NEVERBONER,APHRO_TRAIT) - if(ishuman(M)) - var/mob/living/carbon/human/H = M - var/list/genits = H.adjust_arousal(100, aphro = TRUE) // redundant but should still be here - for(var/g in genits) - var/obj/item/organ/genital/G = g - to_chat(M, "[G.arousal_verb]!") - ..() - -/datum/reagent/drug/aphrodisiacplus/addiction_act_stage2(mob/living/M) - if(prob(30)) - M.adjustOrganLoss(ORGAN_SLOT_BRAIN, 2) - ..() -/datum/reagent/drug/aphrodisiacplus/addiction_act_stage3(mob/living/M) - if(prob(30)) - M.adjustOrganLoss(ORGAN_SLOT_BRAIN, 3) - - ..() -/datum/reagent/drug/aphrodisiacplus/addiction_act_stage4(mob/living/M) - if(prob(30)) - M.adjustOrganLoss(ORGAN_SLOT_BRAIN, 4) - ..() - -/datum/reagent/drug/aphrodisiacplus/overdose_process(mob/living/M) - if(M && M.client?.prefs.arousable && !(M.client?.prefs.cit_toggles & NO_APHRO) && prob(33)) - if(prob(5) && ishuman(M) && M.has_dna() && (M.client?.prefs.cit_toggles & BIMBOFICATION)) - if(!HAS_TRAIT(M,TRAIT_PERMABONER)) - to_chat(M, "Your libido is going haywire!") - ADD_TRAIT(M,TRAIT_PERMABONER,APHRO_TRAIT) - ..() - -/datum/reagent/drug/anaphrodisiac - name = "Camphor" - description = "Naturally found in some species of evergreen trees, camphor is a waxy substance. When injested by most animals, it acts as an anaphrodisiac\ - , reducing libido and calming them. Non-habit forming and not addictive." - taste_description = "dull bitterness" - taste_mult = 2 - color = "#D9D9D9"//rgb(217, 217, 217) - reagent_state = SOLID - can_synth = FALSE - -/datum/reagent/drug/anaphrodisiac/on_mob_life(mob/living/M) - if(M && M.client?.prefs.arousable && prob(16)) - if(ishuman(M)) - var/mob/living/carbon/human/H = M - var/list/genits = H.adjust_arousal(-100, aphro = TRUE) - if(genits.len) - to_chat(M, "You no longer feel aroused.") - ..() - -/datum/reagent/drug/anaphrodisiacplus - name = "Hexacamphor" - description = "Chemically condensed camphor. Causes an extreme reduction in libido and a permanent one if overdosed. Non-addictive." - taste_description = "tranquil celibacy" - color = "#D9D9D9"//rgb(217, 217, 217) - reagent_state = SOLID - overdose_threshold = 20 - can_synth = FALSE - -/datum/reagent/drug/anaphrodisiacplus/on_mob_life(mob/living/M) - if(M && M.client?.prefs.arousable) - REMOVE_TRAIT(M,TRAIT_PERMABONER,APHRO_TRAIT) - if(ishuman(M)) - var/mob/living/carbon/human/H = M - var/list/genits = H.adjust_arousal(-100, aphro = TRUE) - if(genits.len) - to_chat(M, "You no longer feel aroused.") - - ..() - -/datum/reagent/drug/anaphrodisiacplus/overdose_process(mob/living/M) - if(M && M.client?.prefs.arousable && prob(5)) - to_chat(M, "You feel like you'll never feel aroused again...") - ADD_TRAIT(M,TRAIT_NEVERBONER,APHRO_TRAIT) - ..() diff --git a/code/modules/reagents/chemistry/reagents/food_reagents.dm b/code/modules/reagents/chemistry/reagents/food_reagents.dm index d449fa310c..18203f1a4c 100644 --- a/code/modules/reagents/chemistry/reagents/food_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/food_reagents.dm @@ -132,8 +132,8 @@ "You're covered in boiling oil!") M.emote("scream") playsound(M, 'sound/machines/fryer/deep_fryer_emerge.ogg', 25, TRUE) - var/oil_damage = max((holder.chem_temp / fry_temperature) * 0.33,1) //Damage taken per unit - M.adjustFireLoss(oil_damage * max(reac_volume,20)) //Damage caps at 20 + var/oil_damage = min((holder.chem_temp / fry_temperature) * 0.33,1) //Damage taken per unit + M.adjustFireLoss(oil_damage * min(reac_volume,20)) //Damage caps at 20 else ..() return TRUE @@ -768,7 +768,6 @@ color = "#97ee63" taste_description = "pure electricity" -/* //We don't have ethereals here, so I'll just comment it out. /datum/reagent/consumable/liquidelectricity/reaction_mob(mob/living/M, method=TOUCH, reac_volume) //can't be on life because of the way blood works. if((method == INGEST || method == INJECT || method == PATCH) && iscarbon(M)) @@ -776,10 +775,9 @@ var/obj/item/organ/stomach/ethereal/stomach = C.getorganslot(ORGAN_SLOT_STOMACH) if(istype(stomach)) stomach.adjust_charge(reac_volume * REM) -*/ /datum/reagent/consumable/liquidelectricity/on_mob_life(mob/living/carbon/M) - if(prob(25)) // && !isethereal(M)) + if(prob(25) && !isethereal(M)) M.electrocute_act(rand(10,15), "Liquid Electricity in their body", 1) //lmao at the newbs who eat energy bars playsound(M, "sparks", 50, TRUE) return ..() diff --git a/code/modules/reagents/chemistry/reagents/medicine_reagents.dm b/code/modules/reagents/chemistry/reagents/medicine_reagents.dm index 8bb34c0a82..37010cbbb5 100644 --- a/code/modules/reagents/chemistry/reagents/medicine_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/medicine_reagents.dm @@ -515,12 +515,13 @@ overdose_threshold = 30 pH = 2 value = REAGENT_VALUE_UNCOMMON + var/healing = 0.5 /datum/reagent/medicine/omnizine/on_mob_life(mob/living/carbon/M) - M.adjustToxLoss(-0.5*REM, 0) - M.adjustOxyLoss(-0.5*REM, 0) - M.adjustBruteLoss(-0.5*REM, 0) - M.adjustFireLoss(-0.5*REM, 0) + M.adjustToxLoss(-healing*REM, 0) + M.adjustOxyLoss(-healing*REM, 0) + M.adjustBruteLoss(-healing*REM, 0) + M.adjustFireLoss(-healing*REM, 0) ..() . = 1 @@ -532,6 +533,12 @@ ..() . = 1 +/datum/reagent/medicine/omnizine/protozine + name = "Protozine" + description = "A less environmentally friendly and somewhat weaker variant of omnizine." + color = "#d8c7b7" + healing = 0.2 + /datum/reagent/medicine/calomel name = "Calomel" description = "Quickly purges the body of all chemicals. Toxin damage is dealt if the patient is in good condition." diff --git a/code/modules/reagents/chemistry/reagents/other_reagents.dm b/code/modules/reagents/chemistry/reagents/other_reagents.dm index 81ad676613..5c01fd8cf6 100644 --- a/code/modules/reagents/chemistry/reagents/other_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/other_reagents.dm @@ -313,6 +313,13 @@ metabolization_rate = 45 * REAGENTS_METABOLISM . = 1 +/datum/reagent/water/hollowwater + name = "Hollow Water" + description = "An ubiquitous chemical substance that is composed of hydrogen and oxygen, but it looks kinda hollow." + color = "#88878777" + taste_description = "emptyiness" + + /datum/reagent/water/holywater name = "Holy Water" description = "Water blessed by some deity." @@ -883,7 +890,7 @@ if(istype(O, /obj/item/stack/sheet/metal)) var/obj/item/stack/sheet/metal/M = O reac_volume = min(reac_volume, M.amount) - new/obj/item/stack/tile/bronze(get_turf(M), reac_volume) + new/obj/item/stack/sheet/bronze(get_turf(M), reac_volume) M.use(reac_volume) /datum/reagent/nitrogen @@ -950,6 +957,7 @@ color = "#1C1300" // rgb: 30, 20, 0 taste_description = "sour chalk" pH = 5 + material = /datum/material/diamond /datum/reagent/carbon/reaction_turf(turf/T, reac_volume) if(!isspaceturf(T)) @@ -1072,6 +1080,7 @@ pH = 6 overdose_threshold = 30 color = "#c2391d" + material = /datum/material/iron /datum/reagent/iron/on_mob_life(mob/living/carbon/C) if((HAS_TRAIT(C, TRAIT_NOMARROW))) @@ -1103,6 +1112,7 @@ reagent_state = SOLID color = "#F7C430" // rgb: 247, 196, 48 taste_description = "expensive metal" + material = /datum/material/gold /datum/reagent/silver name = "Silver" @@ -1110,6 +1120,7 @@ reagent_state = SOLID color = "#D0D0D0" // rgb: 208, 208, 208 taste_description = "expensive yet reasonable metal" + material = /datum/material/silver /datum/reagent/silver/reaction_mob(mob/living/M, method=TOUCH, reac_volume) if(M.has_bane(BANE_SILVER)) @@ -1123,6 +1134,7 @@ color = "#B8B8C0" // rgb: 184, 184, 192 taste_description = "the inside of a reactor" pH = 4 + material = /datum/material/uranium /datum/reagent/uranium/on_mob_life(mob/living/carbon/M) M.apply_effect(1/M.metabolism_efficiency,EFFECT_IRRADIATE,0) @@ -1144,6 +1156,7 @@ taste_description = "fizzling blue" pH = 12 value = REAGENT_VALUE_RARE + material = /datum/material/bluespace /datum/reagent/bluespace/reaction_mob(mob/living/M, method=TOUCH, reac_volume) if(method == TOUCH || method == VAPOR) @@ -1182,6 +1195,7 @@ color = "#A8A8A8" // rgb: 168, 168, 168 taste_mult = 0 pH = 10 + material = /datum/material/glass /datum/reagent/fuel name = "Welding fuel" @@ -2197,13 +2211,6 @@ M.emote("nya") if(prob(20)) to_chat(M, "[pick("Headpats feel nice.", "The feeling of a hairball...", "Backrubs would be nice.", "Whats behind those doors?")]") - if(ishuman(M)) - var/mob/living/carbon/human/H = M - var/list/adjusted = H.adjust_arousal(2,aphro = TRUE) - for(var/g in adjusted) - var/obj/item/organ/genital/G = g - to_chat(M, "You feel like playing with your [G.name]!") - ..() /datum/reagent/preservahyde @@ -2213,6 +2220,66 @@ color = "#f7685e" metabolization_rate = REAGENTS_METABOLISM * 0.25 +/datum/reagent/wittel + name = "Wittel" + description = "An extremely rare metallic-white substance only found on demon-class planets." + color = "#FFFFFF" // rgb: 255, 255, 255 + taste_mult = 0 // oderless and tasteless + +/datum/reagent/metalgen + name = "Metalgen" + data = list("material"=null) + description = "A purple metal morphic liquid, said to impose it's metallic properties on whatever it touches." + color = "#b000aa" + taste_mult = 0 // oderless and tasteless + var/applied_material_flags = MATERIAL_ADD_PREFIX | MATERIAL_COLOR + var/minumum_material_amount = 100 + +/datum/reagent/metalgen/reaction_obj(obj/O, volume) + metal_morph(O) + return + +/datum/reagent/metalgen/reaction_turf(turf/T, volume) + metal_morph(T) + return + +///turn an object into a special material +/datum/reagent/metalgen/proc/metal_morph(atom/A) + var/metal_ref = data["material"] + if(!metal_ref) + return + var/metal_amount = 0 + + for(var/B in A.custom_materials) //list with what they're made of + metal_amount += A.custom_materials[B] + + if(!metal_amount) + metal_amount = minumum_material_amount //some stuff doesn't have materials at all. To still give them properties, we give them a material. Basically doesnt exist + + var/list/metal_dat = list() + metal_dat[metal_ref] = metal_amount //if we pass the list directly, byond turns metal_ref into "metal_ref" kjewrg8fwcyvf + + A.material_flags = applied_material_flags + A.set_custom_materials(metal_dat) + +/datum/reagent/gravitum + name = "Gravitum" + description = "A rare kind of null fluid, capable of temporalily removing all weight of whatever it touches." //i dont even + color = "#050096" // rgb: 5, 0, 150 + taste_mult = 0 // oderless and tasteless + metabolization_rate = 0.1 * REAGENTS_METABOLISM //20 times as long, so it's actually viable to use + var/time_multiplier = 1 MINUTES //1 minute per unit of gravitum on objects. Seems overpowered, but the whole thing is very niche + +/datum/reagent/gravitum/reaction_obj(obj/O, volume) + O.AddElement(/datum/element/forced_gravity, 0) + + addtimer(CALLBACK(O, .proc/_RemoveElement, /datum/element/forced_gravity, 0), volume * time_multiplier) + +/datum/reagent/gravitum/on_mob_add(mob/living/L) + L.AddElement(/datum/element/forced_gravity, 0) //0 is the gravity, and in this case weightless + +/datum/reagent/gravitum/on_mob_end_metabolize(mob/living/L) + L.RemoveElement(/datum/element/forced_gravity, 0) //body bluids /datum/reagent/consumable/semen @@ -2225,6 +2292,7 @@ color = "#FFFFFF" // rgb: 255, 255, 255 can_synth = FALSE nutriment_factor = 0.5 * REAGENTS_METABOLISM + var/decal_path = /obj/effect/decal/cleanable/semen /datum/reagent/consumable/semen/reaction_turf(turf/T, reac_volume) if(!istype(T)) @@ -2234,7 +2302,7 @@ var/obj/effect/decal/cleanable/semen/S = locate() in T if(!S) - S = new(T) + S = new decal_path(T) if(data["blood_DNA"]) S.add_blood_DNA(list(data["blood_DNA"] = data["blood_type"])) @@ -2258,51 +2326,20 @@ blood_DNA |= S.blood_DNA return ..() -/datum/reagent/consumable/femcum +/datum/reagent/consumable/semen/femcum name = "Female Ejaculate" description = "Vaginal lubricant found in most mammals and other animals of similar nature. Where you found this is your own business." taste_description = "something with a tang" // wew coders who haven't eaten out a girl. - taste_mult = 2 - data = list("donor"=null,"viruses"=null,"donor_DNA"=null,"blood_type"=null,"resistances"=null,"trace_chem"=null,"mind"=null,"ckey"=null,"gender"=null,"real_name"=null) - reagent_state = LIQUID color = "#AAAAAA77" - can_synth = FALSE - nutriment_factor = 0.5 * REAGENTS_METABOLISM + decal_path = /obj/effect/decal/cleanable/semen/femcum -/obj/effect/decal/cleanable/femcum +/obj/effect/decal/cleanable/semen/femcum name = "female ejaculate" - desc = null - gender = PLURAL - density = 0 - layer = ABOVE_NORMAL_TURF_LAYER - icon = 'icons/obj/genitals/effects.dmi' icon_state = "fem1" random_icon_states = list("fem1", "fem2", "fem3", "fem4") blood_state = null bloodiness = null -/obj/effect/decal/cleanable/femcum/Initialize(mapload) - . = ..() - dir = GLOB.cardinals - add_blood_DNA(list("Non-human DNA" = "A+")) - -/obj/effect/decal/cleanable/femcum/replace_decal(obj/effect/decal/cleanable/femcum/F) - if(F.blood_DNA) - blood_DNA |= F.blood_DNA - return ..() - -/datum/reagent/consumable/femcum/reaction_turf(turf/T, reac_volume) - if(!istype(T)) - return - if(reac_volume < 10) - return - - var/obj/effect/decal/cleanable/femcum/S = locate() in T - if(!S) - S = new(T) - if(data["blood_DNA"]) - S.add_blood_DNA(list(data["blood_DNA"] = data["blood_type"])) - /datum/reagent/determination name = "Determination" description = "For when you need to push on a little more. Do NOT allow near plants." @@ -2338,6 +2375,32 @@ M.adjustStaminaLoss(-0.25*REM) // the more wounds, the more stamina regen ..() +datum/reagent/eldritch + name = "Eldritch Essence" + description = "Strange liquid that defies the laws of physics" + taste_description = "Ag'hsj'saje'sh" + color = "#1f8016" + +/datum/reagent/eldritch/on_mob_life(mob/living/carbon/M) + if(IS_HERETIC(M)) + M.drowsyness = max(M.drowsyness-5, 0) + M.AdjustAllImmobility(-40, FALSE) + M.adjustStaminaLoss(-15, FALSE) + M.adjustToxLoss(-3, FALSE) + M.adjustOxyLoss(-3, FALSE) + M.adjustBruteLoss(-3, FALSE) + M.adjustFireLoss(-3, FALSE) + if(ishuman(M) && M.blood_volume < BLOOD_VOLUME_NORMAL) + M.blood_volume += 3 + else + M.adjustOrganLoss(ORGAN_SLOT_BRAIN, 3, 150) + M.adjustToxLoss(2, FALSE) + M.adjustFireLoss(2, FALSE) + M.adjustOxyLoss(2, FALSE) + M.adjustBruteLoss(2, FALSE) + holder.remove_reagent(type, 1) + return TRUE + /datum/reagent/cellulose name = "Cellulose Fibers" description = "A crystaline polydextrose polymer, plants swear by this stuff." @@ -2345,6 +2408,7 @@ color = "#E6E6DA" taste_mult = 0 + /datum/reagent/hairball name = "Hairball" description = "A bundle of keratinous bits and fibers, not easily digestible." diff --git a/code/modules/reagents/chemistry/reagents/toxin_reagents.dm b/code/modules/reagents/chemistry/reagents/toxin_reagents.dm index 8dca028b4a..07934d9880 100644 --- a/code/modules/reagents/chemistry/reagents/toxin_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/toxin_reagents.dm @@ -64,6 +64,7 @@ toxpwr = 3 pH = 4 value = REAGENT_VALUE_RARE //sheets are worth more + material = /datum/material/plasma /datum/reagent/toxin/plasma/on_mob_life(mob/living/carbon/C) if(holder.has_reagent(/datum/reagent/medicine/epinephrine)) diff --git a/code/modules/reagents/chemistry/recipes/drugs.dm b/code/modules/reagents/chemistry/recipes/drugs.dm index a2b8c27552..468d29c052 100644 --- a/code/modules/reagents/chemistry/recipes/drugs.dm +++ b/code/modules/reagents/chemistry/recipes/drugs.dm @@ -62,34 +62,3 @@ results = list(/datum/reagent/moonsugar = 1, /datum/reagent/medicine/morphine = 2.5) required_temp = 315 //a little above normal body temperature required_reagents = list(/datum/reagent/drug/skooma = 1) -/datum/chemical_reaction/aphro - name = "crocin" - id = /datum/reagent/drug/aphrodisiac - results = list(/datum/reagent/drug/aphrodisiac = 6) - required_reagents = list(/datum/reagent/carbon = 2, /datum/reagent/hydrogen = 2, /datum/reagent/oxygen = 2, /datum/reagent/water = 1) - required_temp = 400 - mix_message = "The mixture boils off a pink vapor..."//The water boils off, leaving the crocin - -/datum/chemical_reaction/aphroplus - name = "hexacrocin" - id = /datum/reagent/drug/aphrodisiacplus - results = list(/datum/reagent/drug/aphrodisiacplus = 1) - required_reagents = list(/datum/reagent/drug/aphrodisiac = 6, /datum/reagent/phenol = 1) - required_temp = 400 - mix_message = "The mixture rapidly condenses and darkens in color..." - -/datum/chemical_reaction/anaphro - name = "camphor" - id = /datum/reagent/drug/anaphrodisiac - results = list(/datum/reagent/drug/anaphrodisiac = 6) - required_reagents = list(/datum/reagent/carbon = 2, /datum/reagent/hydrogen = 2, /datum/reagent/oxygen = 2, /datum/reagent/sulfur = 1) - required_temp = 400 - mix_message = "The mixture boils off a yellow, smelly vapor..."//Sulfur burns off, leaving the camphor - -/datum/chemical_reaction/anaphroplus - name = "pentacamphor" - id = /datum/reagent/drug/anaphrodisiacplus - results = list(/datum/reagent/drug/anaphrodisiacplus = 1) - required_reagents = list(/datum/reagent/drug/aphrodisiac = 5, /datum/reagent/acetone = 1) - required_temp = 300 - mix_message = "The mixture thickens and heats up slighty..." diff --git a/code/modules/reagents/chemistry/recipes/medicine.dm b/code/modules/reagents/chemistry/recipes/medicine.dm index bb9a951cac..9e0c78d2e6 100644 --- a/code/modules/reagents/chemistry/recipes/medicine.dm +++ b/code/modules/reagents/chemistry/recipes/medicine.dm @@ -219,6 +219,12 @@ results = list(/datum/reagent/medicine/strange_reagent = 3) required_reagents = list(/datum/reagent/medicine/omnizine = 1, /datum/reagent/water/holywater = 1, /datum/reagent/toxin/mutagen = 1) +/datum/chemical_reaction/strange_reagent/alt + name = "Strange Reagent" + id = /datum/reagent/medicine/strange_reagent + results = list(/datum/reagent/medicine/strange_reagent = 2) + required_reagents = list(/datum/reagent/medicine/omnizine/protozine = 1, /datum/reagent/water/holywater = 1, /datum/reagent/toxin/mutagen = 1) + /datum/chemical_reaction/mannitol name = "Mannitol" id = /datum/reagent/medicine/mannitol @@ -345,4 +351,20 @@ /datum/chemical_reaction/medmesh/on_reaction(datum/reagents/holder, created_volume) var/location = get_turf(holder.my_atom) for(var/i = 1, i <= created_volume, i++) - new /obj/item/stack/medical/mesh/advanced(location) \ No newline at end of file + new /obj/item/stack/medical/mesh/advanced(location) + +/datum/chemical_reaction/suture + required_reagents = list(/datum/reagent/cellulose = 2, /datum/reagent/medicine/styptic_powder = 2) + +/datum/chemical_reaction/suture/on_reaction(datum/reagents/holder, created_volume) + var/location = get_turf(holder.my_atom) + for(var/i = 1, i <= created_volume, i++) + new /obj/item/stack/medical/suture/(location) + +/datum/chemical_reaction/mesh + required_reagents = list(/datum/reagent/cellulose = 2, /datum/reagent/medicine/silver_sulfadiazine = 2) + +/datum/chemical_reaction/mesh/on_reaction(datum/reagents/holder, created_volume) + var/location = get_turf(holder.my_atom) + for(var/i = 1, i <= created_volume, i++) + new /obj/item/stack/medical/mesh/(location) diff --git a/code/modules/reagents/chemistry/recipes/others.dm b/code/modules/reagents/chemistry/recipes/others.dm index f32bc708d0..92861a94ed 100644 --- a/code/modules/reagents/chemistry/recipes/others.dm +++ b/code/modules/reagents/chemistry/recipes/others.dm @@ -1,3 +1,34 @@ +/datum/chemical_reaction/metalgen + name = "metalgen" + id = /datum/reagent/metalgen + required_reagents = list(/datum/reagent/wittel = 1, /datum/reagent/bluespace = 1, /datum/reagent/toxin/mutagen = 1) + results = list(/datum/reagent/metalgen = 1) + +/datum/chemical_reaction/metalgen_imprint + name = "metalgen imprint" + id = /datum/reagent/metalgen + required_reagents = list(/datum/reagent/metalgen = 1, /datum/reagent/liquid_dark_matter = 1) + results = list(/datum/reagent/metalgen = 1) + +/datum/chemical_reaction/holywater + name = "Holy Water" + id = /datum/reagent/water/holywater + results = list(/datum/reagent/water/holywater = 1) + required_reagents = list(/datum/reagent/water/hollowwater = 1) + required_catalysts = list(/datum/reagent/water/holywater = 1) + +/datum/chemical_reaction/metalgen_imprint/on_reaction(datum/reagents/holder, created_volume) + var/datum/reagent/metalgen/MM = holder.get_reagent(/datum/reagent/metalgen) + for(var/datum/reagent/R in holder.reagent_list) + if(R.material && R.volume >= 40) + MM.data["material"] = R.material + holder.remove_reagent(R.type, 40) + +/datum/chemical_reaction/gravitum + name = "gravitum" + id = /datum/reagent/gravitum + required_reagents = list(/datum/reagent/wittel = 1, /datum/reagent/sorium = 10) + results = list(/datum/reagent/gravitum = 10) /datum/chemical_reaction/sterilizine name = "Sterilizine" @@ -684,10 +715,10 @@ required_reagents = list(/datum/reagent/toxin/mindbreaker = 1, /datum/reagent/medicine/synaptizine = 1, /datum/reagent/water = 1) /datum/chemical_reaction/cat - name = "felined mutation toxic" + name = "felinid mutation toxic" id = /datum/reagent/mutationtoxin/felinid results = list(/datum/reagent/mutationtoxin/felinid = 1) - required_reagents = list(/datum/reagent/toxin/mindbreaker = 1, /datum/reagent/ammonia = 1, /datum/reagent/water = 1, /datum/reagent/drug/aphrodisiac = 10, /datum/reagent/mutationtoxin = 1) // Maybe aphro+ if it becomes a shitty meme + required_reagents = list(/datum/reagent/toxin/mindbreaker = 1, /datum/reagent/ammonia = 1, /datum/reagent/water = 1, /datum/reagent/pax/catnip = 1, /datum/reagent/mutationtoxin = 1) required_temp = 450 /datum/chemical_reaction/moff @@ -711,7 +742,7 @@ /datum/chemical_reaction/slime_extractification/on_reaction(datum/reagents/holder, created_volume) var/location = get_turf(holder.my_atom) new /obj/item/slime_extract/grey(location) - + // Liquid Carpets /datum/chemical_reaction/carpet @@ -837,4 +868,4 @@ /datum/chemical_reaction/cellulose_carbonization results = list(/datum/reagent/carbon = 1) required_reagents = list(/datum/reagent/cellulose = 1) - required_temp = 512 \ No newline at end of file + required_temp = 512 diff --git a/code/modules/reagents/reagent_containers/bottle.dm b/code/modules/reagents/reagent_containers/bottle.dm index ad8d722b61..20abcf847f 100644 --- a/code/modules/reagents/reagent_containers/bottle.dm +++ b/code/modules/reagents/reagent_containers/bottle.dm @@ -416,25 +416,3 @@ /obj/item/reagent_containers/glass/bottle/bromine name = "bromine bottle" list_reagents = list(/datum/reagent/bromine = 30) - -//Lewd Stuff - -/obj/item/reagent_containers/glass/bottle/crocin - name = "Crocin bottle" - desc = "A bottle of mild aphrodisiac. Increases libido." - list_reagents = list(/datum/reagent/drug/aphrodisiac = 30) - -/obj/item/reagent_containers/glass/bottle/hexacrocin - name = "Hexacrocin bottle" - desc = "A bottle of strong aphrodisiac. Increases libido." - list_reagents = list(/datum/reagent/drug/aphrodisiacplus = 30) - -/obj/item/reagent_containers/glass/bottle/camphor - name = "Camphor bottle" - desc = "A bottle of mild anaphrodisiac. Reduces libido." - list_reagents = list(/datum/reagent/drug/anaphrodisiac = 30) - -/obj/item/reagent_containers/glass/bottle/hexacamphor - name = "Hexacamphor bottle" - desc = "A bottle of strong anaphrodisiac. Reduces libido." - list_reagents = list(/datum/reagent/drug/anaphrodisiacplus = 30) diff --git a/code/modules/reagents/reagent_dispenser.dm b/code/modules/reagents/reagent_dispenser.dm index 819012a61a..6541deda1c 100644 --- a/code/modules/reagents/reagent_dispenser.dm +++ b/code/modules/reagents/reagent_dispenser.dm @@ -24,7 +24,8 @@ /obj/structure/reagent_dispensers/Initialize() create_reagents(tank_volume, DRAINABLE | AMOUNT_VISIBLE) - reagents.add_reagent(reagent_id, tank_volume) + if(reagent_id) + reagents.add_reagent(reagent_id, tank_volume) . = ..() /obj/structure/reagent_dispensers/proc/boom() @@ -91,6 +92,38 @@ user.put_in_hands(S) paper_cups-- +/obj/structure/reagent_dispensers/plumbed + name = "stationairy water tank" + anchored = TRUE + icon_state = "water_stationairy" + desc = "A stationairy, plumbed, water tank." + +/obj/structure/reagent_dispensers/plumbed/wrench_act(mob/living/user, obj/item/I) + default_unfasten_wrench(user, I) + return TRUE + +/obj/structure/reagent_dispensers/plumbed/default_unfasten_wrench(mob/user, obj/item/I, time = 20) + . = ..() + if(. == SUCCESSFUL_UNFASTEN) + user.visible_message("[user.name] [anchored ? "fasten" : "unfasten"] [src]", \ + "You [anchored ? "fasten" : "unfasten"] [src]") + var/datum/component/plumbing/CP = GetComponent(/datum/component/plumbing) + if(anchored) + CP.enable() + else + CP.disable() + +/obj/structure/reagent_dispensers/plumbed/ComponentInitialize() + AddComponent(/datum/component/plumbing/simple_supply) + +/obj/structure/reagent_dispensers/plumbed/storage + name = "stationairy storage tank" + icon_state = "tank_stationairy" + reagent_id = null //start empty + +/obj/structure/reagent_dispensers/plumbed/storage/ComponentInitialize() + AddComponent(/datum/component/plumbing/tank) + ////////////// //Fuel Tanks// ////////////// @@ -222,19 +255,6 @@ icon_state = "orangekeg" reagent_id = /datum/reagent/consumable/ethanol/mead -/obj/structure/reagent_dispensers/keg/aphro - name = "keg of aphrodisiac" - desc = "A keg of aphrodisiac." - icon_state = "pinkkeg" - reagent_id = /datum/reagent/drug/aphrodisiac - tank_volume = 150 - -/obj/structure/reagent_dispensers/keg/aphro/strong - name = "keg of strong aphrodisiac" - desc = "A keg of strong and addictive aphrodisiac." - reagent_id = /datum/reagent/drug/aphrodisiacplus - tank_volume = 120 - /obj/structure/reagent_dispensers/keg/milk name = "keg of milk" desc = "A keg of pasteurised, homogenised, filtered and semi-skimmed space milk." @@ -284,5 +304,3 @@ icon_state = "bluekeg" reagent_id = /datum/reagent/consumable/ethanol/neurotoxin tank_volume = 100 //2.5x less than the other kegs because it's harder to get - - diff --git a/code/modules/recycling/disposal/bin.dm b/code/modules/recycling/disposal/bin.dm index ba4870903e..c8da9ab5e3 100644 --- a/code/modules/recycling/disposal/bin.dm +++ b/code/modules/recycling/disposal/bin.dm @@ -299,13 +299,15 @@ // handle machine interaction -/obj/machinery/disposal/bin/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ - datum/tgui/master_ui = null, datum/ui_state/state = GLOB.notcontained_state) +/obj/machinery/disposal/bin/ui_state(mob/user) + return GLOB.notcontained_state + +/obj/machinery/disposal/bin/ui_interact(mob/user, datum/tgui/ui) if(stat & BROKEN) return - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) + ui = SStgui.try_update_ui(user, src, ui) if(!ui) - ui = new(user, src, ui_key, "DisposalUnit", name, ui_x, ui_y, master_ui, state) + ui = new(user, src, "DisposalUnit", name) ui.open() /obj/machinery/disposal/bin/ui_data(mob/user) diff --git a/code/modules/research/anomaly/anomaly_core.dm b/code/modules/research/anomaly/anomaly_core.dm new file mode 100644 index 0000000000..7aeb7b3a9b --- /dev/null +++ b/code/modules/research/anomaly/anomaly_core.dm @@ -0,0 +1,63 @@ +// Embedded signaller used in anomalies. +/obj/item/assembly/signaler/anomaly + name = "anomaly core" + desc = "The neutralized core of an anomaly. It'd probably be valuable for research." + icon_state = "anomaly_core" + //inhand_icon_state = "electronic" + lefthand_file = 'icons/mob/inhands/misc/devices_lefthand.dmi' + righthand_file = 'icons/mob/inhands/misc/devices_righthand.dmi' + resistance_flags = FIRE_PROOF + var/anomaly_type = /obj/effect/anomaly + +/obj/item/assembly/signaler/anomaly/receive_signal(datum/signal/signal) + if(!signal) + return FALSE + if(signal.data["code"] != code) + return FALSE + if(suicider) + manual_suicide(suicider) + for(var/obj/effect/anomaly/A in get_turf(src)) + A.anomalyNeutralize() + return TRUE + +/obj/item/assembly/signaler/anomaly/manual_suicide(mob/living/carbon/user) + user.visible_message("[user]'s [src] is reacting to the radio signal, warping [user.p_their()] body!") + //user.set_suicide(TRUE) + user.suicide_log() + user.gib() + +/obj/item/assembly/signaler/anomaly/attackby(obj/item/I, mob/user, params) + if(I.tool_behaviour == TOOL_ANALYZER) + to_chat(user, "Analyzing... [src]'s stabilized field is fluctuating along frequency [format_frequency(frequency)], code [code].") + return ..() + +//Anomaly cores +/obj/item/assembly/signaler/anomaly/pyro + name = "\improper pyroclastic anomaly core" + desc = "The neutralized core of a pyroclastic anomaly. It feels warm to the touch. It'd probably be valuable for research." + icon_state = "pyro_core" + anomaly_type = /obj/effect/anomaly/pyro + +/obj/item/assembly/signaler/anomaly/grav + name = "\improper gravitational anomaly core" + desc = "The neutralized core of a gravitational anomaly. It feels much heavier than it looks. It'd probably be valuable for research." + icon_state = "grav_core" + anomaly_type = /obj/effect/anomaly/grav + +/obj/item/assembly/signaler/anomaly/flux + name = "\improper flux anomaly core" + desc = "The neutralized core of a flux anomaly. Touching it makes your skin tingle. It'd probably be valuable for research." + icon_state = "flux_core" + anomaly_type = /obj/effect/anomaly/flux + +/obj/item/assembly/signaler/anomaly/bluespace + name = "\improper bluespace anomaly core" + desc = "The neutralized core of a bluespace anomaly. It keeps phasing in and out of view. It'd probably be valuable for research." + icon_state = "anomaly_core" + anomaly_type = /obj/effect/anomaly/bluespace + +/obj/item/assembly/signaler/anomaly/vortex + name = "\improper vortex anomaly core" + desc = "The neutralized core of a vortex anomaly. It won't sit still, as if some invisible force is acting on it. It'd probably be valuable for research." + icon_state = "vortex_core" + anomaly_type = /obj/effect/anomaly/bhole diff --git a/code/modules/research/bepis.dm b/code/modules/research/bepis.dm index 87aec72646..7b36a614a7 100644 --- a/code/modules/research/bepis.dm +++ b/code/modules/research/bepis.dm @@ -33,11 +33,13 @@ var/inaccuracy_percentage = 1.5 var/positive_cash_offset = 0 var/negative_cash_offset = 0 - var/minor_rewards = list(/obj/item/stack/circuit_stack/full, //To add a new minor reward, add it here. - /obj/item/flashlight/flashdark, - /obj/item/pen/survival, - /obj/item/circuitboard/machine/sleeper/party, - /obj/item/toy/sprayoncan) + var/list/minor_rewards = list( + //To add a new minor reward, add it here. + /obj/item/stack/circuit_stack/full, + /obj/item/pen/survival, + /obj/item/circuitboard/machine/sleeper/party, + /obj/item/toy/sprayoncan, + ) var/static/list/item_list = list() /obj/machinery/rnd/bepis/attackby(obj/item/O, mob/user, params) @@ -101,6 +103,7 @@ return account.adjust_money(-deposit_value) //The money vanishes, not paid to any accounts. SSblackbox.record_feedback("amount", "BEPIS_credits_spent", deposit_value) + //log_econ("[deposit_value] credits were inserted into [src] by [account.account_holder]") banked_cash += deposit_value use_power(1000 * power_saver) say("Cash deposit successful. There is [banked_cash] in the chamber.") @@ -179,10 +182,10 @@ icon_state = "chamber" return -/obj/machinery/rnd/bepis/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = 0, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) +/obj/machinery/rnd/bepis/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) if(!ui) - ui = new(user, src, ui_key, "Bepis", name, 500, 480, master_ui, state) + ui = new(user, src, "Bepis", name) ui.open() RefreshParts() diff --git a/code/modules/research/designs/machine_desings/machine_designs_medical.dm b/code/modules/research/designs/machine_desings/machine_designs_medical.dm index 329fb7bf6e..84a3ed10d5 100644 --- a/code/modules/research/designs/machine_desings/machine_designs_medical.dm +++ b/code/modules/research/designs/machine_desings/machine_designs_medical.dm @@ -105,3 +105,11 @@ build_path = /obj/item/circuitboard/machine/bloodbankgen departmental_flags = DEPARTMENTAL_FLAG_MEDICAL category = list ("Medical Machinery") + +/datum/design/board/medipen_refiller + name = "Machine Design (Medipen Refiller)" + desc = "The circuit board for a Medipen Refiller." + id = "medipen_refiller" + build_path = /obj/item/circuitboard/machine/medipen_refiller + category = list ("Medical Machinery") + departmental_flags = DEPARTMENTAL_FLAG_MEDICAL diff --git a/code/modules/research/designs/machine_desings/machine_designs_service.dm b/code/modules/research/designs/machine_desings/machine_designs_service.dm index 5cbff1c66a..af4f650793 100644 --- a/code/modules/research/designs/machine_desings/machine_designs_service.dm +++ b/code/modules/research/designs/machine_desings/machine_designs_service.dm @@ -81,6 +81,14 @@ category = list ("Hydroponics Machinery") departmental_flags = DEPARTMENTAL_FLAG_SERVICE +/datum/design/board/hydroponics/auto + name = "Machine Design (Automatic Hydroponics Tray Board)" + desc = "The circuit board for an automatic hydroponics tray. GIVE ME THE PLANT, CAPTAIN." + id = "autohydrotray" + build_path = /obj/machinery/hydroponics/constructable/automagic + category = list ("Hydroponics Machinery") + departmental_flags = DEPARTMENTAL_FLAG_SERVICE | DEPARTMENTAL_FLAG_MEDICAL + /datum/design/board/monkey_recycler name = "Machine Design (Monkey Recycler Board)" desc = "The circuit board for a monkey recycler." diff --git a/code/modules/research/designs/medical_designs.dm b/code/modules/research/designs/medical_designs.dm index e1e55f3476..0a9fce2e67 100644 --- a/code/modules/research/designs/medical_designs.dm +++ b/code/modules/research/designs/medical_designs.dm @@ -961,3 +961,158 @@ build_path = /obj/item/bodypart/r_arm/robot/surplus_upgraded category = list("Medical Designs") departmental_flags = DEPARTMENTAL_FLAG_MEDICAL + + +/datum/design/acclimator + name = "Plumbing Acclimator" + desc = "A heating and cooling device for pipes!" + id = "acclimator" + build_type = PROTOLATHE + materials = list(/datum/material/iron = 1000, /datum/material/glass = 500) + construction_time = 15 + build_path = /obj/machinery/plumbing/acclimator + category = list("Misc","Medical Designs") + departmental_flags = DEPARTMENTAL_FLAG_MEDICAL | DEPARTMENTAL_FLAG_SCIENCE + +/datum/design/disposer + name = "Plumbing Disposer" + desc = "Using the power of Science, dissolves reagents into nothing (almost)." + id = "disposer" + build_type = PROTOLATHE + materials = list(/datum/material/iron = 500, /datum/material/glass = 100) + construction_time = 15 + build_path = /obj/machinery/plumbing/disposer + category = list("Misc","Medical Designs") + departmental_flags = DEPARTMENTAL_FLAG_MEDICAL | DEPARTMENTAL_FLAG_SCIENCE + +/datum/design/plumb_filter + name = "Plumbing Filter" + desc = "Filters out chemicals by their NTDB ID." + id = "plumb_filter" + build_type = PROTOLATHE + materials = list(/datum/material/iron = 1000, /datum/material/glass = 500) + construction_time = 15 + build_path = /obj/machinery/plumbing/filter + category = list("Misc","Medical Designs") + departmental_flags = DEPARTMENTAL_FLAG_MEDICAL | DEPARTMENTAL_FLAG_SCIENCE + +/datum/design/plumb_synth + name = "Plumbing Synthesizer" + desc = "Using standard mass-energy dynamic autoconverters, generates reagents from power and puts them in a pipe." + id = "plumb_synth" + build_type = PROTOLATHE + materials = list(/datum/material/iron = 5000, /datum/material/glass = 1000, /datum/material/plastic = 1000) + construction_time = 15 + build_path = /obj/machinery/plumbing/synthesizer + category = list("Misc","Medical Designs") + departmental_flags = DEPARTMENTAL_FLAG_MEDICAL | DEPARTMENTAL_FLAG_SCIENCE + +/datum/design/plumb_grinder + name = "Plumbing-Linked Autogrinder" + desc = "Automatically extracts reagents from an item by grinding it. Think of the possibilities! Note: does not grind people." + id = "plumb_grinder" + build_type = PROTOLATHE + materials = list(/datum/material/iron = 2000, /datum/material/glass = 1500) + construction_time = 15 + build_path = /obj/machinery/plumbing/grinder_chemical + category = list("Misc","Medical Designs") + departmental_flags = DEPARTMENTAL_FLAG_MEDICAL | DEPARTMENTAL_FLAG_SCIENCE + +/datum/design/reaction_chamber + name = "Plumbing Reaction Chamber" + desc = "You can set a list of allowed reagents and amounts. Once the chamber has these reagents, will let the products through." + id = "reaction_chamber" + build_type = PROTOLATHE + materials = list(/datum/material/iron = 1000, /datum/material/glass = 500) + construction_time = 15 + build_path = /obj/machinery/plumbing/reaction_chamber + category = list("Misc","Medical Designs") + departmental_flags = DEPARTMENTAL_FLAG_MEDICAL | DEPARTMENTAL_FLAG_SCIENCE + +/datum/design/duct_print + name = "Plumbing Ducts" + desc = "Ducts for plumbing! Now lathed for efficiency." + id = "duct_print" + build_type = PROTOLATHE + materials = list(/datum/material/plastic = 400) + construction_time = 1 + build_path = /obj/item/stack/ducts + category = list("Misc","Medical Designs") + departmental_flags = DEPARTMENTAL_FLAG_MEDICAL | DEPARTMENTAL_FLAG_SCIENCE + +/datum/design/plumb_splitter + name = "Plumbing Chemical Splitter" + desc = "A splitter. Has 2 outputs. Can be configured to allow a certain amount through each side." + id = "plumb_splitter" + build_type = PROTOLATHE + materials = list(/datum/material/iron = 750, /datum/material/glass = 250) + construction_time = 15 + build_path = /obj/machinery/plumbing/splitter + category = list("Misc","Medical Designs") + departmental_flags = DEPARTMENTAL_FLAG_MEDICAL | DEPARTMENTAL_FLAG_SCIENCE + +/datum/design/pill_press + name = "Plumbing Automatic Pill Former" + desc = "Automatically forms pills to the required parameters with piped reagents! A good replacement for those lazy, useless chemists." + id = "pill_press" + build_type = PROTOLATHE + materials = list(/datum/material/iron = 1000, /datum/material/glass = 500) + construction_time = 15 + build_path = /obj/machinery/plumbing/pill_press + category = list("Misc","Medical Designs") + departmental_flags = DEPARTMENTAL_FLAG_MEDICAL | DEPARTMENTAL_FLAG_SCIENCE + +/datum/design/plumb_pump + name = "Liquid Extraction Pump" + desc = "Use it for extracting liquids from lavaland's geysers!" + id = "plumb_pump" + build_type = PROTOLATHE + materials = list(/datum/material/iron = 1000, /datum/material/glass = 500) + construction_time = 15 + build_path = /obj/machinery/plumbing/liquid_pump + category = list("Misc","Medical Designs") + departmental_flags = DEPARTMENTAL_FLAG_MEDICAL | DEPARTMENTAL_FLAG_SCIENCE + +/datum/design/plumb_in + name = "Plumbing Input Device" + desc = "A big piped funnel for putting stuff in the pipe network." + id = "plumb_in" + build_type = PROTOLATHE + materials = list(/datum/material/iron = 400, /datum/material/glass = 400) + construction_time = 15 + build_path = /obj/machinery/plumbing/input + category = list("Misc","Medical Designs") + departmental_flags = DEPARTMENTAL_FLAG_MEDICAL | DEPARTMENTAL_FLAG_SCIENCE + +/datum/design/plumb_out + name = "Plumbing Output Device" + desc = "A big piped funnel for taking stuff out of the pipe network." + id = "plumb_out" + build_type = PROTOLATHE + materials = list(/datum/material/iron = 400, /datum/material/glass = 400) + construction_time = 15 + build_path = /obj/machinery/plumbing/output + category = list("Misc","Medical Designs") + departmental_flags = DEPARTMENTAL_FLAG_MEDICAL | DEPARTMENTAL_FLAG_SCIENCE + +/datum/design/plumb_tank + name = "Plumbed Storage Tank" + desc = "A tank for storing plumbed reagents." + id = "plumb_tank" + build_type = PROTOLATHE + materials = list(/datum/material/iron = 10000, /datum/material/glass = 10000, /datum/material/plastic = 4000) + construction_time = 15 + build_path = /obj/machinery/plumbing/tank + category = list("Misc","Medical Designs") + departmental_flags = DEPARTMENTAL_FLAG_MEDICAL | DEPARTMENTAL_FLAG_SCIENCE + +/datum/design/plumb_rcd + name = "Plumbed Autoconstruction Device" + desc = "A RCD for plumbing machines! Cannot make ducts." + id = "plumb_rcd" + build_type = PROTOLATHE + materials = list(/datum/material/iron = 20000, /datum/material/glass = 10000, /datum/material/plastic = 20000, /datum/material/titanium = 2000, /datum/material/diamond = 800, /datum/material/gold = 2000, /datum/material/silver = 2000) + construction_time = 150 + build_path = /obj/item/construction/plumbing + category = list("Misc","Medical Designs") + departmental_flags = DEPARTMENTAL_FLAG_MEDICAL | DEPARTMENTAL_FLAG_SCIENCE diff --git a/code/modules/research/nanites/extra_settings/text.dm b/code/modules/research/nanites/extra_settings/text.dm index 56aa3dd07f..d3cad27bcf 100644 --- a/code/modules/research/nanites/extra_settings/text.dm +++ b/code/modules/research/nanites/extra_settings/text.dm @@ -10,6 +10,9 @@ /datum/nanite_extra_setting/text/get_copy() return new /datum/nanite_extra_setting/text(value) +/datum/nanite_extra_setting/text/get_value() + return html_encode(value) + /datum/nanite_extra_setting/text/get_frontend_list(name) return list(list( "name" = name, diff --git a/code/modules/research/nanites/nanite_chamber_computer.dm b/code/modules/research/nanites/nanite_chamber_computer.dm index b9623b751d..70e4d05590 100644 --- a/code/modules/research/nanites/nanite_chamber_computer.dm +++ b/code/modules/research/nanites/nanite_chamber_computer.dm @@ -5,8 +5,6 @@ var/obj/item/disk/nanite_program/disk icon_screen = "nanite_chamber_control" circuit = /obj/item/circuitboard/computer/nanite_chamber_control - ui_x = 380 - ui_y = 570 /obj/machinery/computer/nanite_chamber_control/Initialize() . = ..() @@ -25,10 +23,10 @@ find_chamber() ..() -/obj/machinery/computer/nanite_chamber_control/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) +/obj/machinery/computer/nanite_chamber_control/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) if(!ui) - ui = new(user, src, ui_key, "NaniteChamberControl", name, ui_x, ui_y, master_ui, state) + ui = new(user, src, "NaniteChamberControl", name) ui.open() /obj/machinery/computer/nanite_chamber_control/ui_data() diff --git a/code/modules/research/nanites/nanite_cloud_controller.dm b/code/modules/research/nanites/nanite_cloud_controller.dm index ef0fc33bd7..44ebe11c29 100644 --- a/code/modules/research/nanites/nanite_cloud_controller.dm +++ b/code/modules/research/nanites/nanite_cloud_controller.dm @@ -1,11 +1,9 @@ /obj/machinery/computer/nanite_cloud_controller name = "nanite cloud controller" desc = "Stores and controls nanite cloud backups." - circuit = /obj/item/circuitboard/computer/nanite_cloud_controller icon = 'icons/obj/machines/research.dmi' icon_state = "nanite_cloud_controller" - ui_x = 375 - ui_y = 700 + circuit = /obj/item/circuitboard/computer/nanite_cloud_controller var/obj/item/disk/nanite_program/disk var/list/datum/nanite_cloud_backup/cloud_backups = list() @@ -20,20 +18,27 @@ /obj/machinery/computer/nanite_cloud_controller/attackby(obj/item/I, mob/user) if(istype(I, /obj/item/disk/nanite_program)) var/obj/item/disk/nanite_program/N = I - if(disk) - eject(user) - if(user.transferItemToLoc(N, src)) + if (user.transferItemToLoc(N, src)) to_chat(user, "You insert [N] into [src].") playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, FALSE) + if(disk) + eject(user) disk = N else ..() +/obj/machinery/computer/nanite_cloud_controller/AltClick(mob/user) + if(disk && user.canUseTopic(src, !issilicon(user))) + to_chat(user, "You take out [disk] from [src].") + eject(user) + return + /obj/machinery/computer/nanite_cloud_controller/proc/eject(mob/living/user) if(!disk) return - if(!istype(user) || !Adjacent(user) ||!user.put_in_active_hand(disk)) - disk.forceMove(drop_location()) + disk.forceMove(drop_location()) + if(istype(user) && user.Adjacent(src)) + user.put_in_active_hand(disk) disk = null /obj/machinery/computer/nanite_cloud_controller/proc/get_backup(cloud_id) @@ -53,10 +58,10 @@ backup.nanites = cloud_copy investigate_log("[key_name(user)] created a new nanite cloud backup with id #[cloud_id]", INVESTIGATE_NANITES) -/obj/machinery/computer/nanite_cloud_controller/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) +/obj/machinery/computer/nanite_cloud_controller/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) if(!ui) - ui = new(user, src, ui_key, "NaniteCloudControl", name, ui_x, ui_y, master_ui, state) + ui = new(user, src, "NaniteCloudControl", name) ui.open() /obj/machinery/computer/nanite_cloud_controller/ui_data() diff --git a/code/modules/research/nanites/nanite_program_hub.dm b/code/modules/research/nanites/nanite_program_hub.dm index 3f62a11f89..495c788845 100644 --- a/code/modules/research/nanites/nanite_program_hub.dm +++ b/code/modules/research/nanites/nanite_program_hub.dm @@ -3,26 +3,24 @@ desc = "Compiles nanite programs from the techweb servers and downloads them into disks." icon = 'icons/obj/machines/research.dmi' icon_state = "nanite_program_hub" - circuit = /obj/item/circuitboard/machine/nanite_program_hub use_power = IDLE_POWER_USE anchored = TRUE density = TRUE - ui_x = 500 - ui_y = 700 + circuit = /obj/item/circuitboard/machine/nanite_program_hub var/obj/item/disk/nanite_program/disk var/datum/techweb/linked_techweb var/current_category = "Main" var/detail_view = TRUE var/categories = list( - list(name = "Utility Nanites"), - list(name = "Medical Nanites"), - list(name = "Sensor Nanites"), - list(name = "Augmentation Nanites"), - list(name = "Suppression Nanites"), - list(name = "Weaponized Nanites"), - list(name = "Protocols") //Moved to default techweb from B.E.P.I.S. research, for now - ) + list(name = "Utility Nanites"), + list(name = "Medical Nanites"), + list(name = "Sensor Nanites"), + list(name = "Augmentation Nanites"), + list(name = "Suppression Nanites"), + list(name = "Weaponized Nanites"), + list(name = "Protocols"), + ) /obj/machinery/nanite_program_hub/Initialize() . = ..() @@ -31,26 +29,45 @@ /obj/machinery/nanite_program_hub/attackby(obj/item/I, mob/user) if(istype(I, /obj/item/disk/nanite_program)) var/obj/item/disk/nanite_program/N = I - if(disk) - eject(user) if(user.transferItemToLoc(N, src)) to_chat(user, "You insert [N] into [src].") playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, FALSE) + if(disk) + eject(user) disk = N else ..() +/obj/machinery/nanite_program_hub/screwdriver_act(mob/living/user, obj/item/I) //remove when runtimed + if(..()) + return TRUE + + return default_deconstruction_screwdriver(user, "nanite_program_hub_t", "nanite_program_hub", I) + +/obj/machinery/nanite_program_hub/crowbar_act(mob/living/user, obj/item/I) + if(..()) + return TRUE + + return default_deconstruction_crowbar(I) + /obj/machinery/nanite_program_hub/proc/eject(mob/living/user) if(!disk) return - if(!istype(user) || !Adjacent(user) || !user.put_in_active_hand(disk)) - disk.forceMove(drop_location()) + disk.forceMove(drop_location()) + if(istype(user) && Adjacent(user)) + user.put_in_active_hand(disk) disk = null -/obj/machinery/nanite_program_hub/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) +/obj/machinery/nanite_program_hub/AltClick(mob/user) + if(disk && user.canUseTopic(src, !issilicon(user))) + to_chat(user, "You take out [disk] from [src].") + eject(user) + return + +/obj/machinery/nanite_program_hub/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) if(!ui) - ui = new(user, src, ui_key, "NaniteProgramHub", name, ui_x, ui_y, master_ui, state) + ui = new(user, src, "NaniteProgramHub", name) ui.open() /obj/machinery/nanite_program_hub/ui_data() @@ -123,9 +140,3 @@ disk.program = null disk.name = initial(disk.name) . = TRUE - - -/obj/machinery/nanite_program_hub/admin/Initialize() - . = ..() - linked_techweb = SSresearch.admin_tech - diff --git a/code/modules/research/nanites/nanite_programmer.dm b/code/modules/research/nanites/nanite_programmer.dm index 3de2a974e2..b6a2c8b28b 100644 --- a/code/modules/research/nanites/nanite_programmer.dm +++ b/code/modules/research/nanites/nanite_programmer.dm @@ -3,41 +3,58 @@ desc = "A device that can edit nanite program disks to adjust their functionality." var/obj/item/disk/nanite_program/disk var/datum/nanite_program/program - circuit = /obj/item/circuitboard/machine/nanite_programmer icon = 'icons/obj/machines/research.dmi' icon_state = "nanite_programmer" use_power = IDLE_POWER_USE anchored = TRUE density = TRUE flags_1 = HEAR_1 - ui_x = 420 - ui_y = 550 + circuit = /obj/item/circuitboard/machine/nanite_programmer /obj/machinery/nanite_programmer/attackby(obj/item/I, mob/user) if(istype(I, /obj/item/disk/nanite_program)) var/obj/item/disk/nanite_program/N = I - if(disk) - eject(user) if(user.transferItemToLoc(N, src)) to_chat(user, "You insert [N] into [src]") playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, FALSE) + if(disk) + eject(user) disk = N program = N.program else ..() +/obj/machinery/nanite_programmer/screwdriver_act(mob/living/user, obj/item/I) + if(..()) + return TRUE + + return default_deconstruction_screwdriver(user, "nanite_programmer_t", "nanite_programmer", I) + +/obj/machinery/nanite_programmer/crowbar_act(mob/living/user, obj/item/I) + if(..()) + return TRUE + + return default_deconstruction_crowbar(I) + /obj/machinery/nanite_programmer/proc/eject(mob/living/user) if(!disk) return - if(!istype(user) || !Adjacent(user) || !user.put_in_active_hand(disk)) - disk.forceMove(drop_location()) + disk.forceMove(drop_location()) + if(istype(user) && user.Adjacent(src)) + user.put_in_active_hand(disk) disk = null program = null -/obj/machinery/nanite_programmer/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) +/obj/machinery/nanite_programmer/AltClick(mob/user) + if(disk && user.canUseTopic(src, !issilicon(user))) + to_chat(user, "You take out [disk] from [src].") + eject(user) + return + +/obj/machinery/nanite_programmer/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) if(!ui) - ui = new(user, src, ui_key, "NaniteProgrammer", name, ui_x, ui_y, master_ui, state) + ui = new(user, src, "NaniteProgrammer", name) ui.open() /obj/machinery/nanite_programmer/ui_data() @@ -131,7 +148,7 @@ program.timer_trigger_delay = timer . = TRUE -/obj/machinery/nanite_programmer/Hear(message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, message_mode, atom/movable/source) +/obj/machinery/nanite_programmer/Hear(message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, list/message_mods = list()) . = ..() var/static/regex/when = regex("(?:^\\W*when|when\\W*$)", "i") //starts or ends with when if(findtext(raw_message, when) && !istype(speaker, /obj/machinery/nanite_programmer)) diff --git a/code/modules/research/nanites/nanite_programs/suppression.dm b/code/modules/research/nanites/nanite_programs/suppression.dm index 3b0d6d0d06..d2aa243fee 100644 --- a/code/modules/research/nanites/nanite_programs/suppression.dm +++ b/code/modules/research/nanites/nanite_programs/suppression.dm @@ -176,7 +176,7 @@ sent_message = message_setting.get_value() if(host_mob.stat == DEAD) return - to_chat(host_mob, "You hear a strange, robotic voice in your head... \"[sent_message]\"") + to_chat(host_mob, "You hear a strange, robotic voice in your head... \"[html_encode(sent_message)]\"") /datum/nanite_program/comm/hallucination name = "Hallucination" diff --git a/code/modules/research/nanites/nanite_remote.dm b/code/modules/research/nanites/nanite_remote.dm index b222b2ad35..e3f5a0f286 100644 --- a/code/modules/research/nanites/nanite_remote.dm +++ b/code/modules/research/nanites/nanite_remote.dm @@ -80,10 +80,13 @@ var/datum/nanite_program/relay/N = X N.relay_signal(code, relay_code, source) -/obj/item/nanite_remote/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.hands_state) - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) +/obj/item/nanite_remote/ui_state(mob/user) + return GLOB.hands_state + +/obj/item/nanite_remote/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) if(!ui) - ui = new(user, src, ui_key, "NaniteRemote", name, 420, 500, master_ui, state) + ui = new(user, src, "NaniteRemote", name) ui.open() /obj/item/nanite_remote/ui_data() @@ -94,7 +97,6 @@ data["locked"] = locked data["saved_settings"] = saved_settings data["program_name"] = current_program_name - return data /obj/item/nanite_remote/ui_act(action, params) diff --git a/code/modules/research/techweb/nodes/medical_nodes.dm b/code/modules/research/techweb/nodes/medical_nodes.dm index 3a9e654b81..150e420c09 100644 --- a/code/modules/research/techweb/nodes/medical_nodes.dm +++ b/code/modules/research/techweb/nodes/medical_nodes.dm @@ -24,6 +24,23 @@ design_ids = list("defib_decay", "defib_shock", "defib_heal", "defib_speed") research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500) +/datum/techweb_node/plumbing + id = "plumbing" + display_name = "Reagent Plumbing Technology" + description = "Plastic tubes, and machinery used for manipulating things in them." + prereq_ids = list("base") + design_ids = list("acclimator", "disposer", "plumb_filter", "plumb_synth", "plumb_grinder", "reaction_chamber", "duct_print", "plumb_splitter", "pill_press", "plumb_pump", "plumb_in", "plumb_out", "plumb_tank", "medipen_refiller") + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 1000) + + +/datum/techweb_node/advplumbing + id = "advplumbing" + display_name = "Advanced Plumbing Technology" + description = "Plumbing RCD." + prereq_ids = list("plumbing", "adv_engi") + design_ids = list("plumb_rcd", "autohydrotray") + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500) + //////////////////////Cybernetics///////////////////// /datum/techweb_node/surplus_limbs diff --git a/code/modules/ruins/lavaland_ruin_code.dm b/code/modules/ruins/lavaland_ruin_code.dm index 45b6939f42..e572f1ee02 100644 --- a/code/modules/ruins/lavaland_ruin_code.dm +++ b/code/modules/ruins/lavaland_ruin_code.dm @@ -93,7 +93,7 @@ /obj/item/stack/sheet/mineral/adamantine = /datum/species/golem/adamantine, /obj/item/stack/sheet/plastic = /datum/species/golem/plastic, /obj/item/stack/tile/brass = /datum/species/golem/clockwork, - /obj/item/stack/tile/bronze = /datum/species/golem/bronze, + /obj/item/stack/sheet/bronze = /datum/species/golem/bronze, /obj/item/stack/sheet/cardboard = /datum/species/golem/cardboard, /obj/item/stack/sheet/leather = /datum/species/golem/leather, /obj/item/stack/sheet/bone = /datum/species/golem/bone, diff --git a/code/modules/ruins/spaceruin_code/TheDerelict.dm b/code/modules/ruins/spaceruin_code/TheDerelict.dm index 513d16a0cb..d26e023df0 100644 --- a/code/modules/ruins/spaceruin_code/TheDerelict.dm +++ b/code/modules/ruins/spaceruin_code/TheDerelict.dm @@ -17,7 +17,6 @@ desc = "Looks like someone started shakily writing a will in space common, but were interrupted by something bloody..." info = "__Objectives #1__: Find out what is hidden in Kosmicheskaya Stantsiya 13s Vault" - /// Vault controller for use on the derelict/KS13. /obj/machinery/computer/vaultcontroller name = "vault controller" @@ -35,15 +34,10 @@ var/siphoned_power = 0 var/siphon_max = 1e7 - ui_x = 300 - ui_y = 120 - - /obj/machinery/computer/monitor/examine(mob/user) . = ..() . += "It appears to be powered via a cable connector." - //Checks for cable connection, charges if possible. /obj/machinery/computer/vaultcontroller/process() if(siphoned_power >= siphon_max) @@ -52,13 +46,11 @@ if(attached_cable) attempt_siphon() - ///Looks for a cable connection beneath the machine. /obj/machinery/computer/vaultcontroller/proc/update_cable() var/turf/T = get_turf(src) attached_cable = locate(/obj/structure/cable) in T - ///Initializes airlock links. /obj/machinery/computer/vaultcontroller/proc/find_airlocks() for(var/obj/machinery/door/airlock/A in GLOB.airlocks) @@ -70,7 +62,6 @@ door2 = A break - ///Tries to charge from powernet excess, no upper limit except max charge. /obj/machinery/computer/vaultcontroller/proc/attempt_siphon() var/surpluspower = clamp(attached_cable.surplus(), 0, (siphon_max - siphoned_power)) @@ -78,7 +69,6 @@ attached_cable.add_load(surpluspower) siphoned_power += surpluspower - ///Handles the doors closing /obj/machinery/computer/vaultcontroller/proc/cycle_close(obj/machinery/door/airlock/A) A.safe = FALSE //Make sure its forced closed, always @@ -86,14 +76,12 @@ A.close() A.bolt() - ///Handles the doors opening /obj/machinery/computer/vaultcontroller/proc/cycle_open(obj/machinery/door/airlock/A) A.unbolt() A.open() A.bolt() - ///Attempts to lock the vault doors /obj/machinery/computer/vaultcontroller/proc/lock_vault() if(door1 && !door1.density) @@ -103,7 +91,6 @@ if(door1.density && door1.locked && door2.density && door2.locked) locked = TRUE - ///Attempts to unlock the vault doors /obj/machinery/computer/vaultcontroller/proc/unlock_vault() if(door1 && door1.density) @@ -113,7 +100,6 @@ if(!door1.density && door1.locked && !door2.density && door2.locked) locked = FALSE - ///Attempts to lock/unlock vault doors, if machine is charged. /obj/machinery/computer/vaultcontroller/proc/activate_lock() if(siphoned_power < siphon_max) @@ -125,15 +111,12 @@ else lock_vault() - -/obj/machinery/computer/vaultcontroller/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ - datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) +/obj/machinery/computer/vaultcontroller/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) if(!ui) - ui = new(user, src, ui_key, "VaultController", name, ui_x, ui_y, master_ui, state) + ui = new(user, src, "VaultController", name) ui.open() - /obj/machinery/computer/vaultcontroller/ui_act(action, params) if(..()) return @@ -141,7 +124,6 @@ if("togglelock") activate_lock() - /obj/machinery/computer/vaultcontroller/ui_data() var/list/data = list() data["stored"] = siphoned_power @@ -149,7 +131,6 @@ data["doorstatus"] = locked return data - ///Airlock that can't be deconstructed, broken or hacked. /obj/machinery/door/airlock/vault/derelict locked = TRUE @@ -158,16 +139,13 @@ resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF id_tag = "derelictvault" - ///Overrides screwdriver attack to prevent all deconstruction and hacking. /obj/machinery/door/airlock/vault/derelict/attackby(obj/item/C, mob/user, params) if(C.tool_behaviour == TOOL_SCREWDRIVER) return ..() - // So drones can teach borgs and AI dronespeak. For best effect, combine with mother drone lawset. - /obj/item/dronespeak_manual name = "dronespeak manual" desc = "The book's cover reads: \"Understanding Dronespeak - An exercise in futility.\"" @@ -181,7 +159,7 @@ to_chat(user, "You start skimming through [src], but you already know dronespeak.") else to_chat(user, "You start skimming through [src], and suddenly the drone chittering makes sense.") - user.grant_language(/datum/language/drone, TRUE, TRUE) + user.grant_language(/datum/language/drone, TRUE, TRUE)//, LANGUAGE_MIND) return if(user.has_language(/datum/language/drone)) @@ -202,7 +180,7 @@ M.visible_message("[user] beats [M] over the head with [src]!", "[user] beats you over the head with [src]!", "You hear smacking.") else M.visible_message("[user] teaches [M] by beating [M.p_them()] over the head with [src]!", "As [user] hits you with [src], chitters resonate in your mind.", "You hear smacking.") - M.grant_language(/datum/language/drone, TRUE, TRUE) + M.grant_language(/datum/language/drone, TRUE, TRUE) //, LANGUAGE_MIND) return /obj/structure/fluff/oldturret diff --git a/code/modules/ruins/spaceruin_code/clericsden.dm b/code/modules/ruins/spaceruin_code/clericsden.dm index 7d1fda6740..3fe4cad794 100644 --- a/code/modules/ruins/spaceruin_code/clericsden.dm +++ b/code/modules/ruins/spaceruin_code/clericsden.dm @@ -21,7 +21,6 @@ desc = "A weaker construct meant to scour ruins for objects of Nar'Sie's affection. Those barbed claws are no joke." icon_state = "proteon" icon_living = "proteon" - threat = 0.4 maxHealth = 35 health = 35 melee_damage_lower = 8 diff --git a/code/modules/security_levels/keycard_authentication.dm b/code/modules/security_levels/keycard_authentication.dm index f6418b9236..7326cad816 100644 --- a/code/modules/security_levels/keycard_authentication.dm +++ b/code/modules/security_levels/keycard_authentication.dm @@ -35,11 +35,13 @@ GLOBAL_DATUM_INIT(keycard_events, /datum/events, new) QDEL_NULL(ev) return ..() -/obj/machinery/keycard_auth/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ - datum/tgui/master_ui = null, datum/ui_state/state = GLOB.physical_state) - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) +/obj/machinery/keycard_auth/ui_state(mob/user) + return GLOB.physical_state + +/obj/machinery/keycard_auth/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) if(!ui) - ui = new(user, src, ui_key, "KeycardAuth", name, ui_x, ui_y, master_ui, state) + ui = new(user, src, "KeycardAuth", name) ui.open() /obj/machinery/keycard_auth/ui_data() diff --git a/code/modules/shuttle/emergency.dm b/code/modules/shuttle/emergency.dm index 637d9ae334..810cadcd2c 100644 --- a/code/modules/shuttle/emergency.dm +++ b/code/modules/shuttle/emergency.dm @@ -45,11 +45,14 @@ say("Please equip your ID card into your ID slot to authenticate.") . = ..() -/obj/machinery/computer/emergency_shuttle/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.human_adjacent_state) +/obj/machinery/computer/emergency_shuttle/ui_state(mob/user) + return GLOB.human_adjacent_state - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) +/obj/machinery/computer/emergency_shuttle/ui_interact(mob/user, datum/tgui/ui) + + ui = SStgui.try_update_ui(user, src, ui) if(!ui) - ui = new(user, src, ui_key, "EmergencyShuttleConsole", name, ui_x, ui_y, master_ui, state) + ui = new(user, src, "EmergencyShuttleConsole", name) ui.open() /obj/machinery/computer/emergency_shuttle/ui_data() @@ -65,8 +68,8 @@ var/job = ID.assignment if(obj_flags & EMAGGED) - name = Gibberish(name, 0) - job = Gibberish(job, 0) + name = Gibberish(name) + job = Gibberish(job) A += list(list("name" = name, "job" = job)) data["authorizations"] = A diff --git a/code/modules/shuttle/shuttle_creation/shuttle_creator.dm b/code/modules/shuttle/shuttle_creation/shuttle_creator.dm index f5a11db60f..b3d99f22ab 100644 --- a/code/modules/shuttle/shuttle_creation/shuttle_creator.dm +++ b/code/modules/shuttle/shuttle_creation/shuttle_creator.dm @@ -43,6 +43,7 @@ GLOBAL_LIST_EMPTY(custom_shuttle_machines) //Machines that require updating (He . = ..() internal_shuttle_creator = new() internal_shuttle_creator.owner_rsd = src + desc += " Attention, the max size of the shuttle is [SHUTTLE_CREATOR_MAX_SIZE]." overlay_holder = new() /obj/item/shuttle_creator/Destroy() @@ -237,13 +238,13 @@ GLOBAL_LIST_EMPTY(custom_shuttle_machines) //Machines that require updating (He port.register() - icon_state = "rsd_used" + icon_state = "rsd_empty" //Clear highlights overlay_holder.clear_highlights() GLOB.custom_shuttle_count ++ - message_admins("[ADMIN_LOOKUPFLW(user)] created a new shuttle with a [src] at [ADMIN_VERBOSEJMP(user)] ([GLOB.custom_shuttle_count] custom shuttles, limit is [CUSTOM_SHUTTLE_LIMIT])") - log_game("[key_name(user)] created a new shuttle with a [src] at [AREACOORD(user)] ([GLOB.custom_shuttle_count] custom shuttles, limit is [CUSTOM_SHUTTLE_LIMIT])") + message_admins("[ADMIN_LOOKUPFLW(user)] created a new shuttle with a [src] at [ADMIN_VERBOSEJMP(user)] ([GLOB.custom_shuttle_count] custom shuttles)") + log_game("[key_name(user)] created a new shuttle with a [src] at [AREACOORD(user)] ([GLOB.custom_shuttle_count] custom shuttles)") return TRUE /obj/item/shuttle_creator/proc/create_shuttle_area(mob/user) @@ -350,7 +351,7 @@ GLOBAL_LIST_EMPTY(custom_shuttle_machines) //Machines that require updating (He loggedOldArea = get_area(get_turf(user)) loggedTurfs |= turfs overlay_holder.highlight_area(turfs) - //TODO READD THIS SHIT: icon_state = "rsd_used" + //TODO READD THIS SHIT: icon_state = "rsd_empty" to_chat(user, "You add the area into the buffer of the [src], you made add more areas or select an airlock to act as a docking port to complete the shuttle.") return turfs diff --git a/code/modules/spells/spell.dm b/code/modules/spells/spell.dm index 57502e2cd5..2272a14612 100644 --- a/code/modules/spells/spell.dm +++ b/code/modules/spells/spell.dm @@ -224,7 +224,15 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell)) //needed for th /obj/effect/proc_holder/spell/proc/choose_targets(mob/user = usr) //depends on subtype - /targeted or /aoe_turf return -/obj/effect/proc_holder/spell/proc/can_target(mob/living/target) +/** + * can_target: Checks if we are allowed to cast the spell on a target. + * + * Arguments: + * * target The atom that is being targeted by the spell. + * * user The mob using the spell. + * * silent If the checks should not give any feedback messages. + */ +/obj/effect/proc_holder/spell/proc/can_target(atom/target, mob/user, silent = FALSE) return TRUE /obj/effect/proc_holder/spell/proc/start_recharge() @@ -296,6 +304,13 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell)) //needed for th /obj/effect/proc_holder/spell/proc/cast(list/targets,mob/user = usr) return +/obj/effect/proc_holder/spell/proc/view_or_range(distance = world.view, center=usr, type="view") + switch(type) + if("view") + . = view(distance,center) + if("range") + . = range(distance,center) + /obj/effect/proc_holder/spell/proc/revert_cast(mob/user = usr) //resets recharge or readds a charge switch(charge_type) if("recharge") @@ -345,7 +360,7 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell)) //needed for th switch(max_targets) if(0) //unlimited for(var/mob/living/target in view_or_range(range, user, selection_type)) - if(!can_target(target)) + if(!can_target(target, user, TRUE)) continue targets += target if(1) //single target can be picked @@ -357,7 +372,7 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell)) //needed for th for(var/mob/living/M in view_or_range(range, user, selection_type)) if(!include_user && user == M) continue - if(!can_target(M)) + if(!can_target(M, user, TRUE)) continue possible_targets += M @@ -365,7 +380,7 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell)) //needed for th //Adds a safety check post-input to make sure those targets are actually in range. var/mob/M if(!random_target) - M = input("Choose the target for the spell.", "Targeting") as null|mob in possible_targets + M = input("Choose the target for the spell.", "Targeting") as null|mob in sortNames(possible_targets) else switch(random_target_priority) if(TARGET_RANDOM) @@ -385,7 +400,7 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell)) //needed for th else var/list/possible_targets = list() for(var/mob/living/target in view_or_range(range, user, selection_type)) - if(!can_target(target)) + if(!can_target(target, user, TRUE)) continue possible_targets += target for(var/i=1,i<=max_targets,i++) @@ -411,7 +426,7 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell)) //needed for th var/list/targets = list() for(var/turf/target in view_or_range(range,user,selection_type)) - if(!can_target(target)) + if(!can_target(target, user, TRUE)) continue if(!(target in view_or_range(inner_radius,user,selection_type))) targets += target diff --git a/code/modules/spells/spell_types/cone_spells.dm b/code/modules/spells/spell_types/cone_spells.dm new file mode 100644 index 0000000000..63bae4b7cf --- /dev/null +++ b/code/modules/spells/spell_types/cone_spells.dm @@ -0,0 +1,117 @@ +/obj/effect/proc_holder/spell/cone + name = "Cone of Nothing" + desc = "Does nothing in a cone! Wow!" + school = "evocation" + charge_max = 100 + clothes_req = FALSE + invocation = "FUKAN NOTHAN" + invocation_type = "shout" + sound = 'sound/magic/forcewall.ogg' + action_icon_state = "shield" + range = -1 + cooldown_min = 0.5 SECONDS + ///This controls how many levels the cone has, increase this value to make a bigger cone. + var/cone_levels = 3 + ///This value determines if the cone penetrates walls. + var/respect_density = FALSE + +/obj/effect/proc_holder/spell/cone/choose_targets(mob/user = usr) + perform(null, user=user) + +///This proc creates a list of turfs that are hit by the cone +/obj/effect/proc_holder/spell/cone/proc/cone_helper(var/turf/starter_turf, var/dir_to_use, var/cone_levels = 3) + var/list/turfs_to_return = list() + var/turf/turf_to_use = starter_turf + var/turf/left_turf + var/turf/right_turf + var/right_dir + var/left_dir + switch(dir_to_use) + if(NORTH) + left_dir = WEST + right_dir = EAST + if(SOUTH) + left_dir = EAST + right_dir = WEST + if(EAST) + left_dir = NORTH + right_dir = SOUTH + if(WEST) + left_dir = SOUTH + right_dir = NORTH + + + for(var/i in 1 to cone_levels) + var/list/level_turfs = list() + turf_to_use = get_step(turf_to_use, dir_to_use) + level_turfs += turf_to_use + if(i != 1) + left_turf = get_step(turf_to_use, left_dir) + level_turfs += left_turf + right_turf = get_step(turf_to_use, right_dir) + level_turfs += right_turf + for(var/left_i in 1 to i -calculate_cone_shape(i)) + if(left_turf.density && respect_density) + break + left_turf = get_step(left_turf, left_dir) + level_turfs += left_turf + for(var/right_i in 1 to i -calculate_cone_shape(i)) + if(right_turf.density && respect_density) + break + right_turf = get_step(right_turf, right_dir) + level_turfs += right_turf + turfs_to_return += list(level_turfs) + if(i == cone_levels) + continue + if(turf_to_use.density && respect_density) + break + return turfs_to_return + +/obj/effect/proc_holder/spell/cone/cast(list/targets,mob/user = usr) + var/list/cone_turfs = cone_helper(get_turf(user), user.dir, cone_levels) + for(var/list/turf_list in cone_turfs) + do_cone_effects(turf_list) + +///This proc does obj, mob and turf cone effects on all targets in a list +/obj/effect/proc_holder/spell/cone/proc/do_cone_effects(list/target_turf_list, level) + for(var/target_turf in target_turf_list) + if(!target_turf) //if turf is no longer there + continue + do_turf_cone_effect(target_turf, level) + if(isopenturf(target_turf)) + var/turf/open/open_turf = target_turf + for(var/movable_content in open_turf) + if(isobj(movable_content)) + do_obj_cone_effect(movable_content, level) + else if(isliving(movable_content)) + do_mob_cone_effect(movable_content, level) + +///This proc deterimines how the spell will affect turfs. +/obj/effect/proc_holder/spell/cone/proc/do_turf_cone_effect(turf/target_turf, level) + return + +///This proc deterimines how the spell will affect objects. +/obj/effect/proc_holder/spell/cone/proc/do_obj_cone_effect(obj/target_obj, level) + return + +///This proc deterimines how the spell will affect mobs. +/obj/effect/proc_holder/spell/cone/proc/do_mob_cone_effect(mob/living/target_mob, level) + return + +///This proc adjusts the cones width depending on the level. +/obj/effect/proc_holder/spell/cone/proc/calculate_cone_shape(current_level) + var/end_taper_start = round(cone_levels * 0.8) + if(current_level > end_taper_start) + return (current_level % end_taper_start) * 2 //someone more talented and probably come up with a better formula. + else + return 2 + +///This type of cone gradually affects each level of the cone instead of affecting the entire area at once. +/obj/effect/proc_holder/spell/cone/staggered + +/obj/effect/proc_holder/spell/cone/staggered/cast(list/targets,mob/user = usr) + var/level_counter = 0 + var/list/cone_turfs = cone_helper(get_turf(user), user.dir, cone_levels) + for(var/list/turf_list in cone_turfs) + level_counter++ + addtimer(CALLBACK(src, .proc/do_cone_effects, turf_list, level_counter), 2 * level_counter) diff --git a/code/modules/spells/spell_types/dumbfire.dm b/code/modules/spells/spell_types/dumbfire.dm index 6931b4ac31..424c702a31 100644 --- a/code/modules/spells/spell_types/dumbfire.dm +++ b/code/modules/spells/spell_types/dumbfire.dm @@ -49,8 +49,8 @@ var/projectile_type = text2path(proj_type) projectile = new projectile_type(user) else if(istype(proj_type, /obj/effect/proc_holder/spell)) - projectile = new /obj/effect/proc_holder/spell/targeted/trigger(user) - var/obj/effect/proc_holder/spell/targeted/trigger/T = projectile + projectile = new /obj/effect/proc_holder/spell/pointed/trigger(user) + var/obj/effect/proc_holder/spell/pointed/trigger/T = projectile T.linked_spells += proj_type else projectile = new proj_type(user) diff --git a/code/modules/spells/spell_types/ethereal_jaunt.dm b/code/modules/spells/spell_types/ethereal_jaunt.dm index 8cf51d45c6..9d91b6534d 100644 --- a/code/modules/spells/spell_types/ethereal_jaunt.dm +++ b/code/modules/spells/spell_types/ethereal_jaunt.dm @@ -17,7 +17,7 @@ action_icon_state = "jaunt" /obj/effect/proc_holder/spell/targeted/ethereal_jaunt/cast(list/targets,mob/user = usr) //magnets, so mostly hardcoded - playsound(get_turf(user), 'sound/magic/ethereal_enter.ogg', 50, 1, -1) + play_sound("enter",user) for(var/mob/living/target in targets) INVOKE_ASYNC(src, .proc/do_jaunt, target) @@ -42,7 +42,7 @@ ADD_TRAIT(target, TRAIT_MOBILITY_NOMOVE, src) target.update_mobility() holder.reappearing = 1 - playsound(get_turf(target), 'sound/magic/ethereal_exit.ogg', 50, 1, -1) + play_sound("exit",target) sleep(25 - jaunt_in_time) new jaunt_in_type(mobloc, holder.dir) target.setDir(holder.dir) @@ -63,6 +63,13 @@ steam.set_up(10, 0, mobloc) steam.start() +/obj/effect/proc_holder/spell/targeted/ethereal_jaunt/proc/play_sound(type,mob/living/target) + switch(type) + if("enter") + playsound(get_turf(target), 'sound/magic/ethereal_enter.ogg', 50, TRUE, -1) + if("exit") + playsound(get_turf(target), 'sound/magic/ethereal_exit.ogg', 50, TRUE, -1) + /obj/effect/dummy/phased_mob/spell_jaunt name = "water" icon = 'icons/effects/effects.dmi' diff --git a/code/modules/spells/spell_types/mind_transfer.dm b/code/modules/spells/spell_types/mind_transfer.dm deleted file mode 100644 index d2ef015d1d..0000000000 --- a/code/modules/spells/spell_types/mind_transfer.dm +++ /dev/null @@ -1,88 +0,0 @@ -/obj/effect/proc_holder/spell/targeted/mind_transfer - name = "Mind Transfer" - desc = "This spell allows the user to switch bodies with a target." - - school = "transmutation" - charge_max = 600 - clothes_req = NONE - invocation = "GIN'YU CAPAN" - invocation_type = "whisper" - range = 1 - cooldown_min = 200 //100 deciseconds reduction per rank - var/unconscious_amount_caster = 400 //how much the caster is stunned for after the spell - var/unconscious_amount_victim = 400 //how much the victim is stunned for after the spell - - action_icon_state = "mindswap" - -/* -Urist: I don't feel like figuring out how you store object spells so I'm leaving this for you to do. -Make sure spells that are removed from spell_list are actually removed and deleted when mind transferring. -Also, you never added distance checking after target is selected. I've went ahead and did that. -*/ -/obj/effect/proc_holder/spell/targeted/mind_transfer/cast(list/targets, mob/living/user = usr, distanceoverride, silent = FALSE) - if(!targets.len) - if(!silent) - to_chat(user, "No mind found!") - return - - if(targets.len > 1) - if(!silent) - to_chat(user, "Too many minds! You're not a hive damnit!") - return - - var/mob/living/target = targets[1] - - var/t_He = target.p_they(TRUE) - var/t_is = target.p_are() - - if(!(target in oview(range)) && !distanceoverride)//If they are not in overview after selection. Do note that !() is necessary for in to work because ! takes precedence over it. - if(!silent) - to_chat(user, "[t_He] [t_is] too far away!") - return - - if(ismegafauna(target)) - if(!silent) - to_chat(user, "This creature is too powerful to control!") - return - - if(target.stat == DEAD) - if(!silent) - to_chat(user, "You don't particularly want to be dead!") - return - - if(!target.key || !target.mind) - if(!silent) - to_chat(user, "[t_He] appear[target.p_s()] to be catatonic! Not even magic can affect [target.p_their()] vacant mind.") - return - - if(user.suiciding) - if(!silent) - to_chat(user, "You're killing yourself! You can't concentrate enough to do this!") - return - - var/datum/mind/TM = target.mind - if(target.anti_magic_check(TRUE, FALSE) || TM.has_antag_datum(/datum/antagonist/wizard) || TM.has_antag_datum(/datum/antagonist/cult) || TM.has_antag_datum(/datum/antagonist/clockcult) || TM.has_antag_datum(/datum/antagonist/changeling) || TM.has_antag_datum(/datum/antagonist/rev) || target.key[1] == "@") - if(!silent) - to_chat(user, "[target.p_their(TRUE)] mind is resisting your spell!") - return - - var/mob/living/victim = target//The target of the spell whos body will be transferred to. - var/mob/living/caster = user//The wizard/whomever doing the body transferring. - - //MIND TRANSFER BEGIN - var/mob/dead/observer/ghost = victim.ghostize(FALSE, TRUE) - caster.mind.transfer_to(victim) - - ghost.mind.transfer_to(caster) - if(ghost.key) - ghost.transfer_ckey(caster) //have to transfer the key since the mind was not active - qdel(ghost) - - //MIND TRANSFER END - - //Here we knock both mobs out for a time. - caster.Unconscious(unconscious_amount_caster) - victim.Unconscious(unconscious_amount_victim) - SEND_SOUND(caster, sound('sound/magic/mandswap.ogg')) - SEND_SOUND(victim, sound('sound/magic/mandswap.ogg'))// only the caster and victim hear the sounds, that way no one knows for sure if the swap happened - return TRUE diff --git a/code/modules/spells/spell_types/barnyard.dm b/code/modules/spells/spell_types/pointed/barnyard.dm similarity index 52% rename from code/modules/spells/spell_types/barnyard.dm rename to code/modules/spells/spell_types/pointed/barnyard.dm index 4b972e8030..61e3cf7127 100644 --- a/code/modules/spells/spell_types/barnyard.dm +++ b/code/modules/spells/spell_types/pointed/barnyard.dm @@ -1,51 +1,54 @@ -/obj/effect/proc_holder/spell/targeted/barnyardcurse +/obj/effect/proc_holder/spell/pointed/barnyardcurse name = "Curse of the Barnyard" desc = "This spell dooms an unlucky soul to possess the speech and facial attributes of a barnyard animal." school = "transmutation" charge_type = "recharge" charge_max = 150 charge_counter = 0 - clothes_req = NONE - stat_allowed = 0 + clothes_req = FALSE + stat_allowed = FALSE invocation = "KN'A FTAGHU, PUCK 'BTHNK!" invocation_type = "shout" range = 7 cooldown_min = 30 - selection_type = "range" - var/list/compatible_mobs = list(/mob/living/carbon/human, /mob/living/carbon/monkey) - + ranged_mousepointer = 'icons/effects/mouse_pointers/barn_target.dmi' action_icon_state = "barn" + active_msg = "You prepare to curse a target..." + deactive_msg = "You dispel the curse..." + /// List of mobs which are allowed to be a target of the spell + var/static/list/compatible_mobs_typecache = typecacheof(list(/mob/living/carbon/human, /mob/living/carbon/monkey)) -/obj/effect/proc_holder/spell/targeted/barnyardcurse/cast(list/targets, mob/user = usr) +/obj/effect/proc_holder/spell/pointed/barnyardcurse/cast(list/targets, mob/user) if(!targets.len) - to_chat(user, "No target found in range.") - return + to_chat(user, "No target found in range!") + return FALSE + if(!can_target(targets[1], user)) + return FALSE var/mob/living/carbon/target = targets[1] - - if(!(target.type in compatible_mobs)) - to_chat(user, "You are unable to curse [target]'s head!") - return - - if(!(target in oview(range))) - to_chat(user, "[target.p_theyre(TRUE)] too far away!") - return - if(target.anti_magic_check()) to_chat(user, "The spell had no effect!") target.visible_message("[target]'s face bursts into flames, which instantly burst outward, leaving [target] unharmed!", \ - "Your face starts burning up, but the flames are repulsed by your anti-magic protection!") - return + "Your face starts burning up, but the flames are repulsed by your anti-magic protection!") + return FALSE var/list/masks = list(/obj/item/clothing/mask/pig/cursed, /obj/item/clothing/mask/cowmask/cursed, /obj/item/clothing/mask/horsehead/cursed) - var/choice = pick(masks) var/obj/item/clothing/mask/magichead = new choice(get_turf(target)) - magichead.flags_inv = null + target.visible_message("[target]'s face bursts into flames, and a barnyard animal's head takes its place!", \ "Your face burns up, and shortly after the fire you realise you have the face of a barnyard animal!") if(!target.dropItemToGround(target.wear_mask)) qdel(target.wear_mask) - target.equip_to_slot_if_possible(magichead, SLOT_WEAR_MASK, 1, 1) - + target.equip_to_slot_if_possible(magichead, ITEM_SLOT_MASK, 1, 1) target.flash_act() + +/obj/effect/proc_holder/spell/pointed/barnyardcurse/can_target(atom/target, mob/user, silent) + . = ..() + if(!.) + return FALSE + if(!is_type_in_typecache(target, compatible_mobs_typecache)) + if(!silent) + to_chat(user, "You are unable to curse [target]!") + return FALSE + return TRUE diff --git a/code/modules/spells/spell_types/pointed/blind.dm b/code/modules/spells/spell_types/pointed/blind.dm new file mode 100644 index 0000000000..a773c5ad8d --- /dev/null +++ b/code/modules/spells/spell_types/pointed/blind.dm @@ -0,0 +1,35 @@ +/obj/effect/proc_holder/spell/pointed/trigger/blind + name = "Blind" + desc = "This spell temporarily blinds a single target." + school = "transmutation" + charge_max = 300 + clothes_req = FALSE + invocation = "STI KALY" + invocation_type = "whisper" + message = "Your eyes cry out in pain!" + cooldown_min = 50 //12 deciseconds reduction per rank + starting_spells = list("/obj/effect/proc_holder/spell/targeted/inflict_handler/blind", "/obj/effect/proc_holder/spell/targeted/genetic/blind") + ranged_mousepointer = 'icons/effects/mouse_pointers/blind_target.dmi' + action_icon_state = "blind" + active_msg = "You prepare to blind a target..." + +/obj/effect/proc_holder/spell/targeted/inflict_handler/blind + amt_eye_blind = 10 + amt_eye_blurry = 20 + sound = 'sound/magic/blind.ogg' + +/obj/effect/proc_holder/spell/targeted/genetic/blind + mutations = list(BLINDMUT) + duration = 300 + charge_max = 400 // needs to be higher than the duration or it'll be permanent + sound = 'sound/magic/blind.ogg' + +/obj/effect/proc_holder/spell/pointed/trigger/blind/can_target(atom/target, mob/user, silent) + . = ..() + if(!.) + return FALSE + if(!isliving(target)) + if(!silent) + to_chat(user, "You can only blind living beings!") + return FALSE + return TRUE diff --git a/code/modules/spells/spell_types/pointed/mind_transfer.dm b/code/modules/spells/spell_types/pointed/mind_transfer.dm new file mode 100644 index 0000000000..28d646f6b6 --- /dev/null +++ b/code/modules/spells/spell_types/pointed/mind_transfer.dm @@ -0,0 +1,103 @@ +/obj/effect/proc_holder/spell/pointed/mind_transfer + name = "Mind Transfer" + desc = "This spell allows the user to switch bodies with a target next to him." + school = "transmutation" + charge_max = 600 + clothes_req = FALSE + invocation = "GIN'YU CAPAN" + invocation_type = "whisper" + range = 1 + cooldown_min = 200 //100 deciseconds reduction per rank + ranged_mousepointer = 'icons/effects/mouse_pointers/mindswap_target.dmi' + action_icon_state = "mindswap" + active_msg = "You prepare to swap minds with a target..." + /// For how long is the caster stunned for after the spell + var/unconscious_amount_caster = 40 SECONDS + /// For how long is the victim stunned for after the spell + var/unconscious_amount_victim = 40 SECONDS + +/obj/effect/proc_holder/spell/pointed/mind_transfer/cast(list/targets, mob/living/user, silent = FALSE) + if(!targets.len) + if(!silent) + to_chat(user, "No mind found!") + return FALSE + if(targets.len > 1) + if(!silent) + to_chat(user, "Too many minds! You're not a hive damnit!") + return FALSE + if(!can_target(targets[1], user, silent)) + return FALSE + + var/mob/living/victim = targets[1] //The target of the spell whos body will be transferred to. + var/datum/mind/VM = victim.mind + if(victim.anti_magic_check(TRUE, FALSE) || VM.has_antag_datum(/datum/antagonist/wizard) || VM.has_antag_datum(/datum/antagonist/cult) || VM.has_antag_datum(/datum/antagonist/changeling) || VM.has_antag_datum(/datum/antagonist/rev) || victim.key[1] == "@") + if(!silent) + to_chat(user, "[victim.p_their(TRUE)] mind is resisting your spell!") + return FALSE + if(istype(victim, /mob/living/simple_animal/hostile/guardian)) + var/mob/living/simple_animal/hostile/guardian/stand = victim + if(stand.summoner) + victim = stand.summoner + + //You should not be able to enter one of the most powerful side-antags as a fucking wizard. + if(istype(victim,/mob/living/simple_animal/slaughter)) + to_chat(user, "The devilish contract doesn't include the 'mind swappable' package, please try again another lifetime.") + return + + //MIND TRANSFER BEGIN + var/mob/dead/observer/ghost = victim.ghostize() + user.mind.transfer_to(victim) + + ghost.mind.transfer_to(user) + if(ghost.key) + user.key = ghost.key //have to transfer the key since the mind was not active + qdel(ghost) + //MIND TRANSFER END + + //Here we knock both mobs out for a time. + user.Unconscious(unconscious_amount_caster) + victim.Unconscious(unconscious_amount_victim) + SEND_SOUND(user, sound('sound/magic/mandswap.ogg')) + SEND_SOUND(victim, sound('sound/magic/mandswap.ogg')) // only the caster and victim hear the sounds, that way no one knows for sure if the swap happened + return TRUE + +/obj/effect/proc_holder/spell/pointed/mind_transfer/can_target(atom/target, mob/user, silent) + . = ..() + if(!.) + return FALSE + if(!isliving(target)) + if(!silent) + to_chat(user, "You can only swap minds with living beings!") + return FALSE + if(user == target) + if(!silent) + to_chat(user, "You can't swap minds with yourself!") + return FALSE + + var/mob/living/victim = target + var/t_He = victim.p_they(TRUE) + + if(ismegafauna(victim)) + if(!silent) + to_chat(user, "This creature is too powerful to control!") + return FALSE + if(victim.stat == DEAD) + if(!silent) + to_chat(user, "You don't particularly want to be dead!") + return FALSE + if(!victim.key || !victim.mind) + if(!silent) + to_chat(user, "[t_He] appear[victim.p_s()] to be catatonic! Not even magic can affect [victim.p_their()] vacant mind.") + return FALSE + if(user.suiciding) + if(!silent) + to_chat(user, "You're killing yourself! You can't concentrate enough to do this!") + return FALSE + if(istype(victim, /mob/living/simple_animal/hostile/guardian)) + var/mob/living/simple_animal/hostile/guardian/stand = victim + if(stand.summoner) + if(stand.summoner == user) + if(!silent) + to_chat(user, "Swapping minds with your own guardian would just put you back into your own head!") + return FALSE + return TRUE diff --git a/code/modules/spells/spell_types/pointed/pointed.dm b/code/modules/spells/spell_types/pointed/pointed.dm new file mode 100644 index 0000000000..7b942dee27 --- /dev/null +++ b/code/modules/spells/spell_types/pointed/pointed.dm @@ -0,0 +1,105 @@ +/obj/effect/proc_holder/spell/pointed + name = "pointed spell" + ranged_mousepointer = 'icons/effects/mouse_pointers/throw_target.dmi' + action_icon_state = "projectile" + /// Message showing to the spell owner upon deactivating pointed spell. + var/deactive_msg = "You dispel the magic..." + /// Message showing to the spell owner upon activating pointed spell. + var/active_msg = "You prepare to use the spell on a target..." + /// Variable dictating if the user is allowed to cast a spell on himself. + var/self_castable = FALSE + /// Variable dictating if the spell will use turf based aim assist + var/aim_assist = TRUE + +/obj/effect/proc_holder/spell/pointed/Trigger(mob/user, skip_can_cast = TRUE) + if(!istype(user)) + return + var/msg + if(!can_cast(user)) + msg = "You can no longer cast [name]!" + remove_ranged_ability(msg) + return + if(active) + msg = "[deactive_msg]" + remove_ranged_ability(msg) + else + msg = "[active_msg] Left-click to activate spell on a target!" + add_ranged_ability(user, msg, TRUE) + on_activation(user) + +/obj/effect/proc_holder/spell/pointed/on_lose(mob/living/user) + remove_ranged_ability() + +/obj/effect/proc_holder/spell/pointed/remove_ranged_ability(msg) + . = ..() + on_deactivation(ranged_ability_user) + +/obj/effect/proc_holder/spell/pointed/add_ranged_ability(mob/living/user, msg, forced) + . = ..() + on_activation(user) + +/** + * on_activation: What happens upon pointed spell activation. + * + * Arguments: + * * user The mob interacting owning the spell. + */ +/obj/effect/proc_holder/spell/pointed/proc/on_activation(mob/user) + return + +/** + * on_activation: What happens upon pointed spell deactivation. + * + * Arguments: + * * user The mob interacting owning the spell. + */ +/obj/effect/proc_holder/spell/pointed/proc/on_deactivation(mob/user) + return + +/obj/effect/proc_holder/spell/pointed/update_icon() + if(!action) + return + if(active) + action.button_icon_state = "[action_icon_state]1" + else + action.button_icon_state = "[action_icon_state]" + action.UpdateButtonIcon() + +/obj/effect/proc_holder/spell/pointed/InterceptClickOn(mob/living/caller, params, atom/target) + if(..()) + return TRUE + if(aim_assist && isturf(target)) + var/list/possible_targets = list() + for(var/A in target) + if(intercept_check(caller, A, TRUE)) + possible_targets += A + if(possible_targets.len == 1) + target = possible_targets[1] + if(!intercept_check(caller, target)) + return TRUE + if(!cast_check(FALSE, caller)) + return TRUE + perform(list(target), user = caller) + remove_ranged_ability() + return TRUE // Do not do any underlying actions after the spell cast + +/** + * intercept_check: Specific spell checks for InterceptClickOn() targets. + * + * Arguments: + * * user The mob using the ranged spell via intercept. + * * target The atom that is being targeted by the spell via intercept. + * * silent If the checks should produce not any feedback messages for the user. + */ +/obj/effect/proc_holder/spell/pointed/proc/intercept_check(mob/user, atom/target, silent = FALSE) + if(!self_castable && target == user) + if(!silent) + to_chat(user, "You cannot cast the spell on yourself!") + return FALSE + if(!(target in view_or_range(range, user, selection_type))) + if(!silent) + to_chat(user, "[target.p_theyre(TRUE)] too far away!") + return FALSE + if(!can_target(target, user, silent)) + return FALSE + return TRUE diff --git a/code/modules/spells/spell_types/projectile.dm b/code/modules/spells/spell_types/projectile.dm index be305520a2..3a8f48cf7c 100644 --- a/code/modules/spells/spell_types/projectile.dm +++ b/code/modules/spells/spell_types/projectile.dm @@ -37,8 +37,8 @@ var/projectile_type = text2path(proj_type) projectile = new projectile_type(user) if(istype(proj_type, /obj/effect/proc_holder/spell)) - projectile = new /obj/effect/proc_holder/spell/targeted/trigger(user) - var/obj/effect/proc_holder/spell/targeted/trigger/T = projectile + projectile = new /obj/effect/proc_holder/spell/pointed/trigger(user) + var/obj/effect/proc_holder/spell/pointed/trigger/T = projectile T.linked_spells += proj_type projectile.icon = proj_icon projectile.icon_state = proj_icon_state diff --git a/code/modules/spells/spell_types/trigger.dm b/code/modules/spells/spell_types/trigger.dm index 39cff63d98..df579d9243 100644 --- a/code/modules/spells/spell_types/trigger.dm +++ b/code/modules/spells/spell_types/trigger.dm @@ -1,30 +1,26 @@ -/obj/effect/proc_holder/spell/targeted/trigger +/obj/effect/proc_holder/spell/pointed/trigger name = "Trigger" desc = "This spell triggers another spell or a few." - var/list/linked_spells = list() //those are just referenced by the trigger spell and are unaffected by it directly var/list/starting_spells = list() //those are added on New() to contents from default spells and are deleted when the trigger spell is deleted to prevent memory leaks -/obj/effect/proc_holder/spell/targeted/trigger/Initialize() +/obj/effect/proc_holder/spell/pointed/trigger/Initialize() . = ..() - for(var/spell in starting_spells) var/spell_to_add = text2path(spell) new spell_to_add(src) //should result in adding to contents, needs testing -/obj/effect/proc_holder/spell/targeted/trigger/Destroy() +/obj/effect/proc_holder/spell/pointed/trigger/Destroy() for(var/spell in contents) qdel(spell) linked_spells = null starting_spells = null return ..() -/obj/effect/proc_holder/spell/targeted/trigger/cast(list/targets,mob/user = usr) +/obj/effect/proc_holder/spell/pointed/trigger/cast(list/targets,mob/user = usr) playMagSound() for(var/mob/living/target in targets) for(var/obj/effect/proc_holder/spell/spell in contents) spell.perform(list(target),0) for(var/obj/effect/proc_holder/spell/spell in linked_spells) spell.perform(list(target),0) - - return \ No newline at end of file diff --git a/code/modules/spells/spell_types/wizard.dm b/code/modules/spells/spell_types/wizard.dm index 13c47ab9ac..14f359ef81 100644 --- a/code/modules/spells/spell_types/wizard.dm +++ b/code/modules/spells/spell_types/wizard.dm @@ -207,40 +207,12 @@ summon_type = list(/mob/living/simple_animal/hostile/netherworld) cast_sound = 'sound/magic/summonitems_generic.ogg' -/obj/effect/proc_holder/spell/targeted/trigger/blind - name = "Blind" - desc = "This spell temporarily blinds a single person and does not require wizard garb." - - school = "transmutation" - charge_max = 300 - clothes_req = NONE - invocation = "STI KALY" - invocation_type = "whisper" - message = "Your eyes cry out in pain!" - cooldown_min = 50 //12 deciseconds reduction per rank - - starting_spells = list("/obj/effect/proc_holder/spell/targeted/inflict_handler/blind","/obj/effect/proc_holder/spell/targeted/genetic/blind") - - action_icon_state = "blind" - /obj/effect/proc_holder/spell/aoe_turf/conjure/creature/cult name = "Summon Creatures (DANGEROUS)" clothes_req = SPELL_CULT_GARB charge_max = 5000 summon_amt = 2 - - -/obj/effect/proc_holder/spell/targeted/inflict_handler/blind - amt_eye_blind = 10 - amt_eye_blurry = 20 - sound = 'sound/magic/blind.ogg' - -/obj/effect/proc_holder/spell/targeted/genetic/blind - mutations = list(BLINDMUT) - duration = 300 - sound = 'sound/magic/blind.ogg' - /obj/effect/proc_holder/spell/aoe_turf/repulse name = "Repulse" desc = "This spell throws everything around the user away." diff --git a/code/modules/station_goals/bsa.dm b/code/modules/station_goals/bsa.dm index 2ca0e65477..472734b74b 100644 --- a/code/modules/station_goals/bsa.dm +++ b/code/modules/station_goals/bsa.dm @@ -180,16 +180,37 @@ reload() /obj/machinery/bsa/full/proc/fire(mob/user, turf/bullseye) - var/turf/point = get_front_turf() - for(var/turf/T in getline(get_step(point,dir),get_target_turf())) - T.ex_act(EXPLODE_DEVASTATE) - point.Beam(get_target_turf(),icon_state="bsa_beam",time=50,maxdistance = world.maxx) //ZZZAP - - message_admins("[ADMIN_LOOKUPFLW(user)] has launched an artillery strike.") - explosion(bullseye,ex_power,ex_power*2,ex_power*4) - reload() + var/turf/point = get_front_turf() + var/turf/target = get_target_turf() + var/atom/movable/blocker + for(var/T in getline(get_step(point, dir), target)) + var/turf/tile = T + if(SEND_SIGNAL(tile, COMSIG_ATOM_BSA_BEAM) & COMSIG_ATOM_BLOCKS_BSA_BEAM) + blocker = tile + else + for(var/AM in tile) + var/atom/movable/stuff = AM + if(SEND_SIGNAL(stuff, COMSIG_ATOM_BSA_BEAM) & COMSIG_ATOM_BLOCKS_BSA_BEAM) + blocker = stuff + break + if(blocker) + target = tile + break + else + tile.ex_act(EXPLODE_DEVASTATE) + point.Beam(target, icon_state = "bsa_beam", time = 50, maxdistance = world.maxx) //ZZZAP + new /obj/effect/temp_visual/bsa_splash(point, dir) + + if(!blocker) + message_admins("[ADMIN_LOOKUPFLW(user)] has launched an artillery strike targeting [ADMIN_VERBOSEJMP(bullseye)].") + log_game("[key_name(user)] has launched an artillery strike targeting [AREACOORD(bullseye)].") + explosion(bullseye, ex_power, ex_power*2, ex_power*4) + else + message_admins("[ADMIN_LOOKUPFLW(user)] has launched an artillery strike targeting [ADMIN_VERBOSEJMP(bullseye)] but it was blocked by [blocker] at [ADMIN_VERBOSEJMP(target)].") + log_game("[key_name(user)] has launched an artillery strike targeting [AREACOORD(bullseye)] but it was blocked by [blocker] at [AREACOORD(target)].") + /obj/machinery/bsa/full/proc/reload() ready = FALSE use_power(power_used_per_shot) @@ -210,20 +231,23 @@ /obj/machinery/computer/bsa_control name = "bluespace artillery control" - var/obj/machinery/bsa/full/cannon - var/notice - var/target use_power = NO_POWER_USE circuit = /obj/item/circuitboard/computer/bsa_control icon = 'icons/obj/machines/particle_accelerator.dmi' icon_state = "control_boxp" + + var/obj/machinery/bsa/full/cannon + var/notice + var/target var/area_aim = FALSE //should also show areas for targeting -/obj/machinery/computer/bsa_control/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ - datum/tgui/master_ui = null, datum/ui_state/state = GLOB.physical_state) - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) +/obj/machinery/computer/bsa_control/ui_state(mob/user) + return GLOB.physical_state + +/obj/machinery/computer/bsa_control/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) if(!ui) - ui = new(user, src, ui_key, "BluespaceArtillery", name, ui_x, ui_y, master_ui, state) + ui = new(user, src, "BluespaceArtillery", name) ui.open() /obj/machinery/computer/bsa_control/ui_data() @@ -255,7 +279,7 @@ if(!GLOB.bsa_unlock) return var/list/gps_locators = list() - for(var/obj/item/gps/G in GLOB.GPS_list) //nulls on the list somehow + for(var/datum/component/gps/G in GLOB.GPS_list) //nulls on the list somehow if(G.tracking) gps_locators[G.gpstag] = G diff --git a/code/modules/station_goals/dna_vault.dm b/code/modules/station_goals/dna_vault.dm index 6d8ab9cc7f..4ac3777a41 100644 --- a/code/modules/station_goals/dna_vault.dm +++ b/code/modules/station_goals/dna_vault.dm @@ -174,14 +174,13 @@ . = ..() -/obj/machinery/dna_vault/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.physical_state) - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) +/obj/machinery/dna_vault/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) if(!ui) roll_powers(user) - ui = new(user, src, ui_key, "DnaVault", name, ui_x, ui_y, master_ui, state) + ui = new(user, src, "DnaVault", name) ui.open() - /obj/machinery/dna_vault/proc/roll_powers(mob/user) if(user in power_lottery) return diff --git a/code/modules/station_goals/shield.dm b/code/modules/station_goals/shield.dm index 299fda4a26..c8fbda8988 100644 --- a/code/modules/station_goals/shield.dm +++ b/code/modules/station_goals/shield.dm @@ -42,10 +42,10 @@ circuit = /obj/item/circuitboard/computer/sat_control var/notice -/obj/machinery/computer/sat_control/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) +/obj/machinery/computer/sat_control/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) if(!ui) - ui = new(user, src, ui_key, "SatelliteControl", name, ui_x, ui_y, master_ui, state) + ui = new(user, src, "SatelliteControl", name) ui.open() /obj/machinery/computer/sat_control/ui_act(action, params) diff --git a/code/modules/surgery/organs/stomach.dm b/code/modules/surgery/organs/stomach.dm index d9cbf9be03..44b4f6362a 100755 --- a/code/modules/surgery/organs/stomach.dm +++ b/code/modules/surgery/organs/stomach.dm @@ -91,3 +91,36 @@ /obj/item/organ/stomach/ipc name = "ipc stomach" icon_state = "stomach-ipc" + + +/obj/item/organ/stomach/ethereal + name = "biological battery" + icon_state = "stomach-p" //Welp. At least it's more unique in functionaliy. + desc = "A crystal-like organ that stores the electric charge of ethereals." + var/crystal_charge = ETHEREAL_CHARGE_FULL + +/obj/item/organ/stomach/ethereal/on_life() + ..() + adjust_charge(-ETHEREAL_CHARGE_FACTOR) + +/obj/item/organ/stomach/ethereal/Insert(mob/living/carbon/M, special = 0, drop_if_replaced = TRUE) + ..() + RegisterSignal(owner, COMSIG_PROCESS_BORGCHARGER_OCCUPANT, .proc/charge) + RegisterSignal(owner, COMSIG_LIVING_ELECTROCUTE_ACT, .proc/on_electrocute) + +/obj/item/organ/stomach/ethereal/Remove(mob/living/carbon/M, special = 0) + UnregisterSignal(owner, COMSIG_PROCESS_BORGCHARGER_OCCUPANT) + UnregisterSignal(owner, COMSIG_LIVING_ELECTROCUTE_ACT) + ..() + +/obj/item/organ/stomach/ethereal/proc/charge(datum/source, amount, repairs) + adjust_charge(amount / 70) + +/obj/item/organ/stomach/ethereal/proc/on_electrocute(datum/source, shock_damage, siemens_coeff = 1, flags = NONE) + if(flags & SHOCK_ILLUSION) + return + adjust_charge(shock_damage * siemens_coeff * 2) + to_chat(owner, "You absorb some of the shock into your body!") + +/obj/item/organ/stomach/ethereal/proc/adjust_charge(amount) + crystal_charge = clamp(crystal_charge + amount, ETHEREAL_CHARGE_NONE, ETHEREAL_CHARGE_DANGEROUS) diff --git a/code/modules/surgery/organs/tongue.dm b/code/modules/surgery/organs/tongue.dm index 1c4a2d3043..7090ab62e2 100644 --- a/code/modules/surgery/organs/tongue.dm +++ b/code/modules/surgery/organs/tongue.dm @@ -312,3 +312,26 @@ desc = "A voice synthesizer used by IPCs to smoothly interface with organic lifeforms." electronics_magic = FALSE organ_flags = ORGAN_SYNTHETIC + +/obj/item/organ/tongue/ethereal + name = "electric discharger" + desc = "A sophisticated ethereal organ, capable of synthesising speech via electrical discharge." + icon_state = "electrotongue" + say_mod = "crackles" + attack_verb = list("shocked", "jolted", "zapped") + taste_sensitivity = 101 // Not a tongue, they can't taste shit + var/static/list/languages_possible_ethereal = typecacheof(list( + /datum/language/common, + /datum/language/draconic, + /datum/language/codespeak, + /datum/language/monkey, + /datum/language/narsie, + /datum/language/beachbum, + /datum/language/aphasia, + /datum/language/sylvan, + /datum/language/voltaic + )) + +/obj/item/organ/tongue/ethereal/Initialize(mapload) + . = ..() + languages_possible = languages_possible_ethereal diff --git a/code/modules/tgui/external.dm b/code/modules/tgui/external.dm index 5de54c439c..46b324e151 100644 --- a/code/modules/tgui/external.dm +++ b/code/modules/tgui/external.dm @@ -1,7 +1,8 @@ /** - * tgui external + * External tgui definitions, such as src_object APIs. * - * Contains all external tgui declarations. + * Copyright (c) 2020 Aleksej Komarov + * SPDX-License-Identifier: MIT */ /** @@ -11,13 +12,9 @@ * If this proc is not implemented properly, the UI will not update correctly. * * required user mob The mob who opened/is using the UI. - * optional ui_key string The ui_key of the UI. * optional ui datum/tgui The UI to be updated, if it exists. - * optional force_open bool If the UI should be re-opened instead of updated. - * optional master_ui datum/tgui The parent UI. - * optional state datum/ui_state The state used to determine status. */ -/datum/proc/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) +/datum/proc/ui_interact(mob/user, datum/tgui/ui) return FALSE // Not implemented. /** @@ -37,10 +34,11 @@ * public * * Static Data to be sent to the UI. - * Static data differs from normal data in that it's large data that should be sent infrequently - * This is implemented optionally for heavy uis that would be sending a lot of redundant data - * frequently. - * Gets squished into one object on the frontend side, but the static part is cached. + * + * Static data differs from normal data in that it's large data that should be + * sent infrequently. This is implemented optionally for heavy uis that would + * be sending a lot of redundant data frequently. Gets squished into one + * object on the frontend side, but the static part is cached. * * required user mob The mob interacting with the UI. * @@ -52,18 +50,17 @@ /** * public * - * Forces an update on static data. Should be done manually whenever something happens to change static data. + * Forces an update on static data. Should be done manually whenever something + * happens to change static data. * * required user the mob currently interacting with the ui * optional ui ui to be updated - * optional ui_key ui key of ui to be updated */ -/datum/proc/update_static_data(mob/user, datum/tgui/ui, ui_key = "main") - ui = SStgui.try_update_ui(user, src, ui_key, ui) - // If there was no ui to update, there's no static data to update either. +/datum/proc/update_static_data(mob/user, datum/tgui/ui) if(!ui) - return - ui.push_data(null, ui_static_data(), TRUE) + ui = SStgui.get_open_ui(user, src) + if(ui) + ui.send_full_update() /** * public @@ -85,17 +82,12 @@ * public * * Called on an object when a tgui object is being created, allowing you to - * customise the html - * For example: inserting a custom stylesheet that you need in the head + * push various assets to tgui, for examples spritesheets. * - * For this purpose, some tags are available in the html, to be parsed out - ^ with replacetext - * (customheadhtml) - Additions to the head tag - * - * required html the html base text + * return list List of asset datums or file paths. */ -/datum/proc/ui_base_html(html) - return html +/datum/proc/ui_assets(mob/user) + return list() /** * private @@ -107,6 +99,15 @@ /datum/proc/ui_host(mob/user) return src // Default src. +/** + * private + * + * The UI's state controller to be used for created uis + * This is a proc over a var for memory reasons + */ +/datum/proc/ui_state(mob/user) + return GLOB.default_state + /** * global * @@ -118,9 +119,17 @@ /** * global * - * Used to track UIs for a mob. + * Tracks open UIs for a user. */ -/mob/var/list/open_uis = list() +/mob/var/list/tgui_open_uis = list() + +/** + * global + * + * Tracks open windows for a user. + */ +/client/var/list/tgui_windows = list() + /** * public * @@ -137,17 +146,43 @@ * * required uiref ref The UI that was closed. */ -/client/verb/uiclose(ref as text) +/client/verb/uiclose(window_id as text) // Name the verb, and hide it from the user panel. set name = "uiclose" - set hidden = 1 + set hidden = TRUE + var/mob/user = src && src.mob + if(!user) + return + // Close all tgui datums based on window_id. + SStgui.force_close_window(user, window_id) - // Get the UI based on the ref. - var/datum/tgui/ui = locate(ref) - - // If we found the UI, close it. - if(istype(ui)) - ui.close() - // Unset machine just to be sure. - if(src && src.mob) - src.mob.unset_machine() +/** + * Middleware for /client/Topic. + * + * return bool Whether the topic is passed (TRUE), or cancelled (FALSE). + */ +/proc/tgui_Topic(href_list) + // Skip non-tgui topics + if(!href_list["tgui"]) + return TRUE + var/type = href_list["type"] + // Unconditionally collect tgui logs + if(type == "log") + log_tgui(usr, href_list["message"]) + // Locate window + var/window_id = href_list["window_id"] + var/datum/tgui_window/window + if(window_id) + window = usr.client.tgui_windows[window_id] + if(!window) + log_tgui(usr, "Error: Couldn't find the window datum, force closing.") + SStgui.force_close_window(usr, window_id) + return FALSE + // Decode payload + var/payload + if(href_list["payload"]) + payload = json_decode(href_list["payload"]) + // Pass message to window + if(window) + window.on_message(type, payload, href_list) + return FALSE diff --git a/code/modules/tgui/states.dm b/code/modules/tgui/states.dm index e626b98815..fa88cc1338 100644 --- a/code/modules/tgui/states.dm +++ b/code/modules/tgui/states.dm @@ -1,7 +1,9 @@ /** - * tgui states + * Base state and helpers for states. Just does some sanity checks, + * implement a proper state for in-depth checks. * - * Base state and helpers for states. Just does some sanity checks, implement a state for in-depth checks. + * Copyright (c) 2020 Aleksej Komarov + * SPDX-License-Identifier: MIT */ /** @@ -26,9 +28,10 @@ . = max(., UI_INTERACTIVE) // Regular ghosts can always at least view if in range. - var/clientviewlist = getviewsize(user.client.view) - if(get_dist(src_object, user) < max(clientviewlist[1],clientviewlist[2])) - . = max(., UI_UPDATE) + if(user.client) + var/clientviewlist = getviewsize(user.client.view) + if(get_dist(src_object, user) < max(clientviewlist[1], clientviewlist[2])) + . = max(., UI_UPDATE) // Check if the state allows interaction var/result = state.can_use_topic(src_object, user) @@ -46,7 +49,8 @@ * return UI_state The state of the UI. */ /datum/ui_state/proc/can_use_topic(src_object, mob/user) - return UI_CLOSE // Don't allow interaction by default. + // Don't allow interaction by default. + return UI_CLOSE /** * public @@ -56,21 +60,31 @@ * return UI_state The state of the UI. */ /mob/proc/shared_ui_interaction(src_object) - if(!client) // Close UIs if mindless. + // Close UIs if mindless. + if(!client) return UI_CLOSE - else if(stat) // Disable UIs if unconcious. + // Disable UIs if unconcious. + else if(stat) return UI_DISABLED - else if(incapacitated() || lying) // Update UIs if incapicitated but concious. + // Update UIs if incapicitated but concious. + else if(incapacitated()) return UI_UPDATE return UI_INTERACTIVE +/mob/living/shared_ui_interaction(src_object) + . = ..() + if(!(mobility_flags & MOBILITY_UI) && . == UI_INTERACTIVE) + return UI_UPDATE + /mob/living/silicon/ai/shared_ui_interaction(src_object) - if(lacks_power()) // Disable UIs if the AI is unpowered. + // Disable UIs if the AI is unpowered. + if(lacks_power()) return UI_DISABLED return ..() /mob/living/silicon/robot/shared_ui_interaction(src_object) - if(!cell || cell.charge <= 0 || locked_down) // Disable UIs if the Borg is unpowered or locked. + // Disable UIs if the Borg is unpowered or locked. + if(!cell || cell.charge <= 0 || locked_down) return UI_DISABLED return ..() @@ -87,7 +101,8 @@ * return UI_state The state of the UI. */ /atom/proc/contents_ui_distance(src_object, mob/living/user) - return user.shared_living_ui_distance(src_object) // Just call this mob's check. + // Just call this mob's check. + return user.shared_living_ui_distance(src_object) /** * public @@ -99,17 +114,21 @@ * return UI_state The state of the UI. */ /mob/living/proc/shared_living_ui_distance(atom/movable/src_object, viewcheck = TRUE) - if(viewcheck && !(src_object in view(src))) // If the object is obscured, close it. + // If the object is obscured, close it. + if(viewcheck && !(src_object in view(src))) return UI_CLOSE - var/dist = get_dist(src_object, src) - if(dist <= 1 || src_object.hasSiliconAccessInArea(src)) // Open and interact if 1-0 tiles away. + // Open and interact if 1-0 tiles away. + if(dist <= 1) return UI_INTERACTIVE - else if(dist <= 2) // View only if 2-3 tiles away. + // View only if 2-3 tiles away. + else if(dist <= 2) return UI_UPDATE - else if(dist <= 5) // Disable if 5 tiles away. + // Disable if 5 tiles away. + else if(dist <= 5) return UI_DISABLED - return UI_CLOSE // Otherwise, we got nothing. + // Otherwise, we got nothing. + return UI_CLOSE /mob/living/carbon/human/shared_living_ui_distance(atom/movable/src_object, viewcheck = TRUE) if(dna.check_mutation(TK) && tkMaxRangeCheck(src, src_object)) diff --git a/code/modules/tgui/states/admin.dm b/code/modules/tgui/states/admin.dm index 61fc373118..227a294078 100644 --- a/code/modules/tgui/states/admin.dm +++ b/code/modules/tgui/states/admin.dm @@ -2,6 +2,9 @@ * tgui state: admin_state * * Checks that the user is an admin, end-of-story. + * + * Copyright (c) 2020 Aleksej Komarov + * SPDX-License-Identifier: MIT */ GLOBAL_DATUM_INIT(admin_state, /datum/ui_state/admin_state, new) diff --git a/code/modules/tgui/states/always.dm b/code/modules/tgui/states/always.dm index a741e2e3d4..210f0896a2 100644 --- a/code/modules/tgui/states/always.dm +++ b/code/modules/tgui/states/always.dm @@ -2,6 +2,9 @@ * tgui state: always_state * * Always grants the user UI_INTERACTIVE. Period. + * + * Copyright (c) 2020 Aleksej Komarov + * SPDX-License-Identifier: MIT */ GLOBAL_DATUM_INIT(always_state, /datum/ui_state/always_state, new) diff --git a/code/modules/tgui/states/conscious.dm b/code/modules/tgui/states/conscious.dm index 4e2793d130..670ca7c07e 100644 --- a/code/modules/tgui/states/conscious.dm +++ b/code/modules/tgui/states/conscious.dm @@ -2,6 +2,9 @@ * tgui state: conscious_state * * Only checks if the user is conscious. + * + * Copyright (c) 2020 Aleksej Komarov + * SPDX-License-Identifier: MIT */ GLOBAL_DATUM_INIT(conscious_state, /datum/ui_state/conscious_state, new) diff --git a/code/modules/tgui/states/contained.dm b/code/modules/tgui/states/contained.dm index f02424d01e..1eb8edba25 100644 --- a/code/modules/tgui/states/contained.dm +++ b/code/modules/tgui/states/contained.dm @@ -2,6 +2,9 @@ * tgui state: contained_state * * Checks that the user is inside the src_object. + * + * Copyright (c) 2020 Aleksej Komarov + * SPDX-License-Identifier: MIT */ GLOBAL_DATUM_INIT(contained_state, /datum/ui_state/contained_state, new) diff --git a/code/modules/tgui/states/deep_inventory.dm b/code/modules/tgui/states/deep_inventory.dm index 43758cbab1..a2b9276a59 100644 --- a/code/modules/tgui/states/deep_inventory.dm +++ b/code/modules/tgui/states/deep_inventory.dm @@ -1,7 +1,11 @@ /** * tgui state: deep_inventory_state * - * Checks that the src_object is in the user's deep (backpack, box, toolbox, etc) inventory. + * Checks that the src_object is in the user's deep + * (backpack, box, toolbox, etc) inventory. + * + * Copyright (c) 2020 Aleksej Komarov + * SPDX-License-Identifier: MIT */ GLOBAL_DATUM_INIT(deep_inventory_state, /datum/ui_state/deep_inventory_state, new) diff --git a/code/modules/tgui/states/default.dm b/code/modules/tgui/states/default.dm index 6bb159640e..367e57beff 100644 --- a/code/modules/tgui/states/default.dm +++ b/code/modules/tgui/states/default.dm @@ -1,7 +1,11 @@ /** * tgui state: default_state * - * Checks a number of things -- mostly physical distance for humans and view for robots. + * Checks a number of things -- mostly physical distance for humans + * and view for robots. + * + * Copyright (c) 2020 Aleksej Komarov + * SPDX-License-Identifier: MIT */ GLOBAL_DATUM_INIT(default_state, /datum/ui_state/default, new) diff --git a/code/modules/tgui/states/default_contained.dm b/code/modules/tgui/states/default_contained.dm deleted file mode 100644 index c532e9f5d1..0000000000 --- a/code/modules/tgui/states/default_contained.dm +++ /dev/null @@ -1,13 +0,0 @@ -/** - * tgui state: default_contained - * - * Basically default and contained combined, allowing for both - */ - -GLOBAL_DATUM_INIT(default_contained_state, /datum/ui_state/default/contained, new) - -/datum/ui_state/default/contained/can_use_topic(atom/src_object, mob/user) - if(src_object.contains(user)) - return UI_INTERACTIVE - return ..() - \ No newline at end of file diff --git a/code/modules/tgui/states/hands.dm b/code/modules/tgui/states/hands.dm index d73d1058ea..1c885ed414 100644 --- a/code/modules/tgui/states/hands.dm +++ b/code/modules/tgui/states/hands.dm @@ -2,6 +2,9 @@ * tgui state: hands_state * * Checks that the src_object is in the user's hands. + * + * Copyright (c) 2020 Aleksej Komarov + * SPDX-License-Identifier: MIT */ GLOBAL_DATUM_INIT(hands_state, /datum/ui_state/hands_state, new) @@ -19,7 +22,7 @@ GLOBAL_DATUM_INIT(hands_state, /datum/ui_state/hands_state, new) return UI_INTERACTIVE return UI_CLOSE -/mob/living/silicon/robot/hands_can_use_topic(obj/src_object) - if(activated(src_object) || istype(src_object.loc, /obj/item/weapon/gripper)) +/mob/living/silicon/robot/hands_can_use_topic(src_object) + if(activated(src_object)) return UI_INTERACTIVE return UI_CLOSE diff --git a/code/modules/tgui/states/human_adjacent.dm b/code/modules/tgui/states/human_adjacent.dm index 7aefe43e44..2ac7c8637b 100644 --- a/code/modules/tgui/states/human_adjacent.dm +++ b/code/modules/tgui/states/human_adjacent.dm @@ -3,6 +3,9 @@ * * In addition to default checks, only allows interaction for a * human adjacent user. + * + * Copyright (c) 2020 Aleksej Komarov + * SPDX-License-Identifier: MIT */ GLOBAL_DATUM_INIT(human_adjacent_state, /datum/ui_state/human_adjacent_state, new) diff --git a/code/modules/tgui/states/inventory.dm b/code/modules/tgui/states/inventory.dm index 43fe2cb451..dc5dd0d57e 100644 --- a/code/modules/tgui/states/inventory.dm +++ b/code/modules/tgui/states/inventory.dm @@ -1,7 +1,11 @@ /** * tgui state: inventory_state * - * Checks that the src_object is in the user's top-level (hand, ear, pocket, belt, etc) inventory. + * Checks that the src_object is in the user's top-level + * (hand, ear, pocket, belt, etc) inventory. + * + * Copyright (c) 2020 Aleksej Komarov + * SPDX-License-Identifier: MIT */ GLOBAL_DATUM_INIT(inventory_state, /datum/ui_state/inventory_state, new) diff --git a/code/modules/tgui/states/language_menu.dm b/code/modules/tgui/states/language_menu.dm index 5c816c8922..6389b05cd5 100644 --- a/code/modules/tgui/states/language_menu.dm +++ b/code/modules/tgui/states/language_menu.dm @@ -1,5 +1,8 @@ /** * tgui state: language_menu_state + * + * Copyright (c) 2020 Aleksej Komarov + * SPDX-License-Identifier: MIT */ GLOBAL_DATUM_INIT(language_menu_state, /datum/ui_state/language_menu, new) diff --git a/code/modules/tgui/states/not_incapacitated.dm b/code/modules/tgui/states/not_incapacitated.dm index 364b59424d..16dcb7881e 100644 --- a/code/modules/tgui/states/not_incapacitated.dm +++ b/code/modules/tgui/states/not_incapacitated.dm @@ -2,6 +2,9 @@ * tgui state: not_incapacitated_state * * Checks that the user isn't incapacitated + * + * Copyright (c) 2020 Aleksej Komarov + * SPDX-License-Identifier: MIT */ GLOBAL_DATUM_INIT(not_incapacitated_state, /datum/ui_state/not_incapacitated_state, new) @@ -24,6 +27,10 @@ GLOBAL_DATUM_INIT(not_incapacitated_turf_state, /datum/ui_state/not_incapacitate /datum/ui_state/not_incapacitated_state/can_use_topic(src_object, mob/user) if(user.stat) return UI_CLOSE - if(user.incapacitated() || user.lying || (turf_check && !isturf(user.loc))) + if(user.incapacitated() || (turf_check && !isturf(user.loc))) return UI_DISABLED - return UI_INTERACTIVE \ No newline at end of file + if(isliving(user)) + var/mob/living/L = user + if(!(L.mobility_flags & MOBILITY_STAND)) + return UI_DISABLED + return UI_INTERACTIVE diff --git a/code/modules/tgui/states/notcontained.dm b/code/modules/tgui/states/notcontained.dm index 642c6ce95f..1d4e6aec19 100644 --- a/code/modules/tgui/states/notcontained.dm +++ b/code/modules/tgui/states/notcontained.dm @@ -1,7 +1,11 @@ /** * tgui state: notcontained_state * - * Checks that the user is not inside src_object, and then makes the default checks. + * Checks that the user is not inside src_object, and then makes the + * default checks. + * + * Copyright (c) 2020 Aleksej Komarov + * SPDX-License-Identifier: MIT */ GLOBAL_DATUM_INIT(notcontained_state, /datum/ui_state/notcontained_state, new) diff --git a/code/modules/tgui/states/observer.dm b/code/modules/tgui/states/observer.dm index 86ad776b13..d105de1c0c 100644 --- a/code/modules/tgui/states/observer.dm +++ b/code/modules/tgui/states/observer.dm @@ -2,6 +2,9 @@ * tgui state: observer_state * * Checks that the user is an observer/ghost. + * + * Copyright (c) 2020 Aleksej Komarov + * SPDX-License-Identifier: MIT */ GLOBAL_DATUM_INIT(observer_state, /datum/ui_state/observer_state, new) diff --git a/code/modules/tgui/states/physical.dm b/code/modules/tgui/states/physical.dm index 88c8a291aa..3073039d14 100644 --- a/code/modules/tgui/states/physical.dm +++ b/code/modules/tgui/states/physical.dm @@ -2,6 +2,9 @@ * tgui state: physical_state * * Short-circuits the default state to only check physical distance. + * + * Copyright (c) 2020 Aleksej Komarov + * SPDX-License-Identifier: MIT */ GLOBAL_DATUM_INIT(physical_state, /datum/ui_state/physical, new) diff --git a/code/modules/tgui/states/self.dm b/code/modules/tgui/states/self.dm index b0c9500fbc..4b6e3b9fd9 100644 --- a/code/modules/tgui/states/self.dm +++ b/code/modules/tgui/states/self.dm @@ -2,6 +2,9 @@ * tgui state: self_state * * Only checks that the user and src_object are the same. + * + * Copyright (c) 2020 Aleksej Komarov + * SPDX-License-Identifier: MIT */ GLOBAL_DATUM_INIT(self_state, /datum/ui_state/self_state, new) diff --git a/code/modules/tgui/states/zlevel.dm b/code/modules/tgui/states/zlevel.dm index 5e3ccfb7de..64ea2fa1c0 100644 --- a/code/modules/tgui/states/zlevel.dm +++ b/code/modules/tgui/states/zlevel.dm @@ -2,6 +2,9 @@ * tgui state: z_state * * Only checks that the Z-level of the user and src_object are the same. + * + * Copyright (c) 2020 Aleksej Komarov + * SPDX-License-Identifier: MIT */ GLOBAL_DATUM_INIT(z_state, /datum/ui_state/z_state, new) diff --git a/code/modules/tgui/subsystem.dm b/code/modules/tgui/subsystem.dm deleted file mode 100644 index cbe94e2d7f..0000000000 --- a/code/modules/tgui/subsystem.dm +++ /dev/null @@ -1,247 +0,0 @@ -/** - * tgui subsystem - * - * Contains all tgui state and subsystem code. - */ - -/** - * public - * - * Get a open UI given a user, src_object, and ui_key and try to update it with data. - * - * required user mob The mob who opened/is using the UI. - * required src_object datum The object/datum which owns the UI. - * required ui_key string The ui_key of the UI. - * optional ui datum/tgui The UI to be updated, if it exists. - * optional force_open bool If the UI should be re-opened instead of updated. - * - * return datum/tgui The found UI. - */ -/datum/controller/subsystem/tgui/proc/try_update_ui(mob/user, datum/src_object, ui_key, datum/tgui/ui, force_open = FALSE) - if(isnull(ui)) // No UI was passed, so look for one. - ui = get_open_ui(user, src_object, ui_key) - - if(!isnull(ui)) - var/data = src_object.ui_data(user) // Get data from the src_object. - if(!force_open) // UI is already open; update it. - ui.push_data(data) - else // Re-open it anyways. - ui.reinitialize(null, data) - return ui // We found the UI, return it. - else - return null // We couldn't find a UI. - -/** - * private - * - * Get a open UI given a user, src_object, and ui_key. - * - * required user mob The mob who opened/is using the UI. - * required src_object datum The object/datum which owns the UI. - * required ui_key string The ui_key of the UI. - * - * return datum/tgui The found UI. - */ -/datum/controller/subsystem/tgui/proc/get_open_ui(mob/user, datum/src_object, ui_key) - var/src_object_key = "[REF(src_object)]" - if(isnull(open_uis[src_object_key]) || !istype(open_uis[src_object_key], /list)) - return null // No UIs open. - else if(isnull(open_uis[src_object_key][ui_key]) || !istype(open_uis[src_object_key][ui_key], /list)) - return null // No UIs open for this object. - - for(var/datum/tgui/ui in open_uis[src_object_key][ui_key]) // Find UIs for this object. - if(ui.user == user) // Make sure we have the right user - return ui - - return null // Couldn't find a UI! - -/** - * private - * - * Update all UIs attached to src_object. - * - * required src_object datum The object/datum which owns the UIs. - * - * return int The number of UIs updated. - */ -/datum/controller/subsystem/tgui/proc/update_uis(datum/src_object) - var/src_object_key = "[REF(src_object)]" - if(isnull(open_uis[src_object_key]) || !istype(open_uis[src_object_key], /list)) - return 0 // Couldn't find any UIs for this object. - - var/update_count = 0 - for(var/ui_key in open_uis[src_object_key]) - for(var/datum/tgui/ui in open_uis[src_object_key][ui_key]) - if(ui && ui.src_object && ui.user && ui.src_object.ui_host(ui.user)) // Check the UI is valid. - ui.process(force = 1) // Update the UI. - update_count++ // Count each UI we update. - return update_count - -/** - * private - * - * Close all UIs attached to src_object. - * - * required src_object datum The object/datum which owns the UIs. - * - * return int The number of UIs closed. - */ -/datum/controller/subsystem/tgui/proc/close_uis(datum/src_object) - var/src_object_key = "[REF(src_object)]" - if(isnull(open_uis[src_object_key]) || !istype(open_uis[src_object_key], /list)) - return 0 // Couldn't find any UIs for this object. - - var/close_count = 0 - for(var/ui_key in open_uis[src_object_key]) - for(var/datum/tgui/ui in open_uis[src_object_key][ui_key]) - if(ui && ui.src_object && ui.user && ui.src_object.ui_host(ui.user)) // Check the UI is valid. - ui.close() // Close the UI. - close_count++ // Count each UI we close. - return close_count - -/** - * private - * - * Close *ALL* UIs - * - * return int The number of UIs closed. - */ -/datum/controller/subsystem/tgui/proc/close_all_uis() - var/close_count = 0 - for(var/src_object_key in open_uis) - for(var/ui_key in open_uis[src_object_key]) - for(var/datum/tgui/ui in open_uis[src_object_key][ui_key]) - if(ui && ui.src_object && ui.user && ui.src_object.ui_host(ui.user)) // Check the UI is valid. - ui.close() // Close the UI. - close_count++ // Count each UI we close. - return close_count - -/** - * private - * - * Update all UIs belonging to a user. - * - * required user mob The mob who opened/is using the UI. - * optional src_object datum If provided, only update UIs belonging this src_object. - * optional ui_key string If provided, only update UIs with this UI key. - * - * return int The number of UIs updated. - */ -/datum/controller/subsystem/tgui/proc/update_user_uis(mob/user, datum/src_object = null, ui_key = null) - if(isnull(user.open_uis) || !istype(user.open_uis, /list) || open_uis.len == 0) - return 0 // Couldn't find any UIs for this user. - - var/update_count = 0 - for(var/datum/tgui/ui in user.open_uis) - if((isnull(src_object) || !isnull(src_object) && ui.src_object == src_object) && (isnull(ui_key) || !isnull(ui_key) && ui.ui_key == ui_key)) - ui.process(force = 1) // Update the UI. - update_count++ // Count each UI we upadte. - return update_count - -/** - * private - * - * Close all UIs belonging to a user. - * - * required user mob The mob who opened/is using the UI. - * optional src_object datum If provided, only close UIs belonging this src_object. - * optional ui_key string If provided, only close UIs with this UI key. - * - * return int The number of UIs closed. - */ -/datum/controller/subsystem/tgui/proc/close_user_uis(mob/user, datum/src_object = null, ui_key = null) - if(isnull(user.open_uis) || !istype(user.open_uis, /list) || open_uis.len == 0) - return 0 // Couldn't find any UIs for this user. - - var/close_count = 0 - for(var/datum/tgui/ui in user.open_uis) - if((isnull(src_object) || !isnull(src_object) && ui.src_object == src_object) && (isnull(ui_key) || !isnull(ui_key) && ui.ui_key == ui_key)) - ui.close() // Close the UI. - close_count++ // Count each UI we close. - return close_count - -/** - * private - * - * Add a UI to the list of open UIs. - * - * required ui datum/tgui The UI to be added. - */ -/datum/controller/subsystem/tgui/proc/on_open(datum/tgui/ui) - var/src_object_key = "[REF(ui.src_object)]" - if(isnull(open_uis[src_object_key]) || !istype(open_uis[src_object_key], /list)) - open_uis[src_object_key] = list(ui.ui_key = list()) // Make a list for the ui_key and src_object. - else if(isnull(open_uis[src_object_key][ui.ui_key]) || !istype(open_uis[src_object_key][ui.ui_key], /list)) - open_uis[src_object_key][ui.ui_key] = list() // Make a list for the ui_key. - - // Append the UI to all the lists. - ui.user.open_uis |= ui - var/list/uis = open_uis[src_object_key][ui.ui_key] - uis |= ui - processing_uis |= ui - -/** - * private - * - * Remove a UI from the list of open UIs. - * - * required ui datum/tgui The UI to be removed. - * - * return bool If the UI was removed or not. - */ -/datum/controller/subsystem/tgui/proc/on_close(datum/tgui/ui) - var/src_object_key = "[REF(ui.src_object)]" - if(isnull(open_uis[src_object_key]) || !istype(open_uis[src_object_key], /list)) - return 0 // It wasn't open. - else if(isnull(open_uis[src_object_key][ui.ui_key]) || !istype(open_uis[src_object_key][ui.ui_key], /list)) - return 0 // It wasn't open. - - processing_uis.Remove(ui) // Remove it from the list of processing UIs. - if(ui.user) // If the user exists, remove it from them too. - ui.user.open_uis.Remove(ui) - var/Ukey = ui.ui_key - var/list/uis = open_uis[src_object_key][Ukey] // Remove it from the list of open UIs. - uis.Remove(ui) - if(!uis.len) - var/list/uiobj = open_uis[src_object_key] - uiobj.Remove(Ukey) - if(!uiobj.len) - open_uis.Remove(src_object_key) - - return 1 // Let the caller know we did it. - -/** - * private - * - * Handle client logout, by closing all their UIs. - * - * required user mob The mob which logged out. - * - * return int The number of UIs closed. - */ -/datum/controller/subsystem/tgui/proc/on_logout(mob/user) - return close_user_uis(user) - -/** - * private - * - * Handle clients switching mobs, by transferring their UIs. - * - * required user source The client's original mob. - * required user target The client's new mob. - * - * return bool If the UIs were transferred. - */ -/datum/controller/subsystem/tgui/proc/on_transfer(mob/source, mob/target) - if(!source || isnull(source.open_uis) || !istype(source.open_uis, /list) || open_uis.len == 0) - return 0 // The old mob had no open UIs. - - if(isnull(target.open_uis) || !istype(target.open_uis, /list)) - target.open_uis = list() // Create a list for the new mob if needed. - - for(var/datum/tgui/ui in source.open_uis) - ui.user = target // Inform the UIs of their new owner. - target.open_uis.Add(ui) // Transfer all the UIs. - - source.open_uis.Cut() // Clear the old list. - return 1 // Let the caller know we did it. diff --git a/code/modules/tgui/tgui.dm b/code/modules/tgui/tgui.dm index 7971a940d4..d0d5ff8ebb 100644 --- a/code/modules/tgui/tgui.dm +++ b/code/modules/tgui/tgui.dm @@ -1,7 +1,6 @@ /** - * tgui - * - * /tg/station user interface library + * Copyright (c) 2020 Aleksej Komarov + * SPDX-License-Identifier: MIT */ /** @@ -14,34 +13,26 @@ var/datum/src_object /// The title of te UI. var/title - /// The ui_key of the UI. This allows multiple UIs for one src_object. - var/ui_key /// The window_id for browse() and onclose(). - var/window_id - /// The window width. - var/width = 0 - /// The window height - var/height = 0 + var/datum/tgui_window/window + /// Key that is used for remembering the window geometry. + var/window_key + /// Deprecated: Window size. + var/window_size /// The interface (template) to be used for this UI. var/interface /// Update the UI every MC tick. var/autoupdate = TRUE /// If the UI has been initialized yet. var/initialized = FALSE - /// The data (and datastructure) used to initialize the UI. - var/list/initial_data - /// The static data used to initialize the UI. - var/list/initial_static_data - /// Holder for the json string, that is sent during the initial update - var/_initial_update + /// Time of opening the window. + var/opened_at + /// Stops further updates when close() was called. + var/closing = FALSE /// The status/visibility of the UI. var/status = UI_INTERACTIVE /// Topic state used to determine status/interactability. var/datum/ui_state/state = null - /// The parent UI. - var/datum/tgui/master_ui - /// Children of this UI. - var/list/datum/tgui/children = list() /** * public @@ -50,38 +41,25 @@ * * required user mob The mob who opened/is using the UI. * required src_object datum The object or datum which owns the UI. - * required ui_key string The ui_key of the UI. * required interface string The interface used to render the UI. * optional title string The title of the UI. - * optional width int The window width. - * optional height int The window height. - * optional master_ui datum/tgui The parent UI. - * optional state datum/ui_state The state used to determine status. + * optional ui_x int Deprecated: Window width. + * optional ui_y int Deprecated: Window height. * * return datum/tgui The requested UI. */ -/datum/tgui/New(mob/user, datum/src_object, ui_key, interface, title, width = 0, height = 0, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) +/datum/tgui/New(mob/user, datum/src_object, interface, title, ui_x, ui_y) + log_tgui(user, "new [interface] fancy [user.client.prefs.tgui_fancy]") src.user = user src.src_object = src_object - src.ui_key = ui_key - // DO NOT replace with \ref here. src_object could potentially be tagged - src.window_id = "[REF(src_object)]-[ui_key]" + src.window_key = "[REF(src_object)]-main" src.interface = interface - if(title) - src.title = sanitize(title) - if(width) - src.width = width - if(height) - src.height = height - - src.master_ui = master_ui - if(master_ui) - master_ui.children += src - src.state = state - - var/datum/asset/assets = get_asset_datum(/datum/asset/group/tgui) - assets.send(user) + src.title = title + src.state = src_object.ui_state() + // Deprecated + if(ui_x && ui_y) + src.window_size = list(ui_x, ui_y) /** * public @@ -90,85 +68,53 @@ */ /datum/tgui/proc/open() if(!user.client) - return // Bail if there is no client. - - update_status(push = FALSE) // Update the window status. + return null + if(window) + return null + process_status() if(status < UI_UPDATE) - return // Bail if we're not supposed to open. - - // Build window options - var/window_options = "can_minimize=0;auto_format=0;" - // If we have a width and height, use them. - if(width && height) - window_options += "size=[width]x[height];" - // Remove titlebar and resize handles for a fancy window - if(user.client.prefs.tgui_fancy) - window_options += "titlebar=0;can_resize=0;" + return null + window = SStgui.request_pooled_window(user) + if(!window) + return null + opened_at = world.time + window.acquire_lock(src) + if(!window.is_ready()) + window.initialize(inline_assets = list( + get_asset_datum(/datum/asset/simple/tgui), + )) else - window_options += "titlebar=1;can_resize=1;" - - // Generate page html - var/html - html = SStgui.basehtml - // Allow the src object to override the html if needed - html = src_object.ui_base_html(html) - // Replace template tokens with important UI data - // NOTE: Intentional \ref usage; tgui datums can't/shouldn't - // be tagged, so this is an effective unwrap - html = replacetextEx(html, "\[tgui:ref]", "\ref[src]") - - // Open the window. - user << browse(html, "window=[window_id];[window_options]") - - // Instruct the client to signal UI when the window is closed. - // NOTE: Intentional \ref usage; tgui datums can't/shouldn't - // be tagged, so this is an effective unwrap - winset(user, window_id, "on-close=\"uiclose \ref[src]\"") - - // Pre-fetch initial state while browser is still loading in - // another thread - if(!initial_data) { - initial_data = src_object.ui_data(user) - } - if(!initial_static_data) { - initial_static_data = src_object.ui_static_data(user) - } - _initial_update = url_encode(get_json(initial_data, initial_static_data)) - + window.send_message("ping") + window.send_asset(get_asset_datum(/datum/asset/simple/fontawesome)) + for(var/datum/asset/asset in src_object.ui_assets(user)) + window.send_asset(asset) + window.send_message("update", get_payload( + with_data = TRUE, + with_static_data = TRUE)) SStgui.on_open(src) /** * public * - * Reinitialize the UI. - * (Possibly with a new interface and/or data). + * Close the UI. * - * optional template string The name of the new interface. - * optional data list The new initial data. + * optional can_be_suspended bool */ -/datum/tgui/proc/reinitialize(interface, list/data, list/static_data) - if(interface) - src.interface = interface - if(data) - initial_data = data - if(static_data) - initial_static_data = static_data - open() - -/** - * public - * - * Close the UI, and all its children. - */ -/datum/tgui/proc/close() - user << browse(null, "window=[window_id]") // Close the window. - src_object.ui_close(user) - SStgui.on_close(src) - for(var/datum/tgui/child in children) // Loop through and close all children. - child.close() - children.Cut() +/datum/tgui/proc/close(can_be_suspended = TRUE) + if(closing) + return + closing = TRUE + // If we don't have window_id, open proc did not have the opportunity + // to finish, therefore it's safe to skip this whole block. + if(window) + // Windows you want to keep are usually blue screens of death + // and we want to keep them around, to allow user to read + // the error message properly. + window.release_lock() + window.close(can_be_suspended) + src_object.ui_close(user) + SStgui.on_close(src) state = null - master_ui = null qdel(src) /** @@ -176,187 +122,173 @@ * * Enable/disable auto-updating of the UI. * - * required state bool Enable/disable auto-updating. + * required value bool Enable/disable auto-updating. */ -/datum/tgui/proc/set_autoupdate(state = TRUE) - autoupdate = state +/datum/tgui/proc/set_autoupdate(autoupdate) + src.autoupdate = autoupdate + +/** + * public + * + * Replace current ui.state with a new one. + * + * required state datum/ui_state/state Next state + */ +/datum/tgui/proc/set_state(datum/ui_state/state) + src.state = state + +/** + * public + * + * Makes an asset available to use in tgui. + * + * required asset datum/asset + */ +/datum/tgui/proc/send_asset(datum/asset/asset) + if(!window) + CRASH("send_asset() can only be called after open().") + window.send_asset(asset) + +/** + * public + * + * Send a full update to the client (includes static data). + * + * optional custom_data list Custom data to send instead of ui_data. + * optional force bool Send an update even if UI is not interactive. + */ +/datum/tgui/proc/send_full_update(custom_data, force) + if(!user.client || !initialized || closing) + return + var/should_update_data = force || status >= UI_UPDATE + window.send_message("update", get_payload( + custom_data, + with_data = should_update_data, + with_static_data = TRUE)) + +/** + * public + * + * Send a partial update to the client (excludes static data). + * + * optional custom_data list Custom data to send instead of ui_data. + * optional force bool Send an update even if UI is not interactive. + */ +/datum/tgui/proc/send_update(custom_data, force) + if(!user.client || !initialized || closing) + return + var/should_update_data = force || status >= UI_UPDATE + window.send_message("update", get_payload( + custom_data, + with_data = should_update_data)) /** * private * * Package the data to send to the UI, as JSON. - * This includes the UI data and config_data. * - * return string The packaged JSON. + * return list */ -/datum/tgui/proc/get_json(list/data, list/static_data) +/datum/tgui/proc/get_payload(custom_data, with_data, with_static_data) var/list/json_data = list() - json_data["config"] = list( "title" = title, "status" = status, "interface" = interface, - "fancy" = user.client.prefs.tgui_fancy, - "locked" = user.client.prefs.tgui_lock, - "observer" = isobserver(user), - "window" = window_id, - // NOTE: Intentional \ref usage; tgui datums can't/shouldn't - // be tagged, so this is an effective unwrap - "ref" = "\ref[src]" + "window" = list( + "key" = window_key, + "size" = window_size, + "fancy" = user.client.prefs.tgui_fancy, + "locked" = user.client.prefs.tgui_lock + ), + "user" = list( + "name" = "[user]", + "ckey" = "[user.ckey]", + "observer" = isobserver(user) + ) ) - - if(!isnull(data)) + var/data = custom_data || with_data && src_object.ui_data(user) + if(data) json_data["data"] = data - if(!isnull(static_data)) + var/static_data = with_static_data && src_object.ui_static_data(user) + if(static_data) json_data["static_data"] = static_data - - // Send shared states if(src_object.tgui_shared_states) json_data["shared"] = src_object.tgui_shared_states - - // Generate the JSON. - var/json = json_encode(json_data) - // Strip #255/improper. - json = replacetext(json, "\proper", "") - json = replacetext(json, "\improper", "") - return json + return json_data /** * private * - * Handle clicks from the UI. - * Call the src_object's ui_act() if status is UI_INTERACTIVE. - * If the src_object's ui_act() returns 1, update all UIs attacked to it. - */ -/datum/tgui/Topic(href, href_list) - if(user != usr) - return // Something is not right here. - - var/action = href_list["action"] - var/params = href_list; params -= "action" - - switch(action) - if("tgui:initialize") - user << output(_initial_update, "[window_id].browser:update") - initialized = TRUE - if("tgui:setSharedState") - // Update the window state. - update_status(push = FALSE) - // Bail if UI is not interactive or usr calling Topic - // is not the UI user. - if(status != UI_INTERACTIVE) - return - var/key = params["key"] - var/value = params["value"] - if(!src_object.tgui_shared_states) - src_object.tgui_shared_states = list() - src_object.tgui_shared_states[key] = value - SStgui.update_uis(src_object) - if("tgui:setFancy") - var/value = text2num(params["value"]) - user.client.prefs.tgui_fancy = value - if("tgui:log") - // Force window to show frills on fatal errors - if(params["fatal"]) - winset(user, window_id, "titlebar=1;can-resize=1;size=600x600") - log_message(params["log"]) - if("tgui:link") - user << link(params["url"]) - else - // Update the window state. - update_status(push = FALSE) - // Call ui_act() on the src_object. - if(src_object.ui_act(action, params, src, state)) - // Update if the object requested it. - SStgui.update_uis(src_object) - -/** - * private - * - * Update the UI. - * Only updates the data if update is true, otherwise only updates the status. - * - * optional force bool If the UI should be forced to update. + * Run an update cycle for this UI. Called internally by SStgui + * every second or so. */ /datum/tgui/process(force = FALSE) + if(closing) + return var/datum/host = src_object.ui_host(user) - if(!src_object || !host || !user) // If the object or user died (or something else), abort. + // If the object or user died (or something else), abort. + if(!src_object || !host || !user || !window) + close(can_be_suspended = FALSE) + return + // Validate ping + if(!initialized && world.time - opened_at > TGUI_PING_TIMEOUT) + log_tgui(user, \ + "Error: Zombie window detected, killing it with fire.\n" \ + + "window_id: [window.id]\n" \ + + "opened_at: [opened_at]\n" \ + + "world.time: [world.time]") + close(can_be_suspended = FALSE) + return + // Update through a normal call to ui_interact + if(status != UI_DISABLED && (autoupdate || force)) + src_object.ui_interact(user, src) + return + // Update status only + var/needs_update = process_status() + if(status <= UI_CLOSE) close() return - - if(status && (force || autoupdate)) - update() // Update the UI if the status and update settings allow it. - else - update_status(push = TRUE) // Otherwise only update status. + if(needs_update) + window.send_message("update", get_payload()) /** * private * - * Push data to an already open UI. - * - * required data list The data to send. - * optional force bool If the update should be sent regardless of state. + * Updates the status, and returns TRUE if status has changed. */ -/datum/tgui/proc/push_data(data, static_data, force = FALSE) - // Update the window state. - update_status(push = FALSE) - // Cannot update UI if it is not set up yet. - if(!initialized) - return - // Cannot update UI, we have no visibility. - if(status <= UI_DISABLED && !force) - return - // Send the new JSON to the update() Javascript function. - user << output( - url_encode(get_json(data, static_data)), - "[window_id].browser:update") +/datum/tgui/proc/process_status() + var/prev_status = status + status = src_object.ui_status(user, state) + return prev_status != status /** * private * - * Updates the UI by interacting with the src_object again, which will hopefully - * call try_ui_update on it. - * - * optional force_open bool If force_open should be passed to ui_interact. + * Callback for handling incoming tgui messages. */ -/datum/tgui/proc/update(force_open = FALSE) - src_object.ui_interact(user, ui_key, src, force_open, master_ui, state) - -/** - * private - * - * Update the status/visibility of the UI for its user. - * - * optional push bool Push an update to the UI (an update is always sent for UI_DISABLED). - */ -/datum/tgui/proc/update_status(push = FALSE) - var/status = src_object.ui_status(user, state) - if(master_ui) - status = min(status, master_ui.status) - set_status(status, push) - if(status == UI_CLOSE) - close() - -/** - * private - * - * Set the status/visibility of the UI. - * - * required status int The status to set (UI_CLOSE/UI_DISABLED/UI_UPDATE/UI_INTERACTIVE). - * optional push bool Push an update to the UI (an update is always sent for UI_DISABLED). - */ -/datum/tgui/proc/set_status(status, push = FALSE) - // Only update if status has changed. - if(src.status != status) - if(src.status == UI_DISABLED) - src.status = status - if(push) - update() - else - src.status = status - // Update if the UI just because disabled, or a push is requested. - if(status == UI_DISABLED || push) - push_data(null, force = TRUE) - -/datum/tgui/proc/log_message(message) - log_tgui("[user] ([user.ckey]) using \"[title]\":\n[message]") +/datum/tgui/proc/on_message(type, list/payload, list/href_list) + // Pass act type messages to ui_act + if(type && copytext(type, 1, 5) == "act/") + process_status() + if(src_object.ui_act(copytext(type, 5), payload, src, state)) + SStgui.update_uis(src_object) + return FALSE + switch(type) + if("ready") + initialized = TRUE + if("pingReply") + initialized = TRUE + if("suspend") + close(can_be_suspended = TRUE) + if("close") + close(can_be_suspended = FALSE) + if("log") + if(href_list["fatal"]) + close(can_be_suspended = FALSE) + if("setSharedState") + if(status != UI_INTERACTIVE) + return + LAZYINITLIST(src_object.tgui_shared_states) + src_object.tgui_shared_states[href_list["key"]] = href_list["value"] + SStgui.update_uis(src_object) diff --git a/code/modules/tgui/tgui_window.dm b/code/modules/tgui/tgui_window.dm new file mode 100644 index 0000000000..3f271163c9 --- /dev/null +++ b/code/modules/tgui/tgui_window.dm @@ -0,0 +1,238 @@ +/** + * Copyright (c) 2020 Aleksej Komarov + * SPDX-License-Identifier: MIT + */ + +/datum/tgui_window + var/id + var/client/client + var/pooled + var/pool_index + var/status = TGUI_WINDOW_CLOSED + var/locked = FALSE + var/datum/tgui/locked_by + var/fatally_errored = FALSE + var/message_queue + var/sent_assets = list() + +/** + * public + * + * Create a new tgui window. + * + * required client /client + * required id string A unique window identifier. + */ +/datum/tgui_window/New(client/client, id, pooled = FALSE) + src.id = id + src.client = client + src.pooled = pooled + if(pooled) + client.tgui_windows[id] = src + src.pool_index = TGUI_WINDOW_INDEX(id) + +/** + * public + * + * Initializes the window with a fresh page. Puts window into the "loading" + * state. You can begin sending messages right after initializing. Messages + * will be put into the queue until the window finishes loading. + * + * optional inline_assets list List of assets to inline into the html. + */ +/datum/tgui_window/proc/initialize(inline_assets = list()) + log_tgui(client, "[id]/initialize") + if(!client) + return + status = TGUI_WINDOW_LOADING + fatally_errored = FALSE + message_queue = null + // Build window options + var/options = "file=[id].html;can_minimize=0;auto_format=0;" + // Remove titlebar and resize handles for a fancy window + if(client.prefs.tgui_fancy) + options += "titlebar=0;can_resize=0;" + else + options += "titlebar=1;can_resize=1;" + // Generate page html + var/html = SStgui.basehtml + html = replacetextEx(html, "\[tgui:windowId]", id) + // Process inline assets + var/inline_styles = "" + var/inline_scripts = "" + for(var/datum/asset/asset in inline_assets) + var/mappings = asset.get_url_mappings() + for(var/name in mappings) + var/url = mappings[name] + // Not urlencoding since asset strings are considered safe + if(copytext(name, -4) == ".css") + inline_styles += "\n" + else if(copytext(name, -3) == ".js") + inline_scripts += "\n" + asset.send() + html = replacetextEx(html, "\n", inline_styles) + html = replacetextEx(html, "\n", inline_scripts) + // Open the window + client << browse(html, "window=[id];[options]") + // Instruct the client to signal UI when the window is closed. + winset(client, id, "on-close=\"uiclose [id]\"") + +/** + * public + * + * Checks if the window is ready to receive data. + * + * return bool + */ +/datum/tgui_window/proc/is_ready() + return status == TGUI_WINDOW_READY + +/** + * public + * + * Checks if the window can be sanely suspended. + * + * return bool + */ +/datum/tgui_window/proc/can_be_suspended() + return !fatally_errored \ + && pooled \ + && pool_index > 0 \ + && pool_index <= TGUI_WINDOW_SOFT_LIMIT \ + && status == TGUI_WINDOW_READY + +/** + * public + * + * Acquire the window lock. Pool will not be able to provide this window + * to other UIs for the duration of the lock. + * + * Can be given an optional tgui datum, which will hook its on_message + * callback into the message stream. + * + * optional ui /datum/tgui + */ +/datum/tgui_window/proc/acquire_lock(datum/tgui/ui) + locked = TRUE + locked_by = ui + +/** + * Release the window lock. + */ +/datum/tgui_window/proc/release_lock() + // Clean up assets sent by tgui datum which requested the lock + if(locked) + sent_assets = list() + locked = FALSE + locked_by = null + +/** + * public + * + * Close the UI. + * + * optional can_be_suspended bool + */ +/datum/tgui_window/proc/close(can_be_suspended = TRUE) + if(!client) + return + if(can_be_suspended && can_be_suspended()) + log_tgui(client, "[id]/close: suspending") + status = TGUI_WINDOW_READY + send_message("suspend") + return + log_tgui(client, "[id]/close") + release_lock() + status = TGUI_WINDOW_CLOSED + message_queue = null + // Do not close the window to give user some time + // to read the error message. + if(!fatally_errored) + client << browse(null, "window=[id]") + +/** + * public + * + * Sends a message to tgui window. + * + * required type string Message type + * required payload list Message payload + * optional force bool Send regardless of the ready status. + */ +/datum/tgui_window/proc/send_message(type, list/payload, force) + if(!client) + return + var/message = json_encode(list( + "type" = type, + "payload" = payload, + )) + // Strip #255/improper. + message = replacetext(message, "\proper", "") + message = replacetext(message, "\improper", "") + // Pack for sending via output() + message = url_encode(message) + // Place into queue if window is still loading + if(!force && status != TGUI_WINDOW_READY) + if(!message_queue) + message_queue = list() + message_queue += list(message) + return + client << output(message, "[id].browser:update") + +/** + * public + * + * Makes an asset available to use in tgui. + * + * required asset datum/asset + */ +/datum/tgui_window/proc/send_asset(datum/asset/asset) + if(!client || !asset) + return + if(istype(asset, /datum/asset/spritesheet)) + var/datum/asset/spritesheet/spritesheet = asset + send_message("asset/stylesheet", spritesheet.css_filename()) + send_message("asset/mappings", asset.get_url_mappings()) + sent_assets += list(asset) + asset.send(client) + +/** + * private + * + * Sends queued messages if the queue wasn't empty. + */ +/datum/tgui_window/proc/flush_message_queue() + if(!client || !message_queue) + return + for(var/message in message_queue) + client << output(message, "[id].browser:update") + message_queue = null + +/** + * private + * + * Callback for handling incoming tgui messages. + */ +/datum/tgui_window/proc/on_message(type, list/payload, list/href_list) + switch(type) + if("ready") + // Status can be READY if user has refreshed the window. + if(status == TGUI_WINDOW_READY) + // Resend the assets + for(var/asset in sent_assets) + send_asset(asset) + status = TGUI_WINDOW_READY + if("log") + if(href_list["fatal"]) + fatally_errored = TRUE + // Pass message to UI that requested the lock + if(locked && locked_by) + locked_by.on_message(type, payload, href_list) + flush_message_queue() + return + // If not locked, handle these message types + switch(type) + if("suspend") + close(can_be_suspended = TRUE) + if("close") + close(can_be_suspended = FALSE) diff --git a/code/modules/uplink/uplink_items/uplink_bundles.dm b/code/modules/uplink/uplink_items/uplink_bundles.dm index fbeaee8939..1b7909a50d 100644 --- a/code/modules/uplink/uplink_items/uplink_bundles.dm +++ b/code/modules/uplink/uplink_items/uplink_bundles.dm @@ -173,8 +173,7 @@ /datum/uplink_item/bundles_TC/reroll/purchase(mob/user, datum/component/uplink/U) var/datum/antagonist/traitor/T = user?.mind?.has_antag_datum(/datum/antagonist/traitor) if(istype(T)) - var/new_traitor_kind = get_random_traitor_kind(list(T.traitor_kind.type)) - T.set_traitor_kind(new_traitor_kind) + T.set_traitor_kind(/datum/traitor_class/human/subterfuge) else to_chat(user,"Invalid user for contract renegotiation.") diff --git a/code/modules/uplink/uplink_items/uplink_clothing.dm b/code/modules/uplink/uplink_items/uplink_clothing.dm index 014e0452b5..c26a9ae1f0 100644 --- a/code/modules/uplink/uplink_items/uplink_clothing.dm +++ b/code/modules/uplink/uplink_items/uplink_clothing.dm @@ -97,3 +97,9 @@ item = /obj/item/clothing/gloves/tackler/combat/insulated include_modes = list(/datum/game_mode/nuclear, /datum/game_mode/nuclear/clown_ops) cost = 2 + +/datum/uplink_item/device_tools/syndicate_eyepatch + name = "Mechanical Eyepatch" + desc = "An eyepatch that connects itself to your eye socket, enhancing your shooting to an impossible degree, allowing your bullets to ricochet far more often than usual." + item = /obj/item/clothing/glasses/eyepatch/syndicate + cost = 8 diff --git a/code/modules/uplink/uplink_items/uplink_stealthdevices.dm b/code/modules/uplink/uplink_items/uplink_stealthdevices.dm index f1c27c640b..28d02cf79b 100644 --- a/code/modules/uplink/uplink_items/uplink_stealthdevices.dm +++ b/code/modules/uplink/uplink_items/uplink_stealthdevices.dm @@ -112,13 +112,13 @@ name = "Radio Jammer" desc = "This device will disrupt any nearby outgoing radio communication when activated. Does not affect binary chat." item = /obj/item/jammer - cost = 5 + cost = 2 /datum/uplink_item/stealthy_tools/smugglersatchel name = "Smuggler's Satchel" desc = "This satchel is thin enough to be hidden in the gap between plating and tiling; great for stashing \ your stolen goods. Comes with a crowbar and a floor tile inside. Properly hidden satchels have been \ - known to survive intact even beyond the current shift. " + known to survive intact even beyond the current shift, but this is just a myth. " item = /obj/item/storage/backpack/satchel/flat - cost = 2 + cost = 1 surplus = 30 diff --git a/code/modules/vehicles/_vehicle.dm b/code/modules/vehicles/_vehicle.dm index ac7fa879f4..12e9f365d0 100644 --- a/code/modules/vehicles/_vehicle.dm +++ b/code/modules/vehicles/_vehicle.dm @@ -18,6 +18,7 @@ var/canmove = TRUE var/emulate_door_bumps = TRUE //when bumping a door try to make occupants bump them to open them. var/default_driver_move = TRUE //handle driver movement instead of letting something else do it like riding datums. + var/enclosed = FALSE // is the rider protected from bullets? assume no var/list/autogrant_actions_passenger //plain list of typepaths var/list/autogrant_actions_controller //assoc list "[bitflag]" = list(typepaths) var/list/mob/occupant_actions //assoc list mob = list(type = action datum assigned to mob) @@ -166,3 +167,9 @@ if(trailer && .) var/dir_to_move = get_dir(trailer.loc, newloc) step(trailer, dir_to_move) + +/obj/vehicle/bullet_act(obj/item/projectile/Proj) //wrapper + if (!enclosed && length(occupants) && !Proj.force_hit && (Proj.def_zone == BODY_ZONE_HEAD || Proj.def_zone == BODY_ZONE_CHEST)) //allows bullets to hit drivers + occupants[1].bullet_act(Proj) // driver dinkage + return BULLET_ACT_HIT + . = ..() diff --git a/code/modules/vehicles/sealed.dm b/code/modules/vehicles/sealed.dm index edaab8b982..28f6b1cca8 100644 --- a/code/modules/vehicles/sealed.dm +++ b/code/modules/vehicles/sealed.dm @@ -1,4 +1,5 @@ /obj/vehicle/sealed + enclosed = TRUE // you're in a sealed vehicle dont get dinked idiot var/enter_delay = 20 flags_1 = BLOCK_FACE_ATOM_1 diff --git a/code/modules/vending/_vending.dm b/code/modules/vending/_vending.dm index a42fe97cb4..a115300085 100644 --- a/code/modules/vending/_vending.dm +++ b/code/modules/vending/_vending.dm @@ -501,10 +501,10 @@ GLOBAL_LIST_EMPTY(vending_products) C.bleed(150) var/obj/item/bodypart/l_leg/l = C.get_bodypart(BODY_ZONE_L_LEG) if(l) - l.receive_damage(brute=200) + l.receive_damage(brute=200, updating_health=TRUE) var/obj/item/bodypart/r_leg/r = C.get_bodypart(BODY_ZONE_R_LEG) if(r) - r.receive_damage(brute=200) + r.receive_damage(brute=200, updating_health=TRUE) if(l || r) C.visible_message("[C]'s legs shatter with a sickening crunch!", \ "Your legs shatter with a sickening crunch!") @@ -672,21 +672,21 @@ GLOBAL_LIST_EMPTY(vending_products) return return ..() -/obj/machinery/vending/ui_base_html(html) - var/datum/asset/spritesheet/assets = get_asset_datum(/datum/asset/spritesheet/vending) - . = replacetext(html, "", assets.css_tag()) +/obj/machinery/vending/ui_assets(mob/user) + return list( + get_asset_datum(/datum/asset/spritesheet/vending), + ) -/obj/machinery/vending/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) +/obj/machinery/vending/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) if(!ui) - var/datum/asset/assets = get_asset_datum(/datum/asset/spritesheet/vending) - assets.send(user) - ui = new(user, src, ui_key, "Vending", ui_key, 450, 600, master_ui, state) + ui = new(user, src, "Vending") ui.open() /obj/machinery/vending/ui_static_data(mob/user) . = list() .["onstation"] = onstation + .["department"] = payment_department .["product_records"] = list() for (var/datum/data/vending_product/R in product_records) var/list/data = list( @@ -713,7 +713,7 @@ GLOBAL_LIST_EMPTY(vending_products) var/list/data = list( path = replacetext(replacetext("[R.product_path]", "/obj/item/", ""), "/", "-"), name = R.name, - price = R.custom_price || default_price, + price = R.custom_premium_price || extra_price, //may cause breakage. please note max_amount = R.max_amount, ref = REF(R), premium = TRUE @@ -722,28 +722,24 @@ GLOBAL_LIST_EMPTY(vending_products) /obj/machinery/vending/ui_data(mob/user) . = list() - var/obj/item/card/id/C = user.get_idcard(TRUE) - .["cost_mult"] = 1 - .["cost_text"] = "" - if(C && C.registered_account) - .["user"] = list() - .["user"]["name"] = C.registered_account.account_holder - .["user"]["cash"] = C.registered_account.account_balance - if(C.registered_account.account_job) - .["user"]["job"] = C.registered_account.account_job.title - else - .["user"]["job"] = "No Job" - var/cost_mult = get_best_discount(C) - if(cost_mult != 1) - .["cost_mult"] = cost_mult - if(cost_mult < 1) - .["cost_text"] = " ([(1 - cost_mult) * 100]% OFF)" + var/mob/living/carbon/human/H + var/obj/item/card/id/C + if(ishuman(user)) + H = user + C = H.get_idcard(TRUE) + if(C?.registered_account) + .["user"] = list() + .["user"]["name"] = C.registered_account.account_holder + .["user"]["cash"] = C.registered_account.account_balance + if(C.registered_account.account_job) + .["user"]["job"] = C.registered_account.account_job.title + .["user"]["department"] = C.registered_account.account_job.paycheck_department else - .["cost_text"] = " ([(cost_mult - 1) * 100]% EXTRA)" + .["user"]["job"] = "No Job" + .["user"]["department"] = "No Department" .["stock"] = list() for (var/datum/data/vending_product/R in product_records + coin_records + hidden_records) .["stock"][R.name] = R.amount - . .["extended_inventory"] = extended_inventory /obj/machinery/vending/ui_act(action, params) @@ -766,7 +762,9 @@ GLOBAL_LIST_EMPTY(vending_products) if(!R || !istype(R) || !R.product_path) vend_ready = TRUE return - var/price_to_use = R.custom_price || default_price + var/price_to_use = default_price + if(R.custom_price) + price_to_use = R.custom_price if(R in hidden_records) if(!extended_inventory) vend_ready = TRUE @@ -780,8 +778,10 @@ GLOBAL_LIST_EMPTY(vending_products) flick(icon_deny,src) vend_ready = TRUE return - if(onstation && price_to_use >= 0) - var/obj/item/card/id/C = usr.get_idcard(TRUE) + if(onstation && ishuman(usr)) + var/mob/living/carbon/human/H = usr + var/obj/item/card/id/C = H.get_idcard(TRUE) + if(!C) say("No card found.") flick(icon_deny,src) @@ -792,11 +792,20 @@ GLOBAL_LIST_EMPTY(vending_products) flick(icon_deny,src) vend_ready = TRUE return + // else if(age_restrictions && R.age_restricted && (!C.registered_age || C.registered_age < AGE_MINOR)) + // say("You are not of legal age to purchase [R.name].") + // if(!(usr in GLOB.narcd_underages)) + // Radio.set_frequency(FREQ_SECURITY) + // Radio.talk_into(src, "SECURITY ALERT: Underaged crewmember [H] recorded attempting to purchase [R.name] in [get_area(src)]. Please watch for substance abuse.", FREQ_SECURITY) + // GLOB.narcd_underages += H + // flick(icon_deny,src) + // vend_ready = TRUE + // return var/datum/bank_account/account = C.registered_account - if(coin_records.Find(R)) - price_to_use = R.custom_premium_price || extra_price - else if(!hidden_records.Find(R)) - price_to_use = round(price_to_use * get_best_discount(C)) + if(account.account_job && account.account_job.paycheck_department == payment_department) + price_to_use = 0 + if(coin_records.Find(R) || hidden_records.Find(R)) + price_to_use = R.custom_premium_price ? R.custom_premium_price : extra_price if(price_to_use && !account.adjust_money(-price_to_use)) say("You do not possess the funds to purchase [R.name].") flick(icon_deny,src) @@ -805,6 +814,8 @@ GLOBAL_LIST_EMPTY(vending_products) var/datum/bank_account/D = SSeconomy.get_dep_account(payment_department) if(D) D.adjust_money(price_to_use) + SSblackbox.record_feedback("amount", "vending_spent", price_to_use) + //log_econ("[price_to_use] credits were inserted into [src] by [D.account_holder] to buy [R].") if(last_shopper != usr || purchase_message_cooldown < world.time) say("Thank you for shopping with [src]!") purchase_message_cooldown = world.time + 5 SECONDS diff --git a/code/modules/vending/kinkmate.dm b/code/modules/vending/kinkmate.dm index df8a4e8a96..dc4f4e9273 100644 --- a/code/modules/vending/kinkmate.dm +++ b/code/modules/vending/kinkmate.dm @@ -36,13 +36,10 @@ /obj/item/clothing/under/misc/keyholesweater = 2, /obj/item/clothing/under/misc/stripper/mankini = 2, /obj/item/clothing/under/costume/jabroni = 2, - /obj/item/dildo/flared/huge = 3, - /obj/item/reagent_containers/glass/bottle/crocin = 5, - /obj/item/reagent_containers/glass/bottle/camphor = 5 + /obj/item/dildo/flared/huge = 3 ) premium = list( /obj/item/clothing/accessory/skullcodpiece/fake = 3, - /obj/item/reagent_containers/glass/bottle/hexacrocin = 10, /obj/item/clothing/under/pants/chaps = 5 ) refill_canister = /obj/item/vending_refill/kink diff --git a/code/modules/vending/medical.dm b/code/modules/vending/medical.dm index 34de3b490c..795d35adc4 100644 --- a/code/modules/vending/medical.dm +++ b/code/modules/vending/medical.dm @@ -46,7 +46,8 @@ /obj/item/wrench/medical = 1, /obj/item/storage/belt/medolier/full = 2, /obj/item/gun/syringe/dart = 2, - /obj/item/storage/briefcase/medical = 2) + /obj/item/storage/briefcase/medical = 2, + /obj/item/plunger/reinforced = 2) armor = list("melee" = 100, "bullet" = 100, "laser" = 100, "energy" = 100, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 50) resistance_flags = FIRE_PROOF diff --git a/code/modules/vending/snack.dm b/code/modules/vending/snack.dm index 7aef2b627c..ff8fd46676 100644 --- a/code/modules/vending/snack.dm +++ b/code/modules/vending/snack.dm @@ -12,7 +12,8 @@ /obj/item/reagent_containers/food/snacks/no_raisin = 5, /obj/item/reagent_containers/food/snacks/spacetwinkie = 5, /obj/item/reagent_containers/food/snacks/cheesiehonkers = 5, - /obj/item/reagent_containers/food/snacks/cornchips = 5) + /obj/item/reagent_containers/food/snacks/cornchips = 5, + /obj/item/reagent_containers/food/snacks/energybar = 6) contraband = list( /obj/item/reagent_containers/food/snacks/cracker = 10, /obj/item/reagent_containers/food/snacks/honeybar = 5, diff --git a/code/modules/zombie/items.dm b/code/modules/zombie/items.dm index 3a7cd4b03f..2cb3a83257 100644 --- a/code/modules/zombie/items.dm +++ b/code/modules/zombie/items.dm @@ -81,3 +81,14 @@ user.updatehealth() user.adjustOrganLoss(ORGAN_SLOT_BRAIN, -hp_gained) // Zom Bee gibbers "BRAAAAISNSs!1!" user.adjust_nutrition(hp_gained, NUTRITION_LEVEL_FULL) + +/obj/item/paper/guides/antag/romerol_instructions + info = "How to do necromancy with chemicals:
\ +
    \ +
  • Use a dropper or syringe (provided) to inject the Romerol (provided) into a target (not provided)
  • \ +
  • Wait for said target to die, or speed the process up by doing it yourself
  • \ +
  • Run away from the target, as they will be hostile when rising back up
  • \ +
  • Optionally: Inject chemical into foods and drinks to further spread possible infection
  • \ +
  • ???
  • \ +
  • Complete assigned objectives amidst the chaos
  • \ +
" \ No newline at end of file diff --git a/config/game_options.txt b/config/game_options.txt index 405ec0405a..a5b0d0b8c4 100644 --- a/config/game_options.txt +++ b/config/game_options.txt @@ -116,6 +116,7 @@ CONTINUOUS CHANGELING CONTINUOUS WIZARD #CONTINUOUS MONKEY CONTINUOUS BLOODSUCKER +CONTINUOUS HERESY ##Note: do not toggle continuous off for these modes, as they have no antagonists and would thus end immediately! @@ -445,6 +446,7 @@ ROUNDSTART_RACES plasmaman #ROUNDSTART_RACES shadow ROUNDSTART_RACES felinid ROUNDSTART_RACES dwarf +ROUNDSTART_RACES ethereal ## Races that are better than humans in some ways, but worse in others #ROUNDSTART_RACES jelly diff --git a/config/spaceRuinBlacklist.txt b/config/spaceRuinBlacklist.txt index 90682f5bad..969e4135f6 100644 --- a/config/spaceRuinBlacklist.txt +++ b/config/spaceRuinBlacklist.txt @@ -52,3 +52,4 @@ #_maps/RandomRuins/SpaceRuins/arcade.dmm #_maps/RandomRuins/SpaceRuins/spacehermit.dmm #_maps/RandomRuins/SpaceRuins/advancedlab.dmm +#_maps/RandomRuins/SpaceRuins/spacediner.dmm diff --git a/html/changelog.html b/html/changelog.html index 2e0891ed7f..fd590f4673 100644 --- a/html/changelog.html +++ b/html/changelog.html @@ -50,6 +50,407 @@ -->
+

23 August 2020

+

DeltaFire15 updated:

+
    +
  • silicons and clockies can now access APCs properly
  • +
+

EmeraldSundisk updated:

+
    +
  • Medbay now has a smartfridge for organ storage
  • +
  • Slight enhancements to the station's electrical wiring layout
  • +
  • Very small library renovation
  • +
  • Exterior airlocks have been given proper air systems for safety's sake
  • +
+

Ghommie updated:

+
    +
  • Stops shielded hardsuits from slowly turning the wearer into a big glowing ball of stacked energy shield overlays.
  • +
  • the shielding overlay is merely visual as result. Aim your clicks.
  • +
+

Ludox235 updated:

+
    +
  • no more 10 pop xenos (25pop now)
  • +
+

MrJWhit updated:

+
    +
  • Increases the majority of airlocks by 1 tile.
  • +
  • Minor adjustments to the TEG engine.
  • +
+

Putnam3145 updated:

+
    +
  • Simplemobs no longer count in dynamic.
  • +
  • "Story" storyteller no longer starts at a ludicrously low threat, always.
  • +
  • Blob threat now scales with coverage.
  • +
  • One person with their pref on no longer overpowers 40 people who might not even know there is one.
  • +
  • Negative-weight rulesets are no longer put into the list.
  • +
+

kiwedespars updated:

+
    +
  • removed durathread from armwraps recipe.
  • +
+

lolman360 updated:

+
    +
  • breath mask balaclava
  • +
+

timothyteakettle updated:

+
    +
  • lizards are now a recommended species for mam snouts
  • +
+

zeroisthebiggay updated:

+
    +
  • new sprites for the temporal katana
  • +
  • suiciding with the temporal katana omae wa mou shinderius you into the shadow realm
  • +
  • twilight isnt earrape
  • +
+ +

22 August 2020

+

Time-Green (copypasta'd by lolman360) updated:

+
    +
  • plumbing
  • +
  • automatic hydro trays
  • +
+ +

21 August 2020

+

LetterN updated:

+
    +
  • Updates and adds some of the tips
  • +
+

Putnam3145 updated:

+
    +
  • added reftracking as a compile flag
  • +
+

SmArtKar updated:

+
    +
  • RSD limitation is now 500 tiles
  • +
  • Fixed broken RSD sprites
  • +
  • Removed that shuttle limit
  • +
+

timothyteakettle updated:

+
    +
  • two snouts can once again be chosen in customization
  • +
  • lizard snouts work again
  • +
+ +

20 August 2020

+

DeltaFire15 updated:

+
    +
  • The cooking oil damage formula is no longer scuffed.
  • +
  • Changed the clockie help-link to lead to our own wiki.
  • +
+

Fikou updated:

+
    +
  • admins can now do html in ahelps properly
  • +
+

Hatterhat updated:

+
    +
  • Pirate threats are now announced as "business propositions", and their arrivals are now also announced properly.
  • +
+

tiramisuapimancer updated:

+
    +
  • Ethereal hair is now their body color instead of accidentally white
  • +
+ +

18 August 2020

+

DeltaFire15 updated:

+
    +
  • kindle cast time: 15ds -> 25ds
  • +
  • Moved the Belligerent Scripture to where it should be in the code
  • +
+

Detective-Google updated:

+
    +
  • glass floors
  • +
  • uncrowbarrable plasma floors tweak:disco inferno's plasma floors can no longer be crowbarred.
  • +
  • ghost cafe has funky fresh art
  • +
  • you can actually remove glass floors now
  • +
  • get_equipped_items is hopefully less gross
  • +
  • plasma cutters are no longer gay
  • +
+

Hatterhat updated:

+
    +
  • Slaughter demons (and laughter demons, being a subtype) are MOB_SIZE_LARGE, with one of the more immediate effects being able to mark them with a crusher and backstab them.
  • +
  • The funny blyat men have stumbled upon another surplus of Mosin-Nagants and are starting to pack them into crates again.
  • +
  • Vehicle riders can now, by default, get shot in the face and/or chest.
  • +
  • Adminspawn only .357 DumDum rounds! Because sometimes the other guy just really needs to hurt.
  • +
  • Bluespace beakers now have a chemical window through the side that shows chemical overlays.
  • +
  • Plant DNA manipulators now let you chuck things over them. Or they WOULD, if LETPASSTHROW worked half a damn.
  • +
+

LetterN updated:

+
    +
  • uplink implant states
  • +
  • tweaks how role assigning works
  • +
+

MrJWhit updated:

+
    +
  • Gives ashwalkers nightvision
  • +
  • Makes tesla blast people, not the environment, to save the server.
  • +
+

TheObserver-sys updated:

+
    +
  • moves Garlic sprites from growing.dmi to growing_vegetable.dmi
  • +
  • Removes the unused Electric Lime mutation, it just takes up space with no actual function nor sprites.
  • +
  • Gives Catnip growing sprites
  • +
  • Removes redundant images in growing.dmi
  • +
+

kiwedespars updated:

+
    +
  • 10 force to a fucking rubber cock.
  • +
+

lolman360 updated:

+
    +
  • shotgun stripper clip nerf. ammoboxes can now accept a load_delay that happens when they attack a magazine, internal or external.
  • +
+

ported from tg updated:

+
    +
  • bronze airlocks and windows can now be built
  • +
  • i also tweaked bronze flooring to be cheaper.
  • +
+

silicons updated:

+
    +
  • stamina draining projectiles without stamina for their primary damage type now has their stamina damage taken into account for shield blocking, rather than the block being done for free for that.
  • +
+

timothyteakettle updated:

+
    +
  • snowflake code tidyup
  • +
  • snowflake code for mutant bodypart selection has been rewritten to be ~14x shorter
  • +
  • meat type and horns can now be selected by any species
  • +
+ +

17 August 2020

+

DeltaFire15 updated:

+
    +
  • Cogscarabs are no longer always Pogscarabs
  • +
+

Strazyplus updated:

+
    +
  • Added drakeborgs
  • +
  • Added drakeplushies
  • +
  • added drakeborg sprites
  • +
  • added drakeplushie sprites
  • +
  • changed some code - added drakeplushies to backpack loadout Removed duplicate voresleeper belly sprites from engdrake & jantidrake. [CC BY-NC-SA 3.0](https://creativecommons.org/licenses/by-nc-sa/3.0/)
  • +
  • Added CC BY-NC-SA 3.0 license details to icon/mob/cyborg moved drakeborg.dmi to icon/mob/cyborg
  • +
+ +

16 August 2020

+

kiwedespars updated:

+
    +
  • nerfed hypereut chaplain weapon.
  • +
  • 50% rng blockchance -> 0%
  • +
  • parry made much worse because it's an actual weapon and a roundstart one at that.
  • +
+

zeroisthebiggay updated:

+
    +
  • tips
  • +
+ +

15 August 2020

+

LetterN updated:

+
    +
  • missing anomaly core icons
  • +
  • wrong state. blame the tg vertion i copied
  • +
+

silicons updated:

+
    +
  • the 8 rotation limit from clockwork chairs has been removed. please don't abuse this.
  • +
  • ethereals can now wear underwear
  • +
+ +

14 August 2020

+

silicons updated:

+
    +
  • abductors can buy things
  • +
+ +

13 August 2020

+

LetterN updated:

+
    +
  • Removes fermisleepers and reverts them to tg ones
  • +
+ +

12 August 2020

+

DeltaFire15 updated:

+
    +
  • hellgun single-pack classification: goodies -> armory
  • +
+

Detective-Google updated:

+
    +
  • hallway table hallway table
  • +
+

Hatterhat updated:

+
    +
  • The temporal katana is now slightly more worthy of the 2 spell point cost, with a smaller, antimagic respecting timestop, less force, and no random blockchance. Society has progressed past the need for blockchance.
  • +
+

LetterN updated:

+
    +
  • Mafia Component
  • +
  • Fixed missing icons and handtele
  • +
+

Putnam3145 updated:

+
    +
  • a whole lot of jank regarding funny part sprite display.
  • +
+

Toriate updated:

+
    +
  • Opossums have migrated into the maintenance tunnels! Seek them out at your own peril!
  • +
+

ancientpower updated:

+
    +
  • Doors added to the west side of box medbay to make things a bit more manageable.
  • +
+

kappa-sama updated:

+
    +
  • smuggler satchel cost 2->1
  • +
  • radio jammer cost 5->2
  • +
  • smuggler satchel uplink description now implies that persistence is disabled
  • +
+

lolman360 updated:

+
    +
  • renameable necklace (accessory, attaches to suit) and ring (glove slot.)
  • +
  • custom rename is now 2048 characters? i think it's characters.
  • +
+

silicons updated:

+
    +
  • You can now use anything as an emoji by doing :/obj/item/path/to/item:. This works for any /atom or subtype.
  • +
+

timothyteakettle updated:

+
    +
  • syndicate agents now have access to mechanical aim enhancers which allow them to aim bullets to bounce off walls
  • +
  • ricochets work properly now for the bullets that support them
  • +
+

zeroisthebiggay updated:

+
    +
  • hair and some sechuds
  • +
  • ce hardsuit radproofing
  • +
+ +

11 August 2020

+

Hatterhat updated:

+
    +
  • PDA uplinks can now steal from pens. Properly. Just make sure to have a pen in your PDA, first.
  • +
+

kappa-sama updated:

+
    +
  • tracer no longer gives you full stamheals per use
  • +
+

zeroisthebiggay updated:

+
    +
  • volaju two
  • +
+ +

10 August 2020

+

Hatterhat updated:

+
    +
  • Parry counterattack text now shows up.
  • +
  • Sterilized gauze is now better at stopping bleeding, and applies slightly faster. Very slightly faster.
  • +
  • Ointment and sutures now hold more in a stack (12 and 15, respectively).
  • +
  • Sterilized gauze can now be made by just pouring 10u sterilizine onto standard medical gauze, instead of having to craft it. Why you had to craft it, I will honestly never know.
  • +
  • Proto-kinetic glaives are more expensive, stagger/cooldown on failed parries increased slightly, perfect parries required for counterattack.
  • +
  • New item: Temporal Katana. 2 points for wizards, timestops upon successful parry, bokken quickparry stats (100 force on melee counter!).
  • +
  • Also you can *smirk. This has no mechanical effect, other than being smug.
  • +
+

KeRSedChaplain updated:

+
    +
  • Added a guide for romerol usage
  • +
  • made infectious zombies not enter softcrit and take no stamina damage
  • +
+

LetterN updated:

+
    +
  • clocktheme color
  • +
  • Ports TGUI-4
  • +
+

Lynxless updated:

+
    +
  • Ports TG #51879
  • +
+

Owai-Seek updated:

+
    +
  • Meatballs now spawn raw from food processors.
  • +
+

Putnam3145 updated:

+
    +
  • Ethereals
  • +
  • (Hexa)crocin
  • +
  • (Hexa)camphor
  • +
  • Tweaked wording for marking tickets IC issue.
  • +
  • Rerolling your traitor goals will ONLY give you "proper" objectives.
  • +
+

Seris02 updated:

+
    +
  • borgs being able to select and use a module when it's too damaged
  • +
+

Sishen1542 updated:

+
    +
  • gave chairs active block/parry in exchange for removal of block_chance
  • +
  • replaces box whiteship tbaton with truncheon
  • +
+

kappa-sama updated:

+
    +
  • made the Dirty Magazines crate cost 4000 instead of 12000 credits
  • +
  • MODS I SPILLED MU JUICE HEJPPHRLP HELPJ JLEP HELP
  • +
+

silicons updated:

+
    +
  • player made areas are no longer valid for malf hacking
  • +
  • default space levels is 4 again.
  • +
  • rats now swarm instead of stacking on one spot.
  • +
  • getting hit by an explosion will now barely hard knockdown, but will leave you somewhat winded.
  • +
+

timothyteakettle updated:

+
    +
  • speech verbs copy through dna copying now
  • +
+ +

09 August 2020

+

Hatterhat updated:

+
    +
  • Proto-kinetic glaives (not crushers) can parry now.
  • +
+

MrJWhit updated:

+
    +
  • Adds a second shutter on the top of the hop line
  • +
+

silicons updated:

+
    +
  • immovable rods no longer drop down chasms
  • +
  • fun removal: squeaking objects now have an 1 second cooldown between squeaks, and will have a 33% chance of interrupting any other squeaking object when Cross()ing, meaning no more ear-fuck conveyor belts.
  • +
+ +

08 August 2020

+

DeltaFire15 updated:

+
    +
  • Roundstart cultists now start with a replica fabricator - no brass though, make your own.
  • +
  • Kindle cast time: 10 > 15, mute after stun end: 2 > 5, slur after mute end: 3 > 5
  • +
  • The ratvarian spear no longer adds negative vitality under very specific circumstances.
  • +
  • The Ratvarian Spear can parry now! Short parries with low leeway, but low cooldown.
  • +
  • The brass claw, a implant-based weapon which gains combo on consecutive hits against the same target.
  • +
  • The sigil of rites, a sigil used to perform various rites with a cost of power and materials
  • +
  • The Rite of Advancement: Used to add a organ or cyberimplant to a clockie without need for surgery.
  • +
  • The Rite of Woundmending: Used to heal all wounds on another cultist, causing toxins damage in return.
  • +
  • The Rite of the Claw: Used to summon a brass claw implant. Maximum of 4 uses per round.
  • +
+

Hatterhat updated:

+
    +
  • You can now buy a toolbox's worth of Mosin-Nagant ammo for a fairly discounted price.
  • +
  • Revolvers from the dedicated kit now have reskinning capabilities.
  • +
  • You can now actually buy the riflery primer, which lets you pump shotguns and work the Mosin's bolt faster.
  • +
  • Bulldog slug magazines now have a unique sprite.
  • +
+

Ludox235 updated:

+
    +
  • Removed an abductee objective that told you to remove all oxygen.
  • +
  • Added a new abductee objective to replace the removed one.
  • +
+

Sishen1542 updated:

+
    +
  • 🅱ï¸oneless
  • +
  • squishy slime emotes
  • +
+

timothyteakettle updated:

+
    +
  • heparin makes you bleed half as much now
  • +
  • cuts make you bleed 25% less now
  • +
  • more items in the loadout and loadout has subcategories now for easier searching
  • +
+

07 August 2020

dapnee updated:

    @@ -1067,271 +1468,6 @@
    • Adds IV bags.
    - -

    21 June 2020

    -

    kevinz000 updated:

    -
      -
    • calculations for punch hit chance has been drastically buffed in favor of the attacker.
    • -
    - -

    20 June 2020

    -

    LetterN updated:

    -
      -
    • Asset cache from tg
    • -
    • Made the map viewer not look bad
    • -
    • Admin matrix right-bracket
    • -
    -

    bunny232 updated:

    -
      -
    • Removed unsavory things from the vent clog event
    • -
    - -

    19 June 2020

    -

    Bhijn updated:

    -
      -
    • Atmos can no longer become completely bricked
    • -
    -

    Funce updated:

    -
      -
    • Square root circuit should now actually work.
    • -
    -

    SmArtKar updated:

    -
      -
    • Fixed my runtimes
    • -
    -

    TheSpaghetti updated:

    -
      -
    • more insectoid insects
    • -
    -

    kevinz000 updated:

    -
      -
    • bay/polaris style say_emphasis has been added. You can now |italicize| _underline_ and +bold+ your messages.
    • -
    -

    timothyteakettle updated:

    -
      -
    • Adds the brain trauma event, where one player gets a random brain trauma!
    • -
    • Adds the wisdom cow event, where the wisdom cow appears on the station!
    • -
    • Adds the fake virus event, where people get fake virus symptoms.
    • -
    • Adds the stray cargo pod event, where a cargo pod crashes into the station.
    • -
    • Adds the fugitives event, where fugitives are loose on the station, and it's the hunters jobs to capture them.
    • -
    - -

    18 June 2020

    -

    Detective-Google updated:

    -
      -
    • cog is now less the suck
    • -
    • couple little derpy bits
    • -
    • malf disk and illegal tech disk moved from ashwalker base (guaranteed) to tendrils (chance based)
    • -
    -

    SmArtKar updated:

    -
      -
    • Ported shuttles from beestation
    • -
    -

    timothyteakettle updated:

    -
      -
    • embeds got reworked, sticky tape was added, more bullets that ricochet also added
    • -
    • medbots can now be tipped over
    • -
    • added more medbot sounds
    • -
    - -

    17 June 2020

    -

    SmArtKar updated:

    -
      -
    • New ID icons
    • -
    • Sutures and Meshes
    • -
    -

    Trilbyspaceclone updated:

    -
      -
    • Gin export takes gin now
    • -
    - -

    16 June 2020

    -

    Ghommie updated:

    -
      -
    • You can't blink nor use LOOC/AOOC as a petrified statue anymore.
    • -
    -

    Trilbyspaceclone updated:

    -
      -
    • BEPIS decal painter has been moved to venders, replacing it being the flashdark
    • -
    -

    kevinz000 updated:

    -
      -
    • projectile ricochets now use a less hilariously terrible way of being handled and should be easier to w
    • -
    • projectile runtime/ricocheting
    • -
    • Lobotomy no longer has a 50% chance of giving you a nigh-unremovable trauma, but does 50 brain damage even on success. On failure, it will give you a lobotomy-class trauma.
    • -
    • spinesnapping from tackling now only gives a lobotomy class trauma instead of magic.
    • -
    -

    timothyteakettle updated:

    -
      -
    • Food carts now function as intended, allowing the pouring and mixing of drinks.
    • -
    • slimes can now change their color using alter form
    • -
    - -

    15 June 2020

    -

    Anturk, kevinz000 updated:

    -
      -
    • VV now properly allows access to datums in associative lists
    • -
    • SDQL2 printout has been upgraded for the 5th time.
    • -
    -

    kevinz000 updated:

    -
      -
    • plushies now work. credits to timothytea.
    • -
    • You can now tape knives to cleanbots
    • -
    -

    kevinz000 (port from VOREStation) updated:

    -
      -
    • Ported zoomba skins for cyborgs.
    • -
    - -

    14 June 2020

    -

    Bhijn updated:

    -
      -
    • raw HTML can no longer be used in flavortext
    • -
    • Added Lesbian Visibility Day (April 26th)
    • -
    • Added Bisexual Visibility Day (September 23rd)
    • -
    • Added Coming Out Day! (October 11th)
    • -
    • Added Intersex Awareness Day (October 26th)
    • -
    • Added Transgender Awareness Week (November 13th - 19th)
    • -
    • Added the Transgender Day of Remembrance (November 20th)
    • -
    • Added Asexual Awareness Week (Last full week of October, this year it'll be Oct. 25-31)
    • -
    • Added the Stonewall Riot Anniversary (June 28)
    • -
    • Moth week is now *actually* the last full week of July, instead of the 4th of every weekday + the 5th Sunday.
    • -
    -

    Floof Ball / Kathrin Morrison / Floof Ball#0798 updated:

    -
      -
    • Improvised Pistol + 32 ACP ammo.
    • -
    • Improvised Energy Gun. Fires 5 shots of 10 burn damage each. Can be upgraded with a lens made from glassworking and T4 parts for a minor buff.
    • -
    • Ammo + gun part loot spawners for mappers.
    • -
    • New sprites for Improvised Rifle, the ability to sling the rifle and a sprite for that.
    • -
    • New sprites for the Improvised Shotgun and its sling sprite.
    • -
    • Improvised shotguns are now two-handed only.
    • -
    • Improvised shotguns now only have a much less harsh 0.9* modifier, keeping them two hits to crit with slugs and buckshot. It can no longer be dual-wielded but can still be sawn off for w_class medium (can fit in backpacks).
    • -
    • Missing handsaw icons added in.
    • -
    • Crafting table cleaned up into sections.
    • -
    -

    Ghommie updated:

    -
      -
    • changed the weak attack message prefix from "inefficiently" to "limply", "feebly" and "saplessly" and lowered the threshold.
    • -
    • Fixing old beserker hardsuits having the wrong helmet type.
    • -
    -

    The0bserver and Stewydeadmike updated:

    -
      -
    • Hey, there's a bit of dust in this recipe book! Recipes using peas? How many recipes does this book even have?
    • -
    • Adds 6 new food items, and 1 new consumable reagent using all forms of the recently discovered peas. Ask your local botanist and chef for them today!
    • -
    -

    YakumoChen updated:

    -
      -
    • Adds polychrome options to loadout
    • -
    • Adds risque polychrome options to Kinkmate vendors
    • -
    -

    kevinz000 updated:

    -
      -
    • emissive blockers can no longer be radioactive.
    • -
    • Ghosts can now scan air inside most objects that contain air by clicking on them.
    • -
    • Directional blocking has been added, keybound to G. This will reduce a portion of incoming damage if done with eligible items at the cost of stamina damage incurred to the user based on damage blocked as well as while active, as well as in most cases preventing the user from doing any attacks while this is active.
    • -
    • Parrying has been added, keybound to F. Timing-based counterattacks, effect heavily dependent on the item, WIP.
    • -
    • Disks are now smaller.
    • -
    - -

    12 June 2020

    -

    EmeraldSundisk updated:

    -
      -
    • The Detective's Office has been commandeered in order to serve a Head of Security. Detectives will find their new office within starboard maintenance.
    • -
    • Adds the Head of Security's standard equipment to their new office.
    • -
    • Slight adjustment/expansion to the main security department
    • -
    • Additional maintenance work
    • -
    -

    timothyteakettle updated:

    -
      -
    • Crabs, cockroaches, slimes and crabs are now small enough to fit in pet carriers
    • -
    - -

    11 June 2020

    -

    Ghommie updated:

    -
      -
    • Balanced vending machine prices to be generally more affordable, a minority has been priced up though.
    • -
    - -

    10 June 2020

    -

    DeltaFire15 updated:

    -
      -
    • Golems / simillar now inherit the neutered antag datum if the creator is neutered.
    • -
    -

    Ghommie updated:

    -
      -
    • Fixing missing pill type buttons from the chem master UI.
    • -
    -

    Naksu updated:

    -
      -
    • Lighting corner updates are ever so slightly faster.
    • -
    -

    Putnam for helping me code the contamination clearing on people updated:

    -
      -
    • Lab made Zeolites have been remade anew and more affective now that they refined the best possable way to mix and make a supper Zeolite capable of clearing contamination form not only people but items!
    • -
    -

    Trilbyspaceclone updated:

    -
      -
    • Tank Dispender has been moved into toxin storage from toxins
    • -
    -

    kevinz000 updated:

    -
      -
    • traitor classes can now be poplocked. hijack/glorious death are now locked to 25/20 respectively.
    • -
    -

    timothyteakettle updated:

    -
      -
    • adds a new fermichem, used for creating sentient plushies!
    • -
    • Mice can now breed using cheese wedges
    • -
    • Royal cheese can be crafted to convert a mouse into king rat
    • -
    - -

    09 June 2020

    -

    Anonymous updated:

    -
      -
    • Added Orville-inspired clothing as a worthy alternative to Trek stuff.
    • -
    • Adds chaplain role allowance to the TMP Service Uniform loadout.
    • -
    • Adds paramedic in every medsci mentioned uniform loadout.
    • -
    -

    DeltaFire15 updated:

    -
      -
    • Offstation AIs can once again only interact with their z-level
    • -
    -

    Ghommie updated:

    -
      -
    • Fixing IC material containers interaction with stacks, for real.
    • -
    -

    Trilbyspaceclone updated:

    -
      -
    • Gasses like BZ and Masiam seem to just sell for less in cargo, markets seem to change it seems
    • -
    -

    kevinz000 updated:

    -
      -
    • plantpeople should stop dying in the halls now
    • -
    • Modifier-independent hotkey bindings have been added.
    • -
    - -

    08 June 2020

    -

    DeltaFire15 updated:

    -
      -
    • Delinging now properly removes their special role
    • -
    • Keycard auth devices now require two seperate IDs with sufficient access to auth.
    • -
    -

    Linzolle updated:

    -
      -
    • shotguns no longer delete chambered shells while firing
    • -
    -

    kevinz000 updated:

    -
      -
    • test
    • -
    -

    shellspeed1 updated:

    -
      -
    • Internal tanks are now printable at the engineering lathe.
    • -
    -

    timothyteakettle updated:

    -
      -
    • newly created areas using blueprints now maintain the previous areas noteleport value
    • -
    • kudzu seeds now actually spawn vines
    • -
GoonStation 13 Development Team diff --git a/html/changelogs/.all_changelog.yml b/html/changelogs/.all_changelog.yml index 02aa9cab74..d4243a01ec 100644 --- a/html/changelogs/.all_changelog.yml +++ b/html/changelogs/.all_changelog.yml @@ -26770,3 +26770,293 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py. instead of cutting it off and discarding the overflow. - rscadd: holoparasites can now play music - balance: lethal blood now causes damaging bleeding instead of outright gibbing +2020-08-08: + DeltaFire15: + - balance: Roundstart cultists now start with a replica fabricator - no brass though, + make your own. + - balance: 'Kindle cast time: 10 > 15, mute after stun end: 2 > 5, slur after mute + end: 3 > 5' + - bugfix: The ratvarian spear no longer adds negative vitality under very specific + circumstances. + - balance: The Ratvarian Spear can parry now! Short parries with low leeway, but + low cooldown. + - rscadd: The brass claw, a implant-based weapon which gains combo on consecutive + hits against the same target. + - rscadd: The sigil of rites, a sigil used to perform various rites with a cost + of power and materials + - rscadd: 'The Rite of Advancement: Used to add a organ or cyberimplant to a clockie + without need for surgery.' + - rscadd: 'The Rite of Woundmending: Used to heal all wounds on another cultist, + causing toxins damage in return.' + - rscadd: 'The Rite of the Claw: Used to summon a brass claw implant. Maximum of + 4 uses per round.' + Hatterhat: + - rscadd: You can now buy a toolbox's worth of Mosin-Nagant ammo for a fairly discounted + price. + - rscadd: Revolvers from the dedicated kit now have reskinning capabilities. + - bugfix: You can now actually buy the riflery primer, which lets you pump shotguns + and work the Mosin's bolt faster. + - imageadd: Bulldog slug magazines now have a unique sprite. + Ludox235: + - rscdel: Removed an abductee objective that told you to remove all oxygen. + - rscadd: Added a new abductee objective to replace the removed one. + Sishen1542: + - tweak: "\U0001F171\uFE0Foneless" + - rscadd: squishy slime emotes + timothyteakettle: + - tweak: heparin makes you bleed half as much now + - tweak: cuts make you bleed 25% less now + - rscadd: more items in the loadout and loadout has subcategories now for easier + searching +2020-08-09: + Hatterhat: + - rscadd: Proto-kinetic glaives (not crushers) can parry now. + MrJWhit: + - rscadd: Adds a second shutter on the top of the hop line + silicons: + - bugfix: immovable rods no longer drop down chasms + - rscdel: 'fun removal: squeaking objects now have an 1 second cooldown between + squeaks, and will have a 33% chance of interrupting any other squeaking object + when Cross()ing, meaning no more ear-fuck conveyor belts.' +2020-08-10: + Hatterhat: + - bugfix: Parry counterattack text now shows up. + - balance: Sterilized gauze is now better at stopping bleeding, and applies slightly + faster. Very slightly faster. + - balance: Ointment and sutures now hold more in a stack (12 and 15, respectively). + - tweak: Sterilized gauze can now be made by just pouring 10u sterilizine onto standard + medical gauze, instead of having to craft it. Why you had to craft it, I will + honestly never know. + - balance: Proto-kinetic glaives are more expensive, stagger/cooldown on failed + parries increased slightly, perfect parries required for counterattack. + - rscadd: 'New item: Temporal Katana. 2 points for wizards, timestops upon successful + parry, bokken quickparry stats (100 force on melee counter!).' + - rscadd: Also you can *smirk. This has no mechanical effect, other than being smug. + KeRSedChaplain: + - rscadd: Added a guide for romerol usage + - balance: made infectious zombies not enter softcrit and take no stamina damage + LetterN: + - tweak: clocktheme color + - code_imp: Ports TGUI-4 + Lynxless: + - rscadd: 'Ports TG #51879' + Owai-Seek: + - tweak: Meatballs now spawn raw from food processors. + Putnam3145: + - rscadd: Ethereals + - rscdel: (Hexa)crocin + - rscdel: (Hexa)camphor + - tweak: Tweaked wording for marking tickets IC issue. + - tweak: Rerolling your traitor goals will ONLY give you "proper" objectives. + Seris02: + - bugfix: borgs being able to select and use a module when it's too damaged + Sishen1542: + - balance: gave chairs active block/parry in exchange for removal of block_chance + - tweak: replaces box whiteship tbaton with truncheon + kappa-sama: + - balance: made the Dirty Magazines crate cost 4000 instead of 12000 credits + - rscadd: MODS I SPILLED MU JUICE HEJPPHRLP HELPJ JLEP HELP + silicons: + - balance: player made areas are no longer valid for malf hacking + - tweak: default space levels is 4 again. + - tweak: rats now swarm instead of stacking on one spot. + - balance: getting hit by an explosion will now barely hard knockdown, but will + leave you somewhat winded. + timothyteakettle: + - tweak: speech verbs copy through dna copying now +2020-08-11: + Hatterhat: + - bugfix: PDA uplinks can now steal from pens. Properly. Just make sure to have + a pen in your PDA, first. + kappa-sama: + - tweak: tracer no longer gives you full stamheals per use + zeroisthebiggay: + - rscadd: volaju two +2020-08-12: + DeltaFire15: + - balance: 'hellgun single-pack classification: goodies -> armory' + Detective-Google: + - bugfix: hallway table hallway table + Hatterhat: + - balance: The temporal katana is now slightly more worthy of the 2 spell point + cost, with a smaller, antimagic respecting timestop, less force, and no random + blockchance. Society has progressed past the need for blockchance. + LetterN: + - rscadd: Mafia Component + - bugfix: Fixed missing icons and handtele + Putnam3145: + - bugfix: a whole lot of jank regarding funny part sprite display. + Toriate: + - rscadd: Opossums have migrated into the maintenance tunnels! Seek them out at + your own peril! + ancientpower: + - tweak: Doors added to the west side of box medbay to make things a bit more manageable. + kappa-sama: + - tweak: smuggler satchel cost 2->1 + - tweak: radio jammer cost 5->2 + - bugfix: smuggler satchel uplink description now implies that persistence is disabled + lolman360: + - rscadd: renameable necklace (accessory, attaches to suit) and ring (glove slot.) + - tweak: custom rename is now 2048 characters? i think it's characters. + silicons: + - rscadd: You can now use anything as an emoji by doing :/obj/item/path/to/item:. + This works for any /atom or subtype. + timothyteakettle: + - rscadd: syndicate agents now have access to mechanical aim enhancers which allow + them to aim bullets to bounce off walls + - bugfix: ricochets work properly now for the bullets that support them + zeroisthebiggay: + - imageadd: hair and some sechuds + - balance: ce hardsuit radproofing +2020-08-13: + LetterN: + - rscdel: Removes fermisleepers and reverts them to tg ones +2020-08-14: + silicons: + - bugfix: abductors can buy things +2020-08-15: + LetterN: + - bugfix: missing anomaly core icons + - bugfix: wrong state. blame the tg vertion i copied + silicons: + - tweak: the 8 rotation limit from clockwork chairs has been removed. please don't + abuse this. + - tweak: ethereals can now wear underwear +2020-08-16: + kiwedespars: + - balance: nerfed hypereut chaplain weapon. + - balance: 50% rng blockchance -> 0% + - balance: parry made much worse because it's an actual weapon and a roundstart + one at that. + zeroisthebiggay: + - rscadd: tips + - rscdel: tips +2020-08-17: + DeltaFire15: + - bugfix: Cogscarabs are no longer always Pogscarabs + Strazyplus: + - rscadd: Added drakeborgs + - rscadd: Added drakeplushies + - imageadd: added drakeborg sprites + - imageadd: added drakeplushie sprites + - code_imp: changed some code - added drakeplushies to backpack loadout Removed + duplicate voresleeper belly sprites from engdrake & jantidrake. [CC BY-NC-SA + 3.0](https://creativecommons.org/licenses/by-nc-sa/3.0/) + - rscadd: Added CC BY-NC-SA 3.0 license details to icon/mob/cyborg moved drakeborg.dmi + to icon/mob/cyborg +2020-08-18: + DeltaFire15: + - balance: 'kindle cast time: 15ds -> 25ds' + - tweak: Moved the Belligerent Scripture to where it should be in the code + Detective-Google: + - rscadd: glass floors + - rscadd: uncrowbarrable plasma floors tweak:disco inferno's plasma floors can no + longer be crowbarred. + - rscadd: ghost cafe has funky fresh art + - bugfix: you can actually remove glass floors now + - code_imp: get_equipped_items is hopefully less gross + - balance: plasma cutters are no longer gay + Hatterhat: + - balance: Slaughter demons (and laughter demons, being a subtype) are MOB_SIZE_LARGE, + with one of the more immediate effects being able to mark them with a crusher + and backstab them. + - balance: The funny blyat men have stumbled upon another surplus of Mosin-Nagants + and are starting to pack them into crates again. + - balance: Vehicle riders can now, by default, get shot in the face and/or chest. + - rscadd: Adminspawn only .357 DumDum rounds! Because sometimes the other guy just + really needs to hurt. + - rscadd: Bluespace beakers now have a chemical window through the side that shows + chemical overlays. + - rscadd: Plant DNA manipulators now let you chuck things over them. Or they WOULD, + if LETPASSTHROW worked half a damn. + LetterN: + - bugfix: uplink implant states + - tweak: tweaks how role assigning works + MrJWhit: + - rscadd: Gives ashwalkers nightvision + - balance: Makes tesla blast people, not the environment, to save the server. + TheObserver-sys: + - bugfix: moves Garlic sprites from growing.dmi to growing_vegetable.dmi + - rscdel: Removes the unused Electric Lime mutation, it just takes up space with + no actual function nor sprites. + - imageadd: Gives Catnip growing sprites + - imagedel: Removes redundant images in growing.dmi + kiwedespars: + - rscadd: 10 force to a fucking rubber cock. + lolman360: + - balance: shotgun stripper clip nerf. ammoboxes can now accept a load_delay that + happens when they attack a magazine, internal or external. + ported from tg: + - rscadd: bronze airlocks and windows can now be built + - balance: i also tweaked bronze flooring to be cheaper. + silicons: + - tweak: stamina draining projectiles without stamina for their primary damage type + now has their stamina damage taken into account for shield blocking, rather + than the block being done for free for that. + timothyteakettle: + - refactor: snowflake code tidyup + - refactor: snowflake code for mutant bodypart selection has been rewritten to be + ~14x shorter + - tweak: meat type and horns can now be selected by any species +2020-08-20: + DeltaFire15: + - bugfix: The cooking oil damage formula is no longer scuffed. + - tweak: Changed the clockie help-link to lead to our own wiki. + Fikou: + - admin: admins can now do html in ahelps properly + Hatterhat: + - balance: Pirate threats are now announced as "business propositions", and their + arrivals are now also announced properly. + tiramisuapimancer: + - bugfix: Ethereal hair is now their body color instead of accidentally white +2020-08-21: + LetterN: + - rscadd: Updates and adds some of the tips + Putnam3145: + - admin: added reftracking as a compile flag + SmArtKar: + - tweak: RSD limitation is now 500 tiles + - bugfix: Fixed broken RSD sprites + - config: Removed that shuttle limit + timothyteakettle: + - bugfix: two snouts can once again be chosen in customization + - bugfix: lizard snouts work again +2020-08-22: + Time-Green (copypasta'd by lolman360): + - rscadd: plumbing + - rscadd: automatic hydro trays +2020-08-23: + DeltaFire15: + - bugfix: silicons and clockies can now access APCs properly + EmeraldSundisk: + - rscadd: Medbay now has a smartfridge for organ storage + - rscadd: Slight enhancements to the station's electrical wiring layout + - rscadd: Very small library renovation + - bugfix: Exterior airlocks have been given proper air systems for safety's sake + Ghommie: + - bugfix: Stops shielded hardsuits from slowly turning the wearer into a big glowing + ball of stacked energy shield overlays. + - tweak: the shielding overlay is merely visual as result. Aim your clicks. + Ludox235: + - tweak: no more 10 pop xenos (25pop now) + MrJWhit: + - tweak: Increases the majority of airlocks by 1 tile. + - tweak: Minor adjustments to the TEG engine. + Putnam3145: + - balance: Simplemobs no longer count in dynamic. + - balance: '"Story" storyteller no longer starts at a ludicrously low threat, always.' + - balance: Blob threat now scales with coverage. + - tweak: One person with their pref on no longer overpowers 40 people who might + not even know there is one. + - bugfix: Negative-weight rulesets are no longer put into the list. + kiwedespars: + - tweak: removed durathread from armwraps recipe. + lolman360: + - rscadd: breath mask balaclava + timothyteakettle: + - bugfix: lizards are now a recommended species for mam snouts + zeroisthebiggay: + - rscadd: new sprites for the temporal katana + - rscadd: suiciding with the temporal katana omae wa mou shinderius you into the + shadow realm + - soundadd: twilight isnt earrape diff --git a/html/changelogs/AutoChangeLog-pr-12960.yml b/html/changelogs/AutoChangeLog-pr-12960.yml deleted file mode 100644 index e37ac7eff0..0000000000 --- a/html/changelogs/AutoChangeLog-pr-12960.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "timothyteakettle" -delete-after: True -changes: - - rscadd: "more items in the loadout and loadout has subcategories now for easier searching" diff --git a/html/changelogs/AutoChangeLog-pr-12992.yml b/html/changelogs/AutoChangeLog-pr-12992.yml deleted file mode 100644 index 41edfb6414..0000000000 --- a/html/changelogs/AutoChangeLog-pr-12992.yml +++ /dev/null @@ -1,7 +0,0 @@ -author: "Hatterhat" -delete-after: True -changes: - - rscadd: "You can now buy a toolbox's worth of Mosin-Nagant ammo for a fairly discounted price." - - rscadd: "Revolvers from the dedicated kit now have reskinning capabilities." - - bugfix: "You can now actually buy the riflery primer, which lets you pump shotguns and work the Mosin's bolt faster." - - imageadd: "Bulldog slug magazines now have a unique sprite." diff --git a/html/changelogs/AutoChangeLog-pr-13013.yml b/html/changelogs/AutoChangeLog-pr-13013.yml deleted file mode 100644 index 8e0b953ade..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13013.yml +++ /dev/null @@ -1,12 +0,0 @@ -author: "DeltaFire15" -delete-after: True -changes: - - balance: "Roundstart cultists now start with a replica fabricator - no brass though, make your own." - - balance: "Kindle cast time: 10 > 15, mute after stun end: 2 > 5, slur after mute end: 3 > 5" - - bugfix: "The ratvarian spear no longer adds negative vitality under very specific circumstances." - - balance: "The Ratvarian Spear can parry now! Short parries with low leeway, but low cooldown." - - rscadd: "The brass claw, a implant-based weapon which gains combo on consecutive hits against the same target." - - rscadd: "The sigil of rites, a sigil used to perform various rites with a cost of power and materials" - - rscadd: "The Rite of Advancement: Used to add a organ or cyberimplant to a clockie without need for surgery." - - rscadd: "The Rite of Woundmending: Used to heal all wounds on another cultist, causing toxins damage in return." - - rscadd: "The Rite of the Claw: Used to summon a brass claw implant. Maximum of 4 uses per round." diff --git a/html/changelogs/AutoChangeLog-pr-13038.yml b/html/changelogs/AutoChangeLog-pr-13038.yml deleted file mode 100644 index 442bd37677..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13038.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Sishen1542" -delete-after: True -changes: - - rscadd: "squishy slime emotes" diff --git a/html/changelogs/AutoChangeLog-pr-13039.yml b/html/changelogs/AutoChangeLog-pr-13039.yml deleted file mode 100644 index de8ea10f35..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13039.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: "timothyteakettle" -delete-after: True -changes: - - tweak: "heparin makes you bleed half as much now" - - tweak: "cuts make you bleed 25% less now" diff --git a/html/changelogs/AutoChangeLog-pr-13041.yml b/html/changelogs/AutoChangeLog-pr-13041.yml deleted file mode 100644 index 1ae84967a8..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13041.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: "Ludox235" -delete-after: True -changes: - - rscdel: "Removed an abductee objective that told you to remove all oxygen." - - rscadd: "Added a new abductee objective to replace the removed one." diff --git a/html/changelogs/AutoChangeLog-pr-13043.yml b/html/changelogs/AutoChangeLog-pr-13043.yml deleted file mode 100644 index 5a9f2ca46f..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13043.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Sishen1542" -delete-after: True -changes: - - tweak: "🅱ï¸oneless" diff --git a/icons/effects/160x160.dmi b/icons/effects/160x160.dmi index 0a97573a9b..2adedb6c03 100644 Binary files a/icons/effects/160x160.dmi and b/icons/effects/160x160.dmi differ diff --git a/icons/effects/96x96.dmi b/icons/effects/96x96.dmi index b60ff97b2b..34f4adf6ce 100644 Binary files a/icons/effects/96x96.dmi and b/icons/effects/96x96.dmi differ diff --git a/icons/effects/beam.dmi b/icons/effects/beam.dmi index 0c4784553c..e5bff44ac4 100644 Binary files a/icons/effects/beam.dmi and b/icons/effects/beam.dmi differ diff --git a/icons/effects/beam_splash.dmi b/icons/effects/beam_splash.dmi new file mode 100644 index 0000000000..d7deb3e927 Binary files /dev/null and b/icons/effects/beam_splash.dmi differ diff --git a/icons/effects/effects.dmi b/icons/effects/effects.dmi index a2fce4678f..52164e1d33 100644 Binary files a/icons/effects/effects.dmi and b/icons/effects/effects.dmi differ diff --git a/icons/effects/eldritch.dmi b/icons/effects/eldritch.dmi new file mode 100644 index 0000000000..82549dccf0 Binary files /dev/null and b/icons/effects/eldritch.dmi differ diff --git a/icons/effects/mouse_pointers/barn_target.dmi b/icons/effects/mouse_pointers/barn_target.dmi new file mode 100644 index 0000000000..475a2b88b1 Binary files /dev/null and b/icons/effects/mouse_pointers/barn_target.dmi differ diff --git a/icons/effects/mouse_pointers/blind_target.dmi b/icons/effects/mouse_pointers/blind_target.dmi new file mode 100644 index 0000000000..1d33fc7a4c Binary files /dev/null and b/icons/effects/mouse_pointers/blind_target.dmi differ diff --git a/icons/effects/mouse_pointers/cult_target.dmi b/icons/effects/mouse_pointers/cult_target.dmi new file mode 100644 index 0000000000..650feb3361 Binary files /dev/null and b/icons/effects/mouse_pointers/cult_target.dmi differ diff --git a/icons/effects/mouse_pointers/mecha_mouse-disable.dmi b/icons/effects/mouse_pointers/mecha_mouse-disable.dmi new file mode 100644 index 0000000000..48924c58c2 Binary files /dev/null and b/icons/effects/mouse_pointers/mecha_mouse-disable.dmi differ diff --git a/icons/effects/mouse_pointers/mecha_mouse.dmi b/icons/effects/mouse_pointers/mecha_mouse.dmi new file mode 100644 index 0000000000..4b46a44684 Binary files /dev/null and b/icons/effects/mouse_pointers/mecha_mouse.dmi differ diff --git a/icons/effects/mouse_pointers/mindswap_target.dmi b/icons/effects/mouse_pointers/mindswap_target.dmi new file mode 100644 index 0000000000..32ccda154d Binary files /dev/null and b/icons/effects/mouse_pointers/mindswap_target.dmi differ diff --git a/icons/effects/mouse_pointers/overload_machine_target.dmi b/icons/effects/mouse_pointers/overload_machine_target.dmi new file mode 100644 index 0000000000..8bc67cdab6 Binary files /dev/null and b/icons/effects/mouse_pointers/overload_machine_target.dmi differ diff --git a/icons/effects/mouse_pointers/override_machine_target.dmi b/icons/effects/mouse_pointers/override_machine_target.dmi new file mode 100644 index 0000000000..77dbb4ba32 Binary files /dev/null and b/icons/effects/mouse_pointers/override_machine_target.dmi differ diff --git a/icons/effects/supplypod_down_target.dmi b/icons/effects/mouse_pointers/supplypod_down_target.dmi similarity index 100% rename from icons/effects/supplypod_down_target.dmi rename to icons/effects/mouse_pointers/supplypod_down_target.dmi diff --git a/icons/effects/mouse_pointers/supplypod_pickturf.dmi b/icons/effects/mouse_pointers/supplypod_pickturf.dmi new file mode 100644 index 0000000000..3ca1131e1a Binary files /dev/null and b/icons/effects/mouse_pointers/supplypod_pickturf.dmi differ diff --git a/icons/effects/mouse_pointers/supplypod_pickturf_down.dmi b/icons/effects/mouse_pointers/supplypod_pickturf_down.dmi new file mode 100644 index 0000000000..113fe47540 Binary files /dev/null and b/icons/effects/mouse_pointers/supplypod_pickturf_down.dmi differ diff --git a/icons/effects/supplypod_target.dmi b/icons/effects/mouse_pointers/supplypod_target.dmi similarity index 100% rename from icons/effects/supplypod_target.dmi rename to icons/effects/mouse_pointers/supplypod_target.dmi diff --git a/icons/effects/mouse_pointers/throw_target.dmi b/icons/effects/mouse_pointers/throw_target.dmi new file mode 100644 index 0000000000..660eafbf2b Binary files /dev/null and b/icons/effects/mouse_pointers/throw_target.dmi differ diff --git a/icons/effects/mouse_pointers/wrap_target.dmi b/icons/effects/mouse_pointers/wrap_target.dmi new file mode 100644 index 0000000000..2e9a338c9e Binary files /dev/null and b/icons/effects/mouse_pointers/wrap_target.dmi differ diff --git a/icons/misc/language.dmi b/icons/misc/language.dmi index 155dbab98d..9501dc9216 100644 Binary files a/icons/misc/language.dmi and b/icons/misc/language.dmi differ diff --git a/icons/mob/actions/actions_ecult.dmi b/icons/mob/actions/actions_ecult.dmi new file mode 100644 index 0000000000..0a130f006e Binary files /dev/null and b/icons/mob/actions/actions_ecult.dmi differ diff --git a/icons/mob/actions/backgrounds.dmi b/icons/mob/actions/backgrounds.dmi index 07839588ce..6b983df95a 100644 Binary files a/icons/mob/actions/backgrounds.dmi and b/icons/mob/actions/backgrounds.dmi differ diff --git a/icons/mob/animal.dmi b/icons/mob/animal.dmi index 13f97d3761..50bf65b27f 100644 Binary files a/icons/mob/animal.dmi and b/icons/mob/animal.dmi differ diff --git a/icons/mob/clothing/back.dmi b/icons/mob/clothing/back.dmi index 9490595484..8594af8ec2 100644 Binary files a/icons/mob/clothing/back.dmi and b/icons/mob/clothing/back.dmi differ diff --git a/icons/mob/clothing/belt.dmi b/icons/mob/clothing/belt.dmi index 52ef75020c..4ac82ca299 100644 Binary files a/icons/mob/clothing/belt.dmi and b/icons/mob/clothing/belt.dmi differ diff --git a/icons/mob/clothing/eyes.dmi b/icons/mob/clothing/eyes.dmi index cd2b84a143..876159c258 100644 Binary files a/icons/mob/clothing/eyes.dmi and b/icons/mob/clothing/eyes.dmi differ diff --git a/icons/mob/clothing/head.dmi b/icons/mob/clothing/head.dmi index 0ad9452994..16571a4aa1 100644 Binary files a/icons/mob/clothing/head.dmi and b/icons/mob/clothing/head.dmi differ diff --git a/icons/mob/clothing/neck.dmi b/icons/mob/clothing/neck.dmi index 86dec62a41..7bfecb4158 100644 Binary files a/icons/mob/clothing/neck.dmi and b/icons/mob/clothing/neck.dmi differ diff --git a/icons/mob/clothing/suit.dmi b/icons/mob/clothing/suit.dmi index c94e8a46d3..08d276a484 100644 Binary files a/icons/mob/clothing/suit.dmi and b/icons/mob/clothing/suit.dmi differ diff --git a/icons/mob/clothing/underwear.dmi b/icons/mob/clothing/underwear.dmi index f0c2cde93d..8cf1144a68 100644 Binary files a/icons/mob/clothing/underwear.dmi and b/icons/mob/clothing/underwear.dmi differ diff --git a/icons/mob/cyborg/Drakeborg-licensing.txt b/icons/mob/cyborg/Drakeborg-licensing.txt new file mode 100644 index 0000000000..f2d3ca925c --- /dev/null +++ b/icons/mob/cyborg/Drakeborg-licensing.txt @@ -0,0 +1,69 @@ +Drakeborg & drakeplushies are created by deviantart.com/mizartz + +https://creativecommons.org/licenses/by-nc-sa/3.0/ +Attribution-NonCommercial-ShareAlike 3.0 Unported + +CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE LEGAL SERVICES. DISTRIBUTION OF THIS LICENSE DOES NOT CREATE AN ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES REGARDING THE INFORMATION PROVIDED, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM ITS USE. +License +THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS CREATIVE COMMONS PUBLIC LICENSE ("CCPL" OR "LICENSE"). THE WORK IS PROTECTED BY COPYRIGHT AND/OR OTHER APPLICABLE LAW. ANY USE OF THE WORK OTHER THAN AS AUTHORIZED UNDER THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED. + +BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND AGREE TO BE BOUND BY THE TERMS OF THIS LICENSE. TO THE EXTENT THIS LICENSE MAY BE CONSIDERED TO BE A CONTRACT, THE LICENSOR GRANTS YOU THE RIGHTS CONTAINED HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND CONDITIONS. + +1. Definitions + +"Adaptation" means a work based upon the Work, or upon the Work and other pre-existing works, such as a translation, adaptation, derivative work, arrangement of music or other alterations of a literary or artistic work, or phonogram or performance and includes cinematographic adaptations or any other form in which the Work may be recast, transformed, or adapted including in any form recognizably derived from the original, except that a work that constitutes a Collection will not be considered an Adaptation for the purpose of this License. For the avoidance of doubt, where the Work is a musical work, performance or phonogram, the synchronization of the Work in timed-relation with a moving image ("synching") will be considered an Adaptation for the purpose of this License. +"Collection" means a collection of literary or artistic works, such as encyclopedias and anthologies, or performances, phonograms or broadcasts, or other works or subject matter other than works listed in Section 1(g) below, which, by reason of the selection and arrangement of their contents, constitute intellectual creations, in which the Work is included in its entirety in unmodified form along with one or more other contributions, each constituting separate and independent works in themselves, which together are assembled into a collective whole. A work that constitutes a Collection will not be considered an Adaptation (as defined above) for the purposes of this License. +"Distribute" means to make available to the public the original and copies of the Work or Adaptation, as appropriate, through sale or other transfer of ownership. +"License Elements" means the following high-level license attributes as selected by Licensor and indicated in the title of this License: Attribution, Noncommercial, ShareAlike. +"Licensor" means the individual, individuals, entity or entities that offer(s) the Work under the terms of this License. +"Original Author" means, in the case of a literary or artistic work, the individual, individuals, entity or entities who created the Work or if no individual or entity can be identified, the publisher; and in addition (i) in the case of a performance the actors, singers, musicians, dancers, and other persons who act, sing, deliver, declaim, play in, interpret or otherwise perform literary or artistic works or expressions of folklore; (ii) in the case of a phonogram the producer being the person or legal entity who first fixes the sounds of a performance or other sounds; and, (iii) in the case of broadcasts, the organization that transmits the broadcast. +"Work" means the literary and/or artistic work offered under the terms of this License including without limitation any production in the literary, scientific and artistic domain, whatever may be the mode or form of its expression including digital form, such as a book, pamphlet and other writing; a lecture, address, sermon or other work of the same nature; a dramatic or dramatico-musical work; a choreographic work or entertainment in dumb show; a musical composition with or without words; a cinematographic work to which are assimilated works expressed by a process analogous to cinematography; a work of drawing, painting, architecture, sculpture, engraving or lithography; a photographic work to which are assimilated works expressed by a process analogous to photography; a work of applied art; an illustration, map, plan, sketch or three-dimensional work relative to geography, topography, architecture or science; a performance; a broadcast; a phonogram; a compilation of data to the extent it is protected as a copyrightable work; or a work performed by a variety or circus performer to the extent it is not otherwise considered a literary or artistic work. +"You" means an individual or entity exercising rights under this License who has not previously violated the terms of this License with respect to the Work, or who has received express permission from the Licensor to exercise rights under this License despite a previous violation. +"Publicly Perform" means to perform public recitations of the Work and to communicate to the public those public recitations, by any means or process, including by wire or wireless means or public digital performances; to make available to the public Works in such a way that members of the public may access these Works from a place and at a place individually chosen by them; to perform the Work to the public by any means or process and the communication to the public of the performances of the Work, including by public digital performance; to broadcast and rebroadcast the Work by any means including signs, sounds or images. +"Reproduce" means to make copies of the Work by any means including without limitation by sound or visual recordings and the right of fixation and reproducing fixations of the Work, including storage of a protected performance or phonogram in digital form or other electronic medium. +2. Fair Dealing Rights. Nothing in this License is intended to reduce, limit, or restrict any uses free from copyright or rights arising from limitations or exceptions that are provided for in connection with the copyright protection under copyright law or other applicable laws. + +3. License Grant. Subject to the terms and conditions of this License, Licensor hereby grants You a worldwide, royalty-free, non-exclusive, perpetual (for the duration of the applicable copyright) license to exercise the rights in the Work as stated below: + +to Reproduce the Work, to incorporate the Work into one or more Collections, and to Reproduce the Work as incorporated in the Collections; +to create and Reproduce Adaptations provided that any such Adaptation, including any translation in any medium, takes reasonable steps to clearly label, demarcate or otherwise identify that changes were made to the original Work. For example, a translation could be marked "The original work was translated from English to Spanish," or a modification could indicate "The original work has been modified."; +to Distribute and Publicly Perform the Work including as incorporated in Collections; and, +to Distribute and Publicly Perform Adaptations. +The above rights may be exercised in all media and formats whether now known or hereafter devised. The above rights include the right to make such modifications as are technically necessary to exercise the rights in other media and formats. Subject to Section 8(f), all rights not expressly granted by Licensor are hereby reserved, including but not limited to the rights described in Section 4(e). + +4. Restrictions. The license granted in Section 3 above is expressly made subject to and limited by the following restrictions: + +You may Distribute or Publicly Perform the Work only under the terms of this License. You must include a copy of, or the Uniform Resource Identifier (URI) for, this License with every copy of the Work You Distribute or Publicly Perform. You may not offer or impose any terms on the Work that restrict the terms of this License or the ability of the recipient of the Work to exercise the rights granted to that recipient under the terms of the License. You may not sublicense the Work. You must keep intact all notices that refer to this License and to the disclaimer of warranties with every copy of the Work You Distribute or Publicly Perform. When You Distribute or Publicly Perform the Work, You may not impose any effective technological measures on the Work that restrict the ability of a recipient of the Work from You to exercise the rights granted to that recipient under the terms of the License. This Section 4(a) applies to the Work as incorporated in a Collection, but this does not require the Collection apart from the Work itself to be made subject to the terms of this License. If You create a Collection, upon notice from any Licensor You must, to the extent practicable, remove from the Collection any credit as required by Section 4(d), as requested. If You create an Adaptation, upon notice from any Licensor You must, to the extent practicable, remove from the Adaptation any credit as required by Section 4(d), as requested. +You may Distribute or Publicly Perform an Adaptation only under: (i) the terms of this License; (ii) a later version of this License with the same License Elements as this License; (iii) a Creative Commons jurisdiction license (either this or a later license version) that contains the same License Elements as this License (e.g., Attribution-NonCommercial-ShareAlike 3.0 US) ("Applicable License"). You must include a copy of, or the URI, for Applicable License with every copy of each Adaptation You Distribute or Publicly Perform. You may not offer or impose any terms on the Adaptation that restrict the terms of the Applicable License or the ability of the recipient of the Adaptation to exercise the rights granted to that recipient under the terms of the Applicable License. You must keep intact all notices that refer to the Applicable License and to the disclaimer of warranties with every copy of the Work as included in the Adaptation You Distribute or Publicly Perform. When You Distribute or Publicly Perform the Adaptation, You may not impose any effective technological measures on the Adaptation that restrict the ability of a recipient of the Adaptation from You to exercise the rights granted to that recipient under the terms of the Applicable License. This Section 4(b) applies to the Adaptation as incorporated in a Collection, but this does not require the Collection apart from the Adaptation itself to be made subject to the terms of the Applicable License. +You may not exercise any of the rights granted to You in Section 3 above in any manner that is primarily intended for or directed toward commercial advantage or private monetary compensation. The exchange of the Work for other copyrighted works by means of digital file-sharing or otherwise shall not be considered to be intended for or directed toward commercial advantage or private monetary compensation, provided there is no payment of any monetary compensation in con-nection with the exchange of copyrighted works. +If You Distribute, or Publicly Perform the Work or any Adaptations or Collections, You must, unless a request has been made pursuant to Section 4(a), keep intact all copyright notices for the Work and provide, reasonable to the medium or means You are utilizing: (i) the name of the Original Author (or pseudonym, if applicable) if supplied, and/or if the Original Author and/or Licensor designate another party or parties (e.g., a sponsor institute, publishing entity, journal) for attribution ("Attribution Parties") in Licensor's copyright notice, terms of service or by other reasonable means, the name of such party or parties; (ii) the title of the Work if supplied; (iii) to the extent reasonably practicable, the URI, if any, that Licensor specifies to be associated with the Work, unless such URI does not refer to the copyright notice or licensing information for the Work; and, (iv) consistent with Section 3(b), in the case of an Adaptation, a credit identifying the use of the Work in the Adaptation (e.g., "French translation of the Work by Original Author," or "Screenplay based on original Work by Original Author"). The credit required by this Section 4(d) may be implemented in any reasonable manner; provided, however, that in the case of a Adaptation or Collection, at a minimum such credit will appear, if a credit for all contributing authors of the Adaptation or Collection appears, then as part of these credits and in a manner at least as prominent as the credits for the other contributing authors. For the avoidance of doubt, You may only use the credit required by this Section for the purpose of attribution in the manner set out above and, by exercising Your rights under this License, You may not implicitly or explicitly assert or imply any connection with, sponsorship or endorsement by the Original Author, Licensor and/or Attribution Parties, as appropriate, of You or Your use of the Work, without the separate, express prior written permission of the Original Author, Licensor and/or Attribution Parties. +For the avoidance of doubt: + +Non-waivable Compulsory License Schemes. In those jurisdictions in which the right to collect royalties through any statutory or compulsory licensing scheme cannot be waived, the Licensor reserves the exclusive right to collect such royalties for any exercise by You of the rights granted under this License; +Waivable Compulsory License Schemes. In those jurisdictions in which the right to collect royalties through any statutory or compulsory licensing scheme can be waived, the Licensor reserves the exclusive right to collect such royalties for any exercise by You of the rights granted under this License if Your exercise of such rights is for a purpose or use which is otherwise than noncommercial as permitted under Section 4(c) and otherwise waives the right to collect royalties through any statutory or compulsory licensing scheme; and, +Voluntary License Schemes. The Licensor reserves the right to collect royalties, whether individually or, in the event that the Licensor is a member of a collecting society that administers voluntary licensing schemes, via that society, from any exercise by You of the rights granted under this License that is for a purpose or use which is otherwise than noncommercial as permitted under Section 4(c). +Except as otherwise agreed in writing by the Licensor or as may be otherwise permitted by applicable law, if You Reproduce, Distribute or Publicly Perform the Work either by itself or as part of any Adaptations or Collections, You must not distort, mutilate, modify or take other derogatory action in relation to the Work which would be prejudicial to the Original Author's honor or reputation. Licensor agrees that in those jurisdictions (e.g. Japan), in which any exercise of the right granted in Section 3(b) of this License (the right to make Adaptations) would be deemed to be a distortion, mutilation, modification or other derogatory action prejudicial to the Original Author's honor and reputation, the Licensor will waive or not assert, as appropriate, this Section, to the fullest extent permitted by the applicable national law, to enable You to reasonably exercise Your right under Section 3(b) of this License (right to make Adaptations) but not otherwise. +5. Representations, Warranties and Disclaimer + +UNLESS OTHERWISE MUTUALLY AGREED TO BY THE PARTIES IN WRITING AND TO THE FULLEST EXTENT PERMITTED BY APPLICABLE LAW, LICENSOR OFFERS THE WORK AS-IS AND MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY KIND CONCERNING THE WORK, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, INCLUDING, WITHOUT LIMITATION, WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, OR THE ABSENCE OF LATENT OR OTHER DEFECTS, ACCURACY, OR THE PRESENCE OF ABSENCE OF ERRORS, WHETHER OR NOT DISCOVERABLE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF IMPLIED WARRANTIES, SO THIS EXCLUSION MAY NOT APPLY TO YOU. + +6. Limitation on Liability. EXCEPT TO THE EXTENT REQUIRED BY APPLICABLE LAW, IN NO EVENT WILL LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY FOR ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES ARISING OUT OF THIS LICENSE OR THE USE OF THE WORK, EVEN IF LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + +7. Termination + +This License and the rights granted hereunder will terminate automatically upon any breach by You of the terms of this License. Individuals or entities who have received Adaptations or Collections from You under this License, however, will not have their licenses terminated provided such individuals or entities remain in full compliance with those licenses. Sections 1, 2, 5, 6, 7, and 8 will survive any termination of this License. +Subject to the above terms and conditions, the license granted here is perpetual (for the duration of the applicable copyright in the Work). Notwithstanding the above, Licensor reserves the right to release the Work under different license terms or to stop distributing the Work at any time; provided, however that any such election will not serve to withdraw this License (or any other license that has been, or is required to be, granted under the terms of this License), and this License will continue in full force and effect unless terminated as stated above. +8. Miscellaneous + +Each time You Distribute or Publicly Perform the Work or a Collection, the Licensor offers to the recipient a license to the Work on the same terms and conditions as the license granted to You under this License. +Each time You Distribute or Publicly Perform an Adaptation, Licensor offers to the recipient a license to the original Work on the same terms and conditions as the license granted to You under this License. +If any provision of this License is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this License, and without further action by the parties to this agreement, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable. +No term or provision of this License shall be deemed waived and no breach consented to unless such waiver or consent shall be in writing and signed by the party to be charged with such waiver or consent. +This License constitutes the entire agreement between the parties with respect to the Work licensed here. There are no understandings, agreements or representations with respect to the Work not specified here. Licensor shall not be bound by any additional provisions that may appear in any communication from You. This License may not be modified without the mutual written agreement of the Licensor and You. +The rights granted under, and the subject matter referenced, in this License were drafted utilizing the terminology of the Berne Convention for the Protection of Literary and Artistic Works (as amended on September 28, 1979), the Rome Convention of 1961, the WIPO Copyright Treaty of 1996, the WIPO Performances and Phonograms Treaty of 1996 and the Universal Copyright Convention (as revised on July 24, 1971). These rights and subject matter take effect in the relevant jurisdiction in which the License terms are sought to be enforced according to the corresponding provisions of the implementation of those treaty provisions in the applicable national law. If the standard suite of rights granted under applicable copyright law includes additional rights not granted under this License, such additional rights are deemed to be included in the License; this License is not intended to restrict the license of any rights under applicable law. +Creative Commons Notice +Creative Commons is not a party to this License, and makes no warranty whatsoever in connection with the Work. Creative Commons will not be liable to You or any party on any legal theory for any damages whatsoever, including without limitation any general, special, incidental or consequential damages arising in connection to this license. Notwithstanding the foregoing two (2) sentences, if Creative Commons has expressly identified itself as the Licensor hereunder, it shall have all rights and obligations of Licensor. + +Except for the limited purpose of indicating to the public that the Work is licensed under the CCPL, Creative Commons does not authorize the use by either party of the trademark "Creative Commons" or any related trademark or logo of Creative Commons without the prior written consent of Creative Commons. Any permitted use will be in compliance with Creative Commons' then-current trademark usage guidelines, as may be published on its website or otherwise made available upon request from time to time. For the avoidance of doubt, this trademark restriction does not form part of this License. + +Creative Commons may be contacted at https://creativecommons.org/. \ No newline at end of file diff --git a/icons/mob/cyborg/drakemech.dmi b/icons/mob/cyborg/drakemech.dmi new file mode 100644 index 0000000000..6a4845d983 Binary files /dev/null and b/icons/mob/cyborg/drakemech.dmi differ diff --git a/icons/mob/eldritch_mobs.dmi b/icons/mob/eldritch_mobs.dmi new file mode 100644 index 0000000000..8a16d53f88 Binary files /dev/null and b/icons/mob/eldritch_mobs.dmi differ diff --git a/icons/mob/hud.dmi b/icons/mob/hud.dmi index c21fa47b9c..1d2007fd63 100644 Binary files a/icons/mob/hud.dmi and b/icons/mob/hud.dmi differ diff --git a/icons/mob/human_face.dmi b/icons/mob/human_face.dmi index a4e2a9d5b2..8055233ea7 100644 Binary files a/icons/mob/human_face.dmi and b/icons/mob/human_face.dmi differ diff --git a/icons/mob/inhands/64x64_lefthand.dmi b/icons/mob/inhands/64x64_lefthand.dmi index 6b47171066..6dc8d82753 100644 Binary files a/icons/mob/inhands/64x64_lefthand.dmi and b/icons/mob/inhands/64x64_lefthand.dmi differ diff --git a/icons/mob/inhands/64x64_righthand.dmi b/icons/mob/inhands/64x64_righthand.dmi index 3750e28906..ca87f74a6f 100644 Binary files a/icons/mob/inhands/64x64_righthand.dmi and b/icons/mob/inhands/64x64_righthand.dmi differ diff --git a/icons/mob/inhands/weapons/swords_lefthand.dmi b/icons/mob/inhands/weapons/swords_lefthand.dmi index 0ca36ad43d..23d80af9ef 100644 Binary files a/icons/mob/inhands/weapons/swords_lefthand.dmi and b/icons/mob/inhands/weapons/swords_lefthand.dmi differ diff --git a/icons/mob/inhands/weapons/swords_righthand.dmi b/icons/mob/inhands/weapons/swords_righthand.dmi index 59d7bbce69..702c0299b5 100644 Binary files a/icons/mob/inhands/weapons/swords_righthand.dmi and b/icons/mob/inhands/weapons/swords_righthand.dmi differ diff --git a/icons/mob/mob.dmi b/icons/mob/mob.dmi index de09fb1c63..23f0e2cc13 100644 Binary files a/icons/mob/mob.dmi and b/icons/mob/mob.dmi differ diff --git a/icons/obj/assemblies/new_assemblies.dmi b/icons/obj/assemblies/new_assemblies.dmi index 2283b84c43..32eda1eb49 100644 Binary files a/icons/obj/assemblies/new_assemblies.dmi and b/icons/obj/assemblies/new_assemblies.dmi differ diff --git a/icons/obj/chemical.dmi b/icons/obj/chemical.dmi index aea15e2e39..cd12f4a457 100644 Binary files a/icons/obj/chemical.dmi and b/icons/obj/chemical.dmi differ diff --git a/icons/obj/clothing/accessories.dmi b/icons/obj/clothing/accessories.dmi index c62a88c829..7d13e3f802 100644 Binary files a/icons/obj/clothing/accessories.dmi and b/icons/obj/clothing/accessories.dmi differ diff --git a/icons/obj/clothing/glasses.dmi b/icons/obj/clothing/glasses.dmi index e8ba88a12f..4fce479a9d 100644 Binary files a/icons/obj/clothing/glasses.dmi and b/icons/obj/clothing/glasses.dmi differ diff --git a/icons/obj/clothing/hats.dmi b/icons/obj/clothing/hats.dmi index 60304999fa..8fbb2abe1e 100644 Binary files a/icons/obj/clothing/hats.dmi and b/icons/obj/clothing/hats.dmi differ diff --git a/icons/obj/clothing/suits.dmi b/icons/obj/clothing/suits.dmi index e8a360bc87..3476b16258 100644 Binary files a/icons/obj/clothing/suits.dmi and b/icons/obj/clothing/suits.dmi differ diff --git a/icons/obj/decals.dmi b/icons/obj/decals.dmi index c280ee786f..7dac61a663 100644 Binary files a/icons/obj/decals.dmi and b/icons/obj/decals.dmi differ diff --git a/icons/obj/eldritch.dmi b/icons/obj/eldritch.dmi new file mode 100644 index 0000000000..50c2913708 Binary files /dev/null and b/icons/obj/eldritch.dmi differ diff --git a/icons/obj/food/food.dmi b/icons/obj/food/food.dmi index 28cdefd331..078cadfd60 100644 Binary files a/icons/obj/food/food.dmi and b/icons/obj/food/food.dmi differ diff --git a/icons/obj/food/piecake.dmi b/icons/obj/food/piecake.dmi index 5638235217..935f7e8ad5 100644 Binary files a/icons/obj/food/piecake.dmi and b/icons/obj/food/piecake.dmi differ diff --git a/icons/obj/guns/projectile.dmi b/icons/obj/guns/projectile.dmi index 9c6df36f49..00670916db 100644 Binary files a/icons/obj/guns/projectile.dmi and b/icons/obj/guns/projectile.dmi differ diff --git a/icons/obj/hydroponics/growing.dmi b/icons/obj/hydroponics/growing.dmi index 5415f47528..0866791ed6 100644 Binary files a/icons/obj/hydroponics/growing.dmi and b/icons/obj/hydroponics/growing.dmi differ diff --git a/icons/obj/hydroponics/growing_vegetables.dmi b/icons/obj/hydroponics/growing_vegetables.dmi index e174b4fb0b..ce0beb86ce 100644 Binary files a/icons/obj/hydroponics/growing_vegetables.dmi and b/icons/obj/hydroponics/growing_vegetables.dmi differ diff --git a/icons/obj/items_and_weapons.dmi b/icons/obj/items_and_weapons.dmi index 57105cc089..c5aca2394f 100644 Binary files a/icons/obj/items_and_weapons.dmi and b/icons/obj/items_and_weapons.dmi differ diff --git a/icons/obj/janitor.dmi b/icons/obj/janitor.dmi index 1f520a42bd..b240391328 100644 Binary files a/icons/obj/janitor.dmi and b/icons/obj/janitor.dmi differ diff --git a/icons/obj/lavaland/terrain.dmi b/icons/obj/lavaland/terrain.dmi new file mode 100644 index 0000000000..4db51145ee Binary files /dev/null and b/icons/obj/lavaland/terrain.dmi differ diff --git a/icons/obj/license.txt b/icons/obj/license.txt new file mode 100644 index 0000000000..2e27ba80f2 --- /dev/null +++ b/icons/obj/license.txt @@ -0,0 +1,3 @@ +icons/obj/plushies.dmi's icon state of secdrake and meddrake by Mizartz. It has been licensed under the CC BY-NC-SA 3.0 license. + +CC BY-NC-SA 3.0 https://creativecommons.org/licenses/by-nc-sa/3.0/ \ No newline at end of file diff --git a/icons/obj/machines/medipen_refiller.dmi b/icons/obj/machines/medipen_refiller.dmi new file mode 100644 index 0000000000..300d218d2d Binary files /dev/null and b/icons/obj/machines/medipen_refiller.dmi differ diff --git a/icons/obj/machines/research.dmi b/icons/obj/machines/research.dmi index 7d64c494fd..7dcd4e6bcb 100644 Binary files a/icons/obj/machines/research.dmi and b/icons/obj/machines/research.dmi differ diff --git a/icons/obj/mafia.dmi b/icons/obj/mafia.dmi new file mode 100644 index 0000000000..c44b80aba1 Binary files /dev/null and b/icons/obj/mafia.dmi differ diff --git a/icons/obj/modular_console.dmi b/icons/obj/modular_console.dmi index cdcf6f1bd5..5d3cd0312c 100644 Binary files a/icons/obj/modular_console.dmi and b/icons/obj/modular_console.dmi differ diff --git a/icons/obj/modular_laptop.dmi b/icons/obj/modular_laptop.dmi index 7cf5a77621..fd24d27a97 100644 Binary files a/icons/obj/modular_laptop.dmi and b/icons/obj/modular_laptop.dmi differ diff --git a/icons/obj/modular_tablet.dmi b/icons/obj/modular_tablet.dmi index 2f9a0559ae..32edb57475 100644 Binary files a/icons/obj/modular_tablet.dmi and b/icons/obj/modular_tablet.dmi differ diff --git a/icons/obj/plumbing/fluid_ducts.dmi b/icons/obj/plumbing/fluid_ducts.dmi new file mode 100644 index 0000000000..87d9d2233b Binary files /dev/null and b/icons/obj/plumbing/fluid_ducts.dmi differ diff --git a/icons/obj/plumbing/plumbers.dmi b/icons/obj/plumbing/plumbers.dmi new file mode 100644 index 0000000000..242622e000 Binary files /dev/null and b/icons/obj/plumbing/plumbers.dmi differ diff --git a/icons/obj/plushes.dmi b/icons/obj/plushes.dmi index 11d02a46cc..ac0c338016 100644 Binary files a/icons/obj/plushes.dmi and b/icons/obj/plushes.dmi differ diff --git a/icons/obj/projectiles.dmi b/icons/obj/projectiles.dmi index 92e76f78bb..94568b8633 100644 Binary files a/icons/obj/projectiles.dmi and b/icons/obj/projectiles.dmi differ diff --git a/icons/obj/reagentfillings.dmi b/icons/obj/reagentfillings.dmi index d7a9a03c41..1ac941bae3 100644 Binary files a/icons/obj/reagentfillings.dmi and b/icons/obj/reagentfillings.dmi differ diff --git a/icons/obj/watercloset.dmi b/icons/obj/watercloset.dmi index 4a299f29dd..2b64176878 100644 Binary files a/icons/obj/watercloset.dmi and b/icons/obj/watercloset.dmi differ diff --git a/icons/turf/floors.dmi b/icons/turf/floors.dmi index 83dd4f5df8..f2b84bbe03 100644 Binary files a/icons/turf/floors.dmi and b/icons/turf/floors.dmi differ diff --git a/icons/turf/floors/glass.dmi b/icons/turf/floors/glass.dmi new file mode 100644 index 0000000000..adf6f57aaa Binary files /dev/null and b/icons/turf/floors/glass.dmi differ diff --git a/icons/turf/floors/reinf_glass.dmi b/icons/turf/floors/reinf_glass.dmi new file mode 100644 index 0000000000..dda99cd07f Binary files /dev/null and b/icons/turf/floors/reinf_glass.dmi differ diff --git a/modular_citadel/code/datums/status_effects/chems.dm b/modular_citadel/code/datums/status_effects/chems.dm index 4fa2a51fac..0e971d4ced 100644 --- a/modular_citadel/code/datums/status_effects/chems.dm +++ b/modular_citadel/code/datums/status_effects/chems.dm @@ -583,16 +583,6 @@ C.Stun(60) to_chat(owner, "Your muscles seize up, then start spasming wildy!") - //wah intensifies wah-rks - else if (lowertext(customTriggers[trigger]) == "cum")//aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa - if (lewd) - if(ishuman(C)) - var/mob/living/carbon/human/H = C - H.mob_climax(forced_climax=TRUE) - C.SetStun(10)//We got your stun effects in somewhere, Kev. - else - C.throw_at(get_step_towards(hearing_args[HEARING_SPEAKER],C), 3, 1) //cut this if it's too hard to get working - //kneel (knockdown) else if (lowertext(customTriggers[trigger]) == "kneel")//as close to kneeling as you can get, I suppose. to_chat(owner, "You drop to the ground unsurreptitiously.") @@ -674,15 +664,6 @@ deltaResist *= 1.25 if (owner.reagents.has_reagent(/datum/reagent/medicine/neurine)) deltaResist *= 1.5 - if (!(owner.client?.prefs.cit_toggles & NO_APHRO) && lewd) - if (owner.reagents.has_reagent(/datum/reagent/drug/anaphrodisiac)) - deltaResist *= 1.5 - if (owner.reagents.has_reagent(/datum/reagent/drug/anaphrodisiacplus)) - deltaResist *= 2 - if (owner.reagents.has_reagent(/datum/reagent/drug/aphrodisiac)) - deltaResist *= 0.75 - if (owner.reagents.has_reagent(/datum/reagent/drug/aphrodisiacplus)) - deltaResist *= 0.5 //Antag resistance //cultists are already brainwashed by their god if(iscultist(owner)) diff --git a/modular_citadel/code/modules/client/loadout/__donator.dm b/modular_citadel/code/modules/client/loadout/__donator.dm index 54dabba779..378c70d187 100644 --- a/modular_citadel/code/modules/client/loadout/__donator.dm +++ b/modular_citadel/code/modules/client/loadout/__donator.dm @@ -4,7 +4,7 @@ name = "IF YOU SEE THIS, PING A CODER RIGHT NOW!" slot = SLOT_IN_BACKPACK path = /obj/item/bikehorn/golden - category = CATEGORY_DONATOR + category = LOADOUT_CATEGORY_DONATOR ckeywhitelist = list("This entry should never appear with this variable set.") //If it does, then that means somebody fucked up the whitelist system pretty hard /datum/gear/donator/donortestingbikehorn diff --git a/modular_citadel/code/modules/client/loadout/_loadout.dm b/modular_citadel/code/modules/client/loadout/_loadout.dm index 9988519471..0ebfa060f2 100644 --- a/modular_citadel/code/modules/client/loadout/_loadout.dm +++ b/modular_citadel/code/modules/client/loadout/_loadout.dm @@ -27,7 +27,10 @@ GLOBAL_LIST_EMPTY(loadout_whitelist_ids) /proc/initialize_global_loadout_items() load_loadout_config() for(var/item in subtypesof(/datum/gear)) - var/datum/gear/I = new item + var/datum/gear/I = item + if(!initial(I.name)) + continue + I = new item LAZYINITLIST(GLOB.loadout_items[I.category]) LAZYINITLIST(GLOB.loadout_items[I.category][I.subcategory]) GLOB.loadout_items[I.category][I.subcategory][I.name] = I @@ -43,8 +46,8 @@ GLOBAL_LIST_EMPTY(loadout_whitelist_ids) /datum/gear var/name - var/category = "NOCATEGORY" - var/subcategory = "NOSUBCATEGORY" + var/category = LOADOUT_CATEGORY_NONE + var/subcategory = LOADOUT_SUBCATEGORY_NONE var/slot var/description var/path //item-to-spawn path diff --git a/modular_citadel/code/modules/client/loadout/_medical.dm b/modular_citadel/code/modules/client/loadout/_medical.dm index bba100faff..e371db94fc 100644 --- a/modular_citadel/code/modules/client/loadout/_medical.dm +++ b/modular_citadel/code/modules/client/loadout/_medical.dm @@ -11,21 +11,21 @@ /datum/gear/uniform/bluescrubs name = "Blue Scrubs" - subcategory = SUBCATEGORY_UNIFORM_JOBS + subcategory = LOADOUT_SUBCATEGORY_UNIFORM_JOBS path = /obj/item/clothing/under/rank/medical/doctor/blue restricted_roles = list("Medical Doctor", "Chief Medical Officer", "Geneticist", "Chemist", "Virologist") restricted_desc = "Medical" /datum/gear/uniform/greenscrubs name = "Green Scrubs" - subcategory = SUBCATEGORY_UNIFORM_JOBS + subcategory = LOADOUT_SUBCATEGORY_UNIFORM_JOBS path = /obj/item/clothing/under/rank/medical/doctor/green restricted_roles = list("Medical Doctor", "Chief Medical Officer", "Geneticist", "Chemist", "Virologist") restricted_desc = "Medical" /datum/gear/uniform/purplescrubs name = "Purple Scrubs" - subcategory = SUBCATEGORY_UNIFORM_JOBS + subcategory = LOADOUT_SUBCATEGORY_UNIFORM_JOBS path = /obj/item/clothing/under/rank/medical/doctor/purple restricted_roles = list("Medical Doctor", "Chief Medical Officer", "Geneticist", "Chemist", "Virologist") restricted_desc = "Medical" @@ -33,13 +33,13 @@ /datum/gear/head/nursehat name = "Nurse Hat" path = /obj/item/clothing/head/nursehat - subcategory = SUBCATEGORY_HEAD_JOBS + subcategory = LOADOUT_SUBCATEGORY_HEAD_JOBS restricted_roles = list("Medical Doctor", "Chief Medical Officer", "Geneticist", "Chemist", "Virologist") restricted_desc = "Medical" /datum/gear/uniform/nursesuit name = "Nurse Suit" path = /obj/item/clothing/under/rank/medical/doctor/nurse - subcategory = SUBCATEGORY_UNIFORM_JOBS + subcategory = LOADOUT_SUBCATEGORY_UNIFORM_JOBS restricted_roles = list("Medical Doctor", "Chief Medical Officer", "Geneticist", "Chemist", "Virologist") restricted_desc = "Medical" diff --git a/modular_citadel/code/modules/client/loadout/_security.dm b/modular_citadel/code/modules/client/loadout/_security.dm index 3ec39008c1..ab316d577b 100644 --- a/modular_citadel/code/modules/client/loadout/_security.dm +++ b/modular_citadel/code/modules/client/loadout/_security.dm @@ -1,70 +1,70 @@ /datum/gear/uniform/navyblueuniformhos name = "Head of Security navyblue uniform" - subcategory = SUBCATEGORY_UNIFORM_JOBS + subcategory = LOADOUT_SUBCATEGORY_UNIFORM_JOBS path = /obj/item/clothing/under/rank/security/head_of_security/formal restricted_roles = list("Head of Security") /datum/gear/head/navybluehosberet name = "Head of security's navyblue beret" path = /obj/item/clothing/head/beret/sec/navyhos - subcategory = SUBCATEGORY_HEAD_JOBS + subcategory = LOADOUT_SUBCATEGORY_HEAD_JOBS restricted_roles = list("Head of Security") /datum/gear/suit/navybluejackethos name = "head of security's navyblue jacket" - subcategory = SUBCATEGORY_SUIT_JOBS + subcategory = LOADOUT_SUBCATEGORY_SUIT_JOBS path = /obj/item/clothing/suit/armor/hos/navyblue restricted_roles = list("Head of Security") /datum/gear/suit/navybluejacketofficer name = "security officer's navyblue jacket" - subcategory = SUBCATEGORY_SUIT_JOBS + subcategory = LOADOUT_SUBCATEGORY_SUIT_JOBS path = /obj/item/clothing/suit/armor/navyblue restricted_roles = list("Security Officer") /datum/gear/head/navyblueofficerberet name = "Security officer's Navyblue beret" path = /obj/item/clothing/head/beret/sec/navyofficer - subcategory = SUBCATEGORY_HEAD_JOBS + subcategory = LOADOUT_SUBCATEGORY_HEAD_JOBS restricted_roles = list("Security Officer") /datum/gear/uniform/navyblueuniformofficer name = "Security officer navyblue uniform" - subcategory = SUBCATEGORY_UNIFORM_JOBS + subcategory = LOADOUT_SUBCATEGORY_UNIFORM_JOBS path = /obj/item/clothing/under/rank/security/officer/formal restricted_roles = list("Security Officer") /datum/gear/suit/navybluejacketwarden name = "warden navyblue jacket" - subcategory = SUBCATEGORY_SUIT_JOBS + subcategory = LOADOUT_SUBCATEGORY_SUIT_JOBS path = /obj/item/clothing/suit/armor/vest/warden/navyblue restricted_roles = list("Warden") /datum/gear/head/navybluewardenberet name = "Warden's navyblue beret" path = /obj/item/clothing/head/beret/sec/navywarden - subcategory = SUBCATEGORY_HEAD_JOBS + subcategory = LOADOUT_SUBCATEGORY_HEAD_JOBS restricted_roles = list("Warden") /datum/gear/uniform/navyblueuniformwarden name = "Warden navyblue uniform" - subcategory = SUBCATEGORY_UNIFORM_JOBS + subcategory = LOADOUT_SUBCATEGORY_UNIFORM_JOBS path = /obj/item/clothing/under/rank/security/warden/formal restricted_roles = list("Warden") /datum/gear/uniform/secskirt name = "Security skirt" - subcategory = SUBCATEGORY_UNIFORM_JOBS + subcategory = LOADOUT_SUBCATEGORY_UNIFORM_JOBS path = /obj/item/clothing/under/rank/security/officer/skirt restricted_roles = list("Security Officer", "Warden", "Head of Security") /datum/gear/uniform/hosskirt name = "Head of security's skirt" - subcategory = SUBCATEGORY_UNIFORM_JOBS + subcategory = LOADOUT_SUBCATEGORY_UNIFORM_JOBS path = /obj/item/clothing/under/rank/security/head_of_security/skirt restricted_roles = list("Head of Security") /datum/gear/glasses/sechud name = "Security Hud" path = /obj/item/clothing/glasses/hud/security - restricted_roles = list("Security Officer", "Warden", "Head of Security") \ No newline at end of file + restricted_roles = list("Security Officer", "Warden", "Head of Security") diff --git a/modular_citadel/code/modules/client/loadout/_service.dm b/modular_citadel/code/modules/client/loadout/_service.dm index 8949c04604..848ad6233c 100644 --- a/modular_citadel/code/modules/client/loadout/_service.dm +++ b/modular_citadel/code/modules/client/loadout/_service.dm @@ -1,33 +1,33 @@ /datum/gear/uniform/greytidestationwide name = "Staff Assistant's jumpsuit" path = /obj/item/clothing/under/misc/staffassistant - subcategory = SUBCATEGORY_UNIFORM_JOBS + subcategory = LOADOUT_SUBCATEGORY_UNIFORM_JOBS restricted_roles = list("Assistant") /datum/gear/suit/neetsuit name = "D.A.B. suit" path = /obj/item/clothing/suit/assu_suit - subcategory = SUBCATEGORY_UNIFORM_JOBS + subcategory = LOADOUT_SUBCATEGORY_UNIFORM_JOBS restricted_roles = list("Assistant") cost = 2 /datum/gear/head/neethelm name = "D.A.B. helmet" path = /obj/item/clothing/head/assu_helmet - subcategory = SUBCATEGORY_HEAD_JOBS + subcategory = LOADOUT_SUBCATEGORY_HEAD_JOBS restricted_roles = list("Assistant") cost = 2 /datum/gear/backpack/plushvar name = "Ratvar Plushie" path = /obj/item/toy/plush/plushvar - subcategory = SUBCATEGORY_BACKPACK_TOYS + subcategory = LOADOUT_SUBCATEGORY_BACKPACK_TOYS cost = 5 restricted_roles = list("Chaplain") /datum/gear/backpack/narplush name = "Narsie Plushie" path = /obj/item/toy/plush/narplush - subcategory = SUBCATEGORY_BACKPACK_TOYS + subcategory = LOADOUT_SUBCATEGORY_BACKPACK_TOYS cost = 5 restricted_roles = list("Chaplain") diff --git a/modular_citadel/code/modules/client/loadout/backpack.dm b/modular_citadel/code/modules/client/loadout/backpack.dm index fe308f5b23..0b700b11e2 100644 --- a/modular_citadel/code/modules/client/loadout/backpack.dm +++ b/modular_citadel/code/modules/client/loadout/backpack.dm @@ -1,17 +1,17 @@ /datum/gear/backpack - category = CATEGORY_BACKPACK - subcategory = SUBCATEGORY_BACKPACK_GENERAL + category = LOADOUT_CATEGORY_BACKPACK + subcategory = LOADOUT_SUBCATEGORY_BACKPACK_GENERAL slot = SLOT_IN_BACKPACK /datum/gear/backpack/plushbox name = "Plushie Choice Box" path = /obj/item/choice_beacon/box/plushie - subcategory = SUBCATEGORY_BACKPACK_TOYS + subcategory = LOADOUT_SUBCATEGORY_BACKPACK_TOYS /datum/gear/backpack/tennis name = "Classic Tennis Ball" path = /obj/item/toy/tennis - subcategory = SUBCATEGORY_BACKPACK_TOYS + subcategory = LOADOUT_SUBCATEGORY_BACKPACK_TOYS /datum/gear/backpack/tennis/red name = "Red Tennis Ball" @@ -40,12 +40,12 @@ /datum/gear/backpack/dildo name = "Customizable dildo" path = /obj/item/dildo/custom - subcategory = SUBCATEGORY_BACKPACK_TOYS + subcategory = LOADOUT_SUBCATEGORY_BACKPACK_TOYS /datum/gear/backpack/toykatana name = "Toy Katana" path = /obj/item/toy/katana - subcategory = SUBCATEGORY_BACKPACK_TOYS + subcategory = LOADOUT_SUBCATEGORY_BACKPACK_TOYS cost = 3 /datum/gear/backpack/tapeplayer @@ -63,7 +63,7 @@ /datum/gear/backpack/crayons name = "Box of crayons" path = /obj/item/storage/crayons - subcategory = SUBCATEGORY_BACKPACK_TOYS + subcategory = LOADOUT_SUBCATEGORY_BACKPACK_TOYS /datum/gear/backpack/multipen name = "A multicolored pen" @@ -98,3 +98,7 @@ name = "A diamond ring box" path = /obj/item/storage/fancy/ringbox/diamond cost = 5 + +/datum/gear/backpack/necklace//this is here because loadout doesn't support proper accessories + name = "A renameable necklace" + path = /obj/item/clothing/accessory/necklace diff --git a/modular_citadel/code/modules/client/loadout/glasses.dm b/modular_citadel/code/modules/client/loadout/glasses.dm index 65bb7ad23c..b0eecbbf28 100644 --- a/modular_citadel/code/modules/client/loadout/glasses.dm +++ b/modular_citadel/code/modules/client/loadout/glasses.dm @@ -1,5 +1,5 @@ /datum/gear/glasses - category = CATEGORY_GLASSES + category = LOADOUT_CATEGORY_GLASSES slot = SLOT_GLASSES /datum/gear/glasses/blindfold diff --git a/modular_citadel/code/modules/client/loadout/gloves.dm b/modular_citadel/code/modules/client/loadout/gloves.dm index 43323af43c..ffa4724f63 100644 --- a/modular_citadel/code/modules/client/loadout/gloves.dm +++ b/modular_citadel/code/modules/client/loadout/gloves.dm @@ -1,5 +1,5 @@ /datum/gear/gloves - category = CATEGORY_GLOVES + category = LOADOUT_CATEGORY_GLOVES slot = SLOT_GLOVES /datum/gear/gloves/fingerless @@ -24,3 +24,7 @@ name = "A diamond ring" path = /obj/item/clothing/gloves/ring/diamond cost = 4 + +/datum/gear/gloves/customring + name = "A ring, renameable" + path = /obj/item/clothing/gloves/ring/custom diff --git a/modular_citadel/code/modules/client/loadout/hands.dm b/modular_citadel/code/modules/client/loadout/hands.dm index ff4827e6bc..db57fb466b 100644 --- a/modular_citadel/code/modules/client/loadout/hands.dm +++ b/modular_citadel/code/modules/client/loadout/hands.dm @@ -1,5 +1,5 @@ /datum/gear/hands - category = CATEGORY_HANDS + category = LOADOUT_CATEGORY_HANDS slot = SLOT_HANDS /datum/gear/hands/cane diff --git a/modular_citadel/code/modules/client/loadout/head.dm b/modular_citadel/code/modules/client/loadout/head.dm index a1495aa7bd..fd03e2279f 100644 --- a/modular_citadel/code/modules/client/loadout/head.dm +++ b/modular_citadel/code/modules/client/loadout/head.dm @@ -1,6 +1,6 @@ /datum/gear/head - category = CATEGORY_HEAD - subcategory = SUBCATEGORY_HEAD_GENERAL + category = LOADOUT_CATEGORY_HEAD + subcategory = LOADOUT_SUBCATEGORY_HEAD_GENERAL slot = SLOT_HEAD /datum/gear/head/baseball @@ -63,33 +63,33 @@ /datum/gear/head/trekcap name = "Federation Officer's Cap (White)" path = /obj/item/clothing/head/caphat/formal/fedcover - subcategory = SUBCATEGORY_HEAD_JOBS + subcategory = LOADOUT_SUBCATEGORY_HEAD_JOBS restricted_roles = list("Captain","Head of Personnel") /datum/gear/head/trekcapcap name = "Federation Officer's Cap (Black)" path = /obj/item/clothing/head/caphat/formal/fedcover/black - subcategory = SUBCATEGORY_HEAD_JOBS + subcategory = LOADOUT_SUBCATEGORY_HEAD_JOBS restricted_roles = list("Captain","Head of Personnel") /datum/gear/head/trekcapmedisci name = "Federation Officer's Cap (Blue)" path = /obj/item/clothing/head/caphat/formal/fedcover/medsci - subcategory = SUBCATEGORY_HEAD_JOBS + subcategory = LOADOUT_SUBCATEGORY_HEAD_JOBS restricted_desc = "Medical and Science" restricted_roles = list("Chief Medical Officer","Medical Doctor","Chemist","Virologist","Paramedic","Geneticist","Research Director","Scientist", "Roboticist") /datum/gear/head/trekcapeng name = "Federation Officer's Cap (Yellow)" path = /obj/item/clothing/head/caphat/formal/fedcover/eng - subcategory = SUBCATEGORY_HEAD_JOBS + subcategory = LOADOUT_SUBCATEGORY_HEAD_JOBS restricted_desc = "Engineering, Security, and Cargo" restricted_roles = list("Chief Engineer","Atmospheric Technician","Station Engineer","Warden","Detective","Security Officer","Head of Security","Cargo Technician", "Shaft Miner", "Quartermaster") /datum/gear/head/trekcapsec name = "Federation Officer's Cap (Red)" path = /obj/item/clothing/head/caphat/formal/fedcover/sec - subcategory = SUBCATEGORY_HEAD_JOBS + subcategory = LOADOUT_SUBCATEGORY_HEAD_JOBS restricted_desc = "Engineering, Security, and Cargo" restricted_roles = list("Chief Engineer","Atmospheric Technician","Station Engineer","Warden","Detective","Security Officer","Head of Security","Cargo Technician", "Shaft Miner", "Quartermaster") @@ -98,7 +98,7 @@ name = "Federation Kepi, command" description = "A visored cap. Intended to be used with ORV uniform." path = /obj/item/clothing/head/kepi/orvi/command - subcategory = SUBCATEGORY_HEAD_JOBS + subcategory = LOADOUT_SUBCATEGORY_HEAD_JOBS restricted_desc = "Heads of Staff" restricted_roles = list("Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Research Director", "Chief Medical Officer", "Quartermaster") @@ -106,7 +106,7 @@ name = "Federation Kepi, ops/sec" description = "A visored cap. Intended to be used with ORV uniform." path = /obj/item/clothing/head/kepi/orvi/engsec - subcategory = SUBCATEGORY_HEAD_JOBS + subcategory = LOADOUT_SUBCATEGORY_HEAD_JOBS restricted_desc = "Engineering, Security and Cargo" restricted_roles = list("Chief Engineer", "Atmospheric Technician", "Station Engineer", "Warden", "Detective", "Security Officer", "Head of Security", "Cargo Technician", "Shaft Miner", "Quartermaster") @@ -114,7 +114,7 @@ name = "Federation Kepi, medsci" description = "A visored cap. Intended to be used with ORV uniform." path = /obj/item/clothing/head/kepi/orvi/medsci - subcategory = SUBCATEGORY_HEAD_JOBS + subcategory = LOADOUT_SUBCATEGORY_HEAD_JOBS restricted_desc = "Medical and Science" restricted_roles = list("Chief Medical Officer", "Medical Doctor", "Chemist", "Virologist", "Paramedic", "Geneticist", "Research Director", "Scientist", "Roboticist") @@ -122,7 +122,7 @@ name = "Federation Kepi, service" description = "A visored cap. Intended to be used with ORV uniform." path = /obj/item/clothing/head/kepi/orvi/service - subcategory = SUBCATEGORY_HEAD_JOBS + subcategory = LOADOUT_SUBCATEGORY_HEAD_JOBS restricted_desc = "Service and Civilian, barring Clown, Mime and Lawyer" restricted_roles = list("Assistant", "Bartender", "Botanist", "Cook", "Curator", "Janitor", "Chaplain") @@ -130,7 +130,7 @@ name = "Federation Kepi, assistant" description = "A visored cap. Intended to be used with ORV uniform." path = /obj/item/clothing/head/kepi/orvi - subcategory = SUBCATEGORY_HEAD_JOBS + subcategory = LOADOUT_SUBCATEGORY_HEAD_JOBS restricted_roles = list("Assistant") /*Commenting out Until next Christmas or made automatic @@ -165,7 +165,7 @@ /datum/gear/head/cowboyhat/sec name = "Cowboy Hat, Security" path = /obj/item/clothing/head/cowboyhat/sec - subcategory = SUBCATEGORY_HEAD_JOBS + subcategory = LOADOUT_SUBCATEGORY_HEAD_JOBS restricted_desc = "Security" restricted_roles = list("Warden","Detective","Security Officer","Head of Security") diff --git a/modular_citadel/code/modules/client/loadout/mask.dm b/modular_citadel/code/modules/client/loadout/mask.dm index ec77eba93c..0d7e32552e 100644 --- a/modular_citadel/code/modules/client/loadout/mask.dm +++ b/modular_citadel/code/modules/client/loadout/mask.dm @@ -1,5 +1,5 @@ /datum/gear/mask - category = CATEGORY_MASK + category = LOADOUT_CATEGORY_MASK slot = SLOT_WEAR_MASK /datum/gear/mask/balaclava diff --git a/modular_citadel/code/modules/client/loadout/neck.dm b/modular_citadel/code/modules/client/loadout/neck.dm index 2e8ec7001d..19311f703a 100644 --- a/modular_citadel/code/modules/client/loadout/neck.dm +++ b/modular_citadel/code/modules/client/loadout/neck.dm @@ -1,21 +1,21 @@ /datum/gear/neck - category = CATEGORY_NECK - subcategory = SUBCATEGORY_NECK_GENERAL + category = LOADOUT_CATEGORY_NECK + subcategory = LOADOUT_SUBCATEGORY_NECK_GENERAL slot = SLOT_NECK /datum/gear/neck/bluetie name = "Blue tie" - subcategory = SUBCATEGORY_NECK_TIE + subcategory = LOADOUT_SUBCATEGORY_NECK_TIE path = /obj/item/clothing/neck/tie/blue /datum/gear/neck/redtie name = "Red tie" - subcategory = SUBCATEGORY_NECK_TIE + subcategory = LOADOUT_SUBCATEGORY_NECK_TIE path = /obj/item/clothing/neck/tie/red /datum/gear/neck/blacktie name = "Black tie" - subcategory = SUBCATEGORY_NECK_TIE + subcategory = LOADOUT_SUBCATEGORY_NECK_TIE path = /obj/item/clothing/neck/tie/black /datum/gear/neck/collar @@ -32,7 +32,7 @@ /datum/gear/neck/scarf name = "White scarf" - subcategory = SUBCATEGORY_NECK_SCARVES + subcategory = LOADOUT_SUBCATEGORY_NECK_SCARVES path = /obj/item/clothing/neck/scarf /datum/gear/neck/scarf/black diff --git a/modular_citadel/code/modules/client/loadout/shoes.dm b/modular_citadel/code/modules/client/loadout/shoes.dm index f92ccbe17c..76d7305971 100644 --- a/modular_citadel/code/modules/client/loadout/shoes.dm +++ b/modular_citadel/code/modules/client/loadout/shoes.dm @@ -1,5 +1,5 @@ /datum/gear/shoes - category = CATEGORY_SHOES + category = LOADOUT_CATEGORY_SHOES slot = SLOT_SHOES /datum/gear/shoes/laceup diff --git a/modular_citadel/code/modules/client/loadout/suit.dm b/modular_citadel/code/modules/client/loadout/suit.dm index 539187af8b..d0be26a8a4 100644 --- a/modular_citadel/code/modules/client/loadout/suit.dm +++ b/modular_citadel/code/modules/client/loadout/suit.dm @@ -1,6 +1,6 @@ /datum/gear/suit - category = CATEGORY_SUIT - subcategory = SUBCATEGORY_SUIT_GENERAL + category = LOADOUT_CATEGORY_SUIT + subcategory = LOADOUT_SUBCATEGORY_SUIT_GENERAL slot = SLOT_WEAR_SUIT /datum/gear/suit/poncho @@ -23,67 +23,67 @@ /datum/gear/suit/jacketbomber name = "Bomber jacket" path = /obj/item/clothing/suit/jacket - subcategory = SUBCATEGORY_SUIT_JACKETS + subcategory = LOADOUT_SUBCATEGORY_SUIT_JACKETS /datum/gear/suit/jacketflannelblack // all of these are reskins of bomber jackets but with the vibe to make you look like a true lumberjack name = "Black flannel jacket" path = /obj/item/clothing/suit/jacket/flannel - subcategory = SUBCATEGORY_SUIT_JACKETS + subcategory = LOADOUT_SUBCATEGORY_SUIT_JACKETS /datum/gear/suit/jacketflannelred name = "Red flannel jacket" path = /obj/item/clothing/suit/jacket/flannel/red - subcategory = SUBCATEGORY_SUIT_JACKETS + subcategory = LOADOUT_SUBCATEGORY_SUIT_JACKETS /datum/gear/suit/jacketflannelaqua name = "Aqua flannel jacket" path = /obj/item/clothing/suit/jacket/flannel/aqua - subcategory = SUBCATEGORY_SUIT_JACKETS + subcategory = LOADOUT_SUBCATEGORY_SUIT_JACKETS /datum/gear/suit/jacketflannelbrown name = "Brown flannel jacket" path = /obj/item/clothing/suit/jacket/flannel/brown - subcategory = SUBCATEGORY_SUIT_JACKETS + subcategory = LOADOUT_SUBCATEGORY_SUIT_JACKETS /datum/gear/suit/jacketleather name = "Leather jacket" path = /obj/item/clothing/suit/jacket/leather - subcategory = SUBCATEGORY_SUIT_JACKETS + subcategory = LOADOUT_SUBCATEGORY_SUIT_JACKETS /datum/gear/suit/overcoatleather name = "Leather overcoat" path = /obj/item/clothing/suit/jacket/leather/overcoat - subcategory = SUBCATEGORY_SUIT_JACKETS + subcategory = LOADOUT_SUBCATEGORY_SUIT_JACKETS /datum/gear/suit/jacketpuffer name = "Puffer jacket" path = /obj/item/clothing/suit/jacket/puffer - subcategory = SUBCATEGORY_SUIT_JACKETS + subcategory = LOADOUT_SUBCATEGORY_SUIT_JACKETS /datum/gear/suit/vestpuffer name = "Puffer vest" path = /obj/item/clothing/suit/jacket/puffer/vest - subcategory = SUBCATEGORY_SUIT_JACKETS + subcategory = LOADOUT_SUBCATEGORY_SUIT_JACKETS /datum/gear/suit/jacketlettermanbrown name = "Brown letterman jacket" path = /obj/item/clothing/suit/jacket/letterman - subcategory = SUBCATEGORY_SUIT_JACKETS + subcategory = LOADOUT_SUBCATEGORY_SUIT_JACKETS /datum/gear/suit/jacketlettermanred name = "Red letterman jacket" path = /obj/item/clothing/suit/jacket/letterman_red - subcategory = SUBCATEGORY_SUIT_JACKETS + subcategory = LOADOUT_SUBCATEGORY_SUIT_JACKETS /datum/gear/suit/jacketlettermanNT name = "Nanotrasen letterman jacket" path = /obj/item/clothing/suit/jacket/letterman_nanotrasen - subcategory = SUBCATEGORY_SUIT_JACKETS + subcategory = LOADOUT_SUBCATEGORY_SUIT_JACKETS /datum/gear/suit/coat name = "Winter coat" path = /obj/item/clothing/suit/hooded/wintercoat - subcategory = SUBCATEGORY_SUIT_COATS + subcategory = LOADOUT_SUBCATEGORY_SUIT_COATS /datum/gear/suit/coat/aformal name = "Assistant's formal winter coat" @@ -155,7 +155,7 @@ /datum/gear/suit/militaryjacket name = "Military Jacket" path = /obj/item/clothing/suit/jacket/miljacket - subcategory = SUBCATEGORY_SUIT_JACKETS + subcategory = LOADOUT_SUBCATEGORY_SUIT_JACKETS /datum/gear/suit/ianshirt name = "Ian Shirt" @@ -164,13 +164,13 @@ /datum/gear/suit/flakjack name = "Flak Jacket" path = /obj/item/clothing/suit/flakjack - subcategory = SUBCATEGORY_SUIT_JACKETS + subcategory = LOADOUT_SUBCATEGORY_SUIT_JACKETS cost = 2 /datum/gear/suit/trekds9_coat name = "DS9 Overcoat (use uniform)" path = /obj/item/clothing/suit/storage/trek/ds9 - subcategory = SUBCATEGORY_SUIT_JOBS + subcategory = LOADOUT_SUBCATEGORY_SUIT_JOBS restricted_desc = "All, barring Service and Civilian" restricted_roles = list("Head of Security","Captain","Head of Personnel","Chief Engineer","Research Director","Chief Medical Officer","Quartermaster", "Medical Doctor","Chemist","Virologist","Paramedic","Geneticist","Scientist", "Roboticist", @@ -180,27 +180,27 @@ /datum/gear/suit/trekcmdcap name = "Fed (movie) uniform, Black" path = /obj/item/clothing/suit/storage/fluff/fedcoat/capt - subcategory = SUBCATEGORY_SUIT_JOBS + subcategory = LOADOUT_SUBCATEGORY_SUIT_JOBS restricted_roles = list("Captain","Head of Personnel") /datum/gear/suit/trekcmdmov name = "Fed (movie) uniform, Red" path = /obj/item/clothing/suit/storage/fluff/fedcoat - subcategory = SUBCATEGORY_SUIT_JOBS + subcategory = LOADOUT_SUBCATEGORY_SUIT_JOBS restricted_desc = "Heads of Staff and Security" restricted_roles = list("Head of Security","Captain","Head of Personnel","Chief Engineer","Research Director","Chief Medical Officer","Quartermaster","Warden","Detective","Security Officer") /datum/gear/suit/trekmedscimov name = "Fed (movie) uniform, Blue" path = /obj/item/clothing/suit/storage/fluff/fedcoat/medsci - subcategory = SUBCATEGORY_SUIT_JOBS + subcategory = LOADOUT_SUBCATEGORY_SUIT_JOBS restricted_desc = "Medical and Science" restricted_roles = list("Chief Medical Officer","Medical Doctor","Chemist","Virologist","Paramedic","Geneticist","Research Director","Scientist", "Roboticist") /datum/gear/suit/trekengmov name = "Fed (movie) uniform, Yellow" path = /obj/item/clothing/suit/storage/fluff/fedcoat/eng - subcategory = SUBCATEGORY_SUIT_JOBS + subcategory = LOADOUT_SUBCATEGORY_SUIT_JOBS restricted_desc = "Engineering and Cargo" restricted_roles = list("Chief Engineer","Atmospheric Technician","Station Engineer","Cargo Technician", "Shaft Miner", "Quartermaster") @@ -212,38 +212,38 @@ /datum/gear/suit/trekcmdmod name = "Fed (Modern) uniform, Red" path = /obj/item/clothing/suit/storage/fluff/modernfedcoat/sec - subcategory = SUBCATEGORY_SUIT_JOBS + subcategory = LOADOUT_SUBCATEGORY_SUIT_JOBS restricted_desc = "Heads of Staff and Security" restricted_roles = list("Head of Security","Captain","Head of Personnel","Chief Engineer","Research Director","Chief Medical Officer","Quartermaster","Warden","Detective","Security Officer") /datum/gear/suit/trekmedscimod name = "Fed (Modern) uniform, Blue" path = /obj/item/clothing/suit/storage/fluff/modernfedcoat/medsci - subcategory = SUBCATEGORY_SUIT_JOBS + subcategory = LOADOUT_SUBCATEGORY_SUIT_JOBS restricted_desc = "Medical and Science" restricted_roles = list("Chief Medical Officer","Medical Doctor","Chemist","Virologist","Paramedic","Geneticist","Research Director","Scientist", "Roboticist") /datum/gear/suit/trekengmod name = "Fed (Modern) uniform, Yellow" path = /obj/item/clothing/suit/storage/fluff/modernfedcoat/eng - subcategory = SUBCATEGORY_SUIT_JOBS + subcategory = LOADOUT_SUBCATEGORY_SUIT_JOBS restricted_desc = "Engineering and Cargo" restricted_roles = list("Chief Engineer","Atmospheric Technician","Station Engineer","Cargo Technician", "Shaft Miner", "Quartermaster") /datum/gear/suit/christmascoatr name = "Red Christmas Coat" path = /obj/item/clothing/suit/hooded/wintercoat/christmascoatr - subcategory = SUBCATEGORY_SUIT_COATS + subcategory = LOADOUT_SUBCATEGORY_SUIT_COATS /datum/gear/suit/christmascoatg name = "Green Christmas Coat" path = /obj/item/clothing/suit/hooded/wintercoat/christmascoatg - subcategory = SUBCATEGORY_SUIT_COATS + subcategory = LOADOUT_SUBCATEGORY_SUIT_COATS /datum/gear/suit/christmascoatrg name = "Red and Green Christmas Coat" path = /obj/item/clothing/suit/hooded/wintercoat/christmascoatrg - subcategory = SUBCATEGORY_SUIT_COATS + subcategory = LOADOUT_SUBCATEGORY_SUIT_COATS /datum/gear/suit/samurai name = "Samurai outfit" diff --git a/modular_citadel/code/modules/client/loadout/uniform.dm b/modular_citadel/code/modules/client/loadout/uniform.dm index e693f9d2f7..5ce73d1cfd 100644 --- a/modular_citadel/code/modules/client/loadout/uniform.dm +++ b/modular_citadel/code/modules/client/loadout/uniform.dm @@ -1,12 +1,12 @@ /datum/gear/uniform - category = CATEGORY_UNIFORM - subcategory = SUBCATEGORY_UNIFORM_GENERAL + category = LOADOUT_CATEGORY_UNIFORM + subcategory = LOADOUT_SUBCATEGORY_UNIFORM_GENERAL slot = SLOT_W_UNIFORM /datum/gear/uniform/suit name = "Black suit" path = /obj/item/clothing/under/suit/black - subcategory = SUBCATEGORY_UNIFORM_SUITS + subcategory = LOADOUT_SUBCATEGORY_UNIFORM_SUITS /datum/gear/uniform/suit/green name = "Green suit" @@ -51,7 +51,7 @@ /datum/gear/uniform/skirt name = "Black skirt" path = /obj/item/clothing/under/dress/skirt - subcategory = SUBCATEGORY_UNIFORM_SKIRTS + subcategory = LOADOUT_SUBCATEGORY_UNIFORM_SKIRTS /datum/gear/uniform/skirt/blue name = "Blue skirt" @@ -88,7 +88,7 @@ /datum/gear/uniform/dress name = "Striped Dress" path = /obj/item/clothing/under/dress/striped - subcategory = SUBCATEGORY_UNIFORM_DRESSES + subcategory = LOADOUT_SUBCATEGORY_UNIFORM_DRESSES /datum/gear/uniform/dress/sun/white name = "White Sundress" @@ -121,7 +121,7 @@ /datum/gear/uniform/pants name = "Yoga Pants" path = /obj/item/clothing/under/pants/yoga - subcategory = SUBCATEGORY_UNIFORM_PANTS + subcategory = LOADOUT_SUBCATEGORY_UNIFORM_PANTS /datum/gear/uniform/kilt name = "Kilt" @@ -134,7 +134,7 @@ /datum/gear/uniform/shorts name = "Athletic Shorts" path = /obj/item/clothing/under/shorts/red - subcategory = SUBCATEGORY_UNIFORM_SHORTS + subcategory = LOADOUT_SUBCATEGORY_UNIFORM_SHORTS /datum/gear/uniform/pants/bjeans name = "Black Jeans" @@ -185,7 +185,7 @@ /datum/gear/uniform/sweater name = "Cream Commando Sweater" path = /obj/item/clothing/under/sweater - subcategory = SUBCATEGORY_UNIFORM_SWEATERS + subcategory = LOADOUT_SUBCATEGORY_UNIFORM_SWEATERS /datum/gear/uniform/sweater/black name = "Black Commando Sweater" @@ -251,21 +251,21 @@ /datum/gear/uniform/trekcmdtos name = "TOS uniform, cmd" path = /obj/item/clothing/under/trek/command - subcategory = SUBCATEGORY_UNIFORM_JOBS + subcategory = LOADOUT_SUBCATEGORY_UNIFORM_JOBS restricted_desc = "Heads of Staff" restricted_roles = list("Head of Security","Captain","Head of Personnel","Chief Engineer","Research Director","Chief Medical Officer","Quartermaster") /datum/gear/uniform/trekmedscitos name = "TOS uniform, med/sci" path = /obj/item/clothing/under/trek/medsci - subcategory = SUBCATEGORY_UNIFORM_JOBS + subcategory = LOADOUT_SUBCATEGORY_UNIFORM_JOBS restricted_desc = "Medical and Science" restricted_roles = list("Chief Medical Officer","Medical Doctor","Chemist","Virologist","Paramedic","Geneticist","Research Director","Scientist", "Roboticist") /datum/gear/uniform/trekengtos name = "TOS uniform, ops/sec" path = /obj/item/clothing/under/trek/engsec - subcategory = SUBCATEGORY_UNIFORM_JOBS + subcategory = LOADOUT_SUBCATEGORY_UNIFORM_JOBS restricted_desc = "Engineering, Security, and Cargo" restricted_roles = list("Chief Engineer","Atmospheric Technician","Station Engineer","Warden","Detective","Security Officer","Head of Security","Cargo Technician", "Shaft Miner", "Quartermaster") @@ -273,21 +273,21 @@ /datum/gear/uniform/trekcmdtng name = "TNG uniform, cmd" path = /obj/item/clothing/under/trek/command/next - subcategory = SUBCATEGORY_UNIFORM_JOBS + subcategory = LOADOUT_SUBCATEGORY_UNIFORM_JOBS restricted_desc = "Heads of Staff" restricted_roles = list("Head of Security","Captain","Head of Personnel","Chief Engineer","Research Director","Chief Medical Officer","Quartermaster") /datum/gear/uniform/trekmedscitng name = "TNG uniform, med/sci" path = /obj/item/clothing/under/trek/medsci/next - subcategory = SUBCATEGORY_UNIFORM_JOBS + subcategory = LOADOUT_SUBCATEGORY_UNIFORM_JOBS restricted_desc = "Medical and Science" restricted_roles = list("Chief Medical Officer","Medical Doctor","Chemist","Virologist","Paramedic","Geneticist","Research Director","Scientist", "Roboticist") /datum/gear/uniform/trekengtng name = "TNG uniform, ops/sec" path = /obj/item/clothing/under/trek/engsec/next - subcategory = SUBCATEGORY_UNIFORM_JOBS + subcategory = LOADOUT_SUBCATEGORY_UNIFORM_JOBS restricted_desc = "Engineering, Security, and Cargo" restricted_roles = list("Chief Engineer","Atmospheric Technician","Station Engineer","Warden","Detective","Security Officer","Head of Security","Cargo Technician", "Shaft Miner", "Quartermaster") @@ -295,21 +295,21 @@ /datum/gear/uniform/trekcmdvoy name = "VOY uniform, cmd" path = /obj/item/clothing/under/trek/command/voy - subcategory = SUBCATEGORY_UNIFORM_JOBS + subcategory = LOADOUT_SUBCATEGORY_UNIFORM_JOBS restricted_desc = "Heads of Staff" restricted_roles = list("Head of Security","Captain","Head of Personnel","Chief Engineer","Research Director","Chief Medical Officer","Quartermaster") /datum/gear/uniform/trekmedscivoy name = "VOY uniform, med/sci" path = /obj/item/clothing/under/trek/medsci/voy - subcategory = SUBCATEGORY_UNIFORM_JOBS + subcategory = LOADOUT_SUBCATEGORY_UNIFORM_JOBS restricted_desc = "Medical and Science" restricted_roles = list("Chief Medical Officer","Medical Doctor","Chemist","Virologist","Paramedic","Geneticist","Research Director","Scientist", "Roboticist") /datum/gear/uniform/trekengvoy name = "VOY uniform, ops/sec" path = /obj/item/clothing/under/trek/engsec/voy - subcategory = SUBCATEGORY_UNIFORM_JOBS + subcategory = LOADOUT_SUBCATEGORY_UNIFORM_JOBS restricted_desc = "Engineering, Security, and Cargo" restricted_roles = list("Chief Engineer","Atmospheric Technician","Station Engineer","Warden","Detective","Security Officer","Head of Security","Cargo Technician", "Shaft Miner", "Quartermaster") @@ -317,21 +317,21 @@ /datum/gear/uniform/trekcmdds9 name = "DS9 uniform, cmd" path = /obj/item/clothing/under/trek/command/ds9 - subcategory = SUBCATEGORY_UNIFORM_JOBS + subcategory = LOADOUT_SUBCATEGORY_UNIFORM_JOBS restricted_desc = "Heads of Staff" restricted_roles = list("Head of Security","Captain","Head of Personnel","Chief Engineer","Research Director","Chief Medical Officer","Quartermaster") /datum/gear/uniform/trekmedscids9 name = "DS9 uniform, med/sci" path = /obj/item/clothing/under/trek/medsci/ds9 - subcategory = SUBCATEGORY_UNIFORM_JOBS + subcategory = LOADOUT_SUBCATEGORY_UNIFORM_JOBS restricted_desc = "Medical and Science" restricted_roles = list("Chief Medical Officer","Medical Doctor","Chemist","Virologist","Paramedic","Geneticist","Research Director","Scientist", "Roboticist") /datum/gear/uniform/trekengds9 name = "DS9 uniform, ops/sec" path = /obj/item/clothing/under/trek/engsec/ds9 - subcategory = SUBCATEGORY_UNIFORM_JOBS + subcategory = LOADOUT_SUBCATEGORY_UNIFORM_JOBS restricted_desc = "Engineering, Security, and Cargo" restricted_roles = list("Chief Engineer","Atmospheric Technician","Station Engineer","Warden","Detective","Security Officer","Head of Security","Cargo Technician", "Shaft Miner", "Quartermaster") @@ -339,21 +339,21 @@ /datum/gear/uniform/trekcmdent name = "ENT uniform, cmd" path = /obj/item/clothing/under/trek/command/ent - subcategory = SUBCATEGORY_UNIFORM_JOBS + subcategory = LOADOUT_SUBCATEGORY_UNIFORM_JOBS restricted_desc = "Heads of Staff" restricted_roles = list("Head of Security","Captain","Head of Personnel","Chief Engineer","Research Director","Chief Medical Officer","Quartermaster") /datum/gear/uniform/trekmedscient name = "ENT uniform, med/sci" path = /obj/item/clothing/under/trek/medsci/ent - subcategory = SUBCATEGORY_UNIFORM_JOBS + subcategory = LOADOUT_SUBCATEGORY_UNIFORM_JOBS restricted_desc = "Medical and Science" restricted_roles = list("Chief Medical Officer","Medical Doctor","Chemist","Virologist","Paramedic","Geneticist","Research Director","Scientist", "Roboticist") /datum/gear/uniform/trekengent name = "ENT uniform, ops/sec" path = /obj/item/clothing/under/trek/engsec/ent - subcategory = SUBCATEGORY_UNIFORM_JOBS + subcategory = LOADOUT_SUBCATEGORY_UNIFORM_JOBS restricted_desc = "Engineering, Security, and Cargo" restricted_roles = list("Chief Engineer","Atmospheric Technician","Station Engineer","Warden","Detective","Security Officer","Head of Security","Cargo Technician", "Shaft Miner", "Quartermaster") @@ -361,7 +361,7 @@ /datum/gear/uniform/trekfedutil name = "TMP uniform" path = /obj/item/clothing/under/trek/fedutil - subcategory = SUBCATEGORY_UNIFORM_JOBS + subcategory = LOADOUT_SUBCATEGORY_UNIFORM_JOBS restricted_desc = "All, barring Service and Civilian" restricted_roles = list("Head of Security","Captain","Head of Personnel","Chief Engineer","Research Director","Chief Medical Officer","Quartermaster", "Medical Doctor","Chemist","Virologist","Paramedic","Geneticist","Scientist", "Roboticist", @@ -371,13 +371,13 @@ /datum/gear/uniform/trekfedtrainee name = "TMP uniform, trainee" path = /obj/item/clothing/under/trek/fedutil/trainee - subcategory = SUBCATEGORY_UNIFORM_JOBS + subcategory = LOADOUT_SUBCATEGORY_UNIFORM_JOBS restricted_roles = list("Assistant", "Janitor", "Cargo Technician") /datum/gear/uniform/trekfedservice name = "TMP uniform, service" path = /obj/item/clothing/under/trek/fedutil/service - subcategory = SUBCATEGORY_UNIFORM_JOBS + subcategory = LOADOUT_SUBCATEGORY_UNIFORM_JOBS restricted_desc = "Service and Civilian, barring Clown, Mime and Lawyer" restricted_roles = list("Assistant", "Bartender", "Botanist", "Cook", "Curator", "Janitor", "Chaplain") @@ -385,52 +385,52 @@ /datum/gear/uniform/orvcmd name = "ORV uniform, cmd" path = /obj/item/clothing/under/trek/command/orv - subcategory = SUBCATEGORY_UNIFORM_JOBS + subcategory = LOADOUT_SUBCATEGORY_UNIFORM_JOBS restricted_desc = "Heads of Staff" restricted_roles = list("Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Research Director", "Chief Medical Officer", "Quartermaster") /datum/gear/uniform/orvcmd_capt name = "ORV uniform, capt" - subcategory = SUBCATEGORY_UNIFORM_JOBS + subcategory = LOADOUT_SUBCATEGORY_UNIFORM_JOBS path = /obj/item/clothing/under/trek/command/orv/captain restricted_roles = list("Captain") /datum/gear/uniform/orvmedsci name = "ORV uniform, med/sci" path = /obj/item/clothing/under/trek/medsci/orv - subcategory = SUBCATEGORY_UNIFORM_JOBS + subcategory = LOADOUT_SUBCATEGORY_UNIFORM_JOBS restricted_desc = "Medical and Science" restricted_roles = list("Chief Medical Officer", "Medical Doctor", "Chemist", "Virologist", "Paramedic", "Geneticist", "Research Director", "Scientist", "Roboticist") /datum/gear/uniform/orvcmd_medsci name = "ORV uniform, med/sci, cmd" path = /obj/item/clothing/under/trek/command/orv/medsci - subcategory = SUBCATEGORY_UNIFORM_JOBS + subcategory = LOADOUT_SUBCATEGORY_UNIFORM_JOBS restricted_roles = list("Chief Medical Officer", "Research Director") /datum/gear/uniform/orvops name = "ORV uniform, ops/sec" path = /obj/item/clothing/under/trek/engsec/orv - subcategory = SUBCATEGORY_UNIFORM_JOBS + subcategory = LOADOUT_SUBCATEGORY_UNIFORM_JOBS restricted_desc = "Engineering, Security and Cargo" restricted_roles = list("Chief Engineer", "Atmospheric Technician", "Station Engineer", "Warden", "Detective", "Security Officer", "Head of Security", "Cargo Technician", "Shaft Miner", "Quartermaster") /datum/gear/uniform/orvcmd_ops name = "ORV uniform, ops/sec, cmd" path = /obj/item/clothing/under/trek/command/orv/engsec - subcategory = SUBCATEGORY_UNIFORM_JOBS + subcategory = LOADOUT_SUBCATEGORY_UNIFORM_JOBS restricted_roles = list("Chief Engineer", "Head of Security") /datum/gear/uniform/orvass name = "ORV uniform, assistant" path = /obj/item/clothing/under/trek/orv - subcategory = SUBCATEGORY_UNIFORM_JOBS + subcategory = LOADOUT_SUBCATEGORY_UNIFORM_JOBS restricted_roles = list("Assistant") /datum/gear/uniform/orvsrv name = "ORV uniform, service" path = /obj/item/clothing/under/trek/orv/service - subcategory = SUBCATEGORY_UNIFORM_JOBS + subcategory = LOADOUT_SUBCATEGORY_UNIFORM_JOBS restricted_roles = list("Assistant", "Bartender", "Botanist", "Cook", "Curator", "Janitor", "Chaplain") restricted_desc = "Service and Civilian, barring Clown, Mime and Lawyer" @@ -476,37 +476,37 @@ /datum/gear/uniform/qipao name = "Qipao, Black" path = /obj/item/clothing/under/costume/qipao - subcategory = SUBCATEGORY_UNIFORM_DRESSES + subcategory = LOADOUT_SUBCATEGORY_UNIFORM_DRESSES cost = 3 /datum/gear/uniform/qipao/white name = "Qipao, White" path = /obj/item/clothing/under/costume/qipao/white - subcategory = SUBCATEGORY_UNIFORM_DRESSES + subcategory = LOADOUT_SUBCATEGORY_UNIFORM_DRESSES cost = 3 /datum/gear/uniform/qipao/red name = "Qipao, Red" path = /obj/item/clothing/under/costume/qipao/red - subcategory = SUBCATEGORY_UNIFORM_DRESSES + subcategory = LOADOUT_SUBCATEGORY_UNIFORM_DRESSES cost = 3 /datum/gear/uniform/cheongsam name = "Cheongsam, Black" path = /obj/item/clothing/under/costume/cheongsam - subcategory = SUBCATEGORY_UNIFORM_DRESSES + subcategory = LOADOUT_SUBCATEGORY_UNIFORM_DRESSES cost = 3 /datum/gear/uniform/cheongsam/white name = "Cheongsam, White" path = /obj/item/clothing/under/costume/cheongsam/white - subcategory = SUBCATEGORY_UNIFORM_DRESSES + subcategory = LOADOUT_SUBCATEGORY_UNIFORM_DRESSES cost = 3 /datum/gear/uniform/cheongsam/red name = "Cheongsam, Red" path = /obj/item/clothing/under/costume/cheongsam/red - subcategory = SUBCATEGORY_UNIFORM_DRESSES + subcategory = LOADOUT_SUBCATEGORY_UNIFORM_DRESSES cost = 3 /datum/gear/uniform/dress/black @@ -539,4 +539,4 @@ /datum/gear/uniform/kimono/sakura name = "Sakura kimono" - path = /obj/item/clothing/under/costume/kimono/sakura \ No newline at end of file + path = /obj/item/clothing/under/costume/kimono/sakura diff --git a/modular_citadel/code/modules/projectiles/guns/ballistic/handguns.dm b/modular_citadel/code/modules/projectiles/guns/ballistic/handguns.dm index 20917c4ba5..4829fd921c 100644 --- a/modular_citadel/code/modules/projectiles/guns/ballistic/handguns.dm +++ b/modular_citadel/code/modules/projectiles/guns/ballistic/handguns.dm @@ -16,13 +16,12 @@ spread = 20 actions_types = list() -/obj/item/gun/ballistic/automatic/toy/pistol/stealth/update_icon() - ..() +/obj/item/gun/ballistic/automatic/toy/pistol/stealth/update_overlays() + . = ..() if(magazine) - cut_overlays() - add_overlay("foamsp-magazine") - else - cut_overlays() + . += "foamsp-magazine" + +/obj/item/gun/ballistic/automatic/toy/pistol/stealth/update_icon_state() icon_state = "[initial(icon_state)][chambered ? "" : "-e"]" /////////RAYGUN MEMES///////// diff --git a/modular_citadel/code/modules/projectiles/guns/ballistic/rifles.dm b/modular_citadel/code/modules/projectiles/guns/ballistic/rifles.dm index 8a1310d2f1..c2bf251de9 100644 --- a/modular_citadel/code/modules/projectiles/guns/ballistic/rifles.dm +++ b/modular_citadel/code/modules/projectiles/guns/ballistic/rifles.dm @@ -155,11 +155,15 @@ casing_ejector = 0 spread = 10 recoil = 0.05 + automatic_burst_overlay = FALSE + var/magtype = "flechettegun" -/obj/item/gun/ballistic/automatic/flechette/update_icon() - cut_overlays() +/obj/item/gun/ballistic/automatic/flechette/update_overlays() + . = ..() if(magazine) - add_overlay("flechettegun-magazine") + . += "[magtype]-magazine" + +/obj/item/gun/ballistic/automatic/flechette/update_icon_state() icon_state = "[initial(icon_state)][chambered ? "" : "-e"]" ///unique variant/// @@ -185,12 +189,7 @@ w_class = WEIGHT_CLASS_SMALL spread = 15 recoil = 0.1 - -/obj/item/gun/ballistic/automatic/flechette/shredder/update_icon() - cut_overlays() - if(magazine) - add_overlay("shreddergun-magazine") - icon_state = "[initial(icon_state)][chambered ? "" : "-e"]" + magtype = "shreddergun" /*///////////////////////////////////////////////////////////// //////////////////////// Zero's Meme ////////////////////////// @@ -218,17 +217,19 @@ burst_size = 4 //Shh. fire_delay = 1 var/body_color = "#3333aa" + automatic_burst_overlay = FALSE -/obj/item/gun/ballistic/automatic/AM4B/update_icon() - ..() +/obj/item/gun/ballistic/automatic/AM4B/ComponentInitialize() + . = ..() + AddElement(/datum/element/update_icon_updates_onmob) + +/obj/item/gun/ballistic/automatic/AM4B/update_overlays() + . = ..() var/mutable_appearance/body_overlay = mutable_appearance('modular_citadel/icons/obj/guns/cit_guns.dmi', "AM4-Body") if(body_color) body_overlay.color = body_color - cut_overlays() //So that it doesn't keep stacking overlays non-stop on top of each other - add_overlay(body_overlay) - if(ismob(loc)) - var/mob/M = loc - M.update_inv_hands() + . += body_overlay + /obj/item/gun/ballistic/automatic/AM4B/AltClick(mob/living/user) . = ..() if(!in_range(src, user)) //Basic checks to prevent abuse diff --git a/modular_citadel/code/modules/projectiles/guns/ballistic/spinfusor.dm b/modular_citadel/code/modules/projectiles/guns/ballistic/spinfusor.dm index 3c0a47bfd7..c4cf8fc00f 100644 --- a/modular_citadel/code/modules/projectiles/guns/ballistic/spinfusor.dm +++ b/modular_citadel/code/modules/projectiles/guns/ballistic/spinfusor.dm @@ -55,8 +55,7 @@ /obj/item/gun/ballistic/automatic/spinfusor/attack_self(mob/living/user) return //caseless rounds are too glitchy to unload properly. Best to make it so that you cannot remove disks from the spinfusor -/obj/item/gun/ballistic/automatic/spinfusor/update_icon() - ..() +/obj/item/gun/ballistic/automatic/spinfusor/update_icon_state() icon_state = "spinfusor[magazine ? "-[get_ammo(1)]" : ""]" /obj/item/ammo_box/aspinfusor diff --git a/modular_citadel/code/modules/projectiles/guns/energy/energy_gun.dm b/modular_citadel/code/modules/projectiles/guns/energy/energy_gun.dm index 49d48e0000..65609f5830 100644 --- a/modular_citadel/code/modules/projectiles/guns/energy/energy_gun.dm +++ b/modular_citadel/code/modules/projectiles/guns/energy/energy_gun.dm @@ -14,16 +14,16 @@ obj/item/gun/energy/e_gun/cx flight_y_offset = 10 var/body_color = "#252528" -obj/item/gun/energy/e_gun/cx/update_icon() - ..() +obj/item/gun/energy/e_gun/cx/ComponentInitialize() + . = ..() + AddElement(/datum/element/update_icon_updates_onmob) + +obj/item/gun/energy/e_gun/cx/update_overlays() + . = ..() var/mutable_appearance/body_overlay = mutable_appearance('modular_citadel/icons/obj/guns/cit_guns.dmi', "cxegun_body") if(body_color) body_overlay.color = body_color - add_overlay(body_overlay) - - if(ismob(loc)) - var/mob/M = loc - M.update_inv_hands() + . += body_overlay obj/item/gun/energy/e_gun/cx/AltClick(mob/living/user) . = ..() diff --git a/modular_citadel/code/modules/projectiles/guns/pumpenergy.dm b/modular_citadel/code/modules/projectiles/guns/pumpenergy.dm index 03a124e306..e81c7c18d3 100644 --- a/modular_citadel/code/modules/projectiles/guns/pumpenergy.dm +++ b/modular_citadel/code/modules/projectiles/guns/pumpenergy.dm @@ -12,7 +12,7 @@ /obj/item/gun/energy/pumpaction/emp_act(severity) //makes it not rack itself when emp'd cell.use(round(cell.charge / severity)) - chambered = 0 //we empty the chamber + chambered = null //we empty the chamber update_icon() /obj/item/gun/energy/pumpaction/process() //makes it not rack itself when self-charging @@ -20,7 +20,7 @@ charge_tick++ if(charge_tick < charge_delay) return - charge_tick = 0 + charge_tick = null if(selfcharge == EGUN_SELFCHARGE_BORG) var/atom/owner = loc if(istype(owner, /obj/item/robot_module)) @@ -44,7 +44,7 @@ if(chambered && !chambered.BB) //if BB is null, i.e the shot has been fired... var/obj/item/ammo_casing/energy/shot = chambered cell.use(shot.e_cost)//... drain the cell cell - chambered = 0 //either way, released the prepared shot + chambered = null //either way, released the prepared shot /obj/item/gun/energy/pumpaction/post_set_firemode() var/has_shot = chambered @@ -52,13 +52,13 @@ if(has_shot) recharge_newshot(TRUE) -/obj/item/gun/energy/pumpaction/update_icon() //adds racked indicators +/obj/item/gun/energy/pumpaction/update_overlays() //adds racked indicators ..() var/obj/item/ammo_casing/energy/shot = ammo_type[current_firemode_index] if(chambered) - add_overlay("[icon_state]_rack_[shot.select_name]") + . += "[icon_state]_rack_[shot.select_name]" else - add_overlay("[icon_state]_rack_empty") + . += "[icon_state]_rack_empty" /obj/item/gun/energy/pumpaction/proc/pump(mob/M) //pumping proc. Checks if the gun is empty and plays a different sound if it is. var/obj/item/ammo_casing/energy/shot = ammo_type[current_firemode_index] diff --git a/modular_citadel/code/modules/reagents/chemistry/recipes/fermi.dm b/modular_citadel/code/modules/reagents/chemistry/recipes/fermi.dm index a24a5beaad..39ba69bd61 100644 --- a/modular_citadel/code/modules/reagents/chemistry/recipes/fermi.dm +++ b/modular_citadel/code/modules/reagents/chemistry/recipes/fermi.dm @@ -178,7 +178,7 @@ name = "Sucubus milk" id = /datum/reagent/fermi/breast_enlarger results = list(/datum/reagent/fermi/breast_enlarger = 8) - required_reagents = list(/datum/reagent/medicine/salglu_solution = 1, /datum/reagent/consumable/milk = 1, /datum/reagent/medicine/synthflesh = 2, /datum/reagent/silicon = 3, /datum/reagent/drug/aphrodisiac = 3) + required_reagents = list(/datum/reagent/medicine/salglu_solution = 2, /datum/reagent/consumable/milk = 1, /datum/reagent/medicine/synthflesh = 2, /datum/reagent/silicon = 5) mix_message = "the reaction gives off a mist of milk." //FermiChem vars: OptimalTempMin = 200 @@ -218,7 +218,7 @@ name = "Incubus draft" id = /datum/reagent/fermi/penis_enlarger results = list(/datum/reagent/fermi/penis_enlarger = 8) - required_reagents = list(/datum/reagent/blood = 5, /datum/reagent/medicine/synthflesh = 2, /datum/reagent/carbon = 2, /datum/reagent/drug/aphrodisiac = 2, /datum/reagent/medicine/salglu_solution = 1) + required_reagents = list(/datum/reagent/blood = 5, /datum/reagent/medicine/synthflesh = 2, /datum/reagent/carbon = 5, /datum/reagent/medicine/salglu_solution = 2) mix_message = "the reaction gives off a spicy mist." //FermiChem vars: OptimalTempMin = 200 @@ -384,7 +384,7 @@ name = "Furranium" id = /datum/reagent/fermi/furranium results = list(/datum/reagent/fermi/furranium = 5) - required_reagents = list(/datum/reagent/drug/aphrodisiac = 1, /datum/reagent/moonsugar = 1, /datum/reagent/silver = 2, /datum/reagent/medicine/salglu_solution = 1) + required_reagents = list(/datum/reagent/pax/catnip = 1, /datum/reagent/silver = 2, /datum/reagent/medicine/salglu_solution = 2) mix_message = "You think you can hear a howl come from the beaker." //FermiChem vars: OptimalTempMin = 350 @@ -402,10 +402,6 @@ FermiChem = TRUE PurityMin = 0.3 -/datum/chemical_reaction/fermi/furranium/organic - id = "furranium_organic" - required_reagents = list(/datum/reagent/drug/aphrodisiac = 1, /datum/reagent/pax/catnip = 1, /datum/reagent/silver = 2, /datum/reagent/medicine/salglu_solution = 1) - //FOR INSTANT REACTIONS - DO NOT MULTIPLY LIMIT BY 10. //There's a weird rounding error or something ugh. @@ -607,4 +603,4 @@ ThermicConstant = 0 HIonRelease = 0.01 RateUpLim = 15 - FermiChem = TRUE \ No newline at end of file + FermiChem = TRUE diff --git a/modular_citadel/icons/mob/mam_snouts.dmi b/modular_citadel/icons/mob/mam_snouts.dmi index ab1a4654b4..4f6682f789 100644 Binary files a/modular_citadel/icons/mob/mam_snouts.dmi and b/modular_citadel/icons/mob/mam_snouts.dmi differ diff --git a/modular_citadel/icons/mob/widerobot.dmi b/modular_citadel/icons/mob/widerobot.dmi index 50c29bb75f..29eb35c715 100644 Binary files a/modular_citadel/icons/mob/widerobot.dmi and b/modular_citadel/icons/mob/widerobot.dmi differ diff --git a/sound/ambience/antag/ecult_op.ogg b/sound/ambience/antag/ecult_op.ogg new file mode 100644 index 0000000000..9944e833a6 Binary files /dev/null and b/sound/ambience/antag/ecult_op.ogg differ diff --git a/sound/effects/footstep/rustystep1.ogg b/sound/effects/footstep/rustystep1.ogg new file mode 100644 index 0000000000..bf90d52779 Binary files /dev/null and b/sound/effects/footstep/rustystep1.ogg differ diff --git a/sound/machines/sm/accent/delam/1.ogg b/sound/machines/sm/accent/delam/1.ogg new file mode 100644 index 0000000000..75c79f89ab Binary files /dev/null and b/sound/machines/sm/accent/delam/1.ogg differ diff --git a/sound/machines/sm/accent/delam/10.ogg b/sound/machines/sm/accent/delam/10.ogg new file mode 100644 index 0000000000..c87b63b526 Binary files /dev/null and b/sound/machines/sm/accent/delam/10.ogg differ diff --git a/sound/machines/sm/accent/delam/11.ogg b/sound/machines/sm/accent/delam/11.ogg new file mode 100644 index 0000000000..c7f678245b Binary files /dev/null and b/sound/machines/sm/accent/delam/11.ogg differ diff --git a/sound/machines/sm/accent/delam/12.ogg b/sound/machines/sm/accent/delam/12.ogg new file mode 100644 index 0000000000..a395942183 Binary files /dev/null and b/sound/machines/sm/accent/delam/12.ogg differ diff --git a/sound/machines/sm/accent/delam/13.ogg b/sound/machines/sm/accent/delam/13.ogg new file mode 100644 index 0000000000..934f17947d Binary files /dev/null and b/sound/machines/sm/accent/delam/13.ogg differ diff --git a/sound/machines/sm/accent/delam/14.ogg b/sound/machines/sm/accent/delam/14.ogg new file mode 100644 index 0000000000..4175e5b947 Binary files /dev/null and b/sound/machines/sm/accent/delam/14.ogg differ diff --git a/sound/machines/sm/accent/delam/15.ogg b/sound/machines/sm/accent/delam/15.ogg new file mode 100644 index 0000000000..dcf73deb84 Binary files /dev/null and b/sound/machines/sm/accent/delam/15.ogg differ diff --git a/sound/machines/sm/accent/delam/16.ogg b/sound/machines/sm/accent/delam/16.ogg new file mode 100644 index 0000000000..20bc19399b Binary files /dev/null and b/sound/machines/sm/accent/delam/16.ogg differ diff --git a/sound/machines/sm/accent/delam/17.ogg b/sound/machines/sm/accent/delam/17.ogg new file mode 100644 index 0000000000..b517fb3d3d Binary files /dev/null and b/sound/machines/sm/accent/delam/17.ogg differ diff --git a/sound/machines/sm/accent/delam/18.ogg b/sound/machines/sm/accent/delam/18.ogg new file mode 100644 index 0000000000..4ef138d27a Binary files /dev/null and b/sound/machines/sm/accent/delam/18.ogg differ diff --git a/sound/machines/sm/accent/delam/19.ogg b/sound/machines/sm/accent/delam/19.ogg new file mode 100644 index 0000000000..f638a6971b Binary files /dev/null and b/sound/machines/sm/accent/delam/19.ogg differ diff --git a/sound/machines/sm/accent/delam/2.ogg b/sound/machines/sm/accent/delam/2.ogg new file mode 100644 index 0000000000..5b480daa2e Binary files /dev/null and b/sound/machines/sm/accent/delam/2.ogg differ diff --git a/sound/machines/sm/accent/delam/20.ogg b/sound/machines/sm/accent/delam/20.ogg new file mode 100644 index 0000000000..6072bc6227 Binary files /dev/null and b/sound/machines/sm/accent/delam/20.ogg differ diff --git a/sound/machines/sm/accent/delam/21.ogg b/sound/machines/sm/accent/delam/21.ogg new file mode 100644 index 0000000000..1223dd946d Binary files /dev/null and b/sound/machines/sm/accent/delam/21.ogg differ diff --git a/sound/machines/sm/accent/delam/22.ogg b/sound/machines/sm/accent/delam/22.ogg new file mode 100644 index 0000000000..9ccfb9b55a Binary files /dev/null and b/sound/machines/sm/accent/delam/22.ogg differ diff --git a/sound/machines/sm/accent/delam/23.ogg b/sound/machines/sm/accent/delam/23.ogg new file mode 100644 index 0000000000..6399a8376a Binary files /dev/null and b/sound/machines/sm/accent/delam/23.ogg differ diff --git a/sound/machines/sm/accent/delam/24.ogg b/sound/machines/sm/accent/delam/24.ogg new file mode 100644 index 0000000000..b51d359807 Binary files /dev/null and b/sound/machines/sm/accent/delam/24.ogg differ diff --git a/sound/machines/sm/accent/delam/25.ogg b/sound/machines/sm/accent/delam/25.ogg new file mode 100644 index 0000000000..823f22f136 Binary files /dev/null and b/sound/machines/sm/accent/delam/25.ogg differ diff --git a/sound/machines/sm/accent/delam/26.ogg b/sound/machines/sm/accent/delam/26.ogg new file mode 100644 index 0000000000..24b2a2f040 Binary files /dev/null and b/sound/machines/sm/accent/delam/26.ogg differ diff --git a/sound/machines/sm/accent/delam/27.ogg b/sound/machines/sm/accent/delam/27.ogg new file mode 100644 index 0000000000..4b4b145b7b Binary files /dev/null and b/sound/machines/sm/accent/delam/27.ogg differ diff --git a/sound/machines/sm/accent/delam/28.ogg b/sound/machines/sm/accent/delam/28.ogg new file mode 100644 index 0000000000..7bc71bf0e6 Binary files /dev/null and b/sound/machines/sm/accent/delam/28.ogg differ diff --git a/sound/machines/sm/accent/delam/29.ogg b/sound/machines/sm/accent/delam/29.ogg new file mode 100644 index 0000000000..7fec2f271c Binary files /dev/null and b/sound/machines/sm/accent/delam/29.ogg differ diff --git a/sound/machines/sm/accent/delam/3.ogg b/sound/machines/sm/accent/delam/3.ogg new file mode 100644 index 0000000000..5b57cc2707 Binary files /dev/null and b/sound/machines/sm/accent/delam/3.ogg differ diff --git a/sound/machines/sm/accent/delam/30.ogg b/sound/machines/sm/accent/delam/30.ogg new file mode 100644 index 0000000000..ed1ec7d89f Binary files /dev/null and b/sound/machines/sm/accent/delam/30.ogg differ diff --git a/sound/machines/sm/accent/delam/31.ogg b/sound/machines/sm/accent/delam/31.ogg new file mode 100644 index 0000000000..0baa82e246 Binary files /dev/null and b/sound/machines/sm/accent/delam/31.ogg differ diff --git a/sound/machines/sm/accent/delam/32.ogg b/sound/machines/sm/accent/delam/32.ogg new file mode 100644 index 0000000000..e925b32d67 Binary files /dev/null and b/sound/machines/sm/accent/delam/32.ogg differ diff --git a/sound/machines/sm/accent/delam/33.ogg b/sound/machines/sm/accent/delam/33.ogg new file mode 100644 index 0000000000..9ddec0e84a Binary files /dev/null and b/sound/machines/sm/accent/delam/33.ogg differ diff --git a/sound/machines/sm/accent/delam/4.ogg b/sound/machines/sm/accent/delam/4.ogg new file mode 100644 index 0000000000..aa4f4da071 Binary files /dev/null and b/sound/machines/sm/accent/delam/4.ogg differ diff --git a/sound/machines/sm/accent/delam/5.ogg b/sound/machines/sm/accent/delam/5.ogg new file mode 100644 index 0000000000..be438f6f15 Binary files /dev/null and b/sound/machines/sm/accent/delam/5.ogg differ diff --git a/sound/machines/sm/accent/delam/6.ogg b/sound/machines/sm/accent/delam/6.ogg new file mode 100644 index 0000000000..b89d52a564 Binary files /dev/null and b/sound/machines/sm/accent/delam/6.ogg differ diff --git a/sound/machines/sm/accent/delam/7.ogg b/sound/machines/sm/accent/delam/7.ogg new file mode 100644 index 0000000000..3a9cfc62ca Binary files /dev/null and b/sound/machines/sm/accent/delam/7.ogg differ diff --git a/sound/machines/sm/accent/delam/8.ogg b/sound/machines/sm/accent/delam/8.ogg new file mode 100644 index 0000000000..7bc0a727fa Binary files /dev/null and b/sound/machines/sm/accent/delam/8.ogg differ diff --git a/sound/machines/sm/accent/delam/9.ogg b/sound/machines/sm/accent/delam/9.ogg new file mode 100644 index 0000000000..5c1bd37405 Binary files /dev/null and b/sound/machines/sm/accent/delam/9.ogg differ diff --git a/sound/machines/sm/accent/normal/1.ogg b/sound/machines/sm/accent/normal/1.ogg new file mode 100644 index 0000000000..e92beed7fe Binary files /dev/null and b/sound/machines/sm/accent/normal/1.ogg differ diff --git a/sound/machines/sm/accent/normal/10.ogg b/sound/machines/sm/accent/normal/10.ogg new file mode 100644 index 0000000000..9efb616f0b Binary files /dev/null and b/sound/machines/sm/accent/normal/10.ogg differ diff --git a/sound/machines/sm/accent/normal/11.ogg b/sound/machines/sm/accent/normal/11.ogg new file mode 100644 index 0000000000..2af0981ef1 Binary files /dev/null and b/sound/machines/sm/accent/normal/11.ogg differ diff --git a/sound/machines/sm/accent/normal/12.ogg b/sound/machines/sm/accent/normal/12.ogg new file mode 100644 index 0000000000..2fab78b02d Binary files /dev/null and b/sound/machines/sm/accent/normal/12.ogg differ diff --git a/sound/machines/sm/accent/normal/13.ogg b/sound/machines/sm/accent/normal/13.ogg new file mode 100644 index 0000000000..784e84e4a8 Binary files /dev/null and b/sound/machines/sm/accent/normal/13.ogg differ diff --git a/sound/machines/sm/accent/normal/14.ogg b/sound/machines/sm/accent/normal/14.ogg new file mode 100644 index 0000000000..af170394dd Binary files /dev/null and b/sound/machines/sm/accent/normal/14.ogg differ diff --git a/sound/machines/sm/accent/normal/15.ogg b/sound/machines/sm/accent/normal/15.ogg new file mode 100644 index 0000000000..05c88c6b29 Binary files /dev/null and b/sound/machines/sm/accent/normal/15.ogg differ diff --git a/sound/machines/sm/accent/normal/16.ogg b/sound/machines/sm/accent/normal/16.ogg new file mode 100644 index 0000000000..46b0e33980 Binary files /dev/null and b/sound/machines/sm/accent/normal/16.ogg differ diff --git a/sound/machines/sm/accent/normal/17.ogg b/sound/machines/sm/accent/normal/17.ogg new file mode 100644 index 0000000000..e432b2ee02 Binary files /dev/null and b/sound/machines/sm/accent/normal/17.ogg differ diff --git a/sound/machines/sm/accent/normal/18.ogg b/sound/machines/sm/accent/normal/18.ogg new file mode 100644 index 0000000000..1e0e91abc8 Binary files /dev/null and b/sound/machines/sm/accent/normal/18.ogg differ diff --git a/sound/machines/sm/accent/normal/19.ogg b/sound/machines/sm/accent/normal/19.ogg new file mode 100644 index 0000000000..31de063e02 Binary files /dev/null and b/sound/machines/sm/accent/normal/19.ogg differ diff --git a/sound/machines/sm/accent/normal/2.ogg b/sound/machines/sm/accent/normal/2.ogg new file mode 100644 index 0000000000..05e3c9ff17 Binary files /dev/null and b/sound/machines/sm/accent/normal/2.ogg differ diff --git a/sound/machines/sm/accent/normal/20.ogg b/sound/machines/sm/accent/normal/20.ogg new file mode 100644 index 0000000000..36810bd8f1 Binary files /dev/null and b/sound/machines/sm/accent/normal/20.ogg differ diff --git a/sound/machines/sm/accent/normal/21.ogg b/sound/machines/sm/accent/normal/21.ogg new file mode 100644 index 0000000000..306e8856e5 Binary files /dev/null and b/sound/machines/sm/accent/normal/21.ogg differ diff --git a/sound/machines/sm/accent/normal/22.ogg b/sound/machines/sm/accent/normal/22.ogg new file mode 100644 index 0000000000..38286aa98b Binary files /dev/null and b/sound/machines/sm/accent/normal/22.ogg differ diff --git a/sound/machines/sm/accent/normal/23.ogg b/sound/machines/sm/accent/normal/23.ogg new file mode 100644 index 0000000000..89f85fed91 Binary files /dev/null and b/sound/machines/sm/accent/normal/23.ogg differ diff --git a/sound/machines/sm/accent/normal/24.ogg b/sound/machines/sm/accent/normal/24.ogg new file mode 100644 index 0000000000..7c12a3e768 Binary files /dev/null and b/sound/machines/sm/accent/normal/24.ogg differ diff --git a/sound/machines/sm/accent/normal/25.ogg b/sound/machines/sm/accent/normal/25.ogg new file mode 100644 index 0000000000..f89175ceb1 Binary files /dev/null and b/sound/machines/sm/accent/normal/25.ogg differ diff --git a/sound/machines/sm/accent/normal/26.ogg b/sound/machines/sm/accent/normal/26.ogg new file mode 100644 index 0000000000..9efd1d8ef3 Binary files /dev/null and b/sound/machines/sm/accent/normal/26.ogg differ diff --git a/sound/machines/sm/accent/normal/27.ogg b/sound/machines/sm/accent/normal/27.ogg new file mode 100644 index 0000000000..1fb1edbb5a Binary files /dev/null and b/sound/machines/sm/accent/normal/27.ogg differ diff --git a/sound/machines/sm/accent/normal/28.ogg b/sound/machines/sm/accent/normal/28.ogg new file mode 100644 index 0000000000..890c5ea429 Binary files /dev/null and b/sound/machines/sm/accent/normal/28.ogg differ diff --git a/sound/machines/sm/accent/normal/29.ogg b/sound/machines/sm/accent/normal/29.ogg new file mode 100644 index 0000000000..cd2aa40714 Binary files /dev/null and b/sound/machines/sm/accent/normal/29.ogg differ diff --git a/sound/machines/sm/accent/normal/3.ogg b/sound/machines/sm/accent/normal/3.ogg new file mode 100644 index 0000000000..38de5571a4 Binary files /dev/null and b/sound/machines/sm/accent/normal/3.ogg differ diff --git a/sound/machines/sm/accent/normal/30.ogg b/sound/machines/sm/accent/normal/30.ogg new file mode 100644 index 0000000000..87d1782768 Binary files /dev/null and b/sound/machines/sm/accent/normal/30.ogg differ diff --git a/sound/machines/sm/accent/normal/31.ogg b/sound/machines/sm/accent/normal/31.ogg new file mode 100644 index 0000000000..9ce3eeb72e Binary files /dev/null and b/sound/machines/sm/accent/normal/31.ogg differ diff --git a/sound/machines/sm/accent/normal/32.ogg b/sound/machines/sm/accent/normal/32.ogg new file mode 100644 index 0000000000..26ca056142 Binary files /dev/null and b/sound/machines/sm/accent/normal/32.ogg differ diff --git a/sound/machines/sm/accent/normal/33.ogg b/sound/machines/sm/accent/normal/33.ogg new file mode 100644 index 0000000000..24964c1ce9 Binary files /dev/null and b/sound/machines/sm/accent/normal/33.ogg differ diff --git a/sound/machines/sm/accent/normal/4.ogg b/sound/machines/sm/accent/normal/4.ogg new file mode 100644 index 0000000000..2e71e976e8 Binary files /dev/null and b/sound/machines/sm/accent/normal/4.ogg differ diff --git a/sound/machines/sm/accent/normal/5.ogg b/sound/machines/sm/accent/normal/5.ogg new file mode 100644 index 0000000000..04852e10f2 Binary files /dev/null and b/sound/machines/sm/accent/normal/5.ogg differ diff --git a/sound/machines/sm/accent/normal/6.ogg b/sound/machines/sm/accent/normal/6.ogg new file mode 100644 index 0000000000..bf06c06bbe Binary files /dev/null and b/sound/machines/sm/accent/normal/6.ogg differ diff --git a/sound/machines/sm/accent/normal/7.ogg b/sound/machines/sm/accent/normal/7.ogg new file mode 100644 index 0000000000..d29821701f Binary files /dev/null and b/sound/machines/sm/accent/normal/7.ogg differ diff --git a/sound/machines/sm/accent/normal/8.ogg b/sound/machines/sm/accent/normal/8.ogg new file mode 100644 index 0000000000..0b94b9dbe0 Binary files /dev/null and b/sound/machines/sm/accent/normal/8.ogg differ diff --git a/sound/machines/sm/accent/normal/9.ogg b/sound/machines/sm/accent/normal/9.ogg new file mode 100644 index 0000000000..545b038be1 Binary files /dev/null and b/sound/machines/sm/accent/normal/9.ogg differ diff --git a/sound/machines/sm/loops/calm.ogg b/sound/machines/sm/loops/calm.ogg new file mode 100644 index 0000000000..cee14fcd13 Binary files /dev/null and b/sound/machines/sm/loops/calm.ogg differ diff --git a/sound/machines/sm/loops/delamming.ogg b/sound/machines/sm/loops/delamming.ogg new file mode 100644 index 0000000000..7d79f0e3c4 Binary files /dev/null and b/sound/machines/sm/loops/delamming.ogg differ diff --git a/sound/machines/sm/supermatter1.ogg b/sound/machines/sm/supermatter1.ogg index 1860e78800..be5185009e 100644 Binary files a/sound/machines/sm/supermatter1.ogg and b/sound/machines/sm/supermatter1.ogg differ diff --git a/sound/machines/sm/supermatter2.ogg b/sound/machines/sm/supermatter2.ogg index fb2d39fe26..5c98d28ed1 100644 Binary files a/sound/machines/sm/supermatter2.ogg and b/sound/machines/sm/supermatter2.ogg differ diff --git a/sound/machines/sm/supermatter3.ogg b/sound/machines/sm/supermatter3.ogg index 93ac3d505b..fb8e09166c 100644 Binary files a/sound/machines/sm/supermatter3.ogg and b/sound/machines/sm/supermatter3.ogg differ diff --git a/sound/music/twilight.ogg b/sound/music/twilight.ogg new file mode 100644 index 0000000000..635663314d Binary files /dev/null and b/sound/music/twilight.ogg differ diff --git a/sound/weapons/etherealhit.ogg b/sound/weapons/etherealhit.ogg new file mode 100644 index 0000000000..19da870961 Binary files /dev/null and b/sound/weapons/etherealhit.ogg differ diff --git a/sound/weapons/etherealmiss.ogg b/sound/weapons/etherealmiss.ogg new file mode 100644 index 0000000000..8feb7cdc91 Binary files /dev/null and b/sound/weapons/etherealmiss.ogg differ diff --git a/strings/names/ethereal.txt b/strings/names/ethereal.txt new file mode 100644 index 0000000000..d3e6a26e6e --- /dev/null +++ b/strings/names/ethereal.txt @@ -0,0 +1,38 @@ +Aten +Apollo +Arche +Atlas +Eos +Halo +Kale +Nysa +Orion +Pallas +Rigel +Themis +Aurora +Andromeda +Lyra +Saggitarius +Crux +Canis +Cygnus +Corvus +Cepheus +Auriga +Corona +Aquilla +Serpens +Cetus +Puppis +Ophiuchus +Carina +Cassiopeia +Canes +Fornax +Berenices +Coma +Vela +Triangulum +Tau +Ceti \ No newline at end of file diff --git a/strings/round_start_sounds.txt b/strings/round_start_sounds.txt index c67bf6b4a6..177a3ea0a8 100644 --- a/strings/round_start_sounds.txt +++ b/strings/round_start_sounds.txt @@ -25,3 +25,4 @@ sound/music/rocketridersprayer.ogg sound/music/theend.ogg sound/music/flyinghigh.ogg sound/music/samsara.ogg +sound/music/twilight.ogg \ No newline at end of file diff --git a/strings/sillytips.txt b/strings/sillytips.txt index bc59a109f0..e6710de95e 100644 --- a/strings/sillytips.txt +++ b/strings/sillytips.txt @@ -25,6 +25,7 @@ This game is older than most of the people playing it. Do not go gentle into that good night. Flashbangs can weaken blob tiles, allowing for you and the crew to easily destroy them. Just the tip? +You can grab someone by clicking on them with the grab intent, then upgrade the grab by clicking on them once more. An aggressive grab will momentarily stun someone, allow you to place Mekhi on a table by clicking on it, or throw them by toggling on throwing. Some people are unable to read text on a game where half of it is based on text. As the Captain, you can use a whetstone to sharpen your fancy fountain pen for extra robustness. As the Lawyer, you are the last bastion of roleplay-focused jobs. Even the curator got a whip to go fight people with, that sellout! @@ -43,5 +44,8 @@ Plasma men are a powerful race with many perks! No really, I swear! So what if t As a Cargo Tech make sure to always buy a tesla to sell back to CC. They love those those. Trust me! Help. Maints. -BZ stops or slows down Lings chem regeneration drastically, make sure to BZ flood the station when lings are confirmed! Admins always regret meme options in their polls. +Putting cat ears on securitrons makes them table people and nya. Mekhi isn't a cat, but he still goes on the table, just roll with it. +As a Changeling, you can live without a head as they are merely vestigal to you, now, finally, you can be a Dullahan without it being Halloween. +People actually have fictional sex between fictional characters in this game. +When in doubt, take a break. A long break, preferably. If the game is wearing down your mental state and it's starting to lose any semblance of fun value, go and do something else for a month or two. By the time you come back, everything you liked will have been changed anyways. diff --git a/strings/tips.txt b/strings/tips.txt index 043405c7a0..5dc4e1b985 100644 --- a/strings/tips.txt +++ b/strings/tips.txt @@ -1,83 +1,91 @@ Where the space map levels connect is randomized every round, but are otherwise kept consistent within rounds. Remember that they are not necessarily bidirectional! You can catch thrown items by toggling on your throw mode with an empty hand active. -To crack the safe in the vault, use a stethoscope or explosives on it. +To crack the safe in the vault, have a stethoscope in one of your hands and fiddle with the tumbler or you can alternatively use several concentrated explosive charges on it. Remember that the latter may result in the contents of the safe becoming a pile of ash. You can climb onto a table by dragging yourself onto one. This takes time and drops the items in your hands on the table. Clicking on a table that someone else is climbing onto will knock them down. You can drag other players onto yourself to open the strip menu, letting you remove their equipment or force them to wear something. Note that exosuits or helmets will block your access to the clothing beneath them, and that certain items take longer to strip or put on than others. Clicking on a windoor rather then bumping into it will keep it open, you can click it again to close it. You can spray a fire extinguisher, throw items or fire a gun while floating through space to change your direction. Simply fire opposite to where you want to go. You can change the control scheme by pressing tab. One is WASD, the other is the arrow keys. Keep in mind that hotkeys are also changed with this. -All vending machines can be hacked to obtain some contraband items from them, and many can be fed with coins to gain access to premium items. +All vending machines can be hacked to obtain some contraband items from them, and many may charge extra credits to give you premium items. Firesuits and winter coats offer mild protection from the cold, allowing you to spend longer periods of time near breaches and space than if wearing nothing at all. Glass shards can be welded to make glass, and metal rods can be welded to make metal. Ores can be welded too, but this takes a lot of fuel. If you need to drag multiple people either to safety or to space, bring a locker or crate over and stuff them all in before hauling them off. -You can grab someone by clicking on them with the grab intent, then upgrade the grab by clicking on them once more. An aggressive grab will momentarily stun someone, allow you to place Mekhi on a table by clicking on it, or throw them by toggling on throwing. +You can grab someone by clicking on them with the grab intent, then upgrade the grab by clicking on them once more. An aggressive grab can temporarily stun someone depending on their luck with resisting out of it, allowing you to slam them on a table by clicking on it, or throw them by toggling on throwing. Holding alt and left clicking a tile will allow you to see its contents in the top right window pane, which is much faster than right clicking. The resist button will allow you to resist out of handcuffs, being buckled to a chair or bed, out of locked lockers and more. Whenever you're stuck, try resisting! You can move an item out of the way by dragging it and then clicking on an adjacent tile with an empty hand. -You can recolor certain items like jumpsuits and gloves in washing machines by also throwing in a crayon. +You can recolor certain items like jumpsuits and gloves in washing machines by also throwing in a crayon. For more advanced fashion you can spray items with a spray can to tint its colors. Some items work better than others at displaying their tints, like sterile and paper masks, or darkly colored gloves. Maintenance is full of equipment that is randomized every round. Look around and see if anything is worth using. -Some roles cannot be antagonists by default, but antag selection is decided first. For instance, you can set Security Officer to High without affecting your chances of becoming an antag -- the game will just select a different role. +Some roles cannot be antagonists by default, but antag selection is decided first. For instance, you can set Security Officer to High without affecting your chances of becoming an antag - the game will just assign you to your next preferred role - or in the case that you have no such preferences set, a random role entirely. There are many places around the station to hide contraband. A few for starters: linen boxes, toilet cisterns, body bags. Experiment to find more! On all maps, you can use a machine in the vault to deposit space cash for cargo points. Otherwise, use it to steal the station's cash and get out before the alarm goes off. -As the Captain, you are one of the highest priority targets on the station. Everything from revolutions, to nuclear operatives, to traitors that need to rob you of your unique lasgun or your life are things to worry about. -As the Captain, always take the nuclear disk and pinpointer with you every shift. It's a good idea to give one of these to another head you can trust with keeping it safe, such as the Head of Security. +As the Captain, you are one of the highest priority targets on the station. Everything from revolutions looking to thwart your rule, to nuclear operatives seeking the disk, to traitors that need to rob you of your several high value items - or your life are all things to be concerned about. +As the Captain, always take the nuclear disk and pinpointer with you every shift. It's a good idea to give one of these to another head you can trust with keeping it safe, such as the Head of Personnel. As the Captain, you have absolute access and control over the station, but this does not mean that being a horrible person won't result in mutiny and a ban. As the Captain, you have a fancy pen that can be used as a holdout dagger or even as a scalpel in surgery! As the Captain, you can purchase a new emergency shuttle using a communications console. Some require credits, while others give you credits in exchange. Keep in mind that purchasing dangerous shuttles will incur the ire of your crew. -As the Chief Medical Officer, your hypospray is like a refillable instant injection syringe that can hold 30 units as opposed to the standard 15. -As the Chief Medical Officer, coordinate and communicate with your doctors, chemists, and geneticists during a nuclear emergency, blob infestation, or some other crisis to keep people alive and fighting. -As a Medical Doctor, pester Research for improved surgical tools. They work faster, don't cost much and are typically more deadly. +As the Chief Medical Officer, your hypospray is like the ones that your Medical Doctors can buy, except it comes in a fancy box that can hold several more hypovials than the standard, and already comes preloaded with specially-made high-capacity hypovials that hold double the reagents the standard ones do. +As the Chief Medical Officer, coordinate and communicate with your doctors, chemists, and paramedics during a nuclear emergency, blob infestation, or some other crisis to keep people alive and fighting. +As a Medical Doctor, pester Research for improved surgical tools. They work faster, combine the purposes of several tools in one (scalpel/saw, retractor/hemostat, drill/cautery), and don't cost many materials to boot! +As a Medical Doctor, the surgical saw and drill are both powerful weapons, the saw is sharp and can slice and dice, while the drill can quickly blind someone if aimed for the eyes. The laser scalpel is an upgraded version producible with Research's aid, and it has the highest force of most common place weapons, while still remaining sharp. As a Medical Doctor, your belt can hold a full set of surgical tools. Using sterilizine before each attempt during surgery will reduce your failure chance on tricky steps or when using less-than-optimal equipment. As a Medical Doctor, you can attempt to drain blood from a husk with a syringe to determine the cause. If you can extract blood, it was caused by extreme temperatures or lasers, if there is no blood to extract, you have confirmed the presence of changelings. As a Medical Doctor, while both heal toxin damage, the difference between charcoal and antitoxin is that charcoal will actively remove all other reagents from one's body, while antitoxin only removes various toxins - but can overdose. -As a Medical Doctor, you can surgically implant or extract things from people's chests. This can range from putting in a bomb to pulling out an alien larva. +As a Medical Doctor, you can surgically implant or extract things from people's chests by performing a cavity implant. This could range from inserting a suicide bomb to embedding the nuke disk into the Captain's chest. +As a Medical Doctor, it's of utmost urgency that you tend to anyone who's been hugged by a facehugger. You only have a couple of minutes from the initial attachment to perform organ manipulation to their chest and remove the rapidly developing alien embryo before it bursts out and immediately kills your patient. As a Medical Doctor, you must target the correct limb and be on help intent when trying to perform surgery on someone. Using disarm attempt will intentionally fail the surgery step. -As a Medical Doctor, corpses with the "...and their soul has departed" description no longer have a ghost attached to them and aren't usually revivable or cloneable. However it may prove useful to be creative in your revivification techniques with these bodies. -As a Medical Doctor, treating plasmamen is not impossible! Salbutamol stops them from suffocating and showers stop them from burning alive. You can even perform surgery on them by doing the procedure on a roller bed under a shower. +As a Medical Doctor, corpses with the "...and their soul has departed" description no longer have a ghost attached to them and can't be revived. However it may prove useful to be creative in your revivification techniques with these bodies. +As a Medical Doctor, treating plasmamen is not impossible! Salbutamol and epinephrine stops them from suffocating due to lack of internals and showers stop them from burning alive. You can even perform surgery on them by doing the procedure on a roller bed under a shower. As a Medical Doctor, you can point your penlight at people to create a medical hologram. This lets them know that you're coming to treat them. As a Medical Doctor, you can extract implants by holding an empty implant case in your offhand while performing the extraction step. As a Medical Doctor, clone scanning people will implant them with a health tracker that displays their vitals in the clone records. Useful to check on crew members that didn't activate suit sensors! -As a Medical Doctor, medical gauze stops bleeding as well as healing 5 brute damage, this even works on the dead! Make sure to always have some gauze on you to stop bleeding before dragging someone. -As a Chemist, there are dozens of chemicals that can heal, and even more that can cause harm. Experiment! +As a Medical Doctor, you can deal with patients who have absurd amounts of wounds by putting them in cryo. This will slowly treat all of their wounds simultaneously, but is much slower than direct treatment. +As a Medical Doctor, Critical Slash wounds are one of the most dangerous conditions someone can have. Apply gauze, epipens, sutures, cauteries, whatever you can, as soon as possible! +As a Medical Doctor, Saline-Glucose not only acts as a temporary boost to a patient's blood level, it also speeds regeneration! Perfect for drained patients! +As a Medical Doctor, medical gauze is an incredibly underrated tool. It can be used to entirely halt a limb from bleeding or sling one that's been shattered until it can be given proper attention. This even works on the dead, too! Be sure to stop someone's bleeding whether they're in critical condition or a corpse, as dragging someone whom is bleeding will rapidly deplete them of all their blood. +As a Chemist, there are dozens of chemicals that can heal, and even more that can cause harm. See which chemicals have the best synergy, both in healing, and in harming. Experiment! As a Chemist, some chemicals can only be synthesized by heating up the contents in the chemical heater. As a Chemist, you will be expected to supply crew with certain chemicals. For example, clonexadone and mannitol for the cryo tubes, unstable mutagen and saltpetre for botany as well as healing pills and patches for the front desk. As a Chemist, you can make 100u bottles from plastic sheets. The ChemMaster can produce infinite 30u glass bottles as well. +As a Chemist, be sure to stock up some hypovials with useful chemicals for any doctors looking to heal on the go, you can also print out the deluxe hypovials at an autolathe specifically for the CMO's special hypospray. +As a Chemist, the reagent dartgun, while neutered in its ability to harm - can still be loaded up with morphine for a ghetto sedation weapon, and a quick shot of charcoal can make a slime hybrid regret their life choices in an instant. As a Geneticist, you can eject someone from cloning early by clicking on the cloner pod with your ID. Note that they will suffer more genetic damage and may lose vital organs from this. -As a Geneticist, becoming a hulk makes you capable of dealing high melee damage, stunlocking people, and punching through walls. However, you can't fire guns, will lose your hulk status if you take too much damage, and are not considered a human by the AI while you are a hulk. +As a Geneticist, becoming a hulk makes you capable of dealing high melee damage, becoming immune to most traditional stuns, and punching through walls. However, you can't fire guns, and will lose your hulk status if you take too much damage. As the Virologist, your viruses can range from healing powers so great that you can heal out of critical status, or diseases so dangerous they can kill the entire crew with airborne spontaneous combustion. Experiment! As the Virologist, you only require small amounts of vaccine to heal a sick patient. Work with the Chemist to distribute your cures more efficiently. As the Research Director, you can take AIs out of their cores by loading them into an intelliCard, and then from there into an AI system integrity restorer computer to revive and/or repair them. As the Research Director, you can lock down cyborgs instead of blowing them up. Then you can have their laws reset or if that doesn't work, safely dismantled. As the Research Director, you can upgrade your modular console with better computer parts to speed up its functions. This can be useful when using the AI system integrity restorer. As the Research Director, your console's NTnet monitoring tool can be used to retrieve airlock passkeys, provided that someone used a door remote. -As a Scientist, you can use the mutation toxin obtained from green slimes to turn yourself into a jelly mutant. Each subspecies has unique features - for example telepathic powers, duplicating bodies or integrating slime extracts! +As a Scientist, you can use the mutation toxin obtained from green slimes to turn yourself into a jelly mutant. Each subspecies has unique features - for example telepathic powers, duplicating bodies or integrating slime extracts for several unique effects! As a Scientist, you can maximize the number of uses you get out of a slime by feeding it slime steroid, created from purple slimes, while alive. You can then apply extract enhancer, created from cerulean slimes, on each extract. -As a Scientist, you can disable anomalies by scanning them with an analyzer, then send a signal on the frequency it gives you with a remote signalling device. This will leave behind an anomaly core, which can be used to construct a Phazon mech, or be used in the destructive analyzer for a 10,000 point bonus! +As a Scientist, you can disable anomalies by scanning them with an analyzer, and then sending a signal on the frequency it gives you with a remote signalling device. Alternatively, you can print out anomaly defusal tools which can instantly disable an anomaly at the protolathe with some research, both of these methods will leave behind an anomaly core, which can be used to construct a Phazon mech, or be used in the destructive analyzer for a 10,000 point bonus! As a Scientist, researchable stock parts can seriously improve the efficiency and speed of machines around the station. In some cases, it can even unlock new functions. As a Scientist, you can generate research points by letting the tachyon-doppler array record increasingly large explosions. As a Scientist, getting drunk just enough will speed up research. Skol! As a Scientist, you can get points by placing slime cores into the destructive analyzer! This even works with crossbred slime cores. -As a Scientist, work with botanists to get different types of seeds, as each type of seed can be used in the destructive analyzer for a small amount of Rnd type points! +As a Scientist, you can get a minuscule amount of points by sacrificing a packet of seeds from Hydroponics into the destructive analyzer! While each individual one may not yield many points per, you can quite easily amass a very large variety of seeds, which could add up over time for a couple extra minutes shaved off of maxing out RND. As a Roboticist, keep an ear out for anomaly announcements. If you get your hands on an anomaly core, you can build a Phazon mech! As a Roboticist, you can repair your cyborgs with a welding tool. If they have taken burn damage from lasers, you can remove their battery, expose the wiring with a screwdriver and replace their wires with a cable coil. As a Roboticist, you can reset a cyborg's module by cutting and mending the reset wire with a wire cutter. +As a Roboticist, pay mind when toying with a cyborg's wires. It's best to pulse wires before immediately cutting them, as cutting them right away without knowing what they do may sever them from the AI, or disable their camera. As a Roboticist, you can greatly help out Shaft Miners by building a Firefighter APLU equipped with a hydraulic clamp and plasma cutter. The mech is ash storm proof and can even walk across lava! -As a Roboticist, you can augment people with cyborg limbs. Augmented limbs can easily be repaired with cables and welders. +As a Roboticist, you can augment people with cyborg limbs. Augmented limbs are immune to the vacuum of space and temperatures while they can very easily be repaired with welders (brute) and cable coils (burn). As a Roboticist, you can use your printer that is linked to the ore silo to teleport mats into your work place! As a Roboticist, you can upgrade cleanbots with adv mops and brooms to make them faster and better! -As a Roboticist, you can upgrade medical bots with diamond-tipped syringes, MK.II Hypospray, dispenser-sleeper-chemheater boards to make them inject faster, harder and better chems! -As the AI, you can click on people's names to look at them. This only works if there are cameras that can see them. +As a Roboticist, you can upgrade medical bots with diamond-tipped syringes, hyposprays, and chemistry machine boards to make their injections pierce hardsuits, work faster, and inject higher quality medicines! +As the AI, you can click on people's names when they speak over the radio to jump your eye to them. This only works if there are cameras that can see them and are not wearing anything which would obsfuscate their face or tracking capabilities. As the AI, you can quickly open and close doors by holding shift while clicking them, bolt them when holding ctrl, and even shock them while holding alt. -As the AI, you can take pictures with your camera and upload them to newscasters. -As a Cyborg, choose your module carefully, as only cutting and mending your reset wire will let you repick it. If possible, refrain from choosing a module until a situation that requires one occurs. -As a Cyborg, you are immune to most forms of stunning, and excel at almost everything far better than humans. However, flashes can easily stunlock you and you cannot do any precision work as you lack hands. +As the AI, you can take pictures with your camera and upload them to newscasters. Cyborgs also share from this pool of pictures. +As a Cyborg, choose your module carefully, as only having your reset wire cut and mended by someone capable of manipulation will let you repick it. If possible, refrain from choosing a module until a situation that requires one occurs. +As a Cyborg, you are immune to most forms of stunning, and excel at almost everything far better than humans. However, flashes and EMPs can easily stunlock you and you fall short in performing any tasks which require hands. As a Cyborg, you are impervious to fires and heat. If you are rogue, you can release plasma fires everywhere and walk through them without a care in the world! As a Cyborg, you are extremely vulnerable to EMPs as EMPs both stun you and damage you. The ion rifle in the armory or a traitor with an EMP kit can kill you in seconds. As a Service Cyborg, your spray can knocks people down. However, it is blocked by gas masks. -As an Engineering Cyborg, you can attach air alarm/fire alarm/APC frames to walls by placing them on the floor and using a screwdriver on them. -As a Medical Cyborg, you can fully perform surgery and even augment people. Best of all, they have a 0% failure chance. -As a Janitor Cyborg, you are the bane of all slaughter demons and even Bubblegum himself. Cleaning up blood stains will severely gimp them. -As a Janitor Cyborg, you get a fancy bottle of drying agent! If you want to be nice, spray the janitor boots with them to magically upgrade them to absorbent galoshes. +As an Engineering Cyborg, you can attach air alarm/fire alarm/APC frames to walls by placing them on the floor and using a screwdriver on them. Alternatively, you can use your in-built pseudo-hand manipulator to show those organics who's boss! It can even perform complex tasks such as removing cells from APCs, or inserting plasma canisters into radiation collectors. +As a Medical Cyborg, you can fully perform surgery and even augment people. Best of all, they have a 0% failure chance, even if done on the floor. +As a Janitor Cyborg, you are the bane of all slaughter demons and can even foil Bubblegum himself. Cleaning up blood stains will severely gimp them, although the latter may just turn you into robotic paste. +As a Janitor Cyborg, you get a fancy bottle of drying agent! If you want to be nice, spray the janitor's galoshes with them to magically upgrade them to absorbent galoshes which automatically dry tiles. As the Chief Engineer, you can rename areas or create entirely new ones using your station blueprints. As the Chief Engineer, your hardsuit is significantly better than everybody else's. It has the best features of both engineering and atmospherics hardsuits - boasting nigh-invulnerability to radiation and all atmospheric conditions. As the Chief Engineer, you can spy on and even forge PDA communications with the message monitor console! The key is in your office. @@ -94,14 +102,14 @@ As an Engineer, you can convert tesla coils into corona analyzers by using a scr As an Engineer, you can use radiation collectors to generate research points. Load them with a 50/50 oxygen/tritium tank and use a multitool to switch them to research mode. As an Engineer, don't underestimate the humble P.A.C.M.A.N. generators. With upgraded parts, a couple units working in tandem are sufficient to take over for an exploded engine or shattered solars. As an Engineer, your departmental protolathe and circuit printer can manufacture the necessary circuit boards and components to build just about anything. Make extra medical machinery everywhere! Build a gibber for security! Set up an array of emitters pointing down the hall! The possibilities are endless! -As an Engineer, you can pry open secure storage by disabling the engine room APC's main breaker. This is obviously a bad idea if the engine is running. -Don't forget that Cargo has access to a meteor defense satellite that can be ordered BEFORE meteors hit the station. Any idle Engineers should have this on their to-do list. -As an Engineer, your RCD can be reloaded with mineral sheets instead of just compressed matter cartridges. +As an Engineer, you can pry open secure storage by disabling the engine room APC's environmental breaker. This is obviously a bad idea if the engine is running. +As an Engineer, don't forget that Cargo has access to a meteor defense satellite that can be ordered BEFORE meteors hit the station. Any idle Engineers should have this on their to-do list. +As an Engineer, your RCD can be reloaded with mineral sheets instead of just compressed matter cartridges. Materials which are combined alloys of other materials (such as reinforced glass and plasteel) provide more matter per sheet to the RCD. As an Atmospheric Technician, you can unwrench a pipe regardless of the pressures of the gases inside, but if they're too high they can burst out and injure you! As an Atmospheric Technician, look into replacing your gas pumps with volumetric gas pumps, as those move air in flat numerical amounts, rather than percentages which leave trace gases. -As an Atmospheric Technician, you are better suited to fighting fires than anyone else. As such, you have access to better firesuits, backpack firefighter tanks, and a completely heat and fire proof rigsuit. +As an Atmospheric Technician, you are better suited to fighting fires than anyone else. As such, you have access to better firesuits, backpack firefighter tanks, and a completely heat and fire proof hardsuit. As an Atmospheric Technician, your backpack firefighter tank can launch resin. This resin will extinguish fires and replace any gases with a safe, room-temperature airmix. -As an Atmospheric Technician, your ATMOS holofan projector blocks gases while allowing objects to pass through. With it, you can quickly contain gas spills, fires and hull breaches. Or, use it to seal a plasmaman cloning room. +As an Atmospheric Technician, your ATMOS holofan projectors can blocks gases and heat while allowing objects to pass through. With it, you can quickly contain gas spills, fires and hull breaches. Or, use it to create a plasmaman friendly lounge. As an Atmospheric Technician, burning a plasma/oxygen mix inside the incinerator will not only produce power, but also gases such as tritium and water vapor. As an Atmospheric Technician, you can change the layer of a pipe by clicking with it on a wrenched pipe or other atmos component of the desired layer. As an Atmospheric Technician, you can take a few cans worth of N2/N2O and cool it down at local freezers. This is a good idea when dealing with (or preparing for) a supermatter meltdown. @@ -111,65 +119,70 @@ As the Head of Security, don't let the power go to your head. You may have high As the Warden, your duty is to be the watchdog of the brig and handler of prisoners when little is happening, and to hand out equipment and weapons to the security officers when a crisis strikes. As the Warden, keep a close eye on the armory at all times, as it is a favored strike point of nuclear operatives and cocky traitors. As the Warden, if a prisoner's crimes are heinous enough you can put them in permabrig or the gulag. Make sure to check on them once in a while! -As the Warden, never underestimate the power of tech slugs! Scattershot fires a cone of weaker lasers, Ion slugs fires EMPs that only effect the tiles they hit, and Pulse slugs fire a singular laser that can one-hit almost any wall! -As the Warden, you can use a surgical saw on riot shotguns to shorten the barrel, making them able to fit in your backpack. +As the Warden, never underestimate the power of tech slugs! Scattershot fires a cone of weaker lasers with little damage fall off, Ion slugs fires EMPs that only effect the tiles they hit, and Pulse slugs fire a singular laser that can one-hit almost any wall! +As the Warden, you can use a surgical saw on riot shotguns to shorten the barrel, making them able to fit in your backpack. Make sure to empty them prior lest you blast yourself in the face! As the Warden, you can implant criminals you suspect might re-offend with devices that will track their location and allow you to remotely inject them with disabling chemicals. As the Warden, you can use handcuffs on orange prisoner shoes to turn them into cuffed shoes, forcing prisoners to walk and potentially thwarting an escape. -As the Warden, tracker implants can be used on sec officers. Doing this will let you track their corpse even without suits, though the implant will biodegrade after 5 minutes. -As the Warden, cryostasis shotgun darts hold 10u of chemicals that will not react untill it hits someone. -As the Warden, chemical implants can be loaded with a cocktail of healing or combat chems, perfect for the Hos or other sec officers to use. Be sure to keep a eye on them though, it will not auto inject! EMPs or starvation mite lead to the chemical implant to go off as well. -As the Warden, tracker implants can be used on sec officers. Doing this will let you be able to message them when telecoms are out, or when you suspect coms are compromised. This is also good against rogue AIs as the prisoner tracker doesn't leave logs or alarms for the AI. +As the Warden, tracker implants can be used on crewmembers. Doing this will let you track their person even without suit sensors and even instantly teleport to them at the local teleporter, although the implant will biodegrade after 5 minutes if its holder ever expires. +As the Warden, cryostasis shotgun darts hold 10u of chemicals that will not react until it hits someone. +As the Warden, chemical implants can be loaded with a cocktail of healing or combat chems, perfect for the HoS or other security officers to make use of in a pinch. Be sure to keep a eye on them though, as they cannot be injected without the prisoner management console! EMPs or starvation might lead to the chemical implant going off preemptively. +As the Warden, tracker implants can be used on your security officers. Doing this will let you be able to message them when telecomms are out, or when you suspect comms are compromised. This is also good against rogue AIs as the prisoner tracker doesn't leave logs or alarms for the AI. As a Security Officer, remember that correlation does not equal causation. Someone may have just been at the wrong place at the wrong time! -As a Security Officer, remember that your belt can hold more then one stun baton. -As a Security Officer, remember harm battoning someone in the head can deconvert them form a being a rev! This sadly doesn't work against the cult, nor does this protect them from getting reconverted. -As a Security Officer, remember that you can attach a sec-lite to your taser or your helmet! +As a Security Officer, remember that your belt can hold more than one stun baton. +As a Security Officer, remember harm beating someone in the head with a blunt object can deconvert them form a being a revolutionary! This sadly doesn't work against either cult, nor does this protect them from getting reconverted unlike a mindshield implant. +As a Security Officer, remember that you can attach a seclite to your taser or your helmet! As a Security Officer, communicate and coordinate with your fellow officers using the security channel (:s) to avoid confusion. -As a Security Officer, your sechuds or HUDsunglasses can not only see crewmates' job assignments and criminal status, but also if they are mindshield implanted. Use this to your advantage in a revolution to definitively tell who is on your side! +As a Security Officer, your security HUDglasses can not only see crewmates' job assignments and criminal status, but also if they are mindshield implanted. Use this to your advantage in a revolution to definitively tell who is on your side! As a Security Officer, mindshield implants can only prevent someone from being turned into a cultist: unlike revolutionaries, it will not de-cult them if they have already been converted. -As a Security Officer, examining someone while wearing sechuds or HUDsunglasses will let you set their arrest level, which will cause Beepsky and other security bots to chase after them. -As a Security Officer, you can take out the power cell on your baton to replace it with a better or fully charged one. Just use a screwdriver on your baton to remove the old cell -As a Security Officer, you can place riot shotguns on your armor, this even works with winter sec coats! +As a Security Officer, examining someone while wearing your security HUDglasses can allow you to swiftly edit their records and criminal status. Be sure to set someone to WANTED if you can't catch up to them, as it'll alert other officers of who's the bad guy, and cause the little security droids to chase after them for you. +As a Security Officer, you can take out the power cell on your baton to replace it with a better or fully charged one. Just use a screwdriver on your baton to remove the old cell. +As a Security Officer, you can just about any firearm on your vest, this even works with other non-standard armor-substitutes like security winter coats! As the Detective, people leave fingerprints everywhere and on everything. With the exception of white latex, gloves will hide them. All is not lost, however, as gloves leave fibers specific to their kind such as black or nitrile, pointing to a general department. -As the Detective, you can use your forensics scanner from a distance. -As the Detective, your revolver can be loaded with .357 ammunition obtained from a hacked autolathe. Firing it has a decent chance to blow up your revolver. +As the Detective, you can use your forensics scanner from a distance. Use this to scan boxes or other storage containers. +As the Detective, your revolver can be loaded with .357 ammunition. Use a screwdriver to permanently modify your revolver into using this type of ammunition, be warned however, firing it has a decent chance to cause the revolver to misfire and shoot you in the foot. As the Lawyer, try to negotiate with the Warden if sentences seem too high for the crime. -As the Lawyer, you can try to convince the captain and Head of Security to hold trials for prisoners in the courtroom. +As the Lawyer, you can try to convince the Captain and Head of Security to hold trials for prisoners in the courtroom. As the Head of Personnel, you are not higher ranking than other heads of staff, even though you are expected to take the Captain's place first should he go missing. If the situation seems too rough for you, consider allowing another head to become temporary Captain. -As the Head of Personnel, you are just as large a target as the Captain because of the potential power your ID and computer can hand out. +As the Head of Personnel, you are just as large a target as the Captain because of the potential power your ID and computer can hand out and your comparative vulnerability. As the Mime, your invisible wall power blocks people as well as projectiles. You can use it in a pinch to delay your pursuer. -As the Mime, you can use :r and :l to speak through your ventriloquist dummy. +As the Mime, you can use :r and :l to speak through your ventriloquist dummy. Sadly, this only works if your vow is broken, but at least you don't have to sacrifice your dignity by actually talking. As the Mime, your oath of silence is your source of power. Breaking it robs you of your powers and of your honor. +As the Mime, breaking your vow of silence is seen as incredibly dishonorable. Most people will seek to trouble and generally ignore a talking Mime. As the Clown, if you lose your banana peel, you can still slip people with your PDA! Honk! As the Clown, eating bananas heals you slightly. Honk! As the Clown, your Holy Grail is the mineral bananium, which can be given to the Roboticist to build you a fun and robust mech beloved by everyone. -As the Clown, you can use your stamp on a sheet of cardboard as the first step of making a honkbot. Fun for the whole crew! -As the Chaplain, your null rod has a lot of functions: it can convert water into holy water, which if spread on the ground prevents wizards from jaunting away, can destroy cultist runes by hitting them, and is a very powerful weapon to boot! -The Chaplain can bless any container with water by hitting it with their bible. Holy water has a myriad of uses against both cults and large amounts of it are a great contributor to success against them. -The Chaplain's holy weapon will kill clockwork marauders in two hits. -As the Chaplain, your bible is also a container that can store small items. Depending on your god, your starting bible may come with a surprise! -As the Chaplain, you are much more likely to get a response by praying to the gods than most people. To boost your chances, make altars with colorful crayon runes, lit candles, and wire art. +As the Clown, you can use your stamp on a sheet of flattened cardboard as the first step of making a honkbot. Fun for the whole crew! +As the Clown, your number one way to win over the crew's favor is by telling jokes and putting forth effort into being comedic. Everyone loves a good clown, but everyone despises a bad one. +As the Chaplain, your null rod has a lot of functions: while being an incredibly powerful weapon with an array of potential utilities depending upon the skin you chose for it, it also nulls cultist and wizard magic entirely, making you immune to them both and in some cases even harming the caster so long as you keep it in a pocket or in your hands. +As the Chaplain, you can bless any water container by hitting it with your bible to turn it into holy water. Holy water has a myriad of uses against both cults and large amounts of it are a great contributor to success against them. +As the Chaplain, your null rod will kill clockwork marauders in two hits while actively hindering their overall combat capabilities just by being nearby to them. +As the Chaplain, your bible is also a container that can store a singular small item. Depending on your God, your starting bible may come with a surprise! +As the Chaplain, you are much more likely to get a response by praying to the Gods than most people as your prayers will send a special noise cue directly to them! To further your chances of getting a response even further, pretty up your altar with crayon runes and wire art, and be sure to put a decent amount of effort into your prayers themselves. The Gods don't like lazy bums. As a Botanist, you can hack the MegaSeed Vendor to get access to more exotic seeds. These seeds can alternatively be ordered from cargo. As a Botanist, you can mutate the plants growing in your hydroponics trays with unstable mutagen or, as an alternative, crude radioactives from chemistry to get special variations. -As a Botanist, you should look into increasing the potency of your plants. This increases the size, amount of chemicals, points gained from grinding them in the biogenerator, and lets people know you are a proficient botanist. -As a Botanist, you can combine production trait chemicals just like a Chemist. Chlorine (blumpkin) + radium and phosphorus (glowshrooms) equals unstable mutagen! +As a Botanist, you should look into increasing the potency of your plants. This is shown by the size of the plant's sprite, and can increase the amount of chemicals, points gained from grinding them in the biogenerator, and lets people know you are a proficient botanist. +As a Botanist, you can combine production trait chemicals and mix your own complex chemicals inside of the plants themselves using precursors. Chlorine (blumpkin) + radium and phosphorus (glowshrooms) equals unstable mutagen! +As a Botanist, earthsblood is an incredibly powerful chemical found in Ambrosia Gaia, it heals all types of damages very rapidly but causes lingering brain damage and has a nasty overdose. You can combine the chemicals from watermelons (water), grass (hydrogen), and cherries (sugar) to mix mannitol in with your earthsblood to completely counteract its main drawback! +As a Botanist, Ambrosia Gaia is a plant mutated from Ambrosia Deus, which is a plant mutated from Ambrosia Vulgaris. The reagent contained within this plant known as earthsblood can make your trays and soil plots completely self sufficient when a plant containing such reagent is composted into them, meaning they won't need nutrients or water, and they'll automatically kill their own weeds and pests. As a Cook, you can load your food into snack vending machines. As a Cook, you can rename your custom made food with a pen. As a Cook, any food you make will be much healthier than the junk food found in vendors. Having the crew routinely eating from you will provide minor buffs. -As a Cook, being in the kitchen will make you remember the basics of Close Quarters Cooking. It is highly effective at removing Assistants from your workplace. +As a Cook, being in the kitchen will make you remember the basics of Close Quarters Cooking (CQC). It is highly effective at removing Assistants from your workplace. As a Cook, your Kitchenmate can vend out trays that fit on your belt slot. These trays pick up 7 food items at a time and are a quick way to transport large meals. As a Cook, the advanced roasting stick is used to cook food at a distance, and can be used on SME, singularity, and other objects that cook food normally. +As a Cook, the deep frier is a tool which can turn very large quantities of seemingly useless objects into food, albeit nutritionally poor and awful tasting food, but hey, food is food. As the Bartender, the drinks you start with only give you the basics. If you want more advanced mixtures, look into working with chemistry, hydroponics, or even mining for things to grind up and throw in! -As the Bartender, you can use a circular saw on your shotgun to make it easier to store. -As a Janitor, if someone steals your janicart, you can instead use your space cleaner spray, grenades, water sprayer, exact bloody revenge or order another from Cargo. +As the Bartender, you can use a circular saw on your shotgun to make it easier to store. Make sure to empty them prior lest you blast yourself in the face! +As a Janitor, if someone steals your janicart, you can instead use your spray bottles, soap, and arsenal of slippery objects to exact your bloody revenge.. ..or just order another one from Cargo. As a Janitor, the trash bag can be used to hold more than trash. Tools, medical equipment, smuggled nuclear disks... You name it! -As a Janitor, mousetraps can be used to create bombs or booby-trap containers. -Beware the Curator, for they are not completely defenseless. The curator's whip always disarms people, their laser pointer can blind humans and cyborgs, and can hide items in wirecut books. +As a Janitor, mousetraps can be used as bomb triggers to booby-trap containers. +As the Curator, for what it's worth, your toys and position are fairly robust. You can order a claymore, a whip, or a free space suit all at roundstart. The claymore is fairly underwhelming, however the whip is an incredibly robust weapon capable of always disarming, and that space suit is also better than the ones in EVA. As the Curator, be sure to keep the shelves stocked and the library clean for crew. As a Cargo Technician, you can hack MULEbots to make them faster, run over people in their way, and even let you ride them! As a Cargo Technician, you can order contraband items from the supply shuttle console by de-constructing it and using a multitool on the circuit board, the re-assembling it. As a Cargo Technician, you can earn more cargo points by shipping back crates from maintenance, liquid containers, plasma sheets, rare seeds from hydroponics, and more! As a Cargo Technician, you get 400 points per packet! Stamp the manifest and sending back the crate will give you 200 points for the paperwork and 200 points for the crate! -As a Cargo Technician, paperwork is an alternative option to shipping off plasma sheets and other goods. Order Paperwork crates and go into the crafting menu to turn pens and undone paper work into completed grant paper work to get 50 points per sheet! +As a Cargo Technician, paperwork and glass blowing are alternative options to shipping off plasma sheets and other goods. Order their respective kits and get to work! Paperwork can be done quickly via the crafting menu for a quick buck, while glass blowing is much more lucrative, but may require some more effort and time. As the Quartermaster, be sure to check the manifests on crates you receive to make sure all the info is correct. If there's a mistake, stamp the manifest DENIED and send it back in a crate with the items untouched for a refund! As the Quartermaster, you can construct an express supply console that instantly delivers crates by drop pod. The impact will cause a small explosion as well. As a Shaft Miner, the northern side of Lavaland has a lot more rare minerals than on the south. @@ -177,25 +190,25 @@ As a Shaft Miner, every monster on Lavaland has a pattern you can exploit to min As a Shaft Miner, you can harvest goliath plates from goliaths and upgrade your explorer's suit, mining hardsuits as well as Firefighter APLUs with them, greatly reducing incoming melee damage. As a Shaft Miner, always have a GPS on you, so a fellow miner or cyborg can come to save you if you die. As a Shaft Miner, you can craft a variety of equipment from the local fauna. Bone axes, lava boats and ash drake armour are just a few of them! -As a Traitor, the cryptographic sequencer (emag) can not only open doors, but also lockers, crates, APCs and more. It can hack cyborgs, and even cause bots to go berserk. Use it on the right machines, and you can even order more traitor gear or contact the Syndicate. Experiment! +As a Traitor, the cryptographic sequencer (emag) can not only open lockers, crates, APCs and more. It can also do things like hack cyborgs, and even cause bots to go berserk. Use it on the right machines, and you can even contact the Syndicate. Experiment! As a Traitor, subverting the AI to serve you can make it an extremely powerful ally. However, be careful of the wording in the laws you give it, as it may use your poorly written laws against you! As a Traitor, the Captain and the Head of Security are two of the most difficult to kill targets on the station. If either one is your target, plan carefully. -As a Traitor, you can manufacture and recycle revolver bullets at a hacked autolathe, making the revolver an extremely powerful tool. +As a Traitor, you can manufacture and recycle revolver bullets at a hacked autolathe, making the revolver an extremely powerful tool if you manage to nab an autolathe for yourself. As a Traitor, you may sometimes be assigned to hunt other traitors, and in turn be hunted by others. As a Traitor, the syndicate encryption key is very useful for coordinating plans with your fellow traitors -- or, of course, betraying them. As a Traitor, plasma can be injected into many things to sabotage them. Power cells, light bulbs, cigars and e-cigs will all explode when used. As a Nuclear Operative, communication is key! Use :t or :h to speak to your fellow operatives and coordinate an attack plan. -As a Nuclear Operative, you should look into purchasing a syndicate cyborg, as they can provide heavy fire support, full access, are immune to conventional stuns, and can easily take down the AI. +As a Nuclear Operative, you should look into purchasing one of the three Syndicate cyborgs in your uplink, as they can provide useful tactical support, function as walking access machines, are immune to conventional stuns, and can easily take down the AI. As a Nuclear Operative, stick together! While your equipment is robust, your fellow operatives are much better at saving your life: they can drag you away from danger while stunned and provide cover fire. As a Nuclear Operative, you might end up in a situation where the AI has bolted you into a room. Having some spare C4 in your pocket can save your life. As a Monkey, you can crawl through air or scrubber vents by alt+left clicking them. You must drop everything you are wearing and holding to do this, however. As a Monkey, you can still wear a few human items, such as backpacks, gas masks and hats, and still have two free hands. As the Malfunctioning AI, you can shunt to an APC if the situation gets bad. This disables your doomsday device if it is active. -As the Malfunctioning AI, you should either order your cyborgs to dismantle the robotics console or blow it up yourself in order to protect them. +As the Malfunctioning AI, you should either order your cyborgs to dismantle the robotics console or blow it up yourself in order to protect them. Do note that this will prevent you from hacking any cyborg made in the future. As the Malfunctioning AI, look into flooding the station with plasma fires to kill off large portions of the crew, letting you pick off the remaining few with space suits who escaped. -Xenomorphs? Science can craft deadly tech shells like pulse slugs and laser scatter shot that are highly effective against any alien threat. -When fighting aliens, it can be a good idea to turn off the gravity due to the alien's lack of zero-gravity control. -When fighting xenomorph aliens, consider a shield. Shields can block their pounces and be worn on the back, but beware of neurotoxin. +Xenomorphs? Any source of burn damage severely harms them. Science can craft deadly tech shells like pulse slugs and laser scatter shot that are highly effective against any alien threat. +When fighting Aliens, it can be a good idea to turn off the gravity due to the every caste of alien's lack of zero-gravity control, especially Hunters and Drones, which are completely and utterly helpless. +When fighting Aliens, consider a shield. A raised shield can halt their attempts to slash at you, and their disarms will always remove an item in your hand before knocking you over, always having something in your hand, no matter how small or worthless, can save your life. As an Alien, your melee prowess is unmatched, but your ranged abilities are sorely lacking. Make use of corners to force a melee confrontation! As an Alien, you take double damage from all burn attacks, such as lasers, welding tools, and fires. Furthermore, fire can destroy your resin and eggs. Expose areas to space to starve away any flamethrower fires before they can do damage! As an Alien, resin floors not only regenerate your plasma supply, but also passively heal you. Fight on resin floors to gain a home turf advantage! @@ -212,6 +225,7 @@ As the Blob, you can produce a Blobbernaut from a factory for 40 resources. Blob As the Blob, you can expand by clicking, create strong blobs with ctrl-click, rally spores with middle-click, and remove blobs with alt-click. You do not need to have your camera over the tile to do this. As the Blob, removing strong blobs, resource nodes, factories, and nodes will give you 4, 15, 25, and 25 resources back, respectively. As the Blob, talking will send a message to all other overminds and all Blobbernauts, allowing you to direct attacks and coordinate. +As the Blob, always make sure where you land is where you want to be, as it is very unlikely you will be getting too far away from it. Land in key points like the armory or the medical bay to immediately cripple the crew before they even find out you exist. Of course, always take into mind if being immediately discovered may outweight the benefits, and stick to maintenance close to these key points of interest to you. As a Blobbernaut, you can communicate with overminds and other Blobbernauts via :b. As a Blobbernaut, your HUD shows your health and the core health of the overmind that created you. As a Revolutionary, you cannot convert a head of staff or someone who has a mindshield implant, such as a security officer or those they implant. Implants can however be surgically removed, and do not carry over with cloning. Take control of medbay to keep control of conversions! @@ -220,6 +234,11 @@ As a Revolutionary, cargo can be your best friend or your worst nightmare. In th As a Revolutionary, your main power comes from how quickly you spread. Convert people as fast as you can and overwhelm the heads of staff before security can arm up. As a Changeling, the Extract DNA sting counts for your genome absorb objective, but does not let you respec your powers. As a Changeling, you can absorb someone by strangling them and using the Absorb verb; this gives you the ability to rechoose your powers, the DNA of whoever you absorbed, the memory of the absorbed, and some samples of things the absorbed said. +As a Changeling, absorbing someone will give you their full memory. This can include things such as a Traitor's uplink, thus absorbing one will allow you to access the Traitor uplink and buy toys for your Changeling self to abuse. +As a Changeling, absorbing another Changeling will permanently boost your chemical reserve, allow you to pick more abilities, and make the victim unable to revive. Be careful when exposing your identity to other Changelings, as they may be out of those wonderful benefits. +As a Changeling, BZ gas will dramatically slow down or even halt your natural chemical regeneration, be sure to avoid it at all costs as some lunatics may try and flood portions of the station to deal with you. +As a Changeling, death is not the end for you! You can revive after two minutes from being dead by triggering your stasis ability, and then waiting for the prompt to resurrect yourself to show up. +As a Changeling, your Regenerate Limbs power will quickly heal all of your wounds, but they'll still leave scars. Changelings can use Fleshmend to get rid of scars, or you can ingest Carpotoxin to get rid of them like a normal person. As a Cultist, do not cause too much chaos before your objective is completed. If the shuttle gets called too soon, you may not have enough time to win. As a Cultist, your team starts off very weak, but if necessary can quickly convert everything they have into raw power. Make sure you have the numbers and equipment to support going loud, or the cult will fall flat on its face. As a Cultist, the Blood Boil rune will deal massive amounts of brute damage to non-cultists, stamina damage to Ratvarian scum, and some damage to fellow cultists of Nar-Sie nearby, but will create a fire where the rune stands on use. @@ -239,9 +258,10 @@ You can deconvert Cultists of Nar-Sie and Servants of Ratvar by feeding them lar Tiles sprayed with holy water will permanently block Servants of Ratvar from teleporting onto them. As a Wizard, you can turn people to stone, then animate the resulting statue with a staff of animation to create an extremely powerful minion, for all of 5 minutes at least. As a Wizard, the fireball spell performs very poorly at close range, as it can easily catch you in the blast. It is best used as a form of artillery down long hallways. -As a Wizard, summoning guns will turn a large portion of the crew against themselves, but will also give everyone anything from a pea shooter to a BFG 9000. Use at your own risk! +As a Wizard, summoning guns will turn a large portion of the crew against themselves, but will also give everyone anything from a energy pistol to a pulse rifle. Use at your own risk! As a Wizard, the staff of chaos can fire any type of bolts from the magical wands. This can range from bolts of instant death to healing or reviving someone. As a Wizard, most spells become unusable if you are not wearing your robe, hat, and sandals. +As a Wizard, it's advisable that you don't dump all of your limited spell points into solely offensive spells, if you can't defend yourself then you're sure to get dunked. As an Abductor, you can select where your victims will be sent on the ship control console. As an Abductor Agent, the combat mode vest has much higher resistance to every kind of weapon, and your helmet prevents the AI from tracking you. As an Abductor, the baton can cycle between four modes: stun, sleep, cuff and probe. @@ -260,17 +280,24 @@ As a Drone, you can ping other drones to alert them of areas in the station in n As a Drone, you can repair yourself by using a screwdriver on yourself and standing still! As a Ghost, you can see the inside of a container on the ground by clicking on it. As a Ghost, you can double click on just about anything to follow it. Or just warp around! +As a Ghost, there's a button in the OOC tab labeled Observe, it lets you see through someone's eyes as if you were the one who's playing them. As a Devil, you gain power for every three souls you control, however you also become more obvious. As a Devil, as long as you control at least one other soul, you will automatically resurrect, as long as a banishment ritual is not performed. At which time a Devil's nameth is spake on the tongue of man, the Devil may appeareth. You can swap floor tiles by holding a crowbar in one hand and a stack of tiles in the other. -When hacking doors, cutting and mending the "test light wire" will restore power to the door. -When hacking, remote singulars pulse when attached to a wire and pinged. This can allow you to hack things or set traps from far away. +When hacking doors, cutting and mending a "test light wire" will restore power to the door. When crafting most items, you can either manually combine parts or use the crafting menu. Suit storage units not only remove blood and dirt from clothing, but also radiation! Remote devices will work when used through cameras. For example: Bluespace RPEDs and door remotes. +You can light a cigar on a supermatter crystal. +Using sticky tape on items can make them stick to people and walls! Be careful, grenades might stick to your hand during the moment of truth! +In a pinch, stripping yourself naked will give you a sizeable resistance to being tackled. What do you value more, your freedom or your dignity? +Wearing riot armor makes you significantly more effective at performing tackle takedowns, but will use extra stamina with each leap! It will also significantly protect you from other tackles! +Epipens contain a powerful coagulant that drastically reduces bleeding on all bleeding wounds. If you don't have time to properly treat someone with lots of slashes or piercings, stick them with a pen to buy some time! +Anything you can light a cigarette with, you can use to cauterize a bleeding wound. Technically, that includes the supermatter. +Suit storage units entirely purge radiation from any carbon mob put inside of them when cycling, at the cost of some horrific burns, this is a very effective strategy to clean someone up after they bathed in the engine. Laser pointers can be upgraded by replacing its micro laser with a better one from RnD! Use a screwdriver on it to remove the old laser. Upgrading the laser pointer gives you better odds of stunning a cyborg, and even blinding people with sunglasses. -Being out of combat mode makes makes you deal less damage to people and objects when attacking. -Resting makes you deal less damage to people and objects when attacking. +Being out of combat mode makes makes you deal less damage to people and objects when attacking. This stacks with the penalty incurred by resting. +Resting makes you deal less damage to people and objects when attacking. This stacks with the penalty incurred by being out of combat mode. You do not regenerate as much stamina while in combat mode. Resting (being on the ground) makes you regenerate stamina faster. Remember to be in combat mode while in combat, as otherwise you will be penalized by taking more incoming damage and dealing less damage to your adversary. diff --git a/strings/traumas.json b/strings/traumas.json index f461c5f5fd..58170bd55a 100644 --- a/strings/traumas.json +++ b/strings/traumas.json @@ -125,13 +125,13 @@ ";chemist can u @pick(create_verbs) holy @pick(mellens) for @pick(s_roles)???!!", "@pick(semicolon) LIZZARRD SPEAKIGN IN EVIL BULL LANGUAGE SCI!!", "@pick(semicolon)POST REBOOT MESSAGE LOLOL FUCK FUCK FUCK YOU", - "@pick(semicolon)so, i was trying to talk to someone on rp today, and then a mime walks up and pies them in the face along with some other prankster--i thought that mimes and clowns are supposed to be hired to entertain not to be a nuisance, and that if entertainment comes at someone elses expense then it's not supposed to be done. is that enough to like submit a player complaint or some shit or am i just being petty?", "@pick(semicolon)*nya", "@pick(semicolon)*awoo", "@pick(semicolon)*merp", "@pick(semicolon)*weh", "@pick(semicolon)My balls finally feel full, again.", - "@pick(semicolon)Assaltign a sec osficer aren't crime if ur @pick(roles)" + "@pick(semicolon)Assaltign a sec osficer aren't crime if ur @pick(roles)", + ";SEC I SPILED MU JICE HELELPH HELPJ JLEP HELP" ], "mutations": [ diff --git a/tgstation.dme b/tgstation.dme index faa1ce990c..79c4274722 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -47,6 +47,7 @@ #include "code\__DEFINES\dynamic.dm" #include "code\__DEFINES\economy.dm" #include "code\__DEFINES\events.dm" +#include "code\__DEFINES\exosuit_fabs.dm" #include "code\__DEFINES\exports.dm" #include "code\__DEFINES\fantasy_affixes.dm" #include "code\__DEFINES\food.dm" @@ -80,6 +81,7 @@ #include "code\__DEFINES\networks.dm" #include "code\__DEFINES\pinpointers.dm" #include "code\__DEFINES\pipe_construction.dm" +#include "code\__DEFINES\plumbing.dm" #include "code\__DEFINES\pool.dm" #include "code\__DEFINES\power.dm" #include "code\__DEFINES\preferences.dm" @@ -300,6 +302,7 @@ #include "code\controllers\subsystem\events.dm" #include "code\controllers\subsystem\fail2topic.dm" #include "code\controllers\subsystem\fire_burning.dm" +#include "code\controllers\subsystem\fluid.dm" #include "code\controllers\subsystem\garbage.dm" #include "code\controllers\subsystem\holodeck.dm" #include "code\controllers\subsystem\icon_smooth.dm" @@ -375,6 +378,7 @@ #include "code\datums\datumvars.dm" #include "code\datums\dna.dm" #include "code\datums\dog_fashion.dm" +#include "code\datums\ductnet.dm" #include "code\datums\emotes.dm" #include "code\datums\ert.dm" #include "code\datums\explosion.dm" @@ -430,6 +434,7 @@ #include "code\datums\components\field_of_vision.dm" #include "code\datums\components\footstep.dm" #include "code\datums\components\fried.dm" +#include "code\datums\components\gps.dm" #include "code\datums\components\identification.dm" #include "code\datums\components\igniter.dm" #include "code\datums\components\infective.dm" @@ -487,6 +492,11 @@ #include "code\datums\components\fantasy\affix.dm" #include "code\datums\components\fantasy\prefixes.dm" #include "code\datums\components\fantasy\suffixes.dm" +#include "code\datums\components\plumbing\_plumbing.dm" +#include "code\datums\components\plumbing\chemical_acclimator.dm" +#include "code\datums\components\plumbing\filter.dm" +#include "code\datums\components\plumbing\reaction_chamber.dm" +#include "code\datums\components\plumbing\splitter.dm" #include "code\datums\components\storage\storage.dm" #include "code\datums\components\storage\ui.dm" #include "code\datums\components\storage\concrete\_concrete.dm" @@ -556,6 +566,7 @@ #include "code\datums\elements\_element.dm" #include "code\datums\elements\art.dm" #include "code\datums\elements\beauty.dm" +#include "code\datums\elements\bsa_blocker.dm" #include "code\datums\elements\cleaning.dm" #include "code\datums\elements\decal.dm" #include "code\datums\elements\dusts_on_catatonia.dm" @@ -725,6 +736,7 @@ #include "code\game\gamemodes\dynamic\dynamic_rulesets_midround.dm" #include "code\game\gamemodes\dynamic\dynamic_rulesets_roundstart.dm" #include "code\game\gamemodes\dynamic\dynamic_storytellers.dm" +#include "code\game\gamemodes\eldritch_cult\eldritch_cult.dm" #include "code\game\gamemodes\extended\extended.dm" #include "code\game\gamemodes\gangs\dominator.dm" #include "code\game\gamemodes\gangs\dominator_countdown.dm" @@ -1278,6 +1290,7 @@ #include "code\game\objects\structures\crates_lockers\crates\secure.dm" #include "code\game\objects\structures\crates_lockers\crates\wooden.dm" #include "code\game\objects\structures\icemoon\cave_entrance.dm" +#include "code\game\objects\structures\lavaland\geyser.dm" #include "code\game\objects\structures\lavaland\necropolis_tendril.dm" #include "code\game\objects\structures\signs\_signs.dm" #include "code\game\objects\structures\signs\signs_departments.dm" @@ -1294,6 +1307,7 @@ #include "code\game\turfs\open.dm" #include "code\game\turfs\turf.dm" #include "code\game\turfs\openspace\openspace.dm" +#include "code\game\turfs\openspace\transparent.dm" #include "code\game\turfs\simulated\chasm.dm" #include "code\game\turfs\simulated\dirtystation.dm" #include "code\game\turfs\simulated\floor.dm" @@ -1389,6 +1403,7 @@ #include "code\modules\admin\view_variables\mark_datum.dm" #include "code\modules\admin\view_variables\mass_edit_variables.dm" #include "code\modules\admin\view_variables\modify_variables.dm" +#include "code\modules\admin\view_variables\reference_tracking.dm" #include "code\modules\admin\view_variables\topic.dm" #include "code\modules\admin\view_variables\topic_basic.dm" #include "code\modules\admin\view_variables\topic_list.dm" @@ -1407,6 +1422,7 @@ #include "code\modules\antagonists\abductor\equipment\abduction_outfits.dm" #include "code\modules\antagonists\abductor\equipment\abduction_surgery.dm" #include "code\modules\antagonists\abductor\equipment\gland.dm" +#include "code\modules\antagonists\abductor\equipment\orderable_gear.dm" #include "code\modules\antagonists\abductor\equipment\glands\access.dm" #include "code\modules\antagonists\abductor\equipment\glands\blood.dm" #include "code\modules\antagonists\abductor\equipment\glands\chem.dm" @@ -1595,6 +1611,16 @@ #include "code\modules\antagonists\disease\disease_disease.dm" #include "code\modules\antagonists\disease\disease_event.dm" #include "code\modules\antagonists\disease\disease_mob.dm" +#include "code\modules\antagonists\eldritch_cult\eldritch_antag.dm" +#include "code\modules\antagonists\eldritch_cult\eldritch_book.dm" +#include "code\modules\antagonists\eldritch_cult\eldritch_effects.dm" +#include "code\modules\antagonists\eldritch_cult\eldritch_items.dm" +#include "code\modules\antagonists\eldritch_cult\eldritch_knowledge.dm" +#include "code\modules\antagonists\eldritch_cult\eldritch_magic.dm" +#include "code\modules\antagonists\eldritch_cult\eldritch_monster_antag.dm" +#include "code\modules\antagonists\eldritch_cult\knowledge\ash_lore.dm" +#include "code\modules\antagonists\eldritch_cult\knowledge\flesh_lore.dm" +#include "code\modules\antagonists\eldritch_cult\knowledge\rust_lore.dm" #include "code\modules\antagonists\ert\ert.dm" #include "code\modules\antagonists\fugitive\fugitive.dm" #include "code\modules\antagonists\fugitive\fugitive_outfits.dm" @@ -2271,6 +2297,7 @@ #include "code\modules\language\swarmer.dm" #include "code\modules\language\sylvan.dm" #include "code\modules\language\vampiric.dm" +#include "code\modules\language\voltaic.dm" #include "code\modules\language\xenocommon.dm" #include "code\modules\library\lib_codex_gigas.dm" #include "code\modules\library\lib_items.dm" @@ -2285,6 +2312,11 @@ #include "code\modules\lighting\lighting_setup.dm" #include "code\modules\lighting\lighting_source.dm" #include "code\modules\lighting\lighting_turf.dm" +#include "code\modules\mafia\_defines.dm" +#include "code\modules\mafia\controller.dm" +#include "code\modules\mafia\map_pieces.dm" +#include "code\modules\mafia\outfits.dm" +#include "code\modules\mafia\roles.dm" #include "code\modules\mapping\map_config.dm" #include "code\modules\mapping\map_orientation_pattern.dm" #include "code\modules\mapping\map_template.dm" @@ -2499,6 +2531,7 @@ #include "code\modules\mob\living\carbon\human\species_types\corporate.dm" #include "code\modules\mob\living\carbon\human\species_types\dullahan.dm" #include "code\modules\mob\living\carbon\human\species_types\dwarves.dm" +#include "code\modules\mob\living\carbon\human\species_types\ethereal.dm" #include "code\modules\mob\living\carbon\human\species_types\felinid.dm" #include "code\modules\mob\living\carbon\human\species_types\flypeople.dm" #include "code\modules\mob\living\carbon\human\species_types\furrypeople.dm" @@ -2579,6 +2612,7 @@ #include "code\modules\mob\living\simple_animal\constructs.dm" #include "code\modules\mob\living\simple_animal\corpse.dm" #include "code\modules\mob\living\simple_animal\damage_procs.dm" +#include "code\modules\mob\living\simple_animal\eldritch_demons.dm" #include "code\modules\mob\living\simple_animal\parrot.dm" #include "code\modules\mob\living\simple_animal\pickle.dm" #include "code\modules\mob\living\simple_animal\shade.dm" @@ -2612,6 +2646,7 @@ #include "code\modules\mob\living\simple_animal\friendly\penguin.dm" #include "code\modules\mob\living\simple_animal\friendly\pet.dm" #include "code\modules\mob\living\simple_animal\friendly\plushie.dm" +#include "code\modules\mob\living\simple_animal\friendly\possum.dm" #include "code\modules\mob\living\simple_animal\friendly\sloth.dm" #include "code\modules\mob\living\simple_animal\friendly\snake.dm" #include "code\modules\mob\living\simple_animal\friendly\drone\_drone.dm" @@ -2719,6 +2754,7 @@ #include "code\modules\mob\living\simple_animal\slime\slime_mobility.dm" #include "code\modules\mob\living\simple_animal\slime\subtypes.dm" #include "code\modules\modular_computers\laptop_vendor.dm" +#include "code\modules\modular_computers\computers\_modular_computer_shared.dm" #include "code\modules\modular_computers\computers\item\computer.dm" #include "code\modules\modular_computers\computers\item\computer_components.dm" #include "code\modules\modular_computers\computers\item\computer_damage.dm" @@ -2739,13 +2775,16 @@ #include "code\modules\modular_computers\file_system\programs\airestorer.dm" #include "code\modules\modular_computers\file_system\programs\alarm.dm" #include "code\modules\modular_computers\file_system\programs\arcade.dm" +#include "code\modules\modular_computers\file_system\programs\atmosscan.dm" #include "code\modules\modular_computers\file_system\programs\card.dm" +#include "code\modules\modular_computers\file_system\programs\cargobounty.dm" #include "code\modules\modular_computers\file_system\programs\configurator.dm" +#include "code\modules\modular_computers\file_system\programs\crewmanifest.dm" #include "code\modules\modular_computers\file_system\programs\file_browser.dm" +#include "code\modules\modular_computers\file_system\programs\jobmanagement.dm" #include "code\modules\modular_computers\file_system\programs\ntdownloader.dm" #include "code\modules\modular_computers\file_system\programs\ntmonitor.dm" #include "code\modules\modular_computers\file_system\programs\ntnrc_client.dm" -#include "code\modules\modular_computers\file_system\programs\nttransfer.dm" #include "code\modules\modular_computers\file_system\programs\powermonitor.dm" #include "code\modules\modular_computers\file_system\programs\radar.dm" #include "code\modules\modular_computers\file_system\programs\robocontrol.dm" @@ -2829,6 +2868,21 @@ #include "code\modules\photography\photos\album.dm" #include "code\modules\photography\photos\frame.dm" #include "code\modules\photography\photos\photo.dm" +#include "code\modules\plumbing\ducts.dm" +#include "code\modules\plumbing\plumbers\_plumb_machinery.dm" +#include "code\modules\plumbing\plumbers\acclimator.dm" +#include "code\modules\plumbing\plumbers\autohydro.dm" +#include "code\modules\plumbing\plumbers\bottler.dm" +#include "code\modules\plumbing\plumbers\destroyer.dm" +#include "code\modules\plumbing\plumbers\fermenter.dm" +#include "code\modules\plumbing\plumbers\filter.dm" +#include "code\modules\plumbing\plumbers\grinder_chemical.dm" +#include "code\modules\plumbing\plumbers\medipenrefill.dm" +#include "code\modules\plumbing\plumbers\pill_press.dm" +#include "code\modules\plumbing\plumbers\pumps.dm" +#include "code\modules\plumbing\plumbers\reaction_chamber.dm" +#include "code\modules\plumbing\plumbers\splitters.dm" +#include "code\modules\plumbing\plumbers\synthesizer.dm" #include "code\modules\pool\pool_controller.dm" #include "code\modules\pool\pool_drain.dm" #include "code\modules\pool\pool_effects.dm" @@ -3078,6 +3132,7 @@ #include "code\modules\research\research_disk.dm" #include "code\modules\research\server.dm" #include "code\modules\research\stock_parts.dm" +#include "code\modules\research\anomaly\anomaly_core.dm" #include "code\modules\research\designs\AI_module_designs.dm" #include "code\modules\research\designs\autobotter_designs.dm" #include "code\modules\research\designs\autoylathe_designs.dm" @@ -3247,9 +3302,9 @@ #include "code\modules\spells\spell.dm" #include "code\modules\spells\spell_types\aimed.dm" #include "code\modules\spells\spell_types\area_teleport.dm" -#include "code\modules\spells\spell_types\barnyard.dm" #include "code\modules\spells\spell_types\bloodcrawl.dm" #include "code\modules\spells\spell_types\charge.dm" +#include "code\modules\spells\spell_types\cone_spells.dm" #include "code\modules\spells\spell_types\conjure.dm" #include "code\modules\spells\spell_types\construct_spells.dm" #include "code\modules\spells\spell_types\curse.dm" @@ -3268,7 +3323,6 @@ #include "code\modules\spells\spell_types\lichdom.dm" #include "code\modules\spells\spell_types\lightning.dm" #include "code\modules\spells\spell_types\mime.dm" -#include "code\modules\spells\spell_types\mind_transfer.dm" #include "code\modules\spells\spell_types\projectile.dm" #include "code\modules\spells\spell_types\rightandwrong.dm" #include "code\modules\spells\spell_types\rod_form.dm" @@ -3285,6 +3339,10 @@ #include "code\modules\spells\spell_types\turf_teleport.dm" #include "code\modules\spells\spell_types\voice_of_god.dm" #include "code\modules\spells\spell_types\wizard.dm" +#include "code\modules\spells\spell_types\pointed\barnyard.dm" +#include "code\modules\spells\spell_types\pointed\blind.dm" +#include "code\modules\spells\spell_types\pointed\mind_transfer.dm" +#include "code\modules\spells\spell_types\pointed\pointed.dm" #include "code\modules\station_goals\bsa.dm" #include "code\modules\station_goals\dna_vault.dm" #include "code\modules\station_goals\shield.dm" @@ -3360,15 +3418,14 @@ #include "code\modules\tgs\includes.dm" #include "code\modules\tgui\external.dm" #include "code\modules\tgui\states.dm" -#include "code\modules\tgui\subsystem.dm" #include "code\modules\tgui\tgui.dm" +#include "code\modules\tgui\tgui_window.dm" #include "code\modules\tgui\states\admin.dm" #include "code\modules\tgui\states\always.dm" #include "code\modules\tgui\states\conscious.dm" #include "code\modules\tgui\states\contained.dm" #include "code\modules\tgui\states\deep_inventory.dm" #include "code\modules\tgui\states\default.dm" -#include "code\modules\tgui\states\default_contained.dm" #include "code\modules\tgui\states\hands.dm" #include "code\modules\tgui\states\human_adjacent.dm" #include "code\modules\tgui\states\inventory.dm" diff --git a/tgui/.eslintrc.yml b/tgui/.eslintrc.yml index 67e74085c7..9fd4db9fd2 100644 --- a/tgui/.eslintrc.yml +++ b/tgui/.eslintrc.yml @@ -8,6 +8,8 @@ env: es6: true browser: true node: true +globals: + Byond: readonly plugins: - react settings: @@ -388,7 +390,7 @@ rules: ## Enforce a particular style for multiline comments # multiline-comment-style: error ## Enforce newlines between operands of ternary expressions - multiline-ternary: [error, always-multiline] + # multiline-ternary: [error, always-multiline] ## Require constructor names to begin with a capital letter # new-cap: error ## Enforce or disallow parentheses when invoking a constructor with no diff --git a/tgui/.gitattributes b/tgui/.gitattributes index 0016cc3bf6..9382416e69 100644 --- a/tgui/.gitattributes +++ b/tgui/.gitattributes @@ -2,9 +2,18 @@ ## Enforce text mode and LF line breaks *.js text eol=lf +*.jsx text eol=lf +*.ts text eol=lf +*.tsx text eol=lf *.css text eol=lf +*.scss text eol=lf *.html text eol=lf *.json text eol=lf +*.yml text eol=lf +*.md text eol=lf +*.bat text eol=lf +yarn.lock text eol=lf +bin/tgui text eol=lf ## Treat bundles as binary and ignore them during conflicts *.bundle.* binary merge=tgui-merge-bundle diff --git a/tgui/README.md b/tgui/README.md index 5ddeb18fdd..9eab0196de 100644 --- a/tgui/README.md +++ b/tgui/README.md @@ -67,8 +67,9 @@ Run one of the following: game as you code it. Very useful, highly recommended. - In order to use it, you should start the game server first, connect to it and wait until the world has been properly loaded and you are no longer - in the lobby. Start tgui dev server. You'll know that it's hooked correctly - if data gets dumped to the log when tgui windows are opened. + in the lobby. Start tgui dev server, and once it has finished building, + press F5 on any tgui window. You'll know that it's hooked correctly if + you see a green bug icon in titlebar and data gets dumped to the console. - `bin/tgui --dev --reload` - reload byond cache once. - `bin/tgui --dev --debug` - run server with debug logging enabled. - `bin/tgui --dev --no-hot` - disable hot module replacement (helps when @@ -134,11 +135,11 @@ logs and time spent on rendering. Use this information to optimize your code, and try to keep re-renders below 16ms. **Kitchen Sink.** -Press `Ctrl+Alt+=` to open the KitchenSink interface. This interface is a +Press `F12` to open the KitchenSink interface. This interface is a playground to test various tgui components. **Layout Debugger.** -Press `Ctrl+Alt+-` to toggle the *layout debugger*. It will show outlines of +Press `F11` to toggle the *layout debugger*. It will show outlines of all tgui elements, which makes it easy to understand how everything comes together, and can reveal certain layout bugs which are not normally visible. @@ -180,8 +181,11 @@ See: [Component Reference](docs/component-reference.md). ## License -All code is licensed with the parent license of *tgstation*, **AGPL-3.0**. +Source code is covered by /tg/station's parent license - **AGPL-3.0** +(see the main [README](../README.md)), unless otherwise indicated. -See the main [README](../README.md) for more details. +Some files are annotated with a copyright header, which explicitly states +the copyright holder and license of the file. Most of the core tgui +source code is available under the **MIT** license. The Authors retain all copyright to their respective work here submitted. diff --git a/tgui/bin/tgui b/tgui/bin/tgui index eb1f200b31..97a86159e6 100755 --- a/tgui/bin/tgui +++ b/tgui/bin/tgui @@ -52,6 +52,7 @@ task-dev-server() { task-eslint() { cd "${base_dir}" eslint ./packages "${@}" + echo "tgui: eslint check passed" } ## Mr. Proper @@ -153,6 +154,13 @@ if [[ ${1} == '--lint-harder' ]]; then exit 0 fi +if [[ ${1} == '--fix' ]]; then + shift 1 + task-install + task-eslint --fix "${@}" + exit 0 +fi + ## Analyze the bundle if [[ ${1} == '--analyze' ]]; then task-install diff --git a/tgui/docs/component-reference.md b/tgui/docs/component-reference.md index a2a0066a70..ff1b4e7dfd 100644 --- a/tgui/docs/component-reference.md +++ b/tgui/docs/component-reference.md @@ -30,6 +30,8 @@ Make sure to add new items to this list if you document new components. - [`Icon`](#icon) - [`Input`](#input) - [`Knob`](#knob) + - [`LabeledControls`](#labeledcontrols) + - [`LabeledControls.Item`](#labeledcontrolsitem) - [`LabeledList`](#labeledlist) - [`LabeledList.Item`](#labeledlistitem) - [`LabeledList.Divider`](#labeledlistdivider) @@ -239,7 +241,7 @@ A ghetto checkbox, made entirely using existing Button API. ### `Button.Confirm` -A button with a an extra confirmation step, using native button component. +A button with an extra confirmation step, using native button component. **Props:** @@ -273,11 +275,11 @@ interface. Example (button): -``` +```jsx @@ -285,11 +287,10 @@ Example (button): Example (map): -``` +```jsx ``` @@ -584,6 +585,24 @@ the input, or successfully enter a number. - `onDrag: (e, value) => void` - An event, which fires about every 500ms when you drag the input up and down, on release and on manual editing. +### `LabeledControls` + +LabeledControls is a horizontal grid, that is designed to hold various +controls, like [Knobs](#knob) or small [Buttons](#button). Every item in +this grid is labeled at the bottom. + +**Props:** + +- See inherited props: [Box](#box) +- `children: LabeledControls.Item` - Items to render. + +### `LabeledControls.Item` + +**Props:** + +- See inherited props: [Box](#box) +- `label: string` - Item label. + ### `LabeledList` LabeledList is a continuous, vertical list of text and other content, where @@ -962,6 +981,7 @@ Example: - `className: string` - Applies a CSS class to the element. - `theme: string` - A name of the theme. - For a list of themes, see `packages/tgui/styles/themes`. +- `title: string` - Window title. - `resizable: boolean` - Controls resizability of the window. - `children: any` - Child elements, which are rendered directly inside the window. If you use a [Dimmer](#dimmer) or [Modal](#modal) in your UI, diff --git a/tgui/docs/converting-old-tgui-interfaces.md b/tgui/docs/converting-old-tgui-interfaces.md index a42724e05c..fe2feebfee 100644 --- a/tgui/docs/converting-old-tgui-interfaces.md +++ b/tgui/docs/converting-old-tgui-interfaces.md @@ -73,6 +73,7 @@ This might look a bit intimidating compared to the reactive part but it's not as You don't really need to know all this to understand how to use it, but I find it helps with understanding when things go wrong. Ractive conditionals can have an `else` as well + ```ractive {{#if data.condition}} value @@ -116,7 +117,7 @@ and you can mix string literals, values, and tags as well. Ractive has loops for iterating over data and inserting something for each member of an array or object -``` +```ractive {{#each data.list_of_foo}} foo {{number}} is here. {{/each}} @@ -135,6 +136,7 @@ Objects are represented by `{}`, arrays by `[]` `list("bla", "blo")` would become `["bla", "blo"]` and `list("foo" = 1, "bar" = 2)` would become `{"foo": 1, "bar": 2}` First things first, above the `return` of the function you're making the interface in, you're going to want to add something like this + ```jsx const things = data.things || []; ``` @@ -142,6 +144,7 @@ const things = data.things || []; This ensures that you'll never be reading a null entry by mistake. Substitute `{}` for objects as appropriate. If it's an array, you'll want to do this in the template + ```jsx {things.map(thing => ( @@ -187,7 +190,7 @@ const fooArray = toArray(fooObject); Also occasionally you'd see an else: -``` +```ractive {{#each data.potentially_empty_list}} Thing "{{name}}" is in this list! {{else}} @@ -220,7 +223,7 @@ This will be a reference of tgui components and the tgui-next equivalent. Equivalent of `` is `
` -``` +```ractive Contents @@ -236,7 +239,7 @@ becomes A feature sometimes used is if `ui-display` has the `button` property, it will contain a `partial` command. This becomes the `buttons` property on `Section`: -``` +```ractive {{#partial button}} // lots more button bullshit here @@ -263,7 +266,7 @@ Very important to note `ui-section` is NOT the equivalent of `Section` `` does not have a direct equivalent, but the closest equivalent is `` -``` +```ractive No Power @@ -293,7 +296,7 @@ Also good to know that if you need the contents of a `LabeledList.Item` to be co `` has a direct equivalent in `` -``` +```ractive Notice stuff! @@ -311,7 +314,7 @@ becomes The equivalent of `ui-button` is `Button` but it works quite a bit differently. -``` +```ractive {
@@ -294,10 +292,10 @@ here's what you need (note that you'll probably be forced to clean your shit up upon code review): ```dm -/obj/copypasta/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = 0, datum/tgui/master_ui = null, datum/ui_state/state = default_state) // Remember to use the appropriate state. - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) +/obj/copypasta/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) if(!ui) - ui = new(user, src, ui_key, "copypasta", name, 300, 300, master_ui, state) + ui = new(user, src, "copypasta") ui.open() /obj/copypasta/ui_data(mob/user) @@ -345,7 +343,7 @@ export const SampleInterface = (props, context) => { + ))} + + + + + + + + + + ); +}; + +const KitchenSinkButton = props => { + return ( +
+ +
+ ); +}; + +const KitchenSinkBox = props => { + return ( +
+ + bold + + + italic + + + opacity 0.5 + + + opacity 0.25 + + + m: 2 + + + left + + + center + + + right + +
+ ); +}; + +const KitchenSinkFlexAndSections = (props, context) => { + const [grow, setGrow] = useLocalState( + context, 'fs_grow', 1); + const [direction, setDirection] = useLocalState( + context, 'fs_direction', 'column'); + const [fill, setFill] = useLocalState( + context, 'fs_fill', true); + const [hasTitle, setHasTitle] = useLocalState( + context, 'fs_title', true); + return ( + + +
+ + + + +
+
+ + + +
+ Content +
+
+ +
+ Content +
+
+
+
+
+ ); +}; + +const KitchenSinkProgressBar = (props, context) => { + const [ + progress, + setProgress, + ] = useLocalState(context, 'progress', 0.5); + return ( +
+ + Value: {Number(progress).toFixed(1)} + + +
+ ); +}; + +const KitchenSinkTabs = (props, context) => { + const [tabIndex, setTabIndex] = useLocalState(context, 'tabIndex', 0); + const [vertical, setVertical] = useLocalState(context, 'tabVert'); + const [altSelection, setAltSelection] = useLocalState(context, 'tabAlt'); + const TAB_RANGE = [1, 2, 3, 4, 5]; + return ( +
+ + setVertical(!vertical)} /> + setAltSelection(!altSelection)} /> + + + {TAB_RANGE.map((number, i) => ( + setTabIndex(i)}> + Tab #{number} + + ))} + +
+ ); +}; + +const KitchenSinkTooltip = props => { + const positions = [ + 'top', + 'left', + 'right', + 'bottom', + 'bottom-left', + 'bottom-right', + ]; + return ( +
+ + + Box (hover me). + + +
+ ); +}; + +const KitchenSinkInput = (props, context) => { + const [ + number, + setNumber, + ] = useLocalState(context, 'number', 0); + const [ + text, + setText, + ] = useLocalState(context, 'text', "Sample text"); + return ( +
+ + + setText(value)} /> + + + setText(value)} /> + + + setNumber(value)} /> + + + setNumber(value)} /> + + + setNumber(value)} /> + + + setNumber(value)} /> + setNumber(value)} /> + + + + setNumber(value)}> + {control => ( + + + {control.inputElement} + + )} + + + + +
+ ); +}; + +const KitchenSinkCollapsible = props => { + return ( +
+ + )}> + + +
+ ); +}; + +const BoxWithSampleText = props => { + return ( + + + Jackdaws love my big sphinx of quartz. + + + The wide electrification of the southern + provinces will give a powerful impetus to the + growth of agriculture. + + + ); +}; + +const KitchenSinkBlockQuote = props => { + return ( +
+
+ +
+
+ ); +}; + +const KitchenSinkByondUi = (props, context) => { + const { config } = useBackend(context); + const [code, setCode] = useLocalState(context, + 'byondUiEvalCode', + `Byond.winset('${window.__windowId__}', {\n 'is-visible': true,\n})`); + return ( + +
+ +
+
setImmediate(() => { + try { + const result = new Function('return (' + code + ')')(); + if (result && result.then) { + logger.log('Promise'); + result.then(logger.log); + } + else { + logger.log(result); + } + } + catch (err) { + logger.log(err); + } + })}> + Evaluate + + )}> + setCode(e.target.value)}> + {code} + +
+
+ ); +}; + +const KitchenSinkThemes = (props, context) => { + const [theme, setTheme] = useLocalState(context, 'kitchenSinkTheme'); + return ( +
+ + + setTheme(value)} /> + + +
+ ); +}; + +const KitchenSinkStorage = (props, context) => { + if (!window.localStorage) { + return ( + + Local storage is not available. + + ); + } + return ( +
{ + localStorage.clear(); + }}> + Clear + + )}> + + + {localStorage.length} + + + {formatSiUnit(localStorage.remainingSpace, 0, 'B')} + + +
+ ); +}; diff --git a/tgui/packages/tgui/debug/index.js b/tgui/packages/tgui/debug/index.js new file mode 100644 index 0000000000..83fc136548 --- /dev/null +++ b/tgui/packages/tgui/debug/index.js @@ -0,0 +1,49 @@ +/** + * @file + * @copyright 2020 Aleksej Komarov + * @license MIT + */ + +import { subscribeToHotKey } from '../hotkeys'; + +export const toggleKitchenSink = () => ({ + type: 'debug/toggleKitchenSink', +}); + +export const toggleDebugLayout = () => ({ + type: 'debug/toggleDebugLayout', +}); + +subscribeToHotKey('F11', () => toggleDebugLayout()); +subscribeToHotKey('F12', () => toggleKitchenSink()); +subscribeToHotKey('Ctrl+Alt+[8]', () => { + // NOTE: We need to call this in a timeout, because we need a clean + // stack in order for this to be a fatal error. + setTimeout(() => { + throw new Error( + 'OOPSIE WOOPSIE!! UwU We made a fucky wucky!! A wittle' + + ' fucko boingo! The code monkeys at our headquarters are' + + ' working VEWY HAWD to fix this!'); + }); +}); + +export const selectDebug = state => state.debug; + +export const useDebug = context => selectDebug(context.store.getState()); + +export const debugReducer = (state = {}, action) => { + const { type, payload } = action; + if (type === 'debug/toggleKitchenSink') { + return { + ...state, + kitchenSink: !state.kitchenSink, + }; + } + if (type === 'debug/toggleDebugLayout') { + return { + ...state, + debugLayout: !state.debugLayout, + }; + } + return state; +}; diff --git a/tgui/packages/tgui/drag.js b/tgui/packages/tgui/drag.js index a29146b796..99db716410 100644 --- a/tgui/packages/tgui/drag.js +++ b/tgui/packages/tgui/drag.js @@ -1,76 +1,174 @@ -import { vecAdd, vecInverse, vecMultiply } from 'common/vector'; -import { winget, winset } from './byond'; +/** + * @file + * @copyright 2020 Aleksej Komarov + * @license MIT + */ + +import { storage } from 'common/storage'; +import { vecAdd, vecInverse, vecMultiply, vecScale } from 'common/vector'; import { createLogger } from './logging'; const logger = createLogger('drag'); -let ref; +let windowKey = window.__windowId__; let dragging = false; let resizing = false; let screenOffset = [0, 0]; +let screenOffsetPromise; let dragPointOffset; let resizeMatrix; let initialSize; let size; -const getWindowPosition = ref => { - return winget(ref, 'pos').then(pos => [pos.x, pos.y]); +export const setWindowKey = key => { + windowKey = key; }; -const setWindowPosition = (ref, vec) => { - return winset(ref, 'pos', vec[0] + ',' + vec[1]); +export const getWindowPosition = () => [ + window.screenLeft, + window.screenTop, +]; + +export const getWindowSize = () => [ + window.innerWidth, + window.innerHeight, +]; + +export const setWindowPosition = vec => { + const byondPos = vecAdd(vec, screenOffset); + return Byond.winset(window.__windowId__, { + pos: byondPos[0] + ',' + byondPos[1], + }); }; -const setWindowSize = (ref, vec) => { - return winset(ref, 'size', vec[0] + ',' + vec[1]); +export const setWindowSize = vec => { + return Byond.winset(window.__windowId__, { + size: vec[0] + 'x' + vec[1], + }); }; -export const setupDrag = async state => { - logger.log('setting up'); - ref = state.config.window; - // Calculate offset caused by windows taskbar - const realPosition = await getWindowPosition(ref); - screenOffset = [ - realPosition[0] - window.screenLeft, - realPosition[1] - window.screenTop, - ]; - // Constraint window position - const [relocated, safePosition] = constraintPosition(realPosition); - if (relocated) { - setWindowPosition(ref, safePosition); +export const getScreenPosition = () => [ + 0 - screenOffset[0], + 0 - screenOffset[1], +]; + +export const getScreenSize = () => [ + window.screen.availWidth, + window.screen.availHeight, +]; + +/** + * Moves an item to the top of the recents array, and keeps its length + * limited to the number in `limit` argument. + * + * Uses a strict equality check for comparisons. + * + * Returns new recents and an item which was trimmed. + */ +const touchRecents = (recents, touchedItem, limit = 50) => { + const nextRecents = [touchedItem]; + let trimmedItem; + for (let i = 0; i < recents.length; i++) { + const item = recents[i]; + if (item === touchedItem) { + continue; + } + if (nextRecents.length < limit) { + nextRecents.push(item); + } + else { + trimmedItem = item; + } } - logger.debug('current state', { ref, screenOffset }); + return [nextRecents, trimmedItem]; +}; + +export const storeWindowGeometry = windowKey => { + logger.log('storing geometry'); + const geometry = { + pos: getWindowPosition(), + size: getWindowSize(), + }; + storage.set(windowKey, geometry); + // Update the list of stored geometries + const [geometries, trimmedKey] = touchRecents( + storage.get('geometries') || [], + windowKey); + if (trimmedKey) { + storage.remove(trimmedKey); + } + storage.set('geometries', geometries); +}; + +export const recallWindowGeometry = async (windowKey, options = {}) => { + // Only recall geometry in fancy mode + const geometry = options.fancy && storage.get(windowKey); + if (geometry) { + logger.log('recalled geometry:', geometry); + } + let pos = geometry?.pos || options.pos; + const size = options.size; + // Set window size + if (size) { + setWindowSize(size); + } + // Set window position + if (pos) { + await screenOffsetPromise; + // Constraint window position if monitor lock was set in preferences. + if (size && options.locked) { + pos = constraintPosition(pos, size)[1]; + } + setWindowPosition(pos); + } + // Set window position at the center of the screen. + else if (size) { + await screenOffsetPromise; + const areaAvailable = [ + window.screen.availWidth - Math.abs(screenOffset[0]), + window.screen.availHeight - Math.abs(screenOffset[1]), + ]; + const pos = vecAdd( + vecScale(areaAvailable, 0.5), + vecScale(size, -0.5), + vecScale(screenOffset, -1.0)); + setWindowPosition(pos); + } +}; + +export const setupDrag = async () => { + // Calculate screen offset caused by the windows taskbar + screenOffsetPromise = Byond.winget(window.__windowId__, 'pos') + .then(pos => [ + pos.x - window.screenLeft, + pos.y - window.screenTop, + ]); + screenOffset = await screenOffsetPromise; + logger.debug('screen offset', screenOffset); }; /** * Constraints window position to safe screen area, accounting for safe * margins which could be a system taskbar. */ -const constraintPosition = position => { - let x = position[0]; - let y = position[1]; +const constraintPosition = (pos, size) => { + const screenPos = getScreenPosition(); + const screenSize = getScreenSize(); + const nextPos = [pos[0], pos[1]]; let relocated = false; - // Left - if (x < 0) { - x = 0; - relocated = true; + for (let i = 0; i < 2; i++) { + const leftBoundary = screenPos[i]; + const rightBoundary = screenPos[i] + screenSize[i]; + if (pos[i] < leftBoundary) { + nextPos[i] = leftBoundary; + relocated = true; + } + else if (pos[i] + size[i] > rightBoundary) { + nextPos[i] = rightBoundary - size[i]; + relocated = true; + } } - // Right - else if (x + window.innerWidth > window.screen.availWidth) { - x = window.screen.availWidth - window.innerWidth; - relocated = true; - } - // Top - if (y < 0) { - y = 0; - relocated = true; - } - // Bottom - else if (y + window.innerHeight > window.screen.availHeight) { - y = window.screen.availHeight - window.innerHeight; - relocated = true; - } - return [relocated, [x, y]]; + return [relocated, nextPos]; }; export const dragStartHandler = event => { @@ -91,6 +189,7 @@ const dragEndHandler = event => { document.removeEventListener('mousemove', dragMoveHandler); document.removeEventListener('mouseup', dragEndHandler); dragging = false; + storeWindowGeometry(windowKey); }; const dragMoveHandler = event => { @@ -98,9 +197,8 @@ const dragMoveHandler = event => { return; } event.preventDefault(); - setWindowPosition(ref, vecAdd( + setWindowPosition(vecAdd( [event.screenX, event.screenY], - screenOffset, dragPointOffset)); }; @@ -127,6 +225,7 @@ const resizeEndHandler = event => { document.removeEventListener('mousemove', resizeMoveHandler); document.removeEventListener('mouseup', resizeEndHandler); resizing = false; + storeWindowGeometry(windowKey); }; const resizeMoveHandler = event => { @@ -140,7 +239,7 @@ const resizeMoveHandler = event => { dragPointOffset, [1, 1]))); // Sane window size values - size[0] = Math.max(size[0], 250); - size[1] = Math.max(size[1], 120); - setWindowSize(ref, size); + size[0] = Math.max(size[0], 150); + size[1] = Math.max(size[1], 50); + setWindowSize(size); }; diff --git a/tgui/packages/tgui/format.js b/tgui/packages/tgui/format.js index 8ce1915f51..1f8420860e 100644 --- a/tgui/packages/tgui/format.js +++ b/tgui/packages/tgui/format.js @@ -1,3 +1,9 @@ +/** + * @file + * @copyright 2020 Aleksej Komarov + * @license MIT + */ + import { clamp, round, toFixed } from 'common/math'; const SI_SYMBOLS = [ @@ -28,7 +34,14 @@ const SI_BASE_INDEX = SI_SYMBOLS.indexOf(' '); * Formats a number to a human readable form, by reducing it to SI units. * TODO: This is quite a shit code and shit math, needs optimization. */ -const formatSiUnit = (value, minBase1000 = -SI_BASE_INDEX, unit = '') => { +export const formatSiUnit = ( + value, + minBase1000 = -SI_BASE_INDEX, + unit = '' +) => { + if (typeof value !== 'number' || !Number.isFinite(value)) { + return value; + } const realBase10 = Math.floor(Math.log10(value)); const base10 = Math.floor(Math.max(minBase1000 * 3, realBase10)); const realBase1000 = Math.floor(realBase10 / 3); diff --git a/tgui/packages/tgui/global.d.ts b/tgui/packages/tgui/global.d.ts new file mode 100644 index 0000000000..ab8870f15c --- /dev/null +++ b/tgui/packages/tgui/global.d.ts @@ -0,0 +1,95 @@ +interface ByondType { + /** + * True if javascript is running in BYOND. + */ + IS_BYOND: boolean; + + /** + * True if browser is IE8 or lower. + */ + IS_LTE_IE8: boolean; + + /** + * True if browser is IE9 or lower. + */ + IS_LTE_IE9: boolean; + + /** + * True if browser is IE10 or lower. + */ + IS_LTE_IE10: boolean; + + /** + * True if browser is IE11 or lower. + */ + IS_LTE_IE11: boolean; + + /** + * Makes a BYOND call. + * + * If path is empty, this will trigger a Topic call. + * You can reference a specific object by setting the "src" parameter. + * + * See: https://secure.byond.com/docs/ref/skinparams.html + */ + call(path: string, params: object): void; + + /** + * Makes an asynchronous BYOND call. Returns a promise. + */ + callAsync(path: string, params: object): Promise; + + /** + * Makes a Topic call. + * + * You can reference a specific object by setting the "src" parameter. + */ + topic(params: object): void; + + /** + * Runs a command or a verb. + */ + command(command: string): void; + + /** + * Retrieves all properties of the BYOND skin element. + * + * Returns a promise with a key-value object containing all properties. + */ + winget(id: string): Promise; + + /** + * Retrieves all properties of the BYOND skin element. + * + * Returns a promise with a key-value object containing all properties. + */ + winget(id: string, propName: '*'): Promise; + + /** + * Retrieves an exactly one property of the BYOND skin element, + * as defined in `propName`. + * + * Returns a promise with the value of that property. + */ + winget(id: string, propName: string): Promise; + + /** + * Retrieves multiple properties of the BYOND skin element, + * as listen in the `propNames` array. + * + * Returns a promise with a key-value object containing listed properties. + */ + winget(id: string, propNames: string[]): Promise; + + /** + * Assigns properties to the BYOND skin element. + */ + winset(id: string, props: object): void; + + /** + * Sets a property on the BYOND skin element to a certain value. + */ + winset(id: string, propName: string, propValue: any): void; +}; + +declare const Byond: ByondType; diff --git a/tgui/packages/tgui/hotkeys.js b/tgui/packages/tgui/hotkeys.js index 30c1b910bf..0beff6b028 100644 --- a/tgui/packages/tgui/hotkeys.js +++ b/tgui/packages/tgui/hotkeys.js @@ -1,4 +1,9 @@ -import { callByond, IS_IE8 } from './byond'; +/** + * @file + * @copyright 2020 Aleksej Komarov + * @license MIT + */ + import { createLogger } from './logging'; const logger = createLogger('hotkeys'); @@ -48,6 +53,18 @@ export const KEY_W = 87; export const KEY_X = 88; export const KEY_Y = 89; export const KEY_Z = 90; +export const KEY_F1 = 112; +export const KEY_F2 = 113; +export const KEY_F3 = 114; +export const KEY_F4 = 115; +export const KEY_F5 = 116; +export const KEY_F6 = 117; +export const KEY_F7 = 118; +export const KEY_F8 = 119; +export const KEY_F9 = 120; +export const KEY_F10 = 121; +export const KEY_F11 = 122; +export const KEY_F12 = 123; export const KEY_EQUAL = 187; export const KEY_MINUS = 189; @@ -64,6 +81,18 @@ const NO_PASSTHROUGH_KEYS = [ KEY_TAB, KEY_CTRL, KEY_SHIFT, + KEY_F1, + KEY_F2, + KEY_F3, + KEY_F4, + KEY_F5, + KEY_F6, + KEY_F7, + KEY_F8, + KEY_F9, + KEY_F10, + KEY_F11, + KEY_F12, ]; // Tracks the "pressed" state of keys @@ -83,6 +112,9 @@ const createHotkeyString = (ctrlKey, altKey, shiftKey, keyCode) => { if (keyCode >= 48 && keyCode <= 90) { str += String.fromCharCode(keyCode); } + else if (keyCode >= KEY_F1 && keyCode <= KEY_F12) { + str += 'F' + (keyCode - 111); + } else { str += '[' + keyCode + ']'; } @@ -129,11 +161,11 @@ const handlePassthrough = (e, eventType) => { // Send this keypress to BYOND if (eventType === 'keydown' && !keyState[keyCode]) { logger.debug('passthrough', eventType, keyData); - return callByond('', { __keydown: keyCode }); + return Byond.topic({ __keydown: keyCode }); } if (eventType === 'keyup' && keyState[keyCode]) { logger.debug('passthrough', eventType, keyData); - return callByond('', { __keyup: keyCode }); + return Byond.topic({ __keyup: keyCode }); } }; @@ -146,41 +178,45 @@ export const releaseHeldKeys = () => { if (keyState[keyCode]) { logger.log(`releasing [${keyCode}] key`); keyState[keyCode] = false; - callByond('', { __keyup: keyCode }); + Byond.topic({ __keyup: keyCode }); } } }; -const handleHotKey = (e, eventType, dispatch) => { +const hotKeySubscribers = []; + +/** + * Subscribes to a certain hotkey, and dispatches a redux action returned + * by the callback function. + */ +export const subscribeToHotKey = (keyString, fn) => { + hotKeySubscribers.push((store, keyData) => { + if (keyData.keyString === keyString) { + const action = fn(store); + if (action) { + store.dispatch(action); + } + } + }); +}; + +const handleHotKey = (e, eventType, store) => { if (eventType !== 'keyup') { return; } const keyData = getKeyData(e); const { - ctrlKey, - altKey, keyCode, hasModifierKeys, keyString, } = keyData; // Dispatch a detected hotkey as a store action - if (hasModifierKeys && !MODIFIER_KEYS.includes(keyCode)) { + if (hasModifierKeys && !MODIFIER_KEYS.includes(keyCode) + || keyCode >= KEY_F1 && keyCode <= KEY_F12) { logger.log(keyString); - // Fun stuff - if (ctrlKey && altKey && keyCode === KEY_BACKSPACE) { - // NOTE: We need to call this in a timeout, because we need a clean - // stack in order for this to be a fatal error. - setTimeout(() => { - throw new Error( - 'OOPSIE WOOPSIE!! UwU We made a fucky wucky!! A wittle' - + ' fucko boingo! The code monkeys at our headquarters are' - + ' working VEWY HAWD to fix this!'); - }); + for (let subscriberFn of hotKeySubscribers) { + subscriberFn(store, keyData); } - dispatch({ - type: 'hotKey', - payload: keyData, - }); } }; @@ -218,18 +254,17 @@ const subscribeToKeyPresses = listenerFn => { // Middleware export const hotKeyMiddleware = store => { - const { dispatch } = store; // Subscribe to key events subscribeToKeyPresses((e, eventType) => { // IE8: Can't determine the focused element, so by extension it passes // keypresses when inputs are focused. - if (!IS_IE8) { + if (!Byond.IS_LTE_IE8) { handlePassthrough(e, eventType); } - handleHotKey(e, eventType, dispatch); + handleHotKey(e, eventType, store); }); // IE8: focusin/focusout only available on IE9+ - if (!IS_IE8) { + if (!Byond.IS_LTE_IE8) { // Clean up when browser window completely loses focus subscribeToLossOfFocus(() => { releaseHeldKeys(); @@ -238,27 +273,3 @@ export const hotKeyMiddleware = store => { // Pass through store actions (do nothing) return next => action => next(action); }; - -// Reducer -export const hotKeyReducer = (state, action) => { - const { type, payload } = action; - if (type === 'hotKey') { - const { ctrlKey, altKey, keyCode } = payload; - // Toggle kitchen sink mode - if (ctrlKey && altKey && keyCode === KEY_EQUAL) { - return { - ...state, - showKitchenSink: !state.showKitchenSink, - }; - } - // Toggle layout debugger - if (ctrlKey && altKey && keyCode === KEY_MINUS) { - return { - ...state, - debugLayout: !state.debugLayout, - }; - } - return state; - } - return state; -}; diff --git a/tgui/packages/tgui/index.js b/tgui/packages/tgui/index.js index fb778ac58c..69092ce00f 100644 --- a/tgui/packages/tgui/index.js +++ b/tgui/packages/tgui/index.js @@ -1,3 +1,9 @@ +/** + * @file + * @copyright 2020 Aleksej Komarov + * @license MIT + */ + // Polyfills import 'core-js/es'; import 'core-js/web/immediate'; @@ -12,75 +18,80 @@ import './polyfills/inferno'; // Themes import './styles/main.scss'; -import './styles/themes/malfunction.scss'; -import './styles/themes/ntos.scss'; +import './styles/themes/abductor.scss'; +import './styles/themes/cardtable.scss'; import './styles/themes/hackerman.scss'; +import './styles/themes/malfunction.scss'; +import './styles/themes/neutral.scss'; +import './styles/themes/ntos.scss'; +import './styles/themes/paper.scss'; import './styles/themes/retro.scss'; import './styles/themes/syndicate.scss'; import './styles/themes/clockcult.scss'; -import './styles/themes/paper.scss'; -import { loadCSS } from 'fg-loadcss'; +import { perf } from 'common/perf'; import { render } from 'inferno'; import { setupHotReloading } from 'tgui-dev-server/link/client'; -import { backendUpdate } from './backend'; -import { IS_IE8 } from './byond'; +import { backendUpdate, backendSuspendSuccess, selectBackend, sendMessage } from './backend'; import { setupDrag } from './drag'; import { logger } from './logging'; import { createStore, StoreProvider } from './store'; -const enteredBundleAt = Date.now(); +perf.mark('inception', window.__inception__); +perf.mark('init'); + const store = createStore(); let reactRoot; let initialRender = true; const renderLayout = () => { - // Mark the beginning of the render - let startedAt; - if (process.env.NODE_ENV !== 'production') { - startedAt = Date.now(); - } - try { - const state = store.getState(); - // Initial render setup - if (initialRender) { - logger.log('initial render', state); - // Setup dragging - setupDrag(state); + perf.mark('render/start'); + const state = store.getState(); + const { suspended, assets } = selectBackend(state); + // Initial render setup + if (initialRender) { + logger.log('initial render', state); + // Setup dragging + if (initialRender !== 'recycled') { + setupDrag(); } - // Start rendering - const { getRoutedComponent } = require('./routes'); - const Component = getRoutedComponent(state); - const element = ( - - - - ); - if (!reactRoot) { - reactRoot = document.getElementById('react-root'); - } - render(element, reactRoot); } - catch (err) { - logger.error('rendering error', err); - throw err; + // Start rendering + const { getRoutedComponent } = require('./routes'); + const Component = getRoutedComponent(state); + const element = ( + + + + ); + if (!reactRoot) { + reactRoot = document.getElementById('react-root'); } + render(element, reactRoot); + if (suspended) { + return; + } + perf.mark('render/finish'); // Report rendering time if (process.env.NODE_ENV !== 'production') { - const finishedAt = Date.now(); - if (initialRender) { + if (initialRender === 'recycled') { + logger.log('rendered in', + perf.measure('render/start', 'render/finish')); + } + else if (initialRender) { logger.debug('serving from:', location.href); - logger.debug('bundle entered in', timeDiff( - window.__inception__, enteredBundleAt)); - logger.debug('initialized in', timeDiff( - enteredBundleAt, startedAt)); - logger.log('rendered in', timeDiff( - startedAt, finishedAt)); - logger.log('fully loaded in', timeDiff( - window.__inception__, finishedAt)); + logger.debug('bundle entered in', + perf.measure('inception', 'init')); + logger.debug('initialized in', + perf.measure('init', 'render/start')); + logger.log('rendered in', + perf.measure('render/start', 'render/finish')); + logger.log('fully loaded in', + perf.measure('inception', 'render/finish')); } else { - logger.debug('rendered in', timeDiff(startedAt, finishedAt)); + logger.debug('rendered in', + perf.measure('render/start', 'render/finish')); } } if (initialRender) { @@ -88,12 +99,6 @@ const renderLayout = () => { } }; -const timeDiff = (startedAt, finishedAt) => { - const diff = finishedAt - startedAt; - const diffFrames = (diff / 16.6667).toFixed(2); - return `${diff}ms (${diffFrames} frames)`; -}; - // Parse JSON and report all abnormal JSON strings coming from BYOND const parseStateJson = json => { let reviver = (key, value) => { @@ -106,7 +111,7 @@ const parseStateJson = json => { }; // IE8: No reviver for you! // See: https://stackoverflow.com/questions/1288962 - if (IS_IE8) { + if (Byond.IS_LTE_IE8) { reviver = undefined; } try { @@ -127,14 +132,36 @@ const setupApp = () => { }); // Subscribe for bankend updates - window.update = stateJson => { - // NOTE: stateJson can be an object only if called manually from console. + window.update = messageJson => { + const { suspended } = selectBackend(store.getState()); + // NOTE: messageJson can be an object only if called manually from console. // This is useful for debugging tgui in external browsers, like Chrome. - const state = typeof stateJson === 'string' - ? parseStateJson(stateJson) - : stateJson; - // Backend update dispatches a store action - store.dispatch(backendUpdate(state)); + const message = typeof messageJson === 'string' + ? parseStateJson(messageJson) + : messageJson; + logger.debug(`received message '${message?.type}'`); + const { type, payload } = message; + if (type === 'update') { + if (suspended) { + logger.log('resuming'); + initialRender = 'recycled'; + } + // Backend update dispatches a store action + store.dispatch(backendUpdate(payload)); + return; + } + if (type === 'suspend') { + store.dispatch(backendSuspendSuccess()); + return; + } + if (type === 'ping') { + sendMessage({ + type: 'pingReply', + }); + return; + } + // Pass the message directly to the store + store.dispatch(message); }; // Enable hot module reloading @@ -157,9 +184,26 @@ const setupApp = () => { } window.update(stateJson); } +}; - // Dynamically load font-awesome from browser's cache - loadCSS('font-awesome.css'); +// Setup a fatal error reporter +window.__logger__ = { + fatal: (error, stack) => { + // Get last state for debugging purposes + const backendState = selectBackend(store.getState()); + const reportedState = { + config: backendState.config, + suspended: backendState.suspended, + suspending: backendState.suspending, + }; + // Send to development server + logger.log('FatalError:', error || stack); + logger.log('State:', reportedState); + // Append this data to the stack + stack += '\nState: ' + JSON.stringify(reportedState); + // Return an updated stack + return stack; + }, }; if (document.readyState === 'loading') { diff --git a/tgui/packages/tgui/interfaces/AbductorConsole.js b/tgui/packages/tgui/interfaces/AbductorConsole.js new file mode 100644 index 0000000000..de750bc9ca --- /dev/null +++ b/tgui/packages/tgui/interfaces/AbductorConsole.js @@ -0,0 +1,157 @@ +import { GenericUplink } from './Uplink'; +import { useBackend, useSharedState } from '../backend'; +import { Button, LabeledList, NoticeBox, Section, Tabs } from '../components'; +import { Fragment } from 'inferno'; +import { Window } from '../layouts'; + +export const AbductorConsole = (props, context) => { + const [tab, setTab] = useSharedState(context, 'tab', 1); + return ( + + + + setTab(1)}> + Abductsoft 3000 + + setTab(2)}> + Mission Settings + + + {tab === 1 && ( + + )} + {tab === 2 && ( + + + + + )} + + + ); +}; + +const Abductsoft = (props, context) => { + const { act, data } = useBackend(context); + const { + experiment, + points, + credits, + } = data; + + if (!experiment) { + return ( + + No Experiment Machine Detected + + ); + } + + return ( + +
+ + + {points} + + +
+ +
+ ); +}; + +const EmergencyTeleporter = (props, context) => { + const { act, data } = useBackend(context); + const { + pad, + gizmo, + } = data; + + if (!pad) { + return ( + + No Telepad Detected + + ); + } + + return ( +
act('teleporter_send')} /> + )}> + + +
+ ); +}; + +const VestSettings = (props, context) => { + const { act, data } = useBackend(context); + const { + vest, + vest_mode, + vest_lock, + } = data; + + if (!vest) { + return ( + + No Agent Vest Detected + + ); + } + + return ( +
act('toggle_vest')} /> + )}> + + +
+ ); +}; diff --git a/tgui/packages/tgui/interfaces/Achievements.js b/tgui/packages/tgui/interfaces/Achievements.js index 464708d248..512c39fb59 100644 --- a/tgui/packages/tgui/interfaces/Achievements.js +++ b/tgui/packages/tgui/interfaces/Achievements.js @@ -12,7 +12,11 @@ export const Achievements = (props, context) => { const achievements = data.achievements .filter(x => x.category === selectedCategory); return ( - + {categories.map(category => ( diff --git a/tgui/packages/tgui/interfaces/AiAirlock.js b/tgui/packages/tgui/interfaces/AiAirlock.js index 4886e71034..a48ce24402 100644 --- a/tgui/packages/tgui/interfaces/AiAirlock.js +++ b/tgui/packages/tgui/interfaces/AiAirlock.js @@ -24,7 +24,9 @@ export const AiAirlock = (props, context) => { const statusBackup = dangerMap[data.power.backup] || dangerMap[0]; const statusElectrify = dangerMap[data.shock] || dangerMap[0]; return ( - +
diff --git a/tgui/packages/tgui/interfaces/AiRestorer.js b/tgui/packages/tgui/interfaces/AiRestorer.js index e91d392d10..9dfacda0c8 100644 --- a/tgui/packages/tgui/interfaces/AiRestorer.js +++ b/tgui/packages/tgui/interfaces/AiRestorer.js @@ -5,7 +5,10 @@ import { Window } from '../layouts'; export const AiRestorer = () => { return ( - + diff --git a/tgui/packages/tgui/interfaces/AirAlarm.js b/tgui/packages/tgui/interfaces/AirAlarm.js index c6f440985a..e669d8d948 100644 --- a/tgui/packages/tgui/interfaces/AirAlarm.js +++ b/tgui/packages/tgui/interfaces/AirAlarm.js @@ -6,12 +6,16 @@ import { Box, Button, LabeledList, NumberInput, Section } from '../components'; import { getGasLabel } from '../constants'; import { Window } from '../layouts'; import { InterfaceLockNoticeBox } from './common/InterfaceLockNoticeBox'; +import { Vent, Scrubber } from './common/AtmosControls'; export const AirAlarm = (props, context) => { const { act, data } = useBackend(context); const locked = data.locked && !data.siliconUser; return ( - + @@ -202,108 +206,6 @@ const AirAlarmControlVents = (props, context) => { )); }; -const Vent = (props, context) => { - const { vent } = props; - const { act } = useBackend(context); - const { - id_tag, - long_name, - power, - checks, - excheck, - incheck, - direction, - external, - internal, - extdefault, - intdefault, - } = vent; - return ( -
act('power', { - id_tag, - val: Number(!power), - })} /> - )}> - - - {direction === 'release' ? 'Pressurizing' : 'Releasing'} - - -
- ); -}; - - // Scrubbers // -------------------------------------------------------- @@ -320,71 +222,6 @@ const AirAlarmControlScrubbers = (props, context) => { )); }; -const Scrubber = (props, context) => { - const { scrubber } = props; - const { act } = useBackend(context); - const { - long_name, - power, - scrubbing, - id_tag, - widenet, - filter_types, - } = scrubber; - return ( -
act('power', { - id_tag, - val: Number(!power), - })} /> - )}> - - -
- ); -}; - - // Modes // -------------------------------------------------------- diff --git a/tgui/packages/tgui/interfaces/AirlockElectronics.js b/tgui/packages/tgui/interfaces/AirlockElectronics.js index e291052e25..a448f55e9b 100644 --- a/tgui/packages/tgui/interfaces/AirlockElectronics.js +++ b/tgui/packages/tgui/interfaces/AirlockElectronics.js @@ -12,7 +12,9 @@ export const AirlockElectronics = (props, context) => { const regions = data.regions || []; const accesses = data.accesses || []; return ( - +
diff --git a/tgui/packages/tgui/interfaces/Apc.js b/tgui/packages/tgui/interfaces/Apc.js index 0f44e3509d..60a11789bc 100644 --- a/tgui/packages/tgui/interfaces/Apc.js +++ b/tgui/packages/tgui/interfaces/Apc.js @@ -6,7 +6,10 @@ import { InterfaceLockNoticeBox } from './common/InterfaceLockNoticeBox'; export const Apc = (props, context) => { return ( - + @@ -82,7 +85,6 @@ const ApcContent = (props, context) => { ); } - return ( @@ -182,57 +184,35 @@ const ApcContent = (props, context) => { onClick={() => act('overload')} /> )}> - act('cover')} /> - )} /> - act('emergency_lighting')} /> - )} /> - act('toggle_nightshift')} /> - )} /> -
- {data.hijackable && ( -
+ + act('hijack')} /> -
); }; diff --git a/tgui/packages/tgui/interfaces/ApcControl.js b/tgui/packages/tgui/interfaces/ApcControl.js new file mode 100644 index 0000000000..449101d529 --- /dev/null +++ b/tgui/packages/tgui/interfaces/ApcControl.js @@ -0,0 +1,306 @@ +import { map, sortBy } from 'common/collections'; +import { flow } from 'common/fp'; +import { pureComponentHooks } from 'common/react'; +import { useBackend, useLocalState } from '../backend'; +import { Box, Button, Dimmer, Flex, Icon, Table, Tabs } from '../components'; +import { Fragment, Window } from '../layouts'; +import { AreaCharge, powerRank } from './PowerMonitor'; + +export const ApcControl = (props, context) => { + const { data } = useBackend(context); + return ( + + {data.authenticated === 1 && ( + + )} + {data.authenticated === 0 && ( + + )} + + ); +}; + +const ApcLoggedOut = (props, context) => { + const { act, data } = useBackend(context); + const { emagged } = data; + const text = emagged === 1 ? 'Open' : 'Log In'; + return ( + +
+
+
+ ); +}; diff --git a/tgui/packages/tgui/interfaces/AutomatedAnnouncement.js b/tgui/packages/tgui/interfaces/AutomatedAnnouncement.js index d7b517d961..0baea4de97 100644 --- a/tgui/packages/tgui/interfaces/AutomatedAnnouncement.js +++ b/tgui/packages/tgui/interfaces/AutomatedAnnouncement.js @@ -17,7 +17,10 @@ export const AutomatedAnnouncement = (props, context) => { newhead, } = data; return ( - +
{ station_name, } = data; return ( - +
- { amount, } = data; return ( - +
{ + const { data } = useBackend(context); + const { + beaker, + processing, + } = data; + return ( + + {!!processing && ( + + + {' Processing...'} + + )} + + {!beaker && ( + No Container + )} + {!!beaker && ( + + )} + + + ); +}; + +export const BiogeneratorContent = (props, context) => { + const { act, data } = useBackend(context); + const { + biomass, + can_process, + categories = [], + } = data; + const [ + searchText, + setSearchText, + ] = useLocalState(context, 'searchText', ''); + const [ + selectedCategory, + setSelectedCategory, + ] = useLocalState(context, 'category', categories[0]?.name); + const testSearch = createSearch(searchText, item => { + return item.name; + }); + const items = searchText.length > 0 + // Flatten all categories and apply search to it + && categories + .flatMap(category => category.items || []) + .filter(testSearch) + .filter((item, i) => i < MAX_SEARCH_RESULTS) + // Select a category and show all items in it + || categories + .find(category => category.name === selectedCategory) + ?.items + // If none of that results in a list, return an empty list + || []; + return ( +
0 ? 'good' : 'bad'}> + {formatMoney(biomass)} Biomass + + )} + buttons={( + + Search + setSearchText(value)} + mx={1} /> +
+ ); +}; + +const ItemList = (props, context) => { + const { act } = useBackend(context); + const [ + hoveredItem, + setHoveredItem, + ] = useLocalState(context, 'hoveredItem', {}); + const hoveredCost = hoveredItem && hoveredItem.cost || 0; + // Append extra hover data to items + const items = props.items.map(item => { + const [ + amount, + setAmount, + ] = useLocalState(context, "amount" + item.name, 1); + const notSameItem = hoveredItem && hoveredItem.name !== item.name; + const notEnoughHovered = props.biomass - hoveredCost + * hoveredItem.amount < item.cost * amount; + const disabledDueToHovered = notSameItem && notEnoughHovered; + const disabled = props.biomass < item.cost * amount || disabledDueToHovered; + return { + ...item, + disabled, + amount, + setAmount, + }; + }); + return items.map(item => ( + + + + {' '}{item.name} + + + item.setAmount(value)} /> + + +
+ + + ); +}; + +const BountyHeader = (props, context) => { + const { act, data } = useBackend(context); + const { + stored_cash, + } = data; + return ( + + formatMoney(value)} /> + {' credits'} + + ); +}; diff --git a/tgui/packages/tgui/interfaces/CargoExpress.js b/tgui/packages/tgui/interfaces/CargoExpress.js index 4e4ccf6a88..685569f6d5 100644 --- a/tgui/packages/tgui/interfaces/CargoExpress.js +++ b/tgui/packages/tgui/interfaces/CargoExpress.js @@ -8,7 +8,10 @@ import { InterfaceLockNoticeBox } from './common/InterfaceLockNoticeBox'; export const CargoExpress = (props, context) => { const { act, data } = useBackend(context); return ( - + diff --git a/tgui/packages/tgui/interfaces/CargoHoldTerminal.js b/tgui/packages/tgui/interfaces/CargoHoldTerminal.js index aaf66e701c..b20c0c9f9b 100644 --- a/tgui/packages/tgui/interfaces/CargoHoldTerminal.js +++ b/tgui/packages/tgui/interfaces/CargoHoldTerminal.js @@ -12,7 +12,10 @@ export const CargoHoldTerminal = (props, context) => { status_report, } = data; return ( - +
diff --git a/tgui/packages/tgui/interfaces/CellularEmporium.js b/tgui/packages/tgui/interfaces/CellularEmporium.js index 8e8d58cb94..07989d8bad 100644 --- a/tgui/packages/tgui/interfaces/CellularEmporium.js +++ b/tgui/packages/tgui/interfaces/CellularEmporium.js @@ -7,7 +7,10 @@ export const CellularEmporium = (props, context) => { const { act, data } = useBackend(context); const { abilities } = data; return ( - +
diff --git a/tgui/packages/tgui/interfaces/CentcomPodLauncher.js b/tgui/packages/tgui/interfaces/CentcomPodLauncher.js index 7b21239144..05982b2fbf 100644 --- a/tgui/packages/tgui/interfaces/CentcomPodLauncher.js +++ b/tgui/packages/tgui/interfaces/CentcomPodLauncher.js @@ -6,7 +6,11 @@ import { Window } from '../layouts'; export const CentcomPodLauncher = () => { return ( - + @@ -57,6 +61,42 @@ export const CentcomPodLauncherContent = (props, context) => { `} onClick={() => act('bay5')} /> + {!!data.effectReverse && ( + + - ))} - + {product === "pill" && ( + + {pill_styles.map(pill => ( + + ))} + + )}
diff --git a/tgui/packages/tgui/interfaces/ChemReactionChamber.js b/tgui/packages/tgui/interfaces/ChemReactionChamber.js index 9af7ef7ddb..cbcf5574d8 100644 --- a/tgui/packages/tgui/interfaces/ChemReactionChamber.js +++ b/tgui/packages/tgui/interfaces/ChemReactionChamber.js @@ -17,7 +17,10 @@ export const ChemReactionChamber = (props, context) => { const emptying = data.emptying; const reagents = data.reagents || []; return ( - +
{ max_transfer, } = data; return ( - +
diff --git a/tgui/packages/tgui/interfaces/ChemSynthesizer.js b/tgui/packages/tgui/interfaces/ChemSynthesizer.js index 26db58cb3a..536173f039 100644 --- a/tgui/packages/tgui/interfaces/ChemSynthesizer.js +++ b/tgui/packages/tgui/interfaces/ChemSynthesizer.js @@ -12,7 +12,9 @@ export const ChemSynthesizer = (props, context) => { possible_amounts = [], } = data; return ( - +
diff --git a/tgui/packages/tgui/interfaces/CivCargoHoldTerminal.js b/tgui/packages/tgui/interfaces/CivCargoHoldTerminal.js new file mode 100644 index 0000000000..5fe3874422 --- /dev/null +++ b/tgui/packages/tgui/interfaces/CivCargoHoldTerminal.js @@ -0,0 +1,103 @@ +import { Fragment } from 'inferno'; +import { useBackend } from '../backend'; +import { AnimatedNumber, Box, Button, Flex, LabeledList, NoticeBox, Section } from '../components'; +import { Window } from '../layouts'; + +export const CivCargoHoldTerminal = (props, context) => { + const { act, data } = useBackend(context); + const { + pad, + sending, + status_report, + id_inserted, + id_bounty_info, + id_bounty_value, + id_bounty_num, + } = data; + const in_text = "Welcome valued employee."; + const out_text = "To begin, insert your ID into the console."; + return ( + + + + + + {id_inserted ? in_text : out_text} + +
+ + + {pad ? "Online" : "Not Found"} + + + {status_report} + + +
+ +
+ + +
+ + ); +}; -const AreaCharge = props => { +export const AreaCharge = props => { const { charging, charge } = props; return ( diff --git a/tgui/packages/tgui/interfaces/ProbingConsole.js b/tgui/packages/tgui/interfaces/ProbingConsole.js new file mode 100644 index 0000000000..4115be4e4b --- /dev/null +++ b/tgui/packages/tgui/interfaces/ProbingConsole.js @@ -0,0 +1,83 @@ +import { useBackend } from '../backend'; +import { Button, LabeledList, NoticeBox, Section } from '../components'; +import { Window } from '../layouts'; + +export const ProbingConsole = (props, context) => { + const { act, data } = useBackend(context); + const { + open, + feedback, + occupant, + occupant_name, + occupant_status, + } = data; + return ( + + +
+ + + {feedback} + + +
+
act('door')} /> + )}> + {occupant && ( + + + {occupant_name} + + + {occupant_status === 3 + ? 'Deceased' + : occupant_status === 2 + ? 'Unconcious' + : 'Concious'} + + +
+
+
+ ); +}; diff --git a/tgui/packages/tgui/interfaces/ProximitySensor.js b/tgui/packages/tgui/interfaces/ProximitySensor.js index 8227d04802..c8dd04c3ee 100644 --- a/tgui/packages/tgui/interfaces/ProximitySensor.js +++ b/tgui/packages/tgui/interfaces/ProximitySensor.js @@ -12,7 +12,9 @@ export const ProximitySensor = (props, context) => { sensitivity, } = data; return ( - +
diff --git a/tgui/packages/tgui/interfaces/Radio.js b/tgui/packages/tgui/interfaces/Radio.js index 68b48d0230..738826ba63 100644 --- a/tgui/packages/tgui/interfaces/Radio.js +++ b/tgui/packages/tgui/interfaces/Radio.js @@ -25,8 +25,20 @@ export const Radio = (props, context) => { name: key, status: !!value, }))(data.channels); + // Calculate window height + let height = 106; + if (subspace) { + if (channels.length > 0) { + height += channels.length * 21 + 6; + } + else { + height += 24; + } + } return ( - +
diff --git a/tgui/packages/tgui/interfaces/RadioactiveMicrolaser.js b/tgui/packages/tgui/interfaces/RadioactiveMicrolaser.js index 40b6794d61..2fd20aa658 100644 --- a/tgui/packages/tgui/interfaces/RadioactiveMicrolaser.js +++ b/tgui/packages/tgui/interfaces/RadioactiveMicrolaser.js @@ -14,7 +14,11 @@ export const RadioactiveMicrolaser = (props, context) => { cooldown, } = data; return ( - +
diff --git a/tgui/packages/tgui/interfaces/RapidPipeDispenser.js b/tgui/packages/tgui/interfaces/RapidPipeDispenser.js index 54b664c57d..0380b7c4a3 100644 --- a/tgui/packages/tgui/interfaces/RapidPipeDispenser.js +++ b/tgui/packages/tgui/interfaces/RapidPipeDispenser.js @@ -72,7 +72,10 @@ export const RapidPipeDispenser = (props, context) => { .find(category => category.cat_name === categoryName) || categories[0]; return ( - +
diff --git a/tgui/packages/tgui/interfaces/RemoteRobotControl.js b/tgui/packages/tgui/interfaces/RemoteRobotControl.js index eb24bf22f8..91e0fa5ddf 100644 --- a/tgui/packages/tgui/interfaces/RemoteRobotControl.js +++ b/tgui/packages/tgui/interfaces/RemoteRobotControl.js @@ -6,7 +6,11 @@ import { Window } from '../layouts'; export const RemoteRobotControl = (props, context) => { return ( - + @@ -19,7 +23,6 @@ export const RemoteRobotControlContent = (props, context) => { const { robots = [], } = data; - if (!robots.length) { return (
@@ -29,7 +32,6 @@ export const RemoteRobotControlContent = (props, context) => {
); } - return robots.map(robot => { return (
{ + return ( + + + + + + ); +}; + +export const RequestKioskContent = (props, context) => { + const { act, data } = useBackend(context); + const { + accountName, + requests = [], + applicants = [], + bountyValue, + bountyText, + } = data; + const color = 'rgba(13, 13, 213, 0.7)'; + const backColor = 'rgba(0, 0, 69, 0.5)'; + return ( + +
+ + act('clear')} /> + )}> + {accountName || 'N/A'} + + +
+ + + {requests?.map(request => ( + +
+ + + {request.owner} + + + {formatMoney(request.value) + ' cr'} + + +
+
+ + ))} + + + +
+