[MIRROR] Resolves mutant species keeping old organs they shouldn't have [MDB IGNORE] (#19958)

* Resolves mutant species keeping old organs they shouldn't have (#73728)

## About The Pull Request

regenerate organs never removed invalid organs when regenerating
## Why It's Good For The Game

Fixes https://github.com/tgstation/tgstation/issues/73640
adds a unit test to prevent regressions in the future

## Changelog
🆑
fix: Plasmamen don't have hearts, again
/🆑

* Resolves mutant species keeping old organs they shouldn't have

* https://github.com/tgstation/tgstation/pull/68168

* Now everything should pass, yes, even appendixes for synths

---------

Co-authored-by: Zephyr <12817816+ZephyrTFA@users.noreply.github.com>
Co-authored-by: GoldenAlpharex <jerego1234@hotmail.com>
Co-authored-by: Coffee <CoffeeDragon16@gmail.com>
This commit is contained in:
SkyratBot
2023-03-26 19:28:28 +02:00
committed by GitHub
parent 45a3020827
commit d4c8a4ed9e
17 changed files with 106 additions and 25 deletions
+4
View File
@@ -13,6 +13,10 @@
#define ORGAN_SYNTHETIC_EMP (1<<5)
// //Can't be removed using surgery
#define ORGAN_UNREMOVABLE (1<<6)
// SKYRAT EDIT START - Customization
/// Synthetic organ granted by a species (for use for organ replacements between species)
#define ORGAN_SYNTHETIC_FROM_SPECIES (1<<7)
// SKYRAT EDIT END
/// When the surgery step fails :(
#define SURGERY_STEP_FAIL -1
@@ -13,6 +13,10 @@
///Take on the dna/preference from whoever we're gonna be inserted in
var/imprint_on_next_insertion = TRUE
/datum/bodypart_overlay/mutant/get_overlay(layer, obj/item/bodypart/limb)
inherit_color(limb) // If draw_color is not set yet, go ahead and do that
return ..()
///Completely random image and color generation (obeys what a player can choose from)
/datum/bodypart_overlay/mutant/proc/randomize_appearance()
randomize_sprite()
@@ -90,8 +94,13 @@
///Give the organ its color. Force will override the existing one.
/datum/bodypart_overlay/mutant/proc/inherit_color(obj/item/bodypart/ownerlimb, force)
if(isnull(ownerlimb))
draw_color = null
return TRUE
if(draw_color && !force)
return
return FALSE
switch(color_source)
if(ORGAN_COLOR_OVERRIDE)
draw_color = override_color(ownerlimb.draw_color)
@@ -102,6 +111,7 @@
return
var/mob/living/carbon/human/human_owner = ownerlimb.owner
draw_color = human_owner.hair_color
return TRUE
///Sprite accessories are singletons, stored list("Big Snout" = instance of /datum/sprite_accessory/snout/big), so here we get that singleton
@@ -172,9 +172,9 @@ GLOBAL_LIST_EMPTY(features_by_species)
///What anim to use for gibbing
var/gib_anim = "gibbed-h"
//Do NOT remove by setting to null. use OR make an ASSOCIATED TRAIT.
//why does it work this way? because traits also disable the downsides of not having an organ, removing organs but not having the trait will make your species die
// Prefer anything other than setting these to null, such as TRAITS
// why?
// because traits also disable the downsides of not having an organ, removing organs but not having the trait or logic will make your species die
///Replaces default brain with a different organ
var/obj/item/organ/internal/brain/mutantbrain = /obj/item/organ/internal/brain
@@ -350,6 +350,9 @@ GLOBAL_LIST_EMPTY(features_by_species)
var/obj/item/organ/oldorgan = C.getorganslot(slot) //used in removing
var/obj/item/organ/neworgan = slot_mutantorgans[slot] //used in adding
if(!neworgan) //these can be null, if so we shouldn't regenerate
if(oldorgan) // although we also need to remove the old organ if it exists
oldorgan.Remove(C, special=TRUE)
qdel(oldorgan)
continue
if(visual_only && !initial(neworgan.visual))
@@ -367,7 +370,7 @@ GLOBAL_LIST_EMPTY(features_by_species)
* - The replaced organ is not in an excluded zone
* - The replaced organ is not unremovable or synthetic (an implant)
*/
if(oldorgan && (!should_have || replace_current) && !(oldorgan.zone in excluded_zones) && !(oldorgan.organ_flags & (ORGAN_UNREMOVABLE|ORGAN_SYNTHETIC)))
if(oldorgan && (!should_have || replace_current) && !(oldorgan.zone in excluded_zones) && (!(oldorgan.organ_flags & (ORGAN_UNREMOVABLE|ORGAN_SYNTHETIC)) || (oldorgan.organ_flags & ORGAN_SYNTHETIC_FROM_SPECIES))) // SKYRAT EDIT - Customization - ORIGINAL: if(oldorgan && (!should_have || replace_current) && !(oldorgan.zone in excluded_zones) && !(oldorgan.organ_flags & (ORGAN_UNREMOVABLE|ORGAN_SYNTHETIC)))
if(slot == ORGAN_SLOT_BRAIN)
var/obj/item/organ/internal/brain/brain = oldorgan
if(!brain.decoy_override)//"Just keep it if it's fake" - confucius, probably
@@ -25,7 +25,6 @@
mutantlungs = null
inherent_biotypes = MOB_HUMANOID|MOB_MINERAL
mutant_organs = list(/obj/item/organ/internal/adamantine_resonator)
mutanttongue = /obj/item/organ/internal/vocal_cords/adamantine
speedmod = 2
payday_modifier = 0.75
armor = 55
@@ -88,8 +87,7 @@
name = "Adamantine Golem"
id = SPECIES_GOLEM_ADAMANTINE
meat = /obj/item/food/meat/slab/human/mutant/golem/adamantine
mutant_organs = list(/obj/item/organ/internal/adamantine_resonator)
mutanttongue = /obj/item/organ/internal/vocal_cords/adamantine
mutant_organs = list(/obj/item/organ/internal/adamantine_resonator, /obj/item/organ/internal/vocal_cords/adamantine)
fixed_mut_color = "#44eedd"
info_text = "As an <span class='danger'>Adamantine Golem</span>, you possess special vocal cords allowing you to \"resonate\" messages to all golems. Your unique mineral makeup makes you immune to most types of magic."
prefix = "Adamantine"
+6 -3
View File
@@ -168,7 +168,7 @@
//Build the mob sprite and use it as our overlay
for(var/external_layer in bodypart_overlay.all_layers)
if(bodypart_overlay.layers & external_layer)
. += bodypart_overlay.get_overlay(external_layer, limb = null)
. += bodypart_overlay.get_overlay(external_layer, ownerlimb)
///The horns of a lizard!
/obj/item/organ/external/horns
@@ -366,8 +366,11 @@
if(draw_layer != bitflag_to_layer(color_swapped_layer))
return ..()
var/list/rgb_list = rgb2num(draw_color)
overlay.color = rgb(color_inverse_base - rgb_list[1], color_inverse_base - rgb_list[2], color_inverse_base - rgb_list[3]) //inversa da color
if(draw_color) // can someone explain to me why draw_color is allowed to EVER BE AN EMPTY STRING
var/list/rgb_list = rgb2num(draw_color)
overlay.color = rgb(color_inverse_base - rgb_list[1], color_inverse_base - rgb_list[2], color_inverse_base - rgb_list[3]) //inversa da color
else
overlay.color = null
/datum/bodypart_overlay/mutant/pod_hair/can_draw_on_bodypart(mob/living/carbon/human/human)
if((human.head?.flags_inv & HIDEHAIR) || (human.wear_mask?.flags_inv & HIDEHAIR))
+1
View File
@@ -156,6 +156,7 @@
#include "monkey_business.dm"
#include "mouse_bite_cable.dm"
#include "mutant_hands_consistency.dm"
#include "mutant_organs.dm"
#include "novaflower_burn.dm"
#include "ntnetwork_tests.dm"
#include "nuke_cinematic.dm"
+65
View File
@@ -0,0 +1,65 @@
/**
* Iterates over all species to ensure that organs are valid after being set to a mutant species
*/
/datum/unit_test/mutant_organs
/datum/unit_test/mutant_organs/Run()
var/mob/living/carbon/human/consistent/dummy = allocate(/mob/living/carbon/human/consistent)
var/list/ignore = list(
/datum/species/dullahan,
)
var/list/species = subtypesof(/datum/species) - ignore
var/static/list/organs_we_care_about = list(
ORGAN_SLOT_BRAIN,
ORGAN_SLOT_HEART,
ORGAN_SLOT_LUNGS,
ORGAN_SLOT_EYES,
ORGAN_SLOT_EARS,
ORGAN_SLOT_TONGUE,
ORGAN_SLOT_LIVER,
ORGAN_SLOT_STOMACH,
ORGAN_SLOT_APPENDIX,
)
for(var/datum/species/species_type as anything in species)
// change them to the species
dummy.set_species(species_type)
// check all their organs
for(var/organ_slot in organs_we_care_about)
var/expected_type = slot_to_species_organ_type(organ_slot, species_type)
var/obj/item/organ/actual_organ = dummy.getorganslot(organ_slot)
if(isnull(actual_organ))
if(!isnull(expected_type))
TEST_FAIL("[species_type] did not update their [organ_slot] organ to [expected_type], no organ was found")
continue
else
if(isnull(expected_type))
TEST_FAIL("[species_type] did not remove their [organ_slot] organ")
continue
if(actual_organ.type != expected_type)
TEST_FAIL("[species_type] did not update their [organ_slot] organ to [expected_type], instead it was [actual_organ.type]")
continue
/datum/unit_test/mutant_organs/proc/slot_to_species_organ_type(slot, datum/species/species)
switch(slot)
if(ORGAN_SLOT_BRAIN)
return initial(species.mutantbrain)
if(ORGAN_SLOT_HEART)
return initial(species.mutantheart)
if(ORGAN_SLOT_LUNGS)
return initial(species.mutantlungs)
if(ORGAN_SLOT_EYES)
return initial(species.mutanteyes)
if(ORGAN_SLOT_EARS)
return initial(species.mutantears)
if(ORGAN_SLOT_TONGUE)
return initial(species.mutanttongue)
if(ORGAN_SLOT_LIVER)
return initial(species.mutantliver)
if(ORGAN_SLOT_STOMACH)
return initial(species.mutantstomach)
if(ORGAN_SLOT_APPENDIX)
return initial(species.mutantappendix)
CRASH("Invalid organ slot [slot]") // just incase someone adds an organ we care about and forgets to add it here
@@ -17,12 +17,12 @@
cold_level_2_threshold = 0
cold_level_3_threshold = 0
status = ORGAN_ROBOTIC
organ_flags = ORGAN_SYNTHETIC
organ_flags = ORGAN_SYNTHETIC | ORGAN_SYNTHETIC_FROM_SPECIES
/obj/item/organ/internal/brain/vox
name = "vox brain"
status = ORGAN_ROBOTIC
organ_flags = ORGAN_SYNTHETIC
organ_flags = ORGAN_SYNTHETIC | ORGAN_SYNTHETIC_FROM_SPECIES
/obj/item/organ/internal/brain/vox/emp_act(severity)
. = ..()
@@ -8,7 +8,7 @@
slot = ORGAN_SLOT_BRAIN
zone = BODY_ZONE_CHEST
status = ORGAN_ROBOTIC
organ_flags = ORGAN_SYNTHETIC
organ_flags = ORGAN_SYNTHETIC | ORGAN_SYNTHETIC_FROM_SPECIES
desc = "A cube of shining metal, four inches to a side and covered in shallow grooves. It has an IPC serial number engraved on the top. It is usually slotted into the chest of synthetic crewmembers."
icon = 'modular_skyrat/master_files/icons/obj/surgery.dmi'
icon_state = "posibrain-ipc"
@@ -12,7 +12,7 @@
slot = ORGAN_SLOT_EARS
gender = PLURAL
status = ORGAN_ROBOTIC
organ_flags = ORGAN_SYNTHETIC
organ_flags = ORGAN_SYNTHETIC | ORGAN_SYNTHETIC_FROM_SPECIES
/obj/item/organ/internal/ears/synth/emp_act(severity)
. = ..()
@@ -3,7 +3,7 @@
icon_state = "cybernetic_eyeballs"
desc = "A very basic set of optical sensors with no extra vision modes or functions."
status = ORGAN_ROBOTIC
organ_flags = ORGAN_SYNTHETIC
organ_flags = ORGAN_SYNTHETIC | ORGAN_SYNTHETIC_FROM_SPECIES
/obj/item/organ/internal/eyes/synth/emp_act(severity)
. = ..()
@@ -1,7 +1,7 @@
/obj/item/organ/internal/heart/synth
name = "hydraulic pump engine"
desc = "An electronic device that handles the hydraulic pumps, powering one's robotic limbs. Without this, synthetics are unable to move."
organ_flags = ORGAN_SYNTHETIC
organ_flags = ORGAN_SYNTHETIC | ORGAN_SYNTHETIC_FROM_SPECIES
status = ORGAN_ROBOTIC
icon = 'modular_skyrat/master_files/icons/obj/surgery.dmi'
icon_state = "heart-ipc"
@@ -1,7 +1,7 @@
/obj/item/organ/internal/liver/synth
name = "reagent processing unit"
desc = "An electronic device that processes the beneficial chemicals for the synthetic user."
organ_flags = ORGAN_SYNTHETIC
organ_flags = ORGAN_SYNTHETIC | ORGAN_SYNTHETIC_FROM_SPECIES
status = ORGAN_ROBOTIC
icon = 'modular_skyrat/master_files/icons/obj/surgery.dmi'
icon_state = "liver-ipc"
@@ -15,7 +15,7 @@
safe_oxygen_min = 0 //What are you doing man, dont breathe with those!
safe_oxygen_max = 0
status = ORGAN_ROBOTIC
organ_flags = ORGAN_SYNTHETIC
organ_flags = ORGAN_SYNTHETIC | ORGAN_SYNTHETIC_FROM_SPECIES
/obj/item/organ/internal/lungs/synth/emp_act(severity)
. = ..()
@@ -10,7 +10,7 @@
slot = "stomach"
desc = "A specialised cell, for synthetic use only. Has a low-power mode. Without this, synthetics are unable to stay powered."
status = ORGAN_ROBOTIC
organ_flags = ORGAN_SYNTHETIC
organ_flags = ORGAN_SYNTHETIC | ORGAN_SYNTHETIC_FROM_SPECIES
/obj/item/organ/internal/stomach/synth/emp_act(severity)
. = ..()
@@ -8,7 +8,7 @@
modifies_speech = TRUE
taste_sensitivity = 25 // not as good as an organic tongue
maxHealth = 100 //RoboTongue!
organ_flags = ORGAN_SYNTHETIC
organ_flags = ORGAN_SYNTHETIC | ORGAN_SYNTHETIC_FROM_SPECIES
/obj/item/organ/internal/tongue/synth/handle_speech(datum/source, list/speech_args)
speech_args[SPEECH_SPANS] |= SPAN_ROBOT
@@ -51,6 +51,7 @@
mutantlungs = /obj/item/organ/internal/lungs/synth
mutantheart = /obj/item/organ/internal/heart/synth
mutantliver = /obj/item/organ/internal/liver/synth
mutantappendix = null
exotic_blood = /datum/reagent/fuel/oil
bodypart_overrides = list(
BODY_ZONE_HEAD = /obj/item/bodypart/head/robot/synth,
@@ -94,10 +95,6 @@
/datum/species/synthetic/on_species_gain(mob/living/carbon/human/transformer)
. = ..()
var/obj/item/organ/internal/appendix/appendix = transformer.getorganslot(ORGAN_SLOT_APPENDIX)
if(appendix)
appendix.Remove(transformer)
qdel(appendix)
var/screen_mutant_bodypart = transformer.dna.mutant_bodyparts[MUTANT_SYNTH_SCREEN]
var/obj/item/organ/internal/eyes/eyes = transformer.getorganslot(ORGAN_SLOT_EYES)