From 46152ac50e9d3714ece538ca69615e38a46db937 Mon Sep 17 00:00:00 2001 From: dwasint <82520990+dwasint@users.noreply.github.com> Date: Wed, 18 Dec 2024 19:59:15 -0800 Subject: [PATCH 01/81] Patreon stacking tokens fix (#4618) * converts tokens to build per month * part 2 automates the metacoins * Update preferences.dm * Update code/modules/client/preferences.dm * stuff * Update meta_tokens.dm * Update meta_tokens.dm --------- Co-authored-by: Lucy --- monkestation/code/datums/meta_tokens.dm | 7 ++++++- monkestation/code/modules/client/preferences.dm | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/monkestation/code/datums/meta_tokens.dm b/monkestation/code/datums/meta_tokens.dm index b1ff622e8870..a4f278f4da68 100644 --- a/monkestation/code/datums/meta_tokens.dm +++ b/monkestation/code/datums/meta_tokens.dm @@ -59,6 +59,10 @@ GLOBAL_LIST_INIT(patreon_etoken_values, list( /datum/meta_token_holder/proc/convert_list_to_tokens(list/saved_tokens) if(!length(saved_tokens)) return + for(var/token in saved_tokens) + if(isnull(saved_tokens[token])) + saved_tokens[token] = 0 + total_low_threat_tokens = saved_tokens["low_threat"] total_medium_threat_tokens = saved_tokens["medium_threat"] total_high_threat_tokens = saved_tokens["high_threat"] @@ -92,13 +96,14 @@ GLOBAL_LIST_INIT(patreon_etoken_values, list( if(!patreon?.has_access(ACCESS_COMMAND_RANK)) return FALSE var/month_number = text2num(time2text(world.time, "MM")) - owner.prefs.token_month = month_number if(owner.prefs.token_month != month_number) owner.prefs.adjust_metacoins(owner?.ckey, 10000, "Monthly Monkecoin rations.", TRUE, FALSE, FALSE) if(!patreon.has_access(ACCESS_TRAITOR_RANK)) owner.prefs.save_preferences() + owner.prefs.token_month = month_number return FALSE if(owner.prefs.token_month == month_number) + owner.prefs.token_month = month_number return FALSE donator_token++ owner.prefs.token_month = month_number diff --git a/monkestation/code/modules/client/preferences.dm b/monkestation/code/modules/client/preferences.dm index c8c7b67c98c9..773a4b31cc59 100644 --- a/monkestation/code/modules/client/preferences.dm +++ b/monkestation/code/modules/client/preferences.dm @@ -28,6 +28,7 @@ "low_threat" = 0, "event_tokens" = 0, "event_token_month" = 0, + "donator" = 0, ) ///amount of metaconis you can earn per shift From f0e787249382c2a63624bc216f597721336815b5 Mon Sep 17 00:00:00 2001 From: ThePooba <81843097+ThePooba@users.noreply.github.com> Date: Thu, 19 Dec 2024 12:20:54 -0700 Subject: [PATCH 02/81] more blugfixes (#4612) * added no interact to fartlight spear so you cant switch hands with it * thing * rem oves debug items from gifts * blacklisted debug and shitass items * uhh bugfix * fix maybe --- code/_globalvars/lists/maintenance_loot.dm | 2 +- code/game/objects/items/gift.dm | 17 ++++++++++++----- code/game/objects/structures/flora.dm | 4 ++-- code/modules/holiday/holidays.dm | 3 +-- .../effects/anomalies/anomalies_lifebringer.dm | 2 +- .../game/objects/items/implants/hardlight.dm | 5 +++++ .../art_sci_overrides/artifact_effects/bomb.dm | 2 +- 7 files changed, 23 insertions(+), 12 deletions(-) diff --git a/code/_globalvars/lists/maintenance_loot.dm b/code/_globalvars/lists/maintenance_loot.dm index c60c9105f541..bcb83d5d97e5 100644 --- a/code/_globalvars/lists/maintenance_loot.dm +++ b/code/_globalvars/lists/maintenance_loot.dm @@ -400,7 +400,7 @@ GLOBAL_LIST_INIT(maint_fauna, list(//fauna: there be critters living in yer main #define maint_uncommon_weight 900 #define maint_rarity_weight 99 #define maint_oddity_weight 4 //1 out of 10,000 would give metastation (180 spawns) a 2 in 111 chance of spawning an oddity per round, similar to xeno egg, monkestation edit: from 1 to 4 -#define maint_holiday_weight 2500 // When holiday loot is enabled, it'll give every loot item a 25% chance of being a holiday item +#define maint_holiday_weight 3500 // When holiday loot is enabled, it'll give every loot item a 25% chance of being a holiday item #define maint_fauna_weight 150 //monkestation edit: adds friendly maintenance bees, also allows for other maintenance fauna to be coded in. //Loot pool used by default maintenance loot spawners diff --git a/code/game/objects/items/gift.dm b/code/game/objects/items/gift.dm index 1b419999f47c..c1a5e10a1b38 100644 --- a/code/game/objects/items/gift.dm +++ b/code/game/objects/items/gift.dm @@ -116,17 +116,24 @@ GLOBAL_LIST_EMPTY(possible_gifts) // // Subtypes of these items will also be blocked. var/list/blocked_items = list( - // Can crash people if too many are spawned. - // NOTE: Not likely to be an issue if the amount is kept low - perhaps a limited variant - // of this (i.e. can only spawn up to 25 humans) could be added for players to use? - /obj/item/debug/human_spawner, // Just leaves the coordinates everywhere /obj/item/gps/visible_debug, // Can lag the hell out of the server /obj/item/gun/energy/recharge/kinetic_accelerator/meme, // Per Biddi's suggestion; plus doesn't seem to do much anyways? /obj/item/research, - ) + //only upsets people consistantly + /obj/item/gun/magic/wand/death, + /obj/item/gun/magic/wand/resurrection/debug, + //holy fuck why was this enabled + /obj/item/debug, + /obj/item/storage/box/debugtools, + /obj/item/gun/energy/beam_rifle/debug, + /obj/item/multitool/field_debug, + /obj/item/bounty_cube/debug_cube, + /obj/item/organ/internal/cyberimp/brain/nif/debug, + /obj/item/spellbook_charge/debug, + ) for(var/blocked_item as anything in blocked_items) // Block the item listed, and any subtypes too. gift_types_list -= typesof(blocked_item) diff --git a/code/game/objects/structures/flora.dm b/code/game/objects/structures/flora.dm index 0030e5543b4e..d3c0482462e7 100644 --- a/code/game/objects/structures/flora.dm +++ b/code/game/objects/structures/flora.dm @@ -462,10 +462,10 @@ if(!unlimited) took_presents[user.ckey] = TRUE - if(prob(50)) + if(prob(5)) user.put_in_hands(new gift_type(drop_location())) return - if(prob(1)) + if(prob(1)) //evil pooba monke moment new /mob/living/carbon/human/species/monkey/angry(drop_location()) to_chat(user, span_warning("A live monkey crawls out of the gift... its PISSED!!!")) return diff --git a/code/modules/holiday/holidays.dm b/code/modules/holiday/holidays.dm index ea1426515a5d..17a2cbc9656e 100644 --- a/code/modules/holiday/holidays.dm +++ b/code/modules/holiday/holidays.dm @@ -816,8 +816,7 @@ list( /obj/item/toy/xmas_cracker = 3, /obj/item/clothing/head/costume/santa = 1, - /obj/item/a_gift/anything = 1, - /obj/item/a_gift = 4 + /obj/item/a_gift/anything = 1 ) = maint_holiday_weight, ) diff --git a/monkestation/code/game/objects/effects/anomalies/anomalies_lifebringer.dm b/monkestation/code/game/objects/effects/anomalies/anomalies_lifebringer.dm index 35582d25aa6e..5f1d506dcc06 100644 --- a/monkestation/code/game/objects/effects/anomalies/anomalies_lifebringer.dm +++ b/monkestation/code/game/objects/effects/anomalies/anomalies_lifebringer.dm @@ -43,7 +43,7 @@ active = FALSE var/turf/open/tile = get_turf(src) if(istype(tile)) - tile.atmos_spawn_air("o2=10;plasma=1;TEMP=3000") + tile.atmos_spawn_air("o2=45;plasma=15;TEMP=6000") return var/mob/living/basic/pet/chosen_pet = pick(pet_type_cache) diff --git a/monkestation/code/game/objects/items/implants/hardlight.dm b/monkestation/code/game/objects/items/implants/hardlight.dm index d85536126869..daa5078b77a4 100644 --- a/monkestation/code/game/objects/items/implants/hardlight.dm +++ b/monkestation/code/game/objects/items/implants/hardlight.dm @@ -189,6 +189,7 @@ righthand_file = 'monkestation/icons/mob/inhands/polearms_righthand.dmi' slot_flags = null can_charge = FALSE //ITS A SPEAR + interaction_flags_item = NONE item_flags = NEEDS_PERMIT | DROPDEL | ABSTRACT | NO_MAT_REDEMPTION resistance_flags = LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF light_system = OVERLAY_LIGHT @@ -198,6 +199,10 @@ var/spears_left = 5 ammo_type = /obj/item/ammo_casing/magic/hardlight_spear +//obj/item/gun/magic/hardlight_spear/attack_hand(mob/user, list/modifiers) +// . = ..() + + /obj/item/gun/magic/hardlight_spear/Initialize(mapload) . = ..() AddComponent(/datum/component/jousting) diff --git a/monkestation/code/modules/art_sci_overrides/artifact_effects/bomb.dm b/monkestation/code/modules/art_sci_overrides/artifact_effects/bomb.dm index 56ec1504836b..9aa995be713d 100644 --- a/monkestation/code/modules/art_sci_overrides/artifact_effects/bomb.dm +++ b/monkestation/code/modules/art_sci_overrides/artifact_effects/bomb.dm @@ -97,7 +97,7 @@ /datum/artifact_effect/bomb/explosive/payload() if(!..()) return FALSE - explosion(our_artifact.holder, devast,heavy,light,light*1.5) + explosion(our_artifact.holder.loc, devast,heavy,light,light*1.5) on_destroy(src) /// DEVESTATING BOMB From 1fb4b2aa178d7e587eb93a14da8bcb80569c725f Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 19 Dec 2024 19:21:17 +0000 Subject: [PATCH 03/81] Automatic changelog for PR #4612 [ci skip] --- html/changelogs/AutoChangeLog-pr-4612.yml | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-4612.yml diff --git a/html/changelogs/AutoChangeLog-pr-4612.yml b/html/changelogs/AutoChangeLog-pr-4612.yml new file mode 100644 index 000000000000..669b0b98c490 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-4612.yml @@ -0,0 +1,7 @@ +author: "ThePooba" +delete-after: True +changes: + - balance: "christmas presents from 50% to 5% chance to get the \"toys only\" christmas present so you gusy get your op bullshit back, but added some stinky stuff to blacklist like the item spawner wand and the var edit wand(what the fuck)" + - balance: "thermonuclear catsplosion more dangerous, twice as likely" + - bugfix: "Added no interact to hardlight spears so you cant switch them in hand and hardlock yourself" + - bugfix: "i think tiny artifacts can now detonate properly now i couldnt get them to spawn properly" \ No newline at end of file From ae34543949a66371ec884565360a29467ed6caeb Mon Sep 17 00:00:00 2001 From: Ghosti <83688318+Gw0sty@users.noreply.github.com> Date: Thu, 19 Dec 2024 15:05:08 -0600 Subject: [PATCH 04/81] Adds upload to research directors remote (#4613) --- code/__DEFINES/access.dm | 1 + 1 file changed, 1 insertion(+) diff --git a/code/__DEFINES/access.dm b/code/__DEFINES/access.dm index 6be8af3db530..844faad63cba 100644 --- a/code/__DEFINES/access.dm +++ b/code/__DEFINES/access.dm @@ -474,6 +474,7 @@ #define REGION_RESEARCH "Research" /// Used to seed the accesses_by_region list in SSid_access. A list of all research regional accesses that are overseen by the RD. #define REGION_ACCESS_RESEARCH list( \ + ACCESS_AI_UPLOAD, \ ACCESS_GENETICS, \ ACCESS_MECH_SCIENCE, \ ACCESS_MINISAT, \ From a22ae88f6440d0152c4661c2a0450a563e339ea9 Mon Sep 17 00:00:00 2001 From: Lucy Date: Thu, 19 Dec 2024 16:05:44 -0500 Subject: [PATCH 05/81] Cargo imports UI now shows the correct price when the station has strong or distant supply lines (#4591) --- monkestation/code/modules/blueshift/components/armament.dm | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/monkestation/code/modules/blueshift/components/armament.dm b/monkestation/code/modules/blueshift/components/armament.dm index c7a8ea7f90f0..52e858ee876f 100644 --- a/monkestation/code/modules/blueshift/components/armament.dm +++ b/monkestation/code/modules/blueshift/components/armament.dm @@ -392,7 +392,7 @@ "ref" = REF(armament_entry), "icon" = armament_entry.cached_base64, "name" = armament_entry.name, - "cost" = armament_entry.cost, + "cost" = cost_calculate(armament_entry.cost), "buyable_ammo" = armament_entry.magazine ? TRUE : FALSE, "magazine_cost" = armament_entry.magazine_cost, "purchased" = purchased_items[armament_entry] ? purchased_items[armament_entry] : 0, @@ -492,7 +492,8 @@ if(!ishuman(user) && !issilicon(user)) return - if(!buyer.has_money(armament_entry.cost)) + var/actual_cost = cost_calculate(armament_entry.cost) + if(!buyer.has_money(actual_cost)) to_chat(user, span_warning("Not enough money!")) return @@ -524,7 +525,7 @@ var/datum/supply_pack/armament/created_pack = new created_pack.name = initial(armament_entry.item_type.name) - created_pack.cost = cost_calculate(armament_entry.cost) //Paid for seperately + created_pack.cost = actual_cost //Paid for seperately created_pack.contains = list(armament_entry.item_type) var/rank From a7a373209ca6a6c61e638f3d2dff2527fb340979 Mon Sep 17 00:00:00 2001 From: Ghosti <83688318+Gw0sty@users.noreply.github.com> Date: Thu, 19 Dec 2024 15:06:32 -0600 Subject: [PATCH 06/81] Various fixes part 2. Electric boogaloo : (#4584) * Fix #4478 & #4274 * Update job to icons * whoops * fix hopefully, bloody linters. * Blueshield modulzarization Will this work doctor? I HAVE NO IDEA! * Species modularization. * When .dmi doesnt save. * Im going to cry and ball this was in the code the entire time and it was never ticked so when I moved it ahbgdkujnbsjkgnfkh * Thesues christmas tree! * Solves a Run test in intregration tests noone cares about poor bitrunners. Will be missed * supermatter + radio update --- _maps/RandomRuins/SpaceRuins/oldstation.dmm | 7 +- _maps/map_files/Theseus/Theseus.dmm | 65 ++- code/datums/id_trim/jobs.dm | 2 +- code/modules/research/techweb/all_nodes.dm | 2 - .../items/devices/radio/encryptionkey.dm | 7 + .../code/modules/blueshield/clothing.dm | 2 +- .../code/modules/blueshield/devices/sensor.dm | 2 +- monkestation/code/modules/blueshield/gun.dm | 2 +- .../code/modules/blueshield/icons/device.dmi | Bin 884 -> 0 bytes .../modules/blueshield/icons/praetorian.dmi | Bin 1333 -> 0 bytes .../blueshield/icons/worn_praetorian.dmi | Bin 2081 -> 0 bytes .../code/modules/blueshield/modsuit/suit.dm | 4 +- .../code/modules/blueshield/modsuit/theme.dm | 4 +- monkestation/code/modules/blueshield/radio.dm | 6 - .../modules/jobs/departments/departments.dm | 15 + .../job.dm => jobs/job_types/blueshield.dm} | 9 - .../jobs/job_types/departments/departments.dm | 6 - .../ruins/spaceruin_code/oldstation.dm | 7 + .../living/carbon/human/species_type/ipc.dm} | 0 .../carbon/human/species_type/oozeling.dm} | 0 .../carbon/human/species_type/satyr.dm} | 0 .../modules/research/techweb/all_nodes.dm | 19 + .../smithing/ipcs/body/internal_organs.dm | 411 ----------------- .../code/modules/smithing/ipcs/research.dm | 19 - .../modules/smithing/oozelings/body/organs.dm | 420 ------------------ .../bodyparts/ipc_bodyparts.dm} | 0 .../bodyparts/oozeling_bodyparts.dm} | 0 .../bodyparts/satyr_bodyparts.dm} | 0 .../modules/surgery/organs/internal/brain.dm | 322 ++++++++++++++ .../modules/surgery/organs/internal/ears.dm | 54 +++ .../modules/surgery/organs/internal/eyes.dm | 48 ++ .../modules/surgery/organs/internal/heart.dm | 164 +++++++ .../modules/surgery/organs/internal/liver.dm | 55 +++ .../modules/surgery/organs/internal/lungs.dm | 59 +++ .../surgery/organs/internal/stomach.dm | 77 ++++ .../modules/surgery/organs/internal/tongue.dm | 54 +++ .../robot_brain_healing.dm | 0 .../robot_chest_repair.dm | 0 .../surgeries => surgery}/robot_healing.dm | 0 .../ipcs/surgeries => surgery}/steps.dm | 0 .../icons/mob/clothing/worn_modsuit.dmi | Bin 3506 -> 13104 bytes .../icons/obj/clothing/modsuits/modsuit.dmi | Bin 2144 -> 6944 bytes monkestation/icons/obj/device.dmi | Bin 75745 -> 76486 bytes .../blueshield/icons => icons/obj}/radio.dmi | Bin .../obj/weapons/guns/tech9.dmi} | Bin tgstation.dme | 27 +- .../tgui/interfaces/common/JobToIcon.ts | 20 + 47 files changed, 968 insertions(+), 921 deletions(-) delete mode 100644 monkestation/code/modules/blueshield/icons/device.dmi delete mode 100644 monkestation/code/modules/blueshield/icons/praetorian.dmi delete mode 100644 monkestation/code/modules/blueshield/icons/worn_praetorian.dmi delete mode 100644 monkestation/code/modules/blueshield/radio.dm create mode 100644 monkestation/code/modules/jobs/departments/departments.dm rename monkestation/code/modules/{blueshield/job.dm => jobs/job_types/blueshield.dm} (90%) delete mode 100644 monkestation/code/modules/jobs/job_types/departments/departments.dm rename monkestation/code/modules/{smithing/ipcs/species.dm => mob/living/carbon/human/species_type/ipc.dm} (100%) rename monkestation/code/modules/{smithing/oozelings/species.dm => mob/living/carbon/human/species_type/oozeling.dm} (100%) rename monkestation/code/modules/{ranching/satyr/species.dm => mob/living/carbon/human/species_type/satyr.dm} (100%) delete mode 100644 monkestation/code/modules/smithing/ipcs/body/internal_organs.dm delete mode 100644 monkestation/code/modules/smithing/ipcs/research.dm delete mode 100644 monkestation/code/modules/smithing/oozelings/body/organs.dm rename monkestation/code/modules/{smithing/ipcs/body/base_bodyparts.dm => surgery/bodyparts/ipc_bodyparts.dm} (100%) rename monkestation/code/modules/{smithing/oozelings/body/bodyparts.dm => surgery/bodyparts/oozeling_bodyparts.dm} (100%) rename monkestation/code/modules/{ranching/satyr/bodyparts.dm => surgery/bodyparts/satyr_bodyparts.dm} (100%) rename monkestation/code/modules/{smithing/ipcs/surgeries => surgery}/robot_brain_healing.dm (100%) rename monkestation/code/modules/{smithing/ipcs/surgeries => surgery}/robot_chest_repair.dm (100%) rename monkestation/code/modules/{smithing/ipcs/surgeries => surgery}/robot_healing.dm (100%) rename monkestation/code/modules/{smithing/ipcs/surgeries => surgery}/steps.dm (100%) rename monkestation/{code/modules/blueshield/icons => icons/obj}/radio.dmi (100%) rename monkestation/{code/modules/blueshield/icons/gun.dmi => icons/obj/weapons/guns/tech9.dmi} (100%) diff --git a/_maps/RandomRuins/SpaceRuins/oldstation.dmm b/_maps/RandomRuins/SpaceRuins/oldstation.dmm index 81e6e4e6245b..9771c0342e11 100644 --- a/_maps/RandomRuins/SpaceRuins/oldstation.dmm +++ b/_maps/RandomRuins/SpaceRuins/oldstation.dmm @@ -4847,10 +4847,13 @@ /area/ruin/space/ancientstation/beta/medbay) "ui" = ( /obj/effect/decal/cleanable/shreds, -/obj/structure/alien/weeds, /obj/structure/closet/crate/secure/science{ req_access = list("away_science") }, +/obj/item/encryptionkey/headset_uncommon, +/obj/item/encryptionkey/headset_uncommon, +/obj/item/encryptionkey/headset_uncommon, +/obj/structure/alien/weeds, /obj/item/transfer_valve, /obj/item/raw_anomaly_core/bluespace, /obj/item/raw_anomaly_core/random, @@ -8624,13 +8627,13 @@ /turf/open/floor/iron/solarpanel/airless, /area/ruin/space/solars/ancientstation/charlie/solars) "Uh" = ( -/obj/machinery/power/supermatter_crystal/shard, /obj/structure/closet/crate/engineering{ name = "supermatter shard crate"; secure = 1; locked = 1; icon_state = "engi_secure_crate" }, +/obj/machinery/power/supermatter_crystal/shard/oldstation, /turf/open/floor/iron/white/textured, /area/ruin/space/ancientstation/delta/proto) "Uj" = ( diff --git a/_maps/map_files/Theseus/Theseus.dmm b/_maps/map_files/Theseus/Theseus.dmm index a8b4e408725a..dad22ba8ccd3 100644 --- a/_maps/map_files/Theseus/Theseus.dmm +++ b/_maps/map_files/Theseus/Theseus.dmm @@ -4443,6 +4443,15 @@ }, /turf/open/floor/iron/dark, /area/station/security/range) +"bqW" = ( +/obj/effect/turf_decal/tile/neutral/full, +/obj/effect/turf_decal/stripes/line{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/structure/closet/emcloset, +/turf/open/floor/iron, +/area/station/security/processing) "brm" = ( /obj/machinery/chem_master/condimaster{ name = "CondiMaster Neo" @@ -9450,7 +9459,6 @@ /obj/machinery/door/airlock/external{ name = "Gulag Shuttle Airlock" }, -/obj/effect/mapping_helpers/airlock/access/all/security/brig, /turf/open/floor/plating, /area/station/security/processing) "cQj" = ( @@ -19743,10 +19751,6 @@ /turf/open/floor/iron, /area/station/construction) "fVH" = ( -/obj/machinery/computer/prisoner/gulag_teleporter_computer{ - dir = 8 - }, -/obj/effect/turf_decal/bot, /obj/effect/turf_decal/trimline/red/filled/line{ dir = 4 }, @@ -19756,6 +19760,9 @@ /obj/effect/turf_decal/stripes/line{ dir = 1 }, +/obj/machinery/gulag_teleporter, +/obj/effect/turf_decal/bot, +/obj/machinery/light/directional/east, /turf/open/floor/iron, /area/station/security/processing) "fVQ" = ( @@ -21898,21 +21905,16 @@ /turf/open/floor/iron/dark, /area/station/security/warden) "gFe" = ( -/obj/machinery/gulag_teleporter, -/obj/effect/turf_decal/bot, -/obj/machinery/gulag_item_reclaimer{ - pixel_x = 31 - }, -/obj/effect/turf_decal/trimline/red/filled/line{ - dir = 4 - }, /obj/effect/turf_decal/tile/neutral/half{ dir = 8 }, /obj/effect/turf_decal/stripes/line{ dir = 1 }, -/obj/machinery/light/directional/east, +/obj/effect/turf_decal/trimline/red/filled/corner, +/obj/effect/turf_decal/trimline/red/filled/corner{ + dir = 4 + }, /turf/open/floor/iron, /area/station/security/processing) "gFf" = ( @@ -33984,6 +33986,7 @@ /obj/structure/disposalpipe/segment{ dir = 4 }, +/obj/effect/spawner/xmastree, /turf/open/floor/iron, /area/station/hallway/primary/central) "kgT" = ( @@ -42128,13 +42131,15 @@ /turf/closed/wall, /area/station/commons/fitness/recreation/entertainment) "mxA" = ( -/obj/structure/closet/emcloset, -/obj/effect/turf_decal/delivery, /obj/effect/turf_decal/trimline/red/filled/line{ dir = 6 }, /obj/machinery/power/apc/auto_name/directional/east, /obj/structure/cable, +/obj/machinery/computer/prisoner/gulag_teleporter_computer{ + dir = 8 + }, +/obj/effect/turf_decal/bot, /turf/open/floor/iron, /area/station/security/processing) "mxD" = ( @@ -55293,12 +55298,13 @@ /area/station/hallway/primary/central/fore) "qtB" = ( /obj/structure/table, -/obj/item/knife{ +/obj/item/knife/kitchen{ pixel_x = -1; pixel_y = 5 }, -/obj/item/knife{ - pixel_x = -10 +/obj/item/knife/kitchen{ + pixel_x = -10; + pixel_y = 0 }, /obj/item/reagent_containers/cup/rag{ pixel_y = 5; @@ -58457,6 +58463,17 @@ /obj/effect/turf_decal/bot, /turf/open/floor/plating, /area/station/maintenance/starboard/central) +"roL" = ( +/obj/machinery/door/airlock/security, +/obj/effect/mapping_helpers/airlock/access/all/security/brig, +/obj/effect/mapping_helpers/airlock/unres{ + dir = 8 + }, +/obj/effect/turf_decal/trimline/red/filled/end{ + dir = 4 + }, +/turf/open/floor/iron, +/area/station/maintenance/port/fore) "rpb" = ( /turf/open/floor/engine/plasma, /area/station/engineering/atmos) @@ -67254,7 +67271,6 @@ /turf/open/floor/carpet, /area/station/hallway/secondary/exit/departure_lounge) "tQX" = ( -/obj/item/kirbyplants/random, /obj/effect/turf_decal/stripes/line{ dir = 5 }, @@ -67263,6 +67279,10 @@ }, /obj/structure/cable, /obj/machinery/camera/directional/east, +/obj/effect/turf_decal/delivery, +/obj/machinery/gulag_item_reclaimer{ + pixel_x = 31 + }, /turf/open/floor/iron, /area/station/security/processing) "tQY" = ( @@ -77835,7 +77855,6 @@ /obj/machinery/door/airlock/external{ name = "Gulag Shuttle Airlock" }, -/obj/effect/mapping_helpers/airlock/access/all/security/brig, /obj/machinery/light/floor/has_bulb, /turf/open/floor/plating, /area/station/security/processing) @@ -109295,7 +109314,7 @@ fTB ctl fTB rtt -cze +bqW mBO gxT xhM @@ -110066,7 +110085,7 @@ ijL ijL ijL ijL -ijL +roL ijL ijL xhM diff --git a/code/datums/id_trim/jobs.dm b/code/datums/id_trim/jobs.dm index e8227001977e..460000a14994 100644 --- a/code/datums/id_trim/jobs.dm +++ b/code/datums/id_trim/jobs.dm @@ -175,7 +175,7 @@ template_access = list( ACCESS_CAPTAIN, ACCESS_CHANGE_IDS, - ACCESS_QM, + ACCESS_HOP, ) job = /datum/job/bitrunner diff --git a/code/modules/research/techweb/all_nodes.dm b/code/modules/research/techweb/all_nodes.dm index ca21aa697171..c3fb51a129c4 100644 --- a/code/modules/research/techweb/all_nodes.dm +++ b/code/modules/research/techweb/all_nodes.dm @@ -533,7 +533,6 @@ design_ids = list( "surgery_heal_brute_upgrade", "surgery_heal_burn_upgrade", - "surgery_heal_robot_upgrade", // monkestation edit: robot surgeries "surgery_filter_upgrade", // monke edit: improved blood filter surgery ) research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 1000) @@ -547,7 +546,6 @@ design_ids = list( "surgery_heal_brute_upgrade_femto", "surgery_heal_burn_upgrade_femto", - "surgery_heal_robot_upgrade_femto", // monkestation edit: robot surgeries "surgery_heal_combo", "surgery_lobotomy", "surgery_wing_reconstruction", diff --git a/monkestation/code/game/objects/items/devices/radio/encryptionkey.dm b/monkestation/code/game/objects/items/devices/radio/encryptionkey.dm index 10997d861408..e87fa9c5253c 100644 --- a/monkestation/code/game/objects/items/devices/radio/encryptionkey.dm +++ b/monkestation/code/game/objects/items/devices/radio/encryptionkey.dm @@ -8,3 +8,10 @@ /obj/item/encryptionkey/headset_uncommon name = "dusty encryption key" channels = list(RADIO_CHANNEL_UNCOMMON = 1) + +/obj/item/encryptionkey/heads/blueshield + name = "\proper the blueshield's encryption key" + icon_state = "cypherkey_centcom" + channels = list(RADIO_CHANNEL_COMMAND = 1, RADIO_CHANNEL_SECURITY = 1) + greyscale_config = /datum/greyscale_config/encryptionkey_centcom + greyscale_colors = "#1d2657#dca01b" diff --git a/monkestation/code/modules/blueshield/clothing.dm b/monkestation/code/modules/blueshield/clothing.dm index 2a72e2317fda..25fcea522e56 100644 --- a/monkestation/code/modules/blueshield/clothing.dm +++ b/monkestation/code/modules/blueshield/clothing.dm @@ -204,7 +204,7 @@ /obj/item/radio/headset/headset_bs name = "\proper the blueshield's headset" desc = "The headset of the guy who keeps the administration alive." - icon = 'monkestation/code/modules/blueshield/icons/radio.dmi' + icon = 'monkestation/icons/obj/radio.dmi' worn_icon = 'monkestation/code/modules/blueshift/icons/mob/clothing/ears.dmi' icon_state = "bshield_headset" worn_icon_state = "bshield_headset" diff --git a/monkestation/code/modules/blueshield/devices/sensor.dm b/monkestation/code/modules/blueshield/devices/sensor.dm index 6f8a5aca717b..7dabd73dd255 100644 --- a/monkestation/code/modules/blueshield/devices/sensor.dm +++ b/monkestation/code/modules/blueshield/devices/sensor.dm @@ -1,7 +1,7 @@ /obj/item/sensor_device/blueshield name = "blueshield's handheld monitor" desc = "A unique model of handheld crew monitor that seems to have been customized for Executive Protection purposes." - icon = 'monkestation/code/modules/blueshield/icons/device.dmi' + icon = 'monkestation/icons/obj/device.dmi' icon_state = "blueshield_scanner" /obj/item/sensor_device/blueshield/attack_self(mob/user) diff --git a/monkestation/code/modules/blueshield/gun.dm b/monkestation/code/modules/blueshield/gun.dm index d4afe1d8af2d..9e3103913a26 100644 --- a/monkestation/code/modules/blueshield/gun.dm +++ b/monkestation/code/modules/blueshield/gun.dm @@ -104,7 +104,7 @@ burst_size = 4 fire_delay = 1 - icon = 'monkestation/code/modules/blueshield/icons/gun.dmi' + icon = 'monkestation/icons/obj/weapons/guns/tech9.dmi' icon_state = "tech9" fire_sound = 'monkestation/code/modules/blueshift/sounds/pistol_light.ogg' diff --git a/monkestation/code/modules/blueshield/icons/device.dmi b/monkestation/code/modules/blueshield/icons/device.dmi deleted file mode 100644 index 449e43052746dc23531228af5b9ed7bb7c36f99a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 884 zcmV-)1B?8LP)V=-0C=2JR&a84_w-Y6@%7{?OD!tS%+FJ>RWQ*r;NmRLOex6#a*U0*I5Sc+ z(=$pSoZ^zil2jm5DJiEkwKyX)H76y$I5{ydFSSUCi!&v&s2C_|$iAJX0V6)i zoTSkIre-E^{^?U^7^ciyjZ+V)>IngQ*v~@95qkQ%D16>Mum7|0@?xm__4zXc$Z}-$ zAO}ziXl*|eK1t-zL&Qb!9w zEBoEdOE_Ya?gF>$-P`@jJJq8YTUNVcD(G63cPWH9T+4~Fa4?ty6-pj8X36G*}*5Pg64m5V9W@_~h76R8ts~q~0Ds z4R-`K0J9vV4!zK%6wuOsya9mRy^PlUg3}SmmV?xR07xH5KhZ83Ap1$|4xeFIxMmdt zs5|=p-VGFWFE5^Eh<6c1$+Oh&4pZNLqPxS$1q-h3D0+cK&F(O*>?gWA3C0000yP)t-sz`(!_ z3>h9CG5{=DG&Dj0N|XRyyQKc~Pn4}GLuUYS;s8K^R8(OU5+*-CPyi!E0GZ4HGiLzI z|G>b&sG3`!00001bW%=J06^y0W&i*H#(Gp(bVOxyV{&P5bZKvH004NLosvxsf-n$; z*X=19*n&}E>&8F~3%Nsukv1tUX-AE>w_u_htbxpCe)_#PlQd?>@>JEVI9K!z)=8t; zf#sVmB@fx6@I|(#M1brBz6*yO!Kcw+IiRtU>$EW%tx>51uAq%5X{B}k&5n|*zqq&1n$&iDdtr#EX|%kJYOI}BZ2T?+wx-yY#3LLvd;L4L-Qh#nl_%KE-?Xg%(NOCh*qipM8Iz=hH|s2iV!CmxpXp+NSyoWpAGo0=+~; zNBF#k2(&@6u}MPz9Qd!kzk7jbd~Ojn3FYSqUv|l?gM50g<_*I4NB9He3tmWg$@&00 z`*c92U%4>`*w;UP2@cK@JmF#RX^f)jwo1T z7I6KP?nl`HTznqNBq~+_*H5QY;-`VWnHuK@E`vw=?8=l7IK z=J9h$NpG>|U#a{xmr}s_*6QQHl zqyBi3{!;*|pNUPh06xE$GM0kVg!14~pXSAdf$C?lP9S6#pUYC? z{0=PJ-1?}A`JE;~E9`t&yS@YfC%^`NZ<4J40QM5>jnC47!Rx@@{C@AiPUClVb#--h z{r`&iz10uv2mIdZOT?#Q3Q=qLwAnP62yHb^#P2cRXJO0V&&t}+OS7JU;`1Lo5Uytu^SkfQ zaHr&w`XJN`^XxINdlmBglRnh?L+!d8Gbi|YWW?{!`@qw#n?Vp!5V=10V}O9)Tl^b! z&H;wH3R(b%-#7U_{Yna)7h<(k5x<9gzm0yuWbkMP8)w*{Xa=3{ySlo%y1I^6y{cNT zuI_SD-{p6{zE4b(L2m8KI&I}0e&+yuO%3Gs?>lhk_heo&LFOJ5{Q2_$F~9E{U<1GJ z8(>iQT?tTkf4zNMe>MH#Kb&C2?@EB61C1T}#qY`ya{8;X7oysMh5rmZEcsn4UweD& zu>w}Ezg5ET%JXx7vghc)y2UsI=OF`w700000NkvXXu0mjflPi=N diff --git a/monkestation/code/modules/blueshield/icons/worn_praetorian.dmi b/monkestation/code/modules/blueshield/icons/worn_praetorian.dmi deleted file mode 100644 index 373986abe4dedef9809130b996fa33363d0befb2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2081 zcmY*Xdpy%^8~^cy-U;b(3QgrfAxV={v(lV$W)ZbXDinoc%VtuJi4r+(&x%Bn$vNX4 z%BeDPcsIv6PY%s_Z8qL{KK=2&f85vizOMWJUf<94z3)V4M{6mNG6(eBMNVQnZrviu48TO9rRPFC^b#Klq%Rm5SP` z=JIN6-9n0KVd`J(I!Uwj0~OoP5_dsU7#g}9sfwUftb4nx%r8jDBDA@k})(#j}|n$c+Z#5j&o zX5MpmbdyEjcbUK$O~jTR{=~CUJf2eF{gr&9h>$j!W{dZhTzkUV;>s8Q>%^lIn*}Dq zei}=Vy|W(Y8>`n-(+^TJyrZooT2k9~%cS;Gx`R}lDbw^J!^1;Uuhg582VBQc-1R-< zyPxH5*ynyU)L7m58vqb|ajIfao>lkGF@Dl9ch&lbl6sTB$58)(bQ&_~rq`CS1B?9c zTYbCIkWFDoyIF^<1+VBtZayT)dOQE;pp~uu(2KjU2oc8t%NBm}Y;TgBes z$(`d6LZN7~-4yQnNL>s~F}JiY(MzN+(qn!?b{bYNMG`;+DH7SH@#GKjCx+A zqlnqCcW8~GcvZ1#u|2StjY>fFRjaSky;;mR%m!(dbqd`lAI~uj>}UVu696ci{Xko5 zAgN}?9lVk6w*72rr(!%BBQBtAd|0D=IysNdIR~ejovy$an!wj6lWA|5ouP4|n`RBr z;gcj=PQtVrqm*eFc0k(EBNG4E&S*9W#TaL}+`8IpZDn1ctCPTTilx`MtTyw+Z0p92 zba-!hR+m85L-epaN9%W0p-^~*4$__~3LC0Z@&bcAt?TfLxaqmRpgnw~iCrB;_P(HI z;XGde^5wd{%7RuU-*Fua;Rh?lBu(p;KtUrA?5L6x?_mvcy7Rhk`&^D>%+DQsKA1#Z`vZ}wIBmd1yLRd2(z%4@61xLljPEo}ISG zhT(ocHNzr6poiY-;URzW3)U&a+@yK*$JOl&yvKPM-%wDRj=y-B`jr^9bfkoNo#u@a z?y0r-OtYwv9ooeI(-i6KP}cEM<}}TFhxE@y*l(f0*OmCpT%peG|IDHFGVz(&;qUQu z?rCAceIAX}6zCbfTc@PdZ_wG``1+Gu&uhAwQW;e|WLYkcc*-hXR(l>@84xue0fYan zKE!SlU;DtWLKZUj&vi}ZbH=Vk=$5@#6hn>DBsaN>qh(A%S55K?A6$Pb*`rKnO z-ksMD9*lJt+h{8bLRX~Ktv4?#nBwp=hE7->&2dxETB;g&`s>lY#p&Yf-N?5>KSRR#W~cS8qsAwk@}v1_d9j?hf8}ZgP&(3^YxQ;9~;5Wwxw3I zb6UcEqaPdhaB7^u3hR_ys+{2G>-vU+bfZ6MwIkG~{Q%G?yW8l85_<0QLcAYJ^xXhg zQ=S*u-(_NM+d$BBq)L7kqhPPq9pR-GS04TsM>ist diff --git a/monkestation/code/modules/blueshield/modsuit/suit.dm b/monkestation/code/modules/blueshield/modsuit/suit.dm index 7314f5f60f6a..7328c7f19ec5 100644 --- a/monkestation/code/modules/blueshield/modsuit/suit.dm +++ b/monkestation/code/modules/blueshield/modsuit/suit.dm @@ -1,6 +1,6 @@ /obj/item/mod/control/pre_equipped/blueshield - worn_icon = 'monkestation/code/modules/blueshield/icons/worn_praetorian.dmi' - icon = 'monkestation/code/modules/blueshield/icons/praetorian.dmi' + worn_icon = 'monkestation/icons/mob/clothing/worn_modsuit.dmi' + icon = 'monkestation/icons/obj/clothing/modsuits/modsuit.dmi' icon_state = "praetorian-control" theme = /datum/mod_theme/blueshield applied_cell = /obj/item/stock_parts/cell/high diff --git a/monkestation/code/modules/blueshield/modsuit/theme.dm b/monkestation/code/modules/blueshield/modsuit/theme.dm index ca1bd0838c52..3cf453b73e6e 100644 --- a/monkestation/code/modules/blueshield/modsuit/theme.dm +++ b/monkestation/code/modules/blueshield/modsuit/theme.dm @@ -22,8 +22,8 @@ ) skins = list( "praetorian" = list( - MOD_ICON_OVERRIDE = 'monkestation/code/modules/blueshield/icons/praetorian.dmi', - MOD_WORN_ICON_OVERRIDE = 'monkestation/code/modules/blueshield/icons/worn_praetorian.dmi', + MOD_ICON_OVERRIDE = 'monkestation/icons/obj/clothing/modsuits/modsuit.dmi', + MOD_WORN_ICON_OVERRIDE = 'monkestation/icons/mob/clothing/worn_modsuit.dmi', HELMET_FLAGS = list( UNSEALED_LAYER = null, UNSEALED_CLOTHING = SNUG_FIT|THICKMATERIAL, diff --git a/monkestation/code/modules/blueshield/radio.dm b/monkestation/code/modules/blueshield/radio.dm deleted file mode 100644 index deddf9bc4eb8..000000000000 --- a/monkestation/code/modules/blueshield/radio.dm +++ /dev/null @@ -1,6 +0,0 @@ -/obj/item/encryptionkey/heads/blueshield - name = "\proper the blueshield's encryption key" - icon_state = "cypherkey_centcom" - channels = list(RADIO_CHANNEL_COMMAND = 1, RADIO_CHANNEL_SECURITY = 1) - greyscale_config = /datum/greyscale_config/encryptionkey_centcom - greyscale_colors = "#1d2657#dca01b" diff --git a/monkestation/code/modules/jobs/departments/departments.dm b/monkestation/code/modules/jobs/departments/departments.dm new file mode 100644 index 000000000000..447e28c76174 --- /dev/null +++ b/monkestation/code/modules/jobs/departments/departments.dm @@ -0,0 +1,15 @@ +/datum/job_department/central_command + department_name = DEPARTMENT_CENTRAL_COMMAND + department_bitflags = DEPARTMENT_BITFLAG_CENTRAL_COMMAND + department_head = /datum/job/captain + department_experience_type = EXP_TYPE_CENTRAL_COMMAND + display_order = 1 + label_class = "command" + ui_color = "#86ff82" + +/datum/job_department/late + department_name = DEPARTMENT_LATE + department_bitflags = DEPARTMENT_BITFLAG_LATE + display_order = 10 + label_class = "latejoin" + ui_color = "#0b6b2b" diff --git a/monkestation/code/modules/blueshield/job.dm b/monkestation/code/modules/jobs/job_types/blueshield.dm similarity index 90% rename from monkestation/code/modules/blueshield/job.dm rename to monkestation/code/modules/jobs/job_types/blueshield.dm index 7bd45ba2b900..236225dba23a 100644 --- a/monkestation/code/modules/blueshield/job.dm +++ b/monkestation/code/modules/jobs/job_types/blueshield.dm @@ -77,12 +77,3 @@ head = /obj/item/clothing/head/helmet/space/plasmaman/blueshield uniform = /obj/item/clothing/under/plasmaman/blueshield - -/datum/job_department/central_command - department_name = DEPARTMENT_CENTRAL_COMMAND - department_bitflags = DEPARTMENT_BITFLAG_CENTRAL_COMMAND - department_head = /datum/job/captain - department_experience_type = EXP_TYPE_CENTRAL_COMMAND - display_order = 1 - label_class = "command" - ui_color = "#86ff82" diff --git a/monkestation/code/modules/jobs/job_types/departments/departments.dm b/monkestation/code/modules/jobs/job_types/departments/departments.dm deleted file mode 100644 index 6b2e4b6a896f..000000000000 --- a/monkestation/code/modules/jobs/job_types/departments/departments.dm +++ /dev/null @@ -1,6 +0,0 @@ -/datum/job_department/late - department_name = DEPARTMENT_LATE - department_bitflags = DEPARTMENT_BITFLAG_LATE - display_order = 10 - label_class = "latejoin" - ui_color = "#0b6b2b" diff --git a/monkestation/code/modules/mapfluff/ruins/spaceruin_code/oldstation.dm b/monkestation/code/modules/mapfluff/ruins/spaceruin_code/oldstation.dm index 1083c4474101..1f723d55e9f4 100644 --- a/monkestation/code/modules/mapfluff/ruins/spaceruin_code/oldstation.dm +++ b/monkestation/code/modules/mapfluff/ruins/spaceruin_code/oldstation.dm @@ -2,3 +2,10 @@ name = "Reminder - air distrubtion." default_raw_text = "Reminder!

Blue on layer 4 is for air.
Red on layer 2 is for the scrubbers.

\ The dispenser prints our pipes with this in mind so they dont get accidentally connected. Doesn't matter if 'purple is a pretty colour', it won't connect." + +/obj/machinery/power/supermatter_crystal/shard/oldstation + name = "Worn Supermatter Shard" + desc = "This shard has lost some of its lustrous shine." + radio_key = /obj/item/encryptionkey/headset_uncommon + emergency_channel = "Uncommon" + warning_channel = "Uncommon" diff --git a/monkestation/code/modules/smithing/ipcs/species.dm b/monkestation/code/modules/mob/living/carbon/human/species_type/ipc.dm similarity index 100% rename from monkestation/code/modules/smithing/ipcs/species.dm rename to monkestation/code/modules/mob/living/carbon/human/species_type/ipc.dm diff --git a/monkestation/code/modules/smithing/oozelings/species.dm b/monkestation/code/modules/mob/living/carbon/human/species_type/oozeling.dm similarity index 100% rename from monkestation/code/modules/smithing/oozelings/species.dm rename to monkestation/code/modules/mob/living/carbon/human/species_type/oozeling.dm diff --git a/monkestation/code/modules/ranching/satyr/species.dm b/monkestation/code/modules/mob/living/carbon/human/species_type/satyr.dm similarity index 100% rename from monkestation/code/modules/ranching/satyr/species.dm rename to monkestation/code/modules/mob/living/carbon/human/species_type/satyr.dm diff --git a/monkestation/code/modules/research/techweb/all_nodes.dm b/monkestation/code/modules/research/techweb/all_nodes.dm index 185a205b6e02..f01f962f74e6 100644 --- a/monkestation/code/modules/research/techweb/all_nodes.dm +++ b/monkestation/code/modules/research/techweb/all_nodes.dm @@ -350,3 +350,22 @@ research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 500) hidden = TRUE +/datum/techweb_node/improved_robotic_tend_wounds + id = "improved_robotic_surgery" + display_name = "Improved Robotic Repair Surgeries" + description = "As it turns out, you don't actually need to cut out entire support rods if it's just scratched!" + prereq_ids = list("engineering") + design_ids = list( + "surgery_heal_robot_upgrade", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 900) + +/datum/techweb_node/advanced_robotic_tend_wounds + id = "advanced_robotic_surgery" + display_name = "Advanced Robotic Surgeries" + description = "Did you know Hephaestus actually has a free online tutorial for synthetic trauma repairs? It's true!" + prereq_ids = list("improved_robotic_surgery") + design_ids = list( + "surgery_heal_robot_upgrade_femto", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 1300) // less expensive than the organic surgery research equivalent since its JUST tend wounds diff --git a/monkestation/code/modules/smithing/ipcs/body/internal_organs.dm b/monkestation/code/modules/smithing/ipcs/body/internal_organs.dm deleted file mode 100644 index 3a8849a9b783..000000000000 --- a/monkestation/code/modules/smithing/ipcs/body/internal_organs.dm +++ /dev/null @@ -1,411 +0,0 @@ -/obj/item/organ/internal/brain/synth - name = "compact positronic brain" - slot = ORGAN_SLOT_BRAIN - zone = BODY_ZONE_HEAD - organ_flags = ORGAN_ROBOTIC | ORGAN_SYNTHETIC_FROM_SPECIES - maxHealth = 2 * STANDARD_ORGAN_THRESHOLD - desc = "A cube of shining metal, four inches to a side and covered in shallow grooves. It has an IPC serial number engraved on the top. It is usually slotted into the chest of synthetic crewmembers." - icon = 'monkestation/code/modules/smithing/icons/ipc_organ.dmi' - icon_state = "posibrain-ipc" - /// The last time (in ticks) a message about brain damage was sent. Don't touch. - var/last_message_time = 0 - -/obj/item/organ/internal/brain/synth/on_insert(mob/living/carbon/brain_owner) - . = ..() - - if(brain_owner.stat != DEAD || !ishuman(brain_owner)) - return - - var/mob/living/carbon/human/user_human = brain_owner - if(HAS_TRAIT(user_human, TRAIT_REVIVES_BY_HEALING) && user_human.health > SYNTH_BRAIN_WAKE_THRESHOLD) - if(!HAS_TRAIT(user_human, TRAIT_DEFIB_BLACKLISTED)) - user_human.revive(FALSE) - -/obj/item/organ/internal/brain/synth/emp_act(severity) // EMP act against the posi, keep the cap far below the organ health - . = ..() - - if(!owner || . & EMP_PROTECT_SELF) - return - - if(!COOLDOWN_FINISHED(src, severe_cooldown)) //So we cant just spam emp to kill people. - COOLDOWN_START(src, severe_cooldown, 10 SECONDS) - - switch(severity) - if(EMP_HEAVY) - to_chat(owner, span_warning("01001001 00100111 01101101 00100000 01100110 01110101 01100011 01101011 01100101 01100100 00101110")) - apply_organ_damage(SYNTH_ORGAN_HEAVY_EMP_DAMAGE, SYNTH_EMP_BRAIN_DAMAGE_MAXIMUM, required_organtype = ORGAN_ROBOTIC) - if(EMP_LIGHT) - to_chat(owner, span_warning("Alert: Electromagnetic damage taken in central processing unit. Error Code: 401-YT")) - apply_organ_damage(SYNTH_ORGAN_LIGHT_EMP_DAMAGE, SYNTH_EMP_BRAIN_DAMAGE_MAXIMUM, required_organtype = ORGAN_ROBOTIC) - -/obj/item/organ/internal/brain/synth/apply_organ_damage(damage_amount, maximumm, required_organtype) - . = ..() - - if(owner && damage > 0 && (world.time - last_message_time) > SYNTH_BRAIN_DAMAGE_MESSAGE_INTERVAL) - last_message_time = world.time - - if(damage > BRAIN_DAMAGE_SEVERE) - to_chat(owner, span_warning("Alre: re oumtnin ilir tocorr:pa ni ne:cnrrpiioruloomatt cessingode: P1_1-H")) - return - - if(damage > BRAIN_DAMAGE_MILD) - to_chat(owner, span_warning("Alert: Minor corruption in central processing unit. Error Code: 001-HP")) - -/* -/obj/item/organ/internal/brain/synth/circuit - name = "compact AI circuit" - desc = "A compact and extremely complex circuit, perfectly dimensioned to fit in the same slot as a synthetic-compatible positronic brain. It is usually slotted into the chest of synthetic crewmembers." - icon = 'monkestation/code/modules/smithing/icons/ipc_organ.dmi' - icon_state = "circuit-occupied" - inhand_icon_state = "electronic" - lefthand_file = 'icons/mob/inhands/items/devices_lefthand.dmi' - righthand_file = 'icons/mob/inhands/items/devices_righthand.dmi' -*/ - -/obj/item/organ/internal/brain/synth/mmi - name = "compact man-machine interface" - desc = "A compact man-machine interface, perfectly dimensioned to fit in the same slot as a synthetic-compatible positronic brain. Unfortunately, the brain seems to be permanently attached to the circuitry, and it seems relatively sensitive to it's environment. It is usually slotted into the chest of synthetic crewmembers." - icon = 'monkestation/code/modules/smithing/icons/ipc_organ.dmi' - icon_state = "mmi-ipc" - -/obj/item/organ/internal/ears/synth - name = "auditory sensors" - icon = 'monkestation/code/modules/smithing/icons/ipc_organ.dmi' - icon_state = "ears-ipc" - desc = "A pair of microphones intended to be installed in an IPC or Synthetics head, that grant the ability to hear." - zone = BODY_ZONE_HEAD - slot = ORGAN_SLOT_EARS - gender = PLURAL - maxHealth = 1 * STANDARD_ORGAN_THRESHOLD - organ_flags = ORGAN_ROBOTIC | ORGAN_SYNTHETIC_FROM_SPECIES - -/obj/item/organ/internal/ears/synth/emp_act(severity) - . = ..() - - if(!owner || . & EMP_PROTECT_SELF) - return - - if(!COOLDOWN_FINISHED(src, severe_cooldown)) //So we cant just spam emp to kill people. - COOLDOWN_START(src, severe_cooldown, 10 SECONDS) - - switch(severity) - if(EMP_HEAVY) - owner.set_jitter_if_lower(SYNTH_BAD_EFFECT_DURATION * SYNTH_HEAVY_EMP_MULTIPLIER) - owner.set_dizzy_if_lower(SYNTH_BAD_EFFECT_DURATION * SYNTH_HEAVY_EMP_MULTIPLIER) - adjustEarDamage(SYNTH_ORGAN_HEAVY_EMP_DAMAGE, SYNTH_DEAF_STACKS) - to_chat(owner, span_warning("Alert: Null feedback from auditory sensors detected, seek maintenance immediately. Error Code: AS-105")) - - if(EMP_LIGHT) - owner.set_jitter_if_lower(SYNTH_BAD_EFFECT_DURATION) - owner.set_dizzy_if_lower(SYNTH_BAD_EFFECT_DURATION) - adjustEarDamage(SYNTH_ORGAN_LIGHT_EMP_DAMAGE, SYNTH_DEAF_STACKS) - to_chat(owner, span_warning("Alert: Anomalous feedback from auditory sensors detected. Error Code: AS-50")) - -/datum/design/synth_ears - name = "Auditory Sensors" - desc = "A pair of microphones intended to be installed in an IPC or Synthetics head, that grant the ability to hear." - id = "synth_ears" - build_type = PROTOLATHE | AWAY_LATHE | MECHFAB - construction_time = 4 SECONDS - materials = list( - /datum/material/iron = HALF_SHEET_MATERIAL_AMOUNT, - /datum/material/glass = HALF_SHEET_MATERIAL_AMOUNT, - ) - build_path = /obj/item/organ/internal/ears/synth - category = list( - RND_CATEGORY_CYBERNETICS + RND_SUBCATEGORY_CYBERNETICS_ORGANS_1 - ) - departmental_flags = DEPARTMENT_BITFLAG_MEDICAL | DEPARTMENT_BITFLAG_SCIENCE - -/obj/item/organ/internal/eyes/synth - name = "optical sensors" - icon_state = "cybernetic_eyeballs" - 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_DOESNT_PROTECT_AGAINST_CONVERSION - -/obj/item/organ/internal/eyes/synth/emp_act(severity) - . = ..() - - if(!owner || . & EMP_PROTECT_SELF) - return - - switch(severity) - if(EMP_HEAVY) - to_chat(owner, span_warning("Alert:Severe electromagnetic interference clouds your optics with static. Error Code: I-CS6")) - apply_organ_damage(SYNTH_ORGAN_HEAVY_EMP_DAMAGE, maxHealth, required_organtype = ORGAN_ROBOTIC) - if(EMP_LIGHT) - to_chat(owner, span_warning("Alert: Mild interference clouds your optics with static. Error Code: I-CS0")) - apply_organ_damage(SYNTH_ORGAN_LIGHT_EMP_DAMAGE, maxHealth, required_organtype = ORGAN_ROBOTIC) - -/datum/design/synth_eyes - name = "Optical Sensors" - desc = "A very basic set of optical sensors with no extra vision modes or functions." - id = "synth_eyes" - build_type = PROTOLATHE | AWAY_LATHE | MECHFAB - construction_time = 4 SECONDS - materials = list( - /datum/material/iron = HALF_SHEET_MATERIAL_AMOUNT, - /datum/material/glass = HALF_SHEET_MATERIAL_AMOUNT, - ) - build_path = /obj/item/organ/internal/eyes/synth - category = list( - RND_CATEGORY_CYBERNETICS + RND_SUBCATEGORY_CYBERNETICS_ORGANS_1 - ) - departmental_flags = DEPARTMENT_BITFLAG_MEDICAL | DEPARTMENT_BITFLAG_SCIENCE - -/obj/item/organ/internal/heart/synth - name = "hydraulic pump engine" - desc = "An electronic device that handles the hydraulic pumps, powering one's robotic limbs. Without this, synthetics are unable to move." - organ_flags = ORGAN_ROBOTIC | ORGAN_SYNTHETIC_FROM_SPECIES - icon = 'monkestation/code/modules/smithing/icons/ipc_organ.dmi' - icon_state = "heart-ipc-on" - base_icon_state = "heart-ipc" - maxHealth = 1.5 * STANDARD_ORGAN_THRESHOLD // 1.5x due to synthcode.tm being weird - zone = BODY_ZONE_CHEST - slot = ORGAN_SLOT_HEART - var/last_message_time = 0 - -/obj/item/organ/internal/heart/synth/emp_act(severity) - . = ..() - - if(!owner || . & EMP_PROTECT_SELF) - return - - if(!COOLDOWN_FINISHED(src, severe_cooldown)) //So we cant just spam emp to kill people. - COOLDOWN_START(src, severe_cooldown, 10 SECONDS) - - switch(severity) - if(EMP_HEAVY) - to_chat(owner, span_warning("Alert: Main hydraulic pump control has taken severe damage, seek maintenance immediately. Error code: HP300-10.")) - apply_organ_damage(SYNTH_ORGAN_HEAVY_EMP_DAMAGE, maxHealth, required_organtype = ORGAN_ROBOTIC) - if(EMP_LIGHT) - to_chat(owner, span_warning("Alert: Main hydraulic pump control has taken light damage, seek maintenance immediately. Error code: HP300-05.")) - apply_organ_damage(SYNTH_ORGAN_LIGHT_EMP_DAMAGE, maxHealth, required_organtype = ORGAN_ROBOTIC) - -/datum/design/synth_heart - name = "Hydraulic Pump Engine" - desc = "An electronic device that handles the hydraulic pumps, powering one's robotic limbs. Without this, synthetics are unable to move." - id = "synth_heart" - build_type = PROTOLATHE | AWAY_LATHE | MECHFAB - construction_time = 4 SECONDS - materials = list( - /datum/material/iron = HALF_SHEET_MATERIAL_AMOUNT, - /datum/material/glass = HALF_SHEET_MATERIAL_AMOUNT, - ) - build_path = /obj/item/organ/internal/heart/synth - category = list( - RND_CATEGORY_CYBERNETICS + RND_SUBCATEGORY_CYBERNETICS_ORGANS_1 - ) - departmental_flags = DEPARTMENT_BITFLAG_MEDICAL | DEPARTMENT_BITFLAG_SCIENCE - -/obj/item/organ/internal/liver/synth - name = "reagent processing unit" - desc = "An electronic device that processes the beneficial chemicals for the synthetic user." - icon = 'monkestation/code/modules/smithing/icons/ipc_organ.dmi' - icon_state = "liver-ipc" - filterToxins = FALSE //We dont filter them, we're immune to them - zone = BODY_ZONE_CHEST - slot = ORGAN_SLOT_LIVER - maxHealth = 1 * STANDARD_ORGAN_THRESHOLD - organ_flags = ORGAN_ROBOTIC | ORGAN_SYNTHETIC_FROM_SPECIES - -/obj/item/organ/internal/liver/synth/emp_act(severity) - . = ..() - - if(!owner || . & EMP_PROTECT_SELF) - return - - if(!COOLDOWN_FINISHED(src, severe_cooldown)) //So we cant just spam emp to kill people. - COOLDOWN_START(src, severe_cooldown, 10 SECONDS) - - switch(severity) - if(EMP_HEAVY) - to_chat(owner, span_warning("Alert: Critical! Reagent processing unit failure, seek maintenance immediately. Error Code: DR-1k")) - apply_organ_damage(SYNTH_ORGAN_HEAVY_EMP_DAMAGE, maxHealth, required_organtype = ORGAN_ROBOTIC) - - if(EMP_LIGHT) - to_chat(owner, span_warning("Alert: Reagent processing unit failure, seek maintenance for diagnostic. Error Code: DR-0k")) - apply_organ_damage(SYNTH_ORGAN_LIGHT_EMP_DAMAGE, maxHealth, required_organtype = ORGAN_ROBOTIC) - -/datum/design/synth_liver - name = "Reagent Processing Unit" - desc = "An electronic device that processes the beneficial chemicals for the synthetic user." - id = "synth_liver" - build_type = PROTOLATHE | AWAY_LATHE | MECHFAB - construction_time = 4 SECONDS - materials = list( - /datum/material/iron = HALF_SHEET_MATERIAL_AMOUNT, - /datum/material/glass = HALF_SHEET_MATERIAL_AMOUNT, - ) - build_path = /obj/item/organ/internal/liver/synth - category = list( - RND_CATEGORY_CYBERNETICS + RND_SUBCATEGORY_CYBERNETICS_ORGANS_1 - ) - departmental_flags = DEPARTMENT_BITFLAG_MEDICAL | DEPARTMENT_BITFLAG_SCIENCE - -/obj/item/organ/internal/lungs/synth - name = "heatsink" - desc = "A device that transfers generated heat to a fluid medium to cool it down. Required to keep your synthetics cool-headed. It's shape resembles lungs." //Purposefully left the 'fluid medium' ambigious for interpretation of the character, whether it be air or fluid cooling - icon = 'monkestation/code/modules/smithing/icons/ipc_organ.dmi' - icon_state = "lungs-ipc" - safe_nitro_min = 0 - safe_co2_max = 0 - safe_plasma_min = 0 - safe_plasma_max = 0 - safe_oxygen_min = 0 //What are you doing man, dont breathe with those! - safe_oxygen_max = 0 - zone = BODY_ZONE_CHEST - slot = ORGAN_SLOT_LUNGS - maxHealth = 1.5 * STANDARD_ORGAN_THRESHOLD - organ_flags = ORGAN_ROBOTIC | ORGAN_SYNTHETIC_FROM_SPECIES - -/obj/item/organ/internal/lungs/synth/emp_act(severity) - . = ..() - - if(!owner || . & EMP_PROTECT_SELF) - return - - if(!COOLDOWN_FINISHED(src, severe_cooldown)) //So we cant just spam emp to kill people. - COOLDOWN_START(src, severe_cooldown, 10 SECONDS) - - switch(severity) - if(EMP_HEAVY) - to_chat(owner, span_warning("Alert: Critical cooling system failure! Seek maintenance immediately. Error Code: 5H-17")) - owner.adjust_bodytemperature(SYNTH_HEAVY_EMP_TEMPERATURE_POWER * TEMPERATURE_DAMAGE_COEFFICIENT) - - if(EMP_LIGHT) - to_chat(owner, span_warning("Alert: Major cooling system failure!")) - owner.adjust_bodytemperature(SYNTH_LIGHT_EMP_TEMPERATURE_POWER * TEMPERATURE_DAMAGE_COEFFICIENT) - -/datum/design/synth_heatsink - name = "Heatsink" - desc = "A device that transfers generated heat to a fluid medium to cool it down. Required to keep your synthetics cool-headed. It's shape resembles lungs." - id = "synth_lungs" - build_type = PROTOLATHE | AWAY_LATHE | MECHFAB - construction_time = 4 SECONDS - materials = list( - /datum/material/iron = HALF_SHEET_MATERIAL_AMOUNT, - /datum/material/glass = HALF_SHEET_MATERIAL_AMOUNT, - ) - build_path = /obj/item/organ/internal/lungs/synth - category = list( - RND_CATEGORY_CYBERNETICS + RND_SUBCATEGORY_CYBERNETICS_ORGANS_1 - ) - departmental_flags = DEPARTMENT_BITFLAG_MEDICAL | DEPARTMENT_BITFLAG_SCIENCE - -///IPCS NO LONGER ARE PURE ELECTRICAL BEINGS, any attempts to change this outside of Borbop will be denied. Thanks. -/obj/item/organ/internal/stomach/synth - name = "synthetic bio-reactor" - icon = 'monkestation/code/modules/smithing/icons/ipc_organ.dmi' - icon_state = "stomach-ipc" - w_class = WEIGHT_CLASS_NORMAL - zone = BODY_ZONE_CHEST - slot = ORGAN_SLOT_STOMACH - maxHealth = 1 * STANDARD_ORGAN_THRESHOLD - zone = "chest" - slot = "stomach" - desc = "A specialised mini reactor, for synthetic use only. Has a low-power mode to ensure baseline functions. Without this, synthetics are unable to stay powered." - organ_flags = ORGAN_ROBOTIC | ORGAN_SYNTHETIC_FROM_SPECIES - -/obj/item/organ/internal/stomach/synth/emp_act(severity) - . = ..() - - if(!owner || . & EMP_PROTECT_SELF) - return - - if(!COOLDOWN_FINISHED(src, severe_cooldown)) //So we cant just spam emp to kill people. - COOLDOWN_START(src, severe_cooldown, 10 SECONDS) - - switch(severity) - if(EMP_HEAVY) - owner.nutrition = max(0, owner.nutrition - SYNTH_STOMACH_HEAVY_EMP_CHARGE_LOSS) - apply_organ_damage(SYNTH_ORGAN_HEAVY_EMP_DAMAGE, maxHealth, required_organtype = ORGAN_ROBOTIC) - to_chat(owner, span_warning("Alert: Severe battery discharge!")) - - if(EMP_LIGHT) - owner.nutrition = max(0, owner.nutrition - SYNTH_STOMACH_LIGHT_EMP_CHARGE_LOSS) - apply_organ_damage(SYNTH_ORGAN_LIGHT_EMP_DAMAGE, maxHealth, required_organtype = ORGAN_ROBOTIC) - to_chat(owner, span_warning("Alert: Minor battery discharge!")) - -/datum/design/synth_stomach - name = "Synthetic Bio-Reactor" - desc = "A specialised mini reactor, for synthetic use only. Has a low-power mode to ensure baseline functions. Without this, synthetics are unable to stay powered." - id = "synth_stomach" - build_type = PROTOLATHE | AWAY_LATHE | MECHFAB - construction_time = 4 SECONDS - materials = list( - /datum/material/iron = HALF_SHEET_MATERIAL_AMOUNT, - /datum/material/glass = HALF_SHEET_MATERIAL_AMOUNT, - ) - build_path = /obj/item/organ/internal/stomach/synth - category = list( - RND_CATEGORY_CYBERNETICS + RND_SUBCATEGORY_CYBERNETICS_ORGANS_1 - ) - departmental_flags = DEPARTMENT_BITFLAG_MEDICAL | DEPARTMENT_BITFLAG_SCIENCE - -/obj/item/organ/internal/stomach/synth/Insert(mob/living/carbon/receiver, special, drop_if_replaced) - . = ..() - RegisterSignal(receiver, COMSIG_PROCESS_BORGCHARGER_OCCUPANT, PROC_REF(on_borg_charge)) - -/obj/item/organ/internal/stomach/synth/Remove(mob/living/carbon/stomach_owner, special) - . = ..() - UnregisterSignal(stomach_owner, COMSIG_PROCESS_BORGCHARGER_OCCUPANT) - -///Handles charging the synth from borg chargers -/obj/item/organ/internal/stomach/synth/proc/on_borg_charge(datum/source, amount) - SIGNAL_HANDLER - - if(owner.nutrition >= NUTRITION_LEVEL_ALMOST_FULL) - return - - amount /= 50 // Lowers the charging amount so it isn't instant - owner.nutrition = min((owner.nutrition + amount), NUTRITION_LEVEL_ALMOST_FULL) // Makes sure we don't make the synth too full, which would apply the overweight slowdown - -/obj/item/organ/internal/tongue/synth - name = "synthetic voicebox" - desc = "A fully-functional synthetic tongue, encased in soft silicone. Features include high-resolution vocals and taste receptors." - icon = 'monkestation/code/modules/smithing/icons/ipc_organ.dmi' - icon_state = "cybertongue" - say_mod = "beeps" - attack_verb_continuous = list("beeps", "boops") - attack_verb_simple = list("beep", "boop") - modifies_speech = TRUE - taste_sensitivity = 25 // not as good as an organic tongue - maxHealth = 100 //RoboTongue! - zone = BODY_ZONE_HEAD - slot = ORGAN_SLOT_TONGUE - organ_flags = ORGAN_ROBOTIC | ORGAN_SYNTHETIC_FROM_SPECIES - -/obj/item/organ/internal/tongue/synth/get_scream_sound() - return 'monkestation/sound/voice/screams/silicon/scream_silicon.ogg' - -/obj/item/organ/internal/tongue/synth/get_laugh_sound() - return pick( - 'monkestation/sound/voice/laugh/silicon/laugh_siliconE1M0.ogg', - 'monkestation/sound/voice/laugh/silicon/laugh_siliconE1M1.ogg', - 'monkestation/sound/voice/laugh/silicon/laugh_siliconM2.ogg', - ) - -/obj/item/organ/internal/tongue/synth/can_speak_language(language) - return TRUE - -/obj/item/organ/internal/tongue/synth/handle_speech(datum/source, list/speech_args) - speech_args[SPEECH_SPANS] |= SPAN_ROBOT - -/datum/design/synth_tongue - name = "Synthetic Tongue" - desc = "A fully-functional synthetic tongue, encased in soft silicone. Features include high-resolution vocals and taste receptors." - id = "synth_tongue" - build_type = PROTOLATHE | AWAY_LATHE | MECHFAB - construction_time = 4 SECONDS - materials = list( - /datum/material/iron = HALF_SHEET_MATERIAL_AMOUNT, - /datum/material/glass = HALF_SHEET_MATERIAL_AMOUNT, - ) - build_path = /obj/item/organ/internal/tongue/synth - category = list( - RND_CATEGORY_CYBERNETICS + RND_SUBCATEGORY_CYBERNETICS_ORGANS_1 - ) - departmental_flags = DEPARTMENT_BITFLAG_MEDICAL | DEPARTMENT_BITFLAG_SCIENCE diff --git a/monkestation/code/modules/smithing/ipcs/research.dm b/monkestation/code/modules/smithing/ipcs/research.dm deleted file mode 100644 index c75d134db45f..000000000000 --- a/monkestation/code/modules/smithing/ipcs/research.dm +++ /dev/null @@ -1,19 +0,0 @@ -/datum/techweb_node/improved_robotic_tend_wounds - id = "improved_robotic_surgery" - display_name = "Improved Robotic Repair Surgeries" - description = "As it turns out, you don't actually need to cut out entire support rods if it's just scratched!" - prereq_ids = list("engineering") - design_ids = list( - "robotic_heal_surgery_upgrade" - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 900) - -/datum/techweb_node/advanced_robotic_tend_wounds - id = "advanced_robotic_surgery" - display_name = "Advanced Robotic Surgeries" - description = "Did you know Hephaestus actually has a free online tutorial for synthetic trauma repairs? It's true!" - prereq_ids = list("improved_robotic_surgery") - design_ids = list( - "robotic_heal_surgery_upgrade_2" - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 1300) // less expensive than the organic surgery research equivalent since its JUST tend wounds diff --git a/monkestation/code/modules/smithing/oozelings/body/organs.dm b/monkestation/code/modules/smithing/oozelings/body/organs.dm deleted file mode 100644 index 6e33ac028af9..000000000000 --- a/monkestation/code/modules/smithing/oozelings/body/organs.dm +++ /dev/null @@ -1,420 +0,0 @@ -/obj/item/organ/internal/eyes/jelly - name = "photosensitive eyespots" - zone = BODY_ZONE_CHEST - organ_flags = ORGAN_UNREMOVABLE - -/obj/item/organ/internal/eyes/roundstartslime - name = "photosensitive eyespots" - zone = BODY_ZONE_CHEST - organ_flags = ORGAN_UNREMOVABLE - -/obj/item/organ/internal/ears/jelly - name = "core audiosomes" - zone = BODY_ZONE_CHEST - organ_flags = ORGAN_UNREMOVABLE - -/obj/item/organ/internal/tongue/jelly - zone = BODY_ZONE_CHEST - organ_flags = ORGAN_UNREMOVABLE - -/obj/item/organ/internal/tongue/jelly/get_possible_languages() - return ..() + /datum/language/slime - -/obj/item/organ/internal/lungs/slime - zone = BODY_ZONE_CHEST - organ_flags = ORGAN_UNREMOVABLE - safe_oxygen_min = 4 //We don't need much oxygen to subsist. - -/obj/item/organ/internal/lungs/slime/on_life(seconds_per_tick, times_fired) - . = ..() - operated = FALSE - -/obj/item/organ/internal/liver/slime - name = "endoplasmic reticulum" - zone = BODY_ZONE_CHEST - organ_flags = ORGAN_UNREMOVABLE - organ_traits = list(TRAIT_TOXINLOVER) - -/obj/item/organ/internal/liver/slime/on_life(seconds_per_tick, times_fired) - . = ..() - operated = FALSE - -/obj/item/organ/internal/stomach/slime - name = "golgi apparatus" - zone = BODY_ZONE_CHEST - organ_flags = ORGAN_UNREMOVABLE - -/obj/item/organ/internal/stomach/slime/on_life(seconds_per_tick, times_fired) - . = ..() - operated = FALSE - -/obj/item/organ/internal/brain/slime - name = "core" - desc = "The center core of a slimeperson, technically their 'extract.' Where the cytoplasm, membrane, and organelles come from; perhaps this is also a mitochondria?" - zone = BODY_ZONE_CHEST - icon = 'monkestation/code/modules/smithing/icons/oozeling.dmi' - icon_state = "slime_core" - resistance_flags = FIRE_PROOF - - var/obj/effect/death_melt_type = /obj/effect/temp_visual/wizard/out - var/core_color = COLOR_WHITE - - var/core_ejected = FALSE - var/gps_active = TRUE - - var/datum/dna/stored_dna - - var/list/stored_items = list() - - var/rebuilt = TRUE - var/coredeath = TRUE - - var/datum/action/cooldown/membrane_murmur/membrane_mur - -/obj/item/organ/internal/brain/slime/Initialize(mapload, mob/living/carbon/organ_owner, list/examine_list) - . = ..() - membrane_mur = new /datum/action/cooldown/membrane_murmur() - colorize() - transform.Scale(2, 2) - -/obj/item/organ/internal/brain/slime/Destroy(force) - QDEL_NULL(membrane_mur) - return ..() - -/obj/item/organ/internal/brain/slime/examine() - . = ..() - if(gps_active) - . += span_notice("A dim light lowly pulsates from the center of the core, indicating an outgoing signal from a tracking microchip.") - . += span_red("You could probably snuff that out.") - . += span_hypnophrase("You remember that pouring plasma on it, if it's non-embodied, would make it regrow one.") - -/obj/item/organ/internal/brain/slime/attack_self(mob/living/user) // Allows a player (presumably an antag) to deactivate the GPS signal on a slime core - if(!(gps_active)) - return - user.visible_message(span_warning("[user] begins jamming their hand into a slime core! Slime goes everywhere!"), - span_notice("You jam your hand into the core, feeling for the densest point! Slime covers your arm."), - span_notice("You hear an obscene squelching sound.") - ) - playsound(user, 'sound/surgery/organ1.ogg', 80, TRUE) - - if(!do_after(user, 30 SECONDS, src)) - user.visible_message(span_warning("[user]'s hand slips out of the core before they can cause any harm!'"), - span_warning("Your hand slips out of the goopy core before you can find it's densest point."), - span_notice("You hear a resounding plop.") - ) - return - - user.visible_message(span_warning("[user] crunches something deep in the slime core! It gradually stops glowing."), - span_notice("You find the densest point, crushing it in your palm. The blinking light in the core slowly dissapates and items start to come out."), - span_notice("You hear a wet crunching sound.")) - playsound(user, 'sound/effects/wounds/crackandbleed.ogg', 80, TRUE) - - drop_items_to_ground(get_turf(user)) - -/obj/item/organ/internal/brain/slime/Insert(mob/living/carbon/organ_owner, special = FALSE, drop_if_replaced, no_id_transfer) - . = ..() - if(!.) - return - colorize() - core_ejected = FALSE - RegisterSignal(organ_owner, COMSIG_MOB_STATCHANGE, PROC_REF(on_stat_change)) - -/obj/item/organ/internal/brain/slime/proc/colorize() - if(isoozeling(owner)) - var/datum/color_palette/generic_colors/located = owner.dna.color_palettes[/datum/color_palette/generic_colors] - core_color = located.return_color(MUTANT_COLOR) - add_atom_colour(core_color, FIXED_COLOUR_PRIORITY) - -/obj/item/organ/internal/brain/slime/proc/on_stat_change(mob/living/victim, new_stat, turf/loc_override) - SIGNAL_HANDLER - - if(new_stat != DEAD) - return - - addtimer(CALLBACK(src, PROC_REF(core_ejection), victim), 0) // explode them after the current proc chain ends, to avoid weirdness - -/obj/item/organ/internal/brain/slime/proc/enable_coredeath() - coredeath = TRUE - if(owner?.stat == DEAD) - addtimer(CALLBACK(src, PROC_REF(core_ejection), owner), 0) - -/////// -/// CORE EJECTION PROC -/// Makes it so that when a slime dies, their core ejects and their body is qdel'd. - -/obj/item/organ/internal/brain/slime/proc/core_ejection(mob/living/carbon/human/victim, new_stat, turf/loc_override) - if(core_ejected || !coredeath) - return - if(QDELETED(stored_dna)) - stored_dna = new - - victim.dna.copy_dna(stored_dna) - core_ejected = TRUE - victim.visible_message(span_warning("[victim]'s body completely dissolves, collapsing outwards!"), span_notice("Your body completely dissolves, collapsing outwards!"), span_notice("You hear liquid splattering.")) - var/turf/death_turf = get_turf(victim) - - for(var/atom/movable/item as anything in victim.get_equipped_items(include_pockets = TRUE)) - victim.dropItemToGround(item) - stored_items |= item - item.forceMove(src) - - if(victim.get_organ_slot(ORGAN_SLOT_BRAIN) == src) - Remove(victim) - if(death_turf) - forceMove(death_turf) - src.wash(CLEAN_WASH) - new death_melt_type(death_turf, victim.dir) - - do_steam_effects(death_turf) - playsound(victim, 'sound/effects/blobattack.ogg', 80, TRUE) - - if(gps_active) // adding the gps signal if they have activated the ability - AddComponent(/datum/component/gps, "[victim]'s Core") - - if(brainmob) - membrane_mur.Grant(brainmob) - var/datum/antagonist/changeling/target_ling = brainmob.mind?.has_antag_datum(/datum/antagonist/changeling) - - if(target_ling) - if(target_ling.oozeling_revives > 0) - target_ling.oozeling_revives-- - addtimer(CALLBACK(src, PROC_REF(rebuild_body), null, FALSE), 30 SECONDS, TIMER_UNIQUE | TIMER_OVERRIDE | TIMER_DELETE_ME) - - if(IS_BLOODSUCKER(brainmob)) - var/datum/antagonist/bloodsucker/target_bloodsucker = brainmob.mind.has_antag_datum(/datum/antagonist/bloodsucker) - if(target_bloodsucker.bloodsucker_blood_volume >= OOZELING_MIN_REVIVE_BLOOD_THRESHOLD) - addtimer(CALLBACK(src, PROC_REF(rebuild_body), null, FALSE), 30 SECONDS, TIMER_UNIQUE | TIMER_OVERRIDE | TIMER_DELETE_ME) - target_bloodsucker.bloodsucker_blood_volume -= (OOZELING_MIN_REVIVE_BLOOD_THRESHOLD * 0.5) - - rebuilt = FALSE - victim.transfer_observers_to(src) - Remove(victim) - qdel(victim) - -/obj/item/organ/internal/brain/slime/proc/do_steam_effects(turf/loc) - var/datum/effect_system/steam_spread/steam = new() - steam.set_up(10, FALSE, loc) - steam.start() - -/////// -/// CHECK FOR REPAIR SECTION -/// Makes it so that when a slime's core has plasma poured on it, it builds a new body and moves the brain into it. - -/obj/item/organ/internal/brain/slime/check_for_repair(obj/item/item, mob/user) - if(damage && item.is_drainable() && item.reagents.has_reagent(/datum/reagent/toxin/plasma)) //attempt to heal the brain - if (item.reagents.get_reagent_amount(/datum/reagent/toxin/plasma) < 100) - user.balloon_alert(user, "too little plasma!") - return FALSE - - user.visible_message( - span_notice("[user] starts to slowly pour the contents of [item] onto [src]. It seems to bubble and roil, beginning to stretch its cytoskeleton outwards..."), - span_notice("You start to slowly pour the contents of [item] onto [src]. It seems to bubble and roil, beginning to stretch its membrane outwards..."), - span_hear("You hear bubbling.") - ) - - if(!do_after(user, 30 SECONDS, src)) - to_chat(user, span_warning("You failed to pour the contents of [item] onto [src]!")) - return FALSE - - if (item.reagents.get_reagent_amount(/datum/reagent/toxin/plasma) < 100) // minor exploit but might as well patch it - user.balloon_alert(user, "too little plasma!") - return FALSE - - user.visible_message( - span_notice("[user] pours the contents of [item] onto [src], causing it to form a proper cytoplasm and outer membrane."), - span_notice("You pour the contents of [item] onto [src], causing it to form a proper cytoplasm and outer membrane."), - span_hear("You hear a splat.") - ) - - item.reagents.remove_reagent(/datum/reagent/toxin/plasma, 100) - rebuild_body(user) - return TRUE - return ..() - -/obj/item/organ/internal/brain/slime/proc/drop_items_to_ground(turf/turf) - for(var/atom/movable/item as anything in stored_items) - item.forceMove(turf) - stored_items.Cut() - -/obj/item/organ/internal/brain/slime/proc/rebuild_body(mob/user, nugget = TRUE) as /mob/living/carbon/human - RETURN_TYPE(/mob/living/carbon/human) - if(rebuilt) - return owner - set_organ_damage(-maxHealth) // heals the brain fully - - if(gps_active) // making sure the gps signal is removed if it's active on revival - gps_active = FALSE - qdel(GetComponent(/datum/component/gps)) - - //we have the plasma. we can rebuild them. - brainmob?.mind?.grab_ghost() - if(isnull(brainmob)) - user?.balloon_alert(user, "This brain is not a viable candidate for repair!") - return null - if(isnull(brainmob.stored_dna)) - user?.balloon_alert(user, "This brain does not contain any dna!") - return null - if(isnull(brainmob.client)) - user?.balloon_alert(user, "This brain does not contain a mind!") - return null - var/mob/living/carbon/human/new_body = new /mob/living/carbon/human(drop_location()) - - rebuilt = TRUE - brainmob.client?.prefs?.safe_transfer_prefs_to(new_body) - new_body.underwear = "Nude" - new_body.undershirt = "Nude" - new_body.socks = "Nude" - stored_dna.transfer_identity(new_body, transfer_SE = TRUE) - new_body.real_name = new_body.dna.real_name - new_body.name = new_body.dna.real_name - new_body.updateappearance(mutcolor_update = TRUE) - new_body.domutcheck() - new_body.forceMove(drop_location()) - if(!nugget) - new_body.set_nutrition(NUTRITION_LEVEL_FED) - new_body.blood_volume = nugget ? (BLOOD_VOLUME_SAFE + 60) : BLOOD_VOLUME_NORMAL - REMOVE_TRAIT(new_body, TRAIT_NO_TRANSFORM, REF(src)) - if(!QDELETED(brainmob)) - SSquirks.AssignQuirks(new_body, brainmob.client) - var/obj/item/organ/internal/brain/new_body_brain = new_body.get_organ_slot(ORGAN_SLOT_BRAIN) - qdel(new_body_brain) - forceMove(new_body) - Insert(new_body) - if(nugget) - for(var/obj/item/bodypart as anything in new_body.bodyparts) - if(istype(bodypart, /obj/item/bodypart/chest)) - continue - qdel(bodypart) - new_body.visible_message(span_warning("[new_body]'s torso \"forms\" from [new_body.p_their()] core, yet to form the rest.")) - to_chat(owner, span_purple("Your torso fully forms out of your core, yet to form the rest.")) - else - new_body.visible_message(span_warning("[new_body]'s body fully forms from [new_body.p_their()] core!")) - to_chat(owner, span_purple("Your body fully forms from your core!")) - - membrane_mur.Remove(brainmob) - brainmob?.mind?.transfer_to(new_body) - new_body.grab_ghost() - transfer_observers_to(new_body) - - drop_items_to_ground(new_body.drop_location()) - return new_body - - -///The rate at which slimes regenerate their jelly normally -#define JELLY_REGEN_RATE 1.5 -///The rate at which slimes regenerate their jelly when they completely run out of it and start taking damage, usually after having cannibalized all their limbs already -#define JELLY_REGEN_RATE_EMPTY 2.5 -///The blood volume at which slimes begin to start losing nutrition -- so that IV drips can work for blood deficient slimes -#define BLOOD_VOLUME_LOSE_NUTRITION 550 - - -/obj/item/organ/internal/heart/slime - name = "slime heart" - - heart_bloodtype = /datum/blood_type/slime - var/datum/action/innate/regenerate_limbs/regenerate_limbs - -/obj/item/organ/internal/heart/slime/Insert(mob/living/carbon/receiver, special, drop_if_replaced) - . = ..() - regenerate_limbs = new - regenerate_limbs.Grant(receiver) - RegisterSignal(receiver, COMSIG_HUMAN_ON_HANDLE_BLOOD, PROC_REF(slime_blood)) - -/obj/item/organ/internal/heart/slime/Remove(mob/living/carbon/heartless, special) - . = ..() - if(regenerate_limbs) - regenerate_limbs.Remove(heartless) - qdel(regenerate_limbs) - UnregisterSignal(heartless, COMSIG_HUMAN_ON_HANDLE_BLOOD) - -/obj/item/organ/internal/heart/slime/proc/slime_blood(mob/living/carbon/human/slime, seconds_per_tick, times_fired) - SIGNAL_HANDLER - - if(slime.stat == DEAD) - return NONE - - . = HANDLE_BLOOD_NO_NUTRITION_DRAIN|HANDLE_BLOOD_NO_EFFECTS - - if(slime.blood_volume <= 0) - slime.blood_volume += JELLY_REGEN_RATE_EMPTY * seconds_per_tick - slime.adjustBruteLoss(2.5 * seconds_per_tick) - to_chat(slime, span_danger("You feel empty!")) - - if(slime.blood_volume < BLOOD_VOLUME_NORMAL) - if(slime.nutrition >= NUTRITION_LEVEL_STARVING) - slime.blood_volume += JELLY_REGEN_RATE * seconds_per_tick - if(slime.blood_volume <= BLOOD_VOLUME_LOSE_NUTRITION) // don't lose nutrition if we are above a certain threshold, otherwise slimes on IV drips will still lose nutrition - slime.adjust_nutrition(-1.25 * seconds_per_tick) - - if(HAS_TRAIT(slime, TRAIT_BLOOD_DEFICIENCY)) - var/datum/quirk/blooddeficiency/blooddeficiency = slime.get_quirk(/datum/quirk/blooddeficiency) - blooddeficiency?.lose_blood(slime, seconds_per_tick) - - if(slime.blood_volume < BLOOD_VOLUME_OKAY) - if(SPT_PROB(2.5, seconds_per_tick)) - to_chat(slime, span_danger("You feel drained!")) - - if(slime.blood_volume < BLOOD_VOLUME_BAD) - Cannibalize_Body(slime) - - regenerate_limbs?.build_all_button_icons(UPDATE_BUTTON_STATUS) - return . - -/obj/item/organ/internal/heart/slime/proc/Cannibalize_Body(mob/living/carbon/human/H) - var/list/limbs_to_consume = list(BODY_ZONE_R_ARM, BODY_ZONE_L_ARM, BODY_ZONE_R_LEG, BODY_ZONE_L_LEG) - H.get_missing_limbs() - var/obj/item/bodypart/consumed_limb - if(!length(limbs_to_consume)) - H.losebreath++ - return - if(H.num_legs) //Legs go before arms - limbs_to_consume -= list(BODY_ZONE_R_ARM, BODY_ZONE_L_ARM) - consumed_limb = H.get_bodypart(pick(limbs_to_consume)) - consumed_limb.drop_limb() - to_chat(H, span_userdanger("Your [consumed_limb] is drawn back into your body, unable to maintain its shape!")) - qdel(consumed_limb) - H.blood_volume += 20 - -/datum/action/innate/regenerate_limbs - name = "Regenerate Limbs" - check_flags = AB_CHECK_CONSCIOUS - button_icon_state = "slimeheal" - button_icon = 'icons/mob/actions/actions_slime.dmi' - background_icon_state = "bg_alien" - overlay_icon_state = "bg_alien_border" - -/datum/action/innate/regenerate_limbs/IsAvailable(feedback = FALSE) - . = ..() - if(!.) - return - var/mob/living/carbon/human/H = owner - var/list/limbs_to_heal = H.get_missing_limbs() - if(!length(limbs_to_heal)) - return FALSE - if(H.blood_volume >= BLOOD_VOLUME_OKAY+40) - return TRUE - -/datum/action/innate/regenerate_limbs/Activate() - var/mob/living/carbon/human/H = owner - var/list/limbs_to_heal = H.get_missing_limbs() - if(!length(limbs_to_heal)) - to_chat(H, span_notice("You feel intact enough as it is.")) - return - to_chat(H, span_notice("You focus intently on your missing [length(limbs_to_heal) >= 2 ? "limbs" : "limb"]...")) - if(H.blood_volume >= 40*length(limbs_to_heal)+BLOOD_VOLUME_OKAY) - H.regenerate_limbs() - H.blood_volume -= 40*length(limbs_to_heal) - to_chat(H, span_notice("...and after a moment you finish reforming!")) - return - else if(H.blood_volume >= 40)//We can partially heal some limbs - while(H.blood_volume >= BLOOD_VOLUME_OKAY+40) - var/healed_limb = pick(limbs_to_heal) - H.regenerate_limb(healed_limb) - limbs_to_heal -= healed_limb - H.blood_volume -= 40 - to_chat(H, span_warning("...but there is not enough of you to fix everything! You must attain more mass to heal completely!")) - return - to_chat(H, span_warning("...but there is not enough of you to go around! You must attain more mass to heal!")) - -#undef JELLY_REGEN_RATE -#undef JELLY_REGEN_RATE_EMPTY -#undef BLOOD_VOLUME_LOSE_NUTRITION diff --git a/monkestation/code/modules/smithing/ipcs/body/base_bodyparts.dm b/monkestation/code/modules/surgery/bodyparts/ipc_bodyparts.dm similarity index 100% rename from monkestation/code/modules/smithing/ipcs/body/base_bodyparts.dm rename to monkestation/code/modules/surgery/bodyparts/ipc_bodyparts.dm diff --git a/monkestation/code/modules/smithing/oozelings/body/bodyparts.dm b/monkestation/code/modules/surgery/bodyparts/oozeling_bodyparts.dm similarity index 100% rename from monkestation/code/modules/smithing/oozelings/body/bodyparts.dm rename to monkestation/code/modules/surgery/bodyparts/oozeling_bodyparts.dm diff --git a/monkestation/code/modules/ranching/satyr/bodyparts.dm b/monkestation/code/modules/surgery/bodyparts/satyr_bodyparts.dm similarity index 100% rename from monkestation/code/modules/ranching/satyr/bodyparts.dm rename to monkestation/code/modules/surgery/bodyparts/satyr_bodyparts.dm diff --git a/monkestation/code/modules/surgery/organs/internal/brain.dm b/monkestation/code/modules/surgery/organs/internal/brain.dm index 54595401627b..a26374a30239 100644 --- a/monkestation/code/modules/surgery/organs/internal/brain.dm +++ b/monkestation/code/modules/surgery/organs/internal/brain.dm @@ -14,3 +14,325 @@ . = ..() if(prob(5) && !robust) SEND_SOUND(owner, sound('sound/ambience/ambiruin3.ogg', volume = 25)) + +/obj/item/organ/internal/brain/slime + name = "core" + desc = "The center core of a slimeperson, technically their 'extract.' Where the cytoplasm, membrane, and organelles come from; perhaps this is also a mitochondria?" + zone = BODY_ZONE_CHEST + icon = 'monkestation/code/modules/smithing/icons/oozeling.dmi' + icon_state = "slime_core" + resistance_flags = FIRE_PROOF + + var/obj/effect/death_melt_type = /obj/effect/temp_visual/wizard/out + var/core_color = COLOR_WHITE + + var/core_ejected = FALSE + var/gps_active = TRUE + + var/datum/dna/stored_dna + + var/list/stored_items = list() + + var/rebuilt = TRUE + var/coredeath = TRUE + + var/datum/action/cooldown/membrane_murmur/membrane_mur + +/obj/item/organ/internal/brain/slime/Initialize(mapload, mob/living/carbon/organ_owner, list/examine_list) + . = ..() + membrane_mur = new /datum/action/cooldown/membrane_murmur() + colorize() + transform.Scale(2, 2) + +/obj/item/organ/internal/brain/slime/Destroy(force) + QDEL_NULL(membrane_mur) + return ..() + +/obj/item/organ/internal/brain/slime/examine() + . = ..() + if(gps_active) + . += span_notice("A dim light lowly pulsates from the center of the core, indicating an outgoing signal from a tracking microchip.") + . += span_red("You could probably snuff that out.") + . += span_hypnophrase("You remember that pouring plasma on it, if it's non-embodied, would make it regrow one.") + +/obj/item/organ/internal/brain/slime/attack_self(mob/living/user) // Allows a player (presumably an antag) to deactivate the GPS signal on a slime core + if(!(gps_active)) + return + user.visible_message(span_warning("[user] begins jamming their hand into a slime core! Slime goes everywhere!"), + span_notice("You jam your hand into the core, feeling for the densest point! Slime covers your arm."), + span_notice("You hear an obscene squelching sound.") + ) + playsound(user, 'sound/surgery/organ1.ogg', 80, TRUE) + + if(!do_after(user, 30 SECONDS, src)) + user.visible_message(span_warning("[user]'s hand slips out of the core before they can cause any harm!'"), + span_warning("Your hand slips out of the goopy core before you can find it's densest point."), + span_notice("You hear a resounding plop.") + ) + return + + user.visible_message(span_warning("[user] crunches something deep in the slime core! It gradually stops glowing."), + span_notice("You find the densest point, crushing it in your palm. The blinking light in the core slowly dissapates and items start to come out."), + span_notice("You hear a wet crunching sound.")) + playsound(user, 'sound/effects/wounds/crackandbleed.ogg', 80, TRUE) + + drop_items_to_ground(get_turf(user)) + +/obj/item/organ/internal/brain/slime/Insert(mob/living/carbon/organ_owner, special = FALSE, drop_if_replaced, no_id_transfer) + . = ..() + if(!.) + return + colorize() + core_ejected = FALSE + RegisterSignal(organ_owner, COMSIG_MOB_STATCHANGE, PROC_REF(on_stat_change)) + +/obj/item/organ/internal/brain/slime/proc/colorize() + if(isoozeling(owner)) + var/datum/color_palette/generic_colors/located = owner.dna.color_palettes[/datum/color_palette/generic_colors] + core_color = located.return_color(MUTANT_COLOR) + add_atom_colour(core_color, FIXED_COLOUR_PRIORITY) + +/obj/item/organ/internal/brain/slime/proc/on_stat_change(mob/living/victim, new_stat, turf/loc_override) + SIGNAL_HANDLER + + if(new_stat != DEAD) + return + + addtimer(CALLBACK(src, PROC_REF(core_ejection), victim), 0) // explode them after the current proc chain ends, to avoid weirdness + +/obj/item/organ/internal/brain/slime/proc/enable_coredeath() + coredeath = TRUE + if(owner?.stat == DEAD) + addtimer(CALLBACK(src, PROC_REF(core_ejection), owner), 0) + +/////// +/// CORE EJECTION PROC +/// Makes it so that when a slime dies, their core ejects and their body is qdel'd. + +/obj/item/organ/internal/brain/slime/proc/core_ejection(mob/living/carbon/human/victim, new_stat, turf/loc_override) + if(core_ejected || !coredeath) + return + if(QDELETED(stored_dna)) + stored_dna = new + + victim.dna.copy_dna(stored_dna) + core_ejected = TRUE + victim.visible_message(span_warning("[victim]'s body completely dissolves, collapsing outwards!"), span_notice("Your body completely dissolves, collapsing outwards!"), span_notice("You hear liquid splattering.")) + var/turf/death_turf = get_turf(victim) + + for(var/atom/movable/item as anything in victim.get_equipped_items(include_pockets = TRUE)) + victim.dropItemToGround(item) + stored_items |= item + item.forceMove(src) + + if(victim.get_organ_slot(ORGAN_SLOT_BRAIN) == src) + Remove(victim) + if(death_turf) + forceMove(death_turf) + src.wash(CLEAN_WASH) + new death_melt_type(death_turf, victim.dir) + + do_steam_effects(death_turf) + playsound(victim, 'sound/effects/blobattack.ogg', 80, TRUE) + + if(gps_active) // adding the gps signal if they have activated the ability + AddComponent(/datum/component/gps, "[victim]'s Core") + + if(brainmob) + membrane_mur.Grant(brainmob) + var/datum/antagonist/changeling/target_ling = brainmob.mind?.has_antag_datum(/datum/antagonist/changeling) + + if(target_ling) + if(target_ling.oozeling_revives > 0) + target_ling.oozeling_revives-- + addtimer(CALLBACK(src, PROC_REF(rebuild_body), null, FALSE), 30 SECONDS, TIMER_UNIQUE | TIMER_OVERRIDE | TIMER_DELETE_ME) + + if(IS_BLOODSUCKER(brainmob)) + var/datum/antagonist/bloodsucker/target_bloodsucker = brainmob.mind.has_antag_datum(/datum/antagonist/bloodsucker) + if(target_bloodsucker.bloodsucker_blood_volume >= OOZELING_MIN_REVIVE_BLOOD_THRESHOLD) + addtimer(CALLBACK(src, PROC_REF(rebuild_body), null, FALSE), 30 SECONDS, TIMER_UNIQUE | TIMER_OVERRIDE | TIMER_DELETE_ME) + target_bloodsucker.bloodsucker_blood_volume -= (OOZELING_MIN_REVIVE_BLOOD_THRESHOLD * 0.5) + + rebuilt = FALSE + victim.transfer_observers_to(src) + Remove(victim) + qdel(victim) + +/obj/item/organ/internal/brain/slime/proc/do_steam_effects(turf/loc) + var/datum/effect_system/steam_spread/steam = new() + steam.set_up(10, FALSE, loc) + steam.start() + +/////// +/// CHECK FOR REPAIR SECTION +/// Makes it so that when a slime's core has plasma poured on it, it builds a new body and moves the brain into it. + +/obj/item/organ/internal/brain/slime/check_for_repair(obj/item/item, mob/user) + if(damage && item.is_drainable() && item.reagents.has_reagent(/datum/reagent/toxin/plasma)) //attempt to heal the brain + if (item.reagents.get_reagent_amount(/datum/reagent/toxin/plasma) < 100) + user.balloon_alert(user, "too little plasma!") + return FALSE + + user.visible_message( + span_notice("[user] starts to slowly pour the contents of [item] onto [src]. It seems to bubble and roil, beginning to stretch its cytoskeleton outwards..."), + span_notice("You start to slowly pour the contents of [item] onto [src]. It seems to bubble and roil, beginning to stretch its membrane outwards..."), + span_hear("You hear bubbling.") + ) + + if(!do_after(user, 30 SECONDS, src)) + to_chat(user, span_warning("You failed to pour the contents of [item] onto [src]!")) + return FALSE + + if (item.reagents.get_reagent_amount(/datum/reagent/toxin/plasma) < 100) // minor exploit but might as well patch it + user.balloon_alert(user, "too little plasma!") + return FALSE + + user.visible_message( + span_notice("[user] pours the contents of [item] onto [src], causing it to form a proper cytoplasm and outer membrane."), + span_notice("You pour the contents of [item] onto [src], causing it to form a proper cytoplasm and outer membrane."), + span_hear("You hear a splat.") + ) + + item.reagents.remove_reagent(/datum/reagent/toxin/plasma, 100) + rebuild_body(user) + return TRUE + return ..() + +/obj/item/organ/internal/brain/slime/proc/drop_items_to_ground(turf/turf) + for(var/atom/movable/item as anything in stored_items) + item.forceMove(turf) + stored_items.Cut() + +/obj/item/organ/internal/brain/slime/proc/rebuild_body(mob/user, nugget = TRUE) as /mob/living/carbon/human + RETURN_TYPE(/mob/living/carbon/human) + if(rebuilt) + return owner + set_organ_damage(-maxHealth) // heals the brain fully + + if(gps_active) // making sure the gps signal is removed if it's active on revival + gps_active = FALSE + qdel(GetComponent(/datum/component/gps)) + + //we have the plasma. we can rebuild them. + brainmob?.mind?.grab_ghost() + if(isnull(brainmob)) + user?.balloon_alert(user, "This brain is not a viable candidate for repair!") + return null + if(isnull(brainmob.stored_dna)) + user?.balloon_alert(user, "This brain does not contain any dna!") + return null + if(isnull(brainmob.client)) + user?.balloon_alert(user, "This brain does not contain a mind!") + return null + var/mob/living/carbon/human/new_body = new /mob/living/carbon/human(drop_location()) + + rebuilt = TRUE + brainmob.client?.prefs?.safe_transfer_prefs_to(new_body) + new_body.underwear = "Nude" + new_body.undershirt = "Nude" + new_body.socks = "Nude" + stored_dna.transfer_identity(new_body, transfer_SE = TRUE) + new_body.real_name = new_body.dna.real_name + new_body.name = new_body.dna.real_name + new_body.updateappearance(mutcolor_update = TRUE) + new_body.domutcheck() + new_body.forceMove(drop_location()) + if(!nugget) + new_body.set_nutrition(NUTRITION_LEVEL_FED) + new_body.blood_volume = nugget ? (BLOOD_VOLUME_SAFE + 60) : BLOOD_VOLUME_NORMAL + REMOVE_TRAIT(new_body, TRAIT_NO_TRANSFORM, REF(src)) + if(!QDELETED(brainmob)) + SSquirks.AssignQuirks(new_body, brainmob.client) + var/obj/item/organ/internal/brain/new_body_brain = new_body.get_organ_slot(ORGAN_SLOT_BRAIN) + qdel(new_body_brain) + forceMove(new_body) + Insert(new_body) + if(nugget) + for(var/obj/item/bodypart as anything in new_body.bodyparts) + if(istype(bodypart, /obj/item/bodypart/chest)) + continue + qdel(bodypart) + new_body.visible_message(span_warning("[new_body]'s torso \"forms\" from [new_body.p_their()] core, yet to form the rest.")) + to_chat(owner, span_purple("Your torso fully forms out of your core, yet to form the rest.")) + else + new_body.visible_message(span_warning("[new_body]'s body fully forms from [new_body.p_their()] core!")) + to_chat(owner, span_purple("Your body fully forms from your core!")) + + membrane_mur.Remove(brainmob) + brainmob?.mind?.transfer_to(new_body) + new_body.grab_ghost() + transfer_observers_to(new_body) + + drop_items_to_ground(new_body.drop_location()) + return new_body + +/obj/item/organ/internal/brain/synth + name = "compact positronic brain" + slot = ORGAN_SLOT_BRAIN + zone = BODY_ZONE_HEAD + organ_flags = ORGAN_ROBOTIC | ORGAN_SYNTHETIC_FROM_SPECIES + maxHealth = 2 * STANDARD_ORGAN_THRESHOLD + desc = "A cube of shining metal, four inches to a side and covered in shallow grooves. It has an IPC serial number engraved on the top. It is usually slotted into the chest of synthetic crewmembers." + icon = 'monkestation/code/modules/smithing/icons/ipc_organ.dmi' + icon_state = "posibrain-ipc" + /// The last time (in ticks) a message about brain damage was sent. Don't touch. + var/last_message_time = 0 + +/obj/item/organ/internal/brain/synth/on_insert(mob/living/carbon/brain_owner) + . = ..() + + if(brain_owner.stat != DEAD || !ishuman(brain_owner)) + return + + var/mob/living/carbon/human/user_human = brain_owner + if(HAS_TRAIT(user_human, TRAIT_REVIVES_BY_HEALING) && user_human.health > SYNTH_BRAIN_WAKE_THRESHOLD) + if(!HAS_TRAIT(user_human, TRAIT_DEFIB_BLACKLISTED)) + user_human.revive(FALSE) + +/obj/item/organ/internal/brain/synth/emp_act(severity) // EMP act against the posi, keep the cap far below the organ health + . = ..() + + if(!owner || . & EMP_PROTECT_SELF) + return + + if(!COOLDOWN_FINISHED(src, severe_cooldown)) //So we cant just spam emp to kill people. + COOLDOWN_START(src, severe_cooldown, 10 SECONDS) + + switch(severity) + if(EMP_HEAVY) + to_chat(owner, span_warning("01001001 00100111 01101101 00100000 01100110 01110101 01100011 01101011 01100101 01100100 00101110")) + apply_organ_damage(SYNTH_ORGAN_HEAVY_EMP_DAMAGE, SYNTH_EMP_BRAIN_DAMAGE_MAXIMUM, required_organtype = ORGAN_ROBOTIC) + if(EMP_LIGHT) + to_chat(owner, span_warning("Alert: Electromagnetic damage taken in central processing unit. Error Code: 401-YT")) + apply_organ_damage(SYNTH_ORGAN_LIGHT_EMP_DAMAGE, SYNTH_EMP_BRAIN_DAMAGE_MAXIMUM, required_organtype = ORGAN_ROBOTIC) + +/obj/item/organ/internal/brain/synth/apply_organ_damage(damage_amount, maximumm, required_organtype) + . = ..() + + if(owner && damage > 0 && (world.time - last_message_time) > SYNTH_BRAIN_DAMAGE_MESSAGE_INTERVAL) + last_message_time = world.time + + if(damage > BRAIN_DAMAGE_SEVERE) + to_chat(owner, span_warning("Alre: re oumtnin ilir tocorr:pa ni ne:cnrrpiioruloomatt cessingode: P1_1-H")) + return + + if(damage > BRAIN_DAMAGE_MILD) + to_chat(owner, span_warning("Alert: Minor corruption in central processing unit. Error Code: 001-HP")) + +/* +/obj/item/organ/internal/brain/synth/circuit + name = "compact AI circuit" + desc = "A compact and extremely complex circuit, perfectly dimensioned to fit in the same slot as a synthetic-compatible positronic brain. It is usually slotted into the chest of synthetic crewmembers." + icon = 'monkestation/code/modules/smithing/icons/ipc_organ.dmi' + icon_state = "circuit-occupied" + inhand_icon_state = "electronic" + lefthand_file = 'icons/mob/inhands/items/devices_lefthand.dmi' + righthand_file = 'icons/mob/inhands/items/devices_righthand.dmi' +*/ + +/obj/item/organ/internal/brain/synth/mmi + name = "compact man-machine interface" + desc = "A compact man-machine interface, perfectly dimensioned to fit in the same slot as a synthetic-compatible positronic brain. Unfortunately, the brain seems to be permanently attached to the circuitry, and it seems relatively sensitive to it's environment. It is usually slotted into the chest of synthetic crewmembers." + icon = 'monkestation/code/modules/smithing/icons/ipc_organ.dmi' + icon_state = "mmi-ipc" + diff --git a/monkestation/code/modules/surgery/organs/internal/ears.dm b/monkestation/code/modules/surgery/organs/internal/ears.dm index a448af9db39c..25ff00d61ae6 100644 --- a/monkestation/code/modules/surgery/organs/internal/ears.dm +++ b/monkestation/code/modules/surgery/organs/internal/ears.dm @@ -3,3 +3,57 @@ desc = "An odd sort of microphone that looks grown, rather than built." icon = 'monkestation/icons/obj/medical/organs/organs.dmi' icon_state = "ears-clock" + +/obj/item/organ/internal/ears/jelly + name = "core audiosomes" + zone = BODY_ZONE_CHEST + organ_flags = ORGAN_UNREMOVABLE + +/obj/item/organ/internal/ears/synth + name = "auditory sensors" + icon = 'monkestation/code/modules/smithing/icons/ipc_organ.dmi' + icon_state = "ears-ipc" + desc = "A pair of microphones intended to be installed in an IPC or Synthetics head, that grant the ability to hear." + zone = BODY_ZONE_HEAD + slot = ORGAN_SLOT_EARS + gender = PLURAL + maxHealth = 1 * STANDARD_ORGAN_THRESHOLD + organ_flags = ORGAN_ROBOTIC | ORGAN_SYNTHETIC_FROM_SPECIES + +/obj/item/organ/internal/ears/synth/emp_act(severity) + . = ..() + + if(!owner || . & EMP_PROTECT_SELF) + return + + if(!COOLDOWN_FINISHED(src, severe_cooldown)) //So we cant just spam emp to kill people. + COOLDOWN_START(src, severe_cooldown, 10 SECONDS) + + switch(severity) + if(EMP_HEAVY) + owner.set_jitter_if_lower(SYNTH_BAD_EFFECT_DURATION * SYNTH_HEAVY_EMP_MULTIPLIER) + owner.set_dizzy_if_lower(SYNTH_BAD_EFFECT_DURATION * SYNTH_HEAVY_EMP_MULTIPLIER) + adjustEarDamage(SYNTH_ORGAN_HEAVY_EMP_DAMAGE, SYNTH_DEAF_STACKS) + to_chat(owner, span_warning("Alert: Null feedback from auditory sensors detected, seek maintenance immediately. Error Code: AS-105")) + + if(EMP_LIGHT) + owner.set_jitter_if_lower(SYNTH_BAD_EFFECT_DURATION) + owner.set_dizzy_if_lower(SYNTH_BAD_EFFECT_DURATION) + adjustEarDamage(SYNTH_ORGAN_LIGHT_EMP_DAMAGE, SYNTH_DEAF_STACKS) + to_chat(owner, span_warning("Alert: Anomalous feedback from auditory sensors detected. Error Code: AS-50")) + +/datum/design/synth_ears + name = "Auditory Sensors" + desc = "A pair of microphones intended to be installed in an IPC or Synthetics head, that grant the ability to hear." + id = "synth_ears" + build_type = PROTOLATHE | AWAY_LATHE | MECHFAB + construction_time = 4 SECONDS + materials = list( + /datum/material/iron = HALF_SHEET_MATERIAL_AMOUNT, + /datum/material/glass = HALF_SHEET_MATERIAL_AMOUNT, + ) + build_path = /obj/item/organ/internal/ears/synth + category = list( + RND_CATEGORY_CYBERNETICS + RND_SUBCATEGORY_CYBERNETICS_ORGANS_1 + ) + departmental_flags = DEPARTMENT_BITFLAG_MEDICAL | DEPARTMENT_BITFLAG_SCIENCE diff --git a/monkestation/code/modules/surgery/organs/internal/eyes.dm b/monkestation/code/modules/surgery/organs/internal/eyes.dm index a70dba2e3f8f..b49eff604977 100644 --- a/monkestation/code/modules/surgery/organs/internal/eyes.dm +++ b/monkestation/code/modules/surgery/organs/internal/eyes.dm @@ -50,3 +50,51 @@ name = "tundra moth eyes" eye_icon_state = "tundramotheyes" icon_state = "eyeballs-tundramoth" + +/obj/item/organ/internal/eyes/jelly + name = "photosensitive eyespots" + zone = BODY_ZONE_CHEST + organ_flags = ORGAN_UNREMOVABLE + +/obj/item/organ/internal/eyes/roundstartslime + name = "photosensitive eyespots" + zone = BODY_ZONE_CHEST + organ_flags = ORGAN_UNREMOVABLE + +/obj/item/organ/internal/eyes/synth + name = "optical sensors" + icon_state = "cybernetic_eyeballs" + 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_DOESNT_PROTECT_AGAINST_CONVERSION + +/obj/item/organ/internal/eyes/synth/emp_act(severity) + . = ..() + + if(!owner || . & EMP_PROTECT_SELF) + return + + switch(severity) + if(EMP_HEAVY) + to_chat(owner, span_warning("Alert:Severe electromagnetic interference clouds your optics with static. Error Code: I-CS6")) + apply_organ_damage(SYNTH_ORGAN_HEAVY_EMP_DAMAGE, maxHealth, required_organtype = ORGAN_ROBOTIC) + if(EMP_LIGHT) + to_chat(owner, span_warning("Alert: Mild interference clouds your optics with static. Error Code: I-CS0")) + apply_organ_damage(SYNTH_ORGAN_LIGHT_EMP_DAMAGE, maxHealth, required_organtype = ORGAN_ROBOTIC) + +/datum/design/synth_eyes + name = "Optical Sensors" + desc = "A very basic set of optical sensors with no extra vision modes or functions." + id = "synth_eyes" + build_type = PROTOLATHE | AWAY_LATHE | MECHFAB + construction_time = 4 SECONDS + materials = list( + /datum/material/iron = HALF_SHEET_MATERIAL_AMOUNT, + /datum/material/glass = HALF_SHEET_MATERIAL_AMOUNT, + ) + build_path = /obj/item/organ/internal/eyes/synth + category = list( + RND_CATEGORY_CYBERNETICS + RND_SUBCATEGORY_CYBERNETICS_ORGANS_1 + ) + departmental_flags = DEPARTMENT_BITFLAG_MEDICAL | DEPARTMENT_BITFLAG_SCIENCE diff --git a/monkestation/code/modules/surgery/organs/internal/heart.dm b/monkestation/code/modules/surgery/organs/internal/heart.dm index ea75864d8089..02ba08878c8a 100644 --- a/monkestation/code/modules/surgery/organs/internal/heart.dm +++ b/monkestation/code/modules/surgery/organs/internal/heart.dm @@ -5,3 +5,167 @@ icon_state = "heart-clock" organ_flags = ORGAN_SYNTHETIC status = ORGAN_ROBOTIC + +///The rate at which slimes regenerate their jelly normally +#define JELLY_REGEN_RATE 1.5 +///The rate at which slimes regenerate their jelly when they completely run out of it and start taking damage, usually after having cannibalized all their limbs already +#define JELLY_REGEN_RATE_EMPTY 2.5 +///The blood volume at which slimes begin to start losing nutrition -- so that IV drips can work for blood deficient slimes +#define BLOOD_VOLUME_LOSE_NUTRITION 550 + + +/obj/item/organ/internal/heart/slime + name = "slime heart" + + heart_bloodtype = /datum/blood_type/slime + var/datum/action/innate/regenerate_limbs/regenerate_limbs + +/obj/item/organ/internal/heart/slime/Insert(mob/living/carbon/receiver, special, drop_if_replaced) + . = ..() + regenerate_limbs = new + regenerate_limbs.Grant(receiver) + RegisterSignal(receiver, COMSIG_HUMAN_ON_HANDLE_BLOOD, PROC_REF(slime_blood)) + +/obj/item/organ/internal/heart/slime/Remove(mob/living/carbon/heartless, special) + . = ..() + if(regenerate_limbs) + regenerate_limbs.Remove(heartless) + qdel(regenerate_limbs) + UnregisterSignal(heartless, COMSIG_HUMAN_ON_HANDLE_BLOOD) + +/obj/item/organ/internal/heart/slime/proc/slime_blood(mob/living/carbon/human/slime, seconds_per_tick, times_fired) + SIGNAL_HANDLER + + if(slime.stat == DEAD) + return NONE + + . = HANDLE_BLOOD_NO_NUTRITION_DRAIN|HANDLE_BLOOD_NO_EFFECTS + + if(slime.blood_volume <= 0) + slime.blood_volume += JELLY_REGEN_RATE_EMPTY * seconds_per_tick + slime.adjustBruteLoss(2.5 * seconds_per_tick) + to_chat(slime, span_danger("You feel empty!")) + + if(slime.blood_volume < BLOOD_VOLUME_NORMAL) + if(slime.nutrition >= NUTRITION_LEVEL_STARVING) + slime.blood_volume += JELLY_REGEN_RATE * seconds_per_tick + if(slime.blood_volume <= BLOOD_VOLUME_LOSE_NUTRITION) // don't lose nutrition if we are above a certain threshold, otherwise slimes on IV drips will still lose nutrition + slime.adjust_nutrition(-1.25 * seconds_per_tick) + + if(HAS_TRAIT(slime, TRAIT_BLOOD_DEFICIENCY)) + var/datum/quirk/blooddeficiency/blooddeficiency = slime.get_quirk(/datum/quirk/blooddeficiency) + blooddeficiency?.lose_blood(slime, seconds_per_tick) + + if(slime.blood_volume < BLOOD_VOLUME_OKAY) + if(SPT_PROB(2.5, seconds_per_tick)) + to_chat(slime, span_danger("You feel drained!")) + + if(slime.blood_volume < BLOOD_VOLUME_BAD) + Cannibalize_Body(slime) + + regenerate_limbs?.build_all_button_icons(UPDATE_BUTTON_STATUS) + return . + +/obj/item/organ/internal/heart/slime/proc/Cannibalize_Body(mob/living/carbon/human/H) + var/list/limbs_to_consume = list(BODY_ZONE_R_ARM, BODY_ZONE_L_ARM, BODY_ZONE_R_LEG, BODY_ZONE_L_LEG) - H.get_missing_limbs() + var/obj/item/bodypart/consumed_limb + if(!length(limbs_to_consume)) + H.losebreath++ + return + if(H.num_legs) //Legs go before arms + limbs_to_consume -= list(BODY_ZONE_R_ARM, BODY_ZONE_L_ARM) + consumed_limb = H.get_bodypart(pick(limbs_to_consume)) + consumed_limb.drop_limb() + to_chat(H, span_userdanger("Your [consumed_limb] is drawn back into your body, unable to maintain its shape!")) + qdel(consumed_limb) + H.blood_volume += 20 + +/datum/action/innate/regenerate_limbs + name = "Regenerate Limbs" + check_flags = AB_CHECK_CONSCIOUS + button_icon_state = "slimeheal" + button_icon = 'icons/mob/actions/actions_slime.dmi' + background_icon_state = "bg_alien" + overlay_icon_state = "bg_alien_border" + +/datum/action/innate/regenerate_limbs/IsAvailable(feedback = FALSE) + . = ..() + if(!.) + return + var/mob/living/carbon/human/H = owner + var/list/limbs_to_heal = H.get_missing_limbs() + if(!length(limbs_to_heal)) + return FALSE + if(H.blood_volume >= BLOOD_VOLUME_OKAY+40) + return TRUE + +/datum/action/innate/regenerate_limbs/Activate() + var/mob/living/carbon/human/H = owner + var/list/limbs_to_heal = H.get_missing_limbs() + if(!length(limbs_to_heal)) + to_chat(H, span_notice("You feel intact enough as it is.")) + return + to_chat(H, span_notice("You focus intently on your missing [length(limbs_to_heal) >= 2 ? "limbs" : "limb"]...")) + if(H.blood_volume >= 40*length(limbs_to_heal)+BLOOD_VOLUME_OKAY) + H.regenerate_limbs() + H.blood_volume -= 40*length(limbs_to_heal) + to_chat(H, span_notice("...and after a moment you finish reforming!")) + return + else if(H.blood_volume >= 40)//We can partially heal some limbs + while(H.blood_volume >= BLOOD_VOLUME_OKAY+40) + var/healed_limb = pick(limbs_to_heal) + H.regenerate_limb(healed_limb) + limbs_to_heal -= healed_limb + H.blood_volume -= 40 + to_chat(H, span_warning("...but there is not enough of you to fix everything! You must attain more mass to heal completely!")) + return + to_chat(H, span_warning("...but there is not enough of you to go around! You must attain more mass to heal!")) + +#undef JELLY_REGEN_RATE +#undef JELLY_REGEN_RATE_EMPTY +#undef BLOOD_VOLUME_LOSE_NUTRITION + +/obj/item/organ/internal/heart/synth + name = "hydraulic pump engine" + desc = "An electronic device that handles the hydraulic pumps, powering one's robotic limbs. Without this, synthetics are unable to move." + organ_flags = ORGAN_ROBOTIC | ORGAN_SYNTHETIC_FROM_SPECIES + icon = 'monkestation/code/modules/smithing/icons/ipc_organ.dmi' + icon_state = "heart-ipc-on" + base_icon_state = "heart-ipc" + maxHealth = 1.5 * STANDARD_ORGAN_THRESHOLD // 1.5x due to synthcode.tm being weird + zone = BODY_ZONE_CHEST + slot = ORGAN_SLOT_HEART + var/last_message_time = 0 + +/obj/item/organ/internal/heart/synth/emp_act(severity) + . = ..() + + if(!owner || . & EMP_PROTECT_SELF) + return + + if(!COOLDOWN_FINISHED(src, severe_cooldown)) //So we cant just spam emp to kill people. + COOLDOWN_START(src, severe_cooldown, 10 SECONDS) + + switch(severity) + if(EMP_HEAVY) + to_chat(owner, span_warning("Alert: Main hydraulic pump control has taken severe damage, seek maintenance immediately. Error code: HP300-10.")) + apply_organ_damage(SYNTH_ORGAN_HEAVY_EMP_DAMAGE, maxHealth, required_organtype = ORGAN_ROBOTIC) + if(EMP_LIGHT) + to_chat(owner, span_warning("Alert: Main hydraulic pump control has taken light damage, seek maintenance immediately. Error code: HP300-05.")) + apply_organ_damage(SYNTH_ORGAN_LIGHT_EMP_DAMAGE, maxHealth, required_organtype = ORGAN_ROBOTIC) + +/datum/design/synth_heart + name = "Hydraulic Pump Engine" + desc = "An electronic device that handles the hydraulic pumps, powering one's robotic limbs. Without this, synthetics are unable to move." + id = "synth_heart" + build_type = PROTOLATHE | AWAY_LATHE | MECHFAB + construction_time = 4 SECONDS + materials = list( + /datum/material/iron = HALF_SHEET_MATERIAL_AMOUNT, + /datum/material/glass = HALF_SHEET_MATERIAL_AMOUNT, + ) + build_path = /obj/item/organ/internal/heart/synth + category = list( + RND_CATEGORY_CYBERNETICS + RND_SUBCATEGORY_CYBERNETICS_ORGANS_1 + ) + departmental_flags = DEPARTMENT_BITFLAG_MEDICAL | DEPARTMENT_BITFLAG_SCIENCE diff --git a/monkestation/code/modules/surgery/organs/internal/liver.dm b/monkestation/code/modules/surgery/organs/internal/liver.dm index 8c04708a6c06..fff44411c88d 100644 --- a/monkestation/code/modules/surgery/organs/internal/liver.dm +++ b/monkestation/code/modules/surgery/organs/internal/liver.dm @@ -8,3 +8,58 @@ alcohol_tolerance = 0 liver_resistance = 0 toxTolerance = 1 //while the organ isn't damaged by doing its job, it doesnt do it very well + +/obj/item/organ/internal/liver/slime + name = "endoplasmic reticulum" + zone = BODY_ZONE_CHEST + organ_flags = ORGAN_UNREMOVABLE + organ_traits = list(TRAIT_TOXINLOVER) + +/obj/item/organ/internal/liver/slime/on_life(seconds_per_tick, times_fired) + . = ..() + operated = FALSE + +/obj/item/organ/internal/liver/synth + name = "reagent processing unit" + desc = "An electronic device that processes the beneficial chemicals for the synthetic user." + icon = 'monkestation/code/modules/smithing/icons/ipc_organ.dmi' + icon_state = "liver-ipc" + filterToxins = FALSE //We dont filter them, we're immune to them + zone = BODY_ZONE_CHEST + slot = ORGAN_SLOT_LIVER + maxHealth = 1 * STANDARD_ORGAN_THRESHOLD + organ_flags = ORGAN_ROBOTIC | ORGAN_SYNTHETIC_FROM_SPECIES + +/obj/item/organ/internal/liver/synth/emp_act(severity) + . = ..() + + if(!owner || . & EMP_PROTECT_SELF) + return + + if(!COOLDOWN_FINISHED(src, severe_cooldown)) //So we cant just spam emp to kill people. + COOLDOWN_START(src, severe_cooldown, 10 SECONDS) + + switch(severity) + if(EMP_HEAVY) + to_chat(owner, span_warning("Alert: Critical! Reagent processing unit failure, seek maintenance immediately. Error Code: DR-1k")) + apply_organ_damage(SYNTH_ORGAN_HEAVY_EMP_DAMAGE, maxHealth, required_organtype = ORGAN_ROBOTIC) + + if(EMP_LIGHT) + to_chat(owner, span_warning("Alert: Reagent processing unit failure, seek maintenance for diagnostic. Error Code: DR-0k")) + apply_organ_damage(SYNTH_ORGAN_LIGHT_EMP_DAMAGE, maxHealth, required_organtype = ORGAN_ROBOTIC) + +/datum/design/synth_liver + name = "Reagent Processing Unit" + desc = "An electronic device that processes the beneficial chemicals for the synthetic user." + id = "synth_liver" + build_type = PROTOLATHE | AWAY_LATHE | MECHFAB + construction_time = 4 SECONDS + materials = list( + /datum/material/iron = HALF_SHEET_MATERIAL_AMOUNT, + /datum/material/glass = HALF_SHEET_MATERIAL_AMOUNT, + ) + build_path = /obj/item/organ/internal/liver/synth + category = list( + RND_CATEGORY_CYBERNETICS + RND_SUBCATEGORY_CYBERNETICS_ORGANS_1 + ) + departmental_flags = DEPARTMENT_BITFLAG_MEDICAL | DEPARTMENT_BITFLAG_SCIENCE diff --git a/monkestation/code/modules/surgery/organs/internal/lungs.dm b/monkestation/code/modules/surgery/organs/internal/lungs.dm index 8b0b2f858738..cad2bda9eeb1 100644 --- a/monkestation/code/modules/surgery/organs/internal/lungs.dm +++ b/monkestation/code/modules/surgery/organs/internal/lungs.dm @@ -5,3 +5,62 @@ icon_state = "lungs-clock" organ_flags = ORGAN_SYNTHETIC status = ORGAN_ROBOTIC + +/obj/item/organ/internal/lungs/slime + zone = BODY_ZONE_CHEST + organ_flags = ORGAN_UNREMOVABLE + safe_oxygen_min = 4 //We don't need much oxygen to subsist. + +/obj/item/organ/internal/lungs/slime/on_life(seconds_per_tick, times_fired) + . = ..() + operated = FALSE + +/obj/item/organ/internal/lungs/synth + name = "heatsink" + desc = "A device that transfers generated heat to a fluid medium to cool it down. Required to keep your synthetics cool-headed. It's shape resembles lungs." //Purposefully left the 'fluid medium' ambigious for interpretation of the character, whether it be air or fluid cooling + icon = 'monkestation/code/modules/smithing/icons/ipc_organ.dmi' + icon_state = "lungs-ipc" + safe_nitro_min = 0 + safe_co2_max = 0 + safe_plasma_min = 0 + safe_plasma_max = 0 + safe_oxygen_min = 0 //What are you doing man, dont breathe with those! + safe_oxygen_max = 0 + zone = BODY_ZONE_CHEST + slot = ORGAN_SLOT_LUNGS + maxHealth = 1.5 * STANDARD_ORGAN_THRESHOLD + organ_flags = ORGAN_ROBOTIC | ORGAN_SYNTHETIC_FROM_SPECIES + +/obj/item/organ/internal/lungs/synth/emp_act(severity) + . = ..() + + if(!owner || . & EMP_PROTECT_SELF) + return + + if(!COOLDOWN_FINISHED(src, severe_cooldown)) //So we cant just spam emp to kill people. + COOLDOWN_START(src, severe_cooldown, 10 SECONDS) + + switch(severity) + if(EMP_HEAVY) + to_chat(owner, span_warning("Alert: Critical cooling system failure! Seek maintenance immediately. Error Code: 5H-17")) + owner.adjust_bodytemperature(SYNTH_HEAVY_EMP_TEMPERATURE_POWER * TEMPERATURE_DAMAGE_COEFFICIENT) + + if(EMP_LIGHT) + to_chat(owner, span_warning("Alert: Major cooling system failure!")) + owner.adjust_bodytemperature(SYNTH_LIGHT_EMP_TEMPERATURE_POWER * TEMPERATURE_DAMAGE_COEFFICIENT) + +/datum/design/synth_heatsink + name = "Heatsink" + desc = "A device that transfers generated heat to a fluid medium to cool it down. Required to keep your synthetics cool-headed. It's shape resembles lungs." + id = "synth_lungs" + build_type = PROTOLATHE | AWAY_LATHE | MECHFAB + construction_time = 4 SECONDS + materials = list( + /datum/material/iron = HALF_SHEET_MATERIAL_AMOUNT, + /datum/material/glass = HALF_SHEET_MATERIAL_AMOUNT, + ) + build_path = /obj/item/organ/internal/lungs/synth + category = list( + RND_CATEGORY_CYBERNETICS + RND_SUBCATEGORY_CYBERNETICS_ORGANS_1 + ) + departmental_flags = DEPARTMENT_BITFLAG_MEDICAL | DEPARTMENT_BITFLAG_SCIENCE diff --git a/monkestation/code/modules/surgery/organs/internal/stomach.dm b/monkestation/code/modules/surgery/organs/internal/stomach.dm index 2ef0eff5e8fc..183b9758b07c 100644 --- a/monkestation/code/modules/surgery/organs/internal/stomach.dm +++ b/monkestation/code/modules/surgery/organs/internal/stomach.dm @@ -18,3 +18,80 @@ organ_flags = ORGAN_SYNTHETIC //max_charge = 7500 //charge = 7500 //old bee code + +/obj/item/organ/internal/stomach/slime + name = "golgi apparatus" + zone = BODY_ZONE_CHEST + organ_flags = ORGAN_UNREMOVABLE + +/obj/item/organ/internal/stomach/slime/on_life(seconds_per_tick, times_fired) + . = ..() + operated = FALSE + +///IPCS NO LONGER ARE PURE ELECTRICAL BEINGS, any attempts to change this outside of Borbop will be denied. Thanks. +/obj/item/organ/internal/stomach/synth + name = "synthetic bio-reactor" + icon = 'monkestation/code/modules/smithing/icons/ipc_organ.dmi' + icon_state = "stomach-ipc" + w_class = WEIGHT_CLASS_NORMAL + zone = BODY_ZONE_CHEST + slot = ORGAN_SLOT_STOMACH + maxHealth = 1 * STANDARD_ORGAN_THRESHOLD + zone = "chest" + slot = "stomach" + desc = "A specialised mini reactor, for synthetic use only. Has a low-power mode to ensure baseline functions. Without this, synthetics are unable to stay powered." + organ_flags = ORGAN_ROBOTIC | ORGAN_SYNTHETIC_FROM_SPECIES + +/obj/item/organ/internal/stomach/synth/emp_act(severity) + . = ..() + + if(!owner || . & EMP_PROTECT_SELF) + return + + if(!COOLDOWN_FINISHED(src, severe_cooldown)) //So we cant just spam emp to kill people. + COOLDOWN_START(src, severe_cooldown, 10 SECONDS) + + switch(severity) + if(EMP_HEAVY) + owner.nutrition = max(0, owner.nutrition - SYNTH_STOMACH_HEAVY_EMP_CHARGE_LOSS) + apply_organ_damage(SYNTH_ORGAN_HEAVY_EMP_DAMAGE, maxHealth, required_organtype = ORGAN_ROBOTIC) + to_chat(owner, span_warning("Alert: Severe battery discharge!")) + + if(EMP_LIGHT) + owner.nutrition = max(0, owner.nutrition - SYNTH_STOMACH_LIGHT_EMP_CHARGE_LOSS) + apply_organ_damage(SYNTH_ORGAN_LIGHT_EMP_DAMAGE, maxHealth, required_organtype = ORGAN_ROBOTIC) + to_chat(owner, span_warning("Alert: Minor battery discharge!")) + +/datum/design/synth_stomach + name = "Synthetic Bio-Reactor" + desc = "A specialised mini reactor, for synthetic use only. Has a low-power mode to ensure baseline functions. Without this, synthetics are unable to stay powered." + id = "synth_stomach" + build_type = PROTOLATHE | AWAY_LATHE | MECHFAB + construction_time = 4 SECONDS + materials = list( + /datum/material/iron = HALF_SHEET_MATERIAL_AMOUNT, + /datum/material/glass = HALF_SHEET_MATERIAL_AMOUNT, + ) + build_path = /obj/item/organ/internal/stomach/synth + category = list( + RND_CATEGORY_CYBERNETICS + RND_SUBCATEGORY_CYBERNETICS_ORGANS_1 + ) + departmental_flags = DEPARTMENT_BITFLAG_MEDICAL | DEPARTMENT_BITFLAG_SCIENCE + +/obj/item/organ/internal/stomach/synth/Insert(mob/living/carbon/receiver, special, drop_if_replaced) + . = ..() + RegisterSignal(receiver, COMSIG_PROCESS_BORGCHARGER_OCCUPANT, PROC_REF(on_borg_charge)) + +/obj/item/organ/internal/stomach/synth/Remove(mob/living/carbon/stomach_owner, special) + . = ..() + UnregisterSignal(stomach_owner, COMSIG_PROCESS_BORGCHARGER_OCCUPANT) + +///Handles charging the synth from borg chargers +/obj/item/organ/internal/stomach/synth/proc/on_borg_charge(datum/source, amount) + SIGNAL_HANDLER + + if(owner.nutrition >= NUTRITION_LEVEL_ALMOST_FULL) + return + + amount /= 50 // Lowers the charging amount so it isn't instant + owner.nutrition = min((owner.nutrition + amount), NUTRITION_LEVEL_ALMOST_FULL) // Makes sure we don't make the synth too full, which would apply the overweight slowdown diff --git a/monkestation/code/modules/surgery/organs/internal/tongue.dm b/monkestation/code/modules/surgery/organs/internal/tongue.dm index c2a45d683494..9d87b87d5cf8 100644 --- a/monkestation/code/modules/surgery/organs/internal/tongue.dm +++ b/monkestation/code/modules/surgery/organs/internal/tongue.dm @@ -38,3 +38,57 @@ /obj/item/organ/internal/tongue/arachnid/get_possible_languages() return ..() + /datum/language/buzzwords + +/obj/item/organ/internal/tongue/jelly + zone = BODY_ZONE_CHEST + organ_flags = ORGAN_UNREMOVABLE + +/obj/item/organ/internal/tongue/jelly/get_possible_languages() + return ..() + /datum/language/slime + +/obj/item/organ/internal/tongue/synth + name = "synthetic voicebox" + desc = "A fully-functional synthetic tongue, encased in soft silicone. Features include high-resolution vocals and taste receptors." + icon = 'monkestation/code/modules/smithing/icons/ipc_organ.dmi' + icon_state = "cybertongue" + say_mod = "beeps" + attack_verb_continuous = list("beeps", "boops") + attack_verb_simple = list("beep", "boop") + modifies_speech = TRUE + taste_sensitivity = 25 // not as good as an organic tongue + maxHealth = 100 //RoboTongue! + zone = BODY_ZONE_HEAD + slot = ORGAN_SLOT_TONGUE + organ_flags = ORGAN_ROBOTIC | ORGAN_SYNTHETIC_FROM_SPECIES + +/obj/item/organ/internal/tongue/synth/get_scream_sound() + return 'monkestation/sound/voice/screams/silicon/scream_silicon.ogg' + +/obj/item/organ/internal/tongue/synth/get_laugh_sound() + return pick( + 'monkestation/sound/voice/laugh/silicon/laugh_siliconE1M0.ogg', + 'monkestation/sound/voice/laugh/silicon/laugh_siliconE1M1.ogg', + 'monkestation/sound/voice/laugh/silicon/laugh_siliconM2.ogg', + ) + +/obj/item/organ/internal/tongue/synth/can_speak_language(language) + return TRUE + +/obj/item/organ/internal/tongue/synth/handle_speech(datum/source, list/speech_args) + speech_args[SPEECH_SPANS] |= SPAN_ROBOT + +/datum/design/synth_tongue + name = "Synthetic Tongue" + desc = "A fully-functional synthetic tongue, encased in soft silicone. Features include high-resolution vocals and taste receptors." + id = "synth_tongue" + build_type = PROTOLATHE | AWAY_LATHE | MECHFAB + construction_time = 4 SECONDS + materials = list( + /datum/material/iron = HALF_SHEET_MATERIAL_AMOUNT, + /datum/material/glass = HALF_SHEET_MATERIAL_AMOUNT, + ) + build_path = /obj/item/organ/internal/tongue/synth + category = list( + RND_CATEGORY_CYBERNETICS + RND_SUBCATEGORY_CYBERNETICS_ORGANS_1 + ) + departmental_flags = DEPARTMENT_BITFLAG_MEDICAL | DEPARTMENT_BITFLAG_SCIENCE diff --git a/monkestation/code/modules/smithing/ipcs/surgeries/robot_brain_healing.dm b/monkestation/code/modules/surgery/robot_brain_healing.dm similarity index 100% rename from monkestation/code/modules/smithing/ipcs/surgeries/robot_brain_healing.dm rename to monkestation/code/modules/surgery/robot_brain_healing.dm diff --git a/monkestation/code/modules/smithing/ipcs/surgeries/robot_chest_repair.dm b/monkestation/code/modules/surgery/robot_chest_repair.dm similarity index 100% rename from monkestation/code/modules/smithing/ipcs/surgeries/robot_chest_repair.dm rename to monkestation/code/modules/surgery/robot_chest_repair.dm diff --git a/monkestation/code/modules/smithing/ipcs/surgeries/robot_healing.dm b/monkestation/code/modules/surgery/robot_healing.dm similarity index 100% rename from monkestation/code/modules/smithing/ipcs/surgeries/robot_healing.dm rename to monkestation/code/modules/surgery/robot_healing.dm diff --git a/monkestation/code/modules/smithing/ipcs/surgeries/steps.dm b/monkestation/code/modules/surgery/steps.dm similarity index 100% rename from monkestation/code/modules/smithing/ipcs/surgeries/steps.dm rename to monkestation/code/modules/surgery/steps.dm diff --git a/monkestation/icons/mob/clothing/worn_modsuit.dmi b/monkestation/icons/mob/clothing/worn_modsuit.dmi index 900e2c30e61e52e73a469c366c3824a7b8b1847e..9d9f37d5a897bb4075f2480b06319a18448e6283 100644 GIT binary patch literal 13104 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 JqwWy-{{cA2BAoyL literal 3506 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 diff --git a/monkestation/icons/obj/clothing/modsuits/modsuit.dmi b/monkestation/icons/obj/clothing/modsuits/modsuit.dmi index 3d550c1034cd51352903ad544c8deac142cbe83e..9be9e19751f12ec10e1fb64d1d73c33323f77131 100644 GIT binary patch literal 6944 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 literal 2144 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 C1x0}X delta 16147 zcmZv@2RK|&*EW1c?=?t77cC-42%-!UL82y6qL(0gh!$ne1VNM_1<{2l(IZNC^O2;{70VWegE&f{@>+dPI1m&d#}CLecx;OIYKhmPZDFi+1iHxz**55XCgI}(lSw^Lv>PP8(vPB8MNmQR83e;cy)SzW%Cw*9-Df?|u zU{ujNaVIR|m2|a?^GTse$W(mEpnzWnz5T7)X4l5v>itV|n)&lTuSW8xeD`|IWB!qX zdUcMjBUAQX*6T7e?)ZrUa+6BZwS2zjwE38>`e_Q=(3_^wdOd2;W*b9x+f!^ey=eO1NRCAM_9h!Zc6izPUmt z%~Te|{Cs#tUcJG&vTXE93-d?VQxlGjSy(rF6t6)3kfRuzo zig;n$cn0SlsDjZB)pY3>jqY`LH&+?N=?UEA!z(F%ko!()JH#dKO?~47M}1jEw{KS2 zg62(C7Mq7tdz~U-v(4{|dRp12a+|WWI|1Y1g71+i^>8!eMdksH{OH&eh58a_Jxc$; z46l4W;;ko3QI=^QnGfZKyF>L}!(#+xl!}fVJWYOcv*>}5V7734l2V()0b9P!UV%<5 z?cHt_7b_0wh-sas?cDaL^ayDZrg)?GMF|Tx{rHnzgT8Y{Bq zS2GsI9?qDAe~s94en;3caGN%6R;d*fP$T?CdTRI1fMrX{9;DN=A&hPEDcX2E4d?Y5 z6Y>(_-!{i8%pD<30}X$ZKHTqAd{+_Q?OvLxGI`Y^-f*66h|hYz!J3Y&!TFUwJ*DBM zfZ&HBfvZnL>xr(0@aHGK@@@BhxonAz? z51kTjy77XqsmS7+3|=P=iYqRM&d7SWc{d7L8q>i-IDX)^-Nw1ItI0$hA5DAnq!^0N z>#AFQC&_#BgwBcaEVQj6%T?*GL2IQ(eoR{|wSb-gtBb-1h0_-QF{%iuE3$$<_EiS2 zFCJfQLao;BZKPbSE;RYUGZTT`d^NzwQ2G!akBtfy8FBi~x0l^~!*VIbPRX8$@Iy}F z%I=G!!;ZwwZjAdr2=f*R@Sdf@A696Q4XlFsYHE5<^fD{gOr8wddRzBu(@ghzs|bi{ zuRA*ind)oyevq#A6gYJ)DJWkbGy9qO{i41~J^EtD_w7j&r*+^#J;~0 zmqK4^zue9K{!g#waQG=58{OED*`JFjhvF{$DU9Q=(UPV~sCVkC#}ckXF%MY?P`v_K z+)jE!z{?;Z!2&ZDfSbg_6gGoUkHbHiiYXBqG7{&qly{EX6F?8+Sn2n5zKLPDE5rbF$m`bLA@ zynOUqQ+?D&(=(b2L4*4V2reYd0D?PyE1Gd`L*RU3oWO^lU$aZ~;g%VS_0bhjO*c`xGKsQXG4#SA)MV-JL7X|1PQ;`X?ZA= zT}72hVADNsshOoZ&95e%Xh^YN8B0&OMxp#&&(}=Q4c!>C&n7;P+rf9tU0j7eb}c&( zpctBTuO73JJ*i>A$b?}s5Nc;Ty~zS3RqnCU&ZEkuV+&C%q8vweKaJV-jF(eTQZ^?` zJ2SAb2wXERYbw4cak7R1?NFwaO;O_Y$iQOOy*)}I2HN6V5B3w^Fz?Ar^2WVMwd>yP z;)YiTY^J-JBaIszoqtaKcp-i1(xsLL;)c1gg3Z!aBi!|owf7f!kowr?qtO&Bu|E{GyVCF5L_z zv5Zh?x)U{Yb=e}LqF~BYh#7>?Z>gR#B`-kY0aY+`a+<1TH4i<8xLQ}DWN-kSHL z`^N9(#O#E2+O7UHc_Z7>DOSkJ$sUi@?Do(cDz-Hq5?cSM8-LpNL&PhD|6nLnA@%{wygqw`sLn^CFdJml@ z2Uk*qc&<{_Ihktoyo5f8 zQv^$igUZ*J1^RDRmfR(NWT>qY%cXcNI5X$LjFucU%_tm`%`SH_%*!54+x?XL^(H&j ziS6ettrq=G_p#zkXoaC*FqE;p0T>t|STUh4Ys+F|N%N^G-HtGh*P;>Z4Z!(tGW$2o zeD8|;5IX+mR~xGy=W~xxk-6B|SWJz_&;;6wx+W1v7yfFXG#|Z;QC0yP6qT=I&F=#r z8h<55Tzm@o&}`w(;loddd#gJe30Y@d>l`O3Vd$CLXMHCq)z^-W^?c)C>cX|7?K_z{ z++_{)$RWhWDIh#&`R(bO<$e%fvAYlp9}Te3(_8gq6i=`<`1L#kQ1H~a+c?7lp{zFlh3Fp<5{ z+1JNymEf=Q{RM2$)= z+$DTgi<&~v`{C*l(l{H=&Ei)U+>VZpaT|hK&^V(IiQzzdM~CSZ7~fGBg$GMzh|bAn zqXGB6^^rp9?0YdxZLC2Xcbn?XstiHVWwjn+Kub=deU2$Y(f>eM%c;k3pX-rt2pq}* zy8<%x2n!U*j{p8$O54OF`9Z75Vm+}a?%?z@dWj3jygn|o1C!7N#)*|F_E;@JTqOe& z6Esd%Sp^|QMNa<)E`Ig52iO2%MMZNB4UOktNxy&n+GS(;c2pON>ke?5nbHq=e(+r<4XaN+w+Eg1?nz%g42z+a6YdSH_2ZpC zbem&W+4(pqctaWBEk5Sr|30Zk^tZex#R?~0CW2ADU&e5OgQ{Cp45|@@Z9-Ql)EOgP z#Y*|SUX+AEi3a0JsPR|`UFuF0MHGi(uO^?J1y*hh8JW7+;P4@VK3AHJZ7d*9a4LA|%P z*Yb*(oD95u!q~50R{}kML&lvMm_6cz)p!=lP57=+0!b*pPkf;7d2acOudi2V4t$_t zyVyScM!Rcgh#@nyU{4j1VCNH`mbSG^e?v@6dsIt940RDJ3psWde;*#QY?i-=f#gNHv;8Fv29pFh_rp&0aZjZ44Pefk9b)j-rC45k^&&&Sub$VK&39AJI9(}0=X zQXYu6)UJMrKUtp@M^rL)@L2xvyfk9KW-Vp$?yZOK#R2S2W<2ty4g4u+)h=|J5r%xLuM~h8mM8FWrrhp22%2!*Hw!O*H0~?1}n|3NM z8mg}tIW|#IN&8LX(9lo-fM8{rRWnib41+XonG%_82nIxGBCDB@LqiXXEE?DWJ!4}E zAR;E_(4PU6^_ahF-5JLV9ahR28XHFxn^yZz!(S|GMLClp^|SBI%>?WiT!Ar`g2Vax z#tr_J-woDJMh;|HnGD-OB4A*IbrpFQxaEBRc!8OTL{yRQ?>(WNBd4b5K9m{W?FB<2KNGS$Bt$8coZPb?} zyefbt?7$OvMd5!$n+XG1cR0Dw-yPpids=GH4E_H7dVbypcrLoFsik#S+gsY+-oEzG zVj$!CQ#(5tu-umxHLenp`j^cO{Wdz9=9@w0E|3FEiVc64TEeqz_4IJf)#Jo9 zT5;c4iVX|*yi|)O5H?XS|IX>=rvU|9Mk$9W)s&Cq-EY#W)Rg*AsKTxAHfK)?co{bG z`oCQwim&$jl$pd`iNEYUMlXO%2^g^;kW}#UbRAE+-ZBRX6Bra5^4RplzL3>rkgNRU zY(+fGa|d*o?P9jaBb3vF5j4`Yu#-cj3Jm%I3WV~=Fb5oAmUPQC`Cx)O=pbIgb5Wx= zS34y%o?qQ5S;qZ34n%oxBrHSG;TsOcW^_>D6R`wEI8_yuS6&D+vs4!h@yXLcJ_XF# z{=;j(bH7pn&wtz@kJ>j81I;6ynFXzeLg=mbVsmSI(xs_yrc$u4`S#$y-MD-2UhQUV zbab08DXE{-^^(EUr3U7*8xI(>HP}LuR{2KGVqp6~eQhoK?XwjqT=va3B1nqN3vU-@l$w-$3Z+zTB%(!olm- zaQg0L-wQoaOQRi?CdDpp&PBxVrVD3pCZQ4f^=_5o-@RixDB!%mU4+WXAt?_blcq#H zqEvomD0;9lraK`%)UFXLM&wb!>L*uz6y;r}NmRes@3)WpmLO(&{}f$h;db*9_KW^P z&XP*0CF<=D?#Ag^Fx1+YAw)S~X=YcN6!p#)tww<0)FV$wQE|x)6lJ4%0D)G_ZRs@@>fA~1Z>Ex74 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 diff --git a/monkestation/code/modules/blueshield/icons/radio.dmi b/monkestation/icons/obj/radio.dmi similarity index 100% rename from monkestation/code/modules/blueshield/icons/radio.dmi rename to monkestation/icons/obj/radio.dmi diff --git a/monkestation/code/modules/blueshield/icons/gun.dmi b/monkestation/icons/obj/weapons/guns/tech9.dmi similarity index 100% rename from monkestation/code/modules/blueshield/icons/gun.dmi rename to monkestation/icons/obj/weapons/guns/tech9.dmi diff --git a/tgstation.dme b/tgstation.dme index a5d9abd8f7d5..efde1e48e361 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -6635,9 +6635,7 @@ #include "monkestation\code\modules\blueshield\closet.dm" #include "monkestation\code\modules\blueshield\clothing.dm" #include "monkestation\code\modules\blueshield\gun.dm" -#include "monkestation\code\modules\blueshield\job.dm" #include "monkestation\code\modules\blueshield\landmarks.dm" -#include "monkestation\code\modules\blueshield\radio.dm" #include "monkestation\code\modules\blueshield\trim.dm" #include "monkestation\code\modules\blueshield\devices\crew_monitor.dm" #include "monkestation\code\modules\blueshield\devices\sensor.dm" @@ -7331,8 +7329,10 @@ #include "monkestation\code\modules\job_xp\milestones\botany_milestones.dm" #include "monkestation\code\modules\job_xp\preferences\base_preferences.dm" #include "monkestation\code\modules\job_xp\preferences\xp_handlers.dm" +#include "monkestation\code\modules\jobs\departments\departments.dm" #include "monkestation\code\modules\jobs\job_types\_job.dm" #include "monkestation\code\modules\jobs\job_types\barber.dm" +#include "monkestation\code\modules\jobs\job_types\blueshield.dm" #include "monkestation\code\modules\jobs\job_types\brig_physician.dm" #include "monkestation\code\modules\jobs\job_types\candysalesman.dm" #include "monkestation\code\modules\jobs\job_types\chaplain.dm" @@ -7351,7 +7351,6 @@ #include "monkestation\code\modules\jobs\job_types\skeleton.dm" #include "monkestation\code\modules\jobs\job_types\virologist.dm" #include "monkestation\code\modules\jobs\job_types\yellowclown.dm" -#include "monkestation\code\modules\jobs\job_types\departments\departments.dm" #include "monkestation\code\modules\jobs\job_types\spawner\bar_drone.dm" #include "monkestation\code\modules\library\bookcase.dm" #include "monkestation\code\modules\library\skill_learning\job_skillchips\shaft_miner.dm" @@ -7595,8 +7594,11 @@ #include "monkestation\code\modules\mob\living\carbon\human\species_type\floran.dm" #include "monkestation\code\modules\mob\living\carbon\human\species_type\flypeople.dm" #include "monkestation\code\modules\mob\living\carbon\human\species_type\goblin.dm" +#include "monkestation\code\modules\mob\living\carbon\human\species_type\ipc.dm" #include "monkestation\code\modules\mob\living\carbon\human\species_type\lizardpeople.dm" +#include "monkestation\code\modules\mob\living\carbon\human\species_type\oozeling.dm" #include "monkestation\code\modules\mob\living\carbon\human\species_type\plasmamen.dm" +#include "monkestation\code\modules\mob\living\carbon\human\species_type\satyr.dm" #include "monkestation\code\modules\mob\living\carbon\human\species_type\simian.dm" #include "monkestation\code\modules\mob\living\carbon\human\species_type\skeletons.dm" #include "monkestation\code\modules\mob\living\carbon\human\species_type\teratoma.dm" @@ -7883,9 +7885,7 @@ #include "monkestation\code\modules\ranching\mutations\tier3.dm" #include "monkestation\code\modules\ranching\name_tags\name_tag.dm" #include "monkestation\code\modules\ranching\satyr\abilities.dm" -#include "monkestation\code\modules\ranching\satyr\bodyparts.dm" #include "monkestation\code\modules\ranching\satyr\external_organs.dm" -#include "monkestation\code\modules\ranching\satyr\species.dm" #include "monkestation\code\modules\ranching\satyr\accessories\prefs.dm" #include "monkestation\code\modules\ranching\satyr\accessories\sprites\fluff.dm" #include "monkestation\code\modules\ranching\satyr\accessories\sprites\horns.dm" @@ -8080,15 +8080,8 @@ #include "monkestation\code\modules\smithing\assembly_bench\assembly_bench.dm" #include "monkestation\code\modules\smithing\assembly_bench\assembly_recipes\_base_recipe.dm" #include "monkestation\code\modules\smithing\assembly_bench\assembly_recipes\weapons.dm" -#include "monkestation\code\modules\smithing\ipcs\species.dm" -#include "monkestation\code\modules\smithing\ipcs\body\base_bodyparts.dm" -#include "monkestation\code\modules\smithing\ipcs\body\internal_organs.dm" #include "monkestation\code\modules\smithing\ipcs\reagents\medical_supplies.dm" #include "monkestation\code\modules\smithing\ipcs\reagents\reagents.dm" -#include "monkestation\code\modules\smithing\ipcs\surgeries\robot_brain_healing.dm" -#include "monkestation\code\modules\smithing\ipcs\surgeries\robot_chest_repair.dm" -#include "monkestation\code\modules\smithing\ipcs\surgeries\robot_healing.dm" -#include "monkestation\code\modules\smithing\ipcs\surgeries\steps.dm" #include "monkestation\code\modules\smithing\items\clothing.dm" #include "monkestation\code\modules\smithing\items\merged_material.dm" #include "monkestation\code\modules\smithing\machines\arc_forge.dm" @@ -8117,9 +8110,6 @@ #include "monkestation\code\modules\smithing\mining_changes\mineral_datums.dm" #include "monkestation\code\modules\smithing\mining_changes\mineral_sample.dm" #include "monkestation\code\modules\smithing\oozelings\actions.dm" -#include "monkestation\code\modules\smithing\oozelings\species.dm" -#include "monkestation\code\modules\smithing\oozelings\body\bodyparts.dm" -#include "monkestation\code\modules\smithing\oozelings\body\organs.dm" #include "monkestation\code\modules\smithing\research\circuits_and_research.dm" #include "monkestation\code\modules\smithing\TEG\circulators.dm" #include "monkestation\code\modules\smithing\TEG\reagents.dm" @@ -8202,6 +8192,10 @@ #include "monkestation\code\modules\surgery\hepatectomy.dm" #include "monkestation\code\modules\surgery\lobectomy.dm" #include "monkestation\code\modules\surgery\nif_debonding.dm" +#include "monkestation\code\modules\surgery\robot_brain_healing.dm" +#include "monkestation\code\modules\surgery\robot_chest_repair.dm" +#include "monkestation\code\modules\surgery\robot_healing.dm" +#include "monkestation\code\modules\surgery\steps.dm" #include "monkestation\code\modules\surgery\advanced\brainwashing.dm" #include "monkestation\code\modules\surgery\advanced\lobotomy.dm" #include "monkestation\code\modules\surgery\advanced\pacification.dm" @@ -8209,7 +8203,10 @@ #include "monkestation\code\modules\surgery\bodyparts\clockwork_bodyparts.dm" #include "monkestation\code\modules\surgery\bodyparts\ethereal_bodyparts.dm" #include "monkestation\code\modules\surgery\bodyparts\floran_bodyparts.dm" +#include "monkestation\code\modules\surgery\bodyparts\ipc_bodyparts.dm" #include "monkestation\code\modules\surgery\bodyparts\monkey_bodyparts.dm" +#include "monkestation\code\modules\surgery\bodyparts\oozeling_bodyparts.dm" +#include "monkestation\code\modules\surgery\bodyparts\satyr_bodyparts.dm" #include "monkestation\code\modules\surgery\bodyparts\teratoma_bodyparts.dm" #include "monkestation\code\modules\surgery\organs\augments.dm" #include "monkestation\code\modules\surgery\organs\autosurgeon.dm" diff --git a/tgui/packages/tgui/interfaces/common/JobToIcon.ts b/tgui/packages/tgui/interfaces/common/JobToIcon.ts index b93296c08c3a..aff948908689 100644 --- a/tgui/packages/tgui/interfaces/common/JobToIcon.ts +++ b/tgui/packages/tgui/interfaces/common/JobToIcon.ts @@ -82,6 +82,7 @@ const ALTTITLES = { Artist: BASEICONS['Assistant'], 'Off-Duty Staff': BASEICONS['Assistant'], 'Off-Duty Crew': BASEICONS['Assistant'], + 'Test Subject': BASEICONS['Assistant'], // Atmospheric Technician - fan 'Life Support Technician': BASEICONS['Atmospheric Technician'], 'Emergency Fire Technician': BASEICONS['Atmospheric Technician'], @@ -98,6 +99,10 @@ const ALTTITLES = { // Blueshield - shield-dog 'Command Bodyguard': BASEICONS['Blueshield'], 'Executive Protection Agent': BASEICONS['Blueshield'], + Bodyguard: BASEICONS['Blueshield'], + 'Revolutionary Repellent': BASEICONS['Blueshield'], + 'Heavily Armed Butler': BASEICONS['Blueshield'], + 'Honor Guard': BASEICONS['Blueshield'], // Botanist - seedling Hydroponicist: BASEICONS['Botanist'], Gardener: BASEICONS['Botanist'], @@ -110,6 +115,8 @@ const ALTTITLES = { 'Station Commander': BASEICONS['Captain'], 'Commanding Officer': BASEICONS['Captain'], 'Site Manager': BASEICONS['Captain'], + 'Criminally Underpaid Babysitter': BASEICONS['Captain'], + Princess: BASEICONS['Captain'], // Cargo Technician - box 'Warehouse Technician': BASEICONS['Cargo Technician'], 'Deck Worker': BASEICONS['Cargo Technician'], @@ -147,6 +154,7 @@ const ALTTITLES = { Butcher: BASEICONS['Cook'], 'Culinary Artist': BASEICONS['Cook'], 'Sous-Chef': BASEICONS['Cook'], + Pizzaiolo: BASEICONS['Cook'], // Coroner - skull Mortician: BASEICONS['Coroner'], 'Funeral Director': BASEICONS['Coroner'], @@ -154,6 +162,7 @@ const ALTTITLES = { Librarian: BASEICONS['Curator'], Journalist: BASEICONS['Curator'], Archivist: BASEICONS['Curator'], + 'Radio Host': BASEICONS['Curator'], // Cyborg - robot Robot: BASEICONS['Cyborg'], Android: BASEICONS['Cyborg'], @@ -198,6 +207,10 @@ const ALTTITLES = { Pantomimist: BASEICONS['Mime'], // Nanotrasen Consultant - clipboard-check 'Nanotrasen Diplomat': BASEICONS['Nanotrasen Consultant'], + 'Corporate Liaison': BASEICONS['Nanotrasen Consultant'], + 'Nanotrasen Fax Operater': BASEICONS['Nanotrasen Consultant'], + 'Nanotrasen Official': BASEICONS['Nanotrasen Consultant'], + 'Nanotrasen Informant': BASEICONS['Nanotrasen Consultant'], // Paramedic - truck-medical 'Emergency Medical Technician': BASEICONS['Paramedic'], 'Search and Rescue Technician': BASEICONS['Paramedic'], @@ -209,6 +222,7 @@ const ALTTITLES = { Convict: BASEICONS['Prisoner'], Felon: BASEICONS['Prisoner'], Inmate: BASEICONS['Prisoner'], + Gamer: BASEICONS['Prisoner'], // Psychologist - brain Psychiatrist: BASEICONS['Psychologist'], Therapist: BASEICONS['Psychologist'], @@ -220,6 +234,7 @@ const ALTTITLES = { 'Supply Foreman': BASEICONS['Quartermaster'], 'Head of Supply': BASEICONS['Quartermaster'], 'Logistics Coordinator': BASEICONS['Quartermaster'], + 'Cargyptian Overseer': BASEICONS['Quartermaster'], // Research Director - user-graduate 'Silicon Administrator': BASEICONS['Research Director'], 'Lead Researcher': BASEICONS['Research Director'], @@ -231,6 +246,7 @@ const ALTTITLES = { 'Biomechanical Engineer': BASEICONS['Roboticist'], 'Mechatronic Engineer': BASEICONS['Roboticist'], 'Apprentice Roboticist': BASEICONS['Roboticist'], + Ripperdoc: BASEICONS['Roboticist'], // Scientist - flask 'Circuitry Designer': BASEICONS['Scientist'], Xenobiologist: BASEICONS['Scientist'], @@ -250,6 +266,8 @@ const ALTTITLES = { Peacekeeper: BASEICONS['Security Officer'], 'Security Cadet': BASEICONS['Security Officer'], // Security Assistant - file-invoice-dollar + 'Correctional Officer': BASEICONS['Security Assistant'], + Deputy: BASEICONS['Security Assistant'], 'Hall Monitor': BASEICONS['Security Assistant'], 'Assistant Officer': BASEICONS['Security Assistant'], 'Professional Snitch': BASEICONS['Security Assistant'], @@ -272,7 +290,9 @@ const ALTTITLES = { 'Engineering Trainee': BASEICONS['Station Engineer'], // Virologist - virus Pathologist: BASEICONS['Virologist'], + 'Fish Doctor': BASEICONS['Virologist'], 'Junior Pathologist': BASEICONS['Virologist'], + 'Plague Doctor': BASEICONS['Virologist'], // Warden - handcuffs 'Brig Sergeant': BASEICONS['Warden'], 'Dispatch Officer': BASEICONS['Warden'], From dd64696d7fed1a535a4c80b0931e491ca640c95e Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 19 Dec 2024 21:08:08 +0000 Subject: [PATCH 07/81] Automatic changelog for PR #4613 [ci skip] --- html/changelogs/AutoChangeLog-pr-4613.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-4613.yml diff --git a/html/changelogs/AutoChangeLog-pr-4613.yml b/html/changelogs/AutoChangeLog-pr-4613.yml new file mode 100644 index 000000000000..bcbc00ae9a6c --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-4613.yml @@ -0,0 +1,4 @@ +author: "Gw0sty" +delete-after: True +changes: + - balance: "Research directors remote now has AI upload access." \ No newline at end of file From e7c985dbea995c0f5ae1945e2add28f50f469856 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 19 Dec 2024 21:08:17 +0000 Subject: [PATCH 08/81] Automatic changelog for PR #4591 [ci skip] --- html/changelogs/AutoChangeLog-pr-4591.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-4591.yml diff --git a/html/changelogs/AutoChangeLog-pr-4591.yml b/html/changelogs/AutoChangeLog-pr-4591.yml new file mode 100644 index 000000000000..27d0bde53f8b --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-4591.yml @@ -0,0 +1,5 @@ +author: "Absolucy" +delete-after: True +changes: + - bugfix: "The cargo imports UI now shows the correct price when the station has strong or distant supply lines." + - bugfix: "Ordering from cargo imports now actually checks to see if you have the correct amount of money when the station has strong or distant supply lines." \ No newline at end of file From e34b8e285ed3d29084d2b008307a22f1900f36b3 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 19 Dec 2024 21:08:25 +0000 Subject: [PATCH 09/81] Automatic changelog for PR #4584 [ci skip] --- html/changelogs/AutoChangeLog-pr-4584.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-4584.yml diff --git a/html/changelogs/AutoChangeLog-pr-4584.yml b/html/changelogs/AutoChangeLog-pr-4584.yml new file mode 100644 index 000000000000..0924724c607b --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-4584.yml @@ -0,0 +1,10 @@ +author: "Gw0sty" +delete-after: True +changes: + - rscadd: "brought the Christmas spirit (tree) to Thesues!" + - rscadd: "Gave Ancient/charlie/oldstation a supermatter shard that gives its warnings on Uncommon frequency" + - rscadd: "Added three uncommon radio keys to the science box on charlie so borgs can get the frequency" + - bugfix: "Replaced knifes in Theseus's kitchen with kitchen knives. Now (nothing changes) chefs can use their knifes in peace." + - bugfix: "Made it so you can actually leave the Theseus Gulag shuttle." + - bugfix: "added missing job to Icons for alt title jobs." + - bugfix: "Ipc surgery research now works as intended" \ No newline at end of file From 8c4c0edfc951b29425be6fd402678b447ff0b28e Mon Sep 17 00:00:00 2001 From: Loiosh42 <129321455+Loiosh42@users.noreply.github.com> Date: Thu, 19 Dec 2024 16:09:52 -0500 Subject: [PATCH 10/81] The stuff (plus extra because I noticed it) (#4621) --- .../projectiles/projectile/bullets/shotgun.dm | 24 +++++++++++++++---- .../code/modules/blueshift/items/ammo.dm | 12 ++++++++++ .../modules/blueshift/items/company_guns.dm | 2 ++ 3 files changed, 33 insertions(+), 5 deletions(-) diff --git a/code/modules/projectiles/projectile/bullets/shotgun.dm b/code/modules/projectiles/projectile/bullets/shotgun.dm index 2199b1c88c75..f3e183bde308 100644 --- a/code/modules/projectiles/projectile/bullets/shotgun.dm +++ b/code/modules/projectiles/projectile/bullets/shotgun.dm @@ -19,15 +19,29 @@ name = "tungsten sabot-slug" icon_state = "gauss" damage = 30 //20 less than slugs. - speed = 0.3 //sub-caliber + lighter = speed. (Smaller number = faster) - armour_penetration = 80 //Tis a solid-tungsten penetrator, what do you expect? - wound_bonus = 5 //30 seems kinda wimpy, 5 bonus puts it over the threshold + speed = 0.25 //sub-caliber + lighter = speed. (Smaller number = faster) + armour_penetration = 70 //Tis a solid-tungsten penetrator, what do you expect? + wound_bonus = -3 //Had issues with massive wounding behind armor, thus... ricochets_max = 2 //Unlike slugs which tend to squish on impact, these are hard enough to bounce rarely. - ricochet_chance = 60 + ricochet_chance = 90 ricochet_auto_aim_range = 4 ricochet_incidence_leeway = 55 embedding = null - demolition_mod = 4 //One higher than it was at 35. It might do less damage, but it will still go through stuff just fine. + demolition_mod = 5 //High-velocity tungsten > steel doors + projectile_piercing = PASSMOB + + +/obj/projectile/bullet/shotgun_slug/apds/pierce/on_hit(atom/target, blocked = 0, pierce_hit) + if(isliving(target)) + // If the bullet has already gone through 3 people, stop it on this hit + if(pierces > 3) + projectile_piercing = NONE + + if(damage > 10) // Lets just be safe with this one + damage -= 7 + armour_penetration -= 10 + + return ..() /obj/projectile/bullet/shotgun_beanbag name = "beanbag slug" diff --git a/monkestation/code/modules/blueshift/items/ammo.dm b/monkestation/code/modules/blueshift/items/ammo.dm index 0d1441a8fb7c..895ef1b5d3cd 100644 --- a/monkestation/code/modules/blueshift/items/ammo.dm +++ b/monkestation/code/modules/blueshift/items/ammo.dm @@ -865,6 +865,18 @@ // We do 80 total damage to anything robotic, namely borgs, and robotic simplemobs AddElement(/datum/element/bane, target_type = /mob/living, mob_biotypes = MOB_ROBOTIC, damage_multiplier = 0, added_damage = anti_materiel_damage_addition) +/obj/projectile/bullet/p60strela/pierce/on_hit(atom/target, blocked = 0, pierce_hit) /// If anyone is deranged enough to use it on soft targets, you may as well let them have fun + if(isliving(target)) + // If the bullet has already gone through 3 people, stop it on this hit + if(pierces > 3) + projectile_piercing = NONE + + if(damage > 10) // Lets just be safe with this one + damage -= 10 + armour_penetration -= 10 + + return ..() + /obj/item/ammo_box/magazine/m10mm/rifle name = "rifle magazine (10mm)" desc = "A well-worn magazine fitted for the surplus rifle." diff --git a/monkestation/code/modules/blueshift/items/company_guns.dm b/monkestation/code/modules/blueshift/items/company_guns.dm index f99c598cfaaf..733fde05e763 100644 --- a/monkestation/code/modules/blueshift/items/company_guns.dm +++ b/monkestation/code/modules/blueshift/items/company_guns.dm @@ -963,6 +963,8 @@ icon_state = "bobr" fire_sound = 'monkestation/code/modules/blueshift/sounds/revolver_fire.ogg' spread = SAWN_OFF_ACC_PENALTY + projectile_damage_multiplier = 0.75 /// No way in hell a handgun with a 3 inch barrel should fire the same cartridge with the same force as a full-length barrel + projectile_wound_bonus = -5 /// In addition, this should help with the balance issues around the Bobr, it being a concealable shotgun with near-instant reload /obj/item/gun/ballistic/revolver/shotgun_revolver/give_manufacturer_examine() AddElement(/datum/element/manufacturer_examine, COMPANY_SZOT) From 5fa762b3d12ee79490aa8431519ccb969ba73c65 Mon Sep 17 00:00:00 2001 From: michaelyoungin <94155147+michaelyoungin@users.noreply.github.com> Date: Thu, 19 Dec 2024 15:10:59 -0600 Subject: [PATCH 11/81] Theprofit CC Office (#4606) * Remaking PR from scratch. * Fixed missing floor tile --- _maps/map_files/generic/CentCom.dmm | 323 ++++++++++++++++++++++------ 1 file changed, 252 insertions(+), 71 deletions(-) diff --git a/_maps/map_files/generic/CentCom.dmm b/_maps/map_files/generic/CentCom.dmm index d733578cad42..bbd27a42418e 100644 --- a/_maps/map_files/generic/CentCom.dmm +++ b/_maps/map_files/generic/CentCom.dmm @@ -19367,6 +19367,11 @@ }, /turf/open/floor/carpet/red, /area/cruiser_dock) +"bhS" = ( +/obj/structure/table/wood, +/obj/machinery/microwave, +/turf/open/floor/iron/vaporwave, +/area/centcom/central_command_areas/adminroom) "bip" = ( /obj/effect/spawner/random/vending/snackvend, /obj/effect/turf_decal/bot_white, @@ -19542,6 +19547,12 @@ }, /turf/open/water/arena, /area/centcom/central_command_areas/admin) +"bxX" = ( +/obj/effect/spawner/random/trash/hobo_squat, +/obj/effect/spawner/random/trash/garbage, +/obj/effect/spawner/random/trash/mess, +/turf/open/floor/plating/rust, +/area/centcom/central_command_areas/adminroom) "bys" = ( /obj/structure/sign/departments/chemistry/alt/directional/east, /obj/effect/turf_decal/tile/orange/half/contrasted{ @@ -19738,6 +19749,20 @@ }, /turf/open/floor/iron/dark, /area/centcom/central_command_areas/hall) +"bYc" = ( +/obj/effect/turf_decal/siding/white{ + dir = 5 + }, +/obj/effect/spawner/random/trash/caution_sign, +/turf/open/floor/grass, +/area/centcom/central_command_areas/admin) +"bYp" = ( +/obj/effect/turf_decal/siding/white{ + dir = 1 + }, +/obj/effect/spawner/random/trash/caution_sign, +/turf/open/floor/grass, +/area/centcom/central_command_areas/admin) "bYA" = ( /obj/machinery/light/neon_lining{ dir = 1; @@ -20170,6 +20195,11 @@ }, /turf/open/floor/iron/white/textured, /area/centcom/central_command_areas/admin) +"cYr" = ( +/obj/structure/bonfire/prelit, +/obj/effect/spawner/random/trash/cigbutt, +/turf/open/floor/plating/rust, +/area/centcom/central_command_areas/adminroom) "dbJ" = ( /obj/machinery/door/airlock/centcom{ name = "Veth's Plantery" @@ -20686,6 +20716,13 @@ "exa" = ( /turf/open/floor/sandy_dirt, /area/centcom/central_command_areas/admin) +"exj" = ( +/obj/effect/spawner/random/trash/bacteria, +/obj/effect/spawner/random/trash/garbage, +/obj/effect/spawner/random/trash/cigbutt, +/obj/effect/spawner/random/trash/mess, +/turf/open/floor/iron/vaporwave, +/area/centcom/central_command_areas/adminroom) "exk" = ( /obj/structure/chair/office/light{ dir = 1 @@ -21732,6 +21769,25 @@ /obj/item/clothing/under/costume/gondola, /turf/open/floor/eighties/red, /area/centcom/central_command_areas/admin) +"gUv" = ( +/obj/effect/spawner/random/trash/bacteria, +/obj/effect/spawner/random/trash/bacteria, +/obj/effect/spawner/random/trash/graffiti, +/obj/effect/spawner/random/trash/garbage, +/obj/effect/spawner/random/trash/cigbutt, +/obj/effect/spawner/random/trash/mess, +/turf/open/floor/plating/rust, +/area/centcom/central_command_areas/adminroom) +"gWc" = ( +/obj/effect/turf_decal/caution/red{ + pixel_y = -15 + }, +/obj/effect/turf_decal/caution/red, +/obj/effect/turf_decal/caution/red{ + pixel_y = -8 + }, +/turf/open/floor/iron/dark/smooth_large, +/area/centcom/central_command_areas/admin) "gXp" = ( /obj/effect/turf_decal/siding/wood{ dir = 8 @@ -22224,6 +22280,13 @@ dir = 8 }, /area/centcom/central_command_areas/adminroom) +"hPF" = ( +/obj/effect/turf_decal/siding/white{ + dir = 9 + }, +/obj/effect/spawner/random/trash/caution_sign, +/turf/open/floor/grass, +/area/centcom/central_command_areas/admin) "hQH" = ( /obj/effect/turf_decal/plaque{ icon_state = "L13" @@ -23029,6 +23092,13 @@ /obj/structure/fake_stairs/wood/directional/north, /turf/open/misc/dirt/station, /area/centcom/central_command_areas/retirement_yard) +"jUo" = ( +/obj/machinery/computer/camera_advanced{ + dir = 8 + }, +/obj/effect/spawner/random/trash/cigbutt, +/turf/open/floor/plating/rust, +/area/centcom/central_command_areas/adminroom) "jUG" = ( /mob/living/basic/xenofauna/meatbeast, /turf/open/floor/material/meat, @@ -23351,6 +23421,10 @@ /obj/machinery/light/directional/north, /turf/open/water/arena, /area/centcom/central_command_areas/admin) +"kSK" = ( +/obj/structure/mineral_door/wood, +/turf/open/floor/plating/rust, +/area/centcom/central_command_areas/adminroom) "kSU" = ( /obj/structure/mineral_door/wood{ color = "543e27"; @@ -23773,6 +23847,12 @@ }, /turf/open/floor/wood/large, /area/centcom/central_command_areas/adminroom) +"msE" = ( +/obj/effect/spawner/random/trash/bacteria, +/obj/effect/spawner/random/trash/garbage, +/obj/effect/spawner/random/trash/garbage, +/turf/open/floor/plating/rust, +/area/centcom/central_command_areas/adminroom) "mvd" = ( /obj/effect/decal/cleanable/blood/gibs/limb{ dir = 8; @@ -24164,6 +24244,12 @@ /obj/machinery/scanner_gate, /turf/open/floor/sandy_dirt, /area/centcom/central_command_areas/admin) +"nGN" = ( +/obj/effect/spawner/random/trash/bacteria, +/obj/effect/spawner/random/trash/garbage, +/obj/effect/spawner/random/trash/mess, +/turf/open/floor/iron/vaporwave, +/area/centcom/central_command_areas/adminroom) "nHl" = ( /obj/structure/flora/grass/jungle/b/style_2, /turf/open/misc/dirt/station, @@ -24473,6 +24559,10 @@ }, /turf/open/floor/iron/dark, /area/centcom/central_command_areas/admin) +"oBb" = ( +/obj/structure/barricade/wooden/crude, +/turf/closed/indestructible/fakeglass, +/area/centcom/central_command_areas/adminroom) "oBm" = ( /obj/effect/turf_decal/trimline/dark_blue/line{ dir = 4 @@ -24759,6 +24849,13 @@ /obj/structure/mop_bucket, /turf/open/floor/iron/dark/textured_large, /area/cruiser_dock) +"ptP" = ( +/obj/machinery/computer/communications/syndicate{ + dir = 8 + }, +/obj/effect/spawner/random/trash/cigbutt, +/turf/open/floor/plating/rust, +/area/centcom/central_command_areas/adminroom) "pvq" = ( /obj/machinery/biomass_recycler, /obj/item/stack/biomass, @@ -25342,6 +25439,13 @@ }, /turf/open/misc/sandy_dirt, /area/centcom/central_command_areas/admin) +"qNR" = ( +/obj/structure/chair/comfy/teal{ + dir = 4 + }, +/obj/effect/spawner/random/trash/cigbutt, +/turf/open/floor/plating/rust, +/area/centcom/central_command_areas/adminroom) "qOJ" = ( /obj/effect/turf_decal/trimline/yellow/filled/line{ dir = 1 @@ -25972,6 +26076,10 @@ }, /turf/open/floor/carpet/neon/simple/green/nodots, /area/centcom/central_command_areas/admin) +"sHS" = ( +/obj/structure/bed/maint, +/turf/open/floor/iron/vaporwave, +/area/centcom/central_command_areas/adminroom) "sIk" = ( /obj/machinery/light/floor/has_bulb, /obj/structure/window/reinforced/spawner/directional/west{ @@ -26029,6 +26137,12 @@ }, /turf/open/floor/carpet/orange, /area/centcom/central_command_areas/admin) +"sRa" = ( +/obj/effect/spawner/random/trash/garbage, +/obj/effect/spawner/random/trash/garbage, +/obj/effect/spawner/random/trash/mess, +/turf/open/floor/iron/vaporwave, +/area/centcom/central_command_areas/adminroom) "sRv" = ( /obj/effect/turf_decal/box/corners{ dir = 1 @@ -26036,6 +26150,11 @@ /obj/structure/shipping_container/vitezstvi, /turf/open/floor/iron/dark/textured_large, /area/cruiser_dock) +"sSL" = ( +/obj/structure/barricade/wooden/crude, +/obj/effect/spawner/random/trash/cigbutt, +/turf/closed/indestructible/fakeglass, +/area/centcom/central_command_areas/adminroom) "sTV" = ( /obj/effect/turf_decal/tile/purple/half/contrasted{ dir = 4 @@ -26688,6 +26807,14 @@ }, /turf/open/floor/glass/plasma, /area/centcom/central_command_areas/adminroom) +"uFf" = ( +/obj/effect/spawner/random/trash/bacteria, +/obj/effect/spawner/random/trash/garbage, +/obj/effect/spawner/random/trash/garbage, +/obj/effect/spawner/random/trash/mess, +/obj/effect/spawner/random/trash/mess, +/turf/open/floor/plating/rust, +/area/centcom/central_command_areas/adminroom) "uGL" = ( /obj/structure/reagent_dispensers/water_cooler, /obj/effect/turf_decal/bot_white, @@ -26696,6 +26823,13 @@ }, /turf/open/floor/iron/dark/textured_large, /area/cruiser_dock) +"uHB" = ( +/obj/structure/table/wood, +/obj/machinery/chem_dispenser/drinks/beer/fullupgrade{ + dir = 4 + }, +/turf/open/floor/plating/rust, +/area/centcom/central_command_areas/adminroom) "uIG" = ( /obj/machinery/door/airlock/centcom{ name = "NT Helpdesk" @@ -26740,6 +26874,12 @@ /obj/effect/mapping_helpers/airlock/access/any/admin/captain, /turf/open/floor/iron/dark/smooth_large, /area/centcom/central_command_areas/admin) +"uPO" = ( +/obj/effect/spawner/random/trash/garbage, +/obj/effect/spawner/random/trash/cigbutt, +/obj/effect/spawner/random/trash/mess, +/turf/open/floor/iron/vaporwave, +/area/centcom/central_command_areas/adminroom) "uPS" = ( /obj/effect/turf_decal/siding/dark_green{ dir = 8 @@ -26751,6 +26891,12 @@ /obj/machinery/light/dim/directional/south, /turf/open/floor/wood/tile, /area/centcom/central_command_areas/admin) +"uRb" = ( +/obj/effect/spawner/random/trash/bacteria, +/obj/effect/spawner/random/trash/graffiti, +/obj/effect/spawner/random/trash/cigbutt, +/turf/open/floor/plating/rust, +/area/centcom/central_command_areas/adminroom) "uSs" = ( /obj/structure/statue/sandstone/venus{ dir = 1; @@ -27079,6 +27225,16 @@ "vFm" = ( /turf/open/floor/mineral/titanium/purple, /area/centcom/central_command_areas/adminroom) +"vFv" = ( +/obj/structure/closet/secure_closet/freezer/fridge, +/obj/item/food/meat/slab/human, +/obj/item/food/meat/slab/human, +/obj/item/food/meat/slab/human, +/obj/item/food/meat/slab/human, +/obj/item/food/meat/slab/human, +/obj/effect/spawner/random/trash/graffiti, +/turf/open/floor/iron/vaporwave, +/area/centcom/central_command_areas/adminroom) "vFK" = ( /obj/structure/window/reinforced/spawner/directional/south, /obj/machinery/chem_heater/debug, @@ -27318,11 +27474,23 @@ }, /turf/open/floor/iron/dark/herringbone, /area/centcom/central_command_areas/evacuation) +"wdA" = ( +/obj/effect/spawner/random/trash/bacteria, +/obj/effect/spawner/random/trash/garbage, +/obj/effect/spawner/random/trash/cigbutt, +/obj/effect/spawner/random/trash/mess, +/turf/open/floor/plating/rust, +/area/centcom/central_command_areas/adminroom) "wel" = ( /obj/effect/turf_decal/stripes/line, /obj/structure/flora/bush/pale/style_3, /turf/open/misc/dirt/station, /area/centcom/central_command_areas/admin) +"wfx" = ( +/obj/structure/barricade/wooden/crude, +/obj/structure/curtain/cloth, +/turf/closed/indestructible/fakeglass, +/area/centcom/central_command_areas/adminroom) "wge" = ( /obj/effect/turf_decal/siding/wood{ dir = 4 @@ -27660,6 +27828,11 @@ dir = 8 }, /area/cruiser_dock) +"wTG" = ( +/obj/effect/spawner/random/trash/bacteria, +/obj/effect/spawner/random/trash/garbage, +/turf/open/floor/iron/vaporwave, +/area/centcom/central_command_areas/adminroom) "wTZ" = ( /obj/machinery/vending/coffee, /obj/effect/turf_decal/bot_white, @@ -27992,6 +28165,14 @@ }, /turf/closed/indestructible/wood, /area/centcom/central_command_areas/admin) +"xQP" = ( +/obj/effect/spawner/random/trash/bacteria, +/obj/effect/spawner/random/trash/garbage, +/obj/effect/spawner/random/trash/garbage, +/obj/effect/spawner/random/trash/cigbutt, +/obj/effect/spawner/random/trash/mess, +/turf/open/floor/plating/rust, +/area/centcom/central_command_areas/adminroom) "xRr" = ( /obj/structure/chair/office/light{ dir = 1 @@ -53192,17 +53373,17 @@ aaa aaa aaa aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa +aOn +aOn +aOn +aOn +aOn +kpH +kpH +kpH +kpH +kpH +kpH aaa aaa aaa @@ -53449,17 +53630,17 @@ aaa aaa aaa aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa +aOn +yhF +mUv +yhF +bYp +wfx +exj +uHB +vFv +cYr +kpH aaa aaa aaa @@ -53706,17 +53887,17 @@ aaa aaa aaa aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa +aOn +yhF +mUv +yhF +bYc +wfx +msE +uFf +xQP +wTG +kpH aaa aaa aaa @@ -53963,17 +54144,17 @@ aaa aaa aaa aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa +aOn +yhF +mUv +yhF +gWc +kSK +nGN +uRb +sRa +bhS +kpH aaa aaa aaa @@ -54220,17 +54401,17 @@ aaa aaa aaa aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa +aOn +yhF +mUv +yhF +hPF +wfx +bxX +qNR +gUv +wdA +kpH aaa aaa aaa @@ -54477,17 +54658,17 @@ aaa aaa aaa aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa +aOn +yhF +mUv +yhF +bYp +wfx +uPO +ptP +jUo +sHS +kpH aaa aaa aaa @@ -54735,14 +54916,14 @@ kpH kpH kpH aOn +yhF +mUv +yhF aOn -aOn -aOn -aOn -kpH -kpH kpH +sSL kpH +oBb kpH kpH aaa From 7d6a8a18db7adca51215c887bb822acf53d15b13 Mon Sep 17 00:00:00 2001 From: Gboster-0 <82319946+Gboster-0@users.noreply.github.com> Date: Thu, 19 Dec 2024 22:15:13 +0100 Subject: [PATCH 12/81] the pin stuffs (#4602) --- code/datums/quirks/neutral_quirks/pride_pin.dm | 1 + code/modules/clothing/under/accessories/badges.dm | 12 ++++++++++++ monkestation/code/modules/blueshift/items/badges.dm | 2 +- 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/code/datums/quirks/neutral_quirks/pride_pin.dm b/code/datums/quirks/neutral_quirks/pride_pin.dm index 0bdb26260109..64fbe43c55ea 100644 --- a/code/datums/quirks/neutral_quirks/pride_pin.dm +++ b/code/datums/quirks/neutral_quirks/pride_pin.dm @@ -18,6 +18,7 @@ pin.current_skin = pride_choice pin.icon_state = pride_reskin + pin.post_reskin() //MONKESTATION EDIT START var/mob/living/carbon/human/H = quirk_holder if (istype(H)) diff --git a/code/modules/clothing/under/accessories/badges.dm b/code/modules/clothing/under/accessories/badges.dm index 69c426bf476e..af3f0c566483 100644 --- a/code/modules/clothing/under/accessories/badges.dm +++ b/code/modules/clothing/under/accessories/badges.dm @@ -195,6 +195,18 @@ GLOBAL_LIST_INIT(pride_pin_reskins, list( . = ..() unique_reskin = GLOB.pride_pin_reskins +/obj/item/clothing/accessory/pride/reskin_obj(mob/M) + . = ..() + post_reskin(M) + +/obj/item/clothing/accessory/pride/post_reskin(mob/our_mob) + for(var/pride_name as anything in GLOB.pride_pin_reskins) + if(GLOB.pride_pin_reskins[pride_name] == icon_state) + name = "[lowertext(pride_name)] pin" + return + + name = initial(name) // If we somehow fail to find our pride in the global list, just make us generic + ///Awarded for being dutiful and extinguishing the debt from the "Indebted" quirk. /obj/item/clothing/accessory/debt_payer_pin name = "debt payer pin" diff --git a/monkestation/code/modules/blueshift/items/badges.dm b/monkestation/code/modules/blueshift/items/badges.dm index 940b1bb8a070..2e7b1b53dd03 100644 --- a/monkestation/code/modules/blueshift/items/badges.dm +++ b/monkestation/code/modules/blueshift/items/badges.dm @@ -186,7 +186,7 @@ GLOBAL_LIST_INIT(pride_pin_reskins, list( "Transgender Pride" = "pride_trans", "Intersex Pride" = "pride_intersex", "Lesbian Pride" = "pride_lesbian", - "Man-Loving-Man / Gay Pride" = "pride_mlm", + "Gay Pride" = "pride_mlm", "Genderfluid Pride" = "pride_genderfluid", "Genderqueer Pride" = "pride_genderqueer", "Aromantic Pride" = "pride_aromantic", From 8e8ece451ac302b47b4ee63a051eda98cd3f6714 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 19 Dec 2024 21:19:51 +0000 Subject: [PATCH 13/81] Automatic changelog for PR #4621 [ci skip] --- html/changelogs/AutoChangeLog-pr-4621.yml | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-4621.yml diff --git a/html/changelogs/AutoChangeLog-pr-4621.yml b/html/changelogs/AutoChangeLog-pr-4621.yml new file mode 100644 index 000000000000..0cbc1c216270 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-4621.yml @@ -0,0 +1,6 @@ +author: "Loiosh42" +delete-after: True +changes: + - balance: "Tweaks AP shotgun shells, and gives them pierce" + - balance: "Nerfs the Bobr" + - balance: "Gives the Wylom AM rifle pierce" \ No newline at end of file From bc98bf65601493ff3b0b6e14352754db6b5cf7f7 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 19 Dec 2024 21:21:13 +0000 Subject: [PATCH 14/81] Automatic changelog for PR #4602 [ci skip] --- html/changelogs/AutoChangeLog-pr-4602.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-4602.yml diff --git a/html/changelogs/AutoChangeLog-pr-4602.yml b/html/changelogs/AutoChangeLog-pr-4602.yml new file mode 100644 index 000000000000..25f412c850c2 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-4602.yml @@ -0,0 +1,4 @@ +author: "Gboster-0" +delete-after: True +changes: + - qol: "Made pride pins display their pride in the name, like \"transexual pride pin\" instead of \"pride pin\"" \ No newline at end of file From cee18247d58baf438d1c587f88e5347d956b519c Mon Sep 17 00:00:00 2001 From: Lucy Date: Thu, 19 Dec 2024 16:32:38 -0500 Subject: [PATCH 15/81] Makes it more obvious in the lobby when there's a job overflow (#4589) * Makes it more obvious in the lobby when there's a job overflow * fix a whoopsie there --- code/__HELPERS/~monkestation-helpers/icons.dm | 44 ++++++++++ code/_onclick/hud/new_player.dm | 77 ++++++++++++++++++ code/modules/asset_cache/asset_list.dm | 6 +- icons/hud/lobby/overflow.dmi | Bin 0 -> 958 bytes .../datums/station_traits/negative_traits.dm | 44 +++++++++- .../modules/asset_cache/assets/job_icons.dm | 21 +++++ .../modules/client/preferences/overflow.dm | 5 ++ tgstation.dme | 2 + .../monkestation/overflow.tsx | 9 ++ 9 files changed, 205 insertions(+), 3 deletions(-) create mode 100644 icons/hud/lobby/overflow.dmi create mode 100644 monkestation/code/modules/asset_cache/assets/job_icons.dm create mode 100644 monkestation/code/modules/client/preferences/overflow.dm create mode 100644 tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/game_preferences/monkestation/overflow.tsx diff --git a/code/__HELPERS/~monkestation-helpers/icons.dm b/code/__HELPERS/~monkestation-helpers/icons.dm index 73b6900edc93..ec8d795bdf4b 100644 --- a/code/__HELPERS/~monkestation-helpers/icons.dm +++ b/code/__HELPERS/~monkestation-helpers/icons.dm @@ -19,3 +19,47 @@ fdel(TMP_UPSCALE_PATH) #undef TMP_UPSCALE_PATH + +/// Returns the (isolated) security HUD icon for the given job. +/proc/get_job_hud_icon(datum/job/job, include_unknown = FALSE) as /icon + RETURN_TYPE(/icon) + var/static/list/icon_cache + var/static/list/unknown_huds + if(isnull(job)) + return + else if(!is_job(job)) + if(ispath(job, /datum/job)) + job = locate(job) in SSjob.all_occupations + else if(istext(job)) + job_loop: + for(var/datum/job/job_instance as anything in SSjob.all_occupations) + if(cmptext(job_instance.title, job) || cmptext(job_instance.config_tag, job)) + job = job_instance + break + for(var/alt_title in job_instance.alt_titles) + if(cmptext(alt_title, job)) + job = job_instance + break job_loop + if(!job) + return null + + // populate the cache if it hasn't been already + if(isnull(icon_cache)) + icon_cache = list() + unknown_huds = list() + for(var/datum/job/job_instance as anything in SSjob.all_occupations) + var/datum/outfit/job_outfit = job_instance.outfit + if(!job_outfit || !job_outfit::id_trim) + continue + var/datum/id_trim/job_trim = job_outfit::id_trim + var/icon_state = job_trim::sechud_icon_state + if(!icon_state || icon_state == SECHUD_UNKNOWN) + icon_state = "hud_noid" + unknown_huds[job_instance.type] = TRUE + var/icon/sechud_icon = icon('icons/mob/huds/hud.dmi', icon_state) + sechud_icon.Crop(1, 17, 8, 24) + icon_cache[job_instance.type] = sechud_icon + + var/job_type = job.type + if(icon_cache[job_type] && (include_unknown || !unknown_huds[job_type])) + return icon(icon_cache[job_type]) diff --git a/code/_onclick/hud/new_player.dm b/code/_onclick/hud/new_player.dm index d5bee6641c3d..b50f4184c73f 100644 --- a/code/_onclick/hud/new_player.dm +++ b/code/_onclick/hud/new_player.dm @@ -160,6 +160,10 @@ if(!.) return var/mob/dead/new_player/new_player = hud.mymob + var/datum/station_trait/overflow_job_bureaucracy/overflow = locate() in SSstation.station_traits + if(!ready && overflow?.picked_job && new_player.client?.prefs?.read_preference(/datum/preference/toggle/verify_overflow)) + if(tgui_alert(new_player, "The current overflow role is [overflow.picked_job.title], are you sure you would like to ready up?", "Overflow Notice", list("Yes", "No")) != "Yes") + return ready = !ready if(ready) new_player.ready = PLAYER_READY_TO_PLAY @@ -574,3 +578,76 @@ . = ..() if(.) SEND_SOUND(usr, 'monkestation/sound/misc/menumonkey.ogg') + +/atom/movable/screen/lobby/overflow_alert + screen_loc = "TOP:-48,CENTER-2.7" + icon = 'icons/hud/lobby/overflow.dmi' + icon_state = "" + base_icon_state = "overflow" + var/datum/job/overflow_job + var/static/disabled = FALSE + var/static/mutable_appearance/job_overlay + +/atom/movable/screen/lobby/overflow_alert/Initialize(mapload) + . = ..() + if(SSticker.current_state == GAME_STATE_STARTUP) + RegisterSignal(SSticker, COMSIG_TICKER_ENTER_PREGAME, PROC_REF(initial_setup)) + else + generate_and_set_icon() + update_appearance(UPDATE_ICON) + +/atom/movable/screen/lobby/overflow_alert/Destroy() + overflow_job = null + UnregisterSignal(SSticker, COMSIG_TICKER_ENTER_PREGAME) + return ..() + +/atom/movable/screen/lobby/overflow_alert/update_icon_state() + if(!disabled && !isnull(job_overlay)) + icon_state = base_icon_state + else + icon_state = "" + return ..() + +/atom/movable/screen/lobby/overflow_alert/update_overlays() + . = ..() + if(!disabled && job_overlay) + . += job_overlay + +/atom/movable/screen/lobby/overflow_alert/MouseEntered(location,control,params) + . = ..() + if(!disabled && overflow_job && !QDELETED(src)) + openToolTip(usr, src, params, title = "Job Overflow", content = "The overflow role this round is [html_encode(overflow_job.title)]!") + +/atom/movable/screen/lobby/overflow_alert/MouseExited() + closeToolTip(usr) + +/atom/movable/screen/lobby/overflow_alert/proc/initial_setup(datum/source) + SIGNAL_HANDLER + UnregisterSignal(SSstation, COMSIG_TICKER_ENTER_PREGAME) + var/datum/station_trait/overflow_job_bureaucracy/overflow = locate() in SSstation.station_traits + overflow_job = overflow?.picked_job + if(overflow_job) + generate_and_set_icon() + else + disabled = TRUE + update_appearance(UPDATE_ICON) + +/atom/movable/screen/lobby/overflow_alert/proc/generate_and_set_icon() + if(disabled || SSticker.current_state == GAME_STATE_STARTUP || !isnull(job_overlay)) + return + var/datum/station_trait/overflow_job_bureaucracy/overflow = locate() in SSstation.station_traits + overflow_job = overflow?.picked_job + if(!overflow_job) + disabled = TRUE + return + var/icon/job_icon = get_job_hud_icon(overflow_job, include_unknown = TRUE) + if(!job_icon) + return + var/icon/resized_icon = resize_icon(job_icon, 16, 16) + if(!resized_icon) + stack_trace("Failed to upscale icon for [overflow_job], upscaling using BYOND!") + job_icon.Scale(16, 16) + resized_icon = job_icon + job_overlay = mutable_appearance(resized_icon) + job_overlay.pixel_x = 8 + job_overlay.pixel_y = 18 diff --git a/code/modules/asset_cache/asset_list.dm b/code/modules/asset_cache/asset_list.dm index c705f0beef70..a4501210d242 100644 --- a/code/modules/asset_cache/asset_list.dm +++ b/code/modules/asset_cache/asset_list.dm @@ -8,10 +8,12 @@ GLOBAL_LIST_EMPTY(asset_datums) //get an assetdatum or make a new one //does NOT ensure it's filled, if you want that use get_asset_datum() -/proc/load_asset_datum(type) +/proc/load_asset_datum(type) as /datum/asset + RETURN_TYPE(/datum/asset) return GLOB.asset_datums[type] || new type() -/proc/get_asset_datum(type) +/proc/get_asset_datum(type) as /datum/asset + RETURN_TYPE(/datum/asset) var/datum/asset/loaded_asset = GLOB.asset_datums[type] || new type() return loaded_asset.ensure_ready() diff --git a/icons/hud/lobby/overflow.dmi b/icons/hud/lobby/overflow.dmi new file mode 100644 index 0000000000000000000000000000000000000000..b7391193f0d23494247bf2ea1bb78d245dcc2b72 GIT binary patch literal 958 zcmV;v13~V=-0C=1Q!A%N-Fc1dN^~@-=RV^@o`7?`}C z?gzpAn7PHW8<@@VA0xFMv{r+io$0A7*h(e*o8d~(=-eZ`d!=oM9I38cO zD8==|-y%s;!&sQ{;Hq%h2o$nuym|ee$^7lRSE$~eXpC*nVN{QkvW4{1UkHU3Yr>2N z0A%Jw?x``R1<<-GT*6lOYyIK<@*gmD_J2^8(b0)oDVLK7MjXWRA6Z;-gT5R9IO_hbxoYa<3~&I`M8I0mmv2;<>Tz0aXGGAKQ;Q|)=zjpIutJY3ijHUf zA3!Qh_qdwqcrAb3%hAcb%}htGDmt5eKCbqylgrU=`?p<>+nmF)pz3jw>3W(xejuV> zfBz>%07*qoM6N<$f&-$&JOBUy literal 0 HcmV?d00001 diff --git a/monkestation/code/datums/station_traits/negative_traits.dm b/monkestation/code/datums/station_traits/negative_traits.dm index 0e31a8ba8144..b760911c00a8 100644 --- a/monkestation/code/datums/station_traits/negative_traits.dm +++ b/monkestation/code/datums/station_traits/negative_traits.dm @@ -6,13 +6,55 @@ report_message = "The Clown Planet has discovered a weakness in the ID scanners of specific airlocks." trait_to_give = STATION_TRAIT_CLOWN_BRIDGE +/datum/station_trait/overflow_job_bureaucracy + /// Has the initial notification been sent to all players yet? + var/notified = FALSE + /// Current type of the picked job. + var/datum/job/picked_job + /// The icon tag for the job, used to display the job icon in the pregame/login notification, + var/icon_tag + +/datum/station_trait/overflow_job_bureaucracy/New() + . = ..() + RegisterSignal(SSdcs, COMSIG_GLOB_CLIENT_CONNECT, PROC_REF(notify_on_login)) + RegisterSignal(SSticker, COMSIG_TICKER_ENTER_PREGAME, PROC_REF(notify_all_players)) + +/// Picks and sets the overflow role. /datum/station_trait/overflow_job_bureaucracy/proc/set_overflow_job_override(datum/source) SIGNAL_HANDLER - var/datum/job/picked_job var/list/possible_jobs = SSjob.joinable_occupations.Copy() + possible_jobs -= SSjob.GetJobType(SSjob.overflow_role) while(length(possible_jobs) && !picked_job?.allow_overflow) picked_job = pick_n_take(possible_jobs) if(!picked_job) CRASH("Failed to find valid job to pick for overflow!") chosen_job_name = lowertext(picked_job.title) // like Chief Engineers vs like chief engineers SSjob.set_overflow_role(picked_job.type) + var/datum/asset/spritesheet/sheet = get_asset_datum(/datum/asset/spritesheet/job_icons) + icon_tag = sheet.icon_tag(sanitize_css_class_name(lowertext(picked_job.config_tag || picked_job.title))) + if(icon_tag) + icon_tag = "[icon_tag] " // vertically align and add a space to the end + +/// Signal handler to notify all connected clients of the overflow role, ran after all initializations are complete. +/datum/station_trait/overflow_job_bureaucracy/proc/notify_all_players(datum/source) + SIGNAL_HANDLER + notified = TRUE + for(var/mob/dead/new_player/lobby_user in GLOB.new_player_list) + INVOKE_ASYNC(src, PROC_REF(notify_client), lobby_user) +l +/// Signal handler to notify newly connecting clients of the overflow role. +/datum/station_trait/overflow_job_bureaucracy/proc/notify_on_login(datum/source, client/client) + SIGNAL_HANDLER + INVOKE_ASYNC(src, PROC_REF(notify_client), client) + +/// Notifies a single client of the current overflow role. +/datum/station_trait/overflow_job_bureaucracy/proc/notify_client(target) + if(!picked_job || !notified) + return + var/client/client = get_player_client(target) + client?.tgui_panel?.window?.send_asset(get_asset_datum(/datum/asset/spritesheet/job_icons)) + to_chat( + target = client, + html = examine_block(span_big(span_info("Current overflow role is [icon_tag][span_name(html_encode(picked_job.title))], make sure to check your job preferences!"))), + type = MESSAGE_TYPE_INFO, + ) diff --git a/monkestation/code/modules/asset_cache/assets/job_icons.dm b/monkestation/code/modules/asset_cache/assets/job_icons.dm new file mode 100644 index 000000000000..a4d794f95ab5 --- /dev/null +++ b/monkestation/code/modules/asset_cache/assets/job_icons.dm @@ -0,0 +1,21 @@ +/datum/asset/spritesheet/job_icons + name = "job_icons" + /// The width and height to scale the job icons to. + var/icon_size = 24 + +/datum/asset/spritesheet/job_icons/create_spritesheets() + var/list/id_list = list() + for(var/datum/job/job as anything in SSjob.all_occupations) + var/id = sanitize_css_class_name(lowertext(job.config_tag || job.title)) + if(id_list[id]) + continue + var/icon/job_icon = get_job_hud_icon(job) + if(!job_icon) + continue + var/icon/resized_icon = resize_icon(job_icon, icon_size, icon_size) + if(!resized_icon) + stack_trace("Failed to upscale icon for [job.type], upscaling using BYOND!") + job_icon.Scale(icon_size, icon_size) + resized_icon = job_icon + Insert(id, resized_icon) + id_list[id] = TRUE diff --git a/monkestation/code/modules/client/preferences/overflow.dm b/monkestation/code/modules/client/preferences/overflow.dm new file mode 100644 index 000000000000..742f45c6133d --- /dev/null +++ b/monkestation/code/modules/client/preferences/overflow.dm @@ -0,0 +1,5 @@ +/datum/preference/toggle/verify_overflow + category = PREFERENCE_CATEGORY_GAME_PREFERENCES + default_value = FALSE + savefile_key = "verify_overflow" + savefile_identifier = PREFERENCE_PLAYER diff --git a/tgstation.dme b/tgstation.dme index efde1e48e361..10b75c35be7d 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -6541,6 +6541,7 @@ #include "monkestation\code\modules\assembly\flash.dm" #include "monkestation\code\modules\asset_cache\assets\botanical_lexicon.dm" #include "monkestation\code\modules\asset_cache\assets\chicken_book.dm" +#include "monkestation\code\modules\asset_cache\assets\job_icons.dm" #include "monkestation\code\modules\asset_cache\assets\loadout_store.dm" #include "monkestation\code\modules\atmospherics\machinery\air_alarm\air_alarm_ac.dm" #include "monkestation\code\modules\balloon_alert\balloon_alert.dm" @@ -7063,6 +7064,7 @@ #include "monkestation\code\modules\client\preferences\inventory.dm" #include "monkestation\code\modules\client\preferences\loadout_override_preference.dm" #include "monkestation\code\modules\client\preferences\multiline_preferences.dm" +#include "monkestation\code\modules\client\preferences\overflow.dm" #include "monkestation\code\modules\client\preferences\prude.dm" #include "monkestation\code\modules\client\preferences\runechat.dm" #include "monkestation\code\modules\client\preferences\show_roundend_credits.dm" diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/game_preferences/monkestation/overflow.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/game_preferences/monkestation/overflow.tsx new file mode 100644 index 000000000000..fe9a3beebdaf --- /dev/null +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/game_preferences/monkestation/overflow.tsx @@ -0,0 +1,9 @@ +import { CheckboxInput, FeatureToggle } from '../../base'; + +export const verify_overflow: FeatureToggle = { + name: 'Confirm Ready During Job Overflow', + category: 'GAMEPLAY', + description: + 'When enabled, readying up will bring up a confirmation prompt if the current round has a different overflow job.', + component: CheckboxInput, +}; From 91bcb96ab9289cae9cf336827152d5ec1bc865b0 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 19 Dec 2024 21:32:58 +0000 Subject: [PATCH 16/81] Automatic changelog for PR #4589 [ci skip] --- html/changelogs/AutoChangeLog-pr-4589.yml | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-4589.yml diff --git a/html/changelogs/AutoChangeLog-pr-4589.yml b/html/changelogs/AutoChangeLog-pr-4589.yml new file mode 100644 index 000000000000..3619e5ed33e9 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-4589.yml @@ -0,0 +1,6 @@ +author: "Absolucy" +delete-after: True +changes: + - qol: "There is now a chat notice and a visual indicator in the lobby for when there's a non-standard overflow." + - qol: "Added a preference (disabled by default) to confirm readying up when there's a non-standard overflow." + - bugfix: "Fixed a bug where the overflow station trait could roll assistants, which just did... nothing." \ No newline at end of file From 1589ff5d8c38cb6feeb096d1f7746388004e011a Mon Sep 17 00:00:00 2001 From: Ghosti <83688318+Gw0sty@users.noreply.github.com> Date: Thu, 19 Dec 2024 17:05:04 -0600 Subject: [PATCH 17/81] Blob infestation (#4603) * Blob gaming * Hud stuff + label * Thanks @Absolucy --- code/game/data_huds.dm | 4 ++- code/modules/events/ghost_role/blob.dm | 4 +-- .../modules/antagonist/blob/blob_antag.dm | 4 +++ .../converted_events/event_overrides.dm | 4 +++ .../converted_events/solo/blob_infection.dm | 30 +++++++++++++++++++ tgstation.dme | 2 ++ 6 files changed, 45 insertions(+), 3 deletions(-) create mode 100644 monkestation/code/modules/antagonist/blob/blob_antag.dm create mode 100644 monkestation/code/modules/storytellers/converted_events/solo/blob_infection.dm diff --git a/code/game/data_huds.dm b/code/game/data_huds.dm index 3f2dde1cc0ab..e9c83f11ad6a 100644 --- a/code/game/data_huds.dm +++ b/code/game/data_huds.dm @@ -225,7 +225,9 @@ Medical HUD! Basic mode needs suit sensors on. var/virus_threat = check_virus() holder.pixel_y = get_cached_height() - world.icon_size - if(HAS_TRAIT(src, TRAIT_XENO_HOST)) + if(HAS_TRAIT(src, TRAIT_BLOB_ALLY)) //Monkestation edit: In the edge where case a blob host has a xeno in them. I think the fact they are a blob host is more important. + holder.icon_state = "hudill5" + else if(HAS_TRAIT(src, TRAIT_XENO_HOST)) holder.icon_state = "hudxeno" else if(stat == DEAD || (HAS_TRAIT(src, TRAIT_FAKEDEATH))) if((key || get_ghost(FALSE, TRUE)) && (can_defib() & DEFIB_REVIVABLE_STATES)) diff --git a/code/modules/events/ghost_role/blob.dm b/code/modules/events/ghost_role/blob.dm index 99836ba2b585..89284678f64d 100644 --- a/code/modules/events/ghost_role/blob.dm +++ b/code/modules/events/ghost_role/blob.dm @@ -1,10 +1,10 @@ /datum/round_event_control/blob name = "Blob" typepath = /datum/round_event/ghost_role/blob - weight = 5 //monkie edit: 10 to 5 + weight = 4 //monkie edit: 10 to 4 max_occurrences = 1 min_players = 35 //monkie edit: 20 to 35 - earliest_start = 80 MINUTES //monkie edit: 20 to 90 + earliest_start = 80 MINUTES //monkie edit: 20 to 80 //dynamic_should_hijack = TRUE category = EVENT_CATEGORY_ENTITIES description = "Spawns a new blob overmind." diff --git a/monkestation/code/modules/antagonist/blob/blob_antag.dm b/monkestation/code/modules/antagonist/blob/blob_antag.dm new file mode 100644 index 000000000000..1265d4740128 --- /dev/null +++ b/monkestation/code/modules/antagonist/blob/blob_antag.dm @@ -0,0 +1,4 @@ +/datum/antagonist/blob/infection/apply_innate_effects(mob/mob_override) + . = ..() + var/mob/target = mob_override || owner.current + ADD_TRAIT(target, TRAIT_BLOB_ALLY, type) diff --git a/monkestation/code/modules/storytellers/converted_events/event_overrides.dm b/monkestation/code/modules/storytellers/converted_events/event_overrides.dm index 918ddfad1280..f3c81d2b60f0 100644 --- a/monkestation/code/modules/storytellers/converted_events/event_overrides.dm +++ b/monkestation/code/modules/storytellers/converted_events/event_overrides.dm @@ -22,6 +22,10 @@ tags = list(TAG_DESTRUCTIVE, TAG_COMBAT, TAG_EXTERNAL, TAG_ALIEN) checks_antag_cap = TRUE +/datum/round_event_control/antagonist/solo/blob_infection + tags = list(TAG_DESTRUCTIVE, TAG_COMBAT, TAG_EXTERNAL, TAG_ALIEN) + checks_antag_cap = TRUE + /datum/round_event_control/brain_trauma track = EVENT_TRACK_MUNDANE tags = list(TAG_TARGETED, TAG_MAGICAL) //im putting magical on this because I think this can give the magic brain traumas diff --git a/monkestation/code/modules/storytellers/converted_events/solo/blob_infection.dm b/monkestation/code/modules/storytellers/converted_events/solo/blob_infection.dm new file mode 100644 index 000000000000..21f44ba27027 --- /dev/null +++ b/monkestation/code/modules/storytellers/converted_events/solo/blob_infection.dm @@ -0,0 +1,30 @@ +/datum/round_event_control/antagonist/solo/blob_infection + name = "Blob Infection" + weight = 4 + antag_flag = ROLE_BLOB_INFECTION + antag_datum = /datum/antagonist/blob/infection + min_players = 35 + maximum_antags = 1 + max_occurrences = 1 + earliest_start = 80 MINUTES + protected_roles = list( + JOB_CAPTAIN, + JOB_NANOTRASEN_REPRESENTATIVE, + JOB_BLUESHIELD, + JOB_HEAD_OF_PERSONNEL, + JOB_CHIEF_ENGINEER, + JOB_CHIEF_MEDICAL_OFFICER, + JOB_RESEARCH_DIRECTOR, + JOB_DETECTIVE, + JOB_HEAD_OF_SECURITY, + JOB_PRISONER, + JOB_SECURITY_OFFICER, + JOB_WARDEN, + JOB_SECURITY_ASSISTANT, + JOB_BRIG_PHYSICIAN, + ) + restricted_roles = list( + JOB_AI, + JOB_CYBORG, + ) + description = "Infects a crewmember with the blob overmind." diff --git a/tgstation.dme b/tgstation.dme index 10b75c35be7d..f6fef1350f0b 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -6192,6 +6192,7 @@ #include "monkestation\code\modules\and_roll_credits\_credits.dm" #include "monkestation\code\modules\and_roll_credits\credits_subsystem.dm" #include "monkestation\code\modules\and_roll_credits\episode_names.dm" +#include "monkestation\code\modules\antagonist\blob\blob_antag.dm" #include "monkestation\code\modules\antagonists\_common\antag_datum.dm" #include "monkestation\code\modules\antagonists\_common\antag_hud.dm" #include "monkestation\code\modules\antagonists\abductor\abductor.dm" @@ -8152,6 +8153,7 @@ #include "monkestation\code\modules\storytellers\antag_rep\helper_procs.dm" #include "monkestation\code\modules\storytellers\converted_events\_base_event.dm" #include "monkestation\code\modules\storytellers\converted_events\event_overrides.dm" +#include "monkestation\code\modules\storytellers\converted_events\solo\blob_infection.dm" #include "monkestation\code\modules\storytellers\converted_events\solo\bloodcult.dm" #include "monkestation\code\modules\storytellers\converted_events\solo\bloodsuckers.dm" #include "monkestation\code\modules\storytellers\converted_events\solo\brother.dm" From 05cf6079e1375d0ffd453fe3741b905fe0bd254f Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 19 Dec 2024 23:05:33 +0000 Subject: [PATCH 18/81] Automatic changelog for PR #4603 [ci skip] --- html/changelogs/AutoChangeLog-pr-4603.yml | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-4603.yml diff --git a/html/changelogs/AutoChangeLog-pr-4603.yml b/html/changelogs/AutoChangeLog-pr-4603.yml new file mode 100644 index 000000000000..b04b35a74b01 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-4603.yml @@ -0,0 +1,6 @@ +author: "Gw0sty" +delete-after: True +changes: + - rscadd: "Added Blob Infections as a triggerable event. A dormant host containing acting as the vessel of a Overmind in them." + - balance: "Infected Blob hosts will show as sick no matter their active state." + - balance: "Lowered the weight of blobs spawning." \ No newline at end of file From bbd3ed11a5ceeba95fce2d89bb62bb60f19874b4 Mon Sep 17 00:00:00 2001 From: Uristthedorf <40842973+Uristthedorf@users.noreply.github.com> Date: Thu, 19 Dec 2024 15:37:54 -0800 Subject: [PATCH 19/81] EMPing a holosign creator will make it delete all its holosigns. (#2561) * EMPs destroy holo stuff. * EMPing a holosign itself doesn't destroy it. It's like if you EMPed a laser, it doesn't destroy it. * Modularizes holosign creator stuff * I dunno the exact place to put it. * Update holosign_creator.dm * Removed pointless check * Update holosign_creator.dm * Update holosign_creator.dm --- monkestation/code/game/objects/items/holosign_creator.dm | 5 +++++ tgstation.dme | 1 + 2 files changed, 6 insertions(+) create mode 100644 monkestation/code/game/objects/items/holosign_creator.dm diff --git a/monkestation/code/game/objects/items/holosign_creator.dm b/monkestation/code/game/objects/items/holosign_creator.dm new file mode 100644 index 000000000000..d66f8265aa18 --- /dev/null +++ b/monkestation/code/game/objects/items/holosign_creator.dm @@ -0,0 +1,5 @@ +/obj/item/holosign_creator/emp_act(severity) + . = ..() + for(var/obj/structure/holosign/sign as anything in signs) + if(prob(90 / severity)) + qdel(sign) diff --git a/tgstation.dme b/tgstation.dme index f6fef1350f0b..f5aad6a4b249 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -6062,6 +6062,7 @@ #include "monkestation\code\game\objects\items\cirno_plush.dm" #include "monkestation\code\game\objects\items\emags.dm" #include "monkestation\code\game\objects\items\gravity_gun.dm" +#include "monkestation\code\game\objects\items\holosign_creator.dm" #include "monkestation\code\game\objects\items\jukebox_beacon.dm" #include "monkestation\code\game\objects\items\miningweapons.dm" #include "monkestation\code\game\objects\items\mop.dm" From b3b6bb29d4c921e7a417da033534a47507741e62 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 19 Dec 2024 23:38:13 +0000 Subject: [PATCH 20/81] Automatic changelog for PR #2561 [ci skip] --- html/changelogs/AutoChangeLog-pr-2561.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-2561.yml diff --git a/html/changelogs/AutoChangeLog-pr-2561.yml b/html/changelogs/AutoChangeLog-pr-2561.yml new file mode 100644 index 000000000000..f7ea2c1dfbd9 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-2561.yml @@ -0,0 +1,4 @@ +author: "Uristthedorf" +delete-after: True +changes: + - rscadd: "EMPing a holosign creator, will destroy all of the holosigns." \ No newline at end of file From 17a0a43e1ad1742279a5d334299569a91abb858f Mon Sep 17 00:00:00 2001 From: Changelogs Date: Thu, 19 Dec 2024 23:54:40 +0000 Subject: [PATCH 21/81] Automatic changelog compile [ci skip] --- html/changelogs/AutoChangeLog-pr-2561.yml | 4 --- html/changelogs/AutoChangeLog-pr-4584.yml | 10 ------ html/changelogs/AutoChangeLog-pr-4589.yml | 6 ---- html/changelogs/AutoChangeLog-pr-4591.yml | 5 --- html/changelogs/AutoChangeLog-pr-4602.yml | 4 --- html/changelogs/AutoChangeLog-pr-4603.yml | 6 ---- html/changelogs/AutoChangeLog-pr-4612.yml | 7 ---- html/changelogs/AutoChangeLog-pr-4613.yml | 4 --- html/changelogs/AutoChangeLog-pr-4621.yml | 6 ---- html/changelogs/archive/2024-12.yml | 43 +++++++++++++++++++++++ 10 files changed, 43 insertions(+), 52 deletions(-) delete mode 100644 html/changelogs/AutoChangeLog-pr-2561.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-4584.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-4589.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-4591.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-4602.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-4603.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-4612.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-4613.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-4621.yml diff --git a/html/changelogs/AutoChangeLog-pr-2561.yml b/html/changelogs/AutoChangeLog-pr-2561.yml deleted file mode 100644 index f7ea2c1dfbd9..000000000000 --- a/html/changelogs/AutoChangeLog-pr-2561.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Uristthedorf" -delete-after: True -changes: - - rscadd: "EMPing a holosign creator, will destroy all of the holosigns." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-4584.yml b/html/changelogs/AutoChangeLog-pr-4584.yml deleted file mode 100644 index 0924724c607b..000000000000 --- a/html/changelogs/AutoChangeLog-pr-4584.yml +++ /dev/null @@ -1,10 +0,0 @@ -author: "Gw0sty" -delete-after: True -changes: - - rscadd: "brought the Christmas spirit (tree) to Thesues!" - - rscadd: "Gave Ancient/charlie/oldstation a supermatter shard that gives its warnings on Uncommon frequency" - - rscadd: "Added three uncommon radio keys to the science box on charlie so borgs can get the frequency" - - bugfix: "Replaced knifes in Theseus's kitchen with kitchen knives. Now (nothing changes) chefs can use their knifes in peace." - - bugfix: "Made it so you can actually leave the Theseus Gulag shuttle." - - bugfix: "added missing job to Icons for alt title jobs." - - bugfix: "Ipc surgery research now works as intended" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-4589.yml b/html/changelogs/AutoChangeLog-pr-4589.yml deleted file mode 100644 index 3619e5ed33e9..000000000000 --- a/html/changelogs/AutoChangeLog-pr-4589.yml +++ /dev/null @@ -1,6 +0,0 @@ -author: "Absolucy" -delete-after: True -changes: - - qol: "There is now a chat notice and a visual indicator in the lobby for when there's a non-standard overflow." - - qol: "Added a preference (disabled by default) to confirm readying up when there's a non-standard overflow." - - bugfix: "Fixed a bug where the overflow station trait could roll assistants, which just did... nothing." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-4591.yml b/html/changelogs/AutoChangeLog-pr-4591.yml deleted file mode 100644 index 27d0bde53f8b..000000000000 --- a/html/changelogs/AutoChangeLog-pr-4591.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: "Absolucy" -delete-after: True -changes: - - bugfix: "The cargo imports UI now shows the correct price when the station has strong or distant supply lines." - - bugfix: "Ordering from cargo imports now actually checks to see if you have the correct amount of money when the station has strong or distant supply lines." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-4602.yml b/html/changelogs/AutoChangeLog-pr-4602.yml deleted file mode 100644 index 25f412c850c2..000000000000 --- a/html/changelogs/AutoChangeLog-pr-4602.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Gboster-0" -delete-after: True -changes: - - qol: "Made pride pins display their pride in the name, like \"transexual pride pin\" instead of \"pride pin\"" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-4603.yml b/html/changelogs/AutoChangeLog-pr-4603.yml deleted file mode 100644 index b04b35a74b01..000000000000 --- a/html/changelogs/AutoChangeLog-pr-4603.yml +++ /dev/null @@ -1,6 +0,0 @@ -author: "Gw0sty" -delete-after: True -changes: - - rscadd: "Added Blob Infections as a triggerable event. A dormant host containing acting as the vessel of a Overmind in them." - - balance: "Infected Blob hosts will show as sick no matter their active state." - - balance: "Lowered the weight of blobs spawning." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-4612.yml b/html/changelogs/AutoChangeLog-pr-4612.yml deleted file mode 100644 index 669b0b98c490..000000000000 --- a/html/changelogs/AutoChangeLog-pr-4612.yml +++ /dev/null @@ -1,7 +0,0 @@ -author: "ThePooba" -delete-after: True -changes: - - balance: "christmas presents from 50% to 5% chance to get the \"toys only\" christmas present so you gusy get your op bullshit back, but added some stinky stuff to blacklist like the item spawner wand and the var edit wand(what the fuck)" - - balance: "thermonuclear catsplosion more dangerous, twice as likely" - - bugfix: "Added no interact to hardlight spears so you cant switch them in hand and hardlock yourself" - - bugfix: "i think tiny artifacts can now detonate properly now i couldnt get them to spawn properly" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-4613.yml b/html/changelogs/AutoChangeLog-pr-4613.yml deleted file mode 100644 index bcbc00ae9a6c..000000000000 --- a/html/changelogs/AutoChangeLog-pr-4613.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Gw0sty" -delete-after: True -changes: - - balance: "Research directors remote now has AI upload access." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-4621.yml b/html/changelogs/AutoChangeLog-pr-4621.yml deleted file mode 100644 index 0cbc1c216270..000000000000 --- a/html/changelogs/AutoChangeLog-pr-4621.yml +++ /dev/null @@ -1,6 +0,0 @@ -author: "Loiosh42" -delete-after: True -changes: - - balance: "Tweaks AP shotgun shells, and gives them pierce" - - balance: "Nerfs the Bobr" - - balance: "Gives the Wylom AM rifle pierce" \ No newline at end of file diff --git a/html/changelogs/archive/2024-12.yml b/html/changelogs/archive/2024-12.yml index 5fd33b0fc7de..662babff5757 100644 --- a/html/changelogs/archive/2024-12.yml +++ b/html/changelogs/archive/2024-12.yml @@ -268,6 +268,49 @@ runtime errors. - balance: Clown spawner artifacts will no longer spawn another spawner if the previous one still exists. + - bugfix: The cargo imports UI now shows the correct price when the station has + strong or distant supply lines. + - bugfix: Ordering from cargo imports now actually checks to see if you have the + correct amount of money when the station has strong or distant supply lines. + - qol: There is now a chat notice and a visual indicator in the lobby for when there's + a non-standard overflow. + - qol: Added a preference (disabled by default) to confirm readying up when there's + a non-standard overflow. + - bugfix: Fixed a bug where the overflow station trait could roll assistants, which + just did... nothing. + Gboster-0: + - qol: Made pride pins display their pride in the name, like "transexual pride pin" + instead of "pride pin" + Gw0sty: + - rscadd: brought the Christmas spirit (tree) to Thesues! + - rscadd: Gave Ancient/charlie/oldstation a supermatter shard that gives its warnings + on Uncommon frequency + - rscadd: Added three uncommon radio keys to the science box on charlie so borgs + can get the frequency + - bugfix: Replaced knifes in Theseus's kitchen with kitchen knives. Now (nothing + changes) chefs can use their knifes in peace. + - bugfix: Made it so you can actually leave the Theseus Gulag shuttle. + - bugfix: added missing job to Icons for alt title jobs. + - bugfix: Ipc surgery research now works as intended + - rscadd: Added Blob Infections as a triggerable event. A dormant host containing + acting as the vessel of a Overmind in them. + - balance: Infected Blob hosts will show as sick no matter their active state. + - balance: Lowered the weight of blobs spawning. + - balance: Research directors remote now has AI upload access. + Loiosh42: + - balance: Tweaks AP shotgun shells, and gives them pierce + - balance: Nerfs the Bobr + - balance: Gives the Wylom AM rifle pierce ThePooba: - bugfix: nerfs christmas presents and allows the real chrimas presents to spawn - bugfix: blob zombie event wont spawn you on asteroids and shit anymore + - balance: christmas presents from 50% to 5% chance to get the "toys only" christmas + present so you gusy get your op bullshit back, but added some stinky stuff to + blacklist like the item spawner wand and the var edit wand(what the fuck) + - balance: thermonuclear catsplosion more dangerous, twice as likely + - bugfix: Added no interact to hardlight spears so you cant switch them in hand + and hardlock yourself + - bugfix: i think tiny artifacts can now detonate properly now i couldnt get them + to spawn properly + Uristthedorf: + - rscadd: EMPing a holosign creator, will destroy all of the holosigns. From 8a5ce3718f1ac5b1a84bbcd99e24e35aa7a13e6f Mon Sep 17 00:00:00 2001 From: Lucy Date: Thu, 19 Dec 2024 23:43:41 -0500 Subject: [PATCH 22/81] Properly give all xenobio slimeperson subspecies slime wings (#4620) --- code/modules/surgery/bodyparts/species_parts/misc_bodyparts.dm | 2 ++ 1 file changed, 2 insertions(+) diff --git a/code/modules/surgery/bodyparts/species_parts/misc_bodyparts.dm b/code/modules/surgery/bodyparts/species_parts/misc_bodyparts.dm index 7b33538404dc..fbf1baa5edea 100644 --- a/code/modules/surgery/bodyparts/species_parts/misc_bodyparts.dm +++ b/code/modules/surgery/bodyparts/species_parts/misc_bodyparts.dm @@ -156,6 +156,7 @@ limb_id = SPECIES_SLIMEPERSON is_dimorphic = TRUE composition_effects = list(/datum/element/soft_landing = 0.5) + wing_types = list(/obj/item/organ/external/wings/functional/slime) palette = /datum/color_palette/generic_colors palette_key = MUTANT_COLOR @@ -199,6 +200,7 @@ biological_state = (BIO_FLESH|BIO_BLOODED) limb_id = SPECIES_LUMINESCENT is_dimorphic = TRUE + wing_types = list(/obj/item/organ/external/wings/functional/slime) palette = /datum/color_palette/generic_colors palette_key = MUTANT_COLOR From 313b8d8dd9a8025294157efd84228bb8d99974bc Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 20 Dec 2024 04:44:04 +0000 Subject: [PATCH 23/81] Automatic changelog for PR #4620 [ci skip] --- html/changelogs/AutoChangeLog-pr-4620.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-4620.yml diff --git a/html/changelogs/AutoChangeLog-pr-4620.yml b/html/changelogs/AutoChangeLog-pr-4620.yml new file mode 100644 index 000000000000..461660252a14 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-4620.yml @@ -0,0 +1,4 @@ +author: "Absolucy" +delete-after: True +changes: + - bugfix: "The xenobio Slimeperson and Luminscent subspecies will now properly get slime wings from drinking a flight potion." \ No newline at end of file From a35f3e80a01edeb4ee3d2da759d7be2611a6f5c6 Mon Sep 17 00:00:00 2001 From: Lucy Date: Thu, 19 Dec 2024 23:45:18 -0500 Subject: [PATCH 24/81] Slime in vents/slime grinders/etc will no longer secrete ooze on the floor (#4619) --- .../slimecore/components/liquid_secretion.dm | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/monkestation/code/modules/slimecore/components/liquid_secretion.dm b/monkestation/code/modules/slimecore/components/liquid_secretion.dm index f1ec48bc4f08..8df882d5ab92 100644 --- a/monkestation/code/modules/slimecore/components/liquid_secretion.dm +++ b/monkestation/code/modules/slimecore/components/liquid_secretion.dm @@ -11,6 +11,8 @@ /datum/component/liquid_secretion/Initialize(reagent_id = /datum/reagent/water, amount = 10, secretion_interval = 1 SECONDS, pre_secrete_callback) . = ..() + if(!ismovable(parent)) + return COMPONENT_INCOMPATIBLE src.reagent_id = reagent_id src.secretion_interval = secretion_interval @@ -38,15 +40,18 @@ if(secretion_interval) src.secretion_interval = secretion_interval - /datum/component/liquid_secretion/process(seconds_per_tick) - if(QDELETED(parent) || !COOLDOWN_FINISHED(src, next_secrete)) + var/atom/movable/parent = src.parent + if(QDELETED(parent)) + return PROCESS_KILL + if(!COOLDOWN_FINISHED(src, next_secrete)) + return + var/turf/open/parent_turf = parent.loc + if(!isopenturf(parent_turf)) return COOLDOWN_START(src, next_secrete, secretion_interval) if(pre_secrete_callback && !pre_secrete_callback.Invoke(parent)) return - - var/turf/parent_turf = get_turf(parent) var/list/reagent_list = list() reagent_list[reagent_id] = amount parent_turf?.add_liquid_list(reagent_list, FALSE, T20C) From 14485994bae7016a0ee0a73ecd01b698ae92b567 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 20 Dec 2024 04:45:38 +0000 Subject: [PATCH 25/81] Automatic changelog for PR #4619 [ci skip] --- html/changelogs/AutoChangeLog-pr-4619.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-4619.yml diff --git a/html/changelogs/AutoChangeLog-pr-4619.yml b/html/changelogs/AutoChangeLog-pr-4619.yml new file mode 100644 index 000000000000..b4cebab4e159 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-4619.yml @@ -0,0 +1,4 @@ +author: "Absolucy" +delete-after: True +changes: + - bugfix: "Slime in vents/slime grinders/etc will no longer secrete ooze on the floor." \ No newline at end of file From f6cde2f47cbc77251badee6fdac79828eb1877e1 Mon Sep 17 00:00:00 2001 From: Lucy Date: Thu, 19 Dec 2024 23:54:22 -0500 Subject: [PATCH 26/81] Add an "Export Lighting Info" mapping verb (#4532) --- code/modules/admin/verbs/mapping.dm | 1 + .../code/modules/admin/verbs/mapping.dm | 47 +++++++++++++++++++ tgstation.dme | 1 + 3 files changed, 49 insertions(+) create mode 100644 monkestation/code/modules/admin/verbs/mapping.dm diff --git a/code/modules/admin/verbs/mapping.dm b/code/modules/admin/verbs/mapping.dm index 6b0dcccf084d..f54444001678 100644 --- a/code/modules/admin/verbs/mapping.dm +++ b/code/modules/admin/verbs/mapping.dm @@ -55,6 +55,7 @@ GLOBAL_LIST_INIT(admin_verbs_debug_mapping, list( /client/proc/station_food_debug, /client/proc/station_stack_debug, /client/proc/check_for_obstructed_atmospherics, + /client/proc/export_lighting_info, // monkestation addition )) GLOBAL_PROTECT(admin_verbs_debug_mapping) diff --git a/monkestation/code/modules/admin/verbs/mapping.dm b/monkestation/code/modules/admin/verbs/mapping.dm new file mode 100644 index 000000000000..897469af998d --- /dev/null +++ b/monkestation/code/modules/admin/verbs/mapping.dm @@ -0,0 +1,47 @@ +/// Returns a list of the lighting level of each open turf on a z-level. +/proc/encode_lighting_levels(z) as /list + RETURN_TYPE(/list) + if(!isnum(z) || !ISINRANGE(z, 1, world.maxz)) + z = SSmapping.levels_by_trait(ZTRAIT_STATION)[1] + stack_trace("Invalid z-level given, defaulting to first station z-level ([z])") + var/list/lighting = new(world.maxx, world.maxy) + for(var/turf/open/floor/floor in Z_TURFS(z)) + lighting[floor.x][floor.y] = floor.is_softly_lit() ? 0 : floor.get_lumcount() + CHECK_TICK + return lighting + +/client/proc/export_lighting_info() + set name = "Export Lighting Info" + set desc = "Exports a JSON file containing info about the lighting level of all floor turfs on a given Z-level." + set category = "Mapping" + + if(!check_rights(R_DEBUG)) + return + var/list/options = list("All Station Z-Levels") + var/turf/our_turf = get_turf(mob) + if(!isnewplayer(mob) && !isnull(our_turf)) + options += "Current Z-Level" + var/list/zs + switch(tgui_alert(src, "What Z-levels would you like to export lighting info for?", "Select Z Levels", options + list("Cancel"))) + if("All Station Z-Levels") + zs = SSmapping.levels_by_trait(ZTRAIT_STATION) + if("Current Z-Level") + zs = list(our_turf.z) + else + return + + var/list/lighting_info = list() + switch(length(zs)) + if(1) + lighting_info = encode_lighting_levels(zs[1]) + if(2 to INFINITY) + for(var/z in zs) + lighting_info["[z]"] = encode_lighting_levels(z) + else + to_chat(src, span_warning("No Z-levels selected!")) + return + + var/file_name = "[ckey]_lighting_info_[time2text(world.timeofday, "MMM_DD_YYYY_hh-mm-ss")].json" + var/json_file = file("tmp/[file_name]") + WRITE_FILE(json_file, json_encode(lighting_info)) + DIRECT_OUTPUT(src, ftp(json_file, file_name)) diff --git a/tgstation.dme b/tgstation.dme index f5aad6a4b249..6ca9cc211af2 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -6175,6 +6175,7 @@ #include "monkestation\code\modules\admin\smites\where_are_your_fingers.dm" #include "monkestation\code\modules\admin\verbs\getlogs.dm" #include "monkestation\code\modules\admin\verbs\kick_player_by_ckey.dm" +#include "monkestation\code\modules\admin\verbs\mapping.dm" #include "monkestation\code\modules\admin\verbs\selectequipment.dm" #include "monkestation\code\modules\admin\verbs\spawn_mixtape.dm" #include "monkestation\code\modules\admin\verbs\tracy.dm" From 9b82239ef418b073cb29a7b63037c00474fbb1b1 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 20 Dec 2024 04:55:01 +0000 Subject: [PATCH 27/81] Automatic changelog for PR #4532 [ci skip] --- html/changelogs/AutoChangeLog-pr-4532.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-4532.yml diff --git a/html/changelogs/AutoChangeLog-pr-4532.yml b/html/changelogs/AutoChangeLog-pr-4532.yml new file mode 100644 index 000000000000..6f9ce916bb99 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-4532.yml @@ -0,0 +1,4 @@ +author: "Absolucy" +delete-after: True +changes: + - admin: "Added a new mapping verb, Export Lighting Info (behind Mapping Verbs - Enable) that exports the lighting info of z levels into a json file." \ No newline at end of file From 83534c221312b70db75248b600139f209c2923c4 Mon Sep 17 00:00:00 2001 From: Wisemonster <87689371+Wisemonster@users.noreply.github.com> Date: Fri, 20 Dec 2024 00:36:22 -0500 Subject: [PATCH 28/81] [TG Port] Replace Heretic Phobia with Cursed Organs (#4475) * Commit non-conflicting files * Commit the curse changes * Fixes up corrupted_organs.dm * impure_medicine_reagents changes * Finishes up corrupted organs * Oops, forgot some keyword args * Buh, forgot a single letter * Fix examines for corrupt organs * Uses right grammar for stomach depending on the pronoun --- code/__DEFINES/antagonists.dm | 3 + code/datums/ai/_ai_controller.dm | 7 +- code/datums/elements/corrupted_organ.dm | 66 +++++ code/datums/elements/relay_attackers.dm | 17 +- .../objects/effects/decals/cleanable/misc.dm | 8 + .../heretic/items/corrupted_organs.dm | 243 ++++++++++++++++++ .../sacrifice_knowledge/sacrifice_buff.dm | 14 + .../sacrifice_knowledge/sacrifice_curse.dm | 93 +++++++ .../impure_medicine_reagents.dm | 13 +- .../sacrifice_knowledge.dm | 41 ++- tgstation.dme | 3 + 11 files changed, 483 insertions(+), 25 deletions(-) create mode 100644 code/datums/elements/corrupted_organ.dm create mode 100644 code/modules/antagonists/heretic/items/corrupted_organs.dm create mode 100644 code/modules/antagonists/heretic/knowledge/sacrifice_knowledge/sacrifice_curse.dm diff --git a/code/__DEFINES/antagonists.dm b/code/__DEFINES/antagonists.dm index 020efe8d0858..47d703974ae3 100644 --- a/code/__DEFINES/antagonists.dm +++ b/code/__DEFINES/antagonists.dm @@ -226,6 +226,9 @@ GLOBAL_LIST_INIT(ai_employers, list( /// Checks if the given mob is either a heretic, heretic monster or a lunatic. #define IS_HERETIC_OR_MONSTER(mob) (IS_HERETIC(mob) || IS_HERETIC_MONSTER(mob) || IS_LUNATIC(mob)) +/// Checks if the given mob is in the mansus realm +#define IS_IN_MANSUS(mob) (istype(get_area(mob), /area/centcom/heretic_sacrifice)) + /// Checks if the given mob is a wizard #define IS_WIZARD(mob) (mob?.mind?.has_antag_datum(/datum/antagonist/wizard)) diff --git a/code/datums/ai/_ai_controller.dm b/code/datums/ai/_ai_controller.dm index 8966193abff9..48b0f1a9db46 100644 --- a/code/datums/ai/_ai_controller.dm +++ b/code/datums/ai/_ai_controller.dm @@ -232,9 +232,10 @@ multiple modular subtrees with behaviors ///Called when the AI controller pawn changes z levels, we check if there's any clients on the new one and wake up the AI if there is. /datum/ai_controller/proc/on_changed_z_level(atom/source, turf/old_turf, turf/new_turf, same_z_layer, notify_contents) SIGNAL_HANDLER - var/mob/mob_pawn = pawn - if((mob_pawn?.client && !continue_processing_when_client)) - return + if (ismob(pawn)) + var/mob/mob_pawn = pawn + if((mob_pawn?.client && !continue_processing_when_client)) + return if(old_turf) SSai_controllers.ai_controllers_by_zlevel[old_turf.z] -= src if(new_turf) diff --git a/code/datums/elements/corrupted_organ.dm b/code/datums/elements/corrupted_organ.dm new file mode 100644 index 000000000000..ee4cf3a1003d --- /dev/null +++ b/code/datums/elements/corrupted_organ.dm @@ -0,0 +1,66 @@ +/// Component applying shared behaviour by cursed organs granted when sacrificed by a heretic +/// Mostly just does something spooky when it is removed +/datum/element/corrupted_organ + +/datum/element/corrupted_organ/Attach(datum/target) + . = ..() + if (!isinternalorgan(target)) + return ELEMENT_INCOMPATIBLE + + RegisterSignal(target, COMSIG_ORGAN_REMOVED, PROC_REF(on_removed)) + + var/atom/atom_parent = target + atom_parent.color = COLOR_VOID_PURPLE + + atom_parent.add_filter(name = "ray", priority = 1, params = list( + type = "rays", + size = 12, + color = COLOR_VOID_PURPLE, + density = 12 + )) + var/ray_filter = atom_parent.get_filter("ray") + animate(ray_filter, offset = 100, time = 2 MINUTES, loop = -1, flags = ANIMATION_PARALLEL) // Absurdly long animate so nobody notices it hitching when it loops + animate(offset = 0, time = 2 MINUTES) // I sure hope duration of animate doesnt have any performance effect + +/datum/element/corrupted_organ/Detach(datum/source) + UnregisterSignal(source, list(COMSIG_ORGAN_REMOVED)) + return ..() + +/// When we're taken out of someone, do something spooky +/datum/element/corrupted_organ/proc/on_removed(atom/organ, mob/living/carbon/loser) + SIGNAL_HANDLER + if (loser.has_reagent(/datum/reagent/water/holywater) || loser.can_block_magic(MAGIC_RESISTANCE|MAGIC_RESISTANCE_HOLY) || prob(20)) + return + if (prob(75)) + organ.AddComponent(\ + /datum/component/haunted_item,\ + haunt_color = "#00000000", \ + aggro_radius = 4, \ + spawn_message = span_revenwarning("[organ] hovers ominously into the air, pulsating with unnatural vigour!"), \ + despawn_message = span_revenwarning("[organ] falls motionless to the ground."), \ + ) + return + var/turf/origin_turf = get_turf(organ) + playsound(organ, 'sound/magic/forcewall.ogg', vol = 100) + new /obj/effect/temp_visual/curse_blast(origin_turf) + organ.visible_message(span_revenwarning("[organ] explodes in a burst of dark energy!")) + for(var/mob/living/target in range(1, origin_turf)) + var/armor = target.run_armor_check(attack_flag = BOMB) + target.apply_damage(30, damagetype = BURN, blocked = armor, spread_damage = TRUE) + qdel(organ) + +/obj/effect/temp_visual/curse_blast + icon = 'icons/effects/64x64.dmi' + pixel_x = -16 + pixel_y = -16 + icon_state = "curse" + duration = 0.3 SECONDS + +/obj/effect/temp_visual/curse_blast/Initialize(mapload) + . = ..() + animate(src, transform = matrix() * 0.2, time = 0, flags = ANIMATION_PARALLEL) + animate(transform = matrix() * 2, time = duration, easing = EASE_IN) + + animate(src, alpha = 255, time = 0, flags = ANIMATION_PARALLEL) + animate(alpha = 255, time = 0.2 SECONDS) + animate(alpha = 0, time = 0.1 SECONDS) diff --git a/code/datums/elements/relay_attackers.dm b/code/datums/elements/relay_attackers.dm index cdc86e6058cb..83e83a40e7ce 100644 --- a/code/datums/elements/relay_attackers.dm +++ b/code/datums/elements/relay_attackers.dm @@ -7,14 +7,15 @@ /datum/element/relay_attackers/Attach(datum/target) . = ..() - // Boy this sure is a lot of ways to tell us that someone tried to attack us - RegisterSignal(target, COMSIG_ATOM_AFTER_ATTACKEDBY, PROC_REF(after_attackby)) - RegisterSignals(target, list(COMSIG_ATOM_ATTACK_HAND, COMSIG_ATOM_ATTACK_PAW, COMSIG_MOB_ATTACK_ALIEN), PROC_REF(on_attack_generic)) - RegisterSignals(target, list(COMSIG_ATOM_ATTACK_BASIC_MOB, COMSIG_ATOM_ATTACK_ANIMAL), PROC_REF(on_attack_npc)) - RegisterSignal(target, COMSIG_PROJECTILE_PREHIT, PROC_REF(on_bullet_act)) - RegisterSignal(target, COMSIG_ATOM_PREHITBY, PROC_REF(on_hitby)) - RegisterSignal(target, COMSIG_ATOM_HULK_ATTACK, PROC_REF(on_attack_hulk)) - RegisterSignal(target, COMSIG_ATOM_ATTACK_MECH, PROC_REF(on_attack_mech)) + if (!HAS_TRAIT(target, TRAIT_RELAYING_ATTACKER)) // Little bit gross but we want to just apply this shit from a bunch of places + // Boy this sure is a lot of ways to tell us that someone tried to attack us + RegisterSignal(target, COMSIG_ATOM_AFTER_ATTACKEDBY, PROC_REF(after_attackby)) + RegisterSignals(target, list(COMSIG_ATOM_ATTACK_HAND, COMSIG_ATOM_ATTACK_PAW, COMSIG_MOB_ATTACK_ALIEN), PROC_REF(on_attack_generic)) + RegisterSignals(target, list(COMSIG_ATOM_ATTACK_BASIC_MOB, COMSIG_ATOM_ATTACK_ANIMAL), PROC_REF(on_attack_npc)) + RegisterSignal(target, COMSIG_PROJECTILE_PREHIT, PROC_REF(on_bullet_act)) + RegisterSignal(target, COMSIG_ATOM_PREHITBY, PROC_REF(on_hitby)) + RegisterSignal(target, COMSIG_ATOM_HULK_ATTACK, PROC_REF(on_attack_hulk)) + RegisterSignal(target, COMSIG_ATOM_ATTACK_MECH, PROC_REF(on_attack_mech)) ADD_TRAIT(target, TRAIT_RELAYING_ATTACKER, REF(src)) /datum/element/relay_attackers/Detach(datum/source, ...) diff --git a/code/game/objects/effects/decals/cleanable/misc.dm b/code/game/objects/effects/decals/cleanable/misc.dm index 091bb5407fad..965e0417f6f9 100644 --- a/code/game/objects/effects/decals/cleanable/misc.dm +++ b/code/game/objects/effects/decals/cleanable/misc.dm @@ -174,6 +174,14 @@ reagents.trans_to(H, reagents.total_volume, transfered_by = user, methods = INGEST) qdel(src) +/// Nebula vomit with extra guests +/obj/effect/decal/cleanable/vomit/nebula/worms + +/obj/effect/decal/cleanable/vomit/nebula/worms/Initialize(mapload, list/datum/disease/diseases) + . = ..() + for (var/i in 1 to rand(2, 3)) + new /mob/living/basic/hivelord_brood(loc) + /obj/effect/decal/cleanable/vomit/old name = "crusty dried vomit" desc = "You try not to look at the chunks, and fail." diff --git a/code/modules/antagonists/heretic/items/corrupted_organs.dm b/code/modules/antagonists/heretic/items/corrupted_organs.dm new file mode 100644 index 000000000000..4923487c03a3 --- /dev/null +++ b/code/modules/antagonists/heretic/items/corrupted_organs.dm @@ -0,0 +1,243 @@ +/// Renders you unable to see people who were heretics at the time that this organ is gained +/obj/item/organ/internal/eyes/corrupt + name = "corrupt orbs" + desc = "These eyes have seen something they shouldn't have." + /// The override images we are applying + var/list/hallucinations + +/obj/item/organ/internal/eyes/corrupt/Initialize(mapload) + . = ..() + AddElement(/datum/element/corrupted_organ) + AddElement(/datum/element/noticable_organ, "eyes have wide dilated pupils, and no iris. Something is moving in the darkness.", BODY_ZONE_PRECISE_EYES) + +/obj/item/organ/internal/eyes/corrupt/Insert(mob/living/carbon/organ_owner, special, drop_if_replaced) + . = ..() + if (!organ_owner.client) + return + + var/list/human_mobs = GLOB.human_list.Copy() + human_mobs -= organ_owner + for (var/mob/living/carbon/human/check_human as anything in human_mobs) + if (!IS_HERETIC(check_human) && !prob(5)) // Throw in some false positives + continue + var/image/invisible_man = image('icons/blanks/32x32.dmi', check_human, "nothing") + invisible_man.override = TRUE + LAZYADD(hallucinations, invisible_man) + + if (LAZYLEN(hallucinations)) + organ_owner.client.images |= hallucinations + +/obj/item/organ/internal/eyes/corrupt/Remove(mob/living/carbon/organ_owner, special) + . = ..() + if (!LAZYLEN(hallucinations)) + return + organ_owner.client?.images -= hallucinations + QDEL_NULL(hallucinations) + + +/// Sometimes speak in incomprehensible tongues +/obj/item/organ/internal/tongue/corrupt + name = "corrupt tongue" + desc = "This one tells only lies." + +/obj/item/organ/internal/tongue/corrupt/Initialize(mapload) + . = ..() + AddElement(/datum/element/corrupted_organ) + AddElement(/datum/element/noticable_organ, "mouth is full of stars.", BODY_ZONE_PRECISE_MOUTH) + +/obj/item/organ/internal/tongue/corrupt/Insert(mob/living/carbon/organ_owner, special, drop_if_replaced) + . = ..() + RegisterSignal(organ_owner, COMSIG_MOB_SAY, PROC_REF(on_spoken)) + +/obj/item/organ/internal/tongue/corrupt/Remove(mob/living/carbon/organ_owner, special) + . = ..() + UnregisterSignal(organ_owner, COMSIG_MOB_SAY) + +/// When the mob speaks, sometimes put it in a different language +/obj/item/organ/internal/tongue/corrupt/proc/on_spoken(mob/living/organ_owner, list/speech_args) + SIGNAL_HANDLER + if (organ_owner.has_reagent(/datum/reagent/water/holywater) || prob(60)) + return + speech_args[SPEECH_LANGUAGE] = /datum/language/shadowtongue + + +/// Randomly secretes alcohol or hallucinogens when you're drinking something +/obj/item/organ/internal/liver/corrupt + name = "corrupt liver" + desc = "After what you've seen you could really go for a drink." + /// How much extra ingredients to add? + var/amount_added = 5 + /// What extra ingredients can we add? + var/list/extra_ingredients = list( + /datum/reagent/consumable/ethanol/pina_olivada, + /datum/reagent/consumable/ethanol/rum, + /datum/reagent/consumable/ethanol/thirteenloko, + /datum/reagent/consumable/ethanol/vodka, + /datum/reagent/consumable/superlaughter, + /datum/reagent/drug/bath_salts, + /datum/reagent/drug/blastoff, + /datum/reagent/drug/happiness, + /datum/reagent/drug/mushroomhallucinogen, + ) + +/obj/item/organ/internal/liver/corrupt/Initialize(mapload) + . = ..() + AddElement(/datum/element/corrupted_organ) + +/obj/item/organ/internal/liver/corrupt/Insert(mob/living/carbon/organ_owner, special, drop_if_replaced) + . = ..() + RegisterSignal(organ_owner, COMSIG_ATOM_EXPOSE_REAGENTS, PROC_REF(on_drank)) + +/obj/item/organ/internal/liver/corrupt/Remove(mob/living/carbon/organ_owner, special) + . = ..() + UnregisterSignal(organ_owner, COMSIG_ATOM_EXPOSE_REAGENTS) + +/// If we drank something, add a little extra +/obj/item/organ/internal/liver/corrupt/proc/on_drank(atom/source, list/reagents, datum/reagents/source_reagents, methods) + SIGNAL_HANDLER + if (!(methods & INGEST)) + return + var/datum/reagents/extra_reagents = new() + extra_reagents.add_reagent(pick(extra_ingredients), amount_added) + extra_reagents.trans_to(source, amount_added, methods = INJECT) + if (prob(20)) + to_chat(source, span_warning("As you take a sip, you feel something bubbling in your stomach...")) + + +/// Rapidly become hungry if you are not digesting blood +/obj/item/organ/internal/stomach/corrupt + name = "corrupt stomach" + desc = "This parasite demands an unwholesome diet in order to be satisfied." + /// Do we have an unholy thirst? + var/thirst_satiated = FALSE + /// Timer for when we get thirsty again + var/thirst_timer + /// How long until we prompt the player to drink blood again? + COOLDOWN_DECLARE(message_cooldown) + +/obj/item/organ/internal/stomach/corrupt/Initialize(mapload) + . = ..() + AddElement(/datum/element/corrupted_organ) + AddElement(/datum/element/noticable_organ, "appear%PRONOUN_S to have an unhealthy pallor.") + +/obj/item/organ/internal/stomach/corrupt/Insert(mob/living/carbon/organ_owner, special, drop_if_replaced) + . = ..() + RegisterSignal(organ_owner, COMSIG_ATOM_EXPOSE_REAGENTS, PROC_REF(on_drank)) + +/obj/item/organ/internal/stomach/corrupt/Remove(mob/living/carbon/organ_owner, special) + . = ..() + UnregisterSignal(organ_owner, COMSIG_ATOM_EXPOSE_REAGENTS) + +/// Check if we drank a little blood +/obj/item/organ/internal/stomach/corrupt/proc/on_drank(atom/source, list/reagents, datum/reagents/source_reagents, methods) + SIGNAL_HANDLER + if (!(methods & INGEST)) + return + + var/contains_blood = locate(/datum/reagent/blood) in reagents + if (!contains_blood) + return + + if (!thirst_satiated) + to_chat(source, span_cultitalic("The thirst is satisfied... for now.")) + thirst_satiated = TRUE + deltimer(thirst_timer) + thirst_timer = addtimer(VARSET_CALLBACK(src, thirst_satiated, FALSE), 3 MINUTES, TIMER_STOPPABLE | TIMER_DELETE_ME) + +/obj/item/organ/internal/stomach/corrupt/handle_hunger(mob/living/carbon/human/human, seconds_per_tick, times_fired) + if (thirst_satiated || human.has_reagent(/datum/reagent/water/holywater)) + return ..() + + human.adjust_nutrition(-1 * seconds_per_tick) + + if (!COOLDOWN_FINISHED(src, message_cooldown)) + return ..() + COOLDOWN_START(src, message_cooldown, 30 SECONDS) + + var/static/list/blood_messages = list( + "Blood...", + "Everyone suddenly looks so tasty.", + "The blood...", + "There's an emptiness in you that only blood can fill.", + "You could really go for some blood right now.", + "You feel the blood rushing through your veins.", + "You think about biting someone's throat.", + "Your stomach growls and you feel a metallic taste in your mouth.", + ) + to_chat(human, span_cultitalic(pick(blood_messages))) + + return ..() + + +/// Occasionally bombards you with spooky hands and lets everyone hear your pulse. +/obj/item/organ/internal/heart/corrupt + name = "corrupt heart" + desc = "What corruption is this spreading along with the blood?" + /// How long until the next heart? + COOLDOWN_DECLARE(hand_cooldown) + +/obj/item/organ/internal/heart/corrupt/Initialize(mapload) + . = ..() + AddElement(/datum/element/corrupted_organ) + +/obj/item/organ/internal/heart/corrupt/on_life(seconds_per_tick, times_fired) + . = ..() + var/obj/item/organ/internal/heart/heart = owner.get_organ_slot(ORGAN_SLOT_HEART) + if (!COOLDOWN_FINISHED(src, hand_cooldown) || IS_IN_MANSUS(owner) || !owner.needs_heart() || !heart.beating || owner.has_reagent(/datum/reagent/water/holywater)) + return + fire_curse_hand(owner) + COOLDOWN_START(src, hand_cooldown, rand(6 SECONDS, 45 SECONDS)) // Wide variance to put you off guard + + +/// Sometimes cough out some kind of dangerous gas +/obj/item/organ/internal/lungs/corrupt + name = "corrupt lungs" + desc = "Some things SHOULD be drowned in tar." + /// How likely are we not to cough every time we take a breath? + var/cough_chance = 15 + /// How much gas to emit? + var/gas_amount = 30 + /// What can we cough up? + var/list/gas_types = list( + /datum/gas/bz = 30, + /datum/gas/miasma = 50, + /datum/gas/plasma = 20, + ) + +/obj/item/organ/internal/lungs/corrupt/Initialize(mapload) + . = ..() + AddElement(/datum/element/corrupted_organ) + +/obj/item/organ/internal/lungs/corrupt/check_breath(datum/gas_mixture/breath, mob/living/carbon/human/breather) + . = ..() + if (!. || IS_IN_MANSUS(owner) || breather.has_reagent(/datum/reagent/water/holywater) || !prob(cough_chance)) + return + breather.emote("cough"); + var/chosen_gas = pick_weight(gas_types) + var/datum/gas_mixture/mix_to_spawn = new() + mix_to_spawn.add_gas(pick(chosen_gas)) + mix_to_spawn.gases[chosen_gas][MOLES] = gas_amount + mix_to_spawn.temperature = breather.bodytemperature + log_atmos("[owner] coughed some gas into the air due to their corrupted lungs.", mix_to_spawn) + var/turf/open/our_turf = get_turf(breather) + our_turf.assume_air(mix_to_spawn) + + +/// It's full of worms +/obj/item/organ/internal/appendix/corrupt + name = "corrupt appendix" + desc = "What kind of dark, cosmic force is even going to bother to corrupt an appendix?" + /// How likely are we to spawn worms? + var/worm_chance = 2 + +/obj/item/organ/internal/appendix/corrupt/Initialize(mapload) + . = ..() + AddElement(/datum/element/corrupted_organ) + AddElement(/datum/element/noticable_organ, "abdomen is distended... and wiggling.", BODY_ZONE_PRECISE_GROIN) + +/obj/item/organ/internal/appendix/corrupt/on_life(seconds_per_tick, times_fired) + . = ..() + if (owner.stat != CONSCIOUS || owner.has_reagent(/datum/reagent/water/holywater) || IS_IN_MANSUS(owner) || !SPT_PROB(worm_chance, seconds_per_tick)) + return + owner.vomit(vomit_type = /obj/effect/decal/cleanable/vomit/nebula/worms, distance = 0) + owner.Knockdown(0.5 SECONDS) diff --git a/code/modules/antagonists/heretic/knowledge/sacrifice_knowledge/sacrifice_buff.dm b/code/modules/antagonists/heretic/knowledge/sacrifice_knowledge/sacrifice_buff.dm index 6faf49021266..1c001c57fcd2 100644 --- a/code/modules/antagonists/heretic/knowledge/sacrifice_knowledge/sacrifice_buff.dm +++ b/code/modules/antagonists/heretic/knowledge/sacrifice_knowledge/sacrifice_buff.dm @@ -86,3 +86,17 @@ return bloodiest_wound.adjust_blood_flow(-0.5) + +/// Torment the target with a frightening hand +/proc/fire_curse_hand(mob/living/carbon/victim) + var/grab_dir = turn(victim.dir, pick(-90, 90, 180, 180)) // Not in front, favour behind + var/turf/spawn_turf = get_ranged_target_turf(victim, grab_dir, 8) + if (isnull(spawn_turf)) + return + new /obj/effect/temp_visual/dir_setting/curse/grasp_portal(spawn_turf, victim.dir) + playsound(spawn_turf, 'sound/effects/curse2.ogg', 80, TRUE, -1) + var/obj/projectile/curse_hand/hel/hand = new (spawn_turf) + hand.preparePixelProjectile(victim, spawn_turf) + if (QDELETED(hand)) // safety check if above fails - above has a stack trace if it does fail + return + hand.fire() diff --git a/code/modules/antagonists/heretic/knowledge/sacrifice_knowledge/sacrifice_curse.dm b/code/modules/antagonists/heretic/knowledge/sacrifice_knowledge/sacrifice_curse.dm new file mode 100644 index 000000000000..6a12ecc30922 --- /dev/null +++ b/code/modules/antagonists/heretic/knowledge/sacrifice_knowledge/sacrifice_curse.dm @@ -0,0 +1,93 @@ +/// A curse given to people to disencourage them from retaliating against someone who sacrificed them +/datum/status_effect/heretic_curse + id = "heretic_curse" + alert_type = null + status_type = STATUS_EFFECT_MULTIPLE // In case several different people sacrifice you, unlucky + /// Who cursed us? + var/mob/living/the_curser + /// Don't experience bad things too often + COOLDOWN_DECLARE(consequence_cooldown) + +/datum/status_effect/heretic_curse/on_creation(mob/living/new_owner, mob/living/the_curser) + src.the_curser = the_curser + return ..() + +/datum/status_effect/heretic_curse/Destroy() + the_curser = null + return ..() + +/datum/status_effect/heretic_curse/on_apply() + if (isnull(the_curser) || !iscarbon(owner)) + return FALSE + + the_curser.AddElement(/datum/element/relay_attackers) + RegisterSignal(the_curser, COMSIG_ATOM_WAS_ATTACKED, PROC_REF(on_curser_attacked)) + RegisterSignal(the_curser, COMSIG_QDELETING, PROC_REF(on_curser_destroyed)) + + owner.AddElement(/datum/element/relay_attackers) + RegisterSignal(owner, COMSIG_ATOM_WAS_ATTACKED, PROC_REF(on_owner_attacked)) + + return TRUE + +/datum/status_effect/heretic_curse/on_remove() + UnregisterSignal(owner, COMSIG_ATOM_WAS_ATTACKED) + UnregisterSignal(the_curser, COMSIG_ATOM_WAS_ATTACKED) + the_curser = null + + +/// If the heretic that cursed us is destroyed this thing is useless now +/datum/status_effect/heretic_curse/proc/on_curser_destroyed() + SIGNAL_HANDLER + qdel(src) + +/// If we attack the guy who cursed us, that's no good +/datum/status_effect/heretic_curse/proc/on_curser_attacked(datum/source, mob/attacker) + SIGNAL_HANDLER + if (attacker != owner || !HAS_TRAIT(source, TRAIT_ALLOW_HERETIC_CASTING)) + return + log_combat(owner, the_curser, "attacked", addition = "and lost some organs because they had previously been sacrificed by them.") + experience_the_consequences() + +/// If we are attacked by the guy who cursed us, that's also no good +/datum/status_effect/heretic_curse/proc/on_owner_attacked(datum/source, mob/attacker) + SIGNAL_HANDLER + if (attacker != the_curser || !HAS_TRAIT(attacker, TRAIT_ALLOW_HERETIC_CASTING)) + return + log_combat(the_curser, owner, "attacked", addition = "and as they had previously sacrificed them, removed some of their organs.") + experience_the_consequences() + +/// Experience something you may not enjoy which may also significantly shorten your lifespan +/datum/status_effect/heretic_curse/proc/experience_the_consequences() + if (!COOLDOWN_FINISHED(src, consequence_cooldown) || owner.stat != CONSCIOUS) + return + + var/mob/living/carbon/carbon_owner = owner + var/obj/item/bodypart/chest/organ_storage = owner.get_bodypart(BODY_ZONE_CHEST) + if (isnull(organ_storage)) + carbon_owner.gib() // IDK how you don't have a chest but you're not getting away that easily + return + + var/list/removable_organs = list() + for(var/obj/item/organ/internal/bodypart_organ in organ_storage.contents) + if(bodypart_organ.organ_flags & ORGAN_UNREMOVABLE) + continue + removable_organs += bodypart_organ + + if (!length(removable_organs)) + return // This one is a little more possible but they're probably already in pretty bad shape by this point + + var/obj/item/organ/internal/removing_organ = pick(removable_organs) + + if (carbon_owner.vomit(blood = TRUE)) + carbon_owner.visible_message(span_boldwarning("[carbon_owner] vomits out [carbon_owner.p_their()] [removing_organ]")) + else + carbon_owner.visible_message(span_boldwarning("[carbon_owner]'s [removing_organ] rips itself out of `[carbon_owner.p_their()] chest!")) + + removing_organ.Remove(carbon_owner) + + var/turf/land_turf = get_step(carbon_owner, carbon_owner.dir) + if (land_turf.is_blocked_turf(exclude_mobs = TRUE)) + land_turf = carbon_owner.drop_location() + + removing_organ.forceMove(land_turf) + COOLDOWN_START(src, consequence_cooldown, 10 SECONDS) diff --git a/code/modules/reagents/chemistry/reagents/impure_reagents/impure_medicine_reagents.dm b/code/modules/reagents/chemistry/reagents/impure_reagents/impure_medicine_reagents.dm index 1f38e6377b6e..25b2d4113204 100644 --- a/code/modules/reagents/chemistry/reagents/impure_reagents/impure_medicine_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/impure_reagents/impure_medicine_reagents.dm @@ -98,18 +98,7 @@ Basically, we fill the time between now and 2s from now with hands based off the /datum/reagent/inverse/helgrasp/proc/spawn_hands(mob/living/carbon/owner) if(!owner && iscarbon(holder.my_atom))//Catch timer owner = holder.my_atom - //Adapted from the end of the curse - but lasts a short time - var/grab_dir = turn(owner.dir, pick(-90, 90, 180, 180)) //grab them from a random direction other than the one faced, favoring grabbing from behind - var/turf/spawn_turf = get_ranged_target_turf(owner, grab_dir, 8)//Larger range so you have more time to dodge - if(!spawn_turf) - return - new/obj/effect/temp_visual/dir_setting/curse/grasp_portal(spawn_turf, owner.dir) - playsound(spawn_turf, 'sound/effects/curse2.ogg', 80, TRUE, -1) - var/obj/projectile/curse_hand/hel/hand = new (spawn_turf) - hand.preparePixelProjectile(owner, spawn_turf) - if(QDELETED(hand)) //safety check if above fails - above has a stack trace if it does fail - return - hand.fire() + fire_curse_hand(owner) //At the end, we clear up any loose hanging timers just in case and spawn any remaining lag_remaining hands all at once. /datum/reagent/inverse/helgrasp/on_mob_delete(mob/living/owner) diff --git a/monkestation/code/modules/antagonists/heretic/knowledge/sacrifice_knowledge/sacrifice_knowledge.dm b/monkestation/code/modules/antagonists/heretic/knowledge/sacrifice_knowledge/sacrifice_knowledge.dm index fc06138a24d0..c78a25f763c3 100644 --- a/monkestation/code/modules/antagonists/heretic/knowledge/sacrifice_knowledge/sacrifice_knowledge.dm +++ b/monkestation/code/modules/antagonists/heretic/knowledge/sacrifice_knowledge/sacrifice_knowledge.dm @@ -26,6 +26,16 @@ var/datum/mind/heretic_mind /// An assoc list of [ref] to [timers] - a list of all the timers of people in the shadow realm currently var/list/return_timers + /// Evil organs we can put in people + var/static/list/grantable_organs = list( + /obj/item/organ/internal/appendix/corrupt, + /obj/item/organ/internal/eyes/corrupt, + /obj/item/organ/internal/heart/corrupt, + /obj/item/organ/internal/liver/corrupt, + /obj/item/organ/internal/lungs/corrupt, + /obj/item/organ/internal/stomach/corrupt, + /obj/item/organ/internal/tongue/corrupt, + ) /datum/heretic_knowledge/hunt_and_sacrifice/Destroy(force) heretic_mind = null @@ -199,6 +209,8 @@ heretic_datum.total_sacrifices++ heretic_datum.knowledge_points += 2 + sacrifice.apply_status_effect(/datum/status_effect/heretic_curse, user) + if(!begin_sacrifice(sacrifice)) disembowel_target(sacrifice) @@ -291,6 +303,8 @@ disembowel_target(sac_target) return + curse_organs(sac_target) + // Send 'em to the destination. If the teleport fails, just disembowel them and stop the chain if(!destination || !do_teleport(sac_target, destination, asoundin = 'sound/magic/repulse.ogg', asoundout = 'sound/magic/blind.ogg', no_effects = TRUE, channel = TELEPORT_CHANNEL_MAGIC, forced = TRUE)) disembowel_target(sac_target) @@ -313,6 +327,31 @@ RegisterSignal(sac_target, COMSIG_MOVABLE_Z_CHANGED, PROC_REF(on_target_escape)) // Cheese condition RegisterSignal(sac_target, COMSIG_LIVING_DEATH, PROC_REF(on_target_death)) // Loss condition +/// Apply a sinister curse to some of the target's organs as an incentive to leave us alone +/datum/heretic_knowledge/hunt_and_sacrifice/proc/curse_organs(mob/living/carbon/human/sac_target) + var/usable_organs = grantable_organs.Copy() + if (isplasmaman(sac_target)) + usable_organs -= /obj/item/organ/internal/lungs/corrupt // Their lungs are already more cursed than anything I could give them + + var/total_implant = rand(2, 4) + var/gave_any = FALSE + + for (var/i in 1 to total_implant) + if (!length(usable_organs)) + break + var/organ_path = pick_n_take(usable_organs) + var/obj/item/organ/internal/to_give = new organ_path + if (!to_give.Insert(sac_target)) + qdel(to_give) + else + gave_any = TRUE + + if (!gave_any) + return + + new /obj/effect/gibspawner/human/bodypartless(get_turf(sac_target)) + sac_target.visible_message(span_boldwarning("Several organs force themselves out of [sac_target]!")) + /** * This proc is called from [proc/after_target_sleeps] when the [sac_target] should be waking up.) * @@ -389,8 +428,6 @@ if(IS_HERETIC(sac_target)) var/datum/antagonist/heretic/victim_heretic = sac_target.mind?.has_antag_datum(/datum/antagonist/heretic) victim_heretic.knowledge_points -= 3 - else - sac_target.gain_trauma(/datum/brain_trauma/mild/phobia/heresy, TRAUMA_RESILIENCE_LOBOTOMY) // monke edit: allow lobotomy to cure the phobia // Wherever we end up, we sure as hell won't be able to explain sac_target.adjust_timed_status_effect(40 SECONDS, /datum/status_effect/speech/slurring/heretic) sac_target.adjust_stutter(40 SECONDS) diff --git a/tgstation.dme b/tgstation.dme index 6ca9cc211af2..56fa38aa8976 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -1391,6 +1391,7 @@ #include "code\datums\elements\climbable.dm" #include "code\datums\elements\connect_loc.dm" #include "code\datums\elements\content_barfer.dm" +#include "code\datums\elements\corrupted_organ.dm" #include "code\datums\elements\crackable.dm" #include "code\datums\elements\crusher_loot.dm" #include "code\datums\elements\cult_eyes.dm" @@ -2944,6 +2945,7 @@ #include "code\modules\antagonists\heretic\moon_lunatic.dm" #include "code\modules\antagonists\heretic\rust_effect.dm" #include "code\modules\antagonists\heretic\transmutation_rune.dm" +#include "code\modules\antagonists\heretic\items\corrupted_organs.dm" #include "code\modules\antagonists\heretic\items\eldritch_flask.dm" #include "code\modules\antagonists\heretic\items\eldritch_painting.dm" #include "code\modules\antagonists\heretic\items\forbidden_book.dm" @@ -2974,6 +2976,7 @@ #include "code\modules\antagonists\heretic\knowledge\starting_lore.dm" #include "code\modules\antagonists\heretic\knowledge\void_lore.dm" #include "code\modules\antagonists\heretic\knowledge\sacrifice_knowledge\sacrifice_buff.dm" +#include "code\modules\antagonists\heretic\knowledge\sacrifice_knowledge\sacrifice_curse.dm" #include "code\modules\antagonists\heretic\knowledge\sacrifice_knowledge\sacrifice_knowledge.dm" #include "code\modules\antagonists\heretic\knowledge\sacrifice_knowledge\sacrifice_map.dm" #include "code\modules\antagonists\heretic\knowledge\sacrifice_knowledge\sacrifice_moodlets.dm" From c63c462a21bb307fffa1175a3261ab9a67d60dc2 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 20 Dec 2024 05:36:43 +0000 Subject: [PATCH 29/81] Automatic changelog for PR #4475 [ci skip] --- html/changelogs/AutoChangeLog-pr-4475.yml | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-4475.yml diff --git a/html/changelogs/AutoChangeLog-pr-4475.yml b/html/changelogs/AutoChangeLog-pr-4475.yml new file mode 100644 index 000000000000..fdd83d337655 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-4475.yml @@ -0,0 +1,6 @@ +author: "Wisemonster, Jacquerel" +delete-after: True +changes: + - rscdel: "Being sacrificed by a Heretic no longer gives you an incurable phobia." + - rscadd: "Being sacrificed by a Heretic will drop 2-4 of your organs on the ground and replace them with \"corrupt organs\" with negative effects which can be suppressed with Holy Water." + - rscadd: "Players who have been sacrificed by Heretics will experience additional and rapidly lethal consequences for attempting to fight someone who previously sacrificed them, as long as that person is wearing a focus." \ No newline at end of file From d5d889d84686fea083edf913d7c183ce88661ab2 Mon Sep 17 00:00:00 2001 From: Coll6 Date: Thu, 19 Dec 2024 23:02:11 -0700 Subject: [PATCH 30/81] [Code Bounty] Unreviewed Mixtape Refund + Bonus (#4414) * Refunds coin on unreviewed cassettes at end round * Fixes refund not returned when different mob * Fix small bug preventing tape from being destroyed * Slight formatting for clarity. * Merge conflict fix. * Adds base for admin review cassettes verb in menu * Change to TGUI using a fun menu as a base. * Interface implemented and basic funcs working. * Interfaceshows if a cassette is denied or approved * Slight refactor. Fixed Reveiwed UI spam + Features * Refactor jsx to jtx * Applies suggestions. --- code/__HELPERS/roundend.dm | 1 + .../~monkestation-helpers/roundend.dm | 23 +++++ code/modules/admin/admin_verbs.dm | 3 +- .../modules/cassettes/cassette_approval.dm | 87 +++++++++++++++-- .../tgui/interfaces/CassetteManager.tsx | 97 +++++++++++++++++++ .../tgui/interfaces/CassetteReview.jsx | 20 +++- 6 files changed, 217 insertions(+), 14 deletions(-) create mode 100644 tgui/packages/tgui/interfaces/CassetteManager.tsx diff --git a/code/__HELPERS/roundend.dm b/code/__HELPERS/roundend.dm index e367535713bc..7112c0447ae6 100644 --- a/code/__HELPERS/roundend.dm +++ b/code/__HELPERS/roundend.dm @@ -301,6 +301,7 @@ GLOBAL_LIST_INIT(round_end_images, world.file2list("data/image_urls.txt")) // MO // monkestation start: token backups, monkecoin rewards, challenges, and roundend webhook save_tokens() + refund_cassette() distribute_rewards() sleep(5 SECONDS) ready_for_reboot = TRUE diff --git a/code/__HELPERS/~monkestation-helpers/roundend.dm b/code/__HELPERS/~monkestation-helpers/roundend.dm index 082c3aaeca38..b6bfb7fc59f0 100644 --- a/code/__HELPERS/~monkestation-helpers/roundend.dm +++ b/code/__HELPERS/~monkestation-helpers/roundend.dm @@ -36,3 +36,26 @@ total_payout += listed_challenge.challenge_payout if(total_payout) client?.prefs?.adjust_metacoins(client?.ckey, total_payout, "Challenge rewards.") + +/datum/controller/subsystem/ticker/proc/refund_cassette() + if(!length(GLOB.cassette_reviews)) + return + + for(var/id in GLOB.cassette_reviews) + var/datum/cassette_review/review = GLOB.cassette_reviews[id] + if(!review || review.action_taken) // Skip if review doesn't exist or already handled (denied / approved) + continue + + var/ownerckey = review.submitted_ckey // ckey of who made the cassette. + if(!ownerckey) + continue + + var/client/client = GLOB.directory[ownerckey] // Use directory for direct lookup (Client might be a differnet mob than when review was made.) + if(client && !QDELETED(client?.prefs)) + var/adjusted = client?.prefs?.adjust_metacoins( + client?.ckey, 5000, + reason = "No action taken on cassette:\[[review.submitted_tape.name]\] before round end.", + announces = TRUE, donator_multipler = FALSE + ) + if(adjusted) + qdel(review) diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm index 3a6bf818b77b..21a8ed975fdd 100644 --- a/code/modules/admin/admin_verbs.dm +++ b/code/modules/admin/admin_verbs.dm @@ -19,6 +19,7 @@ GLOBAL_PROTECT(admin_verbs_default) /client/proc/reload_admins, /client/proc/requests, /client/proc/secrets, + /client/proc/review_cassettes, /*monkestation addition Opens the Cassette Review menu*/ /client/proc/stop_sounds, /client/proc/tag_datum_mapview, ) @@ -159,7 +160,7 @@ GLOBAL_LIST_INIT(admin_verbs_fun, list( /client/proc/toggle_random_events, )) GLOBAL_PROTECT(admin_verbs_fun) -GLOBAL_LIST_INIT(admin_verbs_spawn, list(/datum/admins/proc/spawn_atom, /datum/admins/proc/podspawn_atom, /datum/admins/proc/spawn_cargo, /datum/admins/proc/spawn_objasmob, /client/proc/respawn_character, /datum/admins/proc/beaker_panel, /client/proc/spawn_mixtape)) //Monkestation Addition: mixtape spawner +GLOBAL_LIST_INIT(admin_verbs_spawn, list(/datum/admins/proc/spawn_atom, /datum/admins/proc/podspawn_atom, /datum/admins/proc/spawn_cargo, /datum/admins/proc/spawn_objasmob, /client/proc/respawn_character, /datum/admins/proc/beaker_panel, /client/proc/spawn_mixtape,)) //Monkestation Addition: mixtape spawner GLOBAL_PROTECT(admin_verbs_spawn) GLOBAL_LIST_INIT(admin_verbs_server, world.AVerbsServer()) GLOBAL_PROTECT(admin_verbs_server) diff --git a/monkestation/code/modules/cassettes/cassette_approval.dm b/monkestation/code/modules/cassettes/cassette_approval.dm index dce781859162..69f7306c8574 100644 --- a/monkestation/code/modules/cassettes/cassette_approval.dm +++ b/monkestation/code/modules/cassettes/cassette_approval.dm @@ -73,26 +73,21 @@ GLOBAL_LIST_INIT(cassette_reviews, list()) var/obj/item/device/cassette_tape/submitted_tape var/action_taken = FALSE + var/verdict = "NONE" /datum/cassette_review/Destroy(force) . = ..() - QDEL_LIST(cassette_data) + if(cassette_data) + QDEL_LIST(cassette_data) submitter = null - - GLOB.cassette_reviews["[id]"] -= src - GLOB.cassette_reviews -= id + if(id && (id in GLOB.cassette_reviews)) + GLOB.cassette_reviews -= id // Remove the key /datum/cassette_review/ui_state(mob/user) return GLOB.always_state /datum/cassette_review/ui_interact(mob/user, datum/tgui/ui) . = ..() - if(action_taken) - var/choice = tgui_alert(user, "This tape has already been actioned by another admin do you wish to look it over?", "Cassette Review", list("Yes", "No")) - if(!choice) - return - if(choice == "No") - return ui = SStgui.try_update_ui(user, src, ui) if(!ui) @@ -107,6 +102,8 @@ GLOBAL_LIST_INIT(cassette_reviews, list()) data["submitters_name"] = submitter.real_name data["side1"] = cassette_data["side1"] data["side2"] = cassette_data["side2"] + data["reviewed"] = action_taken + data["verdict"] = verdict return data @@ -121,6 +118,11 @@ GLOBAL_LIST_INIT(cassette_reviews, list()) to_chat(submitter, span_warning("You feel a wave of disapointment wash over you, you can tell that your cassette was denied by the Space Board of Music")) logger.Log(LOG_CATEGORY_MUSIC, "[submitter]'s tape has been rejected by [usr]", list("approver" = usr.name, "submitter" = submitter.name)) action_taken = TRUE + verdict = "DENIED" + +/datum/cassette_review/ui_close()// Don't leave orphaned datums laying around. Hopefully this handles timeouts? + . = ..() + qdel(src) /datum/cassette_review/proc/approve_review(mob/user) if(!check_rights_for(user.client, R_FUN)) @@ -131,8 +133,73 @@ GLOBAL_LIST_INIT(cassette_reviews, list()) message_admins("[submitter]'s tape has been approved by [user]") logger.Log(LOG_CATEGORY_MUSIC, "[submitter]'s tape has been approved by [user]", list("approver" = user.name, "submitter" = submitter.name)) action_taken = TRUE + verdict = "APPROVED" /proc/fetch_review(id) return GLOB.cassette_reviews[id] #undef ADMIN_OPEN_REVIEW + +// Handles UI to manage cassettes. +/client/proc/review_cassettes() //Creates a verb for admins to open up the ui + set name = "Review Cassettes" + set desc = "Review this rounds cassettes." + set category = "Admin.Game" + if(!check_rights(R_FUN)) + return + new /datum/review_cassettes(usr) + +/datum/review_cassettes + var/client/holder //client of whoever is using this datum + var/is_funmin = FALSE + +/datum/review_cassettes/New(user)//user can either be a client or a mob due to byondcode(tm) + holder = get_player_client(user) + is_funmin = check_rights(R_FUN) + ui_interact(holder.mob)//datum has a tgui component, here we open the window + +/datum/review_cassettes/ui_status(mob/user, datum/ui_state/state) + return (user.client == holder && is_funmin) ? UI_INTERACTIVE : UI_CLOSE + + +/datum/review_cassettes/ui_close()// Don't leave orphaned datums laying around. Hopefully this handles timeouts? + qdel(src) + +/datum/review_cassettes/ui_interact(mob/user, datum/tgui/ui) // Open UI and update as it remains open. + . = ..() + + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "CassetteManager") + ui.open() + +/datum/review_cassettes/ui_data(mob/user) + . = ..() + var/list/data = list("cassettes" = list()) // Initialize main data structure with an empty "cassettes" list + + for(var/cassette_id in GLOB.cassette_reviews) + var/datum/cassette_review/cassette = GLOB.cassette_reviews[cassette_id] + var/submitters_name = cassette.submitter + var/obj/item/tape_obj = cassette.submitted_tape + var/reviewed = cassette.action_taken + var/verdict = cassette.verdict + + // Add this cassette's data under its cassette_id + data["cassettes"][cassette_id] = list( + "submitter_name" = submitters_name, + "tape_name" = tape_obj.name, + "reviewed" = reviewed, + "verdict" = verdict, + ) + return data + +/datum/review_cassettes/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) + . = ..() + if(.) + return + if(!length(GLOB.cassette_reviews) || !GLOB.cassette_reviews[action]) + return + + var/datum/cassette_review/cassette = GLOB.cassette_reviews[action] + cassette.ui_interact(ui.user) + diff --git a/tgui/packages/tgui/interfaces/CassetteManager.tsx b/tgui/packages/tgui/interfaces/CassetteManager.tsx new file mode 100644 index 000000000000..f1d596966167 --- /dev/null +++ b/tgui/packages/tgui/interfaces/CassetteManager.tsx @@ -0,0 +1,97 @@ +import { useBackend } from '../backend'; +import { Section, Table, Button } from '../components'; +import { Window } from '../layouts'; +type CassetteDetails = { + submitter_name: string; + tape_name: string; + reviewed: boolean; + verdict: string; +}; + +type CassetteReviewData = { + // List of submitted cassettes. Each cassette id is in hexID_ckey format. + cassettes: Record; +}; + +export const CassetteManager = (props) => { + const { act, data } = useBackend(); + const { cassettes } = data; + + // Convert cassettes object into an array to iterate our buttons + const cassetteEntries = Object.entries(cassettes); + + return ( + + +
+ act(id)} + /> +
+
+
+ ); +}; + +const CassetteTable = ({ + entries, + onReview, +}: { + entries: [string, CassetteDetails][]; + onReview: (id: string) => void; +}) => { + // If entries is not provided or is empty, show a message instead of the table. + if (!entries || entries.length === 0) { + return Nothing to review. The Jam's must flow.; + } + return ( + + + Cassette ID_CKey + Submitter + Title + Reviewed + Action + + + {entries.map(([id, cassette]) => ( + + {id} + {cassette.submitter_name} + {cassette.tape_name} + {cassette.reviewed ? 'Yes' : 'No'} + + onReview(id)} + /> + + + ))} +
+ ); +}; + +const ReviewButton = ({ + reviewed, + verdict, + onClick, +}: { + reviewed: boolean; + verdict: string; + onClick: () => void; +}) => { + const { buttonText, buttonColor } = reviewed + ? verdict === 'APPROVED' + ? { buttonText: 'Approved', buttonColor: 'good' } + : { buttonText: 'Denied', buttonColor: 'bad' } + : { buttonText: 'Pending', buttonColor: undefined }; + + return ( + + ); +}; diff --git a/tgui/packages/tgui/interfaces/CassetteReview.jsx b/tgui/packages/tgui/interfaces/CassetteReview.jsx index 40475e57ec02..9f68a50218a2 100644 --- a/tgui/packages/tgui/interfaces/CassetteReview.jsx +++ b/tgui/packages/tgui/interfaces/CassetteReview.jsx @@ -4,7 +4,7 @@ import { Section, Box, Button, Flex } from '../components'; export const CassetteReview = (props) => { const { act, data } = useBackend(); - const { ckey, submitters_name, side1, side2 } = data; + const { ckey, submitters_name, side1, side2, reviewed, verdict } = data; return ( @@ -34,8 +34,22 @@ export const CassetteReview = (props) => { - - + {reviewed ? ( + verdict === 'APPROVED' ? ( + +
Approved
+
+ ) : ( + +
Denied
+
+ ) + ) : ( + <> + + + + )}
From daf6ddd77e9b838335fc4ad3f0df1e3c7368aeb0 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 20 Dec 2024 06:02:30 +0000 Subject: [PATCH 31/81] Automatic changelog for PR #4414 [ci skip] --- html/changelogs/AutoChangeLog-pr-4414.yml | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-4414.yml diff --git a/html/changelogs/AutoChangeLog-pr-4414.yml b/html/changelogs/AutoChangeLog-pr-4414.yml new file mode 100644 index 000000000000..7c1e26d01425 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-4414.yml @@ -0,0 +1,9 @@ +author: "Siro" +delete-after: True +changes: + - rscadd: "Refunding of unreviewed mixtapes at round end" + - rscadd: "Cassette Manager interface" + - rscadd: "Admin.Games Review Cassettes to the admin menu" + - rscdel: "tgui alert for already reviewed cassettes" + - bugfix: "tgui alert spamming the client when attempting to review an already reviewed cassette." + - bugfix: "Runtime error on cassette_review Destroy proc" \ No newline at end of file From a7a9f75a2f3f8506e20c1e535ce0ec3febb53452 Mon Sep 17 00:00:00 2001 From: Changelogs Date: Fri, 20 Dec 2024 06:05:07 +0000 Subject: [PATCH 32/81] Automatic changelog compile [ci skip] --- html/changelogs/AutoChangeLog-pr-4414.yml | 9 --------- html/changelogs/AutoChangeLog-pr-4475.yml | 6 ------ html/changelogs/AutoChangeLog-pr-4532.yml | 4 ---- html/changelogs/AutoChangeLog-pr-4619.yml | 4 ---- html/changelogs/AutoChangeLog-pr-4620.yml | 4 ---- html/changelogs/archive/2024-12.yml | 23 +++++++++++++++++++++++ 6 files changed, 23 insertions(+), 27 deletions(-) delete mode 100644 html/changelogs/AutoChangeLog-pr-4414.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-4475.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-4532.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-4619.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-4620.yml diff --git a/html/changelogs/AutoChangeLog-pr-4414.yml b/html/changelogs/AutoChangeLog-pr-4414.yml deleted file mode 100644 index 7c1e26d01425..000000000000 --- a/html/changelogs/AutoChangeLog-pr-4414.yml +++ /dev/null @@ -1,9 +0,0 @@ -author: "Siro" -delete-after: True -changes: - - rscadd: "Refunding of unreviewed mixtapes at round end" - - rscadd: "Cassette Manager interface" - - rscadd: "Admin.Games Review Cassettes to the admin menu" - - rscdel: "tgui alert for already reviewed cassettes" - - bugfix: "tgui alert spamming the client when attempting to review an already reviewed cassette." - - bugfix: "Runtime error on cassette_review Destroy proc" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-4475.yml b/html/changelogs/AutoChangeLog-pr-4475.yml deleted file mode 100644 index fdd83d337655..000000000000 --- a/html/changelogs/AutoChangeLog-pr-4475.yml +++ /dev/null @@ -1,6 +0,0 @@ -author: "Wisemonster, Jacquerel" -delete-after: True -changes: - - rscdel: "Being sacrificed by a Heretic no longer gives you an incurable phobia." - - rscadd: "Being sacrificed by a Heretic will drop 2-4 of your organs on the ground and replace them with \"corrupt organs\" with negative effects which can be suppressed with Holy Water." - - rscadd: "Players who have been sacrificed by Heretics will experience additional and rapidly lethal consequences for attempting to fight someone who previously sacrificed them, as long as that person is wearing a focus." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-4532.yml b/html/changelogs/AutoChangeLog-pr-4532.yml deleted file mode 100644 index 6f9ce916bb99..000000000000 --- a/html/changelogs/AutoChangeLog-pr-4532.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Absolucy" -delete-after: True -changes: - - admin: "Added a new mapping verb, Export Lighting Info (behind Mapping Verbs - Enable) that exports the lighting info of z levels into a json file." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-4619.yml b/html/changelogs/AutoChangeLog-pr-4619.yml deleted file mode 100644 index b4cebab4e159..000000000000 --- a/html/changelogs/AutoChangeLog-pr-4619.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Absolucy" -delete-after: True -changes: - - bugfix: "Slime in vents/slime grinders/etc will no longer secrete ooze on the floor." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-4620.yml b/html/changelogs/AutoChangeLog-pr-4620.yml deleted file mode 100644 index 461660252a14..000000000000 --- a/html/changelogs/AutoChangeLog-pr-4620.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Absolucy" -delete-after: True -changes: - - bugfix: "The xenobio Slimeperson and Luminscent subspecies will now properly get slime wings from drinking a flight potion." \ No newline at end of file diff --git a/html/changelogs/archive/2024-12.yml b/html/changelogs/archive/2024-12.yml index 662babff5757..95c9a8b7c5d7 100644 --- a/html/changelogs/archive/2024-12.yml +++ b/html/changelogs/archive/2024-12.yml @@ -314,3 +314,26 @@ to spawn properly Uristthedorf: - rscadd: EMPing a holosign creator, will destroy all of the holosigns. +2024-12-20: + Absolucy: + - bugfix: The xenobio Slimeperson and Luminscent subspecies will now properly get + slime wings from drinking a flight potion. + - bugfix: Slime in vents/slime grinders/etc will no longer secrete ooze on the floor. + - admin: Added a new mapping verb, Export Lighting Info (behind Mapping Verbs - + Enable) that exports the lighting info of z levels into a json file. + Siro: + - rscadd: Refunding of unreviewed mixtapes at round end + - rscadd: Cassette Manager interface + - rscadd: Admin.Games Review Cassettes to the admin menu + - rscdel: tgui alert for already reviewed cassettes + - bugfix: tgui alert spamming the client when attempting to review an already reviewed + cassette. + - bugfix: Runtime error on cassette_review Destroy proc + Wisemonster, Jacquerel: + - rscdel: Being sacrificed by a Heretic no longer gives you an incurable phobia. + - rscadd: Being sacrificed by a Heretic will drop 2-4 of your organs on the ground + and replace them with "corrupt organs" with negative effects which can be suppressed + with Holy Water. + - rscadd: Players who have been sacrificed by Heretics will experience additional + and rapidly lethal consequences for attempting to fight someone who previously + sacrificed them, as long as that person is wearing a focus. From 75fddc3a2ba595a6d884c3cfb4851a3161dace1b Mon Sep 17 00:00:00 2001 From: Uristthedorf <40842973+Uristthedorf@users.noreply.github.com> Date: Fri, 20 Dec 2024 15:29:38 -0800 Subject: [PATCH 33/81] Removes tasers from the armory (#4624) * Removes tasers from the armory * Update VoidRaptor.dmm * Update security.dm --- _maps/map_files/Blueshift/Blueshift.dmm | 3 --- _maps/map_files/BoxStation/BoxStation.dmm | 9 --------- _maps/map_files/Deltastation/DeltaStation2.dmm | 3 --- _maps/map_files/Graveyard/Graveyard.dmm | 3 --- _maps/map_files/IceBoxStation/IceBoxStation.dmm | 3 --- _maps/map_files/KiloStation/KiloStation.dmm | 3 --- _maps/map_files/MetaStation/MetaStation.dmm | 3 --- _maps/map_files/Ouroboros/Ouroboros.dmm | 3 --- _maps/map_files/Voidraptor/VoidRaptor.dmm | 3 --- _maps/map_files/tramstation/tramstation.dmm | 3 --- monkestation/code/modules/cargo/crates/security.dm | 7 +++++++ 11 files changed, 7 insertions(+), 36 deletions(-) diff --git a/_maps/map_files/Blueshift/Blueshift.dmm b/_maps/map_files/Blueshift/Blueshift.dmm index 12e55043d40d..250dae6db367 100644 --- a/_maps/map_files/Blueshift/Blueshift.dmm +++ b/_maps/map_files/Blueshift/Blueshift.dmm @@ -52113,9 +52113,6 @@ /obj/effect/turf_decal/trimline/red/line{ dir = 8 }, -/obj/item/gun/energy/taser, -/obj/item/gun/energy/taser, -/obj/item/gun/energy/taser, /turf/open/floor/iron/dark/textured, /area/station/ai_monitored/security/armory) "kdO" = ( diff --git a/_maps/map_files/BoxStation/BoxStation.dmm b/_maps/map_files/BoxStation/BoxStation.dmm index 82cec3c519f6..8be6a9fced01 100644 --- a/_maps/map_files/BoxStation/BoxStation.dmm +++ b/_maps/map_files/BoxStation/BoxStation.dmm @@ -26105,15 +26105,6 @@ pixel_x = 3; pixel_y = -3 }, -/obj/item/gun/energy/taser{ - pixel_y = 3; - pixel_x = -3 - }, -/obj/item/gun/energy/taser, -/obj/item/gun/energy/taser{ - pixel_y = -3; - pixel_x = 3 - }, /turf/open/floor/iron/dark, /area/station/ai_monitored/security/armory) "iuJ" = ( diff --git a/_maps/map_files/Deltastation/DeltaStation2.dmm b/_maps/map_files/Deltastation/DeltaStation2.dmm index ef6c57926b9b..d1615ee5cb8e 100644 --- a/_maps/map_files/Deltastation/DeltaStation2.dmm +++ b/_maps/map_files/Deltastation/DeltaStation2.dmm @@ -48942,9 +48942,6 @@ }, /obj/effect/turf_decal/bot, /obj/effect/turf_decal/tile/neutral/fourcorners, -/obj/item/gun/energy/taser, -/obj/item/gun/energy/taser, -/obj/item/gun/energy/taser, /turf/open/floor/iron/dark, /area/station/ai_monitored/security/armory) "lzH" = ( diff --git a/_maps/map_files/Graveyard/Graveyard.dmm b/_maps/map_files/Graveyard/Graveyard.dmm index 5d56e33ab206..3ddc9961a7bf 100644 --- a/_maps/map_files/Graveyard/Graveyard.dmm +++ b/_maps/map_files/Graveyard/Graveyard.dmm @@ -32366,9 +32366,6 @@ /obj/item/gun/ballistic/automatic/pistol/paco/no_mag{ pixel_y = 6 }, -/obj/item/gun/energy/taser, -/obj/item/gun/energy/taser, -/obj/item/gun/energy/taser, /obj/effect/turf_decal/tile/dark_red/half{ dir = 1 }, diff --git a/_maps/map_files/IceBoxStation/IceBoxStation.dmm b/_maps/map_files/IceBoxStation/IceBoxStation.dmm index fbd64deb4e24..73d3fce608a4 100644 --- a/_maps/map_files/IceBoxStation/IceBoxStation.dmm +++ b/_maps/map_files/IceBoxStation/IceBoxStation.dmm @@ -8895,9 +8895,6 @@ /obj/item/gun/ballistic/automatic/pistol/paco/no_mag{ pixel_y = 0 }, -/obj/item/gun/energy/taser, -/obj/item/gun/energy/taser, -/obj/item/gun/energy/taser, /turf/open/floor/iron/dark/textured, /area/station/ai_monitored/security/armory/upper) "cIH" = ( diff --git a/_maps/map_files/KiloStation/KiloStation.dmm b/_maps/map_files/KiloStation/KiloStation.dmm index 4d310a600bef..2905e94873ef 100644 --- a/_maps/map_files/KiloStation/KiloStation.dmm +++ b/_maps/map_files/KiloStation/KiloStation.dmm @@ -15352,9 +15352,6 @@ /obj/structure/window/reinforced/spawner/directional/south, /obj/structure/window/reinforced/spawner/directional/west, /obj/effect/turf_decal/tile/neutral/anticorner/contrasted, -/obj/item/gun/energy/taser, -/obj/item/gun/energy/taser, -/obj/item/gun/energy/taser, /turf/open/floor/iron/dark/textured_large, /area/station/ai_monitored/security/armory) "eRh" = ( diff --git a/_maps/map_files/MetaStation/MetaStation.dmm b/_maps/map_files/MetaStation/MetaStation.dmm index 75b2cdf82042..427bd05d6564 100644 --- a/_maps/map_files/MetaStation/MetaStation.dmm +++ b/_maps/map_files/MetaStation/MetaStation.dmm @@ -33406,9 +33406,6 @@ /obj/item/gun/ballistic/automatic/pistol/paco/no_mag{ pixel_y = 6 }, -/obj/item/gun/energy/taser, -/obj/item/gun/energy/taser, -/obj/item/gun/energy/taser, /turf/open/floor/iron/dark, /area/station/ai_monitored/security/armory) "lFo" = ( diff --git a/_maps/map_files/Ouroboros/Ouroboros.dmm b/_maps/map_files/Ouroboros/Ouroboros.dmm index fd7f4d0f0e21..593c6d5967e5 100644 --- a/_maps/map_files/Ouroboros/Ouroboros.dmm +++ b/_maps/map_files/Ouroboros/Ouroboros.dmm @@ -28538,9 +28538,6 @@ c_tag = "Security - Armory" }, /obj/effect/spawner/random/armory/disablers, -/obj/item/gun/energy/taser, -/obj/item/gun/energy/taser, -/obj/item/gun/energy/taser, /turf/open/floor/engine, /area/station/ai_monitored/security/armory) "ixo" = ( diff --git a/_maps/map_files/Voidraptor/VoidRaptor.dmm b/_maps/map_files/Voidraptor/VoidRaptor.dmm index dbae07341eae..167607ecb8c0 100644 --- a/_maps/map_files/Voidraptor/VoidRaptor.dmm +++ b/_maps/map_files/Voidraptor/VoidRaptor.dmm @@ -27190,9 +27190,6 @@ dir = 8 }, /obj/effect/turf_decal/delivery, -/obj/item/gun/energy/taser, -/obj/item/gun/energy/taser, -/obj/item/gun/energy/taser, /turf/open/floor/iron/dark/textured_large, /area/station/ai_monitored/security/armory) "hPi" = ( diff --git a/_maps/map_files/tramstation/tramstation.dmm b/_maps/map_files/tramstation/tramstation.dmm index c5c9f195b510..2d35e94b2274 100644 --- a/_maps/map_files/tramstation/tramstation.dmm +++ b/_maps/map_files/tramstation/tramstation.dmm @@ -51354,9 +51354,6 @@ }, /obj/structure/window/reinforced/spawner/directional/north, /obj/structure/window/reinforced/spawner/directional/south, -/obj/item/gun/energy/taser, -/obj/item/gun/energy/taser, -/obj/item/gun/energy/taser, /turf/open/floor/iron, /area/station/ai_monitored/security/armory) "pph" = ( diff --git a/monkestation/code/modules/cargo/crates/security.dm b/monkestation/code/modules/cargo/crates/security.dm index 3aa70b886cea..c29129636152 100644 --- a/monkestation/code/modules/cargo/crates/security.dm +++ b/monkestation/code/modules/cargo/crates/security.dm @@ -58,3 +58,10 @@ contraband = TRUE contains = list(/obj/item/cortical_cage) crate_name = "anti-borer crate" + +/datum/supply_pack/security/armory/taser + name = "Taser Crate" + desc = "Contains two tasers, ready to tase criminals." + cost = CARGO_CRATE_VALUE * 15 + contains = list(/obj/item/gun/energy/taser = 2) + crate_name = "taser crate" From ddbd77584ce09be76f89b5bedf4dc3ddd5d738a4 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 20 Dec 2024 23:29:57 +0000 Subject: [PATCH 34/81] Automatic changelog for PR #4624 [ci skip] --- html/changelogs/AutoChangeLog-pr-4624.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-4624.yml diff --git a/html/changelogs/AutoChangeLog-pr-4624.yml b/html/changelogs/AutoChangeLog-pr-4624.yml new file mode 100644 index 000000000000..6066900592d1 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-4624.yml @@ -0,0 +1,5 @@ +author: "Uristthedorf" +delete-after: True +changes: + - rscdel: "Removes tasers from the armory." + - rscadd: "Tasers can be bought at cargo." \ No newline at end of file From 96ceaeff6177a05ba4786f46734150f829dc1360 Mon Sep 17 00:00:00 2001 From: Coll6 Date: Fri, 20 Dec 2024 16:33:56 -0700 Subject: [PATCH 35/81] Linking Ooze Sucker Fix (#4622) * Allows ooze sucker to be saved to tool buffer * Allows console to link new ooze sucker. --- .../modules/slimecore/machines/ooze_sucker.dm | 8 +++++++ .../machines/slime_pen_controller.dm | 23 +++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/monkestation/code/modules/slimecore/machines/ooze_sucker.dm b/monkestation/code/modules/slimecore/machines/ooze_sucker.dm index 204b2e61d097..9c9f5bb034ab 100644 --- a/monkestation/code/modules/slimecore/machines/ooze_sucker.dm +++ b/monkestation/code/modules/slimecore/machines/ooze_sucker.dm @@ -261,6 +261,14 @@ GLOBAL_LIST_EMPTY_TYPED(ooze_suckers, /obj/machinery/plumbing/ooze_sucker) balloon_alert_to_viewers("[turned_on ? "enabled" : "disabled"] ooze sucker") return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN +/obj/machinery/plumbing/ooze_sucker/multitool_act(mob/living/user, obj/item/tool) + if(!multitool_check_buffer(user, tool)) + return + var/obj/item/multitool/multitool = tool + multitool.buffer = src + to_chat(user, span_notice("You save the data in the [multitool.name]'s buffer.")) + return TOOL_ACT_TOOLTYPE_SUCCESS + /obj/item/disk/sucker_upgrade name = "ooze sucker upgrade disk" desc = "An upgrade disk for an ooze sucker." diff --git a/monkestation/code/modules/slimecore/machines/slime_pen_controller.dm b/monkestation/code/modules/slimecore/machines/slime_pen_controller.dm index 27b170683443..96b8c676bac6 100644 --- a/monkestation/code/modules/slimecore/machines/slime_pen_controller.dm +++ b/monkestation/code/modules/slimecore/machines/slime_pen_controller.dm @@ -185,6 +185,12 @@ GLOBAL_LIST_EMPTY_TYPED(slime_pen_controllers, /obj/machinery/slime_pen_controll /obj/machinery/slime_pen_controller/multitool_act(mob/living/user, obj/item/multitool/multitool) if(!multitool_check_buffer(user, multitool) || QDELETED(multitool.buffer)) return + if(linked_oozesucker(multitool.buffer, linked_data)) // Linking a new ooze sucker instead of a pen. + balloon_alert_to_viewers("linked sucker") + multitool.buffer.balloon_alert_to_viewers("linked to controller") + to_chat(user, span_notice("You link the [multitool.buffer] to the [src].")) + return TRUE + var/obj/machinery/corral_corner/pad = multitool.buffer if(!istype(pad) || !pad.connected_data) return @@ -197,6 +203,23 @@ GLOBAL_LIST_EMPTY_TYPED(slime_pen_controllers, /obj/machinery/slime_pen_controll to_chat(user, span_notice("You link the [pad] to the [src].")) return TRUE +/obj/machinery/slime_pen_controller/proc/linked_oozesucker(obj/machinery/plumbing/ooze_sucker/target, datum/corral_data/linked_pen) + if(!istype(target) || !istype(linked_pen)) + return + if(get_turf(target.loc) in linked_pen.corral_turfs) + if(linked_sucker) + UnregisterSignal(linked_sucker, COMSIG_QDELETING) + linked_sucker = target + target.linked_controller = src + RegisterSignal(linked_sucker, COMSIG_QDELETING, PROC_REF(clear_sucker_data)) + return TRUE + return + /obj/machinery/slime_pen_controller/proc/clear_data() UnregisterSignal(linked_data, COMSIG_QDELETING) linked_data = null + +/obj/machinery/slime_pen_controller/proc/clear_sucker_data() + UnregisterSignal(linked_sucker, COMSIG_QDELETING) + linked_sucker.linked_controller = null + linked_sucker = null From f156a4846b48921368316a0cfc4434b501de33b9 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 20 Dec 2024 23:34:26 +0000 Subject: [PATCH 36/81] Automatic changelog for PR #4622 [ci skip] --- html/changelogs/AutoChangeLog-pr-4622.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-4622.yml diff --git a/html/changelogs/AutoChangeLog-pr-4622.yml b/html/changelogs/AutoChangeLog-pr-4622.yml new file mode 100644 index 000000000000..1166a40b92ca --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-4622.yml @@ -0,0 +1,5 @@ +author: "Coll6" +delete-after: True +changes: + - rscadd: "Ooze sucker machinery can be stored in multi tool buffer." + - bugfix: "Allows ooze suckers to be linked if its inside a valid pen, that is also linked to the same controller." \ No newline at end of file From 69ca80eae6c69e7a88478f75fb55547ba39aecbf Mon Sep 17 00:00:00 2001 From: Loiosh42 <129321455+Loiosh42@users.noreply.github.com> Date: Fri, 20 Dec 2024 18:49:16 -0500 Subject: [PATCH 37/81] Debilitated Rework - Nerf (#4548) * The stuff, confirmed to work * Edit * Rebalance as requested * Update __projectile_changes.dm --- code/modules/projectiles/projectile.dm | 10 +++++++--- code/modules/projectiles/projectile/beams.dm | 5 +++++ code/modules/projectiles/projectile/bullets/shotgun.dm | 2 ++ code/modules/projectiles/projectile/energy/ebow.dm | 2 ++ .../code/game/objects/items/guns/crank_guns.dm | 4 +++- monkestation/code/modules/blood_datum/debilitated.dm | 4 ++-- 6 files changed, 21 insertions(+), 6 deletions(-) diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm index d47c2c05a5be..95780d649f09 100644 --- a/code/modules/projectiles/projectile.dm +++ b/code/modules/projectiles/projectile.dm @@ -211,6 +211,10 @@ var/parried = FALSE ///how long we paralyze for as this is a disorient var/paralyze_timer = 0 + /// If this projectile inflicts debilitating + var/debilitating = FALSE + /// How many stacks the projectile applies per hit. Default is 1, each stack adds 0.05, it stacks up to 2x stamina damage + var/debilitate_mult = 1 /obj/projectile/Initialize(mapload) . = ..() @@ -256,13 +260,13 @@ // i know that this is probably more with wands and gun mods in mind, but it's a bit silly that the projectile on_hit signal doesn't ping the projectile itself. // maybe we care what the projectile thinks! See about combining these via args some time when it's not 5AM - if(stamina >= 15 && isliving(target)) + if(debilitating == TRUE && isliving(target)) var/mob/living/living = target var/datum/status_effect/stacking/debilitated/effect = living.has_status_effect(/datum/status_effect/stacking/debilitated) if(effect) - effect.add_stacks(1) + effect.add_stacks(debilitate_mult) else - living.apply_status_effect(/datum/status_effect/stacking/debilitated, 1) + living.apply_status_effect(/datum/status_effect/stacking/debilitated, debilitate_mult) if(fired_from) SEND_SIGNAL(fired_from, COMSIG_PROJECTILE_ON_HIT, firer, target, Angle, def_zone, blocked) diff --git a/code/modules/projectiles/projectile/beams.dm b/code/modules/projectiles/projectile/beams.dm index f4ad04bbcb49..b170a7a26db2 100644 --- a/code/modules/projectiles/projectile/beams.dm +++ b/code/modules/projectiles/projectile/beams.dm @@ -118,18 +118,23 @@ tracer_type = /obj/effect/projectile/tracer/disabler muzzle_type = /obj/effect/projectile/muzzle/disabler impact_type = /obj/effect/projectile/impact/disabler + debilitating = TRUE + debilitate_mult = 3 /obj/projectile/beam/disabler/weak stamina = 15 + debilitate_mult = 1.5 /obj/projectile/beam/disabler/smoothbore name = "unfocused disabler beam" weak_against_armour = TRUE + debilitate_mult = 2 /obj/projectile/beam/disabler/smoothbore/prime name = "focused disabler beam" weak_against_armour = FALSE stamina = 35 + debilitate_mult = 3.5 /obj/projectile/beam/pulse name = "pulse" diff --git a/code/modules/projectiles/projectile/bullets/shotgun.dm b/code/modules/projectiles/projectile/bullets/shotgun.dm index f3e183bde308..4d9eda9e2d04 100644 --- a/code/modules/projectiles/projectile/bullets/shotgun.dm +++ b/code/modules/projectiles/projectile/bullets/shotgun.dm @@ -126,6 +126,8 @@ ricochet_incidence_leeway = 75 /// Subtracted from the ricochet chance for each tile traveled var/tile_dropoff_ricochet = 4 + debilitating = TRUE + debilitate_mult = 1 /obj/projectile/bullet/pellet/shotgun_rubbershot/Range() if(ricochet_chance > 0) diff --git a/code/modules/projectiles/projectile/energy/ebow.dm b/code/modules/projectiles/projectile/energy/ebow.dm index e1da23495f4a..8495cbccbdf1 100644 --- a/code/modules/projectiles/projectile/energy/ebow.dm +++ b/code/modules/projectiles/projectile/energy/ebow.dm @@ -7,6 +7,8 @@ eyeblur = 20 SECONDS knockdown = 10 slur = 10 SECONDS + debilitating = TRUE + debilitate_mult = 5 /obj/projectile/energy/bolt/halloween name = "candy corn" diff --git a/monkestation/code/game/objects/items/guns/crank_guns.dm b/monkestation/code/game/objects/items/guns/crank_guns.dm index 5c96a49462cd..93f942bdb870 100644 --- a/monkestation/code/game/objects/items/guns/crank_guns.dm +++ b/monkestation/code/game/objects/items/guns/crank_guns.dm @@ -29,7 +29,7 @@ damage = 35 stamina = 60 -/obj/projectile/beam/disabler/smoothbore/prime +/obj/projectile/beam/disabler/smoothbore/prime /// ????????? why is this here *and* in beams ??????? stamina = 65 /obj/item/ammo_casing/energy/laser/musket @@ -47,3 +47,5 @@ weak_against_armour = FALSE armour_penetration = 25 //less powerful than armor piercing rounds wound_bonus = 10 + debilitating = TRUE + debilitate_mult = 2 diff --git a/monkestation/code/modules/blood_datum/debilitated.dm b/monkestation/code/modules/blood_datum/debilitated.dm index e21663badbb5..1549d7e0f91f 100644 --- a/monkestation/code/modules/blood_datum/debilitated.dm +++ b/monkestation/code/modules/blood_datum/debilitated.dm @@ -5,7 +5,7 @@ /datum/status_effect/stacking/debilitated id = "debilitated" stacks = 0 - max_stacks = 10 + max_stacks = 20 tick_interval = 5 SECONDS delay_before_decay = 30 SECONDS consumed_on_threshold = FALSE @@ -15,7 +15,7 @@ ///our base stamina loss multiplier var/loss_multiplier = 1 ///our per stack increase to stamina loss - var/per_stack_multiplier_increase = 0.1 + var/per_stack_multiplier_increase = 0.05 /datum/status_effect/stacking/debilitated/on_apply() . = ..() From 0a7653ad759cac53d38c6d050145d2e5e8580a72 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 20 Dec 2024 23:49:36 +0000 Subject: [PATCH 38/81] Automatic changelog for PR #4548 [ci skip] --- html/changelogs/AutoChangeLog-pr-4548.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-4548.yml diff --git a/html/changelogs/AutoChangeLog-pr-4548.yml b/html/changelogs/AutoChangeLog-pr-4548.yml new file mode 100644 index 000000000000..d23a01572b01 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-4548.yml @@ -0,0 +1,4 @@ +author: "Loiosh42" +delete-after: True +changes: + - balance: "Reworks Debilitated, and by extension buffs disablers" \ No newline at end of file From 43f389618da2b1898329bdb9b63f26982d0504fb Mon Sep 17 00:00:00 2001 From: Wisemonster <87689371+Wisemonster@users.noreply.github.com> Date: Fri, 20 Dec 2024 18:49:45 -0500 Subject: [PATCH 39/81] Adds a cargo-locked disabler to the quartermaster's locker (#4270) * Makes the cargo-only disabler * Adds the disabler to the QM closet * Fixes the tg dme * Adds cargo office and sorting to allowed areas --- .../crates_lockers/closets/secure/cargo.dm | 1 + .../modules/projectiles/guns/energy/stun.dm | 2 ++ monkestation/code/modules/projectiles/pins.dm | 21 +++++++++++++++++++ tgstation.dme | 2 ++ 4 files changed, 26 insertions(+) create mode 100644 monkestation/code/modules/projectiles/guns/energy/stun.dm create mode 100644 monkestation/code/modules/projectiles/pins.dm diff --git a/code/game/objects/structures/crates_lockers/closets/secure/cargo.dm b/code/game/objects/structures/crates_lockers/closets/secure/cargo.dm index 526c91dbb0a4..7f758a7a6cea 100644 --- a/code/game/objects/structures/crates_lockers/closets/secure/cargo.dm +++ b/code/game/objects/structures/crates_lockers/closets/secure/cargo.dm @@ -17,6 +17,7 @@ new /obj/item/storage/bag/garment/quartermaster(src) new /obj/item/encryptionkey/headset_cargo(src) // monkestation edit - An extra encryption key for someone joining Cargyptia new /obj/item/cargo_teleporter(src) // monkestation edit - singular roundstart cargo teleporter + new /obj/item/gun/energy/disabler/cargo(src) // monkestation edit - a single disabler that can only be used in parts of cargo /obj/structure/closet/secure_closet/quartermaster/populate_contents_immediate() . = ..() diff --git a/monkestation/code/modules/projectiles/guns/energy/stun.dm b/monkestation/code/modules/projectiles/guns/energy/stun.dm new file mode 100644 index 000000000000..5fad2492f767 --- /dev/null +++ b/monkestation/code/modules/projectiles/guns/energy/stun.dm @@ -0,0 +1,2 @@ +/obj/item/gun/energy/disabler/cargo + pin = /obj/item/firing_pin/cargo/unremovable diff --git a/monkestation/code/modules/projectiles/pins.dm b/monkestation/code/modules/projectiles/pins.dm new file mode 100644 index 000000000000..e298be6e115d --- /dev/null +++ b/monkestation/code/modules/projectiles/pins.dm @@ -0,0 +1,21 @@ +/obj/item/firing_pin/cargo //Firing pin for use in cargo only + name = "cargo-locked firing pin" + desc = "A firing pin that scans the area to check if it is within the station's cargo bay or warehouse before firing." + fail_message = "Area check failed" + var/list/station_cargo = list( + /area/station/cargo/warehouse, + /area/station/cargo/storage, + /area/station/cargo/office, + /area/station/cargo/sorting, + ) + +//Checks to see if the user in cargo or it's warehouse +/obj/item/firing_pin/cargo/pin_auth(mob/living/user) + if(!istype(user)) + return FALSE + if (is_type_in_list(get_area(user), station_cargo)) + return TRUE + return FALSE + +/obj/item/firing_pin/cargo/unremovable + pin_removable = FALSE diff --git a/tgstation.dme b/tgstation.dme index 56fa38aa8976..c0a0370d4a52 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -7822,9 +7822,11 @@ #include "monkestation\code\modules\power\singularity\particle_accelerator\particle_controller.dm" #include "monkestation\code\modules\power\singularity\particle_accelerator\particle_emitter.dm" #include "monkestation\code\modules\projectiles\gun.dm" +#include "monkestation\code\modules\projectiles\pins.dm" #include "monkestation\code\modules\projectiles\ammunition\_ammunition.dm" #include "monkestation\code\modules\projectiles\guns\ballistic\revolver.dm" #include "monkestation\code\modules\projectiles\guns\ballistic\ryanecorp_whispering_jester.dm" +#include "monkestation\code\modules\projectiles\guns\energy\stun.dm" #include "monkestation\code\modules\projectiles\guns\special\meat_hook.dm" #include "monkestation\code\modules\projectiles\projectile\spells.dm" #include "monkestation\code\modules\projectiles\projectile\bullets\c45_caseless.dm" From 55783021b9b89aa024a2ce301cd8b950089d9062 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 20 Dec 2024 23:50:04 +0000 Subject: [PATCH 40/81] Automatic changelog for PR #4270 [ci skip] --- html/changelogs/AutoChangeLog-pr-4270.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-4270.yml diff --git a/html/changelogs/AutoChangeLog-pr-4270.yml b/html/changelogs/AutoChangeLog-pr-4270.yml new file mode 100644 index 000000000000..7ec36ae5c59d --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-4270.yml @@ -0,0 +1,4 @@ +author: "Wisemonster" +delete-after: True +changes: + - rscadd: "Added a disabler to QM's locker. It has a cargo-locked firing pin that can only be used in the cargo's warehouse and storage." \ No newline at end of file From 23393a8301fb9262b8396cdefcfef034505b331a Mon Sep 17 00:00:00 2001 From: Sian <109153765+TheColorCyan@users.noreply.github.com> Date: Sat, 21 Dec 2024 04:51:21 +0500 Subject: [PATCH 41/81] Makes interdyne MOD actually fit people without digitigrade legs (#4576) * now its ok * lizard fix * FUCK * i will never know why there are two indentical mod files * final fix * there was 1 pixel missing * shoe fix * last stray pixel fix for the love of god --------- Co-authored-by: TheColorCyan --- icons/mob/clothing/modsuit/mod_clothing.dmi | Bin 134522 -> 133974 bytes icons/obj/clothing/modsuit/mod_clothing.dmi | Bin 80401 -> 80403 bytes monkestation/icons/mob/mod.dmi | Bin 113940 -> 117680 bytes 3 files changed, 0 insertions(+), 0 deletions(-) diff --git a/icons/mob/clothing/modsuit/mod_clothing.dmi b/icons/mob/clothing/modsuit/mod_clothing.dmi index 537b1ffd3ebdd0ab1252927e1e8f40abe3882724..bb7063c32ae25fe38bc663a3929f61b27ce90f0d 100644 GIT binary patch delta 48935 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 d7=3OXk;Bw1wp!51f^kV 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�&>J;U%ui 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 z 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

-+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

  • 95)O#b*F3!4f4|= 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 diff --git a/icons/obj/clothing/modsuit/mod_clothing.dmi b/icons/obj/clothing/modsuit/mod_clothing.dmi index 7eb92f1c3519c58541614356d0bec8dbce485b80..684c99a1c190aa20b696fb3067b30e4cf9ce6aa1 100644 GIT binary patch delta 35143 zcmbUJ1yodT7%qx$8U!Q-1PM_A1*9YdDM64>LILTL5RgWiJ%oT#(jX}*($YC}clXdW z(hM=ca5um6Kj*IXU-zDM)?JHXX7=p(_WQl{yzlev$Yb2-W89Md5-@>*2#c!dQ4F?X z2o@_Vb-i>zx*iGkox&~;XH`|R4)~3S70EK$Mo#JIPg=9H zE=Sn67tx*A*Jtpzd*I*0>C>YZ?teW8`n)V$E!Mp@ya%5PWRWp_xFmRS)|q=p*pN{g z?$zUE>#Q#UEE-91`Q(8|_@0=5D6BW+lX%iJJ z7k{00{EY^uE2GdX5V+4eo&WbOzf|XE{2weYh=gv%HYJg=uq=A8~7cU+(GSgNRFFt0Es zy>7zrMIDaT-~nUT^;rl(6yx0{qU)_NJ0Fk&K+x{zMR_FkUU9b=1_R$GOJ9K&0x%uJ z>xu~rH^&PZfOv$)0Z@(5p?m2E0I?c^`|>P+kqp{H1EkGHrSQYngVvq2-CeqhtYu$H zxh~04wf0b9*FNBT3ZTKp{7u^C+g@@Gc|<_TZZz4vBdcZM%|P`&R#T`o$Y24lXgO8& zto&*!nQ$&TKg0_3RiHrq4%`K?Eupu}n`8&4P2?c6mAApjUM+fnzNwq}>^}dTrBlta zI@QVCs8K~Yw`erh7#dw%A(4KCGPL&g6ExWw7}*^pSc;p>k+8k2_a z36=5U7IJ<`Ji}blZ!rsd-WQ6Cz+T^=HR2GH)EKi^SMlNg@pRM#yY7~b0VL?j|Hj`e zU~T?{mW~c2QL4bpOJb59h)+y7l;Z;yj|d(_qGuj_5O)nJDHwTdT#5Iel)_3)?a8$R=bD*SS!d0m!6ps2_h|9Mu*(uJDetJDr;J5 zMX+#dKk&A^JQo~^2n&<;@$ucKzvKRAD@mE=($k-3abxcAdSQ|Hop6W=dNe1;QAMwA zW}Et1s9o+{|5Za0?U$V|4HP<#lghSkVnx@wcb>70VVsjsI-~OnE7B|D!2UjF&lE8t z4jxdbPC?R77`(L!-IaFQtqC&!uQPY2UBaY}mdx}0ZFRM8PU5@_UGUU`TN;dRQ-zQ@{GpA4m_iLFr^W6q+G$?mo-Q!@hJx{Sp96u52*TQFTeE6 zCzl8TY4wL6Gb$Oi;tgKIpLSg zBcP^hEp24P3lN$un~jZG{50{_?G=$plEVtwYx%zYidKd(z){QCm5-ooz{nX~1`M>m zuu{kW#BDVl;D$*I8GeZ49^8(f6O6W2fwMe9#l9e#rNnywfV9Bu)=%$_-wVG!)Jo9f z*x)quBkc(9VGJJ_4_?t+MFD)f?99pQ@wrN5ZC9wa==eBZX>Eer3 znH1hD`8|=W!Z51s?@u)soo#*p;24NzVRT4Q(G?e$GM+)$ciaJ%1j$FojEQh<(tDMn zB55H?ZxY6hK%vAI54g}PoM`iXe?|lEJfhEn{*a?``*;_0AN0t3ldo9W>~`IoQX9LH z>(KYng_)XjOfa>F7VMk6Fx(w0eVsDmjfG_emfM1ai(TMfUdVTJT{e{WZAq}++72P` zEtiMC!QZ!WO)=tHCD2T~-;~|qbK{fS2)K!TLsVpeDF3vrlmTw?oUcZ+(lE=I@zux+!#++5V!JnKN;0xtSBgz=iP}0{Wg|07Q6OX==>bF~Z@-F)q2m*U zOMSlRo8|{9)^pX>OaAR+kWZnAbr{`X-kO^81i&l9)wQ5dv`4qy5U~^#Qzi`8`neej zejPh=fyy9f!7OvBk7xQxkbT<(S=FX_zw%lOE6VNiA$fu!S6*=;O6Efr(^|W^#yW0! z{&k0W{PFBPtdES>YpzB`avoDe{ck1C=O>#B1b8PWlt}Q0`1w^EQ@!T9>>sdUzPQz) zv!+GAeR$Xs*+|cx=7kYBc+YEcFR^8yfNVc90hCQCPm|Ha2_hM%RzSQvPTIX1$|3q# z5{VE(ss@W+BX{g)pYEk6MJ9<%Al`ai*%kC{^d?;uQC{u;i`1VaJUiE^kTkhEk=ltk z>Pxw(w)c6j8FOo`?u*^<^FPRf+RDv4nep|-;@NNEk`<^~8{lhss!h>ztx<2TmWR8S zPe6(E>B_`mqpeg=_W6!iLUuAfBbZZAp05NXVQmc)NzsKZtG}yLdHLMNyQVRUoiXV& z^nN4otrz8siK=TF?Z0}dC%C4A>@_aCntky7sHNv%RHTBQW#p9PD#!EOdKg`owbsh{ z)O5do;r0gBJ;=PsNmT*ZtF-b4J_%7JLU(^LlwT(4;;qJ z@3&T8)I7@gI}GMg8(j15`s@aJ@0GhF+Aa==XmEhW4g?>XC${=JiT&(~F227TMCy%K z;DxkcHTh0vyZSD5+vU+*y?Y1g`j7d~2~NZX^rv0+nXFFsr6pow-=?~cF!5q8HvzI+ z=K9~mdsC8fo6PqcSI~RcXR8FB+>J8o*sjVRoJ03Mmp!p7GVSP{7~@KLgP?&z6z`Jt z3DInHb4$m=(kvD9XR~>B=53HhFv9El{wAeuejemu5t{FsJTV06%lu#P&s&|-*&(~w zv5lE-ib;{i_%&v}y}G&f{V}Z}kjdryPf71|$-kUuznYejAl+G4vc&t8qXk98WUXD9 zI(iJVpJP3}rXj-b2f_)FSb%(onUh_F!q@)V4TJWEel`;L0Tu|zE-+yMUEO~=H{sM3 z)1lL|WcS>$1>leW)-a14;>yio>XmB4jXq6qlfj=Tcl4pJzrNaLES|$c&3**5S0i4z zwq3`*#wn}gJz3D~w58dlX+8Fh+kEGcr%=5jn&5&DB|W?)VCXjEcDvai}KVxV}mWBHiY_Fpzl(WB$Hf zoNz=OW)(R~91r_$C{g{fyIOd_71K3qi==!);ZimdSHp6SAWSX71 z%-ZCUi$EuJv%!2YMN{MhyCqRBe4l#k%MOBevKW@be!@0(bY@oiXQ#26a^?qV9l@=G zRZ3NYQ+l5H`Jsdh{ki(w<8pxc_y*Q{8Ay>-?|q?(=bWB4oIB8H)bHkyy}L{mozlgn z*#7c75?qoS&v<9G_%DXjWOcn>069B0pmVf?$GP{S)IJze{>9pccsW_J| zkyx@LjV<&33RIWnDzCk2L2sr(-qj~#Cvv+IaKcngDWLzY{y}8>8U2+*u?@p>?V>8I zo#_Z8Jm=5NBPHxY*@``_(Fk?HtNb{hqzeF>+t_ZRDc?cfbZ^;ANoj#SvT$&By)Cm& zwD&iME@SxJ!;s`DOQK9?{bz%fLhhV%s# z_{#dKpk5TpMWk$S1svXpbOtriF8?kN_usws&!e&ET)1)^!|{A0CAUh_@p}Xpe#hmw zPfE~EP$6}Jn3|$tl^sH2?L_fGo2%I&RgAgp-p^nH-0EJh9}-(QCvOt!iuiWNK+icw zJwF>&VoAPZ!TaPtoNE|txHHXNVd1h`pcP2-BE{InhI?*M()479FHf_#Ow_`mk|%ZK z;@5j-DSU>|W_$T#71FDx#sJaaM+lbOOW!T0f-E@oHgd8Pf3c)HK|3a2%Pi$1>~^{r zGX$+-g8l=4!%zC`anwgY7bmj>hm-yHWzRHn{RdA|gQ}o0hy>k#2I|F{eH-ZaD}Qwl7@N>3LA7#=s*JKjD0D`? zj&!jgafBnfjt7%kFi5ZeoMB|r(;4S-aV6wA;I^_>ReO2b6z<#gdf^`}?NMh|UAPSQ z@mi<%=R!PR-)7C;@d=%PN&WGdp3KX-FLkF*QH>TzDt(;!M(>N6a_l<7$xNC+@COSZ zWu`%TNkJ&(O|_hdcG{2__&js`*H(IlHC(XP@q36;>3#2paPIsLAItWeaavE|;P^j6 z2;?Jarbyvv6hOUxC(j()0t(yzw(44KN>=R7_N8AYcE2ZrU0;nakQE+JJJ>y=$92WXzoe4FPGBtFcMQo345# zZhg6mDx2iB8sk-%|0UB&K3tq+^&e93^{qd5_y|~AbN?>f(QyR>ZXjoC5LwG9f?3wc zs6=BmsG+#9f`v;xVv(u2KGsojrhr?%;~KwEMbCUnV&qY zL9$q$mv_(l425Qj5-qFI;l;K}xwx@16P&oXIJN|`kgt-1e*XTEsi{RX?l~0_KvsWR zCstE+3oA9~FriS*k#hSYBNG6&_At7!-U>;Q5!P?u+%s=;VcIJed6h{e*WV|K7UpPn}|N7RaqYVee zq$YVLpHK#^4`Y8Y56C1t8qhO3x#hEC1V3KI!w8!%v6>8zJeQn+wf1dBFLiIibrq^B z5yEw{MZ?aHj^9OtMv=773lm!h`c4rbv$IuA8Yt>7!M7x0nBM1lUnu>A-s?G3dpMhw zypHhP{spgf#v*6nIk2;RMqi+wa+1-KqHP#nNSMCk$YFH}cs{nAQjo4H$X)GE7db40 z#Nib;!(a^TPd!>ph}U@k`coTvxJr}N=Cg_yzR_A-$dp7w9UB^Wc6F(<)d_ZVut>tC z+^&?~W^bb#eSHYG&0v!ecug!)v_p(Q)3{(uemd49>GyZz0iW{HFuQP<8xbr4ftzSR zBqB8ftyGXKMix@@GL|sCT@T9wm6H8tw26@7hk`;Bu?^%34x*zT_Wt&Lv15*`5Ia6P zA}%<+wg}`CeUqS=#oYyhf?mdh`$B^7C=E( z`aKWF9kj)hY@UutiIt7CfpT5D8xL{!cFj3<))k^{J-51=`uX$czY8m>k1wnXi>Vcp zq+r+oxYl-lC&RVh8>B`0bP=oY&pBPGW`x4($%%48L2G&W>+ z%CXpIhV$ciuC|Bwvq66#9VWXo{GdTPVKj78= z%m}-Nwf7@6QM>||TeUfXgS?w4an-Z0Si?NQ>OXjiubRd(9&8gowiHH6*8O4EG!Ita zx1AUqU22 zZ%c{8nBK(y*wJ7gd-O~nyB;P2T)bD)l85W#+xNB>v!W{GRcG#@OwC}1oG8sc z@(lSo2{aSi2r79k-V@UQC$tv%8okz@{k!0ISI; zWR#1}_i2~`=-$zAT+81Sw@fx4ccpt(jr!B#Y8Uef%27boTZ z_qMj9d-kb&))SdqlrTW~g}QIZe36Mugonnl($N48@a1bDHcbdG_6H8@BCQbUB8yQ( z>>`cVDI(akgc5?BT$2jNvnklS{{tMZEf5#xZo|Fhg_Ye~MJuT3=t8UZHUqQb=fJ-V zKbs_+ATw@nuU{fpIbSO3SV;Bpq)3va(T`z}mJ+?CRWQweSl14_8-{;R+(WU_wtCc` za#e2Vj`yPs5Xu;kZBEkP9iDCL=OytKqS|d{8|Qm)ZDxxa&sn@jCVx)gyJcl%{hl~Y zsQYpkP`#DTe&$OXn%chx^Vs=8528P(68?1AecJzl>oJ*%4>1hwWa~nGg$QfVP{&-k z8bXtR?+1mGspQ*%d;W0`o^@C$`;X34rf7GJdzVZW_b?vqe>;^iSpQyh=2VK%Og1;) zYggmW>6|dbcf3gxm|vX>!Qxi3#4oIorFP-Rv2QObEuKm}iXbRN5xoRC)z#Ijkwta4 ziT~zf0S(0!B$rDMU{V#XDla5?31j1))L-vD?n68h!URv>ER;&C9QU^D-o~kXG8qw-G z>mJ>ysGwOY3+aUts;^1RQZ-vY$|u-^!&@pp&pJPT{8$eS?n}HD(=m5Sq?HR;ez|b2 zndw}#8Ptg?eLhZ{ r1Mgi$cmR}i=MIi!9^N&d6tuRU?)I}FGa?e_qVSRL(FD&9` zbrS~p%HK0!CCu}a8ORTl?P?S68TrtpELvA^@MyX+y_^{Oi+_0#{Tw(O8(rCtmJJ{K zhx1s7eAxr6K;7k1XA_cMcC0W)`0E*d8?+g`{Cs5}Vm~rF%kC~N@bF)t@0G0;NrEw2 zQSQ=);q$C8Q1Et6IF6BcM{r#SNhK@aDm+A%?Y?nv=z<|6B70?IPj1C6xVY`7s;?i0 zu0Pr*eQ(FYHhOw`+S#gt`DQ(A7XXJ#Dr!t1Vv@nW@snpJ9B08vZcL5pfDD$Gfpv4v z>c;`bh_BJesvsc-sRg@6SIH?o4C`Dt-QuVnqrBfo5f>Ip5>F>tp}wY=>v@yj4l>ZFG(30; z#!r6BHKKs;*`RTUhmAgs$HY(r>nexfuV3z^QMx>Rs(I0n45W`C3K9Xi|D+b~A?YYw=SSR7glW%Z>@@FlwhI z)@62g&pD`_s{*a_A1^=9CuC<}HC`Kf+P2KTAPl%~7dn@+zVGa zEKdNv{KN=aQA(tq)4xP|vI4lPj(&5)Ap7i}a+o z*}ii^Z~4t}`j1mkqkzk904j`{IcYigvxTU6#ex=OseUYDIrC7XZBC)8$+l%K1cg`8 zQs&djiuzsfCvwc?)zyUk#}8e7H?YfbCIy>~(ACtMNmNQyKj`Py|2UrT<>UXm6*phL zfOXS&1EIEE!~bg5{huSQ|Jf1ze*tj+4i)q$PobAQ(sLcnAY`*4WHVJXjlKbW9?<3f zMQL?jS9HpHft2xWr6>is)Ar=#WJY5n%?_W#&F)h-yUKP#O~K(O?k-I&4;q0u^A`n5fuuCkT196nw`a86WcL1zybcF^{?|E@DMXg7BcMiKe8F!y3h z?4v0cu((6vE;_Q8j3yI*rqUUj*8P6%*kjoYoGj2Dw)M_1jf{)y$j;53y%N{WXD7@s z{WV)^i2_5qyskYd^vw2P%7w`3fc~$~Bk=3!TQ(5os~}yhdbhg{EanVKj;x+e zsDs_x!jC#HH-7{7xc=To4JQ8JsMkEKAJR!vO%=K;<;iCK&XGTUs9*lW(~Frq8p;V1 z=+w~DRN9&dvP9#0vnP&@jwMFT*a}x*ASnYmGc(z!Rvn*r4AYzFwD-ps?B0VDv`&jn zSWiWTq}4SO(&n=nlIoa0bl~YX2Dl2_Hj@#kn2h}vSt?@^jp>}{_26Ac#DAwpq@Hc| z$G<;kG9OIs7e{Y8O(h+Kwc$3NwTR7~trEGd#lnq_*8Bfh3aqsAp6=oR3AGMjn68gg zAu7JWCz=>JOV%LchXv5)b8$$z(qv|0|3FgNY7EdZ-hsIvt=H5?=paM1Q!bfkhb0x& zHKTL`*6upZ9qKwi^3Ekq7mu!Z{5)|KS%1J;OsMC2P6;gf*{OIToS9&b!_}3W%%?Se z|E#sB$Jt?Gd-c(}l{R-f!WqGkW9>5DcFQ)R5WEc}GP2Tzv+-hAtp0dJ>Fjt^MdN&6 z4efn-h1Haa3c@8=afZI}2VC0kXQ}$MZZ-oj?L5~fwm{;+wySr7#{9HlkMZujyapA7asBV|@|obU z@esHjwX+_j=%+RJsl0rhk@cePNiR2BLH<_N3Hl=Vyb>SJun(Tc^7>oh28~PKH)l-{pH)YSAxnjuTQrqcD$uNMldkDwz21wlbNe%`mdzB2e7zjAW$hf9ex zdqWb;{g_`N}Miq@=Ca4hcjNwJ$_tQzki9OOM4;B z>kZi9pPF;zH(WGk-vc(25NTK0dL}Ii=b|=6?PKfw4lx7c)P)o16h?DQ%tx0)&w5%y zg|@&fFEBu5k;f|=kx;@SK=Fv9W#rLljUZA&bFHo_Tk^}Cn^*a=j5G)xkgUU|S_Gc{ zNdy+78uf8FgbW&LzaHfjB_f|1VtYNSMr^$IWQz4#9MU+a zVv_qR+5;Z{LeS3hQA_NMxRx7sYk3;uKB1T@0JS}9D9P|HRy>F;G%&?U><+G8S7y0z zIyw@3F1>1U;D@2*%c6Gd(Y19&!$uN-=BZwA6~af?!n47q6W6UILvP~2is8s z@NCR(@ONX&1%n(}2WcjO5-ZF^oW{H6!q+T$B+p1vQu3bI04U*(yC18C!G^vPSc?tr zUc@=JqAEl#lxni{E>p9Ou#DD@2}FPo5BV+onkv{ub1NDtd2!;Rqx~W0rWT?PAlVDD zB$T`ZRd|={67+zkDWWUizV+IFVj%UXW7dsW-7s^rO*ML6>?1tg+>XT(K!Fb7Lq?nU z#y2=!BZV@>XHD0CZcEja*hgE|AZuM(2?BXT{}jlo6k8rQ=-sv(cI0{_cKn^pdEw1# z1%)Ljznj=5TKeAT_S|k?t+{erEJFoG@qi0O7;w8{Q8j!4fE~HiBz!dj^A8Q(1#4L+ z?|%yuT24ZHWF6d9O)f6(>>rkE#;ul-od4L;n?YS(hnn7?RWG66!kO{9K0n8!6SSfO zB=GL#``rk#micyS`A;7<4h}*=LBZg#^#=g-PI&7Ub`vtB{~PCeZ>oZM2+;ASX zyGsz~K&o+vaHN9C7vvOm!1cNR>(4QcvWm)Nc6PP{&x`BYHs?l2wfB#X-hBkRZe0IR z9a;EK9KK7BMrGT!zJ?1aFmlfX_nJ3!jKHM2(QM{d89YV?F=t*r8T>e}IDjZw;6BBk zceGjA+qsRmp2G>bVn zR7>)ZO*R{T$Yr{B`AbGzBzeE66OKOiZJw>upj!VU0T_!Di|Fm|5K*~eAv2Rl?ZS>+ z*l=I+B-DdeF^isiaxnk4ON~riLw8{li;oXSW;rK(e-{+ADe*J}nDxdPcQuK;sQ0WI z=l^={#mwuveLDGp8DN_Dkhb*p3UWEq+~`cX_AQ#ME8h?}M!4DnqtDSdD5vmi=kcc^ zgN9(wb;MV)g)7|W@XKJ*t!u}cr8`J5fu56YNd#EzdGOU$B>Na^0e2zJLvlkIw#u8$k-ekY$F5F&dWlJISb%R7R7pHedlIl38g$5p!%2p- zE|+rUPgh7&3mvmbKj-L5KnPR8QXx`sP9pkw5cD>py@?eu&mM&p*Iw-jGGb_)pC~v z|1w{N`Ess-Xv3@32#Y?7vq0}_$ENq1_oEkn<+!DVMAD=Vvq;PTsZD-vuLC{ZXb5{+oNv~hDs(Tt?~ zr+QLDulH_yYvT-G&!>MEi58c8B~|7HVg|VPHlw1V7B@D6Xj4J`vp(TaCN5cU5!zPb z)GPKU_Z}%ePEp7{1%?FQzxO|Sh8`T*ihCriXUIucn7J->Pmn+-vAES-VmodL5#_Pt z>P?5%XJ#wFk(#0ra30`yS)rdF3$um*9A_-HLDePJd|swDoiS{`6Fv22mkw5{e#7D#w$HDvurRO{`)sI)WBX$p<{lpNsoJl zLQd9s@tzRzveuPSOd2)@inuMs4c&_4MQ6P31MUs|_@M%4_*r@TU=5>_XPW zR=eS2;+uvu%imE)j^604T+xF|Yp6?UsS^Z$z93yW z`PTyZdvGPl-zv{q#mnnOlwD$=r?*4_4qN7 zk|w;nP!}Ur2YN!v4+Vgbb1|#ixE@tmnh`&7+*{lGG|SHE^T=WnU=8tOpBkw#F0X*PJy;T)8OHz#OxVSQG3U_&4**lCE&;7n zZTau_S(ZO>qSaS0jKVh03BTJ6XCUFF^RfpG#ETqgOBz*}-8_%-d5_o;>Fp-X2vU4p z0)keCA9V1=MWZ?--^l2wO9&13^1UrBO-)6Tc{B=%M@0x+Z&ExQ)@nK96AJv&2_E60 z&f0}ZO5^hv$rybQ)FIQqNTUv!f}8g08GIGZGO?hHbtSdRzWN_B;#++F4`Rct)pMgS zeHt$e?X@}5EQcS=R;e9KpJ!hw>fEk{457+dgw168|9;bw(l4Glv8BNk?DFpVZGSb|Y zIKfOuAjS%lF+luWJ*h(*nWc~qYV9>XbGAUz`R5{N`{}<L92c7h&z`=2|N*h#jXlFAiDy!w58nT&T;9P{LnU3MCh>gi_LWLg@I z<0~|5EcuTE%||V>`&bjB>D3`cSv*-VsKu01_JND=_U$-2Y2ZvNP2x;Gg5?7jO&tRz z#GM&yJDm}rBY6uJ6YmE;6&KgHPyuHvKa1An>B4;)Y;QjLH?wR)R`=Khv)-53+MgsG zktA%#L;$FCo@M;gdF(@**?CEaW8V2pN)Ka*AP-n#MH@Wr+^fG3nX8;ZA9khZe>6A0 z#l|8u!{OXE*xel|i#O(XEG~cD>`SM#D zVFvDLgJ9$M-ejWLYdBs~Cais3C3U-^3WTz5w)>)lQXeElM5@Ps{}P`lHsr|)NC{hg ze0K-O?dT3eYf|;Dfv8@sDt>P)=h=o!133eCf0gU$$PzaX57$$!W_bPcP#gZmjr>RU zFB}4D(Hf{bPk+yvcZM@YS;`pu2z~iC_3O1E%LuzS46JQ~5>iSz8u?B(qZ!7ga4-Ua z$II+9cuAU@>V6AYJncj5w>C#l9URmpeChls+sXEN!g|kir0t^VIL*fq@ANVx-?@_M zRc9absOzg)8f#(iTk;gu6-g2rg4i#Rpl9R<5AxGi4(H~)f`WiS7x9BOOg}^z#@Uyu zs~XIJ{kwuNROAvfzC-z2e(b75FcK}5ko3SGl04mX{hXRW3CEwxY4X&K2flz_7^Vit zyku%q_W)d7U2L!$m?`KL@09%38tYuoiMGiq(b+QO<09Q2IJVXrji-~U>847OJaFXt z%Pw~>rL3ai6$I<= zFgD9CaNWZUtws>jZwH+PJwd0GsKIiIznEH&(*iJ}`)^*RWSC^_m7-NJ=RV)M(Pyn> zeBSHI$Anw{`C2?ChpXMc?;a5WjXcW`{2Y1^09W%^Yu8ASaLW0ptGFXmydV>h8(GpA z(T~=P_#x5aQ~T#Lu{($x?($WQAA2LX5Y8BJeX`lB73A9?>NJk4F#^IwsQgCgnfVm5lXAwVKXOc_Y-{f(I|s$yVNVFNQr(y6>tH z!wVK=bUYjigD|5 z|4^h?`V`)VAWC|bBQn)VkmP~oq(=7Pk~}ZF@s<}9+iJBYyqn(8iQxkFyM08^7OSeO zfvn;N31IH&le+nVzeOy&@J?1;#ID%m7q`N*(^QfNT35TH4|W=(s}DLDTomP+S1
      hPzC*W4HG8%Yae9(Ejm17q*N&rUFLsji6k705%XNIHdPJ8{KrQa$;ccr51M7#GZ*YA#ohkF0xuy%8$Wcro*5chA&3zi5w8=(Vg3 zc_PsZtBKuj_jb${>fLLhib?5Y)b&kGO5^TDaRuhBu((TGN?<-GvI@;*q+;Hh^X4Z8 z?9xG2$sw?~DL6(>UwCs@f0{E=I1Y1w@;qC5;i&-~eHlawg@`V7iik;7(dC?W5Xx%# zw~C>KfDi7{Tjz_Doly_w;I}=TNQp%V>_0lSbc}rD{TWrUeB))SF5W8kK!q$&cWvpdCQfe?{oX!-+Gbs_+= z`8ok$39l6ZdIi?2*X|}m)pw{&i93A$%K}S`NWg&ND$`~new8NAs-=90`BeH20YEkC zs?alUCX_3AMs^$Uf%v`O8U<|h>f>=>rWMy6Am<(&d2%(PlLi%IHY3j z#jesAU)tr&=-KW?)M@as>ug0_q4dj1$2ceFR0H+oOPo*udZXzjM%##w=!_C}6Om?5;IR0Q>ar-SY$R zLcgx6dfY3zabr8TFQIw*38K=wPWMEb^D5@9Ky^BcxRq5OW#Pqot^?Gh8$Xq{_7-Hp znYz{IRT@aM7#3H?X0tV-G51rDbH-b>`p@1I2HL$fjQ6O$vNGb4@G#F1KuJ?zHg;n}(ihJJ&;ax=8$$5I^(5J!!@qr3{}QLr7SEps?9 z2>-Mg$Wk*S@Po0%-8YU;z?~KOhXV~beI`X3m!;ry?Qr_QxrOA_IT}P z+M^MnF<&i=J}kb-Pm1}w50bQ>$|zmk%!MSJlUx{=K~+WebeHoV?Q9iH&CHGC^QZVB0+{Jq(>txR$=s($6ggMV4Ha1JrZu!*L#4EY zGhJRT`&9K20Csh8YP!_&6@Uc>;#VQXSTjIsk65-@Zt!^F{Eq?ETpo|@rONG5(~izC zh@S3#hdt=POj_FG>|9?>u}H)FC|ZkeWkv1{ssaP?H!hro7tv?3ddz8rX}kF2C|veE%oP>Qf1I=SGIhCa?`43Y$jT+N7-)5W$95`nXlDq2d7`e>#2BFFO!LOKmL+4z=F zIoacgmyq}{-bdGvjEpZfwl>9o)#W=f%B7(m_X=0Vq|}l?YL5q9RTJz8*$Em!YiMY^ z)YjHcoIOr~n#$B|!jG37b=M2ZwnG@2VmY5Km5nVB>dsO@G#6~kPr&%g0%mXPM=cX4 zZ5DYAHw2;n-uzV19Z41N3q)wyUr=OM{dEQE2K$>2Y=8<1*d=2v}w zdG7>MJzI!|m?cc@mU0o~9TUwH%L~)ZnV+qDWTEthoQ=TWC%GwGF_aVpgGOI`cDX`KJdQX$!*FG^0&~&+~K_X!un3l#& zPfyQ#mY}Wv6hcFCrgmpnne6`(o4$bkI0^c(Un5_)VA2K-@c6i|BIcyOXwVE1cS*Rs z*U4dZJkp?dBJo-9fX2olc6JvwtM+AI;4JA6Y-z(tWQG=^6BbP=EWU>S&7cmtjTL(* z`?BTM)-@Ctc7K&;-+LMdEHaFZB$!sSAKb2gVe)*R8zwwqd@?hBw%F^`;sI(~kP##E zv*C|($Z|0U_uvooAEoJX~*KQJo8%MIHG71c2itQ zhnL$}exwYiwNO0Chg=T0hOuzqe#qQ(FMCyR+=BKCks>)wsIx7jW=60P_mdvAfDEjt{q7k2qj2zP09f%;Q0X z@{c&^rSUPAIzD{Kbv^(aD=mBOj%fOFw<+LBFS4Vp(r4r_WpgG{^512`B+#{b1AU~tbD({xxB!x(I;f>>p~ zz2ZV~b{ICf@8q4wiso9YmE7Qb81Rr4ihr`_J7N!eOGIJJHqD{5NY~R*)y3YGeq#B9 z&h3tN&*v8SkEcgK@@t!D%%o)F1MNm`^Z*Ov%Y#6TR877gqjFl< z$vrQK(S&)~_aCE)-0b7~UzuBWLGkA3*<9BkrWr4v2Bxz|x#}ERx`xGj_Y*)#z;B5P zZtimVw})OW$8Hef76u-pYHwx6Z+1+xS`YC?tEUJVtgP= zrJ%ENXV&E=4k%`=6drHnI(T@Kee;2=v2WeV_&jVcr!Ff^)LN)&RSai@ePVHS%2F1g z^R1buQugd$q9ne6FW7fhc)6!hz%UCt{zk6eVnQ{QL(Pk{rZRtKB5lrfJ7TbH=^*jL zkGmnfnG}y|Uj4~2Zb!S~!TtHPCXD-HU8*_H7^^mWhdo_o5*pcCj{C2Me;Ohi&Wm08 zf8MD*2?ut6qfM9Xn*SN}@298rnYmEg;U#FB}IA*2@6C)4i)=D%D9<2S2hNmI! zXyn3JK&XOifnV%+XaqF15_qgE;WRulvq>y!>Tn%(;ff{NmkWJ0^8tOQ*IHFXh+eu_ zF5TWn30@!F>Lviy^#xo{juvi=noKamHu!5-6L6t+V{`8ZqmbkF-8eJ1~9O068h%X3I98=~^PV zLfiK0sfhbSDCL~3W~ZR}yh@ryg)S^T*P*QXH`%oAq;Ri9i=XiE^;a=_(9>|SEX9-J z!s1hTOvFINt8O9d$)YtH9)nN_t2^F*9kacB0GqU}=NK#HZ&*N$s;Je{b6XTXC~#{H7YuSr4;cx03RN5tJf<4gx*Wi&)u$8A9&GgnvD%v zT=lfAD_yqTIY~u{Qw^4N=G?6jbL56(&dY|OX?E+b!jekJkhf_mhg8mqYOnKME~2@Z z*$p2u4i4$w#qYrcfA`0VEcTHEsm%tF3k%GynRC|#N0NRx+h0!GT9|2<*V8WwQ5Wnc zOD`L3LAzaBjpMsE^yHq54W1`s`7;EekRTB@MRH0H?CQwU4Vb^Dr%NG&fB2zqh~$MR zXw3<;<$3bqmSr0b-&o+*?_WGZpyPwCLB4Ky+JVD^iLlrKR3~cy6!!s^%PKSMc4S32 zuy8uzrf>b}p&)Z>R(7LC+prhWe8iFWE=b89DmyXV`ud+RrNPFuV^6r$n2urJA|_HK zQOuCn*#AQQ77ovx?+E%Peb!`$cRqh+X!)(_n|yrZA*QZYelLY5%T9YH?$sQW=IBCg z>(kD8DbO0~&^JDqs!v+k_y@eC#G~q|)xB}J((gM%&1J7SWSdToxjst|k%6Cfi9abB zzRxXhq?>@het{Q|041~I?|x+Mxucb7EfWLiz|WT7P6XlR>q=YQ!D}~Cn6~jBAF<#) zn$*F4`(|v!BJxGexoL6x6g>(`S)Nq-^H{)Xb^8sD$t*2!e>5w9)7;W>-7Y&vwMDSt zv<;@F5J@$-6GAJ(FCF&5e25t>aZAfMkqo$rBxfs&TJ!t_DL>ICeUpcw&qal#T4{>w zuZuLqJ@pW02<2Eho|D=K+r87(ZanNhGb9&2N{%4~sV^T~?`ku@c%7Co&Q?BA^-9J+ zVxCYQ`v2DiT1e7A^~{%l>}ItL&WJl*;I9^-{Zcu_I`e|p70wp5xx{k9u^5LtqFgVAeJfv?RU>%tbdqFQ8Yv%1RJ{q zA|2WtLzbDP5@2);Ehk{bVA|P+7BZJ+?qJ0TYZerU&u)jJQ~Mw|1iL4(-9fi>Ds`3 zPj5b^ZqdKqwoX=JcWl#OSD5@CkEvJejT?S}Bn@z{=8)Mq!(8a> zkJ*4%nJzZ3vUErXE;vP~ao|(p9T)HV3gW^c1JjPhbrGZFxpUL?L9x*UIQ{Pye~S~! z7VyaR2dB@d;{Nx*h~V3#o*-pVHT-@^Qw=|Xp~bM4zmPao<$>5-ge~(nUc&lX>gtxl z*twPGBRYnp9N7Q!=@S3H6Z}6vapHep&-wp*-~@QXNc%rthIGR)lO|6I(Fmcjuk6t( zK%^hxdi(9azX<_=5kzPfwdhfRn<9}XJF~f6;n{uvS7m=473CMU4Z{}=(jg(KC?O&x zpdz6XA|NOd5)R#^q`+_iA|a*Hf`FuSHw+*MN_WE$(j_oM4E1h)&wW3CeBU4MdR>cU zP3-I3`#jF$%pHH#Ao_y4bi_HKPwxEr(3sU0mde#I{1yaL<|_1#)8HF=lD-++2{@DK zR%V2TcDyh;$UJhGk_i`(y! z+D{z2sWU)hRUqrWwIBidc|d8|%|^0Sfg;e$W7Yc?ETI{A!~_sHv_nJjmnB~xbgM65 zKqHN4)~|9rBN%w$Pf~P+>UB&Jgzp44ndSN)%0hXfQ8`cF(97f2R;0e+ zKT8mKPkw3OeM0d?7|MRKY8{+u-wX~XN5UT9RN1A>u*)IyI^En_c^|As$$aPN@(^R3 zv1%HhJg4SY;W3`96)O2x)@X7bg9rJpeH5Ka+~+#*!LfccJg{4J?A@ooy-)6l(Ncp` zSc>jNabI72Oj5xdp07Y&eR*ASW$4L!>jI%+3VMh7K&neElO#9UW8KA(_joj8^j)4H zq))Xexy0U@?2$kq{@~9aoj!Wd*GjsE!1y2i$!mIB5mT<<9Yg|ITSnkPPt{Mz_{KrI z)NByqQO6hMuWJNyt06^q`qibJDJJ0&WKM$5N|6IT6pxjW`(v$D5kz(AvG&7|>HF`@ zO3T*KiTkNE?>s#o7i!2X$APp#iH;MA@4=}?Wzt*_j>E^kNJ@!@;LeH<(3gk+7`EM{=?`Z=8;kL7bt@X5)I|@ zt@qWo2aMCX3gma)=1kj!kWIqTis-OIDaYnSSWT5d}? z=xMa9n9pTdn7mAexTFLY(Jiz1V6%#NLvSlnPE@lkF3wcT`DK>CN@N&m6A=6dVkY01 z{(K3o)F2Ut;mhX!WSW=U*UMbW3?84nwnM#T^=z`DX#Rot1wkOZV6esjW``K7nJeV{ zg=ewcB`1yN5R{*M$UAiQcFcyQ0=uwXPXvA1Th+-xKSL%C!cE2Hh1`3ij6grGnyhrV z0oCARV-=KVPB=2z{lg2`UJx%K z9%E|J^-3E6kLC-|z!u=#ihf6~t$soeexi)zr~d4opApmo&G-U3c%PMmDz(h3vYTUBDQ{_c=K{&K*@w zVbvd<;@;3xETwgoAr2Dp@{4Oc%Bt~0g*$6<*pRH93#u;dMVg9_q?+h zxViBI6vuWaMA>fVJpSn$uU#pJgAJ9@`O8?$5`Gm3O9S@9j+C=o!oWxr=>l}xdJvaiAT28OY(`L0lplyDPQ!JfVtbqlB2wQJ_WE_ zzr}Z4O~mXwy-WIo0OzP|i5TCkppa%~R($S`-clByVq%gw>_5M>DZcg#_Rc zd`2#n7l%#Ys8@gYz;Dr!8KR_O?1`N<%d&sHqqv*GGBcIZ&M zg*vh}=;jc!F>{Tm%zMfC;2}CN$2kaidE4Cbej1daKT5;{0=bX7thIzZGSDR$>{2Xg z&;&03d{{k7QTYrGH8!`QAT*w=|Ko)B%3?iQQlL{*ph!sKnhC)GcR7>M?dXiZ!}0I? z*m3iukHC}Baa$2PQXC&^>1U3Phm){={yjqA3l{%DbRQ*6YqPWL7>XKL_HS582UA=6 zU!<_S+c_SIy?Po^BoqQoh{E%u^Y;!mx{KN=zHrm8e1!SG9H^9wGo@A=SeK8WE4)G- zfDyVad56t!G?EbdPVhr&%T2j)VI_3g?`_=K1-yIMvz#L+1T^pAS4&S)pPt?}^{PzC zNQ%K8Xcpng7`)&ODaAsc2LA@NklcJZ$iSVv)*6cvXq1&I{JTVLbq__A{%fctk@5|v z6r&#vEYxx(b3^Q81+)KEZvSY}yb?2<jVz~aPsl<2Y86u+_>OIHt@X- zM)ra2c-+?4ppV%04*M0qWqoBl+0y}=R5(?y|4F=VV+Dg#A=$_EQ0vv8_PL10`e63n zX%dVWSKe%C?w|uCxQ90}sFQY{ExlI-F!x&lFRd`W6)7cC8r`_%Gj8K1xvPRia=UuU ze{oNrH3>viiyopXy=8~wU!hgB;p&WMhqn!sNov!m`8e@n)Fn3T*jL>Rka-We;QcO6 zF;_bl{ou|;9vZ7j&3k|8)kCX{^VnuJOSVGU7WJ@k83~q zwD-j+nGOy8Wv$>iv>xE=N?`L7h*XOm>P=wlPr~2V{6#8qnn=MUjH#lXU2dYM_gl!m zZB(bsj@KOTIEO)Q=3H=T1&3YOvNVz<&F_l8TF>it=e6*5OW@5AOK*!t633sEV5IGrw%0 zX#T-d{VLe5USC2&k`HNAa{Whk1}9eZxrrwA{;KJCWLh%o!d%a&Eorp}**_(7ojEWF@();wQ!^>(JzQZqNw98&;F$bQ@tb=iHZ zzpXEz6Iv*-J4(A1zw-?S^WChhhuE!iVm#MKagdQng0V;fEiDr{HS zrjtc4(m&`-slSS-YT!2##D06YKE9=lF2hQPU$jl^KF`{KC5@~##FJYGo?|wzN_g&? zmXvX%?=~~_81;Hr99Z*h4(sgIRUUZNuDkOf&9VAO#$xSildsXj272pK??;%l1`h0y z>hCkBjwznVxhk;uF7;P`Z*V$Ot;~&Taw9}~-MvpGwJwr7!j;yOrtU$^E^$HP`)Q4> zM-K+keIYQy>!Zv=8bgBro4{3+EO7Vz&js*z68e9i82A5)zq9YZYWgo>OMB0SFOt5I zQyjk8QxG{nsF$*G<$txkgx6PSH?(!E4N*fDqdKWFzFK$(amjsM90aQ~{s#8dO(fbcF ztmUibqTYo4ANp}P5R^_X5L&|IJaAXGF6^B!@Uq|d{`lP#DAi8QvGl?XB{gmd!1a^*nN7-i%yQ|<>+}enKn|7-GE2D^&e5h(pK=!XZ+uJ5>r(3CWUc_}|J8Tj-smL|#8#lrE^>}#NahDl zG;O@|DRSTO$|(7&H_^$uGE1((#_+AnwviLaw_E;TDk z=fVOV0XUBD4dC40Xbk#-2E+5@I{kW8E%p-zp+ov+cHZwJIOtp|?20%Ai1kChV`CTX z_guiBsn%k(^WK8b@qNpqs)8&ilFis2$3c$rZb?JURum75ib=!NlObP8HuJ?BAc*eN zZbaoSU85bd?#GDR@Ivn`imE2V7`oElq(HDXYH7@;VhXV|3X3N(!p1;W<*2i~%x&QE zy7{@2T+BctBOtEKO%OIp{b%laBfiGm<$ck=2@}!u(zGE5hAgr5GW6Slf~uz-zn0!7 zAjJpdKu_8=z~DT(ZxcpbWUyPljdB8YIaPn{9mX2963)(BbRRZwP)(DRdAB3-%$oj3 zjE}hjf8{Oe*1yU^#;fw=u?asvxcRaOy+O!l_Uj?QY{3cKCYX$t<`hs0+Mhm(U3q*x z0zKp2tE&6+yvlv+&2t0y^Yi>T-%A0R#f*+L8as3fc_kT}>3{!p+9Z>hq<(#}@IH`t zOhp(+k5Fs)J6sOi3>*sN@L8+{g||~n@m}mn6u2@X|l7$fLXr&fxyGOmv#@ERd{4DQ;8@> zUfakoOdjHVqWJ9oI4o2-G zp{Br<8Y>%{=E`=G1xemJG3$dkF}RWz(x|o1L#*x5${|+wie)Sn=g3ca&o&cv;|(dH z-w%Xh1$C=627Km2%yPE=@{4#ZgmVv+e))2xC_78!DSBnSu?S-*;k)su=S=_B_W|M( zm&nox?P7QZ;o`#Z^{bwllz$LnDU>vz2z>YFD|%2aI%S$NvE`ciDs92+ws6v_t@+s) zJGJAj!_kxNPAcz8!~Xu~uU#)m>Y-UWevnA`TgRkgH<%9;HDB!nA1E^-N>jl}~an)&ciN+4^Tm(oTG} z2lu}b;^B34uu+MBJ$|*{2ytTS!pX28M!TpEzep15eQlq+H|=OGiC}77WE*o?7M;ZJovINt|ue2@_b91WbH8@wNJG->uEBmmP<< zqK4KV7#zK{RQ!ZZ){O%E)|Eg{-E=m)tl53i+`CrFO6(4kr(?YycaKeeEqIn*s%KIz z1KHJ85YuaV&Zw&%$y83`WPEQ0!72S;R1&t0<_i`?PgN4`$?X%StT=+#v8vztM6uFF ze{XERZsFhXf#q=uOW&!l`oX!QdYF=nOYiZ@3g5{-A@p)Rt46r)N_+8T$mwKE1ZvvW z7lI%kx@%`!U|lcS$8IX*V@50`bJ`=>TXsyfr!m{4l4>B?{&NWtLJK3@)XY9hNF17+ z25P-Hmr899#_}TFPJ5@`5iM0o81=T%LcYUCk2CKVzCIuAZrplvydZ$AqDX!4lWE&5 zVgDbPwud*T358{4F}A9G&95N~OT5Ffx@!Aj=DtBzcG2bXA)Pa)4wOfsx1x$c{{aIk zU9v99l1ajCK+Kf*w-TJZOB^1lN-+OnJf^t1ALsd9r%?m3rb0^tsc+SM*UQe@qJ-pz z{R*lVE7D9)7pT?_!C~HZEI(8CDeqmzy@}%Cw$B^uxusi8V`=ZMOzhoN#o6}Knd#}% zj?b0YK!?rVpBv6!&UQ@O%|_X@D}`BWSKPB-5b2j)zHvi(@dUQ|%an}fkFh>|Nrza; zGdyRq2pui5kEAAs`s1;0PkXx=B2mLf%}~89j2Ut7gi6CdCf<2fOO7Y6)IoK>;RQr7 zvQ0RE8m{3)RMGMubHGH){oMxiw);v@UtUp_x@YdZXx zprP|CWiz|q&V-g51y&uurEKnPpI^KIJ`m;JKX-ga*x6I%x>sa6()D&4!@|uo6{H`6 zZkG>6v(j)kRY76J(;rxwWQLWhS)Fw=80L(5gkXmOv!RiZ)tP-!B%?>p1Nhkp^&4;$ zs=23zu(+%^AIDAgr5+BXc2+&;&Vmh}PTEYLtz^pn9%gUVZk1?aW8^>9%u6TP$RLnk zXit>&8J9Dk%D7wAaU6;&7{4iXG-exmg8}RkK#WC&h;P*u6|TTJP+B~49`GC!WrSJW zBp#jo?w97_#u`3k+1%Q!7-7zFw5^=~oP#gw{`#|cx#Vr{k6qt%{{4RWaFqBH<~Rbi z>#_Girr-IS#qs$@&85GKi^h9J67#a>d!K#siWH9b66wMGS?Bl0n~}UY2L)*SndNy* zdhwyT-rK(`98rJ!guFlIzW=o4!=gn3qkn~yr#waIc0M65+P+2Eg;rRhU1h-(LDn6Y ziBrBTW?S?VNMm1dDxJ+*x<9NZmZheXy`K=10D#eTOpOe#nwtC;pNvaRO@iW55Ru)*i=?IM;+#Yqa5?mES!uIf# zsBcGkN?vEVFSV;E{qL4US!t#3_eA|VXi7PXv1KoBEjXw!{}VdRUfTJ9N`IeXNEm}1 z59w4&dlg4${4T=jpO+W4JQ{ zKNLohlh^#7{7h8)1dQdYnLYoii|+X)%gG~rsy}UwcC`6KxL36gw=Xd?rTS$dBa zVN~Hu>ozQ1tVlW>>v5rgVdJ^Ij=klKLbAdW8M~UdgfY7jo$N?;BlQ`LpIaM4vHZ&md&G`d z>;r0`mSZyaZZ#ah*!qkNGzo^%4j%eve!O6dgi4*yhIlQTIU3s(x%0ZIzBARMsx-TW zPfAXAJUHZdx;hS}s2jHAqGf3!g}UPUajK>-Rqqr^R^UHw&2|F5(^1BDs1Syo{ls^H zUe2EV4WbcL$EZL;hJ}5;iOSHs%&%q`2IiM z5>d+Bc6fiMouJXjaT$84(ulu{Vt;xV`00Er+3tN6PH)>b{eo1YaSirCvgNWHUqxMa z86NzbZCu#iKBctm)q?uA5*7+UDRB{*Dx%Z!%<~cKaB(nuwAb>MQ*mOQqRC%Ca5wSm zjqG0a#utaU&e|=wlF|m}X)E=!pR7q}9gb|z)Jut)(FpbNFqM-Y9-Sm)#!5w@;Pqp% z6H4P&NkwCTMjmrV->PxF#L#>e+%+0`aisaKjX@sP>N>RdU z?IazKz$k0xpLKGQ$};;E^2ud>RBime78p8!qq?;~5KR0@t-h-kd5H6D#@r6ilC6?; zP=d%7=C*I*aO}kY%}+y8|F1vh6WFPafAu0G<6B#3ttmQ;TB zl>ST90HIE&ata0+(huYd+&RLzD_QgNCh1k*(Vvo0pb!$68+2_ykN*BqFjsubH9Uxj zNGJhhvBJ3kGr9ZLB{JmnK=NWL!cXx)<_5ge4;V~^|1Y|az^Xo&a-(lD8s8PMm)v>C zY*Z3(O&VE{T0zEzJRgCVkA4yS$$eglI6Dnir--A)9fd@aLZ4opR6eG(=);a3D6Z3A zv*Q#f5!cUT6*j*IQIsdrnrBRpq9ZXRfv8F1zG-@zzI}hIav5%iL&MU8m`y`H6);My!Wz-Vk#6pVi)B4?V25s>WB4;w*fzSRvK_UKx}P zFKm(d6u_M9?B+jE>AzVcMa8Gl*gbkq+WA2AhtjWZ8^@&z14hW(N6vK_8EnAnykKzS zTG^XyuDk&r^oQN{BXcjNne#{`)aqvDGEw~J=|9b2 zQ*A{fjVU9;&GF)&ykS0(15u3#1_h%e8& z{qmsws!4jgLi>oF!f>-Yw=EzvocNu?vooy06q?4uBX)}?@O0}OXxo~l0m)?jJ>psf#yPLeSe;N6c zW8{#a>4N*pEE_{jt(Vomm!-cjkm!}f(QBe2annM_4QKn)LZ-0kA7cho^j}TnNVi{u zL(7dw%(SR4FrTx{u8DY%7Kyx=OHC!gdC>;quqW(lsd=2O6a<;36O?S*+YdZaT;FrY z-nufIA2IR?1+QIfhH;oMvzSR>`flg#SC6||Vzqq6KlGCLo<)ro8Yy-;Z5*%h6vnrH z9$A@bjBp@?@%p`YkiT$=GV9K|+Jm+c;F#IvQY(Xg{GYNcFH$A-*|pVuu6 zP_9}LVB$_(@FZMFX=0028-9xi8Z&pywiwm%kZ&e&)_PlEEuE6OB$>9%P+`c7%l6m?pB%Xto_ zv^l+h6kMcN6N_$`GZPc04!&|ZF!%ko$x^Qbz7fAhYT@@+`Fq9MA0x0;J-uyv72D4I zR_L{|ZFH2sxFV;p#rf#Si1Mr8iHZ9GydGKGZk%#HPDCvuc3Og#oowMfSVC^Bl4><| zr8-roVr)sy!{~Etlhx_6ExKL(5f3w*CA(+Ix>J>6$&%Ge%*OH^HXT78rsfcx?`wsd zwH_+QH>ZhcV3gO3aCQ?h)YbQx{gR0h1!aw~+)l`xUUhNI!zwaDE;0Y7d%tGW!@bd5 za(8&Qu83IRSM-h2xfh-5$n?9-CfDKglpdWQb9NtcLeHtS(#q25pzC`(=yTYr%|cM# zU`WWD|BuFLPsCFORQaF=vMF`D@eYN3H6irnXiq+632#Hm?!o8xDFMuqbmKoXB-7Vs z>jKvfh$eQ=lswt@20>V7@MQZZR&$u3;@!Wcw?(pj9vFf2)Y%*Ki4GsOZQGTM0AZP4 znq3%8Op4~=!#3E@zT0cR76x;2DH@E~6XLlJb~`-qSok$!N);Myq4ckn5MTNfPr85f zK2cZs*!oOIMHu9n#wlrCY9Sfme$&xZjMx<3;JO|b$J(Qbs4`N{)KwCC0?)42*+bLP zc;#(Rkc%JW$4OW2U1In|?JxYO@ul%??*d26nR~RwZj21qS0f3Wnl=3Uw3$oHIYa*5 zB^{v)GboO9)ckf*(xUo4+NRQ*Ty45vXOVBCU|zu~D; zIK2c}^EEBOwOqHJ@vjBN)--sSr-&fi<~3G#8ZE&_#^LGe^ct#FYHws5MXDsPZ@T#w zu&-RNyL9g&)Z)&IV5N4;fdj-Tx6(m;25J8X_2;fMU&zcrY=H>?)6LA(iYemP=<(m$ zG9NQ_mSI4}bI13F0~$}>q~01eX?VIvf{D)stIH?_rpXC72ZP2A`nm{t6jdlxid@Pe zBOFQxqb>E$_BZ0^pDRkn{OiQqE<9IU7pT#EH#zqNWUtcIGh~IaUgExrDbUOc!Nl~3 zQVf0SOwlKyLDMUQ0|$=CS1BzH|A(K4(G(R~;K%T*HfXH76zOCrkU5@2LW#I9nQB@inD>7fz(*`)&bFn5|4j=4_l4M-NTzi$~XcgL>%xJ=$n{US;UbA@N=sBZz_{Oe>b)6 zLZMsOvB`j8I`*A`xcupJbU*5)z%ut2;2l)1+V^4QHj_*?KTed+;64DVbz{Tbd{s^^ ziF51OqJ2v8IoL#u+OJ=~sF*x=<(vgsi5)T6LlJ|9v2|B2U>h#jXoatA`?%vzC4J1- zOFV`mOsQW{@au`5*+`Ye63_|!yIK8sVG~wIHTDC(JP8;CG%L3E5J#Yn&H)3T-ncx( z4u6Qnoa&~)3-8xzjihM|@|`J9hthoqAEuk0}})SJCfoMk@o5`_aA zjWFFjs|PUhmrVvn#1p|O7{e}&LCuCDjWW*Y1w_r- z4V9Eg@CgVu*IZp(o)jHyoW4hVOFSiuqu}b@)hP{_`@H7YvRGtB=9ws*j;Wi`=T55e zpiC6-t1Hse(D?TyBMK1g!~1Duy={1drf|!f(f5<$XyVuB8qdB@EW~3^~$M>YdplH*mZM(!gl*X%9 zx88X^TKLV0)l03>h3`jXD?SB@v}QOwJU>!0sxTYgHeAgfCyV$w!w*a^VJadAqu~ z84a+;9R58E5?&2|>f+|c#l@vDBD`K8YwZ0Xf?Ya3tnPh<#&_Og!=>DCT@1nEwMN zTjDc~AWW9KhUc2tbQ(?l8S9ZFm*@*SQWkYHneTZrVn#N_yIOgrMAGSgl-dH2(Mz)o zn|Du~inBbq{ktD+NSnSIqGnC*{<)X9S3EaV2*pFn5;C46;Q{7$E; zuHj>`i30b&7sJk6yR`QmHOs-Ne5(uBC6JYg03B;pz+^PVlO-`Szj9@f+5A-_~|T4O}PnrFq|LH3#m^;A5rs zLI5$Z!tRZ#)0oI}ERDavf8WSRR-%k!y~#F+zoL@cTR{VG3P?2qg;v8OBg9RC5fM}YO7asiVg_mtWz7?L?~18gcGjK8 z2{sKeX+PQCNq2X$J9U7KUK||D_udKXbN>TPd@YFQkfI|iOY>W^Ikr-jT+SbDy${(1 z6%^)A+yHbbK=zdL;J>I1ATU+~(48c^Ho`%91BIxJZ^AMR%?pZLc>Te-4xcf+@jUZC z|J(%02ckyUBZ!PTH0y^Xvf|8ds}umZ@ov7;5D;<45qtooKVTdC1tn`=Z^!OyN#Gnd zqVqm;Jf{3*#gDU*dXeFINs+G&UYArmb@HPr+|1Wq!0C*AVI0Hcmz(AJpFUGF+RQMi z=Qvh;RJ6pbFb|E6HrW(B)T;2oK~C5SEpWQ1n%)o=mT5LdGYvLs7)F$5j*pc|l0arf zaK%U@X=D>XRmd}J1|Y#da7t&7q0&XW3#44hrM7Dev>cf|Vydz&EDEdMSt6%7o+>fj zj5_B0((#G~ipJ+q`aa$7Snu}O87bJ$O?2x@{Y>X{zYkFFyZThwOJwGko5J{ebY5!D zxv*Py`en~=h9^JA-ByBn4eEK|25pJ12iea?JJxJIJjZp(U3jA?Mm>#Dc55%}o{efG zWqU&CsM9kVZf8L)L7Kvu508m(cMb)$8rHo!Yh4@Zgz@gW2Ji3Jdm#?E{O8FS#T)Y`evh3O%sQDG5d51# z0QdYjZ{%glu%31#&PjVYXY6KLulmR0ZsnGq8(qCHS-`aHG|~?47*vsY1N~376yH28a37;VIK0QS{b347e$enqvid}goVLDVVtjbAyTY)tQUHv{VDgrna{fMe9 zokyCQLFH|Wq6+GKPn_?lFp2he%Z3BiA7%e+!IVHH|U2tGzg4~&Sp4U5NsjCN%2|rruP>t!^)4*uA39BrJf19dK96qGKV_dh_dSrk z8w}tzhk7=-;ogrT_2xlapOu)iT&?k+aId6&Y+9mCj&>yljb^v|she2VLx=k4)v??) zPvaIb+oUrKn=6GYkrbSMpXUZWhb21*ZP@XKxQRf{&B18(5+vu~P+07VwZS4YgPVp) z)9}Rj*RSWU|6N+T6r3`eUbD_ogfUfx=KV@LKi+p(shcM08?pNZQmPt;`&B8h$lMuR_p$%zTNf$*rvxF!X_G95*|1UT9kHKE?jh^Bl&(^OMR)v@S8QYO zefE^zWnJin4Xw2060F~eDdI+2TIKXA&fZpj#S>Ga_%Sm@g6-Cj{e4D2%{^MO!-%P_ zyKQxe6aYebVX1&*RHa-=wWf2l+W@D0aZly5tvHQhjx4AVxi2L}L(6fMr6F&$(8TPJ z6!0*w{9fY26VJ{v$T!7tA`HAcf!1^z@5%G(geerPu^!ZZ%?->3)J2(O_JNsViUr^x z^u0inj?GeVE8*AWA@`Ql+Ihmj%w!YG`PTdDT^*#aEMdeNNQN8dm8TI2j!{4{UCb4;z;&o2E2~%n>8lGdH-ARKl1Prk zuX-8h7Xr+Xe~`P>6++^GcjLxlvABM7e$Rzh;Q1mQfOPx=0Rz$3kQ2J#*!SMNrC_WE zNMZJ+qY`X*BCyBKSw-zDMvD-ug*w60Zfub*e{nDY=l3zVxNnh92_Ce(Uzp(= z^PCk_t`x3c>QcSn)$j%MY{=^Jt=s-?95p=`z!Ko&XP$ks!*PxXHqnE&s)>n-KF`zI zXgy-jFfJ(JXrA()X(yvGV(w}Jo@sh)Uhet@WIP?jRGZ-Ad2z3VqqO@QCEXewJWUh= zQ!R48e!ar(^DOUqHEO_;r^~^Qrr-4E?h6s;W+xXHw|UrZ$DZrNxTHQGzh-ei#r4+- z%lGXscn>Zj+|m=9ZGKndSNVwQ?FCfPn_pxWI%=i+g`B?Nk32?%l*;PXVX3|foaYps zR#rd|!G35V~$7r=OWQTr-afQ~msePq@emsDwlp?l71Up{yP(*Ho)RqKu z!q7!N9;6#vfWHfJjG&fbXN>Ts@n^wIRBV>|y?^PMxkQ3m^R}o5E+#*2T^e^PWpPJT z%sL2VKN1CHe&4>azaa6JpfLif>cS2gm-}eBN=L9s`~S`0OQI%ysfOq7<~I98{iXr$ zsaa5ZVq8`xx#uduCt@8!BBJljHt??>zn`qa`ueQ{;ckJ@ zrp$f2v0|B=?YD&gR=35CvuV~|Tsj1Qs;SkBo5Qjt(C)OzTOGqjDAHs0$Mi2o!5eZb=tmsGtdh^%W(vsx%@asoC z`-bs%eeO8iUCBVlVbN2kxz@nL^dC6E`!qu!H?z+K-!Qbe6UEpqexVFay|llt`E;e0 z`h=XYMQp{(5g!{WIrHeKAv)2r_N&xHKFQKPZ!J*|goSC;)WW}zIp0AT!F`SI_IP&p z_BQv8=l3u9skaal6Q-t@X}-?Me}pXq6UY4Xc>3aSw^^IU1<2KofO{qy)i@_i#1?x( z`4^7l^snO>LOox?vS<2Yhe%p6d}8;zl{~|K+`B~wqWIBEPpEbO-U3-4jo5eOq4=c- zK-yo9OwDc3gTNn;(Mp!(ZLp+m{PN}PMI;_%=j*Uot!VDhqajg5p#gF5=lhP_PKxUX z#A3!M30QGWK#ePMW=TZ>;YK;6p8}_Rs&QG38nBwwmh-$slDbLQg&J`;I|I}t_s=-J z_7@-;Ev-@VTlN%kA5}%^N#*wSRN_%1jnZO>4saxQ%`5zvfGpgQ=MRt!Y=hL7mQpHB zqA-h#^P-Me_5>lQRK~;5&~RmCL*7UZs;#YMaNRhbU0hyH1Vg^Okg!Qm5q5fwzyo;U zYJ%`99%$`zVQenr6qfsR>4De__(&4()3N^<>gVHuCxbxG@VTh0fC4`*WK0A7y*QG(b3yQ zQS*SF!8=aiE*TWdxY)os=SVWDz`N#c!X$2#ioo0%_GQszOB71AWY`+Gd^gIS`C!VK z9CFIK%J^HaUz7Lw>B7;`QC6!7DPJCqc*%qlvWmoyt%Ls#e~Ln%_WX`$tNq9_E>#V6PJWQU9-qk;&27<4OMKTc$Hs*5tad1-UHT*euDy(N#$0B(OJ`)WdV?EPgeVn@) z3ybP_vkm7ARuH^sl#C~PsYvmvvH8s8g!#-PtS(em5n@SKqLLIzPjB}PMP(rXF0eEK z0O(SU56@6=Rs-QH|F;PolbRsd1mYH{1qEtajRggi0IOEUTc-i7BAhFRk=^-i7!*Qx(UxywtCrzdF?S5 z_w}6dLV-EiUtW0tLZ1DNPYjX-xbjGUt0;_291FXwXiQZ(utT$h=o8{9hv`Q%Dk=WM z&&A#$pQF=BQ)Peh;1m0PBPHq++jYyPx#W_)h!I5qS2}^zyNMAFY=c698q~?q0&Ry zL0*CtVo_%-_fCqCQu!5ddG^yV3GfBSf7Yc@PF5nQ z+UNAXw$Lls1mAb+^q5FHaI`$~Y&8dTdR!#6Z;Y9aAO0BGy)5wI)2vZSybzGpHTQEL zzXTym^V5eZ|J|kr>V{LkdnbVg!;2DSk*2HvdzrT7|DDe-X2l>3UiR=h56_hbGQx+4 z{0#ql&$ifqmC12=f_OLn3x~qsO*nRN$Ay2{0Rfl<#lph!NKrA+coG!iT_ou5UnJ-w zWvXpQZ_kCc??X`5rbGSQNg7PhIO=EzQhGTi)KDx4Y+CdWoT^=Kd@OZwrj|(1mYRyD`&dQNPhTqMzO)q7&5m=)0<>u$r{23?B%TeX*liY+Eh}Izw zE^cn^Sv6)y7-e$F#8@Kn^JioFp)fso*wS0FkW9?7htTN?q@gzvkbARY_l5VJRjt_; zwZOG?^8j$gLcIbbo;O&Slf`SgPz8d3hB^`Khs!4KNrS^@aMMi#mm%MI`Sx|EEaP&N zSaNAMef(=joaO>n%&*Hsty}0zM~_7o{=aZqOr{SE1c*0Bt#W+X%bj49%2azu=dPh7 zmF8ZklZ2R-XOZ@3qP?hI%ID9Yuf}&MrW87nH+J6m#ZaE!ig$S^- zWB|h7<;q6DFR-zo3zcoBjeOCR5|#irt< z(BHp*)7WHjHjhgR2(SOPTNRT?RQssm2~YC&g0g}}*=qXZ>@(WSvM1b%5o{rVyjj2c zMSaevpGCq6pNN2A!Wx>IrrEt6qZT0Z7n^^3&PGc8~GeUpwme-YY!u`}9ucKKDLY(#zi%cRZ1xC)m$GhkMik<+z9 zTu7*9!?Tv%6m?}~+B2Na-62VWyB_~iEgB`o)H_`E^0~|2TuH%OWun!j5nyyXP&VtY zViB`Q&CgfWi{$+bEOE?(e=|2>RckxK9(;}XdVbi00ThVVXGIs(|q3YZC9vW4pYbi301dM@8&(H2VF^@^RtXSzNs8<)8#7hYOPg6sJ-teIa2 z5FfxB71nSVY@=b~+x#bY^luGB$6fNSR=yQ<>Pu9B4W-VP$XP9e6`xUGOp&MxrRCs= zsBgfg^>+&4mwxQ(bv?}z(3c9Z!+D!z1DJNTy)D-o&A{90J!!}V4Uu2$=~eY*6xnmwt3qOnP)gZYaOp zE20<6U;D*64RW)^1wsisR>@T$E zzQCy0JWi$7toJ#l!@hQeitg!fL+p`lCU51S9^)^!Csbv*(={t-dx7>~`gFclfBbmq zj<`79dzDuIy&H$~`%I#HnQ;%L!NKFdaYF&PB?>r6ZtlmkgV|jkJJz}uzcsY4QkKrj zwy(9fw*F3gYtq=D3&wIep3c--@+qI}z?sR;_wq=`>R6cy@tCIur;Th-ce&Q@T_$YOOaf`sE^<9%-p+k16OxAOvR*dqWABo(=yZej`znLhM7OIRBeuP zL|Py88@B}3ls^PeVjgIV^W;*jeEZ=K?efkWgIhAh!VXh+y-#A|=P!|xHr3=s!7gI5 z^)f2U;jEHWh@&Sd0E%hp==_I%aP#FtFS6Ml8XA&1pi%a+;-PKeek{@+jOL3MgpR6Q ztk3mhr=wn*zZZg@SPz$$mO7Ze(aLRC{43hhCSxm+_+0FiR8cU+KXH29l`&*c6Fq%a z93qRl4uVIj;Y{chK@wqWDkl!OSbzkOQ71e{0t6;r*s^dS-OZ!0Ra!rUkZgm9xe7<&m;Vrq^s zA=Dv0{XZhqVOq9!)v_vc7mc6B842FG=qMi+H6_{Hw%T z>q|YTSANV)l?%7dEsn1I$wvru5C9qR)VMxUk6!K|$dwr4@lI$4;A9p#=Fa)A8c zbj*-JN*Cut8sz0VrRIC02*|80D=&|n{o6NE3Q{>8oj4ozucMOxUK~6{W*6Nw!{V?XUyyqPbuy#5Te2-0G4GEHXkzXZ8 z_?~I{Dmt^OGsaWSy@F6vLZB{}t%CYDd2Hk|@TllQucqdw9bc=tf_#K#nX0VG?_I0S zo#RnZP{@Q{VLdDwXpk|Zv>`dg@Bo! zo?tS;Y^sZKu;k78F#&_xIXz$yF}~4lu7v1is%h-Fm%FNHDB(@)w}gAK#7o!)5tyBw z{YPHj`;EYb7PXb&7edSTfcd8HLdA*jWpUuL3VGflA$q$DlqeG zV)`G|i=j6IaDSaw&s`ZkGr$zgCYN$iiC29!EN#?3AA_U{wW)b#XYt8RgI z3Kq{LW80onE|nK)Bavv_838)!;!AZ2-y+x9uCf%r<1`uC?8WE@Q=mAF?O$_iZ$Ihdf4 zLEdlkIi7q{Kg!cX(mwhofWY)(i5d2qE9hER^2b3`6{Dl$Cr1L6%^^Rm!`lJ3xFaEv zR$k5k*vH|I0spTf9)Jt(>mw~XqEA;2MN!FR*w!TFSdQT~c!qs%nevxy;aBe+_<`L8 z^K~|RFP9`!R(hO6@&7~bMd;kN4;-&hfEG~Ef!^ilCf#NB!%N>; zZag7^{-vDnaO$$ngb=(-li8(`LQv1$d!+#IUuI2Wd|+YKLUmPS?(}7f!awL;c|=T& z%}g|QZEX#H*$D_8>A8X{L$TOEN?42gNKtzUcD+PafE=P>V+;ErRPQ@7g5~S;razAL znQxG&KX`p_eqlkxZ9^AoiotnC$Hj4r$Z-6+zfKRyOkJ13666`93@Ijq5`9?|2p*-d z$XHD1CP=Oinzex1*kHU5(|krs44k_5k6zy_M8J(y|LYW(=rx#yga|!;oqKz=7nO#d znxcTL92~&yLsF_zZX3co=ANtcpE$6w_jOQSn#*4^lzveXo{l2m>FB5^(`$Q*z#&-q zkW*bfwn@FXg%-+xUD`UNpYWQw;2d00M1JuRSZzfsm8VZX3Y&K@ST~Wd#&q%%TfBVv z(n^%Bs%VX#AhNYpK3&p}i&XX(_kV7M2ld4q-LRjF48n15DDl`B&t#_v&lf7o-5enB OOIhKWeBmP_|NjS;Fm|&5 delta 35108 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 I)Z+dB1G|44rvLx| diff --git a/monkestation/icons/mob/mod.dmi b/monkestation/icons/mob/mod.dmi index 8f053f47ecaa398bd005c99998c9b1ce2c1977d0..caddf21df1075d6d428c4e45df399eee4a329282 100644 GIT binary patch delta 12011 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 delta 8242 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 Qd1&h4_x0{os9C-KKVLk3y8r+H From 5dd9f5bb4b224ebcff1b3a7e1ee91b8713707d24 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 20 Dec 2024 23:51:41 +0000 Subject: [PATCH 42/81] Automatic changelog for PR #4576 [ci skip] --- html/changelogs/AutoChangeLog-pr-4576.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-4576.yml diff --git a/html/changelogs/AutoChangeLog-pr-4576.yml b/html/changelogs/AutoChangeLog-pr-4576.yml new file mode 100644 index 000000000000..af013c24b846 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-4576.yml @@ -0,0 +1,4 @@ +author: "TheColorCyan" +delete-after: True +changes: + - bugfix: "interdyne MOD no longer looks off when worn by people without digitigrade legs" \ No newline at end of file From 138241027f4577a38cf11d82f48cf40023deced9 Mon Sep 17 00:00:00 2001 From: Lucy Date: Fri, 20 Dec 2024 18:53:55 -0500 Subject: [PATCH 43/81] The monster hunter blood vial is now just a status effect instead of a weird status effect + reagent combination (#4578) --- .../monster_hunters/events/wonderland.dm | 101 ------------------ .../monster_hunters/tools/blood_vial.dm | 92 ++++++++++++++++ tgstation.dme | 1 + 3 files changed, 93 insertions(+), 101 deletions(-) create mode 100644 monkestation/code/modules/antagonists/monster_hunters/tools/blood_vial.dm diff --git a/monkestation/code/modules/antagonists/monster_hunters/events/wonderland.dm b/monkestation/code/modules/antagonists/monster_hunters/events/wonderland.dm index 1e6d4b3a8b42..241a39663571 100644 --- a/monkestation/code/modules/antagonists/monster_hunters/events/wonderland.dm +++ b/monkestation/code/modules/antagonists/monster_hunters/events/wonderland.dm @@ -49,104 +49,3 @@ GLOBAL_LIST_EMPTY(wonderland_marks) desc = "What is this doing here?" icon = 'monkestation/icons/bloodsuckers/rabbit.dmi' icon_state = "red_queen" - -/obj/structure/blood_fountain - name = "blood fountain" - desc = "A huge resevoir of thick blood, perhaps drinking some of it would restore some vigor..." - icon = 'monkestation/icons/bloodsuckers/blood_fountain.dmi' - icon_state = "blood_fountain" - plane = ABOVE_GAME_PLANE - anchored = TRUE - density = TRUE - bound_width = 64 - bound_height = 64 - resistance_flags = INDESTRUCTIBLE - - -/obj/structure/blood_fountain/Initialize(mapload) - . = ..() - add_overlay("droplet") - - -/obj/structure/blood_fountain/attackby(obj/item/bottle, mob/living/user, params) - if(!istype(bottle, /obj/item/blood_vial)) - balloon_alert(user, "Needs a blood vial!") - return ..() - var/obj/item/blood_vial/vial = bottle - vial.fill_vial(user) - -/obj/item/blood_vial - name = "blood vial" - desc = "Used to collect samples of blood from the dead-still blood fountain." - icon = 'monkestation/icons/bloodsuckers/weapons.dmi' - icon_state = "blood_vial_empty" - inhand_icon_state = "beaker" - lefthand_file = 'icons/mob/inhands/items_lefthand.dmi' - righthand_file = 'icons/mob/inhands/items_righthand.dmi' - w_class = WEIGHT_CLASS_TINY - item_flags = NOBLUDGEON - var/filled = FALSE ///does the bottle contain fluid - -/obj/item/blood_vial/proc/fill_vial(mob/living/user) - if(filled) - balloon_alert(user, "Vial already full!") - return - filled = TRUE - icon_state = "blood_vial" - update_appearance() - - -/obj/item/blood_vial/attack_self(mob/living/user) - if(!filled) - balloon_alert(user, "Empty!") - return - filled = FALSE - user.apply_status_effect(/datum/status_effect/cursed_blood) - icon_state = "blood_vial_empty" - update_appearance() - playsound(src, 'monkestation/sound/bloodsuckers/blood_vial_slurp.ogg',50) - -/datum/status_effect/cursed_blood - id = "Blood" - duration = 20 SECONDS - alert_type = /atom/movable/screen/alert/status_effect/cursed_blood - show_duration = TRUE - -/atom/movable/screen/alert/status_effect/cursed_blood - name = "Cursed Blood" - desc = "Something foreign is coursing through your veins." - -/datum/status_effect/cursed_blood/on_apply() - . = ..() - to_chat(owner, span_warning("You feel a great power surging through you!")) - owner.add_movespeed_modifier(/datum/movespeed_modifier/cursed_blood) - - if(iscarbon(owner)) - owner.reagents.add_reagent(/datum/reagent/medicine/blood_vial, 15) - - return TRUE - -/datum/status_effect/cursed_blood/on_remove() - . = ..() - owner.remove_movespeed_modifier(/datum/movespeed_modifier/cursed_blood) - - - -/datum/reagent/medicine/blood_vial - name = "Blood Vial" - metabolization_rate = 0.4 * REAGENTS_METABOLISM - -/datum/reagent/medicine/blood_vial/on_mob_life(mob/living/carbon/affected_mob, seconds_per_tick, times_fired) - if(affected_mob.health < 90 && affected_mob.health > 0) - affected_mob.adjustOxyLoss(-1 * REM * seconds_per_tick, FALSE, required_biotype = affected_biotype, required_respiration_type = affected_respiration_type) - affected_mob.adjustToxLoss(-1 * REM * seconds_per_tick, FALSE, required_biotype = affected_biotype) - affected_mob.adjustBruteLoss(-2 * REM * seconds_per_tick, FALSE, required_bodytype = affected_bodytype) - affected_mob.adjustFireLoss(-2 * REM * seconds_per_tick, FALSE, required_bodytype = affected_bodytype) - - affected_mob.AdjustAllImmobility(-60 * REM * seconds_per_tick) - affected_mob.stamina.adjust(7 * REM * seconds_per_tick, TRUE) - ..() - . = TRUE - -/datum/movespeed_modifier/cursed_blood - multiplicative_slowdown = -0.6 diff --git a/monkestation/code/modules/antagonists/monster_hunters/tools/blood_vial.dm b/monkestation/code/modules/antagonists/monster_hunters/tools/blood_vial.dm new file mode 100644 index 000000000000..11afb8c8f5de --- /dev/null +++ b/monkestation/code/modules/antagonists/monster_hunters/tools/blood_vial.dm @@ -0,0 +1,92 @@ +/obj/structure/blood_fountain + name = "blood fountain" + desc = "A huge resevoir of thick blood, perhaps drinking some of it would restore some vigor..." + icon = 'monkestation/icons/bloodsuckers/blood_fountain.dmi' + icon_state = "blood_fountain" + plane = ABOVE_GAME_PLANE + anchored = TRUE + density = TRUE + bound_width = 64 + bound_height = 64 + resistance_flags = INDESTRUCTIBLE + +/obj/structure/blood_fountain/Initialize(mapload) + . = ..() + add_overlay("droplet") + +/obj/structure/blood_fountain/attackby(obj/item/bottle, mob/living/user, params) + if(!istype(bottle, /obj/item/blood_vial)) + balloon_alert(user, "need a blood vial!") + return ..() + var/obj/item/blood_vial/vial = bottle + vial.fill_vial(user) + +/obj/item/blood_vial + name = "blood vial" + desc = "Used to collect samples of blood from the dead-still blood fountain." + icon = 'monkestation/icons/bloodsuckers/weapons.dmi' + base_icon_state = "blood_vial" + icon_state = "blood_vial_empty" + inhand_icon_state = "beaker" + lefthand_file = 'icons/mob/inhands/items_lefthand.dmi' + righthand_file = 'icons/mob/inhands/items_righthand.dmi' + w_class = WEIGHT_CLASS_TINY + item_flags = NOBLUDGEON + var/filled = FALSE ///does the bottle contain fluid + +/obj/item/blood_vial/proc/fill_vial(mob/living/user) + if(filled) + balloon_alert(user, "vial already full!") + return + filled = TRUE + update_appearance(UPDATE_ICON_STATE) + +/obj/item/blood_vial/attack_self(mob/living/user) + if(!filled) + balloon_alert(user, "empty!") + return + filled = FALSE + user.apply_status_effect(/datum/status_effect/cursed_blood) + update_appearance(UPDATE_ICON_STATE) + playsound(src, 'monkestation/sound/bloodsuckers/blood_vial_slurp.ogg', vol = 50) + +/obj/item/blood_vial/update_icon_state() + icon_state = filled ? base_icon_state : "[base_icon_state]_empty" + return ..() + +/datum/status_effect/cursed_blood + id = "cursed_blood" + duration = 20 SECONDS + tick_interval = 0.2 SECONDS + status_type = STATUS_EFFECT_REFRESH + alert_type = /atom/movable/screen/alert/status_effect/cursed_blood + show_duration = TRUE + processing_speed = STATUS_EFFECT_PRIORITY + +/atom/movable/screen/alert/status_effect/cursed_blood + name = "Cursed Blood" + desc = "Something foreign is coursing through your veins!" + icon_state = "blooddrunk" + +/datum/status_effect/cursed_blood/on_apply() + to_chat(owner, span_warning("You feel a great power surging through you!")) + owner.add_movespeed_modifier(/datum/movespeed_modifier/cursed_blood) + return TRUE + +/datum/status_effect/cursed_blood/on_remove() + owner.remove_movespeed_modifier(/datum/movespeed_modifier/cursed_blood) + +/datum/status_effect/cursed_blood/tick(seconds_per_tick, times_fired) + var/needs_update = FALSE + if(ISINRANGE(owner.health, 0, 90)) + needs_update += owner.adjustBruteLoss(-2 * seconds_per_tick, updating_health = FALSE) + needs_update += owner.adjustFireLoss(-2 * seconds_per_tick, updating_health = FALSE) + needs_update += owner.adjustToxLoss(-1 * seconds_per_tick, updating_health = FALSE, forced = TRUE) + needs_update += owner.adjustOxyLoss(-1 * seconds_per_tick, updating_health = FALSE) + owner.AdjustAllImmobility((-6 SECONDS) * seconds_per_tick) + owner.stamina.adjust(7 * seconds_per_tick, forced = TRUE) + if(needs_update) + owner.updatehealth() + +/datum/movespeed_modifier/cursed_blood + multiplicative_slowdown = -0.6 diff --git a/tgstation.dme b/tgstation.dme index c0a0370d4a52..12c9484b8077 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -6409,6 +6409,7 @@ #include "monkestation\code\modules\antagonists\monster_hunters\monsters\monster_effects\killer_rabbit_effects.dm" #include "monkestation\code\modules\antagonists\monster_hunters\monsters\monster_effects\white_rabbit.dm" #include "monkestation\code\modules\antagonists\monster_hunters\monsters\monster_powers\killer_rabbit_powers.dm" +#include "monkestation\code\modules\antagonists\monster_hunters\tools\blood_vial.dm" #include "monkestation\code\modules\antagonists\monster_hunters\tools\bnuuy_mask.dm" #include "monkestation\code\modules\antagonists\monster_hunters\tools\jack_bomb.dm" #include "monkestation\code\modules\antagonists\monster_hunters\tools\rabbit_eye.dm" From 52086880f9c909d426e95ecf150632834f470376 Mon Sep 17 00:00:00 2001 From: Shoddd <148718717+Shoddd@users.noreply.github.com> Date: Fri, 20 Dec 2024 18:54:06 -0500 Subject: [PATCH 44/81] Doubles number of explorer role slots (#4507) * hand check * immobile * Accidently branched other PR removal * increase --------- Co-authored-by: shodd --- monkestation/code/modules/jobs/job_types/explorer.dm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/monkestation/code/modules/jobs/job_types/explorer.dm b/monkestation/code/modules/jobs/job_types/explorer.dm index 5bd358a57a92..97787c038ea3 100644 --- a/monkestation/code/modules/jobs/job_types/explorer.dm +++ b/monkestation/code/modules/jobs/job_types/explorer.dm @@ -4,8 +4,8 @@ Visit strange places. Die in space." department_head = list(JOB_HEAD_OF_PERSONNEL) faction = FACTION_STATION - total_positions = 3 - spawn_positions = 3 + total_positions = 6 + spawn_positions = 6 supervisors = SUPERVISOR_QM exp_granted_type = EXP_TYPE_CREW config_tag = "EXPLORER" From 592da70f30b6106d5ab452f3ff329a25e934b9ea Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 20 Dec 2024 23:54:14 +0000 Subject: [PATCH 45/81] Automatic changelog for PR #4578 [ci skip] --- html/changelogs/AutoChangeLog-pr-4578.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-4578.yml diff --git a/html/changelogs/AutoChangeLog-pr-4578.yml b/html/changelogs/AutoChangeLog-pr-4578.yml new file mode 100644 index 000000000000..2ade9de8a0fe --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-4578.yml @@ -0,0 +1,4 @@ +author: "Absolucy" +delete-after: True +changes: + - refactor: "The effect from a monster hunter's blood vial is now just a status effect, rather than a weird combination between a status effect and a reagent." \ No newline at end of file From 31f7da370da068254d0edd89e1aabcb44e02bdc2 Mon Sep 17 00:00:00 2001 From: Wisemonster <87689371+Wisemonster@users.noreply.github.com> Date: Fri, 20 Dec 2024 18:54:23 -0500 Subject: [PATCH 46/81] Fix heretic sac not restoring blood and leaving chems inside the sac target. (#4582) * Fix heretic sac * Update monkestation/code/modules/antagonists/heretic/knowledge/sacrifice_knowledge/sacrifice_knowledge.dm Co-authored-by: Lucy * Update monkestation/code/modules/antagonists/heretic/knowledge/sacrifice_knowledge/sacrifice_knowledge.dm Co-authored-by: Lucy * Update monkestation/code/modules/antagonists/heretic/knowledge/sacrifice_knowledge/sacrifice_knowledge.dm Co-authored-by: Lucy * Update monkestation/code/modules/antagonists/heretic/knowledge/sacrifice_knowledge/sacrifice_knowledge.dm Co-authored-by: Lucy --------- Co-authored-by: Lucy --- .../knowledge/sacrifice_knowledge/sacrifice_knowledge.dm | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/monkestation/code/modules/antagonists/heretic/knowledge/sacrifice_knowledge/sacrifice_knowledge.dm b/monkestation/code/modules/antagonists/heretic/knowledge/sacrifice_knowledge/sacrifice_knowledge.dm index c78a25f763c3..6822992e285d 100644 --- a/monkestation/code/modules/antagonists/heretic/knowledge/sacrifice_knowledge/sacrifice_knowledge.dm +++ b/monkestation/code/modules/antagonists/heretic/knowledge/sacrifice_knowledge/sacrifice_knowledge.dm @@ -267,9 +267,14 @@ // and if we fail to revive them, don't proceede the chain sac_target.adjustOxyLoss(-100, FALSE) sac_target.grab_ghost() // monke edit: try to grab their ghost + if(!sac_target.heal_and_revive(50, span_danger("[sac_target]'s heart begins to beat with an unholy force as they return from death!"))) return + //monkestation addition start: + sac_target.reagents?.remove_all(sac_target.reagents.total_volume) //stops chems from killing in the mansus + sac_target.restore_blood() //stops target from just dying from low blood in the mansus + //monkestation addition end if(sac_target.AdjustUnconscious(SACRIFICE_SLEEP_DURATION)) to_chat(sac_target, span_hypnophrase("Your mind feels torn apart as you fall into a shallow slumber...")) else @@ -322,6 +327,10 @@ to_chat(sac_target, span_big(span_hypnophrase("Unnatural forces begin to claw at your every being from beyond the veil."))) sac_target.apply_status_effect(/datum/status_effect/unholy_determination, SACRIFICE_REALM_DURATION) + //monkestation addition start: + sac_target.reagents?.remove_all(sac_target.reagents.total_volume) //stops chems from killing in the mansus + sac_target.restore_blood() //stops target from just dying from low blood in the mansus + //monkestation addition end addtimer(CALLBACK(src, PROC_REF(after_target_wakes), sac_target), SACRIFICE_SLEEP_DURATION * 0.5) // Begin the minigame RegisterSignal(sac_target, COMSIG_MOVABLE_Z_CHANGED, PROC_REF(on_target_escape)) // Cheese condition From 69af46a2875c8ec994cf874abfc79da1451dba8b Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 20 Dec 2024 23:54:24 +0000 Subject: [PATCH 47/81] Automatic changelog for PR #4507 [ci skip] --- html/changelogs/AutoChangeLog-pr-4507.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-4507.yml diff --git a/html/changelogs/AutoChangeLog-pr-4507.yml b/html/changelogs/AutoChangeLog-pr-4507.yml new file mode 100644 index 000000000000..4a4e78fa9ae5 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-4507.yml @@ -0,0 +1,4 @@ +author: "Shoddd" +delete-after: True +changes: + - rscadd: "Explorer now has 6 slots" \ No newline at end of file From 97f211606f8247c9d42b921df5ca57945b50cf6e Mon Sep 17 00:00:00 2001 From: ThePooba <81843097+ThePooba@users.noreply.github.com> Date: Fri, 20 Dec 2024 16:54:36 -0700 Subject: [PATCH 48/81] I fixed cant breathe mood bug (#4631) * guh * double guh * it worked --- code/modules/mob/living/carbon/life.dm | 1 + code/modules/surgery/organs/lungs.dm | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/code/modules/mob/living/carbon/life.dm b/code/modules/mob/living/carbon/life.dm index bc6d946ca869..46a210893fc2 100644 --- a/code/modules/mob/living/carbon/life.dm +++ b/code/modules/mob/living/carbon/life.dm @@ -56,6 +56,7 @@ if(HAS_TRAIT(src, TRAIT_NOBREATH)) setOxyLoss(0) //idk how because spec life should cover this losebreath = 0 + failed_last_breath = 0 return var/next_breath = 4 diff --git a/code/modules/surgery/organs/lungs.dm b/code/modules/surgery/organs/lungs.dm index 31af8b7deb7c..57482868132c 100644 --- a/code/modules/surgery/organs/lungs.dm +++ b/code/modules/surgery/organs/lungs.dm @@ -114,6 +114,8 @@ ///our last lung pop adventure var/lung_pop_tick = 0 + //fucking checks if the last breath failed was actually from something or not, and if not clears it + var/failed_last_breath_checker = 0 // assign the respiration_type /obj/item/organ/internal/lungs/Initialize(mapload) @@ -640,6 +642,10 @@ // Check for moles of gas and handle partial pressures / special conditions. if(num_moles > 0 && not_low_pressure && not_high_pressure) // Breath has more than 0 moles of gas. + //checks if the last breath was one of the not- this fucking breaths so it can clear it + if(failed_last_breath_checker) + breather.failed_last_breath = FALSE + failed_last_breath_checker = FALSE // Route gases through mask filter if breather is wearing one. if(istype(breather.wear_mask) && (breather.wear_mask.clothing_flags & GAS_FILTERING) && breather.wear_mask.has_filter) breath = breather.wear_mask.consume_filter(breath) @@ -672,11 +678,13 @@ breather.cause_pain(BODY_ZONE_CHEST, 10, BRUTE) apply_organ_damage(5) breather.failed_last_breath = TRUE + failed_last_breath_checker = TRUE lung_pop_tick++ // Robot, don't care lol else if((owner && !HAS_TRAIT(owner, TRAIT_ASSISTED_BREATHING))) // Can't breathe! breather.failed_last_breath = TRUE + failed_last_breath_checker = TRUE // The list of gases in the breath. var/list/breath_gases = breath.gases From 2d63a198640d1c20163330a2fc5f1643bdbed732 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 20 Dec 2024 23:54:40 +0000 Subject: [PATCH 49/81] Automatic changelog for PR #4582 [ci skip] --- html/changelogs/AutoChangeLog-pr-4582.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-4582.yml diff --git a/html/changelogs/AutoChangeLog-pr-4582.yml b/html/changelogs/AutoChangeLog-pr-4582.yml new file mode 100644 index 000000000000..8971cf355771 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-4582.yml @@ -0,0 +1,4 @@ +author: "Wisemonster" +delete-after: True +changes: + - bugfix: "Heretic sacrifice targets will have their blood restored and cleared of chems if they are sent to the mansus." \ No newline at end of file From bc50fb44027d29a6b9cad12312b2094a08ed2714 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 20 Dec 2024 23:54:56 +0000 Subject: [PATCH 50/81] Automatic changelog for PR #4631 [ci skip] --- html/changelogs/AutoChangeLog-pr-4631.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-4631.yml diff --git a/html/changelogs/AutoChangeLog-pr-4631.yml b/html/changelogs/AutoChangeLog-pr-4631.yml new file mode 100644 index 000000000000..f34e16680144 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-4631.yml @@ -0,0 +1,4 @@ +author: "ThePooba" +delete-after: True +changes: + - bugfix: "fixes the CANT... BREATH... moodlet but when you could breathe fine" \ No newline at end of file From 2a64625062b7857c880b6ba87ecfc6668cad7e30 Mon Sep 17 00:00:00 2001 From: Changelogs Date: Sat, 21 Dec 2024 01:38:56 +0000 Subject: [PATCH 51/81] Automatic changelog compile [ci skip] --- html/changelogs/AutoChangeLog-pr-4270.yml | 4 ---- html/changelogs/AutoChangeLog-pr-4507.yml | 4 ---- html/changelogs/AutoChangeLog-pr-4548.yml | 4 ---- html/changelogs/AutoChangeLog-pr-4576.yml | 4 ---- html/changelogs/AutoChangeLog-pr-4578.yml | 4 ---- html/changelogs/AutoChangeLog-pr-4582.yml | 4 ---- html/changelogs/AutoChangeLog-pr-4622.yml | 5 ----- html/changelogs/AutoChangeLog-pr-4624.yml | 5 ----- html/changelogs/AutoChangeLog-pr-4631.yml | 4 ---- html/changelogs/archive/2024-12.yml | 25 +++++++++++++++++++++++ 10 files changed, 25 insertions(+), 38 deletions(-) delete mode 100644 html/changelogs/AutoChangeLog-pr-4270.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-4507.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-4548.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-4576.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-4578.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-4582.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-4622.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-4624.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-4631.yml diff --git a/html/changelogs/AutoChangeLog-pr-4270.yml b/html/changelogs/AutoChangeLog-pr-4270.yml deleted file mode 100644 index 7ec36ae5c59d..000000000000 --- a/html/changelogs/AutoChangeLog-pr-4270.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Wisemonster" -delete-after: True -changes: - - rscadd: "Added a disabler to QM's locker. It has a cargo-locked firing pin that can only be used in the cargo's warehouse and storage." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-4507.yml b/html/changelogs/AutoChangeLog-pr-4507.yml deleted file mode 100644 index 4a4e78fa9ae5..000000000000 --- a/html/changelogs/AutoChangeLog-pr-4507.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Shoddd" -delete-after: True -changes: - - rscadd: "Explorer now has 6 slots" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-4548.yml b/html/changelogs/AutoChangeLog-pr-4548.yml deleted file mode 100644 index d23a01572b01..000000000000 --- a/html/changelogs/AutoChangeLog-pr-4548.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Loiosh42" -delete-after: True -changes: - - balance: "Reworks Debilitated, and by extension buffs disablers" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-4576.yml b/html/changelogs/AutoChangeLog-pr-4576.yml deleted file mode 100644 index af013c24b846..000000000000 --- a/html/changelogs/AutoChangeLog-pr-4576.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "TheColorCyan" -delete-after: True -changes: - - bugfix: "interdyne MOD no longer looks off when worn by people without digitigrade legs" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-4578.yml b/html/changelogs/AutoChangeLog-pr-4578.yml deleted file mode 100644 index 2ade9de8a0fe..000000000000 --- a/html/changelogs/AutoChangeLog-pr-4578.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Absolucy" -delete-after: True -changes: - - refactor: "The effect from a monster hunter's blood vial is now just a status effect, rather than a weird combination between a status effect and a reagent." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-4582.yml b/html/changelogs/AutoChangeLog-pr-4582.yml deleted file mode 100644 index 8971cf355771..000000000000 --- a/html/changelogs/AutoChangeLog-pr-4582.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Wisemonster" -delete-after: True -changes: - - bugfix: "Heretic sacrifice targets will have their blood restored and cleared of chems if they are sent to the mansus." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-4622.yml b/html/changelogs/AutoChangeLog-pr-4622.yml deleted file mode 100644 index 1166a40b92ca..000000000000 --- a/html/changelogs/AutoChangeLog-pr-4622.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: "Coll6" -delete-after: True -changes: - - rscadd: "Ooze sucker machinery can be stored in multi tool buffer." - - bugfix: "Allows ooze suckers to be linked if its inside a valid pen, that is also linked to the same controller." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-4624.yml b/html/changelogs/AutoChangeLog-pr-4624.yml deleted file mode 100644 index 6066900592d1..000000000000 --- a/html/changelogs/AutoChangeLog-pr-4624.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: "Uristthedorf" -delete-after: True -changes: - - rscdel: "Removes tasers from the armory." - - rscadd: "Tasers can be bought at cargo." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-4631.yml b/html/changelogs/AutoChangeLog-pr-4631.yml deleted file mode 100644 index f34e16680144..000000000000 --- a/html/changelogs/AutoChangeLog-pr-4631.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "ThePooba" -delete-after: True -changes: - - bugfix: "fixes the CANT... BREATH... moodlet but when you could breathe fine" \ No newline at end of file diff --git a/html/changelogs/archive/2024-12.yml b/html/changelogs/archive/2024-12.yml index 95c9a8b7c5d7..b239606c6752 100644 --- a/html/changelogs/archive/2024-12.yml +++ b/html/changelogs/archive/2024-12.yml @@ -337,3 +337,28 @@ - rscadd: Players who have been sacrificed by Heretics will experience additional and rapidly lethal consequences for attempting to fight someone who previously sacrificed them, as long as that person is wearing a focus. +2024-12-21: + Absolucy: + - refactor: The effect from a monster hunter's blood vial is now just a status effect, + rather than a weird combination between a status effect and a reagent. + Coll6: + - rscadd: Ooze sucker machinery can be stored in multi tool buffer. + - bugfix: Allows ooze suckers to be linked if its inside a valid pen, that is also + linked to the same controller. + Loiosh42: + - balance: Reworks Debilitated, and by extension buffs disablers + Shoddd: + - rscadd: Explorer now has 6 slots + TheColorCyan: + - bugfix: interdyne MOD no longer looks off when worn by people without digitigrade + legs + ThePooba: + - bugfix: fixes the CANT... BREATH... moodlet but when you could breathe fine + Uristthedorf: + - rscdel: Removes tasers from the armory. + - rscadd: Tasers can be bought at cargo. + Wisemonster: + - rscadd: Added a disabler to QM's locker. It has a cargo-locked firing pin that + can only be used in the cargo's warehouse and storage. + - bugfix: Heretic sacrifice targets will have their blood restored and cleared of + chems if they are sent to the mansus. From ac6ae3b7c1b41150c6ec2fe0d421211058185423 Mon Sep 17 00:00:00 2001 From: Shoddd <148718717+Shoddd@users.noreply.github.com> Date: Sat, 21 Dec 2024 15:33:31 -0500 Subject: [PATCH 52/81] NO MORE (#4641) Co-authored-by: shodd --- code/modules/projectiles/guns/magic/wand.dm | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/code/modules/projectiles/guns/magic/wand.dm b/code/modules/projectiles/guns/magic/wand.dm index 82b78a4859ed..56c3a44a5837 100644 --- a/code/modules/projectiles/guns/magic/wand.dm +++ b/code/modules/projectiles/guns/magic/wand.dm @@ -28,6 +28,11 @@ icon_state = "[base_icon_state][charges ? null : "-drained"]" return ..() +/obj/item/gun/magic/wand/can_trigger_gun(mob/living/user, akimbo_usage) + if(akimbo_usage) + return FALSE + return ..() + /obj/item/gun/magic/wand/attack(atom/target, mob/living/user) if(target == user) return From 92dc88bbcf71359d11d8a6c25cf13445b8be4ddc Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sat, 21 Dec 2024 20:33:51 +0000 Subject: [PATCH 53/81] Automatic changelog for PR #4641 [ci skip] --- html/changelogs/AutoChangeLog-pr-4641.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-4641.yml diff --git a/html/changelogs/AutoChangeLog-pr-4641.yml b/html/changelogs/AutoChangeLog-pr-4641.yml new file mode 100644 index 000000000000..2e4b7182013d --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-4641.yml @@ -0,0 +1,4 @@ +author: "Shoddd" +delete-after: True +changes: + - bugfix: "you can no longer akimbo and fire a wand forever" \ No newline at end of file From ece4a124db964d2b6b6a0df71842dec9a3773f27 Mon Sep 17 00:00:00 2001 From: Changelogs Date: Sun, 22 Dec 2024 01:47:17 +0000 Subject: [PATCH 54/81] Automatic changelog compile [ci skip] --- html/changelogs/AutoChangeLog-pr-4641.yml | 4 ---- html/changelogs/archive/2024-12.yml | 3 +++ 2 files changed, 3 insertions(+), 4 deletions(-) delete mode 100644 html/changelogs/AutoChangeLog-pr-4641.yml diff --git a/html/changelogs/AutoChangeLog-pr-4641.yml b/html/changelogs/AutoChangeLog-pr-4641.yml deleted file mode 100644 index 2e4b7182013d..000000000000 --- a/html/changelogs/AutoChangeLog-pr-4641.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Shoddd" -delete-after: True -changes: - - bugfix: "you can no longer akimbo and fire a wand forever" \ No newline at end of file diff --git a/html/changelogs/archive/2024-12.yml b/html/changelogs/archive/2024-12.yml index b239606c6752..5be305e9ae98 100644 --- a/html/changelogs/archive/2024-12.yml +++ b/html/changelogs/archive/2024-12.yml @@ -362,3 +362,6 @@ can only be used in the cargo's warehouse and storage. - bugfix: Heretic sacrifice targets will have their blood restored and cleared of chems if they are sent to the mansus. +2024-12-22: + Shoddd: + - bugfix: you can no longer akimbo and fire a wand forever From 5c655db2193270e0e1324316def309b25cc6ec36 Mon Sep 17 00:00:00 2001 From: Tractor Mann <69653259+Noot-Toot@users.noreply.github.com> Date: Sun, 22 Dec 2024 17:43:08 +0000 Subject: [PATCH 55/81] switcharoo (#4632) i was gonna fix cyborg emps as well, but i couldnt figure out how, if you, the fool reading this try to do so yourself, good luck!~ --- monkestation/code/modules/clothing/gloves/power_gloves.dm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/monkestation/code/modules/clothing/gloves/power_gloves.dm b/monkestation/code/modules/clothing/gloves/power_gloves.dm index 5caefddf16e9..0528ec7e1cc1 100644 --- a/monkestation/code/modules/clothing/gloves/power_gloves.dm +++ b/monkestation/code/modules/clothing/gloves/power_gloves.dm @@ -47,10 +47,10 @@ if(power >= dust_power) //Dusts if there's enough in the grid electrocute_victim.dust(TRUE, FALSE, TRUE) - log_combat(owner, target, "zapped", /obj/item/clothing/gloves/color/yellow/power_gloves, "[power] watts were used resulting in [shock_damage] damage.") + log_combat(owner, target, "zapped", /obj/item/clothing/gloves/color/yellow/power_gloves, "[power] watts were used resulting in the target dusting.") else electrocute_victim.electrocute_act(shock_damage, source, 1, SHOCK_TESLA | ((zap_flags & ZAP_MOB_STUN) ? NONE : SHOCK_NOSTUN)) - log_combat(owner, target, "zapped", /obj/item/clothing/gloves/color/yellow/power_gloves, "[power] watts were used resulting in the target dusting.") + log_combat(owner, target, "zapped", /obj/item/clothing/gloves/color/yellow/power_gloves, "[power] watts were used resulting in [shock_damage] damage.") return From ef34303440ce42d0c139bb60efc610323aea1588 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 22 Dec 2024 17:43:27 +0000 Subject: [PATCH 56/81] Automatic changelog for PR #4632 [ci skip] --- html/changelogs/AutoChangeLog-pr-4632.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-4632.yml diff --git a/html/changelogs/AutoChangeLog-pr-4632.yml b/html/changelogs/AutoChangeLog-pr-4632.yml new file mode 100644 index 000000000000..f88d93e27281 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-4632.yml @@ -0,0 +1,4 @@ +author: "Tractor Mann" +delete-after: True +changes: + - admin: "Admins will no longer be told you dusted someone with power gloves when you didnt, and that you shocked someone with power gloves when you dust them." \ No newline at end of file From c56095648d8b0d03539a3e4b12c19196e0fba2a1 Mon Sep 17 00:00:00 2001 From: dwasint <82520990+dwasint@users.noreply.github.com> Date: Sun, 22 Dec 2024 11:42:33 -0800 Subject: [PATCH 57/81] Update TGS DMAPI (#4643) Co-authored-by: tgstation-server --- code/__DEFINES/tgs.dm | 29 ++++++++++++++++++++++++++++- code/modules/tgs/v5/undefs.dm | 1 + 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/code/__DEFINES/tgs.dm b/code/__DEFINES/tgs.dm index 42f2d5fc31fe..7e1ba820dd8b 100644 --- a/code/__DEFINES/tgs.dm +++ b/code/__DEFINES/tgs.dm @@ -1,7 +1,7 @@ // tgstation-server DMAPI // The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in IETF RFC 2119. -#define TGS_DMAPI_VERSION "7.3.0" +#define TGS_DMAPI_VERSION "7.3.1" // All functions and datums outside this document are subject to change with any version and should not be relied on. @@ -58,6 +58,11 @@ #define TGS_FILE2TEXT_NATIVE file2text #endif +// SpacemanDMM compatibility +#ifndef CAN_BE_REDEFINED +#define CAN_BE_REDEFINED(X) +#endif + // EVENT CODES /// Before a reboot mode change, extras parameters are the current and new reboot mode enums. @@ -160,6 +165,7 @@ * * http_handler - Optional user defined [/datum/tgs_http_handler]. */ /world/proc/TgsNew(datum/tgs_event_handler/event_handler, minimum_required_security_level = TGS_SECURITY_ULTRASAFE, datum/tgs_http_handler/http_handler) + CAN_BE_REDEFINED(TRUE) return /** @@ -170,6 +176,7 @@ * This function should not be called before ..() in [/world/proc/New]. */ /world/proc/TgsInitializationComplete() + CAN_BE_REDEFINED(TRUE) return /// Consumers MUST run this macro at the start of [/world/proc/Topic]. @@ -177,6 +184,7 @@ /// Consumers MUST call this as late as possible in [world/proc/Reboot] (BEFORE ..()). /world/proc/TgsReboot() + CAN_BE_REDEFINED(TRUE) return // DATUM DEFINITIONS @@ -214,6 +222,7 @@ * Returns [TRUE]/[FALSE] based on if the [/datum/tgs_version] contains wildcards. */ /datum/tgs_version/proc/Wildcard() + CAN_BE_REDEFINED(TRUE) return /** @@ -222,6 +231,7 @@ * other_version - The [/datum/tgs_version] to compare against. */ /datum/tgs_version/proc/Equals(datum/tgs_version/other_version) + CAN_BE_REDEFINED(TRUE) return /// Represents a merge of a GitHub pull request. @@ -459,16 +469,19 @@ /// Returns the maximum supported [/datum/tgs_version] of the DMAPI. /world/proc/TgsMaximumApiVersion() + CAN_BE_REDEFINED(TRUE) return /// Returns the minimum supported [/datum/tgs_version] of the DMAPI. /world/proc/TgsMinimumApiVersion() + CAN_BE_REDEFINED(TRUE) return /** * Returns [TRUE] if DreamDaemon was launched under TGS, the API matches, and was properly initialized. [FALSE] will be returned otherwise. */ /world/proc/TgsAvailable() + CAN_BE_REDEFINED(TRUE) return // No function below this succeeds if it TgsAvailable() returns FALSE or if TgsNew() has yet to be called. @@ -480,6 +493,7 @@ * If TGS has not requested a [TGS_REBOOT_MODE_SHUTDOWN] DreamDaemon will be launched again. */ /world/proc/TgsEndProcess() + CAN_BE_REDEFINED(TRUE) return /** @@ -490,6 +504,7 @@ * admin_only: If [TRUE], message will be sent to admin connected chats. Vice-versa applies. */ /world/proc/TgsTargetedChatBroadcast(datum/tgs_message_content/message, admin_only = FALSE) + CAN_BE_REDEFINED(TRUE) return /** @@ -500,6 +515,7 @@ * user: The [/datum/tgs_chat_user] to PM. */ /world/proc/TgsChatPrivateMessage(datum/tgs_message_content/message, datum/tgs_chat_user/user) + CAN_BE_REDEFINED(TRUE) return /** @@ -510,42 +526,52 @@ * channels - Optional list of [/datum/tgs_chat_channel]s to restrict the message to. */ /world/proc/TgsChatBroadcast(datum/tgs_message_content/message, list/channels = null) + CAN_BE_REDEFINED(TRUE) return /// Returns the current [/datum/tgs_version] of TGS if it is running the server, null otherwise. This function may sleep if the call to [/world/proc/TgsNew] is sleeping! /world/proc/TgsVersion() + CAN_BE_REDEFINED(TRUE) return /// Returns the running engine type /world/proc/TgsEngine() + CAN_BE_REDEFINED(TRUE) return /// Returns the current [/datum/tgs_version] of the DMAPI being used if it was activated, null otherwise. This function may sleep if the call to [/world/proc/TgsNew] is sleeping! /world/proc/TgsApiVersion() + CAN_BE_REDEFINED(TRUE) return /// Returns the name of the TGS instance running the game if TGS is present, null otherwise. This function may sleep if the call to [/world/proc/TgsNew] is sleeping! /world/proc/TgsInstanceName() + CAN_BE_REDEFINED(TRUE) return /// Return the current [/datum/tgs_revision_information] of the running server if TGS is present, null otherwise. This function may sleep if the call to [/world/proc/TgsNew] is sleeping! /world/proc/TgsRevision() + CAN_BE_REDEFINED(TRUE) return /// Returns the current BYOND security level as a TGS_SECURITY_ define if TGS is present, null otherwise. This function may sleep if the call to [/world/proc/TgsNew] is sleeping! /world/proc/TgsSecurityLevel() + CAN_BE_REDEFINED(TRUE) return /// Returns the current BYOND visibility level as a TGS_VISIBILITY_ define if TGS is present, null otherwise. Requires TGS to be using interop API version 5 or higher otherwise the string "___unimplemented" wil be returned. This function may sleep if the call to [/world/proc/TgsNew] is sleeping! /world/proc/TgsVisibility() + CAN_BE_REDEFINED(TRUE) return /// Returns a list of active [/datum/tgs_revision_information/test_merge]s if TGS is present, null otherwise. This function may sleep if the call to [/world/proc/TgsNew] is sleeping! /world/proc/TgsTestMerges() + CAN_BE_REDEFINED(TRUE) return /// Returns a list of connected [/datum/tgs_chat_channel]s if TGS is present, null otherwise. This function may sleep if the call to [/world/proc/TgsNew] is sleeping! /world/proc/TgsChatChannelInfo() + CAN_BE_REDEFINED(TRUE) return /** @@ -556,6 +582,7 @@ * wait_for_completion - If set, this function will not return until the event has run to completion. */ /world/proc/TgsTriggerEvent(event_name, list/parameters, wait_for_completion = FALSE) + CAN_BE_REDEFINED(TRUE) return /* diff --git a/code/modules/tgs/v5/undefs.dm b/code/modules/tgs/v5/undefs.dm index acd19dfa6411..ca49e46cdffa 100644 --- a/code/modules/tgs/v5/undefs.dm +++ b/code/modules/tgs/v5/undefs.dm @@ -18,6 +18,7 @@ #undef DMAPI5_PARAMETER_ACCESS_IDENTIFIER #undef DMAPI5_PARAMETER_CUSTOM_COMMANDS +#undef DMAPI5_PARAMETER_TOPIC_PORT #undef DMAPI5_CHUNK #undef DMAPI5_CHUNK_PAYLOAD From 39b4f1887ec8417107332c02bc37b83218002db1 Mon Sep 17 00:00:00 2001 From: Lucy Date: Sun, 22 Dec 2024 14:42:51 -0500 Subject: [PATCH 58/81] Prevent setting the next map from conflicting across LRP/MRP/HRP (#4638) * Prevent setting the next map from conflicting across LRP/MRP/HRP * fix typo --- code/__DEFINES/maps.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/__DEFINES/maps.dm b/code/__DEFINES/maps.dm index d59e0477c798..1bccfebfc558 100644 --- a/code/__DEFINES/maps.dm +++ b/code/__DEFINES/maps.dm @@ -61,7 +61,7 @@ Always compile, always use that verb, and always make sure that it works for wha #define MAP_MAXZ 6 /// Path for the next_map.json file, if someone, for some messed up reason, wants to change it. -#define PATH_TO_NEXT_MAP_JSON "data/next_map.json" +#define PATH_TO_NEXT_MAP_JSON (world.GetConfig("env", "AUXTOOLS_DEBUG_DLL") ? "data/next_map.json" : "data/next_map.[world.port].json") // monkestation edit: messed up cat here, i changed it (added world.port to it if there's no debugger attached) /// List of directories we can load map .json files from #define MAP_DIRECTORY_MAPS "_maps" From 6b05c0989e98ad2ca6ec7bce6102522cc7ecdfab Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 22 Dec 2024 19:43:09 +0000 Subject: [PATCH 59/81] Automatic changelog for PR #4638 [ci skip] --- html/changelogs/AutoChangeLog-pr-4638.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-4638.yml diff --git a/html/changelogs/AutoChangeLog-pr-4638.yml b/html/changelogs/AutoChangeLog-pr-4638.yml new file mode 100644 index 000000000000..a90c6aed296c --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-4638.yml @@ -0,0 +1,4 @@ +author: "Absolucy" +delete-after: True +changes: + - bugfix: "The map selected for the next round should actually always be the map that loads next round." \ No newline at end of file From 7e019ae7476201ae67e6c1f5c7184987626c9df6 Mon Sep 17 00:00:00 2001 From: Lucy Date: Sun, 22 Dec 2024 14:43:24 -0500 Subject: [PATCH 60/81] Properly marks type and confidentiality of a few admin/mentor-related notifications (#4635) --- code/modules/client/client_procs.dm | 7 +++---- monkestation/code/modules/mentor/mentor_follow.dm | 6 +++--- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/code/modules/client/client_procs.dm b/code/modules/client/client_procs.dm index dd5c2b429c12..be80860d23e1 100644 --- a/code/modules/client/client_procs.dm +++ b/code/modules/client/client_procs.dm @@ -460,7 +460,7 @@ GLOBAL_LIST_INIT(blacklisted_builds, list( add_admin_verbs() var/memo_message = get_message_output("memo") if(memo_message) - to_chat(src, memo_message) + to_chat(src, memo_message, type = MESSAGE_TYPE_ADMINLOG, confidential = TRUE) adminGreet() if (mob && reconnecting) var/stealth_admin = mob.client?.holder?.fakekey @@ -479,7 +479,7 @@ GLOBAL_LIST_INIT(blacklisted_builds, list( var/time_stamp = query_last_connected.item[1] var/unread_notes = get_message_output("note", ckey, FALSE, time_stamp) if(unread_notes) - to_chat(src, unread_notes) + to_chat(src, unread_notes, type = MESSAGE_TYPE_ADMINPM, confidential = TRUE) qdel(query_last_connected) var/cached_player_age = set_client_age_from_db(tdata) //we have to cache this because other shit may change it and we need it's current value now down below. @@ -517,7 +517,6 @@ GLOBAL_LIST_INIT(blacklisted_builds, list( message_admins("[key_name_admin(src)] (IP: [address], ID: [computer_id]) is a new BYOND account [account_age] day[(account_age == 1?"":"s")] old, created on [account_join_date].") if (CONFIG_GET(flag/irc_first_connection_alert)) send2tgs_adminless_only("new_byond_user", "[key_name(src)] (IP: [address], ID: [computer_id]) is a new BYOND account [account_age] day[(account_age == 1?"":"s")] old, created on [account_join_date].") - get_message_output("watchlist entry", ckey) if(check_overwatch() && CONFIG_GET(flag/vpn_kick)) return validate_key_in_db() @@ -546,7 +545,7 @@ GLOBAL_LIST_INIT(blacklisted_builds, list( convert_notes_sql(ckey) var/user_messages = get_message_output("message", ckey) if(user_messages) - to_chat(src, user_messages) + to_chat(src, user_messages, type = MESSAGE_TYPE_ADMINPM, confidential = TRUE) if(!winexists(src, "asset_cache_browser")) // The client is using a custom skin, tell them. to_chat(src, span_warning("Unable to access asset cache browser, if you are using a custom skin file, please allow DS to download the updated version, if you are not, then make a bug report. This is not a critical issue but can cause issues with resource downloading, as it is impossible to know when extra resources arrived to you.")) diff --git a/monkestation/code/modules/mentor/mentor_follow.dm b/monkestation/code/modules/mentor/mentor_follow.dm index 09f8e7a058de..7a8e6ed8961c 100644 --- a/monkestation/code/modules/mentor/mentor_follow.dm +++ b/monkestation/code/modules/mentor/mentor_follow.dm @@ -8,8 +8,8 @@ mentor_datum.following = followed_guy usr.reset_perspective(followed_guy) add_verb(src, /client/proc/mentor_unfollow) - to_chat(GLOB.admins, span_adminooc("MENTOR: [key_name(usr)] is now following [key_name(followed_guy)]")) - to_chat(usr, span_info("Click the \"Stop Following\" button in the Mentor tab to stop following [key_name(followed_guy)].")) + to_chat(GLOB.admins, span_adminooc("MENTOR: [key_name(usr)] is now following [key_name(followed_guy)]"), type = MESSAGE_TYPE_ADMINLOG, confidential = TRUE) + to_chat(src, span_info("Click the \"Stop Following\" button in the Mentor tab to stop following [key_name(followed_guy)]."), type = MESSAGE_TYPE_ADMINLOG, confidential = TRUE) log_mentor("[key_name(usr)] began following [key_name(followed_guy)]") /client/proc/mentor_unfollow() @@ -19,6 +19,6 @@ remove_verb(src, /client/proc/mentor_unfollow) usr.reset_perspective() - to_chat(GLOB.admins, span_adminooc("MENTOR: [key_name(usr)] is no longer following [key_name(mentor_datum.following)]")) + to_chat(GLOB.admins, span_adminooc("MENTOR: [key_name(usr)] is no longer following [key_name(mentor_datum.following)]"), type = MESSAGE_TYPE_ADMINLOG, confidential = TRUE) log_mentor("[key_name(usr)] stopped following [key_name(mentor_datum.following)]") mentor_datum.following = null From f548b9fca6657c79b318253b1f723f9166810203 Mon Sep 17 00:00:00 2001 From: Lucy Date: Sun, 22 Dec 2024 14:43:31 -0500 Subject: [PATCH 61/81] Adds tinyfans to arrivals on Blueshift (#4633) --- _maps/map_files/Blueshift/Blueshift.dmm | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/_maps/map_files/Blueshift/Blueshift.dmm b/_maps/map_files/Blueshift/Blueshift.dmm index 250dae6db367..96658451b2c6 100644 --- a/_maps/map_files/Blueshift/Blueshift.dmm +++ b/_maps/map_files/Blueshift/Blueshift.dmm @@ -4701,6 +4701,10 @@ /obj/effect/turf_decal/tile/blue/fourcorners, /turf/open/floor/iron/white, /area/station/medical/treatment_center) +"aWw" = ( +/obj/structure/fans/tiny, +/turf/open/floor/plating, +/area/station/hallway/secondary/entry) "aWA" = ( /obj/structure/cable, /obj/effect/landmark/start/hangover, @@ -55519,6 +55523,7 @@ /obj/effect/mapping_helpers/airlock/cyclelink_helper{ dir = 8 }, +/obj/structure/fans/tiny, /turf/open/floor/plating, /area/station/hallway/secondary/entry) "kKp" = ( @@ -170231,7 +170236,7 @@ ahn cXo cXo rMe -ivx +aWw rMe gLc gLc From 1959d3a08fab51d3c20692dc3209db15296b38a5 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 22 Dec 2024 19:43:43 +0000 Subject: [PATCH 62/81] Automatic changelog for PR #4635 [ci skip] --- html/changelogs/AutoChangeLog-pr-4635.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-4635.yml diff --git a/html/changelogs/AutoChangeLog-pr-4635.yml b/html/changelogs/AutoChangeLog-pr-4635.yml new file mode 100644 index 000000000000..07b5b61ef5ce --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-4635.yml @@ -0,0 +1,4 @@ +author: "Absolucy" +delete-after: True +changes: + - bugfix: "Properly marked the message type and confidentiality of a few admin/mentor-related notifications." \ No newline at end of file From e07d7aab76caae6d4bb5b3673b3a89b9ab90b1d2 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 22 Dec 2024 19:43:49 +0000 Subject: [PATCH 63/81] Automatic changelog for PR #4633 [ci skip] --- html/changelogs/AutoChangeLog-pr-4633.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-4633.yml diff --git a/html/changelogs/AutoChangeLog-pr-4633.yml b/html/changelogs/AutoChangeLog-pr-4633.yml new file mode 100644 index 000000000000..172b28ab6c19 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-4633.yml @@ -0,0 +1,4 @@ +author: "Absolucy" +delete-after: True +changes: + - rscadd: "Added tinyfans to the arrivals shuttle and public mining shuttle doors on Blueshift." \ No newline at end of file From 24684a330cec34bcef9623ed470ebcc6eb983560 Mon Sep 17 00:00:00 2001 From: Lucy Date: Sun, 22 Dec 2024 14:45:41 -0500 Subject: [PATCH 64/81] [PORT] Adds unit test for effects set to "Curse of Mundanity" (and missing IDs) (#4580) Ports https://github.com/tgstation/tgstation/pull/88240 and partially https://github.com/tgstation/tgstation/pull/87842 --- code/__DEFINES/status_effects.dm | 10 +++ code/datums/elements/organ_set_bonus.dm | 4 +- code/datums/status_effects/_status_effect.dm | 2 +- .../datums/status_effects/agent_pinpointer.dm | 2 +- code/datums/status_effects/buffs.dm | 15 ++--- .../status_effects/buffs/stun_asorption.dm | 2 +- .../status_effects/debuffs/blindness.dm | 4 +- code/datums/status_effects/debuffs/debuffs.dm | 30 ++++----- .../debuffs/dna_transformation.dm | 4 +- code/datums/status_effects/debuffs/drunk.dm | 1 + .../status_effects/debuffs/fire_stacks.dm | 3 +- .../status_effects/debuffs/genetic_damage.dm | 2 +- .../status_effects/debuffs/hallucination.dm | 2 +- .../status_effects/debuffs/speech_debuffs.dm | 2 +- .../status_effects/debuffs/tower_of_babel.dm | 2 +- code/datums/status_effects/drug_effects.dm | 6 +- code/datums/status_effects/gas.dm | 2 +- code/datums/status_effects/grouped_effect.dm | 2 + code/datums/status_effects/limited_effect.dm | 3 +- code/datums/status_effects/neutral.dm | 25 ++++---- code/datums/status_effects/stacking_effect.dm | 4 +- code/datums/status_effects/wound_effects.dm | 5 +- .../heretic/magic/ash_ascension.dm | 2 +- .../antagonists/heretic/magic/shadow_cloak.dm | 2 +- .../antagonists/heretic/magic/star_touch.dm | 2 +- .../heretic/status_effects/buffs.dm | 4 +- .../heretic/status_effects/debuffs.dm | 6 +- .../heretic/status_effects/ghoul.dm | 2 +- .../equipment/monster_organs/brimdust_sac.dm | 2 +- .../lavaland/basilisk/basilisk_overheat.dm | 1 + .../space_fauna/revenant/revenant_effects.dm | 2 + code/modules/mob/living/status_procs.dm | 2 +- code/modules/religion/burdened/psyker.dm | 2 +- .../religion/hunt/hunter_pinpointer.dm | 2 +- .../crossbreeding/_status_effects.dm | 16 ++--- code/modules/unit_tests/_unit_tests.dm | 1 + .../unit_tests/status_effect_validity.dm | 61 +++++++++++++++++++ .../code/datums/status_effects/buffs.dm | 2 +- .../code/datums/status_effects/changeling.dm | 6 +- .../code/datums/status_effects/food_buffs.dm | 2 +- .../code/modules/a_medical_day/lungless.dm | 4 +- .../antagonists/borers/code/status_effects.dm | 2 +- .../antagonists/clock_cult/status_effects.dm | 2 +- .../events/wonderland_apocalypse.dm | 2 +- .../monster_hunters/tools/bnuuy_mask.dm | 2 +- .../weapons/hunter_revolver.dm | 2 +- .../artifact_effects/false_rod.dm | 2 +- .../bloodsucker/bloodsucker_frenzy.dm | 2 +- .../bloodsucker/bloodsucker_sol.dm | 2 +- .../modules/bloodsuckers/powers/masquerade.dm | 4 +- .../bloodsuckers/vassals/vassal_pinpointer.dm | 2 +- .../modules/blueshift/species/ashwalker.dm | 4 +- .../pain/status_effects/low_blood_pressure.dm | 2 +- .../modules/datums/status_effects/debuffs.dm | 3 + .../modules/ghost_players/centcom_grace.dm | 2 +- .../modules/liquids/liquid_status_effect.dm | 5 +- .../ranching/chickens/tier1/chicken.dm | 2 + .../crossbreeding/regenerative/cooldown.dm | 2 +- 58 files changed, 193 insertions(+), 102 deletions(-) create mode 100644 code/modules/unit_tests/status_effect_validity.dm diff --git a/code/__DEFINES/status_effects.dm b/code/__DEFINES/status_effects.dm index c9d51b852c76..77b3092cfc68 100644 --- a/code/__DEFINES/status_effects.dm +++ b/code/__DEFINES/status_effects.dm @@ -7,6 +7,16 @@ /// if it only allows one, and new instances just instead refresh the timer #define STATUS_EFFECT_REFRESH 3 +/// Use in status effect "duration" to make it last forever +#define STATUS_EFFECT_PERMANENT -1 +/// Use in status effect "tick_interval" to prevent it from calling tick() +#define STATUS_EFFECT_NO_TICK -1 + +/// Indicates this status effect is an abstract type, ie not instantiated +/// Doesn't actually do anything in practice, primarily just a marker / used in unit tests, +/// so don't worry if your abstract status effect doesn't actually set this +#define STATUS_EFFECT_ID_ABSTRACT "abstract" + ///Processing flags - used to define the speed at which the status will work ///This is fast - 0.2s between ticks (I believe!) #define STATUS_EFFECT_FAST_PROCESS 0 diff --git a/code/datums/elements/organ_set_bonus.dm b/code/datums/elements/organ_set_bonus.dm index aeb63356fb48..2859f7b802c5 100644 --- a/code/datums/elements/organ_set_bonus.dm +++ b/code/datums/elements/organ_set_bonus.dm @@ -42,8 +42,8 @@ /datum/status_effect/organ_set_bonus id = "organ_set_bonus" - duration = -1 - tick_interval = -1 + duration = STATUS_EFFECT_PERMANENT + tick_interval = STATUS_EFFECT_NO_TICK alert_type = null ///how many organs the carbon with this has in the set var/organs = 0 diff --git a/code/datums/status_effects/_status_effect.dm b/code/datums/status_effects/_status_effect.dm index 49ba273c24db..b95504702c28 100644 --- a/code/datums/status_effects/_status_effect.dm +++ b/code/datums/status_effects/_status_effect.dm @@ -6,7 +6,7 @@ /// When set initially / in on_creation, this is how long the status effect lasts in deciseconds. /// While processing, this becomes the world.time when the status effect will expire. /// -1 = infinite duration. - var/duration = -1 + var/duration = STATUS_EFFECT_PERMANENT /// When set initially / in on_creation, this is how long between [proc/tick] calls in deciseconds. /// While processing, this becomes the world.time when the next tick will occur. /// -1 = will stop processing, if duration is also unlimited (-1). diff --git a/code/datums/status_effects/agent_pinpointer.dm b/code/datums/status_effects/agent_pinpointer.dm index 3f64ff252a02..7afb85805f05 100644 --- a/code/datums/status_effects/agent_pinpointer.dm +++ b/code/datums/status_effects/agent_pinpointer.dm @@ -10,7 +10,7 @@ /datum/status_effect/agent_pinpointer id = "agent_pinpointer" - duration = -1 + duration = STATUS_EFFECT_PERMANENT tick_interval = PINPOINTER_PING_TIME alert_type = /atom/movable/screen/alert/status_effect/agent_pinpointer ///The minimum range to start pointing towards your target. diff --git a/code/datums/status_effects/buffs.dm b/code/datums/status_effects/buffs.dm index e4edd4997c62..a2352c34b15d 100644 --- a/code/datums/status_effects/buffs.dm +++ b/code/datums/status_effects/buffs.dm @@ -2,7 +2,7 @@ /datum/status_effect/his_grace id = "his_grace" - duration = -1 + duration = STATUS_EFFECT_PERMANENT tick_interval = 4 alert_type = /atom/movable/screen/alert/status_effect/his_grace var/bloodlust = 0 @@ -86,7 +86,7 @@ /datum/status_effect/cult_master id = "The Cult Master" - duration = -1 + duration = STATUS_EFFECT_PERMANENT alert_type = null on_remove_on_mob_delete = TRUE var/alive = TRUE @@ -116,7 +116,7 @@ /datum/status_effect/blooddrunk id = "blooddrunk" duration = 10 - tick_interval = -1 // monkestation edit + tick_interval = STATUS_EFFECT_NO_TICK // monkestation edit alert_type = /atom/movable/screen/alert/status_effect/blooddrunk /atom/movable/screen/alert/status_effect/blooddrunk @@ -211,7 +211,7 @@ /datum/status_effect/hippocratic_oath id = "Hippocratic Oath" status_type = STATUS_EFFECT_UNIQUE - duration = -1 + duration = STATUS_EFFECT_PERMANENT tick_interval = 25 alert_type = null @@ -423,6 +423,7 @@ duration = 2 SECONDS status_type = STATUS_EFFECT_REPLACE show_duration = TRUE + alert_type = null /datum/status_effect/speed_boost/on_creation(mob/living/new_owner, set_duration) if(isnum(set_duration)) @@ -475,7 +476,7 @@ /datum/status_effect/nest_sustenance id = "nest_sustenance" - duration = -1 + duration = STATUS_EFFECT_PERMANENT tick_interval = 0.4 SECONDS alert_type = /atom/movable/screen/alert/status_effect/nest_sustenance @@ -504,8 +505,8 @@ */ /datum/status_effect/blessing_of_insanity id = "blessing_of_insanity" - duration = -1 - tick_interval = -1 + duration = STATUS_EFFECT_PERMANENT + tick_interval = STATUS_EFFECT_NO_TICK alert_type = /atom/movable/screen/alert/status_effect/blessing_of_insanity /atom/movable/screen/alert/status_effect/blessing_of_insanity diff --git a/code/datums/status_effects/buffs/stun_asorption.dm b/code/datums/status_effects/buffs/stun_asorption.dm index d68f2f7408cc..f6212bc88421 100644 --- a/code/datums/status_effects/buffs/stun_asorption.dm +++ b/code/datums/status_effects/buffs/stun_asorption.dm @@ -9,7 +9,7 @@ */ /datum/status_effect/stun_absorption id = "absorb_stun" - tick_interval = -1 + tick_interval = STATUS_EFFECT_NO_TICK alert_type = null status_type = STATUS_EFFECT_MULTIPLE diff --git a/code/datums/status_effects/debuffs/blindness.dm b/code/datums/status_effects/debuffs/blindness.dm index 0bfaaee7485b..310b995090c8 100644 --- a/code/datums/status_effects/debuffs/blindness.dm +++ b/code/datums/status_effects/debuffs/blindness.dm @@ -5,7 +5,7 @@ /// Nearsighted /datum/status_effect/grouped/nearsighted id = "nearsighted" - tick_interval = -1 + tick_interval = STATUS_EFFECT_NO_TICK alert_type = null // This is not "remove on fullheal" as in practice, // fullheal should instead remove all the sources and in turn cure this @@ -55,7 +55,7 @@ /// Blindness /datum/status_effect/grouped/blindness id = "blindness" - tick_interval = -1 + tick_interval = STATUS_EFFECT_NO_TICK alert_type = /atom/movable/screen/alert/status_effect/blind // This is not "remove on fullheal" as in practice, // fullheal should instead remove all the sources and in turn cure this diff --git a/code/datums/status_effects/debuffs/debuffs.dm b/code/datums/status_effects/debuffs/debuffs.dm index 83572e56630c..3e6491813387 100644 --- a/code/datums/status_effects/debuffs/debuffs.dm +++ b/code/datums/status_effects/debuffs/debuffs.dm @@ -1,7 +1,8 @@ //Largely negative status effects go here, even if they have small benificial effects //STUN EFFECTS /datum/status_effect/incapacitating - tick_interval = -1 // monkestation edit + id = STATUS_EFFECT_ID_ABSTRACT + tick_interval = STATUS_EFFECT_NO_TICK // monkestation edit status_type = STATUS_EFFECT_REPLACE alert_type = null remove_on_fullheal = TRUE @@ -134,7 +135,7 @@ if(!.) return if(HAS_TRAIT(owner, TRAIT_SLEEPIMMUNE)) - tick_interval = -1 + tick_interval = STATUS_EFFECT_NO_TICK else ADD_TRAIT(owner, TRAIT_KNOCKEDOUT, TRAIT_STATUS_EFFECT(id)) RegisterSignal(owner, SIGNAL_ADDTRAIT(TRAIT_SLEEPIMMUNE), PROC_REF(on_owner_insomniac)) @@ -156,7 +157,7 @@ /datum/status_effect/incapacitating/sleeping/proc/on_owner_insomniac(mob/living/source) SIGNAL_HANDLER REMOVE_TRAIT(owner, TRAIT_KNOCKEDOUT, TRAIT_STATUS_EFFECT(id)) - tick_interval = -1 + tick_interval = STATUS_EFFECT_NO_TICK ///If the mob has the TRAIT_SLEEPIMMUNE but somehow looses it we make him sleep and restart the tick() /datum/status_effect/incapacitating/sleeping/proc/on_owner_sleepy(mob/living/source) @@ -237,7 +238,7 @@ //STASIS /datum/status_effect/grouped/stasis id = "stasis" - duration = -1 + duration = STATUS_EFFECT_PERMANENT alert_type = /atom/movable/screen/alert/status_effect/stasis var/last_dead_time @@ -289,7 +290,7 @@ /datum/status_effect/his_wrath //does minor damage over time unless holding His Grace id = "his_wrath" - duration = -1 + duration = STATUS_EFFECT_PERMANENT tick_interval = 4 alert_type = /atom/movable/screen/alert/status_effect/his_wrath @@ -309,7 +310,7 @@ /datum/status_effect/cultghost //is a cult ghost and can't use manifest runes id = "cult_ghost" - duration = -1 + duration = STATUS_EFFECT_PERMANENT alert_type = null /datum/status_effect/cultghost/on_apply() @@ -386,7 +387,7 @@ id = "neck_slice" status_type = STATUS_EFFECT_UNIQUE alert_type = null - duration = -1 + duration = STATUS_EFFECT_PERMANENT /datum/status_effect/neck_slice/on_apply() if(!ishuman(owner)) @@ -511,7 +512,7 @@ /datum/status_effect/gonbola_pacify id = "gonbolaPacify" status_type = STATUS_EFFECT_MULTIPLE - tick_interval = -1 + tick_interval = STATUS_EFFECT_NO_TICK alert_type = null /datum/status_effect/gonbola_pacify/on_apply() @@ -693,9 +694,9 @@ /datum/status_effect/go_away id = "go_away" - duration = 100 + duration = 10 SECONDS status_type = STATUS_EFFECT_REPLACE - tick_interval = 1 + tick_interval = 0.2 SECONDS alert_type = /atom/movable/screen/alert/status_effect/go_away var/direction @@ -716,11 +717,11 @@ /datum/status_effect/fake_virus id = "fake_virus" - duration = 1800//3 minutes + duration = 3 MINUTES //3 minutes status_type = STATUS_EFFECT_REPLACE - tick_interval = 1 + tick_interval = 0.2 SECONDS alert_type = null - var/msg_stage = 0//so you dont get the most intense messages immediately + var/msg_stage = 0//so you don't get the most intense messages immediately /datum/status_effect/fake_virus/on_apply() if(HAS_TRAIT(owner, TRAIT_VIRUSIMMUNE)) @@ -937,7 +938,8 @@ id = "teleport_madness" duration = 10 SECONDS status_type = STATUS_EFFECT_REPLACE - tick_interval = 0.1 SECONDS + tick_interval = 0.2 SECONDS + alert_type = null /datum/status_effect/teleport_madness/tick() dump_in_space(owner) diff --git a/code/datums/status_effects/debuffs/dna_transformation.dm b/code/datums/status_effects/debuffs/dna_transformation.dm index 1ffcc2f5929d..f38c88c3f2bb 100644 --- a/code/datums/status_effects/debuffs/dna_transformation.dm +++ b/code/datums/status_effects/debuffs/dna_transformation.dm @@ -2,7 +2,7 @@ /// then turns them back to how they were before transformation. /datum/status_effect/temporary_transformation id = "temp_dna_transformation" - tick_interval = -1 + tick_interval = STATUS_EFFECT_NO_TICK duration = 1 MINUTES // set in on creation, this just needs to be any value to process alert_type = null remove_on_fullheal = TRUE @@ -85,7 +85,7 @@ return // Already paused time_before_pause = duration - world.time - duration = -1 + duration = STATUS_EFFECT_PERMANENT // Resume if we're none of the above and also were paused else if(time_before_pause != -1) diff --git a/code/datums/status_effects/debuffs/drunk.dm b/code/datums/status_effects/debuffs/drunk.dm index 026577fdc972..4ccc273b0b2b 100644 --- a/code/datums/status_effects/debuffs/drunk.dm +++ b/code/datums/status_effects/debuffs/drunk.dm @@ -15,6 +15,7 @@ tick_interval = 2 SECONDS status_type = STATUS_EFFECT_REPLACE remove_on_fullheal = TRUE + alert_type = null /// The level of drunkness we are currently at. var/drunk_value = 0 diff --git a/code/datums/status_effects/debuffs/fire_stacks.dm b/code/datums/status_effects/debuffs/fire_stacks.dm index d00d0c348439..81d81deee4af 100644 --- a/code/datums/status_effects/debuffs/fire_stacks.dm +++ b/code/datums/status_effects/debuffs/fire_stacks.dm @@ -1,5 +1,6 @@ /datum/status_effect/fire_handler - duration = -1 + duration = STATUS_EFFECT_PERMANENT + id = STATUS_EFFECT_ID_ABSTRACT alert_type = null status_type = STATUS_EFFECT_REFRESH //Custom code on_remove_on_mob_delete = TRUE diff --git a/code/datums/status_effects/debuffs/genetic_damage.dm b/code/datums/status_effects/debuffs/genetic_damage.dm index 438bcc7c6905..12512efd06af 100644 --- a/code/datums/status_effects/debuffs/genetic_damage.dm +++ b/code/datums/status_effects/debuffs/genetic_damage.dm @@ -5,7 +5,7 @@ id = "genetic_damage" alert_type = null status_type = STATUS_EFFECT_REFRESH // New effects will add to total_damage - duration = -1 + duration = STATUS_EFFECT_PERMANENT tick_interval = 2 SECONDS on_remove_on_mob_delete = TRUE // Need to unregister from owner, be_replaced() would cause runtimes remove_on_fullheal = TRUE diff --git a/code/datums/status_effects/debuffs/hallucination.dm b/code/datums/status_effects/debuffs/hallucination.dm index 4c5e1c305e1b..942ab9deb0ed 100644 --- a/code/datums/status_effects/debuffs/hallucination.dm +++ b/code/datums/status_effects/debuffs/hallucination.dm @@ -82,7 +82,7 @@ /datum/status_effect/hallucination/sanity id = "low sanity" status_type = STATUS_EFFECT_REFRESH - duration = -1 // This lasts "forever", only goes away with sanity gain + duration = STATUS_EFFECT_PERMANENT // This lasts "forever", only goes away with sanity gain /datum/status_effect/hallucination/sanity/on_apply() if(!owner.mob_mood) diff --git a/code/datums/status_effects/debuffs/speech_debuffs.dm b/code/datums/status_effects/debuffs/speech_debuffs.dm index 2b095bf6047f..607f78c64af2 100644 --- a/code/datums/status_effects/debuffs/speech_debuffs.dm +++ b/code/datums/status_effects/debuffs/speech_debuffs.dm @@ -1,5 +1,5 @@ /datum/status_effect/speech - id = null + id = STATUS_EFFECT_ID_ABSTRACT alert_type = null remove_on_fullheal = TRUE diff --git a/code/datums/status_effects/debuffs/tower_of_babel.dm b/code/datums/status_effects/debuffs/tower_of_babel.dm index 1ba46d0b87b5..923938185d77 100644 --- a/code/datums/status_effects/debuffs/tower_of_babel.dm +++ b/code/datums/status_effects/debuffs/tower_of_babel.dm @@ -33,7 +33,7 @@ // Used by wizard magic and tower of babel event /datum/status_effect/tower_of_babel/magical id = "tower_of_babel_magic" // do we need a new id? - duration = -1 + duration = STATUS_EFFECT_PERMANENT trait_source = TRAUMA_TRAIT /datum/status_effect/tower_of_babel/magical/on_apply() diff --git a/code/datums/status_effects/drug_effects.dm b/code/datums/status_effects/drug_effects.dm index d01a92743b58..949c00d2edff 100644 --- a/code/datums/status_effects/drug_effects.dm +++ b/code/datums/status_effects/drug_effects.dm @@ -1,6 +1,6 @@ /datum/status_effect/woozy id = "woozy" - tick_interval = -1 + tick_interval = STATUS_EFFECT_NO_TICK status_type = STATUS_EFFECT_UNIQUE alert_type = /atom/movable/screen/alert/status_effect/woozy @@ -14,7 +14,7 @@ /datum/status_effect/high_blood_pressure id = "high_blood_pressure" - tick_interval = -1 + tick_interval = STATUS_EFFECT_NO_TICK status_type = STATUS_EFFECT_UNIQUE alert_type = /atom/movable/screen/alert/status_effect/high_blood_pressure @@ -40,7 +40,7 @@ /datum/status_effect/seizure id = "seizure" - tick_interval = -1 + tick_interval = STATUS_EFFECT_NO_TICK status_type = STATUS_EFFECT_UNIQUE alert_type = /atom/movable/screen/alert/status_effect/seizure diff --git a/code/datums/status_effects/gas.dm b/code/datums/status_effects/gas.dm index bf0822d879f8..f7b8cf2b375b 100644 --- a/code/datums/status_effects/gas.dm +++ b/code/datums/status_effects/gas.dm @@ -57,7 +57,7 @@ /datum/status_effect/freon/lasting id = "lasting_frozen" - duration = -1 + duration = STATUS_EFFECT_PERMANENT /datum/status_effect/hypernob_protection id = "hypernob_protection" diff --git a/code/datums/status_effects/grouped_effect.dm b/code/datums/status_effects/grouped_effect.dm index ade0a187e0db..403f1c740913 100644 --- a/code/datums/status_effects/grouped_effect.dm +++ b/code/datums/status_effects/grouped_effect.dm @@ -1,5 +1,7 @@ /// Status effect from multiple sources, when all sources are removed, so is the effect /datum/status_effect/grouped + id = STATUS_EFFECT_ID_ABSTRACT + alert_type = null // Grouped effects adds itself to [var/sources] and destroys itself if one exists already, there are never actually multiple status_type = STATUS_EFFECT_MULTIPLE /// A list of all sources applying this status effect. Sources are a list of keys diff --git a/code/datums/status_effects/limited_effect.dm b/code/datums/status_effects/limited_effect.dm index 0f56e72da52f..047a7a5ae07c 100644 --- a/code/datums/status_effects/limited_effect.dm +++ b/code/datums/status_effects/limited_effect.dm @@ -1,8 +1,9 @@ /// These effects reapply their on_apply() effect when refreshed while stacks < max_stacks. /datum/status_effect/limited_buff id = "limited_buff" - duration = -1 + duration = STATUS_EFFECT_PERMANENT status_type = STATUS_EFFECT_REFRESH + alert_type = null ///How many stacks we currently have var/stacks = 1 ///How many stacks we can have maximum diff --git a/code/datums/status_effects/neutral.dm b/code/datums/status_effects/neutral.dm index a92823293182..062108241f86 100644 --- a/code/datums/status_effects/neutral.dm +++ b/code/datums/status_effects/neutral.dm @@ -2,8 +2,8 @@ /datum/status_effect/crusher_damage //tracks the damage dealt to this mob by kinetic crushers id = "crusher_damage" - duration = -1 - tick_interval = -1 + duration = STATUS_EFFECT_PERMANENT + tick_interval = STATUS_EFFECT_NO_TICK status_type = STATUS_EFFECT_UNIQUE alert_type = null var/total_damage = 0 @@ -46,7 +46,7 @@ /datum/status_effect/in_love id = "in_love" - duration = -1 + duration = STATUS_EFFECT_PERMANENT status_type = STATUS_EFFECT_UNIQUE alert_type = /atom/movable/screen/alert/status_effect/in_love var/hearts @@ -84,6 +84,7 @@ /datum/status_effect/bounty id = "bounty" status_type = STATUS_EFFECT_UNIQUE + alert_type = null var/mob/living/rewarded /datum/status_effect/bounty/on_creation(mob/living/new_owner, mob/living/caster) @@ -118,8 +119,8 @@ // heldup is for the person being aimed at /datum/status_effect/grouped/heldup id = "heldup" - duration = -1 - tick_interval = -1 + duration = STATUS_EFFECT_PERMANENT + tick_interval = STATUS_EFFECT_NO_TICK status_type = STATUS_EFFECT_MULTIPLE alert_type = /atom/movable/screen/alert/status_effect/heldup @@ -139,8 +140,8 @@ // holdup is for the person aiming /datum/status_effect/holdup id = "holdup" - duration = -1 - tick_interval = -1 + duration = STATUS_EFFECT_PERMANENT + tick_interval = STATUS_EFFECT_NO_TICK status_type = STATUS_EFFECT_UNIQUE alert_type = /atom/movable/screen/alert/status_effect/holdup @@ -152,8 +153,8 @@ // this status effect is used to negotiate the high-fiving capabilities of all concerned parties /datum/status_effect/offering id = "offering" - duration = -1 - tick_interval = -1 + duration = STATUS_EFFECT_PERMANENT + tick_interval = STATUS_EFFECT_NO_TICK status_type = STATUS_EFFECT_UNIQUE alert_type = null /// The people who were offered this item at the start @@ -315,8 +316,8 @@ //this effect gives the user an alert they can use to surrender quickly /datum/status_effect/grouped/surrender id = "surrender" - duration = -1 - tick_interval = -1 + duration = STATUS_EFFECT_PERMANENT + tick_interval = STATUS_EFFECT_NO_TICK status_type = STATUS_EFFECT_UNIQUE alert_type = /atom/movable/screen/alert/status_effect/surrender @@ -344,7 +345,7 @@ /datum/status_effect/caltropped id = "caltropped" duration = 1 SECONDS - tick_interval = -1 // monkestation edit + tick_interval = STATUS_EFFECT_NO_TICK // monkestation edit status_type = STATUS_EFFECT_REFRESH alert_type = null diff --git a/code/datums/status_effects/stacking_effect.dm b/code/datums/status_effects/stacking_effect.dm index 783d9334b215..5cc598f8710c 100644 --- a/code/datums/status_effects/stacking_effect.dm +++ b/code/datums/status_effects/stacking_effect.dm @@ -1,8 +1,8 @@ /// Status effects that can stack. /datum/status_effect/stacking - id = "stacking_base" - duration = -1 // Only removed under specific conditions. + id = STATUS_EFFECT_ID_ABSTRACT + duration = STATUS_EFFECT_PERMANENT // Only removed under specific conditions. tick_interval = 1 SECONDS // Deciseconds between decays, once decay starts alert_type = null /// How many stacks are currently accumulated. diff --git a/code/datums/status_effects/wound_effects.dm b/code/datums/status_effects/wound_effects.dm index e1929bbdc26b..42843ffbbd46 100644 --- a/code/datums/status_effects/wound_effects.dm +++ b/code/datums/status_effects/wound_effects.dm @@ -72,7 +72,7 @@ id = "determination_crash" alert_type = null remove_on_fullheal = TRUE - tick_interval = -1 + tick_interval = STATUS_EFFECT_NO_TICK duration = 10 SECONDS /datum/status_effect/determination_crash/on_apply() @@ -101,7 +101,7 @@ /datum/status_effect/limp id = "limp" status_type = STATUS_EFFECT_REPLACE - tick_interval = -1 // monkestation edit + tick_interval = STATUS_EFFECT_NO_TICK // monkestation edit on_remove_on_mob_delete = TRUE alert_type = /atom/movable/screen/alert/status_effect/limp var/msg_stage = 0//so you dont get the most intense messages immediately @@ -216,6 +216,7 @@ id = "wound" status_type = STATUS_EFFECT_MULTIPLE on_remove_on_mob_delete = TRUE + alert_type = null var/obj/item/bodypart/linked_limb var/datum/wound/linked_wound diff --git a/code/modules/antagonists/heretic/magic/ash_ascension.dm b/code/modules/antagonists/heretic/magic/ash_ascension.dm index c9b6b2ce0458..61b8b66dc403 100644 --- a/code/modules/antagonists/heretic/magic/ash_ascension.dm +++ b/code/modules/antagonists/heretic/magic/ash_ascension.dm @@ -33,7 +33,7 @@ /// Simple status effect for adding a ring of fire around a mob. /datum/status_effect/fire_ring id = "fire_ring" - tick_interval = 0.1 SECONDS + tick_interval = 0.2 SECONDS status_type = STATUS_EFFECT_REFRESH alert_type = null /// The radius of the ring around us. diff --git a/code/modules/antagonists/heretic/magic/shadow_cloak.dm b/code/modules/antagonists/heretic/magic/shadow_cloak.dm index ad942c71a328..3aa0b68c7c78 100644 --- a/code/modules/antagonists/heretic/magic/shadow_cloak.dm +++ b/code/modules/antagonists/heretic/magic/shadow_cloak.dm @@ -126,7 +126,7 @@ /datum/status_effect/shadow_cloak id = "shadow_cloak" alert_type = null - tick_interval = -1 + tick_interval = STATUS_EFFECT_NO_TICK /// How much damage we've been hit with var/damage_sustained = 0 /// How much damage we can be hit with before it starts rolling reveal chances diff --git a/code/modules/antagonists/heretic/magic/star_touch.dm b/code/modules/antagonists/heretic/magic/star_touch.dm index bab07f0871bd..6095dcd01a32 100644 --- a/code/modules/antagonists/heretic/magic/star_touch.dm +++ b/code/modules/antagonists/heretic/magic/star_touch.dm @@ -116,7 +116,7 @@ /datum/status_effect/cosmic_beam id = "cosmic_beam" - tick_interval = 0.1 SECONDS + tick_interval = 0.2 SECONDS duration = 1 MINUTES status_type = STATUS_EFFECT_REPLACE alert_type = null diff --git a/code/modules/antagonists/heretic/status_effects/buffs.dm b/code/modules/antagonists/heretic/status_effects/buffs.dm index 46f1d65acfd2..667668ae1bc7 100644 --- a/code/modules/antagonists/heretic/status_effects/buffs.dm +++ b/code/modules/antagonists/heretic/status_effects/buffs.dm @@ -109,7 +109,7 @@ id = "Silver Knives" alert_type = null status_type = STATUS_EFFECT_MULTIPLE - tick_interval = -1 + tick_interval = STATUS_EFFECT_NO_TICK /// The number of blades we summon up to. var/max_num_blades = 4 /// The radius of the blade's orbit. @@ -242,7 +242,7 @@ /datum/status_effect/caretaker_refuge id = "Caretaker’s Last Refuge" status_type = STATUS_EFFECT_REFRESH - duration = -1 + duration = STATUS_EFFECT_PERMANENT alert_type = null var/static/list/caretaking_traits = list(TRAIT_HANDS_BLOCKED, TRAIT_IGNORESLOWDOWN, TRAIT_SECLUDED_LOCATION) diff --git a/code/modules/antagonists/heretic/status_effects/debuffs.dm b/code/modules/antagonists/heretic/status_effects/debuffs.dm index 1088f846525f..9050cb97d247 100644 --- a/code/modules/antagonists/heretic/status_effects/debuffs.dm +++ b/code/modules/antagonists/heretic/status_effects/debuffs.dm @@ -31,7 +31,7 @@ /datum/status_effect/void_chill/lasting id = "lasting_void_chill" - duration = -1 + duration = STATUS_EFFECT_PERMANENT /datum/movespeed_modifier/void_chill multiplicative_slowdown = 0.3 @@ -199,7 +199,7 @@ alert_type = /atom/movable/screen/alert/status_effect/heretic_lastresort duration = 12 SECONDS status_type = STATUS_EFFECT_REPLACE - tick_interval = -1 + tick_interval = STATUS_EFFECT_NO_TICK /atom/movable/screen/alert/status_effect/heretic_lastresort name = "Last Resort" @@ -219,7 +219,7 @@ /datum/status_effect/moon_converted id = "moon converted" alert_type = /atom/movable/screen/alert/status_effect/moon_converted - duration = -1 + duration = STATUS_EFFECT_PERMANENT status_type = STATUS_EFFECT_REPLACE ///used to track damage var/damage_sustained = 0 diff --git a/code/modules/antagonists/heretic/status_effects/ghoul.dm b/code/modules/antagonists/heretic/status_effects/ghoul.dm index ff730573da59..4f0d89ee815c 100644 --- a/code/modules/antagonists/heretic/status_effects/ghoul.dm +++ b/code/modules/antagonists/heretic/status_effects/ghoul.dm @@ -1,7 +1,7 @@ /datum/status_effect/ghoul id = "ghoul" status_type = STATUS_EFFECT_UNIQUE - duration = -1 + duration = STATUS_EFFECT_PERMANENT alert_type = /atom/movable/screen/alert/status_effect/ghoul /// The new max health value set for the ghoul, if supplied var/new_max_health diff --git a/code/modules/mining/equipment/monster_organs/brimdust_sac.dm b/code/modules/mining/equipment/monster_organs/brimdust_sac.dm index a77e526a9d1f..62a3acdb4472 100644 --- a/code/modules/mining/equipment/monster_organs/brimdust_sac.dm +++ b/code/modules/mining/equipment/monster_organs/brimdust_sac.dm @@ -71,7 +71,7 @@ id = "brimdust_coating" stacks = 0 max_stacks = 3 - tick_interval = -1 + tick_interval = STATUS_EFFECT_NO_TICK consumed_on_threshold = FALSE alert_type = /atom/movable/screen/alert/status_effect/brimdust_coating status_type = STATUS_EFFECT_REFRESH // Allows us to add one stack at a time by just applying the effect diff --git a/code/modules/mob/living/basic/lavaland/basilisk/basilisk_overheat.dm b/code/modules/mob/living/basic/lavaland/basilisk/basilisk_overheat.dm index c0b49fbdc619..71e938c5164e 100644 --- a/code/modules/mob/living/basic/lavaland/basilisk/basilisk_overheat.dm +++ b/code/modules/mob/living/basic/lavaland/basilisk/basilisk_overheat.dm @@ -2,6 +2,7 @@ /datum/status_effect/basilisk_overheat id = "basilisk_overheat" duration = 3 MINUTES + alert_type = null /// Things which will chill us out if we get hit by them var/static/list/chilling_reagents = list( /datum/reagent/medicine/cryoxadone, diff --git a/code/modules/mob/living/basic/space_fauna/revenant/revenant_effects.dm b/code/modules/mob/living/basic/space_fauna/revenant/revenant_effects.dm index 0eeec231973e..41be027797fd 100644 --- a/code/modules/mob/living/basic/space_fauna/revenant/revenant_effects.dm +++ b/code/modules/mob/living/basic/space_fauna/revenant/revenant_effects.dm @@ -1,5 +1,7 @@ /// Parent type for all unique revenant status effects /datum/status_effect/revenant + id = STATUS_EFFECT_ID_ABSTRACT + alert_type = null /datum/status_effect/revenant/on_creation(mob/living/new_owner, duration) if(isnum(duration)) diff --git a/code/modules/mob/living/status_procs.dm b/code/modules/mob/living/status_procs.dm index 3ee50b9d16cf..3c9ad7ea9fed 100644 --- a/code/modules/mob/living/status_procs.dm +++ b/code/modules/mob/living/status_procs.dm @@ -457,7 +457,7 @@ return var/datum/status_effect/incapacitating/sleeping/S = IsSleeping() if(S) - S.duration = -1 + S.duration = STATUS_EFFECT_PERMANENT else S = apply_status_effect(/datum/status_effect/incapacitating/sleeping, -1) return S diff --git a/code/modules/religion/burdened/psyker.dm b/code/modules/religion/burdened/psyker.dm index e913584081cd..e9cf7793d8fd 100644 --- a/code/modules/religion/burdened/psyker.dm +++ b/code/modules/religion/burdened/psyker.dm @@ -270,7 +270,7 @@ id = "psychic_projection" alert_type = null remove_on_fullheal = TRUE - tick_interval = 0.1 SECONDS + tick_interval = 0.2 SECONDS /// Times the target has dry fired a weapon. var/times_dry_fired = 0 /// Needs to reach times_dry_fired for the next dry fire to happen. diff --git a/code/modules/religion/hunt/hunter_pinpointer.dm b/code/modules/religion/hunt/hunter_pinpointer.dm index d2a69d1d57f5..a2312b265a9f 100644 --- a/code/modules/religion/hunt/hunter_pinpointer.dm +++ b/code/modules/religion/hunt/hunter_pinpointer.dm @@ -15,7 +15,7 @@ alert_type = /atom/movable/screen/alert/status_effect/agent_pinpointer/hunters_sense minimum_range = HUNTER_MINIMUM_RANGE tick_interval = HUNTER_PING_TIME - duration = -1 + duration = STATUS_EFFECT_PERMANENT range_fuzz_factor = HUNTER_FUZZ_FACTOR ///Attempting to locate a nearby target to scan and point towards. diff --git a/code/modules/research/xenobiology/crossbreeding/_status_effects.dm b/code/modules/research/xenobiology/crossbreeding/_status_effects.dm index 67c92ea362ca..717e56196e88 100644 --- a/code/modules/research/xenobiology/crossbreeding/_status_effects.dm +++ b/code/modules/research/xenobiology/crossbreeding/_status_effects.dm @@ -61,8 +61,8 @@ /datum/status_effect/slimerecall id = "slime_recall" - duration = -1 //Will be removed by the extract. - tick_interval = -1 + duration = STATUS_EFFECT_PERMANENT //Will be removed by the extract. + tick_interval = STATUS_EFFECT_NO_TICK alert_type = null var/interrupted = FALSE var/mob/target @@ -98,7 +98,7 @@ /datum/status_effect/frozenstasis id = "slime_frozen" status_type = STATUS_EFFECT_UNIQUE - duration = -1 //Will remove self when block breaks. + duration = STATUS_EFFECT_PERMANENT //Will remove self when block breaks. alert_type = /atom/movable/screen/alert/status_effect/freon/stasis var/obj/structure/ice_stasis/cube @@ -127,7 +127,7 @@ /datum/status_effect/slime_clone id = "slime_cloned" status_type = STATUS_EFFECT_UNIQUE - duration = -1 + duration = STATUS_EFFECT_PERMANENT alert_type = null var/mob/living/clone var/datum/mind/originalmind //For when the clone gibs. @@ -172,7 +172,7 @@ /datum/status_effect/slime_clone_decay id = "slime_clonedecay" status_type = STATUS_EFFECT_UNIQUE - duration = -1 + duration = STATUS_EFFECT_PERMANENT alert_type = /atom/movable/screen/alert/status_effect/clone_decay /datum/status_effect/slime_clone_decay/tick() @@ -229,7 +229,7 @@ /datum/status_effect/rebreathing id = "rebreathing" - duration = -1 + duration = STATUS_EFFECT_PERMANENT alert_type = null /datum/status_effect/rebreathing/tick() @@ -439,7 +439,7 @@ /datum/status_effect/stabilized //The base stabilized extract effect, has no effect of its' own. id = "stabilizedbase" - duration = -1 + duration = STATUS_EFFECT_PERMANENT alert_type = null /// Item which provides this buff var/obj/item/slimecross/stabilized/linked_extract @@ -830,7 +830,7 @@ /datum/status_effect/pinkdamagetracker id = "pinkdamagetracker" - duration = -1 + duration = STATUS_EFFECT_PERMANENT alert_type = null var/damage = 0 var/lasthealth diff --git a/code/modules/unit_tests/_unit_tests.dm b/code/modules/unit_tests/_unit_tests.dm index c662ec1f4b74..44e3e0078541 100644 --- a/code/modules/unit_tests/_unit_tests.dm +++ b/code/modules/unit_tests/_unit_tests.dm @@ -219,6 +219,7 @@ #include "spritesheets.dm" #include "stack_singular_name.dm" #include "station_trait_tests.dm" +#include "status_effect_validity.dm" #include "stomach.dm" #include "strange_reagent.dm" #include "strippable.dm" diff --git a/code/modules/unit_tests/status_effect_validity.dm b/code/modules/unit_tests/status_effect_validity.dm new file mode 100644 index 000000000000..29d48c69c6bf --- /dev/null +++ b/code/modules/unit_tests/status_effect_validity.dm @@ -0,0 +1,61 @@ +/// Validates status effect tick interval setup +/datum/unit_test/status_effect_ticks + +/datum/unit_test/status_effect_ticks/Run() + for(var/datum/status_effect/checking as anything in subtypesof(/datum/status_effect)) + if(initial(checking.id) == STATUS_EFFECT_ID_ABSTRACT) + continue + var/tick_speed = initial(checking.tick_interval) + if(tick_speed == STATUS_EFFECT_NO_TICK) + continue + if(tick_speed == INFINITY) + TEST_FAIL("Status effect [checking] has tick_interval set to INFINITY, this is not how you prevent ticks - use tick_interval = STATUS_EFFECT_NO_TICK instead.") + continue + if(tick_speed == 0) + TEST_FAIL("Status effect [checking] has tick_interval set to 0, this is not how you prevent ticks - use tick_interval = STATUS_EFFECT_NO_TICK instead.") + continue + switch(initial(checking.processing_speed)) + if(STATUS_EFFECT_FAST_PROCESS, STATUS_EFFECT_PRIORITY) // monkestation edit: STATUS_EFFECT_PRIORITY + if(tick_speed < SSfastprocess.wait) + TEST_FAIL("Status effect [checking] has tick_interval set to [tick_speed], which is faster than SSfastprocess can tick ([SSfastprocess.wait]).") + if(STATUS_EFFECT_NORMAL_PROCESS) + if(tick_speed < SSprocessing.wait) + TEST_FAIL("Status effect [checking] has tick_interval set to [tick_speed], which is faster than SSprocessing can tick ([SSprocessing.wait]).") + else + TEST_FAIL("Invalid processing speed for status effect [checking] : [initial(checking.processing_speed)]") + +/// Validates status effect alert type setup +/datum/unit_test/status_effect_alert + +/datum/unit_test/status_effect_alert/Run() + // The base typepath is used to indicate "I didn't set an alert type" + var/bad_alert_type = /datum/status_effect::alert_type + TEST_ASSERT_NOTNULL(bad_alert_type, "No alert type defined in /datum/status_effect - This test may be redundant now.") + + for(var/datum/status_effect/checking as anything in subtypesof(/datum/status_effect)) + if(initial(checking.id) == STATUS_EFFECT_ID_ABSTRACT) + continue + if(initial(checking.alert_type) != bad_alert_type) + continue + TEST_FAIL("[checking] has not set alert_type. If you don't want an alert, set alert_type = null - \ + Otherwise, give it an alert subtype.") + +/// Validates status effect id setup +/datum/unit_test/status_effect_ids + +/datum/unit_test/status_effect_ids/Run() + // The base id is used to indicate "I didn't set an id" + var/bad_id = /datum/status_effect::id + TEST_ASSERT_NOTNULL(bad_id, "No id defined in /datum/status_effect - This test may be redundant now.") + + for(var/datum/status_effect/checking as anything in subtypesof(/datum/status_effect)) + if(initial(checking.id) == STATUS_EFFECT_ID_ABSTRACT) + // we are just assuming that a child of an abstract should not be abstract. + // of course in practice, this may not always be the case - but if you're + // structuring a status effect like this, you can just change the parent id to anything else + var/datum/status_effect/checking_parent = initial(checking.parent_type) + if(initial(checking_parent.id) != STATUS_EFFECT_ID_ABSTRACT) + continue + if(initial(checking.id) != bad_id) + continue + TEST_FAIL("[checking] has not set an id. This is required for status effects.") diff --git a/monkestation/code/datums/status_effects/buffs.dm b/monkestation/code/datums/status_effects/buffs.dm index ab6bd0eb4ad7..e5da8e526408 100644 --- a/monkestation/code/datums/status_effects/buffs.dm +++ b/monkestation/code/datums/status_effects/buffs.dm @@ -18,7 +18,7 @@ /datum/status_effect/mayhem show_duration = TRUE - tick_interval = 0 // Just pass me the SSfastprocess ticks please. + tick_interval = STATUS_EFFECT_NO_TICK // Just pass me the SSfastprocess ticks please. alert_type = /atom/movable/screen/alert/status_effect/mayhem diff --git a/monkestation/code/datums/status_effects/changeling.dm b/monkestation/code/datums/status_effects/changeling.dm index 67bbb18c5fe0..1d25b4328871 100644 --- a/monkestation/code/datums/status_effects/changeling.dm +++ b/monkestation/code/datums/status_effects/changeling.dm @@ -19,7 +19,7 @@ id = "changeling_adrenaline" duration = 20 SECONDS show_duration = TRUE - tick_interval = 0 + tick_interval = 0.2 SECONDS alert_type = /atom/movable/screen/alert/status_effect/changeling/adrenaline status_type = STATUS_EFFECT_REFRESH @@ -69,7 +69,7 @@ id = "changeling_panacea" duration = 1 MINUTE show_duration = TRUE - tick_interval = 0 + tick_interval = 0.2 SECONDS alert_type = /atom/movable/screen/alert/status_effect/changeling/panacea status_type = STATUS_EFFECT_REFRESH @@ -158,7 +158,7 @@ /datum/status_effect/changeling_muscles id = "changeling_muscles" - tick_interval = 0 + tick_interval = 1 SECONDS processing_speed = STATUS_EFFECT_NORMAL_PROCESS alert_type = /atom/movable/screen/alert/status_effect/changeling/muscles diff --git a/monkestation/code/datums/status_effects/food_buffs.dm b/monkestation/code/datums/status_effects/food_buffs.dm index 44ae8e55d659..566fc6f05415 100644 --- a/monkestation/code/datums/status_effects/food_buffs.dm +++ b/monkestation/code/datums/status_effects/food_buffs.dm @@ -1,9 +1,9 @@ /datum/status_effect/food + id = STATUS_EFFECT_ID_ABSTRACT duration = 10 MINUTES status_type = STATUS_EFFECT_REPLACE show_duration = TRUE - /datum/status_effect/food/proc/apply_quality(quality) return diff --git a/monkestation/code/modules/a_medical_day/lungless.dm b/monkestation/code/modules/a_medical_day/lungless.dm index 3611d366aa00..73da7035d906 100644 --- a/monkestation/code/modules/a_medical_day/lungless.dm +++ b/monkestation/code/modules/a_medical_day/lungless.dm @@ -1,8 +1,8 @@ /datum/status_effect/lungless id = "no_lungs" alert_type = null - duration = -1 - tick_interval = -1 + duration = STATUS_EFFECT_PERMANENT + tick_interval = STATUS_EFFECT_NO_TICK /datum/status_effect/lungless/on_apply() if(!iscarbon(owner)) diff --git a/monkestation/code/modules/antagonists/borers/code/status_effects.dm b/monkestation/code/modules/antagonists/borers/code/status_effects.dm index edfca2eff0ec..060702ba563e 100644 --- a/monkestation/code/modules/antagonists/borers/code/status_effects.dm +++ b/monkestation/code/modules/antagonists/borers/code/status_effects.dm @@ -1,6 +1,6 @@ /datum/status_effect/borer_sugar id = "borer_sugar" - tick_interval = -1 + tick_interval = STATUS_EFFECT_NO_TICK status_type = STATUS_EFFECT_UNIQUE alert_type = /atom/movable/screen/alert/status_effect/borer_sugar diff --git a/monkestation/code/modules/antagonists/clock_cult/status_effects.dm b/monkestation/code/modules/antagonists/clock_cult/status_effects.dm index 4243d4518a2a..5014a9514d85 100644 --- a/monkestation/code/modules/antagonists/clock_cult/status_effects.dm +++ b/monkestation/code/modules/antagonists/clock_cult/status_effects.dm @@ -2,7 +2,7 @@ id = "interdicted" duration = 2.5 SECONDS status_type = STATUS_EFFECT_REFRESH - tick_interval = 1 + tick_interval = 0.2 SECONDS alert_type = /atom/movable/screen/alert/status_effect/interdiction /// If we kicked the owner out of running mode var/running_toggled = FALSE diff --git a/monkestation/code/modules/antagonists/monster_hunters/events/wonderland_apocalypse.dm b/monkestation/code/modules/antagonists/monster_hunters/events/wonderland_apocalypse.dm index def42a7b2b9b..5627a3fe72b6 100644 --- a/monkestation/code/modules/antagonists/monster_hunters/events/wonderland_apocalypse.dm +++ b/monkestation/code/modules/antagonists/monster_hunters/events/wonderland_apocalypse.dm @@ -123,7 +123,7 @@ /datum/status_effect/wonderland_district id = "wonderland_district" alert_type = /atom/movable/screen/alert/status_effect/wonderland_district - tick_interval = -1 + tick_interval = STATUS_EFFECT_NO_TICK /// List of /datum/action instance that we've registered `COMSIG_ACTION_TRIGGER` on. var/list/datum/action/registered_actions /// Typecache of spells to NOT trigger the effect on. diff --git a/monkestation/code/modules/antagonists/monster_hunters/tools/bnuuy_mask.dm b/monkestation/code/modules/antagonists/monster_hunters/tools/bnuuy_mask.dm index 25694199785d..751d1a544fb5 100644 --- a/monkestation/code/modules/antagonists/monster_hunters/tools/bnuuy_mask.dm +++ b/monkestation/code/modules/antagonists/monster_hunters/tools/bnuuy_mask.dm @@ -55,7 +55,7 @@ /datum/status_effect/bnuuy_mask id = "bnuuy_mask" alert_type = null - tick_interval = -1 + tick_interval = STATUS_EFFECT_NO_TICK var/datum/component/glitching_state/wondershift /datum/status_effect/bnuuy_mask/on_apply() diff --git a/monkestation/code/modules/antagonists/monster_hunters/weapons/hunter_revolver.dm b/monkestation/code/modules/antagonists/monster_hunters/weapons/hunter_revolver.dm index 7bf7932ff9cd..ac89464b2049 100644 --- a/monkestation/code/modules/antagonists/monster_hunters/weapons/hunter_revolver.dm +++ b/monkestation/code/modules/antagonists/monster_hunters/weapons/hunter_revolver.dm @@ -39,7 +39,7 @@ /datum/status_effect/silver_bullet id = "silver_bullet" duration = 8 SECONDS - tick_interval = -1 + tick_interval = STATUS_EFFECT_NO_TICK status_type = STATUS_EFFECT_REFRESH alert_type = /atom/movable/screen/alert/status_effect/silver_bullet diff --git a/monkestation/code/modules/art_sci_overrides/artifact_effects/false_rod.dm b/monkestation/code/modules/art_sci_overrides/artifact_effects/false_rod.dm index 27030a251101..26c4c0501e65 100644 --- a/monkestation/code/modules/art_sci_overrides/artifact_effects/false_rod.dm +++ b/monkestation/code/modules/art_sci_overrides/artifact_effects/false_rod.dm @@ -44,7 +44,7 @@ /datum/status_effect/forced_oath id = "Forced Oath" status_type = STATUS_EFFECT_UNIQUE - duration = -1 + duration = STATUS_EFFECT_PERMANENT tick_interval = 25 alert_type = null var/datum/component/aura_healing/our_aura diff --git a/monkestation/code/modules/bloodsuckers/bloodsucker/bloodsucker_frenzy.dm b/monkestation/code/modules/bloodsuckers/bloodsucker/bloodsucker_frenzy.dm index 0902dafbbf26..325ec0297d74 100644 --- a/monkestation/code/modules/bloodsuckers/bloodsucker/bloodsucker_frenzy.dm +++ b/monkestation/code/modules/bloodsuckers/bloodsucker/bloodsucker_frenzy.dm @@ -31,7 +31,7 @@ /datum/status_effect/frenzy id = "Frenzy" status_type = STATUS_EFFECT_UNIQUE - duration = -1 + duration = STATUS_EFFECT_PERMANENT tick_interval = 1 SECONDS alert_type = /atom/movable/screen/alert/status_effect/frenzy /// The stored Bloodsucker antag datum diff --git a/monkestation/code/modules/bloodsuckers/bloodsucker/bloodsucker_sol.dm b/monkestation/code/modules/bloodsuckers/bloodsucker/bloodsucker_sol.dm index e953d8822cde..51feae965738 100644 --- a/monkestation/code/modules/bloodsuckers/bloodsucker/bloodsucker_sol.dm +++ b/monkestation/code/modules/bloodsuckers/bloodsucker/bloodsucker_sol.dm @@ -153,7 +153,7 @@ /datum/status_effect/bloodsucker_sol id = "bloodsucker_sol" - tick_interval = -1 + tick_interval = STATUS_EFFECT_NO_TICK alert_type = /atom/movable/screen/alert/status_effect/bloodsucker_sol var/list/datum/action/cooldown/bloodsucker/burdened_actions var/static/list/sol_traits = list( diff --git a/monkestation/code/modules/bloodsuckers/powers/masquerade.dm b/monkestation/code/modules/bloodsuckers/powers/masquerade.dm index 0d3737d97c40..840fcb35487e 100644 --- a/monkestation/code/modules/bloodsuckers/powers/masquerade.dm +++ b/monkestation/code/modules/bloodsuckers/powers/masquerade.dm @@ -79,8 +79,8 @@ /datum/status_effect/masquerade id = "masquerade" - duration = -1 - tick_interval = -1 + duration = STATUS_EFFECT_PERMANENT + tick_interval = STATUS_EFFECT_NO_TICK alert_type = /atom/movable/screen/alert/status_effect/masquerade /atom/movable/screen/alert/status_effect/masquerade diff --git a/monkestation/code/modules/bloodsuckers/vassals/vassal_pinpointer.dm b/monkestation/code/modules/bloodsuckers/vassals/vassal_pinpointer.dm index 791b9a8f9f5f..4d0c6b00f213 100644 --- a/monkestation/code/modules/bloodsuckers/vassals/vassal_pinpointer.dm +++ b/monkestation/code/modules/bloodsuckers/vassals/vassal_pinpointer.dm @@ -14,7 +14,7 @@ alert_type = /atom/movable/screen/alert/status_effect/agent_pinpointer/vassal_edition minimum_range = VASSAL_SCAN_MIN_DISTANCE tick_interval = VASSAL_SCAN_PING_TIME - duration = -1 + duration = STATUS_EFFECT_PERMANENT range_fuzz_factor = 0 /datum/status_effect/agent_pinpointer/vassal_edition/on_creation(mob/living/new_owner, ...) diff --git a/monkestation/code/modules/blueshift/species/ashwalker.dm b/monkestation/code/modules/blueshift/species/ashwalker.dm index 773eb4b40f2c..4c7a8ec617b5 100644 --- a/monkestation/code/modules/blueshift/species/ashwalker.dm +++ b/monkestation/code/modules/blueshift/species/ashwalker.dm @@ -117,8 +117,8 @@ /datum/status_effect/ashwalker_damage //tracks the damage dealt to this mob by ashwalkers id = "ashwalker_damage" - duration = -1 - tick_interval = -1 + duration = STATUS_EFFECT_PERMANENT + tick_interval = STATUS_EFFECT_NO_TICK status_type = STATUS_EFFECT_UNIQUE alert_type = null /// How much damage has been dealt to the mob diff --git a/monkestation/code/modules/can_spessmen_feel_pain/pain/status_effects/low_blood_pressure.dm b/monkestation/code/modules/can_spessmen_feel_pain/pain/status_effects/low_blood_pressure.dm index 30b1d0f40592..a42c1259fad9 100644 --- a/monkestation/code/modules/can_spessmen_feel_pain/pain/status_effects/low_blood_pressure.dm +++ b/monkestation/code/modules/can_spessmen_feel_pain/pain/status_effects/low_blood_pressure.dm @@ -1,6 +1,6 @@ /datum/status_effect/low_blood_pressure id = "low_blood_pressure" - tick_interval = -1 + tick_interval = STATUS_EFFECT_NO_TICK status_type = STATUS_EFFECT_UNIQUE alert_type = /atom/movable/screen/alert/status_effect/low_blood_pressure diff --git a/monkestation/code/modules/datums/status_effects/debuffs.dm b/monkestation/code/modules/datums/status_effects/debuffs.dm index 60b8f0587b4e..094d18bd5142 100644 --- a/monkestation/code/modules/datums/status_effects/debuffs.dm +++ b/monkestation/code/modules/datums/status_effects/debuffs.dm @@ -3,6 +3,9 @@ desc = "You've been hit with an EMP! You're malfunctioning!" icon_state = "hypnosis" +/datum/status_effect/ipc + id = STATUS_EFFECT_ID_ABSTRACT + /datum/status_effect/ipc/emp id = "ipc_emp" duration = 120 SECONDS diff --git a/monkestation/code/modules/ghost_players/centcom_grace.dm b/monkestation/code/modules/ghost_players/centcom_grace.dm index d97f50637089..ade5feb4e73a 100644 --- a/monkestation/code/modules/ghost_players/centcom_grace.dm +++ b/monkestation/code/modules/ghost_players/centcom_grace.dm @@ -1,6 +1,6 @@ /datum/status_effect/centcom_grace id = "centcom_grace" - tick_interval = -1 + tick_interval = STATUS_EFFECT_NO_TICK alert_type = null var/last_active = FALSE diff --git a/monkestation/code/modules/liquids/liquid_status_effect.dm b/monkestation/code/modules/liquids/liquid_status_effect.dm index 514667fc0272..9b31a66d3da3 100644 --- a/monkestation/code/modules/liquids/liquid_status_effect.dm +++ b/monkestation/code/modules/liquids/liquid_status_effect.dm @@ -1,7 +1,7 @@ /datum/status_effect/water_affected id = "wateraffected" alert_type = null - duration = -1 + duration = STATUS_EFFECT_PERMANENT /datum/status_effect/water_affected/on_apply() //We should be inside a liquid turf if this is applied @@ -36,8 +36,9 @@ blacklisted_movetypes = FLOATING | FLYING /datum/status_effect/ocean_affected + id = "ocean_affected" + duration = STATUS_EFFECT_PERMANENT alert_type = null - duration = -1 /datum/status_effect/ocean_affected/tick() var/turf/ocean_turf = get_turf(owner) diff --git a/monkestation/code/modules/ranching/chickens/tier1/chicken.dm b/monkestation/code/modules/ranching/chickens/tier1/chicken.dm index 7ecf78db3790..6da6940f9af4 100644 --- a/monkestation/code/modules/ranching/chickens/tier1/chicken.dm +++ b/monkestation/code/modules/ranching/chickens/tier1/chicken.dm @@ -4,4 +4,6 @@ instability = 25 // 25% more likely to mutate than other chickens /datum/status_effect/ranching + id = STATUS_EFFECT_ID_ABSTRACT + alert_type = null show_duration = TRUE diff --git a/monkestation/code/modules/slimecore/crossbreeding/regenerative/cooldown.dm b/monkestation/code/modules/slimecore/crossbreeding/regenerative/cooldown.dm index 0614d914d116..431e99388fb5 100644 --- a/monkestation/code/modules/slimecore/crossbreeding/regenerative/cooldown.dm +++ b/monkestation/code/modules/slimecore/crossbreeding/regenerative/cooldown.dm @@ -1,7 +1,7 @@ /datum/status_effect/slime_regen_cooldown id = "slime_regen_cooldown" status_type = STATUS_EFFECT_MULTIPLE - tick_interval = -1 + tick_interval = STATUS_EFFECT_NO_TICK alert_type = null remove_on_fullheal = TRUE heal_flag_necessary = HEAL_ADMIN From 7f225d04d0033108933a395a3476deb0f518dcc5 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 22 Dec 2024 19:46:00 +0000 Subject: [PATCH 65/81] Automatic changelog for PR #4580 [ci skip] --- html/changelogs/AutoChangeLog-pr-4580.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-4580.yml diff --git a/html/changelogs/AutoChangeLog-pr-4580.yml b/html/changelogs/AutoChangeLog-pr-4580.yml new file mode 100644 index 000000000000..44c2d5bc373d --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-4580.yml @@ -0,0 +1,4 @@ +author: "Absolucy, Melbert" +delete-after: True +changes: + - bugfix: "You should be afflicted by the \"Curse of Mundanity\" far, far less." \ No newline at end of file From 8fdf51502099e14f1f3963e4381c4e0c9696b046 Mon Sep 17 00:00:00 2001 From: Lucy Date: Sun, 22 Dec 2024 15:22:41 -0500 Subject: [PATCH 66/81] All ghosts now see PDA messages, not just observers (#4639) --- .../file_system/programs/messenger/messenger_program.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/modular_computers/file_system/programs/messenger/messenger_program.dm b/code/modules/modular_computers/file_system/programs/messenger/messenger_program.dm index d533d98cf3e1..14cf735d7da1 100644 --- a/code/modules/modular_computers/file_system/programs/messenger/messenger_program.dm +++ b/code/modules/modular_computers/file_system/programs/messenger/messenger_program.dm @@ -608,7 +608,7 @@ // Show it to ghosts var/ghost_message = span_name("[sender] [rigged ? "(as [fake_name]) Rigged " : ""]PDA Message --> [span_name("[signal.format_target()]")]: \"[signal.format_message()]\"") - for(var/mob/player_mob as anything in GLOB.current_observers_list) + for(var/mob/player_mob as anything in GLOB.dead_mob_list) if(player_mob.client && !player_mob.client?.prefs) stack_trace("[player_mob] ([player_mob.ckey]) had null prefs, which shouldn't be possible!") continue From 1b5ce61b81392e2db930ce5c1af8d8e7717cbe9f Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 22 Dec 2024 20:22:59 +0000 Subject: [PATCH 67/81] Automatic changelog for PR #4639 [ci skip] --- html/changelogs/AutoChangeLog-pr-4639.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-4639.yml diff --git a/html/changelogs/AutoChangeLog-pr-4639.yml b/html/changelogs/AutoChangeLog-pr-4639.yml new file mode 100644 index 000000000000..4587ff00e654 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-4639.yml @@ -0,0 +1,4 @@ +author: "Absolucy" +delete-after: True +changes: + - qol: "All ghosts now see PDA messages, not just observers." \ No newline at end of file From 8fa9eb92c43bd00232ed54a6f955523f14774eda Mon Sep 17 00:00:00 2001 From: Changelogs Date: Sun, 22 Dec 2024 20:24:23 +0000 Subject: [PATCH 68/81] Automatic changelog compile [ci skip] --- html/changelogs/AutoChangeLog-pr-4580.yml | 4 ---- html/changelogs/AutoChangeLog-pr-4632.yml | 4 ---- html/changelogs/AutoChangeLog-pr-4633.yml | 4 ---- html/changelogs/AutoChangeLog-pr-4635.yml | 4 ---- html/changelogs/AutoChangeLog-pr-4638.yml | 4 ---- html/changelogs/AutoChangeLog-pr-4639.yml | 4 ---- html/changelogs/archive/2024-12.yml | 13 +++++++++++++ 7 files changed, 13 insertions(+), 24 deletions(-) delete mode 100644 html/changelogs/AutoChangeLog-pr-4580.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-4632.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-4633.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-4635.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-4638.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-4639.yml diff --git a/html/changelogs/AutoChangeLog-pr-4580.yml b/html/changelogs/AutoChangeLog-pr-4580.yml deleted file mode 100644 index 44c2d5bc373d..000000000000 --- a/html/changelogs/AutoChangeLog-pr-4580.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Absolucy, Melbert" -delete-after: True -changes: - - bugfix: "You should be afflicted by the \"Curse of Mundanity\" far, far less." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-4632.yml b/html/changelogs/AutoChangeLog-pr-4632.yml deleted file mode 100644 index f88d93e27281..000000000000 --- a/html/changelogs/AutoChangeLog-pr-4632.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Tractor Mann" -delete-after: True -changes: - - admin: "Admins will no longer be told you dusted someone with power gloves when you didnt, and that you shocked someone with power gloves when you dust them." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-4633.yml b/html/changelogs/AutoChangeLog-pr-4633.yml deleted file mode 100644 index 172b28ab6c19..000000000000 --- a/html/changelogs/AutoChangeLog-pr-4633.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Absolucy" -delete-after: True -changes: - - rscadd: "Added tinyfans to the arrivals shuttle and public mining shuttle doors on Blueshift." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-4635.yml b/html/changelogs/AutoChangeLog-pr-4635.yml deleted file mode 100644 index 07b5b61ef5ce..000000000000 --- a/html/changelogs/AutoChangeLog-pr-4635.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Absolucy" -delete-after: True -changes: - - bugfix: "Properly marked the message type and confidentiality of a few admin/mentor-related notifications." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-4638.yml b/html/changelogs/AutoChangeLog-pr-4638.yml deleted file mode 100644 index a90c6aed296c..000000000000 --- a/html/changelogs/AutoChangeLog-pr-4638.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Absolucy" -delete-after: True -changes: - - bugfix: "The map selected for the next round should actually always be the map that loads next round." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-4639.yml b/html/changelogs/AutoChangeLog-pr-4639.yml deleted file mode 100644 index 4587ff00e654..000000000000 --- a/html/changelogs/AutoChangeLog-pr-4639.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Absolucy" -delete-after: True -changes: - - qol: "All ghosts now see PDA messages, not just observers." \ No newline at end of file diff --git a/html/changelogs/archive/2024-12.yml b/html/changelogs/archive/2024-12.yml index 5be305e9ae98..c35e63293239 100644 --- a/html/changelogs/archive/2024-12.yml +++ b/html/changelogs/archive/2024-12.yml @@ -363,5 +363,18 @@ - bugfix: Heretic sacrifice targets will have their blood restored and cleared of chems if they are sent to the mansus. 2024-12-22: + Absolucy: + - bugfix: Properly marked the message type and confidentiality of a few admin/mentor-related + notifications. + - bugfix: The map selected for the next round should actually always be the map + that loads next round. + - rscadd: Added tinyfans to the arrivals shuttle and public mining shuttle doors + on Blueshift. + - qol: All ghosts now see PDA messages, not just observers. + Absolucy, Melbert: + - bugfix: You should be afflicted by the "Curse of Mundanity" far, far less. Shoddd: - bugfix: you can no longer akimbo and fire a wand forever + Tractor Mann: + - admin: Admins will no longer be told you dusted someone with power gloves when + you didnt, and that you shocked someone with power gloves when you dust them. From abc3ceeedc11afdf0f49a36ce86ecf5e9e299993 Mon Sep 17 00:00:00 2001 From: Lucy Date: Sun, 22 Dec 2024 18:56:57 -0500 Subject: [PATCH 69/81] adds a component to make it obvious what items came from a gift (#4625) --- .../traits/monkestation/declarations.dm | 2 + code/__DEFINES/~monkestation/vv.dm | 1 + code/__HELPERS/~monkestation-helpers/atoms.dm | 8 ++ code/_globalvars/traits/_traits.dm | 13 +-- code/game/objects/items/gift.dm | 1 + code/modules/admin/verbs/admingame.dm | 12 +++ .../code/datums/components/gift_item.dm | 86 +++++++++++++++++++ tgstation.dme | 2 + 8 files changed, 119 insertions(+), 6 deletions(-) create mode 100644 code/__DEFINES/~monkestation/vv.dm create mode 100644 monkestation/code/datums/components/gift_item.dm diff --git a/code/__DEFINES/traits/monkestation/declarations.dm b/code/__DEFINES/traits/monkestation/declarations.dm index 8a07f00fb954..a26127eb0ff5 100644 --- a/code/__DEFINES/traits/monkestation/declarations.dm +++ b/code/__DEFINES/traits/monkestation/declarations.dm @@ -121,6 +121,8 @@ #define TRAIT_BYPASS_COMPRESS_CHECK "can_compress_anyways" /// This item is considered "trash" (and will be eaten by cleaner slimes) #define TRAIT_TRASH_ITEM "trash_item" +/// This item came from a gift. +#define TRAIT_GIFT_ITEM "gift_item" // /atom/movable /// Things with this trait can pass through wooden barricades. diff --git a/code/__DEFINES/~monkestation/vv.dm b/code/__DEFINES/~monkestation/vv.dm new file mode 100644 index 000000000000..8acf0c7ef495 --- /dev/null +++ b/code/__DEFINES/~monkestation/vv.dm @@ -0,0 +1 @@ +#define VV_HK_EXAMINE_GIFT "examine_gift" diff --git a/code/__HELPERS/~monkestation-helpers/atoms.dm b/code/__HELPERS/~monkestation-helpers/atoms.dm index 67b81a50dafb..44f26ac804e0 100644 --- a/code/__HELPERS/~monkestation-helpers/atoms.dm +++ b/code/__HELPERS/~monkestation-helpers/atoms.dm @@ -26,3 +26,11 @@ default_typecache ||= typecacheof(list(/obj/effect, /atom/movable/screen)) typecache = default_typecache return typecache_filter_list_reverse(src.contents, typecache) + +/// Returns a list of all items in our contents that were obtained from gifts. +/atom/proc/get_all_gift_contents() as /list + RETURN_TYPE(/list/obj/item) + . = list() + for(var/obj/item/thing as anything in get_all_contents_type(/obj/item)) + if(!QDELETED(thing) && HAS_TRAIT(thing, TRAIT_GIFT_ITEM)) + . += thing diff --git a/code/_globalvars/traits/_traits.dm b/code/_globalvars/traits/_traits.dm index 7734282dd4d7..12590729049c 100644 --- a/code/_globalvars/traits/_traits.dm +++ b/code/_globalvars/traits/_traits.dm @@ -611,24 +611,31 @@ GLOBAL_LIST_INIT(traits_by_type, list( ), /obj/item = list( "TRAIT_APC_SHOCKING" = TRAIT_APC_SHOCKING, + "TRAIT_ASSISTED_BREATHING" = TRAIT_ASSISTED_BREATHING, "TRAIT_BASIC_QUALITY_BAIT" = TRAIT_BASIC_QUALITY_BAIT, "TRAIT_BELT_SATCHEL" = TRAIT_BELT_SATCHEL, "TRAIT_BLIND_TOOL" = TRAIT_BLIND_TOOL, "TRAIT_BYPASS_COMPRESS_CHECK" = TRAIT_BYPASS_COMPRESS_CHECK, "TRAIT_CUSTOM_TAP_SOUND" = TRAIT_CUSTOM_TAP_SOUND, "TRAIT_DANGEROUS_OBJECT" = TRAIT_DANGEROUS_OBJECT, + "TRAIT_FEATHERED" = TRAIT_FEATHERED, "TRAIT_FISHING_BAIT" = TRAIT_FISHING_BAIT, "TRAIT_FOOD_GRILLED" = TRAIT_FOOD_GRILLED, + "TRAIT_GIFT_ITEM" = TRAIT_GIFT_ITEM, "TRAIT_GOOD_QUALITY_BAIT" = TRAIT_GOOD_QUALITY_BAIT, "TRAIT_GREAT_QUALITY_BAIT" = TRAIT_GREAT_QUALITY_BAIT, "TRAIT_HAUNTED" = TRAIT_HAUNTED, "TRAIT_HONKSPAMMING" = TRAIT_HONKSPAMMING, "TRAIT_INNATELY_FANTASTICAL_ITEM" = TRAIT_INNATELY_FANTASTICAL_ITEM, + "TRAIT_INSTANTLY_PROCESSES_BOULDERS" = TRAIT_INSTANTLY_PROCESSES_BOULDERS, + "TRAIT_LABOURED_BREATHING" = TRAIT_LABOURED_BREATHING, "TRAIT_MAT_TRANSMUTED" = TRAIT_MAT_TRANSMUTED, "TRAIT_MAY_CONTAIN_BLENDED_DUST" = TRAIT_MAY_CONTAIN_BLENDED_DUST, "TRAIT_NEEDS_TWO_HANDS" = TRAIT_NEEDS_TWO_HANDS, "TRAIT_NODROP" = TRAIT_NODROP, + "TRAIT_NON_IMPORTANT_SHOE_BLOCK" = TRAIT_NON_IMPORTANT_SHOE_BLOCK, "TRAIT_NO_BARCODES" = TRAIT_NO_BARCODES, + "TRAIT_NO_ORGAN_DECAY" = TRAIT_NO_ORGAN_DECAY, "TRAIT_NO_STORAGE_INSERT" = TRAIT_NO_STORAGE_INSERT, "TRAIT_NO_TELEPORT" = TRAIT_NO_TELEPORT, "TRAIT_OMNI_BAIT" = TRAIT_OMNI_BAIT, @@ -639,17 +646,11 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_T_RAY_VISIBLE" = TRAIT_T_RAY_VISIBLE, "TRAIT_UNCATCHABLE" = TRAIT_UNCATCHABLE, "TRAIT_WIELDED" = TRAIT_WIELDED, - "TRAIT_FEATHERED" = TRAIT_FEATHERED, - "TRAIT_NON_IMPORTANT_SHOE_BLOCK" = TRAIT_NON_IMPORTANT_SHOE_BLOCK, - "TRAIT_LABOURED_BREATHING" = TRAIT_LABOURED_BREATHING, - "TRAIT_ASSISTED_BREATHING" = TRAIT_ASSISTED_BREATHING, - "TRAIT_NO_ORGAN_DECAY" = TRAIT_NO_ORGAN_DECAY, /* "TRAIT_BAIT_UNCONSUMABLE" = TRAIT_BAIT_UNCONSUMABLE, */ /* "TRAIT_BAKEABLE" = TRAIT_BAKEABLE, */ /* "TRAIT_BYPASS_RANGED_ARMOR" = TRAIT_BYPASS_RANGED_ARMOR, */ /* "TRAIT_CONTRABAND_BLOCKER" = TRAIT_CONTRABAND_BLOCKER, */ /* "TRAIT_GERM_SENSITIVE" = TRAIT_GERM_SENSITIVE, */ - "TRAIT_INSTANTLY_PROCESSES_BOULDERS" = TRAIT_INSTANTLY_PROCESSES_BOULDERS, /* "TRAIT_ITEM_OBJECTIVE_BLOCKED" = TRAIT_ITEM_OBJECTIVE_BLOCKED, */ /* "TRAIT_NO_SIDE_KICK" = TRAIT_NO_SIDE_KICK, */ ), diff --git a/code/game/objects/items/gift.dm b/code/game/objects/items/gift.dm index c1a5e10a1b38..16913a80c04d 100644 --- a/code/game/objects/items/gift.dm +++ b/code/game/objects/items/gift.dm @@ -50,6 +50,7 @@ GLOBAL_LIST_EMPTY(possible_gifts) M.investigate_log("has unwrapped a present containing [I.type].", INVESTIGATE_PRESENTS) M.put_in_hands(I) I.add_fingerprint(M) + I.AddComponent(/datum/component/gift_item, M) // monkestation edit: gift item info component else M.visible_message(span_danger("Oh no! The present that [M] opened had nothing inside it!")) diff --git a/code/modules/admin/verbs/admingame.dm b/code/modules/admin/verbs/admingame.dm index 670b2c76ec76..340cc3d17faa 100644 --- a/code/modules/admin/verbs/admingame.dm +++ b/code/modules/admin/verbs/admingame.dm @@ -45,6 +45,18 @@ full_version = "[M.client.byond_version].[M.client.byond_build ? M.client.byond_build : "xxx"]" body += "
      \[Byond version: [full_version]\]
      " + // monkestation start: gift info + var/list/gifts = M.get_all_gift_contents() + var/gift_amt = length(gifts) + if(gift_amt) + body += "

      Gift items in contents:
      " + for(var/idx in 1 to gift_amt) + var/obj/item/gift = gifts[idx] + body += VV_HREF_TARGET(gift, VV_HK_EXAMINE_GIFT, "[gift.name] ([gift.type])") + if(idx < gift_amt) + body += "
      " + // monkestation end + body += "

      \[ " body += "VV - " diff --git a/monkestation/code/datums/components/gift_item.dm b/monkestation/code/datums/components/gift_item.dm new file mode 100644 index 000000000000..d6f82e9fa89a --- /dev/null +++ b/monkestation/code/datums/components/gift_item.dm @@ -0,0 +1,86 @@ +/// Simple thing that marks an items as having come from a gift. +/datum/component/gift_item + /// The ckey of the player who opened the gift. + var/ckey + /// Weakref to the mob who opened the gift. + var/datum/weakref/giftee + /// Weakref to the mob who opened the gift. + var/datum/weakref/mind + /// The (real) name of mob who opened the gift. + var/name + /// The `world.time` when the gift was opened. + var/open_world_time + /// The `world.timeofday` when the gift was opened. + var/open_timeofday + +/datum/component/gift_item/Initialize(mob/living/giftee) + if(!isitem(parent)) + stack_trace("Tried to assign [type] to a non-item") + return COMPONENT_INCOMPATIBLE + if(!isliving(giftee)) + stack_trace("Tried to assign [type] to something that wasn't a living mob!") + return COMPONENT_INCOMPATIBLE + if(!giftee.ckey) + stack_trace("Tried to assign [type] to a non-player mob!") + return COMPONENT_INCOMPATIBLE + src.ckey = giftee.ckey + src.giftee = WEAKREF(giftee) + src.mind = WEAKREF(giftee.mind) + src.name = "[giftee.mind?.name || giftee.real_name || giftee.name || "N/A"]" + src.open_world_time = world.time + src.open_timeofday = world.timeofday + +/datum/component/gift_item/Destroy(force) + giftee = null + mind = null + return ..() + +/datum/component/gift_item/RegisterWithParent() + RegisterSignal(parent, COMSIG_ATOM_EXAMINE, PROC_REF(on_examine)) + RegisterSignal(parent, COMSIG_ATOM_EXAMINE_MORE, PROC_REF(on_examine_more)) + RegisterSignal(parent, COMSIG_VV_TOPIC, PROC_REF(handle_vv_topic)) + ADD_TRAIT(parent, TRAIT_GIFT_ITEM, type) + +/datum/component/gift_item/UnregisterFromParent() + UnregisterSignal(parent, list(COMSIG_ATOM_EXAMINE, COMSIG_ATOM_EXAMINE_MORE, COMSIG_VV_TOPIC)) + REMOVE_TRAIT(parent, TRAIT_GIFT_ITEM, type) + +/datum/component/gift_item/proc/on_examine(obj/item/source, mob/examiner, list/examine_text) + SIGNAL_HANDLER + if(check_rights_for(examiner.client, R_ADMIN)) + // ensure we always target the right mob for the admin buttons + var/mob/target_mob = resolve_opener_mob() + examine_text += "" + examine_text += span_bold("\[") + span_info(" This item came from a gift opened by [span_name(name)] ([ckey]) [ADMIN_FULLMONTY_NONAME(target_mob)] ") + span_bold("\]") + examine_text += span_bold("\[") + span_info(" It was unwrapped from a gift [span_bold(DisplayTimeText(world.time - open_world_time) + " ago")], at server time [span_bold(time2text(open_timeofday, "YYYY-MM-DD hh:mm:ss"))] ") + span_bold("\]") + examine_text += "" + else if(isobserver(examiner) || HAS_TRAIT(examiner, TRAIT_PRESENT_VISION) || SSticker.current_state >= GAME_STATE_FINISHED) + examine_text += "" + examine_text += span_bold("\[") + span_info(" This item came from a gift opened by [span_name(name)] [DisplayTimeText(world.time - open_world_time)] ago ") + span_bold("\]") + examine_text += "" + +/datum/component/gift_item/proc/on_examine_more(obj/item/source, mob/examiner, list/examine_text) + SIGNAL_HANDLER + examine_text += span_info("This item seems to have been a gift!") + +/datum/component/gift_item/proc/resolve_opener_mob() as /mob + RETURN_TYPE(/mob) + var/mob/opener = giftee.resolve() + var/datum/mind/opener_mind = mind.resolve() + if(opener?.ckey == ckey) + return opener + else if(opener_mind?.current?.ckey == ckey) + return opener_mind.current + else if(GLOB.directory[ckey]) + var/client/current_client = GLOB.directory[ckey] + return current_client.mob + else + for(var/mob/mob in GLOB.mob_list) + if(mob.ckey == ckey) + return mob + +/datum/component/gift_item/proc/handle_vv_topic(datum/source, mob/user, list/href_list) + SIGNAL_HANDLER + if(href_list[VV_HK_EXAMINE_GIFT] && check_rights(R_ADMIN)) + user.examinate(parent) + return COMPONENT_VV_HANDLED diff --git a/tgstation.dme b/tgstation.dme index 12c9484b8077..830016c00216 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -469,6 +469,7 @@ #include "code\__DEFINES\~monkestation\twitch.dm" #include "code\__DEFINES\~monkestation\uplink.dm" #include "code\__DEFINES\~monkestation\virology.dm" +#include "code\__DEFINES\~monkestation\vv.dm" #include "code\__DEFINES\~monkestation\dcs\signals\signals_atom.dm" #include "code\__DEFINES\~monkestation\dcs\signals\signals_blueshift.dm" #include "code\__DEFINES\~monkestation\dcs\signals\signals_carbon.dm" @@ -5955,6 +5956,7 @@ #include "monkestation\code\datums\components\carbon_sprint.dm" #include "monkestation\code\datums\components\charge_adjuster.dm" #include "monkestation\code\datums\components\crafting.dm" +#include "monkestation\code\datums\components\gift_item.dm" #include "monkestation\code\datums\components\gps.dm" #include "monkestation\code\datums\components\irradiated.dm" #include "monkestation\code\datums\components\lock_on_cursor.dm" From 22642ac8a0b64327cf264e221b25efbbad9eb5c1 Mon Sep 17 00:00:00 2001 From: Lucy Date: Sun, 22 Dec 2024 18:57:06 -0500 Subject: [PATCH 70/81] Fire alarms no longer burn out lights (#4636) --- code/modules/power/lighting/light.dm | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/code/modules/power/lighting/light.dm b/code/modules/power/lighting/light.dm index 09c2e1fb2aa0..abef4540dd71 100644 --- a/code/modules/power/lighting/light.dm +++ b/code/modules/power/lighting/light.dm @@ -196,10 +196,10 @@ /obj/machinery/light/proc/handle_fire(area/source, new_fire) SIGNAL_HANDLER - update() + update(dont_burn_out = TRUE) // update the icon_state and luminosity of the light depending on its state -/obj/machinery/light/proc/update(trigger = TRUE) +/obj/machinery/light/proc/update(trigger = TRUE, dont_burn_out = FALSE) switch(status) if(LIGHT_BROKEN,LIGHT_BURNED,LIGHT_EMPTY) on = FALSE @@ -230,11 +230,13 @@ brightness_set = bulb_outer_range * bulb_major_emergency_brightness_mul var/matching = light && brightness_set == light.light_outer_range && power_set == light.light_power && color_set == light.light_color && FC == light.light_falloff_curve && IR == light.light_inner_range if(!matching) - switchcount++ - if( prob( min(60, (switchcount**2)*0.01) ) ) - if(trigger) + var/should_set = TRUE + if(!dont_burn_out) + switchcount++ + if(trigger && prob(min(60, (switchcount ** 2) * 0.01))) burn_out() - else + should_set = FALSE + if(should_set) use_power = ACTIVE_POWER_USE set_light( l_outer_range = brightness_set, @@ -242,7 +244,7 @@ l_power = power_set, l_falloff_curve = FC, l_color = color_set - ) + ) else if(has_emergency_power(LIGHT_EMERGENCY_POWER_USE) && !turned_off()) use_power = IDLE_POWER_USE low_power_mode = TRUE From 78a137baaffbf8e7af4f83500b842549d106870c Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 22 Dec 2024 23:57:17 +0000 Subject: [PATCH 71/81] Automatic changelog for PR #4625 [ci skip] --- html/changelogs/AutoChangeLog-pr-4625.yml | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-4625.yml diff --git a/html/changelogs/AutoChangeLog-pr-4625.yml b/html/changelogs/AutoChangeLog-pr-4625.yml new file mode 100644 index 000000000000..93bfd16bf876 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-4625.yml @@ -0,0 +1,6 @@ +author: "Absolucy" +delete-after: True +changes: + - admin: "Admins can now much more easily see which of a player's items came from a gift." + - rscadd: "Ghosts, santa, and anyone after roundend can an examine an item to see if its a gift, who opened it, and how long ago they did so." + - rscadd: "Closely examining (double-examining) an item will now tell you if it was from a gift." \ No newline at end of file From 57c42300c7d75ac7e494c35432ca9367643d8268 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 22 Dec 2024 23:57:26 +0000 Subject: [PATCH 72/81] Automatic changelog for PR #4636 [ci skip] --- html/changelogs/AutoChangeLog-pr-4636.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-4636.yml diff --git a/html/changelogs/AutoChangeLog-pr-4636.yml b/html/changelogs/AutoChangeLog-pr-4636.yml new file mode 100644 index 000000000000..6c44528767ff --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-4636.yml @@ -0,0 +1,4 @@ +author: "Absolucy" +delete-after: True +changes: + - qol: "Fire alarms no longer burn out lights." \ No newline at end of file From d22da017367ae29a2a605ebf92c45627e893ee66 Mon Sep 17 00:00:00 2001 From: Changelogs Date: Mon, 23 Dec 2024 00:08:33 +0000 Subject: [PATCH 73/81] Automatic changelog compile [ci skip] --- html/changelogs/AutoChangeLog-pr-4625.yml | 6 ------ html/changelogs/AutoChangeLog-pr-4636.yml | 4 ---- html/changelogs/archive/2024-12.yml | 9 +++++++++ 3 files changed, 9 insertions(+), 10 deletions(-) delete mode 100644 html/changelogs/AutoChangeLog-pr-4625.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-4636.yml diff --git a/html/changelogs/AutoChangeLog-pr-4625.yml b/html/changelogs/AutoChangeLog-pr-4625.yml deleted file mode 100644 index 93bfd16bf876..000000000000 --- a/html/changelogs/AutoChangeLog-pr-4625.yml +++ /dev/null @@ -1,6 +0,0 @@ -author: "Absolucy" -delete-after: True -changes: - - admin: "Admins can now much more easily see which of a player's items came from a gift." - - rscadd: "Ghosts, santa, and anyone after roundend can an examine an item to see if its a gift, who opened it, and how long ago they did so." - - rscadd: "Closely examining (double-examining) an item will now tell you if it was from a gift." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-4636.yml b/html/changelogs/AutoChangeLog-pr-4636.yml deleted file mode 100644 index 6c44528767ff..000000000000 --- a/html/changelogs/AutoChangeLog-pr-4636.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Absolucy" -delete-after: True -changes: - - qol: "Fire alarms no longer burn out lights." \ No newline at end of file diff --git a/html/changelogs/archive/2024-12.yml b/html/changelogs/archive/2024-12.yml index c35e63293239..7d60f635696a 100644 --- a/html/changelogs/archive/2024-12.yml +++ b/html/changelogs/archive/2024-12.yml @@ -378,3 +378,12 @@ Tractor Mann: - admin: Admins will no longer be told you dusted someone with power gloves when you didnt, and that you shocked someone with power gloves when you dust them. +2024-12-23: + Absolucy: + - admin: Admins can now much more easily see which of a player's items came from + a gift. + - rscadd: Ghosts, santa, and anyone after roundend can an examine an item to see + if its a gift, who opened it, and how long ago they did so. + - rscadd: Closely examining (double-examining) an item will now tell you if it was + from a gift. + - qol: Fire alarms no longer burn out lights. From 338bd96e9725cd740a1a962956e25941cc5c96f3 Mon Sep 17 00:00:00 2001 From: Shoddd <148718717+Shoddd@users.noreply.github.com> Date: Tue, 24 Dec 2024 01:25:39 -0500 Subject: [PATCH 74/81] free gbp (#4647) Co-authored-by: shodd --- .../code/modules/slimecore/crossbreeding/regenerative/effect.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/monkestation/code/modules/slimecore/crossbreeding/regenerative/effect.dm b/monkestation/code/modules/slimecore/crossbreeding/regenerative/effect.dm index f1f4878fd76b..eea062382329 100644 --- a/monkestation/code/modules/slimecore/crossbreeding/regenerative/effect.dm +++ b/monkestation/code/modules/slimecore/crossbreeding/regenerative/effect.dm @@ -93,7 +93,7 @@ ordered_wounds[1]?.remove_wound() /datum/status_effect/regenerative_extract/get_examine_text() - return "[owner.p_They()] have a subtle, gentle glow to [owner.p_their()] skin, with slime soothing [owner.p_their()] wounds." + return "[owner.p_They()] [owner.p_have()] a subtle, gentle glow to [owner.p_their()] skin, with slime soothing [owner.p_their()] wounds." /atom/movable/screen/alert/status_effect/regen_extract name = "Slime Regeneration" From 6a04546080c755893ca161c825b7e23c5f5b1d90 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 24 Dec 2024 06:26:06 +0000 Subject: [PATCH 75/81] Automatic changelog for PR #4647 [ci skip] --- html/changelogs/AutoChangeLog-pr-4647.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-4647.yml diff --git a/html/changelogs/AutoChangeLog-pr-4647.yml b/html/changelogs/AutoChangeLog-pr-4647.yml new file mode 100644 index 000000000000..3d8845591897 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-4647.yml @@ -0,0 +1,4 @@ +author: "Shoddd" +delete-after: True +changes: + - bugfix: "fixes a typo in regen extract" \ No newline at end of file From e063aa9f4e5d8635d66abd8b41087c81bdff1250 Mon Sep 17 00:00:00 2001 From: Wisemonster <87689371+Wisemonster@users.noreply.github.com> Date: Tue, 24 Dec 2024 06:20:31 -0500 Subject: [PATCH 76/81] Fix syndie base delamming (#4653) --- .../lavaland_surface_syndicate_base1/mistake_inevitable.dmm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_maps/RandomRuins/LavaRuins/lavaland_surface_syndicate_base1/mistake_inevitable.dmm b/_maps/RandomRuins/LavaRuins/lavaland_surface_syndicate_base1/mistake_inevitable.dmm index 1deee17aee2e..091c1b2f53b1 100644 --- a/_maps/RandomRuins/LavaRuins/lavaland_surface_syndicate_base1/mistake_inevitable.dmm +++ b/_maps/RandomRuins/LavaRuins/lavaland_surface_syndicate_base1/mistake_inevitable.dmm @@ -197,8 +197,8 @@ /turf/open/floor/engine, /area/ruin/syndicate_lava_base/testlab) "rX" = ( -/obj/machinery/atmospherics/components/unary/passive_vent, /obj/structure/lattice/catwalk, +/obj/machinery/atmospherics/components/unary/outlet_injector/on, /turf/template_noop, /area/ruin/syndicate_lava_base/testlab) "sa" = ( From 87c6bd0af6ca19b976d11a6dae6db3f174ff49f3 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 24 Dec 2024 11:20:54 +0000 Subject: [PATCH 77/81] Automatic changelog for PR #4653 [ci skip] --- html/changelogs/AutoChangeLog-pr-4653.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-4653.yml diff --git a/html/changelogs/AutoChangeLog-pr-4653.yml b/html/changelogs/AutoChangeLog-pr-4653.yml new file mode 100644 index 000000000000..bc65ae5d60e2 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-4653.yml @@ -0,0 +1,4 @@ +author: "Wisemonster" +delete-after: True +changes: + - bugfix: "Fixed the syndicate lavaland base delamming if they spawned with an SM" \ No newline at end of file From e26532d5014ae180d7965e9bade79c6ecd505c89 Mon Sep 17 00:00:00 2001 From: Uristthedorf <40842973+Uristthedorf@users.noreply.github.com> Date: Tue, 24 Dec 2024 03:24:00 -0800 Subject: [PATCH 78/81] Why was this there? (#4659) --- .../{objects/items/robot => robot/items}/robot_upgrades.dm | 0 tgstation.dme | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename monkestation/code/game/objects/items/{objects/items/robot => robot/items}/robot_upgrades.dm (100%) diff --git a/monkestation/code/game/objects/items/objects/items/robot/robot_upgrades.dm b/monkestation/code/game/objects/items/robot/items/robot_upgrades.dm similarity index 100% rename from monkestation/code/game/objects/items/objects/items/robot/robot_upgrades.dm rename to monkestation/code/game/objects/items/robot/items/robot_upgrades.dm diff --git a/tgstation.dme b/tgstation.dme index 830016c00216..6d7052a6722a 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -6116,10 +6116,10 @@ #include "monkestation\code\game\objects\items\guns\SRN.dm" #include "monkestation\code\game\objects\items\guns\wt_ammo.dm" #include "monkestation\code\game\objects\items\implants\hardlight.dm" -#include "monkestation\code\game\objects\items\objects\items\robot\robot_upgrades.dm" #include "monkestation\code\game\objects\items\rayne_corp\rayne_lantern.dm" #include "monkestation\code\game\objects\items\rayne_corp\rayne_mender.dm" #include "monkestation\code\game\objects\items\robot\items\hypo.dm" +#include "monkestation\code\game\objects\items\robot\items\robot_upgrades.dm" #include "monkestation\code\game\objects\items\stacks\tile_types.dm" #include "monkestation\code\game\objects\items\storage\book.dm" #include "monkestation\code\game\objects\items\storage\boxes.dm" From e02822d1d41c784b59fc2b5ca5ca3a4e954f2807 Mon Sep 17 00:00:00 2001 From: Changelogs Date: Wed, 25 Dec 2024 01:39:17 +0000 Subject: [PATCH 79/81] Automatic changelog compile [ci skip] --- html/changelogs/AutoChangeLog-pr-4647.yml | 4 ---- html/changelogs/AutoChangeLog-pr-4653.yml | 4 ---- html/changelogs/archive/2024-12.yml | 5 +++++ 3 files changed, 5 insertions(+), 8 deletions(-) delete mode 100644 html/changelogs/AutoChangeLog-pr-4647.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-4653.yml diff --git a/html/changelogs/AutoChangeLog-pr-4647.yml b/html/changelogs/AutoChangeLog-pr-4647.yml deleted file mode 100644 index 3d8845591897..000000000000 --- a/html/changelogs/AutoChangeLog-pr-4647.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Shoddd" -delete-after: True -changes: - - bugfix: "fixes a typo in regen extract" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-4653.yml b/html/changelogs/AutoChangeLog-pr-4653.yml deleted file mode 100644 index bc65ae5d60e2..000000000000 --- a/html/changelogs/AutoChangeLog-pr-4653.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Wisemonster" -delete-after: True -changes: - - bugfix: "Fixed the syndicate lavaland base delamming if they spawned with an SM" \ No newline at end of file diff --git a/html/changelogs/archive/2024-12.yml b/html/changelogs/archive/2024-12.yml index 7d60f635696a..d040f0dd1b7d 100644 --- a/html/changelogs/archive/2024-12.yml +++ b/html/changelogs/archive/2024-12.yml @@ -387,3 +387,8 @@ - rscadd: Closely examining (double-examining) an item will now tell you if it was from a gift. - qol: Fire alarms no longer burn out lights. +2024-12-25: + Shoddd: + - bugfix: fixes a typo in regen extract + Wisemonster: + - bugfix: Fixed the syndicate lavaland base delamming if they spawned with an SM From f24cb08096d9512121c68872f835b7035155c002 Mon Sep 17 00:00:00 2001 From: Lucy Date: Wed, 25 Dec 2024 14:46:50 -0500 Subject: [PATCH 80/81] 516 prep: fix chat window z-fighting and tgui-say escape key (#4615) * 516: fix chat window z-fighting and tgui-say escape key Port of https://github.com/ParadiseSS13/Paradise/pull/27676, which in turn is a port of https://github.com/VOREStation/VOREStation/pull/16713 and https://github.com/VOREStation/VOREStation/pull/16734 * revert a bad fix * iffy but workable fix for topic spam bug * possible true fix? * some fixes * add a 516 beta notic * remove 515 experiment stuff * Port my implementation from https://github.com/tgstation/tgstation/pull/88624 * fix scrollbar ports https://github.com/tgstation/tgstation/pull/88617 * update experiments.dm to what /tg/ is doing * remove those outdated comments * Revert "fix scrollbar" (lmao UIs are huge) This reverts commit 7c43266ff84c532821559301281035dccee10fee. * update these two --- code/_experiments.dm | 11 +- code/controllers/subsystem/statpanel.dm | 3 +- code/modules/admin/holder2.dm | 2 +- .../modules/asset_cache/asset_cache_client.dm | 5 +- code/modules/asset_cache/validate_assets.html | 4 +- code/modules/client/client_procs.dm | 6 +- code/modules/tgui_panel/external.dm | 14 +- interface/skin.dmf | 42 +- tgui/global.d.ts | 19 + tgui/packages/common/keys.ts | 18 +- .../common/{storage.js => storage.ts} | 88 +- tgui/packages/tgui-panel/chat/renderer.jsx | 6 +- tgui/packages/tgui-panel/index.jsx | 10 +- tgui/packages/tgui-say/TguiSay.tsx | 9 +- .../tgui/interfaces/KeyComboModal.tsx | 8 +- tgui/public/tgui.html | 1315 +++++++++-------- 16 files changed, 849 insertions(+), 711 deletions(-) rename tgui/packages/common/{storage.js => storage.ts} (62%) diff --git a/code/_experiments.dm b/code/_experiments.dm index ef2240406ed2..c7fdad2f7887 100644 --- a/code/_experiments.dm +++ b/code/_experiments.dm @@ -3,11 +3,8 @@ // Any flag you see here can be flipped with the `-D` CLI argument. // For example, if you want to enable EXPERIMENT_MY_COOL_FEATURE, compile with -DEXPERIMENT_MY_COOL_FEATURE -// EXPERIMENT_515_QDEL_HARD_REFERENCE -// - Hold a hard reference for qdeleted items, and check ref_count, rather than using refs. Requires 515+. - -// EXPERIMENT_515_DONT_CACHE_REF -// - Avoids `text_ref` caching, aided by improvements to ref() speed in 515. +// EXPERIMENT_MY_COOL_FEATURE +// - Does something really cool, just so neat, absolutely banging, gaming and chill #if DM_VERSION < 515 @@ -20,6 +17,6 @@ #define EXPERIMENT_MY_COOL_FEATURE #endif -#if DM_VERSION >= 516 - #error "Remove all 515 experiments" +#if DM_VERSION >= 517 + #error "Remove all 516 experiments" #endif diff --git a/code/controllers/subsystem/statpanel.dm b/code/controllers/subsystem/statpanel.dm index 08a26d9a79cf..3dba3b00faab 100644 --- a/code/controllers/subsystem/statpanel.dm +++ b/code/controllers/subsystem/statpanel.dm @@ -99,11 +99,12 @@ SUBSYSTEM_DEF(statpanels) return /datum/controller/subsystem/statpanels/proc/set_status_tab(client/target) + var/static/list/beta_notice = list("", "You are on the BYOND 516 beta, various UIs and such may be broken!", "Please report issues, and switch back to BYOND 515 if things are causing too many issues for you.") if(!global_data)//statbrowser hasnt fired yet and we were called from immediate_send_stat_data() return target.stat_panel.send_message("update_stat", list( - "global_data" = global_data, + "global_data" = (target.byond_version < 516) ? global_data : (global_data + beta_notice), "ping_str" = "Ping: [round(target.lastping, 1)]ms (Average: [round(target.avgping, 1)]ms)", "other_str" = target.mob?.get_status_tab_items(), )) diff --git a/code/modules/admin/holder2.dm b/code/modules/admin/holder2.dm index 57179bd89bfc..94fde875336c 100644 --- a/code/modules/admin/holder2.dm +++ b/code/modules/admin/holder2.dm @@ -407,7 +407,7 @@ GLOBAL_PROTECT(href_token) /datum/admins/proc/try_give_devtools() if(!(rank_flags() & R_DEBUG) || owner.byond_version < 516) return - winset(owner, null, "browser-options=byondstorage,find,devtools") + winset(owner, null, "browser-options=byondstorage,find,refresh,devtools") /datum/admins/proc/try_give_profiling() if (CONFIG_GET(flag/forbid_admin_profiling)) diff --git a/code/modules/asset_cache/asset_cache_client.dm b/code/modules/asset_cache/asset_cache_client.dm index 3cff8cb41f3e..cf786de09e8b 100644 --- a/code/modules/asset_cache/asset_cache_client.dm +++ b/code/modules/asset_cache/asset_cache_client.dm @@ -36,7 +36,10 @@ var/job = ++last_asset_job var/t = 0 var/timeout_time = timeout - src << browse({""}, "window=asset_cache_browser&file=asset_cache_send_verify.htm") + if(byond_version < 516) + src << browse({""}, "window=asset_cache_browser&file=asset_cache_send_verify.htm") + else + src << browse({""}, "window=asset_cache_browser&file=asset_cache_send_verify.htm") while(!completed_asset_jobs["[job]"] && t < timeout_time) // Reception is handled in Topic() stoplag(1) // Lock up the caller until this is received. diff --git a/code/modules/asset_cache/validate_assets.html b/code/modules/asset_cache/validate_assets.html index 78bcbb92a1ab..70fdca8a9d77 100644 --- a/code/modules/asset_cache/validate_assets.html +++ b/code/modules/asset_cache/validate_assets.html @@ -8,7 +8,7 @@ //this is used over window.location because window.location has a character limit in IE. function sendbyond(text) { var xhr = new XMLHttpRequest(); - xhr.open('GET', '?'+text, true); + xhr.open('GET', 'byond://?' + text, true); xhr.send(null); } var xhr = new XMLHttpRequest(); @@ -24,6 +24,6 @@ }; xhr.send(null); - + diff --git a/code/modules/client/client_procs.dm b/code/modules/client/client_procs.dm index be80860d23e1..f5afc598e84d 100644 --- a/code/modules/client/client_procs.dm +++ b/code/modules/client/client_procs.dm @@ -225,9 +225,6 @@ GLOBAL_LIST_INIT(blacklisted_builds, list( /////////// /client/New(TopicData) - if(byond_version >= 516) // Enable 516 compat browser storage mechanisms - winset(src, "", "browser-options=byondstorage,find") - var/tdata = TopicData //save this for later use TopicData = null //Prevent calls to client.Topic from connect @@ -237,6 +234,9 @@ GLOBAL_LIST_INIT(blacklisted_builds, list( GLOB.clients += src GLOB.directory[ckey] = src + if(byond_version >= 516) + winset(src, null, list("browser-options" = "find,refresh,byondstorage")) + // Instantiate stat panel stat_panel = new(src, "statbrowser") stat_panel.subscribe(src, PROC_REF(on_stat_panel_message)) diff --git a/code/modules/tgui_panel/external.dm b/code/modules/tgui_panel/external.dm index 692244a6e80d..e48ddeb22390 100644 --- a/code/modules/tgui_panel/external.dm +++ b/code/modules/tgui_panel/external.dm @@ -19,27 +19,19 @@ // Failed to fix, using tgalert as fallback action = tgalert(src, "Did that work?", "", "Yes", "No, switch to old ui") if (action == "No, switch to old ui") - winset(src, "output", "on-show=&is-disabled=0&is-visible=1") - winset(src, "browseroutput", "is-disabled=1;is-visible=0") + winset(src, "legacy_output_selector", "left=output_legacy") log_tgui(src, "Failed to fix.", context = "verb/fix_tgui_panel") /client/proc/nuke_chat() // Catch all solution (kick the whole thing in the pants) - winset(src, "output", "on-show=&is-disabled=0&is-visible=1") - winset(src, "browseroutput", "is-disabled=1;is-visible=0") + winset(src, "legacy_output_selector", "left=output_legacy") if(!tgui_panel || !istype(tgui_panel)) log_tgui(src, "tgui_panel datum is missing", context = "verb/fix_tgui_panel") tgui_panel = new(src) tgui_panel.initialize(force = TRUE) // Force show the panel to see if there are any errors - winset(src, "output", "is-disabled=1&is-visible=0") - winset(src, "browseroutput", "is-disabled=0;is-visible=1") - if(byond_version >= 516) - var/list/options = list("byondstorage", "find") - if(check_rights_for(src, R_DEBUG)) - options += "devtools" - winset(src, null, "browser-options=[options.Join(",")]") + winset(src, "legacy_output_selector", "left=output_browser") /client/verb/refresh_tgui() set name = "Refresh TGUI" diff --git a/interface/skin.dmf b/interface/skin.dmf index 9a4704e95120..d46f5c55b184 100644 --- a/interface/skin.dmf +++ b/interface/skin.dmf @@ -226,7 +226,7 @@ window "infowindow" window "outputwindow" elem "outputwindow" type = MAIN - pos = 281,0 + pos = 0,0 size = 640x480 anchor1 = -1,-1 anchor2 = -1,-1 @@ -285,15 +285,26 @@ window "outputwindow" anchor2 = -1,-1 is-visible = false saved-params = "" - elem "browseroutput" - type = BROWSER + elem "legacy_output_selector" + type = CHILD pos = 0,0 size = 640x456 anchor1 = 0,0 anchor2 = 100,100 - is-visible = false - is-disabled = true - saved-params = "" + saved-params = "splitter" + left = "output_legacy" + is-vert = false + +window "output_legacy" + elem "output_legacy" + type = MAIN + pos = 0,0 + size = 640x456 + anchor1 = -1,-1 + anchor2 = -1,-1 + background-color = none + saved-params = "pos;size;is-minimized;is-maximized" + is-pane = true elem "output" type = OUTPUT pos = 0,0 @@ -301,6 +312,25 @@ window "outputwindow" anchor1 = 0,0 anchor2 = 100,100 is-default = true + saved-params = "max-lines" + +window "output_browser" + elem "output_browser" + type = MAIN + pos = 0,0 + size = 640x456 + anchor1 = -1,-1 + anchor2 = -1,-1 + background-color = none + saved-params = "pos;size;is-minimized;is-maximized" + is-pane = true + elem "browseroutput" + type = BROWSER + pos = 0,0 + size = 640x456 + anchor1 = 0,0 + anchor2 = 100,100 + background-color = none saved-params = "" window "popupwindow" diff --git a/tgui/global.d.ts b/tgui/global.d.ts index b1697d5fcdbc..b64bd4006dbe 100644 --- a/tgui/global.d.ts +++ b/tgui/global.d.ts @@ -51,6 +51,11 @@ type ByondType = { */ TRIDENT: number | null; + /** + * Version of Blink engine of WebView2. Null if N/A. + */ + BLINK: number | null; + /** * True if browser is IE8 or lower. */ @@ -162,6 +167,11 @@ type ByondType = { */ parseJson(text: string): any; + /** + * Downloads a blob, platform-agnostic + */ + saveBlob(blob: Blob, filename: string, ext: string): void; + /** * Sends a message to `/datum/tgui_window` which hosts this window instance. */ @@ -205,4 +215,13 @@ interface Window { Byond: ByondType; __store__: Store; __augmentStack__: (store: Store) => StackAugmentor; + + // IE IndexedDB stuff. + msIndexedDB: IDBFactory; + msIDBTransaction: IDBTransaction; + + // 516 byondstorage API. + hubStorage: Storage; + domainStorage: Storage; + serverStorage: Storage; } diff --git a/tgui/packages/common/keys.ts b/tgui/packages/common/keys.ts index 61b79992b486..abbd6b49bb70 100644 --- a/tgui/packages/common/keys.ts +++ b/tgui/packages/common/keys.ts @@ -25,7 +25,8 @@ export enum KEY { Down = 'Down', End = 'End', Enter = 'Enter', - Escape = 'Esc', + Esc = 'Esc', + Escape = 'Escape', Home = 'Home', Insert = 'Insert', Left = 'Left', @@ -37,3 +38,18 @@ export enum KEY { Tab = 'Tab', Up = 'Up', } + +/** + * ### isEscape + * + * Checks if the user has hit the 'ESC' key on their keyboard. + * There's a weirdness in BYOND where this could be either the string + * 'Escape' or 'Esc' depending on the browser. This function handles + * both cases. + * + * @param key - the key to check, typically from event.key + * @returns true if key is Escape or Esc, false otherwise + */ +export const isEscape = (key: string): boolean => { + return key === KEY.Esc || key === KEY.Escape; +}; diff --git a/tgui/packages/common/storage.js b/tgui/packages/common/storage.ts similarity index 62% rename from tgui/packages/common/storage.js rename to tgui/packages/common/storage.ts index 9a47ecc2b54c..b2564acf36dc 100644 --- a/tgui/packages/common/storage.js +++ b/tgui/packages/common/storage.ts @@ -10,6 +10,11 @@ export const IMPL_MEMORY = 0; export const IMPL_HUB_STORAGE = 1; export const IMPL_INDEXED_DB = 2; +type StorageImplementation = + | typeof IMPL_MEMORY + | typeof IMPL_HUB_STORAGE + | typeof IMPL_INDEXED_DB; + const INDEXED_DB_VERSION = 1; const INDEXED_DB_NAME = 'tgui'; const INDEXED_DB_STORE_NAME = 'storage-v1'; @@ -17,7 +22,15 @@ const INDEXED_DB_STORE_NAME = 'storage-v1'; const READ_ONLY = 'readonly'; const READ_WRITE = 'readwrite'; -const testGeneric = (testFn) => () => { +type StorageBackend = { + impl: StorageImplementation; + get(key: string): Promise; + set(key: string, value: any): Promise; + remove(key: string): Promise; + clear(): Promise; +}; + +const testGeneric = (testFn: () => boolean) => (): boolean => { try { return Boolean(testFn()); } catch { @@ -26,69 +39,76 @@ const testGeneric = (testFn) => () => { }; const testHubStorage = testGeneric( - () => window.hubStorage && window.hubStorage.getItem, + () => window.hubStorage && !!window.hubStorage.getItem, ); // TODO: Remove with 516 // prettier-ignore const testIndexedDb = testGeneric(() => ( (window.indexedDB || window.msIndexedDB) - && (window.IDBTransaction || window.msIDBTransaction) + && !!(window.IDBTransaction || window.msIDBTransaction) )); -class MemoryBackend { +class MemoryBackend implements StorageBackend { + private store: Record; + public impl: StorageImplementation; + constructor() { this.impl = IMPL_MEMORY; this.store = {}; } - async get(key) { + async get(key: string): Promise { return this.store[key]; } - async set(key, value) { + async set(key: string, value: any): Promise { this.store[key] = value; } - async remove(key) { + async remove(key: string): Promise { this.store[key] = undefined; } - async clear() { + async clear(): Promise { this.store = {}; } } -class HubStorageBackend { +class HubStorageBackend implements StorageBackend { + public impl: StorageImplementation; + constructor() { this.impl = IMPL_HUB_STORAGE; } - async get(key) { + async get(key: string): Promise { const value = await window.hubStorage.getItem(key); if (typeof value === 'string') { return JSON.parse(value); } + return undefined; } - set(key, value) { + async set(key: string, value: any): Promise { window.hubStorage.setItem(key, JSON.stringify(value)); } - remove(key) { + async remove(key: string): Promise { window.hubStorage.removeItem(key); } - clear() { + async clear(): Promise { window.hubStorage.clear(); } } -class IndexedDbBackend { - // TODO: Remove with 516 +class IndexedDbBackend implements StorageBackend { + public impl: StorageImplementation; + public dbPromise: Promise; + constructor() { this.impl = IMPL_INDEXED_DB; - /** @type {Promise} */ this.dbPromise = new Promise((resolve, reject) => { const indexedDB = window.indexedDB || window.msIndexedDB; const req = indexedDB.open(INDEXED_DB_NAME, INDEXED_DB_VERSION); @@ -96,7 +116,12 @@ class IndexedDbBackend { try { req.result.createObjectStore(INDEXED_DB_STORE_NAME); } catch (err) { - reject(new Error('Failed to upgrade IDB: ' + req.error)); + reject( + new Error( + 'Failed to upgrade IDB: ' + + (err instanceof Error ? err.message : String(err)), + ), + ); } }; req.onsuccess = () => resolve(req.result); @@ -106,14 +131,14 @@ class IndexedDbBackend { }); } - async getStore(mode) { - // prettier-ignore - return this.dbPromise.then((db) => db + private async getStore(mode: IDBTransactionMode): Promise { + const db = await this.dbPromise; + return db .transaction(INDEXED_DB_STORE_NAME, mode) - .objectStore(INDEXED_DB_STORE_NAME)); + .objectStore(INDEXED_DB_STORE_NAME); } - async get(key) { + async get(key: string): Promise { const store = await this.getStore(READ_ONLY); return new Promise((resolve, reject) => { const req = store.get(key); @@ -122,19 +147,19 @@ class IndexedDbBackend { }); } - async set(key, value) { + async set(key: string, value: any): Promise { // NOTE: We deliberately make this operation transactionless const store = await this.getStore(READ_WRITE); store.put(value, key); } - async remove(key) { + async remove(key: string): Promise { // NOTE: We deliberately make this operation transactionless const store = await this.getStore(READ_WRITE); store.delete(key); } - async clear() { + async clear(): Promise { // NOTE: We deliberately make this operation transactionless const store = await this.getStore(READ_WRITE); store.clear(); @@ -145,7 +170,10 @@ class IndexedDbBackend { * Web Storage Proxy object, which selects the best backend available * depending on the environment. */ -class StorageProxy { +class StorageProxy implements StorageBackend { + private backendPromise: Promise; + public impl: StorageImplementation = IMPL_MEMORY; + constructor() { this.backendPromise = (async () => { if (!Byond.TRIDENT && testHubStorage()) { @@ -166,22 +194,22 @@ class StorageProxy { })(); } - async get(key) { + async get(key: string): Promise { const backend = await this.backendPromise; return backend.get(key); } - async set(key, value) { + async set(key: string, value: any): Promise { const backend = await this.backendPromise; return backend.set(key, value); } - async remove(key) { + async remove(key: string): Promise { const backend = await this.backendPromise; return backend.remove(key); } - async clear() { + async clear(): Promise { const backend = await this.backendPromise; return backend.clear(); } diff --git a/tgui/packages/tgui-panel/chat/renderer.jsx b/tgui/packages/tgui-panel/chat/renderer.jsx index fa04d94f38c6..e19c7471888c 100644 --- a/tgui/packages/tgui-panel/chat/renderer.jsx +++ b/tgui/packages/tgui-panel/chat/renderer.jsx @@ -80,7 +80,7 @@ const createReconnectedNode = () => { const handleImageError = (e) => { setTimeout(() => { /** @type {HTMLImageElement} */ - const node = Byond.BLINK !== null ? e : e.target; + const node = e.target; const attempts = parseInt(node.getAttribute('data-reload-n'), 10) || 0; if (attempts >= IMAGE_RETRY_LIMIT) { logger.error(`failed to load an image after ${attempts} attempts`); @@ -612,13 +612,13 @@ class ChatRenderer { + '\n' + '\n'; // Create and send a nice blob - const blob = new Blob([pageHtml]); + const blob = new Blob([pageHtml], { type: 'text/plain' }); const timestamp = new Date() .toISOString() .substring(0, 19) .replace(/[-:]/g, '') .replace('T', '-'); - window.navigator.msSaveBlob(blob, `ss13-chatlog-${timestamp}.html`); + Byond.saveBlob(blob, `ss13-chatlog-${timestamp}.html`, '.html'); } } diff --git a/tgui/packages/tgui-panel/index.jsx b/tgui/packages/tgui-panel/index.jsx index 95559291ee2d..9f43a3091e25 100644 --- a/tgui/packages/tgui-panel/index.jsx +++ b/tgui/packages/tgui-panel/index.jsx @@ -78,14 +78,8 @@ const setupApp = () => { Byond.subscribe((type, payload) => store.dispatch({ type, payload })); // Unhide the panel - Byond.winset('output', { - 'is-visible': false, - }); - Byond.winset('browseroutput', { - 'is-visible': true, - 'is-disabled': false, - pos: '0x0', - size: '0x0', + Byond.winset('legacy_output_selector', { + left: 'output_browser', }); // Resize the panel to match the non-browser output diff --git a/tgui/packages/tgui-say/TguiSay.tsx b/tgui/packages/tgui-say/TguiSay.tsx index 0a1c9c7e4efa..aee0d12a5cf5 100644 --- a/tgui/packages/tgui-say/TguiSay.tsx +++ b/tgui/packages/tgui-say/TguiSay.tsx @@ -6,7 +6,7 @@ import { byondMessages } from './timers'; import { dragStartHandler } from 'tgui/drag'; import { windowOpen, windowClose, windowSet } from './helpers'; import { BooleanLike } from 'common/react'; -import { KEY } from 'common/keys'; +import { isEscape, KEY } from 'common/keys'; type ByondOpen = { channel: Channel; @@ -252,9 +252,10 @@ export class TguiSay extends Component<{}, State> { this.handleIncrementChannel(); break; - case KEY.Escape: - this.handleClose(); - break; + default: + if (isEscape(event.key)) { + this.handleClose(); + } } } diff --git a/tgui/packages/tgui/interfaces/KeyComboModal.tsx b/tgui/packages/tgui/interfaces/KeyComboModal.tsx index 6d618fe01214..515f7162fb3f 100644 --- a/tgui/packages/tgui/interfaces/KeyComboModal.tsx +++ b/tgui/packages/tgui/interfaces/KeyComboModal.tsx @@ -1,4 +1,4 @@ -import { KEY } from 'common/keys'; +import { KEY, isEscape } from 'common/keys'; import { useBackend, useLocalState } from '../backend'; import { Autofocus, Box, Button, Section, Stack } from '../components'; import { Window } from '../layouts'; @@ -18,7 +18,7 @@ const isStandardKey = (event: KeyboardEvent): boolean => { event.key !== KEY.Alt && event.key !== KEY.Control && event.key !== KEY.Shift && - event.key !== KEY.Escape + !isEscape(event.key) ); }; @@ -93,7 +93,7 @@ export const KeyComboModal = (props) => { if (event.key === KEY.Enter) { act('submit', { entry: input }); } - if (event.key === KEY.Escape) { + if (isEscape(event.key)) { act('cancel'); } return; @@ -105,7 +105,7 @@ export const KeyComboModal = (props) => { setValue(formatKeyboardEvent(event)); setBinding(false); return; - } else if (event.key === KEY.Escape) { + } else if (isEscape(event.key)) { setValue(init_value); setBinding(false); return; diff --git a/tgui/public/tgui.html b/tgui/public/tgui.html index 7dded63eee27..8937a9443bc4 100644 --- a/tgui/public/tgui.html +++ b/tgui/public/tgui.html @@ -1,673 +1,730 @@ + - - - - - - - - - + + - - + + + + - - - - - - - - -
      - - -
      - - - A fatal exception has occurred at 002B:C562F1B7 in TGUI. The current - application will be terminated. Please remain calm. Get to the nearest - NTNet workstation and send the copy of the following stack trace to: - https://github.com/Monkestation/Monkestation2.0/. Thank you for your cooperation. - -
      - -
      - -