Archipelago/worlds/stardew_valley/test/TestRules.py

798 lines
39 KiB
Python

from collections import Counter
from . import SVTestBase
from .. import options, HasProgressionPercent
from ..data.craftable_data import all_crafting_recipes_by_name
from ..locations import locations_by_tag, LocationTags, location_table
from ..options import ToolProgression, BuildingProgression, ExcludeGingerIsland, Chefsanity, Craftsanity, Shipsanity, SeasonRandomization, Friendsanity, \
FriendsanityHeartSize, BundleRandomization, SkillProgression
from ..strings.entrance_names import Entrance
from ..strings.region_names import Region
from ..strings.tool_names import Tool, ToolMaterial
class TestProgressiveToolsLogic(SVTestBase):
options = {
ToolProgression.internal_name: ToolProgression.option_progressive,
SeasonRandomization.internal_name: SeasonRandomization.option_randomized,
}
def test_sturgeon(self):
self.multiworld.state.prog_items = {1: Counter()}
sturgeon_rule = self.world.logic.has("Sturgeon")
self.assert_rule_false(sturgeon_rule, self.multiworld.state)
summer = self.world.create_item("Summer")
self.multiworld.state.collect(summer, event=False)
self.assert_rule_false(sturgeon_rule, self.multiworld.state)
fishing_rod = self.world.create_item("Progressive Fishing Rod")
self.multiworld.state.collect(fishing_rod, event=False)
self.multiworld.state.collect(fishing_rod, event=False)
self.assert_rule_false(sturgeon_rule, self.multiworld.state)
fishing_level = self.world.create_item("Fishing Level")
self.multiworld.state.collect(fishing_level, event=False)
self.assert_rule_false(sturgeon_rule, self.multiworld.state)
self.multiworld.state.collect(fishing_level, event=False)
self.multiworld.state.collect(fishing_level, event=False)
self.multiworld.state.collect(fishing_level, event=False)
self.multiworld.state.collect(fishing_level, event=False)
self.multiworld.state.collect(fishing_level, event=False)
self.assert_rule_true(sturgeon_rule, self.multiworld.state)
self.remove(summer)
self.assert_rule_false(sturgeon_rule, self.multiworld.state)
winter = self.world.create_item("Winter")
self.multiworld.state.collect(winter, event=False)
self.assert_rule_true(sturgeon_rule, self.multiworld.state)
self.remove(fishing_rod)
self.assert_rule_false(sturgeon_rule, self.multiworld.state)
def test_old_master_cannoli(self):
self.multiworld.state.prog_items = {1: Counter()}
self.multiworld.state.collect(self.world.create_item("Progressive Axe"), event=False)
self.multiworld.state.collect(self.world.create_item("Progressive Axe"), event=False)
self.multiworld.state.collect(self.world.create_item("Summer"), event=False)
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.world.create_item("Fall")
self.multiworld.state.collect(fall, event=False)
self.assert_rule_false(rule, self.multiworld.state)
tuesday = self.world.create_item("Traveling Merchant: Tuesday")
self.multiworld.state.collect(tuesday, event=False)
self.assert_rule_false(rule, self.multiworld.state)
rare_seed = self.world.create_item("Rare Seed")
self.multiworld.state.collect(rare_seed, event=False)
self.assert_rule_true(rule, self.multiworld.state)
self.remove(fall)
self.assert_rule_false(rule, self.multiworld.state)
self.remove(tuesday)
green_house = self.world.create_item("Greenhouse")
self.multiworld.state.collect(green_house, event=False)
self.assert_rule_false(rule, self.multiworld.state)
friday = self.world.create_item("Traveling Merchant: Friday")
self.multiworld.state.collect(friday, event=False)
self.assertTrue(self.multiworld.get_location("Old Master Cannoli", 1).access_rule(self.multiworld.state))
self.remove(green_house)
self.assert_rule_false(rule, self.multiworld.state)
self.remove(friday)
class TestBundlesLogic(SVTestBase):
options = {
BundleRandomization.internal_name: BundleRandomization.option_vanilla
}
def test_vault_2500g_bundle(self):
self.assertFalse(self.world.logic.region.can_reach_location("2,500g Bundle")(self.multiworld.state))
self.collect_lots_of_money()
self.assertTrue(self.world.logic.region.can_reach_location("2,500g Bundle")(self.multiworld.state))
class TestBuildingLogic(SVTestBase):
options = {
BuildingProgression.internal_name: BuildingProgression.option_progressive
}
def test_coop_blueprint(self):
self.assertFalse(self.world.logic.region.can_reach_location("Coop Blueprint")(self.multiworld.state))
self.collect_lots_of_money()
self.assertTrue(self.world.logic.region.can_reach_location("Coop Blueprint")(self.multiworld.state))
def test_big_coop_blueprint(self):
big_coop_blueprint_rule = self.world.logic.region.can_reach_location("Big Coop Blueprint")
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.collect_lots_of_money()
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.world.create_item("Can Construct Buildings"), event=True)
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.world.create_item("Progressive Coop"), event=False)
self.assertTrue(big_coop_blueprint_rule(self.multiworld.state),
f"Rule is {repr(self.multiworld.get_location('Big Coop Blueprint', self.player).access_rule)}")
def test_deluxe_coop_blueprint(self):
self.assertFalse(self.world.logic.region.can_reach_location("Deluxe Coop Blueprint")(self.multiworld.state))
self.collect_lots_of_money()
self.multiworld.state.collect(self.world.create_item("Can Construct Buildings"), event=True)
self.assertFalse(self.world.logic.region.can_reach_location("Deluxe Coop Blueprint")(self.multiworld.state))
self.multiworld.state.collect(self.world.create_item("Progressive Coop"), event=True)
self.assertFalse(self.world.logic.region.can_reach_location("Deluxe Coop Blueprint")(self.multiworld.state))
self.multiworld.state.collect(self.world.create_item("Progressive Coop"), event=True)
self.assertTrue(self.world.logic.region.can_reach_location("Deluxe Coop Blueprint")(self.multiworld.state))
def test_big_shed_blueprint(self):
big_shed_rule = self.world.logic.region.can_reach_location("Big Shed Blueprint")
self.assertFalse(big_shed_rule(self.multiworld.state),
f"Rule is {repr(self.multiworld.get_location('Big Shed Blueprint', self.player).access_rule)}")
self.collect_lots_of_money()
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.world.create_item("Can Construct Buildings"), event=True)
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.world.create_item("Progressive Shed"), event=True)
self.assertTrue(big_shed_rule(self.multiworld.state),
f"Rule is {repr(self.multiworld.get_location('Big Shed Blueprint', self.player).access_rule)}")
class TestArcadeMachinesLogic(SVTestBase):
options = {
options.ArcadeMachineLocations.internal_name: options.ArcadeMachineLocations.option_full_shuffling,
}
def test_prairie_king(self):
self.assertFalse(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))
self.assertFalse(self.world.logic.region.can_reach_location("Journey of the Prairie King Victory")(self.multiworld.state))
boots = self.world.create_item("JotPK: Progressive Boots")
gun = self.world.create_item("JotPK: Progressive Gun")
ammo = self.world.create_item("JotPK: Progressive Ammo")
life = self.world.create_item("JotPK: Extra Life")
drop = self.world.create_item("JotPK: Increased Drop Rate")
self.multiworld.state.collect(boots, event=True)
self.multiworld.state.collect(gun, event=True)
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))
self.assertFalse(self.world.logic.region.can_reach_location("Journey of the Prairie King Victory")(self.multiworld.state))
self.remove(boots)
self.remove(gun)
self.multiworld.state.collect(boots, event=True)
self.multiworld.state.collect(boots, event=True)
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))
self.assertFalse(self.world.logic.region.can_reach_location("Journey of the Prairie King Victory")(self.multiworld.state))
self.remove(boots)
self.remove(boots)
self.multiworld.state.collect(boots, event=True)
self.multiworld.state.collect(gun, event=True)
self.multiworld.state.collect(ammo, event=True)
self.multiworld.state.collect(life, event=True)
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))
self.assertFalse(self.world.logic.region.can_reach_location("Journey of the Prairie King Victory")(self.multiworld.state))
self.remove(boots)
self.remove(gun)
self.remove(ammo)
self.remove(life)
self.multiworld.state.collect(boots, event=True)
self.multiworld.state.collect(gun, event=True)
self.multiworld.state.collect(gun, event=True)
self.multiworld.state.collect(ammo, event=True)
self.multiworld.state.collect(ammo, event=True)
self.multiworld.state.collect(life, event=True)
self.multiworld.state.collect(drop, event=True)
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))
self.assertFalse(self.world.logic.region.can_reach_location("Journey of the Prairie King Victory")(self.multiworld.state))
self.remove(boots)
self.remove(gun)
self.remove(gun)
self.remove(ammo)
self.remove(ammo)
self.remove(life)
self.remove(drop)
self.multiworld.state.collect(boots, event=True)
self.multiworld.state.collect(boots, event=True)
self.multiworld.state.collect(gun, event=True)
self.multiworld.state.collect(gun, event=True)
self.multiworld.state.collect(gun, event=True)
self.multiworld.state.collect(gun, event=True)
self.multiworld.state.collect(ammo, event=True)
self.multiworld.state.collect(ammo, event=True)
self.multiworld.state.collect(ammo, event=True)
self.multiworld.state.collect(life, event=True)
self.multiworld.state.collect(drop, event=True)
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))
self.assertTrue(self.world.logic.region.can_reach_location("Journey of the Prairie King Victory")(self.multiworld.state))
self.remove(boots)
self.remove(boots)
self.remove(gun)
self.remove(gun)
self.remove(gun)
self.remove(gun)
self.remove(ammo)
self.remove(ammo)
self.remove(ammo)
self.remove(life)
self.remove(drop)
class TestWeaponsLogic(SVTestBase):
options = {
ToolProgression.internal_name: ToolProgression.option_progressive,
options.SkillProgression.internal_name: options.SkillProgression.option_progressive,
}
def test_mine(self):
self.multiworld.state.collect(self.world.create_item("Progressive Pickaxe"), event=True)
self.multiworld.state.collect(self.world.create_item("Progressive Pickaxe"), event=True)
self.multiworld.state.collect(self.world.create_item("Progressive Pickaxe"), event=True)
self.multiworld.state.collect(self.world.create_item("Progressive Pickaxe"), event=True)
self.collect([self.world.create_item("Combat Level")] * 10)
self.collect([self.world.create_item("Mining Level")] * 10)
self.collect([self.world.create_item("Progressive Mine Elevator")] * 24)
self.multiworld.state.collect(self.world.create_item("Bus Repair"), event=True)
self.multiworld.state.collect(self.world.create_item("Skull Key"), event=True)
self.GiveItemAndCheckReachableMine("Progressive Sword", 1)
self.GiveItemAndCheckReachableMine("Progressive Dagger", 1)
self.GiveItemAndCheckReachableMine("Progressive Club", 1)
self.GiveItemAndCheckReachableMine("Progressive Sword", 2)
self.GiveItemAndCheckReachableMine("Progressive Dagger", 2)
self.GiveItemAndCheckReachableMine("Progressive Club", 2)
self.GiveItemAndCheckReachableMine("Progressive Sword", 3)
self.GiveItemAndCheckReachableMine("Progressive Dagger", 3)
self.GiveItemAndCheckReachableMine("Progressive Club", 3)
self.GiveItemAndCheckReachableMine("Progressive Sword", 4)
self.GiveItemAndCheckReachableMine("Progressive Dagger", 4)
self.GiveItemAndCheckReachableMine("Progressive Club", 4)
self.GiveItemAndCheckReachableMine("Progressive Sword", 5)
self.GiveItemAndCheckReachableMine("Progressive Dagger", 5)
self.GiveItemAndCheckReachableMine("Progressive Club", 5)
def GiveItemAndCheckReachableMine(self, item_name: str, reachable_level: int):
item = self.multiworld.create_item(item_name, self.player)
self.multiworld.state.collect(item, event=True)
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)
else:
self.assert_rule_false(rule, self.multiworld.state)
rule = self.world.logic.mine.can_mine_in_the_mines_floor_41_80()
if reachable_level > 1:
self.assert_rule_true(rule, self.multiworld.state)
else:
self.assert_rule_false(rule, self.multiworld.state)
rule = self.world.logic.mine.can_mine_in_the_mines_floor_81_120()
if reachable_level > 2:
self.assert_rule_true(rule, self.multiworld.state)
else:
self.assert_rule_false(rule, self.multiworld.state)
rule = self.world.logic.mine.can_mine_in_the_skull_cavern()
if reachable_level > 3:
self.assert_rule_true(rule, self.multiworld.state)
else:
self.assert_rule_false(rule, self.multiworld.state)
rule = self.world.logic.ability.can_mine_perfectly_in_the_skull_cavern()
if reachable_level > 4:
self.assert_rule_true(rule, self.multiworld.state)
else:
self.assert_rule_false(rule, self.multiworld.state)
class TestRecipeLearnLogic(SVTestBase):
options = {
BuildingProgression.internal_name: BuildingProgression.option_progressive,
options.Cropsanity.internal_name: options.Cropsanity.option_enabled,
options.Cooksanity.internal_name: options.Cooksanity.option_all,
Chefsanity.internal_name: Chefsanity.option_none,
ExcludeGingerIsland.internal_name: ExcludeGingerIsland.option_true,
}
def test_can_learn_qos_recipe(self):
location = "Cook Radish Salad"
rule = self.world.logic.region.can_reach_location(location)
self.assert_rule_false(rule, self.multiworld.state)
self.multiworld.state.collect(self.world.create_item("Progressive House"), event=False)
self.multiworld.state.collect(self.world.create_item("Radish Seeds"), event=False)
self.multiworld.state.collect(self.world.create_item("Spring"), event=False)
self.multiworld.state.collect(self.world.create_item("Summer"), event=False)
self.collect_lots_of_money()
self.assert_rule_false(rule, self.multiworld.state)
self.multiworld.state.collect(self.world.create_item("The Queen of Sauce"), event=False)
self.assert_rule_true(rule, self.multiworld.state)
class TestRecipeReceiveLogic(SVTestBase):
options = {
BuildingProgression.internal_name: BuildingProgression.option_progressive,
options.Cropsanity.internal_name: options.Cropsanity.option_enabled,
options.Cooksanity.internal_name: options.Cooksanity.option_all,
Chefsanity.internal_name: Chefsanity.option_all,
ExcludeGingerIsland.internal_name: ExcludeGingerIsland.option_true,
}
def test_can_learn_qos_recipe(self):
location = "Cook Radish Salad"
rule = self.world.logic.region.can_reach_location(location)
self.assert_rule_false(rule, self.multiworld.state)
self.multiworld.state.collect(self.world.create_item("Progressive House"), event=False)
self.multiworld.state.collect(self.world.create_item("Radish Seeds"), event=False)
self.multiworld.state.collect(self.world.create_item("Summer"), event=False)
self.collect_lots_of_money()
self.assert_rule_false(rule, self.multiworld.state)
spring = self.world.create_item("Spring")
qos = self.world.create_item("The Queen of Sauce")
self.multiworld.state.collect(spring, event=False)
self.multiworld.state.collect(qos, event=False)
self.assert_rule_false(rule, self.multiworld.state)
self.multiworld.state.remove(spring)
self.multiworld.state.remove(qos)
self.multiworld.state.collect(self.world.create_item("Radish Salad Recipe"), event=False)
self.assert_rule_true(rule, self.multiworld.state)
def test_get_chefsanity_check_recipe(self):
location = "Radish Salad Recipe"
rule = self.world.logic.region.can_reach_location(location)
self.assert_rule_false(rule, self.multiworld.state)
self.multiworld.state.collect(self.world.create_item("Spring"), event=False)
self.collect_lots_of_money()
self.assert_rule_false(rule, self.multiworld.state)
seeds = self.world.create_item("Radish Seeds")
summer = self.world.create_item("Summer")
house = self.world.create_item("Progressive House")
self.multiworld.state.collect(seeds, event=False)
self.multiworld.state.collect(summer, event=False)
self.multiworld.state.collect(house, event=False)
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.world.create_item("The Queen of Sauce"), event=False)
self.assert_rule_true(rule, self.multiworld.state)
class TestCraftsanityLogic(SVTestBase):
options = {
BuildingProgression.internal_name: BuildingProgression.option_progressive,
options.Cropsanity.internal_name: options.Cropsanity.option_enabled,
Craftsanity.internal_name: Craftsanity.option_all,
ExcludeGingerIsland.internal_name: ExcludeGingerIsland.option_true,
}
def test_can_craft_recipe(self):
location = "Craft Marble Brazier"
rule = self.world.logic.region.can_reach_location(location)
self.collect([self.world.create_item("Progressive Pickaxe")] * 4)
self.collect([self.world.create_item("Progressive Fishing Rod")] * 4)
self.collect([self.world.create_item("Progressive Sword")] * 4)
self.collect([self.world.create_item("Progressive Mine Elevator")] * 24)
self.collect([self.world.create_item("Mining Level")] * 10)
self.collect([self.world.create_item("Combat Level")] * 10)
self.collect([self.world.create_item("Fishing Level")] * 10)
self.collect_all_the_money()
self.assert_rule_false(rule, self.multiworld.state)
self.multiworld.state.collect(self.world.create_item("Marble Brazier Recipe"), event=False)
self.assert_rule_true(rule, self.multiworld.state)
def test_can_learn_crafting_recipe(self):
location = "Marble Brazier Recipe"
rule = self.world.logic.region.can_reach_location(location)
self.assert_rule_false(rule, self.multiworld.state)
self.collect_lots_of_money()
self.assert_rule_true(rule, self.multiworld.state)
def test_can_craft_festival_recipe(self):
recipe = all_crafting_recipes_by_name["Jack-O-Lantern"]
self.multiworld.state.collect(self.world.create_item("Pumpkin Seeds"), event=False)
self.multiworld.state.collect(self.world.create_item("Torch Recipe"), event=False)
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.world.create_item("Fall"), event=False)
self.assert_rule_false(rule, self.multiworld.state)
self.multiworld.state.collect(self.world.create_item("Jack-O-Lantern Recipe"), event=False)
self.assert_rule_true(rule, self.multiworld.state)
class TestCraftsanityWithFestivalsLogic(SVTestBase):
options = {
BuildingProgression.internal_name: BuildingProgression.option_progressive,
options.Cropsanity.internal_name: options.Cropsanity.option_enabled,
options.FestivalLocations.internal_name: options.FestivalLocations.option_easy,
Craftsanity.internal_name: Craftsanity.option_all,
ExcludeGingerIsland.internal_name: ExcludeGingerIsland.option_true,
}
def test_can_craft_festival_recipe(self):
recipe = all_crafting_recipes_by_name["Jack-O-Lantern"]
self.multiworld.state.collect(self.world.create_item("Pumpkin Seeds"), event=False)
self.multiworld.state.collect(self.world.create_item("Fall"), event=False)
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.world.create_item("Jack-O-Lantern Recipe"), event=False)
self.assert_rule_false(rule, self.multiworld.state)
self.multiworld.state.collect(self.world.create_item("Torch Recipe"), event=False)
self.assert_rule_true(rule, self.multiworld.state)
class TestNoCraftsanityLogic(SVTestBase):
options = {
BuildingProgression.internal_name: BuildingProgression.option_progressive,
SeasonRandomization.internal_name: SeasonRandomization.option_progressive,
options.Cropsanity.internal_name: options.Cropsanity.option_enabled,
options.FestivalLocations.internal_name: options.FestivalLocations.option_disabled,
Craftsanity.internal_name: Craftsanity.option_none,
ExcludeGingerIsland.internal_name: ExcludeGingerIsland.option_true,
}
def test_can_craft_recipe(self):
recipe = all_crafting_recipes_by_name["Wood Floor"]
rule = self.world.logic.crafting.can_craft(recipe)
self.assert_rule_true(rule, self.multiworld.state)
def test_can_craft_festival_recipe(self):
recipe = all_crafting_recipes_by_name["Jack-O-Lantern"]
self.multiworld.state.collect(self.world.create_item("Pumpkin Seeds"), event=False)
self.collect_lots_of_money()
rule = self.world.logic.crafting.can_craft(recipe)
result = rule(self.multiworld.state)
self.assertFalse(result)
self.collect([self.world.create_item("Progressive Season")] * 2)
self.assert_rule_true(rule, self.multiworld.state)
class TestNoCraftsanityWithFestivalsLogic(SVTestBase):
options = {
BuildingProgression.internal_name: BuildingProgression.option_progressive,
options.Cropsanity.internal_name: options.Cropsanity.option_enabled,
options.FestivalLocations.internal_name: options.FestivalLocations.option_easy,
Craftsanity.internal_name: Craftsanity.option_none,
ExcludeGingerIsland.internal_name: ExcludeGingerIsland.option_true,
}
def test_can_craft_festival_recipe(self):
recipe = all_crafting_recipes_by_name["Jack-O-Lantern"]
self.multiworld.state.collect(self.world.create_item("Pumpkin Seeds"), event=False)
self.multiworld.state.collect(self.world.create_item("Fall"), event=False)
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.world.create_item("Jack-O-Lantern Recipe"), event=False)
self.assert_rule_true(rule, self.multiworld.state)
class TestDonationLogicAll(SVTestBase):
options = {
options.Museumsanity.internal_name: options.Museumsanity.option_all
}
def test_cannot_make_any_donation_without_museum_access(self):
railroad_item = "Railroad Boulder Removed"
swap_museum_and_bathhouse(self.multiworld, self.player)
collect_all_except(self.multiworld, railroad_item)
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.world.create_item(railroad_item), event=False)
for donation in locations_by_tag[LocationTags.MUSEUM_DONATIONS]:
self.assertTrue(self.world.logic.region.can_reach_location(donation.name)(self.multiworld.state))
class TestDonationLogicRandomized(SVTestBase):
options = {
options.Museumsanity.internal_name: options.Museumsanity.option_randomized
}
def test_cannot_make_any_donation_without_museum_access(self):
railroad_item = "Railroad Boulder Removed"
swap_museum_and_bathhouse(self.multiworld, self.player)
collect_all_except(self.multiworld, railroad_item)
donation_locations = [location for location in self.get_real_locations() if
LocationTags.MUSEUM_DONATIONS in location_table[location.name].tags]
for donation in donation_locations:
self.assertFalse(self.world.logic.region.can_reach_location(donation.name)(self.multiworld.state))
self.multiworld.state.collect(self.world.create_item(railroad_item), event=False)
for donation in donation_locations:
self.assertTrue(self.world.logic.region.can_reach_location(donation.name)(self.multiworld.state))
class TestDonationLogicMilestones(SVTestBase):
options = {
options.Museumsanity.internal_name: options.Museumsanity.option_milestones
}
def test_cannot_make_any_donation_without_museum_access(self):
railroad_item = "Railroad Boulder Removed"
swap_museum_and_bathhouse(self.multiworld, self.player)
collect_all_except(self.multiworld, railroad_item)
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.world.create_item(railroad_item), event=False)
for donation in locations_by_tag[LocationTags.MUSEUM_MILESTONES]:
self.assertTrue(self.world.logic.region.can_reach_location(donation.name)(self.multiworld.state))
def swap_museum_and_bathhouse(multiworld, player):
museum_region = multiworld.get_region(Region.museum, player)
bathhouse_region = multiworld.get_region(Region.bathhouse_entrance, player)
museum_entrance = multiworld.get_entrance(Entrance.town_to_museum, player)
bathhouse_entrance = multiworld.get_entrance(Entrance.enter_bathhouse_entrance, player)
museum_entrance.connect(bathhouse_region)
bathhouse_entrance.connect(museum_region)
class TestToolVanillaRequiresBlacksmith(SVTestBase):
options = {
options.EntranceRandomization: options.EntranceRandomization.option_buildings,
options.ToolProgression: options.ToolProgression.option_vanilla,
}
seed = 4111845104987680262
# Seed is hardcoded to make sure the ER is a valid roll that actually lock the blacksmith behind the Railroad Boulder Removed.
def test_cannot_get_any_tool_without_blacksmith_access(self):
railroad_item = "Railroad Boulder Removed"
place_region_at_entrance(self.multiworld, self.player, Region.blacksmith, Entrance.enter_bathhouse_entrance)
collect_all_except(self.multiworld, 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]:
self.assert_rule_false(self.world.logic.tool.has_tool(tool, material), self.multiworld.state)
self.multiworld.state.collect(self.world.create_item(railroad_item), event=False)
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]:
self.assert_rule_true(self.world.logic.tool.has_tool(tool, material), self.multiworld.state)
def test_cannot_get_fishing_rod_without_willy_access(self):
railroad_item = "Railroad Boulder Removed"
place_region_at_entrance(self.multiworld, self.player, Region.fish_shop, Entrance.enter_bathhouse_entrance)
collect_all_except(self.multiworld, railroad_item)
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.world.create_item(railroad_item), event=False)
for fishing_rod_level in [3, 4]:
self.assert_rule_true(self.world.logic.tool.has_fishing_rod(fishing_rod_level), self.multiworld.state)
def place_region_at_entrance(multiworld, player, region, entrance):
region_to_place = multiworld.get_region(region, player)
entrance_to_place_region = multiworld.get_entrance(entrance, player)
entrance_to_switch = region_to_place.entrances[0]
region_to_switch = entrance_to_place_region.connected_region
entrance_to_switch.connect(region_to_switch)
entrance_to_place_region.connect(region_to_place)
def collect_all_except(multiworld, item_to_not_collect: str):
for item in multiworld.get_items():
if item.name != item_to_not_collect:
multiworld.state.collect(item)
class TestFriendsanityDatingRules(SVTestBase):
options = {
SeasonRandomization.internal_name: SeasonRandomization.option_randomized_not_winter,
Friendsanity.internal_name: Friendsanity.option_all_with_marriage,
FriendsanityHeartSize.internal_name: 3
}
def test_earning_dating_heart_requires_dating(self):
self.collect_all_the_money()
self.multiworld.state.collect(self.world.create_item("Fall"), event=False)
self.multiworld.state.collect(self.world.create_item("Beach Bridge"), event=False)
self.multiworld.state.collect(self.world.create_item("Progressive House"), event=False)
for i in range(3):
self.multiworld.state.collect(self.world.create_item("Progressive Pickaxe"), event=False)
self.multiworld.state.collect(self.world.create_item("Progressive Weapon"), event=False)
self.multiworld.state.collect(self.world.create_item("Progressive Axe"), event=False)
self.multiworld.state.collect(self.world.create_item("Progressive Barn"), event=False)
for i in range(10):
self.multiworld.state.collect(self.world.create_item("Foraging Level"), event=False)
self.multiworld.state.collect(self.world.create_item("Farming Level"), event=False)
self.multiworld.state.collect(self.world.create_item("Mining Level"), event=False)
self.multiworld.state.collect(self.world.create_item("Combat Level"), event=False)
self.multiworld.state.collect(self.world.create_item("Progressive Mine Elevator"), event=False)
self.multiworld.state.collect(self.world.create_item("Progressive Mine Elevator"), event=False)
npc = "Abigail"
heart_name = f"{npc} <3"
step = 3
self.assert_can_reach_heart_up_to(npc, 3, step)
self.multiworld.state.collect(self.world.create_item(heart_name), event=False)
self.assert_can_reach_heart_up_to(npc, 6, step)
self.multiworld.state.collect(self.world.create_item(heart_name), event=False)
self.assert_can_reach_heart_up_to(npc, 8, step)
self.multiworld.state.collect(self.world.create_item(heart_name), event=False)
self.assert_can_reach_heart_up_to(npc, 10, step)
self.multiworld.state.collect(self.world.create_item(heart_name), event=False)
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):
prefix = "Friendsanity: "
suffix = " <3"
for i in range(1, max_reachable + 1):
if i % step != 0 and i != 14:
continue
location = f"{prefix}{npc} {i}{suffix}"
can_reach = self.world.logic.region.can_reach_location(location)(self.multiworld.state)
self.assertTrue(can_reach, f"Should be able to earn relationship up to {i} hearts")
for i in range(max_reachable + 1, 14 + 1):
if i % step != 0 and i != 14:
continue
location = f"{prefix}{npc} {i}{suffix}"
can_reach = self.world.logic.region.can_reach_location(location)(self.multiworld.state)
self.assertFalse(can_reach, f"Should not be able to earn relationship up to {i} hearts")
class TestShipsanityNone(SVTestBase):
options = {
Shipsanity.internal_name: Shipsanity.option_none
}
def test_no_shipsanity_locations(self):
for location in self.get_real_locations():
self.assertFalse("Shipsanity" in location.name)
self.assertNotIn(LocationTags.SHIPSANITY, location_table[location.name].tags)
class TestShipsanityCrops(SVTestBase):
options = {
Shipsanity.internal_name: Shipsanity.option_crops
}
def test_only_crop_shipsanity_locations(self):
for location in self.get_real_locations():
if LocationTags.SHIPSANITY in location_table[location.name].tags:
self.assertIn(LocationTags.SHIPSANITY_CROP, location_table[location.name].tags)
class TestShipsanityFish(SVTestBase):
options = {
Shipsanity.internal_name: Shipsanity.option_fish
}
def test_only_fish_shipsanity_locations(self):
for location in self.get_real_locations():
if LocationTags.SHIPSANITY in location_table[location.name].tags:
self.assertIn(LocationTags.SHIPSANITY_FISH, location_table[location.name].tags)
class TestShipsanityFullShipment(SVTestBase):
options = {
Shipsanity.internal_name: Shipsanity.option_full_shipment
}
def test_only_full_shipment_shipsanity_locations(self):
for location in self.get_real_locations():
if LocationTags.SHIPSANITY in location_table[location.name].tags:
self.assertIn(LocationTags.SHIPSANITY_FULL_SHIPMENT, location_table[location.name].tags)
self.assertNotIn(LocationTags.SHIPSANITY_FISH, location_table[location.name].tags)
class TestShipsanityFullShipmentWithFish(SVTestBase):
options = {
Shipsanity.internal_name: Shipsanity.option_full_shipment_with_fish
}
def test_only_full_shipment_and_fish_shipsanity_locations(self):
for location in self.get_real_locations():
if LocationTags.SHIPSANITY in location_table[location.name].tags:
self.assertTrue(LocationTags.SHIPSANITY_FULL_SHIPMENT in location_table[location.name].tags or
LocationTags.SHIPSANITY_FISH in location_table[location.name].tags)
class TestShipsanityEverything(SVTestBase):
options = {
Shipsanity.internal_name: Shipsanity.option_everything,
BuildingProgression.internal_name: BuildingProgression.option_progressive
}
def test_all_shipsanity_locations_require_shipping_bin(self):
bin_name = "Shipping Bin"
collect_all_except(self.multiworld, bin_name)
shipsanity_locations = [location for location in self.get_real_locations() if
LocationTags.SHIPSANITY in location_table[location.name].tags]
bin_item = self.world.create_item(bin_name)
for location in shipsanity_locations:
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, event=False)
shipsanity_rule = self.world.logic.region.can_reach_location(location.name)
self.assert_rule_true(shipsanity_rule, self.multiworld.state)
self.remove(bin_item)
class TestVanillaSkillLogicSimplification(SVTestBase):
options = {
SkillProgression.internal_name: SkillProgression.option_vanilla,
ToolProgression.internal_name: ToolProgression.option_progressive,
}
def test_skill_logic_has_level_only_uses_one_has_progression_percent(self):
rule = self.multiworld.worlds[1].logic.skill.has_level("Farming", 8)
self.assertEqual(1, sum(1 for i in rule.current_rules if type(i) == HasProgressionPercent))