Fixes protean outfit duplication (#6010)

This commit is contained in:
The Sharkening
2026-08-14 19:42:35 +02:00
committed by Maia
parent bf5e11cc22
commit c1bbab2fc4
5 changed files with 43 additions and 24 deletions
@@ -350,11 +350,11 @@
var/turf/destination = get_turf(destination_landmark)
//BUBBERSTATION EDIT
if(is_species(sac_target, /datum/species/protean))
if(isprotean(sac_target))
var/obj/item/organ/brain/protean/brain = sac_target.get_organ_slot(ORGAN_SLOT_BRAIN)
if(brain)
brain.revive()
brain.leave_modsuit()
brain.leave_modsuit(TRUE)
//BUBBERSTATION EDIT END
sac_target.visible_message(span_danger("[sac_target] begins to shudder violenty as dark tendrils begin to drag them into thin air!"))
sac_target.equip_to_slot_or_del(new /obj/item/restraints/handcuffs/cult, ITEM_SLOT_HANDCUFFED, indirect_action = TRUE)
+1
View File
@@ -373,6 +373,7 @@
#include "~skyrat\digitigrade_sprites.dm"
#include "~skyrat\nanite_designs.dm"
#include "~skyrat\opposing_force.dm"
#include "~skyrat\proteans.dm"
// SKYRAT EDIT END
// END_INCLUDE
#ifdef REFERENCE_TRACKING_DEBUG //Don't try and parse this file if ref tracking isn't turned on. IE: don't parse ref tracking please mr linter
@@ -0,0 +1,27 @@
/**
* Tests Protean suit transformation and species handling. Makes sure any storage is dropped and its contents not deleted.
*/
/datum/unit_test/protean_species_handling/Run()
var/mob/living/carbon/human/consistent/protean = EASY_ALLOCATE()
var/obj/item/stack/sheet/iron/twenty/iron = EASY_ALLOCATE()
var/obj/item/storage/backpack/bag = EASY_ALLOCATE()
protean.equip_to_slot_if_possible(bag, ITEM_SLOT_BACK, TRUE, TRUE, TRUE, TRUE, TRUE)
protean.equip_to_storage(iron, ITEM_SLOT_BACK)
protean.set_species(/datum/species/protean)
var/datum/species/protean/p_species = protean.dna.species
var/backslot = protean.get_item_by_slot(ITEM_SLOT_BACK)
var/obj/item/mod/core/protean/core = p_species.species_modsuit.core
TEST_ASSERT_EQUAL(p_species.owner, protean, "Protean species did not assign dummy as its owner.")
TEST_ASSERT(istype(backslot, /obj/item/mod/control/pre_equipped/protean), "Protean species did not assign /obj/item/mod/control/protean to ITEM_SLOT_BACK. Backslot: [isnull(backslot) ? "Null" : "[backslot]"]")
TEST_ASSERT_NOTNULL(p_species.species_modsuit, "Protean species failed to link to modsuit.")
TEST_ASSERT_EQUAL(core.linked_species, p_species, "Protean modsuit core failed to link to its species.")
TEST_ASSERT(isturf(bag.loc), "[bag::name] did not drop onto a turf! Location: [isnull(bag.loc) ? "Nullspace" : "[bag.loc]"]")
TEST_ASSERT(locate(/obj/item/stack/sheet/iron/twenty) in bag.contents, "[iron::name] are not inside [bag::name]")
protean.equip_to_storage(iron, ITEM_SLOT_BACK)
TEST_ASSERT_EQUAL(iron.loc, p_species.species_modsuit.atom_storage.real_location, "[iron::name] did not enter [p_species.species_modsuit.name] storage. Does it have a storage module?")
protean.set_species(/datum/species/human)
TEST_ASSERT(isturf(iron.loc), "[iron::name] has not dropped to a turf after species loss. Location: [isnull(iron.loc) ? "Nullspace" : "[iron.loc]"]")
@@ -85,14 +85,6 @@
/mob/living/carbon/human/species/protean
race = /datum/species/protean
/datum/species/protean/Destroy(force)
if(!QDELETED(species_modsuit))
INVOKE_ASYNC(src, PROC_REF(unassimilate_modsuit), null, TRUE)
QDEL_NULL(species_modsuit)
QDEL_NULL(protean_action)
owner = null
return ..()
/datum/species/protean/on_species_gain(mob/living/carbon/human/gainer, datum/species/old_species, pref_load, regenerate_icons = TRUE)
. = ..()
owner = gainer
@@ -126,16 +118,18 @@
organ.balloon_alert_to_viewers("rejected!", vision_distance = 1)
/datum/species/protean/on_species_loss(mob/living/carbon/human/gainer, datum/species/new_species, pref_load)
. = ..()
if(gainer)
UnregisterSignal(owner, COMSIG_CARBON_GAIN_ORGAN)
if(species_modsuit.stored_modsuit)
species_modsuit.stored_modsuit.forceMove(get_turf(gainer))
unassimilate_modsuit(null, TRUE)
if(species_modsuit)
if(species_modsuit.atom_storage)
species_modsuit.atom_storage.remove_all(owner.drop_location())
QDEL_NULL(species_modsuit)
protean_action.Remove(owner)
owner = null
return ..()
/datum/species/protean/proc/equip_modsuit(mob/living/carbon/human/gainer)
species_modsuit = new()
@@ -166,13 +160,7 @@
assimilate_modsuit(owner, suit, TRUE)
species_modsuit.quick_activation()
LAZYINITLIST(outfit.backpack_contents)
if(istype(outfit, /datum/outfit/job))
owner.equip_to_storage(SSwardrobe.provide_type(/obj/item/stack/sheet/iron/twenty, owner), ITEM_SLOT_BACK, TRUE, FALSE)
return
outfit.backpack_contents += /obj/item/stack/sheet/iron/twenty
for(var/path in outfit.backpack_contents)
owner.equip_to_storage(SSwardrobe.provide_type(path, owner), ITEM_SLOT_BACK, TRUE, TRUE)
owner.equip_to_storage(SSwardrobe.provide_type(/obj/item/stack/sheet/iron/twenty, owner), ITEM_SLOT_BACK, TRUE, FALSE)
if(outfit.suit_store)
owner.equip_to_slot_if_possible(SSwardrobe.provide_type(outfit.suit_store, owner), ITEM_SLOT_SUITSTORE, FALSE, TRUE, TRUE, TRUE, TRUE, TRUE)
@@ -67,7 +67,7 @@
/datum/movespeed_modifier/protean_slowdown
variable = TRUE
/obj/item/organ/brain/protean/proc/go_into_suit(forced)
/obj/item/organ/brain/protean/proc/go_into_suit(forced = FALSE)
var/datum/species/protean/protean = owner.dna?.species
if(!istype(protean) || owner.loc == protean.species_modsuit)
return
@@ -84,10 +84,11 @@
owner.remove_status_effect(/datum/status_effect/protean_low_power_mode/low_power)
suit.drop_suit()
owner.forceMove(suit)
sleep(12) //Sleep is fine here because I'm not returning anything and if the brain gets deleted within 12 ticks of this being ran, we have some other serious issues.
if(!forced)
sleep(12) //Sleep is fine here because I'm not returning anything and if the brain gets deleted within 12 ticks of this being ran, we have some other serious issues.
owner.invisibility = initial(owner.invisibility)
/obj/item/organ/brain/protean/proc/leave_modsuit()
/obj/item/organ/brain/protean/proc/leave_modsuit(forced = FALSE)
var/datum/species/protean/protean = owner.dna?.species
if(!istype(protean))
return
@@ -95,8 +96,9 @@
if(dead)
to_chat(owner, span_warning("Your mass is destroyed. You are unable to leave."))
return
if(!do_after(owner, 5 SECONDS, suit, IGNORE_INCAPACITATED))
return
if(!forced)
if(!do_after(owner, 5 SECONDS, suit, IGNORE_INCAPACITATED))
return
if(istype(suit.loc, /obj/item/reagent_containers/cup/soup_pot)) // If protean inside of soup pot
var/obj/item/reagent_containers/cup/soup_pot/pot = suit.loc
pot.remove_first_ingredient(null)
@@ -108,7 +110,8 @@
storage.remove_single(null, suit, get_turf(suit), TRUE)
suit.invisibility = 101
new /obj/effect/temp_visual/protean_from_suit(suit.loc, owner.dir)
sleep(12) //Same as above
if(!forced)
sleep(12) //Same as above
suit.drop_suit()
owner.forceMove(suit.loc)
if(owner.get_item_by_slot(ITEM_SLOT_BACK))