Stardew Valley: implement new game (#1455)

* Stardew Valley Archipelago implementation

* fix breaking changes

* - Added and Updated Documentation for the game

* Removed fun

* Remove entire idea of step, due to possible inconsistency with the main AP core

* Commented out the desired steps, fix renaming after rebase

* Fixed wording

* tests now passes on 3.8

* run flake8

* remove dependency so apworld work again

* remove dependency for real

* - Fix Formatting in the Game Page
- Removed disabled Option Descriptions for Entrance Randomizer
- Improved Game Page's description of the Arcade Machine buffs
- Trimmed down the text on the Options page for Arcade Machines, so that it is smaller

* - Removed blankspace

* remove player field

* remove None check in options

* document the scripts

* fix pytest warning

* use importlib.resources.files

* fix

* add version requirement to importlib_resources

* remove __init__.py from data folder

* increment data version

* let the __init__.py for 3.9

* use sorted() instead of list()

* replace frozenset from fish_data with tuples

* remove dependency on pytest

* - Add a bit of text to the guide to tell them about how to redeem some received items

* - Added a comment about which mod version to use

* change single quotes for double quotes

* Minimum client version both ways

* Changed version number to be more specific. The mod will handle deciding

---------

Co-authored-by: Alex Gilbert <alexgilbert@yahoo.com>
This commit is contained in:
Jérémie Bolduc
2023-02-26 19:19:15 -05:00
committed by GitHub
parent 0286edf20c
commit af7d0dbf37
34 changed files with 5334 additions and 1 deletions

View File

@@ -0,0 +1,53 @@
import unittest
from test.general import setup_solo_multiworld
from .. import StardewValleyWorld
from ..bundle_data import all_bundle_items_except_money
from ..logic import MISSING_ITEM, _False
class TestAllLogicalItem(unittest.TestCase):
multi_world = setup_solo_multiworld(StardewValleyWorld)
world = multi_world.worlds[1]
logic = world.logic
def setUp(self) -> None:
for item in self.multi_world.get_items():
self.multi_world.state.collect(item, event=True)
def test_given_bundle_item_then_is_available_in_logic(self):
for bundle_item in all_bundle_items_except_money:
with self.subTest(bundle_item=bundle_item):
assert bundle_item.item.name in self.logic.item_rules
def test_given_item_rule_then_can_be_resolved(self):
for item in self.logic.item_rules.keys():
with self.subTest(item=item):
rule = self.logic.item_rules[item]
assert MISSING_ITEM not in repr(rule)
assert rule == _False() or rule(self.multi_world.state), f"Could not resolve rule for {item} {rule}"
def test_given_building_rule_then_can_be_resolved(self):
for item in self.logic.building_rules.keys():
with self.subTest(item=item):
rule = self.logic.building_rules[item]
assert MISSING_ITEM not in repr(rule)
assert rule == _False() or rule(self.multi_world.state), f"Could not resolve rule for {item} {rule}"
def test_given_quest_rule_then_can_be_resolved(self):
for item in self.logic.quest_rules.keys():
with self.subTest(item=item):
rule = self.logic.quest_rules[item]
assert MISSING_ITEM not in repr(rule)
assert rule == _False() or rule(self.multi_world.state), f"Could not resolve rule for {item} {rule}"
def test_given_location_rule_then_can_be_resolved(self):
for location in self.multi_world.get_locations(1):
with self.subTest(location=location):
rule = location.access_rule
assert MISSING_ITEM not in repr(rule)
assert rule == _False() or rule(self.multi_world.state), f"Could not resolve rule for {location} {rule}"

View File

@@ -0,0 +1,16 @@
import unittest
from ..bundle_data import all_bundle_items
class TestBundles(unittest.TestCase):
def test_all_bundle_items_have_3_parts(self):
for bundle_item in all_bundle_items:
name = bundle_item.item.name
assert len(name) > 0
id = bundle_item.item.item_id
assert (id > 0 or id == -1)
amount = bundle_item.amount
assert amount > 0
quality = bundle_item.quality
assert quality >= 0

View File

@@ -0,0 +1,20 @@
import unittest
from ..items import load_item_csv
from ..locations import load_location_csv
class TestCsvIntegrity(unittest.TestCase):
def test_items_integrity(self):
items = load_item_csv()
for item in items:
assert item.code_without_offset is not None, \
"Some item do not have an id. Run the script `update_data.py` to generate them."
def test_locations_integrity(self):
locations = load_location_csv()
for location in locations:
assert location.code_without_offset is not None, \
"Some location do not have an id. Run the script `update_data.py` to generate them."

View File

@@ -0,0 +1,127 @@
from BaseClasses import ItemClassification
from . import SVTestBase
from .. import locations, items, location_table, options
from ..items import items_by_group, Group
from ..locations import LocationTags
class TestBaseItemGeneration(SVTestBase):
def test_all_progression_items_are_added_to_the_pool(self):
for classification in [ItemClassification.progression, ItemClassification.useful]:
with self.subTest(classification=classification):
all_classified_items = {self.world.create_item(item)
for item in items.items_by_group[items.Group.COMMUNITY_REWARD]
if item.classification is classification}
for item in all_classified_items:
assert item in self.multiworld.itempool
def test_creates_as_many_item_as_non_event_locations(self):
non_event_locations = [location for location in self.multiworld.get_locations(self.player) if
not location.event]
assert len(non_event_locations), len(self.multiworld.itempool)
class TestGivenProgressiveBackpack(SVTestBase):
options = {options.BackpackProgression.internal_name: options.BackpackProgression.option_progressive}
def test_when_generate_world_then_two_progressive_backpack_are_added(self):
assert self.multiworld.itempool.count(self.world.create_item("Progressive Backpack")) == 2
def test_when_generate_world_then_backpack_locations_are_added(self):
created_locations = {location.name for location in self.multiworld.get_locations(1)}
assert all(location.name in created_locations for location in locations.locations_by_tag[LocationTags.BACKPACK])
class TestRemixedMineRewards(SVTestBase):
def test_when_generate_world_then_one_reward_is_added_per_chest(self):
# assert self.world.create_item("Rusty Sword") in self.multiworld.itempool
assert any(self.world.create_item(item) in self.multiworld.itempool
for item in items_by_group[Group.MINES_FLOOR_10])
assert any(self.world.create_item(item) in self.multiworld.itempool
for item in items_by_group[Group.MINES_FLOOR_20])
assert self.world.create_item("Slingshot") in self.multiworld.itempool
assert any(self.world.create_item(item) in self.multiworld.itempool
for item in items_by_group[Group.MINES_FLOOR_50])
assert any(self.world.create_item(item) in self.multiworld.itempool
for item in items_by_group[Group.MINES_FLOOR_60])
assert self.world.create_item("Master Slingshot") in self.multiworld.itempool
assert any(self.world.create_item(item) in self.multiworld.itempool
for item in items_by_group[Group.MINES_FLOOR_80])
assert any(self.world.create_item(item) in self.multiworld.itempool
for item in items_by_group[Group.MINES_FLOOR_90])
assert self.world.create_item("Stardrop") in self.multiworld.itempool
assert any(self.world.create_item(item) in self.multiworld.itempool
for item in items_by_group[Group.MINES_FLOOR_110])
assert self.world.create_item("Skull Key") in self.multiworld.itempool
# This test as 1 over 90,000 changes to fail... Sorry in advance
def test_when_generate_world_then_rewards_are_not_all_vanilla(self):
assert not all(self.world.create_item(item) in self.multiworld.itempool
for item in
["Leather Boots", "Steel Smallsword", "Tundra Boots", "Crystal Dagger", "Firewalker Boots",
"Obsidian Edge", "Space Boots"])
class TestProgressiveElevator(SVTestBase):
options = {
options.TheMinesElevatorsProgression.internal_name: options.TheMinesElevatorsProgression.option_progressive,
options.ToolProgression.internal_name: options.ToolProgression.option_progressive,
options.SkillProgression.internal_name: options.SkillProgression.option_progressive,
}
def test_given_access_to_floor_115_when_find_another_elevator_then_has_access_to_floor_120(self):
self.collect([self.get_item_by_name("Progressive Pickaxe")] * 2)
self.collect([self.get_item_by_name("Progressive Mine Elevator")] * 22)
self.collect(self.multiworld.create_item("Bone Sword", self.player))
self.collect([self.get_item_by_name("Combat Level")] * 4)
self.collect(self.get_item_by_name("Adventurer's Guild"))
assert not self.multiworld.get_region("The Mines - Floor 120", self.player).can_reach(self.multiworld.state)
self.collect(self.get_item_by_name("Progressive Mine Elevator"))
assert self.multiworld.get_region("The Mines - Floor 120", self.player).can_reach(self.multiworld.state)
def test_given_access_to_floor_115_when_find_another_pickaxe_and_sword_then_has_access_to_floor_120(self):
self.collect([self.get_item_by_name("Progressive Pickaxe")] * 2)
self.collect([self.get_item_by_name("Progressive Mine Elevator")] * 22)
self.collect(self.multiworld.create_item("Bone Sword", self.player))
self.collect([self.get_item_by_name("Combat Level")] * 4)
self.collect(self.get_item_by_name("Adventurer's Guild"))
assert not self.multiworld.get_region("The Mines - Floor 120", self.player).can_reach(self.multiworld.state)
self.collect(self.get_item_by_name("Progressive Pickaxe"))
self.collect(self.multiworld.create_item("Steel Falchion", self.player))
self.collect(self.get_item_by_name("Combat Level"))
self.collect(self.get_item_by_name("Combat Level"))
assert self.multiworld.get_region("The Mines - Floor 120", self.player).can_reach(self.multiworld.state)
class TestLocationGeneration(SVTestBase):
def test_all_location_created_are_in_location_table(self):
for location in self.multiworld.get_locations(self.player):
if not location.event:
assert location.name in location_table
class TestLocationAndItemCount(SVTestBase):
options = {
options.BackpackProgression.internal_name: options.BackpackProgression.option_vanilla,
options.ToolProgression.internal_name: options.ToolProgression.option_vanilla,
options.TheMinesElevatorsProgression.internal_name: options.TheMinesElevatorsProgression.option_vanilla,
options.SkillProgression.internal_name: options.SkillProgression.option_vanilla,
options.BuildingProgression.internal_name: options.BuildingProgression.option_vanilla,
options.ArcadeMachineLocations.internal_name: options.ArcadeMachineLocations.option_disabled,
options.HelpWantedLocations.internal_name: 0,
options.NumberOfPlayerBuffs.internal_name: 12,
}
def test_minimal_location_maximal_items_still_valid(self):
assert len(self.multiworld.get_locations()) >= len(self.multiworld.get_items())

View File

@@ -0,0 +1,26 @@
import unittest
from BaseClasses import MultiWorld
from .. import StardewValleyWorld
from ..items import item_table
class TestItems(unittest.TestCase):
def test_can_create_item_of_resource_pack(self):
item_name = "Resource Pack: 500 Money"
multi_world = MultiWorld(1)
multi_world.game[1] = "Stardew Valley"
multi_world.player_name = {1: "Tester"}
world = StardewValleyWorld(multi_world, 1)
item = world.create_item(item_name)
assert item.name == item_name
def test_items_table_footprint_is_between_717000_and_727000(self):
item_with_lowest_id = min((item for item in item_table.values() if item.code is not None), key=lambda x: x.code)
item_with_highest_id = max((item for item in item_table.values() if item.code is not None),
key=lambda x: x.code)
assert item_with_lowest_id.code >= 717000
assert item_with_highest_id.code < 727000

View File

@@ -0,0 +1,293 @@
from . import SVTestBase
from .. import options
class TestProgressiveToolsLogic(SVTestBase):
options = {
options.ToolProgression.internal_name: options.ToolProgression.option_progressive,
}
def test_sturgeon(self):
assert not self.world.logic.has("Sturgeon")(self.multiworld.state)
summer = self.get_item_by_name("Summer")
self.multiworld.state.collect(summer, event=True)
assert not self.world.logic.has("Sturgeon")(self.multiworld.state)
fishing_rod = self.get_item_by_name("Progressive Fishing Rod")
self.multiworld.state.collect(fishing_rod, event=True)
self.multiworld.state.collect(fishing_rod, event=True)
assert not self.world.logic.has("Sturgeon")(self.multiworld.state)
fishing_level = self.get_item_by_name("Fishing Level")
self.multiworld.state.collect(fishing_level, event=True)
assert not self.world.logic.has("Sturgeon")(self.multiworld.state)
self.multiworld.state.collect(fishing_level, event=True)
self.multiworld.state.collect(fishing_level, event=True)
self.multiworld.state.collect(fishing_level, event=True)
self.multiworld.state.collect(fishing_level, event=True)
self.multiworld.state.collect(fishing_level, event=True)
assert self.world.logic.has("Sturgeon")(self.multiworld.state)
self.remove(summer)
assert not self.world.logic.has("Sturgeon")(self.multiworld.state)
winter = self.get_item_by_name("Winter")
self.multiworld.state.collect(winter, event=True)
assert self.world.logic.has("Sturgeon")(self.multiworld.state)
self.remove(fishing_rod)
assert not self.world.logic.has("Sturgeon")(self.multiworld.state)
def test_old_master_cannoli(self):
self.multiworld.state.collect(self.get_item_by_name("Progressive Axe"), event=True)
self.multiworld.state.collect(self.get_item_by_name("Progressive Axe"), event=True)
assert not self.world.logic.can_reach_location("Old Master Cannoli")(self.multiworld.state)
fall = self.get_item_by_name("Fall")
self.multiworld.state.collect(fall, event=True)
assert not self.world.logic.can_reach_location("Old Master Cannoli")(self.multiworld.state)
tuesday = self.get_item_by_name("Traveling Merchant: Tuesday")
self.multiworld.state.collect(tuesday, event=True)
assert self.world.logic.can_reach_location("Old Master Cannoli")(self.multiworld.state)
self.remove(fall)
assert not self.world.logic.can_reach_location("Old Master Cannoli")(self.multiworld.state)
self.remove(tuesday)
green_house = self.get_item_by_name("Greenhouse")
self.multiworld.state.collect(green_house, event=True)
assert not self.world.logic.can_reach_location("Old Master Cannoli")(self.multiworld.state)
friday = self.get_item_by_name("Traveling Merchant: Friday")
self.multiworld.state.collect(friday, event=True)
assert self.world.logic.can_reach_location("Old Master Cannoli")(self.multiworld.state)
self.remove(green_house)
assert not self.world.logic.can_reach_location("Old Master Cannoli")(self.multiworld.state)
self.remove(friday)
class TestBundlesLogic(SVTestBase):
options = {
}
def test_vault_2500g_bundle(self):
assert not self.world.logic.can_reach_location("2,500g Bundle")(self.multiworld.state)
summer = self.get_item_by_name("Summer")
self.multiworld.state.collect(summer, event=True)
assert self.world.logic.can_reach_location("2,500g Bundle")(self.multiworld.state)
class TestBuildingLogic(SVTestBase):
options = {
options.BuildingProgression.internal_name: options.BuildingProgression.option_progressive_early_shipping_bin
}
def test_coop_blueprint(self):
assert not self.world.logic.can_reach_location("Coop Blueprint")(self.multiworld.state)
summer = self.get_item_by_name("Summer")
self.multiworld.state.collect(summer, event=True)
assert self.world.logic.can_reach_location("Coop Blueprint")(self.multiworld.state)
def test_big_coop_blueprint(self):
assert not self.world.logic.can_reach_location("Big Coop Blueprint")(self.multiworld.state), \
f"Rule is {repr(self.multiworld.get_location('Big Coop Blueprint', self.player).access_rule)}"
self.multiworld.state.collect(self.get_item_by_name("Fall"), event=True)
assert not self.world.logic.can_reach_location("Big Coop Blueprint")(self.multiworld.state), \
f"Rule is {repr(self.multiworld.get_location('Big Coop Blueprint', self.player).access_rule)}"
self.multiworld.state.collect(self.get_item_by_name("Progressive Coop"), event=True)
assert self.world.logic.can_reach_location("Big Coop Blueprint")(self.multiworld.state), \
f"Rule is {repr(self.multiworld.get_location('Big Coop Blueprint', self.player).access_rule)}"
def test_deluxe_big_coop_blueprint(self):
assert not self.world.logic.can_reach_location("Deluxe Coop Blueprint")(self.multiworld.state)
self.multiworld.state.collect(self.get_item_by_name("Year Two"), event=True)
assert not self.world.logic.can_reach_location("Deluxe Coop Blueprint")(self.multiworld.state)
self.multiworld.state.collect(self.get_item_by_name("Progressive Coop"), event=True)
assert not self.world.logic.can_reach_location("Deluxe Coop Blueprint")(self.multiworld.state)
self.multiworld.state.collect(self.get_item_by_name("Progressive Coop"), event=True)
assert self.world.logic.can_reach_location("Deluxe Coop Blueprint")(self.multiworld.state)
def test_big_shed_blueprint(self):
assert not self.world.logic.can_reach_location("Big Shed Blueprint")(self.multiworld.state), \
f"Rule is {repr(self.multiworld.get_location('Big Shed Blueprint', self.player).access_rule)}"
self.multiworld.state.collect(self.get_item_by_name("Year Two"), event=True)
assert not self.world.logic.can_reach_location("Big Shed Blueprint")(self.multiworld.state), \
f"Rule is {repr(self.multiworld.get_location('Big Shed Blueprint', self.player).access_rule)}"
self.multiworld.state.collect(self.get_item_by_name("Progressive Shed"), event=True)
assert self.world.logic.can_reach_location("Big Shed Blueprint")(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):
assert not self.world.logic.can_reach_region("JotPK World 1")(self.multiworld.state)
assert not self.world.logic.can_reach_region("JotPK World 2")(self.multiworld.state)
assert not self.world.logic.can_reach_region("JotPK World 3")(self.multiworld.state)
assert not self.world.logic.can_reach_location("Journey of the Prairie King Victory")(self.multiworld.state)
boots = self.get_item_by_name("JotPK: Progressive Boots")
gun = self.get_item_by_name("JotPK: Progressive Gun")
ammo = self.get_item_by_name("JotPK: Progressive Ammo")
life = self.get_item_by_name("JotPK: Extra Life")
drop = self.get_item_by_name("JotPK: Increased Drop Rate")
self.multiworld.state.collect(boots, event=True)
self.multiworld.state.collect(gun, event=True)
assert self.world.logic.can_reach_region("JotPK World 1")(self.multiworld.state)
assert not self.world.logic.can_reach_region("JotPK World 2")(self.multiworld.state)
assert not self.world.logic.can_reach_region("JotPK World 3")(self.multiworld.state)
assert not self.world.logic.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)
assert self.world.logic.can_reach_region("JotPK World 1")(self.multiworld.state)
assert not self.world.logic.can_reach_region("JotPK World 2")(self.multiworld.state)
assert not self.world.logic.can_reach_region("JotPK World 3")(self.multiworld.state)
assert not self.world.logic.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)
assert self.world.logic.can_reach_region("JotPK World 1")(self.multiworld.state)
assert self.world.logic.can_reach_region("JotPK World 2")(self.multiworld.state)
assert not self.world.logic.can_reach_region("JotPK World 3")(self.multiworld.state)
assert not self.world.logic.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)
assert self.world.logic.can_reach_region("JotPK World 1")(self.multiworld.state)
assert self.world.logic.can_reach_region("JotPK World 2")(self.multiworld.state)
assert self.world.logic.can_reach_region("JotPK World 3")(self.multiworld.state)
assert not self.world.logic.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)
assert self.world.logic.can_reach_region("JotPK World 1")(self.multiworld.state)
assert self.world.logic.can_reach_region("JotPK World 2")(self.multiworld.state)
assert self.world.logic.can_reach_region("JotPK World 3")(self.multiworld.state)
assert self.world.logic.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 = {
options.ToolProgression.internal_name: options.ToolProgression.option_progressive,
options.SkillProgression.internal_name: options.SkillProgression.option_progressive,
}
def test_mine(self):
self.collect(self.get_item_by_name("Adventurer's Guild"))
self.multiworld.state.collect(self.get_item_by_name("Progressive Pickaxe"), event=True)
self.multiworld.state.collect(self.get_item_by_name("Progressive Pickaxe"), event=True)
self.multiworld.state.collect(self.get_item_by_name("Progressive Pickaxe"), event=True)
self.multiworld.state.collect(self.get_item_by_name("Progressive Pickaxe"), event=True)
self.collect([self.get_item_by_name("Combat Level")] * 10)
self.collect([self.get_item_by_name("Progressive Mine Elevator")] * 24)
self.multiworld.state.collect(self.get_item_by_name("Bus Repair"), event=True)
self.multiworld.state.collect(self.get_item_by_name("Skull Key"), event=True)
self.GiveItemAndCheckReachableMine("Rusty Sword", 1)
self.GiveItemAndCheckReachableMine("Wooden Blade", 1)
self.GiveItemAndCheckReachableMine("Elf Blade", 1)
self.GiveItemAndCheckReachableMine("Silver Saber", 2)
self.GiveItemAndCheckReachableMine("Crystal Dagger", 2)
self.GiveItemAndCheckReachableMine("Claymore", 3)
self.GiveItemAndCheckReachableMine("Obsidian Edge", 3)
self.GiveItemAndCheckReachableMine("Bone Sword", 3)
self.GiveItemAndCheckReachableMine("The Slammer", 4)
self.GiveItemAndCheckReachableMine("Lava Katana", 4)
self.GiveItemAndCheckReachableMine("Galaxy Sword", 5)
self.GiveItemAndCheckReachableMine("Galaxy Hammer", 5)
self.GiveItemAndCheckReachableMine("Galaxy Dagger", 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)
if reachable_level > 0:
assert self.world.logic.can_mine_in_the_mines_floor_1_40()(self.multiworld.state)
else:
assert not self.world.logic.can_mine_in_the_mines_floor_1_40()(self.multiworld.state)
if reachable_level > 1:
assert self.world.logic.can_mine_in_the_mines_floor_41_80()(self.multiworld.state)
else:
assert not self.world.logic.can_mine_in_the_mines_floor_41_80()(self.multiworld.state)
if reachable_level > 2:
assert self.world.logic.can_mine_in_the_mines_floor_81_120()(self.multiworld.state)
else:
assert not self.world.logic.can_mine_in_the_mines_floor_81_120()(self.multiworld.state)
if reachable_level > 3:
assert self.world.logic.can_mine_in_the_skull_cavern()(self.multiworld.state)
else:
assert not self.world.logic.can_mine_in_the_skull_cavern()(self.multiworld.state)
if reachable_level > 4:
assert self.world.logic.can_mine_perfectly_in_the_skull_cavern()(self.multiworld.state)
else:
assert not self.world.logic.can_mine_perfectly_in_the_skull_cavern()(self.multiworld.state)
self.remove(item)

View File

@@ -0,0 +1,52 @@
import unittest
from .. import _True
from ..logic import _Received, _Has, _False, _And, _Or
class TestLogicSimplification(unittest.TestCase):
def test_simplify_true_in_and(self):
rules = {
"Wood": _True(),
"Rock": _True(),
}
summer = _Received("Summer", 0, 1)
assert (_Has("Wood", rules) & summer & _Has("Rock", rules)).simplify() == summer
def test_simplify_false_in_or(self):
rules = {
"Wood": _False(),
"Rock": _False(),
}
summer = _Received("Summer", 0, 1)
assert (_Has("Wood", rules) | summer | _Has("Rock", rules)).simplify() == summer
def test_simplify_and_in_and(self):
rule = _And(_And(_Received("Summer", 0, 1), _Received("Fall", 0, 1)),
_And(_Received("Winter", 0, 1), _Received("Spring", 0, 1)))
assert rule.simplify() == _And(_Received("Summer", 0, 1), _Received("Fall", 0, 1), _Received("Winter", 0, 1),
_Received("Spring", 0, 1))
def test_simplify_duplicated_and(self):
rule = _And(_And(_Received("Summer", 0, 1), _Received("Fall", 0, 1)),
_And(_Received("Summer", 0, 1), _Received("Fall", 0, 1)))
assert rule.simplify() == _And(_Received("Summer", 0, 1), _Received("Fall", 0, 1))
def test_simplify_or_in_or(self):
rule = _Or(_Or(_Received("Summer", 0, 1), _Received("Fall", 0, 1)),
_Or(_Received("Winter", 0, 1), _Received("Spring", 0, 1)))
assert rule.simplify() == _Or(_Received("Summer", 0, 1), _Received("Fall", 0, 1), _Received("Winter", 0, 1),
_Received("Spring", 0, 1))
def test_simplify_duplicated_or(self):
rule = _And(_Or(_Received("Summer", 0, 1), _Received("Fall", 0, 1)),
_Or(_Received("Summer", 0, 1), _Received("Fall", 0, 1)))
assert rule.simplify() == _Or(_Received("Summer", 0, 1), _Received("Fall", 0, 1))
def test_simplify_true_in_or(self):
rule = _Or(_True(), _Received("Summer", 0, 1))
assert rule.simplify() == _True()
def test_simplify_false_in_and(self):
rule = _And(_False(), _Received("Summer", 0, 1))
assert rule.simplify() == _False()

View File

@@ -0,0 +1,46 @@
import random
import sys
import unittest
from .. import StardewOptions, options
from ..regions import stardew_valley_regions, mandatory_connections, randomize_connections, RandomizationFlag
connections_by_name = {connection.name for connection in mandatory_connections}
regions_by_name = {region.name for region in stardew_valley_regions}
class TestRegions(unittest.TestCase):
def test_region_exits_lead_somewhere(self):
for region in stardew_valley_regions:
with self.subTest(region=region):
for exit in region.exits:
assert exit in connections_by_name, f"{region.name} is leading to {exit} but it does not exist."
def test_connection_lead_somewhere(self):
for connection in mandatory_connections:
with self.subTest(connection=connection):
assert connection.destination in regions_by_name, \
f"{connection.name} is leading to {connection.destination} but it does not exist."
class TestEntranceRando(unittest.TestCase):
def test_pelican_town_entrance_randomization(self):
for option, flag in [(options.EntranceRandomization.option_pelican_town, RandomizationFlag.PELICAN_TOWN),
(options.EntranceRandomization.option_non_progression, RandomizationFlag.NON_PROGRESSION)]:
with self.subTest(option=option, flag=flag):
seed = random.randrange(sys.maxsize)
rand = random.Random(seed)
world_options = StardewOptions({options.EntranceRandomization.internal_name: option})
_, randomized_connections = randomize_connections(rand, world_options)
for connection in mandatory_connections:
if flag in connection.flag:
assert connection.name in randomized_connections, \
f"Connection {connection.name} should be randomized but it is not in the output. Seed = {seed}"
assert connection.reverse in randomized_connections, \
f"Connection {connection.reverse} should be randomized but it is not in the output. Seed = {seed}"
assert len(set(randomized_connections.values())) == len(
randomized_connections.values()), f"Connections are duplicated in randomization. Seed = {seed}"

View File

@@ -0,0 +1,76 @@
import itertools
import math
import unittest
from BaseClasses import ItemClassification
from .. import ItemData
from ..items import Group, ResourcePackData
class TestResourcePack(unittest.TestCase):
def test_can_transform_resource_pack_data_into_idem_data(self):
resource_pack = ResourcePackData("item name", 1, 1, ItemClassification.filler, frozenset())
items = resource_pack.as_item_data(itertools.count())
assert ItemData(0, "Resource Pack: 1 item name", ItemClassification.filler, {Group.RESOURCE_PACK}) in items
assert ItemData(1, "Resource Pack: 2 item name", ItemClassification.filler, {Group.RESOURCE_PACK}) in items
assert len(items) == 2
def test_when_scale_quantity_then_generate_a_possible_quantity_from_minimal_scaling_to_double(self):
resource_pack = ResourcePackData("item name", default_amount=4, scaling_factor=2)
quantities = resource_pack.scale_quantity.items()
assert (50, 2) in quantities
assert (100, 4) in quantities
assert (150, 6) in quantities
assert (200, 8) in quantities
assert len(quantities) == (4 / 2) * 2
def test_given_scaling_not_multiple_of_default_amount_when_scale_quantity_then_double_is_added_at_200_scaling(self):
resource_pack = ResourcePackData("item name", default_amount=5, scaling_factor=3)
quantities = resource_pack.scale_quantity.items()
assert (40, 2) in quantities
assert (100, 5) in quantities
assert (160, 8) in quantities
assert (200, 10) in quantities
assert len(quantities) == math.ceil(5 / 3) * 2
def test_given_large_default_amount_multiple_of_scaling_factor_when_scale_quantity_then_scaled_amount_multiple(
self):
resource_pack = ResourcePackData("item name", default_amount=500, scaling_factor=50)
quantities = resource_pack.scale_quantity.items()
assert (10, 50) in quantities
assert (20, 100) in quantities
assert (30, 150) in quantities
assert (40, 200) in quantities
assert (50, 250) in quantities
assert (60, 300) in quantities
assert (70, 350) in quantities
assert (80, 400) in quantities
assert (90, 450) in quantities
assert (100, 500) in quantities
assert (110, 550) in quantities
assert (120, 600) in quantities
assert (130, 650) in quantities
assert (140, 700) in quantities
assert (150, 750) in quantities
assert (160, 800) in quantities
assert (170, 850) in quantities
assert (180, 900) in quantities
assert (190, 950) in quantities
assert (200, 1000) in quantities
assert len(quantities) == math.ceil(500 / 50) * 2
def test_given_smallest_multiplier_possible_when_generate_resource_pack_name_then_quantity_is_not_0(self):
resource_pack = ResourcePackData("item name", default_amount=10, scaling_factor=5)
name = resource_pack.create_name_from_multiplier(1)
assert name == "Resource Pack: 5 item name"

View File

@@ -0,0 +1,14 @@
from typing import ClassVar
from test.TestBase import WorldTestBase
from .. import StardewValleyWorld
class SVTestBase(WorldTestBase):
game = "Stardew Valley"
world: StardewValleyWorld
player: ClassVar[int] = 1
def world_setup(self, *args, **kwargs):
super().world_setup(*args, **kwargs)
self.world = self.multiworld.worlds[self.player]