mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-23 21:18:37 +01:00
<!-- Write **BELOW** The Headers and **ABOVE** The comments else it may not be viewable. --> <!-- You can view Contributing.MD for a detailed description of the pull request process. --> closes #53931, #70916, #53931 ## About The Pull Request Organs were previously stored in nullspace. Now they are stored in their prospective bodyparts. Bodyparts are now stored in the mob. I've also had to refactor a lot of code concerning organ movement. Previously, organs were only moved into bodyparts once the bodyparts were removed. To accomodate this change, two major distinctions have been made: **Bodypart removal/insertion** Called only when an organ is taken out of a bodypart. Bodypart overlays, damage modifiers or other changes that should affect a bodypart itself goes here. **Mob insertion/removal** Called when an organ is removed from a mob. This can either be directly, by taking the organ out of a mob, or by removing the bodypart that contains the organ. This lets you add and remove organ effects safely without having to worry about the bodypart. Now that we controle the movement of bodyparts and organs, we can fuck around with them more. Summoning someones head or chest or heart will actually kill them now (and quite violently I must say (chest summoning gibs lol)). https://github.com/tgstation/tgstation/assets/7501474/5efc9dd3-cfd5-4ce4-b70f-d0d74894626e I´ve also added a unit test that violently tears apart and reconstructs a person in different ways to see if they get put toghether the right way This will definitely need a testmerge. I've done a lot of testing to make sure interactions work, but more niche stuff or my own incompetence can always slip through. ## Why It's Good For The Game <!-- Argue for the merits of your changes and how they benefit the game, especially if they are controversial and/or far reaching. If you can't actually explain WHY what you are doing will improve the game, then it probably isn't good for the game in the first place. --> A lot of organ work is quite restricted. You can't C4 someones heart, you cant summon their organs and a lot of exceptions have to be made to keep organs in nullspace. This lets organs (and bodyparts) play more nicely with the rest of the game. This also makes it a lot easier to move away from extorgans since a lot of their unique movement code has been removed and or generalized. I don't like making PRs of this size (I'm so sorry reviewers), but I was in a unique position to replace the entire system in a way I couldn't have done conveniently in multiple PRs ## Changelog <!-- If your PR modifies aspects of the game that can be concretely observed by players or admins you should add a changelog. If your change does NOT meet this description, remove this section. Be sure to properly mark your PRs to prevent unnecessary GBP loss. You can read up on GBP and it's effects on PRs in the tgstation guides for contributors. Please note that maintainers freely reserve the right to remove and add tags should they deem it appropriate. You can attempt to finagle the system all you want, but it's best to shoot for clear communication right off the bat. --> 🆑 refactor: Your organs are now inside your body. Please report any issues with bodypart and organ movement, including exotic organ, on github and scream at me fix: Cases of unexpected organ movement, such as teleporting bodyparts and organs with spells, now invokes a proper reaction (usually violent death) runtime: Fixes HARS runtiming on activation/deactivation fix: Fixes lag when species swapping /🆑 <!-- Both 🆑's are required for the changelog to work! You can put your name to the right of the first 🆑 if you want to overwrite your GitHub username as author ingame. --> <!-- You can use multiple of the same prefix (they're only used for the icon ingame) and delete the unneeded ones. Despite some of the tags, changelogs should generally represent how a player might be affected by the changes rather than a summary of the PR's contents. -->
126 lines
6.2 KiB
Plaintext
126 lines
6.2 KiB
Plaintext
/*
|
|
* This test checks that all heretic knowledges that unlocks rituals
|
|
* properly consume all used atoms and creates all resulting atoms.
|
|
*
|
|
* This test ONLY checks knowledges that unlock rituals which consume atoms and produce atoms.
|
|
* - Rituals that consume atoms, but do not create any atoms (such as rituals of knowledge) are not tested.
|
|
* - Summon rituals sleep after completing as they expect a ghost candidate to fill the summon, so they're skipped.
|
|
* - Final rituals results in a bunch of side-effects and vary a good deal so they're skipped explicitly.
|
|
* - Sacrifice ritual (Hunt and Sacrifice) requires sacrifice targets, as well as spawning a new z-level, so it's better not to test.
|
|
*/
|
|
/datum/unit_test/heretic_rituals
|
|
|
|
/datum/unit_test/heretic_rituals/Run()
|
|
|
|
// Gotta create ourselves a rune and a user to start.
|
|
var/obj/effect/heretic_rune/big/our_rune = allocate(/obj/effect/heretic_rune/big)
|
|
var/mob/living/carbon/human/our_heretic = allocate(/mob/living/carbon/human/consistent)
|
|
// -- Note for the human dummy we create:
|
|
// The user does not actually NEED a heretic antag datum for the type of rituals we're testing,
|
|
// so we don't give them one here. The heretic antag datum has side effects when applied,
|
|
// like creating influences and learning the default knowledge types, so better safe than sorry.
|
|
|
|
// Slap them down somewhere. The "heretic" should be in the middle of the rune, though this doesn't really matter.
|
|
our_rune.forceMove(run_loc_floor_bottom_left)
|
|
our_heretic.forceMove(locate((run_loc_floor_bottom_left.x + 1), (run_loc_floor_bottom_left.y + 1), run_loc_floor_bottom_left.z))
|
|
|
|
// Set up the blacklist for types we don't want to test here. See above for reasons.
|
|
var/list/blacklist_typecache = typecacheof(list(
|
|
/datum/heretic_knowledge/summon,
|
|
/datum/heretic_knowledge/ultimate,
|
|
/datum/heretic_knowledge/hunt_and_sacrifice,
|
|
))
|
|
var/list/all_ritual_knowledge = list()
|
|
|
|
// Now, let's instantiate our all_ritual_knowledge list with knowledge we're gonna test.
|
|
for(var/knowledge_type in typesof(/datum/heretic_knowledge))
|
|
|
|
// Skip blacklisted types
|
|
if(is_type_in_typecache(knowledge_type, blacklist_typecache))
|
|
continue
|
|
|
|
var/datum/heretic_knowledge/instantiated_knowledge = new knowledge_type()
|
|
// No required atoms = it's not a ritual, delete it and move on
|
|
// No resulting atoms = it's not a ritual we test here, delete it and move on
|
|
if(!LAZYLEN(instantiated_knowledge.required_atoms) || !LAZYLEN(instantiated_knowledge.result_atoms))
|
|
qdel(instantiated_knowledge)
|
|
continue
|
|
|
|
all_ritual_knowledge += instantiated_knowledge
|
|
|
|
// All the knowledge we want to test is instantiated, let's actually test their rituals now.
|
|
for(var/datum/heretic_knowledge/knowledge as anything in all_ritual_knowledge)
|
|
// Let's do a dry run of any special checks the knowledge may have
|
|
// without any atoms passed at all. This is to ensure that,
|
|
// if the ritual requires specific circumstances we can't setup in this test,
|
|
// such as freezing temperatures or humans that are augmented on completion,
|
|
// that we don't proceede to try to test them (as they'll fail anyways).
|
|
if(!knowledge.recipe_snowflake_check(our_heretic, list(), list(), get_turf(our_rune)))
|
|
continue
|
|
|
|
// Okay, so we've got a knowledge by this point we definitely want to test.
|
|
// Go though all the atoms it wants for it's ritual and create them on the rune.
|
|
var/list/created_atoms = list()
|
|
for(var/ritual_item_path in knowledge.required_atoms)
|
|
var/amount_to_create = knowledge.required_atoms[ritual_item_path]
|
|
if(islist(ritual_item_path))
|
|
ritual_item_path = pick(ritual_item_path)
|
|
for(var/i in 1 to amount_to_create)
|
|
var/obj/item/item = new ritual_item_path(get_turf(our_heretic))
|
|
if(isitem(item))
|
|
item.item_flags &= ~ABSTRACT
|
|
created_atoms += item
|
|
|
|
// Now, we can ACTUALLY run the ritual. Let's do it.
|
|
// Attempt to run the knowledge via the sacrifice rune.
|
|
// If do_ritual() returns FALSE with our knowledge, it messed up.
|
|
// If do_ritual() returns TRUE, then it was successful.
|
|
if(!our_rune.do_ritual(our_heretic, knowledge))
|
|
// We failed. The knowledge should have everything to succeed, yet it returned FALSE!
|
|
// Clean up the atoms it was meant to consume, so we can keep testing.
|
|
for(var/atom/leftover as anything in created_atoms)
|
|
created_atoms -= leftover
|
|
qdel(leftover)
|
|
|
|
// Aaand throw a fail.
|
|
TEST_FAIL("Heretic rituals: ([knowledge.type]) Despite having all required atoms present, the ritual failed to transmute.")
|
|
continue
|
|
|
|
// Making it here means the ritual was a success.
|
|
// Let's check all the atoms nearby to see if we got what we wanted.
|
|
var/list/atom/movable/nearby_atoms = range(1, our_heretic)
|
|
nearby_atoms -= our_heretic // Our dude is supposed to be there
|
|
nearby_atoms -= our_rune // Same with our rune
|
|
|
|
// Did we get all the results we want?
|
|
for(var/result_item_path in knowledge.result_atoms)
|
|
var/atom/result = locate(result_item_path) in nearby_atoms
|
|
// No, we couldn't find the a resulting atom on the rune. Throw a fail.
|
|
if(!result)
|
|
TEST_FAIL("Heretic rituals: ([knowledge.type]) Despite successfully completing the ritual, a resulting atom could not be found ([result_item_path])")
|
|
continue
|
|
|
|
// Yes, we got a resulting atom we expected! Remove it from the list and clean up.
|
|
nearby_atoms -= result
|
|
qdel(result)
|
|
|
|
// Finally, we checked all of our resulting atoms and cleaned them up.
|
|
// The nearby_atoms list should be devoid of any atom/movables now. Let's double-check that.
|
|
for(var/atom/thing as anything in nearby_atoms)
|
|
if(!ismovable(thing))
|
|
continue
|
|
if(isitem(thing))
|
|
var/obj/item/item = thing
|
|
if(item.item_flags & ABSTRACT) //bodyparts and stuff will get registered otherwise
|
|
continue
|
|
|
|
// There are atoms around the rune still, and there shouldn't be.
|
|
// All component atoms were consumed, and all resulting atoms were cleaned up.
|
|
// This means the ritual may have messed up somewhere. Throw a fail and clean them up so we can keep testing.
|
|
TEST_FAIL("Heretic rituals: ([knowledge.type]) After completing the ritual, there were non-result atoms remaining on the rune. ([thing] - [thing.type])")
|
|
nearby_atoms -= thing
|
|
qdel(thing)
|
|
|
|
// All done, clean up the knowledge list.
|
|
QDEL_LIST(all_ritual_knowledge)
|