 9b22458f44
			
		
	
	9b22458f44
	
	
	
		
			
			Focus of the Update: Compatibility with Stardew Valley 1.6 Released on March 19th 2024 This includes randomization for pretty much all of the new content, including but not limited to - Raccoon Bundles - Booksanity - Skill Masteries - New Recipes, Craftables, Fish, Maps, Farm Type, Festivals and Quests This also includes a significant reorganisation of the code into "Content Packs", to allow for easier modularity of various game mechanics between the settings and the supported mods. This improves maintainability quite a bit. In addition to that, a few **very** requested new features have been introduced, although they weren't the focus of this update - Walnutsanity - Player Buffs - More customizability in settings, such as shorter special orders, ER without farmhouse - New Remixed Bundles
		
			
				
	
	
		
			160 lines
		
	
	
		
			5.6 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			160 lines
		
	
	
		
			5.6 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| import unittest
 | |
| from collections import Counter
 | |
| from typing import ClassVar, Set
 | |
| 
 | |
| from . import SVTestBase
 | |
| from ..content.feature import friendsanity
 | |
| from ..options import Friendsanity, FriendsanityHeartSize
 | |
| 
 | |
| all_vanilla_bachelor = {
 | |
|     "Harvey", "Elliott", "Sam", "Alex", "Shane", "Sebastian", "Emily", "Haley", "Leah", "Abigail", "Penny", "Maru"
 | |
| }
 | |
| 
 | |
| all_vanilla_starting_npc = {
 | |
|     "Alex", "Elliott", "Harvey", "Sam", "Sebastian", "Shane", "Abigail", "Emily", "Haley", "Leah", "Maru", "Penny", "Caroline", "Clint", "Demetrius", "Evelyn",
 | |
|     "George", "Gus", "Jas", "Jodi", "Lewis", "Linus", "Marnie", "Pam", "Pierre", "Robin", "Vincent", "Willy", "Wizard", "Pet",
 | |
| }
 | |
| 
 | |
| all_vanilla_npc = {
 | |
|     "Alex", "Elliott", "Harvey", "Sam", "Sebastian", "Shane", "Abigail", "Emily", "Haley", "Leah", "Maru", "Penny", "Caroline", "Clint", "Demetrius", "Evelyn",
 | |
|     "George", "Gus", "Jas", "Jodi", "Lewis", "Linus", "Marnie", "Pam", "Pierre", "Robin", "Vincent", "Willy", "Wizard", "Pet", "Sandy", "Dwarf", "Kent", "Leo",
 | |
|     "Krobus"
 | |
| }
 | |
| 
 | |
| 
 | |
| class SVFriendsanityTestBase(SVTestBase):
 | |
|     expected_npcs: ClassVar[Set[str]] = set()
 | |
|     expected_pet_heart_size: ClassVar[Set[str]] = set()
 | |
|     expected_bachelor_heart_size: ClassVar[Set[str]] = set()
 | |
|     expected_other_heart_size: ClassVar[Set[str]] = set()
 | |
| 
 | |
|     @classmethod
 | |
|     def setUpClass(cls) -> None:
 | |
|         if cls is SVFriendsanityTestBase:
 | |
|             raise unittest.SkipTest("Base tests disabled")
 | |
| 
 | |
|         super().setUpClass()
 | |
| 
 | |
|     def test_friendsanity(self):
 | |
|         with self.subTest("Items are valid"):
 | |
|             self.check_all_items_match_expected_npcs()
 | |
|         with self.subTest("Correct number of items"):
 | |
|             self.check_correct_number_of_items()
 | |
|         with self.subTest("Locations are valid"):
 | |
|             self.check_all_locations_match_expected_npcs()
 | |
|         with self.subTest("Locations heart size are valid"):
 | |
|             self.check_all_locations_match_heart_size()
 | |
| 
 | |
|     def check_all_items_match_expected_npcs(self):
 | |
|         npc_names = {
 | |
|             name
 | |
|             for item in self.multiworld.itempool
 | |
|             if (name := friendsanity.extract_npc_from_item_name(item.name)) is not None
 | |
|         }
 | |
| 
 | |
|         self.assertEqual(npc_names, self.expected_npcs)
 | |
| 
 | |
|     def check_correct_number_of_items(self):
 | |
|         item_by_npc = Counter()
 | |
|         for item in self.multiworld.itempool:
 | |
|             name = friendsanity.extract_npc_from_item_name(item.name)
 | |
|             if name is None:
 | |
|                 continue
 | |
| 
 | |
|             item_by_npc[name] += 1
 | |
| 
 | |
|         for name, count in item_by_npc.items():
 | |
| 
 | |
|             if name == "Pet":
 | |
|                 self.assertEqual(count, len(self.expected_pet_heart_size))
 | |
|             elif self.world.content.villagers[name].bachelor:
 | |
|                 self.assertEqual(count, len(self.expected_bachelor_heart_size))
 | |
|             else:
 | |
|                 self.assertEqual(count, len(self.expected_other_heart_size))
 | |
| 
 | |
|     def check_all_locations_match_expected_npcs(self):
 | |
|         npc_names = {
 | |
|             name_and_heart[0]
 | |
|             for location_name in self.get_real_location_names()
 | |
|             if (name_and_heart := friendsanity.extract_npc_from_location_name(location_name))[0] is not None
 | |
|         }
 | |
| 
 | |
|         self.assertEqual(npc_names, self.expected_npcs)
 | |
| 
 | |
|     def check_all_locations_match_heart_size(self):
 | |
|         for location_name in self.get_real_location_names():
 | |
|             name, heart_size = friendsanity.extract_npc_from_location_name(location_name)
 | |
|             if name is None:
 | |
|                 continue
 | |
| 
 | |
|             if name == "Pet":
 | |
|                 self.assertIn(heart_size, self.expected_pet_heart_size)
 | |
|             elif self.world.content.villagers[name].bachelor:
 | |
|                 self.assertIn(heart_size, self.expected_bachelor_heart_size)
 | |
|             else:
 | |
|                 self.assertIn(heart_size, self.expected_other_heart_size)
 | |
| 
 | |
| 
 | |
| class TestFriendsanityNone(SVFriendsanityTestBase):
 | |
|     options = {
 | |
|         Friendsanity: Friendsanity.option_none,
 | |
|     }
 | |
| 
 | |
|     @property
 | |
|     def run_default_tests(self) -> bool:
 | |
|         # None is default
 | |
|         return False
 | |
| 
 | |
| 
 | |
| class TestFriendsanityBachelors(SVFriendsanityTestBase):
 | |
|     options = {
 | |
|         Friendsanity: Friendsanity.option_bachelors,
 | |
|         FriendsanityHeartSize: 1,
 | |
|     }
 | |
|     expected_npcs = all_vanilla_bachelor
 | |
|     expected_bachelor_heart_size = {1, 2, 3, 4, 5, 6, 7, 8}
 | |
| 
 | |
| 
 | |
| class TestFriendsanityStartingNpcs(SVFriendsanityTestBase):
 | |
|     options = {
 | |
|         Friendsanity: Friendsanity.option_starting_npcs,
 | |
|         FriendsanityHeartSize: 1,
 | |
|     }
 | |
|     expected_npcs = all_vanilla_starting_npc
 | |
|     expected_pet_heart_size = {1, 2, 3, 4, 5}
 | |
|     expected_bachelor_heart_size = {1, 2, 3, 4, 5, 6, 7, 8}
 | |
|     expected_other_heart_size = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
 | |
| 
 | |
| 
 | |
| class TestFriendsanityAllNpcs(SVFriendsanityTestBase):
 | |
|     options = {
 | |
|         Friendsanity: Friendsanity.option_all,
 | |
|         FriendsanityHeartSize: 4,
 | |
|     }
 | |
|     expected_npcs = all_vanilla_npc
 | |
|     expected_pet_heart_size = {4, 5}
 | |
|     expected_bachelor_heart_size = {4, 8}
 | |
|     expected_other_heart_size = {4, 8, 10}
 | |
| 
 | |
| 
 | |
| class TestFriendsanityHeartSize3(SVFriendsanityTestBase):
 | |
|     options = {
 | |
|         Friendsanity: Friendsanity.option_all_with_marriage,
 | |
|         FriendsanityHeartSize: 3,
 | |
|     }
 | |
|     expected_npcs = all_vanilla_npc
 | |
|     expected_pet_heart_size = {3, 5}
 | |
|     expected_bachelor_heart_size = {3, 6, 9, 12, 14}
 | |
|     expected_other_heart_size = {3, 6, 9, 10}
 | |
| 
 | |
| 
 | |
| class TestFriendsanityHeartSize5(SVFriendsanityTestBase):
 | |
|     options = {
 | |
|         Friendsanity: Friendsanity.option_all_with_marriage,
 | |
|         FriendsanityHeartSize: 5,
 | |
|     }
 | |
|     expected_npcs = all_vanilla_npc
 | |
|     expected_pet_heart_size = {5}
 | |
|     expected_bachelor_heart_size = {5, 10, 14}
 | |
|     expected_other_heart_size = {5, 10}
 |