From fcd7f6efdf5560da3462c90dd15ad402ef5bf1dd Mon Sep 17 00:00:00 2001 From: Skies-Of-Blue <86762641+Skies-Of-Blue@users.noreply.github.com> Date: Mon, 11 Mar 2024 19:13:14 -0700 Subject: [PATCH 001/218] Blindness Accessability Buff (#2828) ## About The Pull Request People can now use various scanners without requiring eyesight. ## Why It's Good For The Game It's 505 FSC and you're telling me we've rolled back accessibility tools for the blind? While it might be the player's choice to take a quirk that limits their abilities (and we compensate them with points accordingly) I hardly think it's necessary to remove their ability to engage with some of the more meaningful mechanics. Let me have my blind roboticist. Please. ## Changelog :cl: tweak: blind characters can now use various scanners, bringing the frontier up to accessibility standards across the galaxy /:cl: --- code/game/objects/items/devices/scanners.dm | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/code/game/objects/items/devices/scanners.dm b/code/game/objects/items/devices/scanners.dm index 6f11fe4ebac1..3f40f82fe0ae 100644 --- a/code/game/objects/items/devices/scanners.dm +++ b/code/game/objects/items/devices/scanners.dm @@ -140,7 +140,7 @@ GENE SCANNER // Used by the PDA medical scanner too /proc/healthscan(mob/user, mob/living/M, mode = SCANNER_VERBOSE, advanced = FALSE) - if(isliving(user) && (user.incapacitated() || user.is_blind())) + if(isliving(user) && (user.incapacitated())) return // the final list of strings to render @@ -456,7 +456,7 @@ GENE SCANNER /obj/item/analyzer/attack_self(mob/user) add_fingerprint(user) - if (user.stat || user.is_blind()) + if (user.stat) return var/turf/location = user.loc @@ -636,7 +636,7 @@ GENE SCANNER custom_materials = list(/datum/material/iron=30, /datum/material/glass=20) /obj/item/slime_scanner/attack(mob/living/M, mob/living/user) - if(user.stat || user.is_blind()) + if(user.stat) return if (!isslime(M)) to_chat(user, "This device can only scan slimes!") From 29d5be5b548b8079dfc393e9f668a3f38674b969 Mon Sep 17 00:00:00 2001 From: Changelogs Date: Mon, 11 Mar 2024 21:32:28 -0500 Subject: [PATCH 002/218] Automatic changelog generation for PR #2828 [ci skip] --- html/changelogs/AutoChangeLog-pr-2828.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-2828.yml diff --git a/html/changelogs/AutoChangeLog-pr-2828.yml b/html/changelogs/AutoChangeLog-pr-2828.yml new file mode 100644 index 000000000000..ee969a79844e --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-2828.yml @@ -0,0 +1,5 @@ +author: Skies-Of-Blue +changes: + - {tweak: 'blind characters can now use various scanners, bringing the frontier + up to accessibility standards across the galaxy'} +delete-after: true From 45fe477a42dded0219246287915a7bceae81fc83 Mon Sep 17 00:00:00 2001 From: meem <75212565+meemofcourse@users.noreply.github.com> Date: Mon, 11 Mar 2024 23:17:33 -0300 Subject: [PATCH 003/218] factional fax machines (#2817) ## About The Pull Request adds subtypes of fax machines with only a few faction admin faxes. look it was really cool when i opened like 7 PRs in one month but i wanna go home ## Why It's Good For The Game no longer will you be able to send faxes to nt as some guy from gec ## Changelog :cl: tweak: Faxes on most ships no longer have access to all admin faxes /:cl: --- .../independent/independent_beluga.dmm | 2 +- .../shuttles/independent/independent_box.dmm | 2 +- .../independent/independent_halftrack.dmm | 2 +- .../independent/independent_rigger.dmm | 2 +- .../independent/independent_rube_goldberg.dmm | 2 +- .../independent/independent_schmiedeberg.dmm | 2 +- .../independent/independent_shetland.dmm | 4 +- _maps/shuttles/inteq/inteq_colossus.dmm | 2 +- _maps/shuttles/inteq/inteq_hound.dmm | 2 +- _maps/shuttles/inteq/inteq_talos.dmm | 2 +- _maps/shuttles/inteq/inteq_valor.dmm | 2 +- _maps/shuttles/inteq/inteq_vaquero.dmm | 2 +- _maps/shuttles/minutemen/minutemen_vela.dmm | 2 +- .../shuttles/nanotrasen/nanotrasen_gecko.dmm | 2 +- .../shuttles/nanotrasen/nanotrasen_heron.dmm | 4 +- .../shuttles/nanotrasen/nanotrasen_osprey.dmm | 2 +- .../shuttles/nanotrasen/nanotrasen_ranger.dmm | 2 +- .../nanotrasen/nanotrasen_skipper.dmm | 4 +- _maps/shuttles/roumain/srm_elder.dmm | 2 +- _maps/shuttles/solgov/solgov_chronicle.dmm | 6 +-- _maps/shuttles/solgov/solgov_inkwell.dmm | 4 +- _maps/shuttles/solgov/solgov_paracelsus.dmm | 2 +- _maps/shuttles/subshuttles/inteq_anvil.dmm | 2 +- .../shuttles/subshuttles/nanotrasen_ancon.dmm | 2 +- _maps/shuttles/syndicate/syndicate_aegis.dmm | 2 +- .../syndicate/syndicate_cybersun_kansatsu.dmm | 2 +- .../syndicate/syndicate_gorlex_hyena.dmm | 2 +- .../syndicate/syndicate_gorlex_komodo.dmm | 2 +- .../syndicate/syndicate_litieguai.dmm | 2 +- .../syndicate/syndicate_twinkleshine.dmm | 4 +- code/modules/paperwork/fax.dm | 50 +++++++++++++++++++ 31 files changed, 87 insertions(+), 37 deletions(-) diff --git a/_maps/shuttles/independent/independent_beluga.dmm b/_maps/shuttles/independent/independent_beluga.dmm index fd498f15872c..e8bf634e863f 100644 --- a/_maps/shuttles/independent/independent_beluga.dmm +++ b/_maps/shuttles/independent/independent_beluga.dmm @@ -322,7 +322,7 @@ /obj/structure/table/reinforced{ color = "#c1b6a5" }, -/obj/machinery/fax, +/obj/machinery/fax/indie, /obj/machinery/airalarm/directional/north, /obj/machinery/camera/autoname{ dir = 6 diff --git a/_maps/shuttles/independent/independent_box.dmm b/_maps/shuttles/independent/independent_box.dmm index 9001bc9faf69..3f17359288cc 100644 --- a/_maps/shuttles/independent/independent_box.dmm +++ b/_maps/shuttles/independent/independent_box.dmm @@ -2589,7 +2589,7 @@ /turf/open/floor/plasteel/tech/grid, /area/ship/crew/toilet) "OF" = ( -/obj/machinery/fax, +/obj/machinery/fax/indie, /obj/structure/table/reinforced, /obj/machinery/light/small/directional/north, /turf/open/floor/plasteel/dark, diff --git a/_maps/shuttles/independent/independent_halftrack.dmm b/_maps/shuttles/independent/independent_halftrack.dmm index 3b04da3c56dc..1363fefa1857 100644 --- a/_maps/shuttles/independent/independent_halftrack.dmm +++ b/_maps/shuttles/independent/independent_halftrack.dmm @@ -271,7 +271,7 @@ /area/ship/security/range) "hF" = ( /obj/structure/table/reinforced, -/obj/machinery/fax, +/obj/machinery/fax/indie, /turf/open/floor/plasteel/dark, /area/ship/bridge) "hH" = ( diff --git a/_maps/shuttles/independent/independent_rigger.dmm b/_maps/shuttles/independent/independent_rigger.dmm index a6312b7de614..8bd2c209481b 100644 --- a/_maps/shuttles/independent/independent_rigger.dmm +++ b/_maps/shuttles/independent/independent_rigger.dmm @@ -234,7 +234,7 @@ "dH" = ( /obj/structure/table/reinforced, /obj/machinery/firealarm/directional/west, -/obj/machinery/fax, +/obj/machinery/fax/indie, /obj/machinery/light/directional/south, /turf/open/floor/carpet/blue, /area/ship/bridge) diff --git a/_maps/shuttles/independent/independent_rube_goldberg.dmm b/_maps/shuttles/independent/independent_rube_goldberg.dmm index 1f4b57035031..d9033819dc3f 100644 --- a/_maps/shuttles/independent/independent_rube_goldberg.dmm +++ b/_maps/shuttles/independent/independent_rube_goldberg.dmm @@ -1281,7 +1281,7 @@ "mj" = ( /obj/structure/table/wood, /obj/machinery/light/directional/east, -/obj/machinery/fax{ +/obj/machinery/fax/indie{ pixel_y = -5 }, /obj/effect/turf_decal/corner/opaque/yellow/border{ diff --git a/_maps/shuttles/independent/independent_schmiedeberg.dmm b/_maps/shuttles/independent/independent_schmiedeberg.dmm index 78836ac3bde9..612ff07c1b61 100644 --- a/_maps/shuttles/independent/independent_schmiedeberg.dmm +++ b/_maps/shuttles/independent/independent_schmiedeberg.dmm @@ -2019,7 +2019,7 @@ /obj/item/gps{ gpstag = "PHARM1" }, -/obj/machinery/fax, +/obj/machinery/fax/indie, /obj/machinery/button/door{ dir = 4; id = "pharmbridge"; diff --git a/_maps/shuttles/independent/independent_shetland.dmm b/_maps/shuttles/independent/independent_shetland.dmm index 365a96a1e33c..5233549f322d 100644 --- a/_maps/shuttles/independent/independent_shetland.dmm +++ b/_maps/shuttles/independent/independent_shetland.dmm @@ -1499,7 +1499,7 @@ /obj/effect/turf_decal/corner/opaque/bottlegreen/full, /obj/machinery/atmospherics/pipe/simple/supply/hidden/layer2, /obj/structure/table/wood, -/obj/machinery/fax, +/obj/machinery/fax/indie, /turf/open/floor/plasteel, /area/ship/security) "pC" = ( @@ -2047,7 +2047,7 @@ /obj/effect/turf_decal/corner/opaque/neutral/half{ dir = 1 }, -/obj/machinery/fax, +/obj/machinery/fax/indie, /obj/item/radio/intercom/directional/south, /turf/open/floor/plasteel/dark, /area/ship/bridge) diff --git a/_maps/shuttles/inteq/inteq_colossus.dmm b/_maps/shuttles/inteq/inteq_colossus.dmm index d57cecb81be0..ed5ac0d11fb6 100644 --- a/_maps/shuttles/inteq/inteq_colossus.dmm +++ b/_maps/shuttles/inteq/inteq_colossus.dmm @@ -115,7 +115,7 @@ /area/ship/hallway/fore) "bJ" = ( /obj/structure/table/reinforced, -/obj/machinery/fax, +/obj/machinery/fax/inteq, /obj/machinery/light/directional/north, /obj/structure/cable{ icon_state = "2-8" diff --git a/_maps/shuttles/inteq/inteq_hound.dmm b/_maps/shuttles/inteq/inteq_hound.dmm index b4e45c49d0b9..e67d176f5683 100644 --- a/_maps/shuttles/inteq/inteq_hound.dmm +++ b/_maps/shuttles/inteq/inteq_hound.dmm @@ -2094,7 +2094,7 @@ "RM" = ( /obj/structure/table/reinforced, /obj/effect/decal/cleanable/dirt/dust, -/obj/machinery/fax, +/obj/machinery/fax/inteq, /turf/open/floor/carpet/orange, /area/ship/bridge) "Sh" = ( diff --git a/_maps/shuttles/inteq/inteq_talos.dmm b/_maps/shuttles/inteq/inteq_talos.dmm index 76a32525dd49..c8bdcb1bd3be 100644 --- a/_maps/shuttles/inteq/inteq_talos.dmm +++ b/_maps/shuttles/inteq/inteq_talos.dmm @@ -1160,7 +1160,7 @@ /area/ship/hallway/central) "hK" = ( /obj/structure/table/reinforced, -/obj/machinery/fax, +/obj/machinery/fax/inteq, /obj/machinery/button/door{ id = "talos_bridge"; name = "Bridge Shutters"; diff --git a/_maps/shuttles/inteq/inteq_valor.dmm b/_maps/shuttles/inteq/inteq_valor.dmm index 658a4c72125f..ede8c585a5c2 100644 --- a/_maps/shuttles/inteq/inteq_valor.dmm +++ b/_maps/shuttles/inteq/inteq_valor.dmm @@ -2757,7 +2757,7 @@ dir = 8 }, /obj/machinery/airalarm/directional/south, -/obj/machinery/fax{ +/obj/machinery/fax/inteq{ pixel_y = 3 }, /turf/open/floor/plasteel/dark, diff --git a/_maps/shuttles/inteq/inteq_vaquero.dmm b/_maps/shuttles/inteq/inteq_vaquero.dmm index d4811f7eed10..c93d0cc7f0a8 100644 --- a/_maps/shuttles/inteq/inteq_vaquero.dmm +++ b/_maps/shuttles/inteq/inteq_vaquero.dmm @@ -2919,7 +2919,7 @@ /area/ship/bridge) "TQ" = ( /obj/structure/table/reinforced, -/obj/machinery/fax, +/obj/machinery/fax/inteq, /obj/machinery/light/small/directional/south, /obj/effect/turf_decal/corner/opaque/brown{ dir = 8 diff --git a/_maps/shuttles/minutemen/minutemen_vela.dmm b/_maps/shuttles/minutemen/minutemen_vela.dmm index 62e213520702..d46365996e2e 100644 --- a/_maps/shuttles/minutemen/minutemen_vela.dmm +++ b/_maps/shuttles/minutemen/minutemen_vela.dmm @@ -5841,7 +5841,7 @@ "FK" = ( /obj/machinery/airalarm/directional/south, /obj/structure/table/reinforced, -/obj/machinery/fax, +/obj/machinery/fax/clip, /turf/open/floor/plasteel/tech, /area/ship/bridge) "FN" = ( diff --git a/_maps/shuttles/nanotrasen/nanotrasen_gecko.dmm b/_maps/shuttles/nanotrasen/nanotrasen_gecko.dmm index 1248c3a9f842..46e396a197a8 100644 --- a/_maps/shuttles/nanotrasen/nanotrasen_gecko.dmm +++ b/_maps/shuttles/nanotrasen/nanotrasen_gecko.dmm @@ -3569,7 +3569,7 @@ /area/ship/maintenance/fore) "JV" = ( /obj/structure/table/reinforced, -/obj/machinery/fax, +/obj/machinery/fax/nanotrasen, /obj/structure/sign/poster/retro/random{ pixel_y = 32 }, diff --git a/_maps/shuttles/nanotrasen/nanotrasen_heron.dmm b/_maps/shuttles/nanotrasen/nanotrasen_heron.dmm index 935f0a2595d3..eb0b34fcf3d7 100644 --- a/_maps/shuttles/nanotrasen/nanotrasen_heron.dmm +++ b/_maps/shuttles/nanotrasen/nanotrasen_heron.dmm @@ -9598,7 +9598,7 @@ /obj/structure/table/reinforced{ color = "#c1b6a5" }, -/obj/machinery/fax, +/obj/machinery/fax/nanotrasen, /obj/machinery/light/directional/south, /turf/open/floor/plasteel/dark, /area/ship/bridge) @@ -10619,7 +10619,7 @@ /obj/structure/table/reinforced{ color = "#c1b6a5" }, -/obj/machinery/fax, +/obj/machinery/fax/nanotrasen, /obj/item/radio/intercom/wideband/directional/west{ pixel_y = 8 }, diff --git a/_maps/shuttles/nanotrasen/nanotrasen_osprey.dmm b/_maps/shuttles/nanotrasen/nanotrasen_osprey.dmm index 95486e6fc6ae..b9f1fe3ee680 100644 --- a/_maps/shuttles/nanotrasen/nanotrasen_osprey.dmm +++ b/_maps/shuttles/nanotrasen/nanotrasen_osprey.dmm @@ -2958,7 +2958,7 @@ /area/ship/science) "tc" = ( /obj/structure/table/reinforced, -/obj/machinery/fax, +/obj/machinery/fax/nanotrasen, /obj/effect/turf_decal/corner/opaque/ntblue, /obj/effect/turf_decal/corner/opaque/ntblue{ dir = 4 diff --git a/_maps/shuttles/nanotrasen/nanotrasen_ranger.dmm b/_maps/shuttles/nanotrasen/nanotrasen_ranger.dmm index 9dc0703630b8..91f43369e93a 100644 --- a/_maps/shuttles/nanotrasen/nanotrasen_ranger.dmm +++ b/_maps/shuttles/nanotrasen/nanotrasen_ranger.dmm @@ -1765,7 +1765,7 @@ /obj/structure/table/reinforced{ color = "#c1b6a5" }, -/obj/machinery/fax, +/obj/machinery/fax/nanotrasen, /turf/open/floor/plasteel/dark, /area/ship/bridge) "sl" = ( diff --git a/_maps/shuttles/nanotrasen/nanotrasen_skipper.dmm b/_maps/shuttles/nanotrasen/nanotrasen_skipper.dmm index 81465759ba48..5ec1a75727d5 100644 --- a/_maps/shuttles/nanotrasen/nanotrasen_skipper.dmm +++ b/_maps/shuttles/nanotrasen/nanotrasen_skipper.dmm @@ -479,7 +479,7 @@ /area/ship/engineering/atmospherics) "ed" = ( /obj/structure/table, -/obj/machinery/fax, +/obj/machinery/fax/nanotrasen, /obj/structure/sign/poster/official/random{ pixel_y = 32 }, @@ -3937,7 +3937,7 @@ /turf/closed/wall, /area/ship/cargo) "Fv" = ( -/obj/machinery/fax, +/obj/machinery/fax/nanotrasen, /obj/structure/table/reinforced, /turf/open/floor/plasteel/mono/dark, /area/ship/bridge) diff --git a/_maps/shuttles/roumain/srm_elder.dmm b/_maps/shuttles/roumain/srm_elder.dmm index fb0de25e83f6..e5f06babb733 100644 --- a/_maps/shuttles/roumain/srm_elder.dmm +++ b/_maps/shuttles/roumain/srm_elder.dmm @@ -2054,7 +2054,7 @@ /area/ship/engineering/engine) "zX" = ( /obj/structure/table/wood, -/obj/machinery/fax, +/obj/machinery/fax/roumain, /obj/effect/turf_decal/spline/fancy/wood{ dir = 8 }, diff --git a/_maps/shuttles/solgov/solgov_chronicle.dmm b/_maps/shuttles/solgov/solgov_chronicle.dmm index a974c8b859c2..b3b2629463ef 100644 --- a/_maps/shuttles/solgov/solgov_chronicle.dmm +++ b/_maps/shuttles/solgov/solgov_chronicle.dmm @@ -771,7 +771,7 @@ /area/ship/crew) "hr" = ( /obj/structure/table/wood/fancy/purple, -/obj/machinery/fax, +/obj/machinery/fax/solgov, /obj/item/desk_flag/solgov{ pixel_x = 8; pixel_y = 13 @@ -2999,7 +2999,7 @@ /turf/open/floor/plasteel/white, /area/ship/security/armory) "CU" = ( -/obj/machinery/fax, +/obj/machinery/fax/solgov, /obj/structure/table/wood, /obj/machinery/light/small/directional/south, /turf/open/floor/wood, @@ -3577,7 +3577,7 @@ /area/ship/security/armory) "Jh" = ( /obj/structure/table/wood/fancy/blue, -/obj/machinery/fax, +/obj/machinery/fax/solgov, /obj/item/desk_flag/solgov{ pixel_x = -9; pixel_y = 14 diff --git a/_maps/shuttles/solgov/solgov_inkwell.dmm b/_maps/shuttles/solgov/solgov_inkwell.dmm index 3c8e75a7ace0..c587193ce0b6 100644 --- a/_maps/shuttles/solgov/solgov_inkwell.dmm +++ b/_maps/shuttles/solgov/solgov_inkwell.dmm @@ -2320,7 +2320,7 @@ /turf/open/floor/plasteel/freezer, /area/ship/crew/toilet) "pd" = ( -/obj/machinery/fax, +/obj/machinery/fax/solgov, /obj/structure/table/wood/fancy/purple, /turf/open/floor/wood/maple, /area/ship/crew/dorm/dormtwo) @@ -5197,7 +5197,7 @@ /area/ship/crew/canteen/kitchen) "HT" = ( /obj/structure/table/wood/fancy/blue, -/obj/machinery/fax, +/obj/machinery/fax/solgov, /turf/open/floor/wood/maple, /area/ship/bridge) "HV" = ( diff --git a/_maps/shuttles/solgov/solgov_paracelsus.dmm b/_maps/shuttles/solgov/solgov_paracelsus.dmm index 70bfabe5d26b..f3e3c2f7bf51 100644 --- a/_maps/shuttles/solgov/solgov_paracelsus.dmm +++ b/_maps/shuttles/solgov/solgov_paracelsus.dmm @@ -1884,7 +1884,7 @@ pixel_x = 8; pixel_y = 12 }, -/obj/machinery/fax, +/obj/machinery/fax/solgov, /turf/open/floor/wood/mahogany, /area/ship/bridge) "sp" = ( diff --git a/_maps/shuttles/subshuttles/inteq_anvil.dmm b/_maps/shuttles/subshuttles/inteq_anvil.dmm index b210a8874ded..f14f1e64d7fd 100644 --- a/_maps/shuttles/subshuttles/inteq_anvil.dmm +++ b/_maps/shuttles/subshuttles/inteq_anvil.dmm @@ -17,7 +17,7 @@ dir = 1 }, /obj/structure/table/reinforced, -/obj/machinery/fax, +/obj/machinery/fax/inteq, /turf/open/floor/plasteel/dark, /area/ship/bridge) "c" = ( diff --git a/_maps/shuttles/subshuttles/nanotrasen_ancon.dmm b/_maps/shuttles/subshuttles/nanotrasen_ancon.dmm index 4565f12416f6..7176477bab9c 100644 --- a/_maps/shuttles/subshuttles/nanotrasen_ancon.dmm +++ b/_maps/shuttles/subshuttles/nanotrasen_ancon.dmm @@ -436,7 +436,7 @@ /area/ship/bridge) "ZG" = ( /obj/structure/table, -/obj/machinery/fax{ +/obj/machinery/fax/nanotrasen{ pixel_y = 5 }, /obj/effect/turf_decal/corner/opaque/green/half, diff --git a/_maps/shuttles/syndicate/syndicate_aegis.dmm b/_maps/shuttles/syndicate/syndicate_aegis.dmm index d86cb9b23de7..f5b0e87a6b1b 100644 --- a/_maps/shuttles/syndicate/syndicate_aegis.dmm +++ b/_maps/shuttles/syndicate/syndicate_aegis.dmm @@ -4187,7 +4187,7 @@ pixel_y = 9 }, /obj/item/radio/intercom/wideband/directional/north, -/obj/machinery/fax, +/obj/machinery/fax/syndicate, /obj/effect/turf_decal/siding/wood{ dir = 5 }, diff --git a/_maps/shuttles/syndicate/syndicate_cybersun_kansatsu.dmm b/_maps/shuttles/syndicate/syndicate_cybersun_kansatsu.dmm index 3a20cb1f5c26..523a524de9d0 100644 --- a/_maps/shuttles/syndicate/syndicate_cybersun_kansatsu.dmm +++ b/_maps/shuttles/syndicate/syndicate_cybersun_kansatsu.dmm @@ -604,7 +604,7 @@ /turf/open/floor/plasteel/tech, /area/ship/crew/dorm) "pa" = ( -/obj/machinery/fax, +/obj/machinery/fax/syndicate, /obj/item/toy/figure/detective{ name = "Intel Buddy"; pixel_x = 5; diff --git a/_maps/shuttles/syndicate/syndicate_gorlex_hyena.dmm b/_maps/shuttles/syndicate/syndicate_gorlex_hyena.dmm index 6a8cee6cc78a..74c00cb758b6 100644 --- a/_maps/shuttles/syndicate/syndicate_gorlex_hyena.dmm +++ b/_maps/shuttles/syndicate/syndicate_gorlex_hyena.dmm @@ -2552,7 +2552,7 @@ pixel_x = 11; pixel_y = -3 }, -/obj/machinery/fax, +/obj/machinery/fax/syndicate, /obj/effect/decal/cleanable/dirt/dust, /obj/effect/turf_decal/borderfloorblack{ dir = 1 diff --git a/_maps/shuttles/syndicate/syndicate_gorlex_komodo.dmm b/_maps/shuttles/syndicate/syndicate_gorlex_komodo.dmm index 3bfb76d1f67d..d3160d0743b1 100644 --- a/_maps/shuttles/syndicate/syndicate_gorlex_komodo.dmm +++ b/_maps/shuttles/syndicate/syndicate_gorlex_komodo.dmm @@ -5024,7 +5024,7 @@ pixel_x = -4; pixel_y = 5 }, -/obj/machinery/fax{ +/obj/machinery/fax/syndicate{ pixel_x = 4; pixel_y = 0 }, diff --git a/_maps/shuttles/syndicate/syndicate_litieguai.dmm b/_maps/shuttles/syndicate/syndicate_litieguai.dmm index 02e738d39bfb..e81231480dfb 100644 --- a/_maps/shuttles/syndicate/syndicate_litieguai.dmm +++ b/_maps/shuttles/syndicate/syndicate_litieguai.dmm @@ -286,7 +286,7 @@ /area/ship/hallway/central) "hF" = ( /obj/structure/table/reinforced, -/obj/machinery/fax, +/obj/machinery/fax/syndicate, /turf/open/floor/plasteel/dark, /area/ship/bridge) "hQ" = ( diff --git a/_maps/shuttles/syndicate/syndicate_twinkleshine.dmm b/_maps/shuttles/syndicate/syndicate_twinkleshine.dmm index 460c9efc29d6..5c49d6a71d6b 100644 --- a/_maps/shuttles/syndicate/syndicate_twinkleshine.dmm +++ b/_maps/shuttles/syndicate/syndicate_twinkleshine.dmm @@ -422,7 +422,7 @@ pixel_y = 32 }, /obj/structure/table, -/obj/machinery/fax{ +/obj/machinery/fax/syndicate{ pixel_y = 5 }, /turf/open/floor/plasteel/tech, @@ -8604,7 +8604,7 @@ /obj/effect/turf_decal/corner/opaque/syndiered/half{ dir = 8 }, -/obj/machinery/fax, +/obj/machinery/fax/syndicate, /turf/open/floor/mineral/plastitanium, /area/ship/bridge) "Xf" = ( diff --git a/code/modules/paperwork/fax.dm b/code/modules/paperwork/fax.dm index 41381a2d3aa1..b48d3b07c1c8 100644 --- a/code/modules/paperwork/fax.dm +++ b/code/modules/paperwork/fax.dm @@ -87,6 +87,7 @@ /obj/machinery/fax/ruin visible_to_network = FALSE + special_networks = list() /obj/machinery/fax/ruin/Initialize(mapload) . = ..() @@ -500,6 +501,55 @@ frontier_network = TRUE visible_to_network = FALSE +/obj/machinery/fax/inteq + special_networks = list( + list(fax_name = "Outpost Authority", fax_id = "outpost", color = "orange", emag_needed = FALSE), + list(fax_name = "IRMG Mothership", fax_id = "inteq", color = "yellow", emag_needed = FALSE), + list(fax_name = "Frontiersmen Communications Quartermaster", fax_id = "frontiersmen", color = "black", emag_needed = TRUE) + ) + +/obj/machinery/fax/clip + special_networks = list( + list(fax_name = "Outpost Authority", fax_id = "outpost", color = "orange", emag_needed = FALSE), + list(fax_name = "Colonial League Leadership", fax_id = "minutemen", color = "blue", emag_needed = FALSE), + list(fax_name = "Frontiersmen Communications Quartermaster", fax_id = "frontiersmen", color = "black", emag_needed = TRUE) + ) + +/obj/machinery/fax/indie + special_networks = list( + list(fax_name = "Outpost Authority", fax_id = "outpost", color = "orange", emag_needed = FALSE), + list(fax_name = "Frontiersmen Communications Quartermaster", fax_id = "frontiersmen", color = "black", emag_needed = TRUE) + ) + +/obj/machinery/fax/nanotrasen + special_networks = list( + list(fax_name = "Outpost Authority", fax_id = "outpost", color = "orange", emag_needed = FALSE), + list(fax_name = "Nanotrasen Central Command", fax_id = "nanotrasen", color = "green", emag_needed = FALSE), + list(fax_name = "Frontiersmen Communications Quartermaster", fax_id = "frontiersmen", color = "black", emag_needed = TRUE) + ) + +/obj/machinery/fax/syndicate + special_networks = list( + list(fax_name = "Outpost Authority", fax_id = "outpost", color = "orange", emag_needed = FALSE), + list(fax_name = "Syndicate Coalition Coordination Center", fax_id = "syndicate", color = "red", emag_needed = FALSE), + list(fax_name = "Frontiersmen Communications Quartermaster", fax_id = "frontiersmen", color = "black", emag_needed = TRUE) + ) + +/obj/machinery/fax/solgov + special_networks = list( + list(fax_name = "Outpost Authority", fax_id = "outpost", color = "orange", emag_needed = FALSE), + list(fax_name = "Solarian Confederation Frontier Affairs", fax_id = "solgov", color = "teal", emag_needed = FALSE), + list(fax_name = "Frontiersmen Communications Quartermaster", fax_id = "frontiersmen", color = "black", emag_needed = TRUE) + ) + +/obj/machinery/fax/roumain + special_networks = list( + list(fax_name = "Outpost Authority", fax_id = "outpost", color = "orange", emag_needed = FALSE), + list(fax_name = "Roumain Council of Huntsmen", fax_id = "roumain", color = "brown", emag_needed = FALSE), + list(fax_name = "Frontiersmen Communications Quartermaster", fax_id = "frontiersmen", color = "black", emag_needed = TRUE) + ) + + /obj/machinery/fax/admin name = "Central Command Fax Machine" fax_name = "Nanotrasen Central Command" From 8aac689678a95232bad826d6a01b3763bf6a6dc3 Mon Sep 17 00:00:00 2001 From: Changelogs Date: Mon, 11 Mar 2024 21:55:19 -0500 Subject: [PATCH 004/218] Automatic changelog generation for PR #2817 [ci skip] --- html/changelogs/AutoChangeLog-pr-2817.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-2817.yml diff --git a/html/changelogs/AutoChangeLog-pr-2817.yml b/html/changelogs/AutoChangeLog-pr-2817.yml new file mode 100644 index 000000000000..b2bcccaff625 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-2817.yml @@ -0,0 +1,4 @@ +author: meemofcourse +changes: + - {tweak: Faxes on most ships no longer have access to all admin faxes} +delete-after: true From 2d6b011a1326e4cf595b0a18762f032a3d30dfc2 Mon Sep 17 00:00:00 2001 From: Skies-Of-Blue <86762641+Skies-Of-Blue@users.noreply.github.com> Date: Mon, 11 Mar 2024 19:20:03 -0700 Subject: [PATCH 005/218] pAI Update: NO GODS NO KINGS NO MASTERS & A Couple Radio Fixes (#2806) ## About The Pull Request Ports: - https://github.com/BeeStation/BeeStation-Hornet/pull/4990 - https://github.com/tgstation/tgstation/pull/55215 - https://github.com/tgstation/tgstation/pull/57033 ## Why It's Good For The Game pAIs are in a weird space of being the only positronic in-setting who MUST bound to a master by law. That doesn't really gel with the rest of our lore. Giving installers the ability to remove that Master-Servant relationship would be nice I think, especially considering pAIs tend to ignore it anyways. Also bugs are bad, okay? ## Changelog :cl: add: a pAI's master can now clear the pAI's zeroth law fix: pAIs are now able to fully utilize installed encryption keys through their integrated transceiver's menu when they have the encryption key software upgrade fix: binary encryption keys work in pAIs that have downloaded the encryption key software /:cl: --- code/game/objects/items/devices/paicard.dm | 12 +++++++++++- code/game/objects/items/devices/radio/headset.dm | 2 -- code/modules/mob/living/silicon/pai/pai_say.dm | 2 +- code/modules/mob/living/silicon/pai/software.dm | 1 + 4 files changed, 13 insertions(+), 4 deletions(-) diff --git a/code/game/objects/items/devices/paicard.dm b/code/game/objects/items/devices/paicard.dm index 41a8f59509a5..dd6a19548afd 100644 --- a/code/game/objects/items/devices/paicard.dm +++ b/code/game/objects/items/devices/paicard.dm @@ -30,7 +30,11 @@ if(pai) if(!pai.master_dna || !pai.master) dat += "Imprint Master DNA
" - dat += "Installed Personality: [pai.name]
" + dat += "Prime directive:
" + if(pai.laws.zeroth) + dat +="[pai.laws.zeroth]
" + else + dat +="None
" dat += "Prime directive:
[pai.laws.zeroth]
" for(var/slaws in pai.laws.supplied) dat += "Additional directives:
[slaws]
" @@ -48,6 +52,7 @@ var/mob/living/carbon/human/H = user if(H.real_name == pai.master || H.dna.unique_enzymes == pai.master_dna) dat += "\[[pai.canholo? "Disable" : "Enable"] holomatrix projectors\]
" + dat += "\[Remove Prime directive\]
" dat += "\[Reset speech synthesis module\]
" dat += "\[Wipe current pAI personality\]
" else @@ -79,6 +84,7 @@ pai.master = M.real_name pai.master_dna = M.dna.unique_enzymes to_chat(pai, "You have been bound to a new master.") + pai.laws.set_zeroth_law("Serve your master.") pai.emittersemicd = FALSE if(href_list["wipe"]) var/confirm = input("Are you CERTAIN you wish to delete the current personality? This action cannot be undone.", "Personality Wipe") in list("Yes", "No") @@ -89,6 +95,10 @@ to_chat(pai, "Your mental faculties leave you.") to_chat(pai, "oblivion... ") qdel(pai) + if(href_list["clear_zero"]) + if((input("Are you CERTAIN you wish to remove this pAI's Prime directive? This action cannot be undone.", "Clear Directive") in list("Yes", "No")) == "Yes") + if(pai) + pai.laws.clear_zeroth_law() if(href_list["fix_speech"]) pai.stuttering = 0 pai.slurring = 0 diff --git a/code/game/objects/items/devices/radio/headset.dm b/code/game/objects/items/devices/radio/headset.dm index 07968246a5ae..574dd88e5cc4 100644 --- a/code/game/objects/items/devices/radio/headset.dm +++ b/code/game/objects/items/devices/radio/headset.dm @@ -335,8 +335,6 @@ GLOBAL_LIST_INIT(channel_tokens, list( /obj/item/radio/headset/silicon/pai name = "\proper mini Integrated Subspace Transceiver " - subspace_transmission = FALSE - /obj/item/radio/headset/silicon/ai name = "\proper Integrated Subspace Transceiver " diff --git a/code/modules/mob/living/silicon/pai/pai_say.dm b/code/modules/mob/living/silicon/pai/pai_say.dm index b44d2cd0870c..cb12258317ba 100644 --- a/code/modules/mob/living/silicon/pai/pai_say.dm +++ b/code/modules/mob/living/silicon/pai/pai_say.dm @@ -5,4 +5,4 @@ ..(message) /mob/living/silicon/pai/binarycheck() - return 0 + return radio?.translate_binary diff --git a/code/modules/mob/living/silicon/pai/software.dm b/code/modules/mob/living/silicon/pai/software.dm index 08e41f3bee44..061c4a74a4b1 100644 --- a/code/modules/mob/living/silicon/pai/software.dm +++ b/code/modules/mob/living/silicon/pai/software.dm @@ -355,6 +355,7 @@ GLOBAL_LIST_INIT(pai_faces_icons, list( if("encryptionkeys") if(href_list["toggle"]) encryptmod = TRUE + radio.subspace_transmission = TRUE if("translator") if(href_list["toggle"]) //This is permanent. From a9d1482063167c3024d9fc8c8b17b042322e3cb0 Mon Sep 17 00:00:00 2001 From: Changelogs Date: Mon, 11 Mar 2024 22:16:21 -0500 Subject: [PATCH 006/218] Automatic changelog generation for PR #2806 [ci skip] --- html/changelogs/AutoChangeLog-pr-2806.yml | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-2806.yml diff --git a/html/changelogs/AutoChangeLog-pr-2806.yml b/html/changelogs/AutoChangeLog-pr-2806.yml new file mode 100644 index 000000000000..6eb2bd745dbe --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-2806.yml @@ -0,0 +1,9 @@ +author: Skies-Of-Blue +changes: + - {rscadd: a pAI's master can now clear the pAI's zeroth law} + - {bugfix: pAIs are now able to fully utilize installed encryption keys through + their integrated transceiver's menu when they have the encryption key software + upgrade} + - {bugfix: binary encryption keys work in pAIs that have downloaded the encryption + key software} +delete-after: true From 5d76a2298845c3a631f03094ddf6d5ecb1886c2d Mon Sep 17 00:00:00 2001 From: Skies-Of-Blue <86762641+Skies-Of-Blue@users.noreply.github.com> Date: Mon, 11 Mar 2024 19:20:16 -0700 Subject: [PATCH 007/218] Ports 'Be polite! While on walk intent you won't bump, swap places or push other people now.' (#2805) ## About The Pull Request Ports https://github.com/tgstation/tgstation/pull/68493, making it so you don't displace or shove people out of the way while walking. ## Why It's Good For The Game Lag has ruined me and so many others one too many times. I have repeatedly seen people accidentally swap places basically since I started playing. This should resolve that. ## Changelog :cl: tweak: crewmen have learned the secrets of being polite. While walking, you will no longer shove or swap places with your crew mates. Be certain to walk around your ship outside of emergencies! /:cl: --- code/modules/mob/living/living.dm | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index 5983d8100112..b240836b55e7 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -93,6 +93,10 @@ //Called when we bump onto a mob /mob/living/proc/MobBump(mob/M) + //No bumping/swapping/pushing others if you are on walk intent + if(m_intent == MOVE_INTENT_WALK) + return TRUE + //Even if we don't push/swap places, we "touched" them, so spread fire spreadFire(M) From 17fccaf532fd8848d0d590650932771000a02da9 Mon Sep 17 00:00:00 2001 From: Changelogs Date: Mon, 11 Mar 2024 22:33:38 -0500 Subject: [PATCH 008/218] Automatic changelog generation for PR #2805 [ci skip] --- html/changelogs/AutoChangeLog-pr-2805.yml | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-2805.yml diff --git a/html/changelogs/AutoChangeLog-pr-2805.yml b/html/changelogs/AutoChangeLog-pr-2805.yml new file mode 100644 index 000000000000..96b13ab06313 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-2805.yml @@ -0,0 +1,6 @@ +author: Skies-Of-Blue +changes: + - {tweak: 'crewmen have learned the secrets of being polite. While walking, you + will no longer shove or swap places with your crew mates. Be certain to walk + around your ship outside of emergencies!'} +delete-after: true From 07e5675e27600e59a80e303872b2f630187969f2 Mon Sep 17 00:00:00 2001 From: Skies-Of-Blue <86762641+Skies-Of-Blue@users.noreply.github.com> Date: Mon, 11 Mar 2024 19:21:06 -0700 Subject: [PATCH 009/218] Prosthesis Changes & Mechanical Surgery Tweaks (#2804) ## About The Pull Request Kept you waiting, huh? Firstly, the smaller changes: - Prosthesis organ manipulation now uses a crowbar instead of a hemostat to remove organs. This was one of two instances of surgical tools being required for IPC Surgery, and it always felt out of place. - Adds a new surgery step, "Close hatch," has been added to most mechanical surgeries for the sake of consistency. This affects implant removal, ipc revival, mechanical brain surgery, and prosthesis organ manipulation. The new steps can be found in the changelog. - Removes player-facing access to chainsaw arms and synthetic arm blades. They always felt ill-fitting for our setting. The code remains, though, just in case someone wants to add untraditional limbs in the future. And now, for the main course: This PR creates two new surgeries, Detach Prosthesis and Prosthesis Attachment, which allow any character with a prosthesis to remove and attach it themself with a set of basic tools. Additionally, it renames Prosthetic Replacement surgery to Limb Grafting surgery, to better reflect its new role as the more surgical variant of limb attachments. Limb Grafting retains all of its previous functionality, minus chainsaw attachments. ## Why It's Good For The Game Hoo boy, this PR was a long time coming. It's always been silly to me that characters are forced to keep their prostheses on 24/7. I can't imagine how uncomfortable that must get. Being forced to have a surgeon remove your leg (or to chop it off with something sharp!!!) just to give their residual limb a breather has always been stifling for prosthesis-based roleplay. This should hopefully open up more options for player expression, and help distinguish standard limbs from mechanical ones. The two new procedures added serve as alternatives for the more surgical Amputation/Grafting duo we've all grown to know and resent, rather than an outright replacement. It's 505 FSC, and prostheses can range from Glorified Peg Leg all the way to Fully Mobile Prosthetic Hand With Synthetic Nerves. As such, I think it's important to keep a couple variants of surgery around for that mechanical expression, even if they end with the same result. This also allows the Friendly Neighborhood Li-Teg to charge extra for limb grafting surgery as opposed to a basic prosthesis attachment procedure :) It's always bugged me that IPCs had to use a hemostat to remove their organs, and I've heard that annoyed sentiment echoed in others over the years. Swapping it gives more consistency to their mechanics overall, and allows for more IPCs to horrifically disassemble themselves as a form of self-soothing while the captain watches in awe. Lastly, chainsaw arms were a meme and have always felt too /TG/ for our setting. Were Shiptest a codebase built from the ground up, I doubt we would have ever seen these added to the game. I know some players expressed interest in having surplus limbs be attach/removable without tools of any sort, but due to time constraints and a general lack of my own abilities, that remains out of reach for the time being. Maybe I'll look into it in the future, who knows. ## Changelog :cl: add: creates close_hatch, a step that mirrors open_hatch in prosthetic surgeries for the sake of consistency. Why you leaving that hatch open?? The final step before screwing to finish surgery. This affects implant removal, ipc revival, mechanical brain surgery, and prosthesis organ manipulation add: creates manipulate_organs/mechanic, a step that swaps the necessary implements in synthetic surgery. Use a crowbar instead of a hemostat to remove any organs on an augmented limb! tweak: changes implant removal surgery to reflect the above. The new tool order is as follows: screwdriver, hand, wrench, crowbar, wrench, hand, screwdriver tweak: changes the (unused) ipc revival surgery to reflect the above. The new tool order is as follows: screwdriver, hand, multitool, inducer, hand, screwdriver tweak: changes mechanical brain surgery to reflect the above. The new tool order is as follows: screwdriver, hand, multitool, hemostat, hand, screwdriver tweak: changes prosthesis organ manipulation to reflect the above. The new tool order is as follows: screwdriver, hand, wrench (if head/chest), multitool, crowbar, wrench (if head/chest), hand, screwdriver add: creates the Detach Prosthesis surgery, a less violent alternative to Amputation. This allows for prosthesis users to remove their own limbs, for the purposes of maintenance or just plain comfort! The tool order is as follows: screwdriver, hand, multitool, wrench, crowbar/wrench/hand (so you can flavor how you remove the limb) tweak: changes the Prosthetic Replacement surgery, renaming it to Limb Grafting surgery. The steps remain the same, but the name needed some retooling, as the procedure is much more surgically involved than its new sibling: add: creates Prosthesis Attachment surgery, a less surgically involved version of the Limb Grafting surgery. This allows for people with prostheses to re-attach the limb they took off with Prosthesis Removal! The tool order is as follows: wrench, multitool, plug in prosthesis, hand, screwdriver del: removes the chainsaw and synthetic arm blade from being viable prostheses. Left the code intact in case someone wants to do something similar in-future /:cl: --- code/modules/surgery/implant_removal.dm | 1 + code/modules/surgery/ipc_revive.dm | 1 + ...thetic_replacement.dm => limb_grafting.dm} | 27 +++--- code/modules/surgery/mechanic_steps.dm | 92 +++++++++++++++++++ code/modules/surgery/mechanical.dm | 27 ++++++ code/modules/surgery/organ_manipulation.dm | 6 +- shiptest.dme | 2 +- 7 files changed, 142 insertions(+), 14 deletions(-) rename code/modules/surgery/{prosthetic_replacement.dm => limb_grafting.dm} (86%) diff --git a/code/modules/surgery/implant_removal.dm b/code/modules/surgery/implant_removal.dm index 68eb25bf2b15..6574fc349225 100644 --- a/code/modules/surgery/implant_removal.dm +++ b/code/modules/surgery/implant_removal.dm @@ -66,4 +66,5 @@ /datum/surgery_step/mechanic_unwrench, /datum/surgery_step/extract_implant, /datum/surgery_step/mechanic_wrench, + /datum/surgery_step/close_hatch, /datum/surgery_step/mechanic_close) diff --git a/code/modules/surgery/ipc_revive.dm b/code/modules/surgery/ipc_revive.dm index 1077a147b4f1..b224bc3a2b60 100644 --- a/code/modules/surgery/ipc_revive.dm +++ b/code/modules/surgery/ipc_revive.dm @@ -8,6 +8,7 @@ /datum/surgery_step/open_hatch, /datum/surgery_step/prepare_electronics, /datum/surgery_step/revive/ipc, + /datum/surgery_step/close_hatch, /datum/surgery_step/mechanic_close ) possible_locs = list(BODY_ZONE_CHEST) diff --git a/code/modules/surgery/prosthetic_replacement.dm b/code/modules/surgery/limb_grafting.dm similarity index 86% rename from code/modules/surgery/prosthetic_replacement.dm rename to code/modules/surgery/limb_grafting.dm index 8b3d4aa1218e..f3cc0d08d5c8 100644 --- a/code/modules/surgery/prosthetic_replacement.dm +++ b/code/modules/surgery/limb_grafting.dm @@ -1,30 +1,35 @@ -/datum/surgery/prosthetic_replacement - name = "Prosthetic replacement" - steps = list(/datum/surgery_step/incise, /datum/surgery_step/clamp_bleeders, /datum/surgery_step/retract_skin, /datum/surgery_step/add_prosthetic) +// Formerly prosthetic_replacement.dm + +/datum/surgery/limb_grafting + name = "Limb grafting" + steps = list(/datum/surgery_step/incise, /datum/surgery_step/clamp_bleeders, /datum/surgery_step/retract_skin, /datum/surgery_step/graft_limb) target_mobtypes = list(/mob/living/carbon/human, /mob/living/carbon/monkey) possible_locs = list(BODY_ZONE_R_ARM, BODY_ZONE_L_ARM, BODY_ZONE_L_LEG, BODY_ZONE_R_LEG, BODY_ZONE_HEAD) requires_bodypart = FALSE //need a missing limb requires_bodypart_type = 0 -/datum/surgery/prosthetic_replacement/can_start(mob/user, mob/living/carbon/target) +/datum/surgery/limb_grafting/can_start(mob/user, mob/living/carbon/target) if(!iscarbon(target)) return 0 var/mob/living/carbon/C = target if(!C.get_bodypart(user.zone_selected)) //can only start if limb is missing return 1 -/datum/surgery_step/add_prosthetic - name = "add prosthetic" +/datum/surgery_step/graft_limb + name = "graft limb" implements = list( /obj/item/bodypart = 100, - /obj/item/organ_storage = 100, - /obj/item/chainsaw = 100, - /obj/item/melee/synthetic_arm_blade = 100) + /obj/item/organ_storage = 100) +// /obj/item/chainsaw = 100, +// /obj/item/melee/synthetic_arm_blade = 100) +// Frankly these have always bothered me. They fill like a bad fit for Shiptest. +// Marking out for now. Keeping the later code used to install unconventional prostheses just in case someone finds a good use for it. + time = 32 experience_given = MEDICAL_SKILL_ORGAN_FIX //won't get full XP if rejected var/organ_rejection_dam = 0 -/datum/surgery_step/add_prosthetic/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) +/datum/surgery_step/graft_limb/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) if(istype(tool, /obj/item/organ_storage)) if(!tool.contents.len) to_chat(user, "There is nothing inside [tool]!") @@ -65,7 +70,7 @@ to_chat(user, "[tool] must be installed onto an arm.") return -1 -/datum/surgery_step/add_prosthetic/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery, default_display_results = FALSE) +/datum/surgery_step/graft_limb/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery, default_display_results = FALSE) . = ..() if(istype(tool, /obj/item/organ_storage)) tool.icon_state = initial(tool.icon_state) diff --git a/code/modules/surgery/mechanic_steps.dm b/code/modules/surgery/mechanic_steps.dm index f1fd128c2d9e..3730f7cf1302 100644 --- a/code/modules/surgery/mechanic_steps.dm +++ b/code/modules/surgery/mechanic_steps.dm @@ -112,3 +112,95 @@ display_results(user, target, "You begin to open the hatch holders in [target]'s [parse_zone(target_zone)]...", "[user] begins to open the hatch holders in [target]'s [parse_zone(target_zone)].", "[user] begins to open the hatch holders in [target]'s [parse_zone(target_zone)].") + +//close hatch + +/datum/surgery_step/close_hatch + name = "close the hatch" + accept_hand = TRUE + time = 1 SECONDS + preop_sound = 'sound/machines/doorclick.ogg' + success_sound = 'sound/items/ratchet.ogg' + +/datum/surgery_step/close_hatch/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) + display_results(user, target, "You begin to close the hatch holders in [target]'s [parse_zone(target_zone)]...", + "[user] begins to close the hatch holders in [target]'s [parse_zone(target_zone)].", + "[user] begins to close the hatch holders in [target]'s [parse_zone(target_zone)].") + +//manipulate organs (metal edition) +/datum/surgery_step/manipulate_organs/mechanic + name = "manipulate mechanical organs" + preop_sound = 'sound/surgery/organ2.ogg' + success_sound = 'sound/surgery/organ1.ogg' + implements_extract = list( + TOOL_HEMOSTAT = 55, + TOOL_CROWBAR = 100, + /obj/item/kitchen/fork = 35) + +//prosthesis removal +/datum/surgery_step/prosthesis_removal + name = "detach prosthesis" + accept_hand = TRUE //once a prosthesis is unseated, it should be a simple matter of removing it without tools + implements = list( + TOOL_WRENCH = 100, + TOOL_CROWBAR = 100) //exists just in case you want to reflavor your prosthesis as something a little more integrated + time = 2.8 SECONDS + preop_sound = 'sound/items/ratchet.ogg' + success_sound = 'sound/machines/doorclick.ogg' + +/datum/surgery_step/prosthesis_removal/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) + display_results(user, target, "You begin to unseat [target]'s [parse_zone(target_zone)]...", + "[user] begins to unseat [target]'s [parse_zone(target_zone)]!", + "[user] begins to unseat [target]'s [parse_zone(target_zone)]!") + +/datum/surgery_step/prosthesis_removal/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery, default_display_results = FALSE) + var/mob/living/carbon/human/L = target + display_results(user, target, "You detach [L]'s [parse_zone(target_zone)].", + "[user] detaches [L]'s [parse_zone(target_zone)]!", + "[user] detaches [L]'s [parse_zone(target_zone)]!") + if(surgery.operated_bodypart) + var/obj/item/bodypart/target_limb = surgery.operated_bodypart + target_limb.drop_limb() + +//Add prosthetic +/datum/surgery_step/add_prosthetic + name = "add prosthetic" + implements = list( + /obj/item/bodypart = 100) + time = 32 + experience_given = MEDICAL_SKILL_ORGAN_FIX //won't get full XP if rejected + var/organ_rejection_dam = 0 + +/datum/surgery_step/add_prosthetic/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) + if(!istype(tool, /obj/item/bodypart)) + to_chat(user, "[tool] isn't a mechanical prosthesis!") + return FALSE + var/obj/item/bodypart/BP = tool + if(ishuman(target)) + if(IS_ORGANIC_LIMB(BP)) + to_chat(user, "[BP] isn't a mechanical prosthesis!") + return -1 + + if(target_zone != BP.body_zone) //so we can't replace a leg with an arm, or a human arm with a monkey arm. + to_chat(user, "[tool] isn't the right type for [parse_zone(target_zone)].") + return -1 + display_results(user, target, "You begin to replace [target]'s [parse_zone(target_zone)] with [tool]...", + "[user] begins to replace [target]'s [parse_zone(target_zone)] with [tool].", + "[user] begins to replace [target]'s [parse_zone(target_zone)].") + +/datum/surgery_step/add_prosthetic/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery, default_display_results = FALSE) + if(HAS_TRAIT(tool, TRAIT_NODROP)) + display_results(user, target, "The [tool] is stuck in your hand!", + "The [tool] seems stuck to [user]'s hand!", + "The [tool] seems stuck to [user]'s hand!") + return FALSE + var/obj/item/bodypart/L = tool + if(!L.attach_limb(target)) + display_results(user, target, "You fail to replace [target]'s [parse_zone(target_zone)]! Their body has rejected [L]!", + "[user] fails to replace [target]'s [parse_zone(target_zone)]!", + "[user] fails to replace [target]'s [parse_zone(target_zone)]!") + return FALSE + display_results(user, target, "You succeed in replacing [target]'s [parse_zone(target_zone)].", + "[user] successfully replaces [target]'s [parse_zone(target_zone)] with [tool]!", + "[user] successfully replaces [target]'s [parse_zone(target_zone)]!") + return ..() diff --git a/code/modules/surgery/mechanical.dm b/code/modules/surgery/mechanical.dm index fe7b583d2c36..0c73c34bd0c7 100644 --- a/code/modules/surgery/mechanical.dm +++ b/code/modules/surgery/mechanical.dm @@ -8,6 +8,7 @@ /datum/surgery_step/open_hatch, /datum/surgery_step/prepare_electronics, /datum/surgery_step/fix_brain, + /datum/surgery_step/close_hatch, /datum/surgery_step/mechanic_close ) lying_required = FALSE @@ -99,3 +100,29 @@ L.electrocute_act(urdamageamt_burn, target) target.take_bodypart_damage(urdamageamt_brute, urdamageamt_burn) return FALSE + +/datum/surgery/prosthesis_removal + name = "Detach prosthesis" + steps = list(/datum/surgery_step/mechanic_open, /datum/surgery_step/open_hatch, /datum/surgery_step/prepare_electronics, /datum/surgery_step/mechanic_unwrench, /datum/surgery_step/prosthesis_removal) + possible_locs = list(BODY_ZONE_R_ARM, BODY_ZONE_L_ARM, BODY_ZONE_L_LEG, BODY_ZONE_R_LEG) // adding BODY_ZONE_HEAD would allow IPCs to remove their heads, could be funny if it weren't for the fact that it breaks their mutcolors and kills FBPs. Future explorers, if you want to fix these issues, you have my blessing + requires_bodypart_type = BODYTYPE_ROBOTIC + lying_required = FALSE + self_operable = TRUE + ignore_clothes = TRUE + +/datum/surgery/prosthesis_attachment + name = "Prosthesis attachment" + steps = list(/datum/surgery_step/mechanic_wrench, /datum/surgery_step/prepare_electronics, /datum/surgery_step/add_prosthetic, /datum/surgery_step/close_hatch, /datum/surgery_step/mechanic_close) + possible_locs = list(BODY_ZONE_R_ARM, BODY_ZONE_L_ARM, BODY_ZONE_L_LEG, BODY_ZONE_R_LEG, BODY_ZONE_HEAD) + requires_bodypart = FALSE //need a missing limb + requires_bodypart_type = 0 + lying_required = FALSE + self_operable = TRUE + ignore_clothes = TRUE + +/datum/surgery/prosthesis_attachment/can_start(mob/user, mob/living/carbon/target) + if(!iscarbon(target)) + return FALSE + var/mob/living/carbon/C = target + if(!C.get_bodypart(user.zone_selected)) //can only start if limb is missing + return TRUE diff --git a/code/modules/surgery/organ_manipulation.dm b/code/modules/surgery/organ_manipulation.dm index 2242c4c242ea..1b14aed144a1 100644 --- a/code/modules/surgery/organ_manipulation.dm +++ b/code/modules/surgery/organ_manipulation.dm @@ -49,8 +49,9 @@ /datum/surgery_step/open_hatch, /datum/surgery_step/mechanic_unwrench, /datum/surgery_step/prepare_electronics, - /datum/surgery_step/manipulate_organs, + /datum/surgery_step/manipulate_organs/mechanic, /datum/surgery_step/mechanic_wrench, + /datum/surgery_step/close_hatch, /datum/surgery_step/mechanic_close ) @@ -60,7 +61,8 @@ /datum/surgery_step/mechanic_open, /datum/surgery_step/open_hatch, /datum/surgery_step/prepare_electronics, - /datum/surgery_step/manipulate_organs, + /datum/surgery_step/manipulate_organs/mechanic, + /datum/surgery_step/close_hatch, /datum/surgery_step/mechanic_close ) diff --git a/shiptest.dme b/shiptest.dme index bb107a1f00f2..b70514ac1d8e 100644 --- a/shiptest.dme +++ b/shiptest.dme @@ -3334,13 +3334,13 @@ #include "code\modules\surgery\implant_removal.dm" #include "code\modules\surgery\ipc_revive.dm" #include "code\modules\surgery\limb_augmentation.dm" +#include "code\modules\surgery\limb_grafting.dm" #include "code\modules\surgery\lobectomy.dm" #include "code\modules\surgery\mechanic_steps.dm" #include "code\modules\surgery\mechanical.dm" #include "code\modules\surgery\organ_manipulation.dm" #include "code\modules\surgery\organic_steps.dm" #include "code\modules\surgery\plastic_surgery.dm" -#include "code\modules\surgery\prosthetic_replacement.dm" #include "code\modules\surgery\remove_embedded_object.dm" #include "code\modules\surgery\revival.dm" #include "code\modules\surgery\stomachpump.dm" From c26c9fd49c330cda5ea1bf904b6a8ceec7846c0a Mon Sep 17 00:00:00 2001 From: Changelogs Date: Mon, 11 Mar 2024 22:50:04 -0500 Subject: [PATCH 010/218] Automatic changelog generation for PR #2804 [ci skip] --- html/changelogs/AutoChangeLog-pr-2804.yml | 33 +++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-2804.yml diff --git a/html/changelogs/AutoChangeLog-pr-2804.yml b/html/changelogs/AutoChangeLog-pr-2804.yml new file mode 100644 index 000000000000..f2ea75a57cfb --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-2804.yml @@ -0,0 +1,33 @@ +author: Skies-Of-Blue +changes: + - {rscadd: 'creates close_hatch, a step that mirrors open_hatch in prosthetic surgeries + for the sake of consistency. Why you leaving that hatch open?? The final step + before screwing to finish surgery. This affects implant removal, ipc revival, + mechanical brain surgery, and prosthesis organ manipulation'} + - {rscadd: 'creates manipulate_organs/mechanic, a step that swaps the necessary + implements in synthetic surgery. Use a crowbar instead of a hemostat to remove + any organs on an augmented limb!'} + - {tweak: 'changes implant removal surgery to reflect the above. The new tool order + is as follows: screwdriver, hand, wrench, crowbar, wrench, hand, screwdriver'} + - {tweak: 'changes the (unused) ipc revival surgery to reflect the above. The new + tool order is as follows: screwdriver, hand, multitool, inducer, hand, screwdriver'} + - {tweak: 'changes mechanical brain surgery to reflect the above. The new tool order + is as follows: screwdriver, hand, multitool, hemostat, hand, screwdriver'} + - {tweak: 'changes prosthesis organ manipulation to reflect the above. The new tool + order is as follows: screwdriver, hand, wrench (if head/chest), multitool, crowbar, + wrench (if head/chest), hand, screwdriver'} + - {rscadd: 'creates the Detach Prosthesis surgery, a less violent alternative to + Amputation. This allows for prosthesis users to remove their own limbs, for + the purposes of maintenance or just plain comfort! The tool order is as follows: + screwdriver, hand, multitool, wrench, crowbar/wrench/hand (so you can flavor + how you remove the limb)'} + - {tweak: 'changes the Prosthetic Replacement surgery, renaming it to Limb Grafting + surgery. The steps remain the same, but the name needed some retooling, as the + procedure is much more surgically involved than its new sibling:'} + - {rscadd: 'creates Prosthesis Attachment surgery, a less surgically involved version + of the Limb Grafting surgery. This allows for people with prostheses to re-attach + the limb they took off with Prosthesis Removal! The tool order is as follows: + wrench, multitool, plug in prosthesis, hand, screwdriver'} + - {rscdel: removes the chainsaw and synthetic arm blade from being viable prostheses. + Left the code intact in case someone wants to do something similar in-future} +delete-after: true From 0b3cc92bc2817bab3e76eb17868cee5368b565e9 Mon Sep 17 00:00:00 2001 From: Sadhorizon <108196626+Sadhorizon@users.noreply.github.com> Date: Tue, 12 Mar 2024 03:21:45 +0100 Subject: [PATCH 011/218] Adds more ways to ignite e-cigarettes. (#2796) ## About The Pull Request Do you want your character to vape, but did they not spawn with a PDA? Well, worry not, this PR adds new ways to ignite your e-cigarettes/e-cigars! First one, is with a tablet. Works essentially the same as with a PDA. There is way more jobs that get a free tablet than those that get a PDA. Plus, you can get those from loadout. Second one, is with an APC. Smash your vape on the APC and it will get ignited! How does it work? Clearly designers were just very thoughtful and included a vape igniter or whatever you use! ## Why It's Good For The Game Items being actually usable is nice. ## Changelog :cl: tweak: E-cigarettes and e-cigars can now be turned on with tablets and APCs. /:cl: --- code/game/objects/items/cigs_lighters.dm | 66 ++++++++++++++++-------- 1 file changed, 45 insertions(+), 21 deletions(-) diff --git a/code/game/objects/items/cigs_lighters.dm b/code/game/objects/items/cigs_lighters.dm index 8800dee20016..a60600b3661f 100644 --- a/code/game/objects/items/cigs_lighters.dm +++ b/code/game/objects/items/cigs_lighters.dm @@ -750,7 +750,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM overlay_state = "slime" grind_results = list(/datum/reagent/iron = 1, /datum/reagent/fuel = 5, /datum/reagent/medicine/pyroxadone = 5) -/obj/item/lighter/clockwork //WS edit: Clockwork Zippo, by Tergius. PR #395 +/obj/item/lighter/clockwork name = "bronze zippo" desc = "A zippo plated with brass. I mean bronze. Has a neat red flame!" icon = 'icons/obj/cigarettes.dmi' @@ -829,7 +829,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM /////////////// /obj/item/clothing/mask/vape name = "\improper E-Cigarette" - desc = "A classy and highly sophisticated electronic cigarette, for classy and dignified gentlemen. A warning label reads \"Warning: Do not fill with flammable materials.\" Must be lit via interfacing with a PDA."//<<< i'd vape to that. + desc = "A classy and highly sophisticated electronic cigarette, for classy and dignified gentlemen. A warning label reads \"Warning: Do not fill with flammable materials.\" Can be lit via interfacing with a PDA, tablet computer, or an APC."//<<< i'd vape to that. icon = 'icons/obj/clothing/masks.dmi' icon_state = "red_vapeoff" item_state = "red_vapeoff" @@ -839,19 +839,19 @@ CIGARETTE PACKETS ARE IN FANCY.DM var/vapetime = 0 //this so it won't puff out clouds every tick var/screw = 0 // kinky var/super = 0 //for the fattest vapes dude. - var/vapecolor //What color the vape should be. If this is not filled out it will automatically be set on Initialize() - WS edit - Lightable e-cigarettes - var/overlayname = "vape" //Used to decide what overlay sprites to use - WS edit - Lightable e-cigarettes + var/vapecolor //What color the vape should be. If this is not filled out it will automatically be set on Initialize() + var/overlayname = "vape" //Used to decide what overlay sprites to use /obj/item/clothing/mask/vape/Initialize(mapload, param_color) . = ..() create_reagents(chem_volume, NO_REACT) reagents.add_reagent(/datum/reagent/drug/nicotine, 50) - if(!vapecolor) //BeginWS edit - Lightable e-cigarettes + if(!vapecolor) if(!param_color) param_color = pick("red","blue","black","white","green","purple","yellow","orange") vapecolor = param_color icon_state = "[vapecolor]_vapeoff" - item_state = "[vapecolor]_vapeoff" //EndWS edit - Lightable e-cigarettes + item_state = "[vapecolor]_vapeoff" /obj/item/clothing/mask/vape/attackby(obj/item/O, mob/user, params) if(O.tool_behaviour == TOOL_SCREWDRIVER) @@ -863,11 +863,11 @@ CIGARETTE PACKETS ARE IN FANCY.DM to_chat(user, "You open the cap on [src].") reagents.flags |= OPENCONTAINER if(obj_flags & EMAGGED) - add_overlay("[overlayname]open_high") //WS edit - lightable e-cigarettes + add_overlay("[overlayname]open_high") else if(super) - add_overlay("[overlayname]open_med") //WS edit - lightable e-cigarettes + add_overlay("[overlayname]open_med") else - add_overlay("[overlayname]open_low") //WS edit - lightable e-cigarettes + add_overlay("[overlayname]open_low") else screw = FALSE to_chat(user, "You close the cap on [src].") @@ -880,18 +880,18 @@ CIGARETTE PACKETS ARE IN FANCY.DM cut_overlays() super = 1 to_chat(user, "You increase the voltage of [src].") - add_overlay("[overlayname]open_med") //WS edit - lightable e-cigarettes + add_overlay("[overlayname]open_med") else cut_overlays() super = 0 to_chat(user, "You decrease the voltage of [src].") - add_overlay("[overlayname]open_low") //WS edit - lightable e-cigarettes + add_overlay("[overlayname]open_low") if(screw && (obj_flags & EMAGGED)) to_chat(user, "[src] can't be modified!") else ..() - if(istype(O, /obj/item/pda)) //BeginWS edit - Lightable e-cigarettes + if(istype(O, /obj/item/pda) || istype(O, /obj/item/modular_computer/tablet)) if(screw) to_chat(user, "You need to close the cap first!") return @@ -918,8 +918,32 @@ CIGARETTE PACKETS ARE IN FANCY.DM STOP_PROCESSING(SSobj, src) src.update_icon_state() user.update_inv_wear_mask() - user.update_inv_hands() //EndWS edit - Lightable e-cigarettes + user.update_inv_hands() +/obj/item/clothing/mask/vape/afterattack(atom/target, mob/user, proximity_flag, click_parameters) + if((!istype(target, /obj/machinery/power/apc)) || !ishuman(user) || !proximity_flag) + return ..() + if(screw) + to_chat(user, "You need to close the cap first!") + return + on = !on + if(on) + user.visible_message( + "[user] turns on [user.p_their()] [src] with a holographic flame from the APC.", + "You turn on your [src] with a holographic flame from the APC." + ) + reagents.flags |= NO_REACT + icon_state = "[vapecolor]_vape" + item_state = "[vapecolor]_vape" + else + user.visible_message( + "[user] turns off [user.p_their()] [src] with a holographic gust from the APC.", + "You turn off your [src] with a holographic gust from the APC." + ) + reagents.flags &= NO_REACT + icon_state = "[vapecolor]_vapeoff" + item_state = "[vapecolor]_vapeoff" + src.update_icon_state() /obj/item/clothing/mask/vape/emag_act(mob/user)// I WON'T REGRET WRITTING THIS, SURLY. if(screw) @@ -928,7 +952,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM obj_flags |= EMAGGED super = 0 to_chat(user, "You maximize the voltage of [src].") - add_overlay("[overlayname]open_high") //WS edit - lightable e-cigarettes + add_overlay("[overlayname]open_high") var/datum/effect_system/spark_spread/sp = new /datum/effect_system/spark_spread //for effect sp.set_up(5, 1, src) sp.start() @@ -944,7 +968,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM /obj/item/clothing/mask/vape/equipped(mob/user, slot) . = ..() - if(slot == ITEM_SLOT_MASK) //BeginWS edit - Lightable e-cigarettes + if(slot == ITEM_SLOT_MASK) if(on) if(!screw) to_chat(user, "You start puffing on \the [src].") @@ -952,7 +976,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM else //it will not start if the vape is opened. to_chat(user, "You need to close the cap first!") else - to_chat(user, "You need to turn on \the [src] first!") //EndWS edit - Lightable e-cigarettes + to_chat(user, "You need to turn on \the [src] first!") /obj/item/clothing/mask/vape/dropped(mob/user) . = ..() @@ -999,7 +1023,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM //open flame removed because vapes are a closed system, they wont light anything on fire if(super && vapetime > 3)//Time to start puffing those fat vapes, yo. - var/datum/effect_system/smoke_spread/chem/smoke_machine/s = new //BeginWS edit - Fix vape clouds + var/datum/effect_system/smoke_spread/chem/smoke_machine/s = new var/datum/reagents/smokereagents = new reagents.trans_to(smokereagents, reagents.total_volume / 10, 0.65) s.set_up(smokereagents, 1, 24, loc) @@ -1011,7 +1035,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM var/datum/reagents/smokereagents = new reagents.trans_to(smokereagents, reagents.total_volume / 5, 0.75) s.set_up(smokereagents, 4, 24, loc) - s.start() //EndWS edit - Fix vape clouds + s.start() vapetime = 0 if(prob(5))//small chance for the vape to break and deal damage if it's emagged playsound(get_turf(src), 'sound/effects/pop_expl.ogg', 50, FALSE) @@ -1027,13 +1051,13 @@ CIGARETTE PACKETS ARE IN FANCY.DM if(reagents && reagents.total_volume) hand_reagents() -/obj/item/clothing/mask/vape/examine(mob/user) //BeginWS edit - Lightable e-cigarettes +/obj/item/clothing/mask/vape/examine(mob/user) . = ..() - to_chat(user, "It is currently [on ? "on" : "off"].") /obj/item/clothing/mask/vape/cigar name = "\improper E-Cigar" - desc = "The latest recreational device developed by a small tech startup, Shadow Tech, the E-Cigar has all the uses of a normal E-Cigarette, with the classiness of short fat cigar. Must be lit via interfacing with a PDA." + desc = "The latest recreational device developed by a small tech startup, Shadow Tech, the E-Cigar has all the uses of a normal E-Cigarette, with the classiness of short fat cigar. Can be lit via interfacing with a PDA, tablet computer, or an APC." icon_state = "ecigar_vapeoff" item_state = "ecigar_vapeoff" vapecolor = "ecigar" From cd095320ef9c67862b9b6f076bbc734cfd506869 Mon Sep 17 00:00:00 2001 From: Changelogs Date: Mon, 11 Mar 2024 23:07:58 -0500 Subject: [PATCH 012/218] Automatic changelog generation for PR #2796 [ci skip] --- html/changelogs/AutoChangeLog-pr-2796.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-2796.yml diff --git a/html/changelogs/AutoChangeLog-pr-2796.yml b/html/changelogs/AutoChangeLog-pr-2796.yml new file mode 100644 index 000000000000..e26ea1d99821 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-2796.yml @@ -0,0 +1,4 @@ +author: Sadhorizon +changes: + - {tweak: E-cigarettes and e-cigars can now be turned on with tablets and APCs.} +delete-after: true From 94dede07f170bf6d5b02c1cf4bf8049935feb525 Mon Sep 17 00:00:00 2001 From: thgvr <81882910+thgvr@users.noreply.github.com> Date: Mon, 11 Mar 2024 19:22:36 -0700 Subject: [PATCH 013/218] Hopefully restores PAI wiping (#2785) ## About The Pull Request Fixes https://github.com/shiptest-ss13/Shiptest/issues/2346 See title Dunno how to test this on my own, needs TM ## Changelog :cl: add: PAIs can wipe themselves again /:cl: --- code/game/objects/items/devices/paicard.dm | 1 - code/modules/mob/living/silicon/pai/pai.dm | 19 ++++++++++++++++--- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/code/game/objects/items/devices/paicard.dm b/code/game/objects/items/devices/paicard.dm index dd6a19548afd..bf08b704beb0 100644 --- a/code/game/objects/items/devices/paicard.dm +++ b/code/game/objects/items/devices/paicard.dm @@ -159,4 +159,3 @@ return if(pai && !pai.holoform) pai.emp_act(severity) - diff --git a/code/modules/mob/living/silicon/pai/pai.dm b/code/modules/mob/living/silicon/pai/pai.dm index 405cda36580c..1f574f08a450 100644 --- a/code/modules/mob/living/silicon/pai/pai.dm +++ b/code/modules/mob/living/silicon/pai/pai.dm @@ -183,7 +183,7 @@ /mob/living/silicon/pai/canUseTopic(atom/movable/M, be_close=FALSE, no_dexterity=FALSE, no_tk=FALSE) if(be_close && !in_range(M, src)) - to_chat(src, "You are too far away!") + to_chat(src, span_warning("You are too far away!")) return FALSE return TRUE @@ -274,7 +274,7 @@ if(cable) if(get_dist(src, cable) > 1) var/turf/T = get_turf(src) - T.visible_message("[cable] rapidly retracts back into its spool.", "You hear a click and the sound of wire spooling rapidly.") + T.visible_message(span_warning("[cable] rapidly retracts back into its spool."), span_hear("You hear a click and the sound of wire spooling rapidly.")) QDEL_NULL(cable) if(hacking) process_hack() @@ -298,4 +298,17 @@ else if(istype(W, /obj/item/encryptionkey)) pai.radio.attackby(W, user, params) else - to_chat(user, "Encryption Key ports not configured.") + to_chat(user, span_alert("Encryption Key ports not configured.")) + +//Wipe +/mob/living/silicon/pai/verb/wipe_self() + var/confirm = alert("Are you sure you want to wipe your own personality? This is PERMANENT.", "Confirm Wipe", "Yes", "No") + if(confirm == "Yes") + var/turf/T = get_turf(src.loc) + T.visible_message( + span_notice("[src] flashes a message across its screen,\"Wiping core files. Please acquire a new personality to continue using pAI device functions.\""), null, \ + span_notice("[src] bleeps electronically.")) + death(FALSE) + ghostize(FALSE) // Disallows reentering body and disassociates mind + else + to_chat(src, "Aborting wipe attempt.") From 71894f3c23f3126d0444328ac26ab8bde642aa24 Mon Sep 17 00:00:00 2001 From: Changelogs Date: Mon, 11 Mar 2024 23:24:47 -0500 Subject: [PATCH 014/218] Automatic changelog generation for PR #2785 [ci skip] --- html/changelogs/AutoChangeLog-pr-2785.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-2785.yml diff --git a/html/changelogs/AutoChangeLog-pr-2785.yml b/html/changelogs/AutoChangeLog-pr-2785.yml new file mode 100644 index 000000000000..82ea3ea2015c --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-2785.yml @@ -0,0 +1,4 @@ +author: thgvr +changes: + - {rscadd: PAIs can wipe themselves again} +delete-after: true From 544135c5dec62abfa7eddf2bb46da2bffa3d74c8 Mon Sep 17 00:00:00 2001 From: meem <75212565+meemofcourse@users.noreply.github.com> Date: Mon, 11 Mar 2024 23:26:11 -0300 Subject: [PATCH 015/218] TGUI Folders and Clipboards + Biscuit Cards (#2760) ## About The Pull Request This pull request ports the following PRs: * https://github.com/tgstation/tgstation/pull/57289 * https://github.com/tgstation/tgstation/pull/57320 * https://github.com/tgstation/tgstation/pull/57400 * https://github.com/tgstation/tgstation/pull/60792 * https://github.com/tgstation/tgstation/pull/74329 ## Why It's Good For The Game cool paperwork ![imagen](https://github.com/shiptest-ss13/Shiptest/assets/75212565/2181a771-290a-4919-9b49-f7ff80ac00ce) ![imagen](https://github.com/shiptest-ss13/Shiptest/assets/75212565/600c656e-68d4-41ee-8225-2a52bd2d0925) ## Changelog :cl: mozi_h, DrDiasyl aka DrTuxedo#0931, GoldenAlpharex add: Clipboards have a snazzy new look. refactor: Gave clipboards some purpose in life: Edit, rename and sort to your hearts' desire! Insert a pen by just clicking it in. Rapidly pick up paper by clicking on it with the clipboard. add: Folders have a snazzy new look. (Check out those colours!) qol: Rapidly pick up paper by clicking on it with a folder. Alt-click to remove an item from a folder. refactor: Split and cleaned up folder code. refactor: Tidied up folder UI code fix: Paper that's on a clipboard doesn't need to be poked to realise that its appearance has changed and to properly display it on a clipboard. fix: You finally figured that using a stamp on a clipboard was more important than using the pen that's currently attached to it. Congratulations! code: Added support for preventing a pen from being removed from a clipboard. add: Added 'biscuit' cards! They can contain documents and can only be accessed by cracking them open, you can't close them back. Nanotrasen now stores spare ID safe codes in them. add: Placed paper cutters around the station. They're in Bridge, HoP office, Warden office, and Cargo. add: Now you can order paper cutters at cargo. fix: Now the paper slip is actually paper. imageadd: The paper slips sprite was slightly tweaked to have text lay more logically, added the corporate paper slip. /:cl: --- _maps/RandomRuins/SpaceRuins/onehalf.dmm | 2 +- .../RandomRuins/SpaceRuins/provinggrounds.dmm | 2 +- _maps/map_files/generic/CentCom.dmm | 2 +- _maps/shuttles/solgov/solgov_chronicle.dmm | 6 +- _maps/shuttles/solgov/solgov_inkwell.dmm | 4 +- _maps/shuttles/solgov/solgov_paracelsus.dmm | 6 +- .../syndicate/syndicate_gec_lugol.dmm | 2 +- .../syndicate/syndicate_gorlex_hyena.dmm | 2 +- .../syndicate/syndicate_gorlex_komodo.dmm | 2 +- .../syndicate/syndicate_twinkleshine.dmm | 4 +- check_regex.yaml | 2 +- .../antagonists/traitor/datum_traitor.dm | 6 +- .../food_and_drinks/food/snacks_pastry.dm | 21 ++ code/modules/paperwork/biscuit.dm | 104 ++++++++ code/modules/paperwork/carbonpaper.dm | 7 +- code/modules/paperwork/clipboard.dm | 222 +++++++++++------- code/modules/paperwork/fax.dm | 2 + code/modules/paperwork/folders.dm | 207 +++++++--------- code/modules/paperwork/folders_premade.dm | 63 +++++ code/modules/paperwork/paper.dm | 12 +- code/modules/paperwork/paper_cutter.dm | 35 +-- .../research/designs/autolathe_designs.dm | 17 ++ icons/obj/bureaucracy.dmi | Bin 26134 -> 26815 bytes shiptest.dme | 2 + tgui/packages/tgui/interfaces/Clipboard.js | 107 +++++++++ tgui/packages/tgui/interfaces/Folder.js | 51 ++++ 26 files changed, 646 insertions(+), 244 deletions(-) create mode 100644 code/modules/paperwork/biscuit.dm create mode 100644 code/modules/paperwork/folders_premade.dm create mode 100644 tgui/packages/tgui/interfaces/Clipboard.js create mode 100644 tgui/packages/tgui/interfaces/Folder.js diff --git a/_maps/RandomRuins/SpaceRuins/onehalf.dmm b/_maps/RandomRuins/SpaceRuins/onehalf.dmm index ed19285b586e..1fb955237126 100644 --- a/_maps/RandomRuins/SpaceRuins/onehalf.dmm +++ b/_maps/RandomRuins/SpaceRuins/onehalf.dmm @@ -923,7 +923,7 @@ /obj/item/clothing/suit/space/hardsuit/syndi/ramzi, /obj/item/reagent_containers/food/drinks/bottle/rum, /obj/item/reagent_containers/food/drinks/bottle/rum, -/obj/item/folder/syndicate/mining, +/obj/item/folder/documents/syndicate/mining, /obj/item/paper/fluff/gateway, /turf/open/floor/plating, /area/ruin/space/has_grav/onehalf) diff --git a/_maps/RandomRuins/SpaceRuins/provinggrounds.dmm b/_maps/RandomRuins/SpaceRuins/provinggrounds.dmm index c43ba0812698..4e7fe7fd9c58 100644 --- a/_maps/RandomRuins/SpaceRuins/provinggrounds.dmm +++ b/_maps/RandomRuins/SpaceRuins/provinggrounds.dmm @@ -208,7 +208,7 @@ /area/ruin/space/has_grav/syndicircle/halls) "gi" = ( /obj/structure/table/reinforced, -/obj/item/folder/syndicate/red, +/obj/item/folder/documents/syndicate/red, /turf/open/floor/plasteel/tech, /area/ruin/space/has_grav/syndicircle/winter) "gp" = ( diff --git a/_maps/map_files/generic/CentCom.dmm b/_maps/map_files/generic/CentCom.dmm index 209466a1b2ef..c441891d33b6 100644 --- a/_maps/map_files/generic/CentCom.dmm +++ b/_maps/map_files/generic/CentCom.dmm @@ -16470,7 +16470,7 @@ /area/centcom) "wCp" = ( /obj/structure/table/wood/fancy/blue, -/obj/item/folder/solgov/red{ +/obj/item/folder/documents/solgov{ pixel_x = -3 }, /obj/item/folder/solgov{ diff --git a/_maps/shuttles/solgov/solgov_chronicle.dmm b/_maps/shuttles/solgov/solgov_chronicle.dmm index b3b2629463ef..9cceb17c5dea 100644 --- a/_maps/shuttles/solgov/solgov_chronicle.dmm +++ b/_maps/shuttles/solgov/solgov_chronicle.dmm @@ -256,8 +256,8 @@ /obj/item/clothing/head/solgov/captain, /obj/item/folder/solgov, /obj/item/folder/solgov, -/obj/item/folder/solgov/red, -/obj/item/folder/solgov/red, +/obj/item/folder/documents/solgov, +/obj/item/folder/documents/solgov, /obj/item/clothing/under/solgov/formal, /obj/item/clothing/gloves/combat, /obj/item/storage/backpack/captain, @@ -4121,7 +4121,7 @@ /obj/item/clothing/gloves/combat, /obj/item/folder/solgov, /obj/item/folder/solgov, -/obj/item/folder/solgov/red, +/obj/item/folder/documents/solgov, /obj/item/clothing/under/solgov/formal, /obj/item/clothing/head/solgov, /obj/item/storage/belt/sabre/solgov, diff --git a/_maps/shuttles/solgov/solgov_inkwell.dmm b/_maps/shuttles/solgov/solgov_inkwell.dmm index c587193ce0b6..e42972d85eed 100644 --- a/_maps/shuttles/solgov/solgov_inkwell.dmm +++ b/_maps/shuttles/solgov/solgov_inkwell.dmm @@ -5784,8 +5784,8 @@ /obj/item/clothing/under/solgov/formal, /obj/item/folder/solgov, /obj/item/folder/solgov, -/obj/item/folder/solgov/red, -/obj/item/folder/solgov/red, +/obj/item/folder/documents/solgov, +/obj/item/folder/documents/solgov, /obj/structure/closet/secure_closet{ icon_state = "cap"; name = "\proper captain's locker"; diff --git a/_maps/shuttles/solgov/solgov_paracelsus.dmm b/_maps/shuttles/solgov/solgov_paracelsus.dmm index f3e3c2f7bf51..b4ca4f13cb07 100644 --- a/_maps/shuttles/solgov/solgov_paracelsus.dmm +++ b/_maps/shuttles/solgov/solgov_paracelsus.dmm @@ -2483,7 +2483,7 @@ /obj/item/clothing/gloves/combat, /obj/item/folder/solgov, /obj/item/folder/solgov, -/obj/item/folder/solgov/red, +/obj/item/folder/documents/solgov, /obj/item/clothing/under/solgov/formal, /obj/item/clothing/head/solgov, /obj/item/storage/belt/sabre/solgov, @@ -3581,8 +3581,8 @@ /obj/item/clothing/under/solgov/formal, /obj/item/folder/solgov, /obj/item/folder/solgov, -/obj/item/folder/solgov/red, -/obj/item/folder/solgov/red, +/obj/item/folder/documents/solgov, +/obj/item/folder/documents/solgov, /obj/structure/closet/secure_closet{ icon_state = "cap"; name = "\proper captain's locker"; diff --git a/_maps/shuttles/syndicate/syndicate_gec_lugol.dmm b/_maps/shuttles/syndicate/syndicate_gec_lugol.dmm index 04e7a8d4b46c..2e4e22caa6d6 100644 --- a/_maps/shuttles/syndicate/syndicate_gec_lugol.dmm +++ b/_maps/shuttles/syndicate/syndicate_gec_lugol.dmm @@ -575,7 +575,7 @@ /area/ship/construction) "gv" = ( /obj/structure/table, -/obj/item/folder/syndicate/red, +/obj/item/folder/documents/syndicate/red, /obj/effect/turf_decal/siding/thinplating/dark{ dir = 1 }, diff --git a/_maps/shuttles/syndicate/syndicate_gorlex_hyena.dmm b/_maps/shuttles/syndicate/syndicate_gorlex_hyena.dmm index 74c00cb758b6..0cd79289edec 100644 --- a/_maps/shuttles/syndicate/syndicate_gorlex_hyena.dmm +++ b/_maps/shuttles/syndicate/syndicate_gorlex_hyena.dmm @@ -1921,7 +1921,7 @@ }, /obj/effect/decal/cleanable/dirt/dust, /obj/item/paper_bin/carbon, -/obj/item/folder/syndicate/red, +/obj/item/folder/documents/syndicate/red, /obj/item/pen/fountain/captain, /obj/item/stamp/hos{ name = "captain's rubber stamp" diff --git a/_maps/shuttles/syndicate/syndicate_gorlex_komodo.dmm b/_maps/shuttles/syndicate/syndicate_gorlex_komodo.dmm index d3160d0743b1..4500ef61d3ba 100644 --- a/_maps/shuttles/syndicate/syndicate_gorlex_komodo.dmm +++ b/_maps/shuttles/syndicate/syndicate_gorlex_komodo.dmm @@ -3112,7 +3112,7 @@ /area/ship/crew/canteen) "El" = ( /obj/structure/filingcabinet, -/obj/item/folder/syndicate/mining, +/obj/item/folder/documents/syndicate/mining, /turf/open/floor/engine, /area/ship/bridge) "Ep" = ( diff --git a/_maps/shuttles/syndicate/syndicate_twinkleshine.dmm b/_maps/shuttles/syndicate/syndicate_twinkleshine.dmm index 5c49d6a71d6b..79c693817dda 100644 --- a/_maps/shuttles/syndicate/syndicate_twinkleshine.dmm +++ b/_maps/shuttles/syndicate/syndicate_twinkleshine.dmm @@ -1692,11 +1692,11 @@ /area/ship/medical) "jO" = ( /obj/structure/table/reinforced, -/obj/item/folder/syndicate/red{ +/obj/item/folder/documents/syndicate/red{ pixel_x = -8; pixel_y = 6 }, -/obj/item/folder/syndicate/blue{ +/obj/item/folder/documents/syndicate/blue{ pixel_x = 6; pixel_y = 4 }, diff --git a/check_regex.yaml b/check_regex.yaml index 5420d8fa692c..062b120ed936 100644 --- a/check_regex.yaml +++ b/check_regex.yaml @@ -38,7 +38,7 @@ standards: - exactly: [ - 271, + 269, "non-bitwise << uses", '(?DO NOT DIGEST." + icon_state = "paperbiscuit" + bg_color = "#ffffff" + w_class = WEIGHT_CLASS_TINY + max_integrity = 130 + drop_sound = 'sound/items/handling/disk_drop.ogg' + pickup_sound = 'sound/items/handling/disk_pickup.ogg' + /// Is biscuit cracked open or not? + var/cracked = FALSE + +/obj/item/folder/biscuit/update_overlays() + . = ..() + if(contents.len) //This is to prevent the not-sealed biscuit to have the folder_paper overlay when it gets sealed + . -= "folder_paper" + if(cracked) //Shows overlay only when it has content and is cracked open + . += "paperbiscuit_paper" + +///Checks if the biscuit has been already cracked. If its not then it dipsplays "unopened!" ballon alert. If it is cracked then it lets the code continue. +/obj/item/folder/biscuit/proc/crack_check(mob/user) + if (cracked) + return TRUE + balloon_alert(user, "unopened!") + return FALSE + +/obj/item/folder/biscuit/examine() + . = ..() + if(!cracked) + . += span_notice("To reach contents you need to crack it open.") + +//All next is done so you can't reach contents, or put any new contents when its not cracked open +/obj/item/folder/biscuit/remove_item(obj/item/item, mob/user) + if (!crack_check(user)) + return + + return ..() + +/obj/item/folder/biscuit/attack_hand(mob/user, list/modifiers) + if (LAZYACCESS(modifiers, RIGHT_CLICK) && !crack_check(user)) + return + + return ..() + +/obj/item/folder/biscuit/attackby(obj/item/weapon, mob/user, params) + if (is_type_in_typecache(weapon, folder_insertables) && !crack_check(user)) + return + + return ..() + +/obj/item/folder/biscuit/attack_self(mob/user) + add_fingerprint(user) + if (!cracked) + if (tgui_alert(user, "Do you want to crack it open?", "Biscuit Cracking", list("Yes", "No")) != "Yes") + return + cracked = TRUE + playsound(get_turf(user), 'sound/effects/snap.ogg', 60) + icon_state = "[icon_state]_cracked" + update_appearance() + + ui_interact(user) +//Corporate "confidental" biscuit cards +/obj/item/folder/biscuit/confidental + name = "\proper confidental biscuit card" + desc = "An confidental biscuit card. In a tasteful blue color with NT logo, looks like a chocolate bar. Has label which says DO NOT DIGEST." + icon_state = "paperbiscuit_secret" + bg_color = "#355e9f" + +//Biscuits which start not-sealed/cracked initially for the crafting, printing and such +/obj/item/folder/biscuit/unsealed + name = "\proper biscuit card" + desc = "An biscuit card. Has a label which says DO NOT DIGEST." + icon_state = "paperbiscuit_cracked" + cracked = TRUE + ///Was the biscuit already sealed by players? To prevent several tgui alerts + var/sealed = FALSE + ///What is the sprite for when its not cracked? As it starts already cracked, and for re-sealing needs to have a sprite + var/not_cracked_icon = "paperbiscuit" + +/obj/item/folder/biscuit/unsealed/examine() + . = ..() + if(!sealed) + . += span_notice("This one have not been sealed yet. You many insert anything to seal it by pressing it in hand. Once sealed, the contents are inaccessible until cracked open (irreversible).") + +//Asks if you want to seal the biscuit, after you do that it behaves like normal paper biscuit. +/obj/item/folder/biscuit/unsealed/attack_self(mob/user) + add_fingerprint(user) + if (!sealed) + if (tgui_alert(user, "Do you want to seal it? You must crack it open to reach the contents again!", "Biscuit Sealing", list("Yes", "No")) != "Yes") + return + cracked = FALSE + sealed = TRUE + playsound(get_turf(user), 'sound/items/tape.ogg', 60) + icon_state = "[not_cracked_icon]" + update_appearance() + + return ..() + +/obj/item/folder/biscuit/unsealed/confidental + name = "\proper confidental biscuit card" + desc = "An confidental biscuit card. In a tasteful blue color with NT logo, looks like a chocolate bar. To reach contents you need to crack it open. Has label which says DO NOT DIGEST." + icon_state = "paperbiscuit_secret_cracked" + bg_color = "#355e9f" + not_cracked_icon = "paperbiscuit_secret" diff --git a/code/modules/paperwork/carbonpaper.dm b/code/modules/paperwork/carbonpaper.dm index 5fb2731c7b4d..bbf0f59afe94 100644 --- a/code/modules/paperwork/carbonpaper.dm +++ b/code/modules/paperwork/carbonpaper.dm @@ -17,7 +17,7 @@ . = ..() if(copied) return - . += span_notice("Right-click to tear off the carbon-copy (you must use both hands).") + . += span_notice("Alt-click to tear off the carbon-copy (you must use both hands).") /obj/item/paper/carbon/proc/removecopy(mob/living/user) if(copied) @@ -34,3 +34,8 @@ /obj/item/paper/carbon_copy icon_state = "cpaper" + +/obj/item/paper/carbon/AltClick(mob/living/carbon/user, obj/item/I) + . = ..() + if(!copied) + removecopy(user) diff --git a/code/modules/paperwork/clipboard.dm b/code/modules/paperwork/clipboard.dm index 462c75c18184..54b9b8268cf9 100644 --- a/code/modules/paperwork/clipboard.dm +++ b/code/modules/paperwork/clipboard.dm @@ -1,3 +1,6 @@ +/** + * Clipboard + */ /obj/item/clipboard name = "clipboard" icon = 'icons/obj/bureaucracy.dmi' @@ -7,115 +10,166 @@ w_class = WEIGHT_CLASS_SMALL throw_speed = 3 throw_range = 7 - var/obj/item/pen/haspen //The stored pen. - var/obj/item/paper/toppaper //The topmost piece of paper. slot_flags = ITEM_SLOT_BELT resistance_flags = FLAMMABLE + // The stored pen + var/obj/item/pen/pen + +// Weakref of the topmost piece of paper +// +// This is used for the paper displayed on the clipboard's icon +// and it is the one attacked, when attacking the clipboard. +// (As you can't organise contents directly in BYOND) + + var/datum/weakref/toppaper_ref /obj/item/clipboard/Initialize() update_appearance() . = ..() /obj/item/clipboard/Destroy() - QDEL_NULL(haspen) - QDEL_NULL(toppaper) //let movable/Destroy handle the rest + QDEL_NULL(pen) return ..() +/obj/item/clipboard/examine() + . = ..() + if(pen) + . += "Alt-click to remove [pen]." + var/obj/item/paper/toppaper = toppaper_ref?.resolve() + if(toppaper) + . += "Ctrl-click to remove [toppaper]." + +/// Take out the topmost paper +/obj/item/clipboard/proc/remove_paper(obj/item/paper/paper, mob/user) + if(!istype(paper)) + return + paper.forceMove(user.loc) + user.put_in_hands(paper) + to_chat(user, "You remove [paper] from [src].") + var/obj/item/paper/toppaper = toppaper_ref?.resolve() + if(paper == toppaper) + toppaper_ref = null + var/obj/item/paper/newtop = locate(/obj/item/paper) in src + if(newtop && (newtop != paper)) + toppaper_ref = WEAKREF(newtop) + else + toppaper_ref = null + update_icon() + +/obj/item/clipboard/proc/remove_pen(mob/user) + pen.forceMove(user.loc) + user.put_in_hands(pen) + to_chat(user, "You remove [pen] from [src].") + pen = null + update_icon() + +/obj/item/clipboard/AltClick(mob/user) + ..() + if(pen) + remove_pen(user) + /obj/item/clipboard/update_overlays() . = ..() + var/obj/item/paper/toppaper = toppaper_ref?.resolve() if(toppaper) . += toppaper.icon_state . += toppaper.overlays - if(haspen) + if(pen) . += "clipboard_pen" . += "clipboard_over" -/obj/item/clipboard/attackby(obj/item/W, mob/user, params) - if(istype(W, /obj/item/paper)) - if(!user.transferItemToLoc(W, src)) +/obj/item/clipboard/CtrlClick(mob/user) + var/obj/item/paper/toppaper = toppaper_ref?.resolve() + remove_paper(toppaper, user) + return TRUE + +/obj/item/clipboard/attackby(obj/item/weapon, mob/user, params) + var/obj/item/paper/toppaper = toppaper_ref?.resolve() + if(istype(weapon, /obj/item/paper)) + //Add paper into the clipboard + if(!user.transferItemToLoc(weapon, src)) return - toppaper = W - to_chat(user, "You clip the paper onto \the [src].") - update_appearance() + toppaper_ref = WEAKREF(weapon) + to_chat(user, "You clip [weapon] onto [src].") + else if(istype(weapon, /obj/item/pen) && !pen) + //Add a pen into the clipboard, attack (write) if there is already one + if(!usr.transferItemToLoc(weapon, src)) + return + pen = weapon + to_chat(usr, "You slot [weapon] into [src].") else if(toppaper) toppaper.attackby(user.get_active_held_item(), user) - update_appearance() - + update_appearance() /obj/item/clipboard/attack_self(mob/user) - var/dat = "Clipboard" - if(haspen) - dat += "Remove Pen

" - else - dat += "Add Pen

" - - //The topmost paper. You can't organise contents directly in byond, so this is what we're stuck with. -Pete - if(toppaper) - var/obj/item/paper/P = toppaper - dat += "Write Remove - [P.name]

" - - for(P in src) - if(P == toppaper) - continue - dat += "Write Remove Move to top - [P.name]
" - user << browse(dat, "window=clipboard") - onclose(user, "clipboard") add_fingerprint(usr) + ui_interact(user) + return + +/obj/item/clipboard/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "Clipboard") + ui.open() + +/obj/item/clipboard/ui_data(mob/user) + // prepare data for TGUI + var/list/data = list() + data["pen"] = "[pen]" + + var/obj/item/paper/toppaper = toppaper_ref?.resolve() + data["top_paper"] = "[toppaper]" + data["top_paper_ref"] = "[REF(toppaper)]" + + data["paper"] = list() + data["paper_ref"] = list() + for(var/obj/item/paper/paper in src) + if(paper == toppaper) + continue + data["paper"] += "[paper]" + data["paper_ref"] += "[REF(paper)]" + + return data + +/obj/item/clipboard/ui_act(action, params) + . = ..() + if(.) + return - -/obj/item/clipboard/Topic(href, href_list) - ..() if(usr.stat != CONSCIOUS || HAS_TRAIT(usr, TRAIT_HANDS_BLOCKED)) return - if(usr.contents.Find(src)) - - if(href_list["pen"]) - if(haspen) - haspen.forceMove(usr.loc) - usr.put_in_hands(haspen) - haspen = null - - if(href_list["addpen"]) - if(!haspen) - var/obj/item/held = usr.get_active_held_item() - if(istype(held, /obj/item/pen)) - var/obj/item/pen/W = held - if(!usr.transferItemToLoc(W, src)) - return - haspen = W - to_chat(usr, "You slot [W] into [src].") - - if(href_list["write"]) - var/obj/item/P = locate(href_list["write"]) in src - if(istype(P)) - if(usr.get_active_held_item()) - P.attackby(usr.get_active_held_item(), usr) - - if(href_list["remove"]) - var/obj/item/P = locate(href_list["remove"]) in src - if(istype(P)) - P.forceMove(usr.loc) - usr.put_in_hands(P) - if(P == toppaper) - toppaper = null - var/obj/item/paper/newtop = locate(/obj/item/paper) in src - if(newtop && (newtop != P)) - toppaper = newtop - else - toppaper = null - - if(href_list["read"]) - var/obj/item/paper/P = locate(href_list["read"]) in src - if(istype(P)) - usr.examinate(P) - - if(href_list["top"]) - var/obj/item/P = locate(href_list["top"]) in src - if(istype(P)) - toppaper = P - to_chat(usr, "You move [P.name] to the top.") - - //Update everything - attack_self(usr) - update_appearance() + switch(action) + // Take the pen out + if("remove_pen") + if(pen) + remove_pen(usr) + . = TRUE + // Take paper out + if("remove_paper") + var/obj/item/paper/paper = locate(params["ref"]) in src + if(istype(paper)) + remove_paper(paper, usr) + . = TRUE + // Look at (or edit) the paper + if("edit_paper") + var/obj/item/paper/paper = locate(params["ref"]) in src + if(istype(paper)) + paper.ui_interact(usr) + update_icon() + . = TRUE + // Move paper to the top + if("move_top_paper") + var/obj/item/paper/paper = locate(params["ref"]) in src + if(istype(paper)) + toppaper_ref = WEAKREF(paper) + to_chat(usr, "You move [paper] to the top.") + update_icon() + . = TRUE + // Rename the paper (it's a verb) + if("rename_paper") + var/obj/item/paper/paper = locate(params["ref"]) in src + if(istype(paper)) + paper.rename() + update_icon() + . = TRUE diff --git a/code/modules/paperwork/fax.dm b/code/modules/paperwork/fax.dm index b48d3b07c1c8..cb5a025da475 100644 --- a/code/modules/paperwork/fax.dm +++ b/code/modules/paperwork/fax.dm @@ -48,6 +48,7 @@ /obj/item/spacecash, /obj/item/holochip, /obj/item/card, + /obj/item/folder/biscuit ) /// Internal radio for announcing over comms var/obj/item/radio/radio @@ -97,6 +98,7 @@ GLOB.fax_machines -= src QDEL_NULL(loaded_item_ref) QDEL_NULL(wires) + QDEL_NULL(radio) return ..() /obj/machinery/fax/update_overlays() diff --git a/code/modules/paperwork/folders.dm b/code/modules/paperwork/folders.dm index 01f4547f048e..ad18b2bcd0b4 100644 --- a/code/modules/paperwork/folders.dm +++ b/code/modules/paperwork/folders.dm @@ -6,141 +6,116 @@ w_class = WEIGHT_CLASS_SMALL pressure_resistance = 2 resistance_flags = FLAMMABLE + /// The background color for tgui in hex (with a `#`) + var/bg_color = "#7f7f7f" + /// A typecache of the objects that can be inserted into a folder + var/static/list/folder_insertables = typecacheof(list( + /obj/item/paper, + /obj/item/photo, + /obj/item/documents + )) + +/obj/item/folder/Initialize() + update_icon() + . = ..() + +/obj/item/folder/Destroy() + for(var/obj/important_thing in contents) + if(!(important_thing.resistance_flags & INDESTRUCTIBLE)) + continue + important_thing.forceMove(drop_location()) //don't destroy round critical content such as objective documents. + return ..() -/obj/item/folder/blue - desc = "A blue folder." - icon_state = "folder_blue" +/obj/item/folder/examine() + . = ..() + if(contents) + . += "Alt-click to remove [contents[1]]." -/obj/item/folder/red - desc = "A red folder." - icon_state = "folder_red" +/obj/item/folder/proc/rename(mob/user) + if(!user.is_literate()) + to_chat(user, "You scribble illegibly on the cover of [src]!") + return -/obj/item/folder/yellow - desc = "A yellow folder." - icon_state = "folder_yellow" + var/inputvalue = stripped_input(user, "What would you like to label the folder?", "Folder Labelling", "", MAX_NAME_LEN) -/obj/item/folder/white - desc = "A white folder." - icon_state = "folder_white" + if(!inputvalue) + return -/obj/item/folder/solgov - desc = "A blue folder with a SolGov seal." - icon_state = "folder_solgov" + if(user.canUseTopic(src, BE_CLOSE)) + name = "folder[(inputvalue ? " - '[inputvalue]'" : null)]" -/obj/item/folder/terragov - desc = "A green folder with a Terran Regency seal." - icon_state = "folder_terragov" +/obj/item/folder/proc/remove_item(obj/item/Item, mob/user) + if(istype(Item)) + Item.forceMove(user.loc) + user.put_in_hands(Item) + to_chat(user, "You remove [Item] from [src].") + update_icon() + +/obj/item/folder/AltClick(mob/user) + ..() + if(contents) + remove_item(contents[1], user) /obj/item/folder/update_overlays() . = ..() if(contents.len) . += "folder_paper" - -/obj/item/folder/attackby(obj/item/W, mob/user, params) - if(burn_paper_product_attackby_check(W, user)) +/obj/item/folder/attackby(obj/item/weapon, mob/user, params) + if(burn_paper_product_attackby_check(weapon, user)) return - if(istype(W, /obj/item/paper) || istype(W, /obj/item/photo) || istype(W, /obj/item/documents) || istype(W, /obj/item/disk)) - if(!user.transferItemToLoc(W, src)) + if(is_type_in_typecache(weapon, folder_insertables)) + /// Add paper, photo or documents into the folder + if(!user.transferItemToLoc(weapon, src)) return - to_chat(user, "You put [W] into [src].") + to_chat(user, "You put [weapon] into [src].") update_appearance() - else if(istype(W, /obj/item/pen)) - if(!user.is_literate()) - to_chat(user, "You scribble illegibly on the cover of [src]!") - return - - var/inputvalue = stripped_input(user, "What would you like to label the folder?", "Folder Labelling", "", MAX_NAME_LEN) - - if(!inputvalue) - return - - if(user.canUseTopic(src, BE_CLOSE)) - name = "folder[(inputvalue ? " - '[inputvalue]'" : null)]" - + else if(istype(weapon, /obj/item/pen)) + rename(user) /obj/item/folder/attack_self(mob/user) - var/dat = "[name]" - - for(var/obj/item/I in src) - dat += "Remove - [I.name]
" - user << browse(dat, "window=folder") - onclose(user, "folder") add_fingerprint(usr) + ui_interact(user) + return + +/obj/item/folder/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "Folder") + ui.open() + +/obj/item/folder/ui_data(mob/user) + var/list/data = list() + if(istype(src, /obj/item/folder/syndicate || /obj/item/folder/documents/syndicate)) + data["theme"] = "syndicate" + data["bg_color"] = "[bg_color]" + data["folder_name"] = "[name]" + + data["contents"] = list() + data["contents_ref"] = list() + for(var/Content in src) + data["contents"] += "[Content]" + data["contents_ref"] += "[REF(Content)]" + + return data + +/obj/item/folder/ui_act(action, params) + . = ..() + if(.) + return - -/obj/item/folder/Topic(href, href_list) - ..() if(usr.stat != CONSCIOUS || HAS_TRAIT(usr, TRAIT_HANDS_BLOCKED)) return - if(usr.contents.Find(src)) - - if(href_list["remove"]) - var/obj/item/I = locate(href_list["remove"]) in src - if(istype(I)) - I.forceMove(usr.loc) - usr.put_in_hands(I) - - if(href_list["read"]) - var/obj/item/I = locate(href_list["read"]) in src - if(istype(I)) - usr.examinate(I) - - //Update everything - attack_self(usr) - update_appearance() - -/obj/item/folder/documents - name = "folder- 'TOP SECRET'" - desc = "A folder stamped \"Top Secret - Property of Nanotrasen Corporation. Unauthorized distribution is punishable by death.\"" - -/obj/item/folder/documents/Initialize() - . = ..() - new /obj/item/documents/nanotrasen(src) - update_appearance() - -/obj/item/folder/syndicate - icon_state = "folder_syndie" - name = "folder- 'TOP SECRET'" - desc = "A folder stamped \"Top Secret - Property of The Syndicate.\"" - -/obj/item/folder/syndicate/red - icon_state = "folder_sred" - -/obj/item/folder/syndicate/red/Initialize() - . = ..() - new /obj/item/documents/syndicate/red(src) - update_appearance() - -/obj/item/folder/syndicate/blue - icon_state = "folder_sblue" - -/obj/item/folder/syndicate/blue/Initialize() - . = ..() - new /obj/item/documents/syndicate/blue(src) - update_appearance() - -/obj/item/folder/syndicate/mining/Initialize() - . = ..() - new /obj/item/documents/syndicate/mining(src) - update_appearance() - -/obj/item/folder/solgov/red - desc = "A blue folder with a SolGov seal." - icon_state = "folder_solgovred" - -/obj/item/folder/solgov/red/Initialize() - . = ..() - new /obj/item/documents/solgov(src) - update_appearance() - - -/obj/item/folder/terragov/red - desc = "A green folder with a Terran Regency seal." - icon_state = "folder_terragovred" - -/obj/item/folder/terragov/red/Initialize() - . = ..() - new /obj/item/documents/terragov(src) - update_appearance() + switch(action) + // Take item out + if("remove") + var/obj/item/Item = locate(params["ref"]) in src + remove_item(Item, usr) + . = TRUE + // Inspect the item + if("examine") + var/obj/item/Item = locate(params["ref"]) in src + if(istype(Item)) + usr.examinate(Item) + . = TRUE diff --git a/code/modules/paperwork/folders_premade.dm b/code/modules/paperwork/folders_premade.dm new file mode 100644 index 000000000000..a919dce944ce --- /dev/null +++ b/code/modules/paperwork/folders_premade.dm @@ -0,0 +1,63 @@ +/obj/item/folder/blue + desc = "A blue folder." + icon_state = "folder_blue" + +/obj/item/folder/red + desc = "A red folder." + icon_state = "folder_red" + +/obj/item/folder/yellow + desc = "A yellow folder." + icon_state = "folder_yellow" + +/obj/item/folder/white + desc = "A white folder." + icon_state = "folder_white" + +/obj/item/folder/solgov + desc = "A blue folder with a SolGov seal." + icon_state = "folder_solgov" + +/obj/item/folder/terragov + desc = "A green folder with a Terran Regency seal." + icon_state = "folder_terragov" + +/obj/item/folder/syndicate + desc = "A folder with a Syndicate color scheme." + icon_state = "folder_syndie" + +/obj/item/folder/documents + var/document = /obj/item/documents/nanotrasen + name = "folder- 'TOP SECRET'" + desc = "A folder stamped \"Top Secret - Property of Nanotrasen Corporation. Unauthorized distribution is punishable by death.\"" + +/obj/item/folder/documents/Initialize() + . = ..() + new document(src) + update_appearance() + +/obj/item/folder/documents/syndicate + icon_state = "folder_syndie" + name = "folder- 'TOP SECRET'" + desc = "A folder stamped \"Top Secret - Property of The Syndicate.\"" + +/obj/item/folder/documents/syndicate/red + document = /obj/item/documents/syndicate/red + icon_state = "folder_sred" + +/obj/item/folder/documents/syndicate/blue + document = /obj/item/documents/syndicate/blue + icon_state = "folder_sblue" + +/obj/item/folder/documents/syndicate/mining + document = /obj/item/documents/syndicate/mining + +/obj/item/folder/documents/solgov + document = /obj/item/documents/solgov + desc = "A blue folder with a SolGov seal." + icon_state = "folder_solgovred" + +/obj/item/folder/documents/terragov + document = /obj/item/documents/terragov + desc = "A green folder with a Terran Regency seal." + icon_state = "folder_terragovred" diff --git a/code/modules/paperwork/paper.dm b/code/modules/paperwork/paper.dm index e30a2bdd9737..d858d7a290e8 100644 --- a/code/modules/paperwork/paper.dm +++ b/code/modules/paperwork/paper.dm @@ -489,8 +489,8 @@ var/obj/item/clipboard/clipboard = loc // This is just so you can still use a stamp if you're holding one. Otherwise, it'll // use the clipboard's pen, if applicable. - if(!istype(holding, /obj/item/stamp) && clipboard.haspen) - holding = clipboard.haspen + if(!istype(holding, /obj/item/stamp) && clipboard.pen) + holding = clipboard.pen data["held_item_details"] = istype(holding) ? holding.get_writing_implement_details() : null @@ -562,8 +562,8 @@ var/obj/item/clipboard/clipboard = loc // This is just so you can still use a stamp if you're holding one. Otherwise, it'll // use the clipboard's pen, if applicable. - if(!istype(holding, /obj/item/stamp) && clipboard.haspen) - holding = clipboard.haspen + if(!istype(holding, /obj/item/stamp) && clipboard.pen) + holding = clipboard.pen // As of the time of writing, can_write outputs a message to the user so we don't have to. if(!user.can_write(holding)) @@ -602,8 +602,8 @@ var/obj/item/clipboard/clipboard = loc // This is just so you can still use a stamp if you're holding one. Otherwise, it'll // use the clipboard's pen, if applicable. - if(!istype(holding, /obj/item/stamp) && clipboard.haspen) - holding = clipboard.haspen + if(!istype(holding, /obj/item/stamp) && clipboard.pen) + holding = clipboard.pen // As of the time of writing, can_write outputs a message to the user so we don't have to. if(!user.can_write(holding)) diff --git a/code/modules/paperwork/paper_cutter.dm b/code/modules/paperwork/paper_cutter.dm index 1c1ebd86336e..20ff55f0d789 100644 --- a/code/modules/paperwork/paper_cutter.dm +++ b/code/modules/paperwork/paper_cutter.dm @@ -28,7 +28,7 @@ /obj/item/papercutter/attackby(obj/item/P, mob/user, params) - if(istype(P, /obj/item/paper) && !storedpaper) + if(istype(P, /obj/item/paper) && !storedpaper && !istype(P, /obj/item/paper/paperslip)) if(!user.transferItemToLoc(P, src)) return playsound(loc, "pageturn", 60, TRUE) @@ -71,8 +71,8 @@ to_chat(user, "You neatly cut [storedpaper].") storedpaper = null qdel(storedpaper) - new /obj/item/paperslip(get_turf(src)) - new /obj/item/paperslip(get_turf(src)) + new /obj/item/paper/paperslip(get_turf(src)) + new /obj/item/paper/paperslip(get_turf(src)) update_appearance() /obj/item/papercutter/MouseDrop(atom/over_object) @@ -89,24 +89,25 @@ M.putItemFromInventoryInHandIfPossible(src, H.held_index) add_fingerprint(M) -/obj/item/paperslip +/obj/item/paper/paperslip name = "paper slip" desc = "A little slip of paper left over after a larger piece was cut. Whoa." icon_state = "paperslip" - icon = 'icons/obj/bureaucracy.dmi' - resistance_flags = FLAMMABLE - max_integrity = 50 - -/obj/item/paperslip/attackby(obj/item/I, mob/living/user, params) - if(burn_paper_product_attackby_check(I, user)) - return - return ..() - -/obj/item/paperslip/Initialize() - . = ..() - pixel_x = base_pixel_x + rand(-5, 5) - pixel_y = base_pixel_y + rand(-5, 5) + lefthand_file = 'icons/mob/inhands/equipment/idcards_lefthand.dmi' + righthand_file = 'icons/mob/inhands/equipment/idcards_righthand.dmi' + grind_results = list(/datum/reagent/cellulose = 1.5) //It's a normal paper sheet divided in 2. 3 divided by 2 equals 1.5, this way you can't magically dupe cellulose + +/obj/item/paper/paperslip/corporate //More fancy and sturdy paper slip which is a "plastic card", used for things like spare ID safe code + name = "corporate plastic card" + desc = "A plastic card for confidental corporate matters. Can be written on with pen somehow." + icon_state = "corppaperslip" + grind_results = list(/datum/reagent/plastic_polymers = 1.5) //It's a plastic card after all + max_integrity = 130 //Slightly more sturdy because of being made out of a plastic + drop_sound = 'sound/items/handling/disk_drop.ogg' + pickup_sound = 'sound/items/handling/disk_pickup.ogg' + throw_range = 6 + throw_speed = 2 /obj/item/hatchet/cutterblade diff --git a/code/modules/research/designs/autolathe_designs.dm b/code/modules/research/designs/autolathe_designs.dm index 71d1ae74c0be..9e16f4fb18b1 100644 --- a/code/modules/research/designs/autolathe_designs.dm +++ b/code/modules/research/designs/autolathe_designs.dm @@ -1198,3 +1198,20 @@ materials = list(/datum/material/iron = 200, /datum/material/glass = 200) build_path = /obj/item/fishing_rod category = list("initial","Misc","Equipment") + + +/datum/design/paper_biscuit + name = "Paper Biscuit" + id = "biscuit" + build_type = PROTOLATHE | AUTOLATHE + materials = list(/datum/material/plastic = 20) + build_path = /obj/item/folder/biscuit/unsealed + category = list("initial", "Tools", "Misc") + +/datum/design/paper_biscuit_confidental + name = "Confidental Paper Biscuit" + id = "confidental_biscuit" + build_type = PROTOLATHE | AUTOLATHE + materials = list(/datum/material/plastic = 30) + build_path = /obj/item/folder/biscuit/unsealed/confidental + category = list("initial", "Tools", "Misc") diff --git a/icons/obj/bureaucracy.dmi b/icons/obj/bureaucracy.dmi index 8a042bc0d081cffd99b3dbab693cd7feb4dd9451..1473efdcd80f033819765037af0d7d63ced230d3 100644 GIT binary patch delta 5525 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 SGg||~Emb8A#rjv~;r|2Bxd9IV delta 4839 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 { + const { act, data } = useBackend(context); + const { pen, top_paper, top_paper_ref, paper, paper_ref } = data; + return ( + + +
+ {pen ? ( + + act('remove_pen')} /> + } + > + {pen} + + + ) : ( + + No pen attached! + + )} +
+ + {top_paper ? ( + + + {top_paper} + + +