Files
Bubberstation/code/datums/components/irradiated.dm
T
MrMelbertandGitHub 9e1c71f794 Reworks transformation sting to be temporarily in living mobs, forever in dead mobs (#78502)
## About The Pull Request

- Reworks transformation sting. 
- Transformation sting is now temporary, lasting 8 minutes (number not
final) in humans.
      - If used on a monkey, it lasts forever instead. 
- While the target mob is dead or in stasis, the duration will not
progress, making it functionally infinite until revived and taken off
stasis, where it will resume its timer where it left off.
   - Chemical cost reduced to 33
   - DNA cost reduced to 2

- Removes TRAIT_NO_TRANSFORMATION_STING, instead just checks for
TRAIT_NO_DNA_COPY
   - These were essentially the same traits, so I just combined the two

- Organizes some trait lists alphabetically

- Adds TRAIT_STASIS, to allow for reacting to mobs entering and exiting
stasis via COMSIGS
- Everything that checks IS_IN_STASIS now checks HAS_TRAIT TRAIT_STASIS,
which is probably more performant, so that's a bonus.

## Why It's Good For The Game

A lot of people don't like the current iteration of Transformation
Sting, me included

Right now it's only use is for a meme - you make the entire station into
felinids until you get lynched, and that's it.

It's not really a healthy ability for ling's current kit, so this pr
attempts to soft rework it to make it a bit more in line with how ling
should be acting - turning it into a source of short term confusion
between people, or using it on a body to cover your tracks.

This accomplish it two fold - One, it is now cheap enough to use twice
in rapid succession, allowing for quick on-the-spot "BE CONFUSED"
situations while you abscond. Two, as mentioned in the last paragraph,
you can poke a body of someone you murder to obfuscate the crime scene
and maybe help out in taking over someone's identity.

## Changelog

🆑 Melbert
balance: Transformation sting now lasts 8 minutes, down from permanent.
However, the effect is paused for dead and stasis mobs, making it
permanent SO LONG AS they stay dead or in stasis. The effect is also
permanent if used on a monkey.
balance: Transformation sting now costs 33 chemicals, down from 50. 
balance: Transformation sting now costs 2 dna points, down from 3. 
fix: Transformation sting works on monkeys again.
refactor: Refactored a bit of human randomization. 
/🆑
2023-09-28 13:47:39 -06:00

201 lines
6.3 KiB
Plaintext

#define RADIATION_IMMEDIATE_TOX_DAMAGE 10
#define RADIATION_TOX_DAMAGE_PER_INTERVAL 2
#define RADIATION_TOX_INTERVAL (25 SECONDS)
#define RADIATION_BURN_SPLOTCH_DAMAGE 11
#define RADIATION_BURN_INTERVAL_MIN (30 SECONDS)
#define RADIATION_BURN_INTERVAL_MAX (60 SECONDS)
// Showers process on SSmachines
#define RADIATION_CLEAN_IMMUNITY_TIME (SSMACHINES_DT + (1 SECONDS))
/// This atom is irradiated, and will glow green.
/// Humans will take toxin damage until all their toxin damage is cleared.
/datum/component/irradiated
dupe_mode = COMPONENT_DUPE_UNIQUE
var/beginning_of_irradiation
var/burn_splotch_timer_id
COOLDOWN_DECLARE(clean_cooldown)
COOLDOWN_DECLARE(last_tox_damage)
/datum/component/irradiated/Initialize()
if (!CAN_IRRADIATE(parent))
return COMPONENT_INCOMPATIBLE
// This isn't incompatible, it's just wrong
if (HAS_TRAIT(parent, TRAIT_RADIMMUNE))
qdel(src)
return
ADD_TRAIT(parent, TRAIT_IRRADIATED, REF(src))
create_glow()
beginning_of_irradiation = world.time
if (ishuman(parent))
var/mob/living/carbon/human/human_parent = parent
human_parent.apply_damage(RADIATION_IMMEDIATE_TOX_DAMAGE, TOX)
START_PROCESSING(SSobj, src)
COOLDOWN_START(src, last_tox_damage, RADIATION_TOX_INTERVAL)
start_burn_splotch_timer()
human_parent.throw_alert(ALERT_IRRADIATED, /atom/movable/screen/alert/irradiated)
/datum/component/irradiated/RegisterWithParent()
RegisterSignal(parent, COMSIG_COMPONENT_CLEAN_ACT, PROC_REF(on_clean))
RegisterSignal(parent, COMSIG_GEIGER_COUNTER_SCAN, PROC_REF(on_geiger_counter_scan))
/datum/component/irradiated/UnregisterFromParent()
UnregisterSignal(parent, list(
COMSIG_COMPONENT_CLEAN_ACT,
COMSIG_GEIGER_COUNTER_SCAN,
))
/datum/component/irradiated/Destroy(force, silent)
var/atom/movable/parent_movable = parent
if (istype(parent_movable))
parent_movable.remove_filter("rad_glow")
var/mob/living/carbon/human/human_parent = parent
if (istype(human_parent))
human_parent.clear_alert(ALERT_IRRADIATED)
REMOVE_TRAIT(parent, TRAIT_IRRADIATED, REF(src))
deltimer(burn_splotch_timer_id)
STOP_PROCESSING(SSobj, src)
return ..()
/datum/component/irradiated/process(seconds_per_tick)
if (!ishuman(parent))
return PROCESS_KILL
if (HAS_TRAIT(parent, TRAIT_RADIMMUNE))
qdel(src)
return PROCESS_KILL
var/mob/living/carbon/human/human_parent = parent
if (human_parent.getToxLoss() == 0)
qdel(src)
return PROCESS_KILL
if (should_halt_effects(parent))
return
if (human_parent.stat > DEAD)
human_parent.dna?.species?.handle_radiation(human_parent, world.time - beginning_of_irradiation, seconds_per_tick)
process_tox_damage(human_parent, seconds_per_tick)
/datum/component/irradiated/proc/should_halt_effects(mob/living/carbon/human/target)
if (HAS_TRAIT(target, TRAIT_STASIS))
return TRUE
if (HAS_TRAIT(target, TRAIT_HALT_RADIATION_EFFECTS))
return TRUE
if (!COOLDOWN_FINISHED(src, clean_cooldown))
return TRUE
return FALSE
/datum/component/irradiated/proc/process_tox_damage(mob/living/carbon/human/target, seconds_per_tick)
if (!COOLDOWN_FINISHED(src, last_tox_damage))
return
target.apply_damage(RADIATION_TOX_DAMAGE_PER_INTERVAL, TOX)
COOLDOWN_START(src, last_tox_damage, RADIATION_TOX_INTERVAL)
/datum/component/irradiated/proc/start_burn_splotch_timer()
addtimer(CALLBACK(src, PROC_REF(give_burn_splotches)), rand(RADIATION_BURN_INTERVAL_MIN, RADIATION_BURN_INTERVAL_MAX), TIMER_STOPPABLE)
/datum/component/irradiated/proc/give_burn_splotches()
// This shouldn't be possible, but just in case.
if (QDELETED(src))
return
start_burn_splotch_timer()
var/mob/living/carbon/human/human_parent = parent
if (should_halt_effects(parent))
return
var/obj/item/bodypart/affected_limb = human_parent.get_bodypart(human_parent.get_random_valid_zone())
human_parent.visible_message(
span_boldwarning("[human_parent]'s [affected_limb.plaintext_zone] bubbles unnaturally, then bursts into blisters!"),
span_boldwarning("Your [affected_limb.plaintext_zone] bubbles unnaturally, then bursts into blisters!"),
)
if(human_parent.is_blind())
to_chat(human_parent, span_boldwarning("Your [affected_limb.plaintext_zone] feels like it's bubbling, then burns like hell!"))
human_parent.apply_damage(RADIATION_BURN_SPLOTCH_DAMAGE, BURN, affected_limb)
playsound(
human_parent,
pick('sound/effects/wounds/sizzle1.ogg', 'sound/effects/wounds/sizzle2.ogg'),
50,
vary = TRUE,
)
/datum/component/irradiated/proc/create_glow()
var/atom/movable/parent_movable = parent
if (!istype(parent_movable))
return
parent_movable.add_filter("rad_glow", 2, list("type" = "outline", "color" = "#39ff1430", "size" = 2))
addtimer(CALLBACK(src, PROC_REF(start_glow_loop), parent_movable), rand(0.1 SECONDS, 1.9 SECONDS)) // Things should look uneven
/datum/component/irradiated/proc/start_glow_loop(atom/movable/parent_movable)
var/filter = parent_movable.get_filter("rad_glow")
if (!filter)
return
animate(filter, alpha = 110, time = 1.5 SECONDS, loop = -1)
animate(alpha = 40, time = 2.5 SECONDS)
/datum/component/irradiated/proc/on_clean(datum/source, clean_types)
SIGNAL_HANDLER
if (!(clean_types & CLEAN_TYPE_RADIATION))
return
if (isitem(parent))
qdel(src)
return COMPONENT_CLEANED
COOLDOWN_START(src, clean_cooldown, RADIATION_CLEAN_IMMUNITY_TIME)
/datum/component/irradiated/proc/on_geiger_counter_scan(datum/source, mob/user, obj/item/geiger_counter/geiger_counter)
SIGNAL_HANDLER
if (isliving(source))
var/mob/living/living_source = source
to_chat(user, span_boldannounce("[icon2html(geiger_counter, user)] Subject is irradiated. Contamination traces back to roughly [DisplayTimeText(world.time - beginning_of_irradiation, 5)] ago. Current toxin levels: [living_source.getToxLoss()]."))
else
// In case the green wasn't obvious enough...
to_chat(user, span_boldannounce("[icon2html(geiger_counter, user)] Target is irradiated."))
return COMSIG_GEIGER_COUNTER_SCAN_SUCCESSFUL
/atom/movable/screen/alert/irradiated
name = "Irradiated"
desc = "You're irradiated! Heal your toxins quick, and stand under a shower to halt the incoming damage."
icon_state = ALERT_IRRADIATED
#undef RADIATION_BURN_SPLOTCH_DAMAGE
#undef RADIATION_BURN_INTERVAL_MIN
#undef RADIATION_BURN_INTERVAL_MAX
#undef RADIATION_CLEAN_IMMUNITY_TIME
#undef RADIATION_IMMEDIATE_TOX_DAMAGE
#undef RADIATION_TOX_INTERVAL
#undef RADIATION_TOX_DAMAGE_PER_INTERVAL