From d3a84adf829d726ebd0b803418ae732dd5c19e34 Mon Sep 17 00:00:00 2001 From: "tgstation-ci[bot]" <179393467+tgstation-ci[bot]@users.noreply.github.com> Date: Thu, 28 Nov 2024 01:46:43 +0000 Subject: [PATCH 001/149] Automatic changelog compile [ci skip] --- html/changelogs/AutoChangeLog-pr-88144.yml | 8 ------- html/changelogs/AutoChangeLog-pr-88207.yml | 4 ---- html/changelogs/AutoChangeLog-pr-88212.yml | 4 ---- html/changelogs/AutoChangeLog-pr-88217.yml | 4 ---- html/changelogs/AutoChangeLog-pr-88218.yml | 4 ---- html/changelogs/AutoChangeLog-pr-88219.yml | 4 ---- html/changelogs/AutoChangeLog-pr-88220.yml | 4 ---- html/changelogs/AutoChangeLog-pr-88221.yml | 4 ---- html/changelogs/AutoChangeLog-pr-88223.yml | 4 ---- html/changelogs/AutoChangeLog-pr-88225.yml | 6 ----- html/changelogs/archive/2024-11.yml | 28 ++++++++++++++++++++++ 11 files changed, 28 insertions(+), 46 deletions(-) delete mode 100644 html/changelogs/AutoChangeLog-pr-88144.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-88207.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-88212.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-88217.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-88218.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-88219.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-88220.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-88221.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-88223.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-88225.yml diff --git a/html/changelogs/AutoChangeLog-pr-88144.yml b/html/changelogs/AutoChangeLog-pr-88144.yml deleted file mode 100644 index 541f128a1d81f..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-88144.yml +++ /dev/null @@ -1,8 +0,0 @@ -author: "Ben10Omintrix" -delete-after: True -changes: - - bugfix: "repairbots no longer get flashed by their own welder" - - bugfix: "repairbots no longer break glass tables they step on" - - bugfix: "repairbots can no longer flush their own welders" - - bugfix: "fixes some runtimes when emagged repairbots try to deconstruct things" - - bugfix: "fixes sentient repairbots not being able to see or remove their material counts" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-88207.yml b/html/changelogs/AutoChangeLog-pr-88207.yml deleted file mode 100644 index 627db590cf4dd..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-88207.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Absolucy" -delete-after: True -changes: - - bugfix: "ACTUALLY allow dot radio prefixes to also work with the tgui-say radio prefix display." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-88212.yml b/html/changelogs/AutoChangeLog-pr-88212.yml deleted file mode 100644 index d8eeded5b519f..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-88212.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "ValuedEmployee" -delete-after: True -changes: - - rscadd: "New purr and meow emotes for players with felinid tongues" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-88217.yml b/html/changelogs/AutoChangeLog-pr-88217.yml deleted file mode 100644 index 54f0d00580506..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-88217.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Mothblocks" -delete-after: True -changes: - - qol: "IV drips now create a beam from their spout to your body, and will visually pull you closer." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-88218.yml b/html/changelogs/AutoChangeLog-pr-88218.yml deleted file mode 100644 index aa138e0ae745f..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-88218.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Melbert" -delete-after: True -changes: - - bugfix: "Maybe fixes some organ manipulation bugs" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-88219.yml b/html/changelogs/AutoChangeLog-pr-88219.yml deleted file mode 100644 index 563f6d175141a..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-88219.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Melbert" -delete-after: True -changes: - - bugfix: "Frozen slimes can't latch on to you (but they can still attack you technically)" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-88220.yml b/html/changelogs/AutoChangeLog-pr-88220.yml deleted file mode 100644 index 9e84257f5f611..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-88220.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Melbert" -delete-after: True -changes: - - bugfix: "Mulebot wire hacking is less fourth wall breaking" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-88221.yml b/html/changelogs/AutoChangeLog-pr-88221.yml deleted file mode 100644 index 6c78766a75c52..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-88221.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Melbert" -delete-after: True -changes: - - bugfix: "Stuff like the SM exploding will no longer output to your OOC tab" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-88223.yml b/html/changelogs/AutoChangeLog-pr-88223.yml deleted file mode 100644 index 9d9c5dcb84022..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-88223.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "SmArtKar" -delete-after: True -changes: - - bugfix: "Fixed colossus committing suicide on a regular basis" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-88225.yml b/html/changelogs/AutoChangeLog-pr-88225.yml deleted file mode 100644 index f1b2dddd24e1c..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-88225.yml +++ /dev/null @@ -1,6 +0,0 @@ -author: "SyncIt21" -delete-after: True -changes: - - bugfix: "chainsaw is not invisible when turned off in hand" - - bugfix: "chainsaw won't play ping sound when turned on" - - bugfix: "mounted chainsaw has a new animated sprite when turned on & won't go invisible in hand" \ No newline at end of file diff --git a/html/changelogs/archive/2024-11.yml b/html/changelogs/archive/2024-11.yml index f01bf01ffa3c6..0e217ba10baf1 100644 --- a/html/changelogs/archive/2024-11.yml +++ b/html/changelogs/archive/2024-11.yml @@ -980,3 +980,31 @@ - bugfix: Brain transplants work again carlarctg: - spellcheck: Fixes a typo in legionnaire abilities +2024-11-28: + Absolucy: + - bugfix: ACTUALLY allow dot radio prefixes to also work with the tgui-say radio + prefix display. + Ben10Omintrix: + - bugfix: repairbots no longer get flashed by their own welder + - bugfix: repairbots no longer break glass tables they step on + - bugfix: repairbots can no longer flush their own welders + - bugfix: fixes some runtimes when emagged repairbots try to deconstruct things + - bugfix: fixes sentient repairbots not being able to see or remove their material + counts + Melbert: + - bugfix: Frozen slimes can't latch on to you (but they can still attack you technically) + - bugfix: Maybe fixes some organ manipulation bugs + - bugfix: Mulebot wire hacking is less fourth wall breaking + - bugfix: Stuff like the SM exploding will no longer output to your OOC tab + Mothblocks: + - qol: IV drips now create a beam from their spout to your body, and will visually + pull you closer. + SmArtKar: + - bugfix: Fixed colossus committing suicide on a regular basis + SyncIt21: + - bugfix: chainsaw is not invisible when turned off in hand + - bugfix: chainsaw won't play ping sound when turned on + - bugfix: mounted chainsaw has a new animated sprite when turned on & won't go invisible + in hand + ValuedEmployee: + - rscadd: New purr and meow emotes for players with felinid tongues From b7c8a0243c48ac2413a7e04fd36470c6e00b04ab Mon Sep 17 00:00:00 2001 From: oranges Date: Thu, 28 Nov 2024 21:18:21 +1300 Subject: [PATCH 002/149] Teleporting while leaning now makes you fall on your face (#88215) Co-authored-by: MrMelbert <51863163+MrMelbert@users.noreply.github.com> --- code/datums/components/leanable.dm | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/code/datums/components/leanable.dm b/code/datums/components/leanable.dm index 3d2a4e0b73e5b..b95fd734ad043 100644 --- a/code/datums/components/leanable.dm +++ b/code/datums/components/leanable.dm @@ -86,19 +86,29 @@ COMSIG_MOB_CLIENT_PRE_MOVE, COMSIG_LIVING_DISARM_HIT, COMSIG_LIVING_GET_PULLED, - COMSIG_MOVABLE_TELEPORTING, ), PROC_REF(stop_leaning)) + + RegisterSignal(src, COMSIG_MOVABLE_TELEPORTED, PROC_REF(teleport_away_while_leaning)) RegisterSignal(src, COMSIG_ATOM_POST_DIR_CHANGE, PROC_REF(lean_dir_changed)) update_fov() +/// You fall on your face if you get teleported while leaning +/mob/living/proc/teleport_away_while_leaning() + SIGNAL_HANDLER + // Make sure we unregister signal handlers and reset animation + stop_leaning() + // -1000 aura + visible_message(span_notice("[src] falls flat on [p_their()] face from losing [p_their()] balance!"), span_warning("You fall suddenly as the object you were leaning on vanishes from contact with you!")) + Knockdown(3 SECONDS) + /mob/living/proc/stop_leaning() SIGNAL_HANDLER UnregisterSignal(src, list( COMSIG_MOB_CLIENT_PRE_MOVE, COMSIG_LIVING_DISARM_HIT, COMSIG_LIVING_GET_PULLED, - COMSIG_MOVABLE_TELEPORTING, COMSIG_ATOM_POST_DIR_CHANGE, + COMSIG_MOVABLE_TELEPORTED, )) animate(src, 0.2 SECONDS, pixel_x = base_pixel_x + body_position_pixel_x_offset, pixel_y = base_pixel_y + body_position_pixel_y_offset) remove_traits(list(TRAIT_UNDENSE, TRAIT_EXPANDED_FOV), LEANING_TRAIT) From c55a4c4d6fb5f600f3ba498e360c0b26b07edf7d Mon Sep 17 00:00:00 2001 From: "tgstation-ci[bot]" <179393467+tgstation-ci[bot]@users.noreply.github.com> Date: Thu, 28 Nov 2024 08:18:41 +0000 Subject: [PATCH 003/149] Automatic changelog for PR #88215 [ci skip] --- html/changelogs/AutoChangeLog-pr-88215.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-88215.yml diff --git a/html/changelogs/AutoChangeLog-pr-88215.yml b/html/changelogs/AutoChangeLog-pr-88215.yml new file mode 100644 index 0000000000000..cb16936a80f81 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-88215.yml @@ -0,0 +1,4 @@ +author: "oranges" +delete-after: True +changes: + - rscadd: "Teleporting a leaning person will now make them fall over" \ No newline at end of file From d2e709d90d8862ea895bb9ff43abf79b0a32d8e9 Mon Sep 17 00:00:00 2001 From: Roxy <75404941+TealSeer@users.noreply.github.com> Date: Thu, 28 Nov 2024 03:53:55 -0500 Subject: [PATCH 004/149] Fix missing returns in limb dislocation treatment code (#88234) --- code/datums/wounds/bones.dm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/code/datums/wounds/bones.dm b/code/datums/wounds/bones.dm index 6b1e16543d7ac..830d128cddce5 100644 --- a/code/datums/wounds/bones.dm +++ b/code/datums/wounds/bones.dm @@ -347,7 +347,7 @@ user.visible_message(span_danger("[user] begins [scanned ? "expertly" : ""] resetting [victim]'s [limb.plaintext_zone] with [I]."), span_notice("You begin resetting [victim]'s [limb.plaintext_zone] with [I][scanned ? ", keeping the holo-image's indications in mind" : ""]...")) if(!do_after(user, treatment_delay, target = victim, extra_checks=CALLBACK(src, PROC_REF(still_exists)))) - return + return TRUE if(victim == user) limb.receive_damage(brute=15, wound_bonus=CANT_WOUND) @@ -359,6 +359,7 @@ victim.emote("scream") qdel(src) + return TRUE /* Severe (Hairline Fracture) From 03a9d25d6d8e836f7e3ee452a72692b70942ff84 Mon Sep 17 00:00:00 2001 From: "tgstation-ci[bot]" <179393467+tgstation-ci[bot]@users.noreply.github.com> Date: Thu, 28 Nov 2024 08:54:15 +0000 Subject: [PATCH 005/149] Automatic changelog for PR #88234 [ci skip] --- html/changelogs/AutoChangeLog-pr-88234.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-88234.yml diff --git a/html/changelogs/AutoChangeLog-pr-88234.yml b/html/changelogs/AutoChangeLog-pr-88234.yml new file mode 100644 index 0000000000000..0e7c068795cf9 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-88234.yml @@ -0,0 +1,4 @@ +author: "TealSeer" +delete-after: True +changes: + - bugfix: "Using a bonesetter to correct a dislocated limb should no longer cause you to hit the patient with it too." \ No newline at end of file From 3114566f5b399a251d2cd661f997e735e973440f Mon Sep 17 00:00:00 2001 From: necromanceranne <40847847+necromanceranne@users.noreply.github.com> Date: Thu, 28 Nov 2024 19:55:26 +1100 Subject: [PATCH 006/149] Prevents bounty pads from sending holographic and abstract items. Tidies the code a bit. (#88242) Co-authored-by: MrMelbert <51863163+MrMelbert@users.noreply.github.com> --- code/game/machinery/civilian_bounties.dm | 28 +++++++++++++++++------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/code/game/machinery/civilian_bounties.dm b/code/game/machinery/civilian_bounties.dm index d8c8a98caef77..dcd967e082e5f 100644 --- a/code/game/machinery/civilian_bounties.dm +++ b/code/game/machinery/civilian_bounties.dm @@ -84,10 +84,16 @@ return FALSE status_report = "Civilian Bounty: " var/obj/machinery/piratepad/civilian/pad = pad_ref?.resolve() - for(var/atom/movable/AM in get_turf(pad)) - if(AM == pad) + for(var/atom/movable/possible_shippable in get_turf(pad)) + if(possible_shippable == pad) continue - if(inserted_scan_id.registered_account.civilian_bounty.applies_to(AM)) + if(possible_shippable.flags_1 & HOLOGRAM_1) + continue + if(isitem(possible_shippable)) + var/obj/item/possible_shippable_item = possible_shippable + if(possible_shippable_item.item_flags & ABSTRACT) + continue + if(inserted_scan_id.registered_account.civilian_bounty.applies_to(possible_shippable)) status_report += "Target Applicable." playsound(loc, 'sound/machines/synth/synth_yes.ogg', 30 , TRUE) return @@ -110,13 +116,19 @@ var/datum/bounty/curr_bounty = inserted_scan_id.registered_account.civilian_bounty var/active_stack = 0 var/obj/machinery/piratepad/civilian/pad = pad_ref?.resolve() - for(var/atom/movable/AM in get_turf(pad)) - if(AM == pad) + for(var/atom/movable/possible_shippable in get_turf(pad)) + if(possible_shippable == pad) + continue + if(possible_shippable.flags_1 & HOLOGRAM_1) continue - if(curr_bounty.applies_to(AM)) + if(isitem(possible_shippable)) + var/obj/item/possible_shippable_item = possible_shippable + if(possible_shippable_item.item_flags & ABSTRACT) + continue + if(curr_bounty.applies_to(possible_shippable)) active_stack ++ - curr_bounty.ship(AM) - qdel(AM) + curr_bounty.ship(possible_shippable) + qdel(possible_shippable) if(active_stack >= 1) status_report += "Bounty Target Found x[active_stack]. " else From 38e1c4f21e776bc96dcc68b8c501411614eee907 Mon Sep 17 00:00:00 2001 From: "tgstation-ci[bot]" <179393467+tgstation-ci[bot]@users.noreply.github.com> Date: Thu, 28 Nov 2024 08:55:56 +0000 Subject: [PATCH 007/149] Automatic changelog for PR #88242 [ci skip] --- html/changelogs/AutoChangeLog-pr-88242.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-88242.yml diff --git a/html/changelogs/AutoChangeLog-pr-88242.yml b/html/changelogs/AutoChangeLog-pr-88242.yml new file mode 100644 index 0000000000000..19bb81e3d39db --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-88242.yml @@ -0,0 +1,5 @@ +author: "necromanceranne" +delete-after: True +changes: + - bugfix: "Civilian bounty pads refuse to send holographic items. Nanotrasen have received far too many holographic fish for their liking. Officer Mathews is still weeping in a corner after all the clownfish in his aquarium turned to dust before his very eyes..." + - code_imp: "Cleans up the bounty pad code just a smidge." \ No newline at end of file From 8b9da265bab1070fbcae77b94db2743d29dfd3e0 Mon Sep 17 00:00:00 2001 From: Runi-c <5150427+Runi-c@users.noreply.github.com> Date: Thu, 28 Nov 2024 08:17:18 -0700 Subject: [PATCH 008/149] Digitigrade code refactor and shoes + explorer suit (Using GAGS and zero sprite bloat) (#88096) ## About The Pull Request Refactors and extends the existing [digitigrade clothing system](https://github.com/tgstation/tgstation/pull/85406) to also support oversuits and shoes (only enabled for sneakers, specific boots, and shaft miner's explorer suit). All digitigrade-specific clothes are generated by GAGS by color sampling the base sprite and applying it to a greyscale template. ![image](https://github.com/user-attachments/assets/c4ce5996-9373-4d76-a0e5-a6b094dd10b4) More up to date boots: ![image](https://github.com/user-attachments/assets/8ead8056-25a3-42dd-9fde-e838e2a810b9) ![image](https://github.com/user-attachments/assets/783a1201-8a77-45a0-af85-8a63b41b63a8) Credit to MrMelbert for prototype code and Junkgle for new sprites ## Why It's Good For The Game Looks good, doesn't introduce maintainability issues or sprite bloat ## Changelog :cl: add: digitigrade lizards can wear certain shoes and suits image: added digitigrade shoes & oversuit templates refactor: improved digi clothing generator code /:cl: --------- Co-authored-by: MrMelbert Co-authored-by: Roryl-c <5150427+Roryl-c@users.noreply.github.com> --- code/__DEFINES/inventory.dm | 1 - .../greyscale_configs/greyscale_clothes.dm | 13 ++- .../greyscale/json_configs/digitigrade.json | 39 +++++++ .../json_configs/jumpsuit_worn_digilegs.json | 10 -- code/game/objects/items.dm | 6 - code/modules/clothing/shoes/_shoes.dm | 3 + code/modules/clothing/shoes/boots.dm | 6 + code/modules/clothing/shoes/sneakers.dm | 8 ++ code/modules/clothing/suits/_suits.dm | 4 + code/modules/clothing/under/_under.dm | 5 +- code/modules/clothing/under/color.dm | 4 +- code/modules/clothing/under/miscellaneous.dm | 4 +- .../modules/mining/equipment/explorer_gear.dm | 4 + .../living/carbon/human/human_update_icons.dm | 109 ++++++++++++------ .../screenshots/screenshot_digi_leg_test.png | Bin 1692 -> 1758 bytes ...anoids__datum_species_lizard_ashwalker.png | Bin 1223 -> 1246 bytes icons/mob/clothing/digi_template.dmi | Bin 0 -> 706 bytes icons/mob/clothing/under/digi_template.dmi | Bin 586 -> 0 bytes icons/mob/clothing/under/masking_helpers.dmi | Bin 454 -> 433 bytes 19 files changed, 156 insertions(+), 60 deletions(-) create mode 100644 code/datums/greyscale/json_configs/digitigrade.json delete mode 100644 code/datums/greyscale/json_configs/jumpsuit_worn_digilegs.json create mode 100644 icons/mob/clothing/digi_template.dmi delete mode 100644 icons/mob/clothing/under/digi_template.dmi diff --git a/code/__DEFINES/inventory.dm b/code/__DEFINES/inventory.dm index 87f7ba50f7576..3e9b0bcc33c6f 100644 --- a/code/__DEFINES/inventory.dm +++ b/code/__DEFINES/inventory.dm @@ -163,7 +163,6 @@ DEFINE_BITFIELD(no_equip_flags, list( /// The sprite works fine for digitigrade legs as-is. #define CLOTHING_DIGITIGRADE_VARIATION_NO_NEW_ICON (1<<2) /// Auto-generates the leg portion of the sprite with GAGS -/// Suggested that you set [/obj/item/var/digitigrade_greyscale_config_worn] when using this flag #define CLOTHING_DIGITIGRADE_MASK (1<<3) /// All variation flags which render "correctly" on a digitigrade leg setup diff --git a/code/datums/greyscale/config_types/greyscale_configs/greyscale_clothes.dm b/code/datums/greyscale/config_types/greyscale_configs/greyscale_clothes.dm index bdc2a7d2928c5..54ea9f4185756 100644 --- a/code/datums/greyscale/config_types/greyscale_configs/greyscale_clothes.dm +++ b/code/datums/greyscale/config_types/greyscale_configs/greyscale_clothes.dm @@ -276,11 +276,6 @@ icon_file = 'icons/mob/inhands/clothing/suits_righthand.dmi' json_config = 'code/datums/greyscale/json_configs/jumpsuit_prison_inhand.json' -/datum/greyscale_config/jumpsuit/worn_digi - name = "Jumpsuit Worn (Digitigrate)" - icon_file = 'icons/mob/clothing/under/digi_template.dmi' - json_config = 'code/datums/greyscale/json_configs/jumpsuit_worn_digilegs.json' - /datum/greyscale_config/eth_tunic name = "Ethereal Tunic" icon_file = 'icons/obj/clothing/under/ethereal.dmi' @@ -627,6 +622,14 @@ name = "Waistcoat (Worn)" icon_file = 'icons/mob/clothing/accessories.dmi' +// Digi Stuff + +/datum/greyscale_config/digitigrade + name = "Digitigrade Clothes" + icon_file = 'icons/mob/clothing/digi_template.dmi' + json_config = 'code/datums/greyscale/json_configs/digitigrade.json' + + // // SUIT + HEAD // (Specifically for toggleable suits with hats, i.e. winter coats) diff --git a/code/datums/greyscale/json_configs/digitigrade.json b/code/datums/greyscale/json_configs/digitigrade.json new file mode 100644 index 0000000000000..899dff334e423 --- /dev/null +++ b/code/datums/greyscale/json_configs/digitigrade.json @@ -0,0 +1,39 @@ +{ + "jumpsuit_worn": [ + { + "type": "icon_state", + "icon_state": "jumpsuit", + "blend_mode": "overlay", + "color_ids": [ 1 ] + } + ], + "oversuit_worn": [ + { + "type": "icon_state", + "icon_state": "oversuit", + "blend_mode": "overlay", + "color_ids": [ 1 ] + } + ], + "sneakers_worn": [ + { + "type": "icon_state", + "icon_state": "shoes_colored", + "blend_mode": "overlay", + "color_ids": [ 1 ] + }, + { + "type": "icon_state", + "icon_state": "shoes_uncolored", + "blend_mode": "overlay" + } + ], + "boots_worn": [ + { + "type": "icon_state", + "icon_state": "boots", + "blend_mode": "overlay", + "color_ids": [ 1 ] + } + ] +} diff --git a/code/datums/greyscale/json_configs/jumpsuit_worn_digilegs.json b/code/datums/greyscale/json_configs/jumpsuit_worn_digilegs.json deleted file mode 100644 index 9aa201cece3c1..0000000000000 --- a/code/datums/greyscale/json_configs/jumpsuit_worn_digilegs.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "": [ - { - "type": "icon_state", - "icon_state": "jumpsuit", - "blend_mode": "overlay", - "color_ids": [ 1 ] - } - ] -} diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index f32690f334cad..b8aec816391a9 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -39,12 +39,6 @@ ///The config type to use for greyscaled belt overlays. Both this and greyscale_colors must be assigned to work. var/greyscale_config_belt - /// Greyscale config used when generating digitigrade versions of the sprite. - var/digitigrade_greyscale_config_worn - /// Greyscale colors used when generating digitigrade versions of the sprite. - /// Optional - If not set it will default to normal greyscale colors, or approximate them if those are unset as well - var/digitigrade_greyscale_colors - /* !!!!!!!!!!!!!!! IMPORTANT !!!!!!!!!!!!!! IF YOU ADD MORE ICON CRAP TO THIS diff --git a/code/modules/clothing/shoes/_shoes.dm b/code/modules/clothing/shoes/_shoes.dm index 3ecec813a95ce..1793a212ae330 100644 --- a/code/modules/clothing/shoes/_shoes.dm +++ b/code/modules/clothing/shoes/_shoes.dm @@ -110,6 +110,9 @@ var/mob/M = loc M.update_worn_shoes() +/obj/item/clothing/shoes/generate_digitigrade_icons(icon/base_icon, greyscale_colors) + return icon(SSgreyscale.GetColoredIconByType(/datum/greyscale_config/digitigrade, greyscale_colors), "boots_worn") + /** * adjust_laces adjusts whether our shoes (assuming they can_be_tied) and tied, untied, or knotted * diff --git a/code/modules/clothing/shoes/boots.dm b/code/modules/clothing/shoes/boots.dm index 77e7b2ff369e2..2dba6ed24fce7 100644 --- a/code/modules/clothing/shoes/boots.dm +++ b/code/modules/clothing/shoes/boots.dm @@ -3,6 +3,7 @@ desc = "High speed, low drag combat boots." icon_state = "jackboots" inhand_icon_state = "jackboots" + supports_variations_flags = CLOTHING_DIGITIGRADE_MASK body_parts_covered = FEET|LEGS armor_type = /datum/armor/shoes_combat strip_delay = 40 @@ -45,6 +46,7 @@ desc = "Nanotrasen-issue Security combat boots for combat scenarios or combat situations. All combat, all the time." icon_state = "jackboots" inhand_icon_state = "jackboots" + supports_variations_flags = CLOTHING_DIGITIGRADE_MASK strip_delay = 30 equip_delay_other = 50 resistance_flags = NONE @@ -71,6 +73,7 @@ desc = "Is it just me or is there a pair of jackboots on the floor?" icon_state = "ftc_boots" inhand_icon_state = null + supports_variations_flags = NONE /obj/item/clothing/shoes/jackboots/floortile/Initialize(mapload) . = ..() @@ -81,6 +84,7 @@ desc = "Boots lined with 'synthetic' animal fur." icon_state = "winterboots" inhand_icon_state = null + supports_variations_flags = CLOTHING_DIGITIGRADE_MASK armor_type = /datum/armor/shoes_winterboots cold_protection = FEET|LEGS min_cold_protection_temperature = SHOES_MIN_TEMP_PROTECT @@ -131,6 +135,7 @@ icon_state = "workboots" inhand_icon_state = "jackboots" armor_type = /datum/armor/shoes_workboots + supports_variations_flags = CLOTHING_DIGITIGRADE_MASK strip_delay = 20 equip_delay_other = 40 lace_time = 8 SECONDS @@ -155,6 +160,7 @@ icon_state = "rus_shoes" inhand_icon_state = null lace_time = 8 SECONDS + supports_variations_flags = CLOTHING_DIGITIGRADE_MASK /obj/item/clothing/shoes/russian/Initialize(mapload) . = ..() diff --git a/code/modules/clothing/shoes/sneakers.dm b/code/modules/clothing/shoes/sneakers.dm index 0ae1e6e9caad9..1fc47accd3534 100644 --- a/code/modules/clothing/shoes/sneakers.dm +++ b/code/modules/clothing/shoes/sneakers.dm @@ -9,9 +9,17 @@ greyscale_config_worn = /datum/greyscale_config/sneakers/worn greyscale_config_inhand_left = /datum/greyscale_config/sneakers/inhand_left greyscale_config_inhand_right = /datum/greyscale_config/sneakers/inhand_right + supports_variations_flags = CLOTHING_DIGITIGRADE_MASK flags_1 = IS_PLAYER_COLORABLE_1 interaction_flags_mouse_drop = NEED_HANDS +/obj/item/clothing/shoes/sneakers/get_general_color(icon/base_icon) + var/colors = SSgreyscale.ParseColorString(greyscale_colors) + return colors ? colors[1] : ..() + +/obj/item/clothing/shoes/sneakers/generate_digitigrade_icons(icon/base_icon, greyscale_colors) + return icon(SSgreyscale.GetColoredIconByType(/datum/greyscale_config/digitigrade, greyscale_colors), "sneakers_worn") + /obj/item/clothing/shoes/sneakers/random/Initialize(mapload) . = ..() greyscale_colors = "#" + random_color() + "#" + random_color() diff --git a/code/modules/clothing/suits/_suits.dm b/code/modules/clothing/suits/_suits.dm index ecae343f68506..78ea1d2f3b7a1 100644 --- a/code/modules/clothing/suits/_suits.dm +++ b/code/modules/clothing/suits/_suits.dm @@ -43,3 +43,7 @@ if(ismob(loc)) var/mob/M = loc M.update_worn_oversuit() + +/obj/item/clothing/suit/generate_digitigrade_icons(icon/base_icon, greyscale_colors) + var/icon/legs = icon(SSgreyscale.GetColoredIconByType(/datum/greyscale_config/digitigrade, greyscale_colors), "oversuit_worn") + return replace_icon_legs(base_icon, legs) diff --git a/code/modules/clothing/under/_under.dm b/code/modules/clothing/under/_under.dm index 85fff72052b23..3fa11d2882c8b 100644 --- a/code/modules/clothing/under/_under.dm +++ b/code/modules/clothing/under/_under.dm @@ -9,7 +9,6 @@ interaction_flags_click = NEED_DEXTERITY armor_type = /datum/armor/clothing_under supports_variations_flags = CLOTHING_DIGITIGRADE_MASK - digitigrade_greyscale_config_worn = /datum/greyscale_config/jumpsuit/worn_digi equip_sound = 'sound/items/equip/jumpsuit_equip.ogg' drop_sound = 'sound/items/handling/cloth_drop.ogg' pickup_sound = 'sound/items/handling/cloth_pickup.ogg' @@ -142,6 +141,10 @@ adjusted = DIGITIGRADE_STYLE update_appearance() +/obj/item/clothing/under/generate_digitigrade_icons(icon/base_icon, greyscale_colors) + var/icon/legs = icon(SSgreyscale.GetColoredIconByType(/datum/greyscale_config/digitigrade, greyscale_colors), "jumpsuit_worn") + return replace_icon_legs(base_icon, legs) + /obj/item/clothing/under/equipped(mob/living/user, slot) ..() if((slot & ITEM_SLOT_ICLOTHING) && freshly_laundered) diff --git a/code/modules/clothing/under/color.dm b/code/modules/clothing/under/color.dm index 9ae1c7d63e366..af64ca4e999e3 100644 --- a/code/modules/clothing/under/color.dm +++ b/code/modules/clothing/under/color.dm @@ -224,10 +224,12 @@ greyscale_config_inhand_left = null greyscale_config_inhand_right = null greyscale_config_worn = null - digitigrade_greyscale_colors = "#3f3f3f" can_adjust = FALSE flags_1 = NONE +/obj/item/clothing/under/color/rainbow/get_general_color(icon/base_icon) + return "#3f3f3f" + /obj/item/clothing/under/color/jumpskirt/rainbow name = "rainbow jumpskirt" desc = "A multi-colored jumpskirt!" diff --git a/code/modules/clothing/under/miscellaneous.dm b/code/modules/clothing/under/miscellaneous.dm index 70d2a5eeadb94..2c428f1c35c1a 100644 --- a/code/modules/clothing/under/miscellaneous.dm +++ b/code/modules/clothing/under/miscellaneous.dm @@ -33,7 +33,9 @@ desc = "Groovy!" icon_state = "psyche" inhand_icon_state = "p_suit" - digitigrade_greyscale_colors = "#3f3f3f" + +/obj/item/clothing/under/misc/psyche/get_general_color(icon/base_icon) + return "#3f3f3f" /obj/item/clothing/under/misc/vice_officer name = "vice officer's jumpsuit" diff --git a/code/modules/mining/equipment/explorer_gear.dm b/code/modules/mining/equipment/explorer_gear.dm index 216275a239076..a6b2f075b8f1e 100644 --- a/code/modules/mining/equipment/explorer_gear.dm +++ b/code/modules/mining/equipment/explorer_gear.dm @@ -6,6 +6,7 @@ icon = 'icons/obj/clothing/suits/utility.dmi' worn_icon = 'icons/mob/clothing/suits/utility.dmi' inhand_icon_state = null + supports_variations_flags = CLOTHING_DIGITIGRADE_MASK body_parts_covered = CHEST|GROIN|LEGS|ARMS cold_protection = CHEST|GROIN|LEGS|ARMS min_cold_protection_temperature = FIRE_SUIT_MIN_TEMP_PROTECT @@ -15,6 +16,9 @@ armor_type = /datum/armor/hooded_explorer resistance_flags = FIRE_PROOF +/obj/item/clothing/suit/hooded/explorer/get_general_color(icon/base_icon) + return "#796755" + /datum/armor/hooded_explorer melee = 30 bullet = 10 diff --git a/code/modules/mob/living/carbon/human/human_update_icons.dm b/code/modules/mob/living/carbon/human/human_update_icons.dm index 73ce6808339b8..6227e9558db8a 100644 --- a/code/modules/mob/living/carbon/human/human_update_icons.dm +++ b/code/modules/mob/living/carbon/human/human_update_icons.dm @@ -573,20 +573,70 @@ There are several things that need to be remembered: return icon(female_clothing_icon) -// These coordonates point to roughly somewhere in the middle of the left leg -// Used in approximating what color the pants of clothing should be +/// Modifies a sprite to conform to digitigrade body shapes +/proc/wear_digi_version(icon/base_icon, obj/item/item, key, greyscale_colors) + ASSERT(istype(item), "wear_digi_version: no item passed") + ASSERT(istext(key), "wear_digi_version: no key passed") + if(isnull(greyscale_colors) || length(SSgreyscale.ParseColorString(greyscale_colors)) > 1) + greyscale_colors = item.get_general_color(base_icon) + + var/index = "[key]-[item.type]-[greyscale_colors]" + var/static/list/digitigrade_clothing_cache = list() + var/icon/resulting_icon = digitigrade_clothing_cache[index] + if(!resulting_icon) + resulting_icon = item.generate_digitigrade_icons(base_icon, greyscale_colors) + if(!resulting_icon) + stack_trace("[item.type] is set to generate a masked digitigrade icon, but generate_digitigrade_icons was not implemented (or error'd).") + return base_icon + digitigrade_clothing_cache[index] = fcopy_rsc(resulting_icon) + + return icon(resulting_icon) + +/// Modifies a sprite to replace the legs with a new version +/proc/replace_icon_legs(icon/base_icon, icon/new_legs) + var/static/icon/leg_mask + if(!leg_mask) + leg_mask = icon('icons/mob/clothing/under/masking_helpers.dmi', "digi_leg_mask") + + // cuts the legs off + base_icon.Blend(leg_mask, ICON_SUBTRACT) + // staples the new legs on + base_icon.Blend(new_legs, ICON_OVERLAY) + return base_icon + +/** + * Generates a digitigrade version of this item's worn icon + * + * Arguments: + * * base_icon: The icon to generate the digitigrade icon from + * * greyscale_colors: The greyscale colors to use for the digitigrade icon + * + * Returns an icon that is the digitigrade version of the item's worn icon + * Returns null if the item has no support for digitigrade variations via this method + */ +/obj/item/proc/generate_digitigrade_icons(icon/base_icon, greyscale_colors) + return null + +/** + * Get what color the item is on "average" + * Can be used to approximate what color this item is/should be + * + * Arguments: + * * base_icon: The icon to get the color from + */ +/obj/item/proc/get_general_color(icon/base_icon) + if(greyscale_colors && length(SSgreyscale.ParseColorString(greyscale_colors)) == 1) + return greyscale_colors + return color + +// These coordinates point to the middle of the left leg #define LEG_SAMPLE_X_LOWER 13 #define LEG_SAMPLE_X_UPPER 14 - #define LEG_SAMPLE_Y_LOWER 8 #define LEG_SAMPLE_Y_UPPER 9 -/// Modifies a sprite to conform to digitigrade body shapes -/proc/wear_digi_version(icon/base_icon, key, greyscale_config = /datum/greyscale_config/jumpsuit/worn_digi, greyscale_colors) - ASSERT(key, "wear_digi_version: no key passed") - ASSERT(ispath(greyscale_config, /datum/greyscale_config), "wear_digi_version: greyscale_config is not a valid path (got: [greyscale_config])") - // items with greyscale colors containing multiple colors are invalid - if(isnull(greyscale_colors) || length(SSgreyscale.ParseColorString(greyscale_colors)) > 1) +/obj/item/clothing/get_general_color(icon/base_icon) + if(slot_flags & (ITEM_SLOT_ICLOTHING|ITEM_SLOT_OCLOTHING)) var/pant_color // approximates the color of the pants by sampling a few pixels in the middle of the left leg for(var/x in LEG_SAMPLE_X_LOWER to LEG_SAMPLE_X_UPPER) @@ -594,37 +644,26 @@ There are several things that need to be remembered: var/xy_color = base_icon.GetPixel(x, y) pant_color = pant_color ? BlendRGB(pant_color, xy_color, 0.5) : xy_color - greyscale_colors = pant_color || "#1d1d1d" // black pants always look good - - var/index = "[key]-[greyscale_config]-[greyscale_colors]" - var/static/list/digitigrade_clothing_icons = list() - var/icon/digitigrade_clothing_icon = digitigrade_clothing_icons[index] - if(!digitigrade_clothing_icon) - var/static/icon/torso_mask - if(!torso_mask) - torso_mask = icon('icons/mob/clothing/under/masking_helpers.dmi', "digi_torso_mask") - var/static/icon/leg_mask - if(!leg_mask) - leg_mask = icon('icons/mob/clothing/under/masking_helpers.dmi', "digi_leg_mask") - - base_icon.Blend(leg_mask, ICON_SUBTRACT) // cuts the legs off - - var/icon/leg_icon = SSgreyscale.GetColoredIconByType(greyscale_config, greyscale_colors) - leg_icon.Blend(torso_mask, ICON_SUBTRACT) // cuts the torso off - - base_icon.Blend(leg_icon, ICON_OVERLAY) // puts the new legs on - - digitigrade_clothing_icon = fcopy_rsc(base_icon) - digitigrade_clothing_icons[index] = digitigrade_clothing_icon + return pant_color || "#1d1d1d" // black pants always look good - return icon(digitigrade_clothing_icon) + return ..() #undef LEG_SAMPLE_X_LOWER #undef LEG_SAMPLE_X_UPPER - #undef LEG_SAMPLE_Y_LOWER #undef LEG_SAMPLE_Y_UPPER +// Points to the tip of the left foot +#define SHOE_SAMPLE_X 11 +#define SHOE_SAMPLE_Y 2 + +/obj/item/clothing/shoes/get_general_color(icon/base_icon) + // just grabs the color of the middle of the left foot + return base_icon.GetPixel(SHOE_SAMPLE_X, SHOE_SAMPLE_Y) || "#1d1d1d" + +#undef SHOE_SAMPLE_X +#undef SHOE_SAMPLE_Y + /mob/living/carbon/human/proc/get_overlays_copy(list/unwantedLayers) var/list/out = new for(var/i in 1 to TOTAL_LAYERS) @@ -774,9 +813,9 @@ generate/load female uniform sprites matching all previously decided variables if(!isinhands && is_digi && (supports_variations_flags & CLOTHING_DIGITIGRADE_MASK)) building_icon = wear_digi_version( base_icon = building_icon || icon(file2use, t_state), + item = src, key = "[t_state]-[file2use]-[female_uniform]", - greyscale_config = digitigrade_greyscale_config_worn || greyscale_config_worn, - greyscale_colors = digitigrade_greyscale_colors || greyscale_colors || color, + greyscale_colors = greyscale_colors, ) if(building_icon) standing = mutable_appearance(building_icon, layer = -layer2use) diff --git a/code/modules/unit_tests/screenshots/screenshot_digi_leg_test.png b/code/modules/unit_tests/screenshots/screenshot_digi_leg_test.png index 1ca452de089462485c7e4d6204dd14452995206d..3907b46b8709b4db3a6a2aeaa4b68a3dba36c500 100644 GIT binary patch delta 1314 zcmV+-1>O3b4c-lqBmvKnC2bodBq}W}GZYjW00{ug&C&n={{RF4jFP2vae|SULJjWj z?j0T^rKz@UTrtm)-i&`iNkly1}7N2%}r^S zw)y|RX-^R6!$@3rWM}8}Og=$47rkrr0ax!b_EQz-(ee3l&e@S8gm8}Z>GR`EO4mJ- zQXaXkl>Y+GiJVJ8pZe_CaVEJ-_%VIzGZX%z4^CGIS4drSZNz_H_QDx=T~0Sie{^EP zPx|3?adokQ?4&2ogd;iU(h(MX;CY05-oS**Lg(F9r83yBlAIQL`+J+Aa zAKGvsN5UD2kt0S%hQJ&9z884DKlTCxJ`BfdqKg`bLt}hN({w~ER2vv5G7-t;01%=jzFKa2*PBLsE7z6 zMQ5Rbz-6>h^c`?IYZ1gj%iGhIA4d`h)a(J6SgC>hS@Z302hkY<{?qCEy0j|0z(Juiq2_>`t6_0B{!ReKt7{jimF z7fJoV-G7?sf4zGB=9gc8d-M900Y6nLna}4mOX-*>b-GVLZy}+_Sn5$0hF22jspolV zTptZM^?HA@E37>PO)p5{xQ;L_GhI^Zeof%}sS#&M)D&a%nn3?}JdMS;$o>H6d-ft*9bX==vX$`$4%i<6ea~Lz ztINyFRc^ioygxwt{)Dab6@Avm_=oHdu>N1u7+B&T&>ri5&&%_?6Yp-1^}ion0lcF< z(*OPOZvEdEhx-2+@J{{T7l-=4FAnv8U;KZu{x3?c|BI(Mt>Ek)&*)q6W9=X5|DxQK z^sRh)MRt|1AMpGt+rv@&2mMd@@1+ob{Q2~Xb)IJrc%JX$sQrWfFSgswhV#vK`}Bf! z#`G`rYdl-GaMYgd^nbA}wjaxnbZlLq2hp?RuzjQdi%oI;Y5VD#>J|Y_kl2pH_Kko3 zFUsokb$R`{+V8_=F)=$1+c)~ZDvI*U_Dfk5m65=X!}g8-ul}m4?Pgn1Z6>hdsQpg= zS2vrI=GsjwzJ45Z;Gq2@{r~l*s;Zl>t@tdaLI)!b+8?C<7YhyPL+gU>_6O?!<+pFk z#dr37p-+CG{lWVGcDcO0y2ax~J-ycB!LvMco`48+F z`~kR=;ssX&s5!cmJO(T|Gyf0$1LQyGV$J{K{R8qJ?&F*C|8W0+{D*r2bN(Ocf8;;> Y4UWg^bb2sFwEzGB07*qoM6N<$f`^W+-BmuFJC2a-(2><{D0FkXi1cU~Ccai*ze;r9gK~!jg?O6?%nm7~< znS^P_s6Z6Nw%Z+APy~0^PHA`g|9{xN;5a&xaGisD_MABzj|9EsUC0Mq-ev4f74Kww zeVlW4;|U?W8?$?ToJr~XH&V(Q-cWX9?F^&oCCUgpXagkQ3oe#KaR5D?_NJL7+kv1XC4S@NqQNGgI_58e8K_ znx+$Cq1wVgk%=In_*7dM=Cf!Tw*>Jtn$2wl9!)P=e-r zpu$o3L}2zh1W`IlbxZ`YroG5Q;4@k%<_b9NbqJC$Vb28Zua_lFmn>aGX_`ihlr7WL zLcr+)f6O$Uc)Uws@Z^agvEa+)IE|xdKA%TXoQ{{vE`gwX$bOpoqB{l#PeP>P{nWZnm=RB57{8=XVqH*N2ave*66Ur;i^j_`TNYa=D~gO50TH`*Q+% z3JEjD(u}gOJd!xilu}vJZY?C;^8LZp?bf7}EIJRyR_dIHRh@qDJ4p3Tok z+4MUV|BLw25>Wjr{3QN85!|0K_=m#2@~@`%eX3u99|_uWsNQNp`hQq^sP9e5^V|gu zem`jA7pua>F!cSPjlV96Vr^%*WFK$=2MP67h;DYx9pzqoHvRJKFMQOhT z{Cu7cpgq?AN|j~Vi}$z3`acNQ0Pks!^#5?YU;huq zq5i)D-mCwI;!yt&#i9Nmil6HLsy6z+dWq8t&Y$s|epRn)f1>}ZdRx=4`sES%f4bZp z@p7G?;i&yl{}cX4EySOHy*y%5miZAc%X1vHKkEN#x7%(x-|luV57^|)oMF)7`KE)T z_Uxelt6jDGR)3>y=KwQ^%8kSJd;MQ+tB3Eq?+;XW2xx*NZXCAX>;I~5emv9cr;yKAVn6F70y{-FPx$8Ak>?XeTz z+zxth(EddK|9Whi=J8i2J}LKBzFTq7{v!RK(*rqw+MbpE_802^e6?Dy*NncaRsM?h z7wiALEH|4Cqi=btj4p2fHp>70!GG=_4Dtt%|1jJiK>ovEe*pOp>0eq7m23G@U zIr@`%1}ro;{}25GU!}2jo9I$G7GGujMbe^8Z8qg?|9+m)1lQLf(M@0000< KMNUMnLSTX}=85S5 diff --git a/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_lizard_ashwalker.png b/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_lizard_ashwalker.png index 3437280e851ba96f3e6d4c02b45ea11513f36f14..9c05ab07e5ffed325061ff64cfa8dbb26caf9096 100644 GIT binary patch delta 1018 zcmV$Y|nm7!W@Uv4JNLB*f#}@BrR} z0Tz1;cVm(PP8r}J$skA)``GvRiw!&jNF$Pnx%Mdd&?5nq!oZQ?7{`@B&nkZcTv?s~ z&){m@!{oIkpO#?_J`x^+t1@+PxXEUCGC$#L?4g9YXWqcNkpbxjz-JzoO4P6yDjC+bv$gs z<10Z*lLb4JhzfyJ6-@nJ#@9je&4L1A#pKn4S0ZRDvCOpPJ~O2D--(qrSpEWz5D zPp7jxpH6dwV1|P`op_<3PtlB4NPM|oXAsQS>&1+}DD2b$6d!5u-Q0is>F9o9{ZJT^ol+=t5)gsZr=`@o>jUUyn8XS6oqV>ytHs zCsvJMza6}Nh=+!Lxo5CQ1beqE@?bLqeo=myO|U?0ZKV%}MMX8xMPxPO(XsQ0nX~m4 z0FN2X-HgZNM%Okc@7;fNME5<0yupBY%uGy)klK?bGJt~lias@sw-`Gbs8#_ zqGJnK9&w8e0_n%BgC6d624(EaR~g8n6sinjArMVqlK?45A$Tl;4*v|3uLwlFhFZz# z@XuH%tWJ%UK#F0rP*#obh@vdov9VNSY_tTg7}`JQx`u^fkI8?>hr{bzD}%S!!vX7= z_YJL@g;~`>YqDVG=zQhIc)zjNxhPX}AxHu77CqlAoP(~iX`4XNY;JcXPzY4WGzp+? z3W1pd`=V|@u(1wuE<&j82{-pAfvFkqbpGE{a1S{k9yOG00#^v&o#(~lH0uE2m12^>{t&Z#WIo o0rF|iFUp{)4_1M&%7lC1Z`C_T088_ep8x;=07*qoM6N<$g4iDF*#H0l delta 995 zcmV<9104L`3C9VLBmr8HB~=Xo2><{D004RbGwu^(k(Pmfs!2paR9J=0SK)fwFbI^1 zM7K`Z(n!+IP2T@CcgRVbFGAk-Z}e;I=HQHx1lJJ$E1MoZ{~ad^hbhK59qjhs@sJYp zA*FO+PRYX~Qv@D~qlXj7DMkFWy8&+I;~^2hr1%X#xTF3N?c2>>Jls}Uh$59ganD%Eh2Mch|I5U5kq(lZ03U-N&1lpegn%QL?n_2_$=8>=285TOHH-l z>c=nnr&(TnhAK-bQl*qds*C4kLHx4h0bW2*5Ra?l0el7nEYBVuYLNv_3UHC)5ERLC zo@e~#0j>Z_MG{$ikA^QZ5&92wSJZv=MN5#XDD?G5k_p~r((4W9(?4B2{B_2q;>AdxA$M?(~X?Nu7aD{Ce&4J zJGwZ3sBxabApQdy!Ak26fe1(RixI(!H$XSRgM0@NtSto|65#Dvhcz%a_5$4~&pR~me`aG^_cz||$VY!P^W+~pza|FUVU4F1yZKr~J6LAzU=CZfX_ zhenu&s~Bt{Ctp0=akAy{hW`yWH2V7FmcR>}M(|e$s}J!o&@cB4Hi_V$mQ5b)X27q; z5Az8&h`poq#jvTU0lJB-VLUpvR?M8eRRCNS&E1X1CM9(vZyu*Na%=GaaX#~$ju;H&T`4fSd*U~FF8~%!o!sayC31k=!3#n;@XB1_zj*YD%bY}2JdgD6ZSKI9|u}hh1t}>XtH4D*nH)|c)xPAxhU&!BS-_W zijl7#&dGM!x=&!Jy2l*}Gy)ScLjtIqM&PEvv8fvn?Cb;8CWQK)a1Eacti$+V^Z%Yg zc*+6ssG;l=ghl|T_|%uK*6(ie0H0$5cx(zHTHm~Wg*SPCJq}v+YrLgt0wF*~Fscm@ zzEN!Q!1Mw)WqjMY`n>lb|`ybANY=At>dA{()h6DThAY9l+0-PR&#cxI7K$KB= RUG4w?002ovPDHLkV1kcS)dK(k diff --git a/icons/mob/clothing/digi_template.dmi b/icons/mob/clothing/digi_template.dmi new file mode 100644 index 0000000000000000000000000000000000000000..319bd875041c7dec5e746d36613068004eaae547 GIT binary patch literal 706 zcmV;z0zLhSP)004jl0{{R3eocQU0000FP)t-sz`($a zlBLVd(R6Ww|NsAb@^TFT0004WQchCV=-0C=2J zR&a84_w-Y6@%7{?OD!tS%+FJ>RWQ*r;NmRLOex6#a*U0*I5Sc+(=$pSoZ^zil2jm5 zDXTQMptv-%M2U+tC9|j)q>qa;ttc@!6~s0~D9i_$OpL;${QQz)f~tx$@>7fBlk;=( zi&9gFR9%`!K)teptDg%v7yzThPjGvb(h~px0mn&1K~!jg?U+fD;~)@4Q{V#_&;caO z0T^@uo96y!>QqEU`J)P3LAw^c$QSbB1DQg@;#ow3AP9o+Ut_(q{`$w222vkeAvD_eyE9$3TjjH=ppds9!LrL94MeWX-zL9V86XaY9$A#EP!x#4y0 z8v1L03Aq-WSFLmnkM%UKGzDm2Ib*{qJW7T26v|xRtmk_WGv0%_E*`TEw}cxY>oVTs zV?9l4Oe^NLga>5p4-J*e_>_{`p7PTNy+Pko9LE|C`rvuPK_5J2)CW%)^+95N>o)9S>GG%#UUp-} z^RaOHZi|CHsBFv@&zE9K^a0@!6TSsA?=Xx!v?JD$w)iiAFCc%?P!I$`5Cq{jF^gF+ zE2GRO{c_Xcjsq-!W7>agXsPo(T5tRDjcRd2=T_m~P%uNKUg}x)x-IesRYRp!F?Tz- zkzOEbUV(X+z0UWhHS+QLiUdIr1VIplkH~d*ykBIuJJ7e?74iFE;NJ!EK8ab~*-78^ ow=9(S)%ch>bb0b|`uaxu7jtMy3bm4fO#lD@07*qoM6N<$g5au2-~a#s literal 0 HcmV?d00001 diff --git a/icons/mob/clothing/under/digi_template.dmi b/icons/mob/clothing/under/digi_template.dmi deleted file mode 100644 index 0c9db80eb1c880eebac6627e659877a5bc2e65a2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 586 zcmV-Q0=4~#P)(^b0d!JMQvg8b*k%9#0Bw3ySad{Xb7OL8aCB*J zZU6vyoKseCa&`CgQ*iP1fTLt$1vDPdqJhZ$X|kxj>nvWw!rgoljvxW41IgN1pqx$r!%44`#L)8eF%(gfg_2EK6u5K$kG$%)ii!&v&s2HS` zi!-e#F*g;&HpEa{l3zfq(!Bimq@vWs;*w$#3@1fbN@jXyd`@b5d~RZKHZIl53a)-G z;Lrg8F5_4YYuIUF0002BNklxtI9$N2ooFk#;&sIYHc1hZTD@@NGW zln6pE!iva?5JW10U@f}(5qlB(v2hse#XCJp1P`|+v_}OMd=adAk@6-1pcg5>f;E*; zUe@)T|0l0jtb392vZhv07C1AZ;0Vw+g08iq{lnB9Kpi`@N5h4JLcs+IstW2@1p~7H O0000J delta 441 zcmV;q0Y?6@1I7c87k{7v0{{R3_Mwly0000CP)t-s{{R60|Nj600RI30Kw2_`00001 zbW%=J06^y0W&i*Hn|f4ObVOxyV{&P5bZKvH004NLm5@6Q!Y~j-Yx@*d(j$H?4N4TH zAXl)AytY@^G4d{OeG({X>}Vx`1^@s6!AV3xR9J=WmeCEvAPhuVf{`)+5?QiSR!U+e zr58-nQm)e74}S>17~4pvgt<{c;COJdP4Y6P;)7E#uS;}6q%L6IYO=MgaXtT}nY?cg zDA`+|g2hyRd9^@+j3D$ym=XCR1d)|Mu%@p5hv_^pfzX(=+ z(c<9%Kwq@@0@kd=;#}i-|DU{?vF?i&=jvJ@7x-`_a54m#8o{YGWBiA%JAiR$jlq*Z jR#1|pPI3)YAUXI1mJ#%->3NZH00000NkvXXu0mjfp0C6Z From 69830bb50a6654e238ce21445f6095d22923abf9 Mon Sep 17 00:00:00 2001 From: "tgstation-ci[bot]" <179393467+tgstation-ci[bot]@users.noreply.github.com> Date: Thu, 28 Nov 2024 15:17:39 +0000 Subject: [PATCH 009/149] Automatic changelog for PR #88096 [ci skip] --- html/changelogs/AutoChangeLog-pr-88096.yml | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-88096.yml diff --git a/html/changelogs/AutoChangeLog-pr-88096.yml b/html/changelogs/AutoChangeLog-pr-88096.yml new file mode 100644 index 0000000000000..c9a52657c9fc1 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-88096.yml @@ -0,0 +1,6 @@ +author: "Runi-c" +delete-after: True +changes: + - rscadd: "digitigrade lizards can wear certain shoes and suits" + - image: "added digitigrade shoes & oversuit templates" + - refactor: "improved digi clothing generator code" \ No newline at end of file From 115609c11301ebf800e8fbc16db9883383eb651e Mon Sep 17 00:00:00 2001 From: paganiy <126676387+paganiy@users.noreply.github.com> Date: Thu, 28 Nov 2024 19:23:18 +0400 Subject: [PATCH 010/149] Adds a new item to the chef traitor's uplink: Molt'Obeso sauce. (#87103) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## About The Pull Request A new item for 2 TC has been added to the chef's traitor uplink – Molt'Obeso sauce! Buying it, you get a bottle for 50 units, filled with this sauce. After eating Molt'Obese, you'll think you're still hungry. It also removes the limit on how much food you can eat, so you can just keep going and going, but you never get full. Plus, Molt'Obeso helps your body absorb more nutrients from food, so the food is even more nourishing with it. ## Why It's Good For The Game The Syndicate sabotages the NT station by making everyone fat? ## Changelog :cl: add: Add a new item to the chef traitor's uplink: Molt'Obeso sauce. A sauce that makes people want to eat too much. /:cl: --- code/__DEFINES/traits/declarations.dm | 2 ++ code/_globalvars/traits/_traits.dm | 1 + code/_globalvars/traits/admin_tooling.dm | 1 + code/_onclick/hud/screen_objects.dm | 4 +++ code/datums/components/food/edible.dm | 9 +++---- code/datums/mood.dm | 4 +++ .../game/objects/items/storage/uplink_kits.dm | 5 ++++ .../chemistry/reagents/food_reagents.dm | 25 +++++++++++++++++-- .../reagent_containers/cups/bottle.dm | 6 +++++ code/modules/uplink/uplink_items/job.dm | 8 ++++++ 10 files changed, 58 insertions(+), 7 deletions(-) diff --git a/code/__DEFINES/traits/declarations.dm b/code/__DEFINES/traits/declarations.dm index eb623ed708ec9..a4cd1f55e997b 100644 --- a/code/__DEFINES/traits/declarations.dm +++ b/code/__DEFINES/traits/declarations.dm @@ -51,6 +51,8 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai #define TRAIT_EMOTEMUTE "emotemute" #define TRAIT_DEAF "deaf" #define TRAIT_FAT "fat" +/// Always hungry. They can eat as much as they want without eating slowdown. +#define TRAIT_GLUTTON "glutton" #define TRAIT_HUSK "husk" ///Blacklisted from being revived via defibrillator #define TRAIT_DEFIB_BLACKLISTED "defib_blacklisted" diff --git a/code/_globalvars/traits/_traits.dm b/code/_globalvars/traits/_traits.dm index c54d78421a304..15cd11e6ae432 100644 --- a/code/_globalvars/traits/_traits.dm +++ b/code/_globalvars/traits/_traits.dm @@ -249,6 +249,7 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_FAST_CUFFING" = TRAIT_FAST_CUFFING, "TRAIT_FAST_TYING" = TRAIT_FAST_TYING, "TRAIT_FAT" = TRAIT_FAT, + "TRAIT_GLUTTON" = TRAIT_GLUTTON, "TRAIT_FEARLESS" = TRAIT_FEARLESS, "TRAIT_FENCE_CLIMBER" = TRAIT_FENCE_CLIMBER, "TRAIT_FINGERPRINT_PASSTHROUGH" = TRAIT_FINGERPRINT_PASSTHROUGH, diff --git a/code/_globalvars/traits/admin_tooling.dm b/code/_globalvars/traits/admin_tooling.dm index 7b7ca780a5409..5a3512f1d8f20 100644 --- a/code/_globalvars/traits/admin_tooling.dm +++ b/code/_globalvars/traits/admin_tooling.dm @@ -106,6 +106,7 @@ GLOBAL_LIST_INIT(admin_visible_traits, list( "TRAIT_FAST_CUFFING" = TRAIT_FAST_CUFFING, "TRAIT_FAST_TYING" = TRAIT_FAST_TYING, "TRAIT_FAT" = TRAIT_FAT, + "TRAIT_GLUTTON" = TRAIT_GLUTTON, "TRAIT_FEARLESS" = TRAIT_FEARLESS, "TRAIT_FENCE_CLIMBER" = TRAIT_FENCE_CLIMBER, "TRAIT_FISH_EATER" = TRAIT_FISH_EATER, diff --git a/code/_onclick/hud/screen_objects.dm b/code/_onclick/hud/screen_objects.dm index ec7070237d333..cbe26c0046be3 100644 --- a/code/_onclick/hud/screen_objects.dm +++ b/code/_onclick/hud/screen_objects.dm @@ -957,6 +957,10 @@ INITIALIZE_IMMEDIATE(/atom/movable/screen/splash) state = HUNGER_STATE_FAT return + if(HAS_TRAIT(hungry, TRAIT_GLUTTON)) + state = HUNGER_STATE_HUNGRY // Can't get enough + return + switch(hungry.nutrition) if(NUTRITION_LEVEL_FULL to INFINITY) state = HUNGER_STATE_FULL diff --git a/code/datums/components/food/edible.dm b/code/datums/components/food/edible.dm index 62e446f5a283a..7d0ca5dbe1275 100644 --- a/code/datums/components/food/edible.dm +++ b/code/datums/components/food/edible.dm @@ -368,12 +368,11 @@ Behavior that's still missing from this component that original food items had t var/fullness = eater.get_fullness() + 10 //The theoretical fullness of the person eating if they were to eat this var/time_to_eat = (eater == feeder) ? eat_time : EAT_TIME_FORCE_FEED - if(HAS_TRAIT(eater, TRAIT_VORACIOUS)) + if(HAS_TRAIT(eater, TRAIT_VORACIOUS) && !HAS_TRAIT(eater, TRAIT_GLUTTON)) //with TRAIT_GLUTTON you consume food without delay if(fullness < NUTRITION_LEVEL_FAT || (eater != feeder)) // No extra delay when being forcefed time_to_eat *= EAT_TIME_VORACIOUS_MULT else time_to_eat *= (fullness / NUTRITION_LEVEL_FAT) * EAT_TIME_VORACIOUS_FULL_MULT // takes longer to eat the more well fed you are - if(eater == feeder)//If you're eating it yourself. if(eat_time > 0 && !do_after(feeder, time_to_eat, eater, timed_action_flags = food_flags & FOOD_FINGER_FOOD ? IGNORE_USER_LOC_CHANGE | IGNORE_TARGET_LOC_CHANGE : NONE)) //Gotta pass the minimal eat time return @@ -385,12 +384,12 @@ Behavior that's still missing from this component that original food items had t var/message_to_consumer = "" var/message_to_blind_consumer = "" - if(junkiness && eater.satiety < -150 && eater.nutrition > NUTRITION_LEVEL_STARVING + 50 && !HAS_TRAIT(eater, TRAIT_VORACIOUS)) + if(junkiness && eater.satiety < -150 && eater.nutrition > NUTRITION_LEVEL_STARVING + 50 && !HAS_TRAIT(eater, TRAIT_VORACIOUS) && !HAS_TRAIT(eater, TRAIT_GLUTTON)) to_chat(eater, span_warning("You don't feel like eating any more junk food at the moment!")) return else if(fullness > (600 * (1 + eater.overeatduration / (4000 SECONDS)))) // The more you eat - the more you can eat - if(HAS_TRAIT(eater, TRAIT_VORACIOUS)) - message_to_nearby_audience = span_notice("[eater] voraciously forces \the [parent] down [eater.p_their()] throat..") + if(HAS_TRAIT(eater, TRAIT_VORACIOUS) || HAS_TRAIT(eater, TRAIT_GLUTTON)) + message_to_nearby_audience = span_notice("[eater] voraciously forces \the [parent] down [eater.p_their()] throat.") message_to_consumer = span_notice("You voraciously force \the [parent] down your throat.") else message_to_nearby_audience = span_warning("[eater] cannot force any more of \the [parent] to go down [eater.p_their()] throat!") diff --git a/code/datums/mood.dm b/code/datums/mood.dm index fe91e1db2c66c..d3f2ac70861e0 100644 --- a/code/datums/mood.dm +++ b/code/datums/mood.dm @@ -124,6 +124,10 @@ clear_mood_event(MOOD_CATEGORY_NUTRITION) return FALSE + if(HAS_TRAIT(mob_parent, TRAIT_GLUTTON)) + add_mood_event(MOOD_CATEGORY_NUTRITION, /datum/mood_event/hungry) //you'll never get enough + return TRUE + if(HAS_TRAIT(mob_parent, TRAIT_FAT) && !HAS_TRAIT(mob_parent, TRAIT_VORACIOUS)) add_mood_event(MOOD_CATEGORY_NUTRITION, /datum/mood_event/fat) return TRUE diff --git a/code/game/objects/items/storage/uplink_kits.dm b/code/game/objects/items/storage/uplink_kits.dm index 9e5ae3ba74b1c..3f813e50b45db 100644 --- a/code/game/objects/items/storage/uplink_kits.dm +++ b/code/game/objects/items/storage/uplink_kits.dm @@ -570,6 +570,11 @@ new /obj/item/book/granter/action/spell/mime/mimery_blockade(src) new /obj/item/book/granter/action/spell/mime/mimery_guns(src) +/obj/item/storage/box/syndie_kit/moltobeso/PopulateContents() + new /obj/item/reagent_containers/cup/bottle/moltobeso(src) + new /obj/item/reagent_containers/syringe(src) + new /obj/item/reagent_containers/dropper(src) + /obj/item/storage/box/syndie_kit/combat_baking/PopulateContents() new /obj/item/food/baguette/combat(src) for(var/i in 1 to 2) diff --git a/code/modules/reagents/chemistry/reagents/food_reagents.dm b/code/modules/reagents/chemistry/reagents/food_reagents.dm index 90937471bf1c4..e43512426dccf 100644 --- a/code/modules/reagents/chemistry/reagents/food_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/food_reagents.dm @@ -13,7 +13,7 @@ inverse_chem_val = 0.1 inverse_chem = null creation_purity = CONSUMABLE_STANDARD_PURITY - /// How much nutrition this reagent supplies + /// How much nutrition this reagent supplies. Look at get_nutriment_factor() for an understanding. var/nutriment_factor = 1 /// affects mood, typically higher for mixed drinks with more complex recipes' var/quality = 0 @@ -54,7 +54,7 @@ if(isitem(the_real_food) && !is_reagent_container(the_real_food)) exposed_mob.add_mob_memory(/datum/memory/good_food, food = the_real_food) -/// Gets just how much nutrition this reagent is worth for the passed mob +/// Gets just how much nutrition this reagent supplies per server tick to the eater /datum/reagent/consumable/proc/get_nutriment_factor(mob/living/carbon/eater) return nutriment_factor * REAGENTS_METABOLISM * purity * 2 @@ -861,6 +861,27 @@ taste_description = "rancid fungus" chemical_flags = REAGENT_CAN_BE_SYNTHESIZED +/datum/reagent/consumable/moltobeso + name = "Molt'Obeso" //pardon my Italian + description = "Concentrated gluttony." + color = "#f8fc36" + taste_description = "gluttony" + taste_mult = 0.3 + nutriment_factor = 0 //the essence of this sauce is to stimulate hunger and improve the absorption of calories from food eaten + metabolization_rate = 0.025 * REAGENTS_METABOLISM + metabolized_traits = list(TRAIT_GLUTTON) + chemical_flags = REAGENT_CAN_BE_SYNTHESIZED + +/datum/reagent/consumable/moltobeso/on_mob_life(mob/living/carbon/affected_mob, seconds_per_tick, times_fired) + . = ..() + for(var/datum/reagent/consumable/food in affected_mob.reagents.reagent_list) + if(food == src) + continue + var/food_factor = food.get_nutriment_factor(affected_mob) + if(food_factor <= 0) + continue + affected_mob.adjust_nutrition(food_factor * REM * seconds_per_tick) + /datum/reagent/consumable/eggrot name = "Rotten Eggyolk" description = "It smells absolutely dreadful." diff --git a/code/modules/reagents/reagent_containers/cups/bottle.dm b/code/modules/reagents/reagent_containers/cups/bottle.dm index f733a4dac8851..ff18c6a945655 100644 --- a/code/modules/reagents/reagent_containers/cups/bottle.dm +++ b/code/modules/reagents/reagent_containers/cups/bottle.dm @@ -255,6 +255,12 @@ desc = "A small bottle of Romerol. The REAL zombie powder." list_reagents = list(/datum/reagent/romerol = 30) +/obj/item/reagent_containers/cup/bottle/moltobeso + name = "Molt'Obeso bottle" + desc = "The revolutionary new sauce from Syndicate's culinary experts, designed to instantly reshape your figure! \ + The key to the effectiveness of this product lies in its unique formulation, which combines carefully selected ingredients to stimulate appetite and enhance the absorption of calories." + list_reagents = list(/datum/reagent/consumable/moltobeso = 50) + /obj/item/reagent_containers/cup/bottle/random_virus name = "Experimental disease culture bottle" desc = "A small bottle. Contains an untested viral culture in synthblood medium." diff --git a/code/modules/uplink/uplink_items/job.dm b/code/modules/uplink/uplink_items/job.dm index 9c0c92edcbfe7..953a6cf7ace5d 100644 --- a/code/modules/uplink/uplink_items/job.dm +++ b/code/modules/uplink/uplink_items/job.dm @@ -142,6 +142,14 @@ cost = 11 restricted_roles = list(JOB_COOK) +/datum/uplink_item/role_restricted/moltobeso + name = "Molt'Obeso Sauce Bottle" + desc = "A branded bottle of Molt'Obeso sauce. This sauce can stimulate hunger in people, leading them to eat more than they intended. \ + It also enhances the absorption of calories from the food consumed." + item = /obj/item/storage/box/syndie_kit/moltobeso + cost = 2 + restricted_roles = list(JOB_COOK) + /datum/uplink_item/role_restricted/turretbox name = "Disposable Sentry Gun" desc = "A disposable sentry gun deployment system cleverly disguised as a toolbox, apply wrench for functionality." From fffdcd11e6a8969e929fd1f166714d0191de8c4b Mon Sep 17 00:00:00 2001 From: "tgstation-ci[bot]" <179393467+tgstation-ci[bot]@users.noreply.github.com> Date: Thu, 28 Nov 2024 15:23:38 +0000 Subject: [PATCH 011/149] Automatic changelog for PR #87103 [ci skip] --- html/changelogs/AutoChangeLog-pr-87103.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-87103.yml diff --git a/html/changelogs/AutoChangeLog-pr-87103.yml b/html/changelogs/AutoChangeLog-pr-87103.yml new file mode 100644 index 0000000000000..d8aed4f42e1b2 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-87103.yml @@ -0,0 +1,4 @@ +author: "paganiy" +delete-after: True +changes: + - rscadd: "Add a new item to the chef traitor's uplink: Molt'Obeso sauce. A sauce that makes people want to eat too much." \ No newline at end of file From b4192098bf21d4f5dd628669d6ac227481d928f2 Mon Sep 17 00:00:00 2001 From: Ghom <42542238+Ghommie@users.noreply.github.com> Date: Thu, 28 Nov 2024 17:58:47 +0100 Subject: [PATCH 012/149] [NO GBP] Fixing the profound fisher component. (#88204) --- code/datums/components/profound_fisher.dm | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/code/datums/components/profound_fisher.dm b/code/datums/components/profound_fisher.dm index cc7e87aeb40af..62019ee3f6c67 100644 --- a/code/datums/components/profound_fisher.dm +++ b/code/datums/components/profound_fisher.dm @@ -17,6 +17,7 @@ if(!isgloves) RegisterSignal(parent, COMSIG_HOSTILE_PRE_ATTACKINGTARGET, PROC_REF(pre_attack)) + RegisterSignal(parent, COMSIG_MOB_COMPLETE_FISHING, PROC_REF(stop_fishing)) else var/obj/item/clothing/gloves = parent RegisterSignal(gloves, COMSIG_ITEM_EQUIPPED, PROC_REF(on_equip)) @@ -68,6 +69,7 @@ if(slot != ITEM_SLOT_GLOVES) return RegisterSignal(equipper, COMSIG_LIVING_UNARMED_ATTACK, PROC_REF(on_unarmed_attack)) + RegisterSignal(equipper, COMSIG_MOB_COMPLETE_FISHING, PROC_REF(stop_fishing)) /datum/component/profound_fisher/proc/open_rod_menu(datum/source, mob/user, list/modifiers) SIGNAL_HANDLER @@ -76,7 +78,7 @@ /datum/component/profound_fisher/proc/on_drop(datum/source, atom/dropper) SIGNAL_HANDLER - UnregisterSignal(dropper, COMSIG_LIVING_UNARMED_ATTACK) + UnregisterSignal(dropper, list(COMSIG_LIVING_UNARMED_ATTACK, COMSIG_MOB_COMPLETE_FISHING)) REMOVE_TRAIT(dropper, TRAIT_PROFOUND_FISHER, TRAIT_GENERIC) //this will cancel the current minigame if the fishing rod was internal. /datum/component/profound_fisher/proc/on_unarmed_attack(mob/living/source, atom/attack_target, proximity_flag, list/modifiers) @@ -108,19 +110,12 @@ return TRUE /datum/component/profound_fisher/proc/begin_fishing(mob/living/user, atom/target) - RegisterSignal(user, COMSIG_MOB_BEGIN_FISHING, PROC_REF(actually_fishing_with_internal_rod)) our_rod.melee_attack_chain(user, target) - UnregisterSignal(user, COMSIG_MOB_BEGIN_FISHING) + ADD_TRAIT(user, TRAIT_PROFOUND_FISHER, TRAIT_GENERIC) -/datum/component/profound_fisher/proc/actually_fishing_with_internal_rod(datum/source) - SIGNAL_HANDLER - ADD_TRAIT(source, TRAIT_PROFOUND_FISHER, REF(parent)) - RegisterSignal(source, COMSIG_MOB_COMPLETE_FISHING, PROC_REF(remove_profound_fisher)) - -/datum/component/profound_fisher/proc/remove_profound_fisher(datum/source) +/datum/component/profound_fisher/proc/stop_fishing(datum/source) SIGNAL_HANDLER REMOVE_TRAIT(source, TRAIT_PROFOUND_FISHER, TRAIT_GENERIC) - UnregisterSignal(source, COMSIG_MOB_COMPLETE_FISHING) /datum/component/profound_fisher/proc/pretend_fish(mob/living/source, atom/target) if(DOING_INTERACTION_WITH_TARGET(source, target)) From 7c1765c718257cc44bd11c482e179f0e409a99ca Mon Sep 17 00:00:00 2001 From: "tgstation-ci[bot]" <179393467+tgstation-ci[bot]@users.noreply.github.com> Date: Thu, 28 Nov 2024 16:59:06 +0000 Subject: [PATCH 013/149] Automatic changelog for PR #88204 [ci skip] --- html/changelogs/AutoChangeLog-pr-88204.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-88204.yml diff --git a/html/changelogs/AutoChangeLog-pr-88204.yml b/html/changelogs/AutoChangeLog-pr-88204.yml new file mode 100644 index 0000000000000..1fe1febd6a185 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-88204.yml @@ -0,0 +1,4 @@ +author: "Ghommie" +delete-after: True +changes: + - bugfix: "Player-controlled lobstrosities, space dragons, space carps and penguins can fish again." \ No newline at end of file From 2e429ce98889342a8c2520e7b50906f2e6792b80 Mon Sep 17 00:00:00 2001 From: Ghom <42542238+Ghommie@users.noreply.github.com> Date: Thu, 28 Nov 2024 19:28:24 +0100 Subject: [PATCH 014/149] Fixing/reworking explosive interactions with organ manip and fishing (#88232) ## About The Pull Request I have grown to dislike the previous implement of explosive fishing. It was particurly broken around fish sources that checked if the fishing spot was of a specific type, and the FISH_SOURCE_FLAG_EXPLOSIVE_MALUS flag only really worked around turfs because of the gap between pooling the spawn locations and spawning the loot, which would have made trying it on movables quite unsafe since they're moved to nullspace when deleted. This has lead me to rework how explosive fishing malus/exhaustion accumulates in a simplier and more effiient way. Fish are now spawned immediately, and the counter for the malus goes up by one each call, and decays over time at a rate of 1 every 5.5 seconds. This also fixes #88227. ## Why It's Good For The Game Easier implementation of explosive fishing and bugfix. ## Changelog :cl: fix: Bombing someone during organ manipulation no longer summons new organs. /:cl: --------- Co-authored-by: Time-Green <7501474+Time-Green@users.noreply.github.com> --- code/modules/fishing/sources/_fish_source.dm | 50 ++++++++++++-------- code/modules/fishing/sources/source_types.dm | 2 +- 2 files changed, 30 insertions(+), 22 deletions(-) diff --git a/code/modules/fishing/sources/_fish_source.dm b/code/modules/fishing/sources/_fish_source.dm index 64c9977fbb924..a80a2514762b5 100644 --- a/code/modules/fishing/sources/_fish_source.dm +++ b/code/modules/fishing/sources/_fish_source.dm @@ -88,8 +88,8 @@ GLOBAL_LIST_INIT(specific_fish_icons, generate_specific_fish_icons()) /// Background image name from /datum/asset/simple/fishing_minigame var/background = "background_default" var/fish_source_flags = NONE - /// If FISH_SOURCE_FLAG_EXPLOSIVE_MALUS is set, this will be used to keep track of the turfs where an explosion happened for when we'll spawn the loot. - var/list/exploded_turfs + /// If FISH_SOURCE_FLAG_EXPLOSIVE_MALUS is set, this will track of how much we're "exhausting" the system by bombing it repeatedly. + var/explosive_fishing_score = 0 ///When linked to a fishing portal, this will be the icon_state of this option in the radial menu var/radial_state = "default" ///When selected by the fishing portal, this will be the icon_state of the overlay shown on the machine. @@ -126,7 +126,8 @@ GLOBAL_LIST_INIT(specific_fish_icons, generate_specific_fish_icons()) stack_trace("wait_time_range for [type] is set but has length different than two") /datum/fish_source/Destroy() - exploded_turfs = null + if(explosive_fishing_score) + STOP_PROCESSING(SSprocessing, src) return ..() ///Called when src is set as the fish source of a fishing spot component @@ -474,29 +475,27 @@ GLOBAL_LIST_INIT(specific_fish_icons, generate_specific_fish_icons()) info = span_tooltip("boldened are the fish you're more likely to catch with your current setup. The opposite is true for smaller names", info) examine_text += span_info("[info]: [english_list(known_fishes)].") +///How much the explosive_fishing_score impacts explosive fishing. The higher the value, the stronger the malus for repeated calls +#define EXPLOSIVE_FISHING_MALUS_EXPONENT 0.55 +///How much the explosive_fishing_score is reduced each second. +#define EXPLOSIVE_FISHING_RECOVERY_RATE 0.18 + /datum/fish_source/proc/spawn_reward_from_explosion(atom/location, severity) - if(!(fish_source_flags & FISH_SOURCE_FLAG_EXPLOSIVE_MALUS)) - explosive_spawn(isturf(location) ? location : location.drop_location(), severity) - return - if(isnull(exploded_turfs)) - exploded_turfs = list() - addtimer(CALLBACK(src, PROC_REF(post_explosion_spawn)), 1) //run this the next tick. - var/turf/turf = get_turf(location) - var/peak_severity = max(exploded_turfs[turf], severity) - exploded_turfs[turf] = peak_severity - -/datum/fish_source/proc/post_explosion_spawn() - var/multiplier = 1/(length(exploded_turfs)**0.5) - for(var/turf/turf as anything in exploded_turfs) - explosive_spawn(turf, exploded_turfs[turf], multiplier) - exploded_turfs = null - -/datum/fish_source/proc/explosive_spawn(atom/location, severity, multiplier = 1) + SIGNAL_HANDLER + var/multiplier = 1 + if(fish_source_flags & FISH_SOURCE_FLAG_EXPLOSIVE_MALUS) + if(explosive_fishing_score <= 0) + explosive_fishing_score = 1 + START_PROCESSING(SSprocessing, src) + else + explosive_fishing_score++ + multiplier = explosive_fishing_score**-EXPLOSIVE_FISHING_MALUS_EXPONENT for(var/i in 1 to (severity + 2)) if(!prob((100 + 100 * severity)/i * multiplier)) continue var/reward_loot = pick_weight(get_fish_table(from_explosion = TRUE)) - var/atom/movable/reward = simple_dispense_reward(reward_loot, location, location) + var/atom/spawn_location = isturf(location) ? location : location.drop_location() + var/atom/movable/reward = simple_dispense_reward(reward_loot, spawn_location, location) if(isnull(reward)) continue if(isfish(reward)) @@ -508,6 +507,15 @@ GLOBAL_LIST_INIT(specific_fish_icons, generate_specific_fish_icons()) if(severity >= EXPLODE_DEVASTATE) reward.ex_act(EXPLODE_LIGHT) +/datum/fish_source/process(seconds_per_tick) + explosive_fishing_score -= EXPLOSIVE_FISHING_RECOVERY_RATE * seconds_per_tick + if(explosive_fishing_score <= 0) + STOP_PROCESSING(SSprocessing, src) + explosive_fishing_score = 0 + +#undef EXPLOSIVE_FISHING_MALUS_EXPONENT +#undef EXPLOSIVE_FISHING_RECOVERY_RATE + ///Called when releasing a fish in a fishing spot with the TRAIT_CATCH_AND_RELEASE trait. /datum/fish_source/proc/readd_fish(obj/item/fish/fish, mob/living/releaser) var/is_morbid = HAS_MIND_TRAIT(releaser, TRAIT_MORBID) diff --git a/code/modules/fishing/sources/source_types.dm b/code/modules/fishing/sources/source_types.dm index 1828091f0616e..c056000c45fde 100644 --- a/code/modules/fishing/sources/source_types.dm +++ b/code/modules/fishing/sources/source_types.dm @@ -601,7 +601,7 @@ seeds_to_draw_from -= seed_path var/picked_path = pick(seeds_to_draw_from) - return new picked_path(get_turf(fishing_spot)) + return new picked_path(spawn_location) /datum/fish_source/carp_rift catalog_description = "Space Dragon Rifts" From a9fe2fe29d5e7407e425ba657a42da9992e17679 Mon Sep 17 00:00:00 2001 From: "tgstation-ci[bot]" <179393467+tgstation-ci[bot]@users.noreply.github.com> Date: Thu, 28 Nov 2024 18:28:48 +0000 Subject: [PATCH 015/149] Automatic changelog for PR #88232 [ci skip] --- html/changelogs/AutoChangeLog-pr-88232.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-88232.yml diff --git a/html/changelogs/AutoChangeLog-pr-88232.yml b/html/changelogs/AutoChangeLog-pr-88232.yml new file mode 100644 index 0000000000000..b0899ab2f409b --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-88232.yml @@ -0,0 +1,4 @@ +author: "Ghommie" +delete-after: True +changes: + - bugfix: "Bombing someone during organ manipulation no longer summons new organs." \ No newline at end of file From fe7c8e1fde1bf8a02b31f7c87497d4eb3bb1ac67 Mon Sep 17 00:00:00 2001 From: carlarctg <53100513+carlarctg@users.noreply.github.com> Date: Thu, 28 Nov 2024 20:42:04 -0300 Subject: [PATCH 016/149] Adds some Fish Content (#88213) ## About The Pull Request Adds a new biotype, MOB_AQUATIC, indicating the mob is water-themed somehow. Given to carp, lobstrosities, frogs, axolotls, penguins, fire sharks. Aquatic mobs can be hooked by fishing rods, even without a jawed fishing hook installed. The carp and fish infusion sets now give the infusee the aquatic biotype. Added support for infusions adding a biotype. You can check for a fish's pulse with a stethoscope, which will tell you its status even without fishing skill. Refined fish health status checks to be more precise. Added 'Fishy' Reagent, a version of strange reagent that only works for fish or aquatic biotype mobs. It's made with omnizine, saltwater, and carpotoxin or tetrodotoxin. Added a lifish chemical reaction that creates fish. ## Why It's Good For The Game Fish content fish content fish content > Adds a new biotype, MOB_AQUATIC, indicating the mob is water-themed somehow. Given to carp, lobstrosities, frogs, axolotls, penguins, fire sharks. We were really missing this one by now. > Aquatic mobs can be hooked by fishing rods, even without a jawed fishing hook installed. > The carp and fish infusion sets now give the infusee the aquatic biotype. Added support for infusions adding a biotype. I want to reel in fish people. This is going to be hilarious. > You can check for a fish's pulse with a stethoscope, which will tell you its status even without fishing skill. Fish doctor content - also lets you see the exact status of a fish's health even if you haven't interacted w/ fishing that shift. > Added 'Fishy' Reagent, a version of strange reagent that only works for fish or aquatic biotype mobs. It's made with omnizine, saltwater, and carpotoxin or tetrodotoxin. A somewhat easier to get version of strange reagent, purely for fish, as they die very easily and the road to making SR is a large diversion. I might add this to cargo, maybe? > Added a lifish chemical reaction that creates fish. Fish. fish fish fish fish fish. @Ghommie ## Changelog :cl: add: Adds a new biotype, MOB_AQUATIC, indicating the mob is water-themed somehow. Given to carp, lobstrosities, frogs, axolotls, penguins, fire sharks. add: Aquatic mobs can be hooked by fishing rods, even without a jawed fishing hook installed. add: The carp and fish infusion sets now give the infusee the aquatic biotype. Added support for infusions adding a biotype. add: You can check for a fish's pulse with a stethoscope, which will tell you its status even without fishing skill. qol: Refined fish health status checks to be more precise. add: Added 'Fishy' Reagent, a version of strange reagent that only works for fish or aquatic biotype mobs. It's made with omnizine, saltwater, and carpotoxin or tetrodotoxin. add: Added a lifish chemical reaction that creates fish. /:cl: --------- Co-authored-by: _0Steven <42909981+00-Steven@users.noreply.github.com> Co-authored-by: Ghom <42542238+Ghommie@users.noreply.github.com> --- code/__DEFINES/mobs.dm | 2 + code/datums/elements/organ_set_bonus.dm | 22 ++++++ .../dna_infuser/organ_sets/carp_organs.dm | 1 + .../dna_infuser/organ_sets/fish_organs.dm | 1 + .../dna_infuser/organ_sets/roach_organs.dm | 9 +-- code/modules/fishing/fish/_fish.dm | 69 ++++++++++++++----- code/modules/fishing/fish/fish_traits.dm | 1 + code/modules/fishing/fish/types/mining.dm | 3 + code/modules/fishing/fish/types/ruins.dm | 3 + code/modules/fishing/fishing_equipment.dm | 7 +- .../mob/living/basic/heretic/fire_shark.dm | 2 +- .../basic/lavaland/lobstrosity/lobstrosity.dm | 1 + .../mob/living/basic/pets/penguin/penguin.dm | 1 + .../mob/living/basic/space_fauna/carp/carp.dm | 2 +- .../mob/living/basic/vermin/axolotl.dm | 2 +- code/modules/mob/living/basic/vermin/frog.dm | 2 +- .../chemistry/reagents/medicine_reagents.dm | 30 ++++++++ .../reagents/chemistry/recipes/medicine.dm | 10 +++ .../reagents/chemistry/recipes/others.dm | 23 +++++++ .../reagent_containers/cups/bottle.dm | 5 ++ 20 files changed, 166 insertions(+), 30 deletions(-) diff --git a/code/__DEFINES/mobs.dm b/code/__DEFINES/mobs.dm index a1496d2e13876..11182e1ea2f6e 100644 --- a/code/__DEFINES/mobs.dm +++ b/code/__DEFINES/mobs.dm @@ -73,6 +73,8 @@ #define MOB_PLANT (1 << 10) ///The mob is a goopy creature, probably coming from xenobiology. #define MOB_SLIME (1 << 11) +/// Mob is fish or water-related. +#define MOB_AQUATIC (1 << 12) //Lung respiration type flags #define RESPIRATION_OXYGEN (1 << 0) diff --git a/code/datums/elements/organ_set_bonus.dm b/code/datums/elements/organ_set_bonus.dm index 118c64fbeafa4..a8d1d3c7ad736 100644 --- a/code/datums/elements/organ_set_bonus.dm +++ b/code/datums/elements/organ_set_bonus.dm @@ -57,6 +57,10 @@ var/required_biotype = MOB_ORGANIC /// A list of traits added to the mob upon bonus activation, can be of any length. var/list/bonus_traits = list() + /// Bonus biotype to add on bonus activation. + var/bonus_biotype + /// If the biotype was added - used to check if we should remove the biotype or not, on organ set loss. + var/biotype_added = FALSE /// Limb overlay to apply upon activation var/limb_overlay /// Color priority for limb overlay @@ -80,10 +84,20 @@ if((required_biotype == MOB_ORGANIC) && !owner.can_mutate()) return FALSE bonus_active = TRUE + // Add traits if(length(bonus_traits)) owner.add_traits(bonus_traits, REF(src)) + + // Add biotype + if(owner.mob_biotypes & bonus_biotype) + biotype_added = FALSE + owner.mob_biotypes |= bonus_biotype + biotype_added = TRUE + if(bonus_activate_text) to_chat(owner, bonus_activate_text) + + // Add limb overlay if(!iscarbon(owner) || !limb_overlay) return TRUE var/mob/living/carbon/carbon_owner = owner @@ -96,10 +110,18 @@ /datum/status_effect/organ_set_bonus/proc/disable_bonus() SHOULD_CALL_PARENT(TRUE) bonus_active = FALSE + + // Remove traits if(length(bonus_traits)) owner.remove_traits(bonus_traits, REF(src)) + // Remove biotype (if added) + if(biotype_added) + owner.mob_biotypes &= ~bonus_biotype + if(bonus_deactivate_text) to_chat(owner, bonus_deactivate_text) + + // Remove limb overlay if(!iscarbon(owner) || QDELETED(owner) || !limb_overlay) return var/mob/living/carbon/carbon_owner = owner diff --git a/code/game/machinery/dna_infuser/organ_sets/carp_organs.dm b/code/game/machinery/dna_infuser/organ_sets/carp_organs.dm index 1e4bc41ae415b..9a873b5e373f6 100644 --- a/code/game/machinery/dna_infuser/organ_sets/carp_organs.dm +++ b/code/game/machinery/dna_infuser/organ_sets/carp_organs.dm @@ -10,6 +10,7 @@ bonus_activate_text = span_notice("Carp DNA is deeply infused with you! You've learned how to propel yourself through space!") bonus_deactivate_text = span_notice("Your DNA is once again mostly yours, and so fades your ability to space-swim...") bonus_traits = list(TRAIT_SPACEWALK) + bonus_biotype = MOB_AQUATIC limb_overlay = /datum/bodypart_overlay/texture/carpskin color_overlay_priority = LIMB_COLOR_CARP_INFUSION diff --git a/code/game/machinery/dna_infuser/organ_sets/fish_organs.dm b/code/game/machinery/dna_infuser/organ_sets/fish_organs.dm index 7dda9ba15639d..69f5a23798ff5 100644 --- a/code/game/machinery/dna_infuser/organ_sets/fish_organs.dm +++ b/code/game/machinery/dna_infuser/organ_sets/fish_organs.dm @@ -23,6 +23,7 @@ TRAIT_EXPANDED_FOV, //fish vision TRAIT_WATER_ADAPTATION, ) + bonus_biotype = MOB_AQUATIC /datum/status_effect/organ_set_bonus/fish/enable_bonus() . = ..() diff --git a/code/game/machinery/dna_infuser/organ_sets/roach_organs.dm b/code/game/machinery/dna_infuser/organ_sets/roach_organs.dm index 03955f06ffe82..2c07038fd1709 100644 --- a/code/game/machinery/dna_infuser/organ_sets/roach_organs.dm +++ b/code/game/machinery/dna_infuser/organ_sets/roach_organs.dm @@ -16,10 +16,9 @@ // - Immunity to nuke gibs // - Nukes come with radiation (not actually but yknow) bonus_traits = list(TRAIT_NUKEIMMUNE, TRAIT_RADIMMUNE, TRAIT_VIRUS_RESISTANCE) + bonus_biotype = MOB_BUG /// Armor type attached to the owner's physiology var/datum/armor/given_armor = /datum/armor/roach_internal_armor - /// Storing biotypes pre-organ bonus applied so we don't remove bug from mobs which should have it. - var/old_biotypes = NONE /datum/status_effect/organ_set_bonus/roach/enable_bonus() . = ..() @@ -29,9 +28,6 @@ var/mob/living/carbon/human/human_owner = owner human_owner.physiology.armor = human_owner.physiology.armor.add_other_armor(given_armor) - old_biotypes = human_owner.mob_biotypes - human_owner.mob_biotypes |= MOB_BUG - /datum/status_effect/organ_set_bonus/roach/disable_bonus() . = ..() if(!ishuman(owner) || QDELETED(owner)) @@ -40,9 +36,6 @@ var/mob/living/carbon/human/human_owner = owner human_owner.physiology.armor = human_owner.physiology.armor.subtract_other_armor(given_armor) - if(!(old_biotypes & MOB_BUG)) // only remove bug if it wasn't there before - human_owner.mob_biotypes &= ~MOB_BUG - /// Roach heart: /// Reduces damage taken from brute attacks from behind, /// but increases duration of knockdowns diff --git a/code/modules/fishing/fish/_fish.dm b/code/modules/fishing/fish/_fish.dm index cee77ae003d88..fcad429c2b9eb 100644 --- a/code/modules/fishing/fish/_fish.dm +++ b/code/modules/fishing/fish/_fish.dm @@ -219,8 +219,26 @@ if(istype(held_item, /obj/item/fish_analyzer)) context[SCREENTIP_CONTEXT_LMB] = "Scan" return CONTEXTUAL_SCREENTIP_SET + if(istype(held_item, /obj/item/clothing/neck/stethoscope)) + context[SCREENTIP_CONTEXT_LMB] = "Check Pulse" + return CONTEXTUAL_SCREENTIP_SET return NONE +/obj/item/fish/item_interaction(mob/living/user, obj/item/tool, list/modifiers) + if(!istype(tool, /obj/item/clothing/neck/stethoscope)) + return NONE + user.balloon_alert_to_viewers("checking pulse") + if(!do_after(user, 2.5 SECONDS, src)) + return ITEM_INTERACT_FAILURE + // Sir... I'm afraid your fish is dying. + user.visible_message(span_notice("[user] checks the pulse of [src] with [tool]."), span_notice("You check the pulse of [src] with [tool].")) + var/warns = get_health_warnings(user, always_deep = TRUE) + if(!warns) + to_chat(user, span_notice("[src] appears to be perfectly healthy!")) + return ITEM_INTERACT_SUCCESS + to_chat(user, warns) + return ITEM_INTERACT_SUCCESS + /obj/item/fish/interact_with_atom_secondary(atom/interacting_with, mob/living/user, list/modifiers) if(!HAS_TRAIT(interacting_with, TRAIT_CATCH_AND_RELEASE)) return NONE @@ -434,27 +452,46 @@ /obj/item/fish/examine(mob/user) . = ..() - if(HAS_MIND_TRAIT(user, TRAIT_EXAMINE_DEEPER_FISH)) - if(status == FISH_DEAD) - . += span_deadsay("It's [HAS_MIND_TRAIT(user, TRAIT_NAIVE) ? "taking the big snooze" : "dead"].") - else - var/list/warnings = list() - if(is_starving()) - warnings += "starving" - if(!HAS_TRAIT(src, TRAIT_FISH_STASIS) && !proper_environment()) - warnings += "drowning" - if(health < initial(health) * 0.6) - warnings += "sick" - if(length(warnings)) - . += span_warning("It's [english_list(warnings)].") if(HAS_MIND_TRAIT(user, TRAIT_EXAMINE_FISH)) . += span_notice("It's [size] cm long.") . += span_notice("It weighs [weight] g.") - if(HAS_TRAIT(src, TRAIT_FISHING_BAIT)) - . += span_smallnoticeital("It can be used as a fishing bait.") + + . += get_health_warnings(user, always_deep = FALSE) + + if(HAS_TRAIT(src, TRAIT_FISHING_BAIT)) + . += span_smallnoticeital("It can be used as a fishing bait.") + if(bites_amount) . += span_warning("It's been bitten by someone.") +/obj/item/fish/proc/get_health_warnings(mob/user, always_deep = FALSE) + if(!HAS_MIND_TRAIT(user, TRAIT_EXAMINE_DEEPER_FISH) && !always_deep) + return + if(status == FISH_DEAD) + return span_deadsay("It's [HAS_MIND_TRAIT(user, TRAIT_NAIVE) ? "taking the big snooze" : "dead"].") + + var/list/warnings = list() + if(is_starving()) + warnings += "starving" + if(!HAS_TRAIT(src, TRAIT_FISH_STASIS) && !proper_environment()) + warnings += "drowning" + + var/health_ratio = health / initial(health) + switch(health_ratio) + if(0 to 0.25) + warnings += "dying" + if(0.25 to 0.5) + warnings += "very unhealthy" + if(0.5 to 0.75) + warnings += "unhealthy" + if(0.75 to 0.9) + warnings += "mostly healthy" + + if(length(warnings)) + . += span_warning("It's [english_list(warnings)].") + + return . + /** * This proc takes a base size, base weight and deviation arguments to generate new size and weight through a gaussian distribution (bell curve) * Mainly used to determinate the size and weight of caught fish. @@ -961,7 +998,7 @@ var/datum/reagent/medicine/strange_reagent/revival = locate() in reagents if(!revival) return - if(reagents[revival] >= 2 * w_class) + if(reagents[revival] >= 2 * w_class && revival.pre_rez_check(src)) set_status(FISH_ALIVE) else balloon_alert_to_viewers("twitches for a moment!") diff --git a/code/modules/fishing/fish/fish_traits.dm b/code/modules/fishing/fish/fish_traits.dm index aa045c6308bf5..c3b813b5b4828 100644 --- a/code/modules/fishing/fish/fish_traits.dm +++ b/code/modules/fishing/fish/fish_traits.dm @@ -596,6 +596,7 @@ GLOBAL_LIST_INIT(spontaneous_fish_traits, populate_spontaneous_fish_traits()) diff_traits_inheritability = 25 catalog_description = "This fish will invert the gravity of the bait at random. May fall upward outside after being caught." added_difficulty = 20 + reagents_to_add = list(/datum/reagent/gravitum = 2.3) /datum/fish_trait/antigrav/minigame_mod(obj/item/fishing_rod/rod, mob/fisherman, datum/fishing_challenge/minigame) minigame.special_effects |= FISHING_MINIGAME_RULE_ANTIGRAV diff --git a/code/modules/fishing/fish/types/mining.dm b/code/modules/fishing/fish/types/mining.dm index 3a1d6ff83107f..4ba63bfdb6579 100644 --- a/code/modules/fishing/fish/types/mining.dm +++ b/code/modules/fishing/fish/types/mining.dm @@ -143,6 +143,9 @@ /obj/item/fish/boned/make_edible(weight_val) return //it's all bones and no meat. +/obj/item/fish/boned/get_health_warnings(mob/user, always_deep = FALSE) + return list(span_deadsay("It's bones.")) + /obj/item/fish/lavaloop name = "lavaloop fish" fish_id = "lavaloop" diff --git a/code/modules/fishing/fish/types/ruins.dm b/code/modules/fishing/fish/types/ruins.dm index a9a7148986775..233c6961d26da 100644 --- a/code/modules/fishing/fish/types/ruins.dm +++ b/code/modules/fishing/fish/types/ruins.dm @@ -37,6 +37,9 @@ /obj/item/fish/mastodon/get_export_price(price, elasticity_percent) return ..() * 1.2 //This should push its soft-capped (it's pretty big) price a bit above the rest +/obj/item/fish/mastodon/get_health_warnings(mob/user, always_deep = FALSE) + return list(span_deadsay("It's bones.")) + ///From the cursed spring /obj/item/fish/soul name = "soulfish" diff --git a/code/modules/fishing/fishing_equipment.dm b/code/modules/fishing/fishing_equipment.dm index ab72b0b0fb26e..d1ed33e9a2154 100644 --- a/code/modules/fishing/fishing_equipment.dm +++ b/code/modules/fishing/fishing_equipment.dm @@ -174,6 +174,9 @@ ///Check if tha target can be caught by the hook /obj/item/fishing_hook/proc/can_be_hooked(atom/target) + if(isliving(target)) + var/mob/living/mob = target + return (mob.mob_biotypes & MOB_AQUATIC) return isitem(target) ///Any special effect when hooking a target that's not managed by the fishing rod. @@ -430,12 +433,12 @@ ///From the fishing mystery box. It's basically a lazarus and a few bottles of strange reagents. /obj/item/storage/box/fish_revival_kit name = "fish revival kit" - desc = "Become a fish doctor today." + desc = "Become a fish doctor today. A label on the side indicates that fish require two to ten reagent units to be splashed onto them for revival, depending on size." illustration = "fish" /obj/item/storage/box/fish_revival_kit/PopulateContents() new /obj/item/lazarus_injector(src) - new /obj/item/reagent_containers/cup/bottle/strange_reagent(src) + new /obj/item/reagent_containers/cup/bottle/fishy_reagent(src) new /obj/item/reagent_containers/cup(src) //to splash the reagents on the fish. new /obj/item/storage/fish_case(src) new /obj/item/storage/fish_case(src) diff --git a/code/modules/mob/living/basic/heretic/fire_shark.dm b/code/modules/mob/living/basic/heretic/fire_shark.dm index 1ac4ccb7b237a..0dfb9a3a1578c 100644 --- a/code/modules/mob/living/basic/heretic/fire_shark.dm +++ b/code/modules/mob/living/basic/heretic/fire_shark.dm @@ -5,7 +5,7 @@ icon_state = "fire_shark" icon_living = "fire_shark" pass_flags = PASSTABLE | PASSMOB - mob_biotypes = MOB_ORGANIC | MOB_BEAST + mob_biotypes = MOB_ORGANIC | MOB_BEAST | MOB_AQUATIC speed = -0.5 health = 16 maxHealth = 16 diff --git a/code/modules/mob/living/basic/lavaland/lobstrosity/lobstrosity.dm b/code/modules/mob/living/basic/lavaland/lobstrosity/lobstrosity.dm index d8288360bd1a2..ebca48f2fa201 100644 --- a/code/modules/mob/living/basic/lavaland/lobstrosity/lobstrosity.dm +++ b/code/modules/mob/living/basic/lavaland/lobstrosity/lobstrosity.dm @@ -12,6 +12,7 @@ maxHealth = 150 health = 150 obj_damage = 15 + mob_biotypes = MOB_ORGANIC|MOB_BEAST|MOB_AQUATIC melee_damage_lower = 15 melee_damage_upper = 19 attack_verb_continuous = "snips" diff --git a/code/modules/mob/living/basic/pets/penguin/penguin.dm b/code/modules/mob/living/basic/pets/penguin/penguin.dm index 0df0dfedcb29c..376234f3a3e52 100644 --- a/code/modules/mob/living/basic/pets/penguin/penguin.dm +++ b/code/modules/mob/living/basic/pets/penguin/penguin.dm @@ -11,6 +11,7 @@ response_harm_simple = "kick" faction = list(FACTION_NEUTRAL) + mob_biotypes = MOB_ORGANIC|MOB_BEAST|MOB_AQUATIC ai_controller = /datum/ai_controller/basic_controller/penguin ///it can lay an egg? var/can_lay_eggs = TRUE diff --git a/code/modules/mob/living/basic/space_fauna/carp/carp.dm b/code/modules/mob/living/basic/space_fauna/carp/carp.dm index b16a00a6906b1..acd72af2b3889 100644 --- a/code/modules/mob/living/basic/space_fauna/carp/carp.dm +++ b/code/modules/mob/living/basic/space_fauna/carp/carp.dm @@ -19,7 +19,7 @@ icon_dead = "base_dead" icon_gib = "carp_gib" gold_core_spawnable = HOSTILE_SPAWN - mob_biotypes = MOB_ORGANIC | MOB_BEAST + mob_biotypes = MOB_ORGANIC | MOB_BEAST | MOB_AQUATIC health = 25 maxHealth = 25 pressure_resistance = 200 diff --git a/code/modules/mob/living/basic/vermin/axolotl.dm b/code/modules/mob/living/basic/vermin/axolotl.dm index 3b1f630df40f1..2ee244a7f62e4 100644 --- a/code/modules/mob/living/basic/vermin/axolotl.dm +++ b/code/modules/mob/living/basic/vermin/axolotl.dm @@ -12,7 +12,7 @@ density = FALSE pass_flags = PASSTABLE | PASSGRILLE | PASSMOB mob_size = MOB_SIZE_TINY - mob_biotypes = MOB_ORGANIC | MOB_BEAST + mob_biotypes = MOB_ORGANIC|MOB_BEAST|MOB_AQUATIC gold_core_spawnable = FRIENDLY_SPAWN response_help_continuous = "pets" diff --git a/code/modules/mob/living/basic/vermin/frog.dm b/code/modules/mob/living/basic/vermin/frog.dm index d2a634b7e9edd..169fa4e833563 100644 --- a/code/modules/mob/living/basic/vermin/frog.dm +++ b/code/modules/mob/living/basic/vermin/frog.dm @@ -4,7 +4,7 @@ icon_state = "frog" icon_living = "frog" icon_dead = "frog_dead" - mob_biotypes = MOB_ORGANIC|MOB_BEAST + mob_biotypes = MOB_ORGANIC|MOB_BEAST|MOB_AQUATIC verb_say = "ribbits" verb_ask = "ribbits inquisitively" verb_exclaim = "croaks" diff --git a/code/modules/reagents/chemistry/reagents/medicine_reagents.dm b/code/modules/reagents/chemistry/reagents/medicine_reagents.dm index da743f9656352..9a169257e1c0c 100644 --- a/code/modules/reagents/chemistry/reagents/medicine_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/medicine_reagents.dm @@ -921,6 +921,10 @@ /// The maximum amount of damage we can revive from, as a ratio of max health var/max_revive_damage_ratio = 2 +// To override for subtypes. +/datum/reagent/medicine/strange_reagent/proc/pre_rez_check(atom/thing_to_rez) + return TRUE + /datum/reagent/medicine/strange_reagent/instant name = "Stranger Reagent" instant = TRUE @@ -980,6 +984,11 @@ exposed_mob.do_jitter_animation(10) return + if(!pre_rez_check(exposed_mob)) + exposed_mob.visible_message(span_warning("[exposed_mob]'s body twitches slightly.")) + exposed_mob.do_jitter_animation(1) + return + exposed_mob.visible_message(span_warning("[exposed_mob]'s body starts convulsing!")) exposed_mob.notify_revival("Your body is being revived with Strange Reagent!") exposed_mob.do_jitter_animation(10) @@ -1010,6 +1019,27 @@ if(need_mob_update) return UPDATE_MOB_HEALTH +/datum/reagent/medicine/strange_reagent/fishy_reagent + name = "Fishy Reagent" + description = "This reagent has a chemical composition very similar to that of Strange Reagent, however, it seems to work purely and only on... fish. Or at least, aquatic creatures." + reagent_state = LIQUID + color = "#5ee8b3" + metabolization_rate = 1.25 * REAGENTS_METABOLISM + taste_description = "magnetic scales" + ph = 0.5 + chemical_flags = REAGENT_CAN_BE_SYNTHESIZED + +// only revives fish. +/datum/reagent/medicine/strange_reagent/fishy_reagent/pre_rez_check(atom/thing_to_rez) + if(ismob(thing_to_rez)) + var/mob/living/mob_to_rez = thing_to_rez + if(mob_to_rez.mob_biotypes & MOB_AQUATIC) + return TRUE + return FALSE + if(isfish(thing_to_rez)) + return TRUE + return FALSE + /datum/reagent/medicine/mannitol name = "Mannitol" description = "Efficiently restores brain damage." diff --git a/code/modules/reagents/chemistry/recipes/medicine.dm b/code/modules/reagents/chemistry/recipes/medicine.dm index 868917893c90c..84f251b759fad 100644 --- a/code/modules/reagents/chemistry/recipes/medicine.dm +++ b/code/modules/reagents/chemistry/recipes/medicine.dm @@ -208,6 +208,16 @@ required_reagents = list(/datum/reagent/medicine/omnizine/protozine = 1, /datum/reagent/water/holywater = 1, /datum/reagent/toxin/mutagen = 1) reaction_tags = REACTION_TAG_EASY | REACTION_TAG_HEALING | REACTION_TAG_PLANT | REACTION_TAG_OTHER +/datum/chemical_reaction/medicine/fishy_reagent + results = list(/datum/reagent/medicine/strange_reagent/fishy_reagent = 3) + required_reagents = list(/datum/reagent/medicine/omnizine = 1, /datum/reagent/water/salt = 1, /datum/reagent/toxin/carpotoxin = 1) + reaction_tags = REACTION_TAG_EASY | REACTION_TAG_HEALING | REACTION_TAG_OTHER + +/datum/chemical_reaction/medicine/fishy_reagent/alt + results = list(/datum/reagent/medicine/strange_reagent/fishy_reagent = 6) + required_reagents = list(/datum/reagent/medicine/omnizine = 1, /datum/reagent/water/salt = 1, /datum/reagent/toxin/tetrodotoxin = 1) + reaction_tags = REACTION_TAG_EASY | REACTION_TAG_HEALING | REACTION_TAG_OTHER + /datum/chemical_reaction/medicine/mannitol results = list(/datum/reagent/medicine/mannitol = 3) required_reagents = list(/datum/reagent/consumable/sugar = 1, /datum/reagent/hydrogen = 1, /datum/reagent/water = 1) diff --git a/code/modules/reagents/chemistry/recipes/others.dm b/code/modules/reagents/chemistry/recipes/others.dm index 542850ac9beae..6219fc964575b 100644 --- a/code/modules/reagents/chemistry/recipes/others.dm +++ b/code/modules/reagents/chemistry/recipes/others.dm @@ -575,6 +575,29 @@ new /mob/living/basic/pet/dog/corgi(location) ..() +/datum/chemical_reaction/lifish + required_reagents = list(/datum/reagent/medicine/strange_reagent/fishy_reagent = 1, /datum/reagent/medicine/c2/synthflesh = 1, /datum/reagent/blood = 1) + required_temp = 374 + reaction_flags = REACTION_INSTANT + reaction_tags = REACTION_TAG_EASY | REACTION_TAG_UNIQUE + +/datum/chemical_reaction/lifish/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume) + var/location = get_turf(holder.my_atom) + + // create fish possibles + var/list/fish_types = list() + for(var/path in subtypesof(/obj/item/fish)) + var/obj/item/fish/fake_fish = path + if(initial(fake_fish.random_case_rarity) == FISH_RARITY_NOPE) // means they aren't mean to be randomly available + continue + fish_types |= path + + // spawn from popssible fishes + for(var/i in 1 to rand(1, created_volume)) // More flop. + var/obj/item/fish/spawned_fish = pick(fish_types) + new spawned_fish(location) + return ..() + //monkey powder heehoo /datum/chemical_reaction/monkey_powder results = list(/datum/reagent/monkey_powder = 5) diff --git a/code/modules/reagents/reagent_containers/cups/bottle.dm b/code/modules/reagents/reagent_containers/cups/bottle.dm index ff18c6a945655..4c757e0e14691 100644 --- a/code/modules/reagents/reagent_containers/cups/bottle.dm +++ b/code/modules/reagents/reagent_containers/cups/bottle.dm @@ -134,6 +134,11 @@ desc = "A small bottle. May be used to revive people." list_reagents = list(/datum/reagent/medicine/strange_reagent = 30) +/obj/item/reagent_containers/cup/bottle/fishy_reagent + name = "Fishy Reagent Bottle" + desc = "A small bottle. May be used to revive fish." + list_reagents = list(/datum/reagent/medicine/strange_reagent/fishy_reagent = 30) + /obj/item/reagent_containers/cup/bottle/traitor name = "syndicate bottle" desc = "A small bottle. Contains a random nasty chemical." From 603bf8edcc8a7eb056d71dff42a0f7922d84fb24 Mon Sep 17 00:00:00 2001 From: "tgstation-ci[bot]" <179393467+tgstation-ci[bot]@users.noreply.github.com> Date: Thu, 28 Nov 2024 23:42:23 +0000 Subject: [PATCH 017/149] Automatic changelog for PR #88213 [ci skip] --- html/changelogs/AutoChangeLog-pr-88213.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-88213.yml diff --git a/html/changelogs/AutoChangeLog-pr-88213.yml b/html/changelogs/AutoChangeLog-pr-88213.yml new file mode 100644 index 0000000000000..ecffed795f669 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-88213.yml @@ -0,0 +1,10 @@ +author: "carlarctg" +delete-after: True +changes: + - rscadd: "Adds a new biotype, MOB_AQUATIC, indicating the mob is water-themed somehow. Given to carp, lobstrosities, frogs, axolotls, penguins, fire sharks." + - rscadd: "Aquatic mobs can be hooked by fishing rods, even without a jawed fishing hook installed." + - rscadd: "The carp and fish infusion sets now give the infusee the aquatic biotype. Added support for infusions adding a biotype." + - rscadd: "You can check for a fish's pulse with a stethoscope, which will tell you its status even without fishing skill." + - qol: "Refined fish health status checks to be more precise." + - rscadd: "Added 'Fishy' Reagent, a version of strange reagent that only works for fish or aquatic biotype mobs. It's made with omnizine, saltwater, and carpotoxin or tetrodotoxin." + - rscadd: "Added a lifish chemical reaction that creates fish." \ No newline at end of file From 2522791fc5cf4ceb7d4795b785b31924b41d39ee Mon Sep 17 00:00:00 2001 From: carlarctg <53100513+carlarctg@users.noreply.github.com> Date: Thu, 28 Nov 2024 21:21:28 -0300 Subject: [PATCH 018/149] Adds some tips for most of my changes to the game (#88186) ## About The Pull Request Adds some tips for most of my changes to the game. ## Why It's Good For The Game Player visibility is important to see what cool features there are and tips are kind of, well, poorly mantained, honestly. Like, the last one was about bitrunning. ## Changelog :cl: qol: Added some tips of the round. /:cl: --------- Co-authored-by: MrMelbert <51863163+MrMelbert@users.noreply.github.com> Co-authored-by: Jacquerel Co-authored-by: norsvenska <73006946+norsvenska@users.noreply.github.com> --- strings/tips.txt | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/strings/tips.txt b/strings/tips.txt index 2e80296af2258..1dc5626606b18 100644 --- a/strings/tips.txt +++ b/strings/tips.txt @@ -290,3 +290,26 @@ You don't need to destroy a Spacecoin machine to make your funds stop draining. As a Bitrunner, upgrading your quantum server will increase rewards and reduce downtime. As a Bitrunner, your avatar has a domain info ability which will give you clues to help complete virtual domains. Bitrunning is a crime. +You can right click someone with wire cutters, jaws of life, and box cutters to instantly snap cablecuffs or zipties. The jaws can even instantly break handcuffs! +You can alt-click tank transfer valves to remove a tank from them. +You can use a multitool in your hand to track the area's local APC. +Some items, when examined, are labeled as 'crafting components', which means you can smack them with another item to directly construct a recipe. Try using an igniter on a rod! +You can further the cycle of life by having two adult plushies play with eachother, creating a smaller junior child plushie. +Most species have only 32 teeth for use in dental implants. Moths have none. Lizards have seventy five. +As a Changeling, Repurposed Glands will break bolas, disable stuns, and give you a hefty speed boost at the cost of the use of your arms - which includes the ability to open restricted airlocks. +As a Geneticist, you should usually save all mutations you unlock. Negative mutations will increase your genetic stability, allowing you to keep more positive mutations. +You can craft peg limbs and crutches with wood for use in dire circumstances. The latter are also available in medical vendors. +As a Heretic, you can also sacrifice cultists, rewarding you with a knowledge point and one of three unique, powerful rewards. +As a Cultist, if you manage to sacrifice a Heretic, you will unlock one of three powerful and unique items to be created in every one of your cult's forges, archives, or altars. +As a Cultist, when you sacrifice a Heretic, they will be bound inside a powerful haunted longsword. Anyone can then unbind the blade, unlocking its powers and abilities, but also allowing the blade to act of its own free will. +As a Syndicate Monkey, you're explosively allergic to species transformations and should probably avoid them. +Biological armor will protect your limb from a zombie's infective attack, unless the limb's more damaged than the armor value. Armor with thick material, such as firesuits and EVA suits, also partially protects, preventing at least the first attack from infection. +In a pinch, you can reduce bleeding or burn infection with several commonplace reagents - flour, salt, saltwater can all be splashed onto the wound to stall for time, and tea can be drank for a boost to your body's defences. +First-aid analyzers double the speed of wound treatment on injuries, alongside giving out normal and improvised instructions for treatment. +Syndicate Duffelbags are a lot quicker to zip and unzip, have significantly less slowdown, and can carry up to two of various bulky, objective-related items - such as fire axes, guns, or gibtonite. Examine them closely to see all the possibilities. +The Coroner's surgical tools are considered 'cruel implements', which speeds up surgery on corpses but slows it on not-yet-corpses. A few other items also have it. +As a Coroner, remember that your autopsy scanner also works as an advanced health analyzer on right-click, but only for corpses. +As the Captain, your sabre deals extra damage to Assistants (as long as they have their original liver). +You can automatically extract and retract arm implants by 'activating' the empty hand they're on. This includes integrated toolsets, cursed katanas, and vorpal scythes. +You can combine the Carpet reagent with various different reagents, such as Oil and Cyanide, to create unique carpet types. +You can bake a birthday cake and then microwave it to create a legendary cake hat. You can then combine it with an energy sword to create an energy cake. From 1c8daf95944874f9fadf98cab2d43a1271ef29ec Mon Sep 17 00:00:00 2001 From: "tgstation-ci[bot]" <179393467+tgstation-ci[bot]@users.noreply.github.com> Date: Fri, 29 Nov 2024 00:21:50 +0000 Subject: [PATCH 019/149] Automatic changelog for PR #88186 [ci skip] --- html/changelogs/AutoChangeLog-pr-88186.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-88186.yml diff --git a/html/changelogs/AutoChangeLog-pr-88186.yml b/html/changelogs/AutoChangeLog-pr-88186.yml new file mode 100644 index 0000000000000..c524913ca6188 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-88186.yml @@ -0,0 +1,4 @@ +author: "carlarctg" +delete-after: True +changes: + - qol: "Added some tips of the round." \ No newline at end of file From e0f7f3ea095c1fc048d9703384cb0c94395fca67 Mon Sep 17 00:00:00 2001 From: carlarctg <53100513+carlarctg@users.noreply.github.com> Date: Thu, 28 Nov 2024 21:21:55 -0300 Subject: [PATCH 020/149] Replaces scarves station trait with scryers (#88167) ## About The Pull Request Removed the scarves station trait and replaced it with modlink scryers. If you're confused, they're those things on the robotics mod crate whose sprite annoyingly and opaquely covers up the actual cores. The scryers allow you to start a semi-private conversation with any other modlink _ignoring the status of comms_. This doesn't make them as useful for shouting out threats but lets you discuss things with essential personnel, or report crime, even after comms is blown up. ![260621454-062983ee-6058-4e78-a3aa-bccda1a3e224](https://github.com/user-attachments/assets/9a6aa38b-e10a-4e23-8691-12538fd3348c) ![image](https://github.com/user-attachments/assets/5464d1a4-5b5b-47c6-9074-080ae3b3592d) https://github.com/tgstation/tgstation/pull/77639 This PR doesn't actually give the modlinks names, so they'll all show up as modlink (394) and be unusable. Something should be done there I'm just not quite sure how to handle it and the inevitable deluge of dropped modlinks that would recieve tons of unheeded calls. ~~Maybe we can make them undroppable for the first 30 minutes.~~ ## Why It's Good For The Game Scryers are a cool and underused aspect of the game. Their ability to function off comms is balanced out by their _in_ability to speak to more than one person at once. Having this as a trait helps showcase them and will likely allow for some enjoyable moments. I'm imagining spam calls, death threats, _actual_ death threats, prank calls, etc. ![image](https://github.com/user-attachments/assets/c505dab5-cd08-4485-b6cb-2d7390630e2a) ## Changelog :cl: add: Centcom's janitorial department has gotten tired of scooping up discarded scarves from the floor and has instead assigned MODlink scryers to some stations' crew in an attempt to spice up the disposal team's jobs. /:cl: --------- Co-authored-by: Ghom <42542238+Ghommie@users.noreply.github.com> --- code/datums/station_traits/neutral_traits.dm | 47 +++++++++----------- 1 file changed, 22 insertions(+), 25 deletions(-) diff --git a/code/datums/station_traits/neutral_traits.dm b/code/datums/station_traits/neutral_traits.dm index 7d83439b6d494..f3bb4fb4a9c75 100644 --- a/code/datums/station_traits/neutral_traits.dm +++ b/code/datums/station_traits/neutral_traits.dm @@ -291,38 +291,35 @@ greyscale_config = /datum/greyscale_config/festive_hat greyscale_config_worn = /datum/greyscale_config/festive_hat/worn -/datum/station_trait/scarves - name = "Scarves" +/datum/station_trait/scryers + name = "Scryers" trait_type = STATION_TRAIT_NEUTRAL - weight = 5 - cost = STATION_TRAIT_COST_MINIMAL + weight = 2 + cost = STATION_TRAIT_COST_LOW show_in_report = TRUE - var/list/scarves + report_message = "Nanotrasen has chosen your station for an experiment - everyone has free scryers! Use these to talk to other people easily and privately." -/datum/station_trait/scarves/New() +/datum/station_trait/scryers/New() . = ..() - report_message = pick( - "Nanotrasen is experimenting with seeing if neck warmth improves employee morale.", - "After Space Fashion Week, scarves are the hot new accessory.", - "Everyone was simultaneously a little bit cold when they packed to go to the station.", - "The station is definitely not under attack by neck grappling aliens masquerading as wool. Definitely not.", - "You all get free scarves. Don't ask why.", - "A shipment of scarves was delivered to the station.", - ) - scarves = typesof(/obj/item/clothing/neck/scarf) + list( - /obj/item/clothing/neck/large_scarf/red, - /obj/item/clothing/neck/large_scarf/green, - /obj/item/clothing/neck/large_scarf/blue, - ) - RegisterSignal(SSdcs, COMSIG_GLOB_JOB_AFTER_SPAWN, PROC_REF(on_job_after_spawn)) - -/datum/station_trait/scarves/proc/on_job_after_spawn(datum/source, datum/job/job, mob/living/spawned, client/player_client) +/datum/station_trait/scryers/proc/on_job_after_spawn(datum/source, datum/job/job, mob/living/spawned, client/player_client) SIGNAL_HANDLER - var/scarf_type = pick(scarves) - - spawned.equip_to_slot_or_del(new scarf_type(spawned), ITEM_SLOT_NECK, initial = FALSE) + if(!ishuman(spawned)) + return + var/mob/living/carbon/human/humanspawned = spawned + // Put their silly little scarf or necktie somewhere else + var/obj/item/silly_little_scarf = humanspawned.wear_neck + if(silly_little_scarf) + humanspawned.temporarilyRemoveItemFromInventory(silly_little_scarf) + silly_little_scarf.forceMove(get_turf(humanspawned)) + humanspawned.equip_in_one_of_slots(silly_little_scarf, ITEM_SLOT_BACKPACK, ITEM_SLOT_LPOCKET, ITEM_SLOT_RPOCKET, qdel_on_fail = FALSE, indirect_action = TRUE) + + var/obj/item/clothing/neck/link_scryer/loaded/new_scryer = new(spawned) + new_scryer.label = spawned.name + new_scryer.update_name() + + spawned.equip_to_slot_or_del(new_scryer, ITEM_SLOT_NECK, initial = FALSE) /datum/station_trait/wallets name = "Wallets!" From b6d95768caa242d6cafcf8a0804484dad833f23e Mon Sep 17 00:00:00 2001 From: "tgstation-ci[bot]" <179393467+tgstation-ci[bot]@users.noreply.github.com> Date: Fri, 29 Nov 2024 00:22:15 +0000 Subject: [PATCH 021/149] Automatic changelog for PR #88167 [ci skip] --- html/changelogs/AutoChangeLog-pr-88167.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-88167.yml diff --git a/html/changelogs/AutoChangeLog-pr-88167.yml b/html/changelogs/AutoChangeLog-pr-88167.yml new file mode 100644 index 0000000000000..fd1a202123488 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-88167.yml @@ -0,0 +1,4 @@ +author: "carlarctg" +delete-after: True +changes: + - rscadd: "Centcom's janitorial department has gotten tired of scooping up discarded scarves from the floor and has instead assigned MODlink scryers to some stations' crew in an attempt to spice up the disposal team's jobs." \ No newline at end of file From f198a553645e851780bfa5519138399e45a6f108 Mon Sep 17 00:00:00 2001 From: carlarctg <53100513+carlarctg@users.noreply.github.com> Date: Thu, 28 Nov 2024 21:28:09 -0300 Subject: [PATCH 022/149] Added 'loose hat' functionality to the hat stabilizing component, used in modsuist (#88030) ## About The Pull Request You can now wear a hat on any modsuit, even w/o the stabilizing module. However: - It will always sit slightly askew, at an angle. - Involuntarily falling to the ground for any reason will cause the hat to fall to the ground. - Being thrown, slapped, or slipped will send it flying off. Added the Atrocinator, Hat Stabilizer, and Tanning modules to the black market. Added the loose hat component to bio/bomb/rad hoods and space helmets. ## Why It's Good For The Game > You can now wear a hat on any modsuit, even w/o the stabilizing module. I think the notion of, say, the Head of Security putting his cap on his modsuit and then being slipped by the clown, who then steals the cap, is really funny. https://github.com/user-attachments/assets/3ad8a74d-0cb8-4118-8beb-d2ce9c76b358 The module is fairly rare and sometimes I just want to wear a silly hat alongside the modsuit without badgering the captain for his hat module. The downsides are rather plentiful so it's not like the hat module is made irrelevant - if anything it makes it more notable. This will add a bunch of enjoyable silliness to rounds, so I think it's worth it. > Added the Atrocinator, Hat Stabilizer, and Tanning modules to the black market. > Added the loose hat component to bio/bomb/rad hoods and space helmets. It sucks losing your iconic drip when you need to venture out to space for whichever reason - this lets you keep it without taking up space in your bag, while having the throw downside. They just feel perfect for the vibes of the black market. More miscellaneous completely useless fancy stuff that has exorbitant prices please! ## Changelog :cl: add: You can now wear a hat on any modsuit, even w/o the stabilizing module. But it may easily fall off... add: Added the Atrocinator, Hat Stabilizer, and Tanning modules to the black market. add: Added the loose hat component to bio/bomb/rad hoods and space helmets. /:cl: ~~I'm having a bit of an issue. Somewhere I fugged up and now the worn overlay on the mod helmet sprite doesn't work properly...~~ Turns out that code was never used and nonfunctional to begin with so I removed it entirely yay --- .../signals/signals_mob/signals_mob_living.dm | 4 + code/datums/components/hat_stabilizer.dm | 99 +++++++++++++++---- code/game/atoms_movable.dm | 1 + code/game/objects/items/hand_items.dm | 1 + .../cargo/markets/market_items/misc.dm | 27 +++++ code/modules/clothing/head/perceptomatrix.dm | 2 + .../clothing/spacesuits/_spacesuits.dm | 4 + code/modules/clothing/spacesuits/pirate.dm | 3 + code/modules/clothing/spacesuits/plasmamen.dm | 4 +- code/modules/clothing/suits/bio.dm | 1 + code/modules/clothing/suits/utility.dm | 2 + code/modules/mob/living/carbon/carbon.dm | 4 - code/modules/mob/living/living.dm | 3 + code/modules/mod/mod_clothes.dm | 5 + code/modules/mod/modules/modules_general.dm | 6 +- 15 files changed, 141 insertions(+), 25 deletions(-) diff --git a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm index 84cfbc8baa918..ba43900425bde 100644 --- a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm +++ b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm @@ -141,6 +141,8 @@ #define COMSIG_LIVING_SLAM_TABLE "living_slam_table" ///from /obj/item/hand_item/slapper/attack(): (source=mob/living/slapper, mob/living/slapped) #define COMSIG_LIVING_SLAP_MOB "living_slap_mob" +///from /obj/item/hand_item/slapper/attack(): (source=mob/living/slapper, mob/living/slapped) +#define COMSIG_LIVING_SLAPPED "living_slapped" /// from /mob/living/*/UnarmedAttack(), before sending [COMSIG_LIVING_UNARMED_ATTACK]: (mob/living/source, atom/target, proximity, modifiers) /// The only reason this exists is so hulk can fire before Fists of the North Star. /// Note that this is called before [/mob/living/proc/can_unarmed_attack] is called, so be wary of that. @@ -288,6 +290,8 @@ ///From mob/living/carbon/proc/throw_mode_on and throw_mode_off #define COMSIG_LIVING_THROW_MODE_TOGGLE "living_throw_mode_toggle" +/// From mob/living/proc/on_fall +#define COMSIG_LIVING_THUD "living_thud" ///From /datum/component/happiness() #define COMSIG_MOB_HAPPINESS_CHANGE "happiness_change" /// From /obj/item/melee/baton/baton_effect(): (datum/source, mob/living/user, /obj/item/melee/baton) diff --git a/code/datums/components/hat_stabilizer.dm b/code/datums/components/hat_stabilizer.dm index 40cae0633f48b..9a79895153023 100644 --- a/code/datums/components/hat_stabilizer.dm +++ b/code/datums/components/hat_stabilizer.dm @@ -1,7 +1,10 @@ /// Allows players to place hats on the atom this is attached to /datum/component/hat_stabilizer + dupe_mode = COMPONENT_DUPE_UNIQUE_PASSARGS /// Currently "stored" hat. No armor or function will be inherited, only the icon and cover flags. var/obj/item/clothing/head/attached_hat + /// If TRUE, the hat will fall to the ground when the owner does so. It can also be shot off. + var/loose_hat = FALSE /// Original cover flags for the helmet, before a hat is placed var/former_flags var/former_visor_flags @@ -10,7 +13,7 @@ /// Pixel_y offset for the hat var/pixel_y_offset -/datum/component/hat_stabilizer/Initialize(add_overlay = FALSE, use_worn_icon = TRUE, pixel_y_offset = 0) +/datum/component/hat_stabilizer/Initialize(use_worn_icon = FALSE, pixel_y_offset = 0, loose_hat = FALSE) if(!ismovable(parent)) return COMPONENT_INCOMPATIBLE @@ -19,14 +22,37 @@ src.use_worn_icon = use_worn_icon src.pixel_y_offset = pixel_y_offset + src.loose_hat = loose_hat + // Examine signals RegisterSignal(source, COMSIG_ATOM_EXAMINE, PROC_REF(on_examine)) + RegisterSignal(source, COMSIG_ATOM_REQUESTING_CONTEXT_FROM_ITEM, PROC_REF(on_requesting_context_from_item)) + + // Equip signals, used to drop loose hats + RegisterSignal(source, COMSIG_ITEM_EQUIPPED, PROC_REF(on_equip)) + RegisterSignal(source, COMSIG_ITEM_DROPPED, PROC_REF(on_drop)) + + // Wear & Remove RegisterSignal(source, COMSIG_ATOM_ATTACKBY, PROC_REF(on_attackby)) - RegisterSignal(source, COMSIG_QDELETING, PROC_REF(on_qdel)) RegisterSignal(source, COMSIG_ATOM_ATTACK_HAND_SECONDARY, PROC_REF(on_secondary_attack_hand)) + + // Overlays RegisterSignals(source, list(COMSIG_MODULE_GENERATE_WORN_OVERLAY, COMSIG_ITEM_GET_WORN_OVERLAYS), PROC_REF(get_worn_overlays)) - RegisterSignal(source, COMSIG_ATOM_REQUESTING_CONTEXT_FROM_ITEM, PROC_REF(on_requesting_context_from_item)) - if (add_overlay) - RegisterSignal(source, COMSIG_ATOM_UPDATE_OVERLAYS, PROC_REF(on_update_overlays)) + + RegisterSignal(source, COMSIG_QDELETING, PROC_REF(on_qdel)) + +// Inherit the new values passed to the component +/datum/component/hat_stabilizer/InheritComponent(datum/component/hat_stabilizer/new_comp, original, use_worn_icon, pixel_y_offset, loose_hat) + if(!original) + return + + if(!isnull(use_worn_icon)) + src.use_worn_icon = use_worn_icon + if(!isnull(use_worn_icon)) + src.use_worn_icon = use_worn_icon + if(!isnull(pixel_y_offset)) + src.pixel_y_offset = pixel_y_offset + if(!isnull(loose_hat)) + src.loose_hat = loose_hat /datum/component/hat_stabilizer/UnregisterFromParent() if (attached_hat) @@ -34,12 +60,44 @@ UnregisterSignal(parent, list(COMSIG_ATOM_EXAMINE, COMSIG_ATOM_ATTACKBY, COMSIG_ATOM_ATTACK_HAND_SECONDARY, COMSIG_MODULE_GENERATE_WORN_OVERLAY, COMSIG_ITEM_GET_WORN_OVERLAYS, COMSIG_ATOM_UPDATE_OVERLAYS, COMSIG_QDELETING, - COMSIG_ATOM_REQUESTING_CONTEXT_FROM_ITEM)) + COMSIG_ATOM_REQUESTING_CONTEXT_FROM_ITEM, COMSIG_ITEM_EQUIPPED, COMSIG_ITEM_DROPPED)) + +/datum/component/hat_stabilizer/proc/on_equip(datum/source, mob/equipper, slot) + SIGNAL_HANDLER + + if(!loose_hat) + return + + var/obj/item/our_item = parent + if(!(slot & our_item.slot_flags)) + return + RegisterSignals(equipper, list(COMSIG_MOB_SLIPPED, COMSIG_LIVING_SLAPPED, COMSIG_MOVABLE_POST_THROW), PROC_REF(throw_hat)) + RegisterSignal(equipper, COMSIG_LIVING_THUD, PROC_REF(drop_hat)) + +/datum/component/hat_stabilizer/proc/on_drop(datum/source, mob/dropper) + SIGNAL_HANDLER + UnregisterSignal(dropper, list(COMSIG_MOB_SLIPPED, COMSIG_LIVING_SLAPPED, COMSIG_MOVABLE_POST_THROW, COMSIG_LIVING_THUD)) + +/datum/component/hat_stabilizer/proc/throw_hat(mob/hatless) + SIGNAL_HANDLER + if(!loose_hat) + return + var/obj/item/hat = remove_hat() + if(!hat) + return + hat.visible_message(span_danger("[hat] goes flying off [hatless]'s head!")) + hat.throw_at(get_edge_target_turf(get_turf(hat), pick(GLOB.alldirs)), 2, 1, spin = TRUE) + +/datum/component/hat_stabilizer/proc/drop_hat(mob/hatless) + SIGNAL_HANDLER + if(!loose_hat) + return + remove_hat() /datum/component/hat_stabilizer/proc/on_examine(datum/source, mob/user, list/base_examine) SIGNAL_HANDLER if(attached_hat) - base_examine += span_notice("There's \a [attached_hat] placed on [parent].") + base_examine += span_notice("There's \a [attached_hat] [loose_hat ? "loosely" : ""] placed on [parent].") else base_examine += span_notice("There's nothing placed on [parent]. Yet.") @@ -49,17 +107,15 @@ return if(attached_hat) var/mutable_appearance/worn_overlay = attached_hat.build_worn_icon(default_layer = ABOVE_BODY_FRONT_HEAD_LAYER-0.1, default_icon_file = 'icons/mob/clothing/head/default.dmi') + // loose hats are slightly angled + if(loose_hat) + var/matrix/tilt_trix = matrix(worn_overlay.transform) + var/angle = 5 + tilt_trix.Turn(angle * pick(1, -1)) + worn_overlay.transform = tilt_trix worn_overlay.pixel_y = pixel_y_offset + attached_hat.worn_y_offset overlays += worn_overlay -/datum/component/hat_stabilizer/proc/on_update_overlays(atom/movable/source, list/overlays) - SIGNAL_HANDLER - if (isnull(attached_hat)) - return - var/mutable_appearance/worn_overlay = use_worn_icon ? attached_hat.build_worn_icon(default_layer = ABOVE_OBJ_LAYER, default_icon_file = 'icons/mob/clothing/head/default.dmi') : mutable_appearance(attached_hat, layer = ABOVE_OBJ_LAYER) - worn_overlay.pixel_y = pixel_y_offset - overlays += worn_overlay - /datum/component/hat_stabilizer/proc/on_qdel(atom/movable/source) SIGNAL_HANDLER @@ -90,7 +146,7 @@ /datum/component/hat_stabilizer/proc/attach_hat(obj/item/clothing/hat, mob/user) var/atom/movable/movable_parent = parent attached_hat = hat - RegisterSignal(hat, COMSIG_MOVABLE_MOVED, PROC_REF(remove_hat)) + RegisterSignal(hat, COMSIG_MOVABLE_MOVED, PROC_REF(on_hat_movement)) if (!isnull(user)) movable_parent.balloon_alert(user, "hat attached") @@ -111,6 +167,10 @@ var/mob/wearer = apparel.loc wearer.update_clothing(wearer.get_slot_by_item(apparel)) +/datum/component/hat_stabilizer/proc/on_hat_movement(obj/hat, mob/user) + SIGNAL_HANDLER + remove_hat(user) + /datum/component/hat_stabilizer/proc/on_secondary_attack_hand(datum/source, mob/user) SIGNAL_HANDLER . = COMPONENT_CANCEL_ATTACK_CHAIN @@ -122,9 +182,9 @@ else movable_parent.balloon_alert_to_viewers("the hat falls to the floor!") -/datum/component/hat_stabilizer/proc/remove_hat(mob/user) - SIGNAL_HANDLER +/datum/component/hat_stabilizer/proc/on_retraction() +/datum/component/hat_stabilizer/proc/remove_hat(mob/user) if(QDELETED(attached_hat)) return @@ -144,6 +204,7 @@ movable_parent.update_appearance() return + var/former_hat = attached_hat var/obj/item/clothing/apparel = parent apparel.detach_clothing_traits(attached_hat) apparel.flags_cover = former_flags @@ -154,6 +215,8 @@ var/mob/wearer = apparel.loc wearer.update_clothing(wearer.get_slot_by_item(apparel)) + return former_hat + /datum/component/hat_stabilizer/proc/on_requesting_context_from_item(atom/source, list/context, obj/item/held_item, mob/user) SIGNAL_HANDLER diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm index 0b46daebb01fb..46e568d5dd281 100644 --- a/code/game/atoms_movable.dm +++ b/code/game/atoms_movable.dm @@ -1320,6 +1320,7 @@ step(src, hitting_atom.dir) return ..() +// Calls throw_at after checking that the move strength is greater than the thrown atom's move resist. Identical args. /atom/movable/proc/safe_throw_at(atom/target, range, speed, mob/thrower, spin = TRUE, diagonals_first = FALSE, datum/callback/callback, force = MOVE_FORCE_STRONG, gentle = FALSE) if((force < (move_resist * MOVE_FORCE_THROW_RATIO)) || (move_resist == INFINITY)) return diff --git a/code/game/objects/items/hand_items.dm b/code/game/objects/items/hand_items.dm index 12bf53f5c3e30..befd9a619a3f4 100644 --- a/code/game/objects/items/hand_items.dm +++ b/code/game/objects/items/hand_items.dm @@ -218,6 +218,7 @@ /obj/item/hand_item/slapper/attack(mob/living/slapped, mob/living/carbon/human/user) SEND_SIGNAL(user, COMSIG_LIVING_SLAP_MOB, slapped) + SEND_SIGNAL(slapped, COMSIG_LIVING_SLAPPED, user) if(iscarbon(slapped)) var/mob/living/carbon/potential_tailed = slapped diff --git a/code/modules/cargo/markets/market_items/misc.dm b/code/modules/cargo/markets/market_items/misc.dm index bb8d3da04d825..a35d85fa7ccca 100644 --- a/code/modules/cargo/markets/market_items/misc.dm +++ b/code/modules/cargo/markets/market_items/misc.dm @@ -51,6 +51,33 @@ stock_max = 2 availability_prob = 30 +/datum/market_item/misc/atrocinator + name = "MOD Anti-Gravity Module" + desc = "We found this module in a maintenance tunnel, behind several warning cones and hazard signs, unlabeled. It's probably safe." + item = /obj/item/mod/module/atrocinator + price_min = CARGO_CRATE_VALUE * 4 + price_max = CARGO_CRATE_VALUE * 7 + stock_max = 1 + availability_prob = 22 + +/datum/market_item/misc/tanner + name = "MOD Tanning Module" + desc = "Ever wanted to be at the beach AND at work? Now you can with this snazzy tanning module!" + item = /obj/item/mod/module/tanner + price_min = CARGO_CRATE_VALUE * 2 + price_max = CARGO_CRATE_VALUE * 3 + stock_max = 2 + availability_prob = 30 + +/datum/market_item/misc/hat_stabilizer + name = "MOD Hat Stabilizer Module" + desc = "Don't sacrifice style for substance with this module! Hats not included." + item = /obj/item/mod/module/tanner + price_min = CARGO_CRATE_VALUE * 2 + price_max = CARGO_CRATE_VALUE * 3 + stock_max = 2 + availability_prob = 35 + /datum/market_item/misc/shove_blocker name = "MOD Bulwark Module" desc = "You have no idea how much effort it took us to extract this module from that damn safeguard MODsuit last shift." diff --git a/code/modules/clothing/head/perceptomatrix.dm b/code/modules/clothing/head/perceptomatrix.dm index 4250a1e399663..e8b75bbdef5bc 100644 --- a/code/modules/clothing/head/perceptomatrix.dm +++ b/code/modules/clothing/head/perceptomatrix.dm @@ -66,6 +66,8 @@ update_appearance(UPDATE_ICON_STATE) update_anomaly_state() + AddComponent(/datum/component/adjust_fishing_difficulty, -7) // PSYCHIC FISHING + AddComponent(/datum/component/hat_stabilizer, loose_hat = TRUE) /obj/item/clothing/head/helmet/perceptomatrix/equipped(mob/living/user, slot) . = ..() diff --git a/code/modules/clothing/spacesuits/_spacesuits.dm b/code/modules/clothing/spacesuits/_spacesuits.dm index eb8cb2a11e524..81a9a4809f521 100644 --- a/code/modules/clothing/spacesuits/_spacesuits.dm +++ b/code/modules/clothing/spacesuits/_spacesuits.dm @@ -36,6 +36,10 @@ . = ..() if(fishing_modifier) AddComponent(/datum/component/adjust_fishing_difficulty, fishing_modifier) + add_stabilizer() + +/obj/item/clothing/head/helmet/space/proc/add_stabilizer(loose_hat = TRUE) + AddComponent(/datum/component/hat_stabilizer, loose_hat = loose_hat) /datum/armor/helmet_space bio = 100 diff --git a/code/modules/clothing/spacesuits/pirate.dm b/code/modules/clothing/spacesuits/pirate.dm index 8ead0aeaa6619..f9625467ccd19 100644 --- a/code/modules/clothing/spacesuits/pirate.dm +++ b/code/modules/clothing/spacesuits/pirate.dm @@ -39,6 +39,9 @@ desc = "A modified EVA helmet with a five-thousand credit Lizzy Vuitton hat affixed to the top, proving that working in deep space is no excuse for being poor." icon_state = "spacetophat" +/obj/item/clothing/head/helmet/space/pirate/tophat/add_stabilizer(loose_hat = FALSE) + return + /obj/item/clothing/suit/space/pirate/silverscale name = "designer pirate suit" desc = "A specially-made Cybersun branded space suit; the fine plastisilk exterior is woven from the cocoons of black-market Lümlan mothroaches \ diff --git a/code/modules/clothing/spacesuits/plasmamen.dm b/code/modules/clothing/spacesuits/plasmamen.dm index 903142fdaa203..d2c31498d184b 100644 --- a/code/modules/clothing/spacesuits/plasmamen.dm +++ b/code/modules/clothing/spacesuits/plasmamen.dm @@ -109,10 +109,12 @@ /obj/item/clothing/head/helmet/space/plasmaman/Initialize(mapload) . = ..() visor_toggling() - AddComponent(/datum/component/hat_stabilizer) update_appearance() register_context() +/obj/item/clothing/head/helmet/space/plasmaman/add_stabilizer(loose_hat = FALSE) + ..() + /obj/item/clothing/head/helmet/space/plasmaman/add_context(atom/source, list/context, obj/item/held_item, mob/living/user) context[SCREENTIP_CONTEXT_ALT_LMB] = "Toggle Welding Screen" if(istype(held_item, /obj/item/toy/crayon)) diff --git a/code/modules/clothing/suits/bio.dm b/code/modules/clothing/suits/bio.dm index 25b28c74d1a7a..919d1da261ecb 100644 --- a/code/modules/clothing/suits/bio.dm +++ b/code/modules/clothing/suits/bio.dm @@ -17,6 +17,7 @@ if(flags_inv & HIDEFACE) AddComponent(/datum/component/clothing_fov_visor, FOV_90_DEGREES) AddComponent(/datum/component/adjust_fishing_difficulty, 6) + AddComponent(/datum/component/hat_stabilizer, loose_hat = TRUE) /datum/armor/head_bio_hood bio = 100 diff --git a/code/modules/clothing/suits/utility.dm b/code/modules/clothing/suits/utility.dm index bb42fb1ed3975..2608c41eb4ad5 100644 --- a/code/modules/clothing/suits/utility.dm +++ b/code/modules/clothing/suits/utility.dm @@ -109,6 +109,7 @@ if(flags_inv & HIDEFACE) AddComponent(/datum/component/clothing_fov_visor, FOV_90_DEGREES) AddComponent(/datum/component/adjust_fishing_difficulty, 8) + AddComponent(/datum/component/hat_stabilizer, loose_hat = TRUE) /datum/armor/utility_bomb_hood melee = 20 @@ -189,6 +190,7 @@ if(flags_inv & HIDEFACE) AddComponent(/datum/component/clothing_fov_visor, FOV_90_DEGREES) AddComponent(/datum/component/adjust_fishing_difficulty, 7) + AddComponent(/datum/component/hat_stabilizer, loose_hat = TRUE) /datum/armor/utility_radiation bio = 60 diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index 7ff695e4a744f..79b3f8aa3cc94 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -244,10 +244,6 @@ paper_note.show_through_camera(usr) -/mob/living/carbon/on_fall() - . = ..() - loc?.handle_fall(src)//it's loc so it doesn't call the mob's handle_fall which does nothing - /mob/living/carbon/resist_buckle() if(!HAS_TRAIT(src, TRAIT_RESTRAINED)) buckled.user_unbuckle_mob(src, src) diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index 029a4376437fb..7f811843f0f92 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -1923,6 +1923,9 @@ GLOBAL_LIST_EMPTY(fire_appearances) /// Called when mob changes from a standing position into a prone while lacking the ability to stand up at the moment. /mob/living/proc/on_fall() + SHOULD_CALL_PARENT(TRUE) + SEND_SIGNAL(src, COMSIG_LIVING_THUD) + loc?.handle_fall(src)//it's loc so it doesn't call the mob's handle_fall which does nothing return /mob/living/forceMove(atom/destination) diff --git a/code/modules/mod/mod_clothes.dm b/code/modules/mod/mod_clothes.dm index 8c5e7a2c4904f..7c63655dee86c 100644 --- a/code/modules/mod/mod_clothes.dm +++ b/code/modules/mod/mod_clothes.dm @@ -11,6 +11,11 @@ cold_protection = HEAD item_flags = IMMUTABLE_SLOW +// Even without a hat stabilizer, hats can be worn - however, they'll fall off very easily +/obj/item/clothing/head/mod/Initialize(mapload) + . = ..() + AddComponent(/datum/component/hat_stabilizer, loose_hat = TRUE) + /obj/item/clothing/suit/mod name = "MOD chestplate" desc = "A chestplate for a MODsuit." diff --git a/code/modules/mod/modules/modules_general.dm b/code/modules/mod/modules/modules_general.dm index d1817e5170ba3..ad81fa828350a 100644 --- a/code/modules/mod/modules/modules_general.dm +++ b/code/modules/mod/modules/modules_general.dm @@ -699,7 +699,8 @@ var/obj/item/clothing/helmet = mod.get_part_from_slot(ITEM_SLOT_HEAD) if(!istype(helmet)) return - helmet.AddComponent(/datum/component/hat_stabilizer) + // Override pre-existing component + helmet.AddComponent(/datum/component/hat_stabilizer, loose_hat = FALSE) /obj/item/mod/module/hat_stabilizer/on_part_deactivation(deleting = FALSE) if(deleting) @@ -707,7 +708,8 @@ var/obj/item/clothing/helmet = mod.get_part_from_slot(ITEM_SLOT_HEAD) if(!istype(helmet)) return - qdel(helmet.GetComponent(/datum/component/hat_stabilizer)) + // Override again! + helmet.AddComponent(/datum/component/hat_stabilizer, loose_hat = TRUE) /obj/item/mod/module/hat_stabilizer/syndicate name = "MOD elite hat stabilizer module" From 0c4cf8bf25822d63fc121b55704f26cb325fff5b Mon Sep 17 00:00:00 2001 From: "tgstation-ci[bot]" <179393467+tgstation-ci[bot]@users.noreply.github.com> Date: Fri, 29 Nov 2024 00:28:32 +0000 Subject: [PATCH 023/149] Automatic changelog for PR #88030 [ci skip] --- html/changelogs/AutoChangeLog-pr-88030.yml | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-88030.yml diff --git a/html/changelogs/AutoChangeLog-pr-88030.yml b/html/changelogs/AutoChangeLog-pr-88030.yml new file mode 100644 index 0000000000000..7f3f1eb854550 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-88030.yml @@ -0,0 +1,6 @@ +author: "carlarctg" +delete-after: True +changes: + - rscadd: "You can now wear a hat on any modsuit, even w/o the stabilizing module. But it may easily fall off..." + - rscadd: "Added the Atrocinator, Hat Stabilizer, and Tanning modules to the black market." + - rscadd: "Added the loose hat component to bio/bomb/rad hoods and space helmets." \ No newline at end of file From 0c5da3981b173d5d64454e63f2215a9726ad42b8 Mon Sep 17 00:00:00 2001 From: carlarctg <53100513+carlarctg@users.noreply.github.com> Date: Thu, 28 Nov 2024 21:29:50 -0300 Subject: [PATCH 024/149] [NO GBP] Various CvH tweaks & fixes (#88168) ## About The Pull Request Increased Rusted Harvester health from 35 to 45. Increased haunted longsword's demolition mod by 20%. Rusted harvesters won't get narsie telling them to bring her their victims. Heretic summons aren't affected by void chill anymore. Add no gbp tag if you want ## Why It's Good For The Game > Increased Rusted Harvester health from 35 to 45. I want these to be frail, but being one-tapped by a sharpened sword is a tad too much I think. I balanced that health amount when they delimbed cultists instantly, but that's now a delayed action on crit so it's moot. > Increased haunted longsword's demolition mod by 50%. To some degree I want people to throw these away deep into maintenance, but there's a binding button now, perfectly serviceable, and I've _seen_ how miserable it is to be stuck alone deep in maintenance waiting for a just-too-long cooldown to break down 6 airlocks in a row. Seal them away the right way or suffer the consequences of your actions. > Rusted harvesters won't get narsie telling them to bring her their victims. They ain't yours, dummy. > Heretic summons & rusted harvesters aren't affected by void chill anymore. Why my friends freezing too? :( This fix also causes 'mansus touched' things to be unaffected by the chill. It includes the crimson medallion, which is obtainable by cultists. In my mind that's not a bad thing but it's not my path rework so I'll tag the author of it ## Changelog :cl: balance: Increased Rusted Harvester health from 35 to 45. balance: Increased haunted longsword's demolition mod by 20%. fix: Rusted harvesters won't get narsie telling them to bring her their victims. fix: Heretic summons aren't affected by void chill anymore. /:cl: --- code/modules/antagonists/cult/cult_items.dm | 1 + code/modules/antagonists/heretic/magic/void_conduit.dm | 2 +- code/modules/mob/living/basic/cult/constructs/harvester.dm | 7 ++++--- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/code/modules/antagonists/cult/cult_items.dm b/code/modules/antagonists/cult/cult_items.dm index c6bfa9cca425a..32d1ca218769b 100644 --- a/code/modules/antagonists/cult/cult_items.dm +++ b/code/modules/antagonists/cult/cult_items.dm @@ -128,6 +128,7 @@ Striking a noncultist, however, will tear their flesh."} free_use = TRUE light_color = COLOR_HERETIC_GREEN light_range = 3 + demolition_mod = 1.5 /// holder for the actual action when created. var/list/datum/action/cooldown/spell/path_sword_actions /// holder for the actual action when created. diff --git a/code/modules/antagonists/heretic/magic/void_conduit.dm b/code/modules/antagonists/heretic/magic/void_conduit.dm index 036415269c975..8d2b193de29e6 100644 --- a/code/modules/antagonists/heretic/magic/void_conduit.dm +++ b/code/modules/antagonists/heretic/magic/void_conduit.dm @@ -94,7 +94,7 @@ var/mob/living/affected_mob = thing_to_affect if(affected_mob.can_block_magic(MAGIC_RESISTANCE)) continue - if(IS_HERETIC(affected_mob)) + if(IS_HERETIC_OR_MONSTER(affected_mob) || HAS_TRAIT(affected_mob, TRAIT_MANSUS_TOUCHED)) affected_mob.apply_status_effect(/datum/status_effect/void_conduit) else affected_mob.apply_status_effect(/datum/status_effect/void_chill, 1) diff --git a/code/modules/mob/living/basic/cult/constructs/harvester.dm b/code/modules/mob/living/basic/cult/constructs/harvester.dm index 95a5956825421..971c341a73abf 100644 --- a/code/modules/mob/living/basic/cult/constructs/harvester.dm +++ b/code/modules/mob/living/basic/cult/constructs/harvester.dm @@ -53,7 +53,8 @@ carbon_target.Paralyze(6 SECONDS) visible_message(span_danger("[src] knocks [carbon_target] down!")) - to_chat(src, span_cult_large("\"Bring [carbon_target.p_them()] to me.\"")) + if(theme == THEME_CULT) + to_chat(src, span_cult_large("\"Bring [carbon_target.p_them()] to me.\"")) /datum/action/innate/seek_master name = "Seek your Master" @@ -142,8 +143,8 @@ can_repair = FALSE slowed_by_drag = FALSE faction = list(FACTION_HERETIC) - maxHealth = 35 - health = 35 + maxHealth = 45 + health = 45 melee_damage_lower = 20 melee_damage_upper = 25 // Dim green From edecc2372772db771030e6e51d80ff2bbd99a740 Mon Sep 17 00:00:00 2001 From: "tgstation-ci[bot]" <179393467+tgstation-ci[bot]@users.noreply.github.com> Date: Fri, 29 Nov 2024 00:30:11 +0000 Subject: [PATCH 025/149] Automatic changelog for PR #88168 [ci skip] --- html/changelogs/AutoChangeLog-pr-88168.yml | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-88168.yml diff --git a/html/changelogs/AutoChangeLog-pr-88168.yml b/html/changelogs/AutoChangeLog-pr-88168.yml new file mode 100644 index 0000000000000..b73a672b5da24 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-88168.yml @@ -0,0 +1,7 @@ +author: "carlarctg" +delete-after: True +changes: + - balance: "Increased Rusted Harvester health from 35 to 45." + - balance: "Increased haunted longsword's demolition mod by 20%." + - bugfix: "Rusted harvesters won't get narsie telling them to bring her their victims." + - bugfix: "Heretic summons aren't affected by void chill anymore." \ No newline at end of file From 36ee0a4750ff9caf6b3c4d6b937cfadebe57cbb5 Mon Sep 17 00:00:00 2001 From: "tgstation-ci[bot]" <179393467+tgstation-ci[bot]@users.noreply.github.com> Date: Fri, 29 Nov 2024 01:46:22 +0000 Subject: [PATCH 026/149] Automatic changelog compile [ci skip] --- html/changelogs/AutoChangeLog-pr-87103.yml | 4 -- html/changelogs/AutoChangeLog-pr-88030.yml | 6 --- html/changelogs/AutoChangeLog-pr-88096.yml | 6 --- html/changelogs/AutoChangeLog-pr-88167.yml | 4 -- html/changelogs/AutoChangeLog-pr-88168.yml | 7 --- html/changelogs/AutoChangeLog-pr-88186.yml | 4 -- html/changelogs/AutoChangeLog-pr-88204.yml | 4 -- html/changelogs/AutoChangeLog-pr-88213.yml | 10 ----- html/changelogs/AutoChangeLog-pr-88215.yml | 4 -- html/changelogs/AutoChangeLog-pr-88232.yml | 4 -- html/changelogs/AutoChangeLog-pr-88234.yml | 4 -- html/changelogs/AutoChangeLog-pr-88242.yml | 5 --- html/changelogs/archive/2024-11.yml | 50 ++++++++++++++++++++++ 13 files changed, 50 insertions(+), 62 deletions(-) delete mode 100644 html/changelogs/AutoChangeLog-pr-87103.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-88030.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-88096.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-88167.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-88168.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-88186.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-88204.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-88213.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-88215.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-88232.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-88234.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-88242.yml diff --git a/html/changelogs/AutoChangeLog-pr-87103.yml b/html/changelogs/AutoChangeLog-pr-87103.yml deleted file mode 100644 index d8aed4f42e1b2..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-87103.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "paganiy" -delete-after: True -changes: - - rscadd: "Add a new item to the chef traitor's uplink: Molt'Obeso sauce. A sauce that makes people want to eat too much." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-88030.yml b/html/changelogs/AutoChangeLog-pr-88030.yml deleted file mode 100644 index 7f3f1eb854550..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-88030.yml +++ /dev/null @@ -1,6 +0,0 @@ -author: "carlarctg" -delete-after: True -changes: - - rscadd: "You can now wear a hat on any modsuit, even w/o the stabilizing module. But it may easily fall off..." - - rscadd: "Added the Atrocinator, Hat Stabilizer, and Tanning modules to the black market." - - rscadd: "Added the loose hat component to bio/bomb/rad hoods and space helmets." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-88096.yml b/html/changelogs/AutoChangeLog-pr-88096.yml deleted file mode 100644 index c9a52657c9fc1..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-88096.yml +++ /dev/null @@ -1,6 +0,0 @@ -author: "Runi-c" -delete-after: True -changes: - - rscadd: "digitigrade lizards can wear certain shoes and suits" - - image: "added digitigrade shoes & oversuit templates" - - refactor: "improved digi clothing generator code" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-88167.yml b/html/changelogs/AutoChangeLog-pr-88167.yml deleted file mode 100644 index fd1a202123488..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-88167.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "carlarctg" -delete-after: True -changes: - - rscadd: "Centcom's janitorial department has gotten tired of scooping up discarded scarves from the floor and has instead assigned MODlink scryers to some stations' crew in an attempt to spice up the disposal team's jobs." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-88168.yml b/html/changelogs/AutoChangeLog-pr-88168.yml deleted file mode 100644 index b73a672b5da24..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-88168.yml +++ /dev/null @@ -1,7 +0,0 @@ -author: "carlarctg" -delete-after: True -changes: - - balance: "Increased Rusted Harvester health from 35 to 45." - - balance: "Increased haunted longsword's demolition mod by 20%." - - bugfix: "Rusted harvesters won't get narsie telling them to bring her their victims." - - bugfix: "Heretic summons aren't affected by void chill anymore." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-88186.yml b/html/changelogs/AutoChangeLog-pr-88186.yml deleted file mode 100644 index c524913ca6188..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-88186.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "carlarctg" -delete-after: True -changes: - - qol: "Added some tips of the round." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-88204.yml b/html/changelogs/AutoChangeLog-pr-88204.yml deleted file mode 100644 index 1fe1febd6a185..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-88204.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Ghommie" -delete-after: True -changes: - - bugfix: "Player-controlled lobstrosities, space dragons, space carps and penguins can fish again." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-88213.yml b/html/changelogs/AutoChangeLog-pr-88213.yml deleted file mode 100644 index ecffed795f669..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-88213.yml +++ /dev/null @@ -1,10 +0,0 @@ -author: "carlarctg" -delete-after: True -changes: - - rscadd: "Adds a new biotype, MOB_AQUATIC, indicating the mob is water-themed somehow. Given to carp, lobstrosities, frogs, axolotls, penguins, fire sharks." - - rscadd: "Aquatic mobs can be hooked by fishing rods, even without a jawed fishing hook installed." - - rscadd: "The carp and fish infusion sets now give the infusee the aquatic biotype. Added support for infusions adding a biotype." - - rscadd: "You can check for a fish's pulse with a stethoscope, which will tell you its status even without fishing skill." - - qol: "Refined fish health status checks to be more precise." - - rscadd: "Added 'Fishy' Reagent, a version of strange reagent that only works for fish or aquatic biotype mobs. It's made with omnizine, saltwater, and carpotoxin or tetrodotoxin." - - rscadd: "Added a lifish chemical reaction that creates fish." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-88215.yml b/html/changelogs/AutoChangeLog-pr-88215.yml deleted file mode 100644 index cb16936a80f81..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-88215.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "oranges" -delete-after: True -changes: - - rscadd: "Teleporting a leaning person will now make them fall over" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-88232.yml b/html/changelogs/AutoChangeLog-pr-88232.yml deleted file mode 100644 index b0899ab2f409b..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-88232.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Ghommie" -delete-after: True -changes: - - bugfix: "Bombing someone during organ manipulation no longer summons new organs." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-88234.yml b/html/changelogs/AutoChangeLog-pr-88234.yml deleted file mode 100644 index 0e7c068795cf9..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-88234.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "TealSeer" -delete-after: True -changes: - - bugfix: "Using a bonesetter to correct a dislocated limb should no longer cause you to hit the patient with it too." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-88242.yml b/html/changelogs/AutoChangeLog-pr-88242.yml deleted file mode 100644 index 19bb81e3d39db..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-88242.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: "necromanceranne" -delete-after: True -changes: - - bugfix: "Civilian bounty pads refuse to send holographic items. Nanotrasen have received far too many holographic fish for their liking. Officer Mathews is still weeping in a corner after all the clownfish in his aquarium turned to dust before his very eyes..." - - code_imp: "Cleans up the bounty pad code just a smidge." \ No newline at end of file diff --git a/html/changelogs/archive/2024-11.yml b/html/changelogs/archive/2024-11.yml index 0e217ba10baf1..7559696167874 100644 --- a/html/changelogs/archive/2024-11.yml +++ b/html/changelogs/archive/2024-11.yml @@ -1008,3 +1008,53 @@ in hand ValuedEmployee: - rscadd: New purr and meow emotes for players with felinid tongues +2024-11-29: + Ghommie: + - bugfix: Player-controlled lobstrosities, space dragons, space carps and penguins + can fish again. + - bugfix: Bombing someone during organ manipulation no longer summons new organs. + Runi-c: + - rscadd: digitigrade lizards can wear certain shoes and suits + - image: added digitigrade shoes & oversuit templates + - refactor: improved digi clothing generator code + TealSeer: + - bugfix: Using a bonesetter to correct a dislocated limb should no longer cause + you to hit the patient with it too. + carlarctg: + - qol: Added some tips of the round. + - balance: Increased Rusted Harvester health from 35 to 45. + - balance: Increased haunted longsword's demolition mod by 20%. + - bugfix: Rusted harvesters won't get narsie telling them to bring her their victims. + - bugfix: Heretic summons aren't affected by void chill anymore. + - rscadd: Centcom's janitorial department has gotten tired of scooping up discarded + scarves from the floor and has instead assigned MODlink scryers to some stations' + crew in an attempt to spice up the disposal team's jobs. + - rscadd: Adds a new biotype, MOB_AQUATIC, indicating the mob is water-themed somehow. + Given to carp, lobstrosities, frogs, axolotls, penguins, fire sharks. + - rscadd: Aquatic mobs can be hooked by fishing rods, even without a jawed fishing + hook installed. + - rscadd: The carp and fish infusion sets now give the infusee the aquatic biotype. + Added support for infusions adding a biotype. + - rscadd: You can check for a fish's pulse with a stethoscope, which will tell you + its status even without fishing skill. + - qol: Refined fish health status checks to be more precise. + - rscadd: Added 'Fishy' Reagent, a version of strange reagent that only works for + fish or aquatic biotype mobs. It's made with omnizine, saltwater, and carpotoxin + or tetrodotoxin. + - rscadd: Added a lifish chemical reaction that creates fish. + - rscadd: You can now wear a hat on any modsuit, even w/o the stabilizing module. + But it may easily fall off... + - rscadd: Added the Atrocinator, Hat Stabilizer, and Tanning modules to the black + market. + - rscadd: Added the loose hat component to bio/bomb/rad hoods and space helmets. + necromanceranne: + - bugfix: Civilian bounty pads refuse to send holographic items. Nanotrasen have + received far too many holographic fish for their liking. Officer Mathews is + still weeping in a corner after all the clownfish in his aquarium turned to + dust before his very eyes... + - code_imp: Cleans up the bounty pad code just a smidge. + oranges: + - rscadd: Teleporting a leaning person will now make them fall over + paganiy: + - rscadd: 'Add a new item to the chef traitor''s uplink: Molt''Obeso sauce. A sauce + that makes people want to eat too much.' From 36212e59e19576da1f82540ff443542b2e253f69 Mon Sep 17 00:00:00 2001 From: CRITAWAKETS Date: Thu, 28 Nov 2024 22:28:18 -0500 Subject: [PATCH 027/149] Adds in the modulo operator to the circuit arithmetic component. (#88253) ## About The Pull Request ![image](https://github.com/user-attachments/assets/17a5d230-c10f-4fda-b782-0d59c2797bff) This PR just adds in modulo to the circuit arithmetic component. ## Why It's Good For The Game You _can_ calculate it yourself, but then it ends up extremely unoptimal and you're usually better off not doing it. It also ends up really hard to read. I want to see more clever circuits and computing things. ## Changelog :cl: add: Added in the modulo operator to the circuit arithmetic component. /:cl: --- code/modules/wiremod/components/math/arithmetic.dm | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/code/modules/wiremod/components/math/arithmetic.dm b/code/modules/wiremod/components/math/arithmetic.dm index 083616f1e0e54..20474ec949295 100644 --- a/code/modules/wiremod/components/math/arithmetic.dm +++ b/code/modules/wiremod/components/math/arithmetic.dm @@ -2,6 +2,7 @@ #define COMP_ARITHMETIC_SUBTRACT "Subtract" #define COMP_ARITHMETIC_MULTIPLY "Multiply" #define COMP_ARITHMETIC_DIVIDE "Divide" +#define COMP_ARITHMETIC_MODULO "Modulo" #define COMP_ARITHMETIC_MIN "Minimum" #define COMP_ARITHMETIC_MAX "Maximum" @@ -34,6 +35,7 @@ COMP_ARITHMETIC_SUBTRACT, COMP_ARITHMETIC_MULTIPLY, COMP_ARITHMETIC_DIVIDE, + COMP_ARITHMETIC_MODULO, COMP_ARITHMETIC_MIN, COMP_ARITHMETIC_MAX, ) @@ -75,6 +77,8 @@ result = null break result /= value + if(COMP_ARITHMETIC_MODULO) + result %= value if(COMP_ARITHMETIC_MAX) result = max(result, value) if(COMP_ARITHMETIC_MIN) @@ -86,5 +90,6 @@ #undef COMP_ARITHMETIC_SUBTRACT #undef COMP_ARITHMETIC_MULTIPLY #undef COMP_ARITHMETIC_DIVIDE +#undef COMP_ARITHMETIC_MODULO #undef COMP_ARITHMETIC_MIN #undef COMP_ARITHMETIC_MAX From 6d423d29d92cc644a6499fcabf4014a5b3f0c908 Mon Sep 17 00:00:00 2001 From: "tgstation-ci[bot]" <179393467+tgstation-ci[bot]@users.noreply.github.com> Date: Fri, 29 Nov 2024 03:28:36 +0000 Subject: [PATCH 028/149] Automatic changelog for PR #88253 [ci skip] --- html/changelogs/AutoChangeLog-pr-88253.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-88253.yml diff --git a/html/changelogs/AutoChangeLog-pr-88253.yml b/html/changelogs/AutoChangeLog-pr-88253.yml new file mode 100644 index 0000000000000..eb837aa04dba1 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-88253.yml @@ -0,0 +1,4 @@ +author: "CRITAWAKETS" +delete-after: True +changes: + - rscadd: "Added in the modulo operator to the circuit arithmetic component." \ No newline at end of file From a17ad68508b99cfca766078f0488d0f0abcd233e Mon Sep 17 00:00:00 2001 From: Lucy Date: Thu, 28 Nov 2024 22:28:46 -0500 Subject: [PATCH 029/149] Fix double-encode in AI shuttle call reasons (#88245) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## About The Pull Request This fixes double html encoding with AI shuttle calls, due to `tgui_input_text` being called without setting `encode = FALSE` - `SSshuttle.requestEvac` expects unencoded text. I added documentation to `SSshuttle.requestEvac`, including clarifying that it expects non-html-encoded text. ## Why It's Good For The Game &​#​39;​ is annoying ## Changelog :cl: fix: Fixed double-encoded messages with AI shuttle call reasons. /:cl: --- code/controllers/subsystem/shuttle.dm | 7 +++++++ code/modules/mob/living/silicon/ai/ai.dm | 1 + 2 files changed, 8 insertions(+) diff --git a/code/controllers/subsystem/shuttle.dm b/code/controllers/subsystem/shuttle.dm index 0ad0a78589221..4f573ee2f2224 100644 --- a/code/controllers/subsystem/shuttle.dm +++ b/code/controllers/subsystem/shuttle.dm @@ -356,6 +356,13 @@ SUBSYSTEM_DEF(shuttle) return TRUE +/** + * Calls the emergency shuttle. + * + * Arguments: + * * user - The mob that called the shuttle. + * * call_reason - The reason the shuttle was called, which should be non-html-encoded text. + */ /datum/controller/subsystem/shuttle/proc/requestEvac(mob/user, call_reason) if (!check_backup_emergency_shuttle()) return diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm index 46cfb5980a20b..e2a898b352642 100644 --- a/code/modules/mob/living/silicon/ai/ai.dm +++ b/code/modules/mob/living/silicon/ai/ai.dm @@ -350,6 +350,7 @@ "What is the nature of your emergency? ([CALL_SHUTTLE_REASON_LENGTH] characters required.)", "Confirm Shuttle Call", max_length = MAX_MESSAGE_LEN, + encode = FALSE, ) if(incapacitated) From d313ec0e4185e17e0cf32c768578fcb12497a469 Mon Sep 17 00:00:00 2001 From: "tgstation-ci[bot]" <179393467+tgstation-ci[bot]@users.noreply.github.com> Date: Fri, 29 Nov 2024 03:29:07 +0000 Subject: [PATCH 030/149] Automatic changelog for PR #88245 [ci skip] --- html/changelogs/AutoChangeLog-pr-88245.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-88245.yml diff --git a/html/changelogs/AutoChangeLog-pr-88245.yml b/html/changelogs/AutoChangeLog-pr-88245.yml new file mode 100644 index 0000000000000..ea65524072acf --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-88245.yml @@ -0,0 +1,4 @@ +author: "Absolucy" +delete-after: True +changes: + - bugfix: "Fixed double-encoded messages with AI shuttle call reasons." \ No newline at end of file From 3cba7e201842ec51f2345f06058813b2105c6405 Mon Sep 17 00:00:00 2001 From: SmArtKar <44720187+SmArtKar@users.noreply.github.com> Date: Fri, 29 Nov 2024 06:29:16 +0300 Subject: [PATCH 031/149] Fixes Nebula's robotics fabricators being obstructed roundstart (#88236) ## About The Pull Request Closes #88230 ## Changelog :cl: fix: Fixed Nebula's robotics fabricators being obstructed roundstart /:cl: --- _maps/map_files/NebulaStation/NebulaStation.dmm | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/_maps/map_files/NebulaStation/NebulaStation.dmm b/_maps/map_files/NebulaStation/NebulaStation.dmm index f4e7bbd43cc51..15bcb272d73f0 100644 --- a/_maps/map_files/NebulaStation/NebulaStation.dmm +++ b/_maps/map_files/NebulaStation/NebulaStation.dmm @@ -23929,6 +23929,13 @@ /obj/effect/turf_decal/delivery, /turf/open/floor/iron/dark, /area/station/command/teleporter) +"dAP" = ( +/obj/effect/turf_decal/delivery, +/obj/machinery/mecha_part_fabricator{ + drop_direction = 1 + }, +/turf/open/floor/iron/dark, +/area/station/science/robotics/lab) "dAT" = ( /obj/effect/spawner/random/entertainment/toy_figure{ pixel_y = 37; @@ -141153,7 +141160,7 @@ /area/station/hallway/primary/central) "uYT" = ( /obj/machinery/mecha_part_fabricator{ - dir = 1 + drop_direction = 1 }, /obj/effect/turf_decal/delivery, /turf/open/floor/iron/dark, @@ -263701,7 +263708,7 @@ juD iZk vqW jyY -uYT +dAP xGM mVH xGM From ccc2533380f5acae6f6afedecd0677a34b729d0e Mon Sep 17 00:00:00 2001 From: "tgstation-ci[bot]" <179393467+tgstation-ci[bot]@users.noreply.github.com> Date: Fri, 29 Nov 2024 03:29:34 +0000 Subject: [PATCH 032/149] Automatic changelog for PR #88236 [ci skip] --- html/changelogs/AutoChangeLog-pr-88236.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-88236.yml diff --git a/html/changelogs/AutoChangeLog-pr-88236.yml b/html/changelogs/AutoChangeLog-pr-88236.yml new file mode 100644 index 0000000000000..71f8df6358def --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-88236.yml @@ -0,0 +1,4 @@ +author: "SmArtKar" +delete-after: True +changes: + - bugfix: "Fixed Nebula's robotics fabricators being obstructed roundstart" \ No newline at end of file From 1dff5f6de37bdc33efb3fcd05112c49ed2cc5acf Mon Sep 17 00:00:00 2001 From: Ghom <42542238+Ghommie@users.noreply.github.com> Date: Fri, 29 Nov 2024 04:33:18 +0100 Subject: [PATCH 033/149] Aquariums are now potential fishing spots. (#88243) ## About The Pull Request You can now fish from aquariums if you wish to. This includes some backend changes to make it possible for the fish table from get_fish_table() to contain instances, and all that it entails up to spawn_reward(), which is a requirement for the gimmick to respect the various traits and other variables of the already instantiated fish rather than read from cached properties. ## Why It's Good For The Game The fish progress score/index had only little nasty flaw that has been nagging me since day one: Not all fish species can be caught. Skipping McGill, which is a peculiar case that for cheevo purposes should be considered a standard goldfish, there is the one, unsignificant yet rare purple sludgefish which can only be gotten as a rare evolution of the generic sludgefish. Talk about petty, but this may be a long-term nit I prefer to handle right now. Also why not? The 'unmarine mastodon' is near impossible to get unless you somehow find a oil well which is locked behind a specific ruin. ## Changelog :cl: fix: Aquariums are now potential fishing spots. /:cl: --- code/__DEFINES/fish.dm | 8 +- code/__HELPERS/cmp.dm | 3 + .../subsystem/processing/fishing.dm | 45 ++++----- code/datums/components/_component.dm | 12 +-- code/datums/components/aquarium.dm | 2 + code/datums/components/fishing_spot.dm | 2 +- code/game/objects/items.dm | 5 +- code/game/turfs/turf.dm | 2 +- code/modules/fishing/bait.dm | 93 +++++++++---------- code/modules/fishing/fish/_fish.dm | 2 + code/modules/fishing/fish/chasm_detritus.dm | 4 +- code/modules/fishing/fish/types/freshwater.dm | 3 + code/modules/fishing/fish/types/station.dm | 1 + code/modules/fishing/fishing_equipment.dm | 8 +- code/modules/fishing/fishing_minigame.dm | 45 +++++++-- code/modules/fishing/sources/_fish_source.dm | 67 ++++++++----- code/modules/fishing/sources/source_types.dm | 40 ++++++++ code/modules/unit_tests/fish_unit_tests.dm | 6 +- strings/fishing_tips.txt | 3 +- 19 files changed, 221 insertions(+), 130 deletions(-) diff --git a/code/__DEFINES/fish.dm b/code/__DEFINES/fish.dm index c64a50cd077df..f9f390f95a189 100644 --- a/code/__DEFINES/fish.dm +++ b/code/__DEFINES/fish.dm @@ -187,7 +187,6 @@ ///Flag added when in an aquarium with the right fluid type. #define FISH_FLAG_SAFE_FLUID (1<<7) - #define MIN_AQUARIUM_TEMP T0C #define MAX_AQUARIUM_TEMP (T0C + 100) #define DEFAULT_AQUARIUM_TEMP (T0C + 24) @@ -260,11 +259,8 @@ #define FISH_SOURCE_FLAG_EXPLOSIVE_MALUS (1<<0) /// The fish source is not elegible for random rewards from bluespace fishing rods #define FISH_SOURCE_FLAG_NO_BLUESPACE_ROD (1<<1) -/** - * If present, fish that can be caught from this source won't be included in the 'fish caught' score, unless - * present in other sources without this flag as well. - */ -#define FISH_SOURCE_FLAG_SKIP_CATCHABLES (1<<2) +/// When examined by someone with enough fishing skill, this will also display fish that doesn't have FISH_FLAG_SHOW_IN_CATALOG +#define FISH_SOURCE_FLAG_IGNORE_HIDDEN_ON_CATALOG (1<<2) /** * A macro to ensure the wikimedia filenames of fish icons are unique, especially since there're a couple fish that have diff --git a/code/__HELPERS/cmp.dm b/code/__HELPERS/cmp.dm index 76651964e24e0..efee782aaeb8d 100644 --- a/code/__HELPERS/cmp.dm +++ b/code/__HELPERS/cmp.dm @@ -30,6 +30,9 @@ /proc/cmp_name_dsc(atom/a, atom/b) return sorttext(a.name, b.name) +/proc/cmp_init_name_asc(atom/a, atom/b) + return sorttext(initial(b.name), initial(a.name)) + /proc/cmp_records_asc(datum/record/a, datum/record/b) return sorttext(b.name, a.name) diff --git a/code/controllers/subsystem/processing/fishing.dm b/code/controllers/subsystem/processing/fishing.dm index 477dbf35e51d2..3f0433b21b9e8 100644 --- a/code/controllers/subsystem/processing/fishing.dm +++ b/code/controllers/subsystem/processing/fishing.dm @@ -19,10 +19,13 @@ PROCESSING_SUBSYSTEM_DEF(fishing) cached_fish_icons = list() cached_unknown_fish_icons = list() fish_properties = list() + catchable_fish = list() var/icon/questionmark = icon('icons/effects/random_spawners.dmi', "questionmark") var/list/mark_dimension = get_icon_dimensions(questionmark) - for(var/obj/item/fish/fish_type as anything in subtypesof(/obj/item/fish)) + var/list/spawned_fish = list() + var/list/fish_subtypes = sortTim(subtypesof(/obj/item/fish), GLOBAL_PROC_REF(cmp_init_name_asc)) + for(var/obj/item/fish/fish_type as anything in fish_subtypes) var/list/fish_dimensions = get_icon_dimensions(fish_type::icon) var/icon/fish_icon = icon(fish_type::icon, fish_type::icon_state, frame = 1, moving = FALSE) cached_fish_icons[fish_type] = icon2base64(fish_icon) @@ -35,6 +38,7 @@ PROCESSING_SUBSYSTEM_DEF(fishing) cached_unknown_fish_icons[fish_type] = icon2base64(unknown_icon) var/obj/item/fish/fish = new fish_type(null, FALSE) + spawned_fish += fish var/list/properties = list() fish_properties[fish_type] = properties properties[FISH_PROPERTIES_FAV_BAIT] = fish.favorite_bait.Copy() @@ -67,36 +71,35 @@ PROCESSING_SUBSYSTEM_DEF(fishing) properties[FISH_PROPERTIES_BEAUTY_SCORE] = beauty_score - qdel(fish) - - catchable_fish = list() - var/list/all_catchables = list() - for(var/source_type as anything in GLOB.preset_fish_sources) - var/datum/fish_source/source = GLOB.preset_fish_sources[source_type] - if(!(source.fish_source_flags & FISH_SOURCE_FLAG_SKIP_CATCHABLES)) - all_catchables |= source.fish_table - for(var/thing in all_catchables) - if(!ispath(thing, /obj/item/fish)) - continue - var/obj/item/fish/fishie = thing - var/fish_id = initial(fishie.fish_id) + var/fish_id + if(fish.fish_id_redirect_path) + var/obj/item/fish/other_path = fish.fish_id_redirect_path + if(!ispath(other_path, /obj/item/fish)) + stack_trace("[fish.type] has a set 'fish_id_redirect_path' variable but it isn't a fish path but [other_path]") + continue + fish_id = initial(other_path.fish_id) + else + fish_id = fish.fish_id if(!fish_id) - stack_trace("[fishie] doesn't have a set 'fish_id' variable despite being a catchable fish") + stack_trace("[fish.type] doesn't have a set 'fish_id' variable despite being a catchable fish") + continue + if(fish.fish_id_redirect_path) continue if(catchable_fish[fish_id]) - stack_trace("[fishie] has a 'fish_id' value already assigned to [catchable_fish[fish_id]]. fish_id: [fish_id]") + stack_trace("[fish.type] has a 'fish_id' value already assigned to [catchable_fish[fish_id]]. fish_id: [fish_id]") continue - catchable_fish[fish_id] = fishie + catchable_fish[fish_id] = fish.type ///init the list of things lures can catch lure_catchables = list() - var/list/fish_types = subtypesof(/obj/item/fish) for(var/lure_type in typesof(/obj/item/fishing_lure)) var/obj/item/fishing_lure/lure = new lure_type lure_catchables[lure_type] = list() - for(var/obj/item/fish/fish_type as anything in fish_types) - if(lure.is_catchable_fish(fish_type, fish_properties[fish_type])) - lure_catchables[lure_type] += fish_type + for(var/obj/item/fish/fish as anything in spawned_fish) + if(lure.is_catchable_fish(fish, fish_properties[fish.type])) + lure_catchables[lure_type] += fish.type qdel(lure) + QDEL_LIST(spawned_fish) + return SS_INIT_SUCCESS diff --git a/code/datums/components/_component.dm b/code/datums/components/_component.dm index 85def333f4c26..2887fc55f8dc4 100644 --- a/code/datums/components/_component.dm +++ b/code/datums/components/_component.dm @@ -470,13 +470,13 @@ for(var/component_key in dc) var/component_or_list = dc[component_key] if(islist(component_or_list)) - for(var/datum/component/I in component_or_list) - if(I.can_transfer) - target.TakeComponent(I) + for(var/datum/component/component in component_or_list) + if(component.can_transfer) + target.TakeComponent(component) else - var/datum/component/C = component_or_list - if(C.can_transfer) - target.TakeComponent(C) + var/datum/component/component = component_or_list + if(!QDELETED(component) && component.can_transfer) + target.TakeComponent(component) /** * Return the object that is the host of any UI's that this component has diff --git a/code/datums/components/aquarium.dm b/code/datums/components/aquarium.dm index e0ef6d8c04aa9..00a476959567e 100644 --- a/code/datums/components/aquarium.dm +++ b/code/datums/components/aquarium.dm @@ -118,6 +118,7 @@ RegisterSignal(movable, COMSIG_ATOM_UI_INTERACT, PROC_REF(interact)) movable.AddElement(/datum/element/relay_attackers) + movable.AddComponent(/datum/component/fishing_spot, /datum/fish_source/aquarium) for(var/atom/movable/content as anything in movable.contents) if(content.flags_1 & INITIALIZED_1) @@ -150,6 +151,7 @@ beauty_by_content = null tracked_fish_by_type = null movable.remove_traits(list(TRAIT_IS_AQUARIUM, TRAIT_AQUARIUM_PANEL_OPEN, TRAIT_STOP_FISH_REPRODUCTION_AND_GROWTH), AQUARIUM_TRAIT) + qdel(movable.GetComponent(/datum/component/fishing_spot)) REMOVE_KEEP_TOGETHER(movable, AQUARIUM_TRAIT) /datum/component/aquarium/PreTransfer(atom/movable/new_parent) diff --git a/code/datums/components/fishing_spot.dm b/code/datums/components/fishing_spot.dm index 3dc99cd8067de..3ce68dce33959 100644 --- a/code/datums/components/fishing_spot.dm +++ b/code/datums/components/fishing_spot.dm @@ -41,7 +41,7 @@ if(!HAS_MIND_TRAIT(user, TRAIT_EXAMINE_FISHING_SPOT)) return - if(!fish_source.has_known_fishes()) + if(!fish_source.has_known_fishes(source)) return examine_text += span_tinynoticeital("This is a fishing spot. You can look again to list its fishes...") diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index b8aec816391a9..cd2ec6c6476f7 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -1883,11 +1883,12 @@ return src /// Checks if the bait is liked by the fish type or not. Returns a multiplier that affects the chance of catching it. -/obj/item/proc/check_bait(obj/item/fish/fish_type) +/obj/item/proc/check_bait(obj/item/fish/fish) if(HAS_TRAIT(src, TRAIT_OMNI_BAIT)) return 1 var/catch_multiplier = 1 - var/list/properties = SSfishing.fish_properties[fish_type] + + var/list/properties = SSfishing.fish_properties[isfish(fish) ? fish.type : fish] //Bait matching likes doubles the chance var/list/fav_bait = properties[FISH_PROPERTIES_FAV_BAIT] for(var/bait_identifer in fav_bait) diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm index aab0f609d0e3f..bda90858cae4e 100644 --- a/code/game/turfs/turf.dm +++ b/code/game/turfs/turf.dm @@ -836,7 +836,7 @@ GLOBAL_LIST_EMPTY(station_turfs) . = ..() if(!fish_source || !HAS_MIND_TRAIT(user, TRAIT_EXAMINE_FISHING_SPOT)) return - if(!GLOB.preset_fish_sources[fish_source].has_known_fishes()) + if(!GLOB.preset_fish_sources[fish_source].has_known_fishes(src)) return . += span_tinynoticeital("This is a fishing spot. You can look again to list its fishes...") diff --git a/code/modules/fishing/bait.dm b/code/modules/fishing/bait.dm index 275f387cbdae7..50cb6ef09b163 100644 --- a/code/modules/fishing/bait.dm +++ b/code/modules/fishing/bait.dm @@ -88,13 +88,11 @@ rod.spin_frequency = null ///Called for every fish subtype by the fishing subsystem when initializing, to populate the list of fish that can be catched with this lure. -/obj/item/fishing_lure/proc/is_catchable_fish(obj/item/fish/fish_type, list/fish_properties) - var/avg_size = initial(fish_type.average_size) +/obj/item/fishing_lure/proc/is_catchable_fish(obj/item/fish/fish, list/fish_properties) var/intermediate_size = FISH_SIZE_SMALL_MAX + (FISH_SIZE_NORMAL_MAX - FISH_SIZE_SMALL_MAX) - if(!ISINRANGE(avg_size, FISH_SIZE_TINY_MAX * 0.5, intermediate_size)) + if(!ISINRANGE(fish.size, FISH_SIZE_TINY_MAX * 0.5, intermediate_size)) return FALSE - var/list/fish_traits = fish_properties[FISH_PROPERTIES_TRAITS] - if(length(list(/datum/fish_trait/vegan, /datum/fish_trait/picky_eater, /datum/fish_trait/nocturnal, /datum/fish_trait/heavy) & fish_traits)) + if(length(list(/datum/fish_trait/vegan, /datum/fish_trait/picky_eater, /datum/fish_trait/nocturnal, /datum/fish_trait/heavy) & fish.fish_traits)) return FALSE return TRUE @@ -120,11 +118,16 @@ . += span_info("You can catch the following fish with this lure: [english_list(known_fishes)].") ///Check if the fish is in the list of catchable fish for this fishing lure. Return value is a multiplier. -/obj/item/fishing_lure/check_bait(obj/item/fish/fish_type) +/obj/item/fishing_lure/check_bait(obj/item/fish/fish) var/multiplier = 0 - if(is_type_in_list(/obj/item/fishing_lure, SSfishing.fish_properties[fish_type][FISH_PROPERTIES_FAV_BAIT])) + var/is_instance = istype(fish) + var/list/fish_properties = SSfishing.fish_properties[is_instance ? fish.type : fish] + if(is_type_in_list(/obj/item/fishing_lure, fish_properties[FISH_PROPERTIES_FAV_BAIT])) multiplier += 2 - if(fish_type in SSfishing.lure_catchables[type]) + if(is_instance) + if(is_catchable_fish(fish, fish_properties)) + multiplier += 10 + else if(fish in SSfishing.lure_catchables[type]) multiplier += 10 return multiplier @@ -133,12 +136,10 @@ desc = "A bigger fishing lure that may attract larger fish. Tiny or picky prey will remain uninterested." icon_state = "plug" -/obj/item/fishing_lure/plug/is_catchable_fish(obj/item/fish/fish_type, list/fish_properties) - var/avg_size = initial(fish_type.average_size) - if(avg_size <= FISH_SIZE_SMALL_MAX) +/obj/item/fishing_lure/plug/is_catchable_fish(obj/item/fish/fish, list/fish_properties) + if(fish.size <= FISH_SIZE_SMALL_MAX) return FALSE - var/list/fish_traits = fish_properties[FISH_PROPERTIES_TRAITS] - if(length(list(/datum/fish_trait/vegan, /datum/fish_trait/picky_eater, /datum/fish_trait/nocturnal, /datum/fish_trait/heavy) & fish_traits)) + if(length(list(/datum/fish_trait/vegan, /datum/fish_trait/picky_eater, /datum/fish_trait/nocturnal, /datum/fish_trait/heavy) & fish.fish_traits)) return FALSE return TRUE @@ -148,17 +149,17 @@ icon_state = "dropping" spin_frequency = list(1.5 SECONDS, 2.8 SECONDS) -/obj/item/fishing_lure/dropping/is_catchable_fish(obj/item/fish/fish_type, list/fish_properties) +/obj/item/fishing_lure/dropping/is_catchable_fish(obj/item/fish/fish, list/fish_properties) var/list/sources = list(/datum/fish_source/toilet, /datum/fish_source/moisture_trap) for(var/datum/fish_source/source as anything in sources) var/datum/fish_source/instance = GLOB.preset_fish_sources[/datum/fish_source/toilet] - if(fish_type in instance.fish_table) + if(fish.type in instance.fish_table) return TRUE var/list/fav_baits = fish_properties[FISH_PROPERTIES_FAV_BAIT] for(var/list/identifier in fav_baits) if(identifier[FISH_BAIT_TYPE] == FISH_BAIT_FOODTYPE && (identifier[FISH_BAIT_VALUE] & (JUNKFOOD|GROSS|TOXIC))) return TRUE - if(initial(fish_type.beauty) <= FISH_BEAUTY_DISGUSTING) + if(fish.beauty <= FISH_BEAUTY_DISGUSTING) return TRUE return FALSE @@ -168,17 +169,15 @@ icon_state = "spoon" spin_frequency = list(1.25 SECONDS, 2.25 SECONDS) -/obj/item/fishing_lure/spoon/is_catchable_fish(obj/item/fish/fish_type, list/fish_properties) - var/avg_size = initial(fish_type.average_size) - if(!ISINRANGE(avg_size, FISH_SIZE_TINY_MAX + 1, FISH_SIZE_NORMAL_MAX)) +/obj/item/fishing_lure/spoon/is_catchable_fish(obj/item/fish/fish, list/fish_properties) + if(!ISINRANGE(fish.size, FISH_SIZE_TINY_MAX + 1, FISH_SIZE_NORMAL_MAX)) return FALSE - var/list/fish_traits = fish_properties[FISH_PROPERTIES_TRAITS] - if(length(list(/datum/fish_trait/vegan, /datum/fish_trait/picky_eater, /datum/fish_trait/nocturnal, /datum/fish_trait/heavy) & fish_traits)) + if(length(list(/datum/fish_trait/vegan, /datum/fish_trait/picky_eater, /datum/fish_trait/nocturnal, /datum/fish_trait/heavy) & fish.fish_traits)) return FALSE - var/fluid_type = initial(fish_type.required_fluid_type) + var/fluid_type = fish.required_fluid_type if(fluid_type == AQUARIUM_FLUID_FRESHWATER || fluid_type == AQUARIUM_FLUID_ANADROMOUS || fluid_type == AQUARIUM_FLUID_ANY_WATER) return TRUE - if((/datum/fish_trait/amphibious in fish_traits) && fluid_type == AQUARIUM_FLUID_AIR) + if((/datum/fish_trait/amphibious in fish.fish_traits) && fluid_type == AQUARIUM_FLUID_AIR) return TRUE return FALSE @@ -188,9 +187,8 @@ icon_state = "artificial_fly" spin_frequency = list(1.1 SECONDS, 2 SECONDS) -/obj/item/fishing_lure/artificial_fly/is_catchable_fish(obj/item/fish/fish_type, list/fish_properties) - var/list/fish_traits = fish_properties[FISH_PROPERTIES_TRAITS] - if(/datum/fish_trait/picky_eater in fish_traits) +/obj/item/fishing_lure/artificial_fly/is_catchable_fish(obj/item/fish/fish, list/fish_properties) + if(/datum/fish_trait/picky_eater in fish.fish_traits) return TRUE return FALSE @@ -216,9 +214,8 @@ . = ..() REMOVE_TRAIT(rod, TRAIT_ROD_IGNORE_ENVIRONMENT, type) -/obj/item/fishing_lure/led/is_catchable_fish(obj/item/fish/fish_type, list/fish_properties) - var/list/fish_traits = fish_properties[FISH_PROPERTIES_TRAITS] - if(length(list(/datum/fish_trait/nocturnal, /datum/fish_trait/heavy) & fish_traits)) +/obj/item/fishing_lure/led/is_catchable_fish(obj/item/fish/fish, list/fish_properties) + if(length(list(/datum/fish_trait/nocturnal, /datum/fish_trait/heavy) & fish.fish_traits)) return TRUE return FALSE @@ -236,9 +233,8 @@ . = ..() REMOVE_TRAIT(rod, TRAIT_ROD_ATTRACT_SHINY_LOVERS, REF(src)) -/obj/item/fishing_lure/lucky_coin/is_catchable_fish(obj/item/fish/fish_type, list/fish_properties) - var/list/fish_traits = fish_properties[FISH_PROPERTIES_TRAITS] - if(/datum/fish_trait/shiny_lover in fish_traits) +/obj/item/fishing_lure/lucky_coin/is_catchable_fish(obj/item/fish/fish, list/fish_properties) + if(/datum/fish_trait/shiny_lover in fish.fish_traits) return TRUE return FALSE @@ -248,9 +244,8 @@ icon_state = "algae" spin_frequency = list(3 SECONDS, 5 SECONDS) -/obj/item/fishing_lure/algae/is_catchable_fish(obj/item/fish/fish_type, list/fish_properties) - var/list/fish_traits = fish_properties[FISH_PROPERTIES_TRAITS] - if(/datum/fish_trait/vegan in fish_traits) +/obj/item/fishing_lure/algae/is_catchable_fish(obj/item/fish/fish, list/fish_properties) + if(/datum/fish_trait/vegan in fish.fish_traits) return TRUE return FALSE @@ -260,11 +255,10 @@ icon_state = "grub" spin_frequency = list(1 SECONDS, 2.7 SECONDS) -/obj/item/fishing_lure/grub/is_catchable_fish(obj/item/fish/fish_type, list/fish_properties) - if(initial(fish_type.average_size) >= FISH_SIZE_SMALL_MAX) +/obj/item/fishing_lure/grub/is_catchable_fish(obj/item/fish/fish, list/fish_properties) + if(fish.size >= FISH_SIZE_SMALL_MAX) return FALSE - var/list/fish_traits = fish_properties[FISH_PROPERTIES_TRAITS] - if(length(list(/datum/fish_trait/vegan, /datum/fish_trait/picky_eater) & fish_traits)) + if(length(list(/datum/fish_trait/vegan, /datum/fish_trait/picky_eater) & fish.fish_traits)) return FALSE return TRUE @@ -274,9 +268,8 @@ icon_state = "buzzbait" spin_frequency = list(0.8 SECONDS, 1.7 SECONDS) -/obj/item/fishing_lure/buzzbait/is_catchable_fish(obj/item/fish/fish_type, list/fish_properties) - var/list/fish_traits = fish_properties[FISH_PROPERTIES_TRAITS] - if(/datum/fish_trait/electrogenesis in fish_traits) +/obj/item/fishing_lure/buzzbait/is_catchable_fish(obj/item/fish/fish, list/fish_properties) + if(HAS_TRAIT(fish, TRAIT_FISH_ELECTROGENESIS)) return TRUE return FALSE @@ -286,14 +279,13 @@ icon_state = "spinnerbait" spin_frequency = list(2 SECONDS, 4 SECONDS) -/obj/item/fishing_lure/spinnerbait/is_catchable_fish(obj/item/fish/fish_type, list/fish_properties) - var/list/fish_traits = fish_properties[FISH_PROPERTIES_TRAITS] - if(!(/datum/fish_trait/predator in fish_traits)) +/obj/item/fishing_lure/spinnerbait/is_catchable_fish(obj/item/fish/fish, list/fish_properties) + if(!(/datum/fish_trait/predator in fish.fish_traits)) return FALSE - var/init_fluid_type = initial(fish_type.required_fluid_type) + var/init_fluid_type = fish.required_fluid_type if(init_fluid_type == AQUARIUM_FLUID_FRESHWATER || init_fluid_type == AQUARIUM_FLUID_ANADROMOUS || init_fluid_type == AQUARIUM_FLUID_ANY_WATER) return TRUE - if((/datum/fish_trait/amphibious in fish_traits) && init_fluid_type == AQUARIUM_FLUID_AIR) //fluid type is changed to freshwater on init + if((/datum/fish_trait/amphibious in fish.fish_traits) && init_fluid_type == AQUARIUM_FLUID_AIR) //fluid type is changed to freshwater on init return TRUE return FALSE @@ -303,11 +295,10 @@ icon_state = "daisy_chain" spin_frequency = list(2 SECONDS, 4 SECONDS) -/obj/item/fishing_lure/daisy_chain/is_catchable_fish(obj/item/fish/fish_type, list/fish_properties) - var/list/fish_traits = fish_properties[FISH_PROPERTIES_TRAITS] - if(!(/datum/fish_trait/predator in fish_traits)) +/obj/item/fishing_lure/daisy_chain/is_catchable_fish(obj/item/fish/fish, list/fish_properties) + if(!(/datum/fish_trait/predator in fish.fish_traits)) return FALSE - var/init_fluid_type = initial(fish_type.required_fluid_type) + var/init_fluid_type = fish.required_fluid_type if(init_fluid_type == AQUARIUM_FLUID_SALTWATER || init_fluid_type == AQUARIUM_FLUID_ANADROMOUS || init_fluid_type == AQUARIUM_FLUID_ANY_WATER) return TRUE return FALSE diff --git a/code/modules/fishing/fish/_fish.dm b/code/modules/fishing/fish/_fish.dm index fcad429c2b9eb..1521eb4cc7767 100644 --- a/code/modules/fishing/fish/_fish.dm +++ b/code/modules/fishing/fish/_fish.dm @@ -170,6 +170,8 @@ * Once set, the value shouldn't be changed, so don't make typos. */ var/fish_id + ///Used to redirect to another fish path so that catching this fish unlocks its entry instead. + var/obj/item/fish/fish_id_redirect_path /obj/item/fish/Initialize(mapload, apply_qualities = TRUE) . = ..() diff --git a/code/modules/fishing/fish/chasm_detritus.dm b/code/modules/fishing/fish/chasm_detritus.dm index 50b35f7d07447..05db957100470 100644 --- a/code/modules/fishing/fish/chasm_detritus.dm +++ b/code/modules/fishing/fish/chasm_detritus.dm @@ -61,7 +61,9 @@ GLOBAL_LIST_INIT_TYPED(chasm_detritus_types, /datum/chasm_detritus, init_chasm_d var/default_spawn = pick(default_contents[default_contents_key]) return new default_spawn(fisher_turf) - return determine_detritus(chasm_contents) + var/atom/movable/detritus = determine_detritus(chasm_contents) + detritus.forceMove(fisher_turf) + return detritus /datum/chasm_detritus/proc/get_chasm_contents(turf/fishing_spot) . = list() diff --git a/code/modules/fishing/fish/types/freshwater.dm b/code/modules/fishing/fish/types/freshwater.dm index 16687bc649790..4e7a7d9c9ebf0 100644 --- a/code/modules/fishing/fish/types/freshwater.dm +++ b/code/modules/fishing/fish/types/freshwater.dm @@ -25,6 +25,7 @@ /obj/item/fish/goldfish/gill name = "McGill" desc = "A great rubber duck tool for Lawyers who can't get a grasp over their case." + fish_id_redirect_path = /obj/item/fish/goldfish stable_population = 1 random_case_rarity = FISH_RARITY_NOPE fish_flags = parent_type::fish_flags & ~FISH_FLAG_SHOW_IN_CATALOG @@ -61,6 +62,7 @@ /obj/item/fish/goldfish/three_eyes/gill name = "McGill" desc = "A great rubber duck tool for Lawyers who can't get a grasp over their case. It looks kinda different today..." + fish_id_redirect_path = /obj/item/fish/goldfish/three_eyes compatible_types = list(/obj/item/fish/goldfish, /obj/item/fish/goldfish/three_eyes) beauty = FISH_BEAUTY_GREAT fish_flags = parent_type::fish_flags & ~FISH_FLAG_SHOW_IN_CATALOG @@ -163,6 +165,7 @@ /obj/item/fish/tadpole name = "tadpole" + fish_id = "tadpole" desc = "The larval spawn of an amphibian. A very minuscle, round creature with a long tail it uses to swim around." icon_state = "tadpole" average_size = 3 diff --git a/code/modules/fishing/fish/types/station.dm b/code/modules/fishing/fish/types/station.dm index 8d958303bf319..353201a1afc78 100644 --- a/code/modules/fishing/fish/types/station.dm +++ b/code/modules/fishing/fish/types/station.dm @@ -64,6 +64,7 @@ /obj/item/fish/sludgefish/purple name = "purple sludgefish" + fish_id = "purple_sludgefish" desc = "A misshapen, fragile, loosely fish-like living goop. This one has developed sexual reproduction mechanisms, and a purple tint to boot." icon_state = "sludgefish_purple" random_case_rarity = FISH_RARITY_NOPE diff --git a/code/modules/fishing/fishing_equipment.dm b/code/modules/fishing/fishing_equipment.dm index d1ed33e9a2154..37aea262426bb 100644 --- a/code/modules/fishing/fishing_equipment.dm +++ b/code/modules/fishing/fishing_equipment.dm @@ -215,8 +215,8 @@ SIGNAL_HANDLER REMOVE_TRAIT(rod, TRAIT_ROD_REMOVE_FISHING_DUD, REF(src)) -/obj/item/fishing_hook/magnet/get_hook_bonus_multiplicative(fish_type, datum/fish_source/source) - if(fish_type == FISHING_DUD || ispath(fish_type, /obj/item/fish)) +/obj/item/fishing_hook/magnet/get_hook_bonus_multiplicative(fish_type) + if(fish_type == FISHING_DUD || ispath(fish_type, /obj/item/fish) || isfish(fish_type)) return ..() // We multiply the odds by five for everything that's not a fish nor a dud @@ -275,9 +275,9 @@ return "The hook on your fishing rod wasn't meant for traditional fishing, rendering it useless at doing so!" -/obj/item/fishing_hook/rescue/get_hook_bonus_multiplicative(fish_type, datum/fish_source/source) +/obj/item/fishing_hook/rescue/get_hook_bonus_multiplicative(fish_type) // Sorry, you won't catch fish with this. - if(ispath(fish_type, /obj/item/fish)) + if(ispath(fish_type, /obj/item/fish) || isfish(fish_type)) return RESCUE_HOOK_FISH_MULTIPLIER return ..() diff --git a/code/modules/fishing/fishing_minigame.dm b/code/modules/fishing/fishing_minigame.dm index a8fa4d26ad8da..75cd0043d2274 100644 --- a/code/modules/fishing/fishing_minigame.dm +++ b/code/modules/fishing/fishing_minigame.dm @@ -357,11 +357,12 @@ GLOBAL_LIST_EMPTY(fishing_challenges_by_user) if(win) if(reward_path != FISHING_DUD) playsound(location, 'sound/effects/bigsplash.ogg', 100) - if(ispath(reward_path, /obj/item/fish)) + if(ispath(reward_path, /obj/item/fish) || isfish(reward_path)) var/obj/item/fish/fish_reward = reward_path - var/fish_id = initial(fish_reward.fish_id) + var/obj/item/fish/redirect_path = initial(fish_reward.fish_id_redirect_path) + var/fish_id = ispath(redirect_path, /obj/item/fish) ? initial(redirect_path.fish_id) : initial(fish_reward.fish_id) if(fish_id) - user.client?.give_award(/datum/award/score/progress/fish, user, initial(fish_reward.fish_id)) + user.client?.give_award(/datum/award/score/progress/fish, user, fish_id) SEND_SIGNAL(user, COMSIG_MOB_COMPLETE_FISHING, src, win) if(!QDELETED(src)) qdel(src) @@ -397,7 +398,13 @@ GLOBAL_LIST_EMPTY(fishing_challenges_by_user) playsound(location, 'sound/effects/fish_splash.ogg', 100) if(HAS_MIND_TRAIT(user, TRAIT_REVEAL_FISH)) - fish_icon = GLOB.specific_fish_icons[reward_path] || FISH_ICON_DEF + var/possible_icon + if(isatom(reward_path)) + var/atom/reward = reward_path + possible_icon = GLOB.specific_fish_icons[reward.type] + else + possible_icon = GLOB.specific_fish_icons[reward_path] + fish_icon = possible_icon || FISH_ICON_DEF switch(fish_icon) if(FISH_ICON_DEF) send_alert("fish!!!") @@ -455,11 +462,22 @@ GLOBAL_LIST_EMPTY(fishing_challenges_by_user) SIGNAL_HANDLER interrupt() +/datum/fishing_challenge/proc/on_reward_removed(datum/source) + SIGNAL_HANDLER + send_alert("reward gone!") + interrupt() + +/datum/fishing_challenge/proc/on_fish_death(obj/item/fish/source) + SIGNAL_HANDLER + if(source.status == FISH_DEAD) + win_anyway() + /datum/fishing_challenge/proc/win_anyway() - if(!completed) - //winning by timeout or idling around shouldn't give as much experience. - experience_multiplier *= 0.5 - complete(TRUE) + if(completed) + return + //winning by timeout / fish death shouldn't give as much experience. + experience_multiplier *= 0.5 + complete(TRUE) /datum/fishing_challenge/proc/hurt_fish(datum/source, obj/item/fish/reward) SIGNAL_HANDLER @@ -506,13 +524,15 @@ GLOBAL_LIST_EMPTY(fishing_challenges_by_user) if(difficulty > FISHING_DEFAULT_DIFFICULTY) completion -= MAX_FISH_COMPLETION_MALUS * (difficulty * 0.01) + var/is_fish_instance = isfish(reward_path) + /// Fish minigame properties - if(ispath(reward_path,/obj/item/fish)) + if(ispath(reward_path,/obj/item/fish) || is_fish_instance) var/obj/item/fish/fish = reward_path var/movement_path = initial(fish.fish_movement_type) mover = new movement_path(src) // Apply fish trait modifiers - var/list/fish_traits = SSfishing.fish_properties[fish][FISH_PROPERTIES_TRAITS] + var/list/fish_traits = is_fish_instance ? fish.fish_traits : SSfishing.fish_properties[fish][FISH_PROPERTIES_TRAITS] for(var/fish_trait in fish_traits) var/datum/fish_trait/trait = GLOB.fish_traits[fish_trait] trait.minigame_mod(used_rod, user, src) @@ -552,6 +572,11 @@ GLOBAL_LIST_EMPTY(fishing_challenges_by_user) var/obj/item/fish/fish = reward_path var/wait_time = (initial(fish.health) / FISH_DAMAGE_PER_SECOND) SECONDS addtimer(CALLBACK(src, PROC_REF(win_anyway)), wait_time, TIMER_DELETE_ME) + else if(ismovable(reward_path)) + var/atom/movable/reward = reward_path + RegisterSignal(reward, COMSIG_MOVABLE_MOVED, PROC_REF(on_reward_removed)) + if(is_fish_instance) + RegisterSignal(reward, COMSIG_FISH_STATUS_CHANGED, PROC_REF(on_fish_death)) start_time = world.time ///Throws a stack with prefixed text. diff --git a/code/modules/fishing/sources/_fish_source.dm b/code/modules/fishing/sources/_fish_source.dm index a80a2514762b5..abf3a298462cb 100644 --- a/code/modules/fishing/sources/_fish_source.dm +++ b/code/modules/fishing/sources/_fish_source.dm @@ -180,16 +180,20 @@ GLOBAL_LIST_INIT(specific_fish_icons, generate_specific_fish_icons()) // Difficulty modifier added by the rod . += rod.difficulty_modifier - if(!ispath(result,/obj/item/fish)) + var/is_fish_instance = isfish(result) + if(!ispath(result,/obj/item/fish) && !is_fish_instance) // In the future non-fish rewards can have variable difficulty calculated here return var/obj/item/fish/caught_fish = result - var/list/fish_properties = SSfishing.fish_properties[caught_fish] + + //Just to clarify when we should use the path instead of the fish, which can be both a path and an instance. + var/result_path = is_fish_instance ? caught_fish.type : result + // Baseline fish difficulty . += initial(caught_fish.fishing_difficulty_modifier) - + var/list/fish_properties = SSfishing.fish_properties[result_path] if(rod.bait) var/obj/item/bait = rod.bait //Fav bait makes it easier @@ -204,7 +208,11 @@ GLOBAL_LIST_INIT(specific_fish_icons, generate_specific_fish_icons()) . += DISLIKED_BAIT_DIFFICULTY_MOD // Matching/not matching fish traits and equipment - var/list/fish_traits = fish_properties[FISH_PROPERTIES_TRAITS] + var/list/fish_traits + if(is_fish_instance) + fish_traits = caught_fish.fish_traits + else + fish_traits = fish_properties[FISH_PROPERTIES_TRAITS] var/additive_mod = 0 var/multiplicative_mod = 1 @@ -217,6 +225,7 @@ GLOBAL_LIST_INIT(specific_fish_icons, generate_specific_fish_icons()) . += additive_mod . *= multiplicative_mod + ///Comsig proc from the fishing minigame for 'roll_reward' /datum/fish_source/proc/roll_reward_minigame(datum/source, obj/item/fishing_rod/rod, mob/fisherman, atom/location, list/rewards) SIGNAL_HANDLER @@ -265,8 +274,6 @@ GLOBAL_LIST_INIT(specific_fish_icons, generate_specific_fish_icons()) else if(istype(reward, /obj/effect/spawner)) // Do not attempt to forceMove() a spawner. It will break things, and the spawned item should already be at the mob's turf by now. fisherman.balloon_alert(fisherman, "caught something!") return - else // for fishing things like corpses, move them to the turf of the fisherman - INVOKE_ASYNC(reward, TYPE_PROC_REF(/atom/movable, forceMove), get_turf(fisherman)) fisherman.balloon_alert(fisherman, "caught [reward]!") return reward @@ -306,6 +313,10 @@ GLOBAL_LIST_INIT(specific_fish_icons, generate_specific_fish_icons()) /datum/fish_source/proc/spawn_reward(reward_path, atom/spawn_location, atom/fishing_spot) if(reward_path == FISHING_DUD) return + if(ismovable(reward_path)) + var/atom/movable/reward = reward_path + reward.forceMove(spawn_location) + return reward if(ispath(reward_path, /datum/chasm_detritus)) return GLOB.chasm_detritus_types[reward_path].dispense_detritus(spawn_location, fishing_spot) if(!ispath(reward_path, /atom/movable)) @@ -317,7 +328,7 @@ GLOBAL_LIST_INIT(specific_fish_icons, generate_specific_fish_icons()) return reward /// Returns the fish table, with with the unavailable items from fish_counts removed. -/datum/fish_source/proc/get_fish_table(from_explosion = FALSE) +/datum/fish_source/proc/get_fish_table(atom/location, from_explosion = FALSE) var/list/table = fish_table.Copy() //message bottles cannot spawn from explosions. They're meant to be one-time messages (rarely) and photos from past rounds //and it would suck if the pool of bottle messages were constantly being emptied by explosive fishing. @@ -336,8 +347,7 @@ GLOBAL_LIST_INIT(specific_fish_icons, generate_specific_fish_icons()) ///Multiplier used to make fishes more common compared to everything else. var/result_multiplier = 1 - - var/list/final_table = get_fish_table() + var/list/final_table = get_fish_table(location) if(bait) for(var/trait in weight_result_multiplier) @@ -357,7 +367,7 @@ GLOBAL_LIST_INIT(specific_fish_icons, generate_specific_fish_icons()) final_table[result] *= rod.hook.get_hook_bonus_multiplicative(result) final_table[result] += rod.hook.get_hook_bonus_additive(result)//Decide on order here so it can be multiplicative - if(ispath(result, /obj/item/fish)) + if(ispath(result, /obj/item/fish) || isfish(result)) if(bait) final_table[result] = round(final_table[result] * result_multiplier, 1) var/mult = bait.check_bait(result) @@ -384,7 +394,7 @@ GLOBAL_LIST_INIT(specific_fish_icons, generate_specific_fish_icons()) var/highest_fish_weight var/list/collected_fish_weights = list() for(var/fishable in table) - if(ispath(fishable, /obj/item/fish)) + if(ispath(fishable, /obj/item/fish) || isfish(fishable)) var/fish_weight = table[fishable] collected_fish_weights[fishable] = fish_weight if(fish_weight > highest_fish_weight) @@ -397,30 +407,38 @@ GLOBAL_LIST_INIT(specific_fish_icons, generate_specific_fish_icons()) table[fish] += round(difference**exponent, 1) /datum/fish_source/proc/get_fish_trait_catch_mods(weight, obj/item/fish/fish, obj/item/fishing_rod/rod, mob/user, atom/location) - if(!ispath(fish, /obj/item/fish)) + var/is_fish_instance = isfish(fish) + if(!ispath(fish, /obj/item/fish) && !is_fish_instance) return weight var/multiplier = 1 - for(var/fish_trait in SSfishing.fish_properties[fish][FISH_PROPERTIES_TRAITS]) + var/list/fish_traits + if(is_fish_instance) + fish_traits = fish.fish_traits + else + fish_traits = SSfishing.fish_properties[fish][FISH_PROPERTIES_TRAITS] + for(var/fish_trait in fish_traits) var/datum/fish_trait/trait = GLOB.fish_traits[fish_trait] - var/list/mod = trait.catch_weight_mod(rod, user, location, fish) + var/list/mod = trait.catch_weight_mod(rod, user, location, is_fish_instance ? fish.type : fish) weight += mod[ADDITIVE_FISHING_MOD] multiplier *= mod[MULTIPLICATIVE_FISHING_MOD] return round(weight * multiplier, 1) ///returns true if this fishing spot has fish that are shown in the catalog. -/datum/fish_source/proc/has_known_fishes() - for(var/reward in fish_table) - if(!ispath(reward, /obj/item/fish)) +/datum/fish_source/proc/has_known_fishes(atom/location) + var/show_anyway = fish_source_flags & FISH_SOURCE_FLAG_IGNORE_HIDDEN_ON_CATALOG + for(var/reward in get_fish_table(location)) + if(!ispath(reward, /obj/item/fish) && !isfish(reward)) continue var/obj/item/fish/prototype = reward - if(initial(prototype.fish_flags) & FISH_FLAG_SHOW_IN_CATALOG) + if(!show_anyway && initial(prototype.fish_flags) & FISH_FLAG_SHOW_IN_CATALOG) return TRUE return FALSE ///Add a string with the names of catchable fishes to the examine text. /datum/fish_source/proc/get_catchable_fish_names(mob/user, atom/location, list/examine_text) var/list/known_fishes = list() + var/show_anyway = fish_source_flags & FISH_SOURCE_FLAG_IGNORE_HIDDEN_ON_CATALOG var/obj/item/fishing_rod/rod = user.get_active_held_item() var/list/final_table @@ -433,17 +451,18 @@ GLOBAL_LIST_INIT(specific_fish_icons, generate_specific_fish_icons()) var/list/rodless_weights = list() var/total_rod_weight = 0 var/list/rod_weights = list() - for(var/reward in fish_table) - var/weight = fish_table[reward] + var/list/table = get_fish_table(location) + for(var/reward in table) + var/weight = table[reward] var/final_weight if(rod) total_weight += weight final_weight = final_table[reward] total_rod_weight += final_weight - if(!ispath(reward, /obj/item/fish)) + if(!ispath(reward, /obj/item/fish) && !isfish(reward)) continue var/obj/item/fish/prototype = reward - if(!(initial(prototype.fish_flags) & FISH_FLAG_SHOW_IN_CATALOG)) + if(!show_anyway && !(initial(prototype.fish_flags) & FISH_FLAG_SHOW_IN_CATALOG)) continue if(rod) rodless_weights[reward] = weight @@ -472,7 +491,7 @@ GLOBAL_LIST_INIT(specific_fish_icons, generate_specific_fish_icons()) var/info = "You can catch the following fish here" if(rod) - info = span_tooltip("boldened are the fish you're more likely to catch with your current setup. The opposite is true for smaller names", info) + info = span_tooltip("In bold are fish you're more likely to catch with the current setup. The opposite is true for the smaller font", info) examine_text += span_info("[info]: [english_list(known_fishes)].") ///How much the explosive_fishing_score impacts explosive fishing. The higher the value, the stronger the malus for repeated calls @@ -493,7 +512,7 @@ GLOBAL_LIST_INIT(specific_fish_icons, generate_specific_fish_icons()) for(var/i in 1 to (severity + 2)) if(!prob((100 + 100 * severity)/i * multiplier)) continue - var/reward_loot = pick_weight(get_fish_table(from_explosion = TRUE)) + var/reward_loot = pick_weight(get_fish_table(location, from_explosion = TRUE)) var/atom/spawn_location = isturf(location) ? location : location.drop_location() var/atom/movable/reward = simple_dispense_reward(reward_loot, spawn_location, location) if(isnull(reward)) diff --git a/code/modules/fishing/sources/source_types.dm b/code/modules/fishing/sources/source_types.dm index c056000c45fde..b14ec608558d1 100644 --- a/code/modules/fishing/sources/source_types.dm +++ b/code/modules/fishing/sources/source_types.dm @@ -698,6 +698,46 @@ return data +#define RANDOM_AQUARIUM_FISH "random_aquarium_fish" + +/datum/fish_source/aquarium + radial_state = "fish_tank" + fish_table = list( + FISHING_DUD = 10, + ) + fish_source_flags = FISH_SOURCE_FLAG_NO_BLUESPACE_ROD|FISH_SOURCE_FLAG_IGNORE_HIDDEN_ON_CATALOG + fishing_difficulty = FISHING_EASY_DIFFICULTY - 5 + +#undef RANDOM_AQUARIUM_FISH + +/datum/fish_source/aquarium/get_fish_table(atom/location, from_explosion = FALSE) + if(istype(location, /obj/machinery/fishing_portal_generator)) + var/obj/machinery/fishing_portal_generator/portal = location + location = portal.current_linked_atom + var/list/table = list() + for(var/obj/item/fish/fish in location) + if(fish.status == FISH_DEAD) //dead fish cannot be caught + continue + table[fish] = 10 + if(!length(table)) + return fish_table + return table + +/datum/fish_source/aquarium/spawn_reward_from_explosion(atom/location, severity) + return //If the aquarium breaks, all fish are released anyway. + +/datum/fish_source/aquarium/generate_wiki_contents(datum/autowiki/fish_sources/wiki) + var/list/data = list() + + data += LIST_VALUE_WRAP_LISTS(list( + FISH_SOURCE_AUTOWIKI_NAME = "Fish", + FISH_SOURCE_AUTOWIKI_DUD = "", + FISH_SOURCE_AUTOWIKI_WEIGHT = 100, + FISH_SOURCE_AUTOWIKI_NOTES = "Any fish currently inside the aquarium, be they alive or dead.", + )) + + return data + /datum/fish_source/hot_spring catalog_description = "Hot Springs" radial_state = "onsen" diff --git a/code/modules/unit_tests/fish_unit_tests.dm b/code/modules/unit_tests/fish_unit_tests.dm index b399dcb94e12e..767c1ceeaebfa 100644 --- a/code/modules/unit_tests/fish_unit_tests.dm +++ b/code/modules/unit_tests/fish_unit_tests.dm @@ -101,6 +101,7 @@ stable_population = INFINITY breeding_timeout = 0 fish_flags = parent_type::fish_flags & ~(FISH_FLAG_SHOW_IN_CATALOG|FISH_FLAG_EXPERIMENT_SCANNABLE) + fish_id_redirect_path = /obj/item/fish/goldfish //Stops SSfishing from complaining var/expected_num_fillets = 0 //used to know how many fillets should be gotten out of this fish /obj/item/fish/testdummy/add_fillet_type() @@ -368,6 +369,7 @@ /obj/item/fish/chasm_crab/instant_growth fish_traits = list() //We don't want to end up applying traits twice on the resulting lobstrosity + fish_id_redirect_path = /obj/item/fish/chasm_crab /datum/unit_test/fish_sources @@ -419,10 +421,10 @@ /datum/fish_source/unit_test_profound_fisher fish_table = list(/obj/item/fish/testdummy = 1) fish_counts = list(/obj/item/fish/testdummy = 2) - fish_source_flags = parent_type::fish_source_flags | FISH_SOURCE_FLAG_SKIP_CATCHABLES + fish_source_flags = parent_type::fish_source_flags /datum/fish_source/unit_test_all_fish - fish_source_flags = parent_type::fish_source_flags | FISH_SOURCE_FLAG_SKIP_CATCHABLES + fish_source_flags = parent_type::fish_source_flags /datum/fish_source/unit_test_all_fish/New() for(var/fish_type as anything in subtypesof(/obj/item/fish)) diff --git a/strings/fishing_tips.txt b/strings/fishing_tips.txt index 836cab85da53f..466540bb187b1 100644 --- a/strings/fishing_tips.txt +++ b/strings/fishing_tips.txt @@ -54,4 +54,5 @@ Fish can grow in size and weight if you fed them somewhat frequently. Giving the Feeding a fish mutagen can triple the probability of generating evolved offsprings, provided it has an evolution. You can print fishing rods of different materials from an autolathe, which can inrease or decrease fishing difficulty, casting range, experience gained and can have other, special effects. Albeit scarcely, it's possible to catch fish made of the same materials of a custom material fishing rod. Equipping a shiny fishing hook and the quality of the bait can improve your odds. -You can use a fishing rod to snatch random organs during the "manipulate organs" step of the "organ manipulation" surgery. \ No newline at end of file +You can use a fishing rod to snatch random organs during the "manipulate organs" step of the "organ manipulation" surgery. +Aquariums are also potential fishing spots. Only useful for catching fish you couldn't find in the wild, as a personal achievement and nothing more. \ No newline at end of file From 5cada1392ae9fd15c7446e3b844bf6e335eda05d Mon Sep 17 00:00:00 2001 From: "tgstation-ci[bot]" <179393467+tgstation-ci[bot]@users.noreply.github.com> Date: Fri, 29 Nov 2024 03:33:40 +0000 Subject: [PATCH 034/149] Automatic changelog for PR #88243 [ci skip] --- html/changelogs/AutoChangeLog-pr-88243.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-88243.yml diff --git a/html/changelogs/AutoChangeLog-pr-88243.yml b/html/changelogs/AutoChangeLog-pr-88243.yml new file mode 100644 index 0000000000000..e8f1bd2db22eb --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-88243.yml @@ -0,0 +1,4 @@ +author: "Ghommie" +delete-after: True +changes: + - bugfix: "Aquariums are now potential fishing spots." \ No newline at end of file From c2413a0b1cdb1db26d0070a930e0887cc1b8193b Mon Sep 17 00:00:00 2001 From: Lucy Date: Fri, 29 Nov 2024 04:50:22 -0500 Subject: [PATCH 035/149] Fix hands/clothes still getting covered in blood with light step (#88247) --- code/datums/components/bloodysoles.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/datums/components/bloodysoles.dm b/code/datums/components/bloodysoles.dm index 461cfcff3aae4..32ec8177f467a 100644 --- a/code/datums/components/bloodysoles.dm +++ b/code/datums/components/bloodysoles.dm @@ -108,7 +108,7 @@ set_bloody_shoes(pool.blood_state, new_our_bloodiness) pool.bloodiness = total_bloodiness - new_our_bloodiness // Give the pool the remaining blood incase we were limited - if(HAS_TRAIT(parent_atom, TRAIT_LIGHT_STEP)) //the character is agile enough to don't mess their clothing and hands just from one blood splatter at floor + if(HAS_TRAIT(parent_atom, TRAIT_LIGHT_STEP) || (wielder && HAS_TRAIT(wielder, TRAIT_LIGHT_STEP))) //the character is agile enough to don't mess their clothing and hands just from one blood splatter at floor return TRUE parent_atom.add_blood_DNA(GET_ATOM_BLOOD_DNA(pool)) From f176db342c88a0e6c1ec150fbeb2fe4f5e2f3215 Mon Sep 17 00:00:00 2001 From: "tgstation-ci[bot]" <179393467+tgstation-ci[bot]@users.noreply.github.com> Date: Fri, 29 Nov 2024 10:01:57 +0000 Subject: [PATCH 036/149] Automatic changelog for PR #88247 [ci skip] --- html/changelogs/AutoChangeLog-pr-88247.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-88247.yml diff --git a/html/changelogs/AutoChangeLog-pr-88247.yml b/html/changelogs/AutoChangeLog-pr-88247.yml new file mode 100644 index 0000000000000..217f594f040f5 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-88247.yml @@ -0,0 +1,4 @@ +author: "Absolucy" +delete-after: True +changes: + - bugfix: "Light Step now properly prevents your hands and clothes from getting covered in blood when stepping in it." \ No newline at end of file From 499874fa8998eb85630666dd0570e5c632a28c0f Mon Sep 17 00:00:00 2001 From: SmArtKar <44720187+SmArtKar@users.noreply.github.com> Date: Fri, 29 Nov 2024 17:32:58 +0300 Subject: [PATCH 037/149] Moves damage overlay disabling into a separate trait for the numb quirk (#88281) ## About The Pull Request Detemination gives you TRAIT_ANALGESIA, so if you take ***too much*** damage you'll be unable to see it as well. Plus linking blunt overlay hiding to reagents isn't very good practice as it can cause flickering if you microdose. (Also fixed incorrect trait sources on the quirk and kept it for the nocrit deathmatch modifier) Closes #88278 ## Changelog :cl: fix: Fixed damage overlays hiding themselves or flickering when you get wounded. /:cl: --- code/__DEFINES/traits/declarations.dm | 2 ++ code/_globalvars/traits/_traits.dm | 1 + code/datums/quirks/negative_quirks/numb.dm | 4 ++-- code/modules/deathmatch/deathmatch_modifier.dm | 2 +- code/modules/mob/living/carbon/carbon.dm | 2 +- 5 files changed, 7 insertions(+), 4 deletions(-) diff --git a/code/__DEFINES/traits/declarations.dm b/code/__DEFINES/traits/declarations.dm index a4cd1f55e997b..21c239c59b914 100644 --- a/code/__DEFINES/traits/declarations.dm +++ b/code/__DEFINES/traits/declarations.dm @@ -509,6 +509,8 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai #define TRAIT_USER_SCOPED "user_scoped" /// Mob is unable to feel pain #define TRAIT_ANALGESIA "analgesia" +/// Mob does not get a damage overlay from brute/burn +#define TRAIT_NO_DAMAGE_OVERLAY "no_damage_overlay" /// Mob has a scar on their left/right eye #define TRAIT_RIGHT_EYE_SCAR "right_eye_scar" #define TRAIT_LEFT_EYE_SCAR "left_eye_scar" diff --git a/code/_globalvars/traits/_traits.dm b/code/_globalvars/traits/_traits.dm index 15cd11e6ae432..f5d79447f56a2 100644 --- a/code/_globalvars/traits/_traits.dm +++ b/code/_globalvars/traits/_traits.dm @@ -381,6 +381,7 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_NOSOFTCRIT" = TRAIT_NOSOFTCRIT, "TRAIT_NO_AUGMENTS" = TRAIT_NO_AUGMENTS, "TRAIT_NO_BLOOD_OVERLAY" = TRAIT_NO_BLOOD_OVERLAY, + "TRAIT_NO_DAMAGE_OVERLAY" = TRAIT_NO_DAMAGE_OVERLAY, "TRAIT_NO_DEBRAIN_OVERLAY" = TRAIT_NO_DEBRAIN_OVERLAY, "TRAIT_NO_DNA_COPY" = TRAIT_NO_DNA_COPY, "TRAIT_NO_DNA_SCRAMBLE" = TRAIT_NO_DNA_SCRAMBLE, diff --git a/code/datums/quirks/negative_quirks/numb.dm b/code/datums/quirks/negative_quirks/numb.dm index ee8b86d342679..cb982cf0641b2 100644 --- a/code/datums/quirks/negative_quirks/numb.dm +++ b/code/datums/quirks/negative_quirks/numb.dm @@ -10,8 +10,8 @@ /datum/quirk/numb/add(client/client_source) quirk_holder.apply_status_effect(/datum/status_effect/grouped/screwy_hud/fake_healthy, type) - quirk_holder.add_traits(list(TRAIT_ANALGESIA, QUIRK_TRAIT)) + quirk_holder.add_traits(list(TRAIT_ANALGESIA, TRAIT_NO_DAMAGE_OVERLAY), QUIRK_TRAIT) /datum/quirk/numb/remove(client/client_source) quirk_holder.remove_status_effect(/datum/status_effect/grouped/screwy_hud/fake_healthy, type) - quirk_holder.remove_traits(list(TRAIT_ANALGESIA, QUIRK_TRAIT)) + quirk_holder.remove_traits(list(TRAIT_ANALGESIA, TRAIT_NO_DAMAGE_OVERLAY), QUIRK_TRAIT) diff --git a/code/modules/deathmatch/deathmatch_modifier.dm b/code/modules/deathmatch/deathmatch_modifier.dm index 9671f19c92a33..edddbe7e267bc 100644 --- a/code/modules/deathmatch/deathmatch_modifier.dm +++ b/code/modules/deathmatch/deathmatch_modifier.dm @@ -82,7 +82,7 @@ description = "Unaffected by critical condition and pain" /datum/deathmatch_modifier/tenacity/apply(mob/living/carbon/player, datum/deathmatch_lobby/lobby) - player.add_traits(list(TRAIT_NOSOFTCRIT, TRAIT_NOHARDCRIT, TRAIT_ANALGESIA), DEATHMATCH_TRAIT) + player.add_traits(list(TRAIT_NOSOFTCRIT, TRAIT_NOHARDCRIT, TRAIT_ANALGESIA, TRAIT_NO_DAMAGE_OVERLAY), DEATHMATCH_TRAIT) /datum/deathmatch_modifier/no_wounds name = "No Wounds" diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index 79b3f8aa3cc94..408a3c30925fd 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -745,7 +745,7 @@ //Fire and Brute damage overlay (BSSR) var/hurtdamage = getBruteLoss() + getFireLoss() + damageoverlaytemp - if(hurtdamage && !HAS_TRAIT(src, TRAIT_ANALGESIA)) + if(hurtdamage && !HAS_TRAIT(src, TRAIT_NO_DAMAGE_OVERLAY)) var/severity = 0 switch(hurtdamage) if(5 to 15) From 6fa9dc50b46dd17c13e6ebbde36a56cc877966c6 Mon Sep 17 00:00:00 2001 From: "tgstation-ci[bot]" <179393467+tgstation-ci[bot]@users.noreply.github.com> Date: Fri, 29 Nov 2024 14:33:17 +0000 Subject: [PATCH 038/149] Automatic changelog for PR #88281 [ci skip] --- html/changelogs/AutoChangeLog-pr-88281.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-88281.yml diff --git a/html/changelogs/AutoChangeLog-pr-88281.yml b/html/changelogs/AutoChangeLog-pr-88281.yml new file mode 100644 index 0000000000000..4f86cfe64f0ac --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-88281.yml @@ -0,0 +1,4 @@ +author: "SmArtKar" +delete-after: True +changes: + - bugfix: "Fixed damage overlays hiding themselves or flickering when you get wounded." \ No newline at end of file From 3c40876f15241c0a786fed757e592c46b153cefa Mon Sep 17 00:00:00 2001 From: MrMelbert <51863163+MrMelbert@users.noreply.github.com> Date: Fri, 29 Nov 2024 08:41:37 -0600 Subject: [PATCH 039/149] Fix itchy skillchip status effect "Curse of Mundanity", adds unit test for effects set to "Curse of Mundanity" (and missing IDs) (#88240) ## About The Pull Request Fixes a lot of status effects having the default alert, adds a unit test to check that status effects don't forget to change it I chose a test rather than just making the default "no alert" because I think people making status effects should think about whether it should have an alert Also I added a test for effects which did not set an ID because that's kind of important, I applied the same mindset here to account for abstract types but admittedly less sold on this one. ## Changelog :cl: Melbert fix: You should be afflicted by the "Curse of Mundanity" far, far less /:cl: --- code/__DEFINES/status_effects.dm | 5 ++ code/datums/quirks/positive_quirks/chipped.dm | 1 + code/datums/status_effects/buffs.dm | 3 + code/datums/status_effects/debuffs/debuffs.dm | 2 + code/datums/status_effects/debuffs/drunk.dm | 1 + .../status_effects/debuffs/fire_stacks.dm | 1 + .../status_effects/debuffs/screwy_hud.dm | 1 + code/datums/status_effects/debuffs/spacer.dm | 1 + .../status_effects/debuffs/speech_debuffs.dm | 2 +- .../datums/status_effects/debuffs/stamcrit.dm | 1 + code/datums/status_effects/grouped_effect.dm | 2 + code/datums/status_effects/limited_effect.dm | 1 + code/datums/status_effects/neutral.dm | 2 + code/datums/status_effects/stacking_effect.dm | 2 +- .../antagonists/heretic/magic/void_conduit.dm | 5 +- .../voidwalker/voidwalker_status_effects.dm | 8 +-- .../lavaland/basilisk/basilisk_overheat.dm | 1 + .../space_fauna/revenant/revenant_effects.dm | 2 + code/modules/unit_tests/_unit_tests.dm | 2 +- .../modules/unit_tests/status_effect_ticks.dm | 23 ------- .../unit_tests/status_effect_validity.dm | 61 +++++++++++++++++++ 21 files changed, 95 insertions(+), 32 deletions(-) delete mode 100644 code/modules/unit_tests/status_effect_ticks.dm 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 756d78c172353..3642973721049 100644 --- a/code/__DEFINES/status_effects.dm +++ b/code/__DEFINES/status_effects.dm @@ -12,6 +12,11 @@ /// 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/quirks/positive_quirks/chipped.dm b/code/datums/quirks/positive_quirks/chipped.dm index 474e8a4adcdc4..26b4883f9b339 100644 --- a/code/datums/quirks/positive_quirks/chipped.dm +++ b/code/datums/quirks/positive_quirks/chipped.dm @@ -68,6 +68,7 @@ id = "itchy skillchip" tick_interval_lowerbound = 5 SECONDS tick_interval_upperbound = 10 MINUTES + alert_type = null ///lower damage we apply to our itchy owner var/minimum_damage = 1 ///upper damage we apply to our itchy owner diff --git a/code/datums/status_effects/buffs.dm b/code/datums/status_effects/buffs.dm index a24e8d4ccdac9..e4471f2f4dbd8 100644 --- a/code/datums/status_effects/buffs.dm +++ b/code/datums/status_effects/buffs.dm @@ -406,6 +406,7 @@ /datum/status_effect/mayhem id = "Mayhem" duration = 2 MINUTES + alert_type = null /// The chainsaw spawned by the status effect var/obj/item/chainsaw/doomslayer/chainsaw @@ -450,6 +451,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)) @@ -595,6 +597,7 @@ id = "radiation_immunity" duration = 1 MINUTES show_duration = TRUE + alert_type = null /datum/status_effect/radiation_immunity/on_apply() ADD_TRAIT(owner, TRAIT_RADIMMUNE, type) diff --git a/code/datums/status_effects/debuffs/debuffs.dm b/code/datums/status_effects/debuffs/debuffs.dm index 02fe573ef36e9..b9b56161e84a7 100644 --- a/code/datums/status_effects/debuffs/debuffs.dm +++ b/code/datums/status_effects/debuffs/debuffs.dm @@ -8,6 +8,7 @@ //Largely negative status effects go here, even if they have small beneficial effects //STUN EFFECTS /datum/status_effect/incapacitating + id = STATUS_EFFECT_ID_ABSTRACT tick_interval = STATUS_EFFECT_NO_TICK status_type = STATUS_EFFECT_REPLACE alert_type = null @@ -967,6 +968,7 @@ duration = 10 SECONDS status_type = STATUS_EFFECT_REPLACE tick_interval = 0.2 SECONDS + alert_type = null /datum/status_effect/teleport_madness/tick(seconds_between_ticks) dump_in_space(owner) diff --git a/code/datums/status_effects/debuffs/drunk.dm b/code/datums/status_effects/debuffs/drunk.dm index 706ab36fcff2c..37ab11f130c4c 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 648f09f31e95f..4b071d87e21e6 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 = 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/screwy_hud.dm b/code/datums/status_effects/debuffs/screwy_hud.dm index 2e8fc566cf460..10c20112160c7 100644 --- a/code/datums/status_effects/debuffs/screwy_hud.dm +++ b/code/datums/status_effects/debuffs/screwy_hud.dm @@ -8,6 +8,7 @@ * accidentally removing another source's hud. */ /datum/status_effect/grouped/screwy_hud + id = STATUS_EFFECT_ID_ABSTRACT alert_type = null /// The priority of this screwyhud over other screwyhuds. var/priority = -1 diff --git a/code/datums/status_effects/debuffs/spacer.dm b/code/datums/status_effects/debuffs/spacer.dm index 1add806c02f0e..ed14fd285968e 100644 --- a/code/datums/status_effects/debuffs/spacer.dm +++ b/code/datums/status_effects/debuffs/spacer.dm @@ -3,6 +3,7 @@ /datum/status_effect/spacer id = "spacer_gravity_effects" status_type = STATUS_EFFECT_REPLACE + alert_type = null /// Essentially, tracks whether this is a planetary map. /// It'd be pretty miserable if you're playing a planetary map and getting the worse of all effects, so we handwave it a bit. VAR_FINAL/nerfed_effects_because_planetary = FALSE diff --git a/code/datums/status_effects/debuffs/speech_debuffs.dm b/code/datums/status_effects/debuffs/speech_debuffs.dm index a557f7ddd4dd4..1ba85ebe72f72 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 tick_interval = STATUS_EFFECT_NO_TICK diff --git a/code/datums/status_effects/debuffs/stamcrit.dm b/code/datums/status_effects/debuffs/stamcrit.dm index 74c3fde12f55f..0d4a844a61e0d 100644 --- a/code/datums/status_effects/debuffs/stamcrit.dm +++ b/code/datums/status_effects/debuffs/stamcrit.dm @@ -1,4 +1,5 @@ /datum/status_effect/incapacitating/stamcrit + id = "stamcrit" status_type = STATUS_EFFECT_UNIQUE // Lasts until we go back to 0 stamina, which is handled by the mob duration = STATUS_EFFECT_PERMANENT diff --git a/code/datums/status_effects/grouped_effect.dm b/code/datums/status_effects/grouped_effect.dm index 601945b83aae4..27b37af1e3567 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 b577248d35eee..047a7a5ae07c8 100644 --- a/code/datums/status_effects/limited_effect.dm +++ b/code/datums/status_effects/limited_effect.dm @@ -3,6 +3,7 @@ id = "limited_buff" 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 43c4ad7a3f09a..23db827daadec 100644 --- a/code/datums/status_effects/neutral.dm +++ b/code/datums/status_effects/neutral.dm @@ -110,6 +110,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) @@ -581,6 +582,7 @@ id = "tinea_luxor_light" processing_speed = STATUS_EFFECT_NORMAL_PROCESS remove_on_fullheal = TRUE + alert_type = null var/obj/effect/dummy/lighting_obj/moblight/mob_light_obj /datum/status_effect/tinlux_light/on_creation(mob/living/new_owner, duration) diff --git a/code/datums/status_effects/stacking_effect.dm b/code/datums/status_effects/stacking_effect.dm index 3ed7846f6ff23..acdefd8290c88 100644 --- a/code/datums/status_effects/stacking_effect.dm +++ b/code/datums/status_effects/stacking_effect.dm @@ -1,7 +1,7 @@ /// Status effects that can stack. /datum/status_effect/stacking - id = "stacking_base" + 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 diff --git a/code/modules/antagonists/heretic/magic/void_conduit.dm b/code/modules/antagonists/heretic/magic/void_conduit.dm index 8d2b193de29e6..16faf3b1a3844 100644 --- a/code/modules/antagonists/heretic/magic/void_conduit.dm +++ b/code/modules/antagonists/heretic/magic/void_conduit.dm @@ -116,13 +116,14 @@ falloff_exponent = 20 /datum/status_effect/void_conduit + id = "void_conduit" duration = 15 SECONDS status_type = STATUS_EFFECT_REPLACE alert_type = null /datum/status_effect/void_conduit/on_apply() - ADD_TRAIT(owner, TRAIT_RESISTLOWPRESSURE, "void_conduit") + ADD_TRAIT(owner, TRAIT_RESISTLOWPRESSURE, type) return TRUE /datum/status_effect/void_conduit/on_remove() - REMOVE_TRAIT(owner, TRAIT_RESISTLOWPRESSURE, "void_conduit") + REMOVE_TRAIT(owner, TRAIT_RESISTLOWPRESSURE, type) diff --git a/code/modules/antagonists/voidwalker/voidwalker_status_effects.dm b/code/modules/antagonists/voidwalker/voidwalker_status_effects.dm index 6b7f733265cae..6fbe461543a90 100644 --- a/code/modules/antagonists/voidwalker/voidwalker_status_effects.dm +++ b/code/modules/antagonists/voidwalker/voidwalker_status_effects.dm @@ -32,15 +32,15 @@ icon_state = "paralysis" /datum/status_effect/void_eatered + id = "void_eatered" duration = 10 SECONDS remove_on_fullheal = TRUE + alert_type = null /datum/status_effect/void_eatered/on_apply() . = ..() - - ADD_TRAIT(owner, TRAIT_NODEATH, REF(src)) + ADD_TRAIT(owner, TRAIT_NODEATH, type) /datum/status_effect/void_eatered/on_remove() . = ..() - - REMOVE_TRAIT(owner, TRAIT_NODEATH, REF(src)) + REMOVE_TRAIT(owner, TRAIT_NODEATH, type) 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 c0b49fbdc6199..71e938c5164e6 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 b7bc6e34dcf7e..6b5f63bf00f0e 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/unit_tests/_unit_tests.dm b/code/modules/unit_tests/_unit_tests.dm index e4f5300006b09..4d16d24e9e93a 100644 --- a/code/modules/unit_tests/_unit_tests.dm +++ b/code/modules/unit_tests/_unit_tests.dm @@ -288,7 +288,7 @@ #include "spritesheets.dm" #include "stack_singular_name.dm" #include "station_trait_tests.dm" -#include "status_effect_ticks.dm" +#include "status_effect_validity.dm" #include "stomach.dm" #include "storage.dm" #include "strange_reagent.dm" diff --git a/code/modules/unit_tests/status_effect_ticks.dm b/code/modules/unit_tests/status_effect_ticks.dm deleted file mode 100644 index d60ba187abc42..0000000000000 --- a/code/modules/unit_tests/status_effect_ticks.dm +++ /dev/null @@ -1,23 +0,0 @@ -/// 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)) - 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) - 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)]") 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 0000000000000..76a367233fd11 --- /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) + 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.") From 55fdc7994e2eff5bd95a0e0c4534818faab43461 Mon Sep 17 00:00:00 2001 From: "tgstation-ci[bot]" <179393467+tgstation-ci[bot]@users.noreply.github.com> Date: Fri, 29 Nov 2024 14:42:16 +0000 Subject: [PATCH 040/149] Automatic changelog for PR #88240 [ci skip] --- html/changelogs/AutoChangeLog-pr-88240.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-88240.yml diff --git a/html/changelogs/AutoChangeLog-pr-88240.yml b/html/changelogs/AutoChangeLog-pr-88240.yml new file mode 100644 index 0000000000000..e634bc152bda3 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-88240.yml @@ -0,0 +1,4 @@ +author: "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 da9d492af21976332a13d149a9ed4c501d98018c Mon Sep 17 00:00:00 2001 From: SmArtKar <44720187+SmArtKar@users.noreply.github.com> Date: Fri, 29 Nov 2024 17:43:59 +0300 Subject: [PATCH 041/149] [NO GBP] Fixes projectile parrying (#88269) ## About The Pull Request I have... questions, to previous self. Yeah. ## Changelog :cl: fix: Fixed projectile parrying /:cl: --- code/__DEFINES/dcs/signals/signals_object.dm | 1 + code/datums/components/parry.dm | 9 +++++---- code/modules/projectiles/projectile.dm | 10 ++++++++-- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/code/__DEFINES/dcs/signals/signals_object.dm b/code/__DEFINES/dcs/signals/signals_object.dm index 69ccaa5fa641b..7e7a5f17837ac 100644 --- a/code/__DEFINES/dcs/signals/signals_object.dm +++ b/code/__DEFINES/dcs/signals/signals_object.dm @@ -393,6 +393,7 @@ ///sent to targets during the process_hit proc of projectiles #define COMSIG_PROJECTILE_PREHIT "com_proj_prehit" #define PROJECTILE_INTERRUPT_HIT (1<<0) + #define PROJECTILE_INTERRUPT_HIT_PHASE (1<<1) ///from /obj/projectile/process_movement(): () #define COMSIG_PROJECTILE_MOVE_PROCESS_STEP "projectile_move_process_step" ///sent to self during the process_hit proc of projectiles diff --git a/code/datums/components/parry.dm b/code/datums/components/parry.dm index e24bb4d2480df..a478fcbd27802 100644 --- a/code/datums/components/parry.dm +++ b/code/datums/components/parry.dm @@ -91,15 +91,16 @@ if (!istype(user) || !parriers[user] || parried) return + parriers -= user - attempt_parry(source, user) + return attempt_parry(source, user) /datum/component/parriable_projectile/proc/attempt_parry(obj/projectile/source, mob/user) if (QDELETED(source) || source.deletion_queued) - return + return NONE if (SEND_SIGNAL(user, COMSIG_LIVING_PROJECTILE_PARRIED, source) & INTERCEPT_PARRY_EFFECTS) - return + return NONE parried = TRUE if (source.firer != user) @@ -120,4 +121,4 @@ user.playsound_local(source.loc, 'sound/effects/parry.ogg', 50, TRUE) user.overlay_fullscreen("projectile_parry", /atom/movable/screen/fullscreen/crit/projectile_parry, 2) addtimer(CALLBACK(user, TYPE_PROC_REF(/mob, clear_fullscreen), "projectile_parry"), 0.25 SECONDS) - return PROJECTILE_INTERRUPT_HIT + return PROJECTILE_INTERRUPT_HIT_PHASE diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm index c4c5d42164ce0..43ef0eee70fe5 100644 --- a/code/modules/projectiles/projectile.dm +++ b/code/modules/projectiles/projectile.dm @@ -523,10 +523,16 @@ target = select_target(target_turf, target) continue - if (SEND_SIGNAL(target, COMSIG_PROJECTILE_PREHIT, src) & PROJECTILE_INTERRUPT_HIT) + var/target_signal = SEND_SIGNAL(target, COMSIG_PROJECTILE_PREHIT, src) + if (target_signal & PROJECTILE_INTERRUPT_HIT_PHASE) + return PROJECTILE_IMPACT_PASSED + if (target_signal & PROJECTILE_INTERRUPT_HIT) return PROJECTILE_IMPACT_INTERRUPTED - if (SEND_SIGNAL(src, COMSIG_PROJECTILE_SELF_PREHIT, target) & PROJECTILE_INTERRUPT_HIT) + var/self_signal = SEND_SIGNAL(src, COMSIG_PROJECTILE_SELF_PREHIT, target) + if (self_signal & PROJECTILE_INTERRUPT_HIT_PHASE) + return PROJECTILE_IMPACT_PASSED + if (self_signal & PROJECTILE_INTERRUPT_HIT) return PROJECTILE_IMPACT_INTERRUPTED if(mode == PROJECTILE_PIERCE_HIT) From b9a17e9a0ddbe69328361aff8ce238cd4b0a4e73 Mon Sep 17 00:00:00 2001 From: "tgstation-ci[bot]" <179393467+tgstation-ci[bot]@users.noreply.github.com> Date: Fri, 29 Nov 2024 14:44:37 +0000 Subject: [PATCH 042/149] Automatic changelog for PR #88269 [ci skip] --- html/changelogs/AutoChangeLog-pr-88269.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-88269.yml diff --git a/html/changelogs/AutoChangeLog-pr-88269.yml b/html/changelogs/AutoChangeLog-pr-88269.yml new file mode 100644 index 0000000000000..a8cc4960e11be --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-88269.yml @@ -0,0 +1,4 @@ +author: "SmArtKar" +delete-after: True +changes: + - bugfix: "Fixed projectile parrying" \ No newline at end of file From f60f5b8334543e929c2ad56f4c6ab0b778b52555 Mon Sep 17 00:00:00 2001 From: MrMelbert <51863163+MrMelbert@users.noreply.github.com> Date: Fri, 29 Nov 2024 10:38:35 -0600 Subject: [PATCH 043/149] Fix admin local sound (#88214) --- code/modules/admin/verbs/playsound.dm | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/code/modules/admin/verbs/playsound.dm b/code/modules/admin/verbs/playsound.dm index d66e7f777c309..5e68dcedbfaea 100644 --- a/code/modules/admin/verbs/playsound.dm +++ b/code/modules/admin/verbs/playsound.dm @@ -42,9 +42,7 @@ ADMIN_VERB(play_local_sound, R_SOUND, "Play Local Sound", "Plays a sound only yo log_admin("[key_name(user)] played a local sound [sound]") message_admins("[key_name_admin(user)] played a local sound [sound]") var/volume = tgui_input_number(user, "What volume would you like the sound to play at?", max_value = 100) - var/sound/admin_sound = sound(sound) - admin_sound.volume = volume || 50 - playsound(get_turf(user.mob), sound, FALSE, FALSE) + playsound(get_turf(user.mob), sound, volume || 50, FALSE) BLACKBOX_LOG_ADMIN_VERB("Play Local Sound") ADMIN_VERB(play_direct_mob_sound, R_SOUND, "Play Direct Mob Sound", "Play a sound directly to a mob.", ADMIN_CATEGORY_FUN, sound as sound, mob/target in world) From 0b45aec88ffa1a3cb1623292b2eca830be50dd46 Mon Sep 17 00:00:00 2001 From: "tgstation-ci[bot]" <179393467+tgstation-ci[bot]@users.noreply.github.com> Date: Fri, 29 Nov 2024 16:38:55 +0000 Subject: [PATCH 044/149] Automatic changelog for PR #88214 [ci skip] --- html/changelogs/AutoChangeLog-pr-88214.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-88214.yml diff --git a/html/changelogs/AutoChangeLog-pr-88214.yml b/html/changelogs/AutoChangeLog-pr-88214.yml new file mode 100644 index 0000000000000..4bb15d4c80e4c --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-88214.yml @@ -0,0 +1,4 @@ +author: "Melbert" +delete-after: True +changes: + - bugfix: "Fixed play local sound for admins" \ No newline at end of file From c9099d0766207c778fc9379d721b99df0039ac6b Mon Sep 17 00:00:00 2001 From: grungussuss <96586172+Sadboysuss@users.noreply.github.com> Date: Fri, 29 Nov 2024 19:40:14 +0300 Subject: [PATCH 045/149] [no gbp] attribution mishaps (#88246) --- sound/music/antag/attribution.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/music/antag/attribution.txt b/sound/music/antag/attribution.txt index 6ae7cecc51970..d7b444fc909c9 100644 --- a/sound/music/antag/attribution.txt +++ b/sound/music/antag/attribution.txt @@ -1,5 +1,5 @@ sound/instrumental/antag/abductee.ogg is from "Warp SFX" https://freesound.org/people/Breviceps/sounds/453391 (CC0) -sound/instrumental/antag/brainwash.ogg is from "nog.wav" https://freesound.org/people/_NOMINAL_/sounds/124602 (CC-BY 3.0) +sound/instrumental/antag/brainwash.ogg is made by FeiH from https://github.com/OracleStation/OracleStation/pull/1122/commits/b28fbbad715b96db029a8e8df38b1357a58daec1 sound/instrumental/antag/hypnosis.ogg is from "Flashback.wav" https://freesound.org/people/Sclolex/sounds/342103 (CC0) { From 6b543476daeb35ade7e3ffe5708ac17eeee98755 Mon Sep 17 00:00:00 2001 From: Ghom <42542238+Ghommie@users.noreply.github.com> Date: Fri, 29 Nov 2024 18:11:59 +0100 Subject: [PATCH 046/149] Aquarium kits can now be printed + other tweaks. (#88068) ## About The Pull Request Aquarium kits can now be printed from service, cargo, science protolathes and the autolathe too, from half a sheet of metal. You still need the other materials to set it up but it should be fairy simple if you can access a proto/autolathe. The 'Growth/Reproduction' setting for aquariums has been renamed to "Safe Mode", which, on top of disabling features such as growth, reproduction, evolution, power generation etc etc, will also disable the water, temperature and food requirements for keeping the fish alive. Useful if you want a purely ornamental aquarium or you have to skidaddle somewhere else for a while. The lawyer, as well as prefilled aquariums start with 'Safe Mode' enabled. The 'Aggressive' fish trait has been replaced with 'Territorial', which is exactly the same but the fish won't lash out unless the aquarium is populated by five fishes or more. No more angelfish viciously attacking the guppy and goldfish in prefilled aquariums. Tweaked a couple values around hunger and fish health loss when starving or in a bad environment to cause slightly less damage. Lastly, added screentips to the aquarium component, which is something I've forgot to do in the PR that brought it. ## Why It's Good For The Game Aquariums may be a complex feature, but as far as I can tell, I had been neglecting the possibility of aquariums as simple room decoration for a while (outside of the beauty-related mechanics), and the constant maintenance (and perhaps a bit of knowhow) they require makes them awful at that. Also, the "growth/reproduction" setting really didn't have a reason to be before, since it didn't offer any tangible benifit to turn it off, so I had to revamped it. Also it's been proven by now that keeping aquariums as cargo-orderable stuff is just bad. As for the fish trait change, it just sucks to see the angelfish shank the goldfish with no way to solve it other than removing the hyper-aggressive killer fish from san diego fella. ## Changelog :cl: balance: Aquarium kits can now be printed from cargo, service, science protolathes as well as the autolathe. They no longer have to be ordered from cargo. balance: Revamped the "Growth/Reproduction" setting for aquarium to "Safe Mode", which also disables the food, temperature and water requiremenets of aquariums, making it useful for purely decorative aquariums. balance: Replaced the "Aggressive" fish trait with "Territorial". No more angelfish shanking the goldfish and guppy in prefilled aquariums with less than 5 fishes. qol: Added screentips to aquariums. /:cl: --- code/__DEFINES/fish.dm | 2 +- code/datums/components/aquarium.dm | 39 ++++++++++-- code/datums/elements/fish_safe_storage.dm | 8 +-- code/modules/cargo/packs/service.dm | 15 ----- code/modules/fishing/aquarium/aquarium.dm | 4 ++ code/modules/fishing/fish/_fish.dm | 61 +++++++++++-------- code/modules/fishing/fish/fish_evolution.dm | 8 +-- code/modules/fishing/fish/fish_traits.dm | 24 +++++--- code/modules/fishing/fish/types/air_space.dm | 2 +- code/modules/fishing/fish/types/anadromous.dm | 2 +- code/modules/fishing/fish/types/freshwater.dm | 2 +- code/modules/fishing/fish/types/ruins.dm | 2 +- code/modules/fishing/fish/types/syndicate.dm | 4 +- code/modules/fishing/fish/types/tiziran.dm | 2 +- .../spaceruin_code/hauntedtradingpost.dm | 3 +- .../designs/autolathe/service_designs.dm | 12 ++++ .../research/techweb/nodes/service_nodes.dm | 1 + strings/fishing_tips.txt | 1 + tgui/packages/tgui/interfaces/Aquarium.tsx | 13 ++-- 19 files changed, 128 insertions(+), 77 deletions(-) diff --git a/code/__DEFINES/fish.dm b/code/__DEFINES/fish.dm index f9f390f95a189..efa29f98dc2a0 100644 --- a/code/__DEFINES/fish.dm +++ b/code/__DEFINES/fish.dm @@ -166,7 +166,7 @@ ///The breeding timeout for newly instantiated fish is multiplied by this. #define NEW_FISH_BREEDING_TIMEOUT_MULT 2 ///The last feeding timestamp of newly instantiated fish is multiplied by this: ergo, they spawn 50% hungry. -#define NEW_FISH_LAST_FEEDING_MULT 0.5 +#define NEW_FISH_LAST_FEEDING_MULT 0.33 //IF YOU ADD ANY NEW FLAG, ADD IT TO THE RESPECTIVE BITFIELD in _globalvars/bitfields.dm TOO! diff --git a/code/datums/components/aquarium.dm b/code/datums/components/aquarium.dm index 00a476959567e..cf86c6b56b470 100644 --- a/code/datums/components/aquarium.dm +++ b/code/datums/components/aquarium.dm @@ -120,6 +120,10 @@ movable.AddElement(/datum/element/relay_attackers) movable.AddComponent(/datum/component/fishing_spot, /datum/fish_source/aquarium) + + movable.flags_1 |= HAS_CONTEXTUAL_SCREENTIPS_1 + RegisterSignal(movable, COMSIG_ATOM_REQUESTING_CONTEXT_FROM_ITEM, PROC_REF(on_requesting_context_from_item)) + for(var/atom/movable/content as anything in movable.contents) if(content.flags_1 & INITIALIZED_1) on_entered(movable, content) @@ -144,6 +148,7 @@ COMSIG_ATOM_ATTACK_ROBOT_SECONDARY, COMSIG_ATOM_ATTACK_HAND_SECONDARY, COMSIG_ATOM_UI_INTERACT, + COMSIG_ATOM_REQUESTING_CONTEXT_FROM_ITEM, )) if(movable.reagents) UnregisterSignal(movable, COMSIG_REAGENTS_NEW_REAGENT) @@ -216,7 +221,7 @@ source.balloon_alert(user, "fed the fish") return ITEM_INTERACT_SUCCESS - if(!HAS_TRAIT(item, TRAIT_AQUARIUM_CONTENT)) + if(!HAS_TRAIT(item, TRAIT_AQUARIUM_CONTENT) || (!isitem(parent) && user.combat_mode)) return //proceed with normal interactions var/broken = source.get_integrity_percentage() <= source.integrity_failure @@ -240,6 +245,10 @@ ///Feed the fish at defined intervals until the feed storage is empty. /datum/component/aquarium/process(seconds_per_tick) + //safe mode, no need to feed the fishes + if(HAS_TRAIT_FROM(parent, TRAIT_STOP_FISH_REPRODUCTION_AND_GROWTH, AQUARIUM_TRAIT)) + last_feeding += seconds_per_tick SECONDS + return var/atom/movable/movable = parent if(!movable.reagents?.total_volume) if(movable.reagents) @@ -255,6 +264,7 @@ /datum/component/aquarium/proc/on_plunger_act(atom/movable/source, obj/item/plunger/plunger, mob/living/user, reinforced) SIGNAL_HANDLER if(!HAS_TRAIT(source, TRAIT_AQUARIUM_PANEL_OPEN)) + source.balloon_alert(user, "open panel first!") return INVOKE_ASYNC(src, PROC_REF(do_plunging), source, user) return COMPONENT_NO_AFTERATTACK @@ -463,7 +473,7 @@ var/atom/movable/aquarium = parent .["fluidType"] = fluid_type .["temperature"] = fluid_temp - .["allowBreeding"] = HAS_TRAIT_FROM(aquarium, TRAIT_STOP_FISH_REPRODUCTION_AND_GROWTH, AQUARIUM_TRAIT) + .["safe_mode"] = !HAS_TRAIT_FROM(aquarium, TRAIT_STOP_FISH_REPRODUCTION_AND_GROWTH, AQUARIUM_TRAIT) .["fishData"] = list() .["feedingInterval"] = feeding_interval / (1 MINUTES) .["propData"] = list() @@ -512,8 +522,8 @@ if(params["fluid"] != fluid_type && (params["fluid"] in fluid_types)) set_fluid_type(params["fluid"]) . = TRUE - if("allow_breeding") - if(HAS_TRAIT(movable, TRAIT_STOP_FISH_REPRODUCTION_AND_GROWTH)) + if("safe_mode") + if(HAS_TRAIT_FROM(movable, TRAIT_STOP_FISH_REPRODUCTION_AND_GROWTH, AQUARIUM_TRAIT)) REMOVE_TRAIT(movable, TRAIT_STOP_FISH_REPRODUCTION_AND_GROWTH, AQUARIUM_TRAIT) else ADD_TRAIT(movable, TRAIT_STOP_FISH_REPRODUCTION_AND_GROWTH, AQUARIUM_TRAIT) @@ -563,5 +573,26 @@ else if(dead_fish > 0) user.add_mood_event("aquarium", morb ? /datum/mood_event/morbid_aquarium_good : /datum/mood_event/aquarium_negative) +/datum/component/aquarium/proc/on_requesting_context_from_item(atom/source, list/context, obj/item/held_item, mob/user) + SIGNAL_HANDLER + var/open_panel = HAS_TRAIT(source, TRAIT_AQUARIUM_PANEL_OPEN) + if(!held_item) + var/isitem = isitem(source) + if(!isitem || open_panel) + context[SCREENTIP_CONTEXT_LMB] = open_panel ? "Adjust settings" : "Admire" + if(isitem) + context[SCREENTIP_CONTEXT_RMB] = "Admire" + context[SCREENTIP_CONTEXT_ALT_LMB] = "[open_panel ? "Open" : "Close"] settings panel" + return CONTEXTUAL_SCREENTIP_SET + if(istype(held_item, /obj/item/plunger)) + context[SCREENTIP_CONTEXT_LMB] = "Empty feed storage" + return CONTEXTUAL_SCREENTIP_SET + if(istype(held_item, /obj/item/reagent_containers/cup/fish_feed) && (!source.reagents || !open_panel)) + context[SCREENTIP_CONTEXT_LMB] = "Feed fishes" + return CONTEXTUAL_SCREENTIP_SET + if(HAS_TRAIT(held_item, TRAIT_AQUARIUM_CONTENT)) + context[SCREENTIP_CONTEXT_LMB] = "Insert in aquarium" + return CONTEXTUAL_SCREENTIP_SET + #undef MIN_AQUARIUM_BEAUTY #undef MAX_AQUARIUM_BEAUTY diff --git a/code/datums/elements/fish_safe_storage.dm b/code/datums/elements/fish_safe_storage.dm index bb7864ced0e6a..ec5c59848646d 100644 --- a/code/datums/elements/fish_safe_storage.dm +++ b/code/datums/elements/fish_safe_storage.dm @@ -22,7 +22,7 @@ /datum/element/fish_safe_storage/Detach(atom/source) for(var/obj/item/fish/fish in source) tracked_fish -= fish - fish.exit_stasis() + REMOVE_TRAIT(fish, TRAIT_FISH_STASIS, REF(src)) UnregisterSignal(source, list(COMSIG_ATOM_ENTERED, COMSIG_ATOM_EXITED, COMSIG_ATOM_AFTER_SUCCESSFUL_INITIALIZED_ON)) return ..() @@ -30,19 +30,19 @@ SIGNAL_HANDLER if(isfish(arrived)) tracked_fish |= arrived - arrived.enter_stasis() + ADD_TRAIT(arrived, TRAIT_FISH_STASIS, REF(src)) /datum/element/fish_safe_storage/proc/on_init_on(datum/source, obj/item/fish/created) SIGNAL_HANDLER if(isfish(created) && !QDELETED(created)) tracked_fish |= created - created.enter_stasis() + ADD_TRAIT(created, TRAIT_FISH_STASIS, REF(src)) /datum/element/fish_safe_storage/proc/on_exit(datum/source, obj/item/fish/gone) SIGNAL_HANDLER if(isfish(gone)) tracked_fish -= gone - gone.exit_stasis() + REMOVE_TRAIT(gone, TRAIT_FISH_STASIS, REF(src)) /datum/element/fish_safe_storage/process(seconds_per_tick) for(var/obj/item/fish/fish as anything in tracked_fish) diff --git a/code/modules/cargo/packs/service.dm b/code/modules/cargo/packs/service.dm index 0e704a62df49d..89ce9a5c3716c 100644 --- a/code/modules/cargo/packs/service.dm +++ b/code/modules/cargo/packs/service.dm @@ -285,21 +285,6 @@ crate_type = /obj/structure/closet/crate/large discountable = SUPPLY_PACK_UNCOMMON_DISCOUNTABLE -/datum/supply_pack/service/aquarium_kit - name = "Aquarium Kit" - desc = "Everything you need to start your own aquarium. Contains aquarium construction kit, \ - fish catalog, fish food and three freshwater fish from our collection." - cost = CARGO_CRATE_VALUE * 5 - contains = list(/obj/item/book/manual/fish_catalog, - /obj/item/storage/fish_case/random/freshwater = 3, - /obj/item/reagent_containers/cup/fish_feed, - /obj/item/storage/box/aquarium_props, - /obj/item/aquarium_kit, - ) - crate_name = "aquarium kit crate" - crate_type = /obj/structure/closet/crate/wooden - discountable = SUPPLY_PACK_UNCOMMON_DISCOUNTABLE - /// Spare bar sign wallmount /datum/supply_pack/service/bar_sign name = "Bar Sign Replacement Kit" diff --git a/code/modules/fishing/aquarium/aquarium.dm b/code/modules/fishing/aquarium/aquarium.dm index 15c7d22693255..d83865497805c 100644 --- a/code/modules/fishing/aquarium/aquarium.dm +++ b/code/modules/fishing/aquarium/aquarium.dm @@ -104,6 +104,8 @@ /obj/structure/aquarium/prefilled/Initialize(mapload) . = ..() + ADD_TRAIT(src, TRAIT_STOP_FISH_REPRODUCTION_AND_GROWTH, AQUARIUM_TRAIT) //start with safe mode on + new /obj/item/aquarium_prop/sand(src) new /obj/item/aquarium_prop/seaweed(src) @@ -246,6 +248,8 @@ /obj/item/fish_tank/lawyer/Initialize(mapload) . = ..() + ADD_TRAIT(src, TRAIT_STOP_FISH_REPRODUCTION_AND_GROWTH, AQUARIUM_TRAIT) //start with safe mode on + new /obj/item/aquarium_prop/sand(src) new /obj/item/aquarium_prop/seaweed(src) diff --git a/code/modules/fishing/fish/_fish.dm b/code/modules/fishing/fish/_fish.dm index 1521eb4cc7767..3d91e1173fc2d 100644 --- a/code/modules/fishing/fish/_fish.dm +++ b/code/modules/fishing/fish/_fish.dm @@ -191,6 +191,9 @@ ADD_TRAIT(src, TRAIT_UNCOMPOSTABLE, REF(src)) //Composting a food that is not real food wouldn't work anyway. START_PROCESSING(SSobj, src) + RegisterSignal(src, SIGNAL_ADDTRAIT(TRAIT_FISH_STASIS), PROC_REF(enter_stasis)) + RegisterSignal(src, SIGNAL_REMOVETRAIT(TRAIT_FISH_STASIS), PROC_REF(exit_stasis)) + //Adding this because not all fish have the gore foodtype that makes them automatically eligible for dna infusion. ADD_TRAIT(src, TRAIT_VALID_DNA_INFUSION, INNATE_TRAIT) @@ -473,7 +476,7 @@ return span_deadsay("It's [HAS_MIND_TRAIT(user, TRAIT_NAIVE) ? "taking the big snooze" : "dead"].") var/list/warnings = list() - if(is_starving()) + if(get_starvation_mult()) warnings += "starving" if(!HAS_TRAIT(src, TRAIT_FISH_STASIS) && !proper_environment()) warnings += "drowning" @@ -797,25 +800,29 @@ . = ..() check_flopping() -/obj/item/fish/proc/enter_stasis() - ADD_TRAIT(src, TRAIT_FISH_STASIS, INNATE_TRAIT) - // Stop processing until inserted into aquarium again. +/// Stop processing once the stasis trait is added +/obj/item/fish/proc/enter_stasis(datum/source) + SIGNAL_HANDLER stop_flopping() STOP_PROCESSING(SSobj, src) -/obj/item/fish/proc/exit_stasis() - REMOVE_TRAIT(src, TRAIT_FISH_STASIS, INNATE_TRAIT) - if(status != FISH_DEAD) - START_PROCESSING(SSobj, src) +/// Start processing again when the stasis trait is removed +/obj/item/fish/proc/exit_stasis(datum/source) + SIGNAL_HANDLER + if(status == FISH_DEAD) + return + START_PROCESSING(SSobj, src) + check_flopping() -///Returns the 0-1 value for hunger -/obj/item/fish/proc/get_hunger() - . = CLAMP01((world.time - last_feeding) / feeding_frequency) +///Returns the value for hunger ranging from 0 to the cap (by default 1) +/obj/item/fish/proc/get_hunger(cap = 1) + . = clamp((world.time - last_feeding) / feeding_frequency, 0, cap) if(HAS_TRAIT(src, TRAIT_FISH_NO_HUNGER)) return min(., 0.2) -/obj/item/fish/proc/is_starving() - return get_hunger() >= 1 +/obj/item/fish/proc/get_starvation_mult() + var/hunger = get_hunger(cap = 2) + return hunger >= 1 ? hunger : 0 ///Feed the fishes with the contents of the fish feed /obj/item/fish/proc/feed(datum/reagents/fed_reagents) @@ -912,12 +919,17 @@ if(HAS_TRAIT(src, TRAIT_FISH_STASIS) || status != FISH_ALIVE) return - process_health(seconds_per_tick) - if(ready_to_reproduce()) - try_to_reproduce() + //safe mode, don't do much except a few things that don't involve growing or reproducing. + if(loc && HAS_TRAIT_FROM(loc, TRAIT_STOP_FISH_REPRODUCTION_AND_GROWTH, AQUARIUM_TRAIT)) + last_feeding += seconds_per_tick SECONDS + breeding_wait += seconds_per_tick SECONDS + else + process_health(seconds_per_tick) + if(ready_to_reproduce()) + try_to_reproduce() - if(HAS_TRAIT(src, TRAIT_FISH_ELECTROGENESIS) && COOLDOWN_FINISHED(src, electrogenesis_cooldown)) - try_electrogenesis() + if(HAS_TRAIT(src, TRAIT_FISH_ELECTROGENESIS) && COOLDOWN_FINISHED(src, electrogenesis_cooldown)) + try_electrogenesis() SEND_SIGNAL(src, COMSIG_FISH_LIFE, seconds_per_tick) @@ -1137,13 +1149,14 @@ /obj/item/fish/proc/process_health(seconds_per_tick) var/health_change_per_second = 0 if(!proper_environment()) - health_change_per_second -= 3 //Dying here - if(is_starving()) - health_change_per_second -= 0.5 //Starving + health_change_per_second -= 2.5 //Dying here + var/starvation_mult = get_starvation_mult() + if(starvation_mult) + health_change_per_second -= 0.25 * starvation_mult //Starving else health_change_per_second += 0.5 //Slowly healing if(HAS_TRAIT(src, TRAIT_FISH_ON_TESLIUM)) - health_change_per_second -= 0.65 //This becomes - 0.15 if safe and not starving. + health_change_per_second -= 0.65 adjust_health(health + health_change_per_second * seconds_per_tick) @@ -1362,7 +1375,7 @@ flop_animation() /obj/item/fish/proc/try_electrogenesis() - if(status == FISH_DEAD || is_starving()) + if(status == FISH_DEAD || get_starvation_mult()) return COOLDOWN_START(src, electrogenesis_cooldown, ELECTROGENESIS_DURATION + ELECTROGENESIS_VARIANCE) var/fish_zap_range = 1 @@ -1446,7 +1459,7 @@ user.electrocute_act(5, src) //was it all worth it? fish_flags |= FISH_FLAG_PETTED new /obj/effect/temp_visual/heart(get_turf(src)) - if((/datum/fish_trait/aggressive in fish_traits) && prob(50)) + if((/datum/fish_trait/predator in fish_traits) && prob(50)) if(!in_aquarium) user.visible_message( span_warning("[src] dances around before biting [user]!"), diff --git a/code/modules/fishing/fish/fish_evolution.dm b/code/modules/fishing/fish/fish_evolution.dm index 8dd9bb0ffcd0d..09ce6452f7527 100644 --- a/code/modules/fishing/fish/fish_evolution.dm +++ b/code/modules/fishing/fish/fish_evolution.dm @@ -96,7 +96,7 @@ GLOBAL_LIST_EMPTY(fishes_by_fish_evolution) name = "???" //The resulting fish is not shown on the catalog. probability = 40 new_fish_type = /obj/item/fish/mastodon - new_traits = list(/datum/fish_trait/heavy, /datum/fish_trait/amphibious, /datum/fish_trait/predator, /datum/fish_trait/aggressive) + new_traits = list(/datum/fish_trait/heavy, /datum/fish_trait/amphibious, /datum/fish_trait/predator, /datum/fish_trait/territorial) conditions_note = "The fish (and its mate) needs to be unusually big both in size and weight." show_result_on_wiki = FALSE @@ -125,13 +125,13 @@ GLOBAL_LIST_EMPTY(fishes_by_fish_evolution) /datum/fish_evolution/chainsawfish probability = 30 new_fish_type = /obj/item/fish/chainsawfish - new_traits = list(/datum/fish_trait/predator, /datum/fish_trait/aggressive) - conditions_note = "The fish needs to be unusually big and aggressive" + new_traits = list(/datum/fish_trait/predator, /datum/fish_trait/territorial) + conditions_note = "The fish needs to be unusually big and territorial" /datum/fish_evolution/chainsawfish/check_conditions(obj/item/fish/source, obj/item/fish/mate, atom/movable/aquarium) var/double_avg_size = /obj/item/fish/goldfish::average_size * 2 var/double_avg_weight = /obj/item/fish/goldfish::average_weight * 2 - if(source.size >= double_avg_size && source.weight >= double_avg_weight && (/datum/fish_trait/aggressive in source.fish_traits)) + if(source.size >= double_avg_size && source.weight >= double_avg_weight && (/datum/fish_trait/territorial in source.fish_traits)) return ..() return FALSE diff --git a/code/modules/fishing/fish/fish_traits.dm b/code/modules/fishing/fish/fish_traits.dm index c3b813b5b4828..7211041915418 100644 --- a/code/modules/fishing/fish/fish_traits.dm +++ b/code/modules/fishing/fish/fish_traits.dm @@ -184,11 +184,12 @@ GLOBAL_LIST_INIT(spontaneous_fish_traits, populate_spontaneous_fish_traits()) /datum/fish_trait/nocturnal/proc/check_light(obj/item/fish/source, seconds_per_tick) SIGNAL_HANDLER - if(source.loc && (HAS_TRAIT(source.loc, TRAIT_IS_AQUARIUM) || isturf(source.loc))) - var/turf/turf = get_turf(source) - var/light_amount = turf.get_lumcount() - if(light_amount > SHADOW_SPECIES_LIGHT_THRESHOLD) - source.adjust_health(source.health - 0.5 * seconds_per_tick) + if(!source.loc || (!HAS_TRAIT(source.loc, TRAIT_IS_AQUARIUM) && !isturf(source.loc))) + return + var/turf/turf = get_turf(source) + var/light_amount = turf.get_lumcount() + if(light_amount > SHADOW_SPECIES_LIGHT_THRESHOLD) + source.adjust_health(source.health - 0.5 * seconds_per_tick) /datum/fish_trait/nocturnal/apply_to_mob(mob/living/basic/mob) . = ..() @@ -518,20 +519,23 @@ GLOBAL_LIST_INIT(spontaneous_fish_traits, populate_spontaneous_fish_traits()) . = ..() ADD_TRAIT(fish, TRAIT_FISH_CROSSBREEDER, FISH_TRAIT_DATUM) -/datum/fish_trait/aggressive - name = "Aggressive" +/datum/fish_trait/territorial + name = "Territorial" inheritability = 80 diff_traits_inheritability = 40 - catalog_description = "This fish is aggressively territorial, and may attack fish that come close to it." + catalog_description = "This fish will start attacking other fish if the aquarium has five or more." -/datum/fish_trait/aggressive/apply_to_fish(obj/item/fish/fish) +/datum/fish_trait/territorial/apply_to_fish(obj/item/fish/fish) . = ..() RegisterSignal(fish, COMSIG_FISH_LIFE, PROC_REF(try_attack_fish)) -/datum/fish_trait/aggressive/proc/try_attack_fish(obj/item/fish/source, seconds_per_tick) +/datum/fish_trait/territorial/proc/try_attack_fish(obj/item/fish/source, seconds_per_tick) SIGNAL_HANDLER if(!source.loc || !HAS_TRAIT(source.loc, TRAIT_IS_AQUARIUM) || !SPT_PROB(1, seconds_per_tick)) return + var/list/fishes = source.get_aquarium_fishes(TRUE, source) + if(length(fishes) < 5) + return for(var/obj/item/fish/victim as anything in source.get_aquarium_fishes(TRUE, source)) if(victim.status != FISH_ALIVE) continue diff --git a/code/modules/fishing/fish/types/air_space.dm b/code/modules/fishing/fish/types/air_space.dm index 3b053dc4c25eb..95418f5248a3b 100644 --- a/code/modules/fishing/fish/types/air_space.dm +++ b/code/modules/fishing/fish/types/air_space.dm @@ -122,7 +122,7 @@ fillet_type = /obj/item/food/fishmeat/carp/no_tox fish_traits = list( /datum/fish_trait/carnivore, - /datum/fish_trait/aggressive, + /datum/fish_trait/territorial, /datum/fish_trait/predator, /datum/fish_trait/necrophage, /datum/fish_trait/no_mating, diff --git a/code/modules/fishing/fish/types/anadromous.dm b/code/modules/fishing/fish/types/anadromous.dm index 7f9e6b4d2e26c..02d126bb30183 100644 --- a/code/modules/fishing/fish/types/anadromous.dm +++ b/code/modules/fishing/fish/types/anadromous.dm @@ -55,7 +55,7 @@ fishing_difficulty_modifier = 10 required_temperature_min = MIN_AQUARIUM_TEMP+12 required_temperature_max = MIN_AQUARIUM_TEMP+27 - fish_traits = list(/datum/fish_trait/carnivore, /datum/fish_trait/predator, /datum/fish_trait/aggressive) + fish_traits = list(/datum/fish_trait/carnivore, /datum/fish_trait/predator, /datum/fish_trait/territorial) evolution_types = list(/datum/fish_evolution/armored_pike) compatible_types = list(/obj/item/fish/pike/armored) favorite_bait = list( diff --git a/code/modules/fishing/fish/types/freshwater.dm b/code/modules/fishing/fish/types/freshwater.dm index 4e7a7d9c9ebf0..cb4546e79616e 100644 --- a/code/modules/fishing/fish/types/freshwater.dm +++ b/code/modules/fishing/fish/types/freshwater.dm @@ -82,7 +82,7 @@ average_size = 30 average_weight = 500 stable_population = 3 - fish_traits = list(/datum/fish_trait/aggressive) + fish_traits = list(/datum/fish_trait/territorial) required_temperature_min = MIN_AQUARIUM_TEMP+22 required_temperature_max = MIN_AQUARIUM_TEMP+30 diff --git a/code/modules/fishing/fish/types/ruins.dm b/code/modules/fishing/fish/types/ruins.dm index 233c6961d26da..da2d2ef77293b 100644 --- a/code/modules/fishing/fish/types/ruins.dm +++ b/code/modules/fishing/fish/types/ruins.dm @@ -24,7 +24,7 @@ average_size = 180 average_weight = 5000 death_text = "%SRC stops moving." - fish_traits = list(/datum/fish_trait/heavy, /datum/fish_trait/amphibious, /datum/fish_trait/revival, /datum/fish_trait/carnivore, /datum/fish_trait/predator, /datum/fish_trait/aggressive) + fish_traits = list(/datum/fish_trait/heavy, /datum/fish_trait/amphibious, /datum/fish_trait/revival, /datum/fish_trait/carnivore, /datum/fish_trait/predator, /datum/fish_trait/territorial) beauty = FISH_BEAUTY_BAD /obj/item/fish/mastodon/Initialize(mapload, apply_qualities = TRUE) diff --git a/code/modules/fishing/fish/types/syndicate.dm b/code/modules/fishing/fish/types/syndicate.dm index 81366c2ba8f75..b36efd4a0c2f2 100644 --- a/code/modules/fishing/fish/types/syndicate.dm +++ b/code/modules/fishing/fish/types/syndicate.dm @@ -97,7 +97,7 @@ FISH_BAIT_VALUE = GORE, ), ) - fish_traits = list(/datum/fish_trait/aggressive, /datum/fish_trait/carnivore, /datum/fish_trait/predator, /datum/fish_trait/stinger) + fish_traits = list(/datum/fish_trait/territorial, /datum/fish_trait/carnivore, /datum/fish_trait/predator, /datum/fish_trait/stinger) required_temperature_min = MIN_AQUARIUM_TEMP+18 required_temperature_max = MIN_AQUARIUM_TEMP+26 @@ -207,7 +207,7 @@ random_case_rarity = FISH_RARITY_GOOD_LUCK_FINDING_THIS beauty = FISH_BEAUTY_GREAT fishing_difficulty_modifier = 20 - fish_traits = list(/datum/fish_trait/carnivore, /datum/fish_trait/predator, /datum/fish_trait/aggressive, /datum/fish_trait/picky_eater, /datum/fish_trait/stinger) + fish_traits = list(/datum/fish_trait/carnivore, /datum/fish_trait/predator, /datum/fish_trait/territorial, /datum/fish_trait/picky_eater, /datum/fish_trait/stinger) evolution_types = null compatible_types = list(/obj/item/fish/pike) favorite_bait = list( diff --git a/code/modules/fishing/fish/types/tiziran.dm b/code/modules/fishing/fish/types/tiziran.dm index 7cc3ea94e6862..fdfbd578083c0 100644 --- a/code/modules/fishing/fish/types/tiziran.dm +++ b/code/modules/fishing/fish/types/tiziran.dm @@ -37,7 +37,7 @@ /obj/item/fish/moonfish/proc/egg_checks(datum/source, seconds_per_tick, growth, result_path) if(result_path != /obj/item/food/moonfish_eggs) //Don't stop the growth of the dwarf subtype. return - if(!proper_environment() || is_starving()) + if(!proper_environment() || get_starvation_mult()) return COMPONENT_DONT_GROW var/count = 0 for(var/obj/item/food/moonfish_eggs/egg in loc) diff --git a/code/modules/mapfluff/ruins/spaceruin_code/hauntedtradingpost.dm b/code/modules/mapfluff/ruins/spaceruin_code/hauntedtradingpost.dm index ac4f257dc2a52..30cb60cc243ee 100644 --- a/code/modules/mapfluff/ruins/spaceruin_code/hauntedtradingpost.dm +++ b/code/modules/mapfluff/ruins/spaceruin_code/hauntedtradingpost.dm @@ -88,12 +88,11 @@ /obj/structure/aquarium/donkfish/Initialize(mapload) . = ..() + ADD_TRAIT(src, TRAIT_STOP_FISH_REPRODUCTION_AND_GROWTH, AQUARIUM_TRAIT) new /obj/item/aquarium_prop/rocks(src) new /obj/item/aquarium_prop/seaweed(src) new /obj/item/fish/donkfish(src) new /obj/item/fish/donkfish(src) - create_reagents(20, SEALED_CONTAINER) - reagents.add_reagent(/datum/reagent/consumable/nutriment, 20) //gimmick ketchup bottle for healing minor injuries /obj/item/reagent_containers/condiment/donksauce diff --git a/code/modules/research/designs/autolathe/service_designs.dm b/code/modules/research/designs/autolathe/service_designs.dm index 21fda49fc1bdc..38e36d269149d 100644 --- a/code/modules/research/designs/autolathe/service_designs.dm +++ b/code/modules/research/designs/autolathe/service_designs.dm @@ -562,6 +562,18 @@ ) departmental_flags = DEPARTMENT_BITFLAG_SERVICE | DEPARTMENT_BITFLAG_CARGO | DEPARTMENT_BITFLAG_SCIENCE +/datum/design/aquarium_kit + name = "Aquarium Kit" + id = "aquarium_kit" + build_type = AUTOLATHE | PROTOLATHE | AWAY_LATHE + materials = list(/datum/material/iron = HALF_SHEET_MATERIAL_AMOUNT) + build_path = /obj/item/aquarium_kit + category = list( + RND_CATEGORY_INITIAL, + RND_CATEGORY_EQUIPMENT + RND_SUBCATEGORY_EQUIPMENT_SERVICE, + ) + departmental_flags = DEPARTMENT_BITFLAG_SERVICE | DEPARTMENT_BITFLAG_CARGO | DEPARTMENT_BITFLAG_SCIENCE + /datum/design/ticket_machine name = "Ticket Machine Frame" id = "ticket_machine" diff --git a/code/modules/research/techweb/nodes/service_nodes.dm b/code/modules/research/techweb/nodes/service_nodes.dm index 824cd611b837d..6786c2f9e1ec1 100644 --- a/code/modules/research/techweb/nodes/service_nodes.dm +++ b/code/modules/research/techweb/nodes/service_nodes.dm @@ -159,6 +159,7 @@ "fishing_portal_generator", "fishing_rod", "fish_case", + "aquarium_kit", ) /datum/techweb_node/fishing_equip_adv diff --git a/strings/fishing_tips.txt b/strings/fishing_tips.txt index 466540bb187b1..fd2e0dccc8100 100644 --- a/strings/fishing_tips.txt +++ b/strings/fishing_tips.txt @@ -55,4 +55,5 @@ Feeding a fish mutagen can triple the probability of generating evolved offsprin You can print fishing rods of different materials from an autolathe, which can inrease or decrease fishing difficulty, casting range, experience gained and can have other, special effects. Albeit scarcely, it's possible to catch fish made of the same materials of a custom material fishing rod. Equipping a shiny fishing hook and the quality of the bait can improve your odds. You can use a fishing rod to snatch random organs during the "manipulate organs" step of the "organ manipulation" surgery. +By opening the aquarium panel and turning "Safe Mode" on, you can easily set up a purely decorative aquarium without having to worry about food, temperature and type of water. Aquariums are also potential fishing spots. Only useful for catching fish you couldn't find in the wild, as a personal achievement and nothing more. \ No newline at end of file diff --git a/tgui/packages/tgui/interfaces/Aquarium.tsx b/tgui/packages/tgui/interfaces/Aquarium.tsx index bbdc753263417..c5eb08e564419 100644 --- a/tgui/packages/tgui/interfaces/Aquarium.tsx +++ b/tgui/packages/tgui/interfaces/Aquarium.tsx @@ -24,7 +24,7 @@ type Data = { fluidTypes: string[]; fishData: FishData[]; propData: PropData[]; - allowBreeding: BooleanLike; + safe_mode: BooleanLike; feedingInterval: number; heartIcon: string; heartIconState: string; @@ -270,7 +270,7 @@ const Settings = (props) => { maxTemperature, fluidTypes, fluidType, - allowBreeding, + safe_mode, feedingInterval, } = data; @@ -319,13 +319,14 @@ const Settings = (props) => {
- +