From 243ce9ea61b463f6de3cd4bb5453dc844e534f06 Mon Sep 17 00:00:00 2001 From: Changelogs Date: Tue, 24 Sep 2024 01:02:51 +0000 Subject: [PATCH 01/30] Automatic changelog compile [ci skip] --- html/changelogs/AutoChangeLog-pr-2932.yml | 5 ----- html/changelogs/AutoChangeLog-pr-3370.yml | 4 ---- html/changelogs/AutoChangeLog-pr-3377.yml | 6 ------ html/changelogs/AutoChangeLog-pr-3392.yml | 4 ---- html/changelogs/AutoChangeLog-pr-3397.yml | 5 ----- html/changelogs/AutoChangeLog-pr-3409.yml | 4 ---- html/changelogs/AutoChangeLog-pr-3411.yml | 4 ---- html/changelogs/AutoChangeLog-pr-3412.yml | 5 ----- html/changelogs/AutoChangeLog-pr-3414.yml | 4 ---- html/changelogs/AutoChangeLog-pr-3415.yml | 4 ---- html/changelogs/AutoChangeLog-pr-3416.yml | 4 ---- html/changelogs/archive/2024-09.yml | 26 +++++++++++++++++++++++ 12 files changed, 26 insertions(+), 49 deletions(-) delete mode 100644 html/changelogs/AutoChangeLog-pr-2932.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-3370.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-3377.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-3392.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-3397.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-3409.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-3411.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-3412.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-3414.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-3415.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-3416.yml diff --git a/html/changelogs/AutoChangeLog-pr-2932.yml b/html/changelogs/AutoChangeLog-pr-2932.yml deleted file mode 100644 index 14c0c5985f64..000000000000 --- a/html/changelogs/AutoChangeLog-pr-2932.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: FalloutFalcon -changes: - - {code_imp: bunch of code organization related to melee} - - {refactor: cleaned up a bunch of melee items to have better inheritance and paths} -delete-after: true diff --git a/html/changelogs/AutoChangeLog-pr-3370.yml b/html/changelogs/AutoChangeLog-pr-3370.yml deleted file mode 100644 index 95a56f2e9b49..000000000000 --- a/html/changelogs/AutoChangeLog-pr-3370.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: trazodont -changes: - - {bugfix: miso soup spelling error} -delete-after: true diff --git a/html/changelogs/AutoChangeLog-pr-3377.yml b/html/changelogs/AutoChangeLog-pr-3377.yml deleted file mode 100644 index 26fbe6b2eec3..000000000000 --- a/html/changelogs/AutoChangeLog-pr-3377.yml +++ /dev/null @@ -1,6 +0,0 @@ -author: Apogee-dev -changes: - - {balance: Changed decoration on Miskilamo ships to look similar to each other} - - {balance: reduced Kilo starting funds to 1500} - - {bugfix: fixed wires on Mudskipper} -delete-after: true diff --git a/html/changelogs/AutoChangeLog-pr-3392.yml b/html/changelogs/AutoChangeLog-pr-3392.yml deleted file mode 100644 index b1fd3875e1c8..000000000000 --- a/html/changelogs/AutoChangeLog-pr-3392.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: thgvr -changes: - - {rscadd: A bunch of kepori underwear have sprites now} -delete-after: true diff --git a/html/changelogs/AutoChangeLog-pr-3397.yml b/html/changelogs/AutoChangeLog-pr-3397.yml deleted file mode 100644 index 673b299d889d..000000000000 --- a/html/changelogs/AutoChangeLog-pr-3397.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: rye, erika -changes: - - {rscadd: 'concrete jugs have been replaced by much more appropriate concrete bags, - jee, i hope whoever made *that* blunder got fired.'} -delete-after: true diff --git a/html/changelogs/AutoChangeLog-pr-3409.yml b/html/changelogs/AutoChangeLog-pr-3409.yml deleted file mode 100644 index e2ad0fc06bde..000000000000 --- a/html/changelogs/AutoChangeLog-pr-3409.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: PositiveEntropy -changes: - - {imageadd: Resprites all balaclavas!} -delete-after: true diff --git a/html/changelogs/AutoChangeLog-pr-3411.yml b/html/changelogs/AutoChangeLog-pr-3411.yml deleted file mode 100644 index cb95ac44d223..000000000000 --- a/html/changelogs/AutoChangeLog-pr-3411.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: zimon9 -changes: - - {rscadd: Adds a bit more contrast to the output of health analyzers} -delete-after: true diff --git a/html/changelogs/AutoChangeLog-pr-3412.yml b/html/changelogs/AutoChangeLog-pr-3412.yml deleted file mode 100644 index 1c0b79981ecd..000000000000 --- a/html/changelogs/AutoChangeLog-pr-3412.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: Bjarl -changes: - - {bugfix: turrets will now _actually_ connect to their console. i swear im a real - coder.} -delete-after: true diff --git a/html/changelogs/AutoChangeLog-pr-3414.yml b/html/changelogs/AutoChangeLog-pr-3414.yml deleted file mode 100644 index a4603970da7e..000000000000 --- a/html/changelogs/AutoChangeLog-pr-3414.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: Thera-Pissed -changes: - - {rscdel: B.E.P.I.S. and related tech nodes.} -delete-after: true diff --git a/html/changelogs/AutoChangeLog-pr-3415.yml b/html/changelogs/AutoChangeLog-pr-3415.yml deleted file mode 100644 index 05558e44aa1c..000000000000 --- a/html/changelogs/AutoChangeLog-pr-3415.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: Thera-Pissed -changes: - - {rscdel: unused did_fire var} -delete-after: true diff --git a/html/changelogs/AutoChangeLog-pr-3416.yml b/html/changelogs/AutoChangeLog-pr-3416.yml deleted file mode 100644 index b99d0706e9ef..000000000000 --- a/html/changelogs/AutoChangeLog-pr-3416.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: thgvr -changes: - - {balance: Colossus now only has 2 recruit slots instead of a whopping !!5!!} -delete-after: true diff --git a/html/changelogs/archive/2024-09.yml b/html/changelogs/archive/2024-09.yml index d6027a6f2a58..130805ee50eb 100644 --- a/html/changelogs/archive/2024-09.yml +++ b/html/changelogs/archive/2024-09.yml @@ -137,3 +137,29 @@ Bjarl: - rscadd: You can now buy flares at the outpost - rscadd: Wasteplanets now will generate concrete filled caves. +2024-09-24: + Apogee-dev: + - balance: Changed decoration on Miskilamo ships to look similar to each other + - balance: reduced Kilo starting funds to 1500 + - bugfix: fixed wires on Mudskipper + Bjarl: + - bugfix: turrets will now _actually_ connect to their console. i swear im a real + coder. + FalloutFalcon: + - code_imp: bunch of code organization related to melee + - refactor: cleaned up a bunch of melee items to have better inheritance and paths + PositiveEntropy: + - imageadd: Resprites all balaclavas! + Thera-Pissed: + - rscdel: unused did_fire var + - rscdel: B.E.P.I.S. and related tech nodes. + rye, erika: + - rscadd: concrete jugs have been replaced by much more appropriate concrete bags, + jee, i hope whoever made *that* blunder got fired. + thgvr: + - balance: Colossus now only has 2 recruit slots instead of a whopping !!5!! + - rscadd: A bunch of kepori underwear have sprites now + trazodont: + - bugfix: miso soup spelling error + zimon9: + - rscadd: Adds a bit more contrast to the output of health analyzers From de14f00d60e1943d8dd43c1cd3c53154f696853c Mon Sep 17 00:00:00 2001 From: Jedi-Toothpaste <53096233+Jedi-Toothpaste@users.noreply.github.com> Date: Tue, 24 Sep 2024 23:47:10 +0100 Subject: [PATCH 02/30] mudskipper and shetland window fix (#3426) ## About The Pull Request Added windows to the mudskipper and shetland's engines as well for consistency see #3434 for the Kilo fixes too. Also seperated the Shetland's engine rooms so both buttons don't open both sides. Now the button in each engine room will open only it's respective side. ## Changelog :cl: fix: Added windows to the mudskipper and shetland's engines. fix: Adjusted the blast doors which open on the Shetland's engines. /:cl: --- .../independent/independent_mudskipper.dmm | 6 +++++ .../independent/independent_shetland.dmm | 24 ++++++++++++++----- 2 files changed, 24 insertions(+), 6 deletions(-) diff --git a/_maps/shuttles/independent/independent_mudskipper.dmm b/_maps/shuttles/independent/independent_mudskipper.dmm index ac2be582662a..be3d9a994e7f 100644 --- a/_maps/shuttles/independent/independent_mudskipper.dmm +++ b/_maps/shuttles/independent/independent_mudskipper.dmm @@ -1096,6 +1096,9 @@ dir = 4; id = "mudskipper_engine" }, +/obj/structure/window/reinforced{ + dir = 8 + }, /turf/open/floor/plating, /area/ship/engineering/engine) "zR" = ( @@ -1670,6 +1673,9 @@ dir = 4; id = "mudskipper_engine" }, +/obj/structure/window/reinforced{ + dir = 8 + }, /turf/open/floor/plating, /area/ship/engineering/engine) "MK" = ( diff --git a/_maps/shuttles/independent/independent_shetland.dmm b/_maps/shuttles/independent/independent_shetland.dmm index 256e9bc75c88..89dd45bb2262 100644 --- a/_maps/shuttles/independent/independent_shetland.dmm +++ b/_maps/shuttles/independent/independent_shetland.dmm @@ -1492,7 +1492,7 @@ }, /obj/machinery/button/door{ dir = 1; - id = "amogusthrusters"; + id = "shetportthrusters"; name = "Thruster Lockdown"; pixel_y = -21 }, @@ -2297,7 +2297,7 @@ pixel_y = 5 }, /obj/machinery/button/door{ - id = "amogusthrusters"; + id = "shetstarboardengine"; name = "Thruster Lockdown"; pixel_y = 24 }, @@ -2748,11 +2748,14 @@ }, /obj/machinery/door/poddoor{ dir = 4; - id = "amogusthrusters" + id = "shetstarboardengine" }, /obj/effect/turf_decal/industrial/warning{ dir = 4 }, +/obj/structure/window/reinforced{ + dir = 8 + }, /turf/open/floor/plating, /area/ship/maintenance/starboard) "wU" = ( @@ -4423,11 +4426,14 @@ }, /obj/machinery/door/poddoor{ dir = 4; - id = "amogusthrusters" + id = "shetportthrusters" }, /obj/effect/turf_decal/industrial/warning{ dir = 4 }, +/obj/structure/window/reinforced{ + dir = 8 + }, /turf/open/floor/plating, /area/ship/maintenance/port) "Lx" = ( @@ -4989,11 +4995,14 @@ }, /obj/machinery/door/poddoor{ dir = 4; - id = "amogusthrusters" + id = "shetportthrusters" }, /obj/effect/turf_decal/industrial/warning{ dir = 4 }, +/obj/structure/window/reinforced{ + dir = 8 + }, /turf/open/floor/plating, /area/ship/maintenance/port) "PR" = ( @@ -5157,11 +5166,14 @@ }, /obj/machinery/door/poddoor{ dir = 4; - id = "amogusthrusters" + id = "shetstarboardengine" }, /obj/effect/turf_decal/industrial/warning{ dir = 4 }, +/obj/structure/window/reinforced{ + dir = 8 + }, /turf/open/floor/plating, /area/ship/maintenance/starboard) "Ri" = ( From 5a7fcb32088ac609ee462c51d7da4ff73e2fd076 Mon Sep 17 00:00:00 2001 From: Changelogs Date: Tue, 24 Sep 2024 17:57:55 -0500 Subject: [PATCH 03/30] Automatic changelog generation for PR #3426 [ci skip] --- html/changelogs/AutoChangeLog-pr-3426.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-3426.yml diff --git a/html/changelogs/AutoChangeLog-pr-3426.yml b/html/changelogs/AutoChangeLog-pr-3426.yml new file mode 100644 index 000000000000..476c9d7c88aa --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-3426.yml @@ -0,0 +1,5 @@ +author: Jedi-Toothpaste +changes: + - {bugfix: Added windows to the mudskipper and shetland's engines.} + - {bugfix: Adjusted the blast doors which open on the Shetland's engines.} +delete-after: true From d52f36b1ce04ae3f2091c787858d3a4ddd205688 Mon Sep 17 00:00:00 2001 From: Theos Date: Tue, 24 Sep 2024 19:44:59 -0400 Subject: [PATCH 04/30] Sawn variants for the illestren and improvised shotgun now properly have their stats set (#3427) ## About The Pull Request If the illestren's sawn off accuracy is unreasonably high I'd like to know because it's TERRIBLE ## Changelog :cl: fix: sawn off illestren/improvised shotgun stats are now consistent if they are spawned in /:cl: --------- Signed-off-by: Theos --- code/modules/projectiles/guns/ballistic/rifle.dm | 2 ++ code/modules/projectiles/guns/ballistic/shotgun.dm | 8 ++++++++ 2 files changed, 10 insertions(+) diff --git a/code/modules/projectiles/guns/ballistic/rifle.dm b/code/modules/projectiles/guns/ballistic/rifle.dm index 2d3cb6908c83..2be77ee20835 100644 --- a/code/modules/projectiles/guns/ballistic/rifle.dm +++ b/code/modules/projectiles/guns/ballistic/rifle.dm @@ -127,6 +127,8 @@ sawn_off = TRUE weapon_weight = WEAPON_MEDIUM w_class = WEIGHT_CLASS_NORMAL + spread = 24 + spread_unwielded = 30 slot_flags = ITEM_SLOT_BELT /obj/item/gun/ballistic/rifle/solgov diff --git a/code/modules/projectiles/guns/ballistic/shotgun.dm b/code/modules/projectiles/guns/ballistic/shotgun.dm index eb8ea3355fe9..2d70bf9851bb 100644 --- a/code/modules/projectiles/guns/ballistic/shotgun.dm +++ b/code/modules/projectiles/guns/ballistic/shotgun.dm @@ -432,6 +432,14 @@ EMPTY_GUN_HELPER(shotgun/automatic/bulldog/inteq) sawn_off = TRUE slot_flags = ITEM_SLOT_BELT + wield_slowdown = 0.25 + wield_delay = 0.3 SECONDS //OP? maybe + + spread = 8 + spread_unwielded = 15 + recoil = 3 //or not + recoil_unwielded = 5 + /obj/item/gun/ballistic/shotgun/automatic/combat/compact/compact name = "compact compact combat shotgun" desc = "A compact version of the compact version of the semi automatic combat shotgun. For when you want a gun the same size as your brain." From fcdc0c0dddfea17b3f62d5733bda8c95499f86bd Mon Sep 17 00:00:00 2001 From: Changelogs Date: Tue, 24 Sep 2024 18:55:45 -0500 Subject: [PATCH 05/30] Automatic changelog generation for PR #3427 [ci skip] --- html/changelogs/AutoChangeLog-pr-3427.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-3427.yml diff --git a/html/changelogs/AutoChangeLog-pr-3427.yml b/html/changelogs/AutoChangeLog-pr-3427.yml new file mode 100644 index 000000000000..9db44c29cad7 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-3427.yml @@ -0,0 +1,5 @@ +author: SomeguyManperson +changes: + - {bugfix: sawn off illestren/improvised shotgun stats are now consistent if they + are spawned in} +delete-after: true From d0171aa08ab7d4770422af584432490c1956b374 Mon Sep 17 00:00:00 2001 From: Changelogs Date: Wed, 25 Sep 2024 01:03:35 +0000 Subject: [PATCH 06/30] Automatic changelog compile [ci skip] --- html/changelogs/AutoChangeLog-pr-3426.yml | 5 ----- html/changelogs/AutoChangeLog-pr-3427.yml | 5 ----- html/changelogs/archive/2024-09.yml | 7 +++++++ 3 files changed, 7 insertions(+), 10 deletions(-) delete mode 100644 html/changelogs/AutoChangeLog-pr-3426.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-3427.yml diff --git a/html/changelogs/AutoChangeLog-pr-3426.yml b/html/changelogs/AutoChangeLog-pr-3426.yml deleted file mode 100644 index 476c9d7c88aa..000000000000 --- a/html/changelogs/AutoChangeLog-pr-3426.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: Jedi-Toothpaste -changes: - - {bugfix: Added windows to the mudskipper and shetland's engines.} - - {bugfix: Adjusted the blast doors which open on the Shetland's engines.} -delete-after: true diff --git a/html/changelogs/AutoChangeLog-pr-3427.yml b/html/changelogs/AutoChangeLog-pr-3427.yml deleted file mode 100644 index 9db44c29cad7..000000000000 --- a/html/changelogs/AutoChangeLog-pr-3427.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: SomeguyManperson -changes: - - {bugfix: sawn off illestren/improvised shotgun stats are now consistent if they - are spawned in} -delete-after: true diff --git a/html/changelogs/archive/2024-09.yml b/html/changelogs/archive/2024-09.yml index 130805ee50eb..d86f5c86c955 100644 --- a/html/changelogs/archive/2024-09.yml +++ b/html/changelogs/archive/2024-09.yml @@ -163,3 +163,10 @@ - bugfix: miso soup spelling error zimon9: - rscadd: Adds a bit more contrast to the output of health analyzers +2024-09-25: + Jedi-Toothpaste: + - bugfix: Added windows to the mudskipper and shetland's engines. + - bugfix: Adjusted the blast doors which open on the Shetland's engines. + SomeguyManperson: + - bugfix: sawn off illestren/improvised shotgun stats are now consistent if they + are spawned in From 975debf86e1907ee0156a514e8d7fe14bb3d3d82 Mon Sep 17 00:00:00 2001 From: generalthrax <139387950+generalthrax@users.noreply.github.com> Date: Wed, 25 Sep 2024 08:44:46 -0500 Subject: [PATCH 07/30] More Rust Reds (#3423) ## About The Pull Request Increases rust reds on the black market from maximum 1 to a maximum of 3 ## Why It's Good For The Game Makes them about as available as the other suits on the market. They Suck, shouldn't really matter ## Changelog :cl: balance: Rust Reds on the blackmarket are now available to a maximum of 3 /:cl: --- code/modules/cargo/blackmarket/blackmarket_items/clothing.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/cargo/blackmarket/blackmarket_items/clothing.dm b/code/modules/cargo/blackmarket/blackmarket_items/clothing.dm index d049589fe40a..7a9803085ab8 100644 --- a/code/modules/cargo/blackmarket/blackmarket_items/clothing.dm +++ b/code/modules/cargo/blackmarket/blackmarket_items/clothing.dm @@ -264,7 +264,7 @@ price_min = 1500 price_max = 2500 - stock = 1 + stock_max = 3 availability_prob = 30 /datum/blackmarket_item/clothing/frontiersmen_hardsuit From 554905548d7b5de1591d04ffeb014aca091caec9 Mon Sep 17 00:00:00 2001 From: Changelogs Date: Wed, 25 Sep 2024 08:56:47 -0500 Subject: [PATCH 08/30] Automatic changelog generation for PR #3423 [ci skip] --- html/changelogs/AutoChangeLog-pr-3423.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-3423.yml diff --git a/html/changelogs/AutoChangeLog-pr-3423.yml b/html/changelogs/AutoChangeLog-pr-3423.yml new file mode 100644 index 000000000000..21c44ad0f32e --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-3423.yml @@ -0,0 +1,4 @@ +author: generalthrax +changes: + - {balance: Rust Reds on the blackmarket are now available to a maximum of 3} +delete-after: true From f93fa2a563c40653ab0d349bc19a2506c29f6cd2 Mon Sep 17 00:00:00 2001 From: zimon9 <122945887+zimon9@users.noreply.github.com> Date: Wed, 25 Sep 2024 09:45:50 -0400 Subject: [PATCH 09/30] Makes Vegan rations actually Vegan (#3408) ## About The Pull Request Exchanges the pizza crackers snack, which is a meat foodtype, with fruit puree, in the vegan chili ration. ## Why It's Good For The Game It always felt like a really minor and silly oversight that pizza crackers weren't actually vegan, which, in turn, made the _vegan ration_ not actually entirely vegan. This isn't really a gamebreaking change, but I thought it might help with consistency. ## Changelog :cl: add: Added fruit puree to vegan rations del: Removed pizza crackers from vegan rations /:cl: --- code/game/objects/items/storage/ration.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/game/objects/items/storage/ration.dm b/code/game/objects/items/storage/ration.dm index b016cc339260..169e0dfad0a6 100644 --- a/code/game/objects/items/storage/ration.dm +++ b/code/game/objects/items/storage/ration.dm @@ -54,7 +54,7 @@ /obj/item/reagent_containers/food/snacks/ration/entree/vegan_chili = 1, /obj/item/reagent_containers/food/snacks/ration/side/vegan_crackers = 1, /obj/item/reagent_containers/food/snacks/ration/side/cornbread = 1, - /obj/item/reagent_containers/food/snacks/ration/snack/pizza_crackers = 1, + /obj/item/reagent_containers/food/snacks/ration/snack/fruit_puree = 1, /obj/item/reagent_containers/food/snacks/ration/condiment/cheese_spread = 1, /obj/item/reagent_containers/food/snacks/ration/pack/grape_beverage = 1, /obj/item/ration_heater = 1 From 053a7ba7721e7924d6698f6bc4b9879746943d82 Mon Sep 17 00:00:00 2001 From: Changelogs Date: Wed, 25 Sep 2024 09:10:35 -0500 Subject: [PATCH 10/30] Automatic changelog generation for PR #3408 [ci skip] --- html/changelogs/AutoChangeLog-pr-3408.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-3408.yml diff --git a/html/changelogs/AutoChangeLog-pr-3408.yml b/html/changelogs/AutoChangeLog-pr-3408.yml new file mode 100644 index 000000000000..f85514c5004c --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-3408.yml @@ -0,0 +1,5 @@ +author: zimon9 +changes: + - {rscadd: Added fruit puree to vegan rations} + - {rscdel: Removed pizza crackers from vegan rations} +delete-after: true From bad30456a4bfa0e495d6cdaf1ecb02c2bb1f184d Mon Sep 17 00:00:00 2001 From: Gristlebee <56049844+Gristlebee@users.noreply.github.com> Date: Wed, 25 Sep 2024 06:46:02 -0700 Subject: [PATCH 11/30] Fixes deconstructing walls causing runtimes (#3398) ## About The Pull Request Fixes the while loops so they dont do silly shit and call procs on turfs they shouldnt. ## Why It's Good For The Game Kill 9 billion runtimes. ## Changelog :cl: fix: fixes wall deconstruction causing runtimes /:cl: --- .../game/mecha/equipment/tools/mining_tools.dm | 7 +++++-- code/game/objects/items.dm | 3 +++ code/game/turfs/closed/_closed.dm | 11 ++++++++--- code/game/turfs/closed/minerals.dm | 8 ++++++-- code/game/turfs/closed/wall/reinf_walls.dm | 3 ++- code/game/turfs/closed/walls.dm | 18 +++--------------- 6 files changed, 27 insertions(+), 23 deletions(-) diff --git a/code/game/mecha/equipment/tools/mining_tools.dm b/code/game/mecha/equipment/tools/mining_tools.dm index e99d24e3f558..d330865a4be2 100644 --- a/code/game/mecha/equipment/tools/mining_tools.dm +++ b/code/game/mecha/equipment/tools/mining_tools.dm @@ -65,17 +65,20 @@ /turf/closed/wall/drill_act(obj/item/mecha_parts/mecha_equipment/drill/drill) while(drill.do_after_mecha(src, 15 / drill.drill_level)) drill.log_message("Drilled through [src]", LOG_MECHA) - alter_integrity(-drill.wall_decon_damage) drill.occupant_message("You drill through some of the outer plating...") playsound(src,'sound/weapons/drill.ogg',60,TRUE) + if(!alter_integrity(-drill.wall_decon_damage)) + return TRUE /turf/closed/wall/r_wall/drill_act(obj/item/mecha_parts/mecha_equipment/drill/drill) if(drill.drill_level >= DRILL_HARDENED) while(drill.do_after_mecha(src, 20 / drill.drill_level)) drill.log_message("Drilled through [src]", LOG_MECHA) - alter_integrity(-drill.wall_decon_damage) drill.occupant_message("You drill through some of the outer plating...") playsound(src,'sound/weapons/drill.ogg',60,TRUE) + if(!alter_integrity(-drill.wall_decon_damage)) + return TRUE + else drill.occupant_message("[src] is too durable to drill through.") diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index 17d6cf96b21a..a1302008cf89 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -957,6 +957,9 @@ GLOBAL_VAR_INIT(embedpocalypse, FALSE) // if true, all items will be able to emb /// Called when a mob tries to use the item as a tool.Handles most checks. /obj/item/proc/use_tool(atom/target, mob/living/user, delay, amount=0, volume=0, datum/callback/extra_checks) + // we have no target, why are we even doing this? + if(isnull(target)) + return // No delay means there is no start message, and no reason to call tool_start_check before use_tool. // Run the start check here so we wouldn't have to call it manually. if(!delay && !tool_start_check(user, amount)) diff --git a/code/game/turfs/closed/_closed.dm b/code/game/turfs/closed/_closed.dm index dc410d027504..766d7e0e5a24 100644 --- a/code/game/turfs/closed/_closed.dm +++ b/code/game/turfs/closed/_closed.dm @@ -227,6 +227,8 @@ return ..() /turf/closed/proc/attack_override(obj/item/W, mob/user, turf/loc) + if(!isclosedturf(src)) + return //the istype cascade has been spread among various procs for easy overriding or if we want to call something specific if(try_decon(W, user, loc) || try_destroy(W, user, loc)) return @@ -252,15 +254,18 @@ return TRUE /turf/closed/proc/try_decon(obj/item/I, mob/user, turf/T) + var/act_duration = breakdown_duration if(I.tool_behaviour == TOOL_WELDER) if(!I.tool_start_check(user, amount=0)) return FALSE - to_chat(user, "You begin slicing through the outer plating...") - while(I.use_tool(src, user, breakdown_duration, volume=50)) + while(I.use_tool(src, user, act_duration, volume=50)) if(iswallturf(src)) to_chat(user, "You slice through some of the outer plating...") - alter_integrity(-(I.wall_decon_damage),user,FALSE,TRUE) + if(!alter_integrity(-(I.wall_decon_damage),user,FALSE,TRUE)) + return TRUE + else + break return FALSE diff --git a/code/game/turfs/closed/minerals.dm b/code/game/turfs/closed/minerals.dm index 0d9b3205cc27..3970cc403d73 100644 --- a/code/game/turfs/closed/minerals.dm +++ b/code/game/turfs/closed/minerals.dm @@ -79,16 +79,20 @@ return ..() /turf/closed/mineral/try_decon(obj/item/I, mob/user, turf/T) + var/act_duration = breakdown_duration if(I.tool_behaviour == TOOL_MINING) if(!I.tool_start_check(user, amount=0)) return FALSE to_chat(user, "You begin breaking through the rock...") - while(I.use_tool(src, user, breakdown_duration, volume=50)) + while(I.use_tool(src, user, act_duration, volume=50)) if(ismineralturf(src)) to_chat(user, "You break through some of the stone...") SSblackbox.record_feedback("tally", "pick_used_mining", 1, I.type) - alter_integrity(-(I.wall_decon_damage),user,FALSE,TRUE) + if(!alter_integrity(-(I.wall_decon_damage),user,FALSE,TRUE)) + return TRUE + else + break return FALSE diff --git a/code/game/turfs/closed/wall/reinf_walls.dm b/code/game/turfs/closed/wall/reinf_walls.dm index ed2f0141eaff..c0fb9232ad28 100644 --- a/code/game/turfs/closed/wall/reinf_walls.dm +++ b/code/game/turfs/closed/wall/reinf_walls.dm @@ -78,7 +78,8 @@ to_chat(user, "You begin slicing through the [src].") while(W.use_tool(src,user,30,volume = 100)) to_chat(user, "You slice through some of the outer plating...") - alter_integrity(-(W.wall_decon_damage)) + if(!alter_integrity(-(W.wall_decon_damage))) + return TRUE return 1 switch(d_state) diff --git a/code/game/turfs/closed/walls.dm b/code/game/turfs/closed/walls.dm index bed648ff592b..1d8f242e216a 100644 --- a/code/game/turfs/closed/walls.dm +++ b/code/game/turfs/closed/walls.dm @@ -85,9 +85,10 @@ return null /turf/closed/wall/attack_override(obj/item/W, mob/user, turf/loc) - if(try_clean(W, user, loc) || try_wallmount(W, user, loc)) + if(!iswallturf(src)) + return + if(try_clean(W, user, loc) || try_wallmount(W, user, loc) || try_decon(W, user, loc) || try_destroy(W, user, loc)) return - ..() /turf/closed/wall/proc/try_clean(obj/item/W, mob/user, turf/T) if((user.a_intent != INTENT_HELP)) @@ -122,19 +123,6 @@ return FALSE -/turf/closed/wall/try_decon(obj/item/I, mob/user, turf/T) - if(I.tool_behaviour == TOOL_WELDER) - if(!I.tool_start_check(user, amount=0)) - return FALSE - - to_chat(user, "You begin slicing through the outer plating...") - while(I.use_tool(src, user, breakdown_duration, volume=50)) - if(iswallturf(src)) - to_chat(user, "You slice through some of the outer plating...") - alter_integrity(-(I.wall_decon_damage),FALSE,TRUE) - - return FALSE - /turf/closed/wall/singularity_pull(S, current_size) ..() wall_singularity_pull(current_size) From b1038979ab692d27e64fbe6905001959322672dd Mon Sep 17 00:00:00 2001 From: Changelogs Date: Wed, 25 Sep 2024 09:24:04 -0500 Subject: [PATCH 12/30] Automatic changelog generation for PR #3398 [ci skip] --- html/changelogs/AutoChangeLog-pr-3398.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-3398.yml diff --git a/html/changelogs/AutoChangeLog-pr-3398.yml b/html/changelogs/AutoChangeLog-pr-3398.yml new file mode 100644 index 000000000000..65eb77137267 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-3398.yml @@ -0,0 +1,4 @@ +author: Gristlebee +changes: + - {bugfix: fixes wall deconstruction causing runtimes} +delete-after: true From de480f809e1aabfc6590453820c5cd024f1b255e Mon Sep 17 00:00:00 2001 From: generalthrax <139387950+generalthrax@users.noreply.github.com> Date: Wed, 25 Sep 2024 08:46:49 -0500 Subject: [PATCH 13/30] Pants Accessories (#3418) ## About The Pull Request Most accessories fit on pants now ## Why It's Good For The Game I should be able to pin my captain's medal on the turtleneck I'm wearing with my black pants. ## Changelog :cl: balance: Most common accessories now fit on pants /:cl: --- code/modules/clothing/under/accessories.dm | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/code/modules/clothing/under/accessories.dm b/code/modules/clothing/under/accessories.dm index d1ee50d1a629..0d05c4e0cf7f 100644 --- a/code/modules/clothing/under/accessories.dm +++ b/code/modules/clothing/under/accessories.dm @@ -137,6 +137,7 @@ icon_state = "bronze" custom_materials = list(/datum/material/iron=1000) resistance_flags = FIRE_PROOF + attachment_slot = null var/medaltype = "medal" //Sprite used for medalbox var/commended = FALSE @@ -409,6 +410,7 @@ icon_state = "holster" item_state = "holster" pocket_storage_component_path = /datum/component/storage/concrete/pockets/holster + attachment_slot = null /obj/item/clothing/accessory/holster/detective name = "detective's shoulder holster" @@ -477,7 +479,7 @@ icon_state = "rilena_pin" above_suit = FALSE minimize_when_attached = TRUE - attachment_slot = CHEST + attachment_slot = null /obj/item/clothing/accessory/rilena_pin/on_uniform_equip(obj/item/clothing/under/U, user) var/mob/living/L = user From 9aab7f2d0df8b76a55d9f43886d655c679057325 Mon Sep 17 00:00:00 2001 From: Changelogs Date: Wed, 25 Sep 2024 09:37:14 -0500 Subject: [PATCH 14/30] Automatic changelog generation for PR #3418 [ci skip] --- html/changelogs/AutoChangeLog-pr-3418.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-3418.yml diff --git a/html/changelogs/AutoChangeLog-pr-3418.yml b/html/changelogs/AutoChangeLog-pr-3418.yml new file mode 100644 index 000000000000..b2b6703a1756 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-3418.yml @@ -0,0 +1,4 @@ +author: generalthrax +changes: + - {balance: Most common accessories now fit on pants} +delete-after: true From 4009cd5c74be78c030d042450c88e8d9f620f443 Mon Sep 17 00:00:00 2001 From: generalthrax <139387950+generalthrax@users.noreply.github.com> Date: Wed, 25 Sep 2024 08:47:03 -0500 Subject: [PATCH 15/30] Exosuit Recharger Equipment in Cargo (#3420) ## About The Pull Request Adds the exosuit recharger machine and computer boards to cargo ## Why It's Good For The Game You can't get them outside of ruins or RND and they're Way Cooler than cell-swapping ## Changelog :cl: add: Exosuit Recharger machines are now available from cargo /:cl: --- code/modules/cargo/packs/mechs.dm | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/code/modules/cargo/packs/mechs.dm b/code/modules/cargo/packs/mechs.dm index 7790e696ee15..744e9f67e2f2 100644 --- a/code/modules/cargo/packs/mechs.dm +++ b/code/modules/cargo/packs/mechs.dm @@ -220,6 +220,15 @@ Mech Equipment /obj/item/mecha_parts/mecha_equipment/antiproj_armor_booster ) +/datum/supply_pack/mech/equipment/recharger + name = "Exosuit Recharger kit" + desc = "Two boards for an exosuit recharger and recharger console. For the stylish exosuit bay." + cost = 400 + contains = list( + /obj/item/circuitboard/computer/mech_bay_power_console, + /obj/item/circuitboard/machine/mech_recharger + ) + /* weapons */ From 14a4b8c324f03571ee1a15be7696efe39c74018c Mon Sep 17 00:00:00 2001 From: Changelogs Date: Wed, 25 Sep 2024 09:50:32 -0500 Subject: [PATCH 16/30] Automatic changelog generation for PR #3420 [ci skip] --- html/changelogs/AutoChangeLog-pr-3420.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-3420.yml diff --git a/html/changelogs/AutoChangeLog-pr-3420.yml b/html/changelogs/AutoChangeLog-pr-3420.yml new file mode 100644 index 000000000000..832736e59bfd --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-3420.yml @@ -0,0 +1,4 @@ +author: generalthrax +changes: + - {rscadd: Exosuit Recharger machines are now available from cargo} +delete-after: true From af77144e59c474fea4831f0241dfb9d95c1ef2c2 Mon Sep 17 00:00:00 2001 From: generalthrax <139387950+generalthrax@users.noreply.github.com> Date: Wed, 25 Sep 2024 08:47:38 -0500 Subject: [PATCH 17/30] Adds .38 Hearth and .38 Chilled ammo boxes, to the Black Market (#3425) ## About The Pull Request Adds ammo boxes for hotshot and iceblox variants of .38 Special, and puts them in the black market. Slightly reflavoured to imply infusion of trickwines by black market elements. Sprites courtesy of @rye-rice ![stuff](https://github.com/user-attachments/assets/3c29840f-e46a-4780-ad92-091c5f5f81d1) ## Why It's Good For The Game Cute little thing to maybe make .38 attractive to some as a gimmicky cartridge ## Changelog :cl: add: Adds .38 Hearth and .38 Chilled specialty ammo boxes to the black market /:cl: --- .../blackmarket/blackmarket_items/ammo.dm | 22 ++++++++++++++++++ .../ammunition/ballistic/revolver.dm | 8 +++---- .../projectiles/boxes_magazines/ammo_boxes.dm | 20 ++++++++++++---- .../projectile/bullets/revolver.dm | 4 ++-- .../research/designs/weapon_designs.dm | 4 ++-- icons/obj/ammo.dmi | Bin 63786 -> 59485 bytes 6 files changed, 46 insertions(+), 12 deletions(-) diff --git a/code/modules/cargo/blackmarket/blackmarket_items/ammo.dm b/code/modules/cargo/blackmarket/blackmarket_items/ammo.dm index 47f7fd884993..d5489edeb3e0 100644 --- a/code/modules/cargo/blackmarket/blackmarket_items/ammo.dm +++ b/code/modules/cargo/blackmarket/blackmarket_items/ammo.dm @@ -271,3 +271,25 @@ stock_min = 2 stock_max = 10 availability_prob = 10 + +/datum/blackmarket_item/ammo/c38hotshot + name = ".38 Hearth Ammo Box" + desc = "We got our ship cook to marinade some .38 in some hearthwine we pocketed off some hunters. It'll cook your targets to a nice well done." + item = /obj/item/ammo_box/c38/hotshot + + price_min = 300 + price_max = 500 + stock_min = 3 + stock_max = 8 + availability_prob = 50 + +/datum/blackmarket_item/ammo/c38iceblox + name = ".38 Chilled Ammo Box" + desc = "One of our runners accidentally spilled some .38 into a fucking pristine icewine shipment. It'll freeze your targets faster than our runner froze solid outside for making a mess." + item = /obj/item/ammo_box/c38/iceblox + + price_min = 300 + price_max = 500 + stock_min = 3 + stock_max = 8 + availability_prob = 50 diff --git a/code/modules/projectiles/ammunition/ballistic/revolver.dm b/code/modules/projectiles/ammunition/ballistic/revolver.dm index e235e00b98f6..8705a932b392 100644 --- a/code/modules/projectiles/ammunition/ballistic/revolver.dm +++ b/code/modules/projectiles/ammunition/ballistic/revolver.dm @@ -88,14 +88,14 @@ projectile_type = /obj/projectile/bullet/c38/dumdum /obj/item/ammo_casing/c38/hotshot - name = ".38 hot shot bullet casing" - desc = "A .38 hot shot bullet casing." + name = ".38 hearth bullet casing" + desc = "A .38 hearth bullet casing." bullet_skin = "incen" projectile_type = /obj/projectile/bullet/c38/hotshot /obj/item/ammo_casing/c38/iceblox - name = ".38 iceblox bullet casing" - desc = "A .38 iceblox bullet casing." + name = ".38 chilled bullet casing" + desc = "A .38 chilled bullet casing." bullet_skin = "surplus" projectile_type = /obj/projectile/bullet/c38/iceblox diff --git a/code/modules/projectiles/boxes_magazines/ammo_boxes.dm b/code/modules/projectiles/boxes_magazines/ammo_boxes.dm index b590f0831df1..443f70c3314d 100644 --- a/code/modules/projectiles/boxes_magazines/ammo_boxes.dm +++ b/code/modules/projectiles/boxes_magazines/ammo_boxes.dm @@ -113,13 +113,13 @@ ammo_type = /obj/item/ammo_casing/c38/dumdum /obj/item/ammo_box/c38/hotshot - name = "speed loader (.38 hot shot)" - desc = "A 6-round speed loader for quickly reloading .38 special revolvers. These hot shot bullets contain an incendiary payload that set targets alight." + name = "speed loader (.38 hearth)" + desc = "A 6-round speed loader for quickly reloading .38 special revolvers. These hearthwine bullets contain an incendiary payload that set targets alight." ammo_type = /obj/item/ammo_casing/c38/hotshot /obj/item/ammo_box/c38/iceblox - name = "speed loader (.38 iceblox)" - desc = "A 6-round speed loader for quickly reloading .38 special revolvers. These iceblox bullets contain a cryogenic payload that chills targets." + name = "speed loader (.38 chilled)" + desc = "A 6-round speed loader for quickly reloading .38 special revolvers. These icewine bullets contain a cryogenic payload that chills targets." ammo_type = /obj/item/ammo_casing/c38/iceblox /obj/item/ammo_box/c38/empty @@ -213,6 +213,18 @@ icon_state = "38box-surplus" ammo_type = /obj/item/ammo_casing/c38/surplus +/obj/item/ammo_box/c38_box/hotshot + name = "ammo box (.38 hearth)" + desc = "An unorthodox .38 Special cartridge infused with hearthwine. Catches the target on fire." + icon_state = "38hotshot" + ammo_type = /obj/item/ammo_casing/c38/hotshot + +/obj/item/ammo_box/c38_box/iceblox + name = "ammo box (.38 chilled)" + desc = "An unorthodox .38 Special cartridge infused with icewine. Chills the target, slowing them down." + icon_state = "38iceblox" + ammo_type = /obj/item/ammo_casing/c38/iceblox + /obj/item/ammo_box/a12g name = "ammo box (12g buckshot)" desc = "A box of 12-gauge buckshot shells, devastating at close range." diff --git a/code/modules/projectiles/projectile/bullets/revolver.dm b/code/modules/projectiles/projectile/bullets/revolver.dm index dede2ce0d7ce..340aa692f5b2 100644 --- a/code/modules/projectiles/projectile/bullets/revolver.dm +++ b/code/modules/projectiles/projectile/bullets/revolver.dm @@ -69,7 +69,7 @@ imp.implant(M) /obj/projectile/bullet/c38/hotshot //similar to incendiary bullets, but do not leave a flaming trail - name = ".38 hot shot bullet" + name = ".38 hearth bullet" ricochets_max = 0 /obj/projectile/bullet/c38/hotshot/on_hit(atom/target, blocked = FALSE) @@ -80,7 +80,7 @@ M.IgniteMob() /obj/projectile/bullet/c38/iceblox //see /obj/projectile/temp for the original code - name = ".38 iceblox bullet" + name = ".38 chilled bullet" var/temperature = 100 ricochets_max = 0 diff --git a/code/modules/research/designs/weapon_designs.dm b/code/modules/research/designs/weapon_designs.dm index 2a8f390e9e36..1c3edc8b7c32 100644 --- a/code/modules/research/designs/weapon_designs.dm +++ b/code/modules/research/designs/weapon_designs.dm @@ -18,7 +18,7 @@ departmental_flags = DEPARTMENTAL_FLAG_SECURITY | DEPARTMENTAL_FLAG_BALLISTICS /datum/design/c38_hotshot - name = "Speed Loader (.38 Hot Shot)" + name = "Speed Loader (.38 Hearth)" desc = "Designed to quickly reload revolvers. Hot Shot bullets contain an incendiary payload." id = "c38_hotshot" build_type = PROTOLATHE @@ -28,7 +28,7 @@ departmental_flags = DEPARTMENTAL_FLAG_SECURITY | DEPARTMENTAL_FLAG_BALLISTICS /datum/design/c38_iceblox - name = "Speed Loader (.38 Iceblox)" + name = "Speed Loader (.38 Chilled)" desc = "Designed to quickly reload revolvers. Iceblox bullets contain a cryogenic payload." id = "c38_iceblox" build_type = PROTOLATHE diff --git a/icons/obj/ammo.dmi b/icons/obj/ammo.dmi index 403b198c179bcfddd76bc5ec6100a098244fa217..ec5f147485401833d8ad24fb12c0cf6a26dc9a09 100644 GIT binary patch literal 59485 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�|5v&&(+6#QTH|7xXxCio~B9FI+ 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

)AGle|iV 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 From 7e9752abf56562c3608ba6598528820f1e9f8fc0 Mon Sep 17 00:00:00 2001 From: FalloutFalcon <86381784+FalloutFalcon@users.noreply.github.com> Date: Wed, 25 Sep 2024 08:51:41 -0500 Subject: [PATCH 18/30] minimum recoil for ballistics (#3330) ## About The Pull Request gives a very small kick to all ballistics, not enough to affect your aim but makes them feel alot better to use. atomization of #3094 currently debating what the value should be.. 0 https://github.com/user-attachments/assets/1630a089-bf9f-4ec5-8853-c2728f420f4e .1 https://github.com/user-attachments/assets/2064b49b-37f5-4860-b273-1f28274724f7 .175 https://github.com/user-attachments/assets/6baba2ad-8100-403e-b6c4-d4e958ad21d6 .25 https://github.com/user-attachments/assets/ca3bdf37-bf30-493e-bb24-ae452cbc6481 a bit of an extreme case being a fast firing auto but it happens to be a gun with a recoil of 0 rn so it will be affected by the change ## Why It's Good For The Game without it, a surprising amount of ballistics get 0 recoil just but wielding them which feels really jarring. ## Changelog :cl: add: Ballistics now have a minimum recoil, not enough to mess up your shot! /:cl: --- code/modules/projectiles/gun.dm | 11 +++++++---- code/modules/projectiles/guns/ballistic.dm | 2 ++ 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm index b59a1530a209..28ef8cecdd80 100644 --- a/code/modules/projectiles/gun.dm +++ b/code/modules/projectiles/gun.dm @@ -207,6 +207,12 @@ ///this is how much deviation the gun recoil can have, recoil pushes the screen towards the reverse angle you shot + some deviation which this is the max. var/recoil_deviation = 22.5 + ///Used if the guns recoil is lower then the min, it clamps the highest recoil + var/min_recoil = 0 + + var/gunslinger_recoil_bonus = 0 + var/gunslinger_spread_bonus = 0 + /// how many shots per burst, Ex: most machine pistols, M90, some ARs are 3rnd burst, while others like the GAR and laser minigun are 2 round burst. var/burst_size = 3 ///The rate of fire when firing in a burst. Not the delay between bursts @@ -318,9 +324,6 @@ ///This prevents gun from firing until the coodown is done, affected by lag var/current_cooldown = 0 - var/gunslinger_recoil_bonus = 0 - var/gunslinger_spread_bonus = 0 - /obj/item/gun/Initialize() . = ..() RegisterSignal(src, COMSIG_TWOHANDED_WIELD, PROC_REF(on_wield)) @@ -815,7 +818,7 @@ /obj/item/gun/proc/calculate_recoil(mob/user, recoil_bonus = 0) if(HAS_TRAIT(user, TRAIT_GUNSLINGER)) recoil_bonus += gunslinger_recoil_bonus - return clamp(recoil_bonus, 0 , INFINITY) + return clamp(recoil_bonus, min_recoil , INFINITY) /obj/item/gun/proc/calculate_spread(mob/user, bonus_spread) var/final_spread = 0 diff --git a/code/modules/projectiles/guns/ballistic.dm b/code/modules/projectiles/guns/ballistic.dm index 0288813fd089..00f48cc29239 100644 --- a/code/modules/projectiles/guns/ballistic.dm +++ b/code/modules/projectiles/guns/ballistic.dm @@ -13,6 +13,8 @@ has_safety = TRUE safety = TRUE + min_recoil = 0.1 + valid_attachments = list( /obj/item/attachment/silencer, /obj/item/attachment/laser_sight, From 12f73cbb6e621e3891d853f4bdd3f28591bae609 Mon Sep 17 00:00:00 2001 From: Changelogs Date: Wed, 25 Sep 2024 10:18:15 -0500 Subject: [PATCH 19/30] Automatic changelog generation for PR #3330 [ci skip] --- html/changelogs/AutoChangeLog-pr-3330.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-3330.yml diff --git a/html/changelogs/AutoChangeLog-pr-3330.yml b/html/changelogs/AutoChangeLog-pr-3330.yml new file mode 100644 index 000000000000..46e461f2f53f --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-3330.yml @@ -0,0 +1,4 @@ +author: FalloutFalcon +changes: + - {rscadd: 'Ballistics now have a minimum recoil, not enough to mess up your shot!'} +delete-after: true From 06cc8b612d18ca841cb03140a7d816d14481bf43 Mon Sep 17 00:00:00 2001 From: FalloutFalcon <86381784+FalloutFalcon@users.noreply.github.com> Date: Wed, 25 Sep 2024 08:52:11 -0500 Subject: [PATCH 20/30] Ship joining starts on locked (#3346) ## About The Pull Request Ship's start on locked instead of open Idea from #772 ## Why It's Good For The Game No longer can an assistant join your ship faster then you can, rejoice in time to write your memo and change your ships name. ## Changelog :cl: fix: ships now start closed. shiptesters be writing there memos and ship names. /:cl: --- code/modules/overmap/ships/controlled_ship_datum.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/overmap/ships/controlled_ship_datum.dm b/code/modules/overmap/ships/controlled_ship_datum.dm index 5d851e52f4fd..efa4e36026c0 100644 --- a/code/modules/overmap/ships/controlled_ship_datum.dm +++ b/code/modules/overmap/ships/controlled_ship_datum.dm @@ -56,7 +56,7 @@ var/owner_check_timer_id /// The ship's join mode. Controls whether players can join freely, have to apply, or can't join at all. - var/join_mode = SHIP_JOIN_MODE_OPEN + var/join_mode = SHIP_JOIN_MODE_CLOSED /// Lazylist of /datum/ship_applications for this ship. Only used if join_mode == SHIP_JOIN_MODE_APPLY var/list/datum/ship_application/applications From 8839b3e262ea10ec415f2680140d805f71be5e32 Mon Sep 17 00:00:00 2001 From: Changelogs Date: Wed, 25 Sep 2024 10:31:47 -0500 Subject: [PATCH 21/30] Automatic changelog generation for PR #3346 [ci skip] --- html/changelogs/AutoChangeLog-pr-3346.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-3346.yml diff --git a/html/changelogs/AutoChangeLog-pr-3346.yml b/html/changelogs/AutoChangeLog-pr-3346.yml new file mode 100644 index 000000000000..46be6f8474b6 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-3346.yml @@ -0,0 +1,4 @@ +author: FalloutFalcon +changes: + - {bugfix: ships now start closed. shiptesters be writing there memos and ship names.} +delete-after: true From 065b41dc33b4682678261952b4686c403b800552 Mon Sep 17 00:00:00 2001 From: FalloutFalcon <86381784+FalloutFalcon@users.noreply.github.com> Date: Wed, 25 Sep 2024 08:52:29 -0500 Subject: [PATCH 22/30] blank ammo (#3352) ## About The Pull Request pending sprites! ## Why It's Good For The Game ## Changelog :cl: add: Added new blank shells for training drills! refactor: Minor refactor of design disks to reduce repeated code /:cl: --- code/modules/cargo/packs/ammo.dm | 12 +++ .../mining/lavaland/necropolis_chests.dm | 28 ------- .../ammunition/ballistic/shotgun.dm | 7 ++ .../projectiles/boxes_magazines/ammo_boxes.dm | 6 ++ .../projectiles/projectile/bullets/shotgun.dm | 6 ++ code/modules/research/designs.dm | 78 ++++++++++++------ .../research/designs/autolathe_designs.dm | 8 ++ .../ruins/spaceruin_code/bigderelict1.dm | 10 --- icons/obj/ammo_shotshells.dmi | Bin 1296 -> 3149 bytes 9 files changed, 93 insertions(+), 62 deletions(-) diff --git a/code/modules/cargo/packs/ammo.dm b/code/modules/cargo/packs/ammo.dm index 6fa0b54966c1..a7ab407b428e 100644 --- a/code/modules/cargo/packs/ammo.dm +++ b/code/modules/cargo/packs/ammo.dm @@ -72,6 +72,18 @@ cost = 500 contains = list(/obj/item/ammo_box/a12g/slug) +/datum/supply_pack/ammo/blank_shells + name = "Blank Shell Crate" + desc = "Contains a box of blank shells." + cost = 500 + contains = list(/obj/item/ammo_box/a12g/blanks) + +/datum/supply_pack/ammo/blank_ammo_disk + name = "Blank Ammo Design Disk Crate" + desc = "Run your own training drills!" + cost = 1000 + contains = list(/obj/item/disk/design_disk/blanks) + /datum/supply_pack/ammo/techshells name = "Unloaded Shotgun Technological Shells Crate" desc = "Contains a box of 7 versatile tech shells, capable of producing a variety of deadly effects for any situation. Some assembly required." diff --git a/code/modules/mining/lavaland/necropolis_chests.dm b/code/modules/mining/lavaland/necropolis_chests.dm index afae0dd0a6c0..e3e9f6aac8f0 100644 --- a/code/modules/mining/lavaland/necropolis_chests.dm +++ b/code/modules/mining/lavaland/necropolis_chests.dm @@ -150,34 +150,6 @@ if(28) new /obj/item/clothing/suit/armor/ascetic(src) -//KA modkit design discs -/obj/item/disk/design_disk/modkit_disc - name = "KA Mod Disk" - desc = "A design disc containing the design for a unique kinetic accelerator modkit. It's compatible with a research console." - illustration = "accel" - color = "#6F6F6F" - var/modkit_design = /datum/design/unique_modkit - -/obj/item/disk/design_disk/modkit_disc/Initialize() - . = ..() - blueprints[1] = new modkit_design - -/obj/item/disk/design_disk/modkit_disc/mob_and_turf_aoe - name = "Offensive Mining Explosion Mod Disk" - modkit_design = /datum/design/unique_modkit/offensive_turf_aoe - -/obj/item/disk/design_disk/modkit_disc/rapid_repeater - name = "Rapid Repeater Mod Disk" - modkit_design = /datum/design/unique_modkit/rapid_repeater - -/obj/item/disk/design_disk/modkit_disc/resonator_blast - name = "Resonator Blast Mod Disk" - modkit_design = /datum/design/unique_modkit/resonator_blast - -/obj/item/disk/design_disk/modkit_disc/bounty - name = "Death Syphon Mod Disk" - modkit_design = /datum/design/unique_modkit/bounty - /datum/design/unique_modkit category = list("Mining Designs", "Cyborg Upgrade Modules") //can't be normally obtained build_type = PROTOLATHE | MECHFAB diff --git a/code/modules/projectiles/ammunition/ballistic/shotgun.dm b/code/modules/projectiles/ammunition/ballistic/shotgun.dm index 9f6a8c169ecd..24854030c041 100644 --- a/code/modules/projectiles/ammunition/ballistic/shotgun.dm +++ b/code/modules/projectiles/ammunition/ballistic/shotgun.dm @@ -46,6 +46,13 @@ icon_state = "incendiary" projectile_type = /obj/projectile/bullet/incendiary/shotgun +/obj/item/ammo_casing/shotgun/blank + name = "blank shell" + desc = "A shell packed with powder but no projectile." + icon_state = "blank" + projectile_type = /obj/projectile/bullet/pellet/blank + custom_materials = list(/datum/material/iron=250) + /obj/item/ammo_casing/shotgun/improvised name = "improvised shell" desc = "An extremely weak shotgun shell with multiple small pellets made out of metal shards." diff --git a/code/modules/projectiles/boxes_magazines/ammo_boxes.dm b/code/modules/projectiles/boxes_magazines/ammo_boxes.dm index 443f70c3314d..5b78f1fc93a1 100644 --- a/code/modules/projectiles/boxes_magazines/ammo_boxes.dm +++ b/code/modules/projectiles/boxes_magazines/ammo_boxes.dm @@ -250,6 +250,12 @@ icon_state = "12gbox-rubbershot" ammo_type = /obj/item/ammo_casing/shotgun/rubbershot +/obj/item/ammo_box/a12g/blanks + name = "ammo box (12g blanks)" + desc = "A box of 12-gauge blank shells, designed for training." + icon_state ="12gbox-slug" + ammo_type = /obj/item/ammo_casing/shotgun/blank + /obj/item/ammo_box/c9mm name = "ammo box (9mm)" desc = "A box of standard 9mm ammo." diff --git a/code/modules/projectiles/projectile/bullets/shotgun.dm b/code/modules/projectiles/projectile/bullets/shotgun.dm index ba9c8c88d7f8..a069102a39cc 100644 --- a/code/modules/projectiles/projectile/bullets/shotgun.dm +++ b/code/modules/projectiles/projectile/bullets/shotgun.dm @@ -114,3 +114,9 @@ damage = 30 armour_penetration = -25 tile_dropoff = 3 + +/obj/projectile/bullet/pellet/blank + name = "blank" + damage = 30 + range = 2 + armour_penetration = -70 diff --git a/code/modules/research/designs.dm b/code/modules/research/designs.dm index 79b28ccef331..340119a4e78a 100644 --- a/code/modules/research/designs.dm +++ b/code/modules/research/designs.dm @@ -97,18 +97,25 @@ other types of metals and chemistry for reagents). color = "#8b70ff" illustration = "design" custom_materials = list(/datum/material/iron =300, /datum/material/glass =100) + var/disk_name = "Design Disk" + var/design_name var/list/blueprints = list() - var/list/starting_blueprints = list() + var/starting_blueprints = list() var/max_blueprints = 1 /obj/item/disk/design_disk/Initialize() . = ..() pixel_x = base_pixel_x + rand(-5, 5) pixel_y = base_pixel_y + rand(-5, 5) - blueprints = new/list(max_blueprints) + if(design_name) + name = jointext(list(disk_name, design_name), " - ") + if(length(starting_blueprints)) + for(var/design in starting_blueprints) + blueprints += new design() /obj/item/disk/design_disk/adv name = "Advanced Component Design Disk" + disk_name = "Advanced Design Disk" color = "#bed876" desc = "A disk for storing device design data for construction in lathes. This one has a little bit of extra storage space." custom_materials = list(/datum/material/iron =300, /datum/material/glass = 100, /datum/material/silver = 50) @@ -116,6 +123,7 @@ other types of metals and chemistry for reagents). /obj/item/disk/design_disk/super name = "Super Component Design Disk" + disk_name = "Super Design Disk" color = "#c25454" desc = "A disk for storing device design data for construction in lathes. This one has more extra storage space." custom_materials = list(/datum/material/iron =300, /datum/material/glass = 100, /datum/material/silver = 50, /datum/material/gold = 50) @@ -123,6 +131,7 @@ other types of metals and chemistry for reagents). /obj/item/disk/design_disk/elite name = "Elite Component Design Disk" + disk_name = "Elite Design Disk" color = "#333333" desc = "A disk for storing device design data for construction in lathes. This one has absurd amounts of extra storage space." custom_materials = list(/datum/material/iron =300, /datum/material/glass = 100, /datum/material/silver = 100, /datum/material/gold = 100, /datum/material/bluespace = 50) @@ -130,39 +139,60 @@ other types of metals and chemistry for reagents). //Disks with content /obj/item/disk/design_disk/ammo_c10mm - name = "Design Disk - 10mm Ammo" + design_name = "10mm Ammo" desc = "A design disk containing the pattern for a refill box of standard 10mm ammo, used in Stechkin pistols." - -/obj/item/disk/design_disk/ammo_c10mm/Initialize() - . = ..() - blueprints[1] = new /datum/design/c10mm() - + starting_blueprints = (/datum/design/c10mm) /obj/item/disk/design_disk/disposable_gun - name = "design disk - disposable gun" + design_name = "Disposable gun" desc = "A design disk containing designs for a cheap and disposable gun." illustration = "gun" max_blueprints = 2 - -/obj/item/disk/design_disk/disposable_gun/Initialize() - . = ..() - blueprints[1] = new /datum/design/disposable_gun() + starting_blueprints = list(/datum/design/disposable_gun) /obj/item/disk/design_disk/clip_mechs - name = "design disk - CLIP exosuit modifications" + design_name = "CLIP exosuit modifications" desc = "A design disk containing specifications for CLIP-custom exosuit conversions." color = "#57b8f0" max_blueprints = 2 - -/obj/item/disk/design_disk/clip_mechs/Initialize() - . = ..() - blueprints[1] = new /datum/design/clip_ripley_upgrade() - blueprints[2] = new /datum/design/clip_durand_upgrade() + starting_blueprints = list(/datum/design/clip_ripley_upgrade, /datum/design/clip_durand_upgrade) /obj/item/disk/design_disk/ammo_c9mm - name = "Design Disk - 9mm Ammo" + design_name = "9mm Ammo" desc = "A design disk containing the pattern for a refill box of standard 9mm ammo, used in Commander pistols." - -/obj/item/disk/design_disk/ammo_c9mm/Initialize() - . = ..() - blueprints[1] = new /datum/design/c9mmautolathe() + starting_blueprints = list(/datum/design/c9mmautolathe) + +/obj/item/disk/design_disk/blanks + design_name = "Blank Ammo" + starting_blueprints = list(/datum/design/blank_shell) + + +/obj/item/disk/design_disk/ammo_1911 + design_name = "1911 Magazine" + desc = "A design disk containing the pattern for the classic 1911's seven round .45ACP magazine." + illustration = "ammo" + starting_blueprints = list(/datum/design/colt_1911_magazine) + +//KA modkit design discs +/obj/item/disk/design_disk/modkit_disc + design_name = "KA Mod" + desc = "A design disc containing the design for a unique kinetic accelerator modkit. It's compatible with a research console." + illustration = "accel" + color = "#6F6F6F" + starting_blueprints = list(/datum/design/unique_modkit) + +/obj/item/disk/design_disk/modkit_disc/mob_and_turf_aoe + design_name = "Offensive Mining Explosion Mod" + starting_blueprints = list(/datum/design/unique_modkit/offensive_turf_aoe) + +/obj/item/disk/design_disk/modkit_disc/rapid_repeater + design_name = "Rapid Repeater Mod" + starting_blueprints = list(/datum/design/unique_modkit/rapid_repeater) + +/obj/item/disk/design_disk/modkit_disc/resonator_blast + design_name = "Resonator Blast Mod" + starting_blueprints = list(/datum/design/unique_modkit/resonator_blast) + +/obj/item/disk/design_disk/modkit_disc/bounty + design_name = "Death Syphon Mod" + starting_blueprints = list(/datum/design/unique_modkit/bounty) diff --git a/code/modules/research/designs/autolathe_designs.dm b/code/modules/research/designs/autolathe_designs.dm index d1fe33024919..0b679dfcc4bf 100644 --- a/code/modules/research/designs/autolathe_designs.dm +++ b/code/modules/research/designs/autolathe_designs.dm @@ -796,6 +796,14 @@ build_path = /obj/item/ammo_casing/shotgun/beanbag category = list("initial", "Security", "Ammo") +/datum/design/blank_shell + name = "Shotgun Blank" + id = "blank_shell" + build_type = AUTOLATHE | PROTOLATHE + materials = list(/datum/material/iron = 2000) + build_path = /obj/item/ammo_casing/shotgun/blank + category = list("Security", "Ammo") + /datum/design/riot_dart name = "Foam Riot Dart" id = "riot_dart" diff --git a/code/modules/ruins/spaceruin_code/bigderelict1.dm b/code/modules/ruins/spaceruin_code/bigderelict1.dm index 99af3b9efa28..9e2a0957547b 100644 --- a/code/modules/ruins/spaceruin_code/bigderelict1.dm +++ b/code/modules/ruins/spaceruin_code/bigderelict1.dm @@ -6,13 +6,3 @@ /obj/item/paper/crumpled/ruins/bigderelict1/coward icon_state = "scrap_bloodied" default_raw_text = "If anyone finds this, please, don't let my kids know I died a coward.." - -/obj/item/disk/design_disk/ammo_1911 - name = "design disk - 1911 magazine" - desc = "A design disk containing the pattern for the classic 1911's seven round .45ACP magazine." - illustration = "ammo" - -/obj/item/disk/design_disk/ammo_1911/Initialize() - . = ..() - var/datum/design/colt_1911_magazine/M = new - blueprints[1] = M diff --git a/icons/obj/ammo_shotshells.dmi b/icons/obj/ammo_shotshells.dmi index fe37023686bdb306d3b9d05aceb053a4352be841..55b00cdd0b21797c4f752dd63dc42530a6d6b336 100644 GIT binary patch literal 3149 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 From 833285300c5ad5867789ab46d5cc2f65ba485602 Mon Sep 17 00:00:00 2001 From: Changelogs Date: Wed, 25 Sep 2024 10:44:41 -0500 Subject: [PATCH 23/30] Automatic changelog generation for PR #3352 [ci skip] --- html/changelogs/AutoChangeLog-pr-3352.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-3352.yml diff --git a/html/changelogs/AutoChangeLog-pr-3352.yml b/html/changelogs/AutoChangeLog-pr-3352.yml new file mode 100644 index 000000000000..266106d74f64 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-3352.yml @@ -0,0 +1,5 @@ +author: FalloutFalcon +changes: + - {rscadd: Added new blank shells for training drills!} + - {refactor: Minor refactor of design disks to reduce repeated code} +delete-after: true From eb41937929ecefa9ea723a2d129ee9b208fa9183 Mon Sep 17 00:00:00 2001 From: FalloutFalcon <86381784+FalloutFalcon@users.noreply.github.com> Date: Wed, 25 Sep 2024 08:58:42 -0500 Subject: [PATCH 24/30] Partial port of tg points of intrest and improved orbit menu (#3320) ## About The Pull Request Squash of #3219 rebased ontop of a revert of #3218 cause i fucked up the commit history - [x] Fix admin menu - [x] Fix auto-observe ## Why It's Good For The Game This massively improves the readability of the orbit menu. You can now add custom points of interest pretty easily as it uses an element now. ## Changelog :cl: add: You can now see ships in the orbit menu and its alot prettier! code: ported tg points of interest and a much improved orbit menu /:cl: --------- Signed-off-by: FalloutFalcon <86381784+FalloutFalcon@users.noreply.github.com> --- _maps/map_files/generic/CentCom.dmm | 12 +- code/__DEFINES/dcs/signals/signals.dm | 6 + code/__HELPERS/_lists.dm | 36 +++ code/__HELPERS/roundend.dm | 2 +- code/__HELPERS/unsorted.dm | 61 +--- code/_globalvars/lists/objects.dm | 2 - .../subsystem/points_of_interest.dm | 227 +++++++++++++++ code/datums/elements/point_of_interest.dm | 22 ++ code/datums/spawners_menu.dm | 2 +- code/game/atom/atom_orbit.dm | 33 +++ code/game/atoms.dm | 5 - code/game/gamemodes/wizard/wizard.dm | 2 +- code/game/mecha/mecha.dm | 4 +- code/game/objects/items/eightball.dm | 4 +- code/modules/admin/player_panel.dm | 12 +- code/modules/admin/verbs/adminjump.dm | 2 +- code/modules/antagonists/cult/runes.dm | 6 +- .../nukeop/equipment/nuclearbomb.dm | 8 +- .../nukeop/equipment/pinpointer.dm | 2 +- code/modules/antagonists/nukeop/nukeop.dm | 2 +- code/modules/awaymissions/capture_the_flag.dm | 4 +- code/modules/awaymissions/corpse.dm | 4 +- code/modules/cargo/centcom_podlauncher.dm | 2 +- code/modules/events/immovable_rod.dm | 4 +- code/modules/events/wizard/greentext.dm | 4 +- .../modules/mob/dead/new_player/new_player.dm | 1 + code/modules/mob/dead/observer/observer.dm | 21 +- code/modules/mob/dead/observer/orbit.dm | 271 ++++++++++++++---- code/modules/mob/living/living.dm | 1 + .../friendly/drone/drones_as_items.dm | 5 - .../hostile/megafauna/colossus.dm | 4 +- code/modules/mob/mob.dm | 2 +- .../file_system/programs/radar.dm | 6 +- code/modules/overmap/helm.dm | 3 + code/modules/power/singularity/singularity.dm | 4 +- code/modules/power/supermatter/supermatter.dm | 4 +- code/modules/power/tesla/energy_ball.dm | 2 +- code/modules/projectiles/guns/energy/pulse.dm | 4 +- code/modules/spells/spell_types/lichdom.dm | 4 +- shiptest.dme | 3 + tgui/packages/tgui/interfaces/Orbit.js | 218 -------------- .../tgui/interfaces/Orbit/OrbitContent.tsx | 98 +++++++ .../tgui/interfaces/Orbit/OrbitItem.tsx | 50 ++++ .../tgui/interfaces/Orbit/OrbitSection.tsx | 65 +++++ .../tgui/interfaces/Orbit/OrbitTooltip.tsx | 57 ++++ .../tgui/interfaces/Orbit/constants.ts | 8 + .../packages/tgui/interfaces/Orbit/helpers.ts | 119 ++++++++ tgui/packages/tgui/interfaces/Orbit/index.tsx | 86 ++++++ tgui/packages/tgui/interfaces/Orbit/types.ts | 38 +++ 49 files changed, 1135 insertions(+), 407 deletions(-) create mode 100644 code/controllers/subsystem/points_of_interest.dm create mode 100644 code/datums/elements/point_of_interest.dm create mode 100644 code/game/atom/atom_orbit.dm delete mode 100644 tgui/packages/tgui/interfaces/Orbit.js create mode 100644 tgui/packages/tgui/interfaces/Orbit/OrbitContent.tsx create mode 100644 tgui/packages/tgui/interfaces/Orbit/OrbitItem.tsx create mode 100644 tgui/packages/tgui/interfaces/Orbit/OrbitSection.tsx create mode 100644 tgui/packages/tgui/interfaces/Orbit/OrbitTooltip.tsx create mode 100644 tgui/packages/tgui/interfaces/Orbit/constants.ts create mode 100644 tgui/packages/tgui/interfaces/Orbit/helpers.ts create mode 100644 tgui/packages/tgui/interfaces/Orbit/index.tsx create mode 100644 tgui/packages/tgui/interfaces/Orbit/types.ts diff --git a/_maps/map_files/generic/CentCom.dmm b/_maps/map_files/generic/CentCom.dmm index e25bceb1dd44..405950bfe633 100644 --- a/_maps/map_files/generic/CentCom.dmm +++ b/_maps/map_files/generic/CentCom.dmm @@ -26,7 +26,7 @@ /turf/open/floor/plasteel/dark, /area/tdome/tdomeadmin) "afh" = ( -/obj/machinery/computer/helm{ +/obj/machinery/computer{ dir = 4 }, /obj/effect/turf_decal/industrial/warning{ @@ -1356,7 +1356,7 @@ /turf/open/floor/plasteel, /area/wizard_station) "ara" = ( -/obj/machinery/computer/helm, +/obj/machinery/computer, /turf/open/floor/plasteel, /area/wizard_station) "ard" = ( @@ -3939,7 +3939,7 @@ /turf/open/floor/mineral/titanium/blue, /area/centcom/evac) "aLP" = ( -/obj/machinery/computer/helm{ +/obj/machinery/computer{ dir = 1 }, /turf/open/floor/mineral/titanium/blue, @@ -8827,7 +8827,7 @@ }, /area/centcom) "gFU" = ( -/obj/machinery/computer/helm, +/obj/machinery/computer, /obj/effect/turf_decal/industrial/warning{ dir = 6 }, @@ -12230,7 +12230,7 @@ /turf/open/floor/plasteel/dark, /area/tdome/tdomeadmin) "nEL" = ( -/obj/machinery/computer/helm, +/obj/machinery/computer, /obj/effect/turf_decal/industrial/warning{ dir = 10 }, @@ -15778,7 +15778,7 @@ /turf/open/floor/plasteel/dark, /area/ctf) "vcL" = ( -/obj/machinery/computer/helm, +/obj/machinery/computer, /obj/effect/turf_decal/corner/transparent/bar, /obj/effect/turf_decal/corner/transparent/bar{ dir = 1 diff --git a/code/__DEFINES/dcs/signals/signals.dm b/code/__DEFINES/dcs/signals/signals.dm index 38f7d8692853..f3295b737904 100644 --- a/code/__DEFINES/dcs/signals/signals.dm +++ b/code/__DEFINES/dcs/signals/signals.dm @@ -735,3 +735,9 @@ ///sent when the access on an id is changed/updated, ensures wallets get updated once ids generate there access #define COSMIG_ACCESS_UPDATED "acces_updated" + +// Point of interest signals +/// Sent from base of /datum/controller/subsystem/points_of_interest/proc/on_poi_element_added : (atom/new_poi) +#define COMSIG_ADDED_POINT_OF_INTEREST "added_point_of_interest" +/// Sent from base of /datum/controller/subsystem/points_of_interest/proc/on_poi_element_removed : (atom/old_poi) +#define COMSIG_REMOVED_POINT_OF_INTEREST "removed_point_of_interest" diff --git a/code/__HELPERS/_lists.dm b/code/__HELPERS/_lists.dm index 435b83e29797..b231b4e944c9 100644 --- a/code/__HELPERS/_lists.dm +++ b/code/__HELPERS/_lists.dm @@ -87,6 +87,42 @@ };\ } while(FALSE) + +/** + * Custom binary search sorted insert utilising comparison procs instead of vars. + * INPUT: Object to be inserted + * LIST: List to insert object into + * TYPECONT: The typepath of the contents of the list + * COMPARE: The object to compare against, usualy the same as INPUT + * COMPARISON: The plaintext name of a proc on INPUT that takes a single argument to accept a single element from LIST and returns a positive, negative or zero number to perform a comparison. + * COMPTYPE: How should the values be compared? Either COMPARE_KEY or COMPARE_VALUE. + */ +#define BINARY_INSERT_PROC_COMPARE(INPUT, LIST, TYPECONT, COMPARE, COMPARISON, COMPTYPE) \ + do {\ + var/list/__BIN_LIST = LIST;\ + var/__BIN_CTTL = length(__BIN_LIST);\ + if(!__BIN_CTTL) {\ + __BIN_LIST += INPUT;\ + } else {\ + var/__BIN_LEFT = 1;\ + var/__BIN_RIGHT = __BIN_CTTL;\ + var/__BIN_MID = (__BIN_LEFT + __BIN_RIGHT) >> 1;\ + var ##TYPECONT/__BIN_ITEM;\ + while(__BIN_LEFT < __BIN_RIGHT) {\ + __BIN_ITEM = COMPTYPE;\ + if(__BIN_ITEM.##COMPARISON(COMPARE) <= 0) {\ + __BIN_LEFT = __BIN_MID + 1;\ + } else {\ + __BIN_RIGHT = __BIN_MID;\ + };\ + __BIN_MID = (__BIN_LEFT + __BIN_RIGHT) >> 1;\ + };\ + __BIN_ITEM = COMPTYPE;\ + __BIN_MID = __BIN_ITEM.##COMPARISON(COMPARE) > 0 ? __BIN_MID : __BIN_MID + 1;\ + __BIN_LIST.Insert(__BIN_MID, INPUT);\ + };\ + } while(FALSE) + //Returns a list in plain english as a string /proc/english_list(list/input, nothing_text = "nothing", and_text = " and ", comma_text = ", ", final_comma_text = "" ) var/total = length(input) diff --git a/code/__HELPERS/roundend.dm b/code/__HELPERS/roundend.dm index 97740a79537e..01fd964120ea 100644 --- a/code/__HELPERS/roundend.dm +++ b/code/__HELPERS/roundend.dm @@ -116,7 +116,7 @@ SSblackbox.record_feedback("associative", "antagonists", 1, antag_info) /datum/controller/subsystem/ticker/proc/record_nuke_disk_location() - var/obj/item/disk/nuclear/N = locate() in GLOB.poi_list + var/obj/item/disk/nuclear/N = locate() in SSpoints_of_interest.other_points_of_interest if(N) var/list/data = list() var/turf/T = get_turf(N) diff --git a/code/__HELPERS/unsorted.dm b/code/__HELPERS/unsorted.dm index 36764c6bae9f..d831296dbb62 100644 --- a/code/__HELPERS/unsorted.dm +++ b/code/__HELPERS/unsorted.dm @@ -294,65 +294,6 @@ Turf and target are separate in case you want to teleport some distance from a t /proc/ionnum() return "[pick("!","@","#","$","%","^","&")][pick("!","@","#","$","%","^","&","*")][pick("!","@","#","$","%","^","&","*")][pick("!","@","#","$","%","^","&","*")]" -//Returns a list of all items of interest with their name -/proc/getpois(mobs_only = FALSE, skip_mindless = FALSE, specify_dead_role = TRUE) - var/list/mobs = sortmobs() - var/list/namecounts = list() - var/list/pois = list() - for(var/mob/M in mobs) - if(skip_mindless && (!M.mind && !M.ckey)) - if(!isbot(M) && !iscameramob(M) && !ismegafauna(M)) - continue - if(M.client && M.client.holder && M.client.holder.fakekey) //stealthmins - continue - var/name = avoid_assoc_duplicate_keys(M.name, namecounts) + M.get_realname_string() - - if(M.stat == DEAD && specify_dead_role) - if(isobserver(M)) - name += " \[ghost\]" - else - name += " \[dead\]" - pois[name] = M - - if(!mobs_only) - for(var/atom/A in GLOB.poi_list) - if(!A || !A.loc) - continue - pois[avoid_assoc_duplicate_keys(A.name, namecounts)] = A - - return pois -//Orders mobs by type then by name -/proc/sortmobs() - var/list/moblist = list() - var/list/sortmob = sortNames(GLOB.mob_list) - for(var/mob/living/silicon/ai/M in sortmob) - moblist.Add(M) - for(var/mob/camera/M in sortmob) - moblist.Add(M) - for(var/mob/living/silicon/pai/M in sortmob) - moblist.Add(M) - for(var/mob/living/silicon/robot/M in sortmob) - moblist.Add(M) - for(var/mob/living/carbon/human/M in sortmob) - moblist.Add(M) - for(var/mob/living/brain/M in sortmob) - moblist.Add(M) - for(var/mob/living/carbon/alien/M in sortmob) - moblist.Add(M) - for(var/mob/dead/observer/M in sortmob) - moblist.Add(M) - for(var/mob/dead/new_player/M in sortmob) - moblist.Add(M) - for(var/mob/living/carbon/monkey/M in sortmob) - moblist.Add(M) - for(var/mob/living/simple_animal/slime/M in sortmob) - moblist.Add(M) - for(var/mob/living/simple_animal/M in sortmob) - moblist.Add(M) - for(var/mob/living/carbon/true_devil/M in sortmob) - moblist.Add(M) - return moblist - // Format a power value in W, kW, MW, or GW. /proc/DisplayPower(powerused) if(powerused < 1000) //Less than a kW @@ -384,7 +325,7 @@ Turf and target are separate in case you want to teleport some distance from a t /proc/get_mob_by_ckey(key) if(!key) return - var/list/mobs = sortmobs() + var/list/mobs = SSpoints_of_interest.get_mob_pois() for(var/mob/M in mobs) if(M.ckey == key) return M diff --git a/code/_globalvars/lists/objects.dm b/code/_globalvars/lists/objects.dm index 7ee53ec1f37b..6d08f1d1bceb 100644 --- a/code/_globalvars/lists/objects.dm +++ b/code/_globalvars/lists/objects.dm @@ -46,8 +46,6 @@ GLOBAL_LIST_EMPTY(apcs_list) GLOBAL_LIST_EMPTY(tracked_implants) /// List of implants the prisoner console can track and send inject commands too GLOBAL_LIST_EMPTY(tracked_chem_implants) -/// List of points of interest for observe/follow -GLOBAL_LIST_EMPTY(poi_list) /// List of all pinpointers. Used to change stuff they are pointing to all at once. GLOBAL_LIST_EMPTY(pinpointer_list) /// List of all zombie_infection organs, for any mass "animation" diff --git a/code/controllers/subsystem/points_of_interest.dm b/code/controllers/subsystem/points_of_interest.dm new file mode 100644 index 000000000000..6de327bc8666 --- /dev/null +++ b/code/controllers/subsystem/points_of_interest.dm @@ -0,0 +1,227 @@ +/// Subsystem for managing all POIs. +SUBSYSTEM_DEF(points_of_interest) + name = "Points of Interest" + + flags = SS_NO_FIRE | SS_NO_INIT + + /// List of mob POIs. This list is automatically sorted. + var/list/datum/point_of_interest/mob_poi/mob_points_of_interest = list() + /// List of non-mob POIs. This list is automatically sorted. + var/list/datum/point_of_interest/other_points_of_interest = list() + /// List of all value:POI datums by their key:target refs. + var/list/datum/point_of_interest/points_of_interest_by_target_ref = list() + +/** + * Turns new_poi into a new point of interest by adding the /datum/element/point_of_interest element to it. + */ +/datum/controller/subsystem/points_of_interest/proc/make_point_of_interest(atom/new_poi) + new_poi.AddElement(/datum/element/point_of_interest) + +/** + * Stops old_poi from being a point of interest by removing the /datum/element/point_of_interest element from it. + */ +/datum/controller/subsystem/points_of_interest/proc/remove_point_of_interest(atom/old_poi) + old_poi.RemoveElement(/datum/element/point_of_interest) + +/** + * Called by [/datum/element/point_of_interest] when it gets removed from old_poi. + */ +/datum/controller/subsystem/points_of_interest/proc/on_poi_element_added(atom/new_poi) + var/datum/point_of_interest/new_poi_datum + if(ismob(new_poi)) + new_poi_datum = new /datum/point_of_interest/mob_poi(new_poi) + BINARY_INSERT_PROC_COMPARE(new_poi_datum, mob_points_of_interest, /datum/point_of_interest/mob_poi, new_poi_datum, compare_to, COMPARE_KEY) + points_of_interest_by_target_ref[REF(new_poi)] = new_poi_datum + else + new_poi_datum = new /datum/point_of_interest(new_poi) + BINARY_INSERT_PROC_COMPARE(new_poi_datum, other_points_of_interest, /datum/point_of_interest, new_poi_datum, compare_to, COMPARE_KEY) + points_of_interest_by_target_ref[REF(new_poi)] = new_poi_datum + + + SEND_SIGNAL(src, COMSIG_ADDED_POINT_OF_INTEREST, new_poi) + +/** + * Called by [/datum/element/point_of_interest] when it gets removed from old_poi. + */ +/datum/controller/subsystem/points_of_interest/proc/on_poi_element_removed(atom/old_poi) + var/poi_ref = REF(old_poi) + var/datum/point_of_interest/poi_to_remove = points_of_interest_by_target_ref[poi_ref] + + if(!poi_to_remove) + return + + if(ismob(old_poi)) + mob_points_of_interest -= poi_to_remove + else + other_points_of_interest -= poi_to_remove + + points_of_interest_by_target_ref -= poi_ref + + poi_to_remove.target = null + + SEND_SIGNAL(src, COMSIG_REMOVED_POINT_OF_INTEREST, old_poi) + +/** + * If there is a valid POI for a given reference, it returns that POI's associated atom. Otherwise, it returns null. + */ +/datum/controller/subsystem/points_of_interest/proc/get_poi_atom_by_ref(reference) + return points_of_interest_by_target_ref[reference]?.target + +/** + * Returns a list of mob POIs with names as keys and mobs as values. + * + * If multiple POIs have the same name, then avoid_assoc_duplicate_keys is used alongside used_name_list to + * tag them as Mob Name (1), Mob Name (2), Mob Name (3) etc. + * + * Arguments: + * * poi_validation_override - [OPTIONAL] Callback to a proc that takes a single argument for the POI and returns TRUE if this POI should be included. Overrides standard POI validation. + * * append_dead_role - [OPTIONAL] If TRUE, adds a ghost tag to the end of observer names and a dead tag to the end of any other mob which is not alive. + */ +/datum/controller/subsystem/points_of_interest/proc/get_mob_pois(datum/callback/poi_validation_override = null, append_dead_role = TRUE) + var/list/pois = list() + var/list/used_name_list = list() + + for(var/datum/point_of_interest/mob_poi/mob_poi as anything in mob_points_of_interest) + if(poi_validation_override) + if(!poi_validation_override.Invoke(mob_poi)) + continue + else if(!mob_poi.validate()) + continue + + var/mob/target_mob = mob_poi.target + var/name = avoid_assoc_duplicate_keys(target_mob.name, used_name_list) + target_mob.get_realname_string() + + // Add the ghost/dead tag to the end of dead mob POIs. + if(append_dead_role && target_mob.stat == DEAD) + if(isobserver(target_mob)) + name += " \[ghost\]" + else + name += " \[dead\]" + + pois[name] = target_mob + + return pois + +/** + * Returns a list of non-mob POIs with names as keys and atoms as values. + * + * If multiple POIs have the same name, then avoid_assoc_duplicate_keys is used alongside used_name_list to + * tag them as Object Name (1), Object Name (2), Object Name (3) etc. + * + * Arguments: + * * poi_validation_override - [OPTIONAL] Callback to a proc that takes a single argument for the POI and returns TRUE if this POI should be included. Overrides standard POI validation. + */ +/datum/controller/subsystem/points_of_interest/proc/get_other_pois(datum/callback/poi_validation_override = null) + var/list/pois = list() + var/list/used_name_list = list() + + for(var/datum/point_of_interest/other_poi as anything in other_points_of_interest) + if(poi_validation_override) + if(!poi_validation_override.Invoke(other_poi)) + continue + else if(!other_poi.validate()) + continue + + var/atom/target_poi = other_poi.target + + pois[avoid_assoc_duplicate_keys(target_poi.name, used_name_list)] = target_poi + + return pois + +/// Returns TRUE if potential_poi has an associated poi_datum that validates. +/datum/controller/subsystem/points_of_interest/proc/is_valid_poi(atom/potential_poi, datum/callback/poi_validation_override = null) + var/datum/point_of_interest/poi_datum = points_of_interest_by_target_ref[REF(potential_poi)] + + if(!poi_datum) + return FALSE + + if(poi_validation_override) + return poi_validation_override.Invoke(poi_datum) + + return poi_datum.validate() + +/// Simple helper datum for points of interest. +/datum/point_of_interest + /// The specific point of interest this datum references. This won't hard del as the POI element will be removed from the target when it qdels, which will clear this reference. + var/atom/target + /// The type of POI this datum references. + var/poi_type = /atom + +/datum/point_of_interest/New(poi_target) + if(!istype(poi_target, poi_type)) + CRASH("Incorrect target type provided to /datum/point_of_interest/New: Expected \[[poi_type]\]") + + target = poi_target + +/// Validates the POI. Returns TRUE if the POI has valid state, returns FALSE if the POI has invalid state. +/datum/point_of_interest/proc/validate() + // In nullspace, invalid as a POI. + if(!target.loc) + return FALSE + + return TRUE + +/// Comparison proc used to sort POIs. Override to implement logic used doing binary sort insertions. +/datum/point_of_interest/proc/compare_to(datum/point_of_interest/rhs) + return cmp_name_asc(target, rhs.target) + +/datum/point_of_interest/mob_poi + poi_type = /mob + +/// Validation for mobs is expanded to invalidate stealthmins and /mob/dead/new_player as POIs. +/datum/point_of_interest/mob_poi/validate() + . = ..() + + if(!.) + return + + var/mob/poi_mob = target + + // Stealthmin, invalid as a POI. + if(poi_mob.client?.holder?.fakekey) + return FALSE + + /* + // POI is a /mob/dead/new_player, players in the lobby are invalid as POIs. + if(isnewplayer(poi_mob)) + return FALSE + */ + + return TRUE + +/// Mob POIs are sorted by a simple priority list depending on their type. When their type priority is identical, they're sub-sorted by name. +/datum/point_of_interest/mob_poi/compare_to(datum/point_of_interest/mob_poi/rhs) + var/sort_difference = get_type_sort_priority() - rhs.get_type_sort_priority() + + // If they're equal in priority, call parent to sort by name. + if(sort_difference == 0) + return ..() + // Else sort by priority. + else + return sort_difference + +/// Priority list broadly stolen from /proc/sortmobs(). Lower numbers are higher priorities when sorted and appear closer to the top or start of lists. +/datum/point_of_interest/mob_poi/proc/get_type_sort_priority() + if(isAI(target)) + return 0 + if(iscameramob(target)) + return 1 + if(ispAI(target)) + return 2 + if(iscyborg(target)) + return 3 + if(ishuman(target)) + return 4 + if(isbrain(target)) + return 5 + if(isalien(target)) + return 6 + if(isobserver(target)) + return 7 + if(isnewplayer(target)) + return 8 + if(isslime(target)) + return 9 + if(isanimal(target)) + return 10 + return 11 diff --git a/code/datums/elements/point_of_interest.dm b/code/datums/elements/point_of_interest.dm new file mode 100644 index 000000000000..d64ee5466ace --- /dev/null +++ b/code/datums/elements/point_of_interest.dm @@ -0,0 +1,22 @@ +/// Designates the atom as a "point of interest", meaning it can be directly orbited +/datum/element/point_of_interest + element_flags = ELEMENT_DETACH + +/datum/element/point_of_interest/Attach(datum/target) + if (!isatom(target)) + return ELEMENT_INCOMPATIBLE + + /* + // New players are abstract mobs assigned to people who are still in the lobby screen. + // As a result, they are not a valid POI and should never be a valid POI. If they + // somehow get this element attached to them, there's something we need to debug. + if(isnewplayer(target)) + return ELEMENT_INCOMPATIBLE + */ + + SSpoints_of_interest.on_poi_element_added(target) + return ..() + +/datum/element/point_of_interest/Detach(datum/target) + SSpoints_of_interest.on_poi_element_removed(target) + return ..() diff --git a/code/datums/spawners_menu.dm b/code/datums/spawners_menu.dm index 9e7e4b334ddc..01709a00c1a1 100644 --- a/code/datums/spawners_menu.dm +++ b/code/datums/spawners_menu.dm @@ -53,7 +53,7 @@ if(!spawnerlist.len) return var/obj/effect/mob_spawn/MS = pick(spawnerlist) - if(!istype(MS) || !(MS in GLOB.poi_list)) + if(!istype(MS) || !(MS in SSpoints_of_interest.other_points_of_interest)) return switch(action) if("jump") diff --git a/code/game/atom/atom_orbit.dm b/code/game/atom/atom_orbit.dm new file mode 100644 index 000000000000..2294293bd8b7 --- /dev/null +++ b/code/game/atom/atom_orbit.dm @@ -0,0 +1,33 @@ +/atom + ///Reference to atom being orbited + var/atom/orbit_target + ///The orbiter component, if there's anything orbiting this atom + var/datum/component/orbiter/orbiters + +/** + * Recursive getter method to return a list of all ghosts orbitting this atom + * + * This will work fine without manually passing arguments. + * * processed - The list of atoms we've already convered + * * source - Is this the atom for who we're counting up all the orbiters? + * * ignored_stealthed_admins - If TRUE, don't count admins who are stealthmoded and orbiting this + */ +/atom/proc/get_all_orbiters(list/processed, source = TRUE, ignore_stealthed_admins = TRUE) + var/list/output = list() + if(!processed) + processed = list() + else if(src in processed) + return output + + if(!source) + output += src + + processed += src + for(var/atom/atom_orbiter as anything in orbiters?.orbiters) + output += atom_orbiter.get_all_orbiters(processed, source = FALSE) + return output + +/mob/get_all_orbiters(list/processed, source = TRUE, ignore_stealthed_admins = TRUE) + if(!source && ignore_stealthed_admins && client?.holder?.fakekey) + return list() + return ..() diff --git a/code/game/atoms.dm b/code/game/atoms.dm index f52b9bdace9e..b96e8a53c824 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -75,9 +75,6 @@ ///Economy cost of item in premium vendor var/custom_premium_price - //List of datums orbiting this atom - var/datum/component/orbiter/orbiters - /// Radiation insulation types var/rad_insulation = RAD_NO_INSULATION @@ -154,8 +151,6 @@ /// The current connector overlay appearance. Saved so that it can be cut when necessary. var/connector_overlay - ///Reference to atom being orbited - var/atom/orbit_target ///Default X pixel offset var/base_pixel_x ///Default Y pixel offset diff --git a/code/game/gamemodes/wizard/wizard.dm b/code/game/gamemodes/wizard/wizard.dm index c3895f302279..83d7a32d1fd9 100644 --- a/code/game/gamemodes/wizard/wizard.dm +++ b/code/game/gamemodes/wizard/wizard.dm @@ -56,7 +56,7 @@ if(isliving(wizard.current) && wizard.current.stat!=DEAD) return FALSE - for(var/obj/item/phylactery/P in GLOB.poi_list) //TODO : IsProperlyDead() + for(var/obj/item/phylactery/P in SSpoints_of_interest.other_points_of_interest) //TODO : IsProperlyDead() if(P.mind && P.mind.has_antag_datum(/datum/antagonist/wizard)) return FALSE diff --git a/code/game/mecha/mecha.dm b/code/game/mecha/mecha.dm index b903564c88d6..a1b46fd2fbfa 100644 --- a/code/game/mecha/mecha.dm +++ b/code/game/mecha/mecha.dm @@ -137,7 +137,7 @@ add_scanmod() add_capacitor() START_PROCESSING(SSobj, src) - GLOB.poi_list |= src + SSpoints_of_interest.make_point_of_interest(src) log_message("[src.name] created.", LOG_MECHA) GLOB.mechas_list += src //global mech list prepare_huds() @@ -176,7 +176,7 @@ AI.gib() //No wreck, no AI to recover AI = null STOP_PROCESSING(SSobj, src) - GLOB.poi_list.Remove(src) + SSpoints_of_interest.remove_point_of_interest(src) equipment.Cut() for(var/datum/atom_hud/data/diagnostic/diag_hud in GLOB.huds) diff --git a/code/game/objects/items/eightball.dm b/code/game/objects/items/eightball.dm index 1396521aaf9a..b721393e85ed 100644 --- a/code/game/objects/items/eightball.dm +++ b/code/game/objects/items/eightball.dm @@ -136,10 +136,10 @@ become_hearing_sensitive(ROUNDSTART_TRAIT) for (var/answer in haunted_answers) votes[answer] = 0 - GLOB.poi_list |= src + SSpoints_of_interest.make_point_of_interest(src) /obj/item/toy/eightball/haunted/Destroy() - GLOB.poi_list -= src + SSpoints_of_interest.remove_point_of_interest(src) . = ..() /obj/item/toy/eightball/haunted/MakeHaunted() diff --git a/code/modules/admin/player_panel.dm b/code/modules/admin/player_panel.dm index cf834c9f9c5d..e5888f8088df 100644 --- a/code/modules/admin/player_panel.dm +++ b/code/modules/admin/player_panel.dm @@ -216,9 +216,10 @@ "} - var/list/mobs = sortmobs() + var/list/mobs = SSpoints_of_interest.get_mob_pois() var/i = 1 - for(var/mob/M in mobs) + for(var/mob_name in mobs) + var/mob/M = mobs[mob_name] if(M.ckey) var/color = "#e6e6e6" @@ -254,12 +255,7 @@ M_job = "Silicon-based" else if(isanimal(M)) //simple animals - if(iscorgi(M)) - M_job = "Corgi" - else if(isslime(M)) - M_job = "slime" - else - M_job = "Animal" + M_job = "Animal" else M_job = "Living" diff --git a/code/modules/admin/verbs/adminjump.dm b/code/modules/admin/verbs/adminjump.dm index 9b84224317a9..708448cf52cd 100644 --- a/code/modules/admin/verbs/adminjump.dm +++ b/code/modules/admin/verbs/adminjump.dm @@ -140,7 +140,7 @@ usr.forceMove(M.loc) SSblackbox.record_feedback("tally", "admin_verb", 1, "Get Key") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! -/client/proc/sendmob(mob/M in sortmobs()) +/client/proc/sendmob(mob/M in SSpoints_of_interest.get_mob_pois()) set category = "Admin.Game" set name = "Send Mob" if(!src.holder) diff --git a/code/modules/antagonists/cult/runes.dm b/code/modules/antagonists/cult/runes.dm index b0fb446405c2..3382672071cc 100644 --- a/code/modules/antagonists/cult/runes.dm +++ b/code/modules/antagonists/cult/runes.dm @@ -450,10 +450,10 @@ structure_check() searches for nearby cultist structures required for the invoca /obj/effect/rune/narsie/Initialize(mapload, set_keyword) . = ..() - GLOB.poi_list |= src + SSpoints_of_interest.make_point_of_interest(src) /obj/effect/rune/narsie/Destroy() - GLOB.poi_list -= src + SSpoints_of_interest.remove_point_of_interest(src) . = ..() /obj/effect/rune/narsie/conceal() //can't hide this, and you wouldn't want to @@ -469,7 +469,7 @@ structure_check() searches for nearby cultist structures required for the invoca if(!(place in summon_objective.summon_spots)) to_chat(user, "The Geometer can only be summoned where the veil is weak - in [english_list(summon_objective.summon_spots)]!") return - if(locate(/obj/singularity/narsie) in GLOB.poi_list) + if(locate(/obj/singularity/narsie) in SSpoints_of_interest.other_points_of_interest) for(var/M in invokers) to_chat(M, "Nar'Sie is already on this plane!") log_game("Nar'Sie rune failed - already summoned") diff --git a/code/modules/antagonists/nukeop/equipment/nuclearbomb.dm b/code/modules/antagonists/nukeop/equipment/nuclearbomb.dm index 26d7321eb813..9c65e50130cf 100644 --- a/code/modules/antagonists/nukeop/equipment/nuclearbomb.dm +++ b/code/modules/antagonists/nukeop/equipment/nuclearbomb.dm @@ -38,7 +38,7 @@ core = new /obj/item/nuke_core(src) STOP_PROCESSING(SSobj, core) update_appearance() - GLOB.poi_list |= src + SSpoints_of_interest.make_point_of_interest(src) previous_level = get_security_level() /obj/machinery/nuclearbomb/Destroy() @@ -46,7 +46,7 @@ if(!exploding) // If we're not exploding, set the alert level back to normal set_safety() - GLOB.poi_list -= src + SSpoints_of_interest.remove_point_of_interest(src) GLOB.nuke_list -= src QDEL_NULL(countdown) QDEL_NULL(core) @@ -611,7 +611,7 @@ This is here to make the tiles around the station mininuke change when it's arme AddElement(/datum/element/bed_tuckable, 6, -6, 0) if(!fake) - GLOB.poi_list |= src + SSpoints_of_interest.make_point_of_interest(src) last_disk_move = world.time START_PROCESSING(SSobj, src) @@ -661,7 +661,7 @@ This is here to make the tiles around the station mininuke change when it's arme /obj/item/disk/nuclear/Destroy(force=FALSE) // respawning is handled in /obj/Destroy() if(force) - GLOB.poi_list -= src + SSpoints_of_interest.remove_point_of_interest(src) . = ..() /obj/item/disk/nuclear/fake diff --git a/code/modules/antagonists/nukeop/equipment/pinpointer.dm b/code/modules/antagonists/nukeop/equipment/pinpointer.dm index b316e60c5e14..c1f9ffa37428 100644 --- a/code/modules/antagonists/nukeop/equipment/pinpointer.dm +++ b/code/modules/antagonists/nukeop/equipment/pinpointer.dm @@ -32,7 +32,7 @@ target = null switch(mode) if(TRACK_NUKE_DISK) - var/obj/item/disk/nuclear/N = locate() in GLOB.poi_list + var/obj/item/disk/nuclear/N = locate() in SSpoints_of_interest.other_points_of_interest target = N if(TRACK_MALF_AI) for(var/V in GLOB.ai_list) diff --git a/code/modules/antagonists/nukeop/nukeop.dm b/code/modules/antagonists/nukeop/nukeop.dm index 9f807d9521e7..f51c64142450 100644 --- a/code/modules/antagonists/nukeop/nukeop.dm +++ b/code/modules/antagonists/nukeop/nukeop.dm @@ -345,7 +345,7 @@ /datum/team/nuclear/antag_listing_entry() var/disk_report = "Nuclear Disk(s)
" disk_report += "
" - for(var/obj/item/disk/nuclear/N in GLOB.poi_list) + for(var/obj/item/disk/nuclear/N in SSpoints_of_interest.other_points_of_interest) disk_report += "
[N.name], " var/atom/disk_loc = N.loc while(!isturf(disk_loc)) diff --git a/code/modules/awaymissions/capture_the_flag.dm b/code/modules/awaymissions/capture_the_flag.dm index 42d7643fb926..5fc667c4db4a 100644 --- a/code/modules/awaymissions/capture_the_flag.dm +++ b/code/modules/awaymissions/capture_the_flag.dm @@ -195,10 +195,10 @@ /obj/machinery/capture_the_flag/Initialize() . = ..() - GLOB.poi_list |= src + SSpoints_of_interest.make_point_of_interest(src) /obj/machinery/capture_the_flag/Destroy() - GLOB.poi_list.Remove(src) + SSpoints_of_interest.remove_point_of_interest(src) return ..() /obj/machinery/capture_the_flag/process() diff --git a/code/modules/awaymissions/corpse.dm b/code/modules/awaymissions/corpse.dm index 0bf0b74c715a..26361b99cfc6 100644 --- a/code/modules/awaymissions/corpse.dm +++ b/code/modules/awaymissions/corpse.dm @@ -61,11 +61,11 @@ if(instant || (roundstart && (mapload || (SSticker && SSticker.current_state > GAME_STATE_SETTING_UP)))) INVOKE_ASYNC(src, PROC_REF(create)) else if(ghost_usable) - GLOB.poi_list |= src + SSpoints_of_interest.make_point_of_interest(src) LAZYADD(GLOB.mob_spawners[name], src) /obj/effect/mob_spawn/Destroy() - GLOB.poi_list -= src + SSpoints_of_interest.remove_point_of_interest(src) var/list/spawners = GLOB.mob_spawners[name] LAZYREMOVE(spawners, src) if(!LAZYLEN(spawners)) diff --git a/code/modules/cargo/centcom_podlauncher.dm b/code/modules/cargo/centcom_podlauncher.dm index dfec659e1644..0b302925e10e 100644 --- a/code/modules/cargo/centcom_podlauncher.dm +++ b/code/modules/cargo/centcom_podlauncher.dm @@ -383,7 +383,7 @@ if (specificTarget) specificTarget = null return - var/list/mobs = getpois()//code stolen from observer.dm + var/list/mobs = SSpoints_of_interest.get_mob_pois() var/inputTarget = input("Select a mob! (Smiting does this automatically)", "Target", null, null) as null|anything in mobs if (isnull(inputTarget)) return diff --git a/code/modules/events/immovable_rod.dm b/code/modules/events/immovable_rod.dm index adde1124935f..4ba2d878ad46 100644 --- a/code/modules/events/immovable_rod.dm +++ b/code/modules/events/immovable_rod.dm @@ -62,7 +62,7 @@ In my current plan for it, 'solid' will be defined as anything with density == 1 z_original = z destination = end special_target = aimed_at - GLOB.poi_list += src + SSpoints_of_interest.make_point_of_interest(src) var/special_target_valid = FALSE if(special_target) @@ -81,7 +81,7 @@ In my current plan for it, 'solid' will be defined as anything with density == 1 ghost.ManualFollow(src) /obj/effect/immovablerod/Destroy() - GLOB.poi_list -= src + SSpoints_of_interest.remove_point_of_interest(src) . = ..() /obj/effect/immovablerod/Moved() diff --git a/code/modules/events/wizard/greentext.dm b/code/modules/events/wizard/greentext.dm index 890bbc0f1f2b..8e4baab893fc 100644 --- a/code/modules/events/wizard/greentext.dm +++ b/code/modules/events/wizard/greentext.dm @@ -34,7 +34,7 @@ /obj/item/greentext/Initialize(mapload) . = ..() - GLOB.poi_list |= src + SSpoints_of_interest.make_point_of_interest(src) roundend_callback = CALLBACK(src, PROC_REF(check_winner)) SSticker.OnRoundend(roundend_callback) @@ -83,7 +83,7 @@ if(!(resistance_flags & ON_FIRE) && !force) return QDEL_HINT_LETMELIVE - GLOB.poi_list.Remove(src) + SSpoints_of_interest.remove_point_of_interest(src) LAZYREMOVE(SSticker.round_end_events, roundend_callback) roundend_callback = null //This ought to free the callback datum, and prevent us from harddeling for(var/i in GLOB.player_list) diff --git a/code/modules/mob/dead/new_player/new_player.dm b/code/modules/mob/dead/new_player/new_player.dm index 8fbf9c32a38e..2dbbd9d4b65b 100644 --- a/code/modules/mob/dead/new_player/new_player.dm +++ b/code/modules/mob/dead/new_player/new_player.dm @@ -35,6 +35,7 @@ . = ..() GLOB.new_player_list += src + SSpoints_of_interest.make_point_of_interest(src) /mob/dead/new_player/Destroy() GLOB.new_player_list -= src diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm index c15c4a1af835..0fcfa5c13940 100644 --- a/code/modules/mob/dead/observer/observer.dm +++ b/code/modules/mob/dead/observer/observer.dm @@ -62,6 +62,9 @@ GLOBAL_VAR_INIT(observer_default_invisibility, INVISIBILITY_OBSERVER) var/datum/orbit_menu/orbit_menu var/datum/spawners_menu/spawners_menu + // The POI we're orbiting (orbit menu) + var/orbiting_ref + /mob/dead/observer/Initialize() set_invisibility(GLOB.observer_default_invisibility) @@ -142,6 +145,8 @@ GLOBAL_VAR_INIT(observer_default_invisibility, INVISIBILITY_OBSERVER) . = ..() + SSpoints_of_interest.make_point_of_interest(src) + grant_all_languages() show_data_huds() data_huds_on = 1 @@ -499,7 +504,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp var/list/dest = list() //List of possible destinations (mobs) var/target = null //Chosen target. - dest += getpois(mobs_only = TRUE) //Fill list, prompt user with list + dest += SSpoints_of_interest.get_mob_pois() target = input("Please, select a player!", "Jump to Mob", null, null) as null|anything in dest if (!target)//Make sure we actually have a target @@ -839,20 +844,24 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp /mob/dead/observer/reset_perspective(atom/A) if(client) if(ismob(client.eye) && (client.eye != src)) - var/mob/target = client.eye - observetarget = null - if(target.observers) - LAZYREMOVE(target.observers, src) + cleanup_observe() if(..()) if(hud_used) client.screen = list() hud_used.show_hud(hud_used.hud_version) +/mob/dead/observer/proc/cleanup_observe() + var/mob/target = client.eye + observetarget = null + client?.perspective = initial(client.perspective) + if(target.observers) + LAZYREMOVE(target.observers, src) + /mob/dead/observer/verb/observe() set name = "Observe" set category = "Ghost" - var/list/creatures = getpois() + var/list/creatures = SSpoints_of_interest.get_mob_pois() reset_perspective(null) diff --git a/code/modules/mob/dead/observer/orbit.dm b/code/modules/mob/dead/observer/orbit.dm index 86d54577538c..051faa5bedac 100644 --- a/code/modules/mob/dead/observer/orbit.dm +++ b/code/modules/mob/dead/observer/orbit.dm @@ -1,6 +1,9 @@ /datum/orbit_menu + ///mobs worth orbiting. Because spaghetti, all mobs have the point of interest, but only some are allowed to actually show up. + ///this obviously should be changed in the future, so we only add mobs as POI if they actually are interesting, and we don't use + ///a typecache. + var/static/list/mob_allowed_typecache var/mob/dead/observer/owner - var/auto_observe = FALSE /datum/orbit_menu/New(mob/dead/observer/new_owner) if(!istype(new_owner)) @@ -23,87 +26,243 @@ switch(action) if ("orbit") var/ref = params["ref"] - var/atom/movable/poi = (locate(ref) in GLOB.mob_list) || (locate(ref) in GLOB.poi_list) - if (poi == null) - . = TRUE - return + var/auto_observe = params["auto_observe"] + var/atom/movable/poi = SSpoints_of_interest.get_poi_atom_by_ref(ref) + + if((ismob(poi) && !SSpoints_of_interest.is_valid_poi(poi, CALLBACK(src, PROC_REF(validate_mob_poi)))) \ + || !SSpoints_of_interest.is_valid_poi(poi) + ) + to_chat(usr, span_notice("That point of interest is no longer valid.")) + return TRUE + + var/mob/dead/observer/user = usr owner.ManualFollow(poi) owner.reset_perspective(null) + user.orbiting_ref = ref if (auto_observe) owner.do_observe(poi) . = TRUE if ("refresh") update_static_data(owner, ui) . = TRUE - if ("toggle_observe") - auto_observe = !auto_observe - if (auto_observe && owner.orbit_target) - owner.do_observe(owner.orbit_target) - else - owner.reset_perspective(null) + /datum/orbit_menu/ui_data(mob/user) var/list/data = list() - data["auto_observe"] = auto_observe + + if(isobserver(user)) + data["orbiting"] = get_currently_orbiting(user) + return data /datum/orbit_menu/ui_static_data(mob/user) - var/list/data = list() + var/list/new_mob_pois = SSpoints_of_interest.get_mob_pois(CALLBACK(src, PROC_REF(validate_mob_poi)), append_dead_role = FALSE) + var/list/new_other_pois = SSpoints_of_interest.get_other_pois() var/list/alive = list() var/list/antagonists = list() + var/list/critical = list() var/list/dead = list() var/list/ghosts = list() var/list/misc = list() var/list/npcs = list() + var/list/ships = list() - var/list/pois = getpois(skip_mindless = TRUE, specify_dead_role = FALSE) - for (var/name in pois) + for(var/name in new_mob_pois) var/list/serialized = list() - serialized["name"] = name - - var/poi = pois[name] - - serialized["ref"] = REF(poi) - - var/mob/M = poi - if (istype(M)) - if (isobserver(M)) - ghosts += list(serialized) - else if (M.stat == DEAD) - dead += list(serialized) - else if (M.mind == null) - npcs += list(serialized) - else - var/number_of_orbiters = M.orbiters?.orbiters?.len - if (number_of_orbiters) - serialized["orbiters"] = number_of_orbiters - - var/datum/mind/mind = M.mind - var/was_antagonist = FALSE - - for (var/_A in mind.antag_datums) - var/datum/antagonist/A = _A - if (A.show_to_ghosts) - was_antagonist = TRUE - serialized["antag"] = A.name - antagonists += list(serialized) - break - - if (!was_antagonist) - alive += list(serialized) + var/mob/mob_poi = new_mob_pois[name] + var/number_of_orbiters = length(mob_poi.get_all_orbiters()) + + if(isnewplayer(mob_poi)) + continue + + serialized["ref"] = REF(mob_poi) + serialized["full_name"] = mob_poi.name + serialized["job"] = mob_poi.job + if(number_of_orbiters) + serialized["orbiters"] = number_of_orbiters + + if(isobserver(mob_poi)) + ghosts += list(serialized) + continue + + if(mob_poi.stat == DEAD) + dead += list(serialized) + continue + + if(isnull(mob_poi.mind)) + if(isliving(mob_poi)) + var/mob/living/npc = mob_poi + serialized["health"] = FLOOR((npc.health / npc.maxHealth * 100), 1) + + npcs += list(serialized) + continue + + serialized["client"] = !!mob_poi.client + serialized["name"] = mob_poi.real_name + + if(isliving(mob_poi)) + serialized += get_living_data(mob_poi) + + var/list/antag_data = get_antag_data(mob_poi.mind) + if(length(antag_data)) + serialized += antag_data + antagonists += list(serialized) + continue + + alive += list(serialized) + + for(var/name in new_other_pois) + var/atom/atom_poi = new_other_pois[name] + + var/list/other_data = get_misc_data(atom_poi) + var/misc_data = list(other_data[1]) + + if(istype(atom_poi, /obj/machinery/computer/helm)) + ships += misc_data else - misc += list(serialized) - - data["alive"] = alive - data["antagonists"] = antagonists - data["dead"] = dead - data["ghosts"] = ghosts - data["misc"] = misc - data["npcs"] = npcs - return data + misc += misc_data + + if(other_data[2]) // Critical = TRUE + critical += misc_data + + return list( + "alive" = alive, + "antagonists" = antagonists, + "critical" = critical, + "dead" = dead, + "ghosts" = ghosts, + "misc" = misc, + "npcs" = npcs, + "ships" = ships, + ) /datum/orbit_menu/ui_assets() . = ..() || list() . += get_asset_datum(/datum/asset/simple/orbit) +/// Helper function to get threat type, group, overrides for job and icon +/datum/orbit_menu/proc/get_antag_data(datum/mind/poi_mind) as /list + var/list/serialized = list() + + for(var/datum/antagonist/antag as anything in poi_mind.antag_datums) + if(!antag.show_to_ghosts) + continue + + serialized["antag"] = antag.name + serialized["antag_group"] = antag.antagpanel_category + serialized["job"] = antag.name + serialized["icon"] = antag.antag_hud_name + + return serialized + +/// Helper to get the current thing we're orbiting (if any) +/datum/orbit_menu/proc/get_currently_orbiting(mob/dead/observer/user) + if(isnull(user.orbiting_ref)) + return + + var/atom/poi = SSpoints_of_interest.get_poi_atom_by_ref(user.orbiting_ref) + if(isnull(poi)) + user.orbiting_ref = null + return + + if((ismob(poi) && !SSpoints_of_interest.is_valid_poi(poi, CALLBACK(src, PROC_REF(validate_mob_poi)))) \ + || !SSpoints_of_interest.is_valid_poi(poi) + ) + user.orbiting_ref = null + return + + var/list/serialized = list() + + if(!ismob(poi)) + var/list/misc_info = get_misc_data(poi) + serialized += misc_info[1] + return serialized + + var/mob/mob_poi = poi + serialized["full_name"] = mob_poi.name + serialized["ref"] = REF(poi) + + if(mob_poi.mind) + serialized["client"] = !!mob_poi.client + serialized["name"] = mob_poi.real_name + + if(isliving(mob_poi)) + serialized += get_living_data(mob_poi) + + return serialized + +/// Helper function to get job / icon / health data for a living mob +/datum/orbit_menu/proc/get_living_data(mob/living/player) as /list + var/list/serialized = list() + + serialized["health"] = FLOOR((player.health / player.maxHealth * 100), 1) + + return serialized + + +/// Gets a list: Misc data and whether it's critical. Handles all snowflakey type cases +/datum/orbit_menu/proc/get_misc_data(atom/movable/atom_poi) as /list + var/list/misc = list() + var/critical = FALSE + + misc["ref"] = REF(atom_poi) + misc["full_name"] = atom_poi.name + + // Display the nuke timer + if(istype(atom_poi, /obj/machinery/nuclearbomb)) + var/obj/machinery/nuclearbomb/bomb = atom_poi + + if(bomb.timing) + misc["extra"] = "Timer: [bomb.countdown?.displayed_text]s" + critical = TRUE + + return list(misc, critical) + + // Display the holder if its a nuke disk + if(istype(atom_poi, /obj/item/disk/nuclear)) + var/obj/item/disk/nuclear/disk = atom_poi + var/mob/holder = disk.pulledby || get(disk, /mob) + misc["extra"] = "Location: [holder?.real_name || "Unsecured"]" + + return list(misc, critical) + + // Display singuloths if they exist + if(istype(atom_poi, /obj/singularity)) + var/obj/singularity/singulo = atom_poi + misc["extra"] = "Energy: [round(singulo.energy)]" + + if(singulo.current_size > 2) + critical = TRUE + + return list(misc, critical) + + if(istype(atom_poi, /obj/machinery/computer/helm)) + var/obj/machinery/computer/helm/helm_poi = atom_poi + if(helm_poi.current_ship) + misc["extra"] = "Ship: [helm_poi.current_ship.name]" + + return list(misc, critical) + + return list(misc, critical) + +/** + * Helper POI validation function passed as a callback to various SSpoints_of_interest procs. + * + * Provides extended validation above and beyond standard, limiting mob POIs without minds or ckeys + * unless they're mobs, camera mobs or megafauna. Also allows exceptions for mobs that are deadchat controlled. + * + * If they satisfy that requirement, falls back to default validation for the POI. + */ +/datum/orbit_menu/proc/validate_mob_poi(datum/point_of_interest/mob_poi/potential_poi) + var/mob/potential_mob_poi = potential_poi.target + if(!potential_mob_poi.mind && !potential_mob_poi.ckey) + if(!mob_allowed_typecache) + mob_allowed_typecache = typecacheof(list( + /mob/living/simple_animal/hostile/megafauna, + /mob/living/simple_animal/hostile/boss + )) + if(!is_type_in_typecache(potential_mob_poi, mob_allowed_typecache) && !potential_mob_poi.GetComponent(/datum/component/deadchat_control)) + return FALSE + + return potential_poi.validate() diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index 1258df8b84c5..6046cfe82b63 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -9,6 +9,7 @@ diag_hud.add_to_hud(src) faction += "[REF(src)]" GLOB.mob_living_list += src + SSpoints_of_interest.make_point_of_interest(src) if(speed) update_living_varspeed() diff --git a/code/modules/mob/living/simple_animal/friendly/drone/drones_as_items.dm b/code/modules/mob/living/simple_animal/friendly/drone/drones_as_items.dm index e0537594c8ff..76dc1f095009 100644 --- a/code/modules/mob/living/simple_animal/friendly/drone/drones_as_items.dm +++ b/code/modules/mob/living/simple_animal/friendly/drone/drones_as_items.dm @@ -30,11 +30,6 @@ var/area/A = get_area(src) if(A) notify_ghosts("A drone shell has been created in \the [A.name].", source = src, action=NOTIFY_ATTACK, flashwindow = FALSE, ignore_key = POLL_IGNORE_DRONE) - GLOB.poi_list |= src - -/obj/effect/mob_spawn/drone/Destroy() - GLOB.poi_list -= src - . = ..() //ATTACK GHOST IGNORING PARENT RETURN VALUE /obj/effect/mob_spawn/drone/attack_ghost(mob/user) diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm index 863abf56dad1..ff06df9c6113 100644 --- a/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm +++ b/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm @@ -607,12 +607,12 @@ GLOBAL_DATUM(blackbox, /obj/machinery/smartfridge/black_box) var/ready_to_deploy = FALSE /obj/machinery/anomalous_crystal/helpers/Destroy() - GLOB.poi_list -= src + SSpoints_of_interest.remove_point_of_interest(src) . = ..() /obj/machinery/anomalous_crystal/helpers/ActivationReaction(mob/user, method) if(..() && !ready_to_deploy) - GLOB.poi_list |= src + SSpoints_of_interest.make_point_of_interest(src) ready_to_deploy = TRUE notify_ghosts("An anomalous crystal has been activated in [get_area(src)]! This crystal can always be used by ghosts hereafter.", enter_link = "(Click to enter)", ghost_sound = 'sound/effects/ghost2.ogg', source = src, action = NOTIFY_ATTACK, header = "Anomalous crystal activated") diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index b1788a7aa50d..a05c2e65688e 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -462,7 +462,7 @@ else client.perspective = EYE_PERSPECTIVE client.eye = loc - return 1 + return TRUE /// Show the mob's inventory to another mob /mob/proc/show_inv(mob/user) diff --git a/code/modules/modular_computers/file_system/programs/radar.dm b/code/modules/modular_computers/file_system/programs/radar.dm index d082503a012d..06324b8f8b78 100644 --- a/code/modules/modular_computers/file_system/programs/radar.dm +++ b/code/modules/modular_computers/file_system/programs/radar.dm @@ -156,7 +156,7 @@ *something like "mob_209". In order to find the actual atom, we need *to search the appropriate list for the REF string. This is dependant *on the program (Lifeline uses GLOB.human_list, while Fission360 uses - *GLOB.poi_list), but the result will be the same; evaluate the string and + *SSpoints_of_interest.other_points_of_interest), but the result will be the same; evaluate the string and *return an atom reference. */ /datum/computer_file/program/radar/proc/find_atom() @@ -269,7 +269,7 @@ pointercolor = "red" /datum/computer_file/program/radar/fission360/find_atom() - return locate(selected) in GLOB.poi_list + return locate(selected) in SSpoints_of_interest.other_points_of_interest /datum/computer_file/program/radar/fission360/scan() if(world.time < next_scan) @@ -286,7 +286,7 @@ name = nuke.name, ) objects += list(nukeinfo) - var/obj/item/disk/nuclear/disk = locate() in GLOB.poi_list + var/obj/item/disk/nuclear/disk = locate() in SSpoints_of_interest.other_points_of_interest if(trackable(disk)) var/list/nukeinfo = list( ref = REF(disk), diff --git a/code/modules/overmap/helm.dm b/code/modules/overmap/helm.dm index 5b1f27fa2cb9..3b825ce39524 100644 --- a/code/modules/overmap/helm.dm +++ b/code/modules/overmap/helm.dm @@ -49,6 +49,8 @@ /obj/machinery/computer/helm/Initialize(mapload, obj/item/circuitboard/C) . = ..() + if(!viewer) + SSpoints_of_interest.make_point_of_interest(src) jump_allowed = world.time + CONFIG_GET(number/bluespace_jump_wait) ntnet_relay = new(src) @@ -76,6 +78,7 @@ SStgui.close_uis(src) ASSERT(length(concurrent_users) == 0) QDEL_NULL(ntnet_relay) + SSpoints_of_interest.remove_point_of_interest(src) if(current_ship) current_ship.helms -= src current_ship = null diff --git a/code/modules/power/singularity/singularity.dm b/code/modules/power/singularity/singularity.dm index 9218b829e940..499a88b161f1 100644 --- a/code/modules/power/singularity/singularity.dm +++ b/code/modules/power/singularity/singularity.dm @@ -38,7 +38,7 @@ src.energy = starting_energy . = ..() START_PROCESSING(SSobj, src) - GLOB.poi_list |= src + SSpoints_of_interest.make_point_of_interest(src) GLOB.singularities |= src for(var/obj/machinery/power/singularity_beacon/singubeacon in GLOB.machines) if(singubeacon.active) @@ -53,7 +53,7 @@ /obj/singularity/Destroy() STOP_PROCESSING(SSobj, src) - GLOB.poi_list.Remove(src) + SSpoints_of_interest.remove_point_of_interest(src) GLOB.singularities.Remove(src) return ..() diff --git a/code/modules/power/supermatter/supermatter.dm b/code/modules/power/supermatter/supermatter.dm index 6ed294fa8936..400366415d9a 100644 --- a/code/modules/power/supermatter/supermatter.dm +++ b/code/modules/power/supermatter/supermatter.dm @@ -275,7 +275,7 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal) SSair.start_processing_machine(src, mapload) countdown = new(src) countdown.start() - GLOB.poi_list |= src + SSpoints_of_interest.make_point_of_interest(src) radio = new(src) radio.keyslot = new radio_key radio.listening = 0 @@ -293,7 +293,7 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal) investigate_log("has been destroyed.", INVESTIGATE_SUPERMATTER) SSair.stop_processing_machine(src) QDEL_NULL(radio) - GLOB.poi_list -= src + SSpoints_of_interest.remove_point_of_interest(src) QDEL_NULL(countdown) if(is_main_engine && GLOB.main_supermatter_engine == src) GLOB.main_supermatter_engine = null diff --git a/code/modules/power/tesla/energy_ball.dm b/code/modules/power/tesla/energy_ball.dm index 7d58610fc7f7..d4a6f71cca4d 100644 --- a/code/modules/power/tesla/energy_ball.dm +++ b/code/modules/power/tesla/energy_ball.dm @@ -151,7 +151,7 @@ /obj/singularity/energy_ball/orbit(obj/singularity/energy_ball/target) if (istype(target)) target.orbiting_balls += src - GLOB.poi_list -= src + SSpoints_of_interest.remove_point_of_interest(src) target.dissipate_strength = target.orbiting_balls.len . = ..() diff --git a/code/modules/projectiles/guns/energy/pulse.dm b/code/modules/projectiles/guns/energy/pulse.dm index c2e5b4cb2933..40fd10e94785 100644 --- a/code/modules/projectiles/guns/energy/pulse.dm +++ b/code/modules/projectiles/guns/energy/pulse.dm @@ -46,7 +46,7 @@ /obj/item/gun/energy/pulse/prize/Initialize() . = ..() - GLOB.poi_list += src + SSpoints_of_interest.make_point_of_interest(src) var/turf/T = get_turf(src) message_admins("A pulse rifle prize has been created at [ADMIN_VERBOSEJMP(T)]") @@ -55,7 +55,7 @@ notify_ghosts("Someone won a pulse rifle as a prize!", source = src, action = NOTIFY_ORBIT, header = "Pulse rifle prize") /obj/item/gun/energy/pulse/prize/Destroy() - GLOB.poi_list -= src + SSpoints_of_interest.remove_point_of_interest(src) . = ..() /obj/item/gun/energy/pulse/pistol diff --git a/code/modules/spells/spell_types/lichdom.dm b/code/modules/spells/spell_types/lichdom.dm index 720670e3fc21..38e2f0df145e 100644 --- a/code/modules/spells/spell_types/lichdom.dm +++ b/code/modules/spells/spell_types/lichdom.dm @@ -99,7 +99,7 @@ name = "phylactery of [mind.name]" active_phylacteries++ - GLOB.poi_list |= src + SSpoints_of_interest.make_point_of_interest(src) START_PROCESSING(SSobj, src) if(initial(SSticker.mode.round_ends_with_antag_death)) SSticker.mode.round_ends_with_antag_death = FALSE @@ -107,7 +107,7 @@ /obj/item/phylactery/Destroy(force=FALSE) STOP_PROCESSING(SSobj, src) active_phylacteries-- - GLOB.poi_list -= src + SSpoints_of_interest.remove_point_of_interest(src) if(!active_phylacteries) SSticker.mode.round_ends_with_antag_death = initial(SSticker.mode.round_ends_with_antag_death) . = ..() diff --git a/shiptest.dme b/shiptest.dme index 88900c60e222..e460d129f655 100644 --- a/shiptest.dme +++ b/shiptest.dme @@ -370,6 +370,7 @@ #include "code\controllers\subsystem\persistence.dm" #include "code\controllers\subsystem\physics.dm" #include "code\controllers\subsystem\ping.dm" +#include "code\controllers\subsystem\points_of_interest.dm" #include "code\controllers\subsystem\profiler.dm" #include "code\controllers\subsystem\radiation.dm" #include "code\controllers\subsystem\radio.dm" @@ -672,6 +673,7 @@ #include "code\datums\elements\lazy_fishing_spot.dm" #include "code\datums\elements\light_blocking.dm" #include "code\datums\elements\mobappearance.dm" +#include "code\datums\elements\point_of_interest.dm" #include "code\datums\elements\plant_backfire.dm" #include "code\datums\elements\renamemob.dm" #include "code\datums\elements\selfknockback.dm" @@ -857,6 +859,7 @@ #include "code\game\area\areas\ruins\space.dm" #include "code\game\area\areas\ruins\templates.dm" #include "code\game\area\areas\ruins\wasteplanet.dm" +#include "code\game\atom\atom_orbit.dm" #include "code\game\gamemodes\events.dm" #include "code\game\gamemodes\game_mode.dm" #include "code\game\gamemodes\objective.dm" diff --git a/tgui/packages/tgui/interfaces/Orbit.js b/tgui/packages/tgui/interfaces/Orbit.js deleted file mode 100644 index 91bf9d1f7929..000000000000 --- a/tgui/packages/tgui/interfaces/Orbit.js +++ /dev/null @@ -1,218 +0,0 @@ -import { createSearch } from 'common/string'; -import { multiline } from 'common/string'; -import { resolveAsset } from '../assets'; -import { useBackend, useLocalState } from '../backend'; -import { - Box, - Button, - Divider, - Flex, - Icon, - Input, - Section, -} from '../components'; -import { Window } from '../layouts'; - -const PATTERN_NUMBER = / \(([0-9]+)\)$/; - -const searchFor = (searchText) => - createSearch(searchText, (thing) => thing.name); - -const compareString = (a, b) => (a < b ? -1 : a > b); - -const compareNumberedText = (a, b) => { - const aName = a.name; - const bName = b.name; - - // Check if aName and bName are the same except for a number at the end - // e.g. Medibot (2) and Medibot (3) - const aNumberMatch = aName.match(PATTERN_NUMBER); - const bNumberMatch = bName.match(PATTERN_NUMBER); - - if ( - aNumberMatch && - bNumberMatch && - aName.replace(PATTERN_NUMBER, '') === bName.replace(PATTERN_NUMBER, '') - ) { - const aNumber = parseInt(aNumberMatch[1], 10); - const bNumber = parseInt(bNumberMatch[1], 10); - - return aNumber - bNumber; - } - - return compareString(aName, bName); -}; - -const BasicSection = (props, context) => { - const { act } = useBackend(context); - const { searchText, source, title } = props; - const things = source.filter(searchFor(searchText)); - things.sort(compareNumberedText); - return ( - source.length > 0 && ( -
- {things.map((thing) => ( -
- ) - ); -}; - -const OrbitedButton = (props, context) => { - const { act } = useBackend(context); - const { color, thing } = props; - - return ( - - ); -}; - -export const Orbit = (props, context) => { - const { act, data } = useBackend(context); - const { alive, antagonists, auto_observe, dead, ghosts, misc, npcs } = data; - - const [searchText, setSearchText] = useLocalState(context, 'searchText', ''); - - const collatedAntagonists = {}; - for (const antagonist of antagonists) { - if (collatedAntagonists[antagonist.antag] === undefined) { - collatedAntagonists[antagonist.antag] = []; - } - collatedAntagonists[antagonist.antag].push(antagonist); - } - - const sortedAntagonists = Object.entries(collatedAntagonists); - sortedAntagonists.sort((a, b) => { - return compareString(a[0], b[0]); - }); - - const orbitMostRelevant = (searchText) => { - for (const source of [ - sortedAntagonists.map(([_, antags]) => antags), - alive, - ghosts, - dead, - npcs, - misc, - ]) { - const member = source - .filter(searchFor(searchText)) - .sort(compareNumberedText)[0]; - if (member !== undefined) { - act('orbit', { ref: member.ref }); - break; - } - } - }; - - return ( - - -
- - - - - - setSearchText(value)} - onEnter={(_, value) => orbitMostRelevant(value)} - /> - - - - - -
- {antagonists.length > 0 && ( -
- {sortedAntagonists.map(([name, antags]) => ( -
- {antags - .filter(searchFor(searchText)) - .sort(compareNumberedText) - .map((antag) => ( - - ))} -
- ))} -
- )} - -
- {alive - .filter(searchFor(searchText)) - .sort(compareNumberedText) - .map((thing) => ( - - ))} -
- -
- {ghosts - .filter(searchFor(searchText)) - .sort(compareNumberedText) - .map((thing) => ( - - ))} -
- - - - - - -
-
- ); -}; diff --git a/tgui/packages/tgui/interfaces/Orbit/OrbitContent.tsx b/tgui/packages/tgui/interfaces/Orbit/OrbitContent.tsx new file mode 100644 index 000000000000..f3c59a75e189 --- /dev/null +++ b/tgui/packages/tgui/interfaces/Orbit/OrbitContent.tsx @@ -0,0 +1,98 @@ +import { toTitleCase } from 'common/string'; + +import { useBackend } from '../../backend'; +import { NoticeBox, Section, Stack, Table, Tooltip } from '../../components'; + +import { getAntagCategories } from './helpers'; +import { AntagGroup, Observable, OrbitData } from './types'; +import { OrbitSection } from './OrbitSection'; + +type ContentSection = { + content: Observable[]; + title: string; + color?: string; +}; + +export const OrbitContent = (props, context) => { + const { act, data } = useBackend(context); + const { antagonists = [], critical = [] } = data; + const { searchText, autoObserve } = props; + + let antagGroups: AntagGroup[] = []; + if (antagonists.length) { + antagGroups = getAntagCategories(antagonists); + } + + const sections: readonly ContentSection[] = [ + { + content: data.alive, + title: 'Alive', + color: 'good', + }, + { + content: data.dead, + title: 'Dead', + }, + { + content: data.ghosts, + title: 'Ghosts', + }, + { + content: data.misc, + title: 'Misc', + }, + { + content: data.npcs, + title: 'NPCs', + }, + { + content: data.ships, + title: 'Ships', + }, + ]; + + return ( +
+ + {critical.map((crit) => ( + + act('orbit', { ref: crit.ref })} + > + + + {toTitleCase(crit.full_name)} + {crit.extra} + +
+
+
+ ))} + + {antagGroups.map(([title, members]) => ( + + ))} + + {sections.map((section) => ( + + ))} +
+
+ ); +}; diff --git a/tgui/packages/tgui/interfaces/Orbit/OrbitItem.tsx b/tgui/packages/tgui/interfaces/Orbit/OrbitItem.tsx new file mode 100644 index 000000000000..957104afa8b9 --- /dev/null +++ b/tgui/packages/tgui/interfaces/Orbit/OrbitItem.tsx @@ -0,0 +1,50 @@ +import { useBackend } from '../../backend'; +import { Stack, Button, Flex, Icon } from '../../components'; + +import { capitalizeFirst } from 'common/string'; + +import { getDisplayColor, getDisplayName } from './helpers'; +import { Antagonist, Observable, OrbitData } from './types'; + +type Props = { + item: Observable | Antagonist; + autoObserve: boolean; + color: string | undefined; +}; + +export const OrbitItem = (props: Props, context) => { + const { item, autoObserve, color } = props; + const { full_name, icon, job, name, orbiters, ref } = item; + + const { act, data } = useBackend(context); + const { orbiting } = data; + + const selected = ref === orbiting?.ref; + const validIcon = !!job && !!icon && icon !== 'hudunknown'; + + return ( + act('orbit', { auto_observe: autoObserve, ref })} + style={{ + display: 'flex', + }} + > + + + ); +}; diff --git a/tgui/packages/tgui/interfaces/Orbit/OrbitSection.tsx b/tgui/packages/tgui/interfaces/Orbit/OrbitSection.tsx new file mode 100644 index 000000000000..d27d9080e08d --- /dev/null +++ b/tgui/packages/tgui/interfaces/Orbit/OrbitSection.tsx @@ -0,0 +1,65 @@ +import { Collapsible, Flex, Tooltip } from '../../components'; +import { isJobOrNameMatch } from './helpers'; +import { OrbitItem } from './OrbitItem'; +import { OrbitTooltip } from './OrbitTooltip'; +import { Observable } from './types'; + +type Props = { + color?: string; + section: Observable[]; + title: string; + searchQuery: string; + autoObserve: boolean; +}; + +/** + * Displays a collapsible with a map of observable items. + * Filters the results if there is a provided search query. + */ +export const OrbitSection = (props: Props) => { + const { color, section = [], title, searchQuery, autoObserve } = props; + + const filteredSection = section.filter((observable) => + isJobOrNameMatch(observable, searchQuery) + ); + + if (!filteredSection.length) { + return null; + } + + return ( + + + {filteredSection.map((item) => { + const content = ( + + ); + + if (!item.health && !item.extra) { + return content; + } + + return ( + } + key={item.ref} + position="bottom-start" + > + {content} + + ); + })} + + + ); +}; diff --git a/tgui/packages/tgui/interfaces/Orbit/OrbitTooltip.tsx b/tgui/packages/tgui/interfaces/Orbit/OrbitTooltip.tsx new file mode 100644 index 000000000000..0a941dcb0fb5 --- /dev/null +++ b/tgui/packages/tgui/interfaces/Orbit/OrbitTooltip.tsx @@ -0,0 +1,57 @@ +import { LabeledList, NoticeBox } from '../../components'; +import { Antagonist, Observable } from './types'; + +type Props = { + item: Observable | Antagonist; +}; + +/** Displays some info on the mob as a tooltip. */ +export const OrbitTooltip = (props: Props) => { + const { item } = props; + const { extra, name, full_name, health, job } = item; + + let antag; + if ('antag' in item) { + antag = item.antag; + } + + const extraInfo = extra?.split(':'); + const displayHealth = !!health && health >= 0 ? `${health}%` : 'Critical'; + const showAFK = 'client' in item && !item.client; + + return ( + <> + + Last Known Data + + + {extraInfo ? ( + + {extraInfo[1]} + + ) : ( + <> + {!!name && ( + {name} + )} + {!!full_name && ( + + {full_name} + + )} + {!!job && {job}} + {!!antag && ( + {antag} + )} + {!!health && ( + + {displayHealth} + + )} + + )} + {showAFK && Away} + + + ); +}; diff --git a/tgui/packages/tgui/interfaces/Orbit/constants.ts b/tgui/packages/tgui/interfaces/Orbit/constants.ts new file mode 100644 index 000000000000..1edadc9bfe45 --- /dev/null +++ b/tgui/packages/tgui/interfaces/Orbit/constants.ts @@ -0,0 +1,8 @@ +export const HEALTH = { + Good: 69, // nice + Average: 19, + Bad: 0, + Crit: -30, + Dead: -100, + Ruined: -200, +} as const; diff --git a/tgui/packages/tgui/interfaces/Orbit/helpers.ts b/tgui/packages/tgui/interfaces/Orbit/helpers.ts new file mode 100644 index 000000000000..7046f784cd6c --- /dev/null +++ b/tgui/packages/tgui/interfaces/Orbit/helpers.ts @@ -0,0 +1,119 @@ +import { createSearch } from '../../../common/string'; + +import { HEALTH } from './constants'; +import { AntagGroup, Antagonist, Observable } from './types'; + +const PATTERN_NUMBER = / \(([0-9]+)\)$/; + +/** Return a map of strings with each antag in its antag_category */ +export const getAntagCategories = (antagonists: Antagonist[]): AntagGroup[] => { + const categories = new Map(); + + for (const player of antagonists) { + const { antag_group } = player; + + if (!categories.has(antag_group)) { + categories.set(antag_group, []); + } + categories.get(antag_group)!.push(player); + } + + const sorted = Array.from(categories.entries()).sort((a, b) => { + const lowerA = a[0].toLowerCase(); + const lowerB = b[0].toLowerCase(); + + if (lowerA < lowerB) return -1; + if (lowerA > lowerB) return 1; + return 0; + }); + + return sorted; +}; + +/** Returns a disguised name in case the person is wearing someone else's ID */ +export const getDisplayName = ( + full_name: string, + nickname?: string +): string => { + if (!nickname) { + return full_name; + } + + return nickname; +}; + +/** Displays color for buttons based on the health or orbiter count. */ +export const getDisplayColor = ( + item: Observable, + override?: string +): string => { + const { job, health, orbiters } = item; + + // Things like blob camera, etc + if (typeof health !== 'number') { + return override ? 'good' : 'grey'; + } + + // Players that are AFK + if ('client' in item && !item.client) { + return 'grey'; + } + + return getHealthColor(health); +}; + +/** Returns the display color for certain health percentages */ +const getHealthColor = (health: number): string => { + switch (true) { + case health > HEALTH.Good: + return 'good'; + case health > HEALTH.Average: + return 'average'; + default: + return 'bad'; + } +}; + +/** Checks if a full name or job title matches the search. */ +export const isJobOrNameMatch = ( + observable: Observable, + searchQuery: string +): boolean => { + if (!searchQuery) return true; + + const { full_name, job } = observable; + + return ( + full_name?.toLowerCase().includes(searchQuery?.toLowerCase()) || + job?.toLowerCase().includes(searchQuery?.toLowerCase()) || + false + ); +}; + +export const searchFor = (searchText) => + createSearch(searchText, (thing: Observable) => thing.full_name); + +export const compareString = (a, b) => (a < b ? -1 : a > b); + +export const compareNumberedText = (a, b) => { + const aName = a.name; + const bName = b.name; + + // Check if aName and bName are the same except for a number at the end + // e.g. Medibot (2) and Medibot (3) + const aNumberMatch = aName.match(PATTERN_NUMBER); + const bNumberMatch = bName.match(PATTERN_NUMBER); + + if ( + aNumberMatch && + bNumberMatch && + aName.replace(PATTERN_NUMBER, '') === bName.replace(PATTERN_NUMBER, '') + ) { + const aNumber = parseInt(aNumberMatch[1], 10); + const bNumber = parseInt(bNumberMatch[1], 10); + + return aNumber - bNumber; + } + + return compareString(aName, bName); +}; diff --git a/tgui/packages/tgui/interfaces/Orbit/index.tsx b/tgui/packages/tgui/interfaces/Orbit/index.tsx new file mode 100644 index 000000000000..f0854f7bfa69 --- /dev/null +++ b/tgui/packages/tgui/interfaces/Orbit/index.tsx @@ -0,0 +1,86 @@ +import { multiline } from '../../../common/string'; +import { useBackend, useLocalState } from '../../backend'; +import { Button, Divider, Flex, Icon, Input, Section } from '../../components'; +import { Window } from '../../layouts'; + +import { searchFor } from './helpers'; +import { OrbitData } from './types'; +import { OrbitContent } from './OrbitContent'; + +export const Orbit = (props, context) => { + const { act, data } = useBackend(context); + + const [searchText, setSearchText] = useLocalState(context, 'searchText', ''); + const [autoObserve, setAutoObserve] = useLocalState( + context, + 'autoObserve', + false + ); + + const orbitMostRelevant = () => { + const mostRelevant = [ + data.antagonists, + data.alive, + data.ghosts, + data.dead, + data.npcs, + data.misc, + data.ships, + ] + .flat() + .filter(searchFor(searchText)) + .sort()[0]; + + if (mostRelevant !== undefined) { + act('orbit', { ref: mostRelevant.ref }); + } + }; + + return ( + + +
+ + + + + + setSearchText(value)} + onEnter={(_, value) => orbitMostRelevant()} + /> + + + + + +
+ +
+
+ ); +}; diff --git a/tgui/packages/tgui/interfaces/Orbit/types.ts b/tgui/packages/tgui/interfaces/Orbit/types.ts new file mode 100644 index 000000000000..4912ae10db4c --- /dev/null +++ b/tgui/packages/tgui/interfaces/Orbit/types.ts @@ -0,0 +1,38 @@ +import { BooleanLike } from '../../../common/react'; + +export type Antagonist = Observable & { antag: string; antag_group: string }; + +export type AntagGroup = [string, Antagonist[]]; + +export type OrbitData = { + alive: Observable[]; + antagonists: Antagonist[]; + critical: Critical[]; + dead: Observable[]; + ghosts: Observable[]; + misc: Observable[]; + npcs: Observable[]; + ships: Observable[]; + orbiting: Observable | null; + autoObserve: boolean; +}; + +export type Observable = { + full_name: string; + ref: string; + // Optionals +} & Partial<{ + client: BooleanLike; + extra: string; + health: number; + icon: string; + job: string; + name: string; + orbiters: number; +}>; + +type Critical = { + extra: string; + full_name: string; + ref: string; +}; From ce35cdda0b8c684a4d4c121871732dd51dec54fd Mon Sep 17 00:00:00 2001 From: Changelogs Date: Wed, 25 Sep 2024 10:57:35 -0500 Subject: [PATCH 25/30] Automatic changelog generation for PR #3320 [ci skip] --- html/changelogs/AutoChangeLog-pr-3320.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-3320.yml diff --git a/html/changelogs/AutoChangeLog-pr-3320.yml b/html/changelogs/AutoChangeLog-pr-3320.yml new file mode 100644 index 000000000000..4832c9776c22 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-3320.yml @@ -0,0 +1,5 @@ +author: FalloutFalcon +changes: + - {rscadd: You can now see ships in the orbit menu and its alot prettier!} + - {code_imp: ported tg points of interest and a much improved orbit menu} +delete-after: true From ddbcb281c1ed2e83fc0b06bddecfb9a386455782 Mon Sep 17 00:00:00 2001 From: Jedi-Toothpaste <53096233+Jedi-Toothpaste@users.noreply.github.com> Date: Wed, 25 Sep 2024 21:32:46 +0100 Subject: [PATCH 26/30] kilo remap fixes (#3424) ## About The Pull Request Kilo remap was good, asides the fact there was not a reinforced window on the thrusters to stop it being spaced if you open the blast doors. However, this problem was self-solving as the blast doors were not connected to the new button. This fixes both issues by adding windows to the thrusters, and linking the button correctly. ![image](https://github.com/user-attachments/assets/852855b1-98a7-4850-bf05-f327c809913e) ![image](https://github.com/user-attachments/assets/1066b7e4-5bb2-41dd-be5f-aa1101df9a00) ## Changelog :cl: fix: Fixed the lack of windows for the Kilo's Thrusters, and fixed the broken link for the new blast doors. /:cl: --- _maps/shuttles/independent/independent_kilo.dmm | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/_maps/shuttles/independent/independent_kilo.dmm b/_maps/shuttles/independent/independent_kilo.dmm index 0dad29cb9f9b..35f955ff0b3d 100644 --- a/_maps/shuttles/independent/independent_kilo.dmm +++ b/_maps/shuttles/independent/independent_kilo.dmm @@ -22,6 +22,9 @@ dir = 4; id = "kilothrusters" }, +/obj/structure/window/reinforced{ + dir = 8 + }, /turf/open/floor/plating/airless, /area/ship/engineering) "av" = ( @@ -1581,6 +1584,9 @@ dir = 4; id = "kilothrusters" }, +/obj/structure/window/reinforced{ + dir = 8 + }, /turf/open/floor/plating, /area/ship/engineering) "MY" = ( @@ -1890,7 +1896,7 @@ /obj/effect/decal/cleanable/oil, /obj/machinery/button/door{ dir = 8; - id = "amogusthrusters"; + id = "kilothrusters"; name = "Thruster Lockdown"; pixel_x = 21 }, From 3f869318da50bb04241f389350db3f0ad60af111 Mon Sep 17 00:00:00 2001 From: Changelogs Date: Wed, 25 Sep 2024 15:43:55 -0500 Subject: [PATCH 27/30] Automatic changelog generation for PR #3424 [ci skip] --- html/changelogs/AutoChangeLog-pr-3424.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-3424.yml diff --git a/html/changelogs/AutoChangeLog-pr-3424.yml b/html/changelogs/AutoChangeLog-pr-3424.yml new file mode 100644 index 000000000000..8258d255a6c2 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-3424.yml @@ -0,0 +1,5 @@ +author: Jedi-Toothpaste +changes: + - {bugfix: "Fixed the lack of windows for the Kilo's Thrusters, and fixed the broken + link for the new blast doors."} +delete-after: true From 3d061395b682198f7b68a2c75b29e2f204709a3f Mon Sep 17 00:00:00 2001 From: Changelogs Date: Thu, 26 Sep 2024 01:01:48 +0000 Subject: [PATCH 28/30] Automatic changelog compile [ci skip] --- html/changelogs/AutoChangeLog-pr-3320.yml | 5 ----- html/changelogs/AutoChangeLog-pr-3330.yml | 4 ---- html/changelogs/AutoChangeLog-pr-3346.yml | 4 ---- html/changelogs/AutoChangeLog-pr-3352.yml | 5 ----- html/changelogs/AutoChangeLog-pr-3398.yml | 4 ---- html/changelogs/AutoChangeLog-pr-3408.yml | 5 ----- html/changelogs/AutoChangeLog-pr-3418.yml | 4 ---- html/changelogs/AutoChangeLog-pr-3420.yml | 4 ---- html/changelogs/AutoChangeLog-pr-3423.yml | 4 ---- html/changelogs/AutoChangeLog-pr-3424.yml | 5 ----- html/changelogs/archive/2024-09.yml | 20 ++++++++++++++++++++ 11 files changed, 20 insertions(+), 44 deletions(-) delete mode 100644 html/changelogs/AutoChangeLog-pr-3320.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-3330.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-3346.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-3352.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-3398.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-3408.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-3418.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-3420.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-3423.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-3424.yml diff --git a/html/changelogs/AutoChangeLog-pr-3320.yml b/html/changelogs/AutoChangeLog-pr-3320.yml deleted file mode 100644 index 4832c9776c22..000000000000 --- a/html/changelogs/AutoChangeLog-pr-3320.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: FalloutFalcon -changes: - - {rscadd: You can now see ships in the orbit menu and its alot prettier!} - - {code_imp: ported tg points of interest and a much improved orbit menu} -delete-after: true diff --git a/html/changelogs/AutoChangeLog-pr-3330.yml b/html/changelogs/AutoChangeLog-pr-3330.yml deleted file mode 100644 index 46e461f2f53f..000000000000 --- a/html/changelogs/AutoChangeLog-pr-3330.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: FalloutFalcon -changes: - - {rscadd: 'Ballistics now have a minimum recoil, not enough to mess up your shot!'} -delete-after: true diff --git a/html/changelogs/AutoChangeLog-pr-3346.yml b/html/changelogs/AutoChangeLog-pr-3346.yml deleted file mode 100644 index 46be6f8474b6..000000000000 --- a/html/changelogs/AutoChangeLog-pr-3346.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: FalloutFalcon -changes: - - {bugfix: ships now start closed. shiptesters be writing there memos and ship names.} -delete-after: true diff --git a/html/changelogs/AutoChangeLog-pr-3352.yml b/html/changelogs/AutoChangeLog-pr-3352.yml deleted file mode 100644 index 266106d74f64..000000000000 --- a/html/changelogs/AutoChangeLog-pr-3352.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: FalloutFalcon -changes: - - {rscadd: Added new blank shells for training drills!} - - {refactor: Minor refactor of design disks to reduce repeated code} -delete-after: true diff --git a/html/changelogs/AutoChangeLog-pr-3398.yml b/html/changelogs/AutoChangeLog-pr-3398.yml deleted file mode 100644 index 65eb77137267..000000000000 --- a/html/changelogs/AutoChangeLog-pr-3398.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: Gristlebee -changes: - - {bugfix: fixes wall deconstruction causing runtimes} -delete-after: true diff --git a/html/changelogs/AutoChangeLog-pr-3408.yml b/html/changelogs/AutoChangeLog-pr-3408.yml deleted file mode 100644 index f85514c5004c..000000000000 --- a/html/changelogs/AutoChangeLog-pr-3408.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: zimon9 -changes: - - {rscadd: Added fruit puree to vegan rations} - - {rscdel: Removed pizza crackers from vegan rations} -delete-after: true diff --git a/html/changelogs/AutoChangeLog-pr-3418.yml b/html/changelogs/AutoChangeLog-pr-3418.yml deleted file mode 100644 index b2b6703a1756..000000000000 --- a/html/changelogs/AutoChangeLog-pr-3418.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: generalthrax -changes: - - {balance: Most common accessories now fit on pants} -delete-after: true diff --git a/html/changelogs/AutoChangeLog-pr-3420.yml b/html/changelogs/AutoChangeLog-pr-3420.yml deleted file mode 100644 index 832736e59bfd..000000000000 --- a/html/changelogs/AutoChangeLog-pr-3420.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: generalthrax -changes: - - {rscadd: Exosuit Recharger machines are now available from cargo} -delete-after: true diff --git a/html/changelogs/AutoChangeLog-pr-3423.yml b/html/changelogs/AutoChangeLog-pr-3423.yml deleted file mode 100644 index 21c44ad0f32e..000000000000 --- a/html/changelogs/AutoChangeLog-pr-3423.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: generalthrax -changes: - - {balance: Rust Reds on the blackmarket are now available to a maximum of 3} -delete-after: true diff --git a/html/changelogs/AutoChangeLog-pr-3424.yml b/html/changelogs/AutoChangeLog-pr-3424.yml deleted file mode 100644 index 8258d255a6c2..000000000000 --- a/html/changelogs/AutoChangeLog-pr-3424.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: Jedi-Toothpaste -changes: - - {bugfix: "Fixed the lack of windows for the Kilo's Thrusters, and fixed the broken - link for the new blast doors."} -delete-after: true diff --git a/html/changelogs/archive/2024-09.yml b/html/changelogs/archive/2024-09.yml index d86f5c86c955..a90afebaaf94 100644 --- a/html/changelogs/archive/2024-09.yml +++ b/html/changelogs/archive/2024-09.yml @@ -170,3 +170,23 @@ SomeguyManperson: - bugfix: sawn off illestren/improvised shotgun stats are now consistent if they are spawned in +2024-09-26: + FalloutFalcon: + - rscadd: Added new blank shells for training drills! + - refactor: Minor refactor of design disks to reduce repeated code + - rscadd: Ballistics now have a minimum recoil, not enough to mess up your shot! + - bugfix: ships now start closed. shiptesters be writing there memos and ship names. + - rscadd: You can now see ships in the orbit menu and its alot prettier! + - code_imp: ported tg points of interest and a much improved orbit menu + Gristlebee: + - bugfix: fixes wall deconstruction causing runtimes + Jedi-Toothpaste: + - bugfix: Fixed the lack of windows for the Kilo's Thrusters, and fixed the broken + link for the new blast doors. + generalthrax: + - balance: Most common accessories now fit on pants + - rscadd: Exosuit Recharger machines are now available from cargo + - balance: Rust Reds on the blackmarket are now available to a maximum of 3 + zimon9: + - rscadd: Added fruit puree to vegan rations + - rscdel: Removed pizza crackers from vegan rations From d67e5e2b91ac23c03ebaf00d5d32db90fceb808c Mon Sep 17 00:00:00 2001 From: Imaginos16 <77556824+Imaginos16@users.noreply.github.com> Date: Thu, 26 Sep 2024 08:48:25 -0700 Subject: [PATCH 29/30] Makes a Slight Cosmetic Edit to Normal Rabbit Ears (#3443) ## About The Pull Request It's subtle but I did it mostly because the current version was bothering me for some god forsaken reason and I guess I'm a perfectionist. ![image](https://github.com/user-attachments/assets/f9fdfe82-d59e-40bd-94a3-4e19b678e2d6) ## Why It's Good For The Game I hate creating characters ## Changelog :cl: PositiveEntropy imageadd: Adjusts the inner part of the normal rabbit ears. /:cl: --- icons/mob/species/human/rabbit.dmi | Bin 1013 -> 1000 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/icons/mob/species/human/rabbit.dmi b/icons/mob/species/human/rabbit.dmi index fcc6599f735685713dabb3bf310c4d1e26339c1e..26f0cb080d22653f3ac9a61223c4a9c877225522 100644 GIT binary patch delta 745 zcmV$i?pxq@o`qVe&}9 zM}2~p?T02UmuD4G9oxaazD_G&?%+ycM|~!3t7t*0WGBkmE2e+@uDl_Ajn^ZkNh`id zEnh?HUh%Bj>rK@G0000000919;yvs{cn+*}N0~3$&J{7{y9+)B%kX->$Nc!MWvpk) zyi0C%U|1QPqUwUyueCYR&r#vpMN}yI`8Kn&x2uG82|tPID(_nl1KQ=>m4{O^Lm8O zX5WGO=&7hO2X|2wQ^tm(nH2xzf_8c`5puKbv4R>28vp2B9n!Jow$-00000NkvXXu0mjfHg8{w delta 758 zcmVl{`oHxo*4LYw0{{R30002|zpS^g6A>7&wZF=F`%C5Tc}(?1LHlSS((1GEnBbWA zm@LEVg%P3||WskQYKJjSIe!epktn96mhRb=b8EoA=*+n`G@ChbVy)a3dAWsj2A93F?M)vv96G;oXGSt_y$p(4mq&w63%_srAA(Kr-~b z@67#vj3592000000Dyz2CSM1TPrml&dFGEZVgLa6Ma*npFNAk}K-|HM-?;yX_zt~T zA1bz$ac?<9GTZ1MqS{!lK5j(;0002|4Kk7^E}eRL;o6ho5=oS#CVl}X@$$ku5(Gms zZZ$FS3)p|)WUvO&xitiS0KyA~egT}{!%qZ#|1YzGBK3?e2^y1l!S;w=8J#VJX^FlE zL1_~IgpXj2YIG+N)(PH*$Fwk8UYD>29bA0}Z1+xv=RT7gVCpsZtDv$CbuKWyU}4+D zf^QwTHvZG6EaNJZh|VA7>5~%v_ovycLdA$RNMP3i^(d;`=AH5V+=HMZ!VvN{O6bbQ9E@;O$GcLYUAqn+3#C*8yiMHA9 o8dGkzJyuX7U;_XE003$D2SExfS^H-GdjJ3c07*qoM6N<$f*}lQQUCw| From 58eb610c1c1c1b48e1b5c308682b2746982bd86a Mon Sep 17 00:00:00 2001 From: Changelogs Date: Thu, 26 Sep 2024 10:59:29 -0500 Subject: [PATCH 30/30] Automatic changelog generation for PR #3443 [ci skip] --- html/changelogs/AutoChangeLog-pr-3443.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-3443.yml diff --git a/html/changelogs/AutoChangeLog-pr-3443.yml b/html/changelogs/AutoChangeLog-pr-3443.yml new file mode 100644 index 000000000000..3fd19b120e6d --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-3443.yml @@ -0,0 +1,4 @@ +author: PositiveEntropy +changes: + - {imageadd: Adjusts the inner part of the normal rabbit ears.} +delete-after: true