mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2025-12-10 17:52:36 +00:00
## About The Pull Request
Hey there,
I've personally fallen for this stupid thing twice (in #77503 and #75627
(d3575161ca)), so I decided to spend a few
hours to crack out a unit test to ensure that I (and no one else) falls
for this stupid thing again.
Let me know if there's a smarter way to code something like this, but I
couldn't figure out a better way to accomodate the current framework and
be as agnostic to certain oddities as possible.
## Why It's Good For The Game
Catches stuff like this:
```txt
[2023-08-11 21:10:04.019] FAILURE #1: The mob Garden Gnome does not have ANY instances of TRAIT_SUBTREE_REQUIRED_ELEMENT, but has a planning subtree (/datum/ai_planning_subtree/target_retaliate) that requires it! at code/modules/unit_tests/ensure_subtree_element.dm:45
- FAILURE #2: The mob the morph does not have ANY instances of TRAIT_SUBTREE_REQUIRED_ELEMENT, but has a planning subtree (/datum/ai_planning_subtree/target_retaliate) that requires it! at code/modules/unit_tests/ensure_subtree_element.dm:45
- FAILURE #3: The mob the guard spiderling (946) does not have ANY instances of TRAIT_SUBTREE_REQUIRED_ELEMENT, but has a planning subtree (/datum/ai_planning_subtree/target_retaliate/to_flee) that requires it! at code/modules/unit_tests/ensure_subtree_element.dm:45
- FAILURE #4: The mob the ambush spiderling (255) does not have ANY instances of TRAIT_SUBTREE_REQUIRED_ELEMENT, but has a planning subtree (/datum/ai_planning_subtree/target_retaliate/to_flee) that requires it! at code/modules/unit_tests/ensure_subtree_element.dm:45
- FAILURE #5: The mob the scout spiderling (375) does not have ANY instances of TRAIT_SUBTREE_REQUIRED_ELEMENT, but has a planning subtree (/datum/ai_planning_subtree/target_retaliate/to_flee) that requires it! at code/modules/unit_tests/ensure_subtree_element.dm:45
- FAILURE #6: The mob the flesh spiderling (337) does not have ANY instances of TRAIT_SUBTREE_REQUIRED_ELEMENT, but has a planning subtree (/datum/ai_planning_subtree/target_retaliate/to_flee) that requires it! at code/modules/unit_tests/ensure_subtree_element.dm:45
- FAILURE #7: The mob the hunter spiderling (869) does not have ANY instances of TRAIT_SUBTREE_REQUIRED_ELEMENT, but has a planning subtree (/datum/ai_planning_subtree/target_retaliate/to_flee) that requires it! at code/modules/unit_tests/ensure_subtree_element.dm:45
- FAILURE #8: The mob the nurse spiderling (629) does not have ANY instances of TRAIT_SUBTREE_REQUIRED_ELEMENT, but has a planning subtree (/datum/ai_planning_subtree/target_retaliate/to_flee) that requires it! at code/modules/unit_tests/ensure_subtree_element.dm:45
- FAILURE #9: The mob the tangle spiderling (19) does not have ANY instances of TRAIT_SUBTREE_REQUIRED_ELEMENT, but has a planning subtree (/datum/ai_planning_subtree/target_retaliate/to_flee) that requires it! at code/modules/unit_tests/ensure_subtree_element.dm:45
- FAILURE #10: The mob the broodmother spiderling (855) does not have ANY instances of TRAIT_SUBTREE_REQUIRED_ELEMENT, but has a planning subtree (/datum/ai_planning_subtree/target_retaliate/to_flee) that requires it! at code/modules/unit_tests/ensure_subtree_element.dm:45
- FAILURE #11: The mob the viper spiderling (519) does not have ANY instances of TRAIT_SUBTREE_REQUIRED_ELEMENT, but has a planning subtree (/datum/ai_planning_subtree/target_retaliate/to_flee) that requires it! at code/modules/unit_tests/ensure_subtree_element.dm:45
- FAILURE #12: The mob the tarantula spiderling (963) does not have ANY instances of TRAIT_SUBTREE_REQUIRED_ELEMENT, but has a planning subtree (/datum/ai_planning_subtree/target_retaliate/to_flee) that requires it! at code/modules/unit_tests/ensure_subtree_element.dm:45
- FAILURE #13: The mob the spiderling (100) does not have ANY instances of TRAIT_SUBTREE_REQUIRED_ELEMENT, but has a planning subtree (/datum/ai_planning_subtree/target_retaliate/to_flee) that requires it! at code/modules/unit_tests/ensure_subtree_element.dm:45
```
(ignore the part about gnomes and morphs, this was an earlier version of
the unit test. everything else was relevant and is fixed)
## Changelog
🆑
fix: Growing spiders will now retaliate against you like they were
always meant to.
/🆑
65 lines
3.4 KiB
Plaintext
65 lines
3.4 KiB
Plaintext
/// The subtree that requires the operational datum.
|
|
#define REQUIRED_SUBTREE "required_subtree"
|
|
/// The list of typepaths of applicable operational datums that would satisfy the requirement.
|
|
#define REQUIRED_OPERATIONAL_DATUMS "required_operational_datums"
|
|
|
|
/// Unit Test that ensure that if we add a specific planning subtree to a basic mob's planning tree, that we also have the operational datum needed for it (component/element).
|
|
/// This can be extended to other "mandatory" operational datums for certain subtrees to work.
|
|
/datum/unit_test/ensure_subtree_operational_datum
|
|
/// Associated list of mobs that we need to test this on. Key is the typepath of the mob, value is a list of the planning subtree and the operational datums that are required for it.
|
|
var/list/testable_mobs = list()
|
|
|
|
/datum/unit_test/ensure_subtree_operational_datum/Run()
|
|
gather_testable_mobs()
|
|
test_applicable_mobs()
|
|
|
|
/// First, look for all mobs that have a planning subtree that requires an element, then add it to the list for stuff to test afterwards. Done like this to not have one mumbo proc that's hard to read.
|
|
/datum/unit_test/ensure_subtree_operational_datum/proc/gather_testable_mobs()
|
|
for(var/mob/living/basic/checkable_mob as anything in subtypesof(/mob/living/basic))
|
|
var/datum/ai_controller/testable_controller = initial(checkable_mob.ai_controller)
|
|
if(isnull(testable_controller))
|
|
continue
|
|
|
|
// we can't do inital() memes on lists so it's allocation time
|
|
testable_controller = allocate(testable_controller)
|
|
var/list/ai_planning_subtrees = testable_controller.planning_subtrees // list of instantiated datums. easy money
|
|
if(!length(ai_planning_subtrees))
|
|
continue
|
|
|
|
for(var/datum/ai_planning_subtree/testable_subtree as anything in ai_planning_subtrees)
|
|
var/list/necessary_datums = testable_subtree.operational_datums
|
|
if(isnull(necessary_datums))
|
|
continue
|
|
|
|
testable_mobs[checkable_mob] = list(
|
|
REQUIRED_OPERATIONAL_DATUMS = necessary_datums,
|
|
REQUIRED_SUBTREE = testable_subtree.type,
|
|
)
|
|
|
|
/// Then, test the mobs that we've found
|
|
/datum/unit_test/ensure_subtree_operational_datum/proc/test_applicable_mobs()
|
|
for(var/mob/living/basic/checkable_mob as anything in testable_mobs)
|
|
var/list/checkable_mob_data = testable_mobs[checkable_mob]
|
|
checkable_mob = allocate(checkable_mob)
|
|
|
|
var/datum/ai_planning_subtree/test_subtree = checkable_mob_data[REQUIRED_SUBTREE]
|
|
var/list/trait_sources = GET_TRAIT_SOURCES(checkable_mob, TRAIT_SUBTREE_REQUIRED_OPERATIONAL_DATUM)
|
|
if(!length(trait_sources)) // yes yes we could use `COUNT_TRAIT_SOURCES` but why invoke the same macro twice
|
|
TEST_FAIL("The mob [checkable_mob] ([checkable_mob.type]) does not have ANY instances of TRAIT_SUBTREE_REQUIRED_OPERATIONAL_DATUM, but has a planning subtree ([test_subtree]) that requires it!")
|
|
continue
|
|
|
|
var/has_element = FALSE
|
|
var/list/testable_operational_datums = checkable_mob_data[REQUIRED_OPERATIONAL_DATUMS]
|
|
for(var/iterable in trait_sources)
|
|
if(iterable in testable_operational_datums)
|
|
has_element = TRUE
|
|
break
|
|
|
|
if(!has_element)
|
|
var/list/message_list = list("The mob [checkable_mob] ([checkable_mob.type]) has a planning subtree ([test_subtree]) that requires a component/element, but does not have any!")
|
|
message_list += "Needs one of the following to satisfy the requirement: ([testable_operational_datums.Join(", ")])"
|
|
TEST_FAIL(message_list.Join(" "))
|
|
|
|
#undef REQUIRED_SUBTREE
|
|
#undef REQUIRED_OPERATIONAL_DATUMS
|