mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2025-12-21 15:14:17 +00:00
* Refactors and optimizes breath code (Saves 12% of carbon/Life()) * Update lungs.dm --------- Co-authored-by: LemonInTheDark <58055496+LemonInTheDark@users.noreply.github.com> Co-authored-by: Gandalf <9026500+Gandalf2k15@users.noreply.github.com>
203 lines
12 KiB
Plaintext
203 lines
12 KiB
Plaintext
#define TEST_CHECK_BREATH_MESSAGE(lungs_organ, message) "[lungs_organ.type]/check_breath() [message]"
|
|
#define TEST_ALERT_THROW_MESSAGE(lungs_organ, alert_name) TEST_CHECK_BREATH_MESSAGE(lungs_organ, "failed to throw alert [alert_name] when expected.")
|
|
#define TEST_ALERT_INHIBIT_MESSAGE(lungs_organ, alert_name) TEST_CHECK_BREATH_MESSAGE(lungs_organ, "threw alert [alert_name] when it wasn't expected.")
|
|
#define GET_MOLES(gas_mixture, gas_type) (gas_mixture.gases[gas_type] ? gas_mixture.gases[gas_type][MOLES] : 0)
|
|
|
|
/// Tests the standard, plasmaman, and lavaland lungs organ to ensure breathing and suffocation behave as expected.
|
|
/// Performs a check on each main (can be life-sustaining) gas, and ensures gas alerts are only thrown when expected.
|
|
/datum/unit_test/lungs
|
|
abstract_type = /datum/unit_test/lungs
|
|
|
|
/datum/unit_test/lungs/lungs_sanity/Run()
|
|
// "Standard" form of breathing.
|
|
// 2500 Litres of O2/N2 gas mix, ideal for life.
|
|
var/datum/gas_mixture/test_mix = create_standard_mix()
|
|
var/mob/living/carbon/human/lab_rat = allocate(/mob/living/carbon/human/consistent)
|
|
var/obj/item/organ/internal/lungs/test_lungs = allocate(/obj/item/organ/internal/lungs)
|
|
// Test one breath of O2/N2 mix.
|
|
lungs_test_check_breath("standard gas mixture", lab_rat, test_lungs, test_mix)
|
|
|
|
// Suffocation with an empty gas mix.
|
|
var/datum/gas_mixture/empty_test_mix = allocate(/datum/gas_mixture)
|
|
lab_rat = allocate(/mob/living/carbon/human/consistent)
|
|
test_lungs = allocate(/obj/item/organ/internal/lungs)
|
|
// Test one breath of nothing. Suffocate due to the breath being empty.
|
|
lungs_test_check_breath("empty gas mixture", lab_rat, test_lungs, empty_test_mix, expect_failure = TRUE)
|
|
|
|
// Suffocation with null. This does indeed happen normally.
|
|
lab_rat = allocate(/mob/living/carbon/human/consistent)
|
|
test_lungs = allocate(/obj/item/organ/internal/lungs)
|
|
// Test one breath of nothing. Suffocate due to the breath being null.
|
|
lungs_test_check_breath("null", lab_rat, test_lungs, null, expect_failure = TRUE)
|
|
|
|
// Suffocation with Nitrogen.
|
|
var/datum/gas_mixture/nitro_test_mix = create_nitrogen_mix()
|
|
lab_rat = allocate(/mob/living/carbon/human/consistent)
|
|
test_lungs = allocate(/obj/item/organ/internal/lungs)
|
|
// Test one breath of Nitrogen. Suffocate due to the breath being 100% N2.
|
|
lungs_test_check_breath("pure Nitrogen", lab_rat, test_lungs, nitro_test_mix, expect_failure = TRUE)
|
|
|
|
/// Tests the Plasmaman lungs organ to ensure Plasma breathing and suffocation behave as expected.
|
|
/datum/unit_test/lungs/lungs_sanity_plasmaman
|
|
|
|
/datum/unit_test/lungs/lungs_sanity_plasmaman/Run()
|
|
// 2500 Litres of pure Plasma.
|
|
var/datum/gas_mixture/plasma_test_mix = create_plasma_mix()
|
|
var/mob/living/carbon/human/lab_rat = allocate(/mob/living/carbon/human/consistent)
|
|
var/obj/item/organ/internal/lungs/plasmaman/test_lungs = allocate(/obj/item/organ/internal/lungs/plasmaman)
|
|
// Test one breath of Plasma on Plasmaman lungs.
|
|
lungs_test_check_breath("pure Plasma", lab_rat, test_lungs, plasma_test_mix)
|
|
|
|
// Tests suffocation with Nitrogen.
|
|
var/datum/gas_mixture/nitro_test_mix = create_nitrogen_mix()
|
|
lab_rat = allocate(/mob/living/carbon/human/consistent)
|
|
test_lungs = allocate(/obj/item/organ/internal/lungs/plasmaman)
|
|
// Test one breath of Nitrogen on Plasmaman lungs.
|
|
lungs_test_check_breath("pure Nitrogen", lab_rat, test_lungs, nitro_test_mix, expect_failure = TRUE)
|
|
|
|
/// Tests the lavaland/Ashwalker lungs organ.
|
|
/// Ensures they can breathe from the lavaland air mixture properly, and suffocate on inadequate mixture.
|
|
/datum/unit_test/lungs/lungs_sanity_ashwalker
|
|
|
|
/datum/unit_test/lungs/lungs_sanity_ashwalker/Run()
|
|
// Gas mix resembling one cell of lavaland's atmosphere.
|
|
var/datum/gas_mixture/lavaland_test_mix = create_lavaland_mix()
|
|
var/obj/item/organ/internal/lungs/lavaland/test_lungs = allocate(/obj/item/organ/internal/lungs/lavaland)
|
|
var/mob/living/carbon/human/lab_rat = allocate(/mob/living/carbon/human/consistent)
|
|
// Test one breath of Lavaland gas mix on Ashwalker lungs.
|
|
lungs_test_check_breath("Lavaland air mixture", lab_rat, test_lungs, lavaland_test_mix)
|
|
|
|
/// Comprehensive unit test for [/obj/item/organ/internal/lungs/proc/check_breath()]
|
|
/// If "expect_failure" is set to TRUE, the test ensures the given Human suffocated.
|
|
/// A "test_name" string is required to contextualize test logs. Describe the gas you're testing.
|
|
/datum/unit_test/lungs/proc/lungs_test_check_breath(test_name, mob/living/carbon/human/lab_rat, obj/item/organ/internal/lungs/test_lungs, datum/gas_mixture/test_mix, expect_failure = FALSE)
|
|
// Setup a small volume of gas which represents one "breath" from test_mix.
|
|
var/datum/gas_mixture/test_breath
|
|
|
|
if(!isnull(test_mix))
|
|
var/total_moles = test_mix.total_moles()
|
|
if(total_moles > 0)
|
|
test_breath = test_mix.remove(total_moles * BREATH_PERCENTAGE)
|
|
|
|
if(isnull(test_breath))
|
|
test_breath = allocate(/datum/gas_mixture, BREATH_VOLUME)
|
|
|
|
// Backup of the breath mixture, to compare against after testing check_breath().
|
|
var/datum/gas_mixture/test_breath_backup = test_breath.copy()
|
|
|
|
// Get partial pressures for each "main" gas.
|
|
var/oxygen_pp = 0
|
|
var/nitro_pp = 0
|
|
var/co2_pp = 0
|
|
var/plasma_pp = 0
|
|
if(test_breath.total_moles() > 0)
|
|
oxygen_pp = test_breath.get_breath_partial_pressure(GET_MOLES(test_breath, /datum/gas/oxygen))
|
|
nitro_pp = test_breath.get_breath_partial_pressure(GET_MOLES(test_breath, /datum/gas/nitrogen))
|
|
co2_pp = test_breath.get_breath_partial_pressure(GET_MOLES(test_breath, /datum/gas/carbon_dioxide))
|
|
plasma_pp = test_breath.get_breath_partial_pressure(GET_MOLES(test_breath, /datum/gas/plasma))
|
|
|
|
// Minimum and maximum gas tolerances for the 4 main life-sustaining gases.
|
|
var/min_oxygen = test_lungs.safe_oxygen_min
|
|
var/min_nitro = test_lungs.safe_nitro_min
|
|
var/min_plasma = test_lungs.safe_plasma_min
|
|
var/max_oxygen = test_lungs.safe_oxygen_max
|
|
var/max_co2 = test_lungs.safe_co2_max
|
|
var/max_plasma = test_lungs.safe_plasma_max
|
|
|
|
// Test a single "breath" of air.
|
|
var/status_code = test_lungs.check_breath(test_breath, lab_rat)
|
|
|
|
// Ensures failed_last_breath is set as we expect, and that check_breath returns a corollary status code.
|
|
if(expect_failure)
|
|
TEST_ASSERT(!status_code, TEST_CHECK_BREATH_MESSAGE(test_lungs, "returned truthy / status code 1 (success) when it wasn't expected."))
|
|
TEST_ASSERT(lab_rat.failed_last_breath, TEST_CHECK_BREATH_MESSAGE(test_lungs, "should suffocate from [test_name]."))
|
|
else
|
|
TEST_ASSERT(status_code, TEST_CHECK_BREATH_MESSAGE(test_lungs, "returned falsy / status code 0 (failure) when it wasn't expected."))
|
|
TEST_ASSERT(!lab_rat.failed_last_breath, TEST_CHECK_BREATH_MESSAGE(test_lungs, "can't get a full breath from [test_name]."))
|
|
|
|
// Checks each "main" gas to ensure gas alerts are thrown/inhibited when expected.
|
|
lungs_test_alert_min(lab_rat, test_lungs, ALERT_NOT_ENOUGH_OXYGEN, min_oxygen, oxygen_pp)
|
|
lungs_test_alert_max(lab_rat, test_lungs, ALERT_TOO_MUCH_OXYGEN, max_oxygen, oxygen_pp)
|
|
|
|
lungs_test_alert_min(lab_rat, test_lungs, ALERT_NOT_ENOUGH_NITRO, min_nitro, nitro_pp)
|
|
|
|
lungs_test_alert_max(lab_rat, test_lungs, ALERT_TOO_MUCH_CO2, max_co2, co2_pp)
|
|
|
|
lungs_test_alert_min(lab_rat, test_lungs, ALERT_NOT_ENOUGH_PLASMA, min_plasma, plasma_pp)
|
|
lungs_test_alert_max(lab_rat, test_lungs, ALERT_TOO_MUCH_PLASMA, max_plasma, plasma_pp)
|
|
|
|
// Track the volumes of O2 and CO2 which are expected to be exhaled.
|
|
var/expected_oxygen = GET_MOLES(test_breath_backup, /datum/gas/oxygen)
|
|
var/expected_nitro = GET_MOLES(test_breath_backup, /datum/gas/nitrogen)
|
|
var/expected_co2 = GET_MOLES(test_breath_backup, /datum/gas/carbon_dioxide)
|
|
var/expected_plasma = GET_MOLES(test_breath_backup, /datum/gas/plasma)
|
|
|
|
// Setup expectations for main gas exchange tests.
|
|
if(min_oxygen)
|
|
expected_co2 += expected_oxygen
|
|
expected_oxygen = 0
|
|
if(min_nitro)
|
|
expected_co2 += GET_MOLES(test_breath_backup, /datum/gas/nitrogen)
|
|
expected_nitro = 0
|
|
if(min_plasma)
|
|
expected_co2 += GET_MOLES(test_breath_backup, /datum/gas/plasma)
|
|
expected_plasma = 0
|
|
|
|
// Validate conversion of inhaled gas to exhaled gas.
|
|
if(min_oxygen)
|
|
TEST_ASSERT(molar_cmp_equals(GET_MOLES(test_breath, /datum/gas/oxygen), expected_oxygen), TEST_CHECK_BREATH_MESSAGE(test_lungs, "should consume all Oxygen initially present in the breath."))
|
|
TEST_ASSERT(molar_cmp_equals(GET_MOLES(test_breath, /datum/gas/carbon_dioxide), expected_co2), TEST_CHECK_BREATH_MESSAGE(test_lungs, "should convert Oxygen into an equivalent volume of CO2."))
|
|
if(min_nitro)
|
|
TEST_ASSERT(molar_cmp_equals(GET_MOLES(test_breath, /datum/gas/nitrogen), expected_nitro), TEST_CHECK_BREATH_MESSAGE(test_lungs, "should consume all Nitrogen initially present in the breath."))
|
|
TEST_ASSERT(molar_cmp_equals(GET_MOLES(test_breath, /datum/gas/carbon_dioxide), expected_co2), TEST_CHECK_BREATH_MESSAGE(test_lungs, "should convert Nitrogen into an equivalent volume of CO2."))
|
|
if(min_plasma)
|
|
TEST_ASSERT(molar_cmp_equals(GET_MOLES(test_breath, /datum/gas/plasma), expected_plasma), TEST_CHECK_BREATH_MESSAGE(test_lungs, "should consume all Plasma initially present in the breath."))
|
|
TEST_ASSERT(molar_cmp_equals(GET_MOLES(test_breath, /datum/gas/carbon_dioxide), expected_co2), TEST_CHECK_BREATH_MESSAGE(test_lungs, "should convert Plasma into an equivalent volume of CO2."))
|
|
|
|
/// Tests minimum gas alerts by comparing gas pressure.
|
|
/datum/unit_test/lungs/proc/lungs_test_alert_min(mob/living/carbon/human/lab_rat, obj/item/organ/internal/lungs/test_lungs, alert_name, min_pressure, pressure)
|
|
var/alert_thrown = lab_rat.has_alert(alert_name)
|
|
var/pressure_safe = (pressure >= min_pressure) || (min_pressure == 0)
|
|
TEST_ASSERT(!pressure_safe && alert_thrown || pressure_safe, TEST_ALERT_THROW_MESSAGE(test_lungs, alert_name))
|
|
TEST_ASSERT(pressure_safe && !alert_thrown || !pressure_safe, TEST_ALERT_INHIBIT_MESSAGE(test_lungs, alert_name))
|
|
|
|
/// Tests maximum gas alerts by comparing gas pressure.
|
|
/datum/unit_test/lungs/proc/lungs_test_alert_max(mob/living/carbon/human/lab_rat, obj/item/organ/internal/lungs/test_lungs, alert_name, max_pressure, pressure)
|
|
var/alert_thrown = lab_rat.has_alert(alert_name)
|
|
var/pressure_safe = (pressure <= max_pressure) || (max_pressure == 0)
|
|
TEST_ASSERT(!pressure_safe && alert_thrown || pressure_safe, TEST_ALERT_THROW_MESSAGE(test_lungs, alert_name))
|
|
TEST_ASSERT(pressure_safe && !alert_thrown || !pressure_safe, TEST_ALERT_INHIBIT_MESSAGE(test_lungs, alert_name))
|
|
|
|
/// Set up a 2500-Litre gas mixture with the given gases and percentages.
|
|
/datum/unit_test/lungs/proc/create_gas_mix(list/gas_to_percent)
|
|
var/datum/gas_mixture/test_mix = allocate(/datum/gas_mixture, 2500)
|
|
test_mix.temperature = T20C
|
|
for(var/datum/gas/gas_type as anything in gas_to_percent)
|
|
test_mix.add_gas(gas_type)
|
|
test_mix.gases[gas_type][MOLES] = (ONE_ATMOSPHERE * 2500 / (R_IDEAL_GAS_EQUATION * T20C) * gas_to_percent[gas_type])
|
|
return test_mix
|
|
|
|
/// Set up an O2/N2 gas mix which is "ideal" for organic life.
|
|
/datum/unit_test/lungs/proc/create_standard_mix()
|
|
return create_gas_mix(list(/datum/gas/oxygen = O2STANDARD, /datum/gas/nitrogen = N2STANDARD))
|
|
|
|
/// Set up a pure Nitrogen gas mix.
|
|
/datum/unit_test/lungs/proc/create_nitrogen_mix()
|
|
return create_gas_mix(list(/datum/gas/nitrogen = 1))
|
|
|
|
/// Set up an O2/N2 gas mix which is "ideal" for plasmamen.
|
|
/datum/unit_test/lungs/proc/create_plasma_mix()
|
|
return create_gas_mix(list(/datum/gas/plasma = 1))
|
|
|
|
/// Set up an Lavaland gas mix which is "ideal" for Ashwalker life.
|
|
/datum/unit_test/lungs/proc/create_lavaland_mix()
|
|
var/datum/gas_mixture/immutable/planetary/lavaland_mix = SSair.planetary[LAVALAND_DEFAULT_ATMOS]
|
|
var/datum/gas_mixture/test_mix = allocate(/datum/gas_mixture, 2500)
|
|
test_mix.copy_from(lavaland_mix)
|
|
return test_mix
|
|
|
|
#undef TEST_CHECK_BREATH_MESSAGE
|
|
#undef TEST_ALERT_THROW_MESSAGE
|
|
#undef TEST_ALERT_INHIBIT_MESSAGE
|
|
#undef GET_MOLES
|