Files
Bubberstation/code/datums/components/evolutionary_leap.dm
Jacquerel 190904b5bb Polymorph belt plays nicely with mob evolution (#94723)
## About The Pull Request

Fixes #82319
Fixes #94129

If your mob type changes while you are transformed via the polymorph
belt, it will transfer the polymorph status to the new mob.
This means that turning into a Bileworm after Bileworms have evolved
will no longer ghost you, and instead you will just keep playing as a
vileworm.
Additionally it means if you copy a chick, spiderling, juvenile lobster,
and walk around as one of those for long enough to grow up, it will
seamlessly move you over.
Or if you turn into a mouse and a nearby regal rat uses their riot
ability it will transform you into a rat, etc.

If you change back into a human and then change back into your mob you
will return to the original state though.

I decided to put this on a new subtype of the status effect rather than
the base type because I think it's more of a programming issue if this
happens for an ability with a fixed transform type (and we wouldn't want
to mutate the possible shapes list in that case), so in those cases we
should keep the existing behaviour of just untransforming you.

Additionally, I made the evolutionary leap component always wait a
minimum of three seconds instead of being instant before transforming a
mob. This means that other things have time to register signals and
react to the transformation, so you should never be deleted by bileworm
evolution any more.

## Why It's Good For The Game

This fixes a few long-standing bugs and seems more fun than
untransforming you.

## Changelog

🆑
fix: If you use the polymorph belt to turn into a mob which transforms
into another mob, it won't ghost you or kick you out upon
transformation.
/🆑
2026-01-07 21:00:41 -07:00

60 lines
2.0 KiB
Plaintext

/**
* ### Evolutionary Leap Component; set a time in the round for a mob to evolve into a more dangerous form!
*
* Used for bileworms, to turn into vileworms!
*/
/datum/component/evolutionary_leap
/// how much time until the parent makes an evolutionary leap
var/evolve_mark
/// id for leap timer
var/timer_id
/// what this mob turns into
var/evolve_path
/datum/component/evolutionary_leap/Initialize(evolve_mark, evolve_path)
if(!isliving(parent))
return COMPONENT_INCOMPATIBLE
src.evolve_mark = evolve_mark
src.evolve_path = evolve_path
//don't setup timer yet, timer calc requires the round to have started
if(!SSticker.HasRoundStarted())
RegisterSignal(SSticker, COMSIG_TICKER_ROUND_STARTING, PROC_REF(comp_on_round_start))
return
//if the round has already taken long enough, evolve in three seconds.
if((world.time - SSticker.round_start_time) > evolve_mark)
addtimer(CALLBACK(src, PROC_REF(leap)), 3 SECONDS, TIMER_DELETE_ME)
return
setup_timer()
/datum/component/evolutionary_leap/Destroy(force)
. = ..()
deltimer(timer_id)
/datum/component/evolutionary_leap/UnregisterFromParent()
UnregisterSignal(SSticker, COMSIG_TICKER_ROUND_STARTING)
/// Proc ran when round starts.
/datum/component/evolutionary_leap/proc/comp_on_round_start()
SIGNAL_HANDLER
UnregisterSignal(SSticker, COMSIG_TICKER_ROUND_STARTING)
setup_timer()
/datum/component/evolutionary_leap/proc/setup_timer()
//in cases where this is calculating roundstart, world.time - SSticker.round_start_time should equal 0
var/sum = (world.time - SSticker.round_start_time)
var/mark = evolve_mark - sum
timer_id = addtimer(CALLBACK(src, PROC_REF(leap), FALSE), mark, TIMER_STOPPABLE)
/datum/component/evolutionary_leap/proc/leap()
var/mob/living/old_mob = parent
if (old_mob.stat == DEAD)
return
var/mob/living/new_mob = evolve_path
var/new_mob_name = initial(new_mob.name)
old_mob.visible_message(span_warning("[old_mob] evolves into \a [new_mob_name]!"))
old_mob.change_mob_type(evolve_path, old_mob.loc, new_name = new_mob_name, delete_old_mob = TRUE)