Stardew Valley: 4.x.x - The Ginger Update (#1931)
## What is this fixing or adding? Major content update for Stardew Valley ## How was this tested? One large-scale public Beta on the archipelago server, plus several smaller private asyncs and test runs You can go to https://github.com/agilbert1412/StardewArchipelago/releases to grab the mod (latest 4.x.x version), the supported mods and the apworld, to test this PR ## New Features: - Festival Checks [Easy mode or Hard Mode] - Special Orders [Both Board and Qi] - Willy's Boat - Ginger Island Parrots - TV Channels - Trap Items [Available in various difficulty levels] - Entrance Randomizer: Buildings and Chaos - New Fishsanity options: Exclude Legendaries, Exclude Hard fish, Only easy fish - Resource Pack overhaul [Resource packs are now more enjoyable and varied] - Goal: Greatest Walnut Hunter [Find every single Golden Walnut] - Goal: Perfection [Achieve Perfection] - Option: Profit Margin [Multiplier over all earnings] - Option: Friendsanity Heart Size [Reduce clutter from friendsanity hearts] - Option: Exclude Ginger Island - will exclude many locations and items to generate a playthrough that does not go to the island - Mod Support [Curated list of mods] ## New Contributors: @Witchybun for the mod support --------- Co-authored-by: Witchybun <embenham05@gmail.com> Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com> Co-authored-by: Fabian Dill <Berserker66@users.noreply.github.com>
This commit is contained in:
@@ -1,30 +1,119 @@
|
||||
from BaseClasses import ItemClassification
|
||||
from . import SVTestBase
|
||||
from BaseClasses import ItemClassification, MultiWorld
|
||||
from . import setup_solo_multiworld, SVTestBase
|
||||
from .. import locations, items, location_table, options
|
||||
from ..data.villagers_data import all_villagers_by_name
|
||||
from ..data.villagers_data import all_villagers_by_name, all_villagers_by_mod_by_name
|
||||
from ..items import items_by_group, Group
|
||||
from ..locations import LocationTags
|
||||
from ..mods.mod_data import ModNames
|
||||
|
||||
|
||||
def get_real_locations(tester: SVTestBase, multiworld: MultiWorld):
|
||||
return [location for location in multiworld.get_locations(tester.player) if not location.event]
|
||||
|
||||
|
||||
def get_real_location_names(tester: SVTestBase, multiworld: MultiWorld):
|
||||
return [location.name for location in multiworld.get_locations(tester.player) if not location.event]
|
||||
|
||||
|
||||
class TestBaseItemGeneration(SVTestBase):
|
||||
options = {
|
||||
options.Friendsanity.internal_name: options.Friendsanity.option_all_with_marriage,
|
||||
options.SeasonRandomization.internal_name: options.SeasonRandomization.option_progressive,
|
||||
options.SpecialOrderLocations.internal_name: options.SpecialOrderLocations.option_board_qi,
|
||||
}
|
||||
|
||||
def test_all_progression_items_are_added_to_the_pool(self):
|
||||
for classification in [ItemClassification.progression, ItemClassification.useful]:
|
||||
with self.subTest(classification=classification):
|
||||
|
||||
all_classified_items = {self.world.create_item(item)
|
||||
for item in items.items_by_group[items.Group.COMMUNITY_REWARD]
|
||||
if item.classification is classification}
|
||||
|
||||
for item in all_classified_items:
|
||||
self.assertIn(item, self.multiworld.itempool)
|
||||
all_created_items = [item.name for item in self.multiworld.itempool]
|
||||
# Ignore all the stuff that the algorithm chooses one of, instead of all, to fulfill logical progression
|
||||
items_to_ignore = [event.name for event in items.events]
|
||||
items_to_ignore.extend(item.name for item in items.all_items if item.mod_name is not None)
|
||||
items_to_ignore.extend(season.name for season in items.items_by_group[Group.SEASON])
|
||||
items_to_ignore.extend(weapon.name for weapon in items.items_by_group[Group.WEAPON])
|
||||
items_to_ignore.extend(footwear.name for footwear in items.items_by_group[Group.FOOTWEAR])
|
||||
items_to_ignore.extend(baby.name for baby in items.items_by_group[Group.BABY])
|
||||
items_to_ignore.extend(resource_pack.name for resource_pack in items.items_by_group[Group.RESOURCE_PACK])
|
||||
progression_items = [item for item in items.all_items if item.classification is ItemClassification.progression
|
||||
and item.name not in items_to_ignore]
|
||||
for progression_item in progression_items:
|
||||
with self.subTest(f"{progression_item.name}"):
|
||||
self.assertIn(progression_item.name, all_created_items)
|
||||
|
||||
def test_creates_as_many_item_as_non_event_locations(self):
|
||||
non_event_locations = [location for location in self.multiworld.get_locations(self.player) if
|
||||
non_event_locations = [location for location in get_real_locations(self, self.multiworld) if
|
||||
not location.event]
|
||||
|
||||
self.assertEqual(len(non_event_locations), len(self.multiworld.itempool))
|
||||
|
||||
def test_does_not_create_deprecated_items(self):
|
||||
all_created_items = [item.name for item in self.multiworld.itempool]
|
||||
for deprecated_item in items.items_by_group[items.Group.DEPRECATED]:
|
||||
with self.subTest(f"{deprecated_item.name}"):
|
||||
self.assertNotIn(deprecated_item.name, all_created_items)
|
||||
|
||||
def test_does_not_create_more_than_one_maximum_one_items(self):
|
||||
all_created_items = [item.name for item in self.multiworld.itempool]
|
||||
for maximum_one_item in items.items_by_group[items.Group.MAXIMUM_ONE]:
|
||||
with self.subTest(f"{maximum_one_item.name}"):
|
||||
self.assertLessEqual(all_created_items.count(maximum_one_item.name), 1)
|
||||
|
||||
def test_does_not_create_exactly_two_items(self):
|
||||
all_created_items = [item.name for item in self.multiworld.itempool]
|
||||
for exactly_two_item in items.items_by_group[items.Group.EXACTLY_TWO]:
|
||||
with self.subTest(f"{exactly_two_item.name}"):
|
||||
count = all_created_items.count(exactly_two_item.name)
|
||||
self.assertTrue(count == 0 or count == 2)
|
||||
|
||||
|
||||
class TestNoGingerIslandItemGeneration(SVTestBase):
|
||||
options = {
|
||||
options.Friendsanity.internal_name: options.Friendsanity.option_all_with_marriage,
|
||||
options.SeasonRandomization.internal_name: options.SeasonRandomization.option_progressive,
|
||||
options.ExcludeGingerIsland.internal_name: options.ExcludeGingerIsland.option_true
|
||||
}
|
||||
|
||||
def test_all_progression_items_except_island_are_added_to_the_pool(self):
|
||||
all_created_items = [item.name for item in self.multiworld.itempool]
|
||||
# Ignore all the stuff that the algorithm chooses one of, instead of all, to fulfill logical progression
|
||||
items_to_ignore = [event.name for event in items.events]
|
||||
items_to_ignore.extend(item.name for item in items.all_items if item.mod_name is not None)
|
||||
items_to_ignore.extend(season.name for season in items.items_by_group[Group.SEASON])
|
||||
items_to_ignore.extend(season.name for season in items.items_by_group[Group.WEAPON])
|
||||
items_to_ignore.extend(season.name for season in items.items_by_group[Group.FOOTWEAR])
|
||||
items_to_ignore.extend(baby.name for baby in items.items_by_group[Group.BABY])
|
||||
progression_items = [item for item in items.all_items if item.classification is ItemClassification.progression
|
||||
and item.name not in items_to_ignore]
|
||||
for progression_item in progression_items:
|
||||
with self.subTest(f"{progression_item.name}"):
|
||||
if Group.GINGER_ISLAND in progression_item.groups:
|
||||
self.assertNotIn(progression_item.name, all_created_items)
|
||||
else:
|
||||
self.assertIn(progression_item.name, all_created_items)
|
||||
|
||||
def test_creates_as_many_item_as_non_event_locations(self):
|
||||
non_event_locations = [location for location in get_real_locations(self, self.multiworld) if
|
||||
not location.event]
|
||||
|
||||
self.assertEqual(len(non_event_locations), len(self.multiworld.itempool))
|
||||
|
||||
def test_does_not_create_deprecated_items(self):
|
||||
all_created_items = [item.name for item in self.multiworld.itempool]
|
||||
for deprecated_item in items.items_by_group[items.Group.DEPRECATED]:
|
||||
with self.subTest(f"Deprecated item: {deprecated_item.name}"):
|
||||
self.assertNotIn(deprecated_item.name, all_created_items)
|
||||
|
||||
def test_does_not_create_more_than_one_maximum_one_items(self):
|
||||
all_created_items = [item.name for item in self.multiworld.itempool]
|
||||
for maximum_one_item in items.items_by_group[items.Group.MAXIMUM_ONE]:
|
||||
with self.subTest(f"{maximum_one_item.name}"):
|
||||
self.assertLessEqual(all_created_items.count(maximum_one_item.name), 1)
|
||||
|
||||
def test_does_not_create_exactly_two_items(self):
|
||||
all_created_items = [item.name for item in self.multiworld.itempool]
|
||||
for exactly_two_item in items.items_by_group[items.Group.EXACTLY_TWO]:
|
||||
with self.subTest(f"{exactly_two_item.name}"):
|
||||
count = all_created_items.count(exactly_two_item.name)
|
||||
self.assertTrue(count == 0 or count == 2)
|
||||
|
||||
|
||||
class TestGivenProgressiveBackpack(SVTestBase):
|
||||
options = {options.BackpackProgression.internal_name: options.BackpackProgression.option_progressive}
|
||||
@@ -35,7 +124,8 @@ class TestGivenProgressiveBackpack(SVTestBase):
|
||||
def test_when_generate_world_then_backpack_locations_are_added(self):
|
||||
created_locations = {location.name for location in self.multiworld.get_locations(1)}
|
||||
backpacks_exist = [location.name in created_locations
|
||||
for location in locations.locations_by_tag[LocationTags.BACKPACK]]
|
||||
for location in locations.locations_by_tag[LocationTags.BACKPACK]
|
||||
if location.name != "Premium Pack"]
|
||||
all_exist = all(backpacks_exist)
|
||||
self.assertTrue(all_exist)
|
||||
|
||||
@@ -72,7 +162,7 @@ class TestRemixedMineRewards(SVTestBase):
|
||||
|
||||
class TestProgressiveElevator(SVTestBase):
|
||||
options = {
|
||||
options.TheMinesElevatorsProgression.internal_name: options.TheMinesElevatorsProgression.option_progressive,
|
||||
options.ElevatorProgression.internal_name: options.ElevatorProgression.option_progressive,
|
||||
options.ToolProgression.internal_name: options.ToolProgression.option_progressive,
|
||||
options.SkillProgression.internal_name: options.SkillProgression.option_progressive,
|
||||
}
|
||||
@@ -110,30 +200,44 @@ class TestProgressiveElevator(SVTestBase):
|
||||
class TestLocationGeneration(SVTestBase):
|
||||
|
||||
def test_all_location_created_are_in_location_table(self):
|
||||
for location in self.multiworld.get_locations(self.player):
|
||||
for location in get_real_locations(self, self.multiworld):
|
||||
if not location.event:
|
||||
self.assertIn(location.name, location_table)
|
||||
|
||||
|
||||
class TestLocationAndItemCount(SVTestBase):
|
||||
options = {
|
||||
options.SeasonRandomization.internal_name: options.SeasonRandomization.option_randomized,
|
||||
options.SeedShuffle.internal_name: options.SeedShuffle.option_shuffled,
|
||||
options.BackpackProgression.internal_name: options.BackpackProgression.option_vanilla,
|
||||
options.ToolProgression.internal_name: options.ToolProgression.option_vanilla,
|
||||
options.SkillProgression.internal_name: options.SkillProgression.option_vanilla,
|
||||
options.BuildingProgression.internal_name: options.BuildingProgression.option_vanilla,
|
||||
options.TheMinesElevatorsProgression.internal_name: options.TheMinesElevatorsProgression.option_vanilla,
|
||||
options.ArcadeMachineLocations.internal_name: options.ArcadeMachineLocations.option_disabled,
|
||||
options.HelpWantedLocations.internal_name: 0,
|
||||
options.Fishsanity.internal_name: options.Fishsanity.option_none,
|
||||
options.Museumsanity.internal_name: options.Museumsanity.option_none,
|
||||
options.Friendsanity.internal_name: options.Museumsanity.option_none,
|
||||
options.NumberOfPlayerBuffs.internal_name: 12,
|
||||
}
|
||||
|
||||
def test_minimal_location_maximal_items_still_valid(self):
|
||||
self.assertGreaterEqual(len(self.multiworld.get_locations()), len(self.multiworld.get_items()))
|
||||
min_max_options = self.minimal_locations_maximal_items()
|
||||
multiworld = setup_solo_multiworld(min_max_options)
|
||||
valid_locations = get_real_locations(self, multiworld)
|
||||
self.assertGreaterEqual(len(valid_locations), len(multiworld.itempool))
|
||||
|
||||
def test_allsanity_without_mods_has_at_least_locations(self):
|
||||
expected_locations = 993
|
||||
allsanity_options = self.allsanity_options_without_mods()
|
||||
multiworld = setup_solo_multiworld(allsanity_options)
|
||||
number_locations = len(get_real_locations(self, multiworld))
|
||||
self.assertGreaterEqual(number_locations, expected_locations)
|
||||
print(f"Stardew Valley - Allsanity Locations without mods: {number_locations}")
|
||||
if number_locations != expected_locations:
|
||||
print(f"\tNew locations detected!"
|
||||
f"\n\tPlease update test_allsanity_without_mods_has_at_least_locations"
|
||||
f"\n\t\tExpected: {expected_locations}"
|
||||
f"\n\t\tActual: {number_locations}")
|
||||
|
||||
def test_allsanity_with_mods_has_at_least_locations(self):
|
||||
expected_locations = 1245
|
||||
allsanity_options = self.allsanity_options_with_mods()
|
||||
multiworld = setup_solo_multiworld(allsanity_options)
|
||||
number_locations = len(get_real_locations(self, multiworld))
|
||||
self.assertGreaterEqual(number_locations, expected_locations)
|
||||
print(f"\nStardew Valley - Allsanity Locations with all mods: {number_locations}")
|
||||
if number_locations != expected_locations:
|
||||
print(f"\tNew locations detected!"
|
||||
f"\n\tPlease update test_allsanity_with_mods_has_at_least_locations"
|
||||
f"\n\t\tExpected: {expected_locations}"
|
||||
f"\n\t\tActual: {number_locations}")
|
||||
|
||||
|
||||
class TestFriendsanityNone(SVTestBase):
|
||||
@@ -142,24 +246,25 @@ class TestFriendsanityNone(SVTestBase):
|
||||
}
|
||||
|
||||
def test_no_friendsanity_items(self):
|
||||
for item in self.multiworld.get_items():
|
||||
self.assertFalse(item.name.endswith(": 1 <3"))
|
||||
for item in self.multiworld.itempool:
|
||||
self.assertFalse(item.name.endswith(" <3"))
|
||||
|
||||
def test_no_friendsanity_locations(self):
|
||||
for location in self.multiworld.get_locations():
|
||||
self.assertFalse(location.name.startswith("Friendsanity"))
|
||||
for location_name in get_real_location_names(self, self.multiworld):
|
||||
self.assertFalse(location_name.startswith("Friendsanity"))
|
||||
|
||||
|
||||
class TestFriendsanityBachelors(SVTestBase):
|
||||
options = {
|
||||
options.Friendsanity.internal_name: options.Friendsanity.option_bachelors,
|
||||
options.FriendsanityHeartSize.internal_name: 1,
|
||||
}
|
||||
bachelors = {"Harvey", "Elliott", "Sam", "Alex", "Shane", "Sebastian", "Emily", "Haley", "Leah", "Abigail", "Penny",
|
||||
"Maru"}
|
||||
|
||||
def test_friendsanity_only_bachelor_items(self):
|
||||
suffix = ": 1 <3"
|
||||
for item in self.multiworld.get_items():
|
||||
suffix = " <3"
|
||||
for item in self.multiworld.itempool:
|
||||
if item.name.endswith(suffix):
|
||||
villager_name = item.name[:item.name.index(suffix)]
|
||||
self.assertIn(villager_name, self.bachelors)
|
||||
@@ -167,9 +272,9 @@ class TestFriendsanityBachelors(SVTestBase):
|
||||
def test_friendsanity_only_bachelor_locations(self):
|
||||
prefix = "Friendsanity: "
|
||||
suffix = " <3"
|
||||
for location in self.multiworld.get_locations():
|
||||
if location.name.startswith(prefix):
|
||||
name_no_prefix = location.name[len(prefix):]
|
||||
for location_name in get_real_location_names(self, self.multiworld):
|
||||
if location_name.startswith(prefix):
|
||||
name_no_prefix = location_name[len(prefix):]
|
||||
name_trimmed = name_no_prefix[:name_no_prefix.index(suffix)]
|
||||
parts = name_trimmed.split(" ")
|
||||
name = parts[0]
|
||||
@@ -181,12 +286,13 @@ class TestFriendsanityBachelors(SVTestBase):
|
||||
class TestFriendsanityStartingNpcs(SVTestBase):
|
||||
options = {
|
||||
options.Friendsanity.internal_name: options.Friendsanity.option_starting_npcs,
|
||||
options.FriendsanityHeartSize.internal_name: 1,
|
||||
}
|
||||
excluded_npcs = {"Leo", "Krobus", "Dwarf", "Sandy", "Kent"}
|
||||
|
||||
def test_friendsanity_only_starting_npcs_items(self):
|
||||
suffix = ": 1 <3"
|
||||
for item in self.multiworld.get_items():
|
||||
suffix = " <3"
|
||||
for item in self.multiworld.itempool:
|
||||
if item.name.endswith(suffix):
|
||||
villager_name = item.name[:item.name.index(suffix)]
|
||||
self.assertNotIn(villager_name, self.excluded_npcs)
|
||||
@@ -194,15 +300,15 @@ class TestFriendsanityStartingNpcs(SVTestBase):
|
||||
def test_friendsanity_only_starting_npcs_locations(self):
|
||||
prefix = "Friendsanity: "
|
||||
suffix = " <3"
|
||||
for location in self.multiworld.get_locations():
|
||||
if location.name.startswith(prefix):
|
||||
name_no_prefix = location.name[len(prefix):]
|
||||
for location_name in get_real_location_names(self, self.multiworld):
|
||||
if location_name.startswith(prefix):
|
||||
name_no_prefix = location_name[len(prefix):]
|
||||
name_trimmed = name_no_prefix[:name_no_prefix.index(suffix)]
|
||||
parts = name_trimmed.split(" ")
|
||||
name = parts[0]
|
||||
hearts = parts[1]
|
||||
self.assertNotIn(name, self.excluded_npcs)
|
||||
self.assertTrue(name in all_villagers_by_name or name == "Pet")
|
||||
self.assertTrue(name in all_villagers_by_mod_by_name[ModNames.vanilla] or name == "Pet")
|
||||
if name == "Pet":
|
||||
self.assertLessEqual(int(hearts), 5)
|
||||
elif all_villagers_by_name[name].bachelor:
|
||||
@@ -214,26 +320,62 @@ class TestFriendsanityStartingNpcs(SVTestBase):
|
||||
class TestFriendsanityAllNpcs(SVTestBase):
|
||||
options = {
|
||||
options.Friendsanity.internal_name: options.Friendsanity.option_all,
|
||||
options.FriendsanityHeartSize.internal_name: 1,
|
||||
}
|
||||
|
||||
def test_friendsanity_all_items(self):
|
||||
suffix = ": 1 <3"
|
||||
for item in self.multiworld.get_items():
|
||||
suffix = " <3"
|
||||
for item in self.multiworld.itempool:
|
||||
if item.name.endswith(suffix):
|
||||
villager_name = item.name[:item.name.index(suffix)]
|
||||
self.assertTrue(villager_name in all_villagers_by_name or villager_name == "Pet")
|
||||
self.assertTrue(villager_name in all_villagers_by_mod_by_name[ModNames.vanilla] or villager_name == "Pet")
|
||||
|
||||
def test_friendsanity_all_locations(self):
|
||||
prefix = "Friendsanity: "
|
||||
suffix = " <3"
|
||||
for location in self.multiworld.get_locations():
|
||||
if location.name.startswith(prefix):
|
||||
name_no_prefix = location.name[len(prefix):]
|
||||
for location_name in get_real_location_names(self, self.multiworld):
|
||||
if location_name.startswith(prefix):
|
||||
name_no_prefix = location_name[len(prefix):]
|
||||
name_trimmed = name_no_prefix[:name_no_prefix.index(suffix)]
|
||||
parts = name_trimmed.split(" ")
|
||||
name = parts[0]
|
||||
hearts = parts[1]
|
||||
self.assertTrue(name in all_villagers_by_name or name == "Pet")
|
||||
self.assertTrue(name in all_villagers_by_mod_by_name[ModNames.vanilla] or name == "Pet")
|
||||
if name == "Pet":
|
||||
self.assertLessEqual(int(hearts), 5)
|
||||
elif all_villagers_by_name[name].bachelor:
|
||||
self.assertLessEqual(int(hearts), 8)
|
||||
else:
|
||||
self.assertLessEqual(int(hearts), 10)
|
||||
|
||||
|
||||
class TestFriendsanityAllNpcsExcludingGingerIsland(SVTestBase):
|
||||
options = {
|
||||
options.Friendsanity.internal_name: options.Friendsanity.option_all,
|
||||
options.FriendsanityHeartSize.internal_name: 1,
|
||||
options.ExcludeGingerIsland.internal_name: options.ExcludeGingerIsland.option_true
|
||||
}
|
||||
|
||||
def test_friendsanity_all_items(self):
|
||||
suffix = " <3"
|
||||
for item in self.multiworld.itempool:
|
||||
if item.name.endswith(suffix):
|
||||
villager_name = item.name[:item.name.index(suffix)]
|
||||
self.assertNotEqual(villager_name, "Leo")
|
||||
self.assertTrue(villager_name in all_villagers_by_mod_by_name[ModNames.vanilla] or villager_name == "Pet")
|
||||
|
||||
def test_friendsanity_all_locations(self):
|
||||
prefix = "Friendsanity: "
|
||||
suffix = " <3"
|
||||
for location_name in get_real_location_names(self, self.multiworld):
|
||||
if location_name.startswith(prefix):
|
||||
name_no_prefix = location_name[len(prefix):]
|
||||
name_trimmed = name_no_prefix[:name_no_prefix.index(suffix)]
|
||||
parts = name_trimmed.split(" ")
|
||||
name = parts[0]
|
||||
hearts = parts[1]
|
||||
self.assertNotEqual(name, "Leo")
|
||||
self.assertTrue(name in all_villagers_by_mod_by_name[ModNames.vanilla] or name == "Pet")
|
||||
if name == "Pet":
|
||||
self.assertLessEqual(int(hearts), 5)
|
||||
elif all_villagers_by_name[name].bachelor:
|
||||
@@ -245,29 +387,182 @@ class TestFriendsanityAllNpcs(SVTestBase):
|
||||
class TestFriendsanityAllNpcsWithMarriage(SVTestBase):
|
||||
options = {
|
||||
options.Friendsanity.internal_name: options.Friendsanity.option_all_with_marriage,
|
||||
options.FriendsanityHeartSize.internal_name: 1,
|
||||
}
|
||||
|
||||
def test_friendsanity_all_with_marriage_items(self):
|
||||
suffix = ": 1 <3"
|
||||
for item in self.multiworld.get_items():
|
||||
suffix = " <3"
|
||||
for item in self.multiworld.itempool:
|
||||
if item.name.endswith(suffix):
|
||||
villager_name = item.name[:item.name.index(suffix)]
|
||||
self.assertTrue(villager_name in all_villagers_by_name or villager_name == "Pet")
|
||||
self.assertTrue(villager_name in all_villagers_by_mod_by_name[ModNames.vanilla] or villager_name == "Pet")
|
||||
|
||||
def test_friendsanity_all_with_marriage_locations(self):
|
||||
prefix = "Friendsanity: "
|
||||
suffix = " <3"
|
||||
for location in self.multiworld.get_locations():
|
||||
if location.name.startswith(prefix):
|
||||
name_no_prefix = location.name[len(prefix):]
|
||||
for location_name in get_real_location_names(self, self.multiworld):
|
||||
if location_name.startswith(prefix):
|
||||
name_no_prefix = location_name[len(prefix):]
|
||||
name_trimmed = name_no_prefix[:name_no_prefix.index(suffix)]
|
||||
parts = name_trimmed.split(" ")
|
||||
name = parts[0]
|
||||
hearts = parts[1]
|
||||
self.assertTrue(name in all_villagers_by_name or name == "Pet")
|
||||
self.assertTrue(name in all_villagers_by_mod_by_name[ModNames.vanilla] or name == "Pet")
|
||||
if name == "Pet":
|
||||
self.assertLessEqual(int(hearts), 5)
|
||||
elif all_villagers_by_name[name].bachelor:
|
||||
self.assertLessEqual(int(hearts), 14)
|
||||
else:
|
||||
self.assertLessEqual(int(hearts), 10)
|
||||
|
||||
|
||||
class TestFriendsanityAllNpcsWithMarriageHeartSize2(SVTestBase):
|
||||
options = {
|
||||
options.Friendsanity.internal_name: options.Friendsanity.option_all_with_marriage,
|
||||
options.FriendsanityHeartSize.internal_name: 2,
|
||||
}
|
||||
|
||||
def test_friendsanity_all_with_marriage_items(self):
|
||||
suffix = " <3"
|
||||
item_names = [item.name for item in self.multiworld.itempool]
|
||||
for villager_name in all_villagers_by_mod_by_name[ModNames.vanilla]:
|
||||
heart_item_name = f"{villager_name}{suffix}"
|
||||
number_heart_items = item_names.count(heart_item_name)
|
||||
if all_villagers_by_name[villager_name].bachelor:
|
||||
self.assertEqual(number_heart_items, 7)
|
||||
else:
|
||||
self.assertEqual(number_heart_items, 5)
|
||||
self.assertEqual(item_names.count("Pet <3"), 3)
|
||||
|
||||
def test_friendsanity_all_with_marriage_locations(self):
|
||||
prefix = "Friendsanity: "
|
||||
suffix = " <3"
|
||||
for location_name in get_real_location_names(self, self.multiworld):
|
||||
if not location_name.startswith(prefix):
|
||||
continue
|
||||
name_no_prefix = location_name[len(prefix):]
|
||||
name_trimmed = name_no_prefix[:name_no_prefix.index(suffix)]
|
||||
parts = name_trimmed.split(" ")
|
||||
name = parts[0]
|
||||
hearts = int(parts[1])
|
||||
self.assertTrue(name in all_villagers_by_mod_by_name[ModNames.vanilla] or name == "Pet")
|
||||
if name == "Pet":
|
||||
self.assertTrue(hearts == 2 or hearts == 4 or hearts == 5)
|
||||
elif all_villagers_by_name[name].bachelor:
|
||||
self.assertTrue(hearts == 2 or hearts == 4 or hearts == 6 or hearts == 8 or hearts == 10 or hearts == 12 or hearts == 14)
|
||||
else:
|
||||
self.assertTrue(hearts == 2 or hearts == 4 or hearts == 6 or hearts == 8 or hearts == 10)
|
||||
|
||||
|
||||
class TestFriendsanityAllNpcsWithMarriageHeartSize3(SVTestBase):
|
||||
options = {
|
||||
options.Friendsanity.internal_name: options.Friendsanity.option_all_with_marriage,
|
||||
options.FriendsanityHeartSize.internal_name: 3,
|
||||
}
|
||||
|
||||
def test_friendsanity_all_with_marriage_items(self):
|
||||
suffix = " <3"
|
||||
item_names = [item.name for item in self.multiworld.itempool]
|
||||
for villager_name in all_villagers_by_mod_by_name[ModNames.vanilla]:
|
||||
heart_item_name = f"{villager_name}{suffix}"
|
||||
number_heart_items = item_names.count(heart_item_name)
|
||||
if all_villagers_by_name[villager_name].bachelor:
|
||||
self.assertEqual(number_heart_items, 5)
|
||||
else:
|
||||
self.assertEqual(number_heart_items, 4)
|
||||
self.assertEqual(item_names.count("Pet <3"), 2)
|
||||
|
||||
def test_friendsanity_all_with_marriage_locations(self):
|
||||
prefix = "Friendsanity: "
|
||||
suffix = " <3"
|
||||
for location_name in get_real_location_names(self, self.multiworld):
|
||||
if not location_name.startswith(prefix):
|
||||
continue
|
||||
name_no_prefix = location_name[len(prefix):]
|
||||
name_trimmed = name_no_prefix[:name_no_prefix.index(suffix)]
|
||||
parts = name_trimmed.split(" ")
|
||||
name = parts[0]
|
||||
hearts = int(parts[1])
|
||||
self.assertTrue(name in all_villagers_by_mod_by_name[ModNames.vanilla] or name == "Pet")
|
||||
if name == "Pet":
|
||||
self.assertTrue(hearts == 3 or hearts == 5)
|
||||
elif all_villagers_by_name[name].bachelor:
|
||||
self.assertTrue(hearts == 3 or hearts == 6 or hearts == 9 or hearts == 12 or hearts == 14)
|
||||
else:
|
||||
self.assertTrue(hearts == 3 or hearts == 6 or hearts == 9 or hearts == 10)
|
||||
|
||||
|
||||
class TestFriendsanityAllNpcsWithMarriageHeartSize4(SVTestBase):
|
||||
options = {
|
||||
options.Friendsanity.internal_name: options.Friendsanity.option_all_with_marriage,
|
||||
options.FriendsanityHeartSize.internal_name: 4,
|
||||
}
|
||||
|
||||
def test_friendsanity_all_with_marriage_items(self):
|
||||
suffix = " <3"
|
||||
item_names = [item.name for item in self.multiworld.itempool]
|
||||
for villager_name in all_villagers_by_mod_by_name[ModNames.vanilla]:
|
||||
heart_item_name = f"{villager_name}{suffix}"
|
||||
number_heart_items = item_names.count(heart_item_name)
|
||||
if all_villagers_by_name[villager_name].bachelor:
|
||||
self.assertEqual(number_heart_items, 4)
|
||||
else:
|
||||
self.assertEqual(number_heart_items, 3)
|
||||
self.assertEqual(item_names.count("Pet <3"), 2)
|
||||
|
||||
def test_friendsanity_all_with_marriage_locations(self):
|
||||
prefix = "Friendsanity: "
|
||||
suffix = " <3"
|
||||
for location_name in get_real_location_names(self, self.multiworld):
|
||||
if not location_name.startswith(prefix):
|
||||
continue
|
||||
name_no_prefix = location_name[len(prefix):]
|
||||
name_trimmed = name_no_prefix[:name_no_prefix.index(suffix)]
|
||||
parts = name_trimmed.split(" ")
|
||||
name = parts[0]
|
||||
hearts = int(parts[1])
|
||||
self.assertTrue(name in all_villagers_by_mod_by_name[ModNames.vanilla] or name == "Pet")
|
||||
if name == "Pet":
|
||||
self.assertTrue(hearts == 4 or hearts == 5)
|
||||
elif all_villagers_by_name[name].bachelor:
|
||||
self.assertTrue(hearts == 4 or hearts == 8 or hearts == 12 or hearts == 14)
|
||||
else:
|
||||
self.assertTrue(hearts == 4 or hearts == 8 or hearts == 10)
|
||||
|
||||
|
||||
class TestFriendsanityAllNpcsWithMarriageHeartSize5(SVTestBase):
|
||||
options = {
|
||||
options.Friendsanity.internal_name: options.Friendsanity.option_all_with_marriage,
|
||||
options.FriendsanityHeartSize.internal_name: 5,
|
||||
}
|
||||
|
||||
def test_friendsanity_all_with_marriage_items(self):
|
||||
suffix = " <3"
|
||||
item_names = [item.name for item in self.multiworld.itempool]
|
||||
for villager_name in all_villagers_by_mod_by_name[ModNames.vanilla]:
|
||||
heart_item_name = f"{villager_name}{suffix}"
|
||||
number_heart_items = item_names.count(heart_item_name)
|
||||
if all_villagers_by_name[villager_name].bachelor:
|
||||
self.assertEqual(number_heart_items, 3)
|
||||
else:
|
||||
self.assertEqual(number_heart_items, 2)
|
||||
self.assertEqual(item_names.count("Pet <3"), 1)
|
||||
|
||||
def test_friendsanity_all_with_marriage_locations(self):
|
||||
prefix = "Friendsanity: "
|
||||
suffix = " <3"
|
||||
for location_name in get_real_location_names(self, self.multiworld):
|
||||
if not location_name.startswith(prefix):
|
||||
continue
|
||||
name_no_prefix = location_name[len(prefix):]
|
||||
name_trimmed = name_no_prefix[:name_no_prefix.index(suffix)]
|
||||
parts = name_trimmed.split(" ")
|
||||
name = parts[0]
|
||||
hearts = int(parts[1])
|
||||
self.assertTrue(name in all_villagers_by_mod_by_name[ModNames.vanilla] or name == "Pet")
|
||||
if name == "Pet":
|
||||
self.assertTrue(hearts == 5)
|
||||
elif all_villagers_by_name[name].bachelor:
|
||||
self.assertTrue(hearts == 5 or hearts == 10 or hearts == 14)
|
||||
else:
|
||||
self.assertTrue(hearts == 5 or hearts == 10)
|
||||
|
||||
Reference in New Issue
Block a user