mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-01-11 09:22:41 +00:00
About The Pull Request
Deletes /obj/shapeshift_holder, replaces it with /datum/status_effect/shapechange_mob
Refactors Heretic worm form into a shapeshift spell
Refactors Wabbajack, and associated code
Fixes #69117
Fixes #65653
Fixes #59127
Fixes #52786
Why It's Good For The Game
/obj/shapeshift_holder was one of the worst remaining abuses of /obj direct subtypes, so I replaced it with a cool fancy datum.
This also decouples the shapeshifting behavior entirely from the shapeshifting spell. So we have support for shapeshifted mobs not sourced from a spell. Which is neat, we could technically swap Wabbajack to use this in the future.
Changelog
cl Melbert
fix: Wabbajacking a shapeshifted mob no longer runtimes horribly. When a shapeshifted mob is wabbajacked, they'll now be removed from their shapeshift and stunned.
fix: Transforming via a shapeshift should no longer rob you of your hearing / runechat awareness.
fix: Shapeshifting plays nicer with holoparasites.
fix: Being polymorphed from a xeno to a non-xeno correctly makes you a non-xeno
refactor: Refactored shapeshifting, the shapeshift holder is now a status effect instead of an object.
refactor: Heretic worm form is a shapeshift spell now, this might have some minor behavioral changes but should overall be the same.
refactor: Refactored Wabbajack (+ cursed pool). Overall a bit more clean / consistent behavior.
/cl
106 lines
4.2 KiB
Plaintext
106 lines
4.2 KiB
Plaintext
/**
|
|
* Validates that all shapeshift type spells have a valid possible_shapes setup.
|
|
*/
|
|
/datum/unit_test/shapeshift_spell_validity
|
|
|
|
/datum/unit_test/shapeshift_spell_validity/Run()
|
|
|
|
var/list/types_to_test = subtypesof(/datum/action/cooldown/spell/shapeshift)
|
|
|
|
for(var/spell_type in types_to_test)
|
|
var/datum/action/cooldown/spell/shapeshift/shift = new spell_type()
|
|
if(!LAZYLEN(shift.possible_shapes))
|
|
Fail("Shapeshift spell: [shift] ([spell_type]) did not have any possible shapeshift options.")
|
|
|
|
for(var/shift_type in shift.possible_shapes)
|
|
if(!ispath(shift_type, /mob/living))
|
|
Fail("Shapeshift spell: [shift] had an invalid / non-living shift type ([shift_type]) in their possible shapes list.")
|
|
|
|
qdel(shift)
|
|
|
|
/**
|
|
* Validates that shapeshift spells put the mob in another mob, as they should.
|
|
*/
|
|
/datum/unit_test/shapeshift_spell
|
|
|
|
/datum/unit_test/shapeshift_spell/Run()
|
|
|
|
var/mob/living/carbon/human/dummy = allocate(/mob/living/carbon/human)
|
|
dummy.mind_initialize()
|
|
|
|
for(var/spell_type in subtypesof(/datum/action/cooldown/spell/shapeshift))
|
|
// Test all shapeshifts as if they were on the mob's body
|
|
var/datum/action/cooldown/spell/shapeshift/bodybound_shift = new spell_type(dummy)
|
|
bodybound_shift.Grant(dummy)
|
|
if(LAZYLEN(bodybound_shift.possible_shapes) > 1)
|
|
for(var/forced_shape in bodybound_shift.possible_shapes)
|
|
test_spell(dummy, bodybound_shift, forced_shape)
|
|
|
|
else if(LAZYLEN(bodybound_shift.possible_shapes) == 1)
|
|
test_spell(dummy, bodybound_shift)
|
|
|
|
qdel(bodybound_shift)
|
|
|
|
// And test all shapeshifts as if they were on the mob's mind
|
|
var/datum/action/cooldown/spell/shapeshift/mindbound_shift = new spell_type(dummy.mind)
|
|
mindbound_shift.Grant(dummy)
|
|
if(LAZYLEN(mindbound_shift.possible_shapes) > 1)
|
|
for(var/forced_shape in mindbound_shift.possible_shapes)
|
|
test_spell(dummy, mindbound_shift, forced_shape)
|
|
|
|
else if(LAZYLEN(bodybound_shift.possible_shapes) == 1)
|
|
test_spell(dummy, mindbound_shift)
|
|
|
|
qdel(mindbound_shift)
|
|
|
|
/datum/unit_test/shapeshift_spell/proc/test_spell(mob/living/carbon/human/dummy, datum/action/cooldown/spell/shapeshift/shift, forced_shape)
|
|
if(forced_shape)
|
|
shift.shapeshift_type = forced_shape
|
|
|
|
shift.next_use_time = 0
|
|
shift.Trigger()
|
|
if(!istype(dummy.loc, shift.shapeshift_type))
|
|
return TEST_FAIL("Shapeshift spell: [shift.name] failed to transform the dummy into the shape [initial(shift.shapeshift_type.name)].")
|
|
|
|
var/mob/living/shape = dummy.loc
|
|
if(!(shift in shape.actions))
|
|
return TEST_FAIL("Shapeshift spell: [shift.name] failed to grant the spell to the dummy's shape.")
|
|
|
|
shift.next_use_time = 0
|
|
shift.Trigger()
|
|
if(istype(dummy.loc, shift.shapeshift_type))
|
|
return TEST_FAIL("Shapeshift spell: [shift.name] failed to transform the dummy back into a human.")
|
|
|
|
|
|
/**
|
|
* Validates that shapeshifts function properly with holoparasites.
|
|
*/
|
|
/datum/unit_test/shapeshift_holoparasites
|
|
|
|
/datum/unit_test/shapeshift_holoparasites/Run()
|
|
|
|
var/mob/living/carbon/human/dummy = allocate(/mob/living/carbon/human)
|
|
|
|
var/datum/action/cooldown/spell/shapeshift/wizard/shift = new(dummy)
|
|
shift.shapeshift_type = shift.possible_shapes[1]
|
|
shift.Grant(dummy)
|
|
|
|
var/mob/living/simple_animal/hostile/guardian/test_stand = allocate(/mob/living/simple_animal/hostile/guardian)
|
|
test_stand.set_summoner(dummy)
|
|
|
|
// The stand's summoner is dummy.
|
|
TEST_ASSERT_EQUAL(test_stand.summoner, dummy, "Holoparasite failed to set the summoner to the correct mob.")
|
|
|
|
// Dummy casts shapeshift. The stand's summoner should become the shape the dummy is within.
|
|
shift.Trigger()
|
|
TEST_ASSERT(istype(dummy.loc, shift.shapeshift_type), "Shapeshift spell failed to transform the dummy into the shape [initial(shift.shapeshift_type.name)].")
|
|
TEST_ASSERT_EQUAL(test_stand.summoner, dummy.loc, "Shapeshift spell failed to transfer the holoparasite to the dummy's shape.")
|
|
|
|
// Dummy casts shapeshfit back, the stand's summoner should become the dummy again.
|
|
shift.next_use_time = 0
|
|
shift.Trigger()
|
|
TEST_ASSERT(!istype(dummy.loc, shift.shapeshift_type), "Shapeshift spell failed to transform the dummy back into human form.")
|
|
TEST_ASSERT_EQUAL(test_stand.summoner, dummy, "Shapeshift spell failed to transfer the holoparasite back to the dummy's human form.")
|
|
|
|
qdel(shift)
|