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
17 changed files with 243 additions and 203 deletions

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}")