From aa9d8763e43f331541190889d1784c8b024c6886 Mon Sep 17 00:00:00 2001 From: Ghosti <83688318+Gw0sty@users.noreply.github.com> Date: Thu, 26 Sep 2024 21:50:04 -0500 Subject: [PATCH 01/25] Fixing Delta botany layering issue (#3575) Was so ugly. Was so annoying. --- .../map_files/Deltastation/DeltaStation2.dmm | 58 +++++++++++++------ 1 file changed, 39 insertions(+), 19 deletions(-) diff --git a/_maps/map_files/Deltastation/DeltaStation2.dmm b/_maps/map_files/Deltastation/DeltaStation2.dmm index 2722d1256f0f..d7ba4ec6ac92 100644 --- a/_maps/map_files/Deltastation/DeltaStation2.dmm +++ b/_maps/map_files/Deltastation/DeltaStation2.dmm @@ -5787,11 +5787,11 @@ /turf/open/floor/iron, /area/station/cargo/storage) "bqC" = ( -/obj/machinery/seed_extractor, /obj/effect/turf_decal/bot, /obj/structure/railing{ dir = 1 }, +/obj/machinery/seed_extractor, /turf/open/floor/iron/dark, /area/station/service/hydroponics) "bqF" = ( @@ -50110,14 +50110,15 @@ /turf/open/floor/iron, /area/station/hallway/primary/fore) "lPs" = ( -/obj/machinery/biogenerator, /obj/effect/turf_decal/bot, /obj/structure/railing{ dir = 1 }, +/obj/machinery/biogenerator, /obj/structure/railing{ dir = 4; - layer = 4.1 + layer = 4.1; + pixel_x = 5 }, /turf/open/floor/iron/dark, /area/station/service/hydroponics) @@ -55073,7 +55074,9 @@ /turf/open/floor/iron, /area/station/service/hydroponics) "mZA" = ( -/obj/machinery/door/window/left/directional/west, +/obj/machinery/door/window/left/directional/west{ + name = "Hydroponics Center" + }, /obj/effect/turf_decal/tile/neutral/fourcorners, /obj/machinery/atmospherics/components/binary/pump{ dir = 8; @@ -61766,19 +61769,21 @@ /turf/open/floor/iron/dark, /area/station/science/explab) "oJj" = ( -/obj/structure/reagent_dispensers/watertank/high, -/obj/effect/turf_decal/delivery/white{ - color = "#52B4E9" - }, -/obj/item/reagent_containers/cup/watering_can, -/obj/item/reagent_containers/cup/watering_can, /obj/structure/railing{ dir = 4; - layer = 4.1 + layer = 4.1; + pixel_x = 5 + }, +/obj/effect/turf_decal/delivery/white{ + color = "#52B4E9" }, /obj/structure/railing{ - dir = 1 + dir = 1; + pixel_x = 5 }, +/obj/structure/reagent_dispensers/watertank/high, +/obj/item/reagent_containers/cup/watering_can, +/obj/item/reagent_containers/cup/watering_can, /turf/open/floor/iron/dark/textured, /area/station/service/hydroponics) "oJy" = ( @@ -70630,13 +70635,17 @@ /obj/effect/turf_decal/delivery/white{ color = "#52B4E9" }, -/obj/machinery/composters, /obj/structure/railing{ - dir = 1 + dir = 1; + pixel_x = -5 }, /obj/structure/railing{ dir = 8; - layer = 4.1 + layer = 4.1; + pixel_x = -5 + }, +/obj/machinery/composters{ + pixel_x = -1 }, /turf/open/floor/iron/dark/textured, /area/station/service/hydroponics) @@ -81018,7 +81027,9 @@ pixel_x = 32 }, /obj/structure/table/wood/fancy/blue, -/obj/machinery/door/window/left/directional/west, +/obj/machinery/door/window/left/directional/west{ + name = "Hydroponics Center" + }, /obj/structure/window/reinforced/spawner/directional/south, /turf/open/floor/wood/tile, /area/station/service/library/artgallery) @@ -92157,14 +92168,15 @@ /turf/open/floor/iron, /area/station/hallway/secondary/exit/departure_lounge) "vZo" = ( -/obj/machinery/smartfridge, /obj/effect/turf_decal/bot, /obj/structure/railing{ dir = 1 }, +/obj/machinery/smartfridge, /obj/structure/railing{ dir = 8; - layer = 4.1 + layer = 4.1; + pixel_x = -5 }, /turf/open/floor/iron/dark, /area/station/service/hydroponics) @@ -97705,6 +97717,11 @@ /obj/effect/turf_decal/tile/blue{ dir = 4 }, +/obj/structure/railing{ + dir = 4; + layer = 4.1; + pixel_x = 5 + }, /turf/open/floor/iron, /area/station/service/hydroponics) "xpr" = ( @@ -100797,7 +100814,10 @@ "yba" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/door/window/right/directional/west{ +/obj/machinery/door/window/left/directional/west{ + name = "Hydroponics Center" + }, +/obj/machinery/door/window/left/directional/west{ name = "Hydroponics Center" }, /turf/open/floor/iron/dark, From 01e12ed815d52dae86ff41c7a10c9ceb1be84387 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 27 Sep 2024 02:50:27 +0000 Subject: [PATCH 02/25] Automatic changelog for PR #3575 [ci skip] --- html/changelogs/AutoChangeLog-pr-3575.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-3575.yml diff --git a/html/changelogs/AutoChangeLog-pr-3575.yml b/html/changelogs/AutoChangeLog-pr-3575.yml new file mode 100644 index 000000000000..f9dead4a3db2 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-3575.yml @@ -0,0 +1,4 @@ +author: "Gw0sty" +delete-after: True +changes: + - bugfix: "Fix Delta's hydroponics railings to be on a lower layer than the machines" \ No newline at end of file From 4176cd153e40c605630de1d9fda90caa42dd9f31 Mon Sep 17 00:00:00 2001 From: Ghosti <83688318+Gw0sty@users.noreply.github.com> Date: Thu, 26 Sep 2024 21:50:37 -0500 Subject: [PATCH 03/25] Late Science department. (#3574) Theres no spawners for RD Sci sec and Robo. Only one for scientist --- _maps/map_files/tramstation/tramstation.dmm | 37 ++++++++++++++++++--- 1 file changed, 33 insertions(+), 4 deletions(-) diff --git a/_maps/map_files/tramstation/tramstation.dmm b/_maps/map_files/tramstation/tramstation.dmm index 410b5b4c822e..ea0799b0b000 100644 --- a/_maps/map_files/tramstation/tramstation.dmm +++ b/_maps/map_files/tramstation/tramstation.dmm @@ -2526,6 +2526,11 @@ "ajF" = ( /turf/open/floor/iron, /area/station/engineering/gravity_generator) +"ajG" = ( +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/effect/landmark/start/scientist, +/turf/open/floor/iron/dark, +/area/station/science/explab) "ajI" = ( /obj/effect/spawner/structure/window, /turf/open/floor/plating, @@ -6708,6 +6713,10 @@ }, /turf/open/floor/iron, /area/station/hallway/secondary/entry) +"bax" = ( +/obj/effect/landmark/start/scientist, +/turf/open/floor/glass/reinforced, +/area/station/science/research) "bay" = ( /obj/effect/decal/cleanable/dirt, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -7863,6 +7872,7 @@ /obj/effect/turf_decal/trimline/purple/filled/line{ dir = 1 }, +/obj/effect/landmark/start/roboticist, /turf/open/floor/iron, /area/station/science/robotics/lab) "buQ" = ( @@ -16035,6 +16045,7 @@ }, /obj/effect/turf_decal/trimline/red/filled/line, /obj/item/radio/intercom/directional/south, +/obj/effect/landmark/start/depsec/science, /turf/open/floor/iron, /area/station/security/checkpoint/science) "eal" = ( @@ -26974,6 +26985,7 @@ /obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ dir = 8 }, +/obj/effect/landmark/start/scientist, /turf/open/floor/iron/cafeteria, /area/station/science/breakroom) "hFJ" = ( @@ -29737,6 +29749,7 @@ /obj/structure/chair/office, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/structure/cable, +/obj/effect/landmark/start/scientist, /turf/open/floor/iron, /area/station/science/lower) "iyi" = ( @@ -33425,6 +33438,10 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/iron, /area/station/hallway/primary/tram/left) +"jFW" = ( +/obj/effect/landmark/start/roboticist, +/turf/open/floor/iron/white, +/area/station/science/robotics/lab) "jGa" = ( /obj/effect/turf_decal/trimline/brown/filled/line{ dir = 1 @@ -35771,6 +35788,10 @@ }, /turf/open/floor/iron, /area/station/engineering/atmos) +"ksh" = ( +/obj/effect/landmark/start/scientist, +/turf/open/floor/iron/white, +/area/station/science/ordnance) "ksq" = ( /obj/effect/mapping_helpers/airlock/access/all/service/general, /obj/effect/turf_decal/trimline/neutral/filled/line, @@ -43617,6 +43638,7 @@ /obj/structure/chair/office/light{ dir = 8 }, +/obj/effect/landmark/start/scientist, /turf/open/floor/iron/dark, /area/station/science/ordnance/testlab) "mQa" = ( @@ -43907,6 +43929,7 @@ "mWe" = ( /obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2, /obj/effect/turf_decal/tile/neutral/fourcorners, +/obj/effect/landmark/start/roboticist, /turf/open/floor/iron/dark, /area/station/science/robotics/lab) "mWj" = ( @@ -46231,6 +46254,7 @@ }, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/effect/landmark/start/depsec/science, /turf/open/floor/iron, /area/station/security/checkpoint/science) "nHW" = ( @@ -47704,6 +47728,7 @@ /obj/structure/disposalpipe/segment{ dir = 6 }, +/obj/effect/landmark/start/roboticist, /turf/open/floor/iron, /area/station/science/robotics/mechbay) "ogp" = ( @@ -56384,6 +56409,7 @@ /obj/structure/chair/office/light{ dir = 1 }, +/obj/effect/landmark/start/research_director, /turf/open/floor/glass/reinforced, /area/station/command/heads_quarters/rd) "qUF" = ( @@ -62792,6 +62818,7 @@ /obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ dir = 4 }, +/obj/effect/landmark/start/depsec/science, /turf/open/floor/iron, /area/station/security/checkpoint/science) "sVV" = ( @@ -77539,6 +77566,7 @@ /obj/structure/disposalpipe/segment{ dir = 4 }, +/obj/effect/landmark/start/scientist, /turf/open/floor/iron/white, /area/station/science/ordnance/office) "xBD" = ( @@ -78996,6 +79024,7 @@ /obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ dir = 1 }, +/obj/effect/landmark/start/depsec/science, /turf/open/floor/iron, /area/station/security/checkpoint/science) "ybX" = ( @@ -131564,7 +131593,7 @@ lkK aeg gPB qOo -qOo +ksh jGx aej oAn @@ -132848,7 +132877,7 @@ dWM frV frV rsQ -rmr +ajG xLN tho sQZ @@ -187578,7 +187607,7 @@ dzu doK uJH uJH -uJH +jFW ukS soq rsL @@ -191690,7 +191719,7 @@ cli oPf jRy odC -dzx +bax tqA rBb rrL From 60617acfe9b302527643311dec17ddcd45f8afc8 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 27 Sep 2024 02:51:01 +0000 Subject: [PATCH 04/25] Automatic changelog for PR #3574 [ci skip] --- html/changelogs/AutoChangeLog-pr-3574.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-3574.yml diff --git a/html/changelogs/AutoChangeLog-pr-3574.yml b/html/changelogs/AutoChangeLog-pr-3574.yml new file mode 100644 index 000000000000..bf7e007d8641 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-3574.yml @@ -0,0 +1,4 @@ +author: "Gw0sty" +delete-after: True +changes: + - rscadd: "Added spawners for Science security officers, Research Directors, robotists, and scientists on Tram Station." \ No newline at end of file From 3cc4b077db027e3269eba31f84f8f9c41c31f3db Mon Sep 17 00:00:00 2001 From: Lucy Date: Thu, 26 Sep 2024 22:54:21 -0400 Subject: [PATCH 05/25] Antag selection weighting fixups (#3481) * Antag selection weighting fixups * various misc storyteller code fixups * improve antag cap logic * fix most antags not being counted at all --- code/__DEFINES/antagonists.dm | 8 +++- code/controllers/master.dm | 2 +- .../antagonists/_common/antag_datum.dm | 2 +- code/modules/antagonists/abductor/abductor.dm | 1 + code/modules/antagonists/blob/blob_minion.dm | 1 + code/modules/antagonists/brother/brother.dm | 1 + .../changeling/fallen_changeling.dm | 1 + .../antagonists/heretic/heretic_monsters.dm | 1 + .../antagonists/magic_servant/servant.dm | 1 + code/modules/antagonists/pirate/pirate.dm | 1 + .../antagonists/pyro_slime/pyro_slime.dm | 1 + .../revolution/enemy_of_the_revolution.dm | 1 + .../sentient_creature/sentient_creature.dm | 1 + .../antagonists/space_dragon/space_carp.dm | 1 + .../venus_human_trap/venus_human_trap.dm | 1 + .../antagonists/wishgranter/wishgranter.dm | 1 + code/modules/antagonists/wizard/wizard.dm | 1 + code/modules/antagonists/xeno/xeno.dm | 1 + .../bitrunning/antagonists/cyber_police.dm | 1 + .../events/ghost_role/alien_infestation.dm | 21 +++++---- monkestation/code/__DEFINES/antag_defines.dm | 2 - .../code/controllers/subsystem/job.dm | 23 ++++++--- .../antagonists/_common/antag_datum.dm | 2 - .../clock_cult/antag_datums/clock_cultist.dm | 1 + .../antagonists/evil_clone/evil_clone.dm | 1 + .../bloodsucker/bloodsucker_shaded.dm | 1 + .../modules/bloodsuckers/vassals/ex_vassal.dm | 1 + .../bloodsuckers/vassals/vassal_datum.dm | 1 + .../storytellers/antag_rep/helper_procs.dm | 18 +++---- .../converted_events/_base_event.dm | 33 +++++++------ .../solo/ghosts/paradox_clone.dm | 22 ++++----- .../storytellers/gamemode_subsystem.dm | 47 +++++++++---------- .../storytellers/storytellers/_storyteller.dm | 2 +- .../disease/symtoms/restricted/stage1.dm | 6 ++- tgstation.dme | 1 - 35 files changed, 119 insertions(+), 91 deletions(-) delete mode 100644 monkestation/code/__DEFINES/antag_defines.dm diff --git a/code/__DEFINES/antagonists.dm b/code/__DEFINES/antagonists.dm index 65aaa36fbb9f..020efe8d0858 100644 --- a/code/__DEFINES/antagonists.dm +++ b/code/__DEFINES/antagonists.dm @@ -342,7 +342,13 @@ GLOBAL_LIST_INIT(human_invader_antagonists, list( #define HUNTER_PACK_PSYKER "Psyker Shikaris" // This flag disables certain checks that presume antagonist datums mean 'baddie'. -#define FLAG_FAKE_ANTAG (1 << 0) +#define FLAG_FAKE_ANTAG (1 << 0) +/// monkestation addition: Whether the antagonist can see exploitable info on people they examine. +#define FLAG_CAN_SEE_EXPOITABLE_INFO (1 << 1) +// monkestation addition: The storyteller will ignore this antag datum as counting against the antag cap. +#define FLAG_ANTAG_CAP_IGNORE (1 << 2) +// monkestation addition: The storyteller will count everyone on this antag's team as a singular antag instead. +#define FLAG_ANTAG_CAP_TEAM (1 << 3) #define FREEDOM_IMPLANT_CHARGES 4 diff --git a/code/controllers/master.dm b/code/controllers/master.dm index 5634f11b172c..5fb06027a5fc 100644 --- a/code/controllers/master.dm +++ b/code/controllers/master.dm @@ -287,7 +287,7 @@ GLOBAL_REAL(Master, /datum/controller/master) if(sleep_offline_after_initializations && CONFIG_GET(flag/resume_after_initializations)) world.sleep_offline = FALSE initializations_finished_with_no_players_logged_in = initialized_tod < REALTIMEOFDAY - 10 - SSgamemode.handle_picking_stroyteller() //monkestation edit + SSgamemode.handle_picking_storyteller() //monkestation edit /** * Initialize a given subsystem and handle the results. diff --git a/code/modules/antagonists/_common/antag_datum.dm b/code/modules/antagonists/_common/antag_datum.dm index 19a346e3654c..9ea41eca4aba 100644 --- a/code/modules/antagonists/_common/antag_datum.dm +++ b/code/modules/antagonists/_common/antag_datum.dm @@ -54,7 +54,7 @@ GLOBAL_LIST_EMPTY(antagonists) /// The typepath for the outfit to show in the preview for the preferences menu. var/preview_outfit /// Flags for antags to turn on or off and check! - var/antag_flags = NONE + var/antag_flags = FLAG_CAN_SEE_EXPOITABLE_INFO // monkestation edit: allow antags to see exploitable info. /// If true, this antagonist can assign themself a new objective var/can_assign_self_objectives = FALSE /// Default to fill in when entering a custom objective. diff --git a/code/modules/antagonists/abductor/abductor.dm b/code/modules/antagonists/abductor/abductor.dm index d3d5bf24b66c..ed32ca368d5a 100644 --- a/code/modules/antagonists/abductor/abductor.dm +++ b/code/modules/antagonists/abductor/abductor.dm @@ -7,6 +7,7 @@ show_in_antagpanel = FALSE //should only show subtypes show_to_ghosts = TRUE suicide_cry = "FOR THE MOTHERSHIP!!" // They can't even talk but y'know + antag_flags = parent_type::antag_flags | FLAG_ANTAG_CAP_TEAM // monkestation addition var/datum/team/abductor_team/team var/sub_role var/outfit diff --git a/code/modules/antagonists/blob/blob_minion.dm b/code/modules/antagonists/blob/blob_minion.dm index 9bf37e961d5d..3e3f7647bcfd 100644 --- a/code/modules/antagonists/blob/blob_minion.dm +++ b/code/modules/antagonists/blob/blob_minion.dm @@ -4,6 +4,7 @@ show_name_in_check_antagonists = TRUE show_to_ghosts = TRUE show_in_antagpanel = FALSE + antag_flags = FLAG_ANTAG_CAP_IGNORE // monkestation addition /// The blob core that this minion is attached to var/datum/weakref/overmind diff --git a/code/modules/antagonists/brother/brother.dm b/code/modules/antagonists/brother/brother.dm index 8218544a305e..22991570da91 100644 --- a/code/modules/antagonists/brother/brother.dm +++ b/code/modules/antagonists/brother/brother.dm @@ -8,6 +8,7 @@ ui_name = "AntagInfoBrother" suicide_cry = "FOR MY BROTHER!!" antag_moodlet = /datum/mood_event/focused + antag_flags = parent_type::antag_flags | FLAG_ANTAG_CAP_TEAM // monkestation addition VAR_PRIVATE datum/team/brother_team/team diff --git a/code/modules/antagonists/changeling/fallen_changeling.dm b/code/modules/antagonists/changeling/fallen_changeling.dm index c44c1b66cd3d..ba5d3c3976ba 100644 --- a/code/modules/antagonists/changeling/fallen_changeling.dm +++ b/code/modules/antagonists/changeling/fallen_changeling.dm @@ -6,6 +6,7 @@ job_rank = ROLE_CHANGELING antag_moodlet = /datum/mood_event/fallen_changeling antag_hud_name = "changeling" + antag_flags = parent_type::antag_flags | FLAG_ANTAG_CAP_IGNORE // monkestation addition /datum/mood_event/fallen_changeling description = "My powers! Where are my powers?!" diff --git a/code/modules/antagonists/heretic/heretic_monsters.dm b/code/modules/antagonists/heretic/heretic_monsters.dm index 4e76b11c90c6..db220e93bd5d 100644 --- a/code/modules/antagonists/heretic/heretic_monsters.dm +++ b/code/modules/antagonists/heretic/heretic_monsters.dm @@ -8,6 +8,7 @@ antag_hud_name = "heretic_beast" suicide_cry = "MY MASTER SMILES UPON ME!!" show_in_antagpanel = FALSE + antag_flags = parent_type::antag_flags | FLAG_ANTAG_CAP_IGNORE // monkestation addition /// Our master (a heretic)'s mind. var/datum/mind/master diff --git a/code/modules/antagonists/magic_servant/servant.dm b/code/modules/antagonists/magic_servant/servant.dm index f6ecaf80cf6c..8851776213fe 100644 --- a/code/modules/antagonists/magic_servant/servant.dm +++ b/code/modules/antagonists/magic_servant/servant.dm @@ -3,6 +3,7 @@ show_in_roundend = FALSE show_in_antagpanel = FALSE show_name_in_check_antagonists = TRUE + antag_flags = parent_type::antag_flags | FLAG_ANTAG_CAP_IGNORE // monkestation addition /datum/antagonist/magic_servant/proc/setup_master(mob/M) var/datum/objective/O = new("Serve [M.real_name].") diff --git a/code/modules/antagonists/pirate/pirate.dm b/code/modules/antagonists/pirate/pirate.dm index d499a8034d80..8812de960ddd 100644 --- a/code/modules/antagonists/pirate/pirate.dm +++ b/code/modules/antagonists/pirate/pirate.dm @@ -7,6 +7,7 @@ show_to_ghosts = TRUE suicide_cry = "FOR ME MATEYS!!" hijack_speed = 2 // That is without doubt the worst pirate I have ever seen. + antag_flags = parent_type::antag_flags | FLAG_ANTAG_CAP_TEAM // monkestation addition var/datum/team/pirate/crew /datum/antagonist/pirate/greet() diff --git a/code/modules/antagonists/pyro_slime/pyro_slime.dm b/code/modules/antagonists/pyro_slime/pyro_slime.dm index aed278d261d9..7f63d0f5482f 100644 --- a/code/modules/antagonists/pyro_slime/pyro_slime.dm +++ b/code/modules/antagonists/pyro_slime/pyro_slime.dm @@ -5,6 +5,7 @@ show_in_antagpanel = FALSE show_name_in_check_antagonists = TRUE show_to_ghosts = TRUE + antag_flags = FLAG_ANTAG_CAP_IGNORE // monkestation addition /datum/antagonist/pyro_slime/on_gain() forge_objectives() diff --git a/code/modules/antagonists/revolution/enemy_of_the_revolution.dm b/code/modules/antagonists/revolution/enemy_of_the_revolution.dm index 93a205a02cd2..0e20463d4898 100644 --- a/code/modules/antagonists/revolution/enemy_of_the_revolution.dm +++ b/code/modules/antagonists/revolution/enemy_of_the_revolution.dm @@ -7,6 +7,7 @@ name = "\improper Enemy of the Revolution" show_in_antagpanel = FALSE suicide_cry = "FOR NANOTRASEN, NOW AND FOREVER!!" + antag_flags = parent_type::antag_flags | FLAG_ANTAG_CAP_IGNORE // monkestation addition /datum/antagonist/enemy_of_the_revolution/forge_objectives() var/datum/objective/survive/survive = new diff --git a/code/modules/antagonists/sentient_creature/sentient_creature.dm b/code/modules/antagonists/sentient_creature/sentient_creature.dm index 4b68a288be12..000fa8b51aff 100644 --- a/code/modules/antagonists/sentient_creature/sentient_creature.dm +++ b/code/modules/antagonists/sentient_creature/sentient_creature.dm @@ -4,6 +4,7 @@ show_in_roundend = FALSE count_against_dynamic_roll_chance = FALSE ui_name = "AntagInfoSentient" + antag_flags = FLAG_ANTAG_CAP_IGNORE // monkestation addition /datum/antagonist/sentient_creature/get_preview_icon() var/icon/final_icon = icon('icons/mob/simple/pets.dmi', "corgi") diff --git a/code/modules/antagonists/space_dragon/space_carp.dm b/code/modules/antagonists/space_dragon/space_carp.dm index 0d06ea3991d9..ad84d0ee4337 100644 --- a/code/modules/antagonists/space_dragon/space_carp.dm +++ b/code/modules/antagonists/space_dragon/space_carp.dm @@ -5,6 +5,7 @@ show_in_antagpanel = FALSE show_name_in_check_antagonists = TRUE show_to_ghosts = TRUE + antag_flags = FLAG_ANTAG_CAP_IGNORE // monkestation addition /// The rift to protect var/datum/weakref/rift diff --git a/code/modules/antagonists/venus_human_trap/venus_human_trap.dm b/code/modules/antagonists/venus_human_trap/venus_human_trap.dm index c84f20d05965..04ffc1dcd51c 100644 --- a/code/modules/antagonists/venus_human_trap/venus_human_trap.dm +++ b/code/modules/antagonists/venus_human_trap/venus_human_trap.dm @@ -5,6 +5,7 @@ show_in_antagpanel = FALSE show_name_in_check_antagonists = TRUE show_to_ghosts = TRUE + antag_flags = FLAG_ANTAG_CAP_IGNORE // monkestation addition /datum/antagonist/venus_human_trap/on_gain() forge_objectives() diff --git a/code/modules/antagonists/wishgranter/wishgranter.dm b/code/modules/antagonists/wishgranter/wishgranter.dm index bfac673535af..d27ad3df8a10 100644 --- a/code/modules/antagonists/wishgranter/wishgranter.dm +++ b/code/modules/antagonists/wishgranter/wishgranter.dm @@ -4,6 +4,7 @@ show_name_in_check_antagonists = TRUE hijack_speed = 2 //You literally are here to do nothing else. Might as well be fast about it. suicide_cry = "HAHAHAHAHA!!" + antag_flags = parent_type::antag_flags | FLAG_ANTAG_CAP_IGNORE // monkestation addition /datum/antagonist/wishgranter/forge_objectives() var/datum/objective/hijack/hijack = new diff --git a/code/modules/antagonists/wizard/wizard.dm b/code/modules/antagonists/wizard/wizard.dm index f86c46f83b6c..f3f6c810baa9 100644 --- a/code/modules/antagonists/wizard/wizard.dm +++ b/code/modules/antagonists/wizard/wizard.dm @@ -38,6 +38,7 @@ GLOBAL_LIST_EMPTY(wizard_spellbook_purchases_by_key) antag_hud_name = "apprentice" show_in_roundend = FALSE show_name_in_check_antagonists = TRUE + antag_flags = parent_type::antag_flags | FLAG_ANTAG_CAP_IGNORE // monkestation addition /// The wizard team this wizard minion is part of. var/datum/team/wizard/wiz_team diff --git a/code/modules/antagonists/xeno/xeno.dm b/code/modules/antagonists/xeno/xeno.dm index 115e40ca595c..eff0866999cf 100644 --- a/code/modules/antagonists/xeno/xeno.dm +++ b/code/modules/antagonists/xeno/xeno.dm @@ -66,6 +66,7 @@ return captive_team = new captive_team.progenitor = owner + antag_flags |= FLAG_ANTAG_CAP_IGNORE // monkestation edit: first captive xeno does not count against cap else if(!istype(new_team)) CRASH("Wrong xeno team type provided to create_team") diff --git a/code/modules/bitrunning/antagonists/cyber_police.dm b/code/modules/bitrunning/antagonists/cyber_police.dm index 73ff96ff7c8c..9d99520dec76 100644 --- a/code/modules/bitrunning/antagonists/cyber_police.dm +++ b/code/modules/bitrunning/antagonists/cyber_police.dm @@ -10,6 +10,7 @@ show_to_ghosts = TRUE suicide_cry = "ALT F4!" ui_name = "AntagInfoCyberAuth" + antag_flags = FLAG_ANTAG_CAP_IGNORE // monkestation addition /datum/antagonist/cyber_police/greet() . = ..() diff --git a/code/modules/events/ghost_role/alien_infestation.dm b/code/modules/events/ghost_role/alien_infestation.dm index 9b35b2145dcf..db3fd898e9ae 100644 --- a/code/modules/events/ghost_role/alien_infestation.dm +++ b/code/modules/events/ghost_role/alien_infestation.dm @@ -87,25 +87,26 @@ if(temp_vent_parent.other_atmos_machines.len > 20) vents += temp_vent - if(!vents.len) + if(!length(vents)) message_admins("An event attempted to spawn an alien but no suitable vents were found. Shutting down.") return MAP_ERROR - for(var/i in 1 to antag_count) - if(!length(candidates)) - break - - var/client/mob_client = pick_n_take_weighted(weighted_candidates) - var/mob/candidate = mob_client.mob - if(candidate.client) //I hate this - candidate.client.prefs.reset_antag_rep() + var/selected_count = 0 + while(length(weighted_candidates) && selected_count < antag_count) + var/client/candidate_ckey = pick_n_take_weighted(weighted_candidates) + var/client/candidate_client = GLOB.directory[candidate_ckey] + if(QDELETED(candidate_client) || QDELETED(candidate_client.mob)) + continue + var/mob/candidate = candidate_client.mob + candidate_client.prefs?.reset_antag_rep() if(!candidate.mind) candidate.mind = new /datum/mind(candidate.key) var/obj/vent = pick_n_take(vents) var/mob/living/carbon/alien/larva/new_xeno = new(vent.loc) - new_xeno.key = candidate.key + new_xeno.ckey = candidate_ckey new_xeno.move_into_vent(vent) + selected_count++ message_admins("[ADMIN_LOOKUPFLW(new_xeno)] has been made into an alien by an event.") new_xeno.log_message("was spawned as an alien by an event.", LOG_GAME) diff --git a/monkestation/code/__DEFINES/antag_defines.dm b/monkestation/code/__DEFINES/antag_defines.dm deleted file mode 100644 index 33358561c55a..000000000000 --- a/monkestation/code/__DEFINES/antag_defines.dm +++ /dev/null @@ -1,2 +0,0 @@ -/// Whether the antagonist can see exploitable info on people they examine. -#define FLAG_CAN_SEE_EXPOITABLE_INFO (1<<1) diff --git a/monkestation/code/controllers/subsystem/job.dm b/monkestation/code/controllers/subsystem/job.dm index cbe28992efda..d3ca62b5b386 100644 --- a/monkestation/code/controllers/subsystem/job.dm +++ b/monkestation/code/controllers/subsystem/job.dm @@ -65,9 +65,10 @@ mass_adjust_antag_rep(cliented_list, 1) var/list/weighted_candidates = return_antag_rep_weight(candidates) - var/antag_selection_loops = SSgamemode.current_roundstart_event.get_antag_amount() - for(var/i in 1 to antag_selection_loops) + var/iter = 0 + while(iter < antag_selection_loops) + iter++ if(antag_selection_loops >= 100) log_storyteller("h_r_a failed, antag_selection_loops went over 100") return FALSE @@ -78,7 +79,11 @@ log_storyteller("h_r_a failed, below required candidates for selected roundstart event") return FALSE break - var/client/dead_client = pick_n_take_weighted(weighted_candidates) + var/candidate_ckey = pick_n_take_weighted(weighted_candidates) + var/client/dead_client = GLOB.directory[candidate_ckey] + if(QDELETED(dead_client)) + antag_selection_loops++ + continue var/mob/dead/new_player/candidate = dead_client.mob if(!candidate.mind || !istype(candidate)) antag_selection_loops++ @@ -105,12 +110,16 @@ continue var/mob/dead/new_player/candidate var/sanity = 0 - while(!candidate && length(weighted_candidates) && !sanity >= 100) + while(QDELETED(candidate) && length(weighted_candidates) && sanity < 100) sanity++ - candidate = pick_n_take_weighted(weighted_candidates) - if(!candidate.mind || !istype(candidate)) + var/candidate_ckey = pick_n_take_weighted(weighted_candidates) + var/client/candidate_client = GLOB.directory[candidate_ckey] + if(QDELETED(candidate_client)) + continue + candidate = candidate_client.mob + if(!isnewplayer(candidate) || QDELING(candidate) || QDELETED(candidate.mind)) candidate = null - if(!candidate) + if(QDELETED(candidate)) if(length(SSgamemode.roundstart_antag_minds) < SSgamemode.current_roundstart_event.base_antags) log_storyteller("h_r_a failed, removing unassigned antag player put us below current event minimum candidates and we were unable to find a replacement") return FALSE diff --git a/monkestation/code/modules/antagonists/_common/antag_datum.dm b/monkestation/code/modules/antagonists/_common/antag_datum.dm index 5995594cf332..177b48b11b54 100644 --- a/monkestation/code/modules/antagonists/_common/antag_datum.dm +++ b/monkestation/code/modules/antagonists/_common/antag_datum.dm @@ -1,6 +1,4 @@ /datum/antagonist - /// Allows antags to check exploitable info - antag_flags = FLAG_CAN_SEE_EXPOITABLE_INFO ///The list of keys that are valid to see our antag hud/of huds we can see var/list/hud_keys /// If this antagonist should be removed from the crew manifest upon gain. diff --git a/monkestation/code/modules/antagonists/clock_cult/antag_datums/clock_cultist.dm b/monkestation/code/modules/antagonists/clock_cult/antag_datums/clock_cultist.dm index 3c4ff85f2aa8..22beb4158965 100644 --- a/monkestation/code/modules/antagonists/clock_cult/antag_datums/clock_cultist.dm +++ b/monkestation/code/modules/antagonists/clock_cult/antag_datums/clock_cultist.dm @@ -203,6 +203,7 @@ /datum/antagonist/clock_cultist/eminence name = "Eminence" + antag_flags = parent_type::antag_flags | FLAG_ANTAG_CAP_IGNORE give_slab = FALSE antag_moodlet = null communicate = null diff --git a/monkestation/code/modules/antagonists/evil_clone/evil_clone.dm b/monkestation/code/modules/antagonists/evil_clone/evil_clone.dm index a3b4bc9591db..f9616c0fa198 100644 --- a/monkestation/code/modules/antagonists/evil_clone/evil_clone.dm +++ b/monkestation/code/modules/antagonists/evil_clone/evil_clone.dm @@ -5,6 +5,7 @@ antagpanel_category = "Evil Clones" show_name_in_check_antagonists = TRUE show_to_ghosts = TRUE + antag_flags = parent_type::antag_flags | FLAG_ANTAG_CAP_IGNORE /datum/antagonist/evil_clone/greet() . = ..() diff --git a/monkestation/code/modules/bloodsuckers/bloodsucker/bloodsucker_shaded.dm b/monkestation/code/modules/bloodsuckers/bloodsucker/bloodsucker_shaded.dm index ecaaaae89223..8384c6b6c1be 100644 --- a/monkestation/code/modules/bloodsuckers/bloodsucker/bloodsucker_shaded.dm +++ b/monkestation/code/modules/bloodsuckers/bloodsucker/bloodsucker_shaded.dm @@ -5,6 +5,7 @@ show_in_roundend = FALSE job_rank = ROLE_BLOODSUCKER antag_hud_name = "bloodsucker" + antag_flags = parent_type::antag_flags | FLAG_ANTAG_CAP_IGNORE /obj/item/soulstone/bloodsucker theme = THEME_WIZARD diff --git a/monkestation/code/modules/bloodsuckers/vassals/ex_vassal.dm b/monkestation/code/modules/bloodsuckers/vassals/ex_vassal.dm index 0599972c219e..977ccdf851f8 100644 --- a/monkestation/code/modules/bloodsuckers/vassals/ex_vassal.dm +++ b/monkestation/code/modules/bloodsuckers/vassals/ex_vassal.dm @@ -12,6 +12,7 @@ silent = TRUE ui_name = FALSE hud_icon = 'monkestation/icons/bloodsuckers/bloodsucker_icons.dmi' + antag_flags = FLAG_ANTAG_CAP_IGNORE ///The revenge vassal that brought us into the fold. var/datum/antagonist/vassal/revenge/revenge_vassal diff --git a/monkestation/code/modules/bloodsuckers/vassals/vassal_datum.dm b/monkestation/code/modules/bloodsuckers/vassals/vassal_datum.dm index c2dd662cce12..72acb40a6d79 100644 --- a/monkestation/code/modules/bloodsuckers/vassals/vassal_datum.dm +++ b/monkestation/code/modules/bloodsuckers/vassals/vassal_datum.dm @@ -8,6 +8,7 @@ roundend_category = "vassals" antagpanel_category = "Bloodsucker" job_rank = ROLE_BLOODSUCKER + antag_flags = parent_type::antag_flags | FLAG_ANTAG_CAP_IGNORE antag_hud_name = "vassal" show_in_roundend = FALSE hud_icon = 'monkestation/icons/bloodsuckers/bloodsucker_icons.dmi' diff --git a/monkestation/code/modules/storytellers/antag_rep/helper_procs.dm b/monkestation/code/modules/storytellers/antag_rep/helper_procs.dm index 5970239e1287..86f54be69e97 100644 --- a/monkestation/code/modules/storytellers/antag_rep/helper_procs.dm +++ b/monkestation/code/modules/storytellers/antag_rep/helper_procs.dm @@ -37,27 +37,21 @@ GLOBAL_LIST_INIT(blessed_ckeys, list( ///give it a list of clients and the value aswell if it should be affected by multipliers and let er rip /proc/mass_adjust_antag_rep(list/clients, value, mulitplier = TRUE) for(var/client/listed_client as anything in clients) - if(!listed_client.prefs || !IS_CLIENT_OR_MOCK(listed_client)) + if(!IS_CLIENT_OR_MOCK(listed_client) || QDELETED(listed_client) || QDELETED(listed_client.prefs)) continue listed_client.prefs.adjust_antag_rep(value, mulitplier) /proc/return_antag_rep_weight(list/candidates) - var/list/returning_list = list() + . = list() for(var/anything in candidates) var/client/client_source if(ismob(anything)) var/mob/mob = anything client_source = mob.client - if(IS_CLIENT_OR_MOCK(anything)) + else if(IS_CLIENT_OR_MOCK(anything)) client_source = anything - if(!client_source) + if(QDELETED(client_source) || !client_source.ckey) continue + .[client_source.ckey] = client_source.prefs?.antag_rep || 10 - returning_list += client_source - var/return_value = 10 - if(client_source.prefs?.antag_rep) - return_value = client_source.prefs.antag_rep - returning_list[client_source] = return_value - - log_antag_rep("Returned Weighted List of [length(returning_list)]", list("before_weight" = candidates, "after_weight" = returning_list)) - return returning_list + log_antag_rep("Returned Weighted List of [length(.)]", list("before_weight" = candidates, "after_weight" = .)) diff --git a/monkestation/code/modules/storytellers/converted_events/_base_event.dm b/monkestation/code/modules/storytellers/converted_events/_base_event.dm index 84ae021d7840..0faa795d6aa3 100644 --- a/monkestation/code/modules/storytellers/converted_events/_base_event.dm +++ b/monkestation/code/modules/storytellers/converted_events/_base_event.dm @@ -240,9 +240,12 @@ var/list/weighted_candidates = return_antag_rep_weight(possible_candidates) - while(length(possible_candidates) && length(candidates) < antag_count) //both of these pick_n_take from possible_candidates so this should be fine + while(length(weighted_candidates) && length(candidates) < antag_count) //both of these pick_n_take from weighted_candidates so this should be fine if(prompted_picking) - var/client/picked_client = pick_n_take_weighted(weighted_candidates) + var/picked_ckey = pick_n_take_weighted(weighted_candidates) + var/client/picked_client = GLOB.directory[picked_ckey] + if(QDELETED(picked_client)) + continue var/mob/picked_mob = picked_client.mob log_storyteller("Prompted antag event mob: [picked_mob], special role: [picked_mob.mind?.special_role ? picked_mob.mind.special_role : "none"]") if(picked_mob) @@ -258,9 +261,10 @@ show_candidate_amount = FALSE, ) else - if(!length(weighted_candidates)) - break - var/client/picked_client = pick_n_take_weighted(weighted_candidates) + var/picked_ckey = pick_n_take_weighted(weighted_candidates) + var/client/picked_client = GLOB.directory[picked_ckey] + if(QDELETED(picked_client)) + continue var/mob/picked_mob = picked_client.mob log_storyteller("Picked antag event mob: [picked_mob], special role: [picked_mob.mind?.special_role ? picked_mob.mind.special_role : "none"]") candidates |= picked_mob @@ -353,22 +357,21 @@ ) var/list/weighted_candidates = return_antag_rep_weight(candidates) + var/selected_count = 0 + while(length(weighted_candidates) && selected_count < antag_count) + var/candidate_ckey = pick_n_take_weighted(weighted_candidates) + var/client/candidate_client = GLOB.directory[candidate_ckey] + if(QDELETED(candidate_client) || QDELETED(candidate_client.mob)) + continue + var/mob/candidate = candidate_client.mob - for(var/i in 1 to antag_count) - if(!length(weighted_candidates)) - break - - var/client/mob_client = pick_n_take_weighted(weighted_candidates) - var/mob/candidate = mob_client.mob - - if(candidate.client) //I hate this - candidate.client.prefs.reset_antag_rep() + candidate_client.prefs?.reset_antag_rep() if(!candidate.mind) candidate.mind = new /datum/mind(candidate.key) - var/mob/living/carbon/human/new_human = make_body(candidate) new_human.mind.special_role = antag_flag new_human.mind.restricted_roles = restricted_roles setup_minds += new_human.mind + selected_count++ setup = TRUE diff --git a/monkestation/code/modules/storytellers/converted_events/solo/ghosts/paradox_clone.dm b/monkestation/code/modules/storytellers/converted_events/solo/ghosts/paradox_clone.dm index 8a1a3223575a..5721f446cf30 100644 --- a/monkestation/code/modules/storytellers/converted_events/solo/ghosts/paradox_clone.dm +++ b/monkestation/code/modules/storytellers/converted_events/solo/ghosts/paradox_clone.dm @@ -52,26 +52,24 @@ ) var/list/weighted_candidates = return_antag_rep_weight(candidates) - - for(var/i in 1 to antag_count) - if(!length(candidates)) - break - - var/client/mob_client = pick_n_take(weighted_candidates) - var/mob/candidate = mob_client.mob - - if(candidate.client) //I hate this - candidate.client.prefs.reset_antag_rep() - + var/selected_count = 0 + while(length(weighted_candidates) && selected_count < antag_count) + var/client/candidate_ckey = pick_n_take_weighted(weighted_candidates) + var/client/candidate_client = GLOB.directory[candidate_ckey] + if(QDELETED(candidate_client) || QDELETED(candidate_client.mob)) + continue + var/mob/candidate = candidate_client.mob + candidate_client.prefs?.reset_antag_rep() if(!candidate.mind) candidate.mind = new /datum/mind(candidate.key) clone_victim = find_original() new_human = duplicate_object(clone_victim, pick(possible_spawns)) - new_human.key = candidate.key + new_human.ckey = candidate_ckey new_human.mind.special_role = antag_flag new_human.mind.restricted_roles = restricted_roles setup_minds += new_human.mind + selected_count++ setup = TRUE diff --git a/monkestation/code/modules/storytellers/gamemode_subsystem.dm b/monkestation/code/modules/storytellers/gamemode_subsystem.dm index 561149220487..01275488fc43 100644 --- a/monkestation/code/modules/storytellers/gamemode_subsystem.dm +++ b/monkestation/code/modules/storytellers/gamemode_subsystem.dm @@ -157,8 +157,6 @@ SUBSYSTEM_DEF(gamemode) var/ran_roundstart = FALSE var/list/triggered_round_events = list() - var/total_valid_antags = 0 - /datum/controller/subsystem/gamemode/Initialize(time, zlevel) // Populate event pools for(var/track in event_tracks) @@ -233,20 +231,29 @@ SUBSYSTEM_DEF(gamemode) var/cap = FLOOR((total_number / ANTAG_CAP_DENOMINATOR), 1) + ANTAG_CAP_FLAT return cap -/// Whether events can inject more antagonists into the round -/datum/controller/subsystem/gamemode/proc/can_inject_antags() - total_valid_antags = 0 - for(var/mob/checked_mob in GLOB.mob_list) - if(!checked_mob.mind) +/datum/controller/subsystem/gamemode/proc/get_antag_count() + . = 0 + var/list/already_counted = list() // Never count the same mind twice + for(var/datum/antagonist/antag as anything in GLOB.antagonists) + if(QDELETED(antag) || QDELETED(antag.owner) || already_counted[antag.owner]) continue - if(!checked_mob.mind.special_role) + if(!antag.count_against_dynamic_roll_chance || (antag.antag_flags & (FLAG_FAKE_ANTAG | FLAG_ANTAG_CAP_IGNORE))) continue - if(checked_mob.stat == DEAD) + if(antag.antag_flags & FLAG_ANTAG_CAP_TEAM) + var/datum/team/antag_team = antag.get_team() + if(antag_team) + if(already_counted[antag_team]) + continue + already_counted[antag_team] = TRUE + var/mob/antag_mob = antag.owner.current + if(QDELETED(antag_mob) || !antag_mob.key || antag_mob.stat == DEAD || antag_mob.client?.is_afk()) continue - total_valid_antags++ - + already_counted[antag.owner] = TRUE + .++ - return (get_antag_cap() > total_valid_antags) +/// Whether events can inject more antagonists into the round +/datum/controller/subsystem/gamemode/proc/can_inject_antags() + return (get_antag_cap() > get_antag_count()) /// Gets candidates for antagonist roles. /datum/controller/subsystem/gamemode/proc/get_candidates(be_special, job_ban, observers, ready_newplayers, living_players, required_time, inherit_required_time = TRUE, midround_antag_pref, no_antags = TRUE, list/restricted_roles, list/required_roles) @@ -798,7 +805,9 @@ SUBSYSTEM_DEF(gamemode) point_thresholds[EVENT_TRACK_ROLESET] = CONFIG_GET(number/roleset_point_threshold) point_thresholds[EVENT_TRACK_OBJECTIVES] = CONFIG_GET(number/objectives_point_threshold) -/datum/controller/subsystem/gamemode/proc/handle_picking_stroyteller() +/datum/controller/subsystem/gamemode/proc/handle_picking_storyteller() + if(CONFIG_GET(flag/disable_storyteller)) + return if(length(GLOB.clients) > MAX_POP_FOR_STORYTELLER_VOTE) secret_storyteller = TRUE selected_storyteller = pick_weight(get_valid_storytellers(TRUE)) @@ -867,23 +876,13 @@ SUBSYSTEM_DEF(gamemode) /// Panel containing information, variables and controls about the gamemode and scheduled event /datum/controller/subsystem/gamemode/proc/admin_panel(mob/user) update_crew_infos() - total_valid_antags = 0 - for(var/mob/checked_mob in GLOB.mob_list) - if(!checked_mob.mind) - continue - if(!checked_mob.mind.special_role) - continue - if(checked_mob.stat == DEAD) - continue - total_valid_antags++ - var/round_started = SSticker.HasRoundStarted() var/list/dat = list() dat += "Storyteller: [storyteller ? "[storyteller.name]" : "None"] " dat += " HALT Storyteller Event Panel Set Storyteller Refresh" dat += "
Storyteller determines points gained, event chances, and is the entity responsible for rolling events." dat += "
Active Players: [active_players] (Head: [head_crew], Sec: [sec_crew], Eng: [eng_crew], Med: [med_crew])" - dat += "
Antagonist Count vs Maximum: [total_valid_antags] / [get_antag_cap()]" + dat += "
Antagonist Count vs Maximum: [get_antag_count()] / [get_antag_cap()]" dat += "
" dat += "Main" dat += " Variables" diff --git a/monkestation/code/modules/storytellers/storytellers/_storyteller.dm b/monkestation/code/modules/storytellers/storytellers/_storyteller.dm index 4e84d41d794d..bd6486890c67 100644 --- a/monkestation/code/modules/storytellers/storytellers/_storyteller.dm +++ b/monkestation/code/modules/storytellers/storytellers/_storyteller.dm @@ -122,7 +122,7 @@ var/list/valid_events = list() // Determine which events are valid to pick for(var/datum/round_event_control/event as anything in mode.event_pools[track]) - var/players_amt = get_active_player_count(alive_check = 1, afk_check = 1, human_check = 1) + var/players_amt = get_active_player_count(alive_check = TRUE, afk_check = TRUE, human_check = TRUE) if(event.can_spawn_event(players_amt)) if(QDELETED(event)) message_admins("[event.name] was deleted!") diff --git a/monkestation/code/modules/virology/disease/symtoms/restricted/stage1.dm b/monkestation/code/modules/virology/disease/symtoms/restricted/stage1.dm index ef13a61fc797..f63dace8b0ea 100644 --- a/monkestation/code/modules/virology/disease/symtoms/restricted/stage1.dm +++ b/monkestation/code/modules/virology/disease/symtoms/restricted/stage1.dm @@ -44,8 +44,9 @@ affected_mob.mind.transfer_to(new_mob) else new_mob.key = affected_mob.key - if(transformed_antag_datum) - new_mob.mind.add_antag_datum(transformed_antag_datum) + if(transformed_antag_datum && !QDELETED(new_mob.mind)) + var/datum/antagonist/given_antag = new_mob.mind.has_antag_datum(transformed_antag_datum) || new_mob.mind.add_antag_datum(transformed_antag_datum) + given_antag?.antag_flags |= FLAG_ANTAG_CAP_IGNORE // ensure they don't count against storyteller cap new_mob.name = affected_mob.real_name new_mob.real_name = new_mob.name new_mob.update_name_tag() @@ -78,6 +79,7 @@ name = "Xenomorph Transformation" new_form = /mob/living/carbon/alien/adult/hunter bantype = ROLE_ALIEN + transformed_antag_datum = /datum/antagonist/xeno /datum/symptom/transformation/slime name = "Advanced Mutation Transformation" diff --git a/tgstation.dme b/tgstation.dme index 4ea67be4cf5c..78cad90c04f4 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -5794,7 +5794,6 @@ #include "interface\fonts\tiny_unicode.dm" #include "interface\fonts\vcr_osd_mono.dm" #include "monkestation\code\__DEFINES\_module_defines.dm" -#include "monkestation\code\__DEFINES\antag_defines.dm" #include "monkestation\code\__DEFINES\projectile.dm" #include "monkestation\code\__DEFINES\signals.dm" #include "monkestation\code\__HELPERS\_lists.dm" From 70e381c566493258c1558faa618f80841fedaae4 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 27 Sep 2024 02:54:41 +0000 Subject: [PATCH 06/25] Automatic changelog for PR #3481 [ci skip] --- html/changelogs/AutoChangeLog-pr-3481.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-3481.yml diff --git a/html/changelogs/AutoChangeLog-pr-3481.yml b/html/changelogs/AutoChangeLog-pr-3481.yml new file mode 100644 index 000000000000..9bc8deb850d3 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-3481.yml @@ -0,0 +1,4 @@ +author: "Absolucy" +delete-after: True +changes: + - bugfix: "Fixed some logic relating to antag selection (roundstart, midround, and ghost roles), hopefully reducing hard deletes and potential issues." \ No newline at end of file From 04aa76d0c85f0aeabad4cdb7ec3da39a2ef70cd2 Mon Sep 17 00:00:00 2001 From: Changelogs Date: Fri, 27 Sep 2024 23:29:46 +0000 Subject: [PATCH 07/25] Automatic changelog compile [ci skip] --- html/changelogs/AutoChangeLog-pr-3481.yml | 4 ---- html/changelogs/AutoChangeLog-pr-3574.yml | 4 ---- html/changelogs/AutoChangeLog-pr-3575.yml | 4 ---- html/changelogs/archive/2024-09.yml | 6 ++++++ 4 files changed, 6 insertions(+), 12 deletions(-) delete mode 100644 html/changelogs/AutoChangeLog-pr-3481.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-3574.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-3575.yml diff --git a/html/changelogs/AutoChangeLog-pr-3481.yml b/html/changelogs/AutoChangeLog-pr-3481.yml deleted file mode 100644 index 9bc8deb850d3..000000000000 --- a/html/changelogs/AutoChangeLog-pr-3481.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Absolucy" -delete-after: True -changes: - - bugfix: "Fixed some logic relating to antag selection (roundstart, midround, and ghost roles), hopefully reducing hard deletes and potential issues." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-3574.yml b/html/changelogs/AutoChangeLog-pr-3574.yml deleted file mode 100644 index bf7e007d8641..000000000000 --- a/html/changelogs/AutoChangeLog-pr-3574.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Gw0sty" -delete-after: True -changes: - - rscadd: "Added spawners for Science security officers, Research Directors, robotists, and scientists on Tram Station." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-3575.yml b/html/changelogs/AutoChangeLog-pr-3575.yml deleted file mode 100644 index f9dead4a3db2..000000000000 --- a/html/changelogs/AutoChangeLog-pr-3575.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Gw0sty" -delete-after: True -changes: - - bugfix: "Fix Delta's hydroponics railings to be on a lower layer than the machines" \ No newline at end of file diff --git a/html/changelogs/archive/2024-09.yml b/html/changelogs/archive/2024-09.yml index c013a8be3fd8..8eec30d57a34 100644 --- a/html/changelogs/archive/2024-09.yml +++ b/html/changelogs/archive/2024-09.yml @@ -595,6 +595,12 @@ Absolucy: - bugfix: Fixed malkavian bloodsuckers not getting an objective when another bloodsucker breaks the masquerade. + - bugfix: Fixed some logic relating to antag selection (roundstart, midround, and + ghost roles), hopefully reducing hard deletes and potential issues. + Gw0sty: + - bugfix: Fix Delta's hydroponics railings to be on a lower layer than the machines + - rscadd: Added spawners for Science security officers, Research Directors, robotists, + and scientists on Tram Station. KnigTheThrasher: - rscadd: Added layer adapters to atmos - bugfix: Added cmo spawner to kilo From b71d1f63367b1d395d6143a53e6e7e72dfaef039 Mon Sep 17 00:00:00 2001 From: Lucy Date: Sat, 28 Sep 2024 01:04:16 -0400 Subject: [PATCH 08/25] Fixed lights stopping emitting light in some situations (#84299) (#3589) ## About The Pull Request closes #77789 edt: also closes #82600 Light sources stop emitting light if the tile in which the light source itself is located and all 4 adjacent tile block the light. This usually happens when a smoke grenade is thrown, or something went wrong in the chemistry again
Videos As it was before https://github.com/tgstation/tgstation/assets/112967882/44ff556b-d09f-4024-945e-c2c105f511a9 Now https://github.com/tgstation/tgstation/assets/112967882/9f9f8f43-47a9-47be-8499-99bab39fc166
## Why It's Good For The Game You wont need to switch the lights twice to make them work after someone threw smoke grenades into the hallways anymore ## Changelog :cl: fix: Fixed lights stopping emitting light in some situations /:cl: --------- Co-authored-by: Kocma-san <112967882+Kocma-san@users.noreply.github.com> Co-authored-by: Ghom <42542238+Ghommie@users.noreply.github.com> --- code/__DEFINES/dcs/signals/signals_turf.dm | 3 +++ code/modules/lighting/lighting_source.dm | 2 ++ code/modules/lighting/lighting_turf.dm | 3 +++ 3 files changed, 8 insertions(+) diff --git a/code/__DEFINES/dcs/signals/signals_turf.dm b/code/__DEFINES/dcs/signals/signals_turf.dm index 397345cc498d..1fd8bf3a318a 100644 --- a/code/__DEFINES/dcs/signals/signals_turf.dm +++ b/code/__DEFINES/dcs/signals/signals_turf.dm @@ -48,3 +48,6 @@ #define COMSIG_TURF_RESET_ELEVATION "turf_reset_elevation" #define ELEVATION_CURRENT_PIXEL_SHIFT 1 #define ELEVATION_MAX_PIXEL_SHIFT 2 + +///Called when turf no longer blocks light from passing through +#define COMSIG_TURF_NO_LONGER_BLOCK_LIGHT "turf_no_longer_block_light" diff --git a/code/modules/lighting/lighting_source.dm b/code/modules/lighting/lighting_source.dm index 3abfd151153f..7477c8296c11 100644 --- a/code/modules/lighting/lighting_source.dm +++ b/code/modules/lighting/lighting_source.dm @@ -88,6 +88,7 @@ //yes, we register the signal to the top atom too, this is intentional and ensures contained lighting updates properly if(ismovable(new_atom_host) && new_atom_host == source_atom) RegisterSignal(new_atom_host, COMSIG_MOVABLE_MOVED, PROC_REF(update_host_lights)) + RegisterSignal(new_atom_host, COMSIG_TURF_NO_LONGER_BLOCK_LIGHT, PROC_REF(force_update)) return TRUE ///remove this light source from old_atom_host's light_sources list, unsetting movement registrations @@ -98,6 +99,7 @@ LAZYREMOVE(old_atom_host.light_sources, src) if(ismovable(old_atom_host) && old_atom_host == source_atom) UnregisterSignal(old_atom_host, COMSIG_MOVABLE_MOVED) + UnregisterSignal(old_atom_host, COMSIG_TURF_NO_LONGER_BLOCK_LIGHT) return TRUE // Yes this doesn't align correctly on anything other than 4 width tabs. diff --git a/code/modules/lighting/lighting_turf.dm b/code/modules/lighting/lighting_turf.dm index d2400097c343..56e64dada77f 100644 --- a/code/modules/lighting/lighting_turf.dm +++ b/code/modules/lighting/lighting_turf.dm @@ -101,6 +101,9 @@ else //If fulltile and opaque, then the whole tile blocks view, no need to continue checking. directional_opacity = ALL_CARDINALS break + else + for(var/atom/movable/content as anything in contents) + SEND_SIGNAL(content, COMSIG_TURF_NO_LONGER_BLOCK_LIGHT) if(. != directional_opacity && (. == ALL_CARDINALS || directional_opacity == ALL_CARDINALS)) reconsider_lights() //The lighting system only cares whether the tile is fully concealed from all directions or not. reconsider_sunlight() //monkestation addition From d5af7a5a83a212782356261e5db07283574f1bc6 Mon Sep 17 00:00:00 2001 From: Lucy Date: Sat, 28 Sep 2024 01:04:31 -0400 Subject: [PATCH 09/25] more bugfixes wehhh (#3573) * fixes contents not being removed from the spatial grid when deleted during movement between 2 grid cells (#75658) ## About The Pull Request fixes the flaky test reports for cockroaches being stuck in the spatial grid (which mothblocks seems to have closed all of) cockroaches get deleted when they die, so theres a spurious unit test failure where if a cockroach is on a tile in grid cell A and moves to a lava tile in grid cell B, they will get killed when lava.Entered() is called, then deleted, and when /atom/movable/Destroy() is called we try to take them out of grid cell B (because their loc is the lava tile) but they were never added to that cell yet because their movement never finished, so that doesnt do anything. THEN moveToNullspace() is called, that movement finishes before the first movement, and then in Moved(old_loc = lava turf) we try to remove it from grid cell B which again doesnt work, and then the first movements Moved(old_loc = original turf) is called where we can actually remove them from the correct grid cell, except we cant because in exit_cell() we subtract `old_target.important_recursive_contents[channel]` from the cells content lists, and since the target is deleted by this point it doesnt have important_recursive_contents. so the fix here is changing this so it subtracts `old_target.important_recursive_contents?[type] || old_target` instead, which works if the target is deleted. also fixes some Entered() overrides that dont call parent and improves documentation on spatial grid defines ## Why It's Good For The Game fixes it without needing the change_loc() setter * Make accelerated particles use processing rather than sleeping and recursion * Simple fix for antitox symptom runtime * Fix pathogen runtime with null wearers * Some more runtime fixes (wow this code is garbage) --------- Co-authored-by: Kylerace --- code/__DEFINES/spatial_gridmap.dm | 11 +-- code/controllers/subsystem/spatial_gridmap.dm | 28 +++--- code/game/atoms_movable.dm | 5 +- code/game/objects/effects/decals/cleanable.dm | 12 ++- code/game/turfs/open/lava.dm | 1 + .../hostile/megafauna/colossus.dm | 1 + .../particle_accelerator/particle.dm | 86 ++++++++++--------- .../virology/disease/symtoms/stage2.dm | 4 +- .../virology/effects/pathogen_cloud.dm | 14 +-- 9 files changed, 85 insertions(+), 77 deletions(-) diff --git a/code/__DEFINES/spatial_gridmap.dm b/code/__DEFINES/spatial_gridmap.dm index f43fcbc3c6d3..97a6f9915399 100644 --- a/code/__DEFINES/spatial_gridmap.dm +++ b/code/__DEFINES/spatial_gridmap.dm @@ -1,12 +1,13 @@ -///each cell in a spatial_grid is this many turfs in length and width +/// each cell in a spatial_grid is this many turfs in length and width (with world.max(x or y) being 255, 15 of these fit on each side of a z level) #define SPATIAL_GRID_CELLSIZE 17 -///Takes a coordinate, and spits out the spatial grid index (x or y) it's inside +/// Takes a coordinate, and spits out the spatial grid index (x or y) it's inside #define GET_SPATIAL_INDEX(coord) ROUND_UP((coord) / SPATIAL_GRID_CELLSIZE) -#define GRID_INDEX_TO_COORDS(index) (index * SPATIAL_GRID_CELLSIZE) +/// changes the cell_(x or y) vars on /datum/spatial_grid_cell to the x or y coordinate on the map for the LOWER LEFT CORNER of the grid cell. +/// index is from 1 to SPATIAL_GRID_CELLS_PER_SIDE +#define GRID_INDEX_TO_COORDS(index) ((((index) - 1) * SPATIAL_GRID_CELLSIZE) + 1) +/// number of grid cells per x or y side of all z levels. pass in world.maxx or world.maxy #define SPATIAL_GRID_CELLS_PER_SIDE(world_bounds) GET_SPATIAL_INDEX(world_bounds) -#define SPATIAL_GRID_CHANNELS 2 - //grid contents channels ///everything that is hearing sensitive is stored in this channel diff --git a/code/controllers/subsystem/spatial_gridmap.dm b/code/controllers/subsystem/spatial_gridmap.dm index ef0495f0b43d..81ae29f6bad4 100644 --- a/code/controllers/subsystem/spatial_gridmap.dm +++ b/code/controllers/subsystem/spatial_gridmap.dm @@ -435,18 +435,18 @@ SUBSYSTEM_DEF(spatial_grid) for(var/type in spatial_grid_categories[old_target.spatial_grid_key]) switch(type) if(SPATIAL_GRID_CONTENTS_TYPE_CLIENTS) - var/list/old_target_contents = old_target.important_recursive_contents //cache for sanic speeds (lists are references anyways) - GRID_CELL_REMOVE(intersecting_cell.client_contents, old_target_contents[SPATIAL_GRID_CONTENTS_TYPE_CLIENTS]) - SEND_SIGNAL(intersecting_cell, SPATIAL_GRID_CELL_EXITED(SPATIAL_GRID_CONTENTS_TYPE_CLIENTS), old_target_contents[SPATIAL_GRID_CONTENTS_TYPE_CLIENTS]) + var/list/old_target_contents = old_target.important_recursive_contents?[type] || old_target + GRID_CELL_REMOVE(intersecting_cell.client_contents, old_target_contents) + SEND_SIGNAL(intersecting_cell, SPATIAL_GRID_CELL_EXITED(type), old_target_contents) if(SPATIAL_GRID_CONTENTS_TYPE_HEARING) - var/list/old_target_contents = old_target.important_recursive_contents //cache for sanic speeds (lists are references anyways) - GRID_CELL_REMOVE(intersecting_cell.hearing_contents, old_target_contents[SPATIAL_GRID_CONTENTS_TYPE_HEARING]) - SEND_SIGNAL(intersecting_cell, SPATIAL_GRID_CELL_EXITED(SPATIAL_GRID_CONTENTS_TYPE_HEARING), old_target_contents[SPATIAL_GRID_CONTENTS_TYPE_HEARING]) + var/list/old_target_contents = old_target.important_recursive_contents?[type] || old_target + GRID_CELL_REMOVE(intersecting_cell.hearing_contents, old_target_contents) + SEND_SIGNAL(intersecting_cell, SPATIAL_GRID_CELL_EXITED(type), old_target_contents) if(SPATIAL_GRID_CONTENTS_TYPE_ATMOS) GRID_CELL_REMOVE(intersecting_cell.atmos_contents, old_target) - SEND_SIGNAL(intersecting_cell, SPATIAL_GRID_CELL_EXITED(SPATIAL_GRID_CONTENTS_TYPE_ATMOS), old_target) + SEND_SIGNAL(intersecting_cell, SPATIAL_GRID_CELL_EXITED(type), old_target) return TRUE @@ -467,14 +467,14 @@ SUBSYSTEM_DEF(spatial_grid) switch(exclusive_type) if(SPATIAL_GRID_CONTENTS_TYPE_CLIENTS) - var/list/old_target_contents = old_target.important_recursive_contents //cache for sanic speeds (lists are references anyways) - GRID_CELL_REMOVE(intersecting_cell.client_contents, old_target_contents[SPATIAL_GRID_CONTENTS_TYPE_CLIENTS]) - SEND_SIGNAL(intersecting_cell, SPATIAL_GRID_CELL_EXITED(exclusive_type), old_target_contents[SPATIAL_GRID_CONTENTS_TYPE_CLIENTS]) + var/list/old_target_contents = old_target.important_recursive_contents?[exclusive_type] || old_target //cache for sanic speeds (lists are references anyways) + GRID_CELL_REMOVE(intersecting_cell.client_contents, old_target_contents) + SEND_SIGNAL(intersecting_cell, SPATIAL_GRID_CELL_EXITED(exclusive_type), old_target_contents) if(SPATIAL_GRID_CONTENTS_TYPE_HEARING) - var/list/old_target_contents = old_target.important_recursive_contents - GRID_CELL_REMOVE(intersecting_cell.hearing_contents, old_target_contents[SPATIAL_GRID_CONTENTS_TYPE_HEARING]) - SEND_SIGNAL(intersecting_cell, SPATIAL_GRID_CELL_EXITED(exclusive_type), old_target_contents[SPATIAL_GRID_CONTENTS_TYPE_HEARING]) + var/list/old_target_contents = old_target.important_recursive_contents?[exclusive_type] || old_target + GRID_CELL_REMOVE(intersecting_cell.hearing_contents, old_target_contents) + SEND_SIGNAL(intersecting_cell, SPATIAL_GRID_CELL_EXITED(exclusive_type), old_target_contents) if(SPATIAL_GRID_CONTENTS_TYPE_ATMOS) GRID_CELL_REMOVE(intersecting_cell.atmos_contents, old_target) @@ -565,7 +565,7 @@ SUBSYSTEM_DEF(spatial_grid) #ifdef UNIT_TESTS if(untracked_movable_error(to_remove)) - find_hanging_cell_refs_for_movable(to_remove, remove_from_cells=TRUE) + find_hanging_cell_refs_for_movable(to_remove, remove_from_cells=FALSE) //dont remove from cells because we should be able to see 2 errors return #endif diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm index dd6f53c6442d..77140b4be624 100644 --- a/code/game/atoms_movable.dm +++ b/code/game/atoms_movable.dm @@ -213,7 +213,7 @@ if(spatial_grid_key) SSspatial_grid.force_remove_from_cell(src) - LAZYCLEARLIST(client_mobs_in_contents) + LAZYNULL(client_mobs_in_contents) . = ..() @@ -225,7 +225,7 @@ //This absolutely must be after moveToNullspace() //We rely on Entered and Exited to manage this list, and the copy of this list that is on any /atom/movable "Containers" //If we clear this before the nullspace move, a ref to this object will be hung in any of its movable containers - LAZYCLEARLIST(important_recursive_contents) + LAZYNULL(important_recursive_contents) vis_locs = null //clears this atom out of all viscontents @@ -775,7 +775,6 @@ pulling.move_from_pull(src, target_turf, glide_size) check_pulling() - //glide_size strangely enough can change mid movement animation and update correctly while the animation is playing //This means that if you don't override it late like this, it will just be set back by the movement update that's called when you move turfs. if(glide_size_override) diff --git a/code/game/objects/effects/decals/cleanable.dm b/code/game/objects/effects/decals/cleanable.dm index 966f668d5eb7..260354cb7cac 100644 --- a/code/game/objects/effects/decals/cleanable.dm +++ b/code/game/objects/effects/decals/cleanable.dm @@ -43,7 +43,7 @@ for(var/datum/disease/D in diseases) if(D.spread_flags & (DISEASE_SPREAD_BLOOD)) src.diseases |= D - + AddElement(/datum/element/beauty, beauty) var/turf/T = get_turf(src) @@ -82,16 +82,14 @@ if(W.get_temperature()) //todo: make heating a reagent holder proc if(istype(W, /obj/item/clothing/mask/cigarette)) return - else - var/hotness = W.get_temperature() - reagents.expose_temperature(hotness) - to_chat(user, span_notice("You heat [name] with [W]!")) + var/hotness = W.get_temperature() + reagents?.expose_temperature(hotness) + to_chat(user, span_notice("You heat [name] with [W]!")) else return ..() /obj/effect/decal/cleanable/fire_act(exposed_temperature, exposed_volume) - if(reagents) - reagents.expose_temperature(exposed_temperature) + reagents?.expose_temperature(exposed_temperature) ..() diff --git a/code/game/turfs/open/lava.dm b/code/game/turfs/open/lava.dm index 1ba428e0f931..81f5cf73bee8 100644 --- a/code/game/turfs/open/lava.dm +++ b/code/game/turfs/open/lava.dm @@ -138,6 +138,7 @@ initial_gas_mix = AIRLESS_ATMOS /turf/open/lava/Entered(atom/movable/arrived, atom/old_loc, list/atom/old_locs) + . = ..() if(burn_stuff(arrived)) START_PROCESSING(SSobj, src) 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 34851c30a65a..0e8a8251e6f0 100644 --- a/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm +++ b/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm @@ -591,6 +591,7 @@ START_PROCESSING(SSobj, src) /obj/structure/closet/stasis/Entered(atom/movable/arrived, atom/old_loc, list/atom/old_locs) + . = ..() if(isliving(arrived) && holder_animal) var/mob/living/possessor = arrived possessor.add_traits(list(TRAIT_UNDENSE, TRAIT_NO_TRANSFORM), STASIS_MUTE) diff --git a/monkestation/code/modules/power/singularity/particle_accelerator/particle.dm b/monkestation/code/modules/power/singularity/particle_accelerator/particle.dm index 83db038d780f..be54d980e48c 100644 --- a/monkestation/code/modules/power/singularity/particle_accelerator/particle.dm +++ b/monkestation/code/modules/power/singularity/particle_accelerator/particle.dm @@ -8,6 +8,7 @@ var/movement_range = 10 var/energy = 10 var/speed = 1 + COOLDOWN_DECLARE(next_move) /obj/effect/accelerated_particle/weak movement_range = 8 @@ -21,39 +22,54 @@ movement_range = 20 energy = 50 - -/obj/effect/accelerated_particle/New(loc) - ..() - - addtimer(CALLBACK(src, PROC_REF(move)), 1) - - /obj/effect/accelerated_particle/Initialize(mapload) . = ..() - RegisterSignal(src, COMSIG_ATOM_ENTERED, PROC_REF(on_entered)) + if(QDELETED(loc)) + return INITIALIZE_HINT_QDEL + START_PROCESSING(SSactualfastprocess, src) -/obj/effect/accelerated_particle/Bump(atom/A) - if(A) - if(isliving(A)) - toxmob(A) - else if(istype(A, /obj/machinery/the_singularitygen)) - var/obj/machinery/the_singularitygen/S = A - S.energy += energy - else if(istype(A, /obj/singularity)) - var/obj/singularity/S = A - S.energy += energy - else if(istype(A, /obj/energy_ball)) - var/obj/energy_ball/S = A - S.energy += energy - else if(istype(A, /obj/structure/blob)) - var/obj/structure/blob/B = A - B.take_damage(energy*0.6) - movement_range = 0 +/obj/effect/accelerated_particle/Destroy(force) + STOP_PROCESSING(SSactualfastprocess, src) + return ..() -/obj/effect/accelerated_particle/proc/on_entered(datum/source, atom/movable/A, atom/old_loc, list/atom/old_locs) - if(isliving(A)) - toxmob(A) +/obj/effect/accelerated_particle/Bump(atom/bumped_atom) + if(QDELETED(bumped_atom)) + return + if(isliving(bumped_atom)) + toxmob(bumped_atom) + else if(istype(bumped_atom, /obj/machinery/the_singularitygen)) + var/obj/machinery/the_singularitygen/generator = bumped_atom + generator.energy += energy + else if(istype(bumped_atom, /obj/singularity)) + var/obj/singularity/singuloth = bumped_atom + singuloth.energy += energy + else if(istype(bumped_atom, /obj/energy_ball)) + var/obj/energy_ball/tesloose = bumped_atom + tesloose.energy += energy + else if(istype(bumped_atom, /obj/structure/blob)) + var/obj/structure/blob/blob = bumped_atom + blob.take_damage(energy * 0.6) + movement_range = 0 +/obj/effect/accelerated_particle/Entered(atom/movable/arrived, atom/old_loc, list/atom/old_locs) + . = ..() + if(isliving(arrived)) + toxmob(arrived) + +/obj/effect/accelerated_particle/process() + if(QDELETED(loc) || movement_range <= 0) + qdel(src) + return PROCESS_KILL + if(!COOLDOWN_FINISHED(src, next_move)) + return + if(!step(src, dir)) + var/turf/next_step = get_step(src, dir) // this doesn't make sense but it was in the original code so I'm keeping it (with an actual qdeleted check) ~Lucy + if(QDELETED(next_step)) + qdel(src) + return PROCESS_KILL + forceMove(next_step) + movement_range-- + COOLDOWN_START(src, next_move, speed) /obj/effect/accelerated_particle/ex_act(severity, target) qdel(src) @@ -61,15 +77,5 @@ /obj/effect/accelerated_particle/singularity_pull() return -/obj/effect/accelerated_particle/proc/toxmob(mob/living/M) - radiation_pulse(M, 1, 3, 0.5) - -/obj/effect/accelerated_particle/proc/move() - if(!step(src,dir)) - forceMove(get_step(src,dir)) - movement_range-- - if(movement_range == 0) - qdel(src) - else - sleep(speed) - move() +/obj/effect/accelerated_particle/proc/toxmob(mob/living/victim) + radiation_pulse(victim, 1, 3, 0.5) diff --git a/monkestation/code/modules/virology/disease/symtoms/stage2.dm b/monkestation/code/modules/virology/disease/symtoms/stage2.dm index e00750ca7466..34aa5c17962f 100644 --- a/monkestation/code/modules/virology/disease/symtoms/stage2.dm +++ b/monkestation/code/modules/virology/disease/symtoms/stage2.dm @@ -459,8 +459,8 @@ badness = EFFECT_DANGER_HELPFUL /datum/symptom/antitox/activate(mob/living/mob) - to_chat(mob, "You feel your toxins being purged!") - mob.adjustToxLoss(-4) + to_chat(mob, span_notice("You feel your toxins being purged!")) + mob?.adjustToxLoss(-4) /datum/symptom/cult_vomit name = "Hemoptysis" diff --git a/monkestation/code/modules/virology/effects/pathogen_cloud.dm b/monkestation/code/modules/virology/effects/pathogen_cloud.dm index 42dd86e2b459..2de81917fe02 100644 --- a/monkestation/code/modules/virology/effects/pathogen_cloud.dm +++ b/monkestation/code/modules/virology/effects/pathogen_cloud.dm @@ -55,9 +55,10 @@ GLOBAL_LIST_INIT(science_goggles_wearers, list()) pathogen = image('monkestation/code/modules/virology/icons/96x96.dmi',src,"pathogen_airborne") pathogen.plane = HUD_PLANE pathogen.appearance_flags = RESET_COLOR|RESET_ALPHA - for (var/mob/living/L as anything in GLOB.science_goggles_wearers) - if (L.client) - L.client.images |= pathogen + for (var/mob/living/wearer as anything in GLOB.science_goggles_wearers) + if(QDELETED(wearer) || QDELETED(wearer.client)) + continue + wearer.client.images |= pathogen source = sourcemob @@ -85,9 +86,10 @@ GLOBAL_LIST_INIT(science_goggles_wearers, list()) SSpathogen_clouds.current_run_clouds -= src if (pathogen) - for (var/mob/living/L in GLOB.science_goggles_wearers) - if (L.client) - L.client.images -= pathogen + for (var/mob/living/wearer as anything in GLOB.science_goggles_wearers) + if(QDELETED(wearer) || QDELETED(wearer.client)) + continue + wearer.client.images -= pathogen pathogen = null GLOB.pathogen_clouds -= src source = null From 2dd0640fee95c9258e69296434d43da305f2d517 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sat, 28 Sep 2024 05:04:39 +0000 Subject: [PATCH 10/25] Automatic changelog for PR #3589 [ci skip] --- html/changelogs/AutoChangeLog-pr-3589.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-3589.yml diff --git a/html/changelogs/AutoChangeLog-pr-3589.yml b/html/changelogs/AutoChangeLog-pr-3589.yml new file mode 100644 index 000000000000..7a388baba630 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-3589.yml @@ -0,0 +1,4 @@ +author: "Absolucy, Kocma-san" +delete-after: True +changes: + - bugfix: "Fixed lights stopping emitting light in some situations." \ No newline at end of file From 16f2f99bfeb71ecb2ff1b0fd0804d11c32681eb8 Mon Sep 17 00:00:00 2001 From: RikuTheKiller <88713943+RikuTheKiller@users.noreply.github.com> Date: Sat, 28 Sep 2024 08:04:55 +0300 Subject: [PATCH 11/25] Remove snowflake conversion immunities (#3477) * guh * yay --- code/__DEFINES/surgery.dm | 2 ++ code/__DEFINES/traits/monkestation/declarations.dm | 2 ++ code/__DEFINES/~monkestation/antagonists.dm | 6 ++++++ code/_globalvars/traits/_traits.dm | 1 + code/modules/antagonists/brother/brother.dm | 3 ++- code/modules/assembly/flash.dm | 5 +++++ code/modules/mob/living/carbon/carbon_defense.dm | 3 ++- monkestation/code/modules/assembly/flash.dm | 2 +- .../code/modules/smithing/ipcs/body/internal_organs.dm | 2 +- 9 files changed, 22 insertions(+), 4 deletions(-) diff --git a/code/__DEFINES/surgery.dm b/code/__DEFINES/surgery.dm index 2c037f3728b2..aa81976f6dd3 100644 --- a/code/__DEFINES/surgery.dm +++ b/code/__DEFINES/surgery.dm @@ -17,6 +17,8 @@ #define ORGAN_HIDDEN (1<<7) /// Synthetic organ granted by a species (for use for organ replacements between species) #define ORGAN_SYNTHETIC_FROM_SPECIES (1<<8) +/// This organ has no impact on conversion via flash, such as revs or bbs. Doesn't affect hypnosis and whatnot, though. MONKESTATION EDIT +#define ORGAN_DOESNT_PROTECT_AGAINST_CONVERSION (1<<9) // Flags for the bodypart_flags var on /obj/item/bodypart /// Bodypart cannot be dismembered or amputated diff --git a/code/__DEFINES/traits/monkestation/declarations.dm b/code/__DEFINES/traits/monkestation/declarations.dm index 2ab31d15b457..29d153abd301 100644 --- a/code/__DEFINES/traits/monkestation/declarations.dm +++ b/code/__DEFINES/traits/monkestation/declarations.dm @@ -53,6 +53,8 @@ #define TRAIT_REVIVES_BY_HEALING "trait_revives_by_healing" /// This mob is a ghost critter. #define TRAIT_GHOST_CRITTER "ghost_critter" +/// This mob is *currently* being flashed by someone with CAN_BYPASS_INNATE_FLASH_RESISTANCE returning TRUE. Used to make IPCs not immune to rev and bb conversions. +#define TRAIT_CONVERSION_FLASHED "conversion_flashed" // /datum/mind + /mob/living /// Prevents the user from casting spells using sign language. Works on both /datum/mind and /mob/living. diff --git a/code/__DEFINES/~monkestation/antagonists.dm b/code/__DEFINES/~monkestation/antagonists.dm index 81040552ec45..353559f0d41f 100644 --- a/code/__DEFINES/~monkestation/antagonists.dm +++ b/code/__DEFINES/~monkestation/antagonists.dm @@ -26,6 +26,12 @@ /// is something a worm #define iscorticalborer(A) (istype(A, /mob/living/basic/cortical_borer)) +/// Is the mob a blood brother +#define IS_BROTHER(mob) (mob?.mind?.has_antag_datum(/datum/antagonist/brother)) + +/// Whether the mob can convert others through innate flash shielding like IPCs (head revolutionaries and blood brothers) +#define CAN_BYPASS_INNATE_FLASH_RESISTANCE(mob) (IS_BROTHER(mob) || IS_HEAD_REVOLUTIONARY(mob)) + // Borer evolution defines // The three primary paths that eventually diverge #define BORER_EVOLUTION_SYMBIOTE "Symbiote" diff --git a/code/_globalvars/traits/_traits.dm b/code/_globalvars/traits/_traits.dm index c11a1b6a1cf5..99db47cf8472 100644 --- a/code/_globalvars/traits/_traits.dm +++ b/code/_globalvars/traits/_traits.dm @@ -186,6 +186,7 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_CLUMSY" = TRAIT_CLUMSY, "TRAIT_COAGULATING" = TRAIT_COAGULATING, "TRAIT_COLDBLOODED" = TRAIT_COLDBLOODED, + "TRAIT_CONVERSION_FLASHED" = TRAIT_CONVERSION_FLASHED, "TRAIT_CORPSELOCKED" = TRAIT_CORPSELOCKED, "TRAIT_CRITICAL_CONDITION" = TRAIT_CRITICAL_CONDITION, "TRAIT_CULT_HALO" = TRAIT_CULT_HALO, diff --git a/code/modules/antagonists/brother/brother.dm b/code/modules/antagonists/brother/brother.dm index 22991570da91..4aef0a99229f 100644 --- a/code/modules/antagonists/brother/brother.dm +++ b/code/modules/antagonists/brother/brother.dm @@ -39,6 +39,7 @@ if (!is_first_brother) to_chat(carbon_owner, span_boldwarning("The Syndicate have higher expectations from you than others. They have granted you an extra flash to convert one other person.")) + carbon_owner.balloon_alert(carbon_owner, "extra flash granted!") return ..() @@ -80,7 +81,7 @@ flashed.balloon_alert(source, "[flashed.p_theyre()] loyal to someone else!") return - if (HAS_TRAIT(flashed, TRAIT_MINDSHIELD) || HAS_MIND_TRAIT(flashed, TRAIT_UNCONVERTABLE) || (flashed.mind.assigned_role?.departments_bitflags & DEPARTMENT_BITFLAG_SECURITY)) // monkestation edit: TRAIT_UNCONVERTABLE + if (HAS_TRAIT(flashed, TRAIT_MINDSHIELD) || HAS_MIND_TRAIT(flashed, TRAIT_UNCONVERTABLE)) // monkestation edit: TRAIT_UNCONVERTABLE and remove hardcoded security check flashed.balloon_alert(source, "[flashed.p_they()] resist!") return diff --git a/code/modules/assembly/flash.dm b/code/modules/assembly/flash.dm index d45528c2d3ed..e80f45ae8dee 100644 --- a/code/modules/assembly/flash.dm +++ b/code/modules/assembly/flash.dm @@ -164,6 +164,9 @@ if(deviation == DEVIATION_FULL) return + if(CAN_BYPASS_INNATE_FLASH_RESISTANCE(user)) // MONKESTATION EDIT: Make IPCs not resistant to bb and rev conversions. + ADD_TRAIT(flashed, TRAIT_CONVERSION_FLASHED, TRAIT_GENERIC) + if(targeted) if(flashed.flash_act(1, 1)) flashed.set_confusion_if_lower(confusion_duration * CONFUSION_STACK_MAX_MULTIPLIER) @@ -185,6 +188,8 @@ if(flashed.flash_act()) flashed.set_confusion_if_lower(confusion_duration * CONFUSION_STACK_MAX_MULTIPLIER) + REMOVE_TRAIT(flashed, TRAIT_CONVERSION_FLASHED, TRAIT_GENERIC) // MONKESTATION EDIT: Make IPCs not resistant to bb and rev conversions. + /** * Handles the directionality of the attack * diff --git a/code/modules/mob/living/carbon/carbon_defense.dm b/code/modules/mob/living/carbon/carbon_defense.dm index 3b21192da75d..bbd4b644412c 100644 --- a/code/modules/mob/living/carbon/carbon_defense.dm +++ b/code/modules/mob/living/carbon/carbon_defense.dm @@ -6,7 +6,8 @@ return INFINITY //For all my homies that can not see in the world var/obj/item/organ/internal/eyes/eyes = get_organ_slot(ORGAN_SLOT_EYES) if(eyes) - . += eyes.flash_protect + if(!HAS_TRAIT(src, TRAIT_CONVERSION_FLASHED) || !(eyes.organ_flags & ORGAN_DOESNT_PROTECT_AGAINST_CONVERSION)) // MONKESTATION EDIT: Make IPCs not immune to rev and bb conversions. + . += eyes.flash_protect else return INFINITY //Can't get flashed without eyes if(isclothing(head)) //Adds head protection diff --git a/monkestation/code/modules/assembly/flash.dm b/monkestation/code/modules/assembly/flash.dm index b67ade990435..273ea4cdf1e5 100644 --- a/monkestation/code/modules/assembly/flash.dm +++ b/monkestation/code/modules/assembly/flash.dm @@ -5,4 +5,4 @@ var/datum/component/can_flash_from_behind/flash_handler = user.GetComponent(/datum/component/can_flash_from_behind) if(REF(blood_bond) in flash_handler?.sources) . += span_boldnotice("In order to convert someone into your blood brother, you must directly flash them, not AoE flash!") - . += span_warning("Conversion will fail if the target is either dead, unconscious, SSD, mindshielded, a member of security, someone else's brother, or if they are targeted by your objectives.") + . += span_warning("Conversion will fail if the target is either dead, unconscious, SSD, mindshielded, someone else's brother or if they are targeted by your objectives.") diff --git a/monkestation/code/modules/smithing/ipcs/body/internal_organs.dm b/monkestation/code/modules/smithing/ipcs/body/internal_organs.dm index dad7cc42e5d3..99f34996424e 100644 --- a/monkestation/code/modules/smithing/ipcs/body/internal_organs.dm +++ b/monkestation/code/modules/smithing/ipcs/body/internal_organs.dm @@ -122,7 +122,7 @@ desc = "A very basic set of optical sensors with no extra vision modes or functions." maxHealth = 1 * STANDARD_ORGAN_THRESHOLD flash_protect = FLASH_PROTECTION_WELDER - organ_flags = ORGAN_ROBOTIC | ORGAN_SYNTHETIC_FROM_SPECIES + organ_flags = ORGAN_ROBOTIC | ORGAN_SYNTHETIC_FROM_SPECIES | ORGAN_DOESNT_PROTECT_AGAINST_CONVERSION /obj/item/organ/internal/eyes/synth/emp_act(severity) . = ..() From 87db66565c6b548db7c3adf26a00cfd8e083c8e2 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sat, 28 Sep 2024 05:05:15 +0000 Subject: [PATCH 12/25] Automatic changelog for PR #3477 [ci skip] --- html/changelogs/AutoChangeLog-pr-3477.yml | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-3477.yml diff --git a/html/changelogs/AutoChangeLog-pr-3477.yml b/html/changelogs/AutoChangeLog-pr-3477.yml new file mode 100644 index 000000000000..1cd9e628d9bc --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-3477.yml @@ -0,0 +1,6 @@ +author: "RikuTheKiller" +delete-after: True +changes: + - balance: "Blood Brothers can now convert members of security if their mindshields are removed." + - balance: "IPCs are no longer immune to being converted by revolutionaries and blood brothers." + - qol: "You now get a balloon alert if you get a second flash as a Blood Brother." \ No newline at end of file From d5d32d5010c3dfd60d8f6e5b5e2ceec6e6dd6212 Mon Sep 17 00:00:00 2001 From: Lucy Date: Sat, 28 Sep 2024 01:06:38 -0400 Subject: [PATCH 13/25] Profiler logs now sort by overtime and have a proper timestamp in the filename (#3588) --- code/__HELPERS/~monkestation-helpers/cmp.dm | 4 ++ code/controllers/subsystem/init_profiler.dm | 2 + code/controllers/subsystem/profiler.dm | 5 ++- monkestation/code/__HELPERS/files.dm | 2 +- .../controllers/subsystem/init_profiler.dm | 28 +++++++++++++ .../code/controllers/subsystem/profiler.dm | 42 +++++++++++++++++++ tgstation.dme | 2 + 7 files changed, 83 insertions(+), 2 deletions(-) create mode 100644 monkestation/code/controllers/subsystem/init_profiler.dm create mode 100644 monkestation/code/controllers/subsystem/profiler.dm diff --git a/code/__HELPERS/~monkestation-helpers/cmp.dm b/code/__HELPERS/~monkestation-helpers/cmp.dm index c87af6cd5202..d7f322409e96 100644 --- a/code/__HELPERS/~monkestation-helpers/cmp.dm +++ b/code/__HELPERS/~monkestation-helpers/cmp.dm @@ -8,3 +8,7 @@ /// Use when you want a list of most to least severe wounds. /proc/cmp_wound_severity_dsc(datum/wound/a, datum/wound/b) return cmp_numeric_dsc(a.severity, b.severity) + +/// Used to sort overtime in profiling data. +/proc/sort_overtime_dsc(list/a, list/b) + return b["over"] - a["over"] diff --git a/code/controllers/subsystem/init_profiler.dm b/code/controllers/subsystem/init_profiler.dm index 063898b6a098..1d1eed74cb46 100644 --- a/code/controllers/subsystem/init_profiler.dm +++ b/code/controllers/subsystem/init_profiler.dm @@ -1,3 +1,4 @@ +/* monkestation edit: reimplemented in [monkestation\code\controllers\subsystem\init_profiler.dm] #define INIT_PROFILE_NAME "init_profiler.json" ///Subsystem exists so we can separately log init time costs from the costs of general operation @@ -26,3 +27,4 @@ SUBSYSTEM_DEF(init_profiler) world.Profile(PROFILE_CLEAR) //Now that we're written this data out, dump it. We don't want it getting mixed up with our current round data #undef INIT_PROFILE_NAME +monkestation end */ diff --git a/code/controllers/subsystem/profiler.dm b/code/controllers/subsystem/profiler.dm index 629590d75ebb..c936cdc3993c 100644 --- a/code/controllers/subsystem/profiler.dm +++ b/code/controllers/subsystem/profiler.dm @@ -6,10 +6,12 @@ SUBSYSTEM_DEF(profiler) var/fetch_cost = 0 var/write_cost = 0 +/* monkestation edit: reimplemented in [monkestation\code\controllers\subsystem\profiler.dm] /datum/controller/subsystem/profiler/stat_entry(msg) msg += "F:[round(fetch_cost,1)]ms" msg += "|W:[round(write_cost,1)]ms" return msg +monkestation end */ /datum/controller/subsystem/profiler/Initialize() if(CONFIG_GET(flag/auto_profile)) @@ -37,6 +39,7 @@ SUBSYSTEM_DEF(profiler) world.Profile(PROFILE_STOP, type = "sendmaps") +/* monkestation edit: reimplemented in [monkestation\code\controllers\subsystem\profiler.dm] /datum/controller/subsystem/profiler/proc/DumpFile() var/timer = TICK_USAGE_REAL var/current_profile_data = world.Profile(PROFILE_REFRESH, format = "json") @@ -59,4 +62,4 @@ SUBSYSTEM_DEF(profiler) WRITE_FILE(prof_file, current_profile_data) WRITE_FILE(sendmaps_file, current_sendmaps_data) write_cost = MC_AVERAGE(write_cost, TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer)) - +monkestation end */ diff --git a/monkestation/code/__HELPERS/files.dm b/monkestation/code/__HELPERS/files.dm index ead24af1cd4e..998c4391c8eb 100644 --- a/monkestation/code/__HELPERS/files.dm +++ b/monkestation/code/__HELPERS/files.dm @@ -3,7 +3,7 @@ var/regex/whitelist_regex if(whitelist) // try not to look at it too hard. yes i wrote this by hand. - whitelist_regex = new("(?:\[\\/\\\\\]$|(?:^|\\\\|\\/)(?:[regex_quote_list(whitelist)]|(?:profiler|sendmaps)-\[0-9\]+)\\.(?:[regex_quote_list(valid_extensions)])$)", "i") + whitelist_regex = new("(?:\[\\/\\\\\]$|(?:^|\\\\|\\/)(?:[regex_quote_list(whitelist)]|(?:profiler|sendmaps)-\[0-9_\\-\]+)\\.(?:[regex_quote_list(valid_extensions)])$)", "i") // wow why was this ever a parameter var/root = "data/logs/" diff --git a/monkestation/code/controllers/subsystem/init_profiler.dm b/monkestation/code/controllers/subsystem/init_profiler.dm new file mode 100644 index 000000000000..a17025be41a2 --- /dev/null +++ b/monkestation/code/controllers/subsystem/init_profiler.dm @@ -0,0 +1,28 @@ +#define INIT_PROFILE_NAME "init_profiler.json" + +///Subsystem exists so we can separately log init time costs from the costs of general operation +///Hopefully this makes sorting out what causes problems when easier +SUBSYSTEM_DEF(init_profiler) + name = "Init Profiler" + init_order = INIT_ORDER_INIT_PROFILER + init_stage = INITSTAGE_MAX + flags = SS_NO_FIRE + +/datum/controller/subsystem/init_profiler/Initialize() + if(CONFIG_GET(flag/auto_profile)) + write_init_profile() + return SS_INIT_SUCCESS + return SS_INIT_NO_NEED + +/datum/controller/subsystem/init_profiler/proc/write_init_profile() + var/list/current_profile_data = world.Profile(PROFILE_REFRESH, format = "json") + current_profile_data = json_decode(current_profile_data) // yes this is stupid but this gets us a list in a non-awful format + CHECK_TICK + sortTim(current_profile_data, GLOBAL_PROC_REF(sort_overtime_dsc)) + + if(!length(current_profile_data)) //Would be nice to have explicit proc to check this + stack_trace("Warning, profiling stopped manually before dump.") + rustg_file_write(json_encode(current_profile_data), "[GLOB.log_directory]/[INIT_PROFILE_NAME]") + world.Profile(PROFILE_CLEAR) //Now that we're written this data out, dump it. We don't want it getting mixed up with our current round data + +#undef INIT_PROFILE_NAME diff --git a/monkestation/code/controllers/subsystem/profiler.dm b/monkestation/code/controllers/subsystem/profiler.dm new file mode 100644 index 000000000000..f3445536588d --- /dev/null +++ b/monkestation/code/controllers/subsystem/profiler.dm @@ -0,0 +1,42 @@ +/datum/controller/subsystem/profiler + var/sort_cost = 0 + +/datum/controller/subsystem/profiler/stat_entry(msg) + msg += "F:[round(fetch_cost, 1)]ms" + msg += "|S:[round(sort_cost, 1)]ms" + msg += "|W:[round(write_cost, 1)]ms" + return msg + +/datum/controller/subsystem/profiler/proc/DumpFile() + var/timer = TICK_USAGE_REAL + var/list/current_profile_data = world.Profile(PROFILE_REFRESH, format = "json") + current_profile_data = json_decode(current_profile_data) // yes this is stupid but this gets us a list in a non-awful format + var/current_sendmaps_data = world.Profile(PROFILE_REFRESH, type = "sendmaps", format = "json") + fetch_cost = MC_AVERAGE(fetch_cost, TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer)) + CHECK_TICK + + if(!length(current_profile_data)) //Would be nice to have explicit proc to check this + stack_trace("Warning, profiling stopped manually before dump.") + + timer = TICK_USAGE_REAL + sortTim(current_profile_data, GLOBAL_PROC_REF(sort_overtime_dsc)) + sort_cost = MC_AVERAGE(sort_cost, TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer)) + + var/timestamp = time2text(world.timeofday, "YYYY-MM-DD_hh-mm-ss") + var/prof_file = "[GLOB.log_directory]/profiler/profiler-[timestamp].json" + if(!length(current_sendmaps_data)) //Would be nice to have explicit proc to check this + stack_trace("Warning, sendmaps profiling stopped manually before dump.") + var/sendmaps_file = "[GLOB.log_directory]/profiler/sendmaps-[timestamp].json" + + timer = TICK_USAGE_REAL + rustg_file_write(json_encode(current_profile_data), prof_file) + rustg_file_write(current_sendmaps_data, sendmaps_file) + write_cost = MC_AVERAGE(write_cost, TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer)) + +/datum/controller/subsystem/profiler/get_metrics() + . = ..() + .["custom"] = list( + "fetch_cost" = fetch_cost, + "sort_cost" = sort_cost, + "write_cost" = write_cost, + ) diff --git a/tgstation.dme b/tgstation.dme index 78cad90c04f4..e8ad085af035 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -5810,7 +5810,9 @@ #include "monkestation\code\controllers\subsystem\autotransfer.dm" #include "monkestation\code\controllers\subsystem\economy.dm" #include "monkestation\code\controllers\subsystem\glowshroom.dm" +#include "monkestation\code\controllers\subsystem\init_profiler.dm" #include "monkestation\code\controllers\subsystem\job.dm" +#include "monkestation\code\controllers\subsystem\profiler.dm" #include "monkestation\code\datums\action.dm" #include "monkestation\code\datums\dna.dm" #include "monkestation\code\datums\emotes.dm" From bb847391e135b74e361cab4eeeebfde7f4405356 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sat, 28 Sep 2024 05:06:59 +0000 Subject: [PATCH 14/25] Automatic changelog for PR #3588 [ci skip] --- html/changelogs/AutoChangeLog-pr-3588.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-3588.yml diff --git a/html/changelogs/AutoChangeLog-pr-3588.yml b/html/changelogs/AutoChangeLog-pr-3588.yml new file mode 100644 index 000000000000..5c7ac05473f3 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-3588.yml @@ -0,0 +1,4 @@ +author: "Absolucy" +delete-after: True +changes: + - server: "Profiler logs now sort by overtime and have a proper timestamp in the filename." \ No newline at end of file From a991873cde97e7b3fa86a2f321848d75d25b8c7f Mon Sep 17 00:00:00 2001 From: Changelogs Date: Sat, 28 Sep 2024 05:07:36 +0000 Subject: [PATCH 15/25] Automatic changelog compile [ci skip] --- html/changelogs/AutoChangeLog-pr-3477.yml | 6 ------ html/changelogs/AutoChangeLog-pr-3588.yml | 4 ---- html/changelogs/AutoChangeLog-pr-3589.yml | 4 ---- html/changelogs/archive/2024-09.yml | 12 ++++++++++++ 4 files changed, 12 insertions(+), 14 deletions(-) delete mode 100644 html/changelogs/AutoChangeLog-pr-3477.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-3588.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-3589.yml diff --git a/html/changelogs/AutoChangeLog-pr-3477.yml b/html/changelogs/AutoChangeLog-pr-3477.yml deleted file mode 100644 index 1cd9e628d9bc..000000000000 --- a/html/changelogs/AutoChangeLog-pr-3477.yml +++ /dev/null @@ -1,6 +0,0 @@ -author: "RikuTheKiller" -delete-after: True -changes: - - balance: "Blood Brothers can now convert members of security if their mindshields are removed." - - balance: "IPCs are no longer immune to being converted by revolutionaries and blood brothers." - - qol: "You now get a balloon alert if you get a second flash as a Blood Brother." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-3588.yml b/html/changelogs/AutoChangeLog-pr-3588.yml deleted file mode 100644 index 5c7ac05473f3..000000000000 --- a/html/changelogs/AutoChangeLog-pr-3588.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Absolucy" -delete-after: True -changes: - - server: "Profiler logs now sort by overtime and have a proper timestamp in the filename." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-3589.yml b/html/changelogs/AutoChangeLog-pr-3589.yml deleted file mode 100644 index 7a388baba630..000000000000 --- a/html/changelogs/AutoChangeLog-pr-3589.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Absolucy, Kocma-san" -delete-after: True -changes: - - bugfix: "Fixed lights stopping emitting light in some situations." \ No newline at end of file diff --git a/html/changelogs/archive/2024-09.yml b/html/changelogs/archive/2024-09.yml index 8eec30d57a34..3be2cf0407b5 100644 --- a/html/changelogs/archive/2024-09.yml +++ b/html/changelogs/archive/2024-09.yml @@ -615,3 +615,15 @@ watch it explode bigger and bettert than before Wisemonster: - balance: Added a telescopic baton to the blueshield's locker +2024-09-28: + Absolucy: + - server: Profiler logs now sort by overtime and have a proper timestamp in the + filename. + Absolucy, Kocma-san: + - bugfix: Fixed lights stopping emitting light in some situations. + RikuTheKiller: + - balance: Blood Brothers can now convert members of security if their mindshields + are removed. + - balance: IPCs are no longer immune to being converted by revolutionaries and blood + brothers. + - qol: You now get a balloon alert if you get a second flash as a Blood Brother. From 10eeb805abe162171e0a007e7521f62f0cf54201 Mon Sep 17 00:00:00 2001 From: Cannibal Hunter <135169022+CannibalHunter@users.noreply.github.com> Date: Sat, 28 Sep 2024 22:16:26 -0500 Subject: [PATCH 16/25] Marketable Admin Plushies 2 (#3603) * marketable admins * add marisa plush * plushie move * Update admin_plushies.dm * Update tgstation.dme * bazinga * Update admin_plushies.dm --------- Co-authored-by: ThePooba <81843097+ThePooba@users.noreply.github.com> --- .../code/game/objects/items/admin_plushies.dm | 197 ++++++++++++++---- monkestation/icons/obj/admin_plushies.dmi | Bin 3573 -> 15997 bytes 2 files changed, 160 insertions(+), 37 deletions(-) diff --git a/monkestation/code/game/objects/items/admin_plushies.dm b/monkestation/code/game/objects/items/admin_plushies.dm index 597c7de333f4..61155eeb5b7d 100644 --- a/monkestation/code/game/objects/items/admin_plushies.dm +++ b/monkestation/code/game/objects/items/admin_plushies.dm @@ -1,13 +1,27 @@ -// This is where all of the MonkeStation Admin Plushies should be stored +// This is where all of the MonkeStation Admin Plushies SHOULD be stored + +// Plushies +/obj/item/toy/plush/admin + name = "admin plushie" + desc = "if you're seeing this there's an issue." + icon = 'monkestation/icons/obj/admin_plushies.dmi' + icon_state = "" + /// A string of text that is optionaly added to the objects desc, it SHOULD be the admin's CKEY. + var/adminCKey = null + +/obj/item/toy/plush/admin/Initialize(mapload) + . = ..() + if(adminCKey) + desc = "[desc]" + " " + "(A member of our beloved admin team- ''[adminCKey]'')" + else + desc = "[desc]" + " " + "(A member of our beloved admin team)" -// Plushies /obj/item/toy/plush/admin/ben_mothman name = "ben mothman" - desc = "HAH this guy is short! Laugh at him.. this is an order! " - icon = 'monkestation/icons/obj/admin_plushies.dmi' + desc = "HAH this guy is short! Laugh at him.. this is an order!" icon_state = "ben" /datum/loadout_item/toys/ben_mothman - name = "ben mothman plush" + name = "Ben Mothman plush" item_path = /obj/item/toy/plush/admin/ben_mothman /datum/store_item/toys/ben_mothman name = "Ben Mothman Plush" @@ -16,11 +30,10 @@ /obj/item/toy/plush/admin/abraxis name = "abraxis" - desc = "This feller is always up to something.. he's even got that huge company I forgot the name of... " - icon = 'monkestation/icons/obj/admin_plushies.dmi' + desc = "This feller is always up to something.. he's even got that huge company I forgot the name of..." icon_state = "abraxis" /datum/loadout_item/toys/abraxis - name = "abraxis plush" + name = "Abraxis Plush" item_path = /obj/item/toy/plush/admin/abraxis /datum/store_item/toys/abraxis name = "Abraxis Plush" @@ -29,11 +42,10 @@ /obj/item/toy/plush/admin/brad name = "brad" - desc = "Woah.. they're BLUE, and they've also got a cane! How fancy dancy. " - icon = 'monkestation/icons/obj/admin_plushies.dmi' + desc = "Woah.. they're BLUE, and they've also got a cane! How fancy dancy." icon_state = "brad" /datum/loadout_item/toys/brad - name = "brad plush" + name = "Brad Plush" item_path = /obj/item/toy/plush/admin/brad /datum/store_item/toys/brad name = "Brad Plush" @@ -42,11 +54,10 @@ /obj/item/toy/plush/admin/andrea name = "andrea" - desc = "Best combat medic around.. if you're legs are blown off and you see this fellah comming around- you're lucky. " - icon = 'monkestation/icons/obj/admin_plushies.dmi' + desc = "Best combat medic around.. if your legs are blown off and you see this fellah comming around- you're lucky." icon_state = "andrea" /datum/loadout_item/toys/andrea - name = "andrea plush" + name = "Andrea Plush" item_path = /obj/item/toy/plush/admin/andrea /datum/store_item/toys/andrea name = "Andrea Plush" @@ -55,11 +66,10 @@ /obj/item/toy/plush/admin/pippi name = "pippi" - desc = "... " - icon = 'monkestation/icons/obj/admin_plushies.dmi' + desc = "..." icon_state = "pippi" /datum/loadout_item/toys/pippi - name = "pippi plush" + name = "Pippi Plush" item_path = /obj/item/toy/plush/admin/pippi /datum/store_item/toys/pippi name = "Pippi Plush" @@ -68,11 +78,10 @@ /obj/item/toy/plush/admin/syndi_kate name = "syndi-kate" - desc = "''GLORY TO THE SYNDICATE!'' " - icon = 'monkestation/icons/obj/admin_plushies.dmi' + desc = "''GLORY TO THE SYNDICATE!''" icon_state = "syndi_kate" /datum/loadout_item/toys/syndi_kate - name = "syndi-kate plush" + name = "Syndi-Kate Plush" item_path = /obj/item/toy/plush/admin/syndi_kate /datum/store_item/toys/syndi_kate name = "Syndi-Kate Plush" @@ -81,11 +90,10 @@ /obj/item/toy/plush/admin/jace name = "jace" - desc = "It's Jace! " - icon = 'monkestation/icons/obj/admin_plushies.dmi' + desc = "It's Jace!" icon_state = "jace" /datum/loadout_item/toys/jace - name = "jace plush" + name = "Jace Plush" item_path = /obj/item/toy/plush/admin/jace /datum/store_item/toys/jace name = "Jace Plush" @@ -94,11 +102,10 @@ /obj/item/toy/plush/admin/lavender name = "lavender" - desc = "It's Lavender! " - icon = 'monkestation/icons/obj/admin_plushies.dmi' + desc = "It's Lavender!" icon_state = "lavender" /datum/loadout_item/toys/lavender - name = "lavender plush" + name = "Lavender Plush" item_path = /obj/item/toy/plush/admin/lavender /datum/store_item/toys/lavender name = "Lavender Plush" @@ -107,11 +114,10 @@ /obj/item/toy/plush/admin/waffles name = "waffles" - desc = "It's Waffles! What a wierdo! " - icon = 'monkestation/icons/obj/admin_plushies.dmi' + desc = "It's Waffles! What a wierdo!" icon_state = "waffles" /datum/loadout_item/toys/waffles - name = "waffles plush" + name = "Waffles Plush" item_path = /obj/item/toy/plush/admin/waffles /datum/store_item/toys/waffles name = "Waffles Plush" @@ -120,11 +126,10 @@ /obj/item/toy/plush/admin/vicky name = "vicky" - desc = "It's Vicky! " - icon = 'monkestation/icons/obj/admin_plushies.dmi' + desc = "It's Vicky!" icon_state = "vicky" /datum/loadout_item/toys/vicky - name = "vicky plush" + name = "Vicky Plush" item_path = /obj/item/toy/plush/admin/vicky /datum/store_item/toys/vicky name = "Vicky Plush" @@ -133,11 +138,10 @@ /obj/item/toy/plush/admin/richard_deckard name = "richard deckard" - desc = "It's Richard Deckard! " - icon = 'monkestation/icons/obj/admin_plushies.dmi' + desc = "It's Richard Deckard!" icon_state = "richard_deckard" /datum/loadout_item/toys/richard_deckard - name = "richard deckard plush" + name = "Richard Deckard Plush" item_path = /obj/item/toy/plush/admin/richard_deckard /datum/store_item/toys/richard_deckard name = "Richard Deckard Plush" @@ -147,12 +151,131 @@ /obj/item/toy/plush/admin/marisa name = "marisa" desc = "It's Marisa! THE GOOBER- LOOK AT HER!" - icon = 'monkestation/icons/obj/admin_plushies.dmi' icon_state = "marisa" /datum/loadout_item/toys/marisa - name = "marisa plush" + name = "Marisa Plush" item_path = /obj/item/toy/plush/admin/marisa /datum/store_item/toys/marisa name = "Marisa Plush" item_path = /obj/item/toy/plush/admin/marisa item_cost = 7500 + +/obj/item/toy/plush/admin/raziel + name = "raziel" + desc = "It's Raziel! He smells of bubblegum, and looks like he'll commit arson if you dont watch em." + icon_state = "raziel" +/datum/loadout_item/toys/raziel + name = "Raziel Plush" + item_path = /obj/item/toy/plush/admin/raziel +/datum/store_item/toys/raziel + name = "Raziel Plush" + item_path = /obj/item/toy/plush/admin/raziel + item_cost = 7500 + +/obj/item/toy/plush/admin/gabbie + name = "gabbie" + desc = "It's Gabbie!" + icon_state = "gabbie" +/datum/loadout_item/toys/gabbie + name = "Gabbie Plush" + item_path = /obj/item/toy/plush/admin/gabbie +/datum/store_item/toys/gabbie + name = "Gabbie Plush" + item_path = /obj/item/toy/plush/admin/gabbie + item_cost = 7500 + +/obj/item/toy/plush/admin/amunsethep + name = "amun set hep" + desc = "CURSE OF THE SANDS BE UPON YOU!!!" + icon_state = "amunsethep" +/datum/loadout_item/toys/amunsethep + name = "Amun Set Hep Plush" + item_path = /obj/item/toy/plush/admin/amunsethep +/datum/store_item/toys/gabbie + name = "Amun Set Hep Plush" + item_path = /obj/item/toy/plush/admin/amunsethep + item_cost = 7500 + +/obj/item/toy/plush/admin/tendsthefire + name = "tends-the-fire" + desc = "It's Tends-The-Fire!, what a lovable little lizard!" + icon_state = "tendsthefire" +/datum/loadout_item/toys/tendsthefire + name = "Tends-The-Fire Plush" + item_path = /obj/item/toy/plush/admin/tendsthefire +/datum/store_item/toys/tendsthefire + name = "Tends-The-Fire Plush" + item_path = /obj/item/toy/plush/admin/tendsthefire + item_cost = 7500 + +/obj/item/toy/plush/admin/haileyspire + name = "hailey spire" + desc = "It's Hailey Spire! They've got a BIG WRENCH- WATCH OUT!!!" + icon_state = "haileyspire" +/datum/loadout_item/toys/haileyspire + name = "Hailey Spire Plush" + item_path = /obj/item/toy/plush/admin/haileyspire +/datum/store_item/toys/haileyspire + name = "Hailey Spire Plush" + item_path = /obj/item/toy/plush/admin/haileyspire + item_cost = 7500 + +/obj/item/toy/plush/admin/haileyspire + name = "hailey spire" + desc = "It's Hailey Spire! They've got a BIG WRENCH- WATCH OUT!!!" + icon_state = "haileyspire" +/datum/loadout_item/toys/haileyspire + name = "Hailey Spire Plush" + item_path = /obj/item/toy/plush/admin/haileyspire +/datum/store_item/toys/haileyspire + name = "Hailey Spire Plush" + item_path = /obj/item/toy/plush/admin/haileyspire + item_cost = 7500 + +/obj/item/toy/plush/admin/sydneysahrin + name = "sydney sahrin" + desc = "It's Sydney Sahrin! Shortest plantmin!" + icon_state = "sydneysahrin" +/datum/loadout_item/toys/sydneysahrin + name = "Sydney Sahrin Plush" + item_path = /obj/item/toy/plush/admin/sydneysahrin +/datum/store_item/toys/sydneysahrin + name = "Sydney Sahrin Plush" + item_path = /obj/item/toy/plush/admin/sydneysahrin + item_cost = 7500 + +/obj/item/toy/plush/admin/veth + name = "veth" + desc = "It's Veth! Suprisingly not upside down!" + icon_state = "veth" +/datum/loadout_item/toys/veth + name = "Veth Plush" + item_path = /obj/item/toy/plush/admin/veth +/datum/store_item/toys/veth + name = "Veth Plush" + item_path = /obj/item/toy/plush/admin/veth + item_cost = 7500 + +/obj/item/toy/plush/admin/cassielpip + name = "cassiel pip" + desc = "Smelly Rat." + icon_state = "cassielpip" +/datum/loadout_item/toys/cassielpip + name = "Cassiel Pip Plush" + item_path = /obj/item/toy/plush/admin/cassielpip +/datum/store_item/toys/cassielpip + name = "Cassiel Pip Plush" + item_path = /obj/item/toy/plush/admin/cassielpip + item_cost = 7500 + +/obj/item/toy/plush/admin/fortune + name = "fortune" + desc = "It's Fortune- the Felinid!" + icon_state = "fortune" +/datum/loadout_item/toys/fortune + name = "Fortune Plush" + item_path = /obj/item/toy/plush/admin/fortune +/datum/store_item/toys/fortune + name = "Fortune Plush" + item_path = /obj/item/toy/plush/admin/fortune + item_cost = 7500 diff --git a/monkestation/icons/obj/admin_plushies.dmi b/monkestation/icons/obj/admin_plushies.dmi index 909da946c84c02f70af0bc1a9a65ebec4e568b12..ead776a9e00ffee0cc861e05715c8d6448335879 100644 GIT binary patch literal 15997 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 literal 3573 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 z za4_iuKPPBkKKGX)8o$G4zXH-{NPSR)t= zhsX3&!fJc?=)0jI?fHOU8o+!v5ddJ?KtC3XJr2Q%$zX)nCspJC(i#Q7C|KtnK6*IE zo)5qXU1KylH9>dOQ^>+>bV}bBxsTBL^Thcy{s8iP2G|^wh=2mW2v;Q#%%c`yMCR*| zoh|eEqKY~S52CaBek31?#p6%De-cYXLXQ(My#t!#Wd9gT0e%(e&pn!Zw(#uX++V-T ze4YLM0mcmr?z=}-Zs)4$Cy;{YAc#G7J_U>pfb>;X0Ldy40L(pP`j3!^xs1&<8GsyM ze>=+bvA4;r0@NHv4OI|)|0Mo25l12FPtW#5gJG=#1vT*O+5Fr*z8|qt$b7yqb;MW3 z`X4){xY;9?ndywqaW?A3#aJT#{CO}Qi;rVb$c(|{-xrV<3`4KKu(0rKVID4^6z2Hn z3re!TqWF*s{X~c*NdLu)IE;vgK#u0^@XMJ{r&gW;ECNj5Dl?H<6X zW%+MQCeyAFU|YE&|9xrq0G9pBt1I$9mfreV&3~)Evbweg0>l0NyN;FB^_OdF%SQYA zcNrV&8~C}twzj_ha&^To@4Wun+S1bM#`=#hfv~)?)A~e!$+rxSAJ^75b^}1#kmcnS z83fQ@-35J$mDQjAiCWk#c}ZTCfBp$JEbr1Pw7Dt&>t}gsWfcqY#xBUe`sLN;D|yMZ zif>HD-O#6hGVGU^*4B60g1-L#O-8V}N&ns0X#?2j|C_%sh8>pHLi_xmrD1bd08)W6 v%>McRJCE%?|9|%Y+kO6@i(KU5e;oe?hmYKZaxg8%00000NkvXXu0mjfx@)g; From c1aa02ac0d24ab645c51dbd8bcc71f62a32dcd74 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 29 Sep 2024 03:16:46 +0000 Subject: [PATCH 17/25] Automatic changelog for PR #3603 [ci skip] --- html/changelogs/AutoChangeLog-pr-3603.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-3603.yml diff --git a/html/changelogs/AutoChangeLog-pr-3603.yml b/html/changelogs/AutoChangeLog-pr-3603.yml new file mode 100644 index 000000000000..04fb79ee9959 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-3603.yml @@ -0,0 +1,4 @@ +author: "CannibalHunter" +delete-after: True +changes: + - rscadd: "Added several more admin plushies to the monkeshop" \ No newline at end of file From 89e91b8edd734d7e169a11ddfc677f77c657df95 Mon Sep 17 00:00:00 2001 From: ThePooba <81843097+ThePooba@users.noreply.github.com> Date: Sun, 29 Sep 2024 13:13:02 -0600 Subject: [PATCH 18/25] Storyteller edits and monkey event (#3570) * roles and events updated * names names names names. * added secret monkey event * added monkeystorm * monkenoise * spell bad mistake fixx * bla bla --- code/modules/events/carp_migration.dm | 2 +- code/modules/events/disease_outbreak.dm | 4 +-- code/modules/events/ghost_role/blob.dm | 3 +- .../events/meteors/stray_meteor_event.dm | 4 +-- code/modules/events/portal_storm.dm | 26 ++++++++++++++++++ code/modules/events/spider_infestation.dm | 2 +- .../code/game/machinery/bomb_actualizer.dm | 9 ++++++ .../converted_events/event_overrides.dm | 1 + monkestation/sound/misc/monkeystorm.ogg | Bin 0 -> 52752 bytes strings/names/clown.txt | 7 ++++- strings/names/mime.txt | 18 +++++++++--- 11 files changed, 63 insertions(+), 13 deletions(-) create mode 100644 monkestation/sound/misc/monkeystorm.ogg diff --git a/code/modules/events/carp_migration.dm b/code/modules/events/carp_migration.dm index 821a01446406..a380750ff67e 100644 --- a/code/modules/events/carp_migration.dm +++ b/code/modules/events/carp_migration.dm @@ -4,7 +4,7 @@ weight = 15 min_players = 20 //monkie edit: 12 to 20 earliest_start = 40 MINUTES //monkie edit: 10 to 40 - max_occurrences = 2 //monkie edit: 6 to 2 + max_occurrences = 3 //monkie edit: 6 to 2 category = EVENT_CATEGORY_ENTITIES description = "Summons a school of space carp." min_wizard_trigger_potency = 0 diff --git a/code/modules/events/disease_outbreak.dm b/code/modules/events/disease_outbreak.dm index 043a0bcd181d..bdd60f16050f 100644 --- a/code/modules/events/disease_outbreak.dm +++ b/code/modules/events/disease_outbreak.dm @@ -22,10 +22,10 @@ /datum/round_event_control/disease_outbreak name = "Disease Outbreak: Classic" typepath = /datum/round_event/disease_outbreak - max_occurrences = 1 + max_occurrences = 2 min_players = 10 weight = 0 - track = EVENT_TRACK_MAJOR + track = EVENT_TRACK_MAJOR //monkie edit earliest_start = 55 MINUTES category = EVENT_CATEGORY_HEALTH description = "A 'classic' virus will infect some members of the crew." diff --git a/code/modules/events/ghost_role/blob.dm b/code/modules/events/ghost_role/blob.dm index 2cdf8174d63a..99836ba2b585 100644 --- a/code/modules/events/ghost_role/blob.dm +++ b/code/modules/events/ghost_role/blob.dm @@ -3,9 +3,8 @@ typepath = /datum/round_event/ghost_role/blob weight = 5 //monkie edit: 10 to 5 max_occurrences = 1 - min_players = 35 //monkie edit: 20 to 35 - earliest_start = 60 MINUTES //monkie edit: 20 to 90 + earliest_start = 80 MINUTES //monkie edit: 20 to 90 //dynamic_should_hijack = TRUE category = EVENT_CATEGORY_ENTITIES description = "Spawns a new blob overmind." diff --git a/code/modules/events/meteors/stray_meteor_event.dm b/code/modules/events/meteors/stray_meteor_event.dm index 53daff1ac8a1..09b91b36a1a2 100644 --- a/code/modules/events/meteors/stray_meteor_event.dm +++ b/code/modules/events/meteors/stray_meteor_event.dm @@ -1,9 +1,9 @@ /datum/round_event_control/stray_meteor name = "Stray Meteor" typepath = /datum/round_event/stray_meteor - weight = 15 //Number subject to change based on how often meteors actually collide with the station + weight = 18 //Number subject to change based on how often meteors actually collide with the station min_players = 15 - max_occurrences = 3 + max_occurrences = 6 earliest_start = 20 MINUTES category = EVENT_CATEGORY_SPACE description = "Throw a random meteor somewhere near the station." diff --git a/code/modules/events/portal_storm.dm b/code/modules/events/portal_storm.dm index 5296814dfadd..55e26bc191bd 100644 --- a/code/modules/events/portal_storm.dm +++ b/code/modules/events/portal_storm.dm @@ -32,6 +32,32 @@ /mob/living/basic/construct/wraith/hostile = 6, ) +//begin monkestation edit +/datum/round_event_control/portal_storm_monkey + name = "Portal Storm: Monkeys" + typepath = /datum/round_event/portal_storm/portal_storm_monkey + weight = 4 + max_occurrences = 2 + earliest_start = 20 MINUTES + category = EVENT_CATEGORY_ENTITIES + track = EVENT_TRACK_MAJOR + description = "Angry monkies pour out of portals." + +/datum/round_event/portal_storm/portal_storm_monkey + boss_types = list(/mob/living/basic/gorilla/lesser = 1) + hostile_types = list( + /mob/living/carbon/human/species/monkey/angry = 10, + ) + +/datum/round_event/portal_storm/portal_storm_monkey/announce(fake) + set waitfor = 0 + sound_to_playing_players('sound/magic/lightning_chargeup.ogg') + sleep(8 SECONDS) + priority_announce("Massive bluespace anomaly detected en route to [station_name()]. Brace for impact.") + sleep(2 SECONDS) + sound_to_playing_players('monkestation/sound/misc/monkeystorm.ogg') + +//end monkestation edit /datum/round_event/portal_storm start_when = 7 end_when = 999 diff --git a/code/modules/events/spider_infestation.dm b/code/modules/events/spider_infestation.dm index 63d965a523c6..bc740e5ba84b 100644 --- a/code/modules/events/spider_infestation.dm +++ b/code/modules/events/spider_infestation.dm @@ -1,7 +1,7 @@ /datum/round_event_control/spider_infestation name = "Spider Infestation" typepath = /datum/round_event/spider_infestation - weight = 6 //monkestation edit: from 10 to 6 + weight = 7 //monkestation edit: from 10 to 6 max_occurrences = 1 min_players = 35 //monkie edit: 20 to 35 earliest_start = 60 MINUTES //monke edit: 20 to 60 diff --git a/monkestation/code/game/machinery/bomb_actualizer.dm b/monkestation/code/game/machinery/bomb_actualizer.dm index cbf791e0cea1..e90f12c35c41 100644 --- a/monkestation/code/game/machinery/bomb_actualizer.dm +++ b/monkestation/code/game/machinery/bomb_actualizer.dm @@ -220,6 +220,15 @@ if(light > 12) capped_light = (GLOB.MAX_EX_LIGHT_RANGE + (light * actualizer_multiplier)) + if(capped_light > 200) + capped_light = 200 + + if(capped_medium > 120) + capped_medium = 120 + + if(capped_heavy > 60) + capped_heavy = 60 + SSexplosions.explode(location, capped_heavy, capped_medium, capped_light, flame, flash, TRUE, TRUE, FALSE, FALSE) exploded = TRUE return COMSIG_CANCEL_EXPLOSION diff --git a/monkestation/code/modules/storytellers/converted_events/event_overrides.dm b/monkestation/code/modules/storytellers/converted_events/event_overrides.dm index 22b582cf127b..918ddfad1280 100644 --- a/monkestation/code/modules/storytellers/converted_events/event_overrides.dm +++ b/monkestation/code/modules/storytellers/converted_events/event_overrides.dm @@ -137,6 +137,7 @@ /datum/round_event_control/operative track = EVENT_TRACK_MAJOR //this is a safe guard and does not trigger normally(technically it can but not really) so no tags + checks_antag_cap = TRUE /datum/round_event_control/portal_storm_syndicate track = EVENT_TRACK_MAJOR diff --git a/monkestation/sound/misc/monkeystorm.ogg b/monkestation/sound/misc/monkeystorm.ogg new file mode 100644 index 0000000000000000000000000000000000000000..aee1a1e5de4e9b76adc06a89cf16ce50ebec53c0 GIT binary patch literal 52752 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 cOg Date: Sun, 29 Sep 2024 19:13:26 +0000 Subject: [PATCH 19/25] Automatic changelog for PR #3570 [ci skip] --- html/changelogs/AutoChangeLog-pr-3570.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-3570.yml diff --git a/html/changelogs/AutoChangeLog-pr-3570.yml b/html/changelogs/AutoChangeLog-pr-3570.yml new file mode 100644 index 000000000000..91f8bd0197e7 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-3570.yml @@ -0,0 +1,5 @@ +author: "ThePooba" +delete-after: True +changes: + - rscadd: "monkeystorm" + - bugfix: "loneop less" \ No newline at end of file From e394c458fd34387245ff5e9ed7c5874eccc68b9b Mon Sep 17 00:00:00 2001 From: Changelogs Date: Sun, 29 Sep 2024 23:32:33 +0000 Subject: [PATCH 20/25] Automatic changelog compile [ci skip] --- html/changelogs/AutoChangeLog-pr-3570.yml | 5 ----- html/changelogs/AutoChangeLog-pr-3603.yml | 4 ---- html/changelogs/archive/2024-09.yml | 6 ++++++ 3 files changed, 6 insertions(+), 9 deletions(-) delete mode 100644 html/changelogs/AutoChangeLog-pr-3570.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-3603.yml diff --git a/html/changelogs/AutoChangeLog-pr-3570.yml b/html/changelogs/AutoChangeLog-pr-3570.yml deleted file mode 100644 index 91f8bd0197e7..000000000000 --- a/html/changelogs/AutoChangeLog-pr-3570.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: "ThePooba" -delete-after: True -changes: - - rscadd: "monkeystorm" - - bugfix: "loneop less" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-3603.yml b/html/changelogs/AutoChangeLog-pr-3603.yml deleted file mode 100644 index 04fb79ee9959..000000000000 --- a/html/changelogs/AutoChangeLog-pr-3603.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "CannibalHunter" -delete-after: True -changes: - - rscadd: "Added several more admin plushies to the monkeshop" \ No newline at end of file diff --git a/html/changelogs/archive/2024-09.yml b/html/changelogs/archive/2024-09.yml index 3be2cf0407b5..63e673d4dfcb 100644 --- a/html/changelogs/archive/2024-09.yml +++ b/html/changelogs/archive/2024-09.yml @@ -627,3 +627,9 @@ - balance: IPCs are no longer immune to being converted by revolutionaries and blood brothers. - qol: You now get a balloon alert if you get a second flash as a Blood Brother. +2024-09-29: + CannibalHunter: + - rscadd: Added several more admin plushies to the monkeshop + ThePooba: + - rscadd: monkeystorm + - bugfix: loneop less From 1a5a5e4904cd015bf3dfecefba9acc23a07117a5 Mon Sep 17 00:00:00 2001 From: Shoddd <148718717+Shoddd@users.noreply.github.com> Date: Sun, 29 Sep 2024 20:46:54 -0400 Subject: [PATCH 21/25] [Code Bounty] Buffs syndicate bible (#3578) * done * done for real this time --- code/modules/library/bibles.dm | 1 + 1 file changed, 1 insertion(+) diff --git a/code/modules/library/bibles.dm b/code/modules/library/bibles.dm index 564104baa9a3..fd8a7842a36e 100644 --- a/code/modules/library/bibles.dm +++ b/code/modules/library/bibles.dm @@ -319,6 +319,7 @@ GLOBAL_LIST_INIT(bibleitemstates, list( name = "Syndicate Tome" desc = "A very ominous tome resembling a bible." icon_state ="ebook" + slot_flags = ITEM_SLOT_BELT | ITEM_SLOT_POCKETS item_flags = NO_BLOOD_ON_ITEM throw_speed = 2 throw_range = 7 From 3955a095b3e9b89a157dc4a8fefa68fc16f22506 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 30 Sep 2024 00:47:15 +0000 Subject: [PATCH 22/25] Automatic changelog for PR #3578 [ci skip] --- html/changelogs/AutoChangeLog-pr-3578.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-3578.yml diff --git a/html/changelogs/AutoChangeLog-pr-3578.yml b/html/changelogs/AutoChangeLog-pr-3578.yml new file mode 100644 index 000000000000..a070c7c3d37a --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-3578.yml @@ -0,0 +1,4 @@ +author: "Shoddd" +delete-after: True +changes: + - balance: "syndicate bible can now provide anti-magic from pocket and belt" \ No newline at end of file From 6fd837997d525ee09863984b8d8cdf509bb1493c Mon Sep 17 00:00:00 2001 From: Ghosti <83688318+Gw0sty@users.noreply.github.com> Date: Sun, 29 Sep 2024 20:27:27 -0500 Subject: [PATCH 23/25] Delta botany double windoor fix (#3616) * Fixing Delta botany layering issue Was so ugly. Was so annoying. * Whoops * Revert "Whoops" This reverts commit bc2305b072cf4c06d44a631c548c8fb9cad3d3cf. * whoops --- _maps/map_files/Deltastation/DeltaStation2.dmm | 3 --- 1 file changed, 3 deletions(-) diff --git a/_maps/map_files/Deltastation/DeltaStation2.dmm b/_maps/map_files/Deltastation/DeltaStation2.dmm index d7ba4ec6ac92..636e928a1c46 100644 --- a/_maps/map_files/Deltastation/DeltaStation2.dmm +++ b/_maps/map_files/Deltastation/DeltaStation2.dmm @@ -100814,9 +100814,6 @@ "yba" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/door/window/left/directional/west{ - name = "Hydroponics Center" - }, /obj/machinery/door/window/left/directional/west{ name = "Hydroponics Center" }, From 028c6b45b090ae7d75a14330a1a4079f83d9a40a Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 30 Sep 2024 01:27:48 +0000 Subject: [PATCH 24/25] Automatic changelog for PR #3616 [ci skip] --- html/changelogs/AutoChangeLog-pr-3616.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-3616.yml diff --git a/html/changelogs/AutoChangeLog-pr-3616.yml b/html/changelogs/AutoChangeLog-pr-3616.yml new file mode 100644 index 000000000000..2d338963ca45 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-3616.yml @@ -0,0 +1,4 @@ +author: "Gw0sty" +delete-after: True +changes: + - bugfix: "Removed the second windoor on delta botany." \ No newline at end of file From 125eb279e01412de5bd3fab687405bf9c9a5cf10 Mon Sep 17 00:00:00 2001 From: Changelogs Date: Mon, 30 Sep 2024 01:43:07 +0000 Subject: [PATCH 25/25] Automatic changelog compile [ci skip] --- html/changelogs/AutoChangeLog-pr-3578.yml | 4 ---- html/changelogs/AutoChangeLog-pr-3616.yml | 4 ---- html/changelogs/archive/2024-09.yml | 5 +++++ 3 files changed, 5 insertions(+), 8 deletions(-) delete mode 100644 html/changelogs/AutoChangeLog-pr-3578.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-3616.yml diff --git a/html/changelogs/AutoChangeLog-pr-3578.yml b/html/changelogs/AutoChangeLog-pr-3578.yml deleted file mode 100644 index a070c7c3d37a..000000000000 --- a/html/changelogs/AutoChangeLog-pr-3578.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Shoddd" -delete-after: True -changes: - - balance: "syndicate bible can now provide anti-magic from pocket and belt" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-3616.yml b/html/changelogs/AutoChangeLog-pr-3616.yml deleted file mode 100644 index 2d338963ca45..000000000000 --- a/html/changelogs/AutoChangeLog-pr-3616.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Gw0sty" -delete-after: True -changes: - - bugfix: "Removed the second windoor on delta botany." \ No newline at end of file diff --git a/html/changelogs/archive/2024-09.yml b/html/changelogs/archive/2024-09.yml index 63e673d4dfcb..82bf8d2bb7a9 100644 --- a/html/changelogs/archive/2024-09.yml +++ b/html/changelogs/archive/2024-09.yml @@ -633,3 +633,8 @@ ThePooba: - rscadd: monkeystorm - bugfix: loneop less +2024-09-30: + Gw0sty: + - bugfix: Removed the second windoor on delta botany. + Shoddd: + - balance: syndicate bible can now provide anti-magic from pocket and belt