Stardew Valley: Move progressive tool options handling in features (#4374)

* create tool progression feature and unwrap option

* replace option usage with calling feature

* add comment explaining why some logic is a weird place

* replace item creation logic with feature

* self review and add unit tests

* rename test cuz I named them too long

* add a test for the trash can useful stuff cuz I thought there was a bug but turns out it works

* self review again

* remove price_multiplier, turns out it's unused during generation

* damn it 3.11 why are you like this

* use blacksmith region when checking vanilla tools

* fix rule

* move can mine using in tool logic

* remove changes to performance test

* properly set the option I guess

* properly set options 2

* that's what happen when you code too late
This commit is contained in:
Jérémie Bolduc
2025-03-08 11:19:29 -05:00
committed by GitHub
parent b5269e9aa4
commit ee9bcb84b7
20 changed files with 262 additions and 121 deletions

View File

@@ -1,17 +1,17 @@
import itertools
from BaseClasses import ItemClassification
from Options import NamedRange
from . import SVTestCase, allsanity_no_mods_6_x_x, allsanity_mods_6_x_x, solo_multiworld
from . import SVTestCase, allsanity_no_mods_6_x_x, allsanity_mods_6_x_x, solo_multiworld, SVTestBase
from .assertion import WorldAssertMixin
from .long.option_names import all_option_choices
from .. import items_by_group, Group, StardewValleyWorld
from ..locations import locations_by_tag, LocationTags, location_table
from ..options import ExcludeGingerIsland, ToolProgression, Goal, SeasonRandomization, TrapItems, SpecialOrderLocations, ArcadeMachineLocations, \
SkillProgression
from ..options import ExcludeGingerIsland, ToolProgression, Goal, SeasonRandomization, TrapItems, SpecialOrderLocations, ArcadeMachineLocations
from ..strings.goal_names import Goal as GoalName
from ..strings.season_names import Season
from ..strings.special_order_names import SpecialOrder
from ..strings.tool_names import ToolMaterial, Tool
from ..strings.tool_names import ToolMaterial, Tool, APTool
SEASONS = {Season.spring, Season.summer, Season.fall, Season.winter}
TOOLS = {"Hoe", "Pickaxe", "Axe", "Watering Can", "Trash Can", "Fishing Rod"}
@@ -77,52 +77,30 @@ class TestSeasonRandomization(SVTestCase):
self.assertEqual(items.count(Season.progressive), 3)
class TestToolProgression(SVTestCase):
def test_given_vanilla_when_generate_then_no_tool_in_pool(self):
world_options = {ToolProgression.internal_name: ToolProgression.option_vanilla}
with solo_multiworld(world_options) as (multi_world, _):
items = {item.name for item in multi_world.get_items()}
for tool in TOOLS:
self.assertNotIn(tool, items)
def test_given_progressive_when_generate_then_each_tool_is_in_pool_4_times(self):
world_options = {ToolProgression.internal_name: ToolProgression.option_progressive,
SkillProgression.internal_name: SkillProgression.option_progressive}
with solo_multiworld(world_options) as (multi_world, _):
items = [item.name for item in multi_world.get_items()]
for tool in TOOLS:
count = items.count("Progressive " + tool)
self.assertEqual(count, 4, f"Progressive {tool} was there {count} times")
scythe_count = items.count("Progressive Scythe")
self.assertEqual(scythe_count, 1, f"Progressive Scythe was there {scythe_count} times")
self.assertEqual(items.count("Golden Scythe"), 0, f"Golden Scythe is deprecated")
def test_given_progressive_with_masteries_when_generate_then_fishing_rod_is_in_the_pool_5_times(self):
world_options = {ToolProgression.internal_name: ToolProgression.option_progressive,
SkillProgression.internal_name: SkillProgression.option_progressive_with_masteries}
with solo_multiworld(world_options) as (multi_world, _):
items = [item.name for item in multi_world.get_items()]
for tool in TOOLS:
count = items.count("Progressive " + tool)
expected_count = 5 if tool == "Fishing Rod" else 4
self.assertEqual(count, expected_count, f"Progressive {tool} was there {count} times")
scythe_count = items.count("Progressive Scythe")
self.assertEqual(scythe_count, 2, f"Progressive Scythe was there {scythe_count} times")
self.assertEqual(items.count("Golden Scythe"), 0, f"Golden Scythe is deprecated")
class TestToolProgression(SVTestBase):
options = {
ToolProgression.internal_name: ToolProgression.option_progressive,
}
def test_given_progressive_when_generate_then_tool_upgrades_are_locations(self):
world_options = {ToolProgression.internal_name: ToolProgression.option_progressive}
with solo_multiworld(world_options) as (multi_world, _):
locations = {locations.name for locations in multi_world.get_locations(1)}
for material, tool in itertools.product(ToolMaterial.tiers.values(),
[Tool.hoe, Tool.pickaxe, Tool.axe, Tool.watering_can, Tool.trash_can]):
if material == ToolMaterial.basic:
continue
self.assertIn(f"{material} {tool} Upgrade", locations)
self.assertIn("Purchase Training Rod", locations)
self.assertIn("Bamboo Pole Cutscene", locations)
self.assertIn("Purchase Fiberglass Rod", locations)
self.assertIn("Purchase Iridium Rod", locations)
locations = set(self.get_real_location_names())
for material, tool in itertools.product(ToolMaterial.tiers.values(),
[Tool.hoe, Tool.pickaxe, Tool.axe, Tool.watering_can, Tool.trash_can]):
if material == ToolMaterial.basic:
continue
self.assertIn(f"{material} {tool} Upgrade", locations)
self.assertIn("Purchase Training Rod", locations)
self.assertIn("Bamboo Pole Cutscene", locations)
self.assertIn("Purchase Fiberglass Rod", locations)
self.assertIn("Purchase Iridium Rod", locations)
def test_given_progressive_when_generate_then_only_3_trash_can_are_progressive(self):
trash_cans = self.get_items_by_name(APTool.trash_can)
progressive_count = sum([1 for item in trash_cans if item.classification == ItemClassification.progression])
useful_count = sum([1 for item in trash_cans if item.classification == ItemClassification.useful])
self.assertEqual(progressive_count, 3)
self.assertEqual(useful_count, 1)
class TestGenerateAllOptionsWithExcludeGingerIsland(WorldAssertMixin, SVTestCase):