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:
53
worlds/stardew_valley/test/TestAllLogic.py
Normal file
53
worlds/stardew_valley/test/TestAllLogic.py
Normal 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}"
|
||||
16
worlds/stardew_valley/test/TestBundles.py
Normal file
16
worlds/stardew_valley/test/TestBundles.py
Normal 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
|
||||
20
worlds/stardew_valley/test/TestData.py
Normal file
20
worlds/stardew_valley/test/TestData.py
Normal 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."
|
||||
127
worlds/stardew_valley/test/TestGeneration.py
Normal file
127
worlds/stardew_valley/test/TestGeneration.py
Normal 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())
|
||||
26
worlds/stardew_valley/test/TestItems.py
Normal file
26
worlds/stardew_valley/test/TestItems.py
Normal 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
|
||||
293
worlds/stardew_valley/test/TestLogic.py
Normal file
293
worlds/stardew_valley/test/TestLogic.py
Normal 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)
|
||||
52
worlds/stardew_valley/test/TestLogicSimplification.py
Normal file
52
worlds/stardew_valley/test/TestLogicSimplification.py
Normal 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()
|
||||
46
worlds/stardew_valley/test/TestRegions.py
Normal file
46
worlds/stardew_valley/test/TestRegions.py
Normal 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}"
|
||||
76
worlds/stardew_valley/test/TestResourcePack.py
Normal file
76
worlds/stardew_valley/test/TestResourcePack.py
Normal 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"
|
||||
14
worlds/stardew_valley/test/__init__.py
Normal file
14
worlds/stardew_valley/test/__init__.py
Normal 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]
|
||||
Reference in New Issue
Block a user