Stardew Valley: Fix a bug where locations in logic would disappear from universal tracker as items get sent (#4230)

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
This commit is contained in:
Jouramie 2024-11-29 19:46:35 -05:00 committed by GitHub
parent 492e3a355e
commit e262c8be9c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
17 changed files with 243 additions and 203 deletions

View File

@ -3,7 +3,7 @@ from random import Random
from typing import Dict, Any, Iterable, Optional, Union, List, TextIO
from BaseClasses import Region, Entrance, Location, Item, Tutorial, ItemClassification, MultiWorld, CollectionState
from Options import PerGameCommonOptions
from Options import PerGameCommonOptions, Accessibility
from worlds.AutoWorld import World, WebWorld
from . import rules
from .bundles.bundle_room import BundleRoom
@ -91,15 +91,14 @@ class StardewValleyWorld(World):
web = StardewWebWorld()
modified_bundles: List[BundleRoom]
randomized_entrances: Dict[str, str]
total_progression_items: int
# all_progression_items: Dict[str, int] # If you need to debug total_progression_items, uncommenting this will help tremendously
total_progression_items: int
excluded_from_total_progression_items: List[str] = [Event.received_walnuts]
def __init__(self, multiworld: MultiWorld, player: int):
super().__init__(multiworld, player)
self.filler_item_pool_names = []
self.total_progression_items = 0
# self.all_progression_items = dict()
# Taking the seed specified in slot data for UT, otherwise just generating the seed.
self.seed = getattr(multiworld, "re_gen_passthrough", {}).get(STARDEW_VALLEY, self.random.getrandbits(64))
@ -121,17 +120,27 @@ class StardewValleyWorld(World):
goal_is_perfection = self.options.goal == Goal.option_perfection
goal_is_island_related = goal_is_walnut_hunter or goal_is_perfection
exclude_ginger_island = self.options.exclude_ginger_island == ExcludeGingerIsland.option_true
if goal_is_island_related and exclude_ginger_island:
self.options.exclude_ginger_island.value = ExcludeGingerIsland.option_false
goal_name = self.options.goal.current_key
player_name = self.multiworld.player_name[self.player]
logger.warning(
f"Goal '{goal_name}' requires Ginger Island. Exclude Ginger Island setting forced to 'False' for player {self.player} ({player_name})")
f"Goal '{goal_name}' requires Ginger Island. Exclude Ginger Island setting forced to 'False' for player {self.player} ({self.player_name})")
if exclude_ginger_island and self.options.walnutsanity != Walnutsanity.preset_none:
self.options.walnutsanity.value = Walnutsanity.preset_none
player_name = self.multiworld.player_name[self.player]
logger.warning(
f"Walnutsanity requires Ginger Island. Ginger Island was excluded from {self.player} ({player_name})'s world, so walnutsanity was force disabled")
f"Walnutsanity requires Ginger Island. Ginger Island was excluded from {self.player} ({self.player_name})'s world, so walnutsanity was force disabled")
if goal_is_perfection and self.options.accessibility == Accessibility.option_minimal:
self.options.accessibility.value = Accessibility.option_full
logger.warning(
f"Goal 'Perfection' requires full accessibility. Accessibility setting forced to 'Full' for player {self.player} ({self.player_name})")
elif self.options.goal == Goal.option_allsanity and self.options.accessibility == Accessibility.option_minimal:
self.options.accessibility.value = Accessibility.option_full
logger.warning(
f"Goal 'Allsanity' requires full accessibility. Accessibility setting forced to 'Full' for player {self.player} ({self.player_name})")
def create_regions(self):
def create_region(name: str, exits: Iterable[str]) -> Region:
@ -171,8 +180,7 @@ class StardewValleyWorld(World):
for location in self.multiworld.get_locations(self.player)
if location.address is not None])
created_items = create_items(self.create_item, self.delete_item, locations_count, items_to_exclude, self.options, self.content,
self.random)
created_items = create_items(self.create_item, locations_count, items_to_exclude, self.options, self.content, self.random)
self.multiworld.itempool += created_items
@ -180,6 +188,18 @@ class StardewValleyWorld(World):
self.setup_player_events()
self.setup_victory()
# This is really a best-effort to get the total progression items count. It is mostly used to spread grinds across spheres are push back locations that
# only become available after months or years in game. In most cases, not having the exact count will not impact the logic.
#
# The actual total can be impacted by the start_inventory_from_pool, when items are removed from the pool but not from the total. The is also a bug
# with plando where additional progression items can be created without being accounted for, which impact the real amount of progression items. This can
# ultimately create unwinnable seeds where some items (like Blueberry seeds) are locked in Shipsanity: Blueberry, but world is deemed winnable as the
# winning rule only check the count of collected progression items.
self.total_progression_items += sum(1 for i in self.multiworld.precollected_items[self.player] if i.advancement)
self.total_progression_items += sum(1 for i in self.multiworld.get_filled_locations(self.player) if i.advancement)
self.total_progression_items += sum(1 for i in created_items if i.advancement)
self.total_progression_items -= 1 # -1 for the victory event
def precollect_starting_season(self):
if self.options.season_randomization == SeasonRandomization.option_progressive:
return
@ -304,14 +324,8 @@ class StardewValleyWorld(World):
if override_classification is None:
override_classification = item.classification
if override_classification & ItemClassification.progression:
self.total_progression_items += 1
return StardewItem(item.name, override_classification, item.code, self.player)
def delete_item(self, item: Item):
if item.classification & ItemClassification.progression:
self.total_progression_items -= 1
def create_starting_item(self, item: Union[str, ItemData]) -> StardewItem:
if isinstance(item, str):
item = item_table[item]
@ -330,10 +344,6 @@ class StardewValleyWorld(World):
region.locations.append(location)
location.place_locked_item(StardewItem(item, ItemClassification.progression, None, self.player))
# This is not ideal, but the rule count them so...
if item != Event.victory:
self.total_progression_items += 1
def set_rules(self):
set_rules(self)
@ -426,15 +436,25 @@ class StardewValleyWorld(World):
def collect(self, state: CollectionState, item: StardewItem) -> bool:
change = super().collect(state, item)
if change:
state.prog_items[self.player][Event.received_walnuts] += self.get_walnut_amount(item.name)
return change
if not change:
return False
walnut_amount = self.get_walnut_amount(item.name)
if walnut_amount:
state.prog_items[self.player][Event.received_walnuts] += walnut_amount
return True
def remove(self, state: CollectionState, item: StardewItem) -> bool:
change = super().remove(state, item)
if change:
state.prog_items[self.player][Event.received_walnuts] -= self.get_walnut_amount(item.name)
return change
if not change:
return False
walnut_amount = self.get_walnut_amount(item.name)
if walnut_amount:
state.prog_items[self.player][Event.received_walnuts] -= walnut_amount
return True
@staticmethod
def get_walnut_amount(item_name: str) -> int:

View File

@ -169,14 +169,14 @@ def get_too_many_items_error_message(locations_count: int, items_count: int) ->
return f"There should be at least as many locations [{locations_count}] as there are mandatory items [{items_count}]"
def create_items(item_factory: StardewItemFactory, item_deleter: StardewItemDeleter, locations_count: int, items_to_exclude: List[Item],
def create_items(item_factory: StardewItemFactory, locations_count: int, items_to_exclude: List[Item],
options: StardewValleyOptions, content: StardewContent, random: Random) -> List[Item]:
items = []
unique_items = create_unique_items(item_factory, options, content, random)
remove_items(item_deleter, items_to_exclude, unique_items)
remove_items(items_to_exclude, unique_items)
remove_items_if_no_room_for_them(item_deleter, unique_items, locations_count, random)
remove_items_if_no_room_for_them(unique_items, locations_count, random)
items += unique_items
logger.debug(f"Created {len(unique_items)} unique items")
@ -192,14 +192,13 @@ def create_items(item_factory: StardewItemFactory, item_deleter: StardewItemDele
return items
def remove_items(item_deleter: StardewItemDeleter, items_to_remove, items):
def remove_items(items_to_remove, items):
for item in items_to_remove:
if item in items:
items.remove(item)
item_deleter(item)
def remove_items_if_no_room_for_them(item_deleter: StardewItemDeleter, unique_items: List[Item], locations_count: int, random: Random):
def remove_items_if_no_room_for_them(unique_items: List[Item], locations_count: int, random: Random):
if len(unique_items) <= locations_count:
return
@ -212,7 +211,7 @@ def remove_items_if_no_room_for_them(item_deleter: StardewItemDeleter, unique_it
logger.debug(f"Player has more items than locations, trying to remove {number_of_items_to_remove} random filler items")
assert len(removable_items) >= number_of_items_to_remove, get_too_many_items_error_message(locations_count, len(unique_items))
items_to_remove = random.sample(removable_items, number_of_items_to_remove)
remove_items(item_deleter, items_to_remove, unique_items)
remove_items(items_to_remove, unique_items)
def create_unique_items(item_factory: StardewItemFactory, options: StardewValleyOptions, content: StardewContent, random: Random) -> List[Item]:

View File

@ -1,10 +1,13 @@
from dataclasses import dataclass
from typing import Iterable, Union, List, Tuple, Hashable
from typing import Iterable, Union, List, Tuple, Hashable, TYPE_CHECKING
from BaseClasses import CollectionState
from .base import BaseStardewRule, CombinableStardewRule
from .protocol import StardewRule
if TYPE_CHECKING:
from .. import StardewValleyWorld
class TotalReceived(BaseStardewRule):
count: int
@ -102,16 +105,19 @@ class HasProgressionPercent(CombinableStardewRule):
return self.percent
def __call__(self, state: CollectionState) -> bool:
stardew_world = state.multiworld.worlds[self.player]
stardew_world: "StardewValleyWorld" = state.multiworld.worlds[self.player]
total_count = stardew_world.total_progression_items
needed_count = (total_count * self.percent) // 100
player_state = state.prog_items[self.player]
if needed_count <= len(player_state):
if needed_count <= len(player_state) - len(stardew_world.excluded_from_total_progression_items):
return True
total_count = 0
for item, item_count in player_state.items():
if item in stardew_world.excluded_from_total_progression_items:
continue
total_count += item_count
if total_count >= needed_count:
return True

View File

@ -11,10 +11,10 @@ class TestCropsanityRules(SVTestBase):
harvest_cactus = self.world.logic.region.can_reach_location("Harvest Cactus Fruit")
self.assert_rule_false(harvest_cactus, self.multiworld.state)
self.multiworld.state.collect(self.world.create_item("Cactus Seeds"), prevent_sweep=False)
self.multiworld.state.collect(self.world.create_item("Shipping Bin"), prevent_sweep=False)
self.multiworld.state.collect(self.world.create_item("Desert Obelisk"), prevent_sweep=False)
self.multiworld.state.collect(self.create_item("Cactus Seeds"))
self.multiworld.state.collect(self.create_item("Shipping Bin"))
self.multiworld.state.collect(self.create_item("Desert Obelisk"))
self.assert_rule_false(harvest_cactus, self.multiworld.state)
self.multiworld.state.collect(self.world.create_item("Greenhouse"), prevent_sweep=False)
self.multiworld.state.collect(self.create_item("Greenhouse"))
self.assert_rule_true(harvest_cactus, self.multiworld.state)

View File

@ -1,6 +1,6 @@
import itertools
from Options import NamedRange
from Options import NamedRange, Accessibility
from . import SVTestCase, allsanity_no_mods_6_x_x, allsanity_mods_6_x_x, solo_multiworld
from .assertion import WorldAssertMixin
from .long.option_names import all_option_choices
@ -54,6 +54,23 @@ class TestGoal(SVTestCase):
victory = multi_world.find_item("Victory", 1)
self.assertEqual(victory.name, location)
def test_given_perfection_goal_when_generate_then_accessibility_is_forced_to_full(self):
"""There is a bug with the current victory condition of the perfection goal that can create unwinnable seeds if the accessibility is set to minimal and
the world gets flooded with progression items through plando. This will increase the amount of collected progression items pass the total amount
calculated for the world when creating the item pool. This will cause the victory condition to be met before all locations are collected, so some could
be left inaccessible, which in practice will make the seed unwinnable.
"""
for accessibility in Accessibility.options.keys():
world_options = {Goal.internal_name: Goal.option_perfection, "accessibility": accessibility}
with self.solo_world_sub_test(f"Accessibility: {accessibility}", world_options) as (_, world):
self.assertEqual(world.options.accessibility, Accessibility.option_full)
def test_given_allsanity_goal_when_generate_then_accessibility_is_forced_to_full(self):
for accessibility in Accessibility.options.keys():
world_options = {Goal.internal_name: Goal.option_allsanity, "accessibility": accessibility}
with self.solo_world_sub_test(f"Accessibility: {accessibility}", world_options) as (_, world):
self.assertEqual(world.options.accessibility, Accessibility.option_full)
class TestSeasonRandomization(SVTestCase):
def test_given_disabled_when_generate_then_all_seasons_are_precollected(self):

View File

@ -6,7 +6,7 @@ from argparse import Namespace
from contextlib import contextmanager
from typing import Dict, ClassVar, Iterable, Tuple, Optional, List, Union, Any
from BaseClasses import MultiWorld, CollectionState, PlandoOptions, get_seed, Location, Item, ItemClassification
from BaseClasses import MultiWorld, CollectionState, PlandoOptions, get_seed, Location, Item
from Options import VerifyKeys
from test.bases import WorldTestBase
from test.general import gen_steps, setup_solo_multiworld as setup_base_solo_multiworld
@ -236,7 +236,6 @@ class SVTestBase(RuleAssertMixin, WorldTestBase, SVTestCase):
self.original_state = self.multiworld.state.copy()
self.original_itempool = self.multiworld.itempool.copy()
self.original_prog_item_count = world.total_progression_items
self.unfilled_locations = self.multiworld.get_unfilled_locations(1)
if self.constructed:
self.world = world # noqa
@ -246,7 +245,6 @@ class SVTestBase(RuleAssertMixin, WorldTestBase, SVTestCase):
self.multiworld.itempool = self.original_itempool
for location in self.unfilled_locations:
location.item = None
self.world.total_progression_items = self.original_prog_item_count
self.multiworld.lock.release()
@ -257,20 +255,13 @@ class SVTestBase(RuleAssertMixin, WorldTestBase, SVTestCase):
return super().run_default_tests
def collect_lots_of_money(self, percent: float = 0.25):
self.multiworld.state.collect(self.world.create_item("Shipping Bin"), prevent_sweep=False)
real_total_prog_items = self.multiworld.worlds[self.player].total_progression_items
self.collect("Shipping Bin")
real_total_prog_items = self.world.total_progression_items
required_prog_items = int(round(real_total_prog_items * percent))
for i in range(required_prog_items):
self.multiworld.state.collect(self.world.create_item("Stardrop"), prevent_sweep=False)
self.multiworld.worlds[self.player].total_progression_items = real_total_prog_items
self.collect("Stardrop", required_prog_items)
def collect_all_the_money(self):
self.multiworld.state.collect(self.world.create_item("Shipping Bin"), prevent_sweep=False)
real_total_prog_items = self.multiworld.worlds[self.player].total_progression_items
required_prog_items = int(round(real_total_prog_items * 0.95))
for i in range(required_prog_items):
self.multiworld.state.collect(self.world.create_item("Stardrop"), prevent_sweep=False)
self.multiworld.worlds[self.player].total_progression_items = real_total_prog_items
self.collect_lots_of_money(0.95)
def collect_everything(self):
non_event_items = [item for item in self.multiworld.get_items() if item.code]
@ -278,7 +269,8 @@ class SVTestBase(RuleAssertMixin, WorldTestBase, SVTestCase):
self.multiworld.state.collect(item)
def collect_all_except(self, item_to_not_collect: str):
for item in self.multiworld.get_items():
non_event_items = [item for item in self.multiworld.get_items() if item.code]
for item in non_event_items:
if item.name != item_to_not_collect:
self.multiworld.state.collect(item)
@ -290,25 +282,26 @@ class SVTestBase(RuleAssertMixin, WorldTestBase, SVTestCase):
def collect(self, item: Union[str, Item, Iterable[Item]], count: int = 1) -> Union[None, Item, List[Item]]:
assert count > 0
if not isinstance(item, str):
super().collect(item)
return
if count == 1:
item = self.create_item(item)
self.multiworld.state.collect(item)
return item
items = []
for i in range(count):
item = self.create_item(item)
self.multiworld.state.collect(item)
items.append(item)
return items
def create_item(self, item: str) -> StardewItem:
created_item = self.world.create_item(item)
if created_item.classification & ItemClassification.progression:
self.multiworld.worlds[self.player].total_progression_items -= 1
return created_item
return self.world.create_item(item)
def remove_one_by_name(self, item: str) -> None:
self.remove(self.create_item(item))
@ -336,7 +329,6 @@ def solo_multiworld(world_options: Optional[Dict[Union[str, StardewValleyOption]
original_state = multiworld.state.copy()
original_itempool = multiworld.itempool.copy()
unfilled_locations = multiworld.get_unfilled_locations(1)
original_prog_item_count = world.total_progression_items
yield multiworld, world
@ -344,7 +336,6 @@ def solo_multiworld(world_options: Optional[Dict[Union[str, StardewValleyOption]
multiworld.itempool = original_itempool
for location in unfilled_locations:
location.item = None
multiworld.total_progression_items = original_prog_item_count
multiworld.lock.release()

View File

@ -19,8 +19,8 @@ class TestArcadeMachinesLogic(SVTestBase):
life = self.create_item("JotPK: Extra Life")
drop = self.create_item("JotPK: Increased Drop Rate")
self.multiworld.state.collect(boots, prevent_sweep=True)
self.multiworld.state.collect(gun, prevent_sweep=True)
self.multiworld.state.collect(boots)
self.multiworld.state.collect(gun)
self.assertTrue(self.world.logic.region.can_reach("JotPK World 1")(self.multiworld.state))
self.assertFalse(self.world.logic.region.can_reach("JotPK World 2")(self.multiworld.state))
self.assertFalse(self.world.logic.region.can_reach("JotPK World 3")(self.multiworld.state))
@ -28,8 +28,8 @@ class TestArcadeMachinesLogic(SVTestBase):
self.remove(boots)
self.remove(gun)
self.multiworld.state.collect(boots, prevent_sweep=True)
self.multiworld.state.collect(boots, prevent_sweep=True)
self.multiworld.state.collect(boots)
self.multiworld.state.collect(boots)
self.assertTrue(self.world.logic.region.can_reach("JotPK World 1")(self.multiworld.state))
self.assertFalse(self.world.logic.region.can_reach("JotPK World 2")(self.multiworld.state))
self.assertFalse(self.world.logic.region.can_reach("JotPK World 3")(self.multiworld.state))
@ -37,10 +37,10 @@ class TestArcadeMachinesLogic(SVTestBase):
self.remove(boots)
self.remove(boots)
self.multiworld.state.collect(boots, prevent_sweep=True)
self.multiworld.state.collect(gun, prevent_sweep=True)
self.multiworld.state.collect(ammo, prevent_sweep=True)
self.multiworld.state.collect(life, prevent_sweep=True)
self.multiworld.state.collect(boots)
self.multiworld.state.collect(gun)
self.multiworld.state.collect(ammo)
self.multiworld.state.collect(life)
self.assertTrue(self.world.logic.region.can_reach("JotPK World 1")(self.multiworld.state))
self.assertTrue(self.world.logic.region.can_reach("JotPK World 2")(self.multiworld.state))
self.assertFalse(self.world.logic.region.can_reach("JotPK World 3")(self.multiworld.state))
@ -50,13 +50,13 @@ class TestArcadeMachinesLogic(SVTestBase):
self.remove(ammo)
self.remove(life)
self.multiworld.state.collect(boots, prevent_sweep=True)
self.multiworld.state.collect(gun, prevent_sweep=True)
self.multiworld.state.collect(gun, prevent_sweep=True)
self.multiworld.state.collect(ammo, prevent_sweep=True)
self.multiworld.state.collect(ammo, prevent_sweep=True)
self.multiworld.state.collect(life, prevent_sweep=True)
self.multiworld.state.collect(drop, prevent_sweep=True)
self.multiworld.state.collect(boots)
self.multiworld.state.collect(gun)
self.multiworld.state.collect(gun)
self.multiworld.state.collect(ammo)
self.multiworld.state.collect(ammo)
self.multiworld.state.collect(life)
self.multiworld.state.collect(drop)
self.assertTrue(self.world.logic.region.can_reach("JotPK World 1")(self.multiworld.state))
self.assertTrue(self.world.logic.region.can_reach("JotPK World 2")(self.multiworld.state))
self.assertTrue(self.world.logic.region.can_reach("JotPK World 3")(self.multiworld.state))
@ -69,17 +69,17 @@ class TestArcadeMachinesLogic(SVTestBase):
self.remove(life)
self.remove(drop)
self.multiworld.state.collect(boots, prevent_sweep=True)
self.multiworld.state.collect(boots, prevent_sweep=True)
self.multiworld.state.collect(gun, prevent_sweep=True)
self.multiworld.state.collect(gun, prevent_sweep=True)
self.multiworld.state.collect(gun, prevent_sweep=True)
self.multiworld.state.collect(gun, prevent_sweep=True)
self.multiworld.state.collect(ammo, prevent_sweep=True)
self.multiworld.state.collect(ammo, prevent_sweep=True)
self.multiworld.state.collect(ammo, prevent_sweep=True)
self.multiworld.state.collect(life, prevent_sweep=True)
self.multiworld.state.collect(drop, prevent_sweep=True)
self.multiworld.state.collect(boots)
self.multiworld.state.collect(boots)
self.multiworld.state.collect(gun)
self.multiworld.state.collect(gun)
self.multiworld.state.collect(gun)
self.multiworld.state.collect(gun)
self.multiworld.state.collect(ammo)
self.multiworld.state.collect(ammo)
self.multiworld.state.collect(ammo)
self.multiworld.state.collect(life)
self.multiworld.state.collect(drop)
self.assertTrue(self.world.logic.region.can_reach("JotPK World 1")(self.multiworld.state))
self.assertTrue(self.world.logic.region.can_reach("JotPK World 2")(self.multiworld.state))
self.assertTrue(self.world.logic.region.can_reach("JotPK World 3")(self.multiworld.state))

View File

@ -23,7 +23,7 @@ class TestBuildingLogic(SVTestBase):
self.assertFalse(big_coop_blueprint_rule(self.multiworld.state),
f"Rule is {repr(self.multiworld.get_location('Big Coop Blueprint', self.player).access_rule)}")
self.multiworld.state.collect(self.create_item("Progressive Coop"), prevent_sweep=False)
self.multiworld.state.collect(self.create_item("Progressive Coop"))
self.assertTrue(big_coop_blueprint_rule(self.multiworld.state),
f"Rule is {repr(self.multiworld.get_location('Big Coop Blueprint', self.player).access_rule)}")
@ -33,10 +33,10 @@ class TestBuildingLogic(SVTestBase):
self.collect_lots_of_money()
self.assertFalse(self.world.logic.region.can_reach_location("Deluxe Coop Blueprint")(self.multiworld.state))
self.multiworld.state.collect(self.create_item("Progressive Coop"), prevent_sweep=True)
self.multiworld.state.collect(self.create_item("Progressive Coop"))
self.assertFalse(self.world.logic.region.can_reach_location("Deluxe Coop Blueprint")(self.multiworld.state))
self.multiworld.state.collect(self.create_item("Progressive Coop"), prevent_sweep=True)
self.multiworld.state.collect(self.create_item("Progressive Coop"))
self.assertTrue(self.world.logic.region.can_reach_location("Deluxe Coop Blueprint")(self.multiworld.state))
def test_big_shed_blueprint(self):
@ -48,6 +48,6 @@ class TestBuildingLogic(SVTestBase):
self.assertFalse(big_shed_rule(self.multiworld.state),
f"Rule is {repr(self.multiworld.get_location('Big Shed Blueprint', self.player).access_rule)}")
self.multiworld.state.collect(self.create_item("Progressive Shed"), prevent_sweep=True)
self.multiworld.state.collect(self.create_item("Progressive Shed"))
self.assertTrue(big_shed_rule(self.multiworld.state),
f"Rule is {repr(self.multiworld.get_location('Big Shed Blueprint', self.player).access_rule)}")

View File

@ -17,14 +17,14 @@ class TestRecipeLearnLogic(SVTestBase):
rule = self.world.logic.region.can_reach_location(location)
self.assert_rule_false(rule, self.multiworld.state)
self.multiworld.state.collect(self.create_item("Progressive House"), prevent_sweep=False)
self.multiworld.state.collect(self.create_item("Radish Seeds"), prevent_sweep=False)
self.multiworld.state.collect(self.create_item("Spring"), prevent_sweep=False)
self.multiworld.state.collect(self.create_item("Summer"), prevent_sweep=False)
self.multiworld.state.collect(self.create_item("Progressive House"))
self.multiworld.state.collect(self.create_item("Radish Seeds"))
self.multiworld.state.collect(self.create_item("Spring"))
self.multiworld.state.collect(self.create_item("Summer"))
self.collect_lots_of_money()
self.assert_rule_false(rule, self.multiworld.state)
self.multiworld.state.collect(self.create_item("The Queen of Sauce"), prevent_sweep=False)
self.multiworld.state.collect(self.create_item("The Queen of Sauce"))
self.assert_rule_true(rule, self.multiworld.state)
@ -42,21 +42,21 @@ class TestRecipeReceiveLogic(SVTestBase):
rule = self.world.logic.region.can_reach_location(location)
self.assert_rule_false(rule, self.multiworld.state)
self.multiworld.state.collect(self.create_item("Progressive House"), prevent_sweep=False)
self.multiworld.state.collect(self.create_item("Radish Seeds"), prevent_sweep=False)
self.multiworld.state.collect(self.create_item("Summer"), prevent_sweep=False)
self.multiworld.state.collect(self.create_item("Progressive House"))
self.multiworld.state.collect(self.create_item("Radish Seeds"))
self.multiworld.state.collect(self.create_item("Summer"))
self.collect_lots_of_money()
self.assert_rule_false(rule, self.multiworld.state)
spring = self.create_item("Spring")
qos = self.create_item("The Queen of Sauce")
self.multiworld.state.collect(spring, prevent_sweep=False)
self.multiworld.state.collect(qos, prevent_sweep=False)
self.multiworld.state.collect(spring)
self.multiworld.state.collect(qos)
self.assert_rule_false(rule, self.multiworld.state)
self.multiworld.state.remove(spring)
self.multiworld.state.remove(qos)
self.multiworld.state.collect(self.create_item("Radish Salad Recipe"), prevent_sweep=False)
self.multiworld.state.collect(self.create_item("Radish Salad Recipe"))
self.assert_rule_true(rule, self.multiworld.state)
def test_get_chefsanity_check_recipe(self):
@ -64,20 +64,20 @@ class TestRecipeReceiveLogic(SVTestBase):
rule = self.world.logic.region.can_reach_location(location)
self.assert_rule_false(rule, self.multiworld.state)
self.multiworld.state.collect(self.create_item("Spring"), prevent_sweep=False)
self.multiworld.state.collect(self.create_item("Spring"))
self.collect_lots_of_money()
self.assert_rule_false(rule, self.multiworld.state)
seeds = self.create_item("Radish Seeds")
summer = self.create_item("Summer")
house = self.create_item("Progressive House")
self.multiworld.state.collect(seeds, prevent_sweep=False)
self.multiworld.state.collect(summer, prevent_sweep=False)
self.multiworld.state.collect(house, prevent_sweep=False)
self.multiworld.state.collect(seeds)
self.multiworld.state.collect(summer)
self.multiworld.state.collect(house)
self.assert_rule_false(rule, self.multiworld.state)
self.multiworld.state.remove(seeds)
self.multiworld.state.remove(summer)
self.multiworld.state.remove(house)
self.multiworld.state.collect(self.create_item("The Queen of Sauce"), prevent_sweep=False)
self.multiworld.state.collect(self.create_item("The Queen of Sauce"))
self.assert_rule_true(rule, self.multiworld.state)

View File

@ -25,7 +25,7 @@ class TestCraftsanityLogic(SVTestBase):
self.collect_all_the_money()
self.assert_rule_false(rule, self.multiworld.state)
self.multiworld.state.collect(self.create_item("Marble Brazier Recipe"), prevent_sweep=False)
self.multiworld.state.collect(self.create_item("Marble Brazier Recipe"))
self.assert_rule_true(rule, self.multiworld.state)
def test_can_learn_crafting_recipe(self):
@ -38,16 +38,16 @@ class TestCraftsanityLogic(SVTestBase):
def test_can_craft_festival_recipe(self):
recipe = all_crafting_recipes_by_name["Jack-O-Lantern"]
self.multiworld.state.collect(self.create_item("Pumpkin Seeds"), prevent_sweep=False)
self.multiworld.state.collect(self.create_item("Torch Recipe"), prevent_sweep=False)
self.multiworld.state.collect(self.create_item("Pumpkin Seeds"))
self.multiworld.state.collect(self.create_item("Torch Recipe"))
self.collect_lots_of_money()
rule = self.world.logic.crafting.can_craft(recipe)
self.assert_rule_false(rule, self.multiworld.state)
self.multiworld.state.collect(self.create_item("Fall"), prevent_sweep=False)
self.multiworld.state.collect(self.create_item("Fall"))
self.assert_rule_false(rule, self.multiworld.state)
self.multiworld.state.collect(self.create_item("Jack-O-Lantern Recipe"), prevent_sweep=False)
self.multiworld.state.collect(self.create_item("Jack-O-Lantern Recipe"))
self.assert_rule_true(rule, self.multiworld.state)
def test_require_furnace_recipe_for_smelting_checks(self):
@ -64,7 +64,7 @@ class TestCraftsanityLogic(SVTestBase):
self.collect_all_the_money()
self.assert_rules_false(rules, self.multiworld.state)
self.multiworld.state.collect(self.create_item("Furnace Recipe"), prevent_sweep=False)
self.multiworld.state.collect(self.create_item("Furnace Recipe"))
self.assert_rules_true(rules, self.multiworld.state)
@ -79,16 +79,16 @@ class TestCraftsanityWithFestivalsLogic(SVTestBase):
def test_can_craft_festival_recipe(self):
recipe = all_crafting_recipes_by_name["Jack-O-Lantern"]
self.multiworld.state.collect(self.create_item("Pumpkin Seeds"), prevent_sweep=False)
self.multiworld.state.collect(self.create_item("Fall"), prevent_sweep=False)
self.multiworld.state.collect(self.create_item("Pumpkin Seeds"))
self.multiworld.state.collect(self.create_item("Fall"))
self.collect_lots_of_money()
rule = self.world.logic.crafting.can_craft(recipe)
self.assert_rule_false(rule, self.multiworld.state)
self.multiworld.state.collect(self.create_item("Jack-O-Lantern Recipe"), prevent_sweep=False)
self.multiworld.state.collect(self.create_item("Jack-O-Lantern Recipe"))
self.assert_rule_false(rule, self.multiworld.state)
self.multiworld.state.collect(self.create_item("Torch Recipe"), prevent_sweep=False)
self.multiworld.state.collect(self.create_item("Torch Recipe"))
self.assert_rule_true(rule, self.multiworld.state)
@ -109,7 +109,7 @@ class TestNoCraftsanityLogic(SVTestBase):
def test_can_craft_festival_recipe(self):
recipe = all_crafting_recipes_by_name["Jack-O-Lantern"]
self.multiworld.state.collect(self.create_item("Pumpkin Seeds"), prevent_sweep=False)
self.multiworld.state.collect(self.create_item("Pumpkin Seeds"))
self.collect_lots_of_money()
rule = self.world.logic.crafting.can_craft(recipe)
result = rule(self.multiworld.state)
@ -126,7 +126,7 @@ class TestNoCraftsanityLogic(SVTestBase):
self.collect([self.create_item("Progressive Sword")] * 4)
self.collect([self.create_item("Progressive Mine Elevator")] * 24)
self.collect([self.create_item("Progressive Trash Can")] * 2)
self.multiworld.state.collect(self.create_item("Furnace Recipe"), prevent_sweep=False)
self.multiworld.state.collect(self.create_item("Furnace Recipe"))
self.collect([self.create_item("Combat Level")] * 10)
self.collect([self.create_item("Fishing Level")] * 10)
self.collect_all_the_money()
@ -147,11 +147,11 @@ class TestNoCraftsanityWithFestivalsLogic(SVTestBase):
def test_can_craft_festival_recipe(self):
recipe = all_crafting_recipes_by_name["Jack-O-Lantern"]
self.multiworld.state.collect(self.create_item("Pumpkin Seeds"), prevent_sweep=False)
self.multiworld.state.collect(self.create_item("Fall"), prevent_sweep=False)
self.multiworld.state.collect(self.create_item("Pumpkin Seeds"))
self.multiworld.state.collect(self.create_item("Fall"))
self.collect_lots_of_money()
rule = self.world.logic.crafting.can_craft(recipe)
self.assert_rule_false(rule, self.multiworld.state)
self.multiworld.state.collect(self.create_item("Jack-O-Lantern Recipe"), prevent_sweep=False)
self.multiworld.state.collect(self.create_item("Jack-O-Lantern Recipe"))
self.assert_rule_true(rule, self.multiworld.state)

View File

@ -18,7 +18,7 @@ class TestDonationLogicAll(SVTestBase):
for donation in locations_by_tag[LocationTags.MUSEUM_DONATIONS]:
self.assertFalse(self.world.logic.region.can_reach_location(donation.name)(self.multiworld.state))
self.multiworld.state.collect(self.create_item(railroad_item), prevent_sweep=False)
self.multiworld.state.collect(self.create_item(railroad_item))
for donation in locations_by_tag[LocationTags.MUSEUM_DONATIONS]:
self.assertTrue(self.world.logic.region.can_reach_location(donation.name)(self.multiworld.state))
@ -39,7 +39,7 @@ class TestDonationLogicRandomized(SVTestBase):
for donation in donation_locations:
self.assertFalse(self.world.logic.region.can_reach_location(donation.name)(self.multiworld.state))
self.multiworld.state.collect(self.create_item(railroad_item), prevent_sweep=False)
self.multiworld.state.collect(self.create_item(railroad_item))
for donation in donation_locations:
self.assertTrue(self.world.logic.region.can_reach_location(donation.name)(self.multiworld.state))
@ -58,7 +58,7 @@ class TestDonationLogicMilestones(SVTestBase):
for donation in locations_by_tag[LocationTags.MUSEUM_MILESTONES]:
self.assertFalse(self.world.logic.region.can_reach_location(donation.name)(self.multiworld.state))
self.multiworld.state.collect(self.create_item(railroad_item), prevent_sweep=False)
self.multiworld.state.collect(self.create_item(railroad_item))
for donation in locations_by_tag[LocationTags.MUSEUM_MILESTONES]:
self.assertTrue(self.world.logic.region.can_reach_location(donation.name)(self.multiworld.state))

View File

@ -11,34 +11,34 @@ class TestFriendsanityDatingRules(SVTestBase):
def test_earning_dating_heart_requires_dating(self):
self.collect_all_the_money()
self.multiworld.state.collect(self.create_item("Fall"), prevent_sweep=False)
self.multiworld.state.collect(self.create_item("Beach Bridge"), prevent_sweep=False)
self.multiworld.state.collect(self.create_item("Progressive House"), prevent_sweep=False)
self.multiworld.state.collect(self.create_item("Fall"))
self.multiworld.state.collect(self.create_item("Beach Bridge"))
self.multiworld.state.collect(self.create_item("Progressive House"))
for i in range(3):
self.multiworld.state.collect(self.create_item("Progressive Pickaxe"), prevent_sweep=False)
self.multiworld.state.collect(self.create_item("Progressive Weapon"), prevent_sweep=False)
self.multiworld.state.collect(self.create_item("Progressive Axe"), prevent_sweep=False)
self.multiworld.state.collect(self.create_item("Progressive Barn"), prevent_sweep=False)
self.multiworld.state.collect(self.create_item("Progressive Pickaxe"))
self.multiworld.state.collect(self.create_item("Progressive Weapon"))
self.multiworld.state.collect(self.create_item("Progressive Axe"))
self.multiworld.state.collect(self.create_item("Progressive Barn"))
for i in range(10):
self.multiworld.state.collect(self.create_item("Foraging Level"), prevent_sweep=False)
self.multiworld.state.collect(self.create_item("Farming Level"), prevent_sweep=False)
self.multiworld.state.collect(self.create_item("Mining Level"), prevent_sweep=False)
self.multiworld.state.collect(self.create_item("Combat Level"), prevent_sweep=False)
self.multiworld.state.collect(self.create_item("Progressive Mine Elevator"), prevent_sweep=False)
self.multiworld.state.collect(self.create_item("Progressive Mine Elevator"), prevent_sweep=False)
self.multiworld.state.collect(self.create_item("Foraging Level"))
self.multiworld.state.collect(self.create_item("Farming Level"))
self.multiworld.state.collect(self.create_item("Mining Level"))
self.multiworld.state.collect(self.create_item("Combat Level"))
self.multiworld.state.collect(self.create_item("Progressive Mine Elevator"))
self.multiworld.state.collect(self.create_item("Progressive Mine Elevator"))
npc = "Abigail"
heart_name = f"{npc} <3"
step = 3
self.assert_can_reach_heart_up_to(npc, 3, step)
self.multiworld.state.collect(self.create_item(heart_name), prevent_sweep=False)
self.multiworld.state.collect(self.create_item(heart_name))
self.assert_can_reach_heart_up_to(npc, 6, step)
self.multiworld.state.collect(self.create_item(heart_name), prevent_sweep=False)
self.multiworld.state.collect(self.create_item(heart_name))
self.assert_can_reach_heart_up_to(npc, 8, step)
self.multiworld.state.collect(self.create_item(heart_name), prevent_sweep=False)
self.multiworld.state.collect(self.create_item(heart_name))
self.assert_can_reach_heart_up_to(npc, 10, step)
self.multiworld.state.collect(self.create_item(heart_name), prevent_sweep=False)
self.multiworld.state.collect(self.create_item(heart_name))
self.assert_can_reach_heart_up_to(npc, 14, step)
def assert_can_reach_heart_up_to(self, npc: str, max_reachable: int, step: int):

View File

@ -76,7 +76,7 @@ class TestShipsanityEverything(SVTestBase):
with self.subTest(location.name):
self.remove(bin_item)
self.assertFalse(self.world.logic.region.can_reach_location(location.name)(self.multiworld.state))
self.multiworld.state.collect(bin_item, prevent_sweep=False)
self.multiworld.state.collect(bin_item)
shipsanity_rule = self.world.logic.region.can_reach_location(location.name)
self.assert_rule_true(shipsanity_rule, self.multiworld.state)
self.remove(bin_item)

View File

@ -1,12 +1,22 @@
import unittest
from BaseClasses import ItemClassification
from ...test import solo_multiworld
from .. import SVTestBase, allsanity_mods_6_x_x
from ...stardew_rule import HasProgressionPercent
class TestHasProgressionPercent(unittest.TestCase):
def test_max_item_amount_is_full_collection(self):
# Not caching because it fails too often for some reason
with solo_multiworld(world_caching=False) as (multiworld, world):
progression_item_count = sum(1 for i in multiworld.get_items() if i.classification & ItemClassification.progression)
self.assertEqual(world.total_progression_items, progression_item_count - 1) # -1 to skip Victory
class TestHasProgressionPercentWithVictory(SVTestBase):
options = allsanity_mods_6_x_x()
def test_has_100_progression_percent_is_false_while_items_are_missing(self):
has_100_progression_percent = HasProgressionPercent(1, 100)
for i, item in enumerate([i for i in self.multiworld.get_items() if i.advancement and i.code][1:]):
if item.name != "Victory":
self.collect(item)
self.assertFalse(has_100_progression_percent(self.multiworld.state),
f"Rule became true after {i} items, total_progression_items is {self.world.total_progression_items}")
def test_has_100_progression_percent_account_for_victory_not_being_collected(self):
has_100_progression_percent = HasProgressionPercent(1, 100)
self.collect_all_except("Victory")
self.assert_rule_true(has_100_progression_percent, self.multiworld.state)

View File

@ -21,30 +21,30 @@ class TestProgressiveToolsLogic(SVTestBase):
self.assert_rule_false(sturgeon_rule, self.multiworld.state)
summer = self.create_item("Summer")
self.multiworld.state.collect(summer, prevent_sweep=False)
self.multiworld.state.collect(summer)
self.assert_rule_false(sturgeon_rule, self.multiworld.state)
fishing_rod = self.create_item("Progressive Fishing Rod")
self.multiworld.state.collect(fishing_rod, prevent_sweep=False)
self.multiworld.state.collect(fishing_rod, prevent_sweep=False)
self.multiworld.state.collect(fishing_rod)
self.multiworld.state.collect(fishing_rod)
self.assert_rule_false(sturgeon_rule, self.multiworld.state)
fishing_level = self.create_item("Fishing Level")
self.multiworld.state.collect(fishing_level, prevent_sweep=False)
self.multiworld.state.collect(fishing_level)
self.assert_rule_false(sturgeon_rule, self.multiworld.state)
self.multiworld.state.collect(fishing_level, prevent_sweep=False)
self.multiworld.state.collect(fishing_level, prevent_sweep=False)
self.multiworld.state.collect(fishing_level, prevent_sweep=False)
self.multiworld.state.collect(fishing_level, prevent_sweep=False)
self.multiworld.state.collect(fishing_level, prevent_sweep=False)
self.multiworld.state.collect(fishing_level)
self.multiworld.state.collect(fishing_level)
self.multiworld.state.collect(fishing_level)
self.multiworld.state.collect(fishing_level)
self.multiworld.state.collect(fishing_level)
self.assert_rule_true(sturgeon_rule, self.multiworld.state)
self.remove(summer)
self.assert_rule_false(sturgeon_rule, self.multiworld.state)
winter = self.create_item("Winter")
self.multiworld.state.collect(winter, prevent_sweep=False)
self.multiworld.state.collect(winter)
self.assert_rule_true(sturgeon_rule, self.multiworld.state)
self.remove(fishing_rod)
@ -53,24 +53,24 @@ class TestProgressiveToolsLogic(SVTestBase):
def test_old_master_cannoli(self):
self.multiworld.state.prog_items = {1: Counter()}
self.multiworld.state.collect(self.create_item("Progressive Axe"), prevent_sweep=False)
self.multiworld.state.collect(self.create_item("Progressive Axe"), prevent_sweep=False)
self.multiworld.state.collect(self.create_item("Summer"), prevent_sweep=False)
self.multiworld.state.collect(self.create_item("Progressive Axe"))
self.multiworld.state.collect(self.create_item("Progressive Axe"))
self.multiworld.state.collect(self.create_item("Summer"))
self.collect_lots_of_money()
rule = self.world.logic.region.can_reach_location("Old Master Cannoli")
self.assert_rule_false(rule, self.multiworld.state)
fall = self.create_item("Fall")
self.multiworld.state.collect(fall, prevent_sweep=False)
self.multiworld.state.collect(fall)
self.assert_rule_false(rule, self.multiworld.state)
tuesday = self.create_item("Traveling Merchant: Tuesday")
self.multiworld.state.collect(tuesday, prevent_sweep=False)
self.multiworld.state.collect(tuesday)
self.assert_rule_false(rule, self.multiworld.state)
rare_seed = self.create_item("Rare Seed")
self.multiworld.state.collect(rare_seed, prevent_sweep=False)
self.multiworld.state.collect(rare_seed)
self.assert_rule_true(rule, self.multiworld.state)
self.remove(fall)
@ -80,11 +80,11 @@ class TestProgressiveToolsLogic(SVTestBase):
green_house = self.create_item("Greenhouse")
self.collect(self.create_item(Event.fall_farming))
self.multiworld.state.collect(green_house, prevent_sweep=False)
self.multiworld.state.collect(green_house)
self.assert_rule_false(rule, self.multiworld.state)
friday = self.create_item("Traveling Merchant: Friday")
self.multiworld.state.collect(friday, prevent_sweep=False)
self.multiworld.state.collect(friday)
self.assertTrue(self.multiworld.get_location("Old Master Cannoli", 1).access_rule(self.multiworld.state))
self.remove(green_house)
@ -111,7 +111,7 @@ class TestToolVanillaRequiresBlacksmith(SVTestBase):
for material in [ToolMaterial.copper, ToolMaterial.iron, ToolMaterial.gold, ToolMaterial.iridium]:
self.assert_rule_false(self.world.logic.tool.has_tool(tool, material), self.multiworld.state)
self.multiworld.state.collect(self.create_item(railroad_item), prevent_sweep=False)
self.multiworld.state.collect(self.create_item(railroad_item))
for tool in [Tool.pickaxe, Tool.axe, Tool.hoe, Tool.trash_can, Tool.watering_can]:
for material in [ToolMaterial.copper, ToolMaterial.iron, ToolMaterial.gold, ToolMaterial.iridium]:
@ -125,7 +125,7 @@ class TestToolVanillaRequiresBlacksmith(SVTestBase):
for fishing_rod_level in [3, 4]:
self.assert_rule_false(self.world.logic.tool.has_fishing_rod(fishing_rod_level), self.multiworld.state)
self.multiworld.state.collect(self.create_item(railroad_item), prevent_sweep=False)
self.multiworld.state.collect(self.create_item(railroad_item))
for fishing_rod_level in [3, 4]:
self.assert_rule_true(self.world.logic.tool.has_fishing_rod(fishing_rod_level), self.multiworld.state)

View File

@ -10,40 +10,40 @@ class TestWeaponsLogic(SVTestBase):
}
def test_mine(self):
self.multiworld.state.collect(self.create_item("Progressive Pickaxe"), prevent_sweep=True)
self.multiworld.state.collect(self.create_item("Progressive Pickaxe"), prevent_sweep=True)
self.multiworld.state.collect(self.create_item("Progressive Pickaxe"), prevent_sweep=True)
self.multiworld.state.collect(self.create_item("Progressive Pickaxe"), prevent_sweep=True)
self.multiworld.state.collect(self.create_item("Progressive House"), prevent_sweep=True)
self.multiworld.state.collect(self.create_item("Progressive Pickaxe"))
self.multiworld.state.collect(self.create_item("Progressive Pickaxe"))
self.multiworld.state.collect(self.create_item("Progressive Pickaxe"))
self.multiworld.state.collect(self.create_item("Progressive Pickaxe"))
self.multiworld.state.collect(self.create_item("Progressive House"))
self.collect([self.create_item("Combat Level")] * 10)
self.collect([self.create_item("Mining Level")] * 10)
self.collect([self.create_item("Progressive Mine Elevator")] * 24)
self.multiworld.state.collect(self.create_item("Bus Repair"), prevent_sweep=True)
self.multiworld.state.collect(self.create_item("Skull Key"), prevent_sweep=True)
self.multiworld.state.collect(self.create_item("Bus Repair"))
self.multiworld.state.collect(self.create_item("Skull Key"))
self.GiveItemAndCheckReachableMine("Progressive Sword", 1)
self.GiveItemAndCheckReachableMine("Progressive Dagger", 1)
self.GiveItemAndCheckReachableMine("Progressive Club", 1)
self.give_item_and_check_reachable_mine("Progressive Sword", 1)
self.give_item_and_check_reachable_mine("Progressive Dagger", 1)
self.give_item_and_check_reachable_mine("Progressive Club", 1)
self.GiveItemAndCheckReachableMine("Progressive Sword", 2)
self.GiveItemAndCheckReachableMine("Progressive Dagger", 2)
self.GiveItemAndCheckReachableMine("Progressive Club", 2)
self.give_item_and_check_reachable_mine("Progressive Sword", 2)
self.give_item_and_check_reachable_mine("Progressive Dagger", 2)
self.give_item_and_check_reachable_mine("Progressive Club", 2)
self.GiveItemAndCheckReachableMine("Progressive Sword", 3)
self.GiveItemAndCheckReachableMine("Progressive Dagger", 3)
self.GiveItemAndCheckReachableMine("Progressive Club", 3)
self.give_item_and_check_reachable_mine("Progressive Sword", 3)
self.give_item_and_check_reachable_mine("Progressive Dagger", 3)
self.give_item_and_check_reachable_mine("Progressive Club", 3)
self.GiveItemAndCheckReachableMine("Progressive Sword", 4)
self.GiveItemAndCheckReachableMine("Progressive Dagger", 4)
self.GiveItemAndCheckReachableMine("Progressive Club", 4)
self.give_item_and_check_reachable_mine("Progressive Sword", 4)
self.give_item_and_check_reachable_mine("Progressive Dagger", 4)
self.give_item_and_check_reachable_mine("Progressive Club", 4)
self.GiveItemAndCheckReachableMine("Progressive Sword", 5)
self.GiveItemAndCheckReachableMine("Progressive Dagger", 5)
self.GiveItemAndCheckReachableMine("Progressive Club", 5)
self.give_item_and_check_reachable_mine("Progressive Sword", 5)
self.give_item_and_check_reachable_mine("Progressive Dagger", 5)
self.give_item_and_check_reachable_mine("Progressive Club", 5)
def GiveItemAndCheckReachableMine(self, item_name: str, reachable_level: int):
def give_item_and_check_reachable_mine(self, item_name: str, reachable_level: int):
item = self.multiworld.create_item(item_name, self.player)
self.multiworld.state.collect(item, prevent_sweep=True)
self.multiworld.state.collect(item)
rule = self.world.logic.mine.can_mine_in_the_mines_floor_1_40()
if reachable_level > 0:
self.assert_rule_true(rule, self.multiworld.state)

View File

@ -7,9 +7,6 @@ import unittest
from BaseClasses import get_seed
from .. import SVTestCase
# There seems to be 4 bytes that appear at random at the end of the output, breaking the json... I don't know where they came from.
BYTES_TO_REMOVE = 4
# <function Location.<lambda> at 0x102ca98a0>
lambda_regex = re.compile(r"^<function Location\.<lambda> at (.*)>$")
@ -27,8 +24,8 @@ class TestGenerationIsStable(SVTestCase):
output_a = subprocess.check_output([sys.executable, '-m', 'worlds.stardew_valley.test.stability.StabilityOutputScript', '--seed', str(seed)])
output_b = subprocess.check_output([sys.executable, '-m', 'worlds.stardew_valley.test.stability.StabilityOutputScript', '--seed', str(seed)])
result_a = json.loads(output_a[:-BYTES_TO_REMOVE])
result_b = json.loads(output_b[:-BYTES_TO_REMOVE])
result_a = json.loads(output_a)
result_b = json.loads(output_b)
for i, ((room_a, bundles_a), (room_b, bundles_b)) in enumerate(zip(result_a["bundles"].items(), result_b["bundles"].items())):
self.assertEqual(room_a, room_b, f"Bundle rooms at index {i} is different between both executions. Seed={seed}")