Nearsighted severity sources (with unit test) + status_effect/grouped minor rework (#88591)

# About The Pull Request
## Nearsighted Sources
Nearsighted now associates/tracks severity applied by each source.
Previously, nearsighted only used a single variable which had to be
shared by every source, which caused problems for things like scarred
eyes which needed independent behaviour.

This implementation allows sources with different severity levels to
coexist without needing workarounds

There are now two different severity types for nearsightedness:
* Correctable: Can be mitigated with vision correction (like glasses)
* Absolute: Cannot be mitigated from any source, used for scarred eyes

Which can allow nearsighted sources to not be affected by vision
correction.
Also, since there is no more technical conflict between the two quirks,
I've made it so that nearsighted and scarred eye can be selected
together (as a QOL change)

There is also a new unit test for this new behaviour
(nearsighted_effect) that checks application and removal
## status_effect/grouped minor rework
Grouped status effects now have `source_added()` and `source_removed()`
procs, which are called whenever a source is added or removed from the
effect

I did this because the previous implementation was somewhat unwieldy. 
Inherited status effects would recieve the _currently existing_ effect
through merge_with_existing, and require them to modify the existing
effect's properties, which is odd and not intuitive to work with (the
proc's `src` was not the existing effect)
It not being called for every source also made users repeat code in
`on_creation()` and `merge_with_existing()` for every source added.

This new interface should prevent repetition and be generally more
intuitive to work with.

# Changelog

🆑
refactor: Nearsighted has been reworked to track severity applied from
each source, as well as allow "non-correctable" nearsightedness (for
things like scarred eyes).
qol: The above being possible now means that you can select the
Nearsighted and Scarred eye quirks together
fix: Any bug that would occur from becoming nearsighted with a scarred
eye should be fixed now
code: status_effect/grouped merging code has been improved (i hope)
/🆑
This commit is contained in:
tonty
2025-01-15 08:29:38 -05:00
committed by GitHub
parent d808702d47
commit e755854af2
9 changed files with 297 additions and 104 deletions

View File

@@ -73,9 +73,18 @@
/// Is the mob blind from the passed source or sources? /// Is the mob blind from the passed source or sources?
#define is_blind_from(sources) has_status_effect_from_source(/datum/status_effect/grouped/blindness, sources) #define is_blind_from(sources) has_status_effect_from_source(/datum/status_effect/grouped/blindness, sources)
/// Causes the mob to become nearsighted via the passed source /// We are not nearsighted right now.
#define NEARSIGHTED_DISABLED 0
/// Something is correcting our vision, but we are still a bit nearsighted.
#define NEARSIGHTED_CORRECTED 1
/// We are fully nearsighted.
#define NEARSIGHTED_ENABLED 2
/// Simplified macro that causes the mob to become nearsighted (with correction possible) via the passed source.
#define become_nearsighted(source) apply_status_effect(/datum/status_effect/grouped/nearsighted, source) #define become_nearsighted(source) apply_status_effect(/datum/status_effect/grouped/nearsighted, source)
/// Cures the mob's nearsightedness from the passed source, removing nearsighted wholesale if no sources are left /// Causes the mob to become nearsighted from the passed source by a severity, which may be corrected with glasses.
#define assign_nearsightedness(source, amount, correctable) apply_status_effect(/datum/status_effect/grouped/nearsighted, source, amount, correctable)
/// Cures the mob's nearsightedness from the passed source, removing nearsighted wholesale if no sources are left.
#define cure_nearsighted(source) remove_status_effect(/datum/status_effect/grouped/nearsighted, source) #define cure_nearsighted(source) remove_status_effect(/datum/status_effect/grouped/nearsighted, source)
/// Is the mob nearsighted? /// Is the mob nearsighted?
@@ -89,7 +98,7 @@
var/datum/status_effect/grouped/nearsighted/nearsight = has_status_effect(/datum/status_effect/grouped/nearsighted) var/datum/status_effect/grouped/nearsighted/nearsight = has_status_effect(/datum/status_effect/grouped/nearsighted)
if(isnull(nearsight)) if(isnull(nearsight))
return FALSE return FALSE
return nearsight.should_be_nearsighted() return (nearsight.should_be_nearsighted() > NEARSIGHTED_CORRECTED)
// Status effect application helpers. // Status effect application helpers.
// These are macros for easier use of adjust_timed_status_effect and set_timed_status_effect. // These are macros for easier use of adjust_timed_status_effect and set_timed_status_effect.

View File

@@ -4,7 +4,8 @@
// Shifted to glob so they are generated at world start instead of risking players doing preference stuff before the subsystem inits // Shifted to glob so they are generated at world start instead of risking players doing preference stuff before the subsystem inits
GLOBAL_LIST_INIT_TYPED(quirk_blacklist, /list/datum/quirk, list( GLOBAL_LIST_INIT_TYPED(quirk_blacklist, /list/datum/quirk, list(
list(/datum/quirk/item_quirk/blindness, /datum/quirk/item_quirk/nearsighted, /datum/quirk/item_quirk/scarred_eye), list(/datum/quirk/item_quirk/blindness, /datum/quirk/item_quirk/nearsighted),
list(/datum/quirk/item_quirk/blindness, /datum/quirk/item_quirk/scarred_eye),
list(/datum/quirk/item_quirk/blindness, /datum/quirk/item_quirk/fluoride_stare), list(/datum/quirk/item_quirk/blindness, /datum/quirk/item_quirk/fluoride_stare),
list(/datum/quirk/item_quirk/blindness, /datum/quirk/touchy), list(/datum/quirk/item_quirk/blindness, /datum/quirk/touchy),
list(/datum/quirk/jolly, /datum/quirk/depression, /datum/quirk/apathetic, /datum/quirk/hypersensitive), list(/datum/quirk/jolly, /datum/quirk/depression, /datum/quirk/apathetic, /datum/quirk/hypersensitive),

View File

@@ -12,15 +12,9 @@
/datum/status_effect/grouped/hooked/proc/still_exists() /datum/status_effect/grouped/hooked/proc/still_exists()
return !QDELETED(src) return !QDELETED(src)
/datum/status_effect/grouped/hooked/on_creation(mob/living/new_owner, datum/beam/fishing_line/source) /datum/status_effect/grouped/hooked/source_added(datum/beam/fishing_line/source)
. = ..()
if(!.) //merged with an existing effect
return
RegisterSignal(source, COMSIG_QDELETING, PROC_REF(on_fishing_line_deleted)) RegisterSignal(source, COMSIG_QDELETING, PROC_REF(on_fishing_line_deleted))
/datum/status_effect/grouped/hooked/merge_with_existing(datum/status_effect/grouped/hooked/existing, datum/beam/fishing_line/source)
existing.RegisterSignal(source, COMSIG_QDELETING, PROC_REF(on_fishing_line_deleted))
/datum/status_effect/grouped/hooked/proc/on_fishing_line_deleted(datum/source) /datum/status_effect/grouped/hooked/proc/on_fishing_line_deleted(datum/source)
SIGNAL_HANDLER SIGNAL_HANDLER
owner.remove_status_effect(type, source) owner.remove_status_effect(type, source)

View File

@@ -2,69 +2,6 @@
/// There are no reason why these cannot be blinded, it is simply for "design reasons" (these things shouldn't be blinded) /// There are no reason why these cannot be blinded, it is simply for "design reasons" (these things shouldn't be blinded)
#define CAN_BE_BLIND(mob) (!isanimal_or_basicmob(mob) && !isbrain(mob) && !isrevenant(mob)) #define CAN_BE_BLIND(mob) (!isanimal_or_basicmob(mob) && !isbrain(mob) && !isrevenant(mob))
/// Nearsighted
/datum/status_effect/grouped/nearsighted
id = "nearsighted"
tick_interval = STATUS_EFFECT_NO_TICK
alert_type = null
// This is not "remove on fullheal" as in practice,
// fullheal should instead remove all the sources and in turn cure this
/// Static list of signals that, when received, we force an update to our nearsighted overlay
var/static/list/update_signals = list(
SIGNAL_ADDTRAIT(TRAIT_NEARSIGHTED_CORRECTED),
SIGNAL_REMOVETRAIT(TRAIT_NEARSIGHTED_CORRECTED),
SIGNAL_ADDTRAIT(TRAIT_SIGHT_BYPASS),
SIGNAL_REMOVETRAIT(TRAIT_SIGHT_BYPASS),
)
/// How severe is our nearsightedness right now
var/overlay_severity = 2
/datum/status_effect/grouped/nearsighted/on_apply()
RegisterSignals(owner, update_signals, PROC_REF(update_nearsightedness))
update_nearsighted_overlay()
return ..()
/datum/status_effect/grouped/nearsighted/on_remove()
UnregisterSignal(owner, update_signals)
owner.clear_fullscreen(id)
return ..()
/// Signal proc for when we gain or lose [TRAIT_NEARSIGHTED_CORRECTED] - (temporarily) disable the overlay if we're correcting it
/datum/status_effect/grouped/nearsighted/proc/update_nearsightedness(datum/source)
SIGNAL_HANDLER
update_nearsighted_overlay()
/// Checks if we should be nearsighted currently, or if we should clear the overlay
/datum/status_effect/grouped/nearsighted/proc/should_be_nearsighted()
if (ishuman(owner))
var/mob/living/carbon/human/human_owner = owner
if (human_owner.get_eye_scars())
return TRUE
if(HAS_TRAIT(owner, TRAIT_NEARSIGHTED_CORRECTED))
return FALSE
if(HAS_TRAIT(owner, TRAIT_SIGHT_BYPASS))
return FALSE
return TRUE
/// Updates our nearsightd overlay, either removing it if we have the trait or adding it if we don't
/datum/status_effect/grouped/nearsighted/proc/update_nearsighted_overlay()
if(should_be_nearsighted())
owner.overlay_fullscreen(id, /atom/movable/screen/fullscreen/impaired, overlay_severity)
else
owner.clear_fullscreen(id)
/// Sets the severity of our nearsighted overlay
/datum/status_effect/grouped/nearsighted/proc/set_nearsighted_severity(to_value)
if(!isnum(to_value))
return
if(overlay_severity == to_value)
return
overlay_severity = to_value
update_nearsighted_overlay()
/// Blindness /// Blindness
/datum/status_effect/grouped/blindness /datum/status_effect/grouped/blindness
id = "blindness" id = "blindness"

View File

@@ -0,0 +1,131 @@
/// Maximum severity level possible.
#define MAX_SEVERITY 3
/// Nearsighted
/datum/status_effect/grouped/nearsighted
id = "nearsighted"
tick_interval = STATUS_EFFECT_NO_TICK
alert_type = null
// This is not "remove on fullheal" as in practice,
// fullheal should instead remove all the sources and in turn cure this
/// Static list of signals that, when received, we force an update to our nearsighted overlay
var/static/list/update_signals = list(
SIGNAL_ADDTRAIT(TRAIT_NEARSIGHTED_CORRECTED),
SIGNAL_REMOVETRAIT(TRAIT_NEARSIGHTED_CORRECTED),
SIGNAL_ADDTRAIT(TRAIT_SIGHT_BYPASS),
SIGNAL_REMOVETRAIT(TRAIT_SIGHT_BYPASS),
)
/* ("source_id" = num) */
/// Associated list of sources with their supplied severity level. Cannot be corrected with glasses.
var/absolute_sources = list()
/// Associated list of sources with their supplied severity level. Can be corrected with glasses.
var/correctable_sources = list()
/// Highest severity value in [var/absolute_sources].
var/absolute_severity = 0
/// Highest severity value in [var/correctable_sources].
var/correctable_severity = 0
/datum/status_effect/grouped/nearsighted/source_added(source, severity = 2, correctable = TRUE)
set_severity(source, severity, correctable)
/datum/status_effect/grouped/nearsighted/source_removed(source, removing)
if(correctable_sources[source])
correctable_sources -= source
recalculate_severity(correctable=TRUE)
if(absolute_sources[source])
absolute_sources -= source
recalculate_severity(correctable=FALSE)
if(!removing) //so the overlay doesn't update twice
update_nearsighted_overlay()
/datum/status_effect/grouped/nearsighted/on_apply()
RegisterSignals(owner, update_signals, PROC_REF(update_nearsightedness))
update_nearsighted_overlay()
return ..()
/datum/status_effect/grouped/nearsighted/on_remove()
UnregisterSignal(owner, update_signals)
owner.clear_fullscreen(id)
return ..()
/// Signal proc for when we gain or lose [TRAIT_NEARSIGHTED_CORRECTED] - (temporarily) disable the overlay if we're correcting it
/datum/status_effect/grouped/nearsighted/proc/update_nearsightedness(datum/source)
SIGNAL_HANDLER
update_nearsighted_overlay()
/// Checks if we should be nearsighted currently, or if we should clear the overlay
/datum/status_effect/grouped/nearsighted/proc/should_be_nearsighted()
if(HAS_TRAIT(owner, TRAIT_SIGHT_BYPASS))
return NEARSIGHTED_DISABLED
if(HAS_TRAIT(owner, TRAIT_NEARSIGHTED_CORRECTED))
return NEARSIGHTED_CORRECTED
return NEARSIGHTED_ENABLED
/// Updates our nearsightd overlay, either removing it if we have the trait or adding it if we don't
/datum/status_effect/grouped/nearsighted/proc/update_nearsighted_overlay()
var/severity = get_severity()
if(severity <= 0) // We aren't nearsighted
owner.clear_fullscreen(id)
else
owner.overlay_fullscreen(id, /atom/movable/screen/fullscreen/impaired, severity)
/// Gets the severity value that would be used when calculating impairment.
/datum/status_effect/grouped/nearsighted/proc/get_severity()
var/are_we_nearsighted = should_be_nearsighted()
if(!are_we_nearsighted)
return 0
var/final_severity = absolute_severity
if(are_we_nearsighted != NEARSIGHTED_CORRECTED) //We don't have corrective vision
final_severity = max(absolute_severity, correctable_severity)
final_severity = min(final_severity, MAX_SEVERITY)
return final_severity
/// Sets the severity of a source. Recalculates the severity variables if there is a change
/datum/status_effect/grouped/nearsighted/proc/set_severity(source, new_severity, correctable = FALSE)
if(!source)
return
if(!isnum(new_severity))
return
var/list/to_search = correctable ? correctable_sources : absolute_sources
if(to_search[source] == new_severity)
return
if(new_severity > 0)
to_search[source] = new_severity
else
to_search -= source
recalculate_severity(correctable)
/* If we have no more of this source, let's remove it (and potentially ourselves) */
if(!absolute_sources[source] && !correctable_sources[source])
owner.remove_status_effect(type, source) //this will update our overlay as well if we're still around
else
update_nearsighted_overlay()
/datum/status_effect/grouped/nearsighted/proc/recalculate_severity(correctable)
if(isnull(correctable))
CRASH("was not provided with an argument (this needs to be explicit)")
var/highest_severity = 0
var/list/to_search = correctable ? correctable_sources : absolute_sources
for(var/existing_source in to_search)
var/candidate = to_search[existing_source]
if(candidate > highest_severity)
highest_severity = candidate
if(correctable)
correctable_severity = highest_severity
else
absolute_severity = highest_severity
#undef MAX_SEVERITY

View File

@@ -7,20 +7,41 @@
/// A list of all sources applying this status effect. Sources are a list of keys /// A list of all sources applying this status effect. Sources are a list of keys
var/list/sources = list() var/list/sources = list()
/datum/status_effect/grouped/on_creation(mob/living/new_owner, source) /datum/status_effect/grouped/on_creation(mob/living/new_owner, source, ...)
//Get our supplied arguments, without new_owner
var/list/new_source_args = args.Copy(2)
var/datum/status_effect/grouped/existing = new_owner.has_status_effect(type) var/datum/status_effect/grouped/existing = new_owner.has_status_effect(type)
if(existing) if(existing)
existing.sources |= source existing.sources |= source
merge_with_existing(existing, source) existing.source_added(arglist(new_source_args))
qdel(src) qdel(src)
return FALSE return FALSE
sources |= source /* We are the original */
return ..()
/datum/status_effect/grouped/proc/merge_with_existing(datum/status_effect/grouped/existing, source) . = ..()
if(.)
sources |= source
source_added(arglist(new_source_args))
/**
* Called after a source is added to the status effect,
* this includes the first source added after creation.
*/
/datum/status_effect/grouped/proc/source_added(source, ...)
return
/**
* Called after a source is removed from the status effect. \
* `removing` will be TRUE if this is the last source, which means
* the effect will be deleted.
*/
/datum/status_effect/grouped/proc/source_removed(source, removing)
return return
/datum/status_effect/grouped/before_remove(source) /datum/status_effect/grouped/before_remove(source)
sources -= source sources -= source
return !length(sources) var/was_last_source = !length(sources)
source_removed(source, was_last_source)
return was_last_source

View File

@@ -313,18 +313,14 @@
apply_scarring_effects() apply_scarring_effects()
/obj/item/organ/eyes/proc/apply_scarring_effects() /obj/item/organ/eyes/proc/apply_scarring_effects()
if (!owner) if(!owner)
return return
var/datum/status_effect/grouped/nearsighted/nearsightedness = owner.is_nearsighted()
// Even if eyes have enough health, our owner still becomes nearsighted // Even if eyes have enough health, our owner still becomes nearsighted
if (scarring & RIGHT_EYE_SCAR) if(scarring & RIGHT_EYE_SCAR)
owner.become_nearsighted(TRAIT_RIGHT_EYE_SCAR) owner.assign_nearsightedness(TRAIT_RIGHT_EYE_SCAR, 1, FALSE)
if (scarring & LEFT_EYE_SCAR) if(scarring & LEFT_EYE_SCAR)
owner.become_nearsighted(TRAIT_LEFT_EYE_SCAR) owner.assign_nearsightedness(TRAIT_LEFT_EYE_SCAR, 1, FALSE)
if (isnull(nearsightedness)) // We aren't nearsighted from any other source if((scarring & RIGHT_EYE_SCAR) && (scarring & LEFT_EYE_SCAR))
nearsightedness = owner.is_nearsighted()
nearsightedness.set_nearsighted_severity(1)
if ((scarring & RIGHT_EYE_SCAR) && (scarring & LEFT_EYE_SCAR))
owner.become_blind(EYE_SCARRING_TRAIT) owner.become_blind(EYE_SCARRING_TRAIT)
owner.update_body() owner.update_body()
@@ -370,10 +366,6 @@
damaged = FALSE damaged = FALSE
// clear nearsightedness from damage // clear nearsightedness from damage
owner.cure_nearsighted(EYE_DAMAGE) owner.cure_nearsighted(EYE_DAMAGE)
// if we're still nearsighted, reset its severity
// this is kinda icky, ideally we'd track severity to source but that's way more complex
var/datum/status_effect/grouped/nearsighted/nearsightedness = owner.is_nearsighted()
nearsightedness?.set_nearsighted_severity(1)
// and cure blindness from damage // and cure blindness from damage
owner.cure_blind(EYE_DAMAGE) owner.cure_blind(EYE_DAMAGE)
return return
@@ -388,10 +380,8 @@
else else
// become nearsighted from damage // become nearsighted from damage
owner.become_nearsighted(EYE_DAMAGE) var/severity = damage > high_threshold ? 3 : 2
// update the severity of our nearsightedness based on our eye damage owner.assign_nearsightedness(EYE_DAMAGE, severity, TRUE)
var/datum/status_effect/grouped/nearsighted/nearsightedness = owner.is_nearsighted()
nearsightedness.set_nearsighted_severity(damage > high_threshold ? 3 : 2)
damaged = TRUE damaged = TRUE

View File

@@ -63,11 +63,11 @@
TEST_ASSERT(!HAS_SCREEN_OVERLAY(dummy, /atom/movable/screen/fullscreen/blind), "Dummy, [status_message], still had the blind sceen overlay.") TEST_ASSERT(!HAS_SCREEN_OVERLAY(dummy, /atom/movable/screen/fullscreen/blind), "Dummy, [status_message], still had the blind sceen overlay.")
/** /**
* Unit test to check that nearsighted is added and disabled correctly * Unit test to check that the nearsighted quirk is added and disabled correctly
*/ */
/datum/unit_test/nearsightedness /datum/unit_test/nearsighted_quirk
/datum/unit_test/nearsightedness/Run() /datum/unit_test/nearsighted_quirk/Run()
var/mob/living/carbon/human/dummy = allocate(/mob/living/carbon/human/consistent) var/mob/living/carbon/human/dummy = allocate(/mob/living/carbon/human/consistent)
var/obj/item/clothing/glasses/regular/glasses = allocate(/obj/item/clothing/glasses/regular) var/obj/item/clothing/glasses/regular/glasses = allocate(/obj/item/clothing/glasses/regular)
@@ -125,7 +125,7 @@
TEST_ASSERT(dummy.is_nearsighted(), "After sustaining minor eye damage ([minor_damage]), the dummy was not nearsighted.") TEST_ASSERT(dummy.is_nearsighted(), "After sustaining minor eye damage ([minor_damage]), the dummy was not nearsighted.")
// Check that the severity is correct // Check that the severity is correct
nearsightedness = dummy.is_nearsighted() nearsightedness = dummy.is_nearsighted()
TEST_ASSERT_EQUAL(nearsightedness.overlay_severity, 2, "After taking minor eye damage, the dummy's nearsightedness was the incorrect severity.") TEST_ASSERT_EQUAL(nearsightedness.get_severity(), 2, "After taking minor eye damage, the dummy's nearsightedness was the incorrect severity.")
nearsightedness = null nearsightedness = null
// Heal eye damage // Heal eye damage
eyes.set_organ_damage(0) eyes.set_organ_damage(0)
@@ -137,11 +137,120 @@
TEST_ASSERT(dummy.is_nearsighted(), "After sustaining major eye damage ([major_damage]), the dummy was not nearsighted.") TEST_ASSERT(dummy.is_nearsighted(), "After sustaining major eye damage ([major_damage]), the dummy was not nearsighted.")
// Check that the severity is correct // Check that the severity is correct
nearsightedness = dummy.is_nearsighted() nearsightedness = dummy.is_nearsighted()
TEST_ASSERT_EQUAL(nearsightedness.overlay_severity, 3, "After taking major eye damage, the dummy's nearsightedness was the incorrect severity.") TEST_ASSERT_EQUAL(nearsightedness.get_severity(), 3, "After taking major eye damage, the dummy's nearsightedness was the incorrect severity.")
nearsightedness = null nearsightedness = null
// Heal eye damage // Heal eye damage
eyes.set_organ_damage(0) eyes.set_organ_damage(0)
TEST_ASSERT(!dummy.is_nearsighted(), "After curing eye damage, the dummy was still nearsighted.") TEST_ASSERT(!dummy.is_nearsighted(), "After curing eye damage, the dummy was still nearsighted.")
#define CORRECTABLE_SOURCE "\[CORRECTABLE SOURCE\]"
#define ABSOLUTE_SOURCE "\[ABSOLUTE SOURCE\]"
/datum/unit_test/nearsighted_effect
/*!
* This tests [/datum/status_effect/grouped/nearsighted]
* * Application (correctable/absolute)
* * Removal (absolute/correctable)
*/
/datum/unit_test/nearsighted_effect/Run()
var/mob/living/carbon/human/dummy = allocate(/mob/living/carbon/human/consistent)
var/datum/status_effect/grouped/nearsighted/myopia
/* APPLICATION */
// Let's test regular nearsightedness first
dummy.assign_nearsightedness(CORRECTABLE_SOURCE, 2, TRUE)
validate_correctable_severity(dummy, "after being given [CORRECTABLE_SOURCE]", 2, list(
CORRECTABLE_SOURCE = 2,
))
myopia = dummy.is_nearsighted()
TEST_ASSERT_EQUAL(myopia.get_severity(), 2, "Final severity amount was incorrect when checked with only correctable nearsightedness.")
// We'll test if the glasses work as expected...
validate_glasses_behaviour(dummy, "after being given [CORRECTABLE_SOURCE]", 0, 2)
// Let's apply an absolute source, we'll test two things at once
dummy.assign_nearsightedness(ABSOLUTE_SOURCE, 1, FALSE)
validate_absolute_severity(dummy, "after being given [ABSOLUTE_SOURCE]", 1, list(
ABSOLUTE_SOURCE = 1,
))
myopia = dummy.is_nearsighted()
TEST_ASSERT_EQUAL(myopia.get_severity(), 2, "Final severity amount wasn't equal to [CORRECTABLE_SOURCE] when a smaller absolute source was present.")
// Do the glasses still work after adding an absolute source?
validate_glasses_behaviour(dummy, "after being given [ABSOLUTE_SOURCE]", 1, 2)
/* REMOVAL */
//There are two different ways a source can be removed, let's test both of them
dummy.cure_nearsighted(ABSOLUTE_SOURCE)
validate_absolute_severity(dummy, "after removing [ABSOLUTE_SOURCE]", 0, list())
myopia = dummy.is_nearsighted()
TEST_ASSERT_NOTNULL(myopia, "Dummy lost nearsightedness after removing [CORRECTABLE_SOURCE] even though there were still sources left.")
//After this, the effect should be removed.
dummy.assign_nearsightedness(CORRECTABLE_SOURCE, 0, TRUE)
TEST_ASSERT(!dummy.is_nearsighted(), "Dummy was still nearsighted after all sources were removed.")
/datum/unit_test/nearsighted_effect/proc/validate_source_contents(checking, status, list/current_sources, list/expected_sources)
TEST_ASSERT_EQUAL(length(current_sources), length(expected_sources), "[checking] had a different amount of contents than expected [status].")
//We'll copy the list to make sure we got all the sources
var/list/hopefully_empty_result = expected_sources.Copy()
for(var/expected_source in expected_sources)
var/expected_severity = expected_sources[expected_source]
TEST_ASSERT_NOTNULL(current_sources[expected_source], "[expected_source] wasn't in [checking] [status].")
TEST_ASSERT_EQUAL(current_sources[expected_source], expected_severity, "The severity for [expected_source] in [checking] [status] wasn't as expected.")
hopefully_empty_result -= expected_source
TEST_ASSERT(!length(hopefully_empty_result), "[checking] has all the sources we wanted [status], but there were unexpected extra sources.")
/datum/unit_test/nearsighted_effect/proc/validate_correctable_severity(mob/living/carbon/human/dummy, status, expected_final_severity, list/expected_sources)
//! This proc expects the dummy to be nearsighted
var/datum/status_effect/grouped/nearsighted/myopia = dummy.is_nearsighted()
TEST_ASSERT_NOTNULL(myopia, "Dummy was not nearsighted when given correctable nearsightedness [status].")
validate_source_contents("correctable sources", status, myopia.correctable_sources, expected_sources)
TEST_ASSERT_EQUAL(myopia.correctable_severity, expected_final_severity, "The determined correctable severity [status] was wrong.")
/datum/unit_test/nearsighted_effect/proc/validate_absolute_severity(mob/living/carbon/human/dummy, status, expected_final_severity, list/expected_sources)
//! This proc expects the dummy to be nearsighted
var/datum/status_effect/grouped/nearsighted/myopia = dummy.is_nearsighted()
TEST_ASSERT_NOTNULL(myopia, "Dummy was not nearsighted when given absolute nearsightedness [status].")
validate_source_contents("absolute sources", status, myopia.absolute_sources, expected_sources)
TEST_ASSERT_EQUAL(myopia.absolute_severity, expected_final_severity, "The determined absolute severity [status] was wrong.")
/// Makes sure that having vision corrected affects the dummy and preserves vision
/datum/unit_test/nearsighted_effect/proc/validate_glasses_behaviour(mob/living/carbon/human/dummy, status, expected_severity_with, expected_severity_without)
//! This proc expects the dummy to be nearsighted
var/obj/item/clothing/glasses/regular/prescriptions = allocate(/obj/item/clothing/glasses/regular)
dummy.equip_to_slot_if_possible(prescriptions, ITEM_SLOT_EYES)
var/datum/status_effect/grouped/nearsighted/myopia = dummy.is_nearsighted()
TEST_ASSERT_NOTNULL(myopia, "Dummy no longer had the nearsighted status after putting on glasses. They should still be nearsighted.")
TEST_ASSERT(!dummy.is_nearsighted_currently(), "Dummy was nearsighted currently [status] even though they were wearing glasses.")
TEST_ASSERT_EQUAL(myopia.get_severity(), expected_severity_with, "get_severity() returned an impossible severity amount when putting on glasses [status].")
// Check their overlay, they might need to lose it
if(expected_severity_with == 0)
TEST_ASSERT(!HAS_SCREEN_OVERLAY(dummy, /atom/movable/screen/fullscreen/impaired), "Dummy still had the nearsighted overlay when putting glasses on [status].")
else
TEST_ASSERT(HAS_SCREEN_OVERLAY(dummy, /atom/movable/screen/fullscreen/impaired), "Dummy lost the nearsighted overlay when putting glasses on [status].")
// Now take them off
QDEL_NULL(prescriptions)
TEST_ASSERT(dummy.is_nearsighted_currently(), "Dummy didn't become nearsighted currently [status] even though they weren't wearing glasses.")
TEST_ASSERT_EQUAL(myopia.get_severity(), expected_severity_without, "get_severity() returned an impossible severity amount when taking off glasses [status].")
// Check their overlay again, they may or may not should still have it
if(expected_severity_without != 0)
TEST_ASSERT(HAS_SCREEN_OVERLAY(dummy, /atom/movable/screen/fullscreen/impaired), "Dummy had the nearsighted overlay when putting glasses on [status].")
else //If the bottom condition is hit, what are we even doing man
TEST_ASSERT(!HAS_SCREEN_OVERLAY(dummy, /atom/movable/screen/fullscreen/impaired),
"Dummy had the nearsighted overlay when putting glasses on [status].")
#undef CORRECTABLE_SOURCE
#undef ABSOLUTE_SOURCE
#undef HAS_SCREEN_OVERLAY #undef HAS_SCREEN_OVERLAY
#undef HAS_CLIENT_COLOR #undef HAS_CLIENT_COLOR

View File

@@ -1914,7 +1914,6 @@
#include "code\datums\status_effects\buffs\food\grant_trait.dm" #include "code\datums\status_effects\buffs\food\grant_trait.dm"
#include "code\datums\status_effects\buffs\food\haste.dm" #include "code\datums\status_effects\buffs\food\haste.dm"
#include "code\datums\status_effects\buffs\food\speech.dm" #include "code\datums\status_effects\buffs\food\speech.dm"
#include "code\datums\status_effects\debuffs\blindness.dm"
#include "code\datums\status_effects\debuffs\choke.dm" #include "code\datums\status_effects\debuffs\choke.dm"
#include "code\datums\status_effects\debuffs\confusion.dm" #include "code\datums\status_effects\debuffs\confusion.dm"
#include "code\datums\status_effects\debuffs\cursed.dm" #include "code\datums\status_effects\debuffs\cursed.dm"
@@ -1949,6 +1948,8 @@
#include "code\datums\status_effects\debuffs\slime\slime_food.dm" #include "code\datums\status_effects\debuffs\slime\slime_food.dm"
#include "code\datums\status_effects\debuffs\slime\slime_leech.dm" #include "code\datums\status_effects\debuffs\slime\slime_leech.dm"
#include "code\datums\status_effects\debuffs\slime\slimed.dm" #include "code\datums\status_effects\debuffs\slime\slimed.dm"
#include "code\datums\status_effects\debuffs\vision\blindness.dm"
#include "code\datums\status_effects\debuffs\vision\nearsighted.dm"
#include "code\datums\storage\storage.dm" #include "code\datums\storage\storage.dm"
#include "code\datums\storage\storage_interface.dm" #include "code\datums\storage\storage_interface.dm"
#include "code\datums\storage\subtypes\backpack.dm" #include "code\datums\storage\subtypes\backpack.dm"