[MDB Ignore] Refactors pills, patches, and generalizes stomach contents, nothing to see here. (#89549)

## About The Pull Request

Currently patches are a subtype of pills, and while they have the
``dissolveable`` var set to FALSE, barely anything checks it (because
people don't expect patches to be pills in disguise) so we end up
patches being dissolveable and implantable, which is far from ideal.
Both have been moved into an ``/obj/item/reagent_containers/applicator``
class, which handles their common logic and helps handling cases where
either one fits. As for gameplay changes:
* Pills no longer dissolve instantly, instead adding their contents to
your stomach after 3 seconds (by default). You can increase the timer by
dropping sugar onto them to thicken their coating, 1s per 1u applied, up
to a full minute. Coating can also be dissolved with water, similarly
-1s per 1u applied. Pills with no coating will work like before.
* Patches now only take half as long to apply (1.5s), but also slowly
trickle in their reagents instead of instantly applying all of them.
This is done via embedding so you could theoretically (if you get lucky)
stick a ranged patch at someone, although they are rather quick to rip
off. The implementation and idea itself are separate, but the idea for
having a visual display has been taken from
https://github.com/Monkestation/Monkestation2.0/pull/2558.

![dreamseeker_Ywd4jQcy3t](https://github.com/user-attachments/assets/7ce0e549-9ecd-4a8a-98ea-12e00754bdd9)
* In order to support the new pill mechanics, stomachs have received
contents. Pills and items that you accidentally swallow now go into your
stomach instead of your chest cavity, and may damage it if they're
sharp, requiring having them surgically cut out (cut the stomach open
with a scalpel, then cauterize it to mend the incision). Or maybe you
can get a bacchus's blessing, or a geneticist hulk to gut punch you,
that may also work. Alien devour ability also uses this system now. If
you get a critical slashing wound on your chest contents of your cut
apart stomach (if a surgeon forgot to mend it, or if you ate too much
glass shard for breakfast) may fall out. However, spacemen with the
strong stomach trait can eat as much glass cereal as they want.

Pill duration can also be chosen in ChemMaster when you have a pill
selected, 0 to 30 seconds.

![image](https://github.com/user-attachments/assets/1f40210e-74dd-49c2-8093-432a747ac8dd)

## Why It's Good For The Game

Patches and pills are extremely similar in their implemenation, former
being a worse version of sprays and pills, with only change being that
pills cannot be applied through helmets while patches and sprays ignore
both. This change makes them useful for separate cases, and allows
reenactment of some classic... movie, scenes, with the pill change. As
for stomach contents, this was probably the sanest way of implementing
pill handling, and everything else (item swallowing and cutting stomachs
open to remove a cyanide pill someone ate before it dissolves) kind of
snowballed from there. I pray to whatever gods that are out there that
this won't have some extremely absurd and cursed interactions (it
probably will).

## Changelog
🆑
add: Instead of dissolving instantly, pills now activate after 4
seconds. This timer can be increased by using a dropper filled with
sugar on them, 1s added per 1u dropped.
add: Patches now stick to you and slowly bleed their reagents, instead
of being strictly inferior to both pills and sprays.
add: Items that you accidentally swallow now go into your stomach
contents.
refactor: Patches are no longer considered pills by the game
refactor: All stomachs now have contents, instead of it being exclusive
to aliens. You can cut open a stomach to empty it with a scalpel, and
mend an existing incision with a cautery.
/🆑
This commit is contained in:
SmArtKar
2025-03-13 17:31:37 +01:00
committed by GitHub
parent 0af4b1c636
commit eb2796831b
85 changed files with 2227 additions and 1666 deletions
+175 -34
View File
@@ -1,4 +1,4 @@
/obj/item/reagent_containers/pill/patch
/obj/item/reagent_containers/applicator/patch
name = "patch"
desc = "A chemical patch for touch based applications."
icon = 'icons/obj/medical/chemical.dmi'
@@ -6,18 +6,19 @@
inhand_icon_state = null
possible_transfer_amounts = list()
volume = 40
apply_type = PATCH
apply_method = "apply"
self_delay = 30 // three seconds
dissolvable = FALSE
embed_type = /datum/embedding/med_patch
// Quick to apply
application_delay = 1.5 SECONDS
self_delay = 1.5 SECONDS
/obj/item/reagent_containers/pill/patch/canconsume(mob/eater, mob/user)
/obj/item/reagent_containers/applicator/patch/canconsume(mob/eater, mob/user)
if(!iscarbon(eater))
return FALSE
if(!ishuman(eater))
return TRUE
var/mob/living/carbon/human/human_eater = eater
var/obj/item/bodypart/affecting = human_eater.get_bodypart(check_zone(user.zone_selected))
var/mob/living/carbon/carbon_eater = eater
var/obj/item/bodypart/affecting = carbon_eater.get_bodypart(check_zone(user.zone_selected))
if(!affecting)
to_chat(user, span_warning("The limb is missing!"))
return FALSE
@@ -26,27 +27,167 @@
to_chat(user, span_notice("Medicine won't work on an inorganic limb!"))
return FALSE
return TRUE // Masks were stopping people from "eating" patches. Thanks, inheritance.
return TRUE
/obj/item/reagent_containers/pill/patch/libital
/obj/item/reagent_containers/applicator/patch/on_consumption(mob/living/carbon/consumer, mob/giver, list/modifiers)
var/clicked_x = LAZYACCESS(modifiers, ICON_X)
var/clicked_y = LAZYACCESS(modifiers, ICON_Y)
if (isnull(clicked_x))
clicked_x = ICON_SIZE_X * (0.5 + rand(-5, 5) * 0.05)
else
clicked_x = text2num(clicked_x)
if (isnull(clicked_y))
clicked_y = ICON_SIZE_Y * (0.5 + rand(-5, 5) * 0.05)
else
clicked_y = text2num(clicked_y)
giver.do_attack_animation(consumer, used_item = src)
var/datum/embedding/med_patch/embed = get_embed()
if (!istype(embed))
embed = set_embed(/datum/embedding/med_patch)
embed.overlay_x = clicked_x - ICON_SIZE_X * 0.5
embed.overlay_y = clicked_y - ICON_SIZE_Y * 0.5
force_embed(consumer, consumer.get_bodypart(check_zone(giver.zone_selected)) || consumer.get_bodypart(BODY_ZONE_CHEST))
/datum/embedding/med_patch
embed_chance = 10
fall_chance = 0
pain_chance = 0
jostle_chance = 0
pain_mult = 0
jostle_pain_mult = 0
// Quick to rip off
rip_time = 0.25 SECONDS
ignore_throwspeed_threshold = TRUE
immune_traits = null
/// How many units are transferred per second
var/transfer_per_second = 0.75
/// Cooldown for reagent messages, prevents spam
COOLDOWN_DECLARE(reagent_message_cd)
// pixel_x and pixel_y for our overlay
var/overlay_x = 0
var/overlay_y = 0
/// Direction in which mob was facing when the patch was applied, used for layering and positional adjustments
var/applied_dir = NONE
/// Patch overlay applied to the mob
var/mutable_appearance/patch_overlay
/datum/embedding/med_patch/set_owner(mob/living/carbon/victim, obj/item/bodypart/target_limb)
. = ..()
overlay_setup()
RegisterSignal(owner, COMSIG_LIVING_IGNITED, PROC_REF(on_ignited))
RegisterSignal(owner, COMSIG_ATOM_DIR_CHANGE, PROC_REF(on_dir_change))
/datum/embedding/med_patch/stop_embedding()
if (owner)
UnregisterSignal(owner, list(COMSIG_LIVING_IGNITED, COMSIG_ATOM_DIR_CHANGE))
if (patch_overlay)
owner.cut_overlay(patch_overlay)
QDEL_NULL(patch_overlay)
return ..()
/datum/embedding/med_patch/can_embed(atom/movable/source, mob/living/carbon/victim, hit_zone, datum/thrownthing/throwingdatum)
. = ..()
if (!.)
return
var/obj/item/bodypart/affecting = victim.get_bodypart(hit_zone) || victim.bodyparts[1]
if (!IS_ORGANIC_LIMB(affecting))
return FALSE
return TRUE
/datum/embedding/med_patch/proc/on_ignited(datum/source)
SIGNAL_HANDLER
if (!(parent.resistance_flags & FLAMMABLE))
return
if (ishuman(owner))
var/mob/living/carbon/human/as_human = owner
if (as_human.get_thermal_protection() >= FIRE_IMMUNITY_MAX_TEMP_PROTECT)
return
INVOKE_ASYNC(src, PROC_REF(fall_out))
qdel(parent)
/// Create a patch overlay and add it to the mob
/datum/embedding/med_patch/proc/overlay_setup()
applied_dir = owner.dir
patch_overlay = mutable_appearance(parent.icon, parent.icon_state, FLOAT_LAYER, parent, appearance_flags = KEEP_APART|RESET_COLOR)
patch_overlay.color = parent.color
if (parent.cached_color_filter)
patch_overlay = filter_appearance_recursive(patch_overlay, parent.cached_color_filter)
patch_overlay.transform *= 0.5
patch_overlay.pixel_w = overlay_x
patch_overlay.pixel_z = overlay_y
owner.add_overlay(patch_overlay)
/// Changes visual position of the patch based on owner's rotation
/datum/embedding/med_patch/proc/on_dir_change(datum/source, old_dir, new_dir)
SIGNAL_HANDLER
owner.cut_overlay(patch_overlay)
if (new_dir == applied_dir)
patch_overlay.pixel_w = overlay_x
patch_overlay.layer = FLOAT_LAYER
owner.add_overlay(patch_overlay)
return
if (new_dir == REVERSE_DIR(applied_dir))
patch_overlay.pixel_w = -overlay_x
patch_overlay.layer = BELOW_MOB_LAYER
owner.add_overlay(patch_overlay)
return
var/check_dir = EAST
var/check_new_dir = SOUTH
if (applied_dir & (NORTH|SOUTH))
check_dir = NORTH
check_new_dir = EAST
// Turn ourselves based on how we were placed originally
var/dir_sign = (applied_dir & check_dir)
if (overlay_x >= 0)
dir_sign = !dir_sign
if (new_dir & check_new_dir)
dir_sign = !dir_sign
// 0.5 multiplier to fake perspective
patch_overlay.pixel_w = overlay_x * (dir_sign ? 0.5 : -0.5)
patch_overlay.layer = dir_sign ? FLOAT_LAYER : BELOW_MOB_LAYER
owner.add_overlay(patch_overlay)
return
/datum/embedding/med_patch/process_effect(seconds_per_tick)
if (HAS_TRAIT(owner, TRAIT_STASIS))
return
if (!parent.reagents.total_volume)
fall_out()
qdel(parent)
return TRUE
var/show_message = FALSE
if (COOLDOWN_FINISHED(src, reagent_message_cd))
show_message = TRUE
COOLDOWN_START(src, reagent_message_cd, PATCH_MESSAGE_COOLDOWN)
parent.reagents.trans_to(owner, transfer_per_second, methods = PATCH, show_message = show_message)
/obj/item/reagent_containers/applicator/patch/libital
name = "libital patch (brute)"
desc = "A pain reliever. Does minor liver damage. Diluted with Granibitaluri."
list_reagents = list(/datum/reagent/medicine/c2/libital = 2, /datum/reagent/medicine/granibitaluri = 8) //10 iterations
icon_state = "bandaid_brute"
/obj/item/reagent_containers/pill/patch/aiuri
/obj/item/reagent_containers/applicator/patch/aiuri
name = "aiuri patch (burn)"
desc = "Helps with burn injuries. Does minor eye damage. Diluted with Granibitaluri."
list_reagents = list(/datum/reagent/medicine/c2/aiuri = 2, /datum/reagent/medicine/granibitaluri = 8)
icon_state = "bandaid_burn"
/obj/item/reagent_containers/pill/patch/synthflesh
/obj/item/reagent_containers/applicator/patch/synthflesh
name = "synthflesh patch"
desc = "Helps with brute and burn injuries. Slightly toxic."
list_reagents = list(/datum/reagent/medicine/c2/synthflesh = 20)
icon_state = "bandaid_both"
/obj/item/reagent_containers/pill/patch/ondansetron
/obj/item/reagent_containers/applicator/patch/ondansetron
name = "ondansetron patch"
desc = "Alleviates nausea. May cause drowsiness."
list_reagents = list(/datum/reagent/medicine/ondansetron = 10)
@@ -54,43 +195,43 @@
// Patch styles for chem master
/obj/item/reagent_containers/pill/patch/style
/obj/item/reagent_containers/applicator/patch/style
icon_state = "bandaid_blank"
/obj/item/reagent_containers/pill/patch/style/brute
/obj/item/reagent_containers/applicator/patch/style/brute
icon_state = "bandaid_brute_2"
/obj/item/reagent_containers/pill/patch/style/burn
/obj/item/reagent_containers/applicator/patch/style/burn
icon_state = "bandaid_burn_2"
/obj/item/reagent_containers/pill/patch/style/bruteburn
/obj/item/reagent_containers/applicator/patch/style/bruteburn
icon_state = "bandaid_both"
/obj/item/reagent_containers/pill/patch/style/toxin
/obj/item/reagent_containers/applicator/patch/style/toxin
icon_state = "bandaid_toxin_2"
/obj/item/reagent_containers/pill/patch/style/oxygen
/obj/item/reagent_containers/applicator/patch/style/oxygen
icon_state = "bandaid_suffocation_2"
/obj/item/reagent_containers/pill/patch/style/omni
/obj/item/reagent_containers/applicator/patch/style/omni
icon_state = "bandaid_mix"
/obj/item/reagent_containers/pill/patch/style/bruteplus
/obj/item/reagent_containers/applicator/patch/style/bruteplus
icon_state = "bandaid_brute"
/obj/item/reagent_containers/pill/patch/style/burnplus
/obj/item/reagent_containers/applicator/patch/style/burnplus
icon_state = "bandaid_burn"
/obj/item/reagent_containers/pill/patch/style/toxinplus
/obj/item/reagent_containers/applicator/patch/style/toxinplus
icon_state = "bandaid_toxin"
/obj/item/reagent_containers/pill/patch/style/oxygenplus
/obj/item/reagent_containers/applicator/patch/style/oxygenplus
icon_state = "bandaid_suffocation"
/obj/item/reagent_containers/pill/patch/style/monkey
/obj/item/reagent_containers/applicator/patch/style/monkey
icon_state = "bandaid_monke"
/obj/item/reagent_containers/pill/patch/style/clown
/obj/item/reagent_containers/applicator/patch/style/clown
icon_state = "bandaid_clown"
/obj/item/reagent_containers/pill/patch/style/one
/obj/item/reagent_containers/applicator/patch/style/one
icon_state = "bandaid_1"
/obj/item/reagent_containers/pill/patch/style/two
/obj/item/reagent_containers/applicator/patch/style/two
icon_state = "bandaid_2"
/obj/item/reagent_containers/pill/patch/style/three
/obj/item/reagent_containers/applicator/patch/style/three
icon_state = "bandaid_3"
/obj/item/reagent_containers/pill/patch/style/four
/obj/item/reagent_containers/applicator/patch/style/four
icon_state = "bandaid_4"
/obj/item/reagent_containers/pill/patch/style/exclamation
/obj/item/reagent_containers/applicator/patch/style/exclamation
icon_state = "bandaid_exclaimationpoint"
/obj/item/reagent_containers/pill/patch/style/question
/obj/item/reagent_containers/applicator/patch/style/question
icon_state = "bandaid_questionmark"
/obj/item/reagent_containers/pill/patch/style/colonthree
/obj/item/reagent_containers/applicator/patch/style/colonthree
icon_state = "bandaid_colonthree"